Merge branch 'libnl3'

This commit is contained in:
Dan Williams 2011-08-23 09:30:50 -05:00
commit 0fe8c80fae
22 changed files with 1335 additions and 786 deletions

View file

@ -312,10 +312,43 @@ else
fi
AC_DEFINE_UNQUOTED(NO_CONSOLEKIT, $no_ck, [Define to disable use of ConsoleKit])
PKG_CHECK_MODULES(LIBNL, libnl-1 >= 1.0-pre8)
have_libnl="no"
PKG_CHECK_MODULES(LIBNL1, libnl-1 >= 1.0-pre8, [have_libnl1=yes], [have_libnl1=no])
if (test "${have_libnl1}" = "yes"); then
AC_DEFINE(HAVE_LIBNL1, 1, [Define if you require libnl-1 legacy support])
LIBNL_CFLAGS="$LIBNL1_CFLAGS"
LIBNL_LIBS="$LIBNL1_LIBS"
libnl_version="1"
have_libnl="yes"
fi
PKG_CHECK_MODULES(LIBNL2, libnl-2.0, [have_libnl2=yes], [have_libnl2=no])
if (test "${have_libnl2}" = "yes"); then
AC_DEFINE(HAVE_LIBNL2, 1, [Define if you require specific libnl-2 support])
LIBNL_CFLAGS="$LIBNL2_CFLAGS"
LIBNL_LIBS="$LIBNL2_LIBS"
libnl_version="2"
have_libnl="yes"
fi
PKG_CHECK_MODULES(LIBNL3, libnl-3.0, [have_libnl2=yes], [have_libnl2=no])
if (test "${have_libnl2}" = "yes"); then
AC_DEFINE(HAVE_LIBNL3, 1, [Define if you require specific libnl-3 support])
LIBNL_CFLAGS="$LIBNL3_CFLAGS"
LIBNL_LIBS="$LIBNL3_LIBS"
libnl_version="3"
have_libnl="yes"
fi
if (test "${have_libnl}" = "no"); then
AC_MSG_ERROR([libnl development header are required])
fi
AC_SUBST(LIBNL_CFLAGS)
AC_SUBST(LIBNL_LIBS)
NM_LIBNL_CHECK
if (test "${libnl_version}" = "1"); then
NM_LIBNL_CHECK
fi
PKG_CHECK_MODULES(UUID, uuid)
AC_SUBST(UUID_CFLAGS)
@ -738,6 +771,8 @@ else
echo PPP support: no
fi
echo libnl version: ${libnl_version}
echo
echo Building documentation: ${with_docs}
echo Building tests: ${with_tests}

View file

@ -159,6 +159,10 @@ NetworkManager_SOURCES = \
nm-manager-auth.h \
nm-netlink-monitor.c \
nm-netlink-monitor.h \
nm-netlink-utils.c \
nm-netlink-utils.h \
nm-netlink-compat.h \
nm-netlink-compat.c \
nm-activation-request.c \
nm-activation-request.h \
nm-properties-changed-signal.c \

View file

@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <stdlib.h>
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
@ -43,9 +44,6 @@
#include "nm-setting-wireless-security.h"
#include "nm-manager-auth.h"
#include <netlink/addr.h>
#include <netinet/in.h>
/*
* nm_ethernet_address_is_valid
*

View file

@ -34,7 +34,9 @@
#include "nm-system.h"
#include "NetworkManagerUtils.h"
#include "nm-logging.h"
#include "nm-netlink-compat.h"
#include "nm-netlink-monitor.h"
#include "nm-netlink-utils.h"
/* Because of a bug in libnl, rtnl.h should be included before route.h */
#include <netlink/route/rtnl.h>
@ -50,15 +52,13 @@
*/
void nm_generic_enable_loopback (void)
{
struct nl_handle * nlh = NULL;
struct nl_sock * nlh = NULL;
struct rtnl_addr * addr = NULL;
struct nl_addr * nl_addr = NULL;
guint32 binaddr = 0;
int iface_idx = -1;
int err;
nm_system_device_set_up_down_with_iface ("lo", TRUE, NULL);
nlh = nm_netlink_get_default_handle ();
if (!nlh)
return;
@ -67,6 +67,8 @@ void nm_generic_enable_loopback (void)
if (iface_idx < 0)
return;
nm_system_iface_set_up (iface_idx, TRUE, NULL);
addr = rtnl_addr_alloc ();
if (!addr)
return;
@ -90,10 +92,10 @@ void nm_generic_enable_loopback (void)
rtnl_addr_set_scope (addr, RT_SCOPE_HOST);
rtnl_addr_set_label (addr, "lo");
if ((err = rtnl_addr_add (nlh, addr, 0)) < 0) {
if (err != -EEXIST) {
nm_log_warn (LOGD_CORE, "error %d returned from rtnl_addr_add():\n%s", err, nl_geterror());
}
err = rtnl_addr_add (nlh, addr, 0);
if (err && (err != -NLE_EXIST)) {
nm_log_warn (LOGD_CORE, "error setting loopback address: (%d) %s",
err, nl_geterror (err));
}
out:
if (addr)

View file

@ -27,6 +27,8 @@
#include "nm-ip6-manager.h"
#include "nm-netlink-monitor.h"
#include "nm-netlink-utils.h"
#include "nm-netlink-compat.h"
#include "NetworkManagerUtils.h"
#include "nm-marshal.h"
#include "nm-logging.h"
@ -44,7 +46,7 @@ typedef struct {
NMNetlinkMonitor *monitor;
GHashTable *devices;
struct nl_handle *nlh;
struct nl_sock *nlh;
struct nl_cache *addr_cache, *route_cache;
guint netlink_id;
@ -553,7 +555,7 @@ process_addr (NMIP6Manager *manager, struct nl_msg *msg)
}
old_size = nl_cache_nitems (priv->addr_cache);
nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL);
nl_cache_include (priv->addr_cache, (struct nl_object *)rtnladdr, NULL, NULL);
rtnl_addr_put (rtnladdr);
/* The kernel will re-notify us of automatically-added addresses
@ -593,7 +595,7 @@ process_route (NMIP6Manager *manager, struct nl_msg *msg)
}
old_size = nl_cache_nitems (priv->route_cache);
nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL);
nl_cache_include (priv->route_cache, (struct nl_object *)rtnlroute, NULL, NULL);
rtnl_route_put (rtnlroute);
/* As above in process_addr */
@ -1248,7 +1250,7 @@ nm_ip6_manager_get_ip6_config (NMIP6Manager *manager, int ifindex)
nm_ip6_route_set_dest (ip6route, dest);
nm_ip6_route_set_prefix (ip6route, rtnl_route_get_dst_len (rtnlroute));
nm_ip6_route_set_next_hop (ip6route, gateway);
metric = rtnl_route_get_metric (rtnlroute, 1);
rtnl_route_get_metric(rtnlroute, 1, &metric);
if (metric != UINT_MAX)
nm_ip6_route_set_metric (ip6route, metric);
nm_ip6_config_take_route (config, ip6route);
@ -1344,8 +1346,10 @@ nm_ip6_manager_init (NMIP6Manager *manager)
G_CALLBACK (netlink_notification), manager);
priv->nlh = nm_netlink_get_default_handle ();
priv->addr_cache = rtnl_addr_alloc_cache (priv->nlh);
priv->route_cache = rtnl_route_alloc_cache (priv->nlh);
rtnl_addr_alloc_cache (priv->nlh, &priv->addr_cache);
g_warn_if_fail (priv->addr_cache != NULL);
rtnl_route_alloc_cache (priv->nlh, NETLINK_ROUTE, NL_AUTO_PROVIDE, &priv->route_cache);
g_warn_if_fail (priv->route_cache != NULL);
}
static void

View file

