📄 quagga.c
字号:
/*************************************************************************** projekt : olsrd-quagga file : quagga.c usage : communication with the zebra-daemon copyright : (C) 2006 by Immo 'FaUl' Wehrenberg e-mail : immo@chaostreff-dortmund.de ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License version 2 as * * published by the Free Software Foundation. * * * ***************************************************************************/#ifdef MY_DEBUG#include <stdio.h>#endif#define HAVE_SOCKLEN_T#include <stdint.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <quagga/zebra.h>#include "quagga.h"#include "olsr.h"#include "log.h"#include "defs.h"#include "local_hna_set.h"#include "routing_table.h"#ifdef USE_UNIX_DOMAIN_SOCKET#include <sys/un.h>#define ZEBRA_SOCKET "/var/run/quagga/zserv.api"#endif#define ZAPI_MESSAGE_NEXTHOP 0x01#define ZAPI_MESSAGE_IFINDEX 0x02#define ZAPI_MESSAGE_DISTANCE 0x04#define ZAPI_MESSAGE_METRIC 0x08#define BUFSIZE 1024#define STATUS_CONNECTED 1#define OPTION_EXPORT 1static struct { char status; // internal status char options; // internal options int sock; // Socket to zebra... char redistribute[ZEBRA_ROUTE_MAX]; char distance; char flags; struct ipv4_route *v4_rt; // routes currently exportet to zebra} zebra;/* prototypes intern */static unsigned char *try_read (ssize_t *);static unsigned char* zebra_route_packet (struct ipv4_route r, ssize_t *);static int parse_interface_add (unsigned char *, size_t);static int parse_interface_delete (unsigned char *, size_t);static int parse_interface_up (unsigned char *, size_t);static int parse_interface_down (unsigned char *, size_t);static int parse_interface_address_add (unsigned char *, size_t);static int parse_interface_address_delete (unsigned char *, size_t);static int parse_ipv4_route (unsigned char *, size_t, struct ipv4_route *);static int ipv4_route_add (unsigned char *, size_t);static int ipv4_route_delete (unsigned char *, size_t);static int parse_ipv6_route_add (unsigned char*, size_t);static void zebra_reconnect (void);static void zebra_connect (void);static uint32_t prefixlentomask (uint8_t);static void free_ipv4_route (struct ipv4_route);/* static void update_olsr_zebra_routes (struct ipv4_route*, struct ipv4_route*);static struct ipv4_route *zebra_create_ipv4_route_table_entry (uint32_t, uint32_t, uint32_t);static struct ipv4_route *zebra_create_ipv4_route_table (void);static void zebra_free_ipv4_route_table (struct ipv4_route*);*//*static uint8_t masktoprefixlen (uint32_t);*/#ifdef MY_DEBUGstatic void dump_ipv4_route (struct ipv4_route r, char *c) { int i = 0, x = 0; puts (c); printf("type: %d\n", r.type); puts("flags:"); printf(" Internal: %s\n",r.flags&ZEBRA_FLAG_INTERNAL?"yes":"no"); printf(" Selfroute %s\n",r.flags&ZEBRA_FLAG_SELFROUTE?"yes":"no"); printf(" Blackhole %s\n",r.flags&ZEBRA_FLAG_BLACKHOLE?"yes":"no"); printf(" IBGP: %s\n",r.flags&ZEBRA_FLAG_IBGP?"yes":"no"); printf(" Selected: %s\n",r.flags&ZEBRA_FLAG_SELECTED?"yes":"no"); printf(" Changed: %s\n",r.flags&ZEBRA_FLAG_CHANGED?"yes":"no"); printf(" static: %s\n",r.flags&ZEBRA_FLAG_STATIC?"yes":"no"); printf(" reject: %s\n",r.flags&ZEBRA_FLAG_REJECT?"yes":"no"); puts("message:"); printf(" nexthop: %s\n",r.message&ZAPI_MESSAGE_NEXTHOP?"yes":"no"); printf(" ifindex: %s\n",r.message&ZAPI_MESSAGE_IFINDEX?"yes":"no"); printf(" distance: %s\n",r.message&ZAPI_MESSAGE_DISTANCE?"yes":"no"); printf(" metric: %s\n",r.message&ZAPI_MESSAGE_METRIC?"yes":"no"); printf("Prefixlen: %d\n", r.prefixlen); printf("Prefix: %d", (unsigned char)r.prefix); c = (char*) &r.prefix; while (++i < (r.prefixlen/8 + (r.prefixlen % 8 ? 1 : 0))) printf(".%d",(unsigned char)*(c + i)); while (i++ < 4) printf(".0"); puts(""); i=0; if (r.message&ZAPI_MESSAGE_NEXTHOP) { printf("nexthop-count: %d\n", r.nh_count); while (i++ < r.nh_count) { if (r.nexthops[i].type == ZEBRA_NEXTHOP_IPV4) { c = (unsigned char*) &r.nexthops[i].payload.v4; printf ("Nexthop %d: %d", i, (unsigned char) *c); while (++x < 4) { printf (".%d", (unsigned char) c[x]); } puts(""); } } i=0; } if (r.message&ZAPI_MESSAGE_IFINDEX) { printf("index-number: %d\n", r.ind_num); while (i++ < r.ind_num) printf("Index: %d: %d\n", i, r.index[i]); i=0; if (r.message&ZAPI_MESSAGE_DISTANCE) printf("Distance: %d\n",r.distance); if (r.message&ZAPI_MESSAGE_METRIC) printf("Metric: %d\n",r.metric); puts("\n"); }}#endifvoid *my_realloc (void *buf, size_t s, const char *c) { buf = realloc (buf, s); if (!buf) { OLSR_PRINTF (1, "(QUAGGA) OUT OF MEMORY: %s\n", strerror(errno)); olsr_syslog(OLSR_LOG_ERR, "olsrd: out of memory!: %m\n"); olsr_exit(c, EXIT_FAILURE); } return buf;}void init_zebra (void) { zebra_connect(); if (!zebra.status&STATUS_CONNECTED) olsr_exit ("(QUAGGA) AIIIII, could not connect to zebra! is zebra running?", EXIT_FAILURE);}void zebra_cleanup (void) { int i; struct rt_entry *tmp; if (zebra.options & OPTION_EXPORT) { OLSR_FOR_ALL_RT_ENTRIES(tmp) { zebra_del_olsr_v4_route(tmp); } OLSR_FOR_ALL_RT_ENTRIES_END(tmp); } for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (zebra.redistribute[i]) zebra_disable_redistribute(i + 1);}static void zebra_reconnect (void) { struct rt_entry *tmp; int i; zebra_connect(); if (!zebra.status & STATUS_CONNECTED) return; // try again next time if (zebra.options & OPTION_EXPORT) { OLSR_FOR_ALL_RT_ENTRIES(tmp) { zebra_add_olsr_v4_route (tmp); } OLSR_FOR_ALL_RT_ENTRIES_END(tmp); } for (i = 0; i < ZEBRA_ROUTE_MAX; i++) if (zebra.redistribute[i]) zebra_redistribute(i + 1); /* Zebra sends us all routes of type it knows after zebra_redistribute(type) */}/* Connect to the zebra-daemon, returns a socket */static void zebra_connect (void) { int ret;#ifndef USE_UNIX_DOMAIN_SOCKET struct sockaddr_in i; if (close (zebra.sock) < 0) olsr_exit ("(QUAGGA) Could not close socket!", EXIT_FAILURE); zebra.sock = socket (AF_INET,SOCK_STREAM, 0);#else struct sockaddr_un i; if (close (zebra.sock) < 0) olsr_exit ("(QUAGGA) Could not close socket!", EXIT_FAILURE); zebra.sock = socket (AF_UNIX,SOCK_STREAM, 0);#endif if (zebra.sock <0 ) olsr_exit("(QUAGGA) Could not create socket!", EXIT_FAILURE); memset (&i, 0, sizeof i);#ifndef USE_UNIX_DOMAIN_SOCKET i.sin_family = AF_INET; i.sin_port = htons (ZEBRA_PORT); i.sin_addr.s_addr = htonl (INADDR_LOOPBACK);#else i.sun_family = AF_UNIX; strcpy (i.sun_path, ZEBRA_SOCKET);#endif ret = connect (zebra.sock, (struct sockaddr *)&i, sizeof i); if (ret < 0) zebra.status &= ~STATUS_CONNECTED; else zebra.status |= STATUS_CONNECTED;} /* Sends a command to zebra, command is the command defined in zebra.h, options is the packet-payload, optlen the length, of the payload */unsigned char zebra_send_command (unsigned char command, unsigned char *options, int optlen) {#ifdef ZEBRA_HEADER_MARKER char *p = olsr_malloc (optlen + 6, "zebra_send_command"); uint16_t length = optlen + 6; /* length of option + command + packet_length + marker + zserv-version */ uint16_t cmd;#else char *p = olsr_malloc (optlen + 3, "zebra_send_command"); uint16_t length = optlen + 3; // length of option + command + packet_length#endif char *pnt = p; int ret; uint16_t len = htons(length); memcpy (p, &len, 2);#ifdef ZEBRA_HEADER_MARKER p[2] = ZEBRA_HEADER_MARKER; p[3] = ZSERV_VERSION; cmd = htons (command); memcpy (p + 4, &cmd, 2); memcpy (p + 6, options, optlen);#else p[2] = command; memcpy (p + 3, options, optlen);#endif errno = 0; do { ret = write (zebra.sock, p, length); if (ret < 0) { if (errno == EINTR) { errno = 0; continue; } else { olsr_printf (1, "(QUAGGA) Disconnected from zebra\n"); zebra.status &= ~STATUS_CONNECTED; free (pnt); return -1; } } p = p+ret; } while ((length -= ret)); free (pnt); return 0;}/* Creates a Route-Packet-Payload, needs address, netmask, nexthop, distance, and a pointer of an size_t */static unsigned char* zebra_route_packet (struct ipv4_route r, ssize_t *optlen) { int count; unsigned char *cmdopt, *t; *optlen = 4; // first: type, flags, message, prefixlen *optlen += r.prefixlen / 8 + (r.prefixlen % 8 ? 1 : 0); // + prefix if (r.message & ZAPI_MESSAGE_NEXTHOP) { if (r.nexthops->type == ZEBRA_NEXTHOP_IPV4 || r.nexthops->type == ZEBRA_NEXTHOP_IPV4_IFINDEX){ *optlen += (sizeof r.nexthops->payload.v4 + sizeof r.nexthops->type) * r.nh_count + 1; } else if (r.nexthops->type == 0) *optlen += 5; } if (r.message & ZAPI_MESSAGE_IFINDEX) *optlen += r.ind_num * sizeof *r.index + 1; if (r.message & ZAPI_MESSAGE_DISTANCE) (*optlen)++; if (r.message & ZAPI_MESSAGE_METRIC) *optlen += sizeof r.metric; cmdopt = olsr_malloc (*optlen, "zebra add_v4_route"); t = cmdopt; *t++ = r.type; *t++ = r.flags; *t++ = r.message; *t++ = r.prefixlen; for (count = 0; count < r.prefixlen/8 + (r.prefixlen % 8 ? 1 : 0); count++) { *t++ = *((char*)&r.prefix + count); /* this is so sick!! */ } if (r.message & ZAPI_MESSAGE_NEXTHOP) { *t++ = r.nh_count; *t++ = r.nexthops->type; if (r.nexthops->type == ZEBRA_NEXTHOP_IPV4 || r.nexthops->type == ZEBRA_NEXTHOP_IPV4_IFINDEX) { for (count = 0; count != r.nh_count; count++) { memcpy (t, &r.nexthops[count].payload.v4, sizeof r.nexthops->payload.v4); t += sizeof r.nexthops->payload.v4; } } else if (r.nexthops->type == 0) { *t++ = 0; *t++ = 0; *t++ = 0; } } if (r.message & ZAPI_MESSAGE_IFINDEX) { *t++ = r.ind_num; memcpy (t, r.index, sizeof *r.index * r.ind_num); t += sizeof r.index * r.ind_num; } if (r.message & ZAPI_MESSAGE_DISTANCE) *t++ = r.distance; if (r.message & ZAPI_MESSAGE_METRIC) { memcpy (t, &r.metric, sizeof r.metric); t += sizeof r.metric; } return cmdopt;}/* adds a route to zebra-daemon */int zebra_add_v4_route (struct ipv4_route r) { unsigned char *cmdopt; ssize_t optlen; int retval; cmdopt = zebra_route_packet (r, &optlen); retval = zebra_send_command (ZEBRA_IPV4_ROUTE_ADD, cmdopt, optlen); free (cmdopt); return retval; }/* deletes a route from the zebra-daemon */int zebra_delete_v4_route (struct ipv4_route r) { unsigned char *cmdopt; ssize_t optlen; int retval; cmdopt = zebra_route_packet (r, &optlen); retval = zebra_send_command (ZEBRA_IPV4_ROUTE_DELETE, cmdopt, optlen); free (cmdopt); return retval; }/* Check wether there is data from zebra aviable */void zebra_check (void* foo __attribute__((unused))) { unsigned char *data, *f; ssize_t len, ret; if (!(zebra.status & STATUS_CONNECTED)) { zebra_reconnect(); return; } data = try_read (&len); if (data) { f = data; do { ret = zebra_parse_packet (f, len); if (!ret) // something wired happened olsr_exit ("(QUAGGA) Zero message length??? ", EXIT_FAILURE); f += ret; } while ((f - data) < len); free (data); }}// tries to read a packet from zebra_socket// if there is something to read - make sure to read whole packagesstatic unsigned char *try_read (ssize_t *len) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -