]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_fsm.c
*: reindent
[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 <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 */
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 *);
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 */
113 struct {
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 };
172
173 /*
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
177 *
178 * Return number of occurred event (arrow in diagram).
179 *
180 */
181 int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
182 {
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;
188
189 if (entry == NULL) {
190 entry = eigrp_neighbor_entry_new();
191 entry->adv_router = msg->adv_router;
192 entry->ei = msg->adv_router->ei;
193 entry->prefix = prefix;
194 msg->entry = entry;
195 }
196
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
201 // entries list
202 eigrp_topology_update_distance(msg);
203
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;
212 }
213 /*
214 * if best entry doesn't satisfy feasibility condition it means
215 * move to active state
216 * dependently if it was query from successor
217 */
218 else {
219 if (msg->packet_type == EIGRP_OPC_QUERY) {
220 return EIGRP_FSM_EVENT_Q_FCN;
221 } else {
222 return EIGRP_FSM_EVENT_NQ_FCN;
223 }
224 }
225
226 break;
227 }
228 case EIGRP_FSM_STATE_ACTIVE_0: {
229 eigrp_topology_update_distance(msg);
230
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;
235 } else {
236 zlog_info("All reply received\n");
237 if (((struct eigrp_neighbor_entry *)
238 prefix->entries->head->data)
239 ->reported_distance
240 < prefix->fdistance) {
241 return EIGRP_FSM_EVENT_LR_FCS;
242 }
243
244 return EIGRP_FSM_EVENT_LR_FCN;
245 }
246 } else if (msg->packet_type == EIGRP_OPC_QUERY
247 && (entry->flags
248 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
249 return EIGRP_FSM_EVENT_QACT;
250 }
251
252 return EIGRP_FSM_KEEP_STATE;
253
254 break;
255 }
256 case EIGRP_FSM_STATE_ACTIVE_1: {
257 int change = eigrp_topology_update_distance(msg);
258
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);
264
265 if (change == 1
266 && (entry->flags
267 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
268 return EIGRP_FSM_EVENT_DINC;
269 } else if (prefix->rij->count) {
270 return EIGRP_FSM_KEEP_STATE;
271 } else {
272 zlog_info("All reply received\n");
273 return EIGRP_FSM_EVENT_LR;
274 }
275 } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1
276 && (entry->flags
277 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
278 return EIGRP_FSM_EVENT_DINC;
279 }
280 return EIGRP_FSM_KEEP_STATE;
281
282 break;
283 }
284 case EIGRP_FSM_STATE_ACTIVE_2: {
285 eigrp_topology_update_distance(msg);
286
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;
291 } else {
292 zlog_info("All reply received\n");
293 if (((struct eigrp_neighbor_entry *)
294 prefix->entries->head->data)
295 ->reported_distance
296 < prefix->fdistance) {
297 return EIGRP_FSM_EVENT_LR_FCS;
298 }
299
300 return EIGRP_FSM_EVENT_LR_FCN;
301 }
302 }
303 return EIGRP_FSM_KEEP_STATE;
304
305 break;
306 }
307 case EIGRP_FSM_STATE_ACTIVE_3: {
308 int change = eigrp_topology_update_distance(msg);
309
310 if (msg->packet_type == EIGRP_OPC_REPLY) {
311 listnode_delete(prefix->rij, entry->adv_router);
312
313 if (change == 1
314 && (entry->flags
315 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
316 return EIGRP_FSM_EVENT_DINC;
317 } else if (prefix->rij->count) {
318 return EIGRP_FSM_KEEP_STATE;
319 } else {
320 zlog_info("All reply received\n");
321 return EIGRP_FSM_EVENT_LR;
322 }
323 } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1
324 && (entry->flags
325 & EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG)) {
326 return EIGRP_FSM_EVENT_DINC;
327 }
328 return EIGRP_FSM_KEEP_STATE;
329
330 break;
331 }
332 }
333
334 return EIGRP_FSM_KEEP_STATE;
335 }
336
337 /*
338 * Function made to execute in separate thread.
339 * Load argument from thread and execute proper NSM function
340 */
341 int eigrp_fsm_event(struct eigrp_fsm_action_message *msg, int event)
342 {
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);
347
348 return 1;
349 }
350
351 /*
352 * Function of event 0.
353 *
354 */
355 int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
356 {
357 struct eigrp *eigrp = msg->eigrp;
358 struct eigrp_prefix_entry *prefix = msg->prefix;
359 struct list *successors = eigrp_topology_get_successor(prefix);
360
361 assert(successors); // If this is NULL we have shit the bed, fun huh?
362
363 prefix->state = EIGRP_FSM_STATE_ACTIVE_1;
364 prefix->rdistance = prefix->distance = prefix->fdistance =
365 ((struct eigrp_neighbor_entry *)successors->head->data)
366 ->distance;
367 prefix->reported_metric =
368 ((struct eigrp_neighbor_entry *)successors->head->data)
369 ->total_metric;
370
371 if (eigrp_nbr_count_get()) {
372 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
373 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
374 } else {
375 eigrp_fsm_event_lr(msg); // in the case that there are no more
376 // neighbors left
377 }
378
379 list_delete(successors);
380
381 return 1;
382 }
383
384 int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
385 {
386 struct eigrp *eigrp = msg->eigrp;
387 struct eigrp_prefix_entry *prefix = msg->prefix;
388 struct list *successors = eigrp_topology_get_successor(prefix);
389
390 assert(successors); // If this is NULL somebody poked us in the eye.
391
392 prefix->state = EIGRP_FSM_STATE_ACTIVE_3;
393 prefix->rdistance = prefix->distance = prefix->fdistance =
394 ((struct eigrp_neighbor_entry *)successors->head->data)
395 ->distance;
396 prefix->reported_metric =
397 ((struct eigrp_neighbor_entry *)successors->head->data)
398 ->total_metric;
399 if (eigrp_nbr_count_get()) {
400 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
401 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
402 } else {
403 eigrp_fsm_event_lr(msg); // in the case that there are no more
404 // neighbors left
405 }
406
407 list_delete(successors);
408
409 return 1;
410 }
411
412 int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
413 {
414 struct eigrp_prefix_entry *prefix = msg->prefix;
415
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)
420 ->total_metric)) {
421 prefix->rdistance = prefix->fdistance =
422 prefix->distance =
423 ((struct eigrp_neighbor_entry *)
424 prefix->entries->head->data)
425 ->distance;
426 prefix->reported_metric =
427 ((struct eigrp_neighbor_entry *)
428 prefix->entries->head->data)
429 ->total_metric;
430 if (msg->packet_type == EIGRP_OPC_QUERY)
431 eigrp_send_reply(msg->adv_router, prefix);
432 prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
433 listnode_add(
434 (eigrp_lookup())->topology_changes_internalIPV4,
435 prefix);
436 }
437 eigrp_topology_update_node_flags(prefix);
438 eigrp_update_routing_table(prefix);
439 }
440
441 if (msg->packet_type == EIGRP_OPC_QUERY)
442 eigrp_send_reply(msg->adv_router, prefix);
443
444 return 1;
445 }
446
447 int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
448 {
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))
453 ->distance;
454 prefix->reported_metric =
455 ((struct eigrp_neighbor_entry *)(prefix->entries->head->data))
456 ->total_metric;
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
463 eigrp_send_reply(
464 ((struct eigrp_neighbor_entry *)successors->head->data)
465 ->adv_router,
466 prefix);
467 list_delete(successors);
468 }
469
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);
476
477 return 1;
478 }
479
480 int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
481 {
482 struct list *successors = eigrp_topology_get_successor(msg->prefix);
483
484 assert(successors); // Trump and his big hands
485
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)
491 ->distance;
492 if (!msg->prefix->rij->count)
493 (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))(
494 msg);
495
496
497 list_delete(successors);
498 return 1;
499 }
500
501 int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
502 {
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))
508 ->distance;
509 prefix->reported_metric =
510 ((struct eigrp_neighbor_entry *)(prefix->entries->head->data))
511 ->total_metric;
512 prefix->fdistance = prefix->fdistance > prefix->distance
513 ? prefix->distance
514 : prefix->fdistance;
515 if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2) {
516 struct list *successors = eigrp_topology_get_successor(prefix);
517
518 assert(successors); // Having a spoon and all you need is a
519 // knife
520
521 eigrp_send_reply(
522 ((struct eigrp_neighbor_entry *)successors->head->data)
523 ->adv_router,
524 prefix);
525
526 list_delete(successors);
527 }
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);
533
534 return 1;
535 }
536
537 int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
538 {
539 struct eigrp *eigrp = msg->eigrp;
540 struct eigrp_prefix_entry *prefix = msg->prefix;
541 struct list *successors = eigrp_topology_get_successor(prefix);
542
543 assert(successors); // Routing without a stack
544
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;
552
553 if (eigrp_nbr_count_get()) {
554 prefix->req_action |= EIGRP_FSM_NEED_QUERY;
555 listnode_add(eigrp->topology_changes_internalIPV4, prefix);
556 } else {
557 eigrp_fsm_event_lr(msg); // in the case that there are no more
558 // neighbors left
559 }
560
561 list_delete(successors);
562
563 return 1;
564 }
565
566 int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
567 {
568 struct list *successors = eigrp_topology_get_successor(msg->prefix);
569
570 assert(successors); // Cats and no Dogs
571
572 msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2;
573 msg->prefix->distance =
574 ((struct eigrp_neighbor_entry *)(successors->head->data))
575 ->distance;
576
577 list_delete(successors);
578 return 1;
579 }