On Tue, Mar 10, 2026 at 1:21 AM Lorenzo Bianconi <
[email protected]> wrote:
>
> > Add LSP/LRP option `requested-encap-ip` so the CMS can request a
specific
> > `Port_Binding.encap` IP (e.g., transit switch ports in ovn-k8s
interconnect
> > mode).
> >
> > When the same encap IP exists for both Geneve and VXLAN, prefer Geneve.
> >
> > If `requested-chassis` is set, consider only encaps on that chassis;
otherwise
> > (router-LSP cases), use IP-only lookup.
> >
> > NB-requested encap overrides the VIF `external_ids:encap-ip`. Track NB
> > ownership with Port_Binding option `is-encap-nb-bound` to avoid
ovn-northd vs
> > ovn-controller races.
> >

Thanks Lei for the revisions, and Mark and Lorenzo for the reviews.
I applied the patch to main, slightly adjusting the commit message and
confirming with Lei - removing "Track NB ownership with Port_Binding option
`is-encap-nb-bound` to avoid ovn-northd vs ovn-controller races." to align
with the code, which didn't need and didn't add the option
`is-encap-nb-bound`.

Best,
Han

>
>
> > CC: Han Zhou <[email protected]>
> > Signed-off-by: Lei Huang <[email protected]>
>
> Acked-by: Lorenzo Bianconi <[email protected]>
>
> > ---
> >  NEWS                             |   3 +
> >  controller/binding.c             |  18 ++++-
> >  northd/en-northd.c               |   4 ++
> >  northd/inc-proc-northd.c         |  11 +++
> >  northd/northd.c                  | 118 +++++++++++++++++++++++++++++--
> >  northd/northd.h                  |   1 +
> >  ovn-nb.xml                       |  18 +++++
> >  ovn-sb.xml                       |   8 +++
> >  tests/ovn-inc-proc-graph-dump.at |   2 +
> >  tests/ovn-northd.at              |  94 ++++++++++++++++++++++++
> >  tests/ovn.at                     |  51 +++++++++++++
> >  11 files changed, 319 insertions(+), 9 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index ef7b4210b..888946b54 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -3,6 +3,9 @@ Post v26.03.0
> >
> >  OVN v26.03.0 - xxx xx xxxx
> >  --------------------------
> > +   - Added LSP/LRP option "requested-encap-ip" to let CMS request a
specific
> > +     SB Port_Binding encap IP (e.g., for transit switch ports in
ovn-k8s
> > +     interconnect mode).
> >     - Added DNS query statistics tracking in ovn-controller using OVS
coverage
> >       counters. Statistics can be queried using "ovn-appctl -t
ovn-controller
> >       coverage/read-counter <counter_name>" or "coverage/show". Tracked
metrics
> > diff --git a/controller/binding.c b/controller/binding.c
> > index eb9524142..fa1984ee7 100644
> > --- a/controller/binding.c
> > +++ b/controller/binding.c
> > @@ -1300,12 +1300,24 @@ claimed_lport_set_up(const struct
sbrec_port_binding *pb,
> >  typedef void (*set_func)(const struct sbrec_port_binding *pb,
> >                           const struct sbrec_encap *);
> >
> > +static bool
> > +pb_encap_managed_by_northd(const struct sbrec_port_binding *pb)
> > +{
> > +    const char *requested_encap_ip = smap_get(&pb->options,
> > +                                              "requested-encap-ip");
> > +    return requested_encap_ip && requested_encap_ip[0];
> > +}
> > +
> >  static bool
> >  update_port_encap_if_needed(const struct sbrec_port_binding *pb,
> >                              const struct sbrec_chassis *chassis_rec,
> >                              const struct ovsrec_interface *iface_rec,
> >                              bool sb_readonly)
> >  {
> > +    if (pb_encap_managed_by_northd(pb)) {
> > +        return true;
> > +    }
> > +
> >      const struct sbrec_encap *encap_rec =
> >          sbrec_get_port_encap(chassis_rec, iface_rec);
> >      if ((encap_rec && pb->encap != encap_rec) ||
> > @@ -1508,7 +1520,8 @@ release_lport_main_chassis(const struct
sbrec_port_binding *pb,
> >                             bool sb_readonly,
> >                             struct if_status_mgr *if_mgr)
> >  {
> > -    if (pb->encap) {
> > +    if (pb->encap &&
> > +        !pb_encap_managed_by_northd(pb)) {
> >          if (sb_readonly) {
> >              return false;
> >          }
> > @@ -2406,7 +2419,8 @@ binding_cleanup(struct ovsdb_idl_txn
*ovnsb_idl_txn,
> >      bool any_changes = false;
> >      SBREC_PORT_BINDING_TABLE_FOR_EACH (binding_rec,
port_binding_table) {
> >          if (binding_rec->chassis == chassis_rec) {
> > -            if (binding_rec->encap) {
> > +            if (binding_rec->encap &&
> > +                !pb_encap_managed_by_northd(binding_rec)) {
> >                  sbrec_port_binding_set_encap(binding_rec, NULL);
> >              }
> >              sbrec_port_binding_set_chassis(binding_rec, NULL);
> > diff --git a/northd/en-northd.c b/northd/en-northd.c
> > index a828f9a5f..c34818dba 100644
> > --- a/northd/en-northd.c
> > +++ b/northd/en-northd.c
> > @@ -51,6 +51,10 @@ northd_get_input_data(struct engine_node *node,
> >          engine_ovsdb_node_get_index(
> >              engine_get_input("SB_chassis", node),
> >              "sbrec_chassis_by_hostname");
> > +    input_data->sbrec_encap_by_ip =
> > +        engine_ovsdb_node_get_index(
> > +            engine_get_input("SB_encap", node),
> > +            "sbrec_encap_by_ip");
> >      input_data->sbrec_ha_chassis_grp_by_name =
> >          engine_ovsdb_node_get_index(
> >              engine_get_input("SB_ha_chassis_group", node),
> > diff --git a/northd/inc-proc-northd.c b/northd/inc-proc-northd.c
> > index b79272324..9c7de172e 100644
> > --- a/northd/inc-proc-northd.c
> > +++ b/northd/inc-proc-northd.c
> > @@ -97,6 +97,7 @@ static unixctl_cb_func chassis_features_list;
> >  #define SB_NODES \
> >      SB_NODE(sb_global) \
> >      SB_NODE(chassis) \
> > +    SB_NODE(encap) \
> >      SB_NODE(address_set) \
> >      SB_NODE(port_group) \
> >      SB_NODE(logical_flow) \
> > @@ -261,6 +262,11 @@ void inc_proc_northd_init(struct ovsdb_idl_loop
*nb,
> >                       NULL);
> >
> >      engine_add_input(&en_northd, &en_sb_chassis, NULL);
> > +    /* northd uses SB Encap mainly to get the index for
requested-encap-ip
> > +     * lookups. Chassis owns Encap membership, so encap create/delete
are
> > +     * covered by the SB chassis input. Hence a noop handler is
sufficient
> > +     * here. */
> > +    engine_add_input(&en_northd, &en_sb_encap, engine_noop_handler);
> >      engine_add_input(&en_northd, &en_sb_mirror, NULL);
> >      engine_add_input(&en_northd, &en_sb_meter, NULL);
> >      engine_add_input(&en_northd, &en_sb_dns, NULL);
> > @@ -514,6 +520,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >                           ip_mcast_index_create(sb->idl);
> >      struct ovsdb_idl_index *sbrec_chassis_by_hostname =
> >          chassis_hostname_index_create(sb->idl);
> > +    struct ovsdb_idl_index *sbrec_encap_by_ip =
> > +        ovsdb_idl_index_create1(sb->idl, &sbrec_encap_col_ip);
> >      struct ovsdb_idl_index *sbrec_mac_binding_by_datapath
> >          = mac_binding_by_datapath_index_create(sb->idl);
> >      struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip
> > @@ -529,6 +537,9 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
> >      engine_ovsdb_node_add_index(&en_sb_chassis,
> >                                  "sbrec_chassis_by_hostname",
> >                                  sbrec_chassis_by_hostname);
> > +    engine_ovsdb_node_add_index(&en_sb_encap,
> > +                                "sbrec_encap_by_ip",
> > +                                sbrec_encap_by_ip);
> >      engine_ovsdb_node_add_index(&en_sb_ha_chassis_group,
> >                                  "sbrec_ha_chassis_grp_by_name",
> >                                  sbrec_ha_chassis_grp_by_name);
> > diff --git a/northd/northd.c b/northd/northd.c
> > index 983975dac..411f44d59 100644
> > --- a/northd/northd.c
> > +++ b/northd/northd.c
> > @@ -2546,6 +2546,90 @@ ovn_port_update_sbrec_chassis(
> >      free(requested_chassis_sb);
> >  }
> >
> > +static const struct sbrec_encap *
> > +encap_lookup_by_ip(struct ovsdb_idl_index *sbrec_encap_by_ip,
> > +                   const char *ip, const char *requested_chassis)
> > +{
> > +    struct sbrec_encap *key =
> > +        sbrec_encap_index_init_row(sbrec_encap_by_ip);
> > +    sbrec_encap_index_set_ip(key, ip);
> > +
> > +    const struct sbrec_encap *best = NULL;
> > +    const struct sbrec_encap *encap;
> > +    SBREC_ENCAP_FOR_EACH_EQUAL (encap, key, sbrec_encap_by_ip) {
> > +        if (requested_chassis &&
> > +            strcmp(encap->chassis_name, requested_chassis)) {
> > +            continue;
> > +        }
> > +
> > +        enum chassis_tunnel_type tun_type =
get_tunnel_type(encap->type);
> > +        if (tun_type == TUNNEL_TYPE_INVALID) {
> > +            continue;
> > +        }
> > +        /* Pick the highest-preference tunnel type (geneve > vxlan)
> > +         * when multiple encap types share the same IP. */
> > +        if (!best || get_tunnel_type(best->type) < tun_type) {
> > +            best = encap;
> > +        }
> > +    }
> > +    sbrec_encap_index_destroy_row(key);
> > +
> > +    return best;
> > +}
> > +
> > +static void
> > +ovn_port_update_requested_encap(
> > +    struct ovsdb_idl_index *sbrec_encap_by_ip,
> > +    const struct ovn_port *op,
> > +    bool was_requested_encap_ip)
> > +{
> > +    if (is_cr_port(op)) {
> > +        return;
> > +    }
> > +
> > +    const struct smap *options = op->nbsp ? &op->nbsp->options
> > +                                          : &op->nbrp->options;
> > +    const char *requested_ip = smap_get(options, "requested-encap-ip");
> > +    if (!requested_ip || !requested_ip[0]) {
> > +        if (was_requested_encap_ip) {
> > +            if (op->sb->encap) {
> > +                sbrec_port_binding_set_encap(op->sb, NULL);
> > +            }
> > +            sbrec_port_binding_update_options_delkey(op->sb,
> > +
"requested-encap-ip");
> > +        }
> > +        return;
> > +    }
> > +
> > +    const char *requested_chassis = op->sb->requested_chassis
> > +                                    ? op->sb->requested_chassis->name
> > +                                    : NULL;
> > +    const struct sbrec_encap *encap =
encap_lookup_by_ip(sbrec_encap_by_ip,
> > +                                                          requested_ip,
> > +
 requested_chassis);
> > +    if (!encap) {
> > +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> > +        if (requested_chassis) {
> > +            VLOG_WARN_RL(&rl,
> > +                         "No Encap matches options
requested-encap-ip=\"%s\" "
> > +                         "and requested-chassis=\"%s\" for logical
port %s; "
> > +                         "clearing Port_Binding.encap.",
> > +                         requested_ip, requested_chassis, op->key);
> > +        } else {
> > +            VLOG_WARN_RL(&rl,
> > +                         "No Encap matches option
requested-encap-ip=\"%s\" "
> > +                         "for logical port %s; clearing
Port_Binding.encap.",
> > +                         requested_ip, op->key);
> > +        }
> > +    }
> > +
> > +    if (op->sb->encap != encap) {
> > +        sbrec_port_binding_set_encap(op->sb, encap);
> > +    }
> > +    sbrec_port_binding_update_options_setkey(op->sb,
"requested-encap-ip",
> > +                                             requested_ip);
> > +}
> > +
> >  static void
> >  check_and_do_sb_mirror_deletion(const struct ovn_port *op)
> >  {
> > @@ -2616,11 +2700,16 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn
*ovnsb_txn,
> >                        struct ovsdb_idl_index
*sbrec_chassis_by_hostname,
> >                        struct ovsdb_idl_index
*sbrec_ha_chassis_grp_by_name,
> >                        const struct sbrec_mirror_table
*sbrec_mirror_table,
> > +                      struct ovsdb_idl_index *sbrec_encap_by_ip,
> >                        const struct ovn_port *op,
> >                        unsigned long *queue_id_bitmap,
> >                        struct sset *active_ha_chassis_grps)
> >  {
> >      sbrec_port_binding_set_datapath(op->sb, op->od->sdp->sb_dp);
> > +    const char *sb_requested_encap_ip = smap_get(&op->sb->options,
> > +                                                 "requested-encap-ip");
> > +    bool was_requested_encap_ip = sb_requested_encap_ip &&
> > +                                  sb_requested_encap_ip[0];
> >      if (op->nbrp) {
> >          /* Note: SB port binding options for router ports are set in
> >           * sync_pbs(). */
> > @@ -2952,6 +3041,9 @@ common:
> >          sbrec_port_binding_set_tunnel_key(op->sb, op->tunnel_key);
> >      }
> >
> > +    ovn_port_update_requested_encap(sbrec_encap_by_ip, op,
> > +                                    was_requested_encap_ip);
> > +
> >      /* ovn-controller will update 'Port_Binding.up' only if it was
explicitly
> >       * set to 'false'.
> >       */
> > @@ -4232,6 +4324,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
> >      const struct sbrec_ha_chassis_group_table
*sbrec_ha_chassis_group_table,
> >      struct ovsdb_idl_index *sbrec_chassis_by_name,
> >      struct ovsdb_idl_index *sbrec_chassis_by_hostname,
> > +    struct ovsdb_idl_index *sbrec_encap_by_ip,
> >      struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name,
> >      struct hmap *ls_datapaths, struct hmap *lr_datapaths,
> >      struct hmap *ls_ports, struct hmap *lr_ports,
> > @@ -4307,6 +4400,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
> >                                sbrec_chassis_by_hostname,
> >                                sbrec_ha_chassis_grp_by_name,
> >                                sbrec_mirror_table,
> > +                              sbrec_encap_by_ip,
> >                                op, queue_id_bitmap,
> >                                &active_ha_chassis_grps);
> >          op->od->is_transit_router |= is_transit_router_port(op);
> > @@ -4321,6 +4415,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
> >                                sbrec_chassis_by_hostname,
> >                                sbrec_ha_chassis_grp_by_name,
> >                                sbrec_mirror_table,
> > +                              sbrec_encap_by_ip,
> >                                op, queue_id_bitmap,
> >                                &active_ha_chassis_grps);
> >          sbrec_port_binding_set_logical_port(op->sb, op->key);
> > @@ -4543,7 +4638,8 @@ ls_port_init(struct ovn_port *op, struct
ovsdb_idl_txn *ovnsb_txn,
> >               const struct sbrec_port_binding *sb,
> >               const struct sbrec_mirror_table *sbrec_mirror_table,
> >               struct ovsdb_idl_index *sbrec_chassis_by_name,
> > -             struct ovsdb_idl_index *sbrec_chassis_by_hostname)
> > +             struct ovsdb_idl_index *sbrec_chassis_by_hostname,
> > +             struct ovsdb_idl_index *sbrec_encap_by_ip)
> >  {
> >      op->od = od;
> >      parse_lsp_addrs(op);
> > @@ -4573,6 +4669,7 @@ ls_port_init(struct ovn_port *op, struct
ovsdb_idl_txn *ovnsb_txn,
> >      }
> >      ovn_port_update_sbrec(ovnsb_txn, sbrec_chassis_by_name,
> >                            sbrec_chassis_by_hostname, NULL,
sbrec_mirror_table,
> > +                          sbrec_encap_by_ip,
> >                            op, NULL, NULL);
> >      return true;
> >  }
> > @@ -4583,13 +4680,15 @@ ls_port_create(struct ovsdb_idl_txn *ovnsb_txn,
struct hmap *ls_ports,
> >                 struct ovn_datapath *od,
> >                 const struct sbrec_mirror_table *sbrec_mirror_table,
> >                 struct ovsdb_idl_index *sbrec_chassis_by_name,
> > -               struct ovsdb_idl_index *sbrec_chassis_by_hostname)
> > +               struct ovsdb_idl_index *sbrec_chassis_by_hostname,
> > +               struct ovsdb_idl_index *sbrec_encap_by_ip)
> >  {
> >      struct ovn_port *op = ovn_port_create(ls_ports, key, nbsp, NULL,
> >                                            NULL);
> >      hmap_insert(&od->ports, &op->dp_node,
hmap_node_hash(&op->key_node));
> >      if (!ls_port_init(op, ovnsb_txn, od, NULL, sbrec_mirror_table,
> > -                      sbrec_chassis_by_name,
sbrec_chassis_by_hostname)) {
> > +                      sbrec_chassis_by_name, sbrec_chassis_by_hostname,
> > +                      sbrec_encap_by_ip)) {
> >          ovn_port_destroy(ls_ports, op);
> >          return NULL;
> >      }
> > @@ -4604,14 +4703,16 @@ ls_port_reinit(struct ovn_port *op, struct
ovsdb_idl_txn *ovnsb_txn,
> >                  const struct sbrec_port_binding *sb,
> >                  const struct sbrec_mirror_table *sbrec_mirror_table,
> >                  struct ovsdb_idl_index *sbrec_chassis_by_name,
> > -                struct ovsdb_idl_index *sbrec_chassis_by_hostname)
> > +                struct ovsdb_idl_index *sbrec_chassis_by_hostname,
> > +                struct ovsdb_idl_index *sbrec_encap_by_ip)
> >  {
> >      ovn_port_cleanup(op);
> >      op->sb = sb;
> >      ovn_port_set_nb(op, nbsp, NULL);
> >      op->primary_port = op->cr_port = NULL;
> >      return ls_port_init(op, ovnsb_txn, od, sb, sbrec_mirror_table,
> > -                        sbrec_chassis_by_name,
sbrec_chassis_by_hostname);
> > +                        sbrec_chassis_by_name,
sbrec_chassis_by_hostname,
> > +                        sbrec_encap_by_ip);
> >  }
> >
> >  /* Returns true if the logical switch has changes which can be
> > @@ -4810,7 +4911,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn
*ovnsb_idl_txn,
> >                                      new_nbsp->name, new_nbsp, od,
> >                                      ni->sbrec_mirror_table,
> >                                      ni->sbrec_chassis_by_name,
> > -                                    ni->sbrec_chassis_by_hostname);
> > +                                    ni->sbrec_chassis_by_hostname,
> > +                                    ni->sbrec_encap_by_ip);
> >                  if (!op) {
> >                      goto fail;
> >                  }
> > @@ -4853,7 +4955,8 @@ ls_handle_lsp_changes(struct ovsdb_idl_txn
*ovnsb_idl_txn,
> >                                      new_nbsp,
> >                                      od, sb, ni->sbrec_mirror_table,
> >                                      ni->sbrec_chassis_by_name,
> > -                                    ni->sbrec_chassis_by_hostname)) {
> > +                                    ni->sbrec_chassis_by_hostname,
> > +                                    ni->sbrec_encap_by_ip)) {
> >                      if (sb) {
> >                          sbrec_port_binding_delete(sb);
> >                      }
> > @@ -20959,6 +21062,7 @@ ovnnb_db_run(struct northd_input *input_data,
> >                  input_data->sbrec_ha_chassis_group_table,
> >                  input_data->sbrec_chassis_by_name,
> >                  input_data->sbrec_chassis_by_hostname,
> > +                input_data->sbrec_encap_by_ip,
> >                  input_data->sbrec_ha_chassis_grp_by_name,
> >                  &data->ls_datapaths.datapaths,
&data->lr_datapaths.datapaths,
> >                  &data->ls_ports, &data->lr_ports,
> > diff --git a/northd/northd.h b/northd/northd.h
> > index 4dcd128cc..a876e0a56 100644
> > --- a/northd/northd.h
> > +++ b/northd/northd.h
> > @@ -86,6 +86,7 @@ struct northd_input {
> >      struct ovsdb_idl_index *nbrec_mirror_by_type_and_sink;
> >      struct ovsdb_idl_index *sbrec_chassis_by_name;
> >      struct ovsdb_idl_index *sbrec_chassis_by_hostname;
> > +    struct ovsdb_idl_index *sbrec_encap_by_ip;
> >      struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;
> >      struct ovsdb_idl_index *sbrec_ip_mcast_by_dp;
> >      struct ovsdb_idl_index *sbrec_fdb_by_dp_and_port;
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index 954ed1166..f1cd89509 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -1567,6 +1567,15 @@
> >            </p>
> >          </column>
> >
> > +        <column name="options" key="requested-encap-ip">
> > +          Requests the encapsulation IP address for the port binding.
If set,
> > +          <code>ovn-northd</code> uses this IP to select the
> > +          <ref table="Encap" db="OVN_Southbound"/> entry written to
> > +          <ref table="Port_Binding" column="encap"
db="OVN_Southbound"/>.
> > +          This is intended for ports without a local OVS interface,
e.g. remote
> > +          transit switch ports in ovn-kubernetes interconnect mode.
> > +        </column>
> > +
> >          <column name="options" key="activation-strategy">
> >            If used with multiple chassis set in
> >            <ref column="requested-chassis"/>, specifies an activation
strategy
> > @@ -4543,6 +4552,15 @@ or
> >          </p>
> >        </column>
> >
> > +      <column name="options" key="requested-encap-ip">
> > +        Requests the encapsulation IP address for the port binding. If
set,
> > +        <code>ovn-northd</code> uses this IP to select the
> > +        <ref table="Encap" db="OVN_Southbound"/> entry written to
> > +        <ref table="Port_Binding" column="encap" db="OVN_Southbound"/>.
> > +        This is intended for ports without a local OVS interface, e.g.
remote
> > +        transit router ports in ovn-kubernetes interconnect mode.
> > +      </column>
> > +
> >        <column name="options" key="dynamic-routing-redistribute"
> >                type='{"type": "string"}'>
> >          <p>
> > diff --git a/ovn-sb.xml b/ovn-sb.xml
> > index 92496b911..46568da62 100644
> > --- a/ovn-sb.xml
> > +++ b/ovn-sb.xml
> > @@ -3829,6 +3829,14 @@ tcp.flags = RST;
> >          </p>
> >        </column>
> >
> > +      <column name="options" key="requested-encap-ip">
> > +        If set, <code>ovn-northd</code> resolves and sets
> > +        <ref column="encap"/> for this port based on the requested
tunnel
> > +        endpoint IP. If absent, <code>ovn-controller</code> may manage
> > +        <ref column="encap"/> from local interface
> > +        <code>external_ids:encap-ip</code>.
> > +      </column>
> > +
> >        <column name="options" key="activation-strategy">
> >          If used with multiple chassis set in
> >          <ref column="requested-chassis"/>, specifies an activation
strategy
> > diff --git a/tests/ovn-inc-proc-graph-dump.at b/tests/
ovn-inc-proc-graph-dump.at
> > index a31aad6e7..c72d90b12 100644
> > --- a/tests/ovn-inc-proc-graph-dump.at
> > +++ b/tests/ovn-inc-proc-graph-dump.at
> > @@ -20,6 +20,7 @@ digraph "Incremental-Processing-Engine" {
> >       NB_network_function_group [[style=filled, shape=box,
fillcolor=white, label="NB_network_function_group"]];
> >       NB_logical_switch_port_health_check [[style=filled, shape=box,
fillcolor=white, label="NB_logical_switch_port_health_check"]];
> >       SB_chassis [[style=filled, shape=box, fillcolor=white,
label="SB_chassis"]];
> > +     SB_encap [[style=filled, shape=box, fillcolor=white,
label="SB_encap"]];
> >       SB_mirror [[style=filled, shape=box, fillcolor=white,
label="SB_mirror"]];
> >       SB_meter [[style=filled, shape=box, fillcolor=white,
label="SB_meter"]];
> >       SB_dns [[style=filled, shape=box, fillcolor=white,
label="SB_dns"]];
> > @@ -78,6 +79,7 @@ digraph "Incremental-Processing-Engine" {
> >       NB_network_function_group -> northd [[label=""]];
> >       NB_logical_switch_port_health_check -> northd [[label=""]];
> >       SB_chassis -> northd [[label=""]];
> > +     SB_encap -> northd [[label="engine_noop_handler"]];
> >       SB_mirror -> northd [[label=""]];
> >       SB_meter -> northd [[label=""]];
> >       SB_dns -> northd [[label=""]];
> > diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> > index e29f6d7b5..4c1440b22 100644
> > --- a/tests/ovn-northd.at
> > +++ b/tests/ovn-northd.at
> > @@ -2896,6 +2896,100 @@ OVN_CLEANUP_NORTHD
> >  AT_CLEANUP
> >  ])
> >
> > +OVN_FOR_EACH_NORTHD_NO_HV([
> > +AT_SETUP([check options:requested-encap-ip fills port binding encap
col])
> > +AT_KEYWORDS([requested encap ip])
> > +ovn_start
> > +
> > +check_uuid ovn-sbctl \
> > +    -- --id=@e11 create encap chassis_name=ch1 ip="192.168.1.1"
type="vxlan" \
> > +    -- --id=@e12 create encap chassis_name=ch1 ip="192.168.1.2"
type="geneve" \
> > +    -- --id=@c1 create chassis name=ch1 encaps=@e11,@e12
> > +check_uuid ovn-sbctl \
> > +    -- --id=@e21 create encap chassis_name=ch2 ip="192.168.2.1"
type="geneve" \
> > +    -- --id=@e22 create encap chassis_name=ch2 ip="192.168.2.2"
type="geneve" \
> > +    -- --id=@c2 create chassis name=ch2 encaps=@e21,@e22
> > +
> > +wait_row_count Chassis 2
> > +wait_row_count Encap 4
> > +en11_uuid=$(fetch_column Encap _uuid ip="192.168.1.1")
> > +en12_uuid=$(fetch_column Encap _uuid ip="192.168.1.2")
> > +en21_uuid=$(fetch_column Encap _uuid ip="192.168.2.1")
> > +en22_uuid=$(fetch_column Encap _uuid ip="192.168.2.2")
> > +ovn-sbctl show
> > +
> > +echo "__file__:__line__: encap uuid: $en11_uuid, ip: 192.168.1.1"
> > +echo "__file__:__line__: encap uuid: $en12_uuid, ip: 192.168.1.2"
> > +echo "__file__:__line__: encap uuid: $en21_uuid, ip: 192.168.2.1"
> > +echo "__file__:__line__: encap uuid: $en22_uuid, ip: 192.168.2.2"
> > +
> > +check ovn-nbctl --wait=sb ls-add ls1
> > +check ovn-nbctl --wait=sb lsp-add ls1 lsp1
> > +check ovn-nbctl --wait=sb lsp-add ls1 lsp2
> > +ovn-nbctl show
> > +
> > +# set options:requested-encap-ip without requested-chassis
> > +check ovn-nbctl --wait=sb set logical-switch-port lsp1 \
> > +    options:requested-encap-ip=192.168.1.1
> > +check ovn-nbctl --wait=sb sync
> > +wait_row_count Port_Binding 1 logical_port=lsp1 encap="$en11_uuid"
> > +
> > +# With requested-chassis set to a different chassis, encap should be
cleared.
> > +check ovn-nbctl --wait=sb set logical-switch-port lsp1 \
> > +    options:requested-chassis=ch2
> > +wait_row_count Port_Binding 1 logical_port=lsp1 'encap=[[]]'
> > +
> > +# Set both options to a matching chassis+IP.
> > +check ovn-nbctl --wait=sb set logical-switch-port lsp1 \
> > +    options:requested-chassis=ch1 \
> > +    options:requested-encap-ip=192.168.1.1
> > +check ovn-nbctl --wait=sb set logical-switch-port lsp2 \
> > +    options:requested-chassis=ch2 \
> > +    options:requested-encap-ip=192.168.2.2
> > +
> > +wait_row_count Port_Binding 1 logical_port=lsp1 encap="$en11_uuid"
> > +wait_row_count Port_Binding 1 logical_port=lsp2 encap="$en22_uuid"
> > +
> > +# Add geneve encap with the same IP and ensure it is preferred over
vxlan.
> > +check_uuid ovn-sbctl \
> > +    -- --id=@e11g create encap chassis_name=ch1 ip="192.168.1.1"
type="geneve" \
> > +    -- add chassis ch1 encaps @e11g
> > +wait_row_count Encap 5
> > +en11g_uuid=$(fetch_column Encap _uuid chassis_name=ch1
ip="192.168.1.1" type=geneve)
> > +wait_row_count Port_Binding 1 logical_port=lsp1 encap="$en11g_uuid"
> > +
> > +# Router LSP path has no requested-chassis, but requested-encap-ip
should work.
> > +check ovn-nbctl --wait=sb lr-add lr1
> > +check ovn-nbctl --wait=sb lrp-add lr1 lrp1 00:00:00:01:00:01
100.64.0.1/24
> > +check ovn-nbctl --wait=sb lsp-add ls1 lsp-router1 \
> > +    -- lsp-set-type lsp-router1 router \
> > +    -- lsp-set-options lsp-router1 router-port=lrp1 \
> > +    -- lsp-set-addresses lsp-router1 router
> > +check ovn-nbctl --wait=sb set logical-switch-port lsp-router1 \
> > +    options:requested-encap-ip=192.168.2.1
> > +wait_row_count Port_Binding 1 logical_port=lsp-router1
encap="$en21_uuid"
> > +wait_row_count Port_Binding 1 logical_port=lsp-router1 \
> > +    options:requested-encap-ip=192.168.2.1
> > +
> > +# remove options:requested-encap-ip from lsp1
> > +check ovn-nbctl --wait=sb remove logical_switch_port lsp1 \
> > +    options requested-encap-ip=192.168.1.1
> > +wait_row_count Port_Binding 1 logical_port=lsp1 'encap=[[]]'
> > +
> > +# remove options:requested-chassis from lsp2 and keep
requested-encap-ip
> > +check ovn-nbctl --wait=sb remove logical_switch_port lsp2 \
> > +    options requested-chassis=ch2
> > +wait_row_count Port_Binding 1 logical_port=lsp2 encap="$en22_uuid"
> > +
> > +# remove options:requested-encap-ip from lsp2
> > +check ovn-nbctl --wait=sb remove logical_switch_port lsp2 \
> > +    options requested-encap-ip=192.168.2.2
> > +wait_row_count Port_Binding 1 logical_port=lsp2 'encap=[[]]'
> > +
> > +OVN_CLEANUP_NORTHD
> > +AT_CLEANUP
> > +])
> > +
> >  OVN_FOR_EACH_NORTHD_NO_HV([
> >  AT_SETUP([port requested-tnl-key])
> >  AT_KEYWORDS([requested tnl tunnel key keys])
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 9082bba82..58e62e2f0 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -40748,6 +40748,57 @@ ignored_dp=lsw0])
> >  AT_CLEANUP
> >  ])
> >
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([ovn-controller - requested-encap-ip should override VIF
encap-ip])
> > +ovn_start
> > +net_add n1
> > +
> > +sim_add hv1
> > +as hv1
> > +ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.1
> > +check ovs-vsctl set Open_vSwitch . \
> > +    external_ids:ovn-encap-ip="192.168.0.1,192.168.0.11" \
> > +    external_ids:ovn-encap-ip-default=192.168.0.1 \
> > +    external_ids:ovn-enable-flow-based-tunnels=false
> > +
> > +check ovn-nbctl ls-add ls0
> > +check ovn-nbctl lsp-add ls0 lsp0
> > +check ovn-nbctl lsp-set-addresses lsp0 "50:54:00:00:00:01 10.0.0.1"
> > +
> > +as hv1
> > +check ovs-vsctl -- add-port br-int vif0 -- \
> > +    set Interface vif0 external-ids:iface-id=lsp0 \
> > +    external-ids:encap-ip=192.168.0.11
> > +
> > +wait_row_count Chassis 1 name=hv1
> > +wait_row_count Encap 4 chassis_name=hv1
> > +check ovn-nbctl --wait=hv sync
> > +wait_for_ports_up lsp0
> > +
> > +encap_uuid_vif=$(ovn-sbctl --bare --columns _uuid find Encap \
> > +    chassis_name=hv1 ip="192.168.0.11" type=geneve)
> > +encap_uuid_nb=$(ovn-sbctl --bare --columns _uuid find Encap \
> > +    chassis_name=hv1 ip="192.168.0.1" type=geneve)
> > +
> > +get_pb_encap_uuid() {
> > +    fetch_column Port_Binding encap logical_port=lsp0
> > +}
> > +
> > +# Verify local VIF encap-ip is reflected by ovn-controller.
> > +OVS_WAIT_UNTIL([test "$encap_uuid_vif" = "$(get_pb_encap_uuid)"])
> > +
> > +# Now request NB-driven encap.
> > +check ovn-nbctl --wait=sb lsp-set-options lsp0 \
> > +    requested-chassis=hv1 requested-encap-ip=192.168.0.1
> > +
> > +# Expected behavior: NB request should win over local iface encap-ip.
> > +OVS_WAIT_UNTIL([test "$encap_uuid_nb" = "$(get_pb_encap_uuid)"])
> > +
> > +OVN_CLEANUP([hv1])
> > +AT_CLEANUP
> > +])
> > +
> >  OVN_FOR_EACH_NORTHD([
> >  AT_SETUP([DHCP RELAY])
> >  ovn_start
> > --
> > 2.43.0
> >
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to