diff mbox series

[ovs-dev,v3,16/16] Reinject RARP packet when activation-strategy=rarp

Message ID 20220217151712.2292329-17-ihrachys@redhat.com
State Changes Requested
Headers show
Series Support additional-chassis for ports | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test fail github build: failed
ovsrobot/github-robot-_ovn-kubernetes fail github build: failed

Commit Message

Ihar Hrachyshka Feb. 17, 2022, 3:17 p.m. UTC
It takes some time for vswitchd to remove the blocking flows, so we need
to wait for the flow_mod message handled before reinjecting the received
RARP packet into the pipeline.

Use a barrier to indicate the message processed by vswitchd.

Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
---
 controller/pinctrl.c | 103 ++++++++++++++++++++++++++++++++++++++++---
 tests/ovn.at         |   8 +++-
 2 files changed, 105 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/controller/pinctrl.c b/controller/pinctrl.c
index af9279bb4..d95a5d8bf 100644
--- a/controller/pinctrl.c
+++ b/controller/pinctrl.c
@@ -201,7 +201,14 @@  static void send_mac_binding_buffered_pkts(struct rconn *swconn)
     OVS_REQUIRES(pinctrl_mutex);
 
 static void pinctrl_rarp_activation_strategy_handler(struct rconn *swconn,
-                                                     const struct match *md);
+                                                     const struct match *md,
+                                                     struct dp_packet *pkt_in);
+
+static void init_pending_rarp_packets(void);
+static void destroy_pending_rarp_packets(void);
+static void flush_pending_rarp_packets(struct rconn *swconn, uint32_t xid)
+    OVS_REQUIRES(pinctrl_mutex);
+
 static void init_activated_ports(void);
 static void destroy_activated_ports(void);
 static void wait_activated_ports(struct ovsdb_idl_txn *ovnsb_idl_txn);
@@ -536,6 +543,7 @@  pinctrl_init(void)
     init_ipv6_prefixd();
     init_buffered_packets_map();
     init_activated_ports();
+    init_pending_rarp_packets();
     init_event_table();
     ip_mcast_snoop_init();
     init_put_vport_bindings();
@@ -3258,7 +3266,8 @@  process_packet_in(struct rconn *swconn, const struct ofp_header *msg)
 
     case ACTION_OPCODE_ACTIVATION_STRATEGY_RARP:
         ovs_mutex_lock(&pinctrl_mutex);
-        pinctrl_rarp_activation_strategy_handler(swconn, &pin.flow_metadata);
+        pinctrl_rarp_activation_strategy_handler(swconn, &pin.flow_metadata,
+                                                 &packet);
         ovs_mutex_unlock(&pinctrl_mutex);
         break;
 
@@ -3319,6 +3328,10 @@  pinctrl_recv(struct rconn *swconn, const struct ofp_header *oh,
     } else if (type == OFPTYPE_PACKET_IN) {
         COVERAGE_INC(pinctrl_total_pin_pkts);
         process_packet_in(swconn, oh);
+    } else if (type == OFPTYPE_BARRIER_REPLY) {
+        ovs_mutex_lock(&pinctrl_mutex);
+        flush_pending_rarp_packets(swconn, ntohl(oh->xid));
+        ovs_mutex_unlock(&pinctrl_mutex);
     } else {
         if (VLOG_IS_DBG_ENABLED()) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
@@ -4072,6 +4085,7 @@  pinctrl_destroy(void)
     destroy_ipv6_prefixd();
     destroy_buffered_packets_map();
     destroy_activated_ports();
+    destroy_pending_rarp_packets();
     event_table_destroy();
     destroy_put_mac_bindings();
     destroy_put_vport_bindings();
@@ -7760,6 +7774,70 @@  encode_flow_mod(struct ofputil_flow_mod *fm)
     return ofputil_encode_flow_mod(fm, OFPUTIL_P_OF15_OXM);
 }
 
