BGP: Add dynamic update group support

This patch implements the 'update-groups' functionality in BGP. This is a
function that can significantly improve BGP performance for Update generation
and resultant network convergence. BGP Updates are formed for "groups" of
peers and then replicated and sent out to each peer rather than being formed
for each peer. Thus major BGP operations related to outbound policy
application, adj-out maintenance and actual Update packet formation
are optimized.

BGP update-groups dynamically groups peers together based on configuration
as well as run-time criteria. Thus, it is more flexible than update-formation
based on peer-groups, which relies on operator configuration.

[Note that peer-group based update formation has been introduced into BGP by
Cumulus but is currently intended only for specific releases.]

From 11098af65b2b8f9535484703e7f40330a71cbae4 Mon Sep 17 00:00:00 2001
Subject: [PATCH] updgrp commits
This commit is contained in:
Donald Sharp 2015-05-19 18:03:47 -07:00
parent 759a13f3cc
commit 3f9c7369f7
52 changed files with 6597 additions and 1306 deletions

View file

@ -16,14 +16,15 @@ libbgp_a_SOURCES = \
bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \
bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \
bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \
bgp_nht.c
bgp_nht.c bgp_updgrp.c bgp_updgrp_packet.c bgp_updgrp_adv.c
noinst_HEADERS = \
bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \
bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \
bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \
bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h
bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h bgp_nht.h \
bgp_updgrp.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@

View file

@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "hash.h"
#include "thread.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@ -36,11 +37,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_updgrp.h"
/* BGP advertise attribute is used for pack same attribute update into
one packet. To do that we maintain attribute hash in struct
peer. */
static struct bgp_advertise_attr *
struct bgp_advertise_attr *
baa_new (void)
{
return (struct bgp_advertise_attr *)
@ -64,7 +66,7 @@ baa_hash_alloc (void *p)
return baa;
}
static unsigned int
unsigned int
baa_hash_key (void *p)
{
struct bgp_advertise_attr * baa = (struct bgp_advertise_attr *) p;
@ -72,7 +74,7 @@ baa_hash_key (void *p)
return attrhash_key_make (baa->attr);
}
static int
int
baa_hash_cmp (const void *p1, const void *p2)
{
const struct bgp_advertise_attr * baa1 = p1;
@ -84,14 +86,14 @@ baa_hash_cmp (const void *p1, const void *p2)
/* BGP update and withdraw information is stored in BGP advertise
structure. This structure is referred from BGP adjacency
information. */
static struct bgp_advertise *
struct bgp_advertise *
bgp_advertise_new (void)
{
return (struct bgp_advertise *)
XCALLOC (MTYPE_BGP_ADVERTISE, sizeof (struct bgp_advertise));
}
static void
void
bgp_advertise_free (struct bgp_advertise *adv)
{
if (adv->binfo)
@ -99,7 +101,7 @@ bgp_advertise_free (struct bgp_advertise *adv)
XFREE (MTYPE_BGP_ADVERTISE, adv);
}
static void
void
bgp_advertise_add (struct bgp_advertise_attr *baa,
struct bgp_advertise *adv)
{
@ -109,7 +111,7 @@ bgp_advertise_add (struct bgp_advertise_attr *baa,
baa->adv = adv;
}
static void
void
bgp_advertise_delete (struct bgp_advertise_attr *baa,
struct bgp_advertise *adv)
{
@ -121,7 +123,7 @@ bgp_advertise_delete (struct bgp_advertise_attr *baa,
baa->adv = adv->next;
}
static struct bgp_advertise_attr *
struct bgp_advertise_attr *
bgp_advertise_intern (struct hash *hash, struct attr *attr)
{
struct bgp_advertise_attr ref;
@ -134,7 +136,7 @@ bgp_advertise_intern (struct hash *hash, struct attr *attr)
return baa;
}
static void
void
bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
{
if (baa->refcnt)
@ -153,12 +155,17 @@ bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)
}
}
/* BGP adjacency keeps minimal advertisement information. */
static void
bgp_adj_out_free (struct bgp_adj_out *adj)
struct bgp_adj_out *
bgp_adj_peer_lookup (struct peer *peer, struct bgp_node *rn)
{
peer_unlock (adj->peer); /* adj_out peer reference */
XFREE (MTYPE_BGP_ADJ_OUT, adj);
struct bgp_adj_out *adj;
struct peer_af *paf;
for (adj = rn->adj_out; adj; adj = adj->next)
SUBGRP_FOREACH_PEER(adj->subgroup, paf)
if (paf->peer == peer)
return adj;
return NULL;
}
int
@ -166,203 +173,20 @@ bgp_adj_out_lookup (struct peer *peer, struct prefix *p,
afi_t afi, safi_t safi, struct bgp_node *rn)
{
struct bgp_adj_out *adj;
struct peer_af *paf;
for (adj = rn->adj_out; adj; adj = adj->next)
if (adj->peer == peer)
break;
if (! adj)
return 0;
SUBGRP_FOREACH_PEER(adj->subgroup, paf)
if (paf->peer == peer)
{
return (adj->adv
? (adj->adv->baa ? 1 : 0)
: (adj->attr ? 1 : 0));
}
return 0;
}
struct bgp_advertise *
bgp_advertise_clean (struct peer *peer, struct bgp_adj_out *adj,
afi_t afi, safi_t safi)
{
struct bgp_advertise *adv;
struct bgp_advertise_attr *baa;
struct bgp_advertise *next;
struct bgp_advertise_fifo *fhead;
adv = adj->adv;
baa = adv->baa;
next = NULL;
fhead = &peer->sync[afi][safi]->withdraw;
if (baa)
{
/* Unlink myself from advertise attribute FIFO. */
bgp_advertise_delete (baa, adv);
/* Fetch next advertise candidate. */
next = baa->adv;
/* Unintern BGP advertise attribute. */
bgp_advertise_unintern (peer->hash[afi][safi], baa);
fhead = &peer->sync[afi][safi]->update;
}
/* Unlink myself from advertisement FIFO. */
BGP_ADV_FIFO_DEL (fhead, adv);
/* Free memory. */
bgp_advertise_free (adj->adv);
adj->adv = NULL;
return next;
}
void
bgp_adj_out_set (struct bgp_node *rn, struct peer *peer, struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi,
struct bgp_info *binfo)
{
struct bgp_adj_out *adj = NULL;
struct bgp_advertise *adv;
if (DISABLE_BGP_ANNOUNCE)
return;
/* Look for adjacency information. */
if (rn)
{
for (adj = rn->adj_out; adj; adj = adj->next)
if (adj->peer == peer)
break;
}
if (! adj)
{
adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
adj->peer = peer_lock (peer); /* adj_out peer reference */
if (rn)
{
BGP_ADJ_OUT_ADD (rn, adj);
bgp_lock_node (rn);
}
}
if (adj->adv)
bgp_advertise_clean (peer, adj, afi, safi);
adj->adv = bgp_advertise_new ();
adv = adj->adv;
adv->rn = rn;
assert (adv->binfo == NULL);
adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */
if (attr)
adv->baa = bgp_advertise_intern (peer->hash[afi][safi], attr);
else
adv->baa = baa_new ();
adv->adj = adj;
/* Add new advertisement to advertisement attribute list. */
bgp_advertise_add (adv->baa, adv);
BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->update, &adv->fifo);
/*
* Schedule write thread (by triggering adjustment of MRAI timer) only if
* update FIFO has grown. Otherwise, it will be done upon the work queue
* being fully processed. Only adjust timer if needed.
*/
if (!BGP_ROUTE_ADV_HOLD(peer->bgp) &&
(BGP_ADV_FIFO_COUNT(&peer->sync[afi][safi]->update) >=
peer->bgp->adv_quanta))
{
if (!peer->radv_adjusted)
{
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("%s scheduling MRAI timer after adj_out_set", peer->host);
bgp_adjust_routeadv(peer);
}
}
}
void
bgp_adj_out_unset (struct bgp_node *rn, struct peer *peer, struct prefix *p,
afi_t afi, safi_t safi)
{
struct bgp_adj_out *adj;
struct bgp_advertise *adv;
if (DISABLE_BGP_ANNOUNCE)
return;
/* Lookup existing adjacency, if it is not there return immediately. */
for (adj = rn->adj_out; adj; adj = adj->next)
if (adj->peer == peer)
break;
if (! adj)
return;
/* Clearn up previous advertisement. */
if (adj->adv)
bgp_advertise_clean (peer, adj, afi, safi);
if (adj->attr)
{
/* We need advertisement structure. */
adj->adv = bgp_advertise_new ();
adv = adj->adv;
adv->rn = rn;
adv->adj = adj;
/* Add to synchronization entry for withdraw announcement. */
BGP_ADV_FIFO_ADD (&peer->sync[afi][safi]->withdraw, &adv->fifo);
/*
* Schedule write thread only if withdraw FIFO has grown. Otherwise,
* it will be done upon the work queue being fully processed.
*/
if (!BGP_ROUTE_ADV_HOLD(peer->bgp) &&
(BGP_ADV_FIFO_COUNT(&peer->sync[afi][safi]->withdraw) >=
peer->bgp->wd_quanta))
{
if (!peer->t_write)
{
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("%s scheduling write thread after adj_out_unset",
peer->host);
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
}
}
}
else
{
/* Remove myself from adjacency. */
BGP_ADJ_OUT_DEL (rn, adj);
/* Free allocated information. */
bgp_adj_out_free (adj);
bgp_unlock_node (rn);
}
}
void
bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,
struct peer *peer, afi_t afi, safi_t safi)
{
if (adj->attr)
bgp_attr_unintern (&adj->attr);
if (adj->adv)
bgp_advertise_clean (peer, adj, afi, safi);
BGP_ADJ_OUT_DEL (rn, adj);
bgp_adj_out_free (adj);
}
void
bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)

View file

@ -21,6 +21,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifndef _QUAGGA_BGP_ADVERTISE_H
#define _QUAGGA_BGP_ADVERTISE_H
struct update_subgroup;
/* BGP advertise FIFO. */
struct bgp_advertise_fifo
{
@ -71,8 +73,14 @@ struct bgp_adj_out
struct bgp_adj_out *next;
struct bgp_adj_out *prev;
/* Advertised peer. */
struct peer *peer;
/* Advertised subgroup. */
struct update_subgroup *subgroup;
/* Threading that makes the adj part of subgroup's adj queue */
TAILQ_ENTRY(bgp_adj_out) subgrp_adj_train;
/* Prefix information. */
struct bgp_node *rn;
/* Advertised attribute. */
struct attr *attr;
@ -149,13 +157,14 @@ struct bgp_synchronize
#define BGP_ADV_FIFO_COUNT(F) \
(F)->count
#define BGP_ADV_FIFO_EMPTY(F) \
(((struct bgp_advertise_fifo *)(F))->next == (struct bgp_advertise *)(F))
#define BGP_ADV_FIFO_HEAD(F) \
((((struct bgp_advertise_fifo *)(F))->next == (struct bgp_advertise *)(F)) \
? NULL : (F)->next)
/* Prototypes. */
extern void bgp_adj_out_set (struct bgp_node *, struct peer *, struct prefix *,
struct attr *, afi_t, safi_t, struct bgp_info *);
extern void bgp_adj_out_unset (struct bgp_node *, struct peer *, struct prefix *,
afi_t, safi_t);
extern void bgp_adj_out_remove (struct bgp_node *, struct bgp_adj_out *,
struct peer *, afi_t, safi_t);
extern int bgp_adj_out_lookup (struct peer *, struct prefix *, afi_t, safi_t,
struct bgp_node *);
@ -163,10 +172,23 @@ extern void bgp_adj_in_set (struct bgp_node *, struct peer *, struct attr *);
extern void bgp_adj_in_unset (struct bgp_node *, struct peer *);
extern void bgp_adj_in_remove (struct bgp_node *, struct bgp_adj_in *);
extern struct bgp_advertise *
bgp_advertise_clean (struct peer *, struct bgp_adj_out *, afi_t, safi_t);
extern void bgp_sync_init (struct peer *);
extern void bgp_sync_delete (struct peer *);
extern unsigned int baa_hash_key (void *p);
extern int baa_hash_cmp (const void *p1, const void *p2);
extern void bgp_advertise_add (struct bgp_advertise_attr *baa,
struct bgp_advertise *adv);
extern struct bgp_advertise *bgp_advertise_new (void);
extern void bgp_advertise_free (struct bgp_advertise *adv);
extern struct bgp_advertise_attr *
bgp_advertise_intern (struct hash *hash, struct attr *attr);
extern struct bgp_advertise_attr *baa_new (void);
extern void
bgp_advertise_delete (struct bgp_advertise_attr *baa,
struct bgp_advertise *adv);
extern void
bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa);
extern struct bgp_adj_out *
bgp_adj_peer_lookup (struct peer *peer, struct bgp_node *rn);
#endif /* _QUAGGA_BGP_ADVERTISE_H */

View file

@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "stream.h"
#include "jhash.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"

View file

@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "hash.h"
#include "jhash.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@ -38,6 +39,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_updgrp.h"
/* Attribute strings for logging. */
static const struct message attr_str [] =
@ -474,7 +476,8 @@ attrhash_cmp (const void *p1, const void *p2)
&& attr1->aspath == attr2->aspath
&& attr1->community == attr2->community
&& attr1->med == attr2->med
&& attr1->local_pref == attr2->local_pref)
&& attr1->local_pref == attr2->local_pref
&& attr1->rmap_change_flags == attr2->rmap_change_flags)
{
const struct attr_extra *ae1 = attr1->extra;
const struct attr_extra *ae2 = attr2->extra;
@ -607,6 +610,40 @@ bgp_attr_intern (struct attr *attr)
return find;
}
/**
* Increment the refcount on various structures that attr holds.
* Note on usage: call _only_ when the 'attr' object has already
* been 'intern'ed and exists in 'attrhash' table. The function
* serves to hold a reference to that (real) object.
* Note also that the caller can safely call bgp_attr_unintern()
* after calling bgp_attr_refcount(). That would release the
* reference and could result in a free() of the attr object.
*/
struct attr *
bgp_attr_refcount (struct attr *attr)
{
/* Intern referenced strucutre. */
if (attr->aspath)
attr->aspath->refcnt++;
if (attr->community)
attr->community->refcnt++;
if (attr->extra)
{
struct attr_extra *attre = attr->extra;
if (attre->ecommunity)
attre->ecommunity->refcnt++;
if (attre->cluster)
attre->cluster->refcnt++;
if (attre->transit)
attre->transit->refcnt++;
}
attr->refcnt++;
return attr;
}
/* Make network statement's attribute. */
struct attr *
@ -1565,7 +1602,7 @@ bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
char buf1[INET6_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug ("%s sent two nexthops %s %s but second one is not a link-local nexthop", peer->host,
inet_ntop (AF_INET6, &attre->mp_nexthop_global,
buf1, INET6_ADDRSTRLEN),
@ -1716,7 +1753,7 @@ bgp_attr_unknown (struct bgp_attr_parser_args *args)
const u_char flag = args->flags;
const bgp_size_t length = args->length;
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
peer->host, type, length);
@ -2098,6 +2135,7 @@ int stream_put_prefix (struct stream *, struct prefix *);
size_t
bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
struct bpacket_attr_vec_arr *vecarr,
struct attr *attr)
{
size_t sizep;
@ -2118,10 +2156,12 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
{
case SAFI_UNICAST:
case SAFI_MULTICAST:
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
stream_putc (s, 4);
stream_put_ipv4 (s, attr->nexthop.s_addr);
break;
case SAFI_MPLS_VPN:
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
stream_putc (s, 12);
stream_putl (s, 0);
stream_putl (s, 0);
@ -2142,6 +2182,7 @@ bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
struct attr_extra *attre = attr->extra;
assert (attr->extra);
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
stream_putc (s, attre->mp_nexthop_len);
stream_put (s, &attre->mp_nexthop_global, 16);
if (attre->mp_nexthop_len == 32)
@ -2194,6 +2235,7 @@ bgp_packet_mpattr_end (struct stream *s, size_t sizep)
bgp_size_t
bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
struct stream *s, struct attr *attr,
struct bpacket_attr_vec_arr *vecarr,
struct prefix *p, afi_t afi, safi_t safi,
struct peer *from, struct prefix_rd *prd, u_char *tag)
{
@ -2202,6 +2244,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
struct aspath *aspath;
int send_as4_path = 0;
int send_as4_aggregator = 0;
int i = 0;
int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
size_t mpattrlen_pos = 0;
@ -2213,7 +2256,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
if (p && !(afi == AFI_IP && safi == SAFI_UNICAST))
{
mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr);
mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, vecarr, attr);
bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
bgp_packet_mpattr_end(s, mpattrlen_pos);
}
@ -2290,15 +2333,8 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
{
stream_putc (s, BGP_ATTR_FLAG_TRANS);
stream_putc (s, BGP_ATTR_NEXT_HOP);
bpacket_attr_vec_arr_set_vec (vecarr, BGP_ATTR_VEC_NH, s, attr);
stream_putc (s, 4);
if (safi == SAFI_MPLS_VPN)
{
if (attr->nexthop.s_addr == 0)
stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
else
stream_put_ipv4 (s, attr->nexthop.s_addr);
}
else
stream_put_ipv4 (s, attr->nexthop.s_addr);
}

View file

@ -116,8 +116,17 @@ struct attr
/* Path origin attribute */
u_char origin;
/* has the route-map changed any attribute?
Used on the peer outbound side. */
u_int32_t rmap_change_flags;
};
/* rmap_change_flags definition */
#define BATTR_RMAP_NEXTHOP_CHANGED (1 << 0)
#define BATTR_RMAP_NEXTHOP_PEER_ADDRESS (1 << 1)
#define BATTR_REFLECTED (1 << 2)
/* Router Reflector related structure. */
struct cluster_list
{
@ -149,6 +158,8 @@ typedef enum {
BGP_ATTR_PARSE_ERROR_NOTIFYPLS = -3,
} bgp_attr_parse_ret_t;
struct bpacket_attr_vec_arr;
/* Prototypes. */
extern void bgp_attr_init (void);
extern void bgp_attr_finish (void);
@ -162,6 +173,7 @@ extern void bgp_attr_dup (struct attr *, struct attr *);
extern void bgp_attr_deep_dup (struct attr *, struct attr *);
extern void bgp_attr_deep_free (struct attr *);
extern struct attr *bgp_attr_intern (struct attr *attr);
extern struct attr *bgp_attr_refcount (struct attr *attr);
extern void bgp_attr_unintern_sub (struct attr *);
extern void bgp_attr_unintern (struct attr **);
extern void bgp_attr_flush (struct attr *);
@ -172,6 +184,7 @@ extern struct attr *bgp_attr_aggregate_intern (struct bgp *, u_char,
struct community *, int as_set, u_char);
extern bgp_size_t bgp_packet_attribute (struct bgp *bgp, struct peer *,
struct stream *, struct attr *,
struct bpacket_attr_vec_arr *vecarr,
struct prefix *, afi_t, safi_t,
struct peer *, struct prefix_rd *,
u_char *);
@ -212,6 +225,7 @@ extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
* finally the _end() function.
*/
extern size_t bgp_packet_mpattr_start(struct stream *s, afi_t afi, safi_t safi,
struct bpacket_attr_vec_arr *vecarr,
struct attr *attr);
extern void bgp_packet_mpattr_prefix(struct stream *s, afi_t afi, safi_t safi,
struct prefix *p, struct prefix_rd *prd,

View file

@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "prefix.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_community.h"

View file

@ -26,6 +26,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "command.h"
#include "log.h"
#include "thread.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_damp.h"

View file

@ -29,6 +29,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "sockunion.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"
@ -36,6 +37,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_updgrp.h"
unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events;
@ -46,6 +48,7 @@ unsigned long conf_bgp_debug_keepalive;
unsigned long conf_bgp_debug_update;
unsigned long conf_bgp_debug_zebra;
unsigned long conf_bgp_debug_nht;
unsigned long conf_bgp_debug_update_groups;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
@ -56,6 +59,7 @@ unsigned long term_bgp_debug_keepalive;
unsigned long term_bgp_debug_update;
unsigned long term_bgp_debug_zebra;
unsigned long term_bgp_debug_nht;
unsigned long term_bgp_debug_update_groups;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
@ -313,6 +317,12 @@ bgp_debug_list_has_entry(struct list *list, struct peer *peer, struct prefix *p)
return 0;
}
int
bgp_debug_peer_updout_enabled(struct peer *peer)
{
return (bgp_debug_list_has_entry(bgp_debug_update_out_peers, peer, NULL));
}
/* Dump attribute. */
int
bgp_dump_attr (struct peer *peer, struct attr *attr, char *buf, size_t size)
@ -438,6 +448,15 @@ bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
bgp_notify->data ? bgp_notify->data : "");
}
static void
bgp_debug_clear_updgrp_update_dbg(struct bgp *bgp)
{
if (!bgp)
bgp = bgp_get_default();
update_group_walk (bgp, update_group_clear_update_dbg, NULL);
}
/* Debug option setting interface. */
unsigned long bgp_debug_option = 0;
@ -912,7 +931,19 @@ DEFUN (debug_bgp_update_direct_peer,
if (inbound)
bgp_debug_list_add_entry(bgp_debug_update_in_peers, peer, NULL);
else
{
struct peer_af *paf;
int af;
bgp_debug_list_add_entry(bgp_debug_update_out_peers, peer, NULL);
PEERAF_FOREACH (peer, paf, af)
{
if (PAF_SUBGRP (paf))
{
UPDGRP_PEER_DBG_EN(PAF_SUBGRP(paf)->update_group);
}
}
}
if (vty->node == CONFIG_NODE)
{
@ -1006,6 +1037,20 @@ DEFUN (no_debug_bgp_update_direct_peer,
vty_out (vty, "BGP updates debugging (outbound) is off%s", VTY_NEWLINE);
}
}
if (found_peer)
{
struct peer_af *paf;
int af;
PEERAF_FOREACH (peer, paf, af)
{
if (PAF_SUBGRP (paf))
{
UPDGRP_PEER_DBG_DIS(PAF_SUBGRP(paf)->update_group);
}
}
}
}
if (found_peer)
@ -1133,6 +1178,8 @@ DEFUN (no_debug_bgp_update,
bgp_debug_list_free(bgp_debug_update_out_peers);
bgp_debug_list_free(bgp_debug_update_prefixes);
bgp_debug_clear_updgrp_update_dbg(vty->index);
if (vty->node == CONFIG_NODE)
{
DEBUG_OFF (update, UPDATE_IN);
@ -1281,6 +1328,42 @@ DEFUN (no_debug_bgp_zebra_prefix,
return CMD_SUCCESS;
}
/* debug bgp update-groups */
DEFUN (debug_bgp_update_groups,
debug_bgp_update_groups_cmd,
"debug bgp update-groups",
DEBUG_STR
BGP_STR
"BGP update-groups\n")
{
if (vty->node == CONFIG_NODE)
DEBUG_ON (update_groups, UPDATE_GROUPS);
else
{
TERM_DEBUG_ON (update_groups, UPDATE_GROUPS);
vty_out (vty, "BGP update-groups debugging is on%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN (no_debug_bgp_update_groups,
no_debug_bgp_update_groups_cmd,
"no debug bgp update-groups",
NO_STR
DEBUG_STR
BGP_STR
"BGP update-groups\n")
{
if (vty->node == CONFIG_NODE)
DEBUG_OFF (update_groups, UPDATE_GROUPS);
else
{
TERM_DEBUG_OFF (update_groups, UPDATE_GROUPS);
vty_out (vty, "BGP update-groups debugging is off%s", VTY_NEWLINE);
}
return CMD_SUCCESS;
}
DEFUN (no_debug_bgp,
no_debug_bgp_cmd,
"no debug bgp",
@ -1295,6 +1378,8 @@ DEFUN (no_debug_bgp,
bgp_debug_list_free(bgp_debug_update_prefixes);
bgp_debug_list_free(bgp_debug_zebra_prefixes);
bgp_debug_clear_updgrp_update_dbg(vty->index);
TERM_DEBUG_OFF (keepalive, KEEPALIVE);
TERM_DEBUG_OFF (update, UPDATE_IN);
TERM_DEBUG_OFF (update, UPDATE_OUT);
@ -1350,6 +1435,9 @@ DEFUN (show_debugging_bgp,
bgp_debug_list_print (vty, " BGP zebra debugging is on",
bgp_debug_zebra_prefixes);
if (BGP_DEBUG (update_groups, UPDATE_GROUPS))
vty_out (vty, " BGP update-groups debugging is on%s", VTY_NEWLINE);
vty_out (vty, "%s", VTY_NEWLINE);
return CMD_SUCCESS;
}
@ -1411,6 +1499,12 @@ bgp_config_write_debug (struct vty *vty)
write++;
}
if (CONF_BGP_DEBUG (update_groups, UPDATE_GROUPS))
{
vty_out (vty, "debug bgp update-groups%s", VTY_NEWLINE);
write++;
}
return write;
}
@ -1445,6 +1539,8 @@ bgp_debug_init (void)
install_element (CONFIG_NODE, &debug_bgp_update_direct_cmd);
install_element (ENABLE_NODE, &debug_bgp_zebra_cmd);
install_element (CONFIG_NODE, &debug_bgp_zebra_cmd);
install_element (ENABLE_NODE, &debug_bgp_update_groups_cmd);
install_element (CONFIG_NODE, &debug_bgp_update_groups_cmd);
/* deb bgp updates [in|out] A.B.C.D */
install_element (ENABLE_NODE, &debug_bgp_update_direct_peer_cmd);
@ -1491,6 +1587,8 @@ bgp_debug_init (void)
install_element (CONFIG_NODE, &no_debug_bgp_update_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_zebra_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_zebra_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_update_groups_cmd);
install_element (CONFIG_NODE, &no_debug_bgp_update_groups_cmd);
install_element (ENABLE_NODE, &no_debug_bgp_cmd);
}
@ -1577,7 +1675,8 @@ bgp_debug_keepalive (struct peer *peer)
}
int
bgp_debug_update (struct peer *peer, struct prefix *p, unsigned int inbound)
bgp_debug_update (struct peer *peer, struct prefix *p,
struct update_group *updgrp, unsigned int inbound)
{
if (inbound)
{
@ -1593,6 +1692,10 @@ bgp_debug_update (struct peer *peer, struct prefix *p, unsigned int inbound)
BGP_DEBUG_UPDATE_OUT,
bgp_debug_update_out_peers))
return 1;
/* Check if update debugging implicitly enabled for the group. */
if (updgrp && UPDGRP_DBG_ON(updgrp))
return 1;
}

View file

@ -22,6 +22,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define _QUAGGA_BGP_DEBUG_H
#include "bgp_attr.h"
#include "bgp_updgrp.h"
/* sort of packet direction */
#define DUMP_ON 1
@ -65,6 +66,7 @@ extern unsigned long conf_bgp_debug_keepalive;
extern unsigned long conf_bgp_debug_update;
extern unsigned long conf_bgp_debug_zebra;
extern unsigned long conf_bgp_debug_nht;
extern unsigned long conf_bgp_debug_update_groups;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
@ -73,6 +75,7 @@ extern unsigned long term_bgp_debug_keepalive;
extern unsigned long term_bgp_debug_update;
extern unsigned long term_bgp_debug_zebra;
extern unsigned long term_bgp_debug_nht;
extern unsigned long term_bgp_debug_update_groups;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
@ -98,6 +101,7 @@ struct bgp_debug_filter
#define BGP_DEBUG_UPDATE_PREFIX 0x04
#define BGP_DEBUG_ZEBRA 0x01
#define BGP_DEBUG_NHT 0x01
#define BGP_DEBUG_UPDATE_GROUPS 0x01
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
@ -125,13 +129,15 @@ struct bgp_debug_filter
extern const char *bgp_type_str[];
extern int bgp_dump_attr (struct peer *, struct attr *, char *, size_t);
extern int bgp_debug_peer_updout_enabled(struct peer *peer);
extern void bgp_notify_print (struct peer *, struct bgp_notify *, const char *);
extern const struct message bgp_status_msg[];
extern const int bgp_status_msg_max;
extern int bgp_debug_neighbor_events(struct peer *peer);
extern int bgp_debug_keepalive(struct peer *peer);
extern int bgp_debug_update(struct peer *peer, struct prefix *p, unsigned int inbound);
extern int bgp_debug_update(struct peer *peer, struct prefix *p,
struct update_group *updgrp, unsigned int inbound);
extern int bgp_debug_zebra(struct prefix *p);
#endif /* _QUAGGA_BGP_DEBUG_H */

View file

@ -27,6 +27,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "prefix.h"
#include "thread.h"
#include "linklist.h"
#include "queue.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgpd.h"

View file

@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "prefix.h"
#include "command.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"

View file

@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "memory.h"
#include "buffer.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"

View file

@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "plist.h"
#include "workqueue.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@ -45,6 +46,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#ifdef HAVE_SNMP
#include "bgpd/bgp_snmp.h"
#endif /* HAVE_SNMP */
#include "bgpd/bgp_updgrp.h"
/* BGP FSM (finite state machine) has three types of functions. Type
one is thread functions. Type two is event functions. Type three
@ -93,11 +95,17 @@ peer_xfer_conn(struct peer *from_peer)
if (!peer || !CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
return from_peer;
if (bgp_debug_neighbor_events(peer))
zlog_debug ("peer transfer (%s -> %s)", from_peer->host, peer->host);
BGP_WRITE_OFF(peer->t_write);
BGP_READ_OFF(peer->t_read);
BGP_WRITE_OFF(from_peer->t_write);
BGP_READ_OFF(from_peer->t_read);
BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_OFF(from_peer->t_routeadv);
fd = peer->fd;
peer->fd = from_peer->fd;
from_peer->fd = fd;
@ -390,27 +398,26 @@ bgp_keepalive_timer (struct thread *thread)
static int
bgp_routeq_empty (struct peer *peer)
{
afi_t afi;
safi_t safi;
struct peer_af *paf;
int af;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
PEERAF_FOREACH(peer, paf, af)
{
if (!FIFO_EMPTY(&peer->sync[afi][safi]->withdraw) ||
!FIFO_EMPTY(&peer->sync[afi][safi]->update))
if (!PAF_SUBGRP(paf))
continue;
if (!advertise_list_is_empty(PAF_SUBGRP(paf)))
return 0;
}
return 1;
}
static int
int
bgp_routeadv_timer (struct thread *thread)
{
struct peer *peer;
peer = THREAD_ARG (thread);
peer->t_routeadv = NULL;
peer->radv_adjusted = 0;
if (bgp_debug_neighbor_events(peer))
zlog_debug ("%s [FSM] Timer (routeadv timer expire)", peer->host);
@ -419,10 +426,9 @@ bgp_routeadv_timer (struct thread *thread)
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
/* MRAI timer is no longer restarted here, it would be done
* when the FIFO is built.
/* MRAI timer will be started again when FIFO is built, no need to
* do it here.
*/
return 0;
}
@ -630,9 +636,6 @@ bgp_adjust_routeadv (struct peer *peer)
return;
}
/* Mark that we've adjusted the timer */
peer->radv_adjusted = 1;
/*
* CASE I:
@ -655,8 +658,6 @@ bgp_adjust_routeadv (struct peer *peer)
{
BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, 0);
if (bgp_debug_update(peer, NULL, 0))
zlog_debug ("%s: MRAI timer to expire instantly", peer->host);
return;
}
@ -685,8 +686,6 @@ bgp_adjust_routeadv (struct peer *peer)
{
BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_ON(peer->t_routeadv, bgp_routeadv_timer, diff);
if (bgp_debug_update(peer, NULL, 0))
zlog_debug ("%s: MRAI timer to expire in %f secs", peer->host, diff);
}
}
@ -720,8 +719,6 @@ bgp_maxmed_onstartup_active (struct bgp *bgp)
void
bgp_maxmed_update (struct bgp *bgp)
{
struct listnode *node, *nnode;
struct peer *peer;
u_char maxmed_active;
u_int32_t maxmed_value;
@ -747,8 +744,7 @@ bgp_maxmed_update (struct bgp *bgp)
bgp->maxmed_active = maxmed_active;
bgp->maxmed_value = maxmed_value;
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
bgp_announce_route_all (peer);
update_group_announce(bgp);
}
}
@ -1005,6 +1001,10 @@ bgp_stop (struct peer *peer)
/* set last reset time */
peer->resettime = peer->uptime = bgp_clock ();
if (BGP_DEBUG (update_groups, UPDATE_GROUPS))
zlog_debug ("%s remove from all update group", peer->host);
update_group_remove_peer_afs(peer);
#ifdef HAVE_SNMP
bgpTrapBackwardTransition (peer);
#endif /* HAVE_SNMP */
@ -1339,6 +1339,7 @@ static int
bgp_establish (struct peer *peer)
{
struct bgp_notify *notify;
struct peer_af *paf;
afi_t afi;
safi_t safi;
int nsf_af_count = 0;
@ -1377,6 +1378,9 @@ bgp_establish (struct peer *peer)
if (bgp_flag_check (peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES))
zlog_info ("%%ADJCHANGE: neighbor %s Up", peer->host);
/* assign update-group/subgroup */
update_group_adjust_peer_afs(peer);
/* graceful restart */
UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
@ -1449,14 +1453,17 @@ bgp_establish (struct peer *peer)
|| CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV))
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH);
bgp_announce_route_all (peer);
bgp_announce_peer (peer);
/* Start the route advertisement timer to send updates to the peer - if BGP
* is not in read-only mode. If it is, the timer will be started at the end
* of read-only mode.
*/
if (!bgp_update_delay_active(peer->bgp))
{
BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 0);
}
if (peer->doppelganger && (peer->doppelganger->status != Deleted))
{

View file

@ -41,6 +41,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
THREAD_WRITE_ON(master,(T),(F),peer,(V)); \
} while (0)
#define BGP_PEER_WRITE_ON(T,F,V, peer) \
do { \
if (!(T) && ((peer)->status != Deleted)) \
THREAD_WRITE_ON(master,(T),(F),(peer),(V)); \
} while (0)
#define BGP_WRITE_OFF(T) \
do { \
if (T) \
@ -79,6 +85,7 @@ extern int bgp_event (struct thread *);
extern int bgp_event_update (struct peer *, int event);
extern int bgp_stop (struct peer *peer);
extern void bgp_timer_set (struct peer *);
extern int bgp_routeadv_timer (struct thread *);
extern void bgp_fsm_change_status (struct peer *peer, int status);
extern const char *peer_down_str[];
extern void bgp_update_delay_end (struct bgp *);

View file

@ -36,6 +36,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "filter.h"
#include "plist.h"
#include "stream.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"

View file

@ -28,6 +28,7 @@
#include "linklist.h"
#include "sockunion.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@ -412,7 +413,8 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best,
old_mpath_count = 0;
prev_mpath = new_best;
mp_node = listhead (mp_list);
debug = bgp_debug_update(NULL, &rn->p, 1) || bgp_debug_update(NULL, &rn->p, 0);
debug = bgp_debug_update(NULL, &rn->p, NULL, 1) ||
bgp_debug_update(NULL, &rn->p, NULL, 0);
if (debug)
prefix2str (&rn->p, pfx_buf, sizeof (pfx_buf));

View file

@ -25,6 +25,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "memory.h"
#include "stream.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"

View file

@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "privs.h"
#include "linklist.h"
#include "network.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_open.h"

View file

@ -31,6 +31,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "hash.h"
#include "jhash.h"
#include "nexthop.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"

View file

@ -27,6 +27,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "command.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"

View file

@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "sockunion.h" /* for inet_ntop () */
#include "linklist.h"
#include "plist.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@ -47,11 +48,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_updgrp.h"
int stream_put_prefix (struct stream *, struct prefix *);
/* Set up BGP packet marker and packet type. */
static int
int
bgp_packet_set_marker (struct stream *s, u_char type)
{
int i;
@ -72,7 +74,7 @@ bgp_packet_set_marker (struct stream *s, u_char type)
/* Set BGP packet header size entry. If size is zero then use current
stream size. */
static int
int
bgp_packet_set_size (struct stream *s)
{
int cp;
@ -85,7 +87,7 @@ bgp_packet_set_size (struct stream *s)
}
/* Add new packet to the peer. */
static void
void
bgp_packet_add (struct peer *peer, struct stream *s)
{
/* Add packet to the end of list. */
@ -140,181 +142,6 @@ bgp_connect_check (struct peer *peer, int change_state)
}
}
/* Make BGP update packet. */
static struct stream *
bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)
{
struct stream *s;
struct stream *snlri;
struct bgp_adj_out *adj;
struct bgp_advertise *adv;
struct stream *packet;
struct bgp_node *rn = NULL;
struct bgp_info *binfo = NULL;
bgp_size_t total_attr_len = 0;
unsigned long attrlen_pos = 0;
int space_remaining = 0;
int space_needed = 0;
size_t mpattrlen_pos = 0;
size_t mpattr_pos = 0;
int num_pfx_adv = 0;
char send_attr_str[BUFSIZ];
int send_attr_printed;
s = peer->work;
stream_reset (s);
snlri = peer->scratch;
stream_reset (snlri);
adv = FIFO_HEAD (&peer->sync[afi][safi]->update);
while (adv)
{
assert (adv->rn);
rn = adv->rn;
adj = adv->adj;
if (adv->binfo)
binfo = adv->binfo;
space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed = BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen);
/* When remaining space can't include NLRI and it's length. */
if (space_remaining < space_needed)
break;
/* If packet is empty, set attribute. */
if (stream_empty (s))
{
struct peer *from = NULL;
if (binfo)
from = binfo->peer;
/* 1: Write the BGP message header - 16 bytes marker, 2 bytes length,
* one byte message type.
*/
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
/* 2: withdrawn routes length */
stream_putw (s, 0);
/* 3: total attributes length - attrlen_pos stores the position */
attrlen_pos = stream_get_endp (s);
stream_putw (s, 0);
/* 4: if there is MP_REACH_NLRI attribute, that should be the first
* attribute, according to draft-ietf-idr-error-handling. Save the
* position.
*/
mpattr_pos = stream_get_endp(s);
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
total_attr_len = bgp_packet_attribute (NULL, peer, s,
adv->baa->attr,
NULL, afi, safi,
from, NULL, NULL);
space_remaining = STREAM_CONCAT_REMAIN (s, snlri, STREAM_SIZE(s)) -
BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed = BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen);
/* If the attributes alone do not leave any room for NLRI then
* return */
if (space_remaining < space_needed)
{
zlog_err ("%s cannot send UPDATE, the attributes do not leave "
"room for NLRI", peer->host);
/* Flush the FIFO update queue */
while (adv)
adv = bgp_advertise_clean (peer, adv->adj, afi, safi);
return NULL;
}
if (BGP_DEBUG (update, UPDATE_OUT) ||
BGP_DEBUG (update, UPDATE_PREFIX))
{
memset (send_attr_str, 0, BUFSIZ);
send_attr_printed = 0;
bgp_dump_attr (peer, adv->baa->attr, send_attr_str, BUFSIZ);
}
}
if (afi == AFI_IP && safi == SAFI_UNICAST)
stream_put_prefix (s, &rn->p);
else
{
/* Encode the prefix in MP_REACH_NLRI attribute */
struct prefix_rd *prd = NULL;
u_char *tag = NULL;
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
if (binfo && binfo->extra)
tag = binfo->extra->tag;
if (stream_empty(snlri))
mpattrlen_pos = bgp_packet_mpattr_start(snlri, afi, safi,
adv->baa->attr);
bgp_packet_mpattr_prefix(snlri, afi, safi, &rn->p, prd, tag);
}
num_pfx_adv++;
if (bgp_debug_update(peer, &rn->p, 0))
{
if (!send_attr_printed)
{
zlog_debug ("%s send UPDATE w/ attr: %s", peer->host, send_attr_str);
send_attr_printed = 1;
}
char buf[INET6_BUFSIZ];
zlog_debug ("%s send UPDATE %s/%d",
peer->host,
inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
rn->p.prefixlen);
}
/* Synchnorize attribute. */
if (adj->attr)
bgp_attr_unintern (&adj->attr);
else
peer->scount[afi][safi]++;
adj->attr = bgp_attr_intern (adv->baa->attr);
adv = bgp_advertise_clean (peer, adj, afi, safi);
}
if (! stream_empty (s))
{
if (!stream_empty(snlri))
{
bgp_packet_mpattr_end(snlri, mpattrlen_pos);
total_attr_len += stream_get_endp(snlri);
}
/* set the total attribute length correctly */
stream_putw_at (s, attrlen_pos, total_attr_len);
if (!stream_empty(snlri))
packet = stream_dupcat(s, snlri, mpattr_pos);
else
packet = stream_dup (s);
bgp_packet_set_size (packet);
if (BGP_DEBUG (update, UPDATE_OUT))
zlog_debug("%s form UPDATE (adv) total len %d numPfx %d",
peer->host,
(stream_get_endp (s) - stream_get_getp (s)), num_pfx_adv);
bgp_packet_add (peer, packet);
stream_reset (s);
stream_reset (snlri);
return packet;
}
return NULL;
}
static struct stream *
bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
{
@ -358,299 +185,28 @@ bgp_update_packet_eor (struct peer *peer, afi_t afi, safi_t safi)
return packet;
}
/* Make BGP withdraw packet. */
/* For ipv4 unicast:
16-octet marker | 2-octet length | 1-octet type |
2-octet withdrawn route length | withdrawn prefixes | 2-octet attrlen (=0)
*/
/* For other afi/safis:
16-octet marker | 2-octet length | 1-octet type |
2-octet withdrawn route length (=0) | 2-octet attrlen |
mp_unreach attr type | attr len | afi | safi | withdrawn prefixes
*/
static struct stream *
bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi)
{
struct stream *s;
struct stream *packet;
struct bgp_adj_out *adj;
struct bgp_advertise *adv;
struct bgp_node *rn;
unsigned long pos;
bgp_size_t unfeasible_len;
bgp_size_t total_attr_len;
size_t mp_start = 0;
size_t attrlen_pos = 0;
size_t mplen_pos = 0;
u_char first_time = 1;
int space_remaining = 0;
int space_needed = 0;
int num_pfx_wd = 0;
s = peer->work;
stream_reset (s);
while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL)
{
assert (adv->rn);
adj = adv->adj;
rn = adv->rn;
space_remaining = STREAM_REMAIN (s) -
BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed = (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN +
PSIZE (rn->p.prefixlen));
if (space_remaining < space_needed)
break;
if (stream_empty (s))
{
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
stream_putw (s, 0); /* unfeasible routes length */
}
else
first_time = 0;
if (afi == AFI_IP && safi == SAFI_UNICAST)
stream_put_prefix (s, &rn->p);
else
{
struct prefix_rd *prd = NULL;
if (rn->prn)
prd = (struct prefix_rd *) &rn->prn->p;
/* If first time, format the MP_UNREACH header */
if (first_time)
{
attrlen_pos = stream_get_endp (s);
/* total attr length = 0 for now. reevaluate later */
stream_putw (s, 0);
mp_start = stream_get_endp (s);
mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
}
bgp_packet_mpunreach_prefix(s, &rn->p, afi, safi, prd, NULL);
}
num_pfx_wd++;
if (bgp_debug_update(peer, &rn->p, 0))
{
char buf[INET6_BUFSIZ];
zlog_debug ("%s send UPDATE %s/%d -- unreachable",
peer->host,
inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, INET6_BUFSIZ),
rn->p.prefixlen);
}
peer->scount[afi][safi]--;
bgp_adj_out_remove (rn, adj, peer, afi, safi);
bgp_unlock_node (rn);
}
if (! stream_empty (s))
{
if (afi == AFI_IP && safi == SAFI_UNICAST)
{
unfeasible_len
= stream_get_endp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN;
stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len);
stream_putw (s, 0);
}
else
{
/* Set the mp_unreach attr's length */
bgp_packet_mpunreach_end(s, mplen_pos);
/* Set total path attribute length. */
total_attr_len = stream_get_endp(s) - mp_start;
stream_putw_at (s, attrlen_pos, total_attr_len);
}
bgp_packet_set_size (s);
if (BGP_DEBUG (update, UPDATE_OUT))
zlog_debug("%s form UPDATE (wd) total len %d numPfx %d",
peer->host,
(stream_get_endp (s) - stream_get_getp (s)), num_pfx_wd);
packet = stream_dup (s);
bgp_packet_add (peer, packet);
stream_reset (s);
return packet;
}
return NULL;
}
void
bgp_default_update_send (struct peer *peer, struct attr *attr,
afi_t afi, safi_t safi, struct peer *from)
{
struct stream *s;
struct stream *packet;
struct prefix p;
unsigned long pos;
bgp_size_t total_attr_len;
if (DISABLE_BGP_ANNOUNCE)
return;
if (afi == AFI_IP)
str2prefix ("0.0.0.0/0", &p);
#ifdef HAVE_IPV6
else
str2prefix ("::/0", &p);
#endif /* HAVE_IPV6 */
/* Logging the attribute. */
if (bgp_debug_update(peer, &p, 0))
{
char attrstr[BUFSIZ];
char buf[INET6_BUFSIZ];
attrstr[0] = '\0';
bgp_dump_attr (peer, attr, attrstr, BUFSIZ);
zlog_debug ("%s send UPDATE %s/%d %s",
peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
p.prefixlen, attrstr);
}
s = stream_new (BGP_MAX_PACKET_SIZE);
/* Make BGP update packet. */
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
/* Unfeasible Routes Length. */
stream_putw (s, 0);
/* Make place for total attribute length. */
pos = stream_get_endp (s);
stream_putw (s, 0);
total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL);
/* Set Total Path Attribute Length. */
stream_putw_at (s, pos, total_attr_len);
/* NLRI set. */
if (p.family == AF_INET && safi == SAFI_UNICAST)
stream_put_prefix (s, &p);
/* Set size. */
bgp_packet_set_size (s);
packet = stream_dup (s);
stream_free (s);
/* Dump packet if debug option is set. */
#ifdef DEBUG
/* bgp_packet_dump (packet); */
#endif /* DEBUG */
/* Add packet to the peer. */
bgp_packet_add (peer, packet);
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
}
void
bgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi)
{
struct stream *s;
struct stream *packet;
struct prefix p;
unsigned long attrlen_pos = 0;
unsigned long cp;
bgp_size_t unfeasible_len;
bgp_size_t total_attr_len;
size_t mp_start = 0;
size_t mplen_pos = 0;
if (DISABLE_BGP_ANNOUNCE)
return;
if (afi == AFI_IP)
str2prefix ("0.0.0.0/0", &p);
#ifdef HAVE_IPV6
else
str2prefix ("::/0", &p);
#endif /* HAVE_IPV6 */
total_attr_len = 0;
if (bgp_debug_update(peer, &p, 0))
{
char buf[INET6_BUFSIZ];
zlog_debug ("%s send UPDATE %s/%d -- unreachable",
peer->host, inet_ntop(p.family, &(p.u.prefix), buf, INET6_BUFSIZ),
p.prefixlen);
}
s = stream_new (BGP_MAX_PACKET_SIZE);
/* Make BGP update packet. */
bgp_packet_set_marker (s, BGP_MSG_UPDATE);
/* Unfeasible Routes Length. */;
cp = stream_get_endp (s);
stream_putw (s, 0);
/* Withdrawn Routes. */
if (p.family == AF_INET && safi == SAFI_UNICAST)
{
stream_put_prefix (s, &p);
unfeasible_len = stream_get_endp (s) - cp - 2;
/* Set unfeasible len. */
stream_putw_at (s, cp, unfeasible_len);
/* Set total path attribute length. */
stream_putw (s, 0);
}
else
{
attrlen_pos = stream_get_endp (s);
stream_putw (s, 0);
mp_start = stream_get_endp (s);
mplen_pos = bgp_packet_mpunreach_start(s, afi, safi);
bgp_packet_mpunreach_prefix(s, &p, afi, safi, NULL, NULL);
/* Set the mp_unreach attr's length */
bgp_packet_mpunreach_end(s, mplen_pos);
/* Set total path attribute length. */
total_attr_len = stream_get_endp(s) - mp_start;
stream_putw_at (s, attrlen_pos, total_attr_len);
}
bgp_packet_set_size (s);
packet = stream_dup (s);
stream_free (s);
/* Add packet to the peer. */
bgp_packet_add (peer, packet);
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
}
/* Get next packet to be written. */
static struct stream *
bgp_write_packet (struct peer *peer)
{
struct stream *s = NULL;
struct peer_af *paf;
struct bpacket *next_pkt;
afi_t afi;
safi_t safi;
struct stream *s = NULL;
struct bgp_advertise *adv;
s = stream_fifo_head (peer->obuf);
if (s)
return s;
/* The code beyond this part deals with update packets, check if updates
are on hold as part of the update-delay post processing stages. */
/*
* The code beyond this part deals with update packets, proceed only
* if peer is Established and updates are not on hold (as part of
* update-delay post processing).
*/
if (peer->status != Established)
return NULL;
if (peer->bgp && (peer->bgp->main_peers_update_hold ||
peer->bgp->rsclient_peers_update_hold))
return NULL;
@ -658,138 +214,109 @@ bgp_write_packet (struct peer *peer)
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw);
if (adv)
paf = peer_af_find (peer, afi, safi);
if (!paf || !PAF_SUBGRP(paf))
continue;
next_pkt = paf->next_pkt_to_send;
/* Try to generate a packet for the peer if we are at the end of
* the list. Always try to push out WITHDRAWs first. */
if (!next_pkt || !next_pkt->buffer)
{
s = bgp_withdraw_packet (peer, afi, safi);
if (s)
return s;
}
next_pkt = subgroup_withdraw_packet(PAF_SUBGRP(paf));
if (!next_pkt || !next_pkt->buffer)
subgroup_update_packet (PAF_SUBGRP(paf));
next_pkt = paf->next_pkt_to_send;
}
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
/* If we still don't have a packet to send to the peer, then
* try to find out out if we have to send eor or if not, skip to
* the next AFI, SAFI.
* Don't send the EOR prematurely... if the subgroup's coalesce
* timer is running, the adjacency-out structure is not created
* yet.
*/
if (!next_pkt || !next_pkt->buffer)
{
adv = FIFO_HEAD (&peer->sync[afi][safi]->update);
if (adv)
{
if (adv->binfo && adv->binfo->uptime <= peer->synctime)
{
if (CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_RCV)
&& CHECK_FLAG (adv->binfo->peer->cap, PEER_CAP_RESTART_ADV)
&& ! (CHECK_FLAG (adv->binfo->peer->cap,
PEER_CAP_RESTART_BIT_RCV) &&
CHECK_FLAG (adv->binfo->peer->cap,
PEER_CAP_RESTART_BIT_ADV))
&& ! CHECK_FLAG (adv->binfo->flags, BGP_INFO_STALE)
&& safi != SAFI_MPLS_VPN)
{
if (CHECK_FLAG (adv->binfo->peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED))
s = bgp_update_packet (peer, afi, safi);
}
else
s = bgp_update_packet (peer, afi, safi);
}
if (s)
return s;
}
if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV))
{
if (peer->afc_nego[afi][safi] && peer->synctime
&& ! CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)
if (!(PAF_SUBGRP(paf))->t_coalesce &&
peer->afc_nego[afi][safi] && peer->synctime
&& ! CHECK_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_EOR_SEND)
&& safi != SAFI_MPLS_VPN)
{
SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND);
SET_FLAG (peer->af_sflags[afi][safi],
PEER_STATUS_EOR_SEND);
return bgp_update_packet_eor (peer, afi, safi);
}
}
continue;
}
/*
* Found a packet template to send, overwrite packet with appropriate
* attributes from peer and advance peer
*/
s = bpacket_reformat_for_peer (next_pkt, paf);
bpacket_queue_advance_peer (paf);
if (bgp_debug_update(peer, NULL, NULL, 0))
zlog_debug ("u%llu:s%llu %s send UPDATE len %d ",
PAF_SUBGRP(paf)->update_group->id, PAF_SUBGRP(paf)->id,
peer->host, (stream_get_endp(s) - stream_get_getp(s)));
return s;
}
return NULL;
}
/* Are there prefixes queued for being withdrawn? */
int
bgp_peer_wd_fifo_exists (struct peer *peer)
/* The next action for the peer from a write perspective */
static void
bgp_write_proceed_actions (struct peer *peer)
{
afi_t afi;
safi_t safi;
struct bgp_advertise *adv;
struct peer_af *paf;
struct bpacket *next_pkt;
int fullq_found = 0;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw))
return 1;
return 0;
}
/* Are there prefixes queued for being advertised?
* Are they recent?
*/
int
bgp_peer_adv_fifo_exists (struct peer *peer, int chk_recent)
{
afi_t afi;
safi_t safi;
struct bgp_advertise *adv;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL)
{
if (!chk_recent)
return 1;
if (adv->binfo->uptime < peer->synctime)
return 1;
}
return 0;
}
/*
* Schedule updates for the peer, if needed.
*/
void
bgp_peer_schedule_updates(struct peer *peer)
{
/* If withdraw FIFO exists, immediately schedule write */
if (bgp_peer_wd_fifo_exists(peer) && !peer->t_write)
{
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("%s scheduling write thread", peer->host);
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
}
/* If update FIFO exists, fire MRAI timer */
if (bgp_peer_adv_fifo_exists(peer, 0) && !peer->radv_adjusted)
{
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("%s scheduling MRAI timer", peer->host);
bgp_adjust_routeadv(peer);
}
}
/* Is there partially written packet or updates we can send right
now. */
static int
bgp_write_proceed (struct peer *peer)
{
/* If queued packet exists, we should try to write it */
if (stream_fifo_head (peer->obuf))
return 1;
{
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
return;
}
/* If there are prefixes to be withdrawn or to be advertised (and
* queued before last MRAI timer expiry), schedule write
*/
if (bgp_peer_wd_fifo_exists(peer)
|| bgp_peer_adv_fifo_exists(peer, 1))
return 1;
return 0;
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
paf = peer_af_find (peer, afi, safi);
if (!paf)
continue;
next_pkt = paf->next_pkt_to_send;
if (next_pkt && next_pkt->buffer)
{
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
return;
}
/* No packets readily available for AFI/SAFI, are there subgroup packets
* that need to be generated? */
if (paf->subgroup &&
bpacket_queue_is_full(SUBGRP_INST(paf->subgroup),
SUBGRP_PKTQ(paf->subgroup)))
fullq_found = 1;
else if (subgroup_packets_to_build (paf->subgroup))
{
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
return;
}
}
if (fullq_found)
{
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
return;
}
}
/* Write packet to the peer. */
@ -816,7 +343,10 @@ bgp_write (struct thread *thread)
s = bgp_write_packet (peer);
if (!s)
return 0; /* nothing to send */
{
bgp_write_proceed_actions (peer);
return 0;
}
sockopt_cork (peer->fd, 1);
@ -892,8 +422,7 @@ bgp_write (struct thread *thread)
while (++count < peer->bgp->wpkt_quanta &&
(s = bgp_write_packet (peer)) != NULL);
if (bgp_write_proceed (peer))
BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
bgp_write_proceed_actions (peer);
done:
/* Update the last write if some updates were written. */
@ -1801,8 +1330,6 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (ret < 0)
return -1;
zlog_err ("%s [Update:RECV] Unfeasible NLRI received", peer->host);
withdraw.afi = AFI_IP;
withdraw.safi = SAFI_UNICAST;
withdraw.nlri = stream_pnt (s);
@ -1871,7 +1398,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
zlog_err ("%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
peer->host);
if (ret && bgp_debug_update(peer, NULL, 1))
if (ret && bgp_debug_update(peer, NULL, NULL, 1))
{
zlog_debug ("%s rcvd UPDATE w/ attr: %s", peer->host, peer->rcvd_attr_str);
peer->rcvd_attr_printed = 1;
@ -2052,7 +1579,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
if (peer->nsf[AFI_IP6][SAFI_MULTICAST])
bgp_clear_stale_route (peer, AFI_IP6, SAFI_MULTICAST);
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug ("rcvd End-of-RIB for IPv6 Multicast from %s", peer->host);
}
}
@ -2082,7 +1609,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)
bgp_update_explicit_eors(peer);
}
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug ("rcvd End-of-RIB for VPNv4 Unicast from %s", peer->host);
}
}
@ -2227,7 +1754,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)
reserved = stream_getc (s);
safi = stream_getc (s);
if (bgp_debug_update(peer, NULL, 0))
if (bgp_debug_update(peer, NULL, NULL, 0))
zlog_debug ("%s rcvd REFRESH_REQ for afi/safi: %d/%d",
peer->host, afi, safi);

