]>
Commit | Line | Data |
---|---|---|
718e3744 | 1 | /* MPLS-VPN |
2 | Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> | |
3 | ||
4 | This file is part of GNU Zebra. | |
5 | ||
6 | GNU Zebra is free software; you can redistribute it and/or modify it | |
7 | under the terms of the GNU General Public License as published by the | |
8 | Free Software Foundation; either version 2, or (at your option) any | |
9 | later version. | |
10 | ||
11 | GNU Zebra is distributed in the hope that it will be useful, but | |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
17 | along with GNU Zebra; see the file COPYING. If not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | 02111-1307, USA. */ | |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "command.h" | |
24 | #include "prefix.h" | |
25 | #include "log.h" | |
26 | #include "memory.h" | |
27 | #include "stream.h" | |
3f9c7369 | 28 | #include "queue.h" |
039f3a34 | 29 | #include "filter.h" |
718e3744 | 30 | |
856ca177 | 31 | #include "lib/json.h" |
718e3744 | 32 | #include "bgpd/bgpd.h" |
33 | #include "bgpd/bgp_table.h" | |
34 | #include "bgpd/bgp_route.h" | |
35 | #include "bgpd/bgp_attr.h" | |
36 | #include "bgpd/bgp_mplsvpn.h" | |
48a5452b | 37 | #include "bgpd/bgp_packet.h" |
3f227172 | 38 | #include "bgpd/bgp_vty.h" |
784d3a42 | 39 | #include "bgpd/bgp_vpn.h" |
718e3744 | 40 | |
65efcfce | 41 | #if ENABLE_BGP_VNC |
f8b6f499 | 42 | #include "bgpd/rfapi/rfapi_backend.h" |
65efcfce LB |
43 | #endif |
44 | ||
d6902373 | 45 | extern int |
3f227172 PG |
46 | argv_find_and_parse_vpnvx(struct cmd_token **argv, int argc, int *index, afi_t *afi) |
47 | { | |
48 | int ret = 0; | |
49 | if (argv_find (argv, argc, "vpnv4", index)) | |
50 | { | |
51 | ret = 1; | |
52 | if (afi) | |
53 | *afi = AFI_IP; | |
54 | } | |
55 | else if (argv_find (argv, argc, "vpnv6", index)) | |
56 | { | |
57 | ret = 1; | |
58 | if (afi) | |
59 | *afi = AFI_IP6; | |
60 | } | |
61 | return ret; | |
62 | } | |
63 | ||
1a39c60a | 64 | u_int16_t |
718e3744 | 65 | decode_rd_type (u_char *pnt) |
66 | { | |
67 | u_int16_t v; | |
68 | ||
69 | v = ((u_int16_t) *pnt++ << 8); | |
65efcfce LB |
70 | #if ENABLE_BGP_VNC |
71 | /* | |
72 | * VNC L2 stores LHI in lower byte, so omit it | |
73 | */ | |
74 | if (v != RD_TYPE_VNC_ETH) | |
75 | v |= (u_int16_t) *pnt; | |
76 | #else /* duplicate code for clarity */ | |
718e3744 | 77 | v |= (u_int16_t) *pnt; |
65efcfce LB |
78 | #endif |
79 | ||
718e3744 | 80 | return v; |
81 | } | |
82 | ||
65efcfce LB |
83 | void |
84 | encode_rd_type (u_int16_t v, u_char *pnt) | |
85 | { | |
86 | *((u_int16_t *)pnt) = htons(v); | |
87 | } | |
88 | ||
718e3744 | 89 | u_int32_t |
90 | decode_label (u_char *pnt) | |
91 | { | |
92 | u_int32_t l; | |
93 | ||
94 | l = ((u_int32_t) *pnt++ << 12); | |
95 | l |= (u_int32_t) *pnt++ << 4; | |
96 | l |= (u_int32_t) ((*pnt & 0xf0) >> 4); | |
97 | return l; | |
98 | } | |
99 | ||
65efcfce LB |
100 | void |
101 | encode_label(u_int32_t label, | |
102 | u_char *pnt) | |
103 | { | |
104 | if (pnt == NULL) | |
105 | return; | |
106 | *pnt++ = (label>>12) & 0xff; | |
107 | *pnt++ = (label>>4) & 0xff; | |
108 | *pnt++ = ((label<<4)+1) & 0xff; /* S=1 */ | |
109 | } | |
110 | ||
fe770c88 | 111 | /* type == RD_TYPE_AS */ |
1a39c60a | 112 | void |
718e3744 | 113 | decode_rd_as (u_char *pnt, struct rd_as *rd_as) |
114 | { | |
115 | rd_as->as = (u_int16_t) *pnt++ << 8; | |
116 | rd_as->as |= (u_int16_t) *pnt++; | |
117 | ||
118 | rd_as->val = ((u_int32_t) *pnt++ << 24); | |
119 | rd_as->val |= ((u_int32_t) *pnt++ << 16); | |
120 | rd_as->val |= ((u_int32_t) *pnt++ << 8); | |
121 | rd_as->val |= (u_int32_t) *pnt; | |
122 | } | |
123 | ||
fe770c88 | 124 | /* type == RD_TYPE_AS4 */ |
1a39c60a | 125 | void |
fe770c88 LB |
126 | decode_rd_as4 (u_char *pnt, struct rd_as *rd_as) |
127 | { | |
128 | rd_as->as = (u_int32_t) *pnt++ << 24; | |
129 | rd_as->as |= (u_int32_t) *pnt++ << 16; | |
130 | rd_as->as |= (u_int32_t) *pnt++ << 8; | |
131 | rd_as->as |= (u_int32_t) *pnt++; | |
132 | ||
133 | rd_as->val = ((u_int16_t) *pnt++ << 8); | |
134 | rd_as->val |= (u_int16_t) *pnt; | |
135 | } | |
136 | ||
137 | /* type == RD_TYPE_IP */ | |
1a39c60a | 138 | void |
718e3744 | 139 | decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip) |
140 | { | |
141 | memcpy (&rd_ip->ip, pnt, 4); | |
142 | pnt += 4; | |
143 | ||
144 | rd_ip->val = ((u_int16_t) *pnt++ << 8); | |
145 | rd_ip->val |= (u_int16_t) *pnt; | |
146 | } | |
147 | ||
65efcfce LB |
148 | #if ENABLE_BGP_VNC |
149 | /* type == RD_TYPE_VNC_ETH */ | |
784d3a42 | 150 | void |
65efcfce LB |
151 | decode_rd_vnc_eth (u_char *pnt, struct rd_vnc_eth *rd_vnc_eth) |
152 | { | |
153 | rd_vnc_eth->type = RD_TYPE_VNC_ETH; | |
154 | rd_vnc_eth->local_nve_id = pnt[1]; | |
155 | memcpy (rd_vnc_eth->macaddr.octet, pnt + 2, ETHER_ADDR_LEN); | |
156 | } | |
157 | #endif | |
158 | ||
718e3744 | 159 | int |
945c8fe9 LB |
160 | bgp_nlri_parse_vpn (struct peer *peer, struct attr *attr, |
161 | struct bgp_nlri *packet) | |
718e3744 | 162 | { |
163 | u_char *pnt; | |
164 | u_char *lim; | |
165 | struct prefix p; | |
945c8fe9 | 166 | int psize = 0; |
718e3744 | 167 | int prefixlen; |
718e3744 | 168 | u_int16_t type; |
169 | struct rd_as rd_as; | |
170 | struct rd_ip rd_ip; | |
171 | struct prefix_rd prd; | |
172 | u_char *tagpnt; | |
a82478b9 DS |
173 | afi_t afi; |
174 | safi_t safi; | |
adbac85e | 175 | int addpath_encoded; |
a82478b9 | 176 | u_int32_t addpath_id; |
718e3744 | 177 | |
178 | /* Check peer status. */ | |
179 | if (peer->status != Established) | |
180 | return 0; | |
181 | ||
182 | /* Make prefix_rd */ | |
183 | prd.family = AF_UNSPEC; | |
184 | prd.prefixlen = 64; | |
185 | ||
186 | pnt = packet->nlri; | |
187 | lim = pnt + packet->length; | |
a82478b9 DS |
188 | afi = packet->afi; |
189 | safi = packet->safi; | |
190 | addpath_id = 0; | |
191 | ||
192 | addpath_encoded = (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_RX_ADV) && | |
193 | CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ADDPATH_AF_TX_RCV)); | |
718e3744 | 194 | |
50905aa2 | 195 | #define VPN_PREFIXLEN_MIN_BYTES (3 + 8) /* label + RD */ |
718e3744 | 196 | for (; pnt < lim; pnt += psize) |
197 | { | |
198 | /* Clear prefix structure. */ | |
199 | memset (&p, 0, sizeof (struct prefix)); | |
200 | ||
a82478b9 DS |
201 | if (addpath_encoded) |
202 | { | |
cd808e74 DS |
203 | |
204 | /* When packet overflow occurs return immediately. */ | |
205 | if (pnt + BGP_ADDPATH_ID_LEN > lim) | |
206 | return -1; | |
207 | ||
a82478b9 DS |
208 | addpath_id = ntohl(*((uint32_t*) pnt)); |
209 | pnt += BGP_ADDPATH_ID_LEN; | |
210 | } | |
211 | ||
e5528198 LB |
212 | /* Fetch prefix length. */ |
213 | prefixlen = *pnt++; | |
214 | p.family = afi2family (packet->afi); | |
215 | psize = PSIZE (prefixlen); | |
216 | ||
48a5452b | 217 | if (prefixlen < VPN_PREFIXLEN_MIN_BYTES*8) |
1f9a9fff | 218 | { |
d6902373 | 219 | zlog_err ("%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)", |
48a5452b | 220 | peer->host, prefixlen); |
1f9a9fff PJ |
221 | return -1; |
222 | } | |
223 | ||
50905aa2 | 224 | /* sanity check against packet data */ |
48a5452b | 225 | if ((pnt + psize) > lim) |
50905aa2 | 226 | { |
d6902373 | 227 | zlog_err ("%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)", |
48a5452b | 228 | peer->host, |
50905aa2 DS |
229 | prefixlen, (uint)(lim-pnt)); |
230 | return -1; | |
231 | } | |
232 | ||
233 | /* sanity check against storage for the IP address portion */ | |
234 | if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t) sizeof(p.u)) | |
235 | { | |
d6902373 | 236 | zlog_err ("%s [Error] Update packet error / VPN (psize %d exceeds storage size %zu)", |
48a5452b | 237 | peer->host, |
50905aa2 DS |
238 | prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, sizeof(p.u)); |
239 | return -1; | |
240 | } | |
241 | ||
242 | /* Sanity check against max bitlen of the address family */ | |
243 | if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen (&p)) | |
244 | { | |
d6902373 | 245 | zlog_err ("%s [Error] Update packet error / VPN (psize %d exceeds family (%u) max byte len %u)", |
48a5452b | 246 | peer->host, |
50905aa2 DS |
247 | prefixlen - VPN_PREFIXLEN_MIN_BYTES*8, |
248 | p.family, prefix_blen (&p)); | |
249 | return -1; | |
50905aa2 DS |
250 | } |
251 | ||
718e3744 | 252 | /* Copyr label to prefix. */ |
50905aa2 | 253 | tagpnt = pnt; |
718e3744 | 254 | |
255 | /* Copy routing distinguisher to rd. */ | |
256 | memcpy (&prd.val, pnt + 3, 8); | |
257 | ||
258 | /* Decode RD type. */ | |
259 | type = decode_rd_type (pnt + 3); | |
260 | ||
fe770c88 LB |
261 | switch (type) |
262 | { | |
263 | case RD_TYPE_AS: | |
264 | decode_rd_as (pnt + 5, &rd_as); | |
265 | break; | |
266 | ||
267 | case RD_TYPE_AS4: | |
268 | decode_rd_as4 (pnt + 5, &rd_as); | |
269 | break; | |
270 | ||
271 | case RD_TYPE_IP: | |
272 | decode_rd_ip (pnt + 5, &rd_ip); | |
273 | break; | |
274 | ||
65efcfce LB |
275 | #if ENABLE_BGP_VNC |
276 | case RD_TYPE_VNC_ETH: | |
277 | break; | |
278 | #endif | |
279 | ||
93b73dfa LB |
280 | default: |
281 | zlog_err ("Unknown RD type %d", type); | |
282 | break; /* just report */ | |
283 | } | |
718e3744 | 284 | |
65efcfce | 285 | p.prefixlen = prefixlen - VPN_PREFIXLEN_MIN_BYTES*8;/* exclude label & RD */ |
50905aa2 DS |
286 | memcpy (&p.u.prefix, pnt + VPN_PREFIXLEN_MIN_BYTES, |
287 | psize - VPN_PREFIXLEN_MIN_BYTES); | |
718e3744 | 288 | |
718e3744 | 289 | if (attr) |
65efcfce | 290 | { |
28070ee3 | 291 | bgp_update (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, |
7ef5a232 | 292 | ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0, NULL); |
65efcfce | 293 | } |
718e3744 | 294 | else |
65efcfce | 295 | { |
28070ee3 | 296 | bgp_withdraw (peer, &p, addpath_id, attr, packet->afi, SAFI_MPLS_VPN, |
7ef5a232 | 297 | ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, NULL); |
28070ee3 | 298 | } |
718e3744 | 299 | } |
718e3744 | 300 | /* Packet length consistency check. */ |
301 | if (pnt != lim) | |
48a5452b | 302 | { |
d6902373 | 303 | zlog_err ("%s [Error] Update packet error / VPN (%zu data remaining after parsing)", |
48a5452b | 304 | peer->host, lim - pnt); |
48a5452b PJ |
305 | return -1; |
306 | } | |
307 | ||
718e3744 | 308 | return 0; |
50905aa2 | 309 | #undef VPN_PREFIXLEN_MIN_BYTES |
718e3744 | 310 | } |
311 | ||
312 | int | |
fd79ac91 | 313 | str2prefix_rd (const char *str, struct prefix_rd *prd) |
718e3744 | 314 | { |
289d2501 LB |
315 | int ret; /* ret of called functions */ |
316 | int lret; /* local ret, of this func */ | |
5228ad27 | 317 | char *p; |
318 | char *p2; | |
289d2501 LB |
319 | struct stream *s = NULL; |
320 | char *half = NULL; | |
718e3744 | 321 | struct in_addr addr; |
322 | ||
323 | s = stream_new (8); | |
324 | ||
325 | prd->family = AF_UNSPEC; | |
326 | prd->prefixlen = 64; | |
327 | ||
289d2501 | 328 | lret = 0; |
718e3744 | 329 | p = strchr (str, ':'); |
330 | if (! p) | |
289d2501 | 331 | goto out; |
718e3744 | 332 | |
333 | if (! all_digit (p + 1)) | |
289d2501 | 334 | goto out; |
718e3744 | 335 | |
336 | half = XMALLOC (MTYPE_TMP, (p - str) + 1); | |
337 | memcpy (half, str, (p - str)); | |
338 | half[p - str] = '\0'; | |
339 | ||
340 | p2 = strchr (str, '.'); | |
341 | ||
342 | if (! p2) | |
343 | { | |
cc5eb677 PG |
344 | unsigned long as_val; |
345 | ||
718e3744 | 346 | if (! all_digit (half)) |
289d2501 LB |
347 | goto out; |
348 | ||
cc5eb677 PG |
349 | as_val = atol(half); |
350 | if (as_val > 0xffff) | |
351 | { | |
352 | stream_putw (s, RD_TYPE_AS4); | |
bac21a7c | 353 | stream_putl (s, as_val); |
cc5eb677 PG |
354 | stream_putw (s, atol (p + 1)); |
355 | } | |
356 | else | |
357 | { | |
358 | stream_putw (s, RD_TYPE_AS); | |
bac21a7c | 359 | stream_putw (s, as_val); |
cc5eb677 PG |
360 | stream_putl (s, atol (p + 1)); |
361 | } | |
718e3744 | 362 | } |
363 | else | |
364 | { | |
365 | ret = inet_aton (half, &addr); | |
366 | if (! ret) | |
289d2501 LB |
367 | goto out; |
368 | ||
718e3744 | 369 | stream_putw (s, RD_TYPE_IP); |
370 | stream_put_in_addr (s, &addr); | |
371 | stream_putw (s, atol (p + 1)); | |
372 | } | |
373 | memcpy (prd->val, s->data, 8); | |
289d2501 LB |
374 | lret = 1; |
375 | ||
376 | out: | |
377 | if (s) | |
378 | stream_free (s); | |
379 | if (half) | |
380 | XFREE(MTYPE_TMP, half); | |
381 | return lret; | |
718e3744 | 382 | } |
383 | ||
384 | int | |
fd79ac91 | 385 | str2tag (const char *str, u_char *tag) |
718e3744 | 386 | { |
fd79ac91 | 387 | unsigned long l; |
388 | char *endptr; | |
389 | u_int32_t t; | |
718e3744 | 390 | |
664711c1 UW |
391 | if (*str == '-') |
392 | return 0; | |
fd79ac91 | 393 | |
664711c1 UW |
394 | errno = 0; |
395 | l = strtoul (str, &endptr, 10); | |
396 | ||
397 | if (*endptr != '\0' || errno || l > UINT32_MAX) | |
fd79ac91 | 398 | return 0; |
718e3744 | 399 | |
fd79ac91 | 400 | t = (u_int32_t) l; |
401 | ||
402 | tag[0] = (u_char)(t >> 12); | |
403 | tag[1] = (u_char)(t >> 4); | |
404 | tag[2] = (u_char)(t << 4); | |
718e3744 | 405 | |
406 | return 1; | |
407 | } | |
408 | ||
409 | char * | |
410 | prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size) | |
411 | { | |
412 | u_char *pnt; | |
413 | u_int16_t type; | |
414 | struct rd_as rd_as; | |
415 | struct rd_ip rd_ip; | |
416 | ||
417 | if (size < RD_ADDRSTRLEN) | |
418 | return NULL; | |
419 | ||
420 | pnt = prd->val; | |
421 | ||
422 | type = decode_rd_type (pnt); | |
423 | ||
424 | if (type == RD_TYPE_AS) | |
425 | { | |
426 | decode_rd_as (pnt + 2, &rd_as); | |
aea339f7 | 427 | snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); |
718e3744 | 428 | return buf; |
429 | } | |
fe770c88 LB |
430 | else if (type == RD_TYPE_AS4) |
431 | { | |
432 | decode_rd_as4 (pnt + 2, &rd_as); | |
433 | snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val); | |
434 | return buf; | |
435 | } | |
718e3744 | 436 | else if (type == RD_TYPE_IP) |
437 | { | |
438 | decode_rd_ip (pnt + 2, &rd_ip); | |
439 | snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); | |
440 | return buf; | |
441 | } | |
65efcfce LB |
442 | #if ENABLE_BGP_VNC |
443 | else if (type == RD_TYPE_VNC_ETH) | |
444 | { | |
445 | snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", | |
446 | *(pnt+1), /* LHI */ | |
447 | *(pnt+2), /* MAC[0] */ | |
448 | *(pnt+3), | |
449 | *(pnt+4), | |
450 | *(pnt+5), | |
451 | *(pnt+6), | |
452 | *(pnt+7)); | |
453 | ||
454 | return buf; | |
455 | } | |
456 | #endif | |
718e3744 | 457 | return NULL; |
458 | } | |
459 | ||
460 | /* For testing purpose, static route of MPLS-VPN. */ | |
461 | DEFUN (vpnv4_network, | |
462 | vpnv4_network_cmd, | |
463 | "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", | |
464 | "Specify a network to announce via BGP\n" | |
0c7b1b01 | 465 | "IPv4 prefix\n" |
718e3744 | 466 | "Specify Route Distinguisher\n" |
467 | "VPN Route Distinguisher\n" | |
468 | "BGP tag\n" | |
469 | "tag value\n") | |
470 | { | |
c500ae40 DW |
471 | int idx_ipv4_prefixlen = 1; |
472 | int idx_ext_community = 3; | |
473 | int idx_word = 5; | |
3da6fcd5 PG |
474 | return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, |
475 | argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL); | |
137446f9 LB |
476 | } |
477 | ||
478 | DEFUN (vpnv4_network_route_map, | |
479 | vpnv4_network_route_map_cmd, | |
480 | "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD route-map WORD", | |
481 | "Specify a network to announce via BGP\n" | |
0c7b1b01 | 482 | "IPv4 prefix\n" |
137446f9 LB |
483 | "Specify Route Distinguisher\n" |
484 | "VPN Route Distinguisher\n" | |
485 | "BGP tag\n" | |
486 | "tag value\n" | |
487 | "route map\n" | |
488 | "route map name\n") | |
489 | { | |
c500ae40 DW |
490 | int idx_ipv4_prefixlen = 1; |
491 | int idx_ext_community = 3; | |
492 | int idx_word = 5; | |
493 | int idx_word_2 = 7; | |
3da6fcd5 PG |
494 | return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, |
495 | argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); | |
718e3744 | 496 | } |
497 | ||
498 | /* For testing purpose, static route of MPLS-VPN. */ | |
499 | DEFUN (no_vpnv4_network, | |
500 | no_vpnv4_network_cmd, | |
501 | "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD", | |
502 | NO_STR | |
503 | "Specify a network to announce via BGP\n" | |
0c7b1b01 | 504 | "IPv4 prefix\n" |
718e3744 | 505 | "Specify Route Distinguisher\n" |
506 | "VPN Route Distinguisher\n" | |
507 | "BGP tag\n" | |
508 | "tag value\n") | |
509 | { | |
c500ae40 DW |
510 | int idx_ipv4_prefixlen = 2; |
511 | int idx_ext_community = 4; | |
512 | int idx_word = 6; | |
3da6fcd5 PG |
513 | return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv4_prefixlen]->arg, |
514 | argv[idx_ext_community]->arg, argv[idx_word]->arg, | |
515 | 0, NULL, NULL, NULL); | |
718e3744 | 516 | } |
517 | ||
c286be96 LX |
518 | DEFUN (vpnv6_network, |
519 | vpnv6_network_cmd, | |
52c439c1 | 520 | "network X:X::X:X/M rd ASN:nn_or_IP-address:nn tag WORD [route-map WORD]", |
c286be96 LX |
521 | "Specify a network to announce via BGP\n" |
522 | "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" | |
523 | "Specify Route Distinguisher\n" | |
524 | "VPN Route Distinguisher\n" | |
525 | "BGP tag\n" | |
11daee81 DS |
526 | "tag value\n" |
527 | "route map\n" | |
528 | "route map name\n") | |
c286be96 LX |
529 | { |
530 | int idx_ipv6_prefix = 1; | |
531 | int idx_ext_community = 3; | |
532 | int idx_word = 5; | |
533 | int idx_word_2 = 7; | |
313605cb | 534 | if (argc == 8) |
3da6fcd5 | 535 | return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, argv[idx_word_2]->arg, 0, NULL, NULL, NULL, NULL); |
52c439c1 | 536 | else |
3da6fcd5 | 537 | return bgp_static_set_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, NULL, 0, NULL, NULL, NULL, NULL); |
c286be96 LX |
538 | } |
539 | ||
540 | /* For testing purpose, static route of MPLS-VPN. */ | |
541 | DEFUN (no_vpnv6_network, | |
542 | no_vpnv6_network_cmd, | |
543 | "no network X:X::X:X/M rd ASN:nn_or_IP-address:nn tag WORD", | |
544 | NO_STR | |
545 | "Specify a network to announce via BGP\n" | |
546 | "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n" | |
547 | "Specify Route Distinguisher\n" | |
548 | "VPN Route Distinguisher\n" | |
549 | "BGP tag\n" | |
550 | "tag value\n") | |
551 | { | |
552 | int idx_ipv6_prefix = 2; | |
553 | int idx_ext_community = 4; | |
554 | int idx_word = 6; | |
3da6fcd5 | 555 | return bgp_static_unset_safi (SAFI_MPLS_VPN, vty, argv[idx_ipv6_prefix]->arg, argv[idx_ext_community]->arg, argv[idx_word]->arg, 0, NULL, NULL, NULL); |
c286be96 LX |
556 | } |
557 | ||
4e019978 | 558 | int |
e3e29b32 LB |
559 | bgp_show_mpls_vpn (struct vty *vty, afi_t afi, struct prefix_rd *prd, |
560 | enum bgp_show_type type, void *output_arg, int tags, u_char use_json) | |
718e3744 | 561 | { |
562 | struct bgp *bgp; | |
563 | struct bgp_table *table; | |
564 | struct bgp_node *rn; | |
565 | struct bgp_node *rm; | |
566 | struct bgp_info *ri; | |
567 | int rd_header; | |
568 | int header = 1; | |
569 | char v4_header[] = " Network Next Hop Metric LocPrf Weight Path%s"; | |
570 | char v4_header_tag[] = " Network Next Hop In tag/Out tag%s"; | |
e3e29b32 LB |
571 | unsigned long output_count = 0; |
572 | unsigned long total_count = 0; | |
856ca177 MS |
573 | json_object *json = NULL; |
574 | json_object *json_mroute = NULL; | |
575 | json_object *json_nroute = NULL; | |
576 | json_object *json_array = NULL; | |
577 | json_object *json_scode = NULL; | |
578 | json_object *json_ocode = NULL; | |
718e3744 | 579 | |
580 | bgp = bgp_get_default (); | |
581 | if (bgp == NULL) | |
582 | { | |
856ca177 MS |
583 | if (!use_json) |
584 | vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE); | |
718e3744 | 585 | return CMD_WARNING; |
586 | } | |
856ca177 MS |
587 | |
588 | if (use_json) | |
589 | { | |
590 | json_scode = json_object_new_object(); | |
591 | json_ocode = json_object_new_object(); | |
592 | json = json_object_new_object(); | |
593 | json_mroute = json_object_new_object(); | |
594 | json_nroute = json_object_new_object(); | |
595 | ||
596 | json_object_string_add(json_scode, "suppressed", "s"); | |
597 | json_object_string_add(json_scode, "damped", "d"); | |
598 | json_object_string_add(json_scode, "history", "h"); | |
599 | json_object_string_add(json_scode, "valid", "*"); | |
600 | json_object_string_add(json_scode, "best", ">"); | |
601 | json_object_string_add(json_scode, "internal", "i"); | |
602 | ||
603 | json_object_string_add(json_ocode, "igp", "i"); | |
604 | json_object_string_add(json_ocode, "egp", "e"); | |
605 | json_object_string_add(json_ocode, "incomplete", "?"); | |
606 | } | |
607 | ||
945c8fe9 LB |
608 | if ((afi != AFI_IP) && (afi != AFI_IP6)) |
609 | { | |
610 | vty_out (vty, "Afi %d not supported%s", afi, VTY_NEWLINE); | |
611 | return CMD_WARNING; | |
612 | } | |
613 | ||
614 | for (rn = bgp_table_top (bgp->rib[afi][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn)) | |
718e3744 | 615 | { |
616 | if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0) | |
617 | continue; | |
618 | ||
619 | if ((table = rn->info) != NULL) | |
620 | { | |
621 | rd_header = 1; | |
622 | ||
623 | for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm)) | |
856ca177 | 624 | { |
e3e29b32 | 625 | total_count++; |
856ca177 MS |
626 | if (use_json) |
627 | json_array = json_object_new_array(); | |
628 | else | |
629 | json_array = NULL; | |
630 | ||
631 | for (ri = rm->info; ri; ri = ri->next) | |
632 | { | |
633 | if (type == bgp_show_type_neighbor) | |
634 | { | |
635 | union sockunion *su = output_arg; | |
636 | ||
637 | if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su)) | |
638 | continue; | |
639 | } | |
640 | if (header) | |
641 | { | |
642 | if (use_json) | |
643 | { | |
644 | if (!tags) | |
645 | { | |
646 | json_object_int_add(json, "bgpTableVersion", 0); | |
647 | json_object_string_add(json, "bgpLocalRouterId", inet_ntoa (bgp->router_id)); | |
648 | json_object_object_add(json, "bgpStatusCodes", json_scode); | |
649 | json_object_object_add(json, "bgpOriginCodes", json_ocode); | |
650 | } | |
651 | } | |
652 | else | |
653 | { | |
654 | if (tags) | |
655 | vty_out (vty, v4_header_tag, VTY_NEWLINE); | |
656 | else | |
657 | { | |
658 | vty_out (vty, "BGP table version is 0, local router ID is %s%s", | |
659 | inet_ntoa (bgp->router_id), VTY_NEWLINE); | |
660 | vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s", | |
661 | VTY_NEWLINE); | |
662 | vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s", | |
663 | VTY_NEWLINE, VTY_NEWLINE); | |
664 | vty_out (vty, v4_header, VTY_NEWLINE); | |
665 | } | |
666 | } | |
667 | header = 0; | |
668 | } | |
669 | ||
670 | if (rd_header) | |
671 | { | |
672 | u_int16_t type; | |
673 | struct rd_as rd_as; | |
ea8b7c71 | 674 | struct rd_ip rd_ip = {0}; |
65efcfce | 675 | #if ENABLE_BGP_VNC |
28070ee3 | 676 | struct rd_vnc_eth rd_vnc_eth = {0}; |
65efcfce | 677 | #endif |
856ca177 MS |
678 | u_char *pnt; |
679 | ||
680 | pnt = rn->p.u.val; | |
681 | ||
682 | /* Decode RD type. */ | |
683 | type = decode_rd_type (pnt); | |
684 | /* Decode RD value. */ | |
685 | if (type == RD_TYPE_AS) | |
686 | decode_rd_as (pnt + 2, &rd_as); | |
fe770c88 LB |
687 | else if (type == RD_TYPE_AS4) |
688 | decode_rd_as4 (pnt + 2, &rd_as); | |
856ca177 MS |
689 | else if (type == RD_TYPE_IP) |
690 | decode_rd_ip (pnt + 2, &rd_ip); | |
65efcfce LB |
691 | #if ENABLE_BGP_VNC |
692 | else if (type == RD_TYPE_VNC_ETH) | |
693 | decode_rd_vnc_eth (pnt, &rd_vnc_eth); | |
694 | #endif | |
856ca177 MS |
695 | |
696 | if (use_json) | |
697 | { | |
698 | char buffer[BUFSIZ]; | |
fe770c88 | 699 | if (type == RD_TYPE_AS || type == RD_TYPE_AS4) |
856ca177 MS |
700 | sprintf (buffer, "%u:%d", rd_as.as, rd_as.val); |
701 | else if (type == RD_TYPE_IP) | |
702 | sprintf (buffer, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); | |
703 | json_object_string_add(json_nroute, "routeDistinguisher", buffer); | |
704 | } | |
705 | else | |
706 | { | |
707 | vty_out (vty, "Route Distinguisher: "); | |
708 | ||
fe770c88 | 709 | if (type == RD_TYPE_AS || type == RD_TYPE_AS4) |
856ca177 MS |
710 | vty_out (vty, "%u:%d", rd_as.as, rd_as.val); |
711 | else if (type == RD_TYPE_IP) | |
712 | vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val); | |
65efcfce LB |
713 | #if ENABLE_BGP_VNC |
714 | else if (type == RD_TYPE_VNC_ETH) | |
715 | vty_out (vty, "%u:%02x:%02x:%02x:%02x:%02x:%02x", | |
716 | rd_vnc_eth.local_nve_id, | |
717 | rd_vnc_eth.macaddr.octet[0], | |
718 | rd_vnc_eth.macaddr.octet[1], | |
719 | rd_vnc_eth.macaddr.octet[2], | |
720 | rd_vnc_eth.macaddr.octet[3], | |
721 | rd_vnc_eth.macaddr.octet[4], | |
722 | rd_vnc_eth.macaddr.octet[5]); | |
723 | #endif | |
856ca177 MS |
724 | vty_out (vty, "%s", VTY_NEWLINE); |
725 | } | |
726 | rd_header = 0; | |
727 | } | |
728 | if (tags) | |
729 | route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN, json_array); | |
730 | else | |
731 | route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN, json_array); | |
e3e29b32 | 732 | output_count++; |
856ca177 MS |
733 | } |
734 | ||
735 | if (use_json) | |
736 | { | |
737 | struct prefix *p; | |
738 | char buf_a[BUFSIZ]; | |
739 | char buf_b[BUFSIZ]; | |
740 | p = &rm->p; | |
741 | sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen); | |
742 | json_object_object_add(json_mroute, buf_a, json_array); | |
743 | } | |
744 | } | |
745 | ||
746 | if (use_json) | |
747 | { | |
748 | struct prefix *p; | |
749 | char buf_a[BUFSIZ]; | |
750 | char buf_b[BUFSIZ]; | |
751 | p = &rn->p; | |
752 | sprintf(buf_a, "%s/%d", inet_ntop (p->family, &p->u.prefix, buf_b, BUFSIZ), p->prefixlen); | |
753 | json_object_object_add(json_nroute, buf_a, json_mroute); | |
754 | } | |
718e3744 | 755 | } |
756 | } | |
856ca177 MS |
757 | |
758 | if (use_json) | |
759 | { | |
760 | json_object_object_add(json, "routes", json_nroute); | |
2aac5767 | 761 | vty_out (vty, "%s%s", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY), VTY_NEWLINE); |
856ca177 MS |
762 | json_object_free(json); |
763 | } | |
e3e29b32 LB |
764 | else |
765 | { | |
766 | if (output_count == 0) | |
767 | vty_out (vty, "No prefixes displayed, %ld exist%s", total_count, VTY_NEWLINE); | |
768 | else | |
5c3cc3ae | 769 | vty_out (vty, "%sDisplayed %ld routes and %ld total paths%s", |
e3e29b32 LB |
770 | VTY_NEWLINE, output_count, total_count, VTY_NEWLINE); |
771 | } | |
772 | ||
718e3744 | 773 | return CMD_SUCCESS; |
774 | } | |
775 | ||
4f280b15 LB |
776 | DEFUN (show_bgp_ip_vpn_all_rd, |
777 | show_bgp_ip_vpn_all_rd_cmd, | |
b99615f9 | 778 | "show bgp "BGP_AFI_CMD_STR" vpn all [rd ASN:nn_or_IP-address:nn] [json]", |
e3e29b32 | 779 | SHOW_STR |
716b2d8a | 780 | IP_STR |
e3e29b32 | 781 | BGP_STR |
05e588f4 | 782 | BGP_VPNVX_HELP_STR |
e3e29b32 LB |
783 | "Display VPN NLRI specific information\n" |
784 | "Display information for a route distinguisher\n" | |
785 | "VPN Route Distinguisher\n" | |
786 | JSON_STR) | |
787 | { | |
b99615f9 | 788 | int idx_rd = 5; |
e3e29b32 LB |
789 | int ret; |
790 | struct prefix_rd prd; | |
3f227172 PG |
791 | afi_t afi; |
792 | int idx = 0; | |
e3e29b32 | 793 | |
3f227172 | 794 | if (argv_find_and_parse_afi (argv, argc, &idx, &afi)) |
e3e29b32 | 795 | { |
b99615f9 | 796 | if (argc >= 7 && argv[idx_rd]->arg) |
3f227172 | 797 | { |
b99615f9 | 798 | ret = str2prefix_rd (argv[idx_rd]->arg, &prd); |
3f227172 PG |
799 | if (! ret) |
800 | { | |
801 | vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); | |
802 | return CMD_WARNING; | |
803 | } | |
804 | return bgp_show_mpls_vpn (vty, afi, &prd, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); | |
805 | } | |
806 | else | |
807 | { | |
808 | return bgp_show_mpls_vpn (vty, afi, NULL, bgp_show_type_normal, NULL, 0, use_json (argc, argv)); | |
809 | } | |
e3e29b32 | 810 | } |
3f227172 | 811 | return CMD_SUCCESS; |
718e3744 | 812 | } |
813 | ||
3f227172 PG |
814 | DEFUN (show_ip_bgp_vpn_rd, |
815 | show_ip_bgp_vpn_rd_cmd, | |
4f280b15 | 816 | "show [ip] bgp "BGP_AFI_CMD_STR" vpn rd ASN:nn_or_IP-address:nn", |
718e3744 | 817 | SHOW_STR |
818 | IP_STR | |
819 | BGP_STR | |
4f280b15 | 820 | BGP_AFI_HELP_STR |
3517059b | 821 | "Address Family modifier\n" |
718e3744 | 822 | "Display information for a route distinguisher\n" |
823 | "VPN Route Distinguisher\n") | |
824 | { | |
4f280b15 | 825 | int idx_ext_community = argc-1; |
718e3744 | 826 | int ret; |
827 | struct prefix_rd prd; | |
3f227172 PG |
828 | afi_t afi; |
829 | int idx = 0; | |
718e3744 | 830 | |
3f227172 | 831 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) |
718e3744 | 832 | { |
3f227172 PG |
833 | ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); |
834 | if (! ret) | |
835 | { | |
836 | vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); | |
837 | return CMD_WARNING; | |
838 | } | |
839 | return bgp_show_mpls_vpn (vty, afi, &prd, bgp_show_type_normal, NULL, 0, 0); | |
718e3744 | 840 | } |
3f227172 PG |
841 | return CMD_SUCCESS; |
842 | } | |
718e3744 | 843 | |
4f280b15 LB |
844 | #ifdef KEEP_OLD_VPN_COMMANDS |
845 | DEFUN (show_ip_bgp_vpn_all, | |
846 | show_ip_bgp_vpn_all_cmd, | |
847 | "show [ip] bgp <vpnv4|vpnv6>", | |
848 | SHOW_STR | |
849 | IP_STR | |
850 | BGP_STR | |
851 | BGP_VPNVX_HELP_STR) | |
852 | { | |
853 | afi_t afi; | |
854 | int idx = 0; | |
855 | ||
856 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) | |
857 | return bgp_show_mpls_vpn (vty, afi, NULL, bgp_show_type_normal, NULL, 0, 0); | |
858 | return CMD_SUCCESS; | |
859 | } | |
860 | ||
3f227172 PG |
861 | DEFUN (show_ip_bgp_vpn_all_tags, |
862 | show_ip_bgp_vpn_all_tags_cmd, | |
863 | "show [ip] bgp <vpnv4|vpnv6> all tags", | |
718e3744 | 864 | SHOW_STR |
865 | IP_STR | |
866 | BGP_STR | |
3f227172 PG |
867 | BGP_VPNVX_HELP_STR |
868 | "Display information about all VPNv4/VPNV6 NLRIs\n" | |
718e3744 | 869 | "Display BGP tags for prefixes\n") |
870 | { | |
3f227172 PG |
871 | afi_t afi; |
872 | int idx = 0; | |
873 | ||
874 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) | |
875 | return bgp_show_mpls_vpn (vty, afi, NULL, bgp_show_type_normal, NULL, 1, 0); | |
876 | return CMD_SUCCESS; | |
718e3744 | 877 | } |
878 | ||
3f227172 PG |
879 | DEFUN (show_ip_bgp_vpn_rd_tags, |
880 | show_ip_bgp_vpn_rd_tags_cmd, | |
881 | "show [ip] bgp <vpnv4|vpnv6> rd ASN:nn_or_IP-address:nn tags", | |
718e3744 | 882 | SHOW_STR |
883 | IP_STR | |
884 | BGP_STR | |
3f227172 | 885 | BGP_VPNVX_HELP_STR |
718e3744 | 886 | "Display information for a route distinguisher\n" |
887 | "VPN Route Distinguisher\n" | |
888 | "Display BGP tags for prefixes\n") | |
889 | { | |
c500ae40 | 890 | int idx_ext_community = 5; |
718e3744 | 891 | int ret; |
892 | struct prefix_rd prd; | |
3f227172 PG |
893 | afi_t afi; |
894 | int idx = 0; | |
718e3744 | 895 | |
3f227172 | 896 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) |
718e3744 | 897 | { |
3f227172 PG |
898 | ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); |
899 | if (! ret) | |
900 | { | |
901 | vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); | |
902 | return CMD_WARNING; | |
903 | } | |
904 | return bgp_show_mpls_vpn (vty, afi, &prd, bgp_show_type_normal, NULL, 1, 0); | |
718e3744 | 905 | } |
3f227172 | 906 | return CMD_SUCCESS; |
718e3744 | 907 | } |
908 | ||
3f227172 PG |
909 | DEFUN (show_ip_bgp_vpn_all_neighbor_routes, |
910 | show_ip_bgp_vpn_all_neighbor_routes_cmd, | |
911 | "show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D routes [json]", | |
718e3744 | 912 | SHOW_STR |
913 | IP_STR | |
914 | BGP_STR | |
3f227172 PG |
915 | BGP_VPNVX_HELP_STR |
916 | "Display information about all VPNv4/VPNv6 NLRIs\n" | |
718e3744 | 917 | "Detailed information on TCP and BGP neighbor connections\n" |
918 | "Neighbor to display information about\n" | |
856ca177 | 919 | "Display routes learned from neighbor\n" |
9973d184 | 920 | JSON_STR) |
718e3744 | 921 | { |
c500ae40 | 922 | int idx_ipv4 = 6; |
c63b83fe | 923 | union sockunion su; |
718e3744 | 924 | struct peer *peer; |
c63b83fe | 925 | int ret; |
db7c8528 | 926 | u_char uj = use_json(argc, argv); |
3f227172 PG |
927 | afi_t afi; |
928 | int idx = 0; | |
c63b83fe | 929 | |
3f227172 | 930 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) |
718e3744 | 931 | { |
3f227172 PG |
932 | ret = str2sockunion (argv[idx_ipv4]->arg, &su); |
933 | if (ret < 0) | |
856ca177 | 934 | { |
3f227172 PG |
935 | if (uj) |
936 | { | |
937 | json_object *json_no = NULL; | |
938 | json_no = json_object_new_object(); | |
939 | json_object_string_add(json_no, "warning", "Malformed address"); | |
940 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
941 | json_object_free(json_no); | |
942 | } | |
943 | else | |
944 | vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); | |
945 | return CMD_WARNING; | |
856ca177 | 946 | } |
718e3744 | 947 | |
3f227172 PG |
948 | peer = peer_lookup (NULL, &su); |
949 | if (! peer || ! peer->afc[afi][SAFI_MPLS_VPN]) | |
856ca177 | 950 | { |
3f227172 PG |
951 | if (uj) |
952 | { | |
953 | json_object *json_no = NULL; | |
954 | json_no = json_object_new_object(); | |
955 | json_object_string_add(json_no, "warning", "No such neighbor or address family"); | |
956 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
957 | json_object_free(json_no); | |
958 | } | |
959 | else | |
960 | vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); | |
961 | return CMD_WARNING; | |
856ca177 | 962 | } |
718e3744 | 963 | |
3f227172 PG |
964 | return bgp_show_mpls_vpn (vty, afi, NULL, bgp_show_type_neighbor, &su, 0, uj); |
965 | } | |
966 | return CMD_SUCCESS; | |
718e3744 | 967 | } |
968 | ||
3f227172 PG |
969 | DEFUN (show_ip_bgp_vpn_rd_neighbor_routes, |
970 | show_ip_bgp_vpn_rd_neighbor_routes_cmd, | |
971 | "show [ip] bgp <vpnv4|vpnv6> rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes [json]", | |
718e3744 | 972 | SHOW_STR |
973 | IP_STR | |
974 | BGP_STR | |
3f227172 | 975 | BGP_VPNVX_HELP_STR |
718e3744 | 976 | "Display information for a route distinguisher\n" |
977 | "VPN Route Distinguisher\n" | |
978 | "Detailed information on TCP and BGP neighbor connections\n" | |
979 | "Neighbor to display information about\n" | |
856ca177 | 980 | "Display routes learned from neighbor\n" |
9973d184 | 981 | JSON_STR) |
718e3744 | 982 | { |
c500ae40 DW |
983 | int idx_ext_community = 5; |
984 | int idx_ipv4 = 7; | |
718e3744 | 985 | int ret; |
c63b83fe | 986 | union sockunion su; |
718e3744 | 987 | struct peer *peer; |
988 | struct prefix_rd prd; | |
db7c8528 | 989 | u_char uj = use_json(argc, argv); |
3f227172 PG |
990 | afi_t afi; |
991 | int idx = 0; | |
718e3744 | 992 | |
3f227172 | 993 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) |
718e3744 | 994 | { |
3f227172 PG |
995 | ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); |
996 | if (! ret) | |
856ca177 | 997 | { |
3f227172 PG |
998 | if (uj) |
999 | { | |
1000 | json_object *json_no = NULL; | |
1001 | json_no = json_object_new_object(); | |
1002 | json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); | |
1003 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1004 | json_object_free(json_no); | |
1005 | } | |
1006 | else | |
1007 | vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); | |
1008 | return CMD_WARNING; | |
856ca177 | 1009 | } |
718e3744 | 1010 | |
3f227172 PG |
1011 | ret = str2sockunion (argv[idx_ipv4]->arg, &su); |
1012 | if (ret < 0) | |
856ca177 | 1013 | { |
3f227172 PG |
1014 | if (uj) |
1015 | { | |
1016 | json_object *json_no = NULL; | |
1017 | json_no = json_object_new_object(); | |
1018 | json_object_string_add(json_no, "warning", "Malformed address"); | |
1019 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1020 | json_object_free(json_no); | |
1021 | } | |
1022 | else | |
1023 | vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); | |
1024 | return CMD_WARNING; | |
856ca177 | 1025 | } |
718e3744 | 1026 | |
3f227172 PG |
1027 | peer = peer_lookup (NULL, &su); |
1028 | if (! peer || ! peer->afc[afi][SAFI_MPLS_VPN]) | |
856ca177 | 1029 | { |
3f227172 PG |
1030 | if (uj) |
1031 | { | |
1032 | json_object *json_no = NULL; | |
1033 | json_no = json_object_new_object(); | |
1034 | json_object_string_add(json_no, "warning", "No such neighbor or address family"); | |
1035 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1036 | json_object_free(json_no); | |
1037 | } | |
1038 | else | |
1039 | vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); | |
1040 | return CMD_WARNING; | |
856ca177 | 1041 | } |
718e3744 | 1042 | |
3f227172 PG |
1043 | return bgp_show_mpls_vpn (vty, afi, &prd, bgp_show_type_neighbor, &su, 0, uj); |
1044 | } | |
1045 | return CMD_SUCCESS; | |
718e3744 | 1046 | } |
1047 | ||
3f227172 PG |
1048 | DEFUN (show_ip_bgp_vpn_all_neighbor_advertised_routes, |
1049 | show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd, | |
1050 | "show [ip] bgp <vpnv4|vpnv6> all neighbors A.B.C.D advertised-routes [json]", | |
718e3744 | 1051 | SHOW_STR |
1052 | IP_STR | |
1053 | BGP_STR | |
3f227172 PG |
1054 | BGP_VPNVX_HELP_STR |
1055 | "Display information about all VPNv4/VPNv6 NLRIs\n" | |
718e3744 | 1056 | "Detailed information on TCP and BGP neighbor connections\n" |
1057 | "Neighbor to display information about\n" | |
856ca177 | 1058 | "Display the routes advertised to a BGP neighbor\n" |
9973d184 | 1059 | JSON_STR) |
718e3744 | 1060 | { |
c500ae40 | 1061 | int idx_ipv4 = 6; |
718e3744 | 1062 | int ret; |
1063 | struct peer *peer; | |
1064 | union sockunion su; | |
db7c8528 | 1065 | u_char uj = use_json(argc, argv); |
3f227172 PG |
1066 | afi_t afi; |
1067 | int idx = 0; | |
718e3744 | 1068 | |
3f227172 | 1069 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) |
718e3744 | 1070 | { |
3f227172 PG |
1071 | ret = str2sockunion (argv[idx_ipv4]->arg, &su); |
1072 | if (ret < 0) | |
856ca177 | 1073 | { |
3f227172 PG |
1074 | if (uj) |
1075 | { | |
1076 | json_object *json_no = NULL; | |
1077 | json_no = json_object_new_object(); | |
1078 | json_object_string_add(json_no, "warning", "Malformed address"); | |
1079 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1080 | json_object_free(json_no); | |
1081 | } | |
1082 | else | |
1083 | vty_out (vty, "Malformed address: %s%s", argv[idx_ipv4]->arg, VTY_NEWLINE); | |
1084 | return CMD_WARNING; | |
856ca177 | 1085 | } |
3f227172 PG |
1086 | peer = peer_lookup (NULL, &su); |
1087 | if (! peer || ! peer->afc[afi][SAFI_MPLS_VPN]) | |
856ca177 | 1088 | { |
3f227172 PG |
1089 | if (uj) |
1090 | { | |
1091 | json_object *json_no = NULL; | |
1092 | json_no = json_object_new_object(); | |
1093 | json_object_string_add(json_no, "warning", "No such neighbor or address family"); | |
1094 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1095 | json_object_free(json_no); | |
1096 | } | |
1097 | else | |
1098 | vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); | |
1099 | return CMD_WARNING; | |
856ca177 | 1100 | } |
784d3a42 | 1101 | return show_adj_route_vpn (vty, peer, NULL, AFI_IP, SAFI_MPLS_VPN, uj); |
3f227172 PG |
1102 | } |
1103 | return CMD_SUCCESS; | |
718e3744 | 1104 | } |
1105 | ||
3f227172 PG |
1106 | DEFUN (show_ip_bgp_vpn_rd_neighbor_advertised_routes, |
1107 | show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd, | |
1108 | "show [ip] bgp <vpnv4|vpnv6> rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes [json]", | |
718e3744 | 1109 | SHOW_STR |
1110 | IP_STR | |
1111 | BGP_STR | |
3f227172 | 1112 | BGP_VPNVX_HELP_STR |
718e3744 | 1113 | "Display information for a route distinguisher\n" |
1114 | "VPN Route Distinguisher\n" | |
1115 | "Detailed information on TCP and BGP neighbor connections\n" | |
1116 | "Neighbor to display information about\n" | |
856ca177 | 1117 | "Display the routes advertised to a BGP neighbor\n" |
9973d184 | 1118 | JSON_STR) |
718e3744 | 1119 | { |
c500ae40 DW |
1120 | int idx_ext_community = 5; |
1121 | int idx_ipv4 = 7; | |
718e3744 | 1122 | int ret; |
1123 | struct peer *peer; | |
1124 | struct prefix_rd prd; | |
1125 | union sockunion su; | |
db7c8528 | 1126 | u_char uj = use_json(argc, argv); |
3f227172 PG |
1127 | afi_t afi; |
1128 | int idx = 0; | |
718e3744 | 1129 | |
3f227172 | 1130 | if (argv_find_and_parse_vpnvx (argv, argc, &idx, &afi)) |
718e3744 | 1131 | { |
3f227172 PG |
1132 | ret = str2sockunion (argv[idx_ipv4]->arg, &su); |
1133 | if (ret < 0) | |
856ca177 | 1134 | { |
3f227172 PG |
1135 | if (uj) |
1136 | { | |
1137 | json_object *json_no = NULL; | |
1138 | json_no = json_object_new_object(); | |
1139 | json_object_string_add(json_no, "warning", "Malformed address"); | |
1140 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1141 | json_object_free(json_no); | |
1142 | } | |
1143 | else | |
1144 | vty_out (vty, "Malformed address: %s%s", argv[idx_ext_community]->arg, VTY_NEWLINE); | |
1145 | return CMD_WARNING; | |
856ca177 | 1146 | } |
3f227172 PG |
1147 | peer = peer_lookup (NULL, &su); |
1148 | if (! peer || ! peer->afc[afi][SAFI_MPLS_VPN]) | |
856ca177 | 1149 | { |
3f227172 PG |
1150 | if (uj) |
1151 | { | |
1152 | json_object *json_no = NULL; | |
1153 | json_no = json_object_new_object(); | |
1154 | json_object_string_add(json_no, "warning", "No such neighbor or address family"); | |
1155 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1156 | json_object_free(json_no); | |
1157 | } | |
1158 | else | |
1159 | vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE); | |
1160 | return CMD_WARNING; | |
856ca177 | 1161 | } |
718e3744 | 1162 | |
3f227172 PG |
1163 | ret = str2prefix_rd (argv[idx_ext_community]->arg, &prd); |
1164 | if (! ret) | |
856ca177 | 1165 | { |
3f227172 PG |
1166 | if (uj) |
1167 | { | |
1168 | json_object *json_no = NULL; | |
1169 | json_no = json_object_new_object(); | |
1170 | json_object_string_add(json_no, "warning", "Malformed Route Distinguisher"); | |
1171 | vty_out (vty, "%s%s", json_object_to_json_string(json_no), VTY_NEWLINE); | |
1172 | json_object_free(json_no); | |
1173 | } | |
1174 | else | |
1175 | vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE); | |
1176 | return CMD_WARNING; | |
856ca177 | 1177 | } |
718e3744 | 1178 | |
784d3a42 | 1179 | return show_adj_route_vpn (vty, peer, &prd, AFI_IP, SAFI_MPLS_VPN, uj); |
3f227172 PG |
1180 | } |
1181 | return CMD_SUCCESS; | |
718e3744 | 1182 | } |
d6902373 | 1183 | #endif /* KEEP_OLD_VPN_COMMANDS */ |
718e3744 | 1184 | |
1185 | void | |
94f2b392 | 1186 | bgp_mplsvpn_init (void) |
718e3744 | 1187 | { |
1188 | install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd); | |
137446f9 | 1189 | install_element (BGP_VPNV4_NODE, &vpnv4_network_route_map_cmd); |
718e3744 | 1190 | install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd); |
1191 | ||
c286be96 | 1192 | install_element (BGP_VPNV6_NODE, &vpnv6_network_cmd); |
c286be96 LX |
1193 | install_element (BGP_VPNV6_NODE, &no_vpnv6_network_cmd); |
1194 | ||
4f280b15 LB |
1195 | install_element (VIEW_NODE, &show_bgp_ip_vpn_all_rd_cmd); |
1196 | install_element (VIEW_NODE, &show_ip_bgp_vpn_rd_cmd); | |
d6902373 | 1197 | #ifdef KEEP_OLD_VPN_COMMANDS |
3f227172 PG |
1198 | install_element (VIEW_NODE, &show_ip_bgp_vpn_all_cmd); |
1199 | install_element (VIEW_NODE, &show_ip_bgp_vpn_rd_cmd); | |
1200 | install_element (VIEW_NODE, &show_ip_bgp_vpn_all_tags_cmd); | |
1201 | install_element (VIEW_NODE, &show_ip_bgp_vpn_rd_tags_cmd); | |
1202 | install_element (VIEW_NODE, &show_ip_bgp_vpn_all_neighbor_routes_cmd); | |
1203 | install_element (VIEW_NODE, &show_ip_bgp_vpn_rd_neighbor_routes_cmd); | |
1204 | install_element (VIEW_NODE, &show_ip_bgp_vpn_all_neighbor_advertised_routes_cmd); | |
1205 | install_element (VIEW_NODE, &show_ip_bgp_vpn_rd_neighbor_advertised_routes_cmd); | |
d6902373 | 1206 | #endif /* KEEP_OLD_VPN_COMMANDS */ |
718e3744 | 1207 | } |