Merge branch 'master' of git://openvswitch.org/openvswitch
[sliver-openvswitch.git] / lib / dpif-netdev.c
index 038dfdc..185fe19 100644 (file)
@@ -151,7 +151,7 @@ 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 *,
                                     int queue_no, const struct flow *,
-                                    uint64_t arg);
+                                    const struct nlattr *userdata);
 static void dp_netdev_execute_actions(struct dp_netdev *,
                                       struct ofpbuf *, struct flow *,
                                       const struct nlattr *actions,
@@ -187,10 +187,17 @@ dpif_netdev_class_is_dummy(const struct dpif_class *class)
     return class != &dpif_netdev_class;
 }
 
+static bool
+dpif_netdev_class_is_planetlab(const struct dpif_class *class)
+{
+    return class == &dpif_planetlab_class;
+}
+
 static const char *
 dpif_netdev_port_open_type(const struct dpif_class *class, const char *type)
 {
     return strcmp(type, "internal") ? type
+                  : dpif_netdev_class_is_planetlab(class) ? "pltap"
                   : dpif_netdev_class_is_dummy(class) ? "dummy"
                   : "tap";
 }
@@ -216,7 +223,8 @@ choose_port(struct dp_netdev *dp, const char *name)
 {
     int port_no;
 
-    if (dp->class != &dpif_netdev_class) {
+    if (dp->class != &dpif_netdev_class && 
+        dp->class != &dpif_planetlab_class) {
         const char *p;
         int start_no = 0;
 
@@ -1043,7 +1051,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
         dp->n_hit++;
     } else {
         dp->n_missed++;
-        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, 0);
+        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, NULL);
     }
 }
 
@@ -1108,37 +1116,51 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
 
 static int
 dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
-                         int queue_no, const struct flow *flow, uint64_t arg)
+                           int queue_no, const struct flow *flow,
+                           const struct nlattr *userdata)
 {
     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;
-
-    if (q->head - q->tail >= MAX_QUEUE_LEN) {
-        dp->n_lost++;
-        return ENOBUFS;
-    }
+    if (q->head - q->tail < MAX_QUEUE_LEN) {
+        struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
+        struct dpif_upcall *upcall = &u->upcall;
+        struct ofpbuf *buf = &u->buf;
+        size_t buf_size;
+
+        upcall->type = queue_no;
+
+        /* Allocate buffer big enough for everything. */
+        buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
+        if (userdata) {
+            buf_size += NLA_ALIGN(userdata->nla_len);
+        }
+        ofpbuf_init(buf, buf_size);
 
-    u = &q->upcalls[q->head++ & QUEUE_MASK];
+        /* Put ODP flow. */
+        odp_flow_key_from_flow(buf, flow, flow->in_port);
+        upcall->key = buf->data;
+        upcall->key_len = buf->size;
 
-    buf = &u->buf;
-    ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
-    odp_flow_key_from_flow(buf, flow, flow->in_port);
-    key_len = buf->size;
-    ofpbuf_pull(buf, key_len);
-    ofpbuf_reserve(buf, 2);
-    ofpbuf_put(buf, packet->data, packet->size);
+        /* Put userdata. */
+        if (userdata) {
+            upcall->userdata = ofpbuf_put(buf, userdata,
+                                          NLA_ALIGN(userdata->nla_len));
+        }
 
-    upcall = &u->upcall;
-    upcall->type = queue_no;
-    upcall->packet = buf;
-    upcall->key = buf->base;
-    upcall->key_len = key_len;
-    upcall->userdata = arg;
+        /* 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;
 
-    return 0;
+        return 0;
+    } else {
+        dp->n_lost++;
+        return ENOBUFS;
+    }
 }
 
 static void
@@ -1180,11 +1202,9 @@ dp_netdev_action_userspace(struct dp_netdev *dp,
                           struct ofpbuf *packet, struct flow *key,
                           const struct nlattr *a)
 {
-    const struct nlattr *userdata_attr;
-    uint64_t userdata;
+    const struct nlattr *userdata;
 
-    userdata_attr = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
-    userdata = userdata_attr ? nl_attr_get_u64(userdata_attr) : 0;
+    userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
     dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata);
 }
 
@@ -1198,7 +1218,6 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
     const struct ovs_key_udp *udp_key;
 
     switch (type) {
-    case OVS_KEY_ATTR_TUN_ID:
     case OVS_KEY_ATTR_PRIORITY:
     case OVS_KEY_ATTR_SKB_MARK:
     case OVS_KEY_ATTR_TUNNEL:
@@ -1233,6 +1252,10 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
         packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst);
         break;
 
+     case OVS_KEY_ATTR_MPLS:
+         set_mpls_lse(packet, nl_attr_get_be32(a));
+         break;
+
      case OVS_KEY_ATTR_UNSPEC:
      case OVS_KEY_ATTR_ENCAP:
      case OVS_KEY_ATTR_ETHERTYPE:
@@ -1279,6 +1302,16 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
             eth_pop_vlan(packet);
             break;
 
+        case OVS_ACTION_ATTR_PUSH_MPLS: {
+            const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+            push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse);
+            break;
+         }
+
+        case OVS_ACTION_ATTR_POP_MPLS:
+            pop_mpls(packet, nl_attr_get_be16(a));
+            break;
+
         case OVS_ACTION_ATTR_SET:
             execute_set_action(packet, nl_attr_get(a));
             break;
@@ -1294,41 +1327,49 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
     }
 }
 
+#define DPIF_NETDEV_CLASS_FUNCTIONS                    \
+    dpif_netdev_enumerate,                             \
+    dpif_netdev_port_open_type,                                \
+    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_port_open_type,
-    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
@@ -1361,3 +1402,4 @@ dpif_dummy_register(bool override)
 
     dpif_dummy_register__("dummy");
 }
+