]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address-label.c
ed360b33914f2ad8a43fb1e1609b7ffe0e625e90
[thirdparty/systemd.git] / src / network / networkd-address-label.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2017 Susant Sahani
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <net/if.h>
22 #include <linux/if_addrlabel.h>
23
24 #include "alloc-util.h"
25 #include "conf-parser.h"
26 #include "networkd-address-label.h"
27 #include "netlink-util.h"
28 #include "networkd-manager.h"
29 #include "parse-util.h"
30 #include "socket-util.h"
31
32 int address_label_new(AddressLabel **ret) {
33 _cleanup_address_label_free_ AddressLabel *addrlabel = NULL;
34
35 addrlabel = new0(AddressLabel, 1);
36 if (!addrlabel)
37 return -ENOMEM;
38
39 *ret = TAKE_PTR(addrlabel);
40
41 return 0;
42 }
43
44 void address_label_free(AddressLabel *label) {
45 if (!label)
46 return;
47
48 if (label->network) {
49 LIST_REMOVE(labels, label->network->address_labels, label);
50 assert(label->network->n_address_labels > 0);
51 label->network->n_address_labels--;
52
53 if (label->section) {
54 hashmap_remove(label->network->address_labels_by_section, label->section);
55 network_config_section_free(label->section);
56 }
57 }
58
59 free(label);
60 }
61
62 static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
63 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
64 _cleanup_address_label_free_ AddressLabel *label = NULL;
65 int r;
66
67 assert(network);
68 assert(ret);
69 assert(!!filename == (section_line > 0));
70
71 r = network_config_section_new(filename, section_line, &n);
72 if (r < 0)
73 return r;
74
75 label = hashmap_get(network->address_labels_by_section, n);
76 if (label) {
77 *ret = TAKE_PTR(label);
78
79 return 0;
80 }
81
82 r = address_label_new(&label);
83 if (r < 0)
84 return r;
85
86 label->section = TAKE_PTR(n);
87
88 r = hashmap_put(network->address_labels_by_section, label->section, label);
89 if (r < 0)
90 return r;
91
92 label->network = network;
93 LIST_APPEND(labels, network->address_labels, label);
94 network->n_address_labels++;
95
96 *ret = TAKE_PTR(label);
97
98 return 0;
99 }
100
101 int address_label_configure(
102 AddressLabel *label,
103 Link *link,
104 sd_netlink_message_handler_t callback,
105 bool update) {
106
107 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
108 int r;
109
110 assert(label);
111 assert(link);
112 assert(link->ifindex > 0);
113 assert(link->manager);
114 assert(link->manager->rtnl);
115
116 r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
117 link->ifindex, AF_INET6);
118 if (r < 0)
119 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
120
121 r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen);
122 if (r < 0)
123 return log_error_errno(r, "Could not set prefixlen: %m");
124
125 r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label);
126 if (r < 0)
127 return log_error_errno(r, "Could not append IFAL_LABEL attribute: %m");
128
129 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6);
130 if (r < 0)
131 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
132
133 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
134 if (r < 0)
135 return log_error_errno(r, "Could not send rtnetlink message: %m");
136
137 link_ref(link);
138
139 return 0;
140 }
141
142 int config_parse_address_label_prefix(const char *unit,
143 const char *filename,
144 unsigned line,
145 const char *section,
146 unsigned section_line,
147 const char *lvalue,
148 int ltype,
149 const char *rvalue,
150 void *data,
151 void *userdata) {
152
153 _cleanup_address_label_free_ AddressLabel *n = NULL;
154 Network *network = userdata;
155 int r;
156
157 assert(filename);
158 assert(section);
159 assert(lvalue);
160 assert(rvalue);
161 assert(data);
162
163 r = address_label_new_static(network, filename, section_line, &n);
164 if (r < 0)
165 return r;
166
167 r = in_addr_prefix_from_string(rvalue, AF_INET6, &n->in_addr, &n->prefixlen);
168 if (r < 0) {
169 log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring assignment: %s", rvalue);
170 return 0;
171 }
172
173 n = NULL;
174
175 return 0;
176 }
177
178 int config_parse_address_label(
179 const char *unit,
180 const char *filename,
181 unsigned line,
182 const char *section,
183 unsigned section_line,
184 const char *lvalue,
185 int ltype,
186 const char *rvalue,
187 void *data,
188 void *userdata) {
189
190 _cleanup_address_label_free_ AddressLabel *n = NULL;
191 Network *network = userdata;
192 uint32_t k;
193 int r;
194
195 assert(filename);
196 assert(section);
197 assert(lvalue);
198 assert(rvalue);
199 assert(data);
200
201 r = address_label_new_static(network, filename, section_line, &n);
202 if (r < 0)
203 return r;
204
205 r = safe_atou32(rvalue, &k);
206 if (r < 0) {
207 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue);
208 return 0;
209 }
210
211 if (k == 0xffffffffUL) {
212 log_syntax(unit, LOG_ERR, filename, line, r, "Adress label is invalid, ignoring: %s", rvalue);
213 return 0;
214 }
215
216 n->label = k;
217 n = NULL;
218
219 return 0;
220 }