core: split route management code out from platform

Create a NMRouteManager singleton.

Refactor, no functional changes apart from change of log domain from
LOGD_PLATFORM to LOGD_CORE.

Subsequent commit will keep track of the conflicting routes, avoid overwriting
older ones with newer ones and apply the new ones when the old ones go away.

(cherry picked from commit 874e4a7595)
This commit is contained in:
Lubomir Rintel 2015-01-02 15:42:11 +01:00
parent f45bd84433
commit af36a41440
11 changed files with 311 additions and 209 deletions

View file

@ -300,6 +300,8 @@ nm_sources = \
nm-dbus-manager.h \
nm-dcb.c \
nm-dcb.h \
nm-route-manager.c \
nm-route-manager.h \
nm-default-route-manager.c \
nm-default-route-manager.h \
nm-dhcp4-config.c \
@ -498,6 +500,9 @@ libnm_iface_helper_la_SOURCES = \
rdisc/nm-rdisc.c \
rdisc/nm-rdisc.h \
\
nm-route-manager.c \
nm-route-manager.h \
\
nm-ip4-config.c \
nm-ip4-config.h \
nm-ip6-config.c \

View file

@ -67,6 +67,7 @@
#include "nm-dns-manager.h"
#include "nm-core-internal.h"
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "nm-device-logging.h"
_LOG_DECLARE_SELF (NMDevice);
@ -7758,7 +7759,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, gboolean deconfig
/* Take out any entries in the routing table and any IP address the device had. */
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex > 0) {
nm_platform_route_flush (NM_PLATFORM_GET, ifindex);
nm_route_manager_route_flush (nm_route_manager_get (), ifindex);
nm_platform_address_flush (NM_PLATFORM_GET, ifindex);
}

View file

@ -32,6 +32,7 @@
#include "nm-device-private.h"
#include "nm-dbus-glib-types.h"
#include "nm-modem-enum-types.h"
#include "nm-route-manager.h"
G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT)
@ -912,7 +913,7 @@ deactivate_cleanup (NMModem *self, NMDevice *device)
priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
ifindex = nm_device_get_ip_ifindex (device);
if (ifindex > 0) {
nm_platform_route_flush (NM_PLATFORM_GET, ifindex);
nm_route_manager_route_flush (nm_route_manager_get (), ifindex);
nm_platform_address_flush (NM_PLATFORM_GET, ifindex);
nm_platform_link_set_down (NM_PLATFORM_GET, ifindex);
}

View file

@ -33,6 +33,7 @@
#include "nm-ip4-config-glue.h"
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
#include "nm-route-manager.h"
G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT)
@ -282,7 +283,7 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_ro
g_array_append_vals (routes, route, 1);
}
success = nm_platform_ip4_route_sync (NM_PLATFORM_GET, ifindex, routes);
success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes);
g_array_unref (routes);
if (!success)
return FALSE;

View file

@ -32,6 +32,7 @@
#include "nm-dbus-manager.h"
#include "nm-dbus-glib-types.h"
#include "nm-ip6-config-glue.h"
#include "nm-route-manager.h"
#include "NetworkManagerUtils.h"
G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT)
@ -396,7 +397,7 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex)
g_array_append_vals (routes, route, 1);
}
success = nm_platform_ip6_route_sync (NM_PLATFORM_GET, ifindex, routes);
success = nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes);
g_array_unref (routes);
}

244
src/nm-route-manager.c Normal file
View file

