datapath: Add support for RHEL-7 / CentOS-7 kernel.
[cascardo/ovs.git] / lib / flow.c
index 2df7b3d..9018b66 100644 (file)
@@ -277,7 +277,7 @@ parse_icmpv6(void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
         (icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
          icmp->icmp6_type == ND_NEIGHBOR_ADVERT)) {
 
-        *nd_target = data_try_pull(datap, sizep, sizeof *nd_target);
+        *nd_target = data_try_pull(datap, sizep, sizeof **nd_target);
         if (OVS_UNLIKELY(!*nd_target)) {
             return false;
         }
@@ -607,12 +607,12 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
                 memset(arp_buf, 0, sizeof arp_buf);
                 if (OVS_LIKELY(parse_icmpv6(&data, &size, icmp, &nd_target,
                                             arp_buf))) {
+                    miniflow_push_words(mf, arp_sha, arp_buf,
+                                             ETH_ADDR_LEN * 2 / 4);
                     if (nd_target) {
                         miniflow_push_words(mf, nd_target, nd_target,
                                             sizeof *nd_target / 4);
                     }
-                    miniflow_push_words(mf, arp_sha, arp_buf,
-                                             ETH_ADDR_LEN * 2 / 4);
                     miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type));
                     miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code));
                 }
@@ -1512,6 +1512,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
 
         l4_len = flow_compose_l4(b, flow);
 
+        ip = ofpbuf_l3(b);
         ip->ip_tot_len = htons(b->l4_ofs - b->l3_ofs + l4_len);
         ip->ip_csum = csum(ip, sizeof *ip);
     } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
@@ -1530,6 +1531,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
 
         l4_len = flow_compose_l4(b, flow);
 
+        nh = ofpbuf_l3(b);
         nh->ip6_plen = htons(l4_len);
     } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
                flow->dl_type == htons(ETH_TYPE_RARP)) {
@@ -1578,13 +1580,15 @@ miniflow_n_values(const struct miniflow *flow)
 static uint32_t *
 miniflow_alloc_values(struct miniflow *flow, int n)
 {
-    if (n <= sizeof flow->inline_values / sizeof(uint32_t)) {
+    int size = MINIFLOW_VALUES_SIZE(n);
+
+    if (size <= sizeof flow->inline_values) {
         flow->values_inline = true;
         return flow->inline_values;
     } else {
         COVERAGE_INC(miniflow_malloc);
         flow->values_inline = false;
-        flow->offline_values = xmalloc(n * sizeof(uint32_t));
+        flow->offline_values = xmalloc(size);
         return flow->offline_values;
     }
 }
@@ -1652,18 +1656,57 @@ miniflow_init_with_minimask(struct miniflow *dst, const struct flow *src,
 void
 miniflow_clone(struct miniflow *dst, const struct miniflow *src)
 {
-    int n = miniflow_n_values(src);
+    int size = MINIFLOW_VALUES_SIZE(miniflow_n_values(src));
+    uint32_t *values;
+
     dst->map = src->map;
-    memcpy(miniflow_alloc_values(dst, n), miniflow_get_values(src),
-           n * sizeof(uint32_t));
+    if (size <= sizeof dst->inline_values) {
+        dst->values_inline = true;
+        values = dst->inline_values;
+    } else {
+        dst->values_inline = false;
+        COVERAGE_INC(miniflow_malloc);
+        dst->offline_values = xmalloc(size);
+        values = dst->offline_values;
+    }
+    memcpy(values, miniflow_get_values(src), size);
+}
+
+/* Initializes 'dst' as a copy of 'src'.  The caller must have allocated
+ * 'dst' to have inline space all data in 'src'. */
+void
+miniflow_clone_inline(struct miniflow *dst, const struct miniflow *src,
+                      size_t n_values)
+{
+    dst->values_inline = true;
+    dst->map = src->map;
+    memcpy(dst->inline_values, miniflow_get_values(src),
+           MINIFLOW_VALUES_SIZE(n_values));
 }
 
 /* Initializes 'dst' with the data in 'src', destroying 'src'.
- * The caller must eventually free 'dst' with miniflow_destroy(). */
+ * The caller must eventually free 'dst' with miniflow_destroy().
+ * 'dst' must be regularly sized miniflow, but 'src' can have
+ * larger than default inline values. */
 void
 miniflow_move(struct miniflow *dst, struct miniflow *src)
 {
-    *dst = *src;
+    int size = MINIFLOW_VALUES_SIZE(miniflow_n_values(src));
+
+    dst->map = src->map;
+    if (size <= sizeof dst->inline_values) {
+        dst->values_inline = true;
+        memcpy(dst->inline_values, miniflow_get_values(src), size);
+        miniflow_destroy(src);
+    } else if (src->values_inline) {
+        dst->values_inline = false;
+        COVERAGE_INC(miniflow_malloc);
+        dst->offline_values = xmalloc(size);
+        memcpy(dst->offline_values, src->inline_values, size);
+    } else {
+        dst->values_inline = false;
+        dst->offline_values = src->offline_values;
+    }
 }
 
 /* Frees any memory owned by 'flow'.  Does not free the storage in which 'flow'