diff options
author | Patrick McHardy <kaber@trash.net> | 2013-07-15 05:16:13 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2013-07-15 05:16:13 +0200 |
commit | a7ecbed56bb620a0e8cd79372886d0fdfeb362c8 (patch) | |
tree | 3942b2949f651325b064237861f8d4c2b4243bdb | |
parent | 9b58fe9c0b7b10bca17f033d7928e65ab5065fc9 (diff) | |
download | busybox-w32-a7ecbed56bb620a0e8cd79372886d0fdfeb362c8.tar.gz busybox-w32-a7ecbed56bb620a0e8cd79372886d0fdfeb362c8.tar.bz2 busybox-w32-a7ecbed56bb620a0e8cd79372886d0fdfeb362c8.zip |
ip link: add VLAN support
function old new delta
do_add_or_delete - 1073 +1073
get_u16 - 62 +62
static.protocols - 16 +16
do_iplink 1235 1232 -3
do_change 495 - -495
------------------------------------------------------------------------------
(add/remove: 3/1 grow/shrink: 0/1 up/down: 1151/-498) Total: 653 bytes
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | networking/libiproute/iplink.c | 137 |
1 files changed, 128 insertions, 9 deletions
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index bad2017fe..45cad711b 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c | |||
@@ -1,6 +1,7 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> | 3 | * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> |
4 | * Patrick McHardy <kaber@trash.net> | ||
4 | * | 5 | * |
5 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
6 | */ | 7 | */ |
@@ -9,6 +10,20 @@ | |||
9 | #include <netpacket/packet.h> | 10 | #include <netpacket/packet.h> |
10 | #include <netinet/if_ether.h> | 11 | #include <netinet/if_ether.h> |
11 | 12 | ||
13 | #include <linux/if_vlan.h> | ||
14 | #undef ETH_P_8021AD | ||
15 | #define ETH_P_8021AD 0x88A8 | ||
16 | #undef VLAN_FLAG_REORDER_HDR | ||
17 | #define VLAN_FLAG_REORDER_HDR 0x1 | ||
18 | #undef VLAN_FLAG_GVRP | ||
19 | #define VLAN_FLAG_GVRP 0x2 | ||
20 | #undef VLAN_FLAG_LOOSE_BINDING | ||
21 | #define VLAN_FLAG_LOOSE_BINDING 0x4 | ||
22 | #undef VLAN_FLAG_MVRP | ||
23 | #define VLAN_FLAG_MVRP 0x8 | ||
24 | #undef IFLA_VLAN_PROTOCOL | ||
25 | #define IFLA_VLAN_PROTOCOL 5 | ||
26 | |||
12 | #include "ip_common.h" /* #include "libbb.h" is inside */ | 27 | #include "ip_common.h" /* #include "libbb.h" is inside */ |
13 | #include "rt_names.h" | 28 | #include "rt_names.h" |
14 | #include "utils.h" | 29 | #include "utils.h" |
@@ -277,12 +292,103 @@ static int ipaddr_list_link(char **argv) | |||
277 | return ipaddr_list_or_flush(argv, 0); | 292 | return ipaddr_list_or_flush(argv, 0); |
278 | } | 293 | } |
279 | 294 | ||
295 | static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) | ||
296 | { | ||
297 | static const char keywords[] ALIGN1 = | ||
298 | "id\0" | ||
299 | "protocol\0" | ||
300 | "reorder_hdr\0" | ||
301 | "gvrp\0" | ||
302 | "mvrp\0" | ||
303 | "loose_binding\0" | ||
304 | ; | ||
305 | static const char protocols[] ALIGN1 = | ||
306 | "802.1q\0" | ||
307 | "802.1ad\0" | ||
308 | ; | ||
309 | static const char str_on_off[] ALIGN1 = | ||
310 | "on\0" | ||
311 | "off\0" | ||
312 | ; | ||
313 | enum { | ||
314 | ARG_id = 0, | ||
315 | ARG_reorder_hdr, | ||
316 | ARG_gvrp, | ||
317 | ARG_mvrp, | ||
318 | ARG_loose_binding, | ||
319 | ARG_protocol, | ||
320 | }; | ||
321 | enum { | ||
322 | PROTO_8021Q = 0, | ||
323 | PROTO_8021AD, | ||
324 | }; | ||
325 | enum { | ||
326 | PARM_on = 0, | ||
327 | PARM_off | ||
328 | }; | ||
329 | int arg; | ||
330 | uint16_t id, proto; | ||
331 | struct ifla_vlan_flags flags = {}; | ||
332 | |||
333 | while (*argv) { | ||
334 | arg = index_in_substrings(keywords, *argv); | ||
335 | if (arg < 0) | ||
336 | invarg(*argv, "type vlan"); | ||
337 | |||
338 | NEXT_ARG(); | ||
339 | if (arg == ARG_id) { | ||
340 | id = get_u16(*argv, "id"); | ||
341 | addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); | ||
342 | } else if (arg == ARG_protocol) { | ||
343 | arg = index_in_substrings(protocols, *argv); | ||
344 | if (arg == PROTO_8021Q) | ||
345 | proto = ETH_P_8021Q; | ||
346 | else if (arg == PROTO_8021AD) | ||
347 | proto = ETH_P_8021AD; | ||
348 | else | ||
349 | bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", | ||
350 | *argv); | ||
351 | addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto)); | ||
352 | } else { | ||
353 | int param = index_in_strings(str_on_off, *argv); | ||
354 | if (param < 0) | ||
355 | die_must_be_on_off(nth_string(keywords, arg)); | ||
356 | |||
357 | if (arg == ARG_reorder_hdr) { | ||
358 | flags.mask |= VLAN_FLAG_REORDER_HDR; | ||
359 | flags.flags &= ~VLAN_FLAG_REORDER_HDR; | ||
360 | if (param == PARM_on) | ||
361 | flags.flags |= VLAN_FLAG_REORDER_HDR; | ||
362 | } else if (arg == ARG_gvrp) { | ||
363 | flags.mask |= VLAN_FLAG_GVRP; | ||
364 | flags.flags &= ~VLAN_FLAG_GVRP; | ||
365 | if (param == PARM_on) | ||
366 | flags.flags |= VLAN_FLAG_GVRP; | ||
367 | } else if (arg == ARG_mvrp) { | ||
368 | flags.mask |= VLAN_FLAG_MVRP; | ||
369 | flags.flags &= ~VLAN_FLAG_MVRP; | ||
370 | if (param == PARM_on) | ||
371 | flags.flags |= VLAN_FLAG_MVRP; | ||
372 | } else { /*if (arg == ARG_loose_binding) */ | ||
373 | flags.mask |= VLAN_FLAG_LOOSE_BINDING; | ||
374 | flags.flags &= ~VLAN_FLAG_LOOSE_BINDING; | ||
375 | if (param == PARM_on) | ||
376 | flags.flags |= VLAN_FLAG_LOOSE_BINDING; | ||
377 | } | ||
378 | } | ||
379 | argv++; | ||
380 | } | ||
381 | |||
382 | if (flags.mask) | ||
383 | addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); | ||
384 | } | ||
385 | |||
280 | #ifndef NLMSG_TAIL | 386 | #ifndef NLMSG_TAIL |
281 | #define NLMSG_TAIL(nmsg) \ | 387 | #define NLMSG_TAIL(nmsg) \ |
282 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) | 388 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) |
283 | #endif | 389 | #endif |
284 | /* Return value becomes exitcode. It's okay to not return at all */ | 390 | /* Return value becomes exitcode. It's okay to not return at all */ |
285 | static int do_change(char **argv, const unsigned rtm) | 391 | static int do_add_or_delete(char **argv, const unsigned rtm) |
286 | { | 392 | { |
287 | static const char keywords[] ALIGN1 = | 393 | static const char keywords[] ALIGN1 = |
288 | "link\0""name\0""type\0""dev\0"; | 394 | "link\0""name\0""type\0""dev\0"; |
@@ -312,15 +418,17 @@ static int do_change(char **argv, const unsigned rtm) | |||
312 | 418 | ||
313 | while (*argv) { | 419 | while (*argv) { |
314 | arg = index_in_substrings(keywords, *argv); | 420 | arg = index_in_substrings(keywords, *argv); |
421 | if (arg == ARG_type) { | ||
422 | NEXT_ARG(); | ||
423 | type_str = *argv++; | ||
424 | break; | ||
425 | } | ||
315 | if (arg == ARG_link) { | 426 | if (arg == ARG_link) { |
316 | NEXT_ARG(); | 427 | NEXT_ARG(); |
317 | link_str = *argv; | 428 | link_str = *argv; |
318 | } else if (arg == ARG_name) { | 429 | } else if (arg == ARG_name) { |
319 | NEXT_ARG(); | 430 | NEXT_ARG(); |
320 | name_str = *argv; | 431 | name_str = *argv; |
321 | } else if (arg == ARG_type) { | ||
322 | NEXT_ARG(); | ||
323 | type_str = *argv; | ||
324 | } else { | 432 | } else { |
325 | if (arg == ARG_dev) { | 433 | if (arg == ARG_dev) { |
326 | if (dev_str) | 434 | if (dev_str) |
@@ -339,6 +447,17 @@ static int do_change(char **argv, const unsigned rtm) | |||
339 | addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); | 447 | addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); |
340 | addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str, | 448 | addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str, |
341 | strlen(type_str)); | 449 | strlen(type_str)); |
450 | |||
451 | if (*argv) { | ||
452 | struct rtattr *data = NLMSG_TAIL(&req.n); | ||
453 | addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); | ||
454 | |||
455 | if (strcmp(type_str, "vlan") == 0) | ||
456 | vlan_parse_opt(argv, &req.n, sizeof(req)); | ||
457 | |||
458 | data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; | ||
459 | } | ||
460 | |||
342 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; | 461 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; |
343 | } | 462 | } |
344 | if (rtm != RTM_NEWLINK) { | 463 | if (rtm != RTM_NEWLINK) { |
@@ -370,13 +489,13 @@ int FAST_FUNC do_iplink(char **argv) | |||
370 | static const char keywords[] ALIGN1 = | 489 | static const char keywords[] ALIGN1 = |
371 | "add\0""delete\0""set\0""show\0""lst\0""list\0"; | 490 | "add\0""delete\0""set\0""show\0""lst\0""list\0"; |
372 | if (*argv) { | 491 | if (*argv) { |
373 | smalluint key = index_in_substrings(keywords, *argv); | 492 | int key = index_in_substrings(keywords, *argv); |
374 | if (key > 5) /* invalid argument */ | 493 | if (key < 0) /* invalid argument */ |
375 | bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); | 494 | invarg(*argv, applet_name); |
376 | argv++; | 495 | argv++; |
377 | if (key <= 1) /* add/delete */ | 496 | if (key <= 1) /* add/delete */ |
378 | return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK); | 497 | return do_add_or_delete(argv, key ? RTM_DELLINK : RTM_NEWLINK); |
379 | else if (key == 2) /* set */ | 498 | if (key == 2) /* set */ |
380 | return do_set(argv); | 499 | return do_set(argv); |
381 | } | 500 | } |
382 | /* show, lst, list */ | 501 | /* show, lst, list */ |