summaryrefslogtreecommitdiffstats
path: root/babeld/xroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'babeld/xroute.c')
-rw-r--r--babeld/xroute.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/babeld/xroute.c b/babeld/xroute.c
new file mode 100644
index 0000000..30204cd
--- /dev/null
+++ b/babeld/xroute.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: MIT
+/*
+Copyright (c) 2007, 2008 by Juliusz Chroboczek
+Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
+*/
+
+#include <zebra.h>
+#include "if.h"
+#include "log.h"
+
+#include "babeld.h"
+#include "kernel.h"
+#include "neighbour.h"
+#include "message.h"
+#include "route.h"
+#include "xroute.h"
+#include "util.h"
+#include "babel_interface.h"
+
+static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
+ unsigned short metric, unsigned int ifindex,
+ int proto, int send_updates);
+
+static struct xroute *xroutes;
+static int numxroutes = 0, maxxroutes = 0;
+
+/* Add redistributed route to Babel table. */
+int
+babel_route_add (struct zapi_route *api)
+{
+ unsigned char uchar_prefix[16];
+
+ switch (api->prefix.family) {
+ case AF_INET:
+ inaddr_to_uchar(uchar_prefix, &api->prefix.u.prefix4);
+ debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route coming from Zebra.");
+ xroute_add_new_route(uchar_prefix, api->prefix.prefixlen + 96,
+ api->metric, api->nexthops[0].ifindex, 0, 1);
+ break;
+ case AF_INET6:
+ in6addr_to_uchar(uchar_prefix, &api->prefix.u.prefix6);
+ debugf(BABEL_DEBUG_ROUTE, "Adding new ipv6 route coming from Zebra.");
+ xroute_add_new_route(uchar_prefix, api->prefix.prefixlen,
+ api->metric, api->nexthops[0].ifindex, 0, 1);
+ break;
+ }
+
+ return 0;
+}
+
+/* Remove redistributed route from Babel table. */
+int
+babel_route_delete (struct zapi_route *api)
+{
+ unsigned char uchar_prefix[16];
+ struct xroute *xroute = NULL;
+
+ switch (api->prefix.family) {
+ case AF_INET:
+ inaddr_to_uchar(uchar_prefix, &api->prefix.u.prefix4);
+ xroute = find_xroute(uchar_prefix, api->prefix.prefixlen + 96);
+ if (xroute != NULL) {
+ debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra).");
+ flush_xroute(xroute);
+ }
+ break;
+ case AF_INET6:
+ in6addr_to_uchar(uchar_prefix, &api->prefix.u.prefix6);
+ xroute = find_xroute(uchar_prefix, api->prefix.prefixlen);
+ if (xroute != NULL) {
+ debugf(BABEL_DEBUG_ROUTE, "Removing ipv6 route (from zebra).");
+ flush_xroute(xroute);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+struct xroute *
+find_xroute(const unsigned char *prefix, unsigned char plen)
+{
+ int i;
+ for(i = 0; i < numxroutes; i++) {
+ if(xroutes[i].plen == plen &&
+ memcmp(xroutes[i].prefix, prefix, 16) == 0)
+ return &xroutes[i];
+ }
+ return NULL;
+}
+
+void
+flush_xroute(struct xroute *xroute)
+{
+ int i;
+
+ i = xroute - xroutes;
+ assert(i >= 0 && i < numxroutes);
+
+ if(i != numxroutes - 1)
+ memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute));
+ numxroutes--;
+ VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute));
+
+ if(numxroutes == 0) {
+ free(xroutes);
+ xroutes = NULL;
+ maxxroutes = 0;
+ } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) {
+ struct xroute *new_xroutes;
+ int n = maxxroutes / 2;
+ new_xroutes = realloc(xroutes, n * sizeof(struct xroute));
+ if(new_xroutes == NULL)
+ return;
+ xroutes = new_xroutes;
+ maxxroutes = n;
+ }
+}
+
+static int
+add_xroute(unsigned char prefix[16], unsigned char plen,
+ unsigned short metric, unsigned int ifindex, int proto)
+{
+ struct xroute *xroute = find_xroute(prefix, plen);
+ if(xroute) {
+ if(xroute->metric <= metric)
+ return 0;
+ xroute->metric = metric;
+ return 1;
+ }
+
+ if(numxroutes >= maxxroutes) {
+ struct xroute *new_xroutes;
+ int n = maxxroutes < 1 ? 8 : 2 * maxxroutes;
+ new_xroutes = xroutes == NULL ?
+ malloc(n * sizeof(struct xroute)) :
+ realloc(xroutes, n * sizeof(struct xroute));
+ if(new_xroutes == NULL)
+ return -1;
+ maxxroutes = n;
+ xroutes = new_xroutes;
+ }
+
+ memcpy(xroutes[numxroutes].prefix, prefix, 16);
+ xroutes[numxroutes].plen = plen;
+ xroutes[numxroutes].metric = metric;
+ xroutes[numxroutes].ifindex = ifindex;
+ xroutes[numxroutes].proto = proto;
+ numxroutes++;
+ return 1;
+}
+
+/* Returns an overestimate of the number of xroutes. */
+int
+xroutes_estimate(void)
+{
+ return numxroutes;
+}
+
+struct xroute_stream {
+ int index;
+};
+
+struct
+xroute_stream *
+xroute_stream(void)
+{
+ struct xroute_stream *stream = malloc(sizeof(struct xroute_stream));
+ if(stream == NULL)
+ return NULL;
+
+ stream->index = 0;
+ return stream;
+}
+
+struct xroute *
+xroute_stream_next(struct xroute_stream *stream)
+{
+ if(stream->index < numxroutes)
+ return &xroutes[stream->index++];
+ else
+ return NULL;
+}
+
+void
+xroute_stream_done(struct xroute_stream *stream)
+{
+ free(stream);
+}
+
+/* add an xroute, verifying some conditions; return 0 if there is no changes */
+static int
+xroute_add_new_route(unsigned char prefix[16], unsigned char plen,
+ unsigned short metric, unsigned int ifindex,
+ int proto, int send_updates)
+{
+ int rc;
+ if(martian_prefix(prefix, plen))
+ return 0;
+ metric = redistribute_filter(prefix, plen, ifindex, proto);
+ if(metric < INFINITY) {
+ rc = add_xroute(prefix, plen, metric, ifindex, proto);
+ if(rc > 0) {
+ struct babel_route *route;
+ route = find_installed_route(prefix, plen);
+ if(route)
+ uninstall_route(route);
+ if(send_updates)
+ send_update(NULL, 0, prefix, plen);
+ return 1;
+ }
+ }
+ return 0;
+}