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

Implementation of 4B ASN support for BGP

parent 44cb1449
...@@ -39,7 +39,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, ...@@ -39,7 +39,6 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <v> set_atom fprefix fprefix_s fipa %type <v> set_atom fprefix fprefix_s fipa
%type <s> decls declsn one_decl function_params %type <s> decls declsn one_decl function_params
%type <h> bgp_path %type <h> bgp_path
%type <i> bgp_one
CF_GRAMMAR CF_GRAMMAR
...@@ -273,14 +272,12 @@ switch_body: /* EMPTY */ { $$ = NULL; } ...@@ -273,14 +272,12 @@ switch_body: /* EMPTY */ { $$ = NULL; }
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */ /* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */
bgp_one:
NUM { $$ = $1; }
| '?' { $$ = PM_ANY; }
;
bgp_path: bgp_path:
bgp_one { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; } NUM { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = NULL; $$->val = $1; $$->any = 0; }
| bgp_one bgp_path { $$ = cfg_alloc(sizeof(struct f_path_mask)); $$->next = $2; $$->val = $1; } | '?' { $$ = 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: constant:
......
...@@ -69,6 +69,30 @@ pm_path_compare(struct f_path_mask *m1, struct f_path_mask *m2) ...@@ -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 * val_compare - compare two values
* @v1: first value * @v1: first value
...@@ -224,7 +248,7 @@ val_print(struct f_val v) ...@@ -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_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_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_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 ); default: PRINTF( "[unknown type %x]", v.type );
#undef PRINTF #undef PRINTF
} }
......
...@@ -14,38 +14,139 @@ ...@@ -14,38 +14,139 @@
#include "lib/unaligned.h" #include "lib/unaligned.h"
#include "lib/string.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 * 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; struct adata *newa;
if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && if (olda->length && olda->data[0] == AS_PATH_SEQUENCE && olda->data[1] < 255)
olda->data[1] < 255) /* Starting with sequence => just prepend the AS number */ /* Starting with sequence => just prepend the AS number */
{ {
newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 2); int nl = olda->length + bs;
newa->length = olda->length + 2; newa = lp_alloc(pool, sizeof(struct adata) + nl);
newa->data[0] = 2; newa->length = nl;
newa->data[0] = AS_PATH_SEQUENCE;
newa->data[1] = olda->data[1] + 1; 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); int nl = olda->length + bs + 2;
newa->length = olda->length + 4; newa = lp_alloc(pool, sizeof(struct adata) + nl);
newa->data[0] = 2; newa->length = nl;
newa->data[0] = AS_PATH_SEQUENCE;
newa->data[1] = 1; 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; 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 void
as_path_format(struct adata *path, byte *buf, unsigned int size) as_path_format(struct adata *path, byte *buf, unsigned int size)
{ {
int bs = bgp_as4_support ? 4 : 2;
byte *p = path->data; byte *p = path->data;
byte *e = p + path->length; byte *e = p + path->length;
byte *end = buf + size - 8; byte *end = buf + size - 16;
int sp = 1; int sp = 1;
int l, isset; int l, isset;
...@@ -69,8 +170,8 @@ as_path_format(struct adata *path, byte *buf, unsigned int size) ...@@ -69,8 +170,8 @@ as_path_format(struct adata *path, byte *buf, unsigned int size)
{ {
if (!sp) if (!sp)
*buf++ = ' '; *buf++ = ' ';
buf += bsprintf(buf, "%d", get_u16(p)); buf += bsprintf(buf, "%u", get_as(p));
p += 2; p += bs;
sp = 0; sp = 0;
} }
if (isset) if (isset)
...@@ -86,6 +187,7 @@ as_path_format(struct adata *path, byte *buf, unsigned int size) ...@@ -86,6 +187,7 @@ as_path_format(struct adata *path, byte *buf, unsigned int size)
int int
as_path_getlen(struct adata *path) as_path_getlen(struct adata *path)
{ {
int bs = bgp_as4_support ? 4 : 2;
int res = 0; int res = 0;
u8 *p = path->data; u8 *p = path->data;
u8 *q = p+path->length; u8 *q = p+path->length;
...@@ -95,8 +197,8 @@ as_path_getlen(struct adata *path) ...@@ -95,8 +197,8 @@ as_path_getlen(struct adata *path)
{ {
switch (*p++) switch (*p++)
{ {
case AS_PATH_SET: len = *p++; res++; p += 2*len; break; case AS_PATH_SET: len = *p++; res++; p += bs * len; break;
case AS_PATH_SEQUENCE: len = *p++; res+=len; p += 2*len; break; case AS_PATH_SEQUENCE: len = *p++; res += len; p += bs * len; break;
default: bug("as_path_getlen: Invalid path segment"); default: bug("as_path_getlen: Invalid path segment");
} }
} }
...@@ -104,9 +206,11 @@ as_path_getlen(struct adata *path) ...@@ -104,9 +206,11 @@ as_path_getlen(struct adata *path)
} }
int 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 *p = path->data;
u8 *q = p+path->length; u8 *q = p+path->length;
int len; int len;
...@@ -117,36 +221,70 @@ as_path_get_first(struct adata *path) ...@@ -117,36 +221,70 @@ as_path_get_first(struct adata *path)
{ {
case AS_PATH_SET: case AS_PATH_SET:
if (len = *p++) if (len = *p++)
res = get_u16(p); {
p += 2*len; found = 1;
res = get_as(p);
p += bs * len;
}
break; break;
case AS_PATH_SEQUENCE: case AS_PATH_SEQUENCE:
if (len = *p++) 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; break;
default: bug("as_path_get_first: Invalid path segment"); default: bug("as_path_get_first: Invalid path segment");
} }
} }
return res;
*orig_as = res;
return found;
} }
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; \ #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; } } \ if (asterisk) { mask = mask->next; if (!mask) { return 1; } } \
} while(0) } while(0)
int int
as_path_match(struct adata *path, struct f_path_mask *mask) as_path_match(struct adata *path, struct f_path_mask *mask)
{ {
int bs = bgp_as4_support ? 4 : 2;
int i; int i;
int asterisk = 0; int asterisk = 0;
u8 *p = path->data; u8 *p = path->data;
u8 *q = p+path->length; u8 *q = p+path->length;
int len; int len;
u8 *next; u8 *next;
u32 as;
asterisk = (mask->val == PM_ANY); asterisk = mask->any;
if (asterisk) if (asterisk)
{ mask = mask->next; if (!mask) return 1; } { mask = mask->next; if (!mask) return 1; }
...@@ -156,20 +294,21 @@ as_path_match(struct adata *path, struct f_path_mask *mask) ...@@ -156,20 +294,21 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
len = *p++; len = *p++;
{ {
u8 *p_save = p; u8 *p_save = p;
next = p_save + 2*len; next = p_save + bs * len;
retry: retry:
p = p_save; p = p_save;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
if (asterisk && (get_u16(p) == mask->val)) { as = get_as(p);
if (asterisk && (as == mask->val)) {
MASK_PLUS; MASK_PLUS;
goto retry; goto retry;
} }
if (!asterisk && (get_u16(p) == mask->val)) { if (!asterisk && (as == mask->val)) {
p = next; p = next;
MASK_PLUS; MASK_PLUS;
goto okay; goto okay;
} }
p+=2; p += bs;
} }
if (!asterisk) if (!asterisk)
return 0; return 0;
...@@ -180,15 +319,15 @@ as_path_match(struct adata *path, struct f_path_mask *mask) ...@@ -180,15 +319,15 @@ as_path_match(struct adata *path, struct f_path_mask *mask)
case AS_PATH_SEQUENCE: case AS_PATH_SEQUENCE:
len = *p++; len = *p++;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
next = p+2; as = get_as(p);
if (asterisk && (get_u16(p) == mask->val)) if (asterisk && (as == mask->val))
MASK_PLUS; MASK_PLUS;
else if (!asterisk) { else if (!asterisk) {
if (get_u16(p) != mask->val) if (as != mask->val)
return 0; return 0;
MASK_PLUS; MASK_PLUS;
} }
p+=2; p += bs;
} }
break; break;
......
...@@ -14,16 +14,29 @@ ...@@ -14,16 +14,29 @@
#define AS_PATH_SET 1 /* Types of path segments */ #define AS_PATH_SET 1 /* Types of path segments */
#define AS_PATH_SEQUENCE 2 #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); void as_path_format(struct adata *path, byte *buf, unsigned int size);
int as_path_getlen(struct adata *path); 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_is_member(struct adata *path, u32 as);
struct f_path_mask { struct f_path_mask {
struct f_path_mask *next; 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); int as_path_match(struct adata *path, struct f_path_mask *mask);
......
This diff is collapsed.
...@@ -76,6 +76,7 @@ static void bgp_connect(struct bgp_proto *p); ...@@ -76,6 +76,7 @@ static void bgp_connect(struct bgp_proto *p);
static void bgp_initiate(struct bgp_proto *p); static void bgp_initiate(struct bgp_proto *p);
static void bgp_setup_listen_sk(void); static void bgp_setup_listen_sk(void);
static void static void
bgp_close(struct bgp_proto *p UNUSED) bgp_close(struct bgp_proto *p UNUSED)
{ {
...@@ -611,6 +612,10 @@ bgp_check(struct bgp_config *c) ...@@ -611,6 +612,10 @@ bgp_check(struct bgp_config *c)
cf_error("Local AS number must be set"); cf_error("Local AS number must be set");
if (!c->remote_as) if (!c->remote_as)
cf_error("Neighbor must be configured"); cf_error("Neighbor must be configured");
if (!bgp_as4_support && (c->local_as > 0xFFFF))
cf_error("Local AS number out of range");
if (!bgp_as4_support && (c->remote_as > 0xFFFF))
cf_error("Neighbor AS number out of range");
} }
static void static void
......
...@@ -16,7 +16,7 @@ struct eattr; ...@@ -16,7 +16,7 @@ struct eattr;
struct bgp_config { struct bgp_config {
struct proto_config c; struct proto_config c;
unsigned int local_as, remote_as; u32 local_as, remote_as;
ip_addr remote_ip; ip_addr remote_ip;
int multihop; /* Number of hops if multihop */ int multihop; /* Number of hops if multihop */
ip_addr multihop_via; /* Multihop: address to route to */ ip_addr multihop_via; /* Multihop: address to route to */
...@@ -47,14 +47,16 @@ struct bgp_conn { ...@@ -47,14 +47,16 @@ struct bgp_conn {
byte *notify_data; byte *notify_data;
int error_flag; /* Error state, ignore all input */ int error_flag; /* Error state, ignore all input */
int primary; /* This connection is primary */ 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 */ unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
}; };
struct bgp_proto { struct bgp_proto {
struct proto p; struct proto p;
struct bgp_config *cf; /* Shortcut to BGP configuration */ 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 is_internal; /* Internal BGP connection (local_as == remote_as) */
int as4_support; /* Peer supports 4B AS numbers [RFC4893] */
u32 local_id; /* BGP identifier of this router */ u32 local_id; /* BGP identifier of this router */
u32 remote_id; /* BGP identifier of the neighbor */ u32 remote_id; /* BGP identifier of the neighbor */
struct bgp_conn *conn; /* Connection we have established */ struct bgp_conn *conn; /* Connection we have established */
...@@ -100,6 +102,9 @@ struct bgp_bucket { ...@@ -100,6 +102,9 @@ struct bgp_bucket {
extern struct linpool *bgp_linpool; extern struct linpool *bgp_linpool;
extern int bgp_as4_support;
void bgp_start_timer(struct timer *t, int value); void bgp_start_timer(struct timer *t, int value);
void bgp_check(struct bgp_config *c); void bgp_check(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len); void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
...@@ -122,7 +127,7 @@ int bgp_rte_better(struct rte *, struct rte *); ...@@ -122,7 +127,7 @@ int bgp_rte_better(struct rte *, struct rte *);
void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *); void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *);
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *); int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
void bgp_attr_init(struct bgp_proto *); void bgp_attr_init(struct bgp_proto *);
unsigned int bgp_encode_attrs(byte *w, struct ea_list *attrs, int remains); unsigned int bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains);
void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck); void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs); void bgp_get_route_info(struct rte *, byte *buf, struct ea_list *attrs);
...@@ -165,6 +170,8 @@ void bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subco ...@@ -165,6 +170,8 @@ void bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subco
#define BA_MP_REACH_NLRI 0x0e /* [RFC2283] */ #define BA_MP_REACH_NLRI 0x0e /* [RFC2283] */
#define BA_MP_UNREACH_NLRI 0x0f #define BA_MP_UNREACH_NLRI 0x0f
#define BA_EXTENDED_COMM 0x10 /* draft-ramachandra-bgp-ext-communities */ #define BA_EXTENDED_COMM 0x10 /* draft-ramachandra-bgp-ext-communities */
#define BA_AS4_PATH 0x11 /* [RFC4893] */
#define BA_AS4_AGGREGATOR 0x12
/* BGP states */ /* BGP states */
......
...@@ -44,12 +44,10 @@ bgp_proto_start: proto_start BGP { ...@@ -44,12 +44,10 @@ bgp_proto_start: proto_start BGP {
bgp_proto: bgp_proto:
bgp_proto_start proto_name '{' bgp_proto_start proto_name '{'
| bgp_proto proto_item ';' | bgp_proto proto_item ';'
| bgp_proto LOCAL AS expr ';' { | bgp_proto LOCAL AS expr ';' { BGP_CFG->local_as = $4; }
if ($4 < 0 || $4 > 65535) cf_error("AS number out of range");
BGP_CFG->local_as = $4;
}
| bgp_proto NEIGHBOR ipa AS expr ';' { | bgp_proto NEIGHBOR ipa AS expr ';' {
if ($5 < 0 || $5 > 65535) cf_error("AS number out of range"); if (ipa_nonzero(BGP_CFG->remote_ip)) cf_error("Only one neighbor per BGP instance is allowed");
BGP_CFG->remote_ip = $3; BGP_CFG->remote_ip = $3;
BGP_CFG->remote_as = $5; BGP_CFG->remote_as = $5;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "nest/iface.h" #include "nest/iface.h"
#include "nest/protocol.h" #include "nest/protocol.h"
#include "nest/route.h" #include "nest/route.h"
#include "nest/attrs.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "lib/unaligned.h" #include "lib/unaligned.h"
#include "lib/socket.h" #include "lib/socket.h"
...@@ -30,33 +31,64 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf) ...@@ -30,33 +31,64 @@ bgp_create_notification(struct bgp_conn *conn, byte *buf)
return buf + 2 + conn->notify_size; return buf + 2 + conn->notify_size;
} }
#ifdef IPV6
static byte *
bgp_put_cap_ipv6(struct bgp_conn *conn UNUSED, byte *buf)
{
*buf++ = 1; /* Capability 1: Multiprotocol extensions */
*buf++ = 4; /* Capability data length */
*buf++ = 0; /* We support AF IPv6 */
*buf++ = BGP_AF_IPV6;
*buf++ = 0; /* RFU */
*buf++ = 1; /* and SAFI 1 */
return buf;
}
#endif
static byte *
bgp_put_cap_as4(struct bgp_conn *conn, byte *buf)
{
*buf++ = 65; /* Capability 65: Support for 4-octet AS number */
*buf++ = 4; /* Capability data length */
put_u32(buf, conn->bgp->local_as);
return buf + 4;
}
static byte * static byte *
bgp_create_open(struct bgp_conn *conn, byte *buf) bgp_create_open(struct bgp_conn *conn, byte *buf)
{ {
struct bgp_proto *p = conn->bgp; struct bgp_proto *p = conn->bgp;
byte *cap;
int cap_len;
BGP_TRACE(D_PACKETS, "Sending OPEN(ver=%d,as=%d,hold=%d,id=%08x)", BGP_TRACE(D_PACKETS, "Sending OPEN(ver=%d,as=%d,hold=%d,id=%08x)",
BGP_VERSION, p->local_as, p->cf->hold_time, p->local_id); BGP_VERSION, p->local_as, p->cf->hold_time, p->local_id);
buf[0] = BGP_VERSION; buf[0] = BGP_VERSION;
put_u16(buf+1, p->local_as); put_u16(buf+1, (p->local_as < 0xFFFF) ? p->local_as : AS_TRANS);
put_u16(buf+3, p->cf->hold_time); put_u16(buf+3, p->cf->hold_time);
put_u32(buf+5, p->local_id); put_u32(buf+5, p->local_id);
#ifndef IPV6 /* Skipped 3 B for length field and Capabilities parameter header */
buf[9] = 0; /* No optional parameters */ cap = buf + 12;
return buf+10;
#else #ifdef IPV6
buf += 9; cap = bgp_put_cap_ipv6(conn, cap);
*buf++ = 8; /* Optional params len */
*buf++ = 2; /* Option: Capability list */
*buf++ = 6; /* Option length */
*buf++ = 1; /* Capability 1: Multiprotocol extensions */
*buf++ = 4; /* Capability data length */
*buf++ = 0; /* We support AF IPv6 */
*buf++ = BGP_AF_IPV6;
*buf++ = 0; /* RFU */
*buf++ = 1; /* and SAFI 1 */
return buf;
#endif #endif
if (bgp_as4_support)