Merge branch 'mainstream'
[sliver-openvswitch.git] / lib / dpif-netdev.c
index d1097e9..42af2ff 100644 (file)
@@ -43,6 +43,7 @@
 #include "list.h"
 #include "meta-flow.h"
 #include "netdev.h"
+#include "netdev-dpdk.h"
 #include "netdev-vport.h"
 #include "netlink.h"
 #include "odp-execute.h"
@@ -67,6 +68,9 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev);
 #define NETDEV_RULE_PRIORITY 0x8000
 
 #define NR_THREADS 1
+/* Use per thread recirc_depth to prevent recirculation loop. */
+#define MAX_RECIRC_DEPTH 5
+DEFINE_STATIC_PER_THREAD_DATA(uint32_t, recirc_depth, 0)
 
 /* Configuration parameters. */
 enum { MAX_FLOWS = 65536 };     /* Maximum number of flows in flow table. */
@@ -394,10 +398,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";
 }
@@ -426,7 +437,8 @@ choose_port(struct dp_netdev *dp, const char *name)
 {
     uint32_t 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;
 
@@ -1135,8 +1147,6 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
 
             return EINVAL;
         }
-        /* Force unwildcard the in_port. */
-        mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
     } else {
         enum mf_field_id id;
         /* No mask key, unwildcard everything except fields whose
@@ -1155,6 +1165,14 @@ dpif_netdev_mask_from_nlattrs(const struct nlattr *key, uint32_t key_len,
         }
     }
 
+    /* Force unwildcard the in_port.
+     *
+     * We need to do this even in the case where we unwildcard "everything"
+     * above because "everything" only includes the 16-bit OpenFlow port number
+     * mask->in_port.ofp_port, which only covers half of the 32-bit datapath
+     * port number mask->in_port.odp_port. */
+    mask->in_port.odp_port = u32_to_odp(UINT32_MAX);
+
     return 0;
 }
 
@@ -1461,8 +1479,8 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *iter_, void *state_,
         odp_flow_key_from_flow(&buf, &netdev_flow->flow,
                                netdev_flow->flow.in_port.odp_port);
 
-        *key = buf.data;
-        *key_len = buf.size;
+        *key = ofpbuf_data(&buf);
+        *key_len = ofpbuf_size(&buf);
     }
 
     if (key && mask) {
@@ -1475,8 +1493,8 @@ dpif_netdev_flow_dump_next(const struct dpif *dpif, void *iter_, void *state_,
                                odp_to_u32(wc.masks.in_port.odp_port),
                                SIZE_MAX);
 
-        *mask = buf.data;
-        *mask_len = buf.size;
+        *mask = ofpbuf_data(&buf);
+        *mask_len = ofpbuf_size(&buf);
     }
 
     if (actions || stats) {
@@ -1514,8 +1532,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
     struct pkt_metadata *md = &execute->md;
     struct flow key;
 
-    if (execute->packet->size < ETH_HEADER_LEN ||
-        execute->packet->size > UINT16_MAX) {
+    if (ofpbuf_size(execute->packet) < ETH_HEADER_LEN ||
+        ofpbuf_size(execute->packet) > UINT16_MAX) {
         return EINVAL;
     }
 
@@ -1733,7 +1751,7 @@ dp_netdev_actions_free(struct dp_netdev_actions *actions)
 }
 \f
 
-inline static void
+static void
 dp_netdev_process_rxq_port(struct dp_netdev *dp,
                           struct dp_netdev_port *port,
                           struct netdev_rxq *rxq)
@@ -1864,6 +1882,7 @@ pmd_thread_main(void *f_)
     poll_cnt = 0;
     poll_list = NULL;
 
+    pmd_thread_setaffinity_cpu(f->id);
 reload:
     poll_cnt = pmd_load_queues(f, &poll_list, poll_cnt);
     atomic_read(&f->change_seq, &port_seq);
@@ -1964,7 +1983,7 @@ dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow,
     ovs_mutex_lock(&bucket->mutex);
     bucket->used = MAX(now, bucket->used);
     bucket->packet_count++;
-    bucket->byte_count += packet->size;
+    bucket->byte_count += ofpbuf_size(packet);
     bucket->tcp_flags |= tcp_flags;
     ovs_mutex_unlock(&bucket->mutex);
 }
@@ -1989,13 +2008,14 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type)
 }
 
 static void
-dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
-                     struct pkt_metadata *md)
+dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
+                struct pkt_metadata *md)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
 {
     struct dp_netdev_flow *netdev_flow;
     struct flow key;
 
-    if (packet->size < ETH_HEADER_LEN) {
+    if (ofpbuf_size(packet) < ETH_HEADER_LEN) {
         ofpbuf_delete(packet);
         return;
     }
@@ -2019,6 +2039,17 @@ dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
     }
 }
 
+static void
+dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
+                     struct pkt_metadata *md)
+    OVS_REQ_RDLOCK(dp->port_rwlock)
+{
+    uint32_t *recirc_depth = recirc_depth_get();
+
+    *recirc_depth = 0;
+    dp_netdev_input(dp, packet, md);
+}
+
 static int
 dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                            int queue_no, int type, const struct flow *flow,
@@ -2043,13 +2074,13 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
         if (userdata) {
             buf_size += NLA_ALIGN(userdata->nla_len);
         }
-        buf_size += packet->size;
+        buf_size += ofpbuf_size(packet);
         ofpbuf_init(buf, buf_size);
 
         /* Put ODP flow. */
         odp_flow_key_from_flow(buf, flow, flow->in_port.odp_port);
-        upcall->key = buf->data;
-        upcall->key_len = buf->size;
+        upcall->key = ofpbuf_data(buf);
+        upcall->key_len = ofpbuf_size(buf);
 
         /* Put userdata. */
         if (userdata) {
@@ -2057,8 +2088,9 @@ dp_netdev_output_userspace(struct dp_netdev *dp, struct ofpbuf *packet,
                                           NLA_ALIGN(userdata->nla_len));
         }
 
-        upcall->packet.data = ofpbuf_put(buf, packet->data, packet->size);
-        upcall->packet.size = packet->size;
+        ofpbuf_set_data(&upcall->packet,
+                        ofpbuf_put(buf, ofpbuf_data(packet), ofpbuf_size(packet)));
+        ofpbuf_set_size(&upcall->packet, ofpbuf_size(packet));
 
         seq_change(q->seq);
 
@@ -2080,13 +2112,14 @@ struct dp_netdev_execute_aux {
 
 static void
 dp_execute_cb(void *aux_, struct ofpbuf *packet,
-              const struct pkt_metadata *md OVS_UNUSED,
+              struct pkt_metadata *md,
               const struct nlattr *a, bool may_steal)
     OVS_NO_THREAD_SAFETY_ANALYSIS
 {
     struct dp_netdev_execute_aux *aux = aux_;
     int type = nl_attr_type(a);
     struct dp_netdev_port *p;
+    uint32_t *depth = recirc_depth_get();
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
@@ -2112,6 +2145,37 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
         }
         break;
     }
+
+    case OVS_ACTION_ATTR_RECIRC:
+        if (*depth < MAX_RECIRC_DEPTH) {
+            struct pkt_metadata recirc_md = *md;
+            struct ofpbuf *recirc_packet;
+            const struct ovs_action_recirc *act;
+
+            recirc_packet = may_steal ? packet : ofpbuf_clone(packet);
+
+            act = nl_attr_get(a);
+            recirc_md.recirc_id = act->recirc_id;
+            recirc_md.dp_hash = 0;
+
+            if (act->hash_alg == OVS_RECIRC_HASH_ALG_L4) {
+                recirc_md.dp_hash = flow_hash_symmetric_l4(aux->key,
+                                                           act->hash_bias);
+                if (!recirc_md.dp_hash) {
+                    recirc_md.dp_hash = 1;  /* 0 is not valid */
+                }
+            }
+
+            (*depth)++;
+            dp_netdev_input(aux->dp, recirc_packet, &recirc_md);
+            (*depth)--;
+
+            break;
+        } else {
+            VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
+        }
+        break;
+
     case OVS_ACTION_ATTR_PUSH_VLAN:
     case OVS_ACTION_ATTR_POP_VLAN:
     case OVS_ACTION_ATTR_PUSH_MPLS:
@@ -2122,7 +2186,6 @@ dp_execute_cb(void *aux_, struct ofpbuf *packet,
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
-
 }
 
 static void
@@ -2137,44 +2200,52 @@ dp_netdev_execute_actions(struct dp_netdev *dp, const struct flow *key,
                         actions, actions_len, dp_execute_cb);
 }
 
+#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,                    \
+    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_state_init,   \
+    dpif_netdev_flow_dump_start,                       \
+    dpif_netdev_flow_dump_next,                                \
+    NULL,                                   \
+    dpif_netdev_flow_dump_done,                                \
+    dpif_netdev_flow_dump_state_uninit,     \
+    dpif_netdev_execute,                               \
+    NULL,                       /* operate */          \
+    dpif_netdev_recv_set,                              \
+    dpif_netdev_handlers_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,
-    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_state_init,
-    dpif_netdev_flow_dump_start,
-    dpif_netdev_flow_dump_next,
-    NULL,
-    dpif_netdev_flow_dump_done,
-    dpif_netdev_flow_dump_state_uninit,
-    dpif_netdev_execute,
-    NULL,                       /* operate */
-    dpif_netdev_recv_set,
-    dpif_netdev_handlers_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
@@ -2255,3 +2326,4 @@ dpif_dummy_register(bool override)
                              "DP PORT NEW-NUMBER",
                              3, 3, dpif_dummy_change_port_number, NULL);
 }
+