Browse Source

babeld: Initial import, for Babel routing protocol.

* Initial import of the Babel routing protocol, ported to Quagga.
* LICENCE: Update the original LICENCE file to include all known potentially
  applicable copyright claims.  Ask that any future contributors to babeld/
  grant MIT/X11 licence to their work.
* *.{c,h}: Add GPL headers, in according with the SFLC guidance on
  dealing with potentially mixed GPL/other licensed work, at:

  https://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html
Paul Jakma 8 years ago
parent
commit
5734509c05

+ 2 - 2
Makefile.am

@@ -1,10 +1,10 @@
 ## Process this file with automake to produce Makefile.in.
 
-SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
+SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \
          @ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
          redhat @SOLARIS@
 
-DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
+DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \
 	  isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
 	  solaris
 

+ 7 - 0
babeld/.gitignore

@@ -0,0 +1,7 @@
+*
+!*.c
+!*.h
+!LICENCE
+!Makefile.am
+!babeld.conf.sample
+!.gitignore

+ 36 - 0
babeld/LICENCE

@@ -0,0 +1,36 @@
+Code in this directory is made available under the following licence:
+
+  ---------------------------------------------------------------------------
+  Copyright (c) 2007, 2008 by 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.
+  ---------------------------------------------------------------------------
+
+The code also makes calls to and links with the "libzebra" code of Quagga,
+in the lib/ directory of this project, which is subject to the GPL licence
+as given in the top-level COPYING file included with Quagga.
+
+Contributors to the code in babeld/ are asked to make their work available
+under the same MIT/X11 licence as given immediately above.  Please indicate
+your assent to this by updating this file and appending the appropriate
+
+  Copyright <year> <Author name>, <author contact details>
+
+line to the existing copyright assertion lines in the MIT/X11 licence text
+above in this file.

+ 29 - 0
babeld/Makefile.am

@@ -0,0 +1,29 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@
+DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
+INSTALL_SDATA=@INSTALL@ -m 600
+
+AM_CFLAGS = $(PICFLAGS)
+AM_LDFLAGS = $(PILDFLAGS)
+
+noinst_LIBRARIES = libbabel.a
+sbin_PROGRAMS = babeld
+
+libbabel_a_SOURCES = \
+	babel_zebra.c net.c kernel.c util.c source.c neighbour.c	\
+	route.c xroute.c message.c resend.c babel_interface.c babeld.c	\
+	babel_filter.c
+
+noinst_HEADERS = \
+	babel_zebra.h net.h kernel.h util.h source.h neighbour.h	\
+	route.h xroute.h message.h resend.h babel_interface.h babeld.h	\
+	babel_filter.h
+
+babeld_SOURCES = \
+	babel_main.c $(libbabel_a_SOURCES)
+
+babeld_LDADD = ../lib/libzebra.la @LIBCAP@
+
+examplesdir = $(exampledir)
+dist_examples_DATA = babeld.conf.sample

+ 188 - 0
babeld/babel_filter.c

@@ -0,0 +1,188 @@
+/*  
+ *  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 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 "babel_filter.h"
+#include "vty.h"
+#include "filter.h"
+#include "log.h"
+#include "plist.h"
+#include "distribute.h"
+#include "util.h"
+
+
+int
+babel_filter_in (struct prefix *p, babel_interface_nfo *babel_ifp)
+{
+    struct distribute *dist;
+    struct access_list *alist;
+    struct prefix_list *plist;
+
+    /* Input distribute-list filtering. */
+    if (babel_ifp != NULL && babel_ifp->list[BABEL_FILTER_IN]) {
+        if (access_list_apply (babel_ifp->list[BABEL_FILTER_IN], p)
+            == FILTER_DENY) {
+            debugf(BABEL_DEBUG_FILTER,
+                   "%s/%d filtered by distribute in",
+                   p->family == AF_INET ?
+                   inet_ntoa(p->u.prefix4) :
+                   inet6_ntoa (p->u.prefix6),
+                   p->prefixlen);
+            return -1;
+	}
+    }
+    if (babel_ifp != NULL && babel_ifp->prefix[BABEL_FILTER_IN]) {
+        if (prefix_list_apply (babel_ifp->prefix[BABEL_FILTER_IN], p)
+            == PREFIX_DENY) {
+            debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
+                        p->family == AF_INET ?
+                        inet_ntoa(p->u.prefix4) :
+                        inet6_ntoa (p->u.prefix6),
+                        p->prefixlen);
+            return -1;
+	}
+    }
+
+    /* All interface filter check. */
+    dist = distribute_lookup (NULL);
+    if (dist) {
+        if (dist->list[DISTRIBUTE_IN]) {
+            alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
+
+            if (alist) {
+                if (access_list_apply (alist, p) == FILTER_DENY) {
+                    debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
+                                p->family == AF_INET ?
+                                inet_ntoa(p->u.prefix4) :
+                                inet6_ntoa (p->u.prefix6),
+                                p->prefixlen);
+                    return -1;
+		}
+	    }
+	}
+        if (dist->prefix[DISTRIBUTE_IN]) {
+            plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
+            if (plist) {
+                if (prefix_list_apply (plist, p) == PREFIX_DENY) {
+                    debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in",
+                                p->family == AF_INET ?
+                                inet_ntoa(p->u.prefix4) :
+                                inet6_ntoa (p->u.prefix6),
+                                p->prefixlen);
+                    return -1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+int
+babel_filter_out (struct prefix *p, babel_interface_nfo *babel_ifp)
+{
+    struct distribute *dist;
+    struct access_list *alist;
+    struct prefix_list *plist;
+
+    if (babel_ifp != NULL && babel_ifp->list[BABEL_FILTER_OUT]) {
+        if (access_list_apply (babel_ifp->list[BABEL_FILTER_OUT], p)
+            == FILTER_DENY) {
+            debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out",
+                        p->family == AF_INET ?
+                        inet_ntoa(p->u.prefix4) :
+                        inet6_ntoa (p->u.prefix6),
+                        p->prefixlen);
+            return -1;
+	}
+    }
+    if (babel_ifp != NULL && babel_ifp->prefix[BABEL_FILTER_OUT]) {
+        if (prefix_list_apply (babel_ifp->prefix[BABEL_FILTER_OUT], p)
+            == PREFIX_DENY) {
+            debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out",
+                        p->family == AF_INET ?
+                        inet_ntoa(p->u.prefix4) :
+                        inet6_ntoa (p->u.prefix6),
+                        p->prefixlen);
+            return -1;
+	}
+    }
+
+    /* All interface filter check. */
+    dist = distribute_lookup (NULL);
+    if (dist) {
+        if (dist->list[DISTRIBUTE_OUT]) {
+            alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
+            if (alist) {
+                if (access_list_apply (alist, p) == FILTER_DENY) {
+                    debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out",
+                                p->family == AF_INET ?
+                                inet_ntoa(p->u.prefix4) :
+                                inet6_ntoa (p->u.prefix6),
+                                p->prefixlen);
+                    return -1;
+		}
+	    }
+	}
+        if (dist->prefix[DISTRIBUTE_OUT]) {
+            plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
+            if (plist) {
+                if (prefix_list_apply (plist, p) == PREFIX_DENY) {
+                    debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out",
+                                p->family == AF_INET ?
+                                inet_ntoa(p->u.prefix4) :
+                                inet6_ntoa (p->u.prefix6),
+                                p->prefixlen);
+                    return -1;
+		}
+	    }
+	}
+    }
+    return 0;
+}
+
+int
+babel_filter_redistribute (struct prefix *p,
+                           babel_interface_nfo *babel_ifp)
+{
+    debugf(BABEL_DEBUG_FILTER, "%s/%d WARNING: no redistribute filter implemented !!!!",
+                p->family == AF_INET ?
+                inet_ntoa(p->u.prefix4) :
+                inet6_ntoa (p->u.prefix6),
+                p->prefixlen);
+    return 0; /* TODO: it redistributes always */
+}

+ 54 - 0
babeld/babel_filter.h

@@ -0,0 +1,54 @@
+/*  
+ *  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 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.
+*/
+
+#ifndef BABELD_BABEL_FILTER_H
+#define BABELD_BABEL_FILTER_H
+
+#include <zebra.h>
+#include "prefix.h"
+#include "babel_interface.h"
+
+/* filter route coming from other worlds */
+int babel_filter_in  (struct prefix *, babel_interface_nfo *);
+/* filter route sending to other worlds */
+int babel_filter_out (struct prefix *, babel_interface_nfo *);
+/* filter route coming from our friend zebra */
+int babel_filter_redistribute
+                     (struct prefix *, babel_interface_nfo *);
+
+#endif /* BABELD_BABEL_FILTER_H */

+ 778 - 0
babeld/babel_interface.c

@@ -0,0 +1,778 @@
+/*  
+ *  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 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#include <zebra.h>
+#include "memory.h"
+#include "log.h"
+#include "command.h"
+#include "prefix.h"
+#include "vector.h"
+
+#include "babel_main.h"
+#include "util.h"
+#include "kernel.h"
+#include "babel_interface.h"
+#include "message.h"
+#include "route.h"
+#include "babel_zebra.h"
+
+
+static int babel_enable_if_lookup (const char *ifname);
+static int babel_enable_if_add (const char *ifname);
+static int babel_enable_if_delete (const char *ifname);
+static int interface_recalculate(struct interface *ifp);
+static int interface_reset(struct interface *ifp);
+static int babel_if_new_hook    (struct interface *ifp);
+static int babel_if_delete_hook (struct interface *ifp);
+static int interface_config_write (struct vty *vty);
+static babel_interface_nfo * babel_interface_allocate ();
+static void babel_interface_free (babel_interface_nfo *bi);
+
+
+static vector babel_enable_if;                 /* enable interfaces (by cmd). */
+static struct cmd_node babel_interface_node =  /* babeld's interface node.    */
+{
+    INTERFACE_NODE,
+    "%s(config-if)# ",
+    1 /* VTYSH */
+};
+
+
+int
+babel_interface_up (int cmd, struct zclient *client, zebra_size_t length)
+{
+    struct stream *s = NULL;
+    struct interface *ifp = NULL;
+
+    debugf(BABEL_DEBUG_IF, "receive a 'interface up'");
+
+    s = zclient->ibuf;
+    ifp = zebra_interface_state_read(s);
+
+    if (ifp == NULL) {
+        return 0;
+    }
+
+    interface_recalculate(ifp);
+    return 0;
+}
+
+int
+babel_interface_down (int cmd, struct zclient *client, zebra_size_t length)
+{
+    struct stream *s = NULL;
+    struct interface *ifp = NULL;
+
+    debugf(BABEL_DEBUG_IF, "receive a 'interface down'");
+
+    s = zclient->ibuf;
+    ifp = zebra_interface_state_read(s);
+
+    if (ifp == NULL) {
+        return 0;
+    }
+
+    interface_reset(ifp);
+    return 0;
+}
+
+int
+babel_interface_add (int cmd, struct zclient *client, zebra_size_t length)
+{
+    struct interface *ifp = NULL;
+
+    debugf(BABEL_DEBUG_IF, "receive a 'interface add'");
+
+    /* read and add the interface in the iflist. */
+    ifp = zebra_interface_add_read (zclient->ibuf);
+
+    if (ifp == NULL) {
+        return 0;
+    }
+
+    interface_recalculate(ifp);
+
+    return 0;
+}
+
+int
+babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length)
+{
+    debugf(BABEL_DEBUG_IF, "receive a 'interface delete'");
+    return 0;
+}
+
+int
+babel_interface_address_add (int cmd, struct zclient *client,
+                             zebra_size_t length)
+{
+    babel_interface_nfo *babel_ifp;
+    struct connected *ifc;
+    struct prefix *prefix;
+
+    debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
+
+    ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
+                                        zclient->ibuf);
+
+    if (ifc == NULL)
+        return 0;
+
+    prefix = ifc->address;
+
+    if (prefix->family == AF_INET) {
+        flush_interface_routes(ifc->ifp, 0);
+        babel_ifp = babel_get_if_nfo(ifc->ifp);
+        if (babel_ifp->ipv4 == NULL) {
+            babel_ifp->ipv4 = malloc(4);
+            if (babel_ifp->ipv4 == NULL) {
+                zlog_err("not einough memory");
+            } else {
+                memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
+            }
+        }
+    }
+
+    send_request(ifc->ifp, NULL, 0);
+    send_update(ifc->ifp, 0, NULL, 0);
+
+    return 0;
+}
+
+int
+babel_interface_address_delete (int cmd, struct zclient *client,
+                                zebra_size_t length)
+{
+    babel_interface_nfo *babel_ifp;
+    struct connected *ifc;
+    struct prefix *prefix;
+
+    debugf(BABEL_DEBUG_IF, "receive a 'interface address add'");
+
+    ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD,
+                                        zclient->ibuf);
+
+    if (ifc == NULL)
+        return 0;
+
+    prefix = ifc->address;
+
+    if (prefix->family == AF_INET) {
+        flush_interface_routes(ifc->ifp, 0);
+        babel_ifp = babel_get_if_nfo(ifc->ifp);
+        if (babel_ifp->ipv4 != NULL
+            && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) {
+            free(babel_ifp->ipv4);
+            babel_ifp->ipv4 = NULL;
+        }
+    }
+
+    send_request(ifc->ifp, NULL, 0);
+    send_update(ifc->ifp, 0, NULL, 0);
+
+    return 0;
+}
+
+/* Lookup function. */
+static int
+babel_enable_if_lookup (const char *ifname)
+{
+    unsigned int i;
+    char *str;
+
+    for (i = 0; i < vector_active (babel_enable_if); i++)
+        if ((str = vector_slot (babel_enable_if, i)) != NULL)
+            if (strcmp (str, ifname) == 0)
+                return i;
+    return -1;
+}
+
+/* Add interface to babel_enable_if. */
+static int
+babel_enable_if_add (const char *ifname)
+{
+    int ret;
+    struct interface *ifp = NULL;
+
+    ret = babel_enable_if_lookup (ifname);
+    if (ret >= 0)
+        return -1;
+
+    vector_set (babel_enable_if, strdup (ifname));
+
+    ifp = if_lookup_by_name(ifname);
+    if (ifp != NULL)
+        babel_get_if_nfo(ifp)->flags |= BABEL_IF_IS_ENABLE;
+
+    return 1;
+}
+
+/* Delete interface from babel_enable_if. */
+static int
+babel_enable_if_delete (const char *ifname)
+{
+    int babel_enable_if_index;
+    char *str;
+    struct interface *ifp = NULL;
+
+    babel_enable_if_index = babel_enable_if_lookup (ifname);
+    if (babel_enable_if_index < 0)
+        return -1;
+
+    str = vector_slot (babel_enable_if, babel_enable_if_index);
+    free (str);
+    vector_unset (babel_enable_if, babel_enable_if_index);
+
+    ifp = if_lookup_by_name(ifname);
+    if (ifp != NULL)
+        babel_get_if_nfo(ifp)->flags &= ~BABEL_IF_IS_ENABLE;
+
+    return 1;
+}
+
+
+/* [Babel Command] Babel enable on specified interface or matched network. */
+DEFUN (babel_network,
+       babel_network_cmd,
+       "network IF_OR_ADDR",
+       "Babel enable on specified interface or network.\n"
+       "Interface or address")
+{
+    int ret;
+    struct prefix p;
+
+    ret = str2prefix (argv[0], &p);
+
+    /* Given string is:               */
+    if (ret) /* an IPv4 or v6 network */
+        return CMD_ERR_NO_MATCH; /* not implemented yet */
+    else     /* an interface name     */
+        ret = babel_enable_if_add (argv[0]);
+
+    if (ret < 0) {
+        vty_out (vty, "There is same network configuration %s%s", argv[0],
+                 VTY_NEWLINE);
+        return CMD_WARNING;
+    }
+
+    return CMD_SUCCESS;
+}
+
+/* [Babel Command] Babel enable on specified interface or matched network. */
+DEFUN (no_babel_network,
+       no_babel_network_cmd,
+       "no network IF_OR_ADDR",
+       NO_STR
+       "Babel enable on specified interface or network.\n"
+       "Interface or address")
+{
+    int ret;
+    struct prefix p;
+
+    ret = str2prefix (argv[0], &p);
+
+    /* Given string is:               */
+    if (ret) /* an IPv4 or v6 network */
+        return CMD_ERR_NO_MATCH; /* not implemented yet */
+    else     /* an interface name     */
+        ret = babel_enable_if_delete (argv[0]);
+
+    if (ret < 0) {
+        vty_out (vty, "can't find network %s%s", argv[0],
+                 VTY_NEWLINE);
+        return CMD_WARNING;
+    }
+
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command] Tell the interface is wire. */
+DEFUN (babel_set_wired,
+       babel_set_wired_cmd,
+       "wired",
+       "Set this interface as wired (default: wireless).\n"
+       "No attributes")
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+
+    ifp = vty->index;
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    assert (babel_ifp != NULL);
+    babel_ifp->flags |= BABEL_IF_WIRED;
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command] Tell the interface is wireless (default). */
+DEFUN (babel_set_wireless,
+       babel_set_wireless_cmd,
+       "wireless",
+       NO_STR
+       "Set this interface as wireless (is default).\n"
+       "No attributes")
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+
+    ifp = vty->index;
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    assert (babel_ifp != NULL);
+    babel_ifp->flags &= ~BABEL_IF_WIRED;
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command] Enable split horizon. */
+DEFUN (babel_split_horizon,
+       babel_split_horizon_cmd,
+       "babel split-horizon",
+       IPV6_STR
+       "Routing Information Protocol\n"
+       "Perform split horizon\n")
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+
+    ifp = vty->index;
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    assert (babel_ifp != NULL);
+    babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON;
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command] Disable split horizon (default). */
+DEFUN (no_babel_split_horizon,
+       no_babel_split_horizon_cmd,
+       "no babel split-horizon",
+       NO_STR
+       IPV6_STR
+       "Routing Information Protocol\n"
+       "Perform split horizon\n")
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+
+    ifp = vty->index;
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    assert (babel_ifp != NULL);
+    babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON;
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command]. */
+DEFUN (babel_set_hello_interval,
+       babel_set_hello_interval_cmd,
+       "hello interval <5-1000000>",
+       "Set interface's hello interval (default: 4000).\n"
+       "Value in miliseconds\n")
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+
+    int interval = atoi(argv[1]);
+
+    ifp = vty->index;
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    assert (babel_ifp != NULL);
+    babel_ifp->hello_interval = interval;
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command]. */
+DEFUN (babel_passive_interface,
+       babel_passive_interface_cmd,
+       "passive-interface",
+       "The daemon will only announce redistributed routes\n"
+       "Interface name\n")
+{
+    if (allow_duplicates) {
+        return CMD_WARNING;
+    }
+    parasitic = -1;
+    return CMD_SUCCESS;
+}
+
+/* [Interface Command]. */
+DEFUN (no_babel_passive_interface,
+       no_babel_passive_interface_cmd,
+       "no passive-interface",
+       NO_STR
+       "The daemon will announce all (filtred) routes\n"
+       "Interface name\n")
+{
+    parasitic = 0;
+    return CMD_SUCCESS;
+}
+
+
+int
+interface_idle(babel_interface_nfo *babel_ifp)
+{
+    return (idle_hello_interval > 0 &&
+            babel_ifp->activity_time < babel_now.tv_sec - idle_time);
+}
+
+/* This should be no more than half the hello interval, so that hellos
+   aren't sent late.  The result is in milliseconds. */
+unsigned
+jitter(babel_interface_nfo *babel_ifp, int urgent)
+{
+    unsigned interval = babel_ifp->hello_interval;
+    if(urgent)
+        interval = MIN(interval, 100);
+    else
+        interval = MIN(interval, 4000);
+    return roughly(interval) / 4;
+}
+
+unsigned
+update_jitter(babel_interface_nfo *babel_ifp, int urgent)
+{
+    unsigned interval = babel_ifp->hello_interval;
+    if(urgent)
+        interval = MIN(interval, 100);
+    else
+        interval = MIN(interval, 4000);
+    return roughly(interval);
+}
+
+/* calculate babeld's specific datas of an interface (change when the interface
+ change) */
+static int
+interface_recalculate(struct interface *ifp)
+{
+    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
+    unsigned char *tmp = NULL;
+    int mtu, rc;
+    struct ipv6_mreq mreq;
+
+    mtu = MIN(ifp->mtu, ifp->mtu6);
+
+    /* We need to be able to fit at least two messages into a packet,
+     so MTUs below 116 require lower layer fragmentation. */
+    /* In IPv6, the minimum MTU is 1280, and every host must be able
+     to reassemble up to 1500 bytes, but I'd rather not rely on this. */
+    if(mtu < 128) {
+        debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).",
+               mtu, ifp->name, ifp->ifindex);
+        mtu = 128;
+    }
+
+    /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */
+    babel_ifp->bufsize = mtu - sizeof(packet_header) - 60;
+    tmp = babel_ifp->sendbuf;
+    babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
+    if(babel_ifp->sendbuf == NULL) {
+        fprintf(stderr, "Couldn't reallocate sendbuf.\n");
+        free(tmp);
+        babel_ifp->bufsize = 0;
+        return -1;
+    }
+    tmp = NULL;
+
+    resize_receive_buffer(mtu);
+
+    if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */
+        babel_ifp->cost = 96;
+        babel_ifp->flags &= ~BABEL_IF_LQ;
+    } else {
+        babel_ifp->cost = 256;
+        babel_ifp->flags |= BABEL_IF_LQ;
+    }
+
+    babel_ifp->activity_time = babel_now.tv_sec;
+    /* Since the interface was marked as active above, the
+     idle_hello_interval cannot be the one being used here. */
+    babel_ifp->update_interval = babel_ifp->hello_interval * 4;
+
+    memset(&mreq, 0, sizeof(mreq));
+    memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
+    mreq.ipv6mr_interface = ifp->ifindex;
+
+    rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                    (char*)&mreq, sizeof(mreq));
+    if(rc < 0) {
+        zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
+                 ifp->name, safe_strerror(errno));
+        /* This is probably due to a missing link-local address,
+         so down this interface, and wait until the main loop
+         tries to up it again. */
+        interface_reset(ifp);
+        return -1;
+    }
+
+    set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval);
+    set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
+    send_hello(ifp);
+    send_request(ifp, NULL, 0);
+
+    update_interface_metric(ifp);
+
+    debugf(BABEL_DEBUG_COMMON,
+           "Upped network %s (%s, cost=%d%s).",
+           ifp->name,
+           (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
+           babel_ifp->cost,
+           babel_ifp->ipv4 ? ", IPv4" : "");
+
+    if(rc > 0)
+        send_update(ifp, 0, NULL, 0);
+
+    /* Check and set if interface is enable. */
+    if (babel_enable_if_lookup(ifp->name) >= 0) {
+        babel_ifp->flags |= BABEL_IF_IS_ENABLE;
+    } else {
+        babel_ifp->flags &= ~BABEL_IF_IS_ENABLE;
+    }
+
+    return 1;
+}
+
+/* Reset the interface as it was new: it's not removed from the interface list,
+ and may be considered as a upped interface. */
+static int
+interface_reset(struct interface *ifp)
+{
+    int rc;
+    struct ipv6_mreq mreq;
+    babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
+
+    flush_interface_routes(ifp, 0);
+    babel_ifp->buffered = 0;
+    babel_ifp->bufsize = 0;
+    free(babel_ifp->sendbuf);
+    babel_ifp->num_buffered_updates = 0;
+    babel_ifp->update_bufsize = 0;
+    if(babel_ifp->buffered_updates)
+        free(babel_ifp->buffered_updates);
+    babel_ifp->buffered_updates = NULL;
+    babel_ifp->sendbuf = NULL;
+
+    if(ifp->ifindex > 0) {
+        memset(&mreq, 0, sizeof(mreq));
+        memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16);
+        mreq.ipv6mr_interface = ifp->ifindex;
+        rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+                        (char*)&mreq, sizeof(mreq));
+        if(rc < 0)
+            zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
+                     ifp->name, safe_strerror(errno));
+    }
+
+    update_interface_metric(ifp);
+
+    debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).",
+           ifp->name,
+           (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless",
+           babel_ifp->cost,
+           babel_ifp->ipv4 ? ", IPv4" : "");
+
+    return 1;
+}
+
+/* Send retraction to all, and reset all interfaces statistics. */
+void
+babel_interface_close_all(void)
+{
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        if(!if_up(ifp))
+            continue;
+        send_wildcard_retraction(ifp);
+        /* Make sure that we expire quickly from our neighbours'
+         association caches. */
+        send_hello_noupdate(ifp, 10);
+        flushbuf(ifp);
+        usleep(roughly(1000));
+        gettime(&babel_now);
+    }
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        if(!if_up(ifp))
+            continue;
+        /* Make sure they got it. */
+        send_wildcard_retraction(ifp);
+        send_hello_noupdate(ifp, 1);
+        flushbuf(ifp);
+        usleep(roughly(10000));
+        gettime(&babel_now);
+        interface_reset(ifp);
+    }
+}
+
+/* return "true" if address is one of our ipv6 addresses */
+int
+is_interface_ll_address(struct interface *ifp, const unsigned char *address)
+{
+    struct connected *connected;
+    struct listnode *node;
+
+    if(!if_up(ifp))
+        return 0;
+
+    FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) {
+        if(connected->address->family == AF_INET6 &&
+           memcmp(&connected->address->u.prefix6, address, 16) == 0)
+            return 1;
+    }
+
+    return 0;
+}
+
+
+void
+babel_if_init ()
+{
+    /* initialize interface list */
+    if_init();
+    if_add_hook (IF_NEW_HOOK,    babel_if_new_hook);
+    if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook);
+
+    babel_enable_if = vector_init (1);
+
+    /* install interface node and commands */
+    install_element (CONFIG_NODE, &interface_cmd);
+    install_element (CONFIG_NODE, &no_interface_cmd);
+    install_node (&babel_interface_node, interface_config_write);
+    install_default(INTERFACE_NODE);
+    install_element(INTERFACE_NODE, &interface_cmd);
+    install_element(INTERFACE_NODE, &no_interface_cmd);
+
+    install_element(BABEL_NODE, &babel_network_cmd);
+    install_element(BABEL_NODE, &no_babel_network_cmd);
+    install_element(INTERFACE_NODE, &babel_split_horizon_cmd);
+    install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd);
+    install_element(INTERFACE_NODE, &babel_set_wired_cmd);
+    install_element(INTERFACE_NODE, &babel_set_wireless_cmd);
+    install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd);
+    install_element(INTERFACE_NODE, &babel_passive_interface_cmd);
+    install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd);
+}
+
+/* hooks: functions called respectively when struct interface is
+ created or deleted. */
+static int
+babel_if_new_hook (struct interface *ifp)
+{
+    ifp->info = babel_interface_allocate();
+    return 0;
+}
+
+static int
+babel_if_delete_hook (struct interface *ifp)
+{
+    babel_interface_free(ifp->info);
+    ifp->info = NULL;
+    return 0;
+}
+
+/* Configuration write function for babeld. */
+static int
+interface_config_write (struct vty *vty)
+{
+    struct listnode *node;
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+    int write = 0;
+
+    for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) {
+        babel_ifp = babel_get_if_nfo(ifp);
+
+        /* Do not display the interface if there is no configuration about it */
+        if (ifp->desc == NULL)
+            continue;
+
+        vty_out (vty, "interface %s%s", ifp->name,
+                 VTY_NEWLINE);
+        if (ifp->desc)
+            vty_out (vty, " description %s%s", ifp->desc,
+                     VTY_NEWLINE);
+
+        /* TODO: to be completed... */
+
+        vty_out (vty, "!%s", VTY_NEWLINE);
+
+        write++;
+    }
+    return write;
+}
+
+/* functions to allocate or free memory for a babel_interface_nfo, filling
+ needed fields */
+static babel_interface_nfo *
+babel_interface_allocate ()
+{
+    babel_interface_nfo *babel_ifp;
+    babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo));
+    if(babel_ifp == NULL)
+        return NULL;
+
+    /* Here are set the default values for an interface. */
+    memset(babel_ifp, 0, sizeof(babel_interface_nfo));
+    /* All flags are unset */
+    babel_ifp->activity_time = babel_now.tv_sec;
+    babel_ifp->bucket_time = babel_now.tv_sec;
+    babel_ifp->bucket = BUCKET_TOKENS_MAX;
+    babel_ifp->hello_seqno = (random() & 0xFFFF);
+    babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL;
+
+    return babel_ifp;
+}
+
+static void
+babel_interface_free (babel_interface_nfo *babel_ifp)
+{
+    XFREE(MTYPE_BABEL_IF, babel_ifp);
+}

