]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-fdb.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-fdb.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b98b483b
AR
2/***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
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
b98b483b 21#include <net/ethernet.h>
cf0fbc49 22#include <net/if.h>
b98b483b 23
b5efdb8a 24#include "alloc-util.h"
b98b483b 25#include "conf-parser.h"
23f53b99 26#include "netdev/bridge.h"
fc2f9534 27#include "netlink-util.h"
fc2f9534 28#include "networkd-fdb.h"
23f53b99 29#include "networkd-manager.h"
b5efdb8a 30#include "util.h"
0e83e7a5 31#include "vlan-util.h"
b98b483b 32
8c34b963
LP
33#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
34
b98b483b 35/* create a new FDB entry or get an existing one. */
8c34b963
LP
36int fdb_entry_new_static(
37 Network *network,
a60a720c 38 unsigned section,
8c34b963
LP
39 FdbEntry **ret) {
40
b98b483b
AR
41 _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
42 struct ether_addr *mac_addr = NULL;
43
44 assert(network);
8c34b963 45 assert(ret);
b98b483b
AR
46
47 /* search entry in hashmap first. */
9ed794a3 48 if (section) {
b98b483b
AR
49 fdb_entry = hashmap_get(network->fdb_entries_by_section, UINT_TO_PTR(section));
50 if (fdb_entry) {
51 *ret = fdb_entry;
52 fdb_entry = NULL;
53
54 return 0;
55 }
56 }
57
8c34b963
LP
58 if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
59 return -E2BIG;
60
b98b483b
AR
61 /* allocate space for MAC address. */
62 mac_addr = new0(struct ether_addr, 1);
63 if (!mac_addr)
64 return -ENOMEM;
65
66 /* allocate space for and FDB entry. */
67 fdb_entry = new0(FdbEntry, 1);
b98b483b
AR
68 if (!fdb_entry) {
69 /* free previously allocated space for mac_addr. */
70 free(mac_addr);
71 return -ENOMEM;
72 }
73
74 /* init FDB structure. */
75 fdb_entry->network = network;
76 fdb_entry->mac_addr = mac_addr;
77
78 LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry);
8c34b963 79 network->n_static_fdb_entries++;
b98b483b
AR
80
81 if (section) {
82 fdb_entry->section = section;
83 hashmap_put(network->fdb_entries_by_section,
84 UINT_TO_PTR(fdb_entry->section), fdb_entry);
85 }
86
87 /* return allocated FDB structure. */
88 *ret = fdb_entry;
89 fdb_entry = NULL;
90
91 return 0;
92}
93
1c4baffc 94static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
ea6ec096 95 Link *link = userdata;
b98b483b
AR
96 int r;
97
ea6ec096 98 assert(link);
b98b483b 99
1c4baffc 100 r = sd_netlink_message_get_errno(m);
ea6ec096 101 if (r < 0 && r != -EEXIST)
6a7a4e4d 102 log_link_error_errno(link, r, "Could not add FDB entry: %m");
b98b483b
AR
103
104 return 1;
105}
106
107/* send a request to the kernel to add a FDB entry in its static MAC table. */
a60a720c 108int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
4afd3348 109 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
1c4baffc 110 sd_netlink *rtnl;
b98b483b 111 int r;
f6bb7ac5
TJ
112 uint8_t flags;
113 Bridge *bridge;
b98b483b 114
ea6ec096 115 assert(link);
f6bb7ac5 116 assert(link->network);
ea6ec096 117 assert(link->manager);
b98b483b 118 assert(fdb_entry);
ea6ec096
TG
119
120 rtnl = link->manager->rtnl;
f6bb7ac5 121 bridge = BRIDGE(link->network->bridge);
b98b483b
AR
122
123 /* create new RTM message */
ea6ec096 124 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, PF_BRIDGE);
b98b483b
AR
125 if (r < 0)
126 return rtnl_log_create_error(r);
127
f6bb7ac5
TJ
128 if (bridge)
129 flags = NTF_MASTER;
130 else
131 flags = NTF_SELF;
132
133 r = sd_rtnl_message_neigh_set_flags(req, flags);
b98b483b
AR
134 if (r < 0)
135 return rtnl_log_create_error(r);
136
137 /* only NUD_PERMANENT state supported. */
138 r = sd_rtnl_message_neigh_set_state(req, NUD_NOARP | NUD_PERMANENT);
139 if (r < 0)
140 return rtnl_log_create_error(r);
141
1c4baffc 142 r = sd_netlink_message_append_ether_addr(req, NDA_LLADDR, fdb_entry->mac_addr);
b98b483b
AR
143 if (r < 0)
144 return rtnl_log_create_error(r);
145
146 /* VLAN Id is optional. We'll add VLAN Id only if it's specified. */
147 if (0 != fdb_entry->vlan_id) {
1c4baffc 148 r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id);
b98b483b
AR
149 if (r < 0)
150 return rtnl_log_create_error(r);
151 }
152
153 /* send message to the kernel to update its internal static MAC table. */
1c4baffc 154 r = sd_netlink_call_async(rtnl, req, set_fdb_handler, link, 0, NULL);
6a7a4e4d
LP
155 if (r < 0)
156 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
b98b483b
AR
157
158 return 0;
159}
160
161/* remove and FDB entry. */
162void fdb_entry_free(FdbEntry *fdb_entry) {
9ed794a3 163 if (!fdb_entry)
b98b483b
AR
164 return;
165
9ed794a3 166 if (fdb_entry->network) {
8c34b963
LP
167 LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry);
168
169 assert(fdb_entry->network->n_static_fdb_entries > 0);
170 fdb_entry->network->n_static_fdb_entries--;
b98b483b 171
8519d8f5 172 if (fdb_entry->section)
8c34b963 173 hashmap_remove(fdb_entry->network->fdb_entries_by_section, UINT_TO_PTR(fdb_entry->section));
b98b483b
AR
174 }
175
176 free(fdb_entry->mac_addr);
177
178 free(fdb_entry);
179}
180
181/* parse the HW address from config files. */
8519d8f5
LP
182int config_parse_fdb_hwaddr(
183 const char *unit,
184 const char *filename,
185 unsigned line,
186 const char *section,
187 unsigned section_line,
188 const char *lvalue,
189 int ltype,
190 const char *rvalue,
191 void *data,
192 void *userdata) {
193
b98b483b
AR
194 Network *network = userdata;
195 _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
196 int r;
197
198 assert(filename);
199 assert(section);
200 assert(lvalue);
201 assert(rvalue);
202 assert(data);
203
204 r = fdb_entry_new_static(network, section_line, &fdb_entry);
6a7a4e4d
LP
205 if (r < 0)
206 return log_oom();
b98b483b
AR
207
208 /* read in the MAC address for the FDB table. */
209 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
210 &fdb_entry->mac_addr->ether_addr_octet[0],
211 &fdb_entry->mac_addr->ether_addr_octet[1],
212 &fdb_entry->mac_addr->ether_addr_octet[2],
213 &fdb_entry->mac_addr->ether_addr_octet[3],
214 &fdb_entry->mac_addr->ether_addr_octet[4],
215 &fdb_entry->mac_addr->ether_addr_octet[5]);
216
8519d8f5 217 if (ETHER_ADDR_LEN != r) {
12ca818f 218 log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
b98b483b
AR
219 return 0;
220 }
221
222 fdb_entry = NULL;
223
224 return 0;
225}
226
227/* parse the VLAN Id from config files. */
8519d8f5
LP
228int config_parse_fdb_vlan_id(
229 const char *unit,
230 const char *filename,
231 unsigned line,
232 const char *section,
233 unsigned section_line,
234 const char *lvalue,
235 int ltype,
236 const char *rvalue,
237 void *data,
238 void *userdata) {
239
b98b483b
AR
240 Network *network = userdata;
241 _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
242 int r;
243
244 assert(filename);
245 assert(section);
246 assert(lvalue);
247 assert(rvalue);
248 assert(data);
249
250 r = fdb_entry_new_static(network, section_line, &fdb_entry);
6a7a4e4d
LP
251 if (r < 0)
252 return log_oom();
b98b483b 253
0e83e7a5
TJ
254 r = config_parse_vlanid(unit, filename, line, section,
255 section_line, lvalue, ltype,
256 rvalue, &fdb_entry->vlan_id, userdata);
6a7a4e4d 257 if (r < 0)
b98b483b 258 return r;
b98b483b
AR
259
260 fdb_entry = NULL;
261
262 return 0;
263}