mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 15:30:26 +00:00 
			
		
		
		
	these changes are for improving the code maintainability Signed-off-by: sri-mohan1 <sri.mohan@samsung.com>
		
			
				
	
	
		
			352 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			352 lines
		
	
	
		
			9.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * EIGRP Network Related Functions.
 | 
						|
 * Copyright (C) 2013-2014
 | 
						|
 * Authors:
 | 
						|
 *   Donnie Savage
 | 
						|
 *   Jan Janovic
 | 
						|
 *   Matej Perina
 | 
						|
 *   Peter Orsag
 | 
						|
 *   Peter Paluch
 | 
						|
 *
 | 
						|
 * This file is part of GNU Zebra.
 | 
						|
 *
 | 
						|
 * GNU Zebra 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.
 | 
						|
 *
 | 
						|
 * GNU Zebra 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 "thread.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "if.h"
 | 
						|
#include "sockunion.h"
 | 
						|
#include "log.h"
 | 
						|
#include "sockopt.h"
 | 
						|
#include "privs.h"
 | 
						|
#include "table.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "lib_errors.h"
 | 
						|
 | 
						|
#include "eigrpd/eigrp_structs.h"
 | 
						|
#include "eigrpd/eigrpd.h"
 | 
						|
#include "eigrpd/eigrp_interface.h"
 | 
						|
#include "eigrpd/eigrp_neighbor.h"
 | 
						|
#include "eigrpd/eigrp_packet.h"
 | 
						|
#include "eigrpd/eigrp_zebra.h"
 | 
						|
#include "eigrpd/eigrp_vty.h"
 | 
						|
#include "eigrpd/eigrp_network.h"
 | 
						|
 | 
						|
static int eigrp_network_match_iface(const struct prefix *connected_prefix,
 | 
						|
				     const struct prefix *prefix);
 | 
						|
static void eigrp_network_run_interface(struct eigrp *, struct prefix *,
 | 
						|
					struct interface *);
 | 
						|
 | 
						|
int eigrp_sock_init(struct vrf *vrf)
 | 
						|
{
 | 
						|
	int eigrp_sock = -1;
 | 
						|
	int ret;
 | 
						|
#ifdef IP_HDRINCL
 | 
						|
	int hincl = 1;
 | 
						|
#endif
 | 
						|
 | 
						|
	if (!vrf)
 | 
						|
		return eigrp_sock;
 | 
						|
 | 
						|
	frr_with_privs(&eigrpd_privs) {
 | 
						|
		eigrp_sock = vrf_socket(
 | 
						|
			AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP, vrf->vrf_id,
 | 
						|
			vrf->vrf_id != VRF_DEFAULT ? vrf->name : NULL);
 | 
						|
		if (eigrp_sock < 0) {
 | 
						|
			zlog_err("%s: socket: %s",
 | 
						|
				 __func__, safe_strerror(errno));
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
 | 
						|
#ifdef IP_HDRINCL
 | 
						|
		/* we will include IP header with packet */
 | 
						|
		ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
 | 
						|
				 sizeof(hincl));
 | 
						|
		if (ret < 0) {
 | 
						|
			zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
 | 
						|
				  eigrp_sock, safe_strerror(errno));
 | 
						|
		}
 | 
						|
#elif defined(IPTOS_PREC_INTERNETCONTROL)
 | 
						|
#warning "IP_HDRINCL not available on this system"
 | 
						|
#warning "using IPTOS_PREC_INTERNETCONTROL"
 | 
						|
		ret = setsockopt_ipv4_tos(eigrp_sock,
 | 
						|
					  IPTOS_PREC_INTERNETCONTROL);
 | 
						|
		if (ret < 0) {
 | 
						|
			zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s",
 | 
						|
				  tos, eigrp_sock, safe_strerror(errno));
 | 
						|
			close(eigrp_sock); /* Prevent sd leak. */
 | 
						|
			return ret;
 | 
						|
		}
 | 
						|
#else /* !IPTOS_PREC_INTERNETCONTROL */
 | 
						|
#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
 | 
						|
		zlog_warn("IP_HDRINCL option not available");
 | 
						|
#endif /* IP_HDRINCL */
 | 
						|
 | 
						|
		ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
 | 
						|
		if (ret < 0)
 | 
						|
			zlog_warn("Can't set pktinfo option for fd %d",
 | 
						|
				  eigrp_sock);
 | 
						|
	}
 | 
						|
 | 
						|
	return eigrp_sock;
 | 
						|
}
 | 
						|
 | 
						|
void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
 | 
						|
{
 | 
						|
	int newbuflen;
 | 
						|
	/* Check if any work has to be done at all. */
 | 
						|
	if (eigrp->maxsndbuflen >= buflen)
 | 
						|
		return;
 | 
						|
 | 
						|
	/* Now we try to set SO_SNDBUF to what our caller has requested
 | 
						|
	 * (the MTU of a newly added interface). However, if the OS has
 | 
						|
	 * truncated the actual buffer size to somewhat less size, try
 | 
						|
	 * to detect it and update our records appropriately. The OS
 | 
						|
	 * may allocate more buffer space, than requested, this isn't
 | 
						|
	 * a error.
 | 
						|
	 */
 | 
						|
	setsockopt_so_sendbuf(eigrp->fd, buflen);
 | 
						|
	newbuflen = getsockopt_so_sendbuf(eigrp->fd);
 | 
						|
	if (newbuflen < 0 || newbuflen < (int)buflen)
 | 
						|
		zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
 | 
						|
			  __func__, buflen, newbuflen);
 | 
						|
	if (newbuflen >= 0)
 | 
						|
		eigrp->maxsndbuflen = (unsigned int)newbuflen;
 | 
						|
	else
 | 
						|
		zlog_warn("%s: failed to get SO_SNDBUF", __func__);
 | 
						|
}
 | 
						|
 | 
						|
int eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p,
 | 
						|
			 unsigned int ifindex)
 | 
						|
{
 | 
						|
	uint8_t val;
 | 
						|
	int ret, len;
 | 
						|
 | 
						|
	val = 0;
 | 
						|
	len = sizeof(val);
 | 
						|
 | 
						|
	/* Prevent receiving self-origined multicast packets. */
 | 
						|
	ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_LOOP, (void *)&val,
 | 
						|
			 len);
 | 
						|
	if (ret < 0)
 | 
						|
		zlog_warn(
 | 
						|
			"can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s",
 | 
						|
			top->fd, safe_strerror(errno));
 | 
						|
 | 
						|
	/* Explicitly set multicast ttl to 1 -- endo. */
 | 
						|
	val = 1;
 | 
						|
	ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val,
 | 
						|
			 len);
 | 
						|
	if (ret < 0)
 | 
						|
		zlog_warn("can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s",
 | 
						|
			  top->fd, safe_strerror(errno));
 | 
						|
 | 
						|
	ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
 | 
						|
	if (ret < 0)
 | 
						|
		zlog_warn(
 | 
						|
			"can't setsockopt IP_MULTICAST_IF (fd %d, addr %pI4, ifindex %u): %s",
 | 
						|
			top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
/* Join to the EIGRP multicast group. */
 | 
						|
int eigrp_if_add_allspfrouters(struct eigrp *top, struct prefix *p,
 | 
						|
			       unsigned int ifindex)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = setsockopt_ipv4_multicast(
 | 
						|
		top->fd, IP_ADD_MEMBERSHIP, p->u.prefix4,
 | 
						|
		htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
 | 
						|
	if (ret < 0)
 | 
						|
		zlog_warn(
 | 
						|
			"can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
 | 
						|
			top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
 | 
						|
	else
 | 
						|
		zlog_debug("interface %pI4 [%u] join EIGRP Multicast group.",
 | 
						|
			   &p->u.prefix4, ifindex);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
 | 
						|
				unsigned int ifindex)
 | 
						|
{
 | 
						|
	int ret;
 | 
						|
 | 
						|
	ret = setsockopt_ipv4_multicast(
 | 
						|
		top->fd, IP_DROP_MEMBERSHIP, p->u.prefix4,
 | 
						|
		htonl(EIGRP_MULTICAST_ADDRESS), ifindex);
 | 
						|
	if (ret < 0)
 | 
						|
		zlog_warn(
 | 
						|
			"can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s",
 | 
						|
			top->fd, &p->u.prefix4, ifindex, safe_strerror(errno));
 | 
						|
	else
 | 
						|
		zlog_debug("interface %pI4 [%u] leave EIGRP Multicast group.",
 | 
						|
			   &p->u.prefix4, ifindex);
 | 
						|
 | 
						|
	return ret;
 | 
						|
}
 | 
						|
 | 
						|
int eigrp_network_set(struct eigrp *eigrp, struct prefix *p)
 | 
						|
{
 | 
						|
	struct vrf *vrf = vrf_lookup_by_id(eigrp->vrf_id);
 | 
						|
	struct route_node *rn;
 | 
						|
	struct interface *ifp;
 | 
						|
 | 
						|
	rn = route_node_get(eigrp->networks, p);
 | 
						|
	if (rn->info) {
 | 
						|
		/* There is already same network statement. */
 | 
						|
		route_unlock_node(rn);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	struct prefix *pref = prefix_new();
 | 
						|
	prefix_copy(pref, p);
 | 
						|
	rn->info = (void *)pref;
 | 
						|
 | 
						|
	/* Schedule Router ID Update. */
 | 
						|
	if (eigrp->router_id.s_addr == INADDR_ANY)
 | 
						|
		eigrp_router_id_update(eigrp);
 | 
						|
	/* Run network config now. */
 | 
						|
	/* Get target interface. */
 | 
						|
	FOR_ALL_INTERFACES (vrf, ifp) {
 | 
						|
		zlog_debug("Setting up %s", ifp->name);
 | 
						|
		eigrp_network_run_interface(eigrp, p, ifp);
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* Check whether interface matches given network
 | 
						|
 * returns: 1, true. 0, false
 | 
						|
 */
 | 
						|
static int eigrp_network_match_iface(const struct prefix *co_prefix,
 | 
						|
				     const struct prefix *net)
 | 
						|
{
 | 
						|
	/* new approach: more elegant and conceptually clean */
 | 
						|
	return prefix_match_network_statement(net, co_prefix);
 | 
						|
}
 | 
						|
 | 
						|
static void eigrp_network_run_interface(struct eigrp *eigrp, struct prefix *p,
 | 
						|
					struct interface *ifp)
 | 
						|
{
 | 
						|
	struct eigrp_interface *ei;
 | 
						|
	struct listnode *cnode;
 | 
						|
	struct connected *co;
 | 
						|
 | 
						|
	/* if interface prefix is match specified prefix,
 | 
						|
	   then create socket and join multicast group. */
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, co)) {
 | 
						|
 | 
						|
		if (CHECK_FLAG(co->flags, ZEBRA_IFA_SECONDARY))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (p->family == co->address->family && !ifp->info
 | 
						|
		    && eigrp_network_match_iface(co->address, p)) {
 | 
						|
 | 
						|
			ei = eigrp_if_new(eigrp, ifp, co->address);
 | 
						|
 | 
						|
			/* Relate eigrp interface to eigrp instance. */
 | 
						|
			ei->eigrp = eigrp;
 | 
						|
 | 
						|
			/* if router_id is not configured, dont bring up
 | 
						|
			 * interfaces.
 | 
						|
			 * eigrp_router_id_update() will call eigrp_if_update
 | 
						|
			 * whenever r-id is configured instead.
 | 
						|
			 */
 | 
						|
			if (if_is_operative(ifp))
 | 
						|
				eigrp_if_up(ei);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void eigrp_if_update(struct interface *ifp)
 | 
						|
{
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct route_node *rn;
 | 
						|
	struct eigrp *eigrp;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * In the event there are multiple eigrp autonymnous systems running,
 | 
						|
	 * we need to check eac one and add the interface as approperate
 | 
						|
	 */
 | 
						|
	for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
 | 
						|
		if (ifp->vrf->vrf_id != eigrp->vrf_id)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* EIGRP must be on and Router-ID must be configured. */
 | 
						|
		if (eigrp->router_id.s_addr == INADDR_ANY)
 | 
						|
			continue;
 | 
						|
 | 
						|
		/* Run each network for this interface. */
 | 
						|
		for (rn = route_top(eigrp->networks); rn; rn = route_next(rn))
 | 
						|
			if (rn->info != NULL) {
 | 
						|
				eigrp_network_run_interface(eigrp, &rn->p, ifp);
 | 
						|
			}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
 | 
						|
{
 | 
						|
	struct route_node *rn;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct eigrp_interface *ei;
 | 
						|
	struct prefix *pref;
 | 
						|
 | 
						|
	rn = route_node_lookup(eigrp->networks, p);
 | 
						|
	if (rn == NULL)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	pref = rn->info;
 | 
						|
	route_unlock_node(rn);
 | 
						|
 | 
						|
	if (!IPV4_ADDR_SAME(&pref->u.prefix4, &p->u.prefix4))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	prefix_ipv4_free((struct prefix_ipv4 **)&rn->info);
 | 
						|
	route_unlock_node(rn); /* initial reference */
 | 
						|
 | 
						|
	/* Find interfaces that not configured already.  */
 | 
						|
	for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei)) {
 | 
						|
		bool found = false;
 | 
						|
 | 
						|
		for (rn = route_top(eigrp->networks); rn; rn = route_next(rn)) {
 | 
						|
			if (rn->info == NULL)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (eigrp_network_match_iface(&ei->address, &rn->p)) {
 | 
						|
				found = true;
 | 
						|
				route_unlock_node(rn);
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (!found) {
 | 
						|
			eigrp_if_free(ei, INTERFACE_DOWN_BY_VTY);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return 1;
 | 
						|
}
 | 
						|
 | 
						|
void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
 | 
						|
{
 | 
						|
}
 |