Message ID | 20241204151207.39657-3-martin.kalcok@canonical.com |
---|---|
State | Accepted |
Delegated to: | Dumitru Ceara |
Headers | show |
Series | IPv4 routes over IPv6 next hop addresses. | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
ovsrobot/github-robot-_ovn-kubernetes | success | github build: passed |
Hi Martin, Felix, On 12/4/24 4:10 PM, Martin Kalcok wrote: > From: Felix Huettner <felix.huettner@mail.schwarz> > > In most cases IPv4 packets are routed only over other IPv4 networks and > IPv6 packets are routed only over IPv6 networks. However there is no > inherent reason for this limitation. Routing IPv4 packets over IPv6 > networks just requires the router to contain a route for an IPv4 network > with an IPv6 nexthop. > > This was previously prevented in OVN in ovn-nbctl and northd. By > removing these filters the forwarding will work if the mac addresses are > prepopulated. > > If the mac addresses are not prepopulated we will attempt to resolve them using > the original address family of the packet and not the address family of the > nexthop. This will fail and we will not forward the packet. > > This feature can for example be used by service providers to > interconnect multiple IPv4 networks of a customer without needing to > negotiate free IPv4 addresses by just using any IPv6 address. > > Signed-off-by: Felix Huettner <felix.huettner@mail.schwarz> Felix, is this email address correct? > Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com> > Co-authored-by: Martin Kalcok <martin.kalcok@canonical.com> > --- After merging Felix's BGP prerequisite patches, there were a bunch of conflicts when applying this patch but I think I managed to address them. I pushed the rebased patches (also with the small nits I had below addressed) to: https://github.com/dceara/ovn/commits/bcba1b74 It would be great if you could double check that it still looks OK to you. If that's the case I can then apply the series to main. > NEWS | 4 + > northd/northd.c | 81 +++--- > northd/northd.h | 2 + > tests/ovn-nbctl.at | 26 +- > tests/ovn-northd.at | 150 +++++++--- > tests/ovn.at | 645 ++++++++++++++++++++++++++++++++++++++++++ > utilities/ovn-nbctl.c | 12 +- > 7 files changed, 829 insertions(+), 91 deletions(-) > > diff --git a/NEWS b/NEWS > index da3aba739..b5aae7d4b 100644 > --- a/NEWS > +++ b/NEWS > @@ -75,6 +75,10 @@ OVN v24.09.0 - 13 Sep 2024 > "routing-protocol-redirect" and "routing-protocols", that allow > redirection of routing protocol traffic received by a router port > to a different logical switch port. > + - Allow Static Routes where the address families of ip_prefix and nexthop > + diverge (e.g. IPv4 packets over IPv6 links). This is currently limited to > + nexthops that have their mac addresses prepopulated (so > + dynamic_neigh_routers must be false). > > OVN v24.03.0 - 01 Mar 2024 > -------------------------- > diff --git a/northd/northd.c b/northd/northd.c > index 3564d45d9..4fb48838b 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -174,6 +174,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2)); > #define REGBIT_KNOWN_LB_SESSION "reg9[6]" > #define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]" > #define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]" > +#define REGBIT_NEXTHOP_IS_IPV4 "reg9[9]" > > /* Register to store the eth address associated to a router port for packets > * received in S_ROUTER_IN_ADMISSION. > @@ -290,7 +291,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2)); > * | | LOOKUP_NEIGHBOR_RESULT/ | | | > * | | SKIP_LOOKUP_NEIGHBOR/ | | | > * | |REGBIT_DHCP_RELAY_REQ_CHK/ | | | > - * | |REGBIT_DHCP_RELAY_RESP_CHK}| | | > + * | |REGBIT_DHCP_RELAY_RESP_CHK | | | > + * | |REGBIT_NEXTHOP_IS_IPV4} | | | > * | | | | | > * | | REG_ORIG_TP_DPORT_ROUTER | | | > * | | | | | > @@ -10861,13 +10863,15 @@ build_routing_policy_flow(struct lflow_table *lflows, struct ovn_datapath *od, > "outport = %s; " > "flags.loopback = 1; " > REG_ECMP_GROUP_ID" = 0; " > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > "next;", > is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, > nexthop, > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > lrp_addr_s, > out_port->lrp_networks.ea_s, > - out_port->json_key); > + out_port->json_key, > + is_ipv4); > > } else if (!strcmp(rule->action, "drop")) { > ds_put_cstr(&actions, debug_drop_action()); > @@ -10951,13 +10955,15 @@ build_ecmp_routing_policy_flows(struct lflow_table *lflows, > "eth.src = %s; " > "outport = %s; " > "flags.loopback = 1; " > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > "next;", > is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, > rp->valid_nexthops[i], > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > lrp_addr_s, > out_port->lrp_networks.ea_s, > - out_port->json_key); > + out_port->json_key, > + is_ipv4); Should we add a TODO item to remember to add support for "reroute" routing policies that change next hop family? > > ds_clear(&match); > ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && " > @@ -11123,6 +11129,8 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, > /* Verify that the next hop is an IP address with an all-ones mask. */ > struct in6_addr nexthop; > unsigned int plen; > + bool is_ipv4_nexthop = true; > + bool is_ipv4_prefix; > bool is_discard_route = !strcmp(route->nexthop, "discard"); > bool valid_nexthop = route->nexthop[0] && !is_discard_route; > if (valid_nexthop) { > @@ -11141,6 +11149,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, > UUID_ARGS(&route->header_.uuid)); > return; > } > + is_ipv4_nexthop = IN6_IS_ADDR_V4MAPPED(&nexthop); > } > > /* Parse ip_prefix */ > @@ -11152,18 +11161,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, > UUID_ARGS(&route->header_.uuid)); > return; > } > - > - /* Verify that ip_prefix and nexthop have same address familiy. */ > - if (valid_nexthop) { > - if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); > - VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix'" > - " %s and 'nexthop' %s in static route "UUID_FMT, > - route->ip_prefix, route->nexthop, > - UUID_ARGS(&route->header_.uuid)); > - return; > - } > - } > + is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&prefix); > > /* Verify that ip_prefix and nexthop are on the same network. */ > if (!is_discard_route && > @@ -11216,6 +11214,8 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, > "ecmp_symmetric_reply", > false); > new_pr->is_discard_route = is_discard_route; > + new_pr->is_ipv4_prefix = is_ipv4_prefix; > + new_pr->is_ipv4_nexthop = is_ipv4_nexthop; > sset_init(&new_pr->ecmp_selection_fields); > > /* If tp_src or tp_dst is included in the selection_fields, implicitly > @@ -11646,7 +11646,7 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, > struct lflow_ref *lflow_ref, const char *protocol) > > { > - bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix); > + bool is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&eg->prefix); > uint16_t priority; > struct ecmp_route_list_node *er; > struct ds route_match = DS_EMPTY_INITIALIZER; > @@ -11655,7 +11655,8 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, > int ofs = !strcmp(eg->origin, ROUTE_ORIGIN_CONNECTED) ? > ROUTE_PRIO_OFFSET_CONNECTED: ROUTE_PRIO_OFFSET_STATIC; > build_route_match(NULL, eg->route_table_id, prefix_s, eg->plen, > - eg->is_src_route, is_ipv4, &route_match, &priority, ofs, > + eg->is_src_route, is_ipv4_prefix, &route_match, > + &priority, ofs, > protocol != NULL); > free(prefix_s); > > @@ -11723,7 +11724,8 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, > /* Find the outgoing port. */ > const char *lrp_addr_s = NULL; > struct ovn_port *out_port = NULL; > - if (!find_static_route_outport(od, lr_ports, route, is_ipv4, > + if (!find_static_route_outport(od, lr_ports, route, > + route_->is_ipv4_nexthop, > &lrp_addr_s, &out_port)) { > continue; > } > @@ -11746,13 +11748,16 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, > "%s = %s; " > "eth.src = %s; " > "outport = %s; " > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > "next;", > - is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, > + route_->is_ipv4_nexthop ? > + REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, > route->nexthop, > - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > + route_->is_ipv4_nexthop ? REG_SRC_IPV4 : REG_SRC_IPV6, > lrp_addr_s, > out_port->lrp_networks.ea_s, > - out_port->json_key); > + out_port->json_key, > + route_->is_ipv4_nexthop); > ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 100, > ds_cstr(&match), ds_cstr(&actions), > &route->header_, lflow_ref); > @@ -11770,15 +11775,15 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od, > bool is_src_route, const uint32_t rtb_id, > const struct sset *bfd_ports, > const struct ovsdb_idl_row *stage_hint, bool is_discard_route, > - int ofs, struct lflow_ref *lflow_ref) > + int ofs, struct lflow_ref *lflow_ref, > + bool is_ipv4_prefix, bool is_ipv4_nexthop) > { > - bool is_ipv4 = strchr(network_s, '.') ? true : false; > struct ds match = DS_EMPTY_INITIALIZER; > uint16_t priority; > const struct ovn_port *op_inport = NULL; > > /* IPv6 link-local addresses must be scoped to the local router port. */ > - if (!is_ipv4) { > + if (!is_ipv4_prefix) { > struct in6_addr network; > ovs_assert(ipv6_parse(network_s, &network)); > if (in6_is_lla(&network)) { > @@ -11786,7 +11791,7 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od, > } > } > build_route_match(op_inport, rtb_id, network_s, plen, is_src_route, > - is_ipv4, &match, &priority, ofs, false); > + is_ipv4_prefix, &match, &priority, ofs, false); > > struct ds common_actions = DS_EMPTY_INITIALIZER; > struct ds actions = DS_EMPTY_INITIALIZER; > @@ -11794,22 +11799,25 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od, > ds_put_cstr(&actions, debug_drop_action()); > } else { > ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ", > - is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); > + is_ipv4_nexthop ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); > if (gateway && gateway[0]) { > ds_put_cstr(&common_actions, gateway); > } else { > - ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? "4" : "6"); > + ds_put_format(&common_actions, "ip%s.dst", > + is_ipv4_prefix ? "4" : "6"); > } > ds_put_format(&common_actions, "; " > "%s = %s; " > "eth.src = %s; " > "outport = %s; " > "flags.loopback = 1; " > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > "next;", > - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > + is_ipv4_nexthop ? REG_SRC_IPV4 : REG_SRC_IPV6, > lrp_addr_s, > op->lrp_networks.ea_s, > - op->json_key); > + op->json_key, > + is_ipv4_nexthop); > ds_put_format(&actions, "ip.ttl--; %s", ds_cstr(&common_actions)); > } > > @@ -11860,7 +11868,8 @@ build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, > lrp_addr_s, prefix_s, route_->plen, route->nexthop, > route_->is_src_route, route_->route_table_id, > bfd_ports, &route->header_, route_->is_discard_route, > - ofs, lflow_ref); > + ofs, lflow_ref, > + route_->is_ipv4_prefix, route_->is_ipv4_nexthop); > > free(prefix_s); > } > @@ -13708,7 +13717,7 @@ build_ip_routing_flows_for_lrp(struct ovn_port *op, > op->lrp_networks.ipv4_addrs[i].network_s, > op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0, > bfd_ports, &op->nbrp->header_, false, > - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, true, true); > } > > for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > @@ -13716,7 +13725,7 @@ build_ip_routing_flows_for_lrp(struct ovn_port *op, > op->lrp_networks.ipv6_addrs[i].network_s, > op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0, > bfd_ports, &op->nbrp->header_, false, > - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, false, false); > } > } > > @@ -14069,11 +14078,13 @@ build_arp_resolve_flows_for_lrouter( > "ip4.mcast || ip6.mcast", "next;", > lflow_ref); > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", > + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, > + REGBIT_NEXTHOP_IS_IPV4 " == 1", > "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;", > lflow_ref); > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", > + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, > + REGBIT_NEXTHOP_IS_IPV4 " == 0", > "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;", > lflow_ref); > > @@ -17033,7 +17044,7 @@ build_routable_flows_for_router_port( > laddrs->ipv4_addrs[k].plen, NULL, false, 0, > bfd_ports, &router_port->nbrp->header_, > false, ROUTE_PRIO_OFFSET_CONNECTED, > - lrp->stateful_lflow_ref); > + lrp->stateful_lflow_ref, true, true); > } > } > } > diff --git a/northd/northd.h b/northd/northd.h > index e93e10f20..a5af72eb7 100644 > --- a/northd/northd.h > +++ b/northd/northd.h > @@ -709,6 +709,8 @@ struct parsed_route { > const struct nbrec_logical_router *nbr; > bool stale; > struct sset ecmp_selection_fields; > + bool is_ipv4_prefix; > + bool is_ipv4_nexthop; > }; > > void ovnnb_db_run(struct northd_input *input_data, > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at > index 2efa13b93..addcc4593 100644 > --- a/tests/ovn-nbctl.at > +++ b/tests/ovn-nbctl.at > @@ -1857,7 +1857,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.2]) > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp0]) > AT_CHECK([ovn-nbctl --bfd lr-route-add lr0 10.0.20.0/24 11.0.2.1 lp0]) > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp1], [1], [], > - [ovn-nbctl: bad IPv4 nexthop argument: lp1 > + [ovn-nbctl: bad nexthop argument: lp1 > ]) > > dnl Add overlapping route with 10.0.0.1/24 > @@ -1871,13 +1871,13 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24a 11.0.0.1], [1], [], > [ovn-nbctl: bad prefix argument: 10.0.0.111/24a > ]) > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1a], [1], [], > - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1a > + [ovn-nbctl: bad nexthop argument: 11.0.0.1a > ]) > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1/24], [1], [], > - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1/24 > + [ovn-nbctl: bad nexthop argument: 11.0.0.1/24 > ]) > AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1/64], [1], [], > - [ovn-nbctl: bad IPv6 nexthop argument: 2001:0db8:0:f103::1/64 > + [ovn-nbctl: bad nexthop argument: 2001:0db8:0:f103::1/64 > ]) > AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 20.0.0.0/24 discard], [1], [], > [ovn-nbctl: ecmp is not valid for discard routes. > @@ -2105,6 +2105,24 @@ check ovn-nbctl lr-route-del lr0 > AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl > ]) > > +dnl Check IPv4 over v6 and IPv6 over v4 routes > +AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 2001:0db8:0:f103::10]) > +AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 11.0.1.10]) > + > +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl > +IPv4 Routes > +Route Table <main>: > + 10.0.0.0/24 2001:db8:0:f103::10 dst-ip > + > +IPv6 Routes > +Route Table <main>: > + 2001:db8::/64 11.0.1.10 dst-ip > +]) > + > +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 > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > index c98f1fcb4..803823afa 100644 > --- a/tests/ovn-northd.at > +++ b/tests/ovn-northd.at > @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | ovn_strip_lflows], [0], [dnl > table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = 0; next;) > table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);) > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) > ]) > > @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf > table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);) > table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);) > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) > ]) > > @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf > table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = <cleared>; next;) > table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);) > table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);) > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; next;) > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) > ]) > > @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \ > sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl > table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = <cleared>; next;) > table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);) > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; next;) > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) > ]) > > @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | \ > sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \ > sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl > table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = <cleared>; next;) > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; next;) > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) > table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) > ]) > @@ -6823,14 +6823,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) > table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;) > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;) > - table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > ]) > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) > + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) > table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) > ]) > > @@ -6841,14 +6841,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) > table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;) > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 && 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=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > ]) > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) > - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) > + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) > table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) > ]) > > @@ -6870,14 +6870,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) > table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;) > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 && 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=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > ]) > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) > - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) > + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) > table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) > ]) > > @@ -6888,14 +6888,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 | ovn_strip_lflows], [0], [dnl > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 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=122 , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 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 | ovn_strip_lflows], [0], [dnl > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=122 , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > ]) > > check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11 > @@ -6928,6 +6928,66 @@ AT_CHECK([grep -e "(lr_in_ip_routing ).*3.3.0.0" lr0flows | sed 's/table=../ta > AT_CLEANUP > ]) > > +OVN_FOR_EACH_NORTHD_NO_HV([ > +AT_SETUP([ovn -- static routes multiple address families flows]) > +AT_KEYWORDS([static-routes-flows]) > +ovn_start > + > +check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 > + > +check ovn-nbctl lr-add lr0 > +check ovn-nbctl set logical_router lr0 options:chassis=ch1 > +check ovn-nbctl ls-add public > +check ovn-nbctl ls-add private > +check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 192.168.0.1/24 > +check ovn-nbctl lsp-add public public-lr0 > +check ovn-nbctl lsp-set-type public-lr0 router > +check ovn-nbctl lsp-set-addresses public-lr0 router > +check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public > + > +check ovn-nbctl lrp-add lr0 lr0-private 00:00:20:20:12:14 2001:db8::1/64 > +check ovn-nbctl lsp-add private private-lr0 > +check ovn-nbctl lsp-set-type private-lr0 router > +check ovn-nbctl lsp-set-addresses private-lr0 router > +check ovn-nbctl lsp-set-options private-lr0 router-port=lr0-private > + > +check ovn-nbctl --wait=sb lr-route-add lr0 10.0.0.0/24 192.168.0.10 > +check ovn-nbctl --wait=sb lr-route-add lr0 11.0.0.0/24 2001:db8::10 > +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:1::/64 192.168.0.20 > +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:2::/64 2001:db8::20 > + > +ovn-sbctl dump-flows lr0 > lr0flows > +AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | ovn_strip_lflows], [0], [dnl > + table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) > + table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) > + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > + table=??(lr_in_ip_routing ), priority=324 , match=(ip6.dst == 2001:db8::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > +]) > + > +AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl > + table=??(lr_in_arp_resolve ), priority=0 , match=(1), action=(drop;) > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 0), action=(get_nd(outport, xxreg0); next;) > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 1), action=(get_arp(outport, reg0); next;) > + table=??(lr_in_arp_resolve ), priority=500 , match=(ip4.mcast || ip6.mcast), action=(next;) > +]) > + > +AT_CHECK([grep -e "lr_in_arp_request" lr0flows | ovn_strip_lflows], [0], [dnl > + table=??(lr_in_arp_request ), priority=0 , match=(1), action=(output;) > + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; output; }; output;) > + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == 00:00:00:00:00:00 && ip6), action=(nd_ns { nd.target = xxreg0; output; }; output;) > + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::10), action=(nd_ns { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target = 2001:db8::10; output; }; output;) > + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::20), action=(nd_ns { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target = 2001:db8::20; output; }; output;) > +]) > + > +AT_CLEANUP > +]) > + > OVN_FOR_EACH_NORTHD_NO_HV([ > AT_SETUP([ovn-northd -- lr multiple gw ports]) > AT_KEYWORDS([multiple-l3dgw-ports]) > @@ -7346,16 +7406,16 @@ AT_CHECK([grep "lr_in_ip_routing_pre" lr0flows | ovn_strip_lflows], [0], [dnl > grep -e "(lr_in_ip_routing ).*outport" lr0flows > > AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | ovn_strip_lflows], [0], [dnl > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) > - table=??(lr_in_ip_routing ), priority=324 , 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=324 , 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=324 , 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=122 , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] = 0; next;) > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] = 0; next;) > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] = 0; next;) > ]) > > AT_CLEANUP > @@ -13450,8 +13510,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl > > AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_in_arp_resolve ), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), action=(get_arp(outport, reg0); next;) > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), action=(get_nd(outport, xxreg0); next;) > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 0), action=(get_nd(outport, xxreg0); next;) > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 1), action=(get_arp(outport, reg0); next;) > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = 00:00:00:00:ff:02; next;) > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = 30:54:00:00:00:03; next;) > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = 00:00:00:00:ff:02; next;) > @@ -13620,8 +13680,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl > > AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl > table=??(lr_in_arp_resolve ), priority=0 , match=(1), action=(drop;) > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), action=(get_arp(outport, reg0); next;) > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), action=(get_nd(outport, xxreg0); next;) > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 0), action=(get_nd(outport, xxreg0); next;) > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 1), action=(get_arp(outport, reg0); next;) > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = 00:00:00:00:ff:02; next;) > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = 00:00:00:00:ff:02; next;) > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = 00:00:00:00:ff:02; next;) > diff --git a/tests/ovn.at b/tests/ovn.at > index 1071208d1..ec90a3b4e 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -39761,3 +39761,648 @@ OVN_CLEANUP([hv1]) > > AT_CLEANUP > ]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv4 over IPv6]) > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > +ovn_start > + > +# Logical network: > +# Two LRs - R1 and R2 that are connected to each other as peers in 2001:db8::/64 > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > +# R2 has ls2 (172.16.1.0/24) connected to it. > + > +ls1_lp1_mac="f0:00:00:01:02:03" > +rp_ls1_mac="00:00:00:01:02:03" > +rp_ls2_mac="00:00:00:01:02:04" > +ls2_lp1_mac="f0:00:00:01:02:04" > + > +ls1_lp1_ip="192.168.1.2" > +ls2_lp1_ip="172.16.1.2" > + > +check ovn-nbctl lr-add R1 > +check ovn-nbctl lr-add R2 > + > +check ovn-nbctl ls-add ls1 > +check ovn-nbctl ls-add ls2 > + > +# Connect ls1 to R1 > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > + > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > + > +# Connect ls2 to R2 > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > + > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > + > +# Connect R1 to R2 > +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 2001:db8::1/64 peer=R2_R1 > +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 2001:db8::2/64 peer=R1_R2 > + > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > + > +# Create logical port ls1-lp1 in ls1 > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > + > +# Create logical port ls2-lp1 in ls2 > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > + > +# Create two hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > + > +sim_add hv1 > +as hv1 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > + options:tx_pcap=hv1/vif1-tx.pcap \ > + options:rxq_pcap=hv1/vif1-rx.pcap \ > + ofport-request=1 > + > +sim_add hv2 > +as hv2 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.2 > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > + options:tx_pcap=hv2/vif1-tx.pcap \ > + options:rxq_pcap=hv2/vif1-rx.pcap \ > + ofport-request=1 > + > + > +# Pre-populate the hypervisors' ARP tables so that we don't lose any > +# packets for ARP resolution (native tunneling doesn't queue packets > +# for ARP resolution). > +OVN_POPULATE_ARP > + > +# Allow some time for ovn-northd and ovn-controller to catch up. > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Packet to send. > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# Packet to Expect > +# The TTL should be decremented by 2. > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +echo ${expected} > expected > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > +]) > + > +# Disable the ls2-lp1 port. > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > +]) > + > +# Send the same packet again and it should not be delivered > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# The 2nd packet sent shound not be received. > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +OVN_CLEANUP([hv1],[hv2]) > + > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6]) > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > +ovn_start > + > +# Logical network: > +# Two LRs - R1 and R2 that are connected to ls-transfer in 2001:db8::/64 > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > +# R2 has ls2 (172.16.1.0/24) connected to it. > + > +ls1_lp1_mac="f0:00:00:01:02:03" > +rp_ls1_mac="00:00:00:01:02:03" > +rp_ls2_mac="00:00:00:01:02:04" > +ls2_lp1_mac="f0:00:00:01:02:04" > + > +ls1_lp1_ip="192.168.1.2" > +ls2_lp1_ip="172.16.1.2" > + > +check ovn-nbctl lr-add R1 > +check ovn-nbctl lr-add R2 > + > +check ovn-nbctl ls-add ls1 > +check ovn-nbctl ls-add ls2 > +check ovn-nbctl ls-add ls-transfer > + > +# Connect ls1 to R1 > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > + > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > + > +# Connect ls2 to R2 > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > + > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > + > +# Connect R1 to R2 > +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 2001:db8::1/64 > +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 2001:db8::2/64 > + > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ > + set Logical_Switch_Port ls-transfer_r1 type=router \ > + options:router-port=R1_ls-transfer addresses=\"router\" > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ > + set Logical_Switch_Port ls-transfer_r2 type=router \ > + options:router-port=R2_ls-transfer addresses=\"router\" > + > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > + > +# Create logical port ls1-lp1 in ls1 > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > + > +# Create logical port ls2-lp1 in ls2 > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > + > +# Create two hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > + > +sim_add hv1 > +as hv1 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > + options:tx_pcap=hv1/vif1-tx.pcap \ > + options:rxq_pcap=hv1/vif1-rx.pcap \ > + ofport-request=1 > + > +sim_add hv2 > +as hv2 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.2 > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > + options:tx_pcap=hv2/vif1-tx.pcap \ > + options:rxq_pcap=hv2/vif1-rx.pcap \ > + ofport-request=1 > + > + > +# Pre-populate the hypervisors' ARP tables so that we don't lose any > +# packets for ARP resolution (native tunneling doesn't queue packets > +# for ARP resolution). > +OVN_POPULATE_ARP > + > +# Allow some time for ovn-northd and ovn-controller to catch up. > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Packet to send. > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# Packet to Expect > +# The TTL should be decremented by 2. > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +echo ${expected} > expected > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > +]) > + > +# Disable the ls2-lp1 port. > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > +]) > + > +# Send the same packet again and it should not be delivered > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# The 2nd packet sent shound not be received. > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +OVN_CLEANUP([hv1],[hv2]) > + > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6, static mac]) > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > +ovn_start > + > +# Logical network: > +# Two LRs - R1 and R2 that are connected to ls-transfer in 2001:db8::/64 > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > +# R2 has ls2 (172.16.1.0/24) connected to it. > + > +ls1_lp1_mac="f0:00:00:01:02:03" > +rp_ls1_mac="00:00:00:01:02:03" > +rp_ls2_mac="00:00:00:01:02:04" > +ls2_lp1_mac="f0:00:00:01:02:04" > + > +ls1_lp1_ip="192.168.1.2" > +ls2_lp1_ip="172.16.1.2" > + > +check ovn-nbctl lr-add R1 > +check ovn-nbctl lr-add R2 > + > +check ovn-nbctl ls-add ls1 > +check ovn-nbctl ls-add ls2 > +check ovn-nbctl ls-add ls-transfer > + > +# Connect ls1 to R1 > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > +check ovn-nbctl set Logical_Router R1 options:dynamic_neigh_routers=true > + > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > + > +# Connect ls2 to R2 > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > +check ovn-nbctl set Logical_Router R2 options:dynamic_neigh_routers=true > + > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > + > +# Connect R1 to R2 > +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 2001:db8::1/64 > +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 2001:db8::2/64 > + > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ > + set Logical_Switch_Port ls-transfer_r1 type=router \ > + options:router-port=R1_ls-transfer addresses=\"router\" > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ > + set Logical_Switch_Port ls-transfer_r2 type=router \ > + options:router-port=R2_ls-transfer addresses=\"router\" > + > +# Static mac binding entries > +check ovn-nbctl static-mac-binding-add R1_ls-transfer 2001:db8::2 00:00:00:02:03:05 > +check ovn-nbctl static-mac-binding-add R2_ls-transfer 2001:db8::1 00:00:00:02:03:04 > + > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > + > +# Create logical port ls1-lp1 in ls1 > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > + > +# Create logical port ls2-lp1 in ls2 > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > + > +# Create two hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > + > +sim_add hv1 > +as hv1 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > + options:tx_pcap=hv1/vif1-tx.pcap \ > + options:rxq_pcap=hv1/vif1-rx.pcap \ > + ofport-request=1 > + > +sim_add hv2 > +as hv2 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.2 > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > + options:tx_pcap=hv2/vif1-tx.pcap \ > + options:rxq_pcap=hv2/vif1-rx.pcap \ > + ofport-request=1 > + > + > +# Pre-populate the hypervisors' ARP tables so that we don't lose any > +# packets for ARP resolution (native tunneling doesn't queue packets > +# for ARP resolution). > +OVN_POPULATE_ARP > + > +# Allow some time for ovn-northd and ovn-controller to catch up. > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Packet to send. > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# Packet to Expect > +# The TTL should be decremented by 2. > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +echo ${expected} > expected > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > +]) > + > +# Disable the ls2-lp1 port. > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > +]) > + > +# Send the same packet again and it should not be delivered > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# The 2nd packet sent shound not be received. > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +OVN_CLEANUP([hv1],[hv2]) > + > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6, ECMP]) > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > +ovn_start > + > +# Logical network: > +# Two LRs - R1 and R2 that are connected to ls-transfer1 and lr-transfer2 in > +# 2001:db8:1::/64 and 2001:db8:2::/64 > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > +# R2 has ls2 (172.16.1.0/24) connected to it. > + > +ls1_lp1_mac="f0:00:00:01:02:03" > +rp_ls1_mac="00:00:00:01:02:03" > +rp_ls2_mac="00:00:00:01:02:04" > +ls2_lp1_mac="f0:00:00:01:02:04" > + > +ls1_lp1_ip="192.168.1.2" > +ls2_lp1_ip="172.16.1.2" > + > +check ovn-nbctl lr-add R1 > +check ovn-nbctl lr-add R2 > + > +check ovn-nbctl ls-add ls1 > +check ovn-nbctl ls-add ls2 > +check ovn-nbctl ls-add ls-transfer1 > +check ovn-nbctl ls-add ls-transfer2 > + > +# Connect ls1 to R1 > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > + > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > + > +# Connect ls2 to R2 > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > + > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > + > +# Connect R1 to R2 (ls-transfer1) > +check ovn-nbctl lrp-add R1 R1_ls-transfer1 00:00:00:02:03:04 2001:db8:1::1/64 > +check ovn-nbctl lrp-add R2 R2_ls-transfer1 00:00:00:02:03:05 2001:db8:1::2/64 > + > +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r1 -- \ > + set Logical_Switch_Port ls-transfer1_r1 type=router \ > + options:router-port=R1_ls-transfer1 addresses=\"router\" > +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r2 -- \ > + set Logical_Switch_Port ls-transfer1_r2 type=router \ > + options:router-port=R2_ls-transfer1 addresses=\"router\" > + > +# Connect R1 to R2 (ls-transfer2) > +check ovn-nbctl lrp-add R1 R1_ls-transfer2 00:00:00:02:03:14 2001:db8:2::1/64 > +check ovn-nbctl lrp-add R2 R2_ls-transfer2 00:00:00:02:03:15 2001:db8:2::2/64 > + > +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r1 -- \ > + set Logical_Switch_Port ls-transfer2_r1 type=router \ > + options:router-port=R1_ls-transfer2 addresses=\"router\" > +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r2 -- \ > + set Logical_Switch_Port ls-transfer2_r2 type=router \ > + options:router-port=R2_ls-transfer2 addresses=\"router\" > + > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8:1::2]) > +AT_CHECK([ovn-nbctl --ecmp lr-route-add R1 "0.0.0.0/0" 2001:db8:2::2]) > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8:1::1]) > +AT_CHECK([ovn-nbctl --ecmp lr-route-add R2 "0.0.0.0/0" 2001:db8:2::1]) > + > +# Create logical port ls1-lp1 in ls1 > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > + > +# Create logical port ls2-lp1 in ls2 > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > + > +# Create two hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > + > +sim_add hv1 > +as hv1 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > + options:tx_pcap=hv1/vif1-tx.pcap \ > + options:rxq_pcap=hv1/vif1-rx.pcap \ > + ofport-request=1 > + > +sim_add hv2 > +as hv2 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.2 > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > + options:tx_pcap=hv2/vif1-tx.pcap \ > + options:rxq_pcap=hv2/vif1-rx.pcap \ > + ofport-request=1 > + > + > +# Pre-populate the hypervisors' ARP tables so that we don't lose any > +# packets for ARP resolution (native tunneling doesn't queue packets > +# for ARP resolution). > +OVN_POPULATE_ARP > + > +# Allow some time for ovn-northd and ovn-controller to catch up. > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Packet to send. > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# Packet to Expect > +# The TTL should be decremented by 2. > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ > + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ > + UDP(sport=53, dport=4369)") Nit: indentation. > +echo ${expected} > expected > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > +]) > + > +# Disable the ls2-lp1 port. > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > +]) > + > +# Send the same packet again and it should not be delivered > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# The 2nd packet sent shound not be received. > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +OVN_CLEANUP([hv1],[hv2]) > + > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv6 over IPv4]) > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > +ovn_start > + > +# Logical network: > +# Two LRs - R1 and R2 that are connected to each other as peers in 10.0.0.0/24 > +# network. R1 has a switchs ls1 (2001:db8:1::/64) connected to it. > +# R2 has ls2 (2001:db8:2::/64) connected to it. > + > +ls1_lp1_mac="f0:00:00:01:02:03" > +rp_ls1_mac="00:00:00:01:02:03" > +rp_ls2_mac="00:00:00:01:02:04" > +ls2_lp1_mac="f0:00:00:01:02:04" > + > +ls1_lp1_ip="2001:db8:1::2" > +ls2_lp1_ip="2001:db8:2::2" > + > +check ovn-nbctl lr-add R1 > +check ovn-nbctl lr-add R2 > + > +check ovn-nbctl ls-add ls1 > +check ovn-nbctl ls-add ls2 > + > +# Connect ls1 to R1 > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 2001:db8:1::1/64 > + > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > + > +# Connect ls2 to R2 > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 2001:db8:2::1/64 > + > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > + > +# Connect R1 to R2 > +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 10.0.0.1/24 peer=R2_R1 > +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 10.0.0.2/24 peer=R1_R2 > + > +AT_CHECK([ovn-nbctl lr-route-add R1 "::/0" 10.0.0.2]) > +AT_CHECK([ovn-nbctl lr-route-add R2 "::/0" 10.0.0.1]) > + > +# Create logical port ls1-lp1 in ls1 > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > + > +# Create logical port ls2-lp1 in ls2 > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > + > +# Create two hypervisor and create OVS ports corresponding to logical ports. > +net_add n1 > + > +sim_add hv1 > +as hv1 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.1 > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > + options:tx_pcap=hv1/vif1-tx.pcap \ > + options:rxq_pcap=hv1/vif1-rx.pcap \ > + ofport-request=1 > + > +sim_add hv2 > +as hv2 > +check ovs-vsctl add-br br-phys > +ovn_attach n1 br-phys 192.168.0.2 > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > + options:tx_pcap=hv2/vif1-tx.pcap \ > + options:rxq_pcap=hv2/vif1-rx.pcap \ > + ofport-request=1 > + > + > +# Pre-populate the hypervisors' ARP tables so that we don't lose any > +# packets for ARP resolution (native tunneling doesn't queue packets > +# for ARP resolution). > +OVN_POPULATE_ARP > + > +# Allow some time for ovn-northd and ovn-controller to catch up. > +wait_for_ports_up > +check ovn-nbctl --wait=hv sync > + > +# Packet to send. > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ > + IPv6(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', hlim=64)/ \ > + UDP(sport=53, dport=4369)") > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# Packet to Expect > +# The TTL should be decremented by 2. > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ > + IPv6(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', hlim=62)/ \ > + UDP(sport=53, dport=4369)") > +echo ${expected} > expected > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [1 > +]) > + > +# Disable the ls2-lp1 port. > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false > + > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [0 > +]) > + > +# Send the same packet again and it should not be delivered > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > + > +# The 2nd packet sent shound not be received. > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > + > +OVN_CLEANUP([hv1],[hv2]) > + > +AT_CLEANUP > +]) > diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c > index d45be75c7..86a3b5966 100644 > --- a/utilities/ovn-nbctl.c > +++ b/utilities/ovn-nbctl.c > @@ -4591,11 +4591,9 @@ 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) { > prefix = normalize_ipv6_prefix_str(ctx->argv[2]); > - v6_prefix = true; > } > if (!prefix) { > ctl_error(ctx, "bad prefix argument: %s", ctx->argv[2]); > @@ -4606,15 +4604,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) > if (is_discard_route) { > next_hop = xasprintf("discard"); > } else { > - next_hop = v6_prefix > - ? normalize_ipv6_addr_str(ctx->argv[3]) > - : normalize_ipv4_addr_str(ctx->argv[3]); > + next_hop = normalize_ipv4_addr_str(ctx->argv[3]); > + if (!next_hop) { > + next_hop = normalize_ipv6_addr_str(ctx->argv[3]); > + } > if (!next_hop) { > /* check if it is a output port. */ > error = lrp_by_name_or_uuid(ctx, ctx->argv[3], true, &out_lrp); > if (error) { > - ctl_error(ctx, "bad %s nexthop argument: %s", > - v6_prefix ? "IPv6" : "IPv4", ctx->argv[3]); > + ctl_error(ctx, "bad nexthop argument: %s", ctx->argv[3]); > free(error); > goto cleanup; > } Regards, Dumitru
Thank you for the review and conflict resolution Dumitru. Your changes look good for my part (register reassignment and system tests). Martin. On Tue, 2024-12-17 at 16:25 +0100, Dumitru Ceara wrote: > Hi Martin, Felix, > > On 12/4/24 4:10 PM, Martin Kalcok wrote: > > From: Felix Huettner <felix.huettner@mail.schwarz> > > > > In most cases IPv4 packets are routed only over other IPv4 networks > > and > > IPv6 packets are routed only over IPv6 networks. However there is > > no > > inherent reason for this limitation. Routing IPv4 packets over IPv6 > > networks just requires the router to contain a route for an IPv4 > > network > > with an IPv6 nexthop. > > > > This was previously prevented in OVN in ovn-nbctl and northd. By > > removing these filters the forwarding will work if the mac > > addresses are > > prepopulated. > > > > If the mac addresses are not prepopulated we will attempt to > > resolve them using > > the original address family of the packet and not the address > > family of the > > nexthop. This will fail and we will not forward the packet. > > > > This feature can for example be used by service providers to > > interconnect multiple IPv4 networks of a customer without needing > > to > > negotiate free IPv4 addresses by just using any IPv6 address. > > > > Signed-off-by: Felix Huettner <felix.huettner@mail.schwarz> > > Felix, is this email address correct? > > > Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com> > > Co-authored-by: Martin Kalcok <martin.kalcok@canonical.com> > > --- > > After merging Felix's BGP prerequisite patches, there were a bunch of > conflicts when applying this patch but I think I managed to address > them. > > I pushed the rebased patches (also with the small nits I had below > addressed) to: > https://github.com/dceara/ovn/commits/bcba1b74 > > It would be great if you could double check that it still looks OK to > you. If that's the case I can then apply the series to main. > > > NEWS | 4 + > > northd/northd.c | 81 +++--- > > northd/northd.h | 2 + > > tests/ovn-nbctl.at | 26 +- > > tests/ovn-northd.at | 150 +++++++--- > > tests/ovn.at | 645 > > ++++++++++++++++++++++++++++++++++++++++++ > > utilities/ovn-nbctl.c | 12 +- > > 7 files changed, 829 insertions(+), 91 deletions(-) > > > > diff --git a/NEWS b/NEWS > > index da3aba739..b5aae7d4b 100644 > > --- a/NEWS > > +++ b/NEWS > > @@ -75,6 +75,10 @@ OVN v24.09.0 - 13 Sep 2024 > > "routing-protocol-redirect" and "routing-protocols", that > > allow > > redirection of routing protocol traffic received by a router > > port > > to a different logical switch port. > > + - Allow Static Routes where the address families of ip_prefix > > and nexthop > > + diverge (e.g. IPv4 packets over IPv6 links). This is currently > > limited to > > + nexthops that have their mac addresses prepopulated (so > > + dynamic_neigh_routers must be false). > > > > OVN v24.03.0 - 01 Mar 2024 > > -------------------------- > > diff --git a/northd/northd.c b/northd/northd.c > > index 3564d45d9..4fb48838b 100644 > > --- a/northd/northd.c > > +++ b/northd/northd.c > > @@ -174,6 +174,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << > > 2)); > > #define REGBIT_KNOWN_LB_SESSION "reg9[6]" > > #define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]" > > #define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]" > > +#define REGBIT_NEXTHOP_IS_IPV4 "reg9[9]" > > > > /* Register to store the eth address associated to a router port > > for packets > > * received in S_ROUTER_IN_ADMISSION. > > @@ -290,7 +291,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << > > 2)); > > * | | LOOKUP_NEIGHBOR_RESULT/ | | | > > * | | SKIP_LOOKUP_NEIGHBOR/ | | | > > * | |REGBIT_DHCP_RELAY_REQ_CHK/ | | | > > - * | |REGBIT_DHCP_RELAY_RESP_CHK}| | | > > + * | |REGBIT_DHCP_RELAY_RESP_CHK | | | > > + * | |REGBIT_NEXTHOP_IS_IPV4} | | | > > * | | | | | > > * | | REG_ORIG_TP_DPORT_ROUTER | | | > > * | | | | | > > @@ -10861,13 +10863,15 @@ build_routing_policy_flow(struct > > lflow_table *lflows, struct ovn_datapath *od, > > "outport = %s; " > > "flags.loopback = 1; " > > REG_ECMP_GROUP_ID" = 0; " > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > "next;", > > is_ipv4 ? REG_NEXT_HOP_IPV4 : > > REG_NEXT_HOP_IPV6, > > nexthop, > > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > lrp_addr_s, > > out_port->lrp_networks.ea_s, > > - out_port->json_key); > > + out_port->json_key, > > + is_ipv4); > > > > } else if (!strcmp(rule->action, "drop")) { > > ds_put_cstr(&actions, debug_drop_action()); > > @@ -10951,13 +10955,15 @@ build_ecmp_routing_policy_flows(struct > > lflow_table *lflows, > > "eth.src = %s; " > > "outport = %s; " > > "flags.loopback = 1; " > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > "next;", > > is_ipv4 ? REG_NEXT_HOP_IPV4 : > > REG_NEXT_HOP_IPV6, > > rp->valid_nexthops[i], > > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > lrp_addr_s, > > out_port->lrp_networks.ea_s, > > - out_port->json_key); > > + out_port->json_key, > > + is_ipv4); > > Should we add a TODO item to remember to add support for "reroute" > routing policies that change next hop family? > > > > > ds_clear(&match); > > ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && " > > @@ -11123,6 +11129,8 @@ parsed_routes_add(struct ovn_datapath *od, > > const struct hmap *lr_ports, > > /* Verify that the next hop is an IP address with an all-ones > > mask. */ > > struct in6_addr nexthop; > > unsigned int plen; > > + bool is_ipv4_nexthop = true; > > + bool is_ipv4_prefix; > > bool is_discard_route = !strcmp(route->nexthop, "discard"); > > bool valid_nexthop = route->nexthop[0] && !is_discard_route; > > if (valid_nexthop) { > > @@ -11141,6 +11149,7 @@ parsed_routes_add(struct ovn_datapath *od, > > const struct hmap *lr_ports, > > UUID_ARGS(&route->header_.uuid)); > > return; > > } > > + is_ipv4_nexthop = IN6_IS_ADDR_V4MAPPED(&nexthop); > > } > > > > /* Parse ip_prefix */ > > @@ -11152,18 +11161,7 @@ parsed_routes_add(struct ovn_datapath *od, > > const struct hmap *lr_ports, > > UUID_ARGS(&route->header_.uuid)); > > return; > > } > > - > > - /* Verify that ip_prefix and nexthop have same address > > familiy. */ > > - if (valid_nexthop) { > > - if (IN6_IS_ADDR_V4MAPPED(&prefix) != > > IN6_IS_ADDR_V4MAPPED(&nexthop)) { > > - static struct vlog_rate_limit rl = > > VLOG_RATE_LIMIT_INIT(5, 1); > > - VLOG_WARN_RL(&rl, "Address family doesn't match > > between 'ip_prefix'" > > - " %s and 'nexthop' %s in static route > > "UUID_FMT, > > - route->ip_prefix, route->nexthop, > > - UUID_ARGS(&route->header_.uuid)); > > - return; > > - } > > - } > > + is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&prefix); > > > > /* Verify that ip_prefix and nexthop are on the same network. > > */ > > if (!is_discard_route && > > @@ -11216,6 +11214,8 @@ parsed_routes_add(struct ovn_datapath *od, > > const struct hmap *lr_ports, > > > > "ecmp_symmetric_reply", > > false); > > new_pr->is_discard_route = is_discard_route; > > + new_pr->is_ipv4_prefix = is_ipv4_prefix; > > + new_pr->is_ipv4_nexthop = is_ipv4_nexthop; > > sset_init(&new_pr->ecmp_selection_fields); > > > > /* If tp_src or tp_dst is included in the selection_fields, > > implicitly > > @@ -11646,7 +11646,7 @@ build_ecmp_route_flow(struct lflow_table > > *lflows, struct ovn_datapath *od, > > struct lflow_ref *lflow_ref, const char > > *protocol) > > > > { > > - bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix); > > + bool is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&eg->prefix); > > uint16_t priority; > > struct ecmp_route_list_node *er; > > struct ds route_match = DS_EMPTY_INITIALIZER; > > @@ -11655,7 +11655,8 @@ build_ecmp_route_flow(struct lflow_table > > *lflows, struct ovn_datapath *od, > > int ofs = !strcmp(eg->origin, ROUTE_ORIGIN_CONNECTED) ? > > ROUTE_PRIO_OFFSET_CONNECTED: ROUTE_PRIO_OFFSET_STATIC; > > build_route_match(NULL, eg->route_table_id, prefix_s, eg- > > >plen, > > - eg->is_src_route, is_ipv4, &route_match, > > &priority, ofs, > > + eg->is_src_route, is_ipv4_prefix, > > &route_match, > > + &priority, ofs, > > protocol != NULL); > > free(prefix_s); > > > > @@ -11723,7 +11724,8 @@ build_ecmp_route_flow(struct lflow_table > > *lflows, struct ovn_datapath *od, > > /* Find the outgoing port. */ > > const char *lrp_addr_s = NULL; > > struct ovn_port *out_port = NULL; > > - if (!find_static_route_outport(od, lr_ports, route, > > is_ipv4, > > + if (!find_static_route_outport(od, lr_ports, route, > > + route_->is_ipv4_nexthop, > > &lrp_addr_s, &out_port)) { > > continue; > > } > > @@ -11746,13 +11748,16 @@ build_ecmp_route_flow(struct lflow_table > > *lflows, struct ovn_datapath *od, > > "%s = %s; " > > "eth.src = %s; " > > "outport = %s; " > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > "next;", > > - is_ipv4 ? REG_NEXT_HOP_IPV4 : > > REG_NEXT_HOP_IPV6, > > + route_->is_ipv4_nexthop ? > > + REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, > > route->nexthop, > > - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > + route_->is_ipv4_nexthop ? REG_SRC_IPV4 : > > REG_SRC_IPV6, > > lrp_addr_s, > > out_port->lrp_networks.ea_s, > > - out_port->json_key); > > + out_port->json_key, > > + route_->is_ipv4_nexthop); > > ovn_lflow_add_with_hint(lflows, od, > > S_ROUTER_IN_IP_ROUTING_ECMP, 100, > > ds_cstr(&match), > > ds_cstr(&actions), > > &route->header_, lflow_ref); > > @@ -11770,15 +11775,15 @@ add_route(struct lflow_table *lflows, > > struct ovn_datapath *od, > > bool is_src_route, const uint32_t rtb_id, > > const struct sset *bfd_ports, > > const struct ovsdb_idl_row *stage_hint, bool > > is_discard_route, > > - int ofs, struct lflow_ref *lflow_ref) > > + int ofs, struct lflow_ref *lflow_ref, > > + bool is_ipv4_prefix, bool is_ipv4_nexthop) > > { > > - bool is_ipv4 = strchr(network_s, '.') ? true : false; > > struct ds match = DS_EMPTY_INITIALIZER; > > uint16_t priority; > > const struct ovn_port *op_inport = NULL; > > > > /* IPv6 link-local addresses must be scoped to the local > > router port. */ > > - if (!is_ipv4) { > > + if (!is_ipv4_prefix) { > > struct in6_addr network; > > ovs_assert(ipv6_parse(network_s, &network)); > > if (in6_is_lla(&network)) { > > @@ -11786,7 +11791,7 @@ add_route(struct lflow_table *lflows, > > struct ovn_datapath *od, > > } > > } > > build_route_match(op_inport, rtb_id, network_s, plen, > > is_src_route, > > - is_ipv4, &match, &priority, ofs, false); > > + is_ipv4_prefix, &match, &priority, ofs, > > false); > > > > struct ds common_actions = DS_EMPTY_INITIALIZER; > > struct ds actions = DS_EMPTY_INITIALIZER; > > @@ -11794,22 +11799,25 @@ add_route(struct lflow_table *lflows, > > struct ovn_datapath *od, > > ds_put_cstr(&actions, debug_drop_action()); > > } else { > > ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s > > = ", > > - is_ipv4 ? REG_NEXT_HOP_IPV4 : > > REG_NEXT_HOP_IPV6); > > + is_ipv4_nexthop ? REG_NEXT_HOP_IPV4 : > > REG_NEXT_HOP_IPV6); > > if (gateway && gateway[0]) { > > ds_put_cstr(&common_actions, gateway); > > } else { > > - ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? > > "4" : "6"); > > + ds_put_format(&common_actions, "ip%s.dst", > > + is_ipv4_prefix ? "4" : "6"); > > } > > ds_put_format(&common_actions, "; " > > "%s = %s; " > > "eth.src = %s; " > > "outport = %s; " > > "flags.loopback = 1; " > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > "next;", > > - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > + is_ipv4_nexthop ? REG_SRC_IPV4 : > > REG_SRC_IPV6, > > lrp_addr_s, > > op->lrp_networks.ea_s, > > - op->json_key); > > + op->json_key, > > + is_ipv4_nexthop); > > ds_put_format(&actions, "ip.ttl--; %s", > > ds_cstr(&common_actions)); > > } > > > > @@ -11860,7 +11868,8 @@ build_static_route_flow(struct lflow_table > > *lflows, struct ovn_datapath *od, > > lrp_addr_s, prefix_s, route_->plen, route->nexthop, > > route_->is_src_route, route_->route_table_id, > > bfd_ports, &route->header_, route_- > > >is_discard_route, > > - ofs, lflow_ref); > > + ofs, lflow_ref, > > + route_->is_ipv4_prefix, route_->is_ipv4_nexthop); > > > > free(prefix_s); > > } > > @@ -13708,7 +13717,7 @@ build_ip_routing_flows_for_lrp(struct > > ovn_port *op, > > op->lrp_networks.ipv4_addrs[i].network_s, > > op->lrp_networks.ipv4_addrs[i].plen, NULL, > > false, 0, > > bfd_ports, &op->nbrp->header_, false, > > - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, true, > > true); > > } > > > > for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > > @@ -13716,7 +13725,7 @@ build_ip_routing_flows_for_lrp(struct > > ovn_port *op, > > op->lrp_networks.ipv6_addrs[i].network_s, > > op->lrp_networks.ipv6_addrs[i].plen, NULL, > > false, 0, > > bfd_ports, &op->nbrp->header_, false, > > - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, false, > > false); > > } > > } > > > > @@ -14069,11 +14078,13 @@ build_arp_resolve_flows_for_lrouter( > > "ip4.mcast || ip6.mcast", "next;", > > lflow_ref); > > > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", > > + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, > > + REGBIT_NEXTHOP_IS_IPV4 " == 1", > > "get_arp(outport, " REG_NEXT_HOP_IPV4 "); > > next;", > > lflow_ref); > > > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", > > + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, > > + REGBIT_NEXTHOP_IS_IPV4 " == 0", > > "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;", > > lflow_ref); > > > > @@ -17033,7 +17044,7 @@ build_routable_flows_for_router_port( > > laddrs->ipv4_addrs[k].plen, NULL, > > false, 0, > > bfd_ports, &router_port->nbrp- > > >header_, > > false, ROUTE_PRIO_OFFSET_CONNECTED, > > - lrp->stateful_lflow_ref); > > + lrp->stateful_lflow_ref, true, > > true); > > } > > } > > } > > diff --git a/northd/northd.h b/northd/northd.h > > index e93e10f20..a5af72eb7 100644 > > --- a/northd/northd.h > > +++ b/northd/northd.h > > @@ -709,6 +709,8 @@ struct parsed_route { > > const struct nbrec_logical_router *nbr; > > bool stale; > > struct sset ecmp_selection_fields; > > + bool is_ipv4_prefix; > > + bool is_ipv4_nexthop; > > }; > > > > void ovnnb_db_run(struct northd_input *input_data, > > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at > > index 2efa13b93..addcc4593 100644 > > --- a/tests/ovn-nbctl.at > > +++ b/tests/ovn-nbctl.at > > @@ -1857,7 +1857,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 > > 10.0.0.1/24 11.0.0.2]) > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp0]) > > AT_CHECK([ovn-nbctl --bfd lr-route-add lr0 10.0.20.0/24 11.0.2.1 > > lp0]) > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp1], [1], [], > > - [ovn-nbctl: bad IPv4 nexthop argument: lp1 > > + [ovn-nbctl: bad nexthop argument: lp1 > > ]) > > > > dnl Add overlapping route with 10.0.0.1/24 > > @@ -1871,13 +1871,13 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 > > 10.0.0.111/24a 11.0.0.1], [1], [], > > [ovn-nbctl: bad prefix argument: 10.0.0.111/24a > > ]) > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1a], > > [1], [], > > - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1a > > + [ovn-nbctl: bad nexthop argument: 11.0.0.1a > > ]) > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1/24], > > [1], [], > > - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1/24 > > + [ovn-nbctl: bad nexthop argument: 11.0.0.1/24 > > ]) > > AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 > > 2001:0db8:0:f103::1/64], [1], [], > > - [ovn-nbctl: bad IPv6 nexthop argument: 2001:0db8:0:f103::1/64 > > + [ovn-nbctl: bad nexthop argument: 2001:0db8:0:f103::1/64 > > ]) > > AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 20.0.0.0/24 discard], > > [1], [], > > [ovn-nbctl: ecmp is not valid for discard routes. > > @@ -2105,6 +2105,24 @@ check ovn-nbctl lr-route-del lr0 > > AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl > > ]) > > > > +dnl Check IPv4 over v6 and IPv6 over v4 routes > > +AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 > > 2001:0db8:0:f103::10]) > > +AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 11.0.1.10]) > > + > > +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl > > +IPv4 Routes > > +Route Table <main>: > > + 10.0.0.0/24 2001:db8:0:f103::10 dst-ip > > + > > +IPv6 Routes > > +Route Table <main>: > > + 2001:db8::/64 11.0.1.10 dst-ip > > +]) > > + > > +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 > > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > > index c98f1fcb4..803823afa 100644 > > --- a/tests/ovn-northd.at > > +++ b/tests/ovn-northd.at > > @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | > > ovn_strip_lflows], [0], [dnl > > table=??(lr_in_policy ), priority=0 , match=(1), > > action=(reg8[[0..15]] = 0; next;) > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, > > 2);) > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; flags.loopback = 1; next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; flags.loopback = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=150 , > > match=(reg8[[0..15]] == 0), action=(next;) > > ]) > > > > @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0- > > 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > select(1, 2);) > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > select(1, 2, 3);) > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=150 , > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > ]) > > > > @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0- > > 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf > > table=??(lr_in_policy ), priority=0 , match=(1), > > action=(reg8[[0..15]] = <cleared>; next;) > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > select(1, 2);) > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > select(1, 2, 3);) > > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > = 1; reg8[[0..15]] = <cleared>; next;) > > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=150 , > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > ]) > > > > @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0- > > 9]]*/reg8\[[0..15\]] = <cleared>/' | \ > > sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' > > | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_policy ), priority=0 , match=(1), > > action=(reg8[[0..15]] = <cleared>; next;) > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > select(1, 2, 3);) > > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > = 1; reg8[[0..15]] = <cleared>; next;) > > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > - table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_policy_ecmp ), priority=100 , > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=150 , > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > ]) > > > > @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | \ > > sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | > > \ > > sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' > > | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_policy ), priority=0 , match=(1), > > action=(reg8[[0..15]] = <cleared>; next;) > > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > = 1; reg8[[0..15]] = <cleared>; next;) > > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > action=(drop;) > > table=??(lr_in_policy_ecmp ), priority=150 , > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > ]) > > @@ -6823,14 +6823,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" > > lr0flows | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_ip_routing ), priority=0 , match=(1), > > action=(drop;) > > table=??(lr_in_ip_routing ), priority=10300, > > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == > > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = > > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; > > next;) > > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > nd_ra), action=(drop;) > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 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=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 > > && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; > > reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;) > > - table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; next;) > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > ]) > > > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | > > ovn_strip_lflows], [0], [dnl > > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; next;) > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > table=??(lr_in_ip_routing_ecmp), priority=150 , > > match=(reg8[[0..15]] == 0), action=(next;) > > ]) > > > > @@ -6841,14 +6841,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" > > lr0flows | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_ip_routing ), priority=0 , match=(1), > > action=(drop;) > > table=??(lr_in_ip_routing ), priority=10300, > > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == > > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = > > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; > > next;) > > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > nd_ra), action=(drop;) > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 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=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 > > && 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=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; next;) > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > ]) > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed > > 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; next;) > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; next;) > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > table=??(lr_in_ip_routing_ecmp), priority=150 , > > match=(reg8[[0..15]] == 0), action=(next;) > > ]) > > > > @@ -6870,14 +6870,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" > > lr0flows | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_ip_routing ), priority=0 , match=(1), > > action=(drop;) > > table=??(lr_in_ip_routing ), priority=10300, > > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == > > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = > > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; > > next;) > > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > nd_ra), action=(drop;) > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 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=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 > > && 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=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; next;) > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > ]) > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed > > 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl > > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; next;) > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; next;) > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > table=??(lr_in_ip_routing_ecmp), priority=150 , > > match=(reg8[[0..15]] == 0), action=(next;) > > ]) > > > > @@ -6888,14 +6888,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 | > > ovn_strip_lflows], [0], [dnl > > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.0.10; reg5 = 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=122 , match=(reg7 == 0 > > && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 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 | > > ovn_strip_lflows], [0], [dnl > > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = ip4.dst; reg5 = 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=122 , match=(reg7 == 0 > > && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > ]) > > > > check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11 > > @@ -6928,6 +6928,66 @@ AT_CHECK([grep -e "(lr_in_ip_routing > > ).*3.3.0.0" lr0flows | sed 's/table=../ta > > AT_CLEANUP > > ]) > > > > +OVN_FOR_EACH_NORTHD_NO_HV([ > > +AT_SETUP([ovn -- static routes multiple address families flows]) > > +AT_KEYWORDS([static-routes-flows]) > > +ovn_start > > + > > +check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 > > + > > +check ovn-nbctl lr-add lr0 > > +check ovn-nbctl set logical_router lr0 options:chassis=ch1 > > +check ovn-nbctl ls-add public > > +check ovn-nbctl ls-add private > > +check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 > > 192.168.0.1/24 > > +check ovn-nbctl lsp-add public public-lr0 > > +check ovn-nbctl lsp-set-type public-lr0 router > > +check ovn-nbctl lsp-set-addresses public-lr0 router > > +check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public > > + > > +check ovn-nbctl lrp-add lr0 lr0-private 00:00:20:20:12:14 > > 2001:db8::1/64 > > +check ovn-nbctl lsp-add private private-lr0 > > +check ovn-nbctl lsp-set-type private-lr0 router > > +check ovn-nbctl lsp-set-addresses private-lr0 router > > +check ovn-nbctl lsp-set-options private-lr0 router-port=lr0- > > private > > + > > +check ovn-nbctl --wait=sb lr-route-add lr0 10.0.0.0/24 > > 192.168.0.10 > > +check ovn-nbctl --wait=sb lr-route-add lr0 11.0.0.0/24 > > 2001:db8::10 > > +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:1::/64 > > 192.168.0.20 > > +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:2::/64 > > 2001:db8::20 > > + > > +ovn-sbctl dump-flows lr0 > lr0flows > > +AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | > > ovn_strip_lflows], [0], [dnl > > + table=??(lr_in_ip_routing ), priority=0 , match=(1), > > action=(drop;) > > + table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > nd_ra), action=(drop;) > > + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = > > 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; > > reg9[[9]] = 0; next;) > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 > > && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = > > 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 > > && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = > > 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = > > 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; > > reg9[[9]] = 0; next;) > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = > > "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > + table=??(lr_in_ip_routing ), priority=324 , match=(ip6.dst == > > 2001:db8::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = > > ip6.dst; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport > > = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > > +]) > > + > > +AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | > > ovn_strip_lflows], [0], [dnl > > + table=??(lr_in_arp_resolve ), priority=0 , match=(1), > > action=(drop;) > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > == 0), action=(get_nd(outport, xxreg0); next;) > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > == 1), action=(get_arp(outport, reg0); next;) > > + table=??(lr_in_arp_resolve ), priority=500 , match=(ip4.mcast > > || ip6.mcast), action=(next;) > > +]) > > + > > +AT_CHECK([grep -e "lr_in_arp_request" lr0flows | > > ovn_strip_lflows], [0], [dnl > > + table=??(lr_in_arp_request ), priority=0 , match=(1), > > action=(output;) > > + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == > > 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = > > ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; > > output; }; output;) > > + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == > > 00:00:00:00:00:00 && ip6), action=(nd_ns { nd.target = xxreg0; > > output; }; output;) > > + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == > > 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::10), action=(nd_ns > > { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target > > = 2001:db8::10; output; }; output;) > > + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == > > 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::20), action=(nd_ns > > { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target > > = 2001:db8::20; output; }; output;) > > +]) > > + > > +AT_CLEANUP > > +]) > > + > > OVN_FOR_EACH_NORTHD_NO_HV([ > > AT_SETUP([ovn-northd -- lr multiple gw ports]) > > AT_KEYWORDS([multiple-l3dgw-ports]) > > @@ -7346,16 +7406,16 @@ AT_CHECK([grep "lr_in_ip_routing_pre" > > lr0flows | ovn_strip_lflows], [0], [dnl > > grep -e "(lr_in_ip_routing ).*outport" lr0flows > > > > AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | > > ovn_strip_lflows], [0], [dnl > > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 1 > > && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = > > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = > > "lrp0"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = > > "lrp1"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = > > "lrp2"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 > > && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = > > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > outport = "lrp0"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > outport = "lrp0"; flags.loopback = 1; next;) > > - table=??(lr_in_ip_routing ), priority=324 , 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=324 , 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=324 , 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=122 , match=(reg7 == 1 > > && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = > > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] > > = 1; next;) > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = > > "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = > > "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = > > "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 > > && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; > > reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = > > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] > > = 1; next;) > > + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] > > = 0; next;) > > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] > > = 0; next;) > > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] > > = 0; next;) > > ]) > > > > AT_CLEANUP > > @@ -13450,8 +13510,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | > > ovn_strip_lflows], [0], [dnl > > > > AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], > > [0], [dnl > > table=??(lr_in_arp_resolve ), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), > > action=(get_arp(outport, reg0); next;) > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), > > action=(get_nd(outport, xxreg0); next;) > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > == 0), action=(get_nd(outport, xxreg0); next;) > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > == 1), action=(get_arp(outport, reg0); next;) > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = > > 00:00:00:00:ff:02; next;) > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = > > 30:54:00:00:00:03; next;) > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = > > 00:00:00:00:ff:02; next;) > > @@ -13620,8 +13680,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | > > ovn_strip_lflows], [0], [dnl > > > > AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], > > [0], [dnl > > table=??(lr_in_arp_resolve ), priority=0 , match=(1), > > action=(drop;) > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), > > action=(get_arp(outport, reg0); next;) > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), > > action=(get_nd(outport, xxreg0); next;) > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > == 0), action=(get_nd(outport, xxreg0); next;) > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > == 1), action=(get_arp(outport, reg0); next;) > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = > > 00:00:00:00:ff:02; next;) > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = > > 00:00:00:00:ff:02; next;) > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = > > 00:00:00:00:ff:02; next;) > > diff --git a/tests/ovn.at b/tests/ovn.at > > index 1071208d1..ec90a3b4e 100644 > > --- a/tests/ovn.at > > +++ b/tests/ovn.at > > @@ -39761,3 +39761,648 @@ OVN_CLEANUP([hv1]) > > > > AT_CLEANUP > > ]) > > + > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv4 over IPv6]) > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > +ovn_start > > + > > +# Logical network: > > +# Two LRs - R1 and R2 that are connected to each other as peers in > > 2001:db8::/64 > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > + > > +ls1_lp1_mac="f0:00:00:01:02:03" > > +rp_ls1_mac="00:00:00:01:02:03" > > +rp_ls2_mac="00:00:00:01:02:04" > > +ls2_lp1_mac="f0:00:00:01:02:04" > > + > > +ls1_lp1_ip="192.168.1.2" > > +ls2_lp1_ip="172.16.1.2" > > + > > +check ovn-nbctl lr-add R1 > > +check ovn-nbctl lr-add R2 > > + > > +check ovn-nbctl ls-add ls1 > > +check ovn-nbctl ls-add ls2 > > + > > +# Connect ls1 to R1 > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > + > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > ls1 type=router \ > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > + > > +# Connect ls2 to R2 > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > + > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > ls2 type=router \ > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > + > > +# Connect R1 to R2 > > +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 2001:db8::1/64 > > peer=R2_R1 > > +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 2001:db8::2/64 > > peer=R1_R2 > > + > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > > + > > +# Create logical port ls1-lp1 in ls1 > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > + > > +# Create logical port ls2-lp1 in ls2 > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > + > > +# Create two hypervisor and create OVS ports corresponding to > > logical ports. > > +net_add n1 > > + > > +sim_add hv1 > > +as hv1 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.1 > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > + ofport-request=1 > > + > > +sim_add hv2 > > +as hv2 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.2 > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > + ofport-request=1 > > + > > + > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > any > > +# packets for ARP resolution (native tunneling doesn't queue > > packets > > +# for ARP resolution). > > +OVN_POPULATE_ARP > > + > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > +wait_for_ports_up > > +check ovn-nbctl --wait=hv sync > > + > > +# Packet to send. > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > src='${ls1_lp1_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# Packet to Expect > > +# The TTL should be decremented by 2. > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > src='${rp_ls2_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +echo ${expected} > expected > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > +]) > > + > > +# Disable the ls2-lp1 port. > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > enabled=false > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > +]) > > + > > +# Send the same packet again and it should not be delivered > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# The 2nd packet sent shound not be received. > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +OVN_CLEANUP([hv1],[hv2]) > > + > > +AT_CLEANUP > > +]) > > + > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over > > IPv6]) > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > +ovn_start > > + > > +# Logical network: > > +# Two LRs - R1 and R2 that are connected to ls-transfer in > > 2001:db8::/64 > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > + > > +ls1_lp1_mac="f0:00:00:01:02:03" > > +rp_ls1_mac="00:00:00:01:02:03" > > +rp_ls2_mac="00:00:00:01:02:04" > > +ls2_lp1_mac="f0:00:00:01:02:04" > > + > > +ls1_lp1_ip="192.168.1.2" > > +ls2_lp1_ip="172.16.1.2" > > + > > +check ovn-nbctl lr-add R1 > > +check ovn-nbctl lr-add R2 > > + > > +check ovn-nbctl ls-add ls1 > > +check ovn-nbctl ls-add ls2 > > +check ovn-nbctl ls-add ls-transfer > > + > > +# Connect ls1 to R1 > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > + > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > ls1 type=router \ > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > + > > +# Connect ls2 to R2 > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > + > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > ls2 type=router \ > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > + > > +# Connect R1 to R2 > > +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 > > 2001:db8::1/64 > > +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 > > 2001:db8::2/64 > > + > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ > > + set Logical_Switch_Port ls-transfer_r1 type=router \ > > + options:router-port=R1_ls-transfer addresses=\"router\" > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ > > + set Logical_Switch_Port ls-transfer_r2 type=router \ > > + options:router-port=R2_ls-transfer addresses=\"router\" > > + > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > > + > > +# Create logical port ls1-lp1 in ls1 > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > + > > +# Create logical port ls2-lp1 in ls2 > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > + > > +# Create two hypervisor and create OVS ports corresponding to > > logical ports. > > +net_add n1 > > + > > +sim_add hv1 > > +as hv1 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.1 > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > + ofport-request=1 > > + > > +sim_add hv2 > > +as hv2 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.2 > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > + ofport-request=1 > > + > > + > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > any > > +# packets for ARP resolution (native tunneling doesn't queue > > packets > > +# for ARP resolution). > > +OVN_POPULATE_ARP > > + > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > +wait_for_ports_up > > +check ovn-nbctl --wait=hv sync > > + > > +# Packet to send. > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > src='${ls1_lp1_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# Packet to Expect > > +# The TTL should be decremented by 2. > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > src='${rp_ls2_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +echo ${expected} > expected > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > +]) > > + > > +# Disable the ls2-lp1 port. > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > enabled=false > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > +]) > > + > > +# Send the same packet again and it should not be delivered > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# The 2nd packet sent shound not be received. > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +OVN_CLEANUP([hv1],[hv2]) > > + > > +AT_CLEANUP > > +]) > > + > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over > > IPv6, static mac]) > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > +ovn_start > > + > > +# Logical network: > > +# Two LRs - R1 and R2 that are connected to ls-transfer in > > 2001:db8::/64 > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > + > > +ls1_lp1_mac="f0:00:00:01:02:03" > > +rp_ls1_mac="00:00:00:01:02:03" > > +rp_ls2_mac="00:00:00:01:02:04" > > +ls2_lp1_mac="f0:00:00:01:02:04" > > + > > +ls1_lp1_ip="192.168.1.2" > > +ls2_lp1_ip="172.16.1.2" > > + > > +check ovn-nbctl lr-add R1 > > +check ovn-nbctl lr-add R2 > > + > > +check ovn-nbctl ls-add ls1 > > +check ovn-nbctl ls-add ls2 > > +check ovn-nbctl ls-add ls-transfer > > + > > +# Connect ls1 to R1 > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > +check ovn-nbctl set Logical_Router R1 > > options:dynamic_neigh_routers=true > > + > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > ls1 type=router \ > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > + > > +# Connect ls2 to R2 > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > +check ovn-nbctl set Logical_Router R2 > > options:dynamic_neigh_routers=true > > + > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > ls2 type=router \ > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > + > > +# Connect R1 to R2 > > +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 > > 2001:db8::1/64 > > +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 > > 2001:db8::2/64 > > + > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ > > + set Logical_Switch_Port ls-transfer_r1 type=router \ > > + options:router-port=R1_ls-transfer addresses=\"router\" > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ > > + set Logical_Switch_Port ls-transfer_r2 type=router \ > > + options:router-port=R2_ls-transfer addresses=\"router\" > > + > > +# Static mac binding entries > > +check ovn-nbctl static-mac-binding-add R1_ls-transfer 2001:db8::2 > > 00:00:00:02:03:05 > > +check ovn-nbctl static-mac-binding-add R2_ls-transfer 2001:db8::1 > > 00:00:00:02:03:04 > > + > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > > + > > +# Create logical port ls1-lp1 in ls1 > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > + > > +# Create logical port ls2-lp1 in ls2 > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > + > > +# Create two hypervisor and create OVS ports corresponding to > > logical ports. > > +net_add n1 > > + > > +sim_add hv1 > > +as hv1 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.1 > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > + ofport-request=1 > > + > > +sim_add hv2 > > +as hv2 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.2 > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > + ofport-request=1 > > + > > + > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > any > > +# packets for ARP resolution (native tunneling doesn't queue > > packets > > +# for ARP resolution). > > +OVN_POPULATE_ARP > > + > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > +wait_for_ports_up > > +check ovn-nbctl --wait=hv sync > > + > > +# Packet to send. > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > src='${ls1_lp1_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# Packet to Expect > > +# The TTL should be decremented by 2. > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > src='${rp_ls2_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +echo ${expected} > expected > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > +]) > > + > > +# Disable the ls2-lp1 port. > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > enabled=false > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > +]) > > + > > +# Send the same packet again and it should not be delivered > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# The 2nd packet sent shound not be received. > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +OVN_CLEANUP([hv1],[hv2]) > > + > > +AT_CLEANUP > > +]) > > + > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over > > IPv6, ECMP]) > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > +ovn_start > > + > > +# Logical network: > > +# Two LRs - R1 and R2 that are connected to ls-transfer1 and lr- > > transfer2 in > > +# 2001:db8:1::/64 and 2001:db8:2::/64 > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > + > > +ls1_lp1_mac="f0:00:00:01:02:03" > > +rp_ls1_mac="00:00:00:01:02:03" > > +rp_ls2_mac="00:00:00:01:02:04" > > +ls2_lp1_mac="f0:00:00:01:02:04" > > + > > +ls1_lp1_ip="192.168.1.2" > > +ls2_lp1_ip="172.16.1.2" > > + > > +check ovn-nbctl lr-add R1 > > +check ovn-nbctl lr-add R2 > > + > > +check ovn-nbctl ls-add ls1 > > +check ovn-nbctl ls-add ls2 > > +check ovn-nbctl ls-add ls-transfer1 > > +check ovn-nbctl ls-add ls-transfer2 > > + > > +# Connect ls1 to R1 > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > + > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > ls1 type=router \ > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > + > > +# Connect ls2 to R2 > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > + > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > ls2 type=router \ > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > + > > +# Connect R1 to R2 (ls-transfer1) > > +check ovn-nbctl lrp-add R1 R1_ls-transfer1 00:00:00:02:03:04 > > 2001:db8:1::1/64 > > +check ovn-nbctl lrp-add R2 R2_ls-transfer1 00:00:00:02:03:05 > > 2001:db8:1::2/64 > > + > > +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r1 -- \ > > + set Logical_Switch_Port ls-transfer1_r1 type=router \ > > + options:router-port=R1_ls-transfer1 addresses=\"router\" > > +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r2 -- \ > > + set Logical_Switch_Port ls-transfer1_r2 type=router \ > > + options:router-port=R2_ls-transfer1 addresses=\"router\" > > + > > +# Connect R1 to R2 (ls-transfer2) > > +check ovn-nbctl lrp-add R1 R1_ls-transfer2 00:00:00:02:03:14 > > 2001:db8:2::1/64 > > +check ovn-nbctl lrp-add R2 R2_ls-transfer2 00:00:00:02:03:15 > > 2001:db8:2::2/64 > > + > > +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r1 -- \ > > + set Logical_Switch_Port ls-transfer2_r1 type=router \ > > + options:router-port=R1_ls-transfer2 addresses=\"router\" > > +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r2 -- \ > > + set Logical_Switch_Port ls-transfer2_r2 type=router \ > > + options:router-port=R2_ls-transfer2 addresses=\"router\" > > + > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8:1::2]) > > +AT_CHECK([ovn-nbctl --ecmp lr-route-add R1 "0.0.0.0/0" > > 2001:db8:2::2]) > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8:1::1]) > > +AT_CHECK([ovn-nbctl --ecmp lr-route-add R2 "0.0.0.0/0" > > 2001:db8:2::1]) > > + > > +# Create logical port ls1-lp1 in ls1 > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > + > > +# Create logical port ls2-lp1 in ls2 > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > + > > +# Create two hypervisor and create OVS ports corresponding to > > logical ports. > > +net_add n1 > > + > > +sim_add hv1 > > +as hv1 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.1 > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > + ofport-request=1 > > + > > +sim_add hv2 > > +as hv2 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.2 > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > + ofport-request=1 > > + > > + > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > any > > +# packets for ARP resolution (native tunneling doesn't queue > > packets > > +# for ARP resolution). > > +OVN_POPULATE_ARP > > + > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > +wait_for_ports_up > > +check ovn-nbctl --wait=hv sync > > + > > +# Packet to send. > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > src='${ls1_lp1_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# Packet to Expect > > +# The TTL should be decremented by 2. > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > src='${rp_ls2_mac}')/ \ > > + IP(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > + UDP(sport=53, dport=4369)") > > Nit: indentation. > > > +echo ${expected} > expected > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > +]) > > + > > +# Disable the ls2-lp1 port. > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > enabled=false > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > +]) > > + > > +# Send the same packet again and it should not be delivered > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# The 2nd packet sent shound not be received. > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +OVN_CLEANUP([hv1],[hv2]) > > + > > +AT_CLEANUP > > +]) > > + > > +OVN_FOR_EACH_NORTHD([ > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv6 over IPv4]) > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > +ovn_start > > + > > +# Logical network: > > +# Two LRs - R1 and R2 that are connected to each other as peers in > > 10.0.0.0/24 > > +# network. R1 has a switchs ls1 (2001:db8:1::/64) connected to it. > > +# R2 has ls2 (2001:db8:2::/64) connected to it. > > + > > +ls1_lp1_mac="f0:00:00:01:02:03" > > +rp_ls1_mac="00:00:00:01:02:03" > > +rp_ls2_mac="00:00:00:01:02:04" > > +ls2_lp1_mac="f0:00:00:01:02:04" > > + > > +ls1_lp1_ip="2001:db8:1::2" > > +ls2_lp1_ip="2001:db8:2::2" > > + > > +check ovn-nbctl lr-add R1 > > +check ovn-nbctl lr-add R2 > > + > > +check ovn-nbctl ls-add ls1 > > +check ovn-nbctl ls-add ls2 > > + > > +# Connect ls1 to R1 > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 2001:db8:1::1/64 > > + > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > ls1 type=router \ > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > + > > +# Connect ls2 to R2 > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 2001:db8:2::1/64 > > + > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > ls2 type=router \ > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > + > > +# Connect R1 to R2 > > +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 10.0.0.1/24 > > peer=R2_R1 > > +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 10.0.0.2/24 > > peer=R1_R2 > > + > > +AT_CHECK([ovn-nbctl lr-route-add R1 "::/0" 10.0.0.2]) > > +AT_CHECK([ovn-nbctl lr-route-add R2 "::/0" 10.0.0.1]) > > + > > +# Create logical port ls1-lp1 in ls1 > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > + > > +# Create logical port ls2-lp1 in ls2 > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > + > > +# Create two hypervisor and create OVS ports corresponding to > > logical ports. > > +net_add n1 > > + > > +sim_add hv1 > > +as hv1 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.1 > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > + ofport-request=1 > > + > > +sim_add hv2 > > +as hv2 > > +check ovs-vsctl add-br br-phys > > +ovn_attach n1 br-phys 192.168.0.2 > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > + ofport-request=1 > > + > > + > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > any > > +# packets for ARP resolution (native tunneling doesn't queue > > packets > > +# for ARP resolution). > > +OVN_POPULATE_ARP > > + > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > +wait_for_ports_up > > +check ovn-nbctl --wait=hv sync > > + > > +# Packet to send. > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > src='${ls1_lp1_mac}')/ \ > > + IPv6(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', hlim=64)/ \ > > + UDP(sport=53, dport=4369)") > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# Packet to Expect > > +# The TTL should be decremented by 2. > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > src='${rp_ls2_mac}')/ \ > > + IPv6(src='${ls1_lp1_ip}', > > dst='${ls2_lp1_ip}', hlim=62)/ \ > > + UDP(sport=53, dport=4369)") > > +echo ${expected} > expected > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [1 > > +]) > > + > > +# Disable the ls2-lp1 port. > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > enabled=false > > + > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [0 > > +]) > > + > > +# Send the same packet again and it should not be delivered > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > + > > +# The 2nd packet sent shound not be received. > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > + > > +OVN_CLEANUP([hv1],[hv2]) > > + > > +AT_CLEANUP > > +]) > > diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c > > index d45be75c7..86a3b5966 100644 > > --- a/utilities/ovn-nbctl.c > > +++ b/utilities/ovn-nbctl.c > > @@ -4591,11 +4591,9 @@ 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) { > > prefix = normalize_ipv6_prefix_str(ctx->argv[2]); > > - v6_prefix = true; > > } > > if (!prefix) { > > ctl_error(ctx, "bad prefix argument: %s", ctx->argv[2]); > > @@ -4606,15 +4604,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) > > if (is_discard_route) { > > next_hop = xasprintf("discard"); > > } else { > > - next_hop = v6_prefix > > - ? normalize_ipv6_addr_str(ctx->argv[3]) > > - : normalize_ipv4_addr_str(ctx->argv[3]); > > + next_hop = normalize_ipv4_addr_str(ctx->argv[3]); > > + if (!next_hop) { > > + next_hop = normalize_ipv6_addr_str(ctx->argv[3]); > > + } > > if (!next_hop) { > > /* check if it is a output port. */ > > error = lrp_by_name_or_uuid(ctx, ctx->argv[3], true, > > &out_lrp); > > if (error) { > > - ctl_error(ctx, "bad %s nexthop argument: %s", > > - v6_prefix ? "IPv6" : "IPv4", ctx- > > >argv[3]); > > + ctl_error(ctx, "bad nexthop argument: %s", ctx- > > >argv[3]); > > free(error); > > goto cleanup; > > } > > Regards, > Dumitru >
On Tue, Dec 17, 2024 at 04:41:44PM +0100, martin.kalcok@canonical.com wrote: > Thank you for the review and conflict resolution Dumitru. Your changes > look good for my part (register reassignment and system tests). > > Martin. > > On Tue, 2024-12-17 at 16:25 +0100, Dumitru Ceara wrote: > > Hi Martin, Felix, > > > > On 12/4/24 4:10 PM, Martin Kalcok wrote: > > > From: Felix Huettner <felix.huettner@mail.schwarz> > > > > > > In most cases IPv4 packets are routed only over other IPv4 networks > > > and > > > IPv6 packets are routed only over IPv6 networks. However there is > > > no > > > inherent reason for this limitation. Routing IPv4 packets over IPv6 > > > networks just requires the router to contain a route for an IPv4 > > > network > > > with an IPv6 nexthop. > > > > > > This was previously prevented in OVN in ovn-nbctl and northd. By > > > removing these filters the forwarding will work if the mac > > > addresses are > > > prepopulated. > > > > > > If the mac addresses are not prepopulated we will attempt to > > > resolve them using > > > the original address family of the packet and not the address > > > family of the > > > nexthop. This will fail and we will not forward the packet. > > > > > > This feature can for example be used by service providers to > > > interconnect multiple IPv4 networks of a customer without needing > > > to > > > negotiate free IPv4 addresses by just using any IPv6 address. > > > > > > Signed-off-by: Felix Huettner <felix.huettner@mail.schwarz> > > > > Felix, is this email address correct? Hi Dumitru, we have since switched our mail domain, so now it is felix.huettner@stackit.cloud However the old one will work for the next years so we can also keep this one. > > > > > Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com> > > > Co-authored-by: Martin Kalcok <martin.kalcok@canonical.com> > > > --- > > > > After merging Felix's BGP prerequisite patches, there were a bunch of > > conflicts when applying this patch but I think I managed to address > > them. > > > > I pushed the rebased patches (also with the small nits I had below > > addressed) to: > > https://github.com/dceara/ovn/commits/bcba1b74 > > > > It would be great if you could double check that it still looks OK to > > you. If that's the case I can then apply the series to main. All of the 3 commits look good from my side. Thanks a lot for going through the conflict hell. Thanks Felix > > > > > NEWS | 4 + > > > northd/northd.c | 81 +++--- > > > northd/northd.h | 2 + > > > tests/ovn-nbctl.at | 26 +- > > > tests/ovn-northd.at | 150 +++++++--- > > > tests/ovn.at | 645 > > > ++++++++++++++++++++++++++++++++++++++++++ > > > utilities/ovn-nbctl.c | 12 +- > > > 7 files changed, 829 insertions(+), 91 deletions(-) > > > > > > diff --git a/NEWS b/NEWS > > > index da3aba739..b5aae7d4b 100644 > > > --- a/NEWS > > > +++ b/NEWS > > > @@ -75,6 +75,10 @@ OVN v24.09.0 - 13 Sep 2024 > > > "routing-protocol-redirect" and "routing-protocols", that > > > allow > > > redirection of routing protocol traffic received by a router > > > port > > > to a different logical switch port. > > > + - Allow Static Routes where the address families of ip_prefix > > > and nexthop > > > + diverge (e.g. IPv4 packets over IPv6 links). This is currently > > > limited to > > > + nexthops that have their mac addresses prepopulated (so > > > + dynamic_neigh_routers must be false). > > > > > > OVN v24.03.0 - 01 Mar 2024 > > > -------------------------- > > > diff --git a/northd/northd.c b/northd/northd.c > > > index 3564d45d9..4fb48838b 100644 > > > --- a/northd/northd.c > > > +++ b/northd/northd.c > > > @@ -174,6 +174,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << > > > 2)); > > > #define REGBIT_KNOWN_LB_SESSION "reg9[6]" > > > #define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]" > > > #define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]" > > > +#define REGBIT_NEXTHOP_IS_IPV4 "reg9[9]" > > > > > > /* Register to store the eth address associated to a router port > > > for packets > > > * received in S_ROUTER_IN_ADMISSION. > > > @@ -290,7 +291,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << > > > 2)); > > > * | | LOOKUP_NEIGHBOR_RESULT/ | | | > > > * | | SKIP_LOOKUP_NEIGHBOR/ | | | > > > * | |REGBIT_DHCP_RELAY_REQ_CHK/ | | | > > > - * | |REGBIT_DHCP_RELAY_RESP_CHK}| | | > > > + * | |REGBIT_DHCP_RELAY_RESP_CHK | | | > > > + * | |REGBIT_NEXTHOP_IS_IPV4} | | | > > > * | | | | | > > > * | | REG_ORIG_TP_DPORT_ROUTER | | | > > > * | | | | | > > > @@ -10861,13 +10863,15 @@ build_routing_policy_flow(struct > > > lflow_table *lflows, struct ovn_datapath *od, > > > "outport = %s; " > > > "flags.loopback = 1; " > > > REG_ECMP_GROUP_ID" = 0; " > > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > > "next;", > > > is_ipv4 ? REG_NEXT_HOP_IPV4 : > > > REG_NEXT_HOP_IPV6, > > > nexthop, > > > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > > lrp_addr_s, > > > out_port->lrp_networks.ea_s, > > > - out_port->json_key); > > > + out_port->json_key, > > > + is_ipv4); > > > > > > } else if (!strcmp(rule->action, "drop")) { > > > ds_put_cstr(&actions, debug_drop_action()); > > > @@ -10951,13 +10955,15 @@ build_ecmp_routing_policy_flows(struct > > > lflow_table *lflows, > > > "eth.src = %s; " > > > "outport = %s; " > > > "flags.loopback = 1; " > > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > > "next;", > > > is_ipv4 ? REG_NEXT_HOP_IPV4 : > > > REG_NEXT_HOP_IPV6, > > > rp->valid_nexthops[i], > > > is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > > lrp_addr_s, > > > out_port->lrp_networks.ea_s, > > > - out_port->json_key); > > > + out_port->json_key, > > > + is_ipv4); > > > > Should we add a TODO item to remember to add support for "reroute" > > routing policies that change next hop family? > > > > > > > > ds_clear(&match); > > > ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && " > > > @@ -11123,6 +11129,8 @@ parsed_routes_add(struct ovn_datapath *od, > > > const struct hmap *lr_ports, > > > /* Verify that the next hop is an IP address with an all-ones > > > mask. */ > > > struct in6_addr nexthop; > > > unsigned int plen; > > > + bool is_ipv4_nexthop = true; > > > + bool is_ipv4_prefix; > > > bool is_discard_route = !strcmp(route->nexthop, "discard"); > > > bool valid_nexthop = route->nexthop[0] && !is_discard_route; > > > if (valid_nexthop) { > > > @@ -11141,6 +11149,7 @@ parsed_routes_add(struct ovn_datapath *od, > > > const struct hmap *lr_ports, > > > UUID_ARGS(&route->header_.uuid)); > > > return; > > > } > > > + is_ipv4_nexthop = IN6_IS_ADDR_V4MAPPED(&nexthop); > > > } > > > > > > /* Parse ip_prefix */ > > > @@ -11152,18 +11161,7 @@ parsed_routes_add(struct ovn_datapath *od, > > > const struct hmap *lr_ports, > > > UUID_ARGS(&route->header_.uuid)); > > > return; > > > } > > > - > > > - /* Verify that ip_prefix and nexthop have same address > > > familiy. */ > > > - if (valid_nexthop) { > > > - if (IN6_IS_ADDR_V4MAPPED(&prefix) != > > > IN6_IS_ADDR_V4MAPPED(&nexthop)) { > > > - static struct vlog_rate_limit rl = > > > VLOG_RATE_LIMIT_INIT(5, 1); > > > - VLOG_WARN_RL(&rl, "Address family doesn't match > > > between 'ip_prefix'" > > > - " %s and 'nexthop' %s in static route > > > "UUID_FMT, > > > - route->ip_prefix, route->nexthop, > > > - UUID_ARGS(&route->header_.uuid)); > > > - return; > > > - } > > > - } > > > + is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&prefix); > > > > > > /* Verify that ip_prefix and nexthop are on the same network. > > > */ > > > if (!is_discard_route && > > > @@ -11216,6 +11214,8 @@ parsed_routes_add(struct ovn_datapath *od, > > > const struct hmap *lr_ports, > > > > > > "ecmp_symmetric_reply", > > > false); > > > new_pr->is_discard_route = is_discard_route; > > > + new_pr->is_ipv4_prefix = is_ipv4_prefix; > > > + new_pr->is_ipv4_nexthop = is_ipv4_nexthop; > > > sset_init(&new_pr->ecmp_selection_fields); > > > > > > /* If tp_src or tp_dst is included in the selection_fields, > > > implicitly > > > @@ -11646,7 +11646,7 @@ build_ecmp_route_flow(struct lflow_table > > > *lflows, struct ovn_datapath *od, > > > struct lflow_ref *lflow_ref, const char > > > *protocol) > > > > > > { > > > - bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix); > > > + bool is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&eg->prefix); > > > uint16_t priority; > > > struct ecmp_route_list_node *er; > > > struct ds route_match = DS_EMPTY_INITIALIZER; > > > @@ -11655,7 +11655,8 @@ build_ecmp_route_flow(struct lflow_table > > > *lflows, struct ovn_datapath *od, > > > int ofs = !strcmp(eg->origin, ROUTE_ORIGIN_CONNECTED) ? > > > ROUTE_PRIO_OFFSET_CONNECTED: ROUTE_PRIO_OFFSET_STATIC; > > > build_route_match(NULL, eg->route_table_id, prefix_s, eg- > > > >plen, > > > - eg->is_src_route, is_ipv4, &route_match, > > > &priority, ofs, > > > + eg->is_src_route, is_ipv4_prefix, > > > &route_match, > > > + &priority, ofs, > > > protocol != NULL); > > > free(prefix_s); > > > > > > @@ -11723,7 +11724,8 @@ build_ecmp_route_flow(struct lflow_table > > > *lflows, struct ovn_datapath *od, > > > /* Find the outgoing port. */ > > > const char *lrp_addr_s = NULL; > > > struct ovn_port *out_port = NULL; > > > - if (!find_static_route_outport(od, lr_ports, route, > > > is_ipv4, > > > + if (!find_static_route_outport(od, lr_ports, route, > > > + route_->is_ipv4_nexthop, > > > &lrp_addr_s, &out_port)) { > > > continue; > > > } > > > @@ -11746,13 +11748,16 @@ build_ecmp_route_flow(struct lflow_table > > > *lflows, struct ovn_datapath *od, > > > "%s = %s; " > > > "eth.src = %s; " > > > "outport = %s; " > > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > > "next;", > > > - is_ipv4 ? REG_NEXT_HOP_IPV4 : > > > REG_NEXT_HOP_IPV6, > > > + route_->is_ipv4_nexthop ? > > > + REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, > > > route->nexthop, > > > - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > > + route_->is_ipv4_nexthop ? REG_SRC_IPV4 : > > > REG_SRC_IPV6, > > > lrp_addr_s, > > > out_port->lrp_networks.ea_s, > > > - out_port->json_key); > > > + out_port->json_key, > > > + route_->is_ipv4_nexthop); > > > ovn_lflow_add_with_hint(lflows, od, > > > S_ROUTER_IN_IP_ROUTING_ECMP, 100, > > > ds_cstr(&match), > > > ds_cstr(&actions), > > > &route->header_, lflow_ref); > > > @@ -11770,15 +11775,15 @@ add_route(struct lflow_table *lflows, > > > struct ovn_datapath *od, > > > bool is_src_route, const uint32_t rtb_id, > > > const struct sset *bfd_ports, > > > const struct ovsdb_idl_row *stage_hint, bool > > > is_discard_route, > > > - int ofs, struct lflow_ref *lflow_ref) > > > + int ofs, struct lflow_ref *lflow_ref, > > > + bool is_ipv4_prefix, bool is_ipv4_nexthop) > > > { > > > - bool is_ipv4 = strchr(network_s, '.') ? true : false; > > > struct ds match = DS_EMPTY_INITIALIZER; > > > uint16_t priority; > > > const struct ovn_port *op_inport = NULL; > > > > > > /* IPv6 link-local addresses must be scoped to the local > > > router port. */ > > > - if (!is_ipv4) { > > > + if (!is_ipv4_prefix) { > > > struct in6_addr network; > > > ovs_assert(ipv6_parse(network_s, &network)); > > > if (in6_is_lla(&network)) { > > > @@ -11786,7 +11791,7 @@ add_route(struct lflow_table *lflows, > > > struct ovn_datapath *od, > > > } > > > } > > > build_route_match(op_inport, rtb_id, network_s, plen, > > > is_src_route, > > > - is_ipv4, &match, &priority, ofs, false); > > > + is_ipv4_prefix, &match, &priority, ofs, > > > false); > > > > > > struct ds common_actions = DS_EMPTY_INITIALIZER; > > > struct ds actions = DS_EMPTY_INITIALIZER; > > > @@ -11794,22 +11799,25 @@ add_route(struct lflow_table *lflows, > > > struct ovn_datapath *od, > > > ds_put_cstr(&actions, debug_drop_action()); > > > } else { > > > ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s > > > = ", > > > - is_ipv4 ? REG_NEXT_HOP_IPV4 : > > > REG_NEXT_HOP_IPV6); > > > + is_ipv4_nexthop ? REG_NEXT_HOP_IPV4 : > > > REG_NEXT_HOP_IPV6); > > > if (gateway && gateway[0]) { > > > ds_put_cstr(&common_actions, gateway); > > > } else { > > > - ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? > > > "4" : "6"); > > > + ds_put_format(&common_actions, "ip%s.dst", > > > + is_ipv4_prefix ? "4" : "6"); > > > } > > > ds_put_format(&common_actions, "; " > > > "%s = %s; " > > > "eth.src = %s; " > > > "outport = %s; " > > > "flags.loopback = 1; " > > > + REGBIT_NEXTHOP_IS_IPV4" = %d; " > > > "next;", > > > - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, > > > + is_ipv4_nexthop ? REG_SRC_IPV4 : > > > REG_SRC_IPV6, > > > lrp_addr_s, > > > op->lrp_networks.ea_s, > > > - op->json_key); > > > + op->json_key, > > > + is_ipv4_nexthop); > > > ds_put_format(&actions, "ip.ttl--; %s", > > > ds_cstr(&common_actions)); > > > } > > > > > > @@ -11860,7 +11868,8 @@ build_static_route_flow(struct lflow_table > > > *lflows, struct ovn_datapath *od, > > > lrp_addr_s, prefix_s, route_->plen, route->nexthop, > > > route_->is_src_route, route_->route_table_id, > > > bfd_ports, &route->header_, route_- > > > >is_discard_route, > > > - ofs, lflow_ref); > > > + ofs, lflow_ref, > > > + route_->is_ipv4_prefix, route_->is_ipv4_nexthop); > > > > > > free(prefix_s); > > > } > > > @@ -13708,7 +13717,7 @@ build_ip_routing_flows_for_lrp(struct > > > ovn_port *op, > > > op->lrp_networks.ipv4_addrs[i].network_s, > > > op->lrp_networks.ipv4_addrs[i].plen, NULL, > > > false, 0, > > > bfd_ports, &op->nbrp->header_, false, > > > - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > > > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, true, > > > true); > > > } > > > > > > for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { > > > @@ -13716,7 +13725,7 @@ build_ip_routing_flows_for_lrp(struct > > > ovn_port *op, > > > op->lrp_networks.ipv6_addrs[i].network_s, > > > op->lrp_networks.ipv6_addrs[i].plen, NULL, > > > false, 0, > > > bfd_ports, &op->nbrp->header_, false, > > > - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); > > > + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, false, > > > false); > > > } > > > } > > > > > > @@ -14069,11 +14078,13 @@ build_arp_resolve_flows_for_lrouter( > > > "ip4.mcast || ip6.mcast", "next;", > > > lflow_ref); > > > > > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", > > > + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, > > > + REGBIT_NEXTHOP_IS_IPV4 " == 1", > > > "get_arp(outport, " REG_NEXT_HOP_IPV4 "); > > > next;", > > > lflow_ref); > > > > > > - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", > > > + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, > > > + REGBIT_NEXTHOP_IS_IPV4 " == 0", > > > "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;", > > > lflow_ref); > > > > > > @@ -17033,7 +17044,7 @@ build_routable_flows_for_router_port( > > > laddrs->ipv4_addrs[k].plen, NULL, > > > false, 0, > > > bfd_ports, &router_port->nbrp- > > > >header_, > > > false, ROUTE_PRIO_OFFSET_CONNECTED, > > > - lrp->stateful_lflow_ref); > > > + lrp->stateful_lflow_ref, true, > > > true); > > > } > > > } > > > } > > > diff --git a/northd/northd.h b/northd/northd.h > > > index e93e10f20..a5af72eb7 100644 > > > --- a/northd/northd.h > > > +++ b/northd/northd.h > > > @@ -709,6 +709,8 @@ struct parsed_route { > > > const struct nbrec_logical_router *nbr; > > > bool stale; > > > struct sset ecmp_selection_fields; > > > + bool is_ipv4_prefix; > > > + bool is_ipv4_nexthop; > > > }; > > > > > > void ovnnb_db_run(struct northd_input *input_data, > > > diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at > > > index 2efa13b93..addcc4593 100644 > > > --- a/tests/ovn-nbctl.at > > > +++ b/tests/ovn-nbctl.at > > > @@ -1857,7 +1857,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 > > > 10.0.0.1/24 11.0.0.2]) > > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp0]) > > > AT_CHECK([ovn-nbctl --bfd lr-route-add lr0 10.0.20.0/24 11.0.2.1 > > > lp0]) > > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp1], [1], [], > > > - [ovn-nbctl: bad IPv4 nexthop argument: lp1 > > > + [ovn-nbctl: bad nexthop argument: lp1 > > > ]) > > > > > > dnl Add overlapping route with 10.0.0.1/24 > > > @@ -1871,13 +1871,13 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 > > > 10.0.0.111/24a 11.0.0.1], [1], [], > > > [ovn-nbctl: bad prefix argument: 10.0.0.111/24a > > > ]) > > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1a], > > > [1], [], > > > - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1a > > > + [ovn-nbctl: bad nexthop argument: 11.0.0.1a > > > ]) > > > AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1/24], > > > [1], [], > > > - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1/24 > > > + [ovn-nbctl: bad nexthop argument: 11.0.0.1/24 > > > ]) > > > AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 > > > 2001:0db8:0:f103::1/64], [1], [], > > > - [ovn-nbctl: bad IPv6 nexthop argument: 2001:0db8:0:f103::1/64 > > > + [ovn-nbctl: bad nexthop argument: 2001:0db8:0:f103::1/64 > > > ]) > > > AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 20.0.0.0/24 discard], > > > [1], [], > > > [ovn-nbctl: ecmp is not valid for discard routes. > > > @@ -2105,6 +2105,24 @@ check ovn-nbctl lr-route-del lr0 > > > AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl > > > ]) > > > > > > +dnl Check IPv4 over v6 and IPv6 over v4 routes > > > +AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 > > > 2001:0db8:0:f103::10]) > > > +AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 11.0.1.10]) > > > + > > > +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl > > > +IPv4 Routes > > > +Route Table <main>: > > > + 10.0.0.0/24 2001:db8:0:f103::10 dst-ip > > > + > > > +IPv6 Routes > > > +Route Table <main>: > > > + 2001:db8::/64 11.0.1.10 dst-ip > > > +]) > > > + > > > +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 > > > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at > > > index c98f1fcb4..803823afa 100644 > > > --- a/tests/ovn-northd.at > > > +++ b/tests/ovn-northd.at > > > @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | > > > ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_policy ), priority=0 , match=(1), > > > action=(reg8[[0..15]] = 0; next;) > > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, > > > 2);) > > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; flags.loopback = 1; next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > > 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; flags.loopback = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > > 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=150 , > > > match=(reg8[[0..15]] == 0), action=(next;) > > > ]) > > > > > > @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0- > > > 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf > > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > > select(1, 2);) > > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > > select(1, 2, 3);) > > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=150 , > > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > > ]) > > > > > > @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0- > > > 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf > > > table=??(lr_in_policy ), priority=0 , match=(1), > > > action=(reg8[[0..15]] = <cleared>; next;) > > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > > select(1, 2);) > > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > > select(1, 2, 3);) > > > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > > = 1; reg8[[0..15]] = <cleared>; next;) > > > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=150 , > > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > > ]) > > > > > > @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0- > > > 9]]*/reg8\[[0..15\]] = <cleared>/' | \ > > > sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' > > > | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_policy ), priority=0 , match=(1), > > > action=(reg8[[0..15]] = <cleared>; next;) > > > table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = > > > select(1, 2, 3);) > > > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > > = 1; reg8[[0..15]] = <cleared>; next;) > > > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > - table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), > > > action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), > > > action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_policy_ecmp ), priority=100 , > > > match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), > > > action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=150 , > > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > > ]) > > > > > > @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | \ > > > sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | > > > \ > > > sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' > > > | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_policy ), priority=0 , match=(1), > > > action=(reg8[[0..15]] = <cleared>; next;) > > > - table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > > = 1; reg8[[0..15]] = <cleared>; next;) > > > + table=??(lr_in_policy ), priority=10 , match=(ip4.src == > > > 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; > > > eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback > > > = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) > > > table=??(lr_in_policy_ecmp ), priority=0 , match=(1), > > > action=(drop;) > > > table=??(lr_in_policy_ecmp ), priority=150 , > > > match=(reg8[[0..15]] == <cleared>), action=(next;) > > > ]) > > > @@ -6823,14 +6823,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" > > > lr0flows | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_ip_routing ), priority=0 , match=(1), > > > action=(drop;) > > > table=??(lr_in_ip_routing ), priority=10300, > > > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == > > > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = > > > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; > > > next;) > > > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > > nd_ra), action=(drop;) > > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 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=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 > > > && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; > > > reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > > ]) > > > > > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; next;) > > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > > table=??(lr_in_ip_routing_ecmp), priority=150 , > > > match=(reg8[[0..15]] == 0), action=(next;) > > > ]) > > > > > > @@ -6841,14 +6841,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" > > > lr0flows | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_ip_routing ), priority=0 , match=(1), > > > action=(drop;) > > > table=??(lr_in_ip_routing ), priority=10300, > > > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == > > > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = > > > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; > > > next;) > > > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > > nd_ra), action=(drop;) > > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 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=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 > > > && 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=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > > ]) > > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed > > > 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; next;) > > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; next;) > > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > > table=??(lr_in_ip_routing_ecmp), priority=150 , > > > match=(reg8[[0..15]] == 0), action=(next;) > > > ]) > > > > > > @@ -6870,14 +6870,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" > > > lr0flows | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_ip_routing ), priority=0 , match=(1), > > > action=(drop;) > > > table=??(lr_in_ip_routing ), priority=10300, > > > match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == > > > 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = > > > 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; > > > next;) > > > table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > > nd_ra), action=(drop;) > > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 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=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 > > > && 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=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > > ]) > > > AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed > > > 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl > > > table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; next;) > > > - table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; next;) > > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing_ecmp), priority=100 , > > > match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = > > > 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; reg9[[9]] = 1; next;) > > > table=??(lr_in_ip_routing_ecmp), priority=150 , > > > match=(reg8[[0..15]] == 0), action=(next;) > > > ]) > > > > > > @@ -6888,14 +6888,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 | > > > ovn_strip_lflows], [0], [dnl > > > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > > && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.0.10; reg5 = 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=122 , match=(reg7 == 0 > > > && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 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 | > > > ovn_strip_lflows], [0], [dnl > > > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > > && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = ip4.dst; reg5 = 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=122 , match=(reg7 == 0 > > > && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; > > > outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > ]) > > > > > > check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11 > > > @@ -6928,6 +6928,66 @@ AT_CHECK([grep -e "(lr_in_ip_routing > > > ).*3.3.0.0" lr0flows | sed 's/table=../ta > > > AT_CLEANUP > > > ]) > > > > > > +OVN_FOR_EACH_NORTHD_NO_HV([ > > > +AT_SETUP([ovn -- static routes multiple address families flows]) > > > +AT_KEYWORDS([static-routes-flows]) > > > +ovn_start > > > + > > > +check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 > > > + > > > +check ovn-nbctl lr-add lr0 > > > +check ovn-nbctl set logical_router lr0 options:chassis=ch1 > > > +check ovn-nbctl ls-add public > > > +check ovn-nbctl ls-add private > > > +check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 > > > 192.168.0.1/24 > > > +check ovn-nbctl lsp-add public public-lr0 > > > +check ovn-nbctl lsp-set-type public-lr0 router > > > +check ovn-nbctl lsp-set-addresses public-lr0 router > > > +check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public > > > + > > > +check ovn-nbctl lrp-add lr0 lr0-private 00:00:20:20:12:14 > > > 2001:db8::1/64 > > > +check ovn-nbctl lsp-add private private-lr0 > > > +check ovn-nbctl lsp-set-type private-lr0 router > > > +check ovn-nbctl lsp-set-addresses private-lr0 router > > > +check ovn-nbctl lsp-set-options private-lr0 router-port=lr0- > > > private > > > + > > > +check ovn-nbctl --wait=sb lr-route-add lr0 10.0.0.0/24 > > > 192.168.0.10 > > > +check ovn-nbctl --wait=sb lr-route-add lr0 11.0.0.0/24 > > > 2001:db8::10 > > > +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:1::/64 > > > 192.168.0.20 > > > +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:2::/64 > > > 2001:db8::20 > > > + > > > +ovn-sbctl dump-flows lr0 > lr0flows > > > +AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > + table=??(lr_in_ip_routing ), priority=0 , match=(1), > > > action=(drop;) > > > + table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || > > > nd_ra), action=(drop;) > > > + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > > && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 > > > && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = > > > 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; > > > reg9[[9]] = 0; next;) > > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 > > > && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = > > > 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = > > > 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; > > > reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 > > > && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = > > > 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = > > > 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; > > > reg9[[9]] = 0; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > > "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = > > > "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , match=(inport == > > > "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; > > > reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = > > > fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = > > > "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , match=(ip6.dst == > > > 2001:db8::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = > > > ip6.dst; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport > > > = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) > > > +]) > > > + > > > +AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > + table=??(lr_in_arp_resolve ), priority=0 , match=(1), > > > action=(drop;) > > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > > == 0), action=(get_nd(outport, xxreg0); next;) > > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > > == 1), action=(get_arp(outport, reg0); next;) > > > + table=??(lr_in_arp_resolve ), priority=500 , match=(ip4.mcast > > > || ip6.mcast), action=(next;) > > > +]) > > > + > > > +AT_CHECK([grep -e "lr_in_arp_request" lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > + table=??(lr_in_arp_request ), priority=0 , match=(1), > > > action=(output;) > > > + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == > > > 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = > > > ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; > > > output; }; output;) > > > + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == > > > 00:00:00:00:00:00 && ip6), action=(nd_ns { nd.target = xxreg0; > > > output; }; output;) > > > + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == > > > 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::10), action=(nd_ns > > > { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target > > > = 2001:db8::10; output; }; output;) > > > + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == > > > 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::20), action=(nd_ns > > > { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target > > > = 2001:db8::20; output; }; output;) > > > +]) > > > + > > > +AT_CLEANUP > > > +]) > > > + > > > OVN_FOR_EACH_NORTHD_NO_HV([ > > > AT_SETUP([ovn-northd -- lr multiple gw ports]) > > > AT_KEYWORDS([multiple-l3dgw-ports]) > > > @@ -7346,16 +7406,16 @@ AT_CHECK([grep "lr_in_ip_routing_pre" > > > lr0flows | ovn_strip_lflows], [0], [dnl > > > grep -e "(lr_in_ip_routing ).*outport" lr0flows > > > > > > AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 1 > > > && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = > > > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = > > > "lrp0"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = > > > "lrp1"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = > > > "lrp2"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 > > > && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = > > > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 > > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > > outport = "lrp0"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 > > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > > outport = "lrp0"; flags.loopback = 1; next;) > > > - table=??(lr_in_ip_routing ), priority=324 , 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=324 , 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=324 , 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=122 , match=(reg7 == 1 > > > && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = > > > 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] > > > = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = > > > "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = > > > "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == > > > 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = > > > ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = > > > "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 > > > && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; > > > reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = > > > 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] > > > = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 > > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 > > > && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 > > > = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; > > > outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] > > > = 0; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] > > > = 0; next;) > > > + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] > > > = 0; next;) > > > ]) > > > > > > AT_CLEANUP > > > @@ -13450,8 +13510,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > > > > AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], > > > [0], [dnl > > > table=??(lr_in_arp_resolve ), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), > > > action=(get_arp(outport, reg0); next;) > > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), > > > action=(get_nd(outport, xxreg0); next;) > > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > > == 0), action=(get_nd(outport, xxreg0); next;) > > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > > == 1), action=(get_arp(outport, reg0); next;) > > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > > "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = > > > 00:00:00:00:ff:02; next;) > > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > > "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = > > > 30:54:00:00:00:03; next;) > > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > > "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = > > > 00:00:00:00:ff:02; next;) > > > @@ -13620,8 +13680,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | > > > ovn_strip_lflows], [0], [dnl > > > > > > AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], > > > [0], [dnl > > > table=??(lr_in_arp_resolve ), priority=0 , match=(1), > > > action=(drop;) > > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), > > > action=(get_arp(outport, reg0); next;) > > > - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), > > > action=(get_nd(outport, xxreg0); next;) > > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > > == 0), action=(get_nd(outport, xxreg0); next;) > > > + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] > > > == 1), action=(get_arp(outport, reg0); next;) > > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > > "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = > > > 00:00:00:00:ff:02; next;) > > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > > "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = > > > 00:00:00:00:ff:02; next;) > > > table=??(lr_in_arp_resolve ), priority=100 , match=(outport == > > > "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = > > > 00:00:00:00:ff:02; next;) > > > diff --git a/tests/ovn.at b/tests/ovn.at > > > index 1071208d1..ec90a3b4e 100644 > > > --- a/tests/ovn.at > > > +++ b/tests/ovn.at > > > @@ -39761,3 +39761,648 @@ OVN_CLEANUP([hv1]) > > > > > > AT_CLEANUP > > > ]) > > > + > > > +OVN_FOR_EACH_NORTHD([ > > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv4 over IPv6]) > > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > > +ovn_start > > > + > > > +# Logical network: > > > +# Two LRs - R1 and R2 that are connected to each other as peers in > > > 2001:db8::/64 > > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > > + > > > +ls1_lp1_mac="f0:00:00:01:02:03" > > > +rp_ls1_mac="00:00:00:01:02:03" > > > +rp_ls2_mac="00:00:00:01:02:04" > > > +ls2_lp1_mac="f0:00:00:01:02:04" > > > + > > > +ls1_lp1_ip="192.168.1.2" > > > +ls2_lp1_ip="172.16.1.2" > > > + > > > +check ovn-nbctl lr-add R1 > > > +check ovn-nbctl lr-add R2 > > > + > > > +check ovn-nbctl ls-add ls1 > > > +check ovn-nbctl ls-add ls2 > > > + > > > +# Connect ls1 to R1 > > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > > + > > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > > ls1 type=router \ > > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > > + > > > +# Connect ls2 to R2 > > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > > + > > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > > ls2 type=router \ > > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > > + > > > +# Connect R1 to R2 > > > +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 2001:db8::1/64 > > > peer=R2_R1 > > > +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 2001:db8::2/64 > > > peer=R1_R2 > > > + > > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > > > + > > > +# Create logical port ls1-lp1 in ls1 > > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > > + > > > +# Create logical port ls2-lp1 in ls2 > > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > > + > > > +# Create two hypervisor and create OVS ports corresponding to > > > logical ports. > > > +net_add n1 > > > + > > > +sim_add hv1 > > > +as hv1 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.1 > > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > +sim_add hv2 > > > +as hv2 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.2 > > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > + > > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > > any > > > +# packets for ARP resolution (native tunneling doesn't queue > > > packets > > > +# for ARP resolution). > > > +OVN_POPULATE_ARP > > > + > > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > > +wait_for_ports_up > > > +check ovn-nbctl --wait=hv sync > > > + > > > +# Packet to send. > > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > > src='${ls1_lp1_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# Packet to Expect > > > +# The TTL should be decremented by 2. > > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > > src='${rp_ls2_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +echo ${expected} > expected > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > > +]) > > > + > > > +# Disable the ls2-lp1 port. > > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > > enabled=false > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > > +]) > > > + > > > +# Send the same packet again and it should not be delivered > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# The 2nd packet sent shound not be received. > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +OVN_CLEANUP([hv1],[hv2]) > > > + > > > +AT_CLEANUP > > > +]) > > > + > > > +OVN_FOR_EACH_NORTHD([ > > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over > > > IPv6]) > > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > > +ovn_start > > > + > > > +# Logical network: > > > +# Two LRs - R1 and R2 that are connected to ls-transfer in > > > 2001:db8::/64 > > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > > + > > > +ls1_lp1_mac="f0:00:00:01:02:03" > > > +rp_ls1_mac="00:00:00:01:02:03" > > > +rp_ls2_mac="00:00:00:01:02:04" > > > +ls2_lp1_mac="f0:00:00:01:02:04" > > > + > > > +ls1_lp1_ip="192.168.1.2" > > > +ls2_lp1_ip="172.16.1.2" > > > + > > > +check ovn-nbctl lr-add R1 > > > +check ovn-nbctl lr-add R2 > > > + > > > +check ovn-nbctl ls-add ls1 > > > +check ovn-nbctl ls-add ls2 > > > +check ovn-nbctl ls-add ls-transfer > > > + > > > +# Connect ls1 to R1 > > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > > + > > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > > ls1 type=router \ > > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > > + > > > +# Connect ls2 to R2 > > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > > + > > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > > ls2 type=router \ > > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > > + > > > +# Connect R1 to R2 > > > +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 > > > 2001:db8::1/64 > > > +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 > > > 2001:db8::2/64 > > > + > > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ > > > + set Logical_Switch_Port ls-transfer_r1 type=router \ > > > + options:router-port=R1_ls-transfer addresses=\"router\" > > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ > > > + set Logical_Switch_Port ls-transfer_r2 type=router \ > > > + options:router-port=R2_ls-transfer addresses=\"router\" > > > + > > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > > > + > > > +# Create logical port ls1-lp1 in ls1 > > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > > + > > > +# Create logical port ls2-lp1 in ls2 > > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > > + > > > +# Create two hypervisor and create OVS ports corresponding to > > > logical ports. > > > +net_add n1 > > > + > > > +sim_add hv1 > > > +as hv1 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.1 > > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > +sim_add hv2 > > > +as hv2 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.2 > > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > + > > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > > any > > > +# packets for ARP resolution (native tunneling doesn't queue > > > packets > > > +# for ARP resolution). > > > +OVN_POPULATE_ARP > > > + > > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > > +wait_for_ports_up > > > +check ovn-nbctl --wait=hv sync > > > + > > > +# Packet to send. > > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > > src='${ls1_lp1_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# Packet to Expect > > > +# The TTL should be decremented by 2. > > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > > src='${rp_ls2_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +echo ${expected} > expected > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > > +]) > > > + > > > +# Disable the ls2-lp1 port. > > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > > enabled=false > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > > +]) > > > + > > > +# Send the same packet again and it should not be delivered > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# The 2nd packet sent shound not be received. > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +OVN_CLEANUP([hv1],[hv2]) > > > + > > > +AT_CLEANUP > > > +]) > > > + > > > +OVN_FOR_EACH_NORTHD([ > > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over > > > IPv6, static mac]) > > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > > +ovn_start > > > + > > > +# Logical network: > > > +# Two LRs - R1 and R2 that are connected to ls-transfer in > > > 2001:db8::/64 > > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > > + > > > +ls1_lp1_mac="f0:00:00:01:02:03" > > > +rp_ls1_mac="00:00:00:01:02:03" > > > +rp_ls2_mac="00:00:00:01:02:04" > > > +ls2_lp1_mac="f0:00:00:01:02:04" > > > + > > > +ls1_lp1_ip="192.168.1.2" > > > +ls2_lp1_ip="172.16.1.2" > > > + > > > +check ovn-nbctl lr-add R1 > > > +check ovn-nbctl lr-add R2 > > > + > > > +check ovn-nbctl ls-add ls1 > > > +check ovn-nbctl ls-add ls2 > > > +check ovn-nbctl ls-add ls-transfer > > > + > > > +# Connect ls1 to R1 > > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > > +check ovn-nbctl set Logical_Router R1 > > > options:dynamic_neigh_routers=true > > > + > > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > > ls1 type=router \ > > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > > + > > > +# Connect ls2 to R2 > > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > > +check ovn-nbctl set Logical_Router R2 > > > options:dynamic_neigh_routers=true > > > + > > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > > ls2 type=router \ > > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > > + > > > +# Connect R1 to R2 > > > +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 > > > 2001:db8::1/64 > > > +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 > > > 2001:db8::2/64 > > > + > > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ > > > + set Logical_Switch_Port ls-transfer_r1 type=router \ > > > + options:router-port=R1_ls-transfer addresses=\"router\" > > > +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ > > > + set Logical_Switch_Port ls-transfer_r2 type=router \ > > > + options:router-port=R2_ls-transfer addresses=\"router\" > > > + > > > +# Static mac binding entries > > > +check ovn-nbctl static-mac-binding-add R1_ls-transfer 2001:db8::2 > > > 00:00:00:02:03:05 > > > +check ovn-nbctl static-mac-binding-add R2_ls-transfer 2001:db8::1 > > > 00:00:00:02:03:04 > > > + > > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) > > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) > > > + > > > +# Create logical port ls1-lp1 in ls1 > > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > > + > > > +# Create logical port ls2-lp1 in ls2 > > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > > + > > > +# Create two hypervisor and create OVS ports corresponding to > > > logical ports. > > > +net_add n1 > > > + > > > +sim_add hv1 > > > +as hv1 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.1 > > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > +sim_add hv2 > > > +as hv2 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.2 > > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > + > > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > > any > > > +# packets for ARP resolution (native tunneling doesn't queue > > > packets > > > +# for ARP resolution). > > > +OVN_POPULATE_ARP > > > + > > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > > +wait_for_ports_up > > > +check ovn-nbctl --wait=hv sync > > > + > > > +# Packet to send. > > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > > src='${ls1_lp1_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# Packet to Expect > > > +# The TTL should be decremented by 2. > > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > > src='${rp_ls2_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +echo ${expected} > expected > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > > +]) > > > + > > > +# Disable the ls2-lp1 port. > > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > > enabled=false > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > > +]) > > > + > > > +# Send the same packet again and it should not be delivered > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# The 2nd packet sent shound not be received. > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +OVN_CLEANUP([hv1],[hv2]) > > > + > > > +AT_CLEANUP > > > +]) > > > + > > > +OVN_FOR_EACH_NORTHD([ > > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over > > > IPv6, ECMP]) > > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > > +ovn_start > > > + > > > +# Logical network: > > > +# Two LRs - R1 and R2 that are connected to ls-transfer1 and lr- > > > transfer2 in > > > +# 2001:db8:1::/64 and 2001:db8:2::/64 > > > +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. > > > +# R2 has ls2 (172.16.1.0/24) connected to it. > > > + > > > +ls1_lp1_mac="f0:00:00:01:02:03" > > > +rp_ls1_mac="00:00:00:01:02:03" > > > +rp_ls2_mac="00:00:00:01:02:04" > > > +ls2_lp1_mac="f0:00:00:01:02:04" > > > + > > > +ls1_lp1_ip="192.168.1.2" > > > +ls2_lp1_ip="172.16.1.2" > > > + > > > +check ovn-nbctl lr-add R1 > > > +check ovn-nbctl lr-add R2 > > > + > > > +check ovn-nbctl ls-add ls1 > > > +check ovn-nbctl ls-add ls2 > > > +check ovn-nbctl ls-add ls-transfer1 > > > +check ovn-nbctl ls-add ls-transfer2 > > > + > > > +# Connect ls1 to R1 > > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 > > > + > > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > > ls1 type=router \ > > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > > + > > > +# Connect ls2 to R2 > > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 > > > + > > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > > ls2 type=router \ > > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > > + > > > +# Connect R1 to R2 (ls-transfer1) > > > +check ovn-nbctl lrp-add R1 R1_ls-transfer1 00:00:00:02:03:04 > > > 2001:db8:1::1/64 > > > +check ovn-nbctl lrp-add R2 R2_ls-transfer1 00:00:00:02:03:05 > > > 2001:db8:1::2/64 > > > + > > > +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r1 -- \ > > > + set Logical_Switch_Port ls-transfer1_r1 type=router \ > > > + options:router-port=R1_ls-transfer1 addresses=\"router\" > > > +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r2 -- \ > > > + set Logical_Switch_Port ls-transfer1_r2 type=router \ > > > + options:router-port=R2_ls-transfer1 addresses=\"router\" > > > + > > > +# Connect R1 to R2 (ls-transfer2) > > > +check ovn-nbctl lrp-add R1 R1_ls-transfer2 00:00:00:02:03:14 > > > 2001:db8:2::1/64 > > > +check ovn-nbctl lrp-add R2 R2_ls-transfer2 00:00:00:02:03:15 > > > 2001:db8:2::2/64 > > > + > > > +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r1 -- \ > > > + set Logical_Switch_Port ls-transfer2_r1 type=router \ > > > + options:router-port=R1_ls-transfer2 addresses=\"router\" > > > +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r2 -- \ > > > + set Logical_Switch_Port ls-transfer2_r2 type=router \ > > > + options:router-port=R2_ls-transfer2 addresses=\"router\" > > > + > > > +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8:1::2]) > > > +AT_CHECK([ovn-nbctl --ecmp lr-route-add R1 "0.0.0.0/0" > > > 2001:db8:2::2]) > > > +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8:1::1]) > > > +AT_CHECK([ovn-nbctl --ecmp lr-route-add R2 "0.0.0.0/0" > > > 2001:db8:2::1]) > > > + > > > +# Create logical port ls1-lp1 in ls1 > > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > > + > > > +# Create logical port ls2-lp1 in ls2 > > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > > + > > > +# Create two hypervisor and create OVS ports corresponding to > > > logical ports. > > > +net_add n1 > > > + > > > +sim_add hv1 > > > +as hv1 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.1 > > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > +sim_add hv2 > > > +as hv2 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.2 > > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > + > > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > > any > > > +# packets for ARP resolution (native tunneling doesn't queue > > > packets > > > +# for ARP resolution). > > > +OVN_POPULATE_ARP > > > + > > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > > +wait_for_ports_up > > > +check ovn-nbctl --wait=hv sync > > > + > > > +# Packet to send. > > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > > src='${ls1_lp1_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=64)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# Packet to Expect > > > +# The TTL should be decremented by 2. > > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > > src='${rp_ls2_mac}')/ \ > > > + IP(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', ttl=62)/ \ > > > + UDP(sport=53, dport=4369)") > > > > Nit: indentation. > > > > > +echo ${expected} > expected > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 > > > +]) > > > + > > > +# Disable the ls2-lp1 port. > > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > > enabled=false > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 > > > +]) > > > + > > > +# Send the same packet again and it should not be delivered > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# The 2nd packet sent shound not be received. > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +OVN_CLEANUP([hv1],[hv2]) > > > + > > > +AT_CLEANUP > > > +]) > > > + > > > +OVN_FOR_EACH_NORTHD([ > > > +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv6 over IPv4]) > > > +AT_SKIP_IF([test $HAVE_SCAPY = no]) > > > +ovn_start > > > + > > > +# Logical network: > > > +# Two LRs - R1 and R2 that are connected to each other as peers in > > > 10.0.0.0/24 > > > +# network. R1 has a switchs ls1 (2001:db8:1::/64) connected to it. > > > +# R2 has ls2 (2001:db8:2::/64) connected to it. > > > + > > > +ls1_lp1_mac="f0:00:00:01:02:03" > > > +rp_ls1_mac="00:00:00:01:02:03" > > > +rp_ls2_mac="00:00:00:01:02:04" > > > +ls2_lp1_mac="f0:00:00:01:02:04" > > > + > > > +ls1_lp1_ip="2001:db8:1::2" > > > +ls2_lp1_ip="2001:db8:2::2" > > > + > > > +check ovn-nbctl lr-add R1 > > > +check ovn-nbctl lr-add R2 > > > + > > > +check ovn-nbctl ls-add ls1 > > > +check ovn-nbctl ls-add ls2 > > > + > > > +# Connect ls1 to R1 > > > +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 2001:db8:1::1/64 > > > + > > > +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- > > > ls1 type=router \ > > > + options:router-port=ls1 addresses=\"$rp_ls1_mac\" > > > + > > > +# Connect ls2 to R2 > > > +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 2001:db8:2::1/64 > > > + > > > +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- > > > ls2 type=router \ > > > + options:router-port=ls2 addresses=\"$rp_ls2_mac\" > > > + > > > +# Connect R1 to R2 > > > +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 10.0.0.1/24 > > > peer=R2_R1 > > > +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 10.0.0.2/24 > > > peer=R1_R2 > > > + > > > +AT_CHECK([ovn-nbctl lr-route-add R1 "::/0" 10.0.0.2]) > > > +AT_CHECK([ovn-nbctl lr-route-add R2 "::/0" 10.0.0.1]) > > > + > > > +# Create logical port ls1-lp1 in ls1 > > > +check ovn-nbctl lsp-add ls1 ls1-lp1 \ > > > +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" > > > + > > > +# Create logical port ls2-lp1 in ls2 > > > +check ovn-nbctl lsp-add ls2 ls2-lp1 \ > > > +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" > > > + > > > +# Create two hypervisor and create OVS ports corresponding to > > > logical ports. > > > +net_add n1 > > > + > > > +sim_add hv1 > > > +as hv1 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.1 > > > +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ > > > + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ > > > + options:tx_pcap=hv1/vif1-tx.pcap \ > > > + options:rxq_pcap=hv1/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > +sim_add hv2 > > > +as hv2 > > > +check ovs-vsctl add-br br-phys > > > +ovn_attach n1 br-phys 192.168.0.2 > > > +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ > > > + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ > > > + options:tx_pcap=hv2/vif1-tx.pcap \ > > > + options:rxq_pcap=hv2/vif1-rx.pcap \ > > > + ofport-request=1 > > > + > > > + > > > +# Pre-populate the hypervisors' ARP tables so that we don't lose > > > any > > > +# packets for ARP resolution (native tunneling doesn't queue > > > packets > > > +# for ARP resolution). > > > +OVN_POPULATE_ARP > > > + > > > +# Allow some time for ovn-northd and ovn-controller to catch up. > > > +wait_for_ports_up > > > +check ovn-nbctl --wait=hv sync > > > + > > > +# Packet to send. > > > +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', > > > src='${ls1_lp1_mac}')/ \ > > > + IPv6(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', hlim=64)/ \ > > > + UDP(sport=53, dport=4369)") > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# Packet to Expect > > > +# The TTL should be decremented by 2. > > > +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', > > > src='${rp_ls2_mac}')/ \ > > > + IPv6(src='${ls1_lp1_ip}', > > > dst='${ls2_lp1_ip}', hlim=62)/ \ > > > + UDP(sport=53, dport=4369)") > > > +echo ${expected} > expected > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [1 > > > +]) > > > + > > > +# Disable the ls2-lp1 port. > > > +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 > > > enabled=false > > > + > > > +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ > > > +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [0 > > > +]) > > > + > > > +# Send the same packet again and it should not be delivered > > > +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" > > > + > > > +# The 2nd packet sent shound not be received. > > > +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) > > > + > > > +OVN_CLEANUP([hv1],[hv2]) > > > + > > > +AT_CLEANUP > > > +]) > > > diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c > > > index d45be75c7..86a3b5966 100644 > > > --- a/utilities/ovn-nbctl.c > > > +++ b/utilities/ovn-nbctl.c > > > @@ -4591,11 +4591,9 @@ 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) { > > > prefix = normalize_ipv6_prefix_str(ctx->argv[2]); > > > - v6_prefix = true; > > > } > > > if (!prefix) { > > > ctl_error(ctx, "bad prefix argument: %s", ctx->argv[2]); > > > @@ -4606,15 +4604,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) > > > if (is_discard_route) { > > > next_hop = xasprintf("discard"); > > > } else { > > > - next_hop = v6_prefix > > > - ? normalize_ipv6_addr_str(ctx->argv[3]) > > > - : normalize_ipv4_addr_str(ctx->argv[3]); > > > + next_hop = normalize_ipv4_addr_str(ctx->argv[3]); > > > + if (!next_hop) { > > > + next_hop = normalize_ipv6_addr_str(ctx->argv[3]); > > > + } > > > if (!next_hop) { > > > /* check if it is a output port. */ > > > error = lrp_by_name_or_uuid(ctx, ctx->argv[3], true, > > > &out_lrp); > > > if (error) { > > > - ctl_error(ctx, "bad %s nexthop argument: %s", > > > - v6_prefix ? "IPv6" : "IPv4", ctx- > > > >argv[3]); > > > + ctl_error(ctx, "bad nexthop argument: %s", ctx- > > > >argv[3]); > > > free(error); > > > goto cleanup; > > > } > > > > Regards, > > Dumitru > > >
On 12/17/24 5:02 PM, Felix Huettner wrote: > On Tue, Dec 17, 2024 at 04:41:44PM +0100, martin.kalcok@canonical.com wrote: >> Thank you for the review and conflict resolution Dumitru. Your changes >> look good for my part (register reassignment and system tests). >> Thanks for checking! >> Martin. >> >> On Tue, 2024-12-17 at 16:25 +0100, Dumitru Ceara wrote: >>> Hi Martin, Felix, >>> >>> On 12/4/24 4:10 PM, Martin Kalcok wrote: >>>> From: Felix Huettner <felix.huettner@mail.schwarz> >>>> >>>> In most cases IPv4 packets are routed only over other IPv4 networks >>>> and >>>> IPv6 packets are routed only over IPv6 networks. However there is >>>> no >>>> inherent reason for this limitation. Routing IPv4 packets over IPv6 >>>> networks just requires the router to contain a route for an IPv4 >>>> network >>>> with an IPv6 nexthop. >>>> >>>> This was previously prevented in OVN in ovn-nbctl and northd. By >>>> removing these filters the forwarding will work if the mac >>>> addresses are >>>> prepopulated. >>>> >>>> If the mac addresses are not prepopulated we will attempt to >>>> resolve them using >>>> the original address family of the packet and not the address >>>> family of the >>>> nexthop. This will fail and we will not forward the packet. >>>> >>>> This feature can for example be used by service providers to >>>> interconnect multiple IPv4 networks of a customer without needing >>>> to >>>> negotiate free IPv4 addresses by just using any IPv6 address. >>>> >>>> Signed-off-by: Felix Huettner <felix.huettner@mail.schwarz> >>> >>> Felix, is this email address correct? > > Hi Dumitru, > > we have since switched our mail domain, so now it is > felix.huettner@stackit.cloud > However the old one will work for the next years so we can also keep > this one. > Ack. >>> >>>> Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com> >>>> Co-authored-by: Martin Kalcok <martin.kalcok@canonical.com> >>>> --- >>> >>> After merging Felix's BGP prerequisite patches, there were a bunch of >>> conflicts when applying this patch but I think I managed to address >>> them. >>> >>> I pushed the rebased patches (also with the small nits I had below >>> addressed) to: >>> https://github.com/dceara/ovn/commits/bcba1b74 >>> >>> It would be great if you could double check that it still looks OK to >>> you. If that's the case I can then apply the series to main. > > All of the 3 commits look good from my side. > Thanks a lot for going through the conflict hell. > No worries, thanks for checking. Regards, Dumitru > Thanks > Felix > >>> >>>> NEWS | 4 + >>>> northd/northd.c | 81 +++--- >>>> northd/northd.h | 2 + >>>> tests/ovn-nbctl.at | 26 +- >>>> tests/ovn-northd.at | 150 +++++++--- >>>> tests/ovn.at | 645 >>>> ++++++++++++++++++++++++++++++++++++++++++ >>>> utilities/ovn-nbctl.c | 12 +- >>>> 7 files changed, 829 insertions(+), 91 deletions(-) >>>> >>>> diff --git a/NEWS b/NEWS >>>> index da3aba739..b5aae7d4b 100644 >>>> --- a/NEWS >>>> +++ b/NEWS >>>> @@ -75,6 +75,10 @@ OVN v24.09.0 - 13 Sep 2024 >>>> "routing-protocol-redirect" and "routing-protocols", that >>>> allow >>>> redirection of routing protocol traffic received by a router >>>> port >>>> to a different logical switch port. >>>> + - Allow Static Routes where the address families of ip_prefix >>>> and nexthop >>>> + diverge (e.g. IPv4 packets over IPv6 links). This is currently >>>> limited to >>>> + nexthops that have their mac addresses prepopulated (so >>>> + dynamic_neigh_routers must be false). >>>> >>>> OVN v24.03.0 - 01 Mar 2024 >>>> -------------------------- >>>> diff --git a/northd/northd.c b/northd/northd.c >>>> index 3564d45d9..4fb48838b 100644 >>>> --- a/northd/northd.c >>>> +++ b/northd/northd.c >>>> @@ -174,6 +174,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << >>>> 2)); >>>> #define REGBIT_KNOWN_LB_SESSION "reg9[6]" >>>> #define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]" >>>> #define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]" >>>> +#define REGBIT_NEXTHOP_IS_IPV4 "reg9[9]" >>>> >>>> /* Register to store the eth address associated to a router port >>>> for packets >>>> * received in S_ROUTER_IN_ADMISSION. >>>> @@ -290,7 +291,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << >>>> 2)); >>>> * | | LOOKUP_NEIGHBOR_RESULT/ | | | >>>> * | | SKIP_LOOKUP_NEIGHBOR/ | | | >>>> * | |REGBIT_DHCP_RELAY_REQ_CHK/ | | | >>>> - * | |REGBIT_DHCP_RELAY_RESP_CHK}| | | >>>> + * | |REGBIT_DHCP_RELAY_RESP_CHK | | | >>>> + * | |REGBIT_NEXTHOP_IS_IPV4} | | | >>>> * | | | | | >>>> * | | REG_ORIG_TP_DPORT_ROUTER | | | >>>> * | | | | | >>>> @@ -10861,13 +10863,15 @@ build_routing_policy_flow(struct >>>> lflow_table *lflows, struct ovn_datapath *od, >>>> "outport = %s; " >>>> "flags.loopback = 1; " >>>> REG_ECMP_GROUP_ID" = 0; " >>>> + REGBIT_NEXTHOP_IS_IPV4" = %d; " >>>> "next;", >>>> is_ipv4 ? REG_NEXT_HOP_IPV4 : >>>> REG_NEXT_HOP_IPV6, >>>> nexthop, >>>> is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, >>>> lrp_addr_s, >>>> out_port->lrp_networks.ea_s, >>>> - out_port->json_key); >>>> + out_port->json_key, >>>> + is_ipv4); >>>> >>>> } else if (!strcmp(rule->action, "drop")) { >>>> ds_put_cstr(&actions, debug_drop_action()); >>>> @@ -10951,13 +10955,15 @@ build_ecmp_routing_policy_flows(struct >>>> lflow_table *lflows, >>>> "eth.src = %s; " >>>> "outport = %s; " >>>> "flags.loopback = 1; " >>>> + REGBIT_NEXTHOP_IS_IPV4" = %d; " >>>> "next;", >>>> is_ipv4 ? REG_NEXT_HOP_IPV4 : >>>> REG_NEXT_HOP_IPV6, >>>> rp->valid_nexthops[i], >>>> is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, >>>> lrp_addr_s, >>>> out_port->lrp_networks.ea_s, >>>> - out_port->json_key); >>>> + out_port->json_key, >>>> + is_ipv4); >>> >>> Should we add a TODO item to remember to add support for "reroute" >>> routing policies that change next hop family? >>> >>>> >>>> ds_clear(&match); >>>> ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && " >>>> @@ -11123,6 +11129,8 @@ parsed_routes_add(struct ovn_datapath *od, >>>> const struct hmap *lr_ports, >>>> /* Verify that the next hop is an IP address with an all-ones >>>> mask. */ >>>> struct in6_addr nexthop; >>>> unsigned int plen; >>>> + bool is_ipv4_nexthop = true; >>>> + bool is_ipv4_prefix; >>>> bool is_discard_route = !strcmp(route->nexthop, "discard"); >>>> bool valid_nexthop = route->nexthop[0] && !is_discard_route; >>>> if (valid_nexthop) { >>>> @@ -11141,6 +11149,7 @@ parsed_routes_add(struct ovn_datapath *od, >>>> const struct hmap *lr_ports, >>>> UUID_ARGS(&route->header_.uuid)); >>>> return; >>>> } >>>> + is_ipv4_nexthop = IN6_IS_ADDR_V4MAPPED(&nexthop); >>>> } >>>> >>>> /* Parse ip_prefix */ >>>> @@ -11152,18 +11161,7 @@ parsed_routes_add(struct ovn_datapath *od, >>>> const struct hmap *lr_ports, >>>> UUID_ARGS(&route->header_.uuid)); >>>> return; >>>> } >>>> - >>>> - /* Verify that ip_prefix and nexthop have same address >>>> familiy. */ >>>> - if (valid_nexthop) { >>>> - if (IN6_IS_ADDR_V4MAPPED(&prefix) != >>>> IN6_IS_ADDR_V4MAPPED(&nexthop)) { >>>> - static struct vlog_rate_limit rl = >>>> VLOG_RATE_LIMIT_INIT(5, 1); >>>> - VLOG_WARN_RL(&rl, "Address family doesn't match >>>> between 'ip_prefix'" >>>> - " %s and 'nexthop' %s in static route >>>> "UUID_FMT, >>>> - route->ip_prefix, route->nexthop, >>>> - UUID_ARGS(&route->header_.uuid)); >>>> - return; >>>> - } >>>> - } >>>> + is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&prefix); >>>> >>>> /* Verify that ip_prefix and nexthop are on the same network. >>>> */ >>>> if (!is_discard_route && >>>> @@ -11216,6 +11214,8 @@ parsed_routes_add(struct ovn_datapath *od, >>>> const struct hmap *lr_ports, >>>> >>>> "ecmp_symmetric_reply", >>>> false); >>>> new_pr->is_discard_route = is_discard_route; >>>> + new_pr->is_ipv4_prefix = is_ipv4_prefix; >>>> + new_pr->is_ipv4_nexthop = is_ipv4_nexthop; >>>> sset_init(&new_pr->ecmp_selection_fields); >>>> >>>> /* If tp_src or tp_dst is included in the selection_fields, >>>> implicitly >>>> @@ -11646,7 +11646,7 @@ build_ecmp_route_flow(struct lflow_table >>>> *lflows, struct ovn_datapath *od, >>>> struct lflow_ref *lflow_ref, const char >>>> *protocol) >>>> >>>> { >>>> - bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix); >>>> + bool is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&eg->prefix); >>>> uint16_t priority; >>>> struct ecmp_route_list_node *er; >>>> struct ds route_match = DS_EMPTY_INITIALIZER; >>>> @@ -11655,7 +11655,8 @@ build_ecmp_route_flow(struct lflow_table >>>> *lflows, struct ovn_datapath *od, >>>> int ofs = !strcmp(eg->origin, ROUTE_ORIGIN_CONNECTED) ? >>>> ROUTE_PRIO_OFFSET_CONNECTED: ROUTE_PRIO_OFFSET_STATIC; >>>> build_route_match(NULL, eg->route_table_id, prefix_s, eg- >>>>> plen, >>>> - eg->is_src_route, is_ipv4, &route_match, >>>> &priority, ofs, >>>> + eg->is_src_route, is_ipv4_prefix, >>>> &route_match, >>>> + &priority, ofs, >>>> protocol != NULL); >>>> free(prefix_s); >>>> >>>> @@ -11723,7 +11724,8 @@ build_ecmp_route_flow(struct lflow_table >>>> *lflows, struct ovn_datapath *od, >>>> /* Find the outgoing port. */ >>>> const char *lrp_addr_s = NULL; >>>> struct ovn_port *out_port = NULL; >>>> - if (!find_static_route_outport(od, lr_ports, route, >>>> is_ipv4, >>>> + if (!find_static_route_outport(od, lr_ports, route, >>>> + route_->is_ipv4_nexthop, >>>> &lrp_addr_s, &out_port)) { >>>> continue; >>>> } >>>> @@ -11746,13 +11748,16 @@ build_ecmp_route_flow(struct lflow_table >>>> *lflows, struct ovn_datapath *od, >>>> "%s = %s; " >>>> "eth.src = %s; " >>>> "outport = %s; " >>>> + REGBIT_NEXTHOP_IS_IPV4" = %d; " >>>> "next;", >>>> - is_ipv4 ? REG_NEXT_HOP_IPV4 : >>>> REG_NEXT_HOP_IPV6, >>>> + route_->is_ipv4_nexthop ? >>>> + REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, >>>> route->nexthop, >>>> - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, >>>> + route_->is_ipv4_nexthop ? REG_SRC_IPV4 : >>>> REG_SRC_IPV6, >>>> lrp_addr_s, >>>> out_port->lrp_networks.ea_s, >>>> - out_port->json_key); >>>> + out_port->json_key, >>>> + route_->is_ipv4_nexthop); >>>> ovn_lflow_add_with_hint(lflows, od, >>>> S_ROUTER_IN_IP_ROUTING_ECMP, 100, >>>> ds_cstr(&match), >>>> ds_cstr(&actions), >>>> &route->header_, lflow_ref); >>>> @@ -11770,15 +11775,15 @@ add_route(struct lflow_table *lflows, >>>> struct ovn_datapath *od, >>>> bool is_src_route, const uint32_t rtb_id, >>>> const struct sset *bfd_ports, >>>> const struct ovsdb_idl_row *stage_hint, bool >>>> is_discard_route, >>>> - int ofs, struct lflow_ref *lflow_ref) >>>> + int ofs, struct lflow_ref *lflow_ref, >>>> + bool is_ipv4_prefix, bool is_ipv4_nexthop) >>>> { >>>> - bool is_ipv4 = strchr(network_s, '.') ? true : false; >>>> struct ds match = DS_EMPTY_INITIALIZER; >>>> uint16_t priority; >>>> const struct ovn_port *op_inport = NULL; >>>> >>>> /* IPv6 link-local addresses must be scoped to the local >>>> router port. */ >>>> - if (!is_ipv4) { >>>> + if (!is_ipv4_prefix) { >>>> struct in6_addr network; >>>> ovs_assert(ipv6_parse(network_s, &network)); >>>> if (in6_is_lla(&network)) { >>>> @@ -11786,7 +11791,7 @@ add_route(struct lflow_table *lflows, >>>> struct ovn_datapath *od, >>>> } >>>> } >>>> build_route_match(op_inport, rtb_id, network_s, plen, >>>> is_src_route, >>>> - is_ipv4, &match, &priority, ofs, false); >>>> + is_ipv4_prefix, &match, &priority, ofs, >>>> false); >>>> >>>> struct ds common_actions = DS_EMPTY_INITIALIZER; >>>> struct ds actions = DS_EMPTY_INITIALIZER; >>>> @@ -11794,22 +11799,25 @@ add_route(struct lflow_table *lflows, >>>> struct ovn_datapath *od, >>>> ds_put_cstr(&actions, debug_drop_action()); >>>> } else { >>>> ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s >>>> = ", >>>> - is_ipv4 ? REG_NEXT_HOP_IPV4 : >>>> REG_NEXT_HOP_IPV6); >>>> + is_ipv4_nexthop ? REG_NEXT_HOP_IPV4 : >>>> REG_NEXT_HOP_IPV6); >>>> if (gateway && gateway[0]) { >>>> ds_put_cstr(&common_actions, gateway); >>>> } else { >>>> - ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? >>>> "4" : "6"); >>>> + ds_put_format(&common_actions, "ip%s.dst", >>>> + is_ipv4_prefix ? "4" : "6"); >>>> } >>>> ds_put_format(&common_actions, "; " >>>> "%s = %s; " >>>> "eth.src = %s; " >>>> "outport = %s; " >>>> "flags.loopback = 1; " >>>> + REGBIT_NEXTHOP_IS_IPV4" = %d; " >>>> "next;", >>>> - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, >>>> + is_ipv4_nexthop ? REG_SRC_IPV4 : >>>> REG_SRC_IPV6, >>>> lrp_addr_s, >>>> op->lrp_networks.ea_s, >>>> - op->json_key); >>>> + op->json_key, >>>> + is_ipv4_nexthop); >>>> ds_put_format(&actions, "ip.ttl--; %s", >>>> ds_cstr(&common_actions)); >>>> } >>>> >>>> @@ -11860,7 +11868,8 @@ build_static_route_flow(struct lflow_table >>>> *lflows, struct ovn_datapath *od, >>>> lrp_addr_s, prefix_s, route_->plen, route->nexthop, >>>> route_->is_src_route, route_->route_table_id, >>>> bfd_ports, &route->header_, route_- >>>>> is_discard_route, >>>> - ofs, lflow_ref); >>>> + ofs, lflow_ref, >>>> + route_->is_ipv4_prefix, route_->is_ipv4_nexthop); >>>> >>>> free(prefix_s); >>>> } >>>> @@ -13708,7 +13717,7 @@ build_ip_routing_flows_for_lrp(struct >>>> ovn_port *op, >>>> op->lrp_networks.ipv4_addrs[i].network_s, >>>> op->lrp_networks.ipv4_addrs[i].plen, NULL, >>>> false, 0, >>>> bfd_ports, &op->nbrp->header_, false, >>>> - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); >>>> + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, true, >>>> true); >>>> } >>>> >>>> for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { >>>> @@ -13716,7 +13725,7 @@ build_ip_routing_flows_for_lrp(struct >>>> ovn_port *op, >>>> op->lrp_networks.ipv6_addrs[i].network_s, >>>> op->lrp_networks.ipv6_addrs[i].plen, NULL, >>>> false, 0, >>>> bfd_ports, &op->nbrp->header_, false, >>>> - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); >>>> + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, false, >>>> false); >>>> } >>>> } >>>> >>>> @@ -14069,11 +14078,13 @@ build_arp_resolve_flows_for_lrouter( >>>> "ip4.mcast || ip6.mcast", "next;", >>>> lflow_ref); >>>> >>>> - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", >>>> + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, >>>> + REGBIT_NEXTHOP_IS_IPV4 " == 1", >>>> "get_arp(outport, " REG_NEXT_HOP_IPV4 "); >>>> next;", >>>> lflow_ref); >>>> >>>> - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", >>>> + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, >>>> + REGBIT_NEXTHOP_IS_IPV4 " == 0", >>>> "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;", >>>> lflow_ref); >>>> >>>> @@ -17033,7 +17044,7 @@ build_routable_flows_for_router_port( >>>> laddrs->ipv4_addrs[k].plen, NULL, >>>> false, 0, >>>> bfd_ports, &router_port->nbrp- >>>>> header_, >>>> false, ROUTE_PRIO_OFFSET_CONNECTED, >>>> - lrp->stateful_lflow_ref); >>>> + lrp->stateful_lflow_ref, true, >>>> true); >>>> } >>>> } >>>> } >>>> diff --git a/northd/northd.h b/northd/northd.h >>>> index e93e10f20..a5af72eb7 100644 >>>> --- a/northd/northd.h >>>> +++ b/northd/northd.h >>>> @@ -709,6 +709,8 @@ struct parsed_route { >>>> const struct nbrec_logical_router *nbr; >>>> bool stale; >>>> struct sset ecmp_selection_fields; >>>> + bool is_ipv4_prefix; >>>> + bool is_ipv4_nexthop; >>>> }; >>>> >>>> void ovnnb_db_run(struct northd_input *input_data, >>>> diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at >>>> index 2efa13b93..addcc4593 100644 >>>> --- a/tests/ovn-nbctl.at >>>> +++ b/tests/ovn-nbctl.at >>>> @@ -1857,7 +1857,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 >>>> 10.0.0.1/24 11.0.0.2]) >>>> AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp0]) >>>> AT_CHECK([ovn-nbctl --bfd lr-route-add lr0 10.0.20.0/24 11.0.2.1 >>>> lp0]) >>>> AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp1], [1], [], >>>> - [ovn-nbctl: bad IPv4 nexthop argument: lp1 >>>> + [ovn-nbctl: bad nexthop argument: lp1 >>>> ]) >>>> >>>> dnl Add overlapping route with 10.0.0.1/24 >>>> @@ -1871,13 +1871,13 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 >>>> 10.0.0.111/24a 11.0.0.1], [1], [], >>>> [ovn-nbctl: bad prefix argument: 10.0.0.111/24a >>>> ]) >>>> AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1a], >>>> [1], [], >>>> - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1a >>>> + [ovn-nbctl: bad nexthop argument: 11.0.0.1a >>>> ]) >>>> AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1/24], >>>> [1], [], >>>> - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1/24 >>>> + [ovn-nbctl: bad nexthop argument: 11.0.0.1/24 >>>> ]) >>>> AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 >>>> 2001:0db8:0:f103::1/64], [1], [], >>>> - [ovn-nbctl: bad IPv6 nexthop argument: 2001:0db8:0:f103::1/64 >>>> + [ovn-nbctl: bad nexthop argument: 2001:0db8:0:f103::1/64 >>>> ]) >>>> AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 20.0.0.0/24 discard], >>>> [1], [], >>>> [ovn-nbctl: ecmp is not valid for discard routes. >>>> @@ -2105,6 +2105,24 @@ check ovn-nbctl lr-route-del lr0 >>>> AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >>>> ]) >>>> >>>> +dnl Check IPv4 over v6 and IPv6 over v4 routes >>>> +AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 >>>> 2001:0db8:0:f103::10]) >>>> +AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 11.0.1.10]) >>>> + >>>> +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl >>>> +IPv4 Routes >>>> +Route Table <main>: >>>> + 10.0.0.0/24 2001:db8:0:f103::10 dst-ip >>>> + >>>> +IPv6 Routes >>>> +Route Table <main>: >>>> + 2001:db8::/64 11.0.1.10 dst-ip >>>> +]) >>>> + >>>> +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 >>>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at >>>> index c98f1fcb4..803823afa 100644 >>>> --- a/tests/ovn-northd.at >>>> +++ b/tests/ovn-northd.at >>>> @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | >>>> ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_policy ), priority=0 , match=(1), >>>> action=(reg8[[0..15]] = 0; next;) >>>> table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, >>>> 2);) >>>> table=??(lr_in_policy_ecmp ), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; flags.loopback = 1; next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = >>>> 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; flags.loopback = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = >>>> 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=150 , >>>> match=(reg8[[0..15]] == 0), action=(next;) >>>> ]) >>>> >>>> @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0- >>>> 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf >>>> table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = >>>> select(1, 2);) >>>> table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = >>>> select(1, 2, 3);) >>>> table=??(lr_in_policy_ecmp ), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), >>>> action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), >>>> action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=150 , >>>> match=(reg8[[0..15]] == <cleared>), action=(next;) >>>> ]) >>>> >>>> @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0- >>>> 9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf >>>> table=??(lr_in_policy ), priority=0 , match=(1), >>>> action=(reg8[[0..15]] = <cleared>; next;) >>>> table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = >>>> select(1, 2);) >>>> table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = >>>> select(1, 2, 3);) >>>> - table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; >>>> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback >>>> = 1; reg8[[0..15]] = <cleared>; next;) >>>> + table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; >>>> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback >>>> = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), >>>> action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), >>>> action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=150 , >>>> match=(reg8[[0..15]] == <cleared>), action=(next;) >>>> ]) >>>> >>>> @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0- >>>> 9]]*/reg8\[[0..15\]] = <cleared>/' | \ >>>> sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' >>>> | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_policy ), priority=0 , match=(1), >>>> action=(reg8[[0..15]] = <cleared>; next;) >>>> table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = >>>> select(1, 2, 3);) >>>> - table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; >>>> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback >>>> = 1; reg8[[0..15]] = <cleared>; next;) >>>> + table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; >>>> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback >>>> = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> - table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), >>>> action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), >>>> action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), >>>> action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_policy_ecmp ), priority=100 , >>>> match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), >>>> action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=150 , >>>> match=(reg8[[0..15]] == <cleared>), action=(next;) >>>> ]) >>>> >>>> @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | \ >>>> sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | >>>> \ >>>> sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' >>>> | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_policy ), priority=0 , match=(1), >>>> action=(reg8[[0..15]] = <cleared>; next;) >>>> - table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; >>>> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback >>>> = 1; reg8[[0..15]] = <cleared>; next;) >>>> + table=??(lr_in_policy ), priority=10 , match=(ip4.src == >>>> 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; >>>> eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback >>>> = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) >>>> table=??(lr_in_policy_ecmp ), priority=0 , match=(1), >>>> action=(drop;) >>>> table=??(lr_in_policy_ecmp ), priority=150 , >>>> match=(reg8[[0..15]] == <cleared>), action=(next;) >>>> ]) >>>> @@ -6823,14 +6823,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" >>>> lr0flows | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_ip_routing ), priority=0 , match=(1), >>>> action=(drop;) >>>> table=??(lr_in_ip_routing ), priority=10300, >>>> match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == >>>> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = >>>> 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; >>>> next;) >>>> table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || >>>> nd_ra), action=(drop;) >>>> - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 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=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 >>>> && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; >>>> reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) >>>> ]) >>>> >>>> AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; next;) >>>> + table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; reg9[[9]] = 1; next;) >>>> table=??(lr_in_ip_routing_ecmp), priority=150 , >>>> match=(reg8[[0..15]] == 0), action=(next;) >>>> ]) >>>> >>>> @@ -6841,14 +6841,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" >>>> lr0flows | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_ip_routing ), priority=0 , match=(1), >>>> action=(drop;) >>>> table=??(lr_in_ip_routing ), priority=10300, >>>> match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == >>>> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = >>>> 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; >>>> next;) >>>> table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || >>>> nd_ra), action=(drop;) >>>> - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 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=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 >>>> && 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=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) >>>> ]) >>>> AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed >>>> 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; next;) >>>> - table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; next;) >>>> + table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; reg9[[9]] = 1; next;) >>>> table=??(lr_in_ip_routing_ecmp), priority=150 , >>>> match=(reg8[[0..15]] == 0), action=(next;) >>>> ]) >>>> >>>> @@ -6870,14 +6870,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" >>>> lr0flows | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_ip_routing ), priority=0 , match=(1), >>>> action=(drop;) >>>> table=??(lr_in_ip_routing ), priority=10300, >>>> match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == >>>> 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = >>>> 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; >>>> next;) >>>> table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || >>>> nd_ra), action=(drop;) >>>> - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 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=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 >>>> && 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=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) >>>> ]) >>>> AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed >>>> 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl >>>> table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; next;) >>>> - table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; next;) >>>> + table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing_ecmp), priority=100 , >>>> match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = >>>> 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; reg9[[9]] = 1; next;) >>>> table=??(lr_in_ip_routing_ecmp), priority=150 , >>>> match=(reg8[[0..15]] == 0), action=(next;) >>>> ]) >>>> >>>> @@ -6888,14 +6888,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 | >>>> ovn_strip_lflows], [0], [dnl >>>> - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 >>>> && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.0.10; reg5 = 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=122 , match=(reg7 == 0 >>>> && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 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 | >>>> ovn_strip_lflows], [0], [dnl >>>> - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 >>>> && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = ip4.dst; reg5 = 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=122 , match=(reg7 == 0 >>>> && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; >>>> outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> ]) >>>> >>>> check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11 >>>> @@ -6928,6 +6928,66 @@ AT_CHECK([grep -e "(lr_in_ip_routing >>>> ).*3.3.0.0" lr0flows | sed 's/table=../ta >>>> AT_CLEANUP >>>> ]) >>>> >>>> +OVN_FOR_EACH_NORTHD_NO_HV([ >>>> +AT_SETUP([ovn -- static routes multiple address families flows]) >>>> +AT_KEYWORDS([static-routes-flows]) >>>> +ovn_start >>>> + >>>> +check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 >>>> + >>>> +check ovn-nbctl lr-add lr0 >>>> +check ovn-nbctl set logical_router lr0 options:chassis=ch1 >>>> +check ovn-nbctl ls-add public >>>> +check ovn-nbctl ls-add private >>>> +check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 >>>> 192.168.0.1/24 >>>> +check ovn-nbctl lsp-add public public-lr0 >>>> +check ovn-nbctl lsp-set-type public-lr0 router >>>> +check ovn-nbctl lsp-set-addresses public-lr0 router >>>> +check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public >>>> + >>>> +check ovn-nbctl lrp-add lr0 lr0-private 00:00:20:20:12:14 >>>> 2001:db8::1/64 >>>> +check ovn-nbctl lsp-add private private-lr0 >>>> +check ovn-nbctl lsp-set-type private-lr0 router >>>> +check ovn-nbctl lsp-set-addresses private-lr0 router >>>> +check ovn-nbctl lsp-set-options private-lr0 router-port=lr0- >>>> private >>>> + >>>> +check ovn-nbctl --wait=sb lr-route-add lr0 10.0.0.0/24 >>>> 192.168.0.10 >>>> +check ovn-nbctl --wait=sb lr-route-add lr0 11.0.0.0/24 >>>> 2001:db8::10 >>>> +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:1::/64 >>>> 192.168.0.20 >>>> +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:2::/64 >>>> 2001:db8::20 >>>> + >>>> +ovn-sbctl dump-flows lr0 > lr0flows >>>> +AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> + table=??(lr_in_ip_routing ), priority=0 , match=(1), >>>> action=(drop;) >>>> + table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || >>>> nd_ra), action=(drop;) >>>> + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 >>>> && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 >>>> && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = >>>> 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; >>>> reg9[[9]] = 0; next;) >>>> + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 >>>> && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = >>>> 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = >>>> 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; >>>> reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 >>>> && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = >>>> 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = >>>> 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; >>>> reg9[[9]] = 0; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , match=(inport == >>>> "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = >>>> "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , match=(inport == >>>> "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; >>>> reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = >>>> fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = >>>> "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , match=(ip6.dst == >>>> 2001:db8::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = >>>> ip6.dst; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport >>>> = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) >>>> +]) >>>> + >>>> +AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> + table=??(lr_in_arp_resolve ), priority=0 , match=(1), >>>> action=(drop;) >>>> + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] >>>> == 0), action=(get_nd(outport, xxreg0); next;) >>>> + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] >>>> == 1), action=(get_arp(outport, reg0); next;) >>>> + table=??(lr_in_arp_resolve ), priority=500 , match=(ip4.mcast >>>> || ip6.mcast), action=(next;) >>>> +]) >>>> + >>>> +AT_CHECK([grep -e "lr_in_arp_request" lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> + table=??(lr_in_arp_request ), priority=0 , match=(1), >>>> action=(output;) >>>> + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == >>>> 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = >>>> ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; >>>> output; }; output;) >>>> + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == >>>> 00:00:00:00:00:00 && ip6), action=(nd_ns { nd.target = xxreg0; >>>> output; }; output;) >>>> + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == >>>> 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::10), action=(nd_ns >>>> { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target >>>> = 2001:db8::10; output; }; output;) >>>> + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == >>>> 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::20), action=(nd_ns >>>> { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target >>>> = 2001:db8::20; output; }; output;) >>>> +]) >>>> + >>>> +AT_CLEANUP >>>> +]) >>>> + >>>> OVN_FOR_EACH_NORTHD_NO_HV([ >>>> AT_SETUP([ovn-northd -- lr multiple gw ports]) >>>> AT_KEYWORDS([multiple-l3dgw-ports]) >>>> @@ -7346,16 +7406,16 @@ AT_CHECK([grep "lr_in_ip_routing_pre" >>>> lr0flows | ovn_strip_lflows], [0], [dnl >>>> grep -e "(lr_in_ip_routing ).*outport" lr0flows >>>> >>>> AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 1 >>>> && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = >>>> 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = >>>> "lrp0"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = >>>> "lrp1"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = >>>> "lrp2"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 >>>> && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = >>>> 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 >>>> && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 >>>> = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; >>>> outport = "lrp0"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 >>>> && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 >>>> = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; >>>> outport = "lrp0"; flags.loopback = 1; next;) >>>> - table=??(lr_in_ip_routing ), priority=324 , 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=324 , 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=324 , 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=122 , match=(reg7 == 1 >>>> && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = >>>> 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] >>>> = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = >>>> "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = >>>> "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == >>>> 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = >>>> ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = >>>> "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 >>>> && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; >>>> reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = >>>> 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] >>>> = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 >>>> && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 >>>> = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; >>>> outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 >>>> && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 >>>> = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; >>>> outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] >>>> = 0; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] >>>> = 0; next;) >>>> + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] >>>> = 0; next;) >>>> ]) >>>> >>>> AT_CLEANUP >>>> @@ -13450,8 +13510,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> >>>> AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], >>>> [0], [dnl >>>> table=??(lr_in_arp_resolve ), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), >>>> action=(get_arp(outport, reg0); next;) >>>> - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), >>>> action=(get_nd(outport, xxreg0); next;) >>>> + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] >>>> == 0), action=(get_nd(outport, xxreg0); next;) >>>> + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] >>>> == 1), action=(get_arp(outport, reg0); next;) >>>> table=??(lr_in_arp_resolve ), priority=100 , match=(outport == >>>> "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = >>>> 00:00:00:00:ff:02; next;) >>>> table=??(lr_in_arp_resolve ), priority=100 , match=(outport == >>>> "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = >>>> 30:54:00:00:00:03; next;) >>>> table=??(lr_in_arp_resolve ), priority=100 , match=(outport == >>>> "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = >>>> 00:00:00:00:ff:02; next;) >>>> @@ -13620,8 +13680,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | >>>> ovn_strip_lflows], [0], [dnl >>>> >>>> AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], >>>> [0], [dnl >>>> table=??(lr_in_arp_resolve ), priority=0 , match=(1), >>>> action=(drop;) >>>> - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), >>>> action=(get_arp(outport, reg0); next;) >>>> - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), >>>> action=(get_nd(outport, xxreg0); next;) >>>> + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] >>>> == 0), action=(get_nd(outport, xxreg0); next;) >>>> + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] >>>> == 1), action=(get_arp(outport, reg0); next;) >>>> table=??(lr_in_arp_resolve ), priority=100 , match=(outport == >>>> "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = >>>> 00:00:00:00:ff:02; next;) >>>> table=??(lr_in_arp_resolve ), priority=100 , match=(outport == >>>> "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = >>>> 00:00:00:00:ff:02; next;) >>>> table=??(lr_in_arp_resolve ), priority=100 , match=(outport == >>>> "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = >>>> 00:00:00:00:ff:02; next;) >>>> diff --git a/tests/ovn.at b/tests/ovn.at >>>> index 1071208d1..ec90a3b4e 100644 >>>> --- a/tests/ovn.at >>>> +++ b/tests/ovn.at >>>> @@ -39761,3 +39761,648 @@ OVN_CLEANUP([hv1]) >>>> >>>> AT_CLEANUP >>>> ]) >>>> + >>>> +OVN_FOR_EACH_NORTHD([ >>>> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv4 over IPv6]) >>>> +AT_SKIP_IF([test $HAVE_SCAPY = no]) >>>> +ovn_start >>>> + >>>> +# Logical network: >>>> +# Two LRs - R1 and R2 that are connected to each other as peers in >>>> 2001:db8::/64 >>>> +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. >>>> +# R2 has ls2 (172.16.1.0/24) connected to it. >>>> + >>>> +ls1_lp1_mac="f0:00:00:01:02:03" >>>> +rp_ls1_mac="00:00:00:01:02:03" >>>> +rp_ls2_mac="00:00:00:01:02:04" >>>> +ls2_lp1_mac="f0:00:00:01:02:04" >>>> + >>>> +ls1_lp1_ip="192.168.1.2" >>>> +ls2_lp1_ip="172.16.1.2" >>>> + >>>> +check ovn-nbctl lr-add R1 >>>> +check ovn-nbctl lr-add R2 >>>> + >>>> +check ovn-nbctl ls-add ls1 >>>> +check ovn-nbctl ls-add ls2 >>>> + >>>> +# Connect ls1 to R1 >>>> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 >>>> + >>>> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- >>>> ls1 type=router \ >>>> + options:router-port=ls1 addresses=\"$rp_ls1_mac\" >>>> + >>>> +# Connect ls2 to R2 >>>> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 >>>> + >>>> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- >>>> ls2 type=router \ >>>> + options:router-port=ls2 addresses=\"$rp_ls2_mac\" >>>> + >>>> +# Connect R1 to R2 >>>> +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 2001:db8::1/64 >>>> peer=R2_R1 >>>> +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 2001:db8::2/64 >>>> peer=R1_R2 >>>> + >>>> +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) >>>> +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) >>>> + >>>> +# Create logical port ls1-lp1 in ls1 >>>> +check ovn-nbctl lsp-add ls1 ls1-lp1 \ >>>> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" >>>> + >>>> +# Create logical port ls2-lp1 in ls2 >>>> +check ovn-nbctl lsp-add ls2 ls2-lp1 \ >>>> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" >>>> + >>>> +# Create two hypervisor and create OVS ports corresponding to >>>> logical ports. >>>> +net_add n1 >>>> + >>>> +sim_add hv1 >>>> +as hv1 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.1 >>>> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ >>>> + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ >>>> + options:tx_pcap=hv1/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv1/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> +sim_add hv2 >>>> +as hv2 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.2 >>>> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ >>>> + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ >>>> + options:tx_pcap=hv2/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv2/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> + >>>> +# Pre-populate the hypervisors' ARP tables so that we don't lose >>>> any >>>> +# packets for ARP resolution (native tunneling doesn't queue >>>> packets >>>> +# for ARP resolution). >>>> +OVN_POPULATE_ARP >>>> + >>>> +# Allow some time for ovn-northd and ovn-controller to catch up. >>>> +wait_for_ports_up >>>> +check ovn-nbctl --wait=hv sync >>>> + >>>> +# Packet to send. >>>> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', >>>> src='${ls1_lp1_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=64)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# Packet to Expect >>>> +# The TTL should be decremented by 2. >>>> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', >>>> src='${rp_ls2_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=62)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +echo ${expected} > expected >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 >>>> +]) >>>> + >>>> +# Disable the ls2-lp1 port. >>>> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 >>>> enabled=false >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 >>>> +]) >>>> + >>>> +# Send the same packet again and it should not be delivered >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# The 2nd packet sent shound not be received. >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +OVN_CLEANUP([hv1],[hv2]) >>>> + >>>> +AT_CLEANUP >>>> +]) >>>> + >>>> +OVN_FOR_EACH_NORTHD([ >>>> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over >>>> IPv6]) >>>> +AT_SKIP_IF([test $HAVE_SCAPY = no]) >>>> +ovn_start >>>> + >>>> +# Logical network: >>>> +# Two LRs - R1 and R2 that are connected to ls-transfer in >>>> 2001:db8::/64 >>>> +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. >>>> +# R2 has ls2 (172.16.1.0/24) connected to it. >>>> + >>>> +ls1_lp1_mac="f0:00:00:01:02:03" >>>> +rp_ls1_mac="00:00:00:01:02:03" >>>> +rp_ls2_mac="00:00:00:01:02:04" >>>> +ls2_lp1_mac="f0:00:00:01:02:04" >>>> + >>>> +ls1_lp1_ip="192.168.1.2" >>>> +ls2_lp1_ip="172.16.1.2" >>>> + >>>> +check ovn-nbctl lr-add R1 >>>> +check ovn-nbctl lr-add R2 >>>> + >>>> +check ovn-nbctl ls-add ls1 >>>> +check ovn-nbctl ls-add ls2 >>>> +check ovn-nbctl ls-add ls-transfer >>>> + >>>> +# Connect ls1 to R1 >>>> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 >>>> + >>>> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- >>>> ls1 type=router \ >>>> + options:router-port=ls1 addresses=\"$rp_ls1_mac\" >>>> + >>>> +# Connect ls2 to R2 >>>> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 >>>> + >>>> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- >>>> ls2 type=router \ >>>> + options:router-port=ls2 addresses=\"$rp_ls2_mac\" >>>> + >>>> +# Connect R1 to R2 >>>> +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 >>>> 2001:db8::1/64 >>>> +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 >>>> 2001:db8::2/64 >>>> + >>>> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ >>>> + set Logical_Switch_Port ls-transfer_r1 type=router \ >>>> + options:router-port=R1_ls-transfer addresses=\"router\" >>>> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ >>>> + set Logical_Switch_Port ls-transfer_r2 type=router \ >>>> + options:router-port=R2_ls-transfer addresses=\"router\" >>>> + >>>> +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) >>>> +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) >>>> + >>>> +# Create logical port ls1-lp1 in ls1 >>>> +check ovn-nbctl lsp-add ls1 ls1-lp1 \ >>>> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" >>>> + >>>> +# Create logical port ls2-lp1 in ls2 >>>> +check ovn-nbctl lsp-add ls2 ls2-lp1 \ >>>> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" >>>> + >>>> +# Create two hypervisor and create OVS ports corresponding to >>>> logical ports. >>>> +net_add n1 >>>> + >>>> +sim_add hv1 >>>> +as hv1 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.1 >>>> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ >>>> + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ >>>> + options:tx_pcap=hv1/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv1/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> +sim_add hv2 >>>> +as hv2 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.2 >>>> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ >>>> + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ >>>> + options:tx_pcap=hv2/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv2/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> + >>>> +# Pre-populate the hypervisors' ARP tables so that we don't lose >>>> any >>>> +# packets for ARP resolution (native tunneling doesn't queue >>>> packets >>>> +# for ARP resolution). >>>> +OVN_POPULATE_ARP >>>> + >>>> +# Allow some time for ovn-northd and ovn-controller to catch up. >>>> +wait_for_ports_up >>>> +check ovn-nbctl --wait=hv sync >>>> + >>>> +# Packet to send. >>>> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', >>>> src='${ls1_lp1_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=64)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# Packet to Expect >>>> +# The TTL should be decremented by 2. >>>> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', >>>> src='${rp_ls2_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=62)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +echo ${expected} > expected >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 >>>> +]) >>>> + >>>> +# Disable the ls2-lp1 port. >>>> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 >>>> enabled=false >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 >>>> +]) >>>> + >>>> +# Send the same packet again and it should not be delivered >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# The 2nd packet sent shound not be received. >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +OVN_CLEANUP([hv1],[hv2]) >>>> + >>>> +AT_CLEANUP >>>> +]) >>>> + >>>> +OVN_FOR_EACH_NORTHD([ >>>> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over >>>> IPv6, static mac]) >>>> +AT_SKIP_IF([test $HAVE_SCAPY = no]) >>>> +ovn_start >>>> + >>>> +# Logical network: >>>> +# Two LRs - R1 and R2 that are connected to ls-transfer in >>>> 2001:db8::/64 >>>> +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. >>>> +# R2 has ls2 (172.16.1.0/24) connected to it. >>>> + >>>> +ls1_lp1_mac="f0:00:00:01:02:03" >>>> +rp_ls1_mac="00:00:00:01:02:03" >>>> +rp_ls2_mac="00:00:00:01:02:04" >>>> +ls2_lp1_mac="f0:00:00:01:02:04" >>>> + >>>> +ls1_lp1_ip="192.168.1.2" >>>> +ls2_lp1_ip="172.16.1.2" >>>> + >>>> +check ovn-nbctl lr-add R1 >>>> +check ovn-nbctl lr-add R2 >>>> + >>>> +check ovn-nbctl ls-add ls1 >>>> +check ovn-nbctl ls-add ls2 >>>> +check ovn-nbctl ls-add ls-transfer >>>> + >>>> +# Connect ls1 to R1 >>>> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 >>>> +check ovn-nbctl set Logical_Router R1 >>>> options:dynamic_neigh_routers=true >>>> + >>>> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- >>>> ls1 type=router \ >>>> + options:router-port=ls1 addresses=\"$rp_ls1_mac\" >>>> + >>>> +# Connect ls2 to R2 >>>> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 >>>> +check ovn-nbctl set Logical_Router R2 >>>> options:dynamic_neigh_routers=true >>>> + >>>> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- >>>> ls2 type=router \ >>>> + options:router-port=ls2 addresses=\"$rp_ls2_mac\" >>>> + >>>> +# Connect R1 to R2 >>>> +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 >>>> 2001:db8::1/64 >>>> +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 >>>> 2001:db8::2/64 >>>> + >>>> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ >>>> + set Logical_Switch_Port ls-transfer_r1 type=router \ >>>> + options:router-port=R1_ls-transfer addresses=\"router\" >>>> +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ >>>> + set Logical_Switch_Port ls-transfer_r2 type=router \ >>>> + options:router-port=R2_ls-transfer addresses=\"router\" >>>> + >>>> +# Static mac binding entries >>>> +check ovn-nbctl static-mac-binding-add R1_ls-transfer 2001:db8::2 >>>> 00:00:00:02:03:05 >>>> +check ovn-nbctl static-mac-binding-add R2_ls-transfer 2001:db8::1 >>>> 00:00:00:02:03:04 >>>> + >>>> +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) >>>> +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) >>>> + >>>> +# Create logical port ls1-lp1 in ls1 >>>> +check ovn-nbctl lsp-add ls1 ls1-lp1 \ >>>> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" >>>> + >>>> +# Create logical port ls2-lp1 in ls2 >>>> +check ovn-nbctl lsp-add ls2 ls2-lp1 \ >>>> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" >>>> + >>>> +# Create two hypervisor and create OVS ports corresponding to >>>> logical ports. >>>> +net_add n1 >>>> + >>>> +sim_add hv1 >>>> +as hv1 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.1 >>>> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ >>>> + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ >>>> + options:tx_pcap=hv1/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv1/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> +sim_add hv2 >>>> +as hv2 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.2 >>>> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ >>>> + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ >>>> + options:tx_pcap=hv2/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv2/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> + >>>> +# Pre-populate the hypervisors' ARP tables so that we don't lose >>>> any >>>> +# packets for ARP resolution (native tunneling doesn't queue >>>> packets >>>> +# for ARP resolution). >>>> +OVN_POPULATE_ARP >>>> + >>>> +# Allow some time for ovn-northd and ovn-controller to catch up. >>>> +wait_for_ports_up >>>> +check ovn-nbctl --wait=hv sync >>>> + >>>> +# Packet to send. >>>> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', >>>> src='${ls1_lp1_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=64)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# Packet to Expect >>>> +# The TTL should be decremented by 2. >>>> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', >>>> src='${rp_ls2_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=62)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +echo ${expected} > expected >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 >>>> +]) >>>> + >>>> +# Disable the ls2-lp1 port. >>>> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 >>>> enabled=false >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 >>>> +]) >>>> + >>>> +# Send the same packet again and it should not be delivered >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# The 2nd packet sent shound not be received. >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +OVN_CLEANUP([hv1],[hv2]) >>>> + >>>> +AT_CLEANUP >>>> +]) >>>> + >>>> +OVN_FOR_EACH_NORTHD([ >>>> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over >>>> IPv6, ECMP]) >>>> +AT_SKIP_IF([test $HAVE_SCAPY = no]) >>>> +ovn_start >>>> + >>>> +# Logical network: >>>> +# Two LRs - R1 and R2 that are connected to ls-transfer1 and lr- >>>> transfer2 in >>>> +# 2001:db8:1::/64 and 2001:db8:2::/64 >>>> +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. >>>> +# R2 has ls2 (172.16.1.0/24) connected to it. >>>> + >>>> +ls1_lp1_mac="f0:00:00:01:02:03" >>>> +rp_ls1_mac="00:00:00:01:02:03" >>>> +rp_ls2_mac="00:00:00:01:02:04" >>>> +ls2_lp1_mac="f0:00:00:01:02:04" >>>> + >>>> +ls1_lp1_ip="192.168.1.2" >>>> +ls2_lp1_ip="172.16.1.2" >>>> + >>>> +check ovn-nbctl lr-add R1 >>>> +check ovn-nbctl lr-add R2 >>>> + >>>> +check ovn-nbctl ls-add ls1 >>>> +check ovn-nbctl ls-add ls2 >>>> +check ovn-nbctl ls-add ls-transfer1 >>>> +check ovn-nbctl ls-add ls-transfer2 >>>> + >>>> +# Connect ls1 to R1 >>>> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 >>>> + >>>> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- >>>> ls1 type=router \ >>>> + options:router-port=ls1 addresses=\"$rp_ls1_mac\" >>>> + >>>> +# Connect ls2 to R2 >>>> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 >>>> + >>>> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- >>>> ls2 type=router \ >>>> + options:router-port=ls2 addresses=\"$rp_ls2_mac\" >>>> + >>>> +# Connect R1 to R2 (ls-transfer1) >>>> +check ovn-nbctl lrp-add R1 R1_ls-transfer1 00:00:00:02:03:04 >>>> 2001:db8:1::1/64 >>>> +check ovn-nbctl lrp-add R2 R2_ls-transfer1 00:00:00:02:03:05 >>>> 2001:db8:1::2/64 >>>> + >>>> +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r1 -- \ >>>> + set Logical_Switch_Port ls-transfer1_r1 type=router \ >>>> + options:router-port=R1_ls-transfer1 addresses=\"router\" >>>> +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r2 -- \ >>>> + set Logical_Switch_Port ls-transfer1_r2 type=router \ >>>> + options:router-port=R2_ls-transfer1 addresses=\"router\" >>>> + >>>> +# Connect R1 to R2 (ls-transfer2) >>>> +check ovn-nbctl lrp-add R1 R1_ls-transfer2 00:00:00:02:03:14 >>>> 2001:db8:2::1/64 >>>> +check ovn-nbctl lrp-add R2 R2_ls-transfer2 00:00:00:02:03:15 >>>> 2001:db8:2::2/64 >>>> + >>>> +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r1 -- \ >>>> + set Logical_Switch_Port ls-transfer2_r1 type=router \ >>>> + options:router-port=R1_ls-transfer2 addresses=\"router\" >>>> +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r2 -- \ >>>> + set Logical_Switch_Port ls-transfer2_r2 type=router \ >>>> + options:router-port=R2_ls-transfer2 addresses=\"router\" >>>> + >>>> +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8:1::2]) >>>> +AT_CHECK([ovn-nbctl --ecmp lr-route-add R1 "0.0.0.0/0" >>>> 2001:db8:2::2]) >>>> +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8:1::1]) >>>> +AT_CHECK([ovn-nbctl --ecmp lr-route-add R2 "0.0.0.0/0" >>>> 2001:db8:2::1]) >>>> + >>>> +# Create logical port ls1-lp1 in ls1 >>>> +check ovn-nbctl lsp-add ls1 ls1-lp1 \ >>>> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" >>>> + >>>> +# Create logical port ls2-lp1 in ls2 >>>> +check ovn-nbctl lsp-add ls2 ls2-lp1 \ >>>> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" >>>> + >>>> +# Create two hypervisor and create OVS ports corresponding to >>>> logical ports. >>>> +net_add n1 >>>> + >>>> +sim_add hv1 >>>> +as hv1 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.1 >>>> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ >>>> + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ >>>> + options:tx_pcap=hv1/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv1/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> +sim_add hv2 >>>> +as hv2 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.2 >>>> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ >>>> + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ >>>> + options:tx_pcap=hv2/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv2/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> + >>>> +# Pre-populate the hypervisors' ARP tables so that we don't lose >>>> any >>>> +# packets for ARP resolution (native tunneling doesn't queue >>>> packets >>>> +# for ARP resolution). >>>> +OVN_POPULATE_ARP >>>> + >>>> +# Allow some time for ovn-northd and ovn-controller to catch up. >>>> +wait_for_ports_up >>>> +check ovn-nbctl --wait=hv sync >>>> + >>>> +# Packet to send. >>>> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', >>>> src='${ls1_lp1_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=64)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# Packet to Expect >>>> +# The TTL should be decremented by 2. >>>> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', >>>> src='${rp_ls2_mac}')/ \ >>>> + IP(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', ttl=62)/ \ >>>> + UDP(sport=53, dport=4369)") >>> >>> Nit: indentation. >>> >>>> +echo ${expected} > expected >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 >>>> +]) >>>> + >>>> +# Disable the ls2-lp1 port. >>>> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 >>>> enabled=false >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 >>>> +]) >>>> + >>>> +# Send the same packet again and it should not be delivered >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# The 2nd packet sent shound not be received. >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +OVN_CLEANUP([hv1],[hv2]) >>>> + >>>> +AT_CLEANUP >>>> +]) >>>> + >>>> +OVN_FOR_EACH_NORTHD([ >>>> +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv6 over IPv4]) >>>> +AT_SKIP_IF([test $HAVE_SCAPY = no]) >>>> +ovn_start >>>> + >>>> +# Logical network: >>>> +# Two LRs - R1 and R2 that are connected to each other as peers in >>>> 10.0.0.0/24 >>>> +# network. R1 has a switchs ls1 (2001:db8:1::/64) connected to it. >>>> +# R2 has ls2 (2001:db8:2::/64) connected to it. >>>> + >>>> +ls1_lp1_mac="f0:00:00:01:02:03" >>>> +rp_ls1_mac="00:00:00:01:02:03" >>>> +rp_ls2_mac="00:00:00:01:02:04" >>>> +ls2_lp1_mac="f0:00:00:01:02:04" >>>> + >>>> +ls1_lp1_ip="2001:db8:1::2" >>>> +ls2_lp1_ip="2001:db8:2::2" >>>> + >>>> +check ovn-nbctl lr-add R1 >>>> +check ovn-nbctl lr-add R2 >>>> + >>>> +check ovn-nbctl ls-add ls1 >>>> +check ovn-nbctl ls-add ls2 >>>> + >>>> +# Connect ls1 to R1 >>>> +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 2001:db8:1::1/64 >>>> + >>>> +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp- >>>> ls1 type=router \ >>>> + options:router-port=ls1 addresses=\"$rp_ls1_mac\" >>>> + >>>> +# Connect ls2 to R2 >>>> +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 2001:db8:2::1/64 >>>> + >>>> +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp- >>>> ls2 type=router \ >>>> + options:router-port=ls2 addresses=\"$rp_ls2_mac\" >>>> + >>>> +# Connect R1 to R2 >>>> +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 10.0.0.1/24 >>>> peer=R2_R1 >>>> +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 10.0.0.2/24 >>>> peer=R1_R2 >>>> + >>>> +AT_CHECK([ovn-nbctl lr-route-add R1 "::/0" 10.0.0.2]) >>>> +AT_CHECK([ovn-nbctl lr-route-add R2 "::/0" 10.0.0.1]) >>>> + >>>> +# Create logical port ls1-lp1 in ls1 >>>> +check ovn-nbctl lsp-add ls1 ls1-lp1 \ >>>> +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" >>>> + >>>> +# Create logical port ls2-lp1 in ls2 >>>> +check ovn-nbctl lsp-add ls2 ls2-lp1 \ >>>> +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" >>>> + >>>> +# Create two hypervisor and create OVS ports corresponding to >>>> logical ports. >>>> +net_add n1 >>>> + >>>> +sim_add hv1 >>>> +as hv1 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.1 >>>> +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ >>>> + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ >>>> + options:tx_pcap=hv1/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv1/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> +sim_add hv2 >>>> +as hv2 >>>> +check ovs-vsctl add-br br-phys >>>> +ovn_attach n1 br-phys 192.168.0.2 >>>> +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ >>>> + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ >>>> + options:tx_pcap=hv2/vif1-tx.pcap \ >>>> + options:rxq_pcap=hv2/vif1-rx.pcap \ >>>> + ofport-request=1 >>>> + >>>> + >>>> +# Pre-populate the hypervisors' ARP tables so that we don't lose >>>> any >>>> +# packets for ARP resolution (native tunneling doesn't queue >>>> packets >>>> +# for ARP resolution). >>>> +OVN_POPULATE_ARP >>>> + >>>> +# Allow some time for ovn-northd and ovn-controller to catch up. >>>> +wait_for_ports_up >>>> +check ovn-nbctl --wait=hv sync >>>> + >>>> +# Packet to send. >>>> +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', >>>> src='${ls1_lp1_mac}')/ \ >>>> + IPv6(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', hlim=64)/ \ >>>> + UDP(sport=53, dport=4369)") >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# Packet to Expect >>>> +# The TTL should be decremented by 2. >>>> +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', >>>> src='${rp_ls2_mac}')/ \ >>>> + IPv6(src='${ls1_lp1_ip}', >>>> dst='${ls2_lp1_ip}', hlim=62)/ \ >>>> + UDP(sport=53, dport=4369)") >>>> +echo ${expected} > expected >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [1 >>>> +]) >>>> + >>>> +# Disable the ls2-lp1 port. >>>> +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 >>>> enabled=false >>>> + >>>> +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ >>>> +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [0 >>>> +]) >>>> + >>>> +# Send the same packet again and it should not be delivered >>>> +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" >>>> + >>>> +# The 2nd packet sent shound not be received. >>>> +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) >>>> + >>>> +OVN_CLEANUP([hv1],[hv2]) >>>> + >>>> +AT_CLEANUP >>>> +]) >>>> diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c >>>> index d45be75c7..86a3b5966 100644 >>>> --- a/utilities/ovn-nbctl.c >>>> +++ b/utilities/ovn-nbctl.c >>>> @@ -4591,11 +4591,9 @@ 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) { >>>> prefix = normalize_ipv6_prefix_str(ctx->argv[2]); >>>> - v6_prefix = true; >>>> } >>>> if (!prefix) { >>>> ctl_error(ctx, "bad prefix argument: %s", ctx->argv[2]); >>>> @@ -4606,15 +4604,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) >>>> if (is_discard_route) { >>>> next_hop = xasprintf("discard"); >>>> } else { >>>> - next_hop = v6_prefix >>>> - ? normalize_ipv6_addr_str(ctx->argv[3]) >>>> - : normalize_ipv4_addr_str(ctx->argv[3]); >>>> + next_hop = normalize_ipv4_addr_str(ctx->argv[3]); >>>> + if (!next_hop) { >>>> + next_hop = normalize_ipv6_addr_str(ctx->argv[3]); >>>> + } >>>> if (!next_hop) { >>>> /* check if it is a output port. */ >>>> error = lrp_by_name_or_uuid(ctx, ctx->argv[3], true, >>>> &out_lrp); >>>> if (error) { >>>> - ctl_error(ctx, "bad %s nexthop argument: %s", >>>> - v6_prefix ? "IPv6" : "IPv4", ctx- >>>>> argv[3]); >>>> + ctl_error(ctx, "bad nexthop argument: %s", ctx- >>>>> argv[3]); >>>> free(error); >>>> goto cleanup; >>>> } >>> >>> Regards, >>> Dumitru >>> >> >
On 12/17/24 5:14 PM, Dumitru Ceara wrote: > On 12/17/24 5:02 PM, Felix Huettner wrote: >> On Tue, Dec 17, 2024 at 04:41:44PM +0100, martin.kalcok@canonical.com wrote: >>> Thank you for the review and conflict resolution Dumitru. Your changes >>> look good for my part (register reassignment and system tests). >>> > Thanks for checking! > >>> Martin. >>> >>> On Tue, 2024-12-17 at 16:25 +0100, Dumitru Ceara wrote: >>>> Hi Martin, Felix, >>>> >>>> On 12/4/24 4:10 PM, Martin Kalcok wrote: >>>>> From: Felix Huettner <felix.huettner@mail.schwarz> >>>>> >>>>> In most cases IPv4 packets are routed only over other IPv4 networks >>>>> and >>>>> IPv6 packets are routed only over IPv6 networks. However there is >>>>> no >>>>> inherent reason for this limitation. Routing IPv4 packets over IPv6 >>>>> networks just requires the router to contain a route for an IPv4 >>>>> network >>>>> with an IPv6 nexthop. >>>>> >>>>> This was previously prevented in OVN in ovn-nbctl and northd. By >>>>> removing these filters the forwarding will work if the mac >>>>> addresses are >>>>> prepopulated. >>>>> >>>>> If the mac addresses are not prepopulated we will attempt to >>>>> resolve them using >>>>> the original address family of the packet and not the address >>>>> family of the >>>>> nexthop. This will fail and we will not forward the packet. >>>>> >>>>> This feature can for example be used by service providers to >>>>> interconnect multiple IPv4 networks of a customer without needing >>>>> to >>>>> negotiate free IPv4 addresses by just using any IPv6 address. >>>>> >>>>> Signed-off-by: Felix Huettner <felix.huettner@mail.schwarz> >>>> Felix, is this email address correct? >> Hi Dumitru, >> >> we have since switched our mail domain, so now it is >> felix.huettner@stackit.cloud >> However the old one will work for the next years so we can also keep >> this one. >> > Ack. > >>>>> Signed-off-by: Martin Kalcok <martin.kalcok@canonical.com> >>>>> Co-authored-by: Martin Kalcok <martin.kalcok@canonical.com> >>>>> --- >>>> After merging Felix's BGP prerequisite patches, there were a bunch of >>>> conflicts when applying this patch but I think I managed to address >>>> them. >>>> >>>> I pushed the rebased patches (also with the small nits I had below >>>> addressed) to: >>>> https://github.com/dceara/ovn/commits/bcba1b74 >>>> >>>> It would be great if you could double check that it still looks OK to >>>> you. If that's the case I can then apply the series to main. >> All of the 3 commits look good from my side. >> Thanks a lot for going through the conflict hell. Applied to main, thanks!
diff --git a/NEWS b/NEWS index da3aba739..b5aae7d4b 100644 --- a/NEWS +++ b/NEWS @@ -75,6 +75,10 @@ OVN v24.09.0 - 13 Sep 2024 "routing-protocol-redirect" and "routing-protocols", that allow redirection of routing protocol traffic received by a router port to a different logical switch port. + - Allow Static Routes where the address families of ip_prefix and nexthop + diverge (e.g. IPv4 packets over IPv6 links). This is currently limited to + nexthops that have their mac addresses prepopulated (so + dynamic_neigh_routers must be false). OVN v24.03.0 - 01 Mar 2024 -------------------------- diff --git a/northd/northd.c b/northd/northd.c index 3564d45d9..4fb48838b 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -174,6 +174,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2)); #define REGBIT_KNOWN_LB_SESSION "reg9[6]" #define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]" #define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]" +#define REGBIT_NEXTHOP_IS_IPV4 "reg9[9]" /* Register to store the eth address associated to a router port for packets * received in S_ROUTER_IN_ADMISSION. @@ -290,7 +291,8 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2)); * | | LOOKUP_NEIGHBOR_RESULT/ | | | * | | SKIP_LOOKUP_NEIGHBOR/ | | | * | |REGBIT_DHCP_RELAY_REQ_CHK/ | | | - * | |REGBIT_DHCP_RELAY_RESP_CHK}| | | + * | |REGBIT_DHCP_RELAY_RESP_CHK | | | + * | |REGBIT_NEXTHOP_IS_IPV4} | | | * | | | | | * | | REG_ORIG_TP_DPORT_ROUTER | | | * | | | | | @@ -10861,13 +10863,15 @@ build_routing_policy_flow(struct lflow_table *lflows, struct ovn_datapath *od, "outport = %s; " "flags.loopback = 1; " REG_ECMP_GROUP_ID" = 0; " + REGBIT_NEXTHOP_IS_IPV4" = %d; " "next;", is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, nexthop, is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, lrp_addr_s, out_port->lrp_networks.ea_s, - out_port->json_key); + out_port->json_key, + is_ipv4); } else if (!strcmp(rule->action, "drop")) { ds_put_cstr(&actions, debug_drop_action()); @@ -10951,13 +10955,15 @@ build_ecmp_routing_policy_flows(struct lflow_table *lflows, "eth.src = %s; " "outport = %s; " "flags.loopback = 1; " + REGBIT_NEXTHOP_IS_IPV4" = %d; " "next;", is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, rp->valid_nexthops[i], is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, lrp_addr_s, out_port->lrp_networks.ea_s, - out_port->json_key); + out_port->json_key, + is_ipv4); ds_clear(&match); ds_put_format(&match, REG_ECMP_GROUP_ID" == %"PRIu16" && " @@ -11123,6 +11129,8 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, /* Verify that the next hop is an IP address with an all-ones mask. */ struct in6_addr nexthop; unsigned int plen; + bool is_ipv4_nexthop = true; + bool is_ipv4_prefix; bool is_discard_route = !strcmp(route->nexthop, "discard"); bool valid_nexthop = route->nexthop[0] && !is_discard_route; if (valid_nexthop) { @@ -11141,6 +11149,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, UUID_ARGS(&route->header_.uuid)); return; } + is_ipv4_nexthop = IN6_IS_ADDR_V4MAPPED(&nexthop); } /* Parse ip_prefix */ @@ -11152,18 +11161,7 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, UUID_ARGS(&route->header_.uuid)); return; } - - /* Verify that ip_prefix and nexthop have same address familiy. */ - if (valid_nexthop) { - if (IN6_IS_ADDR_V4MAPPED(&prefix) != IN6_IS_ADDR_V4MAPPED(&nexthop)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); - VLOG_WARN_RL(&rl, "Address family doesn't match between 'ip_prefix'" - " %s and 'nexthop' %s in static route "UUID_FMT, - route->ip_prefix, route->nexthop, - UUID_ARGS(&route->header_.uuid)); - return; - } - } + is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&prefix); /* Verify that ip_prefix and nexthop are on the same network. */ if (!is_discard_route && @@ -11216,6 +11214,8 @@ parsed_routes_add(struct ovn_datapath *od, const struct hmap *lr_ports, "ecmp_symmetric_reply", false); new_pr->is_discard_route = is_discard_route; + new_pr->is_ipv4_prefix = is_ipv4_prefix; + new_pr->is_ipv4_nexthop = is_ipv4_nexthop; sset_init(&new_pr->ecmp_selection_fields); /* If tp_src or tp_dst is included in the selection_fields, implicitly @@ -11646,7 +11646,7 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, struct lflow_ref *lflow_ref, const char *protocol) { - bool is_ipv4 = IN6_IS_ADDR_V4MAPPED(&eg->prefix); + bool is_ipv4_prefix = IN6_IS_ADDR_V4MAPPED(&eg->prefix); uint16_t priority; struct ecmp_route_list_node *er; struct ds route_match = DS_EMPTY_INITIALIZER; @@ -11655,7 +11655,8 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, int ofs = !strcmp(eg->origin, ROUTE_ORIGIN_CONNECTED) ? ROUTE_PRIO_OFFSET_CONNECTED: ROUTE_PRIO_OFFSET_STATIC; build_route_match(NULL, eg->route_table_id, prefix_s, eg->plen, - eg->is_src_route, is_ipv4, &route_match, &priority, ofs, + eg->is_src_route, is_ipv4_prefix, &route_match, + &priority, ofs, protocol != NULL); free(prefix_s); @@ -11723,7 +11724,8 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, /* Find the outgoing port. */ const char *lrp_addr_s = NULL; struct ovn_port *out_port = NULL; - if (!find_static_route_outport(od, lr_ports, route, is_ipv4, + if (!find_static_route_outport(od, lr_ports, route, + route_->is_ipv4_nexthop, &lrp_addr_s, &out_port)) { continue; } @@ -11746,13 +11748,16 @@ build_ecmp_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, "%s = %s; " "eth.src = %s; " "outport = %s; " + REGBIT_NEXTHOP_IS_IPV4" = %d; " "next;", - is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, + route_->is_ipv4_nexthop ? + REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6, route->nexthop, - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, + route_->is_ipv4_nexthop ? REG_SRC_IPV4 : REG_SRC_IPV6, lrp_addr_s, out_port->lrp_networks.ea_s, - out_port->json_key); + out_port->json_key, + route_->is_ipv4_nexthop); ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 100, ds_cstr(&match), ds_cstr(&actions), &route->header_, lflow_ref); @@ -11770,15 +11775,15 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od, bool is_src_route, const uint32_t rtb_id, const struct sset *bfd_ports, const struct ovsdb_idl_row *stage_hint, bool is_discard_route, - int ofs, struct lflow_ref *lflow_ref) + int ofs, struct lflow_ref *lflow_ref, + bool is_ipv4_prefix, bool is_ipv4_nexthop) { - bool is_ipv4 = strchr(network_s, '.') ? true : false; struct ds match = DS_EMPTY_INITIALIZER; uint16_t priority; const struct ovn_port *op_inport = NULL; /* IPv6 link-local addresses must be scoped to the local router port. */ - if (!is_ipv4) { + if (!is_ipv4_prefix) { struct in6_addr network; ovs_assert(ipv6_parse(network_s, &network)); if (in6_is_lla(&network)) { @@ -11786,7 +11791,7 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od, } } build_route_match(op_inport, rtb_id, network_s, plen, is_src_route, - is_ipv4, &match, &priority, ofs, false); + is_ipv4_prefix, &match, &priority, ofs, false); struct ds common_actions = DS_EMPTY_INITIALIZER; struct ds actions = DS_EMPTY_INITIALIZER; @@ -11794,22 +11799,25 @@ add_route(struct lflow_table *lflows, struct ovn_datapath *od, ds_put_cstr(&actions, debug_drop_action()); } else { ds_put_format(&common_actions, REG_ECMP_GROUP_ID" = 0; %s = ", - is_ipv4 ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); + is_ipv4_nexthop ? REG_NEXT_HOP_IPV4 : REG_NEXT_HOP_IPV6); if (gateway && gateway[0]) { ds_put_cstr(&common_actions, gateway); } else { - ds_put_format(&common_actions, "ip%s.dst", is_ipv4 ? "4" : "6"); + ds_put_format(&common_actions, "ip%s.dst", + is_ipv4_prefix ? "4" : "6"); } ds_put_format(&common_actions, "; " "%s = %s; " "eth.src = %s; " "outport = %s; " "flags.loopback = 1; " + REGBIT_NEXTHOP_IS_IPV4" = %d; " "next;", - is_ipv4 ? REG_SRC_IPV4 : REG_SRC_IPV6, + is_ipv4_nexthop ? REG_SRC_IPV4 : REG_SRC_IPV6, lrp_addr_s, op->lrp_networks.ea_s, - op->json_key); + op->json_key, + is_ipv4_nexthop); ds_put_format(&actions, "ip.ttl--; %s", ds_cstr(&common_actions)); } @@ -11860,7 +11868,8 @@ build_static_route_flow(struct lflow_table *lflows, struct ovn_datapath *od, lrp_addr_s, prefix_s, route_->plen, route->nexthop, route_->is_src_route, route_->route_table_id, bfd_ports, &route->header_, route_->is_discard_route, - ofs, lflow_ref); + ofs, lflow_ref, + route_->is_ipv4_prefix, route_->is_ipv4_nexthop); free(prefix_s); } @@ -13708,7 +13717,7 @@ build_ip_routing_flows_for_lrp(struct ovn_port *op, op->lrp_networks.ipv4_addrs[i].network_s, op->lrp_networks.ipv4_addrs[i].plen, NULL, false, 0, bfd_ports, &op->nbrp->header_, false, - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, true, true); } for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { @@ -13716,7 +13725,7 @@ build_ip_routing_flows_for_lrp(struct ovn_port *op, op->lrp_networks.ipv6_addrs[i].network_s, op->lrp_networks.ipv6_addrs[i].plen, NULL, false, 0, bfd_ports, &op->nbrp->header_, false, - ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref); + ROUTE_PRIO_OFFSET_CONNECTED, lflow_ref, false, false); } } @@ -14069,11 +14078,13 @@ build_arp_resolve_flows_for_lrouter( "ip4.mcast || ip6.mcast", "next;", lflow_ref); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip4", + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, + REGBIT_NEXTHOP_IS_IPV4 " == 1", "get_arp(outport, " REG_NEXT_HOP_IPV4 "); next;", lflow_ref); - ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, "ip6", + ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 1, + REGBIT_NEXTHOP_IS_IPV4 " == 0", "get_nd(outport, " REG_NEXT_HOP_IPV6 "); next;", lflow_ref); @@ -17033,7 +17044,7 @@ build_routable_flows_for_router_port( laddrs->ipv4_addrs[k].plen, NULL, false, 0, bfd_ports, &router_port->nbrp->header_, false, ROUTE_PRIO_OFFSET_CONNECTED, - lrp->stateful_lflow_ref); + lrp->stateful_lflow_ref, true, true); } } } diff --git a/northd/northd.h b/northd/northd.h index e93e10f20..a5af72eb7 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -709,6 +709,8 @@ struct parsed_route { const struct nbrec_logical_router *nbr; bool stale; struct sset ecmp_selection_fields; + bool is_ipv4_prefix; + bool is_ipv4_nexthop; }; void ovnnb_db_run(struct northd_input *input_data, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 2efa13b93..addcc4593 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -1857,7 +1857,7 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 11.0.0.2]) AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp0]) AT_CHECK([ovn-nbctl --bfd lr-route-add lr0 10.0.20.0/24 11.0.2.1 lp0]) AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.10.0/24 lp1], [1], [], - [ovn-nbctl: bad IPv4 nexthop argument: lp1 + [ovn-nbctl: bad nexthop argument: lp1 ]) dnl Add overlapping route with 10.0.0.1/24 @@ -1871,13 +1871,13 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24a 11.0.0.1], [1], [], [ovn-nbctl: bad prefix argument: 10.0.0.111/24a ]) AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1a], [1], [], - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1a + [ovn-nbctl: bad nexthop argument: 11.0.0.1a ]) AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.111/24 11.0.0.1/24], [1], [], - [ovn-nbctl: bad IPv4 nexthop argument: 11.0.0.1/24 + [ovn-nbctl: bad nexthop argument: 11.0.0.1/24 ]) AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1/64], [1], [], - [ovn-nbctl: bad IPv6 nexthop argument: 2001:0db8:0:f103::1/64 + [ovn-nbctl: bad nexthop argument: 2001:0db8:0:f103::1/64 ]) AT_CHECK([ovn-nbctl --ecmp lr-route-add lr0 20.0.0.0/24 discard], [1], [], [ovn-nbctl: ecmp is not valid for discard routes. @@ -2105,6 +2105,24 @@ check ovn-nbctl lr-route-del lr0 AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl ]) +dnl Check IPv4 over v6 and IPv6 over v4 routes +AT_CHECK([ovn-nbctl lr-route-add lr0 10.0.0.1/24 2001:0db8:0:f103::10]) +AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:0::/64 11.0.1.10]) + +AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl +IPv4 Routes +Route Table <main>: + 10.0.0.0/24 2001:db8:0:f103::10 dst-ip + +IPv6 Routes +Route Table <main>: + 2001:db8::/64 11.0.1.10 dst-ip +]) + +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 diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at index c98f1fcb4..803823afa 100644 --- a/tests/ovn-northd.at +++ b/tests/ovn-northd.at @@ -3442,8 +3442,8 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | ovn_strip_lflows], [0], [dnl table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = 0; next;) table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = 1; reg8[[16..31]] = select(1, 2);) table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ]) @@ -3458,11 +3458,11 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);) table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);) table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) ]) @@ -3476,13 +3476,13 @@ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = <cleared>; next;) table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.3), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2);) table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);) - table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; next;) + table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) ]) @@ -3495,11 +3495,11 @@ sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = <cleared>; next;) table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.4), action=(reg8[[0..15]] = <cleared>; reg8[[16..31]] = select(1, 2, 3);) - table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; next;) + table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) - table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 1), action=(reg0 = 172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2), action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_policy_ecmp ), priority=100 , match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3), action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) ]) @@ -3511,7 +3511,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 | \ sed 's/reg8\[[0..15\]] = [[0-9]]*/reg8\[[0..15\]] = <cleared>/' | \ sed 's/reg8\[[0..15\]] == [[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lflows], [0], [dnl table=??(lr_in_policy ), priority=0 , match=(1), action=(reg8[[0..15]] = <cleared>; next;) - table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; next;) + table=??(lr_in_policy ), priority=10 , match=(ip4.src == 10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;) table=??(lr_in_policy_ecmp ), priority=0 , match=(1), action=(drop;) table=??(lr_in_policy_ecmp ), priority=150 , match=(reg8[[0..15]] == <cleared>), action=(next;) ]) @@ -6823,14 +6823,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;) table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; reg8[[0..15]] = 1; reg8[[16..31]] = 1; next;) - table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) ]) AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | ovn_strip_lflows], [0], [dnl table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;) - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ]) @@ -6841,14 +6841,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;) table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 && 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=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) ]) AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;) - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ]) @@ -6870,14 +6870,14 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows | ovn_strip_lflows], [0], [dnl table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) table=??(lr_in_ip_routing ), priority=10300, match=(ct_mark.ecmp_reply_port == 1 && reg7 == 0 && ip4.dst == 1.0.0.1/32), action=(ip.ttl--; flags.loopback = 1; eth.src = 00:00:20:20:12:13; reg5 = 192.168.0.1; outport = "lr0-public"; next;) table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 0 && 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=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; next;) + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) ]) AT_CHECK([grep -e "lr_in_ip_routing_ecmp" lr0flows | sed 's/192\.168\.0\..0/192.168.0.??/' | ovn_strip_lflows], [0], [dnl table=??(lr_in_ip_routing_ecmp), priority=0 , match=(1), action=(drop;) - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) - table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; next;) + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing_ecmp), priority=100 , match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 = 192.168.0.??; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; reg9[[9]] = 1; next;) table=??(lr_in_ip_routing_ecmp), priority=150 , match=(reg8[[0..15]] == 0), action=(next;) ]) @@ -6888,14 +6888,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 | ovn_strip_lflows], [0], [dnl - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 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=122 , match=(reg7 == 0 && ip4.dst == 1.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 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 | ovn_strip_lflows], [0], [dnl - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 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=122 , match=(reg7 == 0 && ip4.dst == 2.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) ]) check ovn-nbctl lr-route-add lr0 3.3.0.0/16 192.168.0.11 @@ -6928,6 +6928,66 @@ AT_CHECK([grep -e "(lr_in_ip_routing ).*3.3.0.0" lr0flows | sed 's/table=../ta AT_CLEANUP ]) +OVN_FOR_EACH_NORTHD_NO_HV([ +AT_SETUP([ovn -- static routes multiple address families flows]) +AT_KEYWORDS([static-routes-flows]) +ovn_start + +check ovn-sbctl chassis-add ch1 geneve 127.0.0.1 + +check ovn-nbctl lr-add lr0 +check ovn-nbctl set logical_router lr0 options:chassis=ch1 +check ovn-nbctl ls-add public +check ovn-nbctl ls-add private +check ovn-nbctl lrp-add lr0 lr0-public 00:00:20:20:12:13 192.168.0.1/24 +check ovn-nbctl lsp-add public public-lr0 +check ovn-nbctl lsp-set-type public-lr0 router +check ovn-nbctl lsp-set-addresses public-lr0 router +check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public + +check ovn-nbctl lrp-add lr0 lr0-private 00:00:20:20:12:14 2001:db8::1/64 +check ovn-nbctl lsp-add private private-lr0 +check ovn-nbctl lsp-set-type private-lr0 router +check ovn-nbctl lsp-set-addresses private-lr0 router +check ovn-nbctl lsp-set-options private-lr0 router-port=lr0-private + +check ovn-nbctl --wait=sb lr-route-add lr0 10.0.0.0/24 192.168.0.10 +check ovn-nbctl --wait=sb lr-route-add lr0 11.0.0.0/24 2001:db8::10 +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:1::/64 192.168.0.20 +check ovn-nbctl --wait=sb lr-route-add lr0 2001:db8:2::/64 2001:db8::20 + +ovn-sbctl dump-flows lr0 > lr0flows +AT_CHECK([grep -e "lr_in_ip_routing " lr0flows | ovn_strip_lflows], [0], [dnl + table=??(lr_in_ip_routing ), priority=0 , match=(1), action=(drop;) + table=??(lr_in_ip_routing ), priority=10550, match=(nd_rs || nd_ra), action=(drop;) + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 10.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 0 && ip4.dst == 11.0.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::10; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 && ip6.dst == 2001:db8:1::/64), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=322 , match=(reg7 == 0 && ip6.dst == 2001:db8:2::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = 2001:db8::20; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-private" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1214; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) + table=??(lr_in_ip_routing ), priority=324 , match=(inport == "lr0-public" && ip6.dst == fe80::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = fe80::200:20ff:fe20:1213; eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 0; next;) + table=??(lr_in_ip_routing ), priority=324 , match=(ip6.dst == 2001:db8::/64), action=(ip.ttl--; reg8[[0..15]] = 0; xxreg0 = ip6.dst; xxreg1 = 2001:db8::1; eth.src = 00:00:20:20:12:14; outport = "lr0-private"; flags.loopback = 1; reg9[[9]] = 0; next;) +]) + +AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl + table=??(lr_in_arp_resolve ), priority=0 , match=(1), action=(drop;) + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 0), action=(get_nd(outport, xxreg0); next;) + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 1), action=(get_arp(outport, reg0); next;) + table=??(lr_in_arp_resolve ), priority=500 , match=(ip4.mcast || ip6.mcast), action=(next;) +]) + +AT_CHECK([grep -e "lr_in_arp_request" lr0flows | ovn_strip_lflows], [0], [dnl + table=??(lr_in_arp_request ), priority=0 , match=(1), action=(output;) + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == 00:00:00:00:00:00 && ip4), action=(arp { eth.dst = ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; output; }; output;) + table=??(lr_in_arp_request ), priority=100 , match=(eth.dst == 00:00:00:00:00:00 && ip6), action=(nd_ns { nd.target = xxreg0; output; }; output;) + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::10), action=(nd_ns { eth.dst = 33:33:ff:00:00:10; ip6.dst = ff02::1:ff00:10; nd.target = 2001:db8::10; output; }; output;) + table=??(lr_in_arp_request ), priority=200 , match=(eth.dst == 00:00:00:00:00:00 && ip6 && xxreg0 == 2001:db8::20), action=(nd_ns { eth.dst = 33:33:ff:00:00:20; ip6.dst = ff02::1:ff00:20; nd.target = 2001:db8::20; output; }; output;) +]) + +AT_CLEANUP +]) + OVN_FOR_EACH_NORTHD_NO_HV([ AT_SETUP([ovn-northd -- lr multiple gw ports]) AT_KEYWORDS([multiple-l3dgw-ports]) @@ -7346,16 +7406,16 @@ AT_CHECK([grep "lr_in_ip_routing_pre" lr0flows | ovn_strip_lflows], [0], [dnl grep -e "(lr_in_ip_routing ).*outport" lr0flows AT_CHECK([grep -e "(lr_in_ip_routing ).*outport" lr0flows | ovn_strip_lflows], [0], [dnl - table=??(lr_in_ip_routing ), priority=122 , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; next;) - table=??(lr_in_ip_routing ), priority=324 , 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=324 , 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=324 , 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=122 , match=(reg7 == 1 && ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.1.10; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.0.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.1.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.1.1; eth.src = 00:00:00:00:01:01; outport = "lrp1"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=124 , match=(ip4.dst == 192.168.2.0/24), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = ip4.dst; reg5 = 192.168.2.1; eth.src = 00:00:00:00:02:01; outport = "lrp2"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=162 , match=(reg7 == 2 && ip4.dst == 1.1.1.1/32), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.20; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 0 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=2 , match=(reg7 == 2 && ip4.dst == 0.0.0.0/0), action=(ip.ttl--; reg8[[0..15]] = 0; reg0 = 192.168.0.10; reg5 = 192.168.0.1; eth.src = 00:00:00:00:00:01; outport = "lrp0"; flags.loopback = 1; reg9[[9]] = 1; next;) + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] = 0; next;) + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] = 0; next;) + table=??(lr_in_ip_routing ), priority=324 , 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; reg9[[9]] = 0; next;) ]) AT_CLEANUP @@ -13450,8 +13510,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl table=??(lr_in_arp_resolve ), priority=0 , match=(1), action=(drop;) - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), action=(get_arp(outport, reg0); next;) - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), action=(get_nd(outport, xxreg0); next;) + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 0), action=(get_nd(outport, xxreg0); next;) + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 1), action=(get_arp(outport, reg0); next;) table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = 00:00:00:00:ff:02; next;) table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = 30:54:00:00:00:03; next;) table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = 00:00:00:00:ff:02; next;) @@ -13620,8 +13680,8 @@ AT_CHECK([grep "lr_in_dnat" lr0flows | ovn_strip_lflows], [0], [dnl AT_CHECK([grep "lr_in_arp_resolve" lr0flows | ovn_strip_lflows], [0], [dnl table=??(lr_in_arp_resolve ), priority=0 , match=(1), action=(drop;) - table=??(lr_in_arp_resolve ), priority=1 , match=(ip4), action=(get_arp(outport, reg0); next;) - table=??(lr_in_arp_resolve ), priority=1 , match=(ip6), action=(get_nd(outport, xxreg0); next;) + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 0), action=(get_nd(outport, xxreg0); next;) + table=??(lr_in_arp_resolve ), priority=1 , match=(reg9[[9]] == 1), action=(get_arp(outport, reg0); next;) table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.100), action=(eth.dst = 00:00:00:00:ff:02; next;) table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.110), action=(eth.dst = 00:00:00:00:ff:02; next;) table=??(lr_in_arp_resolve ), priority=100 , match=(outport == "lr0-public" && reg0 == 172.168.0.120), action=(eth.dst = 00:00:00:00:ff:02; next;) diff --git a/tests/ovn.at b/tests/ovn.at index 1071208d1..ec90a3b4e 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -39761,3 +39761,648 @@ OVN_CLEANUP([hv1]) AT_CLEANUP ]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv4 over IPv6]) +AT_SKIP_IF([test $HAVE_SCAPY = no]) +ovn_start + +# Logical network: +# Two LRs - R1 and R2 that are connected to each other as peers in 2001:db8::/64 +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. +# R2 has ls2 (172.16.1.0/24) connected to it. + +ls1_lp1_mac="f0:00:00:01:02:03" +rp_ls1_mac="00:00:00:01:02:03" +rp_ls2_mac="00:00:00:01:02:04" +ls2_lp1_mac="f0:00:00:01:02:04" + +ls1_lp1_ip="192.168.1.2" +ls2_lp1_ip="172.16.1.2" + +check ovn-nbctl lr-add R1 +check ovn-nbctl lr-add R2 + +check ovn-nbctl ls-add ls1 +check ovn-nbctl ls-add ls2 + +# Connect ls1 to R1 +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 + +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ + options:router-port=ls1 addresses=\"$rp_ls1_mac\" + +# Connect ls2 to R2 +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 + +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ + options:router-port=ls2 addresses=\"$rp_ls2_mac\" + +# Connect R1 to R2 +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 2001:db8::1/64 peer=R2_R1 +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 2001:db8::2/64 peer=R1_R2 + +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) + +# Create logical port ls1-lp1 in ls1 +check ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" + +# Create logical port ls2-lp1 in ls2 +check ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +# Allow some time for ovn-northd and ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Packet to send. +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ + UDP(sport=53, dport=4369)") +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# Packet to Expect +# The TTL should be decremented by 2. +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ + UDP(sport=53, dport=4369)") +echo ${expected} > expected +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 +]) + +# Disable the ls2-lp1 port. +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 +]) + +# Send the same packet again and it should not be delivered +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# The 2nd packet sent shound not be received. +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6]) +AT_SKIP_IF([test $HAVE_SCAPY = no]) +ovn_start + +# Logical network: +# Two LRs - R1 and R2 that are connected to ls-transfer in 2001:db8::/64 +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. +# R2 has ls2 (172.16.1.0/24) connected to it. + +ls1_lp1_mac="f0:00:00:01:02:03" +rp_ls1_mac="00:00:00:01:02:03" +rp_ls2_mac="00:00:00:01:02:04" +ls2_lp1_mac="f0:00:00:01:02:04" + +ls1_lp1_ip="192.168.1.2" +ls2_lp1_ip="172.16.1.2" + +check ovn-nbctl lr-add R1 +check ovn-nbctl lr-add R2 + +check ovn-nbctl ls-add ls1 +check ovn-nbctl ls-add ls2 +check ovn-nbctl ls-add ls-transfer + +# Connect ls1 to R1 +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 + +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ + options:router-port=ls1 addresses=\"$rp_ls1_mac\" + +# Connect ls2 to R2 +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 + +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ + options:router-port=ls2 addresses=\"$rp_ls2_mac\" + +# Connect R1 to R2 +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 2001:db8::1/64 +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 2001:db8::2/64 + +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ + set Logical_Switch_Port ls-transfer_r1 type=router \ + options:router-port=R1_ls-transfer addresses=\"router\" +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ + set Logical_Switch_Port ls-transfer_r2 type=router \ + options:router-port=R2_ls-transfer addresses=\"router\" + +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) + +# Create logical port ls1-lp1 in ls1 +check ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" + +# Create logical port ls2-lp1 in ls2 +check ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +# Allow some time for ovn-northd and ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Packet to send. +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ + UDP(sport=53, dport=4369)") +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# Packet to Expect +# The TTL should be decremented by 2. +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ + UDP(sport=53, dport=4369)") +echo ${expected} > expected +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 +]) + +# Disable the ls2-lp1 port. +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 +]) + +# Send the same packet again and it should not be delivered +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# The 2nd packet sent shound not be received. +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6, static mac]) +AT_SKIP_IF([test $HAVE_SCAPY = no]) +ovn_start + +# Logical network: +# Two LRs - R1 and R2 that are connected to ls-transfer in 2001:db8::/64 +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. +# R2 has ls2 (172.16.1.0/24) connected to it. + +ls1_lp1_mac="f0:00:00:01:02:03" +rp_ls1_mac="00:00:00:01:02:03" +rp_ls2_mac="00:00:00:01:02:04" +ls2_lp1_mac="f0:00:00:01:02:04" + +ls1_lp1_ip="192.168.1.2" +ls2_lp1_ip="172.16.1.2" + +check ovn-nbctl lr-add R1 +check ovn-nbctl lr-add R2 + +check ovn-nbctl ls-add ls1 +check ovn-nbctl ls-add ls2 +check ovn-nbctl ls-add ls-transfer + +# Connect ls1 to R1 +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 +check ovn-nbctl set Logical_Router R1 options:dynamic_neigh_routers=true + +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ + options:router-port=ls1 addresses=\"$rp_ls1_mac\" + +# Connect ls2 to R2 +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 +check ovn-nbctl set Logical_Router R2 options:dynamic_neigh_routers=true + +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ + options:router-port=ls2 addresses=\"$rp_ls2_mac\" + +# Connect R1 to R2 +check ovn-nbctl lrp-add R1 R1_ls-transfer 00:00:00:02:03:04 2001:db8::1/64 +check ovn-nbctl lrp-add R2 R2_ls-transfer 00:00:00:02:03:05 2001:db8::2/64 + +check ovn-nbctl lsp-add ls-transfer ls-transfer_r1 -- \ + set Logical_Switch_Port ls-transfer_r1 type=router \ + options:router-port=R1_ls-transfer addresses=\"router\" +check ovn-nbctl lsp-add ls-transfer ls-transfer_r2 -- \ + set Logical_Switch_Port ls-transfer_r2 type=router \ + options:router-port=R2_ls-transfer addresses=\"router\" + +# Static mac binding entries +check ovn-nbctl static-mac-binding-add R1_ls-transfer 2001:db8::2 00:00:00:02:03:05 +check ovn-nbctl static-mac-binding-add R2_ls-transfer 2001:db8::1 00:00:00:02:03:04 + +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8::2]) +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8::1]) + +# Create logical port ls1-lp1 in ls1 +check ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" + +# Create logical port ls2-lp1 in ls2 +check ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +# Allow some time for ovn-northd and ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Packet to send. +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ + UDP(sport=53, dport=4369)") +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# Packet to Expect +# The TTL should be decremented by 2. +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ + UDP(sport=53, dport=4369)") +echo ${expected} > expected +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 +]) + +# Disable the ls2-lp1 port. +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 +]) + +# Send the same packet again and it should not be delivered +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# The 2nd packet sent shound not be received. +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, LRs connected via LS, IPv4 over IPv6, ECMP]) +AT_SKIP_IF([test $HAVE_SCAPY = no]) +ovn_start + +# Logical network: +# Two LRs - R1 and R2 that are connected to ls-transfer1 and lr-transfer2 in +# 2001:db8:1::/64 and 2001:db8:2::/64 +# network. R1 has a switchs ls1 (192.168.1.0/24) connected to it. +# R2 has ls2 (172.16.1.0/24) connected to it. + +ls1_lp1_mac="f0:00:00:01:02:03" +rp_ls1_mac="00:00:00:01:02:03" +rp_ls2_mac="00:00:00:01:02:04" +ls2_lp1_mac="f0:00:00:01:02:04" + +ls1_lp1_ip="192.168.1.2" +ls2_lp1_ip="172.16.1.2" + +check ovn-nbctl lr-add R1 +check ovn-nbctl lr-add R2 + +check ovn-nbctl ls-add ls1 +check ovn-nbctl ls-add ls2 +check ovn-nbctl ls-add ls-transfer1 +check ovn-nbctl ls-add ls-transfer2 + +# Connect ls1 to R1 +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 192.168.1.1/24 + +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ + options:router-port=ls1 addresses=\"$rp_ls1_mac\" + +# Connect ls2 to R2 +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 172.16.1.1/24 + +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ + options:router-port=ls2 addresses=\"$rp_ls2_mac\" + +# Connect R1 to R2 (ls-transfer1) +check ovn-nbctl lrp-add R1 R1_ls-transfer1 00:00:00:02:03:04 2001:db8:1::1/64 +check ovn-nbctl lrp-add R2 R2_ls-transfer1 00:00:00:02:03:05 2001:db8:1::2/64 + +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r1 -- \ + set Logical_Switch_Port ls-transfer1_r1 type=router \ + options:router-port=R1_ls-transfer1 addresses=\"router\" +check ovn-nbctl lsp-add ls-transfer1 ls-transfer1_r2 -- \ + set Logical_Switch_Port ls-transfer1_r2 type=router \ + options:router-port=R2_ls-transfer1 addresses=\"router\" + +# Connect R1 to R2 (ls-transfer2) +check ovn-nbctl lrp-add R1 R1_ls-transfer2 00:00:00:02:03:14 2001:db8:2::1/64 +check ovn-nbctl lrp-add R2 R2_ls-transfer2 00:00:00:02:03:15 2001:db8:2::2/64 + +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r1 -- \ + set Logical_Switch_Port ls-transfer2_r1 type=router \ + options:router-port=R1_ls-transfer2 addresses=\"router\" +check ovn-nbctl lsp-add ls-transfer2 ls-transfer2_r2 -- \ + set Logical_Switch_Port ls-transfer2_r2 type=router \ + options:router-port=R2_ls-transfer2 addresses=\"router\" + +AT_CHECK([ovn-nbctl lr-route-add R1 "0.0.0.0/0" 2001:db8:1::2]) +AT_CHECK([ovn-nbctl --ecmp lr-route-add R1 "0.0.0.0/0" 2001:db8:2::2]) +AT_CHECK([ovn-nbctl lr-route-add R2 "0.0.0.0/0" 2001:db8:1::1]) +AT_CHECK([ovn-nbctl --ecmp lr-route-add R2 "0.0.0.0/0" 2001:db8:2::1]) + +# Create logical port ls1-lp1 in ls1 +check ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" + +# Create logical port ls2-lp1 in ls2 +check ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +# Allow some time for ovn-northd and ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Packet to send. +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=64)/ \ + UDP(sport=53, dport=4369)") +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# Packet to Expect +# The TTL should be decremented by 2. +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ + IP(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', ttl=62)/ \ + UDP(sport=53, dport=4369)") +echo ${expected} > expected +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [1 +]) + +# Disable the ls2-lp1 port. +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "reg0 == 172.16.1.2" | wc -l], [0], [0 +]) + +# Send the same packet again and it should not be delivered +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# The 2nd packet sent shound not be received. +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP +]) + +OVN_FOR_EACH_NORTHD([ +AT_SETUP([2 HVs, 2 LS, 1 lport/LS, 2 peer LRs, IPv6 over IPv4]) +AT_SKIP_IF([test $HAVE_SCAPY = no]) +ovn_start + +# Logical network: +# Two LRs - R1 and R2 that are connected to each other as peers in 10.0.0.0/24 +# network. R1 has a switchs ls1 (2001:db8:1::/64) connected to it. +# R2 has ls2 (2001:db8:2::/64) connected to it. + +ls1_lp1_mac="f0:00:00:01:02:03" +rp_ls1_mac="00:00:00:01:02:03" +rp_ls2_mac="00:00:00:01:02:04" +ls2_lp1_mac="f0:00:00:01:02:04" + +ls1_lp1_ip="2001:db8:1::2" +ls2_lp1_ip="2001:db8:2::2" + +check ovn-nbctl lr-add R1 +check ovn-nbctl lr-add R2 + +check ovn-nbctl ls-add ls1 +check ovn-nbctl ls-add ls2 + +# Connect ls1 to R1 +check ovn-nbctl lrp-add R1 ls1 $rp_ls1_mac 2001:db8:1::1/64 + +check ovn-nbctl lsp-add ls1 rp-ls1 -- set Logical_Switch_Port rp-ls1 type=router \ + options:router-port=ls1 addresses=\"$rp_ls1_mac\" + +# Connect ls2 to R2 +check ovn-nbctl lrp-add R2 ls2 $rp_ls2_mac 2001:db8:2::1/64 + +check ovn-nbctl lsp-add ls2 rp-ls2 -- set Logical_Switch_Port rp-ls2 type=router \ + options:router-port=ls2 addresses=\"$rp_ls2_mac\" + +# Connect R1 to R2 +check ovn-nbctl lrp-add R1 R1_R2 00:00:00:02:03:04 10.0.0.1/24 peer=R2_R1 +check ovn-nbctl lrp-add R2 R2_R1 00:00:00:02:03:05 10.0.0.2/24 peer=R1_R2 + +AT_CHECK([ovn-nbctl lr-route-add R1 "::/0" 10.0.0.2]) +AT_CHECK([ovn-nbctl lr-route-add R2 "::/0" 10.0.0.1]) + +# Create logical port ls1-lp1 in ls1 +check ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "$ls1_lp1_mac $ls1_lp1_ip" + +# Create logical port ls2-lp1 in ls2 +check ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "$ls2_lp1_mac $ls2_lp1_ip" + +# Create two hypervisor and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +check ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv2 +as hv2 +check ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +check ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +OVN_POPULATE_ARP + +# Allow some time for ovn-northd and ovn-controller to catch up. +wait_for_ports_up +check ovn-nbctl --wait=hv sync + +# Packet to send. +packet=$(fmt_pkt "Ether(dst='${rp_ls1_mac}', src='${ls1_lp1_mac}')/ \ + IPv6(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', hlim=64)/ \ + UDP(sport=53, dport=4369)") +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# Packet to Expect +# The TTL should be decremented by 2. +expected=$(fmt_pkt "Ether(dst='${ls2_lp1_mac}', src='${rp_ls2_mac}')/ \ + IPv6(src='${ls1_lp1_ip}', dst='${ls2_lp1_ip}', hlim=62)/ \ + UDP(sport=53, dport=4369)") +echo ${expected} > expected +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [1 +]) + +# Disable the ls2-lp1 port. +check ovn-nbctl --wait=hv set logical_switch_port ls2-lp1 enabled=false + +AT_CHECK([ovn-sbctl dump-flows | grep lr_in_arp_resolve | \ +grep "xxreg0 == 2001:db8:2::2" | wc -l], [0], [0 +]) + +# Send the same packet again and it should not be delivered +check as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 "$packet" + +# The 2nd packet sent shound not be received. +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +OVN_CLEANUP([hv1],[hv2]) + +AT_CLEANUP +]) diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index d45be75c7..86a3b5966 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -4591,11 +4591,9 @@ 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) { prefix = normalize_ipv6_prefix_str(ctx->argv[2]); - v6_prefix = true; } if (!prefix) { ctl_error(ctx, "bad prefix argument: %s", ctx->argv[2]); @@ -4606,15 +4604,15 @@ nbctl_lr_route_add(struct ctl_context *ctx) if (is_discard_route) { next_hop = xasprintf("discard"); } else { - next_hop = v6_prefix - ? normalize_ipv6_addr_str(ctx->argv[3]) - : normalize_ipv4_addr_str(ctx->argv[3]); + next_hop = normalize_ipv4_addr_str(ctx->argv[3]); + if (!next_hop) { + next_hop = normalize_ipv6_addr_str(ctx->argv[3]); + } if (!next_hop) { /* check if it is a output port. */ error = lrp_by_name_or_uuid(ctx, ctx->argv[3], true, &out_lrp); if (error) { - ctl_error(ctx, "bad %s nexthop argument: %s", - v6_prefix ? "IPv6" : "IPv4", ctx->argv[3]); + ctl_error(ctx, "bad nexthop argument: %s", ctx->argv[3]); free(error); goto cleanup; }