Commit 65a13f9d authored by Dan Williams's avatar Dan Williams

core: convert VLAN interfaces to a device subclass

Many different interface types can support VLANs, including
Infiniband, WiFi, etc.  So we have to create a new device class
for them instead of keeping the support in NMDeviceEthernet.
parent 5ee78414
......@@ -121,6 +121,7 @@ typedef enum {
NM_DEVICE_TYPE_MODEM = 8,
NM_DEVICE_TYPE_INFINIBAND = 9,
NM_DEVICE_TYPE_BOND = 10,
NM_DEVICE_TYPE_VLAN = 11,
} NMDeviceType;
/**
......
......@@ -12,6 +12,7 @@ EXTRA_DIST = \
nm-device-wimax.xml \
nm-device-infiniband.xml \
nm-device-bond.xml \
nm-device-vlan.xml \
nm-device.xml \
nm-ip4-config.xml \
nm-ip6-config.xml \
......
......@@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<xi:include href="nm-device-wimax.xml"/>
<xi:include href="nm-device-infiniband.xml"/>
<xi:include href="nm-device-bond.xml"/>
<xi:include href="nm-device-vlan.xml"/>
<xi:include href="nm-wimax-nsp.xml"/>
<xi:include href="nm-ip4-config.xml"/>
<xi:include href="nm-ip6-config.xml"/>
......
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.freedesktop.NetworkManager.Device.Vlan">
<property name="HwAddress" type="s" access="read">
<tp:docstring>
Hardware address of the device.
</tp:docstring>
</property>
<property name="Carrier" type="b" access="read">
<tp:docstring>
Indicates whether the physical carrier is found (e.g. whether a cable is plugged in or not).
</tp:docstring>
</property>
<property name="VlanId" type="u" access="read">
<tp:docstring>
The VLAN ID of this VLAN interface.
</tp:docstring>
</property>
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
<tp:docstring>
A dictionary mapping property names to variant boxed values
</tp:docstring>
</arg>
</signal>
</interface>
</node>
......@@ -251,6 +251,11 @@
The device is a bond master interface.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="VLAN" value="11">
<tp:docstring>
The device is a VLAN interface.
</tp:docstring>
</tp:enumvalue>
</tp:enum>
<tp:flags name="NM_DEVICE_CAP" value-prefix="NM_DEVICE_CAP" type="u">
......
......@@ -26,6 +26,7 @@ src/nm-device-bt.c
src/nm-device-ethernet.c
src/nm-device-infiniband.c
src/nm-device-olpc-mesh.c
src/nm-device-vlan.c
src/nm-manager.c
src/nm-netlink-monitor.c
src/settings/plugins/ifcfg-rh/reader.c
......
......@@ -134,6 +134,8 @@ NetworkManager_SOURCES = \
nm-device-infiniband.h \
nm-device-bond.c \
nm-device-bond.h \
nm-device-vlan.c \
nm-device-vlan.h \
nm-wifi-ap.c \
nm-wifi-ap.h \
nm-wifi-ap-utils.c \
......@@ -228,6 +230,9 @@ nm-device-olpc-mesh-glue.h: $(top_srcdir)/introspection/nm-device-olpc-mesh.xml
nm-device-bond-glue.h: $(top_srcdir)/introspection/nm-device-bond.xml
$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_bond --mode=glib-server --output=$@ $<
nm-device-vlan-glue.h: $(top_srcdir)/introspection/nm-device-vlan.xml
$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_vlan --mode=glib-server --output=$@ $<
nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
$(AM_V_GEN) dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $<
......@@ -253,6 +258,7 @@ BUILT_SOURCES = \
nm-device-ethernet-glue.h \
nm-device-infiniband-glue.h \
nm-device-bond-glue.h \
nm-device-vlan-glue.h \
nm-device-wifi-glue.h \
nm-device-olpc-mesh-glue.h \
nm-device-bt-glue.h \
......
......@@ -49,7 +49,6 @@
#include "nm-setting-8021x.h"
#include "nm-setting-pppoe.h"
#include "nm-setting-bond.h"
#include "nm-setting-vlan.h"
#include "ppp-manager/nm-ppp-manager.h"
#include "nm-logging.h"
#include "nm-properties-changed-signal.h"
......@@ -97,10 +96,6 @@ typedef struct {
/* PPPoE */
NMPPPManager *ppp_manager;
NMIP4Config *pending_ip4_config;
/* VLAN stuff */
int vlan_id;
int vlan_master_ifindex;
} NMDeviceEthernetPrivate;
enum {
......@@ -250,56 +245,23 @@ constructor (GType type,
object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
if (object) {
self = NM_DEVICE (object);
priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
self = NM_DEVICE (object);
priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
// FIXME: Convert this into a no-export property so type can be specified
// when the device is created.
itype = nm_system_get_iface_type (nm_device_get_ifindex (self), nm_device_get_iface (self));
if (itype == NM_IFACE_TYPE_UNSPEC) {
/* normal ethernet, pass */
} else if (itype == NM_IFACE_TYPE_VLAN) {
char *master_iface;
if (!nm_system_get_iface_vlan_info (nm_device_get_ifindex (self),
&priv->vlan_master_ifindex,
&priv->vlan_id)) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to get VLAN interface info.",
nm_device_get_iface (self));
g_object_unref (object);
return NULL;
}
// FIXME: Convert this into a no-export property so type can be specified
// when the device is created.
itype = nm_system_get_iface_type (nm_device_get_ifindex (self), nm_device_get_iface (self));
g_assert (itype == NM_IFACE_TYPE_UNSPEC);
if (priv->vlan_master_ifindex < 0 || priv->vlan_id < 0) {
nm_log_warn (LOGD_DEVICE, "(%s): VLAN master ifindex (%d) or VLAN ID (%d) invalid.",
nm_device_get_iface (self),
priv->vlan_master_ifindex,
priv->vlan_id);
g_object_unref (object);
return NULL;
}
nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)));
master_iface = nm_netlink_index_to_iface (priv->vlan_master_ifindex);
nm_log_info (LOGD_DEVICE, "(%s): VLAN ID %d with master %s (ifindex: %d)",
nm_device_get_iface (self),
priv->vlan_id,
master_iface ? master_iface : "(unknown)",
priv->vlan_master_ifindex);
g_free (master_iface);
} else {
g_assert_not_reached ();
/* s390 stuff */
_update_s390_subchannels (NM_DEVICE_ETHERNET (self));
}
nm_log_dbg (LOGD_HW | LOGD_ETHER, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)));
/* s390 stuff */
_update_s390_subchannels (NM_DEVICE_ETHERNET (self));
return object;
}
......@@ -338,11 +300,6 @@ device_state_changed (NMDevice *device,
static void
nm_device_ethernet_init (NMDeviceEthernet * self)
{
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
priv->vlan_id = -1;
priv->vlan_master_ifindex = -1;
g_signal_connect (self, "state-changed", G_CALLBACK (device_state_changed), NULL);
}
......@@ -602,74 +559,6 @@ match_ethernet_connection (NMDevice *device, NMConnection *connection,
if (nm_connection_is_type (connection, NM_SETTING_PPPOE_SETTING_NAME)) {
/* NOP */
} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
const char *master, *iface = NULL;
char *tmp_iface = NULL;
int con_master_ifindex = -1;
gboolean iface_matches;
g_assert (s_vlan);
g_assert (s_con);
if (priv->vlan_id < 0) {
g_set_error (error, NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
"The device was not a VLAN interface.");
return FALSE;
}
if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) {
g_set_error (error, NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
"The connection's VLAN ID did not match the device's VLAN ID.");
return FALSE;
}
/* Check master interface */
master = nm_setting_connection_get_master (s_con);
if (!master) {
g_set_error (error, NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
"The connection did not specify a VLAN master.");
return FALSE;
}
if (nm_utils_is_uuid (master)) {
/* FIXME: find the master device based on the connection UUID; this
* is a bit hard because NMDevice objects (by design) have no
* knowledge of other NMDevice objects, and we need to look through
* all active NMDevices to see if they are using the given
* connection UUID.
*/
g_warn_if_reached ();
} else {
/* It's an interface name; match it against our master */
con_master_ifindex = nm_netlink_iface_to_index (master);
if (con_master_ifindex < 0 || con_master_ifindex != priv->vlan_master_ifindex) {
g_set_error (error, NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
"The connection's VLAN master did not match the device's VLAN master interface.");
return FALSE;
}
}
/* Ensure the interface name matches, if it's given */
iface = nm_connection_get_virtual_iface_name (connection);
if (!iface) {
/* If the connection doesn't specify an interface name for the
* VLAN interface, we construct it from the master interface name
* and the VLAN ID.
*/
if (con_master_ifindex >= 0)
iface = tmp_iface = nm_utils_new_vlan_name (master, nm_setting_vlan_get_id (s_vlan));
}
iface_matches = (g_strcmp0 (nm_device_get_ip_iface (device), iface) == 0);
g_free (tmp_iface);
if (!iface_matches) {
g_set_error (error, NM_ETHERNET_ERROR, NM_ETHERNET_ERROR_CONNECTION_INVALID,
"The VLAN connection virtual interface name did not match.");
return FALSE;
}
} else if (nm_connection_is_type (connection, NM_SETTING_WIRED_SETTING_NAME)) {
if (!s_wired) {
g_set_error (error,
......
This diff is collapsed.
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright 2012 Red Hat, Inc.
*/
#ifndef NM_DEVICE_VLAN_H
#define NM_DEVICE_VLAN_H
#include <glib-object.h>
#include "nm-device-wired.h"
G_BEGIN_DECLS
#define NM_TYPE_DEVICE_VLAN (nm_device_vlan_get_type ())
#define NM_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlan))
#define NM_DEVICE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass))
#define NM_IS_DEVICE_VLAN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_VLAN))
#define NM_IS_DEVICE_VLAN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_VLAN))
#define NM_DEVICE_VLAN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_VLAN, NMDeviceVlanClass))
typedef enum {
NM_VLAN_ERROR_CONNECTION_NOT_VLAN = 0,
NM_VLAN_ERROR_CONNECTION_INVALID,
NM_VLAN_ERROR_CONNECTION_INCOMPATIBLE,
} NMVlanError;
#define NM_DEVICE_VLAN_HW_ADDRESS "hw-address"
#define NM_DEVICE_VLAN_CARRIER "carrier"
#define NM_DEVICE_VLAN_ID "vlan-id"
typedef struct {
NMDevice parent;
} NMDeviceVlan;
typedef struct {
NMDeviceClass parent;
/* Signals */
void (*properties_changed) (NMDeviceVlan *device, GHashTable *properties);
} NMDeviceVlanClass;
GType nm_device_vlan_get_type (void);
NMDevice *nm_device_vlan_new (const char *udi,
const char *iface,
NMDevice *parent);
G_END_DECLS
#endif /* NM_DEVICE_VLAN_H */
......@@ -47,6 +47,7 @@
#include "nm-device-modem.h"
#include "nm-device-infiniband.h"
#include "nm-device-bond.h"
#include "nm-device-vlan.h"
#include "nm-system.h"
#include "nm-properties-changed-signal.h"
#include "nm-setting-bluetooth.h"
......@@ -914,38 +915,30 @@ get_active_connections (NMManager *manager, NMConnection *filter)
/* Settings stuff via NMSettings */
/*******************************************************************/
static const char *
get_iface_from_hwaddr (NMManager *self,
NMConnection *connection,
int *out_ifindex)
static NMDevice *
get_device_from_hwaddr (NMManager *self, NMConnection *connection)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *candidate = iter->data;
if (nm_device_hwaddr_matches (candidate, connection, NULL, 0, TRUE)) {
if (out_ifindex)
*out_ifindex = nm_device_get_ip_ifindex (candidate);
return nm_device_get_ip_iface (candidate);
}
if (nm_device_hwaddr_matches (NM_DEVICE (iter->data), connection, NULL, 0, TRUE))
return iter->data;
}
return NULL;
}
static const char *
find_vlan_parent_iface (NMManager *self,
NMConnection *connection,
gboolean check_hwaddr,
int *out_parent_ifindex)
static NMDevice*
find_vlan_parent (NMManager *self,
NMConnection *connection,
gboolean check_hwaddr)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMSettingVlan *s_vlan;
const char *parent;
NMConnection *parent_connection;
const char *parent_iface;
NMDevice *parent = NULL;
GSList *iter;
NMDevice *device;
/* The 'parent' property could be either an interface name, a connection
* UUID, or even given by the MAC address of the connection's ethernet,
......@@ -954,33 +947,32 @@ find_vlan_parent_iface (NMManager *self,
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
parent = nm_setting_vlan_get_parent (s_vlan);
if (parent) {
device = find_device_by_ip_iface (self, parent);
if (device) {
if (out_parent_ifindex)
*out_parent_ifindex = nm_device_get_ip_ifindex (device);
parent_iface = nm_setting_vlan_get_parent (s_vlan);
if (parent_iface) {
parent = find_device_by_ip_iface (self, parent_iface);
if (parent)
return parent;
}
if (nm_utils_is_uuid (parent)) {
if (nm_utils_is_uuid (parent_iface)) {
/* Try as a connection UUID */
parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent);
parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface);
if (parent_connection) {
/* Check if the parent connection is activated on some device already */
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
NMDevice *candidate = NM_DEVICE (iter->data);
if (nm_device_get_connection (candidate) == parent_connection) {
if (out_parent_ifindex)
*out_parent_ifindex = nm_device_get_ip_ifindex (candidate);
return nm_device_get_iface (candidate);
NMActRequest *req;
NMConnection *candidate;
req = nm_device_get_act_request (NM_DEVICE (iter->data));
if (req) {
candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
if (candidate == parent_connection)
return parent;
}
}
/* Check the hardware address of the parent connection */
if (check_hwaddr)
return get_iface_from_hwaddr (self, parent_connection, out_parent_ifindex);
return get_device_from_hwaddr (self, parent_connection);
}
return NULL;
}
......@@ -988,7 +980,7 @@ find_vlan_parent_iface (NMManager *self,
/* Try the hardware address from the VLAN connection's hardware setting */
if (check_hwaddr)
return get_iface_from_hwaddr (self, connection, out_parent_ifindex);
return get_device_from_hwaddr (self, connection);
return NULL;
}
......@@ -997,7 +989,7 @@ find_vlan_parent_iface (NMManager *self,
* get_virtual_iface_name:
* @self: the #NMManager
* @connection: the #NMConnection representing a virtual interface
* @out_parent_ifindex: on success, the parent interface index if any
* @out_parent: on success, the parent device if any
*
* Given @connection, returns the interface name that the connection
* would represent. If the interface name is not given by the connection,
......@@ -1009,24 +1001,25 @@ find_vlan_parent_iface (NMManager *self,
static char *
get_virtual_iface_name (NMManager *self,
NMConnection *connection,
int *out_parent_ifindex)
NMDevice **out_parent)
{
char *vname = NULL;
NMDevice *parent = NULL;
if (out_parent_ifindex)
*out_parent_ifindex = -1;
if (out_parent)
*out_parent = NULL;
if (nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
return g_strdup (nm_connection_get_virtual_iface_name (connection));
if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
NMSettingVlan *s_vlan;
const char *ifname, *parent;
const char *ifname;
s_vlan = nm_connection_get_setting_vlan (connection);
g_return_val_if_fail (s_vlan != NULL, NULL);
parent = find_vlan_parent_iface (self, connection, TRUE, out_parent_ifindex);
parent = find_vlan_parent (self, connection, TRUE);
if (parent) {
/* If the connection doesn't specify the interface name for the VLAN
* device, we create one for it using the VLAN ID and the parent
......@@ -1035,8 +1028,12 @@ get_virtual_iface_name (NMManager *self,
ifname = nm_connection_get_virtual_iface_name (connection);
if (ifname)
vname = g_strdup (ifname);
else
vname = nm_utils_new_vlan_name (parent, nm_setting_vlan_get_id (s_vlan));
else {
vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent),
nm_setting_vlan_get_id (s_vlan));
}
if (out_parent)
*out_parent = parent;
}
}
......@@ -1078,10 +1075,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GSList *iter;
char *iface = NULL, *udi;
NMDevice *device = NULL;
int parent_ifindex = -1;
NMDevice *device = NULL, *parent = NULL;
iface = get_virtual_iface_name (self, connection, &parent_ifindex);
iface = get_virtual_iface_name (self, connection, &parent);
if (!iface) {
nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
nm_connection_get_id (connection));
......@@ -1112,15 +1108,15 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
device = nm_device_bond_new (udi, iface);
g_free (udi);
} else if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
g_return_val_if_fail (parent_ifindex >= 0, FALSE);
g_return_val_if_fail (parent != NULL, FALSE);
if (!nm_system_add_vlan_iface (connection, iface, parent_ifindex)) {
if (!nm_system_add_vlan_iface (connection, iface, nm_device_get_ip_ifindex (parent))) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to add VLAN interface for '%s'",
iface, nm_connection_get_id (connection));
goto out;
}
udi = get_virtual_iface_placeholder_udi ();
device = nm_device_ethernet_new (udi, iface, "8021q");
device = nm_device_vlan_new (udi, iface, parent);
g_free (udi);
}
......@@ -2456,7 +2452,7 @@ nm_manager_activate_connection (NMManager *manager,
} else {
NMDeviceState state;
char *iface;
int master_ifindex = -1;
NMDevice *parent = NULL;
/* Device-based connection */
if (device_path) {
......@@ -2503,7 +2499,7 @@ nm_manager_activate_connection (NMManager *manager,
return NULL;
}
iface = get_virtual_iface_name (manager, connection, &master_ifindex);
iface = get_virtual_iface_name (manager, connection, &parent);
if (!iface) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Failed to determine connection's virtual interface name");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment