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