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