+ 141 - 0
babeld/babel_interface.h

@@ -0,0 +1,141 @@
+/*  
+ *  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 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.
+*/
+
+#ifndef BABEL_INTERFACE_H
+#define BABEL_INTERFACE_H
+
+#include <zebra.h>
+#include "zclient.h"
+
+/* babeld interface informations */
+struct babel_interface {
+    unsigned short flags;                     /* see below */
+    unsigned short cost;
+    struct timeval hello_timeout;
+    struct timeval update_timeout;
+    struct timeval flush_timeout;
+    struct timeval update_flush_timeout;
+    unsigned char *ipv4;
+    int buffered;
+    int bufsize;
+    char have_buffered_hello;
+    char have_buffered_id;
+    char have_buffered_nh;
+    char have_buffered_prefix;
+    unsigned char buffered_id[16];
+    unsigned char buffered_nh[4];
+    unsigned char buffered_prefix[16];
+    unsigned char *sendbuf;
+    struct buffered_update *buffered_updates;
+    int num_buffered_updates;
+    int update_bufsize;
+    time_t bucket_time;
+    unsigned int bucket;
+    time_t activity_time;
+    unsigned short hello_seqno;
+    unsigned hello_interval;
+    unsigned update_interval;
+
+    /* For filter type slot. */
+#define BABEL_FILTER_IN  0
+#define BABEL_FILTER_OUT 1
+#define BABEL_FILTER_MAX 2
+    struct access_list *list[BABEL_FILTER_MAX];               /* Access-list. */
+    struct prefix_list *prefix[BABEL_FILTER_MAX];             /* Prefix-list. */
+};
+
+typedef struct babel_interface babel_interface_nfo;
+static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp)
+{
+    return ((babel_interface_nfo*) ifp->info);
+}
+
+/* babel_interface_nfo flags */
+#define BABEL_IF_WIRED         (1 << 1)
+#define BABEL_IF_SPLIT_HORIZON (1 << 2)
+#define BABEL_IF_LQ            (1 << 3)
+#define BABEL_IF_IS_ENABLE     (1 << 4)
+
+static inline int
+if_up(struct interface *ifp)
+{
+    return (if_is_up(ifp) &&
+            ifp->connected != NULL &&
+            (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_ENABLE));
+}
+
+/* types:
+ struct interface _ifp, struct listnode node */
+#define FOR_ALL_INTERFACES(_ifp, _node)                                              \
+    for(ALL_LIST_ELEMENTS_RO(iflist, _node, _ifp))
+
+/* types:
+ struct interface *ifp, struct connected *_connected, struct listnode *node */
+#define FOR_ALL_INTERFACES_ADDRESSES(ifp, _connected, _node)                   \
+    for(ALL_LIST_ELEMENTS_RO(ifp->connected, _node, _connected))
+
+struct buffered_update {
+    unsigned char id[8];
+    unsigned char prefix[16];
+    unsigned char plen;
+    unsigned char pad[3];
+};
+
+
+/* init function */
+void babel_if_init(void);
+
+/* Callback functions for zebra client */
+int babel_interface_up (int, struct zclient *, zebra_size_t);
+int babel_interface_down (int, struct zclient *, zebra_size_t);
+int babel_interface_add (int, struct zclient *, zebra_size_t);
+int babel_interface_delete (int, struct zclient *, zebra_size_t);
+int babel_interface_address_add (int, struct zclient *, zebra_size_t);
+int babel_interface_address_delete (int, struct zclient *, zebra_size_t);
+
+/* others functions */
+int interface_idle(babel_interface_nfo *);
+unsigned jitter(babel_interface_nfo *, int);
+unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent);
+/* return "true" if "address" is one of our ipv6 addresses */
+int is_interface_ll_address(struct interface *ifp, const unsigned char *address);
+/* Send retraction to all, and reset all interfaces statistics. */
+void babel_interface_close_all(void);
+
+
+#endif