@ -640,7 +640,7 @@ static void
real_deactivate (NMModem *self, NMDevice *device)
{
NMModemPrivate *priv;
const char *iface;
int ifindex;
g_return_if_fail (self != NULL);
g_return_if_fail (NM_IS_MODEM (self));
@ -679,11 +679,11 @@ real_deactivate (NMModem *self, NMDevice *device)
break;
case MM_MODEM_IP_METHOD_STATIC:
case MM_MODEM_IP_METHOD_DHCP:
iface = nm_device_get_ip_iface (device);
ifindex = nm_device_get_ip_ifindex (device);
/* FIXME: use AF_UNSPEC here when we have IPv6 support */
nm_system_device_flush_routes_with_iface (iface, AF_INET);
nm_system_device_flush_addresses_with_iface (iface);
nm_system_device_set_up_down_with_iface (iface, FALSE, NULL);
nm_system_iface_flush_routes (ifindex, AF_INET);
nm_system_iface_flush_addresses (ifindex, AF_UNSPEC);
nm_system_iface_set_up (ifindex, FALSE, NULL);
break;
default:
nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
@ -775,7 +775,7 @@ nm_modem_hw_is_up (NMModem *self, NMDevice *device)
state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
if (priv->pending_ip4_config || _state_is_active (state))
return nm_system_device_is_up (device);
return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
}
return TRUE;
@ -792,7 +792,7 @@ nm_modem_hw_bring_up (NMModem *self, NMDevice *device, gboolean *no_firmware)
state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (device));
if (priv->pending_ip4_config || _state_is_active (state))
return nm_system_device_set_up_down (device, TRUE, no_firmware);
return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
}
return TRUE;

View file

@ -59,6 +59,7 @@
#include "nm-logging.h"
#include "nm-properties-changed-signal.h"
#include "nm-dhcp-manager.h"
#include "nm-netlink-utils.h"
#include "nm-device-ethernet-glue.h"
@ -546,19 +547,19 @@ real_take_down (NMDevice *dev)
static gboolean
real_hw_is_up (NMDevice *device)
{
return nm_system_device_is_up (device);
return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
}
static gboolean
real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
{
return nm_system_device_set_up_down (dev, TRUE, no_firmware);
return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
}
static void
real_hw_take_down (NMDevice *dev)
{
nm_system_device_set_up_down (dev, FALSE, NULL);
nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
}
NMDevice *
@ -677,7 +678,7 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail)
/* Can't change MAC address while device is up */
real_hw_take_down (dev);
success = nm_system_device_set_mac (iface, (struct ether_addr *) addr);
success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
if (success) {
/* MAC address succesfully changed; update the current MAC to match */
_update_hw_addr (self, addr);
@ -1796,73 +1797,19 @@ wired_match_config (NMDevice *self, NMConnection *connection)
return TRUE;
}
typedef struct {
int ifindex;
NMIP4Address *addr;
gboolean found;
} AddrData;
static void
check_one_address (struct nl_object *object, void *user_data)
{
AddrData *data = user_data;
struct rtnl_addr *addr = (struct rtnl_addr *) object;
struct nl_addr *local;
struct in_addr tmp;
if (rtnl_addr_get_ifindex (addr) != data->ifindex)
return;
if (rtnl_addr_get_family (addr) != AF_INET)
return;
if (nm_ip4_address_get_prefix (data->addr) != rtnl_addr_get_prefixlen (addr))
return;
local = rtnl_addr_get_local (addr);
if (nl_addr_get_family (local) != AF_INET)
return;
if (nl_addr_get_len (local) != sizeof (struct in_addr))
return;
if (!nl_addr_get_binary_addr (local))
return;
memcpy (&tmp, nl_addr_get_binary_addr (local), nl_addr_get_len (local));
if (tmp.s_addr != nm_ip4_address_get_address (data->addr))
return;
/* Yay, found it */
data->found = TRUE;
}
static gboolean
ip4_match_config (NMDevice *self, NMConnection *connection)
{
NMSettingIP4Config *s_ip4;
struct nl_handle *nlh = NULL;
struct nl_cache *addr_cache = NULL;
int i, num;
GSList *leases, *iter;
NMDHCPManager *dhcp_mgr;
const char *method;
int ifindex;
AddrData check_data;
ifindex = nm_device_get_ifindex (self);
s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG);
s_ip4 = nm_connection_get_setting_ip4_config (connection);
if (!s_ip4)
return FALSE;
/* Read all the device's IP addresses */
nlh = nm_netlink_get_default_handle ();
if (!nlh)
return FALSE;
addr_cache = rtnl_addr_alloc_cache (nlh);
if (!addr_cache)
return FALSE;
nl_cache_mngt_provide (addr_cache);
/* Get any saved leases that apply to this connection */
dhcp_mgr = nm_dhcp_manager_get ();
leases = nm_dhcp_manager_get_lease_config (dhcp_mgr,
@ -1876,15 +1823,14 @@ ip4_match_config (NMDevice *self, NMConnection *connection)
/* Find at least one lease's address on the device */
for (iter = leases; iter; iter = g_slist_next (iter)) {
NMIP4Config *addr = iter->data;
NMIP4Config *ip4_config = iter->data;
NMIP4Address *addr = nm_ip4_config_get_address (ip4_config, 0);
struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) };
memset (&check_data, 0, sizeof (check_data));
check_data.ifindex = ifindex;
check_data.found = FALSE;
check_data.addr = nm_ip4_config_get_address (addr, 0);
nl_cache_foreach (addr_cache, check_one_address, &check_data);
if (check_data.found) {
if (addr && nm_netlink_find_address (nm_device_get_ip_ifindex (self),
AF_INET,
&tmp,
nm_ip4_address_get_prefix (addr))) {
found = TRUE; /* Yay, device has same address as a lease */
break;
}
@ -1908,16 +1854,16 @@ ip4_match_config (NMDevice *self, NMConnection *connection)
/* Everything below for static addressing */
/* Find all IP4 addresses of this connection in the device's address list */
/* Find all IP4 addresses of this connection on the device */
num = nm_setting_ip4_config_get_num_addresses (s_ip4);
for (i = 0; i < num; i++) {
memset (&check_data, 0, sizeof (check_data));
check_data.ifindex = ifindex;
check_data.found = FALSE;
check_data.addr = nm_setting_ip4_config_get_address (s_ip4, i);
NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i);
struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) };
nl_cache_foreach (addr_cache, check_one_address, &check_data);
if (!check_data.found)
if (!nm_netlink_find_address (nm_device_get_ip_ifindex (self),
AF_INET,
&tmp,
nm_ip4_address_get_prefix (addr)))
return FALSE;
}

View file

@ -271,19 +271,19 @@ error:
static gboolean
real_hw_is_up (NMDevice *device)
{
return nm_system_device_is_up (device);
return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
}
static gboolean
real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
{
return nm_system_device_set_up_down (dev, TRUE, no_firmware);
return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
}
static void
real_hw_take_down (NMDevice *dev)
{
nm_system_device_set_up_down (dev, FALSE, NULL);
nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
}
static gboolean

View file

