summaryrefslogtreecommitdiff
path: root/babeld/xroute.c
diff options
context:
space:
mode:
Diffstat (limited to 'babeld/xroute.c')
-rw-r--r--babeld/xroute.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/babeld/xroute.c b/babeld/xroute.c
new file mode 100644
index 00000000..42f83d07
--- /dev/null
+++ b/babeld/xroute.c
@@ -0,0 +1,226 @@
+/*
+ * This file is free software: you may copy, redistribute and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+Copyright (c) 2007, 2008 by Juliusz Chroboczek
+Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#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"
+
+struct xroute *xroutes;
+int numxroutes = 0;
+int maxxroutes = 0;
+
+/* Add redistributed route to Babel table. */
+int
+babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
+ unsigned int ifindex, struct in_addr *nexthop)
+{
+ unsigned char uchar_prefix[16];
+
+ inaddr_to_uchar(uchar_prefix, &prefix->prefix);
+ debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra.");
+ xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex,
+ 0, 1);
+ return 0;
+}
+
+/* Remove redistributed route from Babel table. */
+int
+babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix,
+ unsigned int ifindex)
+{
+ unsigned char uchar_prefix[16];
+ struct xroute *xroute = NULL;
+
+ inaddr_to_uchar(uchar_prefix, &prefix->prefix);
+ xroute = find_xroute(uchar_prefix, prefix->prefixlen);
+ if (xroute != NULL) {
+ debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra).");
+ flush_xroute(xroute);
+ }
+ return 0;
+}
+
+/* Add redistributed route to Babel table. */
+int
+babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
+ unsigned int ifindex, struct in6_addr *nexthop)
+{
+ unsigned char uchar_prefix[16];
+
+ in6addr_to_uchar(uchar_prefix, &prefix->prefix);
+ debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra.");
+ xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex,
+ 0, 1);
+ return 0;
+}
+
+/* Remove redistributed route from Babel table. */
+int
+babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix,
+ unsigned int ifindex)
+{
+ unsigned char uchar_prefix[16];
+ struct xroute *xroute = NULL;
+
+ in6addr_to_uchar(uchar_prefix, &prefix->prefix);
+ xroute = find_xroute(uchar_prefix, prefix->prefixlen);
+ if (xroute != NULL) {
+ debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra).");
+ flush_xroute(xroute);
+ }
+ 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;
+}
+
+/* add an xroute, verifying some conditions; return 0 if there is no changes */
+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 route *route;
+ route = find_installed_route(prefix, plen);
+ if(route) {
+ if(allow_duplicates < 0 ||
+ metric < allow_duplicates)
+ uninstall_route(route);
+ }
+ if(send_updates)
+ send_update(NULL, 0, prefix, plen);
+ return 1;
+ }
+ }
+ return 0;
+}