Merge branch 'master' into next
[sliver-openvswitch.git] / lib / dpif-netdev.c
index 4ff1a42..8abf1f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #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;
@@ -200,7 +196,7 @@ create_dpif_netdev(struct dp_netdev *dp)
 
     dp->open_cnt++;
 
-    dpname = xasprintf("netdev:dp%d", dp->dp_idx);
+    dpname = xasprintf("dp%d", dp->dp_idx);
     dpif = xmalloc(sizeof *dpif);
     dpif_init(&dpif->dpif, &dpif_netdev_class, dpname, dp->dp_idx, dp->dp_idx);
     dpif->dp = dp;
@@ -223,7 +219,7 @@ create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp)
     }
 
     /* Create datapath. */
-    dp_netdevs[dp_idx] = dp = xcalloc(1, sizeof *dp);
+    dp_netdevs[dp_idx] = dp = xzalloc(sizeof *dp);
     list_push_back(&dp_netdev_list, &dp->node);
     dp->dp_idx = dp_idx;
     dp->open_cnt = 0;
@@ -241,7 +237,7 @@ create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp)
     error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL);
     if (error) {
         dp_netdev_free(dp);
-        return error;
+        return ENODEV;
     }
 
     *dpifp = create_dpif_netdev(dp);
@@ -249,20 +245,20 @@ create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp)
 }
 
 static int
-dpif_netdev_open(const char *name UNUSED, char *suffix, bool create,
+dpif_netdev_open(const char *name, const char *type UNUSED, bool create,
                  struct dpif **dpifp)
 {
     if (create) {
-        if (find_dp_netdev(suffix)) {
+        if (find_dp_netdev(name)) {
             return EEXIST;
         } else {
-            int dp_idx = name_to_dp_idx(suffix);
+            int dp_idx = name_to_dp_idx(name);
             if (dp_idx >= 0) {
-                return create_dp_netdev(suffix, dp_idx, dpifp);
+                return create_dp_netdev(name, dp_idx, dpifp);
             } else {
                 /* Scan for unused dp_idx number. */
                 for (dp_idx = 0; dp_idx < N_DP_NETDEVS; dp_idx++) {
-                    int error = create_dp_netdev(suffix, dp_idx, dpifp);
+                    int error = create_dp_netdev(name, dp_idx, dpifp);
                     if (error != EBUSY) {
                         return error;
                     }
@@ -273,7 +269,7 @@ dpif_netdev_open(const char *name UNUSED, char *suffix, bool create,
             }
         }
     } else {
-        struct dp_netdev *dp = find_dp_netdev(suffix);
+        struct dp_netdev *dp = find_dp_netdev(name);
         if (dp) {
             *dpifp = create_dpif_netdev(dp);
             return 0;
@@ -367,6 +363,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
 {
     bool internal = (flags & ODP_PORT_INTERNAL) != 0;
     struct dp_netdev_port *port;
+    struct netdev_options netdev_options;
     struct netdev *netdev;
     int mtu;
     int error;
@@ -374,13 +371,17 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
     /* XXX reject devices already in some dp_netdev. */
 
     /* Open and validate network device. */
-    if (!internal) {
-        error = netdev_open(devname, NETDEV_ETH_TYPE_ANY, &netdev);
+    memset(&netdev_options, 0, sizeof netdev_options);
+    netdev_options.name = devname;
+    netdev_options.ethertype = NETDEV_ETH_TYPE_ANY;
+    netdev_options.may_create = true;
+    if (internal) {
+        netdev_options.type = "tap";
     } else {
-        char *tapname = xasprintf("tap:%s", devname);
-        error = netdev_open(tapname, NETDEV_ETH_TYPE_ANY, &netdev);
-        free(tapname);
+        netdev_options.may_open = true;
     }
+
+    error = netdev_open(&netdev_options, &netdev);
     if (error) {
         return error;
     }
@@ -424,7 +425,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
@@ -472,6 +473,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);
@@ -484,7 +486,10 @@ 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);
+
+    free(name);
     free(port);
 
     return 0;
@@ -669,7 +674,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) {
@@ -687,6 +692,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;
     }
@@ -700,7 +710,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;
 }
@@ -792,7 +803,7 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
     struct dp_netdev_flow *flow;
     int error;
 
-    flow = xcalloc(1, sizeof *flow);
+    flow = xzalloc(sizeof *flow);
     flow->key = odp_flow->key;
     flow->key.reserved = 0;
 
@@ -829,7 +840,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;
@@ -856,7 +867,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 {
@@ -876,7 +887,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);
 }
@@ -892,7 +903,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;
     }
 
@@ -990,7 +1001,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;
 
@@ -1163,7 +1174,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;
@@ -1292,7 +1303,6 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
 }
 
 const struct dpif_class dpif_netdev_class = {
-    "netdev",
     "netdev",
     dp_netdev_run,
     dp_netdev_wait,
@@ -1321,6 +1331,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,
 };