On 2/11/26 11:12 AM, Ales Musil wrote:
> On Tue, Feb 10, 2026 at 12:24 PM Dumitru Ceara via dev <
> [email protected]> wrote:
> 
>> Commit 9c3ae6f27475 ("northd: Add ECMP symmetric replies for egress.")
>> tried to add ECMP-symmetric-reply semantics to traffic forwarded on
>> sessions initiating from "behind" the static route, i.e., traffic
>> hitting the route in the original direction.
>>
>> However, it decided to commit the session to conntrack only when we
>> finally received reply traffic on the session.
>>
>> As shown in https://issues.redhat.com/browse/FDP-1983, if the hash
>> function of the ECMP route changes in between the original SYN and the
>> last ACK of the 3-way-handshake of a TCP session (e.g., if ECMP paths
>> are added to the route) then traffic in the original direction might
>> incorrectly migrate and be forwarded via a different next-hop than the
>> original SYN.
>>
>> In order to fix this, we now commit the traffic on the first SYN instead
>> of waiting for replies.  That happens in a new logical router pipeline
>> stage 'lr_in_ecmp_stateful_egr', just after 'lr_in_arp_request' where
>> which we store the (resolved) next-hop MAC and packet out-port in
>> conntrack for traffic forwarded by ECMP-symmetric-reply static routes
>> (in the original direction).
>>
>> The system-ovn.at tests also had to be updated because, due to the fact
>> that traffic was committed to conntrack only on the first
>> non-session-setup reply, the tuples were "wrong".  I.e., the conntrack
>> session looked as if it had been created from "outside" the static
>> route.
>>
>> Fixes: 9c3ae6f27475 ("northd: Add ECMP symmetric replies for egress.")
>> Reported-at: https://issues.redhat.com/browse/FDP-1983
>> Signed-off-by: Dumitru Ceara <[email protected]>
>> ---
>>
> 
> Hi Dumitru,
> 
> thank you for the patch, just one tiny nit below.
> 

Hi Ales,

Thanks for the review!

