Hi Numan, I cherry-picked the patch to branch-26.03. It didn't apply cleanly due to ovn-logical-flows.7.rst being removed in that branch, but I resolved the conflict (simply dropped the doc changes) and the rest applied without issues.
I'm submitting the backport patch to the mailing list now. For branch-25.09, the conflicts are more significant (northd.c has structural differences), so I'll skip that one for now. Thanks JayGue On Tue, Jun 9, 2026 at 11:32 AM Numan Siddique <[email protected]> wrote: > > > On Mon, Jun 8, 2026 at 8:02 PM jay <[email protected]> wrote: > >> Hi Numan, >> >> >> Thank you so much for merging the patch and adding me to AUTHORS.rst >> >> >> Yes, I would like this patch to be backported. >> >> I discovered this issue in an OpenStack 2025.2 environment, so having it >> in branch-25.09 and branch-26.03 would be very helpful. >> >> >> Please let me know if you need me to prepare the backport patches, or if >> there's anything else I can help with. >> > > I'm not sure if they apply cleanly. So it would be great if you can > backport and run the tests and let me know if they apply cleanly and tests > pass. > If not, can you please prepare the backport patches and submit ? > Please include the branch names in the subject-prefix. > > Thanks > Numan > > >> Thanks, >> >> JayGue >> >> On Mon, Jun 8, 2026 at 11:36 PM Numan Siddique <[email protected]> wrote: >> >>> >>> >>> On Mon, May 25, 2026 at 8:01 PM JayGue Lee <[email protected]> wrote: >>> >>>> Load_Balancer health checks were silently failing for baremetal pool >>>> members whose backend Logical_Switch_Port has type=external on a >>>> Logical_Switch that has a localnet port (typical for Neutron and the >>>> ovn-octavia-provider baremetal driver on a provider VLAN). >>>> >>>> When the controller emits a health-check probe it stamps the source >>>> MAC with $svc_monitor_mac (or the LRP MAC) and sends it out the LRP. >>>> The reply from the baremetal member re-enters br-int via the localnet >>>> port, so at S_SWITCH_IN_L2_LKUP MFF_LOG_INPORT carries the localnet >>>> LSP's tunnel_key, not the backend LSP's. The per-backend reply >>>> lflow's match "inport == <backend> && ..." never fires, and even the >>>> generic per-LS "eth.dst == $svc_monitor_mac" lflow that calls >>>> handle_svc_check(inport) feeds pinctrl the localnet tunnel_key, >>>> which pinctrl_find_svc_monitor() cannot resolve to a service monitor. >>>> The CMS therefore concludes the member is down. >>>> >>>> Fix the issue inside the logical switch ingress pipeline at the >>>> earliest possible stage so that every downstream lflow (HM reply, >>>> ARP responder, DHCP, FDB, ACL, ...) observes a sensible inport for >>>> the external LSP. >>>> >>>> For each external LSP that lives on a switch with a localnet port, >>>> install a new lflow at S_SWITCH_IN_CHECK_PORT_SEC priority 75: >>>> match : inport == <localnet_port> && eth.src == <external_mac> >>>> action: flags.localnet = 1; inport = <external_lsp>; next; >>>> >>>> The match is specific enough (combined eth.src + localnet inport) >>>> that it does not affect any other localnet traffic. Setting >>>> flags.localnet here preserves the semantics that >>>> build_lswitch_from_localnet_op() and build_lswitch_learn_fdb_op() >>>> previously provided at S_SWITCH_IN_LOOKUP_FDB, which would no longer >>>> fire for external-LSP-sourced packets after the rewrite. >>>> >>>> With this rewrite in place: >>>> >>>> * The original per-backend HM reply lflow at S_SWITCH_IN_L2_LKUP >>>> ("inport == <backend>" / "handle_svc_check(inport);") works >>>> without modification. >>>> * The generic per-LS "eth.dst == $svc_monitor_mac" lflow uses the >>>> backend LSP's tunnel_key when calling handle_svc_check(inport), >>>> so pinctrl_find_svc_monitor() succeeds for the >>>> $svc_monitor_mac-sourced probe case as well. >>>> >>>> Two follow-on adjustments are required because they depended on >>>> MFF_LOG_INPORT being the localnet port for external-LSP traffic: >>>> >>>> * build_lswitch_dhcp_options_and_response() now calls >>>> build_dhcpv4/v6_options_flows() with op (the external LSP) as >>>> the inport for is_external, eliminating the previous >>>> per-localnet-port enumeration. >>>> * build_drop_arp_nd_flows_for_unbound_router_ports() now matches >>>> on op->json_key (the external LSP) instead of the localnet >>>> port. >>>> >>>> tests/ovn-northd.at gains a unit test that exercises a regular VIF >>>> backend on a tenant LS and a type=external backend on a provider LS >>>> with a localnet, asserting the original HM reply lflow forms and the >>>> new inport-rewrite lflow. An additional scenario deletes the >>>> localnet port and verifies the inport-rewrite lflow is removed. >>>> >>>> tests/ovn.at "external logical port" is updated to assert that the >>>> DHCPv4/v6 controller OF flows installed for an external port carry >>>> reg14 == external_lsp_key (the rewritten inport), not the localnet >>>> port's key. >>>> >>>> Signed-off-by: JayGue Lee <[email protected]> >>>> Acked-by: Numan Siddique <[email protected]> >>>> >>> >>> Thanks for addressing the comments. >>> >>> I added you to the AUTHORS.rst file and applied this patch to the main. >>> >>> Do you want this patch to be backported ? >>> >>> Thanks >>> Numan >>> >>> >>>> --- >>>> Documentation/ref/ovn-logical-flows.7.rst | 8 ++ >>>> NEWS | 12 +++ >>>> northd/northd.c | 97 +++++++++++++----- >>>> tests/ovn-northd.at | 116 ++++++++++++++++++++++ >>>> tests/ovn.at | 17 ++-- >>>> 5 files changed, 219 insertions(+), 31 deletions(-) >>>> >>>> diff --git a/Documentation/ref/ovn-logical-flows.7.rst >>>> b/Documentation/ref/ovn-logical-flows.7.rst >>>> index b60f860..2db593c 100644 >>>> --- a/Documentation/ref/ovn-logical-flows.7.rst >>>> +++ b/Documentation/ref/ovn-logical-flows.7.rst >>>> @@ -43,6 +43,14 @@ Ingress table 0 contains these logical flows: >>>> want to prevent duplicate replies and advertisements. This is >>>> achieved by a >>>> rule with priority 80 that sets ``REGBIT_PORT_SEC_DROP" = 1; >>>> next;"``. >>>> >>>> +- For each ``type=external`` logical port on a switch that has a >>>> localnet port, >>>> + a priority 75 flow matches on ``inport == <localnet_port> && eth.src >>>> == >>>> + <external_mac>`` and applies ``flags.localnet = 1; inport = >>>> <external_lsp>; >>>> + next;``. This rewrites ``inport`` from the localnet port to the >>>> external LSP >>>> + so that all downstream stages observe the correct logical inport for >>>> traffic >>>> + originating from the baremetal member. >>>> + >>>> + >>>> - For each (enabled) vtep logical port, a priority 70 flow is added >>>> which >>>> matches on all packets and applies the action >>>> ``next(pipeline=ingress, >>>> table=S_SWITCH_IN_L3_LKUP) = 1;`` to skip most stages of ingress >>>> pipeline and >>>> diff --git a/NEWS b/NEWS >>>> index e34a219..d64179a 100644 >>>> --- a/NEWS >>>> +++ b/NEWS >>>> @@ -16,6 +16,18 @@ Post v26.03.0 >>>> static routes as higher-priority than connected routes, which in >>>> turn led >>>> to changes in administrative distance for specific route types. >>>> Please see >>>> the "Route Administrative Distance" section of the ovn-northd >>>> manpage. >>>> + - Fixed Load_Balancer health check replies failing silently for >>>> + baremetal pool members whose backend LSP is type=external on a >>>> + Logical_Switch that has a localnet port. ovn-northd now installs >>>> + an early inport-rewrite lflow at ls_in_check_port_sec that >>>> + substitutes MFF_LOG_INPORT from the localnet port to the external >>>> + LSP when eth.src matches the external port's MAC, so every >>>> + downstream pipeline stage (including the per-backend HM reply >>>> + lflow and the generic per-LS svc_monitor_mac lflow) observes >>>> + inport == <external_lsp> and pinctrl_find_svc_monitor() succeeds. >>>> + The DHCP and unbound-router ARP/ND drop lflows for external >>>> + ports were updated to key on the external LSP's inport >>>> + accordingly. >>>> >>>> OVN v26.03.0 - xxx xx xxxx >>>> -------------------------- >>>> diff --git a/northd/northd.c b/northd/northd.c >>>> index 0ea7c1b..9bbbd1d 100644 >>>> --- a/northd/northd.c >>>> +++ b/northd/northd.c >>>> @@ -8870,8 +8870,7 @@ build_lb_health_check_response_lflows( >>>> const struct ovn_lb_datapaths *lb_dps, >>>> const struct ovn_datapaths *lr_datapaths, >>>> const struct shash *meter_groups, >>>> - struct ds *match, >>>> - struct ds *action) >>>> + struct ds *match) >>>> { >>>> /* For each LB backend that is monitored by a source_ip belonging >>>> * to a real LRP, install rule that punts service check replies to >>>> the >>>> @@ -8918,7 +8917,6 @@ build_lb_health_check_response_lflows( >>>> } >>>> >>>> ds_clear(match); >>>> - ds_clear(action); >>>> >>>> /* icmp6 type 1 and icmp4 type 3 are included in the >>>> match, because >>>> * the controller is using them to detect unreachable >>>> ports. */ >>>> @@ -10108,6 +10106,13 @@ >>>> build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, >>>> { >>>> struct ds match = DS_EMPTY_INITIALIZER; >>>> >>>> + /* With the early inport rewrite installed at >>>> + * S_SWITCH_IN_CHECK_PORT_SEC, packets from the external LSP arrive >>>> + * here with MFF_LOG_INPORT == op (the external LSP), not the >>>> + * localnet port (which was the value at table 0). The match is >>>> + * therefore keyed on op->json_key. The 'port' (localnet) argument >>>> + * is still used for incremental processing tagging through >>>> + * WITH_IO_PORT below. */ >>>> for (size_t i = 0; i < op->n_lsp_addrs; i++) { >>>> struct ovn_port *rp; >>>> VECTOR_FOR_EACH (&op->od->router_ports, rp) { >>>> @@ -10118,7 +10123,7 @@ >>>> build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, >>>> &match, "inport == %s && eth.src == %s" >>>> " && !is_chassis_resident(%s)" >>>> " && arp.tpa == %s && arp.op == 1", >>>> - port->json_key, >>>> + op->json_key, >>>> op->lsp_addrs[i].ea_s, op->json_key, >>>> rp->lsp_addrs[k].ipv4_addrs[l].addr_s); >>>> ovn_lflow_add(lflows, op->od, >>>> S_SWITCH_IN_EXTERNAL_PORT, >>>> @@ -10134,7 +10139,7 @@ >>>> build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, >>>> &match, "inport == %s && eth.src == %s" >>>> " && !is_chassis_resident(%s)" >>>> " && nd_ns && ip6.dst == {%s, %s} && nd.target >>>> == %s", >>>> - port->json_key, >>>> + op->json_key, >>>> op->lsp_addrs[i].ea_s, op->json_key, >>>> rp->lsp_addrs[k].ipv6_addrs[l].addr_s, >>>> rp->lsp_addrs[k].ipv6_addrs[l].sn_addr_s, >>>> @@ -10152,7 +10157,7 @@ >>>> build_drop_arp_nd_flows_for_unbound_router_ports(struct ovn_port *op, >>>> &match, "inport == %s && eth.src == %s" >>>> " && eth.dst == %s" >>>> " && !is_chassis_resident(%s)", >>>> - port->json_key, >>>> + op->json_key, >>>> op->lsp_addrs[i].ea_s, rp->lsp_addrs[k].ea_s, >>>> op->json_key); >>>> ovn_lflow_add(lflows, op->od, >>>> S_SWITCH_IN_EXTERNAL_PORT, 100, >>>> @@ -10855,24 +10860,20 @@ >>>> build_lswitch_dhcp_options_and_response(struct ovn_port *op, >>>> } >>>> >>>> for (size_t i = 0; i < op->n_lsp_addrs; i++) { >>>> - if (is_external) { >>>> - struct ovn_port *lp; >>>> - VECTOR_FOR_EACH (&op->od->localnet_ports, lp) { >>>> - build_dhcpv4_options_flows( >>>> - op, &op->lsp_addrs[i], lp, is_external, >>>> - meter_groups, lflows, op->lflow_ref); >>>> - build_dhcpv6_options_flows( >>>> - op, &op->lsp_addrs[i], lp, is_external, >>>> - meter_groups, lflows, op->lflow_ref); >>>> - } >>>> - } else { >>>> - build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op, >>>> - is_external, meter_groups, >>>> - lflows, op->lflow_ref); >>>> - build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op, >>>> - is_external, meter_groups, >>>> - lflows, op->lflow_ref); >>>> - } >>>> + /* For both regular VIF and type=external LSPs we pass the LSP >>>> + * itself (op) as the inport. For external ports, the inport >>>> + * rewrite added in build_lswitch_external_lsp_inport_rewrite() >>>> + * at S_SWITCH_IN_CHECK_PORT_SEC has already substituted >>>> + * MFF_LOG_INPORT from the localnet port to the external LSP by >>>> + * the time we reach S_SWITCH_IN_DHCP_OPTIONS. So a single set >>>> + * of DHCP lflows keyed on the external LSP is enough; we no >>>> + * longer need to enumerate every localnet port. */ >>>> + build_dhcpv4_options_flows(op, &op->lsp_addrs[i], op, >>>> + is_external, meter_groups, >>>> + lflows, op->lflow_ref); >>>> + build_dhcpv6_options_flows(op, &op->lsp_addrs[i], op, >>>> + is_external, meter_groups, >>>> + lflows, op->lflow_ref); >>>> } >>>> } >>>> >>>> @@ -10951,6 +10952,51 @@ build_lswitch_external_port(struct ovn_port >>>> *op, >>>> } >>>> } >>>> >>>> +/* For each external LSP on a switch with a localnet port, rewrite >>>> + * MFF_LOG_INPORT from the localnet port to the external LSP when >>>> + * eth.src matches one of the external port's MACs. This makes >>>> + * downstream stages observe inport == <external_lsp> for traffic >>>> + * originating from that baremetal MAC. Intentionally placed at >>>> + * S_SWITCH_IN_CHECK_PORT_SEC priority 75 so it fires before the >>>> + * existing priority-70 generic port-sec rules but does not collide >>>> + * with the priority-100 disabled-port drop. */ >>>> +static void >>>> +build_lswitch_external_lsp_inport_rewrite(struct ovn_port *op, >>>> + struct lflow_table *lflows, >>>> + struct ds *match, >>>> + struct ds *actions) >>>> +{ >>>> + ovs_assert(op->nbsp); >>>> + if (!lsp_is_external(op->nbsp)) { >>>> + return; >>>> + } >>>> + if (!ls_has_localnet_port(op->od)) { >>>> + return; >>>> + } >>>> + /* Also set flags.localnet here. The existing >>>> S_SWITCH_IN_LOOKUP_FDB >>>> + * lflow generated by build_lswitch_learn_fdb_op() sets >>>> + * flags.localnet = 1 only when inport == <localnet> at that table; >>>> + * once we have rewritten inport to the external LSP, that match no >>>> + * longer fires. Copy the assignment into our rewrite action so >>>> + * downstream stages keyed on flags.localnet == 1 continue to work >>>> + * for the external LSP case. */ >>>> + struct ovn_port *lp; >>>> + VECTOR_FOR_EACH (&op->od->localnet_ports, lp) { >>>> + for (size_t i = 0; i < op->n_lsp_addrs; i++) { >>>> + ds_clear(match); >>>> + ds_clear(actions); >>>> + ds_put_format(match, "inport == %s && eth.src == %s", >>>> + lp->json_key, op->lsp_addrs[i].ea_s); >>>> + ds_put_format(actions, >>>> + "flags.localnet = 1; inport = %s; next;", >>>> + op->json_key); >>>> + ovn_lflow_add(lflows, op->od, S_SWITCH_IN_CHECK_PORT_SEC, >>>> 75, >>>> + ds_cstr(match), ds_cstr(actions), >>>> + op->lflow_ref); >>>> + } >>>> + } >>>> +} >>>> + >>>> /* Ingress table 30: Destination lookup, broadcast and multicast >>>> handling >>>> * (priority 70 - 100). */ >>>> static void >>>> @@ -13679,7 +13725,7 @@ build_lrouter_flows_for_lb(struct >>>> ovn_lb_datapaths *lb_dps, >>>> >>>> build_lb_health_check_response_lflows( >>>> lflows, lb, lb_vip, &lb->vips_nb[i], lb_dps, lr_datapaths, >>>> - meter_groups, match, action); >>>> + meter_groups, match); >>>> >>>> if (!build_empty_lb_event_flow(lb_vip, lb, match, action)) { >>>> continue; >>>> @@ -19547,6 +19593,7 @@ build_lswitch_and_lrouter_iterate_by_lsp(struct >>>> ovn_port *op, >>>> meter_groups, actions, >>>> match); >>>> build_lswitch_dhcp_options_and_response(op, lflows, meter_groups); >>>> build_lswitch_external_port(op, lflows); >>>> + build_lswitch_external_lsp_inport_rewrite(op, lflows, match, >>>> actions); >>>> build_lswitch_icmp_packet_toobig_admin_flows(op, lflows, match, >>>> actions); >>>> build_lswitch_ip_unicast_lookup(op, lflows, actions, >>>> match); >>>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at >>>> index 26a19bd..b0f86f7 100644 >>>> --- a/tests/ovn-northd.at >>>> +++ b/tests/ovn-northd.at >>>> @@ -1687,6 +1687,122 @@ OVN_CLEANUP_NORTHD >>>> AT_CLEANUP >>>> ]) >>>> >>>> +OVN_FOR_EACH_NORTHD_NO_HV_PARALLELIZATION([ >>>> +AT_SETUP([Load balancer health check reply lflow for type=external >>>> backend on localnet LS]) >>>> +ovn_start >>>> + >>>> +# Topology: >>>> +# >>>> +# lr0 --(lr0-sw0)-- sw0 (regular tenant LS, 10.0.0.0/24) >>>> +# `-- vm-port (type="", regular VIF backend) >>>> +# >>>> +# lr0 --(lr0-prov)-- prov (provider LS with localnet) >>>> +# |-- prov-localnet (type=localnet) >>>> +# `-- bm-port (type=external, baremetal pool >>>> member) >>>> +# >>>> +# A baremetal LB pool member's LSP is type=external; replies to HM >>>> probes >>>> +# re-enter br-int via the localnet port, so MFF_LOG_INPORT carries the >>>> +# localnet LSP's tunnel_key and the original >>>> +# "inport == <bm-port> && ... ; handle_svc_check(inport);" >>>> +# reply lflow never matches. pinctrl_find_svc_monitor() is keyed on >>>> +# (dp_key, port_key) where port_key = backend LSP's tunnel_key, so >>>> +# MFF_LOG_INPORT must hold that tunnel_key when the controller op >>>> fires. >>>> +# >>>> +# Fix: install an inport-rewrite lflow at S_SWITCH_IN_CHECK_PORT_SEC >>>> +# priority 75 keyed on (inport == <localnet> && eth.src == <bm_mac>) >>>> +# which assigns: >>>> +# flags.localnet = 1; inport = "<bm-port>"; next; >>>> +# Once that fires, every downstream stage (including the original >>>> +# per-backend handle_svc_check lflow at S_SWITCH_IN_L2_LKUP and the >>>> +# generic per-LS svc_monitor_mac lflow) sees inport == <bm-port> and >>>> +# works without further modification. >>>> + >>>> +check ovn-nbctl lr-add lr0 >>>> +check ovn-nbctl lrp-add lr0 lr0-sw0 00:00:00:00:01:01 10.0.0.1/24 >>>> +check ovn-nbctl lrp-add lr0 lr0-prov 00:00:00:00:02:01 10.0.50.1/24 >>>> + >>>> +check ovn-nbctl ls-add sw0 >>>> +check ovn-nbctl --wait=sb lsp-add sw0 sw0-lr0 \ >>>> + -- lsp-set-type sw0-lr0 router \ >>>> + -- lsp-set-options sw0-lr0 router-port=lr0-sw0 \ >>>> + -- lsp-set-addresses sw0-lr0 router >>>> +check ovn-nbctl --wait=sb lsp-add sw0 vm-port \ >>>> + -- lsp-set-addresses vm-port "00:00:00:00:01:02 10.0.0.10" >>>> + >>>> +check ovn-nbctl ls-add prov >>>> +check ovn-nbctl --wait=sb lsp-add prov prov-lr0 \ >>>> + -- lsp-set-type prov-lr0 router \ >>>> + -- lsp-set-options prov-lr0 router-port=lr0-prov \ >>>> + -- lsp-set-addresses prov-lr0 router >>>> +check ovn-nbctl --wait=sb lsp-add prov prov-localnet \ >>>> + -- lsp-set-type prov-localnet localnet \ >>>> + -- lsp-set-options prov-localnet network_name=physnet1 \ >>>> + -- lsp-set-addresses prov-localnet unknown >>>> +check ovn-nbctl --wait=sb lsp-add prov bm-port \ >>>> + -- lsp-set-type bm-port external \ >>>> + -- lsp-set-addresses bm-port "00:00:00:00:02:0a 10.0.50.10" >>>> + >>>> +check ovn-sbctl chassis-add hv1 geneve 127.0.0.1 >>>> +check ovn-sbctl lsp-bind vm-port hv1 >>>> +check ovn-sbctl lsp-bind bm-port hv1 >>>> + >>>> +# LB has both a regular-VIF backend on sw0 and a type=external backend >>>> on prov. >>>> +check ovn-nbctl lb-add lb1 192.168.0.10:80 10.0.0.10:80,10.0.50.10:80 >>>> tcp >>>> +check ovn-nbctl --wait=sb set load_balancer lb1 \ >>>> + ip_port_mappings:10.0.0.10=vm-port:10.0.0.1 >>>> +check ovn-nbctl --wait=sb set load_balancer lb1 \ >>>> + ip_port_mappings:10.0.50.10=bm-port:10.0.50.1 >>>> + >>>> +check_uuid ovn-nbctl --wait=sb -- --id=@hc create >>>> Load_Balancer_Health_Check \ >>>> + vip="192.168.0.10\:80" -- add Load_Balancer lb1 health_check @hc >>>> + >>>> +check ovn-nbctl lr-lb-add lr0 lb1 >>>> +check ovn-nbctl ls-lb-add sw0 lb1 >>>> +check ovn-nbctl ls-lb-add prov lb1 >>>> +check ovn-nbctl --wait=sb sync >>>> + >>>> +# Regular backend on sw0: original "inport == <vm-port>" / >>>> "handle_svc_check(inport);" >>>> +# behavior unchanged. >>>> +AT_CAPTURE_FILE([sw0_lflows]) >>>> +ovn-sbctl dump-flows sw0 | grep ls_in_l2_lkup | grep handle_svc_check \ >>>> + > sw0_lflows >>>> +AT_CHECK([cat sw0_lflows | ovn_strip_lflows], [0], [dnl >>>> + table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == >>>> $svc_monitor_mac && (tcp || icmp || icmp6)), >>>> action=(handle_svc_check(inport);) >>>> + table=??(ls_in_l2_lkup ), priority=110 , match=(inport == >>>> "vm-port" && ip4.dst == 10.0.0.1 && ip4.src == 10.0.0.10 && eth.dst == >>>> 00:00:00:00:01:01 && tcp.src == 80), action=(handle_svc_check(inport);) >>>> +]) >>>> + >>>> +# type=external backend on prov (localnet LS): the per-backend reply >>>> +# lflow keeps the ORIGINAL inport-based match because the >>>> +# inport-rewrite at S_SWITCH_IN_CHECK_PORT_SEC has already substituted >>>> +# MFF_LOG_INPORT to <bm-port> by the time the packet reaches L2_LKUP. >>>> +AT_CAPTURE_FILE([prov_lflows]) >>>> +ovn-sbctl dump-flows prov | grep ls_in_l2_lkup | grep handle_svc_check >>>> \ >>>> + > prov_lflows >>>> +AT_CHECK([cat prov_lflows | ovn_strip_lflows], [0], [dnl >>>> + table=??(ls_in_l2_lkup ), priority=110 , match=(eth.dst == >>>> $svc_monitor_mac && (tcp || icmp || icmp6)), >>>> action=(handle_svc_check(inport);) >>>> + table=??(ls_in_l2_lkup ), priority=110 , match=(inport == >>>> "bm-port" && ip4.dst == 10.0.50.1 && ip4.src == 10.0.50.10 && eth.dst == >>>> 00:00:00:00:02:01 && tcp.src == 80), action=(handle_svc_check(inport);) >>>> +]) >>>> + >>>> +# v6 inport-rewrite lflow at ls_in_check_port_sec priority 75: turns >>>> +# (inport == <prov-localnet> && eth.src == <bm_mac>) into >>>> +# (flags.localnet = 1; inport = "<bm-port>"; next;) >>>> +AT_CAPTURE_FILE([prov_rewrite_lflows]) >>>> +ovn-sbctl dump-flows prov | grep ls_in_check_port_sec \ >>>> + | grep 'priority=75 ' | grep 'inport = ' \ >>>> + > prov_rewrite_lflows >>>> +AT_CHECK([cat prov_rewrite_lflows | ovn_strip_lflows], [0], [dnl >>>> + table=??(ls_in_check_port_sec), priority=75 , match=(inport == >>>> "prov-localnet" && eth.src == 00:00:00:00:02:0a), action=(flags.localnet = >>>> 1; inport = "bm-port"; next;) >>>> +]) >>>> + >>>> +# Delete the localnet port and verify the inport-rewrite lflow >>>> disappears. >>>> +check ovn-nbctl --wait=sb lsp-del prov-localnet >>>> +AT_CHECK([ovn-sbctl dump-flows prov | grep ls_in_check_port_sec \ >>>> + | grep 'priority=75 ' | grep 'inport = '], [1]) >>>> + >>>> +OVN_CLEANUP_NORTHD >>>> +AT_CLEANUP >>>> +]) >>>> + >>>> OVN_FOR_EACH_NORTHD_NO_HV([ >>>> AT_SETUP([Load balancer VIP in NAT entries]) >>>> AT_SKIP_IF([test $HAVE_PYTHON = no]) >>>> diff --git a/tests/ovn.at b/tests/ovn.at >>>> index 0c3d419..7d71717 100644 >>>> --- a/tests/ovn.at >>>> +++ b/tests/ovn.at >>>> @@ -21484,6 +21484,10 @@ grep controller | grep tp_src=546 | grep \ >>>> check ovn-nbctl --wait=hv lsp-add-localnet-port ls1 ln-public phys >>>> >>>> ln_public_key=$(fetch_column Port_Binding tunnel_key >>>> logical_port=ln-public) >>>> +# DHCP lflows for external ports now match on the external LSP's inport >>>> +# (after the inport-rewrite at table 0), so the OF flow's reg14 value >>>> is >>>> +# the external LSP's tunnel_key, not the localnet's. >>>> +lp_ext1_key=$(fetch_column Port_Binding tunnel_key >>>> logical_port=ls1-lp_ext1) >>>> >>>> # The ls1-lp_ext1 should be bound to hv1 as only hv1 is part of the >>>> # ha chassis group. >>>> @@ -21495,13 +21499,13 @@ wait_for_ports_up ls1-lp_ext1 >>>> (ovn-sbctl dump-flows lr0; ovn-sbctl dump-flows ls1) > sbflows >>>> as hv1 ovs-ofctl dump-flows br-int > brintflows >>>> AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | \ >>>> -grep controller | grep "0a.00.00.06" | grep reg14=0x$ln_public_key | \ >>>> +grep controller | grep "0a.00.00.06" | grep reg14=0x$lp_ext1_key | \ >>>> wc -l], [0], [1 >>>> ]) >>>> AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | \ >>>> grep controller | grep tp_src=546 | grep \ >>>> "ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.06" | \ >>>> -grep reg14=0x$ln_public_key | wc -l], [0], [1 >>>> +grep reg14=0x$lp_ext1_key | wc -l], [0], [1 >>>> ]) >>>> >>>> # There should be no DHCPv4/v6 flows for ls1-lp_ext1 on hv2 >>>> @@ -21745,15 +21749,16 @@ ovn-sbctl find port_binding >>>> logical_port=ls1-lp_ext1 >>>> wait_row_count Port_Binding 1 logical_port=ls1-lp_ext1 >>>> chassis=$hv2_uuid >>>> wait_for_ports_up ls1-lp_ext1 >>>> >>>> -# There should be OF flows for DHCP4/v6 for the ls1-lp_ext1 port in hv2 >>>> +# There should be OF flows for DHCP4/v6 for the ls1-lp_ext1 port in >>>> hv2. >>>> +# reg14 carries the external LSP's tunnel_key (after inport rewrite). >>>> AT_CHECK([as hv2 ovs-ofctl dump-flows br-int | \ >>>> -grep controller | grep "0a.00.00.06" | grep reg14=0x$ln_public_key | \ >>>> +grep controller | grep "0a.00.00.06" | grep reg14=0x$lp_ext1_key | \ >>>> wc -l], [0], [1 >>>> ]) >>>> AT_CHECK([as hv2 ovs-ofctl dump-flows br-int | \ >>>> grep controller | grep tp_src=546 | grep \ >>>> "ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.06" | \ >>>> -grep reg14=0x$ln_public_key | wc -l], [0], [1 >>>> +grep reg14=0x$lp_ext1_key | wc -l], [0], [1 >>>> ]) >>>> >>>> # There should be no DHCPv4/v6 flows for ls1-lp_ext1 on hv1 >>>> @@ -21763,7 +21768,7 @@ grep controller | grep "0a.00.00.06" | wc -l], >>>> [0], [0 >>>> AT_CHECK([as hv1 ovs-ofctl dump-flows br-int | \ >>>> grep controller | grep tp_src=546 | grep \ >>>> "ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.06" | \ >>>> -grep reg14=0x$ln_public_key | wc -l], [0], [0 >>>> +grep reg14=0x$lp_ext1_key | wc -l], [0], [0 >>>> ]) >>>> >>>> # Send DHCPDISCOVER again for hv1/ext1. The DHCP response should come >>>> from >>>> -- >>>> 2.49.0 >>>> >>>> _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
