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/>.
* * */
# include "path-util.h"
# include "networkd.h"
# include "libudev-private.h"
2013-12-13 06:30:42 +04:00
# include "udev-util.h"
2013-10-17 05:18:36 +04:00
int manager_new ( Manager * * ret ) {
_cleanup_manager_free_ Manager * m = NULL ;
int r ;
m = new0 ( Manager , 1 ) ;
if ( ! m )
return - ENOMEM ;
2013-11-11 22:34:13 +04:00
r = sd_event_default ( & m - > event ) ;
2013-10-17 05:18:36 +04:00
if ( r < 0 )
return r ;
2013-12-11 21:14:52 +04:00
sd_event_set_watchdog ( m - > event , true ) ;
2013-12-03 21:48:20 +04:00
r = sd_rtnl_open ( RTMGRP_LINK | RTMGRP_IPV4_IFADDR , & m - > rtnl ) ;
2013-10-17 05:18:36 +04:00
if ( r < 0 )
return r ;
m - > udev = udev_new ( ) ;
if ( ! m - > udev )
return - ENOMEM ;
m - > udev_monitor = udev_monitor_new_from_netlink ( m - > udev , " udev " ) ;
if ( ! m - > udev_monitor )
return - ENOMEM ;
m - > links = hashmap_new ( uint64_hash_func , uint64_compare_func ) ;
if ( ! m - > links )
return - ENOMEM ;
2013-11-25 02:37:56 +04:00
m - > bridges = hashmap_new ( string_hash_func , string_compare_func ) ;
if ( ! m - > bridges )
return - ENOMEM ;
2013-10-17 05:18:36 +04:00
LIST_HEAD_INIT ( m - > networks ) ;
m - > network_dirs = strv_new ( " /etc/systemd/network/ " ,
" /run/systemd/network/ " ,
" /usr/lib/systemd/network " ,
# ifdef HAVE_SPLIT_USER
" /lib/systemd/network " ,
# endif
NULL ) ;
if ( ! m - > network_dirs )
return - ENOMEM ;
if ( ! path_strv_canonicalize_uniq ( m - > network_dirs ) )
return - ENOMEM ;
* ret = m ;
m = NULL ;
return 0 ;
}
void manager_free ( Manager * m ) {
2013-11-18 14:54:09 +04:00
Network * network ;
2013-11-25 02:37:56 +04:00
Bridge * bridge ;
2013-11-18 14:54:09 +04:00
Link * link ;
2013-10-17 05:18:36 +04:00
udev_monitor_unref ( m - > udev_monitor ) ;
udev_unref ( m - > udev ) ;
sd_event_source_unref ( m - > udev_event_source ) ;
sd_event_unref ( m - > event ) ;
2013-11-18 14:54:09 +04:00
while ( ( network = m - > networks ) )
network_free ( network ) ;
while ( ( link = hashmap_first ( m - > links ) ) )
link_free ( link ) ;
2013-10-17 05:18:36 +04:00
hashmap_free ( m - > links ) ;
2013-11-18 14:54:09 +04:00
2013-11-25 02:37:56 +04:00
while ( ( bridge = hashmap_first ( m - > bridges ) ) )
bridge_free ( bridge ) ;
hashmap_free ( m - > bridges ) ;
2013-10-17 05:18:36 +04:00
strv_free ( m - > network_dirs ) ;
sd_rtnl_unref ( m - > rtnl ) ;
free ( m ) ;
}
2013-11-25 02:37:56 +04:00
int manager_load_config ( Manager * m ) {
int r ;
/* update timestamp */
paths_check_timestamp ( m - > network_dirs , & m - > network_dirs_ts_usec , true ) ;
r = bridge_load ( m ) ;
if ( r < 0 )
return r ;
r = network_load ( m ) ;
if ( r < 0 )
return r ;
return 0 ;
}
bool manager_should_reload ( Manager * m ) {
return paths_check_timestamp ( m - > network_dirs , & m - > network_dirs_ts_usec , false ) ;
}
2013-10-17 05:18:36 +04:00
static int manager_process_link ( Manager * m , struct udev_device * device ) {
Link * link ;
int r ;
if ( streq_ptr ( udev_device_get_action ( device ) , " remove " ) ) {
uint64_t ifindex ;
2013-11-21 18:30:08 +04:00
log_debug ( " Link removed: %s " , udev_device_get_sysname ( device ) ) ;
2013-10-17 05:18:36 +04:00
ifindex = udev_device_get_ifindex ( device ) ;
link = hashmap_get ( m - > links , & ifindex ) ;
if ( ! link )
return 0 ;
link_free ( link ) ;
} else {
2013-11-21 18:30:08 +04:00
log_debug ( " New link: %s " , udev_device_get_sysname ( device ) ) ;
2013-10-17 05:18:36 +04:00
r = link_add ( m , device ) ;
if ( r < 0 ) {
log_error ( " Could not handle link %s: %s " ,
udev_device_get_sysname ( device ) ,
strerror ( - r ) ) ;
}
}
return 0 ;
}
int manager_udev_enumerate_links ( Manager * m ) {
2013-12-18 06:37:26 +04:00
_cleanup_udev_enumerate_unref_ struct udev_enumerate * e = NULL ;
2013-10-17 05:18:36 +04:00
struct udev_list_entry * item = NULL , * first = NULL ;
int r ;
assert ( m ) ;
e = udev_enumerate_new ( m - > udev ) ;
2013-12-18 06:37:26 +04:00
if ( ! e )
return - ENOMEM ;
2013-10-17 05:18:36 +04:00
r = udev_enumerate_add_match_subsystem ( e , " net " ) ;
if ( r < 0 )
2013-12-18 06:37:26 +04:00
return r ;
2013-10-17 05:18:36 +04:00
r = udev_enumerate_scan_devices ( e ) ;
if ( r < 0 )
2013-12-18 06:37:26 +04:00
return r ;
2013-10-17 05:18:36 +04:00
first = udev_enumerate_get_list_entry ( e ) ;
udev_list_entry_foreach ( item , first ) {
2013-12-18 06:37:26 +04:00
_cleanup_udev_device_unref_ struct udev_device * d = NULL ;
2013-10-17 05:18:36 +04:00
int k ;
d = udev_device_new_from_syspath ( m - > udev , udev_list_entry_get_name ( item ) ) ;
2013-12-18 06:37:26 +04:00
if ( ! d )
return - ENOMEM ;
2013-10-17 05:18:36 +04:00
2013-12-18 06:37:26 +04:00
if ( ! udev_device_get_is_initialized ( d ) )
continue ;
2013-10-17 05:18:36 +04:00
2013-12-18 06:37:26 +04:00
k = manager_process_link ( m , d ) ;
2013-10-17 05:18:36 +04:00
if ( k < 0 )
r = k ;
}
return r ;
}
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 ;
2013-12-13 06:30:42 +04:00
_cleanup_udev_device_unref_ struct udev_device * device = NULL ;
2013-10-17 05:18:36 +04:00
device = udev_monitor_receive_device ( monitor ) ;
if ( ! device )
return - ENOMEM ;
2013-12-13 06:30:42 +04:00
manager_process_link ( m , device ) ;
2013-10-17 05:18:36 +04:00
return 0 ;
}
int manager_udev_listen ( Manager * m ) {
int r ;
r = udev_monitor_filter_add_match_subsystem_devtype ( m - > udev_monitor , " net " , NULL ) ;
if ( r < 0 ) {
log_error ( " Could not add udev monitor filter: %s " , strerror ( - r ) ) ;
return r ;
}
r = udev_monitor_enable_receiving ( m - > udev_monitor ) ;
if ( r < 0 ) {
log_error ( " Could not enable udev monitor " ) ;
return r ;
}
r = sd_event_add_io ( m - > event ,
udev_monitor_get_fd ( m - > udev_monitor ) ,
EPOLLIN , manager_dispatch_link_udev ,
m , & m - > udev_event_source ) ;
if ( r < 0 )
return r ;
return 0 ;
}
2013-11-14 19:22:51 +04:00
2013-12-03 21:48:20 +04:00
static int manager_rtnl_process_link ( sd_rtnl * rtnl , sd_rtnl_message * message , void * userdata ) {
Manager * m = userdata ;
Link * link ;
int r , ifindex ;
r = sd_rtnl_message_link_get_ifindex ( message , & ifindex ) ;
if ( r < 0 )
return 0 ;
link = hashmap_get ( m - > links , & ifindex ) ;
if ( ! link )
return 0 ;
2013-12-17 21:36:09 +04:00
r = link_update ( link , message ) ;
2013-12-03 21:48:20 +04:00
if ( r < 0 )
return 0 ;
return 1 ;
}
2013-11-14 19:22:51 +04:00
int manager_rtnl_listen ( Manager * m ) {
int r ;
r = sd_rtnl_attach_event ( m - > rtnl , m - > event , 0 ) ;
if ( r < 0 )
return r ;
2013-12-03 21:48:20 +04:00
r = sd_rtnl_add_match ( m - > rtnl , RTM_NEWLINK , & manager_rtnl_process_link , m ) ;
if ( r < 0 )
return r ;
2013-11-14 19:22:51 +04:00
return 0 ;
}