@@ -36,8 +36,6 @@ controller_ovn_controller_SOURCES = \
controller/ovn-controller.h \
controller/physical.c \
controller/physical.h \
- controller/mac-learn.c \
- controller/mac-learn.h \
controller/local_data.c \
controller/local_data.h \
controller/ovsport.h \
@@ -25,29 +25,20 @@
VLOG_DEFINE_THIS_MODULE(mac_cache);
+#define MAX_BUFFERED_PACKETS 1000
+#define BUFFER_QUEUE_DEPTH 4
+#define BUFFERED_PACKETS_TIMEOUT_MS 10000
+#define BUFFERED_PACKETS_LOOKUP_MS 100
+
static uint32_t
-mac_cache_mb_data_hash(const struct mac_cache_mb_data *mb_data);
+mac_binding_data_hash(const struct mac_binding_data *mb_data);
static inline bool
-mac_cache_mb_data_equals(const struct mac_cache_mb_data *a,
- const struct mac_cache_mb_data *b);
-static struct mac_cache_mac_binding *
-mac_cache_mac_binding_find(struct mac_cache_data *data,
- const struct mac_cache_mb_data *mb_data);
-static bool
-mac_cache_mb_data_from_sbrec(struct mac_cache_mb_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name);
+mac_binding_data_equals(const struct mac_binding_data *a,
+ const struct mac_binding_data *b);
static uint32_t
-mac_cache_fdb_data_hash(const struct mac_cache_fdb_data *fdb_data);
+fdb_data_hash(const struct fdb_data *fdb_data);
static inline bool
-mac_cache_fdb_data_equals(const struct mac_cache_fdb_data *a,
- const struct mac_cache_fdb_data *b);
-static bool
-mac_cache_fdb_data_from_sbrec(struct mac_cache_fdb_data *data,
- const struct sbrec_fdb *fdb);
-static struct mac_cache_fdb *
-mac_cache_fdb_find(struct mac_cache_data *data,
- const struct mac_cache_fdb_data *fdb_data);
+fdb_data_equals(const struct fdb_data *a, const struct fdb_data *b);
static struct mac_cache_threshold *
mac_cache_threshold_find(struct hmap *thresholds, const struct uuid *uuid);
static uint64_t
@@ -59,6 +50,23 @@ mac_cache_threshold_remove(struct hmap *thresholds,
static void
mac_cache_update_req_delay(struct hmap *thresholds, uint64_t *req_delay);
+static struct buffered_packets *
+buffered_packets_find(struct buffered_packets_ctx *ctx,
+ const struct mac_binding_data *mb_data);
+
+static void
+buffered_packets_remove(struct buffered_packets_ctx *ctx,
+ struct buffered_packets *bp);
+
+static void
+buffered_packets_db_lookup(struct buffered_packets *bp,
+ struct ds *ip, struct eth_addr *mac,
+ struct ovsdb_idl_index *sbrec_pb_by_key,
+ struct ovsdb_idl_index *sbrec_dp_by_key,
+ struct ovsdb_idl_index *sbrec_pb_by_name,
+ struct ovsdb_idl_index *sbrec_mb_by_lport_ip);
+
+/* Thresholds. */
bool
mac_cache_threshold_add(struct mac_cache_data *data,
const struct sbrec_datapath_binding *dp,
@@ -113,50 +121,78 @@ mac_cache_thresholds_clear(struct mac_cache_data *data)
}
}
-void
-mac_cache_mac_binding_add(struct mac_cache_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name)
-{
- struct mac_cache_mb_data mb_data;
- if (!mac_cache_mb_data_from_sbrec(&mb_data, mb, sbrec_pb_by_name)) {
- return;
- }
+/* MAC binding. */
+struct mac_binding *
+mac_binding_add(struct hmap *map, struct mac_binding_data mb_data,
+ long long timestamp) {
- struct mac_cache_mac_binding *mc_mb = mac_cache_mac_binding_find(data,
- &mb_data);
- if (!mc_mb) {
- mc_mb = xmalloc(sizeof *mc_mb);
- hmap_insert(&data->mac_bindings, &mc_mb->hmap_node,
- mac_cache_mb_data_hash(&mb_data));
+ struct mac_binding *mb = mac_binding_find(map, &mb_data);
+ if (!mb) {
+ mb = xmalloc(sizeof *mb);
+ mb->sbrec_mb = NULL;
+ hmap_insert(map, &mb->hmap_node, mac_binding_data_hash(&mb_data));
}
- mc_mb->sbrec_mb = mb;
- mc_mb->data = mb_data;
+ mb->data = mb_data;
+ mb->timestamp = timestamp;
+
+ return mb;
}
void
-mac_cache_mac_binding_remove(struct mac_cache_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name)
-{
- struct mac_cache_mb_data mb_data;
- if (!mac_cache_mb_data_from_sbrec(&mb_data, mb, sbrec_pb_by_name)) {
- return;
+mac_binding_remove(struct hmap *map, struct mac_binding *mb) {
+ hmap_remove(map, &mb->hmap_node);
+ free(mb);
+}
+
+struct mac_binding *
+mac_binding_find(const struct hmap *map,
+ const struct mac_binding_data *mb_data) {
+ uint32_t hash = mac_binding_data_hash(mb_data);
+
+ struct mac_binding *mb;
+ HMAP_FOR_EACH_WITH_HASH (mb, hmap_node, hash, map) {
+ if (mac_binding_data_equals(&mb->data, mb_data)) {
+ return mb;
+ }
}
- struct mac_cache_mac_binding *mc_mb = mac_cache_mac_binding_find(data,
- &mb_data);
- if (!mc_mb) {
- return;
+ return NULL;
+}
+
+bool
+mac_binding_data_from_sbrec(struct mac_binding_data *data,
+ const struct sbrec_mac_binding *mb,
+ struct ovsdb_idl_index *sbrec_pb_by_name)
+{
+ const struct sbrec_port_binding *pb =
+ lport_lookup_by_name(sbrec_pb_by_name, mb->logical_port);
+
+ if (!pb || !pb->datapath || !ip46_parse(mb->ip, &data->ip) ||
+ !eth_addr_from_string(mb->mac, &data->mac)) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "Couldn't parse MAC binding: ip=%s, mac=%s, "
+ "logical_port=%s", mb->ip, mb->mac, mb->logical_port);
+ return false;
}
- hmap_remove(&data->mac_bindings, &mc_mb->hmap_node);
- free(mc_mb);
+ data->dp_key = mb->datapath->tunnel_key;
+ data->port_key = pb->tunnel_key;
+
+ return true;
+}
+
+void
+mac_bindings_clear(struct hmap *map)
+{
+ struct mac_binding *mb;
+ HMAP_FOR_EACH_POP (mb, hmap_node, map) {
+ free(mb);
+ }
}
bool
-mac_cache_sb_mac_binding_updated(const struct sbrec_mac_binding *mb)
+sb_mac_binding_updated(const struct sbrec_mac_binding *mb)
{
bool updated = false;
for (size_t i = 0; i < SBREC_MAC_BINDING_N_COLUMNS; i++) {
@@ -171,56 +207,78 @@ mac_cache_sb_mac_binding_updated(const struct sbrec_mac_binding *mb)
return updated || sbrec_mac_binding_is_deleted(mb);
}
-void
-mac_cache_mac_bindings_clear(struct mac_cache_data *data)
-{
- struct mac_cache_mac_binding *mc_mb;
- HMAP_FOR_EACH_POP (mc_mb, hmap_node, &data->mac_bindings) {
- free(mc_mb);
+const struct sbrec_mac_binding *
+mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
+ const char *logical_port, const char *ip) {
+ struct sbrec_mac_binding *mb =
+ sbrec_mac_binding_index_init_row(sbrec_mac_binding_by_lport_ip);
+ sbrec_mac_binding_index_set_logical_port(mb, logical_port);
+ sbrec_mac_binding_index_set_ip(mb, ip);
+
+ const struct sbrec_mac_binding *retval =
+ sbrec_mac_binding_index_find(sbrec_mac_binding_by_lport_ip, mb);
+
+ sbrec_mac_binding_index_destroy_row(mb);
+
+ return retval;
+}
+
+/* FDB. */
+struct fdb *
+fdb_add(struct hmap *map, struct fdb_data fdb_data) {
+ struct fdb *fdb = fdb_find(map, &fdb_data);
+
+ if (!fdb) {
+ fdb = xmalloc(sizeof *fdb);
+ fdb->sbrec_fdb = NULL;
+ fdb->dp_uuid = UUID_ZERO;
+ hmap_insert(map, &fdb->hmap_node, fdb_data_hash(&fdb_data));
}
+
+ fdb->data = fdb_data;
+
+ return fdb;
}
void
-mac_cache_fdb_add(struct mac_cache_data *data, const struct sbrec_fdb *fdb,
- struct uuid dp_uuid)
+fdb_remove(struct hmap *map, struct fdb *fdb)
{
- struct mac_cache_fdb_data fdb_data;
- if (!mac_cache_fdb_data_from_sbrec(&fdb_data, fdb)) {
- return;
- }
-
- struct mac_cache_fdb *mc_fdb = mac_cache_fdb_find(data, &fdb_data);
+ hmap_remove(map, &fdb->hmap_node);
+ free(fdb);
+}
- if (!mc_fdb) {
- mc_fdb = xmalloc(sizeof *mc_fdb);
- hmap_insert(&data->fdbs, &mc_fdb->hmap_node,
- mac_cache_fdb_data_hash(&fdb_data));
+bool
+fdb_data_from_sbrec(struct fdb_data *data, const struct sbrec_fdb *fdb)
+{
+ if (!eth_addr_from_string(fdb->mac, &data->mac)) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
+ VLOG_WARN_RL(&rl, "Couldn't parse FDB: mac=%s", fdb->mac);
+ return false;
}
- mc_fdb->sbrec_fdb = fdb;
- mc_fdb->data = fdb_data;
- mc_fdb->dp_uuid = dp_uuid;
+ data->dp_key = fdb->dp_key;
+ data->port_key = fdb->port_key;
+
+ return true;
}
-void
-mac_cache_fdb_remove(struct mac_cache_data *data, const struct sbrec_fdb *fdb)
+struct fdb *
+fdb_find(const struct hmap *map, const struct fdb_data *fdb_data)
{
- struct mac_cache_fdb_data fdb_data;
- if (!mac_cache_fdb_data_from_sbrec(&fdb_data, fdb)) {
- return;
- }
+ uint32_t hash = fdb_data_hash(fdb_data);
- struct mac_cache_fdb *mc_fdb = mac_cache_fdb_find(data, &fdb_data);
- if (!mc_fdb) {
- return;
+ struct fdb *fdb;
+ HMAP_FOR_EACH_WITH_HASH (fdb, hmap_node, hash, map) {
+ if (fdb_data_equals(&fdb->data, fdb_data)) {
+ return fdb;
+ }
}
- hmap_remove(&data->fdbs, &mc_fdb->hmap_node);
- free(mc_fdb);
+ return NULL;
}
bool
-mac_cache_sb_fdb_updated(const struct sbrec_fdb *fdb)
+sb_fdb_updated(const struct sbrec_fdb *fdb)
{
bool updated = false;
for (size_t i = 0; i < SBREC_FDB_N_COLUMNS; i++) {
@@ -236,11 +294,11 @@ mac_cache_sb_fdb_updated(const struct sbrec_fdb *fdb)
}
void
-mac_cache_fdbs_clear(struct mac_cache_data *data)
+fdbs_clear(struct hmap *map)
{
- struct mac_cache_fdb *mc_fdb;
- HMAP_FOR_EACH_POP (mc_fdb, hmap_node, &data->fdbs) {
- free(mc_fdb);
+ struct fdb *fdb;
+ HMAP_FOR_EACH_POP (fdb, hmap_node, map) {
+ free(fdb);
}
}
@@ -251,20 +309,21 @@ struct mac_cache_stats {
union {
/* Common data to identify MAC binding. */
- struct mac_cache_mb_data mb;
+ struct mac_binding_data mb;
/* Common data to identify FDB. */
- struct mac_cache_fdb_data fdb;
+ struct fdb_data fdb;
} data;
};
+/* MAC binding stat processing. */
void
-mac_cache_mb_stats_process_flow_stats(struct ovs_list *stats_list,
- struct ofputil_flow_stats *ofp_stats)
+mac_binding_stats_process_flow_stats(struct ovs_list *stats_list,
+ struct ofputil_flow_stats *ofp_stats)
{
struct mac_cache_stats *stats = xmalloc(sizeof *stats);
stats->idle_age_ms = ofp_stats->idle_age * 1000;
- stats->data.mb = (struct mac_cache_mb_data) {
+ stats->data.mb = (struct mac_binding_data) {
.port_key = ofp_stats->match.flow.regs[MFF_LOG_INPORT - MFF_REG0],
.dp_key = ntohll(ofp_stats->match.flow.metadata),
.mac = ofp_stats->match.flow.dl_src
@@ -280,8 +339,8 @@ mac_cache_mb_stats_process_flow_stats(struct ovs_list *stats_list,
}
void
-mac_cache_mb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
- void *data)
+mac_binding_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
+ void *data)
{
struct mac_cache_data *cache_data = data;
struct hmap *thresholds = &cache_data->thresholds[MAC_CACHE_MAC_BINDING];
@@ -289,14 +348,14 @@ mac_cache_mb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
struct mac_cache_stats *stats;
LIST_FOR_EACH_POP (stats, list_node, stats_list) {
- struct mac_cache_mac_binding *mc_mb =
- mac_cache_mac_binding_find(cache_data, &stats->data.mb);
- if (!mc_mb) {
+ struct mac_binding *mb = mac_binding_find(&cache_data->mac_bindings,
+ &stats->data.mb);
+ if (!mb) {
free(stats);
continue;
}
- struct uuid *dp_uuid = &mc_mb->sbrec_mb->datapath->header_.uuid;
+ struct uuid *dp_uuid = &mb->sbrec_mb->datapath->header_.uuid;
struct mac_cache_threshold *threshold =
mac_cache_threshold_find(thresholds, dp_uuid);
@@ -304,9 +363,9 @@ mac_cache_mb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
* used on this chassis. Also make sure that we don't update the
* timestamp more than once during the dump period. */
if (stats->idle_age_ms < threshold->value &&
- (timewall_now - mc_mb->sbrec_mb->timestamp) >=
+ (timewall_now - mb->sbrec_mb->timestamp) >=
threshold->dump_period) {
- sbrec_mac_binding_set_timestamp(mc_mb->sbrec_mb, timewall_now);
+ sbrec_mac_binding_set_timestamp(mb->sbrec_mb, timewall_now);
}
free(stats);
@@ -315,14 +374,15 @@ mac_cache_mb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
mac_cache_update_req_delay(thresholds, req_delay);
}
+/* FDB stat processing. */
void
-mac_cache_fdb_stats_process_flow_stats(struct ovs_list *stats_list,
- struct ofputil_flow_stats *ofp_stats)
+fdb_stats_process_flow_stats(struct ovs_list *stats_list,
+ struct ofputil_flow_stats *ofp_stats)
{
struct mac_cache_stats *stats = xmalloc(sizeof *stats);
stats->idle_age_ms = ofp_stats->idle_age * 1000;
- stats->data.fdb = (struct mac_cache_fdb_data) {
+ stats->data.fdb = (struct fdb_data) {
.port_key = ofp_stats->match.flow.regs[MFF_LOG_INPORT - MFF_REG0],
.dp_key = ntohll(ofp_stats->match.flow.metadata),
.mac = ofp_stats->match.flow.dl_src
@@ -332,8 +392,8 @@ mac_cache_fdb_stats_process_flow_stats(struct ovs_list *stats_list,
}
void
-mac_cache_fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
- void *data)
+fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
+ void *data)
{
struct mac_cache_data *cache_data = data;
struct hmap *thresholds = &cache_data->thresholds[MAC_CACHE_FDB];
@@ -341,22 +401,22 @@ mac_cache_fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
struct mac_cache_stats *stats;
LIST_FOR_EACH_POP (stats, list_node, stats_list) {
- struct mac_cache_fdb *mc_fdb = mac_cache_fdb_find(cache_data,
- &stats->data.fdb);
- if (!mc_fdb) {
+ struct fdb *fdb = fdb_find(&cache_data->fdbs, &stats->data.fdb);
+
+ if (!fdb) {
free(stats);
continue;
}
struct mac_cache_threshold *threshold =
- mac_cache_threshold_find(thresholds, &mc_fdb->dp_uuid);
+ mac_cache_threshold_find(thresholds, &fdb->dp_uuid);
/* If "idle_age" is under threshold it means that the mac binding is
* used on this chassis. Also make sure that we don't update the
* timestamp more than once during the dump period. */
if (stats->idle_age_ms < threshold->value &&
- (timewall_now - mc_fdb->sbrec_fdb->timestamp) >=
+ (timewall_now - fdb->sbrec_fdb->timestamp) >=
threshold->dump_period) {
- sbrec_fdb_set_timestamp(mc_fdb->sbrec_fdb, timewall_now);
+ sbrec_fdb_set_timestamp(fdb->sbrec_fdb, timewall_now);
}
free(stats);
@@ -365,130 +425,207 @@ mac_cache_fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
mac_cache_update_req_delay(thresholds, req_delay);
}
+/* Packet buffering. */
+struct bp_packet_data *
+bp_packet_data_create(const struct ofputil_packet_in *pin,
+ const struct ofpbuf *continuation) {
+ struct bp_packet_data *pd = xmalloc(sizeof *pd);
+
+ pd->pin = (struct ofputil_packet_in) {
+ .packet = xmemdup(pin->packet, pin->packet_len),
+ .packet_len = pin->packet_len,
+ .flow_metadata = pin->flow_metadata,
+ .reason = pin->reason,
+ .table_id = pin->table_id,
+ .cookie = pin->cookie,
+ /* Userdata are empty on purpose,
+ * it is not needed for the continuation. */
+ .userdata = NULL,
+ .userdata_len = 0,
+ };
+ pd->continuation = ofpbuf_clone(continuation);
+
+ return pd;
+}
+
+
void
-mac_cache_stats_destroy(struct ovs_list *stats_list)
-{
- struct mac_cache_stats *stats;
- LIST_FOR_EACH_POP (stats, list_node, stats_list) {
- free(stats);
- }
+bp_packet_data_destroy(struct bp_packet_data *pd) {
+ free(pd->pin.packet);
+ ofpbuf_delete(pd->continuation);
+ free(pd);
}
-static uint32_t
-mac_cache_mb_data_hash(const struct mac_cache_mb_data *mb_data)
-{
- uint32_t hash = 0;
+struct buffered_packets *
+buffered_packets_add(struct buffered_packets_ctx *ctx,
+ struct mac_binding_data mb_data) {
+ uint32_t hash = mac_binding_data_hash(&mb_data);
- hash = hash_add(hash, mb_data->port_key);
- hash = hash_add(hash, mb_data->dp_key);
- hash = hash_add_in6_addr(hash, &mb_data->ip);
- hash = hash_add64(hash, eth_addr_to_uint64(mb_data->mac));
+ struct buffered_packets *bp = buffered_packets_find(ctx, &mb_data);
+ if (!bp) {
+ if (hmap_count(&ctx->buffered_packets) >= MAX_BUFFERED_PACKETS) {
+ return NULL;
+ }
+
+ bp = xmalloc(sizeof *bp);
+ hmap_insert(&ctx->buffered_packets, &bp->hmap_node, hash);
+ bp->mb_data = mb_data;
+ /* Schedule the freshly added buffered packet to do lookup
+ * immediately. */
+ bp->lookup_at_ms = 0;
+ ovs_list_init(&bp->queue);
+ }
- return hash_finish(hash, 32);
+ bp->expire_at_ms = time_msec() + BUFFERED_PACKETS_TIMEOUT_MS;
+
+ return bp;
}
-static inline bool
-mac_cache_mb_data_equals(const struct mac_cache_mb_data *a,
- const struct mac_cache_mb_data *b)
-{
- return a->port_key == b->port_key &&
- a->dp_key == b->dp_key &&
- ipv6_addr_equals(&a->ip, &b->ip) &&
- eth_addr_equals(a->mac, b->mac);
+void
+buffered_packets_packet_data_enqueue(struct buffered_packets *bp,
+ struct bp_packet_data *pd) {
+ if (ovs_list_size(&bp->queue) == BUFFER_QUEUE_DEPTH) {
+ struct bp_packet_data *p = CONTAINER_OF(ovs_list_pop_front(&bp->queue),
+ struct bp_packet_data, node);
+
+ bp_packet_data_destroy(p);
+ }
+ ovs_list_push_back(&bp->queue, &pd->node);
}
-static bool
-mac_cache_mb_data_from_sbrec(struct mac_cache_mb_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name)
-{
- const struct sbrec_port_binding *pb =
- lport_lookup_by_name(sbrec_pb_by_name, mb->logical_port);
+void
+buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
+ const struct hmap *recent_mbs,
+ struct ovsdb_idl_index *sbrec_pb_by_key,
+ struct ovsdb_idl_index *sbrec_dp_by_key,
+ struct ovsdb_idl_index *sbrec_pb_by_name,
+ struct ovsdb_idl_index *sbrec_mb_by_lport_ip) {
+ struct ds ip = DS_EMPTY_INITIALIZER;
+ long long now = time_msec();
+
+ struct buffered_packets *bp;
+ HMAP_FOR_EACH_SAFE (bp, hmap_node, &ctx->buffered_packets) {
+ struct eth_addr mac = eth_addr_zero;
+ /* Remove expired buffered packets. */
+ if (now > bp->expire_at_ms) {
+ buffered_packets_remove(ctx, bp);
+ continue;
+ }
- if (!pb || !pb->datapath || !ip46_parse(mb->ip, &data->ip) ||
- !eth_addr_from_string(mb->mac, &data->mac)) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
- VLOG_WARN_RL(&rl, "Couldn't parse MAC binding: ip=%s, mac=%s, "
- "logical_port=%s", mb->ip, mb->mac, mb->logical_port);
- return false;
+ struct mac_binding *mb = mac_binding_find(recent_mbs, &bp->mb_data);
+ if (mb) {
+ mac = mb->data.mac;
+ } else if (now >= bp->lookup_at_ms) {
+ /* Check if we can do a full lookup. */
+ buffered_packets_db_lookup(bp, &ip, &mac, sbrec_pb_by_key,
+ sbrec_dp_by_key, sbrec_pb_by_name,
+ sbrec_mb_by_lport_ip);
+ /* Schedule next lookup even if we found the MAC address,
+ * if the address was found this struct will be deleted anyway. */
+ bp->lookup_at_ms = now + BUFFERED_PACKETS_LOOKUP_MS;
+ }
+
+ if (eth_addr_is_zero(mac)) {
+ continue;
+ }
+
+ struct bp_packet_data *pd;
+ LIST_FOR_EACH_POP (pd, node, &bp->queue) {
+ struct dp_packet packet;
+ dp_packet_use_const(&packet, pd->pin.packet, pd->pin.packet_len);
+
+ struct eth_header *eth = dp_packet_data(&packet);
+ eth->eth_dst = mac;
+
+ ovs_list_push_back(&ctx->ready_packets_data, &pd->node);
+ }
+
+ buffered_packets_remove(ctx, bp);
}
- data->dp_key = mb->datapath->tunnel_key;
- data->port_key = pb->tunnel_key;
+ ds_destroy(&ip);
+}
- return true;
+bool
+buffered_packets_ctx_is_ready_to_send(struct buffered_packets_ctx *ctx) {
+ return !ovs_list_is_empty(&ctx->ready_packets_data);
}
-static struct mac_cache_mac_binding *
-mac_cache_mac_binding_find(struct mac_cache_data *data,
- const struct mac_cache_mb_data *mb_data)
-{
- uint32_t hash = mac_cache_mb_data_hash(mb_data);
+bool
+buffered_packets_ctx_has_packets(struct buffered_packets_ctx *ctx) {
+ return !hmap_is_empty(&ctx->buffered_packets);
+}
- struct mac_cache_mac_binding *mb;
- HMAP_FOR_EACH_WITH_HASH (mb, hmap_node, hash, &data->mac_bindings) {
- if (mac_cache_mb_data_equals(&mb->data, mb_data)) {
- return mb;
- }
+void
+buffered_packets_ctx_init(struct buffered_packets_ctx *ctx) {
+ hmap_init(&ctx->buffered_packets);
+ ovs_list_init(&ctx->ready_packets_data);
+}
+
+void
+buffered_packets_ctx_destroy(struct buffered_packets_ctx *ctx) {
+ struct bp_packet_data *pd;
+ LIST_FOR_EACH_POP (pd, node, &ctx->ready_packets_data) {
+ bp_packet_data_destroy(pd);
}
- return NULL;
+ struct buffered_packets *bp;
+ HMAP_FOR_EACH_SAFE (bp, hmap_node, &ctx->buffered_packets) {
+ buffered_packets_remove(ctx, bp);
+ }
+ hmap_destroy(&ctx->buffered_packets);
+}
+
+
+void
+mac_cache_stats_destroy(struct ovs_list *stats_list)
+{
+ struct mac_cache_stats *stats;
+ LIST_FOR_EACH_POP (stats, list_node, stats_list) {
+ free(stats);
+ }
}
static uint32_t
-mac_cache_fdb_data_hash(const struct mac_cache_fdb_data *fdb_data)
+mac_binding_data_hash(const struct mac_binding_data *mb_data)
{
uint32_t hash = 0;
- hash = hash_add(hash, fdb_data->port_key);
- hash = hash_add(hash, fdb_data->dp_key);
- hash = hash_add64(hash, eth_addr_to_uint64(fdb_data->mac));
+ hash = hash_add(hash, mb_data->port_key);
+ hash = hash_add(hash, mb_data->dp_key);
+ hash = hash_add_in6_addr(hash, &mb_data->ip);
- return hash_finish(hash, 16);
+ return hash_finish(hash, 24);
}
static inline bool
-mac_cache_fdb_data_equals(const struct mac_cache_fdb_data *a,
- const struct mac_cache_fdb_data *b)
+mac_binding_data_equals(const struct mac_binding_data *a,
+ const struct mac_binding_data *b)
{
return a->port_key == b->port_key &&
a->dp_key == b->dp_key &&
- eth_addr_equals(a->mac, b->mac);
+ ipv6_addr_equals(&a->ip, &b->ip);
}
-static bool
-mac_cache_fdb_data_from_sbrec(struct mac_cache_fdb_data *data,
- const struct sbrec_fdb *fdb)
+static uint32_t
+fdb_data_hash(const struct fdb_data *fdb_data)
{
+ uint32_t hash = 0;
- if (!eth_addr_from_string(fdb->mac, &data->mac)) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
- VLOG_WARN_RL(&rl, "Couldn't parse FDB: mac=%s", fdb->mac);
- return false;
- }
-
- data->dp_key = fdb->dp_key;
- data->port_key = fdb->port_key;
+ hash = hash_add(hash, fdb_data->dp_key);
+ hash = hash_add64(hash, eth_addr_to_uint64(fdb_data->mac));
- return true;
+ return hash_finish(hash, 12);
}
-static struct mac_cache_fdb *
-mac_cache_fdb_find(struct mac_cache_data *data,
- const struct mac_cache_fdb_data *fdb_data)
+static inline bool
+fdb_data_equals(const struct fdb_data *a, const struct fdb_data *b)
{
- uint32_t hash = mac_cache_fdb_data_hash(fdb_data);
-
- struct mac_cache_fdb *fdb;
- HMAP_FOR_EACH_WITH_HASH (fdb, hmap_node, hash, &data->fdbs) {
- if (mac_cache_fdb_data_equals(&fdb->data, fdb_data)) {
- return fdb;
- }
- }
-
- return NULL;
+ return a->dp_key == b->dp_key &&
+ eth_addr_equals(a->mac, b->mac);
}
+
static struct mac_cache_threshold *
mac_cache_threshold_find(struct hmap *thresholds, const struct uuid *uuid)
{
@@ -545,3 +682,66 @@ mac_cache_update_req_delay(struct hmap *thresholds, uint64_t *req_delay)
*req_delay = dump_period < UINT64_MAX ? dump_period : 0;
}
+
+static struct buffered_packets *
+buffered_packets_find(struct buffered_packets_ctx *ctx,
+ const struct mac_binding_data *mb_data) {
+ uint32_t hash = mac_binding_data_hash(mb_data);
+
+ struct buffered_packets *bp;
+ HMAP_FOR_EACH_WITH_HASH (bp, hmap_node, hash, &ctx->buffered_packets) {
+ if (mac_binding_data_equals(&bp->mb_data, mb_data)) {
+ return bp;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+buffered_packets_remove(struct buffered_packets_ctx *ctx,
+ struct buffered_packets *bp) {
+ struct bp_packet_data *pd;
+ LIST_FOR_EACH_POP (pd, node, &bp->queue) {
+ bp_packet_data_destroy(pd);
+ }
+
+ hmap_remove(&ctx->buffered_packets, &bp->hmap_node);
+ free(bp);
+}
+
+static void
+buffered_packets_db_lookup(struct buffered_packets *bp, struct ds *ip,
+ struct eth_addr *mac,
+ struct ovsdb_idl_index *sbrec_pb_by_key,
+ struct ovsdb_idl_index *sbrec_dp_by_key,
+ struct ovsdb_idl_index *sbrec_pb_by_name,
+ struct ovsdb_idl_index *sbrec_mb_by_lport_ip) {
+ const struct sbrec_port_binding *pb =
+ lport_lookup_by_key(sbrec_dp_by_key, sbrec_pb_by_key,
+ bp->mb_data.dp_key, bp->mb_data.port_key);
+ if (!pb) {
+ return;
+ }
+
+ if (!strcmp(pb->type, "chassisredirect")) {
+ const char *dgp_name =
+ smap_get_def(&pb->options, "distributed-port", "");
+ pb = lport_lookup_by_name(sbrec_pb_by_name, dgp_name);
+ if (!pb) {
+ return;
+ }
+ }
+
+ ipv6_format_mapped(&bp->mb_data.ip, ip);
+ const struct sbrec_mac_binding *smb =
+ mac_binding_lookup(sbrec_mb_by_lport_ip, pb->logical_port,
+ ds_cstr_ro(ip));
+ ds_clear(ip);
+
+ if (!smb) {
+ return;
+ }
+
+ eth_addr_from_string(smb->mac, mac);
+}
@@ -18,9 +18,16 @@
#include <stdint.h>
+#include "dp-packet.h"
#include "openvswitch/hmap.h"
-#include "ovn-sb-idl.h"
+#include "openvswitch/hmap.h"
+#include "openvswitch/list.h"
+#include "openvswitch/ofpbuf.h"
#include "openvswitch/ofp-flow.h"
+#include "openvswitch/ofp-packet.h"
+#include "ovn-sb-idl.h"
+
+struct ovsdb_idl_index;
enum mac_cache_type {
MAC_CACHE_MAC_BINDING,
@@ -49,37 +56,73 @@ struct mac_cache_threshold {
uint64_t dump_period;
};
-struct mac_cache_mb_data {
+struct mac_binding_data {
+ /* Keys. */
uint32_t port_key;
uint32_t dp_key;
struct in6_addr ip;
+ /* Value. */
struct eth_addr mac;
};
-struct mac_cache_mac_binding {
+struct mac_binding {
struct hmap_node hmap_node;
/* Common data to identify MAC binding. */
- struct mac_cache_mb_data data;
- /* Reference to the SB MAC binding record. */
+ struct mac_binding_data data;
+ /* Reference to the SB MAC binding record (Might be NULL). */
const struct sbrec_mac_binding *sbrec_mb;
+ /* User specified timestamp (in ms) */
+ long long timestamp;
};
-struct mac_cache_fdb_data {
- uint32_t port_key;
+struct fdb_data {
+ /* Keys. */
uint32_t dp_key;
struct eth_addr mac;
+ /* Value. */
+ uint32_t port_key;
};
-struct mac_cache_fdb {
+struct fdb {
struct hmap_node hmap_node;
/* Common data to identify FDB. */
- struct mac_cache_fdb_data data;
+ struct fdb_data data;
/* Reference to the SB FDB record. */
const struct sbrec_fdb *sbrec_fdb;
/* UUID of datapath for this FDB record. */
struct uuid dp_uuid;
};
+struct bp_packet_data {
+ struct ovs_list node;
+
+ struct ofpbuf *continuation;
+ struct ofputil_packet_in pin;
+};
+
+struct buffered_packets {
+ struct hmap_node hmap_node;
+
+ struct mac_binding_data mb_data;
+
+ /* Queue of packet_data associated with this struct. */
+ struct ovs_list queue;
+
+ /* Timestamp in ms when the buffered packet should expire. */
+ long long int expire_at_ms;
+
+ /* Timestamp in ms when the buffered packet should do full SB lookup.*/
+ long long int lookup_at_ms;
+};
+
+struct buffered_packets_ctx {
+ /* Map of all buffered packets waiting for the MAC address. */
+ struct hmap buffered_packets;
+ /* List of packet data that are ready to be sent. */
+ struct ovs_list ready_packets_data;
+};
+
+/* Thresholds. */
bool mac_cache_threshold_add(struct mac_cache_data *data,
const struct sbrec_datapath_binding *dp,
enum mac_cache_type type);
@@ -87,38 +130,86 @@ bool mac_cache_threshold_replace(struct mac_cache_data *data,
const struct sbrec_datapath_binding *dp,
enum mac_cache_type type);
void mac_cache_thresholds_clear(struct mac_cache_data *data);
-void mac_cache_mac_binding_add(struct mac_cache_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name);
-struct mac_cache_mac_binding *
-mac_cachce_mac_binding_find(struct mac_cache_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name);
-void mac_cache_mac_binding_remove(struct mac_cache_data *data,
- const struct sbrec_mac_binding *mb,
- struct ovsdb_idl_index *sbrec_pb_by_name);
-void mac_cache_mac_bindings_clear(struct mac_cache_data *data);
-bool mac_cache_sb_mac_binding_updated(const struct sbrec_mac_binding *mb);
-
-void mac_cache_fdb_add(struct mac_cache_data *data,
- const struct sbrec_fdb *fdb, struct uuid dp_uuid);
-void mac_cache_fdb_remove(struct mac_cache_data *data,
- const struct sbrec_fdb *fdb);
-bool mac_cache_sb_fdb_updated(const struct sbrec_fdb *fdb);
-void mac_cache_fdbs_clear(struct mac_cache_data *data);
-void
-mac_cache_mb_stats_process_flow_stats(struct ovs_list *stats_list,
- struct ofputil_flow_stats *ofp_stats);
-void mac_cache_mb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
- void *data);
+/* MAC binding. */
+struct mac_binding *mac_binding_add(struct hmap *map,
+ struct mac_binding_data mb_data,
+ long long timestamp);
+
+void mac_binding_remove(struct hmap *map, struct mac_binding *mb);
+
+struct mac_binding *mac_binding_find(const struct hmap *map,
+ const struct mac_binding_data *mb_data);
+
+bool mac_binding_data_from_sbrec(struct mac_binding_data *data,
+ const struct sbrec_mac_binding *mb,
+ struct ovsdb_idl_index *sbrec_pb_by_name);
+void mac_bindings_clear(struct hmap *map);
+
+bool sb_mac_binding_updated(const struct sbrec_mac_binding *mb);
+
+const struct sbrec_mac_binding *
+mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
+ const char *logical_port, const char *ip);
+
+/* FDB. */
+struct fdb *fdb_add(struct hmap *map, struct fdb_data fdb_data);
+
+void fdb_remove(struct hmap *map, struct fdb *fdb);
+
+bool fdb_data_from_sbrec(struct fdb_data *data, const struct sbrec_fdb *fdb);
+
+struct fdb *fdb_find(const struct hmap *map, const struct fdb_data *fdb_data);
+
+bool sb_fdb_updated(const struct sbrec_fdb *fdb);
+
+void fdbs_clear(struct hmap *map);
+
+/* MAC binding stat processing. */
void
-mac_cache_fdb_stats_process_flow_stats(struct ovs_list *stats_list,
- struct ofputil_flow_stats *ofp_stats);
-void mac_cache_fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
- void *data);
+mac_binding_stats_process_flow_stats(struct ovs_list *stats_list,
+ struct ofputil_flow_stats *ofp_stats);
+
+void mac_binding_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
+ void *data);
+
+/* FDB stat processing. */
+void fdb_stats_process_flow_stats(struct ovs_list *stats_list,
+ struct ofputil_flow_stats *ofp_stats);
+
+void fdb_stats_run(struct ovs_list *stats_list, uint64_t *req_delay,
+ void *data);
void mac_cache_stats_destroy(struct ovs_list *stats_list);
+/* Packet buffering. */
+struct bp_packet_data *
+bp_packet_data_create(const struct ofputil_packet_in *pin,
+ const struct ofpbuf *continuation);
+
+void bp_packet_data_destroy(struct bp_packet_data *pd);
+
+struct buffered_packets *
+buffered_packets_add(struct buffered_packets_ctx *ctx,
+ struct mac_binding_data mb_data);
+
+void buffered_packets_packet_data_enqueue(struct buffered_packets *bp,
+ struct bp_packet_data *pd);
+
+void buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
+ const struct hmap *recent_mbs,
+ struct ovsdb_idl_index *sbrec_pb_by_key,
+ struct ovsdb_idl_index *sbrec_dp_by_key,
+ struct ovsdb_idl_index *sbrec_pb_by_name,
+ struct ovsdb_idl_index *sbrec_mb_by_lport_ip);
+
+void buffered_packets_ctx_init(struct buffered_packets_ctx *ctx);
+
+void buffered_packets_ctx_destroy(struct buffered_packets_ctx *ctx);
+
+bool buffered_packets_ctx_is_ready_to_send(struct buffered_packets_ctx *ctx);
+
+bool buffered_packets_ctx_has_packets(struct buffered_packets_ctx *ctx);
+
#endif /* controller/mac-cache.h */
deleted file mode 100644
@@ -1,482 +0,0 @@
-/* Copyright (c) 2020, Red Hat, Inc.
- *
- * 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 "mac-learn.h"
-
-/* OpenvSwitch lib includes. */
-#include "openvswitch/poll-loop.h"
-#include "openvswitch/vlog.h"
-#include "lib/packets.h"
-#include "lib/smap.h"
-#include "lib/timeval.h"
-#include "lport.h"
-#include "ovn-sb-idl.h"
-
-VLOG_DEFINE_THIS_MODULE(mac_learn);
-
-#define MAX_FDB_ENTRIES 1000
-#define MAX_BUFFERED_PACKETS 1000
-#define BUFFER_QUEUE_DEPTH 4
-#define BUFFERED_PACKETS_TIMEOUT_MS 10000
-#define BUFFERED_PACKETS_LOOKUP_MS 100
-
-static size_t keys_ip_hash(uint32_t dp_key, uint32_t port_key,
- struct in6_addr *ip);
-static struct mac_binding *mac_binding_find(const struct mac_bindings_map
- *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);
-static struct buffered_packets *
-buffered_packets_find(struct buffered_packets_ctx *ctx, uint64_t dp_key,
- uint64_t port_key, struct in6_addr *ip, uint32_t hash);
-static void ovn_buffered_packets_remove(struct buffered_packets_ctx *ctx,
- struct buffered_packets *bp);
-static void
-buffered_packets_db_lookup(struct buffered_packets *bp,
- struct ds *ip, struct eth_addr *mac,
- struct ovsdb_idl_index *sbrec_pb_by_key,
- struct ovsdb_idl_index *sbrec_dp_by_key,
- struct ovsdb_idl_index *sbrec_pb_by_name,
- struct ovsdb_idl_index *sbrec_mb_by_lport_ip);
-
-/* mac_binding functions. */
-void
-ovn_mac_bindings_map_init(struct mac_bindings_map *mac_bindings,
- size_t max_size)
-{
- mac_bindings->max_size = max_size;
- hmap_init(&mac_bindings->map);
-}
-
-void
-ovn_mac_bindings_map_destroy(struct mac_bindings_map *mac_bindings)
-{
- struct mac_binding *mb;
-
- HMAP_FOR_EACH_POP (mb, hmap_node, &mac_bindings->map) {
- free(mb);
- }
- hmap_destroy(&mac_bindings->map);
-}
-
-struct mac_binding *
-ovn_mac_binding_add(struct mac_bindings_map *mac_bindings, uint32_t dp_key,
- uint32_t port_key, struct in6_addr *ip,
- struct eth_addr mac, uint32_t timeout_ms)
-{
- uint32_t hash = keys_ip_hash(dp_key, port_key, ip);
-
- struct mac_binding *mb =
- mac_binding_find(mac_bindings, dp_key, port_key, ip, hash);
- size_t max_size = mac_bindings->max_size;
- if (!mb) {
- if (max_size && hmap_count(&mac_bindings->map) >= max_size) {
- return NULL;
- }
- mb = xmalloc(sizeof *mb);
- mb->dp_key = dp_key;
- mb->port_key = port_key;
- mb->ip = *ip;
- mb->timeout_at_ms = time_msec() + timeout_ms;
- hmap_insert(&mac_bindings->map, &mb->hmap_node, hash);
- }
- mb->mac = mac;
-
- return mb;
-}
-
-/* This is called from ovn-controller main context */
-void
-ovn_mac_bindings_map_wait(struct mac_bindings_map *mac_bindings)
-{
- if (hmap_is_empty(&mac_bindings->map)) {
- return;
- }
-
- struct mac_binding *mb;
-
- HMAP_FOR_EACH (mb, hmap_node, &mac_bindings->map) {
- poll_timer_wait_until(mb->timeout_at_ms);
- }
-}
-
-void
-ovn_mac_binding_remove(struct mac_binding *mb,
- struct mac_bindings_map *mac_bindings)
-{
- hmap_remove(&mac_bindings->map, &mb->hmap_node);
- free(mb);
-}
-
-bool
-ovn_mac_binding_timed_out(const struct mac_binding *mb, long long now)
-{
- return now >= mb->timeout_at_ms;
-}
-
-const struct sbrec_mac_binding *
-ovn_mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
- const char *logical_port, const char *ip)
-{
- struct sbrec_mac_binding *mb =
- sbrec_mac_binding_index_init_row(sbrec_mac_binding_by_lport_ip);
- sbrec_mac_binding_index_set_logical_port(mb, logical_port);
- sbrec_mac_binding_index_set_ip(mb, ip);
-
- const struct sbrec_mac_binding *retval =
- sbrec_mac_binding_index_find(sbrec_mac_binding_by_lport_ip, mb);
-
- sbrec_mac_binding_index_destroy_row(mb);
-
- return retval;
-}
-
-/* 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;
-
-}
-
-/* packet buffering functions */
-
-struct packet_data *
-ovn_packet_data_create(const struct ofputil_packet_in *pin,
- const struct ofpbuf *continuation)
-{
- struct packet_data *pd = xmalloc(sizeof *pd);
-
- pd->pin = (struct ofputil_packet_in) {
- .packet = xmemdup(pin->packet, pin->packet_len),
- .packet_len = pin->packet_len,
- .flow_metadata = pin->flow_metadata,
- .reason = pin->reason,
- .table_id = pin->table_id,
- .cookie = pin->cookie,
- /* Userdata are empty on purpose,
- * it is not needed for the continuation. */
- .userdata = NULL,
- .userdata_len = 0,
- };
- pd->continuation = ofpbuf_clone(continuation);
-
- return pd;
-}
-
-
-void
-ovn_packet_data_destroy(struct packet_data *pd)
-{
- free(pd->pin.packet);
- ofpbuf_delete(pd->continuation);
- free(pd);
-}
-
-struct buffered_packets *
-ovn_buffered_packets_add(struct buffered_packets_ctx *ctx, uint64_t dp_key,
- uint64_t port_key, struct in6_addr ip)
-{
- struct buffered_packets *bp;
-
- uint32_t hash = keys_ip_hash(dp_key, port_key, &ip);
-
- bp = buffered_packets_find(ctx, dp_key, port_key, &ip, hash);
- if (!bp) {
- if (hmap_count(&ctx->buffered_packets) >= MAX_BUFFERED_PACKETS) {
- return NULL;
- }
-
- bp = xmalloc(sizeof *bp);
- hmap_insert(&ctx->buffered_packets, &bp->hmap_node, hash);
- bp->ip = ip;
- bp->dp_key = dp_key;
- bp->port_key = port_key;
- /* Schedule the freshly added buffered packet to do lookup
- * immediately. */
- bp->lookup_at_ms = 0;
- ovs_list_init(&bp->queue);
- }
-
- bp->expire_at_ms = time_msec() + BUFFERED_PACKETS_TIMEOUT_MS;
-
- return bp;
-}
-
-void
-ovn_buffered_packets_packet_data_enqueue(struct buffered_packets *bp,
- struct packet_data *pd)
-{
- if (ovs_list_size(&bp->queue) == BUFFER_QUEUE_DEPTH) {
- struct packet_data *p = CONTAINER_OF(ovs_list_pop_front(&bp->queue),
- struct packet_data, node);
-
- ovn_packet_data_destroy(p);
- }
- ovs_list_push_back(&bp->queue, &pd->node);
-}
-
-void
-ovn_buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
- const struct mac_bindings_map *recent_mbs,
- struct ovsdb_idl_index *sbrec_pb_by_key,
- struct ovsdb_idl_index *sbrec_dp_by_key,
- struct ovsdb_idl_index *sbrec_pb_by_name,
- struct ovsdb_idl_index *sbrec_mb_by_lport_ip)
-{
- struct ds ip = DS_EMPTY_INITIALIZER;
- long long now = time_msec();
-
- struct buffered_packets *bp;
-
- HMAP_FOR_EACH_SAFE (bp, hmap_node, &ctx->buffered_packets) {
- struct eth_addr mac = eth_addr_zero;
- /* Remove expired buffered packets. */
- if (now > bp->expire_at_ms) {
- ovn_buffered_packets_remove(ctx, bp);
- continue;
- }
-
- uint32_t hash = keys_ip_hash(bp->dp_key, bp->port_key, &bp->ip);
- struct mac_binding *mb = mac_binding_find(recent_mbs, bp->dp_key,
- bp->port_key, &bp->ip, hash);
-
- if (mb) {
- mac = mb->mac;
- } else if (now >= bp->lookup_at_ms) {
- /* Check if we can do a full lookup. */
- buffered_packets_db_lookup(bp, &ip, &mac, sbrec_pb_by_key,
- sbrec_dp_by_key, sbrec_pb_by_name,
- sbrec_mb_by_lport_ip);
- /* Schedule next lookup even if we found the MAC address,
- * if the address was found this struct will be deleted anyway. */
- bp->lookup_at_ms = now + BUFFERED_PACKETS_LOOKUP_MS;
- }
-
- if (eth_addr_is_zero(mac)) {
- continue;
- }
-
- struct packet_data *pd;
- LIST_FOR_EACH_POP (pd, node, &bp->queue) {
- struct dp_packet packet;
- dp_packet_use_const(&packet, pd->pin.packet, pd->pin.packet_len);
-
- struct eth_header *eth = dp_packet_data(&packet);
- eth->eth_dst = mac;
-
- ovs_list_push_back(&ctx->ready_packets_data, &pd->node);
- }
-
- ovn_buffered_packets_remove(ctx, bp);
- }
-
- ds_destroy(&ip);
-}
-
-bool
-ovn_buffered_packets_ctx_is_ready_to_send(struct buffered_packets_ctx *ctx)
-{
- return !ovs_list_is_empty(&ctx->ready_packets_data);
-}
-
-bool
-ovn_buffered_packets_ctx_has_packets(struct buffered_packets_ctx *ctx)
-{
- return !hmap_is_empty(&ctx->buffered_packets);
-}
-
-void
-ovn_buffered_packets_ctx_init(struct buffered_packets_ctx *ctx)
-{
- hmap_init(&ctx->buffered_packets);
- ovs_list_init(&ctx->ready_packets_data);
-}
-
-void
-ovn_buffered_packets_ctx_destroy(struct buffered_packets_ctx *ctx)
-{
- struct packet_data *pd;
- LIST_FOR_EACH_POP (pd, node, &ctx->ready_packets_data) {
- ovn_packet_data_destroy(pd);
- }
-
- struct buffered_packets *bp;
- HMAP_FOR_EACH_SAFE (bp, hmap_node, &ctx->buffered_packets) {
- ovn_buffered_packets_remove(ctx, bp);
- }
- hmap_destroy(&ctx->buffered_packets);
-}
-
-/* mac_binding related static functions. */
-static size_t
-keys_ip_hash(uint32_t dp_key, uint32_t port_key, struct in6_addr *ip)
-{
- return hash_bytes(ip, sizeof *ip, hash_2words(dp_key, port_key));
-}
-
-static struct mac_binding *
-mac_binding_find(const struct mac_bindings_map *mac_bindings,
- uint32_t dp_key, uint32_t port_key, struct in6_addr *ip,
- size_t hash)
-{
- struct mac_binding *mb;
-
- HMAP_FOR_EACH_WITH_HASH (mb, hmap_node, hash, &mac_bindings->map) {
- if (mb->dp_key == dp_key && mb->port_key == port_key &&
- IN6_ARE_ADDR_EQUAL(&mb->ip, ip)) {
- return mb;
- }
- }
-
- 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;
-}
-
-/* packet buffering static functions. */
-static struct buffered_packets *
-buffered_packets_find(struct buffered_packets_ctx *ctx, uint64_t dp_key,
- uint64_t port_key, struct in6_addr *ip, uint32_t hash)
-{
- struct buffered_packets *mb;
-
- HMAP_FOR_EACH_WITH_HASH (mb, hmap_node, hash, &ctx->buffered_packets) {
- if (mb->dp_key == dp_key && mb->port_key == port_key &&
- IN6_ARE_ADDR_EQUAL(&mb->ip, ip)) {
- return mb;
- }
- }
-
- return NULL;
-}
-
-static void
-ovn_buffered_packets_remove(struct buffered_packets_ctx *ctx,
- struct buffered_packets *bp)
-{
- struct packet_data *pd;
-
- LIST_FOR_EACH_POP (pd, node, &bp->queue) {
- ovn_packet_data_destroy(pd);
- }
-
- hmap_remove(&ctx->buffered_packets, &bp->hmap_node);
- free(bp);
-}
-
-static void
-buffered_packets_db_lookup(struct buffered_packets *bp, struct ds *ip,
- struct eth_addr *mac,
- struct ovsdb_idl_index *sbrec_pb_by_key,
- struct ovsdb_idl_index *sbrec_dp_by_key,
- struct ovsdb_idl_index *sbrec_pb_by_name,
- struct ovsdb_idl_index *sbrec_mb_by_lport_ip)
-{
- const struct sbrec_port_binding *pb = lport_lookup_by_key(sbrec_dp_by_key,
- sbrec_pb_by_key,
- bp->dp_key,
- bp->port_key);
- if (!pb) {
- return;
- }
-
- if (!strcmp(pb->type, "chassisredirect")) {
- const char *dgp_name =
- smap_get_def(&pb->options, "distributed-port", "");
- pb = lport_lookup_by_name(sbrec_pb_by_name, dgp_name);
- if (!pb) {
- return;
- }
- }
-
- ipv6_format_mapped(&bp->ip, ip);
- const struct sbrec_mac_binding *smb =
- ovn_mac_binding_lookup(sbrec_mb_by_lport_ip, pb->logical_port,
- ds_cstr_ro(ip));
- ds_clear(ip);
-
- if (!smb) {
- return;
- }
-
- eth_addr_from_string(smb->mac, mac);
-}
deleted file mode 100644
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2020 Red Hat, Inc.
- *
- * 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_MAC_LEARN_H
-#define OVN_MAC_LEARN_H 1
-
-#include <sys/types.h>
-#include <netinet/in.h>
-
-#include "dp-packet.h"
-#include "openvswitch/hmap.h"
-#include "openvswitch/list.h"
-#include "openvswitch/ofpbuf.h"
-#include "openvswitch/ofp-packet.h"
-
-struct ovsdb_idl_index;
-
-struct mac_binding {
- struct hmap_node hmap_node; /* In a hmap. */
-
- /* Key. */
- uint32_t dp_key;
- uint32_t port_key; /* Port from where this mac_binding is learnt. */
- struct in6_addr ip;
-
- /* Value. */
- struct eth_addr mac;
-
- /* Absolute time (in ms) when a user specific timeout expires for
- * this entry. */
- long long timeout_at_ms;
-};
-
-struct mac_bindings_map {
- struct hmap map;
- /* Maximum capacity of the associated map. "0" means unlimited. */
- size_t max_size;
-};
-
-void ovn_mac_bindings_map_init(struct mac_bindings_map *mac_bindings,
- size_t max_size);
-void ovn_mac_bindings_map_destroy(struct mac_bindings_map *mac_bindings);
-void ovn_mac_bindings_map_wait(struct mac_bindings_map *mac_bindings);
-void ovn_mac_binding_remove(struct mac_binding *mb,
- struct mac_bindings_map *mac_bindings);
-bool ovn_mac_binding_timed_out(const struct mac_binding *mb,
- long long now);
-
-struct mac_binding *ovn_mac_binding_add(struct mac_bindings_map *mac_bindings,
- uint32_t dp_key, uint32_t port_key,
- struct in6_addr *ip,
- struct eth_addr mac,
- uint32_t timeout_ms);
-const struct sbrec_mac_binding *
-ovn_mac_binding_lookup(struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
- const char *logical_port, const char *ip);
-
-
-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);
-
-
-struct packet_data {
- struct ovs_list node;
-
- struct ofpbuf *continuation;
- struct ofputil_packet_in pin;
-};
-
-struct buffered_packets {
- struct hmap_node hmap_node;
-
- struct in6_addr ip;
- uint64_t dp_key;
- uint64_t port_key;
-
- /* Queue of packet_data associated with this struct. */
- struct ovs_list queue;
-
- /* Timestamp in ms when the buffered packet should expire. */
- long long int expire_at_ms;
-
- /* Timestamp in ms when the buffered packet should do full SB lookup.*/
- long long int lookup_at_ms;
-};
-
-struct buffered_packets_ctx {
- /* Map of all buffered packets waiting for the MAC address. */
- struct hmap buffered_packets;
- /* List of packet data that are ready to be sent. */
- struct ovs_list ready_packets_data;
-};
-
-struct packet_data *
-ovn_packet_data_create(const struct ofputil_packet_in *pin,
- const struct ofpbuf *continuation);
-void ovn_packet_data_destroy(struct packet_data *pd);
-struct buffered_packets *
-ovn_buffered_packets_add(struct buffered_packets_ctx *ctx, uint64_t dp_key,
- uint64_t port_key, struct in6_addr ip);
-void ovn_buffered_packets_packet_data_enqueue(struct buffered_packets *bp,
- struct packet_data *pd);
-void
-ovn_buffered_packets_ctx_run(struct buffered_packets_ctx *ctx,
- const struct mac_bindings_map *recent_mbs,
- struct ovsdb_idl_index *sbrec_pb_by_key,
- struct ovsdb_idl_index *sbrec_dp_by_key,
- struct ovsdb_idl_index *sbrec_pb_by_name,
- struct ovsdb_idl_index *sbrec_mb_by_lport_ip);
-void ovn_buffered_packets_ctx_init(struct buffered_packets_ctx *ctx);
-void ovn_buffered_packets_ctx_destroy(struct buffered_packets_ctx *ctx);
-bool
-ovn_buffered_packets_ctx_is_ready_to_send(struct buffered_packets_ctx *ctx);
-bool ovn_buffered_packets_ctx_has_packets(struct buffered_packets_ctx *ctx);
-
-#endif /* OVN_MAC_LEARN_H */
@@ -3275,6 +3275,70 @@ en_lb_data_cleanup(void *data)
uuidset_destroy(&lb_data->new);
}
+static void
+mac_binding_add_sb(struct mac_cache_data *data,
+ const struct sbrec_mac_binding *smb,
+ struct ovsdb_idl_index *sbrec_pb_by_name)
+{
+ struct mac_binding_data mb_data;
+ if (!mac_binding_data_from_sbrec(&mb_data, smb, sbrec_pb_by_name)) {
+ return;
+ }
+
+ struct mac_binding *mb = mac_binding_add(&data->mac_bindings, mb_data, 0);
+
+ mb->sbrec_mb = smb;
+}
+
+static void
+mac_binding_remove_sb(struct mac_cache_data *data,
+ const struct sbrec_mac_binding *smb,
+ struct ovsdb_idl_index *sbrec_pb_by_name)
+{
+ struct mac_binding_data mb_data;
+ if (!mac_binding_data_from_sbrec(&mb_data, smb, sbrec_pb_by_name)) {
+ return;
+ }
+
+ struct mac_binding *mb = mac_binding_find(&data->mac_bindings, &mb_data);
+ if (!mb) {
+ return;
+ }
+
+ mac_binding_remove(&data->mac_bindings, mb);
+}
+
+static void
+fdb_add_sb(struct mac_cache_data *data, const struct sbrec_fdb *sfdb,
+ struct uuid dp_uuid)
+{
+ struct fdb_data fdb_data;
+ if (!fdb_data_from_sbrec(&fdb_data, sfdb)) {
+ return;
+ }
+
+ struct fdb *fdb = fdb_add(&data->fdbs, fdb_data);
+
+ fdb->sbrec_fdb = sfdb;
+ fdb->dp_uuid = dp_uuid;
+}
+
+static void
+fdb_remove_sb(struct mac_cache_data *data, const struct sbrec_fdb *sfdb)
+{
+ struct fdb_data fdb_data;
+ if (!fdb_data_from_sbrec(&fdb_data, sfdb)) {
+ return;
+ }
+
+ struct fdb *fdb = fdb_find(&data->fdbs, &fdb_data);
+ if (!fdb) {
+ return;
+ }
+
+ fdb_remove(&data->fdbs, fdb);
+}
+
static void
mac_cache_mb_handle_for_datapath(struct mac_cache_data *data,
const struct sbrec_datapath_binding *dp,
@@ -3291,9 +3355,9 @@ mac_cache_mb_handle_for_datapath(struct mac_cache_data *data,
const struct sbrec_mac_binding *mb;
SBREC_MAC_BINDING_FOR_EACH_EQUAL (mb, mb_index_row, sbrec_mb_by_dp) {
if (has_threshold) {
- mac_cache_mac_binding_add(data, mb, sbrec_pb_by_name);
+ mac_binding_add_sb(data, mb, sbrec_pb_by_name);
} else {
- mac_cache_mac_binding_remove(data, mb, sbrec_pb_by_name);
+ mac_binding_remove_sb(data, mb, sbrec_pb_by_name);
}
}
@@ -3314,9 +3378,9 @@ mac_cache_fdb_handle_for_datapath(struct mac_cache_data *data,
const struct sbrec_fdb *fdb;
SBREC_FDB_FOR_EACH_EQUAL (fdb, fdb_index_row, sbrec_fdb_by_dp_key) {
if (has_threshold) {
- mac_cache_fdb_add(data, fdb, dp->header_.uuid);
+ fdb_add_sb(data, fdb, dp->header_.uuid);
} else {
- mac_cache_fdb_remove(data, fdb);
+ fdb_remove_sb(data, fdb);
}
}
@@ -3354,8 +3418,8 @@ en_mac_cache_run(struct engine_node *node, void *data)
"name");
mac_cache_thresholds_clear(cache_data);
- mac_cache_mac_bindings_clear(cache_data);
- mac_cache_fdbs_clear(cache_data);
+ mac_bindings_clear(&cache_data->mac_bindings);
+ fdbs_clear(&cache_data->fdbs);
const struct sbrec_mac_binding *sbrec_mb;
SBREC_MAC_BINDING_TABLE_FOR_EACH (sbrec_mb, mb_table) {
@@ -3366,7 +3430,8 @@ en_mac_cache_run(struct engine_node *node, void *data)
if (mac_cache_threshold_add(cache_data, sbrec_mb->datapath,
MAC_CACHE_MAC_BINDING)) {
- mac_cache_mac_binding_add(cache_data, sbrec_mb, sbrec_pb_by_name);
+ mac_binding_add_sb(cache_data, sbrec_mb,
+ sbrec_pb_by_name);
}
}
@@ -3381,8 +3446,8 @@ en_mac_cache_run(struct engine_node *node, void *data)
if (mac_cache_threshold_add(cache_data, local_dp->datapath,
MAC_CACHE_FDB)) {
- mac_cache_fdb_add(cache_data, sbrec_fdb,
- local_dp->datapath->header_.uuid);
+ fdb_add_sb(cache_data, sbrec_fdb,
+ local_dp->datapath->header_.uuid);
}
}
@@ -3406,13 +3471,13 @@ mac_cache_sb_mac_binding_handler(struct engine_node *node, void *data)
const struct sbrec_mac_binding *sbrec_mb;
SBREC_MAC_BINDING_TABLE_FOR_EACH_TRACKED (sbrec_mb, mb_table) {
- if (!mac_cache_sb_mac_binding_updated(sbrec_mb)) {
+ if (!sb_mac_binding_updated(sbrec_mb)) {
continue;
}
if (!sbrec_mac_binding_is_new(sbrec_mb)) {
- mac_cache_mac_binding_remove(cache_data, sbrec_mb,
- sbrec_pb_by_name);
+ mac_binding_remove_sb(cache_data, sbrec_mb,
+ sbrec_pb_by_name);
}
if (sbrec_mac_binding_is_deleted(sbrec_mb) ||
@@ -3423,7 +3488,8 @@ mac_cache_sb_mac_binding_handler(struct engine_node *node, void *data)
if (mac_cache_threshold_add(cache_data, sbrec_mb->datapath,
MAC_CACHE_MAC_BINDING)) {
- mac_cache_mac_binding_add(cache_data, sbrec_mb, sbrec_pb_by_name);
+ mac_binding_add_sb(cache_data, sbrec_mb,
+ sbrec_pb_by_name);
}
}
@@ -3448,12 +3514,12 @@ mac_cache_sb_fdb_handler(struct engine_node *node, void *data)
struct local_datapath *local_dp;
const struct sbrec_fdb *sbrec_fdb;
SBREC_FDB_TABLE_FOR_EACH_TRACKED (sbrec_fdb, fdb_table) {
- if (!mac_cache_sb_fdb_updated(sbrec_fdb)) {
+ if (!sb_fdb_updated(sbrec_fdb)) {
continue;
}
if (!sbrec_fdb_is_new(sbrec_fdb)) {
- mac_cache_fdb_remove(cache_data, sbrec_fdb);
+ fdb_remove_sb(cache_data, sbrec_fdb);
}
local_dp = get_local_datapath(&rt_data->local_datapaths,
@@ -3464,8 +3530,8 @@ mac_cache_sb_fdb_handler(struct engine_node *node, void *data)
if (mac_cache_threshold_add(cache_data, local_dp->datapath,
MAC_CACHE_FDB)) {
- mac_cache_fdb_add(cache_data, sbrec_fdb,
- local_dp->datapath->header_.uuid);
+ fdb_add_sb(cache_data, sbrec_fdb,
+ local_dp->datapath->header_.uuid);
}
}
@@ -3582,9 +3648,9 @@ en_mac_cache_cleanup(void *data)
for (size_t i = 0; i < MAC_CACHE_MAX; i++) {
hmap_destroy(&cache_data->thresholds[i]);
}
- mac_cache_mac_bindings_clear(cache_data);
+ mac_bindings_clear(&cache_data->mac_bindings);
hmap_destroy(&cache_data->mac_bindings);
- mac_cache_fdbs_clear(cache_data);
+ fdbs_clear(&cache_data->fdbs);
hmap_destroy(&cache_data->fdbs);
}
@@ -27,7 +27,7 @@
#include "ha-chassis.h"
#include "local_data.h"
#include "lport.h"
-#include "mac-learn.h"
+#include "mac-cache.h"
#include "nx-match.h"
#include "ofctrl.h"
#include "latch.h"
@@ -382,7 +382,7 @@ static void run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn,
struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
struct ovsdb_idl_index *sbrec_port_binding_by_key,
struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
- const struct fdb_entry *fdb_e)
+ const struct fdb *fdb)
OVS_REQUIRES(pinctrl_mutex);
static void run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn,
struct ovsdb_idl_index *sbrec_port_binding_by_key,
@@ -1523,13 +1523,13 @@ static struct buffered_packets_ctx buffered_packets_ctx;
static void
init_buffered_packets_ctx(void)
{
- ovn_buffered_packets_ctx_init(&buffered_packets_ctx);
+ buffered_packets_ctx_init(&buffered_packets_ctx);
}
static void
destroy_buffered_packets_ctx(void)
{
- ovn_buffered_packets_ctx_destroy(&buffered_packets_ctx);
+ buffered_packets_ctx_destroy(&buffered_packets_ctx);
}
/* Called with in the pinctrl_handler thread context. */
@@ -1539,27 +1539,29 @@ pinctrl_handle_buffered_packets(const struct ofputil_packet_in *pin,
bool is_arp)
OVS_REQUIRES(pinctrl_mutex)
{
- struct in6_addr ip;
const struct match *md = &pin->flow_metadata;
- uint64_t dp_key = ntohll(md->flow.metadata);
- uint64_t oport_key = md->flow.regs[MFF_LOG_OUTPORT - MFF_REG0];
+ struct mac_binding_data mb_data = (struct mac_binding_data) {
+ .dp_key = ntohll(md->flow.metadata),
+ .port_key = md->flow.regs[MFF_LOG_OUTPORT - MFF_REG0],
+ .mac = eth_addr_zero,
+ };
if (is_arp) {
- ip = in6_addr_mapped_ipv4(htonl(md->flow.regs[0]));
+ mb_data.ip = in6_addr_mapped_ipv4(htonl(md->flow.regs[0]));
} else {
ovs_be128 ip6 = hton128(flow_get_xxreg(&md->flow, 0));
- memcpy(&ip, &ip6, sizeof ip);
+ memcpy(&mb_data.ip, &ip6, sizeof mb_data.ip);
}
- struct buffered_packets *bp =
- ovn_buffered_packets_add(&buffered_packets_ctx, dp_key, oport_key, ip);
+ struct buffered_packets *bp = buffered_packets_add(&buffered_packets_ctx,
+ mb_data);
if (!bp) {
COVERAGE_INC(pinctrl_drop_buffered_packets_map);
return;
}
- struct packet_data *pd = ovn_packet_data_create(pin, continuation);
- ovn_buffered_packets_packet_data_enqueue(bp, pd);
+ struct bp_packet_data *pd = bp_packet_data_create(pin, continuation);
+ buffered_packets_packet_data_enqueue(bp, pd);
/* There is a chance that the MAC binding was already created. */
notify_pinctrl_main();
@@ -4772,18 +4774,18 @@ pinctrl_destroy(void)
#define MAX_MAC_BINDINGS 1000
/* Contains "struct mac_binding"s. */
-static struct mac_bindings_map put_mac_bindings;
+static struct hmap put_mac_bindings;
static void
init_put_mac_bindings(void)
{
- ovn_mac_bindings_map_init(&put_mac_bindings, MAX_MAC_BINDINGS);
+ hmap_init(&put_mac_bindings);
}
static void
destroy_put_mac_bindings(void)
{
- ovn_mac_bindings_map_destroy(&put_mac_bindings);
+ hmap_destroy(&put_mac_bindings);
}
/* Called with in the pinctrl_handler thread context. */
@@ -4793,15 +4795,22 @@ pinctrl_handle_put_mac_binding(const struct flow *md,
bool is_arp)
OVS_REQUIRES(pinctrl_mutex)
{
- uint32_t dp_key = ntohll(md->metadata);
- uint32_t port_key = md->regs[MFF_LOG_INPORT - MFF_REG0];
- struct in6_addr ip_key;
+ if (hmap_count(&put_mac_bindings) >= MAX_MAC_BINDINGS) {
+ COVERAGE_INC(pinctrl_drop_put_mac_binding);
+ return;
+ }
+
+ struct mac_binding_data mb_data = (struct mac_binding_data) {
+ .dp_key = ntohll(md->metadata),
+ .port_key = md->regs[MFF_LOG_INPORT - MFF_REG0],
+ .mac = headers->dl_src,
+ };
if (is_arp) {
- ip_key = in6_addr_mapped_ipv4(htonl(md->regs[0]));
+ mb_data.ip = in6_addr_mapped_ipv4(htonl(md->regs[0]));
} else {
ovs_be128 ip6 = hton128(flow_get_xxreg(md, 0));
- memcpy(&ip_key, &ip6, sizeof ip_key);
+ memcpy(&mb_data.ip, &ip6, sizeof mb_data.ip);
}
/* If the ARP reply was unicast we should not delay it,
@@ -4809,13 +4818,8 @@ pinctrl_handle_put_mac_binding(const struct flow *md,
uint32_t delay = eth_addr_is_multicast(headers->dl_dst)
? random_range(MAX_MAC_BINDING_DELAY_MSEC) + 1
: 0;
- struct mac_binding *mb = ovn_mac_binding_add(&put_mac_bindings, dp_key,
- port_key, &ip_key,
- headers->dl_src, delay);
- if (!mb) {
- COVERAGE_INC(pinctrl_drop_put_mac_binding);
- return;
- }
+ long long timestamp = time_msec() + delay;
+ mac_binding_add(&put_mac_bindings, mb_data, timestamp);
/* We can send the buffered packet once the main ovn-controller
* thread calls pinctrl_run() and it writes the mac_bindings stored
@@ -4831,11 +4835,11 @@ send_mac_binding_buffered_pkts(struct rconn *swconn)
enum ofp_version version = rconn_get_version(swconn);
enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
- struct packet_data *pd;
+ struct bp_packet_data *pd;
LIST_FOR_EACH_POP (pd, node, &buffered_packets_ctx.ready_packets_data) {
queue_msg(swconn, ofputil_encode_resume(&pd->pin, pd->continuation,
proto));
- ovn_packet_data_destroy(pd);
+ bp_packet_data_destroy(pd);
}
ovs_list_init(&buffered_packets_ctx.ready_packets_data);
@@ -4856,7 +4860,7 @@ mac_binding_add_to_sb(struct ovsdb_idl_txn *ovnsb_idl_txn,
snprintf(mac_string, sizeof mac_string, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
const struct sbrec_mac_binding *b =
- ovn_mac_binding_lookup(sbrec_mac_binding_by_lport_ip,
+ mac_binding_lookup(sbrec_mac_binding_by_lport_ip,
logical_port, ip);
if (!b) {
if (update_only) {
@@ -4930,24 +4934,24 @@ run_put_mac_binding(struct ovsdb_idl_txn *ovnsb_idl_txn,
/* Convert logical datapath and logical port key into lport. */
const struct sbrec_port_binding *pb = lport_lookup_by_key(
sbrec_datapath_binding_by_key, sbrec_port_binding_by_key,
- mb->dp_key, mb->port_key);
+ mb->data.dp_key, mb->data.port_key);
if (!pb) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_WARN_RL(&rl, "unknown logical port with datapath %"PRIu32" "
- "and port %"PRIu32, mb->dp_key, mb->port_key);
+ "and port %"PRIu32, mb->data.dp_key, mb->data.port_key);
return;
}
/* 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(mb->mac));
+ ETH_ADDR_FMT, ETH_ADDR_ARGS(mb->data.mac));
struct ds ip_s = DS_EMPTY_INITIALIZER;
- ipv6_format_mapped(&mb->ip, &ip_s);
+ ipv6_format_mapped(&mb->data.ip, &ip_s);
mac_binding_add_to_sb(ovnsb_idl_txn, sbrec_mac_binding_by_lport_ip,
- pb->logical_port, pb->datapath, mb->mac,
+ pb->logical_port, pb->datapath, mb->data.mac,
ds_cstr(&ip_s), false);
ds_destroy(&ip_s);
}
@@ -4968,13 +4972,13 @@ run_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn,
long long now = time_msec();
struct mac_binding *mb;
- HMAP_FOR_EACH_SAFE (mb, hmap_node, &put_mac_bindings.map) {
- if (ovn_mac_binding_timed_out(mb, now)) {
+ HMAP_FOR_EACH_SAFE (mb, hmap_node, &put_mac_bindings) {
+ if (now >= mb->timestamp) {
run_put_mac_binding(ovnsb_idl_txn,
sbrec_datapath_binding_by_key,
sbrec_port_binding_by_key,
sbrec_mac_binding_by_lport_ip, mb);
- ovn_mac_binding_remove(mb, &put_mac_bindings);
+ mac_binding_remove(&put_mac_bindings, mb);
}
}
}
@@ -4987,33 +4991,24 @@ run_buffered_binding(const struct sbrec_mac_binding_table *mac_binding_table,
struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip)
OVS_REQUIRES(pinctrl_mutex)
{
- if (!ovn_buffered_packets_ctx_has_packets(&buffered_packets_ctx)) {
+ if (!buffered_packets_ctx_has_packets(&buffered_packets_ctx)) {
return;
}
- struct mac_bindings_map recent_mbs;
- ovn_mac_bindings_map_init(&recent_mbs, 0);
+ struct hmap recent_mbs = HMAP_INITIALIZER(&recent_mbs);
const struct sbrec_mac_binding *smb;
SBREC_MAC_BINDING_TABLE_FOR_EACH_TRACKED (smb, mac_binding_table) {
const struct sbrec_port_binding *pb = lport_lookup_by_name(
sbrec_port_binding_by_name, smb->logical_port);
- if (!pb || !pb->datapath) {
- continue;
- }
-
- struct in6_addr ip;
- if (!ip46_parse(smb->ip, &ip)) {
- continue;
- }
- struct eth_addr mac;
- if (!eth_addr_from_string(smb->mac, &mac)) {
+ struct mac_binding_data mb_data;
+ if (!mac_binding_data_from_sbrec(&mb_data, smb,
+ sbrec_port_binding_by_name)) {
continue;
}
- ovn_mac_binding_add(&recent_mbs, smb->datapath->tunnel_key,
- pb->tunnel_key, &ip, mac, 0);
+ mac_binding_add(&recent_mbs, mb_data, 0);
const char *redirect_port =
smap_get(&pb->options, "chassis-redirect-port");
@@ -5029,19 +5024,20 @@ run_buffered_binding(const struct sbrec_mac_binding_table *mac_binding_table,
/* Add the same entry also for chassisredirect port as the buffered
* traffic might be buffered on the cr port. */
- ovn_mac_binding_add(&recent_mbs, smb->datapath->tunnel_key,
- pb->tunnel_key, &ip, mac, 0);
+ mb_data.port_key = pb->tunnel_key;
+ mac_binding_add(&recent_mbs, mb_data, 0);
}
- ovn_buffered_packets_ctx_run(&buffered_packets_ctx, &recent_mbs,
+ buffered_packets_ctx_run(&buffered_packets_ctx, &recent_mbs,
sbrec_port_binding_by_key,
sbrec_datapath_binding_by_key,
sbrec_port_binding_by_name,
sbrec_mac_binding_by_lport_ip);
- ovn_mac_bindings_map_destroy(&recent_mbs);
+ mac_bindings_clear(&recent_mbs);
+ hmap_destroy(&recent_mbs);
- if (ovn_buffered_packets_ctx_is_ready_to_send(&buffered_packets_ctx)) {
+ if (buffered_packets_ctx_is_ready_to_send(&buffered_packets_ctx)) {
notify_pinctrl_handler();
}
}
@@ -5050,8 +5046,13 @@ static void
wait_put_mac_bindings(struct ovsdb_idl_txn *ovnsb_idl_txn)
OVS_REQUIRES(pinctrl_mutex)
{
- if (ovnsb_idl_txn) {
- ovn_mac_bindings_map_wait(&put_mac_bindings);
+ if (!ovnsb_idl_txn) {
+ return;
+ }
+
+ struct mac_binding *mb;
+ HMAP_FOR_EACH (mb, hmap_node, &put_mac_bindings) {
+ poll_timer_wait_until(mb->timestamp);
}
}
@@ -6692,7 +6693,7 @@ may_inject_pkts(void)
!shash_is_empty(&send_garp_rarp_data) ||
ipv6_prefixd_should_inject() ||
!ovs_list_is_empty(&mcast_query_list) ||
- ovn_buffered_packets_ctx_is_ready_to_send(&buffered_packets_ctx) ||
+ buffered_packets_ctx_is_ready_to_send(&buffered_packets_ctx) ||
bfd_monitor_should_inject());
}
@@ -8903,6 +8904,8 @@ pinctrl_mg_split_buff_handler(struct rconn *swconn, struct dp_packet *pkt,
ofpbuf_uninit(&ofpacts);
}
+#define MAX_FDB_ENTRIES 1000
+
static struct hmap put_fdbs;
/* MAC learning (fdb) related functions. Runs within the main
@@ -8911,13 +8914,13 @@ static struct hmap put_fdbs;
static void
init_fdb_entries(void)
{
- ovn_fdb_init(&put_fdbs);
+ hmap_init(&put_fdbs);
}
static void
destroy_fdb_entries(void)
{
- ovn_fdbs_destroy(&put_fdbs);
+ hmap_destroy(&put_fdbs);
}
static const struct sbrec_fdb *
@@ -8941,21 +8944,21 @@ run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn,
struct ovsdb_idl_index *sbrec_fdb_by_dp_key_mac,
struct ovsdb_idl_index *sbrec_port_binding_by_key,
struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
- const struct fdb_entry *fdb_e)
+ const struct fdb *fdb)
{
/* 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));
+ ETH_ADDR_FMT, ETH_ADDR_ARGS(fdb->data.mac));
/* Update or add an FDB entry. */
const struct sbrec_port_binding *sb_entry_pb = NULL;
const struct sbrec_port_binding *new_entry_pb = NULL;
const struct sbrec_fdb *sb_fdb =
- fdb_lookup(sbrec_fdb_by_dp_key_mac, fdb_e->dp_key, mac_string);
+ fdb_lookup(sbrec_fdb_by_dp_key_mac, fdb->data.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_dp_key(sb_fdb, fdb->data.dp_key);
sbrec_fdb_set_mac(sb_fdb, mac_string);
} else {
/* check whether sb_fdb->port_key is vif or localnet type */
@@ -8964,12 +8967,12 @@ run_put_fdb(struct ovsdb_idl_txn *ovnsb_idl_txn,
sb_fdb->dp_key, sb_fdb->port_key);
new_entry_pb = lport_lookup_by_key(
sbrec_datapath_binding_by_key, sbrec_port_binding_by_key,
- fdb_e->dp_key, fdb_e->port_key);
+ fdb->data.dp_key, fdb->data.port_key);
}
/* Do not have localnet overwrite a previous vif entry */
if (!sb_entry_pb || !new_entry_pb || strcmp(sb_entry_pb->type, "") ||
strcmp(new_entry_pb->type, "localnet")) {
- sbrec_fdb_set_port_key(sb_fdb, fdb_e->port_key);
+ sbrec_fdb_set_port_key(sb_fdb, fdb->data.port_key);
}
/* For backward compatibility check if timestamp column is available
@@ -8990,13 +8993,13 @@ run_put_fdbs(struct ovsdb_idl_txn *ovnsb_idl_txn,
return;
}
- const struct fdb_entry *fdb_e;
- HMAP_FOR_EACH (fdb_e, hmap_node, &put_fdbs) {
+ const struct fdb *fdb;
+ HMAP_FOR_EACH (fdb, hmap_node, &put_fdbs) {
run_put_fdb(ovnsb_idl_txn, sbrec_fdb_by_dp_key_mac,
sbrec_port_binding_by_key,
- sbrec_datapath_binding_by_key, fdb_e);
+ sbrec_datapath_binding_by_key, fdb);
}
- ovn_fdbs_flush(&put_fdbs);
+ fdbs_clear(&put_fdbs);
}
@@ -9013,9 +9016,17 @@ 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];
+ if (hmap_count(&put_mac_bindings) >= MAX_FDB_ENTRIES) {
+ COVERAGE_INC(pinctrl_drop_put_mac_binding);
+ return;
+ }
+
+ struct fdb_data fdb_data = (struct fdb_data) {
+ .dp_key = ntohll(md->metadata),
+ .port_key = md->regs[MFF_LOG_INPORT - MFF_REG0],
+ .mac = headers->dl_src,
+ };
- ovn_fdb_add(&put_fdbs, dp_key, headers->dl_src, port_key);
+ fdb_add(&put_fdbs, fdb_data);
notify_pinctrl_main();
}
@@ -136,7 +136,7 @@ statctrl_init(void)
.table_id = OFTABLE_MAC_CACHE_USE,
};
STATS_NODE(MAC_BINDING, mac_binding_request, mac_cache_stats_destroy,
- mac_cache_mb_stats_process_flow_stats, mac_cache_mb_stats_run);
+ mac_binding_stats_process_flow_stats, mac_binding_stats_run);
struct ofputil_flow_stats_request fdb_request = {
.cookie = htonll(0),
@@ -146,8 +146,7 @@ statctrl_init(void)
.table_id = OFTABLE_LOOKUP_FDB,
};
STATS_NODE(FDB, fdb_request, mac_cache_stats_destroy,
- mac_cache_fdb_stats_process_flow_stats,
- mac_cache_fdb_stats_run);
+ fdb_stats_process_flow_stats, fdb_stats_run);
statctrl_ctx.thread = ovs_thread_create("ovn_statctrl",
statctrl_thread_handler,