There was a race within packet buffering that could
result in first packt being dropped. It could happen
under following conditions and topology:
S1 == R1 == public == R2 == S2
SNAT on R1 and DGP on port connecting R1 with public.

1) The GARP is sent for the GDP SNAT
2) The GARP is delayed on R2 because it's multicast
3) Some traffic that get's buffered on S2
4) An ARP is sent as consequence of the buffering
5) The delayed MAC binding is added to SB
6) Response for the ARP is ignored because the MAC binding
already exists
7) The buffered packet is never sent out and times out

In order to prevent this behavior use the recent MAC bidning
node.

At the same time simplify the packet buffering process
and move it to mac-learn module.

Signed-off-by: Ales Musil <[email protected]>
---
v2: Rebase on top of current main.
v3: Split into two patches.
---
 controller/mac-learn.c      | 138 ++++++++++++++-
 controller/mac-learn.h      |  38 ++++-
 controller/ovn-controller.c |   7 +-
 controller/pinctrl.c        | 325 ++++++++----------------------------
 controller/pinctrl.h        |   4 +-
 5 files changed, 246 insertions(+), 266 deletions(-)

diff --git a/controller/mac-learn.c b/controller/mac-learn.c
index 29c8b1fbb..c1acf03d2 100644
--- a/controller/mac-learn.c
+++ b/controller/mac-learn.c
@@ -18,10 +18,10 @@
 #include "mac-learn.h"
 
 /* OpenvSwitch lib includes. */
+#include "dp-packet.h"
 #include "openvswitch/poll-loop.h"
 #include "openvswitch/vlog.h"
 #include "lib/packets.h"
-#include "lib/random.h"
 #include "lib/smap.h"
 #include "lib/timeval.h"
 
@@ -29,10 +29,11 @@ VLOG_DEFINE_THIS_MODULE(mac_learn);
 
 #define MAX_MAC_BINDINGS 1000
 #define MAX_FDB_ENTRIES  1000
+#define BUFFER_QUEUE_DEPTH 4
 
 static size_t keys_ip_hash(uint32_t dp_key, uint32_t port_key,
                                struct in6_addr *);
-static struct mac_binding *mac_binding_find(struct hmap *mac_bindings,
+static struct mac_binding *mac_binding_find(const struct hmap *mac_bindings,
                                             uint32_t dp_key,
                                             uint32_t port_key,
                                             struct in6_addr *ip, size_t hash);
@@ -165,8 +166,8 @@ keys_ip_hash(uint32_t dp_key, uint32_t port_key, struct 
in6_addr *ip)
 }
 
 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)
