summaryrefslogtreecommitdiffstats
path: root/zebra/router-id.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/router-id.c')
-rw-r--r--zebra/router-id.c614
1 files changed, 614 insertions, 0 deletions
diff --git a/zebra/router-id.c b/zebra/router-id.c
new file mode 100644
index 0000000..9f56cf0
--- /dev/null
+++ b/zebra/router-id.c
@@ -0,0 +1,614 @@
+/*
+ * 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 this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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/zebra_router.h"
+#include "zebra/zapi_msg.h"
+#include "zebra/zebra_vrf.h"
+#include "zebra/router-id.h"
+#include "zebra/redistribute.h"
+
+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)
+{
+ /* non-redistributable addresses shouldn't be used for RIDs either */
+ if (!zebra_check_addr(ifc->address))
+ return 1;
+
+ return 0;
+}
+
+static bool router_id_v6_is_any(struct prefix *p)
+{
+ return memcmp(&p->u.prefix6, &in6addr_any, sizeof(struct in6_addr))
+ == 0;
+}
+
+int router_id_get(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf)
+{
+ struct listnode *node;
+ struct connected *c;
+ struct in6_addr *addr = NULL;
+
+ switch (afi) {
+ case AFI_IP:
+ p->u.prefix4.s_addr = INADDR_ANY;
+ p->family = AF_INET;
+ p->prefixlen = IPV4_MAX_BITLEN;
+ if (zvrf->rid_user_assigned.u.prefix4.s_addr != INADDR_ANY)
+ 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;
+ }
+ return 0;
+ case AFI_IP6:
+ p->u.prefix6 = in6addr_any;
+ p->family = AF_INET6;
+ p->prefixlen = IPV6_MAX_BITLEN;
+ if (!router_id_v6_is_any(&zvrf->rid6_user_assigned))
+ addr = &zvrf->rid6_user_assigned.u.prefix6;
+ else if (!list_isempty(zvrf->rid6_lo_sorted_list)) {
+ node = listtail(zvrf->rid6_lo_sorted_list);
+ c = listgetdata(node);
+ addr = &c->address->u.prefix6;
+ } else if (!list_isempty(zvrf->rid6_all_sorted_list)) {
+ node = listtail(zvrf->rid6_all_sorted_list);
+ c = listgetdata(node);
+ addr = &c->address->u.prefix6;
+ }
+ if (addr)
+ memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr));
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+static int router_id_set(afi_t afi, struct prefix *p, struct zebra_vrf *zvrf)
+{
+ struct prefix after, before;
+ struct listnode *node;
+ struct zserv *client;
+
+ router_id_get(afi, &before, zvrf);
+
+ switch (afi) {
+ case AFI_IP:
+ zvrf->rid_user_assigned.u.prefix4.s_addr = p->u.prefix4.s_addr;
+ break;
+ case AFI_IP6:
+ zvrf->rid6_user_assigned.u.prefix6 = p->u.prefix6;
+ break;
+ default:
+ return -1;
+ }
+
+ router_id_get(afi, &after, zvrf);
+
+ /*
+ * If we've been told that the router-id is exactly the same
+ * do we need to really do anything here?
+ */
+ if (prefix_same(&before, &after))
+ return 0;
+
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ zsend_router_id_update(client, afi, &after, zvrf->vrf->vrf_id);
+
+ return 0;
+}
+
+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 = ifc->ifp->vrf->info;
+ afi_t afi;
+ struct list *rid_lo;
+ struct list *rid_all;
+
+ if (router_id_bad_address(ifc))
+ return;
+
+ switch (ifc->address->family) {
+ case AF_INET:
+ afi = AFI_IP;
+ rid_lo = zvrf->rid_lo_sorted_list;
+ rid_all = zvrf->rid_all_sorted_list;
+ break;
+ case AF_INET6:
+ afi = AFI_IP6;
+ rid_lo = zvrf->rid6_lo_sorted_list;
+ rid_all = zvrf->rid6_all_sorted_list;
+ break;
+ default:
+ return;
+ }
+
+ router_id_get(afi, &before, zvrf);
+
+ l = if_is_loopback(ifc->ifp) ? rid_lo : rid_all;
+
+ if (!router_id_find_node(l, ifc))
+ listnode_add_sort(l, ifc);
+
+ router_id_get(afi, &after, zvrf);
+
+ if (prefix_same(&before, &after))
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ zsend_router_id_update(client, afi, &after, zvrf_id(zvrf));
+}
+
+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 = ifc->ifp->vrf->info;
+ afi_t afi;
+ struct list *rid_lo;
+ struct list *rid_all;
+
+ if (router_id_bad_address(ifc))
+ return;
+
+ switch (ifc->address->family) {
+ case AF_INET:
+ afi = AFI_IP;
+ rid_lo = zvrf->rid_lo_sorted_list;
+ rid_all = zvrf->rid_all_sorted_list;
+ break;
+ case AF_INET6:
+ afi = AFI_IP6;
+ rid_lo = zvrf->rid6_lo_sorted_list;
+ rid_all = zvrf->rid6_all_sorted_list;
+ break;
+ default:
+ return;
+ }
+
+ router_id_get(afi, &before, zvrf);
+
+ if (if_is_loopback(ifc->ifp))
+ l = rid_lo;
+ else
+ l = rid_all;
+
+ if ((c = router_id_find_node(l, ifc)))
+ listnode_delete(l, c);
+
+ router_id_get(afi, &after, zvrf);
+
+ if (prefix_same(&before, &after))
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ zsend_router_id_update(client, afi, &after, zvrf_id(zvrf));
+}
+
+void router_id_write(struct vty *vty, struct zebra_vrf *zvrf)
+{
+ char space[2];
+
+ memset(space, 0, sizeof(space));
+
+ if (zvrf_id(zvrf) != VRF_DEFAULT)
+ snprintf(space, sizeof(space), "%s", " ");
+
+ if (zvrf->rid_user_assigned.u.prefix4.s_addr != INADDR_ANY) {
+ vty_out(vty, "%sip router-id %pI4\n", space,
+ &zvrf->rid_user_assigned.u.prefix4);
+ }
+ if (!router_id_v6_is_any(&zvrf->rid6_user_assigned)) {
+ vty_out(vty, "%sipv6 router-id %pI6\n", space,
+ &zvrf->rid_user_assigned.u.prefix6);
+ }
+}
+
+DEFUN (ip_router_id,
+ ip_router_id_cmd,
+ "ip router-id A.B.C.D vrf NAME",
+ IP_STR
+ "Manually set the router-id\n"
+ "IP address to use for router-id\n"
+ VRF_CMD_HELP_STR)
+{
+ int idx = 0;
+ struct prefix rid;
+ vrf_id_t vrf_id;
+ struct zebra_vrf *zvrf;
+
+ argv_find(argv, argc, "A.B.C.D", &idx);
+
+ if (!inet_pton(AF_INET, argv[idx]->arg, &rid.u.prefix4))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ rid.prefixlen = IPV4_MAX_BITLEN;
+ rid.family = AF_INET;
+
+ argv_find(argv, argc, "NAME", &idx);
+ VRF_GET_ID(vrf_id, argv[idx]->arg, false);
+
+ zvrf = vrf_info_lookup(vrf_id);
+ router_id_set(AFI_IP, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (ip_router_id,
+ router_id_cmd,
+ "router-id A.B.C.D vrf NAME",
+ "Manually set the router-id\n"
+ "IP address to use for router-id\n"
+ VRF_CMD_HELP_STR);
+
+DEFUN (ipv6_router_id,
+ ipv6_router_id_cmd,
+ "ipv6 router-id X:X::X:X vrf NAME",
+ IPV6_STR
+ "Manually set the router-id\n"
+ "IPv6 address to use for router-id\n"
+ VRF_CMD_HELP_STR)
+{
+ int idx = 0;
+ struct prefix rid;
+ vrf_id_t vrf_id;
+ struct zebra_vrf *zvrf;
+
+ argv_find(argv, argc, "X:X::X:X", &idx);
+
+ if (!inet_pton(AF_INET6, argv[idx]->arg, &rid.u.prefix6))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ rid.prefixlen = IPV6_MAX_BITLEN;
+ rid.family = AF_INET6;
+
+ argv_find(argv, argc, "NAME", &idx);
+ VRF_GET_ID(vrf_id, argv[idx]->arg, false);
+
+ zvrf = vrf_info_lookup(vrf_id);
+ router_id_set(AFI_IP6, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+
+DEFUN (ip_router_id_in_vrf,
+ ip_router_id_in_vrf_cmd,
+ "ip router-id A.B.C.D",
+ IP_STR
+ "Manually set the router-id\n"
+ "IP address to use for router-id\n")
+{
+ ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
+ int idx = 0;
+ struct prefix rid;
+
+ argv_find(argv, argc, "A.B.C.D", &idx);
+
+ if (!inet_pton(AF_INET, argv[idx]->arg, &rid.u.prefix4))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ rid.prefixlen = IPV4_MAX_BITLEN;
+ rid.family = AF_INET;
+
+ router_id_set(AFI_IP, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (ip_router_id_in_vrf,
+ router_id_in_vrf_cmd,
+ "router-id A.B.C.D",
+ "Manually set the router-id\n"
+ "IP address to use for router-id\n");
+
+DEFUN (ipv6_router_id_in_vrf,
+ ipv6_router_id_in_vrf_cmd,
+ "ipv6 router-id X:X::X:X",
+ IP6_STR
+ "Manually set the IPv6 router-id\n"
+ "IPV6 address to use for router-id\n")
+{
+ ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
+ int idx = 0;
+ struct prefix rid;
+
+ argv_find(argv, argc, "X:X::X:X", &idx);
+
+ if (!inet_pton(AF_INET6, argv[idx]->arg, &rid.u.prefix6))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ rid.prefixlen = IPV6_MAX_BITLEN;
+ rid.family = AF_INET6;
+
+ router_id_set(AFI_IP6, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_router_id,
+ no_ip_router_id_cmd,
+ "no ip router-id [A.B.C.D vrf NAME]",
+ NO_STR
+ IP_STR
+ "Remove the manually configured router-id\n"
+ "IP address to use for router-id\n"
+ VRF_CMD_HELP_STR)
+{
+ int idx = 0;
+ struct prefix rid;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+ struct zebra_vrf *zvrf;
+
+ rid.u.prefix4.s_addr = 0;
+ rid.prefixlen = 0;
+ rid.family = AF_INET;
+
+ if (argv_find(argv, argc, "NAME", &idx))
+ VRF_GET_ID(vrf_id, argv[idx]->arg, false);
+
+ zvrf = vrf_info_lookup(vrf_id);
+ router_id_set(AFI_IP, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_router_id,
+ no_router_id_cmd,
+ "no router-id [A.B.C.D vrf NAME]",
+ NO_STR
+ "Remove the manually configured router-id\n"
+ "IP address to use for router-id\n"
+ VRF_CMD_HELP_STR);
+
+DEFUN (no_ipv6_router_id,
+ no_ipv6_router_id_cmd,
+ "no ipv6 router-id [X:X::X:X vrf NAME]",
+ NO_STR
+ IPV6_STR
+ "Remove the manually configured IPv6 router-id\n"
+ "IPv6 address to use for router-id\n"
+ VRF_CMD_HELP_STR)
+{
+ int idx = 0;
+ struct prefix rid;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+ struct zebra_vrf *zvrf;
+
+ memset(&rid, 0, sizeof(rid));
+ rid.family = AF_INET;
+
+ if (argv_find(argv, argc, "NAME", &idx))
+ VRF_GET_ID(vrf_id, argv[idx]->arg, false);
+
+ zvrf = vrf_info_lookup(vrf_id);
+ router_id_set(AFI_IP6, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_ip_router_id_in_vrf,
+ no_ip_router_id_in_vrf_cmd,
+ "no ip router-id [A.B.C.D]",
+ NO_STR
+ IP_STR
+ "Remove the manually configured router-id\n"
+ "IP address to use for router-id\n")
+{
+ ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
+
+ struct prefix rid;
+
+ rid.u.prefix4.s_addr = 0;
+ rid.prefixlen = 0;
+ rid.family = AF_INET;
+
+ router_id_set(AFI_IP, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+ALIAS (no_ip_router_id_in_vrf,
+ no_router_id_in_vrf_cmd,
+ "no router-id [A.B.C.D]",
+ NO_STR
+ "Remove the manually configured router-id\n"
+ "IP address to use for router-id\n");
+
+DEFUN (no_ipv6_router_id_in_vrf,
+ no_ipv6_router_id_in_vrf_cmd,
+ "no ipv6 router-id [X:X::X:X]",
+ NO_STR
+ IP6_STR
+ "Remove the manually configured IPv6 router-id\n"
+ "IPv6 address to use for router-id\n")
+{
+ ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf);
+
+ struct prefix rid;
+
+ memset(&rid, 0, sizeof(rid));
+ rid.family = AF_INET;
+
+ router_id_set(AFI_IP6, &rid, zvrf);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (show_ip_router_id,
+ show_ip_router_id_cmd,
+ "show [ip|ipv6] router-id [vrf NAME]",
+ SHOW_STR
+ IP_STR
+ IPV6_STR
+ "Show the configured router-id\n"
+ VRF_CMD_HELP_STR)
+{
+ int idx = 0;
+ vrf_id_t vrf_id = VRF_DEFAULT;
+ struct zebra_vrf *zvrf;
+ const char *vrf_name = "default";
+ char addr_name[INET6_ADDRSTRLEN];
+ int is_ipv6 = 0;
+
+ is_ipv6 = argv_find(argv, argc, "ipv6", &idx);
+
+ if (argv_find(argv, argc, "NAME", &idx)) {
+ VRF_GET_ID(vrf_id, argv[idx]->arg, false);
+ vrf_name = argv[idx]->arg;
+ }
+
+ zvrf = vrf_info_lookup(vrf_id);
+
+ if (zvrf != NULL) {
+ if (is_ipv6) {
+ if (router_id_v6_is_any(&zvrf->rid6_user_assigned))
+ return CMD_SUCCESS;
+ inet_ntop(AF_INET6, &zvrf->rid6_user_assigned.u.prefix6,
+ addr_name, sizeof(addr_name));
+ } else {
+ if (zvrf->rid_user_assigned.u.prefix4.s_addr
+ == INADDR_ANY)
+ return CMD_SUCCESS;
+ inet_ntop(AF_INET, &zvrf->rid_user_assigned.u.prefix4,
+ addr_name, sizeof(addr_name));
+ }
+
+ vty_out(vty, "zebra:\n");
+ vty_out(vty, " router-id %s vrf %s\n", addr_name, vrf_name);
+ }
+
+ return CMD_SUCCESS;
+}
+
+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);
+}
+
+static int router_id_v6_cmp(void *a, void *b)
+{
+ const struct connected *ifa = (const struct connected *)a;
+ const struct connected *ifb = (const struct connected *)b;
+
+ return IPV6_ADDR_CMP(&ifa->address->u.prefix6,
+ &ifb->address->u.prefix6);
+}
+
+void router_id_cmd_init(void)
+{
+ install_element(CONFIG_NODE, &ip_router_id_cmd);
+ install_element(CONFIG_NODE, &router_id_cmd);
+ install_element(CONFIG_NODE, &ipv6_router_id_cmd);
+ install_element(CONFIG_NODE, &no_ip_router_id_cmd);
+ install_element(CONFIG_NODE, &no_router_id_cmd);
+ install_element(CONFIG_NODE, &ip_router_id_in_vrf_cmd);
+ install_element(VRF_NODE, &ip_router_id_in_vrf_cmd);
+ install_element(CONFIG_NODE, &router_id_in_vrf_cmd);
+ install_element(VRF_NODE, &router_id_in_vrf_cmd);
+ install_element(CONFIG_NODE, &ipv6_router_id_in_vrf_cmd);
+ install_element(VRF_NODE, &ipv6_router_id_in_vrf_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_router_id_cmd);
+ install_element(CONFIG_NODE, &no_ip_router_id_in_vrf_cmd);
+ install_element(VRF_NODE, &no_ip_router_id_in_vrf_cmd);
+ install_element(CONFIG_NODE, &no_router_id_in_vrf_cmd);
+ install_element(VRF_NODE, &no_router_id_in_vrf_cmd);
+ install_element(CONFIG_NODE, &no_ipv6_router_id_in_vrf_cmd);
+ install_element(VRF_NODE, &no_ipv6_router_id_in_vrf_cmd);
+ install_element(VIEW_NODE, &show_ip_router_id_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;
+ zvrf->rid6_all_sorted_list = &zvrf->_rid6_all_sorted_list;
+ zvrf->rid6_lo_sorted_list = &zvrf->_rid6_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));
+ memset(zvrf->rid6_all_sorted_list, 0,
+ sizeof(zvrf->_rid6_all_sorted_list));
+ memset(zvrf->rid6_lo_sorted_list, 0,
+ sizeof(zvrf->_rid6_lo_sorted_list));
+ memset(&zvrf->rid6_user_assigned, 0, sizeof(zvrf->rid6_user_assigned));
+
+ zvrf->rid_all_sorted_list->cmp = router_id_cmp;
+ zvrf->rid_lo_sorted_list->cmp = router_id_cmp;
+ zvrf->rid6_all_sorted_list->cmp = router_id_v6_cmp;
+ zvrf->rid6_lo_sorted_list->cmp = router_id_v6_cmp;
+
+ zvrf->rid_user_assigned.family = AF_INET;
+ zvrf->rid_user_assigned.prefixlen = IPV4_MAX_BITLEN;
+ zvrf->rid6_user_assigned.family = AF_INET6;
+ zvrf->rid6_user_assigned.prefixlen = IPV6_MAX_BITLEN;
+}