@ -0,0 +1,244 @@
/* -*- 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 (C) 2015 Red Hat, Inc.
*/
#include "config.h"
#include "nm-route-manager.h"
#include "nm-platform.h"
#include "nm-logging.h"
G_DEFINE_TYPE (NMRouteManager, nm_route_manager, G_TYPE_OBJECT)
static NMRouteManager *_instance;
static gboolean
array_contains_ip4_route (const GArray *routes, const NMPlatformIP4Route *route)
{
guint len = routes ? routes->len : 0;
guint i;
for (i = 0; i < len; i++) {
NMPlatformIP4Route *c = &g_array_index (routes, NMPlatformIP4Route, i);
if (route->network == c->network &&
route->plen == c->plen &&
route->gateway == c->gateway &&
route->metric == c->metric)
return TRUE;
}
return FALSE;
}
static gboolean
array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route)
{
guint len = routes ? routes->len : 0;
guint i;
for (i = 0; i < len; i++) {
NMPlatformIP6Route *c = &g_array_index (routes, NMPlatformIP6Route, i);
if (IN6_ARE_ADDR_EQUAL (&route->network, &c->network) &&
route->plen == c->plen &&
IN6_ARE_ADDR_EQUAL (&route->gateway, &c->gateway) &&
route->metric == c->metric)
return TRUE;
}
return FALSE;
}
/**
* nm_route_manager_ip4_route_sync:
* @ifindex: Interface index
* @known_routes: List of routes
*
* A convenience function to synchronize routes for a specific interface
* with the least possible disturbance. It simply removes routes that are
* not listed and adds routes that are.
* Default routes are ignored (both in @known_routes and those already
* configured on the device).
*
* Returns: %TRUE on success.
*/
gboolean
nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes)
{
GArray *routes;
NMPlatformIP4Route *route;
const NMPlatformIP4Route *known_route;
gboolean success;
int i, i_type;
/* Delete unknown routes */
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP4Route, i);
if (!array_contains_ip4_route (known_routes, route))
(void) nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, route->network, route->plen, route->metric);
}
if (!known_routes) {
g_array_free (routes, TRUE);
return TRUE;
}
/* Add missing routes */
for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) {
for (i = 0; i < known_routes->len && success; i++) {
known_route = &g_array_index (known_routes, NMPlatformIP4Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
continue;
if ((known_route->gateway == 0) ^ (i_type == 0)) {
/* Make two runs over the list of routes. On the first, only add
* device routes, on the second the others (gateway routes). */
continue;
}
/* Ignore routes that already exist */
if (!array_contains_ip4_route (routes, known_route)) {
success = nm_platform_ip4_route_add (NM_PLATFORM_GET,
ifindex,
known_route->source,
known_route->network,
known_route->plen,
known_route->gateway,
0,
known_route->metric,
known_route->mss);
if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) {
nm_log_dbg (LOGD_CORE, "ignore error adding IPv4 route to kernel: %s",
nm_platform_ip4_route_to_string (known_route));
success = TRUE;
}
}
}
}
g_array_free (routes, TRUE);
return success;
}
/**
* nm_route_manager_ip6_route_sync:
* @ifindex: Interface index
* @known_routes: List of routes
*
* A convenience function to synchronize routes for a specific interface
* with the least possible disturbance. It simply removes routes that are
* not listed and adds routes that are.
* Default routes are ignored (both in @known_routes and those already
* configured on the device).
*
* Returns: %TRUE on success.
*/
gboolean
nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes)
{
GArray *routes;
NMPlatformIP6Route *route;
const NMPlatformIP6Route *known_route;
gboolean success;
int i, i_type;
/* Delete unknown routes */
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP6Route, i);
route->ifindex = 0;
if (!array_contains_ip6_route (known_routes, route))
nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, route->network, route->plen, route->metric);
}
if (!known_routes) {
g_array_free (routes, TRUE);
return TRUE;
}
/* Add missing routes */
for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) {
for (i = 0; i < known_routes->len && success; i++) {
known_route = &g_array_index (known_routes, NMPlatformIP6Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
continue;
if (IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway) ^ (i_type == 0)) {
/* Make two runs over the list of routes. On the first, only add
* device routes, on the second the others (gateway routes). */
continue;
}
/* Ignore routes that already exist */
if (!array_contains_ip6_route (routes, known_route)) {
success = nm_platform_ip6_route_add (NM_PLATFORM_GET,
ifindex,
known_route->source,
known_route->network,
known_route->plen,
known_route->gateway,
known_route->metric,
known_route->mss);
if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) {
nm_log_dbg (LOGD_CORE, "ignore error adding IPv6 route to kernel: %s",
nm_platform_ip6_route_to_string (known_route));
success = TRUE;
}
}
}
}
g_array_free (routes, TRUE);
return success;
}
gboolean
nm_route_manager_route_flush (NMRouteManager *self, int ifindex)
{
return nm_route_manager_ip4_route_sync (self, ifindex, NULL)
&& nm_route_manager_ip6_route_sync (self, ifindex, NULL);
}
NMRouteManager *
nm_route_manager_get ()
{
if (G_UNLIKELY (!_instance)) {
_instance = NM_ROUTE_MANAGER (g_object_new (NM_TYPE_ROUTE_MANAGER, NULL));
g_object_add_weak_pointer (G_OBJECT (_instance), (gpointer *) &_instance);
}
return _instance;
}
static void
nm_route_manager_init (NMRouteManager *self)
{
}
static void
nm_route_manager_class_init (NMRouteManagerClass *klass)
{
}

