]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
718e3744 | 2 | /* BGP Extended Communities Attribute. |
896014f4 | 3 | * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> |
896014f4 | 4 | */ |
718e3744 | 5 | |
00d252cb | 6 | #ifndef _QUAGGA_BGP_ECOMMUNITY_H |
7 | #define _QUAGGA_BGP_ECOMMUNITY_H | |
8 | ||
5b820d9e | 9 | #include "bgpd/bgp_route.h" |
7b27cf7b | 10 | #include "bgpd/bgp_rpki.h" |
f4bd90c5 | 11 | #include "bgpd/bgpd.h" |
5b820d9e | 12 | |
7e3ebfd1 | 13 | /* Refer to rfc7153 for the IANA registry definitions. These are |
14 | * updated by other standards like rfc7674. | |
15 | */ | |
718e3744 | 16 | /* High-order octet of the Extended Communities type field. */ |
17 | #define ECOMMUNITY_ENCODE_AS 0x00 | |
18 | #define ECOMMUNITY_ENCODE_IP 0x01 | |
0b2aa3a0 | 19 | #define ECOMMUNITY_ENCODE_AS4 0x02 |
0014c301 | 20 | #define ECOMMUNITY_ENCODE_OPAQUE 0x03 |
e82202b7 | 21 | #define ECOMMUNITY_ENCODE_EVPN 0x06 |
b72220fc | 22 | #define ECOMMUNITY_ENCODE_REDIRECT_IP_NH 0x08 /* Flow Spec */ |
7e3ebfd1 | 23 | /* Generic Transitive Experimental */ |
24 | #define ECOMMUNITY_ENCODE_TRANS_EXP 0x80 | |
25 | ||
a8d72b61 PG |
26 | /* RFC7674 */ |
27 | #define ECOMMUNITY_EXTENDED_COMMUNITY_PART_2 0x81 | |
28 | #define ECOMMUNITY_EXTENDED_COMMUNITY_PART_3 0x82 | |
718e3744 | 29 | |
7e3ebfd1 | 30 | /* Non-transitive extended community types. */ |
31 | #define ECOMMUNITY_ENCODE_AS_NON_TRANS 0x40 | |
32 | #define ECOMMUNITY_ENCODE_IP_NON_TRANS 0x41 | |
33 | #define ECOMMUNITY_ENCODE_AS4_NON_TRANS 0x42 | |
34 | #define ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS 0x43 | |
35 | ||
0014c301 | 36 | /* Low-order octet of the Extended Communities type field. */ |
7e3ebfd1 | 37 | /* Note: This really depends on the high-order octet. This means that |
38 | * multiple definitions for the same value are possible. | |
39 | */ | |
7b27cf7b | 40 | #define ECOMMUNITY_ORIGIN_VALIDATION_STATE 0x00 |
718e3744 | 41 | #define ECOMMUNITY_ROUTE_TARGET 0x02 |
42 | #define ECOMMUNITY_SITE_ORIGIN 0x03 | |
650b0511 | 43 | #define ECOMMUNITY_LINK_BANDWIDTH 0x04 |
a8d72b61 PG |
44 | #define ECOMMUNITY_TRAFFIC_RATE 0x06 /* Flow Spec */ |
45 | #define ECOMMUNITY_TRAFFIC_ACTION 0x07 | |
46 | #define ECOMMUNITY_REDIRECT_VRF 0x08 | |
47 | #define ECOMMUNITY_TRAFFIC_MARKING 0x09 | |
48 | #define ECOMMUNITY_REDIRECT_IP_NH 0x00 | |
2551b26e PG |
49 | /* from IANA: bgp-extended-communities/bgp-extended-communities.xhtml |
50 | * 0x0c Flow-spec Redirect to IPv4 - draft-ietf-idr-flowspec-redirect | |
51 | */ | |
52 | #define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 0x0c | |
9a659715 PG |
53 | /* from draft-ietf-idr-flow-spec-v6-09 |
54 | * 0x0b Flow-spec Redirect to IPv6 | |
55 | */ | |
56 | #define ECOMMUNITY_FLOWSPEC_REDIRECT_IPV6 0x0b | |
718e3744 | 57 | |
128ea8ab | 58 | /* Low-order octet of the Extended Communities type field for EVPN types */ |
1e27ef50 PG |
59 | #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY 0x00 |
60 | #define ECOMMUNITY_EVPN_SUBTYPE_ESI_LABEL 0x01 | |
61 | #define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02 | |
62 | #define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03 | |
74e2bd89 | 63 | #define ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION 0x06 |
1e27ef50 | 64 | #define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d |
68e33151 | 65 | #define ECOMMUNITY_EVPN_SUBTYPE_ND 0x08 |
1e27ef50 | 66 | |
128ea8ab | 67 | #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY 0x01 |
7904e9fd | 68 | |
74e2bd89 AK |
69 | /* DF alg bits - only lower 5 bits are applicable */ |
70 | #define ECOMMUNITY_EVPN_SUBTYPE_DF_ALG_BITS 0x1f | |
71 | ||
7904e9fd AK |
72 | #define ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG 0x01 |
73 | #define ECOMMUNITY_EVPN_SUBTYPE_ND_OVERRIDE_FLAG 0x02 | |
74 | #define ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG 0x04 | |
128ea8ab | 75 | |
4248407b AK |
76 | #define ECOMMUNITY_EVPN_SUBTYPE_ESI_SA_FLAG (1 << 0) /* single-active */ |
77 | ||
0014c301 LB |
78 | /* Low-order octet of the Extended Communities type field for OPAQUE types */ |
79 | #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c | |
80 | ||
718e3744 | 81 | /* Extended communities attribute string format. */ |
82 | #define ECOMMUNITY_FORMAT_ROUTE_MAP 0 | |
83 | #define ECOMMUNITY_FORMAT_COMMUNITY_LIST 1 | |
84 | #define ECOMMUNITY_FORMAT_DISPLAY 2 | |
85 | ||
86 | /* Extended Communities value is eight octet long. */ | |
87 | #define ECOMMUNITY_SIZE 8 | |
c6423c31 | 88 | #define IPV6_ECOMMUNITY_SIZE 20 |
718e3744 | 89 | |
7b27cf7b DA |
90 | /* Extended Community Origin Validation State */ |
91 | enum ecommunity_origin_validation_states { | |
7b27cf7b DA |
92 | ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID, |
93 | ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND, | |
324e8b1f DA |
94 | ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID, |
95 | ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED | |
7b27cf7b DA |
96 | }; |
97 | ||
4372df71 | 98 | /* Extended Communities type flag. */ |
7c40bf39 | 99 | #define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40 |
4372df71 | 100 | |
f5e04c75 PR |
101 | /* Extended Community readable string length */ |
102 | #define ECOMMUNITY_STRLEN 64 | |
103 | ||
718e3744 | 104 | /* Extended Communities attribute. */ |
d62a17ae | 105 | struct ecommunity { |
106 | /* Reference counter. */ | |
107 | unsigned long refcnt; | |
718e3744 | 108 | |
9a659715 PG |
109 | /* Size of Each Unit of Extended Communities attribute. |
110 | * to differentiate between IPv6 ext comm and ext comm | |
111 | */ | |
c6423c31 | 112 | uint8_t unit_size; |
9a659715 | 113 | |
d62a17ae | 114 | /* Size of Extended Communities attribute. */ |
f6e07e1b | 115 | uint32_t size; |
718e3744 | 116 | |
d62a17ae | 117 | /* Extended Communities value. */ |
d7c0a89a | 118 | uint8_t *val; |
718e3744 | 119 | |
d62a17ae | 120 | /* Human readable format string. */ |
121 | char *str; | |
27aa23a4 DA |
122 | |
123 | /* Disable IEEE floating-point encoding for extended community */ | |
124 | bool disable_ieee_floating; | |
718e3744 | 125 | }; |
126 | ||
5a0ccebf QY |
127 | struct ecommunity_as { |
128 | as_t as; | |
129 | uint32_t val; | |
130 | }; | |
131 | ||
132 | struct ecommunity_ip { | |
133 | struct in_addr ip; | |
134 | uint16_t val; | |
135 | }; | |
136 | ||
9a659715 PG |
137 | struct ecommunity_ip6 { |
138 | struct in6_addr ip; | |
139 | uint16_t val; | |
140 | }; | |
141 | ||
718e3744 | 142 | /* Extended community value is eight octet. */ |
d62a17ae | 143 | struct ecommunity_val { |
144 | char val[ECOMMUNITY_SIZE]; | |
718e3744 | 145 | }; |
146 | ||
9a659715 PG |
147 | /* IPv6 Extended community value is eight octet. */ |
148 | struct ecommunity_val_ipv6 { | |
149 | char val[IPV6_ECOMMUNITY_SIZE]; | |
150 | }; | |
151 | ||
152 | #define ecom_length_size(X, Y) ((X)->size * (Y)) | |
153 | ||
c5900768 | 154 | /* |
155 | * Encode BGP Route Target AS:nn. | |
156 | */ | |
d7c0a89a | 157 | static inline void encode_route_target_as(as_t as, uint32_t val, |
d62a17ae | 158 | struct ecommunity_val *eval) |
c5900768 | 159 | { |
d62a17ae | 160 | eval->val[0] = ECOMMUNITY_ENCODE_AS; |
161 | eval->val[1] = ECOMMUNITY_ROUTE_TARGET; | |
162 | eval->val[2] = (as >> 8) & 0xff; | |
163 | eval->val[3] = as & 0xff; | |
164 | eval->val[4] = (val >> 24) & 0xff; | |
165 | eval->val[5] = (val >> 16) & 0xff; | |
166 | eval->val[6] = (val >> 8) & 0xff; | |
167 | eval->val[7] = val & 0xff; | |
c5900768 | 168 | } |
169 | ||
170 | /* | |
171 | * Encode BGP Route Target IP:nn. | |
172 | */ | |
d7c0a89a | 173 | static inline void encode_route_target_ip(struct in_addr ip, uint16_t val, |
d62a17ae | 174 | struct ecommunity_val *eval) |
c5900768 | 175 | { |
d62a17ae | 176 | eval->val[0] = ECOMMUNITY_ENCODE_IP; |
177 | eval->val[1] = ECOMMUNITY_ROUTE_TARGET; | |
178 | memcpy(&eval->val[2], &ip, sizeof(struct in_addr)); | |
179 | eval->val[6] = (val >> 8) & 0xff; | |
180 | eval->val[7] = val & 0xff; | |
c5900768 | 181 | } |
182 | ||
183 | /* | |
184 | * Encode BGP Route Target AS4:nn. | |
185 | */ | |
d7c0a89a | 186 | static inline void encode_route_target_as4(as_t as, uint16_t val, |
d62a17ae | 187 | struct ecommunity_val *eval) |
c5900768 | 188 | { |
d62a17ae | 189 | eval->val[0] = ECOMMUNITY_ENCODE_AS4; |
190 | eval->val[1] = ECOMMUNITY_ROUTE_TARGET; | |
191 | eval->val[2] = (as >> 24) & 0xff; | |
192 | eval->val[3] = (as >> 16) & 0xff; | |
193 | eval->val[4] = (as >> 8) & 0xff; | |
194 | eval->val[5] = as & 0xff; | |
195 | eval->val[6] = (val >> 8) & 0xff; | |
196 | eval->val[7] = val & 0xff; | |
c5900768 | 197 | } |
198 | ||
8bcaad3d DA |
199 | /* Helper function to convert uint32 to IEEE-754 Floating Point */ |
200 | static uint32_t uint32_to_ieee_float_uint32(uint32_t u) | |
201 | { | |
202 | union { | |
203 | float r; | |
204 | uint32_t d; | |
205 | } f = {.r = (float)u}; | |
206 | ||
207 | return f.d; | |
208 | } | |
209 | ||
ca9ac3ef | 210 | /* |
211 | * Encode BGP Link Bandwidth extended community | |
212 | * bandwidth (bw) is in bytes-per-sec | |
213 | */ | |
214 | static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, | |
27aa23a4 DA |
215 | struct ecommunity_val *eval, |
216 | bool disable_ieee_floating) | |
ca9ac3ef | 217 | { |
27aa23a4 DA |
218 | uint32_t bandwidth = |
219 | disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw); | |
8bcaad3d | 220 | |
ca9ac3ef | 221 | memset(eval, 0, sizeof(*eval)); |
222 | eval->val[0] = ECOMMUNITY_ENCODE_AS; | |
223 | if (non_trans) | |
224 | eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; | |
225 | eval->val[1] = ECOMMUNITY_LINK_BANDWIDTH; | |
226 | eval->val[2] = (as >> 8) & 0xff; | |
227 | eval->val[3] = as & 0xff; | |
8bcaad3d DA |
228 | eval->val[4] = (bandwidth >> 24) & 0xff; |
229 | eval->val[5] = (bandwidth >> 16) & 0xff; | |
230 | eval->val[6] = (bandwidth >> 8) & 0xff; | |
231 | eval->val[7] = bandwidth & 0xff; | |
ca9ac3ef | 232 | } |
233 | ||
7b27cf7b DA |
234 | static inline void encode_origin_validation_state(enum rpki_states state, |
235 | struct ecommunity_val *eval) | |
236 | { | |
237 | enum ecommunity_origin_validation_states ovs_state = | |
238 | ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED; | |
239 | ||
240 | switch (state) { | |
241 | case RPKI_VALID: | |
242 | ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID; | |
243 | break; | |
244 | case RPKI_NOTFOUND: | |
245 | ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND; | |
246 | break; | |
247 | case RPKI_INVALID: | |
248 | ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID; | |
249 | break; | |
250 | case RPKI_NOT_BEING_USED: | |
251 | break; | |
252 | } | |
253 | ||
254 | memset(eval, 0, sizeof(*eval)); | |
255 | eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS; | |
256 | eval->val[1] = ECOMMUNITY_ORIGIN_VALIDATION_STATE; | |
257 | eval->val[7] = ovs_state; | |
258 | } | |
259 | ||
d62a17ae | 260 | extern void ecommunity_init(void); |
261 | extern void ecommunity_finish(void); | |
262 | extern void ecommunity_free(struct ecommunity **); | |
27aa23a4 DA |
263 | extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short, |
264 | bool disable_ieee_floating); | |
9a659715 | 265 | extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, |
27aa23a4 DA |
266 | unsigned short length, |
267 | bool disable_ieee_floating); | |
d62a17ae | 268 | extern struct ecommunity *ecommunity_dup(struct ecommunity *); |
269 | extern struct ecommunity *ecommunity_merge(struct ecommunity *, | |
270 | struct ecommunity *); | |
271 | extern struct ecommunity *ecommunity_uniq_sort(struct ecommunity *); | |
272 | extern struct ecommunity *ecommunity_intern(struct ecommunity *); | |
74df8d6d | 273 | extern bool ecommunity_cmp(const void *arg1, const void *arg2); |
df7d4670 | 274 | extern void ecommunity_unintern(struct ecommunity **ecommunity); |
d8b87afe | 275 | extern unsigned int ecommunity_hash_make(const void *); |
d62a17ae | 276 | extern struct ecommunity *ecommunity_str2com(const char *, int, int); |
9a659715 PG |
277 | extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type, |
278 | int keyword_included); | |
d62a17ae | 279 | extern char *ecommunity_ecom2str(struct ecommunity *, int, int); |
c7ee6c35 | 280 | extern void ecommunity_strfree(char **s); |
2d7cdc5b | 281 | extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2); |
3dc339cd DA |
282 | extern bool ecommunity_match(const struct ecommunity *, |
283 | const struct ecommunity *); | |
d62a17ae | 284 | extern char *ecommunity_str(struct ecommunity *); |
285 | extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *, | |
286 | uint8_t, uint8_t); | |
9a659715 | 287 | |
3dc339cd | 288 | extern bool ecommunity_add_val(struct ecommunity *ecom, |
1207a5bc | 289 | struct ecommunity_val *eval, |
290 | bool unique, bool overwrite); | |
9a659715 PG |
291 | extern bool ecommunity_add_val_ipv6(struct ecommunity *ecom, |
292 | struct ecommunity_val_ipv6 *eval, | |
293 | bool unique, bool overwrite); | |
00d252cb | 294 | |
65efcfce | 295 | /* for vpn */ |
d62a17ae | 296 | extern struct ecommunity *ecommunity_new(void); |
3dc339cd DA |
297 | extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, |
298 | uint8_t subtype); | |
d62a17ae | 299 | extern struct ecommunity *ecommunity_new(void); |
3dc339cd DA |
300 | extern bool ecommunity_del_val(struct ecommunity *ecom, |
301 | struct ecommunity_val *eval); | |
dacf6ec1 PG |
302 | struct bgp_pbr_entry_action; |
303 | extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, | |
f01e580f PG |
304 | struct bgp_pbr_entry_action *api, |
305 | afi_t afi); | |
dacf6ec1 | 306 | |
5b820d9e NT |
307 | extern void bgp_compute_aggregate_ecommunity( |
308 | struct bgp_aggregate *aggregate, | |
309 | struct ecommunity *ecommunity); | |
4edd83f9 | 310 | |
311 | extern void bgp_compute_aggregate_ecommunity_hash( | |
312 | struct bgp_aggregate *aggregate, | |
313 | struct ecommunity *ecommunity); | |
314 | extern void bgp_compute_aggregate_ecommunity_val( | |
315 | struct bgp_aggregate *aggregate); | |
5b820d9e NT |
316 | extern void bgp_remove_ecommunity_from_aggregate( |
317 | struct bgp_aggregate *aggregate, | |
318 | struct ecommunity *ecommunity); | |
4edd83f9 | 319 | extern void bgp_remove_ecomm_from_aggregate_hash( |
320 | struct bgp_aggregate *aggregate, | |
321 | struct ecommunity *ecommunity); | |
5b820d9e | 322 | extern void bgp_aggr_ecommunity_remove(void *arg); |
d901dc13 | 323 | extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, |
324 | uint32_t *bw); | |
7b651a32 | 325 | extern struct ecommunity *ecommunity_replace_linkbw(as_t as, |
27aa23a4 DA |
326 | struct ecommunity *ecom, |
327 | uint64_t cum_bw, | |
328 | bool disable_ieee_floating); | |
e8bfa90e | 329 | |
330 | static inline void ecommunity_strip_rts(struct ecommunity *ecom) | |
331 | { | |
332 | uint8_t subtype = ECOMMUNITY_ROUTE_TARGET; | |
333 | ||
334 | ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS, subtype); | |
335 | ecommunity_strip(ecom, ECOMMUNITY_ENCODE_IP, subtype); | |
336 | ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS4, subtype); | |
337 | } | |
7b27cf7b DA |
338 | extern struct ecommunity * |
339 | ecommunity_add_origin_validation_state(enum rpki_states rpki_state, | |
340 | struct ecommunity *ecom); | |
00d252cb | 341 | #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ |