Skip to content

Commit

Permalink
datapath: add skb mark matching and set action
Browse files Browse the repository at this point in the history
This patch adds support for skb mark matching and set action.

Acked-by: Jesse Gross <[email protected]>
Signed-off-by: Ansis Atteka <[email protected]>
  • Loading branch information
Ansis Atteka committed Nov 22, 2012
1 parent 24f974c commit 72e8bf2
Show file tree
Hide file tree
Showing 24 changed files with 158 additions and 34 deletions.
4 changes: 3 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ v1.9.0 - xx xxx xxxx
- The tunneling code no longer assumes input and output keys are symmetric.
If they are not, PMTUD needs to be disabled for tunneling to work. Note
this only applies to flow-based keys.
- Datapath: Support for ipv6 set action.
- Datapath:
- Support for ipv6 set action.
- SKB mark matching and setting.
- FreeBSD is now a supported platform, thanks to code contributions from
Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
- ovs-bugtool: New --ovs option to report only OVS related information.
Expand Down
4 changes: 4 additions & 0 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,10 @@ static int execute_set_action(struct sk_buff *skb,
skb->priority = nla_get_u32(nested_attr);
break;

case OVS_KEY_ATTR_SKB_MARK:
skb_set_mark(skb, nla_get_u32(nested_attr));
break;

case OVS_KEY_ATTR_TUN_ID:
/* If we're only using the TUN_ID action, store the value in a
* temporary instance of struct ovs_key_ipv4_tunnel on the stack.
Expand Down
33 changes: 33 additions & 0 deletions datapath/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,37 @@ static inline void skb_clear_rxhash(struct sk_buff *skb)
#define SET_NETNSOK .netnsok = true,
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
#ifdef CONFIG_NETFILTER
static inline u32 skb_get_mark(struct sk_buff *skb)
{
return skb->nfmark;
}

static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
{
skb->nfmark = mark;
}
#else /* CONFIG_NETFILTER */
static inline u32 skb_get_mark(struct sk_buff *skb)
{
return 0;
}

static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
{
}
#endif
#else /* before 2.6.20 */
static inline u32 skb_get_mark(struct sk_buff *skb)
{
return skb->mark;
}

static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
{
skb->mark = mark;
}
#endif /* after 2.6.20 */

#endif /* compat.h */
8 changes: 8 additions & 0 deletions datapath/datapath.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,13 @@ static int validate_set(const struct nlattr *a,
case OVS_KEY_ATTR_ETHERNET:
break;

case OVS_KEY_ATTR_SKB_MARK:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
if (nla_get_u32(ovs_key) != 0)
return -EINVAL;
#endif
break;

case OVS_KEY_ATTR_IPV4_TUNNEL:
tun_key = nla_data(ovs_key);
if (!tun_key->ipv4_dst)
Expand Down Expand Up @@ -826,6 +833,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)

OVS_CB(packet)->flow = flow;
packet->priority = flow->key.phy.priority;
skb_set_mark(packet, flow->key.phy.skb_mark);

rcu_read_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
Expand Down
24 changes: 24 additions & 0 deletions datapath/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
if (OVS_CB(skb)->tun_key)
memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
key->phy.in_port = in_port;
key->phy.skb_mark = skb_get_mark(skb);

skb_reset_mac_header(skb);

Expand Down Expand Up @@ -835,6 +836,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
[OVS_KEY_ATTR_ENCAP] = -1,
[OVS_KEY_ATTR_PRIORITY] = sizeof(u32),
[OVS_KEY_ATTR_IN_PORT] = sizeof(u32),
[OVS_KEY_ATTR_SKB_MARK] = sizeof(u32),
[OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet),
[OVS_KEY_ATTR_VLAN] = sizeof(__be16),
[OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16),
Expand Down Expand Up @@ -1024,6 +1026,15 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
} else {
swkey->phy.in_port = DP_MAX_PORTS;
}
if (attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {
uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
if (mark != 0)
return -EINVAL;
#endif
swkey->phy.skb_mark = mark;
attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
}

if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
Expand Down Expand Up @@ -1203,6 +1214,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru

flow->key.phy.in_port = DP_MAX_PORTS;
flow->key.phy.priority = 0;
flow->key.phy.skb_mark = 0;
memset(tun_key, 0, sizeof(flow->key.tun_key));

nla_for_each_nested(nla, attr, rem) {
Expand Down Expand Up @@ -1254,6 +1266,14 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
return -EINVAL;
flow->key.phy.in_port = nla_get_u32(nla);
break;

case OVS_KEY_ATTR_SKB_MARK:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
if (nla_get_u32(nla) != 0)
return -EINVAL;
#endif
flow->key.phy.skb_mark = nla_get_u32(nla);
break;
}
}
}
Expand Down Expand Up @@ -1291,6 +1311,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port))
goto nla_put_failure;

