]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute_lwtunnel.c
lwtunnel: Add encapsulation support to ip route
[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/lwtunnel.h>
20 #include <linux/mpls_iptunnel.h>
21 #include <errno.h>
22
23 #include "rt_names.h"
24 #include "utils.h"
25 #include "iproute_lwtunnel.h"
26
27 static int read_encap_type(const char *name)
28 {
29 if (strcmp(name, "mpls") == 0)
30 return LWTUNNEL_ENCAP_MPLS;
31 else if (strcmp(name, "ip") == 0)
32 return LWTUNNEL_ENCAP_IP;
33 else if (strcmp(name, "ip6") == 0)
34 return LWTUNNEL_ENCAP_IP6;
35 else
36 return LWTUNNEL_ENCAP_NONE;
37 }
38
39 static const char *format_encap_type(int type)
40 {
41 switch (type) {
42 case LWTUNNEL_ENCAP_MPLS:
43 return "mpls";
44 case LWTUNNEL_ENCAP_IP:
45 return "ip";
46 case LWTUNNEL_ENCAP_IP6:
47 return "ip6";
48 default:
49 return "unknown";
50 }
51 }
52
53 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
54 {
55 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
56 char abuf[256];
57
58 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
59
60 if (tb[MPLS_IPTUNNEL_DST])
61 fprintf(fp, " %s ", format_host(AF_MPLS,
62 RTA_PAYLOAD(tb[MPLS_IPTUNNEL_DST]),
63 RTA_DATA(tb[MPLS_IPTUNNEL_DST]),
64 abuf, sizeof(abuf)));
65 }
66
67 static void print_encap_ip(FILE *fp, struct rtattr *encap)
68 {
69 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
70 char abuf[256];
71
72 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
73
74 if (tb[LWTUNNEL_IP_ID])
75 fprintf(fp, "id %llu ", ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
76
77 if (tb[LWTUNNEL_IP_SRC])
78 fprintf(fp, "src %s ",
79 rt_addr_n2a(AF_INET,
80 RTA_PAYLOAD(tb[LWTUNNEL_IP_SRC]),
81 RTA_DATA(tb[LWTUNNEL_IP_SRC]),
82 abuf, sizeof(abuf)));
83
84 if (tb[LWTUNNEL_IP_DST])
85 fprintf(fp, "dst %s ",
86 rt_addr_n2a(AF_INET,
87 RTA_PAYLOAD(tb[LWTUNNEL_IP_DST]),
88 RTA_DATA(tb[LWTUNNEL_IP_DST]),
89 abuf, sizeof(abuf)));
90
91 if (tb[LWTUNNEL_IP_TTL])
92 fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
93
94 if (tb[LWTUNNEL_IP_TOS])
95 fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
96 }
97
98 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
99 struct rtattr *encap)
100 {
101 int et;
102
103 if (!encap_type)
104 return;
105
106 et = rta_getattr_u16(encap_type);
107
108 fprintf(fp, " encap %s", format_encap_type(et));
109
110 switch (et) {
111 case LWTUNNEL_ENCAP_MPLS:
112 print_encap_mpls(fp, encap);
113 break;
114 case LWTUNNEL_ENCAP_IP:
115 print_encap_ip(fp, encap);
116 break;
117 }
118 }
119
120 static int parse_encap_mpls(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
121 {
122 inet_prefix addr;
123 int argc = *argcp;
124 char **argv = *argvp;
125
126 if (get_addr(&addr, *argv, AF_MPLS)) {
127 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", *argv);
128 exit(1);
129 }
130
131 rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
132 addr.bytelen);
133
134 *argcp = argc;
135 *argvp = argv;
136
137 return 0;
138 }
139
140 static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
141 {
142 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
143 char **argv = *argvp;
144 int argc = *argcp;
145
146 while (argc > 0) {
147 if (strcmp(*argv, "id") == 0) {
148 __u64 id;
149 NEXT_ARG();
150 if (id_ok++)
151 duparg2("id", *argv);
152 if (get_u64(&id, *argv, 0))
153 invarg("\"id\" value is invalid\n", *argv);
154 rta_addattr64(rta, len, LWTUNNEL_IP_ID, htonll(id));
155 } else if (strcmp(*argv, "dst") == 0) {
156 inet_prefix addr;
157 NEXT_ARG();
158 if (dst_ok++)
159 duparg2("dst", *argv);
160 get_addr(&addr, *argv, AF_INET);
161 rta_addattr_l(rta, len, LWTUNNEL_IP_DST, &addr.data, addr.bytelen);
162 } else if (strcmp(*argv, "tos") == 0) {
163 __u32 tos;
164 NEXT_ARG();
165 if (tos_ok++)
166 duparg2("tos", *argv);
167 if (rtnl_dsfield_a2n(&tos, *argv))
168 invarg("\"tos\" value is invalid\n", *argv);
169 rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
170 } else if (strcmp(*argv, "ttl") == 0) {
171 __u8 ttl;
172 NEXT_ARG();
173 if (ttl_ok++)
174 duparg2("ttl", *argv);
175 if (get_u8(&ttl, *argv, 0))
176 invarg("\"ttl\" value is invalid\n", *argv);
177 rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
178 } else {
179 break;
180 }
181 }
182
183 *argcp = argc;
184 *argvp = argv;
185
186 return 0;
187 }
188
189
190 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
191 {
192 struct rtattr *nest;
193 int argc = *argcp;
194 char **argv = *argvp;
195 __u16 type;
196
197 NEXT_ARG();
198 type = read_encap_type(*argv);
199 if (!type)
200 invarg("\"encap type\" value is invalid\n", *argv);
201
202 NEXT_ARG();
203 if (argc <= 1) {
204 fprintf(stderr, "Error: unexpected end of line after \"encap\"\n");
205 exit(-1);
206 }
207
208 nest = rta_nest(rta, 1024, RTA_ENCAP);
209 switch (type) {
210 case LWTUNNEL_ENCAP_MPLS:
211 parse_encap_mpls(rta, len, &argc, &argv);
212 break;
213 case LWTUNNEL_ENCAP_IP:
214 parse_encap_ip(rta, len, &argc, &argv);
215 break;
216 default:
217 fprintf(stderr, "Error: unsupported encap type\n");
218 break;
219 }
220 rta_nest_end(rta, nest);
221
222 rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
223
224 *argcp = argc;
225 *argvp = argv;
226
227 return 0;
228 }