ok with whitespace fixes below Claudio Jeker(cje...@diehard.n-r-g.com) on 2019.05.10 15:34:22 +0200: > This change is from a much larger patch I'm working on. This cleans up > up_generate_attr() from a hardcoded implementation to a loop-switch > construct. This way attributes are always dumped in ascending order as > suggested by the RFC and adding special attributes is simpler than in the > current way. There is an exception whit the MP attributes because those > are added at a later point. > > Works for me(tm) > -- > :wq Claudio > > Index: rde_update.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v > retrieving revision 1.108 > diff -u -p -r1.108 rde_update.c > --- rde_update.c 21 Jan 2019 02:07:56 -0000 1.108 > +++ rde_update.c 10 May 2019 11:51:28 -0000 > @@ -295,96 +295,155 @@ up_generate_attr(u_char *buf, int len, s > struct filterstate *state, u_int8_t aid) > { > struct rde_aspath *asp = &state->aspath; > - struct attr *oa, *newaggr = NULL; > + struct attr *oa = NULL, *newaggr = NULL; > u_char *pdata; > u_int32_t tmp32; > in_addr_t nexthop; > int flags, r, neednewpath = 0; > u_int16_t wlen = 0, plen; > - u_int8_t l; > - u_int16_t nlen = 0; > - u_char *ndata; > - > - /* origin */ > - if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, > - ATTR_ORIGIN, &asp->origin, 1)) == -1) > - return (-1); > - wlen += r; len -= r; > - > - /* aspath */ > - if (!peer->conf.ebgp || > - peer->conf.flags & PEERFLAG_TRANS_AS) > - pdata = aspath_prepend(asp->aspath, peer->conf.local_as, 0, > - &plen); > - else > - pdata = aspath_prepend(asp->aspath, peer->conf.local_as, 1, > - &plen); > - > - if (!rde_as4byte(peer)) > - pdata = aspath_deflate(pdata, &plen, &neednewpath); > - > - if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, > - ATTR_ASPATH, pdata, plen)) == -1) > - return (-1); > - wlen += r; len -= r; > - free(pdata); > - > - switch (aid) { > - case AID_INET: > - nexthop = up_get_nexthop(peer, state); > - if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, > - ATTR_NEXTHOP, &nexthop, 4)) == -1) > - return (-1); > - wlen += r; len -= r; > - break; > - default: > - break; > - } > - > - /* > - * The old MED from other peers MUST not be announced to others > - * unless the MED is originating from us or the peer is an IBGP one. > - * Only exception are routers with "transparent-as yes" set. > - */ > - if (asp->flags & F_ATTR_MED && (!peer->conf.ebgp || > - asp->flags & F_ATTR_MED_ANNOUNCE || > - peer->conf.flags & PEERFLAG_TRANS_AS)) { > - tmp32 = htonl(asp->med); > - if ((r = attr_write(buf + wlen, len, ATTR_OPTIONAL, > - ATTR_MED, &tmp32, 4)) == -1) > - return (-1); > - wlen += r; len -= r; > - } > - > - if (!peer->conf.ebgp) { > - /* local preference, only valid for ibgp */ > - tmp32 = htonl(asp->lpref); > - if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, > - ATTR_LOCALPREF, &tmp32, 4)) == -1) > - return (-1); > - wlen += r; len -= r; > - } > - > - /* > - * dump all other path attributes. Following rules apply: > - * 1. well-known attrs: ATTR_ATOMIC_AGGREGATE and ATTR_AGGREGATOR > - * pass unmodified (enforce flags to correct values) > - * Actually ATTR_AGGREGATOR may be deflated for OLD 2-byte peers. > - * 2. non-transitive attrs: don't re-announce to ebgp peers > - * 3. transitive known attrs: announce unmodified > - * 4. transitive unknown attrs: set partial bit and re-announce > - */ > - for (l = 0; l < asp->others_len; l++) { > - if ((oa = asp->others[l]) == NULL) > + u_int8_t oalen = 0, type; > + > + if (asp->others_len > 0) > + oa = asp->others[oalen++]; > + > + /* dump attributes in ascending order */ > + for (type = ATTR_ORIGIN; type < 255; type++) { > + r = 0; > + > + while (oa && oa->type < type) { > + if (oalen < asp->others_len) > + oa = asp->others[oalen++];
trailing tab > + else > + oa = NULL; > + } > + > + switch (type) { > + /* > + * Attributes stored in rde_aspath > + */ > + case ATTR_ORIGIN: > + if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, > + ATTR_ORIGIN, &asp->origin, 1)) == -1) > + return (-1); > break; > - switch (oa->type) { > + case ATTR_ASPATH: > + if (!peer->conf.ebgp || > + peer->conf.flags & PEERFLAG_TRANS_AS) > + pdata = aspath_prepend(asp->aspath, > + peer->conf.local_as, 0, &plen); > + else > + pdata = aspath_prepend(asp->aspath, > + peer->conf.local_as, 1, &plen); > + > + if (!rde_as4byte(peer)) > + pdata = aspath_deflate(pdata, &plen, > + &neednewpath); > + > + if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, > + ATTR_ASPATH, pdata, plen)) == -1) > + return (-1); > + free(pdata); > + break; > + case ATTR_NEXTHOP: > + switch (aid) { > + case AID_INET: > + nexthop = up_get_nexthop(peer, state); > + if ((r = attr_write(buf + wlen, len, > + ATTR_WELL_KNOWN, ATTR_NEXTHOP, &nexthop, > + 4)) == -1) > + return (-1); > + break; > + default: > + break; > + } > + break; > + case ATTR_MED: > + /* > + * The old MED from other peers MUST not be announced > + * to others unless the MED is originating from us or > + * the peer is an IBGP one. Only exception are routers > + * with "transparent-as yes" set. > + */ > + if (asp->flags & F_ATTR_MED && (!peer->conf.ebgp || > + asp->flags & F_ATTR_MED_ANNOUNCE || > + peer->conf.flags & PEERFLAG_TRANS_AS)) { > + tmp32 = htonl(asp->med); > + if ((r = attr_write(buf + wlen, len, > + ATTR_OPTIONAL, ATTR_MED, &tmp32, 4)) == -1) > + return (-1); > + } > + break; > + case ATTR_LOCALPREF: > + if (!peer->conf.ebgp) { > + /* local preference, only valid for ibgp */ > + tmp32 = htonl(asp->lpref); > + if ((r = attr_write(buf + wlen, len, > + ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp32, > + 4)) == -1) > + return (-1); > + } > + break; > + /* > + * multiprotocol attributes are handled elsewhere > + */ > + case ATTR_MP_REACH_NLRI: > + case ATTR_MP_UNREACH_NLRI: > + break; > + /* > + * NEW to OLD conversion when sending stuff to a 2byte AS peer > + */ > + case ATTR_AS4_PATH: > + if (neednewpath) { > + if (!peer->conf.ebgp || > + peer->conf.flags & PEERFLAG_TRANS_AS) > + pdata = aspath_prepend(asp->aspath, > + peer->conf.local_as, 0, &plen); > + else > + pdata = aspath_prepend(asp->aspath, > + peer->conf.local_as, 1, &plen); > + flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; > + if (!(asp->flags & F_PREFIX_ANNOUNCED)) > + flags |= ATTR_PARTIAL; > + if (plen == 0) > + r = 0; > + else if ((r = attr_write(buf + wlen, len, flags, > + ATTR_AS4_PATH, pdata, plen)) == -1) > + return (-1); > + free(pdata); > + } > + break; > + case ATTR_AS4_AGGREGATOR: > + if (newaggr) { > + flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; > + if (!(asp->flags & F_PREFIX_ANNOUNCED)) > + flags |= ATTR_PARTIAL; > + if ((r = attr_write(buf + wlen, len, flags, > + ATTR_AS4_AGGREGATOR, newaggr->data, > + newaggr->len)) == -1) > + return (-1); > + } > + break; > + /* > + * dump all other path attributes. Following rules apply: > + * 1. well-known attrs: ATTR_ATOMIC_AGGREGATE and > + * ATTR_AGGREGATOR pass unmodified (enforce flags > + * to correct values). Actually ATTR_AGGREGATOR may be > + * deflated for OLD 2-byte peers. > + * 2. non-transitive attrs: don't re-announce to ebgp peers > + * 3. transitive known attrs: announce unmodified > + * 4. transitive unknown attrs: set partial bit and re-announce > + */ > case ATTR_ATOMIC_AGGREGATE: > + if (oa == NULL || oa->type != type) > + break; > if ((r = attr_write(buf + wlen, len, > ATTR_WELL_KNOWN, ATTR_ATOMIC_AGGREGATE, > NULL, 0)) == -1) > return (-1); > break; > case ATTR_AGGREGATOR: > + if (oa == NULL || oa->type != type) > + break; > if (!rde_as4byte(peer)) { > /* need to deflate the aggregator */ > u_int8_t t[6]; > @@ -417,6 +476,8 @@ up_generate_attr(u_char *buf, int len, s > case ATTR_ORIGINATOR_ID: > case ATTR_CLUSTER_LIST: > case ATTR_LARGE_COMMUNITIES: > + if (oa == NULL || oa->type != type) > + break; > if ((!(oa->flags & ATTR_TRANSITIVE)) && > peer->conf.ebgp) { > r = 0; > @@ -427,8 +488,13 @@ up_generate_attr(u_char *buf, int len, s > return (-1); > break; > case ATTR_EXT_COMMUNITIES: > + if (oa == NULL || oa->type != type) > + break; > /* handle (non-)transitive extended communities */ > if (peer->conf.ebgp) { > + u_char *ndata; > + u_int16_t nlen; > + > ndata = community_ext_delete_non_trans(oa->data, > oa->len, &nlen); > > @@ -440,10 +506,8 @@ up_generate_attr(u_char *buf, int len, s > return (-1); > } > free(ndata); > - } else { > - /* everything got removed */ > - r = 0; > - } > + } trailing space > + /* else everything got removed */ > } else { > if ((r = attr_write(buf + wlen, len, oa->flags, > oa->type, oa->data, oa->len)) == -1) > @@ -451,6 +515,9 @@ up_generate_attr(u_char *buf, int len, s > } > break; > default: > + if (oa == NULL || oa->type != type) > + break; > + > /* unknown attribute */ > if (!(oa->flags & ATTR_TRANSITIVE)) { > /* > @@ -459,7 +526,6 @@ up_generate_attr(u_char *buf, int len, s > * attributes must be quietly ignored and > * not passed along to other BGP peers. > */ > - r = 0; > break; > } > if ((r = attr_write(buf + wlen, len, > @@ -468,36 +534,6 @@ up_generate_attr(u_char *buf, int len, s > return (-1); > break; > } > - wlen += r; len -= r; > - } > - > - /* NEW to OLD conversion when going sending stuff to a 2byte AS peer */ > - if (neednewpath) { > - if (!peer->conf.ebgp || > - peer->conf.flags & PEERFLAG_TRANS_AS) > - pdata = aspath_prepend(asp->aspath, peer->conf.local_as, > - 0, &plen); > - else > - pdata = aspath_prepend(asp->aspath, peer->conf.local_as, > - 1, &plen); > - flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; > - if (!(asp->flags & F_PREFIX_ANNOUNCED)) > - flags |= ATTR_PARTIAL; > - if (plen == 0) > - r = 0; > - else if ((r = attr_write(buf + wlen, len, flags, > - ATTR_AS4_PATH, pdata, plen)) == -1) > - return (-1); > - wlen += r; len -= r; > - free(pdata); > - } > - if (newaggr) { > - flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; > - if (!(asp->flags & F_PREFIX_ANNOUNCED)) > - flags |= ATTR_PARTIAL; > - if ((r = attr_write(buf + wlen, len, flags, > - ATTR_AS4_AGGREGATOR, newaggr->data, newaggr->len)) == -1) > - return (-1); > wlen += r; len -= r; > } > >