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