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