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