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,
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);
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);
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;
if (__copy_from_user(&uf, ufp, sizeof uf))
return -EFAULT;
- uf.key.reserved = 0;
flow = dp_table_lookup(table, &uf.key);
if (!flow)
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);
/* 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
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
};
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. */
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);
/* 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
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
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. */
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 {
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
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 {
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. */
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 {
__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. */
#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. */
__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. */
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;
};
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;
/* ----------------- ----------- -------- */ \
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) \
{
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)) {
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;
flow = xzalloc(sizeof *flow);
flow->key = odp_flow->key;
- flow->key.reserved = 0;
error = set_flow_actions(flow, odp_flow);
if (error) {
}
}
+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)
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);
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);
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;
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
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 *
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),
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;
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),
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));
"%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,
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;
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);
(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));
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:
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);
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}),
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) };
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];
#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)
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 * \
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)];
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);
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).
.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
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")) {
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 },