]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | */ | |
f9e5c9ca DS |
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 *); | |
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 | */ | |
113 | struct { | |
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 | |
5cc74ec1 DS |
173 | static const char *prefix_state2str(enum eigrp_fsm_states state) |
174 | { | |
175 | switch (state) { | |
176 | case EIGRP_FSM_STATE_PASSIVE: | |
177 | return "Passive"; | |
178 | case EIGRP_FSM_STATE_ACTIVE_0: | |
179 | return "Active oij0"; | |
180 | case EIGRP_FSM_STATE_ACTIVE_1: | |
181 | return "Active oij1"; | |
182 | case EIGRP_FSM_STATE_ACTIVE_2: | |
183 | return "Active oij2"; | |
184 | case EIGRP_FSM_STATE_ACTIVE_3: | |
185 | return "Active oij3"; | |
186 | } | |
187 | ||
188 | return "Unknown"; | |
189 | } | |
190 | ||
7f57883e DS |
191 | /* |
192 | * Main function in which are make decisions which event occurred. | |
193 | * msg - argument of type struct eigrp_fsm_action_message contain | |
194 | * details about what happen | |
195 | * | |
196 | * Return number of occurred event (arrow in diagram). | |
197 | * | |
198 | */ | |
6118272f | 199 | static int eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg) |
f9e5c9ca | 200 | { |
d62a17ae | 201 | // Loading base information from message |
202 | // struct eigrp *eigrp = msg->eigrp; | |
203 | struct eigrp_prefix_entry *prefix = msg->prefix; | |
255ab940 | 204 | struct eigrp_nexthop_entry *entry = msg->entry; |
d62a17ae | 205 | u_char actual_state = prefix->state; |
748a2ba4 | 206 | enum metric_change change; |
d62a17ae | 207 | |
208 | if (entry == NULL) { | |
255ab940 | 209 | entry = eigrp_nexthop_entry_new(); |
d62a17ae | 210 | entry->adv_router = msg->adv_router; |
211 | entry->ei = msg->adv_router->ei; | |
212 | entry->prefix = prefix; | |
213 | msg->entry = entry; | |
214 | } | |
215 | ||
748a2ba4 DS |
216 | /* |
217 | * Calculate resultant metrics and insert to correct position | |
218 | * in entries list | |
219 | */ | |
220 | change = eigrp_topology_update_distance(msg); | |
221 | ||
d62a17ae | 222 | switch (actual_state) { |
223 | case EIGRP_FSM_STATE_PASSIVE: { | |
255ab940 | 224 | struct eigrp_nexthop_entry *head = |
695ff37b | 225 | listnode_head(prefix->entries); |
748a2ba4 | 226 | |
d62a17ae | 227 | if (head->reported_distance < prefix->fdistance) { |
228 | return EIGRP_FSM_KEEP_STATE; | |
229 | } | |
230 | /* | |
231 | * if best entry doesn't satisfy feasibility condition it means | |
232 | * move to active state | |
233 | * dependently if it was query from successor | |
234 | */ | |
9a8d52a4 DS |
235 | if (msg->packet_type == EIGRP_OPC_QUERY) { |
236 | return EIGRP_FSM_EVENT_Q_FCN; | |
237 | } else { | |
238 | return EIGRP_FSM_EVENT_NQ_FCN; | |
d62a17ae | 239 | } |
240 | ||
241 | break; | |
242 | } | |
243 | case EIGRP_FSM_STATE_ACTIVE_0: { | |
d62a17ae | 244 | if (msg->packet_type == EIGRP_OPC_REPLY) { |
255ab940 | 245 | struct eigrp_nexthop_entry *head = |
695ff37b | 246 | listnode_head(prefix->entries); |
9a8d52a4 | 247 | |
d62a17ae | 248 | listnode_delete(prefix->rij, entry->adv_router); |
9a8d52a4 | 249 | if (prefix->rij->count) |
d62a17ae | 250 | return EIGRP_FSM_KEEP_STATE; |
d62a17ae | 251 | |
9a8d52a4 DS |
252 | zlog_info("All reply received\n"); |
253 | if (head->reported_distance | |
254 | < prefix->fdistance) { | |
255 | return EIGRP_FSM_EVENT_LR_FCS; | |
d62a17ae | 256 | } |
9a8d52a4 DS |
257 | |
258 | return EIGRP_FSM_EVENT_LR_FCN; | |
d62a17ae | 259 | } else if (msg->packet_type == EIGRP_OPC_QUERY |
260 | && (entry->flags | |
255ab940 | 261 | & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { |
d62a17ae | 262 | return EIGRP_FSM_EVENT_QACT; |
263 | } | |
264 | ||
265 | return EIGRP_FSM_KEEP_STATE; | |
266 | ||
267 | break; | |
268 | } | |
269 | case EIGRP_FSM_STATE_ACTIVE_1: { | |
d62a17ae | 270 | if (msg->packet_type == EIGRP_OPC_QUERY |
255ab940 | 271 | && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { |
d62a17ae | 272 | return EIGRP_FSM_EVENT_QACT; |
273 | } else if (msg->packet_type == EIGRP_OPC_REPLY) { | |
274 | listnode_delete(prefix->rij, entry->adv_router); | |
275 | ||
748a2ba4 | 276 | if (change == METRIC_INCREASE |
d62a17ae | 277 | && (entry->flags |
255ab940 | 278 | & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { |
d62a17ae | 279 | return EIGRP_FSM_EVENT_DINC; |
280 | } else if (prefix->rij->count) { | |
281 | return EIGRP_FSM_KEEP_STATE; | |
282 | } else { | |
283 | zlog_info("All reply received\n"); | |
284 | return EIGRP_FSM_EVENT_LR; | |
285 | } | |
286 | } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1 | |
287 | && (entry->flags | |
255ab940 | 288 | & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { |
d62a17ae | 289 | return EIGRP_FSM_EVENT_DINC; |
290 | } | |
291 | return EIGRP_FSM_KEEP_STATE; | |
292 | ||
293 | break; | |
294 | } | |
295 | case EIGRP_FSM_STATE_ACTIVE_2: { | |
d62a17ae | 296 | if (msg->packet_type == EIGRP_OPC_REPLY) { |
255ab940 | 297 | struct eigrp_nexthop_entry *head = |
695ff37b | 298 | listnode_head(prefix->entries); |
9a8d52a4 | 299 | |
d62a17ae | 300 | listnode_delete(prefix->rij, entry->adv_router); |
301 | if (prefix->rij->count) { | |
302 | return EIGRP_FSM_KEEP_STATE; | |
303 | } else { | |
304 | zlog_info("All reply received\n"); | |
9a8d52a4 | 305 | if (head->reported_distance |
d62a17ae | 306 | < prefix->fdistance) { |
307 | return EIGRP_FSM_EVENT_LR_FCS; | |
308 | } | |
309 | ||
310 | return EIGRP_FSM_EVENT_LR_FCN; | |
311 | } | |
312 | } | |
313 | return EIGRP_FSM_KEEP_STATE; | |
314 | ||
315 | break; | |
316 | } | |
317 | case EIGRP_FSM_STATE_ACTIVE_3: { | |
d62a17ae | 318 | if (msg->packet_type == EIGRP_OPC_REPLY) { |
319 | listnode_delete(prefix->rij, entry->adv_router); | |
320 | ||
748a2ba4 | 321 | if (change == METRIC_INCREASE |
d62a17ae | 322 | && (entry->flags |
255ab940 | 323 | & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { |
d62a17ae | 324 | return EIGRP_FSM_EVENT_DINC; |
325 | } else if (prefix->rij->count) { | |
326 | return EIGRP_FSM_KEEP_STATE; | |
327 | } else { | |
328 | zlog_info("All reply received\n"); | |
329 | return EIGRP_FSM_EVENT_LR; | |
330 | } | |
331 | } else if (msg->packet_type == EIGRP_OPC_UPDATE && change == 1 | |
332 | && (entry->flags | |
255ab940 | 333 | & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) { |
d62a17ae | 334 | return EIGRP_FSM_EVENT_DINC; |
335 | } | |
336 | return EIGRP_FSM_KEEP_STATE; | |
337 | ||
338 | break; | |
339 | } | |
340 | } | |
341 | ||
342 | return EIGRP_FSM_KEEP_STATE; | |
7f57883e DS |
343 | } |
344 | ||
345 | /* | |
346 | * Function made to execute in separate thread. | |
347 | * Load argument from thread and execute proper NSM function | |
348 | */ | |
6118272f | 349 | int eigrp_fsm_event(struct eigrp_fsm_action_message *msg) |
f9e5c9ca | 350 | { |
6118272f | 351 | int event = eigrp_get_fsm_event(msg); |
5cc74ec1 DS |
352 | zlog_info("EIGRP AS: %d State: %s Event: %d Network: %s", |
353 | msg->eigrp->AS, prefix_state2str(msg->prefix->state), | |
354 | event, eigrp_topology_ip_string(msg->prefix)); | |
d62a17ae | 355 | (*(NSM[msg->prefix->state][event].func))(msg); |
7f57883e | 356 | |
d62a17ae | 357 | return 1; |
7f57883e | 358 | } |
f9e5c9ca | 359 | |
7f57883e DS |
360 | /* |
361 | * Function of event 0. | |
362 | * | |
363 | */ | |
f9e5c9ca DS |
364 | int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg) |
365 | { | |
d62a17ae | 366 | struct eigrp *eigrp = msg->eigrp; |
367 | struct eigrp_prefix_entry *prefix = msg->prefix; | |
368 | struct list *successors = eigrp_topology_get_successor(prefix); | |
255ab940 | 369 | struct eigrp_nexthop_entry *ne; |
d62a17ae | 370 | |
371 | assert(successors); // If this is NULL we have shit the bed, fun huh? | |
372 | ||
695ff37b | 373 | ne = listnode_head(successors); |
d62a17ae | 374 | prefix->state = EIGRP_FSM_STATE_ACTIVE_1; |
375 | prefix->rdistance = prefix->distance = prefix->fdistance = | |
695ff37b DS |
376 | ne->distance; |
377 | prefix->reported_metric = ne->total_metric; | |
d62a17ae | 378 | |
379 | if (eigrp_nbr_count_get()) { | |
380 | prefix->req_action |= EIGRP_FSM_NEED_QUERY; | |
381 | listnode_add(eigrp->topology_changes_internalIPV4, prefix); | |
382 | } else { | |
383 | eigrp_fsm_event_lr(msg); // in the case that there are no more | |
384 | // neighbors left | |
385 | } | |
386 | ||
affe9e99 | 387 | list_delete_and_null(&successors); |
d62a17ae | 388 | |
389 | return 1; | |
7f57883e DS |
390 | } |
391 | ||
f9e5c9ca DS |
392 | int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) |
393 | { | |
d62a17ae | 394 | struct eigrp *eigrp = msg->eigrp; |
395 | struct eigrp_prefix_entry *prefix = msg->prefix; | |
396 | struct list *successors = eigrp_topology_get_successor(prefix); | |
255ab940 | 397 | struct eigrp_nexthop_entry *ne; |
d62a17ae | 398 | |
399 | assert(successors); // If this is NULL somebody poked us in the eye. | |
400 | ||
695ff37b | 401 | ne = listnode_head(successors); |
d62a17ae | 402 | prefix->state = EIGRP_FSM_STATE_ACTIVE_3; |
403 | prefix->rdistance = prefix->distance = prefix->fdistance = | |
695ff37b DS |
404 | ne->distance; |
405 | prefix->reported_metric = ne->total_metric; | |
d62a17ae | 406 | if (eigrp_nbr_count_get()) { |
407 | prefix->req_action |= EIGRP_FSM_NEED_QUERY; | |
408 | listnode_add(eigrp->topology_changes_internalIPV4, prefix); | |
409 | } else { | |
410 | eigrp_fsm_event_lr(msg); // in the case that there are no more | |
411 | // neighbors left | |
412 | } | |
413 | ||
affe9e99 | 414 | list_delete_and_null(&successors); |
d62a17ae | 415 | |
416 | return 1; | |
7f57883e DS |
417 | } |
418 | ||
f9e5c9ca DS |
419 | int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) |
420 | { | |
d62a17ae | 421 | struct eigrp_prefix_entry *prefix = msg->prefix; |
255ab940 | 422 | struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); |
d62a17ae | 423 | |
424 | if (prefix->state == EIGRP_FSM_STATE_PASSIVE) { | |
425 | if (!eigrp_metrics_is_same(prefix->reported_metric, | |
695ff37b | 426 | ne->total_metric)) { |
d62a17ae | 427 | prefix->rdistance = prefix->fdistance = |
695ff37b | 428 | prefix->distance = ne->distance; |
d62a17ae | 429 | prefix->reported_metric = |
695ff37b | 430 | ne->total_metric; |
d62a17ae | 431 | if (msg->packet_type == EIGRP_OPC_QUERY) |
432 | eigrp_send_reply(msg->adv_router, prefix); | |
433 | prefix->req_action |= EIGRP_FSM_NEED_UPDATE; | |
434 | listnode_add( | |
435 | (eigrp_lookup())->topology_changes_internalIPV4, | |
436 | prefix); | |
437 | } | |
438 | eigrp_topology_update_node_flags(prefix); | |
439 | eigrp_update_routing_table(prefix); | |
440 | } | |
441 | ||
442 | if (msg->packet_type == EIGRP_OPC_QUERY) | |
443 | eigrp_send_reply(msg->adv_router, prefix); | |
444 | ||
445 | return 1; | |
7f57883e DS |
446 | } |
447 | ||
f9e5c9ca DS |
448 | int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg) |
449 | { | |
d62a17ae | 450 | struct eigrp *eigrp = msg->eigrp; |
451 | struct eigrp_prefix_entry *prefix = msg->prefix; | |
255ab940 | 452 | struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); |
695ff37b | 453 | |
d62a17ae | 454 | prefix->fdistance = prefix->distance = prefix->rdistance = |
695ff37b DS |
455 | ne->distance; |
456 | prefix->reported_metric = ne->total_metric; | |
d62a17ae | 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 | ||
695ff37b DS |
463 | ne = listnode_head(successors); |
464 | eigrp_send_reply(ne->adv_router, | |
465 | prefix); | |
affe9e99 | 466 | list_delete_and_null(&successors); |
d62a17ae | 467 | } |
468 | ||
469 | prefix->state = EIGRP_FSM_STATE_PASSIVE; | |
470 | prefix->req_action |= EIGRP_FSM_NEED_UPDATE; | |
471 | listnode_add(eigrp->topology_changes_internalIPV4, prefix); | |
472 | eigrp_topology_update_node_flags(prefix); | |
473 | eigrp_update_routing_table(prefix); | |
474 | eigrp_update_topology_table_prefix(eigrp->topology_table, prefix); | |
475 | ||
476 | return 1; | |
7f57883e DS |
477 | } |
478 | ||
f9e5c9ca DS |
479 | int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg) |
480 | { | |
d62a17ae | 481 | struct list *successors = eigrp_topology_get_successor(msg->prefix); |
255ab940 | 482 | struct eigrp_nexthop_entry *ne; |
f9e5c9ca | 483 | |
d62a17ae | 484 | assert(successors); // Trump and his big hands |
f6709c16 | 485 | |
695ff37b | 486 | ne = listnode_head(successors); |
d62a17ae | 487 | msg->prefix->state = msg->prefix->state == EIGRP_FSM_STATE_ACTIVE_1 |
488 | ? EIGRP_FSM_STATE_ACTIVE_0 | |
489 | : EIGRP_FSM_STATE_ACTIVE_2; | |
695ff37b | 490 | msg->prefix->distance = ne->distance; |
d62a17ae | 491 | if (!msg->prefix->rij->count) |
492 | (*(NSM[msg->prefix->state][eigrp_get_fsm_event(msg)].func))( | |
493 | msg); | |
7f57883e | 494 | |
7f57883e | 495 | |
affe9e99 | 496 | list_delete_and_null(&successors); |
d62a17ae | 497 | return 1; |
7f57883e DS |
498 | } |
499 | ||
f9e5c9ca DS |
500 | int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg) |
501 | { | |
d62a17ae | 502 | struct eigrp *eigrp = msg->eigrp; |
503 | struct eigrp_prefix_entry *prefix = msg->prefix; | |
255ab940 | 504 | struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); |
695ff37b | 505 | |
d62a17ae | 506 | prefix->state = EIGRP_FSM_STATE_PASSIVE; |
695ff37b DS |
507 | prefix->distance = prefix->rdistance = ne->distance; |
508 | prefix->reported_metric = ne->total_metric; | |
d62a17ae | 509 | prefix->fdistance = prefix->fdistance > prefix->distance |
510 | ? prefix->distance | |
511 | : prefix->fdistance; | |
512 | if (prefix->state == EIGRP_FSM_STATE_ACTIVE_2) { | |
513 | struct list *successors = eigrp_topology_get_successor(prefix); | |
514 | ||
515 | assert(successors); // Having a spoon and all you need is a | |
516 | // knife | |
695ff37b DS |
517 | ne = listnode_head(successors); |
518 | eigrp_send_reply(ne->adv_router, | |
519 | prefix); | |
d62a17ae | 520 | |
affe9e99 | 521 | list_delete_and_null(&successors); |
d62a17ae | 522 | } |
523 | prefix->req_action |= EIGRP_FSM_NEED_UPDATE; | |
524 | listnode_add(eigrp->topology_changes_internalIPV4, prefix); | |
525 | eigrp_topology_update_node_flags(prefix); | |
526 | eigrp_update_routing_table(prefix); | |
527 | eigrp_update_topology_table_prefix(eigrp->topology_table, prefix); | |
528 | ||
529 | return 1; | |
7f57883e DS |
530 | } |
531 | ||
f9e5c9ca DS |
532 | int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg) |
533 | { | |
d62a17ae | 534 | struct eigrp *eigrp = msg->eigrp; |
535 | struct eigrp_prefix_entry *prefix = msg->prefix; | |
255ab940 | 536 | struct eigrp_nexthop_entry *best_successor; |
d62a17ae | 537 | struct list *successors = eigrp_topology_get_successor(prefix); |
538 | ||
539 | assert(successors); // Routing without a stack | |
540 | ||
541 | prefix->state = prefix->state == EIGRP_FSM_STATE_ACTIVE_0 | |
542 | ? EIGRP_FSM_STATE_ACTIVE_1 | |
543 | : EIGRP_FSM_STATE_ACTIVE_3; | |
695ff37b DS |
544 | |
545 | best_successor = listnode_head(successors); | |
d62a17ae | 546 | prefix->rdistance = prefix->distance = best_successor->distance; |
547 | prefix->reported_metric = best_successor->total_metric; | |
548 | ||
549 | if (eigrp_nbr_count_get()) { | |
550 | prefix->req_action |= EIGRP_FSM_NEED_QUERY; | |
551 | listnode_add(eigrp->topology_changes_internalIPV4, prefix); | |
552 | } else { | |
553 | eigrp_fsm_event_lr(msg); // in the case that there are no more | |
554 | // neighbors left | |
555 | } | |
556 | ||
affe9e99 | 557 | list_delete_and_null(&successors); |
d62a17ae | 558 | |
559 | return 1; | |
7f57883e DS |
560 | } |
561 | ||
f9e5c9ca DS |
562 | int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg) |
563 | { | |
d62a17ae | 564 | struct list *successors = eigrp_topology_get_successor(msg->prefix); |
255ab940 | 565 | struct eigrp_nexthop_entry *ne; |
f6709c16 | 566 | |
d62a17ae | 567 | assert(successors); // Cats and no Dogs |
f6709c16 | 568 | |
695ff37b | 569 | ne = listnode_head(successors); |
d62a17ae | 570 | msg->prefix->state = EIGRP_FSM_STATE_ACTIVE_2; |
695ff37b | 571 | msg->prefix->distance = ne->distance; |
f6709c16 | 572 | |
affe9e99 | 573 | list_delete_and_null(&successors); |
d62a17ae | 574 | return 1; |
7f57883e | 575 | } |