/* * 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 #include "if.h" #include "vty.h" #include "sockunion.h" #include "prefix.h" #include "stream.h" #include "command.h" #include "memory.h" #include "zebra_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 = 32; 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 = 128; 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 p2; struct listnode *node; struct zserv *client; 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, &p2, zvrf); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zsend_router_id_update(client, afi, &p2, 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 = vrf_info_get(ifc->ifp->vrf_id); 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 = vrf_info_get(ifc->ifp->vrf_id); 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 = 32; 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 = 128; 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, 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 = 32; 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, 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 = 128; 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, 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, 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_get(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 = 32; zvrf->rid6_user_assigned.family = AF_INET6; zvrf->rid6_user_assigned.prefixlen = 128; }