Annotation of embedaddon/quagga/bgpd/bgp_zebra.c, revision 1.1.1.4

1.1       misho       1: /* zebra client
                      2:    Copyright (C) 1997, 98, 99 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
                     18: Free Software Foundation, Inc., 59 Temple Place - Suite 330,
                     19: Boston, MA 02111-1307, USA.  */
                     20: 
                     21: #include <zebra.h>
                     22: 
                     23: #include "command.h"
                     24: #include "stream.h"
                     25: #include "network.h"
                     26: #include "prefix.h"
                     27: #include "log.h"
                     28: #include "sockunion.h"
                     29: #include "zclient.h"
                     30: #include "routemap.h"
                     31: #include "thread.h"
1.1.1.4 ! misho      32: #include "filter.h"
1.1       misho      33: 
                     34: #include "bgpd/bgpd.h"
                     35: #include "bgpd/bgp_route.h"
                     36: #include "bgpd/bgp_attr.h"
                     37: #include "bgpd/bgp_nexthop.h"
                     38: #include "bgpd/bgp_zebra.h"
                     39: #include "bgpd/bgp_fsm.h"
                     40: #include "bgpd/bgp_debug.h"
1.1.1.2   misho      41: #include "bgpd/bgp_mpath.h"
1.1.1.4 ! misho      42: 
1.1       misho      43: /* All information about zebra. */
                     44: struct zclient *zclient = NULL;
                     45: struct in_addr router_id_zebra;
                     46: 
1.1.1.2   misho      47: /* Growable buffer for nexthops sent to zebra */
                     48: struct stream *bgp_nexthop_buf = NULL;
                     49: 
1.1       misho      50: /* Router-id update message from zebra. */
                     51: static int
1.1.1.4 ! misho      52: bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
        !            53:     vrf_id_t vrf_id)
1.1       misho      54: {
                     55:   struct prefix router_id;
                     56:   struct listnode *node, *nnode;
                     57:   struct bgp *bgp;
                     58: 
                     59:   zebra_router_id_update_read(zclient->ibuf,&router_id);
                     60: 
                     61:   if (BGP_DEBUG(zebra, ZEBRA))
                     62:     {
                     63:       char buf[128];
                     64:       prefix2str(&router_id, buf, sizeof(buf));
                     65:       zlog_debug("Zebra rcvd: router id update %s", buf);
                     66:     }
                     67: 
                     68:   router_id_zebra = router_id.u.prefix4;
                     69: 
                     70:   for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
                     71:     {
                     72:       if (!bgp->router_id_static.s_addr)
                     73:         bgp_router_id_set (bgp, &router_id.u.prefix4);
                     74:     }
                     75: 
                     76:   return 0;
                     77: }
                     78: 
                     79: /* Inteface addition message from zebra. */
                     80: static int
1.1.1.4 ! misho      81: bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
        !            82:     vrf_id_t vrf_id)
1.1       misho      83: {
                     84:   struct interface *ifp;
                     85: 
1.1.1.4 ! misho      86:   ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
1.1       misho      87: 
                     88:   if (BGP_DEBUG(zebra, ZEBRA) && ifp)
                     89:     zlog_debug("Zebra rcvd: interface add %s", ifp->name);
                     90: 
                     91:   return 0;
                     92: }
                     93: 
                     94: static int
                     95: bgp_interface_delete (int command, struct zclient *zclient,
1.1.1.4 ! misho      96:                      zebra_size_t length, vrf_id_t vrf_id)
1.1       misho      97: {
                     98:   struct stream *s;
                     99:   struct interface *ifp;
                    100: 
                    101:   s = zclient->ibuf;
1.1.1.4 ! misho     102:   ifp = zebra_interface_state_read (s, vrf_id);
1.1       misho     103:   ifp->ifindex = IFINDEX_INTERNAL;
                    104: 
                    105:   if (BGP_DEBUG(zebra, ZEBRA))
                    106:     zlog_debug("Zebra rcvd: interface delete %s", ifp->name);
                    107: 
                    108:   return 0;
                    109: }
                    110: 
                    111: static int
1.1.1.4 ! misho     112: bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
        !           113:     vrf_id_t vrf_id)
1.1       misho     114: {
                    115:   struct stream *s;
                    116:   struct interface *ifp;
                    117:   struct connected *c;
                    118:   struct listnode *node, *nnode;
                    119: 
                    120:   s = zclient->ibuf;
1.1.1.4 ! misho     121:   ifp = zebra_interface_state_read (s, vrf_id);
1.1       misho     122: 
                    123:   if (! ifp)
                    124:     return 0;
                    125: 
                    126:   if (BGP_DEBUG(zebra, ZEBRA))
                    127:     zlog_debug("Zebra rcvd: interface %s up", ifp->name);
                    128: 
                    129:   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
                    130:     bgp_connected_add (c);
                    131: 
                    132:   return 0;
                    133: }
                    134: 
                    135: static int
1.1.1.4 ! misho     136: bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
        !           137:     vrf_id_t vrf_id)
1.1       misho     138: {
                    139:   struct stream *s;
                    140:   struct interface *ifp;
                    141:   struct connected *c;
                    142:   struct listnode *node, *nnode;
                    143: 
                    144:   s = zclient->ibuf;
1.1.1.4 ! misho     145:   ifp = zebra_interface_state_read (s, vrf_id);
1.1       misho     146:   if (! ifp)
                    147:     return 0;
                    148: 
                    149:   if (BGP_DEBUG(zebra, ZEBRA))
                    150:     zlog_debug("Zebra rcvd: interface %s down", ifp->name);
                    151: 
                    152:   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
                    153:     bgp_connected_delete (c);
                    154: 
1.1.1.4 ! misho     155:   /* Fast external-failover */
1.1       misho     156:   {
                    157:     struct listnode *mnode;
                    158:     struct bgp *bgp;
                    159:     struct peer *peer;
                    160: 
                    161:     for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
                    162:       {
                    163:        if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
                    164:          continue;
                    165: 
                    166:        for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
                    167:          {
1.1.1.4 ! misho     168:            if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
1.1       misho     169:              continue;
                    170: 
1.1.1.4 ! misho     171:            if (ifp == peer->nexthop.ifp)
1.1       misho     172:              BGP_EVENT_ADD (peer, BGP_Stop);
                    173:          }
                    174:       }
                    175:   }
                    176: 
                    177:   return 0;
                    178: }
                    179: 
                    180: static int
                    181: bgp_interface_address_add (int command, struct zclient *zclient,
1.1.1.4 ! misho     182:                           zebra_size_t length, vrf_id_t vrf_id)
1.1       misho     183: {
                    184:   struct connected *ifc;
                    185: 
1.1.1.4 ! misho     186:   ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
1.1       misho     187: 
                    188:   if (ifc == NULL)
                    189:     return 0;
                    190: 
                    191:   if (BGP_DEBUG(zebra, ZEBRA))
                    192:     {
                    193:       char buf[128];
                    194:       prefix2str(ifc->address, buf, sizeof(buf));
                    195:       zlog_debug("Zebra rcvd: interface %s address add %s",
                    196:                 ifc->ifp->name, buf);
                    197:     }
                    198: 
                    199:   if (if_is_operative (ifc->ifp))
                    200:     bgp_connected_add (ifc);
                    201: 
                    202:   return 0;
                    203: }
                    204: 
                    205: static int
                    206: bgp_interface_address_delete (int command, struct zclient *zclient,
1.1.1.4 ! misho     207:                              zebra_size_t length, vrf_id_t vrf_id)
1.1       misho     208: {
                    209:   struct connected *ifc;
                    210: 
1.1.1.4 ! misho     211:   ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
1.1       misho     212: 
                    213:   if (ifc == NULL)
                    214:     return 0;
                    215: 
                    216:   if (BGP_DEBUG(zebra, ZEBRA))
                    217:     {
                    218:       char buf[128];
                    219:       prefix2str(ifc->address, buf, sizeof(buf));
                    220:       zlog_debug("Zebra rcvd: interface %s address delete %s",
                    221:                 ifc->ifp->name, buf);
                    222:     }
                    223: 
                    224:   if (if_is_operative (ifc->ifp))
                    225:     bgp_connected_delete (ifc);
                    226: 
                    227:   connected_free (ifc);
                    228: 
                    229:   return 0;
                    230: }
                    231: 
                    232: /* Zebra route add and delete treatment. */
                    233: static int
1.1.1.4 ! misho     234: zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
        !           235:     vrf_id_t vrf_id)
1.1       misho     236: {
                    237:   struct stream *s;
                    238:   struct zapi_ipv4 api;
                    239:   struct in_addr nexthop;
                    240:   struct prefix_ipv4 p;
1.1.1.4 ! misho     241:   unsigned char plength = 0;
1.1       misho     242: 
                    243:   s = zclient->ibuf;
                    244:   nexthop.s_addr = 0;
                    245: 
                    246:   /* Type, flags, message. */
                    247:   api.type = stream_getc (s);
                    248:   api.flags = stream_getc (s);
                    249:   api.message = stream_getc (s);
                    250: 
                    251:   /* IPv4 prefix. */
                    252:   memset (&p, 0, sizeof (struct prefix_ipv4));
                    253:   p.family = AF_INET;
1.1.1.4 ! misho     254:   plength = stream_getc (s);
        !           255:   p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, plength);
1.1       misho     256:   stream_get (&p.prefix, s, PSIZE (p.prefixlen));
                    257: 
                    258:   /* Nexthop, ifindex, distance, metric. */
                    259:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
                    260:     {
                    261:       api.nexthop_num = stream_getc (s);
                    262:       nexthop.s_addr = stream_get_ipv4 (s);
                    263:     }
                    264:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
                    265:     {
                    266:       api.ifindex_num = stream_getc (s);
1.1.1.2   misho     267:       stream_getl (s); /* ifindex, unused */
1.1       misho     268:     }
                    269:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
                    270:     api.distance = stream_getc (s);
                    271:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
                    272:     api.metric = stream_getl (s);
                    273:   else
                    274:     api.metric = 0;
                    275: 
                    276:   if (command == ZEBRA_IPV4_ROUTE_ADD)
                    277:     {
                    278:       if (BGP_DEBUG(zebra, ZEBRA))
                    279:        {
                    280:          char buf[2][INET_ADDRSTRLEN];
                    281:          zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u",
                    282:                     zebra_route_string(api.type),
                    283:                     inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
                    284:                     p.prefixlen,
                    285:                     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
                    286:                     api.metric);
                    287:        }
