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