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)
{
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));
}
/* 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;
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));
}
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;
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
/* 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);
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])
{
}
/* 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)
{
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);
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)
{
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)
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)
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]);
{
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";
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, " ");
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;
}
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;
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,
/* 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))
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. */
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);
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);
#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 */
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)
{
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)
{
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 */
peer_group_get (struct bgp *bgp, const char *name)
{
struct peer_group *group;
+ afi_t afi;
group = peer_group_lookup (bgp, name);
if (group)
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;
{
struct bgp *bgp;
struct peer *peer;
+ struct prefix *prefix;
struct peer *other;
struct listnode *node, *nnode;
+ afi_t afi;
bgp = group->bgp;
}
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;
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,
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;
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)
char buf[SU_ADDRSTRLEN];
char *addr;
+ /* Skip dynamic neighbors. */
+ if (peer_dynamic_neighbor (peer))
+ return;
+
if (peer->conf_if)
addr = peer->conf_if;
else
}
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))
/* 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);
/* 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;
/* Peer-group client list. */
struct list *peer;
+ /** Dynamic neighbor listening ranges */
+ struct list *listen_range[AFI_MAX];
+
/* Peer-group config */
struct peer *conf;
};
#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];
/* 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
{
#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.
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);
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 *);
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);
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)
{
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 */
#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);