Signed-off-by: Justin Pettit <jpet...@nicira.com> --- NEWS | 2 + datapath/actions.c | 10 +------ datapath/datapath.c | 4 --- datapath/flow.c | 13 +++------ include/openflow/nicira-ext.h | 9 ++++++ lib/classifier.c | 15 +++++++++- lib/classifier.h | 3 +- lib/flow.c | 12 +++----- lib/meta-flow.c | 57 +++++++++++++++++++++++++++++++--------- lib/meta-flow.h | 3 +- lib/nx-match.c | 16 +++++++++++ lib/nx-match.def | 3 +- lib/nx-match.h | 3 +- lib/odp-util.c | 8 +++--- lib/ofp-util.c | 5 +++ ofproto/ofproto-dpif.c | 2 +- tests/odp.at | 34 +++++++++++++----------- tests/ovs-ofctl.at | 12 ++++++++ utilities/ovs-ofctl.8.in | 8 ++++++ 19 files changed, 151 insertions(+), 68 deletions(-)
diff --git a/NEWS b/NEWS index 51e00cf..d13c906 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ post-v1.3.0 ------------------------ - OpenFlow: - Added ability to match on IPv6 flow label through NXM. + - Added ability to match on ECN bits in IPv4 and IPv6 through NXM. + - Added ability to modify ECN bits in IPv4 and IPv6. - ovs-appctl: - New "fdb/flush" command to flush bridge's MAC learning table. diff --git a/datapath/actions.c b/datapath/actions.c index afd1791..e8b0ce3 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -19,7 +19,6 @@ #include <linux/in6.h> #include <linux/if_arp.h> #include <linux/if_vlan.h> -#include <net/inet_ecn.h> #include <net/ip.h> #include <net/checksum.h> @@ -153,13 +152,8 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, static void set_ip_tos(struct sk_buff *skb, struct iphdr *nh, u8 new_tos) { - u8 old, new; - - /* Set the DSCP bits and preserve the ECN bits. */ - old = nh->tos; - new = new_tos | (nh->tos & INET_ECN_MASK); - csum_replace2(&nh->check, htons(old), htons(new)); - nh->tos = new; + csum_replace2(&nh->check, htons(nh->tos), htons(new_tos)); + nh->tos = new_tos; } static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key) diff --git a/datapath/datapath.c b/datapath/datapath.c index 94aa6ad..ca3e001 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -41,7 +41,6 @@ #include <linux/openvswitch.h> #include <linux/rculist.h> #include <linux/dmi.h> -#include <net/inet_ecn.h> #include <net/genetlink.h> #include "checksum.h" @@ -589,9 +588,6 @@ static int validate_action_key(const struct nlattr *a, if (ipv4_key->ipv4_proto != flow_key->ip.proto) return -EINVAL; - if (ipv4_key->ipv4_tos & INET_ECN_MASK) - return -EINVAL; - if (ipv4_key->ipv4_frag != flow_key->ip.frag) return -EINVAL; diff --git a/datapath/flow.c b/datapath/flow.c index 6b57ec2..f3e3751 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -30,7 +30,6 @@ #include <linux/icmp.h> #include <linux/icmpv6.h> #include <linux/rculist.h> -#include <net/inet_ecn.h> #include <net/ip.h> #include <net/ipv6.h> #include <net/ndisc.h> @@ -200,7 +199,7 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key, payload_ofs = (u8 *)(nh + 1) - skb->data; key->ip.proto = NEXTHDR_NONE; - key->ip.tos = ipv6_get_dsfield(nh) & ~INET_ECN_MASK; + key->ip.tos = ipv6_get_dsfield(nh); key->ipv6.label = *(u32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL); ipv6_addr_copy(&key->ipv6.addr.src, &nh->saddr); ipv6_addr_copy(&key->ipv6.addr.dst, &nh->daddr); @@ -689,7 +688,7 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key, key->ipv4.addr.dst = nh->daddr; key->ip.proto = nh->protocol; - key->ip.tos = nh->tos & ~INET_ECN_MASK; + key->ip.tos = nh->tos; offset = nh->frag_off & htons(IP_OFFSET); if (offset) { @@ -958,8 +957,6 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, if (swkey->eth.type != htons(ETH_P_IP)) goto invalid; ipv4_key = nla_data(nla); - if (ipv4_key->ipv4_tos & INET_ECN_MASK) - goto invalid; if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) goto invalid; swkey->ip.proto = ipv4_key->ipv4_proto; @@ -974,8 +971,6 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, if (swkey->eth.type != htons(ETH_P_IPV6)) goto invalid; ipv6_key = nla_data(nla); - if (ipv6_key->ipv6_tos & INET_ECN_MASK) - goto invalid; if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) goto invalid; swkey->ipv6.label = ipv6_key->ipv6_label; @@ -1249,7 +1244,7 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) ipv4_key->ipv4_src = swkey->ipv4.addr.src; ipv4_key->ipv4_dst = swkey->ipv4.addr.dst; ipv4_key->ipv4_proto = swkey->ip.proto; - ipv4_key->ipv4_tos = swkey->ip.tos & ~INET_ECN_MASK; + ipv4_key->ipv4_tos = swkey->ip.tos; ipv4_key->ipv4_frag = swkey->ip.frag; } else if (swkey->eth.type == htons(ETH_P_IPV6)) { struct ovs_key_ipv6 *ipv6_key; @@ -1265,7 +1260,7 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb) sizeof(ipv6_key->ipv6_dst)); ipv6_key->ipv6_label = swkey->ipv6.label; ipv6_key->ipv6_proto = swkey->ip.proto; - ipv6_key->ipv6_tos = swkey->ip.tos & ~INET_ECN_MASK; + ipv6_key->ipv6_tos = swkey->ip.tos; ipv6_key->ipv6_frag = swkey->ip.frag; } else if (swkey->eth.type == htons(ETH_P_ARP)) { struct ovs_key_arp *arp_key; diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index a2e383d..d0c4602 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -1623,6 +1623,15 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24); * Masking: Not maskable. */ #define NXM_NX_IPV6_LABEL NXM_HEADER (0x0001, 27, 4) +/* The ECN of the IP header. + * + * Prereqs: NXM_OF_ETH_TYPE must be either 0x0800 or 0x86dd. + * + * Format: ECN in the low-order 2 bits. + * + * Masking: Not maskable. */ +#define NXM_NX_IP_ECN NXM_HEADER (0x0001, 28, 1) + /* ## --------------------- ## */ /* ## Requests and replies. ## */ /* ## --------------------- ## */ diff --git a/lib/classifier.c b/lib/classifier.c index 53ef03a..39a84d5 100644 --- a/lib/classifier.c +++ b/lib/classifier.c @@ -318,11 +318,19 @@ cls_rule_set_nw_dst_masked(struct cls_rule *rule, ovs_be32 ip, ovs_be32 mask) } void -cls_rule_set_nw_tos(struct cls_rule *rule, uint8_t nw_tos) +cls_rule_set_nw_dscp(struct cls_rule *rule, uint8_t nw_dscp) { rule->wc.tos_mask |= IP_DSCP_MASK; rule->flow.tos &= ~IP_DSCP_MASK; - rule->flow.tos |= nw_tos & IP_DSCP_MASK; + rule->flow.tos |= nw_dscp & IP_DSCP_MASK; +} + +void +cls_rule_set_nw_ecn(struct cls_rule *rule, uint8_t nw_ecn) +{ + rule->wc.tos_mask |= IP_ECN_MASK; + rule->flow.tos &= ~IP_ECN_MASK; + rule->flow.tos |= nw_ecn & IP_ECN_MASK; } void @@ -620,6 +628,9 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s) if (wc->tos_mask & IP_DSCP_MASK) { ds_put_format(s, "nw_tos=%"PRIu8",", f->tos & IP_DSCP_MASK); } + if (wc->tos_mask & IP_ECN_MASK) { + ds_put_format(s, "nw_ecn=%"PRIu8",", f->tos & IP_ECN_MASK); + } switch (wc->frag_mask) { case FLOW_FRAG_ANY | FLOW_FRAG_LATER: ds_put_format(s, "frag=%s,", diff --git a/lib/classifier.h b/lib/classifier.h index a61d0e6..581ee83 100644 --- a/lib/classifier.h +++ b/lib/classifier.h @@ -116,7 +116,8 @@ void cls_rule_set_nw_src(struct cls_rule *, ovs_be32); bool cls_rule_set_nw_src_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask); void cls_rule_set_nw_dst(struct cls_rule *, ovs_be32); bool cls_rule_set_nw_dst_masked(struct cls_rule *, ovs_be32 ip, ovs_be32 mask); -void cls_rule_set_nw_tos(struct cls_rule *, uint8_t); +void cls_rule_set_nw_dscp(struct cls_rule *, uint8_t); +void cls_rule_set_nw_ecn(struct cls_rule *, uint8_t); void cls_rule_set_frag(struct cls_rule *, uint8_t frag); void cls_rule_set_frag_masked(struct cls_rule *, uint8_t frag, uint8_t mask); void cls_rule_set_icmp_type(struct cls_rule *, uint8_t); diff --git a/lib/flow.c b/lib/flow.c index bc53bd8..8237546 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -148,7 +148,7 @@ parse_ipv6(struct ofpbuf *packet, struct flow *flow) flow->ipv6_dst = nh->ip6_dst; tc_flow = get_unaligned_be32(&nh->ip6_flow); - flow->tos = (ntohl(tc_flow) >> 4) & IP_DSCP_MASK; + flow->tos = ntohl(tc_flow) >> 4; flow->ipv6_label = tc_flow & htonl(IPV6_LABEL_MASK); flow->nw_proto = IPPROTO_NONE; @@ -369,7 +369,7 @@ flow_extract(struct ofpbuf *packet, uint32_t priority, ovs_be64 tun_id, flow->nw_dst = get_unaligned_be32(&nh->ip_dst); flow->nw_proto = nh->ip_proto; - flow->tos = nh->ip_tos & IP_DSCP_MASK; + flow->tos = nh->ip_tos; if (IP_IS_FRAGMENT(nh->ip_frag_off)) { flow->frag |= FLOW_FRAG_ANY; if (nh->ip_frag_off & htons(IP_FRAG_OFF_MASK)) { @@ -526,8 +526,7 @@ flow_format(struct ds *ds, const struct flow *flow) if (flow->dl_type == htons(ETH_TYPE_IPV6)) { ds_put_format(ds, " label%#"PRIx32" proto%"PRIu8" tos%"PRIu8" ipv6", - ntohl(flow->ipv6_label), flow->nw_proto, - flow->tos & IP_DSCP_MASK); + ntohl(flow->ipv6_label), flow->nw_proto, flow->tos); print_ipv6_addr(ds, &flow->ipv6_src); ds_put_cstr(ds, "->"); print_ipv6_addr(ds, &flow->ipv6_dst); @@ -536,8 +535,7 @@ flow_format(struct ds *ds, const struct flow *flow) ds_put_format(ds, " proto%"PRIu8 " tos%"PRIu8 " ip"IP_FMT"->"IP_FMT, - flow->nw_proto, - flow->tos & IP_DSCP_MASK, + flow->nw_proto, flow->tos, IP_ARGS(&flow->nw_src), IP_ARGS(&flow->nw_dst)); } @@ -1016,7 +1014,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow) b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip); ip->ip_ihl_ver = IP_IHL_VER(5, 4); - ip->ip_tos = flow->tos & IP_DSCP_MASK; + ip->ip_tos = flow->tos; ip->ip_proto = flow->nw_proto; ip->ip_src = flow->nw_src; ip->ip_dst = flow->nw_dst; diff --git a/lib/meta-flow.c b/lib/meta-flow.c index a823c30..6e43c86 100644 --- a/lib/meta-flow.c +++ b/lib/meta-flow.c @@ -188,13 +188,20 @@ static const struct mf_field mf_fields[MFF_N_IDS] = { MFP_IP_ANY, NXM_OF_IP_PROTO, }, { - MFF_IP_TOS, "nw_tos", NULL, + MFF_IP_DSCP, "nw_tos", NULL, MF_FIELD_SIZES(u8), MFM_NONE, 0, MFS_DECIMAL, MFP_IP_ANY, NXM_OF_IP_TOS, }, { + MFF_IP_ECN, "nw_ecn", NULL, + 1, 2, + MFM_NONE, 0, + MFS_DECIMAL, + MFP_IP_ANY, + NXM_NX_IP_ECN, + }, { MFF_IP_FRAG, "ip_frag", NULL, 1, 2, MFM_FULLY, 0, @@ -422,8 +429,10 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc) case MFF_IPV6_DST: return ipv6_mask_is_any(&wc->ipv6_dst_mask); - case MFF_IP_TOS: + case MFF_IP_DSCP: return !(wc->tos_mask & IP_DSCP_MASK); + case MFF_IP_ECN: + return !(wc->tos_mask & IP_ECN_MASK); case MFF_IP_FRAG: return !(wc->frag_mask & FLOW_FRAG_MASK); @@ -524,9 +533,12 @@ mf_get_mask(const struct mf_field *mf, const struct flow_wildcards *wc, mask->ipv6 = wc->ipv6_dst_mask; break; - case MFF_IP_TOS: + case MFF_IP_DSCP: mask->u8 = wc->tos_mask & IP_DSCP_MASK; break; + case MFF_IP_ECN: + mask->u8 = wc->tos_mask & IP_ECN_MASK; + break; case MFF_IP_FRAG: mask->u8 = wc->frag_mask & FLOW_FRAG_MASK; break; @@ -642,8 +654,7 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow) * all. For example, the MFF_VLAN_TCI field will never have a nonzero value * without the VLAN_CFI bit being set, but we can't reject those values because * it is still legitimate to test just for those bits (see the documentation - * for NXM_OF_VLAN_TCI in nicira-ext.h). On the other hand, there is never a - * reason to set the low bit of MFF_IP_TOS to 1, so we reject that. */ + * for NXM_OF_VLAN_TCI in nicira-ext.h). */ bool mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) { @@ -692,8 +703,10 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value) case MFF_ND_TLL: return true; - case MFF_IP_TOS: + case MFF_IP_DSCP: return !(value->u8 & ~IP_DSCP_MASK); + case MFF_IP_ECN: + return !(value->u8 & ~IP_ECN_MASK); case MFF_IP_FRAG: return !(value->u8 & ~FLOW_FRAG_MASK); @@ -799,10 +812,14 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow, value->u8 = flow->nw_proto; break; - case MFF_IP_TOS: + case MFF_IP_DSCP: value->u8 = flow->tos & IP_DSCP_MASK; break; + case MFF_IP_ECN: + value->u8 = flow->tos & IP_ECN_MASK; + break; + case MFF_IP_FRAG: value->u8 = flow->frag; break; @@ -950,8 +967,12 @@ mf_set_value(const struct mf_field *mf, cls_rule_set_nw_proto(rule, value->u8); break; - case MFF_IP_TOS: - cls_rule_set_nw_tos(rule, value->u8); + case MFF_IP_DSCP: + cls_rule_set_nw_dscp(rule, value->u8); + break; + + case MFF_IP_ECN: + cls_rule_set_nw_ecn(rule, value->u8); break; case MFF_IP_FRAG: @@ -1117,11 +1138,16 @@ mf_set_wild(const struct mf_field *mf, struct cls_rule *rule) rule->flow.nw_proto = 0; break; - case MFF_IP_TOS: + case MFF_IP_DSCP: rule->wc.tos_mask |= IP_DSCP_MASK; rule->flow.tos &= ~IP_DSCP_MASK; break; + case MFF_IP_ECN: + rule->wc.tos_mask |= IP_ECN_MASK; + rule->flow.tos &= ~IP_ECN_MASK; + break; + case MFF_IP_FRAG: rule->wc.frag_mask |= FLOW_FRAG_MASK; rule->flow.frag &= ~FLOW_FRAG_MASK; @@ -1201,7 +1227,8 @@ mf_set(const struct mf_field *mf, case MFF_VLAN_PCP: case MFF_IPV6_LABEL: case MFF_IP_PROTO: - case MFF_IP_TOS: + case MFF_IP_DSCP: + case MFF_IP_ECN: case MFF_ARP_OP: case MFF_ARP_SHA: case MFF_ARP_THA: @@ -1424,8 +1451,12 @@ mf_random_value(const struct mf_field *mf, union mf_value *value) value->be32 &= ~htonl(IPV6_LABEL_MASK); break; - case MFF_IP_TOS: - value->u8 &= ~0x03; + case MFF_IP_DSCP: + value->u8 &= IP_DSCP_MASK; + break; + + case MFF_IP_ECN: + value->u8 &= IP_ECN_MASK; break; case MFF_IP_FRAG: diff --git a/lib/meta-flow.h b/lib/meta-flow.h index 6e0134c..42523fc 100644 --- a/lib/meta-flow.h +++ b/lib/meta-flow.h @@ -70,7 +70,8 @@ enum mf_field_id { MFF_IPV6_LABEL, /* be32 */ MFF_IP_PROTO, /* u8 (used for IPv4 or IPv6) */ - MFF_IP_TOS, /* u8 (used for IPv4 or IPv6) */ + MFF_IP_DSCP, /* u8 (used for IPv4 or IPv6) */ + MFF_IP_ECN, /* u8 (used for IPv4 or IPv6) */ MFF_IP_FRAG, /* u8 (used for IPv4 or IPv6) */ MFF_ARP_OP, /* be16 */ diff --git a/lib/nx-match.c b/lib/nx-match.c index 98ed6a6..cb73084 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -492,6 +492,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr) nxm_put_8(b, NXM_OF_IP_TOS, flow->tos & IP_DSCP_MASK); } + if (cr->wc.tos_mask & IP_ECN_MASK) { + nxm_put_8(b, NXM_NX_IP_ECN, flow->tos & IP_ECN_MASK); + } + if (!(wc & FWW_NW_PROTO)) { nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto); switch (flow->nw_proto) { @@ -542,6 +546,10 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr) nxm_put_8(b, NXM_OF_IP_TOS, flow->tos & IP_DSCP_MASK); } + if (cr->wc.tos_mask & IP_ECN_MASK) { + nxm_put_8(b, NXM_NX_IP_ECN, flow->tos & IP_ECN_MASK); + } + if (!(wc & FWW_NW_PROTO)) { nxm_put_8(b, NXM_OF_IP_PROTO, flow->nw_proto); switch (flow->nw_proto) { @@ -1047,6 +1055,9 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow) case NFI_NXM_OF_IP_TOS: return flow->tos & IP_DSCP_MASK; + case NFI_NXM_NX_IP_ECN: + return flow->tos & IP_ECN_MASK; + case NFI_NXM_NX_IP_FRAG: return flow->frag; @@ -1202,6 +1213,11 @@ nxm_write_field(const struct nxm_field *dst, struct flow *flow, flow->tos |= new_value & IP_DSCP_MASK; break; + case NFI_NXM_NX_IP_ECN: + flow->tos &= ~IP_ECN_MASK; + flow->tos |= new_value & IP_ECN_MASK; + break; + case NFI_NXM_NX_IP_FRAG: flow->frag = new_value; break; diff --git a/lib/nx-match.def b/lib/nx-match.def index 89efdad..3691043 100644 --- a/lib/nx-match.def +++ b/lib/nx-match.def @@ -26,7 +26,7 @@ DEFINE_FIELD_M(OF_ETH_DST, MFF_ETH_DST, true) DEFINE_FIELD (OF_ETH_SRC, MFF_ETH_SRC, true) DEFINE_FIELD (OF_ETH_TYPE, MFF_ETH_TYPE, false) DEFINE_FIELD_M(OF_VLAN_TCI, MFF_VLAN_TCI, true) -DEFINE_FIELD (OF_IP_TOS, MFF_IP_TOS, true) +DEFINE_FIELD (OF_IP_TOS, MFF_IP_DSCP, true) DEFINE_FIELD (OF_IP_PROTO, MFF_IP_PROTO, false) DEFINE_FIELD_M(OF_IP_SRC, MFF_IPV4_SRC, true) DEFINE_FIELD_M(OF_IP_DST, MFF_IPV4_DST, true) @@ -45,6 +45,7 @@ DEFINE_FIELD (NX_ARP_THA, MFF_ARP_THA, false) DEFINE_FIELD_M(NX_IPV6_SRC, MFF_IPV6_SRC, false) DEFINE_FIELD_M(NX_IPV6_DST, MFF_IPV6_DST, false) DEFINE_FIELD (NX_IPV6_LABEL, MFF_IPV6_LABEL,false) +DEFINE_FIELD (NX_IP_ECN, MFF_IP_ECN, true) /* XXX should we have MFF_ICMPV4_TYPE and MFF_ICMPV6_TYPE? */ DEFINE_FIELD (NX_ICMPV6_TYPE,MFF_ICMP_TYPE, false) DEFINE_FIELD (NX_ICMPV6_CODE,MFF_ICMP_CODE, false) diff --git a/lib/nx-match.h b/lib/nx-match.h index 346604e..6a33dbe 100644 --- a/lib/nx-match.h +++ b/lib/nx-match.h @@ -102,6 +102,7 @@ nxm_decode_n_bits(ovs_be16 ofs_nbits) * NXM_OF_ETH_TYPE 4 2 -- 6 * NXM_OF_VLAN_TCI 4 2 2 8 * NXM_OF_IP_TOS 4 1 -- 5 + * NXM_NX_IP_ECN 4 1 -- 5 * NXM_NX_IP_FRAG 4 1 1 8 * NXM_OF_IP_PROTO 4 2 -- 6 * NXM_OF_IPV6_SRC_W 4 16 16 36 @@ -118,7 +119,7 @@ nxm_decode_n_bits(ovs_be16 ofs_nbits) * NXM_NX_REG_W(4) 4 4 4 12 * NXM_NX_TUN_ID_W 4 8 8 20 * ------------------------------------------- - * total 265 + * total 270 * * So this value is conservative. */ diff --git a/lib/odp-util.c b/lib/odp-util.c index 2853bf7..29abce4 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -370,7 +370,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) case OVS_KEY_ATTR_IPV4: ipv4_key = nl_attr_get(a); ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT"," - "proto=%"PRId8",tos=%"PRIu8",frag=%s)", + "proto=%"PRId8",tos=0x%"PRIx8",frag=%s)", IP_ARGS(&ipv4_key->ipv4_src), IP_ARGS(&ipv4_key->ipv4_dst), ipv4_key->ipv4_proto, ipv4_key->ipv4_tos, @@ -386,7 +386,7 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds) inet_ntop(AF_INET6, ipv6_key->ipv6_dst, dst_str, sizeof dst_str); ds_put_format(ds, "ipv6(src=%s,dst=%s,label=0x%"PRIx32",proto=%"PRId8 - ",tos=%"PRIu8",frag=%s)", + ",tos=0x%"PRIx8",frag=%s)", src_str, dst_str, ntohl(ipv6_key->ipv6_label), ipv6_key->ipv6_proto, ipv6_key->ipv6_tos, ovs_frag_type_to_string(ipv6_key->ipv6_frag)); @@ -876,7 +876,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) ipv4_key->ipv4_src = flow->nw_src; ipv4_key->ipv4_dst = flow->nw_dst; ipv4_key->ipv4_proto = flow->nw_proto; - ipv4_key->ipv4_tos = flow->tos & IP_DSCP_MASK; + ipv4_key->ipv4_tos = flow->tos; ipv4_key->ipv4_frag = ovs_to_odp_frag(flow->frag); } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) { struct ovs_key_ipv6 *ipv6_key; @@ -888,7 +888,7 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow) memcpy(ipv6_key->ipv6_dst, &flow->ipv6_dst, sizeof ipv6_key->ipv6_dst); ipv6_key->ipv6_label = flow->ipv6_label; ipv6_key->ipv6_proto = flow->nw_proto; - ipv6_key->ipv6_tos = flow->tos & IP_DSCP_MASK; + ipv6_key->ipv6_tos = flow->tos; ipv6_key->ipv6_frag = ovs_to_odp_frag(flow->frag); } else if (flow->dl_type == htons(ETH_TYPE_ARP)) { struct ovs_key_arp *arp_key; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 5ef4e80..1b16279 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -897,6 +897,11 @@ ofputil_min_flow_format(const struct cls_rule *rule) return NXFF_NXM; } + /* Only NXM supports matching IP ECN bits. */ + if (wc->tos_mask & IP_ECN_MASK) { + return NXFF_NXM; + } + /* Other formats can express this rule. */ return NXFF_OPENFLOW10; } diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index a3ea474..d43a596 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3679,7 +3679,7 @@ commit_set_nw_action(const struct flow *flow, struct flow *base, ipv4_key.ipv4_src = base->nw_src = flow->nw_src; ipv4_key.ipv4_dst = base->nw_dst = flow->nw_dst; ipv4_key.ipv4_proto = base->nw_proto; - ipv4_key.ipv4_tos = flow->tos & IP_DSCP_MASK; + ipv4_key.ipv4_tos = flow->tos; ipv4_key.ipv4_frag = (base->frag == 0 ? OVS_FRAG_TYPE_NONE : base->frag == FLOW_FRAG_ANY ? OVS_FRAG_TYPE_FIRST : OVS_FRAG_TYPE_LATER); diff --git a/tests/odp.at b/tests/odp.at index 9da93c6..edbd401 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -4,22 +4,24 @@ AT_SETUP([OVS datapath parsing and formatting - valid forms]) AT_DATA([odp-base.txt], [dnl in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x1234) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=128,frag=no) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=128,frag=first) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=128,frag=later) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0,frag=no),tcp(src=80,dst=8080) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0,frag=no),udp(src=81,dst=6632) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0,frag=no),icmp(type=1,code=2) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=112,frag=no) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=112,frag=first) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=112,frag=later) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=6,tos=0,frag=no),tcp(src=80,dst=8080) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=17,tos=0,frag=no),udp(src=6630,dst=22) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0,frag=no),icmpv6(type=1,code=2) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0,frag=no),icmpv6(type=135,code=0),nd(target=::3) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0,frag=no),icmpv6(type=135,code=0),nd(target=::3,sll=00:05:06:07:08:09) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0,frag=no),icmpv6(type=136,code=0),nd(target=::3,tll=00:0a:0b:0c:0d:0e) -in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=no) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x81,frag=no) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=first) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=5,tos=0x80,frag=later) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=6,tos=0x0,frag=no),tcp(src=80,dst=8080) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=17,tos=0x0,frag=no),udp(src=81,dst=6632) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0800),ipv4(src=35.8.2.41,dst=172.16.0.20,proto=1,tos=0x0,frag=no),icmp(type=1,code=2) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=0x70,frag=no) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=0x71,frag=no) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=0x70,frag=first) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=10,tos=0x70,frag=later) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=6,tos=0x0,frag=no),tcp(src=80,dst=8080) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=17,tos=0x0,frag=no),udp(src=6630,dst=22) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0x0,frag=no),icmpv6(type=1,code=2) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0x0,frag=no),icmpv6(type=135,code=0),nd(target=::3) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0x0,frag=no),icmpv6(type=135,code=0),nd(target=::3,sll=00:05:06:07:08:09) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0x0,frag=no),icmpv6(type=136,code=0),nd(target=::3,tll=00:0a:0b:0c:0d:0e) +in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0x0,proto=58,tos=0x0,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e) in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4,tip=5.6.7.8,op=1,sha=00:0f:10:11:12:13,tha=00:14:15:16:17:18) ]) diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 23a4d8c..39093a8 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -211,8 +211,14 @@ NXM_OF_VLAN_TCI_W(0000/e000) # No 802.1Q or with VID=0 # IP TOS NXM_OF_ETH_TYPE(0800) NXM_OF_IP_TOS(f0) +NXM_OF_ETH_TYPE(0800) NXM_OF_IP_TOS(41) NXM_OF_IP_TOS(f0) +# IP ECN +NXM_OF_ETH_TYPE(0800) NXM_NX_IP_ECN(03) +NXM_OF_ETH_TYPE(0800) NXM_NX_IP_ECN(06) +NXM_NX_IP_ECN(03) + # IP protocol NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(01) NXM_OF_ETH_TYPE(0800) NXM_OF_IP_PROTO(05) @@ -389,6 +395,12 @@ NXM_OF_VLAN_TCI_W(0000/e000) # IP TOS NXM_OF_ETH_TYPE(0800), NXM_OF_IP_TOS(f0) +nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE) +nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ) + +# IP ECN +NXM_OF_ETH_TYPE(0800), NXM_NX_IP_ECN(03) +nx_pull_match() returned error 44010102 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_VALUE) nx_pull_match() returned error 44010104 (type OFPET_BAD_REQUEST, code NXBRC_NXM_BAD_PREREQ) # IP protocol diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index 2bf3740..30f9c58 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -408,6 +408,14 @@ When \fBdl_type\fR is wildcarded or set to a value other than 0x0800 or 0x86dd, the value of \fBnw_tos\fR is ignored (see \fBFlow Syntax\fR above). . +.IP \fBnw_ecn=\fIecn\fR +Matches \fIecn\fR bits in IP ToS or IPv6 traffic class fields, which is +specified as a decimal number between 0 and 3, inclusive. +.IP +When \fBdl_type\fR is wildcarded or set to a value other than 0x0800 or +0x86dd, the value of \fBnw_ecn\fR is ignored (see \fBFlow Syntax\fR +above). +. .IP \fBtp_src=\fIport\fR .IQ \fBtp_dst=\fIport\fR When \fBdl_type\fR and \fBnw_proto\fR specify TCP or UDP, \fBtp_src\fR -- 1.7.1 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev