[ovs-dev,2/2] OVN: add buffering support for ipv6 packets

Message ID a893ae299c49b510ee3ed13564a648beea25de25.1536937902.git.lorenzo.bianconi@redhat.com
State New
Headers show
Series
  • add buffering support for IP packets
Related show

Commit Message

Lorenzo Bianconi Sept. 14, 2018, 3:19 p.m.
Add buffering support for IPv6 packets that will be processed by
nd_ns {} action when L2 address is not discovered yet since
otherwise the packet will be substituted with a Neighbor Solicitation
frame and this will result in the lost of the first packet of the
connection

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 ovn/controller/pinctrl.c | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

Patch

diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 3f8c0ac4e..6436be428 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -99,6 +99,7 @@  static void pinctrl_handle_put_nd_ra_opts(
     struct ofputil_packet_in *pin, struct ofpbuf *userdata,
     struct ofpbuf *continuation);
 static void pinctrl_handle_nd_ns(const struct flow *ip_flow,
+                                 struct dp_packet *pkt_in,
                                  const struct match *md,
                                  struct ofpbuf *userdata);
 static void init_ipv6_ras(void);
@@ -1358,7 +1359,8 @@  process_packet_in(const struct ofp_header *msg,
         break;
 
     case ACTION_OPCODE_ND_NS:
-        pinctrl_handle_nd_ns(&headers, &pin.flow_metadata, &userdata);
+        pinctrl_handle_nd_ns(&headers, &packet, &pin.flow_metadata,
+                             &userdata);
         break;
 
     case ACTION_OPCODE_ICMP:
@@ -2569,9 +2571,13 @@  pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md,
 }
 
 static void
-pinctrl_handle_nd_ns(const struct flow *ip_flow, const struct match *md,
-                     struct ofpbuf *userdata)
+pinctrl_handle_nd_ns(const struct flow *ip_flow, struct dp_packet *pkt_in,
+                     const struct match *md, struct ofpbuf *userdata)
 {
+    struct dp_packet *clone, packet;
+    uint64_t packet_stub[128 / 8];
+    char ip[INET6_ADDRSTRLEN];
+
     /* This action only works for IPv6 packets. */
     if (get_dl_type(ip_flow) != htons(ETH_TYPE_IPV6)) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -2579,8 +2585,27 @@  pinctrl_handle_nd_ns(const struct flow *ip_flow, const struct match *md,
         return;
     }
 
-    uint64_t packet_stub[128 / 8];
-    struct dp_packet packet;
+    inet_ntop(AF_INET6, &ip_flow->ipv6_dst, ip, sizeof(ip));
+    uint32_t hash = hash_string(ip, 0);
+    struct buffered_packets *bp = pinctrl_find_buffered_packets(ip, hash);
+    if (!bp) {
+        if (hmap_count(&buffered_packets_map) >= 1000) {
+            COVERAGE_INC(pinctrl_drop_buffered_packets_map);
+            goto send_ns;
+        }
+
+        bp = xmalloc(sizeof *bp);
+        hmap_insert(&buffered_packets_map, &bp->hmap_node, hash);
+        ovs_strlcpy_arrays(bp->ip, ip);
+        bp->head = bp->tail = 0;
+    }
+    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);
+
+send_ns:
     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
 
     compose_nd_ns(&packet, ip_flow->dl_src, &ip_flow->ipv6_src,