xref: /openbmc/linux/net/openvswitch/conntrack.c (revision a8fe58ce)
1 /*
2  * Copyright (c) 2015 Nicira, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of version 2 of the GNU General Public
6  * License as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * General Public License for more details.
12  */
13 
14 #include <linux/module.h>
15 #include <linux/openvswitch.h>
16 #include <net/ip.h>
17 #include <net/netfilter/nf_conntrack_core.h>
18 #include <net/netfilter/nf_conntrack_helper.h>
19 #include <net/netfilter/nf_conntrack_labels.h>
20 #include <net/netfilter/nf_conntrack_zones.h>
21 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
22 
23 #include "datapath.h"
24 #include "conntrack.h"
25 #include "flow.h"
26 #include "flow_netlink.h"
27 
28 struct ovs_ct_len_tbl {
29 	size_t maxlen;
30 	size_t minlen;
31 };
32 
33 /* Metadata mark for masked write to conntrack mark */
34 struct md_mark {
35 	u32 value;
36 	u32 mask;
37 };
38 
39 /* Metadata label for masked write to conntrack label. */
40 struct md_labels {
41 	struct ovs_key_ct_labels value;
42 	struct ovs_key_ct_labels mask;
43 };
44 
45 /* Conntrack action context for execution. */
46 struct ovs_conntrack_info {
47 	struct nf_conntrack_helper *helper;
48 	struct nf_conntrack_zone zone;
49 	struct nf_conn *ct;
50 	u8 commit : 1;
51 	u16 family;
52 	struct md_mark mark;
53 	struct md_labels labels;
54 };
55 
56 static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info);
57 
58 static u16 key_to_nfproto(const struct sw_flow_key *key)
59 {
60 	switch (ntohs(key->eth.type)) {
61 	case ETH_P_IP:
62 		return NFPROTO_IPV4;
63 	case ETH_P_IPV6:
64 		return NFPROTO_IPV6;
65 	default:
66 		return NFPROTO_UNSPEC;
67 	}
68 }
69 
70 /* Map SKB connection state into the values used by flow definition. */
71 static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo)
72 {
73 	u8 ct_state = OVS_CS_F_TRACKED;
74 
75 	switch (ctinfo) {
76 	case IP_CT_ESTABLISHED_REPLY:
77 	case IP_CT_RELATED_REPLY:
78 	case IP_CT_NEW_REPLY:
79 		ct_state |= OVS_CS_F_REPLY_DIR;
80 		break;
81 	default:
82 		break;
83 	}
84 
85 	switch (ctinfo) {
86 	case IP_CT_ESTABLISHED:
87 	case IP_CT_ESTABLISHED_REPLY:
88 		ct_state |= OVS_CS_F_ESTABLISHED;
89 		break;
90 	case IP_CT_RELATED:
91 	case IP_CT_RELATED_REPLY:
92 		ct_state |= OVS_CS_F_RELATED;
93 		break;
94 	case IP_CT_NEW:
95 	case IP_CT_NEW_REPLY:
96 		ct_state |= OVS_CS_F_NEW;
97 		break;
98 	default:
99 		break;
100 	}
101 
102 	return ct_state;
103 }
104 
105 static u32 ovs_ct_get_mark(const struct nf_conn *ct)
106 {
107 #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
108 	return ct ? ct->mark : 0;
109 #else
110 	return 0;
111 #endif
112 }
113 
114 static void ovs_ct_get_labels(const struct nf_conn *ct,
115 			      struct ovs_key_ct_labels *labels)
116 {
117 	struct nf_conn_labels *cl = ct ? nf_ct_labels_find(ct) : NULL;
118 
119 	if (cl) {
120 		size_t len = cl->words * sizeof(long);
121 
122 		if (len > OVS_CT_LABELS_LEN)
123 			len = OVS_CT_LABELS_LEN;
124 		else if (len < OVS_CT_LABELS_LEN)
125 			memset(labels, 0, OVS_CT_LABELS_LEN);
126 		memcpy(labels, cl->bits, len);
127 	} else {
128 		memset(labels, 0, OVS_CT_LABELS_LEN);
129 	}
130 }
131 
132 static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
133 				const struct nf_conntrack_zone *zone,
134 				const struct nf_conn *ct)
135 {
136 	key->ct.state = state;
137 	key->ct.zone = zone->id;
138 	key->ct.mark = ovs_ct_get_mark(ct);
139 	ovs_ct_get_labels(ct, &key->ct.labels);
140 }
141 
142 /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has
143  * previously sent the packet to conntrack via the ct action.
144  */
145 static void ovs_ct_update_key(const struct sk_buff *skb,
146 			      const struct ovs_conntrack_info *info,
147 			      struct sw_flow_key *key, bool post_ct)
148 {
149 	const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
150 	enum ip_conntrack_info ctinfo;
151 	struct nf_conn *ct;
152 	u8 state = 0;
153 
154 	ct = nf_ct_get(skb, &ctinfo);
155 	if (ct) {
156 		state = ovs_ct_get_state(ctinfo);
157 		if (!nf_ct_is_confirmed(ct))
158 			state |= OVS_CS_F_NEW;
159 		if (ct->master)
160 			state |= OVS_CS_F_RELATED;
161 		zone = nf_ct_zone(ct);
162 	} else if (post_ct) {
163 		state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
164 		if (info)
165 			zone = &info->zone;
166 	}
167 	__ovs_ct_update_key(key, state, zone, ct);
168 }
169 
170 void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
171 {
172 	ovs_ct_update_key(skb, NULL, key, false);
173 }
174 
175 int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
176 {
177 	if (nla_put_u32(skb, OVS_KEY_ATTR_CT_STATE, key->ct.state))
178 		return -EMSGSIZE;
179 
180 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
181 	    nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone))
182 		return -EMSGSIZE;
183 
184 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
185 	    nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark))
186 		return -EMSGSIZE;
187 
188 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
189 	    nla_put(skb, OVS_KEY_ATTR_CT_LABELS, sizeof(key->ct.labels),
190 		    &key->ct.labels))
191 		return -EMSGSIZE;
192 
193 	return 0;
194 }
195 
196 static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key,
197 			   u32 ct_mark, u32 mask)
198 {
199 #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
200 	enum ip_conntrack_info ctinfo;
201 	struct nf_conn *ct;
202 	u32 new_mark;
203 
204 
205 	/* The connection could be invalid, in which case set_mark is no-op. */
206 	ct = nf_ct_get(skb, &ctinfo);
207 	if (!ct)
208 		return 0;
209 
210 	new_mark = ct_mark | (ct->mark & ~(mask));
211 	if (ct->mark != new_mark) {
212 		ct->mark = new_mark;
213 		nf_conntrack_event_cache(IPCT_MARK, ct);
214 		key->ct.mark = new_mark;
215 	}
216 
217 	return 0;
218 #else
219 	return -ENOTSUPP;
220 #endif
221 }
222 
223 static int ovs_ct_set_labels(struct sk_buff *skb, struct sw_flow_key *key,
224 			     const struct ovs_key_ct_labels *labels,
225 			     const struct ovs_key_ct_labels *mask)
226 {
227 	enum ip_conntrack_info ctinfo;
228 	struct nf_conn_labels *cl;
229 	struct nf_conn *ct;
230 	int err;
231 
232 	/* The connection could be invalid, in which case set_label is no-op.*/
233 	ct = nf_ct_get(skb, &ctinfo);
234 	if (!ct)
235 		return 0;
236 
237 	cl = nf_ct_labels_find(ct);
238 	if (!cl) {
239 		nf_ct_labels_ext_add(ct);
240 		cl = nf_ct_labels_find(ct);
241 	}
242 	if (!cl || cl->words * sizeof(long) < OVS_CT_LABELS_LEN)
243 		return -ENOSPC;
244 
245 	err = nf_connlabels_replace(ct, (u32 *)labels, (u32 *)mask,
246 				    OVS_CT_LABELS_LEN / sizeof(u32));
247 	if (err)
248 		return err;
249 
250 	ovs_ct_get_labels(ct, &key->ct.labels);
251 	return 0;
252 }
253 
254 /* 'skb' should already be pulled to nh_ofs. */
255 static int ovs_ct_helper(struct sk_buff *skb, u16 proto)
256 {
257 	const struct nf_conntrack_helper *helper;
258 	const struct nf_conn_help *help;
259 	enum ip_conntrack_info ctinfo;
260 	unsigned int protoff;
261 	struct nf_conn *ct;
262 
263 	ct = nf_ct_get(skb, &ctinfo);
264 	if (!ct || ctinfo == IP_CT_RELATED_REPLY)
265 		return NF_ACCEPT;
266 
267 	help = nfct_help(ct);
268 	if (!help)
269 		return NF_ACCEPT;
270 
271 	helper = rcu_dereference(help->helper);
272 	if (!helper)
273 		return NF_ACCEPT;
274 
275 	switch (proto) {
276 	case NFPROTO_IPV4:
277 		protoff = ip_hdrlen(skb);
278 		break;
279 	case NFPROTO_IPV6: {
280 		u8 nexthdr = ipv6_hdr(skb)->nexthdr;
281 		__be16 frag_off;
282 		int ofs;
283 
284 		ofs = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
285 				       &frag_off);
286 		if (ofs < 0 || (frag_off & htons(~0x7)) != 0) {
287 			pr_debug("proto header not found\n");
288 			return NF_ACCEPT;
289 		}
290 		protoff = ofs;
291 		break;
292 	}
293 	default:
294 		WARN_ONCE(1, "helper invoked on non-IP family!");
295 		return NF_DROP;
296 	}
297 
298 	return helper->help(skb, protoff, ct, ctinfo);
299 }
300 
301 /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
302  * value if 'skb' is freed.
303  */
304 static int handle_fragments(struct net *net, struct sw_flow_key *key,
305 			    u16 zone, struct sk_buff *skb)
306 {
307 	struct ovs_skb_cb ovs_cb = *OVS_CB(skb);
308 	int err;
309 
310 	if (key->eth.type == htons(ETH_P_IP)) {
311 		enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone;
312 
313 		memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
314 		err = ip_defrag(net, skb, user);
315 		if (err)
316 			return err;
317 
318 		ovs_cb.mru = IPCB(skb)->frag_max_size;
319 #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
320 	} else if (key->eth.type == htons(ETH_P_IPV6)) {
321 		enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone;
322 
323 		memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
324 		err = nf_ct_frag6_gather(net, skb, user);
325 		if (err)
326 			return err;
327 
328 		key->ip.proto = ipv6_hdr(skb)->nexthdr;
329 		ovs_cb.mru = IP6CB(skb)->frag_max_size;
330 #endif
331 	} else {
332 		kfree_skb(skb);
333 		return -EPFNOSUPPORT;
334 	}
335 
336 	key->ip.frag = OVS_FRAG_TYPE_NONE;
337 	skb_clear_hash(skb);
338 	skb->ignore_df = 1;
339 	*OVS_CB(skb) = ovs_cb;
340 
341 	return 0;
342 }
343 
344 static struct nf_conntrack_expect *
345 ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone,
346 		   u16 proto, const struct sk_buff *skb)
347 {
348 	struct nf_conntrack_tuple tuple;
349 
350 	if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, net, &tuple))
351 		return NULL;
352 	return __nf_ct_expect_find(net, zone, &tuple);
353 }
354 
355 /* Determine whether skb->nfct is equal to the result of conntrack lookup. */
356 static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb,
357 			    const struct ovs_conntrack_info *info)
358 {
359 	enum ip_conntrack_info ctinfo;
360 	struct nf_conn *ct;
361 
362 	ct = nf_ct_get(skb, &ctinfo);
363 	if (!ct)
364 		return false;
365 	if (!net_eq(net, read_pnet(&ct->ct_net)))
366 		return false;
367 	if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct)))
368 		return false;
369 	if (info->helper) {
370 		struct nf_conn_help *help;
371 
372 		help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
373 		if (help && rcu_access_pointer(help->helper) != info->helper)
374 			return false;
375 	}
376 
377 	return true;
378 }
379 
380 static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
381 			   const struct ovs_conntrack_info *info,
382 			   struct sk_buff *skb)
383 {
384 	/* If we are recirculating packets to match on conntrack fields and
385 	 * committing with a separate conntrack action,  then we don't need to
386 	 * actually run the packet through conntrack twice unless it's for a
387 	 * different zone.
388 	 */
389 	if (!skb_nfct_cached(net, skb, info)) {
390 		struct nf_conn *tmpl = info->ct;
391 
392 		/* Associate skb with specified zone. */
393 		if (tmpl) {
394 			if (skb->nfct)
395 				nf_conntrack_put(skb->nfct);
396 			nf_conntrack_get(&tmpl->ct_general);
397 			skb->nfct = &tmpl->ct_general;
398 			skb->nfctinfo = IP_CT_NEW;
399 		}
400 
401 		if (nf_conntrack_in(net, info->family, NF_INET_PRE_ROUTING,
402 				    skb) != NF_ACCEPT)
403 			return -ENOENT;
404 
405 		if (ovs_ct_helper(skb, info->family) != NF_ACCEPT) {
406 			WARN_ONCE(1, "helper rejected packet");
407 			return -EINVAL;
408 		}
409 	}
410 
411 	ovs_ct_update_key(skb, info, key, true);
412 
413 	return 0;
414 }
415 
416 /* Lookup connection and read fields into key. */
417 static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
418 			 const struct ovs_conntrack_info *info,
419 			 struct sk_buff *skb)
420 {
421 	struct nf_conntrack_expect *exp;
422 
423 	exp = ovs_ct_expect_find(net, &info->zone, info->family, skb);
424 	if (exp) {
425 		u8 state;
426 
427 		state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED;
428 		__ovs_ct_update_key(key, state, &info->zone, exp->master);
429 	} else {
430 		int err;
431 
432 		err = __ovs_ct_lookup(net, key, info, skb);
433 		if (err)
434 			return err;
435 	}
436 
437 	return 0;
438 }
439 
440 /* Lookup connection and confirm if unconfirmed. */
441 static int ovs_ct_commit(struct net *net, struct sw_flow_key *key,
442 			 const struct ovs_conntrack_info *info,
443 			 struct sk_buff *skb)
444 {
445 	u8 state;
446 	int err;
447 
448 	state = key->ct.state;
449 	if (key->ct.zone == info->zone.id &&
450 	    ((state & OVS_CS_F_TRACKED) && !(state & OVS_CS_F_NEW))) {
451 		/* Previous lookup has shown that this connection is already
452 		 * tracked and committed. Skip committing.
453 		 */
454 		return 0;
455 	}
456 
457 	err = __ovs_ct_lookup(net, key, info, skb);
458 	if (err)
459 		return err;
460 	if (nf_conntrack_confirm(skb) != NF_ACCEPT)
461 		return -EINVAL;
462 
463 	return 0;
464 }
465 
466 static bool labels_nonzero(const struct ovs_key_ct_labels *labels)
467 {
468 	size_t i;
469 
470 	for (i = 0; i < sizeof(*labels); i++)
471 		if (labels->ct_labels[i])
472 			return true;
473 
474 	return false;
475 }
476 
477 /* Returns 0 on success, -EINPROGRESS if 'skb' is stolen, or other nonzero
478  * value if 'skb' is freed.
479  */
480 int ovs_ct_execute(struct net *net, struct sk_buff *skb,
481 		   struct sw_flow_key *key,
482 		   const struct ovs_conntrack_info *info)
483 {
484 	int nh_ofs;
485 	int err;
486 
487 	/* The conntrack module expects to be working at L3. */
488 	nh_ofs = skb_network_offset(skb);
489 	skb_pull(skb, nh_ofs);
490 
491 	if (key->ip.frag != OVS_FRAG_TYPE_NONE) {
492 		err = handle_fragments(net, key, info->zone.id, skb);
493 		if (err)
494 			return err;
495 	}
496 
497 	if (info->commit)
498 		err = ovs_ct_commit(net, key, info, skb);
499 	else
500 		err = ovs_ct_lookup(net, key, info, skb);
501 	if (err)
502 		goto err;
503 
504 	if (info->mark.mask) {
505 		err = ovs_ct_set_mark(skb, key, info->mark.value,
506 				      info->mark.mask);
507 		if (err)
508 			goto err;
509 	}
510 	if (labels_nonzero(&info->labels.mask))
511 		err = ovs_ct_set_labels(skb, key, &info->labels.value,
512 					&info->labels.mask);
513 err:
514 	skb_push(skb, nh_ofs);
515 	if (err)
516 		kfree_skb(skb);
517 	return err;
518 }
519 
520 static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name,
521 			     const struct sw_flow_key *key, bool log)
522 {
523 	struct nf_conntrack_helper *helper;
524 	struct nf_conn_help *help;
525 
526 	helper = nf_conntrack_helper_try_module_get(name, info->family,
527 						    key->ip.proto);
528 	if (!helper) {
529 		OVS_NLERR(log, "Unknown helper \"%s\"", name);
530 		return -EINVAL;
531 	}
532 
533 	help = nf_ct_helper_ext_add(info->ct, helper, GFP_KERNEL);
534 	if (!help) {
535 		module_put(helper->me);
536 		return -ENOMEM;
537 	}
538 
539 	rcu_assign_pointer(help->helper, helper);
540 	info->helper = helper;
541 	return 0;
542 }
543 
544 static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = {
545 	[OVS_CT_ATTR_COMMIT]	= { .minlen = 0, .maxlen = 0 },
546 	[OVS_CT_ATTR_ZONE]	= { .minlen = sizeof(u16),
547 				    .maxlen = sizeof(u16) },
548 	[OVS_CT_ATTR_MARK]	= { .minlen = sizeof(struct md_mark),
549 				    .maxlen = sizeof(struct md_mark) },
550 	[OVS_CT_ATTR_LABELS]	= { .minlen = sizeof(struct md_labels),
551 				    .maxlen = sizeof(struct md_labels) },
552 	[OVS_CT_ATTR_HELPER]	= { .minlen = 1,
553 				    .maxlen = NF_CT_HELPER_NAME_LEN }
554 };
555 
556 static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
557 		    const char **helper, bool log)
558 {
559 	struct nlattr *a;
560 	int rem;
561 
562 	nla_for_each_nested(a, attr, rem) {
563 		int type = nla_type(a);
564 		int maxlen = ovs_ct_attr_lens[type].maxlen;
565 		int minlen = ovs_ct_attr_lens[type].minlen;
566 
567 		if (type > OVS_CT_ATTR_MAX) {
568 			OVS_NLERR(log,
569 				  "Unknown conntrack attr (type=%d, max=%d)",
570 				  type, OVS_CT_ATTR_MAX);
571 			return -EINVAL;
572 		}
573 		if (nla_len(a) < minlen || nla_len(a) > maxlen) {
574 			OVS_NLERR(log,
575 				  "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)",
576 				  type, nla_len(a), maxlen);
577 			return -EINVAL;
578 		}
579 
580 		switch (type) {
581 		case OVS_CT_ATTR_COMMIT:
582 			info->commit = true;
583 			break;
584 #ifdef CONFIG_NF_CONNTRACK_ZONES
585 		case OVS_CT_ATTR_ZONE:
586 			info->zone.id = nla_get_u16(a);
587 			break;
588 #endif
589 #ifdef CONFIG_NF_CONNTRACK_MARK
590 		case OVS_CT_ATTR_MARK: {
591 			struct md_mark *mark = nla_data(a);
592 
593 			if (!mark->mask) {
594 				OVS_NLERR(log, "ct_mark mask cannot be 0");
595 				return -EINVAL;
596 			}
597 			info->mark = *mark;
598 			break;
599 		}
600 #endif
601 #ifdef CONFIG_NF_CONNTRACK_LABELS
602 		case OVS_CT_ATTR_LABELS: {
603 			struct md_labels *labels = nla_data(a);
604 
605 			if (!labels_nonzero(&labels->mask)) {
606 				OVS_NLERR(log, "ct_labels mask cannot be 0");
607 				return -EINVAL;
608 			}
609 			info->labels = *labels;
610 			break;
611 		}
612 #endif
613 		case OVS_CT_ATTR_HELPER:
614 			*helper = nla_data(a);
615 			if (!memchr(*helper, '\0', nla_len(a))) {
616 				OVS_NLERR(log, "Invalid conntrack helper");
617 				return -EINVAL;
618 			}
619 			break;
620 		default:
621 			OVS_NLERR(log, "Unknown conntrack attr (%d)",
622 				  type);
623 			return -EINVAL;
624 		}
625 	}
626 
627 	if (rem > 0) {
628 		OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem);
629 		return -EINVAL;
630 	}
631 
632 	return 0;
633 }
634 
635 bool ovs_ct_verify(struct net *net, enum ovs_key_attr attr)
636 {
637 	if (attr == OVS_KEY_ATTR_CT_STATE)
638 		return true;
639 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
640 	    attr == OVS_KEY_ATTR_CT_ZONE)
641 		return true;
642 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) &&
643 	    attr == OVS_KEY_ATTR_CT_MARK)
644 		return true;
645 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
646 	    attr == OVS_KEY_ATTR_CT_LABELS) {
647 		struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
648 
649 		return ovs_net->xt_label;
650 	}
651 
652 	return false;
653 }
654 
655 int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
656 		       const struct sw_flow_key *key,
657 		       struct sw_flow_actions **sfa,  bool log)
658 {
659 	struct ovs_conntrack_info ct_info;
660 	const char *helper = NULL;
661 	u16 family;
662 	int err;
663 
664 	family = key_to_nfproto(key);
665 	if (family == NFPROTO_UNSPEC) {
666 		OVS_NLERR(log, "ct family unspecified");
667 		return -EINVAL;
668 	}
669 
670 	memset(&ct_info, 0, sizeof(ct_info));
671 	ct_info.family = family;
672 
673 	nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID,
674 			NF_CT_DEFAULT_ZONE_DIR, 0);
675 
676 	err = parse_ct(attr, &ct_info, &helper, log);
677 	if (err)
678 		return err;
679 
680 	/* Set up template for tracking connections in specific zones. */
681 	ct_info.ct = nf_ct_tmpl_alloc(net, &ct_info.zone, GFP_KERNEL);
682 	if (!ct_info.ct) {
683 		OVS_NLERR(log, "Failed to allocate conntrack template");
684 		return -ENOMEM;
685 	}
686 
687 	__set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
688 	nf_conntrack_get(&ct_info.ct->ct_general);
689 
690 	if (helper) {
691 		err = ovs_ct_add_helper(&ct_info, helper, key, log);
692 		if (err)
693 			goto err_free_ct;
694 	}
695 
696 	err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info,
697 				 sizeof(ct_info), log);
698 	if (err)
699 		goto err_free_ct;
700 
701 	return 0;
702 err_free_ct:
703 	__ovs_ct_free_action(&ct_info);
704 	return err;
705 }
706 
707 int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info,
708 			  struct sk_buff *skb)
709 {
710 	struct nlattr *start;
711 
712 	start = nla_nest_start(skb, OVS_ACTION_ATTR_CT);
713 	if (!start)
714 		return -EMSGSIZE;
715 
716 	if (ct_info->commit && nla_put_flag(skb, OVS_CT_ATTR_COMMIT))
717 		return -EMSGSIZE;
718 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) &&
719 	    nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id))
720 		return -EMSGSIZE;
721 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && ct_info->mark.mask &&
722 	    nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark),
723 		    &ct_info->mark))
724 		return -EMSGSIZE;
725 	if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) &&
726 	    labels_nonzero(&ct_info->labels.mask) &&
727 	    nla_put(skb, OVS_CT_ATTR_LABELS, sizeof(ct_info->labels),
728 		    &ct_info->labels))
729 		return -EMSGSIZE;
730 	if (ct_info->helper) {
731 		if (nla_put_string(skb, OVS_CT_ATTR_HELPER,
732 				   ct_info->helper->name))
733 			return -EMSGSIZE;
734 	}
735 
736 	nla_nest_end(skb, start);
737 
738 	return 0;
739 }
740 
741 void ovs_ct_free_action(const struct nlattr *a)
742 {
743 	struct ovs_conntrack_info *ct_info = nla_data(a);
744 
745 	__ovs_ct_free_action(ct_info);
746 }
747 
748 static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info)
749 {
750 	if (ct_info->helper)
751 		module_put(ct_info->helper->me);
752 	if (ct_info->ct)
753 		nf_ct_put(ct_info->ct);
754 }
755 
756 void ovs_ct_init(struct net *net)
757 {
758 	unsigned int n_bits = sizeof(struct ovs_key_ct_labels) * BITS_PER_BYTE;
759 	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
760 
761 	if (nf_connlabels_get(net, n_bits)) {
762 		ovs_net->xt_label = false;
763 		OVS_NLERR(true, "Failed to set connlabel length");
764 	} else {
765 		ovs_net->xt_label = true;
766 	}
767 }
768 
769 void ovs_ct_exit(struct net *net)
770 {
771 	struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
772 
773 	if (ovs_net->xt_label)
774 		nf_connlabels_put(net);
775 }
776