@ -1133,7 +1133,7 @@ out:
static gboolean
real_hw_is_up (NMDevice *device)
{
return nm_system_device_is_up (device);
return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
}
static gboolean
@ -1142,13 +1142,13 @@ real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
if (!NM_DEVICE_WIFI_GET_PRIVATE (device)->enabled)
return FALSE;
return nm_system_device_set_up_down (device, TRUE, no_firmware);
return nm_system_iface_set_up (nm_device_get_ip_ifindex (device), TRUE, no_firmware);
}
static void
real_hw_take_down (NMDevice *dev)
real_hw_take_down (NMDevice *device)
{
nm_system_device_set_up_down (dev, FALSE, NULL);
nm_system_iface_set_up (nm_device_get_ip_ifindex (device), FALSE, NULL);
}
static gboolean
@ -1209,7 +1209,7 @@ _set_hw_addr (NMDeviceWifi *self, const guint8 *addr, const char *detail)
/* Can't change MAC address while device is up */
real_hw_take_down (dev);
success = nm_system_device_set_mac (iface, (struct ether_addr *) addr);
success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr);
if (success) {
/* MAC address succesfully changed; update the current MAC to match */
_update_hw_addr (self, addr);

View file

@ -47,6 +47,8 @@
#include "nm-utils.h"
#include "nm-logging.h"
#include "nm-netlink-monitor.h"
#include "nm-netlink-utils.h"
#include "nm-netlink-compat.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-connection.h"
@ -1591,16 +1593,15 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason)
NMSettingIP4Config *s_ip4;
NMActRequest *req;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
const char *ip_iface, *method = NULL;
const char *method = NULL;
int ifindex;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
/* Use the IP interface (not the control interface) for IP stuff */
ip_iface = nm_device_get_ip_iface (self);
/* Make sure the interface is up before trying to do anything with it */
if (!nm_system_device_is_up_with_iface (ip_iface))
nm_system_device_set_up_down_with_iface (ip_iface, TRUE, NULL);
ifindex = nm_device_get_ip_ifindex (self);
if (!nm_system_iface_is_up (ifindex))
nm_system_iface_set_up (ifindex, TRUE, NULL);
req = nm_device_get_act_request (self);
connection = nm_act_request_get_connection (req);
@ -1680,10 +1681,10 @@ dhcp6_start (NMDevice *self,
*/
err = nm_system_set_ip6_route (priv->ip_iface ? priv->ip_ifindex : priv->ifindex,
&dest, 8, NULL, 256, 0, RTPROT_BOOT, RT_TABLE_LOCAL, NULL);
if (err && (nl_get_errno () != EEXIST)) {
if (err && (err != -NLE_EXIST)) {
nm_log_err (LOGD_DEVICE | LOGD_IP6,
"(%s): failed to add IPv6 multicast route: %s",
priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror ());
priv->ip_iface ? priv->ip_iface : priv->iface, nl_geterror (err));
}
s_ip6 = (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG);
@ -2820,6 +2821,7 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE;
gboolean tried_ipv6 = FALSE;
int ifindex, family;
g_return_if_fail (self != NULL);
@ -2857,8 +2859,10 @@ nm_device_deactivate (NMDeviceInterface *device, NMDeviceStateReason reason)
clear_act_request (self);
/* Take out any entries in the routing table and any IP address the device had. */
nm_system_device_flush_routes (self, tried_ipv6 ? AF_UNSPEC : AF_INET);
nm_system_device_flush_addresses (self, tried_ipv6 ? AF_UNSPEC : AF_INET);
ifindex = nm_device_get_ip_ifindex (self);
family = tried_ipv6 ? AF_UNSPEC : AF_INET;
nm_system_iface_flush_routes (ifindex, family);
nm_system_iface_flush_addresses (ifindex, family);
nm_device_update_ip4_address (self);
/* Clean up nameservers and addresses */
@ -3009,6 +3013,7 @@ nm_device_set_ip4_config (NMDevice *self,
gboolean success = TRUE;
NMIP4ConfigCompareFlags diff = NM_IP4_COMPARE_FLAG_ALL;
NMDnsManager *dns_mgr;
int ip_ifindex;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (reason != NULL, FALSE);
@ -3039,8 +3044,10 @@ nm_device_set_ip4_config (NMDevice *self,
/* Don't touch the device's actual IP config if the connection is
* assumed when NM starts.
*/
if (!assumed)
success = nm_system_apply_ip4_config (ip_iface, new_config, nm_device_get_priority (self), diff);
if (!assumed) {
ip_ifindex = nm_device_get_ip_ifindex (self);
success = nm_system_apply_ip4_config (ip_ifindex, new_config, nm_device_get_priority (self), diff);
}
if (success || assumed) {
/* Export over D-Bus */
@ -3112,12 +3119,14 @@ nm_device_set_ip6_config (NMDevice *self,
gboolean success = TRUE;
NMIP6ConfigCompareFlags diff = NM_IP6_COMPARE_FLAG_ALL;
NMDnsManager *dns_mgr;
int ip_ifindex;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (reason != NULL, FALSE);
priv = NM_DEVICE_GET_PRIVATE (self);
ip_iface = nm_device_get_ip_iface (self);
ip_ifindex = nm_device_get_ip_ifindex (self);
old_config = priv->ip6_config;
@ -3143,7 +3152,7 @@ nm_device_set_ip6_config (NMDevice *self,
* assumed when NM starts.
*/
if (!assumed)
success = nm_system_apply_ip6_config (ip_iface, new_config, nm_device_get_priority (self), diff);
success = nm_system_apply_ip6_config (ip_ifindex, new_config, nm_device_get_priority (self), diff);
if (success || assumed) {
/* Export over D-Bus */

105
src/nm-netlink-compat.c Normal file
View file

@ -0,0 +1,105 @@
/* -*- 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) 2011 Caixa Magica Software.
*/
#include <config.h>
#include <glib.h>
#include "nm-netlink-compat.h"
#ifndef HAVE_LIBNL1
struct rtnl_nexthop *
nm_netlink_get_nh (struct rtnl_route * route)
{
int hops;
hops = rtnl_route_get_nnexthops (route);
g_return_val_if_fail(hops > 0, NULL);
return rtnl_route_nexthop_n (route, 0);
}
int
rtnl_route_get_oif (struct rtnl_route * route)
{
struct rtnl_nexthop * nh;
nh = nm_netlink_get_nh(route);
g_return_val_if_fail(nh, -NLE_OBJ_NOTFOUND);
return rtnl_route_nh_get_ifindex (nh);
}
int
rtnl_route_set_oif (struct rtnl_route * route, int ifindex)
{
struct rtnl_nexthop * nh;
nh = rtnl_route_nh_alloc();
rtnl_route_nh_set_ifindex(nh, ifindex);
rtnl_route_add_nexthop(route, nh);
return 0;
}
struct nl_addr *
rtnl_route_get_gateway (struct rtnl_route * route)
{
struct rtnl_nexthop * nh;
nh = nm_netlink_get_nh(route);
g_return_val_if_fail(nh, NULL);
return rtnl_route_nh_get_gateway(nh);
}
int
rtnl_route_set_gateway (struct rtnl_route * route, struct nl_addr * gw_addr)
{
struct rtnl_nexthop * nh;
nh = nm_netlink_get_nh(route);
g_return_val_if_fail(nh, -NLE_OBJ_NOTFOUND);
rtnl_route_nh_set_gateway(nh, gw_addr);
return 0;
}
int
rtnl_route_get_dst_len(struct rtnl_route * rtnlroute)
{
struct nl_addr * dst;
dst = rtnl_route_get_dst(rtnlroute);
return nl_addr_get_prefixlen(dst);
}
#endif
#ifdef HAVE_LIBNL1
int
nl_compat_error (int err)
{
err = abs (err);
if (err == EEXIST)
err = NLE_EXIST;
else if (err == ENOENT || err == ESRCH)
err = NLE_OBJ_NOTFOUND;
else if (err == ERANGE)
err = NLE_RANGE;
return -err;
}
#endif

197
src/nm-netlink-compat.h Normal file
View file

@ -0,0 +1,197 @@
/* -*- 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) 2011 Caixa Magica Software.
*/
#ifndef NM_NETLINK_COMPAT_H
#define NM_NETLINK_COMPAT_H
#include <errno.h>
#include <netlink/netlink.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink/route/route.h>
#include <netlink/route/addr.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
#include <netlink/data.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
#include <netlink/route/link.h>
#include <netlink/route/nexthop.h>
#include <config.h>
/* libnl-1 API compatibility for libnl-2/3*/
#ifndef HAVE_LIBNL1
struct rtnl_nexthop * nm_netlink_get_nh(struct rtnl_route *);
int rtnl_route_get_oif(struct rtnl_route *);
int rtnl_route_set_oif(struct rtnl_route *, int);
int rtnl_route_set_gateway(struct rtnl_route *, struct nl_addr *);
int rtnl_route_get_dst_len(struct rtnl_route *);
struct nl_addr * rtnl_route_get_gateway(struct rtnl_route *);
#endif
/* libnl-2 API compatibility for libnl-3 */
#ifdef HAVE_LIBNL3
static inline int
__rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
{
return rtnl_link_alloc_cache (h, AF_UNSPEC, cache);
}
#define rtnl_link_alloc_cache __rtnl_link_alloc_cache
#endif
/* libnl-1.0 compat functions */
#ifdef HAVE_LIBNL1
#define nl_sock nl_handle
/* libnl-1.0 functions with similar prototypes */
#define nl_socket_alloc nl_handle_alloc
#define nl_socket_alloc_cb nl_handle_alloc_cb
#define nl_socket_free nl_handle_destroy
#define nl_socket_set_passcred nl_set_passcred
#define nl_socket_disable_seq_check nl_disable_sequence_check
#define rtnl_route_set_priority rtnl_route_set_prio
/* auxiliary functions */
int nl_compat_error (int);
/* libnl-1.0 functions with modified prototypes in libnl-2/3*/
static inline const char *
__nl_geterror (int err)
{
/* err is set, can be parsed */
return nl_geterror ();
}
#define nl_geterror __nl_geterror
static inline int
__rtnl_addr_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
{
g_return_val_if_fail (cache != NULL, -EINVAL);
*cache = rtnl_addr_alloc_cache (h);
return *cache ? 0 : -ENOMEM;
}
#define rtnl_addr_alloc_cache __rtnl_addr_alloc_cache
static inline int
__rtnl_route_alloc_cache (struct nl_sock *h, int family, int flags, struct nl_cache **cache)
{
g_return_val_if_fail (cache != NULL, -EINVAL);
*cache = rtnl_route_alloc_cache (h);
return *cache ? 0 : -ENOMEM;
}
#define rtnl_route_alloc_cache __rtnl_route_alloc_cache
static inline int
__rtnl_link_alloc_cache (struct nl_sock *h, struct nl_cache **cache)
{
g_return_val_if_fail (cache != NULL, -EINVAL);
*cache = rtnl_link_alloc_cache (h);
return *cache ? 0 : -ENOMEM;
}
#define rtnl_link_alloc_cache __rtnl_link_alloc_cache
static inline int
__rtnl_route_get_metric (struct rtnl_route *route, int metric, unsigned int *value)
{
g_return_val_if_fail (value != NULL, -EINVAL);
*value = rtnl_route_get_metric (route, metric);
return 0;
}
#define rtnl_route_get_metric __rtnl_route_get_metric
static inline int
__rtnl_addr_add (struct nl_sock *h, struct rtnl_addr *addr, int flags)
{
return nl_compat_error (rtnl_addr_add (h, addr, flags));
}
#define rtnl_addr_add __rtnl_addr_add
static inline int
__rtnl_route_add (struct nl_sock *sk, struct rtnl_route *route, int flags)
{
return nl_compat_error (rtnl_route_add (sk, route, flags));
}
#define rtnl_route_add __rtnl_route_add
static inline int
rtnl_route_delete (struct nl_sock *h, struct rtnl_route *route, int flags)
{
return nl_compat_error (rtnl_route_del (h, route, flags));
}
#define rtnl_route_del rtnl_route_delete
static inline int
__rtnl_link_change (struct nl_sock *h, struct rtnl_link *old, struct rtnl_link *tmpl, int flags)
{
return nl_compat_error (rtnl_link_change (h, old, tmpl,flags));
}
#define rtnl_link_change __rtnl_link_change
static inline int
__nl_cache_include (struct nl_cache *cache, struct nl_object *obj, change_func_t cb, void *data)
{
return nl_cache_include (cache, obj, cb);
}
#define nl_cache_include __nl_cache_include
#define NLE_SUCCESS 0
#define NLE_FAILURE 1
#define NLE_INTR 2
#define NLE_BAD_SOCK 3
#define NLE_AGAIN 4
#define NLE_NOMEM 5
#define NLE_EXIST 6
#define NLE_INVAL 7
#define NLE_RANGE 8
#define NLE_MSGSIZE 9
#define NLE_OPNOTSUPP 10
#define NLE_AF_NOSUPPORT 11
#define NLE_OBJ_NOTFOUND 12
#define NLE_NOATTR 13
#define NLE_MISSING_ATTR 14
#define NLE_AF_MISMATCH 15
#define NLE_SEQ_MISMATCH 16
#define NLE_MSG_OVERFLOW 17
#define NLE_MSG_TRUNC 18
#define NLE_NOADDR 19
#define NLE_SRCRT_NOSUPPORT 20
#define NLE_MSG_TOOSHORT 21
#define NLE_MSGTYPE_NOSUPPORT 22
#define NLE_OBJ_MISMATCH 23
#define NLE_NOCACHE 24
#define NLE_BUSY 25
#define NLE_PROTO_MISMATCH 26
#define NLE_NOACCESS 27
#define NLE_PERM 28
#define NLE_PKTLOC_FILE 29
#endif
#endif /* NM_NETLINK_COMPAT_H */

View file

@ -45,6 +45,7 @@
#include <glib.h>
#include <glib/gi18n.h>
#include "nm-netlink-compat.h"
#include "nm-netlink-monitor.h"
#include "nm-logging.h"
@ -58,12 +59,12 @@
typedef struct {
/* Async event listener connection */
struct nl_handle *nlh_event;
struct nl_sock *nlh_event;
GIOChannel * io_channel;
guint event_id;
/* Sync/blocking request/response connection */
struct nl_handle *nlh_sync;
struct nl_sock *nlh_sync;
struct nl_cache * link_cache;
guint request_status_id;
@ -98,7 +99,7 @@ link_msg_handler (struct nl_object *obj, void *arg)
error = g_error_new (NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
_("error processing netlink message: %s"),
nl_geterror ());
nl_geterror (ENOMEM));
g_signal_emit (self, signals[ERROR], 0, error);
g_error_free (error);
return;
@ -130,7 +131,7 @@ link_msg_handler (struct nl_object *obj, void *arg)
static int
event_msg_recv (struct nl_msg *msg, void *arg)
{
struct nl_handle *nlh = arg;
struct nl_sock *nlh = arg;
struct nlmsghdr *hdr = nlmsg_hdr (msg);
struct ucred *creds = nlmsg_get_creds (msg);
const struct sockaddr_nl *snl;
@ -195,6 +196,7 @@ event_handler (GIOChannel *channel,
NMNetlinkMonitor *self = (NMNetlinkMonitor *) user_data;
NMNetlinkMonitorPrivate *priv;
GError *error = NULL;
int err;
g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), TRUE);
@ -225,11 +227,12 @@ event_handler (GIOChannel *channel,
g_return_val_if_fail (!(io_condition & ~EVENT_CONDITIONS), FALSE);
/* Process the netlink messages */
if (nl_recvmsgs_default (priv->nlh_event) < 0) {
err = nl_recvmsgs_default (priv->nlh_event);
if (err < 0) {
error = g_error_new (NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_PROCESSING_MESSAGE,
_("error processing netlink message: %s"),
nl_geterror ());
nl_geterror (err));
g_signal_emit (self, signals[ERROR], 0, error);
g_error_free (error);
}
@ -238,32 +241,35 @@ event_handler (GIOChannel *channel,
}
static gboolean
nlh_setup (struct nl_handle *nlh,
nlh_setup (struct nl_sock *nlh,
nl_recvmsg_msg_cb_t valid_func,
gpointer cb_data,
GError **error)
{
int err;
nl_socket_modify_cb (nlh, NL_CB_MSG_IN, NL_CB_CUSTOM, event_msg_recv, cb_data);
if (valid_func)
nl_socket_modify_cb (nlh, NL_CB_VALID, NL_CB_CUSTOM, valid_func, cb_data);
if (nl_connect (nlh, NETLINK_ROUTE) < 0) {
err = nl_connect (nlh, NETLINK_ROUTE);
if (err < 0) {
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
_("unable to connect to netlink for monitoring link status: %s"),
nl_geterror ());
nl_geterror (err));
return FALSE;
}
/* Enable unix socket peer credentials which we use for verifying that the
* sender of the message is actually the kernel.
*/
if (nl_set_passcred (nlh, 1) < 0) {
if (nl_socket_set_passcred (nlh, 1) < 0) {
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
_("unable to enable netlink handle credential passing: %s"),
nl_geterror ());
nl_geterror (err));
return FALSE;
}
@ -283,20 +289,20 @@ event_connection_setup (NMNetlinkMonitor *self, GError **error)
/* Set up the event listener connection */
cb = nl_cb_alloc (NL_CB_DEFAULT);
priv->nlh_event = nl_handle_alloc_cb (cb);
priv->nlh_event = nl_socket_alloc_cb (cb);
nl_cb_put (cb);
if (!priv->nlh_event) {
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
_("unable to allocate netlink handle for monitoring link status: %s"),
nl_geterror ());
nl_geterror (ENOMEM));
goto error;
}
if (!nlh_setup (priv->nlh_event, event_msg_ready, self, error))
goto error;
nl_disable_sequence_check (priv->nlh_event);
nl_socket_disable_seq_check (priv->nlh_event);
/* Subscribe to the LINK group for internal carrier signals */
if (!nm_netlink_monitor_subscribe (self, RTNLGRP_LINK, error))
@ -327,7 +333,7 @@ error:
nm_netlink_monitor_close_connection (self);
if (priv->nlh_event) {
nl_handle_destroy (priv->nlh_event);
nl_socket_free (priv->nlh_event);
priv->nlh_event = NULL;
}
@ -342,16 +348,17 @@ sync_connection_setup (NMNetlinkMonitor *self, GError **error)
#ifdef LIBNL_NEEDS_ADDR_CACHING_WORKAROUND
struct nl_cache *addr_cache;
#endif
int err;
/* Set up the event listener connection */
cb = nl_cb_alloc (NL_CB_DEFAULT);
priv->nlh_sync = nl_handle_alloc_cb (cb);
priv->nlh_sync = nl_socket_alloc_cb (cb);
nl_cb_put (cb);
if (!priv->nlh_sync) {
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_HANDLE,
_("unable to allocate netlink handle for monitoring link status: %s"),
nl_geterror ());
nl_geterror (ENOMEM));
goto error;
}
@ -365,16 +372,18 @@ sync_connection_setup (NMNetlinkMonitor *self, GError **error)
* result, most addresses will not compare as equal even to
* themselves, busting caching.
*/
addr_cache = rtnl_addr_alloc_cache (priv->nlh_sync);
rtnl_addr_alloc_cache (priv->nlh_sync, &addr_cache);
g_warn_if_fail (addr_cache != NULL);
nl_cache_get_ops (addr_cache)->co_obj_ops->oo_id_attrs &= ~0x80;
nl_cache_free (addr_cache);
#endif
if ((priv->link_cache = rtnl_link_alloc_cache (priv->nlh_sync)) == NULL) {
err = rtnl_link_alloc_cache (priv->nlh_sync, &priv->link_cache);
if (err < 0) {
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_NETLINK_ALLOC_LINK_CACHE,
_("unable to allocate netlink link cache for monitoring link status: %s"),
nl_geterror ());
nl_geterror (err));
goto error;
}
nl_cache_mngt_provide (priv->link_cache);
@ -388,7 +397,7 @@ error:
}
if (priv->nlh_sync) {
nl_handle_destroy (priv->nlh_sync);
nl_socket_free (priv->nlh_sync);
priv->nlh_sync = NULL;
}
@ -483,7 +492,7 @@ gboolean
nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error)
{
NMNetlinkMonitorPrivate *priv;
int subs;
int subs, err;
g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
@ -496,11 +505,12 @@ nm_netlink_monitor_subscribe (NMNetlinkMonitor *self, int group, GError **error)
subs = get_subs (self, group) + 1;
if (subs == 1) {
if (nl_socket_add_membership (priv->nlh_event, group) < 0) {
err = nl_socket_add_membership (priv->nlh_event, group);
if (err < 0) {
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP,
_("unable to join netlink group: %s"),
nl_geterror ());
nl_geterror (err));
return FALSE;
}
}
@ -558,15 +568,17 @@ deferred_emit_carrier_state (gpointer user_data)
{
NMNetlinkMonitor *self = NM_NETLINK_MONITOR (user_data);
NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
int err;
priv->request_status_id = 0;
/* Update the link cache with latest state, and if there are no errors
* emit the link states for all the interfaces in the cache.
*/
if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) {
nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror ());
} else
err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
if (err < 0)
nm_log_err (LOGD_HW, "error updating link cache: %s", nl_geterror (err));
else
nl_cache_foreach_filter (priv->link_cache, NULL, link_msg_handler, self);
return FALSE;
@ -614,6 +626,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
NMNetlinkMonitorPrivate *priv;
GetFlagsInfo info;
struct rtnl_link *filter;
int err;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (NM_IS_NETLINK_MONITOR (self), FALSE);
@ -622,12 +635,13 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
/* Update the link cache with the latest information */
if (nl_cache_refill (priv->nlh_sync, priv->link_cache)) {
err = nl_cache_refill (priv->nlh_sync, priv->link_cache);
if (err < 0) {
g_set_error (error,
NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
_("error updating link cache: %s"),
nl_geterror ());
nl_geterror (err));
return FALSE;
}
@ -640,7 +654,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_LINK_CACHE_UPDATE,
_("error updating link cache: %s"),
nl_geterror ());
nl_geterror (err));
return FALSE;
}
@ -651,7 +665,7 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
NM_NETLINK_MONITOR_ERROR,
NM_NETLINK_MONITOR_ERROR_BAD_ALLOC,
_("error processing netlink message: %s"),
nl_geterror ());
nl_geterror (err));
return FALSE;
}
rtnl_link_set_ifindex (filter, ifindex);
@ -678,11 +692,11 @@ nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *self,
/***************************************************************/
struct nl_handle *
struct nl_sock *
nm_netlink_get_default_handle (void)
{
NMNetlinkMonitor *self;
struct nl_handle *nlh;
struct nl_sock *nlh;
self = nm_netlink_monitor_get ();
nlh = NM_NETLINK_MONITOR_GET_PRIVATE (self)->nlh_sync;
@ -796,12 +810,12 @@ finalize (GObject *object)
}
if (priv->nlh_event) {
nl_handle_destroy (priv->nlh_event);
nl_socket_free (priv->nlh_event);
priv->nlh_event = NULL;
}
if (priv->nlh_sync) {
nl_handle_destroy (priv->nlh_sync);
nl_socket_free (priv->nlh_sync);
priv->nlh_sync = NULL;
}

