On Wed, Aug 7, 2024 at 8:39 PM Numan Siddique <[email protected]> wrote:
>
> On Sat, Jul 20, 2024 at 1:24 AM Han Zhou <[email protected]> wrote:
> >
> > When there are multiple encap IPs configured for a chassis, there are
> > situations that any of the IP may be used, e.g. when encap-ip is not
> > configured for a VIF or when the output port of the pipeline is not
> > a VIF but a chassis-redirect port. In such cases, the encap IP used is
> > unpredictable. This patch introduces the ovn-encap-ip-default option,
> > allowing the configuration of a default IP to be used to ensure
> > deterministic encap IP selection in such cases.
> >
> > Signed-off-by: Han Zhou <[email protected]>
> > ---
> > NEWS | 3 +++
> > controller/binding.c | 13 +++++-----
> > controller/chassis.c | 46 ++++++++++++++++++++++++++++++---
> > controller/ovn-controller.8.xml | 6 +++++
> > ovn-sb.xml | 10 +++++++
> > tests/ovn.at | 37 ++++++++++++++++++++++++--
> > 6 files changed, 103 insertions(+), 12 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index 3e392ff08b5a..b23977a9316d 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -38,6 +38,9 @@ Post v24.03.0
> > ability to disable "VXLAN mode" to extend available tunnel IDs space
> > for
> > datapaths from 4095 to 16711680. For more details see man ovn-nb(5)
> > for
> > mentioned option.
> > + - Add "external_ids:ovn-encap-ip-default" config for ovn-controller to
> > + determine the default encap IP when there are multiple encap IPs
> > + configured.
> >
> > OVN v24.03.0 - 01 Mar 2024
> > --------------------------
> > diff --git a/controller/binding.c b/controller/binding.c
> > index b7e7f48749b8..146b03248f14 100644
> > --- a/controller/binding.c
> > +++ b/controller/binding.c
> > @@ -520,20 +520,21 @@ static struct sbrec_encap *
> > sbrec_get_port_encap(const struct sbrec_chassis *chassis_rec,
> > const struct ovsrec_interface *iface_rec)
> > {
> > -
> > - if (!iface_rec) {
> > + if (chassis_rec->n_encaps < 2) {
> > return NULL;
> > }
> >
> > - const char *encap_ip = smap_get(&iface_rec->external_ids, "encap-ip");
> > - if (!encap_ip) {
> > - return NULL;
> > + const char *encap_ip = NULL;
> > + if (iface_rec) {
> > + encap_ip = smap_get(&iface_rec->external_ids, "encap-ip");
> > }
> >
> > struct sbrec_encap *best_encap = NULL;
> > uint32_t best_type = 0;
> > for (int i = 0; i < chassis_rec->n_encaps; i++) {
> > - if (!strcmp(chassis_rec->encaps[i]->ip, encap_ip)) {
> > + if ((encap_ip && !strcmp(chassis_rec->encaps[i]->ip, encap_ip)) ||
> > + (!encap_ip && smap_get_bool(&chassis_rec->encaps[i]->options,
> > + "is_default", false))) {
> > uint32_t tun_type =
> > get_tunnel_type(chassis_rec->encaps[i]->type);
> > if (tun_type > best_type) {
> > best_type = tun_type;
> > diff --git a/controller/chassis.c b/controller/chassis.c
> > index 4942ba281d66..7fe38efd1159 100644
> > --- a/controller/chassis.c
> > +++ b/controller/chassis.c
> > @@ -63,6 +63,8 @@ struct ovs_chassis_cfg {
> > struct sset encap_type_set;
> > /* Set of encap IPs parsed from the 'ovn-encap-ip' external-id. */
> > struct sset encap_ip_set;
> > + /* Default encap IP when there are two or more encap IPs. Optional. */
> > + const char *encap_ip_default;
> > /* Interface type list formatted in the OVN-SB Chassis required
> > format. */
> > struct ds iface_types;
> > /* Is this chassis an interconnection gateway. */
> > @@ -281,6 +283,7 @@ chassis_parse_ovs_config(const struct
> > ovsrec_open_vswitch_table *ovs_table,
> > const struct ovsrec_bridge *br_int,
> > struct ovs_chassis_cfg *ovs_cfg)
> > {
> > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> > const struct ovsrec_open_vswitch *cfg =
> > ovsrec_open_vswitch_table_first(ovs_table);
> >
> > @@ -298,7 +301,6 @@ chassis_parse_ovs_config(const struct
> > ovsrec_open_vswitch_table *ovs_table,
> > get_chassis_external_id_value(&cfg->external_ids, chassis_id,
> > "ovn-encap-ip", NULL);
> > if (!encap_type || !encap_ips) {
> > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
> > VLOG_INFO_RL(&rl, "Need to specify an encap type and ip");
> > return false;
> > }
> > @@ -333,6 +335,16 @@ chassis_parse_ovs_config(const struct
> > ovsrec_open_vswitch_table *ovs_table,
> > * multiple NICs and is assigning SR-IOV VFs to a guest (as logical
> > ports).
> > */
> > chassis_parse_ovs_encap_ip(encap_ips, &ovs_cfg->encap_ip_set);
> > + const char *encap_ip_default =
> > + get_chassis_external_id_value(&cfg->external_ids, chassis_id,
> > + "ovn-encap-ip-default", NULL);
> > + if (encap_ip_default &&
> > + !sset_contains(&ovs_cfg->encap_ip_set, encap_ip_default)) {
> > + VLOG_INFO_RL(&rl, "ovn-encap-ip-default (%s) must be one of the
> > IPs "
> > + "in ovn-encap-ip.", encap_ip_default);
> > + return false;
> > + }
>
> Hi Han,
>
> Thanks for the patch.
>
> Lets say CMS has configured ovn-encap-ip = [127.0.0.1, 127.0.0.2, 127.0.0.3]
> and ovn-encap-ip-default = 127.0.0.4.
>
> As default encap-ip is not part of the ovn-encap-ip list,
> chassis_run() will always return NULL.
> And after that, ovn-controller will not bind any logical port and the
> I-P engine doesn't run
> until the config option is set to a valid value.
>
> I understand this is a wrong configuration from the user. But since
> this config is optional, I think we
> should log a warning and continue normally. What do you think ?
>
> Other than that, the patch LGTM.
>
> If you agree with my comment to ignore the wrong default ip:
> Acked-by: Numan Siddique <[email protected]>
>
Thanks Numan. Your suggestion makes sense. I applied to main with
below minor change as you suggested:
---
diff --git a/controller/chassis.c b/controller/chassis.c
index fab5109a2f14..2991a0af32c8 100644
--- a/controller/chassis.c
+++ b/controller/chassis.c
@@ -342,9 +342,9 @@ chassis_parse_ovs_config(const struct
ovsrec_open_vswitch_table *ovs_table,
"ovn-encap-ip-default", NULL);
if (encap_ip_default &&
!sset_contains(&ovs_cfg->encap_ip_set, encap_ip_default)) {
- VLOG_INFO_RL(&rl, "ovn-encap-ip-default (%s) must be one of the IPs "
+ VLOG_WARN_RL(&rl, "ovn-encap-ip-default (%s) must be one of the IPs "
"in ovn-encap-ip.", encap_ip_default);
- return false;
+ encap_ip_default = NULL;
}
ovs_cfg->encap_ip_default = encap_ip_default;
---
Thanks,
Han
> Thanks
> Numan
>
> > + ovs_cfg->encap_ip_default = encap_ip_default;
> >
> > chassis_parse_ovs_iface_types(cfg->iface_types, cfg->n_iface_types,
> > &ovs_cfg->iface_types);
> > @@ -534,6 +546,7 @@ chassis_other_config_changed(const struct
> > ovs_chassis_cfg *ovs_cfg,
> > static bool
> > chassis_tunnels_changed(const struct sset *encap_type_set,
> > const struct sset *encap_ip_set,
> > + const char *encap_ip_default,
> > const char *encap_csum,
> > const struct sbrec_chassis *chassis_rec)
> > {
> > @@ -562,6 +575,19 @@ chassis_tunnels_changed(const struct sset
> > *encap_type_set,
> > changed = true;
> > break;
> > }
> > +
> > + if (smap_get_bool(&chassis_rec->encaps[i]->options,
> > + "is_default", false)) {
> > + if (!encap_ip_default || strcmp(encap_ip_default,
> > + chassis_rec->encaps[i]->ip)) {
> > + changed = true;
> > + break;
> > + }
> > + } else if (encap_ip_default && !strcmp(encap_ip_default,
> > +
> > chassis_rec->encaps[i]->ip)) {
> > + changed = true;
> > + break;
> > + }
> > }
> >
> > if (!changed) {
> > @@ -593,6 +619,7 @@ static struct sbrec_encap **
> > chassis_build_encaps(struct ovsdb_idl_txn *ovnsb_idl_txn,
> > const struct sset *encap_type_set,
> > const struct sset *encap_ip_set,
> > + const char *encap_ip_default,
> > const char *chassis_id,
> > const char *encap_csum,
> > size_t *n_encap)
> > @@ -613,7 +640,15 @@ chassis_build_encaps(struct ovsdb_idl_txn
> > *ovnsb_idl_txn,
> >
> > sbrec_encap_set_type(encap, encap_type);
> > sbrec_encap_set_ip(encap, encap_ip);
> > - sbrec_encap_set_options(encap, &options);
> > + if (encap_ip_default && !strcmp(encap_ip_default, encap_ip)) {
> > + struct smap _options;
> > + smap_clone(&_options, &options);
> > + smap_add(&_options, "is_default", "true");
> > + sbrec_encap_set_options(encap, &_options);
> > + smap_destroy(&_options);
> > + } else {
> > + sbrec_encap_set_options(encap, &options);
> > + }
> > sbrec_encap_set_chassis_name(encap, chassis_id);
> >
> > encaps[tunnel_count] = encap;
> > @@ -748,7 +783,9 @@ chassis_update(const struct sbrec_chassis *chassis_rec,
> > /* If any of the encaps should change, update them. */
> > bool tunnels_changed =
> > chassis_tunnels_changed(&ovs_cfg->encap_type_set,
> > - &ovs_cfg->encap_ip_set,
> > ovs_cfg->encap_csum,
> > + &ovs_cfg->encap_ip_set,
> > + ovs_cfg->encap_ip_default,
> > + ovs_cfg->encap_csum,
> > chassis_rec);
> > if (!tunnels_changed) {
> > return updated;
> > @@ -759,7 +796,8 @@ chassis_update(const struct sbrec_chassis *chassis_rec,
> >
> > encaps =
> > chassis_build_encaps(ovnsb_idl_txn, &ovs_cfg->encap_type_set,
> > - &ovs_cfg->encap_ip_set, chassis_id,
> > + &ovs_cfg->encap_ip_set,
> > + ovs_cfg->encap_ip_default, chassis_id,
> > ovs_cfg->encap_csum, &n_encap);
> > sbrec_chassis_set_encaps(chassis_rec, encaps, n_encap);
> > free(encaps);
> > diff --git a/controller/ovn-controller.8.xml
> > b/controller/ovn-controller.8.xml
> > index 6dad00eb146f..89f08843fcbc 100644
> > --- a/controller/ovn-controller.8.xml
> > +++ b/controller/ovn-controller.8.xml
> > @@ -204,6 +204,12 @@
> > </p>
> > </dd>
> >
> > + <dt><code>external_ids:ovn-encap-ip-default</code></dt>
> > + <dd>
> > + When <code>ovn-encap-ip</code> contains multiple IPs, this field
> > + indicates the default one.
> > + </dd>
> > +
> > <dt><code>external_ids:ovn-encap-df_default</code></dt>
> > <dd>
> > indicates the DF flag handling of the encapulation. Set to
> > diff --git a/ovn-sb.xml b/ovn-sb.xml
> > index 73a1be5ed9b8..66d03bd7cdec 100644
> > --- a/ovn-sb.xml
> > +++ b/ovn-sb.xml
> > @@ -562,6 +562,16 @@
> > </p>
> > </column>
> >
> > + <column name="options" key="is_default" type='{"type": "boolean"}'>
> > + <p>
> > + When there are multiple encaps for a chassis with different IPs,
> > this
> > + option indicates if the encap is the default one that matches the
> > IP in
> > + <ref table="Open_vSwitch"
> > column="external_ids:ovn-encap-ip-default"/>
> > + column of the Open_vSwitch database's <ref table="Open_vSwitch"
> > + db="Open_vSwitch"/> table.
> > + </p>
> > + </column>
> > +
> > <column name="ip">
> > The IPv4 address of the encapsulation tunnel endpoint.
> > </column>
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index adc7cb2c8fc6..8250589814aa 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -30133,8 +30133,21 @@ check_packet_tunnel() {
> > local dst_mac=f0:00:00:00:88:01 # lrp-ls1's MAC
> > local src_ip=$(vif_to_ip vif$src)
> > local dst_ip=$(vif_to_ip vif$dst)
> > - local local_encap_ip=192.168.0.$src
> > - local remote_encap_ip=192.168.0.$dst
> > +
> > + local local_encap_ip
> > + if test -n "$3"; then
> > + local_encap_ip=$3
> > + else
> > + local_encap_ip=192.168.0.$src
> > + fi
> > +
> > + local remote_encap_ip
> > + if test -n "$4"; then
> > + remote_encap_ip=$4
> > + else
> > + remote_encap_ip=192.168.0.$dst
> > + fi
> > +
> > local packet=$(fmt_pkt "Ether(dst='${dst_mac}', src='${src_mac}')/ \
> > IP(dst='${dst_ip}', src='${src_ip}')/ \
> > ICMP(type=8)")
> > @@ -30151,6 +30164,26 @@ for i in 1 2; do
> > done
> > done
> >
> > +# Set default encap-ip and remove VIF's encap-ip settings. Packets should
> > go
> > +# through default encap-ip.
> > +
> > +for i in 1 2; do
> > + as hv$i
> > + check ovs-vsctl set open .
> > external_ids:ovn-encap-ip-default=192.168.0.${i}2
> > +
> > + for j in 1 2; do
> > + check ovs-vsctl remove Interface vif$i$j external_ids encap-ip
> > + done
> > +done
> > +
> > +check ovn-nbctl --wait=hv sync
> > +
> > +for i in 1 2; do
> > + for j in 1 2; do
> > + check_packet_tunnel 1$i 2$j 192.168.0.12 192.168.0.22
> > + done
> > +done
> > +
> > OVN_CLEANUP([hv1],[hv2])
> > AT_CLEANUP
> > ])
> > --
> > 2.38.1
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev