#include "queue.h"
#include "memory.h"
#include "lib/json.h"
+#include "lib/bfd.h"
+#include "filter.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_bfd.h"
+#if ENABLE_BGP_VNC
+# include "bgpd/rfapi/rfapi_backend.h"
+# include "bgpd/rfapi/vnc_export_bgp.h"
+#endif
/* All information about zebra. */
struct zclient *zclient = NULL;
-struct in_addr router_id_zebra;
/* Growable buffer for nexthops sent to zebra */
struct stream *bgp_nexthop_buf = NULL;
1. maintain a linked-list and free it after zapi_*_route call
2. use an array to avoid number of mallocs.
Number of supported next-hops are finite, use of arrays should be ok. */
-struct attr attr_cp[BGP_MAXIMUM_MAXPATHS];
-struct attr_extra attr_extra_cp[BGP_MAXIMUM_MAXPATHS];
+struct attr attr_cp[MULTIPATH_NUM];
+struct attr_extra attr_extra_cp[MULTIPATH_NUM];
int attr_index = 0;
/* Once per address-family initialization of the attribute array */
#define BGP_INFO_ATTR_BUF_INIT()\
do {\
- memset(attr_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr));\
- memset(attr_extra_cp, 0, BGP_MAXIMUM_MAXPATHS * sizeof(struct attr_extra));\
+ memset(attr_cp, 0, MULTIPATH_NUM * sizeof(struct attr));\
+ memset(attr_extra_cp, 0, MULTIPATH_NUM * sizeof(struct attr_extra));\
attr_index = 0;\
} while (0)
#define BGP_INFO_ATTR_BUF_COPY(info_src, info_dst)\
do { \
*info_dst = *info_src; \
- assert(attr_index != BGP_MAXIMUM_MAXPATHS);\
+ assert(attr_index != MULTIPATH_NUM);\
attr_cp[attr_index].extra = &attr_extra_cp[attr_index]; \
bgp_attr_dup (&attr_cp[attr_index], info_src->attr); \
bgp_attr_deep_dup (&attr_cp[attr_index], info_src->attr); \
bgp_attr_deep_free(info->attr); \
} while (0)
+
+/* Can we install into zebra? */
+static inline int
+bgp_install_info_to_zebra (struct bgp *bgp)
+{
+ if (zclient->sock <= 0)
+ return 0;
+
+ if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ return 0;
+
+ return 1;
+}
+
+int zclient_num_connects;
+
/* Router-id update message from zebra. */
static int
-bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length)
+bgp_router_id_update (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
{
struct prefix router_id;
- struct listnode *node, *nnode;
- struct bgp *bgp;
zebra_router_id_update_read(zclient->ibuf,&router_id);
if (BGP_DEBUG (zebra, ZEBRA))
{
- char buf[128];
+ char buf[PREFIX2STR_BUFFER];
prefix2str(&router_id, buf, sizeof(buf));
- zlog_debug("Zebra rcvd: router id update %s", buf);
- }
-
- router_id_zebra = router_id.u.prefix4;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
- {
- if (!bgp->router_id_static.s_addr)
- bgp_router_id_set (bgp, &router_id.u.prefix4);
+ zlog_debug("Rx Router Id update VRF %u Id %s", vrf_id, buf);
}
+ bgp_router_id_zebra_bump (vrf_id, &router_id);
return 0;
}
/* Nexthop update message from zebra. */
static int
bgp_read_nexthop_update (int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
- bgp_parse_nexthop_update(command);
+ bgp_parse_nexthop_update(command, vrf_id);
return 0;
}
static int
bgp_read_import_check_update(int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
- bgp_parse_nexthop_update(command);
+ bgp_parse_nexthop_update(command, vrf_id);
return 0;
}
+/* Set or clear interface on which unnumbered neighbor is configured. This
+ * would in turn cause BGP to initiate or turn off IPv6 RAs on this
+ * interface.
+ */
static void
-bgp_start_interface_nbrs (struct interface *ifp)
+bgp_update_interface_nbrs (struct bgp *bgp, struct interface *ifp,
+ struct interface *upd_ifp)
{
- struct listnode *node, *nnode, *mnode;
- struct bgp *bgp;
+ struct listnode *node, *nnode;
struct peer *peer;
- for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (peer->conf_if &&
+ (strcmp (peer->conf_if, ifp->name) == 0))
{
- if (peer->conf_if &&
- (strcmp (peer->conf_if, ifp->name) == 0) &&
- peer->status != Established)
- {
- if (peer_active(peer))
- BGP_EVENT_ADD (peer, BGP_Stop);
- BGP_EVENT_ADD (peer, BGP_Start);
- }
+ if (upd_ifp)
+ {
+ peer->ifp = upd_ifp;
+ bgp_zebra_initiate_radv (bgp, peer);
+ }
+ else
+ {
+ bgp_zebra_terminate_radv (bgp, peer);
+ peer->ifp = upd_ifp;
+ }
+ }
+ }
+}
+
+static void
+bgp_start_interface_nbrs (struct bgp *bgp, struct interface *ifp)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if (peer->conf_if &&
+ (strcmp (peer->conf_if, ifp->name) == 0) &&
+ peer->status != Established)
+ {
+ if (peer_active(peer))
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ BGP_EVENT_ADD (peer, BGP_Start);
}
}
}
static void
-bgp_nbr_connected_add (struct nbr_connected *ifc)
+bgp_nbr_connected_add (struct bgp *bgp, struct nbr_connected *ifc)
{
struct listnode *node;
struct connected *connected;
if (!connected)
return;
- bgp_start_interface_nbrs (ifp);
+ bgp_start_interface_nbrs (bgp, ifp);
}
static void
-bgp_nbr_connected_delete (struct nbr_connected *ifc, int del)
+bgp_nbr_connected_delete (struct bgp *bgp, struct nbr_connected *ifc, int del)
{
- struct listnode *node, *nnode, *mnode;
- struct bgp *bgp;
+ struct listnode *node, *nnode;
struct peer *peer;
struct interface *ifp;
- for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
{
- if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0))
- {
- BGP_EVENT_ADD (peer, BGP_Stop);
- }
+ peer->last_reset = PEER_DOWN_NBR_ADDR_DEL;
+ BGP_EVENT_ADD (peer, BGP_Stop);
}
}
/* Free neighbor also, if we're asked to. */
/* Inteface addition message from zebra. */
static int
-bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length)
+bgp_interface_add (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
{
struct interface *ifp;
+ struct bgp *bgp;
- ifp = zebra_interface_add_read (zclient->ibuf);
+ ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
+ if (!ifp) // unexpected
+ return 0;
if (BGP_DEBUG (zebra, ZEBRA) && ifp)
- zlog_debug("Zebra rcvd: interface add %s", ifp->name);
+ zlog_debug("Rx Intf add VRF %u IF %s", vrf_id, ifp->name);
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
+ bgp_update_interface_nbrs (bgp, ifp, ifp);
return 0;
}
static int
bgp_interface_delete (int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
struct stream *s;
struct interface *ifp;
+ struct bgp *bgp;
s = zclient->ibuf;
- ifp = zebra_interface_state_read (s);
- ifp->ifindex = IFINDEX_INTERNAL;
+ ifp = zebra_interface_state_read (s, vrf_id);
+ if (!ifp) /* This may happen if we've just unregistered for a VRF. */
+ return 0;
+
+ ifp->ifindex = IFINDEX_DELETED;
if (BGP_DEBUG (zebra, ZEBRA))
- zlog_debug("Zebra rcvd: interface delete %s", ifp->name);
+ zlog_debug("Rx Intf del VRF %u IF %s", vrf_id, ifp->name);
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
+ bgp_update_interface_nbrs (bgp, ifp, NULL);
return 0;
}
static int
-bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length)
+bgp_interface_up (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
{
struct stream *s;
struct interface *ifp;
struct connected *c;
struct nbr_connected *nc;
struct listnode *node, *nnode;
+ struct bgp *bgp;
s = zclient->ibuf;
- ifp = zebra_interface_state_read (s);
+ ifp = zebra_interface_state_read (s, vrf_id);
if (! ifp)
return 0;
if (BGP_DEBUG (zebra, ZEBRA))
- zlog_debug("Zebra rcvd: interface %s up", ifp->name);
+ zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name);
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
- bgp_connected_add (c);
+ bgp_connected_add (bgp, c);
for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
- bgp_nbr_connected_add (nc);
+ bgp_nbr_connected_add (bgp, nc);
return 0;
}
static int
-bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length)
+bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
{
struct stream *s;
struct interface *ifp;
struct connected *c;
struct nbr_connected *nc;
struct listnode *node, *nnode;
+ struct bgp *bgp;
s = zclient->ibuf;
- ifp = zebra_interface_state_read (s);
+ ifp = zebra_interface_state_read (s, vrf_id);
if (! ifp)
return 0;
if (BGP_DEBUG (zebra, ZEBRA))
- zlog_debug("Zebra rcvd: interface %s down", ifp->name);
+ zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name);
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
- bgp_connected_delete (c);
+ bgp_connected_delete (bgp, c);
for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
- bgp_nbr_connected_delete (nc, 1);
+ bgp_nbr_connected_delete (bgp, nc, 1);
/* Fast external-failover */
{
- struct listnode *mnode;
- struct bgp *bgp;
struct peer *peer;
- for (ALL_LIST_ELEMENTS_RO (bm->bgp, mnode, bgp))
- {
- if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
- continue;
-
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
- continue;
+ if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+ return 0;
- if (ifp == peer->nexthop.ifp)
- BGP_EVENT_ADD (peer, BGP_Stop);
- }
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+#if defined(HAVE_CUMULUS)
+ /* Take down directly connected EBGP peers as well as 1-hop BFD
+ * tracked (directly connected) IBGP peers.
+ */
+ if ((peer->ttl != 1) && (peer->gtsm_hops != 1) &&
+ (!peer->bfd_info || bgp_bfd_is_peer_multihop(peer)))
+#else
+ /* Take down directly connected EBGP peers */
+ if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
+#endif
+ continue;
+
+ if (ifp == peer->nexthop.ifp)
+ {
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ peer->last_reset = PEER_DOWN_IF_DOWN;
+ }
}
}
static int
bgp_interface_address_add (int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
struct connected *ifc;
- ifc = zebra_interface_address_read (command, zclient->ibuf);
+ ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
if (ifc == NULL)
return 0;
if (bgp_debug_zebra(ifc->address))
{
- char buf[128];
+ char buf[PREFIX2STR_BUFFER];
prefix2str(ifc->address, buf, sizeof(buf));
- zlog_debug("Zebra rcvd: interface %s address add %s",
- ifc->ifp->name, buf);
+ zlog_debug("Rx Intf address add VRF %u IF %s addr %s",
+ vrf_id, ifc->ifp->name, buf);
}
if (if_is_operative (ifc->ifp))
{
- bgp_connected_add (ifc);
+ struct bgp *bgp;
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
+
+ bgp_connected_add (bgp, ifc);
/* If we have learnt of any neighbors on this interface,
* check to kick off any BGP interface-based neighbors,
* but only if this is a link-local address.
*/
if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) &&
!list_isempty(ifc->ifp->nbr_connected))
- bgp_start_interface_nbrs (ifc->ifp);
+ bgp_start_interface_nbrs (bgp, ifc->ifp);
}
return 0;
static int
bgp_interface_address_delete (int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
struct connected *ifc;
+ struct bgp *bgp;
- ifc = zebra_interface_address_read (command, zclient->ibuf);
+ ifc = zebra_interface_address_read (command, zclient->ibuf, vrf_id);
if (ifc == NULL)
return 0;
if (bgp_debug_zebra(ifc->address))
{
- char buf[128];
+ char buf[PREFIX2STR_BUFFER];
prefix2str(ifc->address, buf, sizeof(buf));
- zlog_debug("Zebra rcvd: interface %s address delete %s",
- ifc->ifp->name, buf);
+ zlog_debug("Rx Intf address del VRF %u IF %s addr %s",
+ vrf_id, ifc->ifp->name, buf);
}
if (if_is_operative (ifc->ifp))
- bgp_connected_delete (ifc);
+ {
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (bgp)
+ bgp_connected_delete (bgp, ifc);
+ }
connected_free (ifc);
static int
bgp_interface_nbr_address_add (int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
struct nbr_connected *ifc = NULL;
+ struct bgp *bgp;
- ifc = zebra_interface_nbr_address_read (command, zclient->ibuf);
+ ifc = zebra_interface_nbr_address_read (command, zclient->ibuf, vrf_id);
if (ifc == NULL)
return 0;
if (bgp_debug_zebra(ifc->address))
{
- char buf[128];
+ char buf[PREFIX2STR_BUFFER];
prefix2str(ifc->address, buf, sizeof(buf));
- zlog_debug("Zebra rcvd: interface %s nbr address add %s",
- ifc->ifp->name, buf);
+ zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %s",
+ vrf_id, ifc->ifp->name, buf);
}
if (if_is_operative (ifc->ifp))
- bgp_nbr_connected_add (ifc);
+ {
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (bgp)
+ bgp_nbr_connected_add (bgp, ifc);
+ }
return 0;
}
static int
bgp_interface_nbr_address_delete (int command, struct zclient *zclient,
- zebra_size_t length)
+ zebra_size_t length, vrf_id_t vrf_id)
{
struct nbr_connected *ifc = NULL;
+ struct bgp *bgp;
- ifc = zebra_interface_nbr_address_read (command, zclient->ibuf);
+ ifc = zebra_interface_nbr_address_read (command, zclient->ibuf, vrf_id);
if (ifc == NULL)
return 0;
if (bgp_debug_zebra(ifc->address))
{
- char buf[128];
+ char buf[PREFIX2STR_BUFFER];
prefix2str(ifc->address, buf, sizeof(buf));
- zlog_debug("Zebra rcvd: interface %s nbr address delete %s",
- ifc->ifp->name, buf);
+ zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %s",
+ vrf_id, ifc->ifp->name, buf);
}
if (if_is_operative (ifc->ifp))
- bgp_nbr_connected_delete (ifc, 0);
+ {
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (bgp)
+ bgp_nbr_connected_delete (bgp, ifc, 0);
+ }
nbr_connected_free (ifc);
return 0;
}
+/* VRF update for an interface. */
+static int
+bgp_interface_vrf_update (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
+{
+ struct interface *ifp;
+ vrf_id_t new_vrf_id;
+ struct connected *c;
+ struct nbr_connected *nc;
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ ifp = zebra_interface_vrf_update_read (zclient->ibuf, vrf_id, &new_vrf_id);
+ if (! ifp)
+ return 0;
+
+ if (BGP_DEBUG (zebra, ZEBRA) && ifp)
+ zlog_debug("Rx Intf VRF change VRF %u IF %s NewVRF %u",
+ vrf_id, ifp->name, new_vrf_id);
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
+ bgp_connected_delete (bgp, c);
+
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+ bgp_nbr_connected_delete (bgp, nc, 1);
+
+ /* Fast external-failover */
+ {
+ struct peer *peer;
+
+ if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+ return 0;
+
+ for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
+ {
+ if ((peer->ttl != 1) && (peer->gtsm_hops != 1))
+ continue;
+
+ if (ifp == peer->nexthop.ifp)
+ BGP_EVENT_ADD (peer, BGP_Stop);
+ }
+ }
+
+ if_update_vrf (ifp, ifp->name, strlen (ifp->name), new_vrf_id);
+
+ bgp = bgp_lookup_by_vrf_id (new_vrf_id);
+ if (!bgp)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, c))
+ bgp_connected_add (bgp, c);
+
+ for (ALL_LIST_ELEMENTS (ifp->nbr_connected, node, nnode, nc))
+ bgp_nbr_connected_add (bgp, nc);
+ return 0;
+}
+
/* Zebra route add and delete treatment. */
static int
-zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)
+zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv4 api;
struct prefix_ipv4 p;
unsigned int ifindex;
int i;
+ struct bgp *bgp;
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
s = zclient->ibuf;
nexthop.s_addr = 0;
/* Type, flags, message. */
api.type = stream_getc (s);
api.instance = stream_getw (s);
- api.flags = stream_getc (s);
+ api.flags = stream_getl (s);
api.message = stream_getc (s);
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET;
- p.prefixlen = stream_getc (s);
+ p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */
api.metric = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getw (s);
+ api.tag = stream_getl (s);
else
api.tag = 0;
if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv4 route add %s[%d] %s/%d nexthop %s metric %u tag %d",
+ zlog_debug("Rx IPv4 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+ vrf_id,
zebra_route_string(api.type), api.instance,
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
{
if (i != api.type)
- bgp_redistribute_delete((struct prefix *)&p, i, api.instance);
+ bgp_redistribute_delete(bgp, (struct prefix *)&p, i, api.instance);
}
/* Now perform the add/update. */
- bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, ifindex,
+ bgp_redistribute_add(bgp, (struct prefix *)&p, &nexthop, NULL, ifindex,
api.metric, api.type, api.instance, api.tag);
}
else if (command == ZEBRA_REDISTRIBUTE_IPV4_DEL)
if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv4 route delete %s[%d] %s/%d "
- "nexthop %s metric %u tag %d",
+ zlog_debug("Rx IPv4 route delete VRF %u %s[%d] %s/%d "
+ "nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+ vrf_id,
zebra_route_string(api.type), api.instance,
inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
api.metric,
api.tag);
}
- bgp_redistribute_delete((struct prefix *)&p, api.type, api.instance);
+ bgp_redistribute_delete(bgp, (struct prefix *)&p, api.type, api.instance);
}
return 0;
#ifdef HAVE_IPV6
/* Zebra route add and delete treatment. */
static int
-zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)
+zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
+ vrf_id_t vrf_id)
{
struct stream *s;
struct zapi_ipv6 api;
struct prefix_ipv6 p;
unsigned int ifindex;
int i;
+ struct bgp *bgp;
+
+ bgp = bgp_lookup_by_vrf_id (vrf_id);
+ if (!bgp)
+ return 0;
s = zclient->ibuf;
memset (&nexthop, 0, sizeof (struct in6_addr));
/* Type, flags, message. */
api.type = stream_getc (s);
api.instance = stream_getw (s);
- api.flags = stream_getc (s);
+ api.flags = stream_getl (s);
api.message = stream_getc (s);
/* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6;
- p.prefixlen = stream_getc (s);
+ p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */
api.metric = 0;
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
- api.tag = stream_getw (s);
+ api.tag = stream_getl (s);
else
api.tag = 0;
if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv6 route add %s[%d] %s/%d nexthop %s metric %u tag %d",
+ zlog_debug("Rx IPv6 route add VRF %u %s[%d] %s/%d nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+ vrf_id,
zebra_route_string(api.type), api.instance,
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
{
if (i != api.type)
- bgp_redistribute_delete((struct prefix *)&p, i, api.instance);
+ bgp_redistribute_delete(bgp, (struct prefix *)&p, i, api.instance);
}
- bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, ifindex,
+ bgp_redistribute_add (bgp, (struct prefix *)&p, NULL, &nexthop, ifindex,
api.metric, api.type, api.instance, api.tag);
}
else if (command == ZEBRA_REDISTRIBUTE_IPV6_DEL)
if (bgp_debug_zebra((struct prefix *)&p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra rcvd: IPv6 route delete %s[%d] %s/%d "
- "nexthop %s metric %u tag %d",
+ zlog_debug("Rx IPv6 route delete VRF %u %s[%d] %s/%d "
+ "nexthop %s metric %u tag %"ROUTE_TAG_PRI,
+ vrf_id,
zebra_route_string(api.type), api.instance,
inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])),
p.prefixlen,
api.metric,
api.tag);
}
- bgp_redistribute_delete ((struct prefix *) &p, api.type, api.instance);
+ bgp_redistribute_delete (bgp, (struct prefix *) &p, api.type, api.instance);
}
return 0;
#endif /* HAVE_IPV6 */
struct interface *
-if_lookup_by_ipv4 (struct in_addr *addr)
+if_lookup_by_ipv4 (struct in_addr *addr, vrf_id_t vrf_id)
{
struct listnode *ifnode;
struct listnode *cnode;
p.prefix = *addr;
p.prefixlen = IPV4_MAX_BITLEN;
- for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
{
}
struct interface *
-if_lookup_by_ipv4_exact (struct in_addr *addr)
+if_lookup_by_ipv4_exact (struct in_addr *addr, vrf_id_t vrf_id)
{
struct listnode *ifnode;
struct listnode *cnode;
struct connected *connected;
struct prefix *cp;
- for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
{
#ifdef HAVE_IPV6
struct interface *
-if_lookup_by_ipv6 (struct in6_addr *addr, unsigned int ifindex)
+if_lookup_by_ipv6 (struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id)
{
struct listnode *ifnode;
struct listnode *cnode;
p.prefix = *addr;
p.prefixlen = IPV6_MAX_BITLEN;
- for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
{
if (cp->family == AF_INET6)
if (prefix_match (cp, (struct prefix *)&p))
{
- if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6.s6_addr32[0]))
+ if (IN6_IS_ADDR_LINKLOCAL(&cp->u.prefix6))
{
if (ifindex == ifp->ifindex)
return ifp;
}
struct interface *
-if_lookup_by_ipv6_exact (struct in6_addr *addr, unsigned int ifindex)
+if_lookup_by_ipv6_exact (struct in6_addr *addr, ifindex_t ifindex, vrf_id_t vrf_id)
{
struct listnode *ifnode;
struct listnode *cnode;
struct connected *connected;
struct prefix *cp;
- for (ALL_LIST_ELEMENTS_RO (iflist, ifnode, ifp))
+ for (ALL_LIST_ELEMENTS_RO (vrf_iflist(vrf_id), ifnode, ifp))
{
for (ALL_LIST_ELEMENTS_RO (ifp->connected, cnode, connected))
{
{
nexthop->v4 = local->sin.sin_addr;
if (peer->update_if)
- ifp = if_lookup_by_name (peer->update_if);
+ ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
else
- ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr);
+ ifp = if_lookup_by_ipv4_exact (&local->sin.sin_addr, peer->bgp->vrf_id);
}
#ifdef HAVE_IPV6
if (local->sa.sa_family == AF_INET6)
if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr))
{
if (peer->conf_if || peer->ifname)
- ifp = if_lookup_by_index (if_nametoindex (peer->conf_if ? peer->conf_if : peer->ifname));
+ ifp = if_lookup_by_name_vrf (peer->conf_if ? peer->conf_if : peer->ifname, peer->bgp->vrf_id);
}
else if (peer->update_if)
- ifp = if_lookup_by_name (peer->update_if);
+ ifp = if_lookup_by_name_vrf (peer->update_if, peer->bgp->vrf_id);
else
ifp = if_lookup_by_ipv6_exact (&local->sin6.sin6_addr,
- local->sin6.sin6_scope_id);
+ local->sin6.sin6_scope_id,
+ peer->bgp->vrf_id);
}
#endif /* 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);
+ {
+ /* There is no global nexthop. Use link-local address as both the
+ * global and link-local nexthop. In this scenario, the expectation
+ * for interop is that the network admin would use a route-map to
+ * specify the global IPv6 nexthop.
+ */
+ if_get_ipv6_local (ifp, &nexthop->v6_global);
+ memcpy (&nexthop->v6_local, &nexthop->v6_global,
+ IPV6_MAX_BYTELEN);
+ }
else
if_get_ipv6_local (ifp, &nexthop->v6_local);
+
+ if (if_lookup_by_ipv4 (&remote->sin.sin_addr, peer->bgp->vrf_id))
+ peer->shared_network = 1;
+ else
+ peer->shared_network = 0;
#endif /* HAVE_IPV6 */
}
/* If directory connected set link-local address. */
direct = if_lookup_by_ipv6 (&remote->sin6.sin6_addr,
- remote->sin6.sin6_scope_id);
+ remote->sin6.sin6_scope_id, peer->bgp->vrf_id);
if (direct)
if_get_ipv6_local (ifp, &nexthop->v6_local);
}
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, remote->sin6.sin6_scope_id))
- peer->shared_network = 1;
- else
- peer->shared_network = 0;
+ if (IN6_IS_ADDR_LINKLOCAL (&local->sin6.sin6_addr) ||
+ if_lookup_by_ipv6 (&remote->sin6.sin6_addr, remote->sin6.sin6_scope_id,
+ peer->bgp->vrf_id))
+ peer->shared_network = 1;
+ else
+ peer->shared_network = 0;
+ }
/* KAME stack specific treatment. */
#ifdef KAME
/* If both global and link-local address present. */
if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
{
- /* Workaround for Cisco's nexthop bug. */
- if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
- && info->peer->su_remote->sa.sa_family == AF_INET6)
- nexthop = &info->peer->su_remote->sin6.sin6_addr;
+ /* Check if route-map is set to prefer global over link-local */
+ if (info->attr->extra->mp_nexthop_prefer_global)
+ nexthop = &info->attr->extra->mp_nexthop_global;
else
- nexthop = &info->attr->extra->mp_nexthop_local;
+ {
+ /* Workaround for Cisco's nexthop bug. */
+ if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global)
+ && info->peer->su_remote->sa.sa_family == AF_INET6)
+ nexthop = &info->peer->su_remote->sin6.sin6_addr;
+ else
+ nexthop = &info->attr->extra->mp_nexthop_local;
+ }
}
return nexthop;
bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp,
afi_t afi, safi_t safi)
{
- int flags;
+ u_int32_t flags;
u_char distance;
struct peer *peer;
struct bgp_info *mpinfo;
u_int32_t nhcount, metric;
struct bgp_info local_info;
struct bgp_info *info_cp = &local_info;
- u_short tag;
+ route_tag_t tag;
- if (zclient->sock < 0)
+ /* Don't try to install if we're not connected to Zebra or Zebra doesn't
+ * know of this instance.
+ */
+ if (!bgp_install_info_to_zebra (bgp))
return;
- if ((p->family == AF_INET && !zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP].enabled)
- || (p->family == AF_INET6 && !zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP].enabled))
+ if ((p->family == AF_INET &&
+ !vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], bgp->vrf_id))
+ || (p->family == AF_INET6 &&
+ !vrf_bitmap_check (zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], bgp->vrf_id)))
return;
if (bgp->main_zebra_update_hold)
valid_nh_count++;
}
+ api.vrf_id = bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
+ api.tag = 0;
if (tag)
{
api.tag = tag;
}
- distance = bgp_distance_apply (p, info, bgp);
-
+ distance = bgp_distance_apply (p, info, afi, safi, bgp);
if (distance)
{
SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
if (bgp_debug_zebra(p))
{
int i;
- zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d"
+ zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI
" count %d", (valid_nh_count ? "add":"delete"),
+ bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag, api.nexthop_num);
for (i = 0; i < api.nexthop_num; i++)
if (p->family == AF_INET6 ||
(p->family == AF_INET && BGP_ATTR_NEXTHOP_AFI_IP6(info->attr)))
{
- unsigned int ifindex;
+ ifindex_t ifindex;
struct in6_addr *nexthop;
struct zapi_ipv6 api;
int valid_nh_count = 0;
if (!ifindex)
{
if (info->peer->conf_if || info->peer->ifname)
- ifindex = if_nametoindex (info->peer->conf_if ? info->peer->conf_if : info->peer->ifname);
+ ifindex = ifname2ifindex_vrf (info->peer->conf_if ? info->peer->conf_if :
+ info->peer->ifname, bgp->vrf_id);
else if (info->peer->nexthop.ifp)
ifindex = info->peer->nexthop.ifp->ifindex;
}
if (!ifindex)
{
if (mpinfo->peer->conf_if || mpinfo->peer->ifname)
- ifindex = if_nametoindex (mpinfo->peer->conf_if ? mpinfo->peer->conf_if : mpinfo->peer->ifname);
+ ifindex = ifname2ifindex_vrf (mpinfo->peer->conf_if ? mpinfo->peer->conf_if :
+ mpinfo->peer->ifname, bgp->vrf_id);
else if (mpinfo->peer->nexthop.ifp)
ifindex = mpinfo->peer->nexthop.ifp->ifindex;
}
}
/* Make Zebra API structure. */
+ api.vrf_id = bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.nexthop = (struct in6_addr **)STREAM_DATA (bgp_nexthop_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_IFINDEX);
api.ifindex_num = valid_nh_count;
- api.ifindex = (unsigned int *)STREAM_DATA (bgp_ifindices_buf);
+ api.ifindex = (ifindex_t *)STREAM_DATA (bgp_ifindices_buf);
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;
+ api.tag = 0;
if (tag)
{
api.tag = tag;
}
+ distance = bgp_distance_apply (p, info, afi, safi, bgp);
+ if (distance)
+ {
+ SET_FLAG (api.message, ZAPI_MESSAGE_DISTANCE);
+ api.distance = distance;
+ }
+
if (p->family == AF_INET)
{
if (bgp_debug_zebra(p))
{
int i;
- zlog_debug("Zebra send: IPv4 route %s %s/%d metric %u tag %d",
- valid_nh_count ? "add" : "delete",
+ zlog_debug("Tx IPv4 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+ valid_nh_count ? "add" : "delete", bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++)
if (bgp_debug_zebra(p))
{
int i;
- zlog_debug("Zebra send: IPv6 route %s %s/%d metric %u tag %d",
- valid_nh_count ? "add" : "delete",
+ zlog_debug("Tx IPv6 route %s VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+ valid_nh_count ? "add" : "delete", bgp->vrf_id,
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
for (i = 0; i < api.nexthop_num; i++)
struct bgp_table *table;
struct bgp_info *ri;
+ /* Don't try to install if we're not connected to Zebra or Zebra doesn't
+ * know of this instance.
+ */
+ if (!bgp_install_info_to_zebra (bgp))
+ return;
+
table = bgp->rib[afi][safi];
if (!table) return;
void
bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)
{
- int flags;
+ u_int32_t flags;
struct peer *peer;
- if (zclient->sock < 0)
- return;
+ peer = info->peer;
+ assert(peer);
- if ((p->family == AF_INET && !zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP].enabled)
- || (p->family == AF_INET6 && !zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP].enabled))
+ /* Don't try to install if we're not connected to Zebra or Zebra doesn't
+ * know of this instance.
+ */
+ if (!bgp_install_info_to_zebra (peer->bgp))
return;
- peer = info->peer;
+ if ((p->family == AF_INET &&
+ !vrf_bitmap_check (zclient->redist[AFI_IP][ZEBRA_ROUTE_BGP], peer->bgp->vrf_id))
+ || (p->family == AF_INET6 &&
+ !vrf_bitmap_check (zclient->redist[AFI_IP6][ZEBRA_ROUTE_BGP], peer->bgp->vrf_id)))
+ return;
flags = 0;
{
struct zapi_ipv4 api;
+ api.vrf_id = peer->bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
+ api.tag = 0;
if ((info->attr->extra) && (info->attr->extra->tag != 0))
{
if (bgp_debug_zebra(p))
{
char buf[2][INET_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv4 route delete %s/%d metric %u tag %d",
+ zlog_debug("Tx IPv4 route delete VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+ peer->bgp->vrf_id,
inet_ntop(AF_INET, &p->u.prefix4, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
}
struct zapi_ipv6 api;
assert (info->attr->extra);
-
+
+ api.vrf_id = peer->bgp->vrf_id;
api.flags = flags;
api.type = ZEBRA_ROUTE_BGP;
api.instance = 0;
api.ifindex_num = 0;
SET_FLAG (api.message, ZAPI_MESSAGE_METRIC);
api.metric = info->attr->med;
+ api.tag = 0;
if ((info->attr->extra) && (info->attr->extra->tag != 0))
{
if (bgp_debug_zebra(p))
{
char buf[2][INET6_ADDRSTRLEN];
- zlog_debug("Zebra send: IPv6 route delete %s/%d metric %u tag %d",
+ zlog_debug("Tx IPv6 route delete VRF %u %s/%d metric %u tag %"ROUTE_TAG_PRI,
+ peer->bgp->vrf_id,
inet_ntop(AF_INET6, &p->u.prefix6, buf[0], sizeof(buf[0])),
p->prefixlen, api.metric, api.tag);
}
if (red)
{
listnode_delete(bgp->redist[afi][type], red);
+ XFREE (MTYPE_BGP_REDIST, red);
if (!bgp->redist[afi][type]->count)
{
list_free(bgp->redist[afi][type]);
/* Other routes redistribution into BGP. */
int
-bgp_redistribute_set (afi_t afi, int type, u_short instance)
+bgp_redistribute_set (struct bgp *bgp, afi_t afi, int type, u_short instance)
{
/* Return if already redistribute flag is set. */
- if (redist_check_instance(&zclient->redist[afi][type], instance))
- return CMD_WARNING;
+ if (instance)
+ {
+ if (redist_check_instance(&zclient->mi_redist[afi][type], instance))
+ return CMD_WARNING;
- redist_add_instance(&zclient->redist[afi][type], instance);
+ redist_add_instance(&zclient->mi_redist[afi][type], instance);
+ }
+ else
+ {
+ if (vrf_bitmap_check (zclient->redist[afi][type], bgp->vrf_id))
+ return CMD_WARNING;
- /* Return if zebra connection is not established. */
- if (zclient->sock < 0)
+#if ENABLE_BGP_VNC
+ if (bgp->vrf_id == VRF_DEFAULT &&
+ type == ZEBRA_ROUTE_VNC_DIRECT) {
+ vnc_export_bgp_enable(bgp, afi); /* only enables if mode bits cfg'd */
+ }
+#endif
+
+ vrf_bitmap_set (zclient->redist[afi][type], bgp->vrf_id);
+ }
+
+ /* Don't try to register if we're not connected to Zebra or Zebra doesn't
+ * know of this instance.
+ */
+ if (!bgp_install_info_to_zebra (bgp))
return CMD_WARNING;
if (BGP_DEBUG (zebra, ZEBRA))
- zlog_debug("Zebra send: redistribute add afi %d %s %d", afi,
+ zlog_debug("Tx redistribute add VRF %u afi %d %s %d",
+ bgp->vrf_id, afi,
zebra_route_string(type), instance);
/* Send distribute add message to zebra. */
- zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type, instance);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
+ instance, bgp->vrf_id);
return CMD_SUCCESS;
}
int
bgp_redistribute_resend (struct bgp *bgp, afi_t afi, int type, u_short instance)
{
- /* Return if zebra connection is not established. */
- if (zclient->sock < 0)
+ /* Don't try to send if we're not connected to Zebra or Zebra doesn't
+ * know of this instance.
+ */
+ if (!bgp_install_info_to_zebra (bgp))
return -1;
if (BGP_DEBUG (zebra, ZEBRA))
- zlog_debug("Zebra send: redistribute delete/add afi %d %s %d", afi,
+ zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d",
+ bgp->vrf_id, afi,
zebra_route_string(type), instance);
/* Send distribute add message to zebra. */
- zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance);
- zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type, instance);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type,
+ instance, bgp->vrf_id);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
+ instance, bgp->vrf_id);
return 0;
}
red->redist_metric_flag = 1;
red->redist_metric = metric;
- for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn)) {
- for (ri = rn->info; ri; ri = ri->next) {
- if (ri->sub_type == BGP_ROUTE_REDISTRIBUTE && ri->type == type &&
- ri->instance == red->instance) {
- ri->attr->med = red->redist_metric;
- bgp_info_set_flag(rn, ri, BGP_INFO_ATTR_CHANGED);
- bgp_process(bgp, rn, afi, SAFI_UNICAST);
- }
+ for (rn = bgp_table_top(bgp->rib[afi][SAFI_UNICAST]); rn; rn = bgp_route_next(rn))
+ {
+ for (ri = rn->info; ri; ri = ri->next)
+ {
+ if (ri->sub_type == BGP_ROUTE_REDISTRIBUTE &&
+ ri->type == type &&
+ ri->instance == red->instance)
+ {
+ struct attr *old_attr;
+ struct attr new_attr;
+ struct attr_extra new_extra;
+
+ new_attr.extra = &new_extra;
+ bgp_attr_dup (&new_attr, ri->attr);
+ new_attr.med = red->redist_metric;
+ old_attr = ri->attr;
+ ri->attr = bgp_attr_intern (&new_attr);
+ bgp_attr_unintern (&old_attr);
+
+ bgp_info_set_flag(rn, ri, BGP_INFO_ATTR_CHANGED);
+ bgp_process(bgp, rn, afi, SAFI_UNICAST);
+ }
+ }
}
- }
return 1;
}
+/* Unset redistribution. */
+int
+bgp_redistribute_unreg (struct bgp *bgp, afi_t afi, int type, u_short instance)
+{
+ struct bgp_redist *red;
+
+ red = bgp_redist_lookup(bgp, afi, type, instance);
+ if (!red)
+ return CMD_SUCCESS;
+
+ /* Return if zebra connection is disabled. */
+ if (instance)
+ {
+ if (!redist_check_instance(&zclient->mi_redist[afi][type], instance))
+ return CMD_WARNING;
+ redist_del_instance(&zclient->mi_redist[afi][type], instance);
+ }
+ else
+ {
+ if (! vrf_bitmap_check (zclient->redist[afi][type], bgp->vrf_id))
+ return CMD_WARNING;
+ vrf_bitmap_unset (zclient->redist[afi][type], bgp->vrf_id);
+ }
+
+#if ENABLE_BGP_VNC
+ if (bgp->vrf_id == VRF_DEFAULT &&
+ type == ZEBRA_ROUTE_VNC_DIRECT) {
+ vnc_export_bgp_disable(bgp, afi);
+ }
+#endif
+
+ if (bgp_install_info_to_zebra (bgp))
+ {
+ /* Send distribute delete message to zebra. */
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Tx redistribute del VRF %u afi %d %s %d",
+ bgp->vrf_id, afi, zebra_route_string(type), instance);
+ zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance,
+ bgp->vrf_id);
+ }
+
+ /* Withdraw redistributed routes from current BGP's routing table. */
+ bgp_redistribute_withdraw (bgp, afi, type, instance);
+
+ return CMD_SUCCESS;
+}
+
/* Unset redistribution. */
int
bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance)
if (!red)
return CMD_SUCCESS;
+ bgp_redistribute_unreg(bgp, afi, type, instance);
+
/* Unset route-map. */
if (red->rmap.name)
XFREE(MTYPE_ROUTE_MAP_NAME, red->rmap.name);
bgp_redist_del(bgp, afi, type, instance);
- /* Return if zebra connection is disabled. */
- if (!redist_check_instance(&zclient->redist[afi][type], instance))
- return CMD_WARNING;
- redist_del_instance(&zclient->redist[afi][type], instance);
+ return CMD_SUCCESS;
+}
- if (zclient->sock >= 0)
- {
- /* Send distribute delete message to zebra. */
- if (BGP_DEBUG (zebra, ZEBRA))
- zlog_debug("Zebra send: redistribute delete afi %d %s %d",
- afi, zebra_route_string(type), instance);
- zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance);
- }
-
- /* Withdraw redistributed routes from current BGP's routing table. */
- bgp_redistribute_withdraw (bgp, afi, type, instance);
+/* Update redistribute vrf bitmap during triggers like
+ restart networking or delete/add VRFs */
+void
+bgp_update_redist_vrf_bitmaps (struct bgp *bgp, vrf_id_t old_vrf_id)
+{
+ int i;
+ afi_t afi;
- return CMD_SUCCESS;
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ if (vrf_bitmap_check (zclient->redist[afi][i], old_vrf_id))
+ {
+ vrf_bitmap_unset (zclient->redist[afi][i], old_vrf_id);
+ vrf_bitmap_set (zclient->redist[afi][i], bgp->vrf_id);
+ }
+ return;
}
void
zclient_reset (zclient);
}
+/* Register this instance with Zebra. Invoked upon connect (for
+ * default instance) and when other VRFs are learnt (or created and
+ * already learnt).
+ */
+void
+bgp_zebra_instance_register (struct bgp *bgp)
+{
+ /* Don't try to register if we're not connected to Zebra */
+ if (!zclient || zclient->sock < 0)
+ return;
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Registering VRF %u", bgp->vrf_id);
+
+ /* Register for router-id, interfaces, redistributed routes. */
+ zclient_send_reg_requests (zclient, bgp->vrf_id);
+}
+
+/* Deregister this instance with Zebra. Invoked upon the instance
+ * being deleted (default or VRF) and it is already registered.
+ */
+void
+bgp_zebra_instance_deregister (struct bgp *bgp)
+{
+ /* Don't try to deregister if we're not connected to Zebra */
+ if (zclient->sock < 0)
+ return;
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("Deregistering VRF %u", bgp->vrf_id);
+
+ /* Deregister for router-id, interfaces, redistributed routes. */
+ zclient_send_dereg_requests (zclient, bgp->vrf_id);
+}
+
+void
+bgp_zebra_initiate_radv (struct bgp *bgp, struct peer *peer)
+{
+ int ra_interval = BGP_UNNUM_DEFAULT_RA_INTERVAL;
+
+ /* Don't try to initiate if we're not connected to Zebra */
+ if (zclient->sock < 0)
+ return;
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("%u: Initiating RA for peer %s", bgp->vrf_id, peer->host);
+
+ zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 1, ra_interval);
+}
+
+void
+bgp_zebra_terminate_radv (struct bgp *bgp, struct peer *peer)
+{
+ /* Don't try to terminate if we're not connected to Zebra */
+ if (zclient->sock < 0)
+ return;
+
+ if (BGP_DEBUG (zebra, ZEBRA))
+ zlog_debug("%u: Terminating RA for peer %s", bgp->vrf_id, peer->host);
+
+ zclient_send_interface_radv_req (zclient, bgp->vrf_id, peer->ifp, 0, 0);
+}
+
+/* BGP has established connection with Zebra. */
+static void
+bgp_zebra_connected (struct zclient *zclient)
+{
+ struct bgp *bgp;
+
+ zclient_num_connects++; /* increment even if not responding */
+
+ /* At this point, we may or may not have BGP instances configured, but
+ * we're only interested in the default VRF (others wouldn't have learnt
+ * the VRF from Zebra yet.)
+ */
+ bgp = bgp_get_default();
+ if (!bgp)
+ return;
+
+ bgp_zebra_instance_register (bgp);
+
+ /* Send the client registration */
+ bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER);
+
+ /* TODO - What if we have peers and networks configured, do we have to
+ * kick-start them?
+ */
+}
+
+
void
bgp_zebra_init (struct thread_master *master)
{
+ zclient_num_connects = 0;
+
/* Set default values. */
zclient = zclient_new (master);
zclient_init (zclient, ZEBRA_ROUTE_BGP, 0);
+ zclient->zebra_connected = bgp_zebra_connected;
zclient->router_id_update = bgp_router_id_update;
zclient->interface_add = bgp_interface_add;
zclient->interface_delete = bgp_interface_delete;
zclient->interface_address_delete = bgp_interface_address_delete;
zclient->interface_nbr_address_add = bgp_interface_nbr_address_add;
zclient->interface_nbr_address_delete = bgp_interface_nbr_address_delete;
- zclient->ipv4_route_add = zebra_read_ipv4;
- zclient->ipv4_route_delete = zebra_read_ipv4;
+ zclient->interface_vrf_update = bgp_interface_vrf_update;
zclient->redistribute_route_ipv4_add = zebra_read_ipv4;
zclient->redistribute_route_ipv4_del = 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;
zclient->redistribute_route_ipv6_add = zebra_read_ipv6;
zclient->redistribute_route_ipv6_del = zebra_read_ipv6;
-#endif /* HAVE_IPV6 */
zclient->nexthop_update = bgp_read_nexthop_update;
zclient->import_check_update = bgp_read_import_check_update;
- /* Interface related init. */
- if_init ();
-
bgp_nexthop_buf = stream_new(BGP_NEXTHOP_BUF_SIZE);
bgp_ifindices_buf = stream_new(BGP_IFINDICES_BUF_SIZE);
}
+
+void
+bgp_zebra_destroy(void)
+{
+ if (zclient == NULL)
+ return;
+ zclient_stop(zclient);
+ zclient_free(zclient);
+ zclient = NULL;
+}
+
+int
+bgp_zebra_num_connects(void)
+{
+ return zclient_num_connects;
+}