On Thu, Sep 21, 2017 at 10:56 AM, Miguel Angel Ajo Pelayo <[email protected]> wrote: > On Thu, Sep 21, 2017 at 2:21 PM, Gao Zhenyu <[email protected]> wrote: > >> I think the S/N or E/W are not the matter we should considering now. >> >> The multipath implementation is based on the existing ovn workflows. If >> you can use route to dispatch traffics to different node/logical port, then >> the multipath can make it. Otherwise it must get bug in multipath. >> If the static route cannot dispatch traffic to some nodes or logical port >> then the multipath cannot make it as well. >> >> I am not sure if my understanding is right: I think if you deploy a router >> only on a specific ovn-node, then traffic between A(src)---router----B(dst) >> should go through this router. >> > > That is the point where I'm not sure either. On the tests I made, if you > configured an specific chassis for a router, only the N/S traffic went > through that router (so multipath would make sense there), but in E/W the > traffic going through a router was directly going from origin port chassis, > to destination port chassis, without going through the specific router > chassis. > > May be it is a bug, or may be it was missconfiguration at my side. I will > double check it.
I haven't followed all of this discussion in detail, but the behavior you describe is correct and intentional. E/W is distributed. N/S is centralized. It's actually a little more complicated because you can also define N/S NAT rules that are on other chassis if you have a 1-1 NAT mapping to a logical port on that chassis. > > >> >> Any suggestions and comments are welcome :) >> >> >> Thanks >> Zhenyu Gao >> >> 2017-09-21 19:07 GMT+08:00 Miguel Angel Ajo Pelayo <[email protected]>: >> >>> May be I missed something, but when I tried setting logical routers into >>> specific chassis, still the E/W traffic was handled in a distributed way >>> (from original chassis to destination chassis without going through the >>> router chassis), such chassis was only used for N/S, but may be I got >>> something wrong. >>> >>> >>> On Wed, Sep 20, 2017 at 4:48 PM, Gao Zhenyu <[email protected]> >>> wrote: >>> >>>> " >>>> But, if an ovn port in foo (chassis A) wants to talk to alice1 (chassis >>>> B), >>>> wouldn't all that E/W routing will happen virtually and the end result >>>> is just a tunneled packet between chassis A and chassis B ? " >>>> [ Now the hash function base on dst IP, if foo1 only talks to alice1, >>>> and it is the tunnel packet between chassisA and chassis B ] >>>> >>>> The benifit is if you have two ovn-routers and those router are ONLY >>>> deployed in chassis C and chassis D, the traffics can be sperated in two >>>> paths automatically. Otherwise you need to config static rule one by one to >>>> seperate traffics. >>>> To make a long story short, you also can do same thing by config >>>> numerous static rules to seperate traffic but the multipath can do it >>>> automatically. >>>> >>>> 2017-09-20 22:08 GMT+08:00 Miguel Angel Ajo Pelayo <[email protected]> >>>> : >>>> >>>>> I forgot to say thank you very much for the explanation and diagrams. >>>>> >>>>> On Wed, Sep 20, 2017 at 4:07 PM, Miguel Angel Ajo Pelayo < >>>>> [email protected]> wrote: >>>>> >>>>>> But, if an ovn port in foo (chassis A) wants to talk to alice1 >>>>>> (chassis B), >>>>>> wouldn't all that E/W routing will happen virtually and the end result >>>>>> is just a tunneled packet between chassis A and chassis B ? >>>>>> >>>>>> What's the benefit of multipath there if the possible failing link is >>>>>> always the connection between chassis A and chassis B ? >>>>>> >>>>>> I suspect there's something I'm missing on the picture. >>>>>> >>>>>> On Wed, Sep 20, 2017 at 3:49 PM, Gao Zhenyu <[email protected]> >>>>>> wrote: >>>>>> >>>>>>> You can take a look at this patch that implement a testcase : >>>>>>> https://patchwork.ozlabs.org/patch/815475/ >>>>>>> >>>>>>> In the testcase, we have R1, R2, R3. >>>>>>> >>>>>>> R1 and R2 that are connected to each other via LS "join" in >>>>>>> 20.0.0.0/24 network. >>>>>>> R1 and R3 that are connected to each other via LS "join2" in >>>>>>> 20.0.0.0/24 network. >>>>>>> R1 has switchess foo (192.168.1.0/24) connected to it. R2 and R3 >>>>>>> has alice (172.16.1.0/24) connected to it. >>>>>>> R2 and R3 are gateway routers. >>>>>>> >>>>>>> A packet send to alice1/aclie2 from foo have mulitpath to >>>>>>> destination: >>>>>>> 1. foo-->R1-->join-->R2-->alice. >>>>>>> 2. foo-->R1-->join2-->R3-->alice. >>>>>>> >>>>>>> In this testcase, it simulates two packet, one's destination is >>>>>>> 172.16.1.2, another is 172.16.1.4. The mulitpath that was configured >>>>>>> in R1 >>>>>>> can seperate those traffics to R2/R3. Finally, 172.16.1.2 packet >>>>>>> travels >>>>>>> path2, 172.16.1.4 packet travels path1 >>>>>>> >>>>>>> +------+ >>>>>>> | foo | >>>>>>> +------+ >>>>>>> | >>>>>>> | >>>>>>> +------+ >>>>>>> | R1 |---------+ >>>>>>> +------+ | >>>>>>> | | >>>>>>> | | >>>>>>> +------+ +-------+ >>>>>>> | join | | join2 | >>>>>>> +------+ +-------+ >>>>>>> | | >>>>>>> | | >>>>>>> +------+ +-------+ >>>>>>> | R2 | | R3 | >>>>>>> +------+ +-------+ >>>>>>> | | >>>>>>> | | >>>>>>> +-----------------+ >>>>>>> | alice | >>>>>>> +-----------------+ >>>>>>> | | >>>>>>> alice1 alice2 >>>>>>> >>>>>>> Please let me know if you have any question on it. :) >>>>>>> >>>>>>> Thanks >>>>>>> Zhenyu Gao >>>>>>> >>>>>>> 2017-09-20 20:58 GMT+08:00 Miguel Angel Ajo Pelayo < >>>>>>> [email protected]>: >>>>>>> >>>>>>>> Can you share an example of how this would benefit E/W routing. I'm >>>>>>>> just not seeing the specific use case myself out of ignorance. >>>>>>>> >>>>>>>> It'd be great if you could explain how would it work between several >>>>>>>> ports in the networks and routers (may be a diagram?) otherwise I >>>>>>>> can't be >>>>>>>> really helpful reviewing :) >>>>>>>> >>>>>>>> Cheers, and thanks for the patience. >>>>>>>> >>>>>>>> On Wed, Sep 20, 2017 at 12:25 PM, Gao Zhenyu < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Thanks for the suggestions! >>>>>>>>> >>>>>>>>> Not all Logical port has a real ofp_port connect with it. And >>>>>>>>> bundle_load/bundle actions need real ovs port. >>>>>>>>> Especially in ovn router port, all router port are virtual port >>>>>>>>> which just a number/reg in our ovs-flows. >>>>>>>>> >>>>>>>>> This implement of multipath can seperate ovn east-west traffic, it >>>>>>>>> helps dispatch traffic to gateways and routers easily. >>>>>>>>> >>>>>>>>> For south-north traffic, we can have bundle/bundle_load action to >>>>>>>>> consider the remote tunnel up/down status. I would like to make it >>>>>>>>> step by >>>>>>>>> step and implement it in my next series patches. >>>>>>>>> >>>>>>>>> Thanks >>>>>>>>> Zhenyu Gao >>>>>>>>> >>>>>>>>> 2017-09-20 17:53 GMT+08:00 Miguel Angel Ajo Pelayo < >>>>>>>>> [email protected]>: >>>>>>>>> >>>>>>>>>> I'm not very familiar with multipath implementations, >>>>>>>>>> >>>>>>>>>> but would it be possible to use bundle( ouput action with hrw >>>>>>>>>> algorithm instead of multipath calculation to a register?. >>>>>>>>>> >>>>>>>>>> I say this, because if you look at lib/multipath.c lib/bundle.c >>>>>>>>>> you will find that bundle.c is going to consider the up/down status >>>>>>>>>> (slave_enabled check) of the links. >>>>>>>>>> >>>>>>>>>> That way the controller doesn't need to modify any flow based on >>>>>>>>>> link status. >>>>>>>>>> >>>>>>>>>> On Wed, Sep 20, 2017 at 5:45 AM, Gao Zhenyu < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> Thansk for the questions. >>>>>>>>>>> >>>>>>>>>>> the multipath_port can be set via ovn-nbctl. >>>>>>>>>>> Like : ovn-nbctl -- --id=@lrt create >>>>>>>>>>> Logical_Router_Static_Route ip_prefix=0.0.0.0/0 >>>>>>>>>>> nexthop=10.88.77.1 multipath_port=[mp1,mp2] -- add Logical_Router >>>>>>>>>>> edge1 >>>>>>>>>>> static_routes @lrt >>>>>>>>>>> This patch haven't implement a ovn-nbctl command to configure >>>>>>>>>>> multipath routing. Because I am still considering reusing nexthop or >>>>>>>>>>> output_port(make them become array entries), and want to collect >>>>>>>>>>> suggestions on it. >>>>>>>>>>> >>>>>>>>>>> About the status of next -hop, I would like to introduce >>>>>>>>>>> bundle_load and bfd to make it later. >>>>>>>>>>> >>>>>>>>>>> Thanks >>>>>>>>>>> Zhenyu Gao >>>>>>>>>>> >>>>>>>>>>> 2017-09-20 11:13 GMT+08:00 <[email protected]>: >>>>>>>>>>> >>>>>>>>>>>> How to configure multipath_port in static_route? I think the the >>>>>>>>>>>> multipath >>>>>>>>>>>> can be figured out from exist data of static_route, may not need >>>>>>>>>>>> to add >>>>>>>>>>>> this multipath_port column. >>>>>>>>>>>> >>>>>>>>>>>> And I think we should add a status column to indicate the >>>>>>>>>>>> nexthop state. >>>>>>>>>>>> When some of nexthop in multipath is down, ovn should change the >>>>>>>>>>>> correspond flows. >>>>>>>>>>>> >>>>>>>>>>>> Thanks. >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> Zhenyu Gao <[email protected]> >>>>>>>>>>>> 发件人: [email protected] >>>>>>>>>>>> 2017/09/19 19:37 >>>>>>>>>>>> >>>>>>>>>>>> 收件人: [email protected], [email protected], >>>>>>>>>>>> [email protected], [email protected], [email protected], >>>>>>>>>>>> 抄送: >>>>>>>>>>>> 主题: [ovs-dev] [PATCH v1 1/3] Add multipath static >>>>>>>>>>>> router in >>>>>>>>>>>> OVN northd and north-db >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> 1. ovn-nb.ovsschema was updated to add new field multipath_port. >>>>>>>>>>>> 2. Add multipath feature in ovn-northd part. northd generates >>>>>>>>>>>> multipath >>>>>>>>>>>> flows to dispatch traffic by using packet's IP dst address if >>>>>>>>>>>> user set >>>>>>>>>>>> Logical_Router_Static_Route's multipath_port with ports. >>>>>>>>>>>> 3. Add new table(lr_in_multipath) in ovn-northd's router ingress >>>>>>>>>>>> stages >>>>>>>>>>>> to dispatch traffic to ports. >>>>>>>>>>>> 4. Add multipath flow in Table 5(lr_in_ip_routing) and store >>>>>>>>>>>> hash result >>>>>>>>>>>> into reg0. reg9[2] was used to indicate packet which need >>>>>>>>>>>> dispatching. >>>>>>>>>>>> 5. Add multipath feature description in >>>>>>>>>>>> ovn/northd/ovn-northd.8.xml >>>>>>>>>>>> and ovn/ovn-nb.xml >>>>>>>>>>>> >>>>>>>>>>>> Signed-off-by: Zhenyu Gao <[email protected]> >>>>>>>>>>>> --- >>>>>>>>>>>> ovn/northd/ovn-northd.8.xml | 67 +++++++++++- >>>>>>>>>>>> ovn/northd/ovn-northd.c | 245 >>>>>>>>>>>> ++++++++++++++++++++++++++++++++++++++------ >>>>>>>>>>>> ovn/ovn-nb.ovsschema | 6 +- >>>>>>>>>>>> ovn/ovn-nb.xml | 9 ++ >>>>>>>>>>>> 4 files changed, 289 insertions(+), 38 deletions(-) >>>>>>>>>>>> >>>>>>>>>>>> diff --git a/ovn/northd/ovn-northd.8.xml >>>>>>>>>>>> b/ovn/northd/ovn-northd.8.xml >>>>>>>>>>>> index 0d85ec0..b1ce9a9 100644 >>>>>>>>>>>> --- a/ovn/northd/ovn-northd.8.xml >>>>>>>>>>>> +++ b/ovn/northd/ovn-northd.8.xml >>>>>>>>>>>> @@ -1598,6 +1598,9 @@ icmp4 { >>>>>>>>>>>> port (ingress table <code>ARP Request</code> will >>>>>>>>>>>> generate an ARP >>>>>>>>>>>> request, if needed, with <code>reg0</code> as the target >>>>>>>>>>>> protocol >>>>>>>>>>>> address and <code>reg1</code> as the source protocol >>>>>>>>>>>> address). >>>>>>>>>>>> + A IP route can be configured that it has multipath to >>>>>>>>>>>> next-hop. >>>>>>>>>>>> + If a packet has multipath to destination, OVN assign the >>>>>>>>>>>> port >>>>>>>>>>>> + index into reg[0] to indicate the packet's output port in >>>>>>>>>>>> table 6. >>>>>>>>>>>> </p> >>>>>>>>>>>> >>>>>>>>>>>> <p> >>>>>>>>>>>> @@ -1617,6 +1620,28 @@ icmp4 { >>>>>>>>>>>> >>>>>>>>>>>> <li> >>>>>>>>>>>> <p> >>>>>>>>>>>> + IPv4/IPV6 multipath routing table. For each route to >>>>>>>>>>>> IPv4/IPv6 >>>>>>>>>>>> + network <var>N</var> with netmask <var>M</var>, on >>>>>>>>>>>> multipath >>>>>>>>>>>> port >>>>>>>>>>>> + <var>P</var> with IP address <var>A</var> and Ethernet >>>>>>>>>>>> + address <var>E</var>, a logical flow with match >>>>>>>>>>>> + <code>ip4.dst ==<var>N</var>/<var>M</var></code>,whose >>>>>>>>>>>> priority >>>>>>>>>>>> + is the number of 1-bits plus 10 in <var>M</var>, >>>>>>>>>>>> + has the following actions: >>>>>>>>>>>> + </p> >>>>>>>>>>>> + >>>>>>>>>>>> + <pre> >>>>>>>>>>>> +ip.ttl--; >>>>>>>>>>>> +multipath (nw_dst, 0, modulo_n, <var>n_links</var>, 0, reg0); >>>>>>>>>>>> +reg9[2] = 1 >>>>>>>>>>>> +next; >>>>>>>>>>>> + </pre> >>>>>>>>>>>> + <p> >>>>>>>>>>>> + <var>n_links</var> is the number of multipath port. >>>>>>>>>>>> + </p> >>>>>>>>>>>> + </li> >>>>>>>>>>>> + >>>>>>>>>>>> + <li> >>>>>>>>>>>> + <p> >>>>>>>>>>>> IPv4 routing table. For each route to IPv4 network >>>>>>>>>>>> <var>N</var> with >>>>>>>>>>>> netmask <var>M</var>, on router port <var>P</var> >>>>>>>>>>>> with IP >>>>>>>>>>>> address >>>>>>>>>>>> <var>A</var> and Ethernet >>>>>>>>>>>> @@ -1686,7 +1711,43 @@ next; >>>>>>>>>>>> </li> >>>>>>>>>>>> </ul> >>>>>>>>>>>> >>>>>>>>>>>> - <h3>Ingress Table 6: ARP/ND Resolution</h3> >>>>>>>>>>>> + <h3>Ingress Table 6: Multipath</h3> >>>>>>>>>>>> + <p> >>>>>>>>>>>> + Any packet taht reaches this table is an IP packet and >>>>>>>>>>>> reg9[2]=1 >>>>>>>>>>>> + using the following flows to route to corresponding port. >>>>>>>>>>>> This >>>>>>>>>>>> table >>>>>>>>>>>> + implement dispatching by consuming reg0. >>>>>>>>>>>> + </p> >>>>>>>>>>>> + >>>>>>>>>>>> + <ul> >>>>>>>>>>>> + <li> >>>>>>>>>>>> + <p> >>>>>>>>>>>> + A packet with netmask <var>M</var>, IP address >>>>>>>>>>>> <var>A</var> and >>>>>>>>>>>> + <code>reg9[2] = 1</code>, whose priority above 1 has >>>>>>>>>>>> following >>>>>>>>>>>> + actions: >>>>>>>>>>>> + </p> >>>>>>>>>>>> + >>>>>>>>>>>> + <pre> >>>>>>>>>>>> +reg0 = <var>G</var>; >>>>>>>>>>>> +reg1 = <var>A</var>; >>>>>>>>>>>> +eth.src = <var>E</var>; >>>>>>>>>>>> +outport = <var>P</var>; >>>>>>>>>>>> +flags.loopback = 1; >>>>>>>>>>>> +next; >>>>>>>>>>>> + </pre> >>>>>>>>>>>> + >>>>>>>>>>>> + <p> >>>>>>>>>>>> + <var>G</var> is the gateway IP address. <var>A</var>, >>>>>>>>>>>> <var>E</var> >>>>>>>>>>>> + and <var>P</var> are the values that were described in >>>>>>>>>>>> multipath >>>>>>>>>>>> + routeing in table 5 >>>>>>>>>>>> + </p> >>>>>>>>>>>> + >>>>>>>>>>>> + <p> >>>>>>>>>>>> + A priority-0 logical flow with match has actions >>>>>>>>>>>> <code>next;</code>. >>>>>>>>>>>> + </p> >>>>>>>>>>>> + </li> >>>>>>>>>>>> + </ul> >>>>>>>>>>>> + >>>>>>>>>>>> + <h3>Ingress Table 7: ARP/ND Resolution</h3> >>>>>>>>>>>> >>>>>>>>>>>> <p> >>>>>>>>>>>> Any packet that reaches this table is an IP packet whose >>>>>>>>>>>> next-hop >>>>>>>>>>>> @@ -1779,7 +1840,7 @@ next; >>>>>>>>>>>> </li> >>>>>>>>>>>> </ul> >>>>>>>>>>>> >>>>>>>>>>>> - <h3>Ingress Table 7: Gateway Redirect</h3> >>>>>>>>>>>> + <h3>Ingress Table 8: Gateway Redirect</h3> >>>>>>>>>>>> >>>>>>>>>>>> <p> >>>>>>>>>>>> For distributed logical routers where one of the logical >>>>>>>>>>>> router >>>>>>>>>>>> @@ -1836,7 +1897,7 @@ next; >>>>>>>>>>>> </li> >>>>>>>>>>>> </ul> >>>>>>>>>>>> >>>>>>>>>>>> - <h3>Ingress Table 8: ARP Request</h3> >>>>>>>>>>>> + <h3>Ingress Table 9: ARP Request</h3> >>>>>>>>>>>> >>>>>>>>>>>> <p> >>>>>>>>>>>> In the common case where the Ethernet destination has been >>>>>>>>>>>> resolved, this >>>>>>>>>>>> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c >>>>>>>>>>>> index 49e4ac3..44d1fd4 100644 >>>>>>>>>>>> --- a/ovn/northd/ovn-northd.c >>>>>>>>>>>> +++ b/ovn/northd/ovn-northd.c >>>>>>>>>>>> @@ -135,9 +135,10 @@ enum ovn_stage { >>>>>>>>>>>> PIPELINE_STAGE(ROUTER, IN, UNSNAT, 3, >>>>>>>>>>>> "lr_in_unsnat") \ >>>>>>>>>>>> PIPELINE_STAGE(ROUTER, IN, DNAT, 4, "lr_in_dnat") >>>>>>>>>>>> \ >>>>>>>>>>>> PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 5, >>>>>>>>>>>> "lr_in_ip_routing") \ >>>>>>>>>>>> - PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 6, >>>>>>>>>>>> "lr_in_arp_resolve") \ >>>>>>>>>>>> - PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 7, >>>>>>>>>>>> "lr_in_gw_redirect") \ >>>>>>>>>>>> - PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 8, >>>>>>>>>>>> "lr_in_arp_request") \ >>>>>>>>>>>> + PIPELINE_STAGE(ROUTER, IN, MULTIPATH, 6, >>>>>>>>>>>> "lr_in_multipath") \ >>>>>>>>>>>> + PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 7, >>>>>>>>>>>> "lr_in_arp_resolve") \ >>>>>>>>>>>> + PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 8, >>>>>>>>>>>> "lr_in_gw_redirect") \ >>>>>>>>>>>> + PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 9, >>>>>>>>>>>> "lr_in_arp_request") \ >>>>>>>>>>>> >>>>>>>>>>>> \ >>>>>>>>>>>> /* Logical router egress stages. */ >>>>>>>>>>>> \ >>>>>>>>>>>> PIPELINE_STAGE(ROUTER, OUT, UNDNAT, 0, "lr_out_undnat") >>>>>>>>>>>> \ >>>>>>>>>>>> @@ -173,6 +174,11 @@ enum ovn_stage { >>>>>>>>>>>> * one of the logical router's own IP addresses. */ >>>>>>>>>>>> #define REGBIT_EGRESS_LOOPBACK "reg9[1]" >>>>>>>>>>>> >>>>>>>>>>>> +/* Indicate multipath action has process this packet and store >>>>>>>>>>>> hash >>>>>>>>>>>> result >>>>>>>>>>>> + * into other regX. Should consume the hash result to determin >>>>>>>>>>>> the right >>>>>>>>>>>> + * output port. */ >>>>>>>>>>>> +#define REGBIT_MULTIPATH "reg9[2]" >>>>>>>>>>>> + >>>>>>>>>>>> /* Returns an "enum ovn_stage" built from the arguments. */ >>>>>>>>>>>> static enum ovn_stage >>>>>>>>>>>> ovn_stage_build(enum ovn_datapath_type dp_type, enum >>>>>>>>>>>> ovn_pipeline >>>>>>>>>>>> pipeline, >>>>>>>>>>>> @@ -4142,72 +4148,165 @@ add_route(struct hmap *lflows, const >>>>>>>>>>>> struct >>>>>>>>>>>> ovn_port *op, >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> static void >>>>>>>>>>>> -build_static_route_flow(struct hmap *lflows, struct >>>>>>>>>>>> ovn_datapath *od, >>>>>>>>>>>> - struct hmap *ports, >>>>>>>>>>>> - const struct >>>>>>>>>>>> nbrec_logical_router_static_route >>>>>>>>>>>> *route) >>>>>>>>>>>> +add_multipath_route(struct hmap *lflows, uint32_t port_num, >>>>>>>>>>>> + struct ovn_port **out_ports, >>>>>>>>>>>> + const char **lrp_addr_s, >>>>>>>>>>>> + struct ovn_datapath *od, >>>>>>>>>>>> + const char *network_s, int plen, >>>>>>>>>>>> + const char *gateway, const char *policy) >>>>>>>>>>>> +{ >>>>>>>>>>>> + bool is_ipv4 = strchr(network_s, '.') ? true : false; >>>>>>>>>>>> + struct ds match = DS_EMPTY_INITIALIZER; >>>>>>>>>>>> + const char *dir; >>>>>>>>>>>> + uint16_t priority; >>>>>>>>>>>> + >>>>>>>>>>>> + if (policy && !strcmp(policy, "src-ip")) { >>>>>>>>>>>> + dir = "src"; >>>>>>>>>>>> + priority = plen * 2; >>>>>>>>>>>> + } else { >>>>>>>>>>>> + dir = "dst"; >>>>>>>>>>>> + priority = (plen * 2) + 1; >>>>>>>>>>>> + } >>>>>>>>>>>> + >>>>>>>>>>>> + /* Set higer priority than regular route. */ >>>>>>>>>>>> + priority += 10; >>>>>>>>>>>> + >>>>>>>>>>>> + ds_put_format(&match, "ip%s.%s == %s/%d", is_ipv4 ? "4" : >>>>>>>>>>>> "6", dir, >>>>>>>>>>>> + network_s, plen); >>>>>>>>>>>> + >>>>>>>>>>>> + struct ds actions = DS_EMPTY_INITIALIZER; >>>>>>>>>>>> + >>>>>>>>>>>> + ds_put_format(&actions, "ip.ttl--; "); >>>>>>>>>>>> + ds_put_format(&actions, >>>>>>>>>>>> + "multipath (nw_dst, 0, modulo_n, %u, 0, >>>>>>>>>>>> reg0); " >>>>>>>>>>>> + "%s = 1; " >>>>>>>>>>>> + "next;", >>>>>>>>>>>> + port_num, REGBIT_MULTIPATH); >>>>>>>>>>>> + >>>>>>>>>>>> + /* The priority here is calculated to implement >>>>>>>>>>>> longest-prefix-match >>>>>>>>>>>> + * routing. */ >>>>>>>>>>>> + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING, priority, >>>>>>>>>>>> + ds_cstr(&match), ds_cstr(&actions)); >>>>>>>>>>>> + >>>>>>>>>>>> + for (int i = 0; i < port_num; i++) { >>>>>>>>>>>> + struct ds mp_match = DS_EMPTY_INITIALIZER; >>>>>>>>>>>> + struct ds mp_actions = DS_EMPTY_INITIALIZER; >>>>>>>>>>>> + >>>>>>>>>>>> + ds_put_format(&mp_match, "%s == 1 && reg0 == %d && ", >>>>>>>>>>>> + REGBIT_MULTIPATH, i); >>>>>>>>>>>> + ds_put_format(&mp_match, "ip%s.%s == %s/%d", >>>>>>>>>>>> + is_ipv4 ? "4" : "6", dir, >>>>>>>>>>>> + network_s, plen); >>>>>>>>>>>> + >>>>>>>>>>>> + ds_put_format(&mp_actions, "%sreg0 = ", is_ipv4 ? "" : >>>>>>>>>>>> "xx"); >>>>>>>>>>>> + if (gateway) { >>>>>>>>>>>> + ds_put_cstr(&mp_actions, gateway); >>>>>>>>>>>> + } else { >>>>>>>>>>>> + ds_put_format(&mp_actions, "ip%s.dst", is_ipv4 ? >>>>>>>>>>>> "4" : "6"); >>>>>>>>>>>> + } >>>>>>>>>>>> + >>>>>>>>>>>> + ds_put_format(&mp_actions, "; " >>>>>>>>>>>> + "%sreg1 = %s; " >>>>>>>>>>>> + "eth.src = %s; " >>>>>>>>>>>> + "outport = %s; " >>>>>>>>>>>> + "flags.loopback = 1; " >>>>>>>>>>>> + "next;", >>>>>>>>>>>> + is_ipv4 ? "" : "xx", >>>>>>>>>>>> + lrp_addr_s[i], >>>>>>>>>>>> + out_ports[i]->lrp_networks.ea_s, >>>>>>>>>>>> + out_ports[i]->json_key); >>>>>>>>>>>> + >>>>>>>>>>>> + /* Add flow in table 6 to determin the right output port >>>>>>>>>>>> + * for this traffic. */ >>>>>>>>>>>> + ovn_lflow_add(lflows, od, S_ROUTER_IN_MULTIPATH, >>>>>>>>>>>> priority, >>>>>>>>>>>> + ds_cstr(&mp_match), ds_cstr(&mp_actions)); >>>>>>>>>>>> + ds_destroy(&mp_match); >>>>>>>>>>>> + ds_destroy(&mp_actions); >>>>>>>>>>>> + } >>>>>>>>>>>> + ds_destroy(&match); >>>>>>>>>>>> + ds_destroy(&actions); >>>>>>>>>>>> +} >>>>>>>>>>>> + >>>>>>>>>>>> +static bool >>>>>>>>>>>> +verify_nexthop_prefix(const struct >>>>>>>>>>>> nbrec_logical_router_static_route >>>>>>>>>>>> *route, >>>>>>>>>>>> + bool *is_ipv4, char **prefix_s, unsigned >>>>>>>>>>>> int *plen) >>>>>>>>>>>> { >>>>>>>>>>>> ovs_be32 nexthop; >>>>>>>>>>>> - const char *lrp_addr_s = NULL; >>>>>>>>>>>> - unsigned int plen; >>>>>>>>>>>> - bool is_ipv4; >>>>>>>>>>>> >>>>>>>>>>>> /* Verify that the next hop is an IP address with an >>>>>>>>>>>> all-ones mask. >>>>>>>>>>>> */ >>>>>>>>>>>> - char *error = ip_parse_cidr(route->nexthop, &nexthop, >>>>>>>>>>>> &plen); >>>>>>>>>>>> + char *error = ip_parse_cidr(route->nexthop, &nexthop, plen); >>>>>>>>>>>> if (!error) { >>>>>>>>>>>> - if (plen != 32) { >>>>>>>>>>>> + if (*plen != 32) { >>>>>>>>>>>> static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, >>>>>>>>>>>> 1); >>>>>>>>>>>> VLOG_WARN_RL(&rl, "bad next hop mask %s", >>>>>>>>>>>> route->nexthop); >>>>>>>>>>>> - return; >>>>>>>>>>>> + return false; >>>>>>>>>>>> } >>>>>>>>>>>> - is_ipv4 = true; >>>>>>>>>>>> + *is_ipv4 = true; >>>>>>>>>>>> } else { >>>>>>>>>>>> free(error); >>>>>>>>>>>> >>>>>>>>>>>> struct in6_addr ip6; >>>>>>>>>>>> - error = ipv6_parse_cidr(route->nexthop, &ip6, &plen); >>>>>>>>>>>> + error = ipv6_parse_cidr(route->nexthop, &ip6, plen); >>>>>>>>>>>> if (!error) { >>>>>>>>>>>> - if (plen != 128) { >>>>>>>>>>>> + if (*plen != 128) { >>>>>>>>>>>> static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, 1); >>>>>>>>>>>> VLOG_WARN_RL(&rl, "bad next hop mask %s", >>>>>>>>>>>> route->nexthop); >>>>>>>>>>>> - return; >>>>>>>>>>>> + return false; >>>>>>>>>>>> } >>>>>>>>>>>> - is_ipv4 = false; >>>>>>>>>>>> + *is_ipv4 = false; >>>>>>>>>>>> } else { >>>>>>>>>>>> static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, >>>>>>>>>>>> 1); >>>>>>>>>>>> VLOG_WARN_RL(&rl, "bad next hop ip address %s", >>>>>>>>>>>> route->nexthop); >>>>>>>>>>>> free(error); >>>>>>>>>>>> - return; >>>>>>>>>>>> + return false; >>>>>>>>>>>> } >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> - char *prefix_s; >>>>>>>>>>>> - if (is_ipv4) { >>>>>>>>>>>> + if (*is_ipv4) { >>>>>>>>>>>> ovs_be32 prefix; >>>>>>>>>>>> /* Verify that ip prefix is a valid IPv4 address. */ >>>>>>>>>>>> - error = ip_parse_cidr(route->ip_prefix, &prefix, >>>>>>>>>>>> &plen); >>>>>>>>>>>> + error = ip_parse_cidr(route->ip_prefix, &prefix, plen); >>>>>>>>>>>> if (error) { >>>>>>>>>>>> static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, >>>>>>>>>>>> 1); >>>>>>>>>>>> VLOG_WARN_RL(&rl, "bad 'ip_prefix' in static routes >>>>>>>>>>>> %s", >>>>>>>>>>>> route->ip_prefix); >>>>>>>>>>>> free(error); >>>>>>>>>>>> - return; >>>>>>>>>>>> + return false; >>>>>>>>>>>> } >>>>>>>>>>>> - prefix_s = xasprintf(IP_FMT, IP_ARGS(prefix & >>>>>>>>>>>> be32_prefix_mask(plen))); >>>>>>>>>>>> + *prefix_s = xasprintf(IP_FMT, IP_ARGS(prefix >>>>>>>>>>>> + & >>>>>>>>>>>> be32_prefix_mask(*plen))); >>>>>>>>>>>> } else { >>>>>>>>>>>> /* Verify that ip prefix is a valid IPv6 address. */ >>>>>>>>>>>> struct in6_addr prefix; >>>>>>>>>>>> - error = ipv6_parse_cidr(route->ip_prefix, &prefix, >>>>>>>>>>>> &plen); >>>>>>>>>>>> + error = ipv6_parse_cidr(route->ip_prefix, &prefix, >>>>>>>>>>>> plen); >>>>>>>>>>>> if (error) { >>>>>>>>>>>> static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, >>>>>>>>>>>> 1); >>>>>>>>>>>> VLOG_WARN_RL(&rl, "bad 'ip_prefix' in static routes >>>>>>>>>>>> %s", >>>>>>>>>>>> route->ip_prefix); >>>>>>>>>>>> free(error); >>>>>>>>>>>> - return; >>>>>>>>>>>> + return false; >>>>>>>>>>>> } >>>>>>>>>>>> - struct in6_addr mask = ipv6_create_mask(plen); >>>>>>>>>>>> + struct in6_addr mask = ipv6_create_mask(*plen); >>>>>>>>>>>> struct in6_addr network = ipv6_addr_bitand(&prefix, >>>>>>>>>>>> &mask); >>>>>>>>>>>> - prefix_s = xmalloc(INET6_ADDRSTRLEN); >>>>>>>>>>>> - inet_ntop(AF_INET6, &network, prefix_s, >>>>>>>>>>>> INET6_ADDRSTRLEN); >>>>>>>>>>>> + *prefix_s = xmalloc(INET6_ADDRSTRLEN); >>>>>>>>>>>> + inet_ntop(AF_INET6, &network, *prefix_s, >>>>>>>>>>>> INET6_ADDRSTRLEN); >>>>>>>>>>>> + } >>>>>>>>>>>> + >>>>>>>>>>>> + return true; >>>>>>>>>>>> +} >>>>>>>>>>>> + >>>>>>>>>>>> +static void >>>>>>>>>>>> +build_static_route_flow(struct hmap *lflows, struct >>>>>>>>>>>> ovn_datapath *od, >>>>>>>>>>>> + struct hmap *ports, >>>>>>>>>>>> + const struct >>>>>>>>>>>> nbrec_logical_router_static_route >>>>>>>>>>>> *route) >>>>>>>>>>>> +{ >>>>>>>>>>>> + const char *lrp_addr_s = NULL; >>>>>>>>>>>> + unsigned int plen; >>>>>>>>>>>> + bool is_ipv4; >>>>>>>>>>>> + char *prefix_s = NULL; >>>>>>>>>>>> + >>>>>>>>>>>> + if (!verify_nexthop_prefix(route, &is_ipv4, &prefix_s, >>>>>>>>>>>> &plen)) { >>>>>>>>>>>> + return; >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> /* Find the outgoing port. */ >>>>>>>>>>>> @@ -4270,7 +4369,75 @@ build_static_route_flow(struct hmap >>>>>>>>>>>> *lflows, struct >>>>>>>>>>>> ovn_datapath *od, >>>>>>>>>>>> policy); >>>>>>>>>>>> >>>>>>>>>>>> free_prefix_s: >>>>>>>>>>>> - free(prefix_s); >>>>>>>>>>>> + if (prefix_s) { >>>>>>>>>>>> + free(prefix_s); >>>>>>>>>>>> + } >>>>>>>>>>>> +} >>>>>>>>>>>> + >>>>>>>>>>>> +static void >>>>>>>>>>>> +build_multipath_flow(struct hmap *lflows, struct ovn_datapath >>>>>>>>>>>> *od, >>>>>>>>>>>> + struct hmap *ports, >>>>>>>>>>>> + const struct nbrec_logical_router_static_ro >>>>>>>>>>>> ute >>>>>>>>>>>> *route) >>>>>>>>>>>> +{ >>>>>>>>>>>> + unsigned int plen; >>>>>>>>>>>> + bool is_ipv4; >>>>>>>>>>>> + char *prefix_s = NULL; >>>>>>>>>>>> + >>>>>>>>>>>> + if (!verify_nexthop_prefix(route, &is_ipv4, &prefix_s, >>>>>>>>>>>> &plen)) { >>>>>>>>>>>> + return; >>>>>>>>>>>> + } >>>>>>>>>>>> + >>>>>>>>>>>> + /* Find the outgoing port. */ >>>>>>>>>>>> + struct ovn_port **out_ports = xmalloc(route->n_multipath_port >>>>>>>>>>>> * >>>>>>>>>>>> + sizeof(struct >>>>>>>>>>>> ovn_port *)); >>>>>>>>>>>> + const char **lrp_addr_s = xmalloc(route->n_multipath_port * >>>>>>>>>>>> + sizeof(const char *)); >>>>>>>>>>>> + for (int i = 0; i < route->n_multipath_port; i++) { >>>>>>>>>>>> + // TODO May need to consider some ports are not found? >>>>>>>>>>>> + out_ports[i] = ovn_port_find(ports, >>>>>>>>>>>> route->multipath_port[i]); >>>>>>>>>>>> + if (!out_ports[i]) { >>>>>>>>>>>> + static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, >>>>>>>>>>>> 1); >>>>>>>>>>>> + VLOG_WARN_RL(&rl, "Bad out port %s for static route >>>>>>>>>>>> %s", >>>>>>>>>>>> + route->multipath_port[i], >>>>>>>>>>>> route->ip_prefix); >>>>>>>>>>>> + goto free_ports_lrp_addr; >>>>>>>>>>>> + } >>>>>>>>>>>> + >>>>>>>>>>>> + lrp_addr_s[i] = find_lrp_member_ip(out_ports[i], >>>>>>>>>>>> route->nexthop); >>>>>>>>>>>> + if (!lrp_addr_s[i]) { >>>>>>>>>>>> + if (is_ipv4) { >>>>>>>>>>>> + if (out_ports[i]->lrp_networks.n_ipv4_addrs) { >>>>>>>>>>>> + lrp_addr_s[i] = out_ports[i]-> >>>>>>>>>>>> + lrp_networks.ipv4_addrs[0].addr_s; >>>>>>>>>>>> + } >>>>>>>>>>>> + } else { >>>>>>>>>>>> + if (out_ports[i]->lrp_networks.n_ipv6_addrs) { >>>>>>>>>>>> + lrp_addr_s[i] = out_ports[i]-> >>>>>>>>>>>> + lrp_networks.ipv6_addrs[0].addr_s; >>>>>>>>>>>> + } >>>>>>>>>>>> + } >>>>>>>>>>>> + } >>>>>>>>>>>> + if (!lrp_addr_s[i]) { >>>>>>>>>>>> + static struct vlog_rate_limit rl = >>>>>>>>>>>> VLOG_RATE_LIMIT_INIT(5, >>>>>>>>>>>> 1); >>>>>>>>>>>> + VLOG_WARN_RL(&rl, >>>>>>>>>>>> + "%s has no path for static route %s; >>>>>>>>>>>> next hop >>>>>>>>>>>> %s", >>>>>>>>>>>> + route->multipath_port[i], >>>>>>>>>>>> route->ip_prefix, >>>>>>>>>>>> + route->nexthop); >>>>>>>>>>>> + goto free_ports_lrp_addr; >>>>>>>>>>>> + } >>>>>>>>>>>> + } >>>>>>>>>>>> + >>>>>>>>>>>> + >>>>>>>>>>>> + char *policy = route->policy ? route->policy : "dst-ip"; >>>>>>>>>>>> + add_multipath_route(lflows, route->n_multipath_port, >>>>>>>>>>>> + out_ports, lrp_addr_s, od, >>>>>>>>>>>> + prefix_s, plen, route->nexthop, policy); >>>>>>>>>>>> + >>>>>>>>>>>> +free_ports_lrp_addr: >>>>>>>>>>>> + free(out_ports); >>>>>>>>>>>> + free(lrp_addr_s); >>>>>>>>>>>> + if (prefix_s) { >>>>>>>>>>>> + free(prefix_s); >>>>>>>>>>>> + } >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> static void >>>>>>>>>>>> @@ -5344,7 +5511,7 @@ build_lrouter_flows(struct hmap >>>>>>>>>>>> *datapaths, struct >>>>>>>>>>>> hmap *ports, >>>>>>>>>>>> } >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> - /* Convert the static routes to flows. */ >>>>>>>>>>>> + /* Convert the static routes and multipath route to flows. >>>>>>>>>>>> */ >>>>>>>>>>>> HMAP_FOR_EACH (od, key_node, datapaths) { >>>>>>>>>>>> if (!od->nbr) { >>>>>>>>>>>> continue; >>>>>>>>>>>> @@ -5355,12 +5522,24 @@ build_lrouter_flows(struct hmap >>>>>>>>>>>> *datapaths, struct >>>>>>>>>>>> hmap *ports, >>>>>>>>>>>> >>>>>>>>>>>> route = od->nbr->static_routes[i]; >>>>>>>>>>>> build_static_route_flow(lflows, od, ports, route); >>>>>>>>>>>> + /* Logical router ingress table 5-6: Multipath >>>>>>>>>>>> Routing. >>>>>>>>>>>> + * >>>>>>>>>>>> + * If router has configured a traffic has multiple >>>>>>>>>>>> paths >>>>>>>>>>>> + * to destination. The right output port should be >>>>>>>>>>>> firgured >>>>>>>>>>>> + * out by computing IP packet's header */ >>>>>>>>>>>> + if (route->n_multipath_port > 1) { >>>>>>>>>>>> + /* Generate multipath routes in table 5,6 for >>>>>>>>>>>> + * dedicated traffic */ >>>>>>>>>>>> + build_multipath_flow(lflows, od, ports, route); >>>>>>>>>>>> + } >>>>>>>>>>>> } >>>>>>>>>>>> + /* Packets are allowed by default in table 6. */ >>>>>>>>>>>> + ovn_lflow_add(lflows, od, S_ROUTER_IN_MULTIPATH, 0, "1", >>>>>>>>>>>> "next;"); >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> /* XXX destination unreachable */ >>>>>>>>>>>> >>>>>>>>>>>> - /* Local router ingress table 6: ARP Resolution. >>>>>>>>>>>> + /* Local router ingress table 7: ARP Resolution. >>>>>>>>>>>> * >>>>>>>>>>>> * Any packet that reaches this table is an IP packet whose >>>>>>>>>>>> next-hop >>>>>>>>>>>> IP >>>>>>>>>>>> * address is in reg0. (ip4.dst is the final destination.) >>>>>>>>>>>> This table >>>>>>>>>>>> @@ -5555,7 +5734,7 @@ build_lrouter_flows(struct hmap >>>>>>>>>>>> *datapaths, struct >>>>>>>>>>>> hmap *ports, >>>>>>>>>>>> "get_nd(outport, xxreg0); next;"); >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> - /* Logical router ingress table 7: Gateway redirect. >>>>>>>>>>>> + /* Logical router ingress table 8: Gateway redirect. >>>>>>>>>>>> * >>>>>>>>>>>> * For traffic with outport equal to the l3dgw_port >>>>>>>>>>>> * on a distributed router, this table redirects a subset >>>>>>>>>>>> @@ -5595,7 +5774,7 @@ build_lrouter_flows(struct hmap >>>>>>>>>>>> *datapaths, struct >>>>>>>>>>>> hmap *ports, >>>>>>>>>>>> ovn_lflow_add(lflows, od, S_ROUTER_IN_GW_REDIRECT, 0, >>>>>>>>>>>> "1", >>>>>>>>>>>> "next;"); >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> - /* Local router ingress table 8: ARP request. >>>>>>>>>>>> + /* Local router ingress table 9: ARP request. >>>>>>>>>>>> * >>>>>>>>>>>> * In the common case where the Ethernet destination has >>>>>>>>>>>> been >>>>>>>>>>>> resolved, >>>>>>>>>>>> * this table outputs the packet (priority 0). Otherwise, >>>>>>>>>>>> it >>>>>>>>>>>> composes >>>>>>>>>>>> diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema >>>>>>>>>>>> index a077bfb..b8bdd42 100644 >>>>>>>>>>>> --- a/ovn/ovn-nb.ovsschema >>>>>>>>>>>> +++ b/ovn/ovn-nb.ovsschema >>>>>>>>>>>> @@ -1,7 +1,7 @@ >>>>>>>>>>>> { >>>>>>>>>>>> "name": "OVN_Northbound", >>>>>>>>>>>> "version": "5.8.0", >>>>>>>>>>>> - "cksum": "2812300190 <(281)%20230-0190> 16766", >>>>>>>>>>>> + "cksum": "1967092589 16903", >>>>>>>>>>>> "tables": { >>>>>>>>>>>> "NB_Global": { >>>>>>>>>>>> "columns": { >>>>>>>>>>>> @@ -235,7 +235,9 @@ >>>>>>>>>>>> >>>>>>>>>>>> "dst-ip"]]}, >>>>>>>>>>>> "min": 0, "max": 1}}, >>>>>>>>>>>> "nexthop": {"type": "string"}, >>>>>>>>>>>> - "output_port": {"type": {"key": "string", >>>>>>>>>>>> "min": 0, >>>>>>>>>>>> "max": 1}}}, >>>>>>>>>>>> + "output_port": {"type": {"key": "string", >>>>>>>>>>>> "min": 0, >>>>>>>>>>>> "max": 1}}, >>>>>>>>>>>> + "multipath_port": {"type": {"key": "string", >>>>>>>>>>>> "min": 0, >>>>>>>>>>>> + "max": >>>>>>>>>>>> "unlimited"}}}, >>>>>>>>>>>> "isRoot": false}, >>>>>>>>>>>> "NAT": { >>>>>>>>>>>> "columns": { >>>>>>>>>>>> diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml >>>>>>>>>>>> index 9869d7e..15feb97 100644 >>>>>>>>>>>> --- a/ovn/ovn-nb.xml >>>>>>>>>>>> +++ b/ovn/ovn-nb.xml >>>>>>>>>>>> @@ -1487,6 +1487,15 @@ >>>>>>>>>>>> address as the one via which the <ref >>>>>>>>>>>> column="nexthop"/> is >>>>>>>>>>>> reachable. >>>>>>>>>>>> </p> >>>>>>>>>>>> </column> >>>>>>>>>>>> + <column name="multipath_port"> >>>>>>>>>>>> + <p> >>>>>>>>>>>> + The name of the <ref table="Logical_Router_Port"/> via >>>>>>>>>>>> which the >>>>>>>>>>>> packet >>>>>>>>>>>> + needs to be sent out. When it contains more than two >>>>>>>>>>>> ports, it >>>>>>>>>>>> means >>>>>>>>>>>> + packet has multiple candidate output ports. OVN uses >>>>>>>>>>>> the packet >>>>>>>>>>>> header >>>>>>>>>>>> + to determin which port the packet would be delivered to. >>>>>>>>>>>> + Currently, OVN consumes destination IP address to >>>>>>>>>>>> figure out >>>>>>>>>>>> port. >>>>>>>>>>>> + </p> >>>>>>>>>>>> + </column> >>>>>>>>>>>> </table> >>>>>>>>>>>> >>>>>>>>>>>> <table name="NAT" title="NAT rules"> >>>>>>>>>>>> -- >>>>>>>>>>>> 1.8.3.1 >>>>>>>>>>>> >>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>> dev mailing list >>>>>>>>>>>> [email protected] >>>>>>>>>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>> dev mailing list >>>>>>>>>>>> [email protected] >>>>>>>>>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev >>>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >> > _______________________________________________ > dev mailing list > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev -- Russell Bryant _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
