From d63a9b2b1e4e3eab0d0577d0a0f412d50be1e0a7 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sat, 26 Dec 2009 11:22:57 -0800 Subject: [PATCH] iproute2/iplink: add macvlan options for bridge mode Macvlan can now optionally support forwarding between its ports, if they are in "bridge" mode. This adds support for this option to "ip link add", "ip link set" and "ip -d link show". The default mode in the kernel is now "vepa" mode, meaning "virtual ethernet port aggregator". This mode is used together with the "hairpin" mode of an ethernet bridge that the parent of the macvlan device is connected to. All frames still get sent out to the external interface, but the adjacent bridge is able to send them back on the same wire in hairpin mode, so the macvlan ports are able to see each other, which the bridge can be configured to monitor and control traffic between all macvlan instances. Multicast traffic coming in from the external interface is checked for the source MAC address and only delivered to ports that have not yet seen it. In bridge mode, macvlan will send all multicast traffic to other interfaces that are also in bridge mode but not to those in vepa mode, which get them on the way back from the hairpin. The third supported mode is "private", which prevents communication between macvlans even if the adjacent bridge is in hairpin mode. This behavior is closer to the original implementation of macvlan but stricly maintains isolation. Signed-off-by: Arnd Bergmann --- ip/Makefile | 3 +- ip/iplink_macvlan.c | 93 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 ip/iplink_macvlan.c diff --git a/ip/Makefile b/ip/Makefile index 51914e85..46a98361 100644 --- a/ip/Makefile +++ b/ip/Makefile @@ -2,7 +2,8 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o \ rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \ ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o \ ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \ - iplink_vlan.o link_veth.o link_gre.o iplink_can.o + iplink_vlan.o link_veth.o link_gre.o iplink_can.o \ + iplink_macvlan.o RTMONOBJ=rtmon.o diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c new file mode 100644 index 00000000..a3c78bd8 --- /dev/null +++ b/ip/iplink_macvlan.c @@ -0,0 +1,93 @@ +/* + * iplink_vlan.c VLAN device support + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Patrick McHardy + * Arnd Bergmann + */ + +#include +#include +#include +#include +#include + +#include "rt_names.h" +#include "utils.h" +#include "ip_common.h" + +static void explain(void) +{ + fprintf(stderr, + "Usage: ... macvlan mode { private | vepa | bridge }\n" + ); +} + +static int mode_arg(void) +{ + fprintf(stderr, "Error: argument of \"mode\" must be \"private\", " + "\"vepa\" or \"bridge\"\n"); + return -1; +} + +static int macvlan_parse_opt(struct link_util *lu, int argc, char **argv, + struct nlmsghdr *n) +{ + while (argc > 0) { + if (matches(*argv, "mode") == 0) { + __u32 mode = 0; + NEXT_ARG(); + + if (strcmp(*argv, "private") == 0) + mode = MACVLAN_MODE_PRIVATE; + else if (strcmp(*argv, "vepa") == 0) + mode = MACVLAN_MODE_VEPA; + else if (strcmp(*argv, "bridge") == 0) + mode = MACVLAN_MODE_BRIDGE; + else + return mode_arg(); + + addattr32(n, 1024, IFLA_MACVLAN_MODE, mode); + } else if (matches(*argv, "help") == 0) { + explain(); + return -1; + } else { + fprintf(stderr, "macvlan: what is \"%s\"?\n", *argv); + explain(); + return -1; + } + argc--, argv++; + } + + return 0; +} + +static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) +{ + __u32 mode; + + if (!tb) + return; + + if (!tb[IFLA_MACVLAN_MODE] || + RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32)) + return; + + mode = *(__u32 *)RTA_DATA(tb[IFLA_VLAN_ID]); + fprintf(f, " mode %s ", + mode == MACVLAN_MODE_PRIVATE ? "private" + : mode == MACVLAN_MODE_VEPA ? "vepa" + : mode == MACVLAN_MODE_BRIDGE ? "bridge" + : "unknown"); +} + +struct link_util macvlan_link_util = { + .id = "macvlan", + .maxattr = IFLA_MACVLAN_MAX, + .parse_opt = macvlan_parse_opt, + .print_opt = macvlan_print_opt, +};