Initial implementation of sFlow.
[sliver-openvswitch.git] / lib / dpif-netdev.c
index cae6d23..720e8cb 100644 (file)
 #include <fcntl.h>
 #include <inttypes.h>
 #include <net/if.h>
-#include <linux/rtnetlink.h>
-#include <linux/ethtool.h>
-#include <linux/sockios.h>
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
-#include <sys/sysmacros.h>
 #include <unistd.h>
 
 #include "csum.h"
@@ -160,7 +156,7 @@ get_dp_netdev(const struct dpif *dpif)
 static int
 name_to_dp_idx(const char *name)
 {
-    if (!strncmp(name, "dp", 2) && isdigit(name[2])) {
+    if (!strncmp(name, "dp", 2) && isdigit((unsigned char)name[2])) {
         int dp_idx = atoi(name + 2);
         if (dp_idx >= 0 && dp_idx < N_DP_NETDEVS) {
             return dp_idx;
@@ -377,7 +373,13 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
     if (!internal) {
         error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
     } else {
-        error = netdev_open_tap(devname, &netdev);
+        error = netdev_create(devname, "tap", NULL);
+        if (!error) {
+            error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
+            if (error) {
+                netdev_destroy(devname);
+            }
+        }
     }
     if (error) {
         return error;
@@ -396,7 +398,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
     port->netdev = netdev;
     port->internal = internal;
 
-    mtu = netdev_get_mtu(netdev);
+    netdev_get_mtu(netdev, &mtu);
     if (mtu > max_mtu) {
         max_mtu = mtu;
     }
@@ -422,7 +424,7 @@ dpif_netdev_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
             return do_add_port(dp, devname, flags, port_no);
         }
     }
-    return EXFULL;
+    return EFBIG;
 }
 
 static int
@@ -470,6 +472,7 @@ static int
 do_del_port(struct dp_netdev *dp, uint16_t port_no)
 {
     struct dp_netdev_port *port;
+    char *name;
     int error;
 
     error = get_port_by_number(dp, port_no, &port);
@@ -482,7 +485,12 @@ do_del_port(struct dp_netdev *dp, uint16_t port_no)
     dp->n_ports--;
     dp->serial++;
 
+    name = xstrdup(netdev_get_name(port->netdev));
     netdev_close(port->netdev);
+    if (port->internal) {
+        netdev_destroy(name);
+    }
+    free(name);
     free(port);
 
     return 0;
@@ -667,7 +675,7 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
 }
 
 static void
-answer_flow_query(const struct dp_netdev_flow *flow,
+answer_flow_query(struct dp_netdev_flow *flow, uint32_t query_flags,
                   struct odp_flow *odp_flow)
 {
     if (flow) {
@@ -685,6 +693,11 @@ answer_flow_query(const struct dp_netdev_flow *flow,
                    n * sizeof *odp_flow->actions);
             odp_flow->n_actions = flow->n_actions;
         }
+
+        if (query_flags & ODPFF_ZERO_TCP_FLAGS) {
+            flow->tcp_ctl = 0;
+        }
+
     } else {
         odp_flow->stats.error = ENOENT;
     }
@@ -698,7 +711,8 @@ dpif_netdev_flow_get(const struct dpif *dpif, struct odp_flow flows[], int n)
 
     for (i = 0; i < n; i++) {
         struct odp_flow *odp_flow = &flows[i];
-        answer_flow_query(dp_netdev_lookup_flow(dp, &odp_flow->key), odp_flow);
+        answer_flow_query(dp_netdev_lookup_flow(dp, &odp_flow->key),
+                          odp_flow->flags, odp_flow);
     }
     return 0;
 }
@@ -827,7 +841,7 @@ dpif_netdev_flow_put(struct dpif *dpif, struct odp_flow_put *put)
             if (hmap_count(&dp->flow_table) < MAX_FLOWS) {
                 return add_flow(dpif, &put->flow);
             } else {
-                return EXFULL;
+                return EFBIG;
             }
         } else {
             return ENOENT;
@@ -854,7 +868,7 @@ dpif_netdev_flow_del(struct dpif *dpif, struct odp_flow *odp_flow)
 
     flow = dp_netdev_lookup_flow(dp, &odp_flow->key);
     if (flow) {
-        answer_flow_query(flow, odp_flow);
+        answer_flow_query(flow, 0, odp_flow);
         dp_netdev_free_flow(dp, flow);
         return 0;
     } else {
@@ -874,7 +888,7 @@ dpif_netdev_flow_list(const struct dpif *dpif, struct odp_flow flows[], int n)
         if (i >= n) {
             break;
         }
-        answer_flow_query(flow, &flows[i++]);
+        answer_flow_query(flow, 0, &flows[i++]);
     }
     return hmap_count(&dp->flow_table);
 }
@@ -890,7 +904,7 @@ dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
     flow_t flow;
     int error;
 
-    if (packet->size < ETH_HLEN || packet->size > UINT16_MAX) {
+    if (packet->size < ETH_HEADER_LEN || packet->size > UINT16_MAX) {
         return EINVAL;
     }
 
@@ -988,7 +1002,7 @@ dp_netdev_flow_used(struct dp_netdev_flow *flow, const flow_t *key,
     time_timeval(&flow->used);
     flow->packet_count++;
     flow->byte_count += packet->size;
-    if (key->dl_type == htons(ETH_P_IP)) {
+    if (key->dl_type == htons(ETH_TYPE_IP)) {
         struct ip_header *nh = packet->l3;
         flow->ip_tos = nh->ip_tos;
 
@@ -1161,7 +1175,7 @@ static void
 dp_netdev_set_tp_port(struct ofpbuf *packet, flow_t *key,
                       const struct odp_action_tp_port *a)
 {
-       if (key->dl_type == htons(ETH_P_IP)) {
+       if (key->dl_type == htons(ETH_TYPE_IP)) {
         uint16_t *field;
         if (key->nw_proto == IPPROTO_TCP) {
             struct tcp_header *th = packet->l4;
@@ -1319,6 +1333,8 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_execute,
     dpif_netdev_recv_get_mask,
     dpif_netdev_recv_set_mask,
+    NULL,                       /* get_sflow_probability */
+    NULL,                       /* set_sflow_probability */
     dpif_netdev_recv,
     dpif_netdev_recv_wait,
 };