From a28a880214c4325670150fa7868ba7e1b91bf451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0imerda?= Date: Wed, 27 Mar 2013 22:53:55 +0100 Subject: [PATCH] platform: vlan support --- src/platform/nm-fake-platform.c | 56 ++++++++++++++++++++++ src/platform/nm-linux-platform.c | 66 +++++++++++++++++++++++++ src/platform/nm-platform.c | 73 ++++++++++++++++++++++++++++ src/platform/nm-platform.h | 11 +++++ src/platform/tests/dump.c | 4 ++ src/platform/tests/platform.c | 82 ++++++++++++++++++++++++++------ src/platform/tests/test-link.c | 43 +++++++++++++++++ 7 files changed, 320 insertions(+), 15 deletions(-) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index f834cc6a99..246090e152 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -39,6 +39,9 @@ typedef struct { typedef struct { NMPlatformLink link; + + int vlan_parent; + int vlan_id; } NMFakePlatformLink; #define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate)) @@ -93,6 +96,8 @@ type_to_type_name (NMLinkType type) return "bond"; case NM_LINK_TYPE_TEAM: return "team"; + case NM_LINK_TYPE_VLAN: + return "vlan"; case NM_LINK_TYPE_NONE: default: return NULL; @@ -261,6 +266,7 @@ link_set_up (NMPlatform *platform, int ifindex) switch (device->link.type) { case NM_LINK_TYPE_GENERIC: case NM_LINK_TYPE_DUMMY: + case NM_LINK_TYPE_VLAN: device->link.connected = TRUE; break; case NM_LINK_TYPE_BRIDGE: @@ -458,6 +464,51 @@ slave_get_option (NMPlatform *platform, int slave, const char *option) return sysctl_get (platform, path); } +static gboolean +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +{ + NMFakePlatformLink *device; + + if (!link_add (platform, name, NM_LINK_TYPE_VLAN)) + return FALSE; + + device = link_get (platform, link_get_ifindex (platform, name)); + + g_return_val_if_fail (device, FALSE); + + device->vlan_id = vlan_id; + device->vlan_parent = parent; + + return TRUE; +} + +static gboolean +vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + g_return_val_if_fail (device, FALSE); + + if (parent) + *parent = device->vlan_parent; + if (vlan_id) + *vlan_id = device->vlan_id; + + return TRUE; +} + +static gboolean +vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + return !!link_get (platform, ifindex); +} + +static gboolean +vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + return !!link_get (platform, ifindex); +} + /******************************************************************/ static GArray * @@ -899,6 +950,11 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->slave_set_option = slave_set_option; platform_class->slave_get_option = slave_get_option; + platform_class->vlan_add = vlan_add; + platform_class->vlan_get_info = vlan_get_info; + platform_class->vlan_set_ingress_map = vlan_set_ingress_map; + platform_class->vlan_set_egress_map = vlan_set_egress_map; + platform_class->ip4_address_get_all = ip4_address_get_all; platform_class->ip6_address_get_all = ip6_address_get_all; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 9611a054a4..00c748de46 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -273,6 +273,8 @@ type_to_string (NMLinkType type) return "bond"; case NM_LINK_TYPE_TEAM: return "team"; + case NM_LINK_TYPE_VLAN: + return "vlan"; default: g_warning ("Wrong type: %d", type); return NULL; @@ -313,6 +315,8 @@ link_extract_type (struct rtnl_link *rtnllink, const char **out_name) return_type (NM_LINK_TYPE_BOND, "bond"); else if (!strcmp (type, "team")) return_type (NM_LINK_TYPE_TEAM, "team"); + else if (!strcmp (type, "vlan")) + return_type (NM_LINK_TYPE_VLAN, "vlan"); else return_type (NM_LINK_TYPE_UNKNOWN, "unknown"); } @@ -1104,6 +1108,63 @@ link_supports_vlans (NMPlatform *platform, int ifindex) return !(features->features[block].active & (1 << bit)); } +static int +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +{ + struct nl_object *object = build_rtnl_link (0, name, NM_LINK_TYPE_VLAN); + struct rtnl_link *rtnllink = (struct rtnl_link *) object; + unsigned int kernel_flags; + + kernel_flags = 0; + if (vlan_flags & NM_VLAN_FLAG_REORDER_HEADERS) + kernel_flags |= VLAN_FLAG_REORDER_HDR; + if (vlan_flags & NM_VLAN_FLAG_GVRP) + kernel_flags |= VLAN_FLAG_GVRP; + if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING) + kernel_flags |= VLAN_FLAG_LOOSE_BINDING; + + rtnl_link_set_link (rtnllink, parent); + rtnl_link_vlan_set_id (rtnllink, vlan_id); + rtnl_link_vlan_set_flags (rtnllink, vlan_flags); + + return add_object (platform, object); +} + +static gboolean +vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id) +{ + auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex); + + if (parent) + *parent = rtnllink ? rtnl_link_get_link (rtnllink) : 0; + if (vlan_id) + *vlan_id = rtnllink ? rtnl_link_vlan_get_id (rtnllink) : 0; + + return !!rtnllink; +} + +static gboolean +vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + auto_nl_object struct rtnl_link *change = rtnl_link_alloc (); + + g_assert (change); + rtnl_link_vlan_set_egress_map (change, from, to); + + return link_change (platform, ifindex, change); +} + +static gboolean +vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) +{ + auto_nl_object struct rtnl_link *change = rtnl_link_alloc (); + + g_assert (change); + rtnl_link_vlan_set_egress_map (change, from, to); + + return link_change (platform, ifindex, change); +} + static gboolean link_refresh (NMPlatform *platform, int ifindex, int nle) { @@ -1690,6 +1751,11 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->slave_set_option = slave_set_option; platform_class->slave_get_option = slave_get_option; + platform_class->vlan_add = vlan_add; + platform_class->vlan_get_info = vlan_get_info; + platform_class->vlan_set_ingress_map = vlan_set_ingress_map; + platform_class->vlan_set_egress_map = vlan_set_egress_map; + platform_class->ip4_address_get_all = ip4_address_get_all; platform_class->ip6_address_get_all = ip6_address_get_all; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 7034181c6d..4ddab10b13 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -695,6 +695,36 @@ nm_platform_team_add (const char *name) return nm_platform_link_add (name, NM_LINK_TYPE_TEAM); } +/** + * nm_platform_vlan_add: + * @name: New interface name + * @vlanid: VLAN identifier + * @vlanflags: VLAN flags from libnm-util + * + * Create a software VLAN device. + */ +gboolean +nm_platform_vlan_add (const char *name, int parent, int vlanid, guint32 vlanflags) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (parent >= 0, FALSE); + g_return_val_if_fail (vlanid >= 0, FALSE); + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (klass->vlan_add, FALSE); + + if (nm_platform_link_exists (name)) { + debug ("link already exists: %s", name); + platform->error = NM_PLATFORM_ERROR_EXISTS; + return FALSE; + } + + debug ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x", + name, parent, vlanid, vlanflags); + return klass->vlan_add (platform, name, parent, vlanid, vlanflags); +} + gboolean nm_platform_master_set_option (int ifindex, const char *option, const char *value) { @@ -745,6 +775,49 @@ nm_platform_slave_get_option (int ifindex, const char *option) return klass->slave_get_option (platform, ifindex, option); } +gboolean +nm_platform_vlan_get_info (int ifindex, int *parent, int *vlanid) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (klass->vlan_get_info, FALSE); + + if (parent) + *parent = 0; + if (vlanid) + *vlanid = 0; + + if (nm_platform_link_get_type (ifindex) != NM_LINK_TYPE_VLAN) + return FALSE; + + return klass->vlan_get_info (platform, ifindex, parent, vlanid); +} + +gboolean +nm_platform_vlan_set_ingress_map (int ifindex, int from, int to) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (klass->vlan_set_ingress_map, FALSE); + + debug ("link: setting vlan ingress map for %d from %d to %d", ifindex, from, to); + return klass->vlan_set_ingress_map (platform, ifindex, from, to); +} + +gboolean +nm_platform_vlan_set_egress_map (int ifindex, int from, int to) +{ + reset_error (); + + g_assert (platform); + g_return_val_if_fail (klass->vlan_set_egress_map, FALSE); + + debug ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to); + return klass->vlan_set_egress_map (platform, ifindex, from, to); +} + /******************************************************************/ GArray * diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 19e0fe8311..3e353e452d 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -55,6 +55,7 @@ typedef enum { NM_LINK_TYPE_BRIDGE, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM, + NM_LINK_TYPE_VLAN, } NMLinkType; typedef struct { @@ -169,6 +170,11 @@ typedef struct { gboolean (*slave_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option); + gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags); + gboolean (*vlan_get_info) (NMPlatform *, int ifindex, int *parent, int *vlan_id); + gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to); + gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to); + GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex); GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex); gboolean (*ip4_address_add) (NMPlatform *, int ifindex, in_addr_t address, int plen); @@ -266,6 +272,11 @@ char *nm_platform_master_get_option (int ifindex, const char *option); gboolean nm_platform_slave_set_option (int ifindex, const char *option, const char *value); char *nm_platform_slave_get_option (int ifindex, const char *option); +gboolean nm_platform_vlan_add (const char *name, int parent, int vlanid, guint32 vlanflags); +gboolean nm_platform_vlan_get_info (int ifindex, int *parent, int *vlanid); +gboolean nm_platform_vlan_set_ingress_map (int ifindex, int from, int to); +gboolean nm_platform_vlan_set_egress_map (int ifindex, int from, int to); + GArray *nm_platform_ip4_address_get_all (int ifindex); GArray *nm_platform_ip6_address_get_all (int ifindex); gboolean nm_platform_ip4_address_add (int ifindex, in_addr_t address, int plen); diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c index d5397032ea..d45d0be5cd 100644 --- a/src/platform/tests/dump.c +++ b/src/platform/tests/dump.c @@ -20,6 +20,7 @@ dump_interface (NMPlatformLink *link) const NMPlatformIP4Route *ip4_route; char networkstr[INET6_ADDRSTRLEN]; char gatewaystr[INET6_ADDRSTRLEN]; + int vlan_id, vlan_parent; int i; g_assert (link->up || !link->connected); @@ -34,6 +35,9 @@ dump_interface (NMPlatformLink *link) if (link->master) printf (" master %d", link->master); printf ("\n"); + nm_platform_vlan_get_info (link->ifindex, &vlan_parent, &vlan_id); + if (vlan_parent) + printf (" vlan parent %d id %d\n", vlan_parent, vlan_id); if (nm_platform_link_supports_carrier_detect (link->ifindex)) printf (" feature carrier-detect\n"); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index b5f0f0b515..92fb351049 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -53,6 +53,21 @@ do_sysctl_get (char **argv) return !!value; } +static int +parse_ifindex (const char *str) +{ + char *endptr; + int ifindex = 0; + + ifindex = strtol (str, &endptr, 10); + + if (*endptr) { + ifindex = nm_platform_link_get_ifindex (str); + } + + return ifindex; +} + static gboolean do_link_get_all (char **argv) { @@ -95,6 +110,17 @@ do_team_add (char **argv) return nm_platform_team_add (argv[0]); } +static gboolean +do_vlan_add (char **argv) +{ + const char *name = *argv++; + int parent = parse_ifindex (*argv++); + int vlanid = strtol (*argv++, NULL, 10); + guint32 vlan_flags = strtol (*argv++, NULL, 10); + + return nm_platform_vlan_add (name, parent, vlanid, vlan_flags); +} + static gboolean do_link_exists (char **argv) { @@ -105,21 +131,6 @@ do_link_exists (char **argv) return TRUE; } -static int -parse_ifindex (const char *str) -{ - char *endptr; - int ifindex = 0; - - ifindex = strtol (str, &endptr, 10); - - if (*endptr) { - ifindex = nm_platform_link_get_ifindex (str); - } - - return ifindex; -} - #define LINK_CMD(cmdname) \ static gboolean \ do_link_##cmdname (char **argv) \ @@ -240,6 +251,41 @@ do_slave_get_option (char **argv) return !!value; } +static gboolean +do_vlan_get_info (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int parent; + int vlanid; + + if (!nm_platform_vlan_get_info (ifindex, &parent, &vlanid)) + return FALSE; + + printf ("%d %d\n", parent, vlanid); + + return TRUE; +} + +static gboolean +do_vlan_set_ingress_map (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int from = strtol (*argv++, NULL, 10); + int to = strtol (*argv++, NULL, 10); + + return nm_platform_vlan_set_ingress_map (ifindex, from, to); +} + +static gboolean +do_vlan_set_egress_map (char **argv) +{ + int ifindex = parse_ifindex (*argv++); + int from = strtol (*argv++, NULL, 10); + int to = strtol (*argv++, NULL, 10); + + return nm_platform_vlan_set_egress_map (ifindex, from, to); +} + static gboolean do_ip4_address_get_all (char **argv) { @@ -487,6 +533,7 @@ static const command_t commands[] = { { "bridge-add", "add bridge interface", do_bridge_add, 1, "" }, { "bond-add", "add bond interface", do_bond_add, 1, "" }, { "team-add", "add team interface", do_team_add, 1, "" }, + { "vlan-add", "add vlan interface", do_vlan_add, 4, " " }, { "link-exists", "check ifname for existance", do_link_exists, 1, "" }, { "link-delete", "delete interface", do_link_delete, 1, "" }, { "link-get-ifindex>", "get interface index", do_link_get_ifindex, 1, "" }, @@ -514,6 +561,11 @@ static const command_t commands[] = { "