platform: vlan support

This commit is contained in:
Pavel Šimerda 2013-03-27 22:53:55 +01:00
parent aa943f3115
commit a28a880214
7 changed files with 320 additions and 15 deletions

View file

@ -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;

View file

@ -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;

View file

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

View file

@ -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);

View file

@ -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");

View file

@ -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, "<ifname>" },
{ "bond-add", "add bond interface", do_bond_add, 1, "<ifname>" },
{ "team-add", "add team interface", do_team_add, 1, "<ifname>" },
{ "vlan-add", "add vlan interface", do_vlan_add, 4, "<ifname> <parent> <vlanid> <vlanflags>" },
{ "link-exists", "check ifname for existance", do_link_exists, 1, "<ifname>" },
{ "link-delete", "delete interface", do_link_delete, 1, "<ifname/ifindex>" },
{ "link-get-ifindex>", "get interface index", do_link_get_ifindex, 1, "<ifname>" },
@ -514,6 +561,11 @@ static const command_t commands[] = {
"<ifname/ifindex> <option>" },
{ "link-slave-get-option", "get slave option", do_slave_get_option, 2,
"<ifname/ifindex> <option>" },
{ "vlan-get-info", "get vlan info", do_vlan_get_info, 1, "<ifname/ifindex>" },
{ "vlan-set-ingress-map", "set vlan ingress map", do_vlan_set_ingress_map, 3,
"<ifname/ifindex> <from> <to>" },
{ "vlan-set-egress-map", "set vlan egress map", do_vlan_set_egress_map, 3,
"<ifname/ifindex> <from> <to>" },
{ "ip4-address-get-all", "print all IPv4 addresses", do_ip4_address_get_all, 1, "<ifname/ifindex>" },
{ "ip6-address-get-all", "print all IPv6 addresses", do_ip6_address_get_all, 1, "<ifname/ifindex>" },
{ "ip4-address-add", "add IPv4 address", do_ip4_address_add, 2, "<ifname/ifindex> <address>/<plen>" },

View file

@ -9,6 +9,9 @@
#define BOGUS_NAME "nm-bogus-device"
#define BOGUS_IFINDEX INT_MAX
#define SLAVE_NAME "nm-test-slave"
#define PARENT_NAME "nm-test-parent"
#define VLAN_ID 4077
#define VLAN_FLAGS 0
static void
link_callback (NMPlatform *platform, int ifindex, NMPlatformLink *received, SignalData *data)
@ -89,6 +92,13 @@ test_bogus(void)
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_supports_vlans (BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_vlan_get_info (BOGUS_IFINDEX, NULL, NULL));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_vlan_set_ingress_map (BOGUS_IFINDEX, 0, 0));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_vlan_set_egress_map (BOGUS_IFINDEX, 0, 0));
error (NM_PLATFORM_ERROR_NOT_FOUND);
}
static void
@ -127,6 +137,17 @@ virtual_add (NMLinkType link_type, const char *name, SignalData *link_added, Sig
}
case NM_LINK_TYPE_TEAM:
return nm_platform_team_add (name);
case NM_LINK_TYPE_VLAN:
/* Don't call link_callback for the bridge interface */
if (nm_platform_bridge_add (PARENT_NAME))
accept_signal (link_added);
g_assert (nm_platform_link_set_up (nm_platform_link_get_ifindex (PARENT_NAME)));
accept_signal (link_changed);
return nm_platform_vlan_add (name,
nm_platform_link_get_ifindex (PARENT_NAME),
VLAN_ID, 0);
default:
g_error ("Link type %d unhandled.", link_type);
}
@ -234,6 +255,7 @@ test_virtual (NMLinkType link_type, const char *link_typename)
{
int ifindex;
char *value;
int vlan_parent, vlan_id;
SignalData *link_added = add_signal ("link-added", link_callback);
SignalData *link_changed = add_signal ("link-changed", link_callback);
@ -247,6 +269,12 @@ test_virtual (NMLinkType link_type, const char *link_typename)
g_assert (ifindex >= 0);
g_assert_cmpint (nm_platform_link_get_type (ifindex), ==, link_type);
g_assert_cmpstr (nm_platform_link_get_type_name (ifindex), ==, link_typename);
if (link_type == NM_LINK_TYPE_VLAN) {
g_assert (nm_platform_vlan_get_info (ifindex, &vlan_parent, &vlan_id));
g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (PARENT_NAME));
g_assert_cmpint (vlan_id, ==, VLAN_ID);
no_error ();
}
accept_signal (link_added);
/* Add again */
@ -312,6 +340,12 @@ test_virtual (NMLinkType link_type, const char *link_typename)
g_assert (!nm_platform_link_delete_by_name (DEVICE_NAME));
error (NM_PLATFORM_ERROR_NOT_FOUND);
/* VLAN: Delete parent */
if (link_type == NM_LINK_TYPE_VLAN) {
g_assert (nm_platform_link_delete_by_name (PARENT_NAME));
accept_signal (link_removed);
}
/* No pending signal */
free_signal (link_added);
free_signal (link_changed);
@ -336,6 +370,12 @@ test_team (void)
test_virtual (NM_LINK_TYPE_TEAM, "team");
}
static void
test_vlan ()
{
test_virtual (NM_LINK_TYPE_VLAN, "vlan");
}
static void
test_internal (void)
{
@ -491,8 +531,10 @@ main (int argc, char **argv)
/* Clean up */
nm_platform_link_delete_by_name (DEVICE_NAME);
nm_platform_link_delete_by_name (SLAVE_NAME);
nm_platform_link_delete_by_name (PARENT_NAME);
g_assert (!nm_platform_link_exists (DEVICE_NAME));
g_assert (!nm_platform_link_exists (SLAVE_NAME));
g_assert (!nm_platform_link_exists (PARENT_NAME));
g_test_add_func ("/link/bogus", test_bogus);
g_test_add_func ("/link/loopback", test_loopback);
@ -500,6 +542,7 @@ main (int argc, char **argv)
g_test_add_func ("/link/virtual/bridge", test_bridge);
g_test_add_func ("/link/virtual/bond", test_bond);
g_test_add_func ("/link/virtual/team", test_team);
g_test_add_func ("/link/virtual/vlan", test_vlan);
if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform"))
g_test_add_func ("/link/external", test_external);