Merge branch 'mainstream'
[sliver-openvswitch.git] / lib / dpif-netdev.c
index 7fa2720..9f7bb6e 100644 (file)
@@ -70,8 +70,13 @@ enum { MAX_QUEUE_LEN = 128 };   /* Maximum number of packets per queue. */
 enum { QUEUE_MASK = MAX_QUEUE_LEN - 1 };
 BUILD_ASSERT_DECL(IS_POW2(MAX_QUEUE_LEN));
 
+struct dp_netdev_upcall {
+    struct dpif_upcall upcall;  /* Queued upcall information. */
+    struct ofpbuf buf;          /* ofpbuf instance for upcall.packet. */
+};
+
 struct dp_netdev_queue {
-    struct dpif_upcall *upcalls[MAX_QUEUE_LEN];
+    struct dp_netdev_upcall upcalls[MAX_QUEUE_LEN];
     unsigned int head, tail;
 };
 
@@ -259,10 +264,8 @@ dp_netdev_purge_queues(struct dp_netdev *dp)
         struct dp_netdev_queue *q = &dp->queues[i];
 
         while (q->tail != q->head) {
-            struct dpif_upcall *upcall = q->upcalls[q->tail++ & QUEUE_MASK];
-
-            ofpbuf_delete(upcall->packet);
-            free(upcall);
+            struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+            ofpbuf_uninit(&u->buf);
         }
     }
 }
@@ -313,6 +316,15 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
     return 0;
 }
 
+static const char* internal_port_type(const struct dp_netdev* dp)
+{
+       if (dp->class == &dpif_netdev_class)
+               return "tap";
+       if (dp->class == &dpif_planetlab_class)
+               return "pltap";
+       return "dummy";
+}
+
 static int
 do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
             uint16_t port_no)
@@ -326,9 +338,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
     /* XXX reject devices already in some dp_netdev. */
 
     /* Open and validate network device. */
