Hi Numan, I’ve submitted v5 here [1]. I decided to leave NEWS section unchanged since it mentions OVN IC changes, which is done in patch #3. Also, I see that 21.09.0 tag was created 17 hours ago… so, now this patch series is postponed to 21.12 or there are options?
1: https://patchwork.ozlabs.org/project/ovn/list/?series=265501 Regards, Vladislav Odintsov > On 4 Oct 2021, at 19:20, Numan Siddique <[email protected]> wrote: > > On Sun, Sep 19, 2021 at 5:24 PM Vladislav Odintsov <[email protected] > <mailto:[email protected]>> wrote: >> >> Signed-off-by: Vladislav Odintsov <[email protected]> >> --- >> northd/northd.c | 159 ++++++++++++--- >> northd/ovn-northd.8.xml | 63 ++++-- >> ovn-nb.ovsschema | 5 +- >> ovn-nb.xml | 30 +++ >> tests/ovn-ic.at | 4 + >> tests/ovn-nbctl.at | 196 +++++++++++++++++- >> tests/ovn-northd.at | 76 ++++++- >> tests/ovn.at | 441 +++++++++++++++++++++++++++++++++++++++- >> utilities/ovn-nbctl.c | 134 +++++++++++- >> 9 files changed, 1041 insertions(+), 67 deletions(-) > > > The patch LGTM. > > I see that patch 3 has the NEWS item about this feature. But I think > that can be moved to this patch. > > Acked-by: Numan Siddique <[email protected] <mailto:[email protected]>> > > Numan > >> >> diff --git a/northd/northd.c b/northd/northd.c >> index d1b87891c..c238c6241 100644 >> --- a/northd/northd.c >> +++ b/northd/northd.c >> @@ -152,15 +152,16 @@ enum ovn_stage { >> PIPELINE_STAGE(ROUTER, IN, ECMP_STATEFUL, 7, "lr_in_ecmp_stateful") \ >> PIPELINE_STAGE(ROUTER, IN, ND_RA_OPTIONS, 8, "lr_in_nd_ra_options") \ >> PIPELINE_STAGE(ROUTER, IN, ND_RA_RESPONSE, 9, "lr_in_nd_ra_response") \ >> - PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 10, "lr_in_ip_routing") \ >> - PIPELINE_STAGE(ROUTER, IN, IP_ROUTING_ECMP, 11, >> "lr_in_ip_routing_ecmp") \ >> - PIPELINE_STAGE(ROUTER, IN, POLICY, 12, "lr_in_policy") \ >> - PIPELINE_STAGE(ROUTER, IN, POLICY_ECMP, 13, "lr_in_policy_ecmp") \ >> - PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 14, "lr_in_arp_resolve") \ >> - PIPELINE_STAGE(ROUTER, IN, CHK_PKT_LEN , 15, "lr_in_chk_pkt_len") \ >> - PIPELINE_STAGE(ROUTER, IN, LARGER_PKTS, 16, "lr_in_larger_pkts") \ >> - PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 17, "lr_in_gw_redirect") \ >> - PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 18, "lr_in_arp_request") \ >> + PIPELINE_STAGE(ROUTER, IN, IP_ROUTING_PRE, 10, >> "lr_in_ip_routing_pre") \ >> + PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 11, "lr_in_ip_routing") >> \ >> + PIPELINE_STAGE(ROUTER, IN, IP_ROUTING_ECMP, 12, >> "lr_in_ip_routing_ecmp") \ >> + PIPELINE_STAGE(ROUTER, IN, POLICY, 13, "lr_in_policy") >> \ >> + PIPELINE_STAGE(ROUTER, IN, POLICY_ECMP, 14, "lr_in_policy_ecmp") >> \ >> + PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 15, "lr_in_arp_resolve") >> \ >> + PIPELINE_STAGE(ROUTER, IN, CHK_PKT_LEN, 16, "lr_in_chk_pkt_len") >> \ >> + PIPELINE_STAGE(ROUTER, IN, LARGER_PKTS, 17, "lr_in_larger_pkts") >> \ >> + PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 18, "lr_in_gw_redirect") >> \ >> + PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 19, "lr_in_arp_request") >> \ >> \ >> /* Logical router egress stages. */ \ >> PIPELINE_STAGE(ROUTER, OUT, UNDNAT, 0, "lr_out_undnat") \ >> @@ -229,6 +230,7 @@ enum ovn_stage { >> #define REG_NEXT_HOP_IPV6 "xxreg0" >> #define REG_SRC_IPV4 "reg1" >> #define REG_SRC_IPV6 "xxreg1" >> +#define REG_ROUTE_TABLE_ID "reg7" >> >> #define REG_ORIG_TP_DPORT_ROUTER "reg9[16..31]" >> >> @@ -291,8 +293,9 @@ enum ovn_stage { >> * | R6 | UNUSED | X | | G | >> IN_IP_ROUTING)| >> * | | | R | | 1 | >> | >> * +-----+--------------------------+ E | UNUSED | | >> | >> - * | R7 | UNUSED | G | | | >> | >> - * | | | 3 | | | >> | >> + * | R7 | ROUTE_TABLE_ID | G | | | >> | >> + * | | (>= IN_IP_ROUTING_PRE && | 3 | | | >> | >> + * | | <= IN_IP_ROUTING) | | | | >> | >> * >> +-----+--------------------------+---+-----------------+---+---------------+ >> * | R8 | ECMP_GROUP_ID | | | >> * | | ECMP_MEMBER_ID | X | | >> @@ -8520,11 +8523,72 @@ cleanup: >> ds_destroy(&actions); >> } >> >> +static uint32_t >> +route_table_add(struct simap *route_tables, const char *route_table_name) >> +{ >> + /* route table ids start from 1 */ >> + uint32_t rtb_id = simap_count(route_tables) + 1; >> + >> + if (rtb_id == UINT16_MAX) { >> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); >> + VLOG_WARN_RL(&rl, "too many route tables for Logical Router."); >> + return 0; >> + } >> + >> + if (!simap_put(route_tables, route_table_name, rtb_id)) { >> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); >> + VLOG_WARN_RL(&rl, "Route table id unexpectedly appeared"); >> + } >> + >> + return rtb_id; >> +} >> + >> +static uint32_t >> +get_route_table_id(struct simap *route_tables, const char *route_table_name) >> +{ >> + if (!route_table_name || !strlen(route_table_name)) { >> + return 0; >> + } >> + >> + uint32_t rtb_id = simap_get(route_tables, route_table_name); >> + if (!rtb_id) { >> + rtb_id = route_table_add(route_tables, route_table_name); >> + } >> + >> + return rtb_id; >> +} >> + >> +static void >> +build_route_table_lflow(struct ovn_datapath *od, struct hmap *lflows, >> + struct nbrec_logical_router_port *lrp, >> + struct simap *route_tables) >> +{ >> + struct ds match = DS_EMPTY_INITIALIZER; >> + struct ds actions = DS_EMPTY_INITIALIZER; >> + >> + const char *route_table_name = smap_get(&lrp->options, "route_table"); >> + uint32_t rtb_id = get_route_table_id(route_tables, route_table_name); >> + if (!rtb_id) { >> + return; >> + } >> + >> + ds_put_format(&match, "inport == \"%s\"", lrp->name); >> + ds_put_format(&actions, "%s = %d; next;", >> + REG_ROUTE_TABLE_ID, rtb_id); >> + >> + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 100, >> + ds_cstr(&match), ds_cstr(&actions)); >> + >> + ds_destroy(&match); >> + ds_destroy(&actions); >> +} >> + >> struct parsed_route { >> struct ovs_list list_node; >> struct in6_addr prefix; >> unsigned int plen; >> bool is_src_route; >> + uint32_t route_table_id; >> uint32_t hash; >> const struct nbrec_logical_router_static_route *route; >> bool ecmp_symmetric_reply; >> @@ -8549,7 +8613,7 @@ find_static_route_outport(struct ovn_datapath *od, >> struct hmap *ports, >> * Otherwise return NULL. */ >> static struct parsed_route * >> parsed_routes_add(struct ovn_datapath *od, struct hmap *ports, >> - struct ovs_list *routes, >> + struct ovs_list *routes, struct simap *route_tables, >> const struct nbrec_logical_router_static_route *route, >> struct hmap *bfd_connections) >> { >> @@ -8631,6 +8695,7 @@ parsed_routes_add(struct ovn_datapath *od, struct hmap >> *ports, >> struct parsed_route *pr = xzalloc(sizeof *pr); >> pr->prefix = prefix; >> pr->plen = plen; >> + pr->route_table_id = get_route_table_id(route_tables, >> route->route_table); >> pr->is_src_route = (route->policy && !strcmp(route->policy, >> "src-ip")); >> pr->hash = route_hash(pr); >> @@ -8664,6 +8729,7 @@ struct ecmp_groups_node { >> struct in6_addr prefix; >> unsigned int plen; >> bool is_src_route; >> + uint32_t route_table_id; >> uint16_t route_count; >> struct ovs_list route_list; /* Contains ecmp_route_list_node */ >> }; >> @@ -8672,7 +8738,7 @@ static void >> ecmp_groups_add_route(struct ecmp_groups_node *group, >> const struct parsed_route *route) >> { >> - if (group->route_count == UINT16_MAX) { >> + if (group->route_count == UINT16_MAX) { >> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); >> VLOG_WARN_RL(&rl, "too many routes in a single ecmp group."); >> return; >> @@ -8701,6 +8767,7 @@ ecmp_groups_add(struct hmap *ecmp_groups, >> eg->prefix = route->prefix; >> eg->plen = route->plen; >> eg->is_src_route = route->is_src_route; >> + eg->route_table_id = route->route_table_id; >> ovs_list_init(&eg->route_list); >> ecmp_groups_add_route(eg, route); >> >> @@ -8714,7 +8781,8 @@ ecmp_groups_find(struct hmap *ecmp_groups, struct >> parsed_route *route) >> HMAP_FOR_EACH_WITH_HASH (eg, hmap_node, route->hash, ecmp_groups) { >> if (ipv6_addr_equals(&eg->prefix, &route->prefix) && >> eg->plen == route->plen && >> - eg->is_src_route == route->is_src_route) { >> + eg->is_src_route == route->is_src_route && >> + eg->route_table_id == route->route_table_id) { >> return eg; >> } >> } >> @@ -8761,7 +8829,8 @@ unique_routes_remove(struct hmap *unique_routes, >> HMAP_FOR_EACH_WITH_HASH (ur, hmap_node, route->hash, unique_routes) { >> if (ipv6_addr_equals(&route->prefix, &ur->route->prefix) && >> route->plen == ur->route->plen && >> - route->is_src_route == ur->route->is_src_route) { >> + route->is_src_route == ur->route->is_src_route && >> + route->route_table_id == ur->route->route_table_id) { >> hmap_remove(unique_routes, &ur->hmap_node); >> const struct parsed_route *existed_route = ur->route; >> free(ur); >> @@ -8799,9 +8868,9 @@ build_route_prefix_s(const struct in6_addr *prefix, >> unsigned int plen) >> } >> >> static void >> -build_route_match(const struct ovn_port *op_inport, const char *network_s, >> - int plen, bool is_src_route, bool is_ipv4, struct ds >> *match, >> - uint16_t *priority) >> +build_route_match(const struct ovn_port *op_inport, uint32_t rtb_id, >> + const char *network_s, int plen, bool is_src_route, >> + bool is_ipv4, struct ds *match, uint16_t *priority) >> { >> const char *dir; >> /* The priority here is calculated to implement longest-prefix-match >> @@ -8817,6 +8886,15 @@ build_route_match(const struct ovn_port *op_inport, >> const char *network_s, >> if (op_inport) { >> ds_put_format(match, "inport == %s && ", op_inport->json_key); >> } >> + if (rtb_id) { >> + ds_put_format(match, "%s == %d && ", REG_ROUTE_TABLE_ID, rtb_id); >> + } else { >> + /* Route-table assigned LRPs' routes should have lower priority >> + * in order not to affect directly-connected global routes. >> + * So, enlarge non-route-table routes priority by 100. >> + */ >> + *priority += 100; >> + } >> ds_put_format(match, "ip%s.%s == %s/%d", is_ipv4 ? "4" : "6", dir, >> network_s, plen); >> } >> @@ -8951,7 +9029,7 @@ add_ecmp_symmetric_reply_flows(struct hmap *lflows, >> out_port->lrp_networks.ea_s, >> IN6_IS_ADDR_V4MAPPED(&route->prefix) ? "" : "xx", >> port_ip, out_port->json_key); >> - ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 300, >> + ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING, 400, >> ds_cstr(&match), ds_cstr(&actions), >> &st_route->header_); >> >> @@ -8981,8 +9059,8 @@ build_ecmp_route_flow(struct hmap *lflows, struct >> ovn_datapath *od, >> struct ds route_match = DS_EMPTY_INITIALIZER; >> >> char *prefix_s = build_route_prefix_s(&eg->prefix, eg->plen); >> - build_route_match(NULL, prefix_s, eg->plen, eg->is_src_route, is_ipv4, >> - &route_match, &priority); >> + build_route_match(NULL, eg->route_table_id, prefix_s, eg->plen, >> + eg->is_src_route, is_ipv4, &route_match, &priority); >> free(prefix_s); >> >> struct ds actions = DS_EMPTY_INITIALIZER; >> @@ -9057,8 +9135,8 @@ static void >> add_route(struct hmap *lflows, struct ovn_datapath *od, >> const struct ovn_port *op, const char *lrp_addr_s, >> const char *network_s, int plen, const char *gateway, >> - bool is_src_route, const struct ovsdb_idl_row *stage_hint, >> - bool is_discard_route) >> + bool is_src_route, const uint32_t rtb_id, >> + const struct ovsdb_idl_row *stage_hint, bool is_discard_route) >> { >> bool is_ipv4 = strchr(network_s, '.') ? true : false; >> struct ds match = DS_EMPTY_INITIALIZER; >> @@ -9073,8 +9151,8 @@ add_route(struct hmap *lflows, struct ovn_datapath *od, >> op_inport = op; >> } >> } >> - build_route_match(op_inport, network_s, plen, is_src_route, is_ipv4, >> - &match, &priority); >> + build_route_match(op_inport, rtb_id, network_s, plen, is_src_route, >> + is_ipv4, &match, &priority); >> >> struct ds common_actions = DS_EMPTY_INITIALIZER; >> struct ds actions = DS_EMPTY_INITIALIZER; >> @@ -9137,7 +9215,8 @@ build_static_route_flow(struct hmap *lflows, struct >> ovn_datapath *od, >> char *prefix_s = build_route_prefix_s(&route_->prefix, route_->plen); >> add_route(lflows, route_->is_discard_route ? od : out_port->od, out_port, >> lrp_addr_s, prefix_s, route_->plen, route->nexthop, >> - route_->is_src_route, &route->header_, >> route_->is_discard_route); >> + route_->is_src_route, route_->route_table_id, &route->header_, >> + route_->is_discard_route); >> >> free(prefix_s); >> } >> @@ -10589,6 +10668,17 @@ build_ND_RA_flows_for_lrouter(struct ovn_datapath >> *od, struct hmap *lflows) >> } >> } >> >> +/* Logical router ingress table IP_ROUTING_PRE: >> + * by default goto next. (priority 0). */ >> +static void >> +build_ip_routing_pre_flows_for_lrouter(struct ovn_datapath *od, >> + struct hmap *lflows) >> +{ >> + if (od->nbr) { >> + ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_PRE, 0, "1", >> "next;"); >> + } >> +} >> + >> /* Logical router ingress table IP_ROUTING : IP Routing. >> * >> * A packet that arrives at this table is an IP packet that should be >> @@ -10614,14 +10704,14 @@ build_ip_routing_flows_for_lrouter_port( >> for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { >> add_route(lflows, op->od, op, >> op->lrp_networks.ipv4_addrs[i].addr_s, >> op->lrp_networks.ipv4_addrs[i].network_s, >> - op->lrp_networks.ipv4_addrs[i].plen, NULL, false, >> + op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0, >> &op->nbrp->header_, false); >> } >> >> for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { >> add_route(lflows, op->od, op, >> op->lrp_networks.ipv6_addrs[i].addr_s, >> op->lrp_networks.ipv6_addrs[i].network_s, >> - op->lrp_networks.ipv6_addrs[i].plen, NULL, false, >> + op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0, >> &op->nbrp->header_, false); >> } >> } else if (lsp_is_router(op->nbsp)) { >> @@ -10644,7 +10734,7 @@ build_ip_routing_flows_for_lrouter_port( >> add_route(lflows, peer->od, peer, >> peer->lrp_networks.ipv4_addrs[0].addr_s, >> laddrs->ipv4_addrs[k].network_s, >> - laddrs->ipv4_addrs[k].plen, NULL, false, >> + laddrs->ipv4_addrs[k].plen, NULL, false, 0, >> &peer->nbrp->header_, false); >> } >> } >> @@ -10664,10 +10754,17 @@ build_static_route_flows_for_lrouter( >> struct hmap ecmp_groups = HMAP_INITIALIZER(&ecmp_groups); >> struct hmap unique_routes = HMAP_INITIALIZER(&unique_routes); >> struct ovs_list parsed_routes = OVS_LIST_INITIALIZER(&parsed_routes); >> + struct simap route_tables = SIMAP_INITIALIZER(&route_tables); >> struct ecmp_groups_node *group; >> + >> + for (int i = 0; i < od->nbr->n_ports; i++) { >> + build_route_table_lflow(od, lflows, od->nbr->ports[i], >> + &route_tables); >> + } >> + >> for (int i = 0; i < od->nbr->n_static_routes; i++) { >> struct parsed_route *route = >> - parsed_routes_add(od, ports, &parsed_routes, >> + parsed_routes_add(od, ports, &parsed_routes, &route_tables, >> od->nbr->static_routes[i], >> bfd_connections); >> if (!route) { >> continue; >> @@ -10700,6 +10797,7 @@ build_static_route_flows_for_lrouter( >> ecmp_groups_destroy(&ecmp_groups); >> unique_routes_destroy(&unique_routes); >> parsed_routes_destroy(&parsed_routes); >> + simap_destroy(&route_tables); >> } >> } >> >> @@ -12804,6 +12902,7 @@ build_lswitch_and_lrouter_iterate_by_od(struct >> ovn_datapath *od, >> build_neigh_learning_flows_for_lrouter(od, lsi->lflows, &lsi->match, >> &lsi->actions, lsi->meter_groups); >> build_ND_RA_flows_for_lrouter(od, lsi->lflows); >> + build_ip_routing_pre_flows_for_lrouter(od, lsi->lflows); >> build_static_route_flows_for_lrouter(od, lsi->lflows, lsi->ports, >> lsi->bfd_connections); >> build_mcast_lookup_flows_for_lrouter(od, lsi->lflows, &lsi->match, >> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml >> index 39f4eaa0c..cc2e25367 100644 >> --- a/northd/ovn-northd.8.xml >> +++ b/northd/ovn-northd.8.xml >> @@ -2899,7 +2899,7 @@ icmp6 { >> >> <p> >> If ECMP routes with symmetric reply are configured in the >> - <code>OVN_Northbound</code> database for a gateway router, a >> priority-300 >> + <code>OVN_Northbound</code> database for a gateway router, a >> priority-400 >> flow is added for each router port on which symmetric replies are >> configured. The matching logic for these ports essentially reverses the >> configured logic of the ECMP route. So for instance, a route with a >> @@ -3245,7 +3245,35 @@ output; >> </li> >> </ul> >> >> - <h3>Ingress Table 10: IP Routing</h3> >> + <h3>Ingress Table 10: IP Routing Pre</h3> >> + >> + <p> >> + If a packet arrived at this table from Logical Router Port >> <var>P</var> >> + which has <code>options:route_table</code> value set, a logical flow >> with >> + match <code>inport == "<var>P</var>"</code> with priority 100 and >> action, >> + setting unique-generated per-datapath 32-bit value (non-zero) in OVS >> + register 7. This register is checked in next table. >> + </p> >> + >> + <p> >> + This table contains the following logical flows: >> + </p> >> + >> + <ul> >> + <li> >> + <p> >> + Priority-100 flow with match <code>inport == "LRP_NAME"</code> >> value >> + and action, which set route table identifier in reg7. >> + </p> >> + >> + <p> >> + A priority-0 logical flow with match <code>1</code> has actions >> + <code>next;</code>. >> + </p> >> + </li> >> + </ul> >> + >> + <h3>Ingress Table 11: IP Routing</h3> >> >> <p> >> A packet that arrives at this table is an IP packet that should be >> @@ -3316,10 +3344,10 @@ output; >> <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 >> - 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 in <var>M</var>, has the following actions: >> + <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 100 + the number of 1-bits in <var>M</var>, has the >> + following actions: >> </p> >> >> <pre> >> @@ -3382,6 +3410,13 @@ next; >> If the address <var>A</var> is in the link-local scope, the >> route will be limited to sending on the ingress port. >> </p> >> + >> + <p> >> + For routes with <code>route_table</code> value set >> + <code>reg7 == id</code> is prefixed in logical flow match portion. >> + Priority for routes with <code>route_table</code> value set is >> + the number of 1-bits in <var>M</var>. >> + </p> >> </li> >> >> <li> >> @@ -3408,7 +3443,7 @@ select(reg8[16..31], <var>MID1</var>, <var>MID2</var>, >> ...); >> </li> >> </ul> >> >> - <h3>Ingress Table 11: IP_ROUTING_ECMP</h3> >> + <h3>Ingress Table 12: IP_ROUTING_ECMP</h3> >> >> <p> >> This table implements the second part of IP routing for ECMP routes >> @@ -3460,7 +3495,7 @@ outport = <var>P</var>; >> </li> >> </ul> >> >> - <h3>Ingress Table 12: Router policies</h3> >> + <h3>Ingress Table 13: Router policies</h3> >> <p> >> This table adds flows for the logical router policies configured >> on the logical router. Please see the >> @@ -3532,7 +3567,7 @@ next; >> </li> >> </ul> >> >> - <h3>Ingress Table 13: ECMP handling for router policies</h3> >> + <h3>Ingress Table 14: ECMP handling for router policies</h3> >> <p> >> This table handles the ECMP for the router policies configured >> with multiple nexthops. >> @@ -3576,7 +3611,7 @@ outport = <var>P</var> >> </li> >> </ul> >> >> - <h3>Ingress Table 14: ARP/ND Resolution</h3> >> + <h3>Ingress Table 15: ARP/ND Resolution</h3> >> >> <p> >> Any packet that reaches this table is an IP packet whose next-hop >> @@ -3767,7 +3802,7 @@ outport = <var>P</var> >> >> </ul> >> >> - <h3>Ingress Table 15: Check packet length</h3> >> + <h3>Ingress Table 16: Check packet length</h3> >> >> <p> >> For distributed logical routers or gateway routers with gateway >> @@ -3797,7 +3832,7 @@ REGBIT_PKT_LARGER = check_pkt_larger(<var>L</var>); >> next; >> and advances to the next table. >> </p> >> >> - <h3>Ingress Table 16: Handle larger packets</h3> >> + <h3>Ingress Table 17: Handle larger packets</h3> >> >> <p> >> For distributed logical routers or gateway routers with gateway port >> @@ -3860,7 +3895,7 @@ icmp6 { >> and advances to the next table. >> </p> >> >> - <h3>Ingress Table 17: Gateway Redirect</h3> >> + <h3>Ingress Table 18: Gateway Redirect</h3> >> >> <p> >> For distributed logical routers where one or more of the logical router >> @@ -3907,7 +3942,7 @@ icmp6 { >> </li> >> </ul> >> >> - <h3>Ingress Table 18: ARP Request</h3> >> + <h3>Ingress Table 19: ARP Request</h3> >> >> <p> >> In the common case where the Ethernet destination has been resolved, >> this >> diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema >> index 2ac8ef3ea..a0a171e19 100644 >> --- a/ovn-nb.ovsschema >> +++ b/ovn-nb.ovsschema >> @@ -1,7 +1,7 @@ >> { >> "name": "OVN_Northbound", >> - "version": "5.32.1", >> - "cksum": "2805328215 29734", >> + "version": "5.33.1", >> + "cksum": "3874993350 29785", >> "tables": { >> "NB_Global": { >> "columns": { >> @@ -387,6 +387,7 @@ >> "isRoot": false}, >> "Logical_Router_Static_Route": { >> "columns": { >> + "route_table": {"type": "string"}, >> "ip_prefix": {"type": "string"}, >> "policy": {"type": {"key": {"type": "string", >> "enum": ["set", ["src-ip", >> diff --git a/ovn-nb.xml b/ovn-nb.xml >> index 390cc5a44..99fa78c90 100644 >> --- a/ovn-nb.xml >> +++ b/ovn-nb.xml >> @@ -2772,6 +2772,14 @@ >> prefix according to RFC3663 >> </p> >> </column> >> + >> + <column name="options" key="route_table"> >> + Designates lookup Logical_Router_Static_Routes with specified >> + <code>route_table</code> value. Routes to directly connected >> networks >> + from same Logical Router and routes without <code>route_table</code> >> + option set have higher priority than routes with >> + <code>route_table</code> option set. >> + </column> >> </group> >> >> <group title="Attachment"> >> @@ -2891,6 +2899,28 @@ >> </p> >> </column> >> >> + <column name="route_table"> >> + <p> >> + Any string to place route to separate routing table. If Logical >> Router >> + Port has configured value in <ref table="Logical_Router_Port" >> + column="options" key="route_table"/> other than empty string, OVN >> + performs route lookup for all packets entering Logical Router >> ingress >> + pipeline from this port in the following manner: >> + </p> >> + >> + <ul> >> + <li> >> + 1. First lookup among "global" routes: routes without >> + <code>route_table</code> value set and routes to directly >> connected >> + networks. >> + </li> >> + <li> >> + 2. Next lookup among routes with same <code>route_table</code> >> value >> + as specified in LRP's options:route_table field. >> + </li> >> + </ul> >> + </column> >> + >> <column name="external_ids" key="ic-learned-route"> >> <code>ovn-ic</code> populates this key if the route is learned from the >> global <ref db="OVN_IC_Southbound"/> database. In this case the value >> diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at >> index 32f4e9d02..3aab54362 100644 >> --- a/tests/ovn-ic.at >> +++ b/tests/ovn-ic.at >> @@ -281,6 +281,7 @@ done >> >> AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.11.1.0/24 169.254.0.1 dst-ip >> 10.11.2.0/24 169.254.100.2 dst-ip (learned) >> 10.22.1.0/24 169.254.0.2 src-ip >> @@ -299,6 +300,7 @@ ovn_as az1 ovn-nbctl set nb_global . >> options:ic-route-learn=false >> OVS_WAIT_WHILE([ovn_as az1 ovn-nbctl lr-route-list lr1 | grep learned]) >> AT_CHECK([ovn_as az1 ovn-nbctl lr-route-list lr1], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.11.1.0/24 169.254.0.1 dst-ip >> 10.22.1.0/24 169.254.0.2 src-ip >> ]) >> @@ -314,6 +316,7 @@ ovn_as az1 ovn-nbctl set nb_global . >> options:ic-route-adv=false >> OVS_WAIT_WHILE([ovn_as az2 ovn-nbctl lr-route-list lr2 | grep learned]) >> AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.11.2.0/24 169.254.0.1 dst-ip >> 10.22.2.0/24 169.254.0.2 src-ip >> ]) >> @@ -332,6 +335,7 @@ done >> # Default route should NOT get advertised or learned, by default. >> AT_CHECK([ovn_as az2 ovn-nbctl lr-route-list lr2], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.11.1.0/24 169.254.100.1 dst-ip (learned) >> 10.11.2.0/24 169.254.0.1 dst-ip >> 10.22.2.0/24 169.254.0.2 src-ip >> diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at >> index 9b80ae410..ddb5536ce 100644 >> --- a/tests/ovn-nbctl.at >> +++ b/tests/ovn-nbctl.at >> @@ -1520,6 +1520,7 @@ AT_CHECK([ovn-nbctl --ecmp --policy=src-ip >> lr-route-add lr0 20.0.0.0/24 11.0.0.1 >> >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.1 dst-ip >> 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> 10.0.10.0/24 dst-ip lp0 >> @@ -1534,6 +1535,7 @@ AT_CHECK([ovn-nbctl lrp-add lr0 lp1 f0:00:00:00:00:02 >> 11.0.0.254/24]) >> AT_CHECK([ovn-nbctl --may-exist lr-route-add lr0 10.0.0.111/24 11.0.0.1 lp1]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.1 dst-ip lp1 >> 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> 10.0.10.0/24 dst-ip lp0 >> @@ -1564,6 +1566,7 @@ AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 >> 9.16.1.0/24]) >> >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.1 dst-ip lp1 >> 10.0.10.0/24 dst-ip lp0 >> 10.0.0.0/24 11.0.0.2 src-ip >> @@ -1575,6 +1578,7 @@ AT_CHECK([ovn-nbctl --policy=dst-ip lr-route-del lr0 >> 10.0.0.0/24]) >> AT_CHECK([ovn-nbctl --policy=src-ip lr-route-del lr0 10.0.0.0/24]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.10.0/24 dst-ip lp0 >> 0.0.0.0/0 192.168.0.1 dst-ip >> ]) >> @@ -1585,6 +1589,7 @@ AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 >> 10.0.0.0/24 11.0.0.2]) >> AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.10.0/24 dst-ip lp0 >> 0.0.0.0/0 192.168.0.1 dst-ip >> ]) >> @@ -1601,6 +1606,7 @@ AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 >> 10.0.0.0/24 11.0.0.3]) >> AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 10.0.0.0/24 11.0.0.4 lp0]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.1 dst-ip ecmp >> 10.0.0.0/24 11.0.0.2 dst-ip ecmp >> 10.0.0.0/24 11.0.0.3 dst-ip ecmp >> @@ -1615,6 +1621,7 @@ dnl Delete ecmp routes >> AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.1]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.2 dst-ip ecmp >> 10.0.0.0/24 11.0.0.3 dst-ip ecmp >> 10.0.0.0/24 11.0.0.4 dst-ip lp0 ecmp >> @@ -1622,12 +1629,14 @@ IPv4 Routes >> AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.2]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.3 dst-ip ecmp >> 10.0.0.0/24 11.0.0.4 dst-ip lp0 ecmp >> ]) >> AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.4 lp0]) >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.3 dst-ip >> ]) >> AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.0.0/24 11.0.0.3]) >> @@ -1641,6 +1650,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 >> 2001:0db8:0:f103::1]) >> >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv6 Routes >> +Route Table global: >> 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> ::/0 2001:db8:0:f101::1 dst-ip >> @@ -1650,6 +1660,7 @@ AT_CHECK([ovn-nbctl lr-route-del lr0 2001:0db8:0::/64]) >> >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv6 Routes >> +Route Table global: >> 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> ::/0 2001:db8:0:f101::1 dst-ip >> ]) >> @@ -1677,11 +1688,13 @@ AT_CHECK([ovn-nbctl --may-exist >> --ecmp-symmetric-reply lr-route-add lr0 2003:0db >> >> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> IPv4 Routes >> +Route Table global: >> 10.0.0.0/24 11.0.0.1 dst-ip >> 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> 0.0.0.0/0 192.168.0.1 dst-ip >> >> IPv6 Routes >> +Route Table global: >> 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip ecmp >> 2001:db8:1::/64 2001:db8:0:f103::2 dst-ip ecmp >> @@ -1696,7 +1709,188 @@ AT_CHECK([ovn-nbctl lrp-add lr0 lr0-p0 >> 00:00:01:01:02:03 192.168.10.1/24]) >> bfd_uuid=$(ovn-nbctl create bfd logical_port=lr0-p0 dst_ip=100.0.0.50 >> status=down min_tx=250 min_rx=250 detect_mult=10) >> AT_CHECK([ovn-nbctl lr-route-add lr0 100.0.0.0/24 192.168.0.1]) >> route_uuid=$(fetch_column nb:logical_router_static_route _uuid >> ip_prefix="100.0.0.0/24") >> -AT_CHECK([ovn-nbctl set logical_router_static_route $route_uuid >> bfd=$bfd_uuid])]) >> +AT_CHECK([ovn-nbctl set logical_router_static_route $route_uuid >> bfd=$bfd_uuid]) >> + >> +check ovn-nbctl lr-route-del lr0 >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +]) >> + >> +dnl Check IPv4 routes in route table >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 0.0.0.0/0 192.168.0.1 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.1.1/24 11.0.1.1 >> lp0 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.0.1/24 11.0.0.1 >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +IPv4 Routes >> +Route Table rtb-1: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> +]) >> + >> +check ovn-nbctl lr-route-del lr0 >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +]) >> + >> +dnl Check IPv6 routes in route table >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 0:0:0:0:0:0:0:0/0 >> 2001:0db8:0:f101::1 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 2001:0db8:0::/64 >> 2001:0db8:0:f102::1 lp0 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 2001:0db8:1::/64 >> 2001:0db8:0:f103::1 >> + >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +IPv6 Routes >> +Route Table rtb-1: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> +]) >> + >> +dnl Check IPv4 and IPv6 routes in route table >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 0.0.0.0/0 192.168.0.1 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.1.1/24 11.0.1.1 >> lp0 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 10.0.0.1/24 11.0.0.1 >> + >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +IPv4 Routes >> +Route Table rtb-1: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +IPv6 Routes >> +Route Table rtb-1: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> +]) >> + >> +# Add routes in another route table >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 0.0.0.0/0 192.168.0.1 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 10.0.1.1/24 11.0.1.1 >> lp0 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 10.0.0.1/24 11.0.0.1 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 0:0:0:0:0:0:0:0/0 >> 2001:0db8:0:f101::1 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 2001:0db8:0::/64 >> 2001:0db8:0:f102::1 lp0 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 2001:0db8:1::/64 >> 2001:0db8:0:f103::1 >> + >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +IPv4 Routes >> +Route Table rtb-1: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +Route Table rtb-2: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +IPv6 Routes >> +Route Table rtb-1: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> + >> +Route Table rtb-2: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> +]) >> + >> +# Add routes to global route table >> +check ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.1 >> +check ovn-nbctl lr-route-add lr0 10.0.1.1/24 11.0.1.1 lp0 >> +check ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.1 >> +check ovn-nbctl lr-route-add lr0 0:0:0:0:0:0:0:0/0 2001:0db8:0:f101::1 >> +check ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 2001:0db8:0:f102::1 lp0 >> +check check ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1 >> + >> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >> +IPv4 Routes >> +Route Table global: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +Route Table rtb-1: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +Route Table rtb-2: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +IPv6 Routes >> +Route Table global: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> + >> +Route Table rtb-1: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> + >> +Route Table rtb-2: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> +]) >> + >> +# delete IPv4 route from rtb-1 >> +check ovn-nbctl --route-table=rtb-1 lr-route-del lr0 10.0.0.0/24 >> +AT_CHECK([ovn-nbctl --route-table=rtb-1 lr-route-list lr0], [0], [dnl >> +IPv4 Routes >> +Route Table rtb-1: >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +IPv6 Routes >> +Route Table rtb-1: >> + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> +]) >> + >> +# delete IPv6 route from rtb-2 >> +check ovn-nbctl --route-table=rtb-2 lr-route-del lr0 2001:db8::/64 >> +AT_CHECK([ovn-nbctl --route-table=rtb-2 lr-route-list lr0], [0], [dnl >> +IPv4 Routes >> +Route Table rtb-2: >> + 10.0.0.0/24 11.0.0.1 dst-ip >> + 10.0.1.0/24 11.0.1.1 dst-ip lp0 >> + 0.0.0.0/0 192.168.0.1 dst-ip >> + >> +IPv6 Routes >> +Route Table rtb-2: >> + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip >> + ::/0 2001:db8:0:f101::1 dst-ip >> +]) >> + >> +check ovn-nbctl lr-route-del lr0 >> + >> +# ECMP route in route table >> +check ovn-nbctl --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 192.168.0.1 >> +check ovn-nbctl --ecmp --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 >> 192.168.0.2 >> + >> +# Negative route table case: same prefix >> +AT_CHECK([ovn-nbctl --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 >> 192.168.0.1], [1], [], [dnl >> +ovn-nbctl: duplicate prefix: 0.0.0.0/0 (policy: dst-ip). Use option --ecmp >> to allow this for ECMP routing. >> +]) >> + >> +# Negative route table case: same prefix & nexthop with ecmp >> +AT_CHECK([ovn-nbctl --ecmp --route-table=rtb1 lr-route-add lr0 0.0.0.0/0 >> 192.168.0.2], [1], [], [dnl >> +ovn-nbctl: duplicate nexthop for the same ECMP route >> +]) >> + >> +# Add routes to global route table >> +check ovn-nbctl lrp-add lr0 lrp0 00:00:00:00:00:01 1.1.1.1/24 >> +check ovn-nbctl lrp-set-options lrp0 route_table=rtb1 >> +AT_CHECK([ovn-nbctl get logical-router-port lrp0 options:route_table], [0], >> [dnl >> +rtb1 >> +]) >> +check `ovn-nbctl show lr0 | grep lrp0 -A3 | grep route_table=rtb1` >> +]) >> >> dnl --------------------------------------------------------------------- >> >> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at >> index 5de554455..e6037b045 100644 >> --- a/tests/ovn-northd.at >> +++ b/tests/ovn-northd.at >> @@ -5102,7 +5102,7 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-reply >> lr-route-add lr0 1.0.0.1 192.16 >> >> ovn-sbctl dump-flows lr0 > lr0flows >> AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows | sed >> 's/table=../table=??/' | sort], [0], [dnl >> - table=??(lr_in_ip_routing ), priority=65 , match=(ip4.dst == >> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; >> reg8[[16..31]] = select(1, 2);) >> + table=??(lr_in_ip_routing ), priority=165 , match=(ip4.dst == >> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; >> reg8[[16..31]] = select(1, 2);) >> ]) >> AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed >> 's/192\.168\.0\..0/192.168.0.??/' | sed 's/table=../table=??/' | sort], [0], >> [dnl >> table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 >> && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; >> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) >> @@ -5115,7 +5115,7 @@ check ovn-nbctl --wait=sb --ecmp-symmetric-reply >> lr-route-add lr0 1.0.0.1 192.16 >> >> ovn-sbctl dump-flows lr0 > lr0flows >> AT_CHECK([grep -e "lr_in_ip_routing.*select" lr0flows | sed >> 's/table=../table=??/' | sort], [0], [dnl >> - table=??(lr_in_ip_routing ), priority=65 , match=(ip4.dst == >> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; >> reg8[[16..31]] = select(1, 2);) >> + table=??(lr_in_ip_routing ), priority=165 , match=(ip4.dst == >> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; >> reg8[[16..31]] = select(1, 2);) >> ]) >> AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed >> 's/192\.168\.0\..0/192.168.0.??/' | sed 's/table=../table=??/' | sort], [0], >> [dnl >> table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 >> && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg1 = 192.168.0.1; >> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) >> @@ -5130,14 +5130,14 @@ check ovn-nbctl --wait=sb lr-route-add lr0 >> 1.0.0.0/24 192.168.0.10 >> ovn-sbctl dump-flows lr0 > lr0flows >> >> AT_CHECK([grep -e "lr_in_ip_routing.*192.168.0.10" lr0flows | sed >> 's/table=../table=??/' | sort], [0], [dnl >> - table=??(lr_in_ip_routing ), priority=49 , match=(ip4.dst == >> 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 >> = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; >> flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == >> 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 >> = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; >> flags.loopback = 1; next;) >> ]) >> >> check ovn-nbctl --wait=sb lr-route-add lr0 2.0.0.0/24 lr0-public >> >> ovn-sbctl dump-flows lr0 > lr0flows >> AT_CHECK([grep -e "lr_in_ip_routing.*2.0.0.0" lr0flows | sed >> 's/table=../table=??/' | sort], [0], [dnl >> - table=??(lr_in_ip_routing ), priority=49 , match=(ip4.dst == >> 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = >> 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; >> flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == >> 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = >> 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; >> flags.loopback = 1; next;) >> ]) >> >> AT_CLEANUP >> @@ -5223,3 +5223,71 @@ AT_CHECK([grep lr_in_gw_redirect lrflows | grep cr-DR >> | sed 's/table=../table=?? >> >> AT_CLEANUP >> ]) >> + >> + >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([route tables -- flows]) >> +AT_KEYWORDS([route-tables-flows]) >> +ovn_start >> + >> +check ovn-nbctl lr-add lr0 >> +check ovn-nbctl lrp-add lr0 lrp0 00:00:00:00:00:01 192.168.0.1/24 >> +check ovn-nbctl lrp-add lr0 lrp1 00:00:00:00:01:01 192.168.1.1/24 >> +check ovn-nbctl lrp-add lr0 lrp2 00:00:00:00:02:01 192.168.2.1/24 >> +check ovn-nbctl lrp-set-options lrp1 route_table=rtb-1 >> +check ovn-nbctl lrp-set-options lrp2 route_table=rtb-2 >> + >> +check ovn-nbctl lr-route-add lr0 0.0.0.0/0 192.168.0.10 >> +check ovn-nbctl --route-table=rtb-1 lr-route-add lr0 192.168.0.0/24 >> 192.168.1.10 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 0.0.0.0/0 192.168.0.10 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 1.1.1.1/32 192.168.0.20 >> +check ovn-nbctl --route-table=rtb-2 lr-route-add lr0 2.2.2.2/32 192.168.0.30 >> +check ovn-nbctl --route-table=rtb-2 --ecmp lr-route-add lr0 2.2.2.2/32 >> 192.168.0.31 >> +check ovn-nbctl --wait=sb sync >> + >> +ovn-sbctl dump-flows lr0 > lr0flows >> +AT_CAPTURE_FILE([lr0flows]) >> + >> +AT_CHECK([grep -e "lr_in_ip_routing_pre.*match=(1)" lr0flows | sed >> 's/table=../table=??/'], [0], [dnl >> + table=??(lr_in_ip_routing_pre), priority=0 , match=(1), action=(next;) >> +]) >> + >> +p1_reg=$(grep -oP "lr_in_ip_routing_pre.*lrp1.*action=\(reg7 = \K." >> lr0flows) >> +p2_reg=$(grep -oP "lr_in_ip_routing_pre.*lrp2.*action=\(reg7 = \K." >> lr0flows) >> +echo $p1_reg >> +echo $p2_reg >> + >> +# exact register values are not predictable >> +if [[ $p1_reg -eq 2 ] && [ $p2_reg -eq 1 ]]; then >> + echo "swap reg values in dump" >> + sed -i -r s'/^(.*lrp2.*action=\(reg7 = )(1)(.*)/\12\3/g' lr0flows # >> "reg7 = 1" -> "reg7 = 2" >> + sed -i -r s'/^(.*lrp1.*action=\(reg7 = )(2)(.*)/\11\3/g' lr0flows # >> "reg7 = 2" -> "reg7 = 1" >> + sed -i -r s'/^(.*match=\(reg7 == )(2)( &&.*lrp1.*)/\11\3/g' lr0flows # >> "reg7 == 2" -> "reg7 == 1" >> + sed -i -r s'/^(.*match=\(reg7 == )(1)( &&.*lrp0.*)/\12\3/g' lr0flows # >> "reg7 == 1" -> "reg7 == 2" >> +fi >> + >> +check test "$p1_reg" != "$p2_reg" -a $((p1_reg * p2_reg)) -eq 2 >> + >> +AT_CHECK([grep "lr_in_ip_routing_pre" lr0flows | sed 's/table=../table=??/' >> | sort], [0], [dnl >> + table=??(lr_in_ip_routing_pre), priority=0 , match=(1), action=(next;) >> + table=??(lr_in_ip_routing_pre), priority=100 , match=(inport == "lrp1"), >> action=(reg7 = 1; next;) >> + table=??(lr_in_ip_routing_pre), priority=100 , match=(inport == "lrp2"), >> action=(reg7 = 2; next;) >> +]) >> + >> +grep -e "(lr_in_ip_routing ).*outport" lr0flows >> + >> +AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | sed >> 's/table=../table=??/' | sort], [0], [dnl >> + table=??(lr_in_ip_routing ), priority=1 , match=(reg7 == 2 && >> ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >> 192.168.0.10; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = >> "lrp0"; flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=101 , match=(ip4.dst == >> 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg1 = >> 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = >> 1; next;) >> + table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == >> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = >> 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = >> 1; next;) >> + table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == >> 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = >> 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = >> 1; next;) >> + table=??(lr_in_ip_routing ), priority=149 , match=(ip4.dst == >> 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg1 = >> 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = >> 1; next;) >> + table=??(lr_in_ip_routing ), priority=229 , match=(inport == "lrp0" && >> ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = >> ip6.dst; xxreg1 = fe80::200:ff:fe00:1; eth.src = 00:00:00:00:00:01; outport >> = "lrp0"; flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=229 , match=(inport == "lrp1" && >> ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = >> ip6.dst; xxreg1 = fe80::200:ff:fe00:101; eth.src = 00:00:00:00:01:01; >> outport = "lrp1"; flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=229 , match=(inport == "lrp2" && >> ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = >> ip6.dst; xxreg1 = fe80::200:ff:fe00:201; eth.src = 00:00:00:00:02:01; >> outport = "lrp2"; flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=49 , match=(reg7 == 1 && >> ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >> 192.168.1.10; reg1 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = >> "lrp1"; flags.loopback = 1; next;) >> + table=??(lr_in_ip_routing ), priority=65 , match=(reg7 == 2 && >> ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >> 192.168.0.20; reg1 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = >> "lrp0"; flags.loopback = 1; next;) >> +]) >> + >> +AT_CLEANUP >> +]) >> diff --git a/tests/ovn.at b/tests/ovn.at >> index d76f4ba86..8ca3bb222 100644 >> --- a/tests/ovn.at >> +++ b/tests/ovn.at >> @@ -18079,7 +18079,7 @@ eth_dst=00000000ff01 >> ip_src=$(ip_to_hex 10 0 0 10) >> ip_dst=$(ip_to_hex 172 168 0 101) >> send_icmp_packet 1 1 $eth_src $eth_dst $ip_src $ip_dst c4c9 >> 0000000000000000000000 >> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | awk '/table=25, n_packets=1, >> n_bytes=45/{print $7" "$8}'],[0],[dnl >> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | awk '/table=26, n_packets=1, >> n_bytes=45/{print $7" "$8}'],[0],[dnl >> priority=80,ip,reg15=0x3,metadata=0x3,nw_src=10.0.0.10 actions=drop >> ]) >> >> @@ -22263,6 +22263,433 @@ OVN_CLEANUP([hv1]) >> AT_CLEANUP >> ]) >> >> + >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([route tables -- global routes]) >> +ovn_start >> + >> +# Logical network: >> +# ls1 (192.168.1.0/24) - lrp-lr1-ls1 - lr1 - lrp-lr1-ls2 - ls2 >> (192.168.2.0/24) >> +# >> +# ls1 has lsp11 (192.168.1.11) and ls2 has lsp21 (192.168.2.21) and lsp22 >> +# (192.168.2.22) >> +# >> +# lrp-lr1-ls1 set options:route_table=rtb-1 >> +# >> +# Static routes on lr1: >> +# 0.0.0.0/0 nexthop 192.168.2.21 >> +# 1.1.1.1/32 nexthop 192.168.2.22 route_table=rtb-1 >> +# >> +# Test 1: >> +# lsp11 send packet to 2.2.2.2 >> +# >> +# Expected result: >> +# lsp21 should receive traffic, lsp22 should not receive any traffic >> +# >> +# Test 2: >> +# lsp11 send packet to 1.1.1.1 >> +# >> +# Expected result: >> +# lsp21 should receive traffic, lsp22 should not receive any traffic >> + >> +ovn-nbctl lr-add lr1 >> + >> +for i in 1 2; do >> + ovn-nbctl ls-add ls${i} >> + ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 >> 192.168.${i}.1/24 >> + ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 >> router \ >> + -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \ >> + -- lsp-set-addresses lsp-ls${i}-lr1 router >> +done >> + >> +# install static routes >> +ovn-nbctl lr-route-add lr1 0.0.0.0/0 192.168.2.21 >> +ovn-nbctl --route-table=rtb-1 lr-route-add lr1 1.1.1.1/32 192.168.2.22 >> + >> +# set lrp-lr1-ls1 route table >> +ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1 >> + >> +# Create logical ports >> +ovn-nbctl lsp-add ls1 lsp11 -- \ >> + lsp-set-addresses lsp11 "f0:00:00:00:01:11 192.168.1.11" >> +ovn-nbctl lsp-add ls2 lsp21 -- \ >> + lsp-set-addresses lsp21 "f0:00:00:00:02:21 192.168.2.21" >> +ovn-nbctl lsp-add ls2 lsp22 -- \ >> + lsp-set-addresses lsp22 "f0:00:00:00:02:22 192.168.2.22" >> + >> +net_add n1 >> +sim_add hv1 >> +as hv1 >> +ovs-vsctl add-br br-phys >> +ovn_attach n1 br-phys 192.168.0.1 >> +ovs-vsctl -- add-port br-int hv1-vif1 -- \ >> + set interface hv1-vif1 external-ids:iface-id=lsp11 \ >> + options:tx_pcap=hv1/vif1-tx.pcap \ >> + options:rxq_pcap=hv1/vif1-rx.pcap \ >> + ofport-request=1 >> + >> +ovs-vsctl -- add-port br-int hv1-vif2 -- \ >> + set interface hv1-vif2 external-ids:iface-id=lsp21 \ >> + options:tx_pcap=hv1/vif2-tx.pcap \ >> + options:rxq_pcap=hv1/vif2-rx.pcap \ >> + ofport-request=2 >> + >> +ovs-vsctl -- add-port br-int hv1-vif3 -- \ >> + set interface hv1-vif3 external-ids:iface-id=lsp22 \ >> + options:tx_pcap=hv1/vif3-tx.pcap \ >> + options:rxq_pcap=hv1/vif3-rx.pcap \ >> + ofport-request=3 >> + >> +# wait for earlier changes to take effect >> +check ovn-nbctl --wait=hv sync >> +wait_for_ports_up >> + >> +for i in 1 2; do >> + packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && >> eth.dst==00:00:00:01:01:01 && >> + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && >> ip4.dst==$i.$i.$i.$i && icmp" >> + AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) >> + >> + # Assume all packets go to lsp21. >> + exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 && >> + ip4 && ip.ttl==63 && ip4.src==192.168.1.11 && >> ip4.dst==$i.$i.$i.$i && icmp" >> + echo $exp_packet | ovstest test-ovn expr-to-packets >> expected_lsp21 >> +done >> +> expected_lsp22 >> + >> +# lsp21 should recieve 2 packets and lsp22 should recieve no packets >> +OVS_WAIT_UNTIL([ >> + rcv_n1=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > >> lsp21.packets && cat lsp21.packets | wc -l` >> + rcv_n2=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif3-tx.pcap > >> lsp22.packets && cat lsp22.packets | wc -l` >> + echo $rcv_n1 $rcv_n2 >> + test $rcv_n1 -eq 2 -a $rcv_n2 -eq 0]) >> + >> +for i in 1 2; do >> + sort expected_lsp2$i > expout >> + AT_CHECK([cat lsp2${i}.packets | sort], [0], [expout]) >> +done >> + >> +OVN_CLEANUP([hv1]) >> +AT_CLEANUP >> +]) >> + >> + >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([route tables -- directly connected routes]) >> +ovn_start >> + >> +# Logical network: >> +# ls1 (192.168.1.0/24) - lrp-lr1-ls1 - lr1 - lrp-lr1-ls2 - ls2 >> (192.168.2.0/24) >> +# >> +# ls1 has lsp11 (192.168.1.11) and ls2 has lsp21 (192.168.2.21) >> +# >> +# lrp-lr1-ls1 set options:route_table=rtb-1 >> +# >> +# Static routes on lr1: >> +# 192.168.2.0/25 nexthop 192.168.1.11 route_table=rtb-1 >> +# >> +# Test 1: >> +# lsp11 send packet to 192.168.2.21 >> +# >> +# Expected result: >> +# lsp21 should receive traffic, lsp11 should not receive any traffic >> + >> +ovn-nbctl lr-add lr1 >> + >> +for i in 1 2; do >> + ovn-nbctl ls-add ls${i} >> + ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 >> 192.168.${i}.1/24 >> + ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 >> router \ >> + -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \ >> + -- lsp-set-addresses lsp-ls${i}-lr1 router >> +done >> + >> +# install static route, which overrides directly-connected routes >> +ovn-nbctl --route-table=rtb-1 lr-route-add lr1 192.168.2.0/25 192.168.1.11 >> + >> +# set lrp-lr1-ls1 route table >> +ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1 >> + >> +# Create logical ports >> +ovn-nbctl lsp-add ls1 lsp11 -- \ >> + lsp-set-addresses lsp11 "f0:00:00:00:01:11 192.168.1.11" >> +ovn-nbctl lsp-add ls2 lsp21 -- \ >> + lsp-set-addresses lsp21 "f0:00:00:00:02:21 192.168.2.21" >> + >> +net_add n1 >> +sim_add hv1 >> +as hv1 >> +ovs-vsctl add-br br-phys >> +ovn_attach n1 br-phys 192.168.0.1 >> +ovs-vsctl -- add-port br-int hv1-vif1 -- \ >> + set interface hv1-vif1 external-ids:iface-id=lsp11 \ >> + options:tx_pcap=hv1/vif1-tx.pcap \ >> + options:rxq_pcap=hv1/vif1-rx.pcap \ >> + ofport-request=1 >> + >> +ovs-vsctl -- add-port br-int hv1-vif2 -- \ >> + set interface hv1-vif2 external-ids:iface-id=lsp21 \ >> + options:tx_pcap=hv1/vif2-tx.pcap \ >> + options:rxq_pcap=hv1/vif2-rx.pcap \ >> + ofport-request=2 >> + >> +# wait for earlier changes to take effect >> +check ovn-nbctl --wait=hv sync >> +wait_for_ports_up >> + >> +packet="inport==\"lsp11\" && eth.src==f0:00:00:00:01:11 && >> eth.dst==00:00:00:01:01:01 && >> + ip4 && ip.ttl==64 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.21 >> && icmp" >> +AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) >> + >> +# Assume all packets go to lsp21. >> +exp_packet="eth.src==00:00:00:01:02:01 && eth.dst==f0:00:00:00:02:21 && >> + ip4 && ip.ttl==63 && ip4.src==192.168.1.11 && ip4.dst==192.168.2.21 >> && icmp" >> +echo $exp_packet | ovstest test-ovn expr-to-packets >> expected_lsp21 >> +> expected_lsp11 >> + >> +# lsp21 should recieve 1 icmp packet and lsp11 should recieve no packets >> +OVS_WAIT_UNTIL([ >> + rcv_n11=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > >> lsp11.packets && cat lsp11.packets | wc -l` >> + rcv_n21=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > >> lsp21.packets && cat lsp21.packets | wc -l` >> + echo $rcv_n11 $rcv_n21 >> + test $rcv_n11 -eq 0 -a $rcv_n21 -eq 1]) >> + >> +for i in 11 21; do >> + sort expected_lsp$i > expout >> + AT_CHECK([cat lsp${i}.packets | sort], [0], [expout]) >> +done >> + >> +OVN_CLEANUP([hv1]) >> +AT_CLEANUP >> +]) >> + >> + >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([route tables -- overlapping subnets]) >> +ovn_start >> + >> +# Logical network: >> +# >> +# ls1 (192.168.1.0/24) - lrp-lr1-ls1 -\ /- lrp-lr1-ls2 - ls2 >> (192.168.2.0/24) >> +# lr1 >> +# ls3 (192.168.3.0/24) - lrp-lr1-ls3 -/ \- lrp-lr1-ls4 - ls4 >> (192.168.4.0/24) >> +# >> +# ls1 has lsp11 (192.168.1.11) >> +# ls2 has lsp21 (192.168.2.21) >> +# ls3 has lsp31 (192.168.3.31) >> +# ls4 has lsp41 (192.168.4.41) >> +# >> +# lrp-lr1-ls1 set options:route_table=rtb-1 >> +# lrp-lr1-ls2 set options:route_table=rtb-2 >> +# >> +# Static routes on lr1: >> +# 10.0.0.0/24 nexthop 192.168.3.31 route_table=rtb-1 >> +# 10.0.0.0/24 nexthop 192.168.4.41 route_table=rtb-2 >> +# >> +# Test 1: >> +# lsp11 send packet to 10.0.0.1 >> +# >> +# Expected result: >> +# lsp31 should receive traffic, lsp41 should not receive any traffic >> +# >> +# Test 2: >> +# lsp21 send packet to 10.0.0.1 >> +# >> +# Expected result: >> +# lsp41 should receive traffic, lsp31 should not receive any traffic >> + >> +ovn-nbctl lr-add lr1 >> + >> +# Create logical topology >> +for i in $(seq 1 4); do >> + ovn-nbctl ls-add ls${i} >> + ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 >> 192.168.${i}.1/24 >> + ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 >> router \ >> + -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \ >> + -- lsp-set-addresses lsp-ls${i}-lr1 router >> + ovn-nbctl lsp-add ls$i lsp${i}1 -- \ >> + lsp-set-addresses lsp${i}1 "f0:00:00:00:0${i}:1${i} >> 192.168.${i}.${i}1" >> +done >> + >> +# install static routes >> +ovn-nbctl --route-table=rtb-1 lr-route-add lr1 10.0.0.0/24 192.168.3.31 >> +ovn-nbctl --route-table=rtb-2 lr-route-add lr1 10.0.0.0/24 192.168.4.41 >> + >> +# set lrp-lr1-ls{1,2} route tables >> +ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1 >> +ovn-nbctl lrp-set-options lrp-lr1-ls2 route_table=rtb-2 >> + >> +net_add n1 >> +sim_add hv1 >> +as hv1 >> +ovs-vsctl add-br br-phys >> +ovn_attach n1 br-phys 192.168.0.1 >> + >> +for i in $(seq 1 4); do >> + ovs-vsctl -- add-port br-int hv1-vif${i} -- \ >> + set interface hv1-vif${i} external-ids:iface-id=lsp${i}1 \ >> + options:tx_pcap=hv1/vif${i}-tx.pcap \ >> + options:rxq_pcap=hv1/vif${i}-rx.pcap \ >> + ofport-request=${i} >> +done >> + >> +# wait for earlier changes to take effect >> +check ovn-nbctl --wait=hv sync >> +wait_for_ports_up >> + >> +# lsp31 should recieve packet coming from lsp11 >> +# lsp41 should recieve packet coming from lsp21 >> +for i in $(seq 1 2); do >> + di=$(( i + 2)) # dst index >> + ri=$(( 5 - i)) # reverse index >> + packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} && >> + eth.dst==00:00:00:01:0${i}:01 && ip4 && ip.ttl==64 && >> + ip4.src==192.168.${i}.${i}1 && ip4.dst==10.0.0.1 && icmp" >> + AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) >> + >> + # Assume all packets go to lsp${di}1. >> + exp_packet="eth.src==00:00:00:01:0${di}:01 && >> eth.dst==f0:00:00:00:0${di}:1${di} && >> + ip4 && ip.ttl==63 && ip4.src==192.168.${i}.${i}1 && >> ip4.dst==10.0.0.1 && icmp" >> + echo $exp_packet | ovstest test-ovn expr-to-packets >> >> expected_lsp${di}1 >> + > expected_lsp${ri}1 >> + >> + OVS_WAIT_UNTIL([ >> + rcv_n1=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" >> hv1/vif${di}-tx.pcap > lsp${di}1.packets && cat lsp${di}1.packets | wc -l` >> + rcv_n2=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" >> hv1/vif${ri}-tx.pcap > lsp${ri}1.packets && cat lsp${ri}1.packets | wc -l` >> + echo $rcv_n1 $rcv_n2 >> + test $rcv_n1 -eq 1 -a $rcv_n2 -eq 0]) >> + >> + for j in "${di}1" "${ri}1"; do >> + sort expected_lsp${j} > expout >> + AT_CHECK([cat lsp${j}.packets | sort], [0], [expout]) >> + done >> + >> + # cleanup tx pcap files >> + for j in "${di}1" "${ri}1"; do >> + ovs-vsctl -- remove interface hv1-vif${di} options tx_pcap >> + > hv1/vif${di}-tx.pcap >> + ovs-vsctl -- set interface hv1-vif${di} >> external-ids:iface-id=lsp${di}1 \ >> + options:tx_pcap=hv1/vif${di}-tx.pcap >> + done >> +done >> + >> +OVN_CLEANUP([hv1]) >> +AT_CLEANUP >> +]) >> + >> + >> +OVN_FOR_EACH_NORTHD([ >> +AT_SETUP([route tables IPv6 -- overlapping subnets]) >> +ovn_start >> + >> +# Logical network: >> +# >> +# ls1 (2001:db8:1::/64) - lrp-lr1-ls1 -\ /- lrp-lr1-ls2 - ls2 >> (2001:db8:2::/64) >> +# lr1 >> +# ls3 (2001:db8:3::/64) - lrp-lr1-ls3 -/ \- lrp-lr1-ls4 - ls4 >> (2001:db8:4::/64) >> +# >> +# ls1 has lsp11 (2001:db8:1::11) >> +# ls2 has lsp21 (2001:db8:2::21) >> +# ls3 has lsp31 (2001:db8:3::31) >> +# ls4 has lsp41 (2001:db8:4::41) >> +# >> +# lrp-lr1-ls1 set options:route_table=rtb-1 >> +# lrp-lr1-ls2 set options:route_table=rtb-2 >> +# >> +# Static routes on lr1: >> +# 2001:db8:2000::/64 nexthop 2001:db8:3::31 route_table=rtb-1 >> +# 2001:db8:2000::/64 nexthop 2001:db8:3::41 route_table=rtb-2 >> +# >> +# Test 1: >> +# lsp11 send packet to 2001:db8:2000::1 >> +# >> +# Expected result: >> +# lsp31 should receive traffic, lsp41 should not receive any traffic >> +# >> +# Test 2: >> +# lsp21 send packet to 2001:db8:2000::1 >> +# >> +# Expected result: >> +# lsp41 should receive traffic, lsp31 should not receive any traffic >> + >> +ovn-nbctl lr-add lr1 >> + >> +# Create logical topology >> +for i in $(seq 1 4); do >> + ovn-nbctl ls-add ls${i} >> + ovn-nbctl lrp-add lr1 lrp-lr1-ls${i} 00:00:00:01:0${i}:01 >> 2001:db8:${i}::1/64 >> + ovn-nbctl lsp-add ls${i} lsp-ls${i}-lr1 -- lsp-set-type lsp-ls${i}-lr1 >> router \ >> + -- lsp-set-options lsp-ls${i}-lr1 router-port=lrp-lr1-ls${i} \ >> + -- lsp-set-addresses lsp-ls${i}-lr1 router >> + ovn-nbctl lsp-add ls$i lsp${i}1 -- \ >> + lsp-set-addresses lsp${i}1 "f0:00:00:00:0${i}:1${i} >> 2001:db8:${i}::${i}1" >> +done >> + >> +# install static routes >> +ovn-nbctl --route-table=rtb-1 lr-route-add lr1 2001:db8:2000::/64 >> 2001:db8:3::31 >> +ovn-nbctl --route-table=rtb-2 lr-route-add lr1 2001:db8:2000::/64 >> 2001:db8:4::41 >> + >> +# set lrp-lr1-ls{1,2} route tables >> +ovn-nbctl lrp-set-options lrp-lr1-ls1 route_table=rtb-1 >> +ovn-nbctl lrp-set-options lrp-lr1-ls2 route_table=rtb-2 >> + >> +net_add n1 >> +sim_add hv1 >> +as hv1 >> +ovs-vsctl add-br br-phys >> +ovn_attach n1 br-phys 192.168.0.1 >> + >> +for i in $(seq 1 4); do >> + ovs-vsctl -- add-port br-int hv1-vif${i} -- \ >> + set interface hv1-vif${i} external-ids:iface-id=lsp${i}1 \ >> + options:tx_pcap=hv1/vif${i}-tx.pcap \ >> + options:rxq_pcap=hv1/vif${i}-rx.pcap \ >> + ofport-request=${i} >> +done >> + >> +# wait for earlier changes to take effect >> +AT_CHECK([ovn-nbctl --timeout=3 --wait=hv sync], [0], [ignore]) >> + >> +# lsp31 should recieve packet coming from lsp11 >> +# lsp41 should recieve packet coming from lsp21 >> +for i in $(seq 1 2); do >> + di=$(( i + 2)) # dst index >> + ri=$(( 5 - i)) # reverse index >> + packet="inport==\"lsp${i}1\" && eth.src==f0:00:00:00:0${i}:1${i} && >> + eth.dst==00:00:00:01:0${i}:01 && ip6 && ip.ttl==64 && >> + ip6.src==2001:db8:${i}::${i}1 && ip6.dst==2001:db8:2000::1 && >> icmp6" >> + AT_CHECK([as hv1 ovs-appctl -t ovn-controller inject-pkt "$packet"]) >> + >> + # Assume all packets go to lsp${di}1. >> + exp_packet="eth.src==00:00:00:01:0${di}:01 && >> eth.dst==f0:00:00:00:0${di}:1${di} && ip6 && >> + ip.ttl==63 && ip6.src==2001:db8:${i}::${i}1 && >> ip6.dst==2001:db8:2000::1 && icmp6" >> + echo $exp_packet | ovstest test-ovn expr-to-packets >> >> expected_lsp${di}1 >> + > expected_lsp${ri}1 >> + >> + OVS_WAIT_UNTIL([ >> + rcv_n1=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" >> hv1/vif${di}-tx.pcap > lsp${di}1.packets && cat lsp${di}1.packets | wc -l` >> + rcv_n2=`$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" >> hv1/vif${ri}-tx.pcap > lsp${ri}1.packets && cat lsp${ri}1.packets | wc -l` >> + echo $rcv_n1 $rcv_n2 >> + test $rcv_n1 -eq 1 -a $rcv_n2 -eq 0]) >> + >> + for j in "${di}1" "${ri}1"; do >> + sort expected_lsp${j} > expout >> + AT_CHECK([cat lsp${j}.packets | sort], [0], [expout]) >> + done >> + >> + # cleanup tx pcap files >> + for j in "${di}1" "${ri}1"; do >> + ovs-vsctl -- remove interface hv1-vif${di} options tx_pcap >> + > hv1/vif${di}-tx.pcap >> + ovs-vsctl -- set interface hv1-vif${di} >> external-ids:iface-id=lsp${di}1 \ >> + options:tx_pcap=hv1/vif${di}-tx.pcap >> + done >> +done >> + >> +OVN_CLEANUP([hv1]) >> +AT_CLEANUP >> +]) >> + >> + >> OVN_FOR_EACH_NORTHD([ >> AT_SETUP([forwarding group: 3 HVs, 1 LR, 2 LS]) >> AT_KEYWORDS([forwarding-group]) >> @@ -23018,7 +23445,7 @@ ovn-sbctl dump-flows > sbflows >> AT_CAPTURE_FILE([sbflows]) >> AT_CAPTURE_FILE([offlows]) >> OVS_WAIT_UNTIL([ >> - as hv1 ovs-ofctl dump-flows br-int table=20 > offlows >> + as hv1 ovs-ofctl dump-flows br-int table=21 > offlows >> test $(grep -c "load:0x64->NXM_NX_PKT_MARK" offlows) = 1 && \ >> test $(grep -c "load:0x3->NXM_NX_PKT_MARK" offlows) = 1 && \ >> test $(grep -c "load:0x4->NXM_NX_PKT_MARK" offlows) = 1 && \ >> @@ -23111,12 +23538,12 @@ send_ipv4_pkt hv1 hv1-vif1 505400000003 >> 00000000ff01 \ >> $(ip_to_hex 10 0 0 3) $(ip_to_hex 172 168 0 120) >> >> OVS_WAIT_UNTIL([ >> - test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=20 | \ >> + test 1 -eq $(as hv1 ovs-ofctl dump-flows br-int table=21 | \ >> grep "load:0x2->NXM_NX_PKT_MARK" -c) >> ]) >> >> AT_CHECK([ >> - test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=20 | \ >> + test 0 -eq $(as hv1 ovs-ofctl dump-flows br-int table=21 | \ >> grep "load:0x64->NXM_NX_PKT_MARK" -c) >> ]) >> >> @@ -23819,7 +24246,7 @@ AT_CHECK([ >> grep "priority=100" | \ >> grep -c >> "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" >> >> - grep table=22 hv${hv}flows | \ >> + grep table=23 hv${hv}flows | \ >> grep "priority=200" | \ >> grep -c >> "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" >> done; :], [0], [dnl >> @@ -23944,7 +24371,7 @@ AT_CHECK([ >> grep "priority=100" | \ >> grep -c >> "ct(commit,zone=NXM_NX_REG11\\[[0..15\\]],.*exec(move:NXM_OF_ETH_SRC\\[[\\]]->NXM_NX_CT_LABEL\\[[32..79\\]],load:0x[[0-9]]->NXM_NX_CT_LABEL\\[[80..95\\]]))" >> >> - grep table=22 hv${hv}flows | \ >> + grep table=23 hv${hv}flows | \ >> grep "priority=200" | \ >> grep -c >> "actions=move:NXM_NX_CT_LABEL\\[[32..79\\]]->NXM_OF_ETH_DST\\[[\\]]" >> done; :], [0], [dnl >> @@ -24566,7 +24993,7 @@ AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep >> "actions=controller" | grep >> ]) >> >> # The packet should've been dropped in the lr_in_arp_resolve stage. >> -AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=22, >> n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 >> actions=drop" -c], [0], [dnl >> +AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | grep -E "table=23, >> n_packets=1,.* priority=1,ip,metadata=0x${sw_key},nw_dst=10.0.1.1 >> actions=drop" -c], [0], [dnl >> 1 >> ]) >> >> diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c >> index 10217dcd5..f4a8504e6 100644 >> --- a/utilities/ovn-nbctl.c >> +++ b/utilities/ovn-nbctl.c >> @@ -329,6 +329,8 @@ Logical router port commands:\n\ >> add logical port PORT on ROUTER\n\ >> lrp-set-gateway-chassis PORT CHASSIS [PRIORITY]\n\ >> set gateway chassis for port PORT\n\ >> + lrp-set-options PORT KEY=VALUE [KEY=VALUE]...\n\ >> + set router port options\n\ >> lrp-del-gateway-chassis PORT CHASSIS\n\ >> delete gateway chassis from port PORT\n\ >> lrp-get-gateway-chassis PORT\n\ >> @@ -351,11 +353,17 @@ Logical router port commands:\n\ >> ('overlay' or 'bridged')\n\ >> \n\ >> Route commands:\n\ >> - [--policy=POLICY] [--ecmp] [--ecmp-symmetric-reply] lr-route-add ROUTER >> \n\ >> - PREFIX NEXTHOP [PORT]\n\ >> + [--policy=POLICY]\n\ >> + [--ecmp]\n\ >> + [--ecmp-symmetric-reply]\n\ >> + [--route-table=ROUTE_TABLE]\n\ >> + lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\ >> add a route to ROUTER\n\ >> - [--policy=POLICY] lr-route-del ROUTER [PREFIX [NEXTHOP [PORT]]]\n\ >> + [--policy=POLICY]\n\ >> + [--route-table=ROUTE_TABLE]\n\ >> + lr-route-del ROUTER [PREFIX [NEXTHOP [PORT]]]\n\ >> remove routes from ROUTER\n\ >> + [--route-table=ROUTE_TABLE]\n\ >> lr-route-list ROUTER print routes for ROUTER\n\ >> \n\ >> Policy commands:\n\ >> @@ -743,6 +751,11 @@ print_lr(const struct nbrec_logical_router *lr, struct >> ds *s) >> ds_put_cstr(s, "]\n"); >> } >> >> + const char *route_table = smap_get(&lrp->options, "route_table"); >> + if (route_table) { >> + ds_put_format(s, " route-table: %s\n", route_table); >> + } >> + >> if (lrp->n_gateway_chassis) { >> const struct nbrec_gateway_chassis **gcs; >> >> @@ -862,6 +875,7 @@ nbctl_pre_show(struct ctl_context *ctx) >> ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); >> ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_mac); >> ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_networks); >> + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_options); >> ovsdb_idl_add_column(ctx->idl, >> &nbrec_logical_router_port_col_gateway_chassis); >> >> ovsdb_idl_add_column(ctx->idl, &nbrec_gateway_chassis_col_chassis_name); >> @@ -4000,11 +4014,19 @@ nbctl_lr_policy_list(struct ctl_context *ctx) >> >> static struct nbrec_logical_router_static_route * >> nbctl_lr_get_route(const struct nbrec_logical_router *lr, char *prefix, >> - char *next_hop, bool is_src_route, bool ecmp) >> + char *next_hop, bool is_src_route, bool ecmp, >> + char *route_table) >> { >> for (int i = 0; i < lr->n_static_routes; i++) { >> struct nbrec_logical_router_static_route *route = >> lr->static_routes[i]; >> >> + /* Strict compare for route_table. >> + * If route_table was not specified, >> + * lookup for routes with empty route_table value. */ >> + if (strcmp(route->route_table, route_table ? route_table : "")) { >> + continue; >> + } >> + >> /* Compare route policy. */ >> char *nb_policy = route->policy; >> bool nb_is_src_route = false; >> @@ -4060,6 +4082,8 @@ nbctl_pre_lr_route_add(struct ctl_context *ctx) >> &nbrec_logical_router_static_route_col_bfd); >> ovsdb_idl_add_column(ctx->idl, >> &nbrec_logical_router_static_route_col_options); >> + ovsdb_idl_add_column(ctx->idl, >> + >> &nbrec_logical_router_static_route_col_route_table); >> } >> >> static char * OVS_WARN_UNUSED_RESULT >> @@ -4090,6 +4114,7 @@ nbctl_lr_route_add(struct ctl_context *ctx) >> } >> } >> >> + char *route_table = shash_find_data(&ctx->options, "--route-table"); >> bool v6_prefix = false; >> prefix = normalize_ipv4_prefix_str(ctx->argv[2]); >> if (!prefix) { >> @@ -4159,7 +4184,8 @@ nbctl_lr_route_add(struct ctl_context *ctx) >> bool ecmp = shash_find(&ctx->options, "--ecmp") != NULL || >> ecmp_symmetric_reply; >> struct nbrec_logical_router_static_route *route = >> - nbctl_lr_get_route(lr, prefix, next_hop, is_src_route, ecmp); >> + nbctl_lr_get_route(lr, prefix, next_hop, is_src_route, ecmp, >> + route_table); >> >> /* Validations for nexthop = "discard" */ >> if (is_discard_route) { >> @@ -4223,7 +4249,8 @@ nbctl_lr_route_add(struct ctl_context *ctx) >> } >> >> struct nbrec_logical_router_static_route *discard_route = >> - nbctl_lr_get_route(lr, prefix, "discard", is_src_route, true); >> + nbctl_lr_get_route(lr, prefix, "discard", is_src_route, true, >> + route_table); >> if (discard_route) { >> ctl_error(ctx, "discard nexthop for the same ECMP route exists."); >> goto cleanup; >> @@ -4239,6 +4266,9 @@ nbctl_lr_route_add(struct ctl_context *ctx) >> if (policy) { >> nbrec_logical_router_static_route_set_policy(route, policy); >> } >> + if (route_table) { >> + nbrec_logical_router_static_route_set_route_table(route, >> route_table); >> + } >> >> if (ecmp_symmetric_reply) { >> const struct smap options = SMAP_CONST1(&options, >> @@ -4282,6 +4312,8 @@ nbctl_pre_lr_route_del(struct ctl_context *ctx) >> &nbrec_logical_router_static_route_col_nexthop); >> ovsdb_idl_add_column(ctx->idl, >> &nbrec_logical_router_static_route_col_output_port); >> + ovsdb_idl_add_column(ctx->idl, >> + >> &nbrec_logical_router_static_route_col_route_table); >> >> } >> >> @@ -4295,6 +4327,7 @@ nbctl_lr_route_del(struct ctl_context *ctx) >> return; >> } >> >> + const char *route_table = shash_find_data(&ctx->options, >> "--route-table"); >> const char *policy = shash_find_data(&ctx->options, "--policy"); >> bool is_src_route = false; >> if (policy) { >> @@ -4385,6 +4418,14 @@ nbctl_lr_route_del(struct ctl_context *ctx) >> } >> } >> >> + /* Strict compare for route_table. >> + * If route_table was not specified, >> + * lookup for routes with empty route_table value. */ >> + if (strcmp(lr->static_routes[i]->route_table, >> + route_table ? route_table : "")) { >> + continue; >> + } >> + >> /* Compare output_port, if specified. */ >> if (output_port) { >> char *rt_output_port = lr->static_routes[i]->output_port; >> @@ -5108,6 +5149,41 @@ nbctl_pre_lrp_del_gateway_chassis(struct ctl_context >> *ctx) >> ovsdb_idl_add_column(ctx->idl, &nbrec_gateway_chassis_col_chassis_name); >> } >> >> +static void >> +nbctl_pre_lrp_options(struct ctl_context *ctx) >> +{ >> + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); >> + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_options); >> +} >> + >> +static void >> +nbctl_lrp_set_options(struct ctl_context *ctx) >> +{ >> + const char *id = ctx->argv[1]; >> + const struct nbrec_logical_router_port *lrp = NULL; >> + size_t i; >> + struct smap options = SMAP_INITIALIZER(&options); >> + >> + char *error = lrp_by_name_or_uuid(ctx, id, true, &lrp); >> + if (error) { >> + ctx->error = error; >> + return; >> + } >> + for (i = 2; i < ctx->argc; i++) { >> + char *key, *value; >> + value = xstrdup(ctx->argv[i]); >> + key = strsep(&value, "="); >> + if (value) { >> + smap_add(&options, key, value); >> + } >> + free(key); >> + } >> + >> + nbrec_logical_router_port_set_options(lrp, &options); >> + >> + smap_destroy(&options); >> +} >> + >> /* Removes logical router port 'lrp->gateway_chassis[idx]'. */ >> static void >> remove_gc(const struct nbrec_logical_router_port *lrp, size_t idx) >> @@ -5884,6 +5960,7 @@ route_cmp_details(const struct >> nbrec_logical_router_static_route *r1, >> } >> return r1->output_port ? 1 : -1; >> } >> + >> struct ipv4_route { >> int priority; >> ovs_be32 addr; >> @@ -5893,6 +5970,11 @@ struct ipv4_route { >> static int >> __ipv4_route_cmp(const struct ipv4_route *r1, const struct ipv4_route *r2) >> { >> + int rtb_cmp = strcmp(r1->route->route_table, >> + r2->route->route_table); >> + if (rtb_cmp) { >> + return rtb_cmp; >> + } >> if (r1->priority != r2->priority) { >> return r1->priority > r2->priority ? -1 : 1; >> } >> @@ -5924,6 +6006,11 @@ struct ipv6_route { >> static int >> __ipv6_route_cmp(const struct ipv6_route *r1, const struct ipv6_route *r2) >> { >> + int rtb_cmp = strcmp(r1->route->route_table, >> + r2->route->route_table); >> + if (rtb_cmp) { >> + return rtb_cmp; >> + } >> if (r1->priority != r2->priority) { >> return r1->priority > r2->priority ? -1 : 1; >> } >> @@ -6011,6 +6098,8 @@ nbctl_pre_lr_route_list(struct ctl_context *ctx) >> &nbrec_logical_router_static_route_col_options); >> ovsdb_idl_add_column(ctx->idl, >> &nbrec_logical_router_static_route_col_bfd); >> + ovsdb_idl_add_column(ctx->idl, >> + >> &nbrec_logical_router_static_route_col_route_table); >> } >> >> static void >> @@ -6028,12 +6117,17 @@ nbctl_lr_route_list(struct ctl_context *ctx) >> return; >> } >> >> + char *route_table = shash_find_data(&ctx->options, "--route-table"); >> + >> ipv4_routes = xmalloc(sizeof *ipv4_routes * lr->n_static_routes); >> ipv6_routes = xmalloc(sizeof *ipv6_routes * lr->n_static_routes); >> >> for (int i = 0; i < lr->n_static_routes; i++) { >> const struct nbrec_logical_router_static_route *route >> = lr->static_routes[i]; >> + if (route_table && strcmp(route->route_table, route_table)) { >> + continue; >> + } >> unsigned int plen; >> ovs_be32 ipv4; >> const char *policy = route->policy ? route->policy : "dst-ip"; >> @@ -6074,6 +6168,7 @@ nbctl_lr_route_list(struct ctl_context *ctx) >> if (n_ipv4_routes) { >> ds_put_cstr(&ctx->output, "IPv4 Routes\n"); >> } >> + const struct nbrec_logical_router_static_route *route; >> for (int i = 0; i < n_ipv4_routes; i++) { >> bool ecmp = false; >> if (i < n_ipv4_routes - 1 && >> @@ -6084,6 +6179,15 @@ nbctl_lr_route_list(struct ctl_context *ctx) >> &ipv4_routes[i - 1])) { >> ecmp = true; >> } >> + >> + route = ipv4_routes[i].route; >> + if (!i || (i > 0 && strcmp(route->route_table, >> + ipv4_routes[i - 1].route->route_table))) >> { >> + ds_put_format(&ctx->output, "%sRoute Table %s:\n", i ? "\n" : >> "", >> + strlen(route->route_table) ? route->route_table >> + : "global"); >> + } >> + >> print_route(ipv4_routes[i].route, &ctx->output, ecmp); >> } >> >> @@ -6101,6 +6205,15 @@ nbctl_lr_route_list(struct ctl_context *ctx) >> &ipv6_routes[i - 1])) { >> ecmp = true; >> } >> + >> + route = ipv6_routes[i].route; >> + if (!i || (i > 0 && strcmp(route->route_table, >> + ipv6_routes[i - 1].route->route_table))) >> { >> + ds_put_format(&ctx->output, "%sRoute Table %s:\n", i ? "\n" : >> "", >> + strlen(route->route_table) ? route->route_table >> + : "global"); >> + } >> + >> print_route(ipv6_routes[i].route, &ctx->output, ecmp); >> } >> >> @@ -6919,6 +7032,8 @@ static const struct ctl_command_syntax >> nbctl_commands[] = { >> "PORT CHASSIS [PRIORITY]", >> nbctl_pre_lrp_set_gateway_chassis, nbctl_lrp_set_gateway_chassis, >> NULL, "--may-exist", RW }, >> + { "lrp-set-options", 1, INT_MAX, "PORT KEY=VALUE [KEY=VALUE]...", >> + nbctl_pre_lrp_options, nbctl_lrp_set_options, NULL, "", RW }, >> { "lrp-del-gateway-chassis", 2, 2, "PORT CHASSIS", >> nbctl_pre_lrp_del_gateway_chassis, nbctl_lrp_del_gateway_chassis, >> NULL, "", RW }, >> @@ -6942,12 +7057,13 @@ static const struct ctl_command_syntax >> nbctl_commands[] = { >> /* logical router route commands. */ >> { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", >> nbctl_pre_lr_route_add, nbctl_lr_route_add, NULL, >> - "--may-exist,--ecmp,--ecmp-symmetric-reply,--policy=,--bfd?", RW }, >> + >> "--may-exist,--ecmp,--ecmp-symmetric-reply,--policy=,--route-table=,--bfd?", >> + RW }, >> { "lr-route-del", 1, 4, "ROUTER [PREFIX [NEXTHOP [PORT]]]", >> nbctl_pre_lr_route_del, nbctl_lr_route_del, NULL, >> - "--if-exists,--policy=", RW }, >> + "--if-exists,--policy=,--route-table=", RW }, >> { "lr-route-list", 1, 1, "ROUTER", nbctl_pre_lr_route_list, >> - nbctl_lr_route_list, NULL, "", RO }, >> + nbctl_lr_route_list, NULL, "--route-table=", RO }, >> >> /* Policy commands */ >> { "lr-policy-add", 4, INT_MAX, >> -- >> 2.30.0 >> >> _______________________________________________ >> dev mailing list >> [email protected] <mailto:[email protected]> >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev >> <https://mail.openvswitch.org/mailman/listinfo/ovs-dev> >> > _______________________________________________ > dev mailing list > [email protected] <mailto:[email protected]> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > <https://mail.openvswitch.org/mailman/listinfo/ovs-dev> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
