History

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.

Joe Stringer committed 11 years ago

Commit 182e3041 parent 7f8a4366 files · +83 −4Browse files

Unified · Split

6 files
  1. include/uapi/linux/openvswitch.h +5 −0
  2. net/openvswitch/actions.c +1 −0
  3. net/openvswitch/conntrack.c +64 −3
  4. net/openvswitch/conntrack.h +1 −0
  5. net/openvswitch/flow.h +1 −0
  6. net/openvswitch/flow_netlink.c +11 −1
include/uapi/linux/openvswitch.h+5−0
@@ -325,6 +325,7 @@ enum ovs_key_attr { · 324 unmodified lines
325 * the accepted length of the array. */325 * the accepted length of the array. */
326 OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */326 OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */
327 OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */327 OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */
328 OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */
328 329
329#ifdef __KERNEL__330#ifdef __KERNEL__
330 OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */331 OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */
@@ -613,11 +614,15 @@ struct ovs_action_hash { · 282 unmodified lines
613 * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.614 * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action.
614 * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags.615 * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags.
615 * @OVS_CT_ATTR_ZONE: u16 connection tracking zone.616 * @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.
616 */620 */
617enum ovs_ct_attr {621enum ovs_ct_attr {
618 OVS_CT_ATTR_UNSPEC,622 OVS_CT_ATTR_UNSPEC,
619 OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */623 OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */
620 OVS_CT_ATTR_ZONE, /* u16 zone id. */624 OVS_CT_ATTR_ZONE, /* u16 zone id. */
625 OVS_CT_ATTR_MARK, /* mark to associate with this connection. */
621 __OVS_CT_ATTR_MAX626 __OVS_CT_ATTR_MAX
622};627};
623 628
net/openvswitch/actions.c+1−0
@@ -968,6 +968,7 @@ static int execute_masked_set_action(struct sk_buff *skb, · 967 unmodified lines
968 968
969 case OVS_KEY_ATTR_CT_STATE:969 case OVS_KEY_ATTR_CT_STATE:
970 case OVS_KEY_ATTR_CT_ZONE:970 case OVS_KEY_ATTR_CT_ZONE:
971 case OVS_KEY_ATTR_CT_MARK:
971 err = -EINVAL;972 err = -EINVAL;
972 break;973 break;
973 }974 }
net/openvswitch/conntrack.c+64−3
@@ -28,12 +28,19 @@ struct ovs_ct_len_tbl { · 27 unmodified lines
28 size_t minlen;28 size_t minlen;
29};29};
30 30
31/* Metadata mark for masked write to conntrack mark */
32struct md_mark {
33 u32 value;
34 u32 mask;
35};
36
31/* Conntrack action context for execution. */37/* Conntrack action context for execution. */
32struct ovs_conntrack_info {38struct ovs_conntrack_info {
33 struct nf_conntrack_zone zone;39 struct nf_conntrack_zone zone;
34 struct nf_conn *ct;40 struct nf_conn *ct;
35 u32 flags;41 u32 flags;
36 u16 family;42 u16 family;
43 struct md_mark mark;
37};44};
38 45
39static u16 key_to_nfproto(const struct sw_flow_key *key)46static 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) · 44 unmodified lines
84}91}
85 92
86static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,93static 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)
88{96{
89 key->ct.state = state;97 key->ct.state = state;
90 key->ct.zone = zone->id;98 key->ct.zone = zone->id;
99 key->ct.mark = ct ? ct->mark : 0;
91}100}
92 101
93/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has102/* 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, · 16 unmodified lines
110 } else if (post_ct) {119 } else if (post_ct) {
111 state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;120 state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
112 }121 }
113 __ovs_ct_update_key(key, state, zone);122 __ovs_ct_update_key(key, state, zone, ct);
114}123}
115 124
116void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)125void 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) · 10 unmodified lines
127 nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone))136 nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone))
128 return -EMSGSIZE;137 return -EMSGSIZE;
129 138
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
146static 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
130 return 0;168 return 0;
131}169}
132 170
@@ -247,7 +285,7 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, · 114 unmodified lines
247 u8 state;285 u8 state;
248 286
249 state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED;287 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);
251 } else {289 } else {
252 int err;290 int err;
253 291
@@ -310,7 +348,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, · 56 unmodified lines
310 err = ovs_ct_commit(net, key, info, skb);348 err = ovs_ct_commit(net, key, info, skb);
311 else349 else
312 err = ovs_ct_lookup(net, key, info, skb);350 err = ovs_ct_lookup(net, key, info, skb);
351 if (err)
352 goto err;
313 353
354 if (info->mark.mask)
355 err = ovs_ct_set_mark(skb, key, info->mark.value,
356 info->mark.mask);
357err:
314 skb_push(skb, nh_ofs);358 skb_push(skb, nh_ofs);
315 return err;359 return err;
316}360}
@@ -320,6 +364,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { · 3 unmodified lines
320 .maxlen = sizeof(u32) },364 .maxlen = sizeof(u32) },
321 [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16),365 [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16),
322 .maxlen = sizeof(u16) },366 .maxlen = sizeof(u16) },
367 [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark),
368 .maxlen = sizeof(struct md_mark) },
323};369};
324 370
325static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,371static 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, · 28 unmodified lines
354 case OVS_CT_ATTR_ZONE:400 case OVS_CT_ATTR_ZONE:
355 info->zone.id = nla_get_u16(a);401 info->zone.id = nla_get_u16(a);
356 break;402 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 }
357#endif411#endif
358 default:412 default:
359 OVS_NLERR(log, "Unknown conntrack attr (%d)",413 OVS_NLERR(log, "Unknown conntrack attr (%d)",
@@ -377,6 +431,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr) · 17 unmodified lines
377 if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&431 if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
378 attr == OVS_KEY_ATTR_CT_ZONE)432 attr == OVS_KEY_ATTR_CT_ZONE)
379 return true;433 return true;
434 if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
435 attr == OVS_KEY_ATTR_CT_MARK)
436 return true;
380 437
381 return false;438 return false;
382}439}
@@ -439,6 +496,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, · 56 unmodified lines
439 if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&496 if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
440 nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))497 nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
441 return -EMSGSIZE;498 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;
442 503
443 nla_nest_end(skb, start);504 nla_nest_end(skb, start);
444 505
net/openvswitch/conntrack.h+1−0
@@ -65,6 +65,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb, · 64 unmodified lines
65{65{
66 key->ct.state = 0;66 key->ct.state = 0;
67 key->ct.zone = 0;67 key->ct.zone = 0;
68 key->ct.mark = 0;
68}69}
69 70
70static inline int ovs_ct_put_key(const struct sw_flow_key *key,71static inline int ovs_ct_put_key(const struct sw_flow_key *key,
net/openvswitch/flow.h+1−0
@@ -114,6 +114,7 @@ struct sw_flow_key { · 113 unmodified lines
114 struct {114 struct {
115 /* Connection tracking fields. */115 /* Connection tracking fields. */
116 u16 zone;116 u16 zone;
117 u32 mark;
117 u8 state;118 u8 state;
118 } ct;119 } ct;
119 120
net/openvswitch/flow_netlink.c+11−1
@@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void) · 280 unmodified lines
281 /* Whenever adding new OVS_KEY_ FIELDS, we should consider281 /* Whenever adding new OVS_KEY_ FIELDS, we should consider
282 * updating this function.282 * updating this function.
283 */283 */
284 BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24);284 BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 25);
285 285
286 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */286 return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */
287 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */287 + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */
@@ -292,6 +292,7 @@ size_t ovs_key_attr_size(void) · 4 unmodified lines
292 + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */292 + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */
293 + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */293 + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */
294 + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */294 + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */
295 + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */
295 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */296 + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */
296 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */297 + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */
297 + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */298 + 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] = { · 45 unmodified lines
343 [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },344 [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) },
344 [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) },345 [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) },
345 [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },346 [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) },
347 [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) },
346};348};
347 349
348static bool is_all_zero(const u8 *fp, size_t size)350static 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, · 438 unmodified lines
787 SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);789 SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask);
788 *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);790 *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE);
789 }791 }
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 }
790 return 0;799 return 0;
791}800}
792 801
@@ -1919,6 +1928,7 @@ static int validate_set(const struct nlattr *a, · 1126 unmodified lines
1919 1928
1920 case OVS_KEY_ATTR_PRIORITY:1929 case OVS_KEY_ATTR_PRIORITY:
1921 case OVS_KEY_ATTR_SKB_MARK:1930 case OVS_KEY_ATTR_SKB_MARK:
1931 case OVS_KEY_ATTR_CT_MARK:
1922 case OVS_KEY_ATTR_ETHERNET:1932 case OVS_KEY_ATTR_ETHERNET:
1923 break;1933 break;
1924 1934