chiark / gitweb /
networkd: logging - align messages
[elogind.git] / src / network / networkd-netdev.c
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 <net/if.h>
23
24 #include "networkd.h"
25 #include "network-internal.h"
26 #include "path-util.h"
27 #include "conf-files.h"
28 #include "conf-parser.h"
29 #include "list.h"
30
31 #define VLANID_MAX 4094
32
33 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
34         [NETDEV_KIND_BRIDGE] = "bridge",
35         [NETDEV_KIND_BOND] = "bond",
36         [NETDEV_KIND_VLAN] = "vlan",
37         [NETDEV_KIND_MACVLAN] = "macvlan",
38         [NETDEV_KIND_IPIP] = "ipip",
39         [NETDEV_KIND_GRE] = "gre",
40         [NETDEV_KIND_SIT] = "sit",
41 };
42
43 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
44 DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
45
46 static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
47         [NETDEV_MACVLAN_MODE_PRIVATE] = "private",
48         [NETDEV_MACVLAN_MODE_VEPA] = "vepa",
49         [NETDEV_MACVLAN_MODE_BRIDGE] = "bridge",
50         [NETDEV_MACVLAN_MODE_PASSTHRU] = "passthru",
51 };
52
53 DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
54 DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
55
56 static void netdev_cancel_callbacks(NetDev *netdev) {
57         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
58         netdev_enslave_callback *callback;
59
60         if (!netdev)
61                 return;
62
63         rtnl_message_new_synthetic_error(-ENODEV, 0, &m);
64
65         while ((callback = netdev->callbacks)) {
66                 if (m) {
67                         assert(callback->link);
68                         assert(callback->callback);
69                         assert(netdev->manager);
70                         assert(netdev->manager->rtnl);
71
72                         callback->callback(netdev->manager->rtnl, m, link);
73                 }
74
75                 LIST_REMOVE(callbacks, netdev->callbacks, callback);
76                 free(callback);
77         }
78 }
79
80 static void netdev_free(NetDev *netdev) {
81         if (!netdev)
82                 return;
83
84         netdev_cancel_callbacks(netdev);
85
86         if (netdev->ifname)
87                 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
88
89         free(netdev->filename);
90
91         free(netdev->description);
92         free(netdev->ifname);
93
94         condition_free_list(netdev->match_host);
95         condition_free_list(netdev->match_virt);
96         condition_free_list(netdev->match_kernel);
97         condition_free_list(netdev->match_arch);
98
99         free(netdev);
100 }
101
102 NetDev *netdev_unref(NetDev *netdev) {
103         if (netdev && (-- netdev->n_ref <= 0))
104                 netdev_free(netdev);
105
106         return NULL;
107 }
108
109 NetDev *netdev_ref(NetDev *netdev) {
110         if (netdev)
111                 assert_se(++ netdev->n_ref >= 2);
112
113         return netdev;
114 }
115
116 void netdev_drop(NetDev *netdev) {
117         if (!netdev || netdev->state == NETDEV_STATE_LINGER)
118                 return;
119
120         netdev->state = NETDEV_STATE_LINGER;
121
122         log_debug_netdev(netdev, "netdev removed");
123
124         netdev_cancel_callbacks(netdev);
125
126         netdev_unref(netdev);
127
128         return;
129 }
130
131 int netdev_get(Manager *manager, const char *name, NetDev **ret) {
132         NetDev *netdev;
133
134         assert(manager);
135         assert(name);
136         assert(ret);
137
138         netdev = hashmap_get(manager->netdevs, name);
139         if (!netdev) {
140                 *ret = NULL;
141                 return -ENOENT;
142         }
143
144         *ret = netdev;
145
146         return 0;
147 }
148
149 static int netdev_enter_failed(NetDev *netdev) {
150         netdev->state = NETDEV_STATE_FAILED;
151
152         return 0;
153 }
154
155 static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_rtnl_message_handler_t callback) {
156         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
157         int r;
158
159         assert(netdev);
160         assert(netdev->state == NETDEV_STATE_READY);
161         assert(netdev->manager);
162         assert(netdev->manager->rtnl);
163         assert(link);
164         assert(callback);
165
166         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req,
167                                      RTM_SETLINK, link->ifindex);
168         if (r < 0) {
169                 log_error_netdev(netdev,
170                                  "Could not allocate RTM_SETLINK message: %s",
171                                  strerror(-r));
172                 return r;
173         }
174
175         r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
176         if (r < 0) {
177                 log_error_netdev(netdev,
178                                  "Could not append IFLA_MASTER attribute: %s",
179                                  strerror(-r));
180                 return r;
181         }
182
183         r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
184         if (r < 0) {
185                 log_error_netdev(netdev,
186                                  "Could not send rtnetlink message: %s",
187                                  strerror(-r));
188                 return r;
189         }
190
191         log_debug_netdev(netdev, "enslaving link '%s'", link->ifname);
192
193         return 0;
194 }
195
196 static int netdev_enter_ready(NetDev *netdev) {
197         netdev_enslave_callback *callback;
198
199         assert(netdev);
200         assert(netdev->ifname);
201
202         if (netdev->state != NETDEV_STATE_CREATING)
203                 return 0;
204
205         netdev->state = NETDEV_STATE_READY;
206
207         log_info_netdev(netdev, "netdev ready");
208
209         LIST_FOREACH(callbacks, callback, netdev->callbacks) {
210                 /* enslave the links that were attempted to be enslaved before the
211                  * link was ready */
212                 netdev_enslave_ready(netdev, callback->link, callback->callback);
213         }
214
215         return 0;
216 }
217 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
218         NetDev *netdev = userdata;
219         int r;
220
221         assert(netdev->state != _NETDEV_STATE_INVALID);
222
223         r = sd_rtnl_message_get_errno(m);
224         if (r == -EEXIST)
225                 log_debug_netdev(netdev, "netdev exists, using existing");
226         else if (r < 0) {
227                 log_warning_netdev(netdev, "netdev could not be greated: %s", strerror(-r));
228                 netdev_drop(netdev);
229
230                 return 1;
231         }
232
233         return 1;
234 }
235
236 int config_parse_tunnel_address(const char *unit,
237                                 const char *filename,
238                                 unsigned line,
239                                 const char *section,
240                                 unsigned section_line,
241                                 const char *lvalue,
242                                 int ltype,
243                                 const char *rvalue,
244                                 void *data,
245                                 void *userdata) {
246         NetDev *n = data;
247         unsigned char family = AF_INET;
248         int r;
249
250         assert(filename);
251         assert(lvalue);
252         assert(rvalue);
253         assert(data);
254
255         r = net_parse_inaddr(rvalue, &family, n);
256         if (r < 0) {
257                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
258                            "Tunnel address is invalid, ignoring assignment: %s", rvalue);
259                 return 0;
260         }
261        return 0;
262 }
263
264 static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
265         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
266         const char *kind;
267         int r;
268
269         assert(netdev);
270         assert(!(netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN) ||
271                (link && callback));
272         assert(netdev->ifname);
273         assert(netdev->manager);
274         assert(netdev->manager->rtnl);
275
276         r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, 0);
277         if (r < 0) {
278                 log_error_netdev(netdev,
279                                  "Could not allocate RTM_NEWLINK message: %s",
280                                  strerror(-r));
281                 return r;
282         }
283
284         if (link) {
285                 r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
286                 if (r < 0) {
287                         log_error_netdev(netdev,
288                                          "Could not append IFLA_LINK attribute: %s",
289                                          strerror(-r));
290                         return r;
291                 }
292         }
293
294         r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->ifname);
295         if (r < 0) {
296                 log_error_netdev(netdev,
297                                  "Could not append IFLA_IFNAME attribute: %s",
298                                  strerror(-r));
299                 return r;
300         }
301
302         if(netdev->mtu) {
303                 r = sd_rtnl_message_append_u32(req, IFLA_MTU, netdev->mtu);
304                 if (r < 0) {
305                         log_error_netdev(netdev,
306                                          "Could not append IFLA_MTU attribute: %s",
307                                          strerror(-r));
308                         return r;
309                 }
310         }
311
312         r = sd_rtnl_message_open_container(req, IFLA_LINKINFO);
313         if (r < 0) {
314                 log_error_netdev(netdev,
315                                  "Could not open IFLA_LINKINFO container: %s",
316                                  strerror(-r));
317                 return r;
318         }
319
320         kind = netdev_kind_to_string(netdev->kind);
321         if (!kind) {
322                 log_error_netdev(netdev, "Invalid kind");
323                 return -EINVAL;
324         }
325
326         r = sd_rtnl_message_open_container_union(req, IFLA_INFO_DATA, kind);
327         if (r < 0) {
328                 log_error_netdev(netdev,
329                                  "Could not open IFLA_INFO_DATA container: %s",
330                                   strerror(-r));
331                 return r;
332         }
333
334         if (netdev->vlanid <= VLANID_MAX) {
335                 r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
336                 if (r < 0) {
337                         log_error_netdev(netdev,
338                                          "Could not append IFLA_VLAN_ID attribute: %s",
339                                          strerror(-r));
340                         return r;
341                 }
342         }
343
344         if (netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
345         r = sd_rtnl_message_append_u32(req, IFLA_MACVLAN_MODE, netdev->macvlan_mode);
346         if (r < 0) {
347                 log_error_netdev(netdev,
348                                  "Could not append IFLA_MACVLAN_MODE attribute: %s",
349                                  strerror(-r));
350                         return r;
351                 }
352         }
353
354         r = sd_rtnl_message_close_container(req);
355         if (r < 0) {
356                 log_error_netdev(netdev,
357                                  "Could not close IFLA_INFO_DATA container %s",
358                                  strerror(-r));
359                 return r;
360         }
361
362         r = sd_rtnl_message_close_container(req);
363         if (r < 0) {
364                 log_error_netdev(netdev,
365                                  "Could not close IFLA_LINKINFO container %s",
366                                  strerror(-r));
367                 return r;
368         }
369
370         if (link)
371                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
372         else
373                 r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
374         if (r < 0) {
375                 log_error_netdev(netdev,
376                                  "Could not send rtnetlink message: %s", strerror(-r));
377                 return r;
378         }
379
380         log_debug_netdev(netdev, "creating netdev");
381
382         netdev->state = NETDEV_STATE_CREATING;
383
384         return 0;
385 }
386
387 int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
388         int r;
389
390         if (netdev->kind == NETDEV_KIND_VLAN || netdev->kind == NETDEV_KIND_MACVLAN)
391                 return netdev_create(netdev, link, callback);
392
393         if(netdev->kind == NETDEV_KIND_IPIP ||
394            netdev->kind == NETDEV_KIND_GRE ||
395            netdev->kind ==  NETDEV_KIND_SIT)
396                 return netdev_create_tunnel(link, netdev_create_handler);
397
398         if (netdev->state == NETDEV_STATE_READY) {
399                 r = netdev_enslave_ready(netdev, link, callback);
400                 if (r < 0)
401                         return r;
402         } else {
403                 /* the netdev is not yet read, save this request for when it is*/
404                 netdev_enslave_callback *cb;
405
406                 cb = new0(netdev_enslave_callback, 1);
407                 if (!cb)
408                         return log_oom();
409
410                 cb->callback = callback;
411                 cb->link = link;
412
413                 LIST_PREPEND(callbacks, netdev->callbacks, cb);
414         }
415
416         return 0;
417 }
418
419 int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
420         uint16_t type;
421         const char *kind;
422         char *received_kind;
423         char *received_name;
424         int r, ifindex;
425
426         assert(netdev);
427         assert(message);
428
429         r = sd_rtnl_message_get_type(message, &type);
430         if (r < 0) {
431                 log_error_netdev(netdev, "Could not get rtnl message type");
432                 return r;
433         }
434
435         if (type != RTM_NEWLINK) {
436                 log_error_netdev(netdev, "Can not set ifindex from unexpected rtnl message type");
437                 return -EINVAL;
438         }
439
440         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
441         if (r < 0) {
442                 log_error_netdev(netdev, "Could not get ifindex: %s", strerror(-r));
443                 netdev_enter_failed(netdev);
444                 return r;
445         } else if (ifindex <= 0) {
446                 log_error_netdev(netdev, "Got invalid ifindex: %d", ifindex);
447                 netdev_enter_failed(netdev);
448                 return r;
449         }
450
451
452         if (netdev->ifindex > 0) {
453                 if (netdev->ifindex != ifindex) {
454                         log_error_netdev(netdev, "Could not set ifindex to %d, already set to %d",
455                                          ifindex, netdev->ifindex);
456                         netdev_enter_failed(netdev);
457                         return -EEXIST;
458                 } else
459                         /* ifindex already set to the same for this netdev */
460                         return 0;
461         }
462
463         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &received_name);
464         if (r < 0) {
465                 log_error_netdev(netdev, "Could not get IFNAME");
466                 return r;
467         }
468
469         if (!streq(netdev->ifname, received_name)) {
470                 log_error_netdev(netdev, "Received newlink with wrong IFNAME %s",
471                                  received_name);
472                 netdev_enter_failed(netdev);
473                 return r;
474         }
475
476         r = sd_rtnl_message_enter_container(message, IFLA_LINKINFO);
477         if (r < 0) {
478                 log_error_netdev(netdev, "Could not get LINKINFO");
479                 return r;
480         }
481
482         r = sd_rtnl_message_read_string(message, IFLA_INFO_KIND, &received_kind);
483         if (r < 0) {
484                 log_error_netdev(netdev, "Could not get KIND");
485                 return r;
486         }
487
488         r = sd_rtnl_message_exit_container(message);
489         if (r < 0) {
490                 log_error_netdev(netdev, "Could not exit container");
491                 return r;
492         }
493
494         kind = netdev_kind_to_string(netdev->kind);
495         if (!kind) {
496                 log_error_netdev(netdev, "Could not get kind");
497                 netdev_enter_failed(netdev);
498                 return -EINVAL;
499         }
500
501         if (!streq(kind, received_kind)) {
502                 log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
503                                  "expected %s", received_kind, kind);
504                 netdev_enter_failed(netdev);
505                 return r;
506         }
507
508         netdev->ifindex = ifindex;
509
510         log_debug_netdev(netdev, "netdev has index %d", netdev->ifindex);
511
512         netdev_enter_ready(netdev);
513
514         return 0;
515 }
516
517 static int netdev_load_one(Manager *manager, const char *filename) {
518         _cleanup_netdev_unref_ NetDev *netdev = NULL;
519         _cleanup_fclose_ FILE *file = NULL;
520         int r;
521
522         assert(manager);
523         assert(filename);
524
525         if (null_or_empty_path(filename)) {
526                 log_debug("skipping empty file: %s", filename);
527                 return 0;
528         }
529
530         file = fopen(filename, "re");
531         if (!file) {
532                 if (errno == ENOENT)
533                         return 0;
534                 else
535                         return -errno;
536         }
537
538         netdev = new0(NetDev, 1);
539         if (!netdev)
540                 return log_oom();
541
542         netdev->n_ref = 1;
543         netdev->manager = manager;
544         netdev->state = _NETDEV_STATE_INVALID;
545         netdev->kind = _NETDEV_KIND_INVALID;
546         netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
547         netdev->vlanid = VLANID_MAX + 1;
548
549         r = config_parse(NULL, filename, file, "Match\0NetDev\0VLAN\0MACVLAN\0Tunnel\0",
550                          config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
551                          false, false, netdev);
552         if (r < 0) {
553                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
554                 return r;
555         }
556
557         if (netdev->kind == _NETDEV_KIND_INVALID) {
558                 log_warning("NetDev without Kind configured in %s. Ignoring", filename);
559                 return 0;
560         }
561
562         if (!netdev->ifname) {
563                 log_warning("NetDev without Name configured in %s. Ignoring", filename);
564                 return 0;
565         }
566
567         if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
568                 log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
569                 return 0;
570         }
571
572         if (netdev->kind != NETDEV_KIND_VLAN && netdev->vlanid <= VLANID_MAX) {
573                 log_warning("VLAN Id configured for a %s in %s. Ignoring",
574                             netdev_kind_to_string(netdev->kind), filename);
575                 return 0;
576         }
577
578         if (netdev->kind != NETDEV_KIND_MACVLAN &&
579             netdev->macvlan_mode != _NETDEV_MACVLAN_MODE_INVALID) {
580                 log_warning("MACVLAN Mode configured for a %s in %s. Ignoring",
581                             netdev_kind_to_string(netdev->kind), filename);
582                 return 0;
583         }
584
585         netdev->filename = strdup(filename);
586         if (!netdev->filename)
587                 return log_oom();
588
589         if (net_match_config(NULL, NULL, NULL, NULL, NULL,
590                              netdev->match_host, netdev->match_virt,
591                              netdev->match_kernel, netdev->match_arch,
592                              NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
593                 return 0;
594
595         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
596         if (r < 0)
597                 return r;
598
599         LIST_HEAD_INIT(netdev->callbacks);
600
601         if (netdev->kind != NETDEV_KIND_VLAN &&
602             netdev->kind != NETDEV_KIND_MACVLAN &&
603             netdev->kind != NETDEV_KIND_IPIP &&
604             netdev->kind != NETDEV_KIND_GRE &&
605             netdev->kind != NETDEV_KIND_SIT) {
606                 r = netdev_create(netdev, NULL, NULL);
607                 if (r < 0)
608                         return r;
609         }
610
611         log_debug_netdev(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
612
613         netdev = NULL;
614
615         return 0;
616 }
617
618 int netdev_load(Manager *manager) {
619         NetDev *netdev;
620         char **files, **f;
621         int r;
622
623         assert(manager);
624
625         while ((netdev = hashmap_first(manager->netdevs)))
626                 netdev_unref(netdev);
627
628         r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs);
629         if (r < 0) {
630                 log_error("Failed to enumerate netdev files: %s", strerror(-r));
631                 return r;
632         }
633
634         STRV_FOREACH_BACKWARDS(f, files) {
635                 r = netdev_load_one(manager, *f);
636                 if (r < 0)
637                         return r;
638         }
639
640         strv_free(files);
641
642         return 0;
643 }