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