upcall: Defer ukey deletion until after pushing stats.
[cascardo/ovs.git] / lib / dpif-netdev.c
index 20f4a9e..d32b1bd 100644 (file)
@@ -166,7 +166,7 @@ static int do_add_port(struct dp_netdev *, const char *devname,
 static int do_del_port(struct dp_netdev *, odp_port_t port_no);
 static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
-static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
+static int dp_netdev_output_userspace(struct dp_netdev *, struct ofpbuf *,
                                     int queue_no, const struct flow *,
                                     const struct nlattr *userdata);
 static void dp_netdev_execute_actions(struct dp_netdev *, const struct flow *,
@@ -175,8 +175,7 @@ static void dp_netdev_execute_actions(struct dp_netdev *, const struct flow *,
                                       size_t actions_len);
 static void dp_netdev_port_input(struct dp_netdev *dp,
                                  struct dp_netdev_port *port,
-                                 struct ofpbuf *packet, uint32_t skb_priority,
-                                 uint32_t pkt_mark, const struct flow_tnl *tnl);
+                                 struct ofpbuf *packet);
 
 static struct dpif_netdev *
 dpif_netdev_cast(const struct dpif *dpif)
@@ -344,6 +343,7 @@ dp_netdev_purge_queues(struct dp_netdev *dp)
 
         while (q->tail != q->head) {
             struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+            ofpbuf_uninit(&u->upcall.packet);
             ofpbuf_uninit(&u->buf);
         }
     }
@@ -406,7 +406,7 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
     stats->n_hit = dp->n_hit;
     stats->n_missed = dp->n_missed;
     stats->n_lost = dp->n_lost;
-    stats->n_masks = UINT64_MAX;
+    stats->n_masks = UINT32_MAX;
     stats->n_mask_hit = UINT64_MAX;
     ovs_mutex_unlock(&dp_netdev_mutex);
 
@@ -638,9 +638,9 @@ dpif_netdev_get_max_ports(const struct dpif *dpif OVS_UNUSED)
 static void
 dp_netdev_free_flow(struct dp_netdev *dp, struct dp_netdev_flow *netdev_flow)
 {
-    ovs_rwlock_wrlock(&dp->cls.rwlock);
+    fat_rwlock_wrlock(&dp->cls.rwlock);
     classifier_remove(&dp->cls, &netdev_flow->cr);
-    ovs_rwlock_unlock(&dp->cls.rwlock);
+    fat_rwlock_unlock(&dp->cls.rwlock);
     cls_rule_destroy(&netdev_flow->cr);
 
     hmap_remove(&dp->flow_table, &netdev_flow->node);
@@ -755,9 +755,9 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp, const struct flow *flow)
 {
     struct cls_rule *cr;
 
-    ovs_rwlock_wrlock(&dp->cls.rwlock);
+    fat_rwlock_wrlock(&dp->cls.rwlock);
     cr = classifier_lookup(&dp->cls, flow, NULL);
-    ovs_rwlock_unlock(&dp->cls.rwlock);
+    fat_rwlock_unlock(&dp->cls.rwlock);
 
     return (cr
             ? CONTAINER_OF(cr, struct dp_netdev_flow, cr)
@@ -928,15 +928,15 @@ dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *flow,
 
     match_init(&match, flow, wc);
     cls_rule_init(&netdev_flow->cr, &match, NETDEV_RULE_PRIORITY);
-    ovs_rwlock_wrlock(&dp->cls.rwlock);
+    fat_rwlock_wrlock(&dp->cls.rwlock);
     classifier_insert(&dp->cls, &netdev_flow->cr);
-    ovs_rwlock_unlock(&dp->cls.rwlock);
+    fat_rwlock_unlock(&dp->cls.rwlock);
 
     error = set_flow_actions(netdev_flow, actions, actions_len);
     if (error) {
-        ovs_rwlock_wrlock(&dp->cls.rwlock);
+        fat_rwlock_wrlock(&dp->cls.rwlock);
         classifier_remove(&dp->cls, &netdev_flow->cr);
-        ovs_rwlock_unlock(&dp->cls.rwlock);
+        fat_rwlock_unlock(&dp->cls.rwlock);
         cls_rule_destroy(&netdev_flow->cr);
 
         free(netdev_flow);
@@ -1154,20 +1154,15 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
     /* Get packet metadata. */
     error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len, &md);
     if (!error) {
-        struct ofpbuf *copy;
         struct flow key;
 
-        /* Make a deep copy of 'packet', because we might modify its data. */
-        copy = ofpbuf_clone_with_headroom(execute->packet, DP_NETDEV_HEADROOM);
-
         /* Extract flow key. */
-        flow_extract(copy, md.skb_priority, md.pkt_mark, &md.tunnel,
+        flow_extract(execute->packet, md.skb_priority, md.pkt_mark, &md.tunnel,
                      &md.in_port, &key);
         ovs_mutex_lock(&dp_netdev_mutex);
-        dp_netdev_execute_actions(dp, &key, copy,
+        dp_netdev_execute_actions(dp, &key, execute->packet,
                                   execute->actions, execute->actions_len);
         ovs_mutex_unlock(&dp_netdev_mutex);
-        ofpbuf_delete(copy);
     }
     return error;
 }
@@ -1214,7 +1209,6 @@ dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
         struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
 
         *upcall = u->upcall;
-        upcall->packet = buf;
 
         ofpbuf_uninit(buf);
         *buf = u->buf;
@@ -1265,8 +1259,7 @@ dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
 
 static void
 dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
-                     struct ofpbuf *packet, uint32_t skb_priority,
-                     uint32_t pkt_mark, const struct flow_tnl *tnl)
+                     struct ofpbuf *packet)
 {
     struct dp_netdev_flow *netdev_flow;
     struct flow key;
@@ -1276,7 +1269,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
         return;
     }
     in_port_.odp_port = port->port_no;
-    flow_extract(packet, skb_priority, pkt_mark, tnl, &in_port_, &key);
+    flow_extract(packet, 0, 0, NULL, &in_port_, &key);
     netdev_flow = dp_netdev_lookup_flow(dp, &key);
     if (netdev_flow) {
         dp_netdev_flow_used(netdev_flow, packet);
@@ -1296,22 +1289,24 @@ dpif_netdev_run(struct dpif *dpif)
     struct dp_netdev_port *port;
     struct dp_netdev *dp;
     struct ofpbuf packet;
+    size_t buf_size;
 
     ovs_mutex_lock(&dp_netdev_mutex);
     dp = get_dp_netdev(dpif);
-    ofpbuf_init(&packet,
-                DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu);
+    ofpbuf_init(&packet, 0);
+
+    buf_size = DP_NETDEV_HEADROOM + VLAN_ETH_HEADER_LEN + dp->max_mtu;
 
     LIST_FOR_EACH (port, node, &dp->port_list) {
         int error;
 
-        /* Reset packet contents. */
+        /* Reset packet contents. Packet data may have been stolen. */
         ofpbuf_clear(&packet);
-        ofpbuf_reserve(&packet, DP_NETDEV_HEADROOM);
+        ofpbuf_reserve_with_tailroom(&packet, DP_NETDEV_HEADROOM, buf_size);
 
         error = port->rx ? netdev_rx_recv(port->rx, &packet) : EOPNOTSUPP;
         if (!error) {
-            dp_netdev_port_input(dp, port, &packet, 0, 0, NULL);
+            dp_netdev_port_input(dp, port, &packet);
         } else if (error != EAGAIN && error != EOPNOTSUPP) {
             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
@@ -1351,7 +1346,7 @@ dpif_netdev_wait(struct dpif *dpif)
 }
 
 static int
-dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
+dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                            int queue_no, const struct flow *flow,
                            const struct nlattr *userdata)
 {
@@ -1365,7 +1360,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
         upcall->type = queue_no;
 
         /* Allocate buffer big enough for everything. */
-        buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
+        buf_size = ODPUTIL_FLOW_KEY_BYTES;
         if (userdata) {
             buf_size += NLA_ALIGN(userdata->nla_len);
         }
@@ -1382,15 +1377,10 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
                                           NLA_ALIGN(userdata->nla_len));
         }
 
-        /* Put packet.
-         *
-         * We adjust 'data' and 'size' in 'buf' so that only the packet itself
-         * is visible in 'upcall->packet'.  The ODP flow and (if present)
-         * userdata become part of the headroom. */
-        ofpbuf_put_zeros(buf, 2);
-        buf->data = ofpbuf_put(buf, packet->data, packet->size);
-        buf->size = packet->size;
-        upcall->packet = buf;
+        /* Steal packet data. */
+        ovs_assert(packet->source == OFPBUF_MALLOC);
+        upcall->packet = *packet;
+        ofpbuf_use(packet, NULL, 0);
 
         seq_change(dp->queue_seq);
 
@@ -1421,14 +1411,22 @@ dp_netdev_action_output(void *aux_, struct ofpbuf *packet,
 static void
 dp_netdev_action_userspace(void *aux_, struct ofpbuf *packet,
                            const struct flow *flow OVS_UNUSED,
-                           const struct nlattr *a)
+                           const struct nlattr *a, bool may_steal)
 {
     struct dp_netdev_execute_aux *aux = aux_;
     const struct nlattr *userdata;
 
     userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
+
+    /* Make a copy if we are not allowed to steal the packet's data. */
+    if (!may_steal) {
+        packet = ofpbuf_clone_with_headroom(packet, DP_NETDEV_HEADROOM);
+    }
     dp_netdev_output_userspace(aux->dp, packet, DPIF_UC_ACTION, aux->key,
                                userdata);
+    if (!may_steal) {
+        ofpbuf_uninit(packet);
+    }
 }
 
 static void