1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
23 #include "network-internal.h"
24 #include "path-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
29 #define VLANID_MAX 4094
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",
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");
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",
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");
54 static void netdev_cancel_callbacks(NetDev
*netdev
) {
55 _cleanup_rtnl_message_unref_ sd_rtnl_message
*m
= NULL
;
56 netdev_enslave_callback
*callback
;
61 rtnl_message_new_synthetic_error(-ENODEV
, 0, &m
);
63 while ((callback
= netdev
->callbacks
)) {
65 assert(callback
->link
);
66 assert(callback
->callback
);
67 assert(netdev
->manager
);
68 assert(netdev
->manager
->rtnl
);
70 callback
->callback(netdev
->manager
->rtnl
, m
, link
);
73 LIST_REMOVE(callbacks
, netdev
->callbacks
, callback
);
78 static void netdev_free(NetDev
*netdev
) {
82 netdev_cancel_callbacks(netdev
);
85 hashmap_remove(netdev
->manager
->netdevs
, netdev
->ifname
);
87 free(netdev
->filename
);
89 free(netdev
->description
);
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
);
100 NetDev
*netdev_unref(NetDev
*netdev
) {
101 if (netdev
&& (-- netdev
->n_ref
<= 0))
107 NetDev
*netdev_ref(NetDev
*netdev
) {
109 assert_se(++ netdev
->n_ref
>= 2);
114 void netdev_drop(NetDev
*netdev
) {
115 if (!netdev
|| netdev
->state
== NETDEV_STATE_LINGER
)
118 netdev
->state
= NETDEV_STATE_LINGER
;
120 log_debug_netdev(netdev
, "netdev removed");
122 netdev_cancel_callbacks(netdev
);
124 netdev_unref(netdev
);
129 int netdev_get(Manager
*manager
, const char *name
, NetDev
**ret
) {
136 netdev
= hashmap_get(manager
->netdevs
, name
);
147 static int netdev_enter_failed(NetDev
*netdev
) {
148 netdev
->state
= NETDEV_STATE_FAILED
;
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
;
158 assert(netdev
->state
== NETDEV_STATE_READY
);
159 assert(netdev
->manager
);
160 assert(netdev
->manager
->rtnl
);
164 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &req
,
165 RTM_SETLINK
, link
->ifindex
);
167 log_error_netdev(netdev
,
168 "Could not allocate RTM_SETLINK message: %s",
173 r
= sd_rtnl_message_append_u32(req
, IFLA_MASTER
, netdev
->ifindex
);
175 log_error_netdev(netdev
,
176 "Could not append IFLA_MASTER attribute: %s",
181 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
183 log_error_netdev(netdev
,
184 "Could not send rtnetlink message: %s",
189 log_debug_netdev(netdev
, "enslaving link '%s'", link
->ifname
);
194 static int netdev_enter_ready(NetDev
*netdev
) {
195 netdev_enslave_callback
*callback
;
198 assert(netdev
->ifname
);
200 if (netdev
->state
!= NETDEV_STATE_CREATING
)
203 netdev
->state
= NETDEV_STATE_READY
;
205 log_info_netdev(netdev
, "netdev ready");
207 LIST_FOREACH(callbacks
, callback
, netdev
->callbacks
) {
208 /* enslave the links that were attempted to be enslaved before the
210 netdev_enslave_ready(netdev
, callback
->link
, callback
->callback
);
215 static int netdev_create_handler(sd_rtnl
*rtnl
, sd_rtnl_message
*m
, void *userdata
) {
216 NetDev
*netdev
= userdata
;
219 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
221 r
= sd_rtnl_message_get_errno(m
);
223 log_debug_netdev(netdev
, "netdev exists, using existing");
225 log_warning_netdev(netdev
, "netdev could not be greated: %s", strerror(-r
));
234 int config_parse_tunnel_address(const char *unit
,
235 const char *filename
,
238 unsigned section_line
,
245 unsigned char family
= AF_INET
;
253 r
= net_parse_inaddr(rvalue
, &family
, n
);
255 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
256 "Tunnel address is invalid, ignoring assignment: %s", rvalue
);
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
;
268 assert(!(netdev
->kind
== NETDEV_KIND_VLAN
|| netdev
->kind
== NETDEV_KIND_MACVLAN
) ||
270 assert(netdev
->ifname
);
271 assert(netdev
->manager
);
272 assert(netdev
->manager
->rtnl
);
274 r
= sd_rtnl_message_new_link(netdev
->manager
->rtnl
, &req
, RTM_NEWLINK
, 0);
276 log_error_netdev(netdev
,
277 "Could not allocate RTM_NEWLINK message: %s",
283 r
= sd_rtnl_message_append_u32(req
, IFLA_LINK
, link
->ifindex
);
285 log_error_netdev(netdev
,
286 "Could not append IFLA_LINK attribute: %s",
292 r
= sd_rtnl_message_append_string(req
, IFLA_IFNAME
, netdev
->ifname
);
294 log_error_netdev(netdev
,
295 "Could not append IFLA_IFNAME attribute: %s",
301 r
= sd_rtnl_message_append_u32(req
, IFLA_MTU
, netdev
->mtu
);
303 log_error_netdev(netdev
,
304 "Could not append IFLA_MTU attribute: %s",
310 r
= sd_rtnl_message_open_container(req
, IFLA_LINKINFO
);
312 log_error_netdev(netdev
,
313 "Could not open IFLA_LINKINFO container: %s",
318 kind
= netdev_kind_to_string(netdev
->kind
);
320 log_error_netdev(netdev
, "Invalid kind");
324 r
= sd_rtnl_message_open_container_union(req
, IFLA_INFO_DATA
, kind
);
326 log_error_netdev(netdev
,
327 "Could not open IFLA_INFO_DATA container: %s",
332 if (netdev
->vlanid
<= VLANID_MAX
) {
333 r
= sd_rtnl_message_append_u16(req
, IFLA_VLAN_ID
, netdev
->vlanid
);
335 log_error_netdev(netdev
,
336 "Could not append IFLA_VLAN_ID attribute: %s",
342 if (netdev
->macvlan_mode
!= _NETDEV_MACVLAN_MODE_INVALID
) {
343 r
= sd_rtnl_message_append_u32(req
, IFLA_MACVLAN_MODE
, netdev
->macvlan_mode
);
345 log_error_netdev(netdev
,
346 "Could not append IFLA_MACVLAN_MODE attribute: %s",
352 r
= sd_rtnl_message_close_container(req
);
354 log_error_netdev(netdev
,
355 "Could not close IFLA_INFO_DATA container %s",
360 r
= sd_rtnl_message_close_container(req
);
362 log_error_netdev(netdev
,
363 "Could not close IFLA_LINKINFO container %s",
369 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
371 r
= sd_rtnl_call_async(netdev
->manager
->rtnl
, req
, &netdev_create_handler
, netdev
, 0, NULL
);
373 log_error_netdev(netdev
,
374 "Could not send rtnetlink message: %s", strerror(-r
));
378 log_debug_netdev(netdev
, "creating netdev");
380 netdev
->state
= NETDEV_STATE_CREATING
;
385 int netdev_enslave(NetDev
*netdev
, Link
*link
, sd_rtnl_message_handler_t callback
) {
388 if (netdev
->kind
== NETDEV_KIND_VLAN
|| netdev
->kind
== NETDEV_KIND_MACVLAN
)
389 return netdev_create(netdev
, link
, callback
);
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
);
396 if (netdev
->state
== NETDEV_STATE_READY
) {
397 r
= netdev_enslave_ready(netdev
, link
, callback
);
401 /* the netdev is not yet read, save this request for when it is*/
402 netdev_enslave_callback
*cb
;
404 cb
= new0(netdev_enslave_callback
, 1);
408 cb
->callback
= callback
;
411 LIST_PREPEND(callbacks
, netdev
->callbacks
, cb
);
417 int netdev_set_ifindex(NetDev
*netdev
, sd_rtnl_message
*message
) {
427 r
= sd_rtnl_message_get_type(message
, &type
);
429 log_error_netdev(netdev
, "Could not get rtnl message type");
433 if (type
!= RTM_NEWLINK
) {
434 log_error_netdev(netdev
, "Can not set ifindex from unexpected rtnl message type");
438 r
= sd_rtnl_message_link_get_ifindex(message
, &ifindex
);
440 log_error_netdev(netdev
, "Could not get ifindex: %s", strerror(-r
));
441 netdev_enter_failed(netdev
);
443 } else if (ifindex
<= 0) {
444 log_error_netdev(netdev
, "Got invalid ifindex: %d", ifindex
);
445 netdev_enter_failed(netdev
);
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
);
457 /* ifindex already set to the same for this netdev */
461 r
= sd_rtnl_message_read_string(message
, IFLA_IFNAME
, &received_name
);
463 log_error_netdev(netdev
, "Could not get IFNAME");
467 if (!streq(netdev
->ifname
, received_name
)) {
468 log_error_netdev(netdev
, "Received newlink with wrong IFNAME %s",
470 netdev_enter_failed(netdev
);
474 r
= sd_rtnl_message_enter_container(message
, IFLA_LINKINFO
);
476 log_error_netdev(netdev
, "Could not get LINKINFO");
480 r
= sd_rtnl_message_read_string(message
, IFLA_INFO_KIND
, &received_kind
);
482 log_error_netdev(netdev
, "Could not get KIND");
486 r
= sd_rtnl_message_exit_container(message
);
488 log_error_netdev(netdev
, "Could not exit container");
492 kind
= netdev_kind_to_string(netdev
->kind
);
494 log_error_netdev(netdev
, "Could not get kind");
495 netdev_enter_failed(netdev
);
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
);
506 netdev
->ifindex
= ifindex
;
508 log_debug_netdev(netdev
, "netdev has index %d", netdev
->ifindex
);
510 netdev_enter_ready(netdev
);
515 static int netdev_load_one(Manager
*manager
, const char *filename
) {
516 _cleanup_netdev_unref_ NetDev
*netdev
= NULL
;
517 _cleanup_fclose_
FILE *file
= NULL
;
523 if (null_or_empty_path(filename
)) {
524 log_debug("skipping empty file: %s", filename
);
528 file
= fopen(filename
, "re");
536 netdev
= new0(NetDev
, 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;
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
);
551 log_warning("Could not parse config file %s: %s", filename
, strerror(-r
));
555 if (netdev
->kind
== _NETDEV_KIND_INVALID
) {
556 log_warning("NetDev without Kind configured in %s. Ignoring", filename
);
560 if (!netdev
->ifname
) {
561 log_warning("NetDev without Name configured in %s. Ignoring", filename
);
565 if (netdev
->kind
== NETDEV_KIND_VLAN
&& netdev
->vlanid
> VLANID_MAX
) {
566 log_warning("VLAN without valid Id configured in %s. Ignoring", filename
);
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
);
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
);
583 netdev
->filename
= strdup(filename
);
584 if (!netdev
->filename
)
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)
593 r
= hashmap_put(netdev
->manager
->netdevs
, netdev
->ifname
, netdev
);
597 LIST_HEAD_INIT(netdev
->callbacks
);
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
);
609 log_debug_netdev(netdev
, "loaded %s", netdev_kind_to_string(netdev
->kind
));
616 int netdev_load(Manager
*manager
) {
623 while ((netdev
= hashmap_first(manager
->netdevs
)))
624 netdev_unref(netdev
);
626 r
= conf_files_list_strv(&files
, ".netdev", NULL
, network_dirs
);
628 log_error("Failed to enumerate netdev files: %s", strerror(-r
));
632 STRV_FOREACH_BACKWARDS(f
, files
) {
633 r
= netdev_load_one(manager
, *f
);