On 12/17/24 5:02 PM, Felix Huettner wrote:
> On Tue, Dec 17, 2024 at 04:41:44PM +0100, [email protected] 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 <[email protected]>
>>>>
>>>> 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 <[email protected]>
>>>
>>> Felix, is this email address correct?
> 
> Hi Dumitru,
> 
> we have since switched our mail domain, so now it is
> [email protected]
> However the old one will work for the next years so we can also keep
> this one.
> 

Ack.

>>>
>>>> Signed-off-by: Martin Kalcok <[email protected]>
>>>> Co-authored-by: Martin Kalcok <[email protected]>
>>>> ---
>>>
>>> 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
>>>
>>
> 

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to