On 5/18/26 5:47 AM, jay wrote:
> Hi Numan,
> 

Hi JayGue Lee, Numan,

> Thanks for the detailed feedback. You are right — v5 does not handle
> the case where ovn-controller stamps the probe with $svc_monitor_mac
> and routes it through the LRP (i.e. inport at ls_in_l2_lkup is the
> localnet port, not the backend LSP). I missed that scenario.
> 
> I have implemented the alternative approach you suggested (rewriting
> inport at S_SWITCH_IN_CHECK_PORT_SEC) and sent it as v6:
> 
> 
> https://patchwork.ozlabs.org/project/ovn/patch/[email protected]/
> 
> For each external LSP on a localnet switch, v6 installs:
> 
>   table=ls_in_check_port_sec, priority=75,
>     match=(inport == <localnet> && eth.src == <ext_lsp_mac>),
>     action=(flags.localnet = 1; inport = <ext_lsp>; next;)
> 
> This makes the original per-backend HM reply lflow at ls_in_l2_lkup
> work without modification, which is the elegant part.
> 
> However, the early inport rewrite has side-effects on downstream
> stages that previously relied on inport being the localnet port for
> external LSP traffic. To keep existing functionality intact, v6 also
> needed:
> 
>   1. DHCP (ls_in_dhcp_options / ls_in_dhcp_response):
>      The external-LSP path no longer iterates localnet_ports to set
>      inport; it now passes the external LSP directly (since inport
>      already *is* the external LSP after the rewrite).
> 
>   2. ARP/ND drop flows (build_drop_arp_nd_flows_for_unbound_router_ports):
>      Match clauses changed from inport == <localnet> to
>      inport == <ext_lsp> for the same reason.
> 
>   3. flags.localnet preservation:
>      The rewrite action explicitly sets flags.localnet = 1 because the
>      existing S_SWITCH_IN_LOOKUP_FDB lflow that normally sets this flag
>      matches on inport == <localnet>, which no longer fires after the
>      rewrite.
> 
> CI result: the only failure is the known-flaky
> "system-test-userspace 201- unstable" job, which has been failing on
> unrelated patches throughout 2026 (e.g. 597e4ac, 18d7827). All other
> 25 jobs pass.
> 
> Both v5 and v6 fix the original bug. The trade-off:
> 
>   - v5: self-contained change at ls_in_l2_lkup only; uses
>     flags.localnet + outport trick; does not touch other stages.
>   - v6: structurally cleaner (single inport rewrite benefits all
>     downstream lflows); but the blast radius is larger — changes touch
>     DHCP, ARP/ND, and FDB logic.
> 
> I am happy to go with whichever approach you and the other maintainers
> prefer. Let me know what you think.
> 

I'll try to have a look at v6 in the near future - at a quick glance
over the discussion above it kind of makes sense to me; I guess it's OK
to move future discussions on that version of the patch.

Regards,
Dumitru

