]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_fsm.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / eigrpd / eigrp_fsm.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
7f57883e
DS
2/*
3 * EIGRPd Finite State Machine (DUAL).
4 * Copyright (C) 2013-2014
5 * Authors:
6 * Donnie Savage
7 * Jan Janovic
8 * Matej Perina
9 * Peter Orsag
10 * Peter Paluch
11 *
7f57883e
DS
12 * This file contains functions for executing logic of finite state machine
13 *
14 * +------------ +
15 * | (7) |
16 * | v
17 * +=====================================+
18 * | |
19 * | Passive |
20 * | |
21 * +=====================================+
22 * ^ | ^ ^ ^ |
23 * (3)| | (1)| | (1)| |
24 * | (0)| | (3)| | (2)|
25 * | | | | | +---------------+
26 * | | | | | \
27 * +--------+ | | | +-----------------+ \
28 * / / / | \ \
29 * / / / +----+ \ \
30 * | | | | | |
31 * | v | | | v
d62a17ae 32 * +===========+ (6) +===========+ +===========+ (6) +===========+
33 * | |------->| | (5) | |-------->| |
34 * | | (4) | |------>| | (4) | |
35 * | ACTIVE 0 |<-------| ACTIVE 1 | | ACTIVE 2 |<--------| ACTIVE 3
36 * |
37 * +--| | +--| | +--| | +--| |
38 * | +===========+ | +===========+ | +===========+ |
39 * +===========+
7f57883e
DS
40 * | ^ |(5) | ^ | ^ ^ | ^
41 * | | +---------|------|------------|----+ | | |
42 * +-------+ +------+ +---------+ +---------+
43 * (7) (7) (7) (7)
44 *
45 * 0- input event other than query from successor, FC not satisfied
46 * 1- last reply, FD is reset
47 * 2- query from successor, FC not satisfied
48 * 3- last reply, FC satisfied with current value of FDij
49 * 4- distance increase while in active state
50 * 5- query from successor while in active state
51 * 6- last reply, FC not satisfied with current value of FDij
52 * 7- state not changed, usually by receiving not last reply
7f57883e
DS
53 */
54
7f57883e 55#include <zebra.h>
b45ac5f5 56#include <thread.h>
7f57883e
DS
57
58#include "prefix.h"
59#include "table.h"
60#include "memory.h"
61#include "log.h"
62#include "linklist.h"
63#include "vty.h"
64
e9f1847e 65#include "eigrpd/eigrp_types.h"
7f57883e
DS
66#include "eigrpd/eigrp_structs.h"
67#include "eigrpd/eigrpd.h"
68#include "eigrpd/eigrp_interface.h"
69#include "eigrpd/eigrp_neighbor.h"
70#include "eigrpd/eigrp_packet.h"
71#include "eigrpd/eigrp_zebra.h"
72#include "eigrpd/eigrp_vty.h"
73#include "eigrpd/eigrp_network.h"
74#include "eigrpd/eigrp_dump.h"
75#include "eigrpd/eigrp_topology.h"
76#include "eigrpd/eigrp_fsm.h"
e9f1847e 77#include "eigrpd/eigrp_metric.h"
7f57883e
DS
78
79/*
80 * Prototypes
81 */
f9e5c9ca
DS
82int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *);
83int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *);
84int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *);
85int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *);
86int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *);
87int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *);
88int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *);
89int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *);
7f57883e
DS
90
91//---------------------------------------------------------------------
92
93/*
94 * NSM - field of fields of struct containing one function each.
95 * Which function is used depends on actual state of FSM and occurred
96 * event(arrow in diagram). Usage:
97 * NSM[actual/starting state][occurred event].func
98 * Functions are should be executed within separate thread.
99 */
2b64873d 100const struct {
d62a17ae 101 int (*func)(struct eigrp_fsm_action_message *);
102} NSM[EIGRP_FSM_STATE_MAX][EIGRP_FSM_EVENT_MAX] = {
103 {
104 // PASSIVE STATE
105 {eigrp_fsm_event_nq_fcn}, /* Event 0 */
106 {eigrp_fsm_event_keep_state}, /* Event 1 */
107 {eigrp_fsm_event_q_fcn}, /* Event 2 */
108 {eigrp_fsm_event_keep_state}, /* Event 3 */
109 {eigrp_fsm_event_keep_state}, /* Event 4 */
110 {eigrp_fsm_event_keep_state}, /* Event 5 */
111 {eigrp_fsm_event_keep_state}, /* Event 6 */
112 {eigrp_fsm_event_keep_state}, /* Event 7 */
113 },
114 {
115 // Active 0 state
116 {eigrp_fsm_event_keep_state}, /* Event 0 */
117 {eigrp_fsm_event_keep_state}, /* Event 1 */
118 {eigrp_fsm_event_keep_state}, /* Event 2 */
119 {eigrp_fsm_event_lr_fcs}, /* Event 3 */
120 {eigrp_fsm_event_keep_state}, /* Event 4 */
121 {eigrp_fsm_event_qact}, /* Event 5 */
122 {eigrp_fsm_event_lr_fcn}, /* Event 6 */
123 {eigrp_fsm_event_keep_state}, /* Event 7 */
124 },
125 {
126 // Active 1 state
127 {eigrp_fsm_event_keep_state}, /* Event 0 */
128 {eigrp_fsm_event_lr}, /* Event 1 */
129 {eigrp_fsm_event_keep_state}, /* Event 2 */
130 {eigrp_fsm_event_keep_state}, /* Event 3 */
131 {eigrp_fsm_event_dinc}, /* Event 4 */
132 {eigrp_fsm_event_qact}, /* Event 5 */
133 {eigrp_fsm_event_keep_state}, /* Event 6 */
134 {eigrp_fsm_event_keep_state}, /* Event 7 */
135 },
136 {
137 // Active 2 state
138 {eigrp_fsm_event_keep_state}, /* Event 0 */
139 {eigrp_fsm_event_keep_state}, /* Event 1 */
140 {eigrp_fsm_event_keep_state}, /* Event 2 */
141 {eigrp_fsm_event_lr_fcs}, /* Event 3 */
142 {eigrp_fsm_event_keep_state}, /* Event 4 */
143 {eigrp_fsm_event_keep_state}, /* Event 5 */
144 {eigrp_fsm_event_lr_fcn}, /* Event 6 */
145 {eigrp_fsm_event_keep_state}, /* Event 7 */
146 },
147 {
148 // Active 3 state
149 {eigrp_fsm_event_keep_state}, /* Event 0 */
150 {eigrp_fsm_event_lr}, /* Event 1 */
151 {eigrp_fsm_event_keep_state}, /* Event 2 */
152 {eigrp_fsm_event_keep_state}, /* Event 3 */
153 {eigrp_fsm_event_dinc}, /* Event 4 */
154 {eigrp_fsm_event_keep_state}, /* Event 5 */
155 {eigrp_fsm_event_keep_state}, /* Event 6 */
156 {eigrp_fsm_event_keep_state}, /* Event 7 */
157 },
158};
7f57883e 159
d7c0a89a 160static const char *packet_type2str(uint8_t packet_type)
895722db
DS
161{
162 if (packet_type == EIGRP_OPC_UPDATE)
163 return "Update";
164 if (packet_type == EIGRP_OPC_REQUEST)
165 return "Request";
166 if (packet_type == EIGRP_OPC_QUERY)
167 return "Query";
168 if (packet_type == EIGRP_OPC_REPLY)
169 return "Reply";
170 if (packet_type == EIGRP_OPC_HELLO)
171 return "Hello";
172 if (packet_type == EIGRP_OPC_IPXSAP)
173 return "IPXSAP";
174 if (packet_type == EIGRP_OPC_ACK)
175 return "Ack";
176 if (packet_type == EIGRP_OPC_SIAQUERY)
177 return "SIA Query";
178 if (packet_type == EIGRP_OPC_SIAREPLY)
179 return "SIA Reply";
180
181 return "Unknown";
182}
183
5cc74ec1
DS
184static const char *prefix_state2str(enum eigrp_fsm_states state)
185{
186 switch (state) {
187 case EIGRP_FSM_STATE_PASSIVE:
188 return "Passive";
189 case EIGRP_FSM_STATE_ACTIVE_0:
190 return "Active oij0";
191 case EIGRP_FSM_STATE_ACTIVE_1:
192 return "Active oij1";
193 case EIGRP_FSM_STATE_ACTIVE_2:
194 return "Active oij2";
195 case EIGRP_FSM_STATE_ACTIVE_3:
196 return "Active oij3";
197 }
198
199 return "Unknown";
200}
201
94ccb309
DS
202static const char *fsm_state2str(enum eigrp_fsm_events event)
203{
204 switch (event) {
205 case EIGRP_FSM_KEEP_STATE:
206 return "Keep State Event";
207 case EIGRP_FSM_EVENT_NQ_FCN:
208 return "Non Query Event Feasability not satisfied";
209 case EIGRP_FSM_EVENT_LR:
210 return "Last Reply Event";
211 case EIGRP_FSM_EVENT_Q_FCN:
0437e105 212 return "Query Event Feasability not satisfied";
94ccb309 213 case EIGRP_FSM_EVENT_LR_FCS:
0437e105 214 return "Last Reply Event Feasability satisfied";
94ccb309
DS
215 case EIGRP_FSM_EVENT_DINC:
216 return "Distance Increase Event";
217 case EIGRP_FSM_EVENT_QACT:
218 return "Query from Successor while in active state";
219 case EIGRP_FSM_EVENT_LR_FCN:
220 return "Last Reply Event, Feasibility not satisfied";
5b94ec50 221 }
94ccb309
DS
222
223 return "Unknown";
224}
377f30c3
DS
225
226static const char *change2str(enum metric_change change)
227{
228 switch (change) {
229 case METRIC_DECREASE:
230 return "Decrease";
231 case METRIC_SAME:
232 return "Same";
233 case METRIC_INCREASE:
234 return "Increase";
235 }
236
237 return "Unknown";
238}
7f57883e
DS
239/*
240 * Main function in which are make decisions which event occurred.
241 * msg - argument of type struct eigrp_fsm_action_message contain
242 * details about what happen
243 *
244 * Return number of occurred event (arrow in diagram).
245 *
246 */
996c9314
LB
247static enum eigrp_fsm_events
248eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
f9e5c9ca 249{
d62a17ae 250 // Loading base information from message
251 // struct eigrp *eigrp = msg->eigrp;
dc4accdd
DS
252 struct eigrp_prefix_descriptor *prefix = msg->prefix;
253 struct eigrp_route_descriptor *entry = msg->entry;
d7c0a89a 254 uint8_t actual_state = prefix->state;
748a2ba4 255 enum metric_change change;
d62a17ae 256
257 if (entry == NULL) {
dc4accdd 258 entry = eigrp_route_descriptor_new();
d62a17ae 259 entry->adv_router = msg->adv_router;
260 entry->ei = msg->adv_router->ei;
261 entry->prefix = prefix;
262 msg->entry = entry;
263 }
264
748a2ba4
DS
265 /*
266 * Calculate resultant metrics and insert to correct position
267 * in entries list
268 */
269 change = eigrp_topology_update_distance(msg);
270
377f30c3
DS
271 /* Store for display later */
272 msg->change = change;
273
d62a17ae 274 switch (actual_state) {
275 case EIGRP_FSM_STATE_PASSIVE: {
dc4accdd 276 struct eigrp_route_descriptor *head =
695ff37b 277 listnode_head(prefix->entries);
748a2ba4 278
d62a17ae 279 if (head->reported_distance < prefix->fdistance) {
280 return EIGRP_FSM_KEEP_STATE;
281 }
282 /*
283 * if best entry doesn't satisfy feasibility condition it means
284 * move to active state
285 * dependently if it was query from successor
286 */
9a8d52a4
DS
287 if (msg->packet_type == EIGRP_OPC_QUERY) {
288 return EIGRP_FSM_EVENT_Q_FCN;
289 } else {
290 return EIGRP_FSM_EVENT_NQ_FCN;
d62a17ae 291 }
292
293 break;
294 }
295 case EIGRP_FSM_STATE_ACTIVE_0: {
d62a17ae 296 if (msg->packet_type == EIGRP_OPC_REPLY) {
dc4accdd 297 struct eigrp_route_descriptor *head =
695ff37b 298 listnode_head(prefix->entries);
9a8d52a4 299
d62a17ae 300 listnode_delete(prefix->rij, entry->adv_router);
9a8d52a4 301 if (prefix->rij->count)
d62a17ae 302 return EIGRP_FSM_KEEP_STATE;
d62a17ae 303
9165c5f5 304 zlog_info("All reply received");
996c9314 305 if (head->reported_distance < prefix->fdistance) {
9a8d52a4 306 return EIGRP_FSM_EVENT_LR_FCS;
d62a17ae 307 }
9a8d52a4
DS
308
309 return EIGRP_FSM_EVENT_LR_FCN;
d62a17ae 310 } else if (msg->packet_type == EIGRP_OPC_QUERY
311 && (entry->flags
dc4accdd 312 & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
d62a17ae 313 return EIGRP_FSM_EVENT_QACT;
314 }
315
316 return EIGRP_FSM_KEEP_STATE;
317
318 break;
319 }
320 case EIGRP_FSM_STATE_ACTIVE_1: {
d62a17ae 321 if (msg->packet_type == EIGRP_OPC_QUERY
dc4accdd 322 && (entry->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
d62a17ae 323 return EIGRP_FSM_EVENT_QACT;
324 } else if (msg->packet_type == EIGRP_OPC_REPLY) {
325 listnode_delete(prefix->rij, entry->adv_router);
326
748a2ba4 327 if (change == METRIC_INCREASE
d62a17ae 328 && (entry->flags
dc4accdd 329 & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
d62a17ae 330 return EIGRP_FSM_EVENT_DINC;
331 } else if (prefix->rij->count) {
332 return EIGRP_FSM_KEEP_STATE;
333 } else {
9165c5f5 334 zlog_info("All reply received");
d62a17ae 335 return EIGRP_FSM_EVENT_LR;
336 }
377f30c3
DS
337 } else if (msg->packet_type == EIGRP_OPC_UPDATE
338 && change == METRIC_INCREASE
d62a17ae 339 && (entry->flags
dc4accdd 340 & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
d62a17ae 341 return EIGRP_FSM_EVENT_DINC;
342 }
343 return EIGRP_FSM_KEEP_STATE;
344
345 break;
346 }
347 case EIGRP_FSM_STATE_ACTIVE_2: {
d62a17ae 348 if (msg->packet_type == EIGRP_OPC_REPLY) {
dc4accdd 349 struct eigrp_route_descriptor *head =
695ff37b 350 listnode_head(prefix->entries);
9a8d52a4 351
d62a17ae 352 listnode_delete(prefix->rij, entry->adv_router);
353 if (prefix->rij->count) {
354 return EIGRP_FSM_KEEP_STATE;
355 } else {
9165c5f5 356 zlog_info("All reply received");
9a8d52a4 357 if (head->reported_distance
d62a17ae 358 < prefix->fdistance) {
359 return EIGRP_FSM_EVENT_LR_FCS;
360 }
361
362 return EIGRP_FSM_EVENT_LR_FCN;
363 }
364 }
365 return EIGRP_FSM_KEEP_STATE;
366
367 break;
368 }
369 case EIGRP_FSM_STATE_ACTIVE_3: {
d62a17ae 370 if (msg->packet_type == EIGRP_OPC_REPLY) {
371 listnode_delete(prefix->rij, entry->adv_router);
372
748a2ba4 373 if (change == METRIC_INCREASE
d62a17ae 374 && (entry->flags
dc4accdd 375 & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
d62a17ae 376 return EIGRP_FSM_EVENT_DINC;
377 } else if (prefix->rij->count) {
378 return EIGRP_FSM_KEEP_STATE;
379 } else {
9165c5f5 380 zlog_info("All reply received");
d62a17ae 381 return EIGRP_FSM_EVENT_LR;
382 }
377f30c3
DS
383 } else if (msg->packet_type == EIGRP_OPC_UPDATE
384 && change == METRIC_INCREASE
d62a17ae 385 && (entry->flags
dc4accdd 386 & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
d62a17ae 387 return EIGRP_FSM_EVENT_DINC;
388 }
389 return EIGRP_FSM_KEEP_STATE;
390
391 break;
392 }
393 }
394
395 return EIGRP_FSM_KEEP_STATE;
7f57883e
DS
396}
397
398/*
399 * Function made to execute in separate thread.
400 * Load argument from thread and execute proper NSM function
401 */
6118272f 402int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
f9e5c9ca 403{
94ccb309
DS
404 enum eigrp_fsm_events event = eigrp_get_fsm_event(msg);
405
996c9314 406 zlog_info(
37b4b3cc 407 "EIGRP AS: %d State: %s Event: %s Network: %pI4 Packet Type: %s Reply RIJ Count: %d change: %s",
996c9314 408 msg->eigrp->AS, prefix_state2str(msg->prefix->state),
37b4b3cc 409 fsm_state2str(event), &msg->prefix->destination->u.prefix4,
996c9314
LB
410 packet_type2str(msg->packet_type), msg->prefix->rij->count,
411 change2str(msg->change));
d62a17ae 412 (*(NSM[msg->prefix->state][event].func))(msg);
7f57883e 413
d62a17ae 414 return 1;
7f57883e 415}
f9e5c9ca 416
7f57883e
DS
417/*
418 * Function of event 0.
419 *
420 */
f9e5c9ca
DS
421int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
422{
d62a17ae 423 struct eigrp *eigrp = msg->eigrp;
dc4accdd 424 struct eigrp_prefix_descriptor *prefix = msg->prefix;
d62a17ae 425 struct list *successors = eigrp_topology_get_successor(prefix);
dc4accdd 426 struct eigrp_route_descriptor *ne;
d62a17ae 427
428 assert(successors); // If this is NULL we have shit the bed, fun huh?
429
695ff37b 430 ne = listnode_head(successors);
d62a17ae 431 prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
996c9314 432 prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
695ff37b 433 prefix->reported_metric = ne->total_metric;
d62a17ae 434
2ea6b572 435 if (eigrp_nbr_count_get(eigrp)) {
d62a17ae 436 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
437 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
438 } else {
439 eigrp_fsm_event_lr(msg); // in the case that there are no more
440 // neighbors left
441 }
442
6a154c88 443 list_delete(&successors);
d62a17ae 444
445 return 1;
7f57883e
DS
446}
447
f9e5c9ca
DS
448int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
449{
d62a17ae 450 struct eigrp *eigrp = msg->eigrp;
dc4accdd 451 struct eigrp_prefix_descriptor *prefix = msg->prefix;
d62a17ae 452 struct list *successors = eigrp_topology_get_successor(prefix);
dc4accdd 453 struct eigrp_route_descriptor *ne;
d62a17ae 454
455 assert(successors); // If this is NULL somebody poked us in the eye.
456
695ff37b 457 ne = listnode_head(successors);
d62a17ae 458 prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
996c9314 459 prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
695ff37b 460 prefix->reported_metric = ne->total_metric;
2ea6b572 461 if (eigrp_nbr_count_get(eigrp)) {
d62a17ae 462 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
463 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
464 } else {
465 eigrp_fsm_event_lr(msg); // in the case that there are no more
466 // neighbors left
467 }
468
6a154c88 469 list_delete(&successors);
d62a17ae 470
471 return 1;
7f57883e
DS
472}
473
f9e5c9ca
DS
474int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
475{
17c0e586 476 struct eigrp *eigrp = msg->eigrp;
dc4accdd
DS
477 struct eigrp_prefix_descriptor *prefix = msg->prefix;
478 struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
d62a17ae 479
480 if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
481 if (!eigrp_metrics_is_same(prefix->reported_metric,
695ff37b 482 ne->total_metric)) {
d62a17ae 483 prefix->rdistance = prefix->fdistance =
695ff37b 484 prefix->distance = ne->distance;
996c9314 485 prefix->reported_metric = ne->total_metric;
d62a17ae 486 if (msg->packet_type == EIGRP_OPC_QUERY)
487 eigrp_send_reply(msg->adv_router, prefix);
488 prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
0bf75bd5 489 listnode_add(eigrp->topology_changes_internalIPV4,
490 prefix);
d62a17ae 491 }
0da93ecf
DS
492 eigrp_topology_update_node_flags(eigrp, prefix);
493 eigrp_update_routing_table(eigrp, prefix);
d62a17ae 494 }
495
496 if (msg->packet_type == EIGRP_OPC_QUERY)
497 eigrp_send_reply(msg->adv_router, prefix);
498
499 return 1;
7f57883e
DS
500}
501
f9e5c9ca
DS
502int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
503{
d62a17ae 504 struct eigrp *eigrp = msg->eigrp;
dc4accdd
DS
505 struct eigrp_prefix_descriptor *prefix = msg->prefix;
506 struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
695ff37b 507
996c9314 508 prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance;
695ff37b 509 prefix->reported_metric = ne->total_metric;
d62a17ae 510
511 if (prefix->state == EIGRP_FSM_STATE_ACTIVE_3) {
512 struct list *successors = eigrp_topology_get_successor(prefix);
513
514 assert(successors); // It's like Napolean and Waterloo
515
695ff37b 516 ne = listnode_head(successors);
996c9314 517 eigrp_send_reply(ne->adv_router, prefix);
6a154c88 518 list_delete(&successors);
d62a17ae 519 }
520
521 prefix->state = EIGRP_FSM_STATE_PASSIVE;
522 prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
523 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
0da93ecf
DS
524 eigrp_topology_update_node_flags(eigrp, prefix);
525 eigrp_update_routing_table(eigrp, prefix);
526 eigrp_update_topology_table_prefix(eigrp, eigrp->topology_table,
527 prefix);
d62a17ae 528
529 return 1;
7f57883e
DS
530}
531
f9e5c9ca
DS
532int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
533{
d62a17ae 534 struct list *successors = eigrp_topology_get_successor(msg->prefix);
dc4accdd 535 struct eigrp_route_descriptor *ne;
f9e5c9ca 536
d62a17ae 537 assert(successors); // Trump and his big hands
f6709c16 538
695ff37b 539 ne = listnode_head(successors);
d62a17ae 540 msg->prefix->state = msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1
541 ? EIGRP_FSM_STATE_ACTIVE_0
542 : EIGRP_FSM_STATE_ACTIVE_2;
695ff37b 543 msg->prefix->distance = ne->distance;
d62a17ae 544 if (!msg->prefix->rij->count)
545 (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(
546 msg);
7f57883e 547
7f57883e 548
6a154c88 549 list_delete(&successors);
d62a17ae 550 return 1;
7f57883e
DS
551}
552
f9e5c9ca
DS
553int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
554{
d62a17ae 555 struct eigrp *eigrp = msg->eigrp;
dc4accdd
DS
556 struct eigrp_prefix_descriptor *prefix = msg->prefix;
557 struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
695ff37b 558
d62a17ae 559 prefix->state = EIGRP_FSM_STATE_PASSIVE;
695ff37b
DS
560 prefix->distance = prefix->rdistance = ne->distance;
561 prefix->reported_metric = ne->total_metric;
d62a17ae 562 prefix->fdistance = prefix->fdistance > prefix->distance
563 ? prefix->distance
564 : prefix->fdistance;
565 if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2) {
566 struct list *successors = eigrp_topology_get_successor(prefix);
567
568 assert(successors); // Having a spoon and all you need is a
569 // knife
695ff37b 570 ne = listnode_head(successors);
996c9314 571 eigrp_send_reply(ne->adv_router, prefix);
d62a17ae 572
6a154c88 573 list_delete(&successors);
d62a17ae 574 }
575 prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
576 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
0da93ecf
DS
577 eigrp_topology_update_node_flags(eigrp, prefix);
578 eigrp_update_routing_table(eigrp, prefix);
579 eigrp_update_topology_table_prefix(eigrp, eigrp->topology_table,
580 prefix);
d62a17ae 581
582 return 1;
7f57883e
DS
583}
584
f9e5c9ca
DS
585int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
586{
d62a17ae 587 struct eigrp *eigrp = msg->eigrp;
dc4accdd
DS
588 struct eigrp_prefix_descriptor *prefix = msg->prefix;
589 struct eigrp_route_descriptor *best_successor;
d62a17ae 590 struct list *successors = eigrp_topology_get_successor(prefix);
591
592 assert(successors); // Routing without a stack
593
594 prefix->state = prefix->state == EIGRP_FSM_STATE_ACTIVE_0
595 ? EIGRP_FSM_STATE_ACTIVE_1
596 : EIGRP_FSM_STATE_ACTIVE_3;
695ff37b
DS
597
598 best_successor = listnode_head(successors);
d62a17ae 599 prefix->rdistance = prefix->distance = best_successor->distance;
600 prefix->reported_metric = best_successor->total_metric;
601
2ea6b572 602 if (eigrp_nbr_count_get(eigrp)) {
d62a17ae 603 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
604 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
605 } else {
606 eigrp_fsm_event_lr(msg); // in the case that there are no more
607 // neighbors left
608 }
609
6a154c88 610 list_delete(&successors);
d62a17ae 611
612 return 1;
7f57883e
DS
613}
614
f9e5c9ca
DS
615int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
616{
d62a17ae 617 struct list *successors = eigrp_topology_get_successor(msg->prefix);
dc4accdd 618 struct eigrp_route_descriptor *ne;
f6709c16 619
d62a17ae 620 assert(successors); // Cats and no Dogs
f6709c16 621
695ff37b 622 ne = listnode_head(successors);
d62a17ae 623 msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
695ff37b 624 msg->prefix->distance = ne->distance;
f6709c16 625
6a154c88 626 list_delete(&successors);
d62a17ae 627 return 1;
7f57883e 628}