-/* $OpenBSD: rde.c,v 1.378 2018/02/10 01:24:28 benno Exp $ */
+/* $OpenBSD: rde.c,v 1.379 2018/02/10 05:54:31 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
int rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
u_int8_t *);
int rde_update_get_vpn4(u_char *, u_int16_t, struct bgpd_addr *,
- u_int8_t *);
+ u_int8_t *, int);
void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
void *, u_int16_t);
void rde_update_log(const char *, u_int16_t,
case AID_VPN_IPv4:
while (mplen > 0) {
if ((pos = rde_update_get_vpn4(mpp, mplen,
- &prefix, &prefixlen)) == -1) {
+ &prefix, &prefixlen, 1)) == -1) {
log_peer_warnx(&peer->conf,
"bad VPNv4 withdraw prefix");
rde_update_err(peer, ERR_UPDATE,
case AID_VPN_IPv4:
while (mplen > 0) {
if ((pos = rde_update_get_vpn4(mpp, mplen,
- &prefix, &prefixlen)) == -1) {
+ &prefix, &prefixlen, 0)) == -1) {
log_peer_warnx(&peer->conf,
"bad VPNv4 nlri prefix");
rde_update_err(peer, ERR_UPDATE,
int
rde_update_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
- u_int8_t *prefixlen)
+ u_int8_t *prefixlen, int withdraw)
{
int rv, done = 0;
u_int8_t pfxlen;
if (prefix->vpn4.labellen + 3U >
sizeof(prefix->vpn4.labelstack))
return (-1);
+ if (withdraw) {
+ /* on withdraw ignore the labelstack all together */
+ plen += 3;
+ pfxlen -= 3 * 8;
+ break;
+ }
prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++;
prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++;
/* first withdraws */
wpos = 2; /* reserve space for the length field */
r = up_dump_prefix(queue_buf + wpos, len - wpos - 2,
- &peer->withdraws[AID_INET], peer);
+ &peer->withdraws[AID_INET], peer, 1);
wd_len = r;
/* write withdraws length filed */
wd_len = htons(wd_len);
-/* $OpenBSD: rde.h,v 1.167 2018/02/10 01:24:28 benno Exp $ */
+/* $OpenBSD: rde.h,v 1.168 2018/02/10 05:54:31 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
#define PREFIX_SIZE(x) (((x) + 7) / 8 + 1)
int prefix_remove(struct rib *, struct rde_peer *,
struct bgpd_addr *, int, u_int32_t);
-int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t);
+int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t, int);
int prefix_writebuf(struct ibuf *, struct bgpd_addr *, u_int8_t);
struct prefix *prefix_bypeer(struct rib_entry *, struct rde_peer *,
u_int32_t);
u_int8_t);
int up_generate_marker(struct rde_peer *, u_int8_t);
int up_dump_prefix(u_char *, int, struct uplist_prefix *,
- struct rde_peer *);
+ struct rde_peer *, int);
int up_dump_attrnlri(u_char *, int, struct rde_peer *);
u_char *up_dump_mp_unreach(u_char *, u_int16_t *, struct rde_peer *,
u_int8_t);
-/* $OpenBSD: rde_rib.c,v 1.158 2018/02/07 00:02:02 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.159 2018/02/10 05:54:31 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
/* dump a prefix into specified buffer */
int
-prefix_write(u_char *buf, int len, struct bgpd_addr *prefix, u_int8_t plen)
+prefix_write(u_char *buf, int len, struct bgpd_addr *prefix, u_int8_t plen,
+ int withdraw)
{
int totlen;
memcpy(buf, &prefix->ba, totlen - 1);
return (totlen);
case AID_VPN_IPv4:
- totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn4.rd) +
- prefix->vpn4.labellen;
- plen += (sizeof(prefix->vpn4.rd) + prefix->vpn4.labellen) * 8;
+ totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn4.rd);
+ plen += sizeof(prefix->vpn4.rd) * 8;
+ if (withdraw) {
+ /* withdraw have one compat label as placeholder */
+ totlen += 3;
+ plen += 3 * 8;
+ } else {
+ totlen += prefix->vpn4.labellen;
+ plen += prefix->vpn4.labellen * 8;
+ }
if (totlen > len)
return (-1);
*buf++ = plen;
- memcpy(buf, &prefix->vpn4.labelstack, prefix->vpn4.labellen);
- buf += prefix->vpn4.labellen;
+ if (withdraw) {
+ /* magic compatibility label as per rfc8277 */
+ *buf++ = 0x80;
+ *buf++ = 0x0;
+ *buf++ = 0x0;
+ } else {
+ memcpy(buf, &prefix->vpn4.labelstack,
+ prefix->vpn4.labellen);
+ buf += prefix->vpn4.labellen;
+ }
memcpy(buf, &prefix->vpn4.rd, sizeof(prefix->vpn4.rd));
buf += sizeof(prefix->vpn4.rd);
memcpy(buf, &prefix->vpn4.addr, PREFIX_SIZE(plen) - 1);
if ((bptr = ibuf_reserve(buf, totlen)) == NULL)
return (-1);
- if (prefix_write(bptr, totlen, prefix, plen) == -1)
+ if (prefix_write(bptr, totlen, prefix, plen, 0) == -1)
return (-1);
return (0);
}
-/* $OpenBSD: rde_update.c,v 1.88 2018/02/05 03:55:54 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.89 2018/02/10 05:54:31 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
#define MIN_PREFIX_LEN 5 /* 1 byte prefix length + 4 bytes addr */
int
up_dump_prefix(u_char *buf, int len, struct uplist_prefix *prefix_head,
- struct rde_peer *peer)
+ struct rde_peer *peer, int withdraw)
{
struct update_prefix *upp;
int r, wpos = 0;
- u_int8_t i;
while ((upp = TAILQ_FIRST(prefix_head)) != NULL) {
if ((r = prefix_write(buf + wpos, len - wpos,
- &upp->prefix, upp->prefixlen)) == -1)
+ &upp->prefix, upp->prefixlen, withdraw)) == -1)
break;
wpos += r;
if (RB_REMOVE(uptree_prefix, &peer->up_prefix, upp) == NULL)
log_warnx("dequeuing update failed.");
TAILQ_REMOVE(upp->prefix_h, upp, prefix_l);
peer->up_pcnt--;
- for (i = 0; i < AID_MAX; i++) {
- if (upp->prefix_h == &peer->withdraws[i]) {
- peer->up_wcnt--;
- peer->prefix_sent_withdraw++;
- } else {
- peer->up_nlricnt--;
- peer->prefix_sent_update++;
- }
+ if (withdraw) {
+ peer->up_wcnt--;
+ peer->prefix_sent_withdraw++;
+ } else {
+ peer->up_nlricnt--;
+ peer->prefix_sent_update++;
}
free(upp);
}
wpos += upa->attr_len;
/* last but not least dump the nlri */
- r = up_dump_prefix(buf + wpos, len - wpos, &upa->prefix_h, peer);
+ r = up_dump_prefix(buf + wpos, len - wpos, &upa->prefix_h, peer, 0);
wpos += r;
/* now check if all prefixes were written */
return (NULL);
datalen = up_dump_prefix(buf + wpos, *len - wpos,
- &peer->withdraws[aid], peer);
+ &peer->withdraws[aid], peer, 1);
if (datalen == 0)
return (NULL);
return (-2);
datalen = up_dump_prefix(buf + wpos, *len - wpos,
- &upa->prefix_h, peer);
+ &upa->prefix_h, peer, 0);
if (datalen == 0)
return (-2);