LCOV - code coverage report
Current view: top level - network - networkd-manager.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 192 488 39.3 %
Date: 2015-07-29 18:47:03 Functions: 14 27 51.9 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Tom Gundersen <teg@jklm.no>
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             :  ***/
      21             : 
      22             : #include <sys/socket.h>
      23             : #include <linux/if.h>
      24             : 
      25             : #include "conf-parser.h"
      26             : #include "path-util.h"
      27             : #include "networkd.h"
      28             : #include "networkd-netdev.h"
      29             : #include "networkd-link.h"
      30             : #include "libudev-private.h"
      31             : #include "udev-util.h"
      32             : #include "netlink-util.h"
      33             : #include "bus-util.h"
      34             : #include "def.h"
      35             : #include "virt.h"
      36             : 
      37             : #include "sd-netlink.h"
      38             : #include "sd-daemon.h"
      39             : 
      40             : /* use 8 MB for receive socket kernel queue. */
      41             : #define RCVBUF_SIZE    (8*1024*1024)
      42             : 
      43             : const char* const network_dirs[] = {
      44             :         "/etc/systemd/network",
      45             :         "/run/systemd/network",
      46             :         "/usr/lib/systemd/network",
      47             : #ifdef HAVE_SPLIT_USR
      48             :         "/lib/systemd/network",
      49             : #endif
      50             :         NULL};
      51             : 
      52           1 : static int setup_default_address_pool(Manager *m) {
      53             :         AddressPool *p;
      54             :         int r;
      55             : 
      56           1 :         assert(m);
      57             : 
      58             :         /* Add in the well-known private address ranges. */
      59             : 
      60           1 :         r = address_pool_new_from_string(m, &p, AF_INET6, "fc00::", 7);
      61           1 :         if (r < 0)
      62           0 :                 return r;
      63             : 
      64           1 :         r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
      65           1 :         if (r < 0)
      66           0 :                 return r;
      67             : 
      68           1 :         r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
      69           1 :         if (r < 0)
      70           0 :                 return r;
      71             : 
      72           1 :         r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
      73           1 :         if (r < 0)
      74           0 :                 return r;
      75             : 
      76           1 :         return 0;
      77             : }
      78             : 
      79           0 : static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
      80           0 :         Manager *m = userdata;
      81             : 
      82           0 :         assert(s);
      83           0 :         assert(m);
      84             : 
      85           0 :         m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
      86             : 
      87           0 :         manager_connect_bus(m);
      88             : 
      89           0 :         return 0;
      90             : }
      91             : 
      92           0 : static int manager_reset_all(Manager *m) {
      93             :         Link *link;
      94             :         Iterator i;
      95             :         int r;
      96             : 
      97           0 :         assert(m);
      98             : 
      99           0 :         HASHMAP_FOREACH(link, m->links, i) {
     100           0 :                 r = link_carrier_reset(link);
     101           0 :                 if (r < 0)
     102           0 :                         log_link_warning_errno(link, r, "could not reset carrier: %m");
     103             :         }
     104             : 
     105           0 :         return 0;
     106             : }
     107             : 
     108           0 : static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
     109           0 :         Manager *m = userdata;
     110             :         int b, r;
     111             : 
     112           0 :         assert(message);
     113             : 
     114           0 :         r = sd_bus_message_read(message, "b", &b);
     115           0 :         if (r < 0) {
     116           0 :                 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
     117           0 :                 return 0;
     118             :         }
     119             : 
     120           0 :         if (b)
     121           0 :                 return 0;
     122             : 
     123           0 :         log_debug("Coming back from suspend, resetting all connections...");
     124             : 
     125           0 :         manager_reset_all(m);
     126             : 
     127           0 :         return 0;
     128             : }
     129             : 
     130           0 : int manager_connect_bus(Manager *m) {
     131             :         int r;
     132             : 
     133           0 :         assert(m);
     134             : 
     135           0 :         r = sd_bus_default_system(&m->bus);
     136           0 :         if (r == -ENOENT) {
     137             :                 /* We failed to connect? Yuck, we must be in early
     138             :                  * boot. Let's try in 5s again. As soon as we have
     139             :                  * kdbus we can stop doing this... */
     140             : 
     141           0 :                 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
     142             : 
     143           0 :                 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);
     144           0 :                 if (r < 0)
     145           0 :                         return log_error_errno(r, "Failed to install bus reconnect time event: %m");
     146             : 
     147           0 :                 return 0;
     148           0 :         } if (r < 0)
     149           0 :                 return r;
     150             : 
     151           0 :         r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
     152             :                              "type='signal',"
     153             :                              "sender='org.freedesktop.login1',"
     154             :                              "interface='org.freedesktop.login1.Manager',"
     155             :                              "member='PrepareForSleep',"
     156             :                              "path='/org/freedesktop/login1'",
     157             :                              match_prepare_for_sleep,
     158             :                              m);
     159           0 :         if (r < 0)
     160           0 :                 return log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
     161             : 
     162           0 :         r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
     163           0 :         if (r < 0)
     164           0 :                 return log_error_errno(r, "Failed to add manager object vtable: %m");
     165             : 
     166           0 :         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m);
     167           0 :         if (r < 0)
     168           0 :                return log_error_errno(r, "Failed to add link object vtable: %m");
     169             : 
     170           0 :         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
     171           0 :         if (r < 0)
     172           0 :                 return log_error_errno(r, "Failed to add link enumerator: %m");
     173             : 
     174           0 :         r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m);
     175           0 :         if (r < 0)
     176           0 :                return log_error_errno(r, "Failed to add network object vtable: %m");
     177             : 
     178           0 :         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m);
     179           0 :         if (r < 0)
     180           0 :                 return log_error_errno(r, "Failed to add network enumerator: %m");
     181             : 
     182           0 :         r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
     183           0 :         if (r < 0)
     184           0 :                 return log_error_errno(r, "Failed to register name: %m");
     185             : 
     186           0 :         r = sd_bus_attach_event(m->bus, m->event, 0);
     187           0 :         if (r < 0)
     188           0 :                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
     189             : 
     190           0 :         return 0;
     191             : }
     192             : 
     193           0 : static int manager_udev_process_link(Manager *m, struct udev_device *device) {
     194           0 :         Link *link = NULL;
     195             :         int r, ifindex;
     196             : 
     197           0 :         assert(m);
     198           0 :         assert(device);
     199             : 
     200           0 :         if (!streq_ptr(udev_device_get_action(device), "add"))
     201           0 :                 return 0;
     202             : 
     203           0 :         ifindex = udev_device_get_ifindex(device);
     204           0 :         if (ifindex <= 0) {
     205           0 :                 log_debug("ignoring udev ADD event for device with invalid ifindex");
     206           0 :                 return 0;
     207             :         }
     208             : 
     209           0 :         r = link_get(m, ifindex, &link);
     210           0 :         if (r == -ENODEV)
     211           0 :                 return 0;
     212           0 :         else if (r < 0)
     213           0 :                 return r;
     214             : 
     215           0 :         r = link_initialized(link, device);
     216           0 :         if (r < 0)
     217           0 :                 return r;
     218             : 
     219           0 :         return 0;
     220             : }
     221             : 
     222           0 : static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
     223           0 :         Manager *m = userdata;
     224           0 :         struct udev_monitor *monitor = m->udev_monitor;
     225           0 :         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
     226             : 
     227           0 :         device = udev_monitor_receive_device(monitor);
     228           0 :         if (!device)
     229           0 :                 return -ENOMEM;
     230             : 
     231           0 :         manager_udev_process_link(m, device);
     232           0 :         return 0;
     233             : }
     234             : 
     235           1 : static int manager_connect_udev(Manager *m) {
     236             :         int r;
     237             : 
     238             :         /* udev does not initialize devices inside containers,
     239             :          * so we rely on them being already initialized before
     240             :          * entering the container */
     241           1 :         if (detect_container(NULL) > 0)
     242           0 :                 return 0;
     243             : 
     244           1 :         m->udev = udev_new();
     245           1 :         if (!m->udev)
     246           0 :                 return -ENOMEM;
     247             : 
     248           1 :         m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
     249           1 :         if (!m->udev_monitor)
     250           0 :                 return -ENOMEM;
     251             : 
     252           1 :         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
     253           1 :         if (r < 0)
     254           0 :                 return log_error_errno(r, "Could not add udev monitor filter: %m");
     255             : 
     256           1 :         r = udev_monitor_enable_receiving(m->udev_monitor);
     257           1 :         if (r < 0) {
     258           0 :                 log_error("Could not enable udev monitor");
     259           0 :                 return r;
     260             :         }
     261             : 
     262           1 :         r = sd_event_add_io(m->event,
     263             :                         &m->udev_event_source,
     264             :                         udev_monitor_get_fd(m->udev_monitor),
     265             :                         EPOLLIN, manager_dispatch_link_udev,
     266             :                         m);
     267           1 :         if (r < 0)
     268           0 :                 return r;
     269             : 
     270           1 :         r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
     271           1 :         if (r < 0)
     272           0 :                 return r;
     273             : 
     274           1 :         return 0;
     275             : }
     276             : 
     277           4 : static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
     278           4 :         Manager *m = userdata;
     279           4 :         Link *link = NULL;
     280           4 :         NetDev *netdev = NULL;
     281             :         uint16_t type;
     282             :         const char *name;
     283             :         int r, ifindex;
     284             : 
     285           4 :         assert(rtnl);
     286           4 :         assert(message);
     287           4 :         assert(m);
     288             : 
     289           4 :         if (sd_netlink_message_is_error(message)) {
     290           0 :                 r = sd_netlink_message_get_errno(message);
     291           0 :                 if (r < 0)
     292           0 :                         log_warning_errno(r, "rtnl: could not receive link: %m");
     293             : 
     294           0 :                 return 0;
     295             :         }
     296             : 
     297           4 :         r = sd_netlink_message_get_type(message, &type);
     298           4 :         if (r < 0) {
     299           0 :                 log_warning_errno(r, "rtnl: could not get message type: %m");
     300           0 :                 return 0;
     301           4 :         } else if (type != RTM_NEWLINK && type != RTM_DELLINK) {
     302           0 :                 log_warning("rtnl: received unexpected message type when processing link");
     303           0 :                 return 0;
     304             :         }
     305             : 
     306           4 :         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
     307           4 :         if (r < 0) {
     308           0 :                 log_warning_errno(r, "rtnl: could not get ifindex from link: %m");
     309           0 :                 return 0;
     310           4 :         } else if (ifindex <= 0) {
     311           0 :                 log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
     312           0 :                 return 0;
     313             :         } else
     314           4 :                 link_get(m, ifindex, &link);
     315             : 
     316           4 :         r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
     317           4 :         if (r < 0) {
     318           0 :                 log_warning_errno(r, "rtnl: received link message without ifname: %m");
     319           0 :                 return 0;
     320             :         } else
     321           4 :                 netdev_get(m, name, &netdev);
     322             : 
     323           4 :         switch (type) {
     324             :         case RTM_NEWLINK:
     325           4 :                 if (!link) {
     326             :                         /* link is new, so add it */
     327           4 :                         r = link_add(m, message, &link);
     328           4 :                         if (r < 0) {
     329           0 :                                 log_warning_errno(r, "could not add new link: %m");
     330           0 :                                 return 0;
     331             :                         }
     332             :                 }
     333             : 
     334           4 :                 if (netdev) {
     335             :                         /* netdev exists, so make sure the ifindex matches */
     336           0 :                         r = netdev_set_ifindex(netdev, message);
     337           0 :                         if (r < 0) {
     338           0 :                                 log_warning_errno(r, "could not set ifindex on netdev: %m");
     339           0 :                                 return 0;
     340             :                         }
     341             :                 }
     342             : 
     343           4 :                 r = link_update(link, message);
     344           4 :                 if (r < 0)
     345           0 :                         return 0;
     346             : 
     347           4 :                 break;
     348             : 
     349             :         case RTM_DELLINK:
     350           0 :                 link_drop(link);
     351           0 :                 netdev_drop(netdev);
     352             : 
     353           0 :                 break;
     354             : 
     355             :         default:
     356           0 :                 assert_not_reached("Received invalid RTNL message type.");
     357             :         }
     358             : 
     359           4 :         return 1;
     360             : }
     361             : 
     362           1 : static int systemd_netlink_fd(void) {
     363           1 :         int n, fd, rtnl_fd = -EINVAL;
     364             : 
     365           1 :         n = sd_listen_fds(true);
     366           1 :         if (n <= 0)
     367           1 :                 return -EINVAL;
     368             : 
     369           0 :         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
     370           0 :                 if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
     371           0 :                         if (rtnl_fd >= 0)
     372           0 :                                 return -EINVAL;
     373             : 
     374           0 :                         rtnl_fd = fd;
     375             :                 }
     376             :         }
     377             : 
     378           0 :         return rtnl_fd;
     379             : }
     380             : 
     381           1 : static int manager_connect_rtnl(Manager *m) {
     382             :         int fd, r;
     383             : 
     384           1 :         assert(m);
     385             : 
     386           1 :         fd = systemd_netlink_fd();
     387           1 :         if (fd < 0)
     388           1 :                 r = sd_netlink_open(&m->rtnl);
     389             :         else
     390           0 :                 r = sd_netlink_open_fd(&m->rtnl, fd);
     391           1 :         if (r < 0)
     392           0 :                 return r;
     393             : 
     394           1 :         r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
     395           1 :         if (r < 0)
     396           0 :                 return r;
     397             : 
     398           1 :         r = sd_netlink_attach_event(m->rtnl, m->event, 0);
     399           1 :         if (r < 0)
     400           0 :                 return r;
     401             : 
     402           1 :         r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
     403           1 :         if (r < 0)
     404           0 :                 return r;
     405             : 
     406           1 :         r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
     407           1 :         if (r < 0)
     408           0 :                 return r;
     409             : 
     410           1 :         r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
     411           1 :         if (r < 0)
     412           0 :                 return r;
     413             : 
     414           1 :         r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
     415           1 :         if (r < 0)
     416           0 :                 return r;
     417             : 
     418           1 :         return 0;
     419             : }
     420             : 
     421           1 : int manager_new(Manager **ret) {
     422           2 :         _cleanup_manager_free_ Manager *m = NULL;
     423             :         int r;
     424             : 
     425           1 :         m = new0(Manager, 1);
     426           1 :         if (!m)
     427           0 :                 return -ENOMEM;
     428             : 
     429           1 :         m->state_file = strdup("/run/systemd/netif/state");
     430           1 :         if (!m->state_file)
     431           0 :                 return -ENOMEM;
     432             : 
     433           1 :         r = sd_event_default(&m->event);
     434           1 :         if (r < 0)
     435           0 :                 return r;
     436             : 
     437           1 :         sd_event_set_watchdog(m->event, true);
     438             : 
     439           1 :         sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
     440           1 :         sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
     441             : 
     442           1 :         r = manager_connect_rtnl(m);
     443           1 :         if (r < 0)
     444           0 :                 return r;
     445             : 
     446           1 :         r = manager_connect_udev(m);
     447           1 :         if (r < 0)
     448           0 :                 return r;
     449             : 
     450           1 :         m->netdevs = hashmap_new(&string_hash_ops);
     451           1 :         if (!m->netdevs)
     452           0 :                 return -ENOMEM;
     453             : 
     454           1 :         LIST_HEAD_INIT(m->networks);
     455             : 
     456           1 :         r = setup_default_address_pool(m);
     457           1 :         if (r < 0)
     458           0 :                 return r;
     459             : 
     460           1 :         *ret = m;
     461           1 :         m = NULL;
     462             : 
     463           1 :         return 0;
     464             : }
     465             : 
     466           1 : void manager_free(Manager *m) {
     467             :         Network *network;
     468             :         NetDev *netdev;
     469             :         Link *link;
     470             :         AddressPool *pool;
     471             : 
     472           1 :         if (!m)
     473           0 :                 return;
     474             : 
     475           1 :         free(m->state_file);
     476             : 
     477           1 :         udev_monitor_unref(m->udev_monitor);
     478           1 :         udev_unref(m->udev);
     479           1 :         sd_bus_unref(m->bus);
     480           1 :         sd_bus_slot_unref(m->prepare_for_sleep_slot);
     481           1 :         sd_event_source_unref(m->udev_event_source);
     482           1 :         sd_event_source_unref(m->bus_retry_event_source);
     483           1 :         sd_event_unref(m->event);
     484             : 
     485          10 :         while ((link = hashmap_first(m->links)))
     486           8 :                 link_unref(link);
     487           1 :         hashmap_free(m->links);
     488             : 
     489           5 :         while ((network = m->networks))
     490           3 :                 network_free(network);
     491             : 
     492           1 :         hashmap_free(m->networks_by_name);
     493             : 
     494           2 :         while ((netdev = hashmap_first(m->netdevs)))
     495           0 :                 netdev_unref(netdev);
     496           1 :         hashmap_free(m->netdevs);
     497             : 
     498           6 :         while ((pool = m->address_pools))
     499           4 :                 address_pool_free(pool);
     500             : 
     501           1 :         sd_netlink_unref(m->rtnl);
     502             : 
     503           1 :         free(m);
     504             : }
     505             : 
     506           0 : static bool manager_check_idle(void *userdata) {
     507           0 :         Manager *m = userdata;
     508             :         Link *link;
     509             :         Iterator i;
     510             : 
     511           0 :         assert(m);
     512             : 
     513           0 :         HASHMAP_FOREACH(link, m->links, i) {
     514             :                 /* we are not woken on udev activity, so let's just wait for the
     515             :                  * pending udev event */
     516           0 :                 if (link->state == LINK_STATE_PENDING)
     517           0 :                         return false;
     518             : 
     519           0 :                 if (!link->network)
     520           0 :                         continue;
     521             : 
     522             :                 /* we are not woken on netork activity, so let's stay around */
     523           0 :                 if (link_lldp_enabled(link) ||
     524           0 :                     link_ipv4ll_enabled(link) ||
     525           0 :                     link_dhcp4_server_enabled(link) ||
     526           0 :                     link_dhcp4_enabled(link) ||
     527           0 :                     link_dhcp6_enabled(link))
     528           0 :                         return false;
     529             :         }
     530             : 
     531           0 :         return true;
     532             : }
     533             : 
     534           0 : int manager_run(Manager *m) {
     535           0 :         assert(m);
     536             : 
     537           0 :         if (m->bus)
     538           0 :                 return bus_event_loop_with_idle(
     539             :                                 m->event,
     540             :                                 m->bus,
     541             :                                 "org.freedesktop.network1",
     542             :                                 DEFAULT_EXIT_USEC,
     543             :                                 manager_check_idle,
     544             :                                 m);
     545             :         else
     546             :                 /* failed to connect to the bus, so we lose exit-on-idle logic,
     547             :                    this should not happen except if dbus is not around at all */
     548           0 :                 return sd_event_loop(m->event);
     549             : }
     550             : 
     551           1 : int manager_load_config(Manager *m) {
     552             :         int r;
     553             : 
     554             :         /* update timestamp */
     555           1 :         paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
     556             : 
     557           1 :         r = netdev_load(m);
     558           1 :         if (r < 0)
     559           0 :                 return r;
     560             : 
     561           1 :         r = network_load(m);
     562           1 :         if (r < 0)
     563           0 :                 return r;
     564             : 
     565           1 :         return 0;
     566             : }
     567             : 
     568           1 : bool manager_should_reload(Manager *m) {
     569           1 :         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
     570             : }
     571             : 
     572           1 : int manager_rtnl_enumerate_links(Manager *m) {
     573           2 :         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
     574             :         sd_netlink_message *link;
     575             :         int r;
     576             : 
     577           1 :         assert(m);
     578           1 :         assert(m->rtnl);
     579             : 
     580           1 :         r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
     581           1 :         if (r < 0)
     582           0 :                 return r;
     583             : 
     584           1 :         r = sd_netlink_message_request_dump(req, true);
     585           1 :         if (r < 0)
     586           0 :                 return r;
     587             : 
     588           1 :         r = sd_netlink_call(m->rtnl, req, 0, &reply);
     589           1 :         if (r < 0)
     590           0 :                 return r;
     591             : 
     592           5 :         for (link = reply; link; link = sd_netlink_message_next(link)) {
     593             :                 int k;
     594             : 
     595           4 :                 m->enumerating = true;
     596             : 
     597           4 :                 k = manager_rtnl_process_link(m->rtnl, link, m);
     598           4 :                 if (k < 0)
     599           0 :                         r = k;
     600             : 
     601           4 :                 m->enumerating = false;
     602             :         }
     603             : 
     604           1 :         return r;
     605             : }
     606             : 
     607           0 : int manager_rtnl_enumerate_addresses(Manager *m) {
     608           0 :         _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
     609             :         sd_netlink_message *addr;
     610             :         int r;
     611             : 
     612           0 :         assert(m);
     613           0 :         assert(m->rtnl);
     614             : 
     615           0 :         r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
     616           0 :         if (r < 0)
     617           0 :                 return r;
     618             : 
     619           0 :         r = sd_netlink_message_request_dump(req, true);
     620           0 :         if (r < 0)
     621           0 :                 return r;
     622             : 
     623           0 :         r = sd_netlink_call(m->rtnl, req, 0, &reply);
     624           0 :         if (r < 0)
     625           0 :                 return r;
     626             : 
     627           0 :         for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
     628             :                 int k;
     629             : 
     630           0 :                 m->enumerating = true;
     631             : 
     632           0 :                 k = link_rtnl_process_address(m->rtnl, addr, m);
     633           0 :                 if (k < 0)
     634           0 :                         r = k;
     635             : 
     636           0 :                 m->enumerating = false;
     637             :         }
     638             : 
     639           0 :         return r;
     640             : }
     641             : 
     642           0 : static int set_put_in_addr(Set *s, const struct in_addr *address) {
     643             :         char *p;
     644             :         int r;
     645             : 
     646           0 :         assert(s);
     647             : 
     648           0 :         r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
     649           0 :         if (r < 0)
     650           0 :                 return r;
     651             : 
     652           0 :         r = set_consume(s, p);
     653           0 :         if (r == -EEXIST)
     654           0 :                 return 0;
     655             : 
     656           0 :         return r;
     657             : }
     658             : 
     659           0 : static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
     660           0 :         int r, i, c = 0;
     661             : 
     662           0 :         assert(s);
     663           0 :         assert(n <= 0 || addresses);
     664             : 
     665           0 :         for (i = 0; i < n; i++) {
     666           0 :                 r = set_put_in_addr(s, addresses+i);
     667           0 :                 if (r < 0)
     668           0 :                         return r;
     669             : 
     670           0 :                 c += r;
     671             :         }
     672             : 
     673           0 :         return c;
     674             : }
     675             : 
     676           0 : static void print_string_set(FILE *f, const char *field, Set *s) {
     677           0 :         bool space = false;
     678             :         Iterator i;
     679             :         char *p;
     680             : 
     681           0 :         if (set_isempty(s))
     682           0 :                 return;
     683             : 
     684           0 :         fputs(field, f);
     685             : 
     686           0 :         SET_FOREACH(p, s, i) {
     687           0 :                 if (space)
     688           0 :                         fputc(' ', f);
     689           0 :                 fputs(p, f);
     690           0 :                 space = true;
     691             :         }
     692           0 :         fputc('\n', f);
     693             : }
     694             : 
     695           4 : int manager_save(Manager *m) {
     696           8 :         _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
     697             :         Link *link;
     698             :         Iterator i;
     699           8 :         _cleanup_free_ char *temp_path = NULL;
     700           8 :         _cleanup_fclose_ FILE *f = NULL;
     701           4 :         LinkOperationalState operstate = LINK_OPERSTATE_OFF;
     702             :         const char *operstate_str;
     703             :         int r;
     704             : 
     705           4 :         assert(m);
     706           4 :         assert(m->state_file);
     707             : 
     708             :         /* We add all NTP and DNS server to a set, to filter out duplicates */
     709           4 :         dns = set_new(&string_hash_ops);
     710           4 :         if (!dns)
     711           0 :                 return -ENOMEM;
     712             : 
     713           4 :         ntp = set_new(&string_hash_ops);
     714           4 :         if (!ntp)
     715           0 :                 return -ENOMEM;
     716             : 
     717           4 :         domains = set_new(&string_hash_ops);
     718           4 :         if (!domains)
     719           0 :                 return -ENOMEM;
     720             : 
     721          18 :         HASHMAP_FOREACH(link, m->links, i) {
     722          10 :                 if (link->flags & IFF_LOOPBACK)
     723           1 :                         continue;
     724             : 
     725           9 :                 if (link->operstate > operstate)
     726           4 :                         operstate = link->operstate;
     727             : 
     728           9 :                 if (!link->network)
     729           9 :                         continue;
     730             : 
     731             :                 /* First add the static configured entries */
     732           0 :                 r = set_put_strdupv(dns, link->network->dns);
     733           0 :                 if (r < 0)
     734           0 :                         return r;
     735             : 
     736           0 :                 r = set_put_strdupv(ntp, link->network->ntp);
     737           0 :                 if (r < 0)
     738           0 :                         return r;
     739             : 
     740           0 :                 r = set_put_strdupv(domains, link->network->domains);
     741           0 :                 if (r < 0)
     742           0 :                         return r;
     743             : 
     744           0 :                 if (!link->dhcp_lease)
     745           0 :                         continue;
     746             : 
     747             :                 /* Secondly, add the entries acquired via DHCP */
     748           0 :                 if (link->network->dhcp_dns) {
     749             :                         const struct in_addr *addresses;
     750             : 
     751           0 :                         r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
     752           0 :                         if (r > 0) {
     753           0 :                                 r = set_put_in_addrv(dns, addresses, r);
     754           0 :                                 if (r < 0)
     755           0 :                                         return r;
     756           0 :                         } else if (r < 0 && r != -ENOENT)
     757           0 :                                 return r;
     758             :                 }
     759             : 
     760           0 :                 if (link->network->dhcp_ntp) {
     761             :                         const struct in_addr *addresses;
     762             : 
     763           0 :                         r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
     764           0 :                         if (r > 0) {
     765           0 :                                 r = set_put_in_addrv(ntp, addresses, r);
     766           0 :                                 if (r < 0)
     767           0 :                                         return r;
     768           0 :                         } else if (r < 0 && r != -ENOENT)
     769           0 :                                 return r;
     770             :                 }
     771             : 
     772           0 :                 if (link->network->dhcp_domains) {
     773             :                         const char *domainname;
     774             : 
     775           0 :                         r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
     776           0 :                         if (r >= 0) {
     777           0 :                                 r = set_put_strdup(domains, domainname);
     778           0 :                                 if (r < 0)
     779           0 :                                         return r;
     780           0 :                         } else if (r != -ENOENT)
     781           0 :                                 return r;
     782             :                 }
     783             :         }
     784             : 
     785           4 :         operstate_str = link_operstate_to_string(operstate);
     786           4 :         assert(operstate_str);
     787             : 
     788           4 :         r = fopen_temporary(m->state_file, &f, &temp_path);
     789           4 :         if (r < 0)
     790           4 :                 return r;
     791             : 
     792           0 :         fchmod(fileno(f), 0644);
     793             : 
     794           0 :         fprintf(f,
     795             :                 "# This is private data. Do not parse.\n"
     796             :                 "OPER_STATE=%s\n", operstate_str);
     797             : 
     798           0 :         print_string_set(f, "DNS=", dns);
     799           0 :         print_string_set(f, "NTP=", ntp);
     800           0 :         print_string_set(f, "DOMAINS=", domains);
     801             : 
     802           0 :         r = fflush_and_check(f);
     803           0 :         if (r < 0)
     804           0 :                 goto fail;
     805             : 
     806           0 :         if (rename(temp_path, m->state_file) < 0) {
     807           0 :                 r = -errno;
     808           0 :                 goto fail;
     809             :         }
     810             : 
     811           0 :         if (m->operational_state != operstate) {
     812           0 :                 m->operational_state = operstate;
     813           0 :                 r = manager_send_changed(m, "OperationalState", NULL);
     814           0 :                 if (r < 0)
     815           0 :                         log_error_errno(r, "Could not emit changed OperationalState: %m");
     816             :         }
     817             : 
     818           0 :         return 0;
     819             : 
     820             : fail:
     821           0 :         log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
     822           0 :         unlink(m->state_file);
     823           0 :         unlink(temp_path);
     824           0 :         return r;
     825             : }
     826             : 
     827           0 : int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
     828             :         AddressPool *p;
     829             :         int r;
     830             : 
     831           0 :         assert(m);
     832           0 :         assert(prefixlen > 0);
     833           0 :         assert(found);
     834             : 
     835           0 :         LIST_FOREACH(address_pools, p, m->address_pools) {
     836           0 :                 if (p->family != family)
     837           0 :                         continue;
     838             : 
     839           0 :                 r = address_pool_acquire(p, prefixlen, found);
     840           0 :                 if (r != 0)
     841           0 :                         return r;
     842             :         }
     843             : 
     844           0 :         return 0;
     845             : }
     846             : 
     847           6 : const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
     848           6 :         if (b == ADDRESS_FAMILY_YES ||
     849             :             b == ADDRESS_FAMILY_NO)
     850           2 :                 return yes_no(b == ADDRESS_FAMILY_YES);
     851             : 
     852           4 :         if (b == ADDRESS_FAMILY_IPV4)
     853           1 :                 return "ipv4";
     854           3 :         if (b == ADDRESS_FAMILY_IPV6)
     855           1 :                 return "ipv6";
     856             : 
     857           2 :         return NULL;
     858             : }
     859             : 
     860          10 : AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
     861             :         int r;
     862             : 
     863             :         /* Make this a true superset of a boolean */
     864             : 
     865          10 :         r = parse_boolean(s);
     866          10 :         if (r > 0)
     867           5 :                 return ADDRESS_FAMILY_YES;
     868           5 :         if (r == 0)
     869           1 :                 return ADDRESS_FAMILY_NO;
     870             : 
     871           4 :         if (streq(s, "ipv4"))
     872           1 :                 return ADDRESS_FAMILY_IPV4;
     873           3 :         if (streq(s, "ipv6"))
     874           1 :                 return ADDRESS_FAMILY_IPV6;
     875             : 
     876           2 :         return _ADDRESS_FAMILY_BOOLEAN_INVALID;
     877             : }
     878             : 
     879           2 : DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");

Generated by: LCOV version 1.11