mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 06:00:58 +00:00 
			
		
		
		
	This code fixes a crash in EIGRP when on initial neighbor formation we need to send more than 1 packet of data to the nbr. I was testing this by redistributing connected and just adding a bunch of /32 address to an interface. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
		
			
				
	
	
		
			1146 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1146 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * EIGRP Sending and Receiving EIGRP Update Packets.
 | 
						|
 * Copyright (C) 2013-2016
 | 
						|
 * Authors:
 | 
						|
 *   Donnie Savage
 | 
						|
 *   Jan Janovic
 | 
						|
 *   Matej Perina
 | 
						|
 *   Peter Orsag
 | 
						|
 *   Peter Paluch
 | 
						|
 *   Frantisek Gazo
 | 
						|
 *   Tomas Hvorkovy
 | 
						|
 *   Martin Kontsek
 | 
						|
 *   Lukas Koribsky
 | 
						|
 *
 | 
						|
 * 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 "memory.h"
 | 
						|
#include "linklist.h"
 | 
						|
#include "prefix.h"
 | 
						|
#include "if.h"
 | 
						|
#include "table.h"
 | 
						|
#include "sockunion.h"
 | 
						|
#include "stream.h"
 | 
						|
#include "log.h"
 | 
						|
#include "sockopt.h"
 | 
						|
#include "checksum.h"
 | 
						|
#include "md5.h"
 | 
						|
#include "vty.h"
 | 
						|
#include "plist.h"
 | 
						|
#include "plist_int.h"
 | 
						|
#include "routemap.h"
 | 
						|
#include "vty.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_dump.h"
 | 
						|
#include "eigrpd/eigrp_macros.h"
 | 
						|
#include "eigrpd/eigrp_topology.h"
 | 
						|
#include "eigrpd/eigrp_fsm.h"
 | 
						|
#include "eigrpd/eigrp_network.h"
 | 
						|
#include "eigrpd/eigrp_memory.h"
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn remove_received_prefix_gr
 | 
						|
 *
 | 
						|
 * @param[in]		nbr_prefixes	List of neighbor prefixes
 | 
						|
 * @param[in]		recv_prefix 	Prefix which needs to be removed from
 | 
						|
 * list
 | 
						|
 *
 | 
						|
 * @return void
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function is used for removing received prefix
 | 
						|
 * from list of neighbor prefixes
 | 
						|
 */
 | 
						|
static void remove_received_prefix_gr(struct list *nbr_prefixes,
 | 
						|
				      struct eigrp_prefix_entry *recv_prefix)
 | 
						|
{
 | 
						|
	struct listnode *node1, *node11;
 | 
						|
	struct eigrp_prefix_entry *prefix = NULL;
 | 
						|
 | 
						|
	/* iterate over all prefixes in list */
 | 
						|
	for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) {
 | 
						|
		/* remove prefix from list if found */
 | 
						|
		if (prefix == recv_prefix) {
 | 
						|
			listnode_delete(nbr_prefixes, prefix);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn eigrp_update_receive_GR_ask
 | 
						|
 *
 | 
						|
 * @param[in]		eigrp			EIGRP process
 | 
						|
 * @param[in]		nbr 			Neighbor update of who we
 | 
						|
 * received
 | 
						|
 * @param[in]		nbr_prefixes 	Prefixes which weren't advertised
 | 
						|
 *
 | 
						|
 * @return void
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function is used for notifying FSM about prefixes which
 | 
						|
 * weren't advertised by neighbor:
 | 
						|
 * We will send message to FSM with prefix delay set to infinity.
 | 
						|
 */
 | 
						|
static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
 | 
						|
					struct eigrp_neighbor *nbr,
 | 
						|
					struct list *nbr_prefixes)
 | 
						|
{
 | 
						|
	struct listnode *node1;
 | 
						|
	struct eigrp_prefix_entry *prefix;
 | 
						|
	struct TLV_IPv4_Internal_type *tlv_max;
 | 
						|
 | 
						|
	/* iterate over all prefixes which weren't advertised by neighbor */
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix)) {
 | 
						|
		zlog_debug("GR receive: Neighbor not advertised %s/%d",
 | 
						|
			   inet_ntoa(prefix->destination_ipv4->prefix),
 | 
						|
			   prefix->destination_ipv4->prefixlen);
 | 
						|
 | 
						|
		/* create internal IPv4 TLV with infinite delay */
 | 
						|
		tlv_max = eigrp_IPv4_InternalTLV_new();
 | 
						|
		tlv_max->type = EIGRP_TLV_IPv4_INT;
 | 
						|
		tlv_max->length = 28U;
 | 
						|
		tlv_max->metric = prefix->reported_metric;
 | 
						|
		/* set delay to MAX */
 | 
						|
		tlv_max->metric.delay = EIGRP_MAX_METRIC;
 | 
						|
		tlv_max->destination = prefix->destination_ipv4->prefix;
 | 
						|
		tlv_max->prefix_length = prefix->destination_ipv4->prefixlen;
 | 
						|
 | 
						|
 | 
						|
		/* prepare message for FSM */
 | 
						|
		struct eigrp_fsm_action_message *fsm_msg;
 | 
						|
		fsm_msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
 | 
						|
				  sizeof(struct eigrp_fsm_action_message));
 | 
						|
 | 
						|
		struct eigrp_neighbor_entry *entry =
 | 
						|
			eigrp_prefix_entry_lookup(prefix->entries, nbr);
 | 
						|
 | 
						|
		fsm_msg->packet_type = EIGRP_OPC_UPDATE;
 | 
						|
		fsm_msg->eigrp = eigrp;
 | 
						|
		fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
 | 
						|
		fsm_msg->adv_router = nbr;
 | 
						|
		fsm_msg->data.ipv4_int_type = tlv_max;
 | 
						|
		fsm_msg->entry = entry;
 | 
						|
		fsm_msg->prefix = prefix;
 | 
						|
 | 
						|
		/* send message to FSM */
 | 
						|
		int event = eigrp_get_fsm_event(fsm_msg);
 | 
						|
		eigrp_fsm_event(fsm_msg, event);
 | 
						|
 | 
						|
		/* free memory used by TLV */
 | 
						|
		eigrp_IPv4_InternalTLV_free(tlv_max);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * EIGRP UPDATE read function
 | 
						|
 */
 | 
						|
void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
 | 
						|
			  struct eigrp_header *eigrph, struct stream *s,
 | 
						|
			  struct eigrp_interface *ei, int size)
 | 
						|
{
 | 
						|
	struct eigrp_neighbor *nbr;
 | 
						|
	struct TLV_IPv4_Internal_type *tlv;
 | 
						|
	struct eigrp_prefix_entry *pe;
 | 
						|
	struct eigrp_neighbor_entry *ne;
 | 
						|
	u_int32_t flags;
 | 
						|
	u_int16_t type;
 | 
						|
	u_char same;
 | 
						|
	struct access_list *alist;
 | 
						|
	struct prefix_list *plist;
 | 
						|
	struct eigrp *e;
 | 
						|
	u_char graceful_restart;
 | 
						|
	u_char graceful_restart_final;
 | 
						|
	struct list *nbr_prefixes = NULL;
 | 
						|
 | 
						|
	/* increment statistics. */
 | 
						|
	ei->update_in++;
 | 
						|
 | 
						|
	/* get neighbor struct */
 | 
						|
	nbr = eigrp_nbr_get(ei, eigrph, iph);
 | 
						|
 | 
						|
	/* neighbor must be valid, eigrp_nbr_get creates if none existed */
 | 
						|
	assert(nbr);
 | 
						|
 | 
						|
	flags = ntohl(eigrph->flags);
 | 
						|
 | 
						|
	if (flags & EIGRP_CR_FLAG) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	same = 0;
 | 
						|
	graceful_restart = 0;
 | 
						|
	graceful_restart_final = 0;
 | 
						|
	if ((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
 | 
						|
		same = 1;
 | 
						|
 | 
						|
	nbr->recv_sequence_number = ntohl(eigrph->sequence);
 | 
						|
	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
 | 
						|
		zlog_debug(
 | 
						|
			"Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
 | 
						|
			size,
 | 
						|
			ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT),
 | 
						|
			inet_ntoa(nbr->src), nbr->recv_sequence_number, flags);
 | 
						|
 | 
						|
 | 
						|
	if ((flags == (EIGRP_INIT_FLAG + EIGRP_RS_FLAG + EIGRP_EOT_FLAG))
 | 
						|
	    && (!same)) {
 | 
						|
		/* Graceful restart Update received with all routes */
 | 
						|
 | 
						|
		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
 | 
						|
			  inet_ntoa(nbr->src),
 | 
						|
			  ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
 | 
						|
 | 
						|
		/* get all prefixes from neighbor from topology table */
 | 
						|
		nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
 | 
						|
		graceful_restart = 1;
 | 
						|
		graceful_restart_final = 1;
 | 
						|
	} else if ((flags == (EIGRP_INIT_FLAG + EIGRP_RS_FLAG)) && (!same)) {
 | 
						|
		/* Graceful restart Update received, routes also in next packet
 | 
						|
		 */
 | 
						|
 | 
						|
		zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
 | 
						|
			  inet_ntoa(nbr->src),
 | 
						|
			  ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
 | 
						|
 | 
						|
		/* get all prefixes from neighbor from topology table */
 | 
						|
		nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
 | 
						|
		/* save prefixes to neighbor for later use */
 | 
						|
		nbr->nbr_gr_prefixes = nbr_prefixes;
 | 
						|
		graceful_restart = 1;
 | 
						|
		graceful_restart_final = 0;
 | 
						|
	} else if ((flags == (EIGRP_EOT_FLAG)) && (!same)) {
 | 
						|
		/* If there was INIT+RS Update packet before,
 | 
						|
		 *  consider this as GR EOT */
 | 
						|
 | 
						|
		if (nbr->nbr_gr_prefixes != NULL) {
 | 
						|
			/* this is final packet of GR */
 | 
						|
			nbr_prefixes = nbr->nbr_gr_prefixes;
 | 
						|
			nbr->nbr_gr_prefixes = NULL;
 | 
						|
 | 
						|
			graceful_restart = 1;
 | 
						|
			graceful_restart_final = 1;
 | 
						|
		}
 | 
						|
 | 
						|
	} else if ((flags == (0)) && (!same)) {
 | 
						|
		/* If there was INIT+RS Update packet before,
 | 
						|
		 *  consider this as GR not final packet */
 | 
						|
 | 
						|
		if (nbr->nbr_gr_prefixes != NULL) {
 | 
						|
			/* this is GR not final route packet */
 | 
						|
			nbr_prefixes = nbr->nbr_gr_prefixes;
 | 
						|
 | 
						|
			graceful_restart = 1;
 | 
						|
			graceful_restart_final = 0;
 | 
						|
		}
 | 
						|
 | 
						|
	} else if ((flags & EIGRP_INIT_FLAG)
 | 
						|
		   && (!same)) { /* When in pending state, send INIT update only
 | 
						|
				    if it wasn't
 | 
						|
				    already sent before (only if init_sequence
 | 
						|
				    is 0) */
 | 
						|
		if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
 | 
						|
		    && (nbr->init_sequence_number == 0))
 | 
						|
			eigrp_update_send_init(nbr);
 | 
						|
 | 
						|
		if (nbr->state == EIGRP_NEIGHBOR_UP) {
 | 
						|
			eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
 | 
						|
			eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr);
 | 
						|
			nbr->recv_sequence_number = ntohl(eigrph->sequence);
 | 
						|
			zlog_info("Neighbor %s (%s) is down: peer restarted",
 | 
						|
				  inet_ntoa(nbr->src),
 | 
						|
				  ifindex2ifname(nbr->ei->ifp->ifindex,
 | 
						|
						 VRF_DEFAULT));
 | 
						|
			eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
 | 
						|
			zlog_info("Neighbor %s (%s) is pending: new adjacency",
 | 
						|
				  inet_ntoa(nbr->src),
 | 
						|
				  ifindex2ifname(nbr->ei->ifp->ifindex,
 | 
						|
						 VRF_DEFAULT));
 | 
						|
			eigrp_update_send_init(nbr);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/*If there is topology information*/
 | 
						|
	while (s->endp > s->getp) {
 | 
						|
		type = stream_getw(s);
 | 
						|
		if (type == EIGRP_TLV_IPv4_INT) {
 | 
						|
			struct prefix_ipv4 dest_addr;
 | 
						|
 | 
						|
			stream_set_getp(s, s->getp - sizeof(u_int16_t));
 | 
						|
 | 
						|
			tlv = eigrp_read_ipv4_tlv(s);
 | 
						|
 | 
						|
			/*searching if destination exists */
 | 
						|
			dest_addr.family = AF_INET;
 | 
						|
			dest_addr.prefix = tlv->destination;
 | 
						|
			dest_addr.prefixlen = tlv->prefix_length;
 | 
						|
			struct eigrp_prefix_entry *dest =
 | 
						|
				eigrp_topology_table_lookup_ipv4(
 | 
						|
					eigrp->topology_table, &dest_addr);
 | 
						|
 | 
						|
			/*if exists it comes to DUAL*/
 | 
						|
			if (dest != NULL) {
 | 
						|
				/* remove received prefix from neighbor prefix
 | 
						|
				 * list if in GR */
 | 
						|
				if (graceful_restart)
 | 
						|
					remove_received_prefix_gr(nbr_prefixes,
 | 
						|
								  dest);
 | 
						|
 | 
						|
				struct eigrp_fsm_action_message *msg;
 | 
						|
				msg = XCALLOC(MTYPE_EIGRP_FSM_MSG,
 | 
						|
					      sizeof(struct
 | 
						|
						     eigrp_fsm_action_message));
 | 
						|
				struct eigrp_neighbor_entry *entry =
 | 
						|
					eigrp_prefix_entry_lookup(dest->entries,
 | 
						|
								  nbr);
 | 
						|
 | 
						|
				msg->packet_type = EIGRP_OPC_UPDATE;
 | 
						|
				msg->eigrp = eigrp;
 | 
						|
				msg->data_type = EIGRP_TLV_IPv4_INT;
 | 
						|
				msg->adv_router = nbr;
 | 
						|
				msg->data.ipv4_int_type = tlv;
 | 
						|
				msg->entry = entry;
 | 
						|
				msg->prefix = dest;
 | 
						|
				int event = eigrp_get_fsm_event(msg);
 | 
						|
				eigrp_fsm_event(msg, event);
 | 
						|
			} else {
 | 
						|
				/*Here comes topology information save*/
 | 
						|
				pe = eigrp_prefix_entry_new();
 | 
						|
				pe->serno = eigrp->serno;
 | 
						|
				pe->destination_ipv4 = prefix_ipv4_new();
 | 
						|
				prefix_copy(
 | 
						|
					(struct prefix *)pe->destination_ipv4,
 | 
						|
					(struct prefix *)&dest_addr);
 | 
						|
				pe->af = AF_INET;
 | 
						|
				pe->state = EIGRP_FSM_STATE_PASSIVE;
 | 
						|
				pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
 | 
						|
 | 
						|
				ne = eigrp_neighbor_entry_new();
 | 
						|
				ne->ei = ei;
 | 
						|
				ne->adv_router = nbr;
 | 
						|
				ne->reported_metric = tlv->metric;
 | 
						|
				ne->reported_distance = eigrp_calculate_metrics(
 | 
						|
					eigrp, tlv->metric);
 | 
						|
				/*
 | 
						|
				 * Filtering
 | 
						|
				 */
 | 
						|
				e = eigrp_lookup();
 | 
						|
				/*
 | 
						|
				 * Check if there is any access-list on
 | 
						|
				 * interface (IN direction)
 | 
						|
				 *  and set distance to max
 | 
						|
				 */
 | 
						|
				alist = ei->list[EIGRP_FILTER_IN];
 | 
						|
 | 
						|
				/* Check if access-list fits */
 | 
						|
				if (alist
 | 
						|
				    && access_list_apply(
 | 
						|
					       alist,
 | 
						|
					       (struct prefix *)&dest_addr)
 | 
						|
					       == FILTER_DENY) {
 | 
						|
					/* If yes, set reported metric to Max */
 | 
						|
					ne->reported_metric.delay =
 | 
						|
						EIGRP_MAX_METRIC;
 | 
						|
				} else {
 | 
						|
					ne->distance =
 | 
						|
						eigrp_calculate_total_metrics(
 | 
						|
							eigrp, ne);
 | 
						|
				}
 | 
						|
 | 
						|
				plist = e->prefix[EIGRP_FILTER_IN];
 | 
						|
 | 
						|
				/* Check if prefix-list fits */
 | 
						|
				if (plist
 | 
						|
				    && prefix_list_apply(
 | 
						|
					       plist,
 | 
						|
					       (struct prefix *)&dest_addr)
 | 
						|
					       == PREFIX_DENY) {
 | 
						|
					/* If yes, set reported metric to Max */
 | 
						|
					ne->reported_metric.delay =
 | 
						|
						EIGRP_MAX_METRIC;
 | 
						|
				}
 | 
						|
 | 
						|
				/*Get access-list from current interface */
 | 
						|
				alist = ei->list[EIGRP_FILTER_IN];
 | 
						|
 | 
						|
				/* Check if access-list fits */
 | 
						|
				if (alist
 | 
						|
				    && access_list_apply(
 | 
						|
					       alist,
 | 
						|
					       (struct prefix *)&dest_addr)
 | 
						|
					       == FILTER_DENY) {
 | 
						|
					/* If yes, set reported metric to Max */
 | 
						|
					ne->reported_metric.delay =
 | 
						|
						EIGRP_MAX_METRIC;
 | 
						|
				}
 | 
						|
 | 
						|
				plist = ei->prefix[EIGRP_FILTER_IN];
 | 
						|
 | 
						|
				/* Check if prefix-list fits */
 | 
						|
				if (plist
 | 
						|
				    && prefix_list_apply(
 | 
						|
					       plist,
 | 
						|
					       (struct prefix *)&dest_addr)
 | 
						|
					       == PREFIX_DENY) {
 | 
						|
					/* If yes, set reported metric to Max */
 | 
						|
					ne->reported_metric.delay =
 | 
						|
						EIGRP_MAX_METRIC;
 | 
						|
				}
 | 
						|
				/*
 | 
						|
				 * End of filtering
 | 
						|
				 */
 | 
						|
 | 
						|
				ne->distance = eigrp_calculate_total_metrics(
 | 
						|
					eigrp, ne);
 | 
						|
 | 
						|
				pe->fdistance = pe->distance = pe->rdistance =
 | 
						|
					ne->distance;
 | 
						|
				ne->prefix = pe;
 | 
						|
				ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
 | 
						|
 | 
						|
				eigrp_prefix_entry_add(eigrp->topology_table,
 | 
						|
						       pe);
 | 
						|
				eigrp_neighbor_entry_add(pe, ne);
 | 
						|
				pe->distance = pe->fdistance = pe->rdistance =
 | 
						|
					ne->distance;
 | 
						|
				pe->reported_metric = ne->total_metric;
 | 
						|
				eigrp_topology_update_node_flags(pe);
 | 
						|
 | 
						|
				pe->req_action |= EIGRP_FSM_NEED_UPDATE;
 | 
						|
				listnode_add(
 | 
						|
					eigrp->topology_changes_internalIPV4,
 | 
						|
					pe);
 | 
						|
			}
 | 
						|
			eigrp_IPv4_InternalTLV_free(tlv);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* ask about prefixes not present in GR update,
 | 
						|
	 * if this is final GR packet */
 | 
						|
	if (graceful_restart_final) {
 | 
						|
		eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes);
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * We don't need to send separate Ack for INIT Update. INIT will be
 | 
						|
	 * acked in EOT Update.
 | 
						|
	 */
 | 
						|
	if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG)) {
 | 
						|
		eigrp_hello_send_ack(nbr);
 | 
						|
	}
 | 
						|
 | 
						|
	eigrp_query_send_all(eigrp);
 | 
						|
	eigrp_update_send_all(eigrp, ei);
 | 
						|
}
 | 
						|
 | 
						|
/*send EIGRP Update packet*/
 | 
						|
void eigrp_update_send_init(struct eigrp_neighbor *nbr)
 | 
						|
{
 | 
						|
	struct eigrp_packet *ep;
 | 
						|
	u_int16_t length = EIGRP_HEADER_LEN;
 | 
						|
 | 
						|
	ep = eigrp_packet_new(nbr->ei->ifp->mtu);
 | 
						|
 | 
						|
	/* Prepare EIGRP INIT UPDATE header */
 | 
						|
	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
 | 
						|
		zlog_debug("Enqueuing Update Init Seq [%u] Ack [%u]",
 | 
						|
			   nbr->ei->eigrp->sequence_number,
 | 
						|
			   nbr->recv_sequence_number);
 | 
						|
 | 
						|
	eigrp_packet_header_init(
 | 
						|
		EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_INIT_FLAG,
 | 
						|
		nbr->ei->eigrp->sequence_number, nbr->recv_sequence_number);
 | 
						|
 | 
						|
	// encode Authentication TLV, if needed
 | 
						|
	if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
 | 
						|
	    && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei);
 | 
						|
		eigrp_make_md5_digest(nbr->ei, ep->s,
 | 
						|
				      EIGRP_AUTH_UPDATE_INIT_FLAG);
 | 
						|
	}
 | 
						|
 | 
						|
	/* EIGRP Checksum */
 | 
						|
	eigrp_packet_checksum(nbr->ei, ep->s, length);
 | 
						|
 | 
						|
	ep->length = length;
 | 
						|
	ep->dst.s_addr = nbr->src.s_addr;
 | 
						|
 | 
						|
	/*This ack number we await from neighbor*/
 | 
						|
	nbr->init_sequence_number = nbr->ei->eigrp->sequence_number;
 | 
						|
	ep->sequence_number = nbr->ei->eigrp->sequence_number;
 | 
						|
	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
 | 
						|
		zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
 | 
						|
			   ep->length, ep->sequence_number, inet_ntoa(ep->dst));
 | 
						|
 | 
						|
	/*Put packet to retransmission queue*/
 | 
						|
	eigrp_fifo_push_head(nbr->retrans_queue, ep);
 | 
						|
 | 
						|
	if (nbr->retrans_queue->count == 1) {
 | 
						|
		eigrp_send_packet_reliably(nbr);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void eigrp_update_place_on_nbr_queue(struct eigrp_neighbor *nbr,
 | 
						|
					    struct eigrp_packet *ep,
 | 
						|
					    u_int32_t seq_no,
 | 
						|
					    int length)
 | 
						|
{
 | 
						|
	if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
 | 
						|
	   (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
 | 
						|
	}
 | 
						|
 | 
						|
	/* EIGRP Checksum */
 | 
						|
	eigrp_packet_checksum(nbr->ei, ep->s, length);
 | 
						|
 | 
						|
	ep->length = length;
 | 
						|
	ep->dst.s_addr = nbr->src.s_addr;
 | 
						|
 | 
						|
	/*This ack number we await from neighbor*/
 | 
						|
	ep->sequence_number = seq_no;
 | 
						|
 | 
						|
	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
 | 
						|
		zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
 | 
						|
			   ep->length, ep->sequence_number, inet_ntoa(ep->dst));
 | 
						|
 | 
						|
	/*Put packet to retransmission queue*/
 | 
						|
	eigrp_fifo_push_head(nbr->retrans_queue, ep);
 | 
						|
}
 | 
						|
 | 
						|
void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
 | 
						|
{
 | 
						|
	struct eigrp_packet *ep;
 | 
						|
	u_int16_t length = EIGRP_HEADER_LEN;
 | 
						|
	struct eigrp_neighbor_entry *te;
 | 
						|
	struct eigrp_prefix_entry *pe;
 | 
						|
	struct listnode *node, *node2, *nnode, *nnode2;
 | 
						|
	struct access_list *alist;
 | 
						|
	struct prefix_list *plist;
 | 
						|
	struct access_list *alist_i;
 | 
						|
	struct prefix_list *plist_i;
 | 
						|
	struct eigrp *e;
 | 
						|
	struct prefix_ipv4 *dest_addr;
 | 
						|
	u_int32_t seq_no = nbr->ei->eigrp->sequence_number;
 | 
						|
 | 
						|
	ep = eigrp_packet_new(nbr->ei->ifp->mtu);
 | 
						|
 | 
						|
	/* Prepare EIGRP EOT UPDATE header */
 | 
						|
	eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
 | 
						|
				 seq_no,
 | 
						|
				 nbr->recv_sequence_number);
 | 
						|
 | 
						|
	// encode Authentication TLV, if needed
 | 
						|
	if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
 | 
						|
	   (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
 | 
						|
	}
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) {
 | 
						|
		for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) {
 | 
						|
			if ((te->ei == nbr->ei)
 | 
						|
			    && (te->prefix->nt == EIGRP_TOPOLOGY_TYPE_REMOTE))
 | 
						|
				continue;
 | 
						|
 | 
						|
			if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) {
 | 
						|
				eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
 | 
						|
				eigrp_send_packet_reliably(nbr);
 | 
						|
				seq_no++;
 | 
						|
 | 
						|
				length = EIGRP_HEADER_LEN;
 | 
						|
				ep = eigrp_packet_new(nbr->ei->ifp->mtu);
 | 
						|
				eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, EIGRP_EOT_FLAG,
 | 
						|
							 seq_no, nbr->recv_sequence_number);
 | 
						|
 | 
						|
				if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
 | 
						|
				   (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
 | 
						|
				{
 | 
						|
					length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			/* Get destination address from prefix */
 | 
						|
			dest_addr = pe->destination_ipv4;
 | 
						|
 | 
						|
			/*
 | 
						|
			 * Filtering
 | 
						|
			 */
 | 
						|
			//TODO: Work in progress
 | 
						|
			/* get list from eigrp process */
 | 
						|
			e = eigrp_lookup();
 | 
						|
			/* Get access-lists and prefix-lists from process and interface */
 | 
						|
			alist = e->list[EIGRP_FILTER_OUT];
 | 
						|
			plist = e->prefix[EIGRP_FILTER_OUT];
 | 
						|
			alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
 | 
						|
			plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
 | 
						|
 | 
						|
			/* Check if any list fits */
 | 
						|
			if ((alist
 | 
						|
			     && access_list_apply (alist,
 | 
						|
						   (struct prefix *) dest_addr) == FILTER_DENY)||
 | 
						|
			    (plist && prefix_list_apply (plist,
 | 
						|
							 (struct prefix *) dest_addr) == PREFIX_DENY)||
 | 
						|
			    (alist_i && access_list_apply (alist_i,
 | 
						|
							   (struct prefix *) dest_addr) == FILTER_DENY)||
 | 
						|
			    (plist_i && prefix_list_apply (plist_i,
 | 
						|
							   (struct prefix *) dest_addr) == PREFIX_DENY)) {
 | 
						|
				//pe->reported_metric.delay = EIGRP_MAX_METRIC;
 | 
						|
				continue;
 | 
						|
			} else {
 | 
						|
				length += eigrp_add_internalTLV_to_stream(ep->s, pe);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
 | 
						|
	eigrp_send_packet_reliably(nbr);
 | 
						|
}
 | 
						|
 | 
						|
void eigrp_update_send(struct eigrp_interface *ei)
 | 
						|
{
 | 
						|
	struct eigrp_packet *ep;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct eigrp_neighbor *nbr;
 | 
						|
	struct eigrp_prefix_entry *pe;
 | 
						|
	u_char has_tlv;
 | 
						|
	struct access_list *alist;
 | 
						|
	struct prefix_list *plist;
 | 
						|
	struct access_list *alist_i;
 | 
						|
	struct prefix_list *plist_i;
 | 
						|
	struct eigrp *e;
 | 
						|
	struct prefix_ipv4 *dest_addr;
 | 
						|
	bool packet_sent = false;
 | 
						|
 | 
						|
	u_int16_t length = EIGRP_HEADER_LEN;
 | 
						|
 | 
						|
	ep = eigrp_packet_new(ei->ifp->mtu);
 | 
						|
 | 
						|
	/* Prepare EIGRP INIT UPDATE header */
 | 
						|
	eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei, ep->s, 0,
 | 
						|
				 ei->eigrp->sequence_number, 0);
 | 
						|
 | 
						|
	// encode Authentication TLV, if needed
 | 
						|
	if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
 | 
						|
	    && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei);
 | 
						|
	}
 | 
						|
 | 
						|
	has_tlv = 0;
 | 
						|
	for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node,
 | 
						|
			       nnode, pe)) {
 | 
						|
		if (pe->req_action & EIGRP_FSM_NEED_UPDATE) {
 | 
						|
			/* Get destination address from prefix */
 | 
						|
			dest_addr = pe->destination_ipv4;
 | 
						|
 | 
						|
			/*
 | 
						|
			 * Filtering
 | 
						|
			 */
 | 
						|
			// TODO: Work in progress
 | 
						|
			/* get list from eigrp process */
 | 
						|
			e = eigrp_lookup();
 | 
						|
			/* Get access-lists and prefix-lists from process and
 | 
						|
			 * interface */
 | 
						|
			alist = e->list[EIGRP_FILTER_OUT];
 | 
						|
			plist = e->prefix[EIGRP_FILTER_OUT];
 | 
						|
			alist_i = ei->list[EIGRP_FILTER_OUT];
 | 
						|
			plist_i = ei->prefix[EIGRP_FILTER_OUT];
 | 
						|
 | 
						|
			/* Check if any list fits */
 | 
						|
			if ((alist
 | 
						|
			     && access_list_apply(alist,
 | 
						|
						  (struct prefix *)dest_addr)
 | 
						|
					== FILTER_DENY)
 | 
						|
			    || (plist
 | 
						|
				&& prefix_list_apply(plist,
 | 
						|
						     (struct prefix *)dest_addr)
 | 
						|
					   == PREFIX_DENY)
 | 
						|
			    || (alist_i
 | 
						|
				&& access_list_apply(alist_i,
 | 
						|
						     (struct prefix *)dest_addr)
 | 
						|
					   == FILTER_DENY)
 | 
						|
			    || (plist_i
 | 
						|
				&& prefix_list_apply(plist_i,
 | 
						|
						     (struct prefix *)dest_addr)
 | 
						|
					   == PREFIX_DENY)) {
 | 
						|
				zlog_info("PROC OUT: Skipping");
 | 
						|
				// pe->reported_metric.delay = EIGRP_MAX_METRIC;
 | 
						|
				zlog_info("PROC OUT Prefix: %s",
 | 
						|
					  inet_ntoa(dest_addr->prefix));
 | 
						|
				continue;
 | 
						|
			} else {
 | 
						|
				zlog_info("PROC OUT: NENastavujem metriku ");
 | 
						|
				length += eigrp_add_internalTLV_to_stream(ep->s,
 | 
						|
									  pe);
 | 
						|
				has_tlv = 1;
 | 
						|
			}
 | 
						|
			/*
 | 
						|
			 * End of filtering
 | 
						|
			 */
 | 
						|
 | 
						|
			/* NULL the pointer */
 | 
						|
			dest_addr = NULL;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!has_tlv) {
 | 
						|
		eigrp_packet_free(ep);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
 | 
						|
	    && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
 | 
						|
	}
 | 
						|
 | 
						|
	/* EIGRP Checksum */
 | 
						|
	eigrp_packet_checksum(ei, ep->s, length);
 | 
						|
	ep->length = length;
 | 
						|
 | 
						|
	ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
 | 
						|
 | 
						|
	/*This ack number we await from neighbor*/
 | 
						|
	ep->sequence_number = ei->eigrp->sequence_number;
 | 
						|
 | 
						|
	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
 | 
						|
		zlog_debug("Enqueuing Update length[%u] Seq [%u]", length,
 | 
						|
			   ep->sequence_number);
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) {
 | 
						|
		if (nbr->state == EIGRP_NEIGHBOR_UP) {
 | 
						|
			packet_sent = true;
 | 
						|
			/*Put packet to retransmission queue*/
 | 
						|
			eigrp_fifo_push_head(nbr->retrans_queue, ep);
 | 
						|
 | 
						|
			if (nbr->retrans_queue->count == 1) {
 | 
						|
				eigrp_send_packet_reliably(nbr);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!packet_sent)
 | 
						|
		eigrp_packet_free(ep);
 | 
						|
}
 | 
						|
 | 
						|
void eigrp_update_send_all(struct eigrp *eigrp,
 | 
						|
			   struct eigrp_interface *exception)
 | 
						|
{
 | 
						|
	struct eigrp_interface *iface;
 | 
						|
	struct listnode *node, *node2, *nnode2;
 | 
						|
	struct eigrp_prefix_entry *pe;
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
 | 
						|
		if (iface != exception) {
 | 
						|
			eigrp_update_send(iface);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2,
 | 
						|
			       nnode2, pe)) {
 | 
						|
		if (pe->req_action & EIGRP_FSM_NEED_UPDATE) {
 | 
						|
			pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
 | 
						|
			listnode_delete(eigrp->topology_changes_internalIPV4,
 | 
						|
					pe);
 | 
						|
			zlog_debug("UPDATE COUNT: %d",
 | 
						|
				   eigrp->topology_changes_internalIPV4->count);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn eigrp_update_send_GR_part
 | 
						|
 *
 | 
						|
 * @param[in]		nbr		contains neighbor who would receive Graceful
 | 
						|
 * restart
 | 
						|
 *
 | 
						|
 * @return void
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function used for sending Graceful restart Update packet
 | 
						|
 * and if there are multiple chunks, send only one of them.
 | 
						|
 * It is called from thread. Do not call it directly.
 | 
						|
 *
 | 
						|
 * Uses nbr_gr_packet_type from neighbor.
 | 
						|
 */
 | 
						|
static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
 | 
						|
{
 | 
						|
	struct eigrp_packet *ep;
 | 
						|
	u_int16_t length = EIGRP_HEADER_LEN;
 | 
						|
	struct listnode *node, *nnode;
 | 
						|
	struct eigrp_prefix_entry *pe;
 | 
						|
	struct prefix_ipv4 *dest_addr;
 | 
						|
	struct eigrp *e;
 | 
						|
	struct access_list *alist, *alist_i;
 | 
						|
	struct prefix_list *plist, *plist_i;
 | 
						|
	struct list *prefixes;
 | 
						|
	u_int32_t flags;
 | 
						|
	unsigned int send_prefixes;
 | 
						|
	struct TLV_IPv4_Internal_type *tlv_max;
 | 
						|
 | 
						|
	/* get prefixes to send to neighbor */
 | 
						|
	prefixes = nbr->nbr_gr_prefixes_send;
 | 
						|
 | 
						|
	send_prefixes = 0;
 | 
						|
	length = EIGRP_HEADER_LEN;
 | 
						|
 | 
						|
	/* if there already were last packet chunk, we won't continue */
 | 
						|
	if (nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST)
 | 
						|
		return;
 | 
						|
 | 
						|
	/* if this is first packet chunk, we need to decide,
 | 
						|
	 * if there will be one or more chunks */
 | 
						|
	if (nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_FIRST) {
 | 
						|
		if (prefixes->count <= EIGRP_TLV_MAX_IPv4) {
 | 
						|
			/* there will be only one chunk */
 | 
						|
			flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG
 | 
						|
				+ EIGRP_EOT_FLAG;
 | 
						|
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
 | 
						|
		} else {
 | 
						|
			/* there will be more chunks */
 | 
						|
			flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG;
 | 
						|
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		/* this is not first chunk, and we need to decide,
 | 
						|
		 * if there will be more chunks */
 | 
						|
		if (prefixes->count <= EIGRP_TLV_MAX_IPv4) {
 | 
						|
			/* this is last chunk */
 | 
						|
			flags = EIGRP_EOT_FLAG;
 | 
						|
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
 | 
						|
		} else {
 | 
						|
			/* there will be more chunks */
 | 
						|
			flags = 0;
 | 
						|
			nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	ep = eigrp_packet_new(nbr->ei->ifp->mtu);
 | 
						|
 | 
						|
	/* Prepare EIGRP Graceful restart UPDATE header */
 | 
						|
	eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei, ep->s, flags,
 | 
						|
				 nbr->ei->eigrp->sequence_number,
 | 
						|
				 nbr->recv_sequence_number);
 | 
						|
 | 
						|
	// encode Authentication TLV, if needed
 | 
						|
	if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
 | 
						|
	    && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei);
 | 
						|
	}
 | 
						|
 | 
						|
	for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode,
 | 
						|
			       pe)) {
 | 
						|
		/*
 | 
						|
		 * Filtering
 | 
						|
		 */
 | 
						|
		dest_addr = pe->destination_ipv4;
 | 
						|
		/* get list from eigrp process */
 | 
						|
		e = eigrp_lookup();
 | 
						|
		/* Get access-lists and prefix-lists from process and interface
 | 
						|
		 */
 | 
						|
		alist = e->list[EIGRP_FILTER_OUT];
 | 
						|
		plist = e->prefix[EIGRP_FILTER_OUT];
 | 
						|
		alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
 | 
						|
		plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
 | 
						|
 | 
						|
		/* Check if any list fits */
 | 
						|
		if ((alist
 | 
						|
		     && access_list_apply(alist, (struct prefix *)dest_addr)
 | 
						|
				== FILTER_DENY)
 | 
						|
		    || (plist
 | 
						|
			&& prefix_list_apply(plist, (struct prefix *)dest_addr)
 | 
						|
				   == PREFIX_DENY)
 | 
						|
		    || (alist_i
 | 
						|
			&& access_list_apply(alist_i,
 | 
						|
					     (struct prefix *)dest_addr)
 | 
						|
				   == FILTER_DENY)
 | 
						|
		    || (plist_i
 | 
						|
			&& prefix_list_apply(plist_i,
 | 
						|
					     (struct prefix *)dest_addr)
 | 
						|
				   == PREFIX_DENY)) {
 | 
						|
			/* do not send filtered route */
 | 
						|
			zlog_info("Filtered prefix %s won't be sent out.",
 | 
						|
				  inet_ntoa(dest_addr->prefix));
 | 
						|
		} else {
 | 
						|
			/* sending route which wasn't filtered */
 | 
						|
			length += eigrp_add_internalTLV_to_stream(ep->s, pe);
 | 
						|
			send_prefixes++;
 | 
						|
		}
 | 
						|
 | 
						|
		alist = e->list[EIGRP_FILTER_IN];
 | 
						|
		plist = e->prefix[EIGRP_FILTER_IN];
 | 
						|
		alist_i = nbr->ei->list[EIGRP_FILTER_IN];
 | 
						|
		plist_i = nbr->ei->prefix[EIGRP_FILTER_IN];
 | 
						|
 | 
						|
		/* Check if any list fits */
 | 
						|
		if ((alist
 | 
						|
		     && access_list_apply(alist, (struct prefix *)dest_addr)
 | 
						|
				== FILTER_DENY)
 | 
						|
		    || (plist
 | 
						|
			&& prefix_list_apply(plist, (struct prefix *)dest_addr)
 | 
						|
				   == PREFIX_DENY)
 | 
						|
		    || (alist_i
 | 
						|
			&& access_list_apply(alist_i,
 | 
						|
					     (struct prefix *)dest_addr)
 | 
						|
				   == FILTER_DENY)
 | 
						|
		    || (plist_i
 | 
						|
			&& prefix_list_apply(plist_i,
 | 
						|
					     (struct prefix *)dest_addr)
 | 
						|
				   == PREFIX_DENY)) {
 | 
						|
			/* do not send filtered route */
 | 
						|
			zlog_info("Filtered prefix %s will be removed.",
 | 
						|
				  inet_ntoa(dest_addr->prefix));
 | 
						|
 | 
						|
			tlv_max = eigrp_IPv4_InternalTLV_new();
 | 
						|
			tlv_max->type = EIGRP_TLV_IPv4_INT;
 | 
						|
			tlv_max->length = 28U;
 | 
						|
			tlv_max->metric = pe->reported_metric;
 | 
						|
			/* set delay to MAX */
 | 
						|
			tlv_max->metric.delay = EIGRP_MAX_METRIC;
 | 
						|
			tlv_max->destination = pe->destination_ipv4->prefix;
 | 
						|
			tlv_max->prefix_length =
 | 
						|
				pe->destination_ipv4->prefixlen;
 | 
						|
 | 
						|
			/* prepare message for FSM */
 | 
						|
			struct eigrp_fsm_action_message *fsm_msg;
 | 
						|
			fsm_msg = XCALLOC(
 | 
						|
				MTYPE_EIGRP_FSM_MSG,
 | 
						|
				sizeof(struct eigrp_fsm_action_message));
 | 
						|
 | 
						|
			struct eigrp_neighbor_entry *entry =
 | 
						|
				eigrp_prefix_entry_lookup(pe->entries, nbr);
 | 
						|
 | 
						|
			fsm_msg->packet_type = EIGRP_OPC_UPDATE;
 | 
						|
			fsm_msg->eigrp = e;
 | 
						|
			fsm_msg->data_type = EIGRP_TLV_IPv4_INT;
 | 
						|
			fsm_msg->adv_router = nbr;
 | 
						|
			fsm_msg->data.ipv4_int_type = tlv_max;
 | 
						|
			fsm_msg->entry = entry;
 | 
						|
			fsm_msg->prefix = pe;
 | 
						|
 | 
						|
			/* send message to FSM */
 | 
						|
			int event = eigrp_get_fsm_event(fsm_msg);
 | 
						|
			eigrp_fsm_event(fsm_msg, event);
 | 
						|
 | 
						|
			/* free memory used by TLV */
 | 
						|
			eigrp_IPv4_InternalTLV_free(tlv_max);
 | 
						|
		}
 | 
						|
		/*
 | 
						|
		 * End of filtering
 | 
						|
		 */
 | 
						|
 | 
						|
		/* NULL the pointer */
 | 
						|
		dest_addr = NULL;
 | 
						|
 | 
						|
		/* delete processed prefix from list */
 | 
						|
		listnode_delete(prefixes, pe);
 | 
						|
 | 
						|
		/* if there are enough prefixes, send packet */
 | 
						|
		if (send_prefixes >= EIGRP_TLV_MAX_IPv4)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* compute Auth digest */
 | 
						|
	if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
 | 
						|
	    && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
 | 
						|
		eigrp_make_md5_digest(nbr->ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
 | 
						|
	}
 | 
						|
 | 
						|
	/* EIGRP Checksum */
 | 
						|
	eigrp_packet_checksum(nbr->ei, ep->s, length);
 | 
						|
 | 
						|
	ep->length = length;
 | 
						|
	ep->dst.s_addr = nbr->src.s_addr;
 | 
						|
 | 
						|
	/*This ack number we await from neighbor*/
 | 
						|
	ep->sequence_number = nbr->ei->eigrp->sequence_number;
 | 
						|
 | 
						|
	if (IS_DEBUG_EIGRP_PACKET(0, RECV))
 | 
						|
		zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
 | 
						|
			   ep->length, ep->sequence_number, inet_ntoa(ep->dst));
 | 
						|
 | 
						|
	/*Put packet to retransmission queue*/
 | 
						|
	eigrp_fifo_push_head(nbr->retrans_queue, ep);
 | 
						|
 | 
						|
	if (nbr->retrans_queue->count == 1) {
 | 
						|
		eigrp_send_packet_reliably(nbr);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn eigrp_update_send_GR_thread
 | 
						|
 *
 | 
						|
 * @param[in]		thread		contains neighbor who would receive
 | 
						|
 * Graceful restart
 | 
						|
 *
 | 
						|
 * @return int      always 0
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function used for sending Graceful restart Update packet
 | 
						|
 * in thread, it is prepared for multiple chunks of packet.
 | 
						|
 *
 | 
						|
 * Uses nbr_gr_packet_type and t_nbr_send_gr from neighbor.
 | 
						|
 */
 | 
						|
int eigrp_update_send_GR_thread(struct thread *thread)
 | 
						|
{
 | 
						|
	struct eigrp_neighbor *nbr;
 | 
						|
 | 
						|
	/* get argument from thread */
 | 
						|
	nbr = THREAD_ARG(thread);
 | 
						|
	/* remove this thread pointer */
 | 
						|
	nbr->t_nbr_send_gr = NULL;
 | 
						|
 | 
						|
	/* if there is packet waiting in queue,
 | 
						|
	 * schedule this thread again with small delay */
 | 
						|
	if (nbr->retrans_queue->count > 0) {
 | 
						|
		nbr->t_nbr_send_gr = NULL;
 | 
						|
		thread_add_timer_msec(master, eigrp_update_send_GR_thread, nbr,
 | 
						|
				      10, &nbr->t_nbr_send_gr);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
 | 
						|
	/* send GR EIGRP packet chunk */
 | 
						|
	eigrp_update_send_GR_part(nbr);
 | 
						|
 | 
						|
	/* if it wasn't last chunk, schedule this thread again */
 | 
						|
	if (nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST) {
 | 
						|
		thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
 | 
						|
		nbr->t_nbr_send_gr = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn eigrp_update_send_GR
 | 
						|
 *
 | 
						|
 * @param[in]		nbr			Neighbor who would receive Graceful
 | 
						|
 * restart
 | 
						|
 * @param[in]		gr_type 	Who executed Graceful restart
 | 
						|
 * @param[in]		vty 		Virtual terminal for log output
 | 
						|
 *
 | 
						|
 * @return void
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function used for sending Graceful restart Update packet:
 | 
						|
 * Creates Update packet with INIT, RS, EOT flags and include
 | 
						|
 * all route except those filtered
 | 
						|
 */
 | 
						|
void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
 | 
						|
			  struct vty *vty)
 | 
						|
{
 | 
						|
	struct eigrp_prefix_entry *pe2;
 | 
						|
	struct listnode *node2, *nnode2;
 | 
						|
	struct list *prefixes;
 | 
						|
 | 
						|
	if (gr_type == EIGRP_GR_FILTER) {
 | 
						|
		/* function was called after applying filtration */
 | 
						|
		zlog_info(
 | 
						|
			"Neighbor %s (%s) is resync: route configuration changed",
 | 
						|
			inet_ntoa(nbr->src),
 | 
						|
			ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
 | 
						|
	} else if (gr_type == EIGRP_GR_MANUAL) {
 | 
						|
		/* Graceful restart was called manually */
 | 
						|
		zlog_info("Neighbor %s (%s) is resync: manually cleared",
 | 
						|
			  inet_ntoa(nbr->src),
 | 
						|
			  ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
 | 
						|
 | 
						|
		if (vty != NULL) {
 | 
						|
			vty_time_print(vty, 0);
 | 
						|
			vty_out(vty,
 | 
						|
				"Neighbor %s (%s) is resync: manually cleared\n",
 | 
						|
				inet_ntoa(nbr->src),
 | 
						|
				ifindex2ifname(nbr->ei->ifp->ifindex,
 | 
						|
					       VRF_DEFAULT));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	prefixes = list_new();
 | 
						|
	/* add all prefixes from topology table to list */
 | 
						|
	for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node2, nnode2,
 | 
						|
			       pe2)) {
 | 
						|
		listnode_add(prefixes, pe2);
 | 
						|
	}
 | 
						|
 | 
						|
	/* save prefixes to neighbor */
 | 
						|
	nbr->nbr_gr_prefixes_send = prefixes;
 | 
						|
	/* indicate, that this is first GR Update packet chunk */
 | 
						|
	nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
 | 
						|
	/* execute packet sending in thread */
 | 
						|
	thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
 | 
						|
	nbr->t_nbr_send_gr = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn eigrp_update_send_interface_GR
 | 
						|
 *
 | 
						|
 * @param[in]		ei			Interface to neighbors of which the GR
 | 
						|
 * is sent
 | 
						|
 * @param[in]		gr_type 	Who executed Graceful restart
 | 
						|
 * @param[in]		vty 		Virtual terminal for log output
 | 
						|
 *
 | 
						|
 * @return void
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function used for sending Graceful restart Update packet
 | 
						|
 * to all neighbors on specified interface.
 | 
						|
 */
 | 
						|
void eigrp_update_send_interface_GR(struct eigrp_interface *ei,
 | 
						|
				    enum GR_type gr_type, struct vty *vty)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct eigrp_neighbor *nbr;
 | 
						|
 | 
						|
	/* iterate over all neighbors on eigrp interface */
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(ei->nbrs, node, nbr)) {
 | 
						|
		/* send GR to neighbor */
 | 
						|
		eigrp_update_send_GR(nbr, gr_type, vty);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * @fn eigrp_update_send_process_GR
 | 
						|
 *
 | 
						|
 * @param[in]		eigrp		EIGRP process
 | 
						|
 * @param[in]		gr_type 	Who executed Graceful restart
 | 
						|
 * @param[in]		vty 		Virtual terminal for log output
 | 
						|
 *
 | 
						|
 * @return void
 | 
						|
 *
 | 
						|
 * @par
 | 
						|
 * Function used for sending Graceful restart Update packet
 | 
						|
 * to all neighbors in eigrp process.
 | 
						|
 */
 | 
						|
void eigrp_update_send_process_GR(struct eigrp *eigrp, enum GR_type gr_type,
 | 
						|
				  struct vty *vty)
 | 
						|
{
 | 
						|
	struct listnode *node;
 | 
						|
	struct eigrp_interface *ei;
 | 
						|
 | 
						|
	/* iterate over all eigrp interfaces */
 | 
						|
	for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
 | 
						|
		/* send GR to all neighbors on interface */
 | 
						|
		eigrp_update_send_interface_GR(ei, gr_type, vty);
 | 
						|
	}
 | 
						|
}
 |