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