Skip to content

Commit 182e304

Browse files
joestringerdavem330
authored andcommitted
openvswitch: Allow matching on conntrack mark
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. Signed-off-by: Justin Pettit <[email protected]> Signed-off-by: Joe Stringer <[email protected]> Acked-by: Thomas Graf <[email protected]> Acked-by: Pravin B Shelar <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7f8a436 commit 182e304

File tree

6 files changed

+83
-4
lines changed

6 files changed

+83
-4
lines changed

include/uapi/linux/openvswitch.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ enum ovs_key_attr {
325325
* the accepted length of the array. */
326326
OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */
327327
OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */
328+
OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */
328329

329330
#ifdef __KERNEL__
330331
OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */
@@ -613,11 +614,15 @@ struct ovs_action_hash {
613614
* enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.
614615
* @OVS_CT_ATTR_FLAGS: u32 connection tracking flags.
615616
* @OVS_CT_ATTR_ZONE: u16 connection tracking zone.
617+
* @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the
618+
* mask, the corresponding bit in the value is copied to the connection
619+
* tracking mark field in the connection.
616620
*/
617621
enum ovs_ct_attr {
618622
OVS_CT_ATTR_UNSPEC,
619623
OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */
620624
OVS_CT_ATTR_ZONE, /* u16 zone id. */
625+
OVS_CT_ATTR_MARK, /* mark to associate with this connection. */
621626
__OVS_CT_ATTR_MAX
622627
};
623628

net/openvswitch/actions.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,7 @@ static int execute_masked_set_action(struct sk_buff *skb,
968968

969969
case OVS_KEY_ATTR_CT_STATE:
970970
case OVS_KEY_ATTR_CT_ZONE:
971+
case OVS_KEY_ATTR_CT_MARK:
971972
err = -EINVAL;
972973
break;
973974
}

net/openvswitch/conntrack.c

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,19 @@ struct ovs_ct_len_tbl {
2828
size_t minlen;
2929
};
3030

31+
/* Metadata mark for masked write to conntrack mark */
32+
struct md_mark {
33+
u32 value;
34+
u32 mask;
35+
};
36+
3137
/* Conntrack action context for execution. */
3238
struct ovs_conntrack_info {
3339
struct nf_conntrack_zone zone;
3440
struct nf_conn *ct;
3541
u32 flags;
3642
u16 family;
43+
struct md_mark mark;
3744
};
3845

3946
static u16 key_to_nfproto(const struct sw_flow_key *key)
@@ -84,10 +91,12 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
8491
}
8592

8693
static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
87-
const struct nf_conntrack_zone *zone)
94+
const struct nf_conntrack_zone *zone,
95+
const struct nf_conn *ct)
8896
{
8997
key->ct.state = state;
9098
key->ct.zone = zone->id;
99+
key->ct.mark = ct ? ct->mark : 0;
91100
}
92101

93102
/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
@@ -110,7 +119,7 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
110119
} else if (post_ct) {
111120
state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
112121
}
113-
__ovs_ct_update_key(key, state, zone);
122+
__ovs_ct_update_key(key, state, zone, ct);
114123
}
115124

116125
void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
@@ -127,6 +136,35 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
127136
nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone))
128137
return -EMSGSIZE;
129138

139+
if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
140+
nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark))
141+
return -EMSGSIZE;
142+
143+
return 0;
144+
}
145+
146+
static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
147+
u32 ct_mark, u32 mask)
148+
{
149+
enum ip_conntrack_info ctinfo;
150+
struct nf_conn *ct;
151+
u32 new_mark;
152+
153+
if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK))
154+
return -ENOTSUPP;
155+
156+
/* The connection could be invalid, in which case set_mark is no-op. */
157+
ct = nf_ct_get(skb, &ctinfo);
158+
if (!ct)
159+
return 0;
160+
161+
new_mark = ct_mark | (ct->mark & ~(mask));
162+
if (ct->mark != new_mark) {
163+
ct->mark = new_mark;
164+
nf_conntrack_event_cache(IPCT_MARK, ct);
165+
key->ct.mark = new_mark;
166+
}
167+
130168
return 0;
131169
}
132170

@@ -247,7 +285,7 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
247285
u8 state;
248286

249287
state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED;
250-
__ovs_ct_update_key(key, state, &info->zone);
288+
__ovs_ct_update_key(key, state, &info->zone, exp->master);
251289
} else {
252290
int err;
253291

@@ -310,7 +348,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
310348
err = ovs_ct_commit(net, key, info, skb);
311349
else
312350
err = ovs_ct_lookup(net, key, info, skb);
351+
if (err)
352+
goto err;
313353

354+
if (info->mark.mask)
355+
err = ovs_ct_set_mark(skb, key, info->mark.value,
356+
info->mark.mask);
357+
err:
314358
skb_push(skb, nh_ofs);
315359
return err;
316360
}
@@ -320,6 +364,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
320364
.maxlen = sizeof(u32) },
321365
[OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16),
322366
.maxlen = sizeof(u16) },
367+
[OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark),
368+
.maxlen = sizeof(struct md_mark) },
323369
};
324370

325371
static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
@@ -354,6 +400,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
354400
case OVS_CT_ATTR_ZONE:
355401
info->zone.id = nla_get_u16(a);
356402
break;
403+
#endif
404+
#ifdef CONFIG_NF_CONNTRACK_MARK
405+
case OVS_CT_ATTR_MARK: {
406+
struct md_mark *mark = nla_data(a);
407+
408+
info->mark = *mark;
409+
break;
410+
}
357411
#endif
358412
default:
359413
OVS_NLERR(log, "Unknown conntrack attr (%d)",
@@ -377,6 +431,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr)
377431
if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
378432
attr == OVS_KEY_ATTR_CT_ZONE)
379433
return true;
434+
if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
435+
attr == OVS_KEY_ATTR_CT_MARK)
436+
return true;
380437

381438
return false;
382439
}
@@ -439,6 +496,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
439496
if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
440497
nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
441498
return -EMSGSIZE;
499+
if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
500+
nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark),
501+
&ct_info->mark))
502+
return -EMSGSIZE;
442503

443504
nla_nest_end(skb, start);
444505

net/openvswitch/conntrack.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb,
6565
{
6666
key->ct.state = 0;
6767
key->ct.zone = 0;
68+
key->ct.mark = 0;
6869
}
6970

7071
static inline int ovs_ct_put_key(const struct sw_flow_key *key,

net/openvswitch/flow.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ struct sw_flow_key {
114114
struct {
115115
/* Connection tracking fields. */
116116
u16 zone;
117+
u32 mark;
117118
u8 state;
118119
} ct;
119120

net/openvswitch/flow_netlink.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void)
281281
/* Whenever adding new OVS_KEY_ FIELDS, we should consider
282282
* updating this function.
283283
*/
284-
BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24);
284+
BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 25);
285285

286286
return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
287287
+ nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
@@ -292,6 +292,7 @@ size_t ovs_key_attr_size(void)
292292
+ nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
293293
+ nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */
294294
+ nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
295+
+ nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
295296
+ nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
296297
+ nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
297298
+ nla_total_size(4) /* OVS_KEY_ATTR_VLAN */
@@ -343,6 +344,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
343344
[OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
344345
[OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) },
345346
[OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
347+
[OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) },
346348
};
347349

348350
static bool is_all_zero(const u8 *fp, size_t size)
@@ -787,6 +789,13 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs,
787789
SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);
788790
*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
789791
}
792+
if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) &&
793+
ovs_ct_verify(OVS_KEY_ATTR_CT_MARK)) {
794+
u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]);
795+
796+
SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask);
797+
*attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK);
798+
}
790799
return 0;
791800
}
792801

@@ -1919,6 +1928,7 @@ static int validate_set(const struct nlattr *a,
19191928

19201929
case OVS_KEY_ATTR_PRIORITY:
19211930
case OVS_KEY_ATTR_SKB_MARK:
1931+
case OVS_KEY_ATTR_CT_MARK:
19221932
case OVS_KEY_ATTR_ETHERNET:
19231933
break;
19241934

0 commit comments

Comments
 (0)