Skip to content

Commit

Permalink
Support matching and modifying IP ECN bits.
Browse files Browse the repository at this point in the history
Signed-off-by: Justin Pettit <[email protected]>
Acked-by: Jesse Gross <[email protected]>
  • Loading branch information
Justin Pettit committed Nov 9, 2011
1 parent 9e44d71 commit 530180f
Show file tree
Hide file tree
Showing 21 changed files with 146 additions and 72 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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.
- ovs-appctl:
- New "fdb/flush" command to flush bridge's MAC learning table.

Expand Down
15 changes: 2 additions & 13 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
#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>
#include <net/dsfield.h>

#include "actions.h"
#include "checksum.h"
Expand Down Expand Up @@ -151,17 +151,6 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
*addr = new_addr;
}

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;
}

static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
{
struct iphdr *nh;
Expand All @@ -181,7 +170,7 @@ static int set_ipv4(struct sk_buff *skb, const struct ovs_key_ipv4 *ipv4_key)
set_ip_addr(skb, nh, &nh->daddr, ipv4_key->ipv4_dst);

if (ipv4_key->ipv4_tos != nh->tos)
set_ip_tos(skb, nh, ipv4_key->ipv4_tos);
ipv4_change_dsfield(nh, 0, ipv4_key->ipv4_tos);

return 0;
}
Expand Down
4 changes: 0 additions & 4 deletions datapath/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down
13 changes: 4 additions & 9 deletions datapath/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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 = *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL);
ipv6_addr_copy(&key->ipv6.addr.src, &nh->saddr);
ipv6_addr_copy(&key->ipv6.addr.dst, &nh->daddr);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion datapath/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct sw_flow_key {
} eth;
struct {
u8 proto; /* IP protocol or lower 8 bits of ARP opcode. */
u8 tos; /* IP ToS DSCP in high 6 bits. */
u8 tos; /* IP ToS. */
u8 frag; /* One of OVS_FRAG_TYPE_*. */
} ip;
union {
Expand Down
9 changes: 9 additions & 0 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. ## */
/* ## --------------------- ## */
Expand Down
15 changes: 13 additions & 2 deletions lib/classifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,",
Expand Down
3 changes: 2 additions & 1 deletion lib/classifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 2 additions & 5 deletions lib/dpif-netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1086,12 +1086,9 @@ dp_netdev_set_ip_tos(struct ip_header *nh, uint8_t new_tos)
{
uint8_t *field = &nh->ip_tos;

/* Set the DSCP bits and preserve the ECN bits. */
uint8_t new = new_tos | (nh->ip_tos & IP_ECN_MASK);

nh->ip_csum = recalc_csum16(nh->ip_csum, htons((uint16_t)*field),
htons((uint16_t) new));
*field = new;
htons((uint16_t) new_tos));
*field = new_tos;
}

static void
Expand Down
18 changes: 7 additions & 11 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -525,19 +525,15 @@ flow_format(struct ds *ds, const struct flow *flow)
ntohs(flow->dl_type));

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);
ds_put_format(ds, " label%#"PRIx32" proto%"PRIu8" tos%#"PRIx8" ipv6",
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);

} else {
ds_put_format(ds, " proto%"PRIu8
" tos%"PRIu8
" ip"IP_FMT"->"IP_FMT,
flow->nw_proto,
flow->tos & IP_DSCP_MASK,
ds_put_format(ds, " proto%"PRIu8" tos%#"PRIx8" ip"IP_FMT"->"IP_FMT,
flow->nw_proto, flow->tos,
IP_ARGS(&flow->nw_src),
IP_ARGS(&flow->nw_dst));
}
Expand Down Expand Up @@ -1016,7 +1012,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;
Expand Down
Loading

0 comments on commit 530180f

Please sign in to comment.