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