#include "plist.h"
#include "linklist.h"
#include "workqueue.h"
+#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
+#include "bgpd/bgp_updgrp.h"
+
/* BGP process wide configuration. */
static struct bgp_master bgp_master;
return 0;
}
+/* Local preference configuration. */
+int
+bgp_default_subgroup_pkt_queue_max_set (struct bgp *bgp, u_int32_t queue_size)
+{
+ if (! bgp)
+ return -1;
+
+ bgp->default_subgroup_pkt_queue_max = queue_size;
+
+ return 0;
+}
+
+int
+bgp_default_subgroup_pkt_queue_max_unset (struct bgp *bgp)
+{
+ if (! bgp)
+ return -1;
+ bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
+
+ return 0;
+}
+
+struct peer_af *
+peer_af_create (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_af *af;
+ int afid;
+
+ if (!peer)
+ return NULL;
+
+ afid = afindex(afi, safi);
+ if (afid >= BGP_AF_MAX)
+ return NULL;
+
+ assert(peer->peer_af_array[afid] == NULL);
+
+ /* Allocate new peer af */
+ af = XCALLOC (MTYPE_BGP_PEER_AF, sizeof (struct peer_af));
+ peer->peer_af_array[afid] = af;
+ af->afi = afi;
+ af->safi = safi;
+ af->afid = afid;
+ af->peer = peer;
+
+ //update_group_adjust_peer(af);
+ return af;
+}
+
+struct peer_af *
+peer_af_find (struct peer *peer, afi_t afi, safi_t safi)
+{
+ int afid;
+
+ if (!peer)
+ return NULL;
+
+ afid = afindex(afi, safi);
+ if (afid >= BGP_AF_MAX)
+ return NULL;
+
+ return peer->peer_af_array[afid];
+}
+
+int
+peer_af_delete (struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_af *af;
+ int afid;
+
+ if (!peer)
+ return -1;
+
+ afid = afindex(afi, safi);
+ if (afid >= BGP_AF_MAX)
+ return -1;
+
+ af = peer->peer_af_array[afid];
+ if (!af)
+ return -1;
+
+ bgp_stop_announce_route_timer (af);
+
+ if (PAF_SUBGRP(af))
+ {
+ if (BGP_DEBUG (update_groups, UPDATE_GROUPS))
+ zlog_debug ("u%llu:s%llu remove peer %s",
+ af->subgroup->update_group->id, af->subgroup->id, peer->host);
+ }
+
+ update_subgroup_remove_peer (af->subgroup, af);
+
+ peer->peer_af_array[afid] = NULL;
+ XFREE(MTYPE_BGP_PEER_AF, af);
+ return 0;
+}
+
+
/* If peer is RSERVER_CLIENT in at least one address family and is not member
of a peer_group for that family, return 1.
Used to check wether the peer is included in list bgp->rsclient. */
void
peer_xfer_config (struct peer *peer_dst, struct peer *peer_src)
{
+ struct peer_af *paf;
afi_t afi;
safi_t safi;
+ int afindex;
assert(peer_src);
assert(peer_dst);
peer_dst->allowas_in[afi][safi] = peer_src->allowas_in[afi][safi];
}
+ PEERAF_FOREACH(peer_src, paf, afindex)
+ peer_af_create(peer_dst, paf->afi, paf->safi);
+
/* update-source apply */
if (peer_src->update_source)
{
active = peer_active (peer);
- if (afi && safi)
- peer->afc[afi][safi] = 1;
-
/* Last read and reset time set */
peer->readtime = peer->resettime = bgp_clock ();
SET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
+ if (afi && safi)
+ {
+ peer->afc[afi][safi] = 1;
+ if (peer_af_create(peer, afi, safi) == NULL)
+ {
+ zlog_err("couldn't create af structure for peer %s", peer->host);
+ }
+ }
+
/* Set up peer's events and timers. */
if (! active && peer_active (peer))
bgp_timer_set (peer);
peer->afc[afi][safi] = 1;
+ if (peer_af_create(peer, afi, safi) == NULL)
+ {
+ zlog_err("couldn't create af structure for peer %s", peer->host);
+ }
+
if (! active && peer_active (peer))
bgp_timer_set (peer);
else
/* De-activate the address family configuration. */
peer->afc[afi][safi] = 0;
peer_af_flag_reset (peer, afi, safi);
+ if (peer_af_delete(peer, afi, safi) != 0)
+ {
+ zlog_err("couldn't delete af structure for peer %s", peer->host);
+ }
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
filter->usmap.name = NULL;
peer->default_rmap[afi][safi].name = NULL;
}
+
+ FOREACH_AFI_SAFI (afi, safi)
+ peer_af_delete (peer, afi, safi);
peer_unlock (peer); /* initial reference */
return strcmp (g1->name, g2->name);
}
-/* If peer is configured at least one address family return 1. */
-static int
-peer_group_active (struct peer *peer)
-{
- if (peer->af_group[AFI_IP][SAFI_UNICAST]
- || peer->af_group[AFI_IP][SAFI_MULTICAST]
- || peer->af_group[AFI_IP][SAFI_MPLS_VPN]
- || peer->af_group[AFI_IP6][SAFI_UNICAST]
- || peer->af_group[AFI_IP6][SAFI_MULTICAST])
- return 1;
- return 0;
-}
-
/* Peer group cofiguration. */
static struct peer_group *
peer_group_new (void)
peer->af_group[afi][safi] = 1;
peer->afc[afi][safi] = 1;
+ if (!peer_af_find(peer, afi, safi) &&
+ peer_af_create(peer, afi, safi) == NULL)
+ {
+ zlog_err("couldn't create af structure for peer %s", peer->host);
+ }
if (! peer->group)
{
peer->group = group;
peer->af_group[afi][safi] = 0;
peer->afc[afi][safi] = 0;
peer_af_flag_reset (peer, afi, safi);
+ if (peer_af_delete(peer, afi, safi) != 0)
+ {
+ zlog_err("couldn't delete af structure for peer %s", peer->host);
+ }
if (peer->rib[afi][safi])
peer->rib[afi][safi] = NULL;
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
+ bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
bgp->name = strdup (name);
bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
- bgp->adv_quanta = BGP_ADV_FIFO_QUANTA;
- bgp->wd_quanta = BGP_WD_FIFO_QUANTA;
+ bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
THREAD_TIMER_ON (master, bgp->t_startup, bgp_startup_timer_expire,
bgp, bgp->restart_time);
+ update_group_init(bgp);
return bgp;
}
}
}
else if (type == peer_change_reset_out)
- bgp_announce_route (peer, afi, safi);
+ {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ bgp_announce_route (peer, afi, safi);
+ }
}
struct peer_flag_action
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->status == Established && peer->afc_nego[afi][safi])
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate (peer, afi, safi, 0);
+ bgp_announce_route (peer, afi, safi);
+ }
return 0;
}
peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
}
- if (peer->status == Established && peer->afc_nego[afi][safi])
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate (peer, afi, safi, 0);
+ bgp_announce_route (peer, afi, safi);
+ }
}
return 0;
}
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
- if (peer->status == Established && peer->afc_nego[afi][safi])
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate (peer, afi, safi, 1);
+ bgp_announce_route (peer, afi, safi);
+ }
return 0;
}
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
- if (peer->status == Established && peer->afc_nego[afi][safi])
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate (peer, afi, safi, 1);
+ bgp_announce_route (peer, afi, safi);
+ }
}
return 0;
}
peer->routeadv = routeadv;
peer->v_routeadv = routeadv;
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) {
+ update_group_adjust_peer_afs (peer);
+ if (peer->status == Established)
+ bgp_announce_route_all (peer);
return 0;
+ }
/* peer-group member updates. */
group = peer->group;
SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
peer->routeadv = routeadv;
peer->v_routeadv = routeadv;
+ update_group_adjust_peer_afs (peer);
+ if (peer->status == Established)
+ bgp_announce_route_all (peer);
}
return 0;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+ if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) {
+ update_group_adjust_peer_afs (peer);
+ if (peer->status == Established)
+ bgp_announce_route_all (peer);
return 0;
+ }
/* peer-group member updates. */
group = peer->group;
peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
else
peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+ update_group_adjust_peer_afs (peer);
+ if (peer->status == Established)
+ bgp_announce_route_all (peer);
}
return 0;
return 0;
}
+/*
+ * peer_on_policy_change
+ *
+ * Helper function that is called after the name of the policy
+ * being used by a peer_af has changed.
+ */
+static void
+peer_on_policy_change (struct peer *peer, afi_t afi, safi_t safi)
+{
+ update_group_adjust_peer (peer_af_find (peer, afi, safi));
+}
+
+/* Set route-map to the peer. */
+static void
+peer_reprocess_routes (struct peer *peer, int direct,
+ afi_t afi, safi_t safi)
+{
+ if (peer->status != Established)
+ return;
+
+ if (direct != RMAP_OUT)
+ {
+ if (CHECK_FLAG (peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ bgp_soft_reconfig_in (peer, afi, safi);
+ else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
+ }
+ else
+ bgp_announce_route(peer, afi, safi);
+}
+
+
/* Set distribute list to the peer. */
int
peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
filter->dlist[direct].alist = access_list_lookup (afi, name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
free (filter->dlist[direct].name);
filter->dlist[direct].name = strdup (name);
filter->dlist[direct].alist = access_list_lookup (afi, name);
+
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
}
return 0;
free (filter->dlist[direct].name);
filter->dlist[direct].name = strdup (gfilter->dlist[direct].name);
filter->dlist[direct].alist = gfilter->dlist[direct].alist;
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
return 0;
}
}
filter->dlist[direct].alist = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
free (filter->dlist[direct].name);
filter->dlist[direct].name = NULL;
filter->dlist[direct].alist = NULL;
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
}
return 0;
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
{
+ if (access->name)
+ update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST, access->name,
+ 0, 0);
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
for (afi = AFI_IP; afi < AFI_MAX; afi++)
filter->plist[direct].plist = prefix_list_lookup (afi, name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
free (filter->plist[direct].name);
filter->plist[direct].name = strdup (name);
filter->plist[direct].plist = prefix_list_lookup (afi, name);
+
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
}
return 0;
}
free (filter->plist[direct].name);
filter->plist[direct].name = strdup (gfilter->plist[direct].name);
filter->plist[direct].plist = gfilter->plist[direct].plist;
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
return 0;
}
}
filter->plist[direct].plist = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
free (filter->plist[direct].name);
filter->plist[direct].name = NULL;
filter->plist[direct].plist = NULL;
+
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
}
return 0;
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
{
+
+ /*
+ * Update the prefix-list on update groups.
+ */
+ update_group_policy_update(bgp, BGP_POLICY_PREFIX_LIST,
+ plist ? plist->name : NULL, 0, 0);
+
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
for (afi = AFI_IP; afi < AFI_MAX; afi++)
filter->aslist[direct].aslist = as_list_lookup (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
free (filter->aslist[direct].name);
filter->aslist[direct].name = strdup (name);
filter->aslist[direct].aslist = as_list_lookup (name);
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
}
return 0;
}
free (filter->aslist[direct].name);
filter->aslist[direct].name = strdup (gfilter->aslist[direct].name);
filter->aslist[direct].aslist = gfilter->aslist[direct].aslist;
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
return 0;
}
}
filter->aslist[direct].aslist = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
+ {
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
+ return 0;
+ }
group = peer->group;
for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
free (filter->aslist[direct].name);
filter->aslist[direct].name = NULL;
filter->aslist[direct].aslist = NULL;
+
+ if (direct == FILTER_OUT)
+ peer_on_policy_change (peer, afi, safi);
}
return 0;
for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
{
+ update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST, aslist_name,
+ 0, 0);
+
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
for (afi = AFI_IP; afi < AFI_MAX; afi++)
}
}
}
+
static void
peer_aslist_add (char *aslist_name)
{
}
-/* Set route-map to the peer. */
-static void
-peer_reprocess_routes (struct peer *peer, int direct,
- afi_t afi, safi_t safi)
-{
- if (peer->status != Established)
- return;
-
- if (direct != RMAP_OUT)
- {
- if (CHECK_FLAG (peer->af_flags[afi][safi],
- PEER_FLAG_SOFT_RECONFIG))
- bgp_soft_reconfig_in (peer, afi, safi);
- else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- }
- else
- bgp_announce_route(peer, afi, safi);
-}
-
int
peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
const char *name)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
+ if (direct == RMAP_OUT)
+ peer_on_policy_change (peer, afi, safi);
peer_reprocess_routes(peer, direct, afi, safi);
return 0;
}
free (filter->map[direct].name);
filter->map[direct].name = strdup (name);
filter->map[direct].map = route_map_lookup_by_name (name);
+ if (direct == RMAP_OUT)
+ peer_on_policy_change (peer, afi, safi);
peer_reprocess_routes (peer, direct, afi, safi);
}
return 0;
free (filter->map[direct].name);
filter->map[direct].name = strdup (gfilter->map[direct].name);
filter->map[direct].map = gfilter->map[direct].map;
+ if (direct == RMAP_OUT)
+ peer_on_policy_change (peer, afi, safi);
return 0;
}
}
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
+ if (direct == RMAP_OUT)
+ peer_on_policy_change (peer, afi, safi);
peer_reprocess_routes(peer, direct, afi, safi);
return 0;
}
free (filter->map[direct].name);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
+ if (direct == RMAP_OUT)
+ peer_on_policy_change (peer, afi, safi);
peer_reprocess_routes(peer, direct, afi, safi);
}
return 0;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
+ peer_on_policy_change (peer, afi, safi);
bgp_announce_route (peer, afi, safi);
return 0;
}
free (filter->usmap.name);
filter->usmap.name = strdup (name);
filter->usmap.map = route_map_lookup_by_name (name);
+ peer_on_policy_change (peer, afi, safi);
bgp_announce_route (peer, afi, safi);
}
return 0;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
+ peer_on_policy_change (peer, afi, safi);
bgp_announce_route(peer, afi, safi);
return 0;
}
free (filter->usmap.name);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
+ peer_on_policy_change (peer, afi, safi);
bgp_announce_route(peer, afi, safi);
}
return 0;
vty_out (vty, " neighbor %s password %s%s", addr, peer->password,
VTY_NEWLINE);
+ /* neighbor solo */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL))
+ if (!peer_group_active (peer))
+ vty_out (vty, " neighbor %s solo%s", addr, VTY_NEWLINE);
+
/* BGP port. */
if (peer->port != BGP_PORT_DEFAULT)
vty_out (vty, " neighbor %s port %d%s", addr, peer->port,
vty_out (vty, " bgp default local-preference %d%s",
bgp->default_local_pref, VTY_NEWLINE);
+ /* BGP default subgroup-pkt-queue-max. */
+ if (bgp->default_subgroup_pkt_queue_max != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX)
+ vty_out (vty, " bgp default subgroup-pkt-queue-max %d%s",
+ bgp->default_subgroup_pkt_queue_max, VTY_NEWLINE);
+
/* BGP client-to-client reflection. */
if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE);
/* write quanta */
bgp_config_write_wpkt_quanta (vty, bgp);
+ /* coalesce time */
+ bgp_config_write_coalesce_time(vty, bgp);
+
/* BGP graceful-restart. */
if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
vty_out (vty, " bgp graceful-restart stalepath-time %d%s",