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