2013-10-17 05:18:36 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
Copyright 2013 Tom Gundersen < teg @ jklm . no >
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation ; either version 2.1 of the License , or
( at your option ) any later version .
systemd 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
2014-05-19 00:10:48 +04:00
# include <sys/socket.h>
2014-05-08 19:21:37 +04:00
# include <linux/if.h>
2014-01-06 02:01:10 +04:00
2015-08-27 14:59:06 +03:00
# include "sd-netlink.h"
# include "sd-daemon.h"
2014-05-16 21:44:22 +04:00
# include "conf-parser.h"
2013-10-17 05:18:36 +04:00
# include "path-util.h"
# include "libudev-private.h"
2013-12-13 06:30:42 +04:00
# include "udev-util.h"
2015-06-12 17:31:33 +03:00
# include "netlink-util.h"
2015-02-04 17:00:20 +03:00
# include "bus-util.h"
# include "def.h"
2014-02-12 19:40:24 +04:00
# include "virt.h"
2015-08-27 14:59:06 +03:00
# include "set.h"
2015-08-27 17:45:24 +03:00
# include "local-addresses.h"
2013-10-17 05:18:36 +04:00
2015-08-27 14:59:06 +03:00
# include "networkd.h"
2014-04-15 16:21:44 +04:00
2014-11-27 20:50:48 +03:00
/* use 8 MB for receive socket kernel queue. */
# define RCVBUF_SIZE (8*1024*1024)
2014-01-09 02:41:41 +04:00
const char * const network_dirs [ ] = {
" /etc/systemd/network " ,
" /run/systemd/network " ,
" /usr/lib/systemd/network " ,
2014-03-14 21:19:29 +04:00
# ifdef HAVE_SPLIT_USR
2014-01-09 02:41:41 +04:00
" /lib/systemd/network " ,
# endif
NULL } ;
2014-06-18 20:22:14 +04:00
static int setup_default_address_pool ( Manager * m ) {
AddressPool * p ;
int r ;
assert ( m ) ;
/* Add in the well-known private address ranges. */
r = address_pool_new_from_string ( m , & p , AF_INET6 , " fc00:: " , 7 ) ;
if ( r < 0 )
return r ;
r = address_pool_new_from_string ( m , & p , AF_INET , " 192.168.0.0 " , 16 ) ;
if ( r < 0 )
return r ;
r = address_pool_new_from_string ( m , & p , AF_INET , " 172.16.0.0 " , 12 ) ;
if ( r < 0 )
return r ;
r = address_pool_new_from_string ( m , & p , AF_INET , " 10.0.0.0 " , 8 ) ;
if ( r < 0 )
return r ;
return 0 ;
}
2015-02-03 17:44:12 +03:00
static int on_bus_retry ( sd_event_source * s , usec_t usec , void * userdata ) {
Manager * m = userdata ;
assert ( s ) ;
assert ( m ) ;
m - > bus_retry_event_source = sd_event_source_unref ( m - > bus_retry_event_source ) ;
manager_connect_bus ( m ) ;
return 0 ;
}
static int manager_reset_all ( Manager * m ) {
Link * link ;
Iterator i ;
int r ;
assert ( m ) ;
HASHMAP_FOREACH ( link , m - > links , i ) {
r = link_carrier_reset ( link ) ;
if ( r < 0 )
2015-08-26 21:43:28 +03:00
log_link_warning_errno ( link , r , " Could not reset carrier: %m " ) ;
2015-02-03 17:44:12 +03:00
}
return 0 ;
}
2015-04-29 19:35:10 +03:00
static int match_prepare_for_sleep ( sd_bus_message * message , void * userdata , sd_bus_error * ret_error ) {
2015-02-03 17:44:12 +03:00
Manager * m = userdata ;
int b , r ;
2015-04-29 19:35:10 +03:00
assert ( message ) ;
2015-02-03 17:44:12 +03:00
r = sd_bus_message_read ( message , " b " , & b ) ;
if ( r < 0 ) {
log_debug_errno ( r , " Failed to parse PrepareForSleep signal: %m " ) ;
return 0 ;
}
if ( b )
return 0 ;
log_debug ( " Coming back from suspend, resetting all connections... " ) ;
manager_reset_all ( m ) ;
return 0 ;
}
int manager_connect_bus ( Manager * m ) {
int r ;
assert ( m ) ;
r = sd_bus_default_system ( & m - > bus ) ;
if ( r = = - ENOENT ) {
/* We failed to connect? Yuck, we must be in early
* boot . Let ' s try in 5 s again . As soon as we have
* kdbus we can stop doing this . . . */
log_debug_errno ( r , " Failed to connect to bus, trying again in 5s: %m " ) ;
r = sd_event_add_time ( m - > event , & m - > bus_retry_event_source , CLOCK_MONOTONIC , now ( CLOCK_MONOTONIC ) + 5 * USEC_PER_SEC , 0 , on_bus_retry , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to install bus reconnect time event: %m " ) ;
return 0 ;
2015-08-06 01:31:09 +03:00
}
if ( r < 0 )
2015-02-03 17:44:12 +03:00
return r ;
r = sd_bus_add_match ( m - > bus , & m - > prepare_for_sleep_slot ,
" type='signal', "
" sender='org.freedesktop.login1', "
" interface='org.freedesktop.login1.Manager', "
" member='PrepareForSleep', "
" path='/org/freedesktop/login1' " ,
match_prepare_for_sleep ,
m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add match for PrepareForSleep: %m " ) ;
2015-02-04 13:44:37 +03:00
r = sd_bus_add_object_vtable ( m - > bus , NULL , " /org/freedesktop/network1 " , " org.freedesktop.network1.Manager " , manager_vtable , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add manager object vtable: %m " ) ;
r = sd_bus_add_fallback_vtable ( m - > bus , NULL , " /org/freedesktop/network1/link " , " org.freedesktop.network1.Link " , link_vtable , link_object_find , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add link object vtable: %m " ) ;
r = sd_bus_add_node_enumerator ( m - > bus , NULL , " /org/freedesktop/network1/link " , link_node_enumerator , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add link enumerator: %m " ) ;
2015-02-08 15:27:56 +03:00
r = sd_bus_add_fallback_vtable ( m - > bus , NULL , " /org/freedesktop/network1/network " , " org.freedesktop.network1.Network " , network_vtable , network_object_find , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add network object vtable: %m " ) ;
r = sd_bus_add_node_enumerator ( m - > bus , NULL , " /org/freedesktop/network1/network " , network_node_enumerator , m ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to add network enumerator: %m " ) ;
2015-02-04 13:44:37 +03:00
r = sd_bus_request_name ( m - > bus , " org.freedesktop.network1 " , 0 ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to register name: %m " ) ;
r = sd_bus_attach_event ( m - > bus , m - > event , 0 ) ;
if ( r < 0 )
return log_error_errno ( r , " Failed to attach bus to event loop: %m " ) ;
2015-02-03 17:44:12 +03:00
return 0 ;
}
2015-02-03 17:44:50 +03:00
static int manager_udev_process_link ( Manager * m , struct udev_device * device ) {
Link * link = NULL ;
int r , ifindex ;
2015-02-02 00:13:26 +03:00
2015-02-03 17:44:50 +03:00
assert ( m ) ;
assert ( device ) ;
2015-02-02 00:13:26 +03:00
2015-02-03 17:44:50 +03:00
if ( ! streq_ptr ( udev_device_get_action ( device ) , " add " ) )
return 0 ;
2015-02-02 00:13:26 +03:00
2015-02-03 17:44:50 +03:00
ifindex = udev_device_get_ifindex ( device ) ;
if ( ifindex < = 0 ) {
2015-08-26 21:43:28 +03:00
log_debug ( " Ignoring udev ADD event for device with invalid ifindex " ) ;
2015-02-03 17:44:50 +03:00
return 0 ;
2015-02-02 00:13:26 +03:00
}
2015-02-03 17:44:50 +03:00
r = link_get ( m , ifindex , & link ) ;
if ( r = = - ENODEV )
return 0 ;
else if ( r < 0 )
2013-10-17 05:18:36 +04:00
return r ;
2015-02-03 17:44:50 +03:00
r = link_initialized ( link , device ) ;
2015-02-03 01:21:20 +03:00
if ( r < 0 )
return r ;
2015-02-03 17:44:50 +03:00
return 0 ;
}
2014-11-27 20:50:48 +03:00
2015-02-03 17:44:50 +03:00
static int manager_dispatch_link_udev ( sd_event_source * source , int fd , uint32_t revents , void * userdata ) {
Manager * m = userdata ;
struct udev_monitor * monitor = m - > udev_monitor ;
_cleanup_udev_device_unref_ struct udev_device * device = NULL ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
device = udev_monitor_receive_device ( monitor ) ;
if ( ! device )
2013-11-25 02:37:56 +04:00
return - ENOMEM ;
2015-02-03 17:44:50 +03:00
manager_udev_process_link ( m , device ) ;
2013-10-17 05:18:36 +04:00
return 0 ;
}
2015-02-03 17:44:50 +03:00
static int manager_connect_udev ( Manager * m ) {
int r ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
/* udev does not initialize devices inside containers,
* so we rely on them being already initialized before
* entering the container */
2015-09-07 14:42:47 +03:00
if ( detect_container ( ) > 0 )
2015-02-03 17:44:50 +03:00
return 0 ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
m - > udev = udev_new ( ) ;
if ( ! m - > udev )
return - ENOMEM ;
2013-11-25 02:37:56 +04:00
2015-02-03 17:44:50 +03:00
m - > udev_monitor = udev_monitor_new_from_netlink ( m - > udev , " udev " ) ;
if ( ! m - > udev_monitor )
return - ENOMEM ;
2013-11-25 02:37:56 +04:00
2015-02-03 17:44:50 +03:00
r = udev_monitor_filter_add_match_subsystem_devtype ( m - > udev_monitor , " net " , NULL ) ;
2013-11-25 02:37:56 +04:00
if ( r < 0 )
2015-02-03 17:44:50 +03:00
return log_error_errno ( r , " Could not add udev monitor filter: %m " ) ;
2013-11-25 02:37:56 +04:00
2015-02-03 17:44:50 +03:00
r = udev_monitor_enable_receiving ( m - > udev_monitor ) ;
if ( r < 0 ) {
log_error ( " Could not enable udev monitor " ) ;
2013-11-25 02:37:56 +04:00
return r ;
2014-04-19 22:49:06 +04:00
}
2014-04-15 16:21:44 +04:00
2015-02-03 17:44:50 +03:00
r = sd_event_add_io ( m - > event ,
& m - > udev_event_source ,
udev_monitor_get_fd ( m - > udev_monitor ) ,
EPOLLIN , manager_dispatch_link_udev ,
m ) ;
if ( r < 0 )
2014-04-19 22:49:06 +04:00
return r ;
2014-04-15 16:21:44 +04:00
2015-02-03 17:44:50 +03:00
r = sd_event_source_set_description ( m - > udev_event_source , " networkd-udev " ) ;
2014-04-15 16:21:44 +04:00
if ( r < 0 )
return r ;
2014-02-19 00:42:05 +04:00
2014-04-15 16:21:44 +04:00
return 0 ;
}
2013-10-17 05:18:36 +04:00
2015-06-12 17:31:33 +03:00
static int manager_rtnl_process_link ( sd_netlink * rtnl , sd_netlink_message * message , void * userdata ) {
2014-04-15 16:21:44 +04:00
Manager * m = userdata ;
Link * link = NULL ;
2014-05-09 19:59:20 +04:00
NetDev * netdev = NULL ;
2014-05-08 20:55:11 +04:00
uint16_t type ;
2014-07-18 04:35:16 +04:00
const char * name ;
2014-04-15 16:21:44 +04:00
int r , ifindex ;
2013-10-17 05:18:36 +04:00
2014-04-15 16:21:44 +04:00
assert ( rtnl ) ;
assert ( message ) ;
2013-10-17 05:18:36 +04:00
assert ( m ) ;
2015-06-12 17:31:33 +03:00
if ( sd_netlink_message_is_error ( message ) ) {
r = sd_netlink_message_get_errno ( message ) ;
2014-12-08 21:54:06 +03:00
if ( r < 0 )
2015-08-26 21:43:28 +03:00
log_warning_errno ( r , " rtnl: Could not receive link: %m " ) ;
2014-12-08 21:54:06 +03:00
return 0 ;
}
2015-06-12 17:31:33 +03:00
r = sd_netlink_message_get_type ( message , & type ) ;
2014-05-08 20:55:11 +04:00
if ( r < 0 ) {
2015-08-26 21:43:28 +03:00
log_warning_errno ( r , " rtnl: Could not get message type: %m " ) ;
2014-05-08 20:55:11 +04:00
return 0 ;
2015-04-03 16:21:03 +03:00
} else if ( type ! = RTM_NEWLINK & & type ! = RTM_DELLINK ) {
2015-08-26 21:43:28 +03:00
log_warning ( " rtnl: Received unexpected message type when processing link " ) ;
2015-04-03 16:21:03 +03:00
return 0 ;
2014-05-08 20:55:11 +04:00
}
2014-04-15 16:21:44 +04:00
r = sd_rtnl_message_link_get_ifindex ( message , & ifindex ) ;
2014-12-08 21:54:06 +03:00
if ( r < 0 ) {
2015-08-26 21:43:28 +03:00
log_warning_errno ( r , " rtnl: Could not get ifindex from link: %m " ) ;
2014-12-08 21:54:06 +03:00
return 0 ;
} else if ( ifindex < = 0 ) {
log_warning ( " rtnl: received link message with invalid ifindex: %d " , ifindex ) ;
2014-04-15 16:21:44 +04:00
return 0 ;
2014-05-09 19:59:20 +04:00
} else
link_get ( m , ifindex , & link ) ;
2013-10-17 05:18:36 +04:00
2015-06-12 17:31:33 +03:00
r = sd_netlink_message_read_string ( message , IFLA_IFNAME , & name ) ;
2014-12-08 21:54:06 +03:00
if ( r < 0 ) {
2015-08-26 21:43:28 +03:00
log_warning_errno ( r , " rtnl: Received link message without ifname: %m " ) ;
2014-05-09 19:59:20 +04:00
return 0 ;
} else
2014-05-08 20:55:11 +04:00
netdev_get ( m , name , & netdev ) ;
2014-05-09 19:59:20 +04:00
switch ( type ) {
case RTM_NEWLINK :
if ( ! link ) {
/* link is new, so add it */
r = link_add ( m , message , & link ) ;
if ( r < 0 ) {
2015-08-26 21:43:28 +03:00
log_warning_errno ( r , " Could not add new link: %m " ) ;
2014-05-09 19:59:20 +04:00
return 0 ;
}
}
if ( netdev ) {
/* netdev exists, so make sure the ifindex matches */
2014-04-15 16:21:44 +04:00
r = netdev_set_ifindex ( netdev , message ) ;
if ( r < 0 ) {
2015-08-26 21:43:28 +03:00
log_warning_errno ( r , " Could not set ifindex on netdev: %m " ) ;
2014-04-15 16:21:44 +04:00
return 0 ;
}
}
2013-12-18 20:12:15 +04:00
2014-05-08 20:55:11 +04:00
r = link_update ( link , message ) ;
if ( r < 0 )
return 0 ;
2014-05-09 19:59:20 +04:00
break ;
case RTM_DELLINK :
link_drop ( link ) ;
netdev_drop ( netdev ) ;
break ;
default :
assert_not_reached ( " Received invalid RTNL message type. " ) ;
2014-05-08 20:55:11 +04:00
}
2014-04-15 16:21:44 +04:00
return 1 ;
}
2015-02-03 17:44:50 +03:00
static int systemd_netlink_fd ( void ) {
int n , fd , rtnl_fd = - EINVAL ;
n = sd_listen_fds ( true ) ;
if ( n < = 0 )
return - EINVAL ;
for ( fd = SD_LISTEN_FDS_START ; fd < SD_LISTEN_FDS_START + n ; fd + + ) {
if ( sd_is_socket ( fd , AF_NETLINK , SOCK_RAW , - 1 ) > 0 ) {
if ( rtnl_fd > = 0 )
return - EINVAL ;
rtnl_fd = fd ;
}
}
return rtnl_fd ;
}
static int manager_connect_rtnl ( Manager * m ) {
int fd , r ;
2014-04-15 16:21:44 +04:00
assert ( m ) ;
2015-02-03 17:44:50 +03:00
fd = systemd_netlink_fd ( ) ;
if ( fd < 0 )
2015-06-12 17:31:33 +03:00
r = sd_netlink_open ( & m - > rtnl ) ;
2015-02-03 17:44:50 +03:00
else
2015-06-12 17:31:33 +03:00
r = sd_netlink_open_fd ( & m - > rtnl , fd ) ;
2014-04-15 16:21:44 +04:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
r = sd_netlink_inc_rcvbuf ( m - > rtnl , RCVBUF_SIZE ) ;
2013-10-17 05:18:36 +04:00
if ( r < 0 )
2013-12-18 06:37:26 +04:00
return r ;
2013-10-17 05:18:36 +04:00
2015-06-12 17:31:33 +03:00
r = sd_netlink_attach_event ( m - > rtnl , m - > event , 0 ) ;
2014-04-15 16:21:44 +04:00
if ( r < 0 )
return r ;
2013-10-17 05:18:36 +04:00
2015-06-12 17:31:33 +03:00
r = sd_netlink_add_match ( m - > rtnl , RTM_NEWLINK , & manager_rtnl_process_link , m ) ;
2015-02-03 17:44:50 +03:00
if ( r < 0 )
return r ;
2014-04-15 16:21:44 +04:00
2015-06-12 17:31:33 +03:00
r = sd_netlink_add_match ( m - > rtnl , RTM_DELLINK , & manager_rtnl_process_link , m ) ;
2015-02-03 17:44:50 +03:00
if ( r < 0 )
return r ;
2014-12-08 21:54:06 +03:00
2015-06-12 17:31:33 +03:00
r = sd_netlink_add_match ( m - > rtnl , RTM_NEWADDR , & link_rtnl_process_address , m ) ;
2015-02-03 17:44:50 +03:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
r = sd_netlink_add_match ( m - > rtnl , RTM_DELADDR , & link_rtnl_process_address , m ) ;
2015-02-03 17:44:50 +03:00
if ( r < 0 )
return r ;
return 0 ;
2014-12-08 21:54:06 +03:00
}
2014-04-15 16:21:44 +04:00
2015-02-03 17:44:50 +03:00
int manager_new ( Manager * * ret ) {
_cleanup_manager_free_ Manager * m = NULL ;
2014-12-08 21:54:06 +03:00
int r ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
m = new0 ( Manager , 1 ) ;
if ( ! m )
return - ENOMEM ;
2014-12-08 21:54:06 +03:00
2015-02-03 17:44:50 +03:00
m - > state_file = strdup ( " /run/systemd/netif/state " ) ;
if ( ! m - > state_file )
return - ENOMEM ;
r = sd_event_default ( & m - > event ) ;
2014-12-08 21:54:06 +03:00
if ( r < 0 )
return r ;
2015-02-03 17:44:50 +03:00
sd_event_set_watchdog ( m - > event , true ) ;
sd_event_add_signal ( m - > event , NULL , SIGTERM , NULL , NULL ) ;
sd_event_add_signal ( m - > event , NULL , SIGINT , NULL , NULL ) ;
r = manager_connect_rtnl ( m ) ;
2014-12-08 21:54:06 +03:00
if ( r < 0 )
return r ;
2015-02-03 17:44:50 +03:00
r = manager_connect_udev ( m ) ;
if ( r < 0 )
return r ;
2014-12-08 21:54:06 +03:00
2015-02-03 17:44:50 +03:00
m - > netdevs = hashmap_new ( & string_hash_ops ) ;
if ( ! m - > netdevs )
return - ENOMEM ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
LIST_HEAD_INIT ( m - > networks ) ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
r = setup_default_address_pool ( m ) ;
if ( r < 0 )
return r ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
* ret = m ;
m = NULL ;
2013-10-17 05:18:36 +04:00
return 0 ;
}
2015-02-03 17:44:50 +03:00
void manager_free ( Manager * m ) {
Network * network ;
NetDev * netdev ;
Link * link ;
AddressPool * pool ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
if ( ! m )
return ;
2014-04-15 16:21:44 +04:00
2015-02-03 17:44:50 +03:00
free ( m - > state_file ) ;
2014-04-15 16:21:44 +04:00
2015-08-27 18:38:05 +03:00
sd_event_source_unref ( m - > udev_event_source ) ;
2015-02-03 17:44:50 +03:00
udev_monitor_unref ( m - > udev_monitor ) ;
udev_unref ( m - > udev ) ;
2015-08-27 18:38:05 +03:00
2015-02-03 17:44:50 +03:00
sd_bus_unref ( m - > bus ) ;
sd_bus_slot_unref ( m - > prepare_for_sleep_slot ) ;
sd_event_source_unref ( m - > bus_retry_event_source ) ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
while ( ( link = hashmap_first ( m - > links ) ) )
link_unref ( link ) ;
hashmap_free ( m - > links ) ;
2013-10-17 05:18:36 +04:00
2015-02-03 17:44:50 +03:00
while ( ( network = m - > networks ) )
network_free ( network ) ;
2015-02-08 15:29:35 +03:00
hashmap_free ( m - > networks_by_name ) ;
2015-02-03 17:44:50 +03:00
while ( ( netdev = hashmap_first ( m - > netdevs ) ) )
netdev_unref ( netdev ) ;
hashmap_free ( m - > netdevs ) ;
while ( ( pool = m - > address_pools ) )
address_pool_free ( pool ) ;
2015-06-12 17:31:33 +03:00
sd_netlink_unref ( m - > rtnl ) ;
2015-08-27 18:38:05 +03:00
sd_event_unref ( m - > event ) ;
2015-02-03 17:44:50 +03:00
free ( m ) ;
}
2015-02-04 17:00:20 +03:00
static bool manager_check_idle ( void * userdata ) {
Manager * m = userdata ;
Link * link ;
Iterator i ;
assert ( m ) ;
HASHMAP_FOREACH ( link , m - > links , i ) {
/* we are not woken on udev activity, so let's just wait for the
* pending udev event */
if ( link - > state = = LINK_STATE_PENDING )
return false ;
if ( ! link - > network )
continue ;
/* we are not woken on netork activity, so let's stay around */
if ( link_lldp_enabled ( link ) | |
link_ipv4ll_enabled ( link ) | |
link_dhcp4_server_enabled ( link ) | |
link_dhcp4_enabled ( link ) | |
link_dhcp6_enabled ( link ) )
return false ;
}
return true ;
}
int manager_run ( Manager * m ) {
assert ( m ) ;
2015-02-11 14:57:58 +03:00
if ( m - > bus )
return bus_event_loop_with_idle (
m - > event ,
m - > bus ,
" org.freedesktop.network1 " ,
DEFAULT_EXIT_USEC ,
manager_check_idle ,
m ) ;
else
/* failed to connect to the bus, so we lose exit-on-idle logic,
this should not happen except if dbus is not around at all */
return sd_event_loop ( m - > event ) ;
2015-02-04 17:00:20 +03:00
}
2015-02-03 17:44:50 +03:00
int manager_load_config ( Manager * m ) {
int r ;
/* update timestamp */
paths_check_timestamp ( network_dirs , & m - > network_dirs_ts_usec , true ) ;
r = netdev_load ( m ) ;
2013-10-17 05:18:36 +04:00
if ( r < 0 )
return r ;
2015-02-03 17:44:50 +03:00
r = network_load ( m ) ;
2014-08-28 17:46:29 +04:00
if ( r < 0 )
return r ;
2013-10-17 05:18:36 +04:00
return 0 ;
}
2013-11-14 19:22:51 +04:00
2015-02-03 17:44:50 +03:00
bool manager_should_reload ( Manager * m ) {
return paths_check_timestamp ( network_dirs , & m - > network_dirs_ts_usec , false ) ;
}
int manager_rtnl_enumerate_links ( Manager * m ) {
2015-06-12 17:31:33 +03:00
_cleanup_netlink_message_unref_ sd_netlink_message * req = NULL , * reply = NULL ;
sd_netlink_message * link ;
2013-11-14 19:22:51 +04:00
int r ;
2014-07-01 12:09:52 +04:00
assert ( m ) ;
2015-02-03 17:44:50 +03:00
assert ( m - > rtnl ) ;
2014-07-01 12:09:52 +04:00
2015-02-03 17:44:50 +03:00
r = sd_rtnl_message_new_link ( m - > rtnl , & req , RTM_GETLINK , 0 ) ;
2013-11-14 19:22:51 +04:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
r = sd_netlink_message_request_dump ( req , true ) ;
2013-12-03 21:48:20 +04:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
r = sd_netlink_call ( m - > rtnl , req , 0 , & reply ) ;
2014-05-08 20:55:11 +04:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
for ( link = reply ; link ; link = sd_netlink_message_next ( link ) ) {
2015-02-03 17:44:50 +03:00
int k ;
2014-05-10 21:39:03 +04:00
2015-02-04 12:08:12 +03:00
m - > enumerating = true ;
2015-02-03 17:44:50 +03:00
k = manager_rtnl_process_link ( m - > rtnl , link , m ) ;
if ( k < 0 )
r = k ;
2015-02-04 12:08:12 +03:00
m - > enumerating = false ;
2015-02-03 17:44:50 +03:00
}
2014-05-10 21:39:03 +04:00
2015-02-03 17:44:50 +03:00
return r ;
2013-11-14 19:22:51 +04:00
}
2014-01-06 02:01:10 +04:00
2015-02-03 17:44:50 +03:00
int manager_rtnl_enumerate_addresses ( Manager * m ) {
2015-06-12 17:31:33 +03:00
_cleanup_netlink_message_unref_ sd_netlink_message * req = NULL , * reply = NULL ;
sd_netlink_message * addr ;
2014-01-14 02:48:28 +04:00
int r ;
2015-02-03 17:44:50 +03:00
assert ( m ) ;
assert ( m - > rtnl ) ;
2014-01-18 04:37:35 +04:00
2015-02-03 17:44:50 +03:00
r = sd_rtnl_message_new_addr ( m - > rtnl , & req , RTM_GETADDR , 0 , 0 ) ;
if ( r < 0 )
return r ;
2014-01-18 04:37:35 +04:00
2015-06-12 17:31:33 +03:00
r = sd_netlink_message_request_dump ( req , true ) ;
2014-01-14 02:48:28 +04:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
r = sd_netlink_call ( m - > rtnl , req , 0 , & reply ) ;
2015-02-03 17:44:50 +03:00
if ( r < 0 )
return r ;
2015-06-12 17:31:33 +03:00
for ( addr = reply ; addr ; addr = sd_netlink_message_next ( addr ) ) {
2015-02-03 17:44:50 +03:00
int k ;
2015-02-04 12:08:12 +03:00
m - > enumerating = true ;
2015-02-03 17:44:50 +03:00
k = link_rtnl_process_address ( m - > rtnl , addr , m ) ;
if ( k < 0 )
r = k ;
2015-02-04 12:08:12 +03:00
m - > enumerating = false ;
2015-02-03 17:44:50 +03:00
}
return r ;
2014-01-14 02:48:28 +04:00
}
2014-08-12 15:01:58 +04:00
static int set_put_in_addr ( Set * s , const struct in_addr * address ) {
char * p ;
int r ;
assert ( s ) ;
r = in_addr_to_string ( AF_INET , ( const union in_addr_union * ) address , & p ) ;
if ( r < 0 )
return r ;
r = set_consume ( s , p ) ;
if ( r = = - EEXIST )
return 0 ;
return r ;
}
static int set_put_in_addrv ( Set * s , const struct in_addr * addresses , int n ) {
int r , i , c = 0 ;
assert ( s ) ;
assert ( n < = 0 | | addresses ) ;
for ( i = 0 ; i < n ; i + + ) {
r = set_put_in_addr ( s , addresses + i ) ;
if ( r < 0 )
return r ;
c + = r ;
}
return c ;
}
2014-08-15 18:02:14 +04:00
static void print_string_set ( FILE * f , const char * field , Set * s ) {
bool space = false ;
Iterator i ;
char * p ;
if ( set_isempty ( s ) )
return ;
fputs ( field , f ) ;
SET_FOREACH ( p , s , i ) {
if ( space )
fputc ( ' ' , f ) ;
fputs ( p , f ) ;
space = true ;
}
fputc ( ' \n ' , f ) ;
}
2014-05-08 19:21:37 +04:00
int manager_save ( Manager * m ) {
2014-08-15 18:02:14 +04:00
_cleanup_set_free_free_ Set * dns = NULL , * ntp = NULL , * domains = NULL ;
2014-05-08 19:21:37 +04:00
Link * link ;
Iterator i ;
_cleanup_free_ char * temp_path = NULL ;
_cleanup_fclose_ FILE * f = NULL ;
2014-08-14 00:44:35 +04:00
LinkOperationalState operstate = LINK_OPERSTATE_OFF ;
2014-05-19 22:44:21 +04:00
const char * operstate_str ;
2014-05-08 19:21:37 +04:00
int r ;
assert ( m ) ;
assert ( m - > state_file ) ;
2014-08-12 15:01:58 +04:00
/* We add all NTP and DNS server to a set, to filter out duplicates */
2014-08-13 03:00:18 +04:00
dns = set_new ( & string_hash_ops ) ;
2014-08-12 15:01:58 +04:00
if ( ! dns )
return - ENOMEM ;
2014-08-13 03:00:18 +04:00
ntp = set_new ( & string_hash_ops ) ;
2014-08-12 15:01:58 +04:00
if ( ! ntp )
return - ENOMEM ;
2014-08-13 03:00:18 +04:00
domains = set_new ( & string_hash_ops ) ;
2014-08-15 18:02:14 +04:00
if ( ! domains )
return - ENOMEM ;
2014-05-08 19:21:37 +04:00
HASHMAP_FOREACH ( link , m - > links , i ) {
if ( link - > flags & IFF_LOOPBACK )
continue ;
2014-05-19 22:44:21 +04:00
if ( link - > operstate > operstate )
operstate = link - > operstate ;
2014-08-12 15:01:58 +04:00
if ( ! link - > network )
continue ;
/* First add the static configured entries */
r = set_put_strdupv ( dns , link - > network - > dns ) ;
if ( r < 0 )
return r ;
r = set_put_strdupv ( ntp , link - > network - > ntp ) ;
if ( r < 0 )
return r ;
2014-08-15 18:02:14 +04:00
r = set_put_strdupv ( domains , link - > network - > domains ) ;
if ( r < 0 )
return r ;
2014-08-12 15:01:58 +04:00
if ( ! link - > dhcp_lease )
continue ;
/* Secondly, add the entries acquired via DHCP */
if ( link - > network - > dhcp_dns ) {
const struct in_addr * addresses ;
r = sd_dhcp_lease_get_dns ( link - > dhcp_lease , & addresses ) ;
if ( r > 0 ) {
r = set_put_in_addrv ( dns , addresses , r ) ;
if ( r < 0 )
return r ;
2015-09-04 22:16:35 +03:00
} else if ( r < 0 & & r ! = - ENODATA )
2014-08-12 15:01:58 +04:00
return r ;
}
if ( link - > network - > dhcp_ntp ) {
const struct in_addr * addresses ;
r = sd_dhcp_lease_get_ntp ( link - > dhcp_lease , & addresses ) ;
if ( r > 0 ) {
r = set_put_in_addrv ( ntp , addresses , r ) ;
if ( r < 0 )
return r ;
2015-09-04 22:16:35 +03:00
} else if ( r < 0 & & r ! = - ENODATA )
2014-08-15 18:02:14 +04:00
return r ;
}
if ( link - > network - > dhcp_domains ) {
const char * domainname ;
r = sd_dhcp_lease_get_domainname ( link - > dhcp_lease , & domainname ) ;
if ( r > = 0 ) {
r = set_put_strdup ( domains , domainname ) ;
if ( r < 0 )
return r ;
2015-09-04 22:16:35 +03:00
} else if ( r ! = - ENODATA )
2014-08-12 15:01:58 +04:00
return r ;
}
2014-05-08 19:21:37 +04:00
}
2014-05-19 22:44:21 +04:00
operstate_str = link_operstate_to_string ( operstate ) ;
assert ( operstate_str ) ;
2014-05-08 19:21:37 +04:00
r = fopen_temporary ( m - > state_file , & f , & temp_path ) ;
if ( r < 0 )
2014-08-12 13:55:06 +04:00
return r ;
2014-05-08 19:21:37 +04:00
fchmod ( fileno ( f ) , 0644 ) ;
fprintf ( f ,
" # This is private data. Do not parse. \n "
2014-05-19 22:44:21 +04:00
" OPER_STATE=%s \n " , operstate_str ) ;
2014-05-08 19:21:37 +04:00
2014-08-15 18:02:14 +04:00
print_string_set ( f , " DNS= " , dns ) ;
print_string_set ( f , " NTP= " , ntp ) ;
print_string_set ( f , " DOMAINS= " , domains ) ;
2014-08-12 15:01:58 +04:00
2014-08-12 13:55:06 +04:00
r = fflush_and_check ( f ) ;
if ( r < 0 )
goto fail ;
2014-05-08 19:21:37 +04:00
2014-08-12 13:55:06 +04:00
if ( rename ( temp_path , m - > state_file ) < 0 ) {
2014-05-08 19:21:37 +04:00
r = - errno ;
2014-08-12 13:55:06 +04:00
goto fail ;
2014-05-08 19:21:37 +04:00
}
2015-02-04 13:44:37 +03:00
if ( m - > operational_state ! = operstate ) {
m - > operational_state = operstate ;
r = manager_send_changed ( m , " OperationalState " , NULL ) ;
if ( r < 0 )
log_error_errno ( r , " Could not emit changed OperationalState: %m " ) ;
}
2014-08-12 13:55:06 +04:00
return 0 ;
2014-05-08 19:21:37 +04:00
2014-08-12 13:55:06 +04:00
fail :
2015-07-29 21:31:07 +03:00
( void ) unlink ( m - > state_file ) ;
( void ) unlink ( temp_path ) ;
return log_error_errno ( r , " Failed to save network state to %s: %m " , m - > state_file ) ;
2014-05-08 19:21:37 +04:00
}
2014-06-18 20:22:14 +04:00
2014-07-18 18:09:30 +04:00
int manager_address_pool_acquire ( Manager * m , int family , unsigned prefixlen , union in_addr_union * found ) {
2014-06-18 20:22:14 +04:00
AddressPool * p ;
int r ;
assert ( m ) ;
assert ( prefixlen > 0 ) ;
assert ( found ) ;
LIST_FOREACH ( address_pools , p , m - > address_pools ) {
if ( p - > family ! = family )
continue ;
r = address_pool_acquire ( p , prefixlen , found ) ;
if ( r ! = 0 )
return r ;
}
return 0 ;
}
2015-08-27 17:45:24 +03:00
Link * manager_find_uplink ( Manager * m , Link * exclude ) {
_cleanup_free_ struct local_address * gateways = NULL ;
int n , i ;
assert ( m ) ;
/* Looks for a suitable "uplink", via black magic: an
* interface that is up and where the default route with the
* highest priority points to . */
n = local_gateways ( m - > rtnl , 0 , AF_UNSPEC , & gateways ) ;
if ( n < 0 ) {
log_warning_errno ( n , " Failed to determine list of default gateways: %m " ) ;
return NULL ;
}
for ( i = 0 ; i < n ; i + + ) {
Link * link ;
link = hashmap_get ( m - > links , INT_TO_PTR ( gateways [ i ] . ifindex ) ) ;
if ( ! link ) {
2015-08-27 21:23:17 +03:00
log_debug ( " Weird, found a gateway for a link we don't know. Ignoring. " ) ;
2015-08-27 17:45:24 +03:00
continue ;
}
if ( link = = exclude )
continue ;
if ( link - > operstate < LINK_OPERSTATE_ROUTABLE )
continue ;
return link ;
}
return NULL ;
}