593adb6522fae48ba944ee62f6d4e35223d7a4ac
[oonf.git] / src-plugins / nhdp / constant_metric / constant_metric.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 <errno.h>
47 #include <stdio.h>
48
49 #include "common/common_types.h"
50 #include "common/autobuf.h"
51 #include "common/avl.h"
52 #include "common/avl_comp.h"
53 #include "config/cfg_schema.h"
54 #include "config/cfg_tobin.h"
55 #include "config/cfg_validate.h"
56 #include "core/oonf_cfg.h"
57 #include "core/oonf_logging.h"
58 #include "core/oonf_subsystem.h"
59 #include "subsystems/oonf_class.h"
60 #include "subsystems/oonf_rfc5444.h"
61 #include "subsystems/oonf_timer.h"
62 #include "subsystems/os_interface.h"
63
64 #include "nhdp/nhdp.h"
65 #include "nhdp/nhdp_domain.h"
66 #include "nhdp/nhdp_interfaces.h"
67
68 #include "constant_metric/constant_metric.h"
69
70 /* constants and definitions */
71 #define LOG_CONSTANT_METRIC _olsrv2_constant_metric_subsystem.logging
72
73 /**
74  * Session data for a configured constant metric
75  */
76 struct _linkcost {
77   /*! hook into tree of configured metrics */
78   struct avl_node _node;
79
80   /*! name of interface */
81   char if_name[IF_NAMESIZE];
82
83   /*! neighbor IP the metric is restricted to, NULL if neighbor generic */
84   struct netaddr neighbor;
85
86   /*! configured metric */
87   int32_t cost;
88 };
89
90 /* prototypes */
91 static int _init(void);
92 static void _cleanup(void);
93
94 static void _cb_link_added(void *);
95 static void _cb_set_linkcost(struct oonf_timer_instance *);
96
97 static int _avlcmp_linkcost(const void *, const void *);
98
99 static void _cb_cfg_changed(void);
100
101 /* plugin declaration */
102 static struct cfg_schema_entry _constant_entry[] = {
103   CFG_MAP_NETADDR_V46(_linkcost, neighbor, "neighbor", "-",
104       "Originator of neighbor, '-' for all neighbors", false, true),
105   CFG_MAP_INT32_MINMAX(_linkcost, cost, "cost", "1000",
106       "Link cost to neighbor (or all neighbors)", 0,
107       RFC7181_METRIC_MIN, RFC7181_METRIC_MAX),
108 };
109 static struct cfg_schema_entry _constant_entries[] = {
110   CFG_VALIDATE_TOKENS("constant_metric", "", "Defines the static cost to the link to a neighbor.",
111       _constant_entry, .list=true),
112 };
113
114 static struct cfg_schema_section _constant_section = {
115   CFG_OSIF_SCHEMA_INTERFACE_SECTION_INIT,
116   .cb_delta_handler = _cb_cfg_changed,
117   .entries = _constant_entries,
118   .entry_count = ARRAYSIZE(_constant_entries),
119 };
120
121 static const char *_dependencies[] = {
122   OONF_CLASS_SUBSYSTEM,
123   OONF_TIMER_SUBSYSTEM,
124   OONF_OS_INTERFACE_SUBSYSTEM,
125   OONF_NHDP_SUBSYSTEM,
126 };
127 static struct oonf_subsystem _olsrv2_constant_metric_subsystem = {
128   .name = OONF_CONSTANT_METRIC_SUBSYSTEM,
129   .dependencies = _dependencies,
130   .dependencies_count = ARRAYSIZE(_dependencies),
131   .descr = "OLSRv2 Constant Metric plugin",
132   .author = "Henning Rogge",
133
134   .cfg_section = &_constant_section,
135
136   .init = _init,
137   .cleanup = _cleanup,
138 };
139 DECLARE_OONF_PLUGIN(_olsrv2_constant_metric_subsystem);
140
141 /* timer for handling new NHDP neighbors */
142 static struct oonf_timer_class _setup_timer_info = {
143   .name = "Delayed update of constant NHDP neighbor linkcosts",
144   .callback = _cb_set_linkcost,
145   .periodic = false,
146 };
147
148 static struct oonf_timer_instance _setup_timer = {
149   .class = &_setup_timer_info,
150 };
151
152 /* nhdp metric handler */
153 static struct nhdp_domain_metric _constant_metric_handler = {
154   .name = OONF_CONSTANT_METRIC_SUBSYSTEM,
155 };
156
157 /* NHDP link listeners */
158 static struct oonf_class_extension _link_extenstion = {
159   .ext_name = "constant linkmetric",
160   .class_name = NHDP_CLASS_LINK,
161
162   .cb_add = _cb_link_added,
163 };
164
165 /* storage for settings */
166 static struct oonf_class _linkcost_class = {
167   .name = "Constant linkcost storage",
168   .size = sizeof(struct _linkcost),
169 };
170
171 static struct avl_tree _linkcost_tree;
172
173 /**
174  * Initialize plugin
175  * @return -1 if an error happened, 0 otherwise
176  */
177 static int
178 _init(void) {
179   if (nhdp_domain_metric_add(&_constant_metric_handler)) {
180     return -1;
181   }
182
183   if (oonf_class_extension_add(&_link_extenstion)) {
184     nhdp_domain_metric_remove(&_constant_metric_handler);
185     return -1;
186   }
187
188   oonf_timer_add(&_setup_timer_info);
189   oonf_class_add(&_linkcost_class);
190   avl_init(&_linkcost_tree, _avlcmp_linkcost, false);
191   return 0;
192 }
193
194 /**
195  * Cleanup plugin
196  */
197 static void
198 _cleanup(void) {
199   struct _linkcost *lk, *lk_it;
200
201   avl_for_each_element_safe(&_linkcost_tree, lk, _node, lk_it) {
202     avl_remove(&_linkcost_tree, &lk->_node);
203     oonf_class_free(&_linkcost_class, lk);
204   }
205
206   oonf_timer_stop(&_setup_timer);
207   oonf_timer_remove(&_setup_timer_info);
208
209   oonf_class_remove(&_linkcost_class);
210
211   oonf_class_extension_remove(&_link_extenstion);
212   nhdp_domain_metric_remove(&_constant_metric_handler);
213 }
214
215 /**
216  * Callback triggered when a new nhdp link is added
217  * @param ptr nhdp link
218  */
219 static void
220 _cb_link_added(void *ptr __attribute__((unused))) {
221   oonf_timer_set(&_setup_timer, 1);
222 }
223
224 /**
225  * Get the linkcost object for an interface/neighbor combination
226  * @param ifname name of the interface
227  * @param originator IP of the neighbor
228  * @return linkcost object, NULL if not found
229  */
230 static struct _linkcost *
231 _get_linkcost(const char *ifname, const struct netaddr *originator) {
232   struct _linkcost key;
233   struct _linkcost *entry;
234
235   strscpy(key.if_name, ifname, IF_NAMESIZE);
236   memcpy(&key.neighbor, originator, sizeof(struct netaddr));
237
238   return avl_find_element(&_linkcost_tree, &key, entry, _node);
239 }
240
241 /**
242  * Timer callback for delayed setting of new metric values into db
243  * @param ptr timer instance that fired
244  */
245 static void
246 _cb_set_linkcost(struct oonf_timer_instance *ptr __attribute__((unused))) {
247   struct nhdp_link *lnk;
248   struct _linkcost *entry;
249 #ifdef OONF_LOG_DEBUG_INFO
250   struct netaddr_str nbuf;
251 #endif
252
253   OONF_DEBUG(LOG_CONSTANT_METRIC, "Start setting constant linkcosts");
254   list_for_each_element(nhdp_db_get_link_list(), lnk, _global_node) {
255     const char *ifname;
256
257     ifname = nhdp_interface_get_name(lnk->local_if);
258     OONF_DEBUG(LOG_CONSTANT_METRIC, "Look for constant metric if=%s originator=%s",
259         ifname, netaddr_to_string(&nbuf, &lnk->neigh->originator));
260
261     if (netaddr_get_address_family(&lnk->neigh->originator) == AF_UNSPEC) {
262       continue;
263     }
264
265     entry = _get_linkcost(ifname, &lnk->neigh->originator);
266     if (entry == NULL && nhdp_db_link_is_dualstack(lnk)) {
267       entry = _get_linkcost(ifname, &lnk->dualstack_partner->neigh->originator);
268     }
269     if (entry == NULL) {
270       entry = _get_linkcost(OS_INTERFACE_ANY, &lnk->neigh->originator);
271     }
272     if (entry == NULL && nhdp_db_link_is_dualstack(lnk)) {
273       entry = _get_linkcost(OS_INTERFACE_ANY,
274           &lnk->dualstack_partner->neigh->originator);
275     }
276     if (entry == NULL)  {
277       entry = _get_linkcost(ifname, &NETADDR_UNSPEC);
278     }
279     if (entry == NULL) {
280       entry = _get_linkcost(OS_INTERFACE_ANY, &NETADDR_UNSPEC);
281     }
282     if (entry) {
283       OONF_DEBUG(LOG_CONSTANT_METRIC, "Found metric value %u", entry->cost);
284       nhdp_domain_set_incoming_metric(&_constant_metric_handler, lnk, entry->cost);
285       continue;
286     }
287     else {
288       nhdp_domain_set_incoming_metric(&_constant_metric_handler, lnk, RFC7181_METRIC_INFINITE);
289     }
290   }
291 }
292
293 /**
294  * compare two linkcosts with each other by comparing
295  * interface name and neighbor IP
296  * @param ptr1 first linkcost data
297  * @param ptr2 second linkcost data
298  * @return -1/0/1 depending on comparision of both
299  */
300 static int
301 _avlcmp_linkcost(const void *ptr1, const void *ptr2) {
302   const struct _linkcost *lk1, *lk2;
303   int result;
304
305   lk1 = ptr1;
306   lk2 = ptr2;
307
308   result = avl_comp_strcasecmp(&lk1->if_name, &lk2->if_name);
309   if (result == 0) {
310     result = avl_comp_netaddr(&lk1->neighbor, &lk2->neighbor);
311   }
312   return result;
313 }
314
315 /**
316  * Callback triggered when configuration changes
317  */
318 static void
319 _cb_cfg_changed(void) {
320   struct _linkcost *lk, *lk_it;
321   struct netaddr_str nbuf;
322   const char *ptr;
323   const struct const_strarray *array;
324
325   /* remove old entries for this interface */
326   avl_for_each_element_safe(&_linkcost_tree, lk, _node, lk_it) {
327     if (strcasecmp(lk->if_name, _constant_section.section_name) == 0) {
328       avl_remove(&_linkcost_tree, &lk->_node);
329       oonf_class_free(&_linkcost_class, lk);
330     }
331   }
332
333   array = cfg_db_get_schema_entry_value(
334       _constant_section.post, &_constant_entries[0]);
335   if (!array) {
336     OONF_WARN(LOG_CONSTANT_METRIC, "No link defined for static cost");
337     return;
338   }
339
340   strarray_for_each_element(array, ptr) {
341     lk = oonf_class_malloc(&_linkcost_class);
342     if (lk) {
343       if (cfg_tobin_tokens(lk, ptr, _constant_entry, ARRAYSIZE(_constant_entry), NULL)) {
344         OONF_WARN(LOG_CONSTANT_METRIC,
345             "Could not convert value '%s' in section/key '%s/%s' to binary",
346             _constant_section.type, _constant_entries[0].key.entry, ptr);
347       }
348       else {
349         strscpy(lk->if_name, _constant_section.section_name, IF_NAMESIZE);
350         lk->_node.key = lk;
351         avl_insert(&_linkcost_tree, &lk->_node);
352
353         OONF_DEBUG(LOG_CONSTANT_METRIC, "Add entry (%s/%s: %d)",
354             lk->if_name, netaddr_to_string(&nbuf, &lk->neighbor), lk->cost);
355       }
356     }
357   }
358
359   /* delay updating linkcosts */
360   oonf_timer_set(&_setup_timer, 1);
361 }