+mac_binding_find(const struct hmap *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) {
@@ -201,3 +202,132 @@ fdb_entry_find(struct hmap *fdbs, uint32_t dp_key,
 
     return NULL;
 }
+
+static struct buffered_packets *
+buffered_packets_find(struct hmap *hmap, 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, hmap) {
+        if (mb->dp_key == dp_key && mb->port_key == port_key &&
+            IN6_ARE_ADDR_EQUAL(&mb->ip, ip)) {
+            return mb;
+        }
+    }
+
+    return NULL;
+}
+
+static void
+buffered_packets_destroy(struct buffered_packets *bp)
+{
+    ovn_packet_data_list_destroy(&bp->queue);
+    free(bp);
+}
+
+struct buffered_packets *
+ovn_buffered_packets_add(struct hmap *hmap, 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(hmap, dp_key, port_key, &ip, hash);
+    if (!bp) {
+        if (hmap_count(hmap) >= 1000) {
+            return NULL;
+        }
+
+        bp = xmalloc(sizeof *bp);
+        hmap_insert(hmap, &bp->hmap_node, hash);
+        bp->ip = ip;
+        bp->dp_key = dp_key;
+        bp->port_key = port_key;
+        ovs_list_init(&bp->queue);
+    }
+
+    bp->expire = time_msec() + OVN_BUFFERED_PACKETS_TIMEOUT;
+
+    return bp;
+}
+
+void
+ovn_buffered_packets_add_packet_data(struct buffered_packets *bp,
+                                     struct ofpbuf ofpacts,
+                                     struct dp_packet *packet)
+{
+    struct packet_data *pd = xmalloc(sizeof *pd);
+
+    pd->ofpacts = ofpacts;
+    pd->p = packet;
+
+    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_buffured_packets_prepare_ready(struct hmap *bp_hmap,
+                                   const struct hmap *recent_mac_bindings,
+                                   struct ovs_list *ready_packet_data)
+{
+    long long now = time_msec();
+
+    struct buffered_packets *bp;
+    HMAP_FOR_EACH_SAFE (bp, hmap_node, bp_hmap) {
+        if (now > bp->expire) {
+            hmap_remove(bp_hmap, &bp->hmap_node);
+            buffered_packets_destroy(bp);
+            continue;
+        }
+
+        uint32_t hash = keys_ip_hash(bp->dp_key, bp->port_key, &bp->ip);
+        struct mac_binding *mb = mac_binding_find(recent_mac_bindings,
+                                                  bp->dp_key, bp->port_key,
+                                                  &bp->ip, hash);
+        if (!mb) {
+            continue;
+        }
+
+        struct packet_data *pd;
+        LIST_FOR_EACH_POP (pd, node, &bp->queue) {
+            struct eth_header *eth = dp_packet_data(pd->p);
+            eth->eth_dst = mb->mac;
+
+            ovs_list_push_back(ready_packet_data, &pd->node);
+        }
+
+        hmap_remove(bp_hmap, &bp->hmap_node);
+        buffered_packets_destroy(bp);
+    }
+}
+
+void
+ovn_packet_data_destroy(struct packet_data *pd)
+{
+    dp_packet_delete(pd->p);
+    ofpbuf_uninit(&pd->ofpacts);
+    free(pd);
+}
+
+void
+ovn_packet_data_list_destroy(struct ovs_list *list)
+{
+    struct packet_data *pd;
+    LIST_FOR_EACH_POP (pd, node, list) {
+        ovn_packet_data_destroy(pd);
+    }
+}
+
+void
+ovn_buffered_packets_hmap_destroy(struct hmap *hmap)
+{
+    struct buffered_packets *bp;
+    HMAP_FOR_EACH_POP (bp, hmap_node, hmap) {
+        buffered_packets_destroy(bp);
+    }
+}
diff --git a/controller/mac-learn.h b/controller/mac-learn.h
index 20b6e3b63..7b342d339 100644
--- a/controller/mac-learn.h
+++ b/controller/mac-learn.h
@@ -19,7 +19,11 @@
 
 #include <sys/types.h>
 #include <netinet/in.h>
+
+#include "dp-packet.h"
 #include "openvswitch/hmap.h"
+#include "openvswitch/list.h"
+#include "openvswitch/ofpbuf.h"
 
 struct mac_binding {
     struct hmap_node hmap_node; /* In a hmap. */
@@ -32,7 +36,6 @@ struct mac_binding {
     /* Value. */
     struct eth_addr mac;
 
-    /* Timestamp when to commit to SB. */
     long long expire;
 };
 
@@ -70,6 +73,39 @@ 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 ofpacts;
+    struct dp_packet *p;
+};
+
+struct buffered_packets {
+    struct hmap_node hmap_node;
+
+    struct in6_addr ip;
+    uint64_t dp_key;
+    uint64_t port_key;
+
+    struct ovs_list queue;
+
+    long long int expire;
+};
+
 #define OVN_BUFFERED_PACKETS_TIMEOUT 10000
 
+struct buffered_packets *ovn_buffered_packets_add(struct hmap *hmap,
+                                                  uint64_t dp_key,
+                                                  uint64_t port_key,
+                                                  struct in6_addr ip);
+void ovn_buffered_packets_add_packet_data(struct buffered_packets *bp,
+                                          struct ofpbuf ofpacts,
+                                          struct dp_packet *packet);
+void ovn_buffured_packets_prepare_ready(struct hmap *bp_hmap,
+                                        const struct hmap *recent_mac_bindings,
+                                        struct ovs_list *ready_packet_data);
+void ovn_packet_data_destroy(struct packet_data *pd);
+void ovn_packet_data_list_destroy(struct ovs_list *list);
+void ovn_buffered_packets_hmap_destroy(struct hmap *hmap);
+
 #endif /* OVN_MAC_LEARN_H */
diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
index a42c1affe..4bf841903 100644
--- a/controller/ovn-controller.c
+++ b/controller/ovn-controller.c
@@ -5035,6 +5035,8 @@ main(int argc, char *argv[])
         engine_get_internal_data(&en_template_vars);
     struct ed_type_lb_data *lb_data =
         engine_get_internal_data(&en_lb_data);
+    struct hmap *recent_mac_bindings =
+        engine_get_internal_data(&en_recent_mac_bindings);
 
     ofctrl_init(&lflow_output_data->group_table,
                 &lflow_output_data->meter_table,
@@ -5387,14 +5389,13 @@ main(int argc, char *argv[])
                                         ovnsb_idl_loop.idl),
                                     sbrec_service_monitor_table_get(
                                         ovnsb_idl_loop.idl),
-                                    sbrec_mac_binding_table_get(
-                                        ovnsb_idl_loop.idl),
                                     sbrec_bfd_table_get(ovnsb_idl_loop.idl),
                                     br_int, chassis,
                                     &runtime_data->local_datapaths,
                                     &runtime_data->active_tunnels,
                                     &runtime_data->local_active_ports_ipv6_pd,
-                                    &runtime_data->local_active_ports_ras);
+                                    &runtime_data->local_active_ports_ras,
+                                    recent_mac_bindings);
                         stopwatch_stop(PINCTRL_RUN_STOPWATCH_NAME,
                                        time_msec());
                         mirror_run(ovs_idl_txn,
diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index 611c19568..e57fd4da1 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -178,11 +178,9 @@ struct pinctrl {
 
 static struct pinctrl pinctrl;
 
-static void init_buffered_packets_map(void);
-static void destroy_buffered_packets_map(void);
-static void
-run_buffered_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
-                     const struct sbrec_mac_binding_table *mac_binding_table)
+static void init_buffered_packets_data(void);
+static void destroy_buffered_packets_data(void);
+static void run_buffered_binding(const struct hmap *recent_mac_bidnings)
     OVS_REQUIRES(pinctrl_mutex);
 
 static void pinctrl_handle_put_mac_binding(const struct flow *md,
@@ -535,7 +533,7 @@ pinctrl_init(void)
     init_send_garps_rarps();
     init_ipv6_ras();
     init_ipv6_prefixd();
-    init_buffered_packets_map();
+    init_buffered_packets_data();
     init_activated_ports();
     init_event_table();
     ip_mcast_snoop_init();
@@ -1416,221 +1414,72 @@ prepare_ipv6_prefixd(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
     }
 }
 
-struct buffer_info {
-    struct ofpbuf ofpacts;
-    struct dp_packet *p;
-};
-
-#define BUFFER_QUEUE_DEPTH     4
-struct buffered_packets {
-    struct hmap_node hmap_node;
-    struct ovs_list list;
-
-    /* key */
-    struct in6_addr ip;
-    struct eth_addr ea;
-
-    uint64_t dp_key;
-    uint64_t port_key;
-
-    long long int timestamp;
-
-    struct buffer_info data[BUFFER_QUEUE_DEPTH];
-    uint32_t head, tail;
-};
-
 static struct hmap buffered_packets_map;
-static struct ovs_list buffered_mac_bindings;
+/* List of 'struct packet_data' that is ready to be sent. */
+static struct ovs_list ready_packets_data;
 
 static void
-init_buffered_packets_map(void)
+init_buffered_packets_data(void)
 {
     hmap_init(&buffered_packets_map);
-    ovs_list_init(&buffered_mac_bindings);
-}
-
-static void
-destroy_buffered_packets(struct buffered_packets *bp)
-{
-    struct buffer_info *bi;
-
-    while (bp->head != bp->tail) {
-        bi = &bp->data[bp->head];
-        dp_packet_delete(bi->p);
-        ofpbuf_uninit(&bi->ofpacts);
-
-        bp->head = (bp->head + 1) % BUFFER_QUEUE_DEPTH;
-    }
-}
-
-static void
-destroy_buffered_packets_map(void)
-{
-    struct buffered_packets *bp;
-    HMAP_FOR_EACH_SAFE (bp, hmap_node, &buffered_packets_map) {
-        destroy_buffered_packets(bp);
-        hmap_remove(&buffered_packets_map, &bp->hmap_node);
-        free(bp);
-    }
-    hmap_destroy(&buffered_packets_map);
-
-    LIST_FOR_EACH_POP (bp, list, &buffered_mac_bindings) {
-        destroy_buffered_packets(bp);
-        free(bp);
-    }
+    ovs_list_init(&ready_packets_data);
 }
 
 static void
-buffered_push_packet(struct buffered_packets *bp,
-                     struct dp_packet *packet,
-                     const struct match *md)
-{
-    uint32_t next = (bp->tail + 1) % BUFFER_QUEUE_DEPTH;
-    struct buffer_info *bi = &bp->data[bp->tail];
-
-    ofpbuf_init(&bi->ofpacts, 4096);
-
-    reload_metadata(&bi->ofpacts, md);
-    /* reload pkt_mark field */
-    const struct mf_field *pkt_mark_field = mf_from_id(MFF_PKT_MARK);
-    union mf_value pkt_mark_value;
-    mf_get_value(pkt_mark_field, &md->flow, &pkt_mark_value);
-    ofpact_put_set_field(&bi->ofpacts, pkt_mark_field, &pkt_mark_value, NULL);
-
-    struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&bi->ofpacts);
-    resubmit->in_port = OFPP_CONTROLLER;
-    resubmit->table_id = OFTABLE_REMOTE_OUTPUT;
-
-    bi->p = packet;
-
-    if (next == bp->head) {
-        bi = &bp->data[bp->head];
-        dp_packet_delete(bi->p);
-        ofpbuf_uninit(&bi->ofpacts);
-        bp->head = (bp->head + 1) % BUFFER_QUEUE_DEPTH;
-    }
-    bp->tail = next;
-}
-
-static void
-buffered_send_packets(struct rconn *swconn, struct buffered_packets *bp,
-                      struct eth_addr *addr)
-{
-    enum ofp_version version = rconn_get_version(swconn);
-    enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
-
-    while (bp->head != bp->tail) {
-        struct buffer_info *bi = &bp->data[bp->head];
-        struct eth_header *eth = dp_packet_data(bi->p);
-
-        eth->eth_dst = *addr;
-        struct ofputil_packet_out po = {
-            .packet = dp_packet_data(bi->p),
-            .packet_len = dp_packet_size(bi->p),
-            .buffer_id = UINT32_MAX,
-            .ofpacts = bi->ofpacts.data,
-            .ofpacts_len = bi->ofpacts.size,
-        };
-        match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
-        queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
-
-        ofpbuf_uninit(&bi->ofpacts);
-        dp_packet_delete(bi->p);
-
-        bp->head = (bp->head + 1) % BUFFER_QUEUE_DEPTH;
-    }
-}
-
-static void
-buffered_packets_map_gc(void)
-{
-    struct buffered_packets *cur_qp;
-    long long int now = time_msec();
-
-    HMAP_FOR_EACH_SAFE (cur_qp, hmap_node, &buffered_packets_map) {
-        if (now > cur_qp->timestamp + OVN_BUFFERED_PACKETS_TIMEOUT) {
-            destroy_buffered_packets(cur_qp);
-            hmap_remove(&buffered_packets_map, &cur_qp->hmap_node);
-            free(cur_qp);
-        }
-    }
-}
-
-static uint32_t
-pinctrl_buffer_packet_hash(uint64_t dp_key, uint64_t port_key,
-                           const struct in6_addr *addr)
-{
-    uint32_t hash = 0;
-    hash = hash_add64(hash, port_key);
-    hash = hash_add64(hash, dp_key);
-    hash = hash_bytes(addr, sizeof addr, hash);
-    return hash_finish(hash, 16);
-}
-
-static struct buffered_packets *
-pinctrl_find_buffered_packets(uint64_t dp_key, uint64_t port_key,
-                              const struct in6_addr *ip, uint32_t hash)
-{
-    struct buffered_packets *qp;
-    HMAP_FOR_EACH_WITH_HASH (qp, hmap_node, hash, &buffered_packets_map) {
-        if (qp->dp_key == dp_key && qp->port_key == port_key &&
-            IN6_ARE_ADDR_EQUAL(&qp->ip, ip)) {
-            return qp;
-        }
-    }
-    return NULL;
-}
-
-static struct buffered_packets *
-pinctrl_find_buffered_packets_with_hash(uint64_t dp_key, uint64_t port_key,
-                                        const struct in6_addr *ip)
+destroy_buffered_packets_data(void)
 {
-    uint32_t hash = pinctrl_buffer_packet_hash(dp_key, port_key, ip);
-
-    return pinctrl_find_buffered_packets(dp_key, port_key, ip, hash);
+    ovn_buffered_packets_hmap_destroy(&buffered_packets_map);
+    ovn_packet_data_list_destroy(&ready_packets_data);
 }
 
 /* Called with in the pinctrl_handler thread context. */
