Skip to content

Commit

Permalink
ovn-controller: Support ovn-encap-ip-default option.
Browse files Browse the repository at this point in the history
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]>
Acked-by: Numan Siddique <[email protected]>
  • Loading branch information
hzhou8 committed Aug 8, 2024
1 parent d52e928 commit 6559b44
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 12 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ Post v24.03.0
- Add support for ACL sampling through the new Sample_Collector and Sample
tables. Sampling is supported for both traffic that creates new
connections and for traffic that is part of an existing connection.
- 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
--------------------------
Expand Down
13 changes: 7 additions & 6 deletions controller/binding.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
46 changes: 42 additions & 4 deletions controller/chassis.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -283,6 +285,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);

Expand All @@ -300,7 +303,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;
}
Expand Down Expand Up @@ -335,6 +337,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_WARN_RL(&rl, "ovn-encap-ip-default (%s) must be one of the IPs "
"in ovn-encap-ip.", encap_ip_default);
encap_ip_default = NULL;
}
ovs_cfg->encap_ip_default = encap_ip_default;

chassis_parse_ovs_iface_types(cfg->iface_types, cfg->n_iface_types,
&ovs_cfg->iface_types);
Expand Down Expand Up @@ -548,6 +560,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)
{
Expand Down Expand Up @@ -576,6 +589,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) {
Expand Down Expand Up @@ -607,6 +633,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)
Expand All @@ -627,7 +654,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;
Expand Down Expand Up @@ -763,7 +798,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;
Expand All @@ -774,7 +811,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);
Expand Down
6 changes: 6 additions & 0 deletions controller/ovn-controller.8.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions ovn-sb.xml
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,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>
Expand Down
37 changes: 35 additions & 2 deletions tests/ovn.at
Original file line number Diff line number Diff line change
Expand Up @@ -30251,8 +30251,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)")
Expand All @@ -30269,6 +30282,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
])
Expand Down

0 comments on commit 6559b44

Please sign in to comment.