@@ -26,6 +26,8 @@ lib_libovn_la_SOURCES = \
lib/ovn-parallel-hmap.c \
lib/ip-mcast-index.c \
lib/ip-mcast-index.h \
+ lib/lrp-index.c \
+ lib/lrp-index.h \
lib/mac-binding-index.c \
lib/mac-binding-index.h \
lib/mcast-group-index.c \
new file mode 100644
@@ -0,0 +1,43 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "lib/lrp-index.h"
+#include "lib/ovn-nb-idl.h"
+
+struct ovsdb_idl_index *
+lrp_index_create(struct ovsdb_idl *idl)
+{
+ return ovsdb_idl_index_create1(idl, &nbrec_logical_router_port_col_name);
+}
+
+
+/* Finds and returns the lrp with the given 'name', or NULL if no such
+ * lrp exists. */
+const struct nbrec_logical_router_port *
+lrp_lookup_by_name(struct ovsdb_idl_index *nbrec_lrp_by_name,
+ const char *name)
+{
+ struct nbrec_logical_router_port *target =
+ nbrec_logical_router_port_index_init_row(nbrec_lrp_by_name);
+ nbrec_logical_router_port_index_set_name(target, name);
+
+ struct nbrec_logical_router_port *retval =
+ nbrec_logical_router_port_index_find(nbrec_lrp_by_name, target);
+
+ nbrec_logical_router_port_index_destroy_row(target);
+
+ return retval;
+}
+
new file mode 100644
@@ -0,0 +1,25 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_LRP_INDEX_H
+#define OVN_LRP_INDEX_H 1
+
+struct ovsdb_idl;
+
+struct ovsdb_idl_index *lrp_index_create(struct ovsdb_idl *);
+
+const struct nbrec_logical_router_port *lrp_lookup_by_name(
+ struct ovsdb_idl_index *nbrec_lrp_by_name, const char *name);
+
+#endif /* lib/lrp-index.h */
@@ -1074,6 +1074,103 @@ get_chassis_external_id_value_bool(const struct smap *external_ids,
return ret;
}
+bool
+chassis_find_active_active_networks(const struct sbrec_chassis *chassis,
+ const char *network_name,
+ struct chassis_aa_network
+ *chassis_aa_network) {
+ memset(chassis_aa_network, 0, sizeof *chassis_aa_network);
+
+ const char *aa_ports = smap_get(&chassis->other_config,
+ "ovn-active-active-mappings");
+ bool found = false;
+ char *curnet, *nextnet, *curport, *nextport, *start;
+
+ /* Structure
+ * ovn-active-active-mappings="<network>|<network>"
+ * network="<network_name>;<port>;<port>"
+ * port="<mac>,<ip>" */
+ nextnet = start = xstrdup(aa_ports);
+ while ((curnet = strsep(&nextnet, "|")) && *curnet) {
+ nextport = curnet;
+ char *network = strsep(&nextport, ";");
+ if (strcmp(network, network_name)) {
+ continue;
+ }
+ found = true;
+ chassis_aa_network->network_name = xstrdup(network);
+ chassis_aa_network->n_addresses = 0;
+ while ((curport = strsep(&nextport, ";")) && *curport) {
+ char *mac, *ip;
+
+ mac = strsep(&curport, ",");
+ ip = curport;
+
+ if (!mac || !ip || !*mac || !*ip) {
+ VLOG_ERR("Invalid format for "
+ "ovn-active-active-mappings '%s'",
+ aa_ports);
+ continue;
+ }
+
+ chassis_aa_network->addresses = xrealloc(
+ chassis_aa_network->addresses,
+ (chassis_aa_network->n_addresses + 1
+ ) * sizeof *chassis_aa_network->addresses);
+ struct lport_addresses *address =
+ &chassis_aa_network->addresses[
+ chassis_aa_network->n_addresses];
+ init_lport_addresses(address);
+
+ if (!eth_addr_from_string(mac, &address->ea)) {
+ VLOG_ERR("Invalid mac address in "
+ "ovn-active-active-mappings '%s'",
+ aa_ports);
+ free(address);
+ continue;
+ }
+ snprintf(address->ea_s, sizeof address->ea_s, ETH_ADDR_FMT,
+ ETH_ADDR_ARGS(address->ea));
+
+ ovs_be32 ip4;
+ struct in6_addr ip6;
+ unsigned int plen;
+ char *error;
+
+ error = ip_parse_cidr(ip, &ip4, &plen);
+ if (!error) {
+ if (!ip4) {
+ VLOG_ERR("Invalid ip address in "
+ "ovn-active-active-mappings '%s'",
+ aa_ports);
+ destroy_lport_addresses(address);
+ continue;
+ }
+
+ add_ipv4_netaddr(address, ip4, plen);
+ } else {
+ free(error);
+
+ error = ipv6_parse_cidr(ip, &ip6, &plen);
+ if (!error) {
+ add_ipv6_netaddr(address, ip6, plen);
+ } else {
+ VLOG_ERR("Invalid ip address in "
+ "ovn-active-active-mappings '%s'",
+ aa_ports);
+ destroy_lport_addresses(address);
+ free(error);
+ continue;
+ }
+ }
+ chassis_aa_network->n_addresses++;
+ }
+ }
+
+ free(start);
+ return found;
+}
+
void flow_collector_ids_init(struct flow_collector_ids *ids)
{
ovs_list_init(&ids->list);
@@ -44,6 +44,7 @@ struct ovsrec_flow_sample_collector_set_table;
struct sbrec_datapath_binding;
struct sbrec_logical_flow;
struct sbrec_port_binding;
+struct sbrec_chassis;
struct smap;
struct svec;
struct uuid;
@@ -351,6 +352,16 @@ int64_t daemon_startup_ts(void);
char *lr_lb_address_set_name(uint32_t lr_tunnel_key, int addr_family);
char *lr_lb_address_set_ref(uint32_t lr_tunnel_key, int addr_family);
+struct chassis_aa_network {
+ char *network_name;
+ struct lport_addresses *addresses;
+ size_t n_addresses;
+};
+
+bool chassis_find_active_active_networks(const struct sbrec_chassis *,
+ const char *,
+ struct chassis_aa_network *);
+
const char *
get_chassis_external_id_value(const struct smap *,
const char *chassis_id,
@@ -41,6 +41,10 @@ static void
northd_get_input_data(struct engine_node *node,
struct northd_input *input_data)
{
+ input_data->nbrec_lrp_by_name =
+ engine_ovsdb_node_get_index(
+ engine_get_input("NB_logical_router", node),
+ "nbrec_lrp_by_name");
input_data->sbrec_chassis_by_name =
engine_ovsdb_node_get_index(
engine_get_input("SB_chassis", node),
@@ -19,6 +19,7 @@
#include <stdio.h>
#include "chassis-index.h"
+#include "lrp-index.h"
#include "ip-mcast-index.h"
#include "static-mac-binding-index.h"
#include "lib/inc-proc-eng.h"
@@ -361,6 +362,8 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
.sb_idl = sb->idl,
};
+ struct ovsdb_idl_index *nbrec_lrp_by_name =
+ lrp_index_create(nb->idl);
struct ovsdb_idl_index *sbrec_chassis_by_name =
chassis_index_create(sb->idl);
struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name =
@@ -380,6 +383,9 @@ void inc_proc_northd_init(struct ovsdb_idl_loop *nb,
engine_init(&en_northd_output, &engine_arg);
+ engine_ovsdb_node_add_index(&en_nb_logical_router,
+ "nbrec_lrp_by_name",
+ nbrec_lrp_by_name);
engine_ovsdb_node_add_index(&en_sb_chassis,
"sbrec_chassis_by_name",
sbrec_chassis_by_name);
@@ -14,6 +14,7 @@
#include <config.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
@@ -30,9 +31,11 @@
#include "hmapx.h"
#include "openvswitch/hmap.h"
#include "openvswitch/json.h"
+#include "openvswitch/shash.h"
#include "ovn/lex.h"
#include "lb.h"
#include "lib/chassis-index.h"
+#include "lib/lrp-index.h"
#include "lib/ip-mcast-index.h"
#include "lib/static-mac-binding-index.h"
#include "lib/copp.h"
@@ -1252,6 +1255,11 @@ ovn_port_cleanup(struct ovn_port *port)
free(port->ps_addrs);
port->ps_addrs = NULL;
port->n_ps_addrs = 0;
+ if (port->is_active_active) {
+ ovs_assert(port->aa_chassis_name);
+ free(port->aa_mac);
+ free(port->aa_chassis_name);
+ }
destroy_lport_addresses(&port->lrp_networks);
destroy_lport_addresses(&port->proxy_arp_addrs);
@@ -1433,6 +1441,32 @@ lrport_is_enabled(const struct nbrec_logical_router_port *lrport)
return !lrport->enabled || *lrport->enabled;
}
+static bool
+lrport_is_active_active(const struct nbrec_logical_router_port *lrport)
+{
+ if (!lrport) {
+ return false;
+ }
+ return smap_get_bool(&lrport->options, "active-active-lrp", false);
+}
+
+static const struct nbrec_logical_router_port*
+lsp_get_peer(struct ovsdb_idl_index *nbrec_lrp_by_name,
+ const struct nbrec_logical_switch_port *nbsp)
+{
+ if (!lsp_is_router(nbsp)) {
+ return NULL;
+ }
+
+ const char *peer_name = smap_get( ->options, "router-port");
+ if (!peer_name) {
+ return NULL;
+ }
+
+ return lrp_lookup_by_name(nbrec_lrp_by_name, peer_name);
+}
+
+
static bool
lsp_force_fdb_lookup(const struct ovn_port *op)
{
@@ -1462,6 +1496,18 @@ ovn_port_get_peer(const struct hmap *lr_ports, struct ovn_port *op)
return ovn_port_find(lr_ports, peer_name);
}
+static const char *
+ovn_port_get_mac(struct ovn_port *op)
+{
+ if (op->is_active_active) {
+ return op->aa_mac;
+ } else if (op->primary_port && op->primary_port->is_active_active) {
+ return op->primary_port->aa_mac;
+ } else {
+ return op->nbrp->mac;
+ }
+}
+
static void
ipam_insert_ip_for_datapath(struct ovn_datapath *od, uint32_t ip, bool dynamic)
{
@@ -2295,13 +2341,19 @@ join_logical_ports_lrp(struct hmap *ports,
return op;
}
+struct active_active_port {
+ const struct nbrec_logical_switch_port *nbsp;
+ const struct nbrec_logical_router_port *nbrp;
+ struct ovn_datapath *switch_dp;
+ struct ovn_datapath *router_dp;
+};
+
static struct ovn_port *
create_cr_port(struct ovn_port *op, struct hmap *ports,
struct ovs_list *both_dbs, struct ovs_list *nb_only)
{
- char *redirect_name = ovn_chassis_redirect_name(
- op->nbsp ? op->nbsp->name : op->nbrp->name);
+ char *redirect_name = ovn_chassis_redirect_name(op->key);
struct ovn_port *crp = ovn_port_find(ports, redirect_name);
if (crp && crp->sb && crp->sb->datapath == op->od->sb) {
@@ -2346,6 +2398,8 @@ peer_needs_cr_port_creation(struct ovn_port *op)
static void
join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
+ struct ovsdb_idl_index *nbrec_lrp_by_name,
+ struct ovsdb_idl_index *sbrec_chassis_by_name,
struct hmap *ls_datapaths, struct hmap *lr_datapaths,
struct hmap *ports, unsigned long *queue_id_bitmap,
struct hmap *tag_alloc_table, struct ovs_list *sb_only,
@@ -2355,6 +2409,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
ovs_list_init(nb_only);
ovs_list_init(both);
+ struct shash active_active_ports = SHASH_INITIALIZER(&active_active_ports);
+
const struct sbrec_port_binding *sb;
SBREC_PORT_BINDING_TABLE_FOR_EACH (sb, sbrec_pb_table) {
struct ovn_port *op = ovn_port_create(ports, sb->logical_port,
@@ -2371,6 +2427,20 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
= od->nbr->ports[i];
struct lport_addresses lrp_networks;
+
+ if (lrport_is_active_active(nbrp)) {
+ struct ovn_port *op = ovn_port_find_bound(ports, nbrp->name);
+ if (op) {
+ ovs_list_remove(&op->list);
+ }
+ struct active_active_port *aap = xzalloc(
+ sizeof(struct active_active_port));
+ aap->nbrp = nbrp;
+ aap->router_dp = od;
+ shash_add(&active_active_ports, nbrp->name, aap);
+ continue;
+ }
+
if (!extract_lrp_networks(nbrp, &lrp_networks)) {
static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(5, 1);
@@ -2388,6 +2458,16 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
for (size_t i = 0; i < od->nbs->n_ports; i++) {
const struct nbrec_logical_switch_port *nbsp
= od->nbs->ports[i];
+ const struct nbrec_logical_router_port *nbrp
+ = lsp_get_peer(nbrec_lrp_by_name, nbsp);
+ if (lrport_is_active_active(nbrp)) {
+ struct active_active_port *aap =
+ shash_find_data(&active_active_ports, nbrp->name);
+ ovs_assert(aap);
+ aap->nbsp = nbsp;
+ aap->switch_dp = od;
+ continue;
+ }
join_logical_ports_lsp(ports, nb_only, both, od, nbsp,
nbsp->name, queue_id_bitmap,
tag_alloc_table);
@@ -2466,6 +2546,103 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
}
}
+ /* Now we setup the active-active lrp/lsps */
+ struct shash_node *aa_snode;
+ SHASH_FOR_EACH (aa_snode, &active_active_ports) {
+ const struct active_active_port *aap = aa_snode->data;
+ const struct nbrec_logical_switch_port *nbsp = aap->nbsp;
+ const struct nbrec_logical_router_port *nbrp = aap->nbrp;
+ ovs_assert(nbrp);
+ ovs_assert(aap->switch_dp);
+ ovs_assert(aap->router_dp);
+
+ if (aap->switch_dp->n_localnet_ports != 1) {
+ static struct vlog_rate_limit rl
+ = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "active-active lrp '%s' is not connect to a "
+ "ls with exactly one localnet port", nbrp->name);
+ continue;
+ }
+
+ const struct ovn_port *localnet_port =
+ aap->switch_dp->localnet_ports[0];
+
+ const char *network_name =
+ smap_get(&localnet_port->nbsp->options, "network_name");
+ if (!network_name) {
+ static struct vlog_rate_limit rl
+ = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "active-active lrp '%s' has a localnet port "
+ "connected with no network_name", nbrp->name);
+ continue;
+ }
+
+ if (!nbrp->ha_chassis_group) {
+ static struct vlog_rate_limit rl
+ = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "missing 'ha_chassis_group' for"
+ " active-active-port %s", nbrp->name);
+ continue;
+ }
+
+ for (size_t i = 0; i < nbrp->ha_chassis_group->n_ha_chassis; i++) {
+ const struct nbrec_ha_chassis *hc
+ = nbrp->ha_chassis_group->ha_chassis[i];
+
+ const struct sbrec_chassis *chassis = chassis_lookup_by_name(
+ sbrec_chassis_by_name, hc->chassis_name);
+ if (!chassis) {
+ static struct vlog_rate_limit rl
+ = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "'ha_chassis_group' contains not found"
+ " chassis %s", hc->chassis_name);
+ continue;
+ }
+
+ struct chassis_aa_network networks;
+ if (!chassis_find_active_active_networks(chassis, network_name,
+ &networks)) {
+ static struct vlog_rate_limit rl
+ = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "chassis %s does not contain network"
+ " but it is in ha_chassis_group", chassis->name);
+ continue;
+ }
+
+ for (size_t j = 0; j < networks.n_addresses; j++) {
+ char *lrp_name = xasprintf("%s-%s-%"PRIuSIZE,
+ nbrp->name, chassis->name, j);
+ char *lsp_name = xasprintf("%s-%s-%"PRIuSIZE,
+ nbsp->name, chassis->name, j);
+ struct ovn_port *lrp =
+ join_logical_ports_lrp(ports, nb_only, both, &dgps,
+ aap->router_dp, nbrp,
+ lrp_name, &networks.addresses[j]);
+ struct ovn_port *lsp =
+ join_logical_ports_lsp(ports, nb_only, both,
+ aap->switch_dp, nbsp,
+ lsp_name, queue_id_bitmap,
+ tag_alloc_table);
+ free(lrp_name);
+ free(lsp_name);
+ if (!lrp || !lsp) {
+ continue;
+ }
+ lrp->peer = lsp;
+ lsp->peer = lrp;
+ lrp->is_active_active = true;
+ lsp->is_active_active = true;
+ lrp->aa_mac = xstrdup(networks.addresses[j].ea_s);
+ lrp->aa_chassis_name = xstrdup(chassis->name);
+ lsp->aa_chassis_name = xstrdup(chassis->name);
+ lrp->aa_chassis_index = j;
+ lsp->aa_chassis_index = j;
+ }
+ free(networks.network_name);
+ free(networks.addresses);
+ }
+ }
+
struct hmapx_node *hmapx_node;
HMAPX_FOR_EACH (hmapx_node, &dgps) {
op = hmapx_node->data;
@@ -2523,6 +2700,8 @@ join_logical_ports(const struct sbrec_port_binding_table *sbrec_pb_table,
HMAP_FOR_EACH (op, key_node, ports) {
ipam_add_port_addresses(op->od, op);
}
+
+ shash_destroy_free_data(&active_active_ports);
}
/* Returns an array of strings, each consisting of a MAC address followed
@@ -2876,6 +3055,51 @@ sync_ha_chassis_group_for_sbpb(
sbrec_port_binding_set_ha_chassis_group(pb, sb_ha_grp);
}
+static char *
+generate_ha_chassis_group_active_active(
+ struct ovsdb_idl_txn *ovnsb_txn,
+ struct ovsdb_idl_index *sbrec_chassis_by_name,
+ struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name,
+ const char *chassis_name,
+ const struct sbrec_port_binding *pb)
+{
+ bool new_sb_chassis_group = false;
+ char *chassis_group_name = xasprintf(
+ "active-active-fixed-%s", chassis_name);
+ const struct sbrec_ha_chassis_group *sb_ha_grp =
+ ha_chassis_group_lookup_by_name(
+ sbrec_ha_chassis_grp_by_name, chassis_group_name);
+
+ if (!sb_ha_grp) {
+ sb_ha_grp = sbrec_ha_chassis_group_insert(ovnsb_txn);
+ sbrec_ha_chassis_group_set_name(sb_ha_grp, chassis_group_name);
+ new_sb_chassis_group = true;
+ }
+
+ if (new_sb_chassis_group) {
+ struct sbrec_ha_chassis **sb_ha_chassis = NULL;
+ sb_ha_chassis = xcalloc(1, sizeof *sb_ha_chassis);
+ const struct sbrec_chassis *chassis =
+ chassis_lookup_by_name(sbrec_chassis_by_name, chassis_name);
+ sb_ha_chassis[0] = sbrec_ha_chassis_insert(ovnsb_txn);
+ /* It's perfectly ok if the chassis is NULL. This could
+ * happen when ovn-controller exits and removes its row
+ * from the chassis table in OVN SB DB. */
+ sbrec_ha_chassis_set_chassis(sb_ha_chassis[0], chassis);
+ sbrec_ha_chassis_set_priority(sb_ha_chassis[0], 1);
+ const struct smap external_ids =
+ SMAP_CONST1(&external_ids, "chassis-name",
+ chassis_name);
+ sbrec_ha_chassis_set_external_ids(sb_ha_chassis[0], &external_ids);
+ sbrec_ha_chassis_group_set_ha_chassis(sb_ha_grp, sb_ha_chassis,
+ 1);
+ free(sb_ha_chassis);
+ }
+
+ sbrec_port_binding_set_ha_chassis_group(pb, sb_ha_grp);
+ return chassis_group_name;
+}
+
/* This functions translates the gw chassis on the nb database
* to HA chassis group in the sb database entries.
*/
@@ -3130,14 +3354,29 @@ ovn_port_update_sbrec(struct ovsdb_idl_txn *ovnsb_txn,
"ignoring the latter.", op->nbrp->name);
}
- /* HA Chassis group is set. Ignore 'gateway_chassis'. */
- sync_ha_chassis_group_for_sbpb(ovnsb_txn,
- sbrec_chassis_by_name,
- sbrec_ha_chassis_grp_by_name,
- op->nbrp->ha_chassis_group,
- op->sb);
- sset_add(active_ha_chassis_grps,
- op->nbrp->ha_chassis_group->name);
+ if (op->primary_port && op->primary_port->is_active_active) {
+
+ /* Generate new HA Chassis group just bound to one node. */
+ char *ha_chassis_group =
+ generate_ha_chassis_group_active_active(ovnsb_txn,
+ sbrec_chassis_by_name,
+ sbrec_ha_chassis_grp_by_name,
+ op->primary_port->aa_chassis_name,
+ op->sb);
+ sset_add(active_ha_chassis_grps,
+ ha_chassis_group);
+ free(ha_chassis_group);
+ } else {
+
+ /* HA Chassis group is set. Ignore 'gateway_chassis'. */
+ sync_ha_chassis_group_for_sbpb(ovnsb_txn,
+ sbrec_chassis_by_name,
+ sbrec_ha_chassis_grp_by_name,
+ op->nbrp->ha_chassis_group,
+ op->sb);
+ sset_add(active_ha_chassis_grps,
+ op->nbrp->ha_chassis_group->name);
+ }
} else if (op->nbrp->n_gateway_chassis) {
/* Legacy gateway_chassis support.
* Create ha_chassis_group for the Northbound gateway_chassis
@@ -4252,6 +4491,7 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
const struct sbrec_mac_binding_table *sbrec_mac_binding_table,
const struct sbrec_ha_chassis_group_table *sbrec_ha_chassis_group_table,
const struct sbrec_route_table *sbrec_route_table,
+ struct ovsdb_idl_index *nbrec_lrp_by_name,
struct ovsdb_idl_index *sbrec_chassis_by_name,
struct ovsdb_idl_index *sbrec_chassis_by_hostname,
struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name,
@@ -4272,7 +4512,10 @@ build_ports(struct ovsdb_idl_txn *ovnsb_txn,
/* Borrow ls_ports for joining NB and SB for both LSPs and LRPs.
* We will split them later. */
struct hmap *ports = ls_ports;
- join_logical_ports(sbrec_port_binding_table, ls_datapaths, lr_datapaths,
+ join_logical_ports(sbrec_port_binding_table,
+ nbrec_lrp_by_name,
+ sbrec_chassis_by_name,
+ ls_datapaths, lr_datapaths,
ports, queue_id_bitmap,
&tag_alloc_table, &sb_only, &nb_only, &both);
@@ -12974,7 +13217,7 @@ build_lrouter_icmp_packet_toobig_admin_flows(
" (ip6 && icmp6.type == 2 && icmp6.code == 0)) &&"
" eth.dst == %s && !is_chassis_resident(%s) &&"
" flags.tunnel_rx == 1",
- op->nbrp->mac, op->cr_port->json_key);
+ ovn_port_get_mac(op), op->cr_port->json_key);
ds_clear(actions);
ds_put_format(actions, "outport <-> inport; inport = %s; next;",
op->json_key);
@@ -13017,7 +13260,7 @@ build_lswitch_icmp_packet_toobig_admin_flows(
"((ip4 && icmp4.type == 3 && icmp4.code == 4) ||"
" (ip6 && icmp6.type == 2 && icmp6.code == 0)) && "
"eth.src == %s && outport == %s && flags.tunnel_rx == 1",
- peer->nbrp->mac, op->json_key);
+ ovn_port_get_mac(peer), op->json_key);
ovn_lflow_add(lflows, op->od, S_SWITCH_IN_CHECK_PORT_SEC, 120,
ds_cstr(match), "outport <-> inport; next;",
op->lflow_ref);
@@ -13026,7 +13269,7 @@ build_lswitch_icmp_packet_toobig_admin_flows(
"((ip4 && icmp4.type == 3 && icmp4.code == 4) ||"
" (ip6 && icmp6.type == 2 && icmp6.code == 0)) && "
"eth.dst == %s && flags.tunnel_rx == 1",
- peer->nbrp->mac);
+ ovn_port_get_mac(peer));
ds_clear(actions);
ds_put_format(actions,
"outport <-> inport; next(pipeline=ingress,table=%d);",
@@ -19055,6 +19298,7 @@ ovnnb_db_run(struct northd_input *input_data,
input_data->sbrec_mac_binding_table,
input_data->sbrec_ha_chassis_group_table,
input_data->sbrec_route_table,
+ input_data->nbrec_lrp_by_name,
input_data->sbrec_chassis_by_name,
input_data->sbrec_chassis_by_hostname,
input_data->sbrec_ha_chassis_grp_by_name,
@@ -66,6 +66,7 @@ struct northd_input {
const struct chassis_features *features;
/* Indexes */
+ struct ovsdb_idl_index *nbrec_lrp_by_name;
struct ovsdb_idl_index *sbrec_chassis_by_name;
struct ovsdb_idl_index *sbrec_chassis_by_hostname;
struct ovsdb_idl_index *sbrec_ha_chassis_grp_by_name;
@@ -664,6 +665,15 @@ struct ovn_port {
/* Only used for the router type LSP whose peer is l3dgw_port */
bool enable_router_port_acl;
+ /* Used for active-active port bindings to store the data they where
+ * generated from */
+ bool is_active_active;
+ char *aa_chassis_name;
+ size_t aa_chassis_index;
+ /* The following value is only set on the lrp side of an
+ * active-active port binding */
+ char *aa_mac;
+
/* Reference of lflows generated for this ovn_port.
*
* This data is initialized and destroyed by the en_northd node, but
In case we find a LRP (or a LSP connected to a LRP) that has options:active-active-lrp set we ignore it during normal processing in join_logical_ports. We add an additional section at the end where we then use these ports to generate derived Port_Bindings for each LRP + LSP combination once for each matching ovn-aa-port-mappings entry. In the end this gives us the same result as if someone would have precreated a LRP + LSP combination for each ovn-aa-port-mappings in the northbound. However it allows our users to benefit from active-active routing without their CMS needing to know about this feature (besides the active-active-lrp setting). Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud> --- lib/automake.mk | 2 + lib/lrp-index.c | 43 +++++++ lib/lrp-index.h | 25 ++++ lib/ovn-util.c | 97 ++++++++++++++ lib/ovn-util.h | 11 ++ northd/en-northd.c | 4 + northd/inc-proc-northd.c | 6 + northd/northd.c | 272 +++++++++++++++++++++++++++++++++++++-- northd/northd.h | 10 ++ 9 files changed, 456 insertions(+), 14 deletions(-) create mode 100644 lib/lrp-index.c create mode 100644 lib/lrp-index.h