blob: a4eb73ae5303a0390a398c3bd0078888f7281c1c [file] [log] [blame]
/*
* 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 "vrf.h"
#include "zebra/zserv.h"
#include "zebra/router-id.h"
#include "zebra/redistribute.h"
/* 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 (ALL_LIST_ELEMENTS_RO (l, node, c))
if (prefix_same (ifc->address, c->address))
return c;
return NULL;
}
static int
router_id_bad_address (struct connected *ifc)
{
if (ifc->address->family != AF_INET)
return 1;
/* non-redistributable addresses shouldn't be used for RIDs either */
if (!zebra_check_addr (ifc->address))
return 1;
return 0;
}
void
router_id_get (struct prefix *p, vrf_id_t vrf_id)
{
struct listnode *node;
struct connected *c;
struct zebra_vrf *zvrf = vrf_info_get (vrf_id);
p->u.prefix4.s_addr = 0;
p->family = AF_INET;
p->prefixlen = 32;
if (zvrf->rid_user_assigned.u.prefix4.s_addr)
p->u.prefix4.s_addr = zvrf->rid_user_assigned.u.prefix4.s_addr;
else if (!list_isempty (zvrf->rid_lo_sorted_list))
{
node = listtail (zvrf->rid_lo_sorted_list);
c = listgetdata (node);
p->u.prefix4.s_addr = c->address->u.prefix4.s_addr;
}
else if (!list_isempty (zvrf->rid_all_sorted_list))
{
node = listtail (zvrf->rid_all_sorted_list);
c = listgetdata (node);
p->u.prefix4.s_addr = c->address->u.prefix4.s_addr;
}
}
static void
router_id_set (struct prefix *p, vrf_id_t vrf_id)
{
struct prefix p2;
struct listnode *node;
struct zserv *client;
struct zebra_vrf *zvrf;
if (p->u.prefix4.s_addr == 0) /* unset */
{
zvrf = vrf_info_lookup (vrf_id);
if (! zvrf)
return;
}
else /* set */
zvrf = vrf_info_get (vrf_id);
zvrf->rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr;
router_id_get (&p2, vrf_id);
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
zsend_router_id_update (client, &p2, vrf_id);
}
void
router_id_add_address (struct connected *ifc)
{
struct list *l = NULL;
struct listnode *node;
struct prefix before;
struct prefix after;
struct zserv *client;
struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id);
if (router_id_bad_address (ifc))
return;
router_id_get (&before, zvrf->vrf_id);
if (!strncmp (ifc->ifp->name, "lo", 2)
|| !strncmp (ifc->ifp->name, "dummy", 5))
l = zvrf->rid_lo_sorted_list;
else
l = zvrf->rid_all_sorted_list;
if (!router_id_find_node (l, ifc))
listnode_add_sort (l, ifc);
router_id_get (&after, zvrf->vrf_id);
if (prefix_same (&before, &after))
return;
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
zsend_router_id_update (client, &after, zvrf->vrf_id);
}
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;
struct zebra_vrf *zvrf = vrf_info_get (ifc->ifp->vrf_id);
if (router_id_bad_address (ifc))
return;
router_id_get (&before, zvrf->vrf_id);
if (!strncmp (ifc->ifp->name, "lo", 2)
|| !strncmp (ifc->ifp->name, "dummy", 5))
l = zvrf->rid_lo_sorted_list;
else
l = zvrf->rid_all_sorted_list;
if ((c = router_id_find_node (l, ifc)))
listnode_delete (l, c);
router_id_get (&after, zvrf->vrf_id);
if (prefix_same (&before, &after))
return;
for (ALL_LIST_ELEMENTS_RO (zebrad.client_list, node, client))
zsend_router_id_update (client, &after, zvrf->vrf_id);
}
void
router_id_write (struct vty *vty)
{
struct zebra_vrf *zvrf;
vrf_iter_t iter;
for (iter = vrf_first (); iter != VRF_ITER_INVALID; iter = vrf_next (iter))
if ((zvrf = vrf_iter2info (iter)) != NULL)
if (zvrf->rid_user_assigned.u.prefix4.s_addr)
{
if (zvrf->vrf_id == VRF_DEFAULT)
vty_out (vty, "router-id %s%s",
inet_ntoa (zvrf->rid_user_assigned.u.prefix4),
VTY_NEWLINE);
else
vty_out (vty, "router-id %s vrf %u%s",
inet_ntoa (zvrf->rid_user_assigned.u.prefix4),
zvrf->vrf_id,
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;
vrf_id_t vrf_id = VRF_DEFAULT;
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;
if (argc > 1)
VTY_GET_INTEGER ("VRF ID", vrf_id, argv[1]);
router_id_set (&rid, vrf_id);
return CMD_SUCCESS;
}
ALIAS (router_id,
router_id_vrf_cmd,
"router-id A.B.C.D " VRF_CMD_STR,
"Manually set the router-id\n"
"IP address to use for router-id\n"
VRF_CMD_HELP_STR)
DEFUN (no_router_id,
no_router_id_cmd,
"no router-id",
NO_STR
"Remove the manually configured router-id\n")
{
struct prefix rid;
vrf_id_t vrf_id = VRF_DEFAULT;
rid.u.prefix4.s_addr = 0;
rid.prefixlen = 0;
rid.family = AF_INET;
if (argc > 0)
VTY_GET_INTEGER ("VRF ID", vrf_id, argv[0]);
router_id_set (&rid, vrf_id);
return CMD_SUCCESS;
}
ALIAS (no_router_id,
no_router_id_vrf_cmd,
"no router-id " VRF_CMD_STR,
NO_STR
"Remove the manually configured router-id\n"
VRF_CMD_HELP_STR)
static int
router_id_cmp (void *a, void *b)
{
const struct connected *ifa = (const struct connected *)a;
const struct connected *ifb = (const struct connected *)b;
return IPV4_ADDR_CMP(&ifa->address->u.prefix4.s_addr,&ifb->address->u.prefix4.s_addr);
}
void
router_id_cmd_init (void)
{
install_element (CONFIG_NODE, &router_id_cmd);
install_element (CONFIG_NODE, &no_router_id_cmd);
install_element (CONFIG_NODE, &router_id_vrf_cmd);
install_element (CONFIG_NODE, &no_router_id_vrf_cmd);
}
void
router_id_init (struct zebra_vrf *zvrf)
{
zvrf->rid_all_sorted_list = &zvrf->_rid_all_sorted_list;
zvrf->rid_lo_sorted_list = &zvrf->_rid_lo_sorted_list;
memset (zvrf->rid_all_sorted_list, 0, sizeof (zvrf->_rid_all_sorted_list));
memset (zvrf->rid_lo_sorted_list, 0, sizeof (zvrf->_rid_lo_sorted_list));
memset (&zvrf->rid_user_assigned, 0, sizeof (zvrf->rid_user_assigned));
zvrf->rid_all_sorted_list->cmp = router_id_cmp;
zvrf->rid_lo_sorted_list->cmp = router_id_cmp;
zvrf->rid_user_assigned.family = AF_INET;
zvrf->rid_user_assigned.prefixlen = 32;
}