Fixes for OLSRd2 build process
[oonf.git] / src-plugins / nhdp / nhdp / nhdp.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2013, 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 #include "common/common_types.h"
43 #include "config/cfg_schema.h"
44 #include "core/oonf_logging.h"
45 #include "core/oonf_subsystem.h"
46 #include "subsystems/oonf_class.h"
47 #include "subsystems/oonf_interface.h"
48 #include "subsystems/oonf_rfc5444.h"
49 #include "nhdp/nhdp_hysteresis.h"
50 #include "nhdp/nhdp_interfaces.h"
51 #include "nhdp/nhdp_domain.h"
52 #include "nhdp/nhdp_reader.h"
53 #include "nhdp/nhdp_writer.h"
54 #include "nhdp/nhdp.h"
55
56 /* definitions */
57 struct _domain_parameters {
58   char metric_name[NHDP_DOMAIN_METRIC_MAXLEN];
59   char mpr_name[NHDP_DOMAIN_MPR_MAXLEN];
60 };
61
62 /* prototypes */
63 static void _early_cfg_init(void);
64 static int _init(void);
65 static void _initiate_shutdown(void);
66 static void _cleanup(void);
67
68 static void _cb_cfg_domain_changed(void);
69 static void _cb_cfg_interface_changed(void);
70 static int _cb_validate_domain_section(const char *section_name,
71     struct cfg_named_section *, struct autobuf *);
72
73 /* subsystem definition */
74 static struct cfg_schema_entry _interface_entries[] = {
75   CFG_MAP_ACL_V46(nhdp_interface, ifaddr_filter, "ifaddr_filter",
76       "-127.0.0.0/8\0-::1\0" ACL_DEFAULT_ACCEPT,
77       "Filter for ip interface addresses that should be included in HELLO messages"),
78   CFG_MAP_CLOCK_MIN(nhdp_interface, h_hold_time, "hello_validity", "20.0",
79     "Validity time for NHDP Hello Messages", 100),
80   CFG_MAP_CLOCK_MIN(nhdp_interface, refresh_interval, "hello_interval", "2.0",
81     "Time interval between two NHDP Hello Messages", 100),
82 };
83
84 static struct cfg_schema_section _interface_section = {
85   .type = CFG_INTERFACE_SECTION,
86   .mode = CFG_INTERFACE_SECTION_MODE,
87   .cb_delta_handler = _cb_cfg_interface_changed,
88   .entries = _interface_entries,
89   .entry_count = ARRAYSIZE(_interface_entries),
90 };
91
92 static struct cfg_schema_entry _domain_entries[] = {
93   CFG_MAP_STRING_ARRAY(_domain_parameters, metric_name, "metric", CFG_DOMAIN_ANY_METRIC,
94       "ID of the routing metric used for this domain. '"CFG_DOMAIN_NO_METRIC"'"
95       " means no metric (hopcount!), '"CFG_DOMAIN_ANY_METRIC"' means any metric"
96       " that is loaded (with fallback on '"CFG_DOMAIN_NO_METRIC"').",
97       NHDP_DOMAIN_METRIC_MAXLEN),
98   CFG_MAP_STRING_ARRAY(_domain_parameters, mpr_name,  "mpr", CFG_DOMAIN_ANY_MPR,
99       "ID of the mpr algorithm used for this domain. '"CFG_DOMAIN_NO_MPR"'"
100       " means no mpr algorithm (everyone is MPR), '"CFG_DOMAIN_ANY_MPR"' means"
101       " any metric that is loaded (with fallback on '"CFG_DOMAIN_NO_MPR"').",
102       NHDP_DOMAIN_MPR_MAXLEN),
103 };
104
105 static struct cfg_schema_section _domain_section = {
106   .type = CFG_NHDP_DOMAIN_SECTION,
107   .mode = CFG_SSMODE_NAMED_WITH_DEFAULT,
108   .def_name = CFG_NHDP_DEFAULT_DOMAIN,
109
110   .cb_delta_handler = _cb_cfg_domain_changed,
111   .cb_validate = _cb_validate_domain_section,
112
113   .entries = _domain_entries,
114   .entry_count = ARRAYSIZE(_domain_entries),
115   .next_section = &_interface_section,
116 };
117
118 static const char *_dependencies[] = {
119   OONF_CLOCK_SUBSYSTEM,
120   OONF_CLASS_SUBSYSTEM,
121   OONF_INTERFACE_SUBSYSTEM,
122   OONF_RFC5444_SUBSYSTEM,
123   OONF_TIMER_SUBSYSTEM,
124 };
125 static struct oonf_subsystem nhdp_subsystem = {
126   .name = OONF_NHDP_SUBSYSTEM,
127   .dependencies = _dependencies,
128   .dependencies_count = ARRAYSIZE(_dependencies),
129   .early_cfg_init = _early_cfg_init,
130   .init = _init,
131   .cleanup = _cleanup,
132   .initiate_shutdown = _initiate_shutdown,
133   .cfg_section = &_domain_section,
134 };
135 DECLARE_OONF_PLUGIN(nhdp_subsystem);
136
137 /* other global variables */
138 static struct oonf_rfc5444_protocol *_protocol;
139
140 /* NHDP originator address, might be undefined */
141 static struct netaddr _originator_v4, _originator_v6;
142
143 /* logging sources for NHDP subsystem */
144 enum oonf_log_source LOG_NHDP;
145 enum oonf_log_source LOG_NHDP_R;
146 enum oonf_log_source LOG_NHDP_W;
147
148 /**
149  * Initialize additional logging sources for NHDP
150  */
151 static void
152 _early_cfg_init(void) {
153   LOG_NHDP = nhdp_subsystem.logging;
154   LOG_NHDP_R = oonf_log_register_source(OONF_NHDP_SUBSYSTEM "_r");
155   LOG_NHDP_W = oonf_log_register_source(OONF_NHDP_SUBSYSTEM "_w");
156 }
157
158 /**
159  * Initialize NHDP subsystem
160  * @return 0 if initialized, -1 if an error happened
161  */
162 static int
163 _init(void) {
164   _protocol = oonf_rfc5444_add_protocol(RFC5444_PROTOCOL, true);
165   if (_protocol == NULL) {
166     return -1;
167   }
168
169   if (nhdp_writer_init(_protocol)) {
170     oonf_rfc5444_remove_protocol(_protocol);
171     return -1;
172   }
173
174   nhdp_db_init();
175   nhdp_reader_init(_protocol);
176   nhdp_interfaces_init(_protocol);
177   nhdp_domain_init(_protocol);
178
179   return 0;
180 }
181
182 /**
183  * Begin shutdown by deactivating reader and writer
184  */
185 static void
186 _initiate_shutdown(void) {
187   nhdp_writer_cleanup();
188   nhdp_reader_cleanup();
189 }
190
191 /**
192  * Cleanup NHDP subsystem
193  */
194 static void
195 _cleanup(void) {
196   nhdp_db_cleanup();
197   nhdp_interfaces_cleanup();
198   nhdp_domain_cleanup();
199 }
200
201 /**
202  * Sets the originator address used by NHDP to a new value.
203  * @param addr NHDP originator.
204  */
205 void
206 nhdp_set_originator(const struct netaddr *addr) {
207 #ifdef OONF_LOG_DEBUG_INFO
208   struct netaddr_str buf;
209 #endif
210
211   OONF_DEBUG(LOG_NHDP, "Set originator to %s", netaddr_to_string(&buf, addr));
212   if (netaddr_get_address_family(addr) == AF_INET) {
213     memcpy(&_originator_v4, addr, sizeof(*addr));
214   }
215   else if (netaddr_get_address_family(addr) == AF_INET6) {
216     memcpy(&_originator_v6, addr, sizeof(*addr));
217   }
218 }
219
220 /**
221  * Remove the originator currently set
222  * @param af_type address family type of the originator
223  *   (AF_INET or AF_INET6)
224  */
225 void
226 nhdp_reset_originator(int af_type) {
227   if (af_type == AF_INET) {
228     netaddr_invalidate(&_originator_v4);
229   }
230   else if (af_type == AF_INET6) {
231     netaddr_invalidate(&_originator_v6);
232   }
233 }
234
235 /**
236  * @param af_type address family type of the originator
237  *   (AF_INET or AF_INET6)
238  * @return current NHDP originator
239  */
240 const struct netaddr *
241 nhdp_get_originator(int af_type) {
242   if (af_type == AF_INET) {
243     return &_originator_v4;
244   }
245   else if (af_type == AF_INET6) {
246     return &_originator_v6;
247   }
248   return NULL;
249 }
250
251 /**
252  * default implementation for rfc5444 flooding target selection to
253  * handle dualstack correctly.
254  * @param rfc5444_target
255  * @return
256  */
257 bool
258 nhdp_flooding_selector(struct rfc5444_writer *writer __attribute__((unused)),
259     struct rfc5444_writer_target *rfc5444_target, void *ptr __attribute__((unused))) {
260   return nhdp_message_forwarding_selector(rfc5444_target);
261 }
262
263 /**
264  * default implementation for rfc5444 forwarding selector to
265  * hangle dualstack correctly
266  * @param writer rfc5444 writer
267  * @param target rfc5444 target
268  * @param ptr custom pointer, contains rfc5444 target
269  * @return true if target corresponds to selection
270  */
271 bool
272 nhdp_message_forwarding_selector(struct rfc5444_writer_target *rfc5444_target) {
273   struct oonf_rfc5444_target *target;
274   struct nhdp_interface *interf;
275   bool is_ipv4, flood;
276 #ifdef OONF_LOG_DEBUG_INFO
277   struct netaddr_str buf;
278 #endif
279   target = container_of(rfc5444_target, struct oonf_rfc5444_target, rfc5444_target);
280
281   /* test if this is the ipv4 multicast target */
282   is_ipv4 = target == target->interface->multicast4;
283
284   /* only forward to multicast targets */
285   if (!is_ipv4 && target != target->interface->multicast6) {
286     return false;
287   }
288
289   /* get NHDP interface for target */
290   interf = nhdp_interface_get(target->interface->name);
291   if (interf == NULL) {
292     OONF_DEBUG(LOG_NHDP, "Do not flood message type"
293         " to interface %s: its unknown to NHDP",
294         target->interface->name);
295     return NULL;
296   }
297
298   /* lookup flooding cache in NHDP interface */
299   if (is_ipv4) {
300     flood = interf->use_ipv4_for_flooding
301         || interf->dualstack_af_type == AF_INET;
302   }
303   else {
304     flood =  interf->use_ipv6_for_flooding
305         || interf->dualstack_af_type == AF_INET6;
306   }
307
308   OONF_DEBUG(LOG_NHDP, "Flooding to target %s: %s",
309       netaddr_to_string(&buf, &target->dst), flood ? "yes" : "no");
310
311   return flood;
312 }
313
314 /**
315  * Configuration of a NHDP domain changed
316  */
317 static void
318 _cb_cfg_domain_changed(void) {
319   struct _domain_parameters param;
320   int ext;
321
322   OONF_INFO(LOG_NHDP, "Received domain cfg change for name '%s': %s %s",
323       _domain_section.section_name,
324       _domain_section.pre != NULL ? "pre" : "-",
325       _domain_section.post != NULL ? "post" : "-");
326
327   ext = strtol(_domain_section.section_name, NULL, 10);
328
329   if (cfg_schema_tobin(&param, _domain_section.post,
330       _domain_entries, ARRAYSIZE(_domain_entries))) {
331     OONF_WARN(LOG_NHDP, "Cannot convert NHDP domain configuration.");
332     return;
333   }
334
335   nhdp_domain_configure(ext, param.metric_name, param.mpr_name);
336 }
337
338 /**
339  * Configuration has changed, handle the changes
340  */
341 static void
342 _cb_cfg_interface_changed(void) {
343   struct nhdp_interface *interf;
344
345   OONF_DEBUG(LOG_NHDP, "Configuration of NHDP interface %s changed",
346       _interface_section.section_name);
347
348   /* get interface */
349   interf = nhdp_interface_get(_interface_section.section_name);
350
351   if (_interface_section.post == NULL) {
352     /* section was removed */
353     if (interf != NULL) {
354       nhdp_interface_remove(interf);
355     }
356     return;
357   }
358
359   if (interf == NULL) {
360     interf = nhdp_interface_add(_interface_section.section_name);
361   }
362
363   if (cfg_schema_tobin(interf, _interface_section.post,
364       _interface_entries, ARRAYSIZE(_interface_entries))) {
365     OONF_WARN(LOG_NHDP, "Cannot convert NHDP configuration for interface.");
366     return;
367   }
368
369   /* apply new settings to interface */
370   nhdp_interface_apply_settings(interf);
371 }
372
373 /**
374  * Validate that the name of the domain section is valid
375  * @param section_name name of section including type
376  * @param named cfg named section
377  * @param out output buffer for errors
378  * @return -1 if invalid, 0 otherwise
379  */
380 static int
381 _cb_validate_domain_section(const char *section_name,
382     struct cfg_named_section *named, struct autobuf *out) {
383   char *error = NULL;
384   int ext;
385
386   if (!named->name) {
387     /* default name should be okay */
388     return 0;
389   }
390
391   ext = strtol(named->name, &error, 10);
392   if (error != NULL && *error != 0) {
393     /* illegal domain name */
394     abuf_appendf(out, "name of section '%s' must be a number between 0 and 255",
395         section_name);
396     return -1;
397   }
398
399   if (ext < 0 || ext > 255) {
400     /* name out of range */
401     abuf_appendf(out, "name of section '%s' must be a number between 0 and 255",
402         section_name);
403     return -1;
404   }
405   return 0;
406 }