]>
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 | |
882d7b81 PG |
1119 | * nexthop tracking, unless MPLS allocation per nexthop is |
1120 | * performed. In the default case nexthop tracking does not apply, | |
1121 | * if those routes are subsequently imported to other RIBs within | |
1122 | * BGP, the leaked routes do not carry the original | |
1123 | * BGP_ROUTE_REDISTRIBUTE sub_type. Therefore, in order to determine | |
1124 | * if the route we are currently leaking should have nexthop | |
1125 | * tracking, we must find the ultimate parent so we can check its | |
1126 | * sub_type. | |
f46d45c1 | 1127 | * |
40381db7 | 1128 | * As of now, source_bpi may at most be a second-generation route |
f46d45c1 PZ |
1129 | * (only one hop back to ultimate parent for vrf-vpn-vrf scheme). |
1130 | * Using a loop here supports more complex intra-bgp import-export | |
1131 | * schemes that could be implemented in the future. | |
3bd70bf8 | 1132 | * |
f46d45c1 | 1133 | */ |
f46d45c1 | 1134 | |
ddb5b488 PZ |
1135 | /* |
1136 | * match parent | |
1137 | */ | |
9bcb3eef | 1138 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { |
40381db7 | 1139 | if (bpi->extra && bpi->extra->parent == parent) |
ddb5b488 PZ |
1140 | break; |
1141 | } | |
1142 | ||
40381db7 DS |
1143 | if (bpi) { |
1144 | bool labelssame = labels_same(bpi, label, num_labels); | |
e37fb4bf | 1145 | |
8fac400c AR |
1146 | if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) |
1147 | && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { | |
1148 | if (debug) { | |
1149 | zlog_debug( | |
1150 | "%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, being removed, not leaking", | |
02212dee | 1151 | __func__, to_bgp->name_pretty, |
8fac400c AR |
1152 | source_bpi->flags, bpi->flags, p); |
1153 | } | |
1154 | return NULL; | |
1155 | } | |
1156 | ||
40381db7 DS |
1157 | if (attrhash_cmp(bpi->attr, new_attr) && labelssame |
1158 | && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { | |
ddb5b488 PZ |
1159 | |
1160 | bgp_attr_unintern(&new_attr); | |
1161 | if (debug) | |
1162 | zlog_debug( | |
56ca3b5b | 1163 | "%s: ->%s: %pBD: Found route, no change", |
02212dee | 1164 | __func__, to_bgp->name_pretty, bn); |
ddb5b488 PZ |
1165 | return NULL; |
1166 | } | |
1167 | ||
3840a819 DA |
1168 | /* If the RT was changed via extended communities as an |
1169 | * import/export list, we should withdraw implicitly the old | |
1170 | * path from VRFs. | |
1171 | * For instance, RT list was modified using route-maps: | |
1172 | * route-map test permit 10 | |
1173 | * set extcommunity rt none | |
1174 | */ | |
1175 | if (CHECK_FLAG(bpi->attr->flag, | |
1176 | ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) && | |
1177 | CHECK_FLAG(new_attr->flag, | |
1178 | ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES))) { | |
1179 | if (!ecommunity_cmp( | |
1180 | bgp_attr_get_ecommunity(bpi->attr), | |
1181 | bgp_attr_get_ecommunity(new_attr))) { | |
1aa2c93e | 1182 | vpn_leak_to_vrf_withdraw(bpi); |
02212dee LS |
1183 | bgp_aggregate_decrement(to_bgp, p, bpi, afi, |
1184 | safi); | |
3840a819 DA |
1185 | bgp_path_info_delete(bn, bpi); |
1186 | } | |
1187 | } | |
1188 | ||
ddb5b488 | 1189 | /* attr is changed */ |
40381db7 | 1190 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_ATTR_CHANGED); |
ddb5b488 PZ |
1191 | |
1192 | /* Rewrite BGP route information. */ | |
40381db7 DS |
1193 | if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) |
1194 | bgp_path_info_restore(bn, bpi); | |
ddb5b488 | 1195 | else |
02212dee | 1196 | bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi); |
40381db7 DS |
1197 | bgp_attr_unintern(&bpi->attr); |
1198 | bpi->attr = new_attr; | |
083ec940 | 1199 | bpi->uptime = monotime(NULL); |
ddb5b488 | 1200 | |
e37fb4bf PZ |
1201 | /* |
1202 | * rewrite labels | |
1203 | */ | |
1204 | if (!labelssame) | |
40381db7 | 1205 | setlabels(bpi, label, num_labels); |
e37fb4bf | 1206 | |
dbcf19b8 HS |
1207 | /* |
1208 | * rewrite sid | |
1209 | */ | |
1210 | if (num_sids) { | |
16f3db2d | 1211 | if (new_attr->srv6_l3vpn) { |
7de4c885 HS |
1212 | setsids(bpi, &new_attr->srv6_l3vpn->sid, |
1213 | num_sids); | |
16f3db2d RS |
1214 | |
1215 | extra = bgp_path_info_extra_get(bpi); | |
1216 | ||
1217 | extra->sid[0].loc_block_len = | |
1218 | new_attr->srv6_l3vpn->loc_block_len; | |
1219 | extra->sid[0].loc_node_len = | |
1220 | new_attr->srv6_l3vpn->loc_node_len; | |
1221 | extra->sid[0].func_len = | |
1222 | new_attr->srv6_l3vpn->func_len; | |
1223 | extra->sid[0].arg_len = | |
1224 | new_attr->srv6_l3vpn->arg_len; | |
ea7cd161 RS |
1225 | extra->sid[0].transposition_len = |
1226 | new_attr->srv6_l3vpn->transposition_len; | |
1227 | extra->sid[0].transposition_offset = | |
1228 | new_attr->srv6_l3vpn | |
1229 | ->transposition_offset; | |
16f3db2d | 1230 | } else if (new_attr->srv6_vpn) |
7de4c885 HS |
1231 | setsids(bpi, &new_attr->srv6_vpn->sid, |
1232 | num_sids); | |
d79ff732 HS |
1233 | } else |
1234 | unsetsids(bpi); | |
dbcf19b8 | 1235 | |
960035b2 | 1236 | if (nexthop_self_flag) |
40381db7 | 1237 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF); |
960035b2 | 1238 | |
46dbf9d0 DA |
1239 | if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) |
1240 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN); | |
1241 | ||
02212dee | 1242 | if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, |
b3e97f08 LS |
1243 | source_bpi, bpi, bgp_orig, p, |
1244 | debug)) | |
659251db LS |
1245 | bgp_path_info_set_flag(bn, bpi, BGP_PATH_VALID); |
1246 | else | |
1247 | bgp_path_info_unset_flag(bn, bpi, BGP_PATH_VALID); | |
960035b2 | 1248 | |
ddb5b488 | 1249 | /* Process change. */ |
02212dee LS |
1250 | bgp_aggregate_increment(to_bgp, p, bpi, afi, safi); |
1251 | bgp_process(to_bgp, bn, afi, safi); | |
9bcb3eef | 1252 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
1253 | |
1254 | if (debug) | |
56ca3b5b | 1255 | zlog_debug("%s: ->%s: %pBD Found route, changed attr", |
02212dee | 1256 | __func__, to_bgp->name_pretty, bn); |
ddb5b488 | 1257 | |
40381db7 | 1258 | return bpi; |
ddb5b488 PZ |
1259 | } |
1260 | ||
8fac400c AR |
1261 | if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED)) { |
1262 | if (debug) { | |
1263 | zlog_debug( | |
1264 | "%s: ->%s(s_flags: 0x%x): %pFX: New route, being removed, not leaking", | |
02212dee | 1265 | __func__, to_bgp->name_pretty, |
8fac400c AR |
1266 | source_bpi->flags, p); |
1267 | } | |
1268 | return NULL; | |
1269 | } | |
1270 | ||
be180f97 | 1271 | new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, |
02212dee | 1272 | to_bgp->peer_self, new_attr, bn); |
960035b2 | 1273 | |
4cd690ae PG |
1274 | if (source_bpi->peer) { |
1275 | extra = bgp_path_info_extra_get(new); | |
1276 | extra->peer_orig = peer_lock(source_bpi->peer); | |
1277 | } | |
1278 | ||
960035b2 | 1279 | if (nexthop_self_flag) |
18ee8310 | 1280 | bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF); |
ddb5b488 | 1281 | |
46dbf9d0 DA |
1282 | if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN)) |
1283 | bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN); | |
1284 | ||
18ee8310 | 1285 | bgp_path_info_extra_get(new); |
4b85140f | 1286 | |
dbcf19b8 HS |
1287 | /* |
1288 | * rewrite sid | |
1289 | */ | |
1290 | if (num_sids) { | |
16f3db2d | 1291 | if (new_attr->srv6_l3vpn) { |
dbcf19b8 | 1292 | setsids(new, &new_attr->srv6_l3vpn->sid, num_sids); |
16f3db2d RS |
1293 | |
1294 | extra = bgp_path_info_extra_get(new); | |
1295 | ||
1296 | extra->sid[0].loc_block_len = | |
1297 | new_attr->srv6_l3vpn->loc_block_len; | |
1298 | extra->sid[0].loc_node_len = | |
1299 | new_attr->srv6_l3vpn->loc_node_len; | |
1300 | extra->sid[0].func_len = new_attr->srv6_l3vpn->func_len; | |
1301 | extra->sid[0].arg_len = new_attr->srv6_l3vpn->arg_len; | |
ea7cd161 RS |
1302 | extra->sid[0].transposition_len = |
1303 | new_attr->srv6_l3vpn->transposition_len; | |
1304 | extra->sid[0].transposition_offset = | |
1305 | new_attr->srv6_l3vpn->transposition_offset; | |
16f3db2d | 1306 | } else if (new_attr->srv6_vpn) |
dbcf19b8 | 1307 | setsids(new, &new_attr->srv6_vpn->sid, num_sids); |
d79ff732 HS |
1308 | } else |
1309 | unsetsids(new); | |
dbcf19b8 | 1310 | |
e37fb4bf PZ |
1311 | if (num_labels) |
1312 | setlabels(new, label, num_labels); | |
1313 | ||
18ee8310 | 1314 | new->extra->parent = bgp_path_info_lock(parent); |
9bcb3eef | 1315 | bgp_dest_lock_node( |
ef96e375 | 1316 | (struct bgp_dest *)parent->net); |
ddb5b488 | 1317 | if (bgp_orig) |
21d88ef7 | 1318 | new->extra->bgp_orig = bgp_lock(bgp_orig); |
ddb5b488 PZ |
1319 | if (nexthop_orig) |
1320 | new->extra->nexthop_orig = *nexthop_orig; | |
1321 | ||
02212dee | 1322 | if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, |
b3e97f08 | 1323 | source_bpi, new, bgp_orig, p, debug)) |
659251db LS |
1324 | bgp_path_info_set_flag(bn, new, BGP_PATH_VALID); |
1325 | else | |
1326 | bgp_path_info_unset_flag(bn, new, BGP_PATH_VALID); | |
960035b2 | 1327 | |
02212dee | 1328 | bgp_aggregate_increment(to_bgp, p, new, afi, safi); |
18ee8310 | 1329 | bgp_path_info_add(bn, new); |
ddb5b488 | 1330 | |
9bcb3eef | 1331 | bgp_dest_unlock_node(bn); |
02212dee | 1332 | bgp_process(to_bgp, bn, afi, safi); |
ddb5b488 PZ |
1333 | |
1334 | if (debug) | |
56ca3b5b | 1335 | zlog_debug("%s: ->%s: %pBD: Added new route", __func__, |
02212dee | 1336 | to_bgp->name_pretty, bn); |
ddb5b488 PZ |
1337 | |
1338 | return new; | |
1339 | } | |
1340 | ||
577be36a PG |
1341 | void bgp_mplsvpn_path_nh_label_unlink(struct bgp_path_info *pi) |
1342 | { | |
1343 | struct bgp_label_per_nexthop_cache *blnc; | |
1344 | ||
1345 | if (!pi) | |
1346 | return; | |
1347 | ||
1348 | blnc = pi->label_nexthop_cache; | |
1349 | ||
1350 | if (!blnc) | |
1351 | return; | |
1352 | ||
1353 | LIST_REMOVE(pi, label_nh_thread); | |
1354 | pi->label_nexthop_cache->path_count--; | |
1355 | pi->label_nexthop_cache = NULL; | |
1356 | ||
1357 | if (LIST_EMPTY(&(blnc->paths))) | |
1358 | bgp_label_per_nexthop_free(blnc); | |
1359 | } | |
1360 | ||
1361 | /* Called upon reception of a ZAPI Message from zebra, about | |
1362 | * a new available label. | |
1363 | */ | |
1364 | static int bgp_mplsvpn_get_label_per_nexthop_cb(mpls_label_t label, | |
1365 | void *context, bool allocated) | |
1366 | { | |
1367 | struct bgp_label_per_nexthop_cache *blnc = context; | |
1368 | mpls_label_t old_label; | |
1369 | int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); | |
1370 | struct bgp_path_info *pi; | |
1371 | struct bgp_table *table; | |
1372 | ||
1373 | old_label = blnc->label; | |
1374 | ||
1375 | if (debug) | |
1376 | zlog_debug("%s: label=%u, allocated=%d, nexthop=%pFX", __func__, | |
1377 | label, allocated, &blnc->nexthop); | |
1378 | if (allocated) | |
1379 | /* update the entry with the new label */ | |
1380 | blnc->label = label; | |
1381 | else | |
1382 | /* | |
1383 | * previously-allocated label is now invalid | |
1384 | * eg: zebra deallocated the labels and notifies it | |
1385 | */ | |
1386 | blnc->label = MPLS_INVALID_LABEL; | |
1387 | ||
1388 | if (old_label == blnc->label) | |
1389 | return 0; /* no change */ | |
1390 | ||
1391 | /* update paths */ | |
1392 | if (blnc->label != MPLS_INVALID_LABEL) | |
1c6aa043 PG |
1393 | bgp_zebra_send_nexthop_label( |
1394 | ZEBRA_MPLS_LABELS_ADD, blnc->label, blnc->nh->ifindex, | |
1395 | blnc->nh->vrf_id, ZEBRA_LSP_BGP, &blnc->nexthop); | |
577be36a PG |
1396 | |
1397 | LIST_FOREACH (pi, &(blnc->paths), label_nh_thread) { | |
1398 | if (!pi->net) | |
1399 | continue; | |
1400 | table = bgp_dest_table(pi->net); | |
1401 | if (!table) | |
1402 | continue; | |
1403 | vpn_leak_from_vrf_update(blnc->to_bgp, table->bgp, pi); | |
1404 | } | |
1405 | ||
1406 | return 0; | |
1407 | } | |
1408 | ||
1409 | /* Get a per label nexthop value: | |
1410 | * - Find and return a per label nexthop from the cache | |
1411 | * - else allocate a new per label nexthop cache entry and request a | |
1412 | * label to zebra. Return MPLS_INVALID_LABEL | |
1413 | */ | |
1414 | static mpls_label_t _vpn_leak_from_vrf_get_per_nexthop_label( | |
1415 | struct bgp_path_info *pi, struct bgp *to_bgp, struct bgp *from_bgp, | |
1416 | afi_t afi, safi_t safi) | |
1417 | { | |
1418 | struct bgp_nexthop_cache *bnc = pi->nexthop; | |
1419 | struct bgp_label_per_nexthop_cache *blnc; | |
1420 | struct bgp_label_per_nexthop_cache_head *tree; | |
1421 | struct prefix *nh_pfx = NULL; | |
1422 | struct prefix nh_gate = {0}; | |
1423 | ||
1424 | /* extract the nexthop from the BNC nexthop cache */ | |
1425 | switch (bnc->nexthop->type) { | |
1426 | case NEXTHOP_TYPE_IPV4: | |
1427 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
1428 | /* the nexthop is recursive */ | |
1429 | nh_gate.family = AF_INET; | |
1430 | nh_gate.prefixlen = IPV4_MAX_BITLEN; | |
1431 | IPV4_ADDR_COPY(&nh_gate.u.prefix4, &bnc->nexthop->gate.ipv4); | |
1432 | nh_pfx = &nh_gate; | |
1433 | break; | |
1434 | case NEXTHOP_TYPE_IPV6: | |
1435 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
1436 | /* the nexthop is recursive */ | |
1437 | nh_gate.family = AF_INET6; | |
1438 | nh_gate.prefixlen = IPV6_MAX_BITLEN; | |
1439 | IPV6_ADDR_COPY(&nh_gate.u.prefix6, &bnc->nexthop->gate.ipv6); | |
1440 | nh_pfx = &nh_gate; | |
1441 | break; | |
1442 | case NEXTHOP_TYPE_IFINDEX: | |
1443 | /* the nexthop is direcly connected */ | |
1444 | nh_pfx = &bnc->prefix; | |
1445 | break; | |
1446 | case NEXTHOP_TYPE_BLACKHOLE: | |
1447 | assert(!"Blackhole nexthop. Already checked by the caller."); | |
1448 | } | |
1449 | ||
1450 | /* find or allocate a nexthop label cache entry */ | |
1451 | tree = &from_bgp->mpls_labels_per_nexthop[family2afi(nh_pfx->family)]; | |
1452 | blnc = bgp_label_per_nexthop_find(tree, nh_pfx); | |
1453 | if (!blnc) { | |
1454 | blnc = bgp_label_per_nexthop_new(tree, nh_pfx); | |
1455 | blnc->to_bgp = to_bgp; | |
1456 | /* request a label to zebra for this nexthop | |
1457 | * the response from zebra will trigger the callback | |
1458 | */ | |
1459 | bgp_lp_get(LP_TYPE_NEXTHOP, blnc, | |
1460 | bgp_mplsvpn_get_label_per_nexthop_cb); | |
1461 | } | |
1462 | ||
1463 | if (pi->label_nexthop_cache == blnc) | |
1464 | /* no change */ | |
1465 | return blnc->label; | |
1466 | ||
1467 | /* Unlink from any existing nexthop cache. Free the entry if unused. | |
1468 | */ | |
1469 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1470 | if (blnc) { | |
1471 | /* updates NHT pi list reference */ | |
1472 | LIST_INSERT_HEAD(&(blnc->paths), pi, label_nh_thread); | |
1473 | pi->label_nexthop_cache = blnc; | |
1474 | pi->label_nexthop_cache->path_count++; | |
60e5bc23 | 1475 | blnc->last_update = monotime(NULL); |
577be36a | 1476 | } |
1c6aa043 PG |
1477 | |
1478 | /* then add or update the selected nexthop */ | |
1479 | if (!blnc->nh) | |
1480 | blnc->nh = nexthop_dup(bnc->nexthop, NULL); | |
1481 | else if (!nexthop_same(bnc->nexthop, blnc->nh)) { | |
1482 | nexthop_free(blnc->nh); | |
1483 | blnc->nh = nexthop_dup(bnc->nexthop, NULL); | |
1484 | if (blnc->label != MPLS_INVALID_LABEL) { | |
1485 | bgp_zebra_send_nexthop_label( | |
1486 | ZEBRA_MPLS_LABELS_REPLACE, blnc->label, | |
1487 | bnc->nexthop->ifindex, bnc->nexthop->vrf_id, | |
1488 | ZEBRA_LSP_BGP, &blnc->nexthop); | |
1489 | } | |
1490 | } | |
1491 | ||
577be36a PG |
1492 | return blnc->label; |
1493 | } | |
1494 | ||
1495 | /* Filter out all the cases where a per nexthop label is not possible: | |
1496 | * - return an invalid label when the nexthop is invalid | |
1497 | * - return the per VRF label when the per nexthop label is not supported | |
1498 | * Otherwise, find or request a per label nexthop. | |
1499 | */ | |
1500 | static mpls_label_t vpn_leak_from_vrf_get_per_nexthop_label( | |
1501 | afi_t afi, safi_t safi, struct bgp_path_info *pi, struct bgp *from_bgp, | |
1502 | struct bgp *to_bgp) | |
1503 | { | |
1504 | struct bgp_path_info *bpi_ultimate = bgp_get_imported_bpi_ultimate(pi); | |
1505 | struct bgp *bgp_nexthop = NULL; | |
1506 | bool nh_valid; | |
1507 | afi_t nh_afi; | |
1508 | bool is_bgp_static_route; | |
1509 | ||
1510 | is_bgp_static_route = bpi_ultimate->sub_type == BGP_ROUTE_STATIC && | |
1511 | bpi_ultimate->type == ZEBRA_ROUTE_BGP; | |
1512 | ||
1513 | if (is_bgp_static_route == false && afi == AFI_IP && | |
1514 | CHECK_FLAG(pi->attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) && | |
1515 | (pi->attr->nexthop.s_addr == INADDR_ANY || | |
1516 | !ipv4_unicast_valid(&pi->attr->nexthop))) { | |
1517 | /* IPv4 nexthop in standard BGP encoding format. | |
1518 | * Format of address is not valid (not any, not unicast). | |
1519 | * Fallback to the per VRF label. | |
1520 | */ | |
1521 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1522 | return from_bgp->vpn_policy[afi].tovpn_label; | |
1523 | } | |
1524 | ||
1525 | if (is_bgp_static_route == false && afi == AFI_IP && | |
1526 | pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4 && | |
1527 | (pi->attr->mp_nexthop_global_in.s_addr == INADDR_ANY || | |
1528 | !ipv4_unicast_valid(&pi->attr->mp_nexthop_global_in))) { | |
1529 | /* IPv4 nexthop is in MP-BGP encoding format. | |
1530 | * Format of address is not valid (not any, not unicast). | |
1531 | * Fallback to the per VRF label. | |
1532 | */ | |
1533 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1534 | return from_bgp->vpn_policy[afi].tovpn_label; | |
1535 | } | |
1536 | ||
1537 | if (is_bgp_static_route == false && afi == AFI_IP6 && | |
1538 | (pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL || | |
1539 | pi->attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) && | |
1540 | (IN6_IS_ADDR_UNSPECIFIED(&pi->attr->mp_nexthop_global) || | |
1541 | IN6_IS_ADDR_LOOPBACK(&pi->attr->mp_nexthop_global) || | |
1542 | IN6_IS_ADDR_MULTICAST(&pi->attr->mp_nexthop_global))) { | |
1543 | /* IPv6 nexthop is in MP-BGP encoding format. | |
1544 | * Format of address is not valid | |
1545 | * Fallback to the per VRF label. | |
1546 | */ | |
1547 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1548 | return from_bgp->vpn_policy[afi].tovpn_label; | |
1549 | } | |
1550 | ||
1551 | /* Check the next-hop reachability. | |
1552 | * Get the bgp instance where the bgp_path_info originates. | |
1553 | */ | |
1554 | if (pi->extra && pi->extra->bgp_orig) | |
1555 | bgp_nexthop = pi->extra->bgp_orig; | |
1556 | else | |
1557 | bgp_nexthop = from_bgp; | |
1558 | ||
1559 | nh_afi = BGP_ATTR_NH_AFI(afi, pi->attr); | |
1560 | nh_valid = bgp_find_or_add_nexthop(from_bgp, bgp_nexthop, nh_afi, safi, | |
1561 | pi, NULL, 0, NULL); | |
1562 | ||
1563 | if (!nh_valid && is_bgp_static_route && | |
1564 | !CHECK_FLAG(from_bgp->flags, BGP_FLAG_IMPORT_CHECK)) { | |
1565 | /* "network" prefixes not routable, but since 'no bgp network | |
1566 | * import-check' is configured, they are always valid in the BGP | |
1567 | * table. Fallback to the per-vrf label | |
1568 | */ | |
1569 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1570 | return from_bgp->vpn_policy[afi].tovpn_label; | |
1571 | } | |
1572 | ||
1573 | if (!nh_valid || !pi->nexthop || pi->nexthop->nexthop_num == 0 || | |
1574 | !pi->nexthop->nexthop) { | |
1575 | /* invalid next-hop: | |
1576 | * do not send the per-vrf label | |
1577 | * otherwise, when the next-hop becomes valid, | |
1578 | * we will have 2 BGP updates: | |
1579 | * - one with the per-vrf label | |
1580 | * - the second with the per-nexthop label | |
1581 | */ | |
1582 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1583 | return MPLS_INVALID_LABEL; | |
1584 | } | |
1585 | ||
1586 | if (pi->nexthop->nexthop_num > 1 || | |
1587 | pi->nexthop->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { | |
1588 | /* Blackhole or ECMP routes | |
1589 | * is not compatible with per-nexthop label. | |
1590 | * Fallback to per-vrf label. | |
1591 | */ | |
1592 | bgp_mplsvpn_path_nh_label_unlink(pi); | |
1593 | return from_bgp->vpn_policy[afi].tovpn_label; | |
1594 | } | |
1595 | ||
1596 | return _vpn_leak_from_vrf_get_per_nexthop_label(pi, to_bgp, from_bgp, | |
1597 | afi, safi); | |
1598 | } | |
1599 | ||
ddb5b488 | 1600 | /* cf vnc_import_bgp_add_route_mode_nvegroup() and add_vnc_route() */ |
02212dee LS |
1601 | void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */ |
1602 | struct bgp *from_bgp, /* from */ | |
40381db7 | 1603 | struct bgp_path_info *path_vrf) /* route */ |
ddb5b488 PZ |
1604 | { |
1605 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
9bcb3eef | 1606 | const struct prefix *p = bgp_dest_get_prefix(path_vrf->net); |
ddb5b488 PZ |
1607 | afi_t afi = family2afi(p->family); |
1608 | struct attr static_attr = {0}; | |
1609 | struct attr *new_attr = NULL; | |
1610 | safi_t safi = SAFI_MPLS_VPN; | |
1611 | mpls_label_t label_val; | |
1612 | mpls_label_t label; | |
9bcb3eef | 1613 | struct bgp_dest *bn; |
ddb5b488 | 1614 | const char *debugmsg; |
960035b2 PZ |
1615 | int nexthop_self_flag = 0; |
1616 | ||
1617 | if (debug) | |
02212dee | 1618 | zlog_debug("%s: from vrf %s", __func__, from_bgp->name_pretty); |
ddb5b488 | 1619 | |
b53e67a3 DA |
1620 | if (debug && bgp_attr_get_ecommunity(path_vrf->attr)) { |
1621 | char *s = ecommunity_ecom2str( | |
1622 | bgp_attr_get_ecommunity(path_vrf->attr), | |
1623 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
ddb5b488 | 1624 | |
40381db7 | 1625 | zlog_debug("%s: %s path_vrf->type=%d, EC{%s}", __func__, |
02212dee | 1626 | from_bgp->name, path_vrf->type, s); |
c8f57349 | 1627 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1628 | } |
1629 | ||
02212dee | 1630 | if (!to_bgp) |
ddb5b488 PZ |
1631 | return; |
1632 | ||
1633 | if (!afi) { | |
1634 | if (debug) | |
1635 | zlog_debug("%s: can't get afi of prefix", __func__); | |
1636 | return; | |
1637 | } | |
1638 | ||
12d6100c | 1639 | /* Is this route exportable into the VPN table? */ |
1640 | if (!is_route_injectable_into_vpn(path_vrf)) | |
ddb5b488 PZ |
1641 | return; |
1642 | ||
02212dee | 1643 | if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) { |
ddb5b488 | 1644 | if (debug) |
12a844a5 | 1645 | zlog_debug("%s: %s skipping: %s", __func__, |
02212dee | 1646 | from_bgp->name, debugmsg); |
ddb5b488 PZ |
1647 | return; |
1648 | } | |
1649 | ||
6f4f49b2 QY |
1650 | /* shallow copy */ |
1651 | static_attr = *path_vrf->attr; | |
ddb5b488 PZ |
1652 | |
1653 | /* | |
1654 | * route map handling | |
1655 | */ | |
02212dee | 1656 | if (from_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN]) { |
4b7e6066 | 1657 | struct bgp_path_info info; |
ddb5b488 PZ |
1658 | route_map_result_t ret; |
1659 | ||
1660 | memset(&info, 0, sizeof(info)); | |
02212dee | 1661 | info.peer = to_bgp->peer_self; |
ddb5b488 | 1662 | info.attr = &static_attr; |
02212dee LS |
1663 | ret = route_map_apply(from_bgp->vpn_policy[afi] |
1664 | .rmap[BGP_VPN_POLICY_DIR_TOVPN], | |
1665 | p, &info); | |
ddb5b488 PZ |
1666 | if (RMAP_DENYMATCH == ret) { |
1667 | bgp_attr_flush(&static_attr); /* free any added parts */ | |
1668 | if (debug) | |
1669 | zlog_debug( | |
1670 | "%s: vrf %s route map \"%s\" says DENY, returning", | |
02212dee LS |
1671 | __func__, from_bgp->name_pretty, |
1672 | from_bgp->vpn_policy[afi] | |
ddb5b488 PZ |
1673 | .rmap[BGP_VPN_POLICY_DIR_TOVPN] |
1674 | ->name); | |
1675 | return; | |
1676 | } | |
1677 | } | |
1678 | ||
b53e67a3 DA |
1679 | if (debug && bgp_attr_get_ecommunity(&static_attr)) { |
1680 | char *s = ecommunity_ecom2str( | |
1681 | bgp_attr_get_ecommunity(&static_attr), | |
1682 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
ddb5b488 | 1683 | |
ddb5b488 PZ |
1684 | zlog_debug("%s: post route map static_attr.ecommunity{%s}", |
1685 | __func__, s); | |
c8f57349 | 1686 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1687 | } |
1688 | ||
1689 | /* | |
1690 | * Add the vpn-policy rt-list | |
1691 | */ | |
1692 | struct ecommunity *old_ecom; | |
1693 | struct ecommunity *new_ecom; | |
1694 | ||
e8bfa90e | 1695 | /* Export with the 'from' instance's export RTs. */ |
1696 | /* If doing VRF-to-VRF leaking, strip existing RTs first. */ | |
b53e67a3 | 1697 | old_ecom = bgp_attr_get_ecommunity(&static_attr); |
ddb5b488 | 1698 | if (old_ecom) { |
e8bfa90e | 1699 | new_ecom = ecommunity_dup(old_ecom); |
02212dee LS |
1700 | if (CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST], |
1701 | BGP_CONFIG_VRF_TO_VRF_EXPORT)) | |
e8bfa90e | 1702 | ecommunity_strip_rts(new_ecom); |
02212dee LS |
1703 | new_ecom = ecommunity_merge( |
1704 | new_ecom, from_bgp->vpn_policy[afi] | |
1705 | .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); | |
ddb5b488 PZ |
1706 | if (!old_ecom->refcnt) |
1707 | ecommunity_free(&old_ecom); | |
1708 | } else { | |
1709 | new_ecom = ecommunity_dup( | |
02212dee | 1710 | from_bgp->vpn_policy[afi] |
ddb5b488 PZ |
1711 | .rtlist[BGP_VPN_POLICY_DIR_TOVPN]); |
1712 | } | |
b53e67a3 | 1713 | bgp_attr_set_ecommunity(&static_attr, new_ecom); |
ddb5b488 | 1714 | |
b53e67a3 DA |
1715 | if (debug && bgp_attr_get_ecommunity(&static_attr)) { |
1716 | char *s = ecommunity_ecom2str( | |
1717 | bgp_attr_get_ecommunity(&static_attr), | |
1718 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
ddb5b488 | 1719 | |
ddb5b488 PZ |
1720 | zlog_debug("%s: post merge static_attr.ecommunity{%s}", |
1721 | __func__, s); | |
c8f57349 | 1722 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1723 | } |
1724 | ||
46dbf9d0 DA |
1725 | community_strip_accept_own(&static_attr); |
1726 | ||
ddb5b488 PZ |
1727 | /* Nexthop */ |
1728 | /* if policy nexthop not set, use 0 */ | |
02212dee | 1729 | if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags, |
ddb5b488 | 1730 | BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) { |
ddb5b488 | 1731 | struct prefix *nexthop = |
02212dee | 1732 | &from_bgp->vpn_policy[afi].tovpn_nexthop; |
12a844a5 | 1733 | |
ddb5b488 PZ |
1734 | switch (nexthop->family) { |
1735 | case AF_INET: | |
1736 | /* prevent mp_nexthop_global_in <- self in bgp_route.c | |
1737 | */ | |
1738 | static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr; | |
1739 | ||
1740 | static_attr.mp_nexthop_global_in = nexthop->u.prefix4; | |
0606039c | 1741 | static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; |
ddb5b488 PZ |
1742 | break; |
1743 | ||
1744 | case AF_INET6: | |
1745 | static_attr.mp_nexthop_global = nexthop->u.prefix6; | |
0606039c | 1746 | static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL; |
ddb5b488 PZ |
1747 | break; |
1748 | ||
1749 | default: | |
1750 | assert(0); | |
1751 | } | |
1752 | } else { | |
02212dee | 1753 | if (!CHECK_FLAG(from_bgp->af_flags[afi][SAFI_UNICAST], |
12a844a5 | 1754 | BGP_CONFIG_VRF_TO_VRF_EXPORT)) { |
f784007d RS |
1755 | if (afi == AFI_IP && |
1756 | !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) { | |
020a3f60 DS |
1757 | /* |
1758 | * For ipv4, copy to multiprotocol | |
1759 | * nexthop field | |
1760 | */ | |
1761 | static_attr.mp_nexthop_global_in = | |
1762 | static_attr.nexthop; | |
0606039c DA |
1763 | static_attr.mp_nexthop_len = |
1764 | BGP_ATTR_NHLEN_IPV4; | |
020a3f60 DS |
1765 | /* |
1766 | * XXX Leave static_attr.nexthop | |
1767 | * intact for NHT | |
1768 | */ | |
1769 | static_attr.flag &= | |
1770 | ~ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); | |
12a844a5 DS |
1771 | } |
1772 | } else { | |
77e62f2b | 1773 | /* Update based on next-hop family to account for |
1774 | * RFC 5549 (BGP unnumbered) scenario. Note that | |
1775 | * specific action is only needed for the case of | |
1776 | * IPv4 nexthops as the attr has been copied | |
1777 | * otherwise. | |
1778 | */ | |
40381db7 DS |
1779 | if (afi == AFI_IP |
1780 | && !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) { | |
12a844a5 DS |
1781 | static_attr.mp_nexthop_global_in.s_addr = |
1782 | static_attr.nexthop.s_addr; | |
0606039c DA |
1783 | static_attr.mp_nexthop_len = |
1784 | BGP_ATTR_NHLEN_IPV4; | |
12a844a5 DS |
1785 | static_attr.flag |= |
1786 | ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); | |
12a844a5 | 1787 | } |
ddb5b488 | 1788 | } |
960035b2 | 1789 | nexthop_self_flag = 1; |
ddb5b488 PZ |
1790 | } |
1791 | ||
577be36a PG |
1792 | if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags, |
1793 | BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) | |
1794 | /* per nexthop label mode */ | |
1795 | label_val = vpn_leak_from_vrf_get_per_nexthop_label( | |
1796 | afi, safi, path_vrf, from_bgp, to_bgp); | |
1797 | else | |
1798 | /* per VRF label mode */ | |
1799 | label_val = from_bgp->vpn_policy[afi].tovpn_label; | |
1800 | ||
1801 | if (label_val == MPLS_INVALID_LABEL && | |
1802 | CHECK_FLAG(from_bgp->vpn_policy[afi].flags, | |
1803 | BGP_VPN_POLICY_TOVPN_LABEL_PER_NEXTHOP)) { | |
1804 | /* no valid label for the moment | |
1805 | * when the 'bgp_mplsvpn_get_label_per_nexthop_cb' callback gets | |
1806 | * a valid label value, it will call the current function again. | |
1807 | */ | |
1808 | if (debug) | |
1809 | zlog_debug( | |
1810 | "%s: %s skipping: waiting for a valid per-label nexthop.", | |
1811 | __func__, from_bgp->name_pretty); | |
1812 | return; | |
1813 | } | |
9fa282ee | 1814 | if (label_val == MPLS_LABEL_NONE) |
291e32c3 | 1815 | encode_label(MPLS_LABEL_IMPLICIT_NULL, &label); |
9fa282ee | 1816 | else |
ddb5b488 | 1817 | encode_label(label_val, &label); |
ddb5b488 PZ |
1818 | |
1819 | /* Set originator ID to "me" */ | |
1820 | SET_FLAG(static_attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)); | |
02212dee | 1821 | static_attr.originator_id = to_bgp->router_id; |
ddb5b488 | 1822 | |
dbcf19b8 | 1823 | /* Set SID for SRv6 VPN */ |
02212dee | 1824 | if (from_bgp->vpn_policy[afi].tovpn_sid_locator) { |
05d99980 CS |
1825 | struct srv6_locator_chunk *locator = |
1826 | from_bgp->vpn_policy[afi].tovpn_sid_locator; | |
02212dee LS |
1827 | encode_label( |
1828 | from_bgp->vpn_policy[afi].tovpn_sid_transpose_label, | |
1829 | &label); | |
dbcf19b8 | 1830 | static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN, |
537b608a | 1831 | sizeof(struct bgp_attr_srv6_l3vpn)); |
dbcf19b8 | 1832 | static_attr.srv6_l3vpn->sid_flags = 0x00; |
05d99980 CS |
1833 | static_attr.srv6_l3vpn->endpoint_behavior = |
1834 | afi == AFI_IP | |
1835 | ? (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID) | |
1836 | ? SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID | |
1837 | : SRV6_ENDPOINT_BEHAVIOR_END_DT4) | |
1838 | : (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID) | |
1839 | ? SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID | |
1840 | : SRV6_ENDPOINT_BEHAVIOR_END_DT6); | |
9299fd00 | 1841 | static_attr.srv6_l3vpn->loc_block_len = |
bee2e7d0 RS |
1842 | from_bgp->vpn_policy[afi] |
1843 | .tovpn_sid_locator->block_bits_length; | |
9299fd00 | 1844 | static_attr.srv6_l3vpn->loc_node_len = |
bee2e7d0 RS |
1845 | from_bgp->vpn_policy[afi] |
1846 | .tovpn_sid_locator->node_bits_length; | |
9299fd00 | 1847 | static_attr.srv6_l3vpn->func_len = |
bee2e7d0 RS |
1848 | from_bgp->vpn_policy[afi] |
1849 | .tovpn_sid_locator->function_bits_length; | |
9299fd00 | 1850 | static_attr.srv6_l3vpn->arg_len = |
bee2e7d0 RS |
1851 | from_bgp->vpn_policy[afi] |
1852 | .tovpn_sid_locator->argument_bits_length; | |
9299fd00 | 1853 | static_attr.srv6_l3vpn->transposition_len = |
bee2e7d0 RS |
1854 | from_bgp->vpn_policy[afi] |
1855 | .tovpn_sid_locator->function_bits_length; | |
9299fd00 | 1856 | static_attr.srv6_l3vpn->transposition_offset = |
bee2e7d0 RS |
1857 | from_bgp->vpn_policy[afi] |
1858 | .tovpn_sid_locator->block_bits_length + | |
1859 | from_bgp->vpn_policy[afi] | |
1860 | .tovpn_sid_locator->node_bits_length; | |
1861 | ; | |
dbcf19b8 | 1862 | memcpy(&static_attr.srv6_l3vpn->sid, |
bee2e7d0 RS |
1863 | &from_bgp->vpn_policy[afi] |
1864 | .tovpn_sid_locator->prefix.prefix, | |
69fe7874 | 1865 | sizeof(struct in6_addr)); |
527588aa | 1866 | } else if (from_bgp->tovpn_sid_locator) { |
05d99980 CS |
1867 | struct srv6_locator_chunk *locator = |
1868 | from_bgp->tovpn_sid_locator; | |
527588aa CS |
1869 | encode_label(from_bgp->tovpn_sid_transpose_label, &label); |
1870 | static_attr.srv6_l3vpn = | |
1871 | XCALLOC(MTYPE_BGP_SRV6_L3VPN, | |
1872 | sizeof(struct bgp_attr_srv6_l3vpn)); | |
1873 | static_attr.srv6_l3vpn->sid_flags = 0x00; | |
05d99980 CS |
1874 | static_attr.srv6_l3vpn->endpoint_behavior = |
1875 | CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID) | |
1876 | ? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID | |
1877 | : SRV6_ENDPOINT_BEHAVIOR_END_DT46; | |
527588aa CS |
1878 | static_attr.srv6_l3vpn->loc_block_len = |
1879 | from_bgp->tovpn_sid_locator->block_bits_length; | |
1880 | static_attr.srv6_l3vpn->loc_node_len = | |
1881 | from_bgp->tovpn_sid_locator->node_bits_length; | |
1882 | static_attr.srv6_l3vpn->func_len = | |
1883 | from_bgp->tovpn_sid_locator->function_bits_length; | |
1884 | static_attr.srv6_l3vpn->arg_len = | |
1885 | from_bgp->tovpn_sid_locator->argument_bits_length; | |
1886 | static_attr.srv6_l3vpn->transposition_len = | |
1887 | from_bgp->tovpn_sid_locator->function_bits_length; | |
1888 | static_attr.srv6_l3vpn->transposition_offset = | |
1889 | from_bgp->tovpn_sid_locator->block_bits_length + | |
1890 | from_bgp->tovpn_sid_locator->node_bits_length; | |
1891 | memcpy(&static_attr.srv6_l3vpn->sid, | |
1892 | &from_bgp->tovpn_sid_locator->prefix.prefix, | |
1893 | sizeof(struct in6_addr)); | |
dbcf19b8 HS |
1894 | } |
1895 | ||
ddb5b488 PZ |
1896 | |
1897 | new_attr = bgp_attr_intern( | |
1898 | &static_attr); /* hashed refcounted everything */ | |
1899 | bgp_attr_flush(&static_attr); /* free locally-allocated parts */ | |
1900 | ||
b53e67a3 DA |
1901 | if (debug && bgp_attr_get_ecommunity(new_attr)) { |
1902 | char *s = ecommunity_ecom2str(bgp_attr_get_ecommunity(new_attr), | |
c3e345b1 | 1903 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); |
ddb5b488 | 1904 | |
ddb5b488 | 1905 | zlog_debug("%s: new_attr->ecommunity{%s}", __func__, s); |
c3e345b1 | 1906 | XFREE(MTYPE_ECOMMUNITY_STR, s); |
ddb5b488 PZ |
1907 | } |
1908 | ||
1909 | /* Now new_attr is an allocated interned attr */ | |
1910 | ||
02212dee LS |
1911 | bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, |
1912 | &(from_bgp->vpn_policy[afi].tovpn_rd)); | |
ddb5b488 | 1913 | |
4b7e6066 | 1914 | struct bgp_path_info *new_info; |
ddb5b488 | 1915 | |
88ef2991 | 1916 | new_info = |
02212dee LS |
1917 | leak_update(to_bgp, bn, new_attr, afi, safi, path_vrf, &label, |
1918 | 1, from_bgp, NULL, nexthop_self_flag, debug); | |
ddb5b488 PZ |
1919 | |
1920 | /* | |
1921 | * Routes actually installed in the vpn RIB must also be | |
1922 | * offered to all vrfs (because now they originate from | |
1923 | * the vpn RIB). | |
1924 | * | |
1925 | * Acceptance into other vrfs depends on rt-lists. | |
1926 | * Originating vrf will not accept the looped back route | |
1927 | * because of loop checking. | |
1928 | */ | |
1929 | if (new_info) | |
46dbf9d0 | 1930 | vpn_leak_to_vrf_update(from_bgp, new_info, NULL); |
8ea624a4 DA |
1931 | else |
1932 | bgp_dest_unlock_node(bn); | |
ddb5b488 PZ |
1933 | } |
1934 | ||
02212dee LS |
1935 | void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */ |
1936 | struct bgp *from_bgp, /* from */ | |
40381db7 | 1937 | struct bgp_path_info *path_vrf) /* route */ |
ddb5b488 PZ |
1938 | { |
1939 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
9bcb3eef | 1940 | const struct prefix *p = bgp_dest_get_prefix(path_vrf->net); |
ddb5b488 PZ |
1941 | afi_t afi = family2afi(p->family); |
1942 | safi_t safi = SAFI_MPLS_VPN; | |
40381db7 | 1943 | struct bgp_path_info *bpi; |
9bcb3eef | 1944 | struct bgp_dest *bn; |
ddb5b488 | 1945 | const char *debugmsg; |
960035b2 PZ |
1946 | |
1947 | if (debug) { | |
960035b2 | 1948 | zlog_debug( |
56ca3b5b | 1949 | "%s: entry: leak-from=%s, p=%pBD, type=%d, sub_type=%d", |
02212dee | 1950 | __func__, from_bgp->name_pretty, path_vrf->net, |
40381db7 | 1951 | path_vrf->type, path_vrf->sub_type); |
960035b2 | 1952 | } |
ddb5b488 | 1953 | |
02212dee | 1954 | if (!to_bgp) |
ddb5b488 PZ |
1955 | return; |
1956 | ||
1957 | if (!afi) { | |
1958 | if (debug) | |
1959 | zlog_debug("%s: can't get afi of prefix", __func__); | |
1960 | return; | |
1961 | } | |
1962 | ||
12d6100c | 1963 | /* Is this route exportable into the VPN table? */ |
1964 | if (!is_route_injectable_into_vpn(path_vrf)) | |
1965 | return; | |
1966 | ||
02212dee | 1967 | if (!vpn_leak_to_vpn_active(from_bgp, afi, &debugmsg)) { |
ddb5b488 PZ |
1968 | if (debug) |
1969 | zlog_debug("%s: skipping: %s", __func__, debugmsg); | |
1970 | return; | |
1971 | } | |
1972 | ||
1973 | if (debug) | |
40381db7 | 1974 | zlog_debug("%s: withdrawing (path_vrf=%p)", __func__, path_vrf); |
ddb5b488 | 1975 | |
02212dee LS |
1976 | bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, |
1977 | &(from_bgp->vpn_policy[afi].tovpn_rd)); | |
ddb5b488 | 1978 | |
6f94b685 DS |
1979 | if (!bn) |
1980 | return; | |
ddb5b488 PZ |
1981 | /* |
1982 | * vrf -> vpn | |
40381db7 | 1983 | * match original bpi imported from |
ddb5b488 | 1984 | */ |
9bcb3eef | 1985 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { |
40381db7 | 1986 | if (bpi->extra && bpi->extra->parent == path_vrf) { |
ddb5b488 PZ |
1987 | break; |
1988 | } | |
1989 | } | |
1990 | ||
40381db7 | 1991 | if (bpi) { |
ddb5b488 | 1992 | /* withdraw from looped vrfs as well */ |
1aa2c93e | 1993 | vpn_leak_to_vrf_withdraw(bpi); |
ddb5b488 | 1994 | |
02212dee | 1995 | bgp_aggregate_decrement(to_bgp, p, bpi, afi, safi); |
40381db7 | 1996 | bgp_path_info_delete(bn, bpi); |
02212dee | 1997 | bgp_process(to_bgp, bn, afi, safi); |
ddb5b488 | 1998 | } |
9bcb3eef | 1999 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
2000 | } |
2001 | ||
02212dee | 2002 | void vpn_leak_from_vrf_withdraw_all(struct bgp *to_bgp, struct bgp *from_bgp, |
ddb5b488 PZ |
2003 | afi_t afi) |
2004 | { | |
2005 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); | |
9bcb3eef | 2006 | struct bgp_dest *pdest; |
ddb5b488 PZ |
2007 | safi_t safi = SAFI_MPLS_VPN; |
2008 | ||
2009 | /* | |
02212dee | 2010 | * Walk vpn table, delete bpi with bgp_orig == from_bgp |
ddb5b488 | 2011 | */ |
02212dee | 2012 | for (pdest = bgp_table_top(to_bgp->rib[afi][safi]); pdest; |
9bcb3eef | 2013 | pdest = bgp_route_next(pdest)) { |
ddb5b488 PZ |
2014 | |
2015 | struct bgp_table *table; | |
9bcb3eef | 2016 | struct bgp_dest *bn; |
40381db7 | 2017 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
2018 | |
2019 | /* This is the per-RD table of prefixes */ | |
9bcb3eef | 2020 | table = bgp_dest_get_bgp_table_info(pdest); |
ddb5b488 PZ |
2021 | |
2022 | if (!table) | |
2023 | continue; | |
2024 | ||
2025 | for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { | |
9bcb3eef | 2026 | bpi = bgp_dest_get_bgp_path_info(bn); |
6f94b685 | 2027 | if (debug && bpi) { |
56ca3b5b | 2028 | zlog_debug("%s: looking at prefix %pBD", |
b54892e0 | 2029 | __func__, bn); |
ddb5b488 PZ |
2030 | } |
2031 | ||
6f94b685 | 2032 | for (; bpi; bpi = bpi->next) { |
ddb5b488 PZ |
2033 | if (debug) |
2034 | zlog_debug("%s: type %d, sub_type %d", | |
40381db7 DS |
2035 | __func__, bpi->type, |
2036 | bpi->sub_type); | |
2037 | if (bpi->sub_type != BGP_ROUTE_IMPORTED) | |
ddb5b488 | 2038 | continue; |
40381db7 | 2039 | if (!bpi->extra) |
ddb5b488 | 2040 | continue; |
02212dee LS |
2041 | if ((struct bgp *)bpi->extra->bgp_orig == |
2042 | from_bgp) { | |
ddb5b488 PZ |
2043 | /* delete route */ |
2044 | if (debug) | |
9165c5f5 | 2045 | zlog_debug("%s: deleting it", |
ddb5b488 | 2046 | __func__); |
b19c4f08 | 2047 | /* withdraw from leak-to vrfs as well */ |
1aa2c93e | 2048 | vpn_leak_to_vrf_withdraw(bpi); |
b54892e0 | 2049 | bgp_aggregate_decrement( |
02212dee LS |
2050 | to_bgp, bgp_dest_get_prefix(bn), |
2051 | bpi, afi, safi); | |
40381db7 | 2052 | bgp_path_info_delete(bn, bpi); |
02212dee | 2053 | bgp_process(to_bgp, bn, afi, safi); |
577be36a PG |
2054 | bgp_mplsvpn_path_nh_label_unlink( |
2055 | bpi->extra->parent); | |
ddb5b488 PZ |
2056 | } |
2057 | } | |
2058 | } | |
2059 | } | |
2060 | } | |
2061 | ||
02212dee | 2062 | void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp, |
ddb5b488 PZ |
2063 | afi_t afi) |
2064 | { | |
9bcb3eef | 2065 | struct bgp_dest *bn; |
40381db7 | 2066 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
2067 | int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF); |
2068 | ||
2069 | if (debug) | |
2070 | zlog_debug("%s: entry, afi=%d, vrf=%s", __func__, afi, | |
02212dee | 2071 | from_bgp->name_pretty); |
ddb5b488 | 2072 | |
02212dee | 2073 | for (bn = bgp_table_top(from_bgp->rib[afi][SAFI_UNICAST]); bn; |
ddb5b488 PZ |
2074 | bn = bgp_route_next(bn)) { |
2075 | ||
2076 | if (debug) | |
2077 | zlog_debug("%s: node=%p", __func__, bn); | |
2078 | ||
9bcb3eef | 2079 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 2080 | bpi = bpi->next) { |
ddb5b488 PZ |
2081 | if (debug) |
2082 | zlog_debug( | |
2083 | "%s: calling vpn_leak_from_vrf_update", | |
2084 | __func__); | |
02212dee | 2085 | vpn_leak_from_vrf_update(to_bgp, from_bgp, bpi); |
ddb5b488 PZ |
2086 | } |
2087 | } | |
2088 | } | |
2089 | ||
46dbf9d0 DA |
2090 | static struct bgp *bgp_lookup_by_rd(struct bgp_path_info *bpi, |
2091 | struct prefix_rd *rd, afi_t afi) | |
2092 | { | |
2093 | struct listnode *node, *nnode; | |
2094 | struct bgp *bgp; | |
2095 | ||
2096 | if (!rd) | |
2097 | return NULL; | |
2098 | ||
2099 | /* If ACCEPT_OWN is not enabled for this path - return. */ | |
2100 | if (!CHECK_FLAG(bpi->flags, BGP_PATH_ACCEPT_OWN)) | |
2101 | return NULL; | |
2102 | ||
2103 | for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { | |
2104 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
2105 | continue; | |
2106 | ||
2107 | if (!CHECK_FLAG(bgp->vpn_policy[afi].flags, | |
2108 | BGP_VPN_POLICY_TOVPN_RD_SET)) | |
2109 | continue; | |
2110 | ||
2111 | /* Check if we have source VRF by RD value */ | |
2112 | if (memcmp(&bgp->vpn_policy[afi].tovpn_rd.val, rd->val, | |
2113 | ECOMMUNITY_SIZE) == 0) | |
2114 | return bgp; | |
2115 | } | |
2116 | ||
2117 | return NULL; | |
2118 | } | |
2119 | ||
2120 | static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ | |
2121 | struct bgp *from_bgp, /* from */ | |
2122 | struct bgp_path_info *path_vpn, | |
2123 | struct prefix_rd *prd) | |
ddb5b488 | 2124 | { |
9bcb3eef | 2125 | const struct prefix *p = bgp_dest_get_prefix(path_vpn->net); |
ddb5b488 PZ |
2126 | afi_t afi = family2afi(p->family); |
2127 | ||
ddb5b488 PZ |
2128 | struct attr static_attr = {0}; |
2129 | struct attr *new_attr = NULL; | |
9bcb3eef | 2130 | struct bgp_dest *bn; |
ddb5b488 PZ |
2131 | safi_t safi = SAFI_UNICAST; |
2132 | const char *debugmsg; | |
2133 | struct prefix nexthop_orig; | |
2134 | mpls_label_t *pLabels = NULL; | |
e37fb4bf | 2135 | uint32_t num_labels = 0; |
960035b2 | 2136 | int nexthop_self_flag = 1; |
40381db7 | 2137 | struct bgp_path_info *bpi_ultimate = NULL; |
513bf8d6 | 2138 | int origin_local = 0; |
d6632478 | 2139 | struct bgp *src_vrf; |
8a02d9fe | 2140 | struct interface *ifp; |
4a8cd6ad | 2141 | char rd_buf[RD_ADDRSTRLEN]; |
ddb5b488 PZ |
2142 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); |
2143 | ||
02212dee | 2144 | if (!vpn_leak_from_vpn_active(to_bgp, afi, &debugmsg)) { |
ddb5b488 | 2145 | if (debug) |
4ee5265a DA |
2146 | zlog_debug( |
2147 | "%s: from vpn (%s) to vrf (%s), skipping: %s", | |
2148 | __func__, from_bgp->name_pretty, | |
2149 | to_bgp->name_pretty, debugmsg); | |
a486300b | 2150 | return false; |
ddb5b488 PZ |
2151 | } |
2152 | ||
c479b28e DA |
2153 | /* |
2154 | * For VRF-2-VRF route-leaking, | |
2155 | * the source will be the originating VRF. | |
2156 | * | |
2157 | * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?) | |
2158 | * get the source VRF (BGP) by looking at the RD. | |
2159 | */ | |
2160 | struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi); | |
2161 | ||
2162 | if (path_vpn->extra && path_vpn->extra->bgp_orig) | |
2163 | src_vrf = path_vpn->extra->bgp_orig; | |
2164 | else if (src_bgp) | |
2165 | src_vrf = src_bgp; | |
2166 | else | |
2167 | src_vrf = from_bgp; | |
2168 | ||
ddb5b488 | 2169 | /* Check for intersection of route targets */ |
2d7cdc5b | 2170 | if (!ecommunity_include( |
02212dee | 2171 | to_bgp->vpn_policy[afi].rtlist[BGP_VPN_POLICY_DIR_FROMVPN], |
b53e67a3 | 2172 | bgp_attr_get_ecommunity(path_vpn->attr))) { |
de7cee09 AR |
2173 | if (debug) |
2174 | zlog_debug( | |
ba9dce1c | 2175 | "from vpn (%s) to vrf (%s), skipping after no intersection of route targets", |
02212dee | 2176 | from_bgp->name_pretty, to_bgp->name_pretty); |
a486300b | 2177 | return false; |
ddb5b488 PZ |
2178 | } |
2179 | ||
616e9f0d PG |
2180 | rd_buf[0] = '\0'; |
2181 | if (debug && prd) | |
4a8cd6ad PG |
2182 | prefix_rd2str(prd, rd_buf, sizeof(rd_buf), to_bgp->asnotation); |
2183 | ||
46dbf9d0 DA |
2184 | /* A route MUST NOT ever be accepted back into its source VRF, even if |
2185 | * it carries one or more RTs that match that VRF. | |
2186 | */ | |
dd2d28ea RS |
2187 | if (CHECK_FLAG(path_vpn->flags, BGP_PATH_ACCEPT_OWN) && prd && |
2188 | memcmp(&prd->val, &to_bgp->vpn_policy[afi].tovpn_rd.val, | |
2189 | ECOMMUNITY_SIZE) == 0) { | |
46dbf9d0 DA |
2190 | if (debug) |
2191 | zlog_debug( | |
4a8cd6ad PG |
2192 | "%s: skipping import, match RD (%s) of src VRF (%s) and the prefix (%pFX)", |
2193 | __func__, rd_buf, to_bgp->name_pretty, p); | |
46dbf9d0 DA |
2194 | return false; |
2195 | } | |
2196 | ||
2dbe669b | 2197 | if (debug) |
4a8cd6ad PG |
2198 | zlog_debug("%s: updating RD %s, %pFX to %s", __func__, rd_buf, |
2199 | p, to_bgp->name_pretty); | |
ddb5b488 | 2200 | |
6f4f49b2 QY |
2201 | /* shallow copy */ |
2202 | static_attr = *path_vpn->attr; | |
ddb5b488 | 2203 | |
e8bfa90e | 2204 | struct ecommunity *old_ecom; |
2205 | struct ecommunity *new_ecom; | |
2206 | ||
2207 | /* If doing VRF-to-VRF leaking, strip RTs. */ | |
b53e67a3 | 2208 | old_ecom = bgp_attr_get_ecommunity(&static_attr); |
02212dee LS |
2209 | if (old_ecom && CHECK_FLAG(to_bgp->af_flags[afi][safi], |
2210 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { | |
e8bfa90e | 2211 | new_ecom = ecommunity_dup(old_ecom); |
2212 | ecommunity_strip_rts(new_ecom); | |
b53e67a3 | 2213 | bgp_attr_set_ecommunity(&static_attr, new_ecom); |
1995cb77 DS |
2214 | |
2215 | if (new_ecom->size == 0) { | |
1995cb77 | 2216 | ecommunity_free(&new_ecom); |
b53e67a3 | 2217 | bgp_attr_set_ecommunity(&static_attr, NULL); |
1995cb77 DS |
2218 | } |
2219 | ||
e8bfa90e | 2220 | if (!old_ecom->refcnt) |
2221 | ecommunity_free(&old_ecom); | |
2222 | } | |
2223 | ||
46dbf9d0 DA |
2224 | community_strip_accept_own(&static_attr); |
2225 | ||
ddb5b488 PZ |
2226 | /* |
2227 | * Nexthop: stash and clear | |
2228 | * | |
2229 | * Nexthop is valid in context of VPN core, but not in destination vrf. | |
2230 | * Stash it for later label resolution by vrf ingress path and then | |
2231 | * overwrite with 0, i.e., "me", for the sake of vrf advertisement. | |
2232 | */ | |
40381db7 | 2233 | uint8_t nhfamily = NEXTHOP_FAMILY(path_vpn->attr->mp_nexthop_len); |
ddb5b488 PZ |
2234 | |
2235 | memset(&nexthop_orig, 0, sizeof(nexthop_orig)); | |
2236 | nexthop_orig.family = nhfamily; | |
2237 | ||
c479b28e DA |
2238 | /* If the path has accept-own community and the source VRF |
2239 | * is valid, reset next-hop to self, to allow importing own | |
2240 | * routes between different VRFs on the same node. | |
8a02d9fe DA |
2241 | * Set the nh ifindex to VRF's interface, not the real interface. |
2242 | * Let the kernel to decide with double lookup the real next-hop | |
2243 | * interface when installing the route. | |
c479b28e | 2244 | */ |
8a02d9fe | 2245 | if (src_bgp) { |
c479b28e | 2246 | subgroup_announce_reset_nhop(nhfamily, &static_attr); |
8a02d9fe DA |
2247 | ifp = if_get_vrf_loopback(src_vrf->vrf_id); |
2248 | if (ifp) | |
2249 | static_attr.nh_ifindex = ifp->ifindex; | |
2250 | } | |
c479b28e | 2251 | |
ddb5b488 | 2252 | switch (nhfamily) { |
ddb5b488 PZ |
2253 | case AF_INET: |
2254 | /* save */ | |
40381db7 | 2255 | nexthop_orig.u.prefix4 = path_vpn->attr->mp_nexthop_global_in; |
12256b84 | 2256 | nexthop_orig.prefixlen = IPV4_MAX_BITLEN; |
12a844a5 | 2257 | |
02212dee | 2258 | if (CHECK_FLAG(to_bgp->af_flags[afi][safi], |
12a844a5 DS |
2259 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { |
2260 | static_attr.nexthop.s_addr = | |
2261 | nexthop_orig.u.prefix4.s_addr; | |
2262 | ||
2263 | static_attr.mp_nexthop_global_in = | |
40381db7 | 2264 | path_vpn->attr->mp_nexthop_global_in; |
12a844a5 | 2265 | static_attr.mp_nexthop_len = |
40381db7 | 2266 | path_vpn->attr->mp_nexthop_len; |
12a844a5 | 2267 | } |
de4d0a51 | 2268 | static_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP); |
ddb5b488 | 2269 | break; |
ddb5b488 PZ |
2270 | case AF_INET6: |
2271 | /* save */ | |
40381db7 | 2272 | nexthop_orig.u.prefix6 = path_vpn->attr->mp_nexthop_global; |
13ccce6e | 2273 | nexthop_orig.prefixlen = IPV6_MAX_BITLEN; |
12a844a5 | 2274 | |
02212dee | 2275 | if (CHECK_FLAG(to_bgp->af_flags[afi][safi], |
12a844a5 DS |
2276 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { |
2277 | static_attr.mp_nexthop_global = nexthop_orig.u.prefix6; | |
12a844a5 | 2278 | } |
ddb5b488 PZ |
2279 | break; |
2280 | } | |
2281 | ||
ddb5b488 PZ |
2282 | /* |
2283 | * route map handling | |
ddb5b488 | 2284 | */ |
02212dee | 2285 | if (to_bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN]) { |
4b7e6066 | 2286 | struct bgp_path_info info; |
ddb5b488 PZ |
2287 | route_map_result_t ret; |
2288 | ||
2289 | memset(&info, 0, sizeof(info)); | |
02212dee | 2290 | info.peer = to_bgp->peer_self; |
ddb5b488 | 2291 | info.attr = &static_attr; |
1dcc9e5b | 2292 | info.extra = path_vpn->extra; /* Used for source-vrf filter */ |
02212dee | 2293 | ret = route_map_apply(to_bgp->vpn_policy[afi] |
ddb5b488 | 2294 | .rmap[BGP_VPN_POLICY_DIR_FROMVPN], |
1782514f | 2295 | p, &info); |
ddb5b488 PZ |
2296 | if (RMAP_DENYMATCH == ret) { |
2297 | bgp_attr_flush(&static_attr); /* free any added parts */ | |
2298 | if (debug) | |
2299 | zlog_debug( | |
2300 | "%s: vrf %s vpn-policy route map \"%s\" says DENY, returning", | |
02212dee LS |
2301 | __func__, to_bgp->name_pretty, |
2302 | to_bgp->vpn_policy[afi] | |
ddb5b488 PZ |
2303 | .rmap[BGP_VPN_POLICY_DIR_FROMVPN] |
2304 | ->name); | |
a486300b | 2305 | return false; |
ddb5b488 | 2306 | } |
960035b2 PZ |
2307 | /* |
2308 | * if route-map changed nexthop, don't nexthop-self on output | |
2309 | */ | |
2310 | if (!CHECK_FLAG(static_attr.rmap_change_flags, | |
2311 | BATTR_RMAP_NEXTHOP_UNCHANGED)) | |
2312 | nexthop_self_flag = 0; | |
ddb5b488 PZ |
2313 | } |
2314 | ||
2315 | new_attr = bgp_attr_intern(&static_attr); | |
2316 | bgp_attr_flush(&static_attr); | |
2317 | ||
02212dee | 2318 | bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); |
ddb5b488 PZ |
2319 | |
2320 | /* | |
2321 | * ensure labels are copied | |
513bf8d6 PZ |
2322 | * |
2323 | * However, there is a special case: if the route originated in | |
2324 | * another local VRF (as opposed to arriving via VPN), then the | |
2325 | * nexthop is reached by hairpinning through this router (me) | |
2326 | * using IP forwarding only (no LSP). Therefore, the route | |
2327 | * imported to the VRF should not have labels attached. Note | |
2328 | * that nexthop tracking is also involved: eliminating the | |
2329 | * labels for these routes enables the non-labeled nexthops | |
2330 | * from the originating VRF to be considered valid for this route. | |
ddb5b488 | 2331 | */ |
02212dee | 2332 | if (!CHECK_FLAG(to_bgp->af_flags[afi][safi], |
12a844a5 DS |
2333 | BGP_CONFIG_VRF_TO_VRF_IMPORT)) { |
2334 | /* work back to original route */ | |
da0c0ef7 | 2335 | bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); |
513bf8d6 | 2336 | |
12a844a5 DS |
2337 | /* |
2338 | * if original route was unicast, | |
2339 | * then it did not arrive over vpn | |
2340 | */ | |
40381db7 | 2341 | if (bpi_ultimate->net) { |
12a844a5 | 2342 | struct bgp_table *table; |
513bf8d6 | 2343 | |
9bcb3eef | 2344 | table = bgp_dest_table(bpi_ultimate->net); |
12a844a5 DS |
2345 | if (table && (table->safi == SAFI_UNICAST)) |
2346 | origin_local = 1; | |
2347 | } | |
513bf8d6 | 2348 | |
12a844a5 | 2349 | /* copy labels */ |
40381db7 DS |
2350 | if (!origin_local && path_vpn->extra |
2351 | && path_vpn->extra->num_labels) { | |
2352 | num_labels = path_vpn->extra->num_labels; | |
12a844a5 DS |
2353 | if (num_labels > BGP_MAX_LABELS) |
2354 | num_labels = BGP_MAX_LABELS; | |
40381db7 | 2355 | pLabels = path_vpn->extra->label; |
12a844a5 | 2356 | } |
ddb5b488 | 2357 | } |
513bf8d6 | 2358 | |
b54892e0 | 2359 | if (debug) |
56ca3b5b | 2360 | zlog_debug("%s: pfx %pBD: num_labels %d", __func__, |
b54892e0 | 2361 | path_vpn->net, num_labels); |
ddb5b488 | 2362 | |
8ea624a4 DA |
2363 | if (!leak_update(to_bgp, bn, new_attr, afi, safi, path_vpn, pLabels, |
2364 | num_labels, src_vrf, &nexthop_orig, nexthop_self_flag, | |
2365 | debug)) | |
2366 | bgp_dest_unlock_node(bn); | |
2367 | ||
a486300b | 2368 | return true; |
ddb5b488 PZ |
2369 | } |
2370 | ||
46dbf9d0 DA |
2371 | bool vpn_leak_to_vrf_update(struct bgp *from_bgp, |
2372 | struct bgp_path_info *path_vpn, | |
2373 | struct prefix_rd *prd) | |
ddb5b488 PZ |
2374 | { |
2375 | struct listnode *mnode, *mnnode; | |
2376 | struct bgp *bgp; | |
a486300b | 2377 | bool leak_success = false; |
ddb5b488 PZ |
2378 | |
2379 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
2380 | ||
2381 | if (debug) | |
40381db7 | 2382 | zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); |
ddb5b488 PZ |
2383 | |
2384 | /* Loop over VRFs */ | |
2385 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { | |
2386 | ||
40381db7 DS |
2387 | if (!path_vpn->extra |
2388 | || path_vpn->extra->bgp_orig != bgp) { /* no loop */ | |
a486300b | 2389 | leak_success |= vpn_leak_to_vrf_update_onevrf( |
46dbf9d0 | 2390 | bgp, from_bgp, path_vpn, prd); |
ddb5b488 PZ |
2391 | } |
2392 | } | |
a486300b | 2393 | return leak_success; |
ddb5b488 PZ |
2394 | } |
2395 | ||
1aa2c93e | 2396 | void vpn_leak_to_vrf_withdraw(struct bgp_path_info *path_vpn) |
ddb5b488 | 2397 | { |
b54892e0 | 2398 | const struct prefix *p; |
1b3510a0 | 2399 | afi_t afi; |
ddb5b488 PZ |
2400 | safi_t safi = SAFI_UNICAST; |
2401 | struct bgp *bgp; | |
2402 | struct listnode *mnode, *mnnode; | |
9bcb3eef | 2403 | struct bgp_dest *bn; |
40381db7 | 2404 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
2405 | const char *debugmsg; |
2406 | ||
2407 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
2408 | ||
b54892e0 | 2409 | if (debug) |
56ca3b5b | 2410 | zlog_debug("%s: entry: p=%pBD, type=%d, sub_type=%d", __func__, |
b54892e0 | 2411 | path_vpn->net, path_vpn->type, path_vpn->sub_type); |
960035b2 | 2412 | |
ddb5b488 | 2413 | if (debug) |
40381db7 | 2414 | zlog_debug("%s: start (path_vpn=%p)", __func__, path_vpn); |
ddb5b488 | 2415 | |
40381db7 | 2416 | if (!path_vpn->net) { |
49e5a4a0 | 2417 | #ifdef ENABLE_BGP_VNC |
40381db7 DS |
2418 | /* BGP_ROUTE_RFP routes do not have path_vpn->net set (yet) */ |
2419 | if (path_vpn->type == ZEBRA_ROUTE_BGP | |
2420 | && path_vpn->sub_type == BGP_ROUTE_RFP) { | |
1b3510a0 PZ |
2421 | |
2422 | return; | |
2423 | } | |
56c2c080 | 2424 | #endif |
1b3510a0 | 2425 | if (debug) |
40381db7 DS |
2426 | zlog_debug( |
2427 | "%s: path_vpn->net unexpectedly NULL, no prefix, bailing", | |
1b3510a0 PZ |
2428 | __func__); |
2429 | return; | |
2430 | } | |
2431 | ||
9bcb3eef | 2432 | p = bgp_dest_get_prefix(path_vpn->net); |
1b3510a0 | 2433 | afi = family2afi(p->family); |
ddb5b488 PZ |
2434 | |
2435 | /* Loop over VRFs */ | |
2436 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { | |
b9c7bc5a | 2437 | if (!vpn_leak_from_vpn_active(bgp, afi, &debugmsg)) { |
ddb5b488 | 2438 | if (debug) |
4ee5265a DA |
2439 | zlog_debug("%s: from %s, skipping: %s", |
2440 | __func__, bgp->name_pretty, | |
ddb5b488 PZ |
2441 | debugmsg); |
2442 | continue; | |
2443 | } | |
2444 | ||
2445 | /* Check for intersection of route targets */ | |
2d7cdc5b DA |
2446 | if (!ecommunity_include( |
2447 | bgp->vpn_policy[afi] | |
2448 | .rtlist[BGP_VPN_POLICY_DIR_FROMVPN], | |
2449 | bgp_attr_get_ecommunity(path_vpn->attr))) { | |
ddb5b488 PZ |
2450 | |
2451 | continue; | |
2452 | } | |
2453 | ||
2454 | if (debug) | |
2455 | zlog_debug("%s: withdrawing from vrf %s", __func__, | |
960035b2 | 2456 | bgp->name_pretty); |
ddb5b488 PZ |
2457 | |
2458 | bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, NULL); | |
6f94b685 | 2459 | |
9bcb3eef | 2460 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 2461 | bpi = bpi->next) { |
40381db7 DS |
2462 | if (bpi->extra |
2463 | && (struct bgp_path_info *)bpi->extra->parent | |
2464 | == path_vpn) { | |
ddb5b488 PZ |
2465 | break; |
2466 | } | |
2467 | } | |
2468 | ||
40381db7 | 2469 | if (bpi) { |
ddb5b488 | 2470 | if (debug) |
40381db7 DS |
2471 | zlog_debug("%s: deleting bpi %p", __func__, |
2472 | bpi); | |
2473 | bgp_aggregate_decrement(bgp, p, bpi, afi, safi); | |
2474 | bgp_path_info_delete(bn, bpi); | |
ddb5b488 PZ |
2475 | bgp_process(bgp, bn, afi, safi); |
2476 | } | |
9bcb3eef | 2477 | bgp_dest_unlock_node(bn); |
ddb5b488 PZ |
2478 | } |
2479 | } | |
2480 | ||
02212dee | 2481 | void vpn_leak_to_vrf_withdraw_all(struct bgp *to_bgp, afi_t afi) |
ddb5b488 | 2482 | { |
9bcb3eef | 2483 | struct bgp_dest *bn; |
40381db7 | 2484 | struct bgp_path_info *bpi; |
ddb5b488 PZ |
2485 | safi_t safi = SAFI_UNICAST; |
2486 | int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); | |
ddb5b488 PZ |
2487 | |
2488 | if (debug) | |
2489 | zlog_debug("%s: entry", __func__); | |
2490 | /* | |
40381db7 | 2491 | * Walk vrf table, delete bpi with bgp_orig in a different vrf |
ddb5b488 | 2492 | */ |
02212dee | 2493 | for (bn = bgp_table_top(to_bgp->rib[afi][safi]); bn; |
ddb5b488 PZ |
2494 | bn = bgp_route_next(bn)) { |
2495 | ||
9bcb3eef | 2496 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 2497 | bpi = bpi->next) { |
02212dee LS |
2498 | if (bpi->extra && bpi->extra->bgp_orig != to_bgp && |
2499 | bpi->extra->parent && | |
2500 | is_pi_family_vpn(bpi->extra->parent)) { | |
ddb5b488 PZ |
2501 | |
2502 | /* delete route */ | |
02212dee | 2503 | bgp_aggregate_decrement(to_bgp, |
9bcb3eef | 2504 | bgp_dest_get_prefix(bn), |
b54892e0 | 2505 | bpi, afi, safi); |
40381db7 | 2506 | bgp_path_info_delete(bn, bpi); |
02212dee | 2507 | bgp_process(to_bgp, bn, afi, safi); |
ddb5b488 PZ |
2508 | } |
2509 | } | |
2510 | } | |
2511 | } | |
2512 | ||
02212dee | 2513 | void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from, |
ddb5b488 PZ |
2514 | afi_t afi) |
2515 | { | |
9bcb3eef | 2516 | struct bgp_dest *pdest; |
ddb5b488 PZ |
2517 | safi_t safi = SAFI_MPLS_VPN; |
2518 | ||
02212dee | 2519 | assert(vpn_from); |
73aed584 | 2520 | |
ddb5b488 PZ |
2521 | /* |
2522 | * Walk vpn table | |
2523 | */ | |
02212dee | 2524 | for (pdest = bgp_table_top(vpn_from->rib[afi][safi]); pdest; |
9bcb3eef | 2525 | pdest = bgp_route_next(pdest)) { |
ddb5b488 | 2526 | struct bgp_table *table; |
9bcb3eef | 2527 | struct bgp_dest *bn; |
40381db7 | 2528 | struct bgp_path_info *bpi; |
ddb5b488 | 2529 | |
ddb5b488 | 2530 | /* This is the per-RD table of prefixes */ |
9bcb3eef | 2531 | table = bgp_dest_get_bgp_table_info(pdest); |
ddb5b488 PZ |
2532 | |
2533 | if (!table) | |
2534 | continue; | |
2535 | ||
2536 | for (bn = bgp_table_top(table); bn; bn = bgp_route_next(bn)) { | |
2537 | ||
9bcb3eef | 2538 | for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; |
6f94b685 | 2539 | bpi = bpi->next) { |
ddb5b488 | 2540 | |
02212dee LS |
2541 | if (bpi->extra && |
2542 | bpi->extra->bgp_orig == to_bgp) | |
ddb5b488 PZ |
2543 | continue; |
2544 | ||
02212dee | 2545 | vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from, |
46dbf9d0 | 2546 | bpi, NULL); |
ddb5b488 PZ |
2547 | } |
2548 | } | |
2549 | } | |
2550 | } | |
2551 | ||
d92a55df PZ |
2552 | /* |
2553 | * This function is called for definition/deletion/change to a route-map | |
2554 | */ | |
ddb5b488 PZ |
2555 | static void vpn_policy_routemap_update(struct bgp *bgp, const char *rmap_name) |
2556 | { | |
2557 | int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT); | |
2558 | afi_t afi; | |
2559 | struct route_map *rmap; | |
2560 | ||
2561 | if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT | |
2562 | && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) { | |
2563 | ||
2564 | return; | |
2565 | } | |
2566 | ||
2567 | rmap = route_map_lookup_by_name(rmap_name); /* NULL if deleted */ | |
2568 | ||
2569 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
2570 | ||
d92a55df PZ |
2571 | if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_TOVPN] |
2572 | && !strcmp(rmap_name, | |
ddb5b488 PZ |
2573 | bgp->vpn_policy[afi] |
2574 | .rmap_name[BGP_VPN_POLICY_DIR_TOVPN])) { | |
2575 | ||
2576 | if (debug) | |
2577 | zlog_debug( | |
2578 | "%s: rmap \"%s\" matches vrf-policy tovpn for as %d afi %s", | |
2579 | __func__, rmap_name, bgp->as, | |
2580 | afi2str(afi)); | |
2581 | ||
2582 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, afi, | |
2583 | bgp_get_default(), bgp); | |
2584 | if (debug) | |
2585 | zlog_debug("%s: after vpn_leak_prechange", | |
2586 | __func__); | |
2587 | ||
d92a55df PZ |
2588 | /* in case of definition/deletion */ |
2589 | bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_TOVPN] = | |
2590 | rmap; | |
ddb5b488 PZ |
2591 | |
2592 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, | |
2593 | bgp_get_default(), bgp); | |
d92a55df | 2594 | |
ddb5b488 PZ |
2595 | if (debug) |
2596 | zlog_debug("%s: after vpn_leak_postchange", | |
2597 | __func__); | |
2598 | } | |
2599 | ||
d92a55df PZ |
2600 | if (bgp->vpn_policy[afi].rmap_name[BGP_VPN_POLICY_DIR_FROMVPN] |
2601 | && !strcmp(rmap_name, | |
2602 | bgp->vpn_policy[afi] | |
2603 | .rmap_name[BGP_VPN_POLICY_DIR_FROMVPN])) { | |
b9c7bc5a PZ |
2604 | |
2605 | if (debug) { | |
2606 | zlog_debug("%s: rmap \"%s\" matches vrf-policy fromvpn for as %d afi %s", | |
ddb5b488 PZ |
2607 | __func__, rmap_name, bgp->as, |
2608 | afi2str(afi)); | |
b9c7bc5a | 2609 | } |
ddb5b488 PZ |
2610 | |
2611 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_FROMVPN, afi, | |
2612 | bgp_get_default(), bgp); | |
2613 | ||
d92a55df PZ |
2614 | /* in case of definition/deletion */ |
2615 | bgp->vpn_policy[afi].rmap[BGP_VPN_POLICY_DIR_FROMVPN] = | |
2616 | rmap; | |
ddb5b488 PZ |
2617 | |
2618 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi, | |
2619 | bgp_get_default(), bgp); | |
2620 | } | |
2621 | } | |
2622 | } | |
2623 | ||
636f7608 CS |
2624 | /* This API is used during router-id change, reflect VPNs |
2625 | * auto RD and RT values and readvertise routes to VPN table. | |
2626 | */ | |
e65fe398 MS |
2627 | void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw, |
2628 | bool is_config) | |
636f7608 CS |
2629 | { |
2630 | afi_t afi; | |
de7cee09 AR |
2631 | int debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
2632 | | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
636f7608 CS |
2633 | char *vname; |
2634 | const char *export_name; | |
2635 | char buf[RD_ADDRSTRLEN]; | |
2636 | struct bgp *bgp_import; | |
2637 | struct listnode *node; | |
2638 | struct ecommunity *ecom; | |
9c2fd3fe | 2639 | enum vpn_policy_direction idir, edir; |
636f7608 | 2640 | |
de7cee09 AR |
2641 | /* |
2642 | * Router-id change that is not explicitly configured | |
2643 | * (a change from zebra, frr restart for example) | |
2644 | * should not replace a configured vpn RD/RT. | |
2645 | */ | |
2646 | if (!is_config) { | |
2647 | if (debug) | |
2648 | zlog_debug("%s: skipping non explicit router-id change", | |
2649 | __func__); | |
2650 | return; | |
2651 | } | |
2652 | ||
636f7608 CS |
2653 | if (bgp->inst_type != BGP_INSTANCE_TYPE_DEFAULT |
2654 | && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
2655 | return; | |
2656 | ||
2657 | export_name = bgp->name ? bgp->name : VRF_DEFAULT_NAME; | |
636f7608 CS |
2658 | idir = BGP_VPN_POLICY_DIR_FROMVPN; |
2659 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
2660 | ||
2661 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
2662 | if (!vpn_leak_to_vpn_active(bgp, afi, NULL)) | |
2663 | continue; | |
2664 | ||
2665 | if (withdraw) { | |
2666 | vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, | |
2667 | afi, bgp_get_default(), bgp); | |
2668 | if (debug) | |
2669 | zlog_debug("%s: %s after to_vpn vpn_leak_prechange", | |
2670 | __func__, export_name); | |
2671 | ||
2672 | /* Remove import RT from VRFs */ | |
2673 | ecom = bgp->vpn_policy[afi].rtlist[edir]; | |
2674 | for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi]. | |
2675 | export_vrf, node, vname)) { | |
67bd620c | 2676 | if (strcmp(vname, VRF_DEFAULT_NAME) == 0) |
2677 | bgp_import = bgp_get_default(); | |
2678 | else | |
2679 | bgp_import = bgp_lookup_by_name(vname); | |
636f7608 CS |
2680 | if (!bgp_import) |
2681 | continue; | |
2682 | ||
de7cee09 AR |
2683 | ecommunity_del_val( |
2684 | bgp_import->vpn_policy[afi] | |
2685 | .rtlist[idir], | |
636f7608 | 2686 | (struct ecommunity_val *)ecom->val); |
636f7608 CS |
2687 | } |
2688 | } else { | |
2689 | /* New router-id derive auto RD and RT and export | |
2690 | * to VPN | |
2691 | */ | |
2692 | form_auto_rd(bgp->router_id, bgp->vrf_rd_id, | |
2693 | &bgp->vrf_prd_auto); | |
2694 | bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto; | |
2695 | prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf, | |
4a8cd6ad | 2696 | sizeof(buf), bgp->asnotation); |
f6a460f9 SB |
2697 | |
2698 | /* free up pre-existing memory if any and allocate | |
2699 | * the ecommunity attribute with new RD/RT | |
2700 | */ | |
2701 | if (bgp->vpn_policy[afi].rtlist[edir]) | |
2702 | ecommunity_free( | |
2703 | &bgp->vpn_policy[afi].rtlist[edir]); | |
2704 | bgp->vpn_policy[afi].rtlist[edir] = ecommunity_str2com( | |
2705 | buf, ECOMMUNITY_ROUTE_TARGET, 0); | |
636f7608 CS |
2706 | |
2707 | /* Update import_vrf rt_list */ | |
2708 | ecom = bgp->vpn_policy[afi].rtlist[edir]; | |
2709 | for (ALL_LIST_ELEMENTS_RO(bgp->vpn_policy[afi]. | |
2710 | export_vrf, node, vname)) { | |
67bd620c | 2711 | if (strcmp(vname, VRF_DEFAULT_NAME) == 0) |
2712 | bgp_import = bgp_get_default(); | |
2713 | else | |
2714 | bgp_import = bgp_lookup_by_name(vname); | |
636f7608 CS |
2715 | if (!bgp_import) |
2716 | continue; | |
2717 | if (bgp_import->vpn_policy[afi].rtlist[idir]) | |
2718 | bgp_import->vpn_policy[afi].rtlist[idir] | |
2719 | = ecommunity_merge( | |
2720 | bgp_import->vpn_policy[afi] | |
2721 | .rtlist[idir], ecom); | |
2722 | else | |
2723 | bgp_import->vpn_policy[afi].rtlist[idir] | |
2724 | = ecommunity_dup(ecom); | |
636f7608 | 2725 | } |
e65fe398 | 2726 | |
636f7608 CS |
2727 | /* Update routes to VPN */ |
2728 | vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, | |
2729 | afi, bgp_get_default(), | |
2730 | bgp); | |
2731 | if (debug) | |
2732 | zlog_debug("%s: %s after to_vpn vpn_leak_postchange", | |
2733 | __func__, export_name); | |
2734 | } | |
2735 | } | |
2736 | } | |
2737 | ||
ddb5b488 PZ |
2738 | void vpn_policy_routemap_event(const char *rmap_name) |
2739 | { | |
2740 | int debug = BGP_DEBUG(vpn, VPN_LEAK_RMAP_EVENT); | |
2741 | struct listnode *mnode, *mnnode; | |
2742 | struct bgp *bgp; | |
2743 | ||
2744 | if (debug) | |
2745 | zlog_debug("%s: entry", __func__); | |
2746 | ||
2747 | if (bm->bgp == NULL) /* may be called during cleanup */ | |
2748 | return; | |
2749 | ||
2750 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) | |
2751 | vpn_policy_routemap_update(bgp, rmap_name); | |
2752 | } | |
2753 | ||
1d4e8b0d | 2754 | void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, |
44338987 | 2755 | afi_t afi, safi_t safi) |
2756 | { | |
2757 | const char *export_name; | |
9c2fd3fe | 2758 | enum vpn_policy_direction idir, edir; |
9ecf931b CS |
2759 | char *vname, *tmp_name; |
2760 | char buf[RD_ADDRSTRLEN]; | |
44338987 | 2761 | struct ecommunity *ecom; |
2762 | bool first_export = false; | |
636f7608 | 2763 | int debug; |
9ecf931b CS |
2764 | struct listnode *node; |
2765 | bool is_inst_match = false; | |
44338987 | 2766 | |
5742e42b | 2767 | export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME; |
44338987 | 2768 | idir = BGP_VPN_POLICY_DIR_FROMVPN; |
2769 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
2770 | ||
636f7608 CS |
2771 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | |
2772 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
2773 | ||
1d4e8b0d DS |
2774 | /* |
2775 | * Cross-ref both VRFs. Also, note if this is the first time | |
44338987 | 2776 | * any VRF is importing from "import_vrf". |
2777 | */ | |
a8dadcf6 | 2778 | vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name) |
5742e42b | 2779 | : XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME)); |
a8dadcf6 | 2780 | |
9ecf931b CS |
2781 | /* Check the import_vrf list of destination vrf for the source vrf name, |
2782 | * insert otherwise. | |
2783 | */ | |
2784 | for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, | |
2785 | node, tmp_name)) { | |
2786 | if (strcmp(vname, tmp_name) == 0) { | |
2787 | is_inst_match = true; | |
2788 | break; | |
2789 | } | |
2790 | } | |
2791 | if (!is_inst_match) | |
2792 | listnode_add(to_bgp->vpn_policy[afi].import_vrf, | |
2793 | vname); | |
b9d45462 DS |
2794 | else |
2795 | XFREE(MTYPE_TMP, vname); | |
44338987 | 2796 | |
9ecf931b CS |
2797 | /* Check if the source vrf already exports to any vrf, |
2798 | * first time export requires to setup auto derived RD/RT values. | |
2799 | * Add the destination vrf name to export vrf list if it is | |
2800 | * not present. | |
2801 | */ | |
2802 | is_inst_match = false; | |
44338987 | 2803 | vname = XSTRDUP(MTYPE_TMP, export_name); |
9ecf931b CS |
2804 | if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) { |
2805 | first_export = true; | |
2806 | } else { | |
2807 | for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf, | |
2808 | node, tmp_name)) { | |
2809 | if (strcmp(vname, tmp_name) == 0) { | |
2810 | is_inst_match = true; | |
2811 | break; | |
2812 | } | |
2813 | } | |
2814 | } | |
2815 | if (!is_inst_match) | |
2816 | listnode_add(from_bgp->vpn_policy[afi].export_vrf, | |
2817 | vname); | |
b9d45462 DS |
2818 | else |
2819 | XFREE(MTYPE_TMP, vname); | |
2820 | ||
44338987 | 2821 | /* Update import RT for current VRF using export RT of the VRF we're |
2822 | * importing from. First though, make sure "import_vrf" has that | |
2823 | * set. | |
2824 | */ | |
2825 | if (first_export) { | |
1d4e8b0d DS |
2826 | form_auto_rd(from_bgp->router_id, from_bgp->vrf_rd_id, |
2827 | &from_bgp->vrf_prd_auto); | |
2828 | from_bgp->vpn_policy[afi].tovpn_rd = from_bgp->vrf_prd_auto; | |
2829 | SET_FLAG(from_bgp->vpn_policy[afi].flags, | |
44338987 | 2830 | BGP_VPN_POLICY_TOVPN_RD_SET); |
4a8cd6ad PG |
2831 | prefix_rd2str(&from_bgp->vpn_policy[afi].tovpn_rd, buf, |
2832 | sizeof(buf), from_bgp->asnotation); | |
1d4e8b0d | 2833 | from_bgp->vpn_policy[afi].rtlist[edir] = |
44338987 | 2834 | ecommunity_str2com(buf, ECOMMUNITY_ROUTE_TARGET, 0); |
1d4e8b0d | 2835 | SET_FLAG(from_bgp->af_flags[afi][safi], |
44338987 | 2836 | BGP_CONFIG_VRF_TO_VRF_EXPORT); |
13b7e7f0 DS |
2837 | from_bgp->vpn_policy[afi].tovpn_label = |
2838 | BGP_PREVENT_VRF_2_VRF_LEAK; | |
44338987 | 2839 | } |
1d4e8b0d DS |
2840 | ecom = from_bgp->vpn_policy[afi].rtlist[edir]; |
2841 | if (to_bgp->vpn_policy[afi].rtlist[idir]) | |
2842 | to_bgp->vpn_policy[afi].rtlist[idir] = | |
2843 | ecommunity_merge(to_bgp->vpn_policy[afi] | |
44338987 | 2844 | .rtlist[idir], ecom); |
2845 | else | |
1d4e8b0d DS |
2846 | to_bgp->vpn_policy[afi].rtlist[idir] = ecommunity_dup(ecom); |
2847 | SET_FLAG(to_bgp->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT); | |
44338987 | 2848 | |
636f7608 CS |
2849 | if (debug) { |
2850 | const char *from_name; | |
6a37bfb7 | 2851 | char *ecom1, *ecom2; |
636f7608 CS |
2852 | |
2853 | from_name = from_bgp->name ? from_bgp->name : | |
2854 | VRF_DEFAULT_NAME; | |
6a37bfb7 DS |
2855 | |
2856 | ecom1 = ecommunity_ecom2str( | |
2857 | to_bgp->vpn_policy[afi].rtlist[idir], | |
2858 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
2859 | ||
2860 | ecom2 = ecommunity_ecom2str( | |
2861 | to_bgp->vpn_policy[afi].rtlist[edir], | |
2862 | ECOMMUNITY_FORMAT_ROUTE_MAP, 0); | |
2863 | ||
2864 | zlog_debug( | |
2865 | "%s from %s to %s first_export %u import-rt %s export-rt %s", | |
2866 | __func__, from_name, export_name, first_export, ecom1, | |
2867 | ecom2); | |
2868 | ||
2869 | ecommunity_strfree(&ecom1); | |
2870 | ecommunity_strfree(&ecom2); | |
636f7608 CS |
2871 | } |
2872 | ||
44338987 | 2873 | /* Does "import_vrf" first need to export its routes or that |
2874 | * is already done and we just need to import those routes | |
2875 | * from the global table? | |
2876 | */ | |
2877 | if (first_export) | |
1d4e8b0d | 2878 | vpn_leak_postchange(edir, afi, bgp_get_default(), from_bgp); |
44338987 | 2879 | else |
1d4e8b0d | 2880 | vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp); |
44338987 | 2881 | } |
2882 | ||
1d4e8b0d | 2883 | void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp, |
44338987 | 2884 | afi_t afi, safi_t safi) |
2885 | { | |
a8dadcf6 | 2886 | const char *export_name, *tmp_name; |
9c2fd3fe | 2887 | enum vpn_policy_direction idir, edir; |
44338987 | 2888 | char *vname; |
9ecf931b | 2889 | struct ecommunity *ecom = NULL; |
44338987 | 2890 | struct listnode *node; |
636f7608 | 2891 | int debug; |
44338987 | 2892 | |
5742e42b DS |
2893 | export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME; |
2894 | tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; | |
44338987 | 2895 | idir = BGP_VPN_POLICY_DIR_FROMVPN; |
2896 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
2897 | ||
636f7608 CS |
2898 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | |
2899 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
2900 | ||
44338987 | 2901 | /* Were we importing from "import_vrf"? */ |
1d4e8b0d DS |
2902 | for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf, node, |
2903 | vname)) { | |
a8dadcf6 | 2904 | if (strcmp(vname, tmp_name) == 0) |
020a3f60 | 2905 | break; |
44338987 | 2906 | } |
1d4e8b0d DS |
2907 | |
2908 | /* | |
2909 | * We do not check in the cli if the passed in bgp | |
2910 | * instance is actually imported into us before | |
2911 | * we call this function. As such if we do not | |
2912 | * find this in the import_vrf list than | |
2913 | * we just need to return safely. | |
2914 | */ | |
44338987 | 2915 | if (!vname) |
2916 | return; | |
2917 | ||
636f7608 CS |
2918 | if (debug) |
2919 | zlog_debug("%s from %s to %s", __func__, tmp_name, export_name); | |
2920 | ||
44338987 | 2921 | /* Remove "import_vrf" from our import list. */ |
1d4e8b0d | 2922 | listnode_delete(to_bgp->vpn_policy[afi].import_vrf, vname); |
44338987 | 2923 | XFREE(MTYPE_TMP, vname); |
2924 | ||
2925 | /* Remove routes imported from "import_vrf". */ | |
2926 | /* TODO: In the current logic, we have to first remove all | |
2927 | * imported routes and then (if needed) import back routes | |
2928 | */ | |
1d4e8b0d | 2929 | vpn_leak_prechange(idir, afi, bgp_get_default(), to_bgp); |
44338987 | 2930 | |
1d4e8b0d | 2931 | if (to_bgp->vpn_policy[afi].import_vrf->count == 0) { |
ae6a6fb4 DS |
2932 | if (!to_bgp->vpn_policy[afi].rmap[idir]) |
2933 | UNSET_FLAG(to_bgp->af_flags[afi][safi], | |
2934 | BGP_CONFIG_VRF_TO_VRF_IMPORT); | |
9ecf931b CS |
2935 | if (to_bgp->vpn_policy[afi].rtlist[idir]) |
2936 | ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]); | |
44338987 | 2937 | } else { |
1d4e8b0d | 2938 | ecom = from_bgp->vpn_policy[afi].rtlist[edir]; |
9ecf931b CS |
2939 | if (ecom) |
2940 | ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir], | |
44338987 | 2941 | (struct ecommunity_val *)ecom->val); |
1d4e8b0d | 2942 | vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp); |
44338987 | 2943 | } |
2944 | ||
89d59347 DS |
2945 | /* |
2946 | * What? | |
2947 | * So SA is assuming that since the ALL_LIST_ELEMENTS_RO | |
2948 | * below is checking for NULL that export_vrf can be | |
2949 | * NULL, consequently it is complaining( like a cabbage ) | |
2950 | * that we could dereference and crash in the listcount(..) | |
2951 | * check below. | |
2952 | * So make it happy, under protest, with liberty and justice | |
2953 | * for all. | |
2954 | */ | |
1d4e8b0d | 2955 | assert(from_bgp->vpn_policy[afi].export_vrf); |
89d59347 | 2956 | |
44338987 | 2957 | /* Remove us from "import_vrf's" export list. If no other VRF |
2958 | * is importing from "import_vrf", cleanup appropriately. | |
2959 | */ | |
1d4e8b0d | 2960 | for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf, |
44338987 | 2961 | node, vname)) { |
2962 | if (strcmp(vname, export_name) == 0) | |
2963 | break; | |
2964 | } | |
2965 | ||
1d4e8b0d DS |
2966 | /* |
2967 | * If we have gotten to this point then the vname must | |
2968 | * exist. If not, we are in a world of trouble and | |
2969 | * have slag sitting around. | |
2970 | * | |
2971 | * import_vrf and export_vrf must match in having | |
2972 | * the in/out names as appropriate. | |
9ecf931b CS |
2973 | * export_vrf list could have been cleaned up |
2974 | * as part of no router bgp source instnace. | |
1d4e8b0d | 2975 | */ |
9ecf931b CS |
2976 | if (!vname) |
2977 | return; | |
1d4e8b0d DS |
2978 | |
2979 | listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname); | |
44338987 | 2980 | XFREE(MTYPE_TMP, vname); |
2981 | ||
1d4e8b0d DS |
2982 | if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) { |
2983 | vpn_leak_prechange(edir, afi, bgp_get_default(), from_bgp); | |
2984 | ecommunity_free(&from_bgp->vpn_policy[afi].rtlist[edir]); | |
2985 | UNSET_FLAG(from_bgp->af_flags[afi][safi], | |
44338987 | 2986 | BGP_CONFIG_VRF_TO_VRF_EXPORT); |
1d4e8b0d | 2987 | memset(&from_bgp->vpn_policy[afi].tovpn_rd, 0, |
44338987 | 2988 | sizeof(struct prefix_rd)); |
1d4e8b0d | 2989 | UNSET_FLAG(from_bgp->vpn_policy[afi].flags, |
44338987 | 2990 | BGP_VPN_POLICY_TOVPN_RD_SET); |
13b7e7f0 DS |
2991 | from_bgp->vpn_policy[afi].tovpn_label = MPLS_LABEL_NONE; |
2992 | ||
44338987 | 2993 | } |
2994 | } | |
2995 | ||
718e3744 | 2996 | /* For testing purpose, static route of MPLS-VPN. */ |
2997 | DEFUN (vpnv4_network, | |
2998 | vpnv4_network_cmd, | |
d114b977 | 2999 | "network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)", |
718e3744 | 3000 | "Specify a network to announce via BGP\n" |
0c7b1b01 | 3001 | "IPv4 prefix\n" |
718e3744 | 3002 | "Specify Route Distinguisher\n" |
3003 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
3004 | "VPN NLRI label (tag)\n" |
3005 | "VPN NLRI label (tag)\n" | |
3006 | "Label value\n") | |
718e3744 | 3007 | { |
d62a17ae | 3008 | int idx_ipv4_prefixlen = 1; |
3009 | int idx_ext_community = 3; | |
3010 | int idx_label = 5; | |
3011 | return bgp_static_set_safi( | |
3012 | AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, | |
3013 | argv[idx_ext_community]->arg, argv[idx_label]->arg, NULL, 0, | |
3014 | NULL, NULL, NULL, NULL); | |
137446f9 LB |
3015 | } |
3016 | ||
3017 | DEFUN (vpnv4_network_route_map, | |
3018 | vpnv4_network_route_map_cmd, | |
70dd370f | 3019 | "network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) route-map RMAP_NAME", |
137446f9 | 3020 | "Specify a network to announce via BGP\n" |
0c7b1b01 | 3021 | "IPv4 prefix\n" |
137446f9 LB |
3022 | "Specify Route Distinguisher\n" |
3023 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
3024 | "VPN NLRI label (tag)\n" |
3025 | "VPN NLRI label (tag)\n" | |
3026 | "Label value\n" | |
137446f9 LB |
3027 | "route map\n" |
3028 | "route map name\n") | |
3029 | { | |
d62a17ae | 3030 | int idx_ipv4_prefixlen = 1; |
3031 | int idx_ext_community = 3; | |
3032 | int idx_label = 5; | |
3033 | int idx_word_2 = 7; | |
3034 | return bgp_static_set_safi( | |
3035 | AFI_IP, SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, | |
3036 | argv[idx_ext_community]->arg, argv[idx_label]->arg, | |
3037 | argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); | |
718e3744 | 3038 | } |
3039 | ||
3040 | /* For testing purpose, static route of MPLS-VPN. */ | |
3041 | DEFUN (no_vpnv4_network, | |
3042 | no_vpnv4_network_cmd, | |
d114b977 | 3043 | "no network A.B.C.D/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)", |
718e3744 | 3044 | NO_STR |
3045 | "Specify a network to announce via BGP\n" | |
0c7b1b01 | 3046 | "IPv4 prefix\n" |
718e3744 | 3047 | "Specify Route Distinguisher\n" |
3048 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
3049 | "VPN NLRI label (tag)\n" |
3050 | "VPN NLRI label (tag)\n" | |
3051 | "Label value\n") | |
718e3744 | 3052 | { |
d62a17ae | 3053 | int idx_ipv4_prefixlen = 2; |
3054 | int idx_ext_community = 4; | |
3055 | int idx_label = 6; | |
3056 | return bgp_static_unset_safi(AFI_IP, SAFI_MPLS_VPN, vty, | |
3057 | argv[idx_ipv4_prefixlen]->arg, | |
3058 | argv[idx_ext_community]->arg, | |
3059 | argv[idx_label]->arg, 0, NULL, NULL, NULL); | |
718e3744 | 3060 | } |
3061 | ||
c286be96 LX |
3062 | DEFUN (vpnv6_network, |
3063 | vpnv6_network_cmd, | |
70dd370f | 3064 | "network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575) [route-map RMAP_NAME]", |
c286be96 LX |
3065 | "Specify a network to announce via BGP\n" |
3066 | "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" | |
3067 | "Specify Route Distinguisher\n" | |
3068 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
3069 | "VPN NLRI label (tag)\n" |
3070 | "VPN NLRI label (tag)\n" | |
3071 | "Label value\n" | |
11daee81 DS |
3072 | "route map\n" |
3073 | "route map name\n") | |
c286be96 | 3074 | { |
d62a17ae | 3075 | int idx_ipv6_prefix = 1; |
3076 | int idx_ext_community = 3; | |
3077 | int idx_label = 5; | |
3078 | int idx_word_2 = 7; | |
3079 | if (argc == 8) | |
3080 | return bgp_static_set_safi( | |
3081 | AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, | |
3082 | argv[idx_ext_community]->arg, argv[idx_label]->arg, | |
3083 | argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); | |
3084 | else | |
3085 | return bgp_static_set_safi( | |
3086 | AFI_IP6, SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, | |
3087 | argv[idx_ext_community]->arg, argv[idx_label]->arg, | |
3088 | NULL, 0, NULL, NULL, NULL, NULL); | |
c286be96 LX |
3089 | } |
3090 | ||
3091 | /* For testing purpose, static route of MPLS-VPN. */ | |
3092 | DEFUN (no_vpnv6_network, | |
3093 | no_vpnv6_network_cmd, | |
d114b977 | 3094 | "no network X:X::X:X/M rd ASN:NN_OR_IP-ADDRESS:NN <tag|label> (0-1048575)", |
c286be96 LX |
3095 | NO_STR |
3096 | "Specify a network to announce via BGP\n" | |
3097 | "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" | |
3098 | "Specify Route Distinguisher\n" | |
3099 | "VPN Route Distinguisher\n" | |
fb1d2a2d LB |
3100 | "VPN NLRI label (tag)\n" |
3101 | "VPN NLRI label (tag)\n" | |
3102 | "Label value\n") | |
c286be96 | 3103 | { |
d62a17ae | 3104 | int idx_ipv6_prefix = 2; |
3105 | int idx_ext_community = 4; | |
3106 | int idx_label = 6; | |
3107 | return bgp_static_unset_safi(AFI_IP6, SAFI_MPLS_VPN, vty, | |
3108 | argv[idx_ipv6_prefix]->arg, | |
3109 | argv[idx_ext_community]->arg, | |
3110 | argv[idx_label]->arg, 0, NULL, NULL, NULL); | |
c286be96 LX |
3111 | } |
3112 | ||
d62a17ae | 3113 | int bgp_show_mpls_vpn(struct vty *vty, afi_t afi, struct prefix_rd *prd, |
3114 | enum bgp_show_type type, void *output_arg, int tags, | |
9f049418 | 3115 | bool use_json) |
718e3744 | 3116 | { |
d62a17ae | 3117 | struct bgp *bgp; |
3118 | struct bgp_table *table; | |
27bb782a DA |
3119 | uint16_t show_flags = 0; |
3120 | ||
3121 | if (use_json) | |
3122 | SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); | |
d62a17ae | 3123 | |
3124 | bgp = bgp_get_default(); | |
3125 | if (bgp == NULL) { | |
3126 | if (!use_json) | |
3127 | vty_out(vty, "No BGP process is configured\n"); | |
16307668 RW |
3128 | else |
3129 | vty_out(vty, "{}\n"); | |
d62a17ae | 3130 | return CMD_WARNING; |
3131 | } | |
1ae44dfc | 3132 | table = bgp->rib[afi][SAFI_MPLS_VPN]; |
a4d82a8a | 3133 | return bgp_show_table_rd(vty, bgp, SAFI_MPLS_VPN, table, prd, type, |
27bb782a | 3134 | output_arg, show_flags); |
718e3744 | 3135 | } |
3136 | ||
4f280b15 LB |
3137 | DEFUN (show_bgp_ip_vpn_all_rd, |
3138 | show_bgp_ip_vpn_all_rd_cmd, | |
a111dd97 | 3139 | "show bgp "BGP_AFI_CMD_STR" vpn all [rd <ASN:NN_OR_IP-ADDRESS:NN|all>] [json]", |
e3e29b32 LB |
3140 | SHOW_STR |
3141 | BGP_STR | |
05e588f4 | 3142 | BGP_VPNVX_HELP_STR |
e3e29b32 | 3143 | "Display VPN NLRI specific information\n" |
af8528fa | 3144 | "Display VPN NLRI specific information\n" |
e3e29b32 LB |
3145 | "Display information for a route distinguisher\n" |
3146 | "VPN Route Distinguisher\n" | |
a111dd97 | 3147 | "All VPN Route Distinguishers\n" |
e3e29b32 LB |
3148 | JSON_STR) |
3149 | { | |
d62a17ae | 3150 | int ret; |
3151 | struct prefix_rd prd; | |
3152 | afi_t afi; | |
3153 | int idx = 0; | |
3154 | ||
3155 | if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
3156 | /* Constrain search if user supplies RD && RD != "all" */ |
3157 | if (argv_find(argv, argc, "rd", &idx) | |
3158 | && strcmp(argv[idx + 1]->arg, "all")) { | |
a4d82a8a | 3159 | ret = str2prefix_rd(argv[idx + 1]->arg, &prd); |
d62a17ae | 3160 | if (!ret) { |
3161 | vty_out(vty, | |
3162 | "%% Malformed Route Distinguisher\n"); | |
3163 | return CMD_WARNING; | |
3164 | } | |
3165 | return bgp_show_mpls_vpn(vty, afi, &prd, | |
3166 | bgp_show_type_normal, NULL, 0, | |
3167 | use_json(argc, argv)); | |
3168 | } else { | |
3169 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
3170 | bgp_show_type_normal, NULL, 0, | |
3171 | use_json(argc, argv)); | |
3172 | } | |
3173 | } | |
3174 | return CMD_SUCCESS; | |
718e3744 | 3175 | } |
3176 | ||
af8528fa LB |
3177 | ALIAS(show_bgp_ip_vpn_all_rd, |
3178 | show_bgp_ip_vpn_rd_cmd, | |
a111dd97 | 3179 | "show bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all> [json]", |
af8528fa LB |
3180 | SHOW_STR |
3181 | BGP_STR | |
3182 | BGP_VPNVX_HELP_STR | |
3183 | "Display VPN NLRI specific information\n" | |
3184 | "Display information for a route distinguisher\n" | |
3185 | "VPN Route Distinguisher\n" | |
a111dd97 | 3186 | "All VPN Route Distinguishers\n" |
af8528fa LB |
3187 | JSON_STR) |
3188 | ||
3189 | #ifdef KEEP_OLD_VPN_COMMANDS | |
3f227172 PG |
3190 | DEFUN (show_ip_bgp_vpn_rd, |
3191 | show_ip_bgp_vpn_rd_cmd, | |
a111dd97 | 3192 | "show ip bgp "BGP_AFI_CMD_STR" vpn rd <ASN:NN_OR_IP-ADDRESS:NN|all>", |
718e3744 | 3193 | SHOW_STR |
3194 | IP_STR | |
3195 | BGP_STR | |
4f280b15 | 3196 | BGP_AFI_HELP_STR |
00e6edb9 | 3197 | BGP_AF_MODIFIER_STR |
718e3744 | 3198 | "Display information for a route distinguisher\n" |
a111dd97 TA |
3199 | "VPN Route Distinguisher\n" |
3200 | "All VPN Route Distinguishers\n") | |
718e3744 | 3201 | { |
d62a17ae | 3202 | int idx_ext_community = argc - 1; |
3203 | int ret; | |
3204 | struct prefix_rd prd; | |
3205 | afi_t afi; | |
3206 | int idx = 0; | |
3207 | ||
3208 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
3209 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
3210 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
3211 | bgp_show_type_normal, NULL, 0, | |
3212 | 0); | |
d62a17ae | 3213 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); |
3214 | if (!ret) { | |
3215 | vty_out(vty, "%% Malformed Route Distinguisher\n"); | |
3216 | return CMD_WARNING; | |
3217 | } | |
3218 | return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal, | |
3219 | NULL, 0, 0); | |
3220 | } | |
3221 | return CMD_SUCCESS; | |
3222 | } | |
718e3744 | 3223 | |
4f280b15 LB |
3224 | DEFUN (show_ip_bgp_vpn_all, |
3225 | show_ip_bgp_vpn_all_cmd, | |
3226 | "show [ip] bgp <vpnv4|vpnv6>", | |
3227 | SHOW_STR | |
3228 | IP_STR | |
3229 | BGP_STR | |
3230 | BGP_VPNVX_HELP_STR) | |
3231 | { | |
d62a17ae | 3232 | afi_t afi; |
3233 | int idx = 0; | |
4f280b15 | 3234 | |
d62a17ae | 3235 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) |
3236 | return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal, | |
3237 | NULL, 0, 0); | |
3238 | return CMD_SUCCESS; | |
4f280b15 LB |
3239 | } |
3240 | ||
3f227172 PG |
3241 | DEFUN (show_ip_bgp_vpn_all_tags, |
3242 | show_ip_bgp_vpn_all_tags_cmd, | |
3243 | "show [ip] bgp <vpnv4|vpnv6> all tags", | |
718e3744 | 3244 | SHOW_STR |
3245 | IP_STR | |
3246 | BGP_STR | |
3f227172 PG |
3247 | BGP_VPNVX_HELP_STR |
3248 | "Display information about all VPNv4/VPNV6 NLRIs\n" | |
718e3744 | 3249 | "Display BGP tags for prefixes\n") |
3250 | { | |
d62a17ae | 3251 | afi_t afi; |
3252 | int idx = 0; | |
3f227172 | 3253 | |
d62a17ae | 3254 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) |
3255 | return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_normal, | |
3256 | NULL, 1, 0); | |
3257 | return CMD_SUCCESS; | |
718e3744 | 3258 | } |
3259 | ||
3f227172 PG |
3260 | DEFUN (show_ip_bgp_vpn_rd_tags, |
3261 | show_ip_bgp_vpn_rd_tags_cmd, | |
a111dd97 | 3262 | "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> tags", |
718e3744 | 3263 | SHOW_STR |
3264 | IP_STR | |
3265 | BGP_STR | |
3f227172 | 3266 | BGP_VPNVX_HELP_STR |
718e3744 | 3267 | "Display information for a route distinguisher\n" |
3268 | "VPN Route Distinguisher\n" | |
a111dd97 | 3269 | "All VPN Route Distinguishers\n" |
718e3744 | 3270 | "Display BGP tags for prefixes\n") |
3271 | { | |
d62a17ae | 3272 | int idx_ext_community = 5; |
3273 | int ret; | |
3274 | struct prefix_rd prd; | |
3275 | afi_t afi; | |
3276 | int idx = 0; | |
3277 | ||
3278 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
3279 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
3280 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
3281 | bgp_show_type_normal, NULL, 1, | |
3282 | 0); | |
d62a17ae | 3283 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); |
3284 | if (!ret) { | |
3285 | vty_out(vty, "%% Malformed Route Distinguisher\n"); | |
3286 | return CMD_WARNING; | |
3287 | } | |
3288 | return bgp_show_mpls_vpn(vty, afi, &prd, bgp_show_type_normal, | |
3289 | NULL, 1, 0); | |
3290 | } | |
3291 | return CMD_SUCCESS; | |
718e3744 | 3292 | } |
3293 | ||
3f227172 PG |
3294 | DEFUN (show_ip_bgp_vpn_all_neighbor_routes, |
3295 | show_ip_bgp_vpn_all_neighbor_routes_cmd, | |
3296 | "show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D routes [json]", | |
718e3744 | 3297 | SHOW_STR |
3298 | IP_STR | |
3299 | BGP_STR | |
3f227172 PG |
3300 | BGP_VPNVX_HELP_STR |
3301 | "Display information about all VPNv4/VPNv6 NLRIs\n" | |
718e3744 | 3302 | "Detailed information on TCP and BGP neighbor connections\n" |
3303 | "Neighbor to display information about\n" | |
856ca177 | 3304 | "Display routes learned from neighbor\n" |
9973d184 | 3305 | JSON_STR) |
718e3744 | 3306 | { |
d62a17ae | 3307 | int idx_ipv4 = 6; |
3308 | union sockunion su; | |
3309 | struct peer *peer; | |
3310 | int ret; | |
9f049418 | 3311 | bool uj = use_json(argc, argv); |
d62a17ae | 3312 | afi_t afi; |
3313 | int idx = 0; | |
3314 | ||
3315 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
3316 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
3317 | if (ret < 0) { | |
3318 | if (uj) { | |
3319 | json_object *json_no = NULL; | |
3320 | json_no = json_object_new_object(); | |
3321 | json_object_string_add(json_no, "warning", | |
3322 | "Malformed address"); | |
3323 | vty_out(vty, "%s\n", | |
3324 | json_object_to_json_string(json_no)); | |
3325 | json_object_free(json_no); | |
3326 | } else | |
3327 | vty_out(vty, "Malformed address: %s\n", | |
3328 | argv[idx_ipv4]->arg); | |
3329 | return CMD_WARNING; | |
3330 | } | |
3331 | ||
3332 | peer = peer_lookup(NULL, &su); | |
3333 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
3334 | if (uj) { | |
3335 | json_object *json_no = NULL; | |
3336 | json_no = json_object_new_object(); | |
3337 | json_object_string_add( | |
3338 | json_no, "warning", | |
3339 | "No such neighbor or address family"); | |
3340 | vty_out(vty, "%s\n", | |
3341 | json_object_to_json_string(json_no)); | |
3342 | json_object_free(json_no); | |
3343 | } else | |
3344 | vty_out(vty, | |
3345 | "%% No such neighbor or address family\n"); | |
3346 | return CMD_WARNING; | |
3347 | } | |
3348 | ||
3349 | return bgp_show_mpls_vpn(vty, afi, NULL, bgp_show_type_neighbor, | |
3350 | &su, 0, uj); | |
3351 | } | |
3352 | return CMD_SUCCESS; | |
718e3744 | 3353 | } |
3354 | ||
3f227172 PG |
3355 | DEFUN (show_ip_bgp_vpn_rd_neighbor_routes, |
3356 | show_ip_bgp_vpn_rd_neighbor_routes_cmd, | |
a111dd97 | 3357 | "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D routes [json]", |
718e3744 | 3358 | SHOW_STR |
3359 | IP_STR | |
3360 | BGP_STR | |
3f227172 | 3361 | BGP_VPNVX_HELP_STR |
718e3744 | 3362 | "Display information for a route distinguisher\n" |
3363 | "VPN Route Distinguisher\n" | |
a111dd97 | 3364 | "All VPN Route Distinguishers\n" |
718e3744 | 3365 | "Detailed information on TCP and BGP neighbor connections\n" |
3366 | "Neighbor to display information about\n" | |
856ca177 | 3367 | "Display routes learned from neighbor\n" |
9973d184 | 3368 | JSON_STR) |
718e3744 | 3369 | { |
d62a17ae | 3370 | int idx_ext_community = 5; |
3371 | int idx_ipv4 = 7; | |
3372 | int ret; | |
3373 | union sockunion su; | |
3374 | struct peer *peer; | |
3375 | struct prefix_rd prd; | |
a111dd97 | 3376 | bool prefix_rd_all = false; |
9f049418 | 3377 | bool uj = use_json(argc, argv); |
d62a17ae | 3378 | afi_t afi; |
3379 | int idx = 0; | |
3380 | ||
3381 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
a111dd97 TA |
3382 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
3383 | prefix_rd_all = true; | |
3384 | else { | |
3385 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); | |
3386 | if (!ret) { | |
3387 | if (uj) { | |
3388 | json_object *json_no = NULL; | |
3389 | json_no = json_object_new_object(); | |
3390 | json_object_string_add( | |
3391 | json_no, "warning", | |
3392 | "Malformed Route Distinguisher"); | |
3393 | vty_out(vty, "%s\n", | |
3394 | json_object_to_json_string( | |
3395 | json_no)); | |
3396 | json_object_free(json_no); | |
3397 | } else | |
3398 | vty_out(vty, | |
3399 | "%% Malformed Route Distinguisher\n"); | |
3400 | return CMD_WARNING; | |
3401 | } | |
d62a17ae | 3402 | } |
3403 | ||
3404 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
3405 | if (ret < 0) { | |
3406 | if (uj) { | |
3407 | json_object *json_no = NULL; | |
3408 | json_no = json_object_new_object(); | |
3409 | json_object_string_add(json_no, "warning", | |
3410 | "Malformed address"); | |
3411 | vty_out(vty, "%s\n", | |
3412 | json_object_to_json_string(json_no)); | |
3413 | json_object_free(json_no); | |
3414 | } else | |
3415 | vty_out(vty, "Malformed address: %s\n", | |
3416 | argv[idx_ext_community]->arg); | |
3417 | return CMD_WARNING; | |
3418 | } | |
3419 | ||
3420 | peer = peer_lookup(NULL, &su); | |
3421 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
3422 | if (uj) { | |
3423 | json_object *json_no = NULL; | |
3424 | json_no = json_object_new_object(); | |
3425 | json_object_string_add( | |
3426 | json_no, "warning", | |
3427 | "No such neighbor or address family"); | |
3428 | vty_out(vty, "%s\n", | |
3429 | json_object_to_json_string(json_no)); | |
3430 | json_object_free(json_no); | |
3431 | } else | |
3432 | vty_out(vty, | |
3433 | "%% No such neighbor or address family\n"); | |
3434 | return CMD_WARNING; | |
3435 | } | |
3436 | ||
a111dd97 TA |
3437 | if (prefix_rd_all) |
3438 | return bgp_show_mpls_vpn(vty, afi, NULL, | |
3439 | bgp_show_type_neighbor, &su, 0, | |
3440 | uj); | |
3441 | else | |
3442 | return bgp_show_mpls_vpn(vty, afi, &prd, | |
3443 | bgp_show_type_neighbor, &su, 0, | |
3444 | uj); | |
d62a17ae | 3445 | } |
3446 | return CMD_SUCCESS; | |
718e3744 | 3447 | } |
3448 | ||
3f227172 PG |
3449 | DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes, |
3450 | show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd, | |
3451 | "show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D advertised-routes [json]", | |
718e3744 | 3452 | SHOW_STR |
3453 | IP_STR | |
3454 | BGP_STR | |
3f227172 PG |
3455 | BGP_VPNVX_HELP_STR |
3456 | "Display information about all VPNv4/VPNv6 NLRIs\n" | |
718e3744 | 3457 | "Detailed information on TCP and BGP neighbor connections\n" |
3458 | "Neighbor to display information about\n" | |
856ca177 | 3459 | "Display the routes advertised to a BGP neighbor\n" |
9973d184 | 3460 | JSON_STR) |
718e3744 | 3461 | { |
d62a17ae | 3462 | int idx_ipv4 = 6; |
3463 | int ret; | |
3464 | struct peer *peer; | |
3465 | union sockunion su; | |
9f049418 | 3466 | bool uj = use_json(argc, argv); |
d62a17ae | 3467 | afi_t afi; |
3468 | int idx = 0; | |
3469 | ||
3470 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
3471 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
3472 | if (ret < 0) { | |
3473 | if (uj) { | |
3474 | json_object *json_no = NULL; | |
3475 | json_no = json_object_new_object(); | |
3476 | json_object_string_add(json_no, "warning", | |
3477 | "Malformed address"); | |
3478 | vty_out(vty, "%s\n", | |
3479 | json_object_to_json_string(json_no)); | |
3480 | json_object_free(json_no); | |
3481 | } else | |
3482 | vty_out(vty, "Malformed address: %s\n", | |
3483 | argv[idx_ipv4]->arg); | |
3484 | return CMD_WARNING; | |
3485 | } | |
3486 | peer = peer_lookup(NULL, &su); | |
3487 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
3488 | if (uj) { | |
3489 | json_object *json_no = NULL; | |
3490 | json_no = json_object_new_object(); | |
3491 | json_object_string_add( | |
3492 | json_no, "warning", | |
3493 | "No such neighbor or address family"); | |
3494 | vty_out(vty, "%s\n", | |
3495 | json_object_to_json_string(json_no)); | |
3496 | json_object_free(json_no); | |
3497 | } else | |
3498 | vty_out(vty, | |
3499 | "%% No such neighbor or address family\n"); | |
3500 | return CMD_WARNING; | |
3501 | } | |
3502 | return show_adj_route_vpn(vty, peer, NULL, AFI_IP, | |
3503 | SAFI_MPLS_VPN, uj); | |
3504 | } | |
3505 | return CMD_SUCCESS; | |
718e3744 | 3506 | } |
3507 | ||
3f227172 PG |
3508 | DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, |
3509 | show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd, | |
a111dd97 | 3510 | "show [ip] bgp <vpnv4|vpnv6> rd <ASN:NN_OR_IP-ADDRESS:NN|all> neighbors A.B.C.D advertised-routes [json]", |
718e3744 | 3511 | SHOW_STR |
3512 | IP_STR | |
3513 | BGP_STR | |
3f227172 | 3514 | BGP_VPNVX_HELP_STR |
718e3744 | 3515 | "Display information for a route distinguisher\n" |
3516 | "VPN Route Distinguisher\n" | |
a111dd97 | 3517 | "All VPN Route Distinguishers\n" |
718e3744 | 3518 | "Detailed information on TCP and BGP neighbor connections\n" |
3519 | "Neighbor to display information about\n" | |
856ca177 | 3520 | "Display the routes advertised to a BGP neighbor\n" |
9973d184 | 3521 | JSON_STR) |
718e3744 | 3522 | { |
d62a17ae | 3523 | int idx_ext_community = 5; |
3524 | int idx_ipv4 = 7; | |
3525 | int ret; | |
3526 | struct peer *peer; | |
3527 | struct prefix_rd prd; | |
3528 | union sockunion su; | |
9f049418 | 3529 | bool uj = use_json(argc, argv); |
d62a17ae | 3530 | afi_t afi; |
3531 | int idx = 0; | |
3532 | ||
3533 | if (argv_find_and_parse_vpnvx(argv, argc, &idx, &afi)) { | |
3534 | ret = str2sockunion(argv[idx_ipv4]->arg, &su); | |
3535 | if (ret < 0) { | |
3536 | if (uj) { | |
3537 | json_object *json_no = NULL; | |
3538 | json_no = json_object_new_object(); | |
3539 | json_object_string_add(json_no, "warning", | |
3540 | "Malformed address"); | |
3541 | vty_out(vty, "%s\n", | |
3542 | json_object_to_json_string(json_no)); | |
3543 | json_object_free(json_no); | |
3544 | } else | |
3545 | vty_out(vty, "Malformed address: %s\n", | |
3546 | argv[idx_ext_community]->arg); | |
3547 | return CMD_WARNING; | |
3548 | } | |
3549 | peer = peer_lookup(NULL, &su); | |
3550 | if (!peer || !peer->afc[afi][SAFI_MPLS_VPN]) { | |
3551 | if (uj) { | |
3552 | json_object *json_no = NULL; | |
3553 | json_no = json_object_new_object(); | |
3554 | json_object_string_add( | |
3555 | json_no, "warning", | |
3556 | "No such neighbor or address family"); | |
3557 | vty_out(vty, "%s\n", | |
3558 | json_object_to_json_string(json_no)); | |
3559 | json_object_free(json_no); | |
3560 | } else | |
3561 | vty_out(vty, | |
3562 | "%% No such neighbor or address family\n"); | |
3563 | return CMD_WARNING; | |
3564 | } | |
3565 | ||
a111dd97 TA |
3566 | if (!strcmp(argv[idx_ext_community]->arg, "all")) |
3567 | return show_adj_route_vpn(vty, peer, NULL, AFI_IP, | |
3568 | SAFI_MPLS_VPN, uj); | |
d62a17ae | 3569 | ret = str2prefix_rd(argv[idx_ext_community]->arg, &prd); |
3570 | if (!ret) { | |
3571 | if (uj) { | |
3572 | json_object *json_no = NULL; | |
3573 | json_no = json_object_new_object(); | |
3574 | json_object_string_add( | |
3575 | json_no, "warning", | |
3576 | "Malformed Route Distinguisher"); | |
3577 | vty_out(vty, "%s\n", | |
3578 | json_object_to_json_string(json_no)); | |
3579 | json_object_free(json_no); | |
3580 | } else | |
3581 | vty_out(vty, | |
3582 | "%% Malformed Route Distinguisher\n"); | |
3583 | return CMD_WARNING; | |
3584 | } | |
3585 | ||
3586 | return show_adj_route_vpn(vty, peer, &prd, AFI_IP, | |
3587 | SAFI_MPLS_VPN, uj); | |
3588 | } | |
3589 | return CMD_SUCCESS; | |
718e3744 | 3590 | } |
d6902373 | 3591 | #endif /* KEEP_OLD_VPN_COMMANDS */ |
718e3744 | 3592 | |
d62a17ae | 3593 | void bgp_mplsvpn_init(void) |
718e3744 | 3594 | { |
d62a17ae | 3595 | install_element(BGP_VPNV4_NODE, &vpnv4_network_cmd); |
3596 | install_element(BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd); | |
3597 | install_element(BGP_VPNV4_NODE, &no_vpnv4_network_cmd); | |
718e3744 | 3598 | |
d62a17ae | 3599 | install_element(BGP_VPNV6_NODE, &vpnv6_network_cmd); |
3600 | install_element(BGP_VPNV6_NODE, &no_vpnv6_network_cmd); | |
c286be96 | 3601 | |
d62a17ae | 3602 | install_element(VIEW_NODE, &show_bgp_ip_vpn_all_rd_cmd); |
af8528fa | 3603 | install_element(VIEW_NODE, &show_bgp_ip_vpn_rd_cmd); |
d6902373 | 3604 | #ifdef KEEP_OLD_VPN_COMMANDS |
af8528fa | 3605 | install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_cmd); |
d62a17ae | 3606 | install_element(VIEW_NODE, &show_ip_bgp_vpn_all_cmd); |
3607 | install_element(VIEW_NODE, &show_ip_bgp_vpn_all_tags_cmd); | |
3608 | install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_tags_cmd); | |
3609 | install_element(VIEW_NODE, &show_ip_bgp_vpn_all_neighbor_routes_cmd); | |
3610 | install_element(VIEW_NODE, &show_ip_bgp_vpn_rd_neighbor_routes_cmd); | |
3611 | install_element(VIEW_NODE, | |
3612 | &show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd); | |
3613 | install_element(VIEW_NODE, | |
3614 | &show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd); | |
d6902373 | 3615 | #endif /* KEEP_OLD_VPN_COMMANDS */ |
718e3744 | 3616 | } |
301ad80a PG |
3617 | |
3618 | vrf_id_t get_first_vrf_for_redirect_with_rt(struct ecommunity *eckey) | |
3619 | { | |
3620 | struct listnode *mnode, *mnnode; | |
3621 | struct bgp *bgp; | |
9a659715 PG |
3622 | afi_t afi = AFI_IP; |
3623 | ||
3624 | if (eckey->unit_size == IPV6_ECOMMUNITY_SIZE) | |
3625 | afi = AFI_IP6; | |
301ad80a PG |
3626 | |
3627 | for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) { | |
3628 | struct ecommunity *ec; | |
3629 | ||
3630 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
3631 | continue; | |
3632 | ||
9a659715 PG |
3633 | ec = bgp->vpn_policy[afi].import_redirect_rtlist; |
3634 | ||
3635 | if (ec && eckey->unit_size != ec->unit_size) | |
3636 | continue; | |
301ad80a | 3637 | |
2d7cdc5b | 3638 | if (ecommunity_include(ec, eckey)) |
301ad80a PG |
3639 | return bgp->vrf_id; |
3640 | } | |
3641 | return VRF_UNKNOWN; | |
3642 | } | |
3bd70bf8 PZ |
3643 | |
3644 | /* | |
3645 | * The purpose of this function is to process leaks that were deferred | |
3646 | * from earlier per-vrf configuration due to not-yet-existing default | |
3647 | * vrf, in other words, configuration such as: | |
3648 | * | |
3649 | * router bgp MMM vrf FOO | |
3650 | * address-family ipv4 unicast | |
3651 | * rd vpn export 1:1 | |
3652 | * exit-address-family | |
3653 | * | |
3654 | * router bgp NNN | |
3655 | * ... | |
3656 | * | |
3657 | * This function gets called when the default instance ("router bgp NNN") | |
3658 | * is created. | |
3659 | */ | |
3660 | void vpn_leak_postchange_all(void) | |
3661 | { | |
3662 | struct listnode *next; | |
3663 | struct bgp *bgp; | |
3664 | struct bgp *bgp_default = bgp_get_default(); | |
3665 | ||
3666 | assert(bgp_default); | |
3667 | ||
3668 | /* First, do any exporting from VRFs to the single VPN RIB */ | |
3669 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { | |
3670 | ||
3671 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
3672 | continue; | |
3673 | ||
3674 | vpn_leak_postchange( | |
3675 | BGP_VPN_POLICY_DIR_TOVPN, | |
3676 | AFI_IP, | |
3677 | bgp_default, | |
3678 | bgp); | |
3679 | ||
3680 | vpn_leak_postchange( | |
3681 | BGP_VPN_POLICY_DIR_TOVPN, | |
3682 | AFI_IP6, | |
3683 | bgp_default, | |
3684 | bgp); | |
3685 | } | |
3686 | ||
3687 | /* Now, do any importing to VRFs from the single VPN RIB */ | |
3688 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { | |
3689 | ||
3690 | if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
3691 | continue; | |
3692 | ||
3693 | vpn_leak_postchange( | |
3694 | BGP_VPN_POLICY_DIR_FROMVPN, | |
3695 | AFI_IP, | |
3696 | bgp_default, | |
3697 | bgp); | |
3698 | ||
3699 | vpn_leak_postchange( | |
3700 | BGP_VPN_POLICY_DIR_FROMVPN, | |
3701 | AFI_IP6, | |
3702 | bgp_default, | |
3703 | bgp); | |
3704 | } | |
3705 | } | |
9ecf931b CS |
3706 | |
3707 | /* When a bgp vrf instance is unconfigured, remove its routes | |
3708 | * from the VPN table and this vrf could be importing routes from other | |
3709 | * bgp vrf instnaces, unimport them. | |
3710 | * VRF X and VRF Y are exporting routes to each other. | |
3711 | * When VRF X is deleted, unimport its routes from all target vrfs, | |
3712 | * also VRF Y should unimport its routes from VRF X table. | |
3713 | * This will ensure VPN table is cleaned up appropriately. | |
3714 | */ | |
ff8a8a7a | 3715 | void bgp_vpn_leak_unimport(struct bgp *from_bgp) |
9ecf931b CS |
3716 | { |
3717 | struct bgp *to_bgp; | |
3718 | const char *tmp_name; | |
3719 | char *vname; | |
3720 | struct listnode *node, *next; | |
3721 | safi_t safi = SAFI_UNICAST; | |
3722 | afi_t afi; | |
3723 | bool is_vrf_leak_bind; | |
3724 | int debug; | |
3725 | ||
3726 | if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) | |
ff8a8a7a | 3727 | return; |
9ecf931b CS |
3728 | |
3729 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | | |
3730 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
3731 | ||
3732 | tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; | |
3733 | ||
3734 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
3735 | /* vrf leak is for IPv4 and IPv6 Unicast only */ | |
3736 | if (afi != AFI_IP && afi != AFI_IP6) | |
3737 | continue; | |
3738 | ||
3739 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) { | |
3740 | if (from_bgp == to_bgp) | |
3741 | continue; | |
3742 | ||
3743 | /* Unimport and remove source vrf from the | |
3744 | * other vrfs import list. | |
3745 | */ | |
3746 | struct vpn_policy *to_vpolicy; | |
3747 | ||
3748 | is_vrf_leak_bind = false; | |
3749 | to_vpolicy = &(to_bgp->vpn_policy[afi]); | |
3750 | for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, node, | |
3751 | vname)) { | |
3752 | if (strcmp(vname, tmp_name) == 0) { | |
3753 | is_vrf_leak_bind = true; | |
3754 | break; | |
3755 | } | |
3756 | } | |
3757 | /* skip this bgp instance as there is no leak to this | |
3758 | * vrf instance. | |
3759 | */ | |
3760 | if (!is_vrf_leak_bind) | |
3761 | continue; | |
3762 | ||
3763 | if (debug) | |
3764 | zlog_debug("%s: unimport routes from %s to_bgp %s afi %s import vrfs count %u", | |
3765 | __func__, from_bgp->name_pretty, | |
3766 | to_bgp->name_pretty, afi2str(afi), | |
3767 | to_vpolicy->import_vrf->count); | |
3768 | ||
3769 | vrf_unimport_from_vrf(to_bgp, from_bgp, afi, safi); | |
3770 | ||
3771 | /* readd vrf name as unimport removes import vrf name | |
3772 | * from the destination vrf's import list where the | |
3773 | * `import vrf` configuration still exist. | |
3774 | */ | |
3775 | vname = XSTRDUP(MTYPE_TMP, tmp_name); | |
3776 | listnode_add(to_bgp->vpn_policy[afi].import_vrf, | |
3777 | vname); | |
3778 | SET_FLAG(to_bgp->af_flags[afi][safi], | |
3779 | BGP_CONFIG_VRF_TO_VRF_IMPORT); | |
3780 | ||
3781 | /* If to_bgp exports its routes to the bgp vrf | |
3782 | * which is being deleted, un-import the | |
3783 | * to_bgp routes from VPN. | |
3784 | */ | |
3785 | for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi] | |
3786 | .export_vrf, node, | |
3787 | vname)) { | |
3788 | if (strcmp(vname, tmp_name) == 0) { | |
3789 | vrf_unimport_from_vrf(from_bgp, to_bgp, | |
3790 | afi, safi); | |
3791 | break; | |
3792 | } | |
3793 | } | |
3794 | } | |
3795 | } | |
ff8a8a7a | 3796 | return; |
9ecf931b | 3797 | } |
48381346 CS |
3798 | |
3799 | /* When a router bgp is configured, there could be a bgp vrf | |
3800 | * instance importing routes from this newly configured | |
3801 | * bgp vrf instance. Export routes from configured | |
3802 | * bgp vrf to VPN. | |
3803 | * VRF Y has import from bgp vrf x, | |
3804 | * when a bgp vrf x instance is created, export its routes | |
3805 | * to VRF Y instance. | |
3806 | */ | |
3807 | void bgp_vpn_leak_export(struct bgp *from_bgp) | |
3808 | { | |
3809 | afi_t afi; | |
3810 | const char *export_name; | |
3811 | char *vname; | |
3812 | struct listnode *node, *next; | |
3813 | struct ecommunity *ecom; | |
9c2fd3fe | 3814 | enum vpn_policy_direction idir, edir; |
48381346 CS |
3815 | safi_t safi = SAFI_UNICAST; |
3816 | struct bgp *to_bgp; | |
3817 | int debug; | |
3818 | ||
3819 | debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) | | |
3820 | BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF)); | |
3821 | ||
3822 | idir = BGP_VPN_POLICY_DIR_FROMVPN; | |
3823 | edir = BGP_VPN_POLICY_DIR_TOVPN; | |
3824 | ||
00d968c4 | 3825 | export_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME; |
48381346 CS |
3826 | |
3827 | for (afi = 0; afi < AFI_MAX; ++afi) { | |
3828 | /* vrf leak is for IPv4 and IPv6 Unicast only */ | |
3829 | if (afi != AFI_IP && afi != AFI_IP6) | |
3830 | continue; | |
3831 | ||
3832 | for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) { | |
3833 | if (from_bgp == to_bgp) | |
3834 | continue; | |
3835 | ||
3836 | /* bgp instance has import list, check to see if newly | |
3837 | * configured bgp instance is the list. | |
3838 | */ | |
3839 | struct vpn_policy *to_vpolicy; | |
3840 | ||
3841 | to_vpolicy = &(to_bgp->vpn_policy[afi]); | |
3842 | for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, | |
3843 | node, vname)) { | |
3844 | if (strcmp(vname, export_name) != 0) | |
3845 | continue; | |
3846 | ||
3847 | if (debug) | |
3848 | zlog_debug("%s: found from_bgp %s in to_bgp %s import list, import routes.", | |
3849 | __func__, | |
3850 | export_name, to_bgp->name_pretty); | |
3851 | ||
3852 | ecom = from_bgp->vpn_policy[afi].rtlist[edir]; | |
3853 | /* remove import rt, it will be readded | |
3854 | * as part of import from vrf. | |
3855 | */ | |
3856 | if (ecom) | |
3857 | ecommunity_del_val( | |
3858 | to_vpolicy->rtlist[idir], | |
3859 | (struct ecommunity_val *) | |
3860 | ecom->val); | |
3861 | vrf_import_from_vrf(to_bgp, from_bgp, | |
3862 | afi, safi); | |
3863 | break; | |
3864 | ||
3865 | } | |
3866 | } | |
3867 | } | |
3868 | } |