Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1/*
  2 *  SR-IPv6 implementation
  3 *
  4 *  Author:
  5 *  David Lebrun <david.lebrun@uclouvain.be>
  6 *
  7 *
  8 *  This program is free software; you can redistribute it and/or
  9 *        modify it under the terms of the GNU General Public License
 10 *        as published by the Free Software Foundation; either version
 11 *        2 of the License, or (at your option) any later version.
 12 */
 13
 14#include <linux/types.h>
 15#include <linux/skbuff.h>
 16#include <linux/net.h>
 17#include <linux/module.h>
 18#include <net/ip.h>
 19#include <net/lwtunnel.h>
 20#include <net/netevent.h>
 21#include <net/netns/generic.h>
 22#include <net/ip6_fib.h>
 23#include <net/route.h>
 24#include <net/seg6.h>
 25#include <linux/seg6.h>
 26#include <linux/seg6_local.h>
 27#include <net/addrconf.h>
 28#include <net/ip6_route.h>
 29#include <net/dst_cache.h>
 30#ifdef CONFIG_IPV6_SEG6_HMAC
 31#include <net/seg6_hmac.h>
 32#endif
 33#include <linux/etherdevice.h>
 34
 35struct seg6_local_lwt;
 36
 37struct seg6_action_desc {
 38	int action;
 39	unsigned long attrs;
 40	int (*input)(struct sk_buff *skb, struct seg6_local_lwt *slwt);
 41	int static_headroom;
 42};
 43
 44struct seg6_local_lwt {
 45	int action;
 46	struct ipv6_sr_hdr *srh;
 47	int table;
 48	struct in_addr nh4;
 49	struct in6_addr nh6;
 50	int iif;
 51	int oif;
 52
 53	int headroom;
 54	struct seg6_action_desc *desc;
 55};
 56
 57static struct seg6_local_lwt *seg6_local_lwtunnel(struct lwtunnel_state *lwt)
 58{
 59	return (struct seg6_local_lwt *)lwt->data;
 60}
 61
 62static struct ipv6_sr_hdr *get_srh(struct sk_buff *skb)
 63{
 64	struct ipv6_sr_hdr *srh;
 65	int len, srhoff = 0;
 66
 67	if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
 68		return NULL;
 69
 70	if (!pskb_may_pull(skb, srhoff + sizeof(*srh)))
 71		return NULL;
 72
 73	srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
 74
 75	len = (srh->hdrlen + 1) << 3;
 76
 77	if (!pskb_may_pull(skb, srhoff + len))
 78		return NULL;
 79
 80	if (!seg6_validate_srh(srh, len))
 81		return NULL;
 82
 83	return srh;
 84}
 85
 86static struct ipv6_sr_hdr *get_and_validate_srh(struct sk_buff *skb)
 87{
 88	struct ipv6_sr_hdr *srh;
 89
 90	srh = get_srh(skb);
 91	if (!srh)
 92		return NULL;
 93
 94	if (srh->segments_left == 0)
 95		return NULL;
 96
 97#ifdef CONFIG_IPV6_SEG6_HMAC
 98	if (!seg6_hmac_validate_skb(skb))
 99		return NULL;
100#endif
101
102	return srh;
103}
104
105static bool decap_and_validate(struct sk_buff *skb, int proto)
106{
107	struct ipv6_sr_hdr *srh;
108	unsigned int off = 0;
109
110	srh = get_srh(skb);
111	if (srh && srh->segments_left > 0)
112		return false;
113
114#ifdef CONFIG_IPV6_SEG6_HMAC
115	if (srh && !seg6_hmac_validate_skb(skb))
116		return false;
117#endif
118
119	if (ipv6_find_hdr(skb, &off, proto, NULL, NULL) < 0)
120		return false;
121
122	if (!pskb_pull(skb, off))
123		return false;
124
125	skb_postpull_rcsum(skb, skb_network_header(skb), off);
126
127	skb_reset_network_header(skb);
128	skb_reset_transport_header(skb);
129	skb->encapsulation = 0;
130
131	return true;
132}
133
134static void advance_nextseg(struct ipv6_sr_hdr *srh, struct in6_addr *daddr)
135{
136	struct in6_addr *addr;
137
138	srh->segments_left--;
139	addr = srh->segments + srh->segments_left;
140	*daddr = *addr;
141}
142
143static void lookup_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr,
144			   u32 tbl_id)
145{
146	struct net *net = dev_net(skb->dev);
147	struct ipv6hdr *hdr = ipv6_hdr(skb);
148	int flags = RT6_LOOKUP_F_HAS_SADDR;
149	struct dst_entry *dst = NULL;
150	struct rt6_info *rt;
151	struct flowi6 fl6;
152
153	fl6.flowi6_iif = skb->dev->ifindex;
154	fl6.daddr = nhaddr ? *nhaddr : hdr->daddr;
155	fl6.saddr = hdr->saddr;
156	fl6.flowlabel = ip6_flowinfo(hdr);
157	fl6.flowi6_mark = skb->mark;
158	fl6.flowi6_proto = hdr->nexthdr;
159
160	if (nhaddr)
161		fl6.flowi6_flags = FLOWI_FLAG_KNOWN_NH;
162
163	if (!tbl_id) {
164		dst = ip6_route_input_lookup(net, skb->dev, &fl6, skb, flags);
165	} else {
166		struct fib6_table *table;
167
168		table = fib6_get_table(net, tbl_id);
169		if (!table)
170			goto out;
171
172		rt = ip6_pol_route(net, table, 0, &fl6, skb, flags);
173		dst = &rt->dst;
174	}
175
176	if (dst && dst->dev->flags & IFF_LOOPBACK && !dst->error) {
177		dst_release(dst);
178		dst = NULL;
179	}
180
181out:
182	if (!dst) {
183		rt = net->ipv6.ip6_blk_hole_entry;
184		dst = &rt->dst;
185		dst_hold(dst);
186	}
187
188	skb_dst_drop(skb);
189	skb_dst_set(skb, dst);
190}
191
192/* regular endpoint function */
193static int input_action_end(struct sk_buff *skb, struct seg6_local_lwt *slwt)
194{
195	struct ipv6_sr_hdr *srh;
196
197	srh = get_and_validate_srh(skb);
198	if (!srh)
199		goto drop;
200
201	advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
202
203	lookup_nexthop(skb, NULL, 0);
204
205	return dst_input(skb);
206
207drop:
208	kfree_skb(skb);
209	return -EINVAL;
210}
211
212/* regular endpoint, and forward to specified nexthop */
213static int input_action_end_x(struct sk_buff *skb, struct seg6_local_lwt *slwt)
214{
215	struct ipv6_sr_hdr *srh;
216
217	srh = get_and_validate_srh(skb);
218	if (!srh)
219		goto drop;
220
221	advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
222
223	lookup_nexthop(skb, &slwt->nh6, 0);
224
225	return dst_input(skb);
226
227drop:
228	kfree_skb(skb);
229	return -EINVAL;
230}
231
232static int input_action_end_t(struct sk_buff *skb, struct seg6_local_lwt *slwt)
233{
234	struct ipv6_sr_hdr *srh;
235
236	srh = get_and_validate_srh(skb);
237	if (!srh)
238		goto drop;
239
240	advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
241
242	lookup_nexthop(skb, NULL, slwt->table);
243
244	return dst_input(skb);
245
246drop:
247	kfree_skb(skb);
248	return -EINVAL;
249}
250
251/* decapsulate and forward inner L2 frame on specified interface */
252static int input_action_end_dx2(struct sk_buff *skb,
253				struct seg6_local_lwt *slwt)
254{
255	struct net *net = dev_net(skb->dev);
256	struct net_device *odev;
257	struct ethhdr *eth;
258
259	if (!decap_and_validate(skb, NEXTHDR_NONE))
260		goto drop;
261
262	if (!pskb_may_pull(skb, ETH_HLEN))
263		goto drop;
264
265	skb_reset_mac_header(skb);
266	eth = (struct ethhdr *)skb->data;
267
268	/* To determine the frame's protocol, we assume it is 802.3. This avoids
269	 * a call to eth_type_trans(), which is not really relevant for our
270	 * use case.
271	 */
272	if (!eth_proto_is_802_3(eth->h_proto))
273		goto drop;
274
275	odev = dev_get_by_index_rcu(net, slwt->oif);
276	if (!odev)
277		goto drop;
278
279	/* As we accept Ethernet frames, make sure the egress device is of
280	 * the correct type.
281	 */
282	if (odev->type != ARPHRD_ETHER)
283		goto drop;
284
285	if (!(odev->flags & IFF_UP) || !netif_carrier_ok(odev))
286		goto drop;
287
288	skb_orphan(skb);
289
290	if (skb_warn_if_lro(skb))
291		goto drop;
292
293	skb_forward_csum(skb);
294
295	if (skb->len - ETH_HLEN > odev->mtu)
296		goto drop;
297
298	skb->dev = odev;
299	skb->protocol = eth->h_proto;
300
301	return dev_queue_xmit(skb);
302
303drop:
304	kfree_skb(skb);
305	return -EINVAL;
306}
307
308/* decapsulate and forward to specified nexthop */
309static int input_action_end_dx6(struct sk_buff *skb,
310				struct seg6_local_lwt *slwt)
311{
312	struct in6_addr *nhaddr = NULL;
313
314	/* this function accepts IPv6 encapsulated packets, with either
315	 * an SRH with SL=0, or no SRH.
316	 */
317
318	if (!decap_and_validate(skb, IPPROTO_IPV6))
319		goto drop;
320
321	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
322		goto drop;
323
324	/* The inner packet is not associated to any local interface,
325	 * so we do not call netif_rx().
326	 *
327	 * If slwt->nh6 is set to ::, then lookup the nexthop for the
328	 * inner packet's DA. Otherwise, use the specified nexthop.
329	 */
330
331	if (!ipv6_addr_any(&slwt->nh6))
332		nhaddr = &slwt->nh6;
333
334	lookup_nexthop(skb, nhaddr, 0);
335
336	return dst_input(skb);
337drop:
338	kfree_skb(skb);
339	return -EINVAL;
340}
341
342static int input_action_end_dx4(struct sk_buff *skb,
343				struct seg6_local_lwt *slwt)
344{
345	struct iphdr *iph;
346	__be32 nhaddr;
347	int err;
348
349	if (!decap_and_validate(skb, IPPROTO_IPIP))
350		goto drop;
351
352	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
353		goto drop;
354
355	skb->protocol = htons(ETH_P_IP);
356
357	iph = ip_hdr(skb);
358
359	nhaddr = slwt->nh4.s_addr ?: iph->daddr;
360
361	skb_dst_drop(skb);
362
363	err = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev);
364	if (err)
365		goto drop;
366
367	return dst_input(skb);
368
369drop:
370	kfree_skb(skb);
371	return -EINVAL;
372}
373
374static int input_action_end_dt6(struct sk_buff *skb,
375				struct seg6_local_lwt *slwt)
376{
377	if (!decap_and_validate(skb, IPPROTO_IPV6))
378		goto drop;
379
380	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
381		goto drop;
382
383	lookup_nexthop(skb, NULL, slwt->table);
384
385	return dst_input(skb);
386
387drop:
388	kfree_skb(skb);
389	return -EINVAL;
390}
391
392/* push an SRH on top of the current one */
393static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
394{
395	struct ipv6_sr_hdr *srh;
396	int err = -EINVAL;
397
398	srh = get_and_validate_srh(skb);
399	if (!srh)
400		goto drop;
401
402	err = seg6_do_srh_inline(skb, slwt->srh);
403	if (err)
404		goto drop;
405
406	ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
407	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
408
409	lookup_nexthop(skb, NULL, 0);
410
411	return dst_input(skb);
412
413drop:
414	kfree_skb(skb);
415	return err;
416}
417
418/* encapsulate within an outer IPv6 header and a specified SRH */
419static int input_action_end_b6_encap(struct sk_buff *skb,
420				     struct seg6_local_lwt *slwt)
421{
422	struct ipv6_sr_hdr *srh;
423	int err = -EINVAL;
424
425	srh = get_and_validate_srh(skb);
426	if (!srh)
427		goto drop;
428
429	advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
430
431	skb_reset_inner_headers(skb);
432	skb->encapsulation = 1;
433
434	err = seg6_do_srh_encap(skb, slwt->srh, IPPROTO_IPV6);
435	if (err)
436		goto drop;
437
438	ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
439	skb_set_transport_header(skb, sizeof(struct ipv6hdr));
440
441	lookup_nexthop(skb, NULL, 0);
442
443	return dst_input(skb);
444
445drop:
446	kfree_skb(skb);
447	return err;
448}
449
450static struct seg6_action_desc seg6_action_table[] = {
451	{
452		.action		= SEG6_LOCAL_ACTION_END,
453		.attrs		= 0,
454		.input		= input_action_end,
455	},
456	{
457		.action		= SEG6_LOCAL_ACTION_END_X,
458		.attrs		= (1 << SEG6_LOCAL_NH6),
459		.input		= input_action_end_x,
460	},
461	{
462		.action		= SEG6_LOCAL_ACTION_END_T,
463		.attrs		= (1 << SEG6_LOCAL_TABLE),
464		.input		= input_action_end_t,
465	},
466	{
467		.action		= SEG6_LOCAL_ACTION_END_DX2,
468		.attrs		= (1 << SEG6_LOCAL_OIF),
469		.input		= input_action_end_dx2,
470	},
471	{
472		.action		= SEG6_LOCAL_ACTION_END_DX6,
473		.attrs		= (1 << SEG6_LOCAL_NH6),
474		.input		= input_action_end_dx6,
475	},
476	{
477		.action		= SEG6_LOCAL_ACTION_END_DX4,
478		.attrs		= (1 << SEG6_LOCAL_NH4),
479		.input		= input_action_end_dx4,
480	},
481	{
482		.action		= SEG6_LOCAL_ACTION_END_DT6,
483		.attrs		= (1 << SEG6_LOCAL_TABLE),
484		.input		= input_action_end_dt6,
485	},
486	{
487		.action		= SEG6_LOCAL_ACTION_END_B6,
488		.attrs		= (1 << SEG6_LOCAL_SRH),
489		.input		= input_action_end_b6,
490	},
491	{
492		.action		= SEG6_LOCAL_ACTION_END_B6_ENCAP,
493		.attrs		= (1 << SEG6_LOCAL_SRH),
494		.input		= input_action_end_b6_encap,
495		.static_headroom	= sizeof(struct ipv6hdr),
496	}
497};
498
499static struct seg6_action_desc *__get_action_desc(int action)
500{
501	struct seg6_action_desc *desc;
502	int i, count;
503
504	count = ARRAY_SIZE(seg6_action_table);
505	for (i = 0; i < count; i++) {
506		desc = &seg6_action_table[i];
507		if (desc->action == action)
508			return desc;
509	}
510
511	return NULL;
512}
513
514static int seg6_local_input(struct sk_buff *skb)
515{
516	struct dst_entry *orig_dst = skb_dst(skb);
517	struct seg6_action_desc *desc;
518	struct seg6_local_lwt *slwt;
519
520	if (skb->protocol != htons(ETH_P_IPV6)) {
521		kfree_skb(skb);
522		return -EINVAL;
523	}
524
525	slwt = seg6_local_lwtunnel(orig_dst->lwtstate);
526	desc = slwt->desc;
527
528	return desc->input(skb, slwt);
529}
530
531static const struct nla_policy seg6_local_policy[SEG6_LOCAL_MAX + 1] = {
532	[SEG6_LOCAL_ACTION]	= { .type = NLA_U32 },
533	[SEG6_LOCAL_SRH]	= { .type = NLA_BINARY },
534	[SEG6_LOCAL_TABLE]	= { .type = NLA_U32 },
535	[SEG6_LOCAL_NH4]	= { .type = NLA_BINARY,
536				    .len = sizeof(struct in_addr) },
537	[SEG6_LOCAL_NH6]	= { .type = NLA_BINARY,
538				    .len = sizeof(struct in6_addr) },
539	[SEG6_LOCAL_IIF]	= { .type = NLA_U32 },
540	[SEG6_LOCAL_OIF]	= { .type = NLA_U32 },
541};
542
543static int parse_nla_srh(struct nlattr **attrs, struct seg6_local_lwt *slwt)
544{
545	struct ipv6_sr_hdr *srh;
546	int len;
547
548	srh = nla_data(attrs[SEG6_LOCAL_SRH]);
549	len = nla_len(attrs[SEG6_LOCAL_SRH]);
550
551	/* SRH must contain at least one segment */
552	if (len < sizeof(*srh) + sizeof(struct in6_addr))
553		return -EINVAL;
554
555	if (!seg6_validate_srh(srh, len))
556		return -EINVAL;
557
558	slwt->srh = kmalloc(len, GFP_KERNEL);
559	if (!slwt->srh)
560		return -ENOMEM;
561
562	memcpy(slwt->srh, srh, len);
563
564	slwt->headroom += len;
565
566	return 0;
567}
568
569static int put_nla_srh(struct sk_buff *skb, struct seg6_local_lwt *slwt)
570{
571	struct ipv6_sr_hdr *srh;
572	struct nlattr *nla;
573	int len;
574
575	srh = slwt->srh;
576	len = (srh->hdrlen + 1) << 3;
577
578	nla = nla_reserve(skb, SEG6_LOCAL_SRH, len);
579	if (!nla)
580		return -EMSGSIZE;
581
582	memcpy(nla_data(nla), srh, len);
583
584	return 0;
585}
586
587static int cmp_nla_srh(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
588{
589	int len = (a->srh->hdrlen + 1) << 3;
590
591	if (len != ((b->srh->hdrlen + 1) << 3))
592		return 1;
593
594	return memcmp(a->srh, b->srh, len);
595}
596
597static int parse_nla_table(struct nlattr **attrs, struct seg6_local_lwt *slwt)
598{
599	slwt->table = nla_get_u32(attrs[SEG6_LOCAL_TABLE]);
600
601	return 0;
602}
603
604static int put_nla_table(struct sk_buff *skb, struct seg6_local_lwt *slwt)
605{
606	if (nla_put_u32(skb, SEG6_LOCAL_TABLE, slwt->table))
607		return -EMSGSIZE;
608
609	return 0;
610}
611
612static int cmp_nla_table(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
613{
614	if (a->table != b->table)
615		return 1;
616
617	return 0;
618}
619
620static int parse_nla_nh4(struct nlattr **attrs, struct seg6_local_lwt *slwt)
621{
622	memcpy(&slwt->nh4, nla_data(attrs[SEG6_LOCAL_NH4]),
623	       sizeof(struct in_addr));
624
625	return 0;
626}
627
628static int put_nla_nh4(struct sk_buff *skb, struct seg6_local_lwt *slwt)
629{
630	struct nlattr *nla;
631
632	nla = nla_reserve(skb, SEG6_LOCAL_NH4, sizeof(struct in_addr));
633	if (!nla)
634		return -EMSGSIZE;
635
636	memcpy(nla_data(nla), &slwt->nh4, sizeof(struct in_addr));
637
638	return 0;
639}
640
641static int cmp_nla_nh4(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
642{
643	return memcmp(&a->nh4, &b->nh4, sizeof(struct in_addr));
644}
645
646static int parse_nla_nh6(struct nlattr **attrs, struct seg6_local_lwt *slwt)
647{
648	memcpy(&slwt->nh6, nla_data(attrs[SEG6_LOCAL_NH6]),
649	       sizeof(struct in6_addr));
650
651	return 0;
652}
653
654static int put_nla_nh6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
655{
656	struct nlattr *nla;
657
658	nla = nla_reserve(skb, SEG6_LOCAL_NH6, sizeof(struct in6_addr));
659	if (!nla)
660		return -EMSGSIZE;
661
662	memcpy(nla_data(nla), &slwt->nh6, sizeof(struct in6_addr));
663
664	return 0;
665}
666
667static int cmp_nla_nh6(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
668{
669	return memcmp(&a->nh6, &b->nh6, sizeof(struct in6_addr));
670}
671
672static int parse_nla_iif(struct nlattr **attrs, struct seg6_local_lwt *slwt)
673{
674	slwt->iif = nla_get_u32(attrs[SEG6_LOCAL_IIF]);
675
676	return 0;
677}
678
679static int put_nla_iif(struct sk_buff *skb, struct seg6_local_lwt *slwt)
680{
681	if (nla_put_u32(skb, SEG6_LOCAL_IIF, slwt->iif))
682		return -EMSGSIZE;
683
684	return 0;
685}
686
687static int cmp_nla_iif(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
688{
689	if (a->iif != b->iif)
690		return 1;
691
692	return 0;
693}
694
695static int parse_nla_oif(struct nlattr **attrs, struct seg6_local_lwt *slwt)
696{
697	slwt->oif = nla_get_u32(attrs[SEG6_LOCAL_OIF]);
698
699	return 0;
700}
701
702static int put_nla_oif(struct sk_buff *skb, struct seg6_local_lwt *slwt)
703{
704	if (nla_put_u32(skb, SEG6_LOCAL_OIF, slwt->oif))
705		return -EMSGSIZE;
706
707	return 0;
708}
709
710static int cmp_nla_oif(struct seg6_local_lwt *a, struct seg6_local_lwt *b)
711{
712	if (a->oif != b->oif)
713		return 1;
714
715	return 0;
716}
717
718struct seg6_action_param {
719	int (*parse)(struct nlattr **attrs, struct seg6_local_lwt *slwt);
720	int (*put)(struct sk_buff *skb, struct seg6_local_lwt *slwt);
721	int (*cmp)(struct seg6_local_lwt *a, struct seg6_local_lwt *b);
722};
723
724static struct seg6_action_param seg6_action_params[SEG6_LOCAL_MAX + 1] = {
725	[SEG6_LOCAL_SRH]	= { .parse = parse_nla_srh,
726				    .put = put_nla_srh,
727				    .cmp = cmp_nla_srh },
728
729	[SEG6_LOCAL_TABLE]	= { .parse = parse_nla_table,
730				    .put = put_nla_table,
731				    .cmp = cmp_nla_table },
732
733	[SEG6_LOCAL_NH4]	= { .parse = parse_nla_nh4,
734				    .put = put_nla_nh4,
735				    .cmp = cmp_nla_nh4 },
736
737	[SEG6_LOCAL_NH6]	= { .parse = parse_nla_nh6,
738				    .put = put_nla_nh6,
739				    .cmp = cmp_nla_nh6 },
740
741	[SEG6_LOCAL_IIF]	= { .parse = parse_nla_iif,
742				    .put = put_nla_iif,
743				    .cmp = cmp_nla_iif },
744
745	[SEG6_LOCAL_OIF]	= { .parse = parse_nla_oif,
746				    .put = put_nla_oif,
747				    .cmp = cmp_nla_oif },
748};
749
750static int parse_nla_action(struct nlattr **attrs, struct seg6_local_lwt *slwt)
751{
752	struct seg6_action_param *param;
753	struct seg6_action_desc *desc;
754	int i, err;
755
756	desc = __get_action_desc(slwt->action);
757	if (!desc)
758		return -EINVAL;
759
760	if (!desc->input)
761		return -EOPNOTSUPP;
762
763	slwt->desc = desc;
764	slwt->headroom += desc->static_headroom;
765
766	for (i = 0; i < SEG6_LOCAL_MAX + 1; i++) {
767		if (desc->attrs & (1 << i)) {
768			if (!attrs[i])
769				return -EINVAL;
770
771			param = &seg6_action_params[i];
772
773			err = param->parse(attrs, slwt);
774			if (err < 0)
775				return err;
776		}
777	}
778
779	return 0;
780}
781
782static int seg6_local_build_state(struct nlattr *nla, unsigned int family,
783				  const void *cfg, struct lwtunnel_state **ts,
784				  struct netlink_ext_ack *extack)
785{
786	struct nlattr *tb[SEG6_LOCAL_MAX + 1];
787	struct lwtunnel_state *newts;
788	struct seg6_local_lwt *slwt;
789	int err;
790
791	if (family != AF_INET6)
792		return -EINVAL;
793
794	err = nla_parse_nested(tb, SEG6_LOCAL_MAX, nla, seg6_local_policy,
795			       extack);
796
797	if (err < 0)
798		return err;
799
800	if (!tb[SEG6_LOCAL_ACTION])
801		return -EINVAL;
802
803	newts = lwtunnel_state_alloc(sizeof(*slwt));
804	if (!newts)
805		return -ENOMEM;
806
807	slwt = seg6_local_lwtunnel(newts);
808	slwt->action = nla_get_u32(tb[SEG6_LOCAL_ACTION]);
809
810	err = parse_nla_action(tb, slwt);
811	if (err < 0)
812		goto out_free;
813
814	newts->type = LWTUNNEL_ENCAP_SEG6_LOCAL;
815	newts->flags = LWTUNNEL_STATE_INPUT_REDIRECT;
816	newts->headroom = slwt->headroom;
817
818	*ts = newts;
819
820	return 0;
821
822out_free:
823	kfree(slwt->srh);
824	kfree(newts);
825	return err;
826}
827
828static void seg6_local_destroy_state(struct lwtunnel_state *lwt)
829{
830	struct seg6_local_lwt *slwt = seg6_local_lwtunnel(lwt);
831
832	kfree(slwt->srh);
833}
834
835static int seg6_local_fill_encap(struct sk_buff *skb,
836				 struct lwtunnel_state *lwt)
837{
838	struct seg6_local_lwt *slwt = seg6_local_lwtunnel(lwt);
839	struct seg6_action_param *param;
840	int i, err;
841
842	if (nla_put_u32(skb, SEG6_LOCAL_ACTION, slwt->action))
843		return -EMSGSIZE;
844
845	for (i = 0; i < SEG6_LOCAL_MAX + 1; i++) {
846		if (slwt->desc->attrs & (1 << i)) {
847			param = &seg6_action_params[i];
848			err = param->put(skb, slwt);
849			if (err < 0)
850				return err;
851		}
852	}
853
854	return 0;
855}
856
857static int seg6_local_get_encap_size(struct lwtunnel_state *lwt)
858{
859	struct seg6_local_lwt *slwt = seg6_local_lwtunnel(lwt);
860	unsigned long attrs;
861	int nlsize;
862
863	nlsize = nla_total_size(4); /* action */
864
865	attrs = slwt->desc->attrs;
866
867	if (attrs & (1 << SEG6_LOCAL_SRH))
868		nlsize += nla_total_size((slwt->srh->hdrlen + 1) << 3);
869
870	if (attrs & (1 << SEG6_LOCAL_TABLE))
871		nlsize += nla_total_size(4);
872
873	if (attrs & (1 << SEG6_LOCAL_NH4))
874		nlsize += nla_total_size(4);
875
876	if (attrs & (1 << SEG6_LOCAL_NH6))
877		nlsize += nla_total_size(16);
878
879	if (attrs & (1 << SEG6_LOCAL_IIF))
880		nlsize += nla_total_size(4);
881
882	if (attrs & (1 << SEG6_LOCAL_OIF))
883		nlsize += nla_total_size(4);
884
885	return nlsize;
886}
887
888static int seg6_local_cmp_encap(struct lwtunnel_state *a,
889				struct lwtunnel_state *b)
890{
891	struct seg6_local_lwt *slwt_a, *slwt_b;
892	struct seg6_action_param *param;
893	int i;
894
895	slwt_a = seg6_local_lwtunnel(a);
896	slwt_b = seg6_local_lwtunnel(b);
897
898	if (slwt_a->action != slwt_b->action)
899		return 1;
900
901	if (slwt_a->desc->attrs != slwt_b->desc->attrs)
902		return 1;
903
904	for (i = 0; i < SEG6_LOCAL_MAX + 1; i++) {
905		if (slwt_a->desc->attrs & (1 << i)) {
906			param = &seg6_action_params[i];
907			if (param->cmp(slwt_a, slwt_b))
908				return 1;
909		}
910	}
911
912	return 0;
913}
914
915static const struct lwtunnel_encap_ops seg6_local_ops = {
916	.build_state	= seg6_local_build_state,
917	.destroy_state	= seg6_local_destroy_state,
918	.input		= seg6_local_input,
919	.fill_encap	= seg6_local_fill_encap,
920	.get_encap_size	= seg6_local_get_encap_size,
921	.cmp_encap	= seg6_local_cmp_encap,
922	.owner		= THIS_MODULE,
923};
924
925int __init seg6_local_init(void)
926{
927	return lwtunnel_encap_add_ops(&seg6_local_ops,
928				      LWTUNNEL_ENCAP_SEG6_LOCAL);
929}
930
931void seg6_local_exit(void)
932{
933	lwtunnel_encap_del_ops(&seg6_local_ops, LWTUNNEL_ENCAP_SEG6_LOCAL);
934}