diff options
Diffstat (limited to 'src/nm-system.c')
-rw-r--r-- | src/nm-system.c | 192 |
1 files changed, 155 insertions, 37 deletions
diff --git a/src/nm-system.c b/src/nm-system.c index 35aa36a111..7921fec654 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -44,7 +44,6 @@ #include "nm-system.h" #include "nm-device.h" -#include "nm-named-manager.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-logging.h" @@ -481,32 +480,34 @@ nm_system_apply_ip4_config (const char *iface, return TRUE; } -static struct rtnl_route * -nm_system_device_set_ip6_route (const char *iface, - const struct in6_addr *ip6_dest, - guint32 ip6_prefix, - const struct in6_addr *ip6_gateway, - guint32 metric, - int mss) +int +nm_system_set_ip6_route (int ifindex, + const struct in6_addr *ip6_dest, + guint32 ip6_prefix, + const struct in6_addr *ip6_gateway, + guint32 metric, + int mss, + int protocol, + int table, + struct rtnl_route **out_route) { struct nl_handle *nlh; struct rtnl_route *route; struct nl_addr *dest_addr; struct nl_addr *gw_addr = NULL; - int err, iface_idx; + int err = 0; - nlh = nm_netlink_get_default_handle (); - g_return_val_if_fail (nlh != NULL, NULL); + g_return_val_if_fail (ifindex >= 0, -1); - iface_idx = nm_netlink_iface_to_index (iface); - g_return_val_if_fail (iface_idx >= 0, NULL); + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, -1); - route = create_route (iface_idx, mss); - g_return_val_if_fail (route != NULL, NULL); + route = create_route (ifindex, mss); + g_return_val_if_fail (route != NULL, -1); /* Destination */ dest_addr = nl_addr_build (AF_INET6, (struct in6_addr *) ip6_dest, sizeof (*ip6_dest)); - g_return_val_if_fail (dest_addr != NULL, NULL); + g_return_val_if_fail (dest_addr != NULL, -1); nl_addr_set_prefixlen (dest_addr, (int) ip6_prefix); rtnl_route_set_dst (route, dest_addr); @@ -521,7 +522,7 @@ nm_system_device_set_ip6_route (const char *iface, } else { nm_log_warn (LOGD_DEVICE | LOGD_IP6, "Invalid gateway"); rtnl_route_put (route); - return NULL; + return -1; } } @@ -529,13 +530,19 @@ nm_system_device_set_ip6_route (const char *iface, if (metric) rtnl_route_set_prio (route, metric); + if (protocol) + rtnl_route_set_protocol (route, protocol); + + if (table) + rtnl_route_set_table (route, table); + /* Add the route */ err = rtnl_route_add (nlh, route, 0); if (err == -ESRCH && ip6_gateway) { /* Gateway might be over a bridge; try adding a route to gateway first */ struct rtnl_route *route2; - route2 = create_route (iface_idx, mss); + route2 = create_route (ifindex, mss); if (route2) { /* Add route to gateway over bridge */ rtnl_route_set_dst (route2, gw_addr); @@ -553,15 +560,12 @@ nm_system_device_set_ip6_route (const char *iface, if (gw_addr) nl_addr_put (gw_addr); - if (err) { - nm_log_err (LOGD_DEVICE | LOGD_IP6, - "(%s): failed to set IPv6 route: %s", - iface, nl_geterror ()); + if (out_route) + *out_route = route; + else rtnl_route_put (route); - route = NULL; - } - return route; + return err; } static gboolean @@ -618,24 +622,33 @@ nm_system_apply_ip6_config (const char *iface, } if (flags & NM_IP6_COMPARE_FLAG_ROUTES) { + int ifindex = nm_netlink_iface_to_index (iface); + for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) { NMIP6Route *route = nm_ip6_config_get_route (config, i); - struct rtnl_route *tmp; + int err; /* Don't add the route if it doesn't have a gateway and the connection * is never supposed to be the default connection. */ if ( nm_ip6_config_get_never_default (config) - && IN6_IS_ADDR_UNSPECIFIED(nm_ip6_route_get_dest (route))) + && IN6_IS_ADDR_UNSPECIFIED (nm_ip6_route_get_dest (route))) continue; - tmp = nm_system_device_set_ip6_route (iface, - nm_ip6_route_get_dest (route), - nm_ip6_route_get_prefix (route), - nm_ip6_route_get_next_hop (route), - nm_ip6_route_get_metric (route), - nm_ip6_config_get_mss (config)); - rtnl_route_put (tmp); + err = nm_system_set_ip6_route (ifindex, + nm_ip6_route_get_dest (route), + nm_ip6_route_get_prefix (route), + nm_ip6_route_get_next_hop (route), + nm_ip6_route_get_metric (route), + nm_ip6_config_get_mss (config), + RTPROT_UNSPEC, + RT_TABLE_UNSPEC, + NULL); + if (err) { + nm_log_err (LOGD_DEVICE | LOGD_IP6, + "(%s): failed to set IPv6 route: %s", + iface, nl_geterror ()); + } } } @@ -772,6 +785,48 @@ nm_system_device_set_mtu (const char *iface, guint32 mtu) return success; } +gboolean +nm_system_device_set_mac (const char *iface, const struct ether_addr *mac) +{ + struct rtnl_link *old; + struct rtnl_link *new; + gboolean success = FALSE; + struct nl_handle *nlh; + int iface_idx; + struct nl_addr *addr = NULL; + + g_return_val_if_fail (iface != NULL, FALSE); + g_return_val_if_fail (mac != NULL, FALSE); + + new = rtnl_link_alloc (); + if (!new) + return FALSE; + + iface_idx = nm_netlink_iface_to_index (iface); + old = nm_netlink_index_to_rtnl_link (iface_idx); + if (old) { + addr = nl_addr_build (AF_LLC, (void *) mac, ETH_ALEN); + if (!addr) { + char *mac_str; + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", mac->ether_addr_octet[0], mac->ether_addr_octet[1], mac->ether_addr_octet[2], + mac->ether_addr_octet[3], mac->ether_addr_octet[4], mac->ether_addr_octet[5]); + nm_log_err (LOGD_DEVICE, "(%s): could not allocate memory for MAC address (%s)", iface, mac_str); + g_free (mac_str); + return FALSE; + } + rtnl_link_set_addr (new, addr); + nlh = nm_netlink_get_default_handle (); + if (nlh) { + rtnl_link_change (nlh, old, new, 0); + success = TRUE; + } + rtnl_link_put (old); + } + + rtnl_link_put (new); + return success; +} + static struct rtnl_route * add_ip4_route_to_gateway (const char *iface, guint32 gw, guint32 mss) { @@ -1183,6 +1238,45 @@ foreach_route (void (*callback)(struct nl_object *, gpointer), nl_cache_free (route_cache); } +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); + + 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"; + else if (family == AF_INET6) + sf = "INET6"; + + nm_log_dbg (LOGD_IP4 | LOGD_IP6, " 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 { const char *iface; @@ -1196,6 +1290,10 @@ check_one_route (struct nl_object *object, void *user_data) RouteCheckData *data = (RouteCheckData *) user_data; struct rtnl_route *route = (struct rtnl_route *) object; int err; + guint32 log_level = LOGD_IP4 | LOGD_IP6; + + if (nm_logging_level_enabled (LOGL_DEBUG)) + dump_route (route); /* Delete all routes from this interface */ if (rtnl_route_get_oif (route) != data->iface_idx) @@ -1217,22 +1315,32 @@ check_one_route (struct nl_object *object, void *user_data) addr = nl_addr_get_binary_addr (nl); if (addr) { - if (IN6_IS_ADDR_LINKLOCAL (addr) || IN6_IS_ADDR_MC_LINKLOCAL (addr)) + if ( IN6_IS_ADDR_LINKLOCAL (addr) + || IN6_IS_ADDR_MC_LINKLOCAL (addr) + || (IN6_IS_ADDR_MULTICAST (addr) && (nl_addr_get_prefixlen (nl) == 8))) return; } } + if (data->family == AF_INET) + log_level = LOGD_IP4; + else if (data->family == AF_INET6) + log_level = LOGD_IP6; + nm_log_dbg (log_level, " deleting route"); + err = rtnl_route_del (nm_netlink_get_default_handle (), route, 0); - if (err < 0) { + if (err < 0 && (err != -ERANGE)) { nm_log_err (LOGD_DEVICE, "(%s): error %d returned from rtnl_route_del(): %s", - data->iface, err, nl_geterror()); + data->iface, err, nl_geterror ()); } } static void flush_routes (int ifindex, const char *iface, int family) { RouteCheckData check_data; + guint32 log_level = LOGD_IP4 | LOGD_IP6; + const char *sf = "UNSPEC"; g_return_if_fail (iface != NULL); @@ -1244,6 +1352,16 @@ static void flush_routes (int ifindex, const char *iface, int family) } } + if (family == AF_INET) { + log_level = LOGD_IP4; + sf = "INET"; + } else if (family == AF_INET6) { + log_level = LOGD_IP6; + sf = "INET6"; + } + nm_log_dbg (log_level, "(%s): flushing routes ifindex %d family %s (%d)", + iface, ifindex, sf, family); + memset (&check_data, 0, sizeof (check_data)); check_data.iface = iface; check_data.iface_idx = ifindex; |