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