-    open_type = (strcmp(type, "internal") ? type
-                 : dp->class != &dpif_netdev_class ? "dummy"
-                 : "tap");
+    open_type = (strcmp(type, "internal") ? type : internal_port_type(dp));
     error = netdev_open(devname, open_type, &netdev);
     if (error) {
         return error;
@@ -373,7 +383,9 @@ choose_port(struct dpif *dpif, struct netdev *netdev)
     struct dp_netdev *dp = get_dp_netdev(dpif);
     int port_no;
 
-    if (dpif->dpif_class != &dpif_netdev_class) {
+    if (dpif->dpif_class != &dpif_netdev_class &&
+        dpif->dpif_class != &dpif_planetlab_class)
+    {
         /* If the port name contains a number, try to assign that port number.
          * This can make writing unit tests easier because port numbers are
          * predictable. */
@@ -913,7 +925,7 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
     ofpbuf_reserve(&copy, DP_NETDEV_HEADROOM);
     ofpbuf_put(&copy, execute->packet->data, execute->packet->size);
 
-    flow_extract(&copy, 0, 0, -1, &key);
+    flow_extract(&copy, 0, NULL, -1, &key);
     error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
                                           &key);
     if (!error) {
@@ -960,12 +972,13 @@ dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
 {
     struct dp_netdev_queue *q = find_nonempty_queue(dpif);
     if (q) {
-        struct dpif_upcall *u = q->upcalls[q->tail++ & QUEUE_MASK];
-        *upcall = *u;
-        free(u);
+        struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+
+        *upcall = u->upcall;
+        upcall->packet = buf;
 
         ofpbuf_uninit(buf);
-        *buf = *upcall->packet;
+        *buf = u->buf;
 
         return 0;
     } else {
@@ -992,13 +1005,12 @@ dpif_netdev_recv_purge(struct dpif *dpif)
 }
 \f
 static void
-dp_netdev_flow_used(struct dp_netdev_flow *flow, struct flow *key,
-                    const struct ofpbuf *packet)
+dp_netdev_flow_used(struct dp_netdev_flow *flow, const struct ofpbuf *packet)
 {
     flow->used = time_msec();
     flow->packet_count++;
     flow->byte_count += packet->size;
-    flow->tcp_flags |= packet_get_tcp_flags(packet, key);
+    flow->tcp_flags |= packet_get_tcp_flags(packet, &flow->key);
 }
 
 static void
@@ -1011,10 +1023,10 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
     if (packet->size < ETH_HEADER_LEN) {
         return;
     }
-    flow_extract(packet, 0, 0, odp_port_to_ofp_port(port->port_no), &key);
+    flow_extract(packet, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
     flow = dp_netdev_lookup_flow(dp, &key);
     if (flow) {
-        dp_netdev_flow_used(flow, &key, packet);
+        dp_netdev_flow_used(flow, packet);
         dp_netdev_execute_actions(dp, packet, &key,
                                   flow->actions, flow->actions_len);
         dp->n_hit++;
@@ -1087,6 +1099,7 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
                          int queue_no, const struct flow *flow, uint64_t arg)
 {
     struct dp_netdev_queue *q = &dp->queues[queue_no];
+    struct dp_netdev_upcall *u;
     struct dpif_upcall *upcall;
     struct ofpbuf *buf;
     size_t key_len;
@@ -1096,22 +1109,23 @@ dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
         return ENOBUFS;
     }
 
-    buf = ofpbuf_new(ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
+    u = &q->upcalls[q->head++ & QUEUE_MASK];
+
+    buf = &u->buf;
+    ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
     odp_flow_key_from_flow(buf, flow);
     key_len = buf->size;
     ofpbuf_pull(buf, key_len);
     ofpbuf_reserve(buf, 2);
     ofpbuf_put(buf, packet->data, packet->size);
 
-    upcall = xzalloc(sizeof *upcall);
+    upcall = &u->upcall;
     upcall->type = queue_no;
     upcall->packet = buf;
     upcall->key = buf->base;
     upcall->key_len = key_len;
     upcall->userdata = arg;
 
-    q->upcalls[q->head++ & QUEUE_MASK] = upcall;
-
     return 0;
 }
 
@@ -1174,6 +1188,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
     case OVS_KEY_ATTR_TUN_ID:
     case OVS_KEY_ATTR_PRIORITY:
     case OVS_KEY_ATTR_IPV6:
+    case OVS_KEY_ATTR_IPV4_TUNNEL:
         /* not implemented */
         break;
 
@@ -1259,40 +1274,48 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
     }
 }
 
+#define DPIF_NETDEV_CLASS_FUNCTIONS                    \
+    dpif_netdev_enumerate,                             \
+    dpif_netdev_open,                                  \
+    dpif_netdev_close,                                 \
+    dpif_netdev_destroy,                               \
+    dpif_netdev_run,                                   \
+    dpif_netdev_wait,                                  \
+    dpif_netdev_get_stats,                             \
+    dpif_netdev_port_add,                              \
+    dpif_netdev_port_del,                              \
+    dpif_netdev_port_query_by_number,                  \
+    dpif_netdev_port_query_by_name,                    \
+    dpif_netdev_get_max_ports,                         \
+    NULL,                       /* port_get_pid */     \
+    dpif_netdev_port_dump_start,                       \
+    dpif_netdev_port_dump_next,                                \
+    dpif_netdev_port_dump_done,                                \
+    dpif_netdev_port_poll,                             \
+    dpif_netdev_port_poll_wait,                                \
+    dpif_netdev_flow_get,                              \
+    dpif_netdev_flow_put,                              \
+    dpif_netdev_flow_del,                              \
+    dpif_netdev_flow_flush,                            \
+    dpif_netdev_flow_dump_start,                       \
+    dpif_netdev_flow_dump_next,                                \
+    dpif_netdev_flow_dump_done,                                \
+    dpif_netdev_execute,                               \
+    NULL,                       /* operate */          \
+    dpif_netdev_recv_set,                              \
+    dpif_netdev_queue_to_priority,                     \
+    dpif_netdev_recv,                                  \
+    dpif_netdev_recv_wait,                             \
+    dpif_netdev_recv_purge,                            \
+
 const struct dpif_class dpif_netdev_class = {
     "netdev",
-    dpif_netdev_enumerate,
-    dpif_netdev_open,
-    dpif_netdev_close,
-    dpif_netdev_destroy,
-    dpif_netdev_run,
-    dpif_netdev_wait,
-    dpif_netdev_get_stats,
-    dpif_netdev_port_add,
-    dpif_netdev_port_del,
-    dpif_netdev_port_query_by_number,
-    dpif_netdev_port_query_by_name,
-    dpif_netdev_get_max_ports,
-    NULL,                       /* port_get_pid */
-    dpif_netdev_port_dump_start,
-    dpif_netdev_port_dump_next,
-    dpif_netdev_port_dump_done,
-    dpif_netdev_port_poll,
-    dpif_netdev_port_poll_wait,
-    dpif_netdev_flow_get,
-    dpif_netdev_flow_put,
-    dpif_netdev_flow_del,
-    dpif_netdev_flow_flush,
-    dpif_netdev_flow_dump_start,
-    dpif_netdev_flow_dump_next,
-    dpif_netdev_flow_dump_done,
-    dpif_netdev_execute,
-    NULL,                       /* operate */
-    dpif_netdev_recv_set,
-    dpif_netdev_queue_to_priority,
-    dpif_netdev_recv,
-    dpif_netdev_recv_wait,
-    dpif_netdev_recv_purge,
+    DPIF_NETDEV_CLASS_FUNCTIONS
+};
+
+const struct dpif_class dpif_planetlab_class = {
+    "planetlab",
+    DPIF_NETDEV_CLASS_FUNCTIONS
 };
 
 static void
@@ -1325,3 +1348,4 @@ dpif_dummy_register(bool override)
 
     dpif_dummy_register__("dummy");
 }
+