]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* BGP nexthop scan |
2 | Copyright (C) 2000 Kunihiro Ishiguro | |
3 | ||
4 | This file is part of GNU Zebra. | |
5 | ||
6 | GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published by the | |
8 | Free Software Foundation; either version 2, or (at your option) any | |
9 | later version. | |
10 | ||
11 | GNU Zebra is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU Zebra; see the file COPYING. If not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | 02111-1307, USA. */ | |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "thread.h" | |
25 | #include "prefix.h" | |
26 | #include "zclient.h" | |
27 | #include "stream.h" | |
28 | #include "network.h" | |
29 | #include "log.h" | |
30 | #include "memory.h" | |
31 | ||
32 | #include "bgpd/bgpd.h" | |
33 | #include "bgpd/bgp_table.h" | |
34 | #include "bgpd/bgp_route.h" | |
35 | #include "bgpd/bgp_attr.h" | |
36 | #include "bgpd/bgp_nexthop.h" | |
37 | #include "bgpd/bgp_debug.h" | |
38 | #include "bgpd/bgp_damp.h" | |
39 | #include "zebra/rib.h" | |
40 | #include "zebra/zserv.h" /* For ZEBRA_SERV_PATH. */ | |
41 | ||
42 | struct bgp_nexthop_cache *zlookup_query (struct in_addr); | |
43 | #ifdef HAVE_IPV6 | |
44 | struct bgp_nexthop_cache *zlookup_query_ipv6 (struct in6_addr *); | |
45 | #endif /* HAVE_IPV6 */ | |
46 | \f | |
47 | /* Only one BGP scan thread are activated at the same time. */ | |
00d252cb | 48 | static struct thread *bgp_scan_thread = NULL; |
718e3744 | 49 | |
50 | /* BGP import thread */ | |
00d252cb | 51 | static struct thread *bgp_import_thread = NULL; |
718e3744 | 52 | |
53 | /* BGP scan interval. */ | |
00d252cb | 54 | static int bgp_scan_interval; |
718e3744 | 55 | |
56 | /* BGP import interval. */ | |
00d252cb | 57 | static int bgp_import_interval; |
718e3744 | 58 | |
59 | /* Route table for next-hop lookup cache. */ | |
00d252cb | 60 | static struct bgp_table *bgp_nexthop_cache_table[AFI_MAX]; |
61 | static struct bgp_table *cache1_table[AFI_MAX]; | |
62 | static struct bgp_table *cache2_table[AFI_MAX]; | |
718e3744 | 63 | |
64 | /* Route table for connected route. */ | |
00d252cb | 65 | static struct bgp_table *bgp_connected_table[AFI_MAX]; |
718e3744 | 66 | |
67 | /* BGP nexthop lookup query client. */ | |
68 | static struct zclient *zlookup = NULL; | |
69 | ||
70 | /* BGP process function. */ | |
71 | int bgp_process (struct bgp *, struct bgp_node *, afi_t, safi_t); | |
72 | \f | |
73 | /* Add nexthop to the end of the list. */ | |
74 | void | |
75 | bnc_nexthop_add (struct bgp_nexthop_cache *bnc, struct nexthop *nexthop) | |
76 | { | |
77 | struct nexthop *last; | |
78 | ||
79 | for (last = bnc->nexthop; last && last->next; last = last->next) | |
80 | ; | |
81 | if (last) | |
82 | last->next = nexthop; | |
83 | else | |
84 | bnc->nexthop = nexthop; | |
85 | nexthop->prev = last; | |
86 | } | |
87 | ||
88 | void | |
89 | bnc_nexthop_free (struct bgp_nexthop_cache *bnc) | |
90 | { | |
91 | struct nexthop *nexthop; | |
92 | struct nexthop *next = NULL; | |
93 | ||
94 | for (nexthop = bnc->nexthop; nexthop; nexthop = next) | |
95 | { | |
96 | next = nexthop->next; | |
97 | XFREE (MTYPE_NEXTHOP, nexthop); | |
98 | } | |
99 | } | |
100 | ||
101 | struct bgp_nexthop_cache * | |
102 | bnc_new () | |
103 | { | |
104 | struct bgp_nexthop_cache *new; | |
105 | ||
106 | new = XMALLOC (MTYPE_BGP_NEXTHOP_CACHE, sizeof (struct bgp_nexthop_cache)); | |
107 | memset (new, 0, sizeof (struct bgp_nexthop_cache)); | |
108 | return new; | |
109 | } | |
110 | ||
111 | void | |
112 | bnc_free (struct bgp_nexthop_cache *bnc) | |
113 | { | |
114 | bnc_nexthop_free (bnc); | |
115 | XFREE (MTYPE_BGP_NEXTHOP_CACHE, bnc); | |
116 | } | |
117 | \f | |
118 | int | |
119 | bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2) | |
120 | { | |
121 | if (next1->type != next2->type) | |
122 | return 0; | |
123 | ||
124 | switch (next1->type) | |
125 | { | |
126 | case ZEBRA_NEXTHOP_IPV4: | |
127 | if (! IPV4_ADDR_SAME (&next1->gate.ipv4, &next2->gate.ipv4)) | |
128 | return 0; | |
129 | break; | |
130 | case ZEBRA_NEXTHOP_IFINDEX: | |
131 | case ZEBRA_NEXTHOP_IFNAME: | |
132 | if (next1->ifindex != next2->ifindex) | |
133 | return 0; | |
134 | break; | |
135 | #ifdef HAVE_IPV6 | |
136 | case ZEBRA_NEXTHOP_IPV6: | |
137 | if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) | |
138 | return 0; | |
139 | break; | |
140 | case ZEBRA_NEXTHOP_IPV6_IFINDEX: | |
141 | case ZEBRA_NEXTHOP_IPV6_IFNAME: | |
142 | if (! IPV6_ADDR_SAME (&next1->gate.ipv6, &next2->gate.ipv6)) | |
143 | return 0; | |
144 | if (next1->ifindex != next2->ifindex) | |
145 | return 0; | |
146 | break; | |
147 | #endif /* HAVE_IPV6 */ | |
fa2b17e3 | 148 | default: |
149 | /* do nothing */ | |
150 | break; | |
718e3744 | 151 | } |
152 | return 1; | |
153 | } | |
154 | ||
155 | int | |
156 | bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, | |
157 | struct bgp_nexthop_cache *bnc2) | |
158 | { | |
159 | int i; | |
160 | struct nexthop *next1, *next2; | |
161 | ||
162 | if (bnc1->nexthop_num != bnc2->nexthop_num) | |
163 | return 1; | |
164 | ||
165 | next1 = bnc1->nexthop; | |
166 | next2 = bnc2->nexthop; | |
167 | ||
168 | for (i = 0; i < bnc1->nexthop_num; i++) | |
169 | { | |
170 | if (! bgp_nexthop_same (next1, next2)) | |
171 | return 1; | |
172 | ||
173 | next1 = next1->next; | |
174 | next2 = next2->next; | |
175 | } | |
176 | return 0; | |
177 | } | |
178 | ||
179 | /* If nexthop exists on connected network return 1. */ | |
180 | int | |
181 | bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) | |
182 | { | |
183 | struct bgp_node *rn; | |
184 | ||
185 | /* If zebra is not enabled return */ | |
186 | if (zlookup->sock < 0) | |
187 | return 1; | |
188 | ||
189 | /* Lookup the address is onlink or not. */ | |
190 | if (afi == AFI_IP) | |
191 | { | |
5932020b | 192 | rn = bgp_node_match_ipv4 (bgp_connected_table[AFI_IP], &attr->nexthop); |
718e3744 | 193 | if (rn) |
194 | { | |
195 | bgp_unlock_node (rn); | |
196 | return 1; | |
197 | } | |
198 | } | |
199 | #ifdef HAVE_IPV6 | |
200 | else if (afi == AFI_IP6) | |
201 | { | |
202 | if (attr->mp_nexthop_len == 32) | |
203 | return 1; | |
204 | else if (attr->mp_nexthop_len == 16) | |
205 | { | |
206 | if (IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) | |
207 | return 1; | |
208 | ||
5932020b | 209 | rn = bgp_node_match_ipv6 (bgp_connected_table[AFI_IP6], |
718e3744 | 210 | &attr->mp_nexthop_global); |
211 | if (rn) | |
212 | { | |
213 | bgp_unlock_node (rn); | |
214 | return 1; | |
215 | } | |
216 | } | |
217 | } | |
218 | #endif /* HAVE_IPV6 */ | |
219 | return 0; | |
220 | } | |
221 | ||
222 | #ifdef HAVE_IPV6 | |
223 | /* Check specified next-hop is reachable or not. */ | |
224 | int | |
225 | bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed, | |
226 | int *metricchanged) | |
227 | { | |
228 | struct bgp_node *rn; | |
229 | struct prefix p; | |
230 | struct bgp_nexthop_cache *bnc; | |
231 | struct attr *attr; | |
232 | ||
233 | /* If lookup is not enabled, return valid. */ | |
234 | if (zlookup->sock < 0) | |
235 | { | |
236 | ri->igpmetric = 0; | |
237 | return 1; | |
238 | } | |
239 | ||
240 | /* Only check IPv6 global address only nexthop. */ | |
241 | attr = ri->attr; | |
242 | ||
243 | if (attr->mp_nexthop_len != 16 | |
244 | || IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_global)) | |
245 | return 1; | |
246 | ||
247 | memset (&p, 0, sizeof (struct prefix)); | |
248 | p.family = AF_INET6; | |
249 | p.prefixlen = IPV6_MAX_BITLEN; | |
250 | p.u.prefix6 = attr->mp_nexthop_global; | |
251 | ||
252 | /* IBGP or ebgp-multihop */ | |
5932020b | 253 | rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP6], &p); |
718e3744 | 254 | |
255 | if (rn->info) | |
256 | { | |
257 | bnc = rn->info; | |
258 | bgp_unlock_node (rn); | |
259 | } | |
260 | else | |
261 | { | |
262 | bnc = zlookup_query_ipv6 (&attr->mp_nexthop_global); | |
263 | if (bnc) | |
264 | { | |
265 | struct bgp_table *old; | |
266 | struct bgp_node *oldrn; | |
267 | struct bgp_nexthop_cache *oldbnc; | |
268 | ||
269 | if (changed) | |
270 | { | |
5932020b | 271 | if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6]) |
272 | old = cache2_table[AFI_IP6]; | |
718e3744 | 273 | else |
5932020b | 274 | old = cache1_table[AFI_IP6]; |
718e3744 | 275 | |
276 | oldrn = bgp_node_lookup (old, &p); | |
277 | if (oldrn) | |
278 | { | |
279 | oldbnc = oldrn->info; | |
280 | ||
281 | bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); | |
282 | ||
283 | if (bnc->metric != oldbnc->metric) | |
284 | bnc->metricchanged = 1; | |
285 | } | |
286 | } | |
287 | } | |
288 | else | |
289 | { | |
290 | bnc = bnc_new (); | |
291 | bnc->valid = 0; | |
292 | } | |
293 | rn->info = bnc; | |
294 | } | |
295 | ||
296 | if (changed) | |
297 | *changed = bnc->changed; | |
298 | ||
299 | if (metricchanged) | |
300 | *metricchanged = bnc->metricchanged; | |
301 | ||
302 | if (bnc->valid) | |
303 | ri->igpmetric = bnc->metric; | |
304 | else | |
305 | ri->igpmetric = 0; | |
306 | ||
307 | return bnc->valid; | |
308 | } | |
309 | #endif /* HAVE_IPV6 */ | |
310 | ||
311 | /* Check specified next-hop is reachable or not. */ | |
312 | int | |
313 | bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri, | |
314 | int *changed, int *metricchanged) | |
315 | { | |
316 | struct bgp_node *rn; | |
317 | struct prefix p; | |
318 | struct bgp_nexthop_cache *bnc; | |
319 | struct in_addr addr; | |
320 | ||
321 | /* If lookup is not enabled, return valid. */ | |
322 | if (zlookup->sock < 0) | |
323 | { | |
324 | ri->igpmetric = 0; | |
325 | return 1; | |
326 | } | |
327 | ||
328 | #ifdef HAVE_IPV6 | |
329 | if (afi == AFI_IP6) | |
330 | return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); | |
331 | #endif /* HAVE_IPV6 */ | |
332 | ||
333 | addr = ri->attr->nexthop; | |
334 | ||
335 | memset (&p, 0, sizeof (struct prefix)); | |
336 | p.family = AF_INET; | |
337 | p.prefixlen = IPV4_MAX_BITLEN; | |
338 | p.u.prefix4 = addr; | |
339 | ||
340 | /* IBGP or ebgp-multihop */ | |
5932020b | 341 | rn = bgp_node_get (bgp_nexthop_cache_table[AFI_IP], &p); |
718e3744 | 342 | |
343 | if (rn->info) | |
344 | { | |
345 | bnc = rn->info; | |
346 | bgp_unlock_node (rn); | |
347 | } | |
348 | else | |
349 | { | |
350 | bnc = zlookup_query (addr); | |
351 | if (bnc) | |
352 | { | |
353 | struct bgp_table *old; | |
354 | struct bgp_node *oldrn; | |
355 | struct bgp_nexthop_cache *oldbnc; | |
356 | ||
357 | if (changed) | |
358 | { | |
5932020b | 359 | if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP]) |
360 | old = cache2_table[AFI_IP]; | |
718e3744 | 361 | else |
5932020b | 362 | old = cache1_table[AFI_IP]; |
718e3744 | 363 | |
364 | oldrn = bgp_node_lookup (old, &p); | |
365 | if (oldrn) | |
366 | { | |
367 | oldbnc = oldrn->info; | |
368 | ||
369 | bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); | |
370 | ||
371 | if (bnc->metric != oldbnc->metric) | |
372 | bnc->metricchanged = 1; | |
373 | } | |
374 | } | |
375 | } | |
376 | else | |
377 | { | |
378 | bnc = bnc_new (); | |
379 | bnc->valid = 0; | |
380 | } | |
381 | rn->info = bnc; | |
382 | } | |
383 | ||
384 | if (changed) | |
385 | *changed = bnc->changed; | |
386 | ||
387 | if (metricchanged) | |
388 | *metricchanged = bnc->metricchanged; | |
389 | ||
390 | if (bnc->valid) | |
391 | ri->igpmetric = bnc->metric; | |
392 | else | |
393 | ri->igpmetric = 0; | |
394 | ||
395 | return bnc->valid; | |
396 | } | |
397 | ||
398 | /* Reset and free all BGP nexthop cache. */ | |
399 | void | |
400 | bgp_nexthop_cache_reset (struct bgp_table *table) | |
401 | { | |
402 | struct bgp_node *rn; | |
403 | struct bgp_nexthop_cache *bnc; | |
404 | ||
405 | for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn)) | |
406 | if ((bnc = rn->info) != NULL) | |
407 | { | |
408 | bnc_free (bnc); | |
409 | rn->info = NULL; | |
410 | bgp_unlock_node (rn); | |
411 | } | |
412 | } | |
413 | ||
414 | void | |
5932020b | 415 | bgp_scan (afi_t afi, safi_t safi) |
718e3744 | 416 | { |
417 | struct bgp_node *rn; | |
418 | struct bgp *bgp; | |
419 | struct bgp_info *bi; | |
420 | struct bgp_info *next; | |
421 | struct peer *peer; | |
1eb8ef25 | 422 | struct listnode *node, *nnode; |
718e3744 | 423 | int valid; |
424 | int current; | |
425 | int changed; | |
426 | int metricchanged; | |
427 | ||
428 | /* Change cache. */ | |
5932020b | 429 | if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) |
430 | bgp_nexthop_cache_table[afi] = cache2_table[afi]; | |
718e3744 | 431 | else |
5932020b | 432 | bgp_nexthop_cache_table[afi] = cache1_table[afi]; |
718e3744 | 433 | |
434 | /* Get default bgp. */ | |
435 | bgp = bgp_get_default (); | |
436 | if (bgp == NULL) | |
437 | return; | |
438 | ||
439 | /* Maximum prefix check */ | |
1eb8ef25 | 440 | for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) |
718e3744 | 441 | { |
442 | if (peer->status != Established) | |
443 | continue; | |
444 | ||
5932020b | 445 | if (peer->afc[afi][SAFI_UNICAST]) |
446 | bgp_maximum_prefix_overflow (peer, afi, SAFI_UNICAST, 1); | |
447 | if (peer->afc[afi][SAFI_MULTICAST]) | |
448 | bgp_maximum_prefix_overflow (peer, afi, SAFI_MULTICAST, 1); | |
449 | if (peer->afc[afi][SAFI_MPLS_VPN]) | |
450 | bgp_maximum_prefix_overflow (peer, afi, SAFI_MPLS_VPN, 1); | |
718e3744 | 451 | } |
452 | ||
5932020b | 453 | for (rn = bgp_table_top (bgp->rib[afi][SAFI_UNICAST]); rn; |
718e3744 | 454 | rn = bgp_route_next (rn)) |
455 | { | |
456 | for (bi = rn->info; bi; bi = next) | |
457 | { | |
458 | next = bi->next; | |
459 | ||
460 | if (bi->type == ZEBRA_ROUTE_BGP && bi->sub_type == BGP_ROUTE_NORMAL) | |
461 | { | |
462 | changed = 0; | |
463 | metricchanged = 0; | |
464 | ||
465 | if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) | |
5932020b | 466 | valid = bgp_nexthop_check_ebgp (afi, bi->attr); |
718e3744 | 467 | else |
5932020b | 468 | valid = bgp_nexthop_lookup (afi, bi->peer, bi, |
718e3744 | 469 | &changed, &metricchanged); |
470 | ||
471 | current = CHECK_FLAG (bi->flags, BGP_INFO_VALID) ? 1 : 0; | |
472 | ||
473 | if (changed) | |
474 | SET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); | |
475 | else | |
476 | UNSET_FLAG (bi->flags, BGP_INFO_IGP_CHANGED); | |
477 | ||
478 | if (valid != current) | |
479 | { | |
480 | if (CHECK_FLAG (bi->flags, BGP_INFO_VALID)) | |
481 | { | |
482 | bgp_aggregate_decrement (bgp, &rn->p, bi, | |
5932020b | 483 | afi, SAFI_UNICAST); |
718e3744 | 484 | UNSET_FLAG (bi->flags, BGP_INFO_VALID); |
485 | } | |
486 | else | |
487 | { | |
488 | SET_FLAG (bi->flags, BGP_INFO_VALID); | |
489 | bgp_aggregate_increment (bgp, &rn->p, bi, | |
5932020b | 490 | afi, SAFI_UNICAST); |
718e3744 | 491 | } |
492 | } | |
493 | ||
5932020b | 494 | if (CHECK_FLAG (bgp->af_flags[afi][SAFI_UNICAST], |
718e3744 | 495 | BGP_CONFIG_DAMPENING) |
496 | && bi->damp_info ) | |
5932020b | 497 | if (bgp_damp_scan (bi, afi, SAFI_UNICAST)) |
718e3744 | 498 | bgp_aggregate_increment (bgp, &rn->p, bi, |
5932020b | 499 | afi, SAFI_UNICAST); |
718e3744 | 500 | } |
501 | } | |
5932020b | 502 | bgp_process (bgp, rn, afi, SAFI_UNICAST); |
718e3744 | 503 | } |
504 | ||
505 | /* Flash old cache. */ | |
5932020b | 506 | if (bgp_nexthop_cache_table[afi] == cache1_table[afi]) |
507 | bgp_nexthop_cache_reset (cache2_table[afi]); | |
718e3744 | 508 | else |
5932020b | 509 | bgp_nexthop_cache_reset (cache1_table[afi]); |
f418446b | 510 | |
511 | if (BGP_DEBUG (events, EVENTS)) | |
512 | { | |
513 | if (afi == AFI_IP) | |
514 | zlog_debug ("scanning IPv4 Unicast routing tables"); | |
515 | else if (afi == AFI_IP6) | |
516 | zlog_debug ("scanning IPv6 Unicast routing tables"); | |
517 | } | |
718e3744 | 518 | } |
718e3744 | 519 | |
520 | /* BGP scan thread. This thread check nexthop reachability. */ | |
521 | int | |
5932020b | 522 | bgp_scan_timer (struct thread *t) |
718e3744 | 523 | { |
524 | bgp_scan_thread = | |
5932020b | 525 | thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); |
718e3744 | 526 | |
f418446b | 527 | if (BGP_DEBUG (events, EVENTS)) |
478ba054 | 528 | zlog_debug ("Performing BGP general scanning"); |
718e3744 | 529 | |
5932020b | 530 | bgp_scan (AFI_IP, SAFI_UNICAST); |
718e3744 | 531 | |
532 | #ifdef HAVE_IPV6 | |
5932020b | 533 | bgp_scan (AFI_IP6, SAFI_UNICAST); |
718e3744 | 534 | #endif /* HAVE_IPV6 */ |
535 | ||
536 | return 0; | |
537 | } | |
538 | \f | |
5932020b | 539 | struct bgp_connected_ref |
718e3744 | 540 | { |
541 | unsigned int refcnt; | |
542 | }; | |
543 | ||
544 | void | |
545 | bgp_connected_add (struct connected *ifc) | |
546 | { | |
547 | struct prefix p; | |
548 | struct prefix *addr; | |
549 | struct prefix *dest; | |
550 | struct interface *ifp; | |
551 | struct bgp_node *rn; | |
5932020b | 552 | struct bgp_connected_ref *bc; |
718e3744 | 553 | |
554 | ifp = ifc->ifp; | |
555 | ||
556 | if (! ifp) | |
557 | return; | |
558 | ||
559 | if (if_is_loopback (ifp)) | |
560 | return; | |
561 | ||
562 | addr = ifc->address; | |
563 | dest = ifc->destination; | |
564 | ||
565 | if (addr->family == AF_INET) | |
566 | { | |
567 | memset (&p, 0, sizeof (struct prefix)); | |
568 | p.family = AF_INET; | |
569 | p.prefixlen = addr->prefixlen; | |
570 | ||
3fb9cd6e | 571 | if (CONNECTED_POINTOPOINT_HOST(ifc)) |
718e3744 | 572 | p.u.prefix4 = dest->u.prefix4; |
573 | else | |
574 | p.u.prefix4 = addr->u.prefix4; | |
575 | ||
576 | apply_mask_ipv4 ((struct prefix_ipv4 *) &p); | |
577 | ||
578 | if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) | |
579 | return; | |
580 | ||
5932020b | 581 | rn = bgp_node_get (bgp_connected_table[AFI_IP], (struct prefix *) &p); |
718e3744 | 582 | if (rn->info) |
583 | { | |
584 | bc = rn->info; | |
585 | bc->refcnt++; | |
586 | } | |
587 | else | |
588 | { | |
5932020b | 589 | bc = XMALLOC (0, sizeof (struct bgp_connected_ref)); |
590 | memset (bc, 0, sizeof (struct bgp_connected_ref)); | |
718e3744 | 591 | bc->refcnt = 1; |
592 | rn->info = bc; | |
593 | } | |
594 | } | |
595 | #ifdef HAVE_IPV6 | |
596 | if (addr->family == AF_INET6) | |
597 | { | |
598 | memset (&p, 0, sizeof (struct prefix)); | |
599 | p.family = AF_INET6; | |
600 | p.prefixlen = addr->prefixlen; | |
601 | ||
3fb9cd6e | 602 | if (if_is_pointopoint (ifp) && dest) |
718e3744 | 603 | p.u.prefix6 = dest->u.prefix6; |
604 | else | |
605 | p.u.prefix6 = addr->u.prefix6; | |
606 | ||
607 | apply_mask_ipv6 ((struct prefix_ipv6 *) &p); | |
608 | ||
609 | if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) | |
610 | return; | |
611 | ||
612 | if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) | |
613 | return; | |
614 | ||
5932020b | 615 | rn = bgp_node_get (bgp_connected_table[AFI_IP6], (struct prefix *) &p); |
718e3744 | 616 | if (rn->info) |
617 | { | |
618 | bc = rn->info; | |
619 | bc->refcnt++; | |
620 | } | |
621 | else | |
622 | { | |
5932020b | 623 | bc = XMALLOC (0, sizeof (struct bgp_connected_ref)); |
624 | memset (bc, 0, sizeof (struct bgp_connected_ref)); | |
718e3744 | 625 | bc->refcnt = 1; |
626 | rn->info = bc; | |
627 | } | |
628 | } | |
629 | #endif /* HAVE_IPV6 */ | |
630 | } | |
631 | ||
632 | void | |
633 | bgp_connected_delete (struct connected *ifc) | |
634 | { | |
635 | struct prefix p; | |
636 | struct prefix *addr; | |
637 | struct prefix *dest; | |
638 | struct interface *ifp; | |
639 | struct bgp_node *rn; | |
5932020b | 640 | struct bgp_connected_ref *bc; |
718e3744 | 641 | |
642 | ifp = ifc->ifp; | |
643 | ||
644 | if (if_is_loopback (ifp)) | |
645 | return; | |
646 | ||
647 | addr = ifc->address; | |
648 | dest = ifc->destination; | |
649 | ||
650 | if (addr->family == AF_INET) | |
651 | { | |
652 | memset (&p, 0, sizeof (struct prefix)); | |
653 | p.family = AF_INET; | |
654 | p.prefixlen = addr->prefixlen; | |
655 | ||
3fb9cd6e | 656 | if (CONNECTED_POINTOPOINT_HOST(ifc)) |
718e3744 | 657 | p.u.prefix4 = dest->u.prefix4; |
658 | else | |
659 | p.u.prefix4 = addr->u.prefix4; | |
660 | ||
661 | apply_mask_ipv4 ((struct prefix_ipv4 *) &p); | |
662 | ||
663 | if (prefix_ipv4_any ((struct prefix_ipv4 *) &p)) | |
664 | return; | |
665 | ||
5932020b | 666 | rn = bgp_node_lookup (bgp_connected_table[AFI_IP], &p); |
718e3744 | 667 | if (! rn) |
668 | return; | |
669 | ||
670 | bc = rn->info; | |
671 | bc->refcnt--; | |
672 | if (bc->refcnt == 0) | |
673 | { | |
674 | XFREE (0, bc); | |
675 | rn->info = NULL; | |
676 | } | |
677 | bgp_unlock_node (rn); | |
678 | bgp_unlock_node (rn); | |
679 | } | |
680 | #ifdef HAVE_IPV6 | |
681 | else if (addr->family == AF_INET6) | |
682 | { | |
683 | memset (&p, 0, sizeof (struct prefix)); | |
684 | p.family = AF_INET6; | |
685 | p.prefixlen = addr->prefixlen; | |
686 | ||
3fb9cd6e | 687 | if (if_is_pointopoint (ifp) && dest) |
718e3744 | 688 | p.u.prefix6 = dest->u.prefix6; |
689 | else | |
690 | p.u.prefix6 = addr->u.prefix6; | |
691 | ||
692 | apply_mask_ipv6 ((struct prefix_ipv6 *) &p); | |
693 | ||
694 | if (IN6_IS_ADDR_UNSPECIFIED (&p.u.prefix6)) | |
695 | return; | |
696 | ||
697 | if (IN6_IS_ADDR_LINKLOCAL (&p.u.prefix6)) | |
698 | return; | |
699 | ||
5932020b | 700 | rn = bgp_node_lookup (bgp_connected_table[AFI_IP6], (struct prefix *) &p); |
718e3744 | 701 | if (! rn) |
702 | return; | |
703 | ||
704 | bc = rn->info; | |
705 | bc->refcnt--; | |
706 | if (bc->refcnt == 0) | |
707 | { | |
708 | XFREE (0, bc); | |
709 | rn->info = NULL; | |
710 | } | |
711 | bgp_unlock_node (rn); | |
712 | bgp_unlock_node (rn); | |
713 | } | |
714 | #endif /* HAVE_IPV6 */ | |
715 | } | |
716 | ||
717 | int | |
718 | bgp_nexthop_self (afi_t afi, struct attr *attr) | |
719 | { | |
52dc7ee6 | 720 | struct listnode *node; |
721 | struct listnode *node2; | |
718e3744 | 722 | struct interface *ifp; |
723 | struct connected *ifc; | |
724 | struct prefix *p; | |
725 | ||
1eb8ef25 | 726 | for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) |
718e3744 | 727 | { |
1eb8ef25 | 728 | for (ALL_LIST_ELEMENTS_RO (ifp->connected, node2, ifc)) |
718e3744 | 729 | { |
718e3744 | 730 | p = ifc->address; |
731 | ||
732 | if (p && p->family == AF_INET | |
733 | && IPV4_ADDR_SAME (&p->u.prefix4, &attr->nexthop)) | |
734 | return 1; | |
735 | } | |
736 | } | |
737 | return 0; | |
738 | } | |
739 | \f | |
740 | struct bgp_nexthop_cache * | |
741 | zlookup_read () | |
742 | { | |
743 | struct stream *s; | |
744 | u_int16_t length; | |
745 | u_char command; | |
746 | int nbytes; | |
747 | struct in_addr raddr; | |
748 | u_int32_t metric; | |
749 | int i; | |
750 | u_char nexthop_num; | |
751 | struct nexthop *nexthop; | |
752 | struct bgp_nexthop_cache *bnc; | |
753 | ||
754 | s = zlookup->ibuf; | |
755 | stream_reset (s); | |
756 | ||
757 | nbytes = stream_read (s, zlookup->sock, 2); | |
758 | length = stream_getw (s); | |
759 | ||
760 | nbytes = stream_read (s, zlookup->sock, length - 2); | |
761 | command = stream_getc (s); | |
762 | raddr.s_addr = stream_get_ipv4 (s); | |
763 | metric = stream_getl (s); | |
764 | nexthop_num = stream_getc (s); | |
765 | ||
766 | if (nexthop_num) | |
767 | { | |
768 | bnc = bnc_new (); | |
769 | bnc->valid = 1; | |
770 | bnc->metric = metric; | |
771 | bnc->nexthop_num = nexthop_num; | |
772 | ||
773 | for (i = 0; i < nexthop_num; i++) | |
774 | { | |
775 | nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); | |
776 | memset (nexthop, 0, sizeof (struct nexthop)); | |
777 | nexthop->type = stream_getc (s); | |
778 | switch (nexthop->type) | |
779 | { | |
780 | case ZEBRA_NEXTHOP_IPV4: | |
781 | nexthop->gate.ipv4.s_addr = stream_get_ipv4 (s); | |
782 | break; | |
783 | case ZEBRA_NEXTHOP_IFINDEX: | |
784 | case ZEBRA_NEXTHOP_IFNAME: | |
785 | nexthop->ifindex = stream_getl (s); | |
786 | break; | |
fa2b17e3 | 787 | default: |
788 | /* do nothing */ | |
789 | break; | |
718e3744 | 790 | } |
791 | bnc_nexthop_add (bnc, nexthop); | |
792 | } | |
793 | } | |
794 | else | |
795 | return NULL; | |
796 | ||
797 | return bnc; | |
798 | } | |
799 | ||
800 | struct bgp_nexthop_cache * | |
801 | zlookup_query (struct in_addr addr) | |
802 | { | |
803 | int ret; | |
804 | struct stream *s; | |
805 | ||
806 | /* Check socket. */ | |
807 | if (zlookup->sock < 0) | |
808 | return NULL; | |
809 | ||
810 | s = zlookup->obuf; | |
811 | stream_reset (s); | |
812 | stream_putw (s, 7); | |
813 | stream_putc (s, ZEBRA_IPV4_NEXTHOP_LOOKUP); | |
814 | stream_put_in_addr (s, &addr); | |
815 | ||
816 | ret = writen (zlookup->sock, s->data, 7); | |
817 | if (ret < 0) | |
818 | { | |
819 | zlog_err ("can't write to zlookup->sock"); | |
820 | close (zlookup->sock); | |
821 | zlookup->sock = -1; | |
822 | return NULL; | |
823 | } | |
824 | if (ret == 0) | |
825 | { | |
826 | zlog_err ("zlookup->sock connection closed"); | |
827 | close (zlookup->sock); | |
828 | zlookup->sock = -1; | |
829 | return NULL; | |
830 | } | |
831 | ||
832 | return zlookup_read (); | |
833 | } | |
834 | ||
835 | #ifdef HAVE_IPV6 | |
836 | struct bgp_nexthop_cache * | |
837 | zlookup_read_ipv6 () | |
838 | { | |
839 | struct stream *s; | |
840 | u_int16_t length; | |
841 | u_char command; | |
842 | int nbytes; | |
843 | struct in6_addr raddr; | |
844 | u_int32_t metric; | |
845 | int i; | |
846 | u_char nexthop_num; | |
847 | struct nexthop *nexthop; | |
848 | struct bgp_nexthop_cache *bnc; | |
849 | ||
850 | s = zlookup->ibuf; | |
851 | stream_reset (s); | |
852 | ||
853 | nbytes = stream_read (s, zlookup->sock, 2); | |
854 | length = stream_getw (s); | |
855 | ||
856 | nbytes = stream_read (s, zlookup->sock, length - 2); | |
857 | command = stream_getc (s); | |
858 | ||
859 | stream_get (&raddr, s, 16); | |
860 | ||
861 | metric = stream_getl (s); | |
862 | nexthop_num = stream_getc (s); | |
863 | ||
864 | if (nexthop_num) | |
865 | { | |
866 | bnc = bnc_new (); | |
867 | bnc->valid = 1; | |
868 | bnc->metric = metric; | |
869 | bnc->nexthop_num = nexthop_num; | |
870 | ||
871 | for (i = 0; i < nexthop_num; i++) | |
872 | { | |
873 | nexthop = XMALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); | |
874 | memset (nexthop, 0, sizeof (struct nexthop)); | |
875 | nexthop->type = stream_getc (s); | |
876 | switch (nexthop->type) | |
877 | { | |
878 | case ZEBRA_NEXTHOP_IPV6: | |
879 | stream_get (&nexthop->gate.ipv6, s, 16); | |
880 | break; | |
881 | case ZEBRA_NEXTHOP_IPV6_IFINDEX: | |
882 | case ZEBRA_NEXTHOP_IPV6_IFNAME: | |
883 | stream_get (&nexthop->gate.ipv6, s, 16); | |
884 | nexthop->ifindex = stream_getl (s); | |
885 | break; | |
886 | case ZEBRA_NEXTHOP_IFINDEX: | |
887 | case ZEBRA_NEXTHOP_IFNAME: | |
888 | nexthop->ifindex = stream_getl (s); | |
889 | break; | |
fa2b17e3 | 890 | default: |
891 | /* do nothing */ | |
892 | break; | |
718e3744 | 893 | } |
894 | bnc_nexthop_add (bnc, nexthop); | |
895 | } | |
896 | } | |
897 | else | |
898 | return NULL; | |
899 | ||
900 | return bnc; | |
901 | } | |
902 | ||
903 | struct bgp_nexthop_cache * | |
904 | zlookup_query_ipv6 (struct in6_addr *addr) | |
905 | { | |
906 | int ret; | |
907 | struct stream *s; | |
908 | ||
909 | /* Check socket. */ | |
910 | if (zlookup->sock < 0) | |
911 | return NULL; | |
912 | ||
913 | s = zlookup->obuf; | |
914 | stream_reset (s); | |
915 | stream_putw (s, 19); | |
916 | stream_putc (s, ZEBRA_IPV6_NEXTHOP_LOOKUP); | |
917 | stream_put (s, addr, 16); | |
918 | ||
919 | ret = writen (zlookup->sock, s->data, 19); | |
920 | if (ret < 0) | |
921 | { | |
922 | zlog_err ("can't write to zlookup->sock"); | |
923 | close (zlookup->sock); | |
924 | zlookup->sock = -1; | |
925 | return NULL; | |
926 | } | |
927 | if (ret == 0) | |
928 | { | |
929 | zlog_err ("zlookup->sock connection closed"); | |
930 | close (zlookup->sock); | |
931 | zlookup->sock = -1; | |
932 | return NULL; | |
933 | } | |
934 | ||
935 | return zlookup_read_ipv6 (); | |
936 | } | |
937 | #endif /* HAVE_IPV6 */ | |
938 | ||
939 | int | |
940 | bgp_import_check (struct prefix *p, u_int32_t *igpmetric, struct in_addr *igpnexthop) | |
941 | { | |
942 | struct stream *s; | |
943 | int ret; | |
944 | u_int16_t length; | |
945 | u_char command; | |
946 | int nbytes; | |
947 | struct in_addr addr; | |
948 | struct in_addr nexthop; | |
949 | u_int32_t metric = 0; | |
950 | u_char nexthop_num; | |
951 | u_char nexthop_type; | |
952 | ||
953 | /* If lookup connection is not available return valid. */ | |
954 | if (zlookup->sock < 0) | |
955 | { | |
956 | if (igpmetric) | |
957 | *igpmetric = 0; | |
958 | return 1; | |
959 | } | |
960 | ||
961 | /* Send query to the lookup connection */ | |
962 | s = zlookup->obuf; | |
963 | stream_reset (s); | |
964 | stream_putw (s, 8); | |
965 | stream_putc (s, ZEBRA_IPV4_IMPORT_LOOKUP); | |
966 | stream_putc (s, p->prefixlen); | |
967 | stream_put_in_addr (s, &p->u.prefix4); | |
968 | ||
969 | /* Write the packet. */ | |
970 | ret = writen (zlookup->sock, s->data, 8); | |
971 | ||
972 | if (ret < 0) | |
973 | { | |
974 | zlog_err ("can't write to zlookup->sock"); | |
975 | close (zlookup->sock); | |
976 | zlookup->sock = -1; | |
977 | return 1; | |
978 | } | |
979 | if (ret == 0) | |
980 | { | |
981 | zlog_err ("zlookup->sock connection closed"); | |
982 | close (zlookup->sock); | |
983 | zlookup->sock = -1; | |
984 | return 1; | |
985 | } | |
986 | ||
987 | /* Get result. */ | |
988 | stream_reset (s); | |
989 | ||
990 | /* Fetch length. */ | |
991 | nbytes = stream_read (s, zlookup->sock, 2); | |
992 | length = stream_getw (s); | |
993 | ||
994 | /* Fetch whole data. */ | |
995 | nbytes = stream_read (s, zlookup->sock, length - 2); | |
996 | command = stream_getc (s); | |
997 | addr.s_addr = stream_get_ipv4 (s); | |
998 | metric = stream_getl (s); | |
999 | nexthop_num = stream_getc (s); | |
1000 | ||
1001 | /* Set IGP metric value. */ | |
1002 | if (igpmetric) | |
1003 | *igpmetric = metric; | |
1004 | ||
1005 | /* If there is nexthop then this is active route. */ | |
1006 | if (nexthop_num) | |
1007 | { | |
1008 | nexthop.s_addr = 0; | |
1009 | nexthop_type = stream_getc (s); | |
1010 | if (nexthop_type == ZEBRA_NEXTHOP_IPV4) | |
1011 | { | |
1012 | nexthop.s_addr = stream_get_ipv4 (s); | |
1013 | if (igpnexthop) | |
1014 | *igpnexthop = nexthop; | |
1015 | } | |
1016 | else | |
1017 | *igpnexthop = nexthop; | |
1018 | ||
1019 | return 1; | |
1020 | } | |
1021 | else | |
1022 | return 0; | |
1023 | } | |
1024 | ||
1025 | /* Scan all configured BGP route then check the route exists in IGP or | |
1026 | not. */ | |
1027 | int | |
1028 | bgp_import (struct thread *t) | |
1029 | { | |
1030 | struct bgp *bgp; | |
1031 | struct bgp_node *rn; | |
1032 | struct bgp_static *bgp_static; | |
1eb8ef25 | 1033 | struct listnode *node, *nnode; |
718e3744 | 1034 | int valid; |
1035 | u_int32_t metric; | |
1036 | struct in_addr nexthop; | |
1037 | afi_t afi; | |
1038 | safi_t safi; | |
1039 | ||
1040 | bgp_import_thread = | |
1041 | thread_add_timer (master, bgp_import, NULL, bgp_import_interval); | |
1042 | ||
f418446b | 1043 | if (BGP_DEBUG (events, EVENTS)) |
1044 | zlog_debug ("Import timer expired."); | |
718e3744 | 1045 | |
1eb8ef25 | 1046 | for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp)) |
6cbbc3cc | 1047 | { |
1048 | for (afi = AFI_IP; afi < AFI_MAX; afi++) | |
1049 | for (safi = SAFI_UNICAST; safi < SAFI_MPLS_VPN; safi++) | |
1050 | for (rn = bgp_table_top (bgp->route[afi][safi]); rn; | |
1051 | rn = bgp_route_next (rn)) | |
1052 | if ((bgp_static = rn->info) != NULL) | |
718e3744 | 1053 | { |
6cbbc3cc | 1054 | if (bgp_static->backdoor) |
1055 | continue; | |
718e3744 | 1056 | |
6cbbc3cc | 1057 | valid = bgp_static->valid; |
1058 | metric = bgp_static->igpmetric; | |
1059 | nexthop = bgp_static->igpnexthop; | |
1060 | ||
1061 | if (bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) | |
1062 | && afi == AFI_IP && safi == SAFI_UNICAST) | |
1063 | bgp_static->valid = bgp_import_check (&rn->p, &bgp_static->igpmetric, | |
1064 | &bgp_static->igpnexthop); | |
718e3744 | 1065 | else |
6cbbc3cc | 1066 | { |
1067 | bgp_static->valid = 1; | |
1068 | bgp_static->igpmetric = 0; | |
1069 | bgp_static->igpnexthop.s_addr = 0; | |
1070 | } | |
1071 | ||
1072 | if (bgp_static->valid != valid) | |
1073 | { | |
1074 | if (bgp_static->valid) | |
1075 | bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); | |
1076 | else | |
1077 | bgp_static_withdraw (bgp, &rn->p, afi, safi); | |
1078 | } | |
1079 | else if (bgp_static->valid) | |
1080 | { | |
1081 | if (bgp_static->igpmetric != metric | |
1082 | || bgp_static->igpnexthop.s_addr != nexthop.s_addr | |
1083 | || bgp_static->rmap.name) | |
1084 | bgp_static_update (bgp, &rn->p, bgp_static, afi, safi); | |
1085 | } | |
718e3744 | 1086 | } |
6cbbc3cc | 1087 | } |
718e3744 | 1088 | return 0; |
1089 | } | |
1090 | ||
1091 | /* Connect to zebra for nexthop lookup. */ | |
1092 | int | |
1093 | zlookup_connect (struct thread *t) | |
1094 | { | |
1095 | struct zclient *zlookup; | |
1096 | ||
1097 | zlookup = THREAD_ARG (t); | |
1098 | zlookup->t_connect = NULL; | |
1099 | ||
1100 | if (zlookup->sock != -1) | |
1101 | return 0; | |
1102 | ||
1103 | #ifdef HAVE_TCP_ZEBRA | |
1104 | zlookup->sock = zclient_socket (); | |
1105 | #else | |
1106 | zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); | |
1107 | #endif /* HAVE_TCP_ZEBRA */ | |
1108 | if (zlookup->sock < 0) | |
1109 | return -1; | |
1110 | ||
718e3744 | 1111 | return 0; |
1112 | } | |
1113 | ||
1114 | /* Check specified multiaccess next-hop. */ | |
1115 | int | |
1116 | bgp_multiaccess_check_v4 (struct in_addr nexthop, char *peer) | |
1117 | { | |
1118 | struct bgp_node *rn1; | |
1119 | struct bgp_node *rn2; | |
1120 | struct prefix p1; | |
1121 | struct prefix p2; | |
1122 | struct in_addr addr; | |
1123 | int ret; | |
1124 | ||
1125 | ret = inet_aton (peer, &addr); | |
1126 | if (! ret) | |
1127 | return 0; | |
1128 | ||
1129 | memset (&p1, 0, sizeof (struct prefix)); | |
1130 | p1.family = AF_INET; | |
1131 | p1.prefixlen = IPV4_MAX_BITLEN; | |
1132 | p1.u.prefix4 = nexthop; | |
1133 | memset (&p2, 0, sizeof (struct prefix)); | |
1134 | p2.family = AF_INET; | |
1135 | p2.prefixlen = IPV4_MAX_BITLEN; | |
1136 | p2.u.prefix4 = addr; | |
1137 | ||
1138 | /* If bgp scan is not enabled, return invalid. */ | |
1139 | if (zlookup->sock < 0) | |
1140 | return 0; | |
1141 | ||
5932020b | 1142 | rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1); |
718e3744 | 1143 | if (! rn1) |
1144 | return 0; | |
1145 | ||
5932020b | 1146 | rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2); |
718e3744 | 1147 | if (! rn2) |
1148 | return 0; | |
1149 | ||
1150 | if (rn1 == rn2) | |
1151 | return 1; | |
1152 | ||
1153 | return 0; | |
1154 | } | |
1155 | \f | |
1156 | DEFUN (bgp_scan_time, | |
1157 | bgp_scan_time_cmd, | |
1158 | "bgp scan-time <5-60>", | |
1159 | "BGP specific commands\n" | |
1160 | "Configure background scanner interval\n" | |
1161 | "Scanner interval (seconds)\n") | |
1162 | { | |
1163 | bgp_scan_interval = atoi (argv[0]); | |
1164 | ||
1165 | if (bgp_scan_thread) | |
1166 | { | |
1167 | thread_cancel (bgp_scan_thread); | |
1168 | bgp_scan_thread = | |
5932020b | 1169 | thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); |
718e3744 | 1170 | } |
1171 | ||
1172 | return CMD_SUCCESS; | |
1173 | } | |
1174 | ||
1175 | DEFUN (no_bgp_scan_time, | |
1176 | no_bgp_scan_time_cmd, | |
1177 | "no bgp scan-time", | |
1178 | NO_STR | |
1179 | "BGP specific commands\n" | |
1180 | "Configure background scanner interval\n") | |
1181 | { | |
1182 | bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; | |
1183 | ||
1184 | if (bgp_scan_thread) | |
1185 | { | |
1186 | thread_cancel (bgp_scan_thread); | |
1187 | bgp_scan_thread = | |
5932020b | 1188 | thread_add_timer (master, bgp_scan_timer, NULL, bgp_scan_interval); |
718e3744 | 1189 | } |
1190 | ||
1191 | return CMD_SUCCESS; | |
1192 | } | |
1193 | ||
1194 | ALIAS (no_bgp_scan_time, | |
1195 | no_bgp_scan_time_val_cmd, | |
1196 | "no bgp scan-time <5-60>", | |
1197 | NO_STR | |
1198 | "BGP specific commands\n" | |
1199 | "Configure background scanner interval\n" | |
1200 | "Scanner interval (seconds)\n") | |
1201 | ||
1202 | DEFUN (show_ip_bgp_scan, | |
1203 | show_ip_bgp_scan_cmd, | |
1204 | "show ip bgp scan", | |
1205 | SHOW_STR | |
1206 | IP_STR | |
1207 | BGP_STR | |
1208 | "BGP scan status\n") | |
1209 | { | |
1210 | struct bgp_node *rn; | |
1211 | struct bgp_nexthop_cache *bnc; | |
1212 | ||
1213 | if (bgp_scan_thread) | |
1214 | vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); | |
1215 | else | |
1216 | vty_out (vty, "BGP scan is not running%s", VTY_NEWLINE); | |
1217 | vty_out (vty, "BGP scan interval is %d%s", bgp_scan_interval, VTY_NEWLINE); | |
1218 | ||
1219 | vty_out (vty, "Current BGP nexthop cache:%s", VTY_NEWLINE); | |
5932020b | 1220 | for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP]); rn; rn = bgp_route_next (rn)) |
718e3744 | 1221 | if ((bnc = rn->info) != NULL) |
1222 | { | |
1223 | if (bnc->valid) | |
1224 | vty_out (vty, " %s valid [IGP metric %d]%s", | |
1225 | inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE); | |
1226 | else | |
1227 | vty_out (vty, " %s invalid%s", | |
1228 | inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE); | |
1229 | } | |
1230 | ||
1231 | #ifdef HAVE_IPV6 | |
1232 | { | |
1233 | char buf[BUFSIZ]; | |
5932020b | 1234 | for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]); |
1235 | rn; | |
1236 | rn = bgp_route_next (rn)) | |
718e3744 | 1237 | if ((bnc = rn->info) != NULL) |
1238 | { | |
1239 | if (bnc->valid) | |
1240 | vty_out (vty, " %s valid [IGP metric %d]%s", | |
1241 | inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), | |
1242 | bnc->metric, VTY_NEWLINE); | |
1243 | else | |
1244 | vty_out (vty, " %s invalid%s", | |
1245 | inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), | |
1246 | VTY_NEWLINE); | |
1247 | } | |
1248 | } | |
1249 | #endif /* HAVE_IPV6 */ | |
1250 | ||
1251 | vty_out (vty, "BGP connected route:%s", VTY_NEWLINE); | |
5932020b | 1252 | for (rn = bgp_table_top (bgp_connected_table[AFI_IP]); |
1253 | rn; | |
1254 | rn = bgp_route_next (rn)) | |
718e3744 | 1255 | if (rn->info != NULL) |
1256 | vty_out (vty, " %s/%d%s", inet_ntoa (rn->p.u.prefix4), rn->p.prefixlen, | |
1257 | VTY_NEWLINE); | |
1258 | ||
1259 | #ifdef HAVE_IPV6 | |
1260 | { | |
1261 | char buf[BUFSIZ]; | |
1262 | ||
5932020b | 1263 | for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]); |
1264 | rn; | |
1265 | rn = bgp_route_next (rn)) | |
718e3744 | 1266 | if (rn->info != NULL) |
1267 | vty_out (vty, " %s/%d%s", | |
1268 | inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), | |
1269 | rn->p.prefixlen, | |
1270 | VTY_NEWLINE); | |
1271 | } | |
1272 | #endif /* HAVE_IPV6 */ | |
1273 | ||
1274 | return CMD_SUCCESS; | |
1275 | } | |
1276 | ||
1277 | int | |
1278 | bgp_config_write_scan_time (struct vty *vty) | |
1279 | { | |
1280 | if (bgp_scan_interval != BGP_SCAN_INTERVAL_DEFAULT) | |
1281 | vty_out (vty, " bgp scan-time %d%s", bgp_scan_interval, VTY_NEWLINE); | |
1282 | return CMD_SUCCESS; | |
1283 | } | |
1284 | ||
1285 | void | |
1286 | bgp_scan_init () | |
1287 | { | |
1288 | zlookup = zclient_new (); | |
1289 | zlookup->sock = -1; | |
1290 | zlookup->ibuf = stream_new (ZEBRA_MAX_PACKET_SIZ); | |
1291 | zlookup->obuf = stream_new (ZEBRA_MAX_PACKET_SIZ); | |
1292 | zlookup->t_connect = thread_add_event (master, zlookup_connect, zlookup, 0); | |
1293 | ||
1294 | bgp_scan_interval = BGP_SCAN_INTERVAL_DEFAULT; | |
1295 | bgp_import_interval = BGP_IMPORT_INTERVAL_DEFAULT; | |
1296 | ||
5932020b | 1297 | cache1_table[AFI_IP] = bgp_table_init (); |
1298 | cache2_table[AFI_IP] = bgp_table_init (); | |
1299 | bgp_nexthop_cache_table[AFI_IP] = cache1_table[AFI_IP]; | |
718e3744 | 1300 | |
5932020b | 1301 | bgp_connected_table[AFI_IP] = bgp_table_init (); |
718e3744 | 1302 | |
1303 | #ifdef HAVE_IPV6 | |
5932020b | 1304 | cache1_table[AFI_IP6] = bgp_table_init (); |
1305 | cache2_table[AFI_IP6] = bgp_table_init (); | |
1306 | bgp_nexthop_cache_table[AFI_IP6] = cache1_table[AFI_IP6]; | |
1307 | bgp_connected_table[AFI_IP6] = bgp_table_init (); | |
718e3744 | 1308 | #endif /* HAVE_IPV6 */ |
1309 | ||
1310 | /* Make BGP scan thread. */ | |
5932020b | 1311 | bgp_scan_thread = thread_add_timer (master, bgp_scan_timer, |
1312 | NULL, bgp_scan_interval); | |
6cbbc3cc | 1313 | /* Make BGP import there. */ |
1314 | bgp_import_thread = thread_add_timer (master, bgp_import, NULL, 0); | |
718e3744 | 1315 | |
1316 | install_element (BGP_NODE, &bgp_scan_time_cmd); | |
1317 | install_element (BGP_NODE, &no_bgp_scan_time_cmd); | |
1318 | install_element (BGP_NODE, &no_bgp_scan_time_val_cmd); | |
1319 | install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); | |
1320 | install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); | |
1321 | } |