diff options
Diffstat (limited to '')
-rw-r--r-- | bgpd/bgp_ecommunity.h | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h new file mode 100644 index 0000000..4d7d423 --- /dev/null +++ b/bgpd/bgp_ecommunity.h @@ -0,0 +1,356 @@ +/* BGP Extended Communities Attribute. + * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + * + * This file is part of GNU Zebra. + * + * GNU Zebra 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, or (at your option) any + * later version. + * + * GNU Zebra 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; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _QUAGGA_BGP_ECOMMUNITY_H +#define _QUAGGA_BGP_ECOMMUNITY_H + +#include "bgpd/bgp_route.h" +#include "bgpd/bgp_rpki.h" +#include "bgpd/bgpd.h" + +/* Refer to rfc7153 for the IANA registry definitions. These are + * updated by other standards like rfc7674. + */ +/* High-order octet of the Extended Communities type field. */ +#define ECOMMUNITY_ENCODE_AS 0x00 +#define ECOMMUNITY_ENCODE_IP 0x01 +#define ECOMMUNITY_ENCODE_AS4 0x02 +#define ECOMMUNITY_ENCODE_OPAQUE 0x03 +#define ECOMMUNITY_ENCODE_EVPN 0x06 +#define ECOMMUNITY_ENCODE_REDIRECT_IP_NH 0x08 /* Flow Spec */ +/* Generic Transitive Experimental */ +#define ECOMMUNITY_ENCODE_TRANS_EXP 0x80 + +/* RFC7674 */ +#define ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 0x81 +#define ECOMMUNITY_EXTENDED_COMMUNITY_PART_3 0x82 + +/* Non-transitive extended community types. */ +#define ECOMMUNITY_ENCODE_AS_NON_TRANS 0x40 +#define ECOMMUNITY_ENCODE_IP_NON_TRANS 0x41 +#define ECOMMUNITY_ENCODE_AS4_NON_TRANS 0x42 +#define ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS 0x43 + +/* Low-order octet of the Extended Communities type field. */ +/* Note: This really depends on the high-order octet. This means that + * multiple definitions for the same value are possible. + */ +#define ECOMMUNITY_ORIGIN_VALIDATION_STATE 0x00 +#define ECOMMUNITY_ROUTE_TARGET 0x02 +#define ECOMMUNITY_SITE_ORIGIN 0x03 +#define ECOMMUNITY_LINK_BANDWIDTH 0x04 +#define ECOMMUNITY_TRAFFIC_RATE 0x06 /* Flow Spec */ +#define ECOMMUNITY_TRAFFIC_ACTION 0x07 +#define ECOMMUNITY_REDIRECT_VRF 0x08 +#define ECOMMUNITY_TRAFFIC_MARKING 0x09 +#define ECOMMUNITY_REDIRECT_IP_NH 0x00 +/* from IANA: bgp-extended-communities/bgp-extended-communities.xhtml + * 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect + */ +#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 0x0c +/* from draft-ietf-idr-flow-spec-v6-09 + * 0x0b Flow-spec Redirect to IPv6 + */ +#define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0b + +/* Low-order octet of the Extended Communities type field for EVPN types */ +#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 +#define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02 +#define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03 +#define ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION 0x06 +#define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d +#define ECOMMUNITY_EVPN_SUBTYPE_ND 0x08 + +#define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY 0x01 + +/* DF alg bits - only lower 5 bits are applicable */ +#define ECOMMUNITY_EVPN_SUBTYPE_DF_ALG_BITS 0x1f + +#define ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ND_OVERRIDE_FLAG 0x02 +#define ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG 0x04 + +#define ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG (1 << 0) /* single-active */ + +/* Low-order octet of the Extended Communities type field for OPAQUE types */ +#define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c + +/* Extended communities attribute string format. */ +#define ECOMMUNITY_FORMAT_ROUTE_MAP 0 +#define ECOMMUNITY_FORMAT_COMMUNITY_LIST 1 +#define ECOMMUNITY_FORMAT_DISPLAY 2 + +/* Extended Communities value is eight octet long. */ +#define ECOMMUNITY_SIZE 8 +#define IPV6_ECOMMUNITY_SIZE 20 + +/* Extended Community Origin Validation State */ +enum ecommunity_origin_validation_states { + ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID, + ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND, + ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID, + ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED +}; + +/* Extended Communities type flag. */ +#define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 + +/* Extended Community readable string length */ +#define ECOMMUNITY_STRLEN 64 + +/* Extended Communities attribute. */ +struct ecommunity { + /* Reference counter. */ + unsigned long refcnt; + + /* Size of Each Unit of Extended Communities attribute. + * to differentiate between IPv6 ext comm and ext comm + */ + uint8_t unit_size; + + /* Size of Extended Communities attribute. */ + uint32_t size; + + /* Extended Communities value. */ + uint8_t *val; + + /* Human readable format string. */ + char *str; + + /* Disable IEEE floating-point encoding for extended community */ + bool disable_ieee_floating; +}; + +struct ecommunity_as { + as_t as; + uint32_t val; +}; + +struct ecommunity_ip { + struct in_addr ip; + uint16_t val; +}; + +struct ecommunity_ip6 { + struct in6_addr ip; + uint16_t val; +}; + +/* Extended community value is eight octet. */ +struct ecommunity_val { + char val[ECOMMUNITY_SIZE]; +}; + +/* IPv6 Extended community value is eight octet. */ +struct ecommunity_val_ipv6 { + char val[IPV6_ECOMMUNITY_SIZE]; +}; + +#define ecom_length_size(X, Y) ((X)->size * (Y)) + +/* + * Encode BGP Route Target AS:nn. + */ +static inline void encode_route_target_as(as_t as, uint32_t val, + struct ecommunity_val *eval) +{ + eval->val[0] = ECOMMUNITY_ENCODE_AS; + eval->val[1] = ECOMMUNITY_ROUTE_TARGET; + eval->val[2] = (as >> 8) & 0xff; + eval->val[3] = as & 0xff; + eval->val[4] = (val >> 24) & 0xff; + eval->val[5] = (val >> 16) & 0xff; + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; +} + +/* + * Encode BGP Route Target IP:nn. + */ +static inline void encode_route_target_ip(struct in_addr ip, uint16_t val, + struct ecommunity_val *eval) +{ + eval->val[0] = ECOMMUNITY_ENCODE_IP; + eval->val[1] = ECOMMUNITY_ROUTE_TARGET; + memcpy(&eval->val[2], &ip, sizeof(struct in_addr)); + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; +} + +/* + * Encode BGP Route Target AS4:nn. + */ +static inline void encode_route_target_as4(as_t as, uint16_t val, + struct ecommunity_val *eval) +{ + eval->val[0] = ECOMMUNITY_ENCODE_AS4; + eval->val[1] = ECOMMUNITY_ROUTE_TARGET; + eval->val[2] = (as >> 24) & 0xff; + eval->val[3] = (as >> 16) & 0xff; + eval->val[4] = (as >> 8) & 0xff; + eval->val[5] = as & 0xff; + eval->val[6] = (val >> 8) & 0xff; + eval->val[7] = val & 0xff; +} + +/* Helper function to convert uint32 to IEEE-754 Floating Point */ +static uint32_t uint32_to_ieee_float_uint32(uint32_t u) +{ + union { + float r; + uint32_t d; + } f = {.r = (float)u}; + + return f.d; +} + +/* + * Encode BGP Link Bandwidth extended community + * bandwidth (bw) is in bytes-per-sec + */ +static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, + struct ecommunity_val *eval, + bool disable_ieee_floating) +{ + uint32_t bandwidth = + disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw); + + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_AS; + if (non_trans) + eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; + eval->val[1] = ECOMMUNITY_LINK_BANDWIDTH; + eval->val[2] = (as >> 8) & 0xff; + eval->val[3] = as & 0xff; + eval->val[4] = (bandwidth >> 24) & 0xff; + eval->val[5] = (bandwidth >> 16) & 0xff; + eval->val[6] = (bandwidth >> 8) & 0xff; + eval->val[7] = bandwidth & 0xff; +} + +static inline void encode_origin_validation_state(enum rpki_states state, + struct ecommunity_val *eval) +{ + enum ecommunity_origin_validation_states ovs_state = + ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED; + + switch (state) { + case RPKI_VALID: + ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID; + break; + case RPKI_NOTFOUND: + ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND; + break; + case RPKI_INVALID: + ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID; + break; + case RPKI_NOT_BEING_USED: + break; + } + + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS; + eval->val[1] = ECOMMUNITY_ORIGIN_VALIDATION_STATE; + eval->val[7] = ovs_state; +} + +extern void ecommunity_init(void); +extern void ecommunity_finish(void); +extern void ecommunity_free(struct ecommunity **); +extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short, + bool disable_ieee_floating); +extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, + unsigned short length, + bool disable_ieee_floating); +extern struct ecommunity *ecommunity_dup(struct ecommunity *); +extern struct ecommunity *ecommunity_merge(struct ecommunity *, + struct ecommunity *); +extern struct ecommunity *ecommunity_uniq_sort(struct ecommunity *); +extern struct ecommunity *ecommunity_intern(struct ecommunity *); +extern bool ecommunity_cmp(const void *arg1, const void *arg2); +extern void ecommunity_unintern(struct ecommunity **ecommunity); +extern unsigned int ecommunity_hash_make(const void *); +extern struct ecommunity *ecommunity_str2com(const char *, int, int); +extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type, + int keyword_included); +extern char *ecommunity_ecom2str(struct ecommunity *, int, int); +extern void ecommunity_strfree(char **s); +extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2); +extern bool ecommunity_match(const struct ecommunity *, + const struct ecommunity *); +extern char *ecommunity_str(struct ecommunity *); +extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *, + uint8_t, uint8_t); + +extern bool ecommunity_add_val(struct ecommunity *ecom, + struct ecommunity_val *eval, + bool unique, bool overwrite); +extern bool ecommunity_add_val_ipv6(struct ecommunity *ecom, + struct ecommunity_val_ipv6 *eval, + bool unique, bool overwrite); + +/* for vpn */ +extern struct ecommunity *ecommunity_new(void); +extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, + uint8_t subtype); +extern struct ecommunity *ecommunity_new(void); +extern bool ecommunity_del_val(struct ecommunity *ecom, + struct ecommunity_val *eval); +struct bgp_pbr_entry_action; +extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, + struct bgp_pbr_entry_action *api, + afi_t afi); + +extern void bgp_compute_aggregate_ecommunity( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); + +extern void bgp_compute_aggregate_ecommunity_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_compute_aggregate_ecommunity_val( + struct bgp_aggregate *aggregate); +extern void bgp_remove_ecommunity_from_aggregate( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_remove_ecomm_from_aggregate_hash( + struct bgp_aggregate *aggregate, + struct ecommunity *ecommunity); +extern void bgp_aggr_ecommunity_remove(void *arg); +extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, + uint32_t *bw); +extern struct ecommunity *ecommunity_replace_linkbw(as_t as, + struct ecommunity *ecom, + uint64_t cum_bw, + bool disable_ieee_floating); + +static inline void ecommunity_strip_rts(struct ecommunity *ecom) +{ + uint8_t subtype = ECOMMUNITY_ROUTE_TARGET; + + ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS, subtype); + ecommunity_strip(ecom, ECOMMUNITY_ENCODE_IP, subtype); + ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS4, subtype); +} +extern struct ecommunity * +ecommunity_add_origin_validation_state(enum rpki_states rpki_state, + struct ecommunity *ecom); +#endif /* _QUAGGA_BGP_ECOMMUNITY_H */ |