Merge branch 'master' into scheduler_cleanup
[olsrd.git] / src / hna_set.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2009, 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 "hna_set.h"
43 #include "ipcalc.h"
44 #include "defs.h"
45 #include "parser.h"
46 #include "olsr.h"
47 #include "olsr_timer.h"
48 #include "olsr_socket.h"
49 #include "net_olsr.h"
50 #include "tc_set.h"
51 #include "olsr_ip_prefix_list.h"
52 #include "olsr_logging.h"
53
54 /* Some cookies for stats keeping */
55 static struct olsr_timer_info *hna_net_timer_info = NULL;
56 static struct olsr_memcookie_info *hna_net_mem_cookie = NULL;
57
58 static void olsr_expire_hna_net_entry(void *context);
59
60 /**
61  * Initialize the HNA set
62  */
63 void
64 olsr_init_hna_set(void)
65 {
66   OLSR_INFO(LOG_HNA, "Initialize HNA set...\n");
67
68   hna_net_timer_info = olsr_timer_add("HNA Network", &olsr_expire_hna_net_entry, false);
69
70   hna_net_mem_cookie = olsr_memcookie_add("hna_net", sizeof(struct hna_net));
71 }
72
73 /**
74  * Lookup a network entry in the HNA subtree.
75  *
76  * @param tc the HNA hookup point
77  * @param prefic the prefix to look for
78  *
79  * @return the localized entry or NULL of not found
80  */
81 static struct hna_net *
82 olsr_lookup_hna_net(struct tc_entry *tc, const struct olsr_ip_prefix *prefix)
83 {
84   struct hna_net *hna;
85
86   hna = avl_find_element(&tc->hna_tree, prefix, hna, hna_tc_node);
87   return hna;
88 }
89
90 /**
91  * Adds a network entry to a HNA gateway.
92  *
93  * @param tc the gateway entry to add the network to
94  * @param net the nework prefix to add
95  * @param prefixlen the prefix length
96  *
97  * @return the newly created entry
98  */
99 static struct hna_net *
100 olsr_add_hna_net(struct tc_entry *tc, const struct olsr_ip_prefix *prefix)
101 {
102   /* Add the net */
103   struct hna_net *new_net = olsr_memcookie_malloc(hna_net_mem_cookie);
104
105   /* Fill struct */
106   new_net->hna_prefix = *prefix;
107
108   /* Set backpointer */
109   new_net->hna_tc = tc;
110
111   /*
112    * Insert into the per-tc hna subtree.
113    */
114   new_net->hna_tc_node.key = &new_net->hna_prefix;
115   avl_insert(&tc->hna_tree, &new_net->hna_tc_node);
116
117   return new_net;
118 }
119
120 /**
121  * Delete a single HNA network.
122  *
123  * @param hna_net the hna_net to delete.
124  */
125 static void
126 olsr_delete_hna_net(struct hna_net *hna_net)
127 {
128   struct tc_entry *tc = hna_net->hna_tc;
129
130   /*
131    * Delete the rt_path for the hna_net.
132    */
133   olsr_delete_routing_table(&hna_net->hna_prefix.prefix, hna_net->hna_prefix.prefix_len, &tc->addr, OLSR_RT_ORIGIN_HNA);
134
135   /*
136    * Remove from the per-tc tree.
137    */
138   avl_delete(&tc->hna_tree, &hna_net->hna_tc_node);
139
140   if (hna_net->hna_net_timer) {
141     olsr_timer_stop(hna_net->hna_net_timer);
142     hna_net->hna_net_timer = NULL;
143   }
144   /*
145    * Unlock and free.
146    */
147   olsr_memcookie_free(hna_net_mem_cookie, hna_net);
148 }
149
150 /**
151  * Delete all the HNA nets hanging off a tc entry.
152  *
153  * @param entry the tc entry holding the HNA networks.
154  */
155 void
156 olsr_flush_hna_nets(struct tc_entry *tc)
157 {
158   struct hna_net *hna_net, *iterator;
159
160 #if !defined REMOVE_LOG_DEBUG
161   struct ipaddr_str buf;
162 #endif
163
164   OLSR_DEBUG(LOG_TC, "flush hna nets of '%s' (%u)\n", olsr_ip_to_string(&buf, &tc->addr), tc->edge_tree.count);
165   OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna_net, iterator) {
166     olsr_delete_hna_net(hna_net);
167   }
168 }
169
170 /**
171  * Callback for the hna_net timer.
172  */
173 static void
174 olsr_expire_hna_net_entry(void *context)
175 {
176   struct hna_net *hna_net = context;
177 #if !defined REMOVE_LOG_DEBUG
178   struct ipaddr_str buf;
179   struct ipprefix_str prefixstr;
180 #endif
181
182   OLSR_DEBUG(5, "HNA: timeout %s via hna-gw %s\n",
183              olsr_ip_prefix_to_string(&prefixstr, &hna_net->hna_prefix), olsr_ip_to_string(&buf, &hna_net->hna_tc->addr));
184
185   hna_net->hna_net_timer = NULL;        /* be pedandic */
186
187   olsr_delete_hna_net(hna_net);
188 }
189
190 /**
191  * Update a HNA entry. If it does not exist it
192  * is created.
193  * This is the only function that should be called
194  * from outside concerning creation of HNA entries.
195  *
196  *@param gw address of the gateway
197  *@param net address of the network
198  *@param mask the netmask
199  *@param vtime the validitytime of the entry
200  *
201  *@return nada
202  */
203 static void
204 olsr_update_hna_entry(const union olsr_ip_addr *gw, const struct olsr_ip_prefix *prefix, uint32_t vtime,
205     uint16_t msg_seq)
206 {
207   struct tc_entry *tc = olsr_locate_tc_entry(gw);
208   struct hna_net *net_entry = olsr_lookup_hna_net(tc, prefix);
209
210   if (net_entry == NULL) {
211     /* Need to add the net */
212     net_entry = olsr_add_hna_net(tc, prefix);
213     changes_hna = true;
214   }
215
216   net_entry->tc_entry_seqno = msg_seq;
217
218   /*
219    * Add the rt_path for the entry.
220    */
221   olsr_insert_routing_table(&net_entry->hna_prefix.prefix, net_entry->hna_prefix.prefix_len, &tc->addr, OLSR_RT_ORIGIN_HNA);
222
223   /*
224    * Start, or refresh the timer, whatever is appropriate.
225    */
226   olsr_timer_set(&net_entry->hna_net_timer, vtime,
227                  OLSR_HNA_NET_JITTER, net_entry, hna_net_timer_info);
228 }
229
230 /**
231  * Print all HNA entries.
232  *
233  *@return nada
234  */
235 void
236 olsr_print_hna_set(void)
237 {
238   /* The whole function doesn't do anything else. */
239 #if !defined REMOVE_LOG_INFO
240   struct tc_entry *tc, *tc_iterator;
241   struct ipaddr_str buf;
242   struct ipprefix_str prefixstr;
243   struct timeval_buf timebuf;
244   struct hna_net *hna_net, *hna_iterator;
245
246   OLSR_INFO(LOG_HNA, "\n--- %s ------------------------------------------------- HNA\n\n",
247       olsr_timer_getWallclockString(&timebuf));
248
249   OLSR_FOR_ALL_TC_ENTRIES(tc, tc_iterator) {
250     OLSR_INFO_NH(LOG_HNA, "HNA-gw %s:\n", olsr_ip_to_string(&buf, &tc->addr));
251
252     OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna_net, hna_iterator) {
253       OLSR_INFO_NH(LOG_HNA, "\t%-27s\n", olsr_ip_prefix_to_string(&prefixstr, &hna_net->hna_prefix));
254     }
255   }
256 #endif
257 }
258
259 static void
260 olsr_prune_hna_entries(struct tc_entry *tc)
261 {
262   struct hna_net *hna_net, *iterator;
263
264   OLSR_FOR_ALL_TC_HNA_ENTRIES(tc, hna_net, iterator) {
265     if (hna_net->tc_entry_seqno != tc->hna_seq) {
266       olsr_delete_hna_net(hna_net);
267     }
268   }
269 }
270
271 /**
272  * Process incoming HNA message.
273  * Forwards the message if that is to be done.
274  */
275 void
276 olsr_input_hna(struct olsr_message *msg,
277     struct interface *in_if __attribute__ ((unused)),
278     union olsr_ip_addr *from_addr, enum duplicate_status status)
279 {
280   struct tc_entry *tc;
281   struct olsr_ip_prefix prefix;
282   const uint8_t *curr;
283 #if !defined REMOVE_LOG_DEBUG
284   struct ipaddr_str buf;
285 #endif
286
287
288   /* We are only interested in MID message types. */
289   if (msg->type != HNA_MESSAGE) {
290     return;
291   }
292
293   /*
294    * If the sender interface (NB: not originator) of this message
295    * is not in the symmetric 1-hop neighborhood of this node, the
296    * message MUST be discarded.
297    */
298   if (check_neighbor_link(from_addr) != SYM_LINK) {
299     OLSR_DEBUG(LOG_HNA, "Received HNA from NON SYM neighbor %s\n", olsr_ip_to_string(&buf, from_addr));
300     return;
301   }
302
303   tc = olsr_locate_tc_entry(&msg->originator);
304   if (status != RESET_SEQNO_OLSR_MESSAGE && tc->hna_seq != -1 && olsr_seqno_diff(msg->seqno, tc->hna_seq) <= 0) {
305     /* this HNA is too old, discard it */
306     return;
307   }
308   tc->hna_seq = msg->seqno;
309
310   OLSR_DEBUG(LOG_HNA, "Processing HNA from %s, seq 0x%04x\n", olsr_ip_to_string(&buf, &msg->originator), msg->seqno);
311
312   /*
313    * Now walk the list of HNA advertisements.
314    */
315   curr = msg->payload;
316   while (curr + 2*olsr_cnf->ipsize <= msg->end) {
317     pkt_get_ipaddress(&curr, &prefix.prefix);
318     pkt_get_prefixlen(&curr, &prefix.prefix_len);
319
320     if (!ip_prefix_list_find(&olsr_cnf->hna_entries, &prefix.prefix, prefix.prefix_len, olsr_cnf->ip_version)) {
321       /*
322        * Only update if it's not from us.
323        */
324       olsr_update_hna_entry(&msg->originator, &prefix, msg->vtime, msg->seqno);
325     }
326   }
327
328   /*
329    * Prune the HNAs that did not get refreshed by this advertisment.
330    */
331   olsr_prune_hna_entries(tc);
332 }
333
334 void
335 generate_hna(void *p __attribute__ ((unused))) {
336   struct interface *ifp, *ifp_iterator;
337   struct ip_prefix_entry *h, *h_iterator;
338   uint8_t msg_buffer[MAXMESSAGESIZE - OLSR_HEADERSIZE] __attribute__ ((aligned));
339   uint8_t *curr = msg_buffer;
340   uint8_t *length_field, *last;
341   bool sendHNA = false;
342
343   OLSR_INFO(LOG_PACKET_CREATION, "Building HNA\n-------------------\n");
344
345   pkt_put_u8(&curr, HNA_MESSAGE);
346   pkt_put_reltime(&curr, olsr_cnf->hna_params.validity_time);
347
348   length_field = curr;
349   pkt_put_u16(&curr, 0); /* put in real messagesize later */
350
351   pkt_put_ipaddress(&curr, &olsr_cnf->router_id);
352
353   pkt_put_u8(&curr, 255);
354   pkt_put_u8(&curr, 0);
355   pkt_put_u16(&curr, get_msg_seqno());
356
357   last = msg_buffer + sizeof(msg_buffer) - olsr_cnf->ipsize;
358   OLSR_FOR_ALL_IPPREFIX_ENTRIES(&olsr_cnf->hna_entries, h, h_iterator) {
359     union olsr_ip_addr subnet;
360
361     olsr_prefix_to_netmask(&subnet, h->net.prefix_len);
362     sendHNA = true;
363     pkt_put_ipaddress(&curr, &h->net.prefix);
364     pkt_put_ipaddress(&curr, &subnet);
365   }
366
367   if (!sendHNA) {
368     return;
369   }
370
371   pkt_put_u16(&length_field, curr - msg_buffer);
372
373   OLSR_FOR_ALL_INTERFACES(ifp, ifp_iterator) {
374     if (net_outbuffer_bytes_left(ifp) < curr - msg_buffer) {
375       net_output(ifp);
376       set_buffer_timer(ifp);
377     }
378     net_outbuffer_push(ifp, msg_buffer, curr - msg_buffer);
379   }
380 }
381
382 /*
383  * Local Variables:
384  * c-basic-offset: 2
385  * indent-tabs-mode: nil
386  * End:
387  */