-static int
+static void
 pinctrl_handle_buffered_packets(struct dp_packet *pkt_in,
                                 const struct match *md, bool is_arp)
     OVS_REQUIRES(pinctrl_mutex)
 {
-    struct buffered_packets *bp;
+    struct in6_addr ip;
+    struct ofpbuf ofpacts;
     struct dp_packet *clone;
-    struct in6_addr addr;
+    struct buffered_packets *bp;
     uint64_t dp_key = ntohll(md->flow.metadata);
     uint64_t oport_key = md->flow.regs[MFF_LOG_OUTPORT - MFF_REG0];
 
     if (is_arp) {
-        addr = in6_addr_mapped_ipv4(htonl(md->flow.regs[0]));
+        ip = in6_addr_mapped_ipv4(htonl(md->flow.regs[0]));
     } else {
         ovs_be128 ip6 = hton128(flow_get_xxreg(&md->flow, 0));
-        memcpy(&addr, &ip6, sizeof addr);
+        memcpy(&ip, &ip6, sizeof ip);
     }
 
-    uint32_t hash = pinctrl_buffer_packet_hash(dp_key, oport_key, &addr);
-    bp = pinctrl_find_buffered_packets(dp_key, oport_key, &addr, hash);
+    bp = ovn_buffered_packets_add(&buffered_packets_map, dp_key,
+                                  oport_key, ip);
     if (!bp) {
-        if (hmap_count(&buffered_packets_map) >= 1000) {
-            COVERAGE_INC(pinctrl_drop_buffered_packets_map);
-            return -ENOMEM;
-        }
-
-        bp = xmalloc(sizeof *bp);
-        hmap_insert(&buffered_packets_map, &bp->hmap_node, hash);
-        bp->head = bp->tail = 0;
-        bp->ip = addr;
-        bp->dp_key = dp_key;
-        bp->port_key = oport_key;
+        COVERAGE_INC(pinctrl_drop_buffered_packets_map);
+        return;
     }
-    bp->timestamp = time_msec();
+
     /* clone the packet to send it later with correct L2 address */
     clone = dp_packet_clone_data(dp_packet_data(pkt_in),
                                  dp_packet_size(pkt_in));
-    buffered_push_packet(bp, clone, md);
 
-    return 0;
+
+    ofpbuf_init(&ofpacts, 4096);
+    reload_metadata(&ofpacts, md);
+    /* reload pkt_mark field */
+    const struct mf_field *pkt_mark_field = mf_from_id(MFF_PKT_MARK);
+    union mf_value pkt_mark_value;
+    mf_get_value(pkt_mark_field, &md->flow, &pkt_mark_value);
+    ofpact_put_set_field(&ofpacts, pkt_mark_field, &pkt_mark_value, NULL);
+
+    struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
+    resubmit->in_port = OFPP_CONTROLLER;
+    resubmit->table_id = OFTABLE_REMOTE_OUTPUT;
+
+    ovn_buffered_packets_add_packet_data(bp, ofpacts, clone);
+
+    /* There is a chance that the MAC binding was already created. */
+    notify_pinctrl_main();
 }
 
 /* Called with in the pinctrl_handler thread context. */
