mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 13:03:19 +00:00 
			
		
		
		
	 acddc0ed3c
			
		
	
	
		acddc0ed3c
		
	
	
	
	
		
			
			Done with a combination of regex'ing and banging my head against a wall. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
		
			
				
	
	
		
			629 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			629 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * EIGRPd Finite State Machine (DUAL).
 | |
|  * Copyright (C) 2013-2014
 | |
|  * Authors:
 | |
|  *   Donnie Savage
 | |
|  *   Jan Janovic
 | |
|  *   Matej Perina
 | |
|  *   Peter Orsag
 | |
|  *   Peter Paluch
 | |
|  *
 | |
|  * This file contains functions for executing logic of finite state machine
 | |
|  *
 | |
|  *                                +------------ +
 | |
|  *                                |     (7)     |
 | |
|  *                                |             v
 | |
|  *                    +=====================================+
 | |
|  *                    |                                     |
 | |
|  *                    |              Passive                |
 | |
|  *                    |                                     |
 | |
|  *                    +=====================================+
 | |
|  *                        ^     |     ^     ^     ^    |
 | |
|  *                     (3)|     |  (1)|     |  (1)|    |
 | |
|  *                        |  (0)|     |  (3)|     | (2)|
 | |
|  *                        |     |     |     |     |    +---------------+
 | |
|  *                        |     |     |     |     |                     \
 | |
|  *              +--------+      |     |     |     +-----------------+    \
 | |
|  *            /                /     /      |                        \    \
 | |
|  *          /                /     /        +----+                    \    \
 | |
|  *         |                |     |               |                    |    |
 | |
|  *         |                v     |               |                    |    v
 | |
|  *    +===========+   (6)  +===========+       +===========+   (6) +===========+
 | |
|  *    |           |------->|           |  (5)  |           |-------->| |
 | |
|  *    |           |   (4)  |           |------>|           |   (4)   | |
 | |
|  *    | ACTIVE 0  |<-------| ACTIVE 1  |       | ACTIVE 2  |<--------| ACTIVE 3
 | |
|  * |
 | |
|  * +--|           |     +--|           |    +--|           |      +--| |
 | |
|  * |  +===========+     |  +===========+    |  +===========+      |
 | |
|  * +===========+
 | |
|  * |       ^  |(5)      |      ^            |    ^    ^           |         ^
 | |
|  * |       |  +---------|------|------------|----+    |           |         |
 | |
|  * +-------+            +------+            +---------+           +---------+
 | |
|  *    (7)                 (7)                  (7)                   (7)
 | |
|  *
 | |
|  * 0- input event other than query from successor, FC not satisfied
 | |
|  * 1- last reply, FD is reset
 | |
|  * 2- query from successor, FC not satisfied
 | |
|  * 3- last reply, FC satisfied with current value of FDij
 | |
|  * 4- distance increase while in active state
 | |
|  * 5- query from successor while in active state
 | |
|  * 6- last reply, FC not satisfied with current value of FDij
 | |
|  * 7- state not changed, usually by receiving not last reply
 | |
|  */
 | |
| 
 | |
| #include <zebra.h>
 | |
| #include <thread.h>
 | |
| 
 | |
| #include "prefix.h"
 | |
| #include "table.h"
 | |
| #include "memory.h"
 | |
| #include "log.h"
 | |
| #include "linklist.h"
 | |
| #include "vty.h"
 | |
| 
 | |
| #include "eigrpd/eigrp_types.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"
 | |
| #include "eigrpd/eigrp_dump.h"
 | |
| #include "eigrpd/eigrp_topology.h"
 | |
| #include "eigrpd/eigrp_fsm.h"
 | |
| #include "eigrpd/eigrp_metric.h"
 | |
| 
 | |
| /*
 | |
|  * Prototypes
 | |
|  */
 | |
| int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *);
 | |
| int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *);
 | |
| 
 | |
| //---------------------------------------------------------------------
 | |
| 
 | |
| /*
 | |
|  * NSM - field of fields of struct containing one function each.
 | |
|  * Which function is used depends on actual state of FSM and occurred
 | |
|  * event(arrow in diagram). Usage:
 | |
|  * NSM[actual/starting state][occurred event].func
 | |
|  * Functions are should be executed within separate thread.
 | |
|  */
 | |
