1/* MPLS-VPN
2   Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org>
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING.  If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-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"
28
29#include "bgpd/bgpd.h"
30#include "bgpd/bgp_table.h"
31#include "bgpd/bgp_route.h"
32#include "bgpd/bgp_attr.h"
33#include "bgpd/bgp_mplsvpn.h"
34
35static u_int16_t
36decode_rd_type (u_char *pnt)
37{
38  u_int16_t v;
39
40  v = ((u_int16_t) *pnt++ << 8);
41  v |= (u_int16_t) *pnt;
42  return v;
43}
44
45u_int32_t
46decode_label (u_char *pnt)
47{
48  u_int32_t l;
49
50  l = ((u_int32_t) *pnt++ << 12);
51  l |= (u_int32_t) *pnt++ << 4;
52  l |= (u_int32_t) ((*pnt & 0xf0) >> 4);
53  return l;
54}
55
56static void
57decode_rd_as (u_char *pnt, struct rd_as *rd_as)
58{
59  rd_as->as = (u_int16_t) *pnt++ << 8;
60  rd_as->as |= (u_int16_t) *pnt++;
61
62  rd_as->val = ((u_int32_t) *pnt++ << 24);
63  rd_as->val |= ((u_int32_t) *pnt++ << 16);
64  rd_as->val |= ((u_int32_t) *pnt++ << 8);
65  rd_as->val |= (u_int32_t) *pnt;
66}
67
68static void
69decode_rd_ip (u_char *pnt, struct rd_ip *rd_ip)
70{
71  memcpy (&rd_ip->ip, pnt, 4);
72  pnt += 4;
73
74  rd_ip->val = ((u_int16_t) *pnt++ << 8);
75  rd_ip->val |= (u_int16_t) *pnt;
76}
77
78int
79bgp_nlri_parse_vpnv4 (struct peer *peer, struct attr *attr,
80		      struct bgp_nlri *packet)
81{
82  u_char *pnt;
83  u_char *lim;
84  struct prefix p;
85  int psize;
86  int prefixlen;
87  u_int16_t type;
88  struct rd_as rd_as;
89  struct rd_ip rd_ip;
90  struct prefix_rd prd;
91  u_char *tagpnt;
92
93  /* Check peer status. */
94  if (peer->status != Established)
95    return 0;
96
97  /* Make prefix_rd */
98  prd.family = AF_UNSPEC;
99  prd.prefixlen = 64;
100
101  pnt = packet->nlri;
102  lim = pnt + packet->length;
103
104  for (; pnt < lim; pnt += psize)
105    {
106      /* Clear prefix structure. */
107      memset (&p, 0, sizeof (struct prefix));
108
109      /* Fetch prefix length. */
110      prefixlen = *pnt++;
111      p.family = AF_INET;
112      psize = PSIZE (prefixlen);
113
114      if (prefixlen < 88)
115	{
116	  zlog_err ("prefix length is less than 88: %d", prefixlen);
117	  return -1;
118	}
119
120      /* XXX: Not doing anything with the label */
121      decode_label (pnt);
122
123      /* Copyr label to prefix. */
124      tagpnt = pnt;;
125
126      /* Copy routing distinguisher to rd. */
127      memcpy (&prd.val, pnt + 3, 8);
128
129      /* Decode RD type. */
130      type = decode_rd_type (pnt + 3);
131
132      /* Decode RD value. */
133      if (type == RD_TYPE_AS)
134	decode_rd_as (pnt + 5, &rd_as);
135      else if (type == RD_TYPE_IP)
136	decode_rd_ip (pnt + 5, &rd_ip);
137      else
138	{
139	  zlog_err ("Invalid RD type %d", type);
140	  return -1;
141	}
142
143      p.prefixlen = prefixlen - 88;
144      memcpy (&p.u.prefix, pnt + 11, psize - 11);
145
146#if 0
147      if (type == RD_TYPE_AS)
148	zlog_info ("prefix %ld:%ld:%ld:%s/%d", label, rd_as.as, rd_as.val,
149		   inet_ntoa (p.u.prefix4), p.prefixlen);
150      else if (type == RD_TYPE_IP)
151	zlog_info ("prefix %ld:%s:%ld:%s/%d", label, inet_ntoa (rd_ip.ip),
152		   rd_ip.val, inet_ntoa (p.u.prefix4), p.prefixlen);
153#endif /* 0 */
154
155      if (pnt + psize > lim)
156	return -1;
157
158      if (attr)
159	bgp_update (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
160		    ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt, 0);
161      else
162	bgp_withdraw (peer, &p, attr, AFI_IP, SAFI_MPLS_VPN,
163		      ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, &prd, tagpnt);
164    }
165
166  /* Packet length consistency check. */
167  if (pnt != lim)
168    return -1;
169
170  return 0;
171}
172
173int
174str2prefix_rd (const char *str, struct prefix_rd *prd)
175{
176  int ret;
177  char *p;
178  char *p2;
179  struct stream *s;
180  char *half;
181  struct in_addr addr;
182
183  s = stream_new (8);
184
185  prd->family = AF_UNSPEC;
186  prd->prefixlen = 64;
187
188  p = strchr (str, ':');
189  if (! p)
190    return 0;
191
192  if (! all_digit (p + 1))
193    return 0;
194
195  half = XMALLOC (MTYPE_TMP, (p - str) + 1);
196  memcpy (half, str, (p - str));
197  half[p - str] = '\0';
198
199  p2 = strchr (str, '.');
200
201  if (! p2)
202    {
203      if (! all_digit (half))
204	{
205	  XFREE (MTYPE_TMP, half);
206	  return 0;
207	}
208      stream_putw (s, RD_TYPE_AS);
209      stream_putw (s, atoi (half));
210      stream_putl (s, atol (p + 1));
211    }
212  else
213    {
214      ret = inet_aton (half, &addr);
215      if (! ret)
216	{
217	  XFREE (MTYPE_TMP, half);
218	  return 0;
219	}
220      stream_putw (s, RD_TYPE_IP);
221      stream_put_in_addr (s, &addr);
222      stream_putw (s, atol (p + 1));
223    }
224  memcpy (prd->val, s->data, 8);
225
226  return 1;
227}
228
229int
230str2tag (const char *str, u_char *tag)
231{
232  unsigned long l;
233  char *endptr;
234  u_int32_t t;
235
236  if (*str == '-')
237    return 0;
238
239  errno = 0;
240  l = strtoul (str, &endptr, 10);
241
242  if (*endptr != '\0' || errno || l > UINT32_MAX)
243    return 0;
244
245  t = (u_int32_t) l;
246
247  tag[0] = (u_char)(t >> 12);
248  tag[1] = (u_char)(t >> 4);
249  tag[2] = (u_char)(t << 4);
250
251  return 1;
252}
253
254char *
255prefix_rd2str (struct prefix_rd *prd, char *buf, size_t size)
256{
257  u_char *pnt;
258  u_int16_t type;
259  struct rd_as rd_as;
260  struct rd_ip rd_ip;
261
262  if (size < RD_ADDRSTRLEN)
263    return NULL;
264
265  pnt = prd->val;
266
267  type = decode_rd_type (pnt);
268
269  if (type == RD_TYPE_AS)
270    {
271      decode_rd_as (pnt + 2, &rd_as);
272      snprintf (buf, size, "%u:%d", rd_as.as, rd_as.val);
273      return buf;
274    }
275  else if (type == RD_TYPE_IP)
276    {
277      decode_rd_ip (pnt + 2, &rd_ip);
278      snprintf (buf, size, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
279      return buf;
280    }
281
282  return NULL;
283}
284
285/* For testing purpose, static route of MPLS-VPN. */
286DEFUN (vpnv4_network,
287       vpnv4_network_cmd,
288       "network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
289       "Specify a network to announce via BGP\n"
290       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
291       "Specify Route Distinguisher\n"
292       "VPN Route Distinguisher\n"
293       "BGP tag\n"
294       "tag value\n")
295{
296  return bgp_static_set_vpnv4 (vty, argv[0], argv[1], argv[2]);
297}
298
299/* For testing purpose, static route of MPLS-VPN. */
300DEFUN (no_vpnv4_network,
301       no_vpnv4_network_cmd,
302       "no network A.B.C.D/M rd ASN:nn_or_IP-address:nn tag WORD",
303       NO_STR
304       "Specify a network to announce via BGP\n"
305       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
306       "Specify Route Distinguisher\n"
307       "VPN Route Distinguisher\n"
308       "BGP tag\n"
309       "tag value\n")
310{
311  return bgp_static_unset_vpnv4 (vty, argv[0], argv[1], argv[2]);
312}
313
314static int
315show_adj_route_vpn (struct vty *vty, struct peer *peer, struct prefix_rd *prd)
316{
317  struct bgp *bgp;
318  struct bgp_table *table;
319  struct bgp_node *rn;
320  struct bgp_node *rm;
321  struct attr *attr;
322  int rd_header;
323  int header = 1;
324  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s";
325
326  bgp = bgp_get_default ();
327  if (bgp == NULL)
328    {
329      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
330      return CMD_WARNING;
331    }
332
333  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn;
334       rn = bgp_route_next (rn))
335    {
336      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
337        continue;
338
339      if ((table = rn->info) != NULL)
340        {
341          rd_header = 1;
342
343          for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
344            if ((attr = rm->info) != NULL)
345              {
346                if (header)
347                  {
348                    vty_out (vty, "BGP table version is 0, local router ID is %s%s",
349                             inet_ntoa (bgp->router_id), VTY_NEWLINE);
350                    vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
351                             VTY_NEWLINE);
352                    vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
353                             VTY_NEWLINE, VTY_NEWLINE);
354                    vty_out (vty, v4_header, VTY_NEWLINE);
355                    header = 0;
356                  }
357
358                if (rd_header)
359                  {
360                    u_int16_t type;
361                    struct rd_as rd_as;
362                    struct rd_ip rd_ip;
363                    u_char *pnt;
364
365                    pnt = rn->p.u.val;
366
367                    /* Decode RD type. */
368                    type = decode_rd_type (pnt);
369                    /* Decode RD value. */
370                    if (type == RD_TYPE_AS)
371                      decode_rd_as (pnt + 2, &rd_as);
372                    else if (type == RD_TYPE_IP)
373                      decode_rd_ip (pnt + 2, &rd_ip);
374
375                    vty_out (vty, "Route Distinguisher: ");
376
377                    if (type == RD_TYPE_AS)
378                      vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
379                    else if (type == RD_TYPE_IP)
380                      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
381
382                    vty_out (vty, "%s", VTY_NEWLINE);
383                    rd_header = 0;
384                  }
385                route_vty_out_tmp (vty, &rm->p, attr, SAFI_MPLS_VPN);
386              }
387        }
388    }
389  return CMD_SUCCESS;
390}
391
392enum bgp_show_type
393{
394  bgp_show_type_normal,
395  bgp_show_type_regexp,
396  bgp_show_type_prefix_list,
397  bgp_show_type_filter_list,
398  bgp_show_type_neighbor,
399  bgp_show_type_cidr_only,
400  bgp_show_type_prefix_longer,
401  bgp_show_type_community_all,
402  bgp_show_type_community,
403  bgp_show_type_community_exact,
404  bgp_show_type_community_list,
405  bgp_show_type_community_list_exact
406};
407
408static int
409bgp_show_mpls_vpn (struct vty *vty, struct prefix_rd *prd, enum bgp_show_type type,
410		   void *output_arg, int tags)
411{
412  struct bgp *bgp;
413  struct bgp_table *table;
414  struct bgp_node *rn;
415  struct bgp_node *rm;
416  struct bgp_info *ri;
417  int rd_header;
418  int header = 1;
419  char v4_header[] = "   Network          Next Hop            Metric LocPrf Weight Path%s";
420  char v4_header_tag[] = "   Network          Next Hop      In tag/Out tag%s";
421
422  bgp = bgp_get_default ();
423  if (bgp == NULL)
424    {
425      vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
426      return CMD_WARNING;
427    }
428
429  for (rn = bgp_table_top (bgp->rib[AFI_IP][SAFI_MPLS_VPN]); rn; rn = bgp_route_next (rn))
430    {
431      if (prd && memcmp (rn->p.u.val, prd->val, 8) != 0)
432	continue;
433
434      if ((table = rn->info) != NULL)
435	{
436	  rd_header = 1;
437
438	  for (rm = bgp_table_top (table); rm; rm = bgp_route_next (rm))
439	    for (ri = rm->info; ri; ri = ri->next)
440	      {
441		if (type == bgp_show_type_neighbor)
442		  {
443		    union sockunion *su = output_arg;
444
445		    if (ri->peer->su_remote == NULL || ! sockunion_same(ri->peer->su_remote, su))
446		      continue;
447		  }
448		if (header)
449		  {
450		    if (tags)
451		      vty_out (vty, v4_header_tag, VTY_NEWLINE);
452		    else
453		      {
454			vty_out (vty, "BGP table version is 0, local router ID is %s%s",
455				 inet_ntoa (bgp->router_id), VTY_NEWLINE);
456			vty_out (vty, "Status codes: s suppressed, d damped, h history, * valid, > best, i - internal%s",
457				 VTY_NEWLINE);
458			vty_out (vty, "Origin codes: i - IGP, e - EGP, ? - incomplete%s%s",
459				 VTY_NEWLINE, VTY_NEWLINE);
460			vty_out (vty, v4_header, VTY_NEWLINE);
461		      }
462		    header = 0;
463		  }
464
465		if (rd_header)
466		  {
467		    u_int16_t type;
468		    struct rd_as rd_as;
469		    struct rd_ip rd_ip;
470		    u_char *pnt;
471
472		    pnt = rn->p.u.val;
473
474		    /* Decode RD type. */
475		    type = decode_rd_type (pnt);
476		    /* Decode RD value. */
477		    if (type == RD_TYPE_AS)
478		      decode_rd_as (pnt + 2, &rd_as);
479		    else if (type == RD_TYPE_IP)
480		      decode_rd_ip (pnt + 2, &rd_ip);
481
482		    vty_out (vty, "Route Distinguisher: ");
483
484		    if (type == RD_TYPE_AS)
485		      vty_out (vty, "%u:%d", rd_as.as, rd_as.val);
486		    else if (type == RD_TYPE_IP)
487		      vty_out (vty, "%s:%d", inet_ntoa (rd_ip.ip), rd_ip.val);
488
489		    vty_out (vty, "%s", VTY_NEWLINE);
490		    rd_header = 0;
491		  }
492	        if (tags)
493		  route_vty_out_tag (vty, &rm->p, ri, 0, SAFI_MPLS_VPN);
494	        else
495		  route_vty_out (vty, &rm->p, ri, 0, SAFI_MPLS_VPN);
496	      }
497        }
498    }
499  return CMD_SUCCESS;
500}
501
502DEFUN (show_ip_bgp_vpnv4_all,
503       show_ip_bgp_vpnv4_all_cmd,
504       "show ip bgp vpnv4 all",
505       SHOW_STR
506       IP_STR
507       BGP_STR
508       "Display VPNv4 NLRI specific information\n"
509       "Display information about all VPNv4 NLRIs\n")
510{
511  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL, 0);
512}
513
514DEFUN (show_ip_bgp_vpnv4_rd,
515       show_ip_bgp_vpnv4_rd_cmd,
516       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn",
517       SHOW_STR
518       IP_STR
519       BGP_STR
520       "Display VPNv4 NLRI specific information\n"
521       "Display information for a route distinguisher\n"
522       "VPN Route Distinguisher\n")
523{
524  int ret;
525  struct prefix_rd prd;
526
527  ret = str2prefix_rd (argv[0], &prd);
528  if (! ret)
529    {
530      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
531      return CMD_WARNING;
532    }
533  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 0);
534}
535
536DEFUN (show_ip_bgp_vpnv4_all_tags,
537       show_ip_bgp_vpnv4_all_tags_cmd,
538       "show ip bgp vpnv4 all tags",
539       SHOW_STR
540       IP_STR
541       BGP_STR
542       "Display VPNv4 NLRI specific information\n"
543       "Display information about all VPNv4 NLRIs\n"
544       "Display BGP tags for prefixes\n")
545{
546  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_normal, NULL,  1);
547}
548
549DEFUN (show_ip_bgp_vpnv4_rd_tags,
550       show_ip_bgp_vpnv4_rd_tags_cmd,
551       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn tags",
552       SHOW_STR
553       IP_STR
554       BGP_STR
555       "Display VPNv4 NLRI specific information\n"
556       "Display information for a route distinguisher\n"
557       "VPN Route Distinguisher\n"
558       "Display BGP tags for prefixes\n")
559{
560  int ret;
561  struct prefix_rd prd;
562
563  ret = str2prefix_rd (argv[0], &prd);
564  if (! ret)
565    {
566      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
567      return CMD_WARNING;
568    }
569  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_normal, NULL, 1);
570}
571
572DEFUN (show_ip_bgp_vpnv4_all_neighbor_routes,
573       show_ip_bgp_vpnv4_all_neighbor_routes_cmd,
574       "show ip bgp vpnv4 all neighbors A.B.C.D routes",
575       SHOW_STR
576       IP_STR
577       BGP_STR
578       "Display VPNv4 NLRI specific information\n"
579       "Display information about all VPNv4 NLRIs\n"
580       "Detailed information on TCP and BGP neighbor connections\n"
581       "Neighbor to display information about\n"
582       "Display routes learned from neighbor\n")
583{
584  union sockunion su;
585  struct peer *peer;
586  int ret;
587
588  ret = str2sockunion (argv[0], &su);
589  if (ret < 0)
590    {
591      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
592      return CMD_WARNING;
593    }
594
595  peer = peer_lookup (NULL, &su);
596  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
597    {
598      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
599      return CMD_WARNING;
600    }
601
602  return bgp_show_mpls_vpn (vty, NULL, bgp_show_type_neighbor, &su, 0);
603}
604
605DEFUN (show_ip_bgp_vpnv4_rd_neighbor_routes,
606       show_ip_bgp_vpnv4_rd_neighbor_routes_cmd,
607       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D routes",
608       SHOW_STR
609       IP_STR
610       BGP_STR
611       "Display VPNv4 NLRI specific information\n"
612       "Display information for a route distinguisher\n"
613       "VPN Route Distinguisher\n"
614       "Detailed information on TCP and BGP neighbor connections\n"
615       "Neighbor to display information about\n"
616       "Display routes learned from neighbor\n")
617{
618  int ret;
619  union sockunion su;
620  struct peer *peer;
621  struct prefix_rd prd;
622
623  ret = str2prefix_rd (argv[0], &prd);
624  if (! ret)
625    {
626      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
627      return CMD_WARNING;
628    }
629
630  ret = str2sockunion (argv[1], &su);
631  if (ret < 0)
632    {
633      vty_out (vty, "Malformed address: %s%s", argv[0], VTY_NEWLINE);
634      return CMD_WARNING;
635    }
636
637  peer = peer_lookup (NULL, &su);
638  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
639    {
640      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
641      return CMD_WARNING;
642    }
643
644  return bgp_show_mpls_vpn (vty, &prd, bgp_show_type_neighbor, &su, 0);
645}
646
647DEFUN (show_ip_bgp_vpnv4_all_neighbor_advertised_routes,
648       show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd,
649       "show ip bgp vpnv4 all neighbors A.B.C.D advertised-routes",
650       SHOW_STR
651       IP_STR
652       BGP_STR
653       "Display VPNv4 NLRI specific information\n"
654       "Display information about all VPNv4 NLRIs\n"
655       "Detailed information on TCP and BGP neighbor connections\n"
656       "Neighbor to display information about\n"
657       "Display the routes advertised to a BGP neighbor\n")
658{
659  int ret;
660  struct peer *peer;
661  union sockunion su;
662
663  ret = str2sockunion (argv[0], &su);
664  if (ret < 0)
665    {
666      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
667      return CMD_WARNING;
668    }
669  peer = peer_lookup (NULL, &su);
670  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
671    {
672      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
673      return CMD_WARNING;
674    }
675
676  return show_adj_route_vpn (vty, peer, NULL);
677}
678
679DEFUN (show_ip_bgp_vpnv4_rd_neighbor_advertised_routes,
680       show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd,
681       "show ip bgp vpnv4 rd ASN:nn_or_IP-address:nn neighbors A.B.C.D advertised-routes",
682       SHOW_STR
683       IP_STR
684       BGP_STR
685       "Display VPNv4 NLRI specific information\n"
686       "Display information for a route distinguisher\n"
687       "VPN Route Distinguisher\n"
688       "Detailed information on TCP and BGP neighbor connections\n"
689       "Neighbor to display information about\n"
690       "Display the routes advertised to a BGP neighbor\n")
691{
692  int ret;
693  struct peer *peer;
694  struct prefix_rd prd;
695  union sockunion su;
696
697  ret = str2sockunion (argv[1], &su);
698  if (ret < 0)
699    {
700      vty_out (vty, "%% Malformed address: %s%s", argv[0], VTY_NEWLINE);
701      return CMD_WARNING;
702    }
703  peer = peer_lookup (NULL, &su);
704  if (! peer || ! peer->afc[AFI_IP][SAFI_MPLS_VPN])
705    {
706      vty_out (vty, "%% No such neighbor or address family%s", VTY_NEWLINE);
707      return CMD_WARNING;
708    }
709
710  ret = str2prefix_rd (argv[0], &prd);
711  if (! ret)
712    {
713      vty_out (vty, "%% Malformed Route Distinguisher%s", VTY_NEWLINE);
714      return CMD_WARNING;
715    }
716
717  return show_adj_route_vpn (vty, peer, &prd);
718}
719
720void
721bgp_mplsvpn_init (void)
722{
723  install_element (BGP_VPNV4_NODE, &vpnv4_network_cmd);
724  install_element (BGP_VPNV4_NODE, &no_vpnv4_network_cmd);
725
726
727  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_cmd);
728  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_cmd);
729  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_tags_cmd);
730  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd);
731  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd);
732  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd);
733  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd);
734  install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd);
735
736  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_cmd);
737  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_cmd);
738  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_tags_cmd);
739  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_tags_cmd);
740  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_routes_cmd);
741  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_routes_cmd);
742  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_neighbor_advertised_routes_cmd);
743  install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_neighbor_advertised_routes_cmd);
744}
745