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