View file

@ -90,10 +90,12 @@ gboolean nm_netlink_monitor_get_flags_sync (NMNetlinkMonitor *monitor
guint32 *ifflags,
GError **error);
#include "nm-netlink-compat.h"
/* Generic utility functions */
int nm_netlink_iface_to_index (const char *iface);
char * nm_netlink_index_to_iface (int idx);
struct rtnl_link *nm_netlink_index_to_rtnl_link (int idx);
struct nl_handle *nm_netlink_get_default_handle (void);
struct nl_sock * nm_netlink_get_default_handle (void);
#endif /* NM_NETLINK_MONITOR_H */

423
src/nm-netlink-utils.c Normal file
View file

@ -0,0 +1,423 @@
/* -*- 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) 2011 Red Hat, Inc.
*/
#include "logging/nm-logging.h"
#include "nm-netlink-utils.h"
#include "nm-netlink-monitor.h"
#include "nm-netlink-compat.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netlink/netlink.h>
#include <netlink/addr.h>
#include <netlink/route/addr.h>
#include <errno.h>
typedef struct {
int ifindex;
int family;
void *addr;
int addrlen;
int prefix;
gboolean found;
} FindAddrInfo;
static void
find_one_address (struct nl_object *object, void *user_data)
{
FindAddrInfo *info = user_data;
struct rtnl_addr *addr = (struct rtnl_addr *) object;
struct nl_addr *local;
void *binaddr;
if (info->found)
return;
if (rtnl_addr_get_ifindex (addr) != info->ifindex)
return;
if (rtnl_addr_get_family (addr) != info->family)
return;
if (rtnl_addr_get_prefixlen (addr) != info->prefix)
return;
local = rtnl_addr_get_local (addr);
if (nl_addr_get_family (local) != info->family)
return;
if (nl_addr_get_len (local) != info->addrlen)
return;
binaddr = nl_addr_get_binary_addr (local);
if (binaddr) {
if (memcmp (binaddr, info->addr, info->addrlen) == 0)
info->found = TRUE; /* Yay, found it */
}
}
/**
* nm_netlink_find_address:
* @ifindex: interface index
* @family: address family, either AF_INET or AF_INET6
* @addr: binary address, either struct in_addr* or struct in6_addr*
* @prefix: prefix length
*
* Searches for a matching address on the given interface.
*
* Returns: %TRUE if the given address was found on the interface, %FALSE if it
* was not found or an error occurred.
**/
gboolean
nm_netlink_find_address (int ifindex,
int family,
void *addr, /* struct in_addr or struct in6_addr */
int prefix)
{
struct nl_sock *nlh = NULL;
struct nl_cache *cache = NULL;
FindAddrInfo info;
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE);
g_return_val_if_fail (addr != NULL, FALSE);
g_return_val_if_fail (prefix >= 0, FALSE);
memset (&info, 0, sizeof (info));
info.ifindex = ifindex;
info.family = family;
info.prefix = prefix;
info.addr = addr;
if (family == AF_INET)
info.addrlen = sizeof (struct in_addr);
else if (family == AF_INET6)
info.addrlen = sizeof (struct in6_addr);
else
g_assert_not_reached ();
nlh = nm_netlink_get_default_handle ();
if (nlh) {
rtnl_addr_alloc_cache(nlh, &cache);
if (cache) {
nl_cache_mngt_provide (cache);
nl_cache_foreach (cache, find_one_address, &info);
nl_cache_free (cache);
}
}
return info.found;
}
struct rtnl_route *
nm_netlink_route_new (int ifindex,
int family,
int mss,
...)
{
va_list var_args;
struct rtnl_route *route;
NmNlProp prop = NMNL_PROP_INVALID;
int value;
route = rtnl_route_alloc ();
g_return_val_if_fail (route != NULL, NULL);
if (ifindex >= 0)
rtnl_route_set_oif (route, ifindex);
if (family != AF_UNSPEC)
rtnl_route_set_family (route, family);
if (mss > 0)
rtnl_route_set_metric (route, RTAX_ADVMSS, mss);
va_start (var_args, mss);
prop = va_arg (var_args, NmNlProp);
while (prop != NMNL_PROP_INVALID) {
value = va_arg (var_args, int);
if (prop == NMNL_PROP_PROT && value != RTPROT_UNSPEC)
rtnl_route_set_protocol (route, value);
else if (prop == NMNL_PROP_TABLE && value != RT_TABLE_UNSPEC)
rtnl_route_set_table (route, value);
else if (prop == NMNL_PROP_SCOPE && value != RT_SCOPE_NOWHERE)
rtnl_route_set_scope (route, value);
else if (prop == NMNL_PROP_PRIO && value > 0)
rtnl_route_set_priority (route, value);
prop = va_arg (var_args, NmNlProp);
}
va_end (var_args);
return route;
}
/**
* nm_netlink_route_add:
* @route: the route to add
*
* Returns: zero if succeeded or the netlink error otherwise.
**/
int nm_netlink_route_add(struct rtnl_route * route,
int family,
const void * dest, /* in_addr or in6_addr */
int dest_prefix,
const void * gateway, /* in_addr or in6_addr */
int flags)
{
struct nl_sock * sk;
struct nl_addr * dest_addr, * gw_addr;
void * tmp_addr;
int addrlen, err, log;
if(family == AF_INET) {
addrlen = sizeof(struct in_addr);
log = LOGD_IP4;
}
else if (family == AF_INET6) {
addrlen = sizeof(struct in6_addr);
log = LOGD_IP6;
} else {
g_assert_not_reached ();
}
sk = nm_netlink_get_default_handle();
/* Build up the destination address */
if (dest) {
/* Copy to preserve const */
tmp_addr = g_malloc0(addrlen);
memcpy(tmp_addr, dest, addrlen);
dest_addr = nl_addr_build (family, tmp_addr, addrlen);
g_free(tmp_addr);
g_return_val_if_fail (dest_addr != NULL, -NLE_INVAL);
nl_addr_set_prefixlen (dest_addr, dest_prefix);
rtnl_route_set_dst (route, dest_addr);
nl_addr_put (dest_addr);
}
/* Build up the gateway address */
if (gateway) {
tmp_addr = g_malloc0(addrlen);
memcpy(tmp_addr, gateway, addrlen);
gw_addr = nl_addr_build (family, tmp_addr, addrlen);
g_free(tmp_addr);
if (gw_addr) {
nl_addr_set_prefixlen (gw_addr, 0);
rtnl_route_set_gateway (route, gw_addr);
rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
nl_addr_put(gw_addr);
} else {
nm_log_err (LOGD_DEVICE | log, "Invalid gateway");
}
}
err = rtnl_route_add (sk, route, 0);
/* LIBNL Bug: Aliased ESRCH */
if (err == -NLE_FAILURE)
err = -NLE_OBJ_NOTFOUND;
if (err)
nm_log_warn (LOGD_DEVICE | log,
"Failed to add route %s",
nl_geterror(err));
return err;
}
/**
* nm_netlink_route_delete:
* @route: the route to delete
*
* Returns: %TRUE if the request was successful, %FALSE if it failed
**/
gboolean
nm_netlink_route_delete (struct rtnl_route *route)
{
struct nl_sock *nlh;
int err = 0;
g_return_val_if_fail (route != NULL, FALSE);
nlh = nm_netlink_get_default_handle ();
err = rtnl_route_delete (nlh, route, 0);
if (err)
nm_log_dbg (LOGD_IP4 | LOGD_IP6, "%s (%d)", nl_geterror(err), err);
/* Workaround libnl BUG: ESRCH is aliased to generic NLE_FAILURE
* See: http://git.kernel.org/?p=libs/netlink/libnl.git;a=commit;h=7e9d5f */
if (err == -NLE_FAILURE)
err = -NLE_OBJ_NOTFOUND;
return (err && (err != -NLE_OBJ_NOTFOUND) && (err != -NLE_RANGE) ) ? FALSE : TRUE;
}
static void
dump_route (struct rtnl_route *route)
{
char buf6[INET6_ADDRSTRLEN];
char buf4[INET_ADDRSTRLEN];
struct nl_addr *nl;
struct in6_addr *addr6 = NULL;
struct in_addr *addr4 = NULL;
int prefixlen = 0;
const char *sf = "UNSPEC";
int family = rtnl_route_get_family (route);
guint32 log_level = LOGD_IP4 | LOGD_IP6;
memset (buf6, 0, sizeof (buf6));
memset (buf4, 0, sizeof (buf4));
nl = rtnl_route_get_dst (route);
if (nl) {
if (nl_addr_get_family (nl) == AF_INET) {
addr4 = nl_addr_get_binary_addr (nl);
if (addr4)
inet_ntop (AF_INET, addr4, &buf4[0], sizeof (buf4));
} else if (nl_addr_get_family (nl) == AF_INET6) {
addr6 = nl_addr_get_binary_addr (nl);
if (addr6)
inet_ntop (AF_INET6, addr6, &buf6[0], sizeof (buf6));
}
prefixlen = nl_addr_get_prefixlen (nl);
}
if (family == AF_INET) {
sf = "INET";
log_level = LOGD_IP4;
} else if (family == AF_INET6) {
sf = "INET6";
log_level = LOGD_IP6;
}
nm_log_dbg (log_level, " route idx %d family %s (%d) addr %s/%d",
rtnl_route_get_oif (route),
sf, family,
strlen (buf4) ? buf4 : (strlen (buf6) ? buf6 : "<unknown>"),
prefixlen);
}
typedef struct {
int ifindex;
int family;
int scope;
gboolean ignore_inet6_ll_mc;
const char *iface;
NlRouteForeachFunc callback;
gpointer user_data;
struct rtnl_route *out_route;
} ForeachRouteInfo;
static void
foreach_route_cb (struct nl_object *object, void *user_data)
{
ForeachRouteInfo *info = user_data;
struct rtnl_route *route = (struct rtnl_route *) object;
struct nl_addr *dst;
if (info->out_route)
return;
if (nm_logging_level_enabled (LOGL_DEBUG))
dump_route (route);
if ( info->ifindex >= 0
&& rtnl_route_get_oif (route) != info->ifindex)
return;
if ( info->scope != RT_SCOPE_UNIVERSE
&& rtnl_route_get_scope (route) != info->scope)
return;
if ( info->family != AF_UNSPEC
&& rtnl_route_get_family (route) != info->family)
return;
dst = rtnl_route_get_dst (route);
/* Check for IPv6 LL and MC routes that might need to be ignored */
if ( (info->family == AF_INET6 || info->family == AF_UNSPEC)
&& (rtnl_route_get_family (route) == AF_INET6)) {
struct in6_addr *addr = NULL;
if (dst)
addr = nl_addr_get_binary_addr (dst);
if (addr) {
if ( IN6_IS_ADDR_LINKLOCAL (addr)
|| IN6_IS_ADDR_MC_LINKLOCAL (addr)
|| (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (dst) == 8)))
return;
}
}
info->out_route = info->callback (route, dst, info->iface, info->user_data);
if (info->out_route) {
/* Ref the route so it sticks around after the cache is cleared */
rtnl_route_get (info->out_route);
}
}
/**
* nm_netlink_foreach_route:
* @ifindex: the interface index to filter routes for
* @family: the address family to filter routes for
* @scope: route scope, eg RT_SCOPE_LINK
* @ignore_inet6_ll_mc: if %TRUE ignore IPv6 link-local and multi-cast routes
* @callback: function called when a route matches the filter
* @user_data: data passed to @callback
*
* Filters each route in the routing table against the given @ifindex and
* @family (if given) and calls @callback for each matching route.
*
* Returns: a route if @callback returned one; the caller must dispose of the
* route using rtnl_route_put() when it is no longer required.
**/
struct rtnl_route *
nm_netlink_foreach_route (int ifindex,
int family,
int scope,
gboolean ignore_inet6_ll_mc,
NlRouteForeachFunc callback,
gpointer user_data)
{
struct nl_cache *cache;
ForeachRouteInfo info;
memset (&info, 0, sizeof (info));
info.ifindex = ifindex;
info.family = family;
info.scope = scope;
info.ignore_inet6_ll_mc = ignore_inet6_ll_mc;
info.callback = callback;
info.user_data = user_data;
info.iface = nm_netlink_index_to_iface (ifindex);
rtnl_route_alloc_cache (nm_netlink_get_default_handle (), family, NL_AUTO_PROVIDE, &cache);
g_return_val_if_fail (cache != NULL, NULL);
nl_cache_foreach (cache, foreach_route_cb, &info);
nl_cache_free (cache);
return info.out_route;
}

