]> git.proxmox.com Git - mirror_iproute2.git/blob - tipc/bearer.c
Merge branch 'master' into net-next
[mirror_iproute2.git] / tipc / bearer.c
1 /*
2 * bearer.c TIPC bearer functionality.
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: Richard Alpe <richard.alpe@ericsson.com>
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <netdb.h>
16 #include <errno.h>
17
18 #include <linux/tipc_netlink.h>
19 #include <linux/tipc.h>
20 #include <linux/genetlink.h>
21
22 #include <libmnl/libmnl.h>
23 #include <sys/socket.h>
24
25 #include "cmdl.h"
26 #include "msg.h"
27 #include "bearer.h"
28
29 static void _print_bearer_opts(void)
30 {
31 fprintf(stderr,
32 "OPTIONS\n"
33 " priority - Bearer link priority\n"
34 " tolerance - Bearer link tolerance\n"
35 " window - Bearer link window\n");
36 }
37
38 static void _print_bearer_media(void)
39 {
40 fprintf(stderr,
41 "\nMEDIA\n"
42 " udp - User Datagram Protocol\n"
43 " ib - Infiniband\n"
44 " eth - Ethernet\n");
45 }
46
47 static void cmd_bearer_enable_l2_help(struct cmdl *cmdl, char *media)
48 {
49 fprintf(stderr,
50 "Usage: %s bearer enable media %s device DEVICE [OPTIONS]\n"
51 "\nOPTIONS\n"
52 " domain DOMAIN - Discovery domain\n"
53 " priority PRIORITY - Bearer priority\n",
54 cmdl->argv[0], media);
55 }
56
57 static void cmd_bearer_enable_udp_help(struct cmdl *cmdl, char *media)
58 {
59 fprintf(stderr,
60 "Usage: %s bearer enable media %s name NAME localip IP [OPTIONS]\n"
61 "\nOPTIONS\n"
62 " domain DOMAIN - Discovery domain\n"
63 " priority PRIORITY - Bearer priority\n"
64 " localport PORT - Local UDP port (default 6118)\n"
65 " remoteip IP - Remote IP address\n"
66 " remoteport IP - Remote UDP port (default 6118)\n",
67 cmdl->argv[0], media);
68 }
69
70 static int get_netid_cb(const struct nlmsghdr *nlh, void *data)
71 {
72 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
73 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
74 struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
75 int *netid = (int*)data;
76
77 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
78 if (!info[TIPC_NLA_NET])
79 return MNL_CB_ERROR;
80 mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
81 if (!attrs[TIPC_NLA_NET_ID])
82 return MNL_CB_ERROR;
83 *netid = mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]);
84
85 return MNL_CB_OK;
86 }
87
88 static int generate_multicast(short af, char *buf, int bufsize)
89 {
90 int netid;
91 char mnl_msg[MNL_SOCKET_BUFFER_SIZE];
92 struct nlmsghdr *nlh;
93
94 if (!(nlh = msg_init(mnl_msg, TIPC_NL_NET_GET))) {
95 fprintf(stderr, "error, message initialization failed\n");
96 return -1;
97 }
98 if (msg_dumpit(nlh, get_netid_cb, &netid)) {
99 fprintf(stderr, "error, failed to fetch TIPC network id from kernel\n");
100 return -EINVAL;
101 }
102 if (af == AF_INET)
103 snprintf(buf, bufsize, "228.0.%u.%u", (netid>>8) & 0xFF, netid & 0xFF);
104 else
105 snprintf(buf, bufsize, "ff02::%u", netid);
106
107 return 0;
108 }
109
110 static int nl_add_udp_enable_opts(struct nlmsghdr *nlh, struct opt *opts,
111 struct cmdl *cmdl)
112 {
113 int err;
114 struct opt *opt;
115 struct nlattr *nest;
116 char buf[INET6_ADDRSTRLEN];
117 char *locport = "6118";
118 char *remport = "6118";
119 char *locip = NULL;
120 char *remip = NULL;
121 struct addrinfo *loc = NULL;
122 struct addrinfo *rem = NULL;
123 struct addrinfo hints = {
124 .ai_family = AF_UNSPEC,
125 .ai_socktype = SOCK_DGRAM
126 };
127
128 if (!(opt = get_opt(opts, "localip"))) {
129 fprintf(stderr, "error, udp bearer localip missing\n");
130 cmd_bearer_enable_udp_help(cmdl, "udp");
131 return -EINVAL;
132 }
133 locip = opt->val;
134
135 if ((opt = get_opt(opts, "remoteip")))
136 remip = opt->val;
137
138 if ((opt = get_opt(opts, "localport")))
139 locport = opt->val;
140
141 if ((opt = get_opt(opts, "remoteport")))
142 remport = opt->val;
143
144 if ((err = getaddrinfo(locip, locport, &hints, &loc))) {
145 fprintf(stderr, "UDP local address error: %s\n",
146 gai_strerror(err));
147 return err;
148 }
149
150 if (!remip) {
151 if (generate_multicast(loc->ai_family, buf, sizeof(buf))) {
152 fprintf(stderr, "Failed to generate multicast address\n");
153 return -EINVAL;
154 }
155 remip = buf;
156 }
157
158 if ((err = getaddrinfo(remip, remport, &hints, &rem))) {
159 fprintf(stderr, "UDP remote address error: %s\n",
160 gai_strerror(err));
161 freeaddrinfo(loc);
162 return err;
163 }
164
165 if (rem->ai_family != loc->ai_family) {
166 fprintf(stderr, "UDP local and remote AF mismatch\n");
167 return -EINVAL;
168 }
169
170 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_UDP_OPTS);
171 mnl_attr_put(nlh, TIPC_NLA_UDP_LOCAL, loc->ai_addrlen, loc->ai_addr);
172 mnl_attr_put(nlh, TIPC_NLA_UDP_REMOTE, rem->ai_addrlen, rem->ai_addr);
173 mnl_attr_nest_end(nlh, nest);
174
175 freeaddrinfo(rem);
176 freeaddrinfo(loc);
177
178 return 0;
179 }
180
181 static int nl_add_bearer_name(struct nlmsghdr *nlh, const struct cmd *cmd,
182 struct cmdl *cmdl, struct opt *opts,
183 struct tipc_sup_media sup_media[])
184 {
185 char id[TIPC_MAX_BEARER_NAME];
186 char *media;
187 char *identifier;
188 struct opt *opt;
189 struct tipc_sup_media *entry;
190
191 if (!(opt = get_opt(opts, "media"))) {
192 if (help_flag)
193 (cmd->help)(cmdl);
194 else
195 fprintf(stderr, "error, missing bearer media\n");
196 return -EINVAL;
197 }
198 media = opt->val;
199
200 for (entry = sup_media; entry->media; entry++) {
201 if (strcmp(entry->media, media))
202 continue;
203
204 if (!(opt = get_opt(opts, entry->identifier))) {
205 if (help_flag)
206 (entry->help)(cmdl, media);
207 else
208 fprintf(stderr, "error, missing bearer %s\n",
209 entry->identifier);
210 return -EINVAL;
211 }
212
213 identifier = opt->val;
214 snprintf(id, sizeof(id), "%s:%s", media, identifier);
215 mnl_attr_put_strz(nlh, TIPC_NLA_BEARER_NAME, id);
216
217 return 0;
218 }
219
220 fprintf(stderr, "error, invalid media type %s\n", media);
221
222 return -EINVAL;
223 }
224
225 static void cmd_bearer_enable_help(struct cmdl *cmdl)
226 {
227 fprintf(stderr,
228 "Usage: %s bearer enable [OPTIONS] media MEDIA ARGS...\n\n"
229 "OPTIONS\n"
230 " domain DOMAIN - Discovery domain\n"
231 " priority PRIORITY - Bearer priority\n",
232 cmdl->argv[0]);
233 _print_bearer_media();
234 }
235
236 static int cmd_bearer_enable(struct nlmsghdr *nlh, const struct cmd *cmd,
237 struct cmdl *cmdl, void *data)
238 {
239 int err;
240 struct opt *opt;
241 struct nlattr *nest;
242 char buf[MNL_SOCKET_BUFFER_SIZE];
243 struct opt opts[] = {
244 { "device", NULL },
245 { "domain", NULL },
246 { "localip", NULL },
247 { "localport", NULL },
248 { "media", NULL },
249 { "name", NULL },
250 { "priority", NULL },
251 { "remoteip", NULL },
252 { "remoteport", NULL },
253 { NULL }
254 };
255 struct tipc_sup_media sup_media[] = {
256 { "udp", "name", cmd_bearer_enable_udp_help},
257 { "eth", "device", cmd_bearer_enable_l2_help },
258 { "ib", "device", cmd_bearer_enable_l2_help },
259 { NULL, },
260 };
261
262 if (parse_opts(opts, cmdl) < 0) {
263 if (help_flag)
264 (cmd->help)(cmdl);
265 return -EINVAL;
266 }
267
268 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_ENABLE))) {
269 fprintf(stderr, "error: message initialisation failed\n");
270 return -1;
271 }
272 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
273
274 if ((opt = get_opt(opts, "domain")))
275 mnl_attr_put_u32(nlh, TIPC_NLA_BEARER_DOMAIN, atoi(opt->val));
276
277 if ((opt = get_opt(opts, "priority"))) {
278 struct nlattr *props;
279
280 props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
281 mnl_attr_put_u32(nlh, TIPC_NLA_PROP_PRIO, atoi(opt->val));
282 mnl_attr_nest_end(nlh, props);
283 }
284
285 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
286 if (err)
287 return err;
288
289 opt = get_opt(opts, "media");
290 if (strcmp(opt->val, "udp") == 0) {
291 err = nl_add_udp_enable_opts(nlh, opts, cmdl);
292 if (err)
293 return err;
294 }
295 mnl_attr_nest_end(nlh, nest);
296
297 return msg_doit(nlh, NULL, NULL);
298 }
299
300 static void cmd_bearer_disable_l2_help(struct cmdl *cmdl, char *media)
301 {
302 fprintf(stderr, "Usage: %s bearer disable media %s device DEVICE\n",
303 cmdl->argv[0], media);
304 }
305
306 static void cmd_bearer_disable_udp_help(struct cmdl *cmdl, char *media)
307 {
308 fprintf(stderr, "Usage: %s bearer disable media %s name NAME\n",
309 cmdl->argv[0], media);
310 }
311
312 static void cmd_bearer_disable_help(struct cmdl *cmdl)
313 {
314 fprintf(stderr, "Usage: %s bearer disable media MEDIA ARGS...\n",
315 cmdl->argv[0]);
316 _print_bearer_media();
317 }
318
319 static int cmd_bearer_disable(struct nlmsghdr *nlh, const struct cmd *cmd,
320 struct cmdl *cmdl, void *data)
321 {
322 int err;
323 char buf[MNL_SOCKET_BUFFER_SIZE];
324 struct nlattr *nest;
325 struct opt opts[] = {
326 { "device", NULL },
327 { "name", NULL },
328 { "media", NULL },
329 { NULL }
330 };
331 struct tipc_sup_media sup_media[] = {
332 { "udp", "name", cmd_bearer_disable_udp_help},
333 { "eth", "device", cmd_bearer_disable_l2_help },
334 { "ib", "device", cmd_bearer_disable_l2_help },
335 { NULL, },
336 };
337
338 if (parse_opts(opts, cmdl) < 0) {
339 if (help_flag)
340 (cmd->help)(cmdl);
341 return -EINVAL;
342 }
343
344 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_DISABLE))) {
345 fprintf(stderr, "error, message initialisation failed\n");
346 return -1;
347 }
348
349 nest = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
350 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
351 if (err)
352 return err;
353 mnl_attr_nest_end(nlh, nest);
354
355 return msg_doit(nlh, NULL, NULL);
356
357 }
358
359 static void cmd_bearer_set_help(struct cmdl *cmdl)
360 {
361 fprintf(stderr, "Usage: %s bearer set OPTION media MEDIA ARGS...\n",
362 cmdl->argv[0]);
363 _print_bearer_opts();
364 _print_bearer_media();
365 }
366
367 static void cmd_bearer_set_udp_help(struct cmdl *cmdl, char *media)
368 {
369 fprintf(stderr, "Usage: %s bearer set OPTION media %s name NAME\n\n",
370 cmdl->argv[0], media);
371 _print_bearer_opts();
372 }
373
374 static void cmd_bearer_set_l2_help(struct cmdl *cmdl, char *media)
375 {
376 fprintf(stderr,
377 "Usage: %s bearer set [OPTION]... media %s device DEVICE\n",
378 cmdl->argv[0], media);
379 _print_bearer_opts();
380 }
381
382 static int cmd_bearer_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
383 struct cmdl *cmdl, void *data)
384 {
385 int err;
386 int val;
387 int prop;
388 char buf[MNL_SOCKET_BUFFER_SIZE];
389 struct nlattr *props;
390 struct nlattr *attrs;
391 struct opt opts[] = {
392 { "device", NULL },
393 { "media", NULL },
394 { "name", NULL },
395 { NULL }
396 };
397 struct tipc_sup_media sup_media[] = {
398 { "udp", "name", cmd_bearer_set_udp_help},
399 { "eth", "device", cmd_bearer_set_l2_help },
400 { "ib", "device", cmd_bearer_set_l2_help },
401 { NULL, },
402 };
403
404 if (strcmp(cmd->cmd, "priority") == 0)
405 prop = TIPC_NLA_PROP_PRIO;
406 else if ((strcmp(cmd->cmd, "tolerance") == 0))
407 prop = TIPC_NLA_PROP_TOL;
408 else if ((strcmp(cmd->cmd, "window") == 0))
409 prop = TIPC_NLA_PROP_WIN;
410 else
411 return -EINVAL;
412
413 if (cmdl->optind >= cmdl->argc) {
414 fprintf(stderr, "error, missing value\n");
415 return -EINVAL;
416 }
417 val = atoi(shift_cmdl(cmdl));
418
419 if (parse_opts(opts, cmdl) < 0)
420 return -EINVAL;
421
422 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_SET))) {
423 fprintf(stderr, "error, message initialisation failed\n");
424 return -1;
425 }
426 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
427
428 props = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER_PROP);
429 mnl_attr_put_u32(nlh, prop, val);
430 mnl_attr_nest_end(nlh, props);
431
432 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
433 if (err)
434 return err;
435
436 mnl_attr_nest_end(nlh, attrs);
437
438 return msg_doit(nlh, NULL, NULL);
439 }
440
441 static int cmd_bearer_set(struct nlmsghdr *nlh, const struct cmd *cmd,
442 struct cmdl *cmdl, void *data)
443 {
444 const struct cmd cmds[] = {
445 { "priority", cmd_bearer_set_prop, cmd_bearer_set_help },
446 { "tolerance", cmd_bearer_set_prop, cmd_bearer_set_help },
447 { "window", cmd_bearer_set_prop, cmd_bearer_set_help },
448 { NULL }
449 };
450
451 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
452 }
453
454 static void cmd_bearer_get_help(struct cmdl *cmdl)
455 {
456 fprintf(stderr, "Usage: %s bearer get OPTION media MEDIA ARGS...\n",
457 cmdl->argv[0]);
458 _print_bearer_opts();
459 _print_bearer_media();
460 }
461
462 static void cmd_bearer_get_udp_help(struct cmdl *cmdl, char *media)
463 {
464 fprintf(stderr, "Usage: %s bearer get OPTION media %s name NAME\n\n",
465 cmdl->argv[0], media);
466 _print_bearer_opts();
467 }
468
469 static void cmd_bearer_get_l2_help(struct cmdl *cmdl, char *media)
470 {
471 fprintf(stderr,
472 "Usage: %s bearer get OPTION media %s device DEVICE\n",
473 cmdl->argv[0], media);
474 _print_bearer_opts();
475 }
476
477 static int bearer_get_cb(const struct nlmsghdr *nlh, void *data)
478 {
479 int *prop = data;
480 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
481 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
482 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
483 struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {};
484
485 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
486 if (!info[TIPC_NLA_BEARER])
487 return MNL_CB_ERROR;
488
489 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
490 if (!attrs[TIPC_NLA_BEARER_PROP])
491 return MNL_CB_ERROR;
492
493 mnl_attr_parse_nested(attrs[TIPC_NLA_BEARER_PROP], parse_attrs, props);
494 if (!props[*prop])
495 return MNL_CB_ERROR;
496
497 printf("%u\n", mnl_attr_get_u32(props[*prop]));
498
499 return MNL_CB_OK;
500 }
501
502 static int cmd_bearer_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd,
503 struct cmdl *cmdl, void *data)
504 {
505 int err;
506 int prop;
507 char buf[MNL_SOCKET_BUFFER_SIZE];
508 struct nlattr *attrs;
509 struct opt opts[] = {
510 { "device", NULL },
511 { "media", NULL },
512 { "name", NULL },
513 { NULL }
514 };
515 struct tipc_sup_media sup_media[] = {
516 { "udp", "name", cmd_bearer_get_udp_help},
517 { "eth", "device", cmd_bearer_get_l2_help },
518 { "ib", "device", cmd_bearer_get_l2_help },
519 { NULL, },
520 };
521
522 if (strcmp(cmd->cmd, "priority") == 0)
523 prop = TIPC_NLA_PROP_PRIO;
524 else if ((strcmp(cmd->cmd, "tolerance") == 0))
525 prop = TIPC_NLA_PROP_TOL;
526 else if ((strcmp(cmd->cmd, "window") == 0))
527 prop = TIPC_NLA_PROP_WIN;
528 else
529 return -EINVAL;
530
531 if (parse_opts(opts, cmdl) < 0)
532 return -EINVAL;
533
534 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
535 fprintf(stderr, "error, message initialisation failed\n");
536 return -1;
537 }
538
539 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_BEARER);
540 err = nl_add_bearer_name(nlh, cmd, cmdl, opts, sup_media);
541 if (err)
542 return err;
543 mnl_attr_nest_end(nlh, attrs);
544
545 return msg_doit(nlh, bearer_get_cb, &prop);
546 }
547
548 static int cmd_bearer_get(struct nlmsghdr *nlh, const struct cmd *cmd,
549 struct cmdl *cmdl, void *data)
550 {
551 const struct cmd cmds[] = {
552 { "priority", cmd_bearer_get_prop, cmd_bearer_get_help },
553 { "tolerance", cmd_bearer_get_prop, cmd_bearer_get_help },
554 { "window", cmd_bearer_get_prop, cmd_bearer_get_help },
555 { NULL }
556 };
557
558 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
559 }
560
561 static int bearer_list_cb(const struct nlmsghdr *nlh, void *data)
562 {
563 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
564 struct nlattr *info[TIPC_NLA_MAX + 1] = {};
565 struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1] = {};
566
567 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info);
568 if (!info[TIPC_NLA_BEARER]) {
569 fprintf(stderr, "No bearer in netlink response\n");
570 return MNL_CB_ERROR;
571 }
572
573 mnl_attr_parse_nested(info[TIPC_NLA_BEARER], parse_attrs, attrs);
574 if (!attrs[TIPC_NLA_BEARER_NAME]) {
575 fprintf(stderr, "Bearer name missing in netlink response\n");
576 return MNL_CB_ERROR;
577 }
578
579 printf("%s\n", mnl_attr_get_str(attrs[TIPC_NLA_BEARER_NAME]));
580
581 return MNL_CB_OK;
582 }
583
584 static int cmd_bearer_list(struct nlmsghdr *nlh, const struct cmd *cmd,
585 struct cmdl *cmdl, void *data)
586 {
587 char buf[MNL_SOCKET_BUFFER_SIZE];
588
589 if (help_flag) {
590 fprintf(stderr, "Usage: %s bearer list\n", cmdl->argv[0]);
591 return -EINVAL;
592 }
593
594 if (!(nlh = msg_init(buf, TIPC_NL_BEARER_GET))) {
595 fprintf(stderr, "error, message initialisation failed\n");
596 return -1;
597 }
598
599 return msg_dumpit(nlh, bearer_list_cb, NULL);
600 }
601
602 void cmd_bearer_help(struct cmdl *cmdl)
603 {
604 fprintf(stderr,
605 "Usage: %s bearer COMMAND [ARGS] ...\n"
606 "\n"
607 "COMMANDS\n"
608 " enable - Enable a bearer\n"
609 " disable - Disable a bearer\n"
610 " set - Set various bearer properties\n"
611 " get - Get various bearer properties\n"
612 " list - List bearers\n", cmdl->argv[0]);
613 }
614
615 int cmd_bearer(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
616 void *data)
617 {
618 const struct cmd cmds[] = {
619 { "disable", cmd_bearer_disable, cmd_bearer_disable_help },
620 { "enable", cmd_bearer_enable, cmd_bearer_enable_help },
621 { "get", cmd_bearer_get, cmd_bearer_get_help },
622 { "list", cmd_bearer_list, NULL },
623 { "set", cmd_bearer_set, cmd_bearer_set_help },
624 { NULL }
625 };
626
627 return run_cmd(nlh, cmd, cmds, cmdl, NULL);
628 }