]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_fsm.c
zebra: Allow ns delete to happen after under/over flow checks
[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
7f57883e 70#include <zebra.h>
b45ac5f5 71#include <thread.h>
7f57883e
DS
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
d7c0a89a 173static const char *packet_type2str(uint8_t packet_type)
895722db
DS
174{
175 if (packet_type == EIGRP_OPC_UPDATE)
176 return "Update";
177 if (packet_type == EIGRP_OPC_REQUEST)
178 return "Request";
179 if (packet_type == EIGRP_OPC_QUERY)
180 return "Query";
181 if (packet_type == EIGRP_OPC_REPLY)
182 return "Reply";
183 if (packet_type == EIGRP_OPC_HELLO)
184 return "Hello";
185 if (packet_type == EIGRP_OPC_IPXSAP)
186 return "IPXSAP";
187 if (packet_type == EIGRP_OPC_ACK)
188 return "Ack";
189 if (packet_type == EIGRP_OPC_SIAQUERY)
190 return "SIA Query";
191 if (packet_type == EIGRP_OPC_SIAREPLY)
192 return "SIA Reply";
193
194 return "Unknown";
195}
196
5cc74ec1
DS
197static const char *prefix_state2str(enum eigrp_fsm_states state)
198{
199 switch (state) {
200 case EIGRP_FSM_STATE_PASSIVE:
201 return "Passive";
202 case EIGRP_FSM_STATE_ACTIVE_0:
203 return "Active oij0";
204 case EIGRP_FSM_STATE_ACTIVE_1:
205 return "Active oij1";
206 case EIGRP_FSM_STATE_ACTIVE_2:
207 return "Active oij2";
208 case EIGRP_FSM_STATE_ACTIVE_3:
209 return "Active oij3";
210 }
211
212 return "Unknown";
213}
214
94ccb309
DS
215static const char *fsm_state2str(enum eigrp_fsm_events event)
216{
217 switch (event) {
218 case EIGRP_FSM_KEEP_STATE:
219 return "Keep State Event";
220 case EIGRP_FSM_EVENT_NQ_FCN:
221 return "Non Query Event Feasability not satisfied";
222 case EIGRP_FSM_EVENT_LR:
223 return "Last Reply Event";
224 case EIGRP_FSM_EVENT_Q_FCN:
0437e105 225 return "Query Event Feasability not satisfied";
94ccb309 226 case EIGRP_FSM_EVENT_LR_FCS:
0437e105 227 return "Last Reply Event Feasability satisfied";
94ccb309
DS
228 case EIGRP_FSM_EVENT_DINC:
229 return "Distance Increase Event";
230 case EIGRP_FSM_EVENT_QACT:
231 return "Query from Successor while in active state";
232 case EIGRP_FSM_EVENT_LR_FCN:
233 return "Last Reply Event, Feasibility not satisfied";
234 };
235
236 return "Unknown";
237}
377f30c3
DS
238
239static const char *change2str(enum metric_change change)
240{
241 switch (change) {
242 case METRIC_DECREASE:
243 return "Decrease";
244 case METRIC_SAME:
245 return "Same";
246 case METRIC_INCREASE:
247 return "Increase";
248 }
249
250 return "Unknown";
251}
7f57883e
DS
252/*
253 * Main function in which are make decisions which event occurred.
254 * msg - argument of type struct eigrp_fsm_action_message contain
255 * details about what happen
256 *
257 * Return number of occurred event (arrow in diagram).
258 *
259 */
996c9314
LB
260static enum eigrp_fsm_events
261eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
f9e5c9ca 262{
d62a17ae 263 // Loading base information from message
264 // struct eigrp *eigrp = msg->eigrp;
265 struct eigrp_prefix_entry *prefix = msg->prefix;
255ab940 266 struct eigrp_nexthop_entry *entry = msg->entry;
d7c0a89a 267 uint8_t actual_state = prefix->state;
748a2ba4 268 enum metric_change change;
d62a17ae 269
270 if (entry == NULL) {
255ab940 271 entry = eigrp_nexthop_entry_new();
d62a17ae 272 entry->adv_router = msg->adv_router;
273 entry->ei = msg->adv_router->ei;
274 entry->prefix = prefix;
275 msg->entry = entry;
276 }
277
748a2ba4
DS
278 /*
279 * Calculate resultant metrics and insert to correct position
280 * in entries list
281 */
282 change = eigrp_topology_update_distance(msg);
283
377f30c3
DS
284 /* Store for display later */
285 msg->change = change;
286
d62a17ae 287 switch (actual_state) {
288 case EIGRP_FSM_STATE_PASSIVE: {
255ab940 289 struct eigrp_nexthop_entry *head =
695ff37b 290 listnode_head(prefix->entries);
748a2ba4 291
d62a17ae 292 if (head->reported_distance < prefix->fdistance) {
293 return EIGRP_FSM_KEEP_STATE;
294 }
295 /*
296 * if best entry doesn't satisfy feasibility condition it means
297 * move to active state
298 * dependently if it was query from successor
299 */
9a8d52a4
DS
300 if (msg->packet_type == EIGRP_OPC_QUERY) {
301 return EIGRP_FSM_EVENT_Q_FCN;
302 } else {
303 return EIGRP_FSM_EVENT_NQ_FCN;
d62a17ae 304 }
305
306 break;
307 }
308 case EIGRP_FSM_STATE_ACTIVE_0: {
d62a17ae 309 if (msg->packet_type == EIGRP_OPC_REPLY) {
255ab940 310 struct eigrp_nexthop_entry *head =
695ff37b 311 listnode_head(prefix->entries);
9a8d52a4 312
d62a17ae 313 listnode_delete(prefix->rij, entry->adv_router);
9a8d52a4 314 if (prefix->rij->count)
d62a17ae 315 return EIGRP_FSM_KEEP_STATE;
d62a17ae 316
9a8d52a4 317 zlog_info("All reply received\n");
996c9314 318 if (head->reported_distance < prefix->fdistance) {
9a8d52a4 319 return EIGRP_FSM_EVENT_LR_FCS;
d62a17ae 320 }
9a8d52a4
DS
321
322 return EIGRP_FSM_EVENT_LR_FCN;
d62a17ae 323 } else if (msg->packet_type == EIGRP_OPC_QUERY
324 && (entry->flags
255ab940 325 & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
d62a17ae 326 return EIGRP_FSM_EVENT_QACT;
327 }
328
329 return EIGRP_FSM_KEEP_STATE;
330
331 break;
332 }
333 case EIGRP_FSM_STATE_ACTIVE_1: {
d62a17ae 334 if (msg->packet_type == EIGRP_OPC_QUERY
255ab940 335 && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
d62a17ae 336 return EIGRP_FSM_EVENT_QACT;
337 } else if (msg->packet_type == EIGRP_OPC_REPLY) {
338 listnode_delete(prefix->rij, entry->adv_router);
339
748a2ba4 340 if (change == METRIC_INCREASE
d62a17ae 341 && (entry->flags
255ab940 342 & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
d62a17ae 343 return EIGRP_FSM_EVENT_DINC;
344 } else if (prefix->rij->count) {
345 return EIGRP_FSM_KEEP_STATE;
346 } else {
347 zlog_info("All reply received\n");
348 return EIGRP_FSM_EVENT_LR;
349 }
377f30c3
DS
350 } else if (msg->packet_type == EIGRP_OPC_UPDATE
351 && change == METRIC_INCREASE
d62a17ae 352 && (entry->flags
255ab940 353 & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
d62a17ae 354 return EIGRP_FSM_EVENT_DINC;
355 }
356 return EIGRP_FSM_KEEP_STATE;
357
358 break;
359 }
360 case EIGRP_FSM_STATE_ACTIVE_2: {
d62a17ae 361 if (msg->packet_type == EIGRP_OPC_REPLY) {
255ab940 362 struct eigrp_nexthop_entry *head =
695ff37b 363 listnode_head(prefix->entries);
9a8d52a4 364
d62a17ae 365 listnode_delete(prefix->rij, entry->adv_router);
366 if (prefix->rij->count) {
367 return EIGRP_FSM_KEEP_STATE;
368 } else {
369 zlog_info("All reply received\n");
9a8d52a4 370 if (head->reported_distance
d62a17ae 371 < prefix->fdistance) {
372 return EIGRP_FSM_EVENT_LR_FCS;
373 }
374
375 return EIGRP_FSM_EVENT_LR_FCN;
376 }
377 }
378 return EIGRP_FSM_KEEP_STATE;
379
380 break;
381 }
382 case EIGRP_FSM_STATE_ACTIVE_3: {
d62a17ae 383 if (msg->packet_type == EIGRP_OPC_REPLY) {
384 listnode_delete(prefix->rij, entry->adv_router);
385
748a2ba4 386 if (change == METRIC_INCREASE
d62a17ae 387 && (entry->flags
255ab940 388 & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
d62a17ae 389 return EIGRP_FSM_EVENT_DINC;
390 } else if (prefix->rij->count) {
391 return EIGRP_FSM_KEEP_STATE;
392 } else {
393 zlog_info("All reply received\n");
394 return EIGRP_FSM_EVENT_LR;
395 }
377f30c3
DS
396 } else if (msg->packet_type == EIGRP_OPC_UPDATE
397 && change == METRIC_INCREASE
d62a17ae 398 && (entry->flags
255ab940 399 & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
d62a17ae 400 return EIGRP_FSM_EVENT_DINC;
401 }
402 return EIGRP_FSM_KEEP_STATE;
403
404 break;
405 }
406 }
407
408 return EIGRP_FSM_KEEP_STATE;
7f57883e
DS
409}
410
411/*
412 * Function made to execute in separate thread.
413 * Load argument from thread and execute proper NSM function
414 */
6118272f 415int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
f9e5c9ca 416{
94ccb309
DS
417 enum eigrp_fsm_events event = eigrp_get_fsm_event(msg);
418
996c9314
LB
419 zlog_info(
420 "EIGRP AS: %d State: %s Event: %s Network: %s Packet Type: %s Reply RIJ Count: %d change: %s",
421 msg->eigrp->AS, prefix_state2str(msg->prefix->state),
422 fsm_state2str(event), eigrp_topology_ip_string(msg->prefix),
423 packet_type2str(msg->packet_type), msg->prefix->rij->count,
424 change2str(msg->change));
d62a17ae 425 (*(NSM[msg->prefix->state][event].func))(msg);
7f57883e 426
d62a17ae 427 return 1;
7f57883e 428}
f9e5c9ca 429
7f57883e
DS
430/*
431 * Function of event 0.
432 *
433 */
f9e5c9ca
DS
434int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
435{
d62a17ae 436 struct eigrp *eigrp = msg->eigrp;
437 struct eigrp_prefix_entry *prefix = msg->prefix;
438 struct list *successors = eigrp_topology_get_successor(prefix);
255ab940 439 struct eigrp_nexthop_entry *ne;
d62a17ae 440
441 assert(successors); // If this is NULL we have shit the bed, fun huh?
442
695ff37b 443 ne = listnode_head(successors);
d62a17ae 444 prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
996c9314 445 prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
695ff37b 446 prefix->reported_metric = ne->total_metric;
d62a17ae 447
448 if (eigrp_nbr_count_get()) {
449 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
450 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
451 } else {
452 eigrp_fsm_event_lr(msg); // in the case that there are no more
453 // neighbors left
454 }
455
6a154c88 456 list_delete(&successors);
d62a17ae 457
458 return 1;
7f57883e
DS
459}
460
f9e5c9ca
DS
461int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
462{
d62a17ae 463 struct eigrp *eigrp = msg->eigrp;
464 struct eigrp_prefix_entry *prefix = msg->prefix;
465 struct list *successors = eigrp_topology_get_successor(prefix);
255ab940 466 struct eigrp_nexthop_entry *ne;
d62a17ae 467
468 assert(successors); // If this is NULL somebody poked us in the eye.
469
695ff37b 470 ne = listnode_head(successors);
d62a17ae 471 prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
996c9314 472 prefix->rdistance = prefix->distance = prefix->fdistance = ne->distance;
695ff37b 473 prefix->reported_metric = ne->total_metric;
d62a17ae 474 if (eigrp_nbr_count_get()) {
475 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
476 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
477 } else {
478 eigrp_fsm_event_lr(msg); // in the case that there are no more
479 // neighbors left
480 }
481
6a154c88 482 list_delete(&successors);
d62a17ae 483
484 return 1;
7f57883e
DS
485}
486
f9e5c9ca
DS
487int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
488{
0bf75bd5 489 struct eigrp *eigrp;
d62a17ae 490 struct eigrp_prefix_entry *prefix = msg->prefix;
255ab940 491 struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
d62a17ae 492
493 if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
494 if (!eigrp_metrics_is_same(prefix->reported_metric,
695ff37b 495 ne->total_metric)) {
d62a17ae 496 prefix->rdistance = prefix->fdistance =
695ff37b 497 prefix->distance = ne->distance;
996c9314 498 prefix->reported_metric = ne->total_metric;
d62a17ae 499 if (msg->packet_type == EIGRP_OPC_QUERY)
500 eigrp_send_reply(msg->adv_router, prefix);
501 prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
0bf75bd5 502 eigrp = eigrp_lookup();
503 assert(eigrp);
504 listnode_add(eigrp->topology_changes_internalIPV4,
505 prefix);
d62a17ae 506 }
507 eigrp_topology_update_node_flags(prefix);
508 eigrp_update_routing_table(prefix);
509 }
510
511 if (msg->packet_type == EIGRP_OPC_QUERY)
512 eigrp_send_reply(msg->adv_router, prefix);
513
514 return 1;
7f57883e
DS
515}
516
f9e5c9ca
DS
517int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
518{
d62a17ae 519 struct eigrp *eigrp = msg->eigrp;
520 struct eigrp_prefix_entry *prefix = msg->prefix;
255ab940 521 struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
695ff37b 522
996c9314 523 prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance;
695ff37b 524 prefix->reported_metric = ne->total_metric;
d62a17ae 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
695ff37b 531 ne = listnode_head(successors);
996c9314 532 eigrp_send_reply(ne->adv_router, prefix);
6a154c88 533 list_delete(&successors);
d62a17ae 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(prefix);
540 eigrp_update_routing_table(prefix);
541 eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
542
543 return 1;
7f57883e
DS
544}
545
f9e5c9ca
DS
546int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
547{
d62a17ae 548 struct list *successors = eigrp_topology_get_successor(msg->prefix);
255ab940 549 struct eigrp_nexthop_entry *ne;
f9e5c9ca 550
d62a17ae 551 assert(successors); // Trump and his big hands
f6709c16 552
695ff37b 553 ne = listnode_head(successors);
d62a17ae 554 msg->prefix->state = msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1
555 ? EIGRP_FSM_STATE_ACTIVE_0
556 : EIGRP_FSM_STATE_ACTIVE_2;
695ff37b 557 msg->prefix->distance = ne->distance;
d62a17ae 558 if (!msg->prefix->rij->count)
559 (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(
560 msg);
7f57883e 561
7f57883e 562
6a154c88 563 list_delete(&successors);
d62a17ae 564 return 1;
7f57883e
DS
565}
566
f9e5c9ca
DS
567int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
568{
d62a17ae 569 struct eigrp *eigrp = msg->eigrp;
570 struct eigrp_prefix_entry *prefix = msg->prefix;
255ab940 571 struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
695ff37b 572
d62a17ae 573 prefix->state = EIGRP_FSM_STATE_PASSIVE;
695ff37b
DS
574 prefix->distance = prefix->rdistance = ne->distance;
575 prefix->reported_metric = ne->total_metric;
d62a17ae 576 prefix->fdistance = prefix->fdistance > prefix->distance
577 ? prefix->distance
578 : prefix->fdistance;
579 if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2) {
580 struct list *successors = eigrp_topology_get_successor(prefix);
581
582 assert(successors); // Having a spoon and all you need is a
583 // knife
695ff37b 584 ne = listnode_head(successors);
996c9314 585 eigrp_send_reply(ne->adv_router, prefix);
d62a17ae 586
6a154c88 587 list_delete(&successors);
d62a17ae 588 }
589 prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
590 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
591 eigrp_topology_update_node_flags(prefix);
592 eigrp_update_routing_table(prefix);
593 eigrp_update_topology_table_prefix(eigrp->topology_table, prefix);
594
595 return 1;
7f57883e
DS
596}
597
f9e5c9ca
DS
598int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
599{
d62a17ae 600 struct eigrp *eigrp = msg->eigrp;
601 struct eigrp_prefix_entry *prefix = msg->prefix;
255ab940 602 struct eigrp_nexthop_entry *best_successor;
d62a17ae 603 struct list *successors = eigrp_topology_get_successor(prefix);
604
605 assert(successors); // Routing without a stack
606
607 prefix->state = prefix->state == EIGRP_FSM_STATE_ACTIVE_0
608 ? EIGRP_FSM_STATE_ACTIVE_1
609 : EIGRP_FSM_STATE_ACTIVE_3;
695ff37b
DS
610
611 best_successor = listnode_head(successors);
d62a17ae 612 prefix->rdistance = prefix->distance = best_successor->distance;
613 prefix->reported_metric = best_successor->total_metric;
614
615 if (eigrp_nbr_count_get()) {
616 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
617 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
618 } else {
619 eigrp_fsm_event_lr(msg); // in the case that there are no more
620 // neighbors left
621 }
622
6a154c88 623 list_delete(&successors);
d62a17ae 624
625 return 1;
7f57883e
DS
626}
627
f9e5c9ca
DS
628int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
629{
d62a17ae 630 struct list *successors = eigrp_topology_get_successor(msg->prefix);
255ab940 631 struct eigrp_nexthop_entry *ne;
f6709c16 632
d62a17ae 633 assert(successors); // Cats and no Dogs
f6709c16 634
695ff37b 635 ne = listnode_head(successors);
d62a17ae 636 msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
695ff37b 637 msg->prefix->distance = ne->distance;
f6709c16 638
6a154c88 639 list_delete(&successors);
d62a17ae 640 return 1;
7f57883e 641}