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