datapath: Set the correct bits for OFPAT_SET_NW_TOS action.
[sliver-openvswitch.git] / lib / dpif-netdev.c
index 4ff1a42..d576c73 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;
@@ -377,9 +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 {
-        char *tapname = xasprintf("tap:%s", devname);
-        error = netdev_open(tapname, NETDEV_ETH_TYPE_ANY, &netdev);
-        free(tapname);
+        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;
@@ -424,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
@@ -472,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);
@@ -484,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;
@@ -658,7 +664,7 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
 {
     struct dp_netdev_flow *flow;
 
-    assert(key->reserved == 0);
+    assert(!key->reserved[0] && !key->reserved[1] && !key->reserved[2]);
     HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
                              flow_hash(key, 0), &dp->flow_table) {
         if (flow_equal(&flow->key, key)) {
@@ -669,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) {
@@ -687,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;
     }
@@ -700,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;
 }
@@ -750,6 +762,7 @@ dpif_netdev_validate_actions(const union odp_action *actions, int n_actions,
         case ODPAT_SET_DL_DST:
         case ODPAT_SET_NW_SRC:
         case ODPAT_SET_NW_DST:
+        case ODPAT_SET_NW_TOS:
         case ODPAT_SET_TP_SRC:
         case ODPAT_SET_TP_DST:
             *mutates = true;
@@ -794,7 +807,7 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
 
     flow = xcalloc(1, sizeof *flow);
     flow->key = odp_flow->key;
-    flow->key.reserved = 0;
+    memset(flow->key.reserved, 0, sizeof flow->key.reserved);
 
     error = set_flow_actions(flow, odp_flow);
     if (error) {
@@ -829,7 +842,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 +869,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 +889,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 +905,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 +1003,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;
 
@@ -1159,11 +1172,28 @@ dp_netdev_set_nw_addr(struct ofpbuf *packet, flow_t *key,
     }
 }
 
+static void
+dp_netdev_set_nw_tos(struct ofpbuf *packet, flow_t *key,
+                     const struct odp_action_nw_tos *a)
+{
+    if (key->dl_type == htons(ETH_TYPE_IP)) {
+        struct ip_header *nh = packet->l3;
+        uint8_t *field = &nh->ip_tos;
+
+        /* Set the DSCP bits and preserve the ECN bits. */
+        uint8_t new = (a->nw_tos & IP_DSCP_MASK) | (nh->ip_tos & IP_ECN_MASK);
+
+        nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
+                htons((uint16_t)a->nw_tos));
+        *field = new;
+    }
+}
+
 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;
@@ -1282,6 +1312,10 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
                        dp_netdev_set_nw_addr(packet, key, &a->nw_addr);
                        break;
 
+               case ODPAT_SET_NW_TOS:
+                       dp_netdev_set_nw_tos(packet, key, &a->nw_tos);
+                       break;
+
                case ODPAT_SET_TP_SRC:
                case ODPAT_SET_TP_DST:
                        dp_netdev_set_tp_port(packet, key, &a->tp_port);