]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_route.c
Merge branch 'quagga' into google-bgp-multipath
[mirror_frr.git] / bgpd / bgp_route.c
index f3e46221caf0b57a856f10de80bd48bdec731d0b..087f83961446e6c5f3d23608e55a2d0bce1faf33 100644 (file)
@@ -138,7 +138,7 @@ static void
 bgp_info_free (struct bgp_info *binfo)
 {
   if (binfo->attr)
-    bgp_attr_unintern (binfo->attr);
+    bgp_attr_unintern (&binfo->attr);
   
   bgp_info_extra_free (&binfo->extra);
   bgp_info_mpath_free (&binfo->mpath);
@@ -785,10 +785,12 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
   struct bgp *bgp;
   int transparent;
   int reflect;
+  struct attr *riattr;
 
   from = ri->peer;
   filter = &peer->filter[afi][safi];
   bgp = peer->bgp;
+  riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr;
   
   if (DISABLE_BGP_ANNOUNCE)
     return 0;
@@ -803,11 +805,11 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
 
   /* If peer's id and route's nexthop are same. draft-ietf-idr-bgp4-23 5.1.3 */
   if (p->family == AF_INET
-      && IPV4_ADDR_SAME(&peer->remote_id, &ri->attr->nexthop))
+      && IPV4_ADDR_SAME(&peer->remote_id, &riattr->nexthop))
     return 0;
 #ifdef HAVE_IPV6
   if (p->family == AF_INET6
-     && IPV6_ADDR_SAME(&peer->remote_id, &ri->attr->nexthop))
+     && IPV6_ADDR_SAME(&peer->remote_id, &riattr->nexthop))
     return 0;
 #endif
 
@@ -835,14 +837,14 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
     transparent = 0;
 
   /* If community is not disabled check the no-export and local. */
-  if (! transparent && bgp_community_filter (peer, ri->attr)) 
+  if (! transparent && bgp_community_filter (peer, riattr))
     return 0;
 
   /* If the attribute has originator-id and it is same as remote
      peer's id. */
