// SPDX-License-Identifier: MIT /* Copyright (c) 2007, 2008 by Juliusz Chroboczek Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek */ #include #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; }