]> git.proxmox.com Git - systemd.git/blame - src/network/networkd-fdb.c
Imported Upstream version 221
[systemd.git] / src / network / networkd-fdb.c
CommitLineData
e735f4d4
MP
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
e735f4d4
MP
22#include <net/if.h>
23#include <net/ethernet.h>
24
25#include "networkd.h"
e735f4d4 26#include "networkd-link.h"
e735f4d4
MP
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
86f210e9 83static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
e735f4d4
MP
84 Link *link = userdata;
85 int r;
86
87 assert(link);
88
86f210e9 89 r = sd_netlink_message_get_errno(m);
e735f4d4 90 if (r < 0 && r != -EEXIST)
e3bff60a 91 log_link_error_errno(link, r, "Could not add FDB entry: %m");
e735f4d4
MP
92
93 return 1;
94}
95
96/* send a request to the kernel to add a FDB entry in its static MAC table. */
97int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
86f210e9
MP
98 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
99 sd_netlink *rtnl;
e735f4d4
MP
100 int r;
101
102 assert(link);
103 assert(link->manager);
104 assert(fdb_entry);
105
106 rtnl = link->manager->rtnl;
107
108 /* create new RTM message */
109 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_NEWNEIGH, link->ifindex, PF_BRIDGE);
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
86f210e9 123 r = sd_netlink_message_append_ether_addr(req, NDA_LLADDR, fdb_entry->mac_addr);
e735f4d4
MP
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) {
86f210e9 129 r = sd_netlink_message_append_u16(req, NDA_VLAN, fdb_entry->vlan_id);
e735f4d4
MP
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. */
86f210e9 135 r = sd_netlink_call_async(rtnl, req, set_fdb_handler, link, 0, NULL);
e3bff60a
MP
136 if (r < 0)
137 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
e735f4d4
MP
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
e3bff60a
MP
151 if (fdb_entry->section)
152 hashmap_remove(fdb_entry->network->fdb_entries_by_section,
153 UINT_TO_PTR(fdb_entry->section));
e735f4d4
MP
154 }
155
156 free(fdb_entry->mac_addr);
157
158 free(fdb_entry);
159}
160
161/* parse the HW address from config files. */
e3bff60a
MP
162int 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
e735f4d4
MP
174 Network *network = userdata;
175 _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
176 int r;
177
178 assert(filename);
179 assert(section);
180 assert(lvalue);
181 assert(rvalue);
182 assert(data);
183
184 r = fdb_entry_new_static(network, section_line, &fdb_entry);
e3bff60a
MP
185 if (r < 0)
186 return log_oom();
e735f4d4
MP
187
188 /* read in the MAC address for the FDB table. */
189 r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
190 &fdb_entry->mac_addr->ether_addr_octet[0],
191 &fdb_entry->mac_addr->ether_addr_octet[1],
192 &fdb_entry->mac_addr->ether_addr_octet[2],
193 &fdb_entry->mac_addr->ether_addr_octet[3],
194 &fdb_entry->mac_addr->ether_addr_octet[4],
195 &fdb_entry->mac_addr->ether_addr_octet[5]);
196
e3bff60a
MP
197 if (ETHER_ADDR_LEN != r) {
198 log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not a valid MAC address, ignoring assignment: %s", rvalue);
e735f4d4
MP
199 return 0;
200 }
201
202 fdb_entry = NULL;
203
204 return 0;
205}
206
207/* parse the VLAN Id from config files. */
e3bff60a
MP
208int 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
e735f4d4
MP
220 Network *network = userdata;
221 _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
222 int r;
223
224 assert(filename);
225 assert(section);
226 assert(lvalue);
227 assert(rvalue);
228 assert(data);
229
230 r = fdb_entry_new_static(network, section_line, &fdb_entry);
e3bff60a
MP
231 if (r < 0)
232 return log_oom();
e735f4d4
MP
233
234 r = config_parse_unsigned(unit, filename, line, section,
235 section_line, lvalue, ltype,
236 rvalue, &fdb_entry->vlan_id, userdata);
e3bff60a 237 if (r < 0)
e735f4d4 238 return r;
e735f4d4
MP
239
240 fdb_entry = NULL;
241
242 return 0;
243}