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