View file

@ -26,12 +26,6 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define BGP_UNFEASIBLE_LEN 2U
#define BGP_WRITE_PACKET_MAX 10U
/* Size of FIFOs upon which write thread is triggered. Note that write
* thread is also triggered upon BGP work-queue completion.
*/
#define BGP_ADV_FIFO_QUANTA 500
#define BGP_WD_FIFO_QUANTA 200
/* When to refresh */
#define REFRESH_IMMEDIATE 1
#define REFRESH_DEFER 2
@ -63,8 +57,10 @@ extern int bgp_capability_receive (struct peer *, bgp_size_t);
extern void bgp_update_restarted_peers (struct peer *);
extern void bgp_update_implicit_eors (struct peer *);
extern void bgp_check_update_delay (struct bgp *);
extern int bgp_peer_wd_fifo_exists (struct peer *);
extern int bgp_peer_adv_fifo_exists (struct peer *, int);
extern void bgp_peer_schedule_updates(struct peer *peer);
extern int bgp_valid_host_address (unsigned long addr);
extern int bgp_packet_set_marker (struct stream *s, u_char type);
extern int bgp_packet_set_size (struct stream *s);
extern void bgp_packet_add (struct peer *peer, struct stream *s);
#endif /* _QUAGGA_BGP_PACKET_H */

