|
@@ -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 <zebra.h>
|
|
|
+
|
|
|
+#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;
|
|
|
+}
|
|
|
+
|