]>
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" | |
010260a7 | 25 | #include "ila_common.h" |
1f483fc6 | 26 | #include "json_print.h" |
ec71cae0 TH |
27 | |
28 | static void usage(void) | |
29 | { | |
a03c704b SH |
30 | fprintf(stderr, |
31 | "Usage: ip ila add loc_match LOCATOR_MATCH loc LOCATOR [ dev DEV ] OPTIONS\n" | |
32 | " ip ila del loc_match LOCATOR_MATCH [ loc LOCATOR ] [ dev DEV ]\n" | |
33 | " ip ila list\n" | |
34 | "OPTIONS := [ csum-mode { adj-transport | neutral-map | neutral-map-auto | no-action } ]\n" | |
35 | " [ ident-type { luid | use-format } ]\n"); | |
ec71cae0 TH |
36 | |
37 | exit(-1); | |
38 | } | |
39 | ||
40 | /* netlink socket */ | |
41 | static struct rtnl_handle genl_rth = { .fd = -1 }; | |
42 | static int genl_family = -1; | |
43 | ||
44 | #define ILA_REQUEST(_req, _bufsiz, _cmd, _flags) \ | |
45 | GENL_REQUEST(_req, _bufsiz, genl_family, 0, \ | |
46 | ILA_GENL_VERSION, _cmd, _flags) | |
47 | ||
48 | #define ILA_RTA(g) ((struct rtattr *)(((char *)(g)) + \ | |
49 | NLMSG_ALIGN(sizeof(struct genlmsghdr)))) | |
50 | ||
1f483fc6 | 51 | static void print_addr64(__u64 addr, char *buff, size_t len) |
ec71cae0 TH |
52 | { |
53 | __u16 *words = (__u16 *)&addr; | |
54 | __u16 v; | |
55 | int i, ret; | |
56 | size_t written = 0; | |
57 | char *sep = ":"; | |
58 | ||
59 | for (i = 0; i < 4; i++) { | |
60 | v = ntohs(words[i]); | |
61 | ||
62 | if (i == 3) | |
63 | sep = ""; | |
64 | ||
65 | ret = snprintf(&buff[written], len - written, "%x%s", v, sep); | |
ec71cae0 TH |
66 | written += ret; |
67 | } | |
ec71cae0 TH |
68 | } |
69 | ||
1f483fc6 | 70 | static void print_ila_locid(const char *tag, int attr, struct rtattr *tb[]) |
ec71cae0 TH |
71 | { |
72 | char abuf[256]; | |
ec71cae0 | 73 | |
1f483fc6 SH |
74 | if (tb[attr]) |
75 | print_addr64(rta_getattr_u64(tb[attr]), | |
76 | abuf, sizeof(abuf)); | |
77 | else | |
78 | snprintf(abuf, sizeof(abuf), "-"); | |
ec71cae0 | 79 | |
1f483fc6 SH |
80 | /* 20 = sizeof("xxxx:xxxx:xxxx:xxxx") */ |
81 | print_string(PRINT_ANY, tag, "%-20s", abuf); | |
ec71cae0 TH |
82 | } |
83 | ||
84 | static int print_ila_mapping(const struct sockaddr_nl *who, | |
85 | struct nlmsghdr *n, void *arg) | |
86 | { | |
ec71cae0 TH |
87 | struct genlmsghdr *ghdr; |
88 | struct rtattr *tb[ILA_ATTR_MAX + 1]; | |
89 | int len = n->nlmsg_len; | |
90 | ||
91 | if (n->nlmsg_type != genl_family) | |
92 | return 0; | |
93 | ||
94 | len -= NLMSG_LENGTH(GENL_HDRLEN); | |
95 | if (len < 0) | |
96 | return -1; | |
97 | ||
98 | ghdr = NLMSG_DATA(n); | |
99 | parse_rtattr(tb, ILA_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len); | |
100 | ||
1f483fc6 SH |
101 | open_json_object(NULL); |
102 | print_ila_locid("locator_match", ILA_ATTR_LOCATOR_MATCH, tb); | |
103 | print_ila_locid("locator", ILA_ATTR_LOCATOR, tb); | |
ec71cae0 | 104 | |
1f483fc6 SH |
105 | if (tb[ILA_ATTR_IFINDEX]) { |
106 | __u32 ifindex | |
107 | = rta_getattr_u32(tb[ILA_ATTR_IFINDEX]); | |
2a1bc2fb | 108 | |
1f483fc6 SH |
109 | print_color_string(PRINT_ANY, COLOR_IFNAME, |
110 | "interface", "%-16s", | |
111 | ll_index_to_name(ifindex)); | |
112 | } else { | |
113 | print_string(PRINT_FP, NULL, "%-10s ", "-"); | |
114 | } | |
115 | ||
116 | if (tb[ILA_ATTR_CSUM_MODE]) { | |
117 | __u8 csum = rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE]); | |
118 | ||
119 | print_string(PRINT_ANY, "csum_mode", "%s", | |
120 | ila_csum_mode2name(csum)); | |
121 | } else | |
122 | print_string(PRINT_FP, NULL, "%-10s ", "-"); | |
86905c8f TH |
123 | |
124 | if (tb[ILA_ATTR_IDENT_TYPE]) | |
1f483fc6 | 125 | print_string(PRINT_ANY, "ident_type", "%s", |
86905c8f TH |
126 | ila_ident_type2name(rta_getattr_u8( |
127 | tb[ILA_ATTR_IDENT_TYPE]))); | |
ec71cae0 | 128 | else |
1f483fc6 | 129 | print_string(PRINT_FP, NULL, "%s", "-"); |
2a1bc2fb | 130 | |
1f483fc6 SH |
131 | print_string(PRINT_FP, NULL, "%s", _SL_); |
132 | close_json_object(); | |
ec71cae0 TH |
133 | |
134 | return 0; | |
135 | } | |
136 | ||
137 | #define NLMSG_BUF_SIZE 4096 | |
138 | ||
139 | static int do_list(int argc, char **argv) | |
140 | { | |
141 | ILA_REQUEST(req, 1024, ILA_CMD_GET, NLM_F_REQUEST | NLM_F_DUMP); | |
142 | ||
143 | if (argc > 0) { | |
144 | fprintf(stderr, "\"ip ila show\" does not take " | |
145 | "any arguments.\n"); | |
146 | return -1; | |
147 | } | |
148 | ||
149 | if (rtnl_send(&genl_rth, (void *)&req, req.n.nlmsg_len) < 0) { | |
150 | perror("Cannot send dump request"); | |
151 | exit(1); | |
152 | } | |
153 | ||
1f483fc6 | 154 | new_json_obj(json); |
ec71cae0 TH |
155 | if (rtnl_dump_filter(&genl_rth, print_ila_mapping, stdout) < 0) { |
156 | fprintf(stderr, "Dump terminated\n"); | |
157 | return 1; | |
158 | } | |
1f483fc6 SH |
159 | delete_json_obj(); |
160 | fflush(stdout); | |
ec71cae0 TH |
161 | |
162 | return 0; | |
163 | } | |
164 | ||
165 | static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n, | |
166 | bool adding) | |
167 | { | |
2d01b393 TH |
168 | __u64 locator = 0; |
169 | __u64 locator_match = 0; | |
ec71cae0 | 170 | int ifindex = 0; |
2a1bc2fb | 171 | int csum_mode = 0; |
86905c8f | 172 | int ident_type = 0; |
ec71cae0 TH |
173 | bool loc_set = false; |
174 | bool loc_match_set = false; | |
175 | bool ifindex_set = false; | |
2a1bc2fb | 176 | bool csum_mode_set = false; |
86905c8f | 177 | bool ident_type_set = false; |
ec71cae0 TH |
178 | |
179 | while (argc > 0) { | |
180 | if (!matches(*argv, "loc")) { | |
181 | NEXT_ARG(); | |
182 | ||
183 | if (get_addr64(&locator, *argv) < 0) { | |
184 | fprintf(stderr, "Bad locator: %s\n", *argv); | |
185 | return -1; | |
186 | } | |
187 | loc_set = true; | |
188 | } else if (!matches(*argv, "loc_match")) { | |
189 | NEXT_ARG(); | |
190 | ||
191 | if (get_addr64(&locator_match, *argv) < 0) { | |
192 | fprintf(stderr, "Bad locator to match: %s\n", | |
193 | *argv); | |
194 | return -1; | |
195 | } | |
196 | loc_match_set = true; | |
2a1bc2fb TH |
197 | } else if (!matches(*argv, "csum-mode")) { |
198 | NEXT_ARG(); | |
199 | ||
200 | csum_mode = ila_csum_name2mode(*argv); | |
201 | if (csum_mode < 0) { | |
202 | fprintf(stderr, "Bad csum-mode: %s\n", | |
203 | *argv); | |
204 | return -1; | |
205 | } | |
206 | csum_mode_set = true; | |
86905c8f TH |
207 | } else if (!matches(*argv, "ident-type")) { |
208 | NEXT_ARG(); | |
209 | ||
210 | ident_type = ila_ident_name2type(*argv); | |
211 | if (ident_type < 0) { | |
212 | fprintf(stderr, "Bad ident-type: %s\n", | |
213 | *argv); | |
214 | return -1; | |
215 | } | |
216 | ident_type_set = true; | |
ec71cae0 TH |
217 | } else if (!matches(*argv, "dev")) { |
218 | NEXT_ARG(); | |
219 | ||
220 | ifindex = ll_name_to_index(*argv); | |
221 | if (ifindex == 0) { | |
222 | fprintf(stderr, "No such interface: %s\n", | |
223 | *argv); | |
224 | return -1; | |
225 | } | |
226 | ifindex_set = true; | |
227 | } else { | |
228 | usage(); | |
229 | return -1; | |
230 | } | |
231 | argc--, argv++; | |
232 | } | |
233 | ||
234 | if (adding) { | |
235 | if (!loc_set) { | |
236 | fprintf(stderr, "ila: missing locator\n"); | |
237 | return -1; | |
238 | } | |
239 | if (!loc_match_set) { | |
240 | fprintf(stderr, "ila: missing locator0match\n"); | |
241 | return -1; | |
242 | } | |
243 | } | |
244 | ||
2d01b393 TH |
245 | if (loc_match_set) |
246 | addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match); | |
247 | ||
248 | if (loc_set) | |
249 | addattr64(n, 1024, ILA_ATTR_LOCATOR, locator); | |
ec71cae0 TH |
250 | |
251 | if (ifindex_set) | |
252 | addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex); | |
253 | ||
2a1bc2fb TH |
254 | if (csum_mode_set) |
255 | addattr8(n, 1024, ILA_ATTR_CSUM_MODE, csum_mode); | |
256 | ||
86905c8f TH |
257 | if (ident_type_set) |
258 | addattr8(n, 1024, ILA_ATTR_IDENT_TYPE, ident_type); | |
259 | ||
ec71cae0 TH |
260 | return 0; |
261 | } | |
262 | ||
263 | static int do_add(int argc, char **argv) | |
264 | { | |
265 | ILA_REQUEST(req, 1024, ILA_CMD_ADD, NLM_F_REQUEST); | |
266 | ||
267 | ila_parse_opt(argc, argv, &req.n, true); | |
268 | ||
86bf43c7 | 269 | if (rtnl_talk(&genl_rth, &req.n, NULL) < 0) |
ec71cae0 TH |
270 | return -2; |
271 | ||
272 | return 0; | |
273 | } | |
274 | ||
275 | static int do_del(int argc, char **argv) | |
276 | { | |
277 | ILA_REQUEST(req, 1024, ILA_CMD_DEL, NLM_F_REQUEST); | |
278 | ||
279 | ila_parse_opt(argc, argv, &req.n, false); | |
280 | ||
86bf43c7 | 281 | if (rtnl_talk(&genl_rth, &req.n, NULL) < 0) |
ec71cae0 TH |
282 | return -2; |
283 | ||
284 | return 0; | |
285 | } | |
286 | ||
287 | int do_ipila(int argc, char **argv) | |
288 | { | |
ec71cae0 TH |
289 | if (argc < 1) |
290 | usage(); | |
291 | ||
9423a324 SD |
292 | if (matches(*argv, "help") == 0) |
293 | usage(); | |
294 | ||
295 | if (genl_init_handle(&genl_rth, ILA_GENL_NAME, &genl_family)) | |
296 | exit(1); | |
297 | ||
ec71cae0 TH |
298 | if (matches(*argv, "add") == 0) |
299 | return do_add(argc-1, argv+1); | |
300 | if (matches(*argv, "delete") == 0) | |
301 | return do_del(argc-1, argv+1); | |
302 | if (matches(*argv, "list") == 0) | |
303 | return do_list(argc-1, argv+1); | |
ec71cae0 TH |
304 | |
305 | fprintf(stderr, "Command \"%s\" is unknown, try \"ip ila help\".\n", | |
306 | *argv); | |
307 | exit(-1); | |
308 | } |