ofproto: Match VLAN PCP and rewrite ToS bits (OpenFlow 0.9)
authorJustin Pettit <jpettit@nicira.com>
Wed, 11 Nov 2009 22:59:49 +0000 (14:59 -0800)
committerJustin Pettit <jpettit@nicira.com>
Sat, 23 Jan 2010 02:08:03 +0000 (18:08 -0800)
Starting in OpenFlow 0.9, it is possible to match on the VLAN PCP
(priority) field and rewrite the IP ToS/DSCP bits.  This check-in
provides that support and bumps the wire protocol number to 0x98.

NOTE: The wire changes come together over the set of OpenFlow 0.9 commits,
so OVS will not be OpenFlow-compatible with any official release between
this commit and the one that completes the set.

17 files changed:
datapath/actions.c
datapath/datapath.c
datapath/flow.c
include/openflow/openflow.h
include/openvswitch/datapath-protocol.h
lib/classifier.c
lib/classifier.h
lib/dpif-netdev.c
lib/flow.c
lib/odp-util.c
lib/ofp-print.c
lib/vconn.c
ofproto/ofproto.c
tests/flowgen.pl
tests/test-classifier.c
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c

index cadab05..3eea532 100644 (file)
@@ -252,6 +252,30 @@ static struct sk_buff *set_nw_addr(struct sk_buff *skb,
        return skb;
 }
 
+static struct sk_buff *set_nw_tos(struct sk_buff *skb,
+                                  struct odp_flow_key *key,
+                                  const struct odp_action_nw_tos *a,
+                                  gfp_t gfp)
+{
+       if (key->dl_type != htons(ETH_P_IP))
+               return skb;
+
+       skb = make_writable(skb, 0, gfp);
+       if (skb) {
+               struct iphdr *nh = ip_hdr(skb);
+               u8 *f = &nh->tos;
+               u8 old = *f;
+
+               /* We only set the lower 6 bits. */
+               u8 new = (a->nw_tos & 0x3f) | (nh->tos & 0xc0);
+
+               update_csum(&nh->check, skb, htons((uint16_t)old),
+                               htons((uint16_t)new), 0);
+               *f = new;
+       }
+       return skb;
+}
+
 static struct sk_buff *
 set_tp_port(struct sk_buff *skb, struct odp_flow_key *key,
            const struct odp_action_tp_port *a,
@@ -424,6 +448,10 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
                        skb = set_nw_addr(skb, key, &a->nw_addr, gfp);
                        break;
 
+               case ODPAT_SET_NW_TOS:
+                       skb = set_nw_tos(skb, key, &a->nw_tos, gfp);
+                       break;
+
                case ODPAT_SET_TP_SRC:
                case ODPAT_SET_TP_DST:
                        skb = set_tp_port(skb, key, &a->tp_port, gfp);
index 2a8fb50..ea73f98 100644 (file)
@@ -859,7 +859,6 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
        error = -EFAULT;
        if (copy_from_user(&uf, ufp, sizeof(struct odp_flow_put)))
                goto error;
-       uf.flow.key.reserved = 0;
 
        table = rcu_dereference(dp->table);
        flow = dp_table_lookup(table, &uf.flow.key);
@@ -1004,7 +1003,6 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
        error = -EFAULT;
        if (copy_from_user(&uf, ufp, sizeof uf))
                goto error;
-       uf.key.reserved = 0;
 
        flow = dp_table_lookup(table, &uf.key);
        error = -ENOENT;
@@ -1040,7 +1038,6 @@ static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
 
                if (__copy_from_user(&uf, ufp, sizeof uf))
                        return -EFAULT;
-               uf.key.reserved = 0;
 
                flow = dp_table_lookup(table, &uf.key);
                if (!flow)
index b2de023..f470f3d 100644 (file)
@@ -231,6 +231,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
                struct vlan_hdr *vh = (struct vlan_hdr*)(skb->data + nh_ofs);
                key->dl_type = vh->h_vlan_encapsulated_proto;
                key->dl_vlan = vh->h_vlan_TCI & htons(VLAN_VID_MASK);
+               key->dl_vlan_pcp = (ntohs(vh->h_vlan_TCI) & 0xe000) >> 13;
                nh_ofs += sizeof(struct vlan_hdr);
        }
        memcpy(key->dl_src, eth->h_source, ETH_ALEN);
index 1f18370..c45dbeb 100644 (file)
@@ -46,7 +46,7 @@
 /* The most significant bit being set in the version field indicates an
  * experimental OpenFlow version.  
  */
-#define OFP_VERSION   0x97
+#define OFP_VERSION   0x98
 
 #define OFP_MAX_TABLE_NAME_LEN 32
 #define OFP_MAX_PORT_NAME_LEN  16
@@ -313,6 +313,7 @@ enum ofp_action_type {
     OFPAT_SET_DL_DST,       /* Ethernet destination address. */
     OFPAT_SET_NW_SRC,       /* IP source address. */
     OFPAT_SET_NW_DST,       /* IP destination address. */
+    OFPAT_SET_NW_TOS,       /* IP ToS/DSCP field (6 bits). */
     OFPAT_SET_TP_SRC,       /* TCP/UDP source port. */
     OFPAT_SET_TP_DST,       /* TCP/UDP destination port. */
     OFPAT_VENDOR = 0xffff
@@ -370,6 +371,15 @@ struct ofp_action_nw_addr {
 };
 OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
 
+/* Action structure for OFPAT_SET_NW_TOS. */
+struct ofp_action_nw_tos {
+    uint16_t type;                  /* OFPAT_SET_TW_TOS. */
+    uint16_t len;                   /* Length is 8. */
+    uint8_t nw_tos;                 /* IP ToS/DSCP (6 bits). */
+    uint8_t pad[3];
+};
+OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
+
 /* Action structure for OFPAT_SET_TP_SRC/DST. */
 struct ofp_action_tp_port {
     uint16_t type;                  /* OFPAT_SET_TP_SRC/DST. */
@@ -409,6 +419,7 @@ union ofp_action {
     struct ofp_action_vlan_vid vlan_vid;
     struct ofp_action_vlan_pcp vlan_pcp;
     struct ofp_action_nw_addr nw_addr;
+    struct ofp_action_nw_tos nw_tos;
     struct ofp_action_tp_port tp_port;
 };
 OFP_ASSERT(sizeof(union ofp_action) == 8);
@@ -436,14 +447,14 @@ enum ofp_flow_mod_command {
 
 /* Flow wildcards. */
 enum ofp_flow_wildcards {
-    OFPFW_IN_PORT  = 1 << 0,  /* Switch input port. */
-    OFPFW_DL_VLAN  = 1 << 1,  /* VLAN. */
-    OFPFW_DL_SRC   = 1 << 2,  /* Ethernet source address. */
-    OFPFW_DL_DST   = 1 << 3,  /* Ethernet destination address. */
-    OFPFW_DL_TYPE  = 1 << 4,  /* Ethernet frame type. */
-    OFPFW_NW_PROTO = 1 << 5,  /* IP protocol. */
-    OFPFW_TP_SRC   = 1 << 6,  /* TCP/UDP source port. */
-    OFPFW_TP_DST   = 1 << 7,  /* TCP/UDP destination port. */
+    OFPFW_IN_PORT    = 1 << 0,  /* Switch input port. */
+    OFPFW_DL_VLAN    = 1 << 1,  /* VLAN. */
+    OFPFW_DL_SRC     = 1 << 2,  /* Ethernet source address. */
+    OFPFW_DL_DST     = 1 << 3,  /* Ethernet destination address. */
+    OFPFW_DL_TYPE    = 1 << 4,  /* Ethernet frame type. */
+    OFPFW_NW_PROTO   = 1 << 5,  /* IP protocol. */
+    OFPFW_TP_SRC     = 1 << 6,  /* TCP/UDP source port. */
+    OFPFW_TP_DST     = 1 << 7,  /* TCP/UDP destination port. */
 
     /* IP source address wildcard bit count.  0 is exact match, 1 ignores the
      * LSB, 2 ignores the 2 least-significant bits, ..., 32 and higher wildcard
@@ -460,8 +471,10 @@ enum ofp_flow_wildcards {
     OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT,
     OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT,
 
+    OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */
+
     /* Wildcard all fields. */
-    OFPFW_ALL = ((1 << 20) - 1)
+    OFPFW_ALL = ((1 << 21) - 1)
 };
 
 /* The wildcards for ICMP type and code fields use the transport source 
@@ -492,15 +505,17 @@ struct ofp_match {
     uint8_t dl_src[OFP_ETH_ALEN]; /* Ethernet source address. */
     uint8_t dl_dst[OFP_ETH_ALEN]; /* Ethernet destination address. */
     uint16_t dl_vlan;          /* Input VLAN. */
+    uint8_t dl_vlan_pcp;       /* Input VLAN priority. */
+    uint8_t pad1[1];           /* Align to 64-bits. */
     uint16_t dl_type;          /* Ethernet frame type. */
     uint8_t nw_proto;          /* IP protocol. */
-    uint8_t pad;               /* Align to 32-bits. */
+    uint8_t pad2[3];           /* Align to 64-bits. */
     uint32_t nw_src;           /* IP source address. */
     uint32_t nw_dst;           /* IP destination address. */
     uint16_t tp_src;           /* TCP/UDP source port. */
     uint16_t tp_dst;           /* TCP/UDP destination port. */
 };
-OFP_ASSERT(sizeof(struct ofp_match) == 36);
+OFP_ASSERT(sizeof(struct ofp_match) == 40);
 
 /* The match fields for ICMP type and code use the transport source and 
  * destination port fields, respectively. */
@@ -536,7 +551,7 @@ struct ofp_flow_mod {
                                             from the length field in the 
                                             header. */
 };
-OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
+OFP_ASSERT(sizeof(struct ofp_flow_mod) == 68);
 
 /* Why did this flow expire? */
 enum ofp_flow_expired_reason {
@@ -558,7 +573,7 @@ struct ofp_flow_expired {
     uint64_t packet_count;    
     uint64_t byte_count;
 };
-OFP_ASSERT(sizeof(struct ofp_flow_expired) == 72);
+OFP_ASSERT(sizeof(struct ofp_flow_expired) == 76);
 
 /* Values for 'type' in ofp_error_message.  These values are immutable: they
  * will not change in future versions of the protocol (although new values may
@@ -703,7 +718,7 @@ struct ofp_flow_stats_request {
                                  as an output port.  A value of OFPP_NONE 
                                  indicates no restriction. */
 };
-OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40);
+OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 44);
 
 /* Body of reply to OFPST_FLOW request. */
 struct ofp_flow_stats {
@@ -716,7 +731,7 @@ struct ofp_flow_stats {
                                  when this is not an exact-match entry. */
     uint16_t idle_timeout;    /* Number of seconds idle before expiration. */
     uint16_t hard_timeout;    /* Number of seconds before expiration. */
-    uint16_t pad2[3];         /* Pad to 64 bits. */
+    uint16_t pad2;            /* Pad to 64 bits. */
     uint64_t packet_count;    /* Number of packets in flow. */
     uint64_t byte_count;      /* Number of bytes in flow. */
     struct ofp_action_header actions[0]; /* Actions. */
@@ -733,7 +748,7 @@ struct ofp_aggregate_stats_request {
                                  as an output port.  A value of OFPP_NONE 
                                  indicates no restriction. */
 };
-OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40);
+OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 44);
 
 /* Body of reply to OFPST_AGGREGATE request. */
 struct ofp_aggregate_stats_reply {
index ab7eb9e..971b693 100644 (file)
@@ -162,7 +162,7 @@ struct odp_flow_key {
     __u8   dl_dst[ETH_ALEN];     /* Ethernet destination address. */
     __u8   nw_proto;             /* IP protocol or lower 8 bits of 
                                     ARP opcode. */
-    __u8   reserved;             /* Pad to 64 bits. */
+    __u8   dl_vlan_pcp;          /* Input VLAN priority. */
 };
 
 /* Flags for ODP_FLOW. */
@@ -208,9 +208,10 @@ struct odp_flowvec {
 #define ODPAT_SET_DL_DST        7    /* Ethernet destination address. */
 #define ODPAT_SET_NW_SRC        8    /* IP source address. */
 #define ODPAT_SET_NW_DST        9    /* IP destination address. */
-#define ODPAT_SET_TP_SRC        10   /* TCP/UDP source port. */
-#define ODPAT_SET_TP_DST        11   /* TCP/UDP destination port. */
-#define ODPAT_N_ACTIONS         12
+#define ODPAT_SET_NW_TOS        10   /* IP ToS/DSCP field (6 bits). */
+#define ODPAT_SET_TP_SRC        11   /* TCP/UDP source port. */
+#define ODPAT_SET_TP_DST        12   /* TCP/UDP destination port. */
+#define ODPAT_N_ACTIONS         13
 
 struct odp_action_output {
     __u16 type;                  /* ODPAT_OUTPUT. */
@@ -262,6 +263,14 @@ struct odp_action_nw_addr {
     __be32 nw_addr;             /* IP address. */
 };
 
+struct odp_action_nw_tos {
+    __u16 type;                  /* ODPAT_SET_NW_TOS. */
+    __u8 nw_tos;                 /* IP ToS/DSCP field (6 bits). */
+    __u8 reserved1;
+    __u16 reserved2;
+    __u16 reserved3;
+};
+
 /* Action structure for ODPAT_SET_TP_SRC/DST. */
 struct odp_action_tp_port {
     __u16 type;                  /* ODPAT_SET_TP_SRC/DST. */
@@ -279,6 +288,7 @@ union odp_action {
     struct odp_action_vlan_pcp vlan_pcp;
     struct odp_action_dl_addr dl_addr;
     struct odp_action_nw_addr nw_addr;
+    struct odp_action_nw_tos nw_tos;
     struct odp_action_tp_port tp_port;
 };
 
index 94c8380..b0f60e7 100644 (file)
@@ -55,7 +55,6 @@ void
 cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
                    uint32_t wildcards, unsigned int priority)
 {
-    assert(flow->reserved == 0);
     rule->flow = *flow;
     flow_wildcards_init(&rule->wc, wildcards);
     rule->priority = priority;
index 194b04e..84a3461 100644 (file)
@@ -60,6 +60,7 @@
     /*        -----------------  -----------  -------- */   \
     CLS_FIELD(OFPFW_IN_PORT,     in_port,     IN_PORT)      \
     CLS_FIELD(OFPFW_DL_VLAN,     dl_vlan,     DL_VLAN)      \
+    CLS_FIELD(OFPFW_DL_VLAN_PCP, dl_vlan_pcp, DL_VLAN_PCP)  \
     CLS_FIELD(OFPFW_DL_SRC,      dl_src,      DL_SRC)       \
     CLS_FIELD(OFPFW_DL_DST,      dl_dst,      DL_DST)       \
     CLS_FIELD(OFPFW_DL_TYPE,     dl_type,     DL_TYPE)      \
index c4b5a99..e6cf8fd 100644 (file)
@@ -664,7 +664,6 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
 {
     struct dp_netdev_flow *flow;
 
-    assert(key->reserved == 0);
     HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
                              flow_hash(key, 0), &dp->flow_table) {
         if (flow_equal(&flow->key, key)) {
@@ -762,6 +761,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;
@@ -806,7 +806,6 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
 
     flow = xcalloc(1, sizeof *flow);
     flow->key = odp_flow->key;
-    flow->key.reserved = 0;
 
     error = set_flow_actions(flow, odp_flow);
     if (error) {
@@ -1171,6 +1170,23 @@ 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;
+
+        /* We only set the lower 6 bits. */
+        uint8_t new = (a->nw_tos & 0x3f) | (nh->ip_tos & 0xc0);
+
+        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)
@@ -1294,6 +1310,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);
index 7d4a1bd..45bd01e 100644 (file)
@@ -139,6 +139,7 @@ flow_extract(struct ofpbuf *packet, uint16_t in_port, flow_t *flow)
             if (vh) {
                 flow->dl_type = vh->vlan_next_type;
                 flow->dl_vlan = vh->vlan_tci & htons(VLAN_VID_MASK);
+                flow->dl_vlan_pcp = (ntohs(vh->vlan_tci) & 0xe000) >> 13;
             }
         }
         memcpy(flow->dl_src, eth->eth_src, ETH_ADDR_LEN);
@@ -246,6 +247,7 @@ flow_to_ovs_match(const flow_t *flow, uint32_t wildcards,
     match->in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL
                            : flow->in_port);
     match->dl_vlan = flow->dl_vlan;
+    match->dl_vlan_pcp = flow->dl_vlan_pcp;
     memcpy(match->dl_src, flow->dl_src, ETH_ADDR_LEN);
     memcpy(match->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
     match->dl_type = flow->dl_type;
@@ -254,7 +256,8 @@ flow_to_ovs_match(const flow_t *flow, uint32_t wildcards,
     match->nw_proto = flow->nw_proto;
     match->tp_src = flow->tp_src;
     match->tp_dst = flow->tp_dst;
-    match->pad = 0;
+    memset(match->pad1, '\0', sizeof match->pad1);
+    memset(match->pad2, '\0', sizeof match->pad2);
 }
 
 /* Extract 'flow' with 'wildcards' into the OpenFlow match structure
@@ -297,13 +300,13 @@ flow_from_match(flow_t *flow, uint32_t *wildcards,
     flow->in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
                      : ntohs(match->in_port));
     flow->dl_vlan = match->dl_vlan;
+    flow->dl_vlan_pcp = match->dl_vlan_pcp;
     flow->dl_type = match->dl_type;
     flow->tp_src = match->tp_src;
     flow->tp_dst = match->tp_dst;
     memcpy(flow->dl_src, match->dl_src, ETH_ADDR_LEN);
     memcpy(flow->dl_dst, match->dl_dst, ETH_ADDR_LEN);
     flow->nw_proto = match->nw_proto;
-    flow->reserved = 0;
 }
 
 char *
@@ -317,9 +320,10 @@ flow_to_string(const flow_t *flow)
 void
 flow_format(struct ds *ds, const flow_t *flow)
 {
-    ds_put_format(ds, "in_port%04x:vlan%d mac"ETH_ADDR_FMT"->"ETH_ADDR_FMT" "
-                  "type%04x proto%"PRId8" ip"IP_FMT"->"IP_FMT" port%d->%d",
-                  flow->in_port, ntohs(flow->dl_vlan),
+    ds_put_format(ds, "in_port%04x:vlan%d:pcp%d mac"ETH_ADDR_FMT
+                  "->"ETH_ADDR_FMT" type%04x proto%"PRId8" ip"IP_FMT
+                  "->"IP_FMT" port%d->%d",
+                  flow->in_port, ntohs(flow->dl_vlan), flow->dl_vlan_pcp,
                   ETH_ADDR_ARGS(flow->dl_src), ETH_ADDR_ARGS(flow->dl_dst),
                   ntohs(flow->dl_type), flow->nw_proto,
                   IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst),
index a800162..87ac92b 100644 (file)
@@ -80,6 +80,9 @@ format_odp_action(struct ds *ds, const union odp_action *a)
         ds_put_format(ds, "set_nw_dst("IP_FMT")",
                       IP_ARGS(&a->nw_addr.nw_addr));
         break;
+    case ODPAT_SET_NW_TOS:
+        ds_put_format(ds, "set_nw_tos(%"PRIu8")", a->nw_tos.nw_tos);
+        break;
     case ODPAT_SET_TP_SRC:
         ds_put_format(ds, "set_tp_src(%"PRIu16")", ntohs(a->tp_port.tp_port));
         break;
index 9c1afe4..5385dd1 100644 (file)
@@ -243,6 +243,10 @@ ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
             sizeof(struct ofp_action_nw_addr),
             sizeof(struct ofp_action_nw_addr),
         },
+        [OFPAT_SET_NW_TOS] = {
+            sizeof(struct ofp_action_nw_tos),
+            sizeof(struct ofp_action_nw_tos),
+        },
         [OFPAT_SET_TP_SRC] = {
             sizeof(struct ofp_action_tp_port),
             sizeof(struct ofp_action_tp_port),
@@ -343,6 +347,12 @@ ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
         break;
     }
 
+    case OFPAT_SET_NW_TOS: {
+        struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
+        ds_put_format(string, "mod_nw_tos:%d", nt->nw_tos);
+        break;
+    }
+
     case OFPAT_SET_TP_SRC: {
         struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
         ds_put_format(string, "mod_tp_src:%d", ntohs(ta->tp_port));
@@ -669,6 +679,8 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity)
                "%d", ntohs(om->in_port));
     print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
                "0x%04x", ntohs(om->dl_vlan));
+    print_wild(&f, "dl_vlan_pcp=", w & OFPFW_DL_VLAN_PCP, verbosity,
+               "%d", om->dl_vlan_pcp);
     print_wild(&f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
                ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
     print_wild(&f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
index b11650f..09f6976 100644 (file)
@@ -865,6 +865,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
     memcpy(ofm->match.dl_src, flow->dl_src, sizeof ofm->match.dl_src);
     memcpy(ofm->match.dl_dst, flow->dl_dst, sizeof ofm->match.dl_dst);
     ofm->match.dl_vlan = flow->dl_vlan;
+    ofm->match.dl_vlan_pcp = flow->dl_vlan_pcp;
     ofm->match.dl_type = flow->dl_type;
     ofm->match.nw_src = flow->nw_src;
     ofm->match.nw_dst = flow->nw_dst;
@@ -1265,6 +1266,7 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
     case OFPAT_STRIP_VLAN:
     case OFPAT_SET_NW_SRC:
     case OFPAT_SET_NW_DST:
+    case OFPAT_SET_NW_TOS:
     case OFPAT_SET_TP_SRC:
     case OFPAT_SET_TP_DST:
         return check_action_exact_len(a, len, 8);
index 4995bbe..baa5a8b 100644 (file)
@@ -1846,6 +1846,7 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn,
                          (1u << OFPAT_SET_DL_DST) |
                          (1u << OFPAT_SET_NW_SRC) |
                          (1u << OFPAT_SET_NW_DST) |
+                         (1u << OFPAT_SET_NW_TOS) |
                          (1u << OFPAT_SET_TP_SRC) |
                          (1u << OFPAT_SET_TP_DST));
 
@@ -2163,6 +2164,10 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
         case OFPAT_SET_NW_DST:
             oa = odp_actions_add(ctx->out, ODPAT_SET_NW_DST);
             oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
+
+        case OFPAT_SET_NW_TOS:
+            oa = odp_actions_add(ctx->out, ODPAT_SET_NW_TOS);
+            oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
             break;
 
         case OFPAT_SET_TP_SRC:
@@ -2547,7 +2552,7 @@ flow_stats_cb(struct cls_rule *rule_, void *cbdata_)
     ofs->priority = htons(rule->cr.priority);
     ofs->idle_timeout = htons(rule->idle_timeout);
     ofs->hard_timeout = htons(rule->hard_timeout);
-    memset(ofs->pad2, 0, sizeof ofs->pad2);
+    ofs->pad2 = 0;
     ofs->packet_count = htonll(packet_count);
     ofs->byte_count = htonll(byte_count);
     memcpy(ofs->actions, rule->actions, act_len);
index 45b9728..74738d2 100755 (executable)
@@ -203,8 +203,9 @@ sub output {
                      1);        # in_port
     print FLOWS pack_ethaddr($flow{DL_SRC});
     print FLOWS pack_ethaddr($flow{DL_DST});
-    print FLOWS pack('nnCxNNnn',
+    print FLOWS pack('nCxnCxxxNNnn',
                      $flow{DL_VLAN},
+                     0,          # DL_VLAN_PCP
                      $flow{DL_TYPE},
                      $flow{NW_PROTO},
                      inet_aton($flow{NW_SRC}),
index 0307e48..c1d5101 100644 (file)
@@ -240,6 +240,7 @@ static uint32_t nw_dst_values[] = { T_HTONL(0xc0a80002),
                                     T_HTONL(0xc0a04455) };
 static uint16_t in_port_values[] = { T_HTONS(1), T_HTONS(OFPP_LOCAL) };
 static uint16_t dl_vlan_values[] = { T_HTONS(101), T_HTONS(0) };
+static uint8_t dl_vlan_pcp_values[] = { 7, 0 };
 static uint16_t dl_type_values[]
             = { T_HTONS(ETH_TYPE_IP), T_HTONS(ETH_TYPE_ARP) };
 static uint16_t tp_src_values[] = { T_HTONS(49362), T_HTONS(80) };
@@ -261,6 +262,9 @@ init_values(void)
     values[CLS_F_IDX_DL_VLAN][0] = &dl_vlan_values[0];
     values[CLS_F_IDX_DL_VLAN][1] = &dl_vlan_values[1];
 
+    values[CLS_F_IDX_DL_VLAN_PCP][0] = &dl_vlan_pcp_values[0];
+    values[CLS_F_IDX_DL_VLAN_PCP][1] = &dl_vlan_pcp_values[1];
+
     values[CLS_F_IDX_DL_SRC][0] = dl_src_values[0];
     values[CLS_F_IDX_DL_SRC][1] = dl_src_values[1];
 
@@ -290,6 +294,7 @@ init_values(void)
 #define N_NW_DST_VALUES ARRAY_SIZE(nw_dst_values)
 #define N_IN_PORT_VALUES ARRAY_SIZE(in_port_values)
 #define N_DL_VLAN_VALUES ARRAY_SIZE(dl_vlan_values)
+#define N_DL_VLAN_PCP_VALUES ARRAY_SIZE(dl_vlan_pcp_values)
 #define N_DL_TYPE_VALUES ARRAY_SIZE(dl_type_values)
 #define N_TP_SRC_VALUES ARRAY_SIZE(tp_src_values)
 #define N_TP_DST_VALUES ARRAY_SIZE(tp_dst_values)
@@ -301,6 +306,7 @@ init_values(void)
                        N_NW_DST_VALUES *        \
                        N_IN_PORT_VALUES *       \
                        N_DL_VLAN_VALUES *       \
+                       N_DL_VLAN_PCP_VALUES *   \
                        N_DL_TYPE_VALUES *       \
                        N_TP_SRC_VALUES *        \
                        N_TP_DST_VALUES *        \
@@ -350,6 +356,8 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls)
         flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)];
         flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)];
         flow.dl_vlan = dl_vlan_values[get_value(&x, N_DL_VLAN_VALUES)];
+        flow.dl_vlan_pcp = dl_vlan_pcp_values[get_value(&x,
+                N_DL_VLAN_PCP_VALUES)];
         flow.dl_type = dl_type_values[get_value(&x, N_DL_TYPE_VALUES)];
         flow.tp_src = tp_src_values[get_value(&x, N_TP_SRC_VALUES)];
         flow.tp_dst = tp_dst_values[get_value(&x, N_TP_DST_VALUES)];
@@ -358,7 +366,6 @@ compare_classifiers(struct classifier *cls, struct tcls *tcls)
         memcpy(flow.dl_dst, dl_dst_values[get_value(&x, N_DL_DST_VALUES)],
                ETH_ADDR_LEN);
         flow.nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
-        flow.reserved = 0;
 
         for (include = 1; include <= 3; include++) {
             cr0 = lookup_with_include_bits(cls, &flow, include);
index 439d3f5..109041b 100644 (file)
@@ -228,6 +228,11 @@ as \fIvlan\fR to match packets that are not tagged with a Virtual LAN;
 otherwise, specify a number between 0 and 4095, inclusive, as the
 12-bit VLAN ID to match.
 
+.IP \fBdl_vlan_pcp=\fIpriority\fR
+Matches IEEE 802.1q Priority Code Point (PCP) \fIpriority\fR, which is
+specified as a value between 0 and 7, inclusive.  A higher value
+indicates a higher frame priority level.
+
 .IP \fBdl_src=\fImac\fR
 Matches Ethernet source address \fImac\fR, which is specified as 6 pairs 
 of hexadecimal digits delimited by colons (e.g. \fB00:0A:E4:25:6B:B0\fR).
@@ -364,6 +369,12 @@ Sets the TCP or UDP source port to \fIport\fR.
 
 .IP \fBmod_tp_dst\fB:\fIport\fR
 Sets the TCP or UDP destination port to \fIport\fR.
+
+.IP \fBmod_nw_tos\fB:\fItos\fR
+Sets the IP ToS/DSCP field to \fItos\fR.  Valid values are between 0 and
+255, inclusive.  Note that the two lower reserved bits are never
+modified.
+
 .RE
 
 .IP
index 199bd43..fa2b5d9 100644 (file)
@@ -613,6 +613,10 @@ str_to_action(char *str, struct ofpbuf *b)
             struct ofp_action_tp_port *ta;
             ta = put_action(b, sizeof *ta, OFPAT_SET_TP_DST);
             ta->tp_port = htons(str_to_u32(arg));
+        } else if (!strcasecmp(act, "mod_nw_tos")) {
+            struct ofp_action_nw_tos *nt;
+            nt = put_action(b, sizeof *nt, OFPAT_SET_NW_TOS);
+            nt->nw_tos = str_to_u32(arg);
         } else if (!strcasecmp(act, "output")) {
             put_output_action(b, str_to_u32(arg));
         } else if (!strcasecmp(act, "drop")) {
@@ -686,6 +690,7 @@ parse_field(const char *name, const struct field **f_out)
     static const struct field fields[] = { 
         { "in_port", OFPFW_IN_PORT, F_U16, F_OFS(in_port), 0 },
         { "dl_vlan", OFPFW_DL_VLAN, F_U16, F_OFS(dl_vlan), 0 },
+        { "dl_vlan_pcp", OFPFW_DL_VLAN_PCP, F_U8, F_OFS(dl_vlan_pcp), 0 },
         { "dl_src", OFPFW_DL_SRC, F_MAC, F_OFS(dl_src), 0 },
         { "dl_dst", OFPFW_DL_DST, F_MAC, F_OFS(dl_dst), 0 },
         { "dl_type", OFPFW_DL_TYPE, F_U16, F_OFS(dl_type), 0 },