80
src/nm-netlink-utils.h Normal file
View file

@ -0,0 +1,80 @@
/* -*- 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) 2011 Red Hat, Inc.
*/
#ifndef NM_NETLINK_UTILS_H
#define NM_NETLINK_UTILS_H
#include <glib.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
gboolean nm_netlink_find_address (int ifindex,
int family,
void *addr, /* struct in_addr or struct in6_addr */
int prefix_);
typedef enum {
NMNL_PROP_INVALID = 0,
NMNL_PROP_PROT,
NMNL_PROP_SCOPE,
NMNL_PROP_TABLE,
NMNL_PROP_PRIO,
} NmNlProp;
struct rtnl_route * nm_netlink_route_new (int ifindex,
int family,
int mss,
...) __attribute__((__sentinel__));
int nm_netlink_route_add (struct rtnl_route *route,
int family,
const void * dst, /* struct in_addr or struct in6_addr */
int prefix,
const void * gw, /* struct in_addr or struct in6_addr */
int flags);
gboolean nm_netlink_route_delete (struct rtnl_route *route);
/**
* NlRouteForeachFunc:
* @route: the route being processed
* @dst: the route's destination address
* @iface: the interface name of the index passed to nm_netlink_foreach_route()
* @in_family: the address family passed to nm_netlink_foreach_route()
* @user_data: the user data pointer passed to nm_netlink_foreach_route()
*
* Returns: a route to return to the caller of nm_netlink_foreach_route() which
* terminates routing table iteration, or NULL to continue iterating the
* routing table.
**/
typedef struct rtnl_route * (*NlRouteForeachFunc) (struct rtnl_route *route,
struct nl_addr *dst,
const char *iface,
gpointer user_data);
struct rtnl_route * nm_netlink_foreach_route (int ifindex,
int family,
int scope,
gboolean ignore_inet6_ll_mc,
NlRouteForeachFunc callback,
gpointer user_data);
#endif /* NM_NETLINK_MONITOR_H */

