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