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