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