+ 522 - 0
babeld/babel_main.c

@@ -0,0 +1,522 @@
+/*  
+ *  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 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 zebra library */
+#include <zebra.h>
+#include "getopt.h"
+#include "if.h"
+#include "log.h"
+#include "thread.h"
+#include "privs.h"
+#include "sigevent.h"
+#include "version.h"
+#include "command.h"
+#include "vty.h"
+#include "memory.h"
+
+#include "babel_main.h"
+#include "babeld.h"
+#include "util.h"
+#include "kernel.h"
+#include "babel_interface.h"
+#include "neighbour.h"
+#include "route.h"
+#include "xroute.h"
+#include "message.h"
+#include "resend.h"
+#include "babel_zebra.h"
+
+
+static void babel_init (int argc, char **argv);
+static void babel_usage (char *progname);
+static char *babel_get_progname(char *argv_0);
+static void babel_fail(void);
+static void babel_init_random(void);
+static void babel_replace_by_null(int fd);
+static void babel_load_state_file(void);
+static void babel_init_signals(void);
+static void babel_exit_properly(void);
+static void babel_save_state_file(void);
+
+
+struct thread_master *master;     /* quagga's threads handler */
+struct timeval babel_now;         /* current time             */
+
+unsigned char myid[8];            /* unique id (mac address of an interface) */
+int debug = BABEL_DEBUG_COMMON;
+
+time_t reboot_time;
+int idle_time = 320;
+int link_detect = 0;
+int wireless_hello_interval = -1;
+int wired_hello_interval = -1;
+int idle_hello_interval = -1;
+char *pidfile = "/var/run/babeld.pid";
+
+const unsigned char zeroes[16] = {0};
+const unsigned char ones[16] =
+    {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+static char *state_file = "/var/lib/babeld/babel-state";
+
+unsigned char protocol_group[16]; /* babel's link-local multicast address */
+int protocol_port;                /* babel's port */
+int protocol_socket = -1;         /* socket: communicate with others babeld */
+
+static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG;
+static char *babel_config_file = NULL;
+static char *babel_vty_addr = NULL;
+static int babel_vty_port = BABEL_VTY_PORT;
+
+/* Babeld options. */
+struct option longopts[] =
+{
+    { "daemon",      no_argument,       NULL, 'd'},
+    { "config_file", required_argument, NULL, 'f'},
+    { "pid_file",    required_argument, NULL, 'i'},
+    { "help",        no_argument,       NULL, 'h'},
+    { "vty_addr",    required_argument, NULL, 'A'},
+    { "vty_port",    required_argument, NULL, 'P'},
+    { "user",        required_argument, NULL, 'u'},
+    { "group",       required_argument, NULL, 'g'},
+    { "version",     no_argument,       NULL, 'v'},
+    { 0 }
+};
+
+/* babeld privileges */
+static zebra_capabilities_t _caps_p [] =
+{
+    ZCAP_NET_RAW,
+    ZCAP_BIND
+};
+static struct zebra_privs_t babeld_privs =
+{
+#if defined(QUAGGA_USER)
+    .user = QUAGGA_USER,
+#endif
+#if defined QUAGGA_GROUP
+    .group = QUAGGA_GROUP,
+#endif
+#ifdef VTY_GROUP
+    .vty_group = VTY_GROUP,
+#endif
+    .caps_p = _caps_p,
+    .cap_num_p = 2,
+    .cap_num_i = 0
+};
+
+
+int
+main(int argc, char **argv)
+{
+    struct thread thread;
+    /* and print banner too */
+    babel_init(argc, argv);
+    while (thread_fetch (master, &thread)) {
+        thread_call (&thread);
+    }
+    return 0;
+}
+
+/* make initialisations witch don't need infos about kernel(interfaces, etc.) */
+static void
+babel_init(int argc, char **argv)
+{
+    int rc, opt;
+    int do_daemonise = 0;
+    char *progname = NULL;
+    char *pidfile = PATH_BABELD_PID;
+
+    /* Set umask before anything for security */
+    umask (0027);
+    progname = babel_get_progname(argv[0]);
+
+    /* set default log (lib/log.h) */
+    zlog_default = openzlog(progname, ZLOG_BABEL,
+                            LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
+    /* set log destination as stdout until the config file is read */
+    zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING);
+
+    babel_init_random();
+
+    /* set the Babel's default link-local multicast address and Babel's port */
+    parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL);
+    protocol_port = 6696;
+
+    /* get options */
+    while(1) {
+        opt = getopt_long(argc, argv, "df:i:hA:P:u:g:v", longopts, 0);
+        if(opt < 0)
+            break;
+
+        switch(opt) {
+            case 0:
+                break;
+            case 'd':
+                do_daemonise = -1;
+                break;
+            case 'f':
+                babel_config_file = optarg;
+                break;
+            case 'i':
+                pidfile = optarg;
+                break;
+            case 'A':
+                babel_vty_addr = optarg;
+                break;
+            case 'P':
+                babel_vty_port = atoi (optarg);
+                if (babel_vty_port < 0 || babel_vty_port > 0xffff
+                    || (babel_vty_port == 0 && optarg[0] != '0'/*atoi error*/))
+                    babel_vty_port = BABEL_VTY_PORT;
+                break;
+            case 'u':
+                babeld_privs.user = optarg;
+                break;
+            case 'g':
+                babeld_privs.group = optarg;
+                break;
+            case 'v':
+                print_version (progname);
+                exit (0);
+                break;
+            case 'h':
+                babel_usage (progname);
+                break;
+            default:
+                babel_usage(progname);
+                break;
+        }
+    }
+
+    /* create the threads handler */
+    master = thread_master_create ();
+
+    /* Library inits. */
+    zprivs_init (&babeld_privs);
+    babel_init_signals();
+    cmd_init (1);
+    vty_init (master);
+    memory_init ();
+
+    /* babeld inits (default options) */
+    /* set default interval's values */
+    if(wireless_hello_interval <= 0)
+        wireless_hello_interval = 4000;
+    wireless_hello_interval = MAX(wireless_hello_interval, 5);
+
+    if(wired_hello_interval <= 0)
+        wired_hello_interval = 4000;
+    wired_hello_interval = MAX(wired_hello_interval, 5);
+
+    /* an assertion */
+    if(parasitic && allow_duplicates >= 0) {
+        /* Too difficult to get right. */
+        zlog_err("Sorry, -P and -A are incompatible.");
+        exit(1);
+    }
+
+    babel_replace_by_null(STDIN_FILENO);
+
+    if (do_daemonise && daemonise() < 0) {
+        zlog_err("daemonise: %s", safe_strerror(errno));
+        exit (1);
+    }
+
+    /* write pid file */
+    if (pid_output(pidfile) < 0) {
+        zlog_err("error while writing pidfile");
+        exit (1);
+    };
+
+    /* init some quagga's dependencies, and babeld's commands */
+    babeld_quagga_init();
+    /* init zebra client's structure and it's commands */
+    /* this replace kernel_setup && kernel_setup_socket */
+    babelz_zebra_init ();
+
+    /* Sort all installed commands. */
+    sort_node ();
+
+    /* Get zebra configuration file. */
+    zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
+    vty_read_config (babel_config_file, babel_config_default);
+
+    myseqno = (random() & 0xFFFF);
+    babel_load_state_file();
+
+    /* Create VTY socket */
+    vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH);
+
+    /* init buffer */
+    rc = resize_receive_buffer(1500);
+    if(rc < 0)
+        babel_fail();
+
+    schedule_neighbours_check(5000, 1);
+
+    zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port);
+}
+
+/* return the progname (without path, example: "./x/progname" --> "progname") */
+static char *
+babel_get_progname(char *argv_0) {
+    char *p = strrchr (argv_0, '/');
+    return (p ? ++p : argv_0);
+}
+
+static void
+babel_usage(char *progname)
+{
+    fprintf(stderr,
+            "Syntax: %s "
+            "[-m multicast_address] [-p port] [-S state-file]\n"
+            "                "
+            "[-h hello] [-H wired_hello] [-i idle_hello]\n"
+            "                "
+            "[-k metric] [-A metric] [-s] [-P] [-l] [-w] [-d level] [-g port]\n"
+            "                "
+            "[-t table] [-T table] [-c file] [-C statement]\n"
+            "                "
+            "[-D] [-L logfile] [-I pidfile]\n"
+            "                "
+            "[id] interface...\n",
+            progname);
+    exit(1);
+}
+
+static void
+babel_fail(void)
+{
+    exit(1);
+}
+
+/* initialize random value, and set 'babel_now' by the way. */
+static void
+babel_init_random(void)
+{
+    gettime(&babel_now);
+    int rc;
+    unsigned int seed;
+
+    rc = read_random_bytes(&seed, sizeof(seed));
+    if(rc < 0) {
+        zlog_err("read(random): %s", safe_strerror(errno));
+        seed = 42;
+    }
+
+    seed ^= (babel_now.tv_sec ^ babel_now.tv_usec);
+    srandom(seed);
+}
+
+/*
+ close fd, and replace it by "/dev/null"
+ exit if error
+ */
+static void
+babel_replace_by_null(int fd)
+{
+    int fd_null;
+    int rc;
+
+    fd_null = open("/dev/null", O_RDONLY);
+    if(fd_null < 0) {
+        zlog_err("open(null): %s", safe_strerror(errno));
+        exit(1);
+    }
+
+    rc = dup2(fd_null, fd);
+    if(rc < 0) {
+        zlog_err("dup2(null, 0): %s", safe_strerror(errno));
+        exit(1);
+    }
+
+    close(fd_null);
+}
+
+/*
+ Load the state file: check last babeld's running state, usefull in case of
+ "/etc/init.d/babeld restart"
+ */
+static void
+babel_load_state_file(void)
+{
+    reboot_time = babel_now.tv_sec;
+    int fd;
+    int rc;
+
+    fd = open(state_file, O_RDONLY);
+    if(fd < 0 && errno != ENOENT)
+        zlog_err("open(babel-state: %s)", safe_strerror(errno));
+    rc = unlink(state_file);
+    if(fd >= 0 && rc < 0) {
+        zlog_err("unlink(babel-state): %s", safe_strerror(errno));
+        /* If we couldn't unlink it, it's probably stale. */
+        close(fd);
+        fd = -1;
+    }
+    if(fd >= 0) {
+        char buf[100];
+        char buf2[100];
+        int s;
+        long t;
+        rc = read(fd, buf, 99);
+        if(rc < 0) {
+            zlog_err("read(babel-state): %s", safe_strerror(errno));
+        } else {
+            buf[rc] = '\0';
+            rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
+            if(rc == 3 && s >= 0 && s <= 0xFFFF) {
+                unsigned char sid[8];
+                rc = parse_eui64(buf2, sid);
+                if(rc < 0) {
+                    zlog_err("Couldn't parse babel-state.");
+                } else {
+                    struct timeval realnow;
+                    debugf(BABEL_DEBUG_COMMON,
+                           "Got %s %d %ld from babel-state.",
+                           format_eui64(sid), s, t);
+                    gettimeofday(&realnow, NULL);
+                    if(memcmp(sid, myid, 8) == 0)
+                        myseqno = seqno_plus(s, 1);
+                    else
+                        zlog_err("ID mismatch in babel-state.");
+                    /* Convert realtime into monotonic time. */
+                    if(t >= 1176800000L && t <= realnow.tv_sec)
+                        reboot_time = babel_now.tv_sec - (realnow.tv_sec - t);
+                }
+            } else {
+                zlog_err("Couldn't parse babel-state.");
+            }
+        }
+        close(fd);
+        fd = -1;
+    }
+}
+
+static void
+babel_sigexit(void)
+{
+    zlog_notice("Terminating on signal");
+
+    babel_exit_properly();
+}
+
+static void
+babel_sigusr1 (void)
+{
+    zlog_rotate (NULL);
+}
+
+static void
+babel_init_signals(void)
+{
+    static struct quagga_signal_t babel_signals[] =
+    {
+        {
+            .signal = SIGUSR1,
+            .handler = &babel_sigusr1,
+        },
+        {
+            .signal = SIGINT,
+            .handler = &babel_sigexit,
+        },
+        {
+            .signal = SIGTERM,
+            .handler = &babel_sigexit,
+        },
+    };
+
+    signal_init (master, Q_SIGC(babel_signals), babel_signals);
+}
+
+static void
+babel_exit_properly(void)
+{
+    debugf(BABEL_DEBUG_COMMON, "Exiting...");
+    usleep(roughly(10000));
+    gettime(&babel_now);
+
+    /* Uninstall and flush all routes. */
+    debugf(BABEL_DEBUG_COMMON, "Uninstall routes.");
+    babel_uninstall_all_routes();
+    babel_interface_close_all();
+    babel_zebra_close_connexion();
+    babel_save_state_file();
+    debugf(BABEL_DEBUG_COMMON, "Remove pid file.");
+    if(pidfile)
+        unlink(pidfile);
+    debugf(BABEL_DEBUG_COMMON, "Done.");
+
+    exit(0);
+}
+
+static void
+babel_save_state_file(void)
+{
+    int fd;
+    int rc;
+
+    debugf(BABEL_DEBUG_COMMON, "Save state file.");
+    fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
+    if(fd < 0) {
+        zlog_err("creat(babel-state): %s", safe_strerror(errno));
+        unlink(state_file);
+    } else {
+        struct timeval realnow;
+        char buf[100];
+        gettimeofday(&realnow, NULL);
+        rc = snprintf(buf, 100, "%s %d %ld\n",
+                      format_eui64(myid), (int)myseqno,
+                      (long)realnow.tv_sec);
+        if(rc < 0 || rc >= 100) {
+            zlog_err("write(babel-state): overflow.");
+            unlink(state_file);
+        } else {
+            rc = write(fd, buf, rc);
+            if(rc < 0) {
+                zlog_err("write(babel-state): %s", safe_strerror(errno));
+                unlink(state_file);
+            }
+            fsync(fd);
+        }
+        close(fd);
+    }
+}

