From c3741789530ee824693fd606356acac2ad695f83 Mon Sep 17 00:00:00 2001 From: Lou Berger Date: Tue, 12 Jan 2016 13:42:01 -0500 Subject: bgpd: encap: add attribute handling Signed-off-by: Lou Berger Reviewed-by: David Lamparter --- bgpd/Makefile.am | 6 +- bgpd/bgp_attr.c | 327 +++++++++++++++++- bgpd/bgp_attr.h | 16 + bgpd/bgp_encap_tlv.c | 874 +++++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_encap_tlv.h | 177 ++++++++++ bgpd/bgp_encap_types.h | 174 ++++++++++ bgpd/bgpd.h | 1 + 7 files changed, 1572 insertions(+), 3 deletions(-) create mode 100644 bgpd/bgp_encap_tlv.c create mode 100644 bgpd/bgp_encap_tlv.h create mode 100644 bgpd/bgp_encap_types.h (limited to 'bgpd') diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index a35ad870..82c69eac 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -15,14 +15,16 @@ libbgp_a_SOURCES = \ bgp_debug.c bgp_route.c bgp_zebra.c bgp_open.c bgp_routemap.c \ bgp_packet.c bgp_network.c bgp_filter.c bgp_regex.c bgp_clist.c \ bgp_dump.c bgp_snmp.c bgp_ecommunity.c bgp_mplsvpn.c bgp_nexthop.c \ - bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c + bgp_damp.c bgp_table.c bgp_advertise.c bgp_vty.c bgp_mpath.c \ + bgp_encap_tlv.c noinst_HEADERS = \ bgp_aspath.h bgp_attr.h bgp_community.h bgp_debug.h bgp_fsm.h \ bgp_network.h bgp_open.h bgp_packet.h bgp_regex.h bgp_route.h \ bgpd.h bgp_filter.h bgp_clist.h bgp_dump.h bgp_zebra.h \ bgp_ecommunity.h bgp_mplsvpn.h bgp_nexthop.h bgp_damp.h bgp_table.h \ - bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h + bgp_advertise.h bgp_snmp.h bgp_vty.h bgp_mpath.h \ + bgp_encap_tlv.h bgp_encap_types.h bgpd_SOURCES = bgp_main.c bgpd_LDADD = libbgp.a ../lib/libzebra.la @LIBCAP@ @LIBM@ diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a25ea764..b019347b 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -39,6 +39,8 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #include "bgpd/bgp_debug.h" #include "bgpd/bgp_packet.h" #include "bgpd/bgp_ecommunity.h" +#include "table.h" +#include "bgp_encap_types.h" /* Attribute strings for logging. */ static const struct message attr_str [] = @@ -62,6 +64,7 @@ static const struct message attr_str [] = { BGP_ATTR_AS4_PATH, "AS4_PATH" }, { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" }, { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" }, + { BGP_ATTR_ENCAP, "ENCAP" }, }; static const int attr_str_max = array_size(attr_str); @@ -209,6 +212,105 @@ cluster_finish (void) cluster_hash = NULL; } +struct bgp_attr_encap_subtlv * +encap_tlv_dup(struct bgp_attr_encap_subtlv *orig) +{ + struct bgp_attr_encap_subtlv *new; + struct bgp_attr_encap_subtlv *tail; + struct bgp_attr_encap_subtlv *p; + + for (p = orig, tail = new = NULL; p; p = p->next) { + int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length; + if (tail) { + tail->next = XCALLOC(MTYPE_ENCAP_TLV, size); + tail = tail->next; + } else { + tail = new = XCALLOC(MTYPE_ENCAP_TLV, size); + } + assert(tail); + memcpy(tail, p, size); + tail->next = NULL; + } + + return new; +} + +static void +encap_free(struct bgp_attr_encap_subtlv *p) +{ + struct bgp_attr_encap_subtlv *next; + while (p) { + next = p->next; + p->next = NULL; + XFREE(MTYPE_ENCAP_TLV, p); + p = next; + } +} + +void +bgp_attr_flush_encap(struct attr *attr) +{ + if (!attr || !attr->extra) + return; + + if (attr->extra->encap_subtlvs) { + encap_free(attr->extra->encap_subtlvs); + attr->extra->encap_subtlvs = NULL; + } +} + +/* + * Compare encap sub-tlv chains + * + * 1 = equivalent + * 0 = not equivalent + * + * This algorithm could be made faster if needed + */ +static int +encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2) +{ + struct bgp_attr_encap_subtlv *p; + struct bgp_attr_encap_subtlv *q; + + if (!h1 && !h2) + return 1; + if (h1 && !h2) + return 0; + if (!h1 && h2) + return 0; + if (h1 == h2) + return 1; + + for (p = h1; p; p = p->next) { + for (q = h2; q; q = q->next) { + if ((p->type == q->type) && + (p->length == q->length) && + !memcmp(p->value, q->value, p->length)) { + + break; + } + } + if (!q) + return 0; + } + + for (p = h2; p; p = p->next) { + for (q = h1; q; q = q->next) { + if ((p->type == q->type) && + (p->length == q->length) && + !memcmp(p->value, q->value, p->length)) { + + break; + } + } + if (!q) + return 0; + } + + return 1; +} + /* Unknown transit attribute. */ static struct hash *transit_hash; @@ -300,6 +402,10 @@ bgp_attr_extra_free (struct attr *attr) { if (attr->extra) { + if (attr->extra->encap_subtlvs) { + encap_free(attr->extra->encap_subtlvs); + attr->extra->encap_subtlvs = NULL; + } XFREE (MTYPE_ATTR_EXTRA, attr->extra); attr->extra = NULL; } @@ -335,13 +441,20 @@ bgp_attr_dup (struct attr *new, struct attr *orig) { new->extra = extra; memset(new->extra, 0, sizeof(struct attr_extra)); - if (orig->extra) + if (orig->extra) { *new->extra = *orig->extra; + if (orig->extra->encap_subtlvs) { + new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); + } + } } else if (orig->extra) { new->extra = bgp_attr_extra_new(); *new->extra = *orig->extra; + if (orig->extra->encap_subtlvs) { + new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs); + } } } @@ -438,6 +551,8 @@ attrhash_cmp (const void *p1, const void *p2) && ae1->ecommunity == ae2->ecommunity && ae1->cluster == ae2->cluster && ae1->transit == ae2->transit + && (ae1->encap_tunneltype == ae2->encap_tunneltype) + && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs) && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id)) return 1; else if (ae1 || ae2) @@ -503,6 +618,10 @@ bgp_attr_hash_alloc (void *p) { attr->extra = bgp_attr_extra_new (); *attr->extra = *val->extra; + + if (attr->extra->encap_subtlvs) { + attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs); + } } attr->refcnt = 0; return attr; @@ -592,6 +711,9 @@ bgp_attr_default_intern (u_char origin) struct attr attr; struct attr *new; + memset (&attr, 0, sizeof (struct attr)); + bgp_attr_extra_get (&attr); + bgp_attr_default_set(&attr, origin); new = bgp_attr_intern (&attr); @@ -731,6 +853,8 @@ bgp_attr_flush (struct attr *attr) cluster_free (attre->cluster); if (attre->transit && ! attre->transit->refcnt) transit_free (attre->transit); + encap_free(attre->encap_subtlvs); + attre->encap_subtlvs = NULL; } } @@ -1710,6 +1834,122 @@ bgp_attr_ext_communities (struct bgp_attr_parser_args *args) return BGP_ATTR_PARSE_PROCEED; } +/* Parse Tunnel Encap attribute in an UPDATE */ +static int +bgp_attr_encap( + uint8_t type, + struct peer *peer, /* IN */ + bgp_size_t length, /* IN: attr's length field */ + struct attr *attr, /* IN: caller already allocated */ + u_char flag, /* IN: attr's flags field */ + u_char *startp) +{ + bgp_size_t total; + struct attr_extra *attre = NULL; + struct bgp_attr_encap_subtlv *stlv_last = NULL; + uint16_t tunneltype; + + total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); + + if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS) + || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL)) + { + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute flag isn't optional and transitive %d", flag); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, + startp, total); + return -1; + } + + if (BGP_ATTR_ENCAP == type) { + /* read outer TLV type and length */ + uint16_t tlv_length; + + if (length < 4) { + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute not long enough to contain outer T,L"); + bgp_notify_send_with_data(peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + return -1; + } + tunneltype = stream_getw (BGP_INPUT (peer)); + tlv_length = stream_getw (BGP_INPUT (peer)); + length -= 4; + + if (tlv_length != length) { + zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)", + __func__, tlv_length, length); + } + } + + while (length >= 4) { + uint16_t subtype; + uint16_t sublength; + struct bgp_attr_encap_subtlv *tlv; + + subtype = stream_getw (BGP_INPUT (peer)); + sublength = stream_getw (BGP_INPUT (peer)); + length -= 4; + + if (sublength > length) { + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d", + sublength, length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + return -1; + } + + /* alloc and copy sub-tlv */ + /* TBD make sure these are freed when attributes are released */ + tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength); + tlv->type = subtype; + tlv->length = sublength; + stream_get(tlv->value, peer->ibuf, sublength); + length -= sublength; + + /* attach tlv to encap chain */ + if (!attre) { + attre = bgp_attr_extra_get(attr); + if (BGP_ATTR_ENCAP == type) { + for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next; + stlv_last = stlv_last->next); + if (stlv_last) { + stlv_last->next = tlv; + } else { + attre->encap_subtlvs = tlv; + } + } + } else { + stlv_last->next = tlv; + } + stlv_last = tlv; + } + + if (attre && (BGP_ATTR_ENCAP == type)) { + attre->encap_tunneltype = tunneltype; + } + + if (length) { + /* spurious leftover data */ + zlog (peer->log, LOG_ERR, + "Tunnel Encap attribute length is bad: %d leftover octets", length); + bgp_notify_send_with_data (peer, + BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, + startp, total); + return -1; + } + + return 0; +} + /* BGP unknown attribute treatment. */ static bgp_attr_parse_ret_t bgp_attr_unknown (struct bgp_attr_parser_args *args) @@ -2008,6 +2248,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size, case BGP_ATTR_EXT_COMMUNITIES: ret = bgp_attr_ext_communities (&attr_args); break; + case BGP_ATTR_ENCAP: + ret = bgp_attr_encap (type, peer, length, attr, flag, startp); + break; default: ret = bgp_attr_unknown (&attr_args); break; @@ -2262,6 +2505,88 @@ bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p) return size; } +/* + * Encodes the tunnel encapsulation attribute + */ +static void +bgp_packet_mpattr_tea( + struct bgp *bgp, + struct peer *peer, + struct stream *s, + struct attr *attr, + uint8_t attrtype) +{ + unsigned int attrlenfield = 0; + struct bgp_attr_encap_subtlv *subtlvs; + struct bgp_attr_encap_subtlv *st; + const char *attrname; + + if (!attr || !attr->extra) + return; + + switch (attrtype) { + case BGP_ATTR_ENCAP: + attrname = "Tunnel Encap"; + subtlvs = attr->extra->encap_subtlvs; + + /* + * The tunnel encap attr has an "outer" tlv. + * T = tunneltype, + * L = total length of subtlvs, + * V = concatenated subtlvs. + */ + attrlenfield = 2 + 2; /* T + L */ + break; + + default: + assert(0); + } + + + /* compute attr length */ + for (st = subtlvs; st; st = st->next) { + attrlenfield += (4 + st->length); + } + + /* if no tlvs, don't make attr */ + if (!attrlenfield) + return; + + if (attrlenfield > 0xffff) { + zlog (peer->log, LOG_ERR, + "%s attribute is too long (length=%d), can't send it", + attrname, + attrlenfield); + return; + } + + if (attrlenfield > 0xff) { + /* 2-octet length field */ + stream_putc (s, + BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN); + stream_putc (s, attrtype); + stream_putw (s, attrlenfield & 0xffff); + } else { + /* 1-octet length field */ + stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL); + stream_putc (s, attrtype); + stream_putc (s, attrlenfield & 0xff); + } + + if (attrtype == BGP_ATTR_ENCAP) { + /* write outer T+L */ + stream_putw(s, attr->extra->encap_tunneltype); + stream_putw(s, attrlenfield - 4); + } + + /* write each sub-tlv */ + for (st = subtlvs; st; st = st->next) { + stream_putw (s, st->type); + stream_putw (s, st->length); + stream_put (s, st->value, st->length); + } +} + void bgp_packet_mpattr_end (struct stream *s, size_t sizep) { diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 6fdf1c1a..6a134de4 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -47,6 +47,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA #define BGP_ATTR_MIN_LEN 3 /* Attribute flag, type length. */ #define BGP_ATTR_DEFAULT_WEIGHT 32768 +struct bgp_attr_encap_subtlv { + struct bgp_attr_encap_subtlv *next; /* for chaining */ + uint16_t type; + uint16_t length; + uint8_t value[1]; /* will be extended */ +}; + /* Additional/uncommon BGP attributes. * lazily allocated as and when a struct attr * requires it. @@ -85,6 +92,9 @@ struct attr_extra /* MP Nexthop length */ u_char mp_nexthop_len; + + uint16_t encap_tunneltype; /* grr */ + struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */ }; /* BGP core attribute structure. */ @@ -194,6 +204,12 @@ extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args, extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, struct bgp_nlri *); +extern struct bgp_attr_encap_subtlv * +encap_tlv_dup(struct bgp_attr_encap_subtlv *orig); + +extern void +bgp_attr_flush_encap(struct attr *attr); + /** * Set of functions to encode MP_REACH_NLRI and MP_UNREACH_NLRI attributes. * Typical call sequence is to call _start(), followed by multiple _prefix(), diff --git a/bgpd/bgp_encap_tlv.c b/bgpd/bgp_encap_tlv.c new file mode 100644 index 00000000..058b41eb --- /dev/null +++ b/bgpd/bgp_encap_tlv.c @@ -0,0 +1,874 @@ +/* + * Copyright 2015, LabN Consulting, L.L.C. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include + +#include "memory.h" +#include "prefix.h" +#include "vty.h" +#include "filter.h" + +#include "bgpd.h" +#include "bgp_attr.h" + +#include "bgp_encap_types.h" +#include "bgp_encap_tlv.h" + +/*********************************************************************** + * SUBTLV ENCODE + ***********************************************************************/ + +/* rfc5512 4.1 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_encap_l2tpv3_over_ip( + struct bgp_tea_subtlv_encap_l2tpv3_over_ip *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 4 + st->cookie_length; + + /* sanity check */ + assert(st->cookie_length <= sizeof(st->cookie)); + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; + new->length = total; + p = new->value; + + *p++ = (st->sessionid & 0xff000000) >> 24; + *p++ = (st->sessionid & 0xff0000) >> 16; + *p++ = (st->sessionid & 0xff00) >> 8; + *p++ = (st->sessionid & 0xff); + memcpy(p, st->cookie, st->cookie_length); + return new; +} + +/* rfc5512 4.1 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_encap_gre( + struct bgp_tea_subtlv_encap_gre_key *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 4; + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; + new->length = total; + p = new->value; + + *p++ = (st->gre_key & 0xff000000) >> 24; + *p++ = (st->gre_key & 0xff0000) >> 16; + *p++ = (st->gre_key & 0xff00) >> 8; + *p++ = (st->gre_key & 0xff); + return new; +} + +static struct bgp_attr_encap_subtlv * +subtlv_encode_encap_pbb( + struct bgp_tea_subtlv_encap_pbb *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 1 + 3 + 6 + 2; /* flags + isid + madaddr + vid */ + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION; + new->length = total; + p = new->value; + + *p++ = (st->flag_isid? 0x80: 0) | + (st->flag_vid? 0x40: 0) | + 0; + if (st->flag_isid) { + *p = (st->isid & 0xff0000) >> 16; + *(p+1) = (st->isid & 0xff00) >> 8; + *(p+2) = (st->isid & 0xff); + } + p += 3; + memcpy(p, st->macaddr, 6); + p += 6; + if (st->flag_vid) { + *p++ = (st->vid & 0xf00) >> 8; + *p++ = st->vid & 0xff; + } + return new; +} + +/* rfc5512 4.2 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_proto_type( + struct bgp_tea_subtlv_proto_type *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 2; + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE; + new->length = total; + p = new->value; + + *p++ = (st->proto & 0xff00) >> 8; + *p++ = (st->proto & 0xff); + return new; +} + +/* rfc5512 4.3 */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_color( + struct bgp_tea_subtlv_color *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 8; + + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_COLOR; + new->length = total; + p = new->value; + + *p++ = 0x03; /* transitive*/ + *p++ = 0x0b; + *p++ = 0; /* reserved */ + *p++ = 0; /* reserved */ + + *p++ = (st->color & 0xff000000) >> 24; + *p++ = (st->color & 0xff0000) >> 16; + *p++ = (st->color & 0xff00) >> 8; + *p++ = (st->color & 0xff); + + return new; +} + +/* rfc 5566 4. */ +static struct bgp_attr_encap_subtlv * +subtlv_encode_ipsec_ta( + struct bgp_tea_subtlv_ipsec_ta *st) +{ + struct bgp_attr_encap_subtlv *new; + uint8_t *p; + int total = 2 + st->authenticator_length; + + /* sanity check */ + assert(st->authenticator_length <= sizeof(st->value)); + assert(total <= 0xff); + + new = XCALLOC(MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv) - 1 + total); + assert(new); + new->type = BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA; + new->length = total; + p = new->value; + + *p++ = (st->authenticator_type & 0xff00) >> 8; + *p++ = st->authenticator_type & 0xff; + memcpy(p, st->value, st->authenticator_length); + return new; +} + + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV ENCODE + ***********************************************************************/ + +/* + * requires "extra" and "last" to be defined in caller + */ +#define ENC_SUBTLV(flag, function, field) do {\ + struct bgp_attr_encap_subtlv *new;\ + if (CHECK_FLAG(bet->valid_subtlvs, (flag))) {\ + new = function(&bet->field);\ + if (last) {\ + last->next = new;\ + } else {\ + extra->encap_subtlvs = new;\ + }\ + last = new;\ + }\ +} while (0) + +void +bgp_encap_type_l2tpv3overip_to_tlv( + struct bgp_encap_type_l2tpv3_over_ip *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_L2TPV3_OVER_IP; + + assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); + + ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_l2tpv3_over_ip, st_encap); + ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); + ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); +} + +void +bgp_encap_type_gre_to_tlv( + struct bgp_encap_type_gre *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_GRE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_gre, st_encap); + ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); + ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); +} + +void +bgp_encap_type_ip_in_ip_to_tlv( + struct bgp_encap_type_ip_in_ip *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP; + + ENC_SUBTLV(BGP_TEA_SUBTLV_PROTO_TYPE, subtlv_encode_proto_type, st_proto); + ENC_SUBTLV(BGP_TEA_SUBTLV_COLOR, subtlv_encode_color, st_color); +} + +void +bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_encap_type_transmit_tunnel_endpoint *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT; + + /* no subtlvs for this type */ +} + +void +bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( + struct bgp_encap_type_ipsec_in_tunnel_mode *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); +} + +void +bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); +} + +void +bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE; + + ENC_SUBTLV(BGP_TEA_SUBTLV_IPSEC_TA, subtlv_encode_ipsec_ta, st_ipsec_ta); +} + +void +bgp_encap_type_pbb_to_tlv( + struct bgp_encap_type_pbb *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + struct bgp_attr_encap_subtlv *last; + + /* advance to last subtlv */ + for (last = extra->encap_subtlvs; last && last->next; last = last->next); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_PBB; + + assert(CHECK_FLAG(bet->valid_subtlvs, BGP_TEA_SUBTLV_ENCAP)); + ENC_SUBTLV(BGP_TEA_SUBTLV_ENCAP, subtlv_encode_encap_pbb, st_encap); +} + +void +bgp_encap_type_vxlan_to_tlv( + struct bgp_encap_type_vxlan *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN; +} + +void +bgp_encap_type_nvgre_to_tlv( + struct bgp_encap_type_nvgre *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_NVGRE; +} + +void +bgp_encap_type_mpls_to_tlv( + struct bgp_encap_type_mpls *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS; +} + +void +bgp_encap_type_mpls_in_gre_to_tlv( + struct bgp_encap_type_mpls_in_gre *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_GRE; +} + +void +bgp_encap_type_vxlan_gpe_to_tlv( + struct bgp_encap_type_vxlan_gpe *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_VXLAN_GPE; +} + +void +bgp_encap_type_mpls_in_udp_to_tlv( + struct bgp_encap_type_mpls_in_udp *bet, /* input structure */ + struct attr *attr) +{ + struct attr_extra *extra = bgp_attr_extra_get(attr); + + extra->encap_tunneltype = BGP_ENCAP_TYPE_MPLS_IN_UDP; +} + + +/*********************************************************************** + * SUBTLV DECODE + ***********************************************************************/ +/* rfc5512 4.1 */ +static int +subtlv_decode_encap_l2tpv3_over_ip( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_encap_l2tpv3_over_ip *st) +{ + if (subtlv->length < 4) { + zlog_debug("%s, subtlv length %d is less than 4", + __func__, subtlv->length); + return -1; + } + + st->sessionid = (subtlv->value[0] << 24) | + (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]; + st->cookie_length = subtlv->length - 4; + if (st->cookie_length > sizeof(st->cookie)) { + zlog_debug("%s, subtlv length %d is greater than %d", + __func__, st->cookie_length, (int)sizeof(st->cookie)); + return -1; + } + memcpy(st->cookie, subtlv->value + 4, st->cookie_length); + return 0; +} + +/* rfc5512 4.1 */ +static int +subtlv_decode_encap_gre( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_encap_gre_key *st) +{ + if (subtlv->length != 4) { + zlog_debug("%s, subtlv length %d does not equal 4", + __func__, subtlv->length); + return -1; + } + st->gre_key = (subtlv->value[0] << 24) | + (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]; + return 0; +} + +static int +subtlv_decode_encap_pbb( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_encap_pbb *st) +{ + if (subtlv->length != 1 + 3 + 6 + 2) { + zlog_debug("%s, subtlv length %d does not equal %d", + __func__, subtlv->length, 1 + 3 + 6 + 2); + return -1; + } + if (subtlv->value[0] & 0x80) { + st->flag_isid = 1; + st->isid = (subtlv->value[1] << 16) | + (subtlv->value[2] << 8) | + subtlv->value[3]; + } + if (subtlv->value[0] & 0x40) { + st->flag_vid = 1; + st->vid = ((subtlv->value[10] & 0x0f) << 8) | subtlv->value[11]; + } + memcpy(st->macaddr, subtlv->value + 4, 6); + return 0; +} + +/* rfc5512 4.2 */ +static int +subtlv_decode_proto_type( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_proto_type *st) +{ + if (subtlv->length != 2) { + zlog_debug("%s, subtlv length %d does not equal 2", + __func__, subtlv->length); + return -1; + } + st->proto = (subtlv->value[0] << 8) | subtlv->value[1]; + return 0; +} + +/* rfc5512 4.3 */ +static int +subtlv_decode_color( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_color *st) +{ + if (subtlv->length != 8) { + zlog_debug("%s, subtlv length %d does not equal 8", + __func__, subtlv->length); + return -1; + } + if ((subtlv->value[0] != 0x03) || + (subtlv->value[1] != 0x0b) || + (subtlv->value[2] != 0) || + (subtlv->value[3] != 0)) { + zlog_debug("%s, subtlv value 1st 4 bytes are not 0x030b0000", __func__); + return -1; + } + st->color = (subtlv->value[4] << 24) | + (subtlv->value[5] << 16) | + (subtlv->value[6] << 8) | + subtlv->value[7]; + return 0; +} + +/* rfc 5566 4. */ +static int +subtlv_decode_ipsec_ta( + struct bgp_attr_encap_subtlv *subtlv, + struct bgp_tea_subtlv_ipsec_ta *st) +{ + st->authenticator_length = subtlv->length - 2; + if (st->authenticator_length > sizeof(st->value)) { + zlog_debug("%s, authenticator length %d exceeds storage maximum %d", + __func__, st->authenticator_length, (int)sizeof(st->value)); + return -1; + } + st->authenticator_type = (subtlv->value[0] << 8) | subtlv->value[1]; + memcpy(st->value, subtlv->value + 2, st->authenticator_length); + return 0; +} + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV DECODE + ***********************************************************************/ + +int +tlv_to_bgp_encap_type_l2tpv3overip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_l2tpv3_over_ip *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: + rc |= subtlv_decode_encap_l2tpv3_over_ip(st, &bet->st_encap); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + break; + + case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: + rc |= subtlv_decode_proto_type(st, &bet->st_proto); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + break; + + case BGP_ENCAP_SUBTLV_TYPE_COLOR: + rc |= subtlv_decode_color(st, &bet->st_color); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_gre( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_gre *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: + rc |= subtlv_decode_encap_gre(st, &bet->st_encap); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + break; + + case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: + rc |= subtlv_decode_proto_type(st, &bet->st_proto); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + break; + + case BGP_ENCAP_SUBTLV_TYPE_COLOR: + rc |= subtlv_decode_color(st, &bet->st_color); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_ip_in_ip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ip_in_ip *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE: + rc |= subtlv_decode_proto_type(st, &bet->st_proto); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_PROTO_TYPE; + break; + + case BGP_ENCAP_SUBTLV_TYPE_COLOR: + rc |= subtlv_decode_color(st, &bet->st_color); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_COLOR; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_transmit_tunnel_endpoint *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ipsec_in_tunnel_mode *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: + rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: + rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA: + rc |= subtlv_decode_ipsec_ta(st, &bet->st_ipsec_ta); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_IPSEC_TA; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_vxlan( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_nvgre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_nvgre *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls_in_gre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_gre *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_vxlan_gpe( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan_gpe *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_mpls_in_udp( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_udp *bet) +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + +int +tlv_to_bgp_encap_type_pbb( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_pbb *bet) /* caller-allocated */ +{ + struct bgp_attr_encap_subtlv *st; + int rc = 0; + + for (st = stlv; st; st = st->next) { + switch (st->type) { + case BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION: + rc |= subtlv_decode_encap_pbb(st, &bet->st_encap); + bet->valid_subtlvs |= BGP_TEA_SUBTLV_ENCAP; + break; + + default: + zlog_debug("%s: unexpected subtlv type %d", __func__, st->type); + rc |= -1; + break; + } + } + return rc; +} + diff --git a/bgpd/bgp_encap_tlv.h b/bgpd/bgp_encap_tlv.h new file mode 100644 index 00000000..d94d544d --- /dev/null +++ b/bgpd/bgp_encap_tlv.h @@ -0,0 +1,177 @@ +/* + * Copyright 2015, LabN Consulting, L.L.C. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _QUAGGA_BGP_ENCAP_TLV_H +#define _QUAGGA_BGP_ENCAP_TLV_H + + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV ENCODE + ***********************************************************************/ + +extern void +bgp_encap_type_l2tpv3overip_to_tlv( + struct bgp_encap_type_l2tpv3_over_ip *bet, + struct attr *attr); + +extern void +bgp_encap_type_gre_to_tlv( + struct bgp_encap_type_gre *bet, + struct attr *attr); + +extern void +bgp_encap_type_ip_in_ip_to_tlv( + struct bgp_encap_type_ip_in_ip *bet, + struct attr *attr); + +extern void +bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_encap_type_transmit_tunnel_endpoint *bet, + struct attr *attr); + +extern void +bgp_encap_type_ipsec_in_tunnel_mode_to_tlv( + struct bgp_encap_type_ipsec_in_tunnel_mode *bet, + struct attr *attr); + +extern void +bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode_to_tlv( + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet, + struct attr *attr); + +extern void +bgp_encap_type_pbb_to_tlv( + struct bgp_encap_type_pbb *bet, + struct attr *attr); + +extern void +bgp_encap_type_vxlan_to_tlv( + struct bgp_encap_type_vxlan *bet, + struct attr *attr); + +extern void +bgp_encap_type_nvgre_to_tlv( + struct bgp_encap_type_nvgre *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_to_tlv( + struct bgp_encap_type_mpls *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_in_gre_to_tlv( + struct bgp_encap_type_mpls_in_gre *bet, + struct attr *attr); + +extern void +bgp_encap_type_vxlan_gpe_to_tlv( + struct bgp_encap_type_vxlan_gpe *bet, + struct attr *attr); + +extern void +bgp_encap_type_mpls_in_udp_to_tlv( + struct bgp_encap_type_mpls_in_udp *bet, + struct attr *attr); + +/*********************************************************************** + * TUNNEL TYPE-SPECIFIC TLV DECODE + ***********************************************************************/ + +extern int +tlv_to_bgp_encap_type_l2tpv3overip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_l2tpv3_over_ip *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_gre( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_gre *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_ip_in_ip( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ip_in_ip *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_transmit_tunnel_endpoint( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_transmit_tunnel_endpoint *bet); + +extern int +tlv_to_bgp_encap_type_ipsec_in_tunnel_mode( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_ipsec_in_tunnel_mode *bet); /* caller-allocated */ + +extern int +tlv_to_bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode *bet); + +extern int +tlv_to_bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode *bet); + +extern int +tlv_to_bgp_encap_type_vxlan( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan *bet); + +extern int +tlv_to_bgp_encap_type_nvgre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_nvgre *bet); + +extern int +tlv_to_bgp_encap_type_mpls( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls *bet); + +extern int +tlv_to_bgp_encap_type_mpls( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls *bet); + +extern int +tlv_to_bgp_encap_type_mpls_in_gre( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_gre *bet); + +extern int +tlv_to_bgp_encap_type_vxlan_gpe( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_vxlan_gpe *bet); + +extern int +tlv_to_bgp_encap_type_mpls_in_udp( + struct bgp_attr_encap_subtlv *stlv, + struct bgp_encap_type_mpls_in_udp *bet); + +extern int +tlv_to_bgp_encap_type_pbb( + struct bgp_attr_encap_subtlv *stlv, /* subtlv chain */ + struct bgp_encap_type_pbb *bet); /* caller-allocated */ + +#endif /* _QUAGGA_BGP_ENCAP_TLV_H */ diff --git a/bgpd/bgp_encap_types.h b/bgpd/bgp_encap_types.h new file mode 100644 index 00000000..c81b7297 --- /dev/null +++ b/bgpd/bgp_encap_types.h @@ -0,0 +1,174 @@ +/* + * Copyright 2015, LabN Consulting, L.L.C. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef _QUAGGA_BGP_ENCAP_TYPES_H +#define _QUAGGA_BGP_ENCAP_TYPES_H + +/* from http://www.iana.org/assignments/bgp-parameters/bgp-parameters.xhtml#tunnel-types */ +typedef enum { + BGP_ENCAP_TYPE_RESERVED=0, + BGP_ENCAP_TYPE_L2TPV3_OVER_IP=1, + BGP_ENCAP_TYPE_GRE=2, + BGP_ENCAP_TYPE_TRANSMIT_TUNNEL_ENDPOINT=3, + BGP_ENCAP_TYPE_IPSEC_IN_TUNNEL_MODE=4, + BGP_ENCAP_TYPE_IP_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE=5, + BGP_ENCAP_TYPE_MPLS_IN_IP_TUNNEL_WITH_IPSEC_TRANSPORT_MODE=6, + BGP_ENCAP_TYPE_IP_IN_IP=7, + BGP_ENCAP_TYPE_VXLAN=8, + BGP_ENCAP_TYPE_NVGRE=9, + BGP_ENCAP_TYPE_MPLS=10, + BGP_ENCAP_TYPE_MPLS_IN_GRE=11, + BGP_ENCAP_TYPE_VXLAN_GPE=12, + BGP_ENCAP_TYPE_MPLS_IN_UDP=13, + BGP_ENCAP_TYPE_PBB +} bgp_encap_types; + +typedef enum { + BGP_ENCAP_SUBTLV_TYPE_ENCAPSULATION=1, + BGP_ENCAP_SUBTLV_TYPE_PROTO_TYPE=2, + BGP_ENCAP_SUBTLV_TYPE_IPSEC_TA=3, + BGP_ENCAP_SUBTLV_TYPE_COLOR=4, +} bgp_encap_subtlv_types; + +/* + * Tunnel Encapsulation Attribute subtlvs + */ +struct bgp_tea_subtlv_encap_l2tpv3_over_ip { + uint32_t sessionid; + uint8_t cookie_length; + uint8_t cookie[8]; +}; + +struct bgp_tea_subtlv_encap_gre_key { + uint32_t gre_key; +}; + +struct bgp_tea_subtlv_encap_pbb { + uint32_t flag_isid:1; + uint32_t flag_vid:1; + uint32_t isid:24; + uint16_t vid:12; + uint8_t macaddr[6]; +}; + +struct bgp_tea_subtlv_proto_type { + uint16_t proto; /* ether-type */ +}; + +struct bgp_tea_subtlv_color { + uint32_t color; +}; + +/* + * This is the length of the value part of the ipsec tunnel authenticator + * subtlv. Currently we only support the length for authenticator type 1. + */ +#define BGP_ENCAP_SUBTLV_IPSEC_TA_SIZE 20 + +struct bgp_tea_subtlv_ipsec_ta { + uint16_t authenticator_type; /* only type 1 is supported so far */ + uint8_t authenticator_length; /* octets in value field */ + uint8_t value[BGP_ENCAP_SUBTLV_IPSEC_TA_SIZE]; +}; + +/* + * Subtlv valid flags + * TBD change names to add "VALID" + */ +#define BGP_TEA_SUBTLV_ENCAP 0x00000001 +#define BGP_TEA_SUBTLV_PROTO_TYPE 0x00000002 +#define BGP_TEA_SUBTLV_COLOR 0x00000004 +#define BGP_TEA_SUBTLV_IPSEC_TA 0x00000008 + + +/* + * Tunnel Type-specific APIs + */ +struct bgp_encap_type_reserved { +}; + +struct bgp_encap_type_l2tpv3_over_ip { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_encap_l2tpv3_over_ip st_encap; + struct bgp_tea_subtlv_proto_type st_proto; /* optional */ + struct bgp_tea_subtlv_color st_color; /* optional */ +}; + +struct bgp_encap_type_gre { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_encap_gre_key st_encap; /* optional */ + struct bgp_tea_subtlv_proto_type st_proto; /* optional */ + struct bgp_tea_subtlv_color st_color; /* optional */ +}; + +struct bgp_encap_type_ip_in_ip { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_proto_type st_proto; /* optional */ + struct bgp_tea_subtlv_color st_color; /* optional */ +}; + +struct bgp_encap_type_transmit_tunnel_endpoint { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_ipsec_in_tunnel_mode { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ +}; + +struct bgp_encap_type_ip_in_ip_tunnel_with_ipsec_transport_mode { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ +}; + +struct bgp_encap_type_mpls_in_ip_tunnel_with_ipsec_transport_mode { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_ipsec_ta st_ipsec_ta; /* optional */ +}; + +struct bgp_encap_type_vxlan { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_nvgre { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_mpls { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_mpls_in_gre { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_vxlan_gpe { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_mpls_in_udp { + /* No subtlvs defined in spec? */ +}; + +struct bgp_encap_type_pbb { + uint32_t valid_subtlvs; + struct bgp_tea_subtlv_encap_pbb st_encap; +}; + +#endif /* _QUAGGA_BGP_ENCAP_TYPES_H */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 0b3d449c..eb638950 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -648,6 +648,7 @@ struct bgp_nlri #define BGP_ATTR_AS4_PATH 17 #define BGP_ATTR_AS4_AGGREGATOR 18 #define BGP_ATTR_AS_PATHLIMIT 21 +#define BGP_ATTR_ENCAP 23 /* BGP update origin. */ #define BGP_ORIGIN_IGP 0 -- cgit v1.2.3