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