51
src/nm-route-manager.h Normal file
View file

@ -0,0 +1,51 @@
/* -*- 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 (C) 2015 Red Hat, Inc.
*/
#include <glib-object.h>
#include "nm-types.h"
#ifndef __NETWORKMANAGER_ROUTE_MANAGER_H__
#define __NETWORKMANAGER_ROUTE_MANAGER_H__
#define NM_TYPE_ROUTE_MANAGER (nm_route_manager_get_type ())
#define NM_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManager))
#define NM_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass))
#define NM_IS_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ROUTE_MANAGER))
#define NM_IS_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ROUTE_MANAGER))
#define NM_ROUTE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass))
struct _NMRouteManager {
GObject parent;
};
typedef struct {
GObjectClass parent;
} NMRouteManagerClass;
GType nm_route_manager_get_type (void);
gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes);
gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes);
gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex);
NMRouteManager *nm_route_manager_get (void);
#endif /* NM_ROUTE_MANAGER_H */

View file

@ -40,6 +40,7 @@ typedef struct _NMIP6Config NMIP6Config;
typedef struct _NMManager NMManager;
typedef struct _NMPolicy NMPolicy;
typedef struct _NMRfkillManager NMRfkillManager;
typedef struct _NMRouteManager NMRouteManager;
typedef struct _NMSessionMonitor NMSessionMonitor;
typedef struct _NMSleepMonitor NMSleepMonitor;

View file

