]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* MPLS-VPN |
896014f4 DL |
2 | * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra 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 | * GNU Zebra 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 | */ | |
718e3744 | 20 | |
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "prefix.h" | |
25 | #include "log.h" | |
26 | #include "memory.h" | |
27 | #include "stream.h" | |
3f9c7369 | 28 | #include "queue.h" |
039f3a34 | 29 | #include "filter.h" |
ddb5b488 | 30 | #include "mpls.h" |
b9c7bc5a PZ |
31 | #include "json.h" |
32 | #include "zclient.h" | |
9bedbb1e | 33 | |
718e3744 | 34 | #include "bgpd/bgpd.h" |
ddb5b488 | 35 | #include "bgpd/bgp_debug.h" |
14454c9f | 36 | #include "bgpd/bgp_errors.h" |
718e3744 | 37 | #include "bgpd/bgp_table.h" |
38 | #include "bgpd/bgp_route.h" | |
39 | #include "bgpd/bgp_attr.h" | |
9bedbb1e | 40 | #include "bgpd/bgp_label.h" |
718e3744 | 41 | #include "bgpd/bgp_mplsvpn.h" |
48a5452b | 42 | #include "bgpd/bgp_packet.h" |
3f227172 | 43 | #include "bgpd/bgp_vty.h" |
784d3a42 | 44 | #include "bgpd/bgp_vpn.h" |
ddb5b488 PZ |
45 | #include "bgpd/bgp_ecommunity.h" |
46 | #include "bgpd/bgp_zebra.h" | |
47 | #include "bgpd/bgp_nexthop.h" | |
960035b2 | 48 | #include "bgpd/bgp_nht.h" |
0a2f9ac1 | 49 | #include "bgpd/bgp_evpn.h" |
b72c9e14 | 50 | #include "bgpd/bgp_memory.h" |
718e3744 | 51 | |
49e5a4a0 | 52 | #ifdef ENABLE_BGP_VNC |
f8b6f499 | 53 | #include "bgpd/rfapi/rfapi_backend.h" |
65efcfce LB |
54 | #endif |
55 | ||
ddb5b488 PZ |
56 | /* |
57 | * Definitions and external declarations. | |
58 | */ | |
59 | extern struct zclient *zclient; | |
60 | ||
d62a17ae | 61 | extern int argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, |
62 | int *index, afi_t *afi) | |
3f227172 | 63 | { |
d62a17ae | 64 | int ret = 0; |
65 | if (argv_find(argv, argc, "vpnv4", index)) { | |
66 | ret = 1; | |
67 | if (afi) | |
68 | *afi = AFI_IP; | |
69 | } else if (argv_find(argv, argc, "vpnv6", index)) { | |
70 | ret = 1; | |
71 | if (afi) | |
72 | *afi = AFI_IP6; | |
73 | } | |
74 | return ret; | |
3f227172 PG |
75 | } |
76 | ||
d7c0a89a | 77 | uint32_t decode_label(mpls_label_t *label_pnt) |
718e3744 | 78 | { |
d7c0a89a QY |
79 | uint32_t l; |
80 | uint8_t *pnt = (uint8_t *)label_pnt; | |
718e3744 | 81 | |
d7c0a89a QY |
82 | l = ((uint32_t)*pnt++ << 12); |
83 | l |= (uint32_t)*pnt++ << 4; | |
84 | l |= (uint32_t)((*pnt & 0xf0) >> 4); | |
d62a17ae | 85 | return l; |
718e3744 | 86 | } |
87 | ||
d62a17ae | 88 | void encode_label(mpls_label_t label, mpls_label_t *label_pnt) |
65efcfce | 89 | { |
d7c0a89a | 90 | uint8_t *pnt = (uint8_t *)label_pnt; |
d62a17ae | 91 | if (pnt == NULL) |
92 | return; | |
13b7e7f0 DS |
93 | if (label == BGP_PREVENT_VRF_2_VRF_LEAK) { |
94 | *label_pnt = label; | |
95 | return; | |
96 | } | |
d62a17ae | 97 | *pnt++ = (label >> 12) & 0xff; |
98 | *pnt++ = (label >> 4) & 0xff; | |
99 | *pnt++ = ((label << 4) + 1) & 0xff; /* S=1 */ | |
65efcfce LB |
100 | } |
101 | ||
d62a17ae | 102 | int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, |
103 | struct bgp_nlri *packet) | |
718e3744 | 104 | { |
d62a17ae | 105 | struct prefix p; |
506dbcc8 QY |
106 | uint8_t psize = 0; |
107 | uint8_t prefixlen; | |
d7c0a89a | 108 | uint16_t type; |
d62a17ae | 109 | struct rd_as rd_as; |
110 | struct rd_ip rd_ip; | |
ef1af5e5 | 111 | struct prefix_rd prd = {0}; |
ddb5b488 | 112 | mpls_label_t label = {0}; |
d62a17ae | 113 | afi_t afi; |
114 | safi_t safi; | |
be92fc9f | 115 | bool addpath_capable; |
d7c0a89a | 116 | uint32_t addpath_id; |
506dbcc8 | 117 | int ret = 0; |
d62a17ae | 118 | |
d62a17ae | 119 | /* Make prefix_rd */ |
120 | prd.family = AF_UNSPEC; | |
121 | prd.prefixlen = 64; | |
122 | ||
506dbcc8 QY |
123 | struct stream *data = stream_new(packet->length); |
124 | stream_put(data, packet->nlri, packet->length); | |
d62a17ae | 125 | afi = packet->afi; |
126 | safi = packet->safi; | |
127 | addpath_id = 0; | |
128 | ||
be92fc9f | 129 | addpath_capable = bgp_addpath_encode_rx(peer, afi, safi); |
718e3744 | 130 | |
50905aa2 | 131 | #define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */ |
506dbcc8 | 132 | while (STREAM_READABLE(data) > 0) { |
d62a17ae | 133 | /* Clear prefix structure. */ |
134 | memset(&p, 0, sizeof(struct prefix)); | |
135 | ||
be92fc9f | 136 | if (addpath_capable) { |
506dbcc8 | 137 | STREAM_GET(&addpath_id, data, BGP_ADDPATH_ID_LEN); |
a3a850a1 | 138 | addpath_id = ntohl(addpath_id); |
506dbcc8 QY |
139 | } |
140 | ||
141 | if (STREAM_READABLE(data) < 1) { | |
142 | flog_err( | |
143 | EC_BGP_UPDATE_RCV, | |
144 | "%s [Error] Update packet error / VPN (truncated NLRI of size %u; no prefix length)", | |
145 | peer->host, packet->length); | |
146 | ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; | |
147 | goto done; | |
d62a17ae | 148 | } |
149 | ||
150 | /* Fetch prefix length. */ | |
506dbcc8 | 151 | STREAM_GETC(data, prefixlen); |
d62a17ae | 152 | p.family = afi2family(packet->afi); |
153 | psize = PSIZE(prefixlen); | |
154 | ||
155 | if (prefixlen < VPN_PREFIXLEN_MIN_BYTES * 8) { | |
af4c2728 | 156 | flog_err( |
e50f7cfd | 157 | EC_BGP_UPDATE_RCV, |
d62a17ae | 158 | "%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)", |
159 | peer->host, prefixlen); | |
506dbcc8 QY |
160 | ret = BGP_NLRI_PARSE_ERROR_PREFIX_LENGTH; |
161 | goto done; | |
d62a17ae | 162 | } |
163 | ||
164 | /* sanity check against packet data */ | |
506dbcc8 | 165 | if (STREAM_READABLE(data) < psize) { |
af4c2728 | 166 | flog_err( |
e50f7cfd | 167 | EC_BGP_UPDATE_RCV, |
d62a17ae | 168 | "%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)", |
506dbcc8 QY |
169 | peer->host, prefixlen, packet->length); |
170 | ret = BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW; | |
171 | goto done; | |
d62a17ae | 172 | } |
173 | ||
174 | /* sanity check against storage for the IP address portion */ | |
175 | if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t)sizeof(p.u)) { | |
af4c2728 | 176 | flog_err( |
e50f7cfd | 177 | EC_BGP_UPDATE_RCV, |
d62a17ae | 178 | "%s [Error] Update packet error / VPN (psize %d exceeds storage size %zu)", |
179 | peer->host, | |
180 | prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8, | |
181 | sizeof(p.u)); | |
506dbcc8 QY |
182 | ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; |
183 | goto done; | |
d62a17ae | 184 | } |
185 | ||
186 | /* Sanity check against max bitlen of the address family */ | |
187 | if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen(&p)) { | |
af4c2728 | 188 | flog_err( |
e50f7cfd | 189 | EC_BGP_UPDATE_RCV, |
d62a17ae | 190 | "%s [Error] Update packet error / VPN (psize %d exceeds family (%u) max byte len %u)", |
191 | peer->host, | |
192 | prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8, | |
193 | p.family, prefix_blen(&p)); | |
506dbcc8 QY |
194 | ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; |
195 | goto done; | |
d62a17ae | 196 | } |
197 | ||
198 | /* Copy label to prefix. */ | |
506dbcc8 QY |
199 | if (STREAM_READABLE(data) < BGP_LABEL_BYTES) { |
200 | flog_err( | |
201 | EC_BGP_UPDATE_RCV, | |
202 | "%s [Error] Update packet error / VPN (truncated NLRI of size %u; no label)", | |
203 | peer->host, packet->length); | |
204 | ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; | |
205 | goto done; | |
206 | } | |
207 | ||
208 | STREAM_GET(&label, data, BGP_LABEL_BYTES); | |
d62a17ae | 209 | bgp_set_valid_label(&label); |
210 | ||
211 | /* Copy routing distinguisher to rd. */ | |
506dbcc8 QY |
212 | if (STREAM_READABLE(data) < 8) { |
213 | flog_err( | |
214 | EC_BGP_UPDATE_RCV, | |
215 | "%s [Error] Update packet error / VPN (truncated NLRI of size %u; no RD)", | |
216 | peer->host, packet->length); | |
217 | ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; | |
218 | goto done; | |
219 | } | |
220 | STREAM_GET(&prd.val, data, 8); | |
d62a17ae | 221 | |
222 | /* Decode RD type. */ | |
506dbcc8 | 223 | type = decode_rd_type(prd.val); |
d62a17ae | 224 | |
225 | switch (type) { | |
226 | case RD_TYPE_AS: | |
506dbcc8 | 227 | decode_rd_as(&prd.val[2], &rd_as); |
d62a17ae | 228 | break; |
229 | ||
230 | case RD_TYPE_AS4: | |
506dbcc8 | 231 | decode_rd_as4(&prd.val[2], &rd_as); |
d62a17ae | 232 | break; |
233 | ||
234 | case RD_TYPE_IP: | |
506dbcc8 | 235 | decode_rd_ip(&prd.val[2], &rd_ip); |
d62a17ae | 236 | break; |
fe770c88 | 237 | |
49e5a4a0 | 238 | #ifdef ENABLE_BGP_VNC |
d62a17ae | 239 | case RD_TYPE_VNC_ETH: |
240 | break; | |
65efcfce LB |
241 | #endif |
242 | ||
d62a17ae | 243 | default: |
1c50c1c0 | 244 | flog_err(EC_BGP_UPDATE_RCV, "Unknown RD type %d", type); |
d62a17ae | 245 | break; /* just report */ |
246 | } | |
247 | ||
506dbcc8 QY |
248 | /* exclude label & RD */ |
249 | p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8; | |
250 | STREAM_GET(p.u.val, data, psize - VPN_PREFIXLEN_MIN_BYTES); | |
d62a17ae | 251 | |
252 | if (attr) { | |
253 | bgp_update(peer, &p, addpath_id, attr, packet->afi, | |
254 | SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, | |
b57ba6d2 | 255 | BGP_ROUTE_NORMAL, &prd, &label, 1, 0, NULL); |
d62a17ae | 256 | } else { |
257 | bgp_withdraw(peer, &p, addpath_id, attr, packet->afi, | |
258 | SAFI_MPLS_VPN, ZEBRA_ROUTE_BGP, | |
b57ba6d2 | 259 | BGP_ROUTE_NORMAL, &prd, &label, 1, NULL); |
d62a17ae | 260 | } |
261 | } | |
262 | /* Packet length consistency check. */ | |
506dbcc8 | 263 | if (STREAM_READABLE(data) != 0) { |
af4c2728 | 264 | flog_err( |
e50f7cfd | 265 | EC_BGP_UPDATE_RCV, |
72327cf3 | 266 | "%s [Error] Update packet error / VPN (%zu data remaining after parsing)", |
506dbcc8 | 267 | peer->host, STREAM_READABLE(data)); |
513386b5 | 268 | return BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; |
d62a17ae | 269 | } |
270 | ||
506dbcc8 QY |
271 | goto done; |
272 | ||
273 | stream_failure: | |
274 | flog_err( | |
275 | EC_BGP_UPDATE_RCV, | |
276 | "%s [Error] Update packet error / VPN (NLRI of size %u - length error)", | |
277 | peer->host, packet->length); | |
278 | ret = BGP_NLRI_PARSE_ERROR_PACKET_LENGTH; | |
279 | ||
280 | done: | |
281 | stream_free(data); | |
282 | return ret; | |
283 | ||
50905aa2 | 284 | #undef VPN_PREFIXLEN_MIN_BYTES |
718e3744 | 285 | } |
286 | ||
ddb5b488 PZ |
287 | /* |
288 | * This function informs zebra of the label this vrf sets on routes | |
289 | * leaked to VPN. Zebra should install this label in the kernel with | |
290 | * an action of "pop label and then use this vrf's IP FIB to route the PDU." | |
291 | * | |
292 | * Sending this vrf-label association is qualified by a) whether vrf->vpn | |
293 | * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list | |
294 | * are set) and b) whether vpn-policy label is set. | |
295 | * | |
296 | * If any of these conditions do not hold, then we send MPLS_LABEL_NONE | |
297 | * for this vrf, which zebra interprets to mean "delete this vrf-label | |
298 | * association." | |
299 | */ | |
300 | void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) | |
301 | { | |
302 | mpls_label_t label = MPLS_LABEL_NONE; | |
ddb5b488 PZ |
303 | int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); |
304 | ||
ddb5b488 PZ |
305 | if (bgp->vrf_id == VRF_UNKNOWN) { |
306 | if (debug) { | |
307 | zlog_debug( | |
3efd0893 | 308 | "%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label", |
960035b2 | 309 | __func__, bgp->name_pretty, afi2str(afi)); |
ddb5b488 PZ |
310 | } |
311 | return; | |
312 | } | |
313 | ||
314 | if (vpn_leak_to_vpn_active(bgp, afi, NULL)) { | |
315 | label = bgp->vpn_policy[afi].tovpn_label; | |
316 | } | |
317 | ||
318 | if (debug) { | |
319 | zlog_debug("%s: vrf %s: afi %s: setting label %d for vrf id %d", | |
960035b2 PZ |
320 | __func__, bgp->name_pretty, afi2str(afi), label, |
321 | bgp->vrf_id); | |
ddb5b488 PZ |
322 | } |
323 | ||
3f518d59 DS |
324 | if (label == BGP_PREVENT_VRF_2_VRF_LEAK) |
325 | label = MPLS_LABEL_NONE; | |
ddb5b488 PZ |
326 | zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP); |
327 | bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label; | |
328 | } | |
329 | ||
330 | /* | |
331 | * If zebra tells us vrf has become unconfigured, tell zebra not to | |
332 | * use this label to forward to the vrf anymore | |
333 | */ | |
334 | void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi) | |
335 | { | |
336 | mpls_label_t label = MPLS_LABEL_NONE; | |
337 | int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); | |
338 | ||
339 | if (bgp->vrf_id == VRF_UNKNOWN) { | |
340 | if (debug) { | |
341 | zlog_debug( | |
342 | "%s: vrf_id not set, can't delete zebra vrf label", | |
343 | __func__); | |
344 | } | |
345 | return; | |
346 | } | |
347 | ||
348 | if (debug) { | |
349 | zlog_debug("%s: deleting label for vrf %s (id=%d)", __func__, | |
960035b2 | 350 | bgp->name_pretty, bgp->vrf_id); |
ddb5b488 PZ |
351 | } |
352 | ||
353 | zclient_send_vrf_label(zclient, bgp->vrf_id, afi, label, ZEBRA_LSP_BGP); | |
354 | bgp->vpn_policy[afi].tovpn_zebra_vrf_label_last_sent = label; | |
355 | } | |
356 | ||
b72c9e14 HS |
357 | /* |
358 | * This function informs zebra of the srv6-function this vrf sets on routes | |
359 | * leaked to VPN. Zebra should install this srv6-function in the kernel with | |
360 | * an action of "End.DT4/6's IP FIB to route the PDU." | |
361 | */ | |
362 | void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi) | |
363 | { | |
364 | int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); | |
365 | enum seg6local_action_t act; | |
1bda3e62 | 366 | struct seg6local_context ctx = {}; |
b72c9e14 HS |
367 | struct in6_addr *tovpn_sid = NULL; |
368 | struct in6_addr *tovpn_sid_ls = NULL; | |
369 | struct vrf *vrf; | |
370 | char buf[256] = {0}; | |
371 | ||
372 | if (bgp->vrf_id == VRF_UNKNOWN) { | |
373 | if (debug) | |
7de4c885 | 374 | zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label", |
b72c9e14 HS |
375 | __func__, bgp->name_pretty, afi2str(afi)); |
376 | return; | |
377 | } | |
378 | ||
379 | tovpn_sid = bgp->vpn_policy[afi].tovpn_sid; | |
380 | if (!tovpn_sid) { | |
381 | if (debug) | |
382 | zlog_debug("%s: vrf %s: afi %s: sid not set", __func__, | |
383 | bgp->name_pretty, afi2str(afi)); | |
384 | return; | |
385 | } | |
386 | ||
387 | if (debug) { | |
388 | inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf)); | |
389 | zlog_debug("%s: vrf %s: afi %s: setting sid %s for vrf id %d", | |
390 | __func__, bgp->name_pretty, afi2str(afi), buf, | |
391 | bgp->vrf_id); | |
392 | } | |
393 | ||
394 | vrf = vrf_lookup_by_id(bgp->vrf_id); | |
395 | if (!vrf) | |
396 | return; | |
397 | ||
398 | ctx.table = vrf->data.l.table_id; | |
399 | act = afi == AFI_IP ? ZEBRA_SEG6_LOCAL_ACTION_END_DT4 | |
400 | : ZEBRA_SEG6_LOCAL_ACTION_END_DT6; | |
401 | zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx); | |
402 | ||
403 | tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); | |
404 | *tovpn_sid_ls = *tovpn_sid; | |
405 | bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls; | |
406 | } | |
407 | ||
408 | /* | |
409 | * If zebra tells us vrf has become unconfigured, tell zebra not to | |
410 | * use this srv6-function to forward to the vrf anymore | |
411 | */ | |
412 | void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi) | |
413 | { | |
414 | int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); | |
415 | ||
416 | if (bgp->vrf_id == VRF_UNKNOWN) { | |
417 | if (debug) | |
7de4c885 | 418 | zlog_debug("%s: vrf %s: afi %s: vrf_id not set, can't set zebra vrf label", |
b72c9e14 HS |
419 | __func__, bgp->name_pretty, afi2str(afi)); |
420 | return; | |
421 | } | |
422 | ||
423 | if (debug) | |
424 | zlog_debug("%s: deleting sid for vrf %s afi (id=%d)", __func__, | |
425 | bgp->name_pretty, bgp->vrf_id); | |
426 | ||
427 | zclient_send_localsid(zclient, | |
428 | bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent, | |
429 | bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC, NULL); | |
430 | XFREE(MTYPE_BGP_SRV6_SID, | |
431 | bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent); | |
432 | } | |
433 | ||
e70e9f8e PZ |
434 | int vpn_leak_label_callback( |
435 | mpls_label_t label, | |
436 | void *labelid, | |
437 | bool allocated) | |
438 | { | |
439 | struct vpn_policy *vp = (struct vpn_policy *)labelid; | |
440 | int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); | |
441 | ||
442 | if (debug) | |
443 | zlog_debug("%s: label=%u, allocated=%d", | |
444 | __func__, label, allocated); | |
445 | ||
446 | if (!allocated) { | |
447 | /* | |
448 | * previously-allocated label is now invalid | |
449 | */ | |
450 | if (CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO) && | |
451 | (vp->tovpn_label != MPLS_LABEL_NONE)) { | |
452 | ||
453 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, | |
454 | vp->afi, bgp_get_default(), vp->bgp); | |
455 | vp->tovpn_label = MPLS_LABEL_NONE; | |
456 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, | |
457 | vp->afi, bgp_get_default(), vp->bgp); | |
458 | } | |
459 | return 0; | |
460 | } | |
461 | ||
462 | /* | |
463 | * New label allocation | |
464 | */ | |
465 | if (!CHECK_FLAG(vp->flags, BGP_VPN_POLICY_TOVPN_LABEL_AUTO)) { | |
466 | ||
467 | /* | |
468 | * not currently configured for auto label, reject allocation | |
469 | */ | |
470 | return -1; | |
471 | } | |
472 | ||
473 | if (vp->tovpn_label != MPLS_LABEL_NONE) { | |
474 | if (label == vp->tovpn_label) { | |
475 | /* already have same label, accept but do nothing */ | |
476 | return 0; | |
477 | } | |
478 | /* Shouldn't happen: different label allocation */ | |
e50f7cfd | 479 | flog_err(EC_BGP_LABEL, |
1c50c1c0 QY |
480 | "%s: %s had label %u but got new assignment %u", |
481 | __func__, vp->bgp->name_pretty, vp->tovpn_label, | |
482 | label); | |
e70e9f8e PZ |
483 | /* use new one */ |
484 | } | |
485 | ||
486 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, | |
487 | vp->afi, bgp_get_default(), vp->bgp); | |
488 | vp->tovpn_label = label; | |
489 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, | |
490 | vp->afi, bgp_get_default(), vp->bgp); | |
491 | ||
492 | return 0; | |
493 | } | |
494 | ||
b72c9e14 HS |
495 | static void sid_register(struct bgp *bgp, const struct in6_addr *sid, |
496 | const char *locator_name) | |
497 | { | |
498 | struct bgp_srv6_function *func; | |
499 | func = XCALLOC(MTYPE_BGP_SRV6_FUNCTION, | |
500 | sizeof(struct bgp_srv6_function)); | |
501 | func->sid = *sid; | |
502 | snprintf(func->locator_name, sizeof(func->locator_name), | |
503 | "%s", locator_name); | |
504 | listnode_add(bgp->srv6_functions, func); | |
505 | } | |
506 | ||
507 | static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid) | |
508 | { | |
509 | struct listnode *node; | |
510 | struct bgp_srv6_function *func; | |
7de4c885 | 511 | |
b72c9e14 HS |
512 | for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) |
513 | if (sid_same(&func->sid, sid)) | |
514 | return true; | |
515 | return false; | |
516 | } | |
517 | ||
7de4c885 HS |
518 | /* |
519 | * if index != 0: try to allocate as index-mode | |
520 | * else: try to allocate as auto-mode | |
521 | */ | |
a45cd34e | 522 | static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index, |
921c7e77 | 523 | struct in6_addr *sid_locator) |
b72c9e14 HS |
524 | { |
525 | struct listnode *node; | |
526 | struct prefix_ipv6 *chunk; | |
527 | struct in6_addr sid_buf; | |
528 | bool alloced = false; | |
73e770b7 | 529 | int label = 0; |
b72c9e14 | 530 | |
921c7e77 | 531 | if (!bgp || !sid_locator) |
b72c9e14 HS |
532 | return false; |
533 | ||
534 | for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) { | |
921c7e77 | 535 | *sid_locator = chunk->prefix; |
b72c9e14 HS |
536 | sid_buf = chunk->prefix; |
537 | if (index != 0) { | |
a45cd34e RS |
538 | label = index << 12; |
539 | transpose_sid(&sid_buf, label, 64, 16); | |
b72c9e14 HS |
540 | if (sid_exist(bgp, &sid_buf)) |
541 | return false; | |
542 | alloced = true; | |
543 | break; | |
7de4c885 HS |
544 | } |
545 | ||
546 | for (size_t i = 1; i < 255; i++) { | |
a45cd34e RS |
547 | label = i << 12; |
548 | transpose_sid(&sid_buf, label, 64, 16); | |
7de4c885 HS |
549 | if (sid_exist(bgp, &sid_buf)) |
550 | continue; | |
551 | alloced = true; | |
552 | break; | |
b72c9e14 HS |
553 | } |
554 | } | |
555 | ||
556 | if (!alloced) | |
a45cd34e | 557 | return 0; |
b72c9e14 HS |
558 | |
559 | sid_register(bgp, &sid_buf, bgp->srv6_locator_name); | |
a45cd34e | 560 | return label; |
b72c9e14 HS |
561 | } |
562 | ||
563 | void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi) | |
564 | { | |
565 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
b72c9e14 | 566 | char buf[256]; |
921c7e77 | 567 | struct in6_addr *tovpn_sid, *tovpn_sid_locator; |
a45cd34e | 568 | uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label; |
b72c9e14 HS |
569 | bool tovpn_sid_auto = false; |
570 | ||
571 | if (debug) | |
572 | zlog_debug("%s: try to allocate new SID for vrf %s: afi %s", | |
573 | __func__, bgp_vrf->name_pretty, afi2str(afi)); | |
574 | ||
575 | /* skip when tovpn sid is already allocated on vrf instance */ | |
576 | if (bgp_vrf->vpn_policy[afi].tovpn_sid) | |
577 | return; | |
578 | ||
7de4c885 HS |
579 | /* |
580 | * skip when bgp vpn instance ins't allocated | |
581 | * or srv6 locator chunk isn't allocated | |
582 | */ | |
c0d950a0 | 583 | if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks) |
b72c9e14 HS |
584 | return; |
585 | ||
586 | tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index; | |
587 | tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, | |
588 | BGP_VPN_POLICY_TOVPN_SID_AUTO); | |
589 | ||
590 | /* skip when VPN isn't configured on vrf-instance */ | |
591 | if (tovpn_sid_index == 0 && !tovpn_sid_auto) | |
592 | return; | |
593 | ||
594 | /* check invalid case both configured index and auto */ | |
f7cafbb7 | 595 | if (tovpn_sid_index != 0 && tovpn_sid_auto) { |
b72c9e14 HS |
596 | zlog_err("%s: index-mode and auto-mode both selected. ignored.", |
597 | __func__); | |
598 | return; | |
599 | } | |
600 | ||
921c7e77 RS |
601 | tovpn_sid_locator = |
602 | XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); | |
a45cd34e | 603 | tovpn_sid_transpose_label = |
921c7e77 | 604 | alloc_new_sid(bgp_vpn, tovpn_sid_index, tovpn_sid_locator); |
a45cd34e | 605 | if (tovpn_sid_transpose_label == 0) { |
b72c9e14 HS |
606 | zlog_debug("%s: not allocated new sid for vrf %s: afi %s", |
607 | __func__, bgp_vrf->name_pretty, afi2str(afi)); | |
608 | return; | |
609 | } | |
610 | ||
921c7e77 RS |
611 | tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr)); |
612 | *tovpn_sid = *tovpn_sid_locator; | |
613 | transpose_sid(tovpn_sid, tovpn_sid_transpose_label, | |
614 | BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET, | |
615 | BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH); | |
616 | ||
b72c9e14 | 617 | if (debug) { |
921c7e77 | 618 | inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf)); |
b72c9e14 HS |
619 | zlog_debug("%s: new sid %s allocated for vrf %s: afi %s", |
620 | __func__, buf, bgp_vrf->name_pretty, | |
621 | afi2str(afi)); | |
622 | } | |
921c7e77 RS |
623 | |
624 | bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid; | |
625 | bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator; | |
a45cd34e RS |
626 | bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = |
627 | tovpn_sid_transpose_label; | |
b72c9e14 HS |
628 | } |
629 | ||
a45cd34e RS |
630 | void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset, |
631 | uint8_t len) | |
632 | { | |
633 | for (uint8_t idx = 0; idx < len; idx++) { | |
634 | uint8_t tidx = offset + idx; | |
635 | sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); | |
636 | if (label >> (19 - idx) & 0x1) | |
637 | sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); | |
638 | } | |
639 | } | |
640 | ||
3dc339cd | 641 | static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2) |
ddb5b488 | 642 | { |
f6e07e1b | 643 | uint32_t i, j; |
ddb5b488 PZ |
644 | |
645 | if (!e1 || !e2) | |
3dc339cd | 646 | return false; |
ddb5b488 PZ |
647 | for (i = 0; i < e1->size; ++i) { |
648 | for (j = 0; j < e2->size; ++j) { | |
9a659715 PG |
649 | if (!memcmp(e1->val + (i * e1->unit_size), |
650 | e2->val + (j * e2->unit_size), | |
651 | e1->unit_size)) { | |
ddb5b488 | 652 | |
3dc339cd | 653 | return true; |
ddb5b488 PZ |
654 | } |
655 | } | |
656 | } | |
3dc339cd | 657 | return false; |
ddb5b488 PZ |
658 | } |
659 | ||
40381db7 | 660 | static bool labels_same(struct bgp_path_info *bpi, mpls_label_t *label, |
4b7e6066 | 661 | uint32_t n) |
e37fb4bf PZ |
662 | { |
663 | uint32_t i; | |
664 | ||
40381db7 | 665 | if (!bpi->extra) { |
e37fb4bf PZ |
666 | if (!n) |
667 | return true; | |
668 | else | |
669 | return false; | |
670 | } | |
671 | ||
40381db7 | 672 | if (n != bpi->extra->num_labels) |
e37fb4bf PZ |
673 | return false; |
674 | ||
675 | for (i = 0; i < n; ++i) { | |
40381db7 | 676 | if (label[i] != bpi->extra->label[i]) |
e37fb4bf PZ |
677 | return false; |
678 | } | |
679 | return true; | |
680 | } | |
681 | ||
682 | /* | |
683 | * make encoded route labels match specified encoded label set | |
684 | */ | |
40381db7 | 685 | static void setlabels(struct bgp_path_info *bpi, |
4b7e6066 DS |
686 | mpls_label_t *label, /* array of labels */ |
687 | uint32_t num_labels) | |
e37fb4bf PZ |
688 | { |
689 | if (num_labels) | |
690 | assert(label); | |
691 | assert(num_labels <= BGP_MAX_LABELS); | |
692 | ||
693 | if (!num_labels) { | |
40381db7 DS |
694 | if (bpi->extra) |
695 | bpi->extra->num_labels = 0; | |
e37fb4bf PZ |
696 | return; |
697 | } | |
698 | ||
40381db7 | 699 | struct bgp_path_info_extra *extra = bgp_path_info_extra_get(bpi); |
e37fb4bf PZ |
700 | uint32_t i; |
701 | ||
702 | for (i = 0; i < num_labels; ++i) { | |
703 | extra->label[i] = label[i]; | |
704 | if (!bgp_is_valid_label(&label[i])) { | |
705 | bgp_set_valid_label(&extra->label[i]); | |
706 | } | |
707 | } | |
708 | extra->num_labels = num_labels; | |
709 | } | |
710 | ||
dbcf19b8 HS |
711 | /* |
712 | * make encoded route SIDs match specified encoded sid set | |
713 | */ | |
714 | static void setsids(struct bgp_path_info *bpi, | |
715 | struct in6_addr *sid, | |
716 | uint32_t num_sids) | |
717 | { | |
718 | uint32_t i; | |
719 | struct bgp_path_info_extra *extra; | |
720 | ||
721 | if (num_sids) | |
722 | assert(sid); | |
723 | assert(num_sids <= BGP_MAX_SIDS); | |
724 | ||
725 | if (!num_sids) { | |
726 | if (bpi->extra) | |
727 | bpi->extra->num_sids = 0; | |
728 | return; | |
729 | } | |
730 | ||
731 | extra = bgp_path_info_extra_get(bpi); | |
7de4c885 | 732 | for (i = 0; i < num_sids; i++) |
16f3db2d | 733 | memcpy(&extra->sid[i].sid, &sid[i], sizeof(struct in6_addr)); |
dbcf19b8 HS |
734 | extra->num_sids = num_sids; |
735 | } | |
736 | ||
d79ff732 HS |
737 | static void unsetsids(struct bgp_path_info *bpi) |
738 | { | |
739 | struct bgp_path_info_extra *extra; | |
740 | ||
741 | extra = bgp_path_info_extra_get(bpi); | |
742 | extra->num_sids = 0; | |
743 | memset(extra->sid, 0, sizeof(extra->sid)); | |
744 | } | |
745 | ||
ddb5b488 | 746 | /* |
18ee8310 | 747 | * returns pointer to new bgp_path_info upon success |
ddb5b488 | 748 | */ |
4b7e6066 DS |
749 | static struct bgp_path_info * |
750 | leak_update(struct bgp *bgp, /* destination bgp instance */ | |
9bcb3eef | 751 | struct bgp_dest *bn, struct attr *new_attr, /* already interned */ |
40381db7 | 752 | afi_t afi, safi_t safi, struct bgp_path_info *source_bpi, |
4b7e6066 DS |
753 | mpls_label_t *label, uint32_t num_labels, void *parent, |
754 | struct bgp *bgp_orig, struct prefix *nexthop_orig, | |
755 | int nexthop_self_flag, int debug) | |
ddb5b488 | 756 | { |
9bcb3eef | 757 | const struct prefix *p = bgp_dest_get_prefix(bn); |
40381db7 DS |
758 | struct bgp_path_info *bpi; |
759 | struct bgp_path_info *bpi_ultimate; | |
4b7e6066 | 760 | struct bgp_path_info *new; |
16f3db2d | 761 | struct bgp_path_info_extra *extra; |
dbcf19b8 | 762 | uint32_t num_sids = 0; |
7de4c885 | 763 | |
dbcf19b8 HS |
764 | if (new_attr->srv6_l3vpn || new_attr->srv6_vpn) |
765 | num_sids = 1; | |
766 | ||
b54892e0 DS |
767 | if (debug) |
768 | zlog_debug( | |
56ca3b5b | 769 | "%s: entry: leak-to=%s, p=%pBD, type=%d, sub_type=%d", |
b54892e0 DS |
770 | __func__, bgp->name_pretty, bn, source_bpi->type, |
771 | source_bpi->sub_type); | |
ddb5b488 | 772 | |
f46d45c1 PZ |
773 | /* |
774 | * Routes that are redistributed into BGP from zebra do not get | |
775 | * nexthop tracking. However, if those routes are subsequently | |
776 | * imported to other RIBs within BGP, the leaked routes do not | |
777 | * carry the original BGP_ROUTE_REDISTRIBUTE sub_type. Therefore, | |
778 | * in order to determine if the route we are currently leaking | |
779 | * should have nexthop tracking, we must find the ultimate | |
780 | * parent so we can check its sub_type. | |
781 | * | |
40381db7 | 782 | * As of now, source_bpi may at most be a second-generation route |
f46d45c1 PZ |
783 | * (only one hop back to ultimate parent for vrf-vpn-vrf scheme). |
784 | * Using a loop here supports more complex intra-bgp import-export | |
785 | * schemes that could be implemented in the future. | |
3bd70bf8 | 786 | * |
f46d45c1 | 787 | */ |
da0c0ef7 | 788 | bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); |
f46d45c1 | 789 | |
ddb5b488 PZ |
790 | /* |
791 | * match parent | |
792 | */ | |
9bcb3eef | 793 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { |
40381db7 | 794 | if (bpi->extra && bpi->extra->parent == parent) |
ddb5b488 PZ |
795 | break; |
796 | } | |
797 | ||
40381db7 DS |
798 | if (bpi) { |
799 | bool labelssame = labels_same(bpi, label, num_labels); | |
e37fb4bf | 800 | |
8fac400c AR |
801 | if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) |
802 | && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { | |
803 | if (debug) { | |
804 | zlog_debug( | |
805 | "%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking", | |
806 | __func__, bgp->name_pretty, | |
807 | source_bpi->flags, bpi->flags, p); | |
808 | } | |
809 | return NULL; | |
810 | } | |
811 | ||
40381db7 DS |
812 | if (attrhash_cmp(bpi->attr, new_attr) && labelssame |
813 | && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { | |
ddb5b488 PZ |
814 | |
815 | bgp_attr_unintern(&new_attr); | |
816 | if (debug) | |
817 | zlog_debug( | |
56ca3b5b | 818 | "%s: ->%s: %pBD: Found route, no change", |
b54892e0 | 819 | __func__, bgp->name_pretty, bn); |
ddb5b488 PZ |
820 | return NULL; |
821 | } | |
822 | ||
823 | /* attr is changed */ | |
40381db7 | 824 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_ATTR_CHANGED); |
ddb5b488 PZ |
825 | |
826 | /* Rewrite BGP route information. */ | |
40381db7 DS |
827 | if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) |
828 | bgp_path_info_restore(bn, bpi); | |
ddb5b488 | 829 | else |
40381db7 DS |
830 | bgp_aggregate_decrement(bgp, p, bpi, afi, safi); |
831 | bgp_attr_unintern(&bpi->attr); | |
832 | bpi->attr = new_attr; | |
833 | bpi->uptime = bgp_clock(); | |
ddb5b488 | 834 | |
e37fb4bf PZ |
835 | /* |
836 | * rewrite labels | |
837 | */ | |
838 | if (!labelssame) | |
40381db7 | 839 | setlabels(bpi, label, num_labels); |
e37fb4bf | 840 | |
dbcf19b8 HS |
841 | /* |
842 | * rewrite sid | |
843 | */ | |
844 | if (num_sids) { | |
16f3db2d | 845 | if (new_attr->srv6_l3vpn) { |
7de4c885 HS |
846 | setsids(bpi, &new_attr->srv6_l3vpn->sid, |
847 | num_sids); | |
16f3db2d RS |
848 | |
849 | extra = bgp_path_info_extra_get(bpi); | |
850 | ||
851 | extra->sid[0].loc_block_len = | |
852 | new_attr->srv6_l3vpn->loc_block_len; | |
853 | extra->sid[0].loc_node_len = | |
854 | new_attr->srv6_l3vpn->loc_node_len; | |
855 | extra->sid[0].func_len = | |
856 | new_attr->srv6_l3vpn->func_len; | |
857 | extra->sid[0].arg_len = | |
858 | new_attr->srv6_l3vpn->arg_len; | |
ea7cd161 RS |
859 | extra->sid[0].transposition_len = |
860 | new_attr->srv6_l3vpn->transposition_len; | |
861 | extra->sid[0].transposition_offset = | |
862 | new_attr->srv6_l3vpn | |
863 | ->transposition_offset; | |
16f3db2d | 864 | } else if (new_attr->srv6_vpn) |
7de4c885 HS |
865 | setsids(bpi, &new_attr->srv6_vpn->sid, |
866 | num_sids); | |
d79ff732 HS |
867 | } else |
868 | unsetsids(bpi); | |
dbcf19b8 | 869 | |
960035b2 | 870 | if (nexthop_self_flag) |
40381db7 | 871 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); |
960035b2 PZ |
872 | |
873 | struct bgp *bgp_nexthop = bgp; | |
874 | int nh_valid; | |
875 | ||
40381db7 DS |
876 | if (bpi->extra && bpi->extra->bgp_orig) |
877 | bgp_nexthop = bpi->extra->bgp_orig; | |
960035b2 | 878 | |
0a2f9ac1 | 879 | /* |
880 | * No nexthop tracking for redistributed routes or for | |
881 | * EVPN-imported routes that get leaked. | |
882 | */ | |
883 | if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || | |
884 | is_pi_family_evpn(bpi_ultimate)) | |
960035b2 PZ |
885 | nh_valid = 1; |
886 | else | |
887 | /* | |
888 | * TBD do we need to do anything about the | |
889 | * 'connected' parameter? | |
890 | */ | |
4053e952 | 891 | nh_valid = bgp_find_or_add_nexthop( |
654a5978 | 892 | bgp, bgp_nexthop, afi, safi, bpi, NULL, 0, p); |
960035b2 | 893 | |
d79ff732 HS |
894 | /* |
895 | * If you are using SRv6 VPN instead of MPLS, it need to check | |
896 | * the SID allocation. If the sid is not allocated, the rib | |
897 | * will be invalid. | |
898 | */ | |
899 | if (bgp->srv6_enabled | |
900 | && (!new_attr->srv6_l3vpn && !new_attr->srv6_vpn)) { | |
901 | bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID); | |
902 | nh_valid = false; | |
903 | } | |
904 | ||
960035b2 PZ |
905 | if (debug) |
906 | zlog_debug("%s: nexthop is %svalid (in vrf %s)", | |
907 | __func__, (nh_valid ? "" : "not "), | |
908 | bgp_nexthop->name_pretty); | |
909 | ||
910 | if (nh_valid) | |
40381db7 | 911 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID); |
960035b2 | 912 | |
ddb5b488 | 913 | /* Process change. */ |
40381db7 | 914 | bgp_aggregate_increment(bgp, p, bpi, afi, safi); |
ddb5b488 | 915 | bgp_process(bgp, bn, afi, safi); |
9bcb3eef | 916 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
917 | |
918 | if (debug) | |
56ca3b5b | 919 | zlog_debug("%s: ->%s: %pBD Found route, changed attr", |
b54892e0 | 920 | __func__, bgp->name_pretty, bn); |
ddb5b488 | 921 | |
40381db7 | 922 | return bpi; |
ddb5b488 PZ |
923 | } |
924 | ||
8fac400c AR |
925 | if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)) { |
926 | if (debug) { | |
927 | zlog_debug( | |
928 | "%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking", | |
929 | __func__, bgp->name_pretty, | |
930 | source_bpi->flags, p); | |
931 | } | |
932 | return NULL; | |
933 | } | |
934 | ||
be180f97 | 935 | new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, |
960035b2 PZ |
936 | bgp->peer_self, new_attr, bn); |
937 | ||
938 | if (nexthop_self_flag) | |
18ee8310 | 939 | bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF); |
ddb5b488 | 940 | |
18ee8310 | 941 | bgp_path_info_extra_get(new); |
4b85140f | 942 | |
dbcf19b8 HS |
943 | /* |
944 | * rewrite sid | |
945 | */ | |
946 | if (num_sids) { | |
16f3db2d | 947 | if (new_attr->srv6_l3vpn) { |
dbcf19b8 | 948 | setsids(new, &new_attr->srv6_l3vpn->sid, num_sids); |
16f3db2d RS |
949 | |
950 | extra = bgp_path_info_extra_get(new); | |
951 | ||
952 | extra->sid[0].loc_block_len = | |
953 | new_attr->srv6_l3vpn->loc_block_len; | |
954 | extra->sid[0].loc_node_len = | |
955 | new_attr->srv6_l3vpn->loc_node_len; | |
956 | extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len; | |
957 | extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len; | |
ea7cd161 RS |
958 | extra->sid[0].transposition_len = |
959 | new_attr->srv6_l3vpn->transposition_len; | |
960 | extra->sid[0].transposition_offset = | |
961 | new_attr->srv6_l3vpn->transposition_offset; | |
16f3db2d | 962 | } else if (new_attr->srv6_vpn) |
dbcf19b8 | 963 | setsids(new, &new_attr->srv6_vpn->sid, num_sids); |
d79ff732 HS |
964 | } else |
965 | unsetsids(new); | |
dbcf19b8 | 966 | |
e37fb4bf PZ |
967 | if (num_labels) |
968 | setlabels(new, label, num_labels); | |
969 | ||
18ee8310 | 970 | new->extra->parent = bgp_path_info_lock(parent); |
9bcb3eef DS |
971 | bgp_dest_lock_node( |
972 | (struct bgp_dest *)((struct bgp_path_info *)parent)->net); | |
ddb5b488 | 973 | if (bgp_orig) |
21d88ef7 | 974 | new->extra->bgp_orig = bgp_lock(bgp_orig); |
ddb5b488 PZ |
975 | if (nexthop_orig) |
976 | new->extra->nexthop_orig = *nexthop_orig; | |
977 | ||
960035b2 PZ |
978 | /* |
979 | * nexthop tracking for unicast routes | |
980 | */ | |
981 | struct bgp *bgp_nexthop = bgp; | |
982 | int nh_valid; | |
983 | ||
4b85140f | 984 | if (new->extra->bgp_orig) |
960035b2 PZ |
985 | bgp_nexthop = new->extra->bgp_orig; |
986 | ||
987 | /* | |
988 | * No nexthop tracking for redistributed routes because | |
989 | * their originating protocols will do the tracking and | |
990 | * withdraw those routes if the nexthops become unreachable | |
0a2f9ac1 | 991 | * This also holds good for EVPN-imported routes that get |
992 | * leaked. | |
960035b2 | 993 | */ |
0a2f9ac1 | 994 | if (bpi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE || |
995 | is_pi_family_evpn(bpi_ultimate)) | |
960035b2 PZ |
996 | nh_valid = 1; |
997 | else | |
998 | /* | |
999 | * TBD do we need to do anything about the | |
1000 | * 'connected' parameter? | |
1001 | */ | |
4053e952 | 1002 | nh_valid = bgp_find_or_add_nexthop(bgp, bgp_nexthop, afi, safi, |
654a5978 | 1003 | new, NULL, 0, p); |
960035b2 | 1004 | |
d79ff732 HS |
1005 | /* |
1006 | * If you are using SRv6 VPN instead of MPLS, it need to check | |
1007 | * the SID allocation. If the sid is not allocated, the rib | |
1008 | * will be invalid. | |
1009 | */ | |
1010 | if (bgp->srv6_enabled | |
1011 | && (!new->attr->srv6_l3vpn && !new->attr->srv6_vpn)) { | |
1012 | bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID); | |
1013 | nh_valid = false; | |
1014 | } | |
1015 | ||
960035b2 PZ |
1016 | if (debug) |
1017 | zlog_debug("%s: nexthop is %svalid (in vrf %s)", | |
1018 | __func__, (nh_valid ? "" : "not "), | |
1019 | bgp_nexthop->name_pretty); | |
1020 | if (nh_valid) | |
18ee8310 | 1021 | bgp_path_info_set_flag(bn, new, BGP_PATH_VALID); |
960035b2 | 1022 | |
ddb5b488 | 1023 | bgp_aggregate_increment(bgp, p, new, afi, safi); |
18ee8310 | 1024 | bgp_path_info_add(bn, new); |
ddb5b488 | 1025 | |
9bcb3eef | 1026 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
1027 | bgp_process(bgp, bn, afi, safi); |
1028 | ||
1029 | if (debug) | |
56ca3b5b | 1030 | zlog_debug("%s: ->%s: %pBD: Added new route", __func__, |
b54892e0 | 1031 | bgp->name_pretty, bn); |
ddb5b488 PZ |
1032 | |
1033 | return new; | |
1034 | } | |
1035 | ||
1036 | /* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */ | |
4b7e6066 DS |
1037 | void vpn_leak_from_vrf_update(struct bgp *bgp_vpn, /* to */ |
1038 | struct bgp *bgp_vrf, /* from */ | |
40381db7 | 1039 | struct bgp_path_info *path_vrf) /* route */ |
ddb5b488 PZ |
1040 | { |
1041 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
9bcb3eef | 1042 | const struct prefix *p = bgp_dest_get_prefix(path_vrf->net); |
ddb5b488 PZ |
1043 | afi_t afi = family2afi(p->family); |
1044 | struct attr static_attr = {0}; | |
1045 | struct attr *new_attr = NULL; | |
1046 | safi_t safi = SAFI_MPLS_VPN; | |
1047 | mpls_label_t label_val; | |
1048 | mpls_label_t label; | |
9bcb3eef | 1049 | struct bgp_dest *bn; |
ddb5b488 | 1050 | const char *debugmsg; |
960035b2 PZ |
1051 | int nexthop_self_flag = 0; |
1052 | ||
1053 | if (debug) | |
1054 | zlog_debug("%s: from vrf %s", __func__, bgp_vrf->name_pretty); | |
ddb5b488 | 1055 | |
b53e67a3 DA |
1056 | if (debug && bgp_attr_get_ecommunity(path_vrf->attr)) { |
1057 | char *s = ecommunity_ecom2str( | |
1058 | bgp_attr_get_ecommunity(path_vrf->attr), | |
1059 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
ddb5b488 | 1060 | |
40381db7 DS |
1061 | zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__, |
1062 | bgp_vrf->name, path_vrf->type, s); | |
c8f57349 | 1063 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1064 | } |
1065 | ||
1066 | if (!bgp_vpn) | |
1067 | return; | |
1068 | ||
1069 | if (!afi) { | |
1070 | if (debug) | |
1071 | zlog_debug("%s: can't get afi of prefix", __func__); | |
1072 | return; | |
1073 | } | |
1074 | ||
12d6100c | 1075 | /* Is this route exportable into the VPN table? */ |
1076 | if (!is_route_injectable_into_vpn(path_vrf)) | |
ddb5b488 PZ |
1077 | return; |
1078 | ||
ddb5b488 PZ |
1079 | if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { |
1080 | if (debug) | |
12a844a5 DS |
1081 | zlog_debug("%s: %s skipping: %s", __func__, |
1082 | bgp_vrf->name, debugmsg); | |
ddb5b488 PZ |
1083 | return; |
1084 | } | |
1085 | ||
6f4f49b2 QY |
1086 | /* shallow copy */ |
1087 | static_attr = *path_vrf->attr; | |
ddb5b488 PZ |
1088 | |
1089 | /* | |
1090 | * route map handling | |
1091 | */ | |
1092 | if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) { | |
4b7e6066 | 1093 | struct bgp_path_info info; |
ddb5b488 PZ |
1094 | route_map_result_t ret; |
1095 | ||
1096 | memset(&info, 0, sizeof(info)); | |
1097 | info.peer = bgp_vpn->peer_self; | |
1098 | info.attr = &static_attr; | |
1099 | ret = route_map_apply( | |
1100 | bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN], | |
1782514f | 1101 | p, &info); |
ddb5b488 PZ |
1102 | if (RMAP_DENYMATCH == ret) { |
1103 | bgp_attr_flush(&static_attr); /* free any added parts */ | |
1104 | if (debug) | |
1105 | zlog_debug( | |
1106 | "%s: vrf %s route map \"%s\" says DENY, returning", | |
960035b2 | 1107 | __func__, bgp_vrf->name_pretty, |
ddb5b488 PZ |
1108 | bgp_vrf->vpn_policy[afi] |
1109 | .rmap[BGP_VPN_POLICY_DIR_TOVPN] | |
1110 | ->name); | |
1111 | return; | |
1112 | } | |
1113 | } | |
1114 | ||
b53e67a3 DA |
1115 | if (debug && bgp_attr_get_ecommunity(&static_attr)) { |
1116 | char *s = ecommunity_ecom2str( | |
1117 | bgp_attr_get_ecommunity(&static_attr), | |
1118 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
ddb5b488 | 1119 | |
ddb5b488 PZ |
1120 | zlog_debug("%s: post route map static_attr.ecommunity{%s}", |
1121 | __func__, s); | |
c8f57349 | 1122 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1123 | } |
1124 | ||
1125 | /* | |
1126 | * Add the vpn-policy rt-list | |
1127 | */ | |
1128 | struct ecommunity *old_ecom; | |
1129 | struct ecommunity *new_ecom; | |
1130 | ||
e8bfa90e | 1131 | /* Export with the 'from' instance's export RTs. */ |
1132 | /* If doing VRF-to-VRF leaking, strip existing RTs first. */ | |
b53e67a3 | 1133 | old_ecom = bgp_attr_get_ecommunity(&static_attr); |
ddb5b488 | 1134 | if (old_ecom) { |
e8bfa90e | 1135 | new_ecom = ecommunity_dup(old_ecom); |
1136 | if (CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST], | |
1137 | BGP_CONFIG_VRF_TO_VRF_EXPORT)) | |
1138 | ecommunity_strip_rts(new_ecom); | |
1139 | new_ecom = ecommunity_merge(new_ecom, | |
ddb5b488 PZ |
1140 | bgp_vrf->vpn_policy[afi] |
1141 | .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); | |
1142 | if (!old_ecom->refcnt) | |
1143 | ecommunity_free(&old_ecom); | |
1144 | } else { | |
1145 | new_ecom = ecommunity_dup( | |
1146 | bgp_vrf->vpn_policy[afi] | |
1147 | .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); | |
1148 | } | |
b53e67a3 | 1149 | bgp_attr_set_ecommunity(&static_attr, new_ecom); |
ddb5b488 PZ |
1150 | SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); |
1151 | ||
b53e67a3 DA |
1152 | if (debug && bgp_attr_get_ecommunity(&static_attr)) { |
1153 | char *s = ecommunity_ecom2str( | |
1154 | bgp_attr_get_ecommunity(&static_attr), | |
1155 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
ddb5b488 | 1156 | |
ddb5b488 PZ |
1157 | zlog_debug("%s: post merge static_attr.ecommunity{%s}", |
1158 | __func__, s); | |
c8f57349 | 1159 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1160 | } |
1161 | ||
1162 | /* Nexthop */ | |
1163 | /* if policy nexthop not set, use 0 */ | |
1164 | if (CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags, | |
1165 | BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) { | |
ddb5b488 PZ |
1166 | struct prefix *nexthop = |
1167 | &bgp_vrf->vpn_policy[afi].tovpn_nexthop; | |
12a844a5 | 1168 | |
ddb5b488 PZ |
1169 | switch (nexthop->family) { |
1170 | case AF_INET: | |
1171 | /* prevent mp_nexthop_global_in <- self in bgp_route.c | |
1172 | */ | |
1173 | static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr; | |
1174 | ||
1175 | static_attr.mp_nexthop_global_in = nexthop->u.prefix4; | |
0606039c | 1176 | static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; |
ddb5b488 PZ |
1177 | break; |
1178 | ||
1179 | case AF_INET6: | |
1180 | static_attr.mp_nexthop_global = nexthop->u.prefix6; | |
0606039c | 1181 | static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; |
ddb5b488 PZ |
1182 | break; |
1183 | ||
1184 | default: | |
1185 | assert(0); | |
1186 | } | |
1187 | } else { | |
12a844a5 DS |
1188 | if (!CHECK_FLAG(bgp_vrf->af_flags[afi][SAFI_UNICAST], |
1189 | BGP_CONFIG_VRF_TO_VRF_EXPORT)) { | |
1190 | if (afi == AFI_IP) { | |
020a3f60 DS |
1191 | /* |
1192 | * For ipv4, copy to multiprotocol | |
1193 | * nexthop field | |
1194 | */ | |
1195 | static_attr.mp_nexthop_global_in = | |
1196 | static_attr.nexthop; | |
0606039c DA |
1197 | static_attr.mp_nexthop_len = |
1198 | BGP_ATTR_NHLEN_IPV4; | |
020a3f60 DS |
1199 | /* |
1200 | * XXX Leave static_attr.nexthop | |
1201 | * intact for NHT | |
1202 | */ | |
1203 | static_attr.flag &= | |
1204 | ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); | |
12a844a5 DS |
1205 | } |
1206 | } else { | |
77e62f2b | 1207 | /* Update based on next-hop family to account for |
1208 | * RFC 5549 (BGP unnumbered) scenario. Note that | |
1209 | * specific action is only needed for the case of | |
1210 | * IPv4 nexthops as the attr has been copied | |
1211 | * otherwise. | |
1212 | */ | |
40381db7 DS |
1213 | if (afi == AFI_IP |
1214 | && !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) { | |
12a844a5 DS |
1215 | static_attr.mp_nexthop_global_in.s_addr = |
1216 | static_attr.nexthop.s_addr; | |
0606039c DA |
1217 | static_attr.mp_nexthop_len = |
1218 | BGP_ATTR_NHLEN_IPV4; | |
12a844a5 DS |
1219 | static_attr.flag |= |
1220 | ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); | |
12a844a5 | 1221 | } |
ddb5b488 | 1222 | } |
960035b2 | 1223 | nexthop_self_flag = 1; |
ddb5b488 PZ |
1224 | } |
1225 | ||
1226 | label_val = bgp_vrf->vpn_policy[afi].tovpn_label; | |
1227 | if (label_val == MPLS_LABEL_NONE) { | |
291e32c3 | 1228 | encode_label(MPLS_LABEL_IMPLICIT_NULL, &label); |
ddb5b488 PZ |
1229 | } else { |
1230 | encode_label(label_val, &label); | |
1231 | } | |
1232 | ||
1233 | /* Set originator ID to "me" */ | |
1234 | SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)); | |
1235 | static_attr.originator_id = bgp_vpn->router_id; | |
1236 | ||
dbcf19b8 | 1237 | /* Set SID for SRv6 VPN */ |
69fe7874 | 1238 | if (bgp_vrf->vpn_policy[afi].tovpn_sid_locator) { |
9299fd00 RS |
1239 | encode_label(bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label, |
1240 | &label); | |
dbcf19b8 | 1241 | static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, |
537b608a | 1242 | sizeof(struct bgp_attr_srv6_l3vpn)); |
dbcf19b8 HS |
1243 | static_attr.srv6_l3vpn->sid_flags = 0x00; |
1244 | static_attr.srv6_l3vpn->endpoint_behavior = 0xffff; | |
9299fd00 RS |
1245 | static_attr.srv6_l3vpn->loc_block_len = |
1246 | BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH; | |
1247 | static_attr.srv6_l3vpn->loc_node_len = | |
1248 | BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH; | |
1249 | static_attr.srv6_l3vpn->func_len = | |
1250 | BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH; | |
1251 | static_attr.srv6_l3vpn->arg_len = | |
1252 | BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH; | |
1253 | static_attr.srv6_l3vpn->transposition_len = | |
1254 | BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH; | |
1255 | static_attr.srv6_l3vpn->transposition_offset = | |
1256 | BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET; | |
dbcf19b8 | 1257 | memcpy(&static_attr.srv6_l3vpn->sid, |
69fe7874 RS |
1258 | bgp_vrf->vpn_policy[afi].tovpn_sid_locator, |
1259 | sizeof(struct in6_addr)); | |
dbcf19b8 HS |
1260 | } |
1261 | ||
ddb5b488 PZ |
1262 | |
1263 | new_attr = bgp_attr_intern( | |
1264 | &static_attr); /* hashed refcounted everything */ | |
1265 | bgp_attr_flush(&static_attr); /* free locally-allocated parts */ | |
1266 | ||
b53e67a3 DA |
1267 | if (debug && bgp_attr_get_ecommunity(new_attr)) { |
1268 | char *s = ecommunity_ecom2str(bgp_attr_get_ecommunity(new_attr), | |
c3e345b1 | 1269 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); |
ddb5b488 | 1270 | |
ddb5b488 | 1271 | zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s); |
c3e345b1 | 1272 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1273 | } |
1274 | ||
1275 | /* Now new_attr is an allocated interned attr */ | |
1276 | ||
1277 | bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p, | |
1278 | &(bgp_vrf->vpn_policy[afi].tovpn_rd)); | |
1279 | ||
4b7e6066 | 1280 | struct bgp_path_info *new_info; |
ddb5b488 | 1281 | |
40381db7 DS |
1282 | new_info = leak_update(bgp_vpn, bn, new_attr, afi, safi, path_vrf, |
1283 | &label, 1, path_vrf, bgp_vrf, NULL, | |
960035b2 | 1284 | nexthop_self_flag, debug); |
ddb5b488 PZ |
1285 | |
1286 | /* | |
1287 | * Routes actually installed in the vpn RIB must also be | |
1288 | * offered to all vrfs (because now they originate from | |
1289 | * the vpn RIB). | |
1290 | * | |
1291 | * Acceptance into other vrfs depends on rt-lists. | |
1292 | * Originating vrf will not accept the looped back route | |
1293 | * because of loop checking. | |
1294 | */ | |
1295 | if (new_info) | |
321b4bc9 | 1296 | vpn_leak_to_vrf_update(bgp_vrf, new_info); |
ddb5b488 PZ |
1297 | } |
1298 | ||
4b7e6066 DS |
1299 | void vpn_leak_from_vrf_withdraw(struct bgp *bgp_vpn, /* to */ |
1300 | struct bgp *bgp_vrf, /* from */ | |
40381db7 | 1301 | struct bgp_path_info *path_vrf) /* route */ |
ddb5b488 PZ |
1302 | { |
1303 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
9bcb3eef | 1304 | const struct prefix *p = bgp_dest_get_prefix(path_vrf->net); |
ddb5b488 PZ |
1305 | afi_t afi = family2afi(p->family); |
1306 | safi_t safi = SAFI_MPLS_VPN; | |
40381db7 | 1307 | struct bgp_path_info *bpi; |
9bcb3eef | 1308 | struct bgp_dest *bn; |
ddb5b488 | 1309 | const char *debugmsg; |
960035b2 PZ |
1310 | |
1311 | if (debug) { | |
960035b2 | 1312 | zlog_debug( |
56ca3b5b | 1313 | "%s: entry: leak-from=%s, p=%pBD, type=%d, sub_type=%d", |
b54892e0 | 1314 | __func__, bgp_vrf->name_pretty, path_vrf->net, |
40381db7 | 1315 | path_vrf->type, path_vrf->sub_type); |
960035b2 | 1316 | } |
ddb5b488 | 1317 | |
ddb5b488 PZ |
1318 | if (!bgp_vpn) |
1319 | return; | |
1320 | ||
1321 | if (!afi) { | |
1322 | if (debug) | |
1323 | zlog_debug("%s: can't get afi of prefix", __func__); | |
1324 | return; | |
1325 | } | |
1326 | ||
12d6100c | 1327 | /* Is this route exportable into the VPN table? */ |
1328 | if (!is_route_injectable_into_vpn(path_vrf)) | |
1329 | return; | |
1330 | ||
ddb5b488 PZ |
1331 | if (!vpn_leak_to_vpn_active(bgp_vrf, afi, &debugmsg)) { |
1332 | if (debug) | |
1333 | zlog_debug("%s: skipping: %s", __func__, debugmsg); | |
1334 | return; | |
1335 | } | |
1336 | ||
1337 | if (debug) | |
40381db7 | 1338 | zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf); |
ddb5b488 PZ |
1339 | |
1340 | bn = bgp_afi_node_get(bgp_vpn->rib[afi][safi], afi, safi, p, | |
1341 | &(bgp_vrf->vpn_policy[afi].tovpn_rd)); | |
1342 | ||
6f94b685 DS |
1343 | if (!bn) |
1344 | return; | |
ddb5b488 PZ |
1345 | /* |
1346 | * vrf -> vpn | |
40381db7 | 1347 | * match original bpi imported from |
ddb5b488 | 1348 | */ |
9bcb3eef | 1349 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { |
40381db7 | 1350 | if (bpi->extra && bpi->extra->parent == path_vrf) { |
ddb5b488 PZ |
1351 | break; |
1352 | } | |
1353 | } | |
1354 | ||
40381db7 | 1355 | if (bpi) { |
ddb5b488 | 1356 | /* withdraw from looped vrfs as well */ |
40381db7 | 1357 | vpn_leak_to_vrf_withdraw(bgp_vpn, bpi); |
ddb5b488 | 1358 | |
40381db7 DS |
1359 | bgp_aggregate_decrement(bgp_vpn, p, bpi, afi, safi); |
1360 | bgp_path_info_delete(bn, bpi); | |
ddb5b488 PZ |
1361 | bgp_process(bgp_vpn, bn, afi, safi); |
1362 | } | |
9bcb3eef | 1363 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
1364 | } |
1365 | ||
1366 | void vpn_leak_from_vrf_withdraw_all(struct bgp *bgp_vpn, /* to */ | |
1367 | struct bgp *bgp_vrf, /* from */ | |
1368 | afi_t afi) | |
1369 | { | |
1370 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
9bcb3eef | 1371 | struct bgp_dest *pdest; |
ddb5b488 PZ |
1372 | safi_t safi = SAFI_MPLS_VPN; |
1373 | ||
1374 | /* | |
40381db7 | 1375 | * Walk vpn table, delete bpi with bgp_orig == bgp_vrf |
ddb5b488 | 1376 | */ |
9bcb3eef DS |
1377 | for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest; |
1378 | pdest = bgp_route_next(pdest)) { | |
ddb5b488 PZ |
1379 | |
1380 | struct bgp_table *table; | |
9bcb3eef | 1381 | struct bgp_dest *bn; |
40381db7 | 1382 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
1383 | |
1384 | /* This is the per-RD table of prefixes */ | |
9bcb3eef | 1385 | table = bgp_dest_get_bgp_table_info(pdest); |
ddb5b488 PZ |
1386 | |
1387 | if (!table) | |
1388 | continue; | |
1389 | ||
1390 | for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { | |
9bcb3eef | 1391 | bpi = bgp_dest_get_bgp_path_info(bn); |
6f94b685 | 1392 | if (debug && bpi) { |
56ca3b5b | 1393 | zlog_debug("%s: looking at prefix %pBD", |
b54892e0 | 1394 | __func__, bn); |
ddb5b488 PZ |
1395 | } |
1396 | ||
6f94b685 | 1397 | for (; bpi; bpi = bpi->next) { |
ddb5b488 PZ |
1398 | if (debug) |
1399 | zlog_debug("%s: type %d, sub_type %d", | |
40381db7 DS |
1400 | __func__, bpi->type, |
1401 | bpi->sub_type); | |
1402 | if (bpi->sub_type != BGP_ROUTE_IMPORTED) | |
ddb5b488 | 1403 | continue; |
40381db7 | 1404 | if (!bpi->extra) |
ddb5b488 | 1405 | continue; |
40381db7 | 1406 | if ((struct bgp *)bpi->extra->bgp_orig |
ddb5b488 PZ |
1407 | == bgp_vrf) { |
1408 | /* delete route */ | |
1409 | if (debug) | |
9165c5f5 | 1410 | zlog_debug("%s: deleting it", |
ddb5b488 | 1411 | __func__); |
b19c4f08 AR |
1412 | /* withdraw from leak-to vrfs as well */ |
1413 | vpn_leak_to_vrf_withdraw(bgp_vpn, bpi); | |
b54892e0 DS |
1414 | bgp_aggregate_decrement( |
1415 | bgp_vpn, | |
9bcb3eef | 1416 | bgp_dest_get_prefix(bn), bpi, |
b54892e0 | 1417 | afi, safi); |
40381db7 | 1418 | bgp_path_info_delete(bn, bpi); |
ddb5b488 PZ |
1419 | bgp_process(bgp_vpn, bn, afi, safi); |
1420 | } | |
1421 | } | |
1422 | } | |
1423 | } | |
1424 | } | |
1425 | ||
1426 | void vpn_leak_from_vrf_update_all(struct bgp *bgp_vpn, /* to */ | |
1427 | struct bgp *bgp_vrf, /* from */ | |
1428 | afi_t afi) | |
1429 | { | |
9bcb3eef | 1430 | struct bgp_dest *bn; |
40381db7 | 1431 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
1432 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); |
1433 | ||
1434 | if (debug) | |
1435 | zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi, | |
960035b2 | 1436 | bgp_vrf->name_pretty); |
ddb5b488 PZ |
1437 | |
1438 | for (bn = bgp_table_top(bgp_vrf->rib[afi][SAFI_UNICAST]); bn; | |
1439 | bn = bgp_route_next(bn)) { | |
1440 | ||
1441 | if (debug) | |
1442 | zlog_debug("%s: node=%p", __func__, bn); | |
1443 | ||
9bcb3eef | 1444 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 1445 | bpi = bpi->next) { |
ddb5b488 PZ |
1446 | if (debug) |
1447 | zlog_debug( | |
1448 | "%s: calling vpn_leak_from_vrf_update", | |
1449 | __func__); | |
40381db7 | 1450 | vpn_leak_from_vrf_update(bgp_vpn, bgp_vrf, bpi); |
ddb5b488 PZ |
1451 | } |
1452 | } | |
1453 | } | |
1454 | ||
4b7e6066 DS |
1455 | static void |
1456 | vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ | |
1457 | struct bgp *bgp_vpn, /* from */ | |
40381db7 | 1458 | struct bgp_path_info *path_vpn) /* route */ |
ddb5b488 | 1459 | { |
9bcb3eef | 1460 | const struct prefix *p = bgp_dest_get_prefix(path_vpn->net); |
ddb5b488 PZ |
1461 | afi_t afi = family2afi(p->family); |
1462 | ||
ddb5b488 PZ |
1463 | struct attr static_attr = {0}; |
1464 | struct attr *new_attr = NULL; | |
9bcb3eef | 1465 | struct bgp_dest *bn; |
ddb5b488 PZ |
1466 | safi_t safi = SAFI_UNICAST; |
1467 | const char *debugmsg; | |
1468 | struct prefix nexthop_orig; | |
1469 | mpls_label_t *pLabels = NULL; | |
e37fb4bf | 1470 | uint32_t num_labels = 0; |
960035b2 | 1471 | int nexthop_self_flag = 1; |
40381db7 | 1472 | struct bgp_path_info *bpi_ultimate = NULL; |
513bf8d6 | 1473 | int origin_local = 0; |
d6632478 | 1474 | struct bgp *src_vrf; |
ddb5b488 PZ |
1475 | |
1476 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
1477 | ||
b9c7bc5a | 1478 | if (!vpn_leak_from_vpn_active(bgp_vrf, afi, &debugmsg)) { |
ddb5b488 PZ |
1479 | if (debug) |
1480 | zlog_debug("%s: skipping: %s", __func__, debugmsg); | |
1481 | return; | |
1482 | } | |
1483 | ||
1484 | /* Check for intersection of route targets */ | |
1485 | if (!ecom_intersect( | |
1486 | bgp_vrf->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN], | |
b53e67a3 | 1487 | bgp_attr_get_ecommunity(path_vpn->attr))) { |
de7cee09 AR |
1488 | if (debug) |
1489 | zlog_debug( | |
1490 | "from vpn to vrf %s, skipping after no intersection of route targets", | |
1491 | bgp_vrf->name_pretty); | |
ddb5b488 PZ |
1492 | return; |
1493 | } | |
1494 | ||
2dbe669b DA |
1495 | if (debug) |
1496 | zlog_debug("%s: updating %pFX to vrf %s", __func__, p, | |
1497 | bgp_vrf->name_pretty); | |
ddb5b488 | 1498 | |
6f4f49b2 QY |
1499 | /* shallow copy */ |
1500 | static_attr = *path_vpn->attr; | |
ddb5b488 | 1501 | |
e8bfa90e | 1502 | struct ecommunity *old_ecom; |
1503 | struct ecommunity *new_ecom; | |
1504 | ||
1505 | /* If doing VRF-to-VRF leaking, strip RTs. */ | |
b53e67a3 | 1506 | old_ecom = bgp_attr_get_ecommunity(&static_attr); |
e8bfa90e | 1507 | if (old_ecom && CHECK_FLAG(bgp_vrf->af_flags[afi][safi], |
1508 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { | |
1509 | new_ecom = ecommunity_dup(old_ecom); | |
1510 | ecommunity_strip_rts(new_ecom); | |
b53e67a3 | 1511 | bgp_attr_set_ecommunity(&static_attr, new_ecom); |
1995cb77 DS |
1512 | |
1513 | if (new_ecom->size == 0) { | |
1514 | UNSET_FLAG(static_attr.flag, | |
1515 | ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)); | |
1516 | ecommunity_free(&new_ecom); | |
b53e67a3 | 1517 | bgp_attr_set_ecommunity(&static_attr, NULL); |
1995cb77 DS |
1518 | } |
1519 | ||
e8bfa90e | 1520 | if (!old_ecom->refcnt) |
1521 | ecommunity_free(&old_ecom); | |
1522 | } | |
1523 | ||
ddb5b488 PZ |
1524 | /* |
1525 | * Nexthop: stash and clear | |
1526 | * | |
1527 | * Nexthop is valid in context of VPN core, but not in destination vrf. | |
1528 | * Stash it for later label resolution by vrf ingress path and then | |
1529 | * overwrite with 0, i.e., "me", for the sake of vrf advertisement. | |
1530 | */ | |
40381db7 | 1531 | uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len); |
ddb5b488 PZ |
1532 | |
1533 | memset(&nexthop_orig, 0, sizeof(nexthop_orig)); | |
1534 | nexthop_orig.family = nhfamily; | |
1535 | ||
1536 | switch (nhfamily) { | |
ddb5b488 PZ |
1537 | case AF_INET: |
1538 | /* save */ | |
40381db7 | 1539 | nexthop_orig.u.prefix4 = path_vpn->attr->mp_nexthop_global_in; |
12256b84 | 1540 | nexthop_orig.prefixlen = IPV4_MAX_BITLEN; |
12a844a5 DS |
1541 | |
1542 | if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi], | |
1543 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { | |
1544 | static_attr.nexthop.s_addr = | |
1545 | nexthop_orig.u.prefix4.s_addr; | |
1546 | ||
1547 | static_attr.mp_nexthop_global_in = | |
40381db7 | 1548 | path_vpn->attr->mp_nexthop_global_in; |
12a844a5 | 1549 | static_attr.mp_nexthop_len = |
40381db7 | 1550 | path_vpn->attr->mp_nexthop_len; |
12a844a5 | 1551 | } |
de4d0a51 | 1552 | static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); |
ddb5b488 | 1553 | break; |
ddb5b488 PZ |
1554 | case AF_INET6: |
1555 | /* save */ | |
40381db7 | 1556 | nexthop_orig.u.prefix6 = path_vpn->attr->mp_nexthop_global; |
13ccce6e | 1557 | nexthop_orig.prefixlen = IPV6_MAX_BITLEN; |
12a844a5 DS |
1558 | |
1559 | if (CHECK_FLAG(bgp_vrf->af_flags[afi][safi], | |
1560 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { | |
1561 | static_attr.mp_nexthop_global = nexthop_orig.u.prefix6; | |
12a844a5 | 1562 | } |
ddb5b488 PZ |
1563 | break; |
1564 | } | |
1565 | ||
ddb5b488 PZ |
1566 | /* |
1567 | * route map handling | |
ddb5b488 | 1568 | */ |
ddb5b488 | 1569 | if (bgp_vrf->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) { |
4b7e6066 | 1570 | struct bgp_path_info info; |
ddb5b488 PZ |
1571 | route_map_result_t ret; |
1572 | ||
1573 | memset(&info, 0, sizeof(info)); | |
1574 | info.peer = bgp_vrf->peer_self; | |
1575 | info.attr = &static_attr; | |
1dcc9e5b | 1576 | info.extra = path_vpn->extra; /* Used for source-vrf filter */ |
ddb5b488 PZ |
1577 | ret = route_map_apply(bgp_vrf->vpn_policy[afi] |
1578 | .rmap[BGP_VPN_POLICY_DIR_FROMVPN], | |
1782514f | 1579 | p, &info); |
ddb5b488 PZ |
1580 | if (RMAP_DENYMATCH == ret) { |
1581 | bgp_attr_flush(&static_attr); /* free any added parts */ | |
1582 | if (debug) | |
1583 | zlog_debug( | |
1584 | "%s: vrf %s vpn-policy route map \"%s\" says DENY, returning", | |
960035b2 | 1585 | __func__, bgp_vrf->name_pretty, |
ddb5b488 PZ |
1586 | bgp_vrf->vpn_policy[afi] |
1587 | .rmap[BGP_VPN_POLICY_DIR_FROMVPN] | |
1588 | ->name); | |
1589 | return; | |
1590 | } | |
960035b2 PZ |
1591 | /* |
1592 | * if route-map changed nexthop, don't nexthop-self on output | |
1593 | */ | |
1594 | if (!CHECK_FLAG(static_attr.rmap_change_flags, | |
1595 | BATTR_RMAP_NEXTHOP_UNCHANGED)) | |
1596 | nexthop_self_flag = 0; | |
ddb5b488 PZ |
1597 | } |
1598 | ||
1599 | new_attr = bgp_attr_intern(&static_attr); | |
1600 | bgp_attr_flush(&static_attr); | |
1601 | ||
1602 | bn = bgp_afi_node_get(bgp_vrf->rib[afi][safi], afi, safi, p, NULL); | |
1603 | ||
1604 | /* | |
1605 | * ensure labels are copied | |
513bf8d6 PZ |
1606 | * |
1607 | * However, there is a special case: if the route originated in | |
1608 | * another local VRF (as opposed to arriving via VPN), then the | |
1609 | * nexthop is reached by hairpinning through this router (me) | |
1610 | * using IP forwarding only (no LSP). Therefore, the route | |
1611 | * imported to the VRF should not have labels attached. Note | |
1612 | * that nexthop tracking is also involved: eliminating the | |
1613 | * labels for these routes enables the non-labeled nexthops | |
1614 | * from the originating VRF to be considered valid for this route. | |
ddb5b488 | 1615 | */ |
12a844a5 DS |
1616 | if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi], |
1617 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { | |
1618 | /* work back to original route */ | |
da0c0ef7 | 1619 | bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); |
513bf8d6 | 1620 | |
12a844a5 DS |
1621 | /* |
1622 | * if original route was unicast, | |
1623 | * then it did not arrive over vpn | |
1624 | */ | |
40381db7 | 1625 | if (bpi_ultimate->net) { |
12a844a5 | 1626 | struct bgp_table *table; |
513bf8d6 | 1627 | |
9bcb3eef | 1628 | table = bgp_dest_table(bpi_ultimate->net); |
12a844a5 DS |
1629 | if (table && (table->safi == SAFI_UNICAST)) |
1630 | origin_local = 1; | |
1631 | } | |
513bf8d6 | 1632 | |
12a844a5 | 1633 | /* copy labels */ |
40381db7 DS |
1634 | if (!origin_local && path_vpn->extra |
1635 | && path_vpn->extra->num_labels) { | |
1636 | num_labels = path_vpn->extra->num_labels; | |
12a844a5 DS |
1637 | if (num_labels > BGP_MAX_LABELS) |
1638 | num_labels = BGP_MAX_LABELS; | |
40381db7 | 1639 | pLabels = path_vpn->extra->label; |
12a844a5 | 1640 | } |
ddb5b488 | 1641 | } |
513bf8d6 | 1642 | |
b54892e0 | 1643 | if (debug) |
56ca3b5b | 1644 | zlog_debug("%s: pfx %pBD: num_labels %d", __func__, |
b54892e0 | 1645 | path_vpn->net, num_labels); |
ddb5b488 | 1646 | |
44338987 | 1647 | /* |
1d4e8b0d DS |
1648 | * For VRF-2-VRF route-leaking, |
1649 | * the source will be the originating VRF. | |
44338987 | 1650 | */ |
40381db7 DS |
1651 | if (path_vpn->extra && path_vpn->extra->bgp_orig) |
1652 | src_vrf = path_vpn->extra->bgp_orig; | |
d6632478 PZ |
1653 | else |
1654 | src_vrf = bgp_vpn; | |
1655 | ||
40381db7 DS |
1656 | leak_update(bgp_vrf, bn, new_attr, afi, safi, path_vpn, pLabels, |
1657 | num_labels, path_vpn, /* parent */ | |
1658 | src_vrf, &nexthop_orig, nexthop_self_flag, debug); | |
ddb5b488 PZ |
1659 | } |
1660 | ||
4b7e6066 | 1661 | void vpn_leak_to_vrf_update(struct bgp *bgp_vpn, /* from */ |
40381db7 | 1662 | struct bgp_path_info *path_vpn) /* route */ |
ddb5b488 PZ |
1663 | { |
1664 | struct listnode *mnode, *mnnode; | |
1665 | struct bgp *bgp; | |
1666 | ||
1667 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
1668 | ||
1669 | if (debug) | |
40381db7 | 1670 | zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); |
ddb5b488 PZ |
1671 | |
1672 | /* Loop over VRFs */ | |
1673 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { | |
1674 | ||
40381db7 DS |
1675 | if (!path_vpn->extra |
1676 | || path_vpn->extra->bgp_orig != bgp) { /* no loop */ | |
1677 | vpn_leak_to_vrf_update_onevrf(bgp, bgp_vpn, path_vpn); | |
ddb5b488 PZ |
1678 | } |
1679 | } | |
1680 | } | |
1681 | ||
4b7e6066 | 1682 | void vpn_leak_to_vrf_withdraw(struct bgp *bgp_vpn, /* from */ |
40381db7 | 1683 | struct bgp_path_info *path_vpn) /* route */ |
ddb5b488 | 1684 | { |
b54892e0 | 1685 | const struct prefix *p; |
1b3510a0 | 1686 | afi_t afi; |
ddb5b488 PZ |
1687 | safi_t safi = SAFI_UNICAST; |
1688 | struct bgp *bgp; | |
1689 | struct listnode *mnode, *mnnode; | |
9bcb3eef | 1690 | struct bgp_dest *bn; |
40381db7 | 1691 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
1692 | const char *debugmsg; |
1693 | ||
1694 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
1695 | ||
b54892e0 | 1696 | if (debug) |
56ca3b5b | 1697 | zlog_debug("%s: entry: p=%pBD, type=%d, sub_type=%d", __func__, |
b54892e0 | 1698 | path_vpn->net, path_vpn->type, path_vpn->sub_type); |
960035b2 | 1699 | |
ddb5b488 | 1700 | if (debug) |
40381db7 | 1701 | zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); |
ddb5b488 | 1702 | |
40381db7 | 1703 | if (!path_vpn->net) { |
49e5a4a0 | 1704 | #ifdef ENABLE_BGP_VNC |
40381db7 DS |
1705 | /* BGP_ROUTE_RFP routes do not have path_vpn->net set (yet) */ |
1706 | if (path_vpn->type == ZEBRA_ROUTE_BGP | |
1707 | && path_vpn->sub_type == BGP_ROUTE_RFP) { | |
1b3510a0 PZ |
1708 | |
1709 | return; | |
1710 | } | |
56c2c080 | 1711 | #endif |
1b3510a0 | 1712 | if (debug) |
40381db7 DS |
1713 | zlog_debug( |
1714 | "%s: path_vpn->net unexpectedly NULL, no prefix, bailing", | |
1b3510a0 PZ |
1715 | __func__); |
1716 | return; | |
1717 | } | |
1718 | ||
9bcb3eef | 1719 | p = bgp_dest_get_prefix(path_vpn->net); |
1b3510a0 | 1720 | afi = family2afi(p->family); |
ddb5b488 PZ |
1721 | |
1722 | /* Loop over VRFs */ | |
1723 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { | |
b9c7bc5a | 1724 | if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg)) { |
ddb5b488 PZ |
1725 | if (debug) |
1726 | zlog_debug("%s: skipping: %s", __func__, | |
1727 | debugmsg); | |
1728 | continue; | |
1729 | } | |
1730 | ||
1731 | /* Check for intersection of route targets */ | |
1732 | if (!ecom_intersect(bgp->vpn_policy[afi] | |
1733 | .rtlist[BGP_VPN_POLICY_DIR_FROMVPN], | |
b53e67a3 | 1734 | bgp_attr_get_ecommunity(path_vpn->attr))) { |
ddb5b488 PZ |
1735 | |
1736 | continue; | |
1737 | } | |
1738 | ||
1739 | if (debug) | |
1740 | zlog_debug("%s: withdrawing from vrf %s", __func__, | |
960035b2 | 1741 | bgp->name_pretty); |
ddb5b488 PZ |
1742 | |
1743 | bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, NULL); | |
6f94b685 | 1744 | |
9bcb3eef | 1745 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 1746 | bpi = bpi->next) { |
40381db7 DS |
1747 | if (bpi->extra |
1748 | && (struct bgp_path_info *)bpi->extra->parent | |
1749 | == path_vpn) { | |
ddb5b488 PZ |
1750 | break; |
1751 | } | |
1752 | } | |
1753 | ||
40381db7 | 1754 | if (bpi) { |
ddb5b488 | 1755 | if (debug) |
40381db7 DS |
1756 | zlog_debug("%s: deleting bpi %p", __func__, |
1757 | bpi); | |
1758 | bgp_aggregate_decrement(bgp, p, bpi, afi, safi); | |
1759 | bgp_path_info_delete(bn, bpi); | |
ddb5b488 PZ |
1760 | bgp_process(bgp, bn, afi, safi); |
1761 | } | |
9bcb3eef | 1762 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
1763 | } |
1764 | } | |
1765 | ||
1766 | void vpn_leak_to_vrf_withdraw_all(struct bgp *bgp_vrf, /* to */ | |
1767 | afi_t afi) | |
1768 | { | |
9bcb3eef | 1769 | struct bgp_dest *bn; |
40381db7 | 1770 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
1771 | safi_t safi = SAFI_UNICAST; |
1772 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
ddb5b488 PZ |
1773 | |
1774 | if (debug) | |
1775 | zlog_debug("%s: entry", __func__); | |
1776 | /* | |
40381db7 | 1777 | * Walk vrf table, delete bpi with bgp_orig in a different vrf |
ddb5b488 PZ |
1778 | */ |
1779 | for (bn = bgp_table_top(bgp_vrf->rib[afi][safi]); bn; | |
1780 | bn = bgp_route_next(bn)) { | |
1781 | ||
9bcb3eef | 1782 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 1783 | bpi = bpi->next) { |
9544ddb2 | 1784 | if (bpi->extra |
1785 | && bpi->extra->bgp_orig != bgp_vrf | |
1786 | && bpi->extra->parent | |
1787 | && is_pi_family_vpn(bpi->extra->parent)) { | |
ddb5b488 PZ |
1788 | |
1789 | /* delete route */ | |
b54892e0 | 1790 | bgp_aggregate_decrement(bgp_vrf, |
9bcb3eef | 1791 | bgp_dest_get_prefix(bn), |
b54892e0 | 1792 | bpi, afi, safi); |
40381db7 | 1793 | bgp_path_info_delete(bn, bpi); |
ddb5b488 PZ |
1794 | bgp_process(bgp_vrf, bn, afi, safi); |
1795 | } | |
1796 | } | |
1797 | } | |
1798 | } | |
1799 | ||
1800 | void vpn_leak_to_vrf_update_all(struct bgp *bgp_vrf, /* to */ | |
1801 | struct bgp *bgp_vpn, /* from */ | |
1802 | afi_t afi) | |
1803 | { | |
9bcb3eef | 1804 | struct bgp_dest *pdest; |
ddb5b488 PZ |
1805 | safi_t safi = SAFI_MPLS_VPN; |
1806 | ||
3bd70bf8 | 1807 | assert(bgp_vpn); |
73aed584 | 1808 | |
ddb5b488 PZ |
1809 | /* |
1810 | * Walk vpn table | |
1811 | */ | |
9bcb3eef DS |
1812 | for (pdest = bgp_table_top(bgp_vpn->rib[afi][safi]); pdest; |
1813 | pdest = bgp_route_next(pdest)) { | |
ddb5b488 | 1814 | struct bgp_table *table; |
9bcb3eef | 1815 | struct bgp_dest *bn; |
40381db7 | 1816 | struct bgp_path_info *bpi; |
ddb5b488 | 1817 | |
ddb5b488 | 1818 | /* This is the per-RD table of prefixes */ |
9bcb3eef | 1819 | table = bgp_dest_get_bgp_table_info(pdest); |
ddb5b488 PZ |
1820 | |
1821 | if (!table) | |
1822 | continue; | |
1823 | ||
1824 | for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { | |
1825 | ||
9bcb3eef | 1826 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 1827 | bpi = bpi->next) { |
ddb5b488 | 1828 | |
40381db7 DS |
1829 | if (bpi->extra |
1830 | && bpi->extra->bgp_orig == bgp_vrf) | |
ddb5b488 PZ |
1831 | continue; |
1832 | ||
1833 | vpn_leak_to_vrf_update_onevrf(bgp_vrf, bgp_vpn, | |
40381db7 | 1834 | bpi); |
ddb5b488 PZ |
1835 | } |
1836 | } | |
1837 | } | |
1838 | } | |
1839 | ||
d92a55df PZ |
1840 | /* |
1841 | * This function is called for definition/deletion/change to a route-map | |
1842 | */ | |
ddb5b488 PZ |
1843 | static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name) |
1844 | { | |
1845 | int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT); | |
1846 | afi_t afi; | |
1847 | struct route_map *rmap; | |
1848 | ||
1849 | if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT | |
1850 | && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) { | |
1851 | ||
1852 | return; | |
1853 | } | |
1854 | ||
1855 | rmap = route_map_lookup_by_name(rmap_name); /* NULL if deleted */ | |
1856 | ||
1857 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
1858 | ||
d92a55df PZ |
1859 | if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN] |
1860 | && !strcmp(rmap_name, | |
ddb5b488 PZ |
1861 | bgp->vpn_policy[afi] |
1862 | .rmap_name[BGP_VPN_POLICY_DIR_TOVPN])) { | |
1863 | ||
1864 | if (debug) | |
1865 | zlog_debug( | |
1866 | "%s: rmap \"%s\" matches vrf-policy tovpn for as %d afi %s", | |
1867 | __func__, rmap_name, bgp->as, | |
1868 | afi2str(afi)); | |
1869 | ||
1870 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, | |
1871 | bgp_get_default(), bgp); | |
1872 | if (debug) | |
1873 | zlog_debug("%s: after vpn_leak_prechange", | |
1874 | __func__); | |
1875 | ||
d92a55df PZ |
1876 | /* in case of definition/deletion */ |
1877 | bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] = | |
1878 | rmap; | |
ddb5b488 PZ |
1879 | |
1880 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, | |
1881 | bgp_get_default(), bgp); | |
d92a55df | 1882 | |
ddb5b488 PZ |
1883 | if (debug) |
1884 | zlog_debug("%s: after vpn_leak_postchange", | |
1885 | __func__); | |
1886 | } | |
1887 | ||
d92a55df PZ |
1888 | if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN] |
1889 | && !strcmp(rmap_name, | |
1890 | bgp->vpn_policy[afi] | |
1891 | .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN])) { | |
b9c7bc5a PZ |
1892 | |
1893 | if (debug) { | |
1894 | zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s", | |
ddb5b488 PZ |
1895 | __func__, rmap_name, bgp->as, |
1896 | afi2str(afi)); | |
b9c7bc5a | 1897 | } |
ddb5b488 PZ |
1898 | |
1899 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi, | |
1900 | bgp_get_default(), bgp); | |
1901 | ||
d92a55df PZ |
1902 | /* in case of definition/deletion */ |
1903 | bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN] = | |
1904 | rmap; | |
ddb5b488 PZ |
1905 | |
1906 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi, | |
1907 | bgp_get_default(), bgp); | |
1908 | } | |
1909 | } | |
1910 | } | |
1911 | ||
636f7608 CS |
1912 | /* This API is used during router-id change, reflect VPNs |
1913 | * auto RD and RT values and readvertise routes to VPN table. | |
1914 | */ | |
e65fe398 MS |
1915 | void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, |
1916 | bool is_config) | |
636f7608 CS |
1917 | { |
1918 | afi_t afi; | |
de7cee09 AR |
1919 | int debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
1920 | | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
636f7608 CS |
1921 | char *vname; |
1922 | const char *export_name; | |
1923 | char buf[RD_ADDRSTRLEN]; | |
1924 | struct bgp *bgp_import; | |
1925 | struct listnode *node; | |
1926 | struct ecommunity *ecom; | |
1927 | vpn_policy_direction_t idir, edir; | |
1928 | ||
de7cee09 AR |
1929 | /* |
1930 | * Router-id change that is not explicitly configured | |
1931 | * (a change from zebra, frr restart for example) | |
1932 | * should not replace a configured vpn RD/RT. | |
1933 | */ | |
1934 | if (!is_config) { | |
1935 | if (debug) | |
1936 | zlog_debug("%s: skipping non explicit router-id change", | |
1937 | __func__); | |
1938 | return; | |
1939 | } | |
1940 | ||
636f7608 CS |
1941 | if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT |
1942 | && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
1943 | return; | |
1944 | ||
1945 | export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME; | |
636f7608 CS |
1946 | idir = BGP_VPN_POLICY_DIR_FROMVPN; |
1947 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
1948 | ||
1949 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
1950 | if (!vpn_leak_to_vpn_active(bgp, afi, NULL)) | |
1951 | continue; | |
1952 | ||
1953 | if (withdraw) { | |
1954 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, | |
1955 | afi, bgp_get_default(), bgp); | |
1956 | if (debug) | |
1957 | zlog_debug("%s: %s after to_vpn vpn_leak_prechange", | |
1958 | __func__, export_name); | |
1959 | ||
1960 | /* Remove import RT from VRFs */ | |
1961 | ecom = bgp->vpn_policy[afi].rtlist[edir]; | |
1962 | for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi]. | |
1963 | export_vrf, node, vname)) { | |
67bd620c | 1964 | if (strcmp(vname, VRF_DEFAULT_NAME) == 0) |
1965 | bgp_import = bgp_get_default(); | |
1966 | else | |
1967 | bgp_import = bgp_lookup_by_name(vname); | |
636f7608 CS |
1968 | if (!bgp_import) |
1969 | continue; | |
1970 | ||
de7cee09 AR |
1971 | ecommunity_del_val( |
1972 | bgp_import->vpn_policy[afi] | |
1973 | .rtlist[idir], | |
636f7608 | 1974 | (struct ecommunity_val *)ecom->val); |
636f7608 CS |
1975 | } |
1976 | } else { | |
1977 | /* New router-id derive auto RD and RT and export | |
1978 | * to VPN | |
1979 | */ | |
1980 | form_auto_rd(bgp->router_id, bgp->vrf_rd_id, | |
1981 | &bgp->vrf_prd_auto); | |
1982 | bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto; | |
1983 | prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf, | |
1984 | sizeof(buf)); | |
1985 | bgp->vpn_policy[afi].rtlist[edir] = | |
1986 | ecommunity_str2com(buf, | |
1987 | ECOMMUNITY_ROUTE_TARGET, 0); | |
1988 | ||
1989 | /* Update import_vrf rt_list */ | |
1990 | ecom = bgp->vpn_policy[afi].rtlist[edir]; | |
1991 | for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi]. | |
1992 | export_vrf, node, vname)) { | |
67bd620c | 1993 | if (strcmp(vname, VRF_DEFAULT_NAME) == 0) |
1994 | bgp_import = bgp_get_default(); | |
1995 | else | |
1996 | bgp_import = bgp_lookup_by_name(vname); | |
636f7608 CS |
1997 | if (!bgp_import) |
1998 | continue; | |
1999 | if (bgp_import->vpn_policy[afi].rtlist[idir]) | |
2000 | bgp_import->vpn_policy[afi].rtlist[idir] | |
2001 | = ecommunity_merge( | |
2002 | bgp_import->vpn_policy[afi] | |
2003 | .rtlist[idir], ecom); | |
2004 | else | |
2005 | bgp_import->vpn_policy[afi].rtlist[idir] | |
2006 | = ecommunity_dup(ecom); | |
636f7608 | 2007 | } |
e65fe398 | 2008 | |
636f7608 CS |
2009 | /* Update routes to VPN */ |
2010 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, | |
2011 | afi, bgp_get_default(), | |
2012 | bgp); | |
2013 | if (debug) | |
2014 | zlog_debug("%s: %s after to_vpn vpn_leak_postchange", | |
2015 | __func__, export_name); | |
2016 | } | |
2017 | } | |
2018 | } | |
2019 | ||
ddb5b488 PZ |
2020 | void vpn_policy_routemap_event(const char *rmap_name) |
2021 | { | |
2022 | int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT); | |
2023 | struct listnode *mnode, *mnnode; | |
2024 | struct bgp *bgp; | |
2025 | ||
2026 | if (debug) | |
2027 | zlog_debug("%s: entry", __func__); | |
2028 | ||
2029 | if (bm->bgp == NULL) /* may be called during cleanup */ | |
2030 | return; | |
2031 | ||
2032 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) | |
2033 | vpn_policy_routemap_update(bgp, rmap_name); | |
2034 | } | |
2035 | ||
1d4e8b0d | 2036 | void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, |
44338987 | 2037 | afi_t afi, safi_t safi) |
2038 | { | |
2039 | const char *export_name; | |
2040 | vpn_policy_direction_t idir, edir; | |
9ecf931b CS |
2041 | char *vname, *tmp_name; |
2042 | char buf[RD_ADDRSTRLEN]; | |
44338987 | 2043 | struct ecommunity *ecom; |
2044 | bool first_export = false; | |
636f7608 | 2045 | int debug; |
9ecf931b CS |
2046 | struct listnode *node; |
2047 | bool is_inst_match = false; | |
44338987 | 2048 | |
5742e42b | 2049 | export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME; |
44338987 | 2050 | idir = BGP_VPN_POLICY_DIR_FROMVPN; |
2051 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
2052 | ||
636f7608 CS |
2053 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | |
2054 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
2055 | ||
1d4e8b0d DS |
2056 | /* |
2057 | * Cross-ref both VRFs. Also, note if this is the first time | |
44338987 | 2058 | * any VRF is importing from "import_vrf". |
2059 | */ | |
a8dadcf6 | 2060 | vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name) |
5742e42b | 2061 | : XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME)); |
a8dadcf6 | 2062 | |
9ecf931b CS |
2063 | /* Check the import_vrf list of destination vrf for the source vrf name, |
2064 | * insert otherwise. | |
2065 | */ | |
2066 | for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, | |
2067 | node, tmp_name)) { | |
2068 | if (strcmp(vname, tmp_name) == 0) { | |
2069 | is_inst_match = true; | |
2070 | break; | |
2071 | } | |
2072 | } | |
2073 | if (!is_inst_match) | |
2074 | listnode_add(to_bgp->vpn_policy[afi].import_vrf, | |
2075 | vname); | |
b9d45462 DS |
2076 | else |
2077 | XFREE(MTYPE_TMP, vname); | |
44338987 | 2078 | |
9ecf931b CS |
2079 | /* Check if the source vrf already exports to any vrf, |
2080 | * first time export requires to setup auto derived RD/RT values. | |
2081 | * Add the destination vrf name to export vrf list if it is | |
2082 | * not present. | |
2083 | */ | |
2084 | is_inst_match = false; | |
44338987 | 2085 | vname = XSTRDUP(MTYPE_TMP, export_name); |
9ecf931b CS |
2086 | if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) { |
2087 | first_export = true; | |
2088 | } else { | |
2089 | for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf, | |
2090 | node, tmp_name)) { | |
2091 | if (strcmp(vname, tmp_name) == 0) { | |
2092 | is_inst_match = true; | |
2093 | break; | |
2094 | } | |
2095 | } | |
2096 | } | |
2097 | if (!is_inst_match) | |
2098 | listnode_add(from_bgp->vpn_policy[afi].export_vrf, | |
2099 | vname); | |
b9d45462 DS |
2100 | else |
2101 | XFREE(MTYPE_TMP, vname); | |
2102 | ||
44338987 | 2103 | /* Update import RT for current VRF using export RT of the VRF we're |
2104 | * importing from. First though, make sure "import_vrf" has that | |
2105 | * set. | |
2106 | */ | |
2107 | if (first_export) { | |
1d4e8b0d DS |
2108 | form_auto_rd(from_bgp->router_id, from_bgp->vrf_rd_id, |
2109 | &from_bgp->vrf_prd_auto); | |
2110 | from_bgp->vpn_policy[afi].tovpn_rd = from_bgp->vrf_prd_auto; | |
2111 | SET_FLAG(from_bgp->vpn_policy[afi].flags, | |
44338987 | 2112 | BGP_VPN_POLICY_TOVPN_RD_SET); |
1d4e8b0d | 2113 | prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd, |
44338987 | 2114 | buf, sizeof(buf)); |
1d4e8b0d | 2115 | from_bgp->vpn_policy[afi].rtlist[edir] = |
44338987 | 2116 | ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0); |
1d4e8b0d | 2117 | SET_FLAG(from_bgp->af_flags[afi][safi], |
44338987 | 2118 | BGP_CONFIG_VRF_TO_VRF_EXPORT); |
13b7e7f0 DS |
2119 | from_bgp->vpn_policy[afi].tovpn_label = |
2120 | BGP_PREVENT_VRF_2_VRF_LEAK; | |
44338987 | 2121 | } |
1d4e8b0d DS |
2122 | ecom = from_bgp->vpn_policy[afi].rtlist[edir]; |
2123 | if (to_bgp->vpn_policy[afi].rtlist[idir]) | |
2124 | to_bgp->vpn_policy[afi].rtlist[idir] = | |
2125 | ecommunity_merge(to_bgp->vpn_policy[afi] | |
44338987 | 2126 | .rtlist[idir], ecom); |
2127 | else | |
1d4e8b0d DS |
2128 | to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom); |
2129 | SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT); | |
44338987 | 2130 | |
636f7608 CS |
2131 | if (debug) { |
2132 | const char *from_name; | |
6a37bfb7 | 2133 | char *ecom1, *ecom2; |
636f7608 CS |
2134 | |
2135 | from_name = from_bgp->name ? from_bgp->name : | |
2136 | VRF_DEFAULT_NAME; | |
6a37bfb7 DS |
2137 | |
2138 | ecom1 = ecommunity_ecom2str( | |
2139 | to_bgp->vpn_policy[afi].rtlist[idir], | |
2140 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
2141 | ||
2142 | ecom2 = ecommunity_ecom2str( | |
2143 | to_bgp->vpn_policy[afi].rtlist[edir], | |
2144 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
2145 | ||
2146 | zlog_debug( | |
2147 | "%s from %s to %s first_export %u import-rt %s export-rt %s", | |
2148 | __func__, from_name, export_name, first_export, ecom1, | |
2149 | ecom2); | |
2150 | ||
2151 | ecommunity_strfree(&ecom1); | |
2152 | ecommunity_strfree(&ecom2); | |
636f7608 CS |
2153 | } |
2154 | ||
44338987 | 2155 | /* Does "import_vrf" first need to export its routes or that |
2156 | * is already done and we just need to import those routes | |
2157 | * from the global table? | |
2158 | */ | |
2159 | if (first_export) | |
1d4e8b0d | 2160 | vpn_leak_postchange(edir, afi, bgp_get_default(), from_bgp); |
44338987 | 2161 | else |
1d4e8b0d | 2162 | vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp); |
44338987 | 2163 | } |
2164 | ||
1d4e8b0d | 2165 | void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, |
44338987 | 2166 | afi_t afi, safi_t safi) |
2167 | { | |
a8dadcf6 | 2168 | const char *export_name, *tmp_name; |
44338987 | 2169 | vpn_policy_direction_t idir, edir; |
2170 | char *vname; | |
9ecf931b | 2171 | struct ecommunity *ecom = NULL; |
44338987 | 2172 | struct listnode *node; |
636f7608 | 2173 | int debug; |
44338987 | 2174 | |
5742e42b DS |
2175 | export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME; |
2176 | tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; | |
44338987 | 2177 | idir = BGP_VPN_POLICY_DIR_FROMVPN; |
2178 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
2179 | ||
636f7608 CS |
2180 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | |
2181 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
2182 | ||
44338987 | 2183 | /* Were we importing from "import_vrf"? */ |
1d4e8b0d DS |
2184 | for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node, |
2185 | vname)) { | |
a8dadcf6 | 2186 | if (strcmp(vname, tmp_name) == 0) |
020a3f60 | 2187 | break; |
44338987 | 2188 | } |
1d4e8b0d DS |
2189 | |
2190 | /* | |
2191 | * We do not check in the cli if the passed in bgp | |
2192 | * instance is actually imported into us before | |
2193 | * we call this function. As such if we do not | |
2194 | * find this in the import_vrf list than | |
2195 | * we just need to return safely. | |
2196 | */ | |
44338987 | 2197 | if (!vname) |
2198 | return; | |
2199 | ||
636f7608 CS |
2200 | if (debug) |
2201 | zlog_debug("%s from %s to %s", __func__, tmp_name, export_name); | |
2202 | ||
44338987 | 2203 | /* Remove "import_vrf" from our import list. */ |
1d4e8b0d | 2204 | listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname); |
44338987 | 2205 | XFREE(MTYPE_TMP, vname); |
2206 | ||
2207 | /* Remove routes imported from "import_vrf". */ | |
2208 | /* TODO: In the current logic, we have to first remove all | |
2209 | * imported routes and then (if needed) import back routes | |
2210 | */ | |
1d4e8b0d | 2211 | vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp); |
44338987 | 2212 | |
1d4e8b0d | 2213 | if (to_bgp->vpn_policy[afi].import_vrf->count == 0) { |
ae6a6fb4 DS |
2214 | if (!to_bgp->vpn_policy[afi].rmap[idir]) |
2215 | UNSET_FLAG(to_bgp->af_flags[afi][safi], | |
2216 | BGP_CONFIG_VRF_TO_VRF_IMPORT); | |
9ecf931b CS |
2217 | if (to_bgp->vpn_policy[afi].rtlist[idir]) |
2218 | ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]); | |
44338987 | 2219 | } else { |
1d4e8b0d | 2220 | ecom = from_bgp->vpn_policy[afi].rtlist[edir]; |
9ecf931b CS |
2221 | if (ecom) |
2222 | ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir], | |
44338987 | 2223 | (struct ecommunity_val *)ecom->val); |
1d4e8b0d | 2224 | vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp); |
44338987 | 2225 | } |
2226 | ||
89d59347 DS |
2227 | /* |
2228 | * What? | |
2229 | * So SA is assuming that since the ALL_LIST_ELEMENTS_RO | |
2230 | * below is checking for NULL that export_vrf can be | |
2231 | * NULL, consequently it is complaining( like a cabbage ) | |
2232 | * that we could dereference and crash in the listcount(..) | |
2233 | * check below. | |
2234 | * So make it happy, under protest, with liberty and justice | |
2235 | * for all. | |
2236 | */ | |
1d4e8b0d | 2237 | assert(from_bgp->vpn_policy[afi].export_vrf); |
89d59347 | 2238 | |
44338987 | 2239 | /* Remove us from "import_vrf's" export list. If no other VRF |
2240 | * is importing from "import_vrf", cleanup appropriately. | |
2241 | */ | |
1d4e8b0d | 2242 | for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf, |
44338987 | 2243 | node, vname)) { |
2244 | if (strcmp(vname, export_name) == 0) | |
2245 | break; | |
2246 | } | |
2247 | ||
1d4e8b0d DS |
2248 | /* |
2249 | * If we have gotten to this point then the vname must | |
2250 | * exist. If not, we are in a world of trouble and | |
2251 | * have slag sitting around. | |
2252 | * | |
2253 | * import_vrf and export_vrf must match in having | |
2254 | * the in/out names as appropriate. | |
9ecf931b CS |
2255 | * export_vrf list could have been cleaned up |
2256 | * as part of no router bgp source instnace. | |
1d4e8b0d | 2257 | */ |
9ecf931b CS |
2258 | if (!vname) |
2259 | return; | |
1d4e8b0d DS |
2260 | |
2261 | listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname); | |
44338987 | 2262 | XFREE(MTYPE_TMP, vname); |
2263 | ||
1d4e8b0d DS |
2264 | if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) { |
2265 | vpn_leak_prechange(edir, afi, bgp_get_default(), from_bgp); | |
2266 | ecommunity_free(&from_bgp->vpn_policy[afi].rtlist[edir]); | |
2267 | UNSET_FLAG(from_bgp->af_flags[afi][safi], | |
44338987 | 2268 | BGP_CONFIG_VRF_TO_VRF_EXPORT); |
1d4e8b0d | 2269 | memset(&from_bgp->vpn_policy[afi].tovpn_rd, 0, |
44338987 | 2270 | sizeof(struct prefix_rd)); |
1d4e8b0d | 2271 | UNSET_FLAG(from_bgp->vpn_policy[afi].flags, |
44338987 | 2272 | BGP_VPN_POLICY_TOVPN_RD_SET); |
13b7e7f0 DS |
2273 | from_bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; |
2274 | ||
44338987 | 2275 | } |
2276 | } | |
2277 | ||
718e3744 | 2278 | /* For testing purpose, static route of MPLS-VPN. */ |
2279 | DEFUN (vpnv4_network, | |
2280 | vpnv4_network_cmd, | |
d114b977 | 2281 | "network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)", |
718e3744 | 2282 | "Specify a network to announce via BGP\n" |
0c7b1b01 | 2283 | "IPv4 prefix\n" |
718e3744 | 2284 | "Specify Route Distinguisher\n" |
2285 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
2286 | "VPN NLRI label (tag)\n" |
2287 | "VPN NLRI label (tag)\n" | |
2288 | "Label value\n") | |
718e3744 | 2289 | { |
d62a17ae | 2290 | int idx_ipv4_prefixlen = 1; |
2291 | int idx_ext_community = 3; | |
2292 | int idx_label = 5; | |
2293 | return bgp_static_set_safi( | |
2294 | AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, | |
2295 | argv[idx_ext_community]->arg, argv[idx_label]->arg, NULL, 0, | |
2296 | NULL, NULL, NULL, NULL); | |
137446f9 LB |
2297 | } |
2298 | ||
2299 | DEFUN (vpnv4_network_route_map, | |
2300 | vpnv4_network_route_map_cmd, | |
d114b977 | 2301 | "network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) route-map WORD", |
137446f9 | 2302 | "Specify a network to announce via BGP\n" |
0c7b1b01 | 2303 | "IPv4 prefix\n" |
137446f9 LB |
2304 | "Specify Route Distinguisher\n" |
2305 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
2306 | "VPN NLRI label (tag)\n" |
2307 | "VPN NLRI label (tag)\n" | |
2308 | "Label value\n" | |
137446f9 LB |
2309 | "route map\n" |
2310 | "route map name\n") | |
2311 | { | |
d62a17ae | 2312 | int idx_ipv4_prefixlen = 1; |
2313 | int idx_ext_community = 3; | |
2314 | int idx_label = 5; | |
2315 | int idx_word_2 = 7; | |
2316 | return bgp_static_set_safi( | |
2317 | AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, | |
2318 | argv[idx_ext_community]->arg, argv[idx_label]->arg, | |
2319 | argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); | |
718e3744 | 2320 | } |
2321 | ||
2322 | /* For testing purpose, static route of MPLS-VPN. */ | |
2323 | DEFUN (no_vpnv4_network, | |
2324 | no_vpnv4_network_cmd, | |
d114b977 | 2325 | "no network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)", |
718e3744 | 2326 | NO_STR |
2327 | "Specify a network to announce via BGP\n" | |
0c7b1b01 | 2328 | "IPv4 prefix\n" |
718e3744 | 2329 | "Specify Route Distinguisher\n" |
2330 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
2331 | "VPN NLRI label (tag)\n" |
2332 | "VPN NLRI label (tag)\n" | |
2333 | "Label value\n") | |
718e3744 | 2334 | { |
d62a17ae | 2335 | int idx_ipv4_prefixlen = 2; |
2336 | int idx_ext_community = 4; | |
2337 | int idx_label = 6; | |
2338 | return bgp_static_unset_safi(AFI_IP, SAFI_MPLS_VPN, vty, | |
2339 | argv[idx_ipv4_prefixlen]->arg, | |
2340 | argv[idx_ext_community]->arg, | |
2341 | argv[idx_label]->arg, 0, NULL, NULL, NULL); | |
718e3744 | 2342 | } |
2343 | ||
c286be96 LX |
2344 | DEFUN (vpnv6_network, |
2345 | vpnv6_network_cmd, | |
d114b977 | 2346 | "network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) [route-map WORD]", |
c286be96 LX |
2347 | "Specify a network to announce via BGP\n" |
2348 | "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" | |
2349 | "Specify Route Distinguisher\n" | |
2350 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
2351 | "VPN NLRI label (tag)\n" |
2352 | "VPN NLRI label (tag)\n" | |
2353 | "Label value\n" | |
11daee81 DS |
2354 | "route map\n" |
2355 | "route map name\n") | |
c286be96 | 2356 | { |
d62a17ae | 2357 | int idx_ipv6_prefix = 1; |
2358 | int idx_ext_community = 3; | |
2359 | int idx_label = 5; | |
2360 | int idx_word_2 = 7; | |
2361 | if (argc == 8) | |
2362 | return bgp_static_set_safi( | |
2363 | AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, | |
2364 | argv[idx_ext_community]->arg, argv[idx_label]->arg, | |
2365 | argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); | |
2366 | else | |
2367 | return bgp_static_set_safi( | |
2368 | AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, | |
2369 | argv[idx_ext_community]->arg, argv[idx_label]->arg, | |
2370 | NULL, 0, NULL, NULL, NULL, NULL); | |
c286be96 LX |
2371 | } |
2372 | ||
2373 | /* For testing purpose, static route of MPLS-VPN. */ | |
2374 | DEFUN (no_vpnv6_network, | |
2375 | no_vpnv6_network_cmd, | |
d114b977 | 2376 | "no network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)", |
c286be96 LX |
2377 | NO_STR |
2378 | "Specify a network to announce via BGP\n" | |
2379 | "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" | |
2380 | "Specify Route Distinguisher\n" | |
2381 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
2382 | "VPN NLRI label (tag)\n" |
2383 | "VPN NLRI label (tag)\n" | |
2384 | "Label value\n") | |
c286be96 | 2385 | { |
d62a17ae | 2386 | int idx_ipv6_prefix = 2; |
2387 | int idx_ext_community = 4; | |
2388 | int idx_label = 6; | |
2389 | return bgp_static_unset_safi(AFI_IP6, SAFI_MPLS_VPN, vty, | |
2390 | argv[idx_ipv6_prefix]->arg, | |
2391 | argv[idx_ext_community]->arg, | |
2392 | argv[idx_label]->arg, 0, NULL, NULL, NULL); | |
c286be96 LX |
2393 | } |
2394 | ||
d62a17ae | 2395 | int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd, |
2396 | enum bgp_show_type type, void *output_arg, int tags, | |
9f049418 | 2397 | bool use_json) |
718e3744 | 2398 | { |
d62a17ae | 2399 | struct bgp *bgp; |
2400 | struct bgp_table *table; | |
d62a17ae | 2401 | |
2402 | bgp = bgp_get_default(); | |
2403 | if (bgp == NULL) { | |
2404 | if (!use_json) | |
2405 | vty_out(vty, "No BGP process is configured\n"); | |
16307668 RW |
2406 | else |
2407 | vty_out(vty, "{}\n"); | |
d62a17ae | 2408 | return CMD_WARNING; |
2409 | } | |
1ae44dfc | 2410 | table = bgp->rib[afi][SAFI_MPLS_VPN]; |
a4d82a8a PZ |
2411 | return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type, |
2412 | output_arg, use_json); | |
718e3744 | 2413 | } |
2414 | ||
4f280b15 LB |
2415 | DEFUN (show_bgp_ip_vpn_all_rd, |
2416 | show_bgp_ip_vpn_all_rd_cmd, | |
a111dd97 | 2417 | "show bgp "BGP_AFI_CMD_STR" vpn all [rd <ASN:NN_OR_IP-ADDRESS:NN|all>] [json]", |
e3e29b32 LB |
2418 | SHOW_STR |
2419 | BGP_STR | |
05e588f4 | 2420 | BGP_VPNVX_HELP_STR |
e3e29b32 | 2421 | "Display VPN NLRI specific information\n" |
af8528fa | 2422 | "Display VPN NLRI specific information\n" |
e3e29b32 LB |
2423 | "Display information for a route distinguisher\n" |
2424 | "VPN Route Distinguisher\n" | |
a111dd97 | 2425 | "All VPN Route Distinguishers\n" |
e3e29b32 LB |
2426 | JSON_STR) |
2427 | { | |
d62a17ae | 2428 | int ret; |
2429 | struct prefix_rd prd; | |
2430 | afi_t afi; | |
2431 | int idx = 0; | |
2432 | ||
2433 | if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
2434 | /* Constrain search if user supplies RD && RD != "all" */ |
2435 | if (argv_find(argv, argc, "rd", &idx) | |
2436 | && strcmp(argv[idx + 1]->arg, "all")) { | |
a4d82a8a | 2437 | ret = str2prefix_rd(argv[idx + 1]->arg, &prd); |
d62a17ae | 2438 | if (!ret) { |
2439 | vty_out(vty, | |
2440 | "%% Malformed Route Distinguisher\n"); | |
2441 | return CMD_WARNING; | |
2442 | } | |
2443 | return bgp_show_mpls_vpn(vty, afi, &prd, | |
2444 | bgp_show_type_normal, NULL, 0, | |
2445 | use_json(argc, argv)); | |
2446 | } else { | |
2447 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
2448 | bgp_show_type_normal, NULL, 0, | |
2449 | use_json(argc, argv)); | |
2450 | } | |
2451 | } | |
2452 | return CMD_SUCCESS; | |
718e3744 | 2453 | } |
2454 | ||
af8528fa LB |
2455 | ALIAS(show_bgp_ip_vpn_all_rd, |
2456 | show_bgp_ip_vpn_rd_cmd, | |
a111dd97 | 2457 | "show bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> [json]", |
af8528fa LB |
2458 | SHOW_STR |
2459 | BGP_STR | |
2460 | BGP_VPNVX_HELP_STR | |
2461 | "Display VPN NLRI specific information\n" | |
2462 | "Display information for a route distinguisher\n" | |
2463 | "VPN Route Distinguisher\n" | |
a111dd97 | 2464 | "All VPN Route Distinguishers\n" |
af8528fa LB |
2465 | JSON_STR) |
2466 | ||
2467 | #ifdef KEEP_OLD_VPN_COMMANDS | |
3f227172 PG |
2468 | DEFUN (show_ip_bgp_vpn_rd, |
2469 | show_ip_bgp_vpn_rd_cmd, | |
a111dd97 | 2470 | "show ip bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all>", |
718e3744 | 2471 | SHOW_STR |
2472 | IP_STR | |
2473 | BGP_STR | |
4f280b15 | 2474 | BGP_AFI_HELP_STR |
3517059b | 2475 | "Address Family modifier\n" |
718e3744 | 2476 | "Display information for a route distinguisher\n" |
a111dd97 TA |
2477 | "VPN Route Distinguisher\n" |
2478 | "All VPN Route Distinguishers\n") | |
718e3744 | 2479 | { |
d62a17ae | 2480 | int idx_ext_community = argc - 1; |
2481 | int ret; | |
2482 | struct prefix_rd prd; | |
2483 | afi_t afi; | |
2484 | int idx = 0; | |
2485 | ||
2486 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
2487 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
2488 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
2489 | bgp_show_type_normal, NULL, 0, | |
2490 | 0); | |
d62a17ae | 2491 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); |
2492 | if (!ret) { | |
2493 | vty_out(vty, "%% Malformed Route Distinguisher\n"); | |
2494 | return CMD_WARNING; | |
2495 | } | |
2496 | return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal, | |
2497 | NULL, 0, 0); | |
2498 | } | |
2499 | return CMD_SUCCESS; | |
2500 | } | |
718e3744 | 2501 | |
4f280b15 LB |
2502 | DEFUN (show_ip_bgp_vpn_all, |
2503 | show_ip_bgp_vpn_all_cmd, | |
2504 | "show [ip] bgp <vpnv4|vpnv6>", | |
2505 | SHOW_STR | |
2506 | IP_STR | |
2507 | BGP_STR | |
2508 | BGP_VPNVX_HELP_STR) | |
2509 | { | |
d62a17ae | 2510 | afi_t afi; |
2511 | int idx = 0; | |
4f280b15 | 2512 | |
d62a17ae | 2513 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) |
2514 | return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal, | |
2515 | NULL, 0, 0); | |
2516 | return CMD_SUCCESS; | |
4f280b15 LB |
2517 | } |
2518 | ||
3f227172 PG |
2519 | DEFUN (show_ip_bgp_vpn_all_tags, |
2520 | show_ip_bgp_vpn_all_tags_cmd, | |
2521 | "show [ip] bgp <vpnv4|vpnv6> all tags", | |
718e3744 | 2522 | SHOW_STR |
2523 | IP_STR | |
2524 | BGP_STR | |
3f227172 PG |
2525 | BGP_VPNVX_HELP_STR |
2526 | "Display information about all VPNv4/VPNV6 NLRIs\n" | |
718e3744 | 2527 | "Display BGP tags for prefixes\n") |
2528 | { | |
d62a17ae | 2529 | afi_t afi; |
2530 | int idx = 0; | |
3f227172 | 2531 | |
d62a17ae | 2532 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) |
2533 | return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal, | |
2534 | NULL, 1, 0); | |
2535 | return CMD_SUCCESS; | |
718e3744 | 2536 | } |
2537 | ||
3f227172 PG |
2538 | DEFUN (show_ip_bgp_vpn_rd_tags, |
2539 | show_ip_bgp_vpn_rd_tags_cmd, | |
a111dd97 | 2540 | "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> tags", |
718e3744 | 2541 | SHOW_STR |
2542 | IP_STR | |
2543 | BGP_STR | |
3f227172 | 2544 | BGP_VPNVX_HELP_STR |
718e3744 | 2545 | "Display information for a route distinguisher\n" |
2546 | "VPN Route Distinguisher\n" | |
a111dd97 | 2547 | "All VPN Route Distinguishers\n" |
718e3744 | 2548 | "Display BGP tags for prefixes\n") |
2549 | { | |
d62a17ae | 2550 | int idx_ext_community = 5; |
2551 | int ret; | |
2552 | struct prefix_rd prd; | |
2553 | afi_t afi; | |
2554 | int idx = 0; | |
2555 | ||
2556 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
2557 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
2558 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
2559 | bgp_show_type_normal, NULL, 1, | |
2560 | 0); | |
d62a17ae | 2561 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); |
2562 | if (!ret) { | |
2563 | vty_out(vty, "%% Malformed Route Distinguisher\n"); | |
2564 | return CMD_WARNING; | |
2565 | } | |
2566 | return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal, | |
2567 | NULL, 1, 0); | |
2568 | } | |
2569 | return CMD_SUCCESS; | |
718e3744 | 2570 | } |
2571 | ||
3f227172 PG |
2572 | DEFUN (show_ip_bgp_vpn_all_neighbor_routes, |
2573 | show_ip_bgp_vpn_all_neighbor_routes_cmd, | |
2574 | "show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D routes [json]", | |
718e3744 | 2575 | SHOW_STR |
2576 | IP_STR | |
2577 | BGP_STR | |
3f227172 PG |
2578 | BGP_VPNVX_HELP_STR |
2579 | "Display information about all VPNv4/VPNv6 NLRIs\n" | |
718e3744 | 2580 | "Detailed information on TCP and BGP neighbor connections\n" |
2581 | "Neighbor to display information about\n" | |
856ca177 | 2582 | "Display routes learned from neighbor\n" |
9973d184 | 2583 | JSON_STR) |
718e3744 | 2584 | { |
d62a17ae | 2585 | int idx_ipv4 = 6; |
2586 | union sockunion su; | |
2587 | struct peer *peer; | |
2588 | int ret; | |
9f049418 | 2589 | bool uj = use_json(argc, argv); |
d62a17ae | 2590 | afi_t afi; |
2591 | int idx = 0; | |
2592 | ||
2593 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
2594 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
2595 | if (ret < 0) { | |
2596 | if (uj) { | |
2597 | json_object *json_no = NULL; | |
2598 | json_no = json_object_new_object(); | |
2599 | json_object_string_add(json_no, "warning", | |
2600 | "Malformed address"); | |
2601 | vty_out(vty, "%s\n", | |
2602 | json_object_to_json_string(json_no)); | |
2603 | json_object_free(json_no); | |
2604 | } else | |
2605 | vty_out(vty, "Malformed address: %s\n", | |
2606 | argv[idx_ipv4]->arg); | |
2607 | return CMD_WARNING; | |
2608 | } | |
2609 | ||
2610 | peer = peer_lookup(NULL, &su); | |
2611 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
2612 | if (uj) { | |
2613 | json_object *json_no = NULL; | |
2614 | json_no = json_object_new_object(); | |
2615 | json_object_string_add( | |
2616 | json_no, "warning", | |
2617 | "No such neighbor or address family"); | |
2618 | vty_out(vty, "%s\n", | |
2619 | json_object_to_json_string(json_no)); | |
2620 | json_object_free(json_no); | |
2621 | } else | |
2622 | vty_out(vty, | |
2623 | "%% No such neighbor or address family\n"); | |
2624 | return CMD_WARNING; | |
2625 | } | |
2626 | ||
2627 | return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_neighbor, | |
2628 | &su, 0, uj); | |
2629 | } | |
2630 | return CMD_SUCCESS; | |
718e3744 | 2631 | } |
2632 | ||
3f227172 PG |
2633 | DEFUN (show_ip_bgp_vpn_rd_neighbor_routes, |
2634 | show_ip_bgp_vpn_rd_neighbor_routes_cmd, | |
a111dd97 | 2635 | "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D routes [json]", |
718e3744 | 2636 | SHOW_STR |
2637 | IP_STR | |
2638 | BGP_STR | |
3f227172 | 2639 | BGP_VPNVX_HELP_STR |
718e3744 | 2640 | "Display information for a route distinguisher\n" |
2641 | "VPN Route Distinguisher\n" | |
a111dd97 | 2642 | "All VPN Route Distinguishers\n" |
718e3744 | 2643 | "Detailed information on TCP and BGP neighbor connections\n" |
2644 | "Neighbor to display information about\n" | |
856ca177 | 2645 | "Display routes learned from neighbor\n" |
9973d184 | 2646 | JSON_STR) |
718e3744 | 2647 | { |
d62a17ae | 2648 | int idx_ext_community = 5; |
2649 | int idx_ipv4 = 7; | |
2650 | int ret; | |
2651 | union sockunion su; | |
2652 | struct peer *peer; | |
2653 | struct prefix_rd prd; | |
a111dd97 | 2654 | bool prefix_rd_all = false; |
9f049418 | 2655 | bool uj = use_json(argc, argv); |
d62a17ae | 2656 | afi_t afi; |
2657 | int idx = 0; | |
2658 | ||
2659 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
2660 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
2661 | prefix_rd_all = true; | |
2662 | else { | |
2663 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); | |
2664 | if (!ret) { | |
2665 | if (uj) { | |
2666 | json_object *json_no = NULL; | |
2667 | json_no = json_object_new_object(); | |
2668 | json_object_string_add( | |
2669 | json_no, "warning", | |
2670 | "Malformed Route Distinguisher"); | |
2671 | vty_out(vty, "%s\n", | |
2672 | json_object_to_json_string( | |
2673 | json_no)); | |
2674 | json_object_free(json_no); | |
2675 | } else | |
2676 | vty_out(vty, | |
2677 | "%% Malformed Route Distinguisher\n"); | |
2678 | return CMD_WARNING; | |
2679 | } | |
d62a17ae | 2680 | } |
2681 | ||
2682 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
2683 | if (ret < 0) { | |
2684 | if (uj) { | |
2685 | json_object *json_no = NULL; | |
2686 | json_no = json_object_new_object(); | |
2687 | json_object_string_add(json_no, "warning", | |
2688 | "Malformed address"); | |
2689 | vty_out(vty, "%s\n", | |
2690 | json_object_to_json_string(json_no)); | |
2691 | json_object_free(json_no); | |
2692 | } else | |
2693 | vty_out(vty, "Malformed address: %s\n", | |
2694 | argv[idx_ext_community]->arg); | |
2695 | return CMD_WARNING; | |
2696 | } | |
2697 | ||
2698 | peer = peer_lookup(NULL, &su); | |
2699 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
2700 | if (uj) { | |
2701 | json_object *json_no = NULL; | |
2702 | json_no = json_object_new_object(); | |
2703 | json_object_string_add( | |
2704 | json_no, "warning", | |
2705 | "No such neighbor or address family"); | |
2706 | vty_out(vty, "%s\n", | |
2707 | json_object_to_json_string(json_no)); | |
2708 | json_object_free(json_no); | |
2709 | } else | |
2710 | vty_out(vty, | |
2711 | "%% No such neighbor or address family\n"); | |
2712 | return CMD_WARNING; | |
2713 | } | |
2714 | ||
a111dd97 TA |
2715 | if (prefix_rd_all) |
2716 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
2717 | bgp_show_type_neighbor, &su, 0, | |
2718 | uj); | |
2719 | else | |
2720 | return bgp_show_mpls_vpn(vty, afi, &prd, | |
2721 | bgp_show_type_neighbor, &su, 0, | |
2722 | uj); | |
d62a17ae | 2723 | } |
2724 | return CMD_SUCCESS; | |
718e3744 | 2725 | } |
2726 | ||
3f227172 PG |
2727 | DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes, |
2728 | show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd, | |
2729 | "show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D advertised-routes [json]", | |
718e3744 | 2730 | SHOW_STR |
2731 | IP_STR | |
2732 | BGP_STR | |
3f227172 PG |
2733 | BGP_VPNVX_HELP_STR |
2734 | "Display information about all VPNv4/VPNv6 NLRIs\n" | |
718e3744 | 2735 | "Detailed information on TCP and BGP neighbor connections\n" |
2736 | "Neighbor to display information about\n" | |
856ca177 | 2737 | "Display the routes advertised to a BGP neighbor\n" |
9973d184 | 2738 | JSON_STR) |
718e3744 | 2739 | { |
d62a17ae | 2740 | int idx_ipv4 = 6; |
2741 | int ret; | |
2742 | struct peer *peer; | |
2743 | union sockunion su; | |
9f049418 | 2744 | bool uj = use_json(argc, argv); |
d62a17ae | 2745 | afi_t afi; |
2746 | int idx = 0; | |
2747 | ||
2748 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
2749 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
2750 | if (ret < 0) { | |
2751 | if (uj) { | |
2752 | json_object *json_no = NULL; | |
2753 | json_no = json_object_new_object(); | |
2754 | json_object_string_add(json_no, "warning", | |
2755 | "Malformed address"); | |
2756 | vty_out(vty, "%s\n", | |
2757 | json_object_to_json_string(json_no)); | |
2758 | json_object_free(json_no); | |
2759 | } else | |
2760 | vty_out(vty, "Malformed address: %s\n", | |
2761 | argv[idx_ipv4]->arg); | |
2762 | return CMD_WARNING; | |
2763 | } | |
2764 | peer = peer_lookup(NULL, &su); | |
2765 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
2766 | if (uj) { | |
2767 | json_object *json_no = NULL; | |
2768 | json_no = json_object_new_object(); | |
2769 | json_object_string_add( | |
2770 | json_no, "warning", | |
2771 | "No such neighbor or address family"); | |
2772 | vty_out(vty, "%s\n", | |
2773 | json_object_to_json_string(json_no)); | |
2774 | json_object_free(json_no); | |
2775 | } else | |
2776 | vty_out(vty, | |
2777 | "%% No such neighbor or address family\n"); | |
2778 | return CMD_WARNING; | |
2779 | } | |
2780 | return show_adj_route_vpn(vty, peer, NULL, AFI_IP, | |
2781 | SAFI_MPLS_VPN, uj); | |
2782 | } | |
2783 | return CMD_SUCCESS; | |
718e3744 | 2784 | } |
2785 | ||
3f227172 PG |
2786 | DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, |
2787 | show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd, | |
a111dd97 | 2788 | "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D advertised-routes [json]", |
718e3744 | 2789 | SHOW_STR |
2790 | IP_STR | |
2791 | BGP_STR | |
3f227172 | 2792 | BGP_VPNVX_HELP_STR |
718e3744 | 2793 | "Display information for a route distinguisher\n" |
2794 | "VPN Route Distinguisher\n" | |
a111dd97 | 2795 | "All VPN Route Distinguishers\n" |
718e3744 | 2796 | "Detailed information on TCP and BGP neighbor connections\n" |
2797 | "Neighbor to display information about\n" | |
856ca177 | 2798 | "Display the routes advertised to a BGP neighbor\n" |
9973d184 | 2799 | JSON_STR) |
718e3744 | 2800 | { |
d62a17ae | 2801 | int idx_ext_community = 5; |
2802 | int idx_ipv4 = 7; | |
2803 | int ret; | |
2804 | struct peer *peer; | |
2805 | struct prefix_rd prd; | |
2806 | union sockunion su; | |
9f049418 | 2807 | bool uj = use_json(argc, argv); |
d62a17ae | 2808 | afi_t afi; |
2809 | int idx = 0; | |
2810 | ||
2811 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
2812 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
2813 | if (ret < 0) { | |
2814 | if (uj) { | |
2815 | json_object *json_no = NULL; | |
2816 | json_no = json_object_new_object(); | |
2817 | json_object_string_add(json_no, "warning", | |
2818 | "Malformed address"); | |
2819 | vty_out(vty, "%s\n", | |
2820 | json_object_to_json_string(json_no)); | |
2821 | json_object_free(json_no); | |
2822 | } else | |
2823 | vty_out(vty, "Malformed address: %s\n", | |
2824 | argv[idx_ext_community]->arg); | |
2825 | return CMD_WARNING; | |
2826 | } | |
2827 | peer = peer_lookup(NULL, &su); | |
2828 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
2829 | if (uj) { | |
2830 | json_object *json_no = NULL; | |
2831 | json_no = json_object_new_object(); | |
2832 | json_object_string_add( | |
2833 | json_no, "warning", | |
2834 | "No such neighbor or address family"); | |
2835 | vty_out(vty, "%s\n", | |
2836 | json_object_to_json_string(json_no)); | |
2837 | json_object_free(json_no); | |
2838 | } else | |
2839 | vty_out(vty, | |
2840 | "%% No such neighbor or address family\n"); | |
2841 | return CMD_WARNING; | |
2842 | } | |
2843 | ||
a111dd97 TA |
2844 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
2845 | return show_adj_route_vpn(vty, peer, NULL, AFI_IP, | |
2846 | SAFI_MPLS_VPN, uj); | |
d62a17ae | 2847 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); |
2848 | if (!ret) { | |
2849 | if (uj) { | |
2850 | json_object *json_no = NULL; | |
2851 | json_no = json_object_new_object(); | |
2852 | json_object_string_add( | |
2853 | json_no, "warning", | |
2854 | "Malformed Route Distinguisher"); | |
2855 | vty_out(vty, "%s\n", | |
2856 | json_object_to_json_string(json_no)); | |
2857 | json_object_free(json_no); | |
2858 | } else | |
2859 | vty_out(vty, | |
2860 | "%% Malformed Route Distinguisher\n"); | |
2861 | return CMD_WARNING; | |
2862 | } | |
2863 | ||
2864 | return show_adj_route_vpn(vty, peer, &prd, AFI_IP, | |
2865 | SAFI_MPLS_VPN, uj); | |
2866 | } | |
2867 | return CMD_SUCCESS; | |
718e3744 | 2868 | } |
d6902373 | 2869 | #endif /* KEEP_OLD_VPN_COMMANDS */ |
718e3744 | 2870 | |
d62a17ae | 2871 | void bgp_mplsvpn_init(void) |
718e3744 | 2872 | { |
d62a17ae | 2873 | install_element(BGP_VPNV4_NODE, &vpnv4_network_cmd); |
2874 | install_element(BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd); | |
2875 | install_element(BGP_VPNV4_NODE, &no_vpnv4_network_cmd); | |
718e3744 | 2876 | |
d62a17ae | 2877 | install_element(BGP_VPNV6_NODE, &vpnv6_network_cmd); |
2878 | install_element(BGP_VPNV6_NODE, &no_vpnv6_network_cmd); | |
c286be96 | 2879 | |
d62a17ae | 2880 | install_element(VIEW_NODE, &show_bgp_ip_vpn_all_rd_cmd); |
af8528fa | 2881 | install_element(VIEW_NODE, &show_bgp_ip_vpn_rd_cmd); |
d6902373 | 2882 | #ifdef KEEP_OLD_VPN_COMMANDS |
af8528fa | 2883 | install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_cmd); |
d62a17ae | 2884 | install_element(VIEW_NODE, &show_ip_bgp_vpn_all_cmd); |
2885 | install_element(VIEW_NODE, &show_ip_bgp_vpn_all_tags_cmd); | |
2886 | install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_tags_cmd); | |
2887 | install_element(VIEW_NODE, &show_ip_bgp_vpn_all_neighbor_routes_cmd); | |
2888 | install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_neighbor_routes_cmd); | |
2889 | install_element(VIEW_NODE, | |
2890 | &show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd); | |
2891 | install_element(VIEW_NODE, | |
2892 | &show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd); | |
d6902373 | 2893 | #endif /* KEEP_OLD_VPN_COMMANDS */ |
718e3744 | 2894 | } |
301ad80a PG |
2895 | |
2896 | vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey) | |
2897 | { | |
2898 | struct listnode *mnode, *mnnode; | |
2899 | struct bgp *bgp; | |
9a659715 PG |
2900 | afi_t afi = AFI_IP; |
2901 | ||
2902 | if (eckey->unit_size == IPV6_ECOMMUNITY_SIZE) | |
2903 | afi = AFI_IP6; | |
301ad80a PG |
2904 | |
2905 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { | |
2906 | struct ecommunity *ec; | |
2907 | ||
2908 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
2909 | continue; | |
2910 | ||
9a659715 PG |
2911 | ec = bgp->vpn_policy[afi].import_redirect_rtlist; |
2912 | ||
2913 | if (ec && eckey->unit_size != ec->unit_size) | |
2914 | continue; | |
301ad80a PG |
2915 | |
2916 | if (ecom_intersect(ec, eckey)) | |
2917 | return bgp->vrf_id; | |
2918 | } | |
2919 | return VRF_UNKNOWN; | |
2920 | } | |
3bd70bf8 PZ |
2921 | |
2922 | /* | |
2923 | * The purpose of this function is to process leaks that were deferred | |
2924 | * from earlier per-vrf configuration due to not-yet-existing default | |
2925 | * vrf, in other words, configuration such as: | |
2926 | * | |
2927 | * router bgp MMM vrf FOO | |
2928 | * address-family ipv4 unicast | |
2929 | * rd vpn export 1:1 | |
2930 | * exit-address-family | |
2931 | * | |
2932 | * router bgp NNN | |
2933 | * ... | |
2934 | * | |
2935 | * This function gets called when the default instance ("router bgp NNN") | |
2936 | * is created. | |
2937 | */ | |
2938 | void vpn_leak_postchange_all(void) | |
2939 | { | |
2940 | struct listnode *next; | |
2941 | struct bgp *bgp; | |
2942 | struct bgp *bgp_default = bgp_get_default(); | |
2943 | ||
2944 | assert(bgp_default); | |
2945 | ||
2946 | /* First, do any exporting from VRFs to the single VPN RIB */ | |
2947 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { | |
2948 | ||
2949 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
2950 | continue; | |
2951 | ||
2952 | vpn_leak_postchange( | |
2953 | BGP_VPN_POLICY_DIR_TOVPN, | |
2954 | AFI_IP, | |
2955 | bgp_default, | |
2956 | bgp); | |
2957 | ||
2958 | vpn_leak_postchange( | |
2959 | BGP_VPN_POLICY_DIR_TOVPN, | |
2960 | AFI_IP6, | |
2961 | bgp_default, | |
2962 | bgp); | |
2963 | } | |
2964 | ||
2965 | /* Now, do any importing to VRFs from the single VPN RIB */ | |
2966 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { | |
2967 | ||
2968 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
2969 | continue; | |
2970 | ||
2971 | vpn_leak_postchange( | |
2972 | BGP_VPN_POLICY_DIR_FROMVPN, | |
2973 | AFI_IP, | |
2974 | bgp_default, | |
2975 | bgp); | |
2976 | ||
2977 | vpn_leak_postchange( | |
2978 | BGP_VPN_POLICY_DIR_FROMVPN, | |
2979 | AFI_IP6, | |
2980 | bgp_default, | |
2981 | bgp); | |
2982 | } | |
2983 | } | |
9ecf931b CS |
2984 | |
2985 | /* When a bgp vrf instance is unconfigured, remove its routes | |
2986 | * from the VPN table and this vrf could be importing routes from other | |
2987 | * bgp vrf instnaces, unimport them. | |
2988 | * VRF X and VRF Y are exporting routes to each other. | |
2989 | * When VRF X is deleted, unimport its routes from all target vrfs, | |
2990 | * also VRF Y should unimport its routes from VRF X table. | |
2991 | * This will ensure VPN table is cleaned up appropriately. | |
2992 | */ | |
ff8a8a7a | 2993 | void bgp_vpn_leak_unimport(struct bgp *from_bgp) |
9ecf931b CS |
2994 | { |
2995 | struct bgp *to_bgp; | |
2996 | const char *tmp_name; | |
2997 | char *vname; | |
2998 | struct listnode *node, *next; | |
2999 | safi_t safi = SAFI_UNICAST; | |
3000 | afi_t afi; | |
3001 | bool is_vrf_leak_bind; | |
3002 | int debug; | |
3003 | ||
3004 | if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
ff8a8a7a | 3005 | return; |
9ecf931b CS |
3006 | |
3007 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | | |
3008 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
3009 | ||
3010 | tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; | |
3011 | ||
3012 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
3013 | /* vrf leak is for IPv4 and IPv6 Unicast only */ | |
3014 | if (afi != AFI_IP && afi != AFI_IP6) | |
3015 | continue; | |
3016 | ||
3017 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) { | |
3018 | if (from_bgp == to_bgp) | |
3019 | continue; | |
3020 | ||
3021 | /* Unimport and remove source vrf from the | |
3022 | * other vrfs import list. | |
3023 | */ | |
3024 | struct vpn_policy *to_vpolicy; | |
3025 | ||
3026 | is_vrf_leak_bind = false; | |
3027 | to_vpolicy = &(to_bgp->vpn_policy[afi]); | |
3028 | for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, node, | |
3029 | vname)) { | |
3030 | if (strcmp(vname, tmp_name) == 0) { | |
3031 | is_vrf_leak_bind = true; | |
3032 | break; | |
3033 | } | |
3034 | } | |
3035 | /* skip this bgp instance as there is no leak to this | |
3036 | * vrf instance. | |
3037 | */ | |
3038 | if (!is_vrf_leak_bind) | |
3039 | continue; | |
3040 | ||
3041 | if (debug) | |
3042 | zlog_debug("%s: unimport routes from %s to_bgp %s afi %s import vrfs count %u", | |
3043 | __func__, from_bgp->name_pretty, | |
3044 | to_bgp->name_pretty, afi2str(afi), | |
3045 | to_vpolicy->import_vrf->count); | |
3046 | ||
3047 | vrf_unimport_from_vrf(to_bgp, from_bgp, afi, safi); | |
3048 | ||
3049 | /* readd vrf name as unimport removes import vrf name | |
3050 | * from the destination vrf's import list where the | |
3051 | * `import vrf` configuration still exist. | |
3052 | */ | |
3053 | vname = XSTRDUP(MTYPE_TMP, tmp_name); | |
3054 | listnode_add(to_bgp->vpn_policy[afi].import_vrf, | |
3055 | vname); | |
3056 | SET_FLAG(to_bgp->af_flags[afi][safi], | |
3057 | BGP_CONFIG_VRF_TO_VRF_IMPORT); | |
3058 | ||
3059 | /* If to_bgp exports its routes to the bgp vrf | |
3060 | * which is being deleted, un-import the | |
3061 | * to_bgp routes from VPN. | |
3062 | */ | |
3063 | for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi] | |
3064 | .export_vrf, node, | |
3065 | vname)) { | |
3066 | if (strcmp(vname, tmp_name) == 0) { | |
3067 | vrf_unimport_from_vrf(from_bgp, to_bgp, | |
3068 | afi, safi); | |
3069 | break; | |
3070 | } | |
3071 | } | |
3072 | } | |
3073 | } | |
ff8a8a7a | 3074 | return; |
9ecf931b | 3075 | } |
48381346 CS |
3076 | |
3077 | /* When a router bgp is configured, there could be a bgp vrf | |
3078 | * instance importing routes from this newly configured | |
3079 | * bgp vrf instance. Export routes from configured | |
3080 | * bgp vrf to VPN. | |
3081 | * VRF Y has import from bgp vrf x, | |
3082 | * when a bgp vrf x instance is created, export its routes | |
3083 | * to VRF Y instance. | |
3084 | */ | |
3085 | void bgp_vpn_leak_export(struct bgp *from_bgp) | |
3086 | { | |
3087 | afi_t afi; | |
3088 | const char *export_name; | |
3089 | char *vname; | |
3090 | struct listnode *node, *next; | |
3091 | struct ecommunity *ecom; | |
3092 | vpn_policy_direction_t idir, edir; | |
3093 | safi_t safi = SAFI_UNICAST; | |
3094 | struct bgp *to_bgp; | |
3095 | int debug; | |
3096 | ||
3097 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | | |
3098 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
3099 | ||
3100 | idir = BGP_VPN_POLICY_DIR_FROMVPN; | |
3101 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
3102 | ||
00d968c4 | 3103 | export_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; |
48381346 CS |
3104 | |
3105 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
3106 | /* vrf leak is for IPv4 and IPv6 Unicast only */ | |
3107 | if (afi != AFI_IP && afi != AFI_IP6) | |
3108 | continue; | |
3109 | ||
3110 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) { | |
3111 | if (from_bgp == to_bgp) | |
3112 | continue; | |
3113 | ||
3114 | /* bgp instance has import list, check to see if newly | |
3115 | * configured bgp instance is the list. | |
3116 | */ | |
3117 | struct vpn_policy *to_vpolicy; | |
3118 | ||
3119 | to_vpolicy = &(to_bgp->vpn_policy[afi]); | |
3120 | for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, | |
3121 | node, vname)) { | |
3122 | if (strcmp(vname, export_name) != 0) | |
3123 | continue; | |
3124 | ||
3125 | if (debug) | |
3126 | zlog_debug("%s: found from_bgp %s in to_bgp %s import list, import routes.", | |
3127 | __func__, | |
3128 | export_name, to_bgp->name_pretty); | |
3129 | ||
3130 | ecom = from_bgp->vpn_policy[afi].rtlist[edir]; | |
3131 | /* remove import rt, it will be readded | |
3132 | * as part of import from vrf. | |
3133 | */ | |
3134 | if (ecom) | |
3135 | ecommunity_del_val( | |
3136 | to_vpolicy->rtlist[idir], | |
3137 | (struct ecommunity_val *) | |
3138 | ecom->val); | |
3139 | vrf_import_from_vrf(to_bgp, from_bgp, | |
3140 | afi, safi); | |
3141 | break; | |
3142 | ||
3143 | } | |
3144 | } | |
3145 | } | |
3146 | } |