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

Merge branch 'dev' into out

parents a3b70dc4 1567edea
......@@ -266,7 +266,7 @@ config_commit(struct config *c)
}
if (old_config) /* Reconfiguration already in progress */
{
if (shutting_down)
if (shutting_down == 2)
{
log(L_INFO "New configuration discarded due to shutdown");
config_free(c);
......@@ -314,8 +314,9 @@ order_shutdown(void)
init_list(&c->protos);
init_list(&c->tables);
c->shutdown = 1;
config_commit(c);
shutting_down = 1;
config_commit(c);
shutting_down = 2;
}
/**
......
......@@ -179,6 +179,9 @@ protocol static {
# default bgp_med 0; # MED value we use for comparison when none is defined
# default bgp_local_pref 0; # The same for local preference
# source address 62.168.0.14; # What local address we use for the TCP connection
# password "secret" # Password used for MD5 authentication
# rr client; # I am a route reflector and the neighor is my client
# rr cluster id 1.0.0.1 # Use this value for cluster id instead of my router id
# export where source=RTS_STATIC;
# export filter {
# if source = RTS_STATIC then {
......
......@@ -655,13 +655,19 @@ routing table it wishes to export along with complete path information
route) in order to avoid routing loops.
<p>BIRD supports all requirements of the BGP4 standard as defined in
RFC 1771<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc1771.txt">
including several enhancements from the
latest draft<htmlurl url="ftp://ftp.rfc-editor.org/internet-drafts/draft-ietf-idr-bgp4-09.txt">.
It also supports the community attributes as per
RFC 1997<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc1997.txt">,
capability negotiation defined in
RFC 2842<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc2842.txt">.
RFC 4271<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4271.txt">
It also supports the community attributes
(RFC 1997<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc1997.txt">),
capability negotiation
(RFC 3392<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc3392.txt">),
MD5 password authentication
(RFC 2385<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc2385.txt">),
route reflectors
(RFC 4456<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4456.txt">),
and 4B AS numbers
(RFC 4893<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4893.txt">).
For IPv6, it uses the standard multiprotocol extensions defined in
RFC 2283<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc2283.txt">
including changes described in the
......@@ -721,6 +727,27 @@ for each neighbor using the following configuration parameters:
for next hop calculation. Default: the address of the local end
of the interface our neighbor is connected to.
<tag>password <m/string/</tag> Use this password for MD5 authentication
of BGP sessions. Default: no authentication.
<tag>rr client</tag> Be a route reflector and treat neighbor as
route reflection client. Default: disabled.
<tag>rr cluster id <m/IPv4 address/</tag> Route reflectors use cluster id
to avoid route reflection loops. When there is one route reflector in a cluster
it usually uses its router id as a cluster id, but when there are more route
reflectors in a cluster, these need to be configured (using this option) to
use a common cluster id. Clients in a cluster need not known their cluster
id and this option is not allowed to them Default: a same as router id.
<tag>enable as4 <m/switch/</tag> BGP protocol was designed to use 2B AS numbers
and was extended later to allow 4B AS number. BIRD supports 4B AS extension,
but by disabling this option it can be persuaded not to advertise it and
to maintain old-style sessions with its neighbors. This might be useful for
circumventing bugs in neighbor's implementation of 4B AS extension.
Even when disabled (off), BIRD behaves internally as AS4-aware BGP router.
Default: on.
<tag>disable after error <m/switch/</tag> When an error is encountered (either
locally or by the other side), disable the instance automatically
and wait for an administrator to fix the problem manually. Default: off.
......@@ -757,7 +784,7 @@ for each neighbor using the following configuration parameters:
<tag>default bgp_med <m/number/</tag> Value of the Multiple Exit
Discriminator to be used during route selection when the MED attribute
is missing. Default: infinite.
is missing. Default: 0.
<tag>default bgp_local_pref <m/number/</tag> Value of the Local Preference
to be used during route selection when the Local Preference attribute
......@@ -779,10 +806,16 @@ with `<tt/O/') are optional.
selection among multiple BGP routes (see the selection rules above). It's
used as an additional metric which is propagated through the whole local AS.
<tag>int <cf/bgp_med/ [IO]</tag> The Multiple Exit Discriminator of the route
is an optional attribute which is often used within the local AS to
reflect interior distances to various boundary routers. See the route selection
rules above for exact semantics.
<tag>int <cf/bgp_med/ [O]</tag> The Multiple Exit Discriminator of the route
is an optional attribute which is used on on external (inter-AS) links to
convey to an adjacent AS the optimal entry point into the local AS.
The received attribute may be also propagated over internal BGP links
(and this is default behavior). The attribute value is zeroed when a route
is exported from a routing table to a BGP instance to ensure that the attribute
received from a neighboring AS is not propagated to other neighboring ASes.
A new value might be set in the export filter of a BGP instance.
See RFC 4451<htmlurl url="ftp://ftp.rfc-editor.org/in-notes/rfc4451.txt">
for further discussion of BGP MED attribute.
<tag>enum <cf/bgp_origin/</tag> Origin of the route: either <cf/ORIGIN_IGP/
if the route has originated in an interior routing protocol or
......
......@@ -39,7 +39,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <v> set_atom fprefix fprefix_s fipa
%type <s> decls declsn one_decl function_params
%type <h> bgp_path
%type <i> bgp_one
CF_GRAMMAR
......@@ -273,14 +272,12 @@ switch_body: /* EMPTY */ { $$ = NULL; }
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
bgp_one:
NUM { $$ = $1; }
| '?' { $$ = PM_ANY; }
;
bgp_path:
bgp_one { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; }
| bgp_one bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = $1; }
NUM { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; $$->any = 0; }
| '?' { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = 0; $$->any = 1; }
| NUM bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = $1; $$->any = 0; }
| '?' bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = 0; $$->any = 1; }
;
constant:
......
......@@ -69,6 +69,30 @@ pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2)
}
}
static void
pm_format(struct f_path_mask *p, byte *buf, unsigned int size)
{
byte *end = buf + size - 16;
while (p)
{
if (buf > end)
{
strcpy(buf, " ...");
return;
}
if (p->any)
buf += bsprintf(buf, "? ");
else
buf += bsprintf(buf, "%u ", p->val);
p = p->next;
}
*buf = 0;
}
/**
* val_compare - compare two values
* @v1: first value
......@@ -224,7 +248,7 @@ val_print(struct f_val v)
case T_ENUM: PRINTF( "(enum %x)%d", v.type, v.val.i ); break;
case T_PATH: as_path_format(v.val.ad, buf2, 1020); PRINTF( "(path %s)", buf2 ); break;
case T_CLIST: int_set_format(v.val.ad, buf2, 1020); PRINTF( "(clist %s)", buf2 ); break;
case T_PATH_MASK: debug( "(pathmask " ); { struct f_path_mask *p = v.val.path_mask; while (p) { debug("%d ", p->val); p=p->next; } debug(")" ); } break;
case T_PATH_MASK: pm_format(v.val.path_mask, buf2, 1020); PRINTF( "(pathmask %s)", buf2 ); break;
default: PRINTF( "[unknown type %x]", v.type );
#undef PRINTF
}
......
......@@ -11,6 +11,7 @@
#include "lib/resource.h"
#include "lib/ip.h"
#include "nest/route.h"
#include "nest/attrs.h"
struct f_inst { /* Instruction */
......
......@@ -39,6 +39,7 @@ typedef struct birdsock {
int fd; /* System-dependent data */
node n;
void *rbuf_alloc, *tbuf_alloc;
char *password; /* Password for MD5 authentication */
} sock;
sock *sk_new(pool *); /* Allocate new socket */
......@@ -47,6 +48,7 @@ int sk_send(sock *, unsigned len); /* Send data, <0=err, >0=ok, 0=sleep */
int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to given destination */
void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */
void sk_dump_all(void);
int sk_set_md5_auth(sock *s, ip_addr a, char *passwd); /* Add or remove security associations for given passive socket */
static inline int
sk_send_buffer_empty(sock *sk)
......
......@@ -14,38 +14,139 @@
#include "lib/unaligned.h"
#include "lib/string.h"
/* Global AS4 support, shared by all BGP instances.
* This specifies whether BA_AS_PATH attributes contain 2 or 4 B per ASN
*/
int bgp_as4_support = 1;
static void
put_as(byte *data, u32 as)
{
if (bgp_as4_support)
put_u32(data, as);
else if (as <= 0xFFFF)
put_u16(data, as);
else
bug("put_as: Try to put 32bit AS to 16bit AS Path");
}
static inline u32
get_as(byte *data)
{
return bgp_as4_support ? get_u32(data) : get_u16(data);
}
struct adata *
as_path_prepend(struct linpool *pool, struct adata *olda, int as)
as_path_prepend(struct linpool *pool, struct adata *olda, u32 as)
{
int bs = bgp_as4_support ? 4 : 2;
struct adata *newa;
if (olda->length && olda->data[0] == AS_PATH_SEQUENCE &&
olda->data[1] < 255) /* Starting with sequence => just prepend the AS number */
if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && olda->data[1] < 255)
/* Starting with sequence => just prepend the AS number */
{
newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 2);
newa->length = olda->length + 2;
newa->data[0] = 2;
int nl = olda->length + bs;
newa = lp_alloc(pool, sizeof(struct adata) + nl);
newa->length = nl;
newa->data[0] = AS_PATH_SEQUENCE;
newa->data[1] = olda->data[1] + 1;
memcpy(newa->data+4, olda->data+2, olda->length-2);
memcpy(newa->data + bs + 2, olda->data + 2, olda->length - 2);
}
else /* Create new path segment */
else /* Create new path segment */
{
newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 4);
newa->length = olda->length + 4;
newa->data[0] = 2;
int nl = olda->length + bs + 2;
newa = lp_alloc(pool, sizeof(struct adata) + nl);
newa->length = nl;
newa->data[0] = AS_PATH_SEQUENCE;
newa->data[1] = 1;
memcpy(newa->data+4, olda->data, olda->length);
memcpy(newa->data + bs + 2, olda->data, olda->length);
}
put_u16(newa->data+2, as);
put_as(newa->data + 2, as);
return newa;
}
int
as_path_convert_to_old(struct adata *path, byte *dst, int *new_used)
{
byte *src = path->data;
byte *src_end = src + path->length;
byte *dst_start = dst;
u32 as;
int i, n;
*new_used = 0;
while (src < src_end)
{
n = src[1];
*dst++ = *src++;
*dst++ = *src++;
for(i=0; i<n; i++)
{
as = get_u32(src);
if (as > 0xFFFF)
{
as = AS_TRANS;
*new_used = 1;
}
put_u16(dst, as);
src += 4;
dst += 2;
}
}
return dst - dst_start;
}
int
as_path_convert_to_new(struct adata *path, byte *dst, int req_as)
{
byte *src = path->data;
byte *src_end = src + path->length;
byte *dst_start = dst;
u32 as;
int i, t, n;
while ((src < src_end) && (req_as > 0))
{
t = *src++;
n = *src++;
if (t == AS_PATH_SEQUENCE)
{
if (n > req_as)
n = req_as;
req_as -= n;
}
else // t == AS_PATH_SET
req_as--;
*dst++ = t;
*dst++ = n;
for(i=0; i<n; i++)
{
as = get_u16(src);
put_u32(dst, as);
src += 2;
dst += 4;
}
}
return dst - dst_start;
}
void
as_path_format(struct adata *path, byte *buf, unsigned int size)
{
int bs = bgp_as4_support ? 4 : 2;
byte *p = path->data;
byte *e = p + path->length;
byte *end = buf + size - 8;
byte *end = buf + size - 16;
int sp = 1;
int l, isset;
......@@ -69,8 +170,8 @@ as_path_format(struct adata *path, byte *buf, unsigned int size)
{
if (!sp)
*buf++ = ' ';
buf += bsprintf(buf, "%d", get_u16(p));
p += 2;
buf += bsprintf(buf, "%u", get_as(p));
p += bs;
sp = 0;
}
if (isset)
......@@ -86,6 +187,7 @@ as_path_format(struct adata *path, byte *buf, unsigned int size)
int
as_path_getlen(struct adata *path)
{
int bs = bgp_as4_support ? 4 : 2;
int res = 0;
u8 *p = path->data;
u8 *q = p+path->length;
......@@ -95,8 +197,8 @@ as_path_getlen(struct adata *path)
{
switch (*p++)
{
case AS_PATH_SET: len = *p++; res++; p += 2*len; break;
case AS_PATH_SEQUENCE: len = *p++; res+=len; p += 2*len; break;
case AS_PATH_SET: len = *p++; res++; p += bs * len; break;
case AS_PATH_SEQUENCE: len = *p++; res += len; p += bs * len; break;
default: bug("as_path_getlen: Invalid path segment");
}
}
......@@ -104,9 +206,11 @@ as_path_getlen(struct adata *path)
}
int
as_path_get_first(struct adata *path)
as_path_get_first(struct adata *path, u32 *orig_as)
{
int res = -1;
int bs = bgp_as4_support ? 4 : 2;
int found = 0;
u32 res = 0;
u8 *p = path->data;
u8 *q = p+path->length;
int len;
......@@ -117,36 +221,84 @@ as_path_get_first(struct adata *path)
{
case AS_PATH_SET:
if (len = *p++)
res = get_u16(p);
p += 2*len;
{
found = 1;
res = get_as(p);
p += bs * len;
}
break;
case AS_PATH_SEQUENCE:
if (len = *p++)
res = get_u16(p+2*(len-1));
p += 2*len;
{
found = 1;
res = get_as(p + bs * (len - 1));
p += bs * len;
}
break;
default: bug("as_path_get_first: Invalid path segment");
}
}
return res;
*orig_as = res;
return found;
}
int
as_path_get_last(struct adata *path, u32 *last_as)
{
u8 *p = path->data;
if ((path->length == 0) || (p[0] != AS_PATH_SEQUENCE) || (p[1] == 0))
return 0;
else
{
*last_as = get_as(p+2);
return 1;
}
}
int
as_path_is_member(struct adata *path, u32 as)
{
int bs = bgp_as4_support ? 4 : 2;
u8 *p = path->data;
u8 *q = p+path->length;
int i, n;
while (p<q)
{
n = p[1];
p += 2;
for(i=0; i<n; i++)
{
if (get_as(p) == as)
return 1;
p += bs;
}
}
return 0;
}
#define MASK_PLUS do { mask = mask->next; if (!mask) return next == q; \
asterisk = (mask->val == PM_ANY); \
asterisk = mask->any; \
if (asterisk) { mask = mask->next; if (!mask) { return 1; } } \
} while(0)
int
as_path_match(struct adata *path, struct f_path_mask *mask)
{
int bs = bgp_as4_support ? 4 : 2;
int i;
int asterisk = 0;
u8 *p = path->data;
u8 *q = p+path->length;
int len;
u8 *next;
u32 as;
asterisk = (mask->val == PM_ANY);
asterisk = mask->any;
if (asterisk)
{ mask = mask->next; if (!mask) return 1; }
......@@ -156,20 +308,21 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
len = *p++;
{
u8 *p_save = p;
next = p_save + 2*len;
next = p_save + bs * len;
retry:
p = p_save;
for (i=0; i<len; i++) {
if (asterisk && (get_u16(p) == mask->val)) {
as = get_as(p);
if (asterisk && (as == mask->val)) {
MASK_PLUS;
goto retry;
}
if (!asterisk && (get_u16(p) == mask->val)) {
if (!asterisk && (as == mask->val)) {
p = next;
MASK_PLUS;
goto okay;
}
p+=2;
p += bs;
}
if (!asterisk)
return 0;
......@@ -180,15 +333,15 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
case AS_PATH_SEQUENCE:
len = *p++;
for (i=0; i<len; i++) {
next = p+2;
if (asterisk && (get_u16(p) == mask->val))
as = get_as(p);
if (asterisk && (as == mask->val))
MASK_PLUS;
else if (!asterisk) {
if (get_u16(p) != mask->val)
if (as != mask->val)
return 0;
MASK_PLUS;
}
p+=2;
p += bs;
}
break;
......
......@@ -40,10 +40,12 @@ int_set_format(struct adata *set, byte *buf, unsigned int size)
struct adata *
int_set_add(struct linpool *pool, struct adata *list, u32 val)
{
struct adata *res = lp_alloc(pool, list->length + sizeof(struct adata) + 4);
res->length = list->length+4;
int len = list ? list->length : 0;
struct adata *res = lp_alloc(pool, len + sizeof(struct adata) + 4);
res->length = len + 4;
* (u32 *) res->data = val;
memcpy((char *) res->data + 4, list->data, list->length);
if (list)
memcpy((char *) res->data + 4, list->data, list->length);
return res;
}
......
......@@ -14,16 +14,30 @@
#define AS_PATH_SET 1 /* Types of path segments */
#define AS_PATH_SEQUENCE 2
struct adata *as_path_prepend(struct linpool *pool, struct adata *olda, int as);
#define AS_PATH_MAXLEN 10000
#define AS_TRANS 23456
/* AS_TRANS is used when we need to store 32bit ASN larger than 0xFFFF
* to 16bit slot (like in 16bit AS_PATH). See RFC 4893 for details
*/
struct adata *as_path_prepend(struct linpool *pool, struct adata *olda, u32 as);
int as_path_convert_to_old(struct adata *path, byte *dst, int *new_used);
int as_path_convert_to_new(struct adata *path, byte *dst, int req_as);
void as_path_format(struct adata *path, byte *buf, unsigned int size);
int as_path_getlen(struct adata *path);
int as_path_get_first(struct adata *path);
int as_path_get_first(struct adata *path, u32 *orig_as);
int as_path_get_last(struct adata *path, u32 *last_as);
int as_path_is_member(struct adata *path, u32 as);
struct f_path_mask {
struct f_path_mask *next;
int val;
u32 val;
int any;
};
#define PM_ANY -1
// #define PM_ANY -1
int as_path_match(struct adata *path, struct f_path_mask *mask);
......@@ -34,4 +48,7 @@ struct adata *int_set_add(struct linpool *pool, struct adata *list, u32 val);
int int_set_contains(struct adata *list, u32 val);
struct adata *int_set_del(struct linpool *pool, struct adata *list, u32 val);
static inline int int_set_get_size(struct adata *list)
{ return list->length / 4; }
#endif
This diff is collapsed.
......@@ -76,11 +76,16 @@ static void bgp_connect(struct bgp_proto *p);
static void bgp_initiate(struct bgp_proto *p);
static void bgp_setup_listen_sk(void);
static void
bgp_close(struct bgp_proto *p UNUSED)
bgp_close(struct bgp_proto *p)
{
ASSERT(bgp_counter);
bgp_counter--;
if (p->cf->password)
sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, NULL);
if (!bgp_counter)
{
rfree(bgp_listen_sk);
......@@ -329,6 +334,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
bgp_setup_conn(p, conn);
bgp_setup_sk(p, conn, s);
s->tx_hook = bgp_connected;
s->password = p->cf->password;
conn->state = BS_CONNECT;
if (sk_open(s))
{
......@@ -479,6 +485,13 @@ bgp_start_locked(struct object_lock *lock)
p->local_id = cf->c.global->router_id;
p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip;
p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY);
if (cf->rr_client)
{
p->rr_cluster_id = cf->rr_cluster_id ? cf->rr_cluster_id : p->local_id;
p->rr_client = cf->rr_client;
}
if (!p->neigh)
{
log(L_ERR "%s: Invalid next hop %I", p->p.name, p->next_hop);
......@@ -505,6 +518,7 @@ bgp_start(struct proto *P)
bgp_counter++;
bgp_setup_listen_sk();
if (!bgp_linpool)
bgp_linpool = lp_new(&root_pool, 4080);
......@@ -522,6 +536,17 @@ bgp_start(struct proto *P)
lock->hook = bgp_start_locked;
lock->data = p;
olock_acquire(lock);
/* We should create security association after we get a lock not to
* break existing connections.
*/
if (p->cf->password)
{
int rv = sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->password);
if (rv < 0)
return PS_STOP;
}
return PS_START;
}
......@@ -611,6 +636,14 @@ bgp_check(struct bgp_config *c)
cf_error("Local AS number must be set");
if (!c->remote_as)
cf_error("Neighbor must be configured");
if (!bgp_as4_support && c->enable_as4)
cf_error("AS4 support disabled globbaly");
if (!c->enable_as4 && (c->local_as > 0xFFFF))
cf_error("Local AS number out of range");
if (!c->enable_as4 && (c->remote_as > 0xFFFF))
cf_error("Neighbor AS number out of range");
if ((c->local_as != c->remote_as) && (c->rr_client))
cf_error("Only internal neighbor can be RR client");
}
static void
......
......@@ -16,7 +16,7 @@ struct eattr;
struct bgp_config {
struct proto_config c;
unsigned int local_as, remote_as;
u32 local_as, remote_as;
ip_addr remote_ip;
int multihop; /* Number of hops if multihop */
ip_addr multihop_via; /* Multihop: address to route to */
......@@ -25,6 +25,9 @@ struct bgp_config {
int compare_path_lengths; /* Use path lengths when selecting best route */
u32 default_local_pref; /* Default value for LOCAL_PREF attribute */
u32 default_med; /* Default value for MULTI_EXIT_DISC attribute */
int enable_as4; /* Enable local support for 4B AS numbers [RFC4893] */
u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */
int rr_client; /* Whether neighbor is RR client of me */
unsigned connect_retry_time;
unsigned hold_time, initial_hold_time;
unsigned keepalive_time;
......@@ -33,6 +36,7 @@ struct bgp_config {
unsigned error_delay_time_min; /* Time to wait after an error is detected */
unsigned error_delay_time_max;
unsigned disable_after_error; /* Disable the protocol when error is detected */
char *password; /* Password used for MD5 authentication */
};
struct bgp_conn {
......@@ -47,16 +51,21 @@ struct bgp_conn {
byte *notify_data;
int error_flag; /* Error state, ignore all input */
int primary; /* This connection is primary */
u32 advertised_as; /* Temporary value for AS number received */
unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
};
struct bgp_proto {
struct proto p;
struct bgp_config *cf; /* Shortcut to BGP configuration */
unsigned local_as, remote_as;
u32 local_as, remote_as;
int is_internal; /* Internal BGP connection (local_as == remote_as) */
int as4_support; /* Peer supports 4B AS numbers [RFC4893] */
int as4_session; /* Session uses 4B AS numbers in AS_PATH (both sides support it) */
u32 local_id; /* BGP identifier of this router */
u32 remote_id; /* BGP identifier of the neighbor */
u32 rr_cluster_id; /* Route reflector cluster ID */
int rr_client; /* Whether neighbor is RR client of me */
struct bgp_conn *conn; /* Connection we have established */
struct bgp_conn outgoing_conn; /* Outgoing connection we're working with */
struct bgp_conn incoming_conn; /* Incoming connection we have neither accepted nor rejected yet */
......@@ -100,6 +109,9 @@ struct bgp_bucket {
extern struct linpool *bgp_linpool;
extern int bgp_as4_support;
void bgp_start_timer(struct timer *t, int value);
void bgp_check(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
......@@ -115,17 +127,21 @@ void bgp_close_conn(struct bgp_conn *c);
/* attrs.c */
byte *bgp_attach_attr(struct ea_list **to, struct linpool *, unsigned attr, unsigned val);
void bgp_attach_attr(struct ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val);
byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned attr, unsigned <