+ 54 - 0
babeld/babel_main.h

@@ -0,0 +1,54 @@
+/*  
+ *  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 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.
+*/
+
+extern struct timeval babel_now;         /* current time             */
+extern struct thread_master *master;     /* quagga's threads handler */
+extern int debug;
+extern int wireless_hello_interval, wired_hello_interval, idle_hello_interval;
+extern int idle_time;
+extern int link_detect;
+
+extern unsigned char myid[8];
+
+extern const unsigned char zeroes[16], ones[16];
+
+extern int protocol_port;
+extern unsigned char protocol_group[16];
+extern int protocol_socket;
+extern int kernel_socket;
+extern int max_request_hopcount;

+ 299 - 0
babeld/babel_zebra.c

@@ -0,0 +1,299 @@
+/*  
+ *  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 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.
+*/
+
+/* quagga's includes */
+#include <zebra.h>
+#include "command.h"
+#include "zclient.h"
+#include "stream.h"
+
+/* babel's includes*/
+#include "babel_zebra.h"
+#include "babel_interface.h"
+#include "xroute.h"
+
+void babelz_zebra_init(void);
+
+
+/* we must use a pointer because of zclient.c's functions (new, free). */
+struct zclient *zclient;
+static int zebra_config_write (struct vty *vty);
+/* Redistribution types */
+static struct {
+    int type;
+    int str_min_len;
+    const char *str;
+} redist_type[] = {
+    {ZEBRA_ROUTE_KERNEL,  1, "kernel"},
+    {ZEBRA_ROUTE_CONNECT, 1, "connected"},
+    {ZEBRA_ROUTE_STATIC,  1, "static"},
+    {ZEBRA_ROUTE_OSPF6,   1, "ospf6"},
+    {ZEBRA_ROUTE_BGP,     1, "bgp"},
+    {0, 0, NULL}
+};
+
+/* Zebra node structure. */
+struct cmd_node zebra_node =
+{
+    ZEBRA_NODE,
+    "%s(config-router)# ",
+    1 /* vtysh? yes */
+};
+
+
+/* Zebra route add and delete treatment (ipv6). */
+static int
+babel_zebra_read_ipv6 (int command, struct zclient *zclient,
+		       zebra_size_t length)
+{
+    struct stream *s;
+    struct zapi_ipv6 api;
+    unsigned long ifindex = -1;
+    struct in6_addr nexthop;
+    struct prefix_ipv6 prefix;
+
+    s = zclient->ibuf;
+    ifindex = 0;
+    memset (&nexthop, 0, sizeof (struct in6_addr));
+    memset (&api, 0, sizeof(struct zapi_ipv6));
+    memset (&prefix, 0, sizeof (struct prefix_ipv6));
+
+    /* Type, flags, message. */
+    api.type = stream_getc (s);
+    api.flags = stream_getc (s);
+    api.message = stream_getc (s);
+
+    /* IPv6 prefix. */
+    prefix.family = AF_INET6;
+    prefix.prefixlen = stream_getc (s);
+    stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
+
+    /* Nexthop, ifindex, distance, metric. */
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
+        api.nexthop_num = stream_getc (s);
+        stream_get (&nexthop, s, sizeof(nexthop));
+    }
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
+        api.ifindex_num = stream_getc (s);
+        ifindex = stream_getl (s);
+    }
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+        api.distance = stream_getc (s);
+    else
+        api.distance = 0;
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+        api.metric = stream_getl (s);
+    else
+        api.metric = 0;
+
+    if (command == ZEBRA_IPV6_ROUTE_ADD)
+        babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop);
+    else
+        babel_ipv6_route_delete(&api, &prefix, ifindex);
+
+    return 0;
+}
+
+static int
+babel_zebra_read_ipv4 (int command, struct zclient *zclient,
+		       zebra_size_t length)
+{
+    struct stream *s;
+    struct zapi_ipv4 api;
+    unsigned long ifindex = -1;
+    struct in_addr nexthop;
+    struct prefix_ipv4 prefix;
+
+    s = zclient->ibuf;
+    ifindex = 0;
+    memset (&nexthop, 0, sizeof (struct in_addr));
+    memset (&api, 0, sizeof(struct zapi_ipv4));
+    memset (&prefix, 0, sizeof (struct prefix_ipv4));
+
+    /* Type, flags, message. */
+    api.type = stream_getc (s);
+    api.flags = stream_getc (s);
+    api.message = stream_getc (s);
+
+    /* IPv6 prefix. */
+    prefix.family = AF_INET;
+    prefix.prefixlen = stream_getc (s);
+    stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen));
+
+    /* Nexthop, ifindex, distance, metric. */
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) {
+        api.nexthop_num = stream_getc (s);
+        stream_get (&nexthop, s, sizeof(nexthop));
+    }
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) {
+        api.ifindex_num = stream_getc (s);
+        ifindex = stream_getl (s);
+    }
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
+        api.distance = stream_getc (s);
+    else
+        api.distance = 0;
+    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
+        api.metric = stream_getl (s);
+    else
+        api.metric = 0;
+
+    if (command == ZEBRA_IPV6_ROUTE_ADD) {
+        babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop);
+    } else {
+        babel_ipv4_route_delete(&api, &prefix, ifindex);
+    }
+
+    return 0;
+}
+
+static int
+babel_redistribute_unset (int type)
+{
+    if (! zclient->redist[type])
+        return CMD_SUCCESS;
+
+    zclient->redist[type] = 0;
+
+    if (zclient->sock > 0)
+        zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
+
+    /* perhaps should we remove xroutes having the same type... */
+
+    return CMD_SUCCESS;
+}
+
+
+/* [Babel Command] */
+DEFUN (babel_redistribute_type,
+       babel_redistribute_type_cmd,
+       "redistribute (kernel|connected|static|ospf6|bgp)",
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPFv3)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+    int i;
+
+    for(i = 0; redist_type[i].str != NULL; i++) {
+        if (strncmp (redist_type[i].str, argv[0],
+                     redist_type[i].str_min_len) == 0) {
+            zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient,
+                                  redist_type[i].type);
+            return CMD_SUCCESS;
+        }
+    }
+
+    vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
+
+    return CMD_WARNING;
+}
+
+/* [Babel Command] */
+DEFUN (no_babel_redistribute_type,
+       no_babel_redistribute_type_cmd,
+       "no redistribute (kernel|connected|static|ospf6|bgp)",
+       NO_STR
+       "Redistribute information from another routing protocol\n"
+       "Kernel routes\n"
+       "Connected\n"
+       "Static routes\n"
+       "Open Shortest Path First (OSPFv3)\n"
+       "Border Gateway Protocol (BGP)\n")
+{
+    int i;
+
+    for (i = 0; redist_type[i].str; i++) {
+        if (strncmp(redist_type[i].str, argv[0],
+                    redist_type[i].str_min_len) == 0) {
+            return babel_redistribute_unset (redist_type[i].type);
+        }
+    }
+
+    vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
+
+    return CMD_WARNING;
+}
+
+
+void babelz_zebra_init(void)
+{
+    zclient = zclient_new();
+    zclient_init(zclient, ZEBRA_ROUTE_BABEL);
+
+    zclient->interface_add = babel_interface_add;
+    zclient->interface_delete = babel_interface_delete;
+    zclient->interface_up = babel_interface_up;
+    zclient->interface_down = babel_interface_down;
+    zclient->interface_address_add = babel_interface_address_add;
+    zclient->interface_address_delete = babel_interface_address_delete;
+    zclient->ipv4_route_add = babel_zebra_read_ipv4;
+    zclient->ipv4_route_delete = babel_zebra_read_ipv4;
+    zclient->ipv6_route_add = babel_zebra_read_ipv6;
+    zclient->ipv6_route_delete = babel_zebra_read_ipv6;
+
+    install_node (&zebra_node, zebra_config_write);
+    install_element(BABEL_NODE, &babel_redistribute_type_cmd);
+    install_element(BABEL_NODE, &no_babel_redistribute_type_cmd);
+}
+
+static int
+zebra_config_write (struct vty *vty)
+{
+    fprintf(stderr, "\tzebra_config_write\n");
+    if (! zclient->enable)
+    {
+        vty_out (vty, "no router zebra%s", VTY_NEWLINE);
+        return 1;
+    }
+    else if (! zclient->redist[ZEBRA_ROUTE_BABEL])
+    {
+        vty_out (vty, "router zebra%s", VTY_NEWLINE);
+        vty_out (vty, " no redistribute babel%s", VTY_NEWLINE);
+        return 1;
+    }
+    return 0;
+}
+
+void
+babel_zebra_close_connexion(void)
+{
+    zclient_stop(zclient);
+}

