<para>
<option>veth:</option> 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 <option>lxc.network.link</option>. The
- bridge has to be setup before on the
- system, <command>lxc</command> won't handle
- configuration outside of the container.
+ the container and the other side is attached to a bridge
+ specified by the <option>lxc.network.link</option>. 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, <command>lxc</command> won't handle
+ any configuration outside of the container. By
+ default <command>lxc</command> choose a name for the
+ network device belonging to the outside of the
+ container, this name is handled
+ by <command>lxc</command>, but if you wish to handle
+ this name yourself, you can tell <command>lxc</command>
+ to set a specific name with
+ the <option>lxc.network.veth.pair</option> option.
+ </para>
+
+ <para>
+ <option>vlan:</option> a new network stack is created, a
+ vlan interface is linked with the interface specified by
+ the <option>lxc.network.link</option> and assigned to
+ the container. The vlan identifier is specified with the
+ option <option>lxc.network.vlan.id</option>.
</para>
<para>
interface specified by
the <option>lxc.network.link</option> and assigned to
the container.
+ <option>lxc.network.macvlan.mode</option> specifies the
+ mode the macvlan will use to communicate between
+ different macvlan on the same upper device. The accepted
+ modes are <option>private</option>, the device never
+ communicates with any other device on the same upper_dev (default),
+ <option>vepa</option>, 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 <option>bridge</option>, 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.
</para>
<para>
<option>phys:</option> a new network stack is created
- and the interface specified by
+ and an already existing interface specified by
the <option>lxc.network.link</option> is assigned to the
container.
</para>
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);
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;
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;
}
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'",
return -1;
}
- DEBUG("instanciated vlan '%s', ifindex is '%d'", "vlan1000", netdev->ifindex);
+ DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
+ netdev->ifindex);
+
return 0;
}
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 *);
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);
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;
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)
{
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;
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,
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;
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;
# 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;
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);
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))
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))