]>
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 | ||
c9a25614 DA |
104 | /* Node Target Extended Communities */ |
105 | #define ECOMMUNITY_NODE_TARGET 0x09 | |
106 | #define ECOMMUNITY_NODE_TARGET_RESERVED 0 | |
107 | ||
718e3744 | 108 | /* Extended Communities attribute. */ |
d62a17ae | 109 | struct ecommunity { |
110 | /* Reference counter. */ | |
111 | unsigned long refcnt; | |
718e3744 | 112 | |
9a659715 PG |
113 | /* Size of Each Unit of Extended Communities attribute. |
114 | * to differentiate between IPv6 ext comm and ext comm | |
115 | */ | |
c6423c31 | 116 | uint8_t unit_size; |
9a659715 | 117 | |
d62a17ae | 118 | /* Size of Extended Communities attribute. */ |
f6e07e1b | 119 | uint32_t size; |
718e3744 | 120 | |
d62a17ae | 121 | /* Extended Communities value. */ |
d7c0a89a | 122 | uint8_t *val; |
718e3744 | 123 | |
d62a17ae | 124 | /* Human readable format string. */ |
125 | char *str; | |
27aa23a4 DA |
126 | |
127 | /* Disable IEEE floating-point encoding for extended community */ | |
128 | bool disable_ieee_floating; | |
718e3744 | 129 | }; |
130 | ||
5a0ccebf QY |
131 | struct ecommunity_as { |
132 | as_t as; | |
133 | uint32_t val; | |
134 | }; | |
135 | ||
136 | struct ecommunity_ip { | |
137 | struct in_addr ip; | |
138 | uint16_t val; | |
139 | }; | |
140 | ||
9a659715 PG |
141 | struct ecommunity_ip6 { |
142 | struct in6_addr ip; | |
143 | uint16_t val; | |
144 | }; | |
145 | ||
718e3744 | 146 | /* Extended community value is eight octet. */ |
d62a17ae | 147 | struct ecommunity_val { |
148 | char val[ECOMMUNITY_SIZE]; | |
718e3744 | 149 | }; |
150 | ||
9a659715 PG |
151 | /* IPv6 Extended community value is eight octet. */ |
152 | struct ecommunity_val_ipv6 { | |
153 | char val[IPV6_ECOMMUNITY_SIZE]; | |
154 | }; | |
155 | ||
156 | #define ecom_length_size(X, Y) ((X)->size * (Y)) | |
157 | ||
c5900768 | 158 | /* |
159 | * Encode BGP Route Target AS:nn. | |
160 | */ | |
d7c0a89a | 161 | static inline void encode_route_target_as(as_t as, uint32_t val, |
8f2a51b7 DA |
162 | struct ecommunity_val *eval, |
163 | bool trans) | |
c5900768 | 164 | { |
d62a17ae | 165 | eval->val[0] = ECOMMUNITY_ENCODE_AS; |
8f2a51b7 DA |
166 | if (!trans) |
167 | eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; | |
d62a17ae | 168 | eval->val[1] = ECOMMUNITY_ROUTE_TARGET; |
169 | eval->val[2] = (as >> 8) & 0xff; | |
170 | eval->val[3] = as & 0xff; | |
171 | eval->val[4] = (val >> 24) & 0xff; | |
172 | eval->val[5] = (val >> 16) & 0xff; | |
173 | eval->val[6] = (val >> 8) & 0xff; | |
174 | eval->val[7] = val & 0xff; | |
c5900768 | 175 | } |
176 | ||
177 | /* | |
178 | * Encode BGP Route Target IP:nn. | |
179 | */ | |
8f2a51b7 DA |
180 | static inline void encode_route_target_ip(struct in_addr *ip, uint16_t val, |
181 | struct ecommunity_val *eval, | |
182 | bool trans) | |
c5900768 | 183 | { |
d62a17ae | 184 | eval->val[0] = ECOMMUNITY_ENCODE_IP; |
8f2a51b7 DA |
185 | if (!trans) |
186 | eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; | |
d62a17ae | 187 | eval->val[1] = ECOMMUNITY_ROUTE_TARGET; |
8f2a51b7 | 188 | memcpy(&eval->val[2], ip, sizeof(struct in_addr)); |
d62a17ae | 189 | eval->val[6] = (val >> 8) & 0xff; |
190 | eval->val[7] = val & 0xff; | |
c5900768 | 191 | } |
192 | ||
193 | /* | |
194 | * Encode BGP Route Target AS4:nn. | |
195 | */ | |
d7c0a89a | 196 | static inline void encode_route_target_as4(as_t as, uint16_t val, |
8f2a51b7 DA |
197 | struct ecommunity_val *eval, |
198 | bool trans) | |
c5900768 | 199 | { |
d62a17ae | 200 | eval->val[0] = ECOMMUNITY_ENCODE_AS4; |
8f2a51b7 DA |
201 | if (!trans) |
202 | eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; | |
d62a17ae | 203 | eval->val[1] = ECOMMUNITY_ROUTE_TARGET; |
204 | eval->val[2] = (as >> 24) & 0xff; | |
205 | eval->val[3] = (as >> 16) & 0xff; | |
206 | eval->val[4] = (as >> 8) & 0xff; | |
207 | eval->val[5] = as & 0xff; | |
208 | eval->val[6] = (val >> 8) & 0xff; | |
209 | eval->val[7] = val & 0xff; | |
c5900768 | 210 | } |
211 | ||
8bcaad3d DA |
212 | /* Helper function to convert uint32 to IEEE-754 Floating Point */ |
213 | static uint32_t uint32_to_ieee_float_uint32(uint32_t u) | |
214 | { | |
215 | union { | |
216 | float r; | |
217 | uint32_t d; | |
218 | } f = {.r = (float)u}; | |
219 | ||
220 | return f.d; | |
221 | } | |
222 | ||
ca9ac3ef | 223 | /* |
224 | * Encode BGP Link Bandwidth extended community | |
225 | * bandwidth (bw) is in bytes-per-sec | |
226 | */ | |
227 | static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans, | |
27aa23a4 DA |
228 | struct ecommunity_val *eval, |
229 | bool disable_ieee_floating) | |
ca9ac3ef | 230 | { |
27aa23a4 DA |
231 | uint32_t bandwidth = |
232 | disable_ieee_floating ? bw : uint32_to_ieee_float_uint32(bw); | |
8bcaad3d | 233 | |
ca9ac3ef | 234 | memset(eval, 0, sizeof(*eval)); |
235 | eval->val[0] = ECOMMUNITY_ENCODE_AS; | |
236 | if (non_trans) | |
237 | eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE; | |
238 | eval->val[1] = ECOMMUNITY_LINK_BANDWIDTH; | |
239 | eval->val[2] = (as >> 8) & 0xff; | |
240 | eval->val[3] = as & 0xff; | |
8bcaad3d DA |
241 | eval->val[4] = (bandwidth >> 24) & 0xff; |
242 | eval->val[5] = (bandwidth >> 16) & 0xff; | |
243 | eval->val[6] = (bandwidth >> 8) & 0xff; | |
244 | eval->val[7] = bandwidth & 0xff; | |
ca9ac3ef | 245 | } |
246 | ||
7b27cf7b DA |
247 | static inline void encode_origin_validation_state(enum rpki_states state, |
248 | struct ecommunity_val *eval) | |
249 | { | |
250 | enum ecommunity_origin_validation_states ovs_state = | |
251 | ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED; | |
252 | ||
253 | switch (state) { | |
254 | case RPKI_VALID: | |
255 | ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID; | |
256 | break; | |
257 | case RPKI_NOTFOUND: | |
258 | ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND; | |
259 | break; | |
260 | case RPKI_INVALID: | |
261 | ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID; | |
262 | break; | |
263 | case RPKI_NOT_BEING_USED: | |
264 | break; | |
265 | } | |
266 | ||
267 | memset(eval, 0, sizeof(*eval)); | |
268 | eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS; | |
269 | eval->val[1] = ECOMMUNITY_ORIGIN_VALIDATION_STATE; | |
270 | eval->val[7] = ovs_state; | |
271 | } | |
272 | ||
c9a25614 DA |
273 | static inline void encode_node_target(struct in_addr *node_id, |
274 | struct ecommunity_val *eval, bool trans) | |
275 | { | |
276 | /* | |
277 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
278 | * | 0x01 or 0x41 | Sub-Type(0x09) | Target BGP Identifier | | |
279 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
280 | * | Target BGP Identifier (cont.) | Reserved | | |
281 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
282 | */ | |
283 | memset(eval, 0, sizeof(*eval)); | |
284 | eval->val[0] = ECOMMUNITY_ENCODE_IP; | |
285 | if (!trans) | |
286 | eval->val[0] |= ECOMMUNITY_ENCODE_IP_NON_TRANS; | |
287 | eval->val[1] = ECOMMUNITY_NODE_TARGET; | |
288 | memcpy(&eval->val[2], node_id, sizeof(*node_id)); | |
289 | eval->val[6] = ECOMMUNITY_NODE_TARGET_RESERVED; | |
290 | eval->val[7] = ECOMMUNITY_NODE_TARGET_RESERVED; | |
291 | } | |
292 | ||
d62a17ae | 293 | extern void ecommunity_init(void); |
294 | extern void ecommunity_finish(void); | |
295 | extern void ecommunity_free(struct ecommunity **); | |
27aa23a4 DA |
296 | extern struct ecommunity *ecommunity_parse(uint8_t *, unsigned short, |
297 | bool disable_ieee_floating); | |
9a659715 | 298 | extern struct ecommunity *ecommunity_parse_ipv6(uint8_t *pnt, |
27aa23a4 DA |
299 | unsigned short length, |
300 | bool disable_ieee_floating); | |
d62a17ae | 301 | extern struct ecommunity *ecommunity_dup(struct ecommunity *); |
302 | extern struct ecommunity *ecommunity_merge(struct ecommunity *, | |
303 | struct ecommunity *); | |
304 | extern struct ecommunity *ecommunity_uniq_sort(struct ecommunity *); | |
305 | extern struct ecommunity *ecommunity_intern(struct ecommunity *); | |
74df8d6d | 306 | extern bool ecommunity_cmp(const void *arg1, const void *arg2); |
df7d4670 | 307 | extern void ecommunity_unintern(struct ecommunity **ecommunity); |
d8b87afe | 308 | extern unsigned int ecommunity_hash_make(const void *); |
d62a17ae | 309 | extern struct ecommunity *ecommunity_str2com(const char *, int, int); |
9a659715 PG |
310 | extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type, |
311 | int keyword_included); | |
d62a17ae | 312 | extern char *ecommunity_ecom2str(struct ecommunity *, int, int); |
c7ee6c35 | 313 | extern void ecommunity_strfree(char **s); |
2d7cdc5b | 314 | extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2); |
3dc339cd DA |
315 | extern bool ecommunity_match(const struct ecommunity *, |
316 | const struct ecommunity *); | |
d62a17ae | 317 | extern char *ecommunity_str(struct ecommunity *); |
318 | extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *, | |
319 | uint8_t, uint8_t); | |
9a659715 | 320 | |
3dc339cd | 321 | extern bool ecommunity_add_val(struct ecommunity *ecom, |
1207a5bc | 322 | struct ecommunity_val *eval, |
323 | bool unique, bool overwrite); | |
9a659715 PG |
324 | extern bool ecommunity_add_val_ipv6(struct ecommunity *ecom, |
325 | struct ecommunity_val_ipv6 *eval, | |
326 | bool unique, bool overwrite); | |
00d252cb | 327 | |
65efcfce | 328 | /* for vpn */ |
d62a17ae | 329 | extern struct ecommunity *ecommunity_new(void); |
3dc339cd DA |
330 | extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type, |
331 | uint8_t subtype); | |
d62a17ae | 332 | extern struct ecommunity *ecommunity_new(void); |
3dc339cd DA |
333 | extern bool ecommunity_del_val(struct ecommunity *ecom, |
334 | struct ecommunity_val *eval); | |
dacf6ec1 PG |
335 | struct bgp_pbr_entry_action; |
336 | extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval, | |
f01e580f PG |
337 | struct bgp_pbr_entry_action *api, |
338 | afi_t afi); | |
dacf6ec1 | 339 | |
5b820d9e NT |
340 | extern void bgp_compute_aggregate_ecommunity( |
341 | struct bgp_aggregate *aggregate, | |
342 | struct ecommunity *ecommunity); | |
4edd83f9 | 343 | |
344 | extern void bgp_compute_aggregate_ecommunity_hash( | |
345 | struct bgp_aggregate *aggregate, | |
346 | struct ecommunity *ecommunity); | |
347 | extern void bgp_compute_aggregate_ecommunity_val( | |
348 | struct bgp_aggregate *aggregate); | |
5b820d9e NT |
349 | extern void bgp_remove_ecommunity_from_aggregate( |
350 | struct bgp_aggregate *aggregate, | |
351 | struct ecommunity *ecommunity); | |
4edd83f9 | 352 | extern void bgp_remove_ecomm_from_aggregate_hash( |
353 | struct bgp_aggregate *aggregate, | |
354 | struct ecommunity *ecommunity); | |
5b820d9e | 355 | extern void bgp_aggr_ecommunity_remove(void *arg); |
d901dc13 | 356 | extern const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, |
357 | uint32_t *bw); | |
7b651a32 | 358 | extern struct ecommunity *ecommunity_replace_linkbw(as_t as, |
27aa23a4 DA |
359 | struct ecommunity *ecom, |
360 | uint64_t cum_bw, | |
361 | bool disable_ieee_floating); | |
e8bfa90e | 362 | |
363 | static inline void ecommunity_strip_rts(struct ecommunity *ecom) | |
364 | { | |
365 | uint8_t subtype = ECOMMUNITY_ROUTE_TARGET; | |
366 | ||
367 | ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS, subtype); | |
368 | ecommunity_strip(ecom, ECOMMUNITY_ENCODE_IP, subtype); | |
369 | ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS4, subtype); | |
370 | } | |
7b27cf7b DA |
371 | extern struct ecommunity * |
372 | ecommunity_add_origin_validation_state(enum rpki_states rpki_state, | |
373 | struct ecommunity *ecom); | |
c9a25614 DA |
374 | extern struct ecommunity *ecommunity_add_node_target(struct in_addr *node_id, |
375 | struct ecommunity *old, | |
376 | bool non_trans); | |
377 | extern bool ecommunity_node_target_match(struct ecommunity *ecomm, | |
378 | struct in_addr *local_id); | |
00d252cb | 379 | #endif /* _QUAGGA_BGP_ECOMMUNITY_H */ |