1.1.1.2   misho     288:       bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
                    289:                           api.metric, api.type);
1.1       misho     290:     }
                    291:   else
                    292:     {
                    293:       if (BGP_DEBUG(zebra, ZEBRA))
                    294:        {
                    295:          char buf[2][INET_ADDRSTRLEN];
                    296:          zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d "
                    297:                     "nexthop %s metric %u",
                    298:                     zebra_route_string(api.type),
                    299:                     inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
                    300:                     p.prefixlen,
                    301:                     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
                    302:                     api.metric);
                    303:        }
                    304:       bgp_redistribute_delete((struct prefix *)&p, api.type);
                    305:     }
                    306: 
                    307:   return 0;
                    308: }
                    309: 
                    310: /* Zebra route add and delete treatment. */
                    311: static int
1.1.1.4 ! misho     312: zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
        !           313:     vrf_id_t vrf_id)
1.1       misho     314: {
                    315:   struct stream *s;
                    316:   struct zapi_ipv6 api;
                    317:   struct in6_addr nexthop;
                    318:   struct prefix_ipv6 p;
1.1.1.4 ! misho     319:   unsigned char plength = 0;
1.1       misho     320: 
                    321:   s = zclient->ibuf;
                    322:   memset (&nexthop, 0, sizeof (struct in6_addr));
                    323: 
                    324:   /* Type, flags, message. */
                    325:   api.type = stream_getc (s);
                    326:   api.flags = stream_getc (s);
                    327:   api.message = stream_getc (s);
                    328: 
                    329:   /* IPv6 prefix. */
                    330:   memset (&p, 0, sizeof (struct prefix_ipv6));
                    331:   p.family = AF_INET6;
1.1.1.4 ! misho     332:   plength = stream_getc (s);
        !           333:   p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, plength);
1.1       misho     334:   stream_get (&p.prefix, s, PSIZE (p.prefixlen));
                    335: 
                    336:   /* Nexthop, ifindex, distance, metric. */
                    337:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
                    338:     {
                    339:       api.nexthop_num = stream_getc (s);
                    340:       stream_get (&nexthop, s, 16);
                    341:     }
                    342:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
                    343:     {
                    344:       api.ifindex_num = stream_getc (s);
1.1.1.2   misho     345:       stream_getl (s); /* ifindex, unused */
1.1       misho     346:     }
                    347:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
                    348:     api.distance = stream_getc (s);
                    349:   else
                    350:     api.distance = 0;
                    351:   if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
                    352:     api.metric = stream_getl (s);
                    353:   else
                    354:     api.metric = 0;
                    355: 
                    356:   /* Simply ignore link-local address. */
                    357:   if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
                    358:     return 0;
                    359: 
                    360:   if (command == ZEBRA_IPV6_ROUTE_ADD)
                    361:     {
                    362:       if (BGP_DEBUG(zebra, ZEBRA))
                    363:        {
1.1.1.2   misho     364:          char buf[2][INET6_ADDRSTRLEN];
                    365:          zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
1.1       misho     366:                     zebra_route_string(api.type),
1.1.1.2   misho     367:                     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
                    368:                     p.prefixlen,
                    369:                     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
                    370:                     api.metric);
1.1       misho     371:        }
1.1.1.2   misho     372:       bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
                    373:                            api.metric, api.type);
1.1       misho     374:     }
                    375:   else
                    376:     {
                    377:       if (BGP_DEBUG(zebra, ZEBRA))
                    378:        {
1.1.1.2   misho     379:          char buf[2][INET6_ADDRSTRLEN];
                    380:          zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
                    381:                     "nexthop %s metric %u",
1.1       misho     382:                     zebra_route_string(api.type),
1.1.1.2   misho     383:                     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
                    384:                     p.prefixlen,
                    385:                     inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
                    386:                     api.metric);
1.1       misho     387:        }
                    388:       bgp_redistribute_delete ((struct prefix *) &p, api.type);
                    389:     }
                    390:   
                    391:   return 0;
                    392: }
