chiark / gitweb /
remove unused includes
[elogind.git] / src / network / networkd-fdb.c
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 int 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
83 static int set_fdb_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
84         Link *link = userdata;
85         int r;
86
87         assert(link);
88
89         r = sd_rtnl_message_get_errno(m);
90         if (r < 0 && r != -EEXIST)
91                 log_link_error(link, "Could not add FDB entry: %s", strerror(-r));
92
93         return 1;
94 }
95
96 /* send a request to the kernel to add a FDB entry in its static MAC table. */
97 int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
98         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
99         sd_rtnl *rtnl;
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
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. */
135         r = sd_rtnl_call_async(rtnl, req, set_fdb_handler, link, 0, NULL);
136         if (r < 0) {
137                 log_link_error(link, "Could not send rtnetlink message: %s", strerror(-r));
138                 return r;
139         }
140
141         return 0;
142 }
143
144 /* remove and FDB entry. */
145 void fdb_entry_free(FdbEntry *fdb_entry) {
146         if(!fdb_entry)
147                 return;
148
149         if(fdb_entry->network) {
150                 LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries,
151                             fdb_entry);
152
153                 if(fdb_entry->section)
154                     hashmap_remove(fdb_entry->network->fdb_entries_by_section,
155                                    UINT_TO_PTR(fdb_entry->section));
156         }
157
158         free(fdb_entry->mac_addr);
159
160         free(fdb_entry);
161 }
162
163 /* parse the HW address from config files. */
164 int config_parse_fdb_hwaddr(const char *unit,
165                             const char *filename,
166                             unsigned line,
167                             const char *section,
168                             unsigned section_line,
169                             const char *lvalue,
170                             int ltype,
171                             const char *rvalue,
172                             void *data,
173                             void *userdata) {
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);
185         if (r < 0) {
186                 log_error("Failed to allocate a new FDB entry: %s", strerror(-r));
187                 return r;
188         }
189
190         /* read in the MAC address for the FDB table. */
191         r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
192                    &fdb_entry->mac_addr->ether_addr_octet[0],
193                    &fdb_entry->mac_addr->ether_addr_octet[1],
194                    &fdb_entry->mac_addr->ether_addr_octet[2],
195                    &fdb_entry->mac_addr->ether_addr_octet[3],
196                    &fdb_entry->mac_addr->ether_addr_octet[4],
197                    &fdb_entry->mac_addr->ether_addr_octet[5]);
198
199         if (ETHER_ADDR_LEN !=  r) {
200                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
201                            "Not a valid MAC address, ignoring assignment: %s", rvalue);
202                 return 0;
203         }
204
205         fdb_entry = NULL;
206
207         return 0;
208 }
209
210 /* parse the VLAN Id from config files. */
211 int config_parse_fdb_vlan_id(const char *unit,
212                              const char *filename,
213                              unsigned line,
214                              const char *section,
215                              unsigned section_line,
216                              const char *lvalue,
217                              int ltype,
218                              const char *rvalue,
219                              void *data,
220                              void *userdata) {
221         Network *network = userdata;
222         _cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
223         int r;
224
225         assert(filename);
226         assert(section);
227         assert(lvalue);
228         assert(rvalue);
229         assert(data);
230
231         r = fdb_entry_new_static(network, section_line, &fdb_entry);
232         if (r < 0) {
233                 log_error("Failed to allocate a new FDB entry: %s", strerror(-r));
234                 return r;
235         }
236
237         r = config_parse_unsigned(unit, filename, line, section,
238                                   section_line, lvalue, ltype,
239                                   rvalue, &fdb_entry->vlan_id, userdata);
240         if (r < 0) {
241                 log_error("Failed to parse the unsigned integer: %s", strerror(-r));
242                 return r;
243         }
244
245         fdb_entry = NULL;
246
247         return 0;
248 }