da77ba7cd4ff168b9250e5b01494a54930d30d4e
[oonf.git] / src / generic / link_config / link_config.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <oonf/libcommon/avl.h>
47 #include <oonf/libcommon/avl_comp.h>
48 #include <oonf/oonf.h>
49 #include <oonf/libconfig/cfg_schema.h>
50 #include <oonf/libconfig/cfg_validate.h>
51 #include <oonf/libcore/oonf_logging.h>
52 #include <oonf/libcore/oonf_subsystem.h>
53 #include <oonf/subsystems/oonf_class.h>
54 #include <oonf/subsystems/oonf_layer2.h>
55 #include <oonf/subsystems/oonf_timer.h>
56 #include <oonf/subsystems/os_interface.h>
57
58 #include <oonf/generic/link_config/link_config.h>
59
60 /* definitions and constants */
61 #define LOG_LINK_CONFIG _oonf_link_config_subsystem.logging
62
63 /* Prototypes */
64 static void _early_cfg_init(void);
65 static int _init(void);
66 static void _cleanup(void);
67
68 static void _cb_update_link_config(void *);
69 static void _cb_delayed_config(struct oonf_timer_instance *);
70
71 static int _cb_validate_linkdata(
72   const struct cfg_schema_entry *entry, const char *section_name, const char *value, struct autobuf *out);
73 static void _parse_strarray(struct strarray *array, const char *ifname, enum oonf_layer2_neighbor_index idx);
74 static void _cb_config_changed(void);
75
76 /* define configuration entries */
77
78 /*! configuration validator for linkdata */
79 #define CFG_VALIDATE_LINKDATA(link_index, p_help, args...)                                                             \
80   _CFG_VALIDATE("", "", p_help, .cb_validate = _cb_validate_linkdata, .validate_param = { { .i32 = { link_index } } }, \
81     .list = true, ##args)
82
83 static struct cfg_schema_entry _link_config_if_entries[] = {
84   CFG_VALIDATE_LINKDATA(OONF_LAYER2_NEIGH_RX_BITRATE,
85     "Sets the incoming link speed on the interface. Consists of a speed in"
86     " bits/s (with iso-prefix) and an optional list of mac addresses of neighbor nodes."),
87   CFG_VALIDATE_LINKDATA(OONF_LAYER2_NEIGH_TX_BITRATE,
88     "Sets the outgoing link speed on the interface. Consists of a speed in"
89     " bits/s (with iso-prefix) and an optional list of mac addresses of neighbor nodes."),
90   CFG_VALIDATE_LINKDATA(OONF_LAYER2_NEIGH_RX_MAX_BITRATE,
91     "Sets the maximal incoming link speed on the interface. Consists of a speed in"
92     " bits/s (with iso-prefix) and an optional list of mac addresses of neighbor nodes."),
93   CFG_VALIDATE_LINKDATA(OONF_LAYER2_NEIGH_TX_MAX_BITRATE,
94     "Sets the maximal outgoing link speed on the interface. Consists of a speed in"
95     " bits/s (with iso-prefix) and an optional list of mac addresses of neighbor nodes."),
96   CFG_VALIDATE_LINKDATA(OONF_LAYER2_NEIGH_RX_SIGNAL,
97     "Sets the incoing signal strength on the interface. Consists of a signal strength in"
98     " dBm (with iso-prefix) and an optional list of mac addresses of neighbor nodes."),
99 };
100
101 static struct cfg_schema_section _link_config_section = {
102   CFG_OSIF_SCHEMA_INTERFACE_SECTION_INIT,
103
104   .cb_delta_handler = _cb_config_changed,
105   .entries = _link_config_if_entries,
106   .entry_count = ARRAYSIZE(_link_config_if_entries),
107 };
108
109 /* declare subsystem */
110 static const char *_dependencies[] = {
111   OONF_CLASS_SUBSYSTEM,
112   OONF_LAYER2_SUBSYSTEM,
113   OONF_OS_INTERFACE_SUBSYSTEM,
114 };
115 static struct oonf_subsystem _oonf_link_config_subsystem = {
116   .name = OONF_LINK_CONFIG_SUBSYSTEM,
117   .dependencies = _dependencies,
118   .dependencies_count = ARRAYSIZE(_dependencies),
119   .early_cfg_init = _early_cfg_init,
120   .init = _init,
121   .cleanup = _cleanup,
122
123   .cfg_section = &_link_config_section,
124 };
125 DECLARE_OONF_PLUGIN(_oonf_link_config_subsystem);
126
127 /* originator for smooth set/remove of configured layer2 values */
128 static struct oonf_layer2_origin _l2_origin_current = {
129   .name = "link config updated",
130   .priority = OONF_LAYER2_ORIGIN_CONFIGURED,
131 };
132 static struct oonf_layer2_origin _l2_origin_old = {
133   .name = "link config",
134   .priority = OONF_LAYER2_ORIGIN_CONFIGURED,
135 };
136
137 /* listener for removal of layer2 data */
138 static struct oonf_class_extension _l2net_listener = {
139   .ext_name = "link config listener",
140   .class_name = LAYER2_CLASS_NETWORK,
141
142   .cb_remove = _cb_update_link_config,
143   .cb_change = _cb_update_link_config,
144 };
145 static struct oonf_class_extension _l2neigh_listener = {
146   .ext_name = "link config listener",
147   .class_name = LAYER2_CLASS_NEIGHBOR,
148
149   .cb_remove = _cb_update_link_config,
150   .cb_change = _cb_update_link_config,
151 };
152
153 /* timer for lazy updates */
154 static struct oonf_timer_class _lazy_update_class = {
155   .name = "lazy link config",
156   .callback = _cb_delayed_config,
157 };
158
159 static struct oonf_timer_instance _lazy_update_instance = {
160   .class = &_lazy_update_class,
161 };
162
163 static void
164 _early_cfg_init(void) {
165   struct cfg_schema_entry *entry;
166   size_t i;
167
168   for (i = 0; i < ARRAYSIZE(_link_config_if_entries); i++) {
169     entry = &_link_config_if_entries[i];
170     entry->key.entry =
171       oonf_layer2_neigh_metadata_get((enum oonf_layer2_neighbor_index)entry->validate_param[0].i32[0])->key;
172   }
173 }
174
175 /**
176  * Subsystem constructor
177  * @return always returns 0
178  */
179 static int
180 _init(void) {
181   oonf_layer2_origin_add(&_l2_origin_current);
182   oonf_layer2_origin_add(&_l2_origin_old);
183
184   oonf_class_extension_add(&_l2net_listener);
185   oonf_class_extension_add(&_l2neigh_listener);
186
187   oonf_timer_add(&_lazy_update_class);
188
189   return 0;
190 }
191
192 /**
193  * Subsystem destructor
194  */
195 static void
196 _cleanup(void) {
197   oonf_timer_stop(&_lazy_update_instance);
198   oonf_timer_remove(&_lazy_update_class);
199
200   oonf_class_extension_remove(&_l2net_listener);
201   oonf_class_extension_remove(&_l2neigh_listener);
202
203   oonf_layer2_origin_remove(&_l2_origin_current);
204   oonf_layer2_origin_remove(&_l2_origin_old);
205 }
206
207 /**
208  * Listener for removal of layer2 database entries. Will trigger
209  * a delayed reset of this plugins configured data
210  * @param ptr unused
211  */
212 static void
213 _cb_update_link_config(void *ptr __attribute__((unused))) {
214   if (!oonf_timer_is_active(&_lazy_update_instance)) {
215     OONF_DEBUG(LOG_LINK_CONFIG, "Trigger lazy update");
216     oonf_timer_set(&_lazy_update_instance, OONF_LINK_CONFIG_REWRITE_DELAY);
217   }
218 }
219
220 /**
221  * Callback for delayed update.
222  * @param timer unused
223  */
224 static void
225 _cb_delayed_config(struct oonf_timer_instance *timer __attribute__((unused))) {
226   /* re-read the configuration */
227   OONF_DEBUG(LOG_LINK_CONFIG, "Update configuration settings");
228   _cb_config_changed();
229 }
230
231 /**
232  * Configuration subsystem validator for linkdata
233  * @param entry configuration schema entry
234  * @param section_name name of the configuration section the entry was set
235  * @param value text value of the configuration entry
236  * @param out output buffer for error messages
237  * @return -1 if validation failed, 0 otherwise
238  */
239 static int
240 _cb_validate_linkdata(
241   const struct cfg_schema_entry *entry, const char *section_name, const char *value, struct autobuf *out) {
242   enum oonf_layer2_neighbor_index idx;
243   struct isonumber_str sbuf;
244   struct netaddr_str nbuf;
245   const char *ptr;
246
247   idx = entry->validate_param[0].i32[0];
248
249   /* test if first word is a human readable number */
250   ptr = str_cpynextword(sbuf.buf, value, sizeof(sbuf));
251   if (cfg_validate_int(out, section_name, entry->key.entry, sbuf.buf, INT64_MIN, INT64_MAX, 8,
252         oonf_layer2_neigh_metadata_get(idx)->fraction)) {
253     return -1;
254   }
255
256   while (ptr) {
257     int8_t af[] = { AF_MAC48, AF_EUI64 };
258
259     /* test if the rest of the words are mac addresses */
260     ptr = str_cpynextword(nbuf.buf, ptr, sizeof(nbuf));
261
262     if (cfg_validate_netaddr(out, section_name, entry->key.entry, nbuf.buf, false, af, ARRAYSIZE(af))) {
263       return -1;
264     }
265   }
266   return 0;
267 }
268
269 /**
270  * Parse user input and add the corresponding database entries
271  * @param array pointer to string array
272  * @param ifname interface name
273  * @param idx layer2 neighbor index
274  */
275 static void
276 _parse_strarray(struct strarray *array, const char *ifname, enum oonf_layer2_neighbor_index idx) {
277   struct oonf_layer2_neigh *l2neigh;
278   struct oonf_layer2_net *l2net;
279   struct netaddr_str nbuf;
280   struct netaddr linkmac;
281   struct isonumber_str hbuf;
282   int64_t value;
283   char *entry;
284   const char *ptr;
285
286   l2net = oonf_layer2_net_add(ifname);
287   if (l2net == NULL) {
288     return;
289   }
290
291   strarray_for_each_element(array, entry) {
292     ptr = str_cpynextword(hbuf.buf, entry, sizeof(hbuf));
293     if (isonumber_to_s64(&value, hbuf.buf, oonf_layer2_neigh_metadata_get(idx)->fraction)) {
294       continue;
295     }
296
297     if (ptr == NULL) {
298       /* add network wide data entry */
299       if (!oonf_layer2_data_set_int64(&l2net->neighdata[idx], &_l2_origin_current, value)) {
300         OONF_INFO(LOG_LINK_CONFIG, "if-wide %s for %s: %s", oonf_layer2_neigh_metadata_get(idx)->key, ifname, hbuf.buf);
301       }
302       continue;
303     }
304
305     while (ptr) {
306       ptr = str_cpynextword(nbuf.buf, ptr, sizeof(nbuf));
307
308       if (netaddr_from_string(&linkmac, nbuf.buf) != 0) {
309         break;
310       }
311
312       l2neigh = oonf_layer2_neigh_add(l2net, &linkmac);
313       if (!l2neigh) {
314         continue;
315       }
316
317       if (!oonf_layer2_data_set_int64(&l2neigh->data[idx], &_l2_origin_current, value)) {
318         OONF_INFO(LOG_LINK_CONFIG, "%s to neighbor %s on %s: %s", oonf_layer2_neigh_metadata_get(idx)->key, nbuf.buf,
319           ifname, hbuf.buf);
320       }
321     }
322   }
323 }
324
325 /**
326  * Parse configuration change
327  */
328 static void
329 _cb_config_changed(void) {
330   struct cfg_schema_entry *schema_entry;
331   enum oonf_layer2_neighbor_index l2idx;
332   struct oonf_layer2_neigh *l2neigh, *l2neigh_it;
333   struct oonf_layer2_net *l2net;
334   struct cfg_entry *entry;
335   char ifbuf[IF_NAMESIZE];
336   const char *ifname;
337   size_t idx;
338   bool commit;
339
340   if (_link_config_section.post) {
341     for (idx = 0; idx < ARRAYSIZE(_link_config_if_entries); idx++) {
342       schema_entry = &_link_config_if_entries[idx];
343       l2idx = schema_entry->validate_param[0].i32[0];
344
345       entry = cfg_db_get_entry(_link_config_section.post, schema_entry->key.entry);
346       if (entry) {
347         _parse_strarray(&entry->val, _link_config_section.section_name, l2idx);
348       }
349     }
350   }
351
352   ifname = cfg_get_phy_if(ifbuf, _link_config_section.section_name);
353   l2net = oonf_layer2_net_get(ifname);
354   if (l2net) {
355     /* remove old entries and trigger remove events */
356     oonf_layer2_net_cleanup(l2net, &_l2_origin_old, true);
357
358     commit = false;
359     /* detect changes and relabel the origin */
360     avl_for_each_element_safe(&l2net->neighbors, l2neigh, _node, l2neigh_it) {
361       for (idx = 0; idx < OONF_LAYER2_NEIGH_COUNT; idx++) {
362         if (oonf_layer2_data_get_origin(&l2neigh->data[idx]) == &_l2_origin_current) {
363           oonf_layer2_data_set_origin(&l2neigh->data[idx], &_l2_origin_old);
364           commit = true;
365         }
366       }
367       if (commit) {
368         /* trigger change event */
369         oonf_layer2_neigh_commit(l2neigh);
370       }
371     }
372
373     commit = false;
374     /* detect changes and relabel the origin */
375     for (idx = 0; idx < OONF_LAYER2_NET_COUNT; idx++) {
376       if (oonf_layer2_data_get_origin(&l2net->neighdata[idx]) == &_l2_origin_current) {
377         oonf_layer2_data_set_origin(&l2net->neighdata[idx], &_l2_origin_old);
378         commit = true;
379       }
380     }
381     if (commit) {
382       /* trigger change event */
383       oonf_layer2_net_commit(l2net);
384     }
385   }
386 }