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.
9 * Authors: Roopa Prabhu, <roopa@cumulusnetworks.com>
10 * Thomas Graf <tgraf@suug.ch>
19 #include <linux/ila.h>
20 #include <linux/lwtunnel.h>
21 #include <linux/mpls_iptunnel.h>
26 #include "iproute_lwtunnel.h"
29 #include <linux/seg6.h>
30 #include <linux/seg6_iptunnel.h>
31 #include <linux/seg6_hmac.h>
33 static const char *format_encap_type(int type
)
36 case LWTUNNEL_ENCAP_MPLS
:
38 case LWTUNNEL_ENCAP_IP
:
40 case LWTUNNEL_ENCAP_IP6
:
42 case LWTUNNEL_ENCAP_ILA
:
44 case LWTUNNEL_ENCAP_BPF
:
46 case LWTUNNEL_ENCAP_SEG6
:
53 static void encap_type_usage(void)
57 fprintf(stderr
, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
59 for (i
= 1; i
<= LWTUNNEL_ENCAP_MAX
; i
++)
60 fprintf(stderr
, "%s %s\n", format_encap_type(i
),
61 i
== 1 ? "TYPE := " : " ");
66 static int read_encap_type(const char *name
)
68 if (strcmp(name
, "mpls") == 0)
69 return LWTUNNEL_ENCAP_MPLS
;
70 else if (strcmp(name
, "ip") == 0)
71 return LWTUNNEL_ENCAP_IP
;
72 else if (strcmp(name
, "ip6") == 0)
73 return LWTUNNEL_ENCAP_IP6
;
74 else if (strcmp(name
, "ila") == 0)
75 return LWTUNNEL_ENCAP_ILA
;
76 else if (strcmp(name
, "bpf") == 0)
77 return LWTUNNEL_ENCAP_BPF
;
78 else if (strcmp(name
, "seg6") == 0)
79 return LWTUNNEL_ENCAP_SEG6
;
80 else if (strcmp(name
, "help") == 0)
83 return LWTUNNEL_ENCAP_NONE
;
86 static void print_encap_seg6(FILE *fp
, struct rtattr
*encap
)
88 struct rtattr
*tb
[SEG6_IPTUNNEL_MAX
+1];
89 struct seg6_iptunnel_encap
*tuninfo
;
90 struct ipv6_sr_hdr
*srh
;
93 parse_rtattr_nested(tb
, SEG6_IPTUNNEL_MAX
, encap
);
95 if (!tb
[SEG6_IPTUNNEL_SRH
])
98 tuninfo
= RTA_DATA(tb
[SEG6_IPTUNNEL_SRH
]);
99 fprintf(fp
, "mode %s ",
100 (tuninfo
->mode
== SEG6_IPTUN_MODE_ENCAP
) ? "encap" : "inline");
104 fprintf(fp
, "segs %d [ ", srh
->first_segment
+ 1);
106 for (i
= srh
->first_segment
; i
>= 0; i
--)
108 rt_addr_n2a(AF_INET6
, 16, &srh
->segments
[i
]));
112 if (sr_has_hmac(srh
)) {
113 unsigned int offset
= ((srh
->hdrlen
+ 1) << 3) - 40;
114 struct sr6_tlv_hmac
*tlv
;
116 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ offset
);
117 fprintf(fp
, "hmac 0x%X ", ntohl(tlv
->hmackeyid
));
121 static void print_encap_mpls(FILE *fp
, struct rtattr
*encap
)
123 struct rtattr
*tb
[MPLS_IPTUNNEL_MAX
+1];
125 parse_rtattr_nested(tb
, MPLS_IPTUNNEL_MAX
, encap
);
127 if (tb
[MPLS_IPTUNNEL_DST
])
129 format_host_rta(AF_MPLS
, tb
[MPLS_IPTUNNEL_DST
]));
130 if (tb
[MPLS_IPTUNNEL_TTL
])
131 fprintf(fp
, "ttl %u ",
132 rta_getattr_u8(tb
[MPLS_IPTUNNEL_TTL
]));
135 static void print_encap_ip(FILE *fp
, struct rtattr
*encap
)
137 struct rtattr
*tb
[LWTUNNEL_IP_MAX
+1];
139 parse_rtattr_nested(tb
, LWTUNNEL_IP_MAX
, encap
);
141 if (tb
[LWTUNNEL_IP_ID
])
142 fprintf(fp
, "id %llu ",
143 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP_ID
])));
145 if (tb
[LWTUNNEL_IP_SRC
])
146 fprintf(fp
, "src %s ",
147 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_SRC
]));
149 if (tb
[LWTUNNEL_IP_DST
])
150 fprintf(fp
, "dst %s ",
151 rt_addr_n2a_rta(AF_INET
, tb
[LWTUNNEL_IP_DST
]));
153 if (tb
[LWTUNNEL_IP_TTL
])
154 fprintf(fp
, "ttl %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TTL
]));
156 if (tb
[LWTUNNEL_IP_TOS
])
157 fprintf(fp
, "tos %d ", rta_getattr_u8(tb
[LWTUNNEL_IP_TOS
]));
160 static char *ila_csum_mode2name(__u8 csum_mode
)
163 case ILA_CSUM_ADJUST_TRANSPORT
:
164 return "adj-transport";
165 case ILA_CSUM_NEUTRAL_MAP
:
166 return "neutral-map";
167 case ILA_CSUM_NO_ACTION
:
174 static int ila_csum_name2mode(char *name
)
176 if (strcmp(name
, "adj-transport") == 0)
177 return ILA_CSUM_ADJUST_TRANSPORT
;
178 else if (strcmp(name
, "neutral-map") == 0)
179 return ILA_CSUM_NEUTRAL_MAP
;
180 else if (strcmp(name
, "no-action") == 0)
181 return ILA_CSUM_NO_ACTION
;
186 static void print_encap_ila(FILE *fp
, struct rtattr
*encap
)
188 struct rtattr
*tb
[ILA_ATTR_MAX
+1];
190 parse_rtattr_nested(tb
, ILA_ATTR_MAX
, encap
);
192 if (tb
[ILA_ATTR_LOCATOR
]) {
193 char abuf
[ADDR64_BUF_SIZE
];
195 addr64_n2a(rta_getattr_u64(tb
[ILA_ATTR_LOCATOR
]),
197 fprintf(fp
, " %s ", abuf
);
200 if (tb
[ILA_ATTR_CSUM_MODE
])
201 fprintf(fp
, " csum-mode %s ",
202 ila_csum_mode2name(rta_getattr_u8(tb
[ILA_ATTR_CSUM_MODE
])));
205 static void print_encap_ip6(FILE *fp
, struct rtattr
*encap
)
207 struct rtattr
*tb
[LWTUNNEL_IP6_MAX
+1];
209 parse_rtattr_nested(tb
, LWTUNNEL_IP6_MAX
, encap
);
211 if (tb
[LWTUNNEL_IP6_ID
])
212 fprintf(fp
, "id %llu ",
213 ntohll(rta_getattr_u64(tb
[LWTUNNEL_IP6_ID
])));
215 if (tb
[LWTUNNEL_IP6_SRC
])
216 fprintf(fp
, "src %s ",
217 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_SRC
]));
219 if (tb
[LWTUNNEL_IP6_DST
])
220 fprintf(fp
, "dst %s ",
221 rt_addr_n2a_rta(AF_INET6
, tb
[LWTUNNEL_IP6_DST
]));
223 if (tb
[LWTUNNEL_IP6_HOPLIMIT
])
224 fprintf(fp
, "hoplimit %d ",
225 rta_getattr_u8(tb
[LWTUNNEL_IP6_HOPLIMIT
]));
227 if (tb
[LWTUNNEL_IP6_TC
])
228 fprintf(fp
, "tc %d ", rta_getattr_u8(tb
[LWTUNNEL_IP6_TC
]));
231 static void print_encap_bpf_prog(FILE *fp
, struct rtattr
*encap
,
234 struct rtattr
*tb
[LWT_BPF_PROG_MAX
+1];
236 parse_rtattr_nested(tb
, LWT_BPF_PROG_MAX
, encap
);
237 fprintf(fp
, "%s ", str
);
239 if (tb
[LWT_BPF_PROG_NAME
])
240 fprintf(fp
, "%s ", rta_getattr_str(tb
[LWT_BPF_PROG_NAME
]));
243 static void print_encap_bpf(FILE *fp
, struct rtattr
*encap
)
245 struct rtattr
*tb
[LWT_BPF_MAX
+1];
247 parse_rtattr_nested(tb
, LWT_BPF_MAX
, encap
);
250 print_encap_bpf_prog(fp
, tb
[LWT_BPF_IN
], "in");
252 print_encap_bpf_prog(fp
, tb
[LWT_BPF_OUT
], "out");
253 if (tb
[LWT_BPF_XMIT
])
254 print_encap_bpf_prog(fp
, tb
[LWT_BPF_XMIT
], "xmit");
255 if (tb
[LWT_BPF_XMIT_HEADROOM
])
256 fprintf(fp
, "%d ", rta_getattr_u32(tb
[LWT_BPF_XMIT_HEADROOM
]));
259 void lwt_print_encap(FILE *fp
, struct rtattr
*encap_type
,
260 struct rtattr
*encap
)
267 et
= rta_getattr_u16(encap_type
);
269 fprintf(fp
, " encap %s ", format_encap_type(et
));
272 case LWTUNNEL_ENCAP_MPLS
:
273 print_encap_mpls(fp
, encap
);
275 case LWTUNNEL_ENCAP_IP
:
276 print_encap_ip(fp
, encap
);
278 case LWTUNNEL_ENCAP_ILA
:
279 print_encap_ila(fp
, encap
);
281 case LWTUNNEL_ENCAP_IP6
:
282 print_encap_ip6(fp
, encap
);
284 case LWTUNNEL_ENCAP_BPF
:
285 print_encap_bpf(fp
, encap
);
287 case LWTUNNEL_ENCAP_SEG6
:
288 print_encap_seg6(fp
, encap
);
293 static int parse_encap_seg6(struct rtattr
*rta
, size_t len
, int *argcp
,
296 int mode_ok
= 0, segs_ok
= 0, hmac_ok
= 0;
297 struct seg6_iptunnel_encap
*tuninfo
;
298 struct ipv6_sr_hdr
*srh
;
299 char **argv
= *argvp
;
310 if (strcmp(*argv
, "mode") == 0) {
313 duparg2("mode", *argv
);
314 if (strcmp(*argv
, "encap") == 0)
316 else if (strcmp(*argv
, "inline") == 0)
319 invarg("\"mode\" value is invalid\n", *argv
);
320 } else if (strcmp(*argv
, "segs") == 0) {
323 duparg2("segs", *argv
);
325 invarg("\"segs\" provided before \"mode\"\n",
328 strncpy(segbuf
, *argv
, 1024);
330 } else if (strcmp(*argv
, "hmac") == 0) {
333 duparg2("hmac", *argv
);
334 get_u32(&hmac
, *argv
, 0);
342 for (i
= 0; *s
; *s
++ == ',' ? i
++ : *s
);
348 srhlen
= 8 + 16*nsegs
;
353 tuninfo
= malloc(sizeof(*tuninfo
) + srhlen
);
354 memset(tuninfo
, 0, sizeof(*tuninfo
) + srhlen
);
357 tuninfo
->mode
= SEG6_IPTUN_MODE_ENCAP
;
359 tuninfo
->mode
= SEG6_IPTUN_MODE_INLINE
;
362 srh
->hdrlen
= (srhlen
>> 3) - 1;
364 srh
->segments_left
= nsegs
- 1;
365 srh
->first_segment
= nsegs
- 1;
368 srh
->flags
|= SR6_FLAG1_HMAC
;
370 i
= srh
->first_segment
;
371 for (s
= strtok(segbuf
, ","); s
; s
= strtok(NULL
, ",")) {
372 inet_get_addr(s
, NULL
, &srh
->segments
[i
]);
377 struct sr6_tlv_hmac
*tlv
;
379 tlv
= (struct sr6_tlv_hmac
*)((char *)srh
+ srhlen
- 40);
380 tlv
->tlvhdr
.type
= SR6_TLV_HMAC
;
381 tlv
->tlvhdr
.len
= 38;
382 tlv
->hmackeyid
= htonl(hmac
);
385 rta_addattr_l(rta
, len
, SEG6_IPTUNNEL_SRH
, tuninfo
,
386 sizeof(*tuninfo
) + srhlen
);
395 static int parse_encap_mpls(struct rtattr
*rta
, size_t len
,
396 int *argcp
, char ***argvp
)
400 char **argv
= *argvp
;
403 if (get_addr(&addr
, *argv
, AF_MPLS
)) {
405 "Error: an inet address is expected rather than \"%s\".\n",
410 rta_addattr_l(rta
, len
, MPLS_IPTUNNEL_DST
, &addr
.data
,
417 if (strcmp(*argv
, "ttl") == 0) {
422 duparg2("ttl", *argv
);
423 if (get_u8(&ttl
, *argv
, 0))
424 invarg("\"ttl\" value is invalid\n", *argv
);
425 rta_addattr8(rta
, len
, MPLS_IPTUNNEL_TTL
, ttl
);
432 /* argv is currently the first unparsed argument,
433 * but the lwt_parse_encap() caller will move to the next,
442 static int parse_encap_ip(struct rtattr
*rta
, size_t len
,
443 int *argcp
, char ***argvp
)
445 int id_ok
= 0, dst_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
446 char **argv
= *argvp
;
450 if (strcmp(*argv
, "id") == 0) {
455 duparg2("id", *argv
);
456 if (get_be64(&id
, *argv
, 0))
457 invarg("\"id\" value is invalid\n", *argv
);
458 rta_addattr64(rta
, len
, LWTUNNEL_IP_ID
, id
);
459 } else if (strcmp(*argv
, "dst") == 0) {
464 duparg2("dst", *argv
);
465 get_addr(&addr
, *argv
, AF_INET
);
466 rta_addattr_l(rta
, len
, LWTUNNEL_IP_DST
,
467 &addr
.data
, addr
.bytelen
);
468 } else if (strcmp(*argv
, "tos") == 0) {
473 duparg2("tos", *argv
);
474 if (rtnl_dsfield_a2n(&tos
, *argv
))
475 invarg("\"tos\" value is invalid\n", *argv
);
476 rta_addattr8(rta
, len
, LWTUNNEL_IP_TOS
, tos
);
477 } else if (strcmp(*argv
, "ttl") == 0) {
482 duparg2("ttl", *argv
);
483 if (get_u8(&ttl
, *argv
, 0))
484 invarg("\"ttl\" value is invalid\n", *argv
);
485 rta_addattr8(rta
, len
, LWTUNNEL_IP_TTL
, ttl
);
492 /* argv is currently the first unparsed argument,
493 * but the lwt_parse_encap() caller will move to the next,
502 static int parse_encap_ila(struct rtattr
*rta
, size_t len
,
503 int *argcp
, char ***argvp
)
507 char **argv
= *argvp
;
509 if (get_addr64(&locator
, *argv
) < 0) {
510 fprintf(stderr
, "Bad locator: %s\n", *argv
);
516 rta_addattr64(rta
, 1024, ILA_ATTR_LOCATOR
, locator
);
519 if (strcmp(*argv
, "csum-mode") == 0) {
524 csum_mode
= ila_csum_name2mode(*argv
);
526 invarg("\"csum-mode\" value is invalid\n",
529 rta_addattr8(rta
, 1024, ILA_ATTR_CSUM_MODE
,
538 /* argv is currently the first unparsed argument,
539 * but the lwt_parse_encap() caller will move to the next,
548 static int parse_encap_ip6(struct rtattr
*rta
, size_t len
,
549 int *argcp
, char ***argvp
)
551 int id_ok
= 0, dst_ok
= 0, tos_ok
= 0, ttl_ok
= 0;
552 char **argv
= *argvp
;
556 if (strcmp(*argv
, "id") == 0) {
561 duparg2("id", *argv
);
562 if (get_be64(&id
, *argv
, 0))
563 invarg("\"id\" value is invalid\n", *argv
);
564 rta_addattr64(rta
, len
, LWTUNNEL_IP6_ID
, id
);
565 } else if (strcmp(*argv
, "dst") == 0) {
570 duparg2("dst", *argv
);
571 get_addr(&addr
, *argv
, AF_INET6
);
572 rta_addattr_l(rta
, len
, LWTUNNEL_IP6_DST
,
573 &addr
.data
, addr
.bytelen
);
574 } else if (strcmp(*argv
, "tc") == 0) {
579 duparg2("tc", *argv
);
580 if (rtnl_dsfield_a2n(&tc
, *argv
))
581 invarg("\"tc\" value is invalid\n", *argv
);
582 rta_addattr8(rta
, len
, LWTUNNEL_IP6_TC
, tc
);
583 } else if (strcmp(*argv
, "hoplimit") == 0) {
588 duparg2("hoplimit", *argv
);
589 if (get_u8(&hoplimit
, *argv
, 0))
590 invarg("\"hoplimit\" value is invalid\n",
592 rta_addattr8(rta
, len
, LWTUNNEL_IP6_HOPLIMIT
, hoplimit
);
599 /* argv is currently the first unparsed argument,
600 * but the lwt_parse_encap() caller will move to the next,
614 static void bpf_lwt_cb(void *lwt_ptr
, int fd
, const char *annotation
)
616 struct lwt_x
*x
= lwt_ptr
;
618 rta_addattr32(x
->rta
, x
->len
, LWT_BPF_PROG_FD
, fd
);
619 rta_addattr_l(x
->rta
, x
->len
, LWT_BPF_PROG_NAME
, annotation
,
620 strlen(annotation
) + 1);
623 static const struct bpf_cfg_ops bpf_cb_ops
= {
624 .ebpf_cb
= bpf_lwt_cb
,
627 static int lwt_parse_bpf(struct rtattr
*rta
, size_t len
,
628 int *argcp
, char ***argvp
,
629 int attr
, const enum bpf_prog_type bpf_type
)
631 struct bpf_cfg_in cfg
= {
642 nest
= rta_nest(rta
, len
, attr
);
643 err
= bpf_parse_common(bpf_type
, &cfg
, &bpf_cb_ops
, &x
);
645 fprintf(stderr
, "Failed to parse eBPF program: %s\n",
649 rta_nest_end(rta
, nest
);
657 static void lwt_bpf_usage(void)
659 fprintf(stderr
, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
660 fprintf(stderr
, "BPF := obj FILE [ section NAME ] [ verbose ]\n");
664 static int parse_encap_bpf(struct rtattr
*rta
, size_t len
, int *argcp
,
667 char **argv
= *argvp
;
669 int headroom_set
= 0;
672 if (strcmp(*argv
, "in") == 0) {
674 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_IN
,
675 BPF_PROG_TYPE_LWT_IN
) < 0)
677 } else if (strcmp(*argv
, "out") == 0) {
679 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_OUT
,
680 BPF_PROG_TYPE_LWT_OUT
) < 0)
682 } else if (strcmp(*argv
, "xmit") == 0) {
684 if (lwt_parse_bpf(rta
, len
, &argc
, &argv
, LWT_BPF_XMIT
,
685 BPF_PROG_TYPE_LWT_XMIT
) < 0)
687 } else if (strcmp(*argv
, "headroom") == 0) {
688 unsigned int headroom
;
691 if (get_unsigned(&headroom
, *argv
, 0) || headroom
== 0)
692 invarg("headroom is invalid\n", *argv
);
694 rta_addattr32(rta
, 1024, LWT_BPF_XMIT_HEADROOM
,
697 } else if (strcmp(*argv
, "help") == 0) {
705 /* argv is currently the first unparsed argument,
706 * but the lwt_parse_encap() caller will move to the next,
715 int lwt_parse_encap(struct rtattr
*rta
, size_t len
, int *argcp
, char ***argvp
)
719 char **argv
= *argvp
;
723 type
= read_encap_type(*argv
);
725 invarg("\"encap type\" value is invalid\n", *argv
);
730 "Error: unexpected end of line after \"encap\"\n");
734 nest
= rta_nest(rta
, 1024, RTA_ENCAP
);
736 case LWTUNNEL_ENCAP_MPLS
:
737 parse_encap_mpls(rta
, len
, &argc
, &argv
);
739 case LWTUNNEL_ENCAP_IP
:
740 parse_encap_ip(rta
, len
, &argc
, &argv
);
742 case LWTUNNEL_ENCAP_ILA
:
743 parse_encap_ila(rta
, len
, &argc
, &argv
);
745 case LWTUNNEL_ENCAP_IP6
:
746 parse_encap_ip6(rta
, len
, &argc
, &argv
);
748 case LWTUNNEL_ENCAP_BPF
:
749 if (parse_encap_bpf(rta
, len
, &argc
, &argv
) < 0)
752 case LWTUNNEL_ENCAP_SEG6
:
753 parse_encap_seg6(rta
, len
, &argc
, &argv
);
756 fprintf(stderr
, "Error: unsupported encap type\n");
759 rta_nest_end(rta
, nest
);
761 rta_addattr16(rta
, 1024, RTA_ENCAP_TYPE
, type
);