-  if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
+  if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
     {
-      if (IPV4_ADDR_SAME (&peer->remote_id, &ri->attr->extra->originator_id))
+      if (IPV4_ADDR_SAME (&peer->remote_id, &riattr->extra->originator_id))
        {
          if (BGP_DEBUG (filter, FILTER))  
            zlog (peer->log, LOG_DEBUG,
@@ -865,7 +867,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
       }
 
   /* Output filter check. */
-  if (bgp_output_filter (peer, p, ri->attr, afi, safi) == FILTER_DENY)
+  if (bgp_output_filter (peer, p, riattr, afi, safi) == FILTER_DENY)
     {
       if (BGP_DEBUG (filter, FILTER))
        zlog (peer->log, LOG_DEBUG,
@@ -878,7 +880,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
 
 #ifdef BGP_SEND_ASPATH_CHECK
   /* AS path loop check. */
-  if (aspath_loop_check (ri->attr->aspath, peer->as))
+  if (aspath_loop_check (riattr->aspath, peer->as))
     {
       if (BGP_DEBUG (filter, FILTER))  
         zlog (peer->log, LOG_DEBUG, 
@@ -891,7 +893,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
   /* If we're a CONFED we need to loop check the CONFED ID too */
   if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
     {
-      if (aspath_loop_check(ri->attr->aspath, bgp->confed_id))
+      if (aspath_loop_check(riattr->aspath, bgp->confed_id))
        {
          if (BGP_DEBUG (filter, FILTER))  
            zlog (peer->log, LOG_DEBUG, 
@@ -932,7 +934,7 @@ bgp_announce_check (struct bgp_info *ri, struct peer *peer, struct prefix *p,
     }
   
   /* For modify attribute, copy it to temporary structure. */
-  bgp_attr_dup (attr, ri->attr);
+  bgp_attr_dup (attr, riattr);
   
   /* If local-preference is not set. */
   if ((peer_sort (peer) == BGP_PEER_IBGP 
@@ -1090,11 +1092,11 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
   struct bgp_filter *filter;
   struct bgp_info info;
   struct peer *from;
-  struct bgp *bgp;
+  struct attr *riattr;
 
   from = ri->peer;
   filter = &rsclient->filter[afi][safi];
-  bgp = rsclient->bgp;
+  riattr = bgp_info_mpath_count (ri) ? bgp_info_mpath_attr (ri) : ri->attr;
 
   if (DISABLE_BGP_ANNOUNCE)
     return 0;
@@ -1122,10 +1124,10 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
 
   /* If the attribute has originator-id and it is same as remote
      peer's id. */
-  if (ri->attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
+  if (riattr->flag & ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID))
     {
       if (IPV4_ADDR_SAME (&rsclient->remote_id, 
-                          &ri->attr->extra->originator_id))
+                          &riattr->extra->originator_id))
         {
          if (BGP_DEBUG (filter, FILTER))
            zlog (rsclient->log, LOG_DEBUG,
@@ -1148,7 +1150,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
       }
 
   /* Output filter check. */
-  if (bgp_output_filter (rsclient, p, ri->attr, afi, safi) == FILTER_DENY)
+  if (bgp_output_filter (rsclient, p, riattr, afi, safi) == FILTER_DENY)
     {
       if (BGP_DEBUG (filter, FILTER))
        zlog (rsclient->log, LOG_DEBUG,
@@ -1161,7 +1163,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
 
 #ifdef BGP_SEND_ASPATH_CHECK
   /* AS path loop check. */
-  if (aspath_loop_check (ri->attr->aspath, rsclient->as))
+  if (aspath_loop_check (riattr->aspath, rsclient->as))
     {
       if (BGP_DEBUG (filter, FILTER))
         zlog (rsclient->log, LOG_DEBUG,
@@ -1172,7 +1174,7 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,
 #endif /* BGP_SEND_ASPATH_CHECK */
 
   /* For modify attribute, copy it to temporary structure. */
-  bgp_attr_dup (attr, ri->attr);
+  bgp_attr_dup (attr, riattr);
 
   /* next-hop-set */
   if ((p->family == AF_INET && attr->nexthop.s_addr == 0)
@@ -1316,6 +1318,9 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
          continue;
 
        new_select = ri1;
+       if (do_mpath)
+         bgp_mp_list_add (&mp_list, ri1);
+       old_select = CHECK_FLAG (ri1->flags, BGP_INFO_SELECTED) ? ri1 : NULL;
        if (ri1->next)
          for (ri2 = ri1->next; ri2; ri2 = ri2->next)
            {
@@ -1328,17 +1333,30 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
                  || aspath_cmp_left_confed (ri1->attr->aspath,
                                             ri2->attr->aspath))
                {
+                 if (CHECK_FLAG (ri2->flags, BGP_INFO_SELECTED))
+                   old_select = ri2;
                  if (bgp_info_cmp (bgp, ri2, new_select, &paths_eq))
                    {
                      bgp_info_unset_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
                      new_select = ri2;
+                     if (do_mpath && !paths_eq)
+                       {
+                         bgp_mp_list_clear (&mp_list);
+                         bgp_mp_list_add (&mp_list, ri2);
+                       }
                    }
 
+                 if (do_mpath && paths_eq)
+                   bgp_mp_list_add (&mp_list, ri2);
+
                  bgp_info_set_flag (rn, ri2, BGP_INFO_DMED_CHECK);
                }
            }
        bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_CHECK);
        bgp_info_set_flag (rn, new_select, BGP_INFO_DMED_SELECTED);
+
+       bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg);
+       bgp_mp_list_clear (&mp_list);
       }
 
   /* Check old selected route and new selected route. */
@@ -1372,6 +1390,9 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
 
       if (bgp_info_cmp (bgp, ri, new_select, &paths_eq))
        {
+         if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+           bgp_mp_dmed_deselect (new_select);
+
          new_select = ri;
 
          if (do_mpath && !paths_eq)
@@ -1380,14 +1401,18 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn,
              bgp_mp_list_add (&mp_list, ri);
            }
        }
+      else if (do_mpath && bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+       bgp_mp_dmed_deselect (ri);
 
       if (do_mpath && paths_eq)
        bgp_mp_list_add (&mp_list, ri);
     }
     
 
-  bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg);
+  if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
+    bgp_info_mpath_update (rn, new_select, old_select, &mp_list, mpath_cfg);
 
+  bgp_info_mpath_aggregate_update (new_select, old_select);
   bgp_mp_list_clear (&mp_list);
 
   result->old = old_select;
@@ -1541,7 +1566,7 @@ bgp_process_main (struct work_queue *wq, void *data)
         {
           if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) ||
              CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG))
-            bgp_zebra_announce (p, old_select, bgp);
+            bgp_zebra_announce (p, old_select, bgp, safi);
           
          UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG);
           UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);
@@ -1566,20 +1591,20 @@ bgp_process_main (struct work_queue *wq, void *data)
     }
 
   /* FIB update. */
-  if (safi == SAFI_UNICAST && ! bgp->name &&
-      ! bgp_option_check (BGP_OPT_NO_FIB))
+  if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name &&
+      ! bgp_option_check (BGP_OPT_NO_FIB)))
     {
       if (new_select 
          && new_select->type == ZEBRA_ROUTE_BGP 
          && new_select->sub_type == BGP_ROUTE_NORMAL)
-       bgp_zebra_announce (p, new_select, bgp);
+       bgp_zebra_announce (p, new_select, bgp, safi);
       else
        {
          /* Withdraw the route from the kernel. */
          if (old_select 
              && old_select->type == ZEBRA_ROUTE_BGP
              && old_select->sub_type == BGP_ROUTE_NORMAL)
-           bgp_zebra_withdraw (p, old_select);
+           bgp_zebra_withdraw (p, old_select, safi);
        }
     }
     
@@ -1709,7 +1734,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
        u_int8_t ndata[7];
 
        if (safi == SAFI_MPLS_VPN)
-         safi = BGP_SAFI_VPNV4;
+         safi = SAFI_MPLS_LABELED_VPN;
          
        ndata[0] = (afi >>  8);
        ndata[1] = afi;
@@ -1852,23 +1877,23 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
   /* Apply import policy. */
   if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY)
     {
-      bgp_attr_unintern (attr_new2);
+      bgp_attr_unintern (&attr_new2);
 
       reason = "import-policy;";
       goto filtered;
     }
 
   attr_new = bgp_attr_intern (&new_attr);
-  bgp_attr_unintern (attr_new2);
+  bgp_attr_unintern (&attr_new2);
 
   /* IPv4 unicast next hop check.  */
-  if (afi == AFI_IP && safi == SAFI_UNICAST)
+  if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST))
     {
-     /* Next hop must not be 0.0.0.0 nor Class E address. */
+     /* Next hop must not be 0.0.0.0 nor Class D/E address. */
       if (new_attr.nexthop.s_addr == 0
-         || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
+         || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))
        {
-         bgp_attr_unintern (attr_new);
+         bgp_attr_unintern (&attr_new);
 
          reason = "martian next-hop;";
          goto filtered;
@@ -1898,7 +1923,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
                     p->prefixlen, rsclient->host);
 
           bgp_unlock_node (rn);
