Rename "subsystems" directory to "base"
[oonf.git] / src / generic / dlep / router / dlep_router_interface.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 <unistd.h>
48
49 #include <oonf/libcommon/avl.h>
50 #include <oonf/libcommon/avl_comp.h>
51 #include <oonf/oonf.h>
52 #include <oonf/libcommon/netaddr.h>
53
54 #include <oonf/base/oonf_class.h>
55 #include <oonf/base/oonf_layer2.h>
56 #include <oonf/base/oonf_packet_socket.h>
57 #include <oonf/base/oonf_timer.h>
58 #include <oonf/base/os_interface.h>
59
60 #include <oonf/generic/dlep/dlep_extension.h>
61 #include <oonf/generic/dlep/dlep_iana.h>
62 #include <oonf/generic/dlep/dlep_interface.h>
63 #include <oonf/generic/dlep/dlep_session.h>
64 #include <oonf/generic/dlep/dlep_writer.h>
65
66 #include <oonf/generic/dlep/router/dlep_router.h>
67 #include <oonf/generic/dlep/router/dlep_router_interface.h>
68
69 #include <oonf/generic/dlep/ext_base_ip/ip.h>
70 #include <oonf/generic/dlep/ext_base_metric/metric.h>
71 #include <oonf/generic/dlep/ext_base_proto/proto_router.h>
72 #include <oonf/generic/dlep/ext_l1_statistics/l1_statistics.h>
73 #include <oonf/generic/dlep/ext_l2_statistics/l2_statistics.h>
74 #include <oonf/generic/dlep/ext_radio_attributes/radio_attributes.h>
75 #include <oonf/generic/dlep/ext_lid/lid.h>
76 #include <oonf/generic/dlep/router/dlep_router_internal.h>
77 #include <oonf/generic/dlep/router/dlep_router_session.h>
78
79 static void _connect_to_setup(struct dlep_router_if *router_if);
80 static void _check_connect_to(struct dlep_router_if *router_if);
81 static void _cleanup_interface(struct dlep_router_if *interface);
82 static int _connect_to_if_changed(struct os_interface_listener *);
83 static void _cb_check_connect_to_status(struct oonf_timer_instance *);
84
85 static struct oonf_class _router_if_class = {
86   .name = "DLEP router interface",
87   .size = sizeof(struct dlep_router_if),
88 };
89
90 static bool _shutting_down;
91
92 static struct oonf_layer2_origin _l2_origin = {
93   .name = "dlep router",
94   .proactive = true,
95   .priority = OONF_LAYER2_ORIGIN_RELIABLE,
96 };
97
98 static struct oonf_layer2_origin _l2_default_origin = {
99   .name = "dlep router defaults",
100   .proactive = false,
101   .priority = OONF_LAYER2_ORIGIN_UNRELIABLE,
102 };
103
104 static struct oonf_timer_class _connect_to_watchdog_class = {
105   .name = "connect_to watchdog",
106   .callback = _cb_check_connect_to_status,
107   .periodic = true,
108 };
109
110 /**
111  * Initialize dlep router interface framework. This will also
112  * initialize the dlep router session framework.
113  */
114 void
115 dlep_router_interface_init(void) {
116   oonf_class_add(&_router_if_class);
117
118   dlep_extension_init();
119   dlep_session_init();
120   dlep_router_session_init();
121   dlep_base_proto_router_init();
122   dlep_base_metric_init();
123   dlep_base_ip_init();
124   dlep_l1_statistics_init();
125   dlep_l2_statistics_init();
126   dlep_radio_attributes_init();
127   dlep_lid_init();
128
129   _shutting_down = false;
130
131   oonf_layer2_origin_add(&_l2_origin);
132   oonf_timer_add(&_connect_to_watchdog_class);
133 }
134
135 /**
136  * Cleanup dlep router interface framework. This will also cleanup
137  * all dlep router sessions.
138  */
139 void
140 dlep_router_interface_cleanup(void) {
141   struct dlep_router_if *interf, *it;
142
143   avl_for_each_element_safe(dlep_if_get_tree(false), interf, interf._node, it) {
144     dlep_router_remove_interface(interf);
145   }
146
147   oonf_class_remove(&_router_if_class);
148
149   dlep_base_ip_cleanup();
150   dlep_router_session_cleanup();
151   dlep_extension_cleanup();
152   oonf_layer2_origin_remove(&_l2_origin);
153   oonf_timer_remove(&_connect_to_watchdog_class);
154 }
155
156 /**
157  * Get a dlep router interface by layer2 interface name
158  * @param l2_ifname interface name
159  * @return dlep router interface, NULL if not found
160  */
161 struct dlep_router_if *
162 dlep_router_get_by_layer2_if(const char *l2_ifname) {
163   struct dlep_router_if *interf;
164
165   return avl_find_element(dlep_if_get_tree(false), l2_ifname, interf, interf._node);
166 }
167
168 /**
169  * Get a dlep router interface by dlep datapath name
170  * @param ifname interface name
171  * @return dlep router interface, NULL if not found
172  */
173 struct dlep_router_if *
174 dlep_router_get_by_datapath_if(const char *ifname) {
175   struct dlep_router_if *interf;
176
177   avl_for_each_element(dlep_if_get_tree(false), interf, interf._node) {
178     if (strcmp(interf->interf.udp_config.interface, ifname) == 0) {
179       return interf;
180     }
181   }
182   return NULL;
183 }
184
185 /**
186  * Add a new dlep interface or get existing one with same name.
187  * @param ifname interface name
188  * @return dlep router interface, NULL if allocation failed
189  */
190 struct dlep_router_if *
191 dlep_router_add_interface(const char *ifname) {
192   struct dlep_router_if *interface;
193
194   interface = dlep_router_get_by_layer2_if(ifname);
195   if (interface) {
196     OONF_DEBUG(LOG_DLEP_ROUTER, "use existing instance for %s", ifname);
197     return interface;
198   }
199
200   interface = oonf_class_malloc(&_router_if_class);
201   if (!interface) {
202     return NULL;
203   }
204
205   if (dlep_if_add(&interface->interf, ifname, &_l2_origin, &_l2_default_origin, _connect_to_if_changed, LOG_DLEP_ROUTER, false)) {
206     oonf_class_free(&_router_if_class, interface);
207     return NULL;
208   }
209
210   /* prepare timer */
211   interface->_connect_to_watchdog.class = &_connect_to_watchdog_class;
212
213   OONF_DEBUG(LOG_DLEP_ROUTER, "Add session %s", ifname);
214   return interface;
215 }
216
217 /**
218  * Remove dlep router interface
219  * @param interface dlep router interface
220  */
221 void
222 dlep_router_remove_interface(struct dlep_router_if *interface) {
223   /* close all sessions */
224   _cleanup_interface(interface);
225
226   /* cleanup generic interface */
227   dlep_if_remove(&interface->interf);
228
229   /* remove session */
230   free(interface->interf.session.cfg.peer_type);
231   oonf_class_free(&_router_if_class, interface);
232 }
233
234 /**
235  * Apply new settings to dlep router interface. This will close all
236  * existing dlep sessions.
237  * @param interf dlep router interface
238  */
239 void
240 dlep_router_apply_interface_settings(struct dlep_router_if *interf) {
241   struct dlep_extension *ext;
242
243   oonf_packet_apply_managed(&interf->interf.udp, &interf->interf.udp_config);
244
245   _cleanup_interface(interf);
246
247   if (!netaddr_is_unspec(&interf->connect_to_addr)) {
248     _connect_to_setup(interf);
249   }
250   else {
251     oonf_timer_stop(&interf->_connect_to_watchdog);
252   }
253
254   avl_for_each_element(dlep_extension_get_tree(), ext, _node) {
255     if (ext->cb_session_apply_router) {
256       ext->cb_session_apply_router(&interf->interf.session);
257     }
258   }
259 }
260
261 /**
262  * Send all active sessions a Peer Terminate signal
263  */
264 void
265 dlep_router_terminate_all_sessions(void) {
266   struct dlep_router_if *interf;
267   struct dlep_router_session *router_session;
268
269   _shutting_down = true;
270
271   avl_for_each_element(dlep_if_get_tree(false), interf, interf._node) {
272     avl_for_each_element(&interf->interf.session_tree, router_session, _node) {
273       dlep_session_terminate(&router_session->session, DLEP_STATUS_OKAY, "DLEP router is shutting down");
274     }
275   }
276 }
277
278 /**
279 * open a direct TCP connection for this interface
280 * @param router_if router interface
281 */
282 static void
283 _connect_to_setup(struct dlep_router_if *router_if) {
284   struct os_interface *os_if;
285   const struct os_interface_ip *result;
286   union netaddr_socket local;
287 #ifdef OONF_LOG_DEBUG_INFO
288   struct netaddr_str nbuf;
289 #endif
290
291   os_if = router_if->interf.session.l2_listener.data;
292
293   OONF_DEBUG(LOG_DLEP_ROUTER, "Connect directly to [%s]:%d", netaddr_to_string(&nbuf, &router_if->connect_to_addr),
294       router_if->connect_to_port);
295
296   /* start watchdog */
297   oonf_timer_set(&router_if->_connect_to_watchdog, 1000);
298
299   result = os_interface_get_prefix_from_dst(&router_if->connect_to_addr, os_if);
300   if (result) {
301     /* initialize local and remote socket */
302     netaddr_socket_init(&local, &result->address, 0, os_if->index);
303     netaddr_socket_init(&router_if->connect_to, &router_if->connect_to_addr, router_if->connect_to_port, os_if->index);
304
305     dlep_router_add_session(router_if, &local, &router_if->connect_to);
306   }
307 }
308
309 /**
310  * Close all existing dlep sessions of a dlep interface
311  * @param interface dlep router interface
312  */
313 static void
314 _cleanup_interface(struct dlep_router_if *interface) {
315   struct dlep_router_session *stream, *it;
316
317   /* close TCP connection and socket */
318   avl_for_each_element_safe(&interface->interf.session_tree, stream, _node, it) {
319     dlep_router_remove_session(stream);
320   }
321 }
322
323 /**
324  * check if connect_to session is up and running. If not, restart it.
325  * @param router_if router interface
326  */
327 static void
328 _check_connect_to(struct dlep_router_if *router_if) {
329   struct dlep_router_session *connect_to_session;
330
331   if (netaddr_is_unspec(&router_if->connect_to_addr)) {
332     /* do not connect */
333     return;
334   }
335
336   connect_to_session = dlep_router_get_session(router_if, &router_if->connect_to);
337   if (connect_to_session != NULL
338     && (connect_to_session->session._peer_state == DLEP_PEER_NOT_CONNECTED
339     || connect_to_session->session._peer_state == DLEP_PEER_TERMINATED)) {
340     /* cleanup not working session */
341     dlep_router_remove_session(connect_to_session);
342     connect_to_session = NULL;
343   }
344
345   if (!connect_to_session) {
346     _connect_to_setup(router_if);
347   }
348   return;
349 }
350
351 /**
352 * Interface listener to (re-)establish connect_to session if it failed.
353 * @param interf interface listener that triggered
354 * @return always 0
355 */
356 static int
357 _connect_to_if_changed(struct os_interface_listener *interf) {
358   struct dlep_router_if *router_if;
359
360   router_if = container_of(interf, struct dlep_router_if, interf.session.l2_listener);
361   _check_connect_to(router_if);
362   return 0;
363 }
364
365 /**
366  * Timer callback to watch connect_to session status
367  * @param instance watchdog timer instance
368  */
369 static void
370 _cb_check_connect_to_status(struct oonf_timer_instance *instance) {
371   struct dlep_router_if *router_if;
372
373   router_if = container_of(instance, struct dlep_router_if, _connect_to_watchdog);
374   _check_connect_to(router_if);
375 }