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