• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * iproute_lwtunnel.c
3  *
4  *		This program is free software; you can redistribute it and/or
5  *		modify it under the terms of the GNU General Public License
6  *		as published by the Free Software Foundation; either version
7  *		2 of the License, or (at your option) any later version.
8  *
9  * Authors:	Roopa Prabhu, <roopa@cumulusnetworks.com>
10  *		Thomas Graf <tgraf@suug.ch>
11  *
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <linux/ila.h>
20 #include <linux/lwtunnel.h>
21 #include <linux/mpls_iptunnel.h>
22 #include <errno.h>
23 
24 #include "rt_names.h"
25 #include "utils.h"
26 #include "iproute_lwtunnel.h"
27 #include "bpf_util.h"
28 
29 #include <linux/seg6.h>
30 #include <linux/seg6_iptunnel.h>
31 #include <linux/seg6_hmac.h>
32 #include <linux/seg6_local.h>
33 #include <net/if.h>
34 
format_encap_type(int type)35 static const char *format_encap_type(int type)
36 {
37 	switch (type) {
38 	case LWTUNNEL_ENCAP_MPLS:
39 		return "mpls";
40 	case LWTUNNEL_ENCAP_IP:
41 		return "ip";
42 	case LWTUNNEL_ENCAP_IP6:
43 		return "ip6";
44 	case LWTUNNEL_ENCAP_ILA:
45 		return "ila";
46 	case LWTUNNEL_ENCAP_BPF:
47 		return "bpf";
48 	case LWTUNNEL_ENCAP_SEG6:
49 		return "seg6";
50 	case LWTUNNEL_ENCAP_SEG6_LOCAL:
51 		return "seg6local";
52 	default:
53 		return "unknown";
54 	}
55 }
56 
encap_type_usage(void)57 static void encap_type_usage(void)
58 {
59 	int i;
60 
61 	fprintf(stderr, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
62 
63 	for (i = 1; i <= LWTUNNEL_ENCAP_MAX; i++)
64 		fprintf(stderr, "%s %s\n", format_encap_type(i),
65 			i == 1 ? "TYPE := " : "      ");
66 
67 	exit(-1);
68 }
69 
read_encap_type(const char * name)70 static int read_encap_type(const char *name)
71 {
72 	if (strcmp(name, "mpls") == 0)
73 		return LWTUNNEL_ENCAP_MPLS;
74 	else if (strcmp(name, "ip") == 0)
75 		return LWTUNNEL_ENCAP_IP;
76 	else if (strcmp(name, "ip6") == 0)
77 		return LWTUNNEL_ENCAP_IP6;
78 	else if (strcmp(name, "ila") == 0)
79 		return LWTUNNEL_ENCAP_ILA;
80 	else if (strcmp(name, "bpf") == 0)
81 		return LWTUNNEL_ENCAP_BPF;
82 	else if (strcmp(name, "seg6") == 0)
83 		return LWTUNNEL_ENCAP_SEG6;
84 	else if (strcmp(name, "seg6local") == 0)
85 		return LWTUNNEL_ENCAP_SEG6_LOCAL;
86 	else if (strcmp(name, "help") == 0)
87 		encap_type_usage();
88 
89 	return LWTUNNEL_ENCAP_NONE;
90 }
91 
print_srh(FILE * fp,struct ipv6_sr_hdr * srh)92 static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh)
93 {
94 	int i;
95 
96 	fprintf(fp, "segs %d [ ", srh->first_segment + 1);
97 
98 	for (i = srh->first_segment; i >= 0; i--)
99 		fprintf(fp, "%s ",
100 			rt_addr_n2a(AF_INET6, 16, &srh->segments[i]));
101 
102 	fprintf(fp, "] ");
103 
104 	if (sr_has_hmac(srh)) {
105 		unsigned int offset = ((srh->hdrlen + 1) << 3) - 40;
106 		struct sr6_tlv_hmac *tlv;
107 
108 		tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
109 		fprintf(fp, "hmac 0x%X ", ntohl(tlv->hmackeyid));
110 	}
111 }
112 
113 static const char *seg6_mode_types[] = {
114 	[SEG6_IPTUN_MODE_INLINE]	= "inline",
115 	[SEG6_IPTUN_MODE_ENCAP]		= "encap",
116 	[SEG6_IPTUN_MODE_L2ENCAP]	= "l2encap",
117 };
118 
format_seg6mode_type(int mode)119 static const char *format_seg6mode_type(int mode)
120 {
121 	if (mode < 0 || mode > ARRAY_SIZE(seg6_mode_types))
122 		return "<unknown>";
123 
124 	return seg6_mode_types[mode];
125 }
126 
read_seg6mode_type(const char * mode)127 static int read_seg6mode_type(const char *mode)
128 {
129 	int i;
130 
131 	for (i = 0; i < ARRAY_SIZE(seg6_mode_types); i++) {
132 		if (strcmp(mode, seg6_mode_types[i]) == 0)
133 			return i;
134 	}
135 
136 	return -1;
137 }
138 
print_encap_seg6(FILE * fp,struct rtattr * encap)139 static void print_encap_seg6(FILE *fp, struct rtattr *encap)
140 {
141 	struct rtattr *tb[SEG6_IPTUNNEL_MAX+1];
142 	struct seg6_iptunnel_encap *tuninfo;
143 
144 	parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap);
145 
146 	if (!tb[SEG6_IPTUNNEL_SRH])
147 		return;
148 
149 	tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]);
150 	fprintf(fp, "mode %s ", format_seg6mode_type(tuninfo->mode));
151 
152 	print_srh(fp, tuninfo->srh);
153 }
154 
155 static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
156 	[SEG6_LOCAL_ACTION_END]			= "End",
157 	[SEG6_LOCAL_ACTION_END_X]		= "End.X",
158 	[SEG6_LOCAL_ACTION_END_T]		= "End.T",
159 	[SEG6_LOCAL_ACTION_END_DX2]		= "End.DX2",
160 	[SEG6_LOCAL_ACTION_END_DX6]		= "End.DX6",
161 	[SEG6_LOCAL_ACTION_END_DX4]		= "End.DX4",
162 	[SEG6_LOCAL_ACTION_END_DT6]		= "End.DT6",
163 	[SEG6_LOCAL_ACTION_END_DT4]		= "End.DT4",
164 	[SEG6_LOCAL_ACTION_END_B6]		= "End.B6",
165 	[SEG6_LOCAL_ACTION_END_B6_ENCAP]	= "End.B6.Encaps",
166 	[SEG6_LOCAL_ACTION_END_BM]		= "End.BM",
167 	[SEG6_LOCAL_ACTION_END_S]		= "End.S",
168 	[SEG6_LOCAL_ACTION_END_AS]		= "End.AS",
169 	[SEG6_LOCAL_ACTION_END_AM]		= "End.AM",
170 };
171 
format_action_type(int action)172 static const char *format_action_type(int action)
173 {
174 	if (action < 0 || action > SEG6_LOCAL_ACTION_MAX)
175 		return "<invalid>";
176 
177 	return seg6_action_names[action] ?: "<unknown>";
178 }
179 
read_action_type(const char * name)180 static int read_action_type(const char *name)
181 {
182 	int i;
183 
184 	for (i = 0; i < SEG6_LOCAL_ACTION_MAX + 1; i++) {
185 		if (!seg6_action_names[i])
186 			continue;
187 
188 		if (strcmp(seg6_action_names[i], name) == 0)
189 			return i;
190 	}
191 
192 	return SEG6_LOCAL_ACTION_UNSPEC;
193 }
194 
print_encap_seg6local(FILE * fp,struct rtattr * encap)195 static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
196 {
197 	struct rtattr *tb[SEG6_LOCAL_MAX + 1];
198 	char ifbuf[IFNAMSIZ];
199 	int action;
200 
201 	parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
202 
203 	if (!tb[SEG6_LOCAL_ACTION])
204 		return;
205 
206 	action = rta_getattr_u32(tb[SEG6_LOCAL_ACTION]);
207 
208 	fprintf(fp, "action %s ", format_action_type(action));
209 
210 	if (tb[SEG6_LOCAL_SRH]) {
211 		fprintf(fp, "srh ");
212 		print_srh(fp, RTA_DATA(tb[SEG6_LOCAL_SRH]));
213 	}
214 
215 	if (tb[SEG6_LOCAL_TABLE])
216 		fprintf(fp, "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
217 
218 	if (tb[SEG6_LOCAL_NH4]) {
219 		fprintf(fp, "nh4 %s ",
220 			rt_addr_n2a_rta(AF_INET, tb[SEG6_LOCAL_NH4]));
221 	}
222 
223 	if (tb[SEG6_LOCAL_NH6]) {
224 		fprintf(fp, "nh6 %s ",
225 			rt_addr_n2a_rta(AF_INET6, tb[SEG6_LOCAL_NH6]));
226 	}
227 
228 	if (tb[SEG6_LOCAL_IIF]) {
229 		int iif = rta_getattr_u32(tb[SEG6_LOCAL_IIF]);
230 
231 		fprintf(fp, "iif %s ",
232 			if_indextoname(iif, ifbuf) ?: "<unknown>");
233 	}
234 
235 	if (tb[SEG6_LOCAL_OIF]) {
236 		int oif = rta_getattr_u32(tb[SEG6_LOCAL_OIF]);
237 
238 		fprintf(fp, "oif %s ",
239 			if_indextoname(oif, ifbuf) ?: "<unknown>");
240 	}
241 }
242 
print_encap_mpls(FILE * fp,struct rtattr * encap)243 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
244 {
245 	struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
246 
247 	parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
248 
249 	if (tb[MPLS_IPTUNNEL_DST])
250 		fprintf(fp, " %s ",
251 			format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
252 	if (tb[MPLS_IPTUNNEL_TTL])
253 		fprintf(fp, "ttl %u ",
254 			rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
255 }
256 
print_encap_ip(FILE * fp,struct rtattr * encap)257 static void print_encap_ip(FILE *fp, struct rtattr *encap)
258 {
259 	struct rtattr *tb[LWTUNNEL_IP_MAX+1];
260 
261 	parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
262 
263 	if (tb[LWTUNNEL_IP_ID])
264 		fprintf(fp, "id %llu ",
265 			ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
266 
267 	if (tb[LWTUNNEL_IP_SRC])
268 		fprintf(fp, "src %s ",
269 			rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
270 
271 	if (tb[LWTUNNEL_IP_DST])
272 		fprintf(fp, "dst %s ",
273 			rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
274 
275 	if (tb[LWTUNNEL_IP_TTL])
276 		fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
277 
278 	if (tb[LWTUNNEL_IP_TOS])
279 		fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
280 }
281 
ila_csum_mode2name(__u8 csum_mode)282 static char *ila_csum_mode2name(__u8 csum_mode)
283 {
284 	switch (csum_mode) {
285 	case ILA_CSUM_ADJUST_TRANSPORT:
286 		return "adj-transport";
287 	case ILA_CSUM_NEUTRAL_MAP:
288 		return "neutral-map";
289 	case ILA_CSUM_NO_ACTION:
290 		return "no-action";
291 	default:
292 		return "unknown";
293 	}
294 }
295 
ila_csum_name2mode(char * name)296 static int ila_csum_name2mode(char *name)
297 {
298 	if (strcmp(name, "adj-transport") == 0)
299 		return ILA_CSUM_ADJUST_TRANSPORT;
300 	else if (strcmp(name, "neutral-map") == 0)
301 		return ILA_CSUM_NEUTRAL_MAP;
302 	else if (strcmp(name, "no-action") == 0)
303 		return ILA_CSUM_NO_ACTION;
304 	else
305 		return -1;
306 }
307 
print_encap_ila(FILE * fp,struct rtattr * encap)308 static void print_encap_ila(FILE *fp, struct rtattr *encap)
309 {
310 	struct rtattr *tb[ILA_ATTR_MAX+1];
311 
312 	parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
313 
314 	if (tb[ILA_ATTR_LOCATOR]) {
315 		char abuf[ADDR64_BUF_SIZE];
316 
317 		addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
318 			   abuf, sizeof(abuf));
319 		fprintf(fp, " %s ", abuf);
320 	}
321 
322 	if (tb[ILA_ATTR_CSUM_MODE])
323 		fprintf(fp, " csum-mode %s ",
324 			ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
325 }
326 
print_encap_ip6(FILE * fp,struct rtattr * encap)327 static void print_encap_ip6(FILE *fp, struct rtattr *encap)
328 {
329 	struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
330 
331 	parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
332 
333 	if (tb[LWTUNNEL_IP6_ID])
334 		fprintf(fp, "id %llu ",
335 			ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
336 
337 	if (tb[LWTUNNEL_IP6_SRC])
338 		fprintf(fp, "src %s ",
339 			rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
340 
341 	if (tb[LWTUNNEL_IP6_DST])
342 		fprintf(fp, "dst %s ",
343 			rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
344 
345 	if (tb[LWTUNNEL_IP6_HOPLIMIT])
346 		fprintf(fp, "hoplimit %d ",
347 			rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
348 
349 	if (tb[LWTUNNEL_IP6_TC])
350 		fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
351 }
352 
print_encap_bpf_prog(FILE * fp,struct rtattr * encap,const char * str)353 static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
354 				 const char *str)
355 {
356 	struct rtattr *tb[LWT_BPF_PROG_MAX+1];
357 
358 	parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
359 	fprintf(fp, "%s ", str);
360 
361 	if (tb[LWT_BPF_PROG_NAME])
362 		fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME]));
363 }
364 
print_encap_bpf(FILE * fp,struct rtattr * encap)365 static void print_encap_bpf(FILE *fp, struct rtattr *encap)
366 {
367 	struct rtattr *tb[LWT_BPF_MAX+1];
368 
369 	parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
370 
371 	if (tb[LWT_BPF_IN])
372 		print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
373 	if (tb[LWT_BPF_OUT])
374 		print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
375 	if (tb[LWT_BPF_XMIT])
376 		print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
377 	if (tb[LWT_BPF_XMIT_HEADROOM])
378 		fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
379 }
380 
lwt_print_encap(FILE * fp,struct rtattr * encap_type,struct rtattr * encap)381 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
382 			  struct rtattr *encap)
383 {
384 	int et;
385 
386 	if (!encap_type)
387 		return;
388 
389 	et = rta_getattr_u16(encap_type);
390 
391 	fprintf(fp, " encap %s ", format_encap_type(et));
392 
393 	switch (et) {
394 	case LWTUNNEL_ENCAP_MPLS:
395 		print_encap_mpls(fp, encap);
396 		break;
397 	case LWTUNNEL_ENCAP_IP:
398 		print_encap_ip(fp, encap);
399 		break;
400 	case LWTUNNEL_ENCAP_ILA:
401 		print_encap_ila(fp, encap);
402 		break;
403 	case LWTUNNEL_ENCAP_IP6:
404 		print_encap_ip6(fp, encap);
405 		break;
406 	case LWTUNNEL_ENCAP_BPF:
407 		print_encap_bpf(fp, encap);
408 		break;
409 	case LWTUNNEL_ENCAP_SEG6:
410 		print_encap_seg6(fp, encap);
411 		break;
412 	case LWTUNNEL_ENCAP_SEG6_LOCAL:
413 		print_encap_seg6local(fp, encap);
414 		break;
415 	}
416 }
417 
parse_srh(char * segbuf,int hmac,bool encap)418 static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
419 {
420 	struct ipv6_sr_hdr *srh;
421 	int nsegs = 0;
422 	int srhlen;
423 	char *s;
424 	int i;
425 
426 	s = segbuf;
427 	for (i = 0; *s; *s++ == ',' ? i++ : *s);
428 	nsegs = i + 1;
429 
430 	if (!encap)
431 		nsegs++;
432 
433 	srhlen = 8 + 16*nsegs;
434 
435 	if (hmac)
436 		srhlen += 40;
437 
438 	srh = malloc(srhlen);
439 	memset(srh, 0, srhlen);
440 
441 	srh->hdrlen = (srhlen >> 3) - 1;
442 	srh->type = 4;
443 	srh->segments_left = nsegs - 1;
444 	srh->first_segment = nsegs - 1;
445 
446 	if (hmac)
447 		srh->flags |= SR6_FLAG1_HMAC;
448 
449 	i = srh->first_segment;
450 	for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
451 		inet_get_addr(s, NULL, &srh->segments[i]);
452 		i--;
453 	}
454 
455 	if (hmac) {
456 		struct sr6_tlv_hmac *tlv;
457 
458 		tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
459 		tlv->tlvhdr.type = SR6_TLV_HMAC;
460 		tlv->tlvhdr.len = 38;
461 		tlv->hmackeyid = htonl(hmac);
462 	}
463 
464 	return srh;
465 }
466 
parse_encap_seg6(struct rtattr * rta,size_t len,int * argcp,char *** argvp)467 static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
468 			    char ***argvp)
469 {
470 	int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
471 	struct seg6_iptunnel_encap *tuninfo;
472 	struct ipv6_sr_hdr *srh;
473 	char **argv = *argvp;
474 	char segbuf[1024];
475 	int argc = *argcp;
476 	int encap = -1;
477 	__u32 hmac = 0;
478 	int srhlen;
479 
480 	while (argc > 0) {
481 		if (strcmp(*argv, "mode") == 0) {
482 			NEXT_ARG();
483 			if (mode_ok++)
484 				duparg2("mode", *argv);
485 			encap = read_seg6mode_type(*argv);
486 			if (encap < 0)
487 				invarg("\"mode\" value is invalid\n", *argv);
488 		} else if (strcmp(*argv, "segs") == 0) {
489 			NEXT_ARG();
490 			if (segs_ok++)
491 				duparg2("segs", *argv);
492 			if (encap == -1)
493 				invarg("\"segs\" provided before \"mode\"\n",
494 				       *argv);
495 
496 			strlcpy(segbuf, *argv, 1024);
497 		} else if (strcmp(*argv, "hmac") == 0) {
498 			NEXT_ARG();
499 			if (hmac_ok++)
500 				duparg2("hmac", *argv);
501 			get_u32(&hmac, *argv, 0);
502 		} else {
503 			break;
504 		}
505 		argc--; argv++;
506 	}
507 
508 	srh = parse_srh(segbuf, hmac, encap);
509 	srhlen = (srh->hdrlen + 1) << 3;
510 
511 	tuninfo = malloc(sizeof(*tuninfo) + srhlen);
512 	memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
513 
514 	tuninfo->mode = encap;
515 
516 	memcpy(tuninfo->srh, srh, srhlen);
517 
518 	rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
519 		      sizeof(*tuninfo) + srhlen);
520 
521 	free(tuninfo);
522 	free(srh);
523 
524 	*argcp = argc + 1;
525 	*argvp = argv - 1;
526 
527 	return 0;
528 }
529 
parse_encap_seg6local(struct rtattr * rta,size_t len,int * argcp,char *** argvp)530 static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
531 				 char ***argvp)
532 {
533 	int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
534 	int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0;
535 	__u32 action = 0, table, iif, oif;
536 	struct ipv6_sr_hdr *srh;
537 	char **argv = *argvp;
538 	int argc = *argcp;
539 	char segbuf[1024];
540 	inet_prefix addr;
541 	__u32 hmac = 0;
542 
543 	while (argc > 0) {
544 		if (strcmp(*argv, "action") == 0) {
545 			NEXT_ARG();
546 			if (action_ok++)
547 				duparg2("action", *argv);
548 			action = read_action_type(*argv);
549 			if (!action)
550 				invarg("\"action\" value is invalid\n", *argv);
551 			rta_addattr32(rta, len, SEG6_LOCAL_ACTION, action);
552 		} else if (strcmp(*argv, "table") == 0) {
553 			NEXT_ARG();
554 			if (table_ok++)
555 				duparg2("table", *argv);
556 			get_u32(&table, *argv, 0);
557 			rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
558 		} else if (strcmp(*argv, "nh4") == 0) {
559 			NEXT_ARG();
560 			if (nh4_ok++)
561 				duparg2("nh4", *argv);
562 			get_addr(&addr, *argv, AF_INET);
563 			rta_addattr_l(rta, len, SEG6_LOCAL_NH4, &addr.data,
564 				      addr.bytelen);
565 		} else if (strcmp(*argv, "nh6") == 0) {
566 			NEXT_ARG();
567 			if (nh6_ok++)
568 				duparg2("nh6", *argv);
569 			get_addr(&addr, *argv, AF_INET6);
570 			rta_addattr_l(rta, len, SEG6_LOCAL_NH6, &addr.data,
571 				      addr.bytelen);
572 		} else if (strcmp(*argv, "iif") == 0) {
573 			NEXT_ARG();
574 			if (iif_ok++)
575 				duparg2("iif", *argv);
576 			iif = if_nametoindex(*argv);
577 			if (!iif)
578 				invarg("\"iif\" interface not found\n", *argv);
579 			rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
580 		} else if (strcmp(*argv, "oif") == 0) {
581 			NEXT_ARG();
582 			if (oif_ok++)
583 				duparg2("oif", *argv);
584 			oif = if_nametoindex(*argv);
585 			if (!oif)
586 				invarg("\"oif\" interface not found\n", *argv);
587 			rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
588 		} else if (strcmp(*argv, "srh") == 0) {
589 			NEXT_ARG();
590 			if (srh_ok++)
591 				duparg2("srh", *argv);
592 			if (strcmp(*argv, "segs") != 0)
593 				invarg("missing \"segs\" attribute for srh\n",
594 					*argv);
595 			NEXT_ARG();
596 			if (segs_ok++)
597 				duparg2("segs", *argv);
598 			strncpy(segbuf, *argv, 1024);
599 			segbuf[1023] = 0;
600 			if (!NEXT_ARG_OK())
601 				break;
602 			NEXT_ARG();
603 			if (strcmp(*argv, "hmac") == 0) {
604 				NEXT_ARG();
605 				if (hmac_ok++)
606 					duparg2("hmac", *argv);
607 				get_u32(&hmac, *argv, 0);
608 			} else {
609 				continue;
610 			}
611 		} else {
612 			break;
613 		}
614 		argc--; argv++;
615 	}
616 
617 	if (!action) {
618 		fprintf(stderr, "Missing action type\n");
619 		exit(-1);
620 	}
621 
622 	if (srh_ok) {
623 		int srhlen;
624 
625 		srh = parse_srh(segbuf, hmac,
626 				action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
627 		srhlen = (srh->hdrlen + 1) << 3;
628 		rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
629 		free(srh);
630 	}
631 
632 	*argcp = argc + 1;
633 	*argvp = argv - 1;
634 
635 	return 0;
636 }
637 
parse_encap_mpls(struct rtattr * rta,size_t len,int * argcp,char *** argvp)638 static int parse_encap_mpls(struct rtattr *rta, size_t len,
639 			    int *argcp, char ***argvp)
640 {
641 	inet_prefix addr;
642 	int argc = *argcp;
643 	char **argv = *argvp;
644 	int ttl_ok = 0;
645 
646 	if (get_addr(&addr, *argv, AF_MPLS)) {
647 		fprintf(stderr,
648 			"Error: an inet address is expected rather than \"%s\".\n",
649 			*argv);
650 		exit(1);
651 	}
652 
653 	rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
654 		      addr.bytelen);
655 
656 	argc--;
657 	argv++;
658 
659 	while (argc > 0) {
660 		if (strcmp(*argv, "ttl") == 0) {
661 			__u8 ttl;
662 
663 			NEXT_ARG();
664 			if (ttl_ok++)
665 				duparg2("ttl", *argv);
666 			if (get_u8(&ttl, *argv, 0))
667 				invarg("\"ttl\" value is invalid\n", *argv);
668 			rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl);
669 		} else {
670 			break;
671 		}
672 		argc--; argv++;
673 	}
674 
675 	/* argv is currently the first unparsed argument,
676 	 * but the lwt_parse_encap() caller will move to the next,
677 	 * so step back
678 	 */
679 	*argcp = argc + 1;
680 	*argvp = argv - 1;
681 
682 	return 0;
683 }
684 
parse_encap_ip(struct rtattr * rta,size_t len,int * argcp,char *** argvp)685 static int parse_encap_ip(struct rtattr *rta, size_t len,
686 			  int *argcp, char ***argvp)
687 {
688 	int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
689 	char **argv = *argvp;
690 	int argc = *argcp;
691 
692 	while (argc > 0) {
693 		if (strcmp(*argv, "id") == 0) {
694 			__u64 id;
695 
696 			NEXT_ARG();
697 			if (id_ok++)
698 				duparg2("id", *argv);
699 			if (get_be64(&id, *argv, 0))
700 				invarg("\"id\" value is invalid\n", *argv);
701 			rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
702 		} else if (strcmp(*argv, "dst") == 0) {
703 			inet_prefix addr;
704 
705 			NEXT_ARG();
706 			if (dst_ok++)
707 				duparg2("dst", *argv);
708 			get_addr(&addr, *argv, AF_INET);
709 			rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
710 				      &addr.data, addr.bytelen);
711 		} else if (strcmp(*argv, "tos") == 0) {
712 			__u32 tos;
713 
714 			NEXT_ARG();
715 			if (tos_ok++)
716 				duparg2("tos", *argv);
717 			if (rtnl_dsfield_a2n(&tos, *argv))
718 				invarg("\"tos\" value is invalid\n", *argv);
719 			rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
720 		} else if (strcmp(*argv, "ttl") == 0) {
721 			__u8 ttl;
722 
723 			NEXT_ARG();
724 			if (ttl_ok++)
725 				duparg2("ttl", *argv);
726 			if (get_u8(&ttl, *argv, 0))
727 				invarg("\"ttl\" value is invalid\n", *argv);
728 			rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
729 		} else {
730 			break;
731 		}
732 		argc--; argv++;
733 	}
734 
735 	/* argv is currently the first unparsed argument,
736 	 * but the lwt_parse_encap() caller will move to the next,
737 	 * so step back
738 	 */
739 	*argcp = argc + 1;
740 	*argvp = argv - 1;
741 
742 	return 0;
743 }
744 
parse_encap_ila(struct rtattr * rta,size_t len,int * argcp,char *** argvp)745 static int parse_encap_ila(struct rtattr *rta, size_t len,
746 			   int *argcp, char ***argvp)
747 {
748 	__u64 locator;
749 	int argc = *argcp;
750 	char **argv = *argvp;
751 
752 	if (get_addr64(&locator, *argv) < 0) {
753 		fprintf(stderr, "Bad locator: %s\n", *argv);
754 		exit(1);
755 	}
756 
757 	argc--; argv++;
758 
759 	rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
760 
761 	while (argc > 0) {
762 		if (strcmp(*argv, "csum-mode") == 0) {
763 			int csum_mode;
764 
765 			NEXT_ARG();
766 
767 			csum_mode = ila_csum_name2mode(*argv);
768 			if (csum_mode < 0)
769 				invarg("\"csum-mode\" value is invalid\n",
770 				       *argv);
771 
772 			rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
773 				     (__u8)csum_mode);
774 
775 			argc--; argv++;
776 		} else {
777 			break;
778 		}
779 	}
780 
781 	/* argv is currently the first unparsed argument,
782 	 * but the lwt_parse_encap() caller will move to the next,
783 	 * so step back
784 	 */
785 	*argcp = argc + 1;
786 	*argvp = argv - 1;
787 
788 	return 0;
789 }
790 
parse_encap_ip6(struct rtattr * rta,size_t len,int * argcp,char *** argvp)791 static int parse_encap_ip6(struct rtattr *rta, size_t len,
792 			   int *argcp, char ***argvp)
793 {
794 	int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
795 	char **argv = *argvp;
796 	int argc = *argcp;
797 
798 	while (argc > 0) {
799 		if (strcmp(*argv, "id") == 0) {
800 			__u64 id;
801 
802 			NEXT_ARG();
803 			if (id_ok++)
804 				duparg2("id", *argv);
805 			if (get_be64(&id, *argv, 0))
806 				invarg("\"id\" value is invalid\n", *argv);
807 			rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
808 		} else if (strcmp(*argv, "dst") == 0) {
809 			inet_prefix addr;
810 
811 			NEXT_ARG();
812 			if (dst_ok++)
813 				duparg2("dst", *argv);
814 			get_addr(&addr, *argv, AF_INET6);
815 			rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
816 				      &addr.data, addr.bytelen);
817 		} else if (strcmp(*argv, "tc") == 0) {
818 			__u32 tc;
819 
820 			NEXT_ARG();
821 			if (tos_ok++)
822 				duparg2("tc", *argv);
823 			if (rtnl_dsfield_a2n(&tc, *argv))
824 				invarg("\"tc\" value is invalid\n", *argv);
825 			rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
826 		} else if (strcmp(*argv, "hoplimit") == 0) {
827 			__u8 hoplimit;
828 
829 			NEXT_ARG();
830 			if (ttl_ok++)
831 				duparg2("hoplimit", *argv);
832 			if (get_u8(&hoplimit, *argv, 0))
833 				invarg("\"hoplimit\" value is invalid\n",
834 				       *argv);
835 			rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
836 		} else {
837 			break;
838 		}
839 		argc--; argv++;
840 	}
841 
842 	/* argv is currently the first unparsed argument,
843 	 * but the lwt_parse_encap() caller will move to the next,
844 	 * so step back
845 	 */
846 	*argcp = argc + 1;
847 	*argvp = argv - 1;
848 
849 	return 0;
850 }
851 
852 struct lwt_x {
853 	struct rtattr *rta;
854 	size_t len;
855 };
856 
bpf_lwt_cb(void * lwt_ptr,int fd,const char * annotation)857 static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
858 {
859 	struct lwt_x *x = lwt_ptr;
860 
861 	rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
862 	rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
863 		      strlen(annotation) + 1);
864 }
865 
866 static const struct bpf_cfg_ops bpf_cb_ops = {
867 	.ebpf_cb = bpf_lwt_cb,
868 };
869 
lwt_parse_bpf(struct rtattr * rta,size_t len,int * argcp,char *** argvp,int attr,const enum bpf_prog_type bpf_type)870 static int lwt_parse_bpf(struct rtattr *rta, size_t len,
871 			 int *argcp, char ***argvp,
872 			 int attr, const enum bpf_prog_type bpf_type)
873 {
874 	struct bpf_cfg_in cfg = {
875 		.argc = *argcp,
876 		.argv = *argvp,
877 	};
878 	struct lwt_x x = {
879 		.rta = rta,
880 		.len = len,
881 	};
882 	struct rtattr *nest;
883 	int err;
884 
885 	nest = rta_nest(rta, len, attr);
886 	err = bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, &x);
887 	if (err < 0) {
888 		fprintf(stderr, "Failed to parse eBPF program: %s\n",
889 			strerror(-err));
890 		return -1;
891 	}
892 	rta_nest_end(rta, nest);
893 
894 	*argcp = cfg.argc;
895 	*argvp = cfg.argv;
896 
897 	return 0;
898 }
899 
lwt_bpf_usage(void)900 static void lwt_bpf_usage(void)
901 {
902 	fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
903 	fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
904 	exit(-1);
905 }
906 
parse_encap_bpf(struct rtattr * rta,size_t len,int * argcp,char *** argvp)907 static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
908 			   char ***argvp)
909 {
910 	char **argv = *argvp;
911 	int argc = *argcp;
912 	int headroom_set = 0;
913 
914 	while (argc > 0) {
915 		if (strcmp(*argv, "in") == 0) {
916 			NEXT_ARG();
917 			if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
918 					  BPF_PROG_TYPE_LWT_IN) < 0)
919 				return -1;
920 		} else if (strcmp(*argv, "out") == 0) {
921 			NEXT_ARG();
922 			if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
923 					  BPF_PROG_TYPE_LWT_OUT) < 0)
924 				return -1;
925 		} else if (strcmp(*argv, "xmit") == 0) {
926 			NEXT_ARG();
927 			if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
928 					  BPF_PROG_TYPE_LWT_XMIT) < 0)
929 				return -1;
930 		} else if (strcmp(*argv, "headroom") == 0) {
931 			unsigned int headroom;
932 
933 			NEXT_ARG();
934 			if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
935 				invarg("headroom is invalid\n", *argv);
936 			if (!headroom_set)
937 				rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
938 					      headroom);
939 			headroom_set = 1;
940 		} else if (strcmp(*argv, "help") == 0) {
941 			lwt_bpf_usage();
942 		} else {
943 			break;
944 		}
945 		NEXT_ARG_FWD();
946 	}
947 
948 	/* argv is currently the first unparsed argument,
949 	 * but the lwt_parse_encap() caller will move to the next,
950 	 * so step back
951 	 */
952 	*argcp = argc + 1;
953 	*argvp = argv - 1;
954 
955 	return 0;
956 }
957 
lwt_parse_encap(struct rtattr * rta,size_t len,int * argcp,char *** argvp)958 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
959 {
960 	struct rtattr *nest;
961 	int argc = *argcp;
962 	char **argv = *argvp;
963 	__u16 type;
964 
965 	NEXT_ARG();
966 	type = read_encap_type(*argv);
967 	if (!type)
968 		invarg("\"encap type\" value is invalid\n", *argv);
969 
970 	NEXT_ARG();
971 	if (argc <= 1) {
972 		fprintf(stderr,
973 			"Error: unexpected end of line after \"encap\"\n");
974 		exit(-1);
975 	}
976 
977 	nest = rta_nest(rta, 1024, RTA_ENCAP);
978 	switch (type) {
979 	case LWTUNNEL_ENCAP_MPLS:
980 		parse_encap_mpls(rta, len, &argc, &argv);
981 		break;
982 	case LWTUNNEL_ENCAP_IP:
983 		parse_encap_ip(rta, len, &argc, &argv);
984 		break;
985 	case LWTUNNEL_ENCAP_ILA:
986 		parse_encap_ila(rta, len, &argc, &argv);
987 		break;
988 	case LWTUNNEL_ENCAP_IP6:
989 		parse_encap_ip6(rta, len, &argc, &argv);
990 		break;
991 	case LWTUNNEL_ENCAP_BPF:
992 		if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
993 			exit(-1);
994 		break;
995 	case LWTUNNEL_ENCAP_SEG6:
996 		parse_encap_seg6(rta, len, &argc, &argv);
997 		break;
998 	case LWTUNNEL_ENCAP_SEG6_LOCAL:
999 		parse_encap_seg6local(rta, len, &argc, &argv);
1000 		break;
1001 	default:
1002 		fprintf(stderr, "Error: unsupported encap type\n");
1003 		break;
1004 	}
1005 	rta_nest_end(rta, nest);
1006 
1007 	rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
1008 
1009 	*argcp = argc;
1010 	*argvp = argv;
1011 
1012 	return 0;
1013 }
1014