]> git.puffer.fish Git - mirror/frr.git/commitdiff
This patch adds support for allowing BGP to create and bring up neighbor
authorDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:03:47 +0000 (18:03 -0700)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Wed, 20 May 2015 01:03:47 +0000 (18:03 -0700)
sessions dynamically. The operator configures a range of neighbor addresses
to which peering is allowed. The ranges are configured as subnets and
multiple ranges are allowed. Each range is associated with a peer-group
so that additional parameters can be configured.

BGP neighbor sessions are dynamically created when connections are initiated
by remote neighbors whose addresses fall within a configured range. The
sessions are deleted when the BGP connection terminates.

A limit on the number of neighbors allowed from each range of addresses
can be specified.

IPv4 and IPv6 peering is supported. Over the peering, any of the address
families configured for the peer-group can be negotiated.

bgpd/bgp_fsm.c
bgpd/bgp_network.c
bgpd/bgp_route.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgpd.c
bgpd/bgpd.h
lib/command.h

index 28cfb45af26216bc7ff51bd4f3412195c3aca261..5683c1544429b20be40e530d6516daf6ee92d9cb 100644 (file)
@@ -951,6 +951,15 @@ bgp_stop (struct peer *peer)
   char orf_name[BUFSIZ];
   int ret = 0;
 
+  if (peer_dynamic_neighbor(peer) &&
+      !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE)))
+    {
+      if (bgp_debug_neighbor_events(peer))
+        zlog_debug ("%s (dynamic neighbor) deleted", peer->host);
+      peer_delete (peer);
+      return -1;
+    }
+
   /* Can't do this in Clearing; events are used for state transitions */
   if (peer->status != Clearing)
     {
@@ -1117,6 +1126,14 @@ bgp_stop_with_error (struct peer *peer)
   if (peer->v_start >= (60 * 2))
     peer->v_start = (60 * 2);
 
+  if (peer_dynamic_neighbor(peer))
+    {
+      if (bgp_debug_neighbor_events(peer))
+        zlog_debug ("%s (dynamic neighbor) deleted", peer->host);
+      peer_delete (peer);
+      return -1;
+    }
+
   return(bgp_stop (peer));
 }
 
@@ -1128,6 +1145,14 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code)
   /* Send notify to remote peer */
   bgp_notify_send (peer, code, sub_code);
 
+  if (peer_dynamic_neighbor(peer))
+    {
+      if (bgp_debug_neighbor_events(peer))
+        zlog_debug ("%s (dynamic neighbor) deleted", peer->host);
+      peer_delete (peer);
+      return -1;
+    }
+
   /* Clear start timer value to default. */
   peer->v_start = BGP_INIT_START_TIMER;
 
@@ -1180,6 +1205,14 @@ bgp_connect_success (struct peer *peer)
 static int
 bgp_connect_fail (struct peer *peer)
 {
+  if (peer_dynamic_neighbor(peer))
+    {
+      if (bgp_debug_neighbor_events(peer))
+        zlog_debug ("%s (dynamic neighbor) deleted", peer->host);
+      peer_delete (peer);
+      return -1;
+    }
+
   return (bgp_stop (peer));
 }
 
@@ -1737,9 +1770,11 @@ bgp_event_update (struct peer *peer, int event)
   int ret = 0;
   struct peer *other;
   int passive_conn = 0;
+  int dyn_nbr;
 
   other = peer->doppelganger;
   passive_conn = (CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)) ? 1 : 0;
+  dyn_nbr = peer_dynamic_neighbor(peer);
 
   /* Logging this event. */
   next = FSM [peer->status -1][event - 1].next_state;
@@ -1772,7 +1807,7 @@ bgp_event_update (struct peer *peer, int event)
       bgp_timer_set (peer);
 
     }
-  else if (!passive_conn && peer->bgp)
+  else if (!dyn_nbr && !passive_conn && peer->bgp)
     {
       /* If we got a return value of -1, that means there was an error, restart
        * the FSM. If the peer structure was deleted
index eb8bad76272093e33ef1b6ca0dd7f90b1368b3d3..63d8580aad230dad94f44ce05e2d7de0e136024e 100644 (file)
@@ -224,11 +224,30 @@ bgp_accept (struct thread *thread)
 
   /* Check remote IP address */
   peer1 = peer_lookup (NULL, &su);
+
+  if (! peer1)
+    {
+      peer1 = peer_lookup_dynamic_neighbor (NULL, &su);
+      if (peer1)
+        {
+          /* Dynamic neighbor has been created, let it proceed */
+          peer1->fd = bgp_sock;
+          bgp_fsm_change_status(peer1, Active);
+          BGP_TIMER_OFF(peer1->t_start); /* created in peer_create() */
+
+          if (peer_active (peer1))
+              BGP_EVENT_ADD (peer1, TCP_connection_open);
+
+          return 0;
+        }
+    }
+
   if (! peer1)
     {
       if (bgp_debug_neighbor_events(peer))
        {
-         zlog_debug ("[Event] BGP connection IP address %s is not configured",
+         zlog_debug ("[Event] %s connection rejected - not configured"
+                      " and not valid for dynamic",
                      inet_sutop (&su, buf));
        }
       close (bgp_sock);
index 7094e8ca455d0441b32773e87b912e73e54b4f49..7a465314a2952225baa4f05bf76453ba3ba4598d 100644 (file)
@@ -2508,6 +2508,10 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,
                                   BGP_NOTIFY_CEASE_MAX_PREFIX, ndata, 7);
       }
 
+      /* Dynamic peers will just close their connection. */
+      if (peer_dynamic_neighbor (peer))
+        return 1;
+
       /* restart timer start */
       if (peer->pmax_restart[afi][safi])
        {
index 5cfbaebeb39c3bfcbeb871ebdec9a74a01d70ca8..9fcebaf6edc822868083644bda070e5f1da24c04 100644 (file)
@@ -95,6 +95,9 @@ peer_address_self_check (union sockunion *su)
 }
 
 /* Utility function for looking up peer from VTY.  */
+/* This is used only for configuration, so disallow if attempted on
+ * a dynamic neighbor.
+ */
 static struct peer *
 peer_lookup_vty (struct vty *vty, const char *ip_str)
 {
@@ -124,40 +127,61 @@ peer_lookup_vty (struct vty *vty, const char *ip_str)
                    VTY_NEWLINE);
           return NULL;
         }
