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
24 * along with GNU Zebra; see the file COPYING. If not, write to the
25 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 * Boston, MA 02111-1307, USA.
29 * This file contains functions for executing logic of finite state machine
34 * +=====================================+
38 * +=====================================+
40 * (3)| | (1)| | (1)| |
41 * | (0)| | (3)| | (2)|
42 * | | | | | +---------------+
44 * +--------+ | | | +-----------------+ \
49 * +===========+ (6) +===========+ +===========+ (6) +===========+
50 * | |------->| | (5) | |-------->| |
51 * | | (4) | |------>| | (4) | |
52 * | ACTIVE 0 |<-------| ACTIVE 1 | | ACTIVE 2 |<--------| ACTIVE 3 |
53 * +--| | +--| | +--| | +--| |
54 * | +===========+ | +===========+ | +===========+ | +===========+
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
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"
97 eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message
*);
99 eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message
*);
101 eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message
*);
103 eigrp_fsm_event_lr(struct eigrp_fsm_action_message
*);
105 eigrp_fsm_event_dinc(struct eigrp_fsm_action_message
*);
107 eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message
*);
109 eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message
*);
111 eigrp_fsm_event_qact(struct eigrp_fsm_action_message
*);
113 //---------------------------------------------------------------------
116 * NSM - field of fields of struct containing one function each.
117 * Which function is used depends on actual state of FSM and occurred
118 * event(arrow in diagram). Usage:
119 * NSM[actual/starting state][occurred event].func
120 * Functions are should be executed within separate thread.
124 (*func
)(struct eigrp_fsm_action_message
*);
125 } NSM
[EIGRP_FSM_STATE_MAX
][EIGRP_FSM_EVENT_MAX
] = { {
127 { eigrp_fsm_event_nq_fcn
}, /* Event 0 */
128 { eigrp_fsm_event_keep_state
}, /* Event 1 */
129 { eigrp_fsm_event_q_fcn
}, /* Event 2 */
130 { eigrp_fsm_event_keep_state
}, /* Event 3 */
131 { eigrp_fsm_event_keep_state
}, /* Event 4 */
132 { eigrp_fsm_event_keep_state
}, /* Event 5 */
133 { eigrp_fsm_event_keep_state
}, /* Event 6 */
134 { eigrp_fsm_event_keep_state
}, /* Event 7 */
137 { eigrp_fsm_event_keep_state
}, /* Event 0 */
138 { eigrp_fsm_event_keep_state
}, /* Event 1 */
139 { eigrp_fsm_event_keep_state
}, /* Event 2 */
140 { eigrp_fsm_event_lr_fcs
}, /* Event 3 */
141 { eigrp_fsm_event_keep_state
}, /* Event 4 */
142 { eigrp_fsm_event_qact
}, /* Event 5 */
143 { eigrp_fsm_event_lr_fcn
}, /* Event 6 */
144 { eigrp_fsm_event_keep_state
}, /* Event 7 */
148 { eigrp_fsm_event_keep_state
}, /* Event 0 */
149 { eigrp_fsm_event_lr
}, /* Event 1 */
150 { eigrp_fsm_event_keep_state
}, /* Event 2 */
151 { eigrp_fsm_event_keep_state
}, /* Event 3 */
152 { eigrp_fsm_event_dinc
}, /* Event 4 */
153 { eigrp_fsm_event_qact
}, /* Event 5 */
154 { eigrp_fsm_event_keep_state
}, /* Event 6 */
155 { eigrp_fsm_event_keep_state
}, /* Event 7 */
158 { eigrp_fsm_event_keep_state
}, /* Event 0 */
159 { eigrp_fsm_event_keep_state
}, /* Event 1 */
160 { eigrp_fsm_event_keep_state
}, /* Event 2 */
161 { eigrp_fsm_event_lr_fcs
}, /* Event 3 */
162 { eigrp_fsm_event_keep_state
}, /* Event 4 */
163 { eigrp_fsm_event_keep_state
}, /* Event 5 */
164 { eigrp_fsm_event_lr_fcn
}, /* Event 6 */
165 { eigrp_fsm_event_keep_state
}, /* Event 7 */
168 { eigrp_fsm_event_keep_state
}, /* Event 0 */
169 { eigrp_fsm_event_lr
}, /* Event 1 */
170 { eigrp_fsm_event_keep_state
}, /* Event 2 */
171 { eigrp_fsm_event_keep_state
}, /* Event 3 */
172 { eigrp_fsm_event_dinc
}, /* Event 4 */
173 { eigrp_fsm_event_keep_state
}, /* Event 5 */
174 { eigrp_fsm_event_keep_state
}, /* Event 6 */
175 { eigrp_fsm_event_keep_state
}, /* Event 7 */
179 * Main function in which are make decisions which event occurred.
180 * msg - argument of type struct eigrp_fsm_action_message contain
181 * details about what happen
183 * Return number of occurred event (arrow in diagram).
186 int eigrp_get_fsm_event(struct eigrp_fsm_action_message
*msg
) {
187 // Loading base information from message
188 //struct eigrp *eigrp = msg->eigrp;
189 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
190 struct eigrp_neighbor_entry
*entry
= msg
->entry
;
191 u_char actual_state
= prefix
->state
;
194 entry
= eigrp_neighbor_entry_new();
195 entry
->adv_router
= msg
->adv_router
;
196 entry
->ei
= msg
->adv_router
->ei
;
197 entry
->prefix
= prefix
;
201 // Dividing by actual state of prefix's FSM
202 switch (actual_state
) {
203 case EIGRP_FSM_STATE_PASSIVE
: {
204 //Calculate resultant metrics and insert to correct position in entries list
205 eigrp_topology_update_distance(msg
);
207 struct eigrp_neighbor_entry
* head
=
208 (struct eigrp_neighbor_entry
*) entry
->prefix
->entries
->head
->data
;
209 //zlog_info ("flag: %d rdist: %u dist: %u pfdist: %u pdist: %u", head->flags, head->reported_distance, head->distance, 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 move to active state
215 * dependently if it was query from successor
218 if (msg
->packet_type
== EIGRP_OPC_QUERY
) {
219 return EIGRP_FSM_EVENT_Q_FCN
;
221 return EIGRP_FSM_EVENT_NQ_FCN
;
227 case EIGRP_FSM_STATE_ACTIVE_0
: {
228 eigrp_topology_update_distance(msg
);
230 if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
231 listnode_delete(prefix
->rij
, entry
->adv_router
);
232 if (prefix
->rij
->count
) {
233 return EIGRP_FSM_KEEP_STATE
;
235 zlog_info("All reply received\n");
236 if (((struct eigrp_neighbor_entry
*) prefix
->entries
->head
->data
)->reported_distance
237 < prefix
->fdistance
) {
238 return EIGRP_FSM_EVENT_LR_FCS
;
241 return EIGRP_FSM_EVENT_LR_FCN
;
243 } else if (msg
->packet_type
== EIGRP_OPC_QUERY
244 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
245 return EIGRP_FSM_EVENT_QACT
;
248 return EIGRP_FSM_KEEP_STATE
;
252 case EIGRP_FSM_STATE_ACTIVE_1
: {
253 int change
= eigrp_topology_update_distance(msg
);
255 if (msg
->packet_type
== EIGRP_OPC_QUERY
256 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
257 return EIGRP_FSM_EVENT_QACT
;
258 } else if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
259 listnode_delete(prefix
->rij
, entry
->adv_router
);
262 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
263 return EIGRP_FSM_EVENT_DINC
;
264 } else if (prefix
->rij
->count
) {
265 return EIGRP_FSM_KEEP_STATE
;
267 zlog_info("All reply received\n");
268 return EIGRP_FSM_EVENT_LR
;
270 } else if (msg
->packet_type
== EIGRP_OPC_UPDATE
&& change
== 1
271 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
272 return EIGRP_FSM_EVENT_DINC
;
274 return EIGRP_FSM_KEEP_STATE
;
278 case EIGRP_FSM_STATE_ACTIVE_2
: {
280 eigrp_topology_update_distance(msg
);
282 if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
283 listnode_delete(prefix
->rij
, entry
->adv_router
);
284 if (prefix
->rij
->count
) {
285 return EIGRP_FSM_KEEP_STATE
;
287 zlog_info("All reply received\n");
288 if (((struct eigrp_neighbor_entry
*) prefix
->entries
->head
->data
)->reported_distance
289 < prefix
->fdistance
) {
290 return EIGRP_FSM_EVENT_LR_FCS
;
293 return EIGRP_FSM_EVENT_LR_FCN
;
296 return EIGRP_FSM_KEEP_STATE
;
300 case EIGRP_FSM_STATE_ACTIVE_3
: {
302 int change
= eigrp_topology_update_distance(msg
);
304 if (msg
->packet_type
== EIGRP_OPC_REPLY
) {
305 listnode_delete(prefix
->rij
, entry
->adv_router
);
308 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
309 return EIGRP_FSM_EVENT_DINC
;
310 } else if (prefix
->rij
->count
) {
311 return EIGRP_FSM_KEEP_STATE
;
313 zlog_info("All reply received\n");
314 return EIGRP_FSM_EVENT_LR
;
316 } else if (msg
->packet_type
== EIGRP_OPC_UPDATE
&& change
== 1
317 && (entry
->flags
& EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG
)) {
318 return EIGRP_FSM_EVENT_DINC
;
320 return EIGRP_FSM_KEEP_STATE
;
326 return EIGRP_FSM_KEEP_STATE
;
330 * Function made to execute in separate thread.
331 * Load argument from thread and execute proper NSM function
333 int eigrp_fsm_event(struct eigrp_fsm_action_message
*msg
, int event
) {
335 zlog_info("EIGRP AS: %d State: %d Event: %d Network: %s\n", msg
->eigrp
->AS
,
336 msg
->prefix
->state
, event
, eigrp_topology_ip_string(msg
->prefix
));
337 (*(NSM
[msg
->prefix
->state
][event
].func
))(msg
);
342 * Function of event 0.
345 int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message
*msg
) {
346 struct eigrp
*eigrp
= msg
->eigrp
;
347 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
348 struct list
*successors
= eigrp_topology_get_successor(prefix
);
349 prefix
->state
= EIGRP_FSM_STATE_ACTIVE_1
;
350 prefix
->rdistance
= prefix
->distance
= prefix
->fdistance
=
351 ((struct eigrp_neighbor_entry
*) successors
->head
->data
)->distance
;
352 prefix
->reported_metric
=
353 ((struct eigrp_neighbor_entry
*) successors
->head
->data
)->total_metric
;
355 if (eigrp_nbr_count_get()) {
356 prefix
->req_action
|= EIGRP_FSM_NEED_QUERY
;
357 listnode_add(eigrp
->topology_changes_internalIPV4
,prefix
);
359 eigrp_fsm_event_lr(msg
); //in the case that there are no more neighbors left
365 int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message
*msg
) {
366 struct eigrp
*eigrp
= msg
->eigrp
;
367 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
368 struct list
*successors
= eigrp_topology_get_successor(prefix
);
369 prefix
->state
= EIGRP_FSM_STATE_ACTIVE_3
;
370 prefix
->rdistance
= prefix
->distance
= prefix
->fdistance
=
371 ((struct eigrp_neighbor_entry
*) successors
->head
->data
)->distance
;
372 prefix
->reported_metric
=
373 ((struct eigrp_neighbor_entry
*) successors
->head
->data
)->total_metric
;
374 if (eigrp_nbr_count_get()) {
375 prefix
->req_action
|= EIGRP_FSM_NEED_QUERY
;
376 listnode_add(eigrp
->topology_changes_internalIPV4
,prefix
);
378 eigrp_fsm_event_lr(msg
); //in the case that there are no more neighbors left
384 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message
*msg
) {
386 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
388 if (prefix
->state
== EIGRP_FSM_STATE_PASSIVE
) {
389 if (!eigrp_metrics_is_same(&prefix
->reported_metric
,
390 &((struct eigrp_neighbor_entry
*) prefix
->entries
->head
->data
)->total_metric
)) {
394 ((struct eigrp_neighbor_entry
*) prefix
->entries
->head
->data
)->distance
;
395 prefix
->reported_metric
=
396 ((struct eigrp_neighbor_entry
*) prefix
->entries
->head
->data
)->total_metric
;
397 if (msg
->packet_type
== EIGRP_OPC_QUERY
)
398 eigrp_send_reply(msg
->adv_router
, prefix
);
399 prefix
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
400 listnode_add((eigrp_lookup())->topology_changes_internalIPV4
,prefix
);
402 eigrp_topology_update_node_flags(prefix
);
403 eigrp_update_routing_table(prefix
);
406 if (msg
->packet_type
== EIGRP_OPC_QUERY
)
407 eigrp_send_reply(msg
->adv_router
, prefix
);
412 int eigrp_fsm_event_lr(struct eigrp_fsm_action_message
*msg
) {
413 struct eigrp
*eigrp
= msg
->eigrp
;
414 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
418 ((struct eigrp_neighbor_entry
*) (prefix
->entries
->head
->data
))->distance
;
419 prefix
->reported_metric
=
420 ((struct eigrp_neighbor_entry
*) (prefix
->entries
->head
->data
))->total_metric
;
421 if (prefix
->state
== EIGRP_FSM_STATE_ACTIVE_3
)
423 ((struct eigrp_neighbor_entry
*) (eigrp_topology_get_successor(
424 prefix
)->head
->data
))->adv_router
, prefix
);
425 prefix
->state
= EIGRP_FSM_STATE_PASSIVE
;
426 prefix
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
427 listnode_add(eigrp
->topology_changes_internalIPV4
,prefix
);
428 eigrp_topology_update_node_flags(prefix
);
429 eigrp_update_routing_table(prefix
);
430 eigrp_update_topology_table_prefix(eigrp
->topology_table
, prefix
);
435 int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message
*msg
) {
438 msg
->prefix
->state
== EIGRP_FSM_STATE_ACTIVE_1
?
439 EIGRP_FSM_STATE_ACTIVE_0
: EIGRP_FSM_STATE_ACTIVE_2
;
440 msg
->prefix
->distance
=
441 ((struct eigrp_neighbor_entry
*) (eigrp_topology_get_successor(
442 msg
->prefix
)->head
->data
))->distance
;
443 if (!msg
->prefix
->rij
->count
) {
444 (*(NSM
[msg
->prefix
->state
][eigrp_get_fsm_event(msg
)].func
))(msg
);
450 int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message
*msg
) {
451 struct eigrp
*eigrp
= msg
->eigrp
;
452 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
453 prefix
->state
= EIGRP_FSM_STATE_PASSIVE
;
456 ((struct eigrp_neighbor_entry
*) (prefix
->entries
->head
->data
))->distance
;
457 prefix
->reported_metric
=
458 ((struct eigrp_neighbor_entry
*) (prefix
->entries
->head
->data
))->total_metric
;
460 prefix
->fdistance
> prefix
->distance
?
461 prefix
->distance
: prefix
->fdistance
;
462 if (prefix
->state
== EIGRP_FSM_STATE_ACTIVE_2
)
464 ((struct eigrp_neighbor_entry
*) (eigrp_topology_get_successor(
465 prefix
)->head
->data
))->adv_router
, prefix
);
466 prefix
->req_action
|= EIGRP_FSM_NEED_UPDATE
;
467 listnode_add(eigrp
->topology_changes_internalIPV4
,prefix
);
468 eigrp_topology_update_node_flags(prefix
);
469 eigrp_update_routing_table(prefix
);
470 eigrp_update_topology_table_prefix(eigrp
->topology_table
, prefix
);
475 int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message
*msg
) {
476 struct eigrp
*eigrp
= msg
->eigrp
;
477 struct eigrp_prefix_entry
*prefix
= msg
->prefix
;
479 prefix
->state
== EIGRP_FSM_STATE_ACTIVE_0
?
480 EIGRP_FSM_STATE_ACTIVE_1
: EIGRP_FSM_STATE_ACTIVE_3
;
481 struct eigrp_neighbor_entry
*best_successor
=
482 ((struct eigrp_neighbor_entry
*) (eigrp_topology_get_successor(
483 prefix
)->head
->data
));
484 prefix
->rdistance
= prefix
->distance
= best_successor
->distance
;
485 prefix
->reported_metric
= best_successor
->total_metric
;
486 if (eigrp_nbr_count_get()) {
487 prefix
->req_action
|= EIGRP_FSM_NEED_QUERY
;
488 listnode_add(eigrp
->topology_changes_internalIPV4
,prefix
);
490 eigrp_fsm_event_lr(msg
); //in the case that there are no more neighbors left
496 int eigrp_fsm_event_qact(struct eigrp_fsm_action_message
*msg
) {
497 msg
->prefix
->state
= EIGRP_FSM_STATE_ACTIVE_2
;
498 msg
->prefix
->distance
=
499 ((struct eigrp_neighbor_entry
*) (eigrp_topology_get_successor(
500 msg
->prefix
)->head
->data
))->distance
;