From: Justin Pettit Date: Wed, 11 Nov 2009 22:59:49 +0000 (-0800) Subject: ofproto: Match VLAN PCP and rewrite ToS bits (OpenFlow 0.9) X-Git-Tag: v1.0.0~259^2~111 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=959a2ecdc8a5ffe53e74456ff6eb1ec25092db75;p=sliver-openvswitch.git ofproto: Match VLAN PCP and rewrite ToS bits (OpenFlow 0.9) 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. --- diff --git a/datapath/actions.c b/datapath/actions.c index 4fc0a4a44..fccacf217 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -285,6 +285,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, @@ -491,6 +515,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); diff --git a/datapath/datapath.c b/datapath/datapath.c index 1e878ebee..8de561444 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -940,7 +940,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); @@ -1085,7 +1084,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; @@ -1121,7 +1119,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) diff --git a/datapath/flow.c b/datapath/flow.c index b2de02340..f470f3d6d 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -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); diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 1f1837071..c45dbeb5b 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -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 { diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h index b079f5293..198263324 100644 --- a/include/openvswitch/datapath-protocol.h +++ b/include/openvswitch/datapath-protocol.h @@ -201,7 +201,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. */ @@ -247,9 +247,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. */ @@ -301,6 +302,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. */ @@ -318,6 +327,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; }; diff --git a/lib/classifier.c b/lib/classifier.c index f4280ef0c..6ddfa82d8 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -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; diff --git a/lib/classifier.h b/lib/classifier.h index 194b04e6b..84a3461e2 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -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) \ diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 1dee14b47..8a749b184 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -663,7 +663,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)) { @@ -761,6 +760,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; @@ -805,7 +805,6 @@ add_flow(struct dpif *dpif, struct odp_flow *odp_flow) flow = xzalloc(sizeof *flow); flow->key = odp_flow->key; - flow->key.reserved = 0; error = set_flow_actions(flow, odp_flow); if (error) { @@ -1170,6 +1169,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) @@ -1293,6 +1309,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); diff --git a/lib/flow.c b/lib/flow.c index bfbd54241..d8c287531 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -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 @@ -298,13 +301,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 * @@ -318,9 +321,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), diff --git a/lib/odp-util.c b/lib/odp-util.c index a80016209..87ac92b82 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -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; diff --git a/lib/ofp-print.c b/lib/ofp-print.c index e22712992..64116f775 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -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, diff --git a/lib/vconn.c b/lib/vconn.c index c77b6524d..e381c3d8d 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -892,6 +892,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; @@ -1292,6 +1293,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); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index b1f022f25..447d7f09b 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1853,6 +1853,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)); @@ -2170,6 +2171,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: @@ -2554,7 +2559,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); diff --git a/tests/flowgen.pl b/tests/flowgen.pl index 45b972845..74738d231 100755 --- a/tests/flowgen.pl +++ b/tests/flowgen.pl @@ -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}), diff --git a/tests/test-classifier.c b/tests/test-classifier.c index 010cdc641..f488ac662 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -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); diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 17b5a4006..c89098058 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -212,6 +212,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). @@ -348,6 +353,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 diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 2a171533e..9a3f8c70a 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -580,6 +580,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")) { @@ -653,6 +657,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 },