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