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