| /* |
| * 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; |
| } |
| |