frr/bgpd/bgp_ecommunity.h

342 lines
11 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/* BGP Extended Communities Attribute.
* Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
*/
#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 */