@@ -3597,14 +3446,14 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
             const struct sbrec_dns_table *dns_table,
             const struct sbrec_controller_event_table *ce_table,
             const struct sbrec_service_monitor_table *svc_mon_table,
-            const struct sbrec_mac_binding_table *mac_binding_table,
             const struct sbrec_bfd_table *bfd_table,
             const struct ovsrec_bridge *br_int,
             const struct sbrec_chassis *chassis,
             const struct hmap *local_datapaths,
             const struct sset *active_tunnels,
             const struct shash *local_active_ports_ipv6_pd,
-            const struct shash *local_active_ports_ras)
+            const struct shash *local_active_ports_ras,
+            const struct hmap *recent_mac_bindings)
 {
     ovs_mutex_lock(&pinctrl_mutex);
     run_put_mac_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key,
@@ -3627,7 +3476,7 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
                   sbrec_port_binding_by_key,
                   sbrec_igmp_groups,
                   sbrec_ip_multicast_opts);
-    run_buffered_binding(sbrec_port_binding_by_name, mac_binding_table);
+    run_buffered_binding(recent_mac_bindings);
     sync_svc_monitors(ovnsb_idl_txn, svc_mon_table, sbrec_port_binding_by_name,
                       chassis);
     bfd_monitor_run(ovnsb_idl_txn, bfd_table, sbrec_port_binding_by_name,
@@ -4153,7 +4002,7 @@ pinctrl_destroy(void)
     destroy_send_garps_rarps();
     destroy_ipv6_ras();
     destroy_ipv6_prefixd();
-    destroy_buffered_packets_map();
+    destroy_buffered_packets_data();
     destroy_activated_ports();
     event_table_destroy();
     destroy_put_mac_bindings();
@@ -4240,12 +4089,25 @@ static void
 send_mac_binding_buffered_pkts(struct rconn *swconn)
     OVS_REQUIRES(pinctrl_mutex)
 {
-    struct buffered_packets *bp;
-    LIST_FOR_EACH_POP (bp, list, &buffered_mac_bindings) {
-        buffered_send_packets(swconn, bp, &bp->ea);
-        free(bp);
+    enum ofp_version version = rconn_get_version(swconn);
+    enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
+
+    struct packet_data *pd;
+    LIST_FOR_EACH_POP (pd, node, &ready_packets_data) {
+        struct ofputil_packet_out po = {
+            .packet = dp_packet_data(pd->p),
+            .packet_len = dp_packet_size(pd->p),
+            .buffer_id = UINT32_MAX,
+            .ofpacts = pd->ofpacts.data,
+            .ofpacts_len = pd->ofpacts.size,
+        };
+        match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
+        queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
+
+        ovn_packet_data_destroy(pd);
     }
-    ovs_list_init(&buffered_mac_bindings);
+
+    ovs_list_init(&ready_packets_data);
 }
 
 static const struct sbrec_mac_binding *
@@ -4405,68 +4267,19 @@ run_put_mac_bindings(struct ovsdb_idl_txn 
*ovnsb_idl_txn,
 }
 
 static void
-run_buffered_binding(struct ovsdb_idl_index *sbrec_port_binding_by_name,
-                     const struct sbrec_mac_binding_table *mac_binding_table)
+run_buffered_binding(const struct hmap *recent_mac_bidnings)
     OVS_REQUIRES(pinctrl_mutex)
 {
-    bool notify = false;
-
-    if (!hmap_count(&buffered_packets_map)) {
+    if (!hmap_count(&buffered_packets_map) ||
+        !hmap_count(recent_mac_bidnings)) {
         return;
     }
 
-    const struct sbrec_mac_binding *mb;
-    SBREC_MAC_BINDING_TABLE_FOR_EACH_TRACKED (mb, mac_binding_table) {
-        const struct sbrec_port_binding *pb = lport_lookup_by_name(
-            sbrec_port_binding_by_name, mb->logical_port);
-        if (!pb || !pb->datapath) {
-            continue;
-        }
+    ovn_buffured_packets_prepare_ready(&buffered_packets_map,
+                                       recent_mac_bidnings,
+                                       &ready_packets_data);
 
-        struct in6_addr ip;
-        ovs_be32 ip4;
-        if (ip_parse(mb->ip, &ip4)) {
-            ip = in6_addr_mapped_ipv4(ip4);
-        } else if (!ipv6_parse(mb->ip, &ip)) {
-            continue;
-        }
-
-        struct buffered_packets *bp = pinctrl_find_buffered_packets_with_hash(
-                pb->datapath->tunnel_key, pb->tunnel_key, &ip);
-        if (!bp) {
-            if (!smap_get(&pb->options, "chassis-redirect-port")) {
-                continue;
-            }
-
-            char *redirect_name = xasprintf("cr-%s", pb->logical_port);
-            pb = lport_lookup_by_name(sbrec_port_binding_by_name,
-                                      redirect_name);
-            free(redirect_name);
-
-            if (!pb || !pb->datapath || strcmp(pb->type, "chassisredirect")) {
-                continue;
-            }
-
-            bp = pinctrl_find_buffered_packets_with_hash(
-                    pb->datapath->tunnel_key, pb->tunnel_key, &ip);
-        }
-
-        if (!bp) {
-            continue;
-        }
-
-        if (!ovs_scan(mb->mac, ETH_ADDR_SCAN_FMT,
-                      ETH_ADDR_SCAN_ARGS(bp->ea))) {
-            continue;
-        }
-
-        hmap_remove(&buffered_packets_map, &bp->hmap_node);
-        ovs_list_push_back(&buffered_mac_bindings, &bp->list);
-        notify = true;
-    }
-    buffered_packets_map_gc();
-
-    if (notify) {
+    if (!ovs_list_is_empty(&ready_packets_data)) {
         notify_pinctrl_handler();
     }
 }
@@ -6073,7 +5886,7 @@ may_inject_pkts(void)
             !shash_is_empty(&send_garp_rarp_data) ||
             ipv6_prefixd_should_inject() ||
             !ovs_list_is_empty(&mcast_query_list) ||
-            !ovs_list_is_empty(&buffered_mac_bindings) ||
+            !ovs_list_is_empty(&ready_packets_data) ||
             bfd_monitor_should_inject());
 }
 
diff --git a/controller/pinctrl.h b/controller/pinctrl.h
index 279a49fbc..cf4071952 100644
--- a/controller/pinctrl.h
+++ b/controller/pinctrl.h
@@ -51,13 +51,13 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
                  const struct sbrec_dns_table *,
                  const struct sbrec_controller_event_table *,
                  const struct sbrec_service_monitor_table *,
-                 const struct sbrec_mac_binding_table *,
                  const struct sbrec_bfd_table *,
                  const struct ovsrec_bridge *, const struct sbrec_chassis *,
                  const struct hmap *local_datapaths,
                  const struct sset *active_tunnels,
                  const struct shash *local_active_ports_ipv6_pd,
-                 const struct shash *local_active_ports_ras);
+                 const struct shash *local_active_ports_ras,
+                 const struct hmap *recent_mac_bindings);
 void pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn);
 void pinctrl_destroy(void);
 void pinctrl_set_br_int_name(const char *br_int_name);
-- 
2.39.2

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to