No problem Gao. Btw, give it a try if you want, and double check that's as we said. I dint't have time to recheck, and my memory doesn't use to be great ;-)
On Sat, Sep 23, 2017 at 1:54 AM, Gao Zhenyu <[email protected]> wrote: > Sorry for misleading, in my other testing, I ping the IP(is a router > port's IP) and saw packets go into a chassis(router are pined on this > ovn-chassis by using option:chassis=xxxxx). So in that time I though the > router should be only on a specific ovn-node if route was pinned. > Miguel had told me that router IP is an special case that will be handled > by the specific chassis. > > Sorry for misleading again. I think we can focus on the implementatioin of > multipath now. :) > > Thanks > Zhenyu Gao > > 2017-09-22 20:22 GMT+08:00 Russell Bryant <[email protected]>: > >> 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></c >> ode>,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> >> <(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
