Skip to content

Commit

Permalink
datapath: Allow matching on conntrack mark
Browse files Browse the repository at this point in the history
Allow matching and setting the ct_mark field. As with ct_state and
ct_zone, these fields are populated when the CT action is executed. To
write to this field, a value and mask can be specified as a nested
attribute under the CT action. This data is stored with the conntrack
entry, and is executed after the lookup occurs for the CT action. The
conntrack entry itself must be committed using the COMMIT flag in the CT
action flags for this change to persist.

Upstream: 182e304 "openvswitch: Allow matching on conntrack mark"
Signed-off-by: Justin Pettit <jpettit@nicira.com>
Signed-off-by: Joe Stringer <joestringer@nicira.com>
Acked-by: Pravin B Shelar <pshelar@nicira.com>
  • Loading branch information
joestringer committed Dec 4, 2015
1 parent a94ebc3 commit 372ce97
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 3 deletions.
1 change: 1 addition & 0 deletions datapath/actions.c
Expand Up @@ -981,6 +981,7 @@ static int execute_masked_set_action(struct sk_buff *skb,

case OVS_KEY_ATTR_CT_STATE:
case OVS_KEY_ATTR_CT_ZONE:
case OVS_KEY_ATTR_CT_MARK:
err = -EINVAL;
break;
}
Expand Down
67 changes: 64 additions & 3 deletions datapath/conntrack.c
Expand Up @@ -34,12 +34,19 @@ struct ovs_ct_len_tbl {
size_t minlen;
};

/* Metadata mark for masked write to conntrack mark */
struct md_mark {
u32 value;
u32 mask;
};

/* Conntrack action context for execution. */
struct ovs_conntrack_info {
struct nf_conntrack_zone zone;
struct nf_conn *ct;
u32 flags;
u16 family;
struct md_mark mark;
};

static u16 key_to_nfproto(const struct sw_flow_key *key)
Expand Down Expand Up @@ -90,10 +97,12 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
}

static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
const struct nf_conntrack_zone *zone)
const struct nf_conntrack_zone *zone,
const struct nf_conn *ct)
{
key->ct.state = state;
key->ct.zone = zone->id;
key->ct.mark = ct ? ct->mark : 0;
}

/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
Expand All @@ -116,7 +125,7 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
} else if (post_ct) {
state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
}
__ovs_ct_update_key(key, state, zone);
__ovs_ct_update_key(key, state, zone, ct);
}

void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
Expand All @@ -133,6 +142,35 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone))
return -EMSGSIZE;

if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark))
return -EMSGSIZE;

return 0;
}

static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
u32 ct_mark, u32 mask)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
u32 new_mark;

if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK))
return -ENOTSUPP;

/* The connection could be invalid, in which case set_mark is no-op. */
ct = nf_ct_get(skb, &ctinfo);
if (!ct)
return 0;

new_mark = ct_mark | (ct->mark & ~(mask));
if (ct->mark != new_mark) {
ct->mark = new_mark;
nf_conntrack_event_cache(IPCT_MARK, ct);
key->ct.mark = new_mark;
}

return 0;
}

Expand Down Expand Up @@ -258,7 +296,7 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
u8 state;

state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED;
__ovs_ct_update_key(key, state, &info->zone);
__ovs_ct_update_key(key, state, &info->zone, exp->master);
} else {
int err;

Expand Down Expand Up @@ -321,7 +359,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
err = ovs_ct_commit(net, key, info, skb);
else
err = ovs_ct_lookup(net, key, info, skb);
if (err)
goto err;

if (info->mark.mask)
err = ovs_ct_set_mark(skb, key, info->mark.value,
info->mark.mask);
err:
skb_push(skb, nh_ofs);
return err;
}
Expand All @@ -331,6 +375,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
.maxlen = sizeof(u32) },
[OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16),
.maxlen = sizeof(u16) },
[OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark),
.maxlen = sizeof(struct md_mark) },
};

static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
Expand Down Expand Up @@ -365,6 +411,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
case OVS_CT_ATTR_ZONE:
info->zone.id = nla_get_u16(a);
break;
#endif
#ifdef CONFIG_NF_CONNTRACK_MARK
case OVS_CT_ATTR_MARK: {
struct md_mark *mark = nla_data(a);

info->mark = *mark;
break;
}
#endif
default:
OVS_NLERR(log, "Unknown conntrack attr (%d)",
Expand All @@ -388,6 +442,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr)
if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
attr == OVS_KEY_ATTR_CT_ZONE)
return true;
if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
attr == OVS_KEY_ATTR_CT_MARK)
return true;

return false;
}
Expand Down Expand Up @@ -450,6 +507,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
return -EMSGSIZE;
if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark),
&ct_info->mark))
return -EMSGSIZE;

nla_nest_end(skb, start);

Expand Down
1 change: 1 addition & 0 deletions datapath/conntrack.h
Expand Up @@ -66,6 +66,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb,
{
key->ct.state = 0;
key->ct.zone = 0;
key->ct.mark = 0;
}

static inline int ovs_ct_put_key(const struct sw_flow_key *key,
Expand Down
1 change: 1 addition & 0 deletions datapath/flow.h
Expand Up @@ -114,6 +114,7 @@ struct sw_flow_key {
struct {
/* Connection tracking fields. */
u16 zone;
u32 mark;
u8 state;
} ct;

Expand Down
10 changes: 10 additions & 0 deletions datapath/flow_netlink.c
Expand Up @@ -295,6 +295,7 @@ size_t ovs_key_attr_size(void)
+ nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
+ nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */
+ nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
+ nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
+ nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
+ nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
+ nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
Expand Down Expand Up @@ -351,6 +352,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
[OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
[OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) },
[OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
[OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) },
};

static bool check_attr_len(unsigned int attr_len, unsigned int expected_len)
Expand Down Expand Up @@ -824,6 +826,13 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);
*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
}
if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
ovs_ct_verify(OVS_KEY_ATTR_CT_MARK)) {
u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]);

SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask);
*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK);
}
return 0;
}

Expand Down Expand Up @@ -1957,6 +1966,7 @@ static int validate_set(const struct nlattr *a,

case OVS_KEY_ATTR_PRIORITY:
case OVS_KEY_ATTR_SKB_MARK:
case OVS_KEY_ATTR_CT_MARK:
case OVS_KEY_ATTR_ETHERNET:
break;

Expand Down

0 comments on commit 372ce97

Please sign in to comment.