]> git.proxmox.com Git - mirror_frr.git/blame - bgpd/bgp_evpn.c
bgpd: Additional check on presence of tag/label
[mirror_frr.git] / bgpd / bgp_evpn.c
CommitLineData
7ef5a232 1/* Ethernet-VPN Packet and vty Processing File
896014f4
DL
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 */
7ef5a232 20
7ef5a232
PG
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"
14c1a7bf 29#include "hash.h"
30#include "jhash.h"
31#include "bitfield.h"
7ef5a232
PG
32
33#include "bgpd/bgp_attr_evpn.h"
34#include "bgpd/bgpd.h"
35#include "bgpd/bgp_table.h"
36#include "bgpd/bgp_route.h"
37#include "bgpd/bgp_attr.h"
38#include "bgpd/bgp_mplsvpn.h"
9bedbb1e 39#include "bgpd/bgp_label.h"
7ef5a232 40#include "bgpd/bgp_evpn.h"
14c1a7bf 41#include "bgpd/bgp_evpn_private.h"
42#include "bgpd/bgp_ecommunity.h"
43
44/*
45 * Private functions.
46 */
47
48/*
49 * Make vni hash key.
50 */
51static unsigned int
52vni_hash_key_make(void *p)
53{
54 struct bgpevpn *vpn = p;
55 return (jhash_1word(vpn->vni, 0));
56}
57
58/*
59 * Comparison function for vni hash
60 */
61static int
62vni_hash_cmp (const void *p1, const void *p2)
63{
64 const struct bgpevpn *vpn1 = p1;
65 const struct bgpevpn *vpn2 = p2;
66
67 if (!vpn1 && !vpn2)
68 return 1;
69 if (!vpn1 || !vpn2)
70 return 0;
71 return(vpn1->vni == vpn2->vni);
72}
73
74/*
75 * Make import route target hash key.
76 */
77static unsigned int
78import_rt_hash_key_make (void *p)
79{
80 struct irt_node *irt = p;
81 char *pnt = irt->rt.val;
82 unsigned int key = 0;
83 int c=0;
84
85 key += pnt[c];
86 key += pnt[c + 1];
87 key += pnt[c + 2];
88 key += pnt[c + 3];
89 key += pnt[c + 4];
90 key += pnt[c + 5];
91 key += pnt[c + 6];
92 key += pnt[c + 7];
93
94 return (key);
95}
96
97/*
98 * Comparison function for import rt hash
99 */
100static int
101import_rt_hash_cmp (const void *p1, const void *p2)
102{
103 const struct irt_node *irt1 = p1;
104 const struct irt_node *irt2 = p2;
105
106 if (irt1 == NULL && irt2 == NULL)
107 return 1;
108
109 if (irt1 == NULL || irt2 == NULL)
110 return 0;
111
112 return(memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
113}
114
7724c0a1 115/*
116 * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled.
117 */
118static void
119cleanup_vni_on_disable (struct hash_backet *backet, struct bgp *bgp)
120{
121}
122
14c1a7bf 123/*
124 * Free a VNI entry; iterator function called during cleanup.
125 */
126static void
127free_vni_entry (struct hash_backet *backet, struct bgp *bgp)
128{
129}
130
131
132/*
133 * Public functions.
134 */
7ef5a232
PG
135
136int
4d0e6ece
PG
137bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
138 struct bgp_nlri *packet, int withdraw)
7ef5a232 139{
4d0e6ece
PG
140 u_char *pnt;
141 u_char *lim;
142 struct prefix p;
143 struct prefix_rd prd;
144 struct evpn_addr *p_evpn_p;
145 struct bgp_route_evpn evpn;
146 uint8_t route_type, route_length;
9bedbb1e 147 mpls_label_t label;
4d0e6ece
PG
148 u_int32_t addpath_id = 0;
149
150 /* Check peer status. */
151 if (peer->status != Established)
152 return 0;
153
154 /* Make prefix_rd */
155 prd.family = AF_UNSPEC;
156 prd.prefixlen = 64;
157
158 p_evpn_p = &p.u.prefix_evpn;
159 pnt = packet->nlri;
160 lim = pnt + packet->length;
161 while (pnt < lim) {
162 /* clear evpn structure */
163 memset(&evpn, 0, sizeof(evpn));
164
165 /* Clear prefix structure. */
166 memset(&p, 0, sizeof(struct prefix));
167 memset(&evpn.gw_ip, 0, sizeof(union gw_addr));
168 memset(&evpn.eth_s_id, 0, sizeof(struct eth_segment_id));
169
170 /* Fetch Route Type */
171 route_type = *pnt++;
172 route_length = *pnt++;
173 /* simply ignore. goto next route type if any */
174 if (route_type != EVPN_IP_PREFIX) {
175 if (pnt + route_length > lim) {
176 zlog_err
177 ("not enough bytes for New Route Type left in NLRI?");
178 return -1;
179 }
180 pnt += route_length;
181 continue;
182 }
183
184 /* Fetch RD */
185 if (pnt + 8 > lim) {
186 zlog_err("not enough bytes for RD left in NLRI?");
187 return -1;
188 }
189
190 /* Copy routing distinguisher to rd. */
191 memcpy(&prd.val, pnt, 8);
192 pnt += 8;
193
194 /* Fetch ESI */
195 if (pnt + 10 > lim) {
196 zlog_err("not enough bytes for ESI left in NLRI?");
197 return -1;
198 }
199 memcpy(&evpn.eth_s_id.val, pnt, 10);
200 pnt += 10;
201
202 /* Fetch Ethernet Tag */
203 if (pnt + 4 > lim) {
204 zlog_err("not enough bytes for Eth Tag left in NLRI?");
205 return -1;
206 }
207
208 if (route_type == EVPN_IP_PREFIX) {
209 p_evpn_p->route_type = route_type;
210 memcpy(&(p_evpn_p->eth_tag), pnt, 4);
211 p_evpn_p->eth_tag = ntohl(p_evpn_p->eth_tag);
212 pnt += 4;
213
214 /* Fetch IP prefix length. */
215 p_evpn_p->ip_prefix_length = *pnt++;
216
217 if (p_evpn_p->ip_prefix_length > 128) {
218 zlog_err("invalid prefixlen %d in EVPN NLRI?",
219 p.prefixlen);
220 return -1;
221 }
222 /* determine IPv4 or IPv6 prefix */
223 if (route_length - 4 - 10 - 8 -
224 3 /* label to be read */ >= 32) {
86f1ef44 225 SET_IPADDR_V6 (&p_evpn_p->ip);
226 memcpy(&(p_evpn_p->ip.ipaddr_v6), pnt, 16);
4d0e6ece
PG
227 pnt += 16;
228 memcpy(&evpn.gw_ip.ipv6, pnt, 16);
229 pnt += 16;
230 } else {
86f1ef44 231 SET_IPADDR_V4 (&p_evpn_p->ip);
232 memcpy(&(p_evpn_p->ip.ipaddr_v4), pnt, 4);
4d0e6ece
PG
233 pnt += 4;
234 memcpy(&evpn.gw_ip.ipv4, pnt, 4);
235 pnt += 4;
236 }
237 p.family = AFI_L2VPN;
86f1ef44 238 if (IS_IPADDR_V4(&p_evpn_p->ip))
4d0e6ece
PG
239 p.prefixlen =
240 (u_char) PREFIX_LEN_ROUTE_TYPE_5_IPV4;
241 else
242 p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
243 p.family = AF_ETHERNET;
244 }
245
246 /* Fetch Label */
9bedbb1e 247 if (pnt + BGP_LABEL_BYTES > lim) {
4d0e6ece
PG
248 zlog_err("not enough bytes for Label left in NLRI?");
249 return -1;
250 }
4d0e6ece 251
9bedbb1e
DW
252 memcpy(&label, pnt, BGP_LABEL_BYTES);
253 bgp_set_valid_label(&label);
254 pnt += BGP_LABEL_BYTES;
4d0e6ece
PG
255
256 if (!withdraw) {
257 bgp_update(peer, &p, addpath_id, attr, AFI_L2VPN,
258 SAFI_EVPN, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
9bedbb1e 259 &prd, &label, 0, &evpn);
4d0e6ece
PG
260 } else {
261 bgp_withdraw(peer, &p, addpath_id, attr, AFI_L2VPN,
262 SAFI_EVPN, ZEBRA_ROUTE_BGP,
9bedbb1e 263 BGP_ROUTE_NORMAL, &prd, &label, &evpn);
4d0e6ece 264 }
7ef5a232
PG
265 }
266
4d0e6ece
PG
267 /* Packet length consistency check. */
268 if (pnt != lim)
269 return -1;
270 return 0;
7ef5a232 271}
b18825eb
PG
272
273void
4d0e6ece
PG
274bgp_packet_mpattr_route_type_5(struct stream *s,
275 struct prefix *p, struct prefix_rd *prd,
9bedbb1e 276 mpls_label_t *label, struct attr *attr)
b18825eb 277{
4d0e6ece
PG
278 int len;
279 char temp[16];
280 struct evpn_addr *p_evpn_p;
281
282 memset(&temp, 0, 16);
283 if (p->family != AF_ETHERNET)
284 return;
285 p_evpn_p = &(p->u.prefix_evpn);
86f1ef44 286 if (IS_IPADDR_V4(&p_evpn_p->ip))
4d0e6ece
PG
287 len = 8; /* ipv4 */
288 else
289 len = 32; /* ipv6 */
290 stream_putc(s, EVPN_IP_PREFIX);
291 stream_putc(s,
292 8 /* RD */ + 10 /* ESI */ + 4 /* EthTag */ + 1 + len +
293 3 /* label */ );
294 stream_put(s, prd->val, 8);
295 if (attr && attr->extra)
296 stream_put(s, &(attr->extra->evpn_overlay.eth_s_id), 10);
297 else
298 stream_put(s, &temp, 10);
299 stream_putl(s, p_evpn_p->eth_tag);
300 stream_putc(s, p_evpn_p->ip_prefix_length);
86f1ef44 301 if (IS_IPADDR_V4(&p_evpn_p->ip))
302 stream_put_ipv4(s, p_evpn_p->ip.ipaddr_v4.s_addr);
4d0e6ece 303 else
86f1ef44 304 stream_put(s, &p_evpn_p->ip.ipaddr_v6, 16);
4d0e6ece 305 if (attr && attr->extra) {
86f1ef44 306 if (IS_IPADDR_V4(&p_evpn_p->ip))
4d0e6ece
PG
307 stream_put_ipv4(s,
308 attr->extra->evpn_overlay.gw_ip.ipv4.
309 s_addr);
310 else
311 stream_put(s, &(attr->extra->evpn_overlay.gw_ip.ipv6),
312 16);
313 } else {
86f1ef44 314 if (IS_IPADDR_V4(&p_evpn_p->ip))
4d0e6ece
PG
315 stream_put_ipv4(s, 0);
316 else
317 stream_put(s, &temp, 16);
318 }
319 if (label)
320 stream_put(s, label, 3);
321 else
322 stream_put3(s, 0);
323 return;
b18825eb 324}
14c1a7bf 325
7724c0a1 326/*
327 * Cleanup EVPN information on disable - Need to delete and withdraw
328 * EVPN routes from peers.
329 */
330void
331bgp_evpn_cleanup_on_disable (struct bgp *bgp)
332{
333 hash_iterate (bgp->vnihash,
334 (void (*) (struct hash_backet *, void *))
335 cleanup_vni_on_disable, bgp);
336}
337
14c1a7bf 338/*
339 * Cleanup EVPN information - invoked at the time of bgpd exit or when the
340 * BGP instance (default) is being freed.
341 */
342void
343bgp_evpn_cleanup (struct bgp *bgp)
344{
345 hash_iterate (bgp->vnihash,
346 (void (*) (struct hash_backet *, void *))
347 free_vni_entry, bgp);
348 hash_free (bgp->import_rt_hash);
349 bgp->import_rt_hash = NULL;
350 hash_free (bgp->vnihash);
351 bgp->vnihash = NULL;
352 bf_free (bgp->rd_idspace);
353}
354
355/*
356 * Initialization for EVPN
357 * Create
358 * VNI hash table
359 * hash for RT to VNI
360 * unique rd id space for auto derivation of RD for VNIs
361 */
362void
363bgp_evpn_init (struct bgp *bgp)
364{
365 bgp->vnihash = hash_create (vni_hash_key_make,
366 vni_hash_cmp,
367 "BGP VNI Hash");
368 bgp->import_rt_hash = hash_create (import_rt_hash_key_make,
369 import_rt_hash_cmp,
370 "BGP Import RT Hash");
371 bf_init (bgp->rd_idspace, UINT16_MAX);
372 /*assign 0th index in the bitfield, so that we start with id 1*/
373 bf_assign_zero_index (bgp->rd_idspace);
374}