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 */ |