> 
>>  lib/ovn-util.c          |  4 +--
>>  northd/northd.c         | 54 ++++++++++++++++++++++++++++++++++++-----
>>  northd/northd.h         |  2 ++
>>  northd/ovn-northd.8.xml | 18 +++++++++++---
>>  tests/ovn-northd.at     | 45 ++++++++++++++++++++++++++--------
>>  tests/system-ovn.at     | 12 ++++++---
>>  6 files changed, 110 insertions(+), 25 deletions(-)
>>
>> diff --git a/lib/ovn-util.c b/lib/ovn-util.c
>> index 8a065e3c29..2df51dc7ef 100644
>> --- a/lib/ovn-util.c
>> +++ b/lib/ovn-util.c
>> @@ -968,8 +968,8 @@ ip_address_and_port_from_lb_key(const char *key, char
>> **ip_address,
>>   *
>>   * NOTE: If OVN_NORTHD_PIPELINE_CSUM is updated make sure to double check
>>   * whether an update of OVN_INTERNAL_MINOR_VER is required. */
>> -#define OVN_NORTHD_PIPELINE_CSUM "4239189964 11014"
>> -#define OVN_INTERNAL_MINOR_VER 11
>> +#define OVN_NORTHD_PIPELINE_CSUM "45472499 11094"
>> +#define OVN_INTERNAL_MINOR_VER 12
>>
>>  /* Returns the OVN version. The caller must free the returned value. */
>>  char *
>> diff --git a/northd/northd.c b/northd/northd.c
>> index 2df205ec23..9b74fd4667 100644
>> --- a/northd/northd.c
>> +++ b/northd/northd.c
>> @@ -201,6 +201,9 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
>>  #define REGBIT_DHCP_RELAY_REQ_CHK "reg9[7]"
>>  #define REGBIT_DHCP_RELAY_RESP_CHK "reg9[8]"
>>  #define REGBIT_NEXTHOP_IS_IPV4    "reg9[9]"
>> +/* Register bit to store whether we need to commit this ECMP symmetric
>> + * reply processed packet after resolving its next-hop MAC address. */
>> +#define REGBIT_NEEDS_ECMP_STATEFUL_COMMIT "reg9[10]"
>>
>>  /* Register to store the eth address associated to a router port for
>> packets
>>   * received in S_ROUTER_IN_ADMISSION.
>> @@ -12345,6 +12348,7 @@ add_ecmp_symmetric_reply_flows(struct lflow_table
>> *lflows,
>>       * ds_put_cstr() call. The previous contents are needed.
>>       */
>>      ds_put_cstr(&match, " && (ct.new || ct.est)");
>> +
>>
> 
> nit: Unrelated change.
> 
> 

Ah, my bad.

>>      ds_put_format(&actions,
>>              "ct_commit { ct_label.ecmp_reply_eth = eth.src; "
>>              "ct_mark.ecmp_reply_port = %" PRId64 ";}; "
>> @@ -12499,13 +12503,16 @@ build_ecmp_route_flow(struct lflow_table *lflows,
>>                        "%s = %s; "
>>                        "eth.src = %s; "
>>                        "outport = %s; "
>> -                      REGBIT_NEXTHOP_IS_IPV4" = %d; "
>> -                      "next;",
>> +                      REGBIT_NEXTHOP_IS_IPV4" = %d; ",
>>                        is_ipv4_nexthop ? REG_SRC_IPV4 : REG_SRC_IPV6,
>>                        route->lrp_addr_s,
>>                        route->out_port->lrp_networks.ea_s,
>>                        route->out_port->json_key,
>>                        is_ipv4_nexthop);
>> +        if (route->ecmp_symmetric_reply) {
>> +            ds_put_cstr(&actions, REGBIT_NEEDS_ECMP_STATEFUL_COMMIT " =
>> 1; ");
>> +        }
>> +        ds_put_cstr(&actions, "next;");
>>          ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING_ECMP, 100,
>>                        ds_cstr(&match), ds_cstr(&actions), lflow_ref,
>>                        WITH_HINT(route->source_hint));
>> @@ -15954,7 +15961,7 @@ build_arp_request_flows_for_lrouter(
>>                        "ip6.dst = %s; "
>>                        "nd.target = %s; "
>>                        "output; "
>> -                      "}; output;", ETH_ADDR_ARGS(eth_dst), sn_addr_s,
>> +                      "}; next;", ETH_ADDR_ARGS(eth_dst), sn_addr_s,
>>                        route->nexthop);
>>
>>          ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 200,
>> @@ -15974,7 +15981,7 @@ build_arp_request_flows_for_lrouter(
>>                    "arp.tpa = " REG_NEXT_HOP_IPV4 "; "
>>                    "arp.op = 1; " /* ARP request */
>>                    "output; "
>> -                  "}; output;",
>> +                  "}; next;",
>>                    lflow_ref,
>> WITH_CTRL_METER(copp_meter_get(COPP_ARP_RESOLVE,
>>                                                              od->nbr->copp,
>>
>>  meter_groups)));
>> @@ -15984,11 +15991,40 @@ build_arp_request_flows_for_lrouter(
>>                    "nd_ns { "
>>                    "nd.target = " REG_NEXT_HOP_IPV6 "; "
>>                    "output; "
>> -                  "}; output;",
>> +                  "}; next;",
>>                    lflow_ref,
>> WITH_CTRL_METER(copp_meter_get(COPP_ND_NS_RESOLVE,
>>                                                              od->nbr->copp,
>>
>>  meter_groups)));
>> -    ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;",
>> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "next;",
>> +                  lflow_ref);
>> +}
>> +
>> +static void
>> +build_ecmp_stateful_egr_flows_for_lrouter_port(
>> +    struct ovn_port *op, struct lflow_table *lflows,
>> +    struct ds *match,  struct ds *actions,
>> +    struct lflow_ref *lflow_ref)
>> +{
>> +    ds_clear(match);
>> +    ds_put_format(match, REGBIT_NEEDS_ECMP_STATEFUL_COMMIT " == 1 && ip
>> && "
>> +                  "outport == %s", op->json_key);
>> +
>> +    ds_clear(actions);
>> +    ds_put_format(actions,
>> +                  "ct_commit { ct_label.ecmp_reply_eth = eth.dst; "
>> +                              "ct_mark.ecmp_reply_port = %" PRId64 ";}; "
>> +                  "output;",
>> +                  op->sb->tunnel_key);
>> +    ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ECMP_STATEFUL_EGR, 100,
>> +                  ds_cstr(match), ds_cstr(actions), lflow_ref);
>> +}
>> +
>> +static void
>> +build_ecmp_stateful_egr_flows_for_lrouter(
>> +        struct ovn_datapath *od, struct lflow_table *lflows,
>> +        struct lflow_ref *lflow_ref)
>> +{
>> +    ovn_lflow_add(lflows, od, S_ROUTER_IN_ECMP_STATEFUL_EGR, 0, "1",
>> "output;",
>>                    lflow_ref);
>>  }
>>
>> @@ -19039,6 +19075,8 @@ build_lswitch_and_lrouter_iterate_by_lr(struct
>> ovn_datapath *od,
>>                                          &lsi->actions,
>>                                          lsi->meter_groups,
>>                                          od->datapath_lflows);
>> +    build_ecmp_stateful_egr_flows_for_lrouter(od, lsi->lflows,
>> +                                              od->datapath_lflows);
>>      build_lrouter_network_id_flows(od, lsi->lflows, &lsi->match,
>>                                     &lsi->actions, od->datapath_lflows);
>>      build_misc_local_traffic_drop_flows_for_lrouter(od, lsi->lflows,
>> @@ -19129,6 +19167,10 @@ build_lswitch_and_lrouter_iterate_by_lrp(struct
>> ovn_port *op,
>>      build_lrouter_routing_protocol_redirect(op, lsi->lflows, &lsi->match,
>>                                              &lsi->actions, op->lflow_ref,
>>                                              lsi->ls_ports,
>> lsi->bfd_ports);
>> +    build_ecmp_stateful_egr_flows_for_lrouter_port(op, lsi->lflows,
>> +                                                   &lsi->match,
>> +                                                   &lsi->actions,
>> +                                                   op->lflow_ref);
>>  }
>>
>>  static void *
>> diff --git a/northd/northd.h b/northd/northd.h
>> index f812656af2..9158f3d532 100644
>> --- a/northd/northd.h
>> +++ b/northd/northd.h
>> @@ -602,6 +602,8 @@ ovn_datapath_is_stale(const struct ovn_datapath *od)
>>      PIPELINE_STAGE(ROUTER, IN,  GW_REDIRECT,     25,
>> "lr_in_gw_redirect")     \
>>      PIPELINE_STAGE(ROUTER, IN,  NETWORK_ID,      26, "lr_in_network_id")
>>     \
>>      PIPELINE_STAGE(ROUTER, IN,  ARP_REQUEST,     27,
>> "lr_in_arp_request")     \
>> +    PIPELINE_STAGE(ROUTER, IN,  ECMP_STATEFUL_EGR, 28,
>>     \
>> +                                "lr_in_ecmp_stateful_egr")
>>     \
>>                                                                        \
>>      /* Logical router egress stages. */                               \
>>      PIPELINE_STAGE(ROUTER, OUT, CHECK_DNAT_LOCAL,   0,
>>    \
>> diff --git a/northd/ovn-northd.8.xml b/northd/ovn-northd.8.xml
>> index 279d81f35d..ca37d4e398 100644
>> --- a/northd/ovn-northd.8.xml
>> +++ b/northd/ovn-northd.8.xml
>> @@ -5507,8 +5507,9 @@ icmp6 {
>>
>>      <p>
>>        In the common case where the Ethernet destination has been
>> resolved, this
>> -      table outputs the packet.  Otherwise, it composes and sends an ARP
>> or
>> -      IPv6 Neighbor Solicitation request.  It holds the following flows:
>> +      table advances the packet to the next table.  Otherwise, it
>> composes and
>> +      sends an ARP or IPv6 Neighbor Solicitation request.  It holds the
>> +      following flows:
>>      </p>
>>
>>      <ul>
>> @@ -5577,10 +5578,21 @@ nd_ns {
>>
>>        <li>
>>          Known MAC address.  A priority-0 flow with match <code>1</code>
>> has
>> -        actions <code>output;</code>.
>> +        actions <code>next;</code>.
>>        </li>
>>      </ul>
>>
>> +    <h3>Ingress Table 27: ECMP symmetric reply processing for egress</h3>

This was a copy/paste error.  It should've been "Table 28".

>> +    <p>
>> +      This table contains logical flows that commit IP traffic forwarded
>> by
>> +      ECMP symmetric reply static routes in the "route direction", that
>> is,
>> +      for sessions initiated from behind such routes.  These flows can be
>> hit
>> +      only on gateway routers, the only type of routers that supports ECMP
>> +      symmetric reply routes.  As the egress port of the traffic needs to
>> be
>> +      stored in conntrack for these sessions, one logical flow is added
>> for
>> +      each logical router port.
>> +    </p>
>> +
>>      <h3>Egress Table 0: Check DNAT local </h3>
>>
>>      <p>
>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
>> index f3454a3631..aeb07f1dde 100644
>> --- a/tests/ovn-northd.at
>> +++ b/tests/ovn-northd.at
>> @@ -7139,10 +7139,15 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows |
>> ovn_strip_lflows], [0], [dnl
>>
>>  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"; reg9[[9]]
>> = 1; 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; reg9[[10]] = 1; next;)
>>    table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]]
>> == 0), action=(next;)
>>  ])
>>
>> +AT_CHECK([grep -e "lr_in_ecmp_stateful_egr" lr0flows | ovn_strip_lflows],
>> [0], [dnl
>> +  table=??(lr_in_ecmp_stateful_egr), priority=0    , match=(1),
>> action=(output;)
>> +  table=??(lr_in_ecmp_stateful_egr), priority=100  , match=(reg9[[10]] ==
>> 1 && ip && outport == "lr0-public"), action=(ct_commit {
>> ct_label.ecmp_reply_eth = eth.dst; ct_mark.ecmp_reply_port = 1;}; output;)
>> +])
>> +
>>  check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1
>> 192.168.0.20
>>  check_row_count ECMP_Nexthop 2
>>  check_column 192.168.0.10 ECMP_Nexthop nexthop nexthop=192.168.0.10
>> @@ -7159,8 +7164,8 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows |
>> ovn_strip_lflows], [0], [dnl
>>  ])
>>  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"; 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=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; reg9[[10]] = 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; reg9[[10]] = 1; next;)
>>    table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]]
>> == 0), action=(next;)
>>  ])
>>
>> @@ -7174,6 +7179,16 @@ AT_CHECK([grep -e "lr_in_arp_resolve.*ecmp"
>> lr0flows | ovn_strip_lflows], [0], [
>>    table=??(lr_in_arp_resolve  ), priority=200  ,
>> match=(ct_mark.ecmp_reply_port == 1), action=(push(xxreg1); xxreg1 =
>> ct_label; eth.dst = xxreg1[[32..79]]; pop(xxreg1); next;)
>>  ])
>>
>> +AT_CHECK([grep -e "lr_in_ecmp_stateful_egr" lr0flows | ovn_strip_lflows],
>> [0], [dnl
>> +  table=??(lr_in_ecmp_stateful_egr), priority=0    , match=(1),
>> action=(output;)
>> +  table=??(lr_in_ecmp_stateful_egr), priority=100  , match=(reg9[[10]] ==
>> 1 && ip && outport == "lr0-public"), action=(ct_commit {
>> ct_label.ecmp_reply_eth = eth.dst; ct_mark.ecmp_reply_port = 1;}; output;)
>> +])
>> +
>> +# Check that reroute policies reset ecmp-symmetric-reply behavior when
>> hit.
>> +check ovn-nbctl --wait=sb                                               \
>> +    -- lr-policy-add lr0  20 "ip4.src == 10.0.0.4" reroute 192.168.0.10 \
>> +    -- lr-policy-add lr0  10 "ip4.src == 10.0.0.3" reroute
>> 192.168.0.10,192.168.0.20
>> +
>>  # add ecmp route with wrong nexthop
>>  check ovn-nbctl --wait=sb --ecmp-symmetric-reply lr-route-add lr0 1.0.0.1
>> 192.168.1.20
>>  check_row_count ECMP_Nexthop 2
>> @@ -7191,11 +7206,16 @@ AT_CHECK([grep -w "lr_in_ip_routing" lr0flows |
>> ovn_strip_lflows], [0], [dnl
>>  ])
>>  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"; 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=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; reg9[[10]] = 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; reg9[[10]] = 1; next;)
>>    table=??(lr_in_ip_routing_ecmp), priority=150  , match=(reg8[[0..15]]
>> == 0), action=(next;)
>>  ])
>>
>> +AT_CHECK([grep -e "lr_in_ecmp_stateful_egr" lr0flows | ovn_strip_lflows],
>> [0], [dnl
>> +  table=??(lr_in_ecmp_stateful_egr), priority=0    , match=(1),
>> action=(output;)
>> +  table=??(lr_in_ecmp_stateful_egr), priority=100  , match=(reg9[[10]] ==
>> 1 && ip && outport == "lr0-public"), action=(ct_commit {
>> ct_label.ecmp_reply_eth = eth.dst; ct_mark.ecmp_reply_port = 1;}; output;)
>> +])
>> +
>>  check ovn-nbctl lr-route-del lr0
>>  wait_row_count nb:Logical_Router_Static_Route 0
>>  check_row_count ECMP_Nexthop 0
>> @@ -7241,6 +7261,11 @@ AT_CHECK([grep -e "(lr_in_ip_routing   ).*3.3.0.0"
>> lr0flows | sed 's/table=../ta
>>    table=??(lr_in_ip_routing   ), priority=133  , match=(reg7 == 0 &&
>> ip4.dst == 3.3.0.0/16 && udp), action=(ip.ttl--; flags.loopback = 1;
>> reg8[[0..15]] = 1; reg8[[16..31]] = select(values=(1, 2);
>> hash_fields="ip_dst,ip_proto,ip_src,udp_dst,udp_src");)
>>  ])
>>
>> +AT_CHECK([grep -e "lr_in_ecmp_stateful_egr" lr0flows | ovn_strip_lflows],
>> [0], [dnl
>> +  table=??(lr_in_ecmp_stateful_egr), priority=0    , match=(1),
>> action=(output;)
>> +  table=??(lr_in_ecmp_stateful_egr), priority=100  , match=(reg9[[10]] ==
>> 1 && ip && outport == "lr0-public"), action=(ct_commit {
>> ct_label.ecmp_reply_eth = eth.dst; ct_mark.ecmp_reply_port = 1;}; output;)
>> +])
>> +
>>  OVN_CLEANUP_NORTHD
>>  AT_CLEANUP
>>  ])
>> @@ -7289,11 +7314,11 @@ AT_CHECK([grep -e "lr_in_arp_resolve" lr0flows |
>> ovn_strip_lflows], [0], [dnl
>>  ])
>>
>>  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 && reg9[[9]] == 0), action=(nd_ns { nd.target = xxreg0;
>> output; }; output;)
>> -  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst ==
>> 00:00:00:00:00:00 && reg9[[9]] == 1), 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=200  , match=(eth.dst ==
>> 00:00:00:00:00:00 && reg9[[9]] == 0 && 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 && reg9[[9]] == 0 && 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;)
>> +  table=??(lr_in_arp_request  ), priority=0    , match=(1), action=(next;)
>> +  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst ==
>> 00:00:00:00:00:00 && reg9[[9]] == 0), action=(nd_ns { nd.target = xxreg0;
>> output; }; next;)
>> +  table=??(lr_in_arp_request  ), priority=100  , match=(eth.dst ==
>> 00:00:00:00:00:00 && reg9[[9]] == 1), action=(arp { eth.dst =
>> ff:ff:ff:ff:ff:ff; arp.spa = reg5; arp.tpa = reg0; arp.op = 1; output; };
>> next;)
>> +  table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst ==
>> 00:00:00:00:00:00 && reg9[[9]] == 0 && 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; }; next;)
>> +  table=??(lr_in_arp_request  ), priority=200  , match=(eth.dst ==
>> 00:00:00:00:00:00 && reg9[[9]] == 0 && 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; }; next;)
>>  ])
>>
>>  OVN_CLEANUP_NORTHD
>> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
>> index 82b7e7db5b..c732af9b91 100644
>> --- a/tests/system-ovn.at
>> +++ b/tests/system-ovn.at
>> @@ -6679,7 +6679,8 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2
>> 172.16.0.1 | FORMAT_PING], \
>>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x401020500000000 |
>> FORMAT_CT(172.16.0.1) | \
>>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
>>  sed -e 's/mark=[[0-9]]*/mark=<cleared>/' | sort], [0], [dnl
>>
>> -tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=10.0.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x401020500000000,protoinfo=(state=<cleared>)
>>
>> +icmp,orig=(src=10.0.0.2,dst=172.16.0.1,id=<cleared>,type=8,code=0),reply=(src=172.16.0.1,dst=10.0.0.2,id=<cleared>,type=0,code=0),zone=<cleared>,mark=<cleared>,labels=0x401020500000000
>>
>> +tcp,orig=(src=10.0.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.0.1,dst=10.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x401020500000000,protoinfo=(state=<cleared>)
>>  ])
>>
>>  # Now remove one ECMP route and check that traffic is still being
>> conntracked.
>> @@ -6695,7 +6696,8 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2
>> 172.16.0.1 | FORMAT_PING], \
>>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x401020500000000 |
>> FORMAT_CT(172.16.0.1) | \
>>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
>>  sed -e 's/mark=[[0-9]]*/mark=<cleared>/' | sort], [0], [dnl
>>
>> -tcp,orig=(src=172.16.0.1,dst=10.0.0.2,sport=<cleared>,dport=<cleared>),reply=(src=10.0.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x401020500000000,protoinfo=(state=<cleared>)
>>
>> +icmp,orig=(src=10.0.0.2,dst=172.16.0.1,id=<cleared>,type=8,code=0),reply=(src=172.16.0.1,dst=10.0.0.2,id=<cleared>,type=0,code=0),zone=<cleared>,mark=<cleared>,labels=0x401020500000000
>>
>> +tcp,orig=(src=10.0.0.2,dst=172.16.0.1,sport=<cleared>,dport=<cleared>),reply=(src=172.16.0.1,dst=10.0.0.2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x401020500000000,protoinfo=(state=<cleared>)
>>  ])
>>
>>  OVN_CLEANUP_CONTROLLER([hv1])
>> @@ -6904,7 +6906,8 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2
>> fd07::1 | FORMAT_PING], \
>>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 |
>> FORMAT_CT(fd07::1) | \
>>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
>>  sed -e 's/mark=[[0-9]]*/mark=<cleared>/' | sort], [0], [dnl
>>
>> -tcp,orig=(src=fd07::1,dst=fd01::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd07::1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000,protoinfo=(state=<cleared>)
>>
>> +icmpv6,orig=(src=fd01::2,dst=fd07::1,id=<cleared>,type=128,code=0),reply=(src=fd07::1,dst=fd01::2,id=<cleared>,type=129,code=0),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000
>>
>> +tcp,orig=(src=fd01::2,dst=fd07::1,sport=<cleared>,dport=<cleared>),reply=(src=fd07::1,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000,protoinfo=(state=<cleared>)
>>  ])
>>
>>  # Now remove one ECMP route and check that traffic is still being
>> conntracked.
>> @@ -6920,7 +6923,8 @@ NS_CHECK_EXEC([alice1], [ping -q -c 3 -i 0.3 -w 2
>> fd07::1 | FORMAT_PING], \
>>  AT_CHECK([ovs-appctl dpctl/dump-conntrack | grep 0x1001020400000000 |
>> FORMAT_CT(fd07::1) | \
>>  sed -e 's/zone=[[0-9]]*/zone=<cleared>/' |
>>  sed -e 's/mark=[[0-9]]*/mark=<cleared>/' | sort], [0], [dnl
>>
>> -tcp,orig=(src=fd07::1,dst=fd01::2,sport=<cleared>,dport=<cleared>),reply=(src=fd01::2,dst=fd07::1,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000,protoinfo=(state=<cleared>)
>>
>> +icmpv6,orig=(src=fd01::2,dst=fd07::1,id=<cleared>,type=128,code=0),reply=(src=fd07::1,dst=fd01::2,id=<cleared>,type=129,code=0),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000
>>
>> +tcp,orig=(src=fd01::2,dst=fd07::1,sport=<cleared>,dport=<cleared>),reply=(src=fd07::1,dst=fd01::2,sport=<cleared>,dport=<cleared>),zone=<cleared>,mark=<cleared>,labels=0x1001020400000000,protoinfo=(state=<cleared>)
>>  ])
>>
>>  OVN_CLEANUP_CONTROLLER([hv1])
>> --
>> 2.52.0
>>
>> _______________________________________________
>> dev mailing list
>> [email protected]
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>
>>
> With that addressed:
> Acked-by: Ales Musil <[email protected]>
> 

I fixed up the two minor things above and applied the patch to main,
25.09 and 25.03.

Thanks,
Dumitru

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

Reply via email to