From e892973e391aa93f4aac144527400ae24ad68032 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 28 Dec 2009 22:10:11 +0100 Subject: [PATCH] add macvlan vepa and bridge mode The future kernel 2.6.33 will incorporate the macvlan bridge mode where all the macvlan will be able to communicate if they are using the same physical interface. This is an interesting feature to have containers to communicate together. If we are outside of the container, we have to setup a macvlan on the same physical interface than the containers and use it to communicate with them. Signed-off-by: Daniel Lezcano --- configure.ac | 2 +- doc/lxc.conf.sgml.in | 51 +++++++++++++++++++--- src/lxc/conf.c | 16 ++++--- src/lxc/conf.h | 11 ++++- src/lxc/confile.c | 100 ++++++++++++++++++++++++++++++++----------- src/lxc/network.c | 21 ++++++++- src/lxc/network.h | 2 +- 7 files changed, 162 insertions(+), 41 deletions(-) diff --git a/configure.ac b/configure.ac index a634e8604..0cd8e9522 100644 --- a/configure.ac +++ b/configure.ac @@ -44,7 +44,7 @@ AS_AC_EXPAND(DOCDIR, $docdir) AC_ARG_WITH([config-path], [AC_HELP_STRING( [--with-config-path=dir], - [lxc configuration repository] + [lxc configuration repository path] )], [], [with_config_path="${localstatedir}/lib/lxc"]) AS_AC_EXPAND(LXC_GENERATE_DATE, "$(date)") diff --git a/doc/lxc.conf.sgml.in b/doc/lxc.conf.sgml.in index c12833361..fd618165f 100644 --- a/doc/lxc.conf.sgml.in +++ b/doc/lxc.conf.sgml.in @@ -134,11 +134,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA a new network stack is created, a peer network device is created with one side assigned to - the container and the other side attached to a bridge - specified by the . The - bridge has to be setup before on the - system, lxc won't handle - configuration outside of the container. + the container and the other side is attached to a bridge + specified by the . If + the bridge is not specified, then the veth pair device + will be created but not attached to any + bridge. Otherwise, the bridge has to be setup before on + the system, lxc won't handle + any configuration outside of the container. By + default lxc choose a name for the + network device belonging to the outside of the + container, this name is handled + by lxc, but if you wish to handle + this name yourself, you can tell lxc + to set a specific name with + the option. + + + + a new network stack is created, a + vlan interface is linked with the interface specified by + the and assigned to + the container. The vlan identifier is specified with the + option . @@ -147,11 +164,33 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA interface specified by the and assigned to the container. + specifies the + mode the macvlan will use to communicate between + different macvlan on the same upper device. The accepted + modes are , the device never + communicates with any other device on the same upper_dev (default), + , the new Virtual Ethernet Port + Aggregator (VEPA) mode, it assumes that the adjacent + bridge returns all frames where both source and + destination are local to the macvlan port, i.e. the + bridge is set up as a reflective relay. Broadcast + frames coming in from the upper_dev get flooded to all + macvlan interfaces in VEPA mode, local frames are not + delivered locallay, or , it + provides the behavior of a simple bridge between + different macvlan interfaces on the same port. Frames + from one interface to another one get delivered directly + and are not sent out externally. Broadcast frames get + flooded to all other bridge ports and to the external + interface, but when they come back from a reflective + relay, we don't deliver them again. Since we know all + the MAC addresses, the macvlan bridge mode does not + require learning or STP like the bridge module does. a new network stack is created - and the interface specified by + and an already existing interface specified by the is assigned to the container. diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 98a263b8f..da7c945d8 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -834,8 +834,8 @@ static int instanciate_veth(struct lxc_netdev *netdev) char veth1buf[IFNAMSIZ], *veth1; char veth2[IFNAMSIZ]; - if (netdev->priv.pair) - veth1 = netdev->priv.pair; + if (netdev->priv.veth_attr.pair) + veth1 = netdev->priv.veth_attr.pair; else { snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX"); mktemp(veth1buf); @@ -911,7 +911,8 @@ static int instanciate_macvlan(struct lxc_netdev *netdev) return -1; } - if (lxc_macvlan_create(netdev->link, peer)) { + if (lxc_macvlan_create(netdev->link, peer, + netdev->priv.macvlan_attr.mode)) { ERROR("failed to create macvlan interface '%s' on '%s'", peer, netdev->link); return -1; @@ -924,7 +925,8 @@ static int instanciate_macvlan(struct lxc_netdev *netdev) return -1; } - DEBUG("instanciated macvlan '%s', index is '%d'", peer, netdev->ifindex); + DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'", + peer, netdev->ifindex, netdev->priv.macvlan_attr.mode); return 0; } @@ -939,7 +941,7 @@ static int instanciate_vlan(struct lxc_netdev *netdev) return -1; } - snprintf(peer, sizeof(peer), "vlan%d",netdev->priv.vlan_attr.vid); + snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid); if (lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid)) { ERROR("failed to create vlan interface '%s' on '%s'", @@ -954,7 +956,9 @@ static int instanciate_vlan(struct lxc_netdev *netdev) return -1; } - DEBUG("instanciated vlan '%s', ifindex is '%d'", "vlan1000", netdev->ifindex); + DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000", + netdev->ifindex); + return 0; } diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 8e01d921f..8548eeb53 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -71,6 +71,10 @@ struct lxc_route6 { struct in6_addr addr; }; +struct ifla_veth { + char *pair; /* pair name */ +}; + struct ifla_vlan { uint flags; uint fmask; @@ -78,9 +82,14 @@ struct ifla_vlan { ushort pad; }; +struct ifla_macvlan { + int mode; /* private, vepa, bridge */ +}; + union netdev_p { - char *pair; + struct ifla_veth veth_attr; struct ifla_vlan vlan_attr; + struct ifla_macvlan macvlan_attr; }; /* diff --git a/src/lxc/confile.c b/src/lxc/confile.c index 3593b9a88..a5b626378 100644 --- a/src/lxc/confile.c +++ b/src/lxc/confile.c @@ -50,9 +50,10 @@ static int config_network_type(const char *, char *, struct lxc_conf *); static int config_network_flags(const char *, char *, struct lxc_conf *); static int config_network_link(const char *, char *, struct lxc_conf *); static int config_network_name(const char *, char *, struct lxc_conf *); -static int config_network_pair(const char *, char *, struct lxc_conf *); +static int config_network_veth_pair(const char *, char *, struct lxc_conf *); +static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *); static int config_network_hwaddr(const char *, char *, struct lxc_conf *); -static int config_network_vlanid(const char *, char *, struct lxc_conf *); +static int config_network_vlan_id(const char *, char *, struct lxc_conf *); static int config_network_mtu(const char *, char *, struct lxc_conf *); static int config_network_ipv4(const char *, char *, struct lxc_conf *); static int config_network_ipv6(const char *, char *, struct lxc_conf *); @@ -66,22 +67,23 @@ struct config { static struct config config[] = { - { "lxc.pts", config_pts }, - { "lxc.tty", config_tty }, - { "lxc.cgroup", config_cgroup }, - { "lxc.mount", config_mount }, - { "lxc.rootfs", config_rootfs }, - { "lxc.utsname", config_utsname }, - { "lxc.network.type", config_network_type }, - { "lxc.network.flags", config_network_flags }, - { "lxc.network.link", config_network_link }, - { "lxc.network.name", config_network_name }, - { "lxc.network.veth.pair", config_network_pair }, - { "lxc.network.hwaddr", config_network_hwaddr }, - { "lxc.network.mtu", config_network_mtu }, - { "lxc.network.vlan.id", config_network_vlanid }, - { "lxc.network.ipv4", config_network_ipv4 }, - { "lxc.network.ipv6", config_network_ipv6 }, + { "lxc.pts", config_pts }, + { "lxc.tty", config_tty }, + { "lxc.cgroup", config_cgroup }, + { "lxc.mount", config_mount }, + { "lxc.rootfs", config_rootfs }, + { "lxc.utsname", config_utsname }, + { "lxc.network.type", config_network_type }, + { "lxc.network.flags", config_network_flags }, + { "lxc.network.link", config_network_link }, + { "lxc.network.name", config_network_name }, + { "lxc.network.macvlan.mode", config_network_macvlan_mode }, + { "lxc.network.veth.pair", config_network_veth_pair }, + { "lxc.network.hwaddr", config_network_hwaddr }, + { "lxc.network.mtu", config_network_mtu }, + { "lxc.network.vlan.id", config_network_vlan_id }, + { "lxc.network.ipv4", config_network_ipv4 }, + { "lxc.network.ipv6", config_network_ipv6 }, }; static const size_t config_size = sizeof(config)/sizeof(struct config); @@ -97,7 +99,8 @@ static struct config *getconfig(const char *key) return NULL; } -static int config_network_type(const char *key, char *value, struct lxc_conf *lxc_conf) +static int config_network_type(const char *key, char *value, + struct lxc_conf *lxc_conf) { struct lxc_list *network = &lxc_conf->network; struct lxc_netdev *netdev; @@ -190,6 +193,42 @@ static int network_ifname(char **valuep, char *value) return 0; } +#ifndef MACVLAN_MODE_PRIVATE +# define MACVLAN_MODE_PRIVATE 1 +#endif + +#ifndef MACVLAN_MODE_VEPA +# define MACVLAN_MODE_VEPA 2 +#endif + +#ifndef MACVLAN_MODE_BRIDGE +# define MACVLAN_MODE_BRIDGE 4 +#endif + +static int macvlan_mode(int *valuep, char *value) +{ + struct mc_mode { + char *name; + int mode; + } m[] = { + { "private", MACVLAN_MODE_PRIVATE }, + { "vepa", MACVLAN_MODE_VEPA }, + { "bridge", MACVLAN_MODE_BRIDGE }, + }; + + int i; + + for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) { + if (strcmp(m[i].name, value)) + continue; + + *valuep = m[i].mode; + return 0; + } + + return -1; +} + static int config_network_flags(const char *key, char *value, struct lxc_conf *lxc_conf) { @@ -228,8 +267,20 @@ static int config_network_name(const char *key, char *value, return network_ifname(&netdev->name, value); } -static int config_network_pair(const char *key, char *value, - struct lxc_conf *lxc_conf) +static int config_network_veth_pair(const char *key, char *value, + struct lxc_conf *lxc_conf) +{ + struct lxc_netdev *netdev; + + netdev = network_netdev(key, value, &lxc_conf->network); + if (!netdev) + return -1; + + return network_ifname(&netdev->priv.veth_attr.pair, value); +} + +static int config_network_macvlan_mode(const char *key, char *value, + struct lxc_conf *lxc_conf) { struct lxc_netdev *netdev; @@ -237,7 +288,7 @@ static int config_network_pair(const char *key, char *value, if (!netdev) return -1; - return network_ifname(&netdev->priv.pair, value); + return macvlan_mode(&netdev->priv.macvlan_attr.mode, value); } static int config_network_hwaddr(const char *key, char *value, @@ -258,7 +309,7 @@ static int config_network_hwaddr(const char *key, char *value, return 0; } -static int config_network_vlanid(const char *key, char *value, +static int config_network_vlan_id(const char *key, char *value, struct lxc_conf *lxc_conf) { struct lxc_netdev *netdev; @@ -359,7 +410,8 @@ static int config_network_ipv4(const char *key, char *value, return 0; } -static int config_network_ipv6(const char *key, char *value, struct lxc_conf *lxc_conf) +static int config_network_ipv6(const char *key, char *value, + struct lxc_conf *lxc_conf) { struct lxc_netdev *netdev; struct lxc_inet6dev *inet6dev; diff --git a/src/lxc/network.c b/src/lxc/network.c index 5fd663713..82f3ae7d7 100644 --- a/src/lxc/network.c +++ b/src/lxc/network.c @@ -75,6 +75,10 @@ # define VETH_INFO_PEER 1 #endif +#ifndef IFLA_MACVLAN_MODE +# define IFLA_MACVLAN_MODE 1 +#endif + struct link_req { struct nlmsg nlmsg; struct ifinfomsg ifinfomsg; @@ -445,8 +449,10 @@ int lxc_vlan_create(const char *master, const char *name, ushort vlanid) nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); if (!nest2) goto err1; + if (nla_put_u16(nlmsg, IFLA_VLAN_ID, vlanid)) goto err1; + nla_end_nested(nlmsg, nest2); nla_end_nested(nlmsg, nest); @@ -470,12 +476,12 @@ err3: return err; } -int lxc_macvlan_create(const char *master, const char *name) +int lxc_macvlan_create(const char *master, const char *name, int mode) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; - struct rtattr *nest; + struct rtattr *nest, *nest2; int index, len, err = -1; if (netlink_open(&nlh, NETLINK_ROUTE)) @@ -515,6 +521,17 @@ int lxc_macvlan_create(const char *master, const char *name) if (nla_put_string(nlmsg, IFLA_INFO_KIND, "macvlan")) goto out; + if (mode) { + nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); + if (!nest2) + goto out; + + if (nla_put_u32(nlmsg, IFLA_MACVLAN_MODE, mode)) + goto out; + + nla_end_nested(nlmsg, nest2); + } + nla_end_nested(nlmsg, nest); if (nla_put_u32(nlmsg, IFLA_LINK, index)) diff --git a/src/lxc/network.h b/src/lxc/network.h index d89dfae68..7bac5ee5e 100644 --- a/src/lxc/network.h +++ b/src/lxc/network.h @@ -66,7 +66,7 @@ extern int lxc_veth_create(const char *name1, const char *name2); /* * Create a macvlan network device */ -extern int lxc_macvlan_create(const char *master, const char *name); +extern int lxc_macvlan_create(const char *master, const char *name, int mode); /* * Create a vlan network device -- 2.47.2