if (swkey->phy.skb_mark &&
nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, swkey->phy.skb_mark))
goto nla_put_failure;

nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
if (!nla)
goto nla_put_failure;
Expand Down
6 changes: 4 additions & 2 deletions datapath/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct sw_flow_key {
struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */
struct {
u32 priority; /* Packet QoS priority. */
u32 skb_mark; /* SKB mark. */
u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
} phy;
struct {
Expand Down Expand Up @@ -147,6 +148,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
* OVS_KEY_ATTR_TUN_ID 8 -- 4 12
* OVS_KEY_ATTR_IPV4_TUNNEL 24 -- 4 28
* OVS_KEY_ATTR_IN_PORT 4 -- 4 8
* OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
* OVS_KEY_ATTR_ETHERNET 12 -- 4 16
* OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
* OVS_KEY_ATTR_8021Q 4 -- 4 8
Expand All @@ -156,9 +158,9 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
* OVS_KEY_ATTR_ICMPV6 2 2 4 8
* OVS_KEY_ATTR_ND 28 -- 4 32
* -------------------------------------------------
* total 184
* total 192
*/
#define FLOW_BUFSIZE 184
#define FLOW_BUFSIZE 192

int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
Expand Down
4 changes: 3 additions & 1 deletion debian/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ openvswitch (1.9.0-1) unstable; urgency=low
- The tunneling code no longer assumes input and output keys are symmetric.
If they are not, PMTUD needs to be disabled for tunneling to work. Note
this only applies to flow-based keys.
- Datapath: Support for ipv6 set action.
- Datapath:
- Support for ipv6 set action.
- SKB mark matching and setting.
- FreeBSD is now a supported platform, thanks to code contributions from
Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
- ovs-bugtool: New --ovs option to report only OVS related information.
Expand Down
1 change: 1 addition & 0 deletions include/linux/openvswitch.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ enum ovs_key_attr {
OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */
OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */
OVS_KEY_ATTR_ND, /* struct ovs_key_nd */
OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */
OVS_KEY_ATTR_IPV4_TUNNEL, /* struct ovs_key_ipv4_tunnel */
OVS_KEY_ATTR_TUN_ID = 63, /* be64 tunnel ID */
__OVS_KEY_ATTR_MAX
Expand Down
2 changes: 1 addition & 1 deletion lib/dpif-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ dpif_linux_vport_send(int dp_ifindex, uint32_t port_no,
uint64_t action;

ofpbuf_use_const(&packet, data, size);
flow_extract(&packet, 0, NULL, 0, &flow);
flow_extract(&packet, 0, 0, NULL, 0, &flow);

ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
odp_flow_key_from_flow(&key, &flow, OVSP_NONE);
Expand Down
5 changes: 3 additions & 2 deletions lib/dpif-netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,7 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
ofpbuf_reserve(&copy, DP_NETDEV_HEADROOM);
ofpbuf_put(&copy, execute->packet->data, execute->packet->size);

flow_extract(&copy, 0, NULL, -1, &key);
flow_extract(&copy, 0, 0, NULL, -1, &key);
error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
&key);
if (!error) {
Expand Down Expand Up @@ -1027,7 +1027,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
if (packet->size < ETH_HEADER_LEN) {
return;
}
flow_extract(packet, 0, NULL, port->port_no, &key);
flow_extract(packet, 0, 0, NULL, port->port_no, &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, packet);
Expand Down Expand Up @@ -1192,6 +1192,7 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
switch (type) {
case OVS_KEY_ATTR_TUN_ID:
case OVS_KEY_ATTR_PRIORITY:
case OVS_KEY_ATTR_SKB_MARK:
case OVS_KEY_ATTR_IPV4_TUNNEL:
/* not implemented */
break;
Expand Down
5 changes: 3 additions & 2 deletions lib/flow.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ parse_icmpv6(struct ofpbuf *b, struct flow *flow)
* present and has a correct length, and otherwise NULL.
*/
void
flow_extract(struct ofpbuf *packet, uint32_t skb_priority,
flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
const struct flow_tnl *tnl, uint16_t ofp_in_port,
struct flow *flow)
{
Expand All @@ -352,6 +352,7 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority,
}
flow->in_port = ofp_in_port;
flow->skb_priority = skb_priority;
flow->skb_mark = skb_mark;

packet->l2 = b.data;
packet->l3 = NULL;
Expand Down Expand Up @@ -462,7 +463,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
void
flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
{
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);

fmd->tun_id = flow->tunnel.tun_id;
fmd->metadata = flow->metadata;
Expand Down
11 changes: 6 additions & 5 deletions lib/flow.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct ofpbuf;
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
#define FLOW_WC_SEQ 17
#define FLOW_WC_SEQ 18

#define FLOW_N_REGS 8
BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
Expand Down Expand Up @@ -87,6 +87,7 @@ struct flow {
uint32_t in_port; /* Input port. OpenFlow port number
unless in DPIF code, in which case it
is the datapath port number. */
uint32_t skb_mark; /* Packet mark. */
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
ovs_be16 dl_type; /* Ethernet frame type. */
ovs_be16 tp_src; /* TCP/UDP source port. */
Expand All @@ -105,8 +106,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
#define FLOW_U32S (sizeof(struct flow) / 4)

/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 144 &&
FLOW_WC_SEQ == 17);
BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 152 &&
FLOW_WC_SEQ == 18);

/* Represents the metadata fields of struct flow. */
struct flow_metadata {
Expand All @@ -116,8 +117,8 @@ struct flow_metadata {
uint16_t in_port; /* OpenFlow port or zero. */
};

void flow_extract(struct ofpbuf *, uint32_t priority, const struct flow_tnl *,
uint16_t in_port, struct flow *);
void flow_extract(struct ofpbuf *, uint32_t priority, uint32_t mark,
const struct flow_tnl *, uint16_t in_port, struct flow *);
void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
void flow_get_metadata(const struct flow *, struct flow_metadata *);

Expand Down
2 changes: 1 addition & 1 deletion lib/learning-switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)

/* Extract flow data from 'opi' into 'flow'. */
ofpbuf_use_const(&pkt, pi.packet, pi.packet_len);
flow_extract(&pkt, 0, NULL, pi.fmd.in_port, &flow);
flow_extract(&pkt, 0, 0, NULL, pi.fmd.in_port, &flow);
flow.tunnel.tun_id = pi.fmd.tun_id;

/* Choose output port. */
Expand Down
3 changes: 2 additions & 1 deletion lib/match.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ match_init_exact(struct match *match, const struct flow *flow)

match->flow = *flow;
match->flow.skb_priority = 0;
match->flow.skb_mark = 0;
memset(&match->flow.tunnel, 0, sizeof match->flow.tunnel);
match->flow.tunnel.tun_id = tun_id;
flow_wildcards_init_exact(&match->wc);
Expand Down Expand Up @@ -655,7 +656,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)

int i;

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);

if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "priority=%u,", priority);
Expand Down
2 changes: 1 addition & 1 deletion lib/nx-match.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
int match_len;
int i;

BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);

/* Metadata. */
if (match->wc.masks.in_port) {
Expand Down
Loading

0 comments on commit 72e8bf2

Please sign in to comment.