LCOV - code coverage report
Current view: top level - network/wait-online - manager.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 190 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 10 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 181 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <netinet/ether.h>
       4                 :            : #include <linux/if.h>
       5                 :            : #include <fnmatch.h>
       6                 :            : 
       7                 :            : #include "alloc-util.h"
       8                 :            : #include "link.h"
       9                 :            : #include "manager.h"
      10                 :            : #include "netlink-util.h"
      11                 :            : #include "network-internal.h"
      12                 :            : #include "strv.h"
      13                 :            : #include "time-util.h"
      14                 :            : #include "util.h"
      15                 :            : 
      16                 :          0 : static bool manager_ignore_link(Manager *m, Link *link) {
      17         [ #  # ]:          0 :         assert(m);
      18         [ #  # ]:          0 :         assert(link);
      19                 :            : 
      20                 :            :         /* always ignore the loopback interface */
      21         [ #  # ]:          0 :         if (link->flags & IFF_LOOPBACK)
      22                 :          0 :                 return true;
      23                 :            : 
      24                 :            :         /* if interfaces are given on the command line, ignore all others */
      25   [ #  #  #  # ]:          0 :         if (m->interfaces && !hashmap_contains(m->interfaces, link->ifname))
      26                 :          0 :                 return true;
      27                 :            : 
      28         [ #  # ]:          0 :         if (!link->required_for_online)
      29                 :          0 :                 return true;
      30                 :            : 
      31                 :            :         /* ignore interfaces we explicitly are asked to ignore */
      32                 :          0 :         return strv_fnmatch(m->ignore, link->ifname, 0);
      33                 :            : }
      34                 :            : 
      35                 :          0 : static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {
      36                 :            :         /* This returns the following:
      37                 :            :          * -EAGAIN: not processed by udev or networkd
      38                 :            :          *       0: operstate is not enough
      39                 :            :          *       1: online */
      40                 :            : 
      41         [ #  # ]:          0 :         if (!l->state)
      42   [ #  #  #  # ]:          0 :                 return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
      43                 :            :                                             "link has not yet been processed by udev");
      44                 :            : 
      45         [ #  # ]:          0 :         if (STR_IN_SET(l->state, "configuring", "pending"))
      46   [ #  #  #  # ]:          0 :                 return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
      47                 :            :                                             "link is being processed by networkd");
      48                 :            : 
      49         [ #  # ]:          0 :         if (s < 0)
      50         [ #  # ]:          0 :                 s = m->required_operstate >= 0 ? m->required_operstate : l->required_operstate;
      51                 :            : 
      52         [ #  # ]:          0 :         if (l->operational_state < s) {
      53   [ #  #  #  # ]:          0 :                 log_link_debug(l, "Operational state '%s' is below '%s'",
      54                 :            :                                link_operstate_to_string(l->operational_state),
      55                 :            :                                link_operstate_to_string(s));
      56                 :          0 :                 return 0;
      57                 :            :         }
      58                 :            : 
      59                 :          0 :         return 1;
      60                 :            : }
      61                 :            : 
      62                 :          0 : bool manager_configured(Manager *m) {
      63                 :          0 :         bool one_ready = false;
      64                 :            :         Iterator i;
      65                 :            :         const char *ifname;
      66                 :            :         void *p;
      67                 :            :         Link *l;
      68                 :            :         int r;
      69                 :            : 
      70         [ #  # ]:          0 :         if (!hashmap_isempty(m->interfaces)) {
      71                 :            :                 /* wait for all the links given on the command line to appear */
      72         [ #  # ]:          0 :                 HASHMAP_FOREACH_KEY(p, ifname, m->interfaces, i) {
      73                 :          0 :                         LinkOperationalState s = PTR_TO_INT(p);
      74                 :            : 
      75                 :          0 :                         l = hashmap_get(m->links_by_name, ifname);
      76         [ #  # ]:          0 :                         if (!l) {
      77         [ #  # ]:          0 :                                 log_debug("still waiting for %s", ifname);
      78         [ #  # ]:          0 :                                 if (!m->any)
      79                 :          0 :                                         return false;
      80                 :          0 :                                 continue;
      81                 :            :                         }
      82                 :            : 
      83         [ #  # ]:          0 :                         if (manager_link_is_online(m, l, s) <= 0) {
      84         [ #  # ]:          0 :                                 if (!m->any)
      85                 :          0 :                                         return false;
      86                 :          0 :                                 continue;
      87                 :            :                         }
      88                 :            : 
      89                 :          0 :                         one_ready = true;
      90                 :            :                 }
      91                 :            : 
      92                 :            :                 /* all interfaces given by the command line are online, or
      93                 :            :                  * one of the specified interfaces is online. */
      94                 :          0 :                 return one_ready;
      95                 :            :         }
      96                 :            : 
      97                 :            :         /* wait for all links networkd manages to be in admin state 'configured'
      98                 :            :          * and at least one link to gain a carrier */
      99         [ #  # ]:          0 :         HASHMAP_FOREACH(l, m->links, i) {
     100         [ #  # ]:          0 :                 if (manager_ignore_link(m, l)) {
     101   [ #  #  #  # ]:          0 :                         log_link_debug(l, "link is ignored");
     102                 :          0 :                         continue;
     103                 :            :                 }
     104                 :            : 
     105                 :          0 :                 r = manager_link_is_online(m, l, _LINK_OPERSTATE_INVALID);
     106   [ #  #  #  # ]:          0 :                 if (r < 0 && !m->any)
     107                 :          0 :                         return false;
     108         [ #  # ]:          0 :                 if (r > 0)
     109                 :            :                         /* we wait for at least one link to be ready,
     110                 :            :                          * regardless of who manages it */
     111                 :          0 :                         one_ready = true;
     112                 :            :         }
     113                 :            : 
     114                 :          0 :         return one_ready;
     115                 :            : }
     116                 :            : 
     117                 :          0 : static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
     118                 :          0 :         Manager *m = userdata;
     119                 :            :         uint16_t type;
     120                 :            :         Link *l;
     121                 :            :         const char *ifname;
     122                 :            :         int ifindex, r;
     123                 :            : 
     124         [ #  # ]:          0 :         assert(rtnl);
     125         [ #  # ]:          0 :         assert(m);
     126         [ #  # ]:          0 :         assert(mm);
     127                 :            : 
     128                 :          0 :         r = sd_netlink_message_get_type(mm, &type);
     129         [ #  # ]:          0 :         if (r < 0) {
     130         [ #  # ]:          0 :                 log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
     131                 :          0 :                 return 0;
     132                 :            :         }
     133                 :            : 
     134                 :          0 :         r = sd_rtnl_message_link_get_ifindex(mm, &ifindex);
     135         [ #  # ]:          0 :         if (r < 0) {
     136         [ #  # ]:          0 :                 log_warning_errno(r, "rtnl: Could not get ifindex from link, ignoring: %m");
     137                 :          0 :                 return 0;
     138         [ #  # ]:          0 :         } else if (ifindex <= 0) {
     139         [ #  # ]:          0 :                 log_warning("rtnl: received link message with invalid ifindex %d, ignoring", ifindex);
     140                 :          0 :                 return 0;
     141                 :            :         }
     142                 :            : 
     143                 :          0 :         r = sd_netlink_message_read_string(mm, IFLA_IFNAME, &ifname);
     144         [ #  # ]:          0 :         if (r < 0) {
     145         [ #  # ]:          0 :                 log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
     146                 :          0 :                 return 0;
     147                 :            :         }
     148                 :            : 
     149                 :          0 :         l = hashmap_get(m->links, INT_TO_PTR(ifindex));
     150                 :            : 
     151      [ #  #  # ]:          0 :         switch (type) {
     152                 :            : 
     153                 :          0 :         case RTM_NEWLINK:
     154         [ #  # ]:          0 :                 if (!l) {
     155         [ #  # ]:          0 :                         log_debug("Found link %i", ifindex);
     156                 :            : 
     157                 :          0 :                         r = link_new(m, &l, ifindex, ifname);
     158         [ #  # ]:          0 :                         if (r < 0)
     159         [ #  # ]:          0 :                                 return log_error_errno(r, "Failed to create link object: %m");
     160                 :            :                 }
     161                 :            : 
     162                 :          0 :                 r = link_update_rtnl(l, mm);
     163         [ #  # ]:          0 :                 if (r < 0)
     164   [ #  #  #  # ]:          0 :                         log_link_warning_errno(l, r, "Failed to process RTNL link message, ignoring: %m");
     165                 :            : 
     166                 :          0 :                 r = link_update_monitor(l);
     167   [ #  #  #  # ]:          0 :                 if (r < 0 && r != -ENODATA)
     168   [ #  #  #  # ]:          0 :                         log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
     169                 :            : 
     170                 :          0 :                 break;
     171                 :            : 
     172                 :          0 :         case RTM_DELLINK:
     173         [ #  # ]:          0 :                 if (l) {
     174   [ #  #  #  # ]:          0 :                         log_link_debug(l, "Removing link");
     175                 :          0 :                         link_free(l);
     176                 :            :                 }
     177                 :            : 
     178                 :          0 :                 break;
     179                 :            :         }
     180                 :            : 
     181                 :          0 :         return 0;
     182                 :            : }
     183                 :            : 
     184                 :          0 : static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdata) {
     185                 :          0 :         Manager *m = userdata;
     186                 :            :         int r;
     187                 :            : 
     188                 :          0 :         r = manager_process_link(rtnl, mm, m);
     189         [ #  # ]:          0 :         if (r < 0)
     190                 :          0 :                 return r;
     191                 :            : 
     192         [ #  # ]:          0 :         if (manager_configured(m))
     193                 :          0 :                 sd_event_exit(m->event, 0);
     194                 :            : 
     195                 :          0 :         return 1;
     196                 :            : }
     197                 :            : 
     198                 :          0 : static int manager_rtnl_listen(Manager *m) {
     199                 :          0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     200                 :            :         sd_netlink_message *i;
     201                 :            :         int r;
     202                 :            : 
     203         [ #  # ]:          0 :         assert(m);
     204                 :            : 
     205                 :            :         /* First, subscribe to interfaces coming and going */
     206                 :          0 :         r = sd_netlink_open(&m->rtnl);
     207         [ #  # ]:          0 :         if (r < 0)
     208                 :          0 :                 return r;
     209                 :            : 
     210                 :          0 :         r = sd_netlink_attach_event(m->rtnl, m->event, 0);
     211         [ #  # ]:          0 :         if (r < 0)
     212                 :          0 :                 return r;
     213                 :            : 
     214                 :          0 :         r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, on_rtnl_event, NULL, m, "wait-online-on-NEWLINK");
     215         [ #  # ]:          0 :         if (r < 0)
     216                 :          0 :                 return r;
     217                 :            : 
     218                 :          0 :         r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, on_rtnl_event, NULL, m, "wait-online-on-DELLINK");
     219         [ #  # ]:          0 :         if (r < 0)
     220                 :          0 :                 return r;
     221                 :            : 
     222                 :            :         /* Then, enumerate all links */
     223                 :          0 :         r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
     224         [ #  # ]:          0 :         if (r < 0)
     225                 :          0 :                 return r;
     226                 :            : 
     227                 :          0 :         r = sd_netlink_message_request_dump(req, true);
     228         [ #  # ]:          0 :         if (r < 0)
     229                 :          0 :                 return r;
     230                 :            : 
     231                 :          0 :         r = sd_netlink_call(m->rtnl, req, 0, &reply);
     232         [ #  # ]:          0 :         if (r < 0)
     233                 :          0 :                 return r;
     234                 :            : 
     235         [ #  # ]:          0 :         for (i = reply; i; i = sd_netlink_message_next(i)) {
     236                 :          0 :                 r = manager_process_link(m->rtnl, i, m);
     237         [ #  # ]:          0 :                 if (r < 0)
     238                 :          0 :                         return r;
     239                 :            :         }
     240                 :            : 
     241                 :          0 :         return r;
     242                 :            : }
     243                 :            : 
     244                 :          0 : static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     245                 :          0 :         Manager *m = userdata;
     246                 :            :         Iterator i;
     247                 :            :         Link *l;
     248                 :            :         int r;
     249                 :            : 
     250         [ #  # ]:          0 :         assert(m);
     251                 :            : 
     252                 :          0 :         sd_network_monitor_flush(m->network_monitor);
     253                 :            : 
     254         [ #  # ]:          0 :         HASHMAP_FOREACH(l, m->links, i) {
     255                 :          0 :                 r = link_update_monitor(l);
     256   [ #  #  #  # ]:          0 :                 if (r < 0 && r != -ENODATA)
     257   [ #  #  #  # ]:          0 :                         log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
     258                 :            :         }
     259                 :            : 
     260         [ #  # ]:          0 :         if (manager_configured(m))
     261                 :          0 :                 sd_event_exit(m->event, 0);
     262                 :            : 
     263                 :          0 :         return 0;
     264                 :            : }
     265                 :            : 
     266                 :          0 : static int manager_network_monitor_listen(Manager *m) {
     267                 :            :         int r, fd, events;
     268                 :            : 
     269         [ #  # ]:          0 :         assert(m);
     270                 :            : 
     271                 :          0 :         r = sd_network_monitor_new(&m->network_monitor, NULL);
     272         [ #  # ]:          0 :         if (r < 0)
     273                 :          0 :                 return r;
     274                 :            : 
     275                 :          0 :         fd = sd_network_monitor_get_fd(m->network_monitor);
     276         [ #  # ]:          0 :         if (fd < 0)
     277                 :          0 :                 return fd;
     278                 :            : 
     279                 :          0 :         events = sd_network_monitor_get_events(m->network_monitor);
     280         [ #  # ]:          0 :         if (events < 0)
     281                 :          0 :                 return events;
     282                 :            : 
     283                 :          0 :         r = sd_event_add_io(m->event, &m->network_monitor_event_source,
     284                 :            :                             fd, events, &on_network_event, m);
     285         [ #  # ]:          0 :         if (r < 0)
     286                 :          0 :                 return r;
     287                 :            : 
     288                 :          0 :         return 0;
     289                 :            : }
     290                 :            : 
     291                 :          0 : int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
     292                 :            :                 LinkOperationalState required_operstate,
     293                 :            :                 bool any, usec_t timeout) {
     294                 :          0 :         _cleanup_(manager_freep) Manager *m = NULL;
     295                 :            :         int r;
     296                 :            : 
     297         [ #  # ]:          0 :         assert(ret);
     298                 :            : 
     299                 :          0 :         m = new(Manager, 1);
     300         [ #  # ]:          0 :         if (!m)
     301                 :          0 :                 return -ENOMEM;
     302                 :            : 
     303                 :          0 :         *m = (Manager) {
     304                 :            :                 .interfaces = interfaces,
     305                 :            :                 .ignore = ignore,
     306                 :            :                 .required_operstate = required_operstate,
     307                 :            :                 .any = any,
     308                 :            :         };
     309                 :            : 
     310                 :          0 :         r = sd_event_default(&m->event);
     311         [ #  # ]:          0 :         if (r < 0)
     312                 :          0 :                 return r;
     313                 :            : 
     314                 :          0 :         (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL,  NULL);
     315                 :          0 :         (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
     316                 :            : 
     317         [ #  # ]:          0 :         if (timeout > 0) {
     318                 :            :                 usec_t usec;
     319                 :            : 
     320                 :          0 :                 usec = now(clock_boottime_or_monotonic()) + timeout;
     321                 :            : 
     322                 :          0 :                 r = sd_event_add_time(m->event, NULL, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
     323         [ #  # ]:          0 :                 if (r < 0)
     324                 :          0 :                         return r;
     325                 :            :         }
     326                 :            : 
     327                 :          0 :         sd_event_set_watchdog(m->event, true);
     328                 :            : 
     329                 :          0 :         r = manager_network_monitor_listen(m);
     330         [ #  # ]:          0 :         if (r < 0)
     331                 :          0 :                 return r;
     332                 :            : 
     333                 :          0 :         r = manager_rtnl_listen(m);
     334         [ #  # ]:          0 :         if (r < 0)
     335                 :          0 :                 return r;
     336                 :            : 
     337                 :          0 :         *ret = TAKE_PTR(m);
     338                 :            : 
     339                 :          0 :         return 0;
     340                 :            : }
     341                 :            : 
     342                 :          0 : void manager_free(Manager *m) {
     343         [ #  # ]:          0 :         if (!m)
     344                 :          0 :                 return;
     345                 :            : 
     346         [ #  # ]:          0 :         hashmap_free_with_destructor(m->links, link_free);
     347                 :          0 :         hashmap_free(m->links_by_name);
     348                 :            : 
     349                 :          0 :         sd_event_source_unref(m->network_monitor_event_source);
     350                 :          0 :         sd_network_monitor_unref(m->network_monitor);
     351                 :            : 
     352                 :          0 :         sd_event_source_unref(m->rtnl_event_source);
     353                 :          0 :         sd_netlink_unref(m->rtnl);
     354                 :            : 
     355                 :          0 :         sd_event_unref(m->event);
     356                 :          0 :         free(m);
     357                 :            : 
     358                 :          0 :         return;
     359                 :            : }

Generated by: LCOV version 1.14