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