Fixes for OLSRd2 build process
[oonf.git] / src-plugins / olsrv2 / route_modifier / route_modifier.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/autobuf.h"
43 #include "common/avl.h"
44 #include "common/avl_comp.h"
45 #include "common/common_types.h"
46 #include "common/list.h"
47 #include "common/netaddr.h"
48 #include "common/netaddr_acl.h"
49
50 #include "core/oonf_logging.h"
51 #include "core/oonf_subsystem.h"
52 #include "subsystems/oonf_class.h"
53
54 #include "olsrv2/olsrv2.h"
55 #include "olsrv2/olsrv2_routing.h"
56
57 #include "route_modifier/route_modifier.h"
58
59 /* definitions */
60 struct _routemodifier {
61   /* name of the routing filter */
62   char name[16];
63
64   /* domain of the routing filter */
65   int32_t domain;
66
67   /* address filter */
68   struct netaddr_acl filter;
69   int32_t prefix_length;
70
71   /* modifiers of routes that match the filter, 0 if not modified */
72   int32_t table;
73   int32_t protocol;
74   int32_t distance;
75
76   /* tree of all configured routing filters */
77   struct avl_node _node;
78 };
79
80 /* prototypes */
81 static int _init(void);
82 static void _cleanup(void);
83
84 static struct _routemodifier *_get_modifier(const char *name);
85 static void _destroy_modifier(struct _routemodifier *);
86
87 static bool _cb_rt_filter(struct nhdp_domain *, struct os_route *);
88 static void _cb_cfg_changed(void);
89
90 /* plugin declaration */
91 static struct cfg_schema_entry _modifier_entries[] = {
92   CFG_MAP_INT32_MINMAX(_routemodifier, domain, "domain", "0",
93       "Routing domain id for filter", 0, false, 0, 255),
94   CFG_MAP_ACL(_routemodifier, filter, "matches",
95       ACL_FIRST_REJECT "\0" ACL_DEFAULT_REJECT,
96       "Ip addresses the filter should be applied to"),
97   CFG_MAP_INT32_MINMAX(_routemodifier, prefix_length, "prefix_length", "-1",
98       "Prefix length the filter should be applied to, -1 for any prefix length",
99       0, false, -1, 128),
100   CFG_MAP_INT32_MINMAX(_routemodifier, table, "table", "0",
101       "Set routing table of matching routes to this value", 0, false, 0, 255),
102   CFG_MAP_INT32_MINMAX(_routemodifier, protocol, "protocol", "0",
103       "Set routing protocol of matching routes to this value", 0, false, 0, 255),
104   CFG_MAP_INT32_MINMAX(_routemodifier, distance, "metric", "0",
105       "Set routing metric of matching routes to this value", 0, false, 0, INT32_MAX),
106 };
107
108 static struct cfg_schema_section _modifier_section = {
109   .type = OONF_ROUTE_MODIFIER_SUBSYSTEM,
110   .mode = CFG_SSMODE_NAMED_WITH_DEFAULT,
111   .def_name = "0",
112
113   .cb_delta_handler = _cb_cfg_changed,
114
115   .entries = _modifier_entries,
116   .entry_count = ARRAYSIZE(_modifier_entries),
117 };
118
119 static const char *_dependencies[] = {
120   OONF_CLASS_SUBSYSTEM,
121   OONF_OLSRV2_SUBSYSTEM,
122 };
123 struct oonf_subsystem olsrv2_routemodifier_subsystem = {
124   .name = OONF_ROUTE_MODIFIER_SUBSYSTEM,
125   .dependencies = _dependencies,
126   .dependencies_count = ARRAYSIZE(_dependencies),
127   .descr = "OLSRv2 route-modifier plugin",
128   .author = "Henning Rogge",
129
130   .cfg_section = &_modifier_section,
131
132   .init = _init,
133   .cleanup = _cleanup,
134 };
135 DECLARE_OONF_PLUGIN(olsrv2_routemodifier_subsystem);
136
137 /* class definition for filters */
138 static struct oonf_class _modifier_class = {
139   .name = "routemodifier filter",
140   .size = sizeof(struct _routemodifier),
141 };
142
143 /* callback filter for dijkstra */
144 static struct olsrv2_routing_filter _dijkstra_filter = {
145   .filter = _cb_rt_filter,
146 };
147
148 /* tree of routing filters */
149 static struct avl_tree _modifier_tree;
150
151 /**
152  * Initialize plugin
153  * @return always returns 0 (cannot fail)
154  */
155 static int
156 _init(void) {
157   avl_init(&_modifier_tree, avl_comp_strcasecmp, false);
158   oonf_class_add(&_modifier_class);
159   olsrv2_routing_filter_add(&_dijkstra_filter);
160   return 0;
161 }
162
163 /**
164  * Cleanup plugin
165  */
166 static void
167 _cleanup(void) {
168   struct _routemodifier *mod, *mod_it;
169
170   avl_for_each_element_safe(&_modifier_tree, mod, _node, mod_it) {
171     _destroy_modifier(mod);
172   }
173
174   olsrv2_routing_filter_remove(&_dijkstra_filter);
175   oonf_class_remove(&_modifier_class);
176 }
177
178 /**
179  * Callback for Dijkstra code to see which route should be changed
180  * @param domain pointer to domain of route
181  * @param route routing data
182  * @return always true (we never drop a route)
183  */
184 static bool
185 _cb_rt_filter(struct nhdp_domain *domain, struct os_route *route) {
186   struct _routemodifier *modifier;
187 #ifdef OONF_LOG_DEBUG_INFO
188   struct netaddr_str nbuf;
189 #endif
190
191   avl_for_each_element(&_modifier_tree, modifier, _node) {
192     /* check filter matches this domain */
193     if (domain->index != modifier->domain) {
194       continue;
195     }
196
197     /* check prefix length */
198     if (modifier->prefix_length != -1
199         && modifier->prefix_length != netaddr_get_prefix_length(&route->dst)) {
200       continue;
201     }
202
203     /* check if destination matches */
204     if (!netaddr_acl_check_accept(&modifier->filter, &route->dst)) {
205       continue;
206     }
207
208     /* apply modifiers */
209     if (modifier->table) {
210       OONF_DEBUG(LOG_ROUTE_MODIFIER, "Modify routing table for route to %s: %d",
211           netaddr_to_string(&nbuf, &route->dst), modifier->table);
212       route->table = modifier->table;
213     }
214     if (modifier->protocol) {
215       OONF_DEBUG(LOG_ROUTE_MODIFIER, "Modify routing protocol for route to %s: %d",
216           netaddr_to_string(&nbuf, &route->dst), modifier->protocol);
217       route->protocol = modifier->protocol;
218     }
219     if (modifier->distance) {
220       OONF_DEBUG(LOG_ROUTE_MODIFIER, "Modify routing distance for route to %s: %d",
221           netaddr_to_string(&nbuf, &route->dst), modifier->distance);
222       route->metric = modifier->distance;
223     }
224     break;
225   }
226   return true;
227 }
228
229 /**
230  * Lookups a route modifier or create a new one
231  * @param name name of route modifier
232  * @return pointer to route modifier or NULL if out of memory
233  */
234 static struct _routemodifier *
235 _get_modifier(const char *name) {
236   struct _routemodifier *mod;
237
238   mod = avl_find_element(&_modifier_tree, name, mod, _node);
239   if (mod) {
240     return mod;
241   }
242
243   mod = oonf_class_malloc(&_modifier_class);
244   if (mod == NULL) {
245     return NULL;
246   }
247
248   /* copy key and add to tree */
249   strscpy(mod->name, name, sizeof(mod->name));
250   mod->_node.key = mod->name;
251   avl_insert(&_modifier_tree, &mod->_node);
252
253   return mod;
254 }
255
256 /**
257  * Free all resources associated with a route modifier
258  * @param mod route modifier
259  */
260 static void
261 _destroy_modifier(struct _routemodifier *mod) {
262   avl_remove(&_modifier_tree, &mod->_node);
263   netaddr_acl_remove(&mod->filter);
264   oonf_class_free(&_modifier_class, mod);
265 }
266
267 /**
268  * Configuration changed
269  */
270 static void
271 _cb_cfg_changed(void) {
272   struct _routemodifier *modifier;
273
274   /* get existing modifier */
275   modifier = _get_modifier(_modifier_section.section_name);
276   if (!modifier) {
277     /* out of memory */
278     return;
279   }
280
281   if (_modifier_section.post == NULL) {
282     /* section was removed */
283     _destroy_modifier(modifier);
284     return;
285   }
286
287   if (cfg_schema_tobin(modifier, _modifier_section.post,
288       _modifier_entries, ARRAYSIZE(_modifier_entries))) {
289     OONF_WARN(LOG_ROUTE_MODIFIER,
290         "Could not convert configuration data of section '%s'",
291         _modifier_section.section_name);
292
293     if (_modifier_section.pre == NULL) {
294       _destroy_modifier(modifier);
295     }
296     return;
297   }
298 }