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