]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_update.c
eigrpd: Improve external route distance comparison
[mirror_frr.git] / eigrpd / eigrp_update.c
CommitLineData
7f57883e
DS
1/*
2 * EIGRP Sending and Receiving EIGRP Update Packets.
3 * Copyright (C) 2013-2016
4 * Authors:
5 * Donnie Savage
6 * Jan Janovic
7 * Matej Perina
8 * Peter Orsag
9 * Peter Paluch
10 * Frantisek Gazo
11 * Tomas Hvorkovy
12 * Martin Kontsek
13 * Lukas Koribsky
14 *
15 * This file is part of GNU Zebra.
16 *
17 * GNU Zebra is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License as published by the
19 * Free Software Foundation; either version 2, or (at your option) any
20 * later version.
21 *
22 * GNU Zebra is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
896014f4
DL
27 * You should have received a copy of the GNU General Public License along
28 * with this program; see the file COPYING; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
7f57883e
DS
30 */
31
32#include <zebra.h>
33
34#include "thread.h"
35#include "memory.h"
36#include "linklist.h"
37#include "prefix.h"
38#include "if.h"
39#include "table.h"
40#include "sockunion.h"
41#include "stream.h"
42#include "log.h"
43#include "sockopt.h"
44#include "checksum.h"
45#include "md5.h"
46#include "vty.h"
47#include "plist.h"
48#include "plist_int.h"
49#include "routemap.h"
50#include "vty.h"
51
52#include "eigrpd/eigrp_structs.h"
53#include "eigrpd/eigrpd.h"
54#include "eigrpd/eigrp_interface.h"
55#include "eigrpd/eigrp_neighbor.h"
56#include "eigrpd/eigrp_packet.h"
57#include "eigrpd/eigrp_zebra.h"
58#include "eigrpd/eigrp_vty.h"
59#include "eigrpd/eigrp_dump.h"
60#include "eigrpd/eigrp_macros.h"
61#include "eigrpd/eigrp_topology.h"
62#include "eigrpd/eigrp_fsm.h"
63#include "eigrpd/eigrp_network.h"
64#include "eigrpd/eigrp_memory.h"
65
66/**
67 * @fn remove_received_prefix_gr
68 *
69 * @param[in] nbr_prefixes List of neighbor prefixes
d62a17ae 70 * @param[in] recv_prefix Prefix which needs to be removed from
71 * list
7f57883e
DS
72 *
73 * @return void
74 *
75 * @par
76 * Function is used for removing received prefix
77 * from list of neighbor prefixes
78 */
d62a17ae 79static void remove_received_prefix_gr(struct list *nbr_prefixes,
80 struct eigrp_prefix_entry *recv_prefix)
7f57883e 81{
d62a17ae 82 struct listnode *node1, *node11;
83 struct eigrp_prefix_entry *prefix = NULL;
84
85 /* iterate over all prefixes in list */
86 for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) {
87 /* remove prefix from list if found */
88 if (prefix == recv_prefix) {
89 listnode_delete(nbr_prefixes, prefix);
90 }
91 }
7f57883e
DS
92}
93
94/**
95 * @fn eigrp_update_receive_GR_ask
96 *
97 * @param[in] eigrp EIGRP process
d62a17ae 98 * @param[in] nbr Neighbor update of who we
99 * received
7f57883e
DS
100 * @param[in] nbr_prefixes Prefixes which weren't advertised
101 *
102 * @return void
103 *
104 * @par
105 * Function is used for notifying FSM about prefixes which
106 * weren't advertised by neighbor:
107 * We will send message to FSM with prefix delay set to infinity.
108 */
d62a17ae 109static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
110 struct eigrp_neighbor *nbr,
111 struct list *nbr_prefixes)
7f57883e 112{
d62a17ae 113 struct listnode *node1;
114 struct eigrp_prefix_entry *prefix;
115 struct TLV_IPv4_Internal_type *tlv_max;
116
117 /* iterate over all prefixes which weren't advertised by neighbor */
118 for (ALL_LIST_ELEMENTS_RO(nbr_prefixes, node1, prefix)) {
119 zlog_debug("GR receive: Neighbor not advertised %s/%d",
120 inet_ntoa(prefix->destination_ipv4->prefix),
121 prefix->destination_ipv4->prefixlen);
122
123 /* create internal IPv4 TLV with infinite delay */
124 tlv_max = eigrp_IPv4_InternalTLV_new();
125 tlv_max->type = EIGRP_TLV_IPv4_INT;
126 tlv_max->length = 28U;
127 tlv_max->metric = prefix->reported_metric;
128 /* set delay to MAX */
129 tlv_max->metric.delay = EIGRP_MAX_METRIC;
130 tlv_max->destination = prefix->destination_ipv4->prefix;
131 tlv_max->prefix_length = prefix->destination_ipv4->prefixlen;
132
133
134 /* prepare message for FSM */
92035b1d 135 struct eigrp_fsm_action_message fsm_msg;
d62a17ae 136
137 struct eigrp_neighbor_entry *entry =
138 eigrp_prefix_entry_lookup(prefix->entries, nbr);
139
92035b1d
DS
140 fsm_msg.packet_type = EIGRP_OPC_UPDATE;
141 fsm_msg.eigrp = eigrp;
7cfa4322 142 fsm_msg.data_type = EIGRP_INT;
92035b1d
DS
143 fsm_msg.adv_router = nbr;
144 fsm_msg.data.ipv4_int_type = tlv_max;
145 fsm_msg.entry = entry;
146 fsm_msg.prefix = prefix;
d62a17ae 147
148 /* send message to FSM */
6118272f 149 eigrp_fsm_event(&fsm_msg);
d62a17ae 150
151 /* free memory used by TLV */
152 eigrp_IPv4_InternalTLV_free(tlv_max);
153 }
7f57883e
DS
154}
155
156/*
157 * EIGRP UPDATE read function
158 */
d62a17ae 159void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
160 struct eigrp_header *eigrph, struct stream *s,
161 struct eigrp_interface *ei, int size)
7f57883e 162{
d62a17ae 163 struct eigrp_neighbor *nbr;
164 struct TLV_IPv4_Internal_type *tlv;
165 struct eigrp_prefix_entry *pe;
166 struct eigrp_neighbor_entry *ne;
167 u_int32_t flags;
168 u_int16_t type;
c283f389 169 u_int16_t length;
d62a17ae 170 u_char same;
171 struct access_list *alist;
172 struct prefix_list *plist;
c283f389 173 struct prefix_ipv4 dest_addr;
d62a17ae 174 struct eigrp *e;
175 u_char graceful_restart;
176 u_char graceful_restart_final;
177 struct list *nbr_prefixes = NULL;
178
179 /* increment statistics. */
180 ei->update_in++;
181
182 /* get neighbor struct */
183 nbr = eigrp_nbr_get(ei, eigrph, iph);
184
185 /* neighbor must be valid, eigrp_nbr_get creates if none existed */
186 assert(nbr);
187
188 flags = ntohl(eigrph->flags);
189
190 if (flags & EIGRP_CR_FLAG) {
191 return;
192 }
193
194 same = 0;
195 graceful_restart = 0;
196 graceful_restart_final = 0;
197 if ((nbr->recv_sequence_number) == (ntohl(eigrph->sequence)))
198 same = 1;
199
200 nbr->recv_sequence_number = ntohl(eigrph->sequence);
201 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
202 zlog_debug(
203 "Processing Update size[%u] int(%s) nbr(%s) seq [%u] flags [%0x]",
204 size,
205 ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT),
206 inet_ntoa(nbr->src), nbr->recv_sequence_number, flags);
207
208
209 if ((flags == (EIGRP_INIT_FLAG + EIGRP_RS_FLAG + EIGRP_EOT_FLAG))
210 && (!same)) {
211 /* Graceful restart Update received with all routes */
212
213 zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
214 inet_ntoa(nbr->src),
215 ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
216
217 /* get all prefixes from neighbor from topology table */
218 nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
219 graceful_restart = 1;
220 graceful_restart_final = 1;
221 } else if ((flags == (EIGRP_INIT_FLAG + EIGRP_RS_FLAG)) && (!same)) {
222 /* Graceful restart Update received, routes also in next packet
223 */
224
225 zlog_info("Neighbor %s (%s) is resync: peer graceful-restart",
226 inet_ntoa(nbr->src),
227 ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
228
229 /* get all prefixes from neighbor from topology table */
230 nbr_prefixes = eigrp_neighbor_prefixes_lookup(eigrp, nbr);
231 /* save prefixes to neighbor for later use */
232 nbr->nbr_gr_prefixes = nbr_prefixes;
233 graceful_restart = 1;
234 graceful_restart_final = 0;
235 } else if ((flags == (EIGRP_EOT_FLAG)) && (!same)) {
236 /* If there was INIT+RS Update packet before,
237 * consider this as GR EOT */
238
239 if (nbr->nbr_gr_prefixes != NULL) {
240 /* this is final packet of GR */
241 nbr_prefixes = nbr->nbr_gr_prefixes;
242 nbr->nbr_gr_prefixes = NULL;
243
244 graceful_restart = 1;
245 graceful_restart_final = 1;
246 }
247
248 } else if ((flags == (0)) && (!same)) {
249 /* If there was INIT+RS Update packet before,
250 * consider this as GR not final packet */
251
252 if (nbr->nbr_gr_prefixes != NULL) {
253 /* this is GR not final route packet */
254 nbr_prefixes = nbr->nbr_gr_prefixes;
255
256 graceful_restart = 1;
257 graceful_restart_final = 0;
258 }
259
260 } else if ((flags & EIGRP_INIT_FLAG)
261 && (!same)) { /* When in pending state, send INIT update only
262 if it wasn't
263 already sent before (only if init_sequence
264 is 0) */
265 if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
266 && (nbr->init_sequence_number == 0))
267 eigrp_update_send_init(nbr);
268
269 if (nbr->state == EIGRP_NEIGHBOR_UP) {
270 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
271 eigrp_topology_neighbor_down(nbr->ei->eigrp, nbr);
272 nbr->recv_sequence_number = ntohl(eigrph->sequence);
273 zlog_info("Neighbor %s (%s) is down: peer restarted",
274 inet_ntoa(nbr->src),
275 ifindex2ifname(nbr->ei->ifp->ifindex,
276 VRF_DEFAULT));
277 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
278 zlog_info("Neighbor %s (%s) is pending: new adjacency",
279 inet_ntoa(nbr->src),
280 ifindex2ifname(nbr->ei->ifp->ifindex,
281 VRF_DEFAULT));
282 eigrp_update_send_init(nbr);
283 }
284 }
285
286 /*If there is topology information*/
287 while (s->endp > s->getp) {
288 type = stream_getw(s);
c283f389
DS
289 switch (type) {
290 case EIGRP_TLV_IPv4_INT:
d62a17ae 291 stream_set_getp(s, s->getp - sizeof(u_int16_t));
292
293 tlv = eigrp_read_ipv4_tlv(s);
294
295 /*searching if destination exists */
296 dest_addr.family = AF_INET;
297 dest_addr.prefix = tlv->destination;
298 dest_addr.prefixlen = tlv->prefix_length;
299 struct eigrp_prefix_entry *dest =
300 eigrp_topology_table_lookup_ipv4(
301 eigrp->topology_table, &dest_addr);
302
303 /*if exists it comes to DUAL*/
304 if (dest != NULL) {
305 /* remove received prefix from neighbor prefix
306 * list if in GR */
307 if (graceful_restart)
308 remove_received_prefix_gr(nbr_prefixes,
309 dest);
310
92035b1d 311 struct eigrp_fsm_action_message msg;
d62a17ae 312 struct eigrp_neighbor_entry *entry =
313 eigrp_prefix_entry_lookup(dest->entries,
314 nbr);
315
92035b1d
DS
316 msg.packet_type = EIGRP_OPC_UPDATE;
317 msg.eigrp = eigrp;
7cfa4322 318 msg.data_type = EIGRP_INT;
92035b1d
DS
319 msg.adv_router = nbr;
320 msg.data.ipv4_int_type = tlv;
321 msg.entry = entry;
322 msg.prefix = dest;
6118272f 323 eigrp_fsm_event(&msg);
d62a17ae 324 } else {
325 /*Here comes topology information save*/
326 pe = eigrp_prefix_entry_new();
327 pe->serno = eigrp->serno;
328 pe->destination_ipv4 = prefix_ipv4_new();
329 prefix_copy(
330 (struct prefix *)pe->destination_ipv4,
331 (struct prefix *)&dest_addr);
332 pe->af = AF_INET;
333 pe->state = EIGRP_FSM_STATE_PASSIVE;
334 pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
335
336 ne = eigrp_neighbor_entry_new();
337 ne->ei = ei;
338 ne->adv_router = nbr;
339 ne->reported_metric = tlv->metric;
340 ne->reported_distance = eigrp_calculate_metrics(
341 eigrp, tlv->metric);
342 /*
343 * Filtering
344 */
345 e = eigrp_lookup();
346 /*
347 * Check if there is any access-list on
348 * interface (IN direction)
349 * and set distance to max
350 */
351 alist = ei->list[EIGRP_FILTER_IN];
352
353 /* Check if access-list fits */
354 if (alist
355 && access_list_apply(
356 alist,
357 (struct prefix *)&dest_addr)
358 == FILTER_DENY) {
359 /* If yes, set reported metric to Max */
360 ne->reported_metric.delay =
361 EIGRP_MAX_METRIC;
362 } else {
363 ne->distance =
364 eigrp_calculate_total_metrics(
365 eigrp, ne);
366 }
367
368 plist = e->prefix[EIGRP_FILTER_IN];
369
370 /* Check if prefix-list fits */
371 if (plist
372 && prefix_list_apply(
373 plist,
374 (struct prefix *)&dest_addr)
375 == PREFIX_DENY) {
376 /* If yes, set reported metric to Max */
377 ne->reported_metric.delay =
378 EIGRP_MAX_METRIC;
379 }
380
381 /*Get access-list from current interface */
382 alist = ei->list[EIGRP_FILTER_IN];
383
384 /* Check if access-list fits */
385 if (alist
386 && access_list_apply(
387 alist,
388 (struct prefix *)&dest_addr)
389 == FILTER_DENY) {
390 /* If yes, set reported metric to Max */
391 ne->reported_metric.delay =
392 EIGRP_MAX_METRIC;
393 }
394
395 plist = ei->prefix[EIGRP_FILTER_IN];
396
397 /* Check if prefix-list fits */
398 if (plist
399 && prefix_list_apply(
400 plist,
401 (struct prefix *)&dest_addr)
402 == PREFIX_DENY) {
403 /* If yes, set reported metric to Max */
404 ne->reported_metric.delay =
405 EIGRP_MAX_METRIC;
406 }
407 /*
408 * End of filtering
409 */
410
411 ne->distance = eigrp_calculate_total_metrics(
412 eigrp, ne);
413
414 pe->fdistance = pe->distance = pe->rdistance =
415 ne->distance;
416 ne->prefix = pe;
417 ne->flags = EIGRP_NEIGHBOR_ENTRY_SUCCESSOR_FLAG;
418
419 eigrp_prefix_entry_add(eigrp->topology_table,
420 pe);
421 eigrp_neighbor_entry_add(pe, ne);
422 pe->distance = pe->fdistance = pe->rdistance =
423 ne->distance;
424 pe->reported_metric = ne->total_metric;
425 eigrp_topology_update_node_flags(pe);
426
427 pe->req_action |= EIGRP_FSM_NEED_UPDATE;
428 listnode_add(
429 eigrp->topology_changes_internalIPV4,
430 pe);
431 }
432 eigrp_IPv4_InternalTLV_free(tlv);
c283f389
DS
433 break;
434
435 case EIGRP_TLV_IPv4_EXT:
436 /* DVS: processing of external routes needs packet and fsm work.
437 * for now, lets just not creash the box
438 */
439 default:
440 length = stream_getw(s);
441 // -2 for type, -2 for len
442 for (length-=4; length ; length--) {
443 (void)stream_getc(s);
444 }
d62a17ae 445 }
446 }
447
448 /* ask about prefixes not present in GR update,
449 * if this is final GR packet */
450 if (graceful_restart_final) {
451 eigrp_update_receive_GR_ask(eigrp, nbr, nbr_prefixes);
452 }
453
454 /*
455 * We don't need to send separate Ack for INIT Update. INIT will be
456 * acked in EOT Update.
457 */
458 if ((nbr->state == EIGRP_NEIGHBOR_UP) && !(flags == EIGRP_INIT_FLAG)) {
459 eigrp_hello_send_ack(nbr);
460 }
461
462 eigrp_query_send_all(eigrp);
463 eigrp_update_send_all(eigrp, ei);
7f57883e
DS
464}
465
466/*send EIGRP Update packet*/
d62a17ae 467void eigrp_update_send_init(struct eigrp_neighbor *nbr)
7f57883e 468{
d62a17ae 469 struct eigrp_packet *ep;
470 u_int16_t length = EIGRP_HEADER_LEN;
471
907b4303 472 ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
d62a17ae 473
474 /* Prepare EIGRP INIT UPDATE header */
475 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
476 zlog_debug("Enqueuing Update Init Seq [%u] Ack [%u]",
477 nbr->ei->eigrp->sequence_number,
478 nbr->recv_sequence_number);
479
cf2f4dae
DS
480 eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp,
481 ep->s, EIGRP_INIT_FLAG,
482 nbr->ei->eigrp->sequence_number,
483 nbr->recv_sequence_number);
d62a17ae 484
485 // encode Authentication TLV, if needed
486 if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
487 && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
488 length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei);
489 eigrp_make_md5_digest(nbr->ei, ep->s,
490 EIGRP_AUTH_UPDATE_INIT_FLAG);
491 }
492
493 /* EIGRP Checksum */
494 eigrp_packet_checksum(nbr->ei, ep->s, length);
495
496 ep->length = length;
497 ep->dst.s_addr = nbr->src.s_addr;
498
499 /*This ack number we await from neighbor*/
500 nbr->init_sequence_number = nbr->ei->eigrp->sequence_number;
501 ep->sequence_number = nbr->ei->eigrp->sequence_number;
502 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
503 zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
504 ep->length, ep->sequence_number, inet_ntoa(ep->dst));
505
506 /*Put packet to retransmission queue*/
f90f65a2 507 eigrp_fifo_push(nbr->retrans_queue, ep);
d62a17ae 508
509 if (nbr->retrans_queue->count == 1) {
510 eigrp_send_packet_reliably(nbr);
511 }
7f57883e
DS
512}
513
7ecf0a4d
DS
514static void eigrp_update_place_on_nbr_queue(struct eigrp_neighbor *nbr,
515 struct eigrp_packet *ep,
516 u_int32_t seq_no,
517 int length)
518{
519 if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
520 (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) {
521 eigrp_make_md5_digest(nbr->ei,ep->s, EIGRP_AUTH_UPDATE_FLAG);
522 }
523
524 /* EIGRP Checksum */
525 eigrp_packet_checksum(nbr->ei, ep->s, length);
526
527 ep->length = length;
528 ep->dst.s_addr = nbr->src.s_addr;
529
530 /*This ack number we await from neighbor*/
531 ep->sequence_number = seq_no;
532
533 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
534 zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
535 ep->length, ep->sequence_number, inet_ntoa(ep->dst));
536
537 /*Put packet to retransmission queue*/
f90f65a2 538 eigrp_fifo_push(nbr->retrans_queue, ep);
17a2f658
DS
539
540 if (nbr->retrans_queue->count == 1)
541 eigrp_send_packet_reliably(nbr);
7ecf0a4d
DS
542}
543
a6e8810e
DS
544static void eigrp_update_send_to_all_nbrs(struct eigrp_interface *ei,
545 struct eigrp_packet *ep)
546{
547 struct listnode *node, *nnode;
548 struct eigrp_neighbor *nbr;
549 bool packet_sent = false;
550
551 for (ALL_LIST_ELEMENTS(ei->nbrs, node, nnode, nbr)) {
552 struct eigrp_packet *ep_dup;
553
554 if (nbr->state != EIGRP_NEIGHBOR_UP)
555 continue;
556
557 if (packet_sent)
558 ep_dup = eigrp_packet_duplicate(ep, NULL);
559 else
560 ep_dup = ep;
561
562 ep_dup->nbr = nbr;
563 packet_sent = true;
564 /*Put packet to retransmission queue*/
565 eigrp_fifo_push(nbr->retrans_queue, ep_dup);
566
567 if (nbr->retrans_queue->count == 1) {
568 eigrp_send_packet_reliably(nbr);
569 }
570 }
571
572 if (!packet_sent)
573 eigrp_packet_free(ep);
574}
575
d62a17ae 576void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
7f57883e 577{
d62a17ae 578 struct eigrp_packet *ep;
d62a17ae 579 u_int16_t length = EIGRP_HEADER_LEN;
580 struct eigrp_neighbor_entry *te;
581 struct eigrp_prefix_entry *pe;
582 struct listnode *node, *node2, *nnode, *nnode2;
583 struct access_list *alist;
584 struct prefix_list *plist;
585 struct access_list *alist_i;
586 struct prefix_list *plist_i;
587 struct eigrp *e;
588 struct prefix_ipv4 *dest_addr;
7ecf0a4d 589 u_int32_t seq_no = nbr->ei->eigrp->sequence_number;
d62a17ae 590
907b4303 591 ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
d62a17ae 592
593 /* Prepare EIGRP EOT UPDATE header */
cf2f4dae
DS
594 eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp,
595 ep->s, EIGRP_EOT_FLAG,
596 seq_no, nbr->recv_sequence_number);
d62a17ae 597
598 // encode Authentication TLV, if needed
7ecf0a4d
DS
599 if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
600 (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL)) {
601 length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
d62a17ae 602 }
603
7ecf0a4d 604 for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode, pe)) {
d62a17ae 605 for (ALL_LIST_ELEMENTS(pe->entries, node2, nnode2, te)) {
cd044247 606 if (eigrp_nbr_split_horizon_check(te, nbr->ei))
d62a17ae 607 continue;
608
7ecf0a4d
DS
609 if ((length + 0x001D) > (u_int16_t)nbr->ei->ifp->mtu) {
610 eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
7ecf0a4d
DS
611 seq_no++;
612
613 length = EIGRP_HEADER_LEN;
907b4303 614 ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
cf2f4dae
DS
615 eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp,
616 ep->s, EIGRP_EOT_FLAG,
7ecf0a4d
DS
617 seq_no, nbr->recv_sequence_number);
618
619 if((IF_DEF_PARAMS (nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5) &&
620 (IF_DEF_PARAMS (nbr->ei->ifp)->auth_keychain != NULL))
621 {
622 length += eigrp_add_authTLV_MD5_to_stream(ep->s,nbr->ei);
623 }
624 }
d62a17ae 625 /* Get destination address from prefix */
626 dest_addr = pe->destination_ipv4;
627
628 /*
629 * Filtering
630 */
7ecf0a4d 631 //TODO: Work in progress
d62a17ae 632 /* get list from eigrp process */
633 e = eigrp_lookup();
7ecf0a4d 634 /* Get access-lists and prefix-lists from process and interface */
d62a17ae 635 alist = e->list[EIGRP_FILTER_OUT];
636 plist = e->prefix[EIGRP_FILTER_OUT];
637 alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
638 plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
639
640 /* Check if any list fits */
641 if ((alist
7ecf0a4d
DS
642 && access_list_apply (alist,
643 (struct prefix *) dest_addr) == FILTER_DENY)||
644 (plist && prefix_list_apply (plist,
645 (struct prefix *) dest_addr) == PREFIX_DENY)||
646 (alist_i && access_list_apply (alist_i,
647 (struct prefix *) dest_addr) == FILTER_DENY)||
648 (plist_i && prefix_list_apply (plist_i,
649 (struct prefix *) dest_addr) == PREFIX_DENY)) {
650 //pe->reported_metric.delay = EIGRP_MAX_METRIC;
d62a17ae 651 continue;
652 } else {
7ecf0a4d 653 length += eigrp_add_internalTLV_to_stream(ep->s, pe);
d62a17ae 654 }
d62a17ae 655 }
656 }
657
7ecf0a4d 658 eigrp_update_place_on_nbr_queue (nbr, ep, seq_no, length);
a6e8810e 659 nbr->ei->eigrp->sequence_number = seq_no++;
7f57883e
DS
660}
661
d62a17ae 662void eigrp_update_send(struct eigrp_interface *ei)
7f57883e 663{
d62a17ae 664 struct eigrp_packet *ep;
665 struct listnode *node, *nnode;
d62a17ae 666 struct eigrp_prefix_entry *pe;
667 u_char has_tlv;
668 struct access_list *alist;
669 struct prefix_list *plist;
670 struct access_list *alist_i;
671 struct prefix_list *plist_i;
672 struct eigrp *e;
673 struct prefix_ipv4 *dest_addr;
a6e8810e
DS
674 u_int32_t seq_no = ei->eigrp->sequence_number;
675
676 if (ei->nbrs->count == 0)
677 return;
d62a17ae 678
679 u_int16_t length = EIGRP_HEADER_LEN;
680
907b4303 681 ep = eigrp_packet_new(ei->ifp->mtu, NULL);
d62a17ae 682
683 /* Prepare EIGRP INIT UPDATE header */
cf2f4dae
DS
684 eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp,
685 ep->s, 0, seq_no, 0);
d62a17ae 686
687 // encode Authentication TLV, if needed
688 if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
689 && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
690 length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei);
691 }
692
693 has_tlv = 0;
694 for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node,
695 nnode, pe)) {
cd044247 696 struct eigrp_neighbor_entry *ne;
d62a17ae 697
a75c1cc1
DS
698 if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE))
699 continue;
d62a17ae 700
cd044247
DS
701 ne = listnode_head(pe->entries);
702 if (eigrp_nbr_split_horizon_check(ne, ei))
703 continue;
704
a6e8810e
DS
705 if ((length + 0x001D) > (u_int16_t)ei->ifp->mtu) {
706 if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
707 && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
708 eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
709 }
710
711 eigrp_packet_checksum(ei, ep->s, length);
712 ep->length = length;
713
714 ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
715
716 ep->sequence_number = seq_no;
717 seq_no++;
718 eigrp_update_send_to_all_nbrs(ei, ep);
719
720 length = EIGRP_HEADER_LEN;
721 ep = eigrp_packet_new(ei->ifp->mtu, NULL);
cf2f4dae
DS
722 eigrp_packet_header_init(EIGRP_OPC_UPDATE, ei->eigrp,
723 ep->s, 0, seq_no, 0);
a6e8810e
DS
724 if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
725 && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
726 length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei);
727 }
728 has_tlv = 0;
729 }
a75c1cc1
DS
730 /* Get destination address from prefix */
731 dest_addr = pe->destination_ipv4;
d62a17ae 732
a75c1cc1
DS
733 /*
734 * Filtering
735 */
736 e = eigrp_lookup();
737 /* Get access-lists and prefix-lists from process and
738 * interface */
739 alist = e->list[EIGRP_FILTER_OUT];
740 plist = e->prefix[EIGRP_FILTER_OUT];
741 alist_i = ei->list[EIGRP_FILTER_OUT];
742 plist_i = ei->prefix[EIGRP_FILTER_OUT];
743
744 /* Check if any list fits */
745 if ((alist
746 && access_list_apply(alist,
747 (struct prefix *)dest_addr)
748 == FILTER_DENY)
749 || (plist
750 && prefix_list_apply(plist,
751 (struct prefix *)dest_addr)
752 == PREFIX_DENY)
753 || (alist_i
754 && access_list_apply(alist_i,
755 (struct prefix *)dest_addr)
756 == FILTER_DENY)
757 || (plist_i
758 && prefix_list_apply(plist_i,
759 (struct prefix *)dest_addr)
760 == PREFIX_DENY)) {
761 // pe->reported_metric.delay = EIGRP_MAX_METRIC;
762 continue;
763 } else {
764 length += eigrp_add_internalTLV_to_stream(ep->s,
765 pe);
766 has_tlv = 1;
d62a17ae 767 }
768 }
769
770 if (!has_tlv) {
771 eigrp_packet_free(ep);
772 return;
773 }
774
775 if ((IF_DEF_PARAMS(ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
776 && (IF_DEF_PARAMS(ei->ifp)->auth_keychain != NULL)) {
777 eigrp_make_md5_digest(ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
778 }
779
780 /* EIGRP Checksum */
781 eigrp_packet_checksum(ei, ep->s, length);
782 ep->length = length;
783
784 ep->dst.s_addr = htonl(EIGRP_MULTICAST_ADDRESS);
785
786 /*This ack number we await from neighbor*/
787 ep->sequence_number = ei->eigrp->sequence_number;
788
789 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
790 zlog_debug("Enqueuing Update length[%u] Seq [%u]", length,
791 ep->sequence_number);
792
a6e8810e
DS
793 eigrp_update_send_to_all_nbrs(ei, ep);
794 ei->eigrp->sequence_number = seq_no++;
7f57883e
DS
795}
796
d62a17ae 797void eigrp_update_send_all(struct eigrp *eigrp,
798 struct eigrp_interface *exception)
7f57883e 799{
d62a17ae 800 struct eigrp_interface *iface;
801 struct listnode *node, *node2, *nnode2;
802 struct eigrp_prefix_entry *pe;
803
804 for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
805 if (iface != exception) {
806 eigrp_update_send(iface);
807 }
808 }
809
810 for (ALL_LIST_ELEMENTS(eigrp->topology_changes_internalIPV4, node2,
811 nnode2, pe)) {
812 if (pe->req_action & EIGRP_FSM_NEED_UPDATE) {
813 pe->req_action &= ~EIGRP_FSM_NEED_UPDATE;
814 listnode_delete(eigrp->topology_changes_internalIPV4,
815 pe);
d62a17ae 816 }
817 }
7f57883e
DS
818}
819
820/**
821 * @fn eigrp_update_send_GR_part
822 *
9d303b37
DL
823 * @param[in] nbr contains neighbor who would receive Graceful
824 * restart
7f57883e
DS
825 *
826 * @return void
827 *
828 * @par
829 * Function used for sending Graceful restart Update packet
830 * and if there are multiple chunks, send only one of them.
831 * It is called from thread. Do not call it directly.
832 *
833 * Uses nbr_gr_packet_type from neighbor.
834 */
d62a17ae 835static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
7f57883e 836{
d62a17ae 837 struct eigrp_packet *ep;
838 u_int16_t length = EIGRP_HEADER_LEN;
839 struct listnode *node, *nnode;
840 struct eigrp_prefix_entry *pe;
841 struct prefix_ipv4 *dest_addr;
842 struct eigrp *e;
843 struct access_list *alist, *alist_i;
844 struct prefix_list *plist, *plist_i;
845 struct list *prefixes;
846 u_int32_t flags;
847 unsigned int send_prefixes;
848 struct TLV_IPv4_Internal_type *tlv_max;
849
850 /* get prefixes to send to neighbor */
851 prefixes = nbr->nbr_gr_prefixes_send;
852
853 send_prefixes = 0;
854 length = EIGRP_HEADER_LEN;
855
856 /* if there already were last packet chunk, we won't continue */
857 if (nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_LAST)
858 return;
859
860 /* if this is first packet chunk, we need to decide,
861 * if there will be one or more chunks */
862 if (nbr->nbr_gr_packet_type == EIGRP_PACKET_PART_FIRST) {
863 if (prefixes->count <= EIGRP_TLV_MAX_IPv4) {
864 /* there will be only one chunk */
865 flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG
866 + EIGRP_EOT_FLAG;
867 nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
868 } else {
869 /* there will be more chunks */
870 flags = EIGRP_INIT_FLAG + EIGRP_RS_FLAG;
871 nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
872 }
873 } else {
874 /* this is not first chunk, and we need to decide,
875 * if there will be more chunks */
876 if (prefixes->count <= EIGRP_TLV_MAX_IPv4) {
877 /* this is last chunk */
878 flags = EIGRP_EOT_FLAG;
879 nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_LAST;
880 } else {
881 /* there will be more chunks */
882 flags = 0;
883 nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_NA;
884 }
885 }
886
907b4303 887 ep = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
d62a17ae 888
889 /* Prepare EIGRP Graceful restart UPDATE header */
cf2f4dae 890 eigrp_packet_header_init(EIGRP_OPC_UPDATE, nbr->ei->eigrp, ep->s, flags,
d62a17ae 891 nbr->ei->eigrp->sequence_number,
892 nbr->recv_sequence_number);
893
894 // encode Authentication TLV, if needed
895 if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
896 && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
897 length += eigrp_add_authTLV_MD5_to_stream(ep->s, nbr->ei);
898 }
899
900 for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node, nnode,
901 pe)) {
902 /*
903 * Filtering
904 */
905 dest_addr = pe->destination_ipv4;
906 /* get list from eigrp process */
907 e = eigrp_lookup();
908 /* Get access-lists and prefix-lists from process and interface
909 */
910 alist = e->list[EIGRP_FILTER_OUT];
911 plist = e->prefix[EIGRP_FILTER_OUT];
912 alist_i = nbr->ei->list[EIGRP_FILTER_OUT];
913 plist_i = nbr->ei->prefix[EIGRP_FILTER_OUT];
914
915 /* Check if any list fits */
916 if ((alist
917 && access_list_apply(alist, (struct prefix *)dest_addr)
918 == FILTER_DENY)
919 || (plist
920 && prefix_list_apply(plist, (struct prefix *)dest_addr)
921 == PREFIX_DENY)
922 || (alist_i
923 && access_list_apply(alist_i,
924 (struct prefix *)dest_addr)
925 == FILTER_DENY)
926 || (plist_i
927 && prefix_list_apply(plist_i,
928 (struct prefix *)dest_addr)
929 == PREFIX_DENY)) {
930 /* do not send filtered route */
931 zlog_info("Filtered prefix %s won't be sent out.",
932 inet_ntoa(dest_addr->prefix));
933 } else {
934 /* sending route which wasn't filtered */
935 length += eigrp_add_internalTLV_to_stream(ep->s, pe);
936 send_prefixes++;
937 }
938
939 alist = e->list[EIGRP_FILTER_IN];
940 plist = e->prefix[EIGRP_FILTER_IN];
941 alist_i = nbr->ei->list[EIGRP_FILTER_IN];
942 plist_i = nbr->ei->prefix[EIGRP_FILTER_IN];
943
944 /* Check if any list fits */
945 if ((alist
946 && access_list_apply(alist, (struct prefix *)dest_addr)
947 == FILTER_DENY)
948 || (plist
949 && prefix_list_apply(plist, (struct prefix *)dest_addr)
950 == PREFIX_DENY)
951 || (alist_i
952 && access_list_apply(alist_i,
953 (struct prefix *)dest_addr)
954 == FILTER_DENY)
955 || (plist_i
956 && prefix_list_apply(plist_i,
957 (struct prefix *)dest_addr)
958 == PREFIX_DENY)) {
959 /* do not send filtered route */
960 zlog_info("Filtered prefix %s will be removed.",
961 inet_ntoa(dest_addr->prefix));
962
963 tlv_max = eigrp_IPv4_InternalTLV_new();
964 tlv_max->type = EIGRP_TLV_IPv4_INT;
965 tlv_max->length = 28U;
966 tlv_max->metric = pe->reported_metric;
967 /* set delay to MAX */
968 tlv_max->metric.delay = EIGRP_MAX_METRIC;
969 tlv_max->destination = pe->destination_ipv4->prefix;
970 tlv_max->prefix_length =
971 pe->destination_ipv4->prefixlen;
972
973 /* prepare message for FSM */
92035b1d 974 struct eigrp_fsm_action_message fsm_msg;
d62a17ae 975
976 struct eigrp_neighbor_entry *entry =
977 eigrp_prefix_entry_lookup(pe->entries, nbr);
978
92035b1d
DS
979 fsm_msg.packet_type = EIGRP_OPC_UPDATE;
980 fsm_msg.eigrp = e;
7cfa4322 981 fsm_msg.data_type = EIGRP_INT;
92035b1d
DS
982 fsm_msg.adv_router = nbr;
983 fsm_msg.data.ipv4_int_type = tlv_max;
984 fsm_msg.entry = entry;
985 fsm_msg.prefix = pe;
d62a17ae 986
987 /* send message to FSM */
6118272f 988 eigrp_fsm_event(&fsm_msg);
d62a17ae 989
990 /* free memory used by TLV */
991 eigrp_IPv4_InternalTLV_free(tlv_max);
992 }
993 /*
994 * End of filtering
995 */
996
997 /* NULL the pointer */
998 dest_addr = NULL;
999
1000 /* delete processed prefix from list */
1001 listnode_delete(prefixes, pe);
1002
1003 /* if there are enough prefixes, send packet */
1004 if (send_prefixes >= EIGRP_TLV_MAX_IPv4)
1005 break;
1006 }
1007
1008 /* compute Auth digest */
1009 if ((IF_DEF_PARAMS(nbr->ei->ifp)->auth_type == EIGRP_AUTH_TYPE_MD5)
1010 && (IF_DEF_PARAMS(nbr->ei->ifp)->auth_keychain != NULL)) {
1011 eigrp_make_md5_digest(nbr->ei, ep->s, EIGRP_AUTH_UPDATE_FLAG);
1012 }
1013
1014 /* EIGRP Checksum */
1015 eigrp_packet_checksum(nbr->ei, ep->s, length);
1016
1017 ep->length = length;
1018 ep->dst.s_addr = nbr->src.s_addr;
1019
1020 /*This ack number we await from neighbor*/
1021 ep->sequence_number = nbr->ei->eigrp->sequence_number;
1022
1023 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
1024 zlog_debug("Enqueuing Update Init Len [%u] Seq [%u] Dest [%s]",
1025 ep->length, ep->sequence_number, inet_ntoa(ep->dst));
1026
1027 /*Put packet to retransmission queue*/
f90f65a2 1028 eigrp_fifo_push(nbr->retrans_queue, ep);
d62a17ae 1029
1030 if (nbr->retrans_queue->count == 1) {
1031 eigrp_send_packet_reliably(nbr);
1032 }
7f57883e
DS
1033}
1034
1035/**
1036 * @fn eigrp_update_send_GR_thread
1037 *
d62a17ae 1038 * @param[in] thread contains neighbor who would receive
1039 * Graceful restart
7f57883e
DS
1040 *
1041 * @return int always 0
1042 *
1043 * @par
1044 * Function used for sending Graceful restart Update packet
1045 * in thread, it is prepared for multiple chunks of packet.
1046 *
1047 * Uses nbr_gr_packet_type and t_nbr_send_gr from neighbor.
1048 */
d62a17ae 1049int eigrp_update_send_GR_thread(struct thread *thread)
7f57883e 1050{
d62a17ae 1051 struct eigrp_neighbor *nbr;
1052
1053 /* get argument from thread */
1054 nbr = THREAD_ARG(thread);
1055 /* remove this thread pointer */
1056 nbr->t_nbr_send_gr = NULL;
1057
1058 /* if there is packet waiting in queue,
1059 * schedule this thread again with small delay */
1060 if (nbr->retrans_queue->count > 0) {
1061 nbr->t_nbr_send_gr = NULL;
1062 thread_add_timer_msec(master, eigrp_update_send_GR_thread, nbr,
1063 10, &nbr->t_nbr_send_gr);
1064 return 0;
1065 }
1066
1067 /* send GR EIGRP packet chunk */
1068 eigrp_update_send_GR_part(nbr);
1069
1070 /* if it wasn't last chunk, schedule this thread again */
1071 if (nbr->nbr_gr_packet_type != EIGRP_PACKET_PART_LAST) {
1072 thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
1073 nbr->t_nbr_send_gr = NULL;
1074 }
1075
1076 return 0;
7f57883e
DS
1077}
1078
1079/**
1080 * @fn eigrp_update_send_GR
1081 *
9d303b37
DL
1082 * @param[in] nbr Neighbor who would receive Graceful
1083 * restart
7f57883e
DS
1084 * @param[in] gr_type Who executed Graceful restart
1085 * @param[in] vty Virtual terminal for log output
1086 *
1087 * @return void
1088 *
1089 * @par
1090 * Function used for sending Graceful restart Update packet:
1091 * Creates Update packet with INIT, RS, EOT flags and include
1092 * all route except those filtered
1093 */
d62a17ae 1094void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
1095 struct vty *vty)
7f57883e 1096{
d62a17ae 1097 struct eigrp_prefix_entry *pe2;
1098 struct listnode *node2, *nnode2;
1099 struct list *prefixes;
1100
1101 if (gr_type == EIGRP_GR_FILTER) {
1102 /* function was called after applying filtration */
1103 zlog_info(
1104 "Neighbor %s (%s) is resync: route configuration changed",
1105 inet_ntoa(nbr->src),
1106 ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
1107 } else if (gr_type == EIGRP_GR_MANUAL) {
1108 /* Graceful restart was called manually */
1109 zlog_info("Neighbor %s (%s) is resync: manually cleared",
1110 inet_ntoa(nbr->src),
1111 ifindex2ifname(nbr->ei->ifp->ifindex, VRF_DEFAULT));
1112
1113 if (vty != NULL) {
1114 vty_time_print(vty, 0);
1115 vty_out(vty,
1116 "Neighbor %s (%s) is resync: manually cleared\n",
1117 inet_ntoa(nbr->src),
1118 ifindex2ifname(nbr->ei->ifp->ifindex,
1119 VRF_DEFAULT));
1120 }
1121 }
1122
1123 prefixes = list_new();
1124 /* add all prefixes from topology table to list */
1125 for (ALL_LIST_ELEMENTS(nbr->ei->eigrp->topology_table, node2, nnode2,
1126 pe2)) {
1127 listnode_add(prefixes, pe2);
1128 }
1129
1130 /* save prefixes to neighbor */
1131 nbr->nbr_gr_prefixes_send = prefixes;
1132 /* indicate, that this is first GR Update packet chunk */
1133 nbr->nbr_gr_packet_type = EIGRP_PACKET_PART_FIRST;
1134 /* execute packet sending in thread */
1135 thread_execute(master, eigrp_update_send_GR_thread, nbr, 0);
1136 nbr->t_nbr_send_gr = NULL;
7f57883e
DS
1137}
1138
1139/**
1140 * @fn eigrp_update_send_interface_GR
1141 *
9d303b37
DL
1142 * @param[in] ei Interface to neighbors of which the GR
1143 * is sent
7f57883e
DS
1144 * @param[in] gr_type Who executed Graceful restart
1145 * @param[in] vty Virtual terminal for log output
1146 *
1147 * @return void
1148 *
1149 * @par
1150 * Function used for sending Graceful restart Update packet
1151 * to all neighbors on specified interface.
1152 */
d62a17ae 1153void eigrp_update_send_interface_GR(struct eigrp_interface *ei,
1154 enum GR_type gr_type, struct vty *vty)
7f57883e 1155{
d62a17ae 1156 struct listnode *node;
1157 struct eigrp_neighbor *nbr;
1158
1159 /* iterate over all neighbors on eigrp interface */
1160 for (ALL_LIST_ELEMENTS_RO(ei->nbrs, node, nbr)) {
1161 /* send GR to neighbor */
1162 eigrp_update_send_GR(nbr, gr_type, vty);
1163 }
7f57883e
DS
1164}
1165
1166/**
1167 * @fn eigrp_update_send_process_GR
1168 *
1169 * @param[in] eigrp EIGRP process
1170 * @param[in] gr_type Who executed Graceful restart
1171 * @param[in] vty Virtual terminal for log output
1172 *
1173 * @return void
1174 *
1175 * @par
1176 * Function used for sending Graceful restart Update packet
1177 * to all neighbors in eigrp process.
1178 */
d62a17ae 1179void eigrp_update_send_process_GR(struct eigrp *eigrp, enum GR_type gr_type,
1180 struct vty *vty)
7f57883e 1181{
d62a17ae 1182 struct listnode *node;
1183 struct eigrp_interface *ei;
1184
1185 /* iterate over all eigrp interfaces */
1186 for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
1187 /* send GR to all neighbors on interface */
1188 eigrp_update_send_interface_GR(ei, gr_type, vty);
1189 }
f9e5c9ca 1190}