| const struct {
 | |
| 	int (*func)(struct eigrp_fsm_action_message *);
 | |
| } NSM[EIGRP_FSM_STATE_MAX][EIGRP_FSM_EVENT_MAX] = {
 | |
| 	{
 | |
| 		// PASSIVE STATE
 | |
| 		{eigrp_fsm_event_nq_fcn},     /* Event 0 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 1 */
 | |
| 		{eigrp_fsm_event_q_fcn},      /* Event 2 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 3 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 4 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 5 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 6 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 7 */
 | |
| 	},
 | |
| 	{
 | |
| 		// Active 0 state
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 0 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 1 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 2 */
 | |
| 		{eigrp_fsm_event_lr_fcs},     /* Event 3 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 4 */
 | |
| 		{eigrp_fsm_event_qact},       /* Event 5 */
 | |
| 		{eigrp_fsm_event_lr_fcn},     /* Event 6 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 7 */
 | |
| 	},
 | |
| 	{
 | |
| 		// Active 1 state
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 0 */
 | |
| 		{eigrp_fsm_event_lr},	 /* Event 1 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 2 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 3 */
 | |
| 		{eigrp_fsm_event_dinc},       /* Event 4 */
 | |
| 		{eigrp_fsm_event_qact},       /* Event 5 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 6 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 7 */
 | |
| 	},
 | |
| 	{
 | |
| 		// Active 2 state
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 0 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 1 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 2 */
 | |
| 		{eigrp_fsm_event_lr_fcs},     /* Event 3 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 4 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 5 */
 | |
| 		{eigrp_fsm_event_lr_fcn},     /* Event 6 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 7 */
 | |
| 	},
 | |
| 	{
 | |
| 		// Active 3 state
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 0 */
 | |
| 		{eigrp_fsm_event_lr},	 /* Event 1 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 2 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 3 */
 | |
| 		{eigrp_fsm_event_dinc},       /* Event 4 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 5 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 6 */
 | |
| 		{eigrp_fsm_event_keep_state}, /* Event 7 */
 | |
| 	},
 | |
| };
 | |
| 
 | |
| static const char *packet_type2str(uint8_t packet_type)
 | |
| {
 | |
| 	if (packet_type == EIGRP_OPC_UPDATE)
 | |
| 		return "Update";
 | |
| 	if (packet_type == EIGRP_OPC_REQUEST)
 | |
| 		return "Request";
 | |
| 	if (packet_type == EIGRP_OPC_QUERY)
 | |
| 		return "Query";
 | |
| 	if (packet_type == EIGRP_OPC_REPLY)
 | |
| 		return "Reply";
 | |
| 	if (packet_type == EIGRP_OPC_HELLO)
 | |
| 		return "Hello";
 | |
| 	if (packet_type == EIGRP_OPC_IPXSAP)
 | |
| 		return "IPXSAP";
 | |
| 	if (packet_type == EIGRP_OPC_ACK)
 | |
| 		return "Ack";
 | |
| 	if (packet_type == EIGRP_OPC_SIAQUERY)
 | |
| 		return "SIA Query";
 | |
| 	if (packet_type == EIGRP_OPC_SIAREPLY)
 | |
| 		return "SIA Reply";
 | |
| 
 | |
| 	return "Unknown";
 | |
| }
 | |
| 
 | |
| static const char *prefix_state2str(enum eigrp_fsm_states state)
 | |
| {
 | |
| 	switch (state) {
 | |
| 	case EIGRP_FSM_STATE_PASSIVE:
 | |
| 		return "Passive";
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_0:
 | |
| 		return "Active oij0";
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_1:
 | |
| 		return "Active oij1";
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_2:
 | |
| 		return "Active oij2";
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_3:
 | |
| 		return "Active oij3";
 | |
| 	}
 | |
| 
 | |
| 	return "Unknown";
 | |
| }
 | |
| 
 | |
| static const char *fsm_state2str(enum eigrp_fsm_events event)
 | |
| {
 | |
| 	switch (event) {
 | |
| 	case EIGRP_FSM_KEEP_STATE:
 | |
| 		return "Keep State Event";
 | |
| 	case EIGRP_FSM_EVENT_NQ_FCN:
 | |
| 		return "Non Query Event Feasability not satisfied";
 | |
| 	case EIGRP_FSM_EVENT_LR:
 | |
| 		return "Last Reply Event";
 | |
| 	case EIGRP_FSM_EVENT_Q_FCN:
 | |
| 		return "Query Event Feasability not satisfied";
 | |
| 	case EIGRP_FSM_EVENT_LR_FCS:
 | |
| 		return "Last Reply Event Feasability satisfied";
 | |
| 	case EIGRP_FSM_EVENT_DINC:
 | |
| 		return "Distance Increase Event";
 | |
| 	case EIGRP_FSM_EVENT_QACT:
 | |
| 		return "Query from Successor while in active state";
 | |
| 	case EIGRP_FSM_EVENT_LR_FCN:
 | |
| 		return "Last Reply Event, Feasibility not satisfied";
 | |
| 	}
 | |
| 
 | |
| 	return "Unknown";
 | |
| }
 | |
| 
 | |
| static const char *change2str(enum metric_change change)
 | |
| {
 | |
| 	switch (change) {
 | |
| 	case METRIC_DECREASE:
 | |
| 		return "Decrease";
 | |
| 	case METRIC_SAME:
 | |
| 		return "Same";
 | |
| 	case METRIC_INCREASE:
 | |
| 		return "Increase";
 | |
| 	}
 | |
| 
 | |
| 	return "Unknown";
 | |
| }
 | |
| /*
 | |
|  * Main function in which are make decisions which event occurred.
 | |
|  * msg - argument of type struct eigrp_fsm_action_message contain
 | |
|  * details about what happen
 | |
|  *
 | |
|  * Return number of occurred event (arrow in diagram).
 | |
|  *
 | |
|  */
 | |
| static enum eigrp_fsm_events
 | |
| eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	// Loading base information from message
 | |
| 	// struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct eigrp_route_descriptor *entry = msg->entry;
 | |
| 	uint8_t actual_state = prefix->state;
 | |
| 	enum metric_change change;
 | |
| 
 | |