+ 43 - 0
babeld/babel_zebra.h

@@ -0,0 +1,43 @@
+/*  
+ *  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 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.
+*/
+
+
+extern struct zclient *zclient;
+
+void babelz_zebra_init(void);
+void babel_zebra_close_connexion(void);

+ 766 - 0
babeld/babeld.c

@@ -0,0 +1,766 @@
+/*  
+ *  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 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 <zebra.h>
+#include "command.h"
+#include "prefix.h"
+#include "memory.h"
+#include "memtypes.h"
+#include "table.h"
+#include "distribute.h"
+#include "prefix.h"
+#include "filter.h"
+#include "plist.h"
+
+#include "babel_main.h"
+#include "babeld.h"
+#include "util.h"
+#include "net.h"
+#include "kernel.h"
+#include "babel_interface.h"
+#include "neighbour.h"
+#include "route.h"
+#include "message.h"
+#include "resend.h"
+#include "babel_filter.h"
+
+
+static int babel_init_routing_process(struct thread *thread);
+static void babel_get_myid(void);
+static void babel_initial_noise(void);
+static int babel_read_protocol (struct thread *thread);
+static int babel_main_loop(struct thread *thread);
+static void babel_set_timer(struct timeval *timeout);
+static void babel_fill_with_next_timeout(struct timeval *tv);
+
+
+/* Informations relative to the babel running daemon. */
+static struct babel *babel_routing_process = NULL;
+static unsigned char *receive_buffer = NULL;
+static int receive_buffer_size = 0;
+
+/* timeouts */
+struct timeval check_neighbours_timeout;
+static time_t expiry_time;
+static time_t source_expiry_time;
+
+/* Babel node structure. */
+static struct cmd_node cmd_babel_node =
+{
+    .node   = BABEL_NODE,
+    .prompt = "%s(config-router)# ",
+    .vtysh  = 1,
+};
+
+/* print current babel configuration on vty */
+static int
+babel_config_write (struct vty *vty)
+{
+    return 0;
+}
+
+
+static int
+babel_create_routing_process (void)
+{
+    assert (babel_routing_process == NULL);
+
+    /* Allocaste Babel instance. */
+    babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel));
+
+    /* Initialize timeouts */
+    gettime(&babel_now);
+    expiry_time = babel_now.tv_sec + roughly(30);
+    source_expiry_time = babel_now.tv_sec + roughly(300);
+
+    /* Make socket for Babel protocol. */
+    protocol_socket = babel_socket(protocol_port);
+    if (protocol_socket < 0) {
+        zlog_err("Couldn't create link local socket: %s", safe_strerror(errno));
+        goto fail;
+    }
+
+    /* Threads. */
+    babel_routing_process->t_read =
+    thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
+    /* wait a little: zebra will announce interfaces, addresses, routes... */
+    babel_routing_process->t_update =
+    thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L);
+    return 0;
+
+fail:
+    XFREE(MTYPE_BABEL, babel_routing_process);
+    babel_routing_process = NULL;
+    return -1;
+}
+
+/* thread reading entries form others babel daemons */
+static int
+babel_read_protocol (struct thread *thread)
+{
+    int rc;
+    struct interface *ifp = NULL;
+    struct sockaddr_in6 sin6;
+    struct listnode *linklist_node = NULL;
+
+    assert(babel_routing_process != NULL);
+    assert(protocol_socket >= 0);
+
+    rc = babel_recv(protocol_socket,
+                    receive_buffer, receive_buffer_size,
+                    (struct sockaddr*)&sin6, sizeof(sin6));
+    if(rc < 0) {
+        if(errno != EAGAIN && errno != EINTR) {
+            zlog_err("recv: %s", safe_strerror(errno));
+        }
+    } else {
+        FOR_ALL_INTERFACES(ifp, linklist_node) {
+            if(!if_up(ifp))
+                continue;
+            if(ifp->ifindex == sin6.sin6_scope_id) {
+                parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
+                             receive_buffer, rc);
+                break;
+            }
+        }
+    }
+
+    /* re-add thread */
+    babel_routing_process->t_read =
+    thread_add_read(master, &babel_read_protocol, NULL, protocol_socket);
+    return 0;
+}
+
+/* Zebra will give some information, especially about interfaces. This function
+ must be call with a litte timeout wich may give zebra the time to do his job,
+ making these inits have sense. */
+static int
+babel_init_routing_process(struct thread *thread)
+{
+    babel_get_myid();
+    debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid));
+    babel_initial_noise();
+    babel_main_loop(thread);/* this function self-add to the t_update thread */
+    return 0;
+}
+
+/* fill "myid" with an unique id (only if myid != {0}). */
+static void
+babel_get_myid(void)
+{
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+    int rc;
+    int i;
+
+    /* if we already have an id (from state file), we return. */
+    if (memcmp(myid, zeroes, 8) != 0) {
+        return;
+    }
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        /* ifp->ifindex is not necessarily valid at this point */
+        int ifindex = if_nametoindex(ifp->name);
+        if(ifindex > 0) {
+            unsigned char eui[8];
+            rc = if_eui64(ifp->name, ifindex, eui);
+            if(rc < 0)
+                continue;
+            memcpy(myid, eui, 8);
+            return;
+        }
+    }
+
+    /* We failed to get a global EUI64 from the interfaces we were given.
+     Let's try to find an interface with a MAC address. */
+    for(i = 1; i < 256; i++) {
+        char buf[IF_NAMESIZE], *ifname;
+        unsigned char eui[8];
+        ifname = if_indextoname(i, buf);
+        if(ifname == NULL)
+            continue;
+        rc = if_eui64(ifname, i, eui);
+        if(rc < 0)
+            continue;
+        memcpy(myid, eui, 8);
+        return;
+    }
+
+    zlog_err("Warning: couldn't find router id -- using random value.");
+
+    rc = read_random_bytes(myid, 8);
+    if(rc < 0) {
+        zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno));
+        exit(1);
+    }
+    /* Clear group and global bits */
+    myid[0] &= ~3;
+}
+
+/* Make some noise so that others notice us, and send retractions in
+ case we were restarted recently */
+static void
+babel_initial_noise(void)
+{
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        if(!if_up(ifp))
+            continue;
+        /* Apply jitter before we send the first message. */
+        usleep(roughly(10000));
+        gettime(&babel_now);
+        send_hello(ifp);
+        send_wildcard_retraction(ifp);
+    }
+
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        if(!if_up(ifp))
+            continue;
+        usleep(roughly(10000));
+        gettime(&babel_now);
+        send_hello(ifp);
+        send_wildcard_retraction(ifp);
+        send_self_update(ifp);
+        send_request(ifp, NULL, 0);
+        flushupdates(ifp);
+        flushbuf(ifp);
+    }
+}
+
+/* Delete all the added babel routes, make babeld only speak to zebra. */
+static void
+babel_clean_routing_process()
+{
+    babel_uninstall_all_routes();
+    babel_interface_close_all();
+
+    /* cancel threads */
+    if (babel_routing_process->t_read != NULL) {
+        thread_cancel(babel_routing_process->t_read);
+    }
+    if (babel_routing_process->t_update != NULL) {
+        thread_cancel(babel_routing_process->t_update);
+    }
+
+    XFREE(MTYPE_BABEL, babel_routing_process);
+    babel_routing_process = NULL;
+}
+
+/* Function used with timeout. */
+static int
+babel_main_loop(struct thread *thread)
+{
+    struct timeval tv;
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    while(1) {
+        gettime(&babel_now);
+
+        /* timeouts --------------------------------------------------------- */
+        /* get the next timeout */
+        babel_fill_with_next_timeout(&tv);
+        /* if there is no timeout, we must wait. */
+        if(timeval_compare(&tv, &babel_now) > 0) {
+            timeval_minus(&tv, &tv, &babel_now);
+            debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs",
+                   tv.tv_sec * 1000 + tv.tv_usec / 1000);
+            /* it happens often to have less than 1 ms, it's bad. */
+            timeval_add_msec(&tv, &tv, 300);
+            babel_set_timer(&tv);
+            return 0;
+        }
+
+        gettime(&babel_now);
+
+        /* update database -------------------------------------------------- */
+        if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) {
+            int msecs;
+            msecs = check_neighbours();
+            msecs = MAX(msecs, 10);
+            schedule_neighbours_check(msecs, 1);
+        }
+
+        if(babel_now.tv_sec >= expiry_time) {
+            expire_routes();
+            expire_resend();
+            expiry_time = babel_now.tv_sec + roughly(30);
+        }
+
+        if(babel_now.tv_sec >= source_expiry_time) {
+            expire_sources();
+            source_expiry_time = babel_now.tv_sec + roughly(300);
+        }
+
+        FOR_ALL_INTERFACES(ifp, linklist_node) {
+            babel_interface_nfo *babel_ifp = NULL;
+            if(!if_up(ifp))
+                continue;
+            babel_ifp = babel_get_if_nfo(ifp);
+            if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0)
+                send_hello(ifp);
+            if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0)
+                send_update(ifp, 0, NULL, 0);
+            if(timeval_compare(&babel_now,
+                               &babel_ifp->update_flush_timeout) >= 0)
+                flushupdates(ifp);
+        }
+
+        if(resend_time.tv_sec != 0) {
+            if(timeval_compare(&babel_now, &resend_time) >= 0)
+                do_resend();
+        }
+
+        if(unicast_flush_timeout.tv_sec != 0) {
+            if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0)
+                flush_unicast(1);
+        }
+
+        FOR_ALL_INTERFACES(ifp, linklist_node) {
+            babel_interface_nfo *babel_ifp = NULL;
+            if(!if_up(ifp))
+                continue;
+            babel_ifp = babel_get_if_nfo(ifp);
+            if(babel_ifp->flush_timeout.tv_sec != 0) {
+                if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0)
+                    flushbuf(ifp);
+            }
+        }
+    }
+
+    assert(0); /* this line should never be reach */
+}
+
+static void
+printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname)
+{
+    static struct timeval curr_tv;
+    static char buffer[200];
+    static const char *curr_tag = NULL;
+
+    switch (cmd) {
+        case 0: /* reset timeval */
+            curr_tv = *tv;
+            if(ifname != NULL) {
+                snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
+                curr_tag = buffer;
+            } else {
+                curr_tag = tag;
+            }
+            break;
+        case 1: /* take the min */
+            if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */
+                break;
+            }
+            if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec &&
+                                               tv->tv_usec < curr_tv.tv_usec)) {
+                curr_tv = *tv;
+                if(ifname != NULL) {
+                    snprintf(buffer, 200L, "interface: %s; %s", ifname, tag);
+                    curr_tag = buffer;
+                } else {
+                    curr_tag = tag;
+                }
+            }
+            break;
+        case 2: /* print message */
+            debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag);
+            break;
+        default:
+            break;
+    }
+}
+
+static void
+babel_fill_with_next_timeout(struct timeval *tv)
+{
+#if (defined NO_DEBUG)
+#define printIfMin(a,b,c,d)
+#else
+#define printIfMin(a,b,c,d) \
+  if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);}
+
+    struct interface *ifp = NULL;
+    struct listnode *linklist_node = NULL;
+
+    *tv = check_neighbours_timeout;
+    printIfMin(tv, 0, "check_neighbours_timeout", NULL);
+    timeval_min_sec(tv, expiry_time);
+    printIfMin(tv, 1, "expiry_time", NULL);
+    timeval_min_sec(tv, source_expiry_time);
+    printIfMin(tv, 1, "source_expiry_time", NULL);
+    timeval_min(tv, &resend_time);
+    printIfMin(tv, 1, "resend_time", NULL);
+    FOR_ALL_INTERFACES(ifp, linklist_node) {
+        babel_interface_nfo *babel_ifp = NULL;
+        if(!if_up(ifp))
+            continue;
+        babel_ifp = babel_get_if_nfo(ifp);
+        timeval_min(tv, &babel_ifp->flush_timeout);
+        printIfMin(tv, 1, "flush_timeout", ifp->name);
+        timeval_min(tv, &babel_ifp->hello_timeout);
+        printIfMin(tv, 1, "hello_timeout", ifp->name);
+        timeval_min(tv, &babel_ifp->update_timeout);
+        printIfMin(tv, 1, "update_timeout", ifp->name);
+        timeval_min(tv, &babel_ifp->update_flush_timeout);
+        printIfMin(tv, 1, "update_flush_timeout",ifp->name);
+    }
+    timeval_min(tv, &unicast_flush_timeout);
+    printIfMin(tv, 1, "unicast_flush_timeout", NULL);
+    printIfMin(tv, 2, NULL, NULL);
+#undef printIfMin
+#endif
+}
+
+/* set the t_update thread of the babel routing process to be launch in
+ 'timeout' (approximate at the milisecond) */
+static void
+babel_set_timer(struct timeval *timeout)
+{
+    long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+    if (babel_routing_process->t_update != NULL) {
+        thread_cancel(babel_routing_process->t_update);
+    }
+    babel_routing_process->t_update =
+    thread_add_timer_msec(master, &babel_main_loop, NULL, msecs);
+}
+
+/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */
+void
+schedule_neighbours_check(int msecs, int override)
+{
+    struct timeval timeout;
+
+    timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2));
+    if(override)
+        check_neighbours_timeout = timeout;
+    else
+        timeval_min(&check_neighbours_timeout, &timeout);
+}
+
+int
+resize_receive_buffer(int size)
+{
+    if(size <= receive_buffer_size)
+        return 0;
+
+    if(receive_buffer == NULL) {
+        receive_buffer = malloc(size);
+        if(receive_buffer == NULL) {
+            zlog_err("malloc(receive_buffer): %s", safe_strerror(errno));
+            return -1;
+        }
+        receive_buffer_size = size;
+    } else {
+        unsigned char *new;
+        new = realloc(receive_buffer, size);
+        if(new == NULL) {
+            zlog_err("realloc(receive_buffer): %s", safe_strerror(errno));
+            return -1;
+        }
+        receive_buffer = new;
+        receive_buffer_size = size;
+    }
+    return 1;
+}
+
+static void
+babel_distribute_update (struct distribute *dist)
+{
+    struct interface *ifp;
+    babel_interface_nfo *babel_ifp;
+    struct access_list *alist;
+    struct prefix_list *plist;
+
+    if (! dist->ifname)
+        return;
+
+    ifp = if_lookup_by_name (dist->ifname);
+    if (ifp == NULL)
+        return;
+
+    babel_ifp = babel_get_if_nfo(ifp);
+
+    if (dist->list[DISTRIBUTE_IN]) {
+        alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
+        if (alist)
+            babel_ifp->list[BABEL_FILTER_IN] = alist;
+        else
+            babel_ifp->list[BABEL_FILTER_IN] = NULL;
+    } else {
+        babel_ifp->list[BABEL_FILTER_IN] = NULL;
+    }
+
+    if (dist->list[DISTRIBUTE_OUT]) {
+        alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
+        if (alist)
+            babel_ifp->list[BABEL_FILTER_OUT] = alist;
+        else
+            babel_ifp->list[BABEL_FILTER_OUT] = NULL;
+    } else {
+        babel_ifp->list[BABEL_FILTER_OUT] = NULL;
+    }
+
+    if (dist->prefix[DISTRIBUTE_IN]) {
+        plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
+        if (plist)
+            babel_ifp->prefix[BABEL_FILTER_IN] = plist;
+        else
+            babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
+    } else {
+        babel_ifp->prefix[BABEL_FILTER_IN] = NULL;
+    }
+
+    if (dist->prefix[DISTRIBUTE_OUT]) {
+        plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
+        if (plist)
+            babel_ifp->prefix[BABEL_FILTER_OUT] = plist;
+        else
+            babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
+    } else {
+        babel_ifp->prefix[BABEL_FILTER_OUT] = NULL;
+    }
+}
+
+void
+babel_distribute_update_interface (struct interface *ifp)
+{
+    struct distribute *dist;
+
+    dist = distribute_lookup (ifp->name);
+    if (dist)
+        babel_distribute_update (dist);
+}
+
+/* Update all interface's distribute list. */
+static void
+babel_distribute_update_all (struct prefix_list *notused)
+{
+    struct interface *ifp;
+    struct listnode *node;
+
+    for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
+        babel_distribute_update_interface (ifp);
+}
+
+static void
+babel_distribute_update_all_wrapper (struct access_list *notused)
+{
+    babel_distribute_update_all(NULL);
+}
+
+
+/* [Command] */
+DEFUN (router_babel,
+       router_babel_cmd,
+       "router babel",
+       "Enable a routing process\n"
+       "Make Babel instance command\n")
+{
+    int ret;
+
+    vty->node = BABEL_NODE;
+
+    if (!babel_routing_process) {
+        ret = babel_create_routing_process ();
+
+        /* Notice to user we couldn't create Babel. */
+        if (ret < 0) {
+            zlog_warn ("can't create Babel");
+        }
+    }
+
+    return CMD_SUCCESS;
+}
+
+/* [Command] */
+DEFUN (no_router_babel,
+       no_router_babel_cmd,
+       "no router babel",
+       NO_STR
+       "Disable a routing process\n"
+       "Remove Babel instance command\n")
+{
+    if(babel_routing_process)
+        babel_clean_routing_process();
+    return CMD_SUCCESS;
+}
+
+/* [Babel Command] */
+DEFUN (babel_set_protocol_group,
+       babel_set_protocol_group_cmd,
+       "protocol group ADDR",
+       "Set the protocol group, default is ff02::1:6.\n"
+       "IPv6 address")
+{
+    int ret;
+    struct prefix p;
+
+    ret = str2prefix (argv[0], &p);
+
+    /* Given string is:                 */
+    if (ret) { /* an IPv4 or v6 network */
+        if (p.family != AF_INET6) {
+            return CMD_WARNING;
+        }
+        in6addr_to_uchar(protocol_group, &p.u.prefix6);
+    } else {   /* an interface name     */
+        return CMD_WARNING;
+    }
+
+    if (ret < 0) {
+        vty_out (vty, "%s must be an ipv6 address%s", argv[0],
+                 VTY_NEWLINE);
+        return CMD_WARNING;
+    }
+
+    return CMD_SUCCESS;
+}
+
+/* [Babel Command] */
+DEFUN (babel_set_protocol_port,
+       babel_set_protocol_port_cmd,
+       "protocol port <1-65535>",
+       "Set the protocol port (default is defined in RFC).\n"
+       "IPv6 address")
+{
+    int port = atoi(argv[0]);
+    protocol_port = port;
+
+    return CMD_SUCCESS;
+}
+
+
+void
+babeld_quagga_init(void)
+{
+
+    install_node(&cmd_babel_node, &babel_config_write);
+
+    install_element(CONFIG_NODE, &router_babel_cmd);
+    install_element(CONFIG_NODE, &no_router_babel_cmd);
+
+    install_default(BABEL_NODE);
+
+    babel_if_init();
+
+    /* Access list install. */
+    access_list_init ();
+    access_list_add_hook (babel_distribute_update_all_wrapper);
+    access_list_delete_hook (babel_distribute_update_all_wrapper);
+
+    /* Prefix list initialize.*/
+    prefix_list_init ();
+    prefix_list_add_hook (babel_distribute_update_all);
+    prefix_list_delete_hook (babel_distribute_update_all);
+
+    /* Distribute list install. */
+    distribute_list_init (BABEL_NODE);
+    distribute_list_add_hook (babel_distribute_update);
+    distribute_list_delete_hook (babel_distribute_update);
+}
+
+int /* DEPRECATED: for compatibility with old babeld (configuration.{c,h})*/
+input_filter(const unsigned char *id,
+             const unsigned char *prefix, unsigned short plen,
+             const unsigned char *neigh, unsigned int ifindex)
+{
+    struct interface *ifp = NULL;
+    struct prefix p;
+    p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
+    p.prefixlen = plen;
+    if (p.family == AF_INET) {
+        uchar_to_inaddr(&p.u.prefix4, prefix);
+    } else {
+        uchar_to_in6addr(&p.u.prefix6, prefix);
+    }
+
+    ifp = if_lookup_by_index(ifindex);
+    if (ifp != NULL) {
+        return babel_filter_in(&p, babel_get_if_nfo(ifp));
+    }
+
+    return babel_filter_in(&p, NULL);
+}
+
+int /* DEPRECATED: for compatibility with old babeld */
+output_filter(const unsigned char *id, const unsigned char *prefix,
+              unsigned short plen, unsigned int ifindex)
+{
+    struct interface *ifp = NULL;
+    struct prefix p;
+    p.family = v4mapped(prefix) ? AF_INET : AF_INET6;
+    p.prefixlen = plen;
+    if (p.family == AF_INET) {
+        uchar_to_inaddr(&p.u.prefix4, prefix);
+    } else {
+        uchar_to_in6addr(&p.u.prefix6, prefix);
+    }
+
+    ifp = if_lookup_by_index(ifindex);
+    if (ifp != NULL) {
+        return babel_filter_out(&p, babel_get_if_nfo(ifp));
+    }
+
+    return babel_filter_out(&p, NULL);
+}
+
+int /* DEPRECATED: for compatibility with old babeld */
+r