diff options
Diffstat (limited to 'zebra/router-id.c')
-rw-r--r-- | zebra/router-id.c | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/zebra/router-id.c b/zebra/router-id.c new file mode 100644 index 00000000..3052e56a --- /dev/null +++ b/zebra/router-id.c @@ -0,0 +1,265 @@ +/* + * Router ID for zebra daemon. + * + * Copyright (C) 2004 James R. Leu + * + * This file is part of Quagga routing suite. + * + * Quagga is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * Quagga 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 GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "if.h" +#include "vty.h" +#include "sockunion.h" +#include "prefix.h" +#include "stream.h" +#include "command.h" +#include "memory.h" +#include "ioctl.h" +#include "connected.h" +#include "network.h" +#include "log.h" +#include "table.h" +#include "rib.h" + +#include "zebra/zserv.h" + +static struct list rid_all_sorted_list; +static struct list rid_lo_sorted_list; +static struct prefix rid_user_assigned; + +/* master zebra server structure */ +extern struct zebra_t zebrad; + +static struct connected * +router_id_find_node (struct list *l, struct connected *ifc) +{ + struct listnode *node; + struct connected *c; + + for (node = l->head; node; node = node->next) + { + c = (struct connected *) getdata (node); + if (prefix_same (ifc->address, c->address)) + return c; + } + return NULL; +} + +static int +router_id_bad_address (struct connected *ifc) +{ + struct prefix n; + + if (ifc->address->family != AF_INET) + return 1; + + n.u.prefix4.s_addr = htonl (INADDR_LOOPBACK); + n.prefixlen = 8; + n.family = AF_INET; + + if (prefix_match (&n, ifc->address)) + return 1; + + return 0; +} + +void +router_id_get (struct prefix *p) +{ + struct listnode *node; + struct connected *c; + + p->u.prefix4.s_addr = 0; + p->family = AF_INET; + p->prefixlen = 32; + + if (rid_user_assigned.u.prefix4.s_addr) + p->u.prefix4.s_addr = rid_user_assigned.u.prefix4.s_addr; + else if (!list_isempty (&rid_lo_sorted_list)) + { + node = listtail (&rid_lo_sorted_list); + c = getdata (node); + p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; + } + else if (!list_isempty (&rid_all_sorted_list)) + { + node = listtail (&rid_all_sorted_list); + c = getdata (node); + p->u.prefix4.s_addr = c->address->u.prefix4.s_addr; + } +} + +static void +router_id_set (struct prefix *p) +{ + struct prefix p2; + struct listnode *node; + struct zserv *client; + + rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr; + + router_id_get (&p2); + for (node = listhead (zebrad.client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_router_id_update (client, &p2); +} + +void +router_id_add_address (struct connected *ifc) +{ + struct list *l = NULL; + struct listnode *node; + struct prefix before; + struct prefix after; + struct zserv *client; + + if (router_id_bad_address (ifc)) + return; + + router_id_get (&before); + + if (!strncmp (ifc->ifp->name, "lo", 2) + || !strncmp (ifc->ifp->name, "dummy", 5)) + l = &rid_lo_sorted_list; + else + l = &rid_all_sorted_list; + + if (!router_id_find_node (l, ifc)) + listnode_add (l, ifc); + + router_id_get (&after); + + if (prefix_same (&before, &after)) + return; + + for (node = listhead (zebrad.client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_router_id_update (client, &after); +} + +void +router_id_del_address (struct connected *ifc) +{ + struct connected *c; + struct list *l; + struct prefix after; + struct prefix before; + struct listnode *node; + struct zserv *client; + + if (router_id_bad_address (ifc)) + return; + + router_id_get (&before); + + if (!strncmp (ifc->ifp->name, "lo", 2) + || !strncmp (ifc->ifp->name, "dummy", 5)) + l = &rid_lo_sorted_list; + else + l = &rid_all_sorted_list; + + if ((c = router_id_find_node (l, ifc))) + listnode_delete (l, c); + + router_id_get (&after); + + if (prefix_same (&before, &after)) + return; + + for (node = listhead (zebrad.client_list); node; nextnode (node)) + if ((client = getdata (node)) != NULL) + zsend_router_id_update (client, &after); +} + +void +router_id_write (struct vty *vty) +{ + if (rid_user_assigned.u.prefix4.s_addr) + vty_out (vty, "router-id %s%s", inet_ntoa (rid_user_assigned.u.prefix4), + VTY_NEWLINE); +} + +DEFUN (router_id, + router_id_cmd, + "router-id A.B.C.D", + "Manually set the router-id\n" + "IP address to use for router-id\n") +{ + struct prefix rid; + + rid.u.prefix4.s_addr = inet_addr (argv[0]); + if (!rid.u.prefix4.s_addr) + return CMD_WARNING; + + rid.prefixlen = 32; + rid.family = AF_INET; + + router_id_set (&rid); + + return CMD_SUCCESS; +} + +DEFUN (no_router_id, + no_router_id_cmd, + "no router-id", + NO_STR + "Remove the manually configured router-id\n") +{ + struct prefix rid; + + rid.u.prefix4.s_addr = 0; + rid.prefixlen = 0; + rid.family = AF_INET; + + router_id_set (&rid); + + return CMD_SUCCESS; +} + +int +router_id_cmp (void *a, void *b) +{ + unsigned int A, B; + + A = ((struct connected *) a)->address->u.prefix4.s_addr; + B = ((struct connected *) b)->address->u.prefix4.s_addr; + + if (A > B) + return 1; + else if (A < B) + return -1; + return 0; +} + +void +router_id_init (void) +{ + install_element (CONFIG_NODE, &router_id_cmd); + install_element (CONFIG_NODE, &no_router_id_cmd); + + memset (&rid_all_sorted_list, 0, sizeof (rid_all_sorted_list)); + memset (&rid_lo_sorted_list, 0, sizeof (rid_lo_sorted_list)); + memset (&rid_user_assigned, 0, sizeof (rid_user_assigned)); + + rid_all_sorted_list.cmp = router_id_cmp; + rid_lo_sorted_list.cmp = router_id_cmp; + + rid_user_assigned.family = AF_INET; + rid_user_assigned.prefixlen = 32; +} |