frr/bgpd/bgp_zebra.c

1194 lines
30 KiB
C
Raw Normal View History

2002-12-13 21:15:29 +01:00
/* zebra client
Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
This file is part of GNU Zebra.
GNU Zebra is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
GNU Zebra is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Zebra; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include <zebra.h>
#include "command.h"
#include "stream.h"
#include "network.h"
#include "prefix.h"
#include "log.h"
#include "sockunion.h"
#include "zclient.h"
#include "routemap.h"
#include "thread.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_mpath.h"
2002-12-13 21:15:29 +01:00
/* All information about zebra. */
[bgpd] Stability fixes including bugs 397, 492 I've spent the last several weeks working on stability fixes to bgpd. These patches fix all of the numerous crashes, assertion failures, memory leaks and memory stomping I could find. Valgrind was used extensively. Added new function bgp_exit() to help catch problems. If "debug bgp" is configured and bgpd exits with status of 0, statistics on remaining lib/memory.c allocations are printed to stderr. It is my hope that other developers will use this to stay on top of memory issues. Example questionable exit: bgpd: memstats: Current memory utilization in module LIB: bgpd: memstats: Link List : 6 bgpd: memstats: Link Node : 5 bgpd: memstats: Hash : 8 bgpd: memstats: Hash Bucket : 2 bgpd: memstats: Hash Index : 8 bgpd: memstats: Work queue : 3 bgpd: memstats: Work queue item : 2 bgpd: memstats: Work queue name string : 3 bgpd: memstats: Current memory utilization in module BGP: bgpd: memstats: BGP instance : 1 bgpd: memstats: BGP peer : 1 bgpd: memstats: BGP peer hostname : 1 bgpd: memstats: BGP attribute : 1 bgpd: memstats: BGP extra attributes : 1 bgpd: memstats: BGP aspath : 1 bgpd: memstats: BGP aspath str : 1 bgpd: memstats: BGP table : 24 bgpd: memstats: BGP node : 1 bgpd: memstats: BGP route : 1 bgpd: memstats: BGP synchronise : 8 bgpd: memstats: BGP Process queue : 1 bgpd: memstats: BGP node clear queue : 1 bgpd: memstats: NOTE: If configuration exists, utilization may be expected. Example clean exit: bgpd: memstats: No remaining tracked memory utilization. This patch fixes bug #397: "Invalid free in bgp_announce_check()". This patch fixes bug #492: "SIGBUS in bgpd/bgp_route.c: bgp_clear_route_node()". My apologies for not separating out these changes into individual patches. The complexity of doing so boggled what is left of my brain. I hope this is all still useful to the community. This code has been production tested, in non-route-server-client mode, on a linux 32-bit box and a 64-bit box. Release/reset functions, used by bgp_exit(), added to: bgpd/bgp_attr.c,h bgpd/bgp_community.c,h bgpd/bgp_dump.c,h bgpd/bgp_ecommunity.c,h bgpd/bgp_filter.c,h bgpd/bgp_nexthop.c,h bgpd/bgp_route.c,h lib/routemap.c,h File by file analysis: * bgpd/bgp_aspath.c: Prevent re-use of ashash after it is released. * bgpd/bgp_attr.c: #if removed uncalled cluster_dup(). * bgpd/bgp_clist.c,h: Allow community_list_terminate() to be called from bgp_exit(). * bgpd/bgp_filter.c: Fix aslist->name use without allocation check, and also fix memory leak. * bgpd/bgp_main.c: Created bgp_exit() exit routine. This function frees allocations made as part of bgpd initialization and, to some extent, configuration. If "debug bgp" is configured, memory stats are printed as described above. * bgpd/bgp_nexthop.c: zclient_new() already allocates stream for ibuf/obuf, so bgp_scan_init() shouldn't do it too. Also, made it so zlookup is global so bgp_exit() can use it. * bgpd/bgp_packet.c: bgp_capability_msg_parse() call to bgp_clear_route() adjusted to use new BGP_CLEAR_ROUTE_NORMAL flag. * bgpd/bgp_route.h: Correct reference counter "lock" to be signed. bgp_clear_route() now accepts a bgp_clear_route_type of either BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. * bgpd/bgp_route.c: - bgp_process_rsclient(): attr was being zero'ed and then bgp_attr_extra_free() was being called with it, even though it was never filled with valid data. - bgp_process_rsclient(): Make sure rsclient->group is not NULL before use. - bgp_processq_del(): Add call to bgp_table_unlock(). - bgp_process(): Add call to bgp_table_lock(). - bgp_update_rsclient(): memset clearing of new_attr not needed since declarationw with "= { 0 }" does it. memset was already commented out. - bgp_update_rsclient(): Fix screwed up misleading indentation. - bgp_withdraw_rsclient(): Fix screwed up misleading indentation. - bgp_clear_route_node(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_node_queue_del(): Add call to bgp_table_unlock() and also free struct bgp_clear_node_queue used for work item. - bgp_clear_node_complete(): Do peer_unlock() after BGP_EVENT_ADD() in case peer is released by peer_unlock() call. - bgp_clear_route_table(): Support BGP_CLEAR_ROUTE_MY_RSCLIENT. Use struct bgp_clear_node_queue to supply data to worker. Add call to bgp_table_lock(). - bgp_clear_route(): Add support for BGP_CLEAR_ROUTE_NORMAL or BGP_CLEAR_ROUTE_MY_RSCLIENT. - bgp_clear_route_all(): Use BGP_CLEAR_ROUTE_NORMAL. Bug 397 fixes: - bgp_default_originate() - bgp_announce_table() * bgpd/bgp_table.h: - struct bgp_table: Added reference count. Changed type of owner to be "struct peer *" rather than "void *". - struct bgp_node: Correct reference counter "lock" to be signed. * bgpd/bgp_table.c: - Added bgp_table reference counting. - bgp_table_free(): Fixed cleanup code. Call peer_unlock() on owner if set. - bgp_unlock_node(): Added assertion. - bgp_node_get(): Added call to bgp_lock_node() to code path that it was missing from. * bgpd/bgp_vty.c: - peer_rsclient_set_vty(): Call peer_lock() as part of peer assignment to owner. Handle failure gracefully. - peer_rsclient_unset_vty(): Add call to bgp_clear_route() with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. * bgpd/bgp_zebra.c: Made it so zclient is global so bgp_exit() can use it. * bgpd/bgpd.c: - peer_lock(): Allow to be called when status is "Deleted". - peer_deactivate(): Supply BGP_CLEAR_ROUTE_NORMAL purpose to bgp_clear_route() call. - peer_delete(): Common variable listnode pn. Fix bug in which rsclient was only dealt with if not part of a peer group. Call bgp_clear_route() for rsclient, if appropriate, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - peer_group_get(): Use XSTRDUP() instead of strdup() for conf->host. - peer_group_bind(): Call bgp_clear_route() for rsclient, and do so with BGP_CLEAR_ROUTE_MY_RSCLIENT purpose. - bgp_create(): Use XSTRDUP() instead of strdup() for peer_self->host. - bgp_delete(): Delete peers before groups, rather than after. And then rather than deleting rsclients, verify that there are none at this point. - bgp_unlock(): Add assertion. - bgp_free(): Call bgp_table_finish() rather than doing XFREE() itself. * lib/command.c,h: Compiler warning fixes. Add cmd_terminate(). Fixed massive leak in install_element() in which cmd_make_descvec() was being called more than once for the same cmd->strvec/string/doc. * lib/log.c: Make closezlog() check fp before calling fclose(). * lib/memory.c: Catch when alloc count goes negative by using signed counts. Correct #endif comment. Add log_memstats_stderr(). * lib/memory.h: Add log_memstats_stderr(). * lib/thread.c: thread->funcname was being accessed in thread_call() after it had been freed. Rearranged things so that thread_call() frees funcname. Also made it so thread_master_free() cleans up cpu_record. * lib/vty.c,h: Use global command_cr. Add vty_terminate(). * lib/zclient.c,h: Re-enable zclient_free().
2009-07-18 07:44:03 +02:00
struct zclient *zclient = NULL;
2004-10-03 20:18:34 +02:00
struct in_addr router_id_zebra;
2002-12-13 21:15:29 +01:00
/* Growable buffer for nexthops sent to zebra */
struct stream *bgp_nexthop_buf = NULL;
struct stream *bgp_ifindices_buf = NULL;
2004-10-03 20:18:34 +02:00
/* Router-id update message from zebra. */
static int
2004-10-03 20:18:34 +02:00
bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length)
2002-12-13 21:15:29 +01:00
{
2004-10-03 20:18:34 +02:00
struct prefix router_id;
struct listnode *node, *nnode;
2004-10-03 20:18:34 +02:00
struct bgp *bgp;
2002-12-13 21:15:29 +01:00
2004-10-03 20:18:34 +02:00
zebra_router_id_update_read(zclient->ibuf,&router_id);
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[128];
prefix2str(&router_id, buf, sizeof(buf));
zlog_debug("Zebra rcvd: router id update %s", buf);
}
2004-10-03 20:18:34 +02:00
router_id_zebra = router_id.u.prefix4;
2002-12-13 21:15:29 +01:00
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
2002-12-13 21:15:29 +01:00
{
2004-10-03 20:18:34 +02:00
if (!bgp->router_id_static.s_addr)
bgp_router_id_set (bgp, &router_id.u.prefix4);
2002-12-13 21:15:29 +01:00
}
2004-10-03 20:18:34 +02:00
2002-12-13 21:15:29 +01:00
return 0;
}
/* Inteface addition message from zebra. */
static int
2002-12-13 21:15:29 +01:00
bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
{
struct interface *ifp;
ifp = zebra_interface_add_read (zclient->ibuf);
if (BGP_DEBUG(zebra, ZEBRA) && ifp)
zlog_debug("Zebra rcvd: interface add %s", ifp->name);
2002-12-13 21:15:29 +01:00
return 0;
}
static int
2002-12-13 21:15:29 +01:00
bgp_interface_delete (int command, struct zclient *zclient,
zebra_size_t length)
{
struct stream *s;
struct interface *ifp;
s = zclient->ibuf;
ifp = zebra_interface_state_read (s);
2005-04-02 Andrew J. Schorr <ajschorr@alumni.princeton.edu> Fix problems when netlink interfaces are renamed (same ifindex used for a new interface). Start cleaning up some problems with the way interface names are handled. * interface.c: (if_new_intern_ifindex) Remove obsolete function. (if_delete_update) After distributing the interface deletion message, set ifp->ifindex to IFINDEX_INTERNAL. (if_dump_vty) Detect pseudo interface by checking if ifp->ifindex is IFINDEX_INTERNAL. (zebra_interface) Check return code from interface_cmd.func. Do not set internal ifindex values to if_new_intern_ifindex(), since we now use IFINDEX_INTERNAL for all pseudo interfaces. * kernel_socket.c: (ifm_read) Fix code and comments to reflect that all internal interfaces now have ifp->ifindex set to IFINDEX_INTERNAL. * rt_netlink.c: (set_ifindex) New function used to update ifp->ifindex. Detects interface rename events by checking if that ifindex is already being used. If it is, delete the old interface before assigning the ifindex to the new interface. (netlink_interface, netlink_link_change) Call set_ifindex to update the ifindex. * if.h: Remove define for IFINDEX_INTERNBASE and add define IFINDEX_INTERNAL 0, since all internal (i.e. non-kernel) pseudo- interfaces should have ifindex set to 0. (if_new) Remove function. (if_delete_retain) New function to delete an interface without removing from iflist and freeing the structure. (ifname2ifindex) New function. * if.c: (if_new) Remove function (absorb into if_create). (if_create) Replace function if_new with call to calloc. Set ifp->ifindex to IFINDEX_INTERNAL. Fix off-by-one error in assert to check length of interface name. Add error message if interface with this name already exists. (if_delete_retain) New function to delete an interface without removing from iflist and freeing the structure. (if_delete) Implement with help of if_delete_retain. (ifindex2ifname) Reimplement using if_lookup_by_index. (ifname2ifindex) New function to complement ifindex2ifname. (interface) The interface command should check the name length and fail with a warning message if it is too long. (no_interface) Fix spelling in warning message. (if_nametoindex) Reimplement using if_lookup_by_name. (if_indextoname, ifaddr_ipv4_lookup) Reimplement using if_lookup_by_index. * bgp_zebra.c: (bgp_interface_delete) After deleting, set ifp->ifindex to IFINDEX_INTERNAL. * isis_zebra.c: (isis_zebra_if_del) Call if_delete_retain instead of if_delete, since it is generally not safe to remove interface structures. After deleting, set ifp->ifindex to IFINDEX_INTERNAL. (zebra_interface_if_lookup) Tighten up code. * ospf6_zebra.c: (ospf6_zebra_if_del) Previously, this whole function was commented out. But this is not safe: we should at least update the ifindex when the interface is deleted. So the new version updates the interface status and sets ifp->ifindex to IFINDEX_INTERNAL. (ospf6_zebra_route_update) Use if_indextoname properly. * ospf_vty.c: (show_ip_ospf_interface_sub) Show ifindex and interface flags to help with debugging. * ospf_zebra.c: (ospf_interface_delete) After deleting, set ifp->ifindex to IFINDEX_INTERNAL. (zebra_interface_if_lookup) Make function static. Tighten up code. * rip_interface.c: (rip_interface_delete) After deleting, set ifp->ifindex to IFINDEX_INTERNAL. * ripng_interface.c: (ripng_interface_delete) After deleting, set ifp->ifindex to IFINDEX_INTERNAL.
2005-04-02 20:38:43 +02:00
ifp->ifindex = IFINDEX_INTERNAL;
2002-12-13 21:15:29 +01:00
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface delete %s", ifp->name);
2002-12-13 21:15:29 +01:00
return 0;
}
static int
2002-12-13 21:15:29 +01:00
bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length)
{
struct stream *s;
struct interface *ifp;
struct connected *c;
struct listnode *node, *nnode;
2002-12-13 21:15:29 +01:00
s = zclient->ibuf;
ifp = zebra_interface_state_read (s);
if (! ifp)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface %s up", ifp->name);
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
bgp_connected_add (c);
2002-12-13 21:15:29 +01:00
return 0;
}
static int
2002-12-13 21:15:29 +01:00
bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length)
{
struct stream *s;
struct interface *ifp;
struct connected *c;
struct listnode *node, *nnode;
2002-12-13 21:15:29 +01:00
s = zclient->ibuf;
ifp = zebra_interface_state_read (s);
if (! ifp)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Zebra rcvd: interface %s down", ifp->name);
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
bgp_connected_delete (c);
2002-12-13 21:15:29 +01:00
bgpd: fix fast external fallover behavior ISSUES 1. When an interface goes down, the zclient callbacks are invoked in the following order: (a) address_delete() that removes the connected address list: ifp->connected, (b) interface_down() that performs "fast external fallover" operation. The operation relies on ifp->connected to look for peers that should be brought down. That's a cyclic dependency. 2. 'ttl-security' configuration handler sets peer->ttl to MAXTTL (so that BGP packets are sent with TTL=255, as per the requirement of ttl-security). This, however, is incompatible with 'fast external fallover' as the fallover operation checks for (ttl == 1) to determine directly connected peers. 3. The current fallover operation does not work for IPv6 address family. PATCH 1. The patch removes the dependency on 'ifp->connected' list for fast fallover. The peer already contains a nexthop structure that reflects the peering address. The nexthop structure has a pointer to the interface (ifp) that peering address resolves to. Everytime the TCP connection succeeds, the ifp is updated. The patch uses this ifp in the interface_down() callback for a match for the peers that should be brought down. 2. The evaluation for directly connected peering is enhanced as 'peer->ttl == 1' OR 'peer->gtsm_hops == 1'. Thus a ttl-security configuration on the peer with one hop is directly connected and should be brought down under 'fast external fallover'. 3. Because of fix (1), IPv6 address family works automatically. Signed-off-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com> Reviewed-by: Dinesh G Dutt <ddutt@cumulusnetworks.com> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
2013-09-11 05:33:55 +02:00
/* Fast external-failover */
2002-12-13 21:15:29 +01:00
{
struct listnode *mnode;
2002-12-13 21:15:29 +01:00
struct bgp *bgp;
struct peer *peer;
for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
2002-12-13 21:15:29 +01:00
{
if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
continue;
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
2002-12-13 21:15:29 +01:00
{
bgpd: fix fast external fallover behavior ISSUES 1. When an interface goes down, the zclient callbacks are invoked in the following order: (a) address_delete() that removes the connected address list: ifp->connected, (b) interface_down() that performs "fast external fallover" operation. The operation relies on ifp->connected to look for peers that should be brought down. That's a cyclic dependency. 2. 'ttl-security' configuration handler sets peer->ttl to MAXTTL (so that BGP packets are sent with TTL=255, as per the requirement of ttl-security). This, however, is incompatible with 'fast external fallover' as the fallover operation checks for (ttl == 1) to determine directly connected peers. 3. The current fallover operation does not work for IPv6 address family. PATCH 1. The patch removes the dependency on 'ifp->connected' list for fast fallover. The peer already contains a nexthop structure that reflects the peering address. The nexthop structure has a pointer to the interface (ifp) that peering address resolves to. Everytime the TCP connection succeeds, the ifp is updated. The patch uses this ifp in the interface_down() callback for a match for the peers that should be brought down. 2. The evaluation for directly connected peering is enhanced as 'peer->ttl == 1' OR 'peer->gtsm_hops == 1'. Thus a ttl-security configuration on the peer with one hop is directly connected and should be brought down under 'fast external fallover'. 3. Because of fix (1), IPv6 address family works automatically. Signed-off-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com> Reviewed-by: Dinesh G Dutt <ddutt@cumulusnetworks.com> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
2013-09-11 05:33:55 +02:00
if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
2002-12-13 21:15:29 +01:00
continue;
bgpd: fix fast external fallover behavior ISSUES 1. When an interface goes down, the zclient callbacks are invoked in the following order: (a) address_delete() that removes the connected address list: ifp->connected, (b) interface_down() that performs "fast external fallover" operation. The operation relies on ifp->connected to look for peers that should be brought down. That's a cyclic dependency. 2. 'ttl-security' configuration handler sets peer->ttl to MAXTTL (so that BGP packets are sent with TTL=255, as per the requirement of ttl-security). This, however, is incompatible with 'fast external fallover' as the fallover operation checks for (ttl == 1) to determine directly connected peers. 3. The current fallover operation does not work for IPv6 address family. PATCH 1. The patch removes the dependency on 'ifp->connected' list for fast fallover. The peer already contains a nexthop structure that reflects the peering address. The nexthop structure has a pointer to the interface (ifp) that peering address resolves to. Everytime the TCP connection succeeds, the ifp is updated. The patch uses this ifp in the interface_down() callback for a match for the peers that should be brought down. 2. The evaluation for directly connected peering is enhanced as 'peer->ttl == 1' OR 'peer->gtsm_hops == 1'. Thus a ttl-security configuration on the peer with one hop is directly connected and should be brought down under 'fast external fallover'. 3. Because of fix (1), IPv6 address family works automatically. Signed-off-by: Pradosh Mohapatra <pmohapat@cumulusnetworks.com> Reviewed-by: Dinesh G Dutt <ddutt@cumulusnetworks.com> Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
2013-09-11 05:33:55 +02:00
if (ifp == peer->nexthop.ifp)
2002-12-13 21:15:29 +01:00
BGP_EVENT_ADD (peer, BGP_Stop);
}
}
}
return 0;
}
static int
2002-12-13 21:15:29 +01:00
bgp_interface_address_add (int command, struct zclient *zclient,
zebra_size_t length)
{
struct connected *ifc;
2004-05-08 Paul Jakma <paul@dishone.st> * bgp_zebra.c: (bgp_interface_address_add) sync to zclient changes (bgp_interface_address_delete) ditto. (bgp_zebra_announce) ditto. (bgp_zebra_withdraw) ditto. * isis_zebra.c: Sync with zclient changes. * zclient.c (zapi_ipv4_route) Follow Sowmini's lead and describe message format. * ospf6_zebra.c: Sync to zclient changes * ospf_zebra.c: Sync with lib/zclient changes * rip_zebra.c: sync with zclient changes. * rip_interface.c: ditto. * ripng_{interface,zebra}.c: sync with zclient changes 2004-05-08 Sowmini Varadhan <sowmini.varadhan@sun.com> * zclient.c: (zapi_ipv4_add) collapsed into zapi_ipv4_route (zapi_ipv4_delete) ditto. (zapi_ipv4_route) add/delete a route by way of cmd arg. (zapi_ipv6_add) collapsed into zapi_ipv6_route. (zapi_ipv6_delete) ditto. (zapi_ipv6_route) add/delete a route by way of cmd arg. (zebra_interface_address_delete_read) collapsed into zebra_interface_address_read. (zebra_interface_address_delete_read) ditto. (zebra_interface_address_read) read address add/delete messages by way of type argument. Describe command message format. (zebra_interface_add_read) Unconditionally read new ifmtu6 field. Describe command message format. (zebra_interface_state_read) Unconditionally read new ifmtu6 field. (zclient_redistribute_set) Collapsed into zclient_redistribute (zclient_redistribute_unset) ditto (zclient_redistribute) set/unset redistribution. (zclient_redistribute_default_set) Collapsed into zclient_redistribute_default. (zclient_redistribute_default_unset) ditto. (zclient_redistribute_default) Redistribute default set/unset. * zclient.h: delete zapi_ipv{4,6}_add, zapi_ipv{4,6}_delete. Add zapi_ipv{4,6}_route. delete zclient_redistribute_set/unset. Add zclient_redistribute. Ditto for zclient_redistribute_default_{set/unset}.
2004-05-08 13:48:26 +02:00
ifc = zebra_interface_address_read (command, zclient->ibuf);
2002-12-13 21:15:29 +01:00
if (ifc == NULL)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[128];
prefix2str(ifc->address, buf, sizeof(buf));
zlog_debug("Zebra rcvd: interface %s address add %s",
ifc->ifp->name, buf);
}
2002-12-13 22:03:13 +01:00
if (if_is_operative (ifc->ifp))
2002-12-13 21:15:29 +01:00
bgp_connected_add (ifc);
return 0;
}
static int
2002-12-13 21:15:29 +01:00
bgp_interface_address_delete (int command, struct zclient *zclient,
zebra_size_t length)
{
struct connected *ifc;
2004-05-08 Paul Jakma <paul@dishone.st> * bgp_zebra.c: (bgp_interface_address_add) sync to zclient changes (bgp_interface_address_delete) ditto. (bgp_zebra_announce) ditto. (bgp_zebra_withdraw) ditto. * isis_zebra.c: Sync with zclient changes. * zclient.c (zapi_ipv4_route) Follow Sowmini's lead and describe message format. * ospf6_zebra.c: Sync to zclient changes * ospf_zebra.c: Sync with lib/zclient changes * rip_zebra.c: sync with zclient changes. * rip_interface.c: ditto. * ripng_{interface,zebra}.c: sync with zclient changes 2004-05-08 Sowmini Varadhan <sowmini.varadhan@sun.com> * zclient.c: (zapi_ipv4_add) collapsed into zapi_ipv4_route (zapi_ipv4_delete) ditto. (zapi_ipv4_route) add/delete a route by way of cmd arg. (zapi_ipv6_add) collapsed into zapi_ipv6_route. (zapi_ipv6_delete) ditto. (zapi_ipv6_route) add/delete a route by way of cmd arg. (zebra_interface_address_delete_read) collapsed into zebra_interface_address_read. (zebra_interface_address_delete_read) ditto. (zebra_interface_address_read) read address add/delete messages by way of type argument. Describe command message format. (zebra_interface_add_read) Unconditionally read new ifmtu6 field. Describe command message format. (zebra_interface_state_read) Unconditionally read new ifmtu6 field. (zclient_redistribute_set) Collapsed into zclient_redistribute (zclient_redistribute_unset) ditto (zclient_redistribute) set/unset redistribution. (zclient_redistribute_default_set) Collapsed into zclient_redistribute_default. (zclient_redistribute_default_unset) ditto. (zclient_redistribute_default) Redistribute default set/unset. * zclient.h: delete zapi_ipv{4,6}_add, zapi_ipv{4,6}_delete. Add zapi_ipv{4,6}_route. delete zclient_redistribute_set/unset. Add zclient_redistribute. Ditto for zclient_redistribute_default_{set/unset}.
2004-05-08 13:48:26 +02:00
ifc = zebra_interface_address_read (command, zclient->ibuf);
2002-12-13 21:15:29 +01:00
if (ifc == NULL)
return 0;
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[128];
prefix2str(ifc->address, buf, sizeof(buf));
zlog_debug("Zebra rcvd: interface %s address delete %s",
ifc->ifp->name, buf);
}
2002-12-13 22:03:13 +01:00
if (if_is_operative (ifc->ifp))
2002-12-13 21:15:29 +01:00
bgp_connected_delete (ifc);
connected_free (ifc);
return 0;
}
/* Zebra route add and delete treatment. */
static int
2002-12-13 21:15:29 +01:00
zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
{
struct stream *s;
struct zapi_ipv4 api;
struct in_addr nexthop;
struct prefix_ipv4 p;
s = zclient->ibuf;
nexthop.s_addr = 0;
/* Type, flags, message. */
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET;
p.prefixlen = stream_getc (s);
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
{
api.nexthop_num = stream_getc (s);
nexthop.s_addr = stream_get_ipv4 (s);
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
stream_getl (s); /* ifindex, unused */
2002-12-13 21:15:29 +01:00
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
if (command == ZEBRA_IPV4_ROUTE_ADD)
{
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv4 route add %s %s/%d nexthop %s metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL,
api.metric, api.type);
}
2002-12-13 21:15:29 +01:00
else
{
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv4 route delete %s %s/%d "
"nexthop %s metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_delete((struct prefix *)&p, api.type);
}
2002-12-13 21:15:29 +01:00
return 0;
}
#ifdef HAVE_IPV6
/* Zebra route add and delete treatment. */
static int
2002-12-13 21:15:29 +01:00
zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
{
struct stream *s;
struct zapi_ipv6 api;
struct in6_addr nexthop;
struct prefix_ipv6 p;
s = zclient->ibuf;
memset (&nexthop, 0, sizeof (struct in6_addr));
/* Type, flags, message. */
api.type = stream_getc (s);
api.flags = stream_getc (s);
api.message = stream_getc (s);
/* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6;
p.prefixlen = stream_getc (s);
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
{
api.nexthop_num = stream_getc (s);
stream_get (&nexthop, s, 16);
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))
{
api.ifindex_num = stream_getc (s);
stream_getl (s); /* ifindex, unused */
2002-12-13 21:15:29 +01:00
}
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))
api.distance = stream_getc (s);
else
api.distance = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC))
api.metric = stream_getl (s);
else
api.metric = 0;
/* Simply ignore link-local address. */
if (IN6_IS_ADDR_LINKLOCAL (&p.prefix))
return 0;
if (command == ZEBRA_IPV6_ROUTE_ADD)
{
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop,
api.metric, api.type);
}
2002-12-13 21:15:29 +01:00
else
{
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d "
"nexthop %s metric %u",
zebra_route_string(api.type),
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
bgp_redistribute_delete ((struct prefix *) &p, api.type);
}
2002-12-13 21:15:29 +01:00
return 0;
}
#endif /* HAVE_IPV6 */
2002-12-13 21:15:29 +01:00
struct interface *
if_lookup_by_ipv4 (struct in_addr *addr)
{
struct listnode *ifnode;
struct listnode *cnode;
2002-12-13 21:15:29 +01:00
struct interface *ifp;
struct connected *connected;
struct prefix_ipv4 p;
struct prefix *cp;
p.family = AF_INET;
p.prefix = *addr;
p.prefixlen = IPV4_MAX_BITLEN;
for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
2002-12-13 21:15:29 +01:00
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
2002-12-13 21:15:29 +01:00
{
cp = connected->address;
if (cp->family == AF_INET)
if (prefix_match (cp, (struct prefix *)&p))
return ifp;
}
}
return NULL;
}
struct interface *
if_lookup_by_ipv4_exact (struct in_addr *addr)
{
struct listnode *ifnode;
struct listnode *cnode;
2002-12-13 21:15:29 +01:00
struct interface *ifp;
struct connected *connected;
struct prefix *cp;
for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
2002-12-13 21:15:29 +01:00
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
2002-12-13 21:15:29 +01:00
{
cp = connected->address;
if (cp->family == AF_INET)
if (IPV4_ADDR_SAME (&cp->u.prefix4, addr))
return ifp;
}
}
return NULL;
}
#ifdef HAVE_IPV6
struct interface *
if_lookup_by_ipv6 (struct in6_addr *addr)
{
struct listnode *ifnode;
struct listnode *cnode;
2002-12-13 21:15:29 +01:00
struct interface *ifp;
struct connected *connected;
struct prefix_ipv6 p;
struct prefix *cp;
p.family = AF_INET6;
p.prefix = *addr;
p.prefixlen = IPV6_MAX_BITLEN;
for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
2002-12-13 21:15:29 +01:00
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
2002-12-13 21:15:29 +01:00
{
cp = connected->address;
if (cp->family == AF_INET6)
if (prefix_match (cp, (struct prefix *)&p))
return ifp;
}
}
return NULL;
}
struct interface *
if_lookup_by_ipv6_exact (struct in6_addr *addr)
{
struct listnode *ifnode;
struct listnode *cnode;
2002-12-13 21:15:29 +01:00
struct interface *ifp;
struct connected *connected;
struct prefix *cp;
for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
2002-12-13 21:15:29 +01:00
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
2002-12-13 21:15:29 +01:00
{
cp = connected->address;
if (cp->family == AF_INET6)
if (IPV6_ADDR_SAME (&cp->u.prefix6, addr))
return ifp;
}
}
return NULL;
}
static int
2002-12-13 21:15:29 +01:00
if_get_ipv6_global (struct interface *ifp, struct in6_addr *addr)
{
struct listnode *cnode;
2002-12-13 21:15:29 +01:00
struct connected *connected;
struct prefix *cp;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
2002-12-13 21:15:29 +01:00
{
cp = connected->address;
if (cp->family == AF_INET6)
if (! IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6))
{
memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
return 1;
}
}
return 0;
}
static int
2002-12-13 21:15:29 +01:00
if_get_ipv6_local (struct interface *ifp, struct in6_addr *addr)
{
struct listnode *cnode;
2002-12-13 21:15:29 +01:00
struct connected *connected;
struct prefix *cp;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
2002-12-13 21:15:29 +01:00
{
cp = connected->address;
if (cp->family == AF_INET6)
if (IN6_IS_ADDR_LINKLOCAL (&cp->u.prefix6))
{
memcpy (addr, &cp->u.prefix6, IPV6_MAX_BYTELEN);
return 1;
}
}
return 0;
}
#endif /* HAVE_IPV6 */
static int
if_get_ipv4_address (struct interface *ifp, struct in_addr *addr)
{
struct listnode *cnode;
struct connected *connected;
struct prefix *cp;
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
{
cp = connected->address;
if ((cp->family == AF_INET) && !ipv4_martian(&(cp->u.prefix4)))
{
*addr = cp->u.prefix4;
return 1;
}
}
return 0;
}
2002-12-13 21:15:29 +01:00
int
bgp_nexthop_set (union sockunion *local, union sockunion *remote,
struct bgp_nexthop *nexthop, struct peer *peer)
{
int ret = 0;
struct interface *ifp = NULL;
memset (nexthop, 0, sizeof (struct bgp_nexthop));
if (!local)
return -1;
if (!remote)
return -1;
if (local->sa.sa_family == AF_INET)
{
nexthop->v4 = local->sin.sin_addr;
ifp = if_lookup_by_ipv4 (&local->sin.sin_addr);
}
#ifdef HAVE_IPV6
if (local->sa.sa_family == AF_INET6)
{
if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
{
if (peer->ifname)
ifp = if_lookup_by_index (if_nametoindex (peer->ifname));
}
else
ifp = if_lookup_by_ipv6 (&local->sin6.sin6_addr);
}
#endif /* HAVE_IPV6 */
if (!ifp)
return -1;
nexthop->ifp = ifp;
/* IPv4 connection. */
if (local->sa.sa_family == AF_INET)
{
#ifdef HAVE_IPV6
/* IPv6 nexthop*/
ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
/* There is no global nexthop. */
if (!ret)
if_get_ipv6_local (ifp, &nexthop->v6_global);
else
if_get_ipv6_local (ifp, &nexthop->v6_local);
#endif /* HAVE_IPV6 */
}
#ifdef HAVE_IPV6
/* IPv6 connection. */
if (local->sa.sa_family == AF_INET6)
{
struct interface *direct = NULL;
/* IPv4 nexthop. */
ret = if_get_ipv4_address(ifp, &nexthop->v4);
if (!ret && peer->local_id.s_addr)
2002-12-13 21:15:29 +01:00
nexthop->v4 = peer->local_id;
/* Global address*/
if (! IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
{
memcpy (&nexthop->v6_global, &local->sin6.sin6_addr,
IPV6_MAX_BYTELEN);
/* If directory connected set link-local address. */
direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr);
if (direct)
if_get_ipv6_local (ifp, &nexthop->v6_local);
}
else
/* Link-local address. */
{
ret = if_get_ipv6_global (ifp, &nexthop->v6_global);
/* If there is no global address. Set link-local address as
global. I know this break RFC specification... */
if (!ret)
memcpy (&nexthop->v6_global, &local->sin6.sin6_addr,
IPV6_MAX_BYTELEN);
else
memcpy (&nexthop->v6_local, &local->sin6.sin6_addr,
IPV6_MAX_BYTELEN);
}
}
if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) ||
if_lookup_by_ipv6 (&remote->sin6.sin6_addr))
peer->shared_network = 1;
else
peer->shared_network = 0;
/* KAME stack specific treatment. */
#ifdef KAME
if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_global)
&& IN6_LINKLOCAL_IFINDEX (nexthop->v6_global))
{
SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_global, 0);
}
if (IN6_IS_ADDR_LINKLOCAL (&nexthop->v6_local)
&& IN6_LINKLOCAL_IFINDEX (nexthop->v6_local))
{
SET_IN6_LINKLOCAL_IFINDEX (nexthop->v6_local, 0);
}
#endif /* KAME */
#endif /* HAVE_IPV6 */
return ret;
}
void
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)
2002-12-13 21:15:29 +01:00
{
int flags;
u_char distance;
struct peer *peer;
struct bgp_info *mpinfo;
size_t oldsize, newsize;
u_int32_t nhcount;
2002-12-13 21:15:29 +01:00
if (zclient->sock < 0)
return;
if (! zclient->redist[ZEBRA_ROUTE_BGP])
return;
flags = 0;
peer = info->peer;
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED)
2002-12-13 21:15:29 +01:00
{
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
}
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
2002-12-13 21:15:29 +01:00
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
nhcount = 1 + bgp_info_mpath_count (info);
2002-12-13 21:15:29 +01:00
if (p->family == AF_INET)
{
struct zapi_ipv4 api;
struct in_addr *nexthop;
/* resize nexthop buffer size if necessary */
if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
(sizeof (struct in_addr *) * nhcount))
{
newsize = (sizeof (struct in_addr *) * nhcount);
newsize = stream_resize (bgp_nexthop_buf, newsize);
if (newsize == oldsize)
{
zlog_err ("can't resize nexthop buffer");
return;
}
}
stream_reset (bgp_nexthop_buf);
2002-12-13 21:15:29 +01:00
api.flags = flags;
nexthop = &info->attr->nexthop;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
{
nexthop = &mpinfo->attr->nexthop;
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in_addr *));
}
2002-12-13 21:15:29 +01:00
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
2002-12-13 21:15:29 +01:00
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = nhcount;
api.nexthop = (struct in_addr **)STREAM_DATA (bgp_nexthop_buf);
2002-12-13 21:15:29 +01:00
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
distance = bgp_distance_apply (p, info, bgp);
if (distance)
{
SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
api.distance = distance;
}
if (BGP_DEBUG(zebra, ZEBRA))
{
int i;
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra send: IPv4 route add %s/%d nexthop %s metric %u"
" count %d",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, api.nexthop[0], buf[1], sizeof(buf[1])),
api.metric, api.nexthop_num);
for (i = 1; i < api.nexthop_num; i++)
zlog_debug("Zebra send: IPv4 route add [nexthop %d] %s",
i, inet_ntop(AF_INET, api.nexthop[i], buf[1],
sizeof(buf[1])));
}
2004-05-08 Paul Jakma <paul@dishone.st> * bgp_zebra.c: (bgp_interface_address_add) sync to zclient changes (bgp_interface_address_delete) ditto. (bgp_zebra_announce) ditto. (bgp_zebra_withdraw) ditto. * isis_zebra.c: Sync with zclient changes. * zclient.c (zapi_ipv4_route) Follow Sowmini's lead and describe message format. * ospf6_zebra.c: Sync to zclient changes * ospf_zebra.c: Sync with lib/zclient changes * rip_zebra.c: sync with zclient changes. * rip_interface.c: ditto. * ripng_{interface,zebra}.c: sync with zclient changes 2004-05-08 Sowmini Varadhan <sowmini.varadhan@sun.com> * zclient.c: (zapi_ipv4_add) collapsed into zapi_ipv4_route (zapi_ipv4_delete) ditto. (zapi_ipv4_route) add/delete a route by way of cmd arg. (zapi_ipv6_add) collapsed into zapi_ipv6_route. (zapi_ipv6_delete) ditto. (zapi_ipv6_route) add/delete a route by way of cmd arg. (zebra_interface_address_delete_read) collapsed into zebra_interface_address_read. (zebra_interface_address_delete_read) ditto. (zebra_interface_address_read) read address add/delete messages by way of type argument. Describe command message format. (zebra_interface_add_read) Unconditionally read new ifmtu6 field. Describe command message format. (zebra_interface_state_read) Unconditionally read new ifmtu6 field. (zclient_redistribute_set) Collapsed into zclient_redistribute (zclient_redistribute_unset) ditto (zclient_redistribute) set/unset redistribution. (zclient_redistribute_default_set) Collapsed into zclient_redistribute_default. (zclient_redistribute_default_unset) ditto. (zclient_redistribute_default) Redistribute default set/unset. * zclient.h: delete zapi_ipv{4,6}_add, zapi_ipv{4,6}_delete. Add zapi_ipv{4,6}_route. delete zclient_redistribute_set/unset. Add zclient_redistribute. Ditto for zclient_redistribute_default_{set/unset}.
2004-05-08 13:48:26 +02:00
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient,
(struct prefix_ipv4 *) p, &api);
2002-12-13 21:15:29 +01:00
}
#ifdef HAVE_IPV6
2002-12-13 21:15:29 +01:00
/* We have to think about a IPv6 link-local address curse. */
if (p->family == AF_INET6)
{
unsigned int ifindex;
struct in6_addr *nexthop;
struct zapi_ipv6 api;
int valid_nh_count = 0;
/* resize nexthop buffer size if necessary */
if ((oldsize = stream_get_size (bgp_nexthop_buf)) <
(sizeof (struct in6_addr *) * nhcount))
{
newsize = (sizeof (struct in6_addr *) * nhcount);
newsize = stream_resize (bgp_nexthop_buf, newsize);
if (newsize == oldsize)
{
zlog_err ("can't resize nexthop buffer");
return;
}
}
stream_reset (bgp_nexthop_buf);
/* resize ifindices buffer size if necessary */
if ((oldsize = stream_get_size (bgp_ifindices_buf)) <
(sizeof (unsigned int) * nhcount))
{
newsize = (sizeof (unsigned int) * nhcount);
newsize = stream_resize (bgp_ifindices_buf, newsize);
if (newsize == oldsize)
{
zlog_err ("can't resize nexthop buffer");
return;
}
}
stream_reset (bgp_ifindices_buf);
2002-12-13 21:15:29 +01:00
ifindex = 0;
nexthop = NULL;
assert (info->attr->extra);
2002-12-13 21:15:29 +01:00
/* Only global address nexthop exists. */
if (info->attr->extra->mp_nexthop_len == 16)
nexthop = &info->attr->extra->mp_nexthop_global;
2002-12-13 21:15:29 +01:00
/* If both global and link-local address present. */
if (info->attr->extra->mp_nexthop_len == 32)
2002-12-13 21:15:29 +01:00
{
/* Workaround for Cisco's nexthop bug. */
if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
2002-12-13 21:15:29 +01:00
&& peer->su_remote->sa.sa_family == AF_INET6)
nexthop = &peer->su_remote->sin6.sin6_addr;
else
nexthop = &info->attr->extra->mp_nexthop_local;
2002-12-13 21:15:29 +01:00
if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
if (nexthop == NULL)
return;
if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
{
if (info->peer->ifname)
ifindex = if_nametoindex (info->peer->ifname);
else if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
valid_nh_count++;
for (mpinfo = bgp_info_mpath_first (info); mpinfo;
mpinfo = bgp_info_mpath_next (mpinfo))
{
/* Only global address nexthop exists. */
if (mpinfo->attr->extra->mp_nexthop_len == 16)
{
nexthop = &mpinfo->attr->extra->mp_nexthop_global;
}
/* If both global and link-local address present. */
if (mpinfo->attr->extra->mp_nexthop_len == 32)
{
/* Workaround for Cisco's nexthop bug. */
if (IN6_IS_ADDR_UNSPECIFIED (&mpinfo->attr->extra->mp_nexthop_global)
&& mpinfo->peer->su_remote->sa.sa_family == AF_INET6)
{
nexthop = &mpinfo->peer->su_remote->sin6.sin6_addr;
}
else
{
nexthop = &mpinfo->attr->extra->mp_nexthop_local;
}
if (mpinfo->peer->nexthop.ifp)
{
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
}
}
if (nexthop == NULL)
{
continue;
}
if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
{
if (mpinfo->peer->ifname)
{
ifindex = if_nametoindex (mpinfo->peer->ifname);
}
else if (mpinfo->peer->nexthop.ifp)
{
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
}
}
if (ifindex == 0)
{
continue;
}
stream_put (bgp_nexthop_buf, &nexthop, sizeof (struct in6_addr *));
stream_put (bgp_ifindices_buf, &ifindex, sizeof (unsigned int));
valid_nh_count++;
}
2002-12-13 21:15:29 +01:00
/* Make Zebra API structure. */
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
2002-12-13 21:15:29 +01:00
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = valid_nh_count;
api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf);
2002-12-13 21:15:29 +01:00
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = valid_nh_count;
api.ifindex = (unsigned int *)STREAM_DATA (bgp_ifindices_buf);
2002-12-13 21:15:29 +01:00
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra send: IPv6 route add %s/%d nexthop %s metric %u",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
2004-05-08 Paul Jakma <paul@dishone.st> * bgp_zebra.c: (bgp_interface_address_add) sync to zclient changes (bgp_interface_address_delete) ditto. (bgp_zebra_announce) ditto. (bgp_zebra_withdraw) ditto. * isis_zebra.c: Sync with zclient changes. * zclient.c (zapi_ipv4_route) Follow Sowmini's lead and describe message format. * ospf6_zebra.c: Sync to zclient changes * ospf_zebra.c: Sync with lib/zclient changes * rip_zebra.c: sync with zclient changes. * rip_interface.c: ditto. * ripng_{interface,zebra}.c: sync with zclient changes 2004-05-08 Sowmini Varadhan <sowmini.varadhan@sun.com> * zclient.c: (zapi_ipv4_add) collapsed into zapi_ipv4_route (zapi_ipv4_delete) ditto. (zapi_ipv4_route) add/delete a route by way of cmd arg. (zapi_ipv6_add) collapsed into zapi_ipv6_route. (zapi_ipv6_delete) ditto. (zapi_ipv6_route) add/delete a route by way of cmd arg. (zebra_interface_address_delete_read) collapsed into zebra_interface_address_read. (zebra_interface_address_delete_read) ditto. (zebra_interface_address_read) read address add/delete messages by way of type argument. Describe command message format. (zebra_interface_add_read) Unconditionally read new ifmtu6 field. Describe command message format. (zebra_interface_state_read) Unconditionally read new ifmtu6 field. (zclient_redistribute_set) Collapsed into zclient_redistribute (zclient_redistribute_unset) ditto (zclient_redistribute) set/unset redistribution. (zclient_redistribute_default_set) Collapsed into zclient_redistribute_default. (zclient_redistribute_default_unset) ditto. (zclient_redistribute_default) Redistribute default set/unset. * zclient.h: delete zapi_ipv{4,6}_add, zapi_ipv{4,6}_delete. Add zapi_ipv{4,6}_route. delete zclient_redistribute_set/unset. Add zclient_redistribute. Ditto for zclient_redistribute_default_{set/unset}.
2004-05-08 13:48:26 +02:00
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient,
(struct prefix_ipv6 *) p, &api);
2002-12-13 21:15:29 +01:00
}
#endif /* HAVE_IPV6 */
}
void
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
2002-12-13 21:15:29 +01:00
{
int flags;
struct peer *peer;
if (zclient->sock < 0)
return;
if (! zclient->redist[ZEBRA_ROUTE_BGP])
return;
peer = info->peer;
flags = 0;
if (peer->sort == BGP_PEER_IBGP)
2002-12-13 21:15:29 +01:00
{
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
SET_FLAG (flags, ZEBRA_FLAG_IBGP);
}
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
2002-12-13 21:15:29 +01:00
SET_FLAG (flags, ZEBRA_FLAG_INTERNAL);
if (p->family == AF_INET)
{
struct zapi_ipv4 api;
struct in_addr *nexthop;
api.flags = flags;
nexthop = &info->attr->nexthop;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
2002-12-13 21:15:29 +01:00
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET_ADDRSTRLEN];
zlog_debug("Zebra send: IPv4 route delete %s/%d nexthop %s metric %u",
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET, nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
2004-05-08 Paul Jakma <paul@dishone.st> * bgp_zebra.c: (bgp_interface_address_add) sync to zclient changes (bgp_interface_address_delete) ditto. (bgp_zebra_announce) ditto. (bgp_zebra_withdraw) ditto. * isis_zebra.c: Sync with zclient changes. * zclient.c (zapi_ipv4_route) Follow Sowmini's lead and describe message format. * ospf6_zebra.c: Sync to zclient changes * ospf_zebra.c: Sync with lib/zclient changes * rip_zebra.c: sync with zclient changes. * rip_interface.c: ditto. * ripng_{interface,zebra}.c: sync with zclient changes 2004-05-08 Sowmini Varadhan <sowmini.varadhan@sun.com> * zclient.c: (zapi_ipv4_add) collapsed into zapi_ipv4_route (zapi_ipv4_delete) ditto. (zapi_ipv4_route) add/delete a route by way of cmd arg. (zapi_ipv6_add) collapsed into zapi_ipv6_route. (zapi_ipv6_delete) ditto. (zapi_ipv6_route) add/delete a route by way of cmd arg. (zebra_interface_address_delete_read) collapsed into zebra_interface_address_read. (zebra_interface_address_delete_read) ditto. (zebra_interface_address_read) read address add/delete messages by way of type argument. Describe command message format. (zebra_interface_add_read) Unconditionally read new ifmtu6 field. Describe command message format. (zebra_interface_state_read) Unconditionally read new ifmtu6 field. (zclient_redistribute_set) Collapsed into zclient_redistribute (zclient_redistribute_unset) ditto (zclient_redistribute) set/unset redistribution. (zclient_redistribute_default_set) Collapsed into zclient_redistribute_default. (zclient_redistribute_default_unset) ditto. (zclient_redistribute_default) Redistribute default set/unset. * zclient.h: delete zapi_ipv{4,6}_add, zapi_ipv{4,6}_delete. Add zapi_ipv{4,6}_route. delete zclient_redistribute_set/unset. Add zclient_redistribute. Ditto for zclient_redistribute_default_{set/unset}.
2004-05-08 13:48:26 +02:00
zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient,
(struct prefix_ipv4 *) p, &api);
2002-12-13 21:15:29 +01:00
}
#ifdef HAVE_IPV6
/* We have to think about a IPv6 link-local address curse. */
if (p->family == AF_INET6)
{
struct zapi_ipv6 api;
unsigned int ifindex;
struct in6_addr *nexthop;
assert (info->attr->extra);
2002-12-13 21:15:29 +01:00
ifindex = 0;
nexthop = NULL;
/* Only global address nexthop exists. */
if (info->attr->extra->mp_nexthop_len == 16)
nexthop = &info->attr->extra->mp_nexthop_global;
2002-12-13 21:15:29 +01:00
/* If both global and link-local address present. */
if (info->attr->extra->mp_nexthop_len == 32)
2002-12-13 21:15:29 +01:00
{
nexthop = &info->attr->extra->mp_nexthop_local;
2002-12-13 21:15:29 +01:00
if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
if (nexthop == NULL)
return;
if (IN6_IS_ADDR_LINKLOCAL (nexthop) && ! ifindex)
if (info->peer->ifname)
ifindex = if_nametoindex (info->peer->ifname);
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.message = 0;
api.safi = safi;
2002-12-13 21:15:29 +01:00
SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
api.nexthop = &nexthop;
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = 1;
api.ifindex = &ifindex;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
if (BGP_DEBUG(zebra, ZEBRA))
{
char buf[2][INET6_ADDRSTRLEN];
zlog_debug("Zebra send: IPv6 route delete %s/%d nexthop %s metric %u",
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen,
inet_ntop(AF_INET6, nexthop, buf[1], sizeof(buf[1])),
api.metric);
}
2004-05-08 Paul Jakma <paul@dishone.st> * bgp_zebra.c: (bgp_interface_address_add) sync to zclient changes (bgp_interface_address_delete) ditto. (bgp_zebra_announce) ditto. (bgp_zebra_withdraw) ditto. * isis_zebra.c: Sync with zclient changes. * zclient.c (zapi_ipv4_route) Follow Sowmini's lead and describe message format. * ospf6_zebra.c: Sync to zclient changes * ospf_zebra.c: Sync with lib/zclient changes * rip_zebra.c: sync with zclient changes. * rip_interface.c: ditto. * ripng_{interface,zebra}.c: sync with zclient changes 2004-05-08 Sowmini Varadhan <sowmini.varadhan@sun.com> * zclient.c: (zapi_ipv4_add) collapsed into zapi_ipv4_route (zapi_ipv4_delete) ditto. (zapi_ipv4_route) add/delete a route by way of cmd arg. (zapi_ipv6_add) collapsed into zapi_ipv6_route. (zapi_ipv6_delete) ditto. (zapi_ipv6_route) add/delete a route by way of cmd arg. (zebra_interface_address_delete_read) collapsed into zebra_interface_address_read. (zebra_interface_address_delete_read) ditto. (zebra_interface_address_read) read address add/delete messages by way of type argument. Describe command message format. (zebra_interface_add_read) Unconditionally read new ifmtu6 field. Describe command message format. (zebra_interface_state_read) Unconditionally read new ifmtu6 field. (zclient_redistribute_set) Collapsed into zclient_redistribute (zclient_redistribute_unset) ditto (zclient_redistribute) set/unset redistribution. (zclient_redistribute_default_set) Collapsed into zclient_redistribute_default. (zclient_redistribute_default_unset) ditto. (zclient_redistribute_default) Redistribute default set/unset. * zclient.h: delete zapi_ipv{4,6}_add, zapi_ipv{4,6}_delete. Add zapi_ipv{4,6}_route. delete zclient_redistribute_set/unset. Add zclient_redistribute. Ditto for zclient_redistribute_default_{set/unset}.
2004-05-08 13:48:26 +02:00
zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient,
(struct prefix_ipv6 *) p, &api);
2002-12-13 21:15:29 +01:00
}
#endif /* HAVE_IPV6 */
}
2002-12-13 21:15:29 +01:00
/* Other routes redistribution into BGP. */
int
bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type)
{
/* Set flag to BGP instance. */
bgp->redist[afi][type] = 1;
/* Return if already redistribute flag is set. */
if (zclient->redist[type])
return CMD_WARNING;
zclient->redist[type] = 1;
/* Return if zebra connection is not established. */
if (zclient->sock < 0)
return CMD_WARNING;
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Zebra send: redistribute add %s", zebra_route_string(type));
2002-12-13 21:15:29 +01:00
/* Send distribute add message to zebra. */
2005-04-11 Andrew J. Schorr <ajschorr@alumni.princeton.edu> Implement non-blocking zclient I/O with buffering. * zclient.h (struct zclient): Add two fields to support non-blocking I/O: struct buffer *wb, and struct thread *t_write. (zclient_free): Remove function. (zebra_redistribute_send): Change 2nd arg from socket fd to struct zclient * (needed to support non-blocking I/O and buffering). (zclient_send_message): New function to send an arbitrary message with non-blocking I/O. * zclient.c (zclient_new): Create write buffer. (zclient_free): Remove unused function. (zclient_stop): Must cancel new t_write thread. Also, reset all buffers: ibuf, obuf, and wb. (zclient_failed): New helper function for typical error handling. (zclient_flush_data): New thread to flush queued data. (zclient_send_message): New function to send the message in zclient->obuf to zebra using non-blocking I/O and buffering. (zebra_message_send, zapi_ipv4_route, zapi_ipv6_route): Use new zclient_send_message function instead of calling writen. (zclient_start): Set socket non-blocking. Also, change 2nd arg to zebra_redistribute_send from zclient->sock to zclient. (zebra_redistribute_send): Change 2nd arg to struct zclient *. Can now use zclient->obuf to assemble the message instead of allocating a temporary stream. And call zclient_send_message to send the message instead of writen. (zclient_read): Convert to support non-blocking I/O by using stream_read_try instead of deprecated stream_read. (zclient_redistribute): Change 2nd arg to zebra_redistribute_send from zclient->sock to zclient. * ospf6_zebra.c (ospf6_zebra_redistribute, ospf6_zebra_no_redistribute): Change 2nd arg to zebra_redistribute_send from zclient->sock to zclient. * ospf_zebra.c (ospf_zebra_add): Call zclient_send_message instead of writen. * rip_zebra.c (rip_redistribute_set, rip_redistribute_unset, rip_redistribute_clean): Change 2nd arg to zebra_redistribute_send from zclient->sock to zclient. * ripng_zebra.c (ripng_redistribute_unset, ripng_redistribute_clean): Change 2nd arg to zebra_redistribute_send from zclient->sock to zclient. * bgp_zebra.c (bgp_redistribute_set, bgp_redistribute_unset): The 2nd arg to zebra_redistribute_send is now zclient instead of zclient->sock. * isis_zebra.h (isis_zebra_finish): Remove declaration of unused function. * isis_zebra.c (isis_zebra_route_add_ipv4): Call zclient_send_message to send the message to zebra instead of calling writen directly, since zclient_send_message understands non-blocking I/O and will manage the buffer queue appropriately. (isis_zebra_finish): Remove unused function, particularly since the zclient_free function has been removed.
2005-04-11 17:51:40 +02:00
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
2002-12-13 21:15:29 +01:00
return CMD_SUCCESS;
}
/* Redistribute with route-map specification. */
int
bgp_redistribute_rmap_set (struct bgp *bgp, afi_t afi, int type,
const char *name)
2002-12-13 21:15:29 +01:00
{
if (bgp->rmap[afi][type].name
&& (strcmp (bgp->rmap[afi][type].name, name) == 0))
return 0;
if (bgp->rmap[afi][type].name)
free (bgp->rmap[afi][type].name);
bgp->rmap[afi][type].name = strdup (name);
bgp->rmap[afi][type].map = route_map_lookup_by_name (name);
return 1;
}
/* Redistribute with metric specification. */
int
bgp_redistribute_metric_set (struct bgp *bgp, afi_t afi, int type,
u_int32_t metric)
{
if (bgp->redist_metric_flag[afi][type]
&& bgp->redist_metric[afi][type] == metric)
return 0;
bgp->redist_metric_flag[afi][type] = 1;
bgp->redist_metric[afi][type] = metric;
return 1;
}
/* Unset redistribution. */
int
bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type)
{
/* Unset flag from BGP instance. */
bgp->redist[afi][type] = 0;
/* Unset route-map. */
if (bgp->rmap[afi][type].name)
free (bgp->rmap[afi][type].name);
bgp->rmap[afi][type].name = NULL;
bgp->rmap[afi][type].map = NULL;
/* Unset metric. */
bgp->redist_metric_flag[afi][type] = 0;
bgp->redist_metric[afi][type] = 0;
/* Return if zebra connection is disabled. */
if (! zclient->redist[type])
return CMD_WARNING;
zclient->redist[type] = 0;
if (bgp->redist[AFI_IP][type] == 0
&& bgp->redist[AFI_IP6][type] == 0
&& zclient->sock >= 0)
{
/* Send distribute delete message to zebra. */
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Zebra send: redistribute delete %s",
zebra_route_string(type));
zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
}
2002-12-13 21:15:29 +01:00
/* Withdraw redistributed routes from current BGP's routing table. */
bgp_redistribute_withdraw (bgp, afi, type);
return CMD_SUCCESS;
}
/* Unset redistribution route-map configuration. */
int
bgp_redistribute_routemap_unset (struct bgp *bgp, afi_t afi, int type)
{
if (! bgp->rmap[afi][type].name)
return 0;
/* Unset route-map. */
free (bgp->rmap[afi][type].name);
bgp->rmap[afi][type].name = NULL;
bgp->rmap[afi][type].map = NULL;
return 1;
}
/* Unset redistribution metric configuration. */
int
bgp_redistribute_metric_unset (struct bgp *bgp, afi_t afi, int type)
{
if (! bgp->redist_metric_flag[afi][type])
return 0;
/* Unset metric. */
bgp->redist_metric_flag[afi][type] = 0;
bgp->redist_metric[afi][type] = 0;
return 1;
}
2002-12-13 21:15:29 +01:00
void
bgp_zclient_reset (void)
2002-12-13 21:15:29 +01:00
{
zclient_reset (zclient);
}
void
bgp_zebra_init (void)
2002-12-13 21:15:29 +01:00
{
/* Set default values. */
zclient = zclient_new ();
zclient_init (zclient, ZEBRA_ROUTE_BGP);
2004-10-03 20:18:34 +02:00
zclient->router_id_update = bgp_router_id_update;
2002-12-13 21:15:29 +01:00
zclient->interface_add = bgp_interface_add;
zclient->interface_delete = bgp_interface_delete;
zclient->interface_address_add = bgp_interface_address_add;
zclient->interface_address_delete = bgp_interface_address_delete;
zclient->ipv4_route_add = zebra_read_ipv4;
zclient->ipv4_route_delete = zebra_read_ipv4;
zclient->interface_up = bgp_interface_up;
zclient->interface_down = bgp_interface_down;
#ifdef HAVE_IPV6
zclient->ipv6_route_add = zebra_read_ipv6;
zclient->ipv6_route_delete = zebra_read_ipv6;
#endif /* HAVE_IPV6 */
/* Interface related init. */
if_init ();
bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
2002-12-13 21:15:29 +01:00
}