+      if (peer_dynamic_neighbor (peer))
+        {
+          vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s",
+                  VTY_NEWLINE);
+          return NULL;
+        }
+
     }
   return peer;
 }
 
 /* Utility function for looking up peer or peer group.  */
+/* This is used only for configuration, so disallow if attempted on
+ * a dynamic neighbor.
+ */
 static struct peer *
 peer_and_group_lookup_vty (struct vty *vty, const char *peer_str)
 {
   int ret;
   struct bgp *bgp;
   union sockunion su;
-  struct peer *peer;
-  struct peer_group *group;
+  struct peer *peer = NULL;
+  struct peer_group *group = NULL;
 
   bgp = vty->index;
 
   ret = str2sockunion (peer_str, &su);
   if (ret == 0)
     {
+      /* IP address, locate peer. */
       peer = peer_lookup (bgp, &su);
-      if (peer)
-       return peer;
     }
   else
     {
+      /* Not IP, could match either peer configured on interface or a group. */
       peer = peer_lookup_by_conf_if (bgp, peer_str);
-      if (peer)
-        return peer;
+      if (!peer)
+        group = peer_group_lookup (bgp, peer_str);
+    }
 
-      group = peer_group_lookup (bgp, peer_str);
-      if (group)
-       return group->conf;
+  if (peer)
+    {
+      if (peer_dynamic_neighbor (peer))
+        {
+          vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s",
+                  VTY_NEWLINE);
+          return NULL;
+        }
+
+      return peer;
     }
 
+  if (group)
+    return group->conf;
+
   vty_out (vty, "%% Specify remote-as or peer-group commands first%s",
           VTY_NEWLINE);
 
@@ -237,6 +261,15 @@ bgp_vty_return (struct vty *vty, int ret)
     case BGP_ERR_AS_OVERRIDE:
       str = "as-override cannot be configured for IBGP peers";
       break;
