9efeb3edda20e8ee0ca65201211e8a9ef2275065
[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"
22 #include "log.h"
23 #include "defs.h"
24 #include "routing_table.h"
25
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36
37 #ifdef USE_UNIX_DOMAIN_SOCKET
38 #include <sys/un.h>
39 #define ZEBRA_SOCKET "/var/run/quagga/zserv.api"
40 #endif
41
42 #define ZEBRA_MAX_PACKET_SIZ            4096
43
44 #define ZEBRA_IPV4_ROUTE_ADD            7
45 #define ZEBRA_IPV4_ROUTE_DELETE         8
46 #define ZEBRA_REDISTRIBUTE_ADD          11
47 #define ZEBRA_REDISTRIBUTE_DELETE       12
48 #define ZEBRA_MESSAGE_MAX               23
49
50 #define ZEBRA_ROUTE_OLSR                11
51 #define ZEBRA_ROUTE_MAX                 13
52
53 #define ZEBRA_FLAG_SELECTED             0x10
54
55 #define ZEBRA_NEXTHOP_IFINDEX           1
56 #define ZEBRA_NEXTHOP_IPV4              3
57 #define ZEBRA_NEXTHOP_IPV4_IFINDEX      4
58
59 #define ZAPI_MESSAGE_NEXTHOP  0x01
60 #define ZAPI_MESSAGE_IFINDEX  0x02
61 #define ZAPI_MESSAGE_DISTANCE 0x04
62 #define ZAPI_MESSAGE_METRIC   0x08
63
64 #define BUFSIZE 1024
65
66 #define STATUS_CONNECTED 1
67 #define OPTION_EXPORT 1
68
69 static struct {
70   char status;                         // internal status
71   char options;                        // internal options
72   int sock;                            // Socket to zebra...
73   char redistribute[ZEBRA_ROUTE_MAX];
74   char distance;
75   char flags;
76   struct ipv4_route *v4_rt;            // routes currently exportet to zebra
77 } zebra;
78
79 /* prototypes intern */
80 #if 0
81 static unsigned char *try_read(ssize_t *);
82 static unsigned char *zebra_route_packet(struct ipv4_route r, ssize_t *);
83 static int parse_interface_add(unsigned char *, size_t);
84 static int parse_interface_delete(unsigned char *, size_t);
85 static int parse_interface_up(unsigned char *, size_t);
86 static int parse_interface_down(unsigned char *, size_t);
87 static int parse_interface_address_add(unsigned char *, size_t);
88 static int parse_interface_address_delete(unsigned char *, size_t);
89 static int parse_ipv4_route(unsigned char *, size_t, struct ipv4_route *);
90 static int ipv4_route_add(unsigned char *, size_t);
91 static int ipv4_route_delete(unsigned char *, size_t);
92 static int parse_ipv6_route_add(unsigned char *, size_t);
93 static void zebra_reconnect(void);
94 #endif
95 static void zebra_connect(void);
96
97 #if 0
98 static void free_ipv4_route(struct ipv4_route);
99
100 /*
101 static void update_olsr_zebra_routes (struct ipv4_route*, struct ipv4_route*);
102 static struct ipv4_route *zebra_create_ipv4_route_table_entry (uint32_t,
103                                                                uint32_t,
104                                                                uint32_t);
105 static struct ipv4_route *zebra_create_ipv4_route_table (void);
106 static void zebra_free_ipv4_route_table (struct ipv4_route*);
107 */
108 #endif
109
110 /*static uint8_t masktoprefixlen (uint32_t);*/
111
112 void *
113 my_realloc(void *buf, size_t s, const char *c)
114 {
115   buf = realloc(buf, s);
116   if (!buf) {
117     OLSR_PRINTF(1, "(QUAGGA) OUT OF MEMORY: %s\n", strerror(errno));
118     olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n");
119     olsr_exit(c, EXIT_FAILURE);
120   }
121   return buf;
122 }
123
124 void
125 init_zebra(void)
126 {
127   zebra_connect();
128   if (!(zebra.status & STATUS_CONNECTED))
129     olsr_exit("(QUAGGA) AIIIII, could not connect to zebra! is zebra running?", EXIT_FAILURE);
130 }
131
132 void
133 zebra_cleanup(void)
134 {
135 #if 0
136   int i;
137 #endif
138   struct rt_entry *tmp;
139
140   if (zebra.options & OPTION_EXPORT) {
141     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
142       zebra_del_route(tmp);
143     }
144     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
145   }
146
147 #if 0
148   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
149     if (zebra.redistribute[i])
150       zebra_disable_redistribute(i + 1);
151 #endif
152 }
153
154 #if 0
155 static void
156 zebra_reconnect(void)
157 {
158   struct rt_entry *tmp;
159   int i;
160
161   zebra_connect();
162   if (!(zebra.status & STATUS_CONNECTED))
163     return;                     // try again next time
164
165   if (zebra.options & OPTION_EXPORT) {
166     OLSR_FOR_ALL_RT_ENTRIES(tmp) {
167       zebra_add_route(tmp);
168     }
169     OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
170   }
171
172   for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
173     if (zebra.redistribute[i])
174       zebra_redistribute(i + 1);
175   /* Zebra sends us all routes of type it knows after
176      zebra_redistribute(type) */
177 }
178 #endif
179
180 /* Connect to the zebra-daemon, returns a socket */
181 static void
182 zebra_connect(void)
183 {
184
185   int ret;
186
187 #ifndef USE_UNIX_DOMAIN_SOCKET
188   struct sockaddr_in i;
189   if (close(zebra.sock) < 0)
190     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
191
192   zebra.sock = socket(AF_INET, SOCK_STREAM, 0);
193 #else
194   struct sockaddr_un i;
195   if (close(zebra.sock) < 0)
196     olsr_exit("(QUAGGA) Could not close socket!", EXIT_FAILURE);
197
198   zebra.sock = socket(AF_UNIX, SOCK_STREAM, 0);
199 #endif
200
201   if (zebra.sock < 0)
202     olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
203
204   memset(&i, 0, sizeof i);
205 #ifndef USE_UNIX_DOMAIN_SOCKET
206   i.sin_family = AF_INET;
207   i.sin_port = htons(ZEBRA_PORT);
208   i.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
209 #else
210   i.sun_family = AF_UNIX;
211   strscpy(i.sun_path, ZEBRA_SOCKET, sizeof(i.sun_path));
212 #endif
213
214   ret = connect(zebra.sock, (struct sockaddr *)&i, sizeof i);
215   if (ret < 0)
216     zebra.status &= ~STATUS_CONNECTED;
217   else
218     zebra.status |= STATUS_CONNECTED;
219 }
220
221 /* Sends a command to zebra, command is
222    the command defined in zebra.h, options is the packet-payload,
223    optlen the length, of the payload */
224 unsigned char
225 zebra_send_command(unsigned char *options)
226 {
227
228   unsigned char *pnt;
229   uint16_t len;
230   int ret;
231
232   if (!(zebra.status & STATUS_CONNECTED))
233     return 0;
234
235   pnt = options;
236   memcpy(&len, pnt, 2);
237
238   len = ntohs(len);
239
240   do {
241     ret = write(zebra.sock, pnt, len);
242     if (ret < 0) {
243       if ((errno == EINTR) || (errno == EAGAIN)) {
244         errno = 0;
245         ret = 0;
246         continue;
247       } else {
248         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
249         zebra.status &= ~STATUS_CONNECTED;
250         free(options);
251         return -1;
252       }
253     }
254     pnt = pnt + ret;
255   } while ((len -= ret));
256   free(options);
257   return 0;
258 }
259
260 /* Creates a Route-Packet-Payload, needs address, netmask, nexthop,
261    distance, and a pointer of an size_t */
262 static unsigned char *
263 zebra_route_packet(uint32_t cmd, struct ipv4_route r)
264 {
265
266   int count;
267   uint8_t len;
268   uint16_t size;
269   uint32_t ind, metric;
270
271   unsigned char *cmdopt, *t;
272
273   cmdopt = olsr_malloc(ZEBRA_MAX_PACKET_SIZ, "zebra add_v4_route");
274
275   t = &cmdopt[2];
276   *t++ = cmd;
277   *t++ = r.type;
278   *t++ = r.flags;
279   *t++ = r.message;
280   *t++ = r.prefixlen;
281   len = (r.prefixlen + 7) / 8;
282   memcpy(t, &r.prefix.v4.s_addr, len);
283   t = t + len;
284
285   if (r.message & ZAPI_MESSAGE_NEXTHOP) {
286     *t++ = r.nh_count + r.ind_num;
287
288       for (count = 0; count < r.nh_count; count++) {
289         *t++ = ZEBRA_NEXTHOP_IPV4;
290         memcpy(t, &r.nexthop[count].v4.s_addr, sizeof r.nexthop[count].v4.s_addr);
291         t += sizeof r.nexthop[count].v4.s_addr;
292       }
293       for (count = 0; count < r.ind_num; count++) {
294         *t++ = ZEBRA_NEXTHOP_IFINDEX;
295         ind = htonl(r.index[count]);
296         memcpy(t, &ind, sizeof ind);
297         t += sizeof ind;
298       }
299   }
300   if ((r.message & ZAPI_MESSAGE_DISTANCE) > 0)
301     *t++ = r.distance;
302   if ((r.message & ZAPI_MESSAGE_METRIC) > 0) {
303     metric = htonl(r.metric);
304     memcpy(t, &metric, sizeof metric);
305     t += sizeof metric;
306   }
307   size = htons(t - cmdopt);
308   memcpy(cmdopt, &size, 2);
309
310   return cmdopt;
311 }
312
313 #if 0
314 /* adds a route to zebra-daemon */
315 int
316 zebra_add_v4_route(const struct ipv4_route r)
317 {
318
319   unsigned char *cmdopt;
320   ssize_t optlen;
321   int retval;
322
323   cmdopt = zebra_route_packet(r, &optlen);
324
325   retval = zebra_send_command(ZEBRA_IPV4_ROUTE_ADD, cmdopt, optlen);
326   free(cmdopt);
327   return retval;
328
329 }
330
331 /* deletes a route from the zebra-daemon */
332 int
333 zebra_delete_v4_route(struct ipv4_route r)
334 {
335
336   unsigned char *cmdopt;
337   ssize_t optlen;
338   int retval;
339
340   cmdopt = zebra_route_packet(r, &optlen);
341
342   retval = zebra_send_command(ZEBRA_IPV4_ROUTE_DELETE, cmdopt, optlen);
343   free(cmdopt);
344
345   return retval;
346
347 }
348
349 /* Check wether there is data from zebra aviable */
350 void
351 zebra_check(void *foo __attribute__ ((unused)))
352 {
353   unsigned char *data, *f;
354   ssize_t len, ret;
355
356   if (!(zebra.status & STATUS_CONNECTED)) {
357     zebra_reconnect();
358     return;
359   }
360   data = try_read(&len);
361   if (data) {
362     f = data;
363     do {
364       ret = zebra_parse_packet(f, len);
365       if (!ret)                 // something wired happened
366         olsr_exit("(QUAGGA) Zero message length??? ", EXIT_FAILURE);
367       f += ret;
368     }
369     while ((f - data) < len);
370     free(data);
371   }
372 }
373
374 // tries to read a packet from zebra_socket
375 // if there is something to read - make sure to read whole packages
376 static unsigned char *
377 try_read(ssize_t * len)
378 {
379   unsigned char *buf = NULL;
380   ssize_t ret = 0, bsize = 0;
381   uint16_t length = 0, l = 0;
382   int sockstate;
383
384   *len = 0;
385
386   sockstate = fcntl(zebra.sock, F_GETFL, 0);
387   fcntl(zebra.sock, F_SETFL, sockstate | O_NONBLOCK);
388
389   do {
390     if (*len == bsize) {
391       bsize += BUFSIZE;
392       buf = my_realloc(buf, bsize, "Zebra try_read");
393     }
394     ret = read (zebra.sock, buf + *len, bsize - *len);
395     if (!ret) {                 // nothing more to read, packet is broken, discard!
396       free(buf);
397       return NULL;
398     }
399
400     if (ret < 0) {
401       if (errno != EAGAIN) {    // oops - we got disconnected
402         OLSR_PRINTF(1, "(QUAGGA) Disconnected from zebra\n");
403         zebra.status &= ~STATUS_CONNECTED;
404       }
405       free(buf);
406       return NULL;
407     }
408
409     *len += ret;
410     do {
411       memcpy(&length, buf + l, 2);
412       length = ntohs(length);
413       l += length;
414     } while (*len > l);
415     if (*len < l)
416       fcntl(zebra.sock, F_SETFL, sockstate);
417   }
418   while (*len != l); // GOT FULL PACKAGE!!
419
420   fcntl(zebra.sock, F_SETFL, sockstate);
421   return buf;
422 }
423
424 /* Parse a packet recived from zebra */
425 int
426 zebra_parse_packet(unsigned char *packet, ssize_t maxlen)
427 {
428
429   uint16_t command;
430   int skip;
431
432   /* Array of functions */
433   int (*foo[ZEBRA_MESSAGE_MAX]) (unsigned char *, size_t) = {
434   parse_interface_add, parse_interface_delete, parse_interface_address_add, parse_interface_address_delete, parse_interface_up,
435       parse_interface_down, ipv4_route_add, ipv4_route_delete, parse_ipv6_route_add};
436
437   uint16_t length;
438   int ret;
439
440   memcpy(&length, packet, 2);
441   length = ntohs(length);
442
443   if (maxlen < length) {
444     OLSR_PRINTF(1, "(QUAGGA) maxlen = %lu, packet_length = %d\n", (unsigned long)maxlen, length);
445     olsr_exit("(QUAGGA) programmer is an idiot", EXIT_FAILURE);
446   }
447 #ifdef ZEBRA_HEADER_MARKER
448   if (packet[2] == 255) {       // found header marker!!
449     //packet[3] == ZSERV_VERSION: FIXME: HANDLE THIS!
450     memcpy(&command, packet + 4, sizeof command);       // two bytes command now!
451     command = ntohs(command) - 1;
452     skip = 6;
453   }
454 #else
455   command = packet[2] - 1;
456   skip = 3;
457 #endif
458
459   if (command < ZEBRA_MESSAGE_MAX && foo[command]) {
460     if (!(ret = foo[command] (packet + skip, length - skip)))
461       return length;
462     else
463       OLSR_PRINTF(1, "(QUAGGA) Parse error: %d\n", ret);
464   } else
465     OLSR_PRINTF(1, "(QUAGGA) Unknown packet type: %d\n", packet[2]);
466
467   OLSR_PRINTF(1, "(Quagga) RECIVED PACKET FROM ZEBRA THAT I CAN'T PARSE");
468
469   return length;
470 }
471
472 static int
473 parse_interface_add(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
474 {
475   //todo
476   return 0;
477 }
478
479 static int
480 parse_interface_delete(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
481 {
482   //todo
483   return 0;
484 }
485
486 static int
487 parse_interface_address_add(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
488 {
489
490   //todo
491   return 0;
492 }
493
494 static int
495 parse_interface_up(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
496 {
497
498   //todo
499   return 0;
500 }
501
502 static int
503 parse_interface_down(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
504 {
505
506   //todo
507   return 0;
508 }
509
510 static int
511 parse_interface_address_delete(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
512 {
513   //todo
514   return 0;
515 }
516
517 /* Parse an ipv4-route-packet recived from zebra
518  */
519 static int
520 parse_ipv4_route(unsigned char *opt, size_t len, struct ipv4_route *r)
521 {
522   int c;
523   size_t size;
524
525   if (len < 4)
526     return -1;
527
528   r->type = *opt++;
529   r->flags = *opt++;
530   r->message = *opt++;
531   r->prefixlen = *opt++;
532   len -= 4;
533   r->prefix = 0;
534
535   if ((int)len < r->prefixlen / 8 + (r->prefixlen % 8 ? 1 : 0))
536     return -1;
537
538   size = r->prefixlen/8 + (r->prefixlen % 8 ? 1 : 0);
539   memcpy (&r->prefix, opt, size);
540   opt += size;
541   len -= size;
542
543   if (r->message & ZAPI_MESSAGE_NEXTHOP) {
544     if (len < 1)
545       return -1;
546     r->nh_count = *opt++;
547     len--;
548     if (len < (sizeof(uint32_t) + 1) * r->nh_count)
549       return -1;
550     r->nexthops =
551       olsr_malloc((sizeof r->nexthops->type + sizeof r->nexthops->payload) * r->nh_count, "quagga: parse_ipv4_route_add");
552     for (c = 0; c < r->nh_count; c++) {
553 // Quagga Bug! nexthop type is NOT sent by zebra
554 //      r->nexthops[c].type = *opt++;
555 //      len--;
556       memcpy(&r->nexthops[c].payload.v4, opt, sizeof(uint32_t));
557       opt += sizeof(uint32_t);
558       len -= sizeof(uint32_t);
559     }
560   }
561
562   if (r->message & ZAPI_MESSAGE_IFINDEX) {
563     if (len < 1)
564       return -1;
565     r->ind_num = *opt++;
566     len--;
567     if (len < sizeof(uint32_t) * r->ind_num)
568       return -1;
569     r->index = olsr_malloc(sizeof(uint32_t) * r->ind_num, "quagga: parse_ipv4_route_add");
570     memcpy(r->index, opt, r->ind_num * sizeof(uint32_t));
571     opt += sizeof(uint32_t) * r->ind_num;
572     len -= sizeof(uint32_t) * r->ind_num;
573   }
574
575   if (r->message & ZAPI_MESSAGE_DISTANCE) {
576     if (len < 1)
577       return -1;
578     r->distance = *opt++;
579     len--;
580   }
581
582   if (r->message & ZAPI_MESSAGE_METRIC) {
583     if (len < sizeof(uint32_t))
584       return -1;
585     memcpy(&r->metric, opt, sizeof(uint32_t));
586   }
587
588   return 0;
589 }
590
591 static int
592 ipv4_route_add(unsigned char *opt, size_t len)
593 {
594
595   struct ipv4_route r;
596   int f;
597
598   f = parse_ipv4_route(opt, len, &r);
599   if (f < 0)
600     return f;
601
602   return add_hna4_route(r);
603 }
604
605 static int
606 ipv4_route_delete(unsigned char *opt, size_t len)
607 {
608   struct ipv4_route r;
609   int f;
610
611   f = parse_ipv4_route(opt, len, &r);
612   if (f < 0)
613     return f;
614
615   return delete_hna4_route(r);
616
617 }
618
619 static int
620 parse_ipv6_route_add(unsigned char *opt __attribute__ ((unused)), size_t len __attribute__ ((unused)))
621 {
622   //todo
623   return 0;
624 }
625
626 /* start redistribution FROM zebra */
627 int
628 zebra_redistribute(unsigned char type)
629 {
630
631   if (type > ZEBRA_ROUTE_MAX)
632     return -1;
633   zebra.redistribute[type - 1] = 1;
634
635   return zebra_send_command(ZEBRA_REDISTRIBUTE_ADD, &type, 1);
636
637 }
638
639 /* end redistribution FROM zebra */
640 int
641 zebra_disable_redistribute(unsigned char type)
642 {
643
644   if (type > ZEBRA_ROUTE_MAX)
645     return -1;
646   zebra.redistribute[type - 1] = 0;
647
648   return zebra_send_command(ZEBRA_REDISTRIBUTE_DELETE, &type, 1);
649
650 }
651
652 int
653 add_hna4_route(struct ipv4_route r)
654 {
655   union olsr_ip_addr net;
656
657   net.v4.s_addr = r.prefix;
658
659   ip_prefix_list_add(&olsr_cnf->hna_entries, &net, r.prefixlen);
660   free_ipv4_route(r);
661   return 0;
662 }
663
664 int
665 delete_hna4_route(struct ipv4_route r)
666 {
667
668   union olsr_ip_addr net;
669
670   net.v4.s_addr = r.prefix;
671
672   ip_prefix_list_remove(&olsr_cnf->hna_entries, &net, r.prefixlen);
673   free_ipv4_route(r);
674   return 0;
675
676 }
677
678 static void
679 free_ipv4_route(struct ipv4_route r)
680 {
681
682   if (r.message & ZAPI_MESSAGE_IFINDEX && r.ind_num)
683     free(r.index);
684   if (r.message & ZAPI_MESSAGE_NEXTHOP && r.nh_count)
685     free(r.nexthops);
686
687 }
688 #endif
689
690 /*
691 static uint8_t masktoprefixlen (uint32_t mask) {
692
693   uint8_t prefixlen = 0;
694
695   mask = htonl (mask);
696
697   if (mask) while (mask << ++prefixlen && prefixlen < 32);
698
699   return prefixlen;
700
701 }
702 */
703
704 int
705 zebra_add_route(const struct rt_entry *r)
706 {
707
708   struct ipv4_route route;
709   int retval;
710
711   route.distance = 0;
712   route.type = ZEBRA_ROUTE_OLSR;
713   route.flags = zebra.flags;
714   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
715   route.prefixlen = r->rt_dst.prefix_len;
716   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
717   route.ind_num = 0;
718   route.index = NULL;
719   route.nh_count = 0;
720   route.nexthop = NULL;
721
722   if (r->rt_best->rtp_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr && route.prefixlen == 32) {
723     return 0;                   /* Quagga BUG workaround: don't add routes with destination = gateway
724                                    see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
725     route.ind_num++;
726     route.index = olsr_malloc(sizeof *route.index, "zebra_add_route");
727     *route.index = r->rt_best->rtp_nexthop.iif_index;
728   } else {
729     route.nh_count++;
730     route.nexthop = olsr_malloc(sizeof *route.nexthop, "zebra_add_route");
731     route.nexthop->v4.s_addr = r->rt_best->rtp_nexthop.gateway.v4.s_addr;
732   }
733
734   route.metric = r->rt_best->rtp_metric.hops;
735
736   if (zebra.distance) {
737     route.message |= ZAPI_MESSAGE_DISTANCE;
738     route.distance = zebra.distance;
739   }
740
741   retval = zebra_send_command(zebra_route_packet(ZEBRA_IPV4_ROUTE_ADD, route));
742
743   return retval;
744 }
745
746 int
747 zebra_del_route(const struct rt_entry *r)
748 {
749
750   struct ipv4_route route;
751   int retval;
752   route.distance = 0;
753   route.type = ZEBRA_ROUTE_OLSR;
754   route.flags = zebra.flags;
755   route.message = ZAPI_MESSAGE_NEXTHOP | ZAPI_MESSAGE_METRIC;
756   route.prefixlen = r->rt_dst.prefix_len;
757   route.prefix.v4.s_addr = r->rt_dst.prefix.v4.s_addr;
758   route.ind_num = 0;
759   route.index = NULL;
760   route.nh_count = 0;
761   route.nexthop = NULL;
762
763   if (r->rt_nexthop.gateway.v4.s_addr == r->rt_dst.prefix.v4.s_addr && route.prefixlen == 32) {
764     return 0;                   /* Quagga BUG workaround: don't delete routes with destination = gateway
765                                    see http://lists.olsr.org/pipermail/olsr-users/2006-June/001726.html */
766     route.ind_num++;
767     route.index = olsr_malloc(sizeof *route.index, "zebra_del_route");
768     *route.index = r->rt_nexthop.iif_index;
769   } else {
770     route.nh_count++;
771     route.nexthop = olsr_malloc(sizeof *route.nexthop, "zebra_del_route");
772     route.nexthop->v4.s_addr = r->rt_nexthop.gateway.v4.s_addr;
773   }
774
775   route.metric = 0;
776
777   if (zebra.distance) {
778     route.message |= ZAPI_MESSAGE_DISTANCE;
779     route.distance = zebra.distance;
780   }
781
782   retval = zebra_send_command(zebra_route_packet(ZEBRA_IPV4_ROUTE_DELETE, route));
783
784   return retval;
785 }
786
787 void
788 zebra_olsr_distance(unsigned char dist)
789 {
790   zebra.distance = dist;
791 }
792
793 void
794 zebra_olsr_localpref(void)
795 {
796   zebra.flags &= ZEBRA_FLAG_SELECTED;
797 }
798
799 void
800 zebra_export_routes(unsigned char t)
801 {
802   if (t)
803     zebra.options |= OPTION_EXPORT;
804   else
805     zebra.options &= ~OPTION_EXPORT;
806 }
807
808 /*
809  * Local Variables:
810  * c-basic-offset: 2
811  * indent-tabs-mode: nil
812  * End:
813  */