ofproto: Match on IP ToS/DSCP bits (OpenFlow 1.0)
authorJustin Pettit <jpettit@nicira.com>
Fri, 22 Jan 2010 01:34:05 +0000 (17:34 -0800)
committerJustin Pettit <jpettit@nicira.com>
Sat, 20 Feb 2010 10:22:28 +0000 (02:22 -0800)
OpenFlow 1.0 adds support for matching on IP ToS/DSCP bits.

NOTE: OVS at this point is not wire-compatible with OpenFlow 1.0 until
the final commit in this OpenFlow 1.0 set.

14 files changed:
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/ofp-print.c
lib/vconn.c
tests/flowgen.pl
tests/test-classifier.c
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c

index 8de5614442ec9909e7df2b6ac908de346c91c7da..34d2c9bc2bb1df13eea46a468870f8344ef90bd2 100644 (file)
@@ -940,6 +940,7 @@ 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;
+       memset(uf.flow.key.reserved, 0, sizeof uf.flow.key.reserved);
 
        table = rcu_dereference(dp->table);
        flow = dp_table_lookup(table, &uf.flow.key);
@@ -1084,6 +1085,7 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
        error = -EFAULT;
        if (copy_from_user(&uf, ufp, sizeof uf))
                goto error;
+       memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
        flow = dp_table_lookup(table, &uf.key);
        error = -ENOENT;
@@ -1119,6 +1121,7 @@ static int query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
 
                if (__copy_from_user(&uf, ufp, sizeof uf))
                        return -EFAULT;
+               memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
                flow = dp_table_lookup(table, &uf.key);
                if (!flow)
index f470f3d6d39679fda5e4b176dbfba67816ee0380..4dc94889f419b8d9bfe2c2d41ef90ccf0682bd00 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2007, 2008, 2009 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
  *
  * Significant portions of this file may be copied from parts of the Linux
  * kernel, by Linus Torvalds and others.
@@ -244,6 +244,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct odp_flow_key *key)
                int th_ofs = nh_ofs + nh->ihl * 4;
                key->nw_src = nh->saddr;
                key->nw_dst = nh->daddr;
+               key->nw_tos = nh->tos & 0xfc;
                key->nw_proto = nh->protocol;
                skb_set_transport_header(skb, th_ofs);
 
index 654682d0ba8e08c8362cfdf53451bb6b61b4b6f6..87f9f2cf9e10f371c0bbb6269155c316f06f753a 100644 (file)
@@ -318,7 +318,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_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
@@ -380,7 +380,7 @@ OFP_ASSERT(sizeof(struct ofp_action_nw_addr) == 8);
 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 nw_tos;                 /* IP TOS (DSCP field, 6 bits). */
     uint8_t pad[3];
 };
 OFP_ASSERT(sizeof(struct ofp_action_nw_tos) == 8);
@@ -477,9 +477,10 @@ enum ofp_flow_wildcards {
     OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT,
 
     OFPFW_DL_VLAN_PCP = 1 << 20, /* VLAN priority. */
+    OFPFW_NW_TOS = 1 << 21, /* IP ToS (DSCP field, 6 bits). */
 
     /* Wildcard all fields. */
-    OFPFW_ALL = ((1 << 21) - 1)
+    OFPFW_ALL = ((1 << 22) - 1)
 };
 
 /* The wildcards for ICMP type and code fields use the transport source 
@@ -513,9 +514,10 @@ struct ofp_match {
     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_tos;            /* IP ToS (DSCP field, 6 bits). */
     uint8_t nw_proto;          /* IP protocol or lower 8 bits of 
                                   ARP opcode. */
-    uint8_t pad2[3];           /* Align to 64-bits. */
+    uint8_t pad2[2];           /* 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. */
index 19826332419efef93a54679e2c5e7390cea0f66d..84646c2297f76237c93eb9cb55c7e18c32387a58 100644 (file)
@@ -202,6 +202,8 @@ struct odp_flow_key {
     __u8   nw_proto;             /* IP protocol or lower 8 bits of 
                                     ARP opcode. */
     __u8   dl_vlan_pcp;          /* Input VLAN priority. */
+    __u8   nw_tos;               /* IP ToS (DSCP field, 6 bits). */
+    __u8   reserved[3];          /* Align to 32-bits...must be zeroed. */
 };
 
 /* Flags for ODP_FLOW. */
index 02cb02302c91b3082a6e0de56686a5bbbe6d9cff..036c372bd5437a69ceb7842113c6af849a332833 100644 (file)
@@ -57,6 +57,7 @@ void
 cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
                    uint32_t wildcards, unsigned int priority)
 {
+    assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
     rule->flow = *flow;
     flow_wildcards_init(&rule->wc, wildcards);
     rule->priority = priority;
index 45cb9572be3af25115db98254b0b705ba2dda019..f6cc93b9c7bc5ba8837d48b268c3a401219fcf37 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.
@@ -67,6 +67,7 @@
     CLS_FIELD(OFPFW_NW_SRC_MASK, nw_src,      NW_SRC)       \
     CLS_FIELD(OFPFW_NW_DST_MASK, nw_dst,      NW_DST)       \
     CLS_FIELD(OFPFW_NW_PROTO,    nw_proto,    NW_PROTO)     \
+    CLS_FIELD(OFPFW_NW_TOS,      nw_tos,      NW_TOS)       \
     CLS_FIELD(OFPFW_TP_SRC,      tp_src,      TP_SRC)       \
     CLS_FIELD(OFPFW_TP_DST,      tp_dst,      TP_DST)
 
index 8a749b184c43669645e41854732faca2b13cdf2a..1cab12ba163e78cc998782be0f1c126b864c51b6 100644 (file)
@@ -663,6 +663,7 @@ dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
 {
     struct dp_netdev_flow *flow;
 
+    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)) {
@@ -805,6 +806,7 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow)
 
     flow = xzalloc(sizeof *flow);
     flow->key = odp_flow->key;
+    memset(flow->key.reserved, 0, sizeof flow->key.reserved);
 
     error = set_flow_actions(flow, odp_flow);
     if (error) {
index 68a704783bb8d56a3e0ab3309132ebbb059ecbf6..d22890e54705fee67b43b21bbed2f021980252e3 100644 (file)
@@ -151,6 +151,7 @@ flow_extract(struct ofpbuf *packet, uint16_t in_port, flow_t *flow)
             if (nh) {
                 flow->nw_src = nh->ip_src;
                 flow->nw_dst = nh->ip_dst;
+                flow->nw_tos = nh->ip_tos & 0xfc;
                 flow->nw_proto = nh->ip_proto;
                 packet->l4 = b.data;
                 if (!IP_IS_FRAGMENT(nh->ip_frag_off)) {
@@ -251,6 +252,7 @@ flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match)
     match->dl_type = flow->dl_type;
     match->nw_src = flow->nw_src;
     match->nw_dst = flow->nw_dst;
+    match->nw_tos = flow->nw_tos;
     match->nw_proto = flow->nw_proto;
     match->tp_src = flow->tp_src;
     match->tp_dst = flow->tp_dst;
@@ -276,7 +278,9 @@ flow_from_match(flow_t *flow, uint32_t *wildcards,
     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_tos = match->nw_tos;
     flow->nw_proto = match->nw_proto;
+    memset(flow->reserved, 0, sizeof flow->reserved);
 }
 
 char *
@@ -291,11 +295,11 @@ void
 flow_format(struct ds *ds, const flow_t *flow)
 {
     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",
+                  "->"ETH_ADDR_FMT" type%04x proto%"PRId8" tos%"PRIu8
+                  " 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,
+                  ntohs(flow->dl_type), flow->nw_proto, flow->nw_tos,
                   IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst),
                   ntohs(flow->tp_src), ntohs(flow->tp_dst));
 }
index 8e0358096ab75eb41ed163f83d43e20fdd4d3968..90afec48d5ac430683e84780fd57049a8c5c8471 100644 (file)
@@ -696,6 +696,8 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity)
         } else {
             print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
                        "%u", om->nw_proto);
+            print_wild(&f, "nw_tos=", w & OFPFW_NW_TOS, verbosity,
+                       "%u", om->nw_tos);
         }
     }
     if (om->nw_proto == IP_TYPE_ICMP) {
index 7aab8215cf8fe99c52939be44897fd0ec70b771b..f8d3beb0c0c153e98e7b8ad42d5e5653e02190d6 100644 (file)
@@ -898,6 +898,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
     ofm->match.nw_src = flow->nw_src;
     ofm->match.nw_dst = flow->nw_dst;
     ofm->match.nw_proto = flow->nw_proto;
+    ofm->match.nw_tos = flow->nw_tos;
     ofm->match.tp_src = flow->tp_src;
     ofm->match.tp_dst = flow->tp_dst;
     ofm->command = htons(command);
index 74738d231fa4a3856b598cfab9029850ec6f42a1..bbb6f11d42bc34e005f6a1dd36b18238fab59a47 100755 (executable)
@@ -1,6 +1,6 @@
 #! /usr/bin/perl
 
-# 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.
@@ -60,6 +60,7 @@ sub output {
     $flow{DL_SRC} = "00:02:e3:0f:80:a4";
     $flow{DL_DST} = "00:1a:92:40:ac:05";
     $flow{NW_PROTO} = 0;
+    $flow{NW_TOS} = 0;
     $flow{NW_SRC} = '0.0.0.0';
     $flow{NW_DST} = '0.0.0.0';
     $flow{TP_SRC} = 0;
@@ -78,6 +79,7 @@ sub output {
         $flow{DL_TYPE} = 0x0800; # ETH_TYPE_IP
         $flow{NW_SRC} = '10.0.2.15';
         $flow{NW_DST} = '192.168.1.20';
+        $flow{NW_TOS} = 44;
         if ($attrs{TP_PROTO} eq 'other') {
             $flow{NW_PROTO} = 42;
         } elsif ($attrs{TP_PROTO} eq 'TCP' ||
@@ -124,7 +126,7 @@ sub output {
         if ($attrs{DL_TYPE} eq 'ip') {
             my $ip = pack('CCnnnCCnNN',
                           (4 << 4) | 5,    # version, hdrlen
-                          0,               # type of service
+                          $flow{NW_TOS},   # type of service
                           0,               # total length (filled in later)
                           65432,           # id
                           0,               # frag offset
@@ -203,10 +205,11 @@ sub output {
                      1);        # in_port
     print FLOWS pack_ethaddr($flow{DL_SRC});
     print FLOWS pack_ethaddr($flow{DL_DST});
-    print FLOWS pack('nCxnCxxxNNnn',
+    print FLOWS pack('nCxnCCxxNNnn',
                      $flow{DL_VLAN},
                      0,          # DL_VLAN_PCP
                      $flow{DL_TYPE},
+                     $flow{NW_TOS},
                      $flow{NW_PROTO},
                      inet_aton($flow{NW_SRC}),
                      inet_aton($flow{NW_DST}),
index f488ac662102fb603db12c8fbb91a1f16d85e74f..6c81cd60f090b0c23b411c942c0af51d2901e1db 100644 (file)
@@ -250,6 +250,7 @@ static uint8_t dl_src_values[][6] = { { 0x00, 0x02, 0xe3, 0x0f, 0x80, 0xa4 },
 static uint8_t dl_dst_values[][6] = { { 0x4a, 0x27, 0x71, 0xae, 0x64, 0xc1 },
                                       { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
 static uint8_t nw_proto_values[] = { IP_TYPE_TCP, IP_TYPE_ICMP };
+static uint8_t nw_tos_values[] = { 49, 0 };
 
 static void *values[CLS_N_FIELDS][2];
 
@@ -283,6 +284,9 @@ init_values(void)
     values[CLS_F_IDX_NW_PROTO][0] = &nw_proto_values[0];
     values[CLS_F_IDX_NW_PROTO][1] = &nw_proto_values[1];
 
+    values[CLS_F_IDX_NW_TOS][0] = &nw_tos_values[0];
+    values[CLS_F_IDX_NW_TOS][1] = &nw_tos_values[1];
+
     values[CLS_F_IDX_TP_SRC][0] = &tp_src_values[0];
     values[CLS_F_IDX_TP_SRC][1] = &tp_src_values[1];
 
@@ -301,6 +305,7 @@ init_values(void)
 #define N_DL_SRC_VALUES ARRAY_SIZE(dl_src_values)
 #define N_DL_DST_VALUES ARRAY_SIZE(dl_dst_values)
 #define N_NW_PROTO_VALUES ARRAY_SIZE(nw_proto_values)
+#define N_NW_TOS_VALUES ARRAY_SIZE(nw_tos_values)
 
 #define N_FLOW_VALUES (N_NW_SRC_VALUES *        \
                        N_NW_DST_VALUES *        \
@@ -312,7 +317,8 @@ init_values(void)
                        N_TP_DST_VALUES *        \
                        N_DL_SRC_VALUES *        \
                        N_DL_DST_VALUES *        \
-                       N_NW_PROTO_VALUES)
+                       N_NW_PROTO_VALUES *      \
+                       N_NW_TOS_VALUES)
 
 static unsigned int
 get_value(unsigned int *x, unsigned n_values)
@@ -366,6 +372,8 @@ 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.nw_tos = nw_tos_values[get_value(&x, N_NW_TOS_VALUES)];
+        memset(flow.reserved, 0, sizeof flow.reserved);
 
         for (include = 1; include <= 3; include++) {
             cr0 = lookup_with_include_bits(cls, &flow, include);
index 978dd1e0722bba818806c727bd506c15e43e2c16..15be8e986c6285d599d24f5570a6aa11c116cd3c 100644 (file)
@@ -1,4 +1,4 @@
-.TH ovs\-ofctl 8 "June 2009" "Open vSwitch" "Open vSwitch Manual"
+.TH ovs\-ofctl 8 "January 2010" "Open vSwitch" "Open vSwitch Manual"
 .ds PN ovs\-ofctl
 
 .SH NAME
@@ -240,6 +240,11 @@ Matches IPv4 destination address \fIip\fR.
 Matches IP protocol type \fIproto\fR, which is specified as a decimal 
 number between 0 and 255, inclusive (e.g. 6 to match TCP packets).
 
+.IP \fBnw_tos=\fItos\fR
+Matches IP ToS/DSCP field \fItos\fR, which is specified as a decimal 
+number between 0 and 255, inclusive.  Note that the two lower reserved
+bits are ignored for matching purposes.
+
 .IP \fBtp_src=\fIport\fR
 Matches UDP or TCP source port \fIport\fR, which is specified as a decimal 
 number between 0 and 65535, inclusive (e.g. 80 to match packets originating 
index 1a4700cd7bbf7a5f24eaa7dd36ace9a16f6dbd6b..852d542e864ab3073dd3e5e12d622455dbb9c845 100644 (file)
@@ -667,6 +667,7 @@ parse_field(const char *name, const struct field **f_out)
         { "nw_dst", OFPFW_NW_DST_MASK, F_IP,
           F_OFS(nw_dst), OFPFW_NW_DST_SHIFT },
         { "nw_proto", OFPFW_NW_PROTO, F_U8, F_OFS(nw_proto), 0 },
+        { "nw_tos", OFPFW_NW_TOS, F_U8, F_OFS(nw_tos), 0 },
         { "tp_src", OFPFW_TP_SRC, F_U16, F_OFS(tp_src), 0 },
         { "tp_dst", OFPFW_TP_DST, F_U16, F_OFS(tp_dst), 0 },
         { "icmp_type", OFPFW_ICMP_TYPE, F_U16, F_OFS(icmp_type), 0 },