]> git.proxmox.com Git - mirror_frr.git/blob - bgpd/bgp_attr_evpn.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / bgpd / bgp_attr_evpn.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Ethernet-VPN Attribute handling file
3 * Copyright (C) 2016 6WIND
4 */
5
6 #include <zebra.h>
7
8 #include "command.h"
9 #include "filter.h"
10 #include "prefix.h"
11 #include "log.h"
12 #include "memory.h"
13 #include "stream.h"
14 #include "vxlan.h"
15
16 #include "bgpd/bgpd.h"
17 #include "bgpd/bgp_attr.h"
18 #include "bgpd/bgp_route.h"
19 #include "bgpd/bgp_attr_evpn.h"
20 #include "bgpd/bgp_ecommunity.h"
21 #include "bgpd/bgp_evpn.h"
22 #include "bgpd/bgp_evpn_private.h"
23
24 bool bgp_route_evpn_same(const struct bgp_route_evpn *e1,
25 const struct bgp_route_evpn *e2)
26 {
27 return (e1->type == e2->type &&
28 !memcmp(&(e1->eth_s_id), &(e2->eth_s_id), sizeof(esi_t)) &&
29 !ipaddr_cmp(&(e1->gw_ip), &(e2->gw_ip)));
30 }
31
32 void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
33 {
34 struct ecommunity_val routermac_ecom;
35 struct ecommunity *ecomm = bgp_attr_get_ecommunity(attr);
36
37 memset(&routermac_ecom, 0, sizeof(routermac_ecom));
38 routermac_ecom.val[0] = ECOMMUNITY_ENCODE_EVPN;
39 routermac_ecom.val[1] = ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC;
40 memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
41 if (!ecomm) {
42 bgp_attr_set_ecommunity(attr, ecommunity_new());
43 ecomm = bgp_attr_get_ecommunity(attr);
44 }
45 ecommunity_add_val(ecomm, &routermac_ecom, false, false);
46 ecommunity_str(ecomm);
47 }
48
49 /* converts to an esi
50 * returns 1 on success, 0 otherwise
51 * format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
52 * if id is null, check only is done
53 */
54 bool str2esi(const char *str, esi_t *id)
55 {
56 unsigned int a[ESI_BYTES];
57 int i;
58
59 if (!str)
60 return false;
61 if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1,
62 a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9)
63 != ESI_BYTES) {
64 /* error in incoming str length */
65 return false;
66 }
67 /* valid mac address */
68 if (!id)
69 return true;
70 for (i = 0; i < ESI_BYTES; ++i)
71 id->val[i] = a[i] & 0xff;
72 return true;
73 }
74
75 char *ecom_mac2str(char *ecom_mac)
76 {
77 char *en;
78
79 en = ecom_mac;
80 en += 2;
81
82 return prefix_mac2str((struct ethaddr *)en, NULL, 0);
83 }
84
85 /* Fetch router-mac from extended community */
86 bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
87 {
88 uint32_t i = 0;
89 struct ecommunity *ecom;
90
91 ecom = bgp_attr_get_ecommunity(attr);
92 if (!ecom || !ecom->size)
93 return false;
94
95 /* If there is a router mac extended community, set RMAC in attr */
96 for (i = 0; i < ecom->size; i++) {
97 uint8_t *pnt = NULL;
98 uint8_t type = 0;
99 uint8_t sub_type = 0;
100
101 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
102 type = *pnt++;
103 sub_type = *pnt++;
104
105 if (!(type == ECOMMUNITY_ENCODE_EVPN
106 && sub_type == ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC))
107 continue;
108
109 memcpy(rmac, pnt, ETH_ALEN);
110 return true;
111 }
112 return false;
113 }
114
115 /*
116 * return true if attr contains default gw extended community
117 */
118 uint8_t bgp_attr_default_gw(struct attr *attr)
119 {
120 struct ecommunity *ecom;
121 uint32_t i;
122
123 ecom = bgp_attr_get_ecommunity(attr);
124 if (!ecom || !ecom->size)
125 return 0;
126
127 /* If there is a default gw extendd community return true otherwise
128 * return 0 */
129 for (i = 0; i < ecom->size; i++) {
130 uint8_t *pnt;
131 uint8_t type, sub_type;
132
133 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
134 type = *pnt++;
135 sub_type = *pnt++;
136
137 if ((type == ECOMMUNITY_ENCODE_OPAQUE
138 && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW))
139 return 1;
140 }
141
142 return 0;
143 }
144
145 /*
146 * Fetch and return the DF preference and algorithm from
147 * DF election extended community, if present, else 0.
148 */
149 uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
150 {
151 struct ecommunity *ecom;
152 uint32_t i;
153 uint16_t df_pref = 0;
154
155 *alg = EVPN_MH_DF_ALG_SERVICE_CARVING;
156 ecom = bgp_attr_get_ecommunity(attr);
157 if (!ecom || !ecom->size)
158 return 0;
159
160 for (i = 0; i < ecom->size; i++) {
161 uint8_t *pnt;
162 uint8_t type, sub_type;
163
164 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
165 type = *pnt++;
166 sub_type = *pnt++;
167 if (!(type == ECOMMUNITY_ENCODE_EVPN
168 && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DF_ELECTION))
169 continue;
170
171 *alg = (*pnt++) & ECOMMUNITY_EVPN_SUBTYPE_DF_ALG_BITS;
172
173 pnt += 3;
174 pnt = ptr_get_be16(pnt, &df_pref);
175 (void)pnt; /* consume value */
176 break;
177 }
178
179 return df_pref;
180 }
181
182 /*
183 * Fetch and return the sequence number from MAC Mobility extended
184 * community, if present, else 0.
185 */
186 uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
187 {
188 struct ecommunity *ecom;
189 uint32_t i;
190 uint8_t flags = 0;
191
192 ecom = bgp_attr_get_ecommunity(attr);
193 if (!ecom || !ecom->size)
194 return 0;
195
196 /* If there is a MAC Mobility extended community, return its
197 * sequence number.
198 * TODO: RFC is silent on handling of multiple MAC mobility extended
199 * communities for the same route. We will bail out upon the first
200 * one.
201 */
202 for (i = 0; i < ecom->size; i++) {
203 const uint8_t *pnt;
204 uint8_t type, sub_type;
205 uint32_t seq_num;
206
207 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
208 type = *pnt++;
209 sub_type = *pnt++;
210 if (!(type == ECOMMUNITY_ENCODE_EVPN
211 && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY))
212 continue;
213 flags = *pnt++;
214
215 if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY)
216 *sticky = 1;
217 else
218 *sticky = 0;
219
220 pnt++;
221 pnt = ptr_get_be32(pnt, &seq_num);
222 (void)pnt; /* consume value */
223 return seq_num;
224 }
225
226 return 0;
227 }
228
229 /*
230 * return true if attr contains router flag extended community
231 */
232 void bgp_attr_evpn_na_flag(struct attr *attr,
233 uint8_t *router_flag, bool *proxy)
234 {
235 struct ecommunity *ecom;
236 uint32_t i;
237 uint8_t val;
238
239 ecom = bgp_attr_get_ecommunity(attr);
240 if (!ecom || !ecom->size)
241 return;
242
243 /* If there is a evpn na extendd community set router_flag */
244 for (i = 0; i < ecom->size; i++) {
245 uint8_t *pnt;
246 uint8_t type, sub_type;
247
248 pnt = (ecom->val + (i * ECOMMUNITY_SIZE));
249 type = *pnt++;
250 sub_type = *pnt++;
251
252 if (type == ECOMMUNITY_ENCODE_EVPN &&
253 sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) {
254 val = *pnt++;
255
256 if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
257 *router_flag = 1;
258
259 if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG)
260 *proxy = true;
261
262 break;
263 }
264 }
265 }
266
267 /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */
268 extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
269 struct prefix *dst)
270 {
271 struct evpn_addr *p_evpn_p;
272 struct prefix p2;
273 struct prefix *src = &p2;
274
275 if (!dst || dst->family == 0)
276 return -1;
277 /* store initial prefix in src */
278 prefix_copy(src, dst);
279 memset(dst, 0, sizeof(struct prefix));
280 p_evpn_p = &(dst->u.prefix_evpn);
281 dst->family = AF_EVPN;
282 p_evpn_p->route_type = evpn_type;
283 if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
284 p_evpn_p->prefix_addr.eth_tag = eth_tag;
285 p_evpn_p->prefix_addr.ip_prefix_length = p2.prefixlen;
286 if (src->family == AF_INET) {
287 SET_IPADDR_V4(&p_evpn_p->prefix_addr.ip);
288 memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v4,
289 &src->u.prefix4,
290 sizeof(struct in_addr));
291 dst->prefixlen = (uint16_t)PREFIX_LEN_ROUTE_TYPE_5_IPV4;
292 } else {
293 SET_IPADDR_V6(&p_evpn_p->prefix_addr.ip);
294 memcpy(&p_evpn_p->prefix_addr.ip.ipaddr_v6,
295 &src->u.prefix6,
296 sizeof(struct in6_addr));
297 dst->prefixlen = (uint16_t)PREFIX_LEN_ROUTE_TYPE_5_IPV6;
298 }
299 } else
300 return -1;
301 return 0;
302 }