1 /***************************************************************************
4 usage : communication with the zebra-daemon
5 copyright : (C) 2006 by Immo 'FaUl' Wehrenberg
6 e-mail : immo@chaostreff-dortmund.de
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License version 2 as *
13 * published by the Free Software Foundation. *
15 ***************************************************************************/
22 #define HAVE_SOCKLEN_T
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <quagga/zebra.h>
34 #include "local_hna_set.h"
35 #include "routing_table.h"
37 #ifdef USE_UNIX_DOMAIN_SOCKET
39 #define ZEBRA_SOCKET "/var/run/quagga/zserv.api"
42 #define ZAPI_MESSAGE_NEXTHOP 0x01
43 #define ZAPI_MESSAGE_IFINDEX 0x02
44 #define ZAPI_MESSAGE_DISTANCE 0x04
45 #define ZAPI_MESSAGE_METRIC 0x08
49 #define STATUS_CONNECTED 1
50 #define OPTION_EXPORT 1
53 char status; // internal status
54 char options; // internal options
55 int sock; // Socket to zebra...
56 char redistribute[ZEBRA_ROUTE_MAX];
59 struct ipv4_route *v4_rt; // routes currently exportet to zebra
63 /* prototypes intern */
64 static unsigned char *try_read (ssize_t *);
65 static unsigned char* zebra_route_packet (struct ipv4_route r, ssize_t *);
66 static int parse_interface_add (unsigned char *, size_t);
67 static int parse_interface_delete (unsigned char *, size_t);
68 static int parse_interface_up (unsigned char *, size_t);
69 static int parse_interface_down (unsigned char *, size_t);
70 static int parse_interface_address_add (unsigned char *, size_t);
71 static int parse_interface_address_delete (unsigned char *, size_t);
72 static int parse_ipv4_route (unsigned char *, size_t, struct ipv4_route *);
73 static int ipv4_route_add (unsigned char *, size_t);
74 static int ipv4_route_delete (unsigned char *, size_t);
75 static int parse_ipv6_route_add (unsigned char*, size_t);
76 static void zebra_reconnect (void);
77 static void zebra_connect (void);
79 static uint32_t prefixlentomask (uint8_t);
80 static void free_ipv4_route (struct ipv4_route);
82 static void update_olsr_zebra_routes (struct ipv4_route*, struct ipv4_route*);
83 static struct ipv4_route *zebra_create_ipv4_route_table_entry (uint32_t,
86 static struct ipv4_route *zebra_create_ipv4_route_table (void);
87 static void zebra_free_ipv4_route_table (struct ipv4_route*);
90 /*static uint8_t masktoprefixlen (uint32_t);*/
94 static void dump_ipv4_route (struct ipv4_route r, char *c) {
98 printf("type: %d\n", r.type);
100 printf(" Internal: %s\n",r.flags&ZEBRA_FLAG_INTERNAL?"yes":"no");
101 printf(" Selfroute %s\n",r.flags&ZEBRA_FLAG_SELFROUTE?"yes":"no");
102 printf(" Blackhole %s\n",r.flags&ZEBRA_FLAG_BLACKHOLE?"yes":"no");
103 printf(" IBGP: %s\n",r.flags&ZEBRA_FLAG_IBGP?"yes":"no");
104 printf(" Selected: %s\n",r.flags&ZEBRA_FLAG_SELECTED?"yes":"no");
105 printf(" Changed: %s\n",r.flags&ZEBRA_FLAG_CHANGED?"yes":"no");
106 printf(" static: %s\n",r.flags&ZEBRA_FLAG_STATIC?"yes":"no");
107 printf(" reject: %s\n",r.flags&ZEBRA_FLAG_REJECT?"yes":"no");
109 printf(" nexthop: %s\n",r.message&ZAPI_MESSAGE_NEXTHOP?"yes":"no");
110 printf(" ifindex: %s\n",r.message&ZAPI_MESSAGE_IFINDEX?"yes":"no");
111 printf(" distance: %s\n",r.message&ZAPI_MESSAGE_DISTANCE?"yes":"no");
112 printf(" metric: %s\n",r.message&ZAPI_MESSAGE_METRIC?"yes":"no");
113 printf("Prefixlen: %d\n", r.prefixlen);
114 printf("Prefix: %d", (unsigned char)r.prefix);
115 c = (char*) &r.prefix;
116 while (++i < (r.prefixlen/8 + (r.prefixlen % 8 ? 1 : 0)))
117 printf(".%d",(unsigned char)*(c + i));
122 if (r.message&ZAPI_MESSAGE_NEXTHOP) {
123 printf("nexthop-count: %d\n", r.nh_count);
124 while (i++ < r.nh_count) {
125 if (r.nexthops[i].type == ZEBRA_NEXTHOP_IPV4) {
126 c = (unsigned char*) &r.nexthops[i].payload.v4;
127 printf ("Nexthop %d: %d", i, (unsigned char) *c);
129 printf (".%d", (unsigned char) c[x]);
136 if (r.message&ZAPI_MESSAGE_IFINDEX) {
138 printf("index-number: %d\n", r.ind_num);
139 while (i++ < r.ind_num)
140 printf("Index: %d: %d\n", i, r.index[i]);
142 if (r.message&ZAPI_MESSAGE_DISTANCE)
143 printf("Distance: %d\n",r.distance);
144 if (r.message&ZAPI_MESSAGE_METRIC)
145 printf("Metric: %d\n",r.metric);
151 void *my_realloc (void *buf, size_t s, const char *c) {
152 buf = realloc (buf, s);
154 OLSR_PRINTF (1, "(QUAGGA) OUT OF MEMORY: %s\n", strerror(errno));
155 olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n");
156 olsr_exit(c, EXIT_FAILURE);
161 void init_zebra (void) {
163 if (!zebra.status&STATUS_CONNECTED)
164 olsr_exit ("(QUAGGA) AIIIII, could not connect to zebra! is zebra running?",
168 void zebra_cleanup (void) {
170 struct rt_entry *tmp;
172 if (zebra.options & OPTION_EXPORT) {
173 OLSR_FOR_ALL_RT_ENTRIES(tmp) {
174 zebra_del_olsr_v4_route(tmp);
175 } OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
178 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
179 if (zebra.redistribute[i]) zebra_disable_redistribute(i + 1);
183 static void zebra_reconnect (void) {
184 struct rt_entry *tmp;
188 if (!zebra.status & STATUS_CONNECTED) return; // try again next time
190 if (zebra.options & OPTION_EXPORT) {
191 OLSR_FOR_ALL_RT_ENTRIES(tmp) {
192 zebra_add_olsr_v4_route (tmp);
193 } OLSR_FOR_ALL_RT_ENTRIES_END(tmp);
196 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
197 if (zebra.redistribute[i]) zebra_redistribute(i + 1);
198 /* Zebra sends us all routes of type it knows after
199 zebra_redistribute(type) */
204 /* Connect to the zebra-daemon, returns a socket */
205 static void zebra_connect (void) {
209 #ifndef USE_UNIX_DOMAIN_SOCKET
210 struct sockaddr_in i;
211 if (close (zebra.sock) < 0) olsr_exit ("(QUAGGA) Could not close socket!", EXIT_FAILURE);
214 zebra.sock = socket (AF_INET,SOCK_STREAM, 0);
216 struct sockaddr_un i;
217 if (close (zebra.sock) < 0) olsr_exit ("(QUAGGA) Could not close socket!", EXIT_FAILURE);
219 zebra.sock = socket (AF_UNIX,SOCK_STREAM, 0);
223 olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE);
225 memset (&i, 0, sizeof i);
226 #ifndef USE_UNIX_DOMAIN_SOCKET
227 i.sin_family = AF_INET;
228 i.sin_port = htons (ZEBRA_PORT);
229 i.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
231 i.sun_family = AF_UNIX;
232 strcpy (i.sun_path, ZEBRA_SOCKET);
235 ret = connect (zebra.sock, (struct sockaddr *)&i, sizeof i);
236 if (ret < 0) zebra.status &= ~STATUS_CONNECTED;
237 else zebra.status |= STATUS_CONNECTED;
241 /* Sends a command to zebra, command is
242 the command defined in zebra.h, options is the packet-payload,
243 optlen the length, of the payload */
244 unsigned char zebra_send_command (unsigned char command,
245 unsigned char *options, int optlen) {
247 #ifdef ZEBRA_HEADER_MARKER
248 char *p = olsr_malloc (optlen + 6, "zebra_send_command");
249 uint16_t length = optlen + 6; /* length of option + command + packet_length +
250 marker + zserv-version */
253 char *p = olsr_malloc (optlen + 3, "zebra_send_command");
254 uint16_t length = optlen + 3; // length of option + command + packet_length
259 uint16_t len = htons(length);
263 #ifdef ZEBRA_HEADER_MARKER
264 p[2] = ZEBRA_HEADER_MARKER;
265 p[3] = ZSERV_VERSION;
266 cmd = htons (command);
267 memcpy (p + 4, &cmd, 2);
268 memcpy (p + 6, options, optlen);
271 memcpy (p + 3, options, optlen);
277 ret = write (zebra.sock, p, length);
279 if (errno == EINTR) {
284 olsr_printf (1, "(QUAGGA) Disconnected from zebra\n");
285 zebra.status &= ~STATUS_CONNECTED;
291 } while ((length -= ret));
297 /* Creates a Route-Packet-Payload, needs address, netmask, nexthop,
298 distance, and a pointer of an size_t */
299 static unsigned char* zebra_route_packet (struct ipv4_route r,
304 unsigned char *cmdopt, *t;
305 *optlen = 4; // first: type, flags, message, prefixlen
306 *optlen += r.prefixlen / 8 + (r.prefixlen % 8 ? 1 : 0); // + prefix
307 if (r.message & ZAPI_MESSAGE_NEXTHOP) {
308 if (r.nexthops->type == ZEBRA_NEXTHOP_IPV4
309 || r.nexthops->type == ZEBRA_NEXTHOP_IPV4_IFINDEX){
310 *optlen += (sizeof r.nexthops->payload.v4
311 + sizeof r.nexthops->type) * r.nh_count + 1;
313 else if (r.nexthops->type == 0)
316 if (r.message & ZAPI_MESSAGE_IFINDEX)
317 *optlen += r.ind_num * sizeof *r.index + 1;
318 if (r.message & ZAPI_MESSAGE_DISTANCE)
320 if (r.message & ZAPI_MESSAGE_METRIC)
321 *optlen += sizeof r.metric;
323 cmdopt = olsr_malloc (*optlen, "zebra add_v4_route");
330 for (count = 0; count < r.prefixlen/8 + (r.prefixlen % 8 ? 1 : 0); count++) {
331 *t++ = *((char*)&r.prefix + count); /* this is so sick!! */
334 if (r.message & ZAPI_MESSAGE_NEXTHOP) {
336 *t++ = r.nexthops->type;
337 if (r.nexthops->type == ZEBRA_NEXTHOP_IPV4 ||
338 r.nexthops->type == ZEBRA_NEXTHOP_IPV4_IFINDEX) {
339 for (count = 0; count != r.nh_count; count++) {
340 memcpy (t, &r.nexthops[count].payload.v4,
341 sizeof r.nexthops->payload.v4);
342 t += sizeof r.nexthops->payload.v4;
345 else if (r.nexthops->type == 0) {
351 if (r.message & ZAPI_MESSAGE_IFINDEX) {
353 memcpy (t, r.index, sizeof *r.index * r.ind_num);
354 t += sizeof r.index * r.ind_num;
356 if (r.message & ZAPI_MESSAGE_DISTANCE)
358 if (r.message & ZAPI_MESSAGE_METRIC) {
359 memcpy (t, &r.metric, sizeof r.metric);
360 t += sizeof r.metric;
366 /* adds a route to zebra-daemon */
367 int zebra_add_v4_route (struct ipv4_route r) {
369 unsigned char *cmdopt;
373 cmdopt = zebra_route_packet (r, &optlen);
375 retval = zebra_send_command (ZEBRA_IPV4_ROUTE_ADD, cmdopt, optlen);
381 /* deletes a route from the zebra-daemon */
382 int zebra_delete_v4_route (struct ipv4_route r) {
384 unsigned char *cmdopt;
388 cmdopt = zebra_route_packet (r, &optlen);
390 retval = zebra_send_command (ZEBRA_IPV4_ROUTE_DELETE, cmdopt, optlen);
398 /* Check wether there is data from zebra aviable */
399 void zebra_check (void* foo __attribute__((unused))) {
400 unsigned char *data, *f;
403 if (!(zebra.status & STATUS_CONNECTED)) {
407 data = try_read (&len);
411 ret = zebra_parse_packet (f, len);
412 if (!ret) // something wired happened
413 olsr_exit ("(QUAGGA) Zero message length??? ", EXIT_FAILURE);
415 } while ((f - data) < len);
421 // tries to read a packet from zebra_socket
422 // if there is something to read - make sure to read whole packages
423 static unsigned char *try_read (ssize_t *len) {
424 unsigned char *buf = NULL;
425 ssize_t ret = 0, bsize = 0;
426 uint16_t length = 0, l = 0;
431 sockstate = fcntl (zebra.sock, F_GETFL, 0);
432 fcntl (zebra.sock, F_SETFL, sockstate|O_NONBLOCK);
437 buf = my_realloc (buf, bsize, "Zebra try_read");
439 ret = read (zebra.sock, buf + l, bsize - l);
440 if (!ret) { // nothing more to read, packet is broken, discard!
444 if (ret < 0 && errno != EAGAIN) { // oops - we got disconnected
445 olsr_printf (1, "(QUAGGA) Disconnected from zebra\n");
446 zebra.status &= ~STATUS_CONNECTED;
450 while ((*len - l) > length) {
452 memcpy (&length, buf + l, 2);
453 length = ntohs (length);
455 if (((*len) - l) == length) break; // GOT FULL PACKAGE!!
457 fcntl (zebra.sock, F_SETFL, sockstate);
462 fcntl (zebra.sock, F_SETFL, sockstate);
467 /* Parse a packet recived from zebra */
468 int zebra_parse_packet (unsigned char *packet, ssize_t maxlen) {
473 /* Array of functions */
474 int (*foo[ZEBRA_MESSAGE_MAX]) (unsigned char *, size_t) = {
476 parse_interface_delete,
477 parse_interface_address_add,
478 parse_interface_address_delete,
480 parse_interface_down,
490 puts ("DEBUG: zebra_parse_packet");
493 memcpy (&length, packet, 2);
494 length = ntohs (length);
496 if (maxlen < length) {
497 olsr_printf (1, "(QUAGGA) maxlen = %lu, packet_length = %d\n", (unsigned long)maxlen, length);
498 olsr_exit ("(QUAGGA) programmer is an idiot", EXIT_FAILURE);
501 #ifdef ZEBRA_HEADER_MARKER
502 if (packet[2] == 255) { // found header marker!!
503 //packet[3] == ZSERV_VERSION: FIXME: HANDLE THIS!
504 memcpy (command, packet + 4, sizeof command); // two bytes command now!
505 command-- = ntohs (command);
509 command = packet[2] - 1;
513 if (command < ZEBRA_MESSAGE_MAX && foo[command]) {
514 if (!(ret = foo[command] (packet + skip, length - skip)))
516 else olsr_printf (1, "(QUAGGA) Parse error: %d\n", ret);
519 olsr_printf (1, "(QUAGGA) Unknown packet type: %d\n", packet[2]);
521 olsr_printf (1, "(Quagga) RECIVED PACKET FROM ZEBRA THAT I CAN'T PARSE");
527 static int parse_interface_add (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
533 static int parse_interface_delete (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
539 static int parse_interface_address_add (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
545 static int parse_interface_up (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
551 static int parse_interface_down (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
558 static int parse_interface_address_delete (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
564 /* Parse an ipv4-route-packet recived from zebra
566 static int parse_ipv4_route (unsigned char *opt, size_t len, struct ipv4_route *r) {
569 if (len < 4) return -1;
574 r->prefixlen = *opt++;
578 if ((int)len < r->prefixlen/8 + (r->prefixlen % 8 ? 1 : 0)) return -1;
580 memcpy (&r->prefix, opt, r->prefixlen/8 + (r->prefixlen % 8 ? 1 : 0));
581 opt += r->prefixlen/8 + (r->prefixlen % 8 ? 1 : 0);
583 if (r->message & ZAPI_MESSAGE_NEXTHOP) {
584 if (len < 1) return -1;
585 r->nh_count = *opt++;
587 if (len < (sizeof (uint32_t) + 1) * r->nh_count) return -1;
588 r->nexthops = olsr_malloc ((sizeof r->nexthops->type +
589 sizeof r->nexthops->payload) * r->nh_count,
590 "quagga: parse_ipv4_route_add");
591 for (c = 0; c < r->nh_count; c++) {
592 r->nexthops[c].type = *opt++;
593 memcpy (&r->nexthops[c].payload.v4, opt, sizeof (uint32_t));
594 opt += sizeof (uint32_t);
595 len -= sizeof (uint32_t) + 1;
599 if (r->message & ZAPI_MESSAGE_IFINDEX) {
600 if (len < 1) return -1;
602 if (len < sizeof (uint32_t) * r->ind_num) return -1;
603 r->index = olsr_malloc (sizeof (uint32_t) * r->ind_num,
604 "quagga: parse_ipv4_route_add");
605 memcpy (r->index, opt, r->ind_num * sizeof (uint32_t));
606 opt += sizeof (uint32_t) * r->ind_num;
607 len -= sizeof (uint32_t) * r->ind_num;
610 if (r->message & ZAPI_MESSAGE_DISTANCE) {
611 if (len < 1) return -1;
612 r->distance = *opt++;
616 if (r->message & ZAPI_MESSAGE_METRIC) {
617 if (len < sizeof (uint32_t)) return -1;
618 memcpy (&r->metric, opt, sizeof (uint32_t));
625 static int ipv4_route_add (unsigned char *opt, size_t len) {
630 f = parse_ipv4_route (opt, len, &r);
633 return add_hna4_route (r);
636 static int ipv4_route_delete (unsigned char *opt, size_t len) {
640 f = parse_ipv4_route (opt, len, &r);
643 return delete_hna4_route (r);
647 static int parse_ipv6_route_add (unsigned char *opt __attribute__((unused)), size_t len __attribute__((unused))) {
653 /* start redistribution FROM zebra */
654 int zebra_redistribute (unsigned char type) {
656 if (type > ZEBRA_ROUTE_MAX) return -1;
657 zebra.redistribute[type - 1] = 1;
659 return zebra_send_command (ZEBRA_REDISTRIBUTE_ADD, &type, 1);
665 /* end redistribution FROM zebra */
666 int zebra_disable_redistribute (unsigned char type) {
668 if (type > ZEBRA_ROUTE_MAX) return -1;
669 zebra.redistribute[type - 1] = 0;
671 return zebra_send_command (ZEBRA_REDISTRIBUTE_DELETE, &type, 1);
675 static uint32_t prefixlentomask (uint8_t prefix) {
679 mask = 0xffffffff<<(32-prefix);
686 int add_hna4_route (struct ipv4_route r) {
687 union olsr_ip_addr net, mask;
690 dump_ipv4_route(r, "add_hna4_route");
693 mask.v4 = prefixlentomask(r.prefixlen);
696 add_local_hna4_entry(&net, &mask);
701 int delete_hna4_route (struct ipv4_route r) {
703 union olsr_ip_addr net, mask;
706 dump_ipv4_route(r, "delete_hna4_route");
709 mask.v4 = prefixlentomask(r.prefixlen);
712 remove_local_hna4_entry(&net, &mask) ? 0 : -1;
718 static void free_ipv4_route (struct ipv4_route r) {
720 if(r.message&ZAPI_MESSAGE_IFINDEX && r.ind_num) free(r.index);
721 if(r.message&ZAPI_MESSAGE_NEXTHOP && r.nh_count) free(r.nexthops);
726 static uint8_t masktoprefixlen (uint32_t mask) {
728 uint8_t prefixlen = 0;
732 if (mask) while (mask << ++prefixlen && prefixlen < 32);
739 int zebra_add_olsr_v4_route (struct rt_entry *r) {
741 struct ipv4_route route;
744 route.type = ZEBRA_ROUTE_OLSR; // OLSR
745 route.message = ZAPI_MESSAGE_METRIC;
746 route.flags = zebra.flags;
747 route.prefixlen =(r->rt_dst.prefix_len);
748 route.prefix = r->rt_dst.prefix.v4;
749 if ((r->rt_best->rtp_nexthop.gateway.v4 == r->rt_dst.prefix.v4 &&
750 route.prefixlen == 32)) {
751 route.message |= ZAPI_MESSAGE_IFINDEX | ZAPI_MESSAGE_NEXTHOP;
753 route.index = olsr_malloc (sizeof *route.index,
754 "zebra_add_olsr_v4_route");
755 *route.index = htonl(r->rt_best->rtp_nexthop.iif_index);
756 route.nexthops = olsr_malloc (sizeof route.nexthops->type +
757 sizeof route.nexthops->payload,
758 "zebra_add_olsr_v4_route");
760 route.nexthops->type = 0;
763 route.message |= ZAPI_MESSAGE_NEXTHOP;
765 route.nexthops = olsr_malloc (route.nh_count *
766 (sizeof route.nexthops->type +
767 sizeof route.nexthops->payload),
768 "zebra_add_olsr_v4_route");
769 route.nexthops->type = ZEBRA_NEXTHOP_IPV4;
770 route.nexthops->payload.v4 = r->rt_best->rtp_nexthop.gateway.v4;
773 route.metric = r->rt_best->rtp_metric.hops;
774 route.metric = htonl(route.metric);
776 if (zebra.distance) {
777 route.message |= ZAPI_MESSAGE_DISTANCE;
778 route.distance = zebra.distance;
781 retval = zebra_add_v4_route(route);
782 free_ipv4_route (route);
786 int zebra_del_olsr_v4_route (struct rt_entry *r) {
788 struct ipv4_route route;
790 route.type = ZEBRA_ROUTE_OLSR; // OLSR
791 route.message = ZAPI_MESSAGE_METRIC;
792 route.flags = zebra.flags;
793 route.prefixlen = r->rt_dst.prefix_len;
794 route.prefix = r->rt_dst.prefix.v4;
795 if ((r->rt_best->rtp_nexthop.gateway.v4 == r->rt_dst.prefix.v4 &&
796 route.prefixlen == 32)){
797 route.message |= ZAPI_MESSAGE_IFINDEX;
799 route.index = olsr_malloc (sizeof *route.index,
800 "zebra_add_olsr_v4_route");
801 *route.index = htonl (r->rt_best->rtp_nexthop.iif_index);
802 route.nexthops = olsr_malloc (sizeof route.nexthops->type +
803 sizeof route.nexthops->payload,
804 "zebra_add_olsr_v4_route");
806 route.nexthops->type = 0;
809 route.message |= ZAPI_MESSAGE_NEXTHOP;
811 route.nexthops = olsr_malloc (route.nh_count *
812 (sizeof route.nexthops->type +
813 sizeof route.nexthops->payload),
814 "zebra_add_olsr_v4_route");
815 route.nexthops->type = ZEBRA_NEXTHOP_IPV4;
816 route.nexthops->payload.v4 = r->rt_best->rtp_nexthop.gateway.v4;
818 route.metric = r->rt_best->rtp_metric.hops;
819 route.metric = htonl (route.metric);
821 if (zebra.distance) {
822 route.message |= ZAPI_MESSAGE_DISTANCE;
823 route.distance = zebra.distance;
826 retval = zebra_delete_v4_route(route);
828 free_ipv4_route (route);
832 void zebra_olsr_distance (unsigned char dist) {
833 zebra.distance = dist;
836 void zebra_olsr_localpref (void) {
837 zebra.flags &= ZEBRA_FLAG_SELECTED;
840 void zebra_export_routes (unsigned char t) {
842 zebra.options |= OPTION_EXPORT;
844 zebra.options &= ~OPTION_EXPORT;