-          bgp_attr_unintern (attr_new);
+          bgp_attr_unintern (&attr_new);
 
           return;
         }
@@ -1918,7 +1943,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,
       bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);
 
       /* Update to new attribute.  */
-      bgp_attr_unintern (ri->attr);
+      bgp_attr_unintern (&ri->attr);
       ri->attr = attr_new;
 
       /* Update MPLS tag.  */
@@ -2113,18 +2138,18 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
       /* If the peer is EBGP and nexthop is not on connected route,
         discard it.  */
       if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1
-         && ! bgp_nexthop_check_ebgp (afi, &new_attr)
+         && ! bgp_nexthop_onlink (afi, &new_attr)
          && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
        {
          reason = "non-connected next-hop;";
          goto filtered;
        }
 
-      /* Next hop must not be 0.0.0.0 nor Class E address.  Next hop
+      /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop
         must not be my own address.  */
       if (bgp_nexthop_self (afi, &new_attr)
          || new_attr.nexthop.s_addr == 0
-         || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000)
+         || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))
        {
          reason = "martian next-hop;";
          goto filtered;
@@ -2178,7 +2203,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
            }
 
          bgp_unlock_node (rn);
-         bgp_attr_unintern (attr_new);
+         bgp_attr_unintern (&attr_new);
          bgp_attr_extra_free (&new_attr);
          
          return 0;
@@ -2225,7 +2250,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,
        }
        
       /* Update to new attribute.  */
-      bgp_attr_unintern (ri->attr);
+      bgp_attr_unintern (&ri->attr);
       ri->attr = attr_new;
 
       /* Update MPLS tag.  */
@@ -2517,7 +2542,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)
     }
   
   bgp_attr_extra_free (&attr);
-  aspath_unintern (aspath);
+  aspath_unintern (&aspath);
 }
 \f
 static void
@@ -2986,7 +3011,7 @@ bgp_cleanup_routes (void)
          if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
              && ri->type == ZEBRA_ROUTE_BGP 
              && ri->sub_type == BGP_ROUTE_NORMAL)
-           bgp_zebra_withdraw (&rn->p, ri);
+           bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
 
       table = bgp->rib[AFI_IP6][SAFI_UNICAST];
 
@@ -2995,7 +3020,7 @@ bgp_cleanup_routes (void)
          if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)
              && ri->type == ZEBRA_ROUTE_BGP 
              && ri->sub_type == BGP_ROUTE_NORMAL)
-           bgp_zebra_withdraw (&rn->p, ri);
+           bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);
     }
 }
 
@@ -3265,7 +3290,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
           bgp_attr_flush (&attr_tmp);
 
           /* Unintern original. */
-          aspath_unintern (attr.aspath);
+          aspath_unintern (&attr.aspath);
           bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
           bgp_attr_extra_free (&attr);
           
@@ -3292,8 +3317,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
 
       bgp->peer_self->rmap_type = 0;
 
-      bgp_attr_unintern (attr_new);
-      aspath_unintern (attr.aspath);
+      bgp_attr_unintern (&attr_new);
+      aspath_unintern (&attr.aspath);
       bgp_attr_extra_free (&attr);
 
       bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);
@@ -3303,7 +3328,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
 
   bgp->peer_self->rmap_type = 0;
 
-  bgp_attr_unintern (attr_new);
+  bgp_attr_unintern (&attr_new);
   attr_new = bgp_attr_intern (&new_attr);
   bgp_attr_extra_free (&new_attr);
 
@@ -3318,8 +3343,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
          !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
         {
           bgp_unlock_node (rn);
-          bgp_attr_unintern (attr_new);
-          aspath_unintern (attr.aspath);
+          bgp_attr_unintern (&attr_new);
+          aspath_unintern (&attr.aspath);
           bgp_attr_extra_free (&attr);
           return;
        }
@@ -3331,14 +3356,14 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
           /* Rewrite BGP route information. */
          if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
            bgp_info_restore(rn, ri);
-          bgp_attr_unintern (ri->attr);
+          bgp_attr_unintern (&ri->attr);
           ri->attr = attr_new;
           ri->uptime = bgp_clock ();
 
           /* Process change. */
           bgp_process (bgp, rn, afi, safi);
           bgp_unlock_node (rn);
-          aspath_unintern (attr.aspath);
+          aspath_unintern (&attr.aspath);
           bgp_attr_extra_free (&attr);
           return;
         }
@@ -3363,7 +3388,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,
   bgp_process (bgp, rn, afi, safi);
 
   /* Unintern original. */
-  aspath_unintern (attr.aspath);
+  aspath_unintern (&attr.aspath);
   bgp_attr_extra_free (&attr);
 }
 
@@ -3413,7 +3438,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
          bgp_attr_flush (&attr_tmp);
 
          /* Unintern original. */
-         aspath_unintern (attr.aspath);
+         aspath_unintern (&attr.aspath);
          bgp_attr_extra_free (&attr);
          bgp_static_withdraw (bgp, p, afi, safi);
          return;
@@ -3434,8 +3459,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
          !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))
        {
          bgp_unlock_node (rn);
-         bgp_attr_unintern (attr_new);
-         aspath_unintern (attr.aspath);
+         bgp_attr_unintern (&attr_new);
+         aspath_unintern (&attr.aspath);
          bgp_attr_extra_free (&attr);
          return;
        }
@@ -3449,7 +3474,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
            bgp_info_restore(rn, ri);
          else
            bgp_aggregate_decrement (bgp, p, ri, afi, safi);
-         bgp_attr_unintern (ri->attr);
+         bgp_attr_unintern (&ri->attr);
          ri->attr = attr_new;
          ri->uptime = bgp_clock ();
 
@@ -3457,7 +3482,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
          bgp_aggregate_increment (bgp, p, ri, afi, safi);
          bgp_process (bgp, rn, afi, safi);
          bgp_unlock_node (rn);
-         aspath_unintern (attr.aspath);
+         aspath_unintern (&attr.aspath);
          bgp_attr_extra_free (&attr);
          return;
        }
@@ -3485,7 +3510,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,
   bgp_process (bgp, rn, afi, safi);
 
   /* Unintern original. */
