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