+struct rarp_packet {
+    uint32_t xid;
+    int64_t dp_key;
+    int64_t port_key;
+    struct dp_packet *pkt;
+    struct ovs_list list;
+};
+
+static struct ovs_list pending_rarp_packets;
+
+static void
+init_pending_rarp_packets(void)
+{
+    ovs_list_init(&pending_rarp_packets);
+}
+
+static void
+destroy_pending_rarp_packets(void)
+{
+    struct rarp_packet *rp;
+    LIST_FOR_EACH_POP (rp, list, &pending_rarp_packets) {
+        free(rp->pkt);
+        free(rp);
+    }
+}
+
+static void flush_pending_rarp_packets(struct rconn *swconn, uint32_t xid)
+    OVS_REQUIRES(pinctrl_mutex)
+{
+    struct rarp_packet *rp, *next;
+    LIST_FOR_EACH_SAFE (rp, next, list, &pending_rarp_packets) {
+        if (rp->xid != xid) {
+            continue;
+        }
+        /* Blocking flows are now gone; re-inject RARP message. */
+        uint64_t ofpacts_stub[4096 / 8];
+        struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
+        enum ofp_version version = rconn_get_version(swconn);
+        put_load(rp->dp_key, MFF_LOG_DATAPATH, 0, 64, &ofpacts);
+        put_load(rp->port_key, MFF_LOG_INPORT, 0, 32, &ofpacts);
+        struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
+        resubmit->in_port = OFPP_CONTROLLER;
+        resubmit->table_id = OFTABLE_LOG_INGRESS_PIPELINE;
+
+        struct ofputil_packet_out po = {
+            .packet = dp_packet_data(rp->pkt),
+            .packet_len = dp_packet_size(rp->pkt),
+            .buffer_id = UINT32_MAX,
+            .ofpacts = ofpacts.data,
+            .ofpacts_len = ofpacts.size,
+        };
+        match_set_in_port(&po.flow_metadata, OFPP_CONTROLLER);
+
+        enum ofputil_protocol proto;
+        proto = ofputil_protocol_from_ofp_version(version);
+        queue_msg(swconn, ofputil_encode_packet_out(&po, proto));
+        ofpbuf_uninit(&ofpacts);
+
+        ovs_list_remove(&rp->list);
+        free(rp->pkt);
+        free(rp);
+    }
+}
+
 struct port_pair {
     uint32_t dp_key;
     uint32_t port_key;
@@ -7828,7 +7906,8 @@  bool pinctrl_is_port_activated(int64_t dp_key, int64_t port_key)
 
 static void
 pinctrl_rarp_activation_strategy_handler(struct rconn *swconn,
-                                         const struct match *md)
+                                         const struct match *md,
+                                         struct dp_packet *pkt_in)
     OVS_REQUIRES(pinctrl_mutex)
 {
     struct match match;
@@ -7874,10 +7953,24 @@  pinctrl_rarp_activation_strategy_handler(struct rconn *swconn,
     queue_msg(swconn, encode_flow_mod(&fm));
     minimatch_destroy(&mmatch);
 
+    ovs_be32 xid = queue_msg(
+        swconn, ofputil_encode_barrier_request(OFP15_VERSION));
+
+    /* Delay delivery of RARP to when blocking flows are deleted. */
+    uint32_t port_key = md->flow.regs[MFF_LOG_INPORT - MFF_REG0];
+    uint32_t dp_key = ntohll(md->flow.metadata);
+
+    struct rarp_packet *rp = xmalloc(sizeof *rp);
+    rp->xid = ntohl(xid);
+    rp->port_key = port_key;
+    rp->dp_key = dp_key;
+    rp->pkt = dp_packet_clone(pkt_in);
+    ovs_list_push_back(&pending_rarp_packets, &rp->list);
+
     /* Tag the port as activated in-memory. */
     struct port_pair *pp = xmalloc(sizeof *pp);
-    pp->port_key = md->flow.regs[MFF_LOG_INPORT - MFF_REG0];
-    pp->dp_key = ntohll(md->flow.metadata);
+    pp->port_key = port_key;
+    pp->dp_key = dp_key;
     ovs_list_push_front(&activated_ports, &pp->list);
 
     /* Notify main thread on pending additional-chassis-activated updates. */
diff --git a/tests/ovn.at b/tests/ovn.at
index a0698c362..f6c2e309f 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -14450,6 +14450,7 @@  send_rarp() {
     local hv=$1 inport=$2 eth_src=$3 eth_dst=$4 spa=$5 tpa=$6
     local request=${eth_dst}${eth_src}80350001080006040001${eth_src}${spa}${eth_dst}${tpa}
     as ${hv} ovs-appctl netdev-dummy/receive $inport $request
+    echo "${request}"
 }
 
 reset_pcap_file() {
@@ -14508,7 +14509,12 @@  reset_env
 AT_CHECK([ovn-sbctl find port_binding logical_port=migrator | grep -q additional-chassis-activated], [1])
 
 # Now activate hv2:Migrator location
-send_rarp hv2 migrator 000000000001 ffffffffffff $migrator_spa $migrator_spa
+request=$(send_rarp hv2 migrator 000000000001 ffffffffffff $migrator_spa $migrator_spa)
+
+# RARP was reinjected into the pipeline
+echo $request >> hv3/outside.expected
+
+check_packets
 reset_env
 
 pb_uuid=$(ovn-sbctl --bare --columns _uuid find Port_Binding logical_port=migrator)