-  aspath_unintern (attr.aspath);
+  aspath_unintern (&attr.aspath);
   bgp_attr_extra_free (&attr);
 }
 
@@ -4219,7 +4244,7 @@ DEFUN (ipv6_bgp_network,
        "Specify a network to announce via BGP\n"
        "IPv6 prefix <network>/<length>\n")
 {
-  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST,
+  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty),
                          NULL, 0);
 }
 
@@ -4242,7 +4267,7 @@ DEFUN (no_ipv6_bgp_network,
        "Specify a network to announce via BGP\n"
        "IPv6 prefix <network>/<length>\n")
 {
-  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST);
+  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty));
 }
 
 ALIAS (no_ipv6_bgp_network,
@@ -5294,7 +5319,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only,
 \f
 /* Redistribute route treatment. */
 void
-bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
+bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop,
+                     const struct in6_addr *nexthop6,
                      u_int32_t metric, u_char type)
 {
   struct bgp *bgp;
@@ -5314,6 +5340,15 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
   if (nexthop)
     attr.nexthop = *nexthop;
 
+#ifdef HAVE_IPV6
+  if (nexthop6)
+    {
+      struct attr_extra *extra = bgp_attr_extra_get(&attr);
+      extra->mp_nexthop_global = *nexthop6;
+      extra->mp_nexthop_len = 16;
+    }
+#endif
+
   attr.med = metric;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
 
@@ -5349,7 +5384,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
                  bgp_attr_extra_free (&attr_new);
                  
                  /* Unintern original. */
-                 aspath_unintern (attr.aspath);
+                 aspath_unintern (&attr.aspath);
                  bgp_attr_extra_free (&attr);
                  bgp_redistribute_delete (p, type);
                  return;
@@ -5372,8 +5407,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
              if (attrhash_cmp (bi->attr, new_attr) &&
                  !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))
                {
-                 bgp_attr_unintern (new_attr);
-                 aspath_unintern (attr.aspath);
+                 bgp_attr_unintern (&new_attr);
+                 aspath_unintern (&attr.aspath);
                  bgp_attr_extra_free (&attr);
                  bgp_unlock_node (bn);
                  return;
@@ -5388,7 +5423,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
                    bgp_info_restore(bn, bi);
                  else
                    bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST);
-                 bgp_attr_unintern (bi->attr);
+                 bgp_attr_unintern (&bi->attr);
                  bi->attr = new_attr;
                  bi->uptime = bgp_clock ();
  
@@ -5396,7 +5431,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
                  bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST);
                  bgp_process (bgp, bn, afi, SAFI_UNICAST);
                  bgp_unlock_node (bn);
-                 aspath_unintern (attr.aspath);
+                 aspath_unintern (&attr.aspath);
                  bgp_attr_extra_free (&attr);
                  return;
                } 
@@ -5418,7 +5453,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,
     }
 
   /* Unintern original. */
-  aspath_unintern (attr.aspath);
+  aspath_unintern (&attr.aspath);
   bgp_attr_extra_free (&attr);
 }
 
@@ -9434,10 +9469,8 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
         safi = SAFI_MULTICAST;
       else if (strncmp (safi_str, "u", 1) == 0)
         safi = SAFI_UNICAST;
-      else if (strncmp (safi_str, "vpnv4", 5) == 0)
-        safi = BGP_SAFI_VPNV4;
-      else if (strncmp (safi_str, "vpnv6", 6) == 0)
-        safi = BGP_SAFI_VPNV6;
+      else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0)
+        safi = SAFI_MPLS_LABELED_VPN;
       else
         {
           vty_out (vty, "%% Invalid subsequent address family %s%s",
@@ -9452,13 +9485,6 @@ bgp_table_stats_vty (struct vty *vty, const char *name,
       return CMD_WARNING;
     }
 
-  if ((afi == AFI_IP && safi ==  BGP_SAFI_VPNV6)
-      || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4))
-    {
-      vty_out (vty, "%% Invalid subsequent address family %s for %s%s",
-               afi_str, safi_str, VTY_NEWLINE);
-      return CMD_WARNING;
-    }
   return bgp_table_stats (vty, bgp, afi, safi);
 }
 
@@ -12636,6 +12662,9 @@ bgp_route_init (void)
   install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);
   install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd);
 
+  install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
+  install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd);
+
   /* Old config IPv6 BGP commands.  */
   install_element (BGP_NODE, &old_ipv6_bgp_network_cmd);
   install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd);