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