]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute_lwtunnel.c
ila: support for configuring identifier and hook types
[mirror_iproute2.git] / ip / iproute_lwtunnel.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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 case ILA_CSUM_NEUTRAL_MAP_AUTO:
292 return "neutral-map-auto";
293 default:
294 return "unknown";
295 }
296 }
297
298 static int ila_csum_name2mode(char *name)
299 {
300 if (strcmp(name, "adj-transport") == 0)
301 return ILA_CSUM_ADJUST_TRANSPORT;
302 else if (strcmp(name, "neutral-map") == 0)
303 return ILA_CSUM_NEUTRAL_MAP;
304 else if (strcmp(name, "no-action") == 0)
305 return ILA_CSUM_NO_ACTION;
306 else if (strcmp(name, "neutral-map-auto") == 0)
307 return ILA_CSUM_NEUTRAL_MAP_AUTO;
308 else
309 return -1;
310 }
311
312 static char *ila_ident_type2name(__u8 ident_type)
313 {
314 switch (ident_type) {
315 case ILA_ATYPE_IID:
316 return "iid";
317 case ILA_ATYPE_LUID:
318 return "luid";
319 case ILA_ATYPE_VIRT_V4:
320 return "virt-v4";
321 case ILA_ATYPE_VIRT_UNI_V6:
322 return "virt-uni-v6";
323 case ILA_ATYPE_VIRT_MULTI_V6:
324 return "virt-multi-v6";
325 case ILA_ATYPE_NONLOCAL_ADDR:
326 return "nonlocal-addr";
327 case ILA_ATYPE_USE_FORMAT:
328 return "use-format";
329 default:
330 return "unknown";
331 }
332 }
333
334 static int ila_ident_name2type(char *name)
335 {
336 if (!strcmp(name, "luid"))
337 return ILA_ATYPE_LUID;
338 else if (!strcmp(name, "use-format"))
339 return ILA_ATYPE_USE_FORMAT;
340 #if 0 /* No kernel support for configuring these yet */
341 else if (!strcmp(name, "iid"))
342 return ILA_ATYPE_IID;
343 else if (!strcmp(name, "virt-v4"))
344 return ILA_ATYPE_VIRT_V4;
345 else if (!strcmp(name, "virt-uni-v6"))
346 return ILA_ATYPE_VIRT_UNI_V6;
347 else if (!strcmp(name, "virt-multi-v6"))
348 return ILA_ATYPE_VIRT_MULTI_V6;
349 else if (!strcmp(name, "nonlocal-addr"))
350 return ILA_ATYPE_NONLOCAL_ADDR;
351 #endif
352 else
353 return -1;
354 }
355
356 static char *ila_hook_type2name(__u8 hook_type)
357 {
358 switch (hook_type) {
359 case ILA_HOOK_ROUTE_OUTPUT:
360 return "output";
361 case ILA_HOOK_ROUTE_INPUT:
362 return "input";
363 default:
364 return "unknown";
365 }
366 }
367
368 static int ila_hook_name2type(char *name)
369 {
370 if (!strcmp(name, "output"))
371 return ILA_HOOK_ROUTE_OUTPUT;
372 else if (!strcmp(name, "input"))
373 return ILA_HOOK_ROUTE_INPUT;
374 else
375 return -1;
376 }
377
378 static void print_encap_ila(FILE *fp, struct rtattr *encap)
379 {
380 struct rtattr *tb[ILA_ATTR_MAX+1];
381
382 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
383
384 if (tb[ILA_ATTR_LOCATOR]) {
385 char abuf[ADDR64_BUF_SIZE];
386
387 addr64_n2a(rta_getattr_u64(tb[ILA_ATTR_LOCATOR]),
388 abuf, sizeof(abuf));
389 fprintf(fp, " %s ", abuf);
390 }
391
392 if (tb[ILA_ATTR_CSUM_MODE])
393 fprintf(fp, " csum-mode %s ",
394 ila_csum_mode2name(rta_getattr_u8(
395 tb[ILA_ATTR_CSUM_MODE])));
396
397 if (tb[ILA_ATTR_IDENT_TYPE])
398 fprintf(fp, " ident-type %s ",
399 ila_ident_type2name(rta_getattr_u8(
400 tb[ILA_ATTR_IDENT_TYPE])));
401
402 if (tb[ILA_ATTR_HOOK_TYPE])
403 fprintf(fp, " hook-type %s ",
404 ila_hook_type2name(rta_getattr_u8(
405 tb[ILA_ATTR_HOOK_TYPE])));
406 }
407
408 static void print_encap_ip6(FILE *fp, struct rtattr *encap)
409 {
410 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
411
412 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
413
414 if (tb[LWTUNNEL_IP6_ID])
415 fprintf(fp, "id %llu ",
416 ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
417
418 if (tb[LWTUNNEL_IP6_SRC])
419 fprintf(fp, "src %s ",
420 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
421
422 if (tb[LWTUNNEL_IP6_DST])
423 fprintf(fp, "dst %s ",
424 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
425
426 if (tb[LWTUNNEL_IP6_HOPLIMIT])
427 fprintf(fp, "hoplimit %d ",
428 rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
429
430 if (tb[LWTUNNEL_IP6_TC])
431 fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
432 }
433
434 static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
435 const char *str)
436 {
437 struct rtattr *tb[LWT_BPF_PROG_MAX+1];
438
439 parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
440 fprintf(fp, "%s ", str);
441
442 if (tb[LWT_BPF_PROG_NAME])
443 fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME]));
444 }
445
446 static void print_encap_bpf(FILE *fp, struct rtattr *encap)
447 {
448 struct rtattr *tb[LWT_BPF_MAX+1];
449
450 parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
451
452 if (tb[LWT_BPF_IN])
453 print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
454 if (tb[LWT_BPF_OUT])
455 print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
456 if (tb[LWT_BPF_XMIT])
457 print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
458 if (tb[LWT_BPF_XMIT_HEADROOM])
459 fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
460 }
461
462 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
463 struct rtattr *encap)
464 {
465 int et;
466
467 if (!encap_type)
468 return;
469
470 et = rta_getattr_u16(encap_type);
471
472 fprintf(fp, " encap %s ", format_encap_type(et));
473
474 switch (et) {
475 case LWTUNNEL_ENCAP_MPLS:
476 print_encap_mpls(fp, encap);
477 break;
478 case LWTUNNEL_ENCAP_IP:
479 print_encap_ip(fp, encap);
480 break;
481 case LWTUNNEL_ENCAP_ILA:
482 print_encap_ila(fp, encap);
483 break;
484 case LWTUNNEL_ENCAP_IP6:
485 print_encap_ip6(fp, encap);
486 break;
487 case LWTUNNEL_ENCAP_BPF:
488 print_encap_bpf(fp, encap);
489 break;
490 case LWTUNNEL_ENCAP_SEG6:
491 print_encap_seg6(fp, encap);
492 break;
493 case LWTUNNEL_ENCAP_SEG6_LOCAL:
494 print_encap_seg6local(fp, encap);
495 break;
496 }
497 }
498
499 static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
500 {
501 struct ipv6_sr_hdr *srh;
502 int nsegs = 0;
503 int srhlen;
504 char *s;
505 int i;
506
507 s = segbuf;
508 for (i = 0; *s; *s++ == ',' ? i++ : *s);
509 nsegs = i + 1;
510
511 if (!encap)
512 nsegs++;
513
514 srhlen = 8 + 16*nsegs;
515
516 if (hmac)
517 srhlen += 40;
518
519 srh = malloc(srhlen);
520 memset(srh, 0, srhlen);
521
522 srh->hdrlen = (srhlen >> 3) - 1;
523 srh->type = 4;
524 srh->segments_left = nsegs - 1;
525 srh->first_segment = nsegs - 1;
526
527 if (hmac)
528 srh->flags |= SR6_FLAG1_HMAC;
529
530 i = srh->first_segment;
531 for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
532 inet_get_addr(s, NULL, &srh->segments[i]);
533 i--;
534 }
535
536 if (hmac) {
537 struct sr6_tlv_hmac *tlv;
538
539 tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40);
540 tlv->tlvhdr.type = SR6_TLV_HMAC;
541 tlv->tlvhdr.len = 38;
542 tlv->hmackeyid = htonl(hmac);
543 }
544
545 return srh;
546 }
547
548 static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
549 char ***argvp)
550 {
551 int mode_ok = 0, segs_ok = 0, hmac_ok = 0;
552 struct seg6_iptunnel_encap *tuninfo;
553 struct ipv6_sr_hdr *srh;
554 char **argv = *argvp;
555 char segbuf[1024];
556 int argc = *argcp;
557 int encap = -1;
558 __u32 hmac = 0;
559 int srhlen;
560
561 while (argc > 0) {
562 if (strcmp(*argv, "mode") == 0) {
563 NEXT_ARG();
564 if (mode_ok++)
565 duparg2("mode", *argv);
566 encap = read_seg6mode_type(*argv);
567 if (encap < 0)
568 invarg("\"mode\" value is invalid\n", *argv);
569 } else if (strcmp(*argv, "segs") == 0) {
570 NEXT_ARG();
571 if (segs_ok++)
572 duparg2("segs", *argv);
573 if (encap == -1)
574 invarg("\"segs\" provided before \"mode\"\n",
575 *argv);
576
577 strlcpy(segbuf, *argv, 1024);
578 } else if (strcmp(*argv, "hmac") == 0) {
579 NEXT_ARG();
580 if (hmac_ok++)
581 duparg2("hmac", *argv);
582 get_u32(&hmac, *argv, 0);
583 } else {
584 break;
585 }
586 argc--; argv++;
587 }
588
589 srh = parse_srh(segbuf, hmac, encap);
590 srhlen = (srh->hdrlen + 1) << 3;
591
592 tuninfo = malloc(sizeof(*tuninfo) + srhlen);
593 memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
594
595 tuninfo->mode = encap;
596
597 memcpy(tuninfo->srh, srh, srhlen);
598
599 rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
600 sizeof(*tuninfo) + srhlen);
601
602 free(tuninfo);
603 free(srh);
604
605 *argcp = argc + 1;
606 *argvp = argv - 1;
607
608 return 0;
609 }
610
611 static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
612 char ***argvp)
613 {
614 int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
615 int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0;
616 __u32 action = 0, table, iif, oif;
617 struct ipv6_sr_hdr *srh;
618 char **argv = *argvp;
619 int argc = *argcp;
620 char segbuf[1024];
621 inet_prefix addr;
622 __u32 hmac = 0;
623
624 while (argc > 0) {
625 if (strcmp(*argv, "action") == 0) {
626 NEXT_ARG();
627 if (action_ok++)
628 duparg2("action", *argv);
629 action = read_action_type(*argv);
630 if (!action)
631 invarg("\"action\" value is invalid\n", *argv);
632 rta_addattr32(rta, len, SEG6_LOCAL_ACTION, action);
633 } else if (strcmp(*argv, "table") == 0) {
634 NEXT_ARG();
635 if (table_ok++)
636 duparg2("table", *argv);
637 get_u32(&table, *argv, 0);
638 rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
639 } else if (strcmp(*argv, "nh4") == 0) {
640 NEXT_ARG();
641 if (nh4_ok++)
642 duparg2("nh4", *argv);
643 get_addr(&addr, *argv, AF_INET);
644 rta_addattr_l(rta, len, SEG6_LOCAL_NH4, &addr.data,
645 addr.bytelen);
646 } else if (strcmp(*argv, "nh6") == 0) {
647 NEXT_ARG();
648 if (nh6_ok++)
649 duparg2("nh6", *argv);
650 get_addr(&addr, *argv, AF_INET6);
651 rta_addattr_l(rta, len, SEG6_LOCAL_NH6, &addr.data,
652 addr.bytelen);
653 } else if (strcmp(*argv, "iif") == 0) {
654 NEXT_ARG();
655 if (iif_ok++)
656 duparg2("iif", *argv);
657 iif = if_nametoindex(*argv);
658 if (!iif)
659 invarg("\"iif\" interface not found\n", *argv);
660 rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
661 } else if (strcmp(*argv, "oif") == 0) {
662 NEXT_ARG();
663 if (oif_ok++)
664 duparg2("oif", *argv);
665 oif = if_nametoindex(*argv);
666 if (!oif)
667 invarg("\"oif\" interface not found\n", *argv);
668 rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
669 } else if (strcmp(*argv, "srh") == 0) {
670 NEXT_ARG();
671 if (srh_ok++)
672 duparg2("srh", *argv);
673 if (strcmp(*argv, "segs") != 0)
674 invarg("missing \"segs\" attribute for srh\n",
675 *argv);
676 NEXT_ARG();
677 if (segs_ok++)
678 duparg2("segs", *argv);
679 strncpy(segbuf, *argv, 1024);
680 segbuf[1023] = 0;
681 if (!NEXT_ARG_OK())
682 break;
683 NEXT_ARG();
684 if (strcmp(*argv, "hmac") == 0) {
685 NEXT_ARG();
686 if (hmac_ok++)
687 duparg2("hmac", *argv);
688 get_u32(&hmac, *argv, 0);
689 } else {
690 continue;
691 }
692 } else {
693 break;
694 }
695 argc--; argv++;
696 }
697
698 if (!action) {
699 fprintf(stderr, "Missing action type\n");
700 exit(-1);
701 }
702
703 if (srh_ok) {
704 int srhlen;
705
706 srh = parse_srh(segbuf, hmac,
707 action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
708 srhlen = (srh->hdrlen + 1) << 3;
709 rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
710 free(srh);
711 }
712
713 *argcp = argc + 1;
714 *argvp = argv - 1;
715
716 return 0;
717 }
718
719 static int parse_encap_mpls(struct rtattr *rta, size_t len,
720 int *argcp, char ***argvp)
721 {
722 inet_prefix addr;
723 int argc = *argcp;
724 char **argv = *argvp;
725 int ttl_ok = 0;
726
727 if (get_addr(&addr, *argv, AF_MPLS)) {
728 fprintf(stderr,
729 "Error: an inet address is expected rather than \"%s\".\n",
730 *argv);
731 exit(1);
732 }
733
734 rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
735 addr.bytelen);
736
737 argc--;
738 argv++;
739
740 while (argc > 0) {
741 if (strcmp(*argv, "ttl") == 0) {
742 __u8 ttl;
743
744 NEXT_ARG();
745 if (ttl_ok++)
746 duparg2("ttl", *argv);
747 if (get_u8(&ttl, *argv, 0))
748 invarg("\"ttl\" value is invalid\n", *argv);
749 rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl);
750 } else {
751 break;
752 }
753 argc--; argv++;
754 }
755
756 /* argv is currently the first unparsed argument,
757 * but the lwt_parse_encap() caller will move to the next,
758 * so step back
759 */
760 *argcp = argc + 1;
761 *argvp = argv - 1;
762
763 return 0;
764 }
765
766 static int parse_encap_ip(struct rtattr *rta, size_t len,
767 int *argcp, char ***argvp)
768 {
769 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
770 char **argv = *argvp;
771 int argc = *argcp;
772
773 while (argc > 0) {
774 if (strcmp(*argv, "id") == 0) {
775 __u64 id;
776
777 NEXT_ARG();
778 if (id_ok++)
779 duparg2("id", *argv);
780 if (get_be64(&id, *argv, 0))
781 invarg("\"id\" value is invalid\n", *argv);
782 rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
783 } else if (strcmp(*argv, "dst") == 0) {
784 inet_prefix addr;
785
786 NEXT_ARG();
787 if (dst_ok++)
788 duparg2("dst", *argv);
789 get_addr(&addr, *argv, AF_INET);
790 rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
791 &addr.data, addr.bytelen);
792 } else if (strcmp(*argv, "tos") == 0) {
793 __u32 tos;
794
795 NEXT_ARG();
796 if (tos_ok++)
797 duparg2("tos", *argv);
798 if (rtnl_dsfield_a2n(&tos, *argv))
799 invarg("\"tos\" value is invalid\n", *argv);
800 rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
801 } else if (strcmp(*argv, "ttl") == 0) {
802 __u8 ttl;
803
804 NEXT_ARG();
805 if (ttl_ok++)
806 duparg2("ttl", *argv);
807 if (get_u8(&ttl, *argv, 0))
808 invarg("\"ttl\" value is invalid\n", *argv);
809 rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
810 } else {
811 break;
812 }
813 argc--; argv++;
814 }
815
816 /* argv is currently the first unparsed argument,
817 * but the lwt_parse_encap() caller will move to the next,
818 * so step back
819 */
820 *argcp = argc + 1;
821 *argvp = argv - 1;
822
823 return 0;
824 }
825
826 static int parse_encap_ila(struct rtattr *rta, size_t len,
827 int *argcp, char ***argvp)
828 {
829 __u64 locator;
830 int argc = *argcp;
831 char **argv = *argvp;
832
833 if (get_addr64(&locator, *argv) < 0) {
834 fprintf(stderr, "Bad locator: %s\n", *argv);
835 exit(1);
836 }
837
838 argc--; argv++;
839
840 rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
841
842 while (argc > 0) {
843 if (strcmp(*argv, "csum-mode") == 0) {
844 int csum_mode;
845
846 NEXT_ARG();
847
848 csum_mode = ila_csum_name2mode(*argv);
849 if (csum_mode < 0)
850 invarg("\"csum-mode\" value is invalid\n",
851 *argv);
852
853 rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
854 (__u8)csum_mode);
855
856 argc--; argv++;
857 } else if (strcmp(*argv, "ident-type") == 0) {
858 int ident_type;
859
860 NEXT_ARG();
861
862 ident_type = ila_ident_name2type(*argv);
863 if (ident_type < 0)
864 invarg("\"ident-type\" value is invalid\n",
865 *argv);
866
867 rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
868 (__u8)ident_type);
869
870 argc--; argv++;
871 } else if (strcmp(*argv, "hook-type") == 0) {
872 int hook_type;
873
874 NEXT_ARG();
875
876 hook_type = ila_hook_name2type(*argv);
877 if (hook_type < 0)
878 invarg("\"hook-type\" value is invalid\n",
879 *argv);
880
881 rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
882 (__u8)hook_type);
883
884 argc--; argv++;
885 } else {
886 break;
887 }
888 }
889
890 /* argv is currently the first unparsed argument,
891 * but the lwt_parse_encap() caller will move to the next,
892 * so step back
893 */
894 *argcp = argc + 1;
895 *argvp = argv - 1;
896
897 return 0;
898 }
899
900 static int parse_encap_ip6(struct rtattr *rta, size_t len,
901 int *argcp, char ***argvp)
902 {
903 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
904 char **argv = *argvp;
905 int argc = *argcp;
906
907 while (argc > 0) {
908 if (strcmp(*argv, "id") == 0) {
909 __u64 id;
910
911 NEXT_ARG();
912 if (id_ok++)
913 duparg2("id", *argv);
914 if (get_be64(&id, *argv, 0))
915 invarg("\"id\" value is invalid\n", *argv);
916 rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
917 } else if (strcmp(*argv, "dst") == 0) {
918 inet_prefix addr;
919
920 NEXT_ARG();
921 if (dst_ok++)
922 duparg2("dst", *argv);
923 get_addr(&addr, *argv, AF_INET6);
924 rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
925 &addr.data, addr.bytelen);
926 } else if (strcmp(*argv, "tc") == 0) {
927 __u32 tc;
928
929 NEXT_ARG();
930 if (tos_ok++)
931 duparg2("tc", *argv);
932 if (rtnl_dsfield_a2n(&tc, *argv))
933 invarg("\"tc\" value is invalid\n", *argv);
934 rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
935 } else if (strcmp(*argv, "hoplimit") == 0) {
936 __u8 hoplimit;
937
938 NEXT_ARG();
939 if (ttl_ok++)
940 duparg2("hoplimit", *argv);
941 if (get_u8(&hoplimit, *argv, 0))
942 invarg("\"hoplimit\" value is invalid\n",
943 *argv);
944 rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
945 } else {
946 break;
947 }
948 argc--; argv++;
949 }
950
951 /* argv is currently the first unparsed argument,
952 * but the lwt_parse_encap() caller will move to the next,
953 * so step back
954 */
955 *argcp = argc + 1;
956 *argvp = argv - 1;
957
958 return 0;
959 }
960
961 struct lwt_x {
962 struct rtattr *rta;
963 size_t len;
964 };
965
966 static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
967 {
968 struct lwt_x *x = lwt_ptr;
969
970 rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
971 rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
972 strlen(annotation) + 1);
973 }
974
975 static const struct bpf_cfg_ops bpf_cb_ops = {
976 .ebpf_cb = bpf_lwt_cb,
977 };
978
979 static int lwt_parse_bpf(struct rtattr *rta, size_t len,
980 int *argcp, char ***argvp,
981 int attr, const enum bpf_prog_type bpf_type)
982 {
983 struct bpf_cfg_in cfg = {
984 .argc = *argcp,
985 .argv = *argvp,
986 };
987 struct lwt_x x = {
988 .rta = rta,
989 .len = len,
990 };
991 struct rtattr *nest;
992 int err;
993
994 nest = rta_nest(rta, len, attr);
995 err = bpf_parse_common(bpf_type, &cfg, &bpf_cb_ops, &x);
996 if (err < 0) {
997 fprintf(stderr, "Failed to parse eBPF program: %s\n",
998 strerror(-err));
999 return -1;
1000 }
1001 rta_nest_end(rta, nest);
1002
1003 *argcp = cfg.argc;
1004 *argvp = cfg.argv;
1005
1006 return 0;
1007 }
1008
1009 static void lwt_bpf_usage(void)
1010 {
1011 fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
1012 fprintf(stderr, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
1013 exit(-1);
1014 }
1015
1016 static int parse_encap_bpf(struct rtattr *rta, size_t len, int *argcp,
1017 char ***argvp)
1018 {
1019 char **argv = *argvp;
1020 int argc = *argcp;
1021 int headroom_set = 0;
1022
1023 while (argc > 0) {
1024 if (strcmp(*argv, "in") == 0) {
1025 NEXT_ARG();
1026 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_IN,
1027 BPF_PROG_TYPE_LWT_IN) < 0)
1028 return -1;
1029 } else if (strcmp(*argv, "out") == 0) {
1030 NEXT_ARG();
1031 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_OUT,
1032 BPF_PROG_TYPE_LWT_OUT) < 0)
1033 return -1;
1034 } else if (strcmp(*argv, "xmit") == 0) {
1035 NEXT_ARG();
1036 if (lwt_parse_bpf(rta, len, &argc, &argv, LWT_BPF_XMIT,
1037 BPF_PROG_TYPE_LWT_XMIT) < 0)
1038 return -1;
1039 } else if (strcmp(*argv, "headroom") == 0) {
1040 unsigned int headroom;
1041
1042 NEXT_ARG();
1043 if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
1044 invarg("headroom is invalid\n", *argv);
1045 if (!headroom_set)
1046 rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
1047 headroom);
1048 headroom_set = 1;
1049 } else if (strcmp(*argv, "help") == 0) {
1050 lwt_bpf_usage();
1051 } else {
1052 break;
1053 }
1054 NEXT_ARG_FWD();
1055 }
1056
1057 /* argv is currently the first unparsed argument,
1058 * but the lwt_parse_encap() caller will move to the next,
1059 * so step back
1060 */
1061 *argcp = argc + 1;
1062 *argvp = argv - 1;
1063
1064 return 0;
1065 }
1066
1067 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
1068 {
1069 struct rtattr *nest;
1070 int argc = *argcp;
1071 char **argv = *argvp;
1072 __u16 type;
1073
1074 NEXT_ARG();
1075 type = read_encap_type(*argv);
1076 if (!type)
1077 invarg("\"encap type\" value is invalid\n", *argv);
1078
1079 NEXT_ARG();
1080 if (argc <= 1) {
1081 fprintf(stderr,
1082 "Error: unexpected end of line after \"encap\"\n");
1083 exit(-1);
1084 }
1085
1086 nest = rta_nest(rta, 1024, RTA_ENCAP);
1087 switch (type) {
1088 case LWTUNNEL_ENCAP_MPLS:
1089 parse_encap_mpls(rta, len, &argc, &argv);
1090 break;
1091 case LWTUNNEL_ENCAP_IP:
1092 parse_encap_ip(rta, len, &argc, &argv);
1093 break;
1094 case LWTUNNEL_ENCAP_ILA:
1095 parse_encap_ila(rta, len, &argc, &argv);
1096 break;
1097 case LWTUNNEL_ENCAP_IP6:
1098 parse_encap_ip6(rta, len, &argc, &argv);
1099 break;
1100 case LWTUNNEL_ENCAP_BPF:
1101 if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
1102 exit(-1);
1103 break;
1104 case LWTUNNEL_ENCAP_SEG6:
1105 parse_encap_seg6(rta, len, &argc, &argv);
1106 break;
1107 case LWTUNNEL_ENCAP_SEG6_LOCAL:
1108 parse_encap_seg6local(rta, len, &argc, &argv);
1109 break;
1110 default:
1111 fprintf(stderr, "Error: unsupported encap type\n");
1112 break;
1113 }
1114 rta_nest_end(rta, nest);
1115
1116 rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
1117
1118 *argcp = argc;
1119 *argvp = argv;
1120
1121 return 0;
1122 }