mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 05:27:16 +02:00

a) EIGRP was having issues with the prefix created as part of the topology destination. Make this just a part of the topology data structure instead of allocating it. b) EIGRP was not freeing up any memory associated with the network table. Free it. c) EIGRP was confusing zebra shutdown as part of the deletion of the last eigrp data structure. This was inappropriate it should be part of the `I'm just shutting down`. d) The QOBJ was not being properly freed, free it. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
627 lines
19 KiB
C
627 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 "frrevent.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: %pFX Packet Type: %s Reply RIJ Count: %d change: %s",
|
|
msg->eigrp->AS, prefix_state2str(msg->prefix->state), fsm_state2str(event),
|
|
&msg->prefix->destination, 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;
|
|
}
|