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