1.1.1.4 ! misho     393: 
1.1       misho     394: struct interface *
                    395: if_lookup_by_ipv4 (struct in_addr *addr)
                    396: {
                    397:   struct listnode *ifnode;
                    398:   struct listnode *cnode;
                    399:   struct interface *ifp;
                    400:   struct connected *connected;
                    401:   struct prefix_ipv4 p;
                    402:   struct prefix *cp; 
                    403:   
                    404:   p.family = AF_INET;
                    405:   p.prefix = *addr;
                    406:   p.prefixlen = IPV4_MAX_BITLEN;
                    407: 
                    408:   for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
                    409:     {
                    410:       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
                    411:        {
                    412:          cp = connected->address;
                    413:            
                    414:          if (cp->family == AF_INET)
                    415:            if (prefix_match (cp, (struct prefix *)&p))
                    416:              return ifp;
                    417:        }
                    418:     }
                    419:   return NULL;
                    420: }
                    421: 
                    422: struct interface *
                    423: if_lookup_by_ipv4_exact (struct in_addr *addr)
                    424: {
                    425:   struct listnode *ifnode;
                    426:   struct listnode *cnode;
                    427:   struct interface *ifp;
                    428:   struct connected *connected;
                    429:   struct prefix *cp; 
                    430:   
                    431:   for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
                    432:     {
                    433:       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
                    434:        {
                    435:          cp = connected->address;
                    436:            
                    437:          if (cp->family == AF_INET)
                    438:            if (IPV4_ADDR_SAME (&cp->u.prefix4, addr))
                    439:              return ifp;
                    440:        }
                    441:     }
                    442:   return NULL;
                    443: }
                    444: 
                    445: struct interface *
                    446: if_lookup_by_ipv6 (struct in6_addr *addr)
                    447: {
                    448:   struct listnode *ifnode;
                    449:   struct listnode *cnode;
                    450:   struct interface *ifp;
                    451:   struct connected *connected;
                    452:   struct prefix_ipv6 p;
                    453:   struct prefix *cp; 
                    454:   
                    455:   p.family = AF_INET6;
                    456:   p.prefix = *addr;
                    457:   p.prefixlen = IPV6_MAX_BITLEN;
                    458: 
                    459:   for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
                    460:     {
                    461:       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
                    462:        {
                    463:          cp = connected->address;
                    464:            
                    465:          if (cp->family == AF_INET6)
                    466:            if (prefix_match (cp, (struct prefix *)&p))
                    467:              return ifp;
                    468:        }
                    469:     }
                    470:   return NULL;
                    471: }
                    472: 
                    473: struct interface *
                    474: if_lookup_by_ipv6_exact (struct in6_addr *addr)
                    475: {
                    476:   struct listnode *ifnode;
                    477:   struct listnode *cnode;
                    478:   struct interface *ifp;
                    479:   struct connected *connected;
                    480:   struct prefix *cp; 
                    481: 
                    482:   for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
                    483:     {
                    484:       for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
                    485:        {
                    486:          cp = connected->address;
                    487:            
                    488:          if (cp->family == AF_INET6)
                    489:            if (IPV6_ADDR_SAME (&cp->u.prefix6, addr))
                    490:              return ifp;
                    491:        }
                    492:     }
                    493:   return NULL;
                    494: }
                    495: 
                    496: static int
                    497: if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr)
                    498: {
                    499:   struct listnode *cnode;
                    500:   struct connected *connected;
                    501:   struct prefix *cp; 
                    502:   
                    503:   for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
                    504:     {
                    505:       cp = connected->address;
                    506:            
                    507:       if (cp->family == AF_INET6)
                    508:        if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6))
                    509:          {
                    510:            memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
                    511:            return 1;
                    512:          }
                    513:     }
                    514:   return 0;
                    515: }
                    516: 
                    517: static int
                    518: if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr)
                    519: {
                    520:   struct listnode *cnode;
                    521:   struct connected *connected;
                    522:   struct prefix *cp; 
                    523:   
                    524:   for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
                    525:     {
                    526:       cp = connected->address;
                    527:            
                    528:       if (cp->family == AF_INET6)
                    529:        if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6))
                    530:          {
                    531:            memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
                    532:            return 1;
                    533:          }
                    534:     }
                    535:   return 0;
                    536: }
1.1.1.4 ! misho     537: 
        !           538: static int
        !           539: if_get_ipv4_address (struct interface *ifp, struct in_addr *addr)
        !           540: {
        !           541:   struct listnode *cnode;
        !           542:   struct connected *connected;
        !           543:   struct prefix *cp;
        !           544: 
        !           545:   for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
        !           546:     {
        !           547:       cp = connected->address;
        !           548:       if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4)))
        !           549:          {
        !           550:            *addr = cp->u.prefix4;
        !           551:            return 1;
        !           552:          }
        !           553:     }
        !           554:   return 0;
        !           555: }
