mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-06-20 07:08:29 +02:00
platform,device: merge branch 'lr/bridge-rh1141266'
Assume connections for bridges with slaves, and associated fixes for bridges. https://bugzilla.redhat.com/show_bug.cgi?id=1141266
This commit is contained in:
commit
1f1aebebea
4 changed files with 205 additions and 55 deletions
|
|
@ -977,6 +977,22 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure
|
|||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_finish_init:
|
||||
* @self: the master device
|
||||
*
|
||||
* Whatever needs to be done post-initialization, when the device has a DBus
|
||||
* object name.
|
||||
*/
|
||||
void
|
||||
nm_device_finish_init (NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
if (priv->master)
|
||||
nm_device_enslave_slave (priv->master, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
carrier_changed (NMDevice *self, gboolean carrier)
|
||||
{
|
||||
|
|
@ -1137,6 +1153,27 @@ update_for_ip_ifname_change (NMDevice *self)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_set_master (NMDevice *self, int ifindex)
|
||||
{
|
||||
NMDevice *master;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
master = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex);
|
||||
if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) {
|
||||
g_clear_object (&priv->master);
|
||||
priv->master = g_object_ref (master);
|
||||
nm_device_master_add_slave (master, self, FALSE);
|
||||
} else if (master) {
|
||||
_LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring",
|
||||
nm_device_get_iface (master));
|
||||
} else {
|
||||
_LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s",
|
||||
ifindex,
|
||||
nm_platform_link_get_name (ifindex));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
device_link_changed (NMDevice *self, NMPlatformLink *info)
|
||||
{
|
||||
|
|
@ -1180,25 +1217,12 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||
}
|
||||
|
||||
/* Update slave status for external changes */
|
||||
if (info->master && !priv->enslaved) {
|
||||
NMDevice *master;
|
||||
|
||||
master = nm_manager_get_device_by_ifindex (nm_manager_get (), info->master);
|
||||
if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) {
|
||||
g_clear_object (&priv->master);
|
||||
priv->master = g_object_ref (master);
|
||||
nm_device_master_add_slave (master, self, FALSE);
|
||||
nm_device_enslave_slave (master, self, NULL);
|
||||
} else if (master) {
|
||||
_LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring",
|
||||
nm_device_get_iface (master));
|
||||
} else {
|
||||
_LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s",
|
||||
info->master,
|
||||
nm_platform_link_get_name (info->master));
|
||||
}
|
||||
} else if (priv->enslaved && !info->master)
|
||||
if (priv->enslaved && info->master != nm_device_get_ifindex (priv->master))
|
||||
nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE);
|
||||
if (info->master && !priv->enslaved)
|
||||
device_set_master (self, info->master);
|
||||
if (priv->master)
|
||||
nm_device_enslave_slave (priv->master, self, NULL);
|
||||
|
||||
if (klass->link_changed)
|
||||
klass->link_changed (self, info);
|
||||
|
|
@ -1380,6 +1404,7 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure)
|
|||
G_CALLBACK (slave_state_changed), self);
|
||||
priv->slaves = g_slist_append (priv->slaves, info);
|
||||
}
|
||||
nm_device_queue_recheck_assume (self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -1965,8 +1990,9 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
|
|||
ip6_method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);
|
||||
if ( g_strcmp0 (ip4_method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0
|
||||
&& g_strcmp0 (ip6_method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0
|
||||
&& !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))) {
|
||||
_LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not slave)");
|
||||
&& !nm_setting_connection_get_master (NM_SETTING_CONNECTION (s_con))
|
||||
&& !priv->slaves) {
|
||||
_LOGD (LOGD_DEVICE, "ignoring generated connection (no IP and not in master-slave relationship)");
|
||||
g_object_unref (connection);
|
||||
connection = NULL;
|
||||
}
|
||||
|
|
@ -2126,7 +2152,7 @@ nm_device_emit_recheck_assume (gpointer self)
|
|||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
priv->recheck_assume_id = 0;
|
||||
if (!nm_device_get_act_request (self) && (priv->ip4_config || priv->ip6_config)) {
|
||||
if (!nm_device_get_act_request (self)) {
|
||||
_LOGD (LOGD_DEVICE, "emit RECHECK_ASSUME signal");
|
||||
g_signal_emit (self, signals[RECHECK_ASSUME], 0);
|
||||
}
|
||||
|
|
@ -7944,6 +7970,7 @@ constructed (GObject *object)
|
|||
{
|
||||
NMDevice *self = NM_DEVICE (object);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
int master;
|
||||
|
||||
nm_device_update_hw_address (self);
|
||||
|
||||
|
|
@ -7976,6 +8003,11 @@ constructed (GObject *object)
|
|||
if (priv->is_software)
|
||||
priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE;
|
||||
|
||||
/* Enslave ourselves */
|
||||
master = nm_platform_link_get_master (priv->ifindex);
|
||||
if (master)
|
||||
device_set_master (self, master);
|
||||
|
||||
priv->con_provider = nm_connection_provider_get ();
|
||||
g_assert (priv->con_provider);
|
||||
g_signal_connect (priv->con_provider,
|
||||
|
|
|
|||
|
|
@ -216,6 +216,8 @@ GType nm_device_get_type (void);
|
|||
const char * nm_device_get_path (NMDevice *dev);
|
||||
void nm_device_dbus_export (NMDevice *device);
|
||||
|
||||
void nm_device_finish_init (NMDevice *device);
|
||||
|
||||
const char * nm_device_get_udi (NMDevice *dev);
|
||||
const char * nm_device_get_iface (NMDevice *dev);
|
||||
int nm_device_get_ifindex (NMDevice *dev);
|
||||
|
|
|
|||
|
|
@ -1819,6 +1819,7 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
|
|||
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);
|
||||
|
||||
nm_device_dbus_export (device);
|
||||
nm_device_finish_init (device);
|
||||
|
||||
if (try_assume) {
|
||||
connection_assumed = recheck_assume_connection (device, self);
|
||||
|
|
|
|||
|
|
@ -1880,6 +1880,33 @@ _rtnl_addr_timestamps_equal_fuzzy (guint32 ts1, guint32 ts2)
|
|||
return diff <= 2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nm_nl_object_diff (ObjectType type, struct nl_object *_a, struct nl_object *_b)
|
||||
{
|
||||
if (nl_object_diff (_a, _b)) {
|
||||
/* libnl thinks objects are different*/
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) {
|
||||
struct rtnl_addr *a = (struct rtnl_addr *) _a;
|
||||
struct rtnl_addr *b = (struct rtnl_addr *) _b;
|
||||
|
||||
/* libnl nl_object_diff() ignores differences in timestamp. Let's care about
|
||||
* them (if they are large enough).
|
||||
*
|
||||
* Note that these valid and preferred timestamps are absolute, after
|
||||
* _rtnl_addr_hack_lifetimes_rel_to_abs(). */
|
||||
if ( !_rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (a),
|
||||
rtnl_addr_get_preferred_lifetime (b))
|
||||
|| !_rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (a),
|
||||
rtnl_addr_get_valid_lifetime (b)))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* This function does all the magic to avoid race conditions caused
|
||||
* by concurrent usage of synchronous commands and an asynchronous cache. This
|
||||
* might be a nice future addition to libnl but it requires to do all operations
|
||||
|
|
@ -1985,24 +2012,9 @@ event_notification (struct nl_msg *msg, gpointer user_data)
|
|||
* This also catches notifications for internal addition or change, unless
|
||||
* another action occured very soon after it.
|
||||
*/
|
||||
if (!nl_object_diff (kernel_object, cached_object)) {
|
||||
if (type == OBJECT_TYPE_IP4_ADDRESS || type == OBJECT_TYPE_IP6_ADDRESS) {
|
||||
struct rtnl_addr *c = (struct rtnl_addr *) cached_object;
|
||||
struct rtnl_addr *k = (struct rtnl_addr *) kernel_object;
|
||||
if (!nm_nl_object_diff (type, kernel_object, cached_object))
|
||||
return NL_OK;
|
||||
|
||||
/* libnl nl_object_diff() ignores differences in timestamp. Let's care about
|
||||
* them (if they are large enough).
|
||||
*
|
||||
* Note that these valid and preferred timestamps are absolute, after
|
||||
* _rtnl_addr_hack_lifetimes_rel_to_abs(). */
|
||||
if ( _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_preferred_lifetime (c),
|
||||
rtnl_addr_get_preferred_lifetime (k))
|
||||
&& _rtnl_addr_timestamps_equal_fuzzy (rtnl_addr_get_valid_lifetime (c),
|
||||
rtnl_addr_get_valid_lifetime (k)))
|
||||
return NL_OK;
|
||||
} else
|
||||
return NL_OK;
|
||||
}
|
||||
/* Handle external change */
|
||||
nl_cache_remove (cached_object);
|
||||
nle = nl_cache_add (cache, kernel_object);
|
||||
|
|
@ -3982,6 +3994,106 @@ ip6_route_exists (NMPlatform *platform, int ifindex, struct in6_addr network, in
|
|||
|
||||
/******************************************************************/
|
||||
|
||||
/* Initialize the link cache while ensuring all links are of AF_UNSPEC,
|
||||
* family (even though the kernel might set AF_BRIDGE for bridges).
|
||||
* See also: _nl_link_family_unset() */
|
||||
static void
|
||||
init_link_cache (NMPlatform *platform)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
struct nl_object *object = NULL;
|
||||
|
||||
rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache);
|
||||
|
||||
do {
|
||||
for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) {
|
||||
if (rtnl_link_get_family ((struct rtnl_link *)object) != AF_UNSPEC)
|
||||
break;
|
||||
}
|
||||
|
||||
if (object) {
|
||||
/* A non-AF_UNSPEC object encoutnered */
|
||||
struct nl_object *existing;
|
||||
|
||||
nl_object_get (object);
|
||||
nl_cache_remove (object);
|
||||
rtnl_link_set_family ((struct rtnl_link *)object, AF_UNSPEC);
|
||||
existing = nl_cache_search (priv->link_cache, object);
|
||||
if (existing)
|
||||
nl_object_put (existing);
|
||||
else
|
||||
nl_cache_add (priv->link_cache, object);
|
||||
nl_object_put (object);
|
||||
}
|
||||
} while (object);
|
||||
}
|
||||
|
||||
/* Calls announce_object with appropriate arguments for all objects
|
||||
* which are not coherent between old and new caches and deallocates
|
||||
* the old cache. */
|
||||
static void
|
||||
cache_announce_changes (NMPlatform *platform, struct nl_cache *new, struct nl_cache *old)
|
||||
{
|
||||
struct nl_object *object;
|
||||
|
||||
if (!old)
|
||||
return;
|
||||
|
||||
for (object = nl_cache_get_first (new); object; object = nl_cache_get_next (object)) {
|
||||
struct nl_object *cached_object = nm_nl_cache_search (old, object);
|
||||
|
||||
if (cached_object) {
|
||||
ObjectType type = object_type_from_nl_object (object);
|
||||
if (nm_nl_object_diff (type, object, cached_object))
|
||||
announce_object (platform, object, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
nl_object_put (cached_object);
|
||||
} else
|
||||
announce_object (platform, object, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
}
|
||||
for (object = nl_cache_get_first (old); object; object = nl_cache_get_next (object)) {
|
||||
struct nl_object *cached_object = nm_nl_cache_search (new, object);
|
||||
if (cached_object)
|
||||
nl_object_put (cached_object);
|
||||
else
|
||||
announce_object (platform, object, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
}
|
||||
|
||||
nl_cache_free (old);
|
||||
}
|
||||
|
||||
/* Creates and populates the netlink object caches. Called upon platform init and
|
||||
* when we run out of sync (out of buffer space, netlink congestion control). In case
|
||||
* the caches already exist, it finds changed, added and removed objects, announces
|
||||
* them and destroys the old caches. */
|
||||
static void
|
||||
cache_repopulate_all (NMPlatform *platform)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
struct nl_cache *old_link_cache = priv->link_cache;
|
||||
struct nl_cache *old_address_cache = priv->address_cache;
|
||||
struct nl_cache *old_route_cache = priv->route_cache;
|
||||
struct nl_object *object;
|
||||
|
||||
debug ("platform: %spopulate platform cache", old_link_cache ? "re" : "");
|
||||
|
||||
/* Allocate new netlink caches */
|
||||
init_link_cache (platform);
|
||||
rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache);
|
||||
rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
|
||||
g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
|
||||
|
||||
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
|
||||
_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
|
||||
}
|
||||
|
||||
/* Make sure all changes we've missed are announced. */
|
||||
cache_announce_changes (platform, priv->link_cache, old_link_cache);
|
||||
cache_announce_changes (platform, priv->address_cache, old_address_cache);
|
||||
cache_announce_changes (platform, priv->route_cache, old_route_cache);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI))
|
||||
#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
|
||||
#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
|
||||
|
|
@ -4008,7 +4120,8 @@ event_handler (GIOChannel *channel,
|
|||
GIOCondition io_condition,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (user_data);
|
||||
NMPlatform *platform = NM_PLATFORM (user_data);
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
int nle;
|
||||
|
||||
nle = nl_recvmsgs_default (priv->nlh_event);
|
||||
|
|
@ -4020,6 +4133,17 @@ event_handler (GIOChannel *channel,
|
|||
* and can happen easily. */
|
||||
debug ("Uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
|
||||
break;
|
||||
case -NLE_NOMEM:
|
||||
warning ("Too many netlink events. Need to resynchronize platform cache");
|
||||
/* Drain the event queue, we've lost events and are out of sync anyway and we'd
|
||||
* like to free up some space. We'll read in the status synchronously. */
|
||||
nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL);
|
||||
do {
|
||||
nle = nl_recvmsgs_default (priv->nlh_event);
|
||||
} while (nle != -NLE_AGAIN);
|
||||
nl_socket_modify_cb (priv->nlh_event, NL_CB_VALID, NL_CB_CUSTOM, event_notification, user_data);
|
||||
cache_repopulate_all (platform);
|
||||
break;
|
||||
default:
|
||||
error ("Failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle);
|
||||
break;
|
||||
|
|
@ -4051,6 +4175,12 @@ setup_socket (gboolean event, gpointer user_data)
|
|||
nle = nl_socket_set_passcred (sock, 1);
|
||||
g_assert (!nle);
|
||||
|
||||
/* No blocking for event socket, so that we can drain it safely. */
|
||||
if (event) {
|
||||
nle = nl_socket_set_nonblocking (sock);
|
||||
g_assert (!nle);
|
||||
}
|
||||
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
|
@ -4065,7 +4195,6 @@ udev_device_added (NMPlatform *platform,
|
|||
const char *ifname;
|
||||
int ifindex;
|
||||
gboolean was_announceable = FALSE;
|
||||
int nle;
|
||||
|
||||
ifname = g_udev_device_get_name (udev_device);
|
||||
if (!ifname) {
|
||||
|
|
@ -4096,12 +4225,6 @@ udev_device_added (NMPlatform *platform,
|
|||
g_hash_table_insert (priv->udev_devices, GINT_TO_POINTER (ifindex),
|
||||
g_object_ref (udev_device));
|
||||
|
||||
/* Grow the netlink socket buffer beyond 128k if we have more that 32 interfaces. */
|
||||
nle = nl_socket_set_buffer_size (priv->nlh_event,
|
||||
MAX (131072, 4096 * g_hash_table_size (priv->udev_devices)), 0);
|
||||
if (nle)
|
||||
warning ("udev-add: failed to adjust netlink socket buffer size");
|
||||
|
||||
/* Announce devices only if they also have been discovered via Netlink. */
|
||||
if (rtnllink && link_is_announceable (platform, rtnllink))
|
||||
announce_object (platform, (struct nl_object *) rtnllink, was_announceable ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL);
|
||||
|
|
@ -4196,7 +4319,6 @@ setup (NMPlatform *platform)
|
|||
int channel_flags;
|
||||
gboolean status;
|
||||
int nle;
|
||||
struct nl_object *object;
|
||||
|
||||
/* Initialize netlink socket for requests */
|
||||
priv->nlh = setup_socket (FALSE, platform);
|
||||
|
|
@ -4232,14 +4354,7 @@ setup (NMPlatform *platform)
|
|||
(EVENT_CONDITIONS | ERROR_CONDITIONS | DISCONNECT_CONDITIONS),
|
||||
event_handler, platform);
|
||||
|
||||
/* Allocate netlink caches */
|
||||
rtnl_link_alloc_cache (priv->nlh, AF_UNSPEC, &priv->link_cache);
|
||||
rtnl_addr_alloc_cache (priv->nlh, &priv->address_cache);
|
||||
rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
|
||||
g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
|
||||
|
||||
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object))
|
||||
_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
|
||||
cache_repopulate_all (platform);
|
||||
|
||||
#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
|
||||
/* Initial check for user IPv6LL support once the link cache is allocated
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue