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