aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/openvswitch.h5
-rw-r--r--net/openvswitch/actions.c1
-rw-r--r--net/openvswitch/conntrack.c67
-rw-r--r--net/openvswitch/conntrack.h1
-rw-r--r--net/openvswitch/flow.h1
-rw-r--r--net/openvswitch/flow_netlink.c12
6 files changed, 83 insertions, 4 deletions
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 55f599792673..7a185b554343 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -325,6 +325,7 @@ enum ovs_key_attr {
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 {
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_MAX 626 __OVS_CT_ATTR_MAX
622}; 627};
623 628
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 72ca2c491b0a..9741d2c703df 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -968,6 +968,7 @@ static int execute_masked_set_action(struct sk_buff *skb,
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 }
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index 1189fd50f1cf..e53dafccf21f 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -28,12 +28,19 @@ struct ovs_ct_len_tbl {
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)
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 has 102/* 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,
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)
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,
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,
310 err = ovs_ct_commit(net, key, info, skb); 348 err = ovs_ct_commit(net, key, info, skb);
311 else 349 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] = {
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,
@@ -355,6 +401,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
355 info->zone.id = nla_get_u16(a); 401 info->zone.id = nla_get_u16(a);
356 break; 402 break;
357#endif 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 }
411#endif
358 default: 412 default:
359 OVS_NLERR(log, "Unknown conntrack attr (%d)", 413 OVS_NLERR(log, "Unknown conntrack attr (%d)",
360 type); 414 type);
@@ -377,6 +431,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr)
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,
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
diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h
index e812ee64a718..87b289c58978 100644
--- a/net/openvswitch/conntrack.h
+++ b/net/openvswitch/conntrack.h
@@ -65,6 +65,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb,
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,
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 312c7d755b9b..e05e69711ce1 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -114,6 +114,7 @@ struct sw_flow_key {
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
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 4e795b289eb7..b17a4ec348f9 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void)
281 /* Whenever adding new OVS_KEY_ FIELDS, we should consider 281 /* 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)
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] = {
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,
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,
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