> Thanks
> JayGue Lee
> 
> On Sat, May 16, 2026 at 7:46 AM Numan Siddique <[email protected]> wrote:
> 
>> On Mon, May 11, 2026 at 11:40 PM JayGue Lee <[email protected]> wrote:
>>>
>>>
>>> build_lb_health_check_response_lflows() builds a per-backend
>>> service_monitor reply punt lflow with the match:
>>>
>>>     inport == "<backend_lsp>" && ip4.dst == <svc_mon_src_ip> &&
>>>     ip4.src == <backend_ip>   && eth.dst == <svc_mon_lrp_mac> &&
>>>     tcp.src == <backend_port>
>>>
>>> When the backend's LSP is type=external on a Logical_Switch that has
>>> a localnet port (the typical configuration produced by Neutron /
>>> ovn-octavia-provider for baremetal pool members on a provider VLAN),
>>> the probe reply re-enters br-int through the localnet port.  At the
>>> time the lflow is evaluated MFF_LOG_INPORT therefore carries the
>>> localnet LSP's tunnel_key, not the backend LSP's, and
>>> 'inport == "<backend_lsp>"' never matches.
>>>
>>> Even if the match is rewritten to 'inport == "<localnet_lsp>"',
>>> 'handle_svc_check(inport);' alone is not sufficient: pinctrl indexes
>>> its svc_monitors_map by (dp_key, port_key) where port_key equals the
>>> backend LSP's tunnel_key (sync_svc_monitors() in controller/pinctrl.c
>>> sets svc_mon->port_key = pb->tunnel_key from
>>> sb_svc_mon->logical_port).  pinctrl_find_svc_monitor() therefore
>>> requires MFF_LOG_INPORT to hold the backend LSP's tunnel_key when
>>> the controller op fires, otherwise the lookup fails silently and
>>> Service_Monitor.status stays 'offline' indefinitely even though the
>>> backend is fully reachable on the wire.
>>>
>>> Detect type=external backends on a Logical_Switch with a localnet
>>> port and substitute a localnet-aware reply lflow:
>>>
>>>   match  : flags.localnet == 1 && eth.src == <bm_mac> &&
>>>            ip{4,6}.dst == <svc_mon_src_ip> &&
>>>            ip{4,6}.src == <backend_ip> &&
>>>            eth.dst == <svc_mon_lrp_mac> && <proto-tail>
>>>   action : outport = "<backend_lsp>";
>>>            handle_svc_check(outport);
>>>            outport = "";
>>>
>>> flags.localnet is set in S_SWITCH_IN_LOOKUP_FDB on packets arriving
>>> from any localnet port (commit e6ffc4919c388, "northd: Enable ARP/ND
>>> responder for localnet-sourced requests."), so it identifies the
>>> re-entry path independently of which localnet LSP the packet came
>>> through (a switch may have several).  eth.src disambiguates which
>>> baremetal backend on that localnet.
>>>
>>> handle_svc_check(<field>) saves MFF_LOG_INPORT, moves <field> into
>>> it, runs the controller op, and restores MFF_LOG_INPORT
>>> (encode_HANDLE_SVC_CHECK() in lib/actions.c).  Borrowing
>>> MFF_LOG_OUTPORT to carry the backend LSP's tunnel_key into
>>> MFF_LOG_INPORT for the punt is exactly what pinctrl needs and is the
>>> same semantics as the manual workaround flow operators install today
>>> ('actions=set_field:<bm_tunnel_key>->reg14, controller(...)').
>>> 'outport = "";' clears MFF_LOG_OUTPORT afterwards so the cleared
>>> value does not leak into egress and reflect the reply back to the
>>> backend.
>>>
>>> Regular (non-external) backends are unchanged.
>>>
>>> Suggested-by: Numan Siddique <[email protected]>
>>> Signed-off-by: JayGue Lee <[email protected]>
>>
>> Thanks for the patch.
>>
>> Looks to me your solution is incomplete.
>>
>> With LB health checks,  CMS/user can configure to use a private IP
>> from the subnet
>> or the router port IP as the source IP for the health checks generated
>> by ovn-controller.
>>
>> The code you've added only handles the scenario when the router port
>> IP is configured
>> to use as the source ip.  The test case you added confirms that.
>>
>> It is also possible that the user can configure some other private IP
>> from the same subnet in which case
>> ovn-controller will use the $svc_monitor_mac (which is generated and
>> stored in nb_global)
>> as the source mac when it sends out the health check packet.  For this
>> scenario the existing logical flow
>> (which is shown below) will be matched and ovn-controller ignore it as
>> the inport is localnet port and not external port.
>>
>> There is one more inline comment below.  Please see.
>>
>>
>> Instead of the approach you have taken in this patch which is to add
>> logical flows which checks on
>> "flags.localnet == 1" how about we do the following ?
>>
>>    - In the logical switch pipeline just after port security checks
>> we can add another stage (or in the apply port security stage itself)
>>      which matches on localnet port and eth.src == <external_port_mac>
>> and rewrites the inport to the actual external port.
>>
>> Eg.
>>    if there is an external port "foo_external_port" with mac
>> "00:00:01:00:00:50" then add the flow like below
>>
>>   table=0 (ls_in_check_port_sec), priority=70   , match=(inport ==
>> "localnet-port" && eth.src == 00:00:01:00:00:50), action=(inport =
>> "foo_external_port"; next;)
>>
>> I think if we do this, then we don't have to match on localnet port
>> and eth.src down the line in other pipeline stages of the logical
>> switch.
>> And the existing logical flows for the handle_svc_check() would work
>> without any issues.
>>
>> The downside of this approach is that it will break DHCP for external
>> ports (and maybe a few others).  I think those can be fixed.
>>
>> I am not forcing this approach, but checking if it makes sense to do
>> this way.  If not we can continue with your patch and address the
>> comments which I provided above.
>>
>> @Dumitru Ceara @Ales Musil @Mark Michelson @Han Zhou and others,  do
>> you have any thoughts on this ?
>>
>> @JayGue Lee   Either you can wait for comments from others or address
>> the review comments and submit v6 meanwhile.
>>
>>
>> Thanks
>> Numan
>>
>>> ---
>>> v5 (this revision):
>>>   - Test-only fix.  In v3/v4 the new ovn-northd.at unit test
>>>     used 'check ovn-nbctl ... -- --id=@hc create
>>>     Load_Balancer_Health_Check ...' which caused the testsuite
>>>     to fail because the create command prints the new row's
>>>     UUID to stdout while 'check' expects an empty stdout (see
>>>     Documentation/topics/test-development.rst).  Replaced with
>>>     'check_uuid', matching the convention used elsewhere in
>>>     the same file (e.g. tests/ovn-northd.at:1506).  No
>>>     functional change.  Verified locally on a Linux VM:
>>>     227/227 ovn-northd.at unit tests PASS, including the new
>>>     687/688 (parallelization=yes/no).
>>> v4:
>>>   - Address 0-day Robot checkpatch warnings on v3: two
>>>     ds_put_format() lines in build_lb_health_check_response_lflows()
>>>     were 80 chars after the new 'else' indentation pushed them over
>>>     the 79-char limit.  Fixed by breaking the format string onto a
>>>     new line, matching the style already used in the new
>>>     'external_via_localnet' branch.  No functional change.
>>> v3:
>>>   - Address review feedback from Numan Siddique on the original
>>>     bug report thread (ovs-discuss).  Numan suggested fixing the
>>>     existing reply lflow rather than adding a new one, by matching
>>>     on inport == <localnet_port> when the backend is type=external.
>>>   - Restructure the patch accordingly: instead of emitting a second
>>>     lflow at the same priority, the existing per-backend reply lflow
>>>     is now a single ovn_lflow_add() whose match/action are branched
>>>     when the backend is type=external on a Logical_Switch with a
>>>     localnet port.  This is a smaller and conceptually cleaner change
>>>     than v2 (no duplicate lflows on the same datapath, no priority
>>>     overlap to reason about).
>>>   - Match uses 'flags.localnet == 1 && eth.src == <bm_mac>' instead
>>>     of 'inport == "<localnet_lsp>"'.  flags.localnet is now set in
>>>     S_SWITCH_IN_LOOKUP_FDB by commit e6ffc4919c388 ("northd: Enable
>>>     ARP/ND responder for localnet-sourced requests."), so a single
>>>     predicate covers Logical_Switches that have multiple localnet
>>>     LSPs (which is common in Neutron provider deployments).  eth.src
>>>     disambiguates which baremetal backend on that localnet.
>>>   - Action piece preserved from v2 ('outport = "<backend_lsp>";
>>>     handle_svc_check(outport); outport = "";').  Match-only fixes do
>>>     not work because pinctrl_find_svc_monitor() (controller/pinctrl.c)
>>>     indexes svc_monitors_map by (dp_key, port_key) where port_key is
>>>     the backend LSP's tunnel_key, so MFF_LOG_INPORT must hold that
>>>     tunnel_key when the controller op fires.  This is also what the
>>>     manual workaround flow operators install today
>>>     ('actions=set_field:<bm_tunnel_key>->reg14, controller(...)') does
>>>     in production, confirmed against a live br-int dump.
>>>   - Use ls_has_localnet_port() helper added by commit 9699f8922c02747
>>>     ("northd: Add ls_has_localnet_port() helper.") instead of the
>>>     open-coded vector_is_empty(&od->localnet_ports) check.
>>>   - Updated commit subject to "Fix HM reply lflow for type=external
>>>     backends on localnet LS." to reflect that v3 modifies the
>>>     existing lflow rather than generating a new one.
>>>   - Test rewritten: a single Logical_Router peers with two switches
>>>     (a regular tenant LS with a VM backend, and a provider LS with a
>>>     localnet port and a type=external backend) and a single LB binds
>>>     both backends.  The test asserts the regular backend keeps the
>>>     original 'inport == "<vm-port>" / handle_svc_check(inport);'
>>>     behavior and the type=external backend gets the localnet-aware
>>>     match and the outport-borrowing action.
>>> v2:
>>>   - Replaced the ovn_port_find() call (which crashed on
>>>     peer_switch_od->ports because that hmap is keyed on dp_node, not
>>>     key_node) with an inline HMAP_FOR_EACH (dp_node, ...) loop.
>>>
>>>  NEWS                |  6 +++
>>>  northd/northd.c     | 96 ++++++++++++++++++++++++++++++++++++++------
>>>  tests/ovn-northd.at | 98 +++++++++++++++++++++++++++++++++++++++++++++
>>>  3 files changed, 187 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/NEWS b/NEWS
>>> index 68cdbff..0fa8a07 100644
>>> --- a/NEWS
>>> +++ b/NEWS
>>> @@ -6,6 +6,12 @@ Post v26.03.0
>>>       * Add ECMP/multi-homing support for EVPN FDB entries. FDB entries
>>>         backed by a kernel nexthop group are load-balanced via OpenFlow
>>>         select groups with weighted buckets.
>>> +   - 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 emits a
>>> +     localnet-aware reply lflow (matched on flags.localnet + eth.src)
>>> +     and loads the backend LSP's tunnel_key into MFF_LOG_INPORT for
>>> +     the controller dispatch so pinctrl_find_svc_monitor() succeeds.
>>>
>>>  OVN v26.03.0 - xxx xx xxxx
>>>  --------------------------
>>> diff --git a/northd/northd.c b/northd/northd.c
>>> index 8305e04..cc1c2ef 100644
>>> --- a/northd/northd.c
>>> +++ b/northd/northd.c
>>> @@ -8922,30 +8922,82 @@ build_lb_health_check_response_lflows(
>>>                  continue;
>>>              }
>>>
>>> +            /* For backends whose LSP is type=external on a switch with
>> a
>>> +             * localnet port (typical for Neutron / ovn-octavia-provider
>>> +             * baremetal pool members on a provider VLAN), the reply
>>> +             * re-enters br-int via the localnet port.  At that point
>>> +             * MFF_LOG_INPORT carries the localnet LSP's tunnel_key, not
>>> +             * the backend's, so the original 'inport == <backend>'
>> match
>>> +             * never fires and pinctrl_handle_svc_check() never runs.
>>> +             *
>>> +             * Detect that case here so we can substitute a
>> localnet-aware
>>> +             * match (keyed on flags.localnet + eth.src) and an action
>>> +             * that loads the backend LSP's tunnel_key into
>> MFF_LOG_INPORT
>>> +             * before dispatching to ovn-controller, which is what
>>> +             * pinctrl_find_svc_monitor() keys on. */
>>> +            struct ovn_port *backend_op = NULL;
>>> +            struct ovn_port *op;
>>> +            HMAP_FOR_EACH (op, dp_node, &peer_switch_od->ports) {
>>> +                if (op->nbsp && op->key
>>> +                    && !strcmp(op->key, backend_nb->logical_port)) {
>>> +                    backend_op = op;
>>> +                    break;
>>> +                }
>>> +            }
>>> +            bool external_via_localnet =
>>> +                backend_op && backend_op->nbsp && backend_op->nbsp->type
>>> +                && !strcmp(backend_op->nbsp->type, "external")
>>> +                && backend_op->n_lsp_addrs
>>> +                && ls_has_localnet_port(peer_switch_od);
>>> +
>>>              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. */
>>>              if (addr_is_ipv6(backend_nb->svc_mon_src_ip)) {
>>> -                ds_put_format(match, "inport == \"%s\" && ip6.dst == %s
>> && "
>>> -                              "ip6.src == %s && eth.dst == %s && ",
>>> -                              backend_nb->logical_port,
>>> -                              backend_nb->svc_mon_src_ip,
>>> -                              backend->ip_str,
>>> -
>> backend_nb->svc_mon_lrp->lrp_networks.ea_s);
>>> +                if (external_via_localnet) {
>>> +                    ds_put_format(match,
>>> +                                  "flags.localnet == 1 && eth.src == %s
>> && "
>>> +                                  "ip6.dst == %s && ip6.src == %s && "
>>> +                                  "eth.dst == %s && ",
>>> +                                  backend_op->lsp_addrs[0].ea_s,
>>> +                                  backend_nb->svc_mon_src_ip,
>>> +                                  backend->ip_str,
>>> +
>> backend_nb->svc_mon_lrp->lrp_networks.ea_s);
>>> +                } else {
>>> +                    ds_put_format(match,
>>> +                                  "inport == \"%s\" && ip6.dst == %s &&
>> "
>>> +                                  "ip6.src == %s && eth.dst == %s && ",
>>> +                                  backend_nb->logical_port,
>>> +                                  backend_nb->svc_mon_src_ip,
>>> +                                  backend->ip_str,
>>> +
>> backend_nb->svc_mon_lrp->lrp_networks.ea_s);
>>> +                }
>>>                  if (!strcmp(protocol, "tcp")) {
>>>                      ds_put_format(match, "tcp.src == %s",
>> backend->port_str);
>>>                  } else {
>>>                      ds_put_cstr(match, "icmp6.type == 1");
>>>                  }
>>>              } else {
>>> -                ds_put_format(match, "inport == \"%s\" && ip4.dst == %s
>> && "
>>> -                              "ip4.src == %s && eth.dst == %s && ",
>>> -                              backend_nb->logical_port,
>>> -                              backend_nb->svc_mon_src_ip,
>>> -                              backend->ip_str,
>>> -
>> backend_nb->svc_mon_lrp->lrp_networks.ea_s);
>>> +                if (external_via_localnet) {
>>> +                    ds_put_format(match,
>>> +                                  "flags.localnet == 1 && eth.src == %s
>> && "
>>> +                                  "ip4.dst == %s && ip4.src == %s && "
>>> +                                  "eth.dst == %s && ",
>>> +                                  backend_op->lsp_addrs[0].ea_s,
>>> +                                  backend_nb->svc_mon_src_ip,
>>> +                                  backend->ip_str,
>>> +
>> backend_nb->svc_mon_lrp->lrp_networks.ea_s);
>>> +                } else {
>>> +                    ds_put_format(match,
>>> +                                  "inport == \"%s\" && ip4.dst == %s &&
>> "
>>> +                                  "ip4.src == %s && eth.dst == %s && ",
>>> +                                  backend_nb->logical_port,
>>> +                                  backend_nb->svc_mon_src_ip,
>>> +                                  backend->ip_str,
>>> +
>> backend_nb->svc_mon_lrp->lrp_networks.ea_s);
>>> +                }
>>>                  if (!strcmp(protocol, "tcp")) {
>>>                      ds_put_format(match, "tcp.src == %s",
>> backend->port_str);
>>>                  } else {
>>> @@ -8953,6 +9005,24 @@ build_lb_health_check_response_lflows(
>>>                  }
>>>              }
>>>
>>> +            /* For the type=external/localnet case, MFF_LOG_INPORT at
>> this
>>> +             * point holds the localnet LSP's tunnel_key but pinctrl
>> indexes
>>> +             * Service_Monitor by the backend LSP's tunnel_key.  Borrow
>>> +             * MFF_LOG_OUTPORT to carry the backend LSP's tunnel_key
>> into
>>> +             * MFF_LOG_INPORT for the controller dispatch
>> (handle_svc_check()
>>> +             * saves/moves/restores MFF_LOG_INPORT around the punt),
>> then
>>> +             * clear outport so the cleared MFF_LOG_OUTPORT does not
>> leak
>>> +             * into egress. */
>>> +            if (external_via_localnet) {
>>> +                ds_put_format(action,
>>> +                              "outport = \"%s\"; "
>>> +                              "handle_svc_check(outport); "
>>> +                              "outport = \"\";",
>>> +                              backend_nb->logical_port);
>>
>> Why do you set outport to the backend logical port name ?
>> ovn-controller expects the inport to be set right ?
>> The action should set inport right ?
>>
>> i.e
>> uint32_t port_key = md->flow.regs[MFF_LOG_INPORT - MFF_REG0];
>>
>>
>> Thanks
>> Numan
>>
>>> +            } else {
>>> +                ds_put_cstr(action, "handle_svc_check(inport);");
>>> +            }
>>> +
>>>              /* ovn-controller expects health check responses from the LS
>>>               * datapath in which the backend is located. That's why we
>>>               * install the response lflow into the peer's datapath. */
>>> @@ -8960,7 +9030,7 @@ build_lb_health_check_response_lflows(
>>>
>>  peer_switch_od->nbs->copp,
>>>                                                 meter_groups);
>>>              ovn_lflow_add(lflows, peer_switch_od, S_SWITCH_IN_L2_LKUP,
>> 110,
>>> -                          ds_cstr(match), "handle_svc_check(inport);",
>>> +                          ds_cstr(match), ds_cstr(action),
>>>                            lb_dps->lflow_ref, WITH_CTRL_METER(meter));
>>>          }
>>>      }
>>> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
>>> index 074b152..708586c 100644
>>> --- a/tests/ovn-northd.at
>>> +++ b/tests/ovn-northd.at
>>> @@ -1687,6 +1687,104 @@ 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.
>>> +#
>>> +# The fix replaces the per-backend reply lflow's match/action when the
>>> +# backend is type=external on a switch with a localnet port:
>>> +#   match  : "flags.localnet == 1 && eth.src == <bm_mac> && ..."
>>> +#   action : "outport = "<bm-port>"; handle_svc_check(outport); outport
>> = "";"
>>> +# handle_svc_check() saves/moves/restores MFF_LOG_INPORT around the
>> punt,
>>> +# so dispatch sees REG14 = bm-port's tunnel_key as required by pinctrl.
>>> +# Regular (non-external) backends keep the original behavior.
>>> +
>>> +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): match keyed on
>> flags.localnet
>>> +# + eth.src, action borrows outport to load the backend tunnel_key into
>>> +# MFF_LOG_INPORT for the controller dispatch.
>>> +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=(flags.localnet
>> == 1 && eth.src == 00:00:00:00:02:0a && ip4.dst == 10.0.50.1 && ip4.src ==
>> 10.0.50.10 && eth.dst == 00:00:00:00:02:01 && tcp.src == 80),
>> action=(outport = "bm-port"; handle_svc_check(outport); outport = "";)
>>> +])
>>> +
>>> +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])
>>> --
>>> 2.49.0
>>>
>>
> 

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

Reply via email to