View file

@ -425,6 +425,7 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
NMConnection *connection = NULL;
NMSettingConnection *s_con = NULL;
const char *connection_id;
int ip_ifindex = 0;
best = get_best_ip4_device (policy->manager, &best_req);
if (!best)
@ -461,17 +462,18 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
NMDevice *parent;
ip_iface = nm_vpn_connection_get_ip_iface (candidate);
ip_ifindex = nm_vpn_connection_get_ip_ifindex (candidate);
connection = nm_vpn_connection_get_connection (candidate);
addr = nm_ip4_config_get_address (ip4_config, 0);
parent = nm_vpn_connection_get_parent_device (candidate);
parent_ip4 = nm_device_get_ip4_config (parent);
nm_system_replace_default_ip4_route_vpn (ip_iface,
nm_system_replace_default_ip4_route_vpn (ip_ifindex,
nm_ip4_address_get_gateway (addr),
nm_vpn_connection_get_ip4_internal_gateway (candidate),
nm_ip4_config_get_mss (ip4_config),
nm_device_get_ip_iface (parent),
nm_device_get_ip_ifindex (parent),
nm_ip4_config_get_mss (parent_ip4));
dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
@ -483,12 +485,14 @@ update_ip4_routing_and_dns (NMPolicy *policy, gboolean force_update)
if (!ip_iface || !ip4_config) {
connection = nm_act_request_get_connection (best_req);
ip_iface = nm_device_get_ip_iface (best);
ip_ifindex = nm_device_get_ip_ifindex (best);
ip4_config = nm_device_get_ip4_config (best);
g_assert (ip4_config);
addr = nm_ip4_config_get_address (ip4_config, 0);
nm_system_replace_default_ip4_route (ip_iface, nm_ip4_address_get_gateway (addr), nm_ip4_config_get_mss (ip4_config));
nm_system_replace_default_ip4_route (ip_ifindex,
nm_ip4_address_get_gateway (addr),
nm_ip4_config_get_mss (ip4_config));
dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
}
@ -551,6 +555,7 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
NMIP6Config *ip6_config = NULL;
NMIP6Address *addr;
const char *ip_iface = NULL;
int ip_ifindex = -1;
NMConnection *connection = NULL;
NMSettingConnection *s_con = NULL;
const char *connection_id;
@ -608,11 +613,12 @@ update_ip6_routing_and_dns (NMPolicy *policy, gboolean force_update)
if (!ip_iface || !ip6_config) {
connection = nm_act_request_get_connection (best_req);
ip_iface = nm_device_get_ip_iface (best);
ip_ifindex = nm_device_get_ip_ifindex (best);
ip6_config = nm_device_get_ip6_config (best);
g_assert (ip6_config);
addr = nm_ip6_config_get_address (ip6_config, 0);
nm_system_replace_default_ip6_route (ip_iface, nm_ip6_address_get_gateway (addr));
nm_system_replace_default_ip6_route (ip_ifindex, nm_ip6_address_get_gateway (addr));
dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
}

File diff suppressed because it is too large Load diff

View file

@ -35,33 +35,31 @@
* implemented in the backend files in backends/ directory
*/
void nm_system_device_flush_routes (NMDevice *dev, int family);
void nm_system_device_flush_routes_with_iface (const char *iface, int family);
gboolean nm_system_iface_flush_routes (int ifindex, int family);
gboolean nm_system_replace_default_ip4_route (const char *iface,
gboolean nm_system_replace_default_ip4_route (int ifindex,
guint32 gw,
guint32 mss);
gboolean nm_system_replace_default_ip6_route (const char *iface,
gboolean nm_system_replace_default_ip6_route (int ifindex,
const struct in6_addr *gw);
gboolean nm_system_replace_default_ip4_route_vpn (const char *iface,
gboolean nm_system_replace_default_ip4_route_vpn (int ifindex,
guint32 ext_gw,
guint32 int_gw,
guint32 mss,
const char *parent_iface,
int parent_ifindex,
guint32 parent_mss);
struct rtnl_route *nm_system_add_ip4_vpn_gateway_route (NMDevice *parent_device, NMIP4Config *vpn_config);
void nm_system_device_flush_addresses (NMDevice *dev, int family);
void nm_system_device_flush_addresses_with_iface (const char *iface);
gboolean nm_system_iface_flush_addresses (int ifindex, int family);
void nm_system_enable_loopback (void);
void nm_system_update_dns (void);
gboolean nm_system_apply_ip4_config (const char *iface,
gboolean nm_system_apply_ip4_config (int ifindex,
NMIP4Config *config,
int priority,
NMIP4ConfigCompareFlags flags);
@ -76,22 +74,19 @@ int nm_system_set_ip6_route (int ifindex,
int table,
struct rtnl_route **out_route);
gboolean nm_system_apply_ip6_config (const char *iface,
gboolean nm_system_apply_ip6_config (int ifindex,
NMIP6Config *config,
int priority,
NMIP6ConfigCompareFlags flags);
gboolean nm_system_device_set_up_down (NMDevice *dev,
gboolean up,
gboolean *no_firmware);
gboolean nm_system_device_set_up_down_with_iface (const char *iface,
gboolean up,
gboolean *no_firmware);
gboolean nm_system_iface_set_up (int ifindex,
gboolean up,
gboolean *no_firmware);
gboolean nm_system_device_is_up (NMDevice *device);
gboolean nm_system_device_is_up_with_iface (const char *iface);
gboolean nm_system_iface_is_up (int ifindex);
gboolean nm_system_device_set_mtu (const char *iface, guint32 mtu);
gboolean nm_system_device_set_mac (const char *iface, const struct ether_addr *mac);
gboolean nm_system_iface_set_mtu (int ifindex, guint32 mtu);
gboolean nm_system_iface_set_mac (int ifindex, const struct ether_addr *mac);
#endif

View file

@ -46,6 +46,7 @@
#include "NetworkManagerUtils.h"
#include "nm-dns-manager.h"
#include "nm-netlink-monitor.h"
#include "nm-netlink-utils.h"
#include "nm-glib-compat.h"
#include "settings/nm-settings-connection.h"
@ -86,6 +87,7 @@ typedef struct {
NMIP4Config *ip4_config;
guint32 ip4_internal_gw;
char *ip_iface;
int ip_ifindex;
char *banner;
struct rtnl_route *gw_route;
@ -424,6 +426,13 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
goto error;
}
/* Grab the interface index for address/routing operations */
priv->ip_ifindex = nm_netlink_iface_to_index (priv->ip_iface);
if (!priv->ip_ifindex) {
nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface);
goto error;
}
addr = nm_ip4_address_new ();
nm_ip4_address_set_prefix (addr, 24); /* default to class C */
@ -529,9 +538,9 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
nm_utils_merge_ip4_config (config, s_ip4);
nm_system_device_set_up_down_with_iface (priv->ip_iface, TRUE, NULL);
nm_system_iface_set_up (priv->ip_ifindex, TRUE, NULL);
if (nm_system_apply_ip4_config (priv->ip_iface, config, 0, NM_IP4_COMPARE_FLAG_ALL)) {
if (nm_system_apply_ip4_config (priv->ip_ifindex, config, 0, NM_IP4_COMPARE_FLAG_ALL)) {
NMDnsManager *dns_mgr;
/* Add any explicit route to the VPN gateway through the parent device */
@ -765,6 +774,14 @@ nm_vpn_connection_get_ip_iface (NMVPNConnection *connection)
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_iface;
}
int
nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection)
{
g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), -1);
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex;
}
NMDevice *
nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
{
@ -940,11 +957,11 @@ vpn_cleanup (NMVPNConnection *connection)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
if (priv->ip_iface) {
nm_system_device_set_up_down_with_iface (priv->ip_iface, FALSE, NULL);
if (priv->ip_ifindex) {
nm_system_iface_set_up (priv->ip_ifindex, FALSE, NULL);
/* FIXME: use AF_UNSPEC here when we have IPv6 support */
nm_system_device_flush_routes_with_iface (priv->ip_iface, AF_INET);
nm_system_device_flush_addresses_with_iface (priv->ip_iface);
nm_system_iface_flush_routes (priv->ip_ifindex, AF_INET);
nm_system_iface_flush_addresses (priv->ip_ifindex, AF_UNSPEC);
}
if (priv->ip4_config) {
@ -958,12 +975,12 @@ vpn_cleanup (NMVPNConnection *connection)
/* Remove any previously added VPN gateway host route */
if (priv->gw_route)
rtnl_route_del (nm_netlink_get_default_handle (), priv->gw_route, 0);
nm_netlink_route_delete (priv->gw_route);
/* Reset routes and addresses of the currently active device */
parent_config = nm_device_get_ip4_config (priv->parent_dev);
if (parent_config) {
if (!nm_system_apply_ip4_config (nm_device_get_ip_iface (priv->parent_dev),
if (!nm_system_apply_ip4_config (nm_device_get_ip_ifindex (priv->parent_dev),
nm_device_get_ip4_config (priv->parent_dev),
nm_device_get_priority (priv->parent_dev),
NM_IP4_COMPARE_FLAG_ADDRESSES | NM_IP4_COMPARE_FLAG_ROUTES)) {
@ -982,6 +999,7 @@ vpn_cleanup (NMVPNConnection *connection)
g_free (priv->ip_iface);
priv->ip_iface = NULL;
priv->ip_ifindex = 0;
/* Clear out connection secrets to ensure that the settings service
* gets asked for them next time the connection is activated.

View file

@ -72,6 +72,7 @@ void nm_vpn_connection_disconnect (NMVPNConnection *connect
NMVPNConnectionStateReason reason);
NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connection);
const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection);
int nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection);
NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection);

View file

@ -390,7 +390,7 @@ real_take_down (NMDevice *device)
static gboolean
real_hw_is_up (NMDevice *device)
{
return nm_system_device_is_up (device);
return nm_system_iface_is_up (nm_device_get_ip_ifindex (device));
}
static gboolean
@ -401,13 +401,13 @@ real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
if (!priv->enabled || !priv->wimaxd_enabled)
return FALSE;
return nm_system_device_set_up_down (dev, TRUE, no_firmware);
return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware);
}
static void
real_hw_take_down (NMDevice *dev)
{
nm_system_device_set_up_down (dev, FALSE, NULL);
nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL);
}
static void