From 853c8bfd101109fce7b7422486ddaff4e2e6aa03 Mon Sep 17 00:00:00 2001
From: Numan Siddique <numans@ovn.org>
Date: Fri, 29 Jan 2021 14:46:30 +0530
Subject: [PATCH 07/16] MAC learning: Add a new FDB table in southbound db.
This patch
- Adds a new table 'FDB' in Southbound database.
- Adds a new pinctrl_handler action - ACTION_OPCODE_PUT_FDB
which learns the port-to-mac bindings and stores it in the
'FDB' table. This handler will be used later.
- Upcoming patch adds necessary OVN actions to learn the port-to-mac
bindings.
Unlike MAC_Binding Southbound table, FDB table stores the datapath
tunnel key and port key. This makes it easier for ovn-controller to
program the OF rules and it doesn't need to do any logical port
lookup in the Port_Binding table.
Acked-by: Mark Michelson <mmichels@redhat.com>
Signed-off-by: Numan Siddique <numans@ovn.org>
(cherry picked from upstream commit 6ec3b12590f9193659d549e30d96b1a22bbb1288)
Change-Id: Iaff80667e71d20fbab434fb3031b2222e22425aa
---
controller/mac-learn.c | 79 +++++++++++++++++++++++++++++
controller/mac-learn.h | 20 ++++++++
controller/ovn-controller.c | 5 ++
controller/pinctrl.c | 118 ++++++++++++++++++++++++++++++++++++++++++++
controller/pinctrl.h | 1 +
include/ovn/actions.h | 4 ++
ovn-sb.ovsschema | 17 ++++++-
ovn-sb.xml | 24 +++++++++
8 files changed, 266 insertions(+), 2 deletions(-)
diff --git a/controller/mac-learn.c b/controller/mac-learn.c
index 36a6d6e..27634dc 100644
--- a/controller/mac-learn.c
+++ b/controller/mac-learn.c
@@ -19,11 +19,13 @@
/* OpenvSwitch lib includes. */
#include "openvswitch/vlog.h"
+#include "lib/packets.h"
#include "lib/smap.h"
VLOG_DEFINE_THIS_MODULE(mac_learn);
#define MAX_MAC_BINDINGS 1000
+#define MAX_FDB_ENTRIES 1000
static size_t mac_binding_hash(uint32_t dp_key, uint32_t port_key,
struct in6_addr *);
@@ -31,7 +33,12 @@ static struct mac_binding *mac_binding_find(struct hmap *mac_bindings,
uint32_t dp_key,
uint32_t port_key,
struct in6_addr *ip, size_t hash);
+static size_t fdb_entry_hash(uint32_t dp_key, struct eth_addr *);
+static struct fdb_entry *fdb_entry_find(struct hmap *fdbs, uint32_t dp_key,
+ struct eth_addr *mac, size_t hash);
+
+/* mac_binding functions. */
void
ovn_mac_bindings_init(struct hmap *mac_bindings)
{
@@ -79,6 +86,55 @@ ovn_mac_binding_add(struct hmap *mac_bindings, uint32_t dp_key,
return mb;
}
+/* fdb functions. */
+void
+ovn_fdb_init(struct hmap *fdbs)
+{
+ hmap_init(fdbs);
+}
+
+void
+ovn_fdbs_flush(struct hmap *fdbs)
+{
+ struct fdb_entry *fdb_e;
+ HMAP_FOR_EACH_POP (fdb_e, hmap_node, fdbs) {
+ free(fdb_e);
+ }
+}
+
+void
+ovn_fdbs_destroy(struct hmap *fdbs)
+{
+ ovn_fdbs_flush(fdbs);
+ hmap_destroy(fdbs);
+}
+
+struct fdb_entry *
+ovn_fdb_add(struct hmap *fdbs, uint32_t dp_key, struct eth_addr mac,
+ uint32_t port_key)
+{
+ uint32_t hash = fdb_entry_hash(dp_key, &mac);
+
+ struct fdb_entry *fdb_e =
+ fdb_entry_find(fdbs, dp_key, &mac, hash);
+ if (!fdb_e) {
+ if (hmap_count(fdbs) >= MAX_FDB_ENTRIES) {
+ return NULL;
+ }
+
+ fdb_e = xzalloc(sizeof *fdb_e);
+ fdb_e->dp_key = dp_key;
+ fdb_e->mac = mac;
+ hmap_insert(fdbs, &fdb_e->hmap_node, hash);
+ }
+ fdb_e->port_key = port_key;
+
+ return fdb_e;
+
+}
+
+/* mac_binding related static functions. */
+
static size_t
mac_binding_hash(uint32_t dp_key, uint32_t port_key, struct in6_addr *ip)
{
@@ -99,3 +155,26 @@ mac_binding_find(struct hmap *mac_bindings, uint32_t dp_key,
return NULL;
}
+
+/* fdb related static functions. */
+
+static size_t
+fdb_entry_hash(uint32_t dp_key, struct eth_addr *mac)
+{
+ uint64_t mac64 = eth_addr_to_uint64(*mac);
+ return hash_2words(dp_key, hash_uint64(mac64));
+}
+
+static struct fdb_entry *
+fdb_entry_find(struct hmap *fdbs, uint32_t dp_key,
+ struct eth_addr *mac, size_t hash)
+{
+ struct fdb_entry *fdb_e;
+ HMAP_FOR_EACH_WITH_HASH (fdb_e, hmap_node, hash, fdbs) {
+ if (fdb_e->dp_key == dp_key && eth_addr_equals(fdb_e->mac, *mac)) {
+ return fdb_e;
+ }
+ }
+
+ return NULL;
+}
diff --git a/controller/mac-learn.h b/controller/mac-learn.h
index 3a8520c..7a7897e 100644
--- a/controller/mac-learn.h
+++ b/controller/mac-learn.h
@@ -43,4 +43,24 @@ struct mac_binding *ovn_mac_binding_add(struct hmap *mac_bindings,
struct eth_addr mac);
+
+struct fdb_entry {
+ struct hmap_node hmap_node; /* In a hmap. */
+
+ /* Key. */
+ uint32_t dp_key;
+ struct eth_addr mac;
+
+ /* value. */
+ uint32_t port_key;
+};
+
+void ovn_fdb_init(struct hmap *fdbs);
+void ovn_fdbs_flush(struct hmap *fdbs);
+void ovn_fdbs_destroy(struct hmap *fdbs);
+
+struct fdb_entry *ovn_fdb_add(struct hmap *fdbs,
+ uint32_t dp_key, struct eth_addr mac,
+ uint32_t port_key);
+
#endif /* OVN_MAC_LEARN_H */
\ No newline at end of file
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index fc2a767..cc002db 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -2471,6 +2471,10 @@ main(int argc, char *argv[])
= ip_mcast_index_create(ovnsb_idl_loop.idl);
struct ovsdb_idl_index *sbrec_igmp_group
= igmp_group_index_create(ovnsb_idl_loop.idl);
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac
+ = ovsdb_idl_index_create2(ovnsb_idl_loop.idl,
+ &sbrec_fdb_col_mac,
+ &sbrec_fdb_col_dp_key);
ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
ovsdb_idl_omit_alert(ovnsb_idl_loop.idl,
@@ -2864,6 +2868,7 @@ main(int argc, char *argv[])
sbrec_mac_binding_by_lport_ip,
sbrec_igmp_group,
sbrec_ip_multicast,
+ sbrec_fdb_by_dp_key_mac,
sbrec_dns_table_get(ovnsb_idl_loop.idl),
sbrec_controller_event_table_get(
ovnsb_idl_loop.idl),
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 0f258ba..3dc1038 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -340,6 +340,22 @@ static void bfd_monitor_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
const struct sbrec_chassis *chassis,
const struct sset *active_tunnels)
OVS_REQUIRES(pinctrl_mutex);
+static void init_fdb_entries(void);
+static void destroy_fdb_entries(void);
+static const struct sbrec_fdb *fdb_lookup(
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
+ uint32_t dp_key, const char *mac);
+static void run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn,
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
+ const struct fdb_entry *fdb_e)
+ OVS_REQUIRES(pinctrl_mutex);
+static void run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn,
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac)
+ OVS_REQUIRES(pinctrl_mutex);
+static void wait_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn);
+static void pinctrl_handle_put_fdb(const struct flow *md,
+ const struct flow *headers)
+ OVS_REQUIRES(pinctrl_mutex);
COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);
COVERAGE_DEFINE(pinctrl_drop_buffered_packets_map);
@@ -506,6 +522,7 @@ pinctrl_init(void)
init_put_vport_bindings();
init_svc_monitors();
bfd_monitor_init();
+ init_fdb_entries();
pinctrl.br_int_name = NULL;
pinctrl_handler_seq = seq_create();
pinctrl_main_seq = seq_create();
@@ -3020,6 +3037,12 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
ovs_mutex_unlock(&pinctrl_mutex);
break;
+ case ACTION_OPCODE_PUT_FDB:
+ ovs_mutex_lock(&pinctrl_mutex);
+ pinctrl_handle_put_fdb(&pin.flow_metadata.flow, &headers);
+ ovs_mutex_unlock(&pinctrl_mutex);
+ break;
+
case ACTION_OPCODE_PUT_DHCPV6_OPTS:
pinctrl_handle_put_dhcpv6_opts(swconn, &packet, &pin, &userdata,
&continuation);
@@ -3297,6 +3320,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
struct ovsdb_idl_index *sbrec_igmp_groups,
struct ovsdb_idl_index *sbrec_ip_multicast_opts,
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
const struct sbrec_dns_table *dns_table,
const struct sbrec_controller_event_table *ce_table,
const struct sbrec_service_monitor_table *svc_mon_table,
@@ -3333,6 +3357,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
chassis);
bfd_monitor_run(ovnsb_idl_txn, bfd_table, sbrec_port_binding_by_name,
chassis, active_tunnels);
+ run_put_fdbs(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac);
ovs_mutex_unlock(&pinctrl_mutex);
}
@@ -3856,6 +3881,7 @@ pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn)
wait_put_vport_bindings(ovnsb_idl_txn);
int64_t new_seq = seq_read(pinctrl_main_seq);
seq_wait(pinctrl_main_seq, new_seq);
+ wait_put_fdbs(ovnsb_idl_txn);
}
/* Called by ovn-controller. */
@@ -3877,6 +3903,7 @@ pinctrl_destroy(void)
ip_mcast_snoop_destroy();
destroy_svc_monitors();
bfd_monitor_destroy();
+ destroy_fdb_entries();
seq_destroy(pinctrl_main_seq);
seq_destroy(pinctrl_handler_seq);
}
@@ -7495,3 +7522,94 @@ pinctrl_handle_svc_check(struct rconn *swconn, const struct flow *ip_flow,
svc_mon->next_send_time = time_msec() + svc_mon->interval;
}
}
+
+static struct hmap put_fdbs;
+
+/* MAC learning (fdb) related functions. Runs within the main
+ * ovn-controller thread context. */
+
+static void
+init_fdb_entries(void)
+{
+ ovn_fdb_init(&put_fdbs);
+}
+
+static void
+destroy_fdb_entries(void)
+{
+ ovn_fdbs_destroy(&put_fdbs);
+}
+
+static const struct sbrec_fdb *
+fdb_lookup(struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac, uint32_t dp_key,
+ const char *mac)
+{
+ struct sbrec_fdb *fdb = sbrec_fdb_index_init_row(sbrec_fdb_by_dp_key_mac);
+ sbrec_fdb_index_set_dp_key(fdb, dp_key);
+ sbrec_fdb_index_set_mac(fdb, mac);
+
+ const struct sbrec_fdb *retval
+ = sbrec_fdb_index_find(sbrec_fdb_by_dp_key_mac, fdb);
+
+ sbrec_fdb_index_destroy_row(fdb);
+
+ return retval;
+}
+
+static void
+run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn,
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
+ const struct fdb_entry *fdb_e)
+{
+ /* Convert ethernet argument to string form for database. */
+ char mac_string[ETH_ADDR_STRLEN + 1];
+ snprintf(mac_string, sizeof mac_string,
+ ETH_ADDR_FMT, ETH_ADDR_ARGS(fdb_e->mac));
+
+ /* Update or add an FDB entry. */
+ const struct sbrec_fdb *sb_fdb =
+ fdb_lookup(sbrec_fdb_by_dp_key_mac, fdb_e->dp_key, mac_string);
+ if (!sb_fdb) {
+ sb_fdb = sbrec_fdb_insert(ovnsb_idl_txn);
+ sbrec_fdb_set_dp_key(sb_fdb, fdb_e->dp_key);
+ sbrec_fdb_set_mac(sb_fdb, mac_string);
+ }
+ sbrec_fdb_set_port_key(sb_fdb, fdb_e->port_key);
+}
+
+static void
+run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn,
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac)
+ OVS_REQUIRES(pinctrl_mutex)
+{
+ if (!ovnsb_idl_txn) {
+ return;
+ }
+
+ const struct fdb_entry *fdb_e;
+ HMAP_FOR_EACH (fdb_e, hmap_node, &put_fdbs) {
+ run_put_fdb(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac, fdb_e);
+ }
+ ovn_fdbs_flush(&put_fdbs);
+}
+
+
+static void
+wait_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn)
+{
+ if (ovnsb_idl_txn && !hmap_is_empty(&put_fdbs)) {
+ poll_immediate_wake();
+ }
+}
+
+/* Called with in the pinctrl_handler thread context. */
+static void
+pinctrl_handle_put_fdb(const struct flow *md, const struct flow *headers)
+ OVS_REQUIRES(pinctrl_mutex)
+{
+ uint32_t dp_key = ntohll(md->metadata);
+ uint32_t port_key = md->regs[MFF_LOG_INPORT - MFF_REG0];
+
+ ovn_fdb_add(&put_fdbs, dp_key, headers->dl_src, port_key);
+ notify_pinctrl_main();
+}
diff --git a/controller/pinctrl.h b/controller/pinctrl.h
index 8555d98..cc0a519 100644
--- a/controller/pinctrl.h
+++ b/controller/pinctrl.h
@@ -42,6 +42,7 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
struct ovsdb_idl_index *sbrec_igmp_groups,
struct ovsdb_idl_index *sbrec_ip_multicast_opts,
+ struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
const struct sbrec_dns_table *,
const struct sbrec_controller_event_table *,
const struct sbrec_service_monitor_table *,
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index be87e61..a2d28c6 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -641,6 +641,10 @@ enum action_opcode {
* The actions, in OpenFlow 1.3 format, follow the action_header.
*/
ACTION_OPCODE_SCTP_ABORT,
+
+ /* put_fdb(inport, eth.src).
+ */
+ ACTION_OPCODE_PUT_FDB,
};
/* Header. */
diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
index 0d20f08..246e390 100644
--- a/ovn-sb.ovsschema
+++ b/ovn-sb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Southbound",
- "version": "20.15.0",
- "cksum": "539683023 25965",
+ "version": "20.16.0",
+ "cksum": "1219580357 26536",
"tables": {
"SB_Global": {
"columns": {
@@ -513,6 +513,19 @@
"type": {"key": "string", "value": "string",
"min": 0, "max": "unlimited"}}},
"indexes": [["logical_port", "dst_ip", "src_port", "disc"]],
+ "isRoot": true},
+ "FDB": {
+ "columns": {
+ "mac": {"type": "string"},
+ "dp_key": {
+ "type": {"key": {"type": "integer",
+ "minInteger": 1,
+ "maxInteger": 16777215}}},
+ "port_key": {
+ "type": {"key": {"type": "integer",
+ "minInteger": 1,
+ "maxInteger": 16777215}}}},
+ "indexes": [["mac", "dp_key"]],
"isRoot": true}
}
}
diff --git a/ovn-sb.xml b/ovn-sb.xml
index 2f251bd..b8912b3 100644
--- a/ovn-sb.xml
+++ b/ovn-sb.xml
@@ -4330,4 +4330,28 @@ tcp.flags = RST;
</column>
</group>
</table>
+
+ <table name="FDB" title="Port to MAC bindings">
+ <p>
+ This table is primarily used to learn the MACs observed on a VIF
+ which belongs to a <code>Logical_Switch_Port</code> record in
+ <code>OVN_Northbound</code> whose port security is disabled
+ and 'unknown' address set. If port security is disabled on a
+ <code>Logical_Switch_Port</code> record, OVN should allow traffic
+ with any source mac from the VIF. This table will be used to deliver
+ a packet to the VIF, If a packet's <code>eth.dst</code> is learnt.
+ </p>
+
+ <column name="mac">
+ The learnt mac address.
+ </column>
+
+ <column name="dp_key">
+ The key of the datapath on which this FDB was learnt.
+ </column>
+
+ <column name="port_key">
+ The key of the port binding on which this FDB was learnt.
+ </column>
+ </table>
</database>
--
1.8.3.1