2 * EIGRP Sending and Receiving EIGRP Hello Packets.
3 * Copyright (C) 2013-2016
15 * This file is part of GNU Zebra.
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
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.
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
40 #include "sockunion.h"
48 #include "eigrpd/eigrp_structs.h"
49 #include "eigrpd/eigrpd.h"
50 #include "eigrpd/eigrp_interface.h"
51 #include "eigrpd/eigrp_neighbor.h"
52 #include "eigrpd/eigrp_packet.h"
53 #include "eigrpd/eigrp_zebra.h"
54 #include "eigrpd/eigrp_vty.h"
55 #include "eigrpd/eigrp_dump.h"
56 #include "eigrpd/eigrp_macros.h"
57 #include "eigrpd/eigrp_errors.h"
59 /* Packet Type String. */
60 static const struct message eigrp_general_tlv_type_str
[] = {
61 {EIGRP_TLV_PARAMETER
, "PARAMETER"},
62 {EIGRP_TLV_AUTH
, "AUTH"},
63 {EIGRP_TLV_SEQ
, "SEQ"},
64 {EIGRP_TLV_SW_VERSION
, "SW_VERSION"},
65 {EIGRP_TLV_NEXT_MCAST_SEQ
, "NEXT_MCAST_SEQ"},
66 {EIGRP_TLV_PEER_TERMINATION
, "PEER_TERMINATION"},
67 {EIGRP_TLV_PEER_MTRLIST
, "PEER_MTRLIST"},
68 {EIGRP_TLV_PEER_TIDLIST
, "PEER_TIDLIST"},
73 * @fn eigrp_hello_timer
75 * @param[in] thread current execution thread timer is associated with
77 * @return int always returns 0
80 * Called once per "hello" time interval, default 5 seconds
81 * Sends hello packet via multicast for all interfaces eigrp
84 int eigrp_hello_timer(struct thread
*thread
)
86 struct eigrp_interface
*ei
;
88 ei
= THREAD_ARG(thread
);
91 if (IS_DEBUG_EIGRP(0, TIMERS
))
92 zlog_debug("Start Hello Timer (%s) Expire [%u]", IF_NAME(ei
),
95 /* Sending hello packet. */
96 eigrp_hello_send(ei
, EIGRP_HELLO_NORMAL
, NULL
);
98 /* Hello timer set. */
100 thread_add_timer(master
, eigrp_hello_timer
, ei
, ei
->params
.v_hello
,
107 * @fn eigrp_hello_parameter_decode
109 * @param[in] nbr neighbor the ACK should be sent to
110 * @param[in] param pointer packet TLV is stored to
112 * @return uint16_t number of bytes added to packet stream
115 * Encode Parameter TLV, used to convey metric weights and the hold time.
118 * Note the addition of K6 for the new extended metrics, and does not apply to
119 * older TLV packet formats.
121 static struct eigrp_neighbor
*
122 eigrp_hello_parameter_decode(struct eigrp_neighbor
*nbr
,
123 struct eigrp_tlv_hdr_type
*tlv
)
125 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
126 struct TLV_Parameter_Type
*param
= (struct TLV_Parameter_Type
*)tlv
;
128 /* First validate TLV length */
129 if (tlv
->length
< sizeof(struct TLV_Parameter_Type
))
132 /* copy over the values passed in by the neighbor */
139 nbr
->v_holddown
= ntohs(param
->hold_time
);
142 * Check K1-K5 have the correct values to be able to become neighbors
143 * K6 does not have to match
145 if ((eigrp
->k_values
[0] == nbr
->K1
) && (eigrp
->k_values
[1] == nbr
->K2
)
146 && (eigrp
->k_values
[2] == nbr
->K3
)
147 && (eigrp
->k_values
[3] == nbr
->K4
)
148 && (eigrp
->k_values
[4] == nbr
->K5
)) {
150 if (eigrp_nbr_state_get(nbr
) == EIGRP_NEIGHBOR_DOWN
) {
152 "Neighbor %pI4 (%s) is pending: new adjacency",
154 ifindex2ifname(nbr
->ei
->ifp
->ifindex
,
157 /* Expedited hello sent */
158 eigrp_hello_send(nbr
->ei
, EIGRP_HELLO_NORMAL
, NULL
);
160 // if(ntohl(nbr->ei->address->u.prefix4.s_addr) >
161 // ntohl(nbr->src.s_addr))
162 eigrp_update_send_init(nbr
);
164 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_PENDING
);
167 if (eigrp_nbr_state_get(nbr
) != EIGRP_NEIGHBOR_DOWN
) {
168 if ((param
->K1
& param
->K2
& param
->K3
& param
->K4
172 "Neighbor %pI4 (%s) is down: Interface PEER-TERMINATION received",
174 ifindex2ifname(nbr
->ei
->ifp
->ifindex
,
176 eigrp_nbr_delete(nbr
);
180 "Neighbor %pI4 (%s) going down: Kvalue mismatch",
182 ifindex2ifname(nbr
->ei
->ifp
->ifindex
,
184 eigrp_nbr_state_set(nbr
, EIGRP_NEIGHBOR_DOWN
);
193 eigrp_hello_authentication_decode(struct stream
*s
,
194 struct eigrp_tlv_hdr_type
*tlv_header
,
195 struct eigrp_neighbor
*nbr
)
197 struct TLV_MD5_Authentication_Type
*md5
;
199 md5
= (struct TLV_MD5_Authentication_Type
*)tlv_header
;
201 if (md5
->auth_type
== EIGRP_AUTH_TYPE_MD5
) {
202 /* Validate tlv length */
203 if (md5
->length
< sizeof(struct TLV_MD5_Authentication_Type
))
206 return eigrp_check_md5_digest(s
, md5
, nbr
,
207 EIGRP_AUTH_BASIC_HELLO_FLAG
);
208 } else if (md5
->auth_type
== EIGRP_AUTH_TYPE_SHA256
) {
209 /* Validate tlv length */
210 if (md5
->length
< sizeof(struct TLV_SHA256_Authentication_Type
))
213 return eigrp_check_sha256_digest(
214 s
, (struct TLV_SHA256_Authentication_Type
*)tlv_header
,
215 nbr
, EIGRP_AUTH_BASIC_HELLO_FLAG
);
222 * @fn eigrp_sw_version_decode
224 * @param[in] nbr neighbor the ACK shoudl be sent to
225 * @param[in] param pointer to TLV software version information
230 * Read the software version in the specified location.
231 * This consists of two bytes of OS version, and two bytes of EIGRP
234 static void eigrp_sw_version_decode(struct eigrp_neighbor
*nbr
,
235 struct eigrp_tlv_hdr_type
*tlv
)
237 struct TLV_Software_Type
*version
= (struct TLV_Software_Type
*)tlv
;
239 /* Validate TLV length */
240 if (tlv
->length
< sizeof(struct TLV_Software_Type
))
243 nbr
->os_rel_major
= version
->vender_major
;
244 nbr
->os_rel_minor
= version
->vender_minor
;
245 nbr
->tlv_rel_major
= version
->eigrp_major
;
246 nbr
->tlv_rel_minor
= version
->eigrp_minor
;
251 * @fn eigrp_peer_termination_decode
253 * @param[in] nbr neighbor the ACK shoudl be sent to
254 * @param[in] tlv pointer to TLV software version information
259 * Read the address in the TLV and match to out address. If
260 * a match is found, move the sending neighbor to the down state. If
261 * out address is not in the TLV, then ignore the peer termination
263 static void eigrp_peer_termination_decode(struct eigrp_neighbor
*nbr
,
264 struct eigrp_tlv_hdr_type
*tlv
)
266 struct eigrp
*eigrp
= nbr
->ei
->eigrp
;
267 struct TLV_Peer_Termination_type
*param
=
268 (struct TLV_Peer_Termination_type
*)tlv
;
270 /* Validate TLV length */
271 if (tlv
->length
< sizeof(struct TLV_Peer_Termination_type
))
274 uint32_t my_ip
= nbr
->ei
->address
.u
.prefix4
.s_addr
;
275 uint32_t received_ip
= param
->neighbor_ip
;
277 if (my_ip
== received_ip
) {
279 "Neighbor %pI4 (%s) is down: Peer Termination received",
281 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
));
282 /* set neighbor to DOWN */
283 nbr
->state
= EIGRP_NEIGHBOR_DOWN
;
284 /* delete neighbor */
285 eigrp_nbr_delete(nbr
);
290 * @fn eigrp_peer_termination_encode
292 * @param[in,out] s packet stream TLV is stored to
293 * @param[in] nbr_addr pointer to neighbor address for Peer
296 * @return uint16_t number of bytes added to packet stream
299 * Function used to encode Peer Termination TLV to Hello packet.
301 static uint16_t eigrp_peer_termination_encode(struct stream
*s
,
302 struct in_addr
*nbr_addr
)
304 uint16_t length
= EIGRP_TLV_PEER_TERMINATION_LEN
;
306 /* fill in type and length */
307 stream_putw(s
, EIGRP_TLV_PEER_TERMINATION
);
308 stream_putw(s
, length
);
310 /* fill in unknown field 0x04 */
311 stream_putc(s
, 0x04);
313 /* finally neighbor IP address */
314 stream_put_ipv4(s
, nbr_addr
->s_addr
);
320 * @fn eigrp_hello_receive
322 * @param[in] eigrp eigrp routing process
323 * @param[in] iph pointer to ip header
324 * @param[in] eigrph pointer to eigrp header
325 * @param[in] s input ip stream
326 * @param[in] ei eigrp interface packet arrived on
327 * @param[in] size size of eigrp packet
332 * This is the main worker function for processing hello packets. It
333 * will validate the peer associated with the src ip address of the ip
334 * header, and then decode each of the general TLVs which the packet
338 * Not all TLVs are current decoder. This is a work in progress..
340 void eigrp_hello_receive(struct eigrp
*eigrp
, struct ip
*iph
,
341 struct eigrp_header
*eigrph
, struct stream
*s
,
342 struct eigrp_interface
*ei
, int size
)
344 struct eigrp_tlv_hdr_type
*tlv_header
;
345 struct eigrp_neighbor
*nbr
;
349 /* get neighbor struct */
350 nbr
= eigrp_nbr_get(ei
, eigrph
, iph
);
352 /* neighbor must be valid, eigrp_nbr_get creates if none existed */
355 if (IS_DEBUG_EIGRP_PACKET(eigrph
->opcode
- 1, RECV
))
356 zlog_debug("Processing Hello size[%u] int(%s) nbr(%pI4)", size
,
357 ifindex2ifname(nbr
->ei
->ifp
->ifindex
, eigrp
->vrf_id
),
360 size
-= EIGRP_HEADER_LEN
;
364 tlv_header
= (struct eigrp_tlv_hdr_type
*)eigrph
->tlv
;
367 type
= ntohs(tlv_header
->type
);
368 length
= ntohs(tlv_header
->length
);
370 /* Validate length against packet size */
374 if ((length
> 0) && (length
<= size
)) {
375 if (IS_DEBUG_EIGRP_PACKET(0, RECV
))
378 lookup_msg(eigrp_general_tlv_type_str
,
381 // determine what General TLV is being processed
383 case EIGRP_TLV_PARAMETER
:
384 nbr
= eigrp_hello_parameter_decode(nbr
,
389 case EIGRP_TLV_AUTH
: {
390 if (eigrp_hello_authentication_decode(
400 case EIGRP_TLV_SW_VERSION
:
401 eigrp_sw_version_decode(nbr
, tlv_header
);
403 case EIGRP_TLV_NEXT_MCAST_SEQ
:
405 case EIGRP_TLV_PEER_TERMINATION
:
406 eigrp_peer_termination_decode(nbr
, tlv_header
);
409 case EIGRP_TLV_PEER_MTRLIST
:
410 case EIGRP_TLV_PEER_TIDLIST
:
417 tlv_header
= (struct eigrp_tlv_hdr_type
*)(((char *)tlv_header
)
424 /*If received packet is hello with Parameter TLV*/
425 if (ntohl(eigrph
->ack
) == 0) {
426 /* increment statistics. */
429 eigrp_nbr_state_update(nbr
);
432 if (IS_DEBUG_EIGRP_PACKET(0, RECV
))
433 zlog_debug("Hello Packet received from %pI4", &nbr
->src
);
439 void eigrp_sw_version_initialize(void)
441 char ver_string
[] = VERSION
;
442 char *dash
= strstr(ver_string
, "-");
448 ret
= sscanf(ver_string
, "%" SCNu32
".%" SCNu32
, &FRR_MAJOR
,
451 flog_err(EC_EIGRP_PACKET
,
452 "Did not Properly parse %s, please fix VERSION string",
457 * @fn eigrp_sw_version_encode
459 * @param[in,out] s packet stream TLV is stored to
461 * @return uint16_t number of bytes added to packet stream
464 * Store the software version in the specified location.
465 * This consists of two bytes of OS version, and two bytes of EIGRP
468 static uint16_t eigrp_sw_version_encode(struct stream
*s
)
470 uint16_t length
= EIGRP_TLV_SW_VERSION_LEN
;
472 // setup the tlv fields
473 stream_putw(s
, EIGRP_TLV_SW_VERSION
);
474 stream_putw(s
, length
);
476 stream_putc(s
, FRR_MAJOR
); //!< major os version
477 stream_putc(s
, FRR_MINOR
); //!< minor os version
479 /* and the core eigrp version */
480 stream_putc(s
, EIGRP_MAJOR_VERSION
);
481 stream_putc(s
, EIGRP_MINOR_VERSION
);
487 * @fn eigrp_tidlist_encode
489 * @param[in,out] s packet stream TLV is stored to
494 * If doing mutli-topology, then store the supported TID list.
495 * This is currently a place holder function
497 static uint16_t eigrp_tidlist_encode(struct stream
*s
)
499 // uint16_t length = EIGRP_TLV_SW_VERSION_LEN;
504 * @fn eigrp_sequence_encode
506 * @param[in,out] s packet stream TLV is stored to
508 * @return uint16_t number of bytes added to packet stream
511 * Part of conditional receive process
514 static uint16_t eigrp_sequence_encode(struct eigrp
*eigrp
, struct stream
*s
)
516 uint16_t length
= EIGRP_TLV_SEQ_BASE_LEN
;
517 struct eigrp_interface
*ei
;
518 struct listnode
*node
, *node2
, *nnode2
;
519 struct eigrp_neighbor
*nbr
;
520 size_t backup_end
, size_end
;
523 // add in the parameters TLV
524 backup_end
= stream_get_endp(s
);
525 stream_putw(s
, EIGRP_TLV_SEQ
);
527 stream_putw(s
, 0x0000);
528 stream_putc(s
, IPV4_MAX_BYTELEN
);
531 for (ALL_LIST_ELEMENTS_RO(eigrp
->eiflist
, node
, ei
)) {
532 for (ALL_LIST_ELEMENTS(ei
->nbrs
, node2
, nnode2
, nbr
)) {
533 if (nbr
->multicast_queue
->count
> 0) {
534 length
+= (uint16_t)stream_put_ipv4(
542 stream_set_endp(s
, backup_end
);
546 backup_end
= stream_get_endp(s
);
547 stream_set_endp(s
, size_end
);
548 stream_putw(s
, length
);
549 stream_set_endp(s
, backup_end
);
555 * @fn eigrp_sequence_encode
557 * @param[in,out] s packet stream TLV is stored to
559 * @return uint16_t number of bytes added to packet stream
562 * Part of conditional receive process
565 static uint16_t eigrp_next_sequence_encode(struct eigrp
*eigrp
,
568 uint16_t length
= EIGRP_NEXT_SEQUENCE_TLV_SIZE
;
570 // add in the parameters TLV
571 stream_putw(s
, EIGRP_TLV_NEXT_MCAST_SEQ
);
572 stream_putw(s
, EIGRP_NEXT_SEQUENCE_TLV_SIZE
);
573 stream_putl(s
, eigrp
->sequence_number
+ 1);
579 * @fn eigrp_hello_parameter_encode
581 * @param[in] ei pointer to interface hello packet came in on
582 * @param[in,out] s packet stream TLV is stored to
584 * @return uint16_t number of bytes added to packet stream
587 * Encode Parameter TLV, used to convey metric weights and the hold time.
590 * Note the addition of K6 for the new extended metrics, and does not apply to
591 * older TLV packet formats.
593 static uint16_t eigrp_hello_parameter_encode(struct eigrp_interface
*ei
,
594 struct stream
*s
, uint8_t flags
)
596 // add in the parameters TLV
597 stream_putw(s
, EIGRP_TLV_PARAMETER
);
598 stream_putw(s
, EIGRP_TLV_PARAMETER_LEN
);
600 // if graceful shutdown is needed to be announced, send all 255 in K
602 if (flags
& EIGRP_HELLO_GRACEFUL_SHUTDOWN
) {
603 stream_putc(s
, 0xff); /* K1 */
604 stream_putc(s
, 0xff); /* K2 */
605 stream_putc(s
, 0xff); /* K3 */
606 stream_putc(s
, 0xff); /* K4 */
607 stream_putc(s
, 0xff); /* K5 */
608 stream_putc(s
, 0xff); /* K6 */
609 } else // set k values
611 stream_putc(s
, ei
->eigrp
->k_values
[0]); /* K1 */
612 stream_putc(s
, ei
->eigrp
->k_values
[1]); /* K2 */
613 stream_putc(s
, ei
->eigrp
->k_values
[2]); /* K3 */
614 stream_putc(s
, ei
->eigrp
->k_values
[3]); /* K4 */
615 stream_putc(s
, ei
->eigrp
->k_values
[4]); /* K5 */
616 stream_putc(s
, ei
->eigrp
->k_values
[5]); /* K6 */
619 // and set hold time value..
620 stream_putw(s
, ei
->params
.v_wait
);
622 return EIGRP_TLV_PARAMETER_LEN
;
626 * @fn eigrp_hello_encode
628 * @param[in] ei pointer to interface hello packet came in on
629 * @param[in] s packet stream TLV is stored to
630 * @param[in] ack if non-zero, neigbors sequence packet to ack
631 * @param[in] flags type of hello packet
632 * @param[in] nbr_addr pointer to neighbor address for Peer
635 * @return eigrp_packet pointer initialize hello packet
638 * Allocate an EIGRP hello packet, and add in the the approperate TLVs
641 static struct eigrp_packet
*eigrp_hello_encode(struct eigrp_interface
*ei
,
642 in_addr_t addr
, uint32_t ack
,
644 struct in_addr
*nbr_addr
)
646 struct eigrp_packet
*ep
;
647 uint16_t length
= EIGRP_HEADER_LEN
;
649 // allocate a new packet to be sent
650 ep
= eigrp_packet_new(EIGRP_PACKET_MTU(ei
->ifp
->mtu
), NULL
);
653 // encode common header feilds
654 eigrp_packet_header_init(EIGRP_OPC_HELLO
, ei
->eigrp
, ep
->s
, 0,
657 // encode Authentication TLV
658 if ((ei
->params
.auth_type
== EIGRP_AUTH_TYPE_MD5
)
659 && (ei
->params
.auth_keychain
!= NULL
)) {
660 length
+= eigrp_add_authTLV_MD5_to_stream(ep
->s
, ei
);
661 } else if ((ei
->params
.auth_type
== EIGRP_AUTH_TYPE_SHA256
)
662 && (ei
->params
.auth_keychain
!= NULL
)) {
663 length
+= eigrp_add_authTLV_SHA256_to_stream(ep
->s
, ei
);
666 /* encode appropriate parameters to Hello packet */
667 if (flags
& EIGRP_HELLO_GRACEFUL_SHUTDOWN
)
668 length
+= eigrp_hello_parameter_encode(
669 ei
, ep
->s
, EIGRP_HELLO_GRACEFUL_SHUTDOWN
);
671 length
+= eigrp_hello_parameter_encode(
672 ei
, ep
->s
, EIGRP_HELLO_NORMAL
);
674 // figure out the version of code we're running
675 length
+= eigrp_sw_version_encode(ep
->s
);
677 if (flags
& EIGRP_HELLO_ADD_SEQUENCE
) {
678 length
+= eigrp_sequence_encode(ei
->eigrp
, ep
->s
);
679 length
+= eigrp_next_sequence_encode(ei
->eigrp
, ep
->s
);
682 // add in the TID list if doing multi-topology
683 length
+= eigrp_tidlist_encode(ep
->s
);
685 /* encode Peer Termination TLV if needed */
686 if (flags
& EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR
)
688 eigrp_peer_termination_encode(ep
->s
, nbr_addr
);
693 // set soruce address for the hello packet
694 ep
->dst
.s_addr
= addr
;
696 if ((ei
->params
.auth_type
== EIGRP_AUTH_TYPE_MD5
)
697 && (ei
->params
.auth_keychain
!= NULL
)) {
698 eigrp_make_md5_digest(ei
, ep
->s
,
699 EIGRP_AUTH_BASIC_HELLO_FLAG
);
700 } else if ((ei
->params
.auth_type
== EIGRP_AUTH_TYPE_SHA256
)
701 && (ei
->params
.auth_keychain
!= NULL
)) {
702 eigrp_make_sha256_digest(ei
, ep
->s
,
703 EIGRP_AUTH_BASIC_HELLO_FLAG
);
707 eigrp_packet_checksum(ei
, ep
->s
, length
);
714 * @fn eigrp_hello_send
716 * @param[in] nbr neighbor the ACK should be sent to
721 * Send (unicast) a hello packet with the destination address
722 * associated with the neighbor. The eigrp header ACK feild will be
723 * updated to the neighbor's sequence number to acknolodge any
724 * outstanding packets
726 void eigrp_hello_send_ack(struct eigrp_neighbor
*nbr
)
728 struct eigrp_packet
*ep
;
730 /* if packet succesfully created, add it to the interface queue */
731 ep
= eigrp_hello_encode(nbr
->ei
, nbr
->src
.s_addr
,
732 nbr
->recv_sequence_number
, EIGRP_HELLO_NORMAL
,
736 if (IS_DEBUG_EIGRP_PACKET(0, SEND
))
737 zlog_debug("Queueing [Hello] Ack Seq [%u] nbr [%pI4]",
738 nbr
->recv_sequence_number
, &nbr
->src
);
740 /* Add packet to the top of the interface output queue*/
741 eigrp_fifo_push(nbr
->ei
->obuf
, ep
);
743 /* Hook thread to write packet. */
744 if (nbr
->ei
->on_write_q
== 0) {
745 listnode_add(nbr
->ei
->eigrp
->oi_write_q
, nbr
->ei
);
746 nbr
->ei
->on_write_q
= 1;
748 thread_add_write(master
, eigrp_write
, nbr
->ei
->eigrp
,
749 nbr
->ei
->eigrp
->fd
, &nbr
->ei
->eigrp
->t_write
);
754 * @fn eigrp_hello_send
756 * @param[in] ei pointer to interface hello should be sent
757 * @param[in] flags type of hello packet
758 * @param[in] nbr_addr pointer to neighbor address for Peer
764 * Build and enqueue a generic (multicast) periodic hello packet for
765 * sending. If no packets are currently queues, the packet will be
768 void eigrp_hello_send(struct eigrp_interface
*ei
, uint8_t flags
,
769 struct in_addr
*nbr_addr
)
771 struct eigrp_packet
*ep
= NULL
;
773 if (IS_DEBUG_EIGRP_PACKET(0, SEND
))
774 zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei
));
776 /* if packet was succesfully created, then add it to the interface queue
778 ep
= eigrp_hello_encode(ei
, htonl(EIGRP_MULTICAST_ADDRESS
), 0, flags
,
782 // Add packet to the top of the interface output queue
783 eigrp_fifo_push(ei
->obuf
, ep
);
785 /* Hook thread to write packet. */
786 if (ei
->on_write_q
== 0) {
787 listnode_add(ei
->eigrp
->oi_write_q
, ei
);
791 if (ei
->eigrp
->t_write
== NULL
) {
792 if (flags
& EIGRP_HELLO_GRACEFUL_SHUTDOWN
) {
793 thread_execute(master
, eigrp_write
, ei
->eigrp
,
796 thread_add_write(master
, eigrp_write
, ei
->eigrp
,
798 &ei
->eigrp
->t_write
);