mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 09:04:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			288 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			288 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 "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)
 | |
| {
 | |
| 	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(zrouter.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_id(zvrf));
 | |
| 
 | |
| 	if (if_is_loopback(ifc->ifp))
 | |
| 		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_id(zvrf));
 | |
| 
 | |
| 	if (prefix_same(&before, &after))
 | |
| 		return;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
 | |
| 		zsend_router_id_update(client, &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);
 | |
| 
 | |
| 	if (router_id_bad_address(ifc))
 | |
| 		return;
 | |
| 
 | |
| 	router_id_get(&before, zvrf_id(zvrf));
 | |
| 
 | |
| 	if (if_is_loopback(ifc->ifp))
 | |
| 		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_id(zvrf));
 | |
| 
 | |
| 	if (prefix_same(&before, &after))
 | |
| 		return;
 | |
| 
 | |
| 	for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
 | |
| 		zsend_router_id_update(client, &after, zvrf_id(zvrf));
 | |
| }
 | |
| 
 | |
| void router_id_write(struct vty *vty)
 | |
| {
 | |
| 	struct vrf *vrf;
 | |
| 	struct zebra_vrf *zvrf;
 | |
| 
 | |
| 	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
 | |
| 		if ((zvrf = vrf->info) != NULL)
 | |
| 			if (zvrf->rid_user_assigned.u.prefix4.s_addr) {
 | |
| 				if (zvrf_id(zvrf) == VRF_DEFAULT)
 | |
| 					vty_out(vty, "router-id %s\n",
 | |
| 						inet_ntoa(
 | |
| 							zvrf->rid_user_assigned
 | |
| 								.u.prefix4));
 | |
| 				else
 | |
| 					vty_out(vty, "router-id %s vrf %s\n",
 | |
| 						inet_ntoa(
 | |
| 							zvrf->rid_user_assigned
 | |
| 								.u.prefix4),
 | |
| 						zvrf_name(zvrf));
 | |
| 			}
 | |
| }
 | |
| 
 | |
| DEFUN (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)
 | |
| {
 | |
| 	int idx_ipv4 = 1;
 | |
| 	int idx_name = 3;
 | |
| 
 | |
| 	struct prefix rid;
 | |
| 	vrf_id_t vrf_id = VRF_DEFAULT;
 | |
| 
 | |
| 	rid.u.prefix4.s_addr = inet_addr(argv[idx_ipv4]->arg);
 | |
| 	if (!rid.u.prefix4.s_addr)
 | |
| 		return CMD_WARNING_CONFIG_FAILED;
 | |
| 
 | |
| 	rid.prefixlen = 32;
 | |
| 	rid.family = AF_INET;
 | |
| 
 | |
| 	if (argc > 2)
 | |
| 		VRF_GET_ID(vrf_id, argv[idx_name]->arg, false);
 | |
| 
 | |
| 	router_id_set(&rid, vrf_id);
 | |
| 
 | |
| 	return CMD_SUCCESS;
 | |
| }
 | |
| 
 | |
| DEFUN (no_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)
 | |
| {
 | |
| 	int idx_name = 4;
 | |
| 
 | |
| 	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 > 3)
 | |
| 		VRF_GET_ID(vrf_id, argv[idx_name]->arg, false);
 | |
| 
 | |
| 	router_id_set(&rid, vrf_id);
 | |
| 
 | |
| 	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);
 | |
| }
 | |
| 
 | |
| void router_id_cmd_init(void)
 | |
| {
 | |
| 	install_element(CONFIG_NODE, &router_id_cmd);
 | |
| 	install_element(CONFIG_NODE, &no_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;
 | |
| 
 | |
| 	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;
 | |
| }
 | 
