pkgsrc-wip/openbgpd-as4byte/patches/patch-bg
George Michaelson edb12a94da This is a modified import of the FreeBSD port of OpenBGPD.
This pkg includes modifications to implement 4byte (32bit) AS number extensions
to BGP.

the original FreeBSD port descr is appended below.

-george

OpenBGPD is a FREE implementation of the Border Gateway Protocol, Version 4.
It allows ordinary machines to be used as routers exchanging routes with
other systems speaking the BGP protocol.

WWW: http://www.openbgp.org/

- Florent Thoumie
flz@xbsd.org
2007-01-12 04:32:48 +00:00

300 lines
9.6 KiB
Text
Executable file

--- bgpd/rde.c.orig 2007-01-11 15:02:39.000000000 +1000
+++ bgpd/rde.c 2007-01-11 16:32:45.000000000 +1000
@@ -626,6 +631,10 @@
{
struct rde_peer *peer;
struct rde_aspath *asp = NULL, *fasp;
+ struct attr *a;
+ struct attr *b;
+ struct attr tmp;
+ struct aspath *new_aspath;
u_char *p, *mpp = NULL;
int pos = 0;
u_int16_t afi, len, mplen;
@@ -633,6 +642,7 @@
u_int16_t attrpath_len;
u_int16_t nlri_len;
u_int8_t prefixlen, safi, subtype;
+ u_int32_t aggregator_as;
struct bgpd_addr prefix;
struct mpattr mpa;
@@ -668,31 +678,88 @@
if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
/* parse path attributes */
+ /* allocate an empty path structure */
asp = path_get();
+ /* len is the length of the attribute set in bytes */
while (len > 0) {
- if ((pos = rde_attr_parse(p, len, peer, asp,
- &mpa)) < 0) {
+
+ if ((pos = rde_attr_parse(p, len, peer, asp, &mpa)) < 0) {
path_put(asp);
+ /****/
+ fprintf(stderr,"Attribute parse error\n") ;
+/***/
+
return (-1);
}
p += pos;
len -= pos;
}
+ /* perform an AGGREGATOR substitution */
+ /* first check that NEW_AGGREGATOR attribute was present */
+ if ((a = attr_optget(asp, ATTR_NEW_AGGREGATOR)) != NULL) {
+ /* second, check that an AGGREGATOR attribute was present */
+ if ((b = attr_optget(asp, ATTR_AGGREGATOR)) != NULL) {
+ /* then check that we are on a 2 byte to 4 byte boundary */
+ /* and the AGGREGATOR is AS_TRANS */
+ if (!(peer->capa_received.as_4bytes)) {
+ aggregator_as = as_extract(b->data,4) ;
+ if (aggregator_as == AS_TRANS) {
+ memcpy(b->data,a->data,4) ;
+ /* now re-hash the aggregator attribute by releasing it and re-adding it*/
+ tmp.flags = b->flags ;
+ tmp.type = b->flags ;
+ tmp.len = b->len ;
+ tmp.data = malloc(tmp.len) ;
+ memcpy(tmp.data,b->data,tmp.len) ;
+ attr_free(asp,b) ;
+ attr_optadd(asp,tmp.flags,tmp.type,tmp.data,tmp.len) ;
+ free(tmp.data) ;
+ }
+ }
+ }
+ /* now remove the NEW_AGGREGATOR attribute */
+ attr_free(asp,a) ;
+ }
+
+ /* attempt a PATH substitution */
+ /* first check that NEW_PATH attribute was present */
+ if ((a = attr_optget(asp, ATTR_NEW_ASPATH)) != NULL) {
+ /* then check that we are on a 2 byte to 4 byte boundary */
+ if (!(peer->capa_received.as_4bytes)) {
+ if ((new_aspath = aspath_translate(asp->aspath,a->data,a->len)) == NULL) {
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_NEWASPATH,
+ NULL, 0);
+ path_put(asp);
+ return (-1);
+ }
+ aspath_put(asp->aspath) ;
+ asp->aspath = new_aspath;
+ }
+ /* now remove the NEW_AS_PATH attribute */
+ attr_free(asp,a) ;
+ }
+
+
/* check for missing but necessary attributes */
- if ((subtype = rde_attr_missing(asp, peer->conf.ebgp,
- nlri_len))) {
+ if ((subtype = rde_attr_missing(asp, peer->conf.ebgp, nlri_len))) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
&subtype, sizeof(u_int8_t));
path_put(asp);
+ /***/
+ fprintf(stderr,"Missing well known attributes\n");
+ /***/
return (-1);
}
/* enforce remote AS if requested */
if (asp->flags & F_ATTR_ASPATH &&
peer->conf.enforce_as == ENFORCE_AS_ON)
- if (peer->conf.remote_as !=
- aspath_neighbor(asp->aspath)) {
+ if (peer->conf.remote_as != aspath_neighbor(asp->aspath,4)) {
+ /***/
+ fprintf(stderr,"Remote AS is not equal to aspath neighbor AS\n") ;
+ fprintf(stderr,"configured remote AS is %u, Neighbor is %u\n",peer->conf.remote_as,aspath_neighbor(asp->aspath,4)) ;
+ /***/
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
NULL, 0);
path_put(asp);
@@ -820,7 +887,10 @@
p += 2 + attrpath_len;
/* aspath needs to be loop free nota bene this is not a hard error */
- if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as)) {
+ if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as,4)) {
+ /****/
+ fprintf(stderr,"LOOP in AS PATH\n");
+/***/
path_put(asp);
return (0);
}
@@ -1012,19 +1082,26 @@
#define CHECK_FLAGS(s, t, m) \
(((s) & ~(ATTR_EXTLEN | (m))) == (t))
+/* parse update attribute set */
int
rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer,
struct rde_aspath *a, struct mpattr *mpa)
{
struct bgpd_addr nexthop;
u_char *op = p;
+ u_char *new_p;
u_int32_t tmp32;
u_int16_t attr_len;
+ u_int16_t new_attr_len;
u_int16_t plen = 0;
u_int8_t flags;
u_int8_t type;
u_int8_t tmp8;
+ /****/
+ fprintf(stderr,"rde_attr_parse - parse update\n") ;
+ /****/
+
if (len < 3) {
bad_len:
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLEN, op, len);
@@ -1050,6 +1127,9 @@
/* adjust len to the actual attribute size including header */
len = plen + attr_len;
+/*****/
+ fprintf(stderr,"UPDATE: attribute: flags = %x, length=%u attr = %u\n",flags, attr_len,type) ;
+/*****/
switch (type) {
case ATTR_UNDEF:
rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNSPECIFIC, NULL, 0);
@@ -1076,9 +1156,16 @@
a->flags |= F_ATTR_ORIGIN;
break;
case ATTR_ASPATH:
+ /****/
+ fprintf(stderr,"AS Path\n") ;
+ /****/
+
if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
goto bad_flags;
- if (aspath_verify(p, attr_len) != 0) {
+ /****/
+ fprintf(stderr,"Received ASPATH, 4byte = %u\n",peer->capa_received.as_4bytes);
+ /****/
+ if (aspath_verify(p, attr_len, peer->capa_received.as_4bytes) < 0) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
NULL, 0);
return (-1);
@@ -1086,9 +1173,51 @@
if (a->flags & F_ATTR_ASPATH)
goto bad_list;
a->flags |= F_ATTR_ASPATH;
- a->aspath = aspath_get(p, attr_len);
+ new_p = p ;
+ new_attr_len = attr_len ;
+ /****/
+ fprintf(stderr,"peer 4byte? = %d\n",peer->capa_received.as_4bytes) ;
+ /****/
+ if (!(peer->capa_received.as_4bytes)) {
+ /****/
+ fprintf(stderr,"inflate the as path to 4bytes\n") ;
+ /****/
+
+ if (!(new_p = aspath_inflate(p,attr_len,&new_attr_len)))
+ return(-1) ;
+ }
+ a->aspath = aspath_get(new_p, new_attr_len,4);
+ if (!(peer->capa_received.as_4bytes)) {
+ free(new_p) ;
+ }
plen += attr_len;
break;
+ case ATTR_NEW_ASPATH:
+ /****/
+ fprintf(stderr,"Received NEW_ASPATH, 4byte = %u\n",peer->capa_received.as_4bytes);
+ /****/
+
+ /* should only receive this attr from 2 byte as (old) bgp peers */
+ if (peer->capa_received.as_4bytes)
+ goto bad_flags ;
+
+ if (attr_len <= 4)
+ goto bad_len;
+
+ /* flag setting is optional (0x80) and transitive (0x40) */
+ if (!(flags & (ATTR_OPTIONAL | ATTR_TRANSITIVE)))
+ goto bad_flags;
+
+ if (aspath_verify(p, attr_len, 1) < 0) {
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_NEWASPATH,
+ NULL, 0);
+ return (-1);
+ }
+
+ /* store this attribute and perform path sustitution at the end of the
+ attribute parse block */
+ goto optattr;
+
case ATTR_NEXTHOP:
if (attr_len != 4)
goto bad_len;
@@ -1149,10 +1278,35 @@
goto bad_flags;
goto optattr;
case ATTR_AGGREGATOR:
- if (attr_len != 6)
+ if ((peer->capa_received.as_4bytes) && (attr_len != 8))
+ goto bad_len;
+ if ((!(peer->capa_received.as_4bytes)) && (attr_len != 6))
goto bad_len;
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
goto bad_flags;
+ if (peer->capa_received.as_4bytes)
+ goto optattr;
+ new_attr_len = attr_len + 2 ;
+ if ((new_p = malloc(new_attr_len)) == NULL)
+ fatal("rde_attr_parse") ;
+ new_p[0] = 0;
+ new_p[1] = 0 ;
+ memcpy(&new_p[2],p,6);
+ if (attr_optadd(a, flags, type, new_p, new_attr_len) == -1) {
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST,NULL, 0);
+ return (-1);
+ }
+ free(new_p) ;
+ plen += attr_len;
+ break;
+ case ATTR_NEW_AGGREGATOR:
+ /* should only receive this attr from 2 byte as (old) bgp peers */
+ if (peer->capa_received.as_4bytes)
+ goto bad_flags ;
+ if (attr_len != 8)
+ goto bad_len;
+ if (!(flags & (ATTR_OPTIONAL | ATTR_TRANSITIVE)))
+ goto bad_flags;
goto optattr;
case ATTR_COMMUNITIES:
if ((attr_len & 0x3) != 0)
@@ -1527,7 +1681,7 @@
for (i = 0; i <= pathtable.path_hashmask; i++) {
LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) {
- if (!aspath_match(asp->aspath, a->type, a->as))
+ if (!aspath_match(asp->aspath, a->type, a->as,4))
continue;
/* match found */
LIST_FOREACH(p, &asp->prefix_h, path_l)
@@ -1957,7 +2111,7 @@
/*
* generic helper function
*/
-u_int16_t
+u_int32_t
rde_local_as(void)
{
return (conf->as);
@@ -2261,7 +2415,7 @@
struct rde_peer *p;
asp = path_get();
- asp->aspath = aspath_get(NULL, 0);
+ asp->aspath = aspath_get(NULL, 0,3);
asp->origin = ORIGIN_IGP;
asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;