1.1       misho     556: 
                    557: int
                    558: bgp_nexthop_set (union sockunion *local, union sockunion *remote, 
                    559:                 struct bgp_nexthop *nexthop, struct peer *peer)
                    560: {
                    561:   int ret = 0;
                    562:   struct interface *ifp = NULL;
                    563: 
                    564:   memset (nexthop, 0, sizeof (struct bgp_nexthop));
                    565: 
                    566:   if (!local)
                    567:     return -1;
                    568:   if (!remote)
                    569:     return -1;
                    570: 
                    571:   if (local->sa.sa_family == AF_INET)
                    572:     {
                    573:       nexthop->v4 = local->sin.sin_addr;
                    574:       ifp = if_lookup_by_ipv4 (&local->sin.sin_addr);
                    575:     }
                    576:   if (local->sa.sa_family == AF_INET6)
                    577:     {
                    578:       if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
                    579:        {
                    580:          if (peer->ifname)
1.1.1.4 ! misho     581:            ifp = if_lookup_by_name (peer->ifname);
1.1       misho     582:        }
                    583:       else
                    584:        ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr);
                    585:     }
                    586: 
                    587:   if (!ifp)
                    588:     return -1;
                    589: 
                    590:   nexthop->ifp = ifp;
                    591: 
                    592:   /* IPv4 connection. */
                    593:   if (local->sa.sa_family == AF_INET)
                    594:     {
                    595:       /* IPv6 nexthop*/
                    596:       ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
                    597: 
                    598:       /* There is no global nexthop. */
                    599:       if (!ret)
                    600:        if_get_ipv6_local (ifp, &nexthop->v6_global);
                    601:       else
                    602:        if_get_ipv6_local (ifp, &nexthop->v6_local);
                    603:     }
                    604: 
                    605:   /* IPv6 connection. */
                    606:   if (local->sa.sa_family == AF_INET6)
                    607:     {
                    608:       struct interface *direct = NULL;
                    609: 
1.1.1.4 ! misho     610:       /* IPv4 nexthop. */
        !           611:       ret = if_get_ipv4_address(ifp, &nexthop->v4);
        !           612:       if (!ret && peer->local_id.s_addr)
1.1       misho     613:        nexthop->v4 = peer->local_id;
                    614: 
                    615:       /* Global address*/
                    616:       if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
                    617:        {
                    618:          memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, 
                    619:                  IPV6_MAX_BYTELEN);
                    620: 
                    621:          /* If directory connected set link-local address. */
                    622:          direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr);
                    623:          if (direct)
                    624:            if_get_ipv6_local (ifp, &nexthop->v6_local);
                    625:        }
                    626:       else
                    627:        /* Link-local address. */
                    628:        {
                    629:          ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
                    630: 
                    631:          /* If there is no global address.  Set link-local address as
                    632:              global.  I know this break RFC specification... */
                    633:          if (!ret)
                    634:            memcpy (&nexthop->v6_global, &local->sin6.sin6_addr, 
                    635:                    IPV6_MAX_BYTELEN);
                    636:          else
                    637:            memcpy (&nexthop->v6_local, &local->sin6.sin6_addr, 
                    638:                    IPV6_MAX_BYTELEN);
                    639:        }
                    640:     }
                    641: 
                    642:   if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) ||
                    643:       if_lookup_by_ipv6 (&remote->sin6.sin6_addr))
                    644:     peer->shared_network = 1;
                    645:   else
                    646:     peer->shared_network = 0;
                    647: 
                    648:   /* KAME stack specific treatment.  */
                    649: #ifdef KAME
                    650:   if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global)
                    651:       && IN6_LINKLOCAL_IFINDEX (nexthop->v6_global))
                    652:     {
                    653:       SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0);
                    654:     }
                    655:   if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local)
                    656:       && IN6_LINKLOCAL_IFINDEX (nexthop->v6_local))
                    657:     {
                    658:       SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0);
                    659:     }
                    660: #endif /* KAME */
                    661:   return ret;
                    662: }
                    663: 
                    664: void
1.1.1.2   misho     665: bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
1.1       misho     666: {
                    667:   int flags;
                    668:   u_char distance;
                    669:   struct peer *peer;
1.1.1.2   misho     670:   struct bgp_info *mpinfo;
                    671:   size_t oldsize, newsize;
1.1       misho     672: 
                    673:   if (zclient->sock < 0)
                    674:     return;
                    675: 
1.1.1.4 ! misho     676:   if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT))
1.1       misho     677:     return;
                    678: 
                    679:   flags = 0;
                    680:   peer = info->peer;
                    681: 
1.1.1.3   misho     682:   if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
1.1       misho     683:     {
                    684:       SET_FLAG (flags, ZEBRA_FLAG_IBGP);
                    685:       SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
                    686:     }
                    687: 
1.1.1.3   misho     688:   if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
1.1       misho     689:       || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
                    690:     SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
                    691: 
1.1.1.2   misho     692:   /* resize nexthop buffer size if necessary */
                    693:   if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
                    694:       (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1)))
                    695:     {
                    696:       newsize = (sizeof (struct in_addr *) * (bgp_info_mpath_count (info) + 1));
                    697:       newsize = stream_resize (bgp_nexthop_buf, newsize);
                    698:       if (newsize == oldsize)
                    699:        {
                    700:          zlog_err ("can't resize nexthop buffer");
                    701:          return;
                    702:        }
                    703:     }
                    704: 
                    705:   stream_reset (bgp_nexthop_buf);
                    706: 
1.1       misho     707:   if (p->family == AF_INET)
                    708:     {
                    709:       struct zapi_ipv4 api;
                    710:       struct in_addr *nexthop;
                    711: 
1.1.1.4 ! misho     712:       api.vrf_id = VRF_DEFAULT;
1.1       misho     713:       api.flags = flags;
                    714:       nexthop = &info->attr->nexthop;
1.1.1.2   misho     715:       stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
                    716:       for (mpinfo = bgp_info_mpath_first (info); mpinfo;
                    717:           mpinfo = bgp_info_mpath_next (mpinfo))
                    718:        {
                    719:          nexthop = &mpinfo->attr->nexthop;
                    720:          stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
                    721:        }
1.1       misho     722: 
                    723:       api.type = ZEBRA_ROUTE_BGP;
                    724:       api.message = 0;
1.1.1.2   misho     725:       api.safi = safi;
1.1       misho     726:       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
1.1.1.2   misho     727:       api.nexthop_num = 1 + bgp_info_mpath_count (info);
                    728:       api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
1.1       misho     729:       api.ifindex_num = 0;
                    730:       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
                    731:       api.metric = info->attr->med;
                    732: 
                    733:       distance = bgp_distance_apply (p, info, bgp);
                    734: 
                    735:       if (distance)
                    736:        {
                    737:          SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
                    738:          api.distance = distance;
                    739:        }
                    740: 
                    741:       if (BGP_DEBUG(zebra, ZEBRA))
                    742:        {
1.1.1.2   misho     743:          int i;
1.1       misho     744:          char buf[2][INET_ADDRSTRLEN];
1.1.1.2   misho     745:          zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
                    746:                     " count %d",
1.1       misho     747:                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                    748:                     p->prefixlen,
1.1.1.2   misho     749:                     inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
                    750:                     api.metric, api.nexthop_num);
                    751:          for (i = 1; i < api.nexthop_num; i++)
                    752:            zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
                    753:                       i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
                    754:                                    sizeof(buf[1])));
1.1       misho     755:        }
                    756: 
                    757:       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, 
                    758:                        (struct prefix_ipv4 *) p, &api);
                    759:     }
1.1.1.4 ! misho     760: 
1.1       misho     761:   /* We have to think about a IPv6 link-local address curse. */
                    762:   if (p->family == AF_INET6)
                    763:     {
1.1.1.4 ! misho     764:       ifindex_t ifindex;
1.1       misho     765:       struct in6_addr *nexthop;
                    766:       struct zapi_ipv6 api;
                    767: 
                    768:       ifindex = 0;
                    769:       nexthop = NULL;
                    770:       
                    771:       assert (info->attr->extra);
                    772:       
                    773:       /* Only global address nexthop exists. */
                    774:       if (info->attr->extra->mp_nexthop_len == 16)
                    775:        nexthop = &info->attr->extra->mp_nexthop_global;
                    776:       
                    777:       /* If both global and link-local address present. */
                    778:       if (info->attr->extra->mp_nexthop_len == 32)
                    779:        {
                    780:          /* Workaround for Cisco's nexthop bug.  */
                    781:          if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
                    782:              && peer->su_remote->sa.sa_family == AF_INET6)
                    783:            nexthop = &peer->su_remote->sin6.sin6_addr;
                    784:          else
                    785:            nexthop = &info->attr->extra->mp_nexthop_local;
                    786: 
                    787:          if (info->peer->nexthop.ifp)
                    788:            ifindex = info->peer->nexthop.ifp->ifindex;
                    789:        }
                    790: 
                    791:       if (nexthop == NULL)
                    792:        return;
                    793: 
                    794:       if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
                    795:        {
                    796:          if (info->peer->ifname)
1.1.1.4 ! misho     797:            ifindex = ifname2ifindex (info->peer->ifname);
1.1       misho     798:          else if (info->peer->nexthop.ifp)
                    799:            ifindex = info->peer->nexthop.ifp->ifindex;
                    800:        }
                    801: 
                    802:       /* Make Zebra API structure. */
1.1.1.4 ! misho     803:       api.vrf_id = VRF_DEFAULT;
1.1       misho     804:       api.flags = flags;
                    805:       api.type = ZEBRA_ROUTE_BGP;
                    806:       api.message = 0;
1.1.1.2   misho     807:       api.safi = safi;
1.1       misho     808:       SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
                    809:       api.nexthop_num = 1;
                    810:       api.nexthop = &nexthop;
                    811:       SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
                    812:       api.ifindex_num = 1;
                    813:       api.ifindex = &ifindex;
                    814:       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
                    815:       api.metric = info->attr->med;
                    816: 
                    817:       if (BGP_DEBUG(zebra, ZEBRA))
                    818:        {
                    819:          char buf[2][INET6_ADDRSTRLEN];
                    820:          zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
                    821:                     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                    822:                     p->prefixlen,
                    823:                     inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
                    824:                     api.metric);
                    825:        }
                    826: 
                    827:       zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, 
                    828:                        (struct prefix_ipv6 *) p, &api);
                    829:     }
                    830: }
                    831: 
                    832: void
1.1.1.2   misho     833: bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
1.1       misho     834: {
                    835:   int flags;
                    836:   struct peer *peer;
                    837: 
                    838:   if (zclient->sock < 0)
                    839:     return;
                    840: 
1.1.1.4 ! misho     841:   if (! vrf_bitmap_check (zclient->redist[ZEBRA_ROUTE_BGP], VRF_DEFAULT))
1.1       misho     842:     return;
                    843: 
                    844:   peer = info->peer;
                    845:   flags = 0;
                    846: 
1.1.1.3   misho     847:   if (peer->sort == BGP_PEER_IBGP)
1.1       misho     848:     {
                    849:       SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
                    850:       SET_FLAG (flags, ZEBRA_FLAG_IBGP);
                    851:     }
                    852: 
1.1.1.3   misho     853:   if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
1.1       misho     854:       || CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
                    855:     SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
                    856: 
                    857:   if (p->family == AF_INET)
                    858:     {
                    859:       struct zapi_ipv4 api;
                    860: 
1.1.1.4 ! misho     861:       api.vrf_id = VRF_DEFAULT;
1.1       misho     862:       api.flags = flags;
                    863: 
                    864:       api.type = ZEBRA_ROUTE_BGP;
                    865:       api.message = 0;
1.1.1.2   misho     866:       api.safi = safi;
1.1.1.4 ! misho     867:       api.nexthop_num = 0;
1.1       misho     868:       api.ifindex_num = 0;
                    869:       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
                    870:       api.metric = info->attr->med;
                    871: 
                    872:       if (BGP_DEBUG(zebra, ZEBRA))
                    873:        {
                    874:          char buf[2][INET_ADDRSTRLEN];
1.1.1.4 ! misho     875:          zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u",
1.1       misho     876:                     inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
                    877:                     p->prefixlen,
                    878:                     api.metric);
                    879:        }
                    880: 
                    881:       zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, 
                    882:                        (struct prefix_ipv4 *) p, &api);
                    883:     }
1.1.1.4 ! misho     884: 
1.1       misho     885:   /* We have to think about a IPv6 link-local address curse. */
                    886:   if (p->family == AF_INET6)
                    887:     {
                    888:       struct zapi_ipv6 api;
                    889:       
1.1.1.4 ! misho     890:       api.vrf_id = VRF_DEFAULT;
1.1       misho     891:       api.flags = flags;
                    892:       api.type = ZEBRA_ROUTE_BGP;
                    893:       api.message = 0;
1.1.1.2   misho     894:       api.safi = safi;
1.1.1.4 ! misho     895:       api.nexthop_num = 0;
        !           896:       api.ifindex_num = 0;
1.1       misho     897:       SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
                    898:       api.metric = info->attr->med;
                    899: 
                    900:       if (BGP_DEBUG(zebra, ZEBRA))
                    901:        {
                    902:          char buf[2][INET6_ADDRSTRLEN];
1.1.1.4 ! misho     903:          zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u",
1.1       misho     904:                     inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
                    905:                     p->prefixlen,
                    906:                     api.metric);
                    907:        }
                    908: 
                    909:       zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, 
                    910:                        (struct prefix_ipv6 *) p, &api);
                    911:     }
                    912: }
1.1.1.4 ! misho     913: 
1.1       misho     914: /* Other routes redistribution into BGP. */
                    915: int
                    916: bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type)
                    917: {
                    918:   /* Set flag to BGP instance. */
                    919:   bgp->redist[afi][type] = 1;
                    920: 
                    921:   /* Return if already redistribute flag is set. */
1.1.1.4 ! misho     922:   if (vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT))
1.1       misho     923:     return CMD_WARNING;
                    924: 
1.1.1.4 ! misho     925:   vrf_bitmap_set (zclient->redist[type], VRF_DEFAULT);
1.1       misho     926: 
                    927:   /* Return if zebra connection is not established. */
                    928:   if (zclient->sock < 0)
                    929:     return CMD_WARNING;
                    930: 
                    931:   if (BGP_DEBUG(zebra, ZEBRA))
                    932:     zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
                    933:     
                    934:   /* Send distribute add message to zebra. */
1.1.1.4 ! misho     935:   zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type, VRF_DEFAULT);
1.1       misho     936: 
                    937:   return CMD_SUCCESS;
                    938: }
                    939: 
                    940: /* Redistribute with route-map specification.  */
                    941: int
                    942: bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type, 
                    943:                            const char *name)
                    944: {
                    945:   if (bgp->rmap[afi][type].name
                    946:       && (strcmp (bgp->rmap[afi][type].name, name) == 0))
                    947:     return 0;
                    948: 
                    949:   if (bgp->rmap[afi][type].name)
                    950:     free (bgp->rmap[afi][type].name);
                    951:   bgp->rmap[afi][type].name = strdup (name);
                    952:   bgp->rmap[afi][type].map = route_map_lookup_by_name (name);
                    953: 
                    954:   return 1;
                    955: }
                    956: 
                    957: /* Redistribute with metric specification.  */
                    958: int
                    959: bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type,
                    960:                             u_int32_t metric)
                    961: {
                    962:   if (bgp->redist_metric_flag[afi][type]
                    963:       && bgp->redist_metric[afi][type] == metric)
                    964:     return 0;
                    965: 
                    966:   bgp->redist_metric_flag[afi][type] = 1;
                    967:   bgp->redist_metric[afi][type] = metric;
                    968: 
                    969:   return 1;
                    970: }
                    971: 
                    972: /* Unset redistribution.  */
                    973: int
                    974: bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
                    975: {
                    976:   /* Unset flag from BGP instance. */
                    977:   bgp->redist[afi][type] = 0;
                    978: 
                    979:   /* Unset route-map. */
                    980:   if (bgp->rmap[afi][type].name)
                    981:     free (bgp->rmap[afi][type].name);
                    982:   bgp->rmap[afi][type].name = NULL;
                    983:   bgp->rmap[afi][type].map = NULL;
                    984: 
                    985:   /* Unset metric. */
                    986:   bgp->redist_metric_flag[afi][type] = 0;
                    987:   bgp->redist_metric[afi][type] = 0;
                    988: 
                    989:   /* Return if zebra connection is disabled. */
1.1.1.4 ! misho     990:   if (! vrf_bitmap_check (zclient->redist[type], VRF_DEFAULT))
1.1       misho     991:     return CMD_WARNING;
1.1.1.4 ! misho     992:   vrf_bitmap_unset (zclient->redist[type], VRF_DEFAULT);
1.1       misho     993: 
                    994:   if (bgp->redist[AFI_IP][type] == 0 
                    995:       && bgp->redist[AFI_IP6][type] == 0 
                    996:       && zclient->sock >= 0)
                    997:     {
                    998:       /* Send distribute delete message to zebra. */
                    999:       if (BGP_DEBUG(zebra, ZEBRA))
                   1000:        zlog_debug("Zebra send: redistribute delete %s",
                   1001:                   zebra_route_string(type));
1.1.1.4 ! misho    1002:       zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type,
        !          1003:                                VRF_DEFAULT);
1.1       misho    1004:     }
                   1005:   
                   1006:   /* Withdraw redistributed routes from current BGP's routing table. */
                   1007:   bgp_redistribute_withdraw (bgp, afi, type);
                   1008: 
                   1009:   return CMD_SUCCESS;
                   1010: }
                   1011: 
                   1012: /* Unset redistribution route-map configuration.  */
                   1013: int
                   1014: bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type)
                   1015: {
                   1016:   if (! bgp->rmap[afi][type].name)
                   1017:     return 0;
                   1018: 
                   1019:   /* Unset route-map. */
                   1020:   free (bgp->rmap[afi][type].name);
                   1021:   bgp->rmap[afi][type].name = NULL;
                   1022:   bgp->rmap[afi][type].map = NULL;
                   1023: 
                   1024:   return 1;
                   1025: }
                   1026: 
                   1027: /* Unset redistribution metric configuration.  */
                   1028: int
                   1029: bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type)
                   1030: {
                   1031:   if (! bgp->redist_metric_flag[afi][type])
                   1032:     return 0;
                   1033: 
                   1034:   /* Unset metric. */
                   1035:   bgp->redist_metric_flag[afi][type] = 0;
                   1036:   bgp->redist_metric[afi][type] = 0;
                   1037: 
                   1038:   return 1;
                   1039: }
1.1.1.4 ! misho    1040: 
1.1       misho    1041: void
                   1042: bgp_zclient_reset (void)
                   1043: {
                   1044:   zclient_reset (zclient);
                   1045: }
                   1046: 
1.1.1.4 ! misho    1047: static void
        !          1048: bgp_zebra_connected (struct zclient *zclient)
        !          1049: {
        !          1050:   zclient_send_requests (zclient, VRF_DEFAULT);
        !          1051: }
        !          1052: 
1.1       misho    1053: void
1.1.1.4 ! misho    1054: bgp_zebra_init (struct thread_master *master)
1.1       misho    1055: {
                   1056:   /* Set default values. */
1.1.1.4 ! misho    1057:   zclient = zclient_new (master);
1.1       misho    1058:   zclient_init (zclient, ZEBRA_ROUTE_BGP);
1.1.1.4 ! misho    1059:   zclient->zebra_connected = bgp_zebra_connected;
1.1       misho    1060:   zclient->router_id_update = bgp_router_id_update;
                   1061:   zclient->interface_add = bgp_interface_add;
                   1062:   zclient->interface_delete = bgp_interface_delete;
                   1063:   zclient->interface_address_add = bgp_interface_address_add;
                   1064:   zclient->interface_address_delete = bgp_interface_address_delete;
                   1065:   zclient->ipv4_route_add = zebra_read_ipv4;
                   1066:   zclient->ipv4_route_delete = zebra_read_ipv4;
                   1067:   zclient->interface_up = bgp_interface_up;
                   1068:   zclient->interface_down = bgp_interface_down;
                   1069:   zclient->ipv6_route_add = zebra_read_ipv6;
                   1070:   zclient->ipv6_route_delete = zebra_read_ipv6;
1.1.1.2   misho    1071: 
                   1072:   bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
1.1.1.4 ! misho    1073: }
        !          1074: 
        !          1075: void
        !          1076: bgp_zebra_destroy(void)
        !          1077: {
        !          1078:   if (zclient == NULL)
        !          1079:     return;
        !          1080:   zclient_stop(zclient);
        !          1081:   zclient_free(zclient);
        !          1082:   zclient = NULL;
1.1       misho    1083: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>