+    case BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT:
+      str = "Invalid limit for number of dynamic neighbors";
+      break;
+    case BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS:
+      str = "Dynamic neighbor listen range already exists";
+      break;
+    case BGP_ERR_INVALID_FOR_DYNAMIC_PEER:
+      str = "Operation not allowed on a dynamic neighbor";
+      break;
     }
   if (str)
     {
@@ -1883,6 +1916,176 @@ DEFUN (no_bgp_rr_allow_outbound_policy,
   return CMD_SUCCESS;
 }
 
+DEFUN (bgp_listen_limit,
+       bgp_listen_limit_cmd,
+       "bgp listen limit " DYNAMIC_NEIGHBOR_LIMIT_RANGE,
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "maximum number of BGP Dynamic Neighbors that can be created\n"
+       "Configure Dynamic Neighbors listen limit value\n")
+{
+  struct bgp *bgp;
+  int listen_limit;
+
+  bgp = vty->index;
+
+  VTY_GET_INTEGER_RANGE ("listen limit", listen_limit, argv[0],
+                         BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN,
+                         BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX);
+
+  bgp_listen_limit_set (bgp, listen_limit);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_listen_limit,
+       no_bgp_listen_limit_cmd,
+       "no bgp listen limit",
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "unset maximum number of BGP Dynamic Neighbors that can be created\n"
+       "Configure Dynamic Neighbors listen limit value to default\n")
+{
+  struct bgp *bgp;
+
+  bgp = vty->index;
+  bgp_listen_limit_unset (bgp);
+  return CMD_SUCCESS;
+}
+
+
+DEFUN (bgp_listen_range,
+       bgp_listen_range_cmd,
+       LISTEN_RANGE_CMD "peer-group WORD" ,
+       "BGP specific commands\n"
+       "Configure BGP Dynamic Neighbors\n"
+       "add a listening range for Dynamic Neighbors\n"
+       LISTEN_RANGE_ADDR_STR)
+{
+  struct bgp *bgp;
+  struct prefix range;
+  struct peer_group *group;
+  afi_t afi;
+  int ret;
+
+  bgp = vty->index;
+
+  //VTY_GET_IPV4_PREFIX ("listen range", range, argv[0]);
+
+  /* Convert IP prefix string to struct prefix. */
+  ret = str2prefix (argv[0], &range);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed listen range%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  afi = family2afi(range.family);
+
+#ifdef HAVE_IPV6
+  if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&range.u.prefix6))
+    {
+      vty_out (vty, "%% Malformed listen range (link-local address)%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+#endif /* HAVE_IPV6 */
+
+  apply_mask (&range);
+
+
+  group = peer_group_lookup (bgp, argv[1]);
+  if (! group)
+    {
+      vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = peer_group_listen_range_add(group, &range);
+  return bgp_vty_return (vty, ret);
+}
+
+DEFUN (no_bgp_listen_range,
+       no_bgp_listen_range_cmd,
+       "no bgp listen range A.B.C.D/M peer-group WORD" ,
+       "BGP specific commands\n"
+       "Configure BGP defaults\n"
+       "delete a listening range for Dynamic Neighbors\n"
+       "Remove Dynamic Neighbors listening range\n")
+{
+  struct bgp *bgp;
+  struct prefix range;
+  struct peer_group *group;
+  afi_t afi;
+  int ret;
+
+  bgp = vty->index;
+
+  // VTY_GET_IPV4_PREFIX ("listen range", range, argv[0]);
+
+  /* Convert IP prefix string to struct prefix. */
+  ret = str2prefix (argv[0], &range);
+  if (! ret)
+    {
+      vty_out (vty, "%% Malformed listen range%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  afi = family2afi(range.family);
+
+#ifdef HAVE_IPV6
+  if (afi == AFI_IP6 && IN6_IS_ADDR_LINKLOCAL (&range.u.prefix6))
+    {
+      vty_out (vty, "%% Malformed listen range (link-local address)%s",
+              VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+#endif /* HAVE_IPV6 */
+
+  apply_mask (&range);
+
+
+  group = peer_group_lookup (bgp, argv[1]);
+  if (! group)
+    {
+      vty_out (vty, "%% Peer-group does not exist%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  ret = peer_group_listen_range_del(group, &range);
+  return bgp_vty_return (vty, ret);
+}
+
+int
+bgp_config_write_listen (struct vty *vty, struct bgp *bgp)
+{
+  struct peer_group *group;
+  struct listnode *node, *nnode, *rnode, *nrnode;
+  struct prefix *range;
+  afi_t afi;
+  char buf[128];
+
+  if (bgp->dynamic_neighbors_limit != BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT)
+      vty_out (vty, " bgp listen limit %d%s",
+               bgp->dynamic_neighbors_limit, VTY_NEWLINE);
+
+  for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+    {
+      for (afi = AFI_IP; afi < AFI_MAX; afi++)
+        {
+          for (ALL_LIST_ELEMENTS (group->listen_range[afi], rnode, nrnode, range))
+            {
+              prefix2str(range, buf, sizeof(buf));
+              vty_out(vty, " bgp listen range %s peer-group %s%s",
+                      buf, group->name, VTY_NEWLINE);
+            }
+        }
+    }
+
+  return 0;
+}
+
+
 static int
 peer_remote_as_vty (struct vty *vty, const char *peer_str, 
                     const char *as_str, afi_t afi, safi_t safi)
@@ -2041,6 +2244,13 @@ DEFUN (no_neighbor,
       peer = peer_lookup (vty->index, &su);
       if (peer)
        {
+          if (peer_dynamic_neighbor (peer))
+            {
+              vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s",
+                       VTY_NEWLINE);
+              return CMD_WARNING;
+            }
+
          other = peer->doppelganger;
          peer_delete (peer);
          if (other && other->status != Deleted)
@@ -2396,6 +2606,15 @@ DEFUN (neighbor_set_peer_group,
                    VTY_NEWLINE);
           return CMD_WARNING;
         }
+
+      /* Disallow for dynamic neighbor. */
+      peer = peer_lookup (bgp, &su);
+      if (peer && peer_dynamic_neighbor (peer))
+        {
+          vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s",
+                  VTY_NEWLINE);
+          return CMD_WARNING;
+        }
     }
 
   group = peer_group_lookup (bgp, argv[1]);
@@ -7903,9 +8122,10 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
 {
   struct peer *peer;
   struct listnode *node, *nnode;
-  unsigned int count = 0;
-  char timebuf[BGP_UPTIME_LEN];
+  unsigned int count = 0, dn_count = 0;
+  char timebuf[BGP_UPTIME_LEN], dn_flag[2];
   int len;
+  struct peer_group *group;
 
   /* Header string for each address family. */
   static char header[] = "Neighbor        V    AS MsgRcvd MsgSent   TblVer  InQ OutQ Up/Down  State/PfxRcd";
@@ -8006,7 +8226,14 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
           
          count++;
 
-         len = vty_out (vty, "%s", peer->host);
+      memset(dn_flag, '\0', sizeof(dn_flag));
+      if (peer_dynamic_neighbor(peer))
+        {
+          dn_count++;
+          dn_flag[0] = '*';
+        }
+
+      len = vty_out (vty, "%s%s", dn_flag, peer->host);
          len = 16 - len;
          if (len < 1)
            vty_out (vty, "%s%*s", VTY_NEWLINE, 16, " ");
@@ -8076,6 +8303,16 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi, char *del
     vty_out (vty, "No %s neighbor is configured%s",
             afi == AFI_IP ? "IPv4" : "IPv6", VTY_NEWLINE);
 
+
+  if (dn_count)
+    {
+      vty_out(vty, "* - dynamic neighbor%s", VTY_NEWLINE);
+      vty_out(vty,
+              "%d %s dynamic neighbor(s), limit %d%s",
+              dn_count, afi == AFI_IP ? "IPv4" : "IPv6",
+              bgp->dynamic_neighbors_limit, VTY_NEWLINE);
+    }
+
   return CMD_SUCCESS;
 }
 
@@ -8642,6 +8879,7 @@ bgp_show_peer (struct vty *vty, struct peer *p)
   struct bgp *bgp;
   char buf1[BUFSIZ], buf[SU_ADDRSTRLEN];
   char timebuf[BGP_UPTIME_LEN];
+  char dn_flag[2];
   afi_t afi;
   safi_t safi;
   u_int16_t i;
@@ -8654,7 +8892,14 @@ bgp_show_peer (struct vty *vty, struct peer *p)
              BGP_PEER_SU_UNSPEC(p) ? "None" :
              sockunion2str (&p->su, buf, SU_ADDRSTRLEN));
   else /* Configured IP address. */
-    vty_out (vty, "BGP neighbor is %s, ", p->host);
+    {
+      memset(dn_flag, '\0', sizeof(dn_flag));
+      if (peer_dynamic_neighbor(p))
+        dn_flag[0] = '*';
+
+      vty_out (vty, "BGP neighbor is %s%s, ", dn_flag, p->host);
+    }
+
   vty_out (vty, "remote AS %u, ", p->as);
   vty_out (vty, "local AS %u%s%s, ",
           p->change_local_as ? p->change_local_as : p->local_as,
@@ -8672,8 +8917,26 @@ bgp_show_peer (struct vty *vty, struct peer *p)
   
   /* Peer-group */
   if (p->group)
-    vty_out (vty, " Member of peer-group %s for session parameters%s",
-            p->group->name, VTY_NEWLINE);
+    {
+      vty_out (vty, " Member of peer-group %s for session parameters%s",
+               p->group->name, VTY_NEWLINE);
+
+      if (dn_flag[0])
+        {
+          struct prefix *prefix = NULL, *range = NULL;
+
+          prefix = sockunion2hostprefix(&(p->su));
+          if (prefix)
+            range = peer_group_lookup_dynamic_neighbor_range (p->group,
+                                                              prefix);
+          if (range)
+            {
+              prefix2str(range, buf1, sizeof(buf1));
+              vty_out (vty, " Belongs to the subnet range group: %s%s",
+                       buf1, VTY_NEWLINE);
+            }
+        }
+    }
 
   /* Administrative shutdown. */
   if (CHECK_FLAG (p->flags, PEER_FLAG_SHUTDOWN))
@@ -9968,6 +10231,205 @@ DEFUN (show_bgp_updgrps_afi_adj_subgroup,
   show_bgp_updgrps_adj_info_aux(vty, afi, safi, argv[3], atoll(argv[2]));
 }
 
+static int
+bgp_show_one_peer_group (struct vty *vty, struct peer_group *group)
+{
+  struct listnode *node, *nnode;
+  struct prefix *range;
+  struct peer *conf;
+  struct peer *peer;
+  char buf[128];
+  afi_t afi;
+  safi_t safi;
+  char *peer_status, *af_str;
+  int lr_count;
+  int dynamic;
+  int af_cfgd;
+
+  conf = group->conf;
+
+  vty_out (vty, "%sBGP peer-group %s,  remote AS %d%s",
+           VTY_NEWLINE, group->name, conf->as, VTY_NEWLINE);
+
+  if (group->bgp->as == conf->as)
+    vty_out (vty, "  Peer-group type is internal%s", VTY_NEWLINE);
+  else
+    vty_out (vty, "  Peer-group type is external%s", VTY_NEWLINE);
+
+  /* Display AFs configured. */
+  vty_out (vty, "  Configured address-families:");
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++)
+      {
+        if (conf->afc[afi][safi])
+          {
+            af_cfgd = 1;
+            vty_out (vty, " %s;", afi_safi_print(afi, safi));
+          }
+      }
+  if (!af_cfgd)
+    vty_out (vty, " none%s", VTY_NEWLINE);
+  else
+    vty_out (vty, "%s", VTY_NEWLINE);
+
+  /* Display listen ranges (for dynamic neighbors), if any */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    {
+      if (afi == AFI_IP)
+        af_str = "IPv4";
+      else if (afi == AFI_IP6)
+        af_str = "IPv6";
+      lr_count = listcount(group->listen_range[afi]);
+      if (lr_count)
+        {
+          vty_out(vty,
+                  "  %d %s listen range(s)%s",
+                  lr_count, af_str, VTY_NEWLINE);
+
+
+          for (ALL_LIST_ELEMENTS (group->listen_range[afi], node,
+                                  nnode, range))
+            {
+              prefix2str(range, buf, sizeof(buf));
+              vty_out(vty, "    %s%s", buf, VTY_NEWLINE);
+            }
+        }
+    }
+
+  /* Display group members and their status */
+  if (listcount(group->peer))
+    {
+      vty_out (vty, "  Peer-group members:%s", VTY_NEWLINE);
+      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+        {
+          if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
+            peer_status = "Idle (Admin)";
+          else if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+            peer_status = "Idle (PfxCt)";
+          else
+            peer_status = LOOKUP(bgp_status_msg, peer->status);
+
+          dynamic = peer_dynamic_neighbor(peer);
+          vty_out (vty, "    %s %s %s %s",
+                   peer->host, dynamic ? "(dynamic)" : "",
+                   peer_status, VTY_NEWLINE);
+        }
+    }
+
+  return CMD_SUCCESS;
+}
+
+/* Show BGP peer group's information. */
+enum show_group_type
+{
+  show_all_groups,
+  show_peer_group
+};
+
+static int
+bgp_show_peer_group (struct vty *vty, struct bgp *bgp,
+                     enum show_group_type type, const char *group_name)
+{
+  struct listnode *node, *nnode;
+  struct peer_group *group;
+  int find = 0;
+
+  for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+    {
+      switch (type)
+       {
+       case show_all_groups:
+         bgp_show_one_peer_group (vty, group);
+         break;
+       case show_peer_group:
+          if (group_name && (strcmp(group->name, group_name) == 0))
+            {
+              find = 1;
+              bgp_show_one_peer_group (vty, group);
+           }
+         break;
+       }
+    }
+
+  if (type == show_peer_group && ! find)
+    vty_out (vty, "%% No such peer-groupr%s", VTY_NEWLINE);
+
+  return CMD_SUCCESS;
+}
+
+static int
+bgp_show_peer_group_vty (struct vty *vty, const char *name,
+                         enum show_group_type type, const char *group_name)
+{
+  struct bgp *bgp;
+  int ret = CMD_SUCCESS;
+
+  if (name)
+    {
+      bgp = bgp_lookup_by_name (name);
+
+      if (! bgp)
+        {
+          vty_out (vty, "%% No such BGP instance exist%s", VTY_NEWLINE);
+          return CMD_WARNING;
+        }
+    }
+
+  bgp = bgp_get_default ();
+
+  if (bgp)
+    ret = bgp_show_peer_group (vty, bgp, type, group_name);
+
+  return ret;
+}
+
+DEFUN (show_ip_bgp_peer_groups,
+       show_ip_bgp_peer_groups_cmd,
+       "show ip bgp peer-group",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "Detailed information on all BGP peer groups\n")
+{
+  return bgp_show_peer_group_vty (vty, NULL, show_all_groups, NULL);
+}
+
+DEFUN (show_ip_bgp_instance_peer_groups,
+       show_ip_bgp_instance_peer_groups_cmd,
+       "show ip bgp view WORD peer-group",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP View\n"
+       "Detailed information on all BGP peer groups\n")
+{
+  return bgp_show_peer_group_vty (vty, argv[0], show_all_groups, NULL);
+}
+
+DEFUN (show_ip_bgp_peer_group,
+       show_ip_bgp_peer_group_cmd,
+       "show ip bgp peer-group WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP peer-group name\n"
+       "Detailed information on a BGP peer group\n")
+{
+  return bgp_show_peer_group_vty (vty, NULL, show_peer_group, argv[0]);
+}
+
+DEFUN (show_ip_bgp_instance_peer_group,
+       show_ip_bgp_instance_peer_group_cmd,
+       "show ip bgp view WORD peer-group WORD",
+       SHOW_STR
+       IP_STR
+       BGP_STR
+       "BGP View\n"
+       "BGP peer-group name\n"
+       "Detailed information on a BGP peer group\n")
+{
+  return bgp_show_peer_group_vty (vty, argv[0], show_peer_group, argv[1]);
+}
 
 /* Redistribute VTY commands.  */
 
@@ -10812,6 +11274,14 @@ bgp_vty_init (void)
   install_element (BGP_NODE, &bgp_rr_allow_outbound_policy_cmd);
   install_element (BGP_NODE, &no_bgp_rr_allow_outbound_policy_cmd);
 
+  /* "bgp listen limit" commands. */
+  install_element (BGP_NODE, &bgp_listen_limit_cmd);
+  install_element (BGP_NODE, &no_bgp_listen_limit_cmd);
+
+  /* "bgp listen range" commands. */
+  install_element (BGP_NODE, &bgp_listen_range_cmd);
+  install_element (BGP_NODE, &no_bgp_listen_range_cmd);
+
   /* "neighbor remote-as" commands. */
   install_element (BGP_NODE, &neighbor_remote_as_cmd);
   install_element (BGP_NODE, &neighbor_interface_config_cmd);
@@ -11806,6 +12276,16 @@ bgp_vty_init (void)
   install_element (ENABLE_NODE, &show_ipv6_mbgp_summary_cmd);
 #endif /* HAVE_IPV6 */
 
+  /* "show ip bgp peer-group" commands. */
+  install_element (VIEW_NODE, &show_ip_bgp_peer_groups_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_peer_groups_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_peer_group_cmd);
+  install_element (VIEW_NODE, &show_ip_bgp_instance_peer_group_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_peer_groups_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_peer_groups_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_peer_group_cmd);
+  install_element (ENABLE_NODE, &show_ip_bgp_instance_peer_group_cmd);
+
   /* "show ip bgp rsclient" commands. */
   install_element (VIEW_NODE, &show_ip_bgp_rsclient_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd);
index 1357e3c25ad37ae9f44dbe4ab14933c8ec3fa620..7f47f263be77879849a2e8f2468bd5a98b88bfb7 100644 (file)
@@ -22,11 +22,13 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 #define _QUAGGA_BGP_VTY_H
 
 #define CMD_AS_RANGE "<1-4294967295>"
+#define DYNAMIC_NEIGHBOR_LIMIT_RANGE "<1-5000>"
 
 extern void bgp_vty_init (void);
 extern const char *afi_safi_print (afi_t, safi_t);
 extern int bgp_config_write_update_delay (struct vty *, struct bgp *);
 extern int bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
+extern int bgp_config_write_listen(struct vty *vty, struct bgp *bgp);
 extern int bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp);
 
 #endif /* _QUAGGA_BGP_VTY_H */
index 17bf8cf5d6233c2a958d845a049be4100cc7a5d8..cbe8580f3a784a68172a0ab396dfc80178a7af11 100644 (file)
@@ -572,6 +572,29 @@ bgp_default_subgroup_pkt_queue_max_unset (struct bgp *bgp)
   return 0;
 }
 
+/* Listen limit configuration.  */
+int
+bgp_listen_limit_set (struct bgp *bgp, int listen_limit)
+{
+  if (! bgp)
+    return -1;
+
+  bgp->dynamic_neighbors_limit = listen_limit;
+
+  return 0;
+}
+
+int
+bgp_listen_limit_unset (struct bgp *bgp)
+{
+  if (! bgp)
+    return -1;
+
+  bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
+
+  return 0;
+}
+
 struct peer_af *
 peer_af_create (struct peer *peer, afi_t afi, safi_t safi)
 {
@@ -1309,6 +1332,13 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, const char *conf_if, as_t
 
   if (peer)
     {
+      /* Not allowed for a dynamic peer. */
+      if (peer_dynamic_neighbor (peer))
+        {
+          *as = peer->as;
+          return BGP_ERR_INVALID_FOR_DYNAMIC_PEER;
+        }
+
       /* When this peer is a member of peer-group.  */
       if (peer->group)
        {
@@ -1551,6 +1581,9 @@ peer_delete (struct peer *peer)
      relationship.  */
   if (peer->group)
     {
+      if (peer_dynamic_neighbor(peer))
+        peer_drop_dynamic_neighbor(peer);
+
       if ((pn = listnode_lookup (peer->group->peer, peer)))
         {
           peer = peer_unlock (peer); /* group->peer list reference */
@@ -1719,6 +1752,7 @@ struct peer_group *
 peer_group_get (struct bgp *bgp, const char *name)
 {
   struct peer_group *group;
+  afi_t afi;
 
   group = peer_group_lookup (bgp, name);
   if (group)
@@ -1728,6 +1762,8 @@ peer_group_get (struct bgp *bgp, const char *name)
   group->bgp = bgp;
   group->name = strdup (name);
   group->peer = list_new ();
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    group->listen_range[afi] = list_new ();
   group->conf = peer_new (bgp);
   if (! bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
     group->conf->afc[AFI_IP][SAFI_UNICAST] = 1;
@@ -2039,8 +2075,10 @@ peer_group_delete (struct peer_group *group)
 {
   struct bgp *bgp;
   struct peer *peer;
+  struct prefix *prefix;
   struct peer *other;
   struct listnode *node, *nnode;
+  afi_t afi;
 
   bgp = group->bgp;
 
@@ -2057,6 +2095,15 @@ peer_group_delete (struct peer_group *group)
     }
   list_delete (group->peer);
 
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    {
+      for (ALL_LIST_ELEMENTS (group->listen_range[afi], node, nnode, prefix))
+        {
+          prefix_free(prefix);
+        }
+      list_delete (group->listen_range[afi]);
+    }
+
   free (group->name);
   group->name = NULL;
 
@@ -2100,6 +2147,78 @@ peer_group_remote_as_delete (struct peer_group *group)
   return 0;
 }
 
+int
+peer_group_listen_range_add (struct peer_group *group, struct prefix *range)
+{
+  struct prefix *prefix;
+  struct listnode *node, *nnode;
+  afi_t afi;
+
+  afi = family2afi(range->family);
+
+  /* Group needs remote AS configured. */
+  if (! group->conf->as)
+    return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
+
+  /* Ensure no duplicates. Currently we don't care about overlaps. */
+  for (ALL_LIST_ELEMENTS (group->listen_range[afi], node, nnode, prefix))
+    {
+      if (prefix_same(range, prefix))
+        return BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS;
+    }
+
+  prefix = prefix_new();
+  prefix_copy(prefix, range);
+  listnode_add(group->listen_range[afi], prefix);
+  return 0;
+}
+
+int
+peer_group_listen_range_del (struct peer_group *group, struct prefix *range)
+{
+  struct prefix *prefix, *prefix2;
+  struct listnode *node, *nnode;
+  struct peer *peer;
+  afi_t afi;
+  char buf[SU_ADDRSTRLEN];
+
+  afi = family2afi(range->family);
+
+  /* Identify the listen range. */
+  for (ALL_LIST_ELEMENTS (group->listen_range[afi], node, nnode, prefix))
+    {
+      if (prefix_same(range, prefix))
+        break;
+    }
+
+  if (!prefix)
+    return BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND;
+
+  prefix2str(prefix, buf, sizeof(buf));
+
+  /* Dispose off any dynamic neighbors that exist due to this listen range */
+  for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+    {
+      if (!peer_dynamic_neighbor (peer))
+        continue;
+
+      prefix2 = sockunion2hostprefix(&peer->su);
+      if (prefix_match(prefix, prefix2))
+        {
+          if (bgp_debug_neighbor_events(peer))
+            zlog_debug ("Deleting dynamic neighbor %s group %s upon "
+                        "delete of listen range %s",
+                        peer->host, group->name, buf);
+          peer_delete (peer);
+        }
+    }
+
+  /* Get rid of the listen range */
+  listnode_delete(group->listen_range[afi], prefix);
+
+  return 0;
+}
+
 /* Bind specified peer to peer group.  */
 int
 peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer,
@@ -2365,6 +2484,8 @@ bgp_create (as_t *as, const char *name)
   bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
   bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
   bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
+  bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
+  bgp->dynamic_neighbors_count = 0;
 
   bgp->as = *as;
 
@@ -2660,6 +2781,189 @@ peer_lookup (struct bgp *bgp, union sockunion *su)
   return NULL;
 }
 
+struct peer *
+peer_create_bind_dynamic_neighbor (struct bgp *bgp, union sockunion *su,
+                                   struct peer_group *group)
+{
+  struct peer *peer;
+  afi_t afi;
+  safi_t safi;
+  as_t as;
+
+  /* Create peer first; we've already checked group config is valid. */
+  peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, 0, 0);
+  if (!peer)
+    return NULL;
+
+  /* Link to group */
+  peer->group = group;
+  peer = peer_lock (peer);
+  listnode_add (group->peer, peer);
+
+  /*
+   * Bind peer for all AFs configured for the group. We don't call
+   * peer_group_bind as that is sub-optimal and does some stuff we don't want.
+   */
+  for (afi = AFI_IP; afi < AFI_MAX; afi++)
+    for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+      {
+        if (!group->conf->afc[afi][safi])
+          continue;
+        peer->af_group[afi][safi] = 1;
+        peer->afc[afi][safi] = 1;
+        if (!peer_af_find(peer, afi, safi) &&
+            peer_af_create(peer, afi, safi) == NULL)
+          {
+            zlog_err("couldn't create af structure for peer %s", peer->host);
+          }
+        peer_group2peer_config_copy (group, peer, afi, safi);
+      }
+
+  /* Mark as dynamic, but also as a "config node" for other things to work. */
+  SET_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR);
+  SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
+
+  return peer;
+}
+
+struct prefix *
+peer_group_lookup_dynamic_neighbor_range (struct peer_group * group,
+                                          struct prefix * prefix)
+{
+  struct listnode *node, *nnode;
+  struct prefix *range;
+  afi_t afi;
+
+  afi = family2afi(prefix->family);
+
+  if (group->listen_range[afi])
+    for (ALL_LIST_ELEMENTS (group->listen_range[afi], node, nnode, range))
+      if (prefix_match(range, prefix))
+        return range;
+
+  return NULL;
+}
+
+struct peer_group *
+peer_group_lookup_dynamic_neighbor (struct bgp *bgp, struct prefix *prefix,
+                                    struct prefix **listen_range)
+{
+  struct prefix *range = NULL;
+  struct peer_group *group = NULL;
+  struct listnode *node, *nnode;
+
+  *listen_range = NULL;
+  if (bgp != NULL)
+    {
+      for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+        if ((range = peer_group_lookup_dynamic_neighbor_range(group, prefix)))
+          break;
+    }
+  else if (bm->bgp != NULL)
+    {
+      struct listnode *bgpnode, *nbgpnode;
+
+      for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
+        for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
+          if ((range = peer_group_lookup_dynamic_neighbor_range(group, prefix)))
+            break;
+    }
+
+  *listen_range = range;
+  return (group && range) ? group : NULL;
+}
+
+struct peer *
+peer_lookup_dynamic_neighbor (struct bgp *bgp, union sockunion *su)
+{
+  struct peer_group *group;
+  struct bgp *gbgp;
+  struct peer *peer;
+  struct prefix *prefix;
+  struct prefix *listen_range;
+  int dncount;
+  char buf[SU_ADDRSTRLEN];
+  char buf1[SU_ADDRSTRLEN];
+
+  prefix = sockunion2hostprefix(su);
+  if (!prefix)
+    return NULL;
+
+  /* See if incoming connection matches a configured listen range. */
+  group = peer_group_lookup_dynamic_neighbor (bgp, prefix, &listen_range);
+
+  if (! group)
+    return NULL;
+
+  gbgp = group->bgp;
+
+  if (! gbgp)
+    return NULL;
+
+  prefix2str(prefix, buf, sizeof(buf));
+  prefix2str(listen_range, buf1, sizeof(buf1));
+
+  if (bgp_debug_neighbor_events(NULL))
+    zlog_debug ("Dynamic Neighbor %s matches group %s listen range %s",
+                buf, group->name, buf1);
+
+  /* Are we within the listen limit? */
+  dncount = gbgp->dynamic_neighbors_count;
+
+  if (dncount >= gbgp->dynamic_neighbors_limit)
+    {
+      if (bgp_debug_neighbor_events(NULL))
+        zlog_debug ("Dynamic Neighbor %s rejected - at limit %d",
+                    inet_sutop (su, buf), gbgp->dynamic_neighbors_limit);
+      return NULL;
+    }
+
+  /* Ensure group is not disabled. */
+  if (CHECK_FLAG (group->conf->flags, PEER_FLAG_SHUTDOWN))
+    {
+      if (bgp_debug_neighbor_events(NULL))
+        zlog_debug ("Dynamic Neighbor %s rejected - group %s disabled",
+                    buf, group->name);
+      return NULL;
+    }
+
+  /* Check that at least one AF is activated for the group. */
+  if (!peer_group_af_configured (group))
+    {
+      if (bgp_debug_neighbor_events(NULL))
+        zlog_debug ("Dynamic Neighbor %s rejected - no AF activated for group %s",
+                    buf, group->name);
+      return NULL;
+    }
+
+  /* Create dynamic peer and bind to associated group. */
+  peer = peer_create_bind_dynamic_neighbor (gbgp, su, group);
+  assert (peer);
+
+  gbgp->dynamic_neighbors_count = ++dncount;
+
+  if (bgp_debug_neighbor_events(peer))
+    zlog_debug ("%s Dynamic Neighbor added, group %s count %d",
+                peer->host, group->name, dncount);
+
+  return peer;
+}
+
+void peer_drop_dynamic_neighbor (struct peer *peer)
+{
+  int dncount = -1;
+  if (peer->group && peer->group->bgp)
+    {
+      dncount = peer->group->bgp->dynamic_neighbors_count;
+      if (dncount)
+        peer->group->bgp->dynamic_neighbors_count = --dncount;
+    }
+  if (bgp_debug_neighbor_events(peer))
+    zlog_debug ("%s dropped from group %s, count %d",
+                 peer->host, peer->group->name, dncount);
+}
+
+
 /* If peer is configured at least one address family return 1. */
 int
 peer_active (struct peer *peer)
@@ -5468,6 +5772,10 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,
   char buf[SU_ADDRSTRLEN];
   char *addr;
 
+  /* Skip dynamic neighbors. */
+  if (peer_dynamic_neighbor (peer))
+    return;
+
   if (peer->conf_if)
     addr = peer->conf_if;
   else
@@ -5895,6 +6203,10 @@ bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
     }
   for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
     {
+      /* Skip dynamic neighbors. */
+      if (peer_dynamic_neighbor (peer))
+        continue;
+
       if (peer->afc[afi][safi])
        {
          if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
@@ -6125,6 +6437,9 @@ bgp_config_write (struct vty *vty)
       /* Distance configuration. */
       bgp_config_write_distance (vty, bgp);
       
+      /* listen range and limit for dynamic BGP neighbors */
+      bgp_config_write_listen (vty, bgp);
+
       /* No auto-summary */
       if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
        vty_out (vty, " no auto-summary%s", VTY_NEWLINE);
index 9863649525122f50c0f9e8ad068e0f799605f20b..8b046e597cfcb82632835a0438bb9598d91cc4fd 100644 (file)
@@ -134,6 +134,12 @@ struct bgp
   /* BGP peer group.  */
   struct list *group;
 
+  /* The maximum number of BGP dynamic neighbors that can be created */
+  int dynamic_neighbors_limit;
+
+    /* The current number of BGP dynamic neighbors */
+  int dynamic_neighbors_count;
+
   /* BGP route-server-clients. */
   struct list *rsclient;
 
@@ -302,6 +308,9 @@ struct peer_group
   /* Peer-group client list. */
   struct list *peer;
 
+  /** Dynamic neighbor listening ranges */
+  struct list *listen_range[AFI_MAX];
+
   /* Peer-group config */
   struct peer *conf;
 };
@@ -570,6 +579,7 @@ struct peer
 #define PEER_FLAG_CONFIG_NODE              (1 << 10) /* the node to update configs on */
 #define PEER_FLAG_BFD                      (1 << 11) /* bfd */
 #define PEER_FLAG_LONESOUL                  (1 << 12)
+#define PEER_FLAG_DYNAMIC_NEIGHBOR          (1 << 13) /* dynamic neighbor */
 
   /* NSF mode (graceful restart) */
   u_char nsf[AFI_MAX][SAFI_MAX];
@@ -970,6 +980,11 @@ struct bgp_nlri
 /* Check AS path loop when we send NLRI.  */
 /* #define BGP_SEND_ASPATH_CHECK */
 
+/* BGP Dynamic Neighbors feature */
+#define BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT    100
+#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN          1
+#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX       5000
+
 /* Flag for peer_clear_soft().  */
 enum bgp_clear_type
 {
@@ -1026,7 +1041,11 @@ enum bgp_clear_type
 #define BGP_ERR_NO_INTERFACE_CONFIG             -32
 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS    -33
 #define BGP_ERR_AS_OVERRIDE                     -34
-#define BGP_ERR_MAX                            -35
+#define BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT -35
+#define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS  -36
+#define BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_NOT_FOUND -37
+#define BGP_ERR_INVALID_FOR_DYNAMIC_PEER        -38
+#define BGP_ERR_MAX                             -39
 
 /*
  * Enumeration of different policy kinds a peer can be configured with.
@@ -1060,6 +1079,15 @@ extern struct peer *peer_conf_interface_get(struct bgp *, const char *, afi_t,
 extern void  bgp_peer_conf_if_to_su_update (struct peer *);
 extern struct peer_group *peer_group_lookup (struct bgp *, const char *);
 extern struct peer_group *peer_group_get (struct bgp *, const char *);
+extern struct peer *peer_create_bind_dynamic_neighbor (struct bgp *,
+                    union sockunion *, struct peer_group *);
+extern struct prefix *peer_group_lookup_dynamic_neighbor_range (
+                     struct peer_group *, struct prefix *);
+extern struct peer_group *peer_group_lookup_dynamic_neighbor (struct bgp *,
+                     struct prefix *, struct prefix **);
+extern struct peer *peer_lookup_dynamic_neighbor (struct bgp *,
+                     union sockunion *);
+extern void peer_drop_dynamic_neighbor (struct peer *);
 extern struct peer *peer_lock (struct peer *);
 extern struct peer *peer_unlock (struct peer *);
 extern bgp_peer_sort_t peer_sort (struct peer *peer);
@@ -1113,6 +1141,9 @@ extern int bgp_default_local_preference_unset (struct bgp *);
 extern int bgp_default_subgroup_pkt_queue_max_set (struct bgp *bgp, u_int32_t);
 extern int bgp_default_subgroup_pkt_queue_max_unset (struct bgp *bgp);
 
+extern int bgp_listen_limit_set (struct bgp *, int);
+extern int bgp_listen_limit_unset (struct bgp *);
+
 extern int bgp_update_delay_active (struct bgp *);
 extern int bgp_update_delay_configured (struct bgp *);
 extern int peer_rsclient_active (struct peer *);
@@ -1123,6 +1154,7 @@ extern int peer_group_remote_as (struct bgp *, const char *, as_t *);
 extern int peer_delete (struct peer *peer);
 extern int peer_group_delete (struct peer_group *);
 extern int peer_group_remote_as_delete (struct peer_group *);
+extern int peer_group_listen_range_add(struct peer_group *, struct prefix *);
 
 extern int peer_activate (struct peer *, afi_t, safi_t);
 extern int peer_deactivate (struct peer *, afi_t, safi_t);
@@ -1279,6 +1311,21 @@ peer_afi_active_nego (const struct peer *peer, afi_t afi)
   return 0;
 }
 
+/* If at least one address family activated for group, return 1. */
+static inline int
+peer_group_af_configured (struct peer_group *group)
+{
+  struct peer *peer = group->conf;
+
+  if (peer->afc[AFI_IP][SAFI_UNICAST]
+      || peer->afc[AFI_IP][SAFI_MULTICAST]
+      || peer->afc[AFI_IP][SAFI_MPLS_VPN]
+      || peer->afc[AFI_IP6][SAFI_UNICAST]
+      || peer->afc[AFI_IP6][SAFI_MULTICAST])
+    return 1;
+  return 0;
+}
+
 static inline char *
 timestamp_string (time_t ts)
 {
@@ -1299,4 +1346,10 @@ peer_established (struct peer *peer)
   return 0;
 }
 
+static inline int
+peer_dynamic_neighbor (struct peer *peer)
+{
+  return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0;
+}
+
 #endif /* _QUAGGA_BGPD_H */
index de09c7d947ef128efa3c966fe4ca29a8f8a2507b..9a548211731c7a89ed4d8d232877642e6f995e9d 100644 (file)
@@ -508,6 +508,15 @@ struct cmd_token
 #define NEIGHBOR_ADDR_STR2 "Neighbor address\nNeighbor tag\n"
 #endif /* HAVE_IPV6 */
 
+/* Dynamic neighbor (listen range) configuration */
+#ifdef HAVE_IPV6
+#define LISTEN_RANGE_CMD      "bgp listen range (A.B.C.D/M|X:X::X:X/M) "
+#define LISTEN_RANGE_ADDR_STR "Neighbor address\nNeighbor IPv6 address\n"
+#else
+#define LISTEN_RANGE_CMD      "bgp listen range A.B.C.D/M "
+#define LISTEN_RANGE_ADDR_STR "Neighbor address\n"
+#endif /* HAVE_IPV6 */
+
 /* Prototypes. */
 extern void install_node (struct cmd_node *, int (*) (struct vty *));
 extern void install_default (enum node_type);