From 834377ea559d665520910968358c522f30d3eb93 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Thu, 21 Jan 2010 17:34:05 -0800 Subject: [PATCH] ofproto: Match on IP ToS/DSCP bits (OpenFlow 1.0) 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. --- datapath/datapath.c | 3 +++ datapath/flow.c | 3 ++- include/openflow/openflow.h | 10 ++++++---- include/openvswitch/datapath-protocol.h | 2 ++ lib/classifier.c | 1 + lib/classifier.h | 3 ++- lib/dpif-netdev.c | 2 ++ lib/flow.c | 10 +++++++--- lib/ofp-print.c | 2 ++ lib/vconn.c | 1 + tests/flowgen.pl | 9 ++++++--- tests/test-classifier.c | 10 +++++++++- utilities/ovs-ofctl.8.in | 7 ++++++- utilities/ovs-ofctl.c | 1 + 14 files changed, 50 insertions(+), 14 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 8de561444..34d2c9bc2 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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) diff --git a/datapath/flow.c b/datapath/flow.c index f470f3d6d..4dc94889f 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -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); diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 654682d0b..87f9f2cf9 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -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. */ diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index 198263324..84646c229 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -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. */ diff --git a/lib/classifier.c b/lib/classifier.c index 02cb02302..036c372bd 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -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; diff --git a/lib/classifier.h b/lib/classifier.h index 45cb9572b..f6cc93b9c 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -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) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 8a749b184..1cab12ba1 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -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) { diff --git a/lib/flow.c b/lib/flow.c index 68a704783..d22890e54 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -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)); } diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 8e0358096..90afec48d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -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) { diff --git a/lib/vconn.c b/lib/vconn.c index 7aab8215c..f8d3beb0c 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -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); diff --git a/tests/flowgen.pl b/tests/flowgen.pl index 74738d231..bbb6f11d4 100755 --- a/tests/flowgen.pl +++ b/tests/flowgen.pl @@ -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}), diff --git a/tests/test-classifier.c b/tests/test-classifier.c index f488ac662..6c81cd60f 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -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); diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 978dd1e07..15be8e986 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -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 diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 1a4700cd7..852d542e8 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -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 }, -- 2.43.0