Fix 'inactive' routes when using 'additional' option
[olsrd.git] / lib / quagga / src / quagga.c
1 /*
2  * OLSRd Quagga plugin
3  *
4  * Copyright (C) 2006-2008 Immo 'FaUl' Wehrenberg <immo@chaostreff-dortmund.de>
5  * Copyright (C) 2007-2008 Vasilis Tsiligiannis <acinonyxs@yahoo.gr>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation or - at your option - under
10  * the terms of the GNU General Public Licence version 2 but can be
11  * linked to any BSD-Licenced Software with public available sourcecode
12  *
13  */
14
15 /* -------------------------------------------------------------------------
16  * File               : quagga.c
17  * Description        : functions to interface to the zebra daemon
18  * ------------------------------------------------------------------------- */
19
20
21 #define HAVE_SOCKLEN_T
22
23 #include "quagga.h"
24 #include "olsr.h" /* olsr_exit
25                      olsr_malloc */
26 #include "log.h" /* olsr_syslog */
27 #include "common/string.h" /* strscpy */
28 #include "olsr_ip_prefix_list.h" /* ip_prefix_list_add
29                                     ip_prefix_list_remove */
30
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #ifdef USE_UNIX_DOMAIN_SOCKET
42 #include <sys/un.h>
43 #endif
44
45 export_route_function orig_add_route_function = NULL;
46 export_route_function orig_del_route_function = NULL;
47
48 /* prototypes intern */
49 static struct {
50   char status; // internal status
51   char options; // internal options
52   int sock; // Socket to zebra...
53   char redistribute[ZEBRA_ROUTE_MAX];
54   char distance;
55   char flags;
56   struct zebra_route *v4_rt; // routes currently exportet to zebra
57 } zebra;
58
59 static void *my_realloc (void *, size_t, const char *);
60 static void zebra_connect (void);
61 static unsigned char *try_read (ssize_t *);
62 static int zebra_send_command (unsigned char *);
63 static unsigned char* zebra_route_packet (uint16_t, struct zebra_route *);
64 static unsigned char *zebra_redistribute_packet (unsigned char, unsigned char);
65 static struct zebra_route *zebra_parse_route (unsigned char *);
66 #if 0
67 static void zebra_reconnect (void);
68 #endif
69 static void free_ipv4_route (struct zebra_route *);
70
71
72 static void *my_realloc (void *buf, size_t s, const char *c) {
73   buf = realloc (buf, s);
74   if (!buf) {
75     OLSR_PRINTF (1, "(QUAGGA) OUT OF MEMORY: %s\n", strerror(errno));
76     olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n");
77     olsr_exit(c, EXIT_FAILURE);
78   }
79   return buf;
80 }
81
82
83 void init_zebra (void) {
84   zebra_connect();
85   if (!(zebra.status&STATUS_CONNECTED))
86     olsr_exit ("(QUAGGA) AIIIII, could not connect to zebra! is zebra running?",
87                EXIT_FAILURE);
88 }
89
90
91 void zebra_cleanup (void) {
92   int i;
93   struct rt_entry *tmp;
94
95   if (zebra.options & OPTION_EXPORT) {
96     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
97       zebra_del_route(tmp);
98     } OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
99   }
100
101   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
102     if (zebra.redistribute[i]) zebra_disable_redistribute(i);
103 }
104
105
106 #if 0
107 static void zebra_reconnect (void) {
108   struct rt_entry *tmp;
109   int i;
110
111   zebra_connect();
112   if (!(zebra.status & STATUS_CONNECTED)) return; // try again next time
113
114   if (zebra.options & OPTION_EXPORT) {
115     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
116       zebra_add_route (tmp);
117     } OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
118   }
119
120   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
121     if (zebra.redistribute[i]) zebra_redistribute(i + 1);
122   /* Zebra sends us all routes of type it knows after
123      zebra_redistribute(type) */
124 }
125 #endif
126
127
128 /* Connect to the zebra-daemon, returns a socket */
129 static void zebra_connect (void) {
130
131   int ret;
132
133 #ifndef USE_UNIX_DOMAIN_SOCKET
134   struct sockaddr_in i;
135   if (close (zebra.sock) < 0) olsr_exit ("(QUAGGA) Could not close socket!", EXIT_FAILURE);
136
137
138   zebra.sock = socket (AF_INET,SOCK_STREAM, 0);
139 #else
140   struct sockaddr_un i;
141   if (close (zebra.sock) < 0) olsr_exit ("(QUAGGA) Could not close socket!", EXIT_FAILURE);
142
143   zebra.sock = socket (AF_UNIX,SOCK_STREAM, 0);
144 #endif
145
146   if (zebra.sock <0 )
147     olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
148
149   memset (&i, 0, sizeof i);
150 #ifndef USE_UNIX_DOMAIN_SOCKET
151   i.sin_family = AF_INET;
152   i.sin_port = htons (ZEBRA_PORT);
153   i.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
154 #else
155   i.sun_family = AF_UNIX;
156   strscpy (i.sun_path, ZEBRA_SOCKET, sizeof(i.sun_path));
157 #endif
158
159   ret = connect (zebra.sock, (struct sockaddr *)&i, sizeof i);
160   if  (ret < 0) zebra.status &= ~STATUS_CONNECTED;
161   else zebra.status |= STATUS_CONNECTED;
162 }
163
164
165 /* Sends a command to zebra, command is
166    the command defined in zebra.h, options is the packet-payload,
167    optlen the length, of the payload */
168 static int zebra_send_command (unsigned char *options) {
169
170   unsigned char *pnt;
171   uint16_t len;
172   int ret;
173
174   if (!(zebra.status & STATUS_CONNECTED)) return 0;
175
176   pnt = options;
177   memcpy (&len, pnt, 2);
178
179   len = ntohs(len);
180
181   do {
182     ret = write (zebra.sock, pnt, len);
183     if (ret < 0) {
184       if ((errno == EINTR) || (errno == EAGAIN)) {
185         errno = 0;
186         ret = 0;
187         continue;
188       }
189       else {
190         OLSR_PRINTF (1, "(QUAGGA) Disconnected from zebra\n");
191         zebra.status &= ~STATUS_CONNECTED;
192         free (options);
193         return -1;
194       }
195     }
196     pnt = pnt+ret;
197   } while ((len -= ret));
198   free (options);
199   return 0;
200 }
201
202
203 /* Creates a Route-Packet-Payload, needs address, netmask, nexthop,
204    distance, and a pointer of an size_t */
205 static unsigned char* zebra_route_packet (uint16_t cmd, struct zebra_route *r) {
206
207   int count;
208   uint8_t len;
209   uint16_t size;
210   uint32_t ind, metric;
211
212   unsigned char *cmdopt, *t;
213
214   cmdopt = olsr_malloc (ZEBRA_MAX_PACKET_SIZ , "zebra add_v4_route");
215
216   t = &cmdopt[2];
217   *t++ = cmd;
218   *t++ = r->type;
219   *t++ = r->flags;
220   *t++ = r->message;
221   *t++ = r->prefixlen;
222   len = (r->prefixlen + 7) / 8;
223   memcpy (t, &r->prefix.v4.s_addr, len);
224   t = t + len;
225
226   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
227     *t++ = r->nexthop_num + r->ifindex_num;
228
229       for (count = 0; count < r->nexthop_num; count++)
230         {
231           *t++ = ZEBRA_NEXTHOP_IPV4;
232           memcpy (t, &r->nexthop[count].v4.s_addr,
233                   sizeof r->nexthop[count].v4.s_addr);
234           t += sizeof r->nexthop[count].v4.s_addr;
235         }
236       for (count = 0; count < r->ifindex_num; count++)
237         {
238           *t++ = ZEBRA_NEXTHOP_IFINDEX;
239           ind = htonl(r->ifindex[count]);
240           memcpy (t, &ind, sizeof ind);
241           t += sizeof ind;
242         }
243     }
244   if ((r->message & ZAPI_MESSAGE_DISTANCE) > 0)
245     *t++ = r->distance;
246   if ((r->message & ZAPI_MESSAGE_METRIC) > 0)
247     {
248       metric = htonl (r->metric);
249       memcpy (t, &metric, sizeof metric);
250       t += sizeof metric;
251     }
252   size = htons (t - cmdopt);
253   memcpy (cmdopt, &size, 2);
254
255   return cmdopt;
256 }
257
258
259 /* Check wether there is data from zebra aviable */
260 void zebra_parse (void* foo __attribute__((unused))) {
261   unsigned char *data, *f;
262   unsigned char command;
263   uint16_t length;
264   ssize_t len;
265   struct zebra_route *route;
266
267   if (!(zebra.status & STATUS_CONNECTED)) {
268 //    zebra_reconnect();
269     return;
270   }
271   data = try_read (&len);
272   if (data) {
273     f = data;
274     do {
275       memcpy (&length, f, sizeof length);
276       length = ntohs (length);
277       if (!length) // something wired happened
278         olsr_exit ("(QUAGGA) Zero message length??? ", EXIT_FAILURE);
279       command = f[2];
280       switch (command) {
281         case ZEBRA_IPV4_ROUTE_ADD:
282           route = zebra_parse_route(f);
283           ip_prefix_list_add(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
284           free_ipv4_route (route);
285           free (route);
286           break;
287         case ZEBRA_IPV4_ROUTE_DELETE:
288           route = zebra_parse_route(f);
289           ip_prefix_list_remove(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen, olsr_cnf->ip_version);
290           free_ipv4_route (route);
291           free (route);
292           break;
293         default:
294           break;
295       }
296       f += length;
297     } while ((f - data) < len);
298     free (data);
299   }
300 }
301
302
303 // tries to read a packet from zebra_socket
304 // if there is something to read - make sure to read whole packages
305 static unsigned char *try_read (ssize_t *size) {
306   unsigned char *buf;
307   ssize_t bytes, bufsize;
308   uint16_t length, offset;
309   int sockstatus;
310
311   /* initialize variables */
312   buf = NULL;
313   offset = 0;
314   *size = 0;
315   bufsize = 0;
316
317   /* save socket status and set non-blocking for read */
318   sockstatus = fcntl (zebra.sock, F_GETFL);
319   fcntl (zebra.sock, F_SETFL, sockstatus|O_NONBLOCK);
320
321   /* read whole packages */
322   do {
323
324   /* (re)allocate buffer */
325     if (*size == bufsize) {
326       bufsize += BUFSIZE;
327       buf = my_realloc (buf, bufsize, "Zebra try_read");
328     }
329
330   /* read from socket */
331     bytes = read (zebra.sock, buf + *size, bufsize - *size);
332   /* handle broken packet */
333     if (!bytes) {
334       free (buf);
335       return NULL;
336     }
337   /* handle no data available */
338     if (bytes < 0) {
339   /* handle disconnect */
340       if (errno != EAGAIN) { // oops - we got disconnected
341         OLSR_PRINTF (1, "(QUAGGA) Disconnected from zebra\n");
342         zebra.status &= ~STATUS_CONNECTED;
343       }
344       free (buf);
345       return NULL;
346     }
347
348     *size += bytes;
349
350   /* detect zebra packet fragmentation */
351     do {
352       memcpy (&length, buf + offset, sizeof length);
353       length = ntohs (length);
354       offset += length;
355     } while (*size >= (ssize_t) (offset + sizeof length));
356   /* set blocking socket on fragmented packet */
357     if (*size != offset)
358       fcntl (zebra.sock, F_SETFL, sockstatus);
359
360   } while (*size != offset);
361
362   /* restore socket status */
363   fcntl (zebra.sock, F_SETFL, sockstatus);
364
365   return buf;
366 }
367
368
369 /* Parse an ipv4-route-packet recived from zebra
370  */
371 static struct zebra_route *zebra_parse_route (unsigned char *opt) {
372
373   struct zebra_route *r;
374   int c;
375   size_t size;
376   uint16_t length;
377   unsigned char *pnt;
378
379   memcpy (&length, opt, sizeof length);
380   length = ntohs (length);
381
382   r = olsr_malloc (sizeof *r , "zebra_parse_route");
383   pnt = &opt[3];
384   r->type = *pnt++;
385   r->flags = *pnt++;
386   r->message = *pnt++;
387   r->prefixlen = *pnt++;
388   r->prefix.v4.s_addr = 0;
389
390   size = (r->prefixlen + 7) / 8;
391   memcpy (&r->prefix.v4.s_addr, pnt, size);
392   pnt += size;
393
394   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
395     r->nexthop_num = *pnt++;
396     r->nexthop = olsr_malloc ((sizeof *r->nexthop) * r->nexthop_num,
397         "quagga: zebra_parse_route");
398     for (c = 0; c < r->nexthop_num; c++) {
399       memcpy (&r->nexthop[c].v4.s_addr, pnt, sizeof r->nexthop[c].v4.s_addr);
400       pnt += sizeof r->nexthop[c].v4.s_addr;
401     }
402   }
403
404   if (r->message & ZAPI_MESSAGE_IFINDEX) {
405     r->ifindex_num = *pnt++;
406     r->ifindex = olsr_malloc (sizeof (uint32_t) * r->ifindex_num,
407                             "quagga: zebra_parse_route");
408     for (c = 0; c < r->ifindex_num; c++) {
409       memcpy (&r->ifindex[c], pnt, sizeof r->ifindex[c]);
410       r->ifindex[c] = ntohl (r->ifindex[c]);
411       pnt += sizeof r->ifindex[c];
412     }
413   }
414
415   if (r->message & ZAPI_MESSAGE_DISTANCE) {
416     r->distance = *pnt++;
417   }
418
419 // Quagga v0.98.6 BUG workaround: metric is always sent by zebra
420 // even without ZAPI_MESSAGE_METRIC message.
421 //  if (r.message & ZAPI_MESSAGE_METRIC) {
422     memcpy (&r->metric, pnt, sizeof (uint32_t));
423     r->metric = ntohl (r->metric);
424       pnt += sizeof r->metric;
425 //  }
426
427     if (pnt - opt != length) { olsr_exit ("(QUAGGA) length does not match ??? ", EXIT_FAILURE);
428      }
429
430   return r;
431 }
432
433
434 static unsigned char *zebra_redistribute_packet (unsigned char cmd, unsigned char type) {
435   unsigned char *data, *pnt;
436   uint16_t size;
437
438   data = olsr_malloc (ZEBRA_MAX_PACKET_SIZ , "zebra_redistribute_packet");
439
440   pnt = &data[2];
441   *pnt++ = cmd;
442   *pnt++ = type;
443   size = htons (pnt - data);
444   memcpy (data, &size, 2);
445
446   return data;
447 }
448
449
450 /* start redistribution FROM zebra */
451 int zebra_redistribute (unsigned char type) {
452
453       if (zebra_send_command(zebra_redistribute_packet (ZEBRA_REDISTRIBUTE_ADD, type)) < 0)
454         olsr_exit("(QUAGGA) could not send redistribute add command", EXIT_FAILURE);
455
456   if (type > ZEBRA_ROUTE_MAX-1) return -1;
457   zebra.redistribute[type] = 1;
458
459   return 0;
460
461 }
462
463
464 /* end redistribution FROM zebra */
465 int zebra_disable_redistribute (unsigned char type) {
466
467       if (zebra_send_command(zebra_redistribute_packet (ZEBRA_REDISTRIBUTE_DELETE, type)) < 0)
468         olsr_exit("(QUAGGA) could not send redistribute delete command", EXIT_FAILURE);
469
470   if (type > ZEBRA_ROUTE_MAX-1) return -1;
471   zebra.redistribute[type] = 0;
472
473   return 0;
474
475 }
476
477
478 static void free_ipv4_route (struct zebra_route *r) {
479
480   if(r->ifindex_num) free(r->ifindex);
481   if(r->nexthop_num) free(r->nexthop);
482
483 }
484
485
486 int zebra_add_route (const struct rt_entry *r) {
487
488   struct zebra_route route;
489   int retval;
490
491   route.type = ZEBRA_ROUTE_OLSR;
492   route.flags = zebra.flags;
493   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
494   route.prefixlen = r->rt_dst.prefix_len;
495   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
496   route.ifindex_num = 0;
497   route.ifindex = NULL;
498   route.nexthop_num = 0;
499   route.nexthop = NULL;
500
501   if (r->rt_best->rtp_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr &&
502        route.prefixlen == 32) {
503     route.ifindex_num++;
504     route.ifindex = olsr_malloc (sizeof *route.ifindex,
505                                "zebra_add_route");
506     *route.ifindex = r->rt_best->rtp_nexthop.interface->if_index;
507   }
508   else {
509     route.nexthop_num++;
510     route.nexthop = olsr_malloc (sizeof *route.nexthop, "zebra_add_route");
511     route.nexthop->v4.s_addr = r->rt_best->rtp_nexthop.gateway.v4.s_addr;
512   }
513
514   route.metric = r->rt_best->rtp_metric.hops;
515
516   if (zebra.distance) {
517     route.message |= ZAPI_MESSAGE_DISTANCE;
518     route.distance = zebra.distance;
519   }
520
521   retval = zebra_send_command (zebra_route_packet (ZEBRA_IPV4_ROUTE_ADD, &route));
522   return retval;
523
524 }
525
526 int zebra_del_route (const struct rt_entry *r) {
527
528   struct zebra_route route;
529   int retval;
530   
531   route.type = ZEBRA_ROUTE_OLSR;
532   route.flags = zebra.flags;
533   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
534   route.prefixlen = r->rt_dst.prefix_len;
535   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
536   route.ifindex_num = 0;
537   route.ifindex = NULL;
538   route.nexthop_num = 0;
539   route.nexthop = NULL;
540
541   if (r->rt_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr &&
542        route.prefixlen == 32){
543     route.ifindex_num++;
544     route.ifindex = olsr_malloc (sizeof *route.ifindex,
545                                "zebra_del_route");
546     *route.ifindex = r->rt_nexthop.interface->if_index;
547   }
548   else {
549     route.nexthop_num++;
550     route.nexthop = olsr_malloc (sizeof *route.nexthop, "zebra_del_route");
551     route.nexthop->v4.s_addr = r->rt_nexthop.gateway.v4.s_addr;
552   }
553
554   route.metric = 0;
555
556   if (zebra.distance) {
557     route.message |= ZAPI_MESSAGE_DISTANCE;
558     route.distance = zebra.distance;
559   }
560
561
562   retval = zebra_send_command (zebra_route_packet (ZEBRA_IPV4_ROUTE_DELETE, &route));
563   return retval;
564
565 }
566
567 int zebra_add_route_hook (const struct rt_entry *rt, int ip_version) {
568   int ret = -1;
569   if (AF_INET == ip_version) {
570
571     /* Quagga BUG workaround: don't add routes with destination = gateway
572        see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
573     if (rt->rt_best->rtp_nexthop.gateway.v4.s_addr == rt->rt_dst.prefix.v4.s_addr &&
574         rt->rt_dst.prefix_len == 32) return -1;
575
576     ret = zebra_add_route(rt);
577   }
578   if (NULL != orig_add_route_function) {
579     ret = orig_add_route_function(rt, ip_version);
580   }
581   return ret;
582 }
583
584 int zebra_del_route_hook (const struct rt_entry *rt, int ip_version) {
585   int ret = -1;
586   if (AF_INET == ip_version) {
587
588     /* Quagga BUG workaround: don't delete routes with destination = gateway
589        see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
590     if (rt->rt_nexthop.gateway.v4.s_addr == rt->rt_dst.prefix.v4.s_addr &&
591         rt->rt_dst.prefix_len == 32) return -1;
592
593     ret = zebra_del_route(rt);
594   }
595   if (NULL != orig_del_route_function) {
596     ret = orig_del_route_function(rt, ip_version);
597   }
598   return ret;
599 }
600
601 void zebra_olsr_distance (unsigned char dist) {
602   zebra.distance = dist;
603 }
604
605 void zebra_olsr_localpref (void) {
606   zebra.flags &= ZEBRA_FLAG_SELECTED;
607 }
608
609 void zebra_export_routes (unsigned char t) {
610   if (t)
611     zebra.options |= OPTION_EXPORT;
612   else
613     zebra.options &= ~OPTION_EXPORT;
614 }
615
616 /*
617  * Local Variables:
618  * c-basic-offset: 2
619  * indent-tabs-mode: nil
620  * End:
621  */