]>
Commit | Line | Data |
---|---|---|
ec71cae0 TH |
1 | /* |
2 | * ipila.c ILA (Identifier Locator Addressing) support | |
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: Tom Herbert <tom@herbertland.com> | |
10 | */ | |
11 | ||
12 | #include <netdb.h> | |
13 | #include <stdio.h> | |
14 | #include <stdlib.h> | |
15 | #include <string.h> | |
16 | #include <net/if.h> | |
17 | #include <linux/ila.h> | |
18 | #include <linux/genetlink.h> | |
19 | #include <linux/ip.h> | |
20 | #include <arpa/inet.h> | |
21 | ||
22 | #include "libgenl.h" | |
23 | #include "utils.h" | |
24 | #include "ip_common.h" | |
25 | ||
26 | static void usage(void) | |
27 | { | |
28 | fprintf(stderr, "Usage: ip ila add loc_match LOCATOR_MATCH " | |
2a1bc2fb TH |
29 | "loc LOCATOR [ dev DEV ] " |
30 | "[ csum-mode { adj-transport | neutral-map | " | |
86905c8f TH |
31 | "neutral-map-auto | no-action } ] " |
32 | "[ ident-type { luid | use-format } ]\n"); | |
ec71cae0 TH |
33 | fprintf(stderr, " ip ila del loc_match LOCATOR_MATCH " |
34 | "[ loc LOCATOR ] [ dev DEV ]\n"); | |
35 | fprintf(stderr, " ip ila list\n"); | |
36 | fprintf(stderr, "\n"); | |
37 | ||
38 | exit(-1); | |
39 | } | |
40 | ||
41 | /* netlink socket */ | |
42 | static struct rtnl_handle genl_rth = { .fd = -1 }; | |
43 | static int genl_family = -1; | |
44 | ||
45 | #define ILA_REQUEST(_req, _bufsiz, _cmd, _flags) \ | |
46 | GENL_REQUEST(_req, _bufsiz, genl_family, 0, \ | |
47 | ILA_GENL_VERSION, _cmd, _flags) | |
48 | ||
49 | #define ILA_RTA(g) ((struct rtattr *)(((char *)(g)) + \ | |
50 | NLMSG_ALIGN(sizeof(struct genlmsghdr)))) | |
51 | ||
52 | #define ADDR_BUF_SIZE sizeof("xxxx:xxxx:xxxx:xxxx") | |
53 | ||
2a1bc2fb TH |
54 | static char *ila_csum_mode2name(__u8 csum_mode) |
55 | { | |
56 | switch (csum_mode) { | |
57 | case ILA_CSUM_ADJUST_TRANSPORT: | |
58 | return "adj-transport"; | |
59 | case ILA_CSUM_NEUTRAL_MAP: | |
60 | return "neutral-map"; | |
61 | case ILA_CSUM_NO_ACTION: | |
62 | return "no-action"; | |
11775523 TH |
63 | case ILA_CSUM_NEUTRAL_MAP_AUTO: |
64 | return "neutral-map-auto"; | |
2a1bc2fb TH |
65 | default: |
66 | return "unknown"; | |
67 | } | |
68 | } | |
69 | ||
70 | static int ila_csum_name2mode(char *name) | |
71 | { | |
72 | if (strcmp(name, "adj-transport") == 0) | |
73 | return ILA_CSUM_ADJUST_TRANSPORT; | |
74 | else if (strcmp(name, "neutral-map") == 0) | |
75 | return ILA_CSUM_NEUTRAL_MAP; | |
11775523 TH |
76 | else if (strcmp(name, "neutral-map-auto") == 0) |
77 | return ILA_CSUM_NEUTRAL_MAP_AUTO; | |
86905c8f TH |
78 | else if (strcmp(name, "no-action") == 0) |
79 | return ILA_CSUM_NO_ACTION; | |
80 | else if (strcmp(name, "neutral-map-auto") == 0) | |
81 | return ILA_CSUM_NEUTRAL_MAP_AUTO; | |
82 | else | |
83 | return -1; | |
84 | } | |
85 | ||
86 | static char *ila_ident_type2name(__u8 ident_type) | |
87 | { | |
88 | switch (ident_type) { | |
89 | case ILA_ATYPE_IID: | |
90 | return "iid"; | |
91 | case ILA_ATYPE_LUID: | |
92 | return "luid"; | |
93 | case ILA_ATYPE_VIRT_V4: | |
94 | return "virt-v4"; | |
95 | case ILA_ATYPE_VIRT_UNI_V6: | |
96 | return "virt-uni-v6"; | |
97 | case ILA_ATYPE_VIRT_MULTI_V6: | |
98 | return "virt-multi-v6"; | |
99 | case ILA_ATYPE_NONLOCAL_ADDR: | |
100 | return "nonlocal-addr"; | |
101 | case ILA_ATYPE_USE_FORMAT: | |
102 | return "use-format"; | |
103 | default: | |
104 | return "unknown"; | |
105 | } | |
106 | } | |
107 | ||
108 | static int ila_ident_name2type(char *name) | |
109 | { | |
110 | if (!strcmp(name, "luid")) | |
111 | return ILA_ATYPE_LUID; | |
112 | else if (!strcmp(name, "use-format")) | |
113 | return ILA_ATYPE_USE_FORMAT; | |
114 | #if 0 /* No kernel support for configuring these yet */ | |
115 | else if (!strcmp(name, "iid")) | |
116 | return ILA_ATYPE_IID; | |
117 | else if (!strcmp(name, "virt-v4")) | |
118 | return ILA_ATYPE_VIRT_V4; | |
119 | else if (!strcmp(name, "virt-uni-v6")) | |
120 | return ILA_ATYPE_VIRT_UNI_V6; | |
121 | else if (!strcmp(name, "virt-multi-v6")) | |
122 | return ILA_ATYPE_VIRT_MULTI_V6; | |
123 | else if (!strcmp(name, "nonlocal-addr")) | |
124 | return ILA_ATYPE_NONLOCAL_ADDR; | |
125 | #endif | |
2a1bc2fb TH |
126 | else |
127 | return -1; | |
128 | } | |
129 | ||
ec71cae0 TH |
130 | static int print_addr64(__u64 addr, char *buff, size_t len) |
131 | { | |
132 | __u16 *words = (__u16 *)&addr; | |
133 | __u16 v; | |
134 | int i, ret; | |
135 | size_t written = 0; | |
136 | char *sep = ":"; | |
137 | ||
138 | for (i = 0; i < 4; i++) { | |
139 | v = ntohs(words[i]); | |
140 | ||
141 | if (i == 3) | |
142 | sep = ""; | |
143 | ||
144 | ret = snprintf(&buff[written], len - written, "%x%s", v, sep); | |
145 | if (ret < 0) | |
146 | return ret; | |
147 | ||
148 | written += ret; | |
149 | } | |
150 | ||
151 | return written; | |
152 | } | |
153 | ||
154 | static void print_ila_locid(FILE *fp, int attr, struct rtattr *tb[], int space) | |
155 | { | |
156 | char abuf[256]; | |
157 | size_t blen; | |
158 | int i; | |
159 | ||
160 | if (tb[attr]) { | |
d3357cfc | 161 | blen = print_addr64(rta_getattr_u64(tb[attr]), |
ec71cae0 TH |
162 | abuf, sizeof(abuf)); |
163 | fprintf(fp, "%s", abuf); | |
164 | } else { | |
165 | fprintf(fp, "-"); | |
166 | blen = 1; | |
167 | } | |
168 | ||
169 | for (i = 0; i < space - blen; i++) | |
170 | fprintf(fp, " "); | |
171 | } | |
172 | ||
173 | static int print_ila_mapping(const struct sockaddr_nl *who, | |
174 | struct nlmsghdr *n, void *arg) | |
175 | { | |
176 | FILE *fp = (FILE *)arg; | |
177 | struct genlmsghdr *ghdr; | |
178 | struct rtattr *tb[ILA_ATTR_MAX + 1]; | |
179 | int len = n->nlmsg_len; | |
180 | ||
181 | if (n->nlmsg_type != genl_family) | |
182 | return 0; | |
183 | ||
184 | len -= NLMSG_LENGTH(GENL_HDRLEN); | |
185 | if (len < 0) | |
186 | return -1; | |
187 | ||
188 | ghdr = NLMSG_DATA(n); | |
189 | parse_rtattr(tb, ILA_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); | |
190 | ||
191 | print_ila_locid(fp, ILA_ATTR_LOCATOR_MATCH, tb, ADDR_BUF_SIZE); | |
192 | print_ila_locid(fp, ILA_ATTR_LOCATOR, tb, ADDR_BUF_SIZE); | |
193 | ||
194 | if (tb[ILA_ATTR_IFINDEX]) | |
2a1bc2fb TH |
195 | fprintf(fp, "%-16s", |
196 | ll_index_to_name(rta_getattr_u32( | |
197 | tb[ILA_ATTR_IFINDEX]))); | |
198 | else | |
86905c8f | 199 | fprintf(fp, "%-10s ", "-"); |
2a1bc2fb TH |
200 | |
201 | if (tb[ILA_ATTR_CSUM_MODE]) | |
202 | fprintf(fp, "%s", | |
203 | ila_csum_mode2name(rta_getattr_u8( | |
204 | tb[ILA_ATTR_CSUM_MODE]))); | |
86905c8f TH |
205 | else |
206 | fprintf(fp, "%-10s ", "-"); | |
207 | ||
208 | if (tb[ILA_ATTR_IDENT_TYPE]) | |
209 | fprintf(fp, "%s", | |
210 | ila_ident_type2name(rta_getattr_u8( | |
211 | tb[ILA_ATTR_IDENT_TYPE]))); | |
ec71cae0 TH |
212 | else |
213 | fprintf(fp, "-"); | |
2a1bc2fb | 214 | |
ec71cae0 TH |
215 | fprintf(fp, "\n"); |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
220 | #define NLMSG_BUF_SIZE 4096 | |
221 | ||
222 | static int do_list(int argc, char **argv) | |
223 | { | |
224 | ILA_REQUEST(req, 1024, ILA_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP); | |
225 | ||
226 | if (argc > 0) { | |
227 | fprintf(stderr, "\"ip ila show\" does not take " | |
228 | "any arguments.\n"); | |
229 | return -1; | |
230 | } | |
231 | ||
232 | if (rtnl_send(&genl_rth, (void *)&req, req.n.nlmsg_len) < 0) { | |
233 | perror("Cannot send dump request"); | |
234 | exit(1); | |
235 | } | |
236 | ||
237 | if (rtnl_dump_filter(&genl_rth, print_ila_mapping, stdout) < 0) { | |
238 | fprintf(stderr, "Dump terminated\n"); | |
239 | return 1; | |
240 | } | |
241 | ||
242 | return 0; | |
243 | } | |
244 | ||
245 | static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n, | |
246 | bool adding) | |
247 | { | |
2d01b393 TH |
248 | __u64 locator = 0; |
249 | __u64 locator_match = 0; | |
ec71cae0 | 250 | int ifindex = 0; |
2a1bc2fb | 251 | int csum_mode = 0; |
86905c8f | 252 | int ident_type = 0; |
ec71cae0 TH |
253 | bool loc_set = false; |
254 | bool loc_match_set = false; | |
255 | bool ifindex_set = false; | |
2a1bc2fb | 256 | bool csum_mode_set = false; |
86905c8f | 257 | bool ident_type_set = false; |
ec71cae0 TH |
258 | |
259 | while (argc > 0) { | |
260 | if (!matches(*argv, "loc")) { | |
261 | NEXT_ARG(); | |
262 | ||
263 | if (get_addr64(&locator, *argv) < 0) { | |
264 | fprintf(stderr, "Bad locator: %s\n", *argv); | |
265 | return -1; | |
266 | } | |
267 | loc_set = true; | |
268 | } else if (!matches(*argv, "loc_match")) { | |
269 | NEXT_ARG(); | |
270 | ||
271 | if (get_addr64(&locator_match, *argv) < 0) { | |
272 | fprintf(stderr, "Bad locator to match: %s\n", | |
273 | *argv); | |
274 | return -1; | |
275 | } | |
276 | loc_match_set = true; | |
2a1bc2fb TH |
277 | } else if (!matches(*argv, "csum-mode")) { |
278 | NEXT_ARG(); | |
279 | ||
280 | csum_mode = ila_csum_name2mode(*argv); | |
281 | if (csum_mode < 0) { | |
282 | fprintf(stderr, "Bad csum-mode: %s\n", | |
283 | *argv); | |
284 | return -1; | |
285 | } | |
286 | csum_mode_set = true; | |
86905c8f TH |
287 | } else if (!matches(*argv, "ident-type")) { |
288 | NEXT_ARG(); | |
289 | ||
290 | ident_type = ila_ident_name2type(*argv); | |
291 | if (ident_type < 0) { | |
292 | fprintf(stderr, "Bad ident-type: %s\n", | |
293 | *argv); | |
294 | return -1; | |
295 | } | |
296 | ident_type_set = true; | |
ec71cae0 TH |
297 | } else if (!matches(*argv, "dev")) { |
298 | NEXT_ARG(); | |
299 | ||
300 | ifindex = ll_name_to_index(*argv); | |
301 | if (ifindex == 0) { | |
302 | fprintf(stderr, "No such interface: %s\n", | |
303 | *argv); | |
304 | return -1; | |
305 | } | |
306 | ifindex_set = true; | |
307 | } else { | |
308 | usage(); | |
309 | return -1; | |
310 | } | |
311 | argc--, argv++; | |
312 | } | |
313 | ||
314 | if (adding) { | |
315 | if (!loc_set) { | |
316 | fprintf(stderr, "ila: missing locator\n"); | |
317 | return -1; | |
318 | } | |
319 | if (!loc_match_set) { | |
320 | fprintf(stderr, "ila: missing locator0match\n"); | |
321 | return -1; | |
322 | } | |
323 | } | |
324 | ||
2d01b393 TH |
325 | if (loc_match_set) |
326 | addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); | |
327 | ||
328 | if (loc_set) | |
329 | addattr64(n, 1024, ILA_ATTR_LOCATOR, locator); | |
ec71cae0 TH |
330 | |
331 | if (ifindex_set) | |
332 | addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex); | |
333 | ||
2a1bc2fb TH |
334 | if (csum_mode_set) |
335 | addattr8(n, 1024, ILA_ATTR_CSUM_MODE, csum_mode); | |
336 | ||
86905c8f TH |
337 | if (ident_type_set) |
338 | addattr8(n, 1024, ILA_ATTR_IDENT_TYPE, ident_type); | |
339 | ||
ec71cae0 TH |
340 | return 0; |
341 | } | |
342 | ||
343 | static int do_add(int argc, char **argv) | |
344 | { | |
345 | ILA_REQUEST(req, 1024, ILA_CMD_ADD, NLM_F_REQUEST); | |
346 | ||
347 | ila_parse_opt(argc, argv, &req.n, true); | |
348 | ||
86bf43c7 | 349 | if (rtnl_talk(&genl_rth, &req.n, NULL) < 0) |
ec71cae0 TH |
350 | return -2; |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
355 | static int do_del(int argc, char **argv) | |
356 | { | |
357 | ILA_REQUEST(req, 1024, ILA_CMD_DEL, NLM_F_REQUEST); | |
358 | ||
359 | ila_parse_opt(argc, argv, &req.n, false); | |
360 | ||
86bf43c7 | 361 | if (rtnl_talk(&genl_rth, &req.n, NULL) < 0) |
ec71cae0 TH |
362 | return -2; |
363 | ||
364 | return 0; | |
365 | } | |
366 | ||
367 | int do_ipila(int argc, char **argv) | |
368 | { | |
ec71cae0 TH |
369 | if (argc < 1) |
370 | usage(); | |
371 | ||
9423a324 SD |
372 | if (matches(*argv, "help") == 0) |
373 | usage(); | |
374 | ||
375 | if (genl_init_handle(&genl_rth, ILA_GENL_NAME, &genl_family)) | |
376 | exit(1); | |
377 | ||
ec71cae0 TH |
378 | if (matches(*argv, "add") == 0) |
379 | return do_add(argc-1, argv+1); | |
380 | if (matches(*argv, "delete") == 0) | |
381 | return do_del(argc-1, argv+1); | |
382 | if (matches(*argv, "list") == 0) | |
383 | return do_list(argc-1, argv+1); | |
ec71cae0 TH |
384 | |
385 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip ila help\".\n", | |
386 | *argv); | |
387 | exit(-1); | |
388 | } |