2 * EIGRPd Finite State Machine (DUAL).
3 * Copyright (C) 2013-2014
11 * This file is part of GNU Zebra.
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
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.
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
27 * This file contains functions for executing logic of finite state machine
32 * +=====================================+
36 * +=====================================+
38 * (3)| | (1)| | (1)| |
39 * | (0)| | (3)| | (2)|
40 * | | | | | +---------------+
42 * +--------+ | | | +-----------------+ \
47 * +===========+ (6) +===========+ +===========+ (6) +===========+
48 * | |------->| | (5) | |-------->| |
49 * | | (4) | |------>| | (4) | |
50 * | ACTIVE 0 |<-------| ACTIVE 1 | | ACTIVE 2 |<--------| ACTIVE 3
52 * +--| | +--| | +--| | +--| |
53 * | +===========+ | +===========+ | +===========+ |
55 * | ^ |(5) | ^ | ^ ^ | ^
56 * | | +---------|------|------------|----+ | | |
57 * +-------+ +------+ +---------+ +---------+
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
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"
95 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message
*);
96 int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message
*);
97 int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message
*);
98 int eigrp_fsm_event_lr(struct eigrp_fsm_action_message
*);
99 int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message
*);
100 int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message
*);
101 int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message
*);
102 int eigrp_fsm_event_qact(struct eigrp_fsm_action_message
*);
104 //---------------------------------------------------------------------
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.
114 int (*func
)(struct eigrp_fsm_action_message
*);
115 } NSM
[EIGRP_FSM_STATE_MAX
][EIGRP_FSM_EVENT_MAX
] = {
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 */
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 */
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 */
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 */
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 */
174 * Main function in which are make decisions which event occurred.
175 * msg - argument of type struct eigrp_fsm_action_message contain
176 * details about what happen
178 * Return number of occurred event (arrow in diagram).
181 int eigrp_get_fsm_event(struct eigrp_fsm_action_message
*msg
)
183 // Loading base information from message
184 // struct eigrp *eigrp = msg->eigrp;
185 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
186 struct eigrp_neighbor_entry
*entry
= msg
->entry
;
187 u_char actual_state
= prefix
->state
;
190 entry
= eigrp_neighbor_entry_new();
191 entry
->adv_router
= msg
->adv_router
;
192 entry
->ei
= msg
->adv_router
->ei
;
193 entry
->prefix
= prefix
;
197 // Dividing by actual state of prefix's FSM
198 switch (actual_state
) {
199 case EIGRP_FSM_STATE_PASSIVE
: {
200 // Calculate resultant metrics and insert to correct position in
202 eigrp_topology_update_distance(msg
);
204 struct eigrp_neighbor_entry
*head
=
205 (struct eigrp_neighbor_entry
*)
206 entry
->prefix
->entries
->head
->data
;
207 // zlog_info ("flag: %d rdist: %u dist: %u pfdist: %u pdist:
208 // %u", head->flags, head->reported_distance, head->distance,
209 // prefix->fdistance, prefix->distance);
210 if (head
->reported_distance
< prefix
->fdistance
) {
211 return EIGRP_FSM_KEEP_STATE
;
214 * if best entry doesn't satisfy feasibility condition it means
215 * move to active state
216 * dependently if it was query from successor
219 if (msg
->packet_type
== EIGRP_OPC_QUERY
) {
220 return EIGRP_FSM_EVENT_Q_FCN
;
222 return EIGRP_FSM_EVENT_NQ_FCN
;
228 case EIGRP_FSM_STATE_ACTIVE_0
: {
229 eigrp_topology_update_distance(msg
);
231 if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
232 listnode_delete(prefix
->rij
, entry
->adv_router
);
233 if (prefix
->rij
->count
) {
234 return EIGRP_FSM_KEEP_STATE
;
236 zlog_info("All reply received\n");
237 if (((struct eigrp_neighbor_entry
*)
238 prefix
->entries
->head
->data
)
240 < prefix
->fdistance
) {
241 return EIGRP_FSM_EVENT_LR_FCS
;
244 return EIGRP_FSM_EVENT_LR_FCN
;
246 } else if (msg
->packet_type
== EIGRP_OPC_QUERY
248 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
249 return EIGRP_FSM_EVENT_QACT
;
252 return EIGRP_FSM_KEEP_STATE
;
256 case EIGRP_FSM_STATE_ACTIVE_1
: {
257 int change
= eigrp_topology_update_distance(msg
);
259 if (msg
->packet_type
== EIGRP_OPC_QUERY
260 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
261 return EIGRP_FSM_EVENT_QACT
;
262 } else if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
263 listnode_delete(prefix
->rij
, entry
->adv_router
);
267 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
268 return EIGRP_FSM_EVENT_DINC
;
269 } else if (prefix
->rij
->count
) {
270 return EIGRP_FSM_KEEP_STATE
;
272 zlog_info("All reply received\n");
273 return EIGRP_FSM_EVENT_LR
;
275 } else if (msg
->packet_type
== EIGRP_OPC_UPDATE
&& change
== 1
277 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
278 return EIGRP_FSM_EVENT_DINC
;
280 return EIGRP_FSM_KEEP_STATE
;
284 case EIGRP_FSM_STATE_ACTIVE_2
: {
285 eigrp_topology_update_distance(msg
);
287 if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
288 listnode_delete(prefix
->rij
, entry
->adv_router
);
289 if (prefix
->rij
->count
) {
290 return EIGRP_FSM_KEEP_STATE
;
292 zlog_info("All reply received\n");
293 if (((struct eigrp_neighbor_entry
*)
294 prefix
->entries
->head
->data
)
296 < prefix
->fdistance
) {
297 return EIGRP_FSM_EVENT_LR_FCS
;
300 return EIGRP_FSM_EVENT_LR_FCN
;
303 return EIGRP_FSM_KEEP_STATE
;
307 case EIGRP_FSM_STATE_ACTIVE_3
: {
308 int change
= eigrp_topology_update_distance(msg
);
310 if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
311 listnode_delete(prefix
->rij
, entry
->adv_router
);
315 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
316 return EIGRP_FSM_EVENT_DINC
;
317 } else if (prefix
->rij
->count
) {
318 return EIGRP_FSM_KEEP_STATE
;
320 zlog_info("All reply received\n");
321 return EIGRP_FSM_EVENT_LR
;
323 } else if (msg
->packet_type
== EIGRP_OPC_UPDATE
&& change
== 1
325 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
326 return EIGRP_FSM_EVENT_DINC
;
328 return EIGRP_FSM_KEEP_STATE
;
334 return EIGRP_FSM_KEEP_STATE
;
338 * Function made to execute in separate thread.
339 * Load argument from thread and execute proper NSM function
341 int eigrp_fsm_event(struct eigrp_fsm_action_message
*msg
, int event
)
343 zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s\n",
344 msg
->eigrp
->AS
, msg
->prefix
->state
, event
,
345 eigrp_topology_ip_string(msg
->prefix
));
346 (*(NSM
[msg
->prefix
->state
][event
].func
))(msg
);
352 * Function of event 0.
355 int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message
*msg
)
357 struct eigrp
*eigrp
= msg
->eigrp
;
358 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
359 struct list
*successors
= eigrp_topology_get_successor(prefix
);
361 assert(successors
); // If this is NULL we have shit the bed, fun huh?
363 prefix
->state
= EIGRP_FSM_STATE_ACTIVE_1
;
364 prefix
->rdistance
= prefix
->distance
= prefix
->fdistance
=
365 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
367 prefix
->reported_metric
=
368 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
371 if (eigrp_nbr_count_get()) {
372 prefix
->req_action
|= EIGRP_FSM_NEED_QUERY
;
373 listnode_add(eigrp
->topology_changes_internalIPV4
, prefix
);
375 eigrp_fsm_event_lr(msg
); // in the case that there are no more
379 list_delete(successors
);
384 int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message
*msg
)
386 struct eigrp
*eigrp
= msg
->eigrp
;
387 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
388 struct list
*successors
= eigrp_topology_get_successor(prefix
);
390 assert(successors
); // If this is NULL somebody poked us in the eye.
392 prefix
->state
= EIGRP_FSM_STATE_ACTIVE_3
;
393 prefix
->rdistance
= prefix
->distance
= prefix
->fdistance
=
394 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
396 prefix
->reported_metric
=
397 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
399 if (eigrp_nbr_count_get()) {
400 prefix
->req_action
|= EIGRP_FSM_NEED_QUERY
;
401 listnode_add(eigrp
->topology_changes_internalIPV4
, prefix
);
403 eigrp_fsm_event_lr(msg
); // in the case that there are no more
407 list_delete(successors
);
412 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message
*msg
)
414 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
416 if (prefix
->state
== EIGRP_FSM_STATE_PASSIVE
) {
417 if (!eigrp_metrics_is_same(prefix
->reported_metric
,
418 ((struct eigrp_neighbor_entry
*)
419 prefix
->entries
->head
->data
)
421 prefix
->rdistance
= prefix
->fdistance
=
423 ((struct eigrp_neighbor_entry
*)
424 prefix
->entries
->head
->data
)
426 prefix
->reported_metric
=
427 ((struct eigrp_neighbor_entry
*)
428 prefix
->entries
->head
->data
)
430 if (msg
->packet_type
== EIGRP_OPC_QUERY
)
431 eigrp_send_reply(msg
->adv_router
, prefix
);
432 prefix
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
434 (eigrp_lookup())->topology_changes_internalIPV4
,
437 eigrp_topology_update_node_flags(prefix
);
438 eigrp_update_routing_table(prefix
);
441 if (msg
->packet_type
== EIGRP_OPC_QUERY
)
442 eigrp_send_reply(msg
->adv_router
, prefix
);
447 int eigrp_fsm_event_lr(struct eigrp_fsm_action_message
*msg
)
449 struct eigrp
*eigrp
= msg
->eigrp
;
450 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
451 prefix
->fdistance
= prefix
->distance
= prefix
->rdistance
=
452 ((struct eigrp_neighbor_entry
*)(prefix
->entries
->head
->data
))
454 prefix
->reported_metric
=
455 ((struct eigrp_neighbor_entry
*)(prefix
->entries
->head
->data
))
458 if (prefix
->state
== EIGRP_FSM_STATE_ACTIVE_3
) {
459 struct list
*successors
= eigrp_topology_get_successor(prefix
);
461 assert(successors
); // It's like Napolean and Waterloo
464 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
467 list_delete(successors
);
470 prefix
->state
= EIGRP_FSM_STATE_PASSIVE
;
471 prefix
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
472 listnode_add(eigrp
->topology_changes_internalIPV4
, prefix
);
473 eigrp_topology_update_node_flags(prefix
);
474 eigrp_update_routing_table(prefix
);
475 eigrp_update_topology_table_prefix(eigrp
->topology_table
, prefix
);
480 int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message
*msg
)
482 struct list
*successors
= eigrp_topology_get_successor(msg
->prefix
);
484 assert(successors
); // Trump and his big hands
486 msg
->prefix
->state
= msg
->prefix
->state
== EIGRP_FSM_STATE_ACTIVE_1
487 ? EIGRP_FSM_STATE_ACTIVE_0
488 : EIGRP_FSM_STATE_ACTIVE_2
;
489 msg
->prefix
->distance
=
490 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
492 if (!msg
->prefix
->rij
->count
)
493 (*(NSM
[msg
->prefix
->state
][eigrp_get_fsm_event(msg
)].func
))(
497 list_delete(successors
);
501 int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message
*msg
)
503 struct eigrp
*eigrp
= msg
->eigrp
;
504 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
505 prefix
->state
= EIGRP_FSM_STATE_PASSIVE
;
506 prefix
->distance
= prefix
->rdistance
=
507 ((struct eigrp_neighbor_entry
*)(prefix
->entries
->head
->data
))
509 prefix
->reported_metric
=
510 ((struct eigrp_neighbor_entry
*)(prefix
->entries
->head
->data
))
512 prefix
->fdistance
= prefix
->fdistance
> prefix
->distance
515 if (prefix
->state
== EIGRP_FSM_STATE_ACTIVE_2
) {
516 struct list
*successors
= eigrp_topology_get_successor(prefix
);
518 assert(successors
); // Having a spoon and all you need is a
522 ((struct eigrp_neighbor_entry
*)successors
->head
->data
)
526 list_delete(successors
);
528 prefix
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
529 listnode_add(eigrp
->topology_changes_internalIPV4
, prefix
);
530 eigrp_topology_update_node_flags(prefix
);
531 eigrp_update_routing_table(prefix
);
532 eigrp_update_topology_table_prefix(eigrp
->topology_table
, prefix
);
537 int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message
*msg
)
539 struct eigrp
*eigrp
= msg
->eigrp
;
540 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
541 struct list
*successors
= eigrp_topology_get_successor(prefix
);
543 assert(successors
); // Routing without a stack
545 prefix
->state
= prefix
->state
== EIGRP_FSM_STATE_ACTIVE_0
546 ? EIGRP_FSM_STATE_ACTIVE_1
547 : EIGRP_FSM_STATE_ACTIVE_3
;
548 struct eigrp_neighbor_entry
*best_successor
=
549 ((struct eigrp_neighbor_entry
*)(successors
->head
->data
));
550 prefix
->rdistance
= prefix
->distance
= best_successor
->distance
;
551 prefix
->reported_metric
= best_successor
->total_metric
;
553 if (eigrp_nbr_count_get()) {
554 prefix
->req_action
|= EIGRP_FSM_NEED_QUERY
;
555 listnode_add(eigrp
->topology_changes_internalIPV4
, prefix
);
557 eigrp_fsm_event_lr(msg
); // in the case that there are no more
561 list_delete(successors
);
566 int eigrp_fsm_event_qact(struct eigrp_fsm_action_message
*msg
)
568 struct list
*successors
= eigrp_topology_get_successor(msg
->prefix
);
570 assert(successors
); // Cats and no Dogs
572 msg
->prefix
->state
= EIGRP_FSM_STATE_ACTIVE_2
;
573 msg
->prefix
->distance
=
574 ((struct eigrp_neighbor_entry
*)(successors
->head
->data
))
577 list_delete(successors
);