Rename "subsystems" directory to "base"
[oonf.git] / src / generic / dlep / ext_base_ip / ip.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/autobuf.h>
47 #include <oonf/libcommon/avl.h>
48 #include <oonf/oonf.h>
49 #include <oonf/base/oonf_layer2.h>
50 #include <oonf/base/oonf_timer.h>
51
52 #include <oonf/generic/dlep/dlep_extension.h>
53 #include <oonf/generic/dlep/dlep_iana.h>
54 #include <oonf/generic/dlep/dlep_interface.h>
55 #include <oonf/generic/dlep/dlep_reader.h>
56 #include <oonf/generic/dlep/dlep_writer.h>
57 #include <oonf/generic/dlep/radio/dlep_radio_interface.h>
58 #include <oonf/generic/dlep/radio/dlep_radio_session.h>
59
60 #include <oonf/generic/dlep/ext_base_ip/ip.h>
61
62 struct _prefix_storage {
63   struct netaddr prefix;
64
65   bool add;
66
67   struct avl_node _node;
68 };
69
70 static void _cb_session_init(struct dlep_session *session);
71 static void _cb_session_cleanup(struct dlep_session *session);
72 static int _radio_write_session_update(
73   struct dlep_extension *ext, struct dlep_session *session, const struct oonf_layer2_neigh_key *neigh);
74 static int _radio_write_destination_update(
75   struct dlep_extension *ext, struct dlep_session *session, const struct oonf_layer2_neigh_key *neigh);
76 static enum dlep_parser_error _router_process_session_update(struct dlep_extension *ext, struct dlep_session *session);
77 static enum dlep_parser_error _router_process_destination_update(
78   struct dlep_extension *ext, struct dlep_session *session);
79 static void _add_prefix(struct avl_tree *tree, struct netaddr *addr, bool add);
80
81 static void _cb_add_if_ip(void *ptr);
82 static void _cb_remove_if_ip(void *ptr);
83 static void _cb_add_neigh_ip(void *ptr);
84 static void _cb_remove_neigh_ip(void *ptr);
85
86 /* peer initialization ack/peer update/destination update */
87 static const uint16_t _ip_tlvs[] = {
88   DLEP_IPV4_ADDRESS_TLV,
89   DLEP_IPV4_SUBNET_TLV,
90   DLEP_IPV6_ADDRESS_TLV,
91   DLEP_IPV6_SUBNET_TLV,
92 };
93
94 /* supported signals of this extension */
95 static struct dlep_extension_signal _signals[] = {
96   {
97     .id = DLEP_SESSION_INITIALIZATION_ACK,
98     .supported_tlvs = _ip_tlvs,
99     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
100     .add_radio_tlvs = _radio_write_session_update,
101     .process_router = _router_process_session_update,
102   },
103   {
104     .id = DLEP_SESSION_UPDATE,
105     .supported_tlvs = _ip_tlvs,
106     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
107     .add_radio_tlvs = _radio_write_session_update,
108     .process_router = _router_process_session_update,
109   },
110   {
111     .id = DLEP_DESTINATION_UP,
112     .supported_tlvs = _ip_tlvs,
113     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
114     .add_radio_tlvs = _radio_write_destination_update,
115     .process_router = _router_process_destination_update,
116   },
117   {
118     .id = DLEP_DESTINATION_UPDATE,
119     .supported_tlvs = _ip_tlvs,
120     .supported_tlv_count = ARRAYSIZE(_ip_tlvs),
121     .add_radio_tlvs = _radio_write_destination_update,
122     .process_router = _router_process_destination_update,
123   },
124 };
125
126 /* supported TLVs of this extension */
127 static struct dlep_extension_tlv _tlvs[] = {
128   { DLEP_MAC_ADDRESS_TLV, 6, 8 },
129   { DLEP_IPV4_ADDRESS_TLV, 5, 5 },
130   { DLEP_IPV4_SUBNET_TLV, 6, 6 },
131   { DLEP_IPV6_ADDRESS_TLV, 17, 17 },
132   { DLEP_IPV6_SUBNET_TLV, 18, 18 },
133 };
134
135 /* DLEP base extension, radio side */
136 static struct dlep_extension _base_ip = {
137   .id = DLEP_EXTENSION_BASE_IP,
138   .name = "base metric",
139
140   .signals = _signals,
141   .signal_count = ARRAYSIZE(_signals),
142   .tlvs = _tlvs,
143   .tlv_count = ARRAYSIZE(_tlvs),
144
145   .cb_session_init_radio = _cb_session_init,
146   .cb_session_init_router = _cb_session_init,
147
148   .cb_session_cleanup_radio = _cb_session_cleanup,
149   .cb_session_cleanup_router = _cb_session_cleanup,
150 };
151
152 static struct oonf_class _prefix_class = {
153   .name = "dlep ip prefix",
154   .size = sizeof(struct _prefix_storage),
155 };
156
157 static struct oonf_class_extension _l2_interface_ip_listener = {
158   .ext_name = "dlep l2 if-ip",
159   .class_name = LAYER2_CLASS_NETWORK_ADDRESS,
160
161   .cb_add = _cb_add_if_ip,
162   .cb_remove = _cb_remove_if_ip,
163 };
164
165 static struct oonf_class_extension _l2_neighbor_ip_listener = {
166   .ext_name = "dlep l2 neigh-ip",
167   .class_name = LAYER2_CLASS_NEIGHBOR_ADDRESS,
168
169   .cb_add = _cb_add_neigh_ip,
170   .cb_remove = _cb_remove_neigh_ip,
171 };
172
173 /**
174  * Initialize the base metric DLEP extension
175  * @return this extension
176  */
177 struct dlep_extension *
178 dlep_base_ip_init(void) {
179   dlep_extension_add(&_base_ip);
180   oonf_class_add(&_prefix_class);
181   oonf_class_extension_add(&_l2_interface_ip_listener);
182   oonf_class_extension_add(&_l2_neighbor_ip_listener);
183
184   return &_base_ip;
185 }
186
187 void
188 dlep_base_ip_cleanup(void) {
189   oonf_class_extension_remove(&_l2_neighbor_ip_listener);
190   oonf_class_extension_remove(&_l2_interface_ip_listener);
191   oonf_class_remove(&_prefix_class);
192 }
193
194 static void
195 _cb_session_init(struct dlep_session *session) {
196   struct oonf_layer2_neighbor_address *l2neigh_ip;
197   struct oonf_layer2_neigh *l2neigh;
198   struct oonf_layer2_peer_address *l2net_ip;
199   struct oonf_layer2_net *l2net;
200   struct dlep_local_neighbor *dlep_neighbor;
201
202   l2net = oonf_layer2_net_get(session->l2_listener.name);
203   if (!l2net) {
204     return;
205   }
206
207   avl_for_each_element(&l2net->local_peer_ips, l2net_ip, _net_node) {
208     _add_prefix(&session->_ip_prefix_modification, &l2net_ip->ip, true);
209   }
210
211   avl_for_each_element(&l2net->neighbors, l2neigh, _node) {
212     dlep_neighbor = dlep_session_add_local_neighbor(session, &l2neigh->key);
213     if (dlep_neighbor) {
214       avl_for_each_element(&l2neigh->remote_neighbor_ips, l2neigh_ip, _neigh_node) {
215         _add_prefix(&dlep_neighbor->_ip_prefix_modification, &l2neigh_ip->ip, true);
216       }
217     }
218   }
219 }
220
221 static void
222 _cb_session_cleanup(struct dlep_session *session) {
223   struct dlep_local_neighbor *l2neigh;
224   struct _prefix_storage *storage, *storage_it;
225
226   /* remove all stored changes for neighbors */
227   avl_for_each_element(&session->local_neighbor_tree, l2neigh, _node) {
228     avl_for_each_element_safe(&l2neigh->_ip_prefix_modification, storage, _node, storage_it) {
229       avl_remove(&l2neigh->_ip_prefix_modification, &storage->_node);
230       oonf_class_free(&_prefix_class, storage);
231     }
232   }
233
234   /* remove all stored changes for the local peer */
235   avl_for_each_element_safe(&session->_ip_prefix_modification, storage, _node, storage_it) {
236     avl_remove(&session->_ip_prefix_modification, &storage->_node);
237     oonf_class_free(&_prefix_class, storage);
238   }
239 }
240
241 static int
242 _radio_write_session_update(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session,
243   const struct oonf_layer2_neigh_key *neigh __attribute__((unused))) {
244   struct _prefix_storage *storage, *storage_it;
245
246   struct netaddr_str nbuf;
247
248   avl_for_each_element(&session->_ip_prefix_modification, storage, _node) {
249     OONF_INFO(session->log_source, "Add '%s' (%s) to session update", netaddr_to_string(&nbuf, &storage->prefix),
250       storage->add ? "add" : "remove");
251     if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, storage->add)) {
252       OONF_WARN(session->log_source, "Cannot add '%s' (%s) to session update",
253         netaddr_to_string(&nbuf, &storage->prefix), storage->add ? "add" : "remove");
254       return -1;
255     }
256   }
257
258   /* no error, now remove elements from temporary storage */
259   avl_for_each_element_safe(&session->_ip_prefix_modification, storage, _node, storage_it) {
260     avl_remove(&session->_ip_prefix_modification, &storage->_node);
261     oonf_class_free(&_prefix_class, storage);
262   }
263   return 0;
264 }
265
266 static int
267 _radio_write_destination_update(struct dlep_extension *ext __attribute__((unused)), struct dlep_session *session,
268     const struct oonf_layer2_neigh_key *neigh) {
269   struct dlep_local_neighbor *dlep_neigh;
270   struct _prefix_storage *storage, *storage_it;
271
272   union oonf_layer2_neigh_key_str nkbuf;
273   struct netaddr_str nbuf1;
274
275   dlep_neigh = dlep_session_get_local_neighbor(session, neigh);
276   if (!dlep_neigh) {
277     OONF_WARN(session->log_source,
278       "Could not find dlep_neighbor for neighbor %s",
279       oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true));
280     return -1;
281   }
282
283   /* send every attached IP towards the router */
284   avl_for_each_element(&dlep_neigh->_ip_prefix_modification, storage, _node) {
285     OONF_INFO(session->log_source, "add '%s' (%s) to destination update %s",
286       netaddr_to_string(&nbuf1, &storage->prefix), storage->add ? "add" : "remove",
287       oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true));
288     if (dlep_writer_add_ip_tlv(&session->writer, &storage->prefix, storage->add)) {
289       OONF_WARN(session->log_source, "Cannot add '%s' (%s) to destination update %s",
290         netaddr_to_string(&nbuf1, &storage->prefix), storage->add ? "add" : "remove",
291         oonf_layer2_neigh_key_to_string(&nkbuf, neigh, true));
292       return -1;
293     }
294   }
295
296   /* no error, now remove elements from temporary storage */
297   avl_for_each_element_safe(&dlep_neigh->_ip_prefix_modification, storage, _node, storage_it) {
298     avl_remove(&dlep_neigh->_ip_prefix_modification, &storage->_node);
299     oonf_class_free(&_prefix_class, storage);
300   }
301   return 0;
302 }
303
304 static void
305 _process_session_ip_tlvs(
306   const struct oonf_layer2_origin *origin, struct oonf_layer2_net *l2net, struct netaddr *ip, bool add) {
307   struct oonf_layer2_peer_address *l2addr;
308
309   if (add) {
310     oonf_layer2_net_add_ip(l2net, origin, ip);
311   }
312   else if ((l2addr = oonf_layer2_net_get_local_ip(l2net, ip))) {
313     oonf_layer2_net_remove_ip(l2addr, origin);
314   }
315 }
316
317 static enum dlep_parser_error
318 _router_process_session_update(struct dlep_extension *ext __attribute((unused)), struct dlep_session *session) {
319   struct oonf_layer2_net *l2net;
320   struct netaddr ip;
321   struct dlep_parser_value *value;
322   bool add_ip;
323
324   l2net = oonf_layer2_net_get(session->l2_listener.name);
325   if (!l2net) {
326     return 0;
327   }
328
329   /* ipv4 address */
330   value = dlep_session_get_tlv_value(session, DLEP_IPV4_ADDRESS_TLV);
331   while (value) {
332     if (dlep_reader_ipv4_tlv(&ip, &add_ip, session, value)) {
333       return -1;
334     }
335     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
336     value = dlep_session_get_next_tlv_value(session, value);
337   }
338
339   /* ipv6 address */
340   value = dlep_session_get_tlv_value(session, DLEP_IPV6_ADDRESS_TLV);
341   while (value) {
342     if (dlep_reader_ipv6_tlv(&ip, &add_ip, session, value)) {
343       return -1;
344     }
345     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
346     value = dlep_session_get_next_tlv_value(session, value);
347   }
348
349   /* ipv4 subnet */
350   value = dlep_session_get_tlv_value(session, DLEP_IPV4_SUBNET_TLV);
351   while (value) {
352     if (dlep_reader_ipv4_subnet_tlv(&ip, &add_ip, session, value)) {
353       return -1;
354     }
355     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
356     value = dlep_session_get_next_tlv_value(session, value);
357   }
358
359   /* ipv6 subnet */
360   value = dlep_session_get_tlv_value(session, DLEP_IPV6_SUBNET_TLV);
361   while (value) {
362     if (dlep_reader_ipv6_subnet_tlv(&ip, &add_ip, session, value)) {
363       return -1;
364     }
365     _process_session_ip_tlvs(session->l2_origin, l2net, &ip, add_ip);
366     value = dlep_session_get_next_tlv_value(session, value);
367   }
368   return 0;
369 }
370
371 static void
372 _process_destination_ip_tlv(
373   const struct oonf_layer2_origin *origin, struct oonf_layer2_neigh *l2neigh, struct netaddr *ip, bool add) {
374   struct oonf_layer2_neighbor_address *l2addr;
375
376   if (add) {
377     oonf_layer2_neigh_add_ip(l2neigh, origin, ip);
378   }
379   else if ((l2addr = oonf_layer2_neigh_get_remote_ip(l2neigh, ip))) {
380     oonf_layer2_neigh_remove_ip(l2addr, origin);
381   }
382 }
383
384 static enum dlep_parser_error
385 _router_process_destination_update(struct dlep_extension *ext __attribute((unused)), struct dlep_session *session) {
386   struct oonf_layer2_neigh *l2neigh;
387   struct netaddr ip;
388   struct dlep_parser_value *value;
389   bool add_ip;
390
391   l2neigh = dlep_extension_get_l2_neighbor(session);
392   if (!l2neigh) {
393     return 0;
394   }
395
396   /* ipv4 address */
397   value = dlep_session_get_tlv_value(session, DLEP_IPV4_ADDRESS_TLV);
398   while (value) {
399     if (dlep_reader_ipv4_tlv(&ip, &add_ip, session, value)) {
400       return -1;
401     }
402     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
403     value = dlep_session_get_next_tlv_value(session, value);
404   }
405
406   /* ipv6 address */
407   value = dlep_session_get_tlv_value(session, DLEP_IPV6_ADDRESS_TLV);
408   while (value) {
409     if (dlep_reader_ipv6_tlv(&ip, &add_ip, session, value)) {
410       return -1;
411     }
412     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
413     value = dlep_session_get_next_tlv_value(session, value);
414   }
415
416   /* ipv4 subnet */
417   value = dlep_session_get_tlv_value(session, DLEP_IPV4_SUBNET_TLV);
418   while (value) {
419     if (dlep_reader_ipv4_subnet_tlv(&ip, &add_ip, session, value)) {
420       return -1;
421     }
422     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
423     value = dlep_session_get_next_tlv_value(session, value);
424   }
425
426   /* ipv6 subnet */
427   value = dlep_session_get_tlv_value(session, DLEP_IPV6_SUBNET_TLV);
428   while (value) {
429     if (dlep_reader_ipv6_subnet_tlv(&ip, &add_ip, session, value)) {
430       return -1;
431     }
432     _process_destination_ip_tlv(session->l2_origin, l2neigh, &ip, add_ip);
433     value = dlep_session_get_next_tlv_value(session, value);
434   }
435   return 0;
436 }
437
438 static void
439 _add_prefix(struct avl_tree *tree, struct netaddr *addr, bool add) {
440   struct _prefix_storage *storage;
441
442   storage = avl_find_element(tree, addr, storage, _node);
443   if (storage) {
444     storage->add = add;
445     return;
446   }
447
448   storage = oonf_class_malloc(&_prefix_class);
449   if (!storage) {
450     return;
451   }
452
453   /* copy key and put into tree */
454   memcpy(&storage->prefix, addr, sizeof(*addr));
455   storage->_node.key = &storage->prefix;
456   avl_insert(tree, &storage->_node);
457
458   storage->add = add;
459 }
460
461 static void
462 _modify_if_ip(const char *if_name, struct netaddr *prefix, bool add) {
463   struct dlep_radio_if *interf;
464   struct dlep_radio_session *radio_session;
465
466   avl_for_each_element(dlep_if_get_tree(true), interf, interf._node) {
467     if (strcmp(interf->interf.l2_ifname, if_name) == 0) {
468       avl_for_each_element(&interf->interf.session_tree, radio_session, _node) {
469         _add_prefix(&radio_session->session._ip_prefix_modification, prefix, add);
470       }
471     }
472   }
473 }
474
475 static void
476 _cb_add_if_ip(void *ptr) {
477   struct oonf_layer2_peer_address *peer_ip = ptr;
478   _modify_if_ip(peer_ip->l2net->name, &peer_ip->ip, true);
479 }
480
481 static void
482 _cb_remove_if_ip(void *ptr) {
483   struct oonf_layer2_peer_address *peer_ip = ptr;
484   _modify_if_ip(peer_ip->l2net->name, &peer_ip->ip, false);
485 }
486
487 static void
488 _modify_neigh_ip(const char *if_name, struct oonf_layer2_neigh_key *neighbor, struct netaddr *prefix, bool add) {
489   struct dlep_radio_if *radio_interf;
490   struct dlep_local_neighbor *dlep_neighbor;
491   struct dlep_radio_session *radio_session;
492
493   avl_for_each_element(dlep_if_get_tree(true), radio_interf, interf._node) {
494     if (strcmp(radio_interf->interf.l2_ifname, if_name) == 0) {
495       avl_for_each_element(&radio_interf->interf.session_tree, radio_session, _node) {
496         dlep_neighbor = dlep_session_add_local_neighbor(&radio_session->session, neighbor);
497         if (dlep_neighbor) {
498           _add_prefix(&dlep_neighbor->_ip_prefix_modification, prefix, add);
499         }
500       }
501     }
502   }
503 }
504
505 static void
506 _cb_add_neigh_ip(void *ptr) {
507   struct oonf_layer2_neighbor_address *neigh_ip = ptr;
508   _modify_neigh_ip(neigh_ip->l2neigh->network->name, &neigh_ip->l2neigh->key, &neigh_ip->ip, true);
509 }
510
511 static void
512 _cb_remove_neigh_ip(void *ptr) {
513   struct oonf_layer2_neighbor_address *neigh_ip = ptr;
514   _modify_neigh_ip(neigh_ip->l2neigh->network->name, &neigh_ip->l2neigh->key, &neigh_ip->ip, false);
515 }