summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_ecommunity.h
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_ecommunity.h')
-rw-r--r--bgpd/bgp_ecommunity.h413
1 files changed, 413 insertions, 0 deletions
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
new file mode 100644
index 0000000..7dc04d2
--- /dev/null
+++ b/bgpd/bgp_ecommunity.h
@@ -0,0 +1,413 @@
+// 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
+#define ECOMMUNITY_COLOR 0x0b /* RFC9012 - color */
+
+/* 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
+
+/* Node Target Extended Communities */
+#define ECOMMUNITY_NODE_TARGET 0x09
+#define ECOMMUNITY_NODE_TARGET_RESERVED 0
+
+/* 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,
+ bool trans)
+{
+ eval->val[0] = ECOMMUNITY_ENCODE_AS;
+ if (!trans)
+ eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ 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,
+ bool trans)
+{
+ eval->val[0] = ECOMMUNITY_ENCODE_IP;
+ if (!trans)
+ eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ 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,
+ bool trans)
+{
+ eval->val[0] = ECOMMUNITY_ENCODE_AS4;
+ if (!trans)
+ eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+ 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;
+}
+
+static inline void encode_node_target(struct in_addr *node_id,
+ struct ecommunity_val *eval, bool trans)
+{
+ /*
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x01 or 0x41 | Sub-Type(0x09) | Target BGP Identifier |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Target BGP Identifier (cont.) | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ memset(eval, 0, sizeof(*eval));
+ eval->val[0] = ECOMMUNITY_ENCODE_IP;
+ if (!trans)
+ eval->val[0] |= ECOMMUNITY_ENCODE_IP_NON_TRANS;
+ eval->val[1] = ECOMMUNITY_NODE_TARGET;
+ memcpy(&eval->val[2], node_id, sizeof(*node_id));
+ eval->val[6] = ECOMMUNITY_NODE_TARGET_RESERVED;
+ eval->val[7] = ECOMMUNITY_NODE_TARGET_RESERVED;
+}
+
+/*
+ * Encode BGP Color extended community
+ * is's a transitive opaque Extended community (RFC 9012 4.3)
+ * flag is set to 0
+ * RFC 9012 14.10: No values have currently been registered.
+ * 4.3: this field MUST be set to zero by the originator
+ * and ignored by the receiver;
+ *
+ */
+static inline void encode_color(uint32_t color_id, struct ecommunity_val *eval)
+{
+ /*
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x03 | Sub-Type(0x0b) | Flags |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Color Value |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ memset(eval, 0, sizeof(*eval));
+ eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE;
+ eval->val[1] = ECOMMUNITY_COLOR;
+ eval->val[2] = 0x00;
+ eval->val[3] = 0x00;
+ eval->val[4] = (color_id >> 24) & 0xff;
+ eval->val[5] = (color_id >> 16) & 0xff;
+ eval->val[6] = (color_id >> 8) & 0xff;
+ eval->val[7] = color_id & 0xff;
+}
+
+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 *ecom);
+extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *,
+ uint8_t, uint8_t);
+
+extern uint32_t ecommunity_select_color(const struct ecommunity *ecom);
+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);
+
+extern bool soo_in_ecom(struct ecommunity *ecom, struct ecommunity *soo);
+
+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);
+extern struct ecommunity *ecommunity_add_node_target(struct in_addr *node_id,
+ struct ecommunity *old,
+ bool non_trans);
+extern bool ecommunity_node_target_match(struct ecommunity *ecomm,
+ struct in_addr *local_id);
+#endif /* _QUAGGA_BGP_ECOMMUNITY_H */