View file

@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "command.h"
#include "memory.h"
#include "queue.h"
#include "bgpd.h"
#include "bgp_aspath.h"

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,12 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
struct bgp_nexthop_cache;
#define BGP_SHOW_SCODE_HEADER "Status codes: s suppressed, d damped, "\
"h history, * valid, > best, = multipath,%s"\
" i internal, r RIB-failure, S Stale, R Removed%s"
#define BGP_SHOW_OCODE_HEADER "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s"
#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path%s"
/* Ancillary information to struct bgp_info,
* used for uncommonly used data (aggregation, MPLS, etc.)
* and lazily allocated to save memory.
@ -199,12 +205,19 @@ enum bgp_path_type
BGP_PATH_MULTIPATH
};
static inline void
bgp_bump_version (struct bgp_node *node)
{
node->version = bgp_table_next_version(bgp_node_table(node));
}
/* Prototypes. */
extern void bgp_process_queue_init (void);
extern void bgp_route_init (void);
extern void bgp_route_finish (void);
extern void bgp_cleanup_routes (void);
extern void bgp_announce_route (struct peer *, afi_t, safi_t);
extern void bgp_stop_announce_route_timer(struct peer_af *paf);
extern void bgp_announce_route_all (struct peer *);
extern void bgp_default_originate (struct peer *, afi_t, safi_t, int);
extern void bgp_soft_reconfig_in (struct peer *, afi_t, safi_t);
@ -280,4 +293,13 @@ extern void route_vty_out (struct vty *, struct prefix *, struct bgp_info *, int
extern void route_vty_out_tag (struct vty *, struct prefix *, struct bgp_info *, int, safi_t);
extern void route_vty_out_tmp (struct vty *, struct prefix *, struct attr *, safi_t, char *);
extern int
subgroup_process_announce_selected (struct update_subgroup *subgrp,
struct bgp_info *selected,
struct bgp_node *rn);
extern int subgroup_announce_check(struct bgp_info *ri,
struct update_subgroup *subgrp,
struct prefix *p, struct attr *attr);
#endif /* _QUAGGA_BGP_ROUTE_H */

View file

@ -40,6 +40,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "buffer.h"
#include "sockunion.h"
#include "hash.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@ -1103,12 +1104,17 @@ route_set_ip_nexthop (void *rule, struct prefix *prefix,
bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_remote);
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
}
else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT)
&& peer->su_local
&& sockunion_family (peer->su_local) == AF_INET)
else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT))
{
bgp_info->attr->nexthop.s_addr = sockunion2ip (peer->su_local);
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
/* The next hop value will be set as part of packet rewrite.
* Set the flags here to indicate that rewrite needs to be done.
* Also, clear the value.
*/
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_CHANGED);
bgp_info->attr->nexthop.s_addr = 0;
}
}
else
@ -1116,6 +1122,8 @@ route_set_ip_nexthop (void *rule, struct prefix *prefix,
/* Set next hop value. */
bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
bgp_info->attr->nexthop = *rins->address;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_CHANGED);
}
}
@ -2177,6 +2185,9 @@ route_set_ipv6_nexthop_global (void *rule, struct prefix *prefix,
/* Set nexthop length. */
if (bgp_info->attr->extra->mp_nexthop_len == 0)
bgp_info->attr->extra->mp_nexthop_len = 16;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_CHANGED);
}
return RMAP_OKAY;
@ -2241,6 +2252,9 @@ route_set_ipv6_nexthop_local (void *rule, struct prefix *prefix,
/* Set nexthop length. */
if (bgp_info->attr->extra->mp_nexthop_len != 32)
bgp_info->attr->extra->mp_nexthop_len = 32;
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_CHANGED);
}
return RMAP_OKAY;
@ -2313,20 +2327,20 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix,
INET6_ADDRSTRLEN),
&peer_address);
}
else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT)
&& peer->su_local
&& sockunion_family (peer->su_local) == AF_INET6)
else if (CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_OUT))
{
inet_pton (AF_INET, sockunion2str (peer->su_local,
peer_addr_buf,
INET6_ADDRSTRLEN),
&peer_address);
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_PEER_ADDRESS);
SET_FLAG(bgp_info->attr->rmap_change_flags,
BATTR_RMAP_NEXTHOP_CHANGED);
/* clear next hop value. */
memset (&((bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global),
0, sizeof (struct in6_addr));
}
if (IN6_IS_ADDR_LINKLOCAL(&peer_address))
{
/* Set next hop value. */
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_local = peer_address;
/* The next hop value will be set as part of packet rewrite. */
/* Set nexthop length. */
if (bgp_info->attr->extra->mp_nexthop_len != 32)
@ -2334,8 +2348,7 @@ route_set_ipv6_nexthop_peer (void *rule, struct prefix *prefix,
}
else
{
/* Set next hop value. */
(bgp_attr_extra_get (bgp_info->attr))->mp_nexthop_global = peer_address;
/* The next hop value will be set as part of packet rewrite. */
/* Set nexthop length. */
if (bgp_info->attr->extra->mp_nexthop_len == 0)
@ -2652,7 +2665,7 @@ bgp_route_map_process_peer (char *rmap_name, struct peer *peer,
if (CHECK_FLAG (peer->af_flags[afi][safi],
PEER_FLAG_SOFT_RECONFIG))
{
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug("Processing route_map %s update on "
"peer %s (inbound, soft-reconfig)",
rmap_name, peer->host);
@ -2663,7 +2676,7 @@ bgp_route_map_process_peer (char *rmap_name, struct peer *peer,
|| CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
{
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug("Processing route_map %s update on "
"peer %s (inbound, route-refresh)",
rmap_name, peer->host);
@ -2699,7 +2712,7 @@ bgp_route_map_process_peer (char *rmap_name, struct peer *peer,
if (CHECK_FLAG (peer->af_flags[afi][safi],
PEER_FLAG_SOFT_RECONFIG))
{
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug("Processing route_map %s update on "
"peer %s (import, soft-reconfig)",
rmap_name, peer->host);
@ -2709,7 +2722,7 @@ bgp_route_map_process_peer (char *rmap_name, struct peer *peer,
else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
|| CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
{
if (bgp_debug_update(peer, NULL, 1))
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug("Processing route_map %s update on "
"peer %s (import, route-refresh)",
rmap_name, peer->host);
@ -2719,27 +2732,24 @@ bgp_route_map_process_peer (char *rmap_name, struct peer *peer,
}
}
/*
* For outbound, unsuppress and default-originate map change (content or
* map created), merely update the "config" here, the actual route
* announcement happens at the group level.
*/
if (filter->map[RMAP_OUT].name &&
(strcmp(rmap_name, filter->map[RMAP_OUT].name) == 0))
{
filter->map[RMAP_OUT].map =
route_map_lookup_by_name (filter->map[RMAP_OUT].name);
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("Processing route_map %s update on peer %s (outbound)",
rmap_name, peer->host);
if (route_update)
bgp_announce_route_all(peer);
}
if (filter->usmap.name &&
(strcmp(rmap_name, filter->usmap.name) == 0))
{
filter->usmap.map = route_map_lookup_by_name (filter->usmap.name);
if (route_update)
bgp_announce_route_all(peer);
}
if (peer->default_rmap[afi][safi].name &&
(strcmp (rmap_name, peer->default_rmap[afi][safi].name) == 0))
peer->default_rmap[afi][safi].map =
route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
}
static void
@ -2807,26 +2817,16 @@ bgp_route_map_process_update (void *arg, char *rmap_name, int route_update)
if (! peer->afc[afi][safi])
continue;
/* process in/out/import/export route-maps */
/* process in/out/import/export/default-orig route-maps */
bgp_route_map_process_peer(rmap_name, peer, afi, safi, route_update);
/* process default-originate route-map */
if (peer->default_rmap[afi][safi].name &&
(strcmp (rmap_name, peer->default_rmap[afi][safi].name) == 0))
{
peer->default_rmap[afi][safi].map =
route_map_lookup_by_name (peer->default_rmap[afi][safi].name);
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("Processing route_map %s update on "
"default-originate", rmap_name);
if (route_update)
bgp_default_originate (peer, afi, safi, 0);
}
}
}
/* for outbound/default-orig route-maps, process for groups */
update_group_policy_update(bgp, BGP_POLICY_ROUTE_MAP, rmap_name,
route_update, 0);
/* update peer-group config (template) */
bgp_route_map_update_peer_group(rmap_name, bgp);
/* For table route-map updates. */
@ -2893,7 +2893,7 @@ bgp_route_map_process_update (void *arg, char *rmap_name, int route_update)
if (route_update)
{
if (bgp_debug_update(peer, NULL, 0))
if (BGP_DEBUG (zebra, ZEBRA))
zlog_debug("Processing route_map %s update on "
"redistributed routes", rmap_name);
@ -2932,13 +2932,18 @@ bgp_route_map_mark_update (char *rmap_name)
for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
{
if (bgp->t_rmap_update == NULL)
{
/* rmap_update_timer of 0 means don't do route updates */
if (bgp->rmap_update_timer)
{
bgp->t_rmap_update =
thread_add_timer(master, bgp_route_map_update_timer, bgp,
bgp->rmap_update_timer);
/* Signal the groups that a route-map update event has started */
update_group_policy_update(bgp, BGP_POLICY_ROUTE_MAP, rmap_name, 1, 1);
}
else
bgp_route_map_process_update((void *)bgp, rmap_name, 0);
}

View file

@ -24,6 +24,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "memory.h"
#include "sockunion.h"
#include "vty.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"

View file

@ -43,6 +43,7 @@ struct bgp_table
struct peer *owner;
struct route_table *route_table;
u_int64_t version;
};
struct bgp_node
@ -63,6 +64,7 @@ struct bgp_node
struct bgp_node *prn;
u_int64_t version;
u_char flags;
#define BGP_NODE_PROCESS_SCHEDULED (1 << 0)
#define BGP_NODE_USER_CLEAR (1 << 1)
@ -353,4 +355,18 @@ bgp_table_iter_started (bgp_table_iter_t * iter)
return route_table_iter_started (&iter->rt_iter);
}
/* This would benefit from a real atomic operation...
* until then. */
static inline u_int64_t
bgp_table_next_version (struct bgp_table *table)
{
return ++table->version;
}
static inline u_int64_t
bgp_table_version (struct bgp_table *table)
{
return table->version;
}
#endif /* _QUAGGA_BGP_TABLE_H */

1842
bgpd/bgp_updgrp.c Normal file

File diff suppressed because it is too large Load diff

594
bgpd/bgp_updgrp.h Normal file
View file

@ -0,0 +1,594 @@
/**
* bgp_updgrp.c: BGP update group structures
*
* @copyright Copyright (C) 2014 Cumulus Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.net>
* @author Rajesh Varadarajan <rajesh@sproute.net>
* @author Pradosh Mohapatra <pradosh@sproute.net>
*
* 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.
*/
#ifndef _QUAGGA_BGP_UPDGRP_H
#define _QUAGGA_BGP_UPDGRP_H
#include "bgp_advertise.h"
#define BGP_DEFAULT_SUBGROUP_COALESCE_TIME 200
#define PEER_UPDGRP_FLAGS (PEER_FLAG_LOCAL_AS_NO_PREPEND | \
PEER_FLAG_LOCAL_AS_REPLACE_AS)
#define PEER_UPDGRP_AF_FLAGS (PEER_FLAG_SEND_COMMUNITY | \
PEER_FLAG_SEND_EXT_COMMUNITY | \
PEER_FLAG_DEFAULT_ORIGINATE | \
PEER_FLAG_REFLECTOR_CLIENT | \
PEER_FLAG_NEXTHOP_SELF | \
PEER_FLAG_NEXTHOP_UNCHANGED | \
PEER_FLAG_AS_PATH_UNCHANGED | \
PEER_FLAG_MED_UNCHANGED | \
PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | \
PEER_FLAG_REMOVE_PRIVATE_AS | \
PEER_FLAG_REMOVE_PRIVATE_AS_ALL | \
PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE | \
PEER_FLAG_AS_OVERRIDE)
#define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV)
#define PEER_UPDGRP_AF_CAP_FLAGS (PEER_CAP_ORF_PREFIX_SM_RCV | \
PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
typedef enum
{
BGP_ATTR_VEC_NH = 0,
BGP_ATTR_VEC_MAX
} bpacket_attr_vec_type;
typedef struct
{
u_int32_t flags;
unsigned long offset;
} bpacket_attr_vec;
#define BPACKET_ATTRVEC_FLAGS_UPDATED (1 << 0)
#define BPACKET_ATTRVEC_FLAGS_RMAP_CHANGED (1 << 1)
#define BPACKET_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS (1 << 2)
#define BPACKET_ATTRVEC_FLAGS_REFLECTED (1 << 3)
typedef struct bpacket_attr_vec_arr
{
bpacket_attr_vec entries[BGP_ATTR_VEC_MAX];
} bpacket_attr_vec_arr;
struct bpacket
{
/* for being part of an update subgroup's message list */
TAILQ_ENTRY (bpacket) pkt_train;
/* list of peers (well, peer_afs) that the packet needs to be sent to */
LIST_HEAD (pkt_peer_list, peer_af) peers;
struct stream *buffer;
bpacket_attr_vec_arr arr;
unsigned int ver;
};
struct bpacket_queue
{
TAILQ_HEAD (pkt_queue, bpacket) pkts;
#if 0
/* A dummy packet that is used to thread all peers that have
completed their work */
struct bpacket sentinel;
#endif
unsigned int conf_max_count;
unsigned int curr_count;
unsigned int hwm_count;
unsigned int max_count_reached_count;
};
struct update_group
{
/* back pointer to the BGP instance */
struct bgp *bgp;
/* list of subgroups that belong to the update group */
LIST_HEAD (subgrp_list, update_subgroup) subgrps;
/* lazy way to store configuration common to all peers
hash function will compute from this data */
struct peer *conf;
afi_t afi;
safi_t safi;
int afid;
u_int64_t id;
time_t uptime;
u_int32_t join_events;
u_int32_t prune_events;
u_int32_t merge_events;
u_int32_t updgrp_switch_events;
u_int32_t peer_refreshes_combined;
u_int32_t adj_count;
u_int32_t split_events;
u_int32_t merge_checks_triggered;
u_int32_t subgrps_created;
u_int32_t subgrps_deleted;
u_int32_t num_dbg_en_peers;
};
/*
* Shorthand for a global statistics counter.
*/
#define UPDGRP_GLOBAL_STAT(updgrp, stat) \
((updgrp)->bgp->update_group_stats.stat)
/*
* Add the given value to a counter on an update group and the bgp
* instance.
*/
#define UPDGRP_INCR_STAT_BY(updgrp, stat, value) \
do { \
(updgrp)->stat += (value); \
UPDGRP_GLOBAL_STAT(updgrp, stat) += (value); \
} while (0)
/*
* Increment a counter on a update group and its parent structures.
*/
#define UPDGRP_INCR_STAT(subgrp, stat) \
UPDGRP_INCR_STAT_BY(subgrp, stat, 1)
struct update_subgroup
{
/* back pointer to the parent update group */
struct update_group *update_group;
/* list of peers that belong to the subgroup */
LIST_HEAD (peer_list, peer_af) peers;
int peer_count;
/* for being part of an update group's subgroup list */
LIST_ENTRY (update_subgroup) updgrp_train;
struct bpacket_queue pkt_queue;
/*
* List of adj-out structures for this subgroup.
* It essentially represents the snapshot of every prefix that
* has been advertised to the members of the subgroup
*/
TAILQ_HEAD (adjout_queue, bgp_adj_out) adjq;
/* packet buffer for update generation */
struct stream *work;
/* We use a separate stream to encode MP_REACH_NLRI for efficient
* NLRI packing. peer->work stores all the other attributes. The
* actual packet is then constructed by concatenating the two.
*/
struct stream *scratch;
/* synchronization list and time */
struct bgp_synchronize *sync;
/* send prefix count */
unsigned long scount;
/* announcement attribute hash */
struct hash *hash;
struct thread *t_coalesce;
u_int32_t v_coalesce;
struct thread *t_merge_check;
/* table version that the subgroup has caught up to. */
uint64_t version;
/* version maintained to record adj changes */
uint64_t adj_version;
time_t uptime;
/*
* Identifying information about the subgroup that this subgroup was split
* from, if any.
*/
struct
{
u_int64_t update_group_id;
u_int64_t subgroup_id;
} split_from;
u_int32_t join_events;
u_int32_t prune_events;
/*
* This is bumped up when another subgroup merges into this one.
*/
u_int32_t merge_events;
u_int32_t updgrp_switch_events;
u_int32_t peer_refreshes_combined;
u_int32_t adj_count;
u_int32_t split_events;
u_int32_t merge_checks_triggered;
u_int64_t id;
struct zlog *log;
u_int16_t sflags;
/* Subgroup flags, see below */
u_int16_t flags;
};
/*
* We need to do an outbound refresh to get this subgroup into a
* consistent state.
*/
#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0)
#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0)
/*
* Add the given value to the specified counter on a subgroup and its
* parent structures.
*/
#define SUBGRP_INCR_STAT_BY(subgrp, stat, value) \
do { \
(subgrp)->stat += (value); \
if ((subgrp)->update_group) \
UPDGRP_INCR_STAT_BY((subgrp)->update_group, stat, value); \
} while (0)
/*
* Increment a counter on a subgroup and its parent structures.
*/
#define SUBGRP_INCR_STAT(subgrp, stat) \
SUBGRP_INCR_STAT_BY(subgrp, stat, 1)
/*
* Decrement a counter on a subgroup and its parent structures.
*/
#define SUBGRP_DECR_STAT(subgrp, stat) \
SUBGRP_INCR_STAT_BY(subgrp, stat, -1)
typedef int (*updgrp_walkcb) (struct update_group * updgrp, void *ctx);
/* really a private structure */
struct updwalk_context
{
struct vty *vty;
struct bgp_node *rn;
struct bgp_info *ri;
u_int64_t updgrp_id;
u_int64_t subgrp_id;
bgp_policy_type_e policy_type;
char *policy_name;
int policy_event_start_flag;
int policy_route_update;
updgrp_walkcb cb;
void *context;
u_int8_t flags;
#define UPDWALK_FLAGS_ADVQUEUE (1 << 0)
#define UPDWALK_FLAGS_ADVERTISED (1 << 1)
};
#define UPDWALK_CONTINUE HASHWALK_CONTINUE
#define UPDWALK_ABORT HASHWALK_ABORT
#define PAF_PEER(p) ((p)->peer)
#define PAF_SUBGRP(p) ((p)->subgroup)
#define PAF_UPDGRP(p) ((p)->subgroup->update_group)
#define PAF_PKTQ(f) SUBGRP_PKTQ((f)->subgroup)
#define UPDGRP_PEER(u) ((u)->conf)
#define UPDGRP_AFI(u) ((u)->afi)
#define UPDGRP_SAFI(u) ((u)->safi)
#define UPDGRP_INST(u) ((u)->bgp)
#define UPDGRP_AFFLAGS(u) \
((u)->conf->af_flags[UPDGRP_AFI(u)][UPDGRP_SAFI(u)])
#define UPDGRP_DBG_ON(u) ((u)->num_dbg_en_peers)
#define UPDGRP_PEER_DBG_EN(u) (((u)->num_dbg_en_peers)++)
#define UPDGRP_PEER_DBG_DIS(u) (((u)->num_dbg_en_peers)--)
#define UPDGRP_PEER_DBG_OFF(u) (u)->num_dbg_en_peers = 0
#define SUBGRP_AFI(s) UPDGRP_AFI((s)->update_group)
#define SUBGRP_SAFI(s) UPDGRP_SAFI((s)->update_group)
#define SUBGRP_PEER(s) UPDGRP_PEER((s)->update_group)
#define SUBGRP_PCOUNT(s) ((s)->peer_count)
#define SUBGRP_PFIRST(s) LIST_FIRST(&((s)->peers))
#define SUBGRP_PKTQ(s) &((s)->pkt_queue)
#define SUBGRP_INST(s) UPDGRP_INST((s)->update_group)
#define SUBGRP_AFFLAGS(s) UPDGRP_AFFLAGS((s)->update_group)
#define SUBGRP_UPDGRP(s) ((s)->update_group)
/*
* Walk all subgroups in an update group.
*/
#define UPDGRP_FOREACH_SUBGRP(updgrp, subgrp) \
LIST_FOREACH(subgrp, &((updgrp)->subgrps), updgrp_train)
#define UPDGRP_FOREACH_SUBGRP_SAFE(updgrp, subgrp, tmp_subgrp) \
LIST_FOREACH_SAFE(subgrp, &((updgrp)->subgrps), updgrp_train, tmp_subgrp)
#define SUBGRP_FOREACH_PEER(subgrp, paf) \
LIST_FOREACH(paf, &(subgrp->peers), subgrp_train)
#define SUBGRP_FOREACH_PEER_SAFE(subgrp, paf, temp_paf) \
LIST_FOREACH_SAFE(paf, &(subgrp->peers), subgrp_train, temp_paf)
#define SUBGRP_FOREACH_ADJ(subgrp, adj) \
TAILQ_FOREACH(adj, &(subgrp->adjq), subgrp_adj_train)
#define SUBGRP_FOREACH_ADJ_SAFE(subgrp, adj, adj_temp) \
TAILQ_FOREACH_SAFE(adj, &(subgrp->adjq), subgrp_adj_train, adj_temp)
/* Prototypes. */
/* bgp_updgrp.c */
extern void update_group_init (struct bgp *);
extern void
update_group_show (struct bgp *bgp, afi_t afi, safi_t safi, struct vty *vty);
extern void update_group_show_stats (struct bgp *bgp, struct vty *vty);
extern void update_group_adjust_peer (struct peer_af *paf);
extern int update_group_adjust_soloness (struct peer *peer, int set);
extern void
update_subgroup_remove_peer (struct update_subgroup *, struct peer_af *);
extern struct bgp_table *update_subgroup_rib (struct update_subgroup *);
extern void
update_subgroup_split_peer (struct peer_af *, struct update_group *);
extern int
update_subgroup_check_merge (struct update_subgroup *, const char *);
extern int
update_subgroup_trigger_merge_check (struct update_subgroup *,
int force);
extern void update_group_policy_update (struct bgp *bgp,
bgp_policy_type_e ptype, char *pname,
int route_update, int start_event);
extern void update_group_af_walk (struct bgp *bgp, afi_t afi, safi_t safi,
updgrp_walkcb cb, void *ctx);
extern void update_group_walk (struct bgp *bgp, updgrp_walkcb cb, void *ctx);
extern void update_group_periodic_merge (struct bgp *bgp);
extern void update_group_start_advtimer (struct bgp *bgp);
extern void update_subgroup_inherit_info (struct update_subgroup *to,
struct update_subgroup *from);
/* bgp_updgrp_packet.c */
extern struct bpacket *bpacket_alloc (void);
extern void bpacket_free (struct bpacket *pkt);
extern void bpacket_queue_init (struct bpacket_queue *q);
extern void bpacket_queue_cleanup (struct bpacket_queue *q);
extern void bpacket_queue_sanity_check (struct bpacket_queue *q);
extern struct bpacket *bpacket_queue_add (struct bpacket_queue *q,
struct stream *s,
struct bpacket_attr_vec_arr
*vecarr);
struct bpacket *bpacket_queue_remove (struct bpacket_queue *q);
extern struct bpacket *bpacket_queue_first (struct bpacket_queue *q);
struct bpacket *bpacket_queue_last (struct bpacket_queue *q);
unsigned int bpacket_queue_length (struct bpacket_queue *q);
unsigned int bpacket_queue_hwm_length (struct bpacket_queue *q);
int bpacket_queue_is_full (struct bgp *bgp, struct bpacket_queue *q);
extern void bpacket_queue_advance_peer (struct peer_af *paf);
extern void bpacket_queue_remove_peer (struct peer_af *paf);
extern void bpacket_add_peer (struct bpacket *pkt, struct peer_af *paf);
unsigned int bpacket_queue_virtual_length (struct peer_af *paf);
extern void bpacket_queue_show_vty (struct bpacket_queue *q, struct vty *vty);
int subgroup_packets_to_build (struct update_subgroup *subgrp);
extern struct bpacket *subgroup_update_packet (struct update_subgroup *s);
extern struct bpacket *subgroup_withdraw_packet (struct update_subgroup *s);
extern struct stream *bpacket_reformat_for_peer (struct bpacket *pkt,
struct peer_af *paf);
extern void bpacket_attr_vec_arr_reset (struct bpacket_attr_vec_arr *vecarr);
extern void bpacket_attr_vec_arr_set_vec (struct bpacket_attr_vec_arr *vecarr,
bpacket_attr_vec_type type,
struct stream *s,
struct attr *attr);
extern void
subgroup_default_update_packet (struct update_subgroup *subgrp,
struct attr *attr, struct peer *from);
extern void subgroup_default_withdraw_packet (struct update_subgroup *subgrp);
/* bgp_updgrp_adv.c */
extern struct bgp_advertise *bgp_advertise_clean_subgroup (struct
update_subgroup
*subgrp,
struct bgp_adj_out
*adj);
extern void update_group_show_adj_queue (struct bgp *bgp, afi_t afi,
safi_t safi, struct vty *vty,
u_int64_t id);
extern void update_group_show_advertised (struct bgp *bgp, afi_t afi,
safi_t safi, struct vty *vty,
u_int64_t id);
extern void update_group_show_packet_queue (struct bgp *bgp, afi_t afi,
safi_t safi, struct vty *vty,
u_int64_t id);
extern void subgroup_announce_route (struct update_subgroup *subgrp);
extern void subgroup_announce_all (struct update_subgroup *subgrp);
extern void
subgroup_default_originate (struct update_subgroup *subgrp, int withdraw);
extern void
group_announce_route (struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_node *rn, struct bgp_info *ri);
extern void subgroup_clear_table (struct update_subgroup *subgrp);
extern void update_group_announce (struct bgp *bgp);
extern void update_group_announce_rrclients (struct bgp *bgp);
extern void peer_af_announce_route (struct peer_af *paf, int combine);
extern struct bgp_adj_out *bgp_adj_out_alloc (struct update_subgroup *subgrp,
struct bgp_node *rn);
extern void bgp_adj_out_remove_subgroup (struct bgp_node *rn,
struct bgp_adj_out *adj,
struct update_subgroup *subgrp);
extern void
bgp_adj_out_set_subgroup (struct bgp_node *rn,
struct update_subgroup *subgrp,
struct attr *attr, struct bgp_info *binfo);
extern void
bgp_adj_out_unset_subgroup (struct bgp_node *rn,
struct update_subgroup *subgrp);
void
subgroup_announce_table (struct update_subgroup *subgrp,
struct bgp_table *table, int rsclient);
extern void
subgroup_trigger_write (struct update_subgroup *subgrp);
extern int
update_group_clear_update_dbg (struct update_group *updgrp, void *arg);
/*
* Inline functions
*/
/*
* bpacket_queue_is_empty
*/
static inline int
bpacket_queue_is_empty (struct bpacket_queue *queue)
{
/*
* The packet queue is empty if it only contains a sentinel.
*/
if (queue->curr_count != 1)
return 0;
assert (bpacket_queue_first (queue)->buffer == NULL);
return 1;
}
/*
* bpacket_next
*
* Returns the packet after the given packet in a bpacket queue.
*/
static inline struct bpacket *
bpacket_next (struct bpacket *pkt)
{
return TAILQ_NEXT (pkt, pkt_train);
}
/*
* update_group_adjust_peer_afs
*
* Adjust all peer_af structures for the given peer.
*/
static inline void
update_group_adjust_peer_afs (struct peer *peer)
{
struct peer_af *paf;
afi_t afi;
PEERAF_FOREACH (peer, paf, afi) update_group_adjust_peer (paf);
}
/*
* update_group_remove_peer_afs
*
* Remove all peer_af structures for the given peer from their subgroups.
*/
static inline void
update_group_remove_peer_afs (struct peer *peer)
{
struct peer_af *paf;
afi_t afi;
PEERAF_FOREACH (peer, paf, afi)
update_subgroup_remove_peer (PAF_SUBGRP (paf), paf);
}
/*
* update_subgroup_needs_refresh
*/
static inline int
update_subgroup_needs_refresh (const struct update_subgroup *subgrp)
{
if (CHECK_FLAG (subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH))
return 1;
else
return 0;
}
/*
* update_subgroup_set_needs_refresh
*/
static inline void
update_subgroup_set_needs_refresh (struct update_subgroup *subgrp, int value)
{
if (value)
SET_FLAG (subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH);
else
UNSET_FLAG (subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH);
}
static inline struct update_subgroup *
peer_subgroup (struct peer *peer, afi_t afi, safi_t safi)
{
struct peer_af *paf;
paf = peer_af_find (peer, afi, safi);
if (paf)
return PAF_SUBGRP (paf);
return NULL;
}
/*
* update_group_adjust_peer_afs
*
* Adjust all peer_af structures for the given peer.
*/
static inline void
bgp_announce_peer (struct peer *peer)
{
struct peer_af *paf;
int af;
PEERAF_FOREACH (peer, paf, af) subgroup_announce_all (PAF_SUBGRP (paf));
}
/**
* advertise_list_is_empty
*/
static inline int
advertise_list_is_empty (struct update_subgroup *subgrp)
{
if (!BGP_ADV_FIFO_EMPTY (&subgrp->sync->update) ||
!BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw) ||
!BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw_low))
{
return 0;
}
return 1;
}
#endif /* _QUAGGA_BGP_UPDGRP_H */

765
bgpd/bgp_updgrp_adv.c Normal file
View file

@ -0,0 +1,765 @@
/**
* bgp_updgrp_adv.c: BGP update group advertisement and adjacency
* maintenance
*
*
* @copyright Copyright (C) 2014 Cumulus Networks, Inc.
*
* @author Avneesh Sachdev <avneesh@sproute.net>
* @author Rajesh Varadarajan <rajesh@sproute.net>
* @author Pradosh Mohapatra <pradosh@sproute.net>
*
* 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 "memory.h"
#include "prefix.h"
#include "hash.h"
#include "thread.h"
#include "queue.h"
#include "routemap.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_advertise.h"
/********************
* PRIVATE FUNCTIONS
********************/
static inline struct bgp_adj_out *
adj_lookup (struct bgp_node *rn, struct update_subgroup *subgrp)
{
struct bgp_adj_out *adj;
if (!rn || !subgrp)
return NULL;
for (adj = rn->adj_out; adj; adj = adj->next)
if (adj->subgroup == subgrp)
break;
return adj;
}
static void
adj_free (struct bgp_adj_out *adj)
{
TAILQ_REMOVE (&(adj->subgroup->adjq), adj, subgrp_adj_train);
SUBGRP_DECR_STAT (adj->subgroup, adj_count);
XFREE (MTYPE_BGP_ADJ_OUT, adj);
}
static int
group_announce_route_walkcb (struct update_group *updgrp, void *arg)
{
struct updwalk_context *ctx = arg;
struct update_subgroup *subgrp;
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
{
/*
* Skip the subgroups that have coalesce timer running. We will
* walk the entire prefix table for those subgroups when the
* coalesce timer fires.
*/
if (!subgrp->t_coalesce)
subgroup_process_announce_selected (subgrp, ctx->ri, ctx->rn);
}
return UPDWALK_CONTINUE;
}
static void
subgrp_show_adjq_vty (struct update_subgroup *subgrp, struct vty *vty,
u_int8_t flags)
{
struct bgp_table *table;
struct bgp_adj_out *adj;
unsigned long output_count;
struct bgp_node *rn;
int header1 = 1;
struct bgp *bgp;
int header2 = 1;
bgp = SUBGRP_INST (subgrp);
if (!bgp)
return;
table = bgp->rib[SUBGRP_AFI (subgrp)][SUBGRP_SAFI (subgrp)];
output_count = 0;
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (adj = rn->adj_out; adj; adj = adj->next)
if (adj->subgroup == subgrp)
{
if (header1)
{
vty_out (vty,
"BGP table version is %llu, local router ID is %s%s",
table->version, inet_ntoa (bgp->router_id),
VTY_NEWLINE);
vty_out (vty, BGP_SHOW_SCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
vty_out (vty, BGP_SHOW_OCODE_HEADER, VTY_NEWLINE, VTY_NEWLINE);
header1 = 0;
}
if (header2)
{
vty_out (vty, BGP_SHOW_HEADER, VTY_NEWLINE);
header2 = 0;
}
if ((flags & UPDWALK_FLAGS_ADVQUEUE) && adj->adv && adj->adv->baa)
{
route_vty_out_tmp (vty, &rn->p, adj->adv->baa->attr,
SUBGRP_SAFI (subgrp), NULL);
output_count++;
}
if ((flags & UPDWALK_FLAGS_ADVERTISED) && adj->attr)
{
route_vty_out_tmp (vty, &rn->p, adj->attr, SUBGRP_SAFI (subgrp),
NULL);
output_count++;
}
}
if (output_count != 0)
vty_out (vty, "%sTotal number of prefixes %ld%s",
VTY_NEWLINE, output_count, VTY_NEWLINE);
}
static int
updgrp_show_adj_walkcb (struct update_group *updgrp, void *arg)
{
struct updwalk_context *ctx = arg;
struct update_subgroup *subgrp;
struct vty *vty;
vty = ctx->vty;
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
{
if (ctx->subgrp_id && (ctx->subgrp_id != subgrp->id))
continue;
vty_out (vty, "update group %llu, subgroup %llu%s", updgrp->id,
subgrp->id, VTY_NEWLINE);
subgrp_show_adjq_vty (subgrp, vty, ctx->flags);
}
return UPDWALK_CONTINUE;
}
static void
updgrp_show_adj (struct bgp *bgp, afi_t afi, safi_t safi,
struct vty *vty, u_int64_t id, u_int8_t flags)
{
struct updwalk_context ctx;
memset (&ctx, 0, sizeof (ctx));
ctx.vty = vty;
ctx.subgrp_id = id;
ctx.flags = flags;
update_group_af_walk (bgp, afi, safi, updgrp_show_adj_walkcb, &ctx);
}
static int
subgroup_coalesce_timer (struct thread *thread)
{
struct update_subgroup *subgrp;
subgrp = THREAD_ARG (thread);
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
zlog_debug ("u%llu:s%llu announcing routes upon coalesce timer expiry",
(SUBGRP_UPDGRP (subgrp))->id, subgrp->id);
subgrp->t_coalesce = NULL;
subgrp->v_coalesce = 0;
subgroup_announce_route (subgrp);
/* While the announce_route() may kick off the route advertisement timer for
* the members of the subgroup, we'd like to send the initial updates much
* faster (i.e., without enforcing MRAI). Also, if there were no routes to
* announce, this is the method currently employed to trigger the EOR.
*/
if (!bgp_update_delay_active(SUBGRP_INST(subgrp)))
{
struct peer_af *paf;
struct peer *peer;
SUBGRP_FOREACH_PEER (subgrp, paf)
{
peer = PAF_PEER(paf);
BGP_TIMER_OFF(peer->t_routeadv);
BGP_TIMER_ON (peer->t_routeadv, bgp_routeadv_timer, 0);
}
}
return 0;
}
static int
update_group_announce_walkcb (struct update_group *updgrp, void *arg)
{
struct update_subgroup *subgrp;
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
{
subgroup_announce_all (subgrp);
}
return UPDWALK_CONTINUE;
}
static int
update_group_announce_rrc_walkcb (struct update_group *updgrp, void *arg)
{
struct update_subgroup *subgrp;
afi_t afi;
safi_t safi;
struct peer *peer;
afi = UPDGRP_AFI (updgrp);
safi = UPDGRP_SAFI (updgrp);
peer = UPDGRP_PEER (updgrp);
/* Only announce if this is a group of route-reflector-clients */
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
{
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp)
{
subgroup_announce_all (subgrp);
}
}
return UPDWALK_CONTINUE;
}
/********************
* PUBLIC FUNCTIONS
********************/
/**
* Allocate an adj-out object. Do proper initialization of its fields,
* primarily its association with the subgroup and the prefix.
*/
struct bgp_adj_out *
bgp_adj_out_alloc (struct update_subgroup *subgrp, struct bgp_node *rn)
{
struct bgp_adj_out *adj;
adj = XCALLOC (MTYPE_BGP_ADJ_OUT, sizeof (struct bgp_adj_out));
adj->subgroup = subgrp;
if (rn)
{
BGP_ADJ_OUT_ADD (rn, adj);
bgp_lock_node (rn);
adj->rn = rn;
}
TAILQ_INSERT_TAIL (&(subgrp->adjq), adj, subgrp_adj_train);
SUBGRP_INCR_STAT (subgrp, adj_count);
return adj;
}
struct bgp_advertise *
bgp_advertise_clean_subgroup (struct update_subgroup *subgrp,
struct bgp_adj_out *adj)
{
struct bgp_advertise *adv;
struct bgp_advertise_attr *baa;
struct bgp_advertise *next;
struct bgp_advertise_fifo *fhead;
adv = adj->adv;
baa = adv->baa;
next = NULL;
if (baa)
{
fhead = &subgrp->sync->update;
/* Unlink myself from advertise attribute FIFO. */
bgp_advertise_delete (baa, adv);
/* Fetch next advertise candidate. */
next = baa->adv;
/* Unintern BGP advertise attribute. */
bgp_advertise_unintern (subgrp->hash, baa);
}
else
fhead = &subgrp->sync->withdraw;
/* Unlink myself from advertisement FIFO. */
BGP_ADV_FIFO_DEL (fhead, adv);
/* Free memory. */
bgp_advertise_free (adj->adv);
adj->adv = NULL;
return next;
}
void
bgp_adj_out_set_subgroup (struct bgp_node *rn,
struct update_subgroup *subgrp,
struct attr *attr, struct bgp_info *binfo)
{
struct bgp_adj_out *adj = NULL;
struct bgp_advertise *adv;
if (DISABLE_BGP_ANNOUNCE)
return;
/* Look for adjacency information. */
adj = adj_lookup (rn, subgrp);
if (!adj)
{
adj = bgp_adj_out_alloc (subgrp, rn);
if (!adj)
return;
}
if (adj->adv)
bgp_advertise_clean_subgroup (subgrp, adj);
adj->adv = bgp_advertise_new ();
adv = adj->adv;
adv->rn = rn;
assert (adv->binfo == NULL);
adv->binfo = bgp_info_lock (binfo); /* bgp_info adj_out reference */
if (attr)
adv->baa = bgp_advertise_intern (subgrp->hash, attr);
else
adv->baa = baa_new ();
adv->adj = adj;
/* Add new advertisement to advertisement attribute list. */
bgp_advertise_add (adv->baa, adv);
/*
* If the update adv list is empty, trigger the member peers'
* mrai timers so the socket writes can happen.
*/
if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->update))
{
struct peer_af *paf;
SUBGRP_FOREACH_PEER (subgrp, paf)
{
bgp_adjust_routeadv (PAF_PEER (paf));
}
}
BGP_ADV_FIFO_ADD (&subgrp->sync->update, &adv->fifo);
subgrp->version = max (subgrp->version, rn->version);
}
void
bgp_adj_out_unset_subgroup (struct bgp_node *rn,
struct update_subgroup *subgrp)
{
struct bgp_adj_out *adj;
struct bgp_advertise *adv;
if (DISABLE_BGP_ANNOUNCE)
return;
/* Lookup existing adjacency, if it is not there return immediately. */
adj = adj_lookup (rn, subgrp);
if (!adj)
goto done;
/* Clearn up previous advertisement. */
if (adj->adv)
bgp_advertise_clean_subgroup (subgrp, adj);
if (adj->attr)
{
/* We need advertisement structure. */
adj->adv = bgp_advertise_new ();
adv = adj->adv;
adv->rn = rn;
adv->adj = adj;
/* Schedule packet write, if FIFO is getting its first entry. */
if (BGP_ADV_FIFO_EMPTY (&subgrp->sync->withdraw))
subgroup_trigger_write(subgrp);
/* Add to synchronization entry for withdraw announcement. */
BGP_ADV_FIFO_ADD (&subgrp->sync->withdraw, &adv->fifo);
}
else
{
/* Remove myself from adjacency. */
BGP_ADJ_OUT_DEL (rn, adj);
/* Free allocated information. */
adj_free (adj);
bgp_unlock_node (rn);
}
/*
* Fall through.
*/
done:
subgrp->version = max (subgrp->version, rn->version);
}
void
bgp_adj_out_remove_subgroup (struct bgp_node *rn, struct bgp_adj_out *adj,
struct update_subgroup *subgrp)
{
if (adj->attr)
bgp_attr_unintern (&adj->attr);
if (adj->adv)
bgp_advertise_clean_subgroup (subgrp, adj);
BGP_ADJ_OUT_DEL (rn, adj);
adj_free (adj);
}
/*
* Go through all the routes and clean up the adj/adv structures corresponding
* to the subgroup.
*/
void
subgroup_clear_table (struct update_subgroup *subgrp)
{
struct bgp_adj_out *aout, *taout;
SUBGRP_FOREACH_ADJ_SAFE (subgrp, aout, taout)
{
bgp_unlock_node (aout->rn);
bgp_adj_out_remove_subgroup (aout->rn, aout, subgrp);
}
}
/*
* subgroup_announce_table
*/
void
subgroup_announce_table (struct update_subgroup *subgrp,
struct bgp_table *table, int rsclient)
{
struct bgp_node *rn;
struct bgp_info *ri;
struct attr attr;
struct attr_extra extra;
struct peer *peer;
struct peer *onlypeer;
afi_t afi;
safi_t safi;
peer = SUBGRP_PEER (subgrp);
afi = SUBGRP_AFI (subgrp);
safi = SUBGRP_SAFI (subgrp);
onlypeer = ((SUBGRP_PCOUNT (subgrp) == 1) ?
(SUBGRP_PFIRST (subgrp))->peer : NULL);
if (rsclient)
assert(onlypeer);
if (!table)
table = (rsclient) ? onlypeer->rib[afi][safi] : peer->bgp->rib[afi][safi];
if (safi != SAFI_MPLS_VPN
&& CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
subgroup_default_originate (subgrp, 0);
/* It's initialized in bgp_announce_[check|check_rsclient]() */
attr.extra = &extra;
for (rn = bgp_table_top (table); rn; rn = bgp_route_next (rn))
for (ri = rn->info; ri; ri = ri->next)
if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED))
{
if (!rsclient
&& subgroup_announce_check (ri, subgrp, &rn->p, &attr))
bgp_adj_out_set_subgroup (rn, subgrp, &attr, ri);
else
bgp_adj_out_unset_subgroup (rn, subgrp);
}
/*
* We walked through the whole table -- make sure our version number
* is consistent with the one on the table. This should allow
* subgroups to merge sooner if a peer comes up when the route node
* with the largest version is no longer in the table. This also
* covers the pathological case where all routes in the table have
* now been deleted.
*/
subgrp->version = max (subgrp->version, table->version);
/*
* Start a task to merge the subgroup if necessary.
*/
update_subgroup_trigger_merge_check (subgrp, 0);
}
/*
* subgroup_announce_route
*
* Refresh all routes out to a subgroup.
*/
void
subgroup_announce_route (struct update_subgroup *subgrp)
{
struct bgp_node *rn;
struct bgp_table *table;
struct peer *onlypeer;
struct peer *peer;
if (update_subgroup_needs_refresh (subgrp))
{
update_subgroup_set_needs_refresh (subgrp, 0);
}
/*
* First update is deferred until ORF or ROUTE-REFRESH is received
*/
onlypeer = ((SUBGRP_PCOUNT (subgrp) == 1) ?
(SUBGRP_PFIRST (subgrp))->peer : NULL);
if (onlypeer &&
CHECK_FLAG (onlypeer->
af_sflags[SUBGRP_AFI (subgrp)][SUBGRP_SAFI (subgrp)],
PEER_STATUS_ORF_WAIT_REFRESH))
return;
if (SUBGRP_SAFI (subgrp) != SAFI_MPLS_VPN)
subgroup_announce_table (subgrp, NULL, 0);
else
for (rn = bgp_table_top (update_subgroup_rib (subgrp)); rn;
rn = bgp_route_next (rn))
if ((table = (rn->info)) != NULL)
subgroup_announce_table (subgrp, table, 0);
peer = SUBGRP_PEER(subgrp);
if (CHECK_FLAG(peer->af_flags[SUBGRP_AFI(subgrp)][SUBGRP_SAFI(subgrp)],
PEER_FLAG_RSERVER_CLIENT))
subgroup_announce_table (subgrp, NULL, 1);
}
void
subgroup_default_originate (struct update_subgroup *subgrp, int withdraw)
{
struct bgp *bgp;
struct attr attr;
struct aspath *aspath;
struct prefix p;
struct peer *from;
struct bgp_node *rn;
struct bgp_info *ri;
struct peer *peer;
int ret = RMAP_DENYMATCH;
afi_t afi;
safi_t safi;
if (!subgrp)
return;
peer = SUBGRP_PEER (subgrp);
afi = SUBGRP_AFI (subgrp);
safi = SUBGRP_SAFI (subgrp);
if (!(afi == AFI_IP || afi == AFI_IP6))
return;
bgp = peer->bgp;
from = bgp->peer_self;
bgp_attr_default_set (&attr, BGP_ORIGIN_IGP);
aspath = attr.aspath;
attr.local_pref = bgp->default_local_pref;
memcpy (&attr.nexthop, &peer->nexthop.v4, IPV4_MAX_BYTELEN);
if (afi == AFI_IP)
str2prefix ("0.0.0.0/0", &p);
#ifdef HAVE_IPV6
else if (afi == AFI_IP6)
{
struct attr_extra *ae = attr.extra;
str2prefix ("::/0", &p);
/* IPv6 global nexthop must be included. */
memcpy (&ae->mp_nexthop_global, &peer->nexthop.v6_global,
IPV6_MAX_BYTELEN);
ae->mp_nexthop_len = 16;
/* If the peer is on shared nextwork and we have link-local
nexthop set it. */
if (peer->shared_network
&& !IN6_IS_ADDR_UNSPECIFIED (&peer->nexthop.v6_local))
{
memcpy (&ae->mp_nexthop_local, &peer->nexthop.v6_local,
IPV6_MAX_BYTELEN);
ae->mp_nexthop_len = 32;
}
}
#endif /* HAVE_IPV6 */
if (peer->default_rmap[afi][safi].name)
{
SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
for (rn = bgp_table_top (bgp->rib[afi][safi]); rn;
rn = bgp_route_next (rn))
{
for (ri = rn->info; ri; ri = ri->next)
{
struct attr dummy_attr;
struct attr_extra dummy_extra;
struct bgp_info info;
/* Provide dummy so the route-map can't modify the attributes */
dummy_attr.extra = &dummy_extra;
bgp_attr_dup (&dummy_attr, ri->attr);
info.peer = ri->peer;
info.attr = &dummy_attr;
ret =
route_map_apply (peer->default_rmap[afi][safi].map, &rn->p,
RMAP_BGP, &info);
/* The route map might have set attributes. If we don't flush them
* here, they will be leaked. */
bgp_attr_flush (&dummy_attr);
if (ret != RMAP_DENYMATCH)
break;
}
if (ret != RMAP_DENYMATCH)
break;
}
bgp->peer_self->rmap_type = 0;
if (ret == RMAP_DENYMATCH)
withdraw = 1;
}
if (withdraw)
{
if (CHECK_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
subgroup_default_withdraw_packet (subgrp);
UNSET_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE);
}
else
{
if (!CHECK_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
{
SET_FLAG (subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE);
subgroup_default_update_packet (subgrp, &attr, from);
}
}
bgp_attr_extra_free (&attr);
aspath_unintern (&aspath);
}
/*
* Announce the BGP table to a subgroup.
*
* At startup, we try to optimize route announcement by coalescing the
* peer-up events. This is done only the first time - from then on,
* subgrp->v_coalesce will be set to zero and the normal logic
* prevails.
*/
void
subgroup_announce_all (struct update_subgroup *subgrp)
{
if (!subgrp)
return;
/*
* If coalesce timer value is not set, announce routes immediately.
*/
if (!subgrp->v_coalesce)
{
if (bgp_debug_update(NULL, NULL, subgrp->update_group, 0))
zlog_debug ("u%llu:s%llu announcing all routes",
subgrp->update_group->id, subgrp->id);
subgroup_announce_route (subgrp);
return;
}
/*
* We should wait for the coalesce timer. Arm the timer if not done.
*/
if (!subgrp->t_coalesce)
{
THREAD_TIMER_MSEC_ON (master, subgrp->t_coalesce, subgroup_coalesce_timer,
subgrp, subgrp->v_coalesce);
}
}
/*
* Go through all update subgroups and set up the adv queue for the
* input route.
*/
void
group_announce_route (struct bgp *bgp, afi_t afi, safi_t safi,
struct bgp_node *rn, struct bgp_info *ri)
{
struct updwalk_context ctx;
ctx.ri = ri;
ctx.rn = rn;
update_group_af_walk (bgp, afi, safi, group_announce_route_walkcb, &ctx);
}
void
update_group_show_adj_queue (struct bgp *bgp, afi_t afi, safi_t safi,
struct vty *vty, u_int64_t id)
{
updgrp_show_adj (bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVQUEUE);
}
void
update_group_show_advertised (struct bgp *bgp, afi_t afi, safi_t safi,
struct vty *vty, u_int64_t id)
{
updgrp_show_adj (bgp, afi, safi, vty, id, UPDWALK_FLAGS_ADVERTISED);
}
void
update_group_announce (struct bgp *bgp)
{
update_group_walk (bgp, update_group_announce_walkcb, NULL);
}
void
update_group_announce_rrclients (struct bgp *bgp)
{
update_group_walk (bgp, update_group_announce_rrc_walkcb, NULL);
}

1136
bgpd/bgp_updgrp_packet.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -30,6 +30,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "log.h"
#include "memory.h"
#include "hash.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_advertise.h"
@ -50,6 +51,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_mpath.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_updgrp.h"
extern struct in_addr router_id_zebra;
@ -1027,6 +1029,51 @@ DEFUN (no_bgp_wpkt_quanta,
return bgp_wpkt_quanta_config_vty(vty, argv[0], 0);
}
int
bgp_coalesce_config_vty (struct vty *vty, const char *num, char set)
{
struct bgp *bgp;
bgp = vty->index;
if (set)
VTY_GET_INTEGER_RANGE ("coalesce-time", bgp->coalesce_time, num,
0, 4294967295);
else
bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
return CMD_SUCCESS;
}
int
bgp_config_write_coalesce_time (struct vty *vty, struct bgp *bgp)
{
if (bgp->coalesce_time != BGP_DEFAULT_SUBGROUP_COALESCE_TIME)
vty_out (vty, " coalesce-time %d%s",
bgp->coalesce_time, VTY_NEWLINE);
return 0;
}
DEFUN (bgp_coalesce_time,
bgp_coalesce_time_cmd,
"coalesce-time <0-4294967295>",
"Subgroup coalesce timer\n"
"Subgroup coalesce timer value (in ms)\n")
{
return bgp_coalesce_config_vty(vty, argv[0], 1);
}
DEFUN (no_bgp_coalesce_time,
no_bgp_coalesce_time_cmd,
"no coalesce-time <0-4294967295>",
"Subgroup coalesce timer\n"
"Subgroup coalesce timer value (in ms)\n")
{
return bgp_coalesce_config_vty(vty, argv[0], 0);
}
/* Maximum-paths configuration */
DEFUN (bgp_maxpaths,
bgp_maxpaths_cmd,
@ -1757,37 +1804,39 @@ ALIAS (no_bgp_default_local_preference,
"local preference (higher=more preferred)\n"
"Configure default local preference value\n")
static void
peer_announce_routes_if_rmap_out (struct bgp *bgp)
DEFUN (bgp_default_subgroup_pkt_queue_max,
bgp_default_subgroup_pkt_queue_max_cmd,
"bgp default subgroup-pkt-queue-max <20-100>",
"BGP specific commands\n"
"Configure BGP defaults\n"
"subgroup-pkt-queue-max\n"
"Configure subgroup packet queue max\n")
{
struct peer *peer;
struct listnode *node, *nnode;
struct bgp_filter *filter;
afi_t afi;
safi_t safi;
struct bgp *bgp;
u_int32_t max_size;
/* Reannounce all routes to appropriate neighbors */
for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
{
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
{
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
{
/* check if there's an out route-map on this client */
filter = &peer->filter[afi][safi];
if (ROUTE_MAP_OUT_NAME(filter))
{
if (bgp_debug_update(peer, NULL, 0))
zlog_debug("%s: Announcing routes again for peer %s"
"(afi=%d, safi=%d", __func__, peer->host, afi,
safi);
bgp = vty->index;
bgp_announce_route_all(peer);
}
}
}
}
VTY_GET_INTEGER ("subgroup packet queue max", max_size, argv[0]);
bgp_default_subgroup_pkt_queue_max_set (bgp, max_size);
return CMD_SUCCESS;
}
DEFUN (no_bgp_default_subgroup_pkt_queue_max,
no_bgp_default_subgroup_pkt_queue_max_cmd,
"no bgp default subgroup-pkt-queue-max",
NO_STR
"BGP specific commands\n"
"Configure BGP defaults\n"
"subgroup-pkt-queue-max\n")
{
struct bgp *bgp;
bgp = vty->index;
bgp_default_subgroup_pkt_queue_max_unset (bgp);
return CMD_SUCCESS;
}
DEFUN (bgp_rr_allow_outbound_policy,
@ -1806,7 +1855,7 @@ DEFUN (bgp_rr_allow_outbound_policy,
if (!bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY))
{
bgp_flag_set(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY);
peer_announce_routes_if_rmap_out(bgp);
update_group_announce_rrclients(bgp);
}
return CMD_SUCCESS;
@ -1828,7 +1877,7 @@ DEFUN (no_bgp_rr_allow_outbound_policy,
if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY))
{
bgp_flag_unset(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY);
peer_announce_routes_if_rmap_out(bgp);
update_group_announce_rrclients(bgp);
}
return CMD_SUCCESS;
@ -2197,6 +2246,43 @@ ALIAS (no_neighbor_local_as,
"Do not prepend local-as to updates from ebgp peers\n"
"Do not prepend local-as to updates from ibgp peers\n")
DEFUN (neighbor_solo,
neighbor_solo_cmd,
NEIGHBOR_CMD2 "solo",
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Solo peer - part of its own update group\n")
{
struct peer *peer;
int ret;
peer = peer_and_group_lookup_vty (vty, argv[0]);
if (! peer)
return CMD_WARNING;
ret = update_group_adjust_soloness(peer, 1);
return bgp_vty_return (vty, ret);
}
DEFUN (no_neighbor_solo,
no_neighbor_solo_cmd,
NO_NEIGHBOR_CMD2 "solo",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Solo peer - part of its own update group\n")
{
struct peer *peer;
int ret;
peer = peer_and_group_lookup_vty (vty, argv[0]);
if (! peer)
return CMD_WARNING;
ret = update_group_adjust_soloness(peer, 0);
return bgp_vty_return (vty, ret);
}
DEFUN (neighbor_password,
neighbor_password_cmd,
NEIGHBOR_CMD2 "password LINE",
@ -7685,6 +7771,12 @@ DEFUN (show_bgp_memory,
count * sizeof (struct bgp_static)),
VTY_NEWLINE);
if ((count = mtype_stats_alloc (MTYPE_BGP_PACKET)))
vty_out (vty, "%ld Packets, using %s of memory%s", count,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
count * sizeof (struct bpacket)),
VTY_NEWLINE);
/* Adj-In/Out */
if ((count = mtype_stats_alloc (MTYPE_BGP_ADJ_IN)))
vty_out (vty, "%ld Adj-In entries, using %s of memory%s", count,
@ -7876,6 +7968,9 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
if (bgp->v_maxmed_admin)
vty_out (vty, "Max-med administrative active%s", VTY_NEWLINE);
vty_out(vty, "BGP table version %llu%s",
bgp_table_version(bgp->rib[afi][safi]), VTY_NEWLINE);
ents = bgp_table_count (bgp->rib[afi][safi]);
vty_out (vty, "RIB entries %ld, using %s of memory%s", ents,
mtype_memstr (memstrbuf, sizeof (memstrbuf),
@ -7927,7 +8022,7 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
vty_out(vty, "%c", *delimit);
if (!delimit)
vty_out (vty, "%5u %7d %7d %8d %4d %4u ",
vty_out (vty, "%5u %7d %7d %8lu %4d %4u ",
peer->as,
peer->open_in + peer->update_in + peer->keepalive_in
+ peer->notify_in + peer->refresh_in
@ -7935,12 +8030,11 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
peer->open_out + peer->update_out + peer->keepalive_out
+ peer->notify_out + peer->refresh_out
+ peer->dynamic_cap_out,
peer->version[afi][safi],
0,
0,
peer->sync[afi][safi]->update.count +
peer->sync[afi][safi]->withdraw.count);
(unsigned long) peer->obuf->count);
else
vty_out (vty, "%5u %c %7d %c %7d %c %8d %c %4d %c %4u %c",
vty_out (vty, "%5u %c %7d %c %7d %c %8lu %c %4d %c %4u %c",
peer->as, *delimit,
peer->open_in + peer->update_in + peer->keepalive_in
+ peer->notify_in + peer->refresh_in
@ -7948,10 +8042,9 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
peer->open_out + peer->update_out + peer->keepalive_out
+ peer->notify_out + peer->refresh_out
+ peer->dynamic_cap_out, *delimit,
peer->version[afi][safi], *delimit,
0, *delimit,
0, *delimit,
peer->sync[afi][safi]->update.count +
peer->sync[afi][safi]->withdraw.count, *delimit);
(unsigned long) peer->obuf->count, *delimit);
vty_out (vty, "%8s",
peer_uptime (peer->uptime, timebuf, BGP_UPTIME_LEN));
@ -8320,6 +8413,7 @@ static void
bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
{
struct bgp_filter *filter;
struct peer_af *paf;
char orf_pfx_name[BUFSIZ];
int orf_pfx_count;
@ -8331,6 +8425,17 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
if (p->af_group[afi][safi])
vty_out (vty, " %s peer-group member%s", p->group->name, VTY_NEWLINE);
paf = peer_af_find(p, afi, safi);
if (paf && PAF_SUBGRP(paf))
{
vty_out (vty, " Update group %llu, subgroup %llu%s",
PAF_UPDGRP(paf)->id, PAF_SUBGRP(paf)->id, VTY_NEWLINE);
vty_out (vty, " Packet Queue length %d%s",
bpacket_queue_virtual_length(paf), VTY_NEWLINE);
} else
{
vty_out(vty, " Not part of any update group%s", VTY_NEWLINE);
}
if (CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
|| CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_RCV)
|| CHECK_FLAG (p->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_OLD_RCV)
@ -8425,7 +8530,8 @@ bgp_show_peer_afi (struct vty *vty, struct peer *p, afi_t afi, safi_t safi)
vty_out (vty, " default route-map %s%s,",
p->default_rmap[afi][safi].map ? "*" : "",
p->default_rmap[afi][safi].name);
if (CHECK_FLAG (p->af_sflags[afi][safi], PEER_STATUS_DEFAULT_ORIGINATE))
if (paf && PAF_SUBGRP(paf) && CHECK_FLAG(PAF_SUBGRP(paf)->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE))
vty_out (vty, " default sent%s", VTY_NEWLINE);
else
vty_out (vty, " default not sent%s", VTY_NEWLINE);
@ -8962,7 +9068,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
vty_out (vty, "Next connect timer due in %ld seconds%s",
thread_timer_remain_second (p->t_connect), VTY_NEWLINE);
if (p->t_routeadv)
vty_out (vty, "MRAI (interval %ld) timer expires in %ld seconds%s",
vty_out (vty, "MRAI (interval %u) timer expires in %ld seconds%s",
p->v_routeadv, thread_timer_remain_second (p->t_routeadv),
VTY_NEWLINE);
@ -9664,6 +9770,205 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary,
#endif /* HAVE IPV6 */
DEFUN (show_ip_bgp_updgrps,
show_ip_bgp_updgrps_cmd,
"show ip bgp update-groups summary",
SHOW_STR
IP_STR
BGP_STR
"BGP update groups\n"
"Summary information\n")
{
struct bgp *bgp;
bgp = bgp_get_default();
if (bgp)
update_group_show(bgp, AFI_IP, SAFI_UNICAST, vty);
return CMD_SUCCESS;
}
DEFUN (show_bgp_ipv6_updgrps,
show_bgp_ipv6_updgrps_cmd,
"show bgp update-groups summary",
SHOW_STR
BGP_STR
"BGP update groups\n"
"Summary information\n")
{
struct bgp *bgp;
bgp = bgp_get_default();
if (bgp)
update_group_show(bgp, AFI_IP6, SAFI_UNICAST, vty);
return CMD_SUCCESS;
}
DEFUN (show_bgp_updgrps,
show_bgp_updgrps_cmd,
"show bgp (ipv4|ipv6) (unicast|multicast) update-groups summary",
SHOW_STR
BGP_STR
"Address family\n"
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"BGP update groups\n"
"Summary information\n")
{
struct bgp *bgp;
afi_t afi;
safi_t safi;
afi = (strcmp(argv[0], "ipv4") == 0) ? AFI_IP : AFI_IP6;
safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
bgp = bgp_get_default();
if (bgp)
update_group_show(bgp, afi, safi, vty);
return CMD_SUCCESS;
}
DEFUN (show_bgp_updgrps_stats,
show_bgp_updgrps_stats_cmd,
"show bgp update-groups statistics",
SHOW_STR
BGP_STR
"BGP update groups\n"
"Statistics\n")
{
struct bgp *bgp;
bgp = bgp_get_default();
if (bgp)
update_group_show_stats(bgp, vty);
return CMD_SUCCESS;
}
static void
show_bgp_updgrps_adj_info_aux (struct vty *vty, afi_t afi, safi_t safi,
const char *what, u_int64_t subgrp_id)
{
struct bgp *bgp;
bgp = bgp_get_default();
if (bgp)
{
if (!strcmp(what, "advertise-queue"))
update_group_show_adj_queue(bgp, afi, safi, vty, subgrp_id);
else if (!strcmp(what, "advertised-routes"))
update_group_show_advertised(bgp, afi, safi, vty, subgrp_id);
else if (!strcmp(what, "packet-queue"))
update_group_show_packet_queue(bgp, afi, safi, vty, subgrp_id);
}
}
DEFUN (show_ip_bgp_updgrps_adj,
show_ip_bgp_updgrps_adj_cmd,
"show ip bgp update-groups (advertise-queue|advertised-routes|packet-queue)",
SHOW_STR
IP_STR
BGP_STR
"BGP update groups\n"
"Advertisement queue\n"
"Announced routes\n"
"Packet queue\n")
{
show_bgp_updgrps_adj_info_aux(vty, AFI_IP, SAFI_UNICAST, argv[0], 0);
return CMD_SUCCESS;
}
DEFUN (show_bgp_updgrps_afi_adj,
show_bgp_updgrps_afi_adj_cmd,
"show bgp (ipv4|ipv6) (unicast|multicast) update-groups (advertise-queue|advertised-routes|packet-queue)",
SHOW_STR
BGP_STR
"Address family\n"
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"BGP update groups\n"
"Advertisement queue\n"
"Announced routes\n"
"Packet queue\n")
{
afi_t afi;
safi_t safi;
afi = (strcmp(argv[0], "ipv4") == 0) ? AFI_IP : AFI_IP6;
safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
show_bgp_updgrps_adj_info_aux(vty, afi, safi, argv[2], 0);
}
DEFUN (show_bgp_updgrps_adj,
show_bgp_updgrps_adj_cmd,
"show bgp update-groups (advertise-queue|advertised-routes|packet-queue)",
SHOW_STR
BGP_STR
"BGP update groups\n"
"Advertisement queue\n"
"Announced routes\n"
"Packet queue\n")
{
show_bgp_updgrps_adj_info_aux(vty, AFI_IP6, SAFI_UNICAST, argv[0], 0);
return CMD_SUCCESS;
}
DEFUN (show_ip_bgp_updgrps_adj_s,
show_ip_bgp_updgrps_adj_subgroup_cmd,
"show ip bgp update-groups SUBGROUP-ID (advertise-queue|advertised-routes|packet-queue)",
SHOW_STR
IP_STR
BGP_STR
"BGP update groups\n"
"64-bit subgroup id\n"
"Advertisement queue\n"
"Announced routes\n"
"Packet queue\n")
{
show_bgp_updgrps_adj_info_aux(vty, AFI_IP, SAFI_UNICAST, argv[1],
atoll(argv[0]));
return CMD_SUCCESS;
}
DEFUN (show_bgp_updgrps_adj_s,
show_bgp_updgrps_adj_subgroup_cmd,
"show bgp update-groups SUBGROUP-ID (advertise-queue|advertised-routes|packet-queue)",
SHOW_STR
BGP_STR
"BGP update groups\n"
"64-bit subgroup id\n"
"Advertisement queue\n"
"Announced routes\n"
"Packet queue\n")
{
show_bgp_updgrps_adj_info_aux(vty, AFI_IP6, SAFI_UNICAST, argv[1],
atoll(argv[0]));
return CMD_SUCCESS;
}
DEFUN (show_bgp_updgrps_afi_adj_subgroup,
show_bgp_updgrps_afi_adj_subgroup_cmd,
"show bgp (ipv4|ipv6) (unicast|multicast) update-groups SUBGROUP-ID (advertise-queue|advertised-routes|packet-queue)",
SHOW_STR
BGP_STR
"Address family\n"
"Address family\n"
"Address Family modifier\n"
"Address Family modifier\n"
"BGP update groups\n"
"64-bit subgroup id\n"
"Advertisement queue\n"
"Announced routes\n"
"Packet queue\n")
{
afi_t afi;
safi_t safi;
afi = (strcmp(argv[0], "ipv4") == 0) ? AFI_IP : AFI_IP6;
safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
show_bgp_updgrps_adj_info_aux(vty, afi, safi, argv[3], atoll(argv[2]));
}
/* Redistribute VTY commands. */
DEFUN (bgp_redistribute_ipv4,
@ -10393,6 +10698,9 @@ bgp_vty_init (void)
install_element (BGP_NODE, &bgp_wpkt_quanta_cmd);
install_element (BGP_NODE, &no_bgp_wpkt_quanta_cmd);
install_element (BGP_NODE, &bgp_coalesce_time_cmd);
install_element (BGP_NODE, &no_bgp_coalesce_time_cmd);
/* "maximum-paths" commands. */
install_element (BGP_NODE, &bgp_maxpaths_cmd);
install_element (BGP_NODE, &no_bgp_maxpaths_cmd);
@ -10496,6 +10804,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_bgp_default_local_preference_cmd);
install_element (BGP_NODE, &no_bgp_default_local_preference_val_cmd);
/* "bgp default subgroup-pkt-queue-max" commands. */
install_element (BGP_NODE, &bgp_default_subgroup_pkt_queue_max_cmd);
install_element (BGP_NODE, &no_bgp_default_subgroup_pkt_queue_max_cmd);
/* bgp ibgp-allow-policy-mods command */
install_element (BGP_NODE, &bgp_rr_allow_outbound_policy_cmd);
install_element (BGP_NODE, &no_bgp_rr_allow_outbound_policy_cmd);
@ -10521,6 +10833,10 @@ bgp_vty_init (void)
install_element (BGP_NODE, &no_neighbor_local_as_val2_cmd);
install_element (BGP_NODE, &no_neighbor_local_as_val3_cmd);
/* "neighbor solo" commands. */
install_element (BGP_NODE, &neighbor_solo_cmd);
install_element (BGP_NODE, &no_neighbor_solo_cmd);
/* "neighbor password" commands. */
install_element (BGP_NODE, &neighbor_password_cmd);
install_element (BGP_NODE, &no_neighbor_password_cmd);
@ -11353,6 +11669,15 @@ bgp_vty_init (void)
/* "show ip bgp summary" commands. */
install_element (VIEW_NODE, &show_ip_bgp_summary_cmd);
install_element (VIEW_NODE, &show_ip_bgp_summary_csv_cmd);
install_element (VIEW_NODE, &show_ip_bgp_updgrps_cmd);
install_element (VIEW_NODE, &show_bgp_updgrps_cmd);
install_element (VIEW_NODE, &show_bgp_ipv6_updgrps_cmd);
install_element (VIEW_NODE, &show_ip_bgp_updgrps_adj_cmd);
install_element (VIEW_NODE, &show_bgp_updgrps_adj_cmd);
install_element (VIEW_NODE, &show_bgp_updgrps_afi_adj_cmd);
install_element (VIEW_NODE, &show_ip_bgp_updgrps_adj_subgroup_cmd);
install_element (VIEW_NODE, &show_bgp_updgrps_adj_subgroup_cmd);
install_element (VIEW_NODE, &show_bgp_updgrps_afi_adj_subgroup_cmd);
install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd);
install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd);
install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd);
@ -11371,6 +11696,15 @@ bgp_vty_init (void)
#endif /* HAVE_IPV6 */
install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_summary_csv_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_updgrps_cmd);
install_element (RESTRICTED_NODE, &show_bgp_updgrps_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv6_updgrps_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_updgrps_adj_cmd);
install_element (RESTRICTED_NODE, &show_bgp_updgrps_adj_cmd);
install_element (RESTRICTED_NODE, &show_bgp_updgrps_afi_adj_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_updgrps_adj_subgroup_cmd);
install_element (RESTRICTED_NODE, &show_bgp_updgrps_adj_subgroup_cmd);
install_element (RESTRICTED_NODE, &show_bgp_updgrps_afi_adj_subgroup_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd);
install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd);
install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd);
@ -11389,6 +11723,16 @@ bgp_vty_init (void)
#endif /* HAVE_IPV6 */
install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_summary_csv_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_updgrps_cmd);
install_element (ENABLE_NODE, &show_bgp_updgrps_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv6_updgrps_cmd);
install_element (ENABLE_NODE, &show_bgp_updgrps_stats_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_updgrps_adj_cmd);
install_element (ENABLE_NODE, &show_bgp_updgrps_adj_cmd);
install_element (ENABLE_NODE, &show_bgp_updgrps_afi_adj_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_updgrps_adj_subgroup_cmd);
install_element (ENABLE_NODE, &show_bgp_updgrps_adj_subgroup_cmd);
install_element (ENABLE_NODE, &show_bgp_updgrps_afi_adj_subgroup_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd);
install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd);
install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd);

View file

@ -27,5 +27,6 @@ extern void bgp_vty_init (void);
extern const char *afi_safi_print (afi_t, safi_t);
extern int bgp_config_write_update_delay (struct vty *, struct bgp *);
extern int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
extern int bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp);
#endif /* _QUAGGA_BGP_VTY_H */

View file

@ -29,6 +29,7 @@ Boston, MA 02111-1307, USA. */
#include "zclient.h"
#include "routemap.h"
#include "thread.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"

View file

@ -35,6 +35,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#include "plist.h"
#include "linklist.h"
#include "workqueue.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
@ -62,6 +63,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#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;
@ -547,6 +550,104 @@ bgp_default_local_preference_unset (struct bgp *bgp)
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. */
@ -906,8 +1007,10 @@ peer_new (struct bgp *bgp)
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);
@ -953,6 +1056,9 @@ peer_xfer_config (struct peer *peer_dst, struct peer *peer_src)
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)
{
@ -1057,9 +1163,6 @@ peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
active = peer_active (peer);
if (afi && safi)
peer->afc[afi][safi] = 1;
/* Last read and reset time set */
peer->readtime = peer->resettime = bgp_clock ();
@ -1068,6 +1171,15 @@ peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
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);
@ -1273,6 +1385,11 @@ peer_activate (struct peer *peer, afi_t afi, safi_t 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);
}
if (! active && peer_active (peer))
bgp_timer_set (peer);
else
@ -1332,6 +1449,10 @@ peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
/* 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))
{
@ -1552,6 +1673,9 @@ peer_delete (struct peer *peer)
peer->default_rmap[afi][safi].name = NULL;
}
FOREACH_AFI_SAFI (afi, safi)
peer_af_delete (peer, afi, safi);
peer_unlock (peer); /* initial reference */
return 0;
@ -1563,19 +1687,6 @@ peer_group_cmp (struct peer_group *g1, struct peer_group *g2)
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)
@ -2052,6 +2163,11 @@ peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer,
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;
@ -2151,6 +2267,10 @@ peer_group_unbind (struct bgp *bgp, struct peer *peer,
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;
@ -2240,6 +2360,7 @@ bgp_create (as_t *as, const char *name)
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;
@ -2251,12 +2372,12 @@ bgp_create (as_t *as, const char *name)
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;
}
@ -2614,7 +2735,10 @@ peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
}
}
else if (type == peer_change_reset_out)
{
update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_announce_route (peer, afi, safi);
}
}
struct peer_flag_action
@ -3386,8 +3510,11 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
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;
}
@ -3405,8 +3532,11 @@ peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
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;
}
@ -3437,8 +3567,11 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
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;
}
@ -3453,8 +3586,11 @@ peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
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;
}
@ -3670,8 +3806,12 @@ peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv)
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;
@ -3680,6 +3820,9 @@ peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv)
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;
@ -3702,8 +3845,12 @@ peer_advertise_interval_unset (struct peer *peer)
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;
@ -3716,6 +3863,10 @@ peer_advertise_interval_unset (struct peer *peer)
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;
@ -4035,6 +4186,40 @@ peer_password_unset (struct peer *peer)
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,
@ -4064,7 +4249,11 @@ 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))
{
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))
@ -4078,6 +4267,9 @@ peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
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;
@ -4113,6 +4305,8 @@ peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
}
}
@ -4123,7 +4317,11 @@ peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
filter->dlist[direct].alist = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
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))
@ -4137,6 +4335,8 @@ peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
@ -4158,6 +4358,9 @@ peer_distribute_update (struct access_list *access)
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++)
@ -4224,7 +4427,11 @@ peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
filter->plist[direct].plist = prefix_list_lookup (afi, name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
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))
@ -4238,6 +4445,9 @@ peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
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;
}
@ -4272,6 +4482,8 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
}
}
@ -4282,7 +4494,11 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
filter->plist[direct].plist = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
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))
@ -4296,6 +4512,9 @@ peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
@ -4317,6 +4536,13 @@ peer_prefix_list_update (struct prefix_list *plist)
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++)
@ -4379,7 +4605,11 @@ peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
filter->aslist[direct].aslist = as_list_lookup (name);
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
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))
@ -4393,6 +4623,8 @@ peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
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;
}
@ -4427,6 +4659,8 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
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;
}
}
@ -4437,7 +4671,11 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
filter->aslist[direct].aslist = NULL;
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
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))
@ -4451,6 +4689,9 @@ peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
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;
@ -4471,6 +4712,9 @@ peer_aslist_update (char *aslist_name)
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++)
@ -4507,6 +4751,7 @@ peer_aslist_update (char *aslist_name)
}
}
}
static void
peer_aslist_add (char *aslist_name)
{
@ -4522,27 +4767,6 @@ peer_aslist_del (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)
@ -4572,6 +4796,8 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
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;
}
@ -4588,6 +4814,8 @@ peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
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;
@ -4626,6 +4854,8 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
}
}
@ -4637,6 +4867,8 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
}
@ -4653,6 +4885,8 @@ peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
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;
@ -4683,6 +4917,7 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
peer_on_policy_change (peer, afi, safi);
bgp_announce_route (peer, afi, safi);
return 0;
}
@ -4699,6 +4934,7 @@ peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
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;
@ -4727,6 +4963,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
{
peer_on_policy_change (peer, afi, safi);
bgp_announce_route(peer, afi, safi);
return 0;
}
@ -4743,6 +4980,7 @@ peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
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;
@ -5301,6 +5539,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
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,
@ -5741,6 +5984,11 @@ bgp_config_write (struct vty *vty)
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);
@ -5797,6 +6045,9 @@ bgp_config_write (struct vty *vty)
/* 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",

View file

@ -22,14 +22,42 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
#define _QUAGGA_BGPD_H
/* For union sockunion. */
#include "queue.h"
#include "sockunion.h"
#include "routemap.h"
struct update_subgroup;
struct bpacket;
/* Typedef BGP specific types. */
typedef u_int32_t as_t;
typedef u_int16_t as16_t; /* we may still encounter 16 Bit asnums */
typedef u_int16_t bgp_size_t;
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
enum bgp_af_index
{
BGP_AF_START,
BGP_AF_IPV4_UNICAST = BGP_AF_START,
BGP_AF_IPV4_MULTICAST,
BGP_AF_IPV4_VPN,
BGP_AF_IPV6_UNICAST,
BGP_AF_IPV6_MULTICAST,
BGP_AF_MAX
};
#define AF_FOREACH(af) \
for ((af) = BGP_AF_START; (af) < BGP_AF_MAX; (af)++)
#define FOREACH_AFI_SAFI(afi, safi) \
for (afi = AFI_IP; afi < AFI_MAX; afi++) \
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
/* BGP master for system wide configurations and variables. */
struct bgp_master
{
@ -61,6 +89,9 @@ struct bgp_master
#define BGP_OPT_MULTIPLE_INSTANCE (1 << 1)
#define BGP_OPT_CONFIG_CISCO (1 << 2)
#define BGP_OPT_NO_LISTEN (1 << 3)
u_int64_t updgrp_idspace;
u_int64_t subgrp_idspace;
};
/* BGP route-map structure. */
@ -106,6 +137,27 @@ struct bgp
/* BGP route-server-clients. */
struct list *rsclient;
struct hash *update_groups[BGP_AF_MAX];
/*
* Global statistics for update groups.
*/
struct {
u_int32_t join_events;
u_int32_t prune_events;
u_int32_t merge_events;
u_int32_t split_events;
u_int32_t updgrp_switch_events;
u_int32_t peer_refreshes_combined;
u_int32_t adj_count;
u_int32_t merge_checks_triggered;
u_int32_t updgrps_created;
u_int32_t updgrps_deleted;
u_int32_t subgrps_created;
u_int32_t subgrps_deleted;
} update_group_stats;
/* BGP configuration. */
u_int16_t config;
#define BGP_CONFIG_ROUTER_ID (1 << 0)
@ -212,6 +264,9 @@ struct bgp
/* BGP default local-preference. */
u_int32_t default_local_pref;
/* BGP default subgroup pkt queue max */
u_int32_t default_subgroup_pkt_queue_max;
/* BGP default timer. */
u_int32_t default_holdtime;
u_int32_t default_keepalive;
@ -229,8 +284,7 @@ struct bgp
} maxpaths[AFI_MAX][SAFI_MAX];
u_int32_t wpkt_quanta; /* per peer packet quanta to write */
u_int32_t adv_quanta; /* adv FIFO size that triggers write */
u_int32_t wd_quanta; /* withdraw FIFO size that triggers write */
u_int32_t coalesce_time;
};
#define BGP_ROUTE_ADV_HOLD(bgp) \
@ -346,6 +400,38 @@ typedef enum
#define BGP_MAX_PACKET_SIZE 4096
#define BGP_MAX_PACKET_SIZE_OVERFLOW 1024
/*
* Trigger delay for bgp_announce_route().
*/
#define BGP_ANNOUNCE_ROUTE_SHORT_DELAY_MS 100
#define BGP_ANNOUNCE_ROUTE_DELAY_MS 500
struct peer_af
{
/* back pointer to the peer */
struct peer *peer;
/* which subgroup the peer_af belongs to */
struct update_subgroup *subgroup;
/* for being part of an update subgroup's peer list */
LIST_ENTRY(peer_af) subgrp_train;
/* for being part of a packet's peer list */
LIST_ENTRY(peer_af) pkt_train;
struct bpacket *next_pkt_to_send;
/*
* Trigger timer for bgp_announce_route().
*/
struct thread *t_announce_route;
afi_t afi;
safi_t safi;
int afid;
};
/* BGP neighbor structure. */
struct peer
{
@ -362,6 +448,10 @@ struct peer
/* BGP peer group. */
struct peer_group *group;
u_char af_group[AFI_MAX][SAFI_MAX];
u_int64_t version[AFI_MAX][SAFI_MAX];
/* BGP peer_af structures, per configured AF on this peer */
struct peer_af *peer_af_array[BGP_AF_MAX];
/* Peer's remote AS number. */
as_t as;
@ -479,6 +569,7 @@ struct peer
#define PEER_FLAG_DELETE (1 << 9) /* mark the peer for deleting */
#define PEER_FLAG_CONFIG_NODE (1 << 10) /* the node to update configs on */
#define PEER_FLAG_BFD (1 << 11) /* bfd */
#define PEER_FLAG_LONESOUL (1 << 12)
/* NSF mode (graceful restart) */
u_char nsf[AFI_MAX][SAFI_MAX];
@ -572,8 +663,6 @@ struct peer
struct thread *t_gr_restart;
struct thread *t_gr_stale;
int radv_adjusted; /* flag if MRAI has been adjusted or not */
/* workqueues */
struct work_queue *clear_node_queue;
@ -699,6 +788,12 @@ struct bgp_nlri
bgp_size_t length;
};
#define PEERAF_FOREACH(peer, paf, afi) \
for ((afi) = BGP_AF_START, (paf) = (peer)->peer_af_array[(afi)]; \
(afi) < BGP_AF_MAX; \
(afi)++, (paf) = (peer)->peer_af_array[(afi)]) \
if ((paf) != NULL) \
/* BGP versions. */
#define BGP_VERSION_4 4
@ -852,6 +947,9 @@ struct bgp_nlri
/* BGP default local preference. */
#define BGP_DEFAULT_LOCAL_PREF 100
/* BGP default subgroup packet queue max . */
#define BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX 40
/* BGP graceful restart */
#define BGP_DEFAULT_RESTART_TIME 120
#define BGP_DEFAULT_STALEPATH_TIME 360
@ -930,6 +1028,17 @@ enum bgp_clear_type
#define BGP_ERR_AS_OVERRIDE -34
#define BGP_ERR_MAX -35
/*
* Enumeration of different policy kinds a peer can be configured with.
*/
typedef enum
{
BGP_POLICY_ROUTE_MAP,
BGP_POLICY_FILTER_LIST,
BGP_POLICY_PREFIX_LIST,
BGP_POLICY_DISTRIBUTE_LIST,
} bgp_policy_type_e;
extern struct bgp_master *bm;
extern struct thread_master *master;
@ -1001,6 +1110,9 @@ extern int bgp_timers_unset (struct bgp *);
extern int bgp_default_local_preference_set (struct bgp *, u_int32_t);
extern int bgp_default_local_preference_unset (struct bgp *);
extern int bgp_default_subgroup_pkt_queue_max_set (struct bgp *bgp, u_int32_t);
extern int bgp_default_subgroup_pkt_queue_max_unset (struct bgp *bgp);
extern int bgp_update_delay_active (struct bgp *);
extern int bgp_update_delay_configured (struct bgp *);
extern int peer_rsclient_active (struct peer *);
@ -1096,4 +1208,95 @@ extern int bgp_route_map_update_timer (struct thread *thread);
extern void bgp_route_map_terminate(void);
extern int peer_cmp (struct peer *p1, struct peer *p2);
extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t);
extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t);
extern int peer_af_delete (struct peer *, afi_t, safi_t);
static inline int
afindex (afi_t afi, safi_t safi)
{
switch (afi)
{
case AFI_IP:
switch (safi)
{
case SAFI_UNICAST:
return BGP_AF_IPV4_UNICAST;
break;
case SAFI_MULTICAST:
return BGP_AF_IPV4_MULTICAST;
break;
case SAFI_MPLS_VPN:
return BGP_AF_IPV4_VPN;
break;
default:
return BGP_AF_MAX;
break;
}
break;
case AFI_IP6:
switch (safi)
{
case SAFI_UNICAST:
return BGP_AF_IPV6_UNICAST;
break;
case SAFI_MULTICAST:
return BGP_AF_IPV6_MULTICAST;
break;
default:
return BGP_AF_MAX;
break;
}
break;
default:
return BGP_AF_MAX;
break;
}
}
/* If peer is configured at least one address family return 1. */
static inline 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;
}
/* If peer is negotiated at least one address family return 1. */
static inline int
peer_afi_active_nego (const struct peer *peer, afi_t afi)
{
if (peer->afc_nego[afi][SAFI_UNICAST]
|| peer->afc_nego[afi][SAFI_MULTICAST]
|| peer->afc_nego[afi][SAFI_MPLS_VPN])
return 1;
return 0;
}
static inline char *
timestamp_string (time_t ts)
{
#ifdef HAVE_CLOCK_MONOTONIC
time_t tbuf;
tbuf = time(NULL) - (bgp_clock() - ts);
return ctime(&tbuf);
#else
return ctime(&ts);
#endif /* HAVE_CLOCK_MONOTONIC */
}
static inline int
peer_established (struct peer *peer)
{
if (peer->status == Established)
return 1;
return 0;
}
#endif /* _QUAGGA_BGPD_H */

View file

@ -60,6 +60,17 @@ elif test -n "$CFLAGS" ; then
cflags_specified=yes ;
fi
AC_ARG_ENABLE(tcmalloc,
[ --enable-tcmalloc Turn on tcmalloc],
[case "${enableval}" in
yes) tcmalloc_enabled=true
LIBS="$LIBS -ltcmalloc_minimal"
;;
no) tcmalloc_enabled=false ;;
*) AC_MSG_ERROR(bad value ${enableval} for --enable-tcmalloc) ;;
esac],[tcmalloc_enabled=false])
dnl --------------------
dnl Check CC and friends
dnl --------------------

View file

@ -225,6 +225,31 @@ hash_iterate (struct hash *hash,
}
}
/* Iterator function for hash. */
void
hash_walk (struct hash *hash,
int (*func) (struct hash_backet *, void *), void *arg)
{
unsigned int i;
struct hash_backet *hb;
struct hash_backet *hbnext;
int ret = HASHWALK_CONTINUE;
for (i = 0; i < hash->size; i++)
{
for (hb = hash->index[i]; hb; hb = hbnext)
{
/* get pointer to next hash backet here, in case (*func)
* decides to delete hb by calling hash_release
*/
hbnext = hb->next;
ret = (*func) (hb, arg);
if (ret == HASHWALK_ABORT)
return;
}
}
}
/* Clean up hash. */
void
hash_clean (struct hash *hash, void (*free_func) (void *))

