chiark / gitweb /
dc2af9dd24e776f4f3156d9708e90cfe71271575
[elogind.git] / src / network / networkd-network.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 "net-util.h"
24 #include "path-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
27
28 static int network_load_one(Manager *manager, const char *filename) {
29         _cleanup_network_free_ Network *network = NULL;
30         _cleanup_fclose_ FILE *file = NULL;
31         int r;
32
33         file = fopen(filename, "re");
34         if (!file) {
35                 if (errno == ENOENT)
36                         return 0;
37                 else
38                         return errno;
39         }
40
41         network = new0(Network, 1);
42         if (!network)
43                 return log_oom();
44
45         network->manager = manager;
46
47         LIST_HEAD_INIT(network->addresses);
48         LIST_HEAD_INIT(network->routes);
49
50         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
51         if (!network->addresses_by_section)
52                 return log_oom();
53
54         network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
55         if (!network->routes_by_section)
56                 return log_oom();
57
58         network->filename = strdup(filename);
59         if (!network->filename)
60                 return log_oom();
61
62         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0", config_item_perf_lookup,
63                         (void*) network_gperf_lookup, false, false, network);
64         if (r < 0) {
65                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
66                 return r;
67         } else
68                 log_debug("Parsed configuration file %s", filename);
69
70         LIST_PREPEND(networks, manager->networks, network);
71         network = NULL;
72
73         return 0;
74 }
75
76 int network_load(Manager *manager) {
77         Network *network;
78         char **files, **f;
79         int r;
80
81         assert(manager);
82
83         while ((network = manager->networks))
84                 network_free(network);
85
86         /* update timestamp */
87         paths_check_timestamp(manager->network_dirs, &manager->network_dirs_ts_usec, true);
88
89         r = conf_files_list_strv(&files, ".network", NULL, (const char **)manager->network_dirs);
90         if (r < 0) {
91                 log_error("failed to enumerate network files: %s", strerror(-r));
92                 return r;
93         }
94
95         STRV_FOREACH_BACKWARDS(f, files) {
96                 r = network_load_one(manager, *f);
97                 if (r < 0)
98                         return r;
99         }
100
101         strv_free(files);
102
103         return 0;
104 }
105
106 bool network_should_reload(Manager *manager) {
107         return paths_check_timestamp(manager->network_dirs, &manager->network_dirs_ts_usec, false);
108 }
109
110 void network_free(Network *network) {
111         Route *route;
112         Address *address;
113
114         if (!network)
115                 return;
116
117         free(network->filename);
118
119         free(network->match_mac);
120         free(network->match_path);
121         free(network->match_driver);
122         free(network->match_type);
123         free(network->match_name);
124
125         free(network->description);
126
127         while ((route = network->routes))
128                 route_free(route);
129
130         while ((address = network->addresses))
131                 address_free(address);
132
133         hashmap_free(network->addresses_by_section);
134         hashmap_free(network->routes_by_section);
135
136         LIST_REMOVE(networks, network->manager->networks, network);
137
138         free(network);
139 }
140
141 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
142         Network *network;
143
144         assert(manager);
145         assert(device);
146         assert(ret);
147
148         if (network_should_reload(manager))
149                 network_load(manager);
150
151         LIST_FOREACH(networks, network, manager->networks) {
152                 if (net_match_config(network->match_mac, network->match_path,
153                                         network->match_driver, network->match_type,
154                                         network->match_name,
155                                         udev_device_get_sysattr_value(device, "address"),
156                                         udev_device_get_property_value(device, "ID_PATH"),
157                                         udev_device_get_driver(device),
158                                         udev_device_get_devtype(device),
159                                         udev_device_get_sysname(device))) {
160                         log_debug("Network file %s applies to link %s",
161                                         network->filename,
162                                         udev_device_get_sysname(device));
163                         *ret = network;
164                         return 0;
165                 }
166         }
167
168         *ret = NULL;
169
170         return -ENOENT;
171 }
172
173 int network_apply(Manager *manager, Network *network, Link *link) {
174         int r;
175
176         log_info("Network '%s' being applied to link '%u'",
177                         network->description, (unsigned) link->ifindex);
178
179         link->network = network;
180
181         r = link_configure(link);
182         if (r < 0)
183                 return r;
184
185         return 0;
186 }