@ -2340,207 +2340,6 @@ nm_platform_ip6_route_exists (NMPlatform *self, int ifindex, struct in6_addr net
return klass->ip6_route_exists (self, ifindex, network, plen, metric);
}
static gboolean
array_contains_ip4_route (const GArray *routes, const NMPlatformIP4Route *route)
{
guint len = routes ? routes->len : 0;
guint i;
for (i = 0; i < len; i++) {
NMPlatformIP4Route *c = &g_array_index (routes, NMPlatformIP4Route, i);
if (route->network == c->network &&
route->plen == c->plen &&
route->gateway == c->gateway &&
route->metric == c->metric)
return TRUE;
}
return FALSE;
}
static gboolean
array_contains_ip6_route (const GArray *routes, const NMPlatformIP6Route *route)
{
guint len = routes ? routes->len : 0;
guint i;
for (i = 0; i < len; i++) {
NMPlatformIP6Route *c = &g_array_index (routes, NMPlatformIP6Route, i);
if (IN6_ARE_ADDR_EQUAL (&route->network, &c->network) &&
route->plen == c->plen &&
IN6_ARE_ADDR_EQUAL (&route->gateway, &c->gateway) &&
route->metric == c->metric)
return TRUE;
}
return FALSE;
}
/**
* nm_platform_ip4_route_sync:
* @self: platform instance
* @ifindex: Interface index
* @known_routes: List of routes
*
* A convenience function to synchronize routes for a specific interface
* with the least possible disturbance. It simply removes routes that are
* not listed and adds routes that are.
* Default routes are ignored (both in @known_routes and those already
* configured on the device).
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_ip4_route_sync (NMPlatform *self, int ifindex, const GArray *known_routes)
{
GArray *routes;
NMPlatformIP4Route *route;
const NMPlatformIP4Route *known_route;
gboolean success;
int i, i_type;
_CHECK_SELF (self, klass, FALSE);
/* Delete unknown routes */
routes = nm_platform_ip4_route_get_all (self, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP4Route, i);
if (!array_contains_ip4_route (known_routes, route))
(void) nm_platform_ip4_route_delete (self, ifindex, route->network, route->plen, route->metric);
}
if (!known_routes) {
g_array_free (routes, TRUE);
return TRUE;
}
/* Add missing routes */
for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) {
for (i = 0; i < known_routes->len && success; i++) {
known_route = &g_array_index (known_routes, NMPlatformIP4Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
continue;
if ( (i_type == 0 && known_route->gateway != 0)
|| (i_type == 1 && known_route->gateway == 0)) {
/* Make two runs over the list of routes. On the first, only add
* device routes, on the second the others (gateway routes). */
continue;
}
/* Ignore routes that already exist */
if (!array_contains_ip4_route (routes, known_route)) {
success = nm_platform_ip4_route_add (self,
ifindex,
known_route->source,
known_route->network,
known_route->plen,
known_route->gateway,
0,
known_route->metric,
known_route->mss);
if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) {
nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv4 route to kernel: %s",
nm_platform_ip4_route_to_string (known_route));
success = TRUE;
}
}
}
}
g_array_free (routes, TRUE);
return success;
}
/**
* nm_platform_ip6_route_sync:
* @self: platform instance
* @ifindex: Interface index
* @known_routes: List of routes
*
* A convenience function to synchronize routes for a specific interface
* with the least possible disturbance. It simply removes routes that are
* not listed and adds routes that are.
* Default routes are ignored (both in @known_routes and those already
* configured on the device).
*
* Returns: %TRUE on success.
*/
gboolean
nm_platform_ip6_route_sync (NMPlatform *self, int ifindex, const GArray *known_routes)
{
GArray *routes;
NMPlatformIP6Route *route;
const NMPlatformIP6Route *known_route;
gboolean success;
int i, i_type;
_CHECK_SELF (self, klass, FALSE);
/* Delete unknown routes */
routes = nm_platform_ip6_route_get_all (self, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP6Route, i);
route->ifindex = 0;
if (!array_contains_ip6_route (known_routes, route))
nm_platform_ip6_route_delete (self, ifindex, route->network, route->plen, route->metric);
}
if (!known_routes) {
g_array_free (routes, TRUE);
return TRUE;
}
/* Add missing routes */
for (i_type = 0, success = TRUE; i_type < 2 && success; i_type++) {
for (i = 0; i < known_routes->len && success; i++) {
known_route = &g_array_index (known_routes, NMPlatformIP6Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (known_route))
continue;
if ( (i_type == 0 && !IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway))
|| (i_type == 1 && IN6_IS_ADDR_UNSPECIFIED (&known_route->gateway))) {
/* Make two runs over the list of routes. On the first, only add
* device routes, on the second the others (gateway routes). */
continue;
}
/* Ignore routes that already exist */
if (!array_contains_ip6_route (routes, known_route)) {
success = nm_platform_ip6_route_add (self,
ifindex,
known_route->source,
known_route->network,
known_route->plen,
known_route->gateway,
known_route->metric,
known_route->mss);
if (!success && known_route->source < NM_IP_CONFIG_SOURCE_USER) {
nm_log_dbg (LOGD_PLATFORM, "ignore error adding IPv6 route to kernel: %s",
nm_platform_ip6_route_to_string (known_route));
success = TRUE;
}
}
}
}
g_array_free (routes, TRUE);
return success;
}
gboolean
nm_platform_route_flush (NMPlatform *self, int ifindex)
{
return nm_platform_ip4_route_sync (self, ifindex, NULL)
&& nm_platform_ip6_route_sync (self, ifindex, NULL);
}
/******************************************************************/
static const char *

View file

@ -713,9 +713,6 @@ gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t
gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric);
gboolean nm_platform_ip4_route_exists (NMPlatform *self, int ifindex, in_addr_t network, int plen, guint32 metric);
gboolean nm_platform_ip6_route_exists (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric);
gboolean nm_platform_ip4_route_sync (NMPlatform *self, int ifindex, const GArray *known_routes);
gboolean nm_platform_ip6_route_sync (NMPlatform *self, int ifindex, const GArray *known_routes);
gboolean nm_platform_route_flush (NMPlatform *self, int ifindex);
const char *nm_platform_link_to_string (const NMPlatformLink *link);
const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address);

View file

@ -44,6 +44,7 @@
#include "nm-agent-manager.h"
#include "nm-core-internal.h"
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "nm-vpn-connection-glue.h"
@ -233,7 +234,7 @@ vpn_cleanup (NMVpnConnection *connection, NMDevice *parent_dev)
if (priv->ip_ifindex) {
nm_platform_link_set_down (NM_PLATFORM_GET, priv->ip_ifindex);
nm_platform_route_flush (NM_PLATFORM_GET, priv->ip_ifindex);
nm_route_manager_route_flush (nm_route_manager_get (), priv->ip_ifindex);
nm_platform_address_flush (NM_PLATFORM_GET, priv->ip_ifindex);
}