Commit 6601a148 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Merge branch 'add-path'

parents 2d0b7e24 283c7dfa
......@@ -795,7 +795,7 @@ interpret(struct f_inst *what)
case SA_GW: res.val.px.ip = rta->gw; break;
case SA_NET: res.val.px.ip = (*f_rte)->net->n.prefix;
res.val.px.len = (*f_rte)->net->n.pxlen; break;
case SA_PROTO: res.val.s = rta->proto->name; break;
case SA_PROTO: res.val.s = rta->src->proto->name; break;
case SA_SOURCE: res.val.i = rta->source; break;
case SA_SCOPE: res.val.i = rta->scope; break;
case SA_CAST: res.val.i = rta->cast; break;
......@@ -827,7 +827,7 @@ interpret(struct f_inst *what)
case SA_GW:
{
ip_addr ip = v1.val.px.ip;
neighbor *n = neigh_find(rta->proto, &ip, 0);
neighbor *n = neigh_find(rta->src->proto, &ip, 0);
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
......
......@@ -11,6 +11,7 @@
#include <stdarg.h>
#include <string.h>
#include <strings.h>
int bsprintf(char *str, const char *fmt, ...);
int bvsprintf(char *str, const char *fmt, va_list args);
......
......@@ -218,6 +218,7 @@ proto_free_ahooks(struct proto *p)
p->main_ahook = NULL;
}
/**
* proto_config_new - create a new protocol configuration
* @pr: protocol the configuration will belong to
......@@ -830,6 +831,9 @@ proto_schedule_feed(struct proto *p, int initial)
/* Connect protocol to routing table */
if (initial && !p->proto->multitable)
{
p->main_source = rt_get_source(p, 0);
rt_lock_source(p->main_source);
p->main_ahook = proto_add_announce_hook(p, p->table, &p->stats);
p->main_ahook->in_filter = p->cf->in_filter;
p->main_ahook->out_filter = p->cf->out_filter;
......@@ -837,6 +841,7 @@ proto_schedule_feed(struct proto *p, int initial)
p->main_ahook->in_limit = p->cf->in_limit;
p->main_ahook->out_limit = p->cf->out_limit;
p->main_ahook->in_keep_filtered = p->cf->in_keep_filtered;
proto_reset_limit(p->main_ahook->rx_limit);
proto_reset_limit(p->main_ahook->in_limit);
proto_reset_limit(p->main_ahook->out_limit);
......@@ -890,6 +895,8 @@ proto_flush_loop(void *unused UNUSED)
return;
}
rt_prune_sources();
again:
WALK_LIST(p, flush_proto_list)
if (p->flushing)
......@@ -1088,6 +1095,12 @@ proto_notify_state(struct proto *p, unsigned ps)
if ((cs == FS_FEEDING) || (cs == FS_HAPPY))
proto_schedule_flush(p);
if (p->proto->multitable)
{
rt_unlock_source(p->main_source);
p->main_source = NULL;
}
neigh_prune(); // FIXME convert neighbors to resource?
rfree(p->pool);
p->pool = NULL;
......
......@@ -187,7 +187,7 @@ struct proto {
int (*reload_routes)(struct proto *);
/*
* Routing entry hooks (called only for rte's belonging to this protocol):
* Routing entry hooks (called only for routes belonging to this protocol):
*
* rte_recalculate Called at the beginning of the best route selection
* rte_better Compare two rte's and decide which one is better (1=first, 0=second).
......@@ -203,6 +203,7 @@ struct proto {
void (*rte_remove)(struct network *, struct rte *);
struct rtable *table; /* Our primary routing table */
struct rte_src *main_source; /* Primary route source */
struct announce_hook *main_ahook; /* Primary announcement hook */
struct announce_hook *ahooks; /* Announcement hooks for this protocol */
......
......@@ -251,10 +251,10 @@ void rt_unlock_table(rtable *);
void rt_setup(pool *, rtable *, char *, struct rtable_config *);
static inline net *net_find(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_find(&tab->fib, &addr, len); }
static inline net *net_get(rtable *tab, ip_addr addr, unsigned len) { return (net *) fib_get(&tab->fib, &addr, len); }
rte *rte_find(net *net, struct proto *p);
rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *);
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src);
static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); }
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct rte_src *src);
static inline void rte_update(struct proto *p, net *net, rte *new) { rte_update2(p->main_ahook, net, new, p->main_source); }
void rte_discard(rtable *tab, rte *old);
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
void rte_dump(rte *);
......@@ -300,9 +300,18 @@ struct mpnh {
unsigned char weight;
};
struct rte_src {
struct rte_src *next; /* Hash chain */
struct proto *proto; /* Protocol the source is based on */
u32 private_id; /* Private ID, assigned by the protocol */
u32 global_id; /* Globally unique ID of the source */
unsigned uc; /* Use count */
};
typedef struct rta {
struct rta *next, **pprev; /* Hash chain */
struct proto *proto; /* Protocol instance that originally created the route */
struct rte_src *src; /* Route source that created the route */
unsigned uc; /* Use count */
byte source; /* Route source (RTS_...) */
byte scope; /* Route scope (SCOPE_... -- see ip.h) */
......@@ -421,6 +430,13 @@ typedef struct ea_list {
#define EALF_BISECT 2 /* Use interval bisection for searching */
#define EALF_CACHED 4 /* Attributes belonging to cached rta */
struct rte_src *rt_find_source(struct proto *p, u32 id);
struct rte_src *rt_get_source(struct proto *p, u32 id);
static inline void rt_lock_source(struct rte_src *src) { src->uc++; }
static inline void rt_unlock_source(struct rte_src *src) { src->uc--; }
void rt_prune_sources(void);
eattr *ea_find(ea_list *, unsigned ea);
int ea_get_int(ea_list *, unsigned ea, int def);
void ea_dump(ea_list *);
......@@ -437,6 +453,7 @@ static inline int mpnh_same(struct mpnh *x, struct mpnh *y)
void rta_init(void);
rta *rta_lookup(rta *); /* Get rta equivalent to this one, uc++ */
static inline int rta_is_cached(rta *r) { return r->aflags & RTAF_CACHED; }
static inline rta *rta_clone(rta *r) { r->uc++; return r; }
void rta__free(rta *r);
static inline void rta_free(rta *r) { if (r && !--r->uc) rta__free(r); }
......
......@@ -58,9 +58,194 @@ pool *rta_pool;
static slab *rta_slab;
static slab *mpnh_slab;
static slab *rte_src_slab;
/* rte source ID bitmap */
static u32 *src_ids;
static u32 src_id_size, src_id_used, src_id_pos;
#define SRC_ID_SIZE_DEF 4
/* rte source hash */
static struct rte_src **src_table;
static u32 src_hash_order, src_hash_size, src_hash_count;
#define SRC_HASH_ORDER_DEF 6
#define SRC_HASH_ORDER_MAX 18
#define SRC_HASH_ORDER_MIN 10
struct protocol *attr_class_to_protocol[EAP_MAX];
static void
rte_src_init(void)
{
rte_src_slab = sl_new(rta_pool, sizeof(struct rte_src));
src_id_pos = 0;
src_id_size = SRC_ID_SIZE_DEF;
src_ids = mb_allocz(rta_pool, src_id_size * sizeof(u32));
/* ID 0 is reserved */
src_ids[0] = 1;
src_id_used = 1;
src_hash_count = 0;
src_hash_order = SRC_HASH_ORDER_DEF;
src_hash_size = 1 << src_hash_order;
src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
}
static inline int u32_cto(unsigned int x) { return ffs(~x) - 1; }
static inline u32
rte_src_alloc_id(void)
{
int i, j;
for (i = src_id_pos; i < src_id_size; i++)
if (src_ids[i] != 0xffffffff)
goto found;
/* If we are at least 7/8 full, expand */
if (src_id_used > (src_id_size * 28))
{
src_id_size *= 2;
src_ids = mb_realloc(src_ids, src_id_size * sizeof(u32));
bzero(src_ids + i, (src_id_size - i) * sizeof(u32));
goto found;
}
for (i = 0; i < src_id_pos; i++)
if (src_ids[i] != 0xffffffff)
goto found;
ASSERT(0);
found:
ASSERT(i < 0x8000000);
src_id_pos = i;
j = u32_cto(src_ids[i]);
src_ids[i] |= (1 << j);
src_id_used++;
return 32 * i + j;
}
static inline void
rte_src_free_id(u32 id)
{
int i = id / 32;
int j = id % 32;
ASSERT((i < src_id_size) && (src_ids[i] & (1 << j)));
src_ids[i] &= ~(1 << j);
src_id_used--;
}
static inline u32 rte_src_hash(struct proto *p, u32 x, u32 order)
{ return (x * 2902958171u) >> (32 - order); }
static void
rte_src_rehash(int step)
{
struct rte_src **old_tab, *src, *src_next;
u32 old_size, hash, i;
old_tab = src_table;
old_size = src_hash_size;
src_hash_order += step;
src_hash_size = 1 << src_hash_order;
src_table = mb_allocz(rta_pool, src_hash_size * sizeof(struct rte_src *));
for (i = 0; i < old_size; i++)
for (src = old_tab[i]; src; src = src_next)
{
src_next = src->next;
hash = rte_src_hash(src->proto, src->private_id, src_hash_order);
src->next = src_table[hash];
src_table[hash] = src;
}
mb_free(old_tab);
}
struct rte_src *
rt_find_source(struct proto *p, u32 id)
{
struct rte_src *src;
u32 hash = rte_src_hash(p, id, src_hash_order);
for (src = src_table[hash]; src; src = src->next)
if ((src->proto == p) && (src->private_id == id))
return src;
return NULL;
}
struct rte_src *
rt_get_source(struct proto *p, u32 id)
{
struct rte_src *src;
u32 hash = rte_src_hash(p, id, src_hash_order);
for (src = src_table[hash]; src; src = src->next)
if ((src->proto == p) && (src->private_id == id))
return src;
src = sl_alloc(rte_src_slab);
src->proto = p;
src->private_id = id;
src->global_id = rte_src_alloc_id();
src->uc = 0;
src->next = src_table[hash];
src_table[hash] = src;
src_hash_count++;
if ((src_hash_count > src_hash_size) && (src_hash_order < SRC_HASH_ORDER_MAX))
rte_src_rehash(1);
return src;
}
static inline void
rt_remove_source(struct rte_src **sp)
{
struct rte_src *src = *sp;
*sp = src->next;
rte_src_free_id(src->global_id);
sl_free(rte_src_slab, src);
src_hash_count--;
}
void
rt_prune_sources(void)
{
struct rte_src **sp;
int i;
for (i = 0; i < src_hash_size; i++)
{
sp = &src_table[i];
while (*sp)
{
if ((*sp)->uc == 0)
rt_remove_source(sp);
else
sp = &(*sp)->next;
}
}
while ((src_hash_count < (src_hash_size / 4)) && (src_hash_order > SRC_HASH_ORDER_MIN))
rte_src_rehash(-1);
}
/*
* Multipath Next Hop
*/
static inline unsigned int
mpnh_hash(struct mpnh *x)
{
......@@ -681,14 +866,14 @@ rta_alloc_hash(void)
static inline unsigned int
rta_hash(rta *a)
{
return (a->proto->hash_key ^ ipa_hash(a->gw) ^
return (((unsigned) a->src) ^ ipa_hash(a->gw) ^
mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
}
static inline int
rta_same(rta *x, rta *y)
{
return (x->proto == y->proto &&
return (x->src == y->src &&
x->source == y->source &&
x->scope == y->scope &&
x->cast == y->cast &&
......@@ -785,6 +970,7 @@ rta_lookup(rta *o)
r = rta_copy(o);
r->hash_key = h;
r->aflags = RTAF_CACHED;
rt_lock_source(r->src);
rt_lock_hostentry(r->hostentry);
rta_insert(r);
......@@ -804,6 +990,7 @@ rta__free(rta *a)
a->next->pprev = a->pprev;
a->aflags = 0; /* Poison the entry */
rt_unlock_hostentry(a->hostentry);
rt_unlock_source(a->src);
mpnh_free(a->nexthops);
ea_free(a->eattrs);
sl_free(rta_slab, a);
......@@ -826,7 +1013,7 @@ rta_dump(rta *a)
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
debug("p=%s uc=%d %s %s%s%s h=%04x",
a->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
a->src->proto->name, a->uc, rts[a->source], ip_scope_text(a->scope), rtc[a->cast],
rtd[a->dest], a->hash_key);
if (!(a->aflags & RTAF_CACHED))
debug(" !CACHED");
......@@ -894,6 +1081,7 @@ rta_init(void)
rta_slab = sl_new(rta_pool, sizeof(rta));
mpnh_slab = sl_new(rta_pool, sizeof(struct mpnh));
rta_alloc_hash();
rte_src_init();
}
/*
......
......@@ -51,29 +51,31 @@ dev_ifa_notify(struct proto *p, unsigned c, struct ifa *ad)
DBG("dev_if_notify: device shutdown: prefix not found\n");
return;
}
rte_update(p->table, n, p, p, NULL);
rte_update(p, n, NULL);
}
else if (c & IF_CHANGE_UP)
{
rta *a, A;
rta *a;
net *n;
rte *e;
DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
bzero(&A, sizeof(A));
A.proto = p;
A.source = RTS_DEVICE;
A.scope = SCOPE_UNIVERSE;
A.cast = RTC_UNICAST;
A.dest = RTD_DEVICE;
A.iface = ad->iface;
A.eattrs = NULL;
a = rta_lookup(&A);
rta a0 = {
.src = p->main_source,
.source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE,
.cast = RTC_UNICAST,
.dest = RTD_DEVICE,
.iface = ad->iface
};
a = rta_lookup(&a0);
n = net_get(p->table, ad->prefix, ad->pxlen);
e = rte_get_temp(a);
e->net = n;
e->pflags = 0;
rte_update(p->table, n, p, p, e);
rte_update(p, n, e);
}
}
......
This diff is collapsed.
......@@ -621,12 +621,14 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
return -1;
}
/*
static void
bgp_init_prefix(struct fib_node *N)
{
struct bgp_prefix *p = (struct bgp_prefix *) N;
p->bucket_node.next = NULL;
}
*/
static int
bgp_compare_u32(const u32 *x, const u32 *y)
......@@ -870,30 +872,125 @@ bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
mb_free(buck);
}
/* Prefix hash table */
static inline u32 prefix_hash(ip_addr prefix, int pxlen, u32 path_id, u32 order)
{
u32 x = ipa_hash(prefix) + pxlen + path_id;
return (x * 2902958171u) >> (32 - order);
}
static inline u32 px_hash_size(struct bgp_proto *p)
{ return 1 << p->px_hash_order; }
void
bgp_init_prefix_table(struct bgp_proto *p, u32 order)
{
p->px_hash_count = 0;
p->px_hash_order = order;
p->prefix_table = mb_allocz(p->p.pool, px_hash_size(p) * sizeof(struct bgp_prefix *));
p->prefix_slab = sl_new(p->p.pool, sizeof(struct bgp_prefix));
}
static void
bgp_rehash_prefix_table(struct bgp_proto *p, int step)
{
struct bgp_prefix **old_tab, *px, *px_next;
u32 old_size, hash, i;
old_tab = p->prefix_table;
old_size = px_hash_size(p);
p->px_hash_order += step;
p->prefix_table = mb_allocz(p->p.pool, px_hash_size(p) * sizeof(struct bgp_prefix *));
for (i = 0; i < old_size; i++)
for (px = old_tab[i]; px; px = px_next)
{
px_next = px->next;
hash = prefix_hash(px->n.prefix, px->n.pxlen, px->path_id, p->px_hash_order);
px->next = p->prefix_table[hash];
p->prefix_table[hash] = px;
}
mb_free(old_tab);
}
static struct bgp_prefix *
bgp_get_prefix(struct bgp_proto *p, ip_addr prefix, int pxlen, u32 path_id)
{
struct bgp_prefix *bp;
u32 hash = prefix_hash(prefix, pxlen, path_id, p->px_hash_order);
for (bp = p->prefix_table[hash]; bp; bp = bp->next)
if (bp->n.pxlen == pxlen && ipa_equal(bp->n.prefix, prefix) && bp->path_id == path_id)
return bp;
bp = sl_alloc(p->prefix_slab);
bp->n.prefix = prefix;
bp->n.pxlen = pxlen;
bp->path_id = path_id;
bp->next = p->prefix_table[hash];
p->prefix_table[hash] = bp;
bp->bucket_node.next = NULL;
p->px_hash_count++;
if ((p->px_hash_count > px_hash_size(p)) && (p->px_hash_order < 18))
bgp_rehash_prefix_table(p, 1);
return bp;
}
void
bgp_free_prefix(struct bgp_proto *p, struct bgp_prefix *bp)
{
struct bgp_prefix **bpp;
u32 hash = prefix_hash(bp->n.prefix, bp->n.pxlen, bp->path_id, p->px_hash_order);
for (bpp = &p->prefix_table[hash]; *bpp; *bpp = (*bpp)->next)
if (*bpp == bp)
break;
*bpp = bp->next;
sl_free(p->prefix_slab, bp);
p->px_hash_count--;
if ((p->px_hash_count < (px_hash_size(p) / 4)) && (p->px_hash_order > 10))
bgp_rehash_prefix_table(p, -1);
}
void
bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
{
struct bgp_proto *p = (struct bgp_proto *) P;
struct bgp_bucket *buck;
struct bgp_prefix *px;
rte *key;
u32 path_id;
DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
if (new)
{
key = new;
buck = bgp_get_bucket(p, n, attrs, new->attrs->source != RTS_BGP);
if (!buck) /* Inconsistent attribute list */
return;
}
else
{
key = old;
if (!(buck = p->withdraw_bucket))
{
buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
init_list(&buck->prefixes);
}
}
px = fib_get(&p->prefix_fib, &n->n.prefix, n->n.pxlen);
path_id = p->add_path_tx ? key->attrs->src->global_id : 0;
px = bgp_get_prefix(p, n->n.prefix, n->n.pxlen, path_id);
if (px->bucket_node.next)
{
DBG("\tRemoving old entry.\n");
......@@ -1026,7 +1123,7 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
if (rr)
{
/* Handling route reflection, RFC 4456 */
struct bgp_proto *src = (struct bgp_proto *) e->attrs->proto;
struct bgp_proto *src = (struct bgp_proto *) e->attrs->src->proto;
a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_ORIGINATOR_ID));
if (!a)
......@@ -1076,7 +1173,8 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
{
rte *e = *new;
struct bgp_proto *p = (struct bgp_proto *) P;
struct bgp_proto *new_bgp = (e->attrs->proto->proto == &proto_bgp) ? (struct bgp_proto *) e->attrs->proto : NULL;
struct bgp_proto *new_bgp = (e->attrs->src->proto->proto == &proto_bgp) ?
(struct bgp_proto *) e->attrs->src->proto : NULL;
if (p == new_bgp) /* Poison reverse updates */
return -1;
......@@ -1115,7 +1213,7 @@ bgp_get_neighbor(rte *r)
if (e && as_path_get_first(e->u.ptr, &as))
return as;
else
return ((struct bgp_proto *) r->attrs->proto)->remote_as;
return ((struct bgp_proto *) r->attrs->src->proto)->remote_as;
}
static inline int
......@@ -1128,8 +1226,8 @@ rte_resolvable(rte *rt)
int
bgp_rte_better(rte *new, rte *old)
{
struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->proto;
struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->proto;
struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->src->proto;
struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->src->proto;
eattr *x, *y;
u32 n, o;
......@@ -1263,7 +1361,7 @@ same_group(rte *r, u32 lpref, u32 lasn)
static inline int
use_deterministic_med(rte *r)
{
struct proto *P = r->attrs->proto;
struct proto *P = r->attrs->src->proto;
return (P->proto == &proto_bgp) && ((struct bgp_proto *) P)->cf->deterministic_med;
}
......@@ -1548,7 +1646,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
int withdraw = 0;
bzero(a, sizeof(rta));
a->proto = &bgp->p;
a->source = RTS_BGP;
a->scope = SCOPE_UNIVERSE;
a->cast = RTC_UNICAST;
......@@ -1757,14 +1854,14 @@ bgp_get_attr(eattr *a, byte *buf, int buflen)
}
void
bgp_attr_init(struct bgp_proto *p)
bgp_init_bucket_table(struct bgp_proto *p)
{
p->hash_size = 256;
p->hash_limit = p->hash_size * 4;
p->bucket_hash = mb_allocz(p->p.pool, p->hash_size * sizeof(struct bgp_bucket *));
init_list(&p->bucket_queue);
p->withdraw_bucket = NULL;
fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
// fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
}
void
......
......@@ -367,7 +367,9 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
p->conn = conn;
p->last_error_class = 0;
p->last_error_code = 0;
bgp_attr_init(conn->bgp);
bgp_init_bucket_table(p);
bgp_init_prefix_table(p, 8);
bgp_conn_set_state(conn, BS_ESTABLISHED);
proto_notify_state(&p->p, PS_UP);
}
......@@ -417,8 +419,11 @@ static void
bgp_send_open(struct bgp_conn *conn)
{
conn->start_state = conn->bgp->start_state;
conn->want_as4_support = conn->bgp->cf->enable_as4 && (conn->start_state != BSS_CONNECT_NOCAP);
conn->peer_as4_support = 0; // Default value, possibly changed by receiving capability.
// Default values, possibly changed by receiving capabilities.
conn->peer_refresh_support = 0;
conn->peer_as4_support = 0;
conn->peer_add_path = 0;
conn->advertised_as = 0;
DBG("BGP: Sending open\n");
......@@ -970,19 +975,17 @@ get_igp_table(struct bgp_config *cf)
static struct proto *
bgp_init(struct proto_config *C)
{
struct bgp_config *c = (struct bgp_config *) C;
struct proto *P = proto_new(C, sizeof(struct bgp_proto));
struct bgp_config *c = (struct bgp_config *) C;
struct bgp_proto *p = (struct bgp_proto *) P;
P->accept_ra_types = c->secondary ? RA_ACCEPTED : RA_OPTIMAL;
P->rt_notify = bgp_rt_notify;
P->rte_better = bgp_rte_better;
P->import_control = bgp_import_control;
P->neigh_notify = bgp_neigh_notify;
P->reload_routes = bgp_reload_routes;
if (c->deterministic_med)
P->rte_recalculate = bgp_rte_recalculate;
P->rte_better = bgp_rte_better;
P->rte_recalculate = c->deterministic_med ? bgp_rte_recalculate : NULL;
p->cf = c;
p->local_as = c->local_as;
......@@ -1238,15 +1241,19 @@ bgp_show_proto_info(struct proto *P)
else if (P->proto_state == PS_UP)
{
cli_msg(-1006, " Neighbor ID: %R", p->remote_id);
cli_msg(-1006, " Neighbor caps: %s%s",
cli_msg(-1006, " Neighbor caps: %s%s%s%s",
c->peer_refresh_support ? " refresh" : "",
c->peer_as4_support ? " AS4" : "");
cli_msg(-1006, " Session: %s%s%s%s%s",
c->peer_as4_support ? " AS4" : "",
(c->peer_add_path & ADD_PATH_RX) ? " add-path-rx" : "",
(c->peer_add_path & ADD_PATH_TX) ? " add-path-tx" : "");
cli_msg(-1006, " Session: %s%s%s%s%s%s%s",
p->is_internal ? "internal" : "external",
p->cf->multihop ? " multihop" : "",
p->rr_client ? " route-reflector" : "",
p->rs_client ? " route-server" : "",
p->as4_session ? " AS4" : "");
p->as4_session ? " AS4" : "",
p->add_path_rx ? " add-path-rx" : "",
p->add_path_tx ? " add-path-tx" : "");
cli_msg(-1006, " Source address: %I", p->source_addr);
if (P->cf->in_limit)
cli_msg(-1006, " Route limit: %d/%d",
......
......@@ -45,6 +45,7 @@ struct bgp_config {
int passive; /* Do not initiate outgoing connection */
int interpret_communities; /* Hardwired handling of well-known communities */
int secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */