Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* BGP-4 Finite State Machine |
3 | | * From RFC1771 [A Border Gateway Protocol 4 (BGP-4)] |
4 | | * Copyright (C) 1996, 97, 98 Kunihiro Ishiguro |
5 | | */ |
6 | | #define FUZZING 1 |
7 | | |
8 | | #include <zebra.h> |
9 | | |
10 | | #include "linklist.h" |
11 | | #include "prefix.h" |
12 | | #include "sockunion.h" |
13 | | #include "frrevent.h" |
14 | | #include "log.h" |
15 | | #include "stream.h" |
16 | | #include "ringbuf.h" |
17 | | #include "memory.h" |
18 | | #include "plist.h" |
19 | | #include "workqueue.h" |
20 | | #include "queue.h" |
21 | | #include "filter.h" |
22 | | #include "command.h" |
23 | | #include "lib_errors.h" |
24 | | #include "zclient.h" |
25 | | #include "lib/json.h" |
26 | | #include "bgpd/bgpd.h" |
27 | | #include "bgpd/bgp_attr.h" |
28 | | #include "bgpd/bgp_debug.h" |
29 | | #include "bgpd/bgp_errors.h" |
30 | | #include "bgpd/bgp_fsm.h" |
31 | | #include "bgpd/bgp_packet.h" |
32 | | #include "bgpd/bgp_network.h" |
33 | | #include "bgpd/bgp_route.h" |
34 | | #include "bgpd/bgp_dump.h" |
35 | | #include "bgpd/bgp_open.h" |
36 | | #include "bgpd/bgp_advertise.h" |
37 | | #include "bgpd/bgp_community.h" |
38 | | #include "bgpd/bgp_updgrp.h" |
39 | | #include "bgpd/bgp_nht.h" |
40 | | #include "bgpd/bgp_bfd.h" |
41 | | #include "bgpd/bgp_memory.h" |
42 | | #include "bgpd/bgp_keepalives.h" |
43 | | #include "bgpd/bgp_io.h" |
44 | | #include "bgpd/bgp_zebra.h" |
45 | | #include "bgpd/bgp_vty.h" |
46 | | |
47 | | DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer)); |
48 | | DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer)); |
49 | | |
50 | | enum bgp_fsm_state_progress { |
51 | | BGP_FSM_FAILURE_AND_DELETE = -2, |
52 | | BGP_FSM_FAILURE = -1, |
53 | | BGP_FSM_SUCCESS = 0, |
54 | | BGP_FSM_SUCCESS_STATE_TRANSFER = 1, |
55 | | }; |
56 | | |
57 | | /* Definition of display strings corresponding to FSM events. This should be |
58 | | * kept consistent with the events defined in bgpd.h |
59 | | */ |
60 | | static const char *const bgp_event_str[] = { |
61 | | NULL, |
62 | | "BGP_Start", |
63 | | "BGP_Stop", |
64 | | "TCP_connection_open", |
65 | | "TCP_connection_open_w_delay", |
66 | | "TCP_connection_closed", |
67 | | "TCP_connection_open_failed", |
68 | | "TCP_fatal_error", |
69 | | "ConnectRetry_timer_expired", |
70 | | "Hold_Timer_expired", |
71 | | "KeepAlive_timer_expired", |
72 | | "DelayOpen_timer_expired", |
73 | | "Receive_OPEN_message", |
74 | | "Receive_KEEPALIVE_message", |
75 | | "Receive_UPDATE_message", |
76 | | "Receive_NOTIFICATION_message", |
77 | | "Clearing_Completed", |
78 | | }; |
79 | | |
80 | | /* BGP FSM (finite state machine) has three types of functions. Type |
81 | | one is thread functions. Type two is event functions. Type three |
82 | | is FSM functions. Timer functions are set by bgp_timer_set |
83 | | function. */ |
84 | | |
85 | | /* BGP event function. */ |
86 | | void bgp_event(struct event *event); |
87 | | |
88 | | /* BGP thread functions. */ |
89 | | static void bgp_start_timer(struct event *event); |
90 | | static void bgp_connect_timer(struct event *event); |
91 | | static void bgp_holdtime_timer(struct event *event); |
92 | | static void bgp_delayopen_timer(struct event *event); |
93 | | |
94 | | /* BGP FSM functions. */ |
95 | | static enum bgp_fsm_state_progress bgp_start(struct peer *); |
96 | | |
97 | | /* Register peer with NHT */ |
98 | | int bgp_peer_reg_with_nht(struct peer *peer) |
99 | 0 | { |
100 | 0 | int connected = 0; |
101 | |
|
102 | 0 | if (peer->sort == BGP_PEER_EBGP && peer->ttl == BGP_DEFAULT_TTL |
103 | 0 | && !CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK) |
104 | 0 | && !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_DISABLE_NH_CONNECTED_CHK)) |
105 | 0 | connected = 1; |
106 | |
|
107 | 0 | return bgp_find_or_add_nexthop( |
108 | 0 | peer->bgp, peer->bgp, family2afi(peer->su.sa.sa_family), |
109 | 0 | SAFI_UNICAST, NULL, peer, connected, NULL); |
110 | 0 | } |
111 | | |
112 | | static void peer_xfer_stats(struct peer *peer_dst, struct peer *peer_src) |
113 | 0 | { |
114 | | /* Copy stats over. These are only the pre-established state stats */ |
115 | 0 | peer_dst->open_in += peer_src->open_in; |
116 | 0 | peer_dst->open_out += peer_src->open_out; |
117 | 0 | peer_dst->keepalive_in += peer_src->keepalive_in; |
118 | 0 | peer_dst->keepalive_out += peer_src->keepalive_out; |
119 | 0 | peer_dst->notify_in += peer_src->notify_in; |
120 | 0 | peer_dst->notify_out += peer_src->notify_out; |
121 | 0 | peer_dst->dynamic_cap_in += peer_src->dynamic_cap_in; |
122 | 0 | peer_dst->dynamic_cap_out += peer_src->dynamic_cap_out; |
123 | 0 | } |
124 | | |
125 | | static struct peer *peer_xfer_conn(struct peer *from_peer) |
126 | 0 | { |
127 | 0 | struct peer *peer; |
128 | 0 | afi_t afi; |
129 | 0 | safi_t safi; |
130 | 0 | int fd; |
131 | 0 | enum bgp_fsm_status status, pstatus; |
132 | 0 | enum bgp_fsm_events last_evt, last_maj_evt; |
133 | |
|
134 | 0 | assert(from_peer != NULL); |
135 | |
|
136 | 0 | peer = from_peer->doppelganger; |
137 | |
|
138 | 0 | if (!peer || !CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) |
139 | 0 | return from_peer; |
140 | | |
141 | | /* |
142 | | * Let's check that we are not going to loose known configuration |
143 | | * state based upon doppelganger rules. |
144 | | */ |
145 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
146 | 0 | if (from_peer->afc[afi][safi] != peer->afc[afi][safi]) { |
147 | 0 | flog_err( |
148 | 0 | EC_BGP_DOPPELGANGER_CONFIG, |
149 | 0 | "from_peer->afc[%d][%d] is not the same as what we are overwriting", |
150 | 0 | afi, safi); |
151 | 0 | return NULL; |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | 0 | if (bgp_debug_neighbor_events(peer)) |
156 | 0 | zlog_debug("%s: peer transfer %p fd %d -> %p fd %d)", |
157 | 0 | from_peer->host, from_peer, from_peer->fd, peer, |
158 | 0 | peer->fd); |
159 | |
|
160 | 0 | bgp_writes_off(peer); |
161 | 0 | bgp_reads_off(peer); |
162 | 0 | bgp_writes_off(from_peer); |
163 | 0 | bgp_reads_off(from_peer); |
164 | | |
165 | | /* |
166 | | * Before exchanging FD remove doppelganger from |
167 | | * keepalive peer hash. It could be possible conf peer |
168 | | * fd is set to -1. If blocked on lock then keepalive |
169 | | * thread can access peer pointer with fd -1. |
170 | | */ |
171 | 0 | bgp_keepalives_off(from_peer); |
172 | |
|
173 | 0 | EVENT_OFF(peer->t_routeadv); |
174 | 0 | EVENT_OFF(peer->t_connect); |
175 | 0 | EVENT_OFF(peer->t_delayopen); |
176 | 0 | EVENT_OFF(peer->t_connect_check_r); |
177 | 0 | EVENT_OFF(peer->t_connect_check_w); |
178 | 0 | EVENT_OFF(from_peer->t_routeadv); |
179 | 0 | EVENT_OFF(from_peer->t_connect); |
180 | 0 | EVENT_OFF(from_peer->t_delayopen); |
181 | 0 | EVENT_OFF(from_peer->t_connect_check_r); |
182 | 0 | EVENT_OFF(from_peer->t_connect_check_w); |
183 | 0 | EVENT_OFF(from_peer->t_process_packet); |
184 | | |
185 | | /* |
186 | | * At this point in time, it is possible that there are packets pending |
187 | | * on various buffers. Those need to be transferred or dropped, |
188 | | * otherwise we'll get spurious failures during session establishment. |
189 | | */ |
190 | 0 | frr_with_mutex (&peer->io_mtx, &from_peer->io_mtx) { |
191 | 0 | fd = peer->fd; |
192 | 0 | peer->fd = from_peer->fd; |
193 | 0 | from_peer->fd = fd; |
194 | |
|
195 | 0 | stream_fifo_clean(peer->ibuf); |
196 | 0 | stream_fifo_clean(peer->obuf); |
197 | | |
198 | | /* |
199 | | * this should never happen, since bgp_process_packet() is the |
200 | | * only task that sets and unsets the current packet and it |
201 | | * runs in our pthread. |
202 | | */ |
203 | 0 | if (peer->curr) { |
204 | 0 | flog_err( |
205 | 0 | EC_BGP_PKT_PROCESS, |
206 | 0 | "[%s] Dropping pending packet on connection transfer:", |
207 | 0 | peer->host); |
208 | | /* there used to be a bgp_packet_dump call here, but |
209 | | * that's extremely confusing since there's no way to |
210 | | * identify the packet in MRT dumps or BMP as dropped |
211 | | * due to connection transfer. |
212 | | */ |
213 | 0 | stream_free(peer->curr); |
214 | 0 | peer->curr = NULL; |
215 | 0 | } |
216 | | |
217 | | // copy each packet from old peer's output queue to new peer |
218 | 0 | while (from_peer->obuf->head) |
219 | 0 | stream_fifo_push(peer->obuf, |
220 | 0 | stream_fifo_pop(from_peer->obuf)); |
221 | | |
222 | | // copy each packet from old peer's input queue to new peer |
223 | 0 | while (from_peer->ibuf->head) |
224 | 0 | stream_fifo_push(peer->ibuf, |
225 | 0 | stream_fifo_pop(from_peer->ibuf)); |
226 | |
|
227 | 0 | ringbuf_wipe(peer->ibuf_work); |
228 | 0 | ringbuf_copy(peer->ibuf_work, from_peer->ibuf_work, |
229 | 0 | ringbuf_remain(from_peer->ibuf_work)); |
230 | 0 | } |
231 | |
|
232 | 0 | peer->as = from_peer->as; |
233 | 0 | peer->v_holdtime = from_peer->v_holdtime; |
234 | 0 | peer->v_keepalive = from_peer->v_keepalive; |
235 | 0 | peer->v_routeadv = from_peer->v_routeadv; |
236 | 0 | peer->v_delayopen = from_peer->v_delayopen; |
237 | 0 | peer->v_gr_restart = from_peer->v_gr_restart; |
238 | 0 | peer->cap = from_peer->cap; |
239 | 0 | peer->remote_role = from_peer->remote_role; |
240 | 0 | status = peer->status; |
241 | 0 | pstatus = peer->ostatus; |
242 | 0 | last_evt = peer->last_event; |
243 | 0 | last_maj_evt = peer->last_major_event; |
244 | 0 | peer->status = from_peer->status; |
245 | 0 | peer->ostatus = from_peer->ostatus; |
246 | 0 | peer->last_event = from_peer->last_event; |
247 | 0 | peer->last_major_event = from_peer->last_major_event; |
248 | 0 | from_peer->status = status; |
249 | 0 | from_peer->ostatus = pstatus; |
250 | 0 | from_peer->last_event = last_evt; |
251 | 0 | from_peer->last_major_event = last_maj_evt; |
252 | 0 | peer->remote_id = from_peer->remote_id; |
253 | 0 | peer->last_reset = from_peer->last_reset; |
254 | 0 | peer->max_packet_size = from_peer->max_packet_size; |
255 | |
|
256 | 0 | BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, |
257 | 0 | peer->bgp->peer); |
258 | |
|
259 | 0 | if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) { |
260 | |
|
261 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); |
262 | |
|
263 | 0 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { |
264 | 0 | peer_nsf_stop(peer); |
265 | 0 | } |
266 | 0 | } |
267 | |
|
268 | 0 | if (peer->hostname) { |
269 | 0 | XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); |
270 | 0 | peer->hostname = NULL; |
271 | 0 | } |
272 | 0 | if (from_peer->hostname != NULL) { |
273 | 0 | peer->hostname = from_peer->hostname; |
274 | 0 | from_peer->hostname = NULL; |
275 | 0 | } |
276 | |
|
277 | 0 | if (peer->domainname) { |
278 | 0 | XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); |
279 | 0 | peer->domainname = NULL; |
280 | 0 | } |
281 | 0 | if (from_peer->domainname != NULL) { |
282 | 0 | peer->domainname = from_peer->domainname; |
283 | 0 | from_peer->domainname = NULL; |
284 | 0 | } |
285 | |
|
286 | 0 | if (peer->soft_version) { |
287 | 0 | XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); |
288 | 0 | peer->soft_version = NULL; |
289 | 0 | } |
290 | 0 | if (from_peer->soft_version) { |
291 | 0 | peer->soft_version = from_peer->soft_version; |
292 | 0 | from_peer->soft_version = NULL; |
293 | 0 | } |
294 | |
|
295 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
296 | 0 | peer->af_sflags[afi][safi] = from_peer->af_sflags[afi][safi]; |
297 | 0 | peer->af_cap[afi][safi] = from_peer->af_cap[afi][safi]; |
298 | 0 | peer->afc_nego[afi][safi] = from_peer->afc_nego[afi][safi]; |
299 | 0 | peer->afc_adv[afi][safi] = from_peer->afc_adv[afi][safi]; |
300 | 0 | peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi]; |
301 | 0 | peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi]; |
302 | 0 | peer->llgr[afi][safi] = from_peer->llgr[afi][safi]; |
303 | 0 | } |
304 | |
|
305 | 0 | if (bgp_getsockname(peer) < 0) { |
306 | 0 | flog_err( |
307 | 0 | EC_LIB_SOCKET, |
308 | 0 | "%%bgp_getsockname() failed for %s peer %s fd %d (from_peer fd %d)", |
309 | 0 | (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER) |
310 | 0 | ? "accept" |
311 | 0 | : ""), |
312 | 0 | peer->host, peer->fd, from_peer->fd); |
313 | 0 | BGP_EVENT_ADD(peer, BGP_Stop); |
314 | 0 | BGP_EVENT_ADD(from_peer, BGP_Stop); |
315 | 0 | return NULL; |
316 | 0 | } |
317 | 0 | if (from_peer->status > Active) { |
318 | 0 | if (bgp_getsockname(from_peer) < 0) { |
319 | 0 | flog_err( |
320 | 0 | EC_LIB_SOCKET, |
321 | 0 | "%%bgp_getsockname() failed for %s from_peer %s fd %d (peer fd %d)", |
322 | |
|
323 | 0 | (CHECK_FLAG(from_peer->sflags, |
324 | 0 | PEER_STATUS_ACCEPT_PEER) |
325 | 0 | ? "accept" |
326 | 0 | : ""), |
327 | 0 | from_peer->host, from_peer->fd, peer->fd); |
328 | 0 | bgp_stop(from_peer); |
329 | 0 | from_peer = NULL; |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | | |
334 | | // Note: peer_xfer_stats() must be called with I/O turned OFF |
335 | 0 | if (from_peer) |
336 | 0 | peer_xfer_stats(peer, from_peer); |
337 | | |
338 | | /* Register peer for NHT. This is to allow RAs to be enabled when |
339 | | * needed, even on a passive connection. |
340 | | */ |
341 | 0 | bgp_peer_reg_with_nht(peer); |
342 | 0 | if (from_peer) |
343 | 0 | bgp_replace_nexthop_by_peer(from_peer, peer); |
344 | |
|
345 | 0 | bgp_reads_on(peer); |
346 | 0 | bgp_writes_on(peer); |
347 | 0 | event_add_event(bm->master, bgp_process_packet, peer, 0, |
348 | 0 | &peer->t_process_packet); |
349 | |
|
350 | 0 | return (peer); |
351 | 0 | } |
352 | | |
353 | | /* Hook function called after bgp event is occered. And vty's |
354 | | neighbor command invoke this function after making neighbor |
355 | | structure. */ |
356 | | void bgp_timer_set(struct peer *peer) |
357 | 1 | { |
358 | 1 | #ifdef FUZZING |
359 | 1 | return; |
360 | 0 | #endif |
361 | 0 | afi_t afi; |
362 | 0 | safi_t safi; |
363 | |
|
364 | 0 | switch (peer->status) { |
365 | 0 | case Idle: |
366 | | /* First entry point of peer's finite state machine. In Idle |
367 | | status start timer is on unless peer is shutdown or peer is |
368 | | inactive. All other timer must be turned off */ |
369 | 0 | if (BGP_PEER_START_SUPPRESSED(peer) || !peer_active(peer) |
370 | 0 | || peer->bgp->vrf_id == VRF_UNKNOWN) { |
371 | 0 | EVENT_OFF(peer->t_start); |
372 | 0 | } else { |
373 | 0 | BGP_TIMER_ON(peer->t_start, bgp_start_timer, |
374 | 0 | peer->v_start); |
375 | 0 | } |
376 | 0 | EVENT_OFF(peer->t_connect); |
377 | 0 | EVENT_OFF(peer->t_holdtime); |
378 | 0 | bgp_keepalives_off(peer); |
379 | 0 | EVENT_OFF(peer->t_routeadv); |
380 | 0 | EVENT_OFF(peer->t_delayopen); |
381 | 0 | break; |
382 | | |
383 | 0 | case Connect: |
384 | | /* After start timer is expired, the peer moves to Connect |
385 | | status. Make sure start timer is off and connect timer is |
386 | | on. */ |
387 | 0 | EVENT_OFF(peer->t_start); |
388 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) |
389 | 0 | BGP_TIMER_ON(peer->t_connect, bgp_connect_timer, |
390 | 0 | (peer->v_delayopen + peer->v_connect)); |
391 | 0 | else |
392 | 0 | BGP_TIMER_ON(peer->t_connect, bgp_connect_timer, |
393 | 0 | peer->v_connect); |
394 | |
|
395 | 0 | EVENT_OFF(peer->t_holdtime); |
396 | 0 | bgp_keepalives_off(peer); |
397 | 0 | EVENT_OFF(peer->t_routeadv); |
398 | 0 | break; |
399 | | |
400 | 0 | case Active: |
401 | | /* Active is waiting connection from remote peer. And if |
402 | | connect timer is expired, change status to Connect. */ |
403 | 0 | EVENT_OFF(peer->t_start); |
404 | | /* If peer is passive mode, do not set connect timer. */ |
405 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE) |
406 | 0 | || CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { |
407 | 0 | EVENT_OFF(peer->t_connect); |
408 | 0 | } else { |
409 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) |
410 | 0 | BGP_TIMER_ON( |
411 | 0 | peer->t_connect, bgp_connect_timer, |
412 | 0 | (peer->v_delayopen + peer->v_connect)); |
413 | 0 | else |
414 | 0 | BGP_TIMER_ON(peer->t_connect, bgp_connect_timer, |
415 | 0 | peer->v_connect); |
416 | 0 | } |
417 | 0 | EVENT_OFF(peer->t_holdtime); |
418 | 0 | bgp_keepalives_off(peer); |
419 | 0 | EVENT_OFF(peer->t_routeadv); |
420 | 0 | break; |
421 | | |
422 | 0 | case OpenSent: |
423 | | /* OpenSent status. */ |
424 | 0 | EVENT_OFF(peer->t_start); |
425 | 0 | EVENT_OFF(peer->t_connect); |
426 | 0 | if (peer->v_holdtime != 0) { |
427 | 0 | BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, |
428 | 0 | peer->v_holdtime); |
429 | 0 | } else { |
430 | 0 | EVENT_OFF(peer->t_holdtime); |
431 | 0 | } |
432 | 0 | bgp_keepalives_off(peer); |
433 | 0 | EVENT_OFF(peer->t_routeadv); |
434 | 0 | EVENT_OFF(peer->t_delayopen); |
435 | 0 | break; |
436 | | |
437 | 0 | case OpenConfirm: |
438 | | /* OpenConfirm status. */ |
439 | 0 | EVENT_OFF(peer->t_start); |
440 | 0 | EVENT_OFF(peer->t_connect); |
441 | | |
442 | | /* |
443 | | * If the negotiated Hold Time value is zero, then the Hold Time |
444 | | * timer and KeepAlive timers are not started. |
445 | | * Additionally if a different hold timer has been negotiated |
446 | | * than we must stop then start the timer again |
447 | | */ |
448 | 0 | EVENT_OFF(peer->t_holdtime); |
449 | 0 | if (peer->v_holdtime == 0) |
450 | 0 | bgp_keepalives_off(peer); |
451 | 0 | else { |
452 | 0 | BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, |
453 | 0 | peer->v_holdtime); |
454 | 0 | bgp_keepalives_on(peer); |
455 | 0 | } |
456 | 0 | EVENT_OFF(peer->t_routeadv); |
457 | 0 | EVENT_OFF(peer->t_delayopen); |
458 | 0 | break; |
459 | | |
460 | 0 | case Established: |
461 | | /* In Established status start and connect timer is turned |
462 | | off. */ |
463 | 0 | EVENT_OFF(peer->t_start); |
464 | 0 | EVENT_OFF(peer->t_connect); |
465 | 0 | EVENT_OFF(peer->t_delayopen); |
466 | | |
467 | | /* |
468 | | * Same as OpenConfirm, if holdtime is zero then both holdtime |
469 | | * and keepalive must be turned off. |
470 | | * Additionally if a different hold timer has been negotiated |
471 | | * then we must stop then start the timer again |
472 | | */ |
473 | 0 | EVENT_OFF(peer->t_holdtime); |
474 | 0 | if (peer->v_holdtime == 0) |
475 | 0 | bgp_keepalives_off(peer); |
476 | 0 | else { |
477 | 0 | BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, |
478 | 0 | peer->v_holdtime); |
479 | 0 | bgp_keepalives_on(peer); |
480 | 0 | } |
481 | 0 | break; |
482 | 0 | case Deleted: |
483 | 0 | EVENT_OFF(peer->t_gr_restart); |
484 | 0 | EVENT_OFF(peer->t_gr_stale); |
485 | |
|
486 | 0 | FOREACH_AFI_SAFI (afi, safi) |
487 | 0 | EVENT_OFF(peer->t_llgr_stale[afi][safi]); |
488 | |
|
489 | 0 | EVENT_OFF(peer->t_pmax_restart); |
490 | 0 | EVENT_OFF(peer->t_refresh_stalepath); |
491 | | /* fallthru */ |
492 | 0 | case Clearing: |
493 | 0 | EVENT_OFF(peer->t_start); |
494 | 0 | EVENT_OFF(peer->t_connect); |
495 | 0 | EVENT_OFF(peer->t_holdtime); |
496 | 0 | bgp_keepalives_off(peer); |
497 | 0 | EVENT_OFF(peer->t_routeadv); |
498 | 0 | EVENT_OFF(peer->t_delayopen); |
499 | 0 | break; |
500 | 0 | case BGP_STATUS_MAX: |
501 | 0 | flog_err(EC_LIB_DEVELOPMENT, |
502 | 0 | "BGP_STATUS_MAX while a legal state is not valid state for the FSM"); |
503 | 0 | break; |
504 | 0 | } |
505 | 0 | } |
506 | | |
507 | | /* BGP start timer. This function set BGP_Start event to thread value |
508 | | and process event. */ |
509 | | static void bgp_start_timer(struct event *thread) |
510 | 0 | { |
511 | 0 | struct peer *peer; |
512 | 0 |
|
513 | 0 | peer = EVENT_ARG(thread); |
514 | 0 |
|
515 | 0 | if (bgp_debug_neighbor_events(peer)) |
516 | 0 | zlog_debug("%s [FSM] Timer (start timer expire).", peer->host); |
517 | 0 |
|
518 | 0 | EVENT_VAL(thread) = BGP_Start; |
519 | 0 | bgp_event(thread); /* bgp_event unlocks peer */ |
520 | 0 | } |
521 | | |
522 | | /* BGP connect retry timer. */ |
523 | | static void bgp_connect_timer(struct event *thread) |
524 | 0 | { |
525 | 0 | struct peer *peer; |
526 | 0 |
|
527 | 0 | peer = EVENT_ARG(thread); |
528 | 0 |
|
529 | 0 | /* stop the DelayOpenTimer if it is running */ |
530 | 0 | EVENT_OFF(peer->t_delayopen); |
531 | 0 |
|
532 | 0 | assert(!peer->t_write); |
533 | 0 | assert(!peer->t_read); |
534 | 0 |
|
535 | 0 | if (bgp_debug_neighbor_events(peer)) |
536 | 0 | zlog_debug("%s [FSM] Timer (connect timer expire)", peer->host); |
537 | 0 |
|
538 | 0 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) |
539 | 0 | bgp_stop(peer); |
540 | 0 | else { |
541 | 0 | EVENT_VAL(thread) = ConnectRetry_timer_expired; |
542 | 0 | bgp_event(thread); /* bgp_event unlocks peer */ |
543 | 0 | } |
544 | 0 | } |
545 | | |
546 | | /* BGP holdtime timer. */ |
547 | | static void bgp_holdtime_timer(struct event *thread) |
548 | 0 | { |
549 | 0 | atomic_size_t inq_count; |
550 | 0 | struct peer *peer; |
551 | 0 |
|
552 | 0 | peer = EVENT_ARG(thread); |
553 | 0 |
|
554 | 0 | if (bgp_debug_neighbor_events(peer)) |
555 | 0 | zlog_debug("%s [FSM] Timer (holdtime timer expire)", |
556 | 0 | peer->host); |
557 | 0 |
|
558 | 0 | /* |
559 | 0 | * Given that we do not have any expectation of ordering |
560 | 0 | * for handling packets from a peer -vs- handling |
561 | 0 | * the hold timer for a peer as that they are both |
562 | 0 | * events on the peer. If we have incoming |
563 | 0 | * data on the peers inq, let's give the system a chance |
564 | 0 | * to handle that data. This can be especially true |
565 | 0 | * for systems where we are heavily loaded for one |
566 | 0 | * reason or another. |
567 | 0 | */ |
568 | 0 | inq_count = atomic_load_explicit(&peer->ibuf->count, |
569 | 0 | memory_order_relaxed); |
570 | 0 | if (inq_count) |
571 | 0 | BGP_TIMER_ON(peer->t_holdtime, bgp_holdtime_timer, |
572 | 0 | peer->v_holdtime); |
573 | 0 |
|
574 | 0 | EVENT_VAL(thread) = Hold_Timer_expired; |
575 | 0 | bgp_event(thread); /* bgp_event unlocks peer */ |
576 | 0 | } |
577 | | |
578 | | void bgp_routeadv_timer(struct event *thread) |
579 | 0 | { |
580 | 0 | struct peer *peer; |
581 | |
|
582 | 0 | peer = EVENT_ARG(thread); |
583 | |
|
584 | 0 | if (bgp_debug_neighbor_events(peer)) |
585 | 0 | zlog_debug("%s [FSM] Timer (routeadv timer expire)", |
586 | 0 | peer->host); |
587 | |
|
588 | 0 | peer->synctime = monotime(NULL); |
589 | |
|
590 | 0 | event_add_timer_msec(bm->master, bgp_generate_updgrp_packets, peer, 0, |
591 | 0 | &peer->t_generate_updgrp_packets); |
592 | | |
593 | | /* MRAI timer will be started again when FIFO is built, no need to |
594 | | * do it here. |
595 | | */ |
596 | 0 | } |
597 | | |
598 | | /* RFC 4271 DelayOpenTimer */ |
599 | | void bgp_delayopen_timer(struct event *thread) |
600 | 0 | { |
601 | 0 | struct peer *peer; |
602 | 0 |
|
603 | 0 | peer = EVENT_ARG(thread); |
604 | 0 |
|
605 | 0 | if (bgp_debug_neighbor_events(peer)) |
606 | 0 | zlog_debug("%s [FSM] Timer (DelayOpentimer expire)", |
607 | 0 | peer->host); |
608 | 0 |
|
609 | 0 | EVENT_VAL(thread) = DelayOpen_timer_expired; |
610 | 0 | bgp_event(thread); /* bgp_event unlocks peer */ |
611 | 0 | } |
612 | | |
613 | | /* BGP Peer Down Cause */ |
614 | | const char *const peer_down_str[] = {"", |
615 | | "Router ID changed", |
616 | | "Remote AS changed", |
617 | | "Local AS change", |
618 | | "Cluster ID changed", |
619 | | "Confederation identifier changed", |
620 | | "Confederation peer changed", |
621 | | "RR client config change", |
622 | | "RS client config change", |
623 | | "Update source change", |
624 | | "Address family activated", |
625 | | "Admin. shutdown", |
626 | | "User reset", |
627 | | "BGP Notification received", |
628 | | "BGP Notification send", |
629 | | "Peer closed the session", |
630 | | "Neighbor deleted", |
631 | | "Peer-group add member", |
632 | | "Peer-group delete member", |
633 | | "Capability changed", |
634 | | "Passive config change", |
635 | | "Multihop config change", |
636 | | "NSF peer closed the session", |
637 | | "Intf peering v6only config change", |
638 | | "BFD down received", |
639 | | "Interface down", |
640 | | "Neighbor address lost", |
641 | | "No path to specified Neighbor", |
642 | | "Waiting for Peer IPv6 LLA", |
643 | | "Waiting for VRF to be initialized", |
644 | | "No AFI/SAFI activated for peer", |
645 | | "AS Set config change", |
646 | | "Waiting for peer OPEN", |
647 | | "Reached received prefix count", |
648 | | "Socket Error", |
649 | | "Admin. shutdown (RTT)"}; |
650 | | |
651 | | static void bgp_graceful_restart_timer_off(struct peer *peer) |
652 | 0 | { |
653 | 0 | afi_t afi; |
654 | 0 | safi_t safi; |
655 | 0 |
|
656 | 0 | FOREACH_AFI_SAFI (afi, safi) |
657 | 0 | if (CHECK_FLAG(peer->af_sflags[afi][safi], |
658 | 0 | PEER_STATUS_LLGR_WAIT)) |
659 | 0 | return; |
660 | 0 |
|
661 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); |
662 | 0 | EVENT_OFF(peer->t_gr_stale); |
663 | 0 |
|
664 | 0 | if (peer_dynamic_neighbor(peer) && |
665 | 0 | !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { |
666 | 0 | if (bgp_debug_neighbor_events(peer)) |
667 | 0 | zlog_debug("%s (dynamic neighbor) deleted (%s)", |
668 | 0 | peer->host, __func__); |
669 | 0 | peer_delete(peer); |
670 | 0 | } |
671 | 0 |
|
672 | 0 | bgp_timer_set(peer); |
673 | 0 | } |
674 | | |
675 | | static void bgp_llgr_stale_timer_expire(struct event *thread) |
676 | 0 | { |
677 | 0 | struct peer_af *paf; |
678 | 0 | struct peer *peer; |
679 | 0 | afi_t afi; |
680 | 0 | safi_t safi; |
681 | 0 |
|
682 | 0 | paf = EVENT_ARG(thread); |
683 | 0 |
|
684 | 0 | peer = paf->peer; |
685 | 0 | afi = paf->afi; |
686 | 0 | safi = paf->safi; |
687 | 0 |
|
688 | 0 | /* If the timer for the "Long-lived Stale Time" expires before the |
689 | 0 | * session is re-established, the helper MUST delete all the |
690 | 0 | * stale routes from the neighbor that it is retaining. |
691 | 0 | */ |
692 | 0 | if (bgp_debug_neighbor_events(peer)) |
693 | 0 | zlog_debug("%pBP Long-lived stale timer (%s) expired", peer, |
694 | 0 | get_afi_safi_str(afi, safi, false)); |
695 | 0 |
|
696 | 0 | UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_LLGR_WAIT); |
697 | 0 |
|
698 | 0 | bgp_clear_stale_route(peer, afi, safi); |
699 | 0 |
|
700 | 0 | bgp_graceful_restart_timer_off(peer); |
701 | 0 | } |
702 | | |
703 | | static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) |
704 | 0 | { |
705 | 0 | struct bgp_dest *dest; |
706 | 0 | struct bgp_path_info *pi; |
707 | 0 | struct bgp_table *table; |
708 | 0 | struct attr attr; |
709 | 0 |
|
710 | 0 | if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { |
711 | 0 | for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; |
712 | 0 | dest = bgp_route_next(dest)) { |
713 | 0 | struct bgp_dest *rm; |
714 | 0 |
|
715 | 0 | table = bgp_dest_get_bgp_table_info(dest); |
716 | 0 | if (!table) |
717 | 0 | continue; |
718 | 0 |
|
719 | 0 | for (rm = bgp_table_top(table); rm; |
720 | 0 | rm = bgp_route_next(rm)) |
721 | 0 | for (pi = bgp_dest_get_bgp_path_info(rm); pi; |
722 | 0 | pi = pi->next) { |
723 | 0 | if (pi->peer != peer) |
724 | 0 | continue; |
725 | 0 |
|
726 | 0 | if (bgp_attr_get_community(pi->attr) && |
727 | 0 | community_include( |
728 | 0 | bgp_attr_get_community( |
729 | 0 | pi->attr), |
730 | 0 | COMMUNITY_NO_LLGR)) |
731 | 0 | continue; |
732 | 0 |
|
733 | 0 | if (bgp_debug_neighbor_events(peer)) |
734 | 0 | zlog_debug( |
735 | 0 | "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", |
736 | 0 | peer, &dest->p); |
737 | 0 |
|
738 | 0 | attr = *pi->attr; |
739 | 0 | bgp_attr_add_llgr_community(&attr); |
740 | 0 | pi->attr = bgp_attr_intern(&attr); |
741 | 0 | bgp_recalculate_afi_safi_bestpaths( |
742 | 0 | peer->bgp, afi, safi); |
743 | 0 |
|
744 | 0 | break; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } else { |
748 | 0 | for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; |
749 | 0 | dest = bgp_route_next(dest)) |
750 | 0 | for (pi = bgp_dest_get_bgp_path_info(dest); pi; |
751 | 0 | pi = pi->next) { |
752 | 0 | if (pi->peer != peer) |
753 | 0 | continue; |
754 | 0 |
|
755 | 0 | if (bgp_attr_get_community(pi->attr) && |
756 | 0 | community_include( |
757 | 0 | bgp_attr_get_community(pi->attr), |
758 | 0 | COMMUNITY_NO_LLGR)) |
759 | 0 | continue; |
760 | 0 |
|
761 | 0 | if (bgp_debug_neighbor_events(peer)) |
762 | 0 | zlog_debug( |
763 | 0 | "%pBP Long-lived set stale community (LLGR_STALE) for: %pFX", |
764 | 0 | peer, &dest->p); |
765 | 0 |
|
766 | 0 | attr = *pi->attr; |
767 | 0 | bgp_attr_add_llgr_community(&attr); |
768 | 0 | pi->attr = bgp_attr_intern(&attr); |
769 | 0 | bgp_recalculate_afi_safi_bestpaths(peer->bgp, |
770 | 0 | afi, safi); |
771 | 0 |
|
772 | 0 | break; |
773 | 0 | } |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | | static void bgp_graceful_restart_timer_expire(struct event *thread) |
778 | 0 | { |
779 | 0 | struct peer *peer, *tmp_peer; |
780 | 0 | struct listnode *node, *nnode; |
781 | 0 | struct peer_af *paf; |
782 | 0 | afi_t afi; |
783 | 0 | safi_t safi; |
784 | 0 |
|
785 | 0 | peer = EVENT_ARG(thread); |
786 | 0 |
|
787 | 0 | if (bgp_debug_neighbor_events(peer)) { |
788 | 0 | zlog_debug("%pBP graceful restart timer expired", peer); |
789 | 0 | zlog_debug("%pBP graceful restart stalepath timer stopped", |
790 | 0 | peer); |
791 | 0 | } |
792 | 0 |
|
793 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
794 | 0 | if (!peer->nsf[afi][safi]) |
795 | 0 | continue; |
796 | 0 |
|
797 | 0 | /* Once the "Restart Time" period ends, the LLGR period is |
798 | 0 | * said to have begun and the following procedures MUST be |
799 | 0 | * performed: |
800 | 0 | * |
801 | 0 | * The helper router MUST start a timer for the |
802 | 0 | * "Long-lived Stale Time". |
803 | 0 | * |
804 | 0 | * The helper router MUST attach the LLGR_STALE community |
805 | 0 | * for the stale routes being retained. Note that this |
806 | 0 | * requirement implies that the routes would need to be |
807 | 0 | * readvertised, to disseminate the modified community. |
808 | 0 | */ |
809 | 0 | if (peer->llgr[afi][safi].stale_time) { |
810 | 0 | paf = peer_af_find(peer, afi, safi); |
811 | 0 | if (!paf) |
812 | 0 | continue; |
813 | 0 |
|
814 | 0 | if (bgp_debug_neighbor_events(peer)) |
815 | 0 | zlog_debug( |
816 | 0 | "%pBP Long-lived stale timer (%s) started for %d sec", |
817 | 0 | peer, |
818 | 0 | get_afi_safi_str(afi, safi, false), |
819 | 0 | peer->llgr[afi][safi].stale_time); |
820 | 0 |
|
821 | 0 | SET_FLAG(peer->af_sflags[afi][safi], |
822 | 0 | PEER_STATUS_LLGR_WAIT); |
823 | 0 |
|
824 | 0 | bgp_set_llgr_stale(peer, afi, safi); |
825 | 0 | bgp_clear_stale_route(peer, afi, safi); |
826 | 0 |
|
827 | 0 | event_add_timer(bm->master, bgp_llgr_stale_timer_expire, |
828 | 0 | paf, peer->llgr[afi][safi].stale_time, |
829 | 0 | &peer->t_llgr_stale[afi][safi]); |
830 | 0 |
|
831 | 0 | for (ALL_LIST_ELEMENTS(peer->bgp->peer, node, nnode, |
832 | 0 | tmp_peer)) |
833 | 0 | bgp_announce_route(tmp_peer, afi, safi, false); |
834 | 0 | } else { |
835 | 0 | bgp_clear_stale_route(peer, afi, safi); |
836 | 0 | } |
837 | 0 | } |
838 | 0 |
|
839 | 0 | bgp_graceful_restart_timer_off(peer); |
840 | 0 | } |
841 | | |
842 | | static void bgp_graceful_stale_timer_expire(struct event *thread) |
843 | 0 | { |
844 | 0 | struct peer *peer; |
845 | 0 | afi_t afi; |
846 | 0 | safi_t safi; |
847 | 0 |
|
848 | 0 | peer = EVENT_ARG(thread); |
849 | 0 |
|
850 | 0 | if (bgp_debug_neighbor_events(peer)) |
851 | 0 | zlog_debug("%pBP graceful restart stalepath timer expired", |
852 | 0 | peer); |
853 | 0 |
|
854 | 0 | /* NSF delete stale route */ |
855 | 0 | FOREACH_AFI_SAFI_NSF (afi, safi) |
856 | 0 | if (peer->nsf[afi][safi]) |
857 | 0 | bgp_clear_stale_route(peer, afi, safi); |
858 | 0 | } |
859 | | |
860 | | /* Selection deferral timer processing function */ |
861 | | static void bgp_graceful_deferral_timer_expire(struct event *thread) |
862 | 0 | { |
863 | 0 | struct afi_safi_info *info; |
864 | 0 | afi_t afi; |
865 | 0 | safi_t safi; |
866 | 0 | struct bgp *bgp; |
867 | 0 |
|
868 | 0 | info = EVENT_ARG(thread); |
869 | 0 | afi = info->afi; |
870 | 0 | safi = info->safi; |
871 | 0 | bgp = info->bgp; |
872 | 0 |
|
873 | 0 | if (BGP_DEBUG(update, UPDATE_OUT)) |
874 | 0 | zlog_debug( |
875 | 0 | "afi %d, safi %d : graceful restart deferral timer expired", |
876 | 0 | afi, safi); |
877 | 0 |
|
878 | 0 | bgp->gr_info[afi][safi].eor_required = 0; |
879 | 0 | bgp->gr_info[afi][safi].eor_received = 0; |
880 | 0 | XFREE(MTYPE_TMP, info); |
881 | 0 |
|
882 | 0 | /* Best path selection */ |
883 | 0 | bgp_best_path_select_defer(bgp, afi, safi); |
884 | 0 | } |
885 | | |
886 | | static bool bgp_update_delay_applicable(struct bgp *bgp) |
887 | 0 | { |
888 | | /* update_delay_over flag should be reset (set to 0) for any new |
889 | | applicability of the update-delay during BGP process lifetime. |
890 | | And it should be set after an occurence of the update-delay is |
891 | | over)*/ |
892 | 0 | if (!bgp->update_delay_over) |
893 | 0 | return true; |
894 | 0 | return false; |
895 | 0 | } |
896 | | |
897 | | bool bgp_update_delay_active(struct bgp *bgp) |
898 | 2 | { |
899 | 2 | if (bgp->t_update_delay) |
900 | 0 | return true; |
901 | 2 | return false; |
902 | 2 | } |
903 | | |
904 | | bool bgp_update_delay_configured(struct bgp *bgp) |
905 | 0 | { |
906 | 0 | if (bgp->v_update_delay) |
907 | 0 | return true; |
908 | 0 | return false; |
909 | 0 | } |
910 | | |
911 | | /* Do the post-processing needed when bgp comes out of the read-only mode |
912 | | on ending the update delay. */ |
913 | | void bgp_update_delay_end(struct bgp *bgp) |
914 | 0 | { |
915 | 0 | EVENT_OFF(bgp->t_update_delay); |
916 | 0 | EVENT_OFF(bgp->t_establish_wait); |
917 | | |
918 | | /* Reset update-delay related state */ |
919 | 0 | bgp->update_delay_over = 1; |
920 | 0 | bgp->established = 0; |
921 | 0 | bgp->restarted_peers = 0; |
922 | 0 | bgp->implicit_eors = 0; |
923 | 0 | bgp->explicit_eors = 0; |
924 | |
|
925 | 0 | frr_timestamp(3, bgp->update_delay_end_time, |
926 | 0 | sizeof(bgp->update_delay_end_time)); |
927 | | |
928 | | /* |
929 | | * Add an end-of-initial-update marker to the main process queues so |
930 | | * that |
931 | | * the route advertisement timer for the peers can be started. Also set |
932 | | * the zebra and peer update hold flags. These flags are used to achieve |
933 | | * three stages in the update-delay post processing: |
934 | | * 1. Finish best-path selection for all the prefixes held on the |
935 | | * queues. |
936 | | * (routes in BGP are updated, and peers sync queues are populated |
937 | | * too) |
938 | | * 2. As the eoiu mark is reached in the bgp process routine, ship all |
939 | | * the |
940 | | * routes to zebra. With that zebra should see updates from BGP |
941 | | * close |
942 | | * to each other. |
943 | | * 3. Unblock the peer update writes. With that peer update packing |
944 | | * with |
945 | | * the prefixes should be at its maximum. |
946 | | */ |
947 | 0 | bgp_add_eoiu_mark(bgp); |
948 | 0 | bgp->main_zebra_update_hold = 1; |
949 | 0 | bgp->main_peers_update_hold = 1; |
950 | | |
951 | | /* |
952 | | * Resume the queue processing. This should trigger the event that would |
953 | | * take care of processing any work that was queued during the read-only |
954 | | * mode. |
955 | | */ |
956 | 0 | work_queue_unplug(bgp->process_queue); |
957 | 0 | } |
958 | | |
959 | | /** |
960 | | * see bgp_fsm.h |
961 | | */ |
962 | | void bgp_start_routeadv(struct bgp *bgp) |
963 | 0 | { |
964 | 0 | struct listnode *node, *nnode; |
965 | 0 | struct peer *peer; |
966 | |
|
967 | 0 | zlog_info("%s, update hold status %d", __func__, |
968 | 0 | bgp->main_peers_update_hold); |
969 | |
|
970 | 0 | if (bgp->main_peers_update_hold) |
971 | 0 | return; |
972 | | |
973 | 0 | frr_timestamp(3, bgp->update_delay_peers_resume_time, |
974 | 0 | sizeof(bgp->update_delay_peers_resume_time)); |
975 | |
|
976 | 0 | for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { |
977 | 0 | if (!peer_established(peer)) |
978 | 0 | continue; |
979 | 0 | EVENT_OFF(peer->t_routeadv); |
980 | 0 | BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); |
981 | 0 | } |
982 | 0 | } |
983 | | |
984 | | /** |
985 | | * see bgp_fsm.h |
986 | | */ |
987 | | void bgp_adjust_routeadv(struct peer *peer) |
988 | 0 | { |
989 | 0 | time_t nowtime = monotime(NULL); |
990 | 0 | double diff; |
991 | 0 | unsigned long remain; |
992 | | |
993 | | /* Bypass checks for special case of MRAI being 0 */ |
994 | 0 | if (peer->v_routeadv == 0) { |
995 | | /* Stop existing timer, just in case it is running for a |
996 | | * different |
997 | | * duration and schedule write thread immediately. |
998 | | */ |
999 | 0 | EVENT_OFF(peer->t_routeadv); |
1000 | |
|
1001 | 0 | peer->synctime = monotime(NULL); |
1002 | | /* If suppress fib pending is enabled, route is advertised to |
1003 | | * peers when the status is received from the FIB. The delay |
1004 | | * is added to update group packet generate which will allow |
1005 | | * more routes to be sent in the update message |
1006 | | */ |
1007 | 0 | BGP_UPDATE_GROUP_TIMER_ON(&peer->t_generate_updgrp_packets, |
1008 | 0 | bgp_generate_updgrp_packets); |
1009 | 0 | return; |
1010 | 0 | } |
1011 | | |
1012 | | |
1013 | | /* |
1014 | | * CASE I: |
1015 | | * If the last update was written more than MRAI back, expire the timer |
1016 | | * instantly so that we can send the update out sooner. |
1017 | | * |
1018 | | * <------- MRAI ---------> |
1019 | | * |-----------------|-----------------------| |
1020 | | * <------------- m ------------> |
1021 | | * ^ ^ ^ |
1022 | | * | | | |
1023 | | * | | current time |
1024 | | * | timer start |
1025 | | * last write |
1026 | | * |
1027 | | * m > MRAI |
1028 | | */ |
1029 | 0 | diff = difftime(nowtime, peer->last_update); |
1030 | 0 | if (diff > (double)peer->v_routeadv) { |
1031 | 0 | EVENT_OFF(peer->t_routeadv); |
1032 | 0 | BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); |
1033 | 0 | return; |
1034 | 0 | } |
1035 | | |
1036 | | /* |
1037 | | * CASE II: |
1038 | | * - Find when to expire the MRAI timer. |
1039 | | * If MRAI timer is not active, assume we can start it now. |
1040 | | * |
1041 | | * <------- MRAI ---------> |
1042 | | * |------------|-----------------------| |
1043 | | * <-------- m ----------><----- r -----> |
1044 | | * ^ ^ ^ |
1045 | | * | | | |
1046 | | * | | current time |
1047 | | * | timer start |
1048 | | * last write |
1049 | | * |
1050 | | * (MRAI - m) < r |
1051 | | */ |
1052 | 0 | if (peer->t_routeadv) |
1053 | 0 | remain = event_timer_remain_second(peer->t_routeadv); |
1054 | 0 | else |
1055 | 0 | remain = peer->v_routeadv; |
1056 | 0 | diff = peer->v_routeadv - diff; |
1057 | 0 | if (diff <= (double)remain) { |
1058 | 0 | EVENT_OFF(peer->t_routeadv); |
1059 | 0 | BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, diff); |
1060 | 0 | } |
1061 | 0 | } |
1062 | | |
1063 | | static bool bgp_maxmed_onstartup_applicable(struct bgp *bgp) |
1064 | 0 | { |
1065 | 0 | if (!bgp->maxmed_onstartup_over) |
1066 | 0 | return true; |
1067 | 0 | return false; |
1068 | 0 | } |
1069 | | |
1070 | | bool bgp_maxmed_onstartup_configured(struct bgp *bgp) |
1071 | 0 | { |
1072 | 0 | if (bgp->v_maxmed_onstartup != BGP_MAXMED_ONSTARTUP_UNCONFIGURED) |
1073 | 0 | return true; |
1074 | 0 | return false; |
1075 | 0 | } |
1076 | | |
1077 | | bool bgp_maxmed_onstartup_active(struct bgp *bgp) |
1078 | 0 | { |
1079 | 0 | if (bgp->t_maxmed_onstartup) |
1080 | 0 | return true; |
1081 | 0 | return false; |
1082 | 0 | } |
1083 | | |
1084 | | void bgp_maxmed_update(struct bgp *bgp) |
1085 | 0 | { |
1086 | 0 | uint8_t maxmed_active; |
1087 | 0 | uint32_t maxmed_value; |
1088 | |
|
1089 | 0 | if (bgp->v_maxmed_admin) { |
1090 | 0 | maxmed_active = 1; |
1091 | 0 | maxmed_value = bgp->maxmed_admin_value; |
1092 | 0 | } else if (bgp->t_maxmed_onstartup) { |
1093 | 0 | maxmed_active = 1; |
1094 | 0 | maxmed_value = bgp->maxmed_onstartup_value; |
1095 | 0 | } else { |
1096 | 0 | maxmed_active = 0; |
1097 | 0 | maxmed_value = BGP_MAXMED_VALUE_DEFAULT; |
1098 | 0 | } |
1099 | |
|
1100 | 0 | if (bgp->maxmed_active != maxmed_active |
1101 | 0 | || bgp->maxmed_value != maxmed_value) { |
1102 | 0 | bgp->maxmed_active = maxmed_active; |
1103 | 0 | bgp->maxmed_value = maxmed_value; |
1104 | |
|
1105 | 0 | update_group_announce(bgp); |
1106 | 0 | } |
1107 | 0 | } |
1108 | | |
1109 | | int bgp_fsm_error_subcode(int status) |
1110 | 0 | { |
1111 | 0 | int fsm_err_subcode = BGP_NOTIFY_FSM_ERR_SUBCODE_UNSPECIFIC; |
1112 | |
|
1113 | 0 | switch (status) { |
1114 | 0 | case OpenSent: |
1115 | 0 | fsm_err_subcode = BGP_NOTIFY_FSM_ERR_SUBCODE_OPENSENT; |
1116 | 0 | break; |
1117 | 0 | case OpenConfirm: |
1118 | 0 | fsm_err_subcode = BGP_NOTIFY_FSM_ERR_SUBCODE_OPENCONFIRM; |
1119 | 0 | break; |
1120 | 0 | case Established: |
1121 | 0 | fsm_err_subcode = BGP_NOTIFY_FSM_ERR_SUBCODE_ESTABLISHED; |
1122 | 0 | break; |
1123 | 0 | default: |
1124 | 0 | break; |
1125 | 0 | } |
1126 | | |
1127 | 0 | return fsm_err_subcode; |
1128 | 0 | } |
1129 | | |
1130 | | /* The maxmed onstartup timer expiry callback. */ |
1131 | | static void bgp_maxmed_onstartup_timer(struct event *thread) |
1132 | 0 | { |
1133 | 0 | struct bgp *bgp; |
1134 | 0 |
|
1135 | 0 | zlog_info("Max med on startup ended - timer expired."); |
1136 | 0 |
|
1137 | 0 | bgp = EVENT_ARG(thread); |
1138 | 0 | EVENT_OFF(bgp->t_maxmed_onstartup); |
1139 | 0 | bgp->maxmed_onstartup_over = 1; |
1140 | 0 |
|
1141 | 0 | bgp_maxmed_update(bgp); |
1142 | 0 | } |
1143 | | |
1144 | | static void bgp_maxmed_onstartup_begin(struct bgp *bgp) |
1145 | 0 | { |
1146 | | /* Applicable only once in the process lifetime on the startup */ |
1147 | 0 | if (bgp->maxmed_onstartup_over) |
1148 | 0 | return; |
1149 | | |
1150 | 0 | zlog_info("Begin maxmed onstartup mode - timer %d seconds", |
1151 | 0 | bgp->v_maxmed_onstartup); |
1152 | |
|
1153 | 0 | event_add_timer(bm->master, bgp_maxmed_onstartup_timer, bgp, |
1154 | 0 | bgp->v_maxmed_onstartup, &bgp->t_maxmed_onstartup); |
1155 | |
|
1156 | 0 | if (!bgp->v_maxmed_admin) { |
1157 | 0 | bgp->maxmed_active = 1; |
1158 | 0 | bgp->maxmed_value = bgp->maxmed_onstartup_value; |
1159 | 0 | } |
1160 | | |
1161 | | /* Route announce to all peers should happen after this in |
1162 | | * bgp_establish() */ |
1163 | 0 | } |
1164 | | |
1165 | | static void bgp_maxmed_onstartup_process_status_change(struct peer *peer) |
1166 | 0 | { |
1167 | 0 | if (peer_established(peer) && !peer->bgp->established) { |
1168 | 0 | bgp_maxmed_onstartup_begin(peer->bgp); |
1169 | 0 | } |
1170 | 0 | } |
1171 | | |
1172 | | /* The update delay timer expiry callback. */ |
1173 | | static void bgp_update_delay_timer(struct event *thread) |
1174 | 0 | { |
1175 | 0 | struct bgp *bgp; |
1176 | 0 |
|
1177 | 0 | zlog_info("Update delay ended - timer expired."); |
1178 | 0 |
|
1179 | 0 | bgp = EVENT_ARG(thread); |
1180 | 0 | EVENT_OFF(bgp->t_update_delay); |
1181 | 0 | bgp_update_delay_end(bgp); |
1182 | 0 | } |
1183 | | |
1184 | | /* The establish wait timer expiry callback. */ |
1185 | | static void bgp_establish_wait_timer(struct event *thread) |
1186 | 0 | { |
1187 | 0 | struct bgp *bgp; |
1188 | 0 |
|
1189 | 0 | zlog_info("Establish wait - timer expired."); |
1190 | 0 |
|
1191 | 0 | bgp = EVENT_ARG(thread); |
1192 | 0 | EVENT_OFF(bgp->t_establish_wait); |
1193 | 0 | bgp_check_update_delay(bgp); |
1194 | 0 | } |
1195 | | |
1196 | | /* Steps to begin the update delay: |
1197 | | - initialize queues if needed |
1198 | | - stop the queue processing |
1199 | | - start the timer */ |
1200 | | static void bgp_update_delay_begin(struct bgp *bgp) |
1201 | 0 | { |
1202 | 0 | struct listnode *node, *nnode; |
1203 | 0 | struct peer *peer; |
1204 | | |
1205 | | /* Stop the processing of queued work. Enqueue shall continue */ |
1206 | 0 | work_queue_plug(bgp->process_queue); |
1207 | |
|
1208 | 0 | for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) |
1209 | 0 | peer->update_delay_over = 0; |
1210 | | |
1211 | | /* Start the update-delay timer */ |
1212 | 0 | event_add_timer(bm->master, bgp_update_delay_timer, bgp, |
1213 | 0 | bgp->v_update_delay, &bgp->t_update_delay); |
1214 | |
|
1215 | 0 | if (bgp->v_establish_wait != bgp->v_update_delay) |
1216 | 0 | event_add_timer(bm->master, bgp_establish_wait_timer, bgp, |
1217 | 0 | bgp->v_establish_wait, &bgp->t_establish_wait); |
1218 | |
|
1219 | 0 | frr_timestamp(3, bgp->update_delay_begin_time, |
1220 | 0 | sizeof(bgp->update_delay_begin_time)); |
1221 | 0 | } |
1222 | | |
1223 | | static void bgp_update_delay_process_status_change(struct peer *peer) |
1224 | 0 | { |
1225 | 0 | if (peer_established(peer)) { |
1226 | 0 | if (!peer->bgp->established++) { |
1227 | 0 | bgp_update_delay_begin(peer->bgp); |
1228 | 0 | zlog_info( |
1229 | 0 | "Begin read-only mode - update-delay timer %d seconds", |
1230 | 0 | peer->bgp->v_update_delay); |
1231 | 0 | } |
1232 | 0 | if (CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) |
1233 | 0 | bgp_update_restarted_peers(peer); |
1234 | 0 | } |
1235 | 0 | if (peer->ostatus == Established |
1236 | 0 | && bgp_update_delay_active(peer->bgp)) { |
1237 | | /* Adjust the update-delay state to account for this flap. |
1238 | | NOTE: Intentionally skipping adjusting implicit_eors or |
1239 | | explicit_eors |
1240 | | counters. Extra sanity check in bgp_check_update_delay() |
1241 | | should |
1242 | | be enough to take care of any additive discrepancy in bgp eor |
1243 | | counters */ |
1244 | 0 | peer->bgp->established--; |
1245 | 0 | peer->update_delay_over = 0; |
1246 | 0 | } |
1247 | 0 | } |
1248 | | |
1249 | | /* Called after event occurred, this function change status and reset |
1250 | | read/write and timer thread. */ |
1251 | | void bgp_fsm_change_status(struct peer *peer, enum bgp_fsm_status status) |
1252 | 0 | { |
1253 | 0 | struct bgp *bgp; |
1254 | 0 | uint32_t peer_count; |
1255 | |
|
1256 | 0 | bgp = peer->bgp; |
1257 | 0 | peer_count = bgp->established_peers; |
1258 | |
|
1259 | 0 | if (status == Established) |
1260 | 0 | bgp->established_peers++; |
1261 | 0 | else if ((peer_established(peer)) && (status != Established)) |
1262 | 0 | bgp->established_peers--; |
1263 | |
|
1264 | 0 | if (bgp_debug_neighbor_events(peer)) { |
1265 | 0 | struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id); |
1266 | |
|
1267 | 0 | zlog_debug("%s : vrf %s(%u), Status: %s established_peers %u", __func__, |
1268 | 0 | vrf ? vrf->name : "Unknown", bgp->vrf_id, |
1269 | 0 | lookup_msg(bgp_status_msg, status, NULL), |
1270 | 0 | bgp->established_peers); |
1271 | 0 | } |
1272 | | |
1273 | | /* Set to router ID to the value provided by RIB if there are no peers |
1274 | | * in the established state and peer count did not change |
1275 | | */ |
1276 | 0 | if ((peer_count != bgp->established_peers) && |
1277 | 0 | (bgp->established_peers == 0)) |
1278 | 0 | bgp_router_id_zebra_bump(bgp->vrf_id, NULL); |
1279 | | |
1280 | | /* Transition into Clearing or Deleted must /always/ clear all routes.. |
1281 | | * (and must do so before actually changing into Deleted.. |
1282 | | */ |
1283 | 0 | if (status >= Clearing) { |
1284 | 0 | bgp_clear_route_all(peer); |
1285 | | |
1286 | | /* If no route was queued for the clear-node processing, |
1287 | | * generate the |
1288 | | * completion event here. This is needed because if there are no |
1289 | | * routes |
1290 | | * to trigger the background clear-node thread, the event won't |
1291 | | * get |
1292 | | * generated and the peer would be stuck in Clearing. Note that |
1293 | | * this |
1294 | | * event is for the peer and helps the peer transition out of |
1295 | | * Clearing |
1296 | | * state; it should not be generated per (AFI,SAFI). The event |
1297 | | * is |
1298 | | * directly posted here without calling clear_node_complete() as |
1299 | | * we |
1300 | | * shouldn't do an extra unlock. This event will get processed |
1301 | | * after |
1302 | | * the state change that happens below, so peer will be in |
1303 | | * Clearing |
1304 | | * (or Deleted). |
1305 | | */ |
1306 | 0 | if (!work_queue_is_scheduled(peer->clear_node_queue) && |
1307 | 0 | status != Deleted) |
1308 | 0 | BGP_EVENT_ADD(peer, Clearing_Completed); |
1309 | 0 | } |
1310 | | |
1311 | | /* Preserve old status and change into new status. */ |
1312 | 0 | peer->ostatus = peer->status; |
1313 | 0 | peer->status = status; |
1314 | | |
1315 | | /* Reset received keepalives counter on every FSM change */ |
1316 | 0 | peer->rtt_keepalive_rcv = 0; |
1317 | | |
1318 | | /* Fire backward transition hook if that's the case */ |
1319 | 0 | if (peer->ostatus == Established && peer->status != Established) |
1320 | 0 | hook_call(peer_backward_transition, peer); |
1321 | | |
1322 | | /* Save event that caused status change. */ |
1323 | 0 | peer->last_major_event = peer->cur_event; |
1324 | | |
1325 | | /* Operations after status change */ |
1326 | 0 | hook_call(peer_status_changed, peer); |
1327 | |
|
1328 | 0 | if (status == Established) |
1329 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); |
1330 | | |
1331 | | /* If max-med processing is applicable, do the necessary. */ |
1332 | 0 | if (status == Established) { |
1333 | 0 | if (bgp_maxmed_onstartup_configured(peer->bgp) |
1334 | 0 | && bgp_maxmed_onstartup_applicable(peer->bgp)) |
1335 | 0 | bgp_maxmed_onstartup_process_status_change(peer); |
1336 | 0 | else |
1337 | 0 | peer->bgp->maxmed_onstartup_over = 1; |
1338 | 0 | } |
1339 | | |
1340 | | /* If update-delay processing is applicable, do the necessary. */ |
1341 | 0 | if (bgp_update_delay_configured(peer->bgp) |
1342 | 0 | && bgp_update_delay_applicable(peer->bgp)) |
1343 | 0 | bgp_update_delay_process_status_change(peer); |
1344 | |
|
1345 | 0 | if (bgp_debug_neighbor_events(peer)) |
1346 | 0 | zlog_debug("%s fd %d went from %s to %s", peer->host, peer->fd, |
1347 | 0 | lookup_msg(bgp_status_msg, peer->ostatus, NULL), |
1348 | 0 | lookup_msg(bgp_status_msg, peer->status, NULL)); |
1349 | 0 | } |
1350 | | |
1351 | | /* Flush the event queue and ensure the peer is shut down */ |
1352 | | static enum bgp_fsm_state_progress bgp_clearing_completed(struct peer *peer) |
1353 | 0 | { |
1354 | 0 | enum bgp_fsm_state_progress rc = bgp_stop(peer); |
1355 | |
|
1356 | 0 | if (rc >= BGP_FSM_SUCCESS) |
1357 | 0 | BGP_EVENT_FLUSH(peer); |
1358 | |
|
1359 | 0 | return rc; |
1360 | 0 | } |
1361 | | |
1362 | | /* Administrative BGP peer stop event. */ |
1363 | | /* May be called multiple times for the same peer */ |
1364 | | enum bgp_fsm_state_progress bgp_stop(struct peer *peer) |
1365 | 0 | { |
1366 | 0 | afi_t afi; |
1367 | 0 | safi_t safi; |
1368 | 0 | char orf_name[BUFSIZ]; |
1369 | 0 | enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS; |
1370 | 0 | struct bgp *bgp = peer->bgp; |
1371 | 0 | struct graceful_restart_info *gr_info = NULL; |
1372 | |
|
1373 | 0 | peer->nsf_af_count = 0; |
1374 | | |
1375 | | /* deregister peer */ |
1376 | 0 | if (peer->bfd_config |
1377 | 0 | && peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE) |
1378 | 0 | bfd_sess_uninstall(peer->bfd_config->session); |
1379 | |
|
1380 | 0 | if (peer_dynamic_neighbor_no_nsf(peer) && |
1381 | 0 | !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { |
1382 | 0 | if (bgp_debug_neighbor_events(peer)) |
1383 | 0 | zlog_debug("%s (dynamic neighbor) deleted (%s)", |
1384 | 0 | peer->host, __func__); |
1385 | 0 | peer_delete(peer); |
1386 | 0 | return BGP_FSM_FAILURE_AND_DELETE; |
1387 | 0 | } |
1388 | | |
1389 | | /* Can't do this in Clearing; events are used for state transitions */ |
1390 | 0 | if (peer->status != Clearing) { |
1391 | | /* Delete all existing events of the peer */ |
1392 | 0 | BGP_EVENT_FLUSH(peer); |
1393 | 0 | } |
1394 | | |
1395 | | /* Increment Dropped count. */ |
1396 | 0 | if (peer_established(peer)) { |
1397 | 0 | peer->dropped++; |
1398 | | |
1399 | | /* Notify BGP conditional advertisement process */ |
1400 | 0 | peer->advmap_table_change = true; |
1401 | | |
1402 | | /* bgp log-neighbor-changes of neighbor Down */ |
1403 | 0 | if (CHECK_FLAG(peer->bgp->flags, |
1404 | 0 | BGP_FLAG_LOG_NEIGHBOR_CHANGES)) { |
1405 | 0 | struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id); |
1406 | |
|
1407 | 0 | zlog_info( |
1408 | 0 | "%%ADJCHANGE: neighbor %pBP in vrf %s Down %s", |
1409 | 0 | peer, |
1410 | 0 | vrf ? ((vrf->vrf_id != VRF_DEFAULT) |
1411 | 0 | ? vrf->name |
1412 | 0 | : VRF_DEFAULT_NAME) |
1413 | 0 | : "", |
1414 | 0 | peer_down_str[(int)peer->last_reset]); |
1415 | 0 | } |
1416 | | |
1417 | | /* graceful restart */ |
1418 | 0 | if (peer->t_gr_stale) { |
1419 | 0 | EVENT_OFF(peer->t_gr_stale); |
1420 | 0 | if (bgp_debug_neighbor_events(peer)) |
1421 | 0 | zlog_debug( |
1422 | 0 | "%pBP graceful restart stalepath timer stopped", |
1423 | 0 | peer); |
1424 | 0 | } |
1425 | 0 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { |
1426 | 0 | if (bgp_debug_neighbor_events(peer)) { |
1427 | 0 | zlog_debug( |
1428 | 0 | "%pBP graceful restart timer started for %d sec", |
1429 | 0 | peer, peer->v_gr_restart); |
1430 | 0 | zlog_debug( |
1431 | 0 | "%pBP graceful restart stalepath timer started for %d sec", |
1432 | 0 | peer, peer->bgp->stalepath_time); |
1433 | 0 | } |
1434 | 0 | BGP_TIMER_ON(peer->t_gr_restart, |
1435 | 0 | bgp_graceful_restart_timer_expire, |
1436 | 0 | peer->v_gr_restart); |
1437 | 0 | BGP_TIMER_ON(peer->t_gr_stale, |
1438 | 0 | bgp_graceful_stale_timer_expire, |
1439 | 0 | peer->bgp->stalepath_time); |
1440 | 0 | } else { |
1441 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); |
1442 | |
|
1443 | 0 | FOREACH_AFI_SAFI_NSF (afi, safi) |
1444 | 0 | peer->nsf[afi][safi] = 0; |
1445 | 0 | } |
1446 | | |
1447 | | /* Stop route-refresh stalepath timer */ |
1448 | 0 | if (peer->t_refresh_stalepath) { |
1449 | 0 | EVENT_OFF(peer->t_refresh_stalepath); |
1450 | |
|
1451 | 0 | if (bgp_debug_neighbor_events(peer)) |
1452 | 0 | zlog_debug( |
1453 | 0 | "%pBP route-refresh restart stalepath timer stopped", |
1454 | 0 | peer); |
1455 | 0 | } |
1456 | | |
1457 | | /* If peer reset before receiving EOR, decrement EOR count and |
1458 | | * cancel the selection deferral timer if there are no |
1459 | | * pending EOR messages to be received |
1460 | | */ |
1461 | 0 | if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) { |
1462 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1463 | 0 | if (!peer->afc_nego[afi][safi] |
1464 | 0 | || CHECK_FLAG(peer->af_sflags[afi][safi], |
1465 | 0 | PEER_STATUS_EOR_RECEIVED)) |
1466 | 0 | continue; |
1467 | | |
1468 | 0 | gr_info = &bgp->gr_info[afi][safi]; |
1469 | 0 | if (!gr_info) |
1470 | 0 | continue; |
1471 | | |
1472 | 0 | if (gr_info->eor_required) |
1473 | 0 | gr_info->eor_required--; |
1474 | |
|
1475 | 0 | if (BGP_DEBUG(update, UPDATE_OUT)) |
1476 | 0 | zlog_debug("peer %s, EOR_required %d", |
1477 | 0 | peer->host, |
1478 | 0 | gr_info->eor_required); |
1479 | | |
1480 | | /* There is no pending EOR message */ |
1481 | 0 | if (gr_info->eor_required == 0) { |
1482 | 0 | if (gr_info->t_select_deferral) { |
1483 | 0 | void *info = EVENT_ARG( |
1484 | 0 | gr_info->t_select_deferral); |
1485 | 0 | XFREE(MTYPE_TMP, info); |
1486 | 0 | } |
1487 | 0 | EVENT_OFF(gr_info->t_select_deferral); |
1488 | 0 | gr_info->eor_received = 0; |
1489 | 0 | } |
1490 | 0 | } |
1491 | 0 | } |
1492 | | |
1493 | | /* set last reset time */ |
1494 | 0 | peer->resettime = peer->uptime = monotime(NULL); |
1495 | |
|
1496 | 0 | if (BGP_DEBUG(update_groups, UPDATE_GROUPS)) |
1497 | 0 | zlog_debug("%s remove from all update group", |
1498 | 0 | peer->host); |
1499 | 0 | update_group_remove_peer_afs(peer); |
1500 | | |
1501 | | /* Reset peer synctime */ |
1502 | 0 | peer->synctime = 0; |
1503 | 0 | } |
1504 | | |
1505 | | /* stop keepalives */ |
1506 | 0 | bgp_keepalives_off(peer); |
1507 | | |
1508 | | /* Stop read and write threads. */ |
1509 | 0 | bgp_writes_off(peer); |
1510 | 0 | bgp_reads_off(peer); |
1511 | |
|
1512 | 0 | EVENT_OFF(peer->t_connect_check_r); |
1513 | 0 | EVENT_OFF(peer->t_connect_check_w); |
1514 | | |
1515 | | /* Stop all timers. */ |
1516 | 0 | EVENT_OFF(peer->t_start); |
1517 | 0 | EVENT_OFF(peer->t_connect); |
1518 | 0 | EVENT_OFF(peer->t_holdtime); |
1519 | 0 | EVENT_OFF(peer->t_routeadv); |
1520 | 0 | EVENT_OFF(peer->t_delayopen); |
1521 | | |
1522 | | /* Clear input and output buffer. */ |
1523 | 0 | frr_with_mutex (&peer->io_mtx) { |
1524 | 0 | if (peer->ibuf) |
1525 | 0 | stream_fifo_clean(peer->ibuf); |
1526 | 0 | if (peer->obuf) |
1527 | 0 | stream_fifo_clean(peer->obuf); |
1528 | |
|
1529 | 0 | if (peer->ibuf_work) |
1530 | 0 | ringbuf_wipe(peer->ibuf_work); |
1531 | |
|
1532 | 0 | if (peer->curr) { |
1533 | 0 | stream_free(peer->curr); |
1534 | 0 | peer->curr = NULL; |
1535 | 0 | } |
1536 | 0 | } |
1537 | | |
1538 | | /* Close of file descriptor. */ |
1539 | 0 | if (peer->fd >= 0) { |
1540 | 0 | close(peer->fd); |
1541 | 0 | peer->fd = -1; |
1542 | 0 | } |
1543 | | |
1544 | | /* Reset capabilities. */ |
1545 | 0 | peer->cap = 0; |
1546 | | |
1547 | | /* Resetting neighbor role to the default value */ |
1548 | 0 | peer->remote_role = ROLE_UNDEFINED; |
1549 | |
|
1550 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
1551 | | /* Reset all negotiated variables */ |
1552 | 0 | peer->afc_nego[afi][safi] = 0; |
1553 | 0 | peer->afc_adv[afi][safi] = 0; |
1554 | 0 | peer->afc_recv[afi][safi] = 0; |
1555 | | |
1556 | | /* peer address family capability flags*/ |
1557 | 0 | peer->af_cap[afi][safi] = 0; |
1558 | | |
1559 | | /* peer address family status flags*/ |
1560 | 0 | peer->af_sflags[afi][safi] = 0; |
1561 | | |
1562 | | /* Received ORF prefix-filter */ |
1563 | 0 | peer->orf_plist[afi][safi] = NULL; |
1564 | |
|
1565 | 0 | if ((peer->status == OpenConfirm) || (peer_established(peer))) { |
1566 | | /* ORF received prefix-filter pnt */ |
1567 | 0 | snprintf(orf_name, sizeof(orf_name), "%s.%d.%d", |
1568 | 0 | peer->host, afi, safi); |
1569 | 0 | prefix_bgp_orf_remove_all(afi, orf_name); |
1570 | 0 | } |
1571 | 0 | } |
1572 | | |
1573 | | /* Reset keepalive and holdtime */ |
1574 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) { |
1575 | 0 | peer->v_keepalive = peer->keepalive; |
1576 | 0 | peer->v_holdtime = peer->holdtime; |
1577 | 0 | } else { |
1578 | 0 | peer->v_keepalive = peer->bgp->default_keepalive; |
1579 | 0 | peer->v_holdtime = peer->bgp->default_holdtime; |
1580 | 0 | } |
1581 | | |
1582 | | /* Reset DelayOpenTime */ |
1583 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) |
1584 | 0 | peer->v_delayopen = peer->delayopen; |
1585 | 0 | else |
1586 | 0 | peer->v_delayopen = peer->bgp->default_delayopen; |
1587 | |
|
1588 | 0 | peer->update_time = 0; |
1589 | |
|
1590 | 0 | if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) |
1591 | 0 | && !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) { |
1592 | 0 | peer_delete(peer); |
1593 | 0 | ret = BGP_FSM_FAILURE_AND_DELETE; |
1594 | 0 | } else { |
1595 | 0 | bgp_peer_conf_if_to_su_update(peer); |
1596 | 0 | } |
1597 | 0 | return ret; |
1598 | 0 | } |
1599 | | |
1600 | | /* BGP peer is stoped by the error. */ |
1601 | | static enum bgp_fsm_state_progress bgp_stop_with_error(struct peer *peer) |
1602 | 0 | { |
1603 | | /* Double start timer. */ |
1604 | 0 | peer->v_start *= 2; |
1605 | | |
1606 | | /* Overflow check. */ |
1607 | 0 | if (peer->v_start >= (60 * 2)) |
1608 | 0 | peer->v_start = (60 * 2); |
1609 | |
|
1610 | 0 | if (peer_dynamic_neighbor_no_nsf(peer)) { |
1611 | 0 | if (bgp_debug_neighbor_events(peer)) |
1612 | 0 | zlog_debug("%s (dynamic neighbor) deleted (%s)", |
1613 | 0 | peer->host, __func__); |
1614 | 0 | peer_delete(peer); |
1615 | 0 | return BGP_FSM_FAILURE; |
1616 | 0 | } |
1617 | | |
1618 | 0 | return bgp_stop(peer); |
1619 | 0 | } |
1620 | | |
1621 | | |
1622 | | /* something went wrong, send notify and tear down */ |
1623 | | static enum bgp_fsm_state_progress |
1624 | | bgp_stop_with_notify(struct peer *peer, uint8_t code, uint8_t sub_code) |
1625 | 0 | { |
1626 | | /* Send notify to remote peer */ |
1627 | 0 | bgp_notify_send(peer, code, sub_code); |
1628 | |
|
1629 | 0 | if (peer_dynamic_neighbor_no_nsf(peer)) { |
1630 | 0 | if (bgp_debug_neighbor_events(peer)) |
1631 | 0 | zlog_debug("%s (dynamic neighbor) deleted (%s)", |
1632 | 0 | peer->host, __func__); |
1633 | 0 | peer_delete(peer); |
1634 | 0 | return BGP_FSM_FAILURE; |
1635 | 0 | } |
1636 | | |
1637 | | /* Clear start timer value to default. */ |
1638 | 0 | peer->v_start = BGP_INIT_START_TIMER; |
1639 | |
|
1640 | 0 | return bgp_stop(peer); |
1641 | 0 | } |
1642 | | |
1643 | | /** |
1644 | | * Determines whether a TCP session has successfully established for a peer and |
1645 | | * events as appropriate. |
1646 | | * |
1647 | | * This function is called when setting up a new session. After connect() is |
1648 | | * called on the peer's socket (in bgp_start()), the fd is passed to poll() |
1649 | | * to wait for connection success or failure. When poll() returns, this |
1650 | | * function is called to evaluate the result. |
1651 | | * |
1652 | | * Due to differences in behavior of poll() on Linux and BSD - specifically, |
1653 | | * the value of .revents in the case of a closed connection - this function is |
1654 | | * scheduled both for a read and a write event. The write event is triggered |
1655 | | * when the connection is established. A read event is triggered when the |
1656 | | * connection is closed. Thus we need to cancel whichever one did not occur. |
1657 | | */ |
1658 | | static void bgp_connect_check(struct event *thread) |
1659 | 0 | { |
1660 | 0 | int status; |
1661 | 0 | socklen_t slen; |
1662 | 0 | int ret; |
1663 | 0 | struct peer *peer; |
1664 | 0 |
|
1665 | 0 | peer = EVENT_ARG(thread); |
1666 | 0 | assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); |
1667 | 0 | assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); |
1668 | 0 | assert(!peer->t_read); |
1669 | 0 | assert(!peer->t_write); |
1670 | 0 |
|
1671 | 0 | EVENT_OFF(peer->t_connect_check_r); |
1672 | 0 | EVENT_OFF(peer->t_connect_check_w); |
1673 | 0 |
|
1674 | 0 | /* Check file descriptor. */ |
1675 | 0 | slen = sizeof(status); |
1676 | 0 | ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *)&status, |
1677 | 0 | &slen); |
1678 | 0 |
|
1679 | 0 | /* If getsockopt is fail, this is fatal error. */ |
1680 | 0 | if (ret < 0) { |
1681 | 0 | zlog_err("can't get sockopt for nonblocking connect: %d(%s)", |
1682 | 0 | errno, safe_strerror(errno)); |
1683 | 0 | BGP_EVENT_ADD(peer, TCP_fatal_error); |
1684 | 0 | return; |
1685 | 0 | } |
1686 | 0 |
|
1687 | 0 | /* When status is 0 then TCP connection is established. */ |
1688 | 0 | if (status == 0) { |
1689 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER_DELAYOPEN)) |
1690 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open_w_delay); |
1691 | 0 | else |
1692 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open); |
1693 | 0 | return; |
1694 | 0 | } else { |
1695 | 0 | if (bgp_debug_neighbor_events(peer)) |
1696 | 0 | zlog_debug("%s [Event] Connect failed %d(%s)", |
1697 | 0 | peer->host, status, safe_strerror(status)); |
1698 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open_failed); |
1699 | 0 | return; |
1700 | 0 | } |
1701 | 0 | } |
1702 | | |
1703 | | /* TCP connection open. Next we send open message to remote peer. And |
1704 | | add read thread for reading open message. */ |
1705 | | static enum bgp_fsm_state_progress bgp_connect_success(struct peer *peer) |
1706 | 0 | { |
1707 | 0 | if (peer->fd < 0) { |
1708 | 0 | flog_err(EC_BGP_CONNECT, "%s peer's fd is negative value %d", |
1709 | 0 | __func__, peer->fd); |
1710 | 0 | return bgp_stop(peer); |
1711 | 0 | } |
1712 | | |
1713 | 0 | if (bgp_getsockname(peer) < 0) { |
1714 | 0 | flog_err_sys(EC_LIB_SOCKET, |
1715 | 0 | "%s: bgp_getsockname(): failed for peer %s, fd %d", |
1716 | 0 | __func__, peer->host, peer->fd); |
1717 | 0 | bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, |
1718 | 0 | bgp_fsm_error_subcode(peer->status)); |
1719 | 0 | bgp_writes_on(peer); |
1720 | 0 | return BGP_FSM_FAILURE; |
1721 | 0 | } |
1722 | | |
1723 | | /* |
1724 | | * If we are doing nht for a peer that ls v6 LL based |
1725 | | * massage the event system to make things happy |
1726 | | */ |
1727 | 0 | bgp_nht_interface_events(peer); |
1728 | |
|
1729 | 0 | bgp_reads_on(peer); |
1730 | |
|
1731 | 0 | if (bgp_debug_neighbor_events(peer)) { |
1732 | 0 | if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) |
1733 | 0 | zlog_debug("%s open active, local address %pSU", |
1734 | 0 | peer->host, peer->su_local); |
1735 | 0 | else |
1736 | 0 | zlog_debug("%s passive open", peer->host); |
1737 | 0 | } |
1738 | | |
1739 | | /* Send an open message */ |
1740 | 0 | bgp_open_send(peer); |
1741 | |
|
1742 | 0 | return BGP_FSM_SUCCESS; |
1743 | 0 | } |
1744 | | |
1745 | | /* TCP connection open with RFC 4271 optional session attribute DelayOpen flag |
1746 | | * set. |
1747 | | */ |
1748 | | static enum bgp_fsm_state_progress |
1749 | | bgp_connect_success_w_delayopen(struct peer *peer) |
1750 | 0 | { |
1751 | 0 | if (peer->fd < 0) { |
1752 | 0 | flog_err(EC_BGP_CONNECT, "%s: peer's fd is negative value %d", |
1753 | 0 | __func__, peer->fd); |
1754 | 0 | return bgp_stop(peer); |
1755 | 0 | } |
1756 | | |
1757 | 0 | if (bgp_getsockname(peer) < 0) { |
1758 | 0 | flog_err_sys(EC_LIB_SOCKET, |
1759 | 0 | "%s: bgp_getsockname(): failed for peer %s, fd %d", |
1760 | 0 | __func__, peer->host, peer->fd); |
1761 | 0 | bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, |
1762 | 0 | bgp_fsm_error_subcode(peer->status)); |
1763 | 0 | bgp_writes_on(peer); |
1764 | 0 | return BGP_FSM_FAILURE; |
1765 | 0 | } |
1766 | | |
1767 | | /* |
1768 | | * If we are doing nht for a peer that ls v6 LL based |
1769 | | * massage the event system to make things happy |
1770 | | */ |
1771 | 0 | bgp_nht_interface_events(peer); |
1772 | |
|
1773 | 0 | bgp_reads_on(peer); |
1774 | |
|
1775 | 0 | if (bgp_debug_neighbor_events(peer)) { |
1776 | 0 | if (!CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) |
1777 | 0 | zlog_debug("%s open active, local address %pSU", |
1778 | 0 | peer->host, peer->su_local); |
1779 | 0 | else |
1780 | 0 | zlog_debug("%s passive open", peer->host); |
1781 | 0 | } |
1782 | | |
1783 | | /* set the DelayOpenTime to the inital value */ |
1784 | 0 | peer->v_delayopen = peer->delayopen; |
1785 | | |
1786 | | /* Start the DelayOpenTimer if it is not already running */ |
1787 | 0 | if (!peer->t_delayopen) |
1788 | 0 | BGP_TIMER_ON(peer->t_delayopen, bgp_delayopen_timer, |
1789 | 0 | peer->v_delayopen); |
1790 | |
|
1791 | 0 | if (bgp_debug_neighbor_events(peer)) |
1792 | 0 | zlog_debug("%s [FSM] BGP OPEN message delayed for %d seconds", |
1793 | 0 | peer->host, peer->delayopen); |
1794 | |
|
1795 | 0 | return BGP_FSM_SUCCESS; |
1796 | 0 | } |
1797 | | |
1798 | | /* TCP connect fail */ |
1799 | | static enum bgp_fsm_state_progress bgp_connect_fail(struct peer *peer) |
1800 | 0 | { |
1801 | 0 | if (peer_dynamic_neighbor_no_nsf(peer)) { |
1802 | 0 | if (bgp_debug_neighbor_events(peer)) |
1803 | 0 | zlog_debug("%s (dynamic neighbor) deleted (%s)", |
1804 | 0 | peer->host, __func__); |
1805 | 0 | peer_delete(peer); |
1806 | 0 | return BGP_FSM_FAILURE_AND_DELETE; |
1807 | 0 | } |
1808 | | |
1809 | | /* |
1810 | | * If we are doing nht for a peer that ls v6 LL based |
1811 | | * massage the event system to make things happy |
1812 | | */ |
1813 | 0 | bgp_nht_interface_events(peer); |
1814 | |
|
1815 | 0 | return bgp_stop(peer); |
1816 | 0 | } |
1817 | | |
1818 | | /* This function is the first starting point of all BGP connection. It |
1819 | | * try to connect to remote peer with non-blocking IO. |
1820 | | */ |
1821 | | enum bgp_fsm_state_progress bgp_start(struct peer *peer) |
1822 | 0 | { |
1823 | 0 | int status; |
1824 | |
|
1825 | 0 | bgp_peer_conf_if_to_su_update(peer); |
1826 | |
|
1827 | 0 | if (peer->su.sa.sa_family == AF_UNSPEC) { |
1828 | 0 | if (bgp_debug_neighbor_events(peer)) |
1829 | 0 | zlog_debug( |
1830 | 0 | "%s [FSM] Unable to get neighbor's IP address, waiting...", |
1831 | 0 | peer->host); |
1832 | 0 | peer->last_reset = PEER_DOWN_NBR_ADDR; |
1833 | 0 | return BGP_FSM_FAILURE; |
1834 | 0 | } |
1835 | | |
1836 | 0 | if (BGP_PEER_START_SUPPRESSED(peer)) { |
1837 | 0 | if (bgp_debug_neighbor_events(peer)) |
1838 | 0 | flog_err(EC_BGP_FSM, |
1839 | 0 | "%s [FSM] Trying to start suppressed peer - this is never supposed to happen!", |
1840 | 0 | peer->host); |
1841 | 0 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN)) |
1842 | 0 | peer->last_reset = PEER_DOWN_RTT_SHUTDOWN; |
1843 | 0 | else if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) |
1844 | 0 | peer->last_reset = PEER_DOWN_USER_SHUTDOWN; |
1845 | 0 | else if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN)) |
1846 | 0 | peer->last_reset = PEER_DOWN_USER_SHUTDOWN; |
1847 | 0 | else if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) |
1848 | 0 | peer->last_reset = PEER_DOWN_PFX_COUNT; |
1849 | 0 | return BGP_FSM_FAILURE; |
1850 | 0 | } |
1851 | | |
1852 | | /* Scrub some information that might be left over from a previous, |
1853 | | * session |
1854 | | */ |
1855 | | /* Connection information. */ |
1856 | 0 | if (peer->su_local) { |
1857 | 0 | sockunion_free(peer->su_local); |
1858 | 0 | peer->su_local = NULL; |
1859 | 0 | } |
1860 | |
|
1861 | 0 | if (peer->su_remote) { |
1862 | 0 | sockunion_free(peer->su_remote); |
1863 | 0 | peer->su_remote = NULL; |
1864 | 0 | } |
1865 | | |
1866 | | /* Clear remote router-id. */ |
1867 | 0 | peer->remote_id.s_addr = INADDR_ANY; |
1868 | | |
1869 | | /* Clear peer capability flag. */ |
1870 | 0 | peer->cap = 0; |
1871 | | |
1872 | | /* If the peer is passive mode, force to move to Active mode. */ |
1873 | 0 | if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) { |
1874 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open_failed); |
1875 | 0 | return BGP_FSM_SUCCESS; |
1876 | 0 | } |
1877 | | |
1878 | 0 | if (peer->bgp->vrf_id == VRF_UNKNOWN) { |
1879 | 0 | if (bgp_debug_neighbor_events(peer)) |
1880 | 0 | flog_err( |
1881 | 0 | EC_BGP_FSM, |
1882 | 0 | "%s [FSM] In a VRF that is not initialised yet", |
1883 | 0 | peer->host); |
1884 | 0 | peer->last_reset = PEER_DOWN_VRF_UNINIT; |
1885 | 0 | return BGP_FSM_FAILURE; |
1886 | 0 | } |
1887 | | |
1888 | | /* Register peer for NHT. If next hop is already resolved, proceed |
1889 | | * with connection setup, else wait. |
1890 | | */ |
1891 | 0 | if (!bgp_peer_reg_with_nht(peer)) { |
1892 | 0 | if (bgp_zebra_num_connects()) { |
1893 | 0 | if (bgp_debug_neighbor_events(peer)) |
1894 | 0 | zlog_debug( |
1895 | 0 | "%s [FSM] Waiting for NHT, no path to neighbor present", |
1896 | 0 | peer->host); |
1897 | 0 | peer->last_reset = PEER_DOWN_WAITING_NHT; |
1898 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open_failed); |
1899 | 0 | return BGP_FSM_SUCCESS; |
1900 | 0 | } |
1901 | 0 | } |
1902 | | |
1903 | 0 | assert(!peer->t_write); |
1904 | 0 | assert(!peer->t_read); |
1905 | 0 | assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON)); |
1906 | 0 | assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON)); |
1907 | 0 | status = bgp_connect(peer); |
1908 | |
|
1909 | 0 | switch (status) { |
1910 | 0 | case connect_error: |
1911 | 0 | if (bgp_debug_neighbor_events(peer)) |
1912 | 0 | zlog_debug("%s [FSM] Connect error", peer->host); |
1913 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open_failed); |
1914 | 0 | break; |
1915 | 0 | case connect_success: |
1916 | 0 | if (bgp_debug_neighbor_events(peer)) |
1917 | 0 | zlog_debug( |
1918 | 0 | "%s [FSM] Connect immediately success, fd %d", |
1919 | 0 | peer->host, peer->fd); |
1920 | |
|
1921 | 0 | BGP_EVENT_ADD(peer, TCP_connection_open); |
1922 | 0 | break; |
1923 | 0 | case connect_in_progress: |
1924 | | /* To check nonblocking connect, we wait until socket is |
1925 | | readable or writable. */ |
1926 | 0 | if (bgp_debug_neighbor_events(peer)) |
1927 | 0 | zlog_debug( |
1928 | 0 | "%s [FSM] Non blocking connect waiting result, fd %d", |
1929 | 0 | peer->host, peer->fd); |
1930 | 0 | if (peer->fd < 0) { |
1931 | 0 | flog_err(EC_BGP_FSM, |
1932 | 0 | "%s peer's fd is negative value %d", __func__, |
1933 | 0 | peer->fd); |
1934 | 0 | return BGP_FSM_FAILURE; |
1935 | 0 | } |
1936 | | /* |
1937 | | * - when the socket becomes ready, poll() will signify POLLOUT |
1938 | | * - if it fails to connect, poll() will signify POLLHUP |
1939 | | * - POLLHUP is handled as a 'read' event by thread.c |
1940 | | * |
1941 | | * therefore, we schedule both a read and a write event with |
1942 | | * bgp_connect_check() as the handler for each and cancel the |
1943 | | * unused event in that function. |
1944 | | */ |
1945 | 0 | event_add_read(bm->master, bgp_connect_check, peer, peer->fd, |
1946 | 0 | &peer->t_connect_check_r); |
1947 | 0 | event_add_write(bm->master, bgp_connect_check, peer, peer->fd, |
1948 | 0 | &peer->t_connect_check_w); |
1949 | 0 | break; |
1950 | 0 | } |
1951 | 0 | return BGP_FSM_SUCCESS; |
1952 | 0 | } |
1953 | | |
1954 | | /* Connect retry timer is expired when the peer status is Connect. */ |
1955 | | static enum bgp_fsm_state_progress bgp_reconnect(struct peer *peer) |
1956 | 0 | { |
1957 | 0 | enum bgp_fsm_state_progress ret; |
1958 | |
|
1959 | 0 | ret = bgp_stop(peer); |
1960 | 0 | if (ret < BGP_FSM_SUCCESS) |
1961 | 0 | return ret; |
1962 | | |
1963 | | /* Send graceful restart capabilty */ |
1964 | 0 | BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(peer->bgp, |
1965 | 0 | peer->bgp->peer); |
1966 | |
|
1967 | 0 | return bgp_start(peer); |
1968 | 0 | } |
1969 | | |
1970 | | static enum bgp_fsm_state_progress bgp_fsm_open(struct peer *peer) |
1971 | 0 | { |
1972 | | /* If DelayOpen is active, we may still need to send an open message */ |
1973 | 0 | if ((peer->status == Connect) || (peer->status == Active)) |
1974 | 0 | bgp_open_send(peer); |
1975 | | |
1976 | | /* Send keepalive and make keepalive timer */ |
1977 | 0 | bgp_keepalive_send(peer); |
1978 | |
|
1979 | 0 | return BGP_FSM_SUCCESS; |
1980 | 0 | } |
1981 | | |
1982 | | /* FSM error, unexpected event. This is error of BGP connection. So cut the |
1983 | | peer and change to Idle status. */ |
1984 | | static enum bgp_fsm_state_progress bgp_fsm_event_error(struct peer *peer) |
1985 | 0 | { |
1986 | 0 | flog_err(EC_BGP_FSM, "%s [FSM] unexpected packet received in state %s", |
1987 | 0 | peer->host, lookup_msg(bgp_status_msg, peer->status, NULL)); |
1988 | |
|
1989 | 0 | return bgp_stop_with_notify(peer, BGP_NOTIFY_FSM_ERR, |
1990 | 0 | bgp_fsm_error_subcode(peer->status)); |
1991 | 0 | } |
1992 | | |
1993 | | /* Hold timer expire. This is error of BGP connection. So cut the |
1994 | | peer and change to Idle status. */ |
1995 | | static enum bgp_fsm_state_progress bgp_fsm_holdtime_expire(struct peer *peer) |
1996 | 0 | { |
1997 | 0 | if (bgp_debug_neighbor_events(peer)) |
1998 | 0 | zlog_debug("%s [FSM] Hold timer expire", peer->host); |
1999 | | |
2000 | | /* RFC8538 updates RFC 4724 by defining an extension that permits |
2001 | | * the Graceful Restart procedures to be performed when the BGP |
2002 | | * speaker receives a BGP NOTIFICATION message or the Hold Time expires. |
2003 | | */ |
2004 | 0 | if (peer_established(peer) && |
2005 | 0 | bgp_has_graceful_restart_notification(peer)) |
2006 | 0 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) |
2007 | 0 | SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); |
2008 | |
|
2009 | 0 | return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0); |
2010 | 0 | } |
2011 | | |
2012 | | /* RFC 4271 DelayOpenTimer_Expires event */ |
2013 | | static enum bgp_fsm_state_progress |
2014 | | bgp_fsm_delayopen_timer_expire(struct peer *peer) |
2015 | 0 | { |
2016 | | /* Stop the DelayOpenTimer */ |
2017 | 0 | EVENT_OFF(peer->t_delayopen); |
2018 | | |
2019 | | /* Send open message to peer */ |
2020 | 0 | bgp_open_send(peer); |
2021 | | |
2022 | | /* Set the HoldTimer to a large value (4 minutes) */ |
2023 | 0 | peer->v_holdtime = 245; |
2024 | |
|
2025 | 0 | return BGP_FSM_SUCCESS; |
2026 | 0 | } |
2027 | | |
2028 | | /* Start the selection deferral timer thread for the specified AFI, SAFI */ |
2029 | | static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi, |
2030 | | struct graceful_restart_info *gr_info) |
2031 | 0 | { |
2032 | 0 | struct afi_safi_info *thread_info; |
2033 | | |
2034 | | /* If the deferral timer is active, then increment eor count */ |
2035 | 0 | if (gr_info->t_select_deferral) { |
2036 | 0 | gr_info->eor_required++; |
2037 | 0 | return 0; |
2038 | 0 | } |
2039 | | |
2040 | | /* Start the deferral timer when the first peer enabled for the graceful |
2041 | | * restart is established |
2042 | | */ |
2043 | 0 | if (gr_info->eor_required == 0) { |
2044 | 0 | thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info)); |
2045 | |
|
2046 | 0 | thread_info->afi = afi; |
2047 | 0 | thread_info->safi = safi; |
2048 | 0 | thread_info->bgp = bgp; |
2049 | |
|
2050 | 0 | event_add_timer(bm->master, bgp_graceful_deferral_timer_expire, |
2051 | 0 | thread_info, bgp->select_defer_time, |
2052 | 0 | &gr_info->t_select_deferral); |
2053 | 0 | } |
2054 | 0 | gr_info->eor_required++; |
2055 | | /* Send message to RIB indicating route update pending */ |
2056 | 0 | if (gr_info->af_enabled[afi][safi] == false) { |
2057 | 0 | gr_info->af_enabled[afi][safi] = true; |
2058 | | /* Send message to RIB */ |
2059 | 0 | bgp_zebra_update(bgp, afi, safi, |
2060 | 0 | ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); |
2061 | 0 | } |
2062 | 0 | if (BGP_DEBUG(update, UPDATE_OUT)) |
2063 | 0 | zlog_debug("Started the deferral timer for %s eor_required %d", |
2064 | 0 | get_afi_safi_str(afi, safi, false), |
2065 | 0 | gr_info->eor_required); |
2066 | 0 | return 0; |
2067 | 0 | } |
2068 | | |
2069 | | /* Update the graceful restart information for the specified AFI, SAFI */ |
2070 | | static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) |
2071 | 0 | { |
2072 | 0 | struct graceful_restart_info *gr_info; |
2073 | 0 | struct bgp *bgp = peer->bgp; |
2074 | 0 | int ret = 0; |
2075 | |
|
2076 | 0 | if ((afi < AFI_IP) || (afi >= AFI_MAX)) { |
2077 | 0 | if (BGP_DEBUG(update, UPDATE_OUT)) |
2078 | 0 | zlog_debug("%s : invalid afi %d", __func__, afi); |
2079 | 0 | return -1; |
2080 | 0 | } |
2081 | | |
2082 | 0 | if ((safi < SAFI_UNICAST) || (safi > SAFI_MPLS_VPN)) { |
2083 | 0 | if (BGP_DEBUG(update, UPDATE_OUT)) |
2084 | 0 | zlog_debug("%s : invalid safi %d", __func__, safi); |
2085 | 0 | return -1; |
2086 | 0 | } |
2087 | | |
2088 | | /* Restarting router */ |
2089 | 0 | if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) |
2090 | 0 | && BGP_PEER_RESTARTING_MODE(peer)) { |
2091 | | /* Check if the forwarding state is preserved */ |
2092 | 0 | if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { |
2093 | 0 | gr_info = &(bgp->gr_info[afi][safi]); |
2094 | 0 | ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); |
2095 | 0 | } |
2096 | 0 | } |
2097 | 0 | return ret; |
2098 | 0 | } |
2099 | | |
2100 | | /** |
2101 | | * Transition to Established state. |
2102 | | * |
2103 | | * Convert peer from stub to full fledged peer, set some timers, and generate |
2104 | | * initial updates. |
2105 | | */ |
2106 | | static enum bgp_fsm_state_progress bgp_establish(struct peer *peer) |
2107 | 0 | { |
2108 | 0 | afi_t afi; |
2109 | 0 | safi_t safi; |
2110 | 0 | int nsf_af_count = 0; |
2111 | 0 | enum bgp_fsm_state_progress ret = BGP_FSM_SUCCESS; |
2112 | 0 | struct peer *other; |
2113 | 0 | int status; |
2114 | 0 | struct peer *orig = peer; |
2115 | |
|
2116 | 0 | other = peer->doppelganger; |
2117 | 0 | hash_release(peer->bgp->peerhash, peer); |
2118 | 0 | if (other) |
2119 | 0 | hash_release(peer->bgp->peerhash, other); |
2120 | |
|
2121 | 0 | peer = peer_xfer_conn(peer); |
2122 | 0 | if (!peer) { |
2123 | 0 | flog_err(EC_BGP_CONNECT, "%%Neighbor failed in xfer_conn"); |
2124 | | |
2125 | | /* |
2126 | | * A failure of peer_xfer_conn but not putting the peers |
2127 | | * back in the hash ends up with a situation where incoming |
2128 | | * connections are rejected, as that the peer is not found |
2129 | | * when a lookup is done |
2130 | | */ |
2131 | 0 | (void)hash_get(orig->bgp->peerhash, orig, hash_alloc_intern); |
2132 | 0 | if (other) |
2133 | 0 | (void)hash_get(other->bgp->peerhash, other, |
2134 | 0 | hash_alloc_intern); |
2135 | 0 | return BGP_FSM_FAILURE; |
2136 | 0 | } |
2137 | | |
2138 | 0 | if (other == peer) |
2139 | 0 | ret = BGP_FSM_SUCCESS_STATE_TRANSFER; |
2140 | | |
2141 | | /* Reset capability open status flag. */ |
2142 | 0 | if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN)) |
2143 | 0 | SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); |
2144 | | |
2145 | | /* Clear start timer value to default. */ |
2146 | 0 | peer->v_start = BGP_INIT_START_TIMER; |
2147 | | |
2148 | | /* Increment established count. */ |
2149 | 0 | peer->established++; |
2150 | 0 | bgp_fsm_change_status(peer, Established); |
2151 | | |
2152 | | /* bgp log-neighbor-changes of neighbor Up */ |
2153 | 0 | if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) { |
2154 | 0 | struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id); |
2155 | 0 | zlog_info("%%ADJCHANGE: neighbor %pBP in vrf %s Up", peer, |
2156 | 0 | vrf ? ((vrf->vrf_id != VRF_DEFAULT) |
2157 | 0 | ? vrf->name |
2158 | 0 | : VRF_DEFAULT_NAME) |
2159 | 0 | : ""); |
2160 | 0 | } |
2161 | | /* assign update-group/subgroup */ |
2162 | 0 | update_group_adjust_peer_afs(peer); |
2163 | | |
2164 | | /* graceful restart */ |
2165 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); |
2166 | 0 | if (bgp_debug_neighbor_events(peer)) { |
2167 | 0 | if (BGP_PEER_RESTARTING_MODE(peer)) |
2168 | 0 | zlog_debug("%pBP BGP_RESTARTING_MODE", peer); |
2169 | 0 | else if (BGP_PEER_HELPER_MODE(peer)) |
2170 | 0 | zlog_debug("%pBP BGP_HELPER_MODE", peer); |
2171 | 0 | } |
2172 | |
|
2173 | 0 | FOREACH_AFI_SAFI_NSF (afi, safi) { |
2174 | 0 | if (peer->afc_nego[afi][safi] && |
2175 | 0 | CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && |
2176 | 0 | CHECK_FLAG(peer->af_cap[afi][safi], |
2177 | 0 | PEER_CAP_RESTART_AF_RCV)) { |
2178 | 0 | if (peer->nsf[afi][safi] && |
2179 | 0 | !CHECK_FLAG(peer->af_cap[afi][safi], |
2180 | 0 | PEER_CAP_RESTART_AF_PRESERVE_RCV)) |
2181 | 0 | bgp_clear_stale_route(peer, afi, safi); |
2182 | |
|
2183 | 0 | peer->nsf[afi][safi] = 1; |
2184 | 0 | nsf_af_count++; |
2185 | 0 | } else { |
2186 | 0 | if (peer->nsf[afi][safi]) |
2187 | 0 | bgp_clear_stale_route(peer, afi, safi); |
2188 | 0 | peer->nsf[afi][safi] = 0; |
2189 | 0 | } |
2190 | | /* Update the graceful restart information */ |
2191 | 0 | if (peer->afc_nego[afi][safi]) { |
2192 | 0 | if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) { |
2193 | 0 | status = bgp_update_gr_info(peer, afi, safi); |
2194 | 0 | if (status < 0) |
2195 | 0 | zlog_err( |
2196 | 0 | "Error in updating graceful restart for %s", |
2197 | 0 | get_afi_safi_str(afi, safi, |
2198 | 0 | false)); |
2199 | 0 | } else { |
2200 | 0 | if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && |
2201 | 0 | BGP_PEER_RESTARTING_MODE(peer) && |
2202 | 0 | CHECK_FLAG(peer->bgp->flags, |
2203 | 0 | BGP_FLAG_GR_PRESERVE_FWD)) |
2204 | 0 | peer->bgp->gr_info[afi][safi] |
2205 | 0 | .eor_required++; |
2206 | 0 | } |
2207 | 0 | } |
2208 | 0 | } |
2209 | |
|
2210 | 0 | if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) { |
2211 | 0 | if ((bgp_peer_gr_mode_get(peer) == PEER_GR) |
2212 | 0 | || ((bgp_peer_gr_mode_get(peer) == PEER_GLOBAL_INHERIT) |
2213 | 0 | && (bgp_global_gr_mode_get(peer->bgp) == GLOBAL_GR))) { |
2214 | 0 | FOREACH_AFI_SAFI (afi, safi) |
2215 | | /* Send route processing complete |
2216 | | message to RIB */ |
2217 | 0 | bgp_zebra_update( |
2218 | 0 | peer->bgp, afi, safi, |
2219 | 0 | ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); |
2220 | 0 | } |
2221 | 0 | } else { |
2222 | | /* Peer sends R-bit. In this case, we need to send |
2223 | | * ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */ |
2224 | 0 | if (CHECK_FLAG(peer->cap, |
2225 | 0 | PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) { |
2226 | 0 | FOREACH_AFI_SAFI (afi, safi) |
2227 | | /* Send route processing complete |
2228 | | message to RIB */ |
2229 | 0 | bgp_zebra_update( |
2230 | 0 | peer->bgp, afi, safi, |
2231 | 0 | ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); |
2232 | 0 | } |
2233 | 0 | } |
2234 | |
|
2235 | 0 | peer->nsf_af_count = nsf_af_count; |
2236 | |
|
2237 | 0 | if (nsf_af_count) |
2238 | 0 | SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); |
2239 | 0 | else { |
2240 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); |
2241 | 0 | if (peer->t_gr_stale) { |
2242 | 0 | EVENT_OFF(peer->t_gr_stale); |
2243 | 0 | if (bgp_debug_neighbor_events(peer)) |
2244 | 0 | zlog_debug( |
2245 | 0 | "%pBP graceful restart stalepath timer stopped", |
2246 | 0 | peer); |
2247 | 0 | } |
2248 | 0 | } |
2249 | |
|
2250 | 0 | if (peer->t_gr_restart) { |
2251 | 0 | EVENT_OFF(peer->t_gr_restart); |
2252 | 0 | if (bgp_debug_neighbor_events(peer)) |
2253 | 0 | zlog_debug("%pBP graceful restart timer stopped", peer); |
2254 | 0 | } |
2255 | | |
2256 | | /* Reset uptime, turn on keepalives, send current table. */ |
2257 | 0 | if (!peer->v_holdtime) |
2258 | 0 | bgp_keepalives_on(peer); |
2259 | |
|
2260 | 0 | peer->uptime = monotime(NULL); |
2261 | | |
2262 | | /* Send route-refresh when ORF is enabled. |
2263 | | * Stop Long-lived Graceful Restart timers. |
2264 | | */ |
2265 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
2266 | 0 | if (peer->t_llgr_stale[afi][safi]) { |
2267 | 0 | EVENT_OFF(peer->t_llgr_stale[afi][safi]); |
2268 | 0 | if (bgp_debug_neighbor_events(peer)) |
2269 | 0 | zlog_debug( |
2270 | 0 | "%pBP Long-lived stale timer stopped for afi/safi: %d/%d", |
2271 | 0 | peer, afi, safi); |
2272 | 0 | } |
2273 | |
|
2274 | 0 | if (CHECK_FLAG(peer->af_cap[afi][safi], |
2275 | 0 | PEER_CAP_ORF_PREFIX_SM_ADV)) { |
2276 | 0 | if (CHECK_FLAG(peer->af_cap[afi][safi], |
2277 | 0 | PEER_CAP_ORF_PREFIX_RM_RCV)) |
2278 | 0 | bgp_route_refresh_send( |
2279 | 0 | peer, afi, safi, ORF_TYPE_PREFIX, |
2280 | 0 | REFRESH_IMMEDIATE, 0, |
2281 | 0 | BGP_ROUTE_REFRESH_NORMAL); |
2282 | 0 | else if (CHECK_FLAG(peer->af_cap[afi][safi], |
2283 | 0 | PEER_CAP_ORF_PREFIX_RM_OLD_RCV)) |
2284 | 0 | bgp_route_refresh_send( |
2285 | 0 | peer, afi, safi, ORF_TYPE_PREFIX_OLD, |
2286 | 0 | REFRESH_IMMEDIATE, 0, |
2287 | 0 | BGP_ROUTE_REFRESH_NORMAL); |
2288 | 0 | } |
2289 | 0 | } |
2290 | | |
2291 | | /* First update is deferred until ORF or ROUTE-REFRESH is received */ |
2292 | 0 | FOREACH_AFI_SAFI (afi, safi) { |
2293 | 0 | if (CHECK_FLAG(peer->af_cap[afi][safi], |
2294 | 0 | PEER_CAP_ORF_PREFIX_RM_ADV)) |
2295 | 0 | if (CHECK_FLAG(peer->af_cap[afi][safi], |
2296 | 0 | PEER_CAP_ORF_PREFIX_SM_RCV) |
2297 | 0 | || CHECK_FLAG(peer->af_cap[afi][safi], |
2298 | 0 | PEER_CAP_ORF_PREFIX_SM_OLD_RCV)) |
2299 | 0 | SET_FLAG(peer->af_sflags[afi][safi], |
2300 | 0 | PEER_STATUS_ORF_WAIT_REFRESH); |
2301 | 0 | } |
2302 | |
|
2303 | 0 | bgp_announce_peer(peer); |
2304 | | |
2305 | | /* Start the route advertisement timer to send updates to the peer - if |
2306 | | * BGP |
2307 | | * is not in read-only mode. If it is, the timer will be started at the |
2308 | | * end |
2309 | | * of read-only mode. |
2310 | | */ |
2311 | 0 | if (!bgp_update_delay_active(peer->bgp)) { |
2312 | 0 | EVENT_OFF(peer->t_routeadv); |
2313 | 0 | BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0); |
2314 | 0 | } |
2315 | |
|
2316 | 0 | if (peer->doppelganger && (peer->doppelganger->status != Deleted)) { |
2317 | 0 | if (bgp_debug_neighbor_events(peer)) |
2318 | 0 | zlog_debug( |
2319 | 0 | "[Event] Deleting stub connection for peer %s", |
2320 | 0 | peer->host); |
2321 | |
|
2322 | 0 | if (peer->doppelganger->status > Active) |
2323 | 0 | bgp_notify_send(peer->doppelganger, BGP_NOTIFY_CEASE, |
2324 | 0 | BGP_NOTIFY_CEASE_COLLISION_RESOLUTION); |
2325 | 0 | else |
2326 | 0 | peer_delete(peer->doppelganger); |
2327 | 0 | } |
2328 | | |
2329 | | /* |
2330 | | * If we are replacing the old peer for a doppelganger |
2331 | | * then switch it around in the bgp->peerhash |
2332 | | * the doppelgangers su and this peer's su are the same |
2333 | | * so the hash_release is the same for either. |
2334 | | */ |
2335 | 0 | (void)hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); |
2336 | | |
2337 | | /* Start BFD peer if not already running. */ |
2338 | 0 | if (peer->bfd_config) |
2339 | 0 | bgp_peer_bfd_update_source(peer); |
2340 | |
|
2341 | 0 | return ret; |
2342 | 0 | } |
2343 | | |
2344 | | /* Keepalive packet is received. */ |
2345 | | static enum bgp_fsm_state_progress bgp_fsm_keepalive(struct peer *peer) |
2346 | 0 | { |
2347 | 0 | EVENT_OFF(peer->t_holdtime); |
2348 | 0 | return BGP_FSM_SUCCESS; |
2349 | 0 | } |
2350 | | |
2351 | | /* Update packet is received. */ |
2352 | | static enum bgp_fsm_state_progress bgp_fsm_update(struct peer *peer) |
2353 | 0 | { |
2354 | 0 | EVENT_OFF(peer->t_holdtime); |
2355 | 0 | return BGP_FSM_SUCCESS; |
2356 | 0 | } |
2357 | | |
2358 | | /* This is empty event. */ |
2359 | | static enum bgp_fsm_state_progress bgp_ignore(struct peer *peer) |
2360 | 0 | { |
2361 | 0 | flog_err( |
2362 | 0 | EC_BGP_FSM, |
2363 | 0 | "%s [FSM] Ignoring event %s in state %s, prior events %s, %s, fd %d", |
2364 | 0 | peer->host, bgp_event_str[peer->cur_event], |
2365 | 0 | lookup_msg(bgp_status_msg, peer->status, NULL), |
2366 | 0 | bgp_event_str[peer->last_event], |
2367 | 0 | bgp_event_str[peer->last_major_event], peer->fd); |
2368 | 0 | return BGP_FSM_SUCCESS; |
2369 | 0 | } |
2370 | | |
2371 | | /* This is to handle unexpected events.. */ |
2372 | | static enum bgp_fsm_state_progress bgp_fsm_exception(struct peer *peer) |
2373 | 0 | { |
2374 | 0 | flog_err( |
2375 | 0 | EC_BGP_FSM, |
2376 | 0 | "%s [FSM] Unexpected event %s in state %s, prior events %s, %s, fd %d", |
2377 | 0 | peer->host, bgp_event_str[peer->cur_event], |
2378 | 0 | lookup_msg(bgp_status_msg, peer->status, NULL), |
2379 | 0 | bgp_event_str[peer->last_event], |
2380 | 0 | bgp_event_str[peer->last_major_event], peer->fd); |
2381 | 0 | return bgp_stop(peer); |
2382 | 0 | } |
2383 | | |
2384 | | void bgp_fsm_nht_update(struct peer *peer, bool has_valid_nexthops) |
2385 | 0 | { |
2386 | 0 | if (!peer) |
2387 | 0 | return; |
2388 | | |
2389 | 0 | switch (peer->status) { |
2390 | 0 | case Idle: |
2391 | 0 | if (has_valid_nexthops) |
2392 | 0 | BGP_EVENT_ADD(peer, BGP_Start); |
2393 | 0 | break; |
2394 | 0 | case Connect: |
2395 | 0 | if (!has_valid_nexthops) { |
2396 | 0 | EVENT_OFF(peer->t_connect); |
2397 | 0 | BGP_EVENT_ADD(peer, TCP_fatal_error); |
2398 | 0 | } |
2399 | 0 | break; |
2400 | 0 | case Active: |
2401 | 0 | if (has_valid_nexthops) { |
2402 | 0 | EVENT_OFF(peer->t_connect); |
2403 | 0 | BGP_EVENT_ADD(peer, ConnectRetry_timer_expired); |
2404 | 0 | } |
2405 | 0 | break; |
2406 | 0 | case OpenSent: |
2407 | 0 | case OpenConfirm: |
2408 | 0 | case Established: |
2409 | 0 | if (!has_valid_nexthops |
2410 | 0 | && (peer->gtsm_hops == BGP_GTSM_HOPS_CONNECTED |
2411 | 0 | || peer->bgp->fast_convergence)) |
2412 | 0 | BGP_EVENT_ADD(peer, TCP_fatal_error); |
2413 | 0 | case Clearing: |
2414 | 0 | case Deleted: |
2415 | 0 | case BGP_STATUS_MAX: |
2416 | 0 | break; |
2417 | 0 | } |
2418 | 0 | } |
2419 | | |
2420 | | /* Finite State Machine structure */ |
2421 | | static const struct { |
2422 | | enum bgp_fsm_state_progress (*func)(struct peer *); |
2423 | | enum bgp_fsm_status next_state; |
2424 | | } FSM[BGP_STATUS_MAX - 1][BGP_EVENTS_MAX - 1] = { |
2425 | | { |
2426 | | /* Idle state: In Idle state, all events other than BGP_Start is |
2427 | | ignored. With BGP_Start event, finite state machine calls |
2428 | | bgp_start(). */ |
2429 | | {bgp_start, Connect}, /* BGP_Start */ |
2430 | | {bgp_stop, Idle}, /* BGP_Stop */ |
2431 | | {bgp_stop, Idle}, /* TCP_connection_open */ |
2432 | | {bgp_stop, Idle}, /* TCP_connection_open_w_delay */ |
2433 | | {bgp_stop, Idle}, /* TCP_connection_closed */ |
2434 | | {bgp_ignore, Idle}, /* TCP_connection_open_failed */ |
2435 | | {bgp_stop, Idle}, /* TCP_fatal_error */ |
2436 | | {bgp_ignore, Idle}, /* ConnectRetry_timer_expired */ |
2437 | | {bgp_ignore, Idle}, /* Hold_Timer_expired */ |
2438 | | {bgp_ignore, Idle}, /* KeepAlive_timer_expired */ |
2439 | | {bgp_ignore, Idle}, /* DelayOpen_timer_expired */ |
2440 | | {bgp_ignore, Idle}, /* Receive_OPEN_message */ |
2441 | | {bgp_ignore, Idle}, /* Receive_KEEPALIVE_message */ |
2442 | | {bgp_ignore, Idle}, /* Receive_UPDATE_message */ |
2443 | | {bgp_ignore, Idle}, /* Receive_NOTIFICATION_message */ |
2444 | | {bgp_ignore, Idle}, /* Clearing_Completed */ |
2445 | | }, |
2446 | | { |
2447 | | /* Connect */ |
2448 | | {bgp_ignore, Connect}, /* BGP_Start */ |
2449 | | {bgp_stop, Idle}, /* BGP_Stop */ |
2450 | | {bgp_connect_success, OpenSent}, /* TCP_connection_open */ |
2451 | | {bgp_connect_success_w_delayopen, |
2452 | | Connect}, /* TCP_connection_open_w_delay */ |
2453 | | {bgp_stop, Idle}, /* TCP_connection_closed */ |
2454 | | {bgp_connect_fail, Active}, /* TCP_connection_open_failed */ |
2455 | | {bgp_connect_fail, Idle}, /* TCP_fatal_error */ |
2456 | | {bgp_reconnect, Connect}, /* ConnectRetry_timer_expired */ |
2457 | | {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */ |
2458 | | {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */ |
2459 | | {bgp_fsm_delayopen_timer_expire, |
2460 | | OpenSent}, /* DelayOpen_timer_expired */ |
2461 | | {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ |
2462 | | {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */ |
2463 | | {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */ |
2464 | | {bgp_stop, Idle}, /* Receive_NOTIFICATION_message */ |
2465 | | {bgp_fsm_exception, Idle}, /* Clearing_Completed */ |
2466 | | }, |
2467 | | { |
2468 | | /* Active, */ |
2469 | | {bgp_ignore, Active}, /* BGP_Start */ |
2470 | | {bgp_stop, Idle}, /* BGP_Stop */ |
2471 | | {bgp_connect_success, OpenSent}, /* TCP_connection_open */ |
2472 | | {bgp_connect_success_w_delayopen, |
2473 | | Active}, /* TCP_connection_open_w_delay */ |
2474 | | {bgp_stop, Idle}, /* TCP_connection_closed */ |
2475 | | {bgp_ignore, Active}, /* TCP_connection_open_failed */ |
2476 | | {bgp_fsm_exception, Idle}, /* TCP_fatal_error */ |
2477 | | {bgp_start, Connect}, /* ConnectRetry_timer_expired */ |
2478 | | {bgp_fsm_exception, Idle}, /* Hold_Timer_expired */ |
2479 | | {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */ |
2480 | | {bgp_fsm_delayopen_timer_expire, |
2481 | | OpenSent}, /* DelayOpen_timer_expired */ |
2482 | | {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ |
2483 | | {bgp_fsm_exception, Idle}, /* Receive_KEEPALIVE_message */ |
2484 | | {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */ |
2485 | | {bgp_fsm_exception, Idle}, /* Receive_NOTIFICATION_message */ |
2486 | | {bgp_fsm_exception, Idle}, /* Clearing_Completed */ |
2487 | | }, |
2488 | | { |
2489 | | /* OpenSent, */ |
2490 | | {bgp_ignore, OpenSent}, /* BGP_Start */ |
2491 | | {bgp_stop, Idle}, /* BGP_Stop */ |
2492 | | {bgp_stop, Active}, /* TCP_connection_open */ |
2493 | | {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */ |
2494 | | {bgp_stop, Active}, /* TCP_connection_closed */ |
2495 | | {bgp_stop, Active}, /* TCP_connection_open_failed */ |
2496 | | {bgp_stop, Active}, /* TCP_fatal_error */ |
2497 | | {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */ |
2498 | | {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ |
2499 | | {bgp_fsm_exception, Idle}, /* KeepAlive_timer_expired */ |
2500 | | {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */ |
2501 | | {bgp_fsm_open, OpenConfirm}, /* Receive_OPEN_message */ |
2502 | | {bgp_fsm_event_error, Idle}, /* Receive_KEEPALIVE_message */ |
2503 | | {bgp_fsm_event_error, Idle}, /* Receive_UPDATE_message */ |
2504 | | {bgp_fsm_event_error, Idle}, /* Receive_NOTIFICATION_message */ |
2505 | | {bgp_fsm_exception, Idle}, /* Clearing_Completed */ |
2506 | | }, |
2507 | | { |
2508 | | /* OpenConfirm, */ |
2509 | | {bgp_ignore, OpenConfirm}, /* BGP_Start */ |
2510 | | {bgp_stop, Idle}, /* BGP_Stop */ |
2511 | | {bgp_stop, Idle}, /* TCP_connection_open */ |
2512 | | {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */ |
2513 | | {bgp_stop, Idle}, /* TCP_connection_closed */ |
2514 | | {bgp_stop, Idle}, /* TCP_connection_open_failed */ |
2515 | | {bgp_stop, Idle}, /* TCP_fatal_error */ |
2516 | | {bgp_fsm_exception, Idle}, /* ConnectRetry_timer_expired */ |
2517 | | {bgp_fsm_holdtime_expire, Idle}, /* Hold_Timer_expired */ |
2518 | | {bgp_ignore, OpenConfirm}, /* KeepAlive_timer_expired */ |
2519 | | {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */ |
2520 | | {bgp_fsm_exception, Idle}, /* Receive_OPEN_message */ |
2521 | | {bgp_establish, Established}, /* Receive_KEEPALIVE_message */ |
2522 | | {bgp_fsm_exception, Idle}, /* Receive_UPDATE_message */ |
2523 | | {bgp_stop_with_error, Idle}, /* Receive_NOTIFICATION_message */ |
2524 | | {bgp_fsm_exception, Idle}, /* Clearing_Completed */ |
2525 | | }, |
2526 | | { |
2527 | | /* Established, */ |
2528 | | {bgp_ignore, Established}, /* BGP_Start */ |
2529 | | {bgp_stop, Clearing}, /* BGP_Stop */ |
2530 | | {bgp_stop, Clearing}, /* TCP_connection_open */ |
2531 | | {bgp_fsm_exception, Idle}, /* TCP_connection_open_w_delay */ |
2532 | | {bgp_stop, Clearing}, /* TCP_connection_closed */ |
2533 | | {bgp_stop, Clearing}, /* TCP_connection_open_failed */ |
2534 | | {bgp_stop, Clearing}, /* TCP_fatal_error */ |
2535 | | {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ |
2536 | | {bgp_fsm_holdtime_expire, Clearing}, /* Hold_Timer_expired */ |
2537 | | {bgp_ignore, Established}, /* KeepAlive_timer_expired */ |
2538 | | {bgp_fsm_exception, Idle}, /* DelayOpen_timer_expired */ |
2539 | | {bgp_stop, Clearing}, /* Receive_OPEN_message */ |
2540 | | {bgp_fsm_keepalive, |
2541 | | Established}, /* Receive_KEEPALIVE_message */ |
2542 | | {bgp_fsm_update, Established}, /* Receive_UPDATE_message */ |
2543 | | {bgp_stop_with_error, |
2544 | | Clearing}, /* Receive_NOTIFICATION_message */ |
2545 | | {bgp_fsm_exception, Idle}, /* Clearing_Completed */ |
2546 | | }, |
2547 | | { |
2548 | | /* Clearing, */ |
2549 | | {bgp_ignore, Clearing}, /* BGP_Start */ |
2550 | | {bgp_stop, Clearing}, /* BGP_Stop */ |
2551 | | {bgp_stop, Clearing}, /* TCP_connection_open */ |
2552 | | {bgp_stop, Clearing}, /* TCP_connection_open_w_delay */ |
2553 | | {bgp_stop, Clearing}, /* TCP_connection_closed */ |
2554 | | {bgp_stop, Clearing}, /* TCP_connection_open_failed */ |
2555 | | {bgp_stop, Clearing}, /* TCP_fatal_error */ |
2556 | | {bgp_stop, Clearing}, /* ConnectRetry_timer_expired */ |
2557 | | {bgp_stop, Clearing}, /* Hold_Timer_expired */ |
2558 | | {bgp_stop, Clearing}, /* KeepAlive_timer_expired */ |
2559 | | {bgp_stop, Clearing}, /* DelayOpen_timer_expired */ |
2560 | | {bgp_stop, Clearing}, /* Receive_OPEN_message */ |
2561 | | {bgp_stop, Clearing}, /* Receive_KEEPALIVE_message */ |
2562 | | {bgp_stop, Clearing}, /* Receive_UPDATE_message */ |
2563 | | {bgp_stop, Clearing}, /* Receive_NOTIFICATION_message */ |
2564 | | {bgp_clearing_completed, Idle}, /* Clearing_Completed */ |
2565 | | }, |
2566 | | { |
2567 | | /* Deleted, */ |
2568 | | {bgp_ignore, Deleted}, /* BGP_Start */ |
2569 | | {bgp_ignore, Deleted}, /* BGP_Stop */ |
2570 | | {bgp_ignore, Deleted}, /* TCP_connection_open */ |
2571 | | {bgp_ignore, Deleted}, /* TCP_connection_open_w_delay */ |
2572 | | {bgp_ignore, Deleted}, /* TCP_connection_closed */ |
2573 | | {bgp_ignore, Deleted}, /* TCP_connection_open_failed */ |
2574 | | {bgp_ignore, Deleted}, /* TCP_fatal_error */ |
2575 | | {bgp_ignore, Deleted}, /* ConnectRetry_timer_expired */ |
2576 | | {bgp_ignore, Deleted}, /* Hold_Timer_expired */ |
2577 | | {bgp_ignore, Deleted}, /* KeepAlive_timer_expired */ |
2578 | | {bgp_ignore, Deleted}, /* DelayOpen_timer_expired */ |
2579 | | {bgp_ignore, Deleted}, /* Receive_OPEN_message */ |
2580 | | {bgp_ignore, Deleted}, /* Receive_KEEPALIVE_message */ |
2581 | | {bgp_ignore, Deleted}, /* Receive_UPDATE_message */ |
2582 | | {bgp_ignore, Deleted}, /* Receive_NOTIFICATION_message */ |
2583 | | {bgp_ignore, Deleted}, /* Clearing_Completed */ |
2584 | | }, |
2585 | | }; |
2586 | | |
2587 | | /* Execute event process. */ |
2588 | | void bgp_event(struct event *thread) |
2589 | 0 | { |
2590 | 0 | enum bgp_fsm_events event; |
2591 | 0 | struct peer *peer; |
2592 | |
|
2593 | 0 | peer = EVENT_ARG(thread); |
2594 | 0 | event = EVENT_VAL(thread); |
2595 | |
|
2596 | 0 | peer_lock(peer); |
2597 | 0 | bgp_event_update(peer, event); |
2598 | 0 | peer_unlock(peer); |
2599 | 0 | } |
2600 | | |
2601 | | int bgp_event_update(struct peer *peer, enum bgp_fsm_events event) |
2602 | 0 | { |
2603 | 0 | enum bgp_fsm_status next; |
2604 | 0 | enum bgp_fsm_state_progress ret = 0; |
2605 | 0 | struct peer *other; |
2606 | 0 | int passive_conn = 0; |
2607 | 0 | int dyn_nbr; |
2608 | | |
2609 | | /* default return code */ |
2610 | 0 | ret = FSM_PEER_NOOP; |
2611 | |
|
2612 | 0 | other = peer->doppelganger; |
2613 | 0 | passive_conn = |
2614 | 0 | (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) ? 1 : 0; |
2615 | 0 | dyn_nbr = peer_dynamic_neighbor(peer); |
2616 | | |
2617 | | /* Logging this event. */ |
2618 | 0 | next = FSM[peer->status - 1][event - 1].next_state; |
2619 | |
|
2620 | 0 | if (bgp_debug_neighbor_events(peer) && peer->status != next) |
2621 | 0 | zlog_debug("%s [FSM] %s (%s->%s), fd %d", peer->host, |
2622 | 0 | bgp_event_str[event], |
2623 | 0 | lookup_msg(bgp_status_msg, peer->status, NULL), |
2624 | 0 | lookup_msg(bgp_status_msg, next, NULL), peer->fd); |
2625 | |
|
2626 | 0 | peer->last_event = peer->cur_event; |
2627 | 0 | peer->cur_event = event; |
2628 | | |
2629 | | /* Call function. */ |
2630 | 0 | if (FSM[peer->status - 1][event - 1].func) |
2631 | 0 | ret = (*(FSM[peer->status - 1][event - 1].func))(peer); |
2632 | |
|
2633 | 0 | if (ret >= BGP_FSM_SUCCESS) { |
2634 | 0 | if (ret == BGP_FSM_SUCCESS_STATE_TRANSFER && |
2635 | 0 | next == Established) { |
2636 | | /* The case when doppelganger swap accurred in |
2637 | | bgp_establish. |
2638 | | Update the peer pointer accordingly */ |
2639 | 0 | ret = FSM_PEER_TRANSFERRED; |
2640 | 0 | peer = other; |
2641 | 0 | } |
2642 | | |
2643 | | /* If status is changed. */ |
2644 | 0 | if (next != peer->status) { |
2645 | 0 | bgp_fsm_change_status(peer, next); |
2646 | | |
2647 | | /* |
2648 | | * If we're going to ESTABLISHED then we executed a |
2649 | | * peer transfer. In this case we can either return |
2650 | | * FSM_PEER_TRANSITIONED or FSM_PEER_TRANSFERRED. |
2651 | | * Opting for TRANSFERRED since transfer implies |
2652 | | * session establishment. |
2653 | | */ |
2654 | 0 | if (ret != FSM_PEER_TRANSFERRED) |
2655 | 0 | ret = FSM_PEER_TRANSITIONED; |
2656 | 0 | } |
2657 | | |
2658 | | /* Make sure timer is set. */ |
2659 | 0 | bgp_timer_set(peer); |
2660 | |
|
2661 | 0 | } else { |
2662 | | /* |
2663 | | * If we got a return value of -1, that means there was an |
2664 | | * error, restart the FSM. Since bgp_stop() was called on the |
2665 | | * peer. only a few fields are safe to access here. In any case |
2666 | | * we need to indicate that the peer was stopped in the return |
2667 | | * code. |
2668 | | */ |
2669 | 0 | if (!dyn_nbr && !passive_conn && peer->bgp && |
2670 | 0 | ret != BGP_FSM_FAILURE_AND_DELETE) { |
2671 | 0 | flog_err( |
2672 | 0 | EC_BGP_FSM, |
2673 | 0 | "%s [FSM] Failure handling event %s in state %s, prior events %s, %s, fd %d, last reset: %s", |
2674 | 0 | peer->host, bgp_event_str[peer->cur_event], |
2675 | 0 | lookup_msg(bgp_status_msg, peer->status, NULL), |
2676 | 0 | bgp_event_str[peer->last_event], |
2677 | 0 | bgp_event_str[peer->last_major_event], peer->fd, |
2678 | 0 | peer_down_str[peer->last_reset]); |
2679 | 0 | bgp_stop(peer); |
2680 | 0 | bgp_fsm_change_status(peer, Idle); |
2681 | 0 | bgp_timer_set(peer); |
2682 | 0 | } |
2683 | 0 | ret = FSM_PEER_STOPPED; |
2684 | 0 | } |
2685 | |
|
2686 | 0 | return ret; |
2687 | 0 | } |
2688 | | /* BGP GR Code */ |
2689 | | |
2690 | | int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, |
2691 | | enum global_mode global_new_state, |
2692 | | enum global_mode global_old_state) |
2693 | 0 | { |
2694 | 0 | struct peer *peer = {0}; |
2695 | 0 | struct listnode *node = {0}; |
2696 | 0 | struct listnode *nnode = {0}; |
2697 | 0 | enum peer_mode peer_old_state = PEER_INVALID; |
2698 | |
|
2699 | 0 | for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { |
2700 | |
|
2701 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2702 | 0 | zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__, |
2703 | 0 | peer->host); |
2704 | |
|
2705 | 0 | peer_old_state = bgp_peer_gr_mode_get(peer); |
2706 | |
|
2707 | 0 | if (peer_old_state == PEER_GLOBAL_INHERIT) { |
2708 | | |
2709 | | /* |
2710 | | *Reset only these peers and send a |
2711 | | *new open message with the change capabilities. |
2712 | | *Considering the mode to be "global_new_state" and |
2713 | | *do all operation accordingly |
2714 | | */ |
2715 | |
|
2716 | 0 | switch (global_new_state) { |
2717 | 0 | case GLOBAL_HELPER: |
2718 | 0 | BGP_PEER_GR_HELPER_ENABLE(peer); |
2719 | 0 | break; |
2720 | 0 | case GLOBAL_GR: |
2721 | 0 | BGP_PEER_GR_ENABLE(peer); |
2722 | 0 | break; |
2723 | 0 | case GLOBAL_DISABLE: |
2724 | 0 | BGP_PEER_GR_DISABLE(peer); |
2725 | 0 | break; |
2726 | 0 | case GLOBAL_INVALID: |
2727 | 0 | zlog_debug("%s [BGP_GR] GLOBAL_INVALID", |
2728 | 0 | __func__); |
2729 | 0 | return BGP_ERR_GR_OPERATION_FAILED; |
2730 | 0 | } |
2731 | 0 | } |
2732 | 0 | } |
2733 | | |
2734 | 0 | bgp->global_gr_present_state = global_new_state; |
2735 | |
|
2736 | 0 | return BGP_GR_SUCCESS; |
2737 | 0 | } |
2738 | | |
2739 | | int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd) |
2740 | 0 | { |
2741 | 0 | enum global_mode global_new_state = GLOBAL_INVALID; |
2742 | 0 | enum global_mode global_old_state = GLOBAL_INVALID; |
2743 | |
|
2744 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2745 | 0 | zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__, |
2746 | 0 | print_global_gr_cmd(global_gr_cmd)); |
2747 | |
|
2748 | 0 | global_old_state = bgp_global_gr_mode_get(bgp); |
2749 | |
|
2750 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2751 | 0 | zlog_debug("[BGP_GR] global_old_gr_state :%s:", |
2752 | 0 | print_global_gr_mode(global_old_state)); |
2753 | |
|
2754 | 0 | if (global_old_state != GLOBAL_INVALID) { |
2755 | 0 | global_new_state = |
2756 | 0 | bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; |
2757 | |
|
2758 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2759 | 0 | zlog_debug("[BGP_GR] global_new_gr_state :%s:", |
2760 | 0 | print_global_gr_mode(global_new_state)); |
2761 | 0 | } else { |
2762 | 0 | zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", |
2763 | 0 | __func__); |
2764 | 0 | return BGP_ERR_GR_OPERATION_FAILED; |
2765 | 0 | } |
2766 | | |
2767 | 0 | if (global_new_state == GLOBAL_INVALID) { |
2768 | 0 | zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID", |
2769 | 0 | __func__); |
2770 | 0 | return BGP_ERR_GR_INVALID_CMD; |
2771 | 0 | } |
2772 | 0 | if (global_new_state == global_old_state) { |
2773 | | /* Trace msg */ |
2774 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2775 | 0 | zlog_debug( |
2776 | 0 | "%s [BGP_GR] global_new_state == global_old_state :%s", |
2777 | 0 | __func__, |
2778 | 0 | print_global_gr_mode(global_new_state)); |
2779 | 0 | return BGP_GR_NO_OPERATION; |
2780 | 0 | } |
2781 | | |
2782 | 0 | return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, |
2783 | 0 | global_old_state); |
2784 | 0 | } |
2785 | | |
2786 | | const char *print_peer_gr_mode(enum peer_mode pr_mode) |
2787 | 0 | { |
2788 | 0 | const char *peer_gr_mode = NULL; |
2789 | |
|
2790 | 0 | switch (pr_mode) { |
2791 | 0 | case PEER_HELPER: |
2792 | 0 | peer_gr_mode = "PEER_HELPER"; |
2793 | 0 | break; |
2794 | 0 | case PEER_GR: |
2795 | 0 | peer_gr_mode = "PEER_GR"; |
2796 | 0 | break; |
2797 | 0 | case PEER_DISABLE: |
2798 | 0 | peer_gr_mode = "PEER_DISABLE"; |
2799 | 0 | break; |
2800 | 0 | case PEER_INVALID: |
2801 | 0 | peer_gr_mode = "PEER_INVALID"; |
2802 | 0 | break; |
2803 | 0 | case PEER_GLOBAL_INHERIT: |
2804 | 0 | peer_gr_mode = "PEER_GLOBAL_INHERIT"; |
2805 | 0 | break; |
2806 | 0 | } |
2807 | | |
2808 | 0 | return peer_gr_mode; |
2809 | 0 | } |
2810 | | |
2811 | | const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd) |
2812 | 0 | { |
2813 | 0 | const char *peer_gr_cmd = NULL; |
2814 | |
|
2815 | 0 | switch (pr_gr_cmd) { |
2816 | 0 | case PEER_GR_CMD: |
2817 | 0 | peer_gr_cmd = "PEER_GR_CMD"; |
2818 | 0 | break; |
2819 | 0 | case NO_PEER_GR_CMD: |
2820 | 0 | peer_gr_cmd = "NO_PEER_GR_CMD"; |
2821 | 0 | break; |
2822 | 0 | case PEER_DISABLE_CMD: |
2823 | 0 | peer_gr_cmd = "PEER_DISABLE_GR_CMD"; |
2824 | 0 | break; |
2825 | 0 | case NO_PEER_DISABLE_CMD: |
2826 | 0 | peer_gr_cmd = "NO_PEER_DISABLE_GR_CMD"; |
2827 | 0 | break; |
2828 | 0 | case PEER_HELPER_CMD: |
2829 | 0 | peer_gr_cmd = "PEER_HELPER_CMD"; |
2830 | 0 | break; |
2831 | 0 | case NO_PEER_HELPER_CMD: |
2832 | 0 | peer_gr_cmd = "NO_PEER_HELPER_CMD"; |
2833 | 0 | break; |
2834 | 0 | } |
2835 | | |
2836 | 0 | return peer_gr_cmd; |
2837 | 0 | } |
2838 | | |
2839 | | const char *print_global_gr_mode(enum global_mode gl_mode) |
2840 | 0 | { |
2841 | 0 | const char *global_gr_mode = "???"; |
2842 | |
|
2843 | 0 | switch (gl_mode) { |
2844 | 0 | case GLOBAL_HELPER: |
2845 | 0 | global_gr_mode = "GLOBAL_HELPER"; |
2846 | 0 | break; |
2847 | 0 | case GLOBAL_GR: |
2848 | 0 | global_gr_mode = "GLOBAL_GR"; |
2849 | 0 | break; |
2850 | 0 | case GLOBAL_DISABLE: |
2851 | 0 | global_gr_mode = "GLOBAL_DISABLE"; |
2852 | 0 | break; |
2853 | 0 | case GLOBAL_INVALID: |
2854 | 0 | global_gr_mode = "GLOBAL_INVALID"; |
2855 | 0 | break; |
2856 | 0 | } |
2857 | | |
2858 | 0 | return global_gr_mode; |
2859 | 0 | } |
2860 | | |
2861 | | const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd) |
2862 | 0 | { |
2863 | 0 | const char *global_gr_cmd = NULL; |
2864 | |
|
2865 | 0 | switch (gl_gr_cmd) { |
2866 | 0 | case GLOBAL_GR_CMD: |
2867 | 0 | global_gr_cmd = "GLOBAL_GR_CMD"; |
2868 | 0 | break; |
2869 | 0 | case NO_GLOBAL_GR_CMD: |
2870 | 0 | global_gr_cmd = "NO_GLOBAL_GR_CMD"; |
2871 | 0 | break; |
2872 | 0 | case GLOBAL_DISABLE_CMD: |
2873 | 0 | global_gr_cmd = "GLOBAL_DISABLE_CMD"; |
2874 | 0 | break; |
2875 | 0 | case NO_GLOBAL_DISABLE_CMD: |
2876 | 0 | global_gr_cmd = "NO_GLOBAL_DISABLE_CMD"; |
2877 | 0 | break; |
2878 | 0 | } |
2879 | | |
2880 | 0 | return global_gr_cmd; |
2881 | 0 | } |
2882 | | |
2883 | | enum global_mode bgp_global_gr_mode_get(struct bgp *bgp) |
2884 | 2 | { |
2885 | 2 | return bgp->global_gr_present_state; |
2886 | 2 | } |
2887 | | |
2888 | | enum peer_mode bgp_peer_gr_mode_get(struct peer *peer) |
2889 | 0 | { |
2890 | 0 | return peer->peer_gr_present_state; |
2891 | 0 | } |
2892 | | |
2893 | | int bgp_neighbor_graceful_restart(struct peer *peer, int peer_gr_cmd) |
2894 | 0 | { |
2895 | 0 | enum peer_mode peer_new_state = PEER_INVALID; |
2896 | 0 | enum peer_mode peer_old_state = PEER_INVALID; |
2897 | 0 | struct bgp_peer_gr peer_state; |
2898 | 0 | int result = BGP_GR_FAILURE; |
2899 | | |
2900 | | /* |
2901 | | * fetch peer_old_state from peer structure also |
2902 | | * fetch global_old_state from bgp structure, |
2903 | | * peer had a back pointer to bgpo struct ; |
2904 | | */ |
2905 | |
|
2906 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2907 | 0 | zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:", |
2908 | 0 | __func__, peer->host, |
2909 | 0 | print_peer_gr_cmd(peer_gr_cmd)); |
2910 | |
|
2911 | 0 | peer_old_state = bgp_peer_gr_mode_get(peer); |
2912 | |
|
2913 | 0 | if (peer_old_state == PEER_INVALID) { |
2914 | 0 | zlog_debug("[BGP_GR] peer_old_state == Invalid state !"); |
2915 | 0 | return BGP_ERR_GR_OPERATION_FAILED; |
2916 | 0 | } |
2917 | | |
2918 | 0 | peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; |
2919 | 0 | peer_new_state = peer_state.next_state; |
2920 | |
|
2921 | 0 | if (peer_new_state == PEER_INVALID) { |
2922 | 0 | zlog_debug( |
2923 | 0 | "[BGP_GR] Invalid bgp graceful restart command used !"); |
2924 | 0 | return BGP_ERR_GR_INVALID_CMD; |
2925 | 0 | } |
2926 | | |
2927 | 0 | if (peer_new_state != peer_old_state) { |
2928 | 0 | result = peer_state.action_fun(peer, peer_old_state, |
2929 | 0 | peer_new_state); |
2930 | 0 | } else { |
2931 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2932 | 0 | zlog_debug( |
2933 | 0 | "[BGP_GR] peer_old_state == peer_new_state !"); |
2934 | 0 | return BGP_GR_NO_OPERATION; |
2935 | 0 | } |
2936 | | |
2937 | 0 | if (result == BGP_GR_SUCCESS) { |
2938 | | |
2939 | | /* Update the mode i.e peer_new_state into the peer structure */ |
2940 | 0 | peer->peer_gr_present_state = peer_new_state; |
2941 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2942 | 0 | zlog_debug( |
2943 | 0 | "[BGP_GR] Successfully change the state of the peer to : %s : !", |
2944 | 0 | print_peer_gr_mode(peer_new_state)); |
2945 | |
|
2946 | 0 | return BGP_GR_SUCCESS; |
2947 | 0 | } |
2948 | | |
2949 | 0 | return result; |
2950 | 0 | } |
2951 | | |
2952 | | unsigned int bgp_peer_gr_action(struct peer *peer, int old_peer_state, |
2953 | | int new_peer_state) |
2954 | 0 | { |
2955 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
2956 | 0 | zlog_debug( |
2957 | 0 | "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", |
2958 | 0 | __func__, print_peer_gr_mode(old_peer_state), |
2959 | 0 | print_peer_gr_mode(new_peer_state)); |
2960 | |
|
2961 | 0 | int bgp_gr_global_mode = GLOBAL_INVALID; |
2962 | 0 | unsigned int ret = BGP_GR_FAILURE; |
2963 | |
|
2964 | 0 | if (old_peer_state == new_peer_state) { |
2965 | | /* Nothing to do over here as the present and old state is the |
2966 | | * same */ |
2967 | 0 | return BGP_GR_NO_OPERATION; |
2968 | 0 | } |
2969 | 0 | if ((old_peer_state == PEER_INVALID) |
2970 | 0 | || (new_peer_state == PEER_INVALID)) { |
2971 | | /* something bad happend , print error message */ |
2972 | 0 | return BGP_ERR_GR_INVALID_CMD; |
2973 | 0 | } |
2974 | | |
2975 | 0 | bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); |
2976 | |
|
2977 | 0 | if ((old_peer_state == PEER_GLOBAL_INHERIT) |
2978 | 0 | && (new_peer_state != PEER_GLOBAL_INHERIT)) { |
2979 | | |
2980 | | /* fetch the Mode running in the Global state machine |
2981 | | *from the bgp structure into a variable called |
2982 | | *bgp_gr_global_mode |
2983 | | */ |
2984 | | |
2985 | | /* Here we are checking if the |
2986 | | *1. peer_new_state == global_mode == helper_mode |
2987 | | *2. peer_new_state == global_mode == GR_mode |
2988 | | *3. peer_new_state == global_mode == disabled_mode |
2989 | | */ |
2990 | |
|
2991 | 0 | BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); |
2992 | |
|
2993 | 0 | if (new_peer_state == bgp_gr_global_mode) { |
2994 | | /*This is incremental updates i.e no tear down |
2995 | | *of the existing session |
2996 | | *as the peer is already working in the same mode. |
2997 | | */ |
2998 | 0 | ret = BGP_GR_SUCCESS; |
2999 | 0 | } else { |
3000 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3001 | 0 | zlog_debug( |
3002 | 0 | "[BGP_GR] Peer state changed from :%s ", |
3003 | 0 | print_peer_gr_mode(old_peer_state)); |
3004 | |
|
3005 | 0 | bgp_peer_move_to_gr_mode(peer, new_peer_state); |
3006 | |
|
3007 | 0 | ret = BGP_GR_SUCCESS; |
3008 | 0 | } |
3009 | 0 | } |
3010 | | /* In the case below peer is going into Global inherit mode i.e. |
3011 | | * the peer would work as the mode configured at the global level |
3012 | | */ |
3013 | 0 | else if ((new_peer_state == PEER_GLOBAL_INHERIT) |
3014 | 0 | && (old_peer_state != PEER_GLOBAL_INHERIT)) { |
3015 | | /* Here in this case it would be destructive |
3016 | | * in all the cases except one case when, |
3017 | | * Global GR is configured Disabled |
3018 | | * and present_peer_state is not disable |
3019 | | */ |
3020 | |
|
3021 | 0 | BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); |
3022 | |
|
3023 | 0 | if (old_peer_state == bgp_gr_global_mode) { |
3024 | | |
3025 | | /* This is incremental updates |
3026 | | *i.e no tear down of the existing session |
3027 | | *as the peer is already working in the same mode. |
3028 | | */ |
3029 | 0 | ret = BGP_GR_SUCCESS; |
3030 | 0 | } else { |
3031 | | /* Destructive always */ |
3032 | | /* Tear down the old session |
3033 | | * and send the new capability |
3034 | | * as per the bgp_gr_global_mode |
3035 | | */ |
3036 | |
|
3037 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3038 | 0 | zlog_debug( |
3039 | 0 | "[BGP_GR] Peer state changed from :%s", |
3040 | 0 | print_peer_gr_mode(old_peer_state)); |
3041 | |
|
3042 | 0 | bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); |
3043 | |
|
3044 | 0 | ret = BGP_GR_SUCCESS; |
3045 | 0 | } |
3046 | 0 | } else { |
3047 | | /* |
3048 | | *This else case, it include all the cases except --> |
3049 | | *(new_peer_state != Peer_Global) && |
3050 | | *( old_peer_state != Peer_Global ) |
3051 | | */ |
3052 | 0 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3053 | 0 | zlog_debug("[BGP_GR] Peer state changed from :%s", |
3054 | 0 | print_peer_gr_mode(old_peer_state)); |
3055 | |
|
3056 | 0 | bgp_peer_move_to_gr_mode(peer, new_peer_state); |
3057 | |
|
3058 | 0 | ret = BGP_GR_SUCCESS; |
3059 | 0 | } |
3060 | |
|
3061 | 0 | return ret; |
3062 | 0 | } |
3063 | | |
3064 | | inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) |
3065 | | |
3066 | 2 | { |
3067 | 2 | int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); |
3068 | | |
3069 | 2 | switch (new_state) { |
3070 | 0 | case PEER_HELPER: |
3071 | 0 | BGP_PEER_GR_HELPER_ENABLE(peer); |
3072 | 0 | break; |
3073 | 0 | case PEER_GR: |
3074 | 0 | BGP_PEER_GR_ENABLE(peer); |
3075 | 0 | break; |
3076 | 0 | case PEER_DISABLE: |
3077 | 0 | BGP_PEER_GR_DISABLE(peer); |
3078 | 0 | break; |
3079 | 2 | case PEER_GLOBAL_INHERIT: |
3080 | 2 | BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); |
3081 | | |
3082 | 2 | if (bgp_global_gr_mode == GLOBAL_HELPER) { |
3083 | 2 | BGP_PEER_GR_HELPER_ENABLE(peer); |
3084 | 2 | } else if (bgp_global_gr_mode == GLOBAL_GR) { |
3085 | 0 | BGP_PEER_GR_ENABLE(peer); |
3086 | 0 | } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { |
3087 | 0 | BGP_PEER_GR_DISABLE(peer); |
3088 | 0 | } else { |
3089 | 0 | zlog_err( |
3090 | 0 | "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!"); |
3091 | 0 | } |
3092 | 2 | break; |
3093 | 0 | default: |
3094 | 0 | zlog_err( |
3095 | 0 | "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); |
3096 | 0 | break; |
3097 | 2 | } |
3098 | 2 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3099 | 0 | zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", |
3100 | 2 | new_state); |
3101 | 2 | } |
3102 | | |
3103 | | void bgp_peer_gr_flags_update(struct peer *peer) |
3104 | 534 | { |
3105 | 534 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3106 | 0 | zlog_debug("%s [BGP_GR] called !", __func__); |
3107 | 534 | if (CHECK_FLAG(peer->peer_gr_new_status_flag, |
3108 | 534 | PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) |
3109 | 534 | SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); |
3110 | 0 | else |
3111 | 0 | UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); |
3112 | 534 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3113 | 0 | zlog_debug( |
3114 | 534 | "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", |
3115 | 534 | peer->host, |
3116 | 534 | (CHECK_FLAG(peer->flags, |
3117 | 534 | PEER_FLAG_GRACEFUL_RESTART_HELPER) |
3118 | 534 | ? "Set" |
3119 | 534 | : "UnSet")); |
3120 | 534 | if (CHECK_FLAG(peer->peer_gr_new_status_flag, |
3121 | 534 | PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) |
3122 | 0 | SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); |
3123 | 534 | else |
3124 | 534 | UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); |
3125 | 534 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3126 | 0 | zlog_debug( |
3127 | 534 | "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", |
3128 | 534 | peer->host, |
3129 | 534 | (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) |
3130 | 534 | ? "Set" |
3131 | 534 | : "UnSet")); |
3132 | 534 | if (CHECK_FLAG(peer->peer_gr_new_status_flag, |
3133 | 534 | PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) |
3134 | 534 | SET_FLAG(peer->flags, |
3135 | 534 | PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); |
3136 | 0 | else |
3137 | 0 | UNSET_FLAG(peer->flags, |
3138 | 534 | PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); |
3139 | 534 | if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) |
3140 | 0 | zlog_debug( |
3141 | 534 | "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", |
3142 | 534 | peer->host, |
3143 | 534 | (CHECK_FLAG(peer->flags, |
3144 | 534 | PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) |
3145 | 534 | ? "Set" |
3146 | 534 | : "UnSet")); |
3147 | | |
3148 | 534 | if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) |
3149 | 534 | && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { |
3150 | 0 | zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!", |
3151 | 0 | peer->host); |
3152 | |
|
3153 | 0 | UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); |
3154 | |
|
3155 | 0 | if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { |
3156 | |
|
3157 | 0 | peer_nsf_stop(peer); |
3158 | 0 | zlog_debug( |
3159 | 0 | "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!", |
3160 | 0 | peer->host); |
3161 | 0 | } |
3162 | 0 | } |
3163 | 534 | } |