View file

@ -25,6 +25,9 @@ Boston, MA 02111-1307, USA. */
#define HASH_INITIAL_SIZE 256 /* initial number of backets. */
#define HASH_THRESHOLD 10 /* expand when backet. */
#define HASHWALK_CONTINUE 0
#define HASHWALK_ABORT -1
struct hash_backet
{
/* Linked list. */
@ -71,6 +74,9 @@ extern void *hash_release (struct hash *, void *);
extern void hash_iterate (struct hash *,
void (*) (struct hash_backet *, void *), void *);
extern void hash_walk (struct hash *,
int (*) (struct hash_backet *, void *), void *);
extern void hash_clean (struct hash *, void (*) (void *));
extern void hash_free (struct hash *);

View file

@ -99,6 +99,10 @@ struct memory_list memory_list_bgp[] =
{ MTYPE_PEER_GROUP, "Peer group" },
{ MTYPE_PEER_DESC, "Peer description" },
{ MTYPE_PEER_PASSWORD, "Peer password string" },
{ MTYPE_BGP_PEER_AF, "BGP peer af" },
{ MTYPE_BGP_UPDGRP, "BGP update group" },
{ MTYPE_BGP_UPD_SUBGRP, "BGP update subgroup" },
{ MTYPE_BGP_PACKET, "BGP packet" },
{ MTYPE_ATTR, "BGP attribute" },
{ MTYPE_ATTR_EXTRA, "BGP extra attributes" },
{ MTYPE_AS_PATH, "BGP aspath" },

View file

@ -329,7 +329,7 @@ prefix_list_delete (struct prefix_list *plist)
route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
if (master->delete_hook)
(*master->delete_hook) (NULL);
(*master->delete_hook) (plist);
if (plist->name)
XFREE (MTYPE_PREFIX_LIST_STR, plist->name);

View file

@ -552,7 +552,7 @@ sockopt_v6only (int family, int sock)
/* If same family and same prefix return 1. */
int
sockunion_same (union sockunion *su1, union sockunion *su2)
sockunion_same (const union sockunion *su1, const union sockunion *su2)
{
int ret = 0;

View file

@ -86,7 +86,7 @@ enum connect_result
extern int str2sockunion (const char *, union sockunion *);
extern const char *sockunion2str (union sockunion *, char *, size_t);
extern int sockunion_cmp (union sockunion *, union sockunion *);
extern int sockunion_same (union sockunion *, union sockunion *);
extern int sockunion_same (const union sockunion *, const union sockunion *);
extern union sockunion *sockunion_str2su (const char *str);
extern int sockunion_accept (int sock, union sockunion *);

View file

@ -401,6 +401,21 @@ stream_getl_from (struct stream *s, size_t from)
return l;
}
/* Copy from stream at specific location to destination. */
void
stream_get_from (void *dst, struct stream *s, size_t from, size_t size)
{
STREAM_VERIFY_SANE(s);
if (!GETP_VALID (s, from + size))
{
STREAM_BOUND_WARN (s, "get from");
return;
}
memcpy (dst, s->data + from, size);
}
u_int32_t
stream_getl (struct stream *s)
{
@ -709,6 +724,38 @@ stream_put_in_addr (struct stream *s, struct in_addr *addr)
return sizeof (u_int32_t);
}
/* Put in_addr at location in the stream. */
int
stream_put_in_addr_at (struct stream *s, size_t putp, struct in_addr *addr)
{
STREAM_VERIFY_SANE(s);
if (!PUT_AT_VALID (s, putp + 4))
{
STREAM_BOUND_WARN (s, "put");
return 0;
}
memcpy (&s->data[putp], addr, 4);
return 4;
}
/* Put in6_addr at location in the stream. */
int
stream_put_in6_addr_at (struct stream *s, size_t putp, struct in6_addr *addr)
{
STREAM_VERIFY_SANE(s);
if (!PUT_AT_VALID (s, putp + 16))
{
STREAM_BOUND_WARN (s, "put");
return 0;
}
memcpy (&s->data[putp], addr, 16);
return 16;
}
/* Put prefix by nlri type format. */
int
stream_put_prefix (struct stream *s, struct prefix *p)

View file

@ -173,9 +173,12 @@ extern int stream_putq (struct stream *, uint64_t);
extern int stream_putq_at (struct stream *, size_t, uint64_t);
extern int stream_put_ipv4 (struct stream *, u_int32_t);
extern int stream_put_in_addr (struct stream *, struct in_addr *);
extern int stream_put_in_addr_at (struct stream *, size_t, struct in_addr *);
extern int stream_put_in6_addr_at (struct stream *, size_t, struct in6_addr *);
extern int stream_put_prefix (struct stream *, struct prefix *);
extern void stream_get (void *, struct stream *, size_t);
extern void stream_get_from (void *, struct stream *, size_t, size_t);
extern u_char stream_getc (struct stream *);
extern u_char stream_getc_from (struct stream *, size_t);
extern u_int16_t stream_getw (struct stream *);

View file

@ -3,6 +3,7 @@
#include "vty.h"
#include "stream.h"
#include "privs.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_aspath.h"

View file

@ -4,6 +4,7 @@
#include "stream.h"
#include "privs.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_open.h"

View file

@ -4,6 +4,7 @@
#include "stream.h"
#include "privs.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"

View file

@ -29,6 +29,7 @@
#include "linklist.h"
#include "memory.h"
#include "zclient.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"

View file

@ -4,6 +4,7 @@
#include "stream.h"
#include "privs.h"
#include "memory.h"
#include "queue.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"