netdev: Map to OpenFlow port for flow lookup
[sliver-openvswitch.git] / lib / dpif-netdev.c
index d73050a..7fa2720 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -113,7 +113,7 @@ struct dp_netdev_flow {
     long long int used;         /* Last used time, in monotonic msecs. */
     long long int packet_count; /* Number of packets matched. */
     long long int byte_count;   /* Number of bytes matched. */
-    ovs_be16 tcp_ctl;           /* Bitwise-OR of seen tcp_ctl values. */
+    uint8_t tcp_flags;          /* Bitwise-OR of seen tcp_flags values. */
 
     /* Actions. */
     struct nlattr *actions;
@@ -165,6 +165,17 @@ get_dp_netdev(const struct dpif *dpif)
     return dpif_netdev_cast(dpif)->dp;
 }
 
+static int
+dpif_netdev_enumerate(struct sset *all_dps)
+{
+    struct shash_node *node;
+
+    SHASH_FOR_EACH(node, &dp_netdevs) {
+        sset_add(all_dps, node->name);
+    }
+    return 0;
+}
+
 static struct dpif *
 create_dpif_netdev(struct dp_netdev *dp)
 {
@@ -396,7 +407,16 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
     struct dp_netdev *dp = get_dp_netdev(dpif);
     int port_no;
 
-    port_no = choose_port(dpif, netdev);
+    if (*port_nop != UINT16_MAX) {
+        if (*port_nop >= MAX_PORTS) {
+            return EFBIG;
+        } else if (dp->ports[*port_nop]) {
+            return EBUSY;
+        }
+        port_no = *port_nop;
+    } else {
+        port_no = choose_port(dpif, netdev);
+    }
     if (port_no >= 0) {
         *port_nop = port_no;
         return do_add_port(dp, netdev_get_name(netdev),
@@ -627,7 +647,7 @@ get_dpif_flow_stats(struct dp_netdev_flow *flow, struct dpif_flow_stats *stats)
     stats->n_packets = flow->packet_count;
     stats->n_bytes = flow->byte_count;
     stats->used = flow->used;
-    stats->tcp_flags = TCP_FLAGS(flow->tcp_ctl);
+    stats->tcp_flags = flow->tcp_flags;
 }
 
 static int
@@ -702,10 +722,9 @@ set_flow_actions(struct dp_netdev_flow *flow,
 }
 
 static int
-add_flow(struct dpif *dpif, const struct flow *key,
-         const struct nlattr *actions, size_t actions_len)
+dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *key,
+                   const struct nlattr *actions, size_t actions_len)
 {
-    struct dp_netdev *dp = get_dp_netdev(dpif);
     struct dp_netdev_flow *flow;
     int error;
 
@@ -728,7 +747,7 @@ clear_stats(struct dp_netdev_flow *flow)
     flow->used = 0;
     flow->packet_count = 0;
     flow->byte_count = 0;
-    flow->tcp_ctl = 0;
+    flow->tcp_flags = 0;
 }
 
 static int
@@ -751,7 +770,8 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
                 if (put->stats) {
                     memset(put->stats, 0, sizeof *put->stats);
                 }
-                return add_flow(dpif, &key, put->actions, put->actions_len);
+                return dp_netdev_flow_add(dp, &key, put->actions,
+                                          put->actions_len);
             } else {
                 return EFBIG;
             }
@@ -777,24 +797,22 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
 }
 
 static int
-dpif_netdev_flow_del(struct dpif *dpif,
-                     const struct nlattr *nl_key, size_t nl_key_len,
-                     struct dpif_flow_stats *stats)
+dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
 {
     struct dp_netdev *dp = get_dp_netdev(dpif);
     struct dp_netdev_flow *flow;
     struct flow key;
     int error;
 
-    error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key);
+    error = dpif_netdev_flow_from_nlattrs(del->key, del->key_len, &key);
     if (error) {
         return error;
     }
 
     flow = dp_netdev_lookup_flow(dp, &key);
     if (flow) {
-        if (stats) {
-            get_dpif_flow_stats(flow, stats);
+        if (del->stats) {
+            get_dpif_flow_stats(flow, del->stats);
         }
         dp_netdev_free_flow(dp, flow);
         return 0;
@@ -937,7 +955,8 @@ find_nonempty_queue(struct dpif *dpif)
 }
 
 static int
-dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall)
+dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
+                 struct ofpbuf *buf)
 {
     struct dp_netdev_queue *q = find_nonempty_queue(dpif);
     if (q) {
@@ -945,6 +964,9 @@ dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall)
         *upcall = *u;
         free(u);
 
+        ofpbuf_uninit(buf);
+        *buf = *upcall->packet;
+
         return 0;
     } else {
         return EAGAIN;
@@ -976,11 +998,7 @@ dp_netdev_flow_used(struct dp_netdev_flow *flow, struct flow *key,
     flow->used = time_msec();
     flow->packet_count++;
     flow->byte_count += packet->size;
-    if (key->dl_type == htons(ETH_TYPE_IP) &&
-        key->nw_proto == IPPROTO_TCP && packet->l7) {
-        struct tcp_header *th = packet->l4;
-        flow->tcp_ctl |= th->tcp_ctl;
-    }
+    flow->tcp_flags |= packet_get_tcp_flags(packet, key);
 }
 
 static void
@@ -993,7 +1011,7 @@ 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, port->port_no, &key);
+    flow_extract(packet, 0, 0, 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);
@@ -1243,7 +1261,7 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
 
 const struct dpif_class dpif_netdev_class = {
     "netdev",
-    NULL,                       /* enumerate */
+    dpif_netdev_enumerate,
     dpif_netdev_open,
     dpif_netdev_close,
     dpif_netdev_destroy,