Rename zebra route structure and members
[olsrd.git] / lib / quagga / src / quagga.c
1
2 /***************************************************************************
3  projekt              : olsrd-quagga
4  file                 : quagga.c
5  usage                : communication with the zebra-daemon
6  copyright            : (C) 2006 by Immo 'FaUl' Wehrenberg
7  e-mail               : immo@chaostreff-dortmund.de
8  ***************************************************************************/
9
10 /***************************************************************************
11  *                                                                         *
12  *   This program is free software; you can redistribute it and/or modify  *
13  *   it under the terms of the GNU General Public License version 2 as     *
14  *   published by the Free Software Foundation.                            *
15  *                                                                         *
16  ***************************************************************************/
17
18 #define HAVE_SOCKLEN_T
19
20 #include "quagga.h"
21 #include "olsr.h" /* olsr_exit
22                      olsr_malloc */
23 #include "log.h" /* olsr_syslog */
24
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35
36 #ifdef USE_UNIX_DOMAIN_SOCKET
37 #include <sys/un.h>
38 #endif
39
40 /* prototypes intern */
41 static struct {
42   char status;                         // internal status
43   char options;                        // internal options
44   int sock;                            // Socket to zebra...
45   char redistribute[ZEBRA_ROUTE_MAX];
46   char distance;
47   char flags;
48   struct zebra_route *v4_rt;           // routes currently exportet to zebra
49 } zebra;
50
51 static unsigned char *zebra_route_packet(uint16_t, struct zebra_route *);
52 static struct zebra_route *zebra_parse_route (unsigned char *);
53 static unsigned char *try_read(ssize_t *);
54 #if 0
55 static void zebra_reconnect(void);
56 #endif
57 static void zebra_connect(void);
58 static void free_ipv4_route(struct zebra_route *);
59
60 void *
61 my_realloc(void *buf, size_t s, const char *c)
62 {
63   buf = realloc(buf, s);
64   if (!buf) {
65     OLSR_PRINTF(1, "(QUAGGA) OUT OF MEMORY: %s\n", strerror(errno));
66     olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n");
67     olsr_exit(c, EXIT_FAILURE);
68   }
69   return buf;
70 }
71
72 void
73 init_zebra(void)
74 {
75   zebra_connect();
76   if (!(zebra.status & STATUS_CONNECTED))
77     olsr_exit("(QUAGGA) AIIIII, could not connect to zebra! is zebra running?", EXIT_FAILURE);
78 }
79
80 void
81 zebra_cleanup(void)
82 {
83   int i;
84   struct rt_entry *tmp;
85
86   if (zebra.options & OPTION_EXPORT) {
87     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
88       zebra_del_route(tmp);
89     }
90     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
91   }
92
93   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
94     if (zebra.redistribute[i])
95       zebra_disable_redistribute(i);
96 }
97
98 #if 0
99 static void
100 zebra_reconnect(void)
101 {
102   struct rt_entry *tmp;
103   int i;
104
105   zebra_connect();
106   if (!(zebra.status & STATUS_CONNECTED))
107     return;                     // try again next time
108
109   if (zebra.options & OPTION_EXPORT) {
110     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
111       zebra_add_route(tmp);
112     }
113     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
114   }
115
116   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
117     if (zebra.redistribute[i])
118       zebra_redistribute(i + 1);
119   /* Zebra sends us all routes of type it knows after
120      zebra_redistribute(type) */
121 }
122 #endif
123
124 /* Connect to the zebra-daemon, returns a socket */
125 static void
126 zebra_connect(void)
127 {
128
129   int ret;
130
131 #ifndef USE_UNIX_DOMAIN_SOCKET
132   struct sockaddr_in i;
133   if (close(zebra.sock) < 0)
134     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
135
136   zebra.sock = socket(AF_INET, SOCK_STREAM, 0);
137 #else
138   struct sockaddr_un i;
139   if (close(zebra.sock) < 0)
140     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
141
142   zebra.sock = socket(AF_UNIX, SOCK_STREAM, 0);
143 #endif
144
145   if (zebra.sock < 0)
146     olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
147
148   memset(&i, 0, sizeof i);
149 #ifndef USE_UNIX_DOMAIN_SOCKET
150   i.sin_family = AF_INET;
151   i.sin_port = htons(ZEBRA_PORT);
152   i.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
153 #else
154   i.sun_family = AF_UNIX;
155   strscpy(i.sun_path, ZEBRA_SOCKET, sizeof(i.sun_path));
156 #endif
157
158   ret = connect(zebra.sock, (struct sockaddr *)&i, sizeof i);
159   if (ret < 0)
160     zebra.status &= ~STATUS_CONNECTED;
161   else
162     zebra.status |= STATUS_CONNECTED;
163 }
164
165 /* Sends a command to zebra, command is
166    the command defined in zebra.h, options is the packet-payload,
167    optlen the length, of the payload */
168 int
169 zebra_send_command(unsigned char *options)
170 {
171
172   unsigned char *pnt;
173   uint16_t len;
174   int ret;
175
176   if (!(zebra.status & STATUS_CONNECTED))
177     return 0;
178
179   pnt = options;
180   memcpy(&len, pnt, 2);
181
182   len = ntohs(len);
183
184   do {
185     ret = write(zebra.sock, pnt, len);
186     if (ret < 0) {
187       if ((errno == EINTR) || (errno == EAGAIN)) {
188         errno = 0;
189         ret = 0;
190         continue;
191       } else {
192         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
193         zebra.status &= ~STATUS_CONNECTED;
194         free(options);
195         return -1;
196       }
197     }
198     pnt = pnt + ret;
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     OLSR_PRINTF(1, "length zebra_parse %u\n", (unsigned int) len);
275     do {
276       memcpy(&length, f, sizeof length);
277       length = ntohs (length);
278       if (!length) // something wired happened
279         olsr_exit("(QUAGGA) Zero message length??? ", EXIT_FAILURE);
280       command = f[2];
281       switch (command) {
282         case ZEBRA_IPV4_ROUTE_ADD:
283           route = zebra_parse_route(f);
284           ip_prefix_list_add(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
285           free_ipv4_route(route);
286           free(route);
287           break;
288         case ZEBRA_IPV4_ROUTE_DELETE:
289           route = zebra_parse_route(f);
290           ip_prefix_list_remove(&olsr_cnf->hna_entries, &route->prefix, route->prefixlen);
291           free_ipv4_route(route);
292           free(route);
293           break;
294         default:
295           break;
296       }
297       f += length;
298     }
299     while ((f - data) < len);
300     free(data);
301   }
302 }
303
304 // tries to read a packet from zebra_socket
305 // if there is something to read - make sure to read whole packages
306 static unsigned char *
307 try_read(ssize_t * len)
308 {
309   unsigned char *buf = NULL;
310   ssize_t ret = 0, bsize = 0;
311   uint16_t length = 0, l = 0;
312   int sockstate;
313
314   *len = 0;
315
316   sockstate = fcntl(zebra.sock, F_GETFL, 0);
317   fcntl(zebra.sock, F_SETFL, sockstate | O_NONBLOCK);
318
319   do {
320     if (*len == bsize) {
321       bsize += BUFSIZE;
322       buf = my_realloc(buf, bsize, "Zebra try_read");
323     }
324     ret = read (zebra.sock, buf + *len, bsize - *len);
325     if (!ret) {                 // nothing more to read, packet is broken, discard!
326       free(buf);
327       return NULL;
328     }
329
330     if (ret < 0) {
331       if (errno != EAGAIN) {    // oops - we got disconnected
332         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
333         zebra.status &= ~STATUS_CONNECTED;
334       }
335       free(buf);
336       return NULL;
337     }
338
339     *len += ret;
340     do {
341       memcpy(&length, buf + l, 2);
342       length = ntohs(length);
343       l += length;
344     } while (*len > l);
345     if (*len < l)
346       fcntl(zebra.sock, F_SETFL, sockstate);
347   }
348   while (*len != l); // GOT FULL PACKAGE!!
349
350   fcntl(zebra.sock, F_SETFL, sockstate);
351   return buf;
352 }
353
354 /* Parse an ipv4-route-packet recived from zebra
355  */
356 struct zebra_route
357 *zebra_parse_route(unsigned char *opt)
358 {
359   struct zebra_route *r;
360   int c;
361   size_t size;
362   uint16_t length;
363   unsigned char *pnt;
364
365   memcpy(&length, opt, sizeof length);
366   length = ntohs (length);
367
368   r = olsr_malloc(sizeof *r, "zebra_parse_route");
369   pnt = &opt[3];
370   r->type = *pnt++;
371   r->flags = *pnt++;
372   r->message = *pnt++;
373   r->prefixlen = *pnt++;
374   r->prefix.v4.s_addr = 0;
375
376   size = (r->prefixlen + 7) / 8;
377   memcpy(&r->prefix.v4.s_addr, pnt, size);
378   pnt += size;
379
380   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
381     r->nexthop_num = *pnt++;
382     r->nexthop = olsr_malloc((sizeof *r->nexthop) * r->nexthop_num, "quagga: zebra_parse_route");
383     for (c = 0; c < r->nexthop_num; c++) {
384       memcpy(&r->nexthop[c].v4.s_addr, pnt, sizeof r->nexthop[c].v4.s_addr);
385       pnt += sizeof r->nexthop[c].v4.s_addr;
386     }
387   }
388
389   if (r->message & ZAPI_MESSAGE_IFINDEX) {
390     r->ifindex_num = *pnt++;
391     r->ifindex = olsr_malloc(sizeof(uint32_t) * r->ifindex_num, "quagga: zebra_parse_route");
392     for (c = 0; c < r->ifindex_num; c++) {
393       memcpy(&r->ifindex[c], pnt, sizeof r->ifindex[c]);
394       r->ifindex[c] = ntohl (r->ifindex[c]);
395       pnt += sizeof r->ifindex[c];
396     }
397   }
398
399   if (r->message & ZAPI_MESSAGE_DISTANCE) {
400     r->distance = *pnt++;
401   }
402
403 // Quagga v0.98.6 BUG workaround: metric is always sent by zebra
404 // even without ZAPI_MESSAGE_METRIC message.
405 //  if (r.message & ZAPI_MESSAGE_METRIC) {
406     memcpy(&r->metric, pnt, sizeof (uint32_t));
407     r->metric = ntohl(r->metric);
408     pnt += sizeof r->metric;
409 //  }
410
411   OLSR_PRINTF(1, "%u \n", (unsigned int) (pnt-opt));
412
413   if (pnt - opt != length) {
414     olsr_exit("(QUAGGA) length does not match ??? ", EXIT_FAILURE);
415   }
416
417   return r;
418 }
419
420 static unsigned char
421 *zebra_redistribute_packet (unsigned char cmd, unsigned char type)
422 {
423   unsigned char *data, *pnt;
424   uint16_t size;
425
426   data = olsr_malloc(ZEBRA_MAX_PACKET_SIZ , "zebra_redistribute_packet");
427
428   pnt = &data[2];
429   *pnt++ = cmd;
430   *pnt++ = type;
431   size = htons(pnt - data);
432   memcpy(data, &size, 2);
433
434   return data;
435 }
436
437 /* start redistribution FROM zebra */
438 int
439 zebra_redistribute(unsigned char type)
440 {
441
442   if (zebra_send_command(zebra_redistribute_packet(ZEBRA_REDISTRIBUTE_ADD, type)) < 0)
443     olsr_exit("(QUAGGA) could not send redistribute add command", EXIT_FAILURE);
444
445   if (type > ZEBRA_ROUTE_MAX - 1)
446     return -1;
447   zebra.redistribute[type] = 1;
448
449   return 0;
450
451 }
452
453 /* end redistribution FROM zebra */
454 int
455 zebra_disable_redistribute(unsigned char type)
456 {
457
458   if (zebra_send_command(zebra_redistribute_packet(ZEBRA_REDISTRIBUTE_DELETE, type)) < 0)
459     olsr_exit("(QUAGGA) could not send redistribute delete command", EXIT_FAILURE);
460
461   if (type > ZEBRA_ROUTE_MAX - 1)
462     return -1;
463   zebra.redistribute[type] = 0;
464
465   return 0;
466
467 }
468
469 static void
470 free_ipv4_route(struct zebra_route *r)
471 {
472
473   if(r->ifindex_num)
474     free(r->ifindex);
475   if(r->nexthop_num)
476     free(r->nexthop);
477
478 }
479
480 int
481 zebra_add_route(const struct rt_entry *r)
482 {
483
484   struct zebra_route route;
485   int retval;
486
487   route.distance = 0;
488   route.type = ZEBRA_ROUTE_OLSR;
489   route.flags = zebra.flags;
490   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
491   route.prefixlen = r->rt_dst.prefix_len;
492   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
493   route.ifindex_num = 0;
494   route.ifindex = NULL;
495   route.nexthop_num = 0;
496   route.nexthop = NULL;
497
498   if (r->rt_best->rtp_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr && route.prefixlen == 32) {
499     return 0;                   /* Quagga BUG workaround: don't add routes with destination = gateway
500                                    see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
501     route.ifindex_num++;
502     route.ifindex = olsr_malloc(sizeof *route.ifindex, "zebra_add_route");
503     *route.ifindex = r->rt_best->rtp_nexthop.iif_index;
504   } else {
505     route.nexthop_num++;
506     route.nexthop = olsr_malloc(sizeof *route.nexthop, "zebra_add_route");
507     route.nexthop->v4.s_addr = r->rt_best->rtp_nexthop.gateway.v4.s_addr;
508   }
509
510   route.metric = r->rt_best->rtp_metric.hops;
511
512   if (zebra.distance) {
513     route.message |= ZAPI_MESSAGE_DISTANCE;
514     route.distance = zebra.distance;
515   }
516
517   retval = zebra_send_command(zebra_route_packet(ZEBRA_IPV4_ROUTE_ADD, &route));
518
519   return retval;
520 }
521
522 int
523 zebra_del_route(const struct rt_entry *r)
524 {
525
526   struct zebra_route route;
527   int retval;
528   route.distance = 0;
529   route.type = ZEBRA_ROUTE_OLSR;
530   route.flags = zebra.flags;
531   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
532   route.prefixlen = r->rt_dst.prefix_len;
533   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
534   route.ifindex_num = 0;
535   route.ifindex = NULL;
536   route.nexthop_num = 0;
537   route.nexthop = NULL;
538
539   if (r->rt_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr && route.prefixlen == 32) {
540     return 0;                   /* Quagga BUG workaround: don't delete routes with destination = gateway
541                                    see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
542     route.ifindex_num++;
543     route.ifindex = olsr_malloc(sizeof *route.ifindex, "zebra_del_route");
544     *route.ifindex = r->rt_nexthop.iif_index;
545   } else {
546     route.nexthop_num++;
547     route.nexthop = olsr_malloc(sizeof *route.nexthop, "zebra_del_route");
548     route.nexthop->v4.s_addr = r->rt_nexthop.gateway.v4.s_addr;
549   }
550
551   route.metric = 0;
552
553   if (zebra.distance) {
554     route.message |= ZAPI_MESSAGE_DISTANCE;
555     route.distance = zebra.distance;
556   }
557
558   retval = zebra_send_command(zebra_route_packet(ZEBRA_IPV4_ROUTE_DELETE, &route));
559
560   return retval;
561 }
562
563 void
564 zebra_olsr_distance(unsigned char dist)
565 {
566   zebra.distance = dist;
567 }
568
569 void
570 zebra_olsr_localpref(void)
571 {
572   zebra.flags &= ZEBRA_FLAG_SELECTED;
573 }
574
575 void
576 zebra_export_routes(unsigned char t)
577 {
578   if (t)
579     zebra.options |= OPTION_EXPORT;
580   else
581     zebra.options &= ~OPTION_EXPORT;
582 }
583
584 /*
585  * Local Variables:
586  * c-basic-offset: 2
587  * indent-tabs-mode: nil
588  * End:
589  */