| 	if (entry == NULL) {
 | |
| 		entry = eigrp_route_descriptor_new();
 | |
| 		entry->adv_router = msg->adv_router;
 | |
| 		entry->ei = msg->adv_router->ei;
 | |
| 		entry->prefix = prefix;
 | |
| 		msg->entry = entry;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Calculate resultant metrics and insert to correct position
 | |
| 	 * in entries list
 | |
| 	 */
 | |
| 	change = eigrp_topology_update_distance(msg);
 | |
| 
 | |
| 	/* Store for display later */
 | |
| 	msg->change = change;
 | |
| 
 | |
| 	switch (actual_state) {
 | |
| 	case EIGRP_FSM_STATE_PASSIVE: {
 | |
| 		struct eigrp_route_descriptor *head =
 | |
| 			listnode_head(prefix->entries);
 | |
| 
 | |
| 		if (head->reported_distance < prefix->fdistance) {
 | |
| 			return EIGRP_FSM_KEEP_STATE;
 | |
| 		}
 | |
| 		/*
 | |
| 		 * if best entry doesn't satisfy feasibility condition it means
 | |
| 		 * move to active state
 | |
| 		 * dependently if it was query from successor
 | |
| 		 */
 | |
| 		if (msg->packet_type == EIGRP_OPC_QUERY) {
 | |
| 			return EIGRP_FSM_EVENT_Q_FCN;
 | |
| 		} else {
 | |
| 			return EIGRP_FSM_EVENT_NQ_FCN;
 | |
| 		}
 | |
| 
 | |
| 		break;
 | |
| 	}
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_0: {
 | |
| 		if (msg->packet_type == EIGRP_OPC_REPLY) {
 | |
| 			struct eigrp_route_descriptor *head =
 | |
| 				listnode_head(prefix->entries);
 | |
| 
 | |
| 			listnode_delete(prefix->rij, entry->adv_router);
 | |
| 			if (prefix->rij->count)
 | |
| 				return EIGRP_FSM_KEEP_STATE;
 | |
| 
 | |
| 			zlog_info("All reply received");
 | |
| 			if (head->reported_distance < prefix->fdistance) {
 | |
| 				return EIGRP_FSM_EVENT_LR_FCS;
 | |
| 			}
 | |
| 
 | |
| 			return EIGRP_FSM_EVENT_LR_FCN;
 | |
| 		} else if (msg->packet_type == EIGRP_OPC_QUERY
 | |
| 			   && (entry->flags
 | |
| 			       & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
 | |
| 			return EIGRP_FSM_EVENT_QACT;
 | |
| 		}
 | |
| 
 | |
| 		return EIGRP_FSM_KEEP_STATE;
 | |
| 
 | |
| 		break;
 | |
| 	}
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_1: {
 | |
| 		if (msg->packet_type == EIGRP_OPC_QUERY
 | |
| 		    && (entry->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
 | |
| 			return EIGRP_FSM_EVENT_QACT;
 | |
| 		} else if (msg->packet_type == EIGRP_OPC_REPLY) {
 | |
| 			listnode_delete(prefix->rij, entry->adv_router);
 | |
| 
 | |
| 			if (change == METRIC_INCREASE
 | |
| 			    && (entry->flags
 | |
| 				& EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
 | |
| 				return EIGRP_FSM_EVENT_DINC;
 | |
| 			} else if (prefix->rij->count) {
 | |
| 				return EIGRP_FSM_KEEP_STATE;
 | |
| 			} else {
 | |
| 				zlog_info("All reply received");
 | |
| 				return EIGRP_FSM_EVENT_LR;
 | |
| 			}
 | |
| 		} else if (msg->packet_type == EIGRP_OPC_UPDATE
 | |
| 			   && change == METRIC_INCREASE
 | |
| 			   && (entry->flags
 | |
| 			       & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
 | |
| 			return EIGRP_FSM_EVENT_DINC;
 | |
| 		}
 | |
| 		return EIGRP_FSM_KEEP_STATE;
 | |
| 
 | |
| 		break;
 | |
| 	}
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_2: {
 | |
| 		if (msg->packet_type == EIGRP_OPC_REPLY) {
 | |
| 			struct eigrp_route_descriptor *head =
 | |
| 				listnode_head(prefix->entries);
 | |
| 
 | |
| 			listnode_delete(prefix->rij, entry->adv_router);
 | |
| 			if (prefix->rij->count) {
 | |
| 				return EIGRP_FSM_KEEP_STATE;
 | |
| 			} else {
 | |
| 				zlog_info("All reply received");
 | |
| 				if (head->reported_distance
 | |
| 				    < prefix->fdistance) {
 | |
| 					return EIGRP_FSM_EVENT_LR_FCS;
 | |
| 				}
 | |
| 
 | |
| 				return EIGRP_FSM_EVENT_LR_FCN;
 | |
| 			}
 | |
| 		}
 | |
| 		return EIGRP_FSM_KEEP_STATE;
 | |
| 
 | |
| 		break;
 | |
| 	}
 | |
| 	case EIGRP_FSM_STATE_ACTIVE_3: {
 | |
| 		if (msg->packet_type == EIGRP_OPC_REPLY) {
 | |
| 			listnode_delete(prefix->rij, entry->adv_router);
 | |
| 
 | |
| 			if (change == METRIC_INCREASE
 | |
| 			    && (entry->flags
 | |
| 				& EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
 | |
| 				return EIGRP_FSM_EVENT_DINC;
 | |
| 			} else if (prefix->rij->count) {
 | |
| 				return EIGRP_FSM_KEEP_STATE;
 | |
| 			} else {
 | |
| 				zlog_info("All reply received");
 | |
| 				return EIGRP_FSM_EVENT_LR;
 | |
| 			}
 | |
| 		} else if (msg->packet_type == EIGRP_OPC_UPDATE
 | |
| 			   && change == METRIC_INCREASE
 | |
| 			   && (entry->flags
 | |
| 			       & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
 | |
| 			return EIGRP_FSM_EVENT_DINC;
 | |
| 		}
 | |
| 		return EIGRP_FSM_KEEP_STATE;
 | |
| 
 | |
| 		break;
 | |
| 	}
 | |
| 	}
 | |
| 
 | |
| 	return EIGRP_FSM_KEEP_STATE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Function made to execute in separate thread.
 | |
|  * Load argument from thread and execute proper NSM function
 | |
|  */
 | |
| int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	enum eigrp_fsm_events event = eigrp_get_fsm_event(msg);
 | |
| 
 | |
| 	zlog_info(
 | |
| 		"EIGRP AS: %d State: %s Event: %s Network: %pI4 Packet Type: %s Reply RIJ Count: %d change: %s",
 | |
| 		msg->eigrp->AS, prefix_state2str(msg->prefix->state),
 | |
| 		fsm_state2str(event), &msg->prefix->destination->u.prefix4,
 | |
| 		packet_type2str(msg->packet_type), msg->prefix->rij->count,
 | |
| 		change2str(msg->change));
 | |
| 	(*(NSM[msg->prefix->state][event].func))(msg);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Function of event 0.
 | |
|  *
 | |
|  */
 | |
| int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct list *successors = eigrp_topology_get_successor(prefix);
 | |
| 	struct eigrp_route_descriptor *ne;
 | |
| 
 | |
| 	assert(successors); // If this is NULL we have shit the bed, fun huh?
 | |
| 
 | |
| 	ne = listnode_head(successors);
 | |
| 	prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
 | |
| 	prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
 | |
| 	prefix->reported_metric = ne->total_metric;
 | |
| 
 | |
| 	if (eigrp_nbr_count_get(eigrp)) {
 | |
| 		prefix->req_action |= EIGRP_FSM_NEED_QUERY;
 | |
| 		listnode_add(eigrp->topology_changes_internalIPV4, prefix);
 | |
| 	} else {
 | |
| 		eigrp_fsm_event_lr(msg); // in the case that there are no more
 | |
| 					 // neighbors left
 | |
| 	}
 | |
| 
 | |
| 	list_delete(&successors);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct list *successors = eigrp_topology_get_successor(prefix);
 | |
| 	struct eigrp_route_descriptor *ne;
 | |
| 
 | |
| 	assert(successors); // If this is NULL somebody poked us in the eye.
 | |
| 
 | |
| 	ne = listnode_head(successors);
 | |
| 	prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
 | |
| 	prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
 | |
| 	prefix->reported_metric = ne->total_metric;
 | |
| 	if (eigrp_nbr_count_get(eigrp)) {
 | |
| 		prefix->req_action |= EIGRP_FSM_NEED_QUERY;
 | |
| 		listnode_add(eigrp->topology_changes_internalIPV4, prefix);
 | |
| 	} else {
 | |
| 		eigrp_fsm_event_lr(msg); // in the case that there are no more
 | |
| 					 // neighbors left
 | |
| 	}
 | |
| 
 | |
| 	list_delete(&successors);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 | |
| 
 | |
| 	if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
 | |
| 		if (!eigrp_metrics_is_same(prefix->reported_metric,
 | |
| 					   ne->total_metric)) {
 | |
| 			prefix->rdistance = prefix->fdistance =
 | |
| 				prefix->distance = ne->distance;
 | |
| 			prefix->reported_metric = ne->total_metric;
 | |
| 			if (msg->packet_type == EIGRP_OPC_QUERY)
 | |
| 				eigrp_send_reply(msg->adv_router, prefix);
 | |
| 			prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
 | |
| 			listnode_add(eigrp->topology_changes_internalIPV4,
 | |
| 				     prefix);
 | |
| 		}
 | |
| 		eigrp_topology_update_node_flags(eigrp, prefix);
 | |
| 		eigrp_update_routing_table(eigrp, prefix);
 | |
| 	}
 | |
| 
 | |
| 	if (msg->packet_type == EIGRP_OPC_QUERY)
 | |
| 		eigrp_send_reply(msg->adv_router, prefix);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 | |
| 
 | |
| 	prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance;
 | |
| 	prefix->reported_metric = ne->total_metric;
 | |
| 
 | |
| 	if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3) {
 | |
| 		struct list *successors = eigrp_topology_get_successor(prefix);
 | |
| 
 | |
| 		assert(successors); // It's like Napolean and Waterloo
 | |
| 
 | |
| 		ne = listnode_head(successors);
 | |
| 		eigrp_send_reply(ne->adv_router, prefix);
 | |
| 		list_delete(&successors);
 | |
| 	}
 | |
| 
 | |
| 	prefix->state = EIGRP_FSM_STATE_PASSIVE;
 | |
| 	prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
 | |
| 	listnode_add(eigrp->topology_changes_internalIPV4, prefix);
 | |
| 	eigrp_topology_update_node_flags(eigrp, prefix);
 | |
| 	eigrp_update_routing_table(eigrp, prefix);
 | |
| 	eigrp_update_topology_table_prefix(eigrp, eigrp->topology_table,
 | |
| 					   prefix);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct list *successors = eigrp_topology_get_successor(msg->prefix);
 | |
| 	struct eigrp_route_descriptor *ne;
 | |
| 
 | |
| 	assert(successors); // Trump and his big hands
 | |
| 
 | |
| 	ne = listnode_head(successors);
 | |
| 	msg->prefix->state = msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1
 | |
| 				     ? EIGRP_FSM_STATE_ACTIVE_0
 | |
| 				     : EIGRP_FSM_STATE_ACTIVE_2;
 | |
| 	msg->prefix->distance = ne->distance;
 | |
| 	if (!msg->prefix->rij->count)
 | |
| 		(*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(
 | |
| 			msg);
 | |
| 
 | |
| 
 | |
| 	list_delete(&successors);
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
 | |
| 
 | |
| 	prefix->state = EIGRP_FSM_STATE_PASSIVE;
 | |
| 	prefix->distance = prefix->rdistance = ne->distance;
 | |
| 	prefix->reported_metric = ne->total_metric;
 | |
| 	prefix->fdistance = prefix->fdistance > prefix->distance
 | |
| 				    ? prefix->distance
 | |
| 				    : prefix->fdistance;
 | |
| 	if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2) {
 | |
| 		struct list *successors = eigrp_topology_get_successor(prefix);
 | |
| 
 | |
| 		assert(successors); // Having a spoon and all you need is a
 | |
| 				    // knife
 | |
| 		ne = listnode_head(successors);
 | |
| 		eigrp_send_reply(ne->adv_router, prefix);
 | |
| 
 | |
| 		list_delete(&successors);
 | |
| 	}
 | |
| 	prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
 | |
| 	listnode_add(eigrp->topology_changes_internalIPV4, prefix);
 | |
| 	eigrp_topology_update_node_flags(eigrp, prefix);
 | |
| 	eigrp_update_routing_table(eigrp, prefix);
 | |
| 	eigrp_update_topology_table_prefix(eigrp, eigrp->topology_table,
 | |
| 					   prefix);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct eigrp *eigrp = msg->eigrp;
 | |
| 	struct eigrp_prefix_descriptor *prefix = msg->prefix;
 | |
| 	struct eigrp_route_descriptor *best_successor;
 | |
| 	struct list *successors = eigrp_topology_get_successor(prefix);
 | |
| 
 | |
| 	assert(successors); // Routing without a stack
 | |
| 
 | |
| 	prefix->state = prefix->state == EIGRP_FSM_STATE_ACTIVE_0
 | |
| 				? EIGRP_FSM_STATE_ACTIVE_1
 | |
| 				: EIGRP_FSM_STATE_ACTIVE_3;
 | |
| 
 | |
| 	best_successor = listnode_head(successors);
 | |
| 	prefix->rdistance = prefix->distance = best_successor->distance;
 | |
| 	prefix->reported_metric = best_successor->total_metric;
 | |
| 
 | |
| 	if (eigrp_nbr_count_get(eigrp)) {
 | |
| 		prefix->req_action |= EIGRP_FSM_NEED_QUERY;
 | |
| 		listnode_add(eigrp->topology_changes_internalIPV4, prefix);
 | |
| 	} else {
 | |
| 		eigrp_fsm_event_lr(msg); // in the case that there are no more
 | |
| 					 // neighbors left
 | |
| 	}
 | |
| 
 | |
| 	list_delete(&successors);
 | |
| 
 | |
| 	return 1;
 | |
| }
 | |
| 
 | |
| int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
 | |
| {
 | |
| 	struct list *successors = eigrp_topology_get_successor(msg->prefix);
 | |
| 	struct eigrp_route_descriptor *ne;
 | |
| 
 | |
| 	assert(successors); // Cats and no Dogs
 | |
| 
 | |
| 	ne = listnode_head(successors);
 | |
| 	msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
 | |
| 	msg->prefix->distance = ne->distance;
 | |
| 
 | |
| 	list_delete(&successors);
 | |
| 	return 1;
 | |
| }
 |