From 706b45087289bd9186275c85ae8909d4e094d708 Mon Sep 17 00:00:00 2001 From: Sihui Han Date: Thu, 1 Jun 2017 19:26:42 +0000 Subject: [PATCH 1/6] quagga patch for dynamic neightbor --- bgpd/bgp_fsm.c | 33 +++ bgpd/bgp_network.c | 23 ++- bgpd/bgp_route.c | 4 + bgpd/bgp_vty.c | 488 ++++++++++++++++++++++++++++++++++++++++++++- bgpd/bgp_vty.h | 2 + bgpd/bgpd.c | 315 +++++++++++++++++++++++++++++ bgpd/bgpd.h | 54 +++++ lib/command.h | 10 + 8 files changed, 919 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index b8f8dd64..86c1ede7 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -439,6 +439,15 @@ bgp_stop (struct peer *peer) safi_t safi; char orf_name[BUFSIZ]; + 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) { @@ -588,6 +597,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; + } + bgp_stop (peer); return 0; @@ -609,6 +626,14 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) return -1; } + 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; @@ -656,6 +681,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; + } + bgp_stop (peer); return 0; } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 92a81296..69504c94 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -220,6 +220,7 @@ bgp_accept (struct thread *thread) peer1 = peer_lookup (NULL, &su); + /* * Close incoming connection from directly connected EBGP peers until we receive interface_up message from zebra @@ -243,14 +244,32 @@ bgp_accept (struct thread *thread) if (BGP_DEBUG (events, EVENTS)) zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf)); - + + 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; + } + } + /* Check remote IP address */ if (! peer1 || peer1->status == Idle) { if (BGP_DEBUG (events, EVENTS)) { if (! peer1) - zlog_debug ("[Event] BGP connection IP address %s is not configured", + zlog_debug ("[Event] BGP connection IP address %s rejected - not configured" + " and not valid for dynamic", inet_sutop (&su, buf)); else zlog_debug ("[Event] BGP connection IP address %s is Idle state", diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 17c3cad5..a968da72 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1769,6 +1769,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]) { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index c00d17e8..66facead 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -92,6 +92,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) { @@ -115,18 +118,27 @@ peer_lookup_vty (struct vty *vty, const char *ip_str) vty_out (vty, "%% Specify remote-as or peer-group commands first%s", 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; @@ -135,7 +147,14 @@ peer_and_group_lookup_vty (struct vty *vty, const char *peer_str) { peer = peer_lookup (bgp, &su); if (peer) - return peer; + { + if (peer_dynamic_neighbor (peer)) + { + vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s",VTY_NEWLINE); + return NULL; + } + return peer; + } } else { @@ -220,6 +239,15 @@ bgp_vty_return (struct vty *vty, int ret) case BGP_ERR_NO_IBGP_WITH_TTLHACK: str = "ttl-security only allowed for EBGP 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) { @@ -1529,7 +1557,15 @@ 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; + } + peer_delete (peer); + } } return CMD_SUCCESS; @@ -1875,6 +1911,176 @@ peer_flag_modify_vty (struct vty *vty, const char *ip_str, return bgp_vty_return (vty, ret); } +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_flag_set_vty (struct vty *vty, const char *ip_str, u_int16_t flag) { @@ -4479,6 +4685,15 @@ bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, vty_out (vty, "No BGP process is configured%s", 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; + } } return bgp_clear (vty, bgp, afi, safi, sort, stype, arg); @@ -6932,9 +7147,10 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) { 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"; @@ -6988,7 +7204,14 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) 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, " "); @@ -7556,13 +7779,17 @@ bgp_show_peer (struct vty *vty, struct peer *p) struct bgp *bgp; char buf1[BUFSIZ]; char timebuf[BGP_UPTIME_LEN]; + char dn_flag[2]; afi_t afi; safi_t safi; bgp = p->bgp; /* 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, @@ -7580,8 +7807,25 @@ 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); + 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)) @@ -7995,6 +8239,16 @@ bgp_show_neighbor_vty (struct vty *vty, const char *name, if (bgp) bgp_show_neighbor (vty, bgp, type, &su); + + 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; } @@ -8591,6 +8845,206 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary, #endif /* HAVE IPV6 */ +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. */ DEFUN (bgp_redistribute_ipv4, @@ -9250,6 +9704,14 @@ bgp_vty_init (void) install_element (BGP_NODE, &no_bgp_default_local_preference_cmd); install_element (BGP_NODE, &no_bgp_default_local_preference_val_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, &no_neighbor_cmd); @@ -10146,6 +10608,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); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 2df8aaa5..606c9bdc 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -22,8 +22,10 @@ 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_listen(struct vty *vty, struct bgp *bgp); #endif /* _QUAGGA_BGP_VTY_H */ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d72708e4..a09f8b24 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -274,6 +274,29 @@ bgp_timers_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; +} + /* BGP confederation configuration. */ int bgp_confederation_id_set (struct bgp *bgp, as_t as) @@ -980,6 +1003,13 @@ peer_remote_as (struct bgp *bgp, union sockunion *su, as_t *as, 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) { @@ -1209,6 +1239,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 */ @@ -1377,6 +1410,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) @@ -1386,6 +1420,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; @@ -1694,7 +1730,9 @@ peer_group_delete (struct peer_group *group) { struct bgp *bgp; struct peer *peer; + struct perfix *prefix; struct listnode *node, *nnode; + afi_t afi; bgp = group->bgp; @@ -1705,6 +1743,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; @@ -1740,6 +1787,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, @@ -1978,6 +2097,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; @@ -2268,6 +2389,189 @@ peer_lookup_with_open (union sockunion *su, as_t remote_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) @@ -4795,6 +5099,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; + addr = peer->host; if (peer_group_active (peer)) g_peer = peer->group->conf; @@ -5186,6 +5494,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->sflags, PEER_STATUS_ACCEPT_PEER)) @@ -5380,6 +5692,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); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 40c381c2..e634aace 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -83,6 +83,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; @@ -186,6 +192,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; }; @@ -393,6 +402,7 @@ struct peer #define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */ #define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */ #define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */ +#define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 13) /* dynamic neighbor */ /* NSF mode (graceful restart) */ u_char nsf[AFI_MAX][SAFI_MAX]; @@ -775,6 +785,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 { @@ -830,6 +845,10 @@ enum bgp_clear_type #define BGP_ERR_NO_IBGP_WITH_TTLHACK -31 #define BGP_ERR_MAX -32 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS -33 +#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 extern struct bgp_master *bm; @@ -844,6 +863,16 @@ extern int bgp_nexthop_set (union sockunion *, union sockunion *, struct bgp_nexthop *, struct peer *); extern struct bgp *bgp_get_default (void); extern struct bgp *bgp_lookup (as_t, 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 bgp *bgp_lookup_by_name (const char *); extern struct peer *peer_lookup (struct bgp *, union sockunion *); extern struct peer_group *peer_group_lookup (struct bgp *, const char *); @@ -897,6 +926,9 @@ extern int bgp_timers_unset (struct bgp *); extern int bgp_default_local_preference_set (struct bgp *, u_int32_t); extern int bgp_default_local_preference_unset (struct bgp *); +extern int bgp_listen_limit_set (struct bgp *, int); +extern int bgp_listen_limit_unset (struct bgp *); + extern int peer_rsclient_active (struct peer *); extern int peer_remote_as (struct bgp *, union sockunion *, as_t *, afi_t, safi_t); @@ -904,6 +936,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); @@ -985,4 +1018,25 @@ extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); extern int peer_ttl_security_hops_set (struct peer *, int); extern int peer_ttl_security_hops_unset (struct peer *); + +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 int +peer_dynamic_neighbor (struct peer *peer) +{ + return (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_NEIGHBOR)) ? 1 : 0; +} + #endif /* _QUAGGA_BGPD_H */ diff --git a/lib/command.h b/lib/command.h index 8eb0cbd9..5348f5d7 100644 --- a/lib/command.h +++ b/lib/command.h @@ -504,6 +504,16 @@ 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); From e336debeefbe0e8277eb95cbbb0cc4f5f15cc7cc Mon Sep 17 00:00:00 2001 From: Sihui Han Date: Fri, 9 Jun 2017 19:08:59 +0000 Subject: [PATCH 2/6] [dynamic neighbor]: support dynamic neighbor configuration --- bgpd/bgp_fsm.c | 21 ++++++++--- bgpd/bgp_vty.c | 47 +++++++++++++------------ bgpd/bgpd.c | 92 ++++++++++++++++++++++++++++++++++++++++-------- bgpd/bgpd.h | 94 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 210 insertions(+), 44 deletions(-) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 86c1ede7..fb3ac146 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -442,8 +442,10 @@ bgp_stop (struct peer *peer) 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); + if (BGP_DEBUG (events, EVENTS)) + { + zlog_debug("%s (dynamic neighbor) deleted", peer->host); + } peer_delete (peer); return -1; } @@ -599,8 +601,11 @@ bgp_stop_with_error (struct peer *peer) if (peer_dynamic_neighbor(peer)) { - if (bgp_debug_neighbor_events(peer)) + if (BGP_DEBUG (events, EVENTS)) + { zlog_debug ("%s (dynamic neighbor) deleted", peer->host); + } + peer_delete (peer); return -1; } @@ -628,8 +633,11 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) if (peer_dynamic_neighbor(peer)) { - if (bgp_debug_neighbor_events(peer)) + if (BGP_DEBUG (events, EVENTS)) + { zlog_debug ("%s (dynamic neighbor) deleted", peer->host); + } + peer_delete (peer); return -1; } @@ -683,8 +691,11 @@ bgp_connect_fail (struct peer *peer) { if (peer_dynamic_neighbor(peer)) { - if (bgp_debug_neighbor_events(peer)) + if (BGP_DEBUG (events, EVENTS)) + { zlog_debug ("%s (dynamic neighbor) deleted", peer->host); + } + peer_delete (peer); return -1; } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 66facead..73bdbe55 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -121,7 +121,7 @@ peer_lookup_vty (struct vty *vty, const char *ip_str) if (peer_dynamic_neighbor (peer)) { - vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s",VTY_NEWLINE); + vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s", VTY_NEWLINE); return NULL; } return peer; @@ -1823,6 +1823,7 @@ DEFUN (neighbor_set_peer_group, union sockunion su; struct bgp *bgp; struct peer_group *group; + struct peer *peer = NULL; bgp = vty->index; @@ -1833,10 +1834,11 @@ DEFUN (neighbor_set_peer_group, return CMD_WARNING; } - group = peer_group_lookup (bgp, argv[1]); - if (! group) + /* Disallow for dynamic neighbor. */ + peer = peer_lookup (bgp, &su); + if (peer && peer_dynamic_neighbor (peer)) { - vty_out (vty, "%% Configure the peer-group first%s", VTY_NEWLINE); + vty_out (vty, "%% Operation not allowed on a dynamic neighbor%s", VTY_NEWLINE); return CMD_WARNING; } @@ -1847,6 +1849,14 @@ DEFUN (neighbor_set_peer_group, return CMD_WARNING; } + 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_bind (bgp, &su, group, bgp_node_afi (vty), bgp_node_safi (vty), &as); @@ -4685,15 +4695,6 @@ bgp_clear_vty (struct vty *vty, const char *name, afi_t afi, safi_t safi, vty_out (vty, "No BGP process is configured%s", 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; - } } return bgp_clear (vty, bgp, afi, safi, sort, stype, arg); @@ -7256,6 +7257,16 @@ bgp_show_summary (struct vty *vty, struct bgp *bgp, int afi, int safi) else 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; } @@ -8239,16 +8250,6 @@ bgp_show_neighbor_vty (struct vty *vty, const char *name, if (bgp) bgp_show_neighbor (vty, bgp, type, &su); - - 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; } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a09f8b24..31de89bc 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -279,9 +279,9 @@ int bgp_listen_limit_set (struct bgp *bgp, int listen_limit) { if (! bgp) - return -1 + return -1; - bgp->dynamic_neighbors_limit = listen_limit + bgp->dynamic_neighbors_limit = listen_limit; return 0; } @@ -1235,6 +1235,8 @@ peer_delete (struct peer *peer) if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT)) peer_nsf_stop (peer); + SET_FLAG(peer->flags, PEER_FLAG_DELETE); + /* If this peer belongs to peer group, clear up the relationship. */ if (peer->group) @@ -1730,7 +1732,7 @@ peer_group_delete (struct peer_group *group) { struct bgp *bgp; struct peer *peer; - struct perfix *prefix; + struct prefix *prefix; struct listnode *node, *nnode; afi_t afi; @@ -1845,10 +1847,13 @@ peer_group_listen_range_del (struct peer_group *group, struct prefix *range) prefix2 = sockunion2hostprefix(&peer->su); if (prefix_match(prefix, prefix2)) { - if (bgp_debug_neighbor_events(peer)) - zlog_debug ("Deleting dynamic neighbor %s group %s upon " + if (BGP_DEBUG (events, EVENTS)) + { + zlog_debug ("Deleting dynamic neighbor %s group %s upon " "delete of listen range %s", peer->host, group->name, buf); + } + peer_delete (peer); } } @@ -2399,7 +2404,7 @@ peer_create_bind_dynamic_neighbor (struct bgp *bgp, union sockunion *su, 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); + peer = peer_create (su, bgp, bgp->as, group->conf->as, 0, 0); if (!peer) return NULL; @@ -2424,13 +2429,14 @@ peer_create_bind_dynamic_neighbor (struct bgp *bgp, union sockunion *su, { 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); - + /* currently not supported */ + /* SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); */ return peer; } @@ -2511,36 +2517,47 @@ peer_lookup_dynamic_neighbor (struct bgp *bgp, union sockunion *su) prefix2str(prefix, buf, sizeof(buf)); prefix2str(listen_range, buf1, sizeof(buf1)); - if (bgp_debug_neighbor_events(NULL)) + if (BGP_DEBUG (events, EVENTS)) + { 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)) + if (BGP_DEBUG (events, EVENTS)) + { 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)) + if (BGP_DEBUG (events, EVENTS)) + { 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)) + if (BGP_DEBUG (events, EVENTS)) + { zlog_debug ("Dynamic Neighbor %s rejected - no AF activated for group %s", buf, group->name); + } + return NULL; } @@ -2550,9 +2567,11 @@ peer_lookup_dynamic_neighbor (struct bgp *bgp, union sockunion *su) gbgp->dynamic_neighbors_count = ++dncount; - if (bgp_debug_neighbor_events(peer)) + if (BGP_DEBUG (events, EVENTS)) + { zlog_debug ("%s Dynamic Neighbor added, group %s count %d", peer->host, group->name, dncount); + } return peer; } @@ -2566,9 +2585,12 @@ void peer_drop_dynamic_neighbor (struct peer *peer) if (dncount) peer->group->bgp->dynamic_neighbors_count = --dncount; } - if (bgp_debug_neighbor_events(peer)) + + if (BGP_DEBUG (events, EVENTS)) + { zlog_debug ("%s dropped from group %s, count %d", peer->host, peer->group->name, dncount); + } } @@ -2883,6 +2905,48 @@ peer_is_group_member (struct peer *peer, afi_t afi, safi_t safi) return 0; } +struct peer_af * +peer_af_create (struct peer *peer, afi_t afi, safi_t safi) +{ + struct peer_af *af; + int afid; + + if (!peer) + return NULL; + + afid = afindex(afi, safi); + if (afid >= BGP_AF_MAX) + return NULL; + + assert(peer->peer_af_array[afid] == NULL); + + /* Allocate new peer af */ + af = XCALLOC (MTYPE_BGP_PEER_AF, sizeof (struct peer_af)); + peer->peer_af_array[afid] = af; + af->afi = afi; + af->safi = safi; + af->afid = afid; + af->peer = peer; + + //update_group_adjust_peer(af); + return af; +} + +struct peer_af * +peer_af_find (struct peer *peer, afi_t afi, safi_t safi) +{ + int afid; + + if (!peer) + return NULL; + + afid = afindex(afi, safi); + if (afid >= BGP_AF_MAX) + return NULL; + + return peer->peer_af_array[afid]; +} + static int peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag, int set) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index e634aace..23da8f96 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -23,6 +23,7 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA /* For union sockunion. */ #include "sockunion.h" +#include "openbsd-queue.h" /* Typedef BGP specific types. */ typedef u_int32_t as_t; @@ -62,6 +63,50 @@ struct bgp_master #define BGP_OPT_NO_LISTEN (1 << 3) }; +enum bgp_af_index +{ + BGP_AF_START, + BGP_AF_IPV4_UNICAST = BGP_AF_START, + BGP_AF_IPV4_MULTICAST, + BGP_AF_IPV4_VPN, + BGP_AF_IPV6_UNICAST, + BGP_AF_IPV6_MULTICAST, + BGP_AF_IPV6_VPN, + BGP_AF_IPV4_ENCAP, + BGP_AF_IPV6_ENCAP, + BGP_AF_L2VPN_EVPN, + BGP_AF_IPV4_LBL_UNICAST, + BGP_AF_IPV6_LBL_UNICAST, + BGP_AF_MAX +}; + +struct peer_af +{ + /* back pointer to the peer */ + struct peer *peer; + + /* which subgroup the peer_af belongs to */ + struct update_subgroup *subgroup; + + /* for being part of an update subgroup's peer list */ + LIST_ENTRY(peer_af) subgrp_train; + + /* for being part of a packet's peer list */ + LIST_ENTRY(peer_af) pkt_train; + + struct bpacket *next_pkt_to_send; + + /* + * Trigger timer for bgp_announce_route(). + */ + struct thread *t_announce_route; + + afi_t afi; + safi_t safi; + int afid; +}; + + /* BGP instance structure. */ struct bgp { @@ -299,6 +344,9 @@ struct peer struct peer_group *group; u_char af_group[AFI_MAX][SAFI_MAX]; + /* BGP peer_af structures, per configured AF on this peer */ + struct peer_af *peer_af_array[BGP_AF_MAX]; + /* Peer's remote AS number. */ as_t as; @@ -402,7 +450,8 @@ struct peer #define PEER_FLAG_DISABLE_CONNECTED_CHECK (1 << 6) /* disable-connected-check */ #define PEER_FLAG_LOCAL_AS_NO_PREPEND (1 << 7) /* local-as no-prepend */ #define PEER_FLAG_LOCAL_AS_REPLACE_AS (1 << 8) /* local-as no-prepend replace-as */ -#define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 13) /* dynamic neighbor */ +#define PEER_FLAG_DELETE (1 << 9) /* mark the peer for deleting */ +#define PEER_FLAG_DYNAMIC_NEIGHBOR (1 << 10) /* dynamic neighbor */ /* NSF mode (graceful restart) */ u_char nsf[AFI_MAX][SAFI_MAX]; @@ -949,6 +998,9 @@ extern int peer_group_unbind (struct bgp *, struct peer *, struct peer_group *, extern int peer_flag_set (struct peer *, u_int32_t); extern int peer_flag_unset (struct peer *, u_int32_t); +extern struct peer_af * peer_af_create (struct peer *, afi_t, safi_t); +extern struct peer_af * peer_af_find (struct peer *, afi_t, safi_t); + extern int peer_af_flag_set (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_unset (struct peer *, afi_t, safi_t, u_int32_t); extern int peer_af_flag_check (struct peer *, afi_t, safi_t, u_int32_t); @@ -1018,7 +1070,6 @@ extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type); extern int peer_ttl_security_hops_set (struct peer *, int); extern int peer_ttl_security_hops_unset (struct peer *); - static inline int peer_group_af_configured (struct peer_group *group) { @@ -1033,6 +1084,45 @@ peer_group_af_configured (struct peer_group *group) return 0; } +static inline int +afindex (afi_t afi, safi_t safi) +{ + switch (afi) + { + case AFI_IP: + switch (safi) + { + case SAFI_UNICAST: + return BGP_AF_IPV4_UNICAST; + break; + case SAFI_MULTICAST: + return BGP_AF_IPV4_MULTICAST; + break; + case SAFI_MPLS_VPN: + return BGP_AF_IPV4_VPN; + break; + default: + return BGP_AF_MAX; + break; + } + break; + case AFI_IP6: + switch (safi) + { + case SAFI_UNICAST: + return BGP_AF_IPV6_UNICAST; + break; + case SAFI_MULTICAST: + return BGP_AF_IPV6_MULTICAST; + break; + default: + return BGP_AF_MAX; + break; + } + } +} + + static inline int peer_dynamic_neighbor (struct peer *peer) { From 0461308bb1051dfd5a87ae85ab081f7119f3cfdc Mon Sep 17 00:00:00 2001 From: Sihui Han Date: Mon, 12 Jun 2017 18:18:16 +0000 Subject: [PATCH 3/6] update according to comments --- bgpd/bgp_fsm.c | 8 +- bgpd/bgp_network.c | 1 - lib/openbsd-queue.h | 533 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 537 insertions(+), 5 deletions(-) create mode 100644 lib/openbsd-queue.h diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index fb3ac146..79ccf5df 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -444,7 +444,7 @@ bgp_stop (struct peer *peer) { if (BGP_DEBUG (events, EVENTS)) { - zlog_debug("%s (dynamic neighbor) deleted", peer->host); + zlog_debug("BGP stop: %s (dynamic neighbor) deleted", peer->host); } peer_delete (peer); return -1; @@ -603,7 +603,7 @@ bgp_stop_with_error (struct peer *peer) { if (BGP_DEBUG (events, EVENTS)) { - zlog_debug ("%s (dynamic neighbor) deleted", peer->host); + zlog_debug ("BGP stop with error: %s (dynamic neighbor) deleted", peer->host); } peer_delete (peer); @@ -635,7 +635,7 @@ bgp_stop_with_notify (struct peer *peer, u_char code, u_char sub_code) { if (BGP_DEBUG (events, EVENTS)) { - zlog_debug ("%s (dynamic neighbor) deleted", peer->host); + zlog_debug ("BGP stop with notify: %s (dynamic neighbor) deleted", peer->host); } peer_delete (peer); @@ -693,7 +693,7 @@ bgp_connect_fail (struct peer *peer) { if (BGP_DEBUG (events, EVENTS)) { - zlog_debug ("%s (dynamic neighbor) deleted", peer->host); + zlog_debug ("BGP connection fail: %s (dynamic neighbor) deleted", peer->host); } peer_delete (peer); diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 69504c94..02ec4535 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -220,7 +220,6 @@ bgp_accept (struct thread *thread) peer1 = peer_lookup (NULL, &su); - /* * Close incoming connection from directly connected EBGP peers until we receive interface_up message from zebra diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h new file mode 100644 index 00000000..5e81fdd1 --- /dev/null +++ b/lib/openbsd-queue.h @@ -0,0 +1,533 @@ +/* $OpenBSD: queue.h,v 1.43 2015/12/28 19:38:40 millert Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues and XOR simple queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * An XOR simple queue is used in the same way as a regular simple queue. + * The difference is that the head structure also includes a "cookie" that + * is XOR'd with the queue pointer (first, last or next) to generate the + * real pointer value. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC)) +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST(head); \ + (var) && ((tvar) = SLIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_AFTER(elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ + _Q_INVALIDATE((elm)->field.sle_next); \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods. + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST(head); \ + (var) && ((tvar) = LIST_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SIMPLEQ_FIRST(head); \ + (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \ + (var) = (tvar)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_CONCAT(head1, head2) do { \ + if (!SIMPLEQ_EMPTY((head2))) { \ + *(head1)->sqh_last = (head2)->sqh_first; \ + (head1)->sqh_last = (head2)->sqh_last; \ + SIMPLEQ_INIT((head2)); \ + } \ +} while (0) + +/* + * XOR Simple queue definitions. + */ +#define XSIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqx_first; /* first element */ \ + struct type **sqx_last; /* addr of last next element */ \ + unsigned long sqx_cookie; \ +} + +#define XSIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqx_next; /* next element */ \ +} + +/* + * XOR Simple queue access methods. + */ +#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \ + (unsigned long)(ptr))) +#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first)) +#define XSIMPLEQ_END(head) NULL +#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head)) +#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next)) + + +#define XSIMPLEQ_FOREACH(var, head, field) \ + for ((var) = XSIMPLEQ_FIRST(head); \ + (var) != XSIMPLEQ_END(head); \ + (var) = XSIMPLEQ_NEXT(head, var, field)) + +#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = XSIMPLEQ_FIRST(head); \ + (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \ + (var) = (tvar)) + +/* + * XOR Simple queue functions. + */ +#define XSIMPLEQ_INIT(head) do { \ + arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \ + (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ +} while (0) + +#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqx_next = (head)->sqx_first) == \ + XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ + (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \ +} while (0) + +#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \ + *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ +} while (0) + +#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \ + XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ + (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \ +} while (0) + +#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqx_first = XSIMPLEQ_XOR(head, \ + (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \ +} while (0) + +#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \ + (elm)->field.sqx_next)->field.sqx_next) \ + == XSIMPLEQ_XOR(head, NULL)) \ + (head)->sqx_last = \ + XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \ +} while (0) + + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue access methods. + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ From 19f3be25b961c54a093d5df098cec037cf8dcaa9 Mon Sep 17 00:00:00 2001 From: Sihui Han Date: Mon, 12 Jun 2017 20:11:34 +0000 Subject: [PATCH 4/6] Add mtype definition --- lib/memtypes.c | 1 + lib/memtypes.h | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/memtypes.c b/lib/memtypes.c index 1a0c11fe..9eef4bba 100644 --- a/lib/memtypes.c +++ b/lib/memtypes.c @@ -93,6 +93,7 @@ struct memory_list memory_list_bgp[] = { MTYPE_BGP_LISTENER, "BGP listen socket details" }, { MTYPE_BGP_PEER, "BGP peer" }, { MTYPE_BGP_PEER_HOST, "BGP peer hostname" }, + { MTYPE_BGP_PEER_AF, "BGP peer af" }, { MTYPE_PEER_GROUP, "Peer group" }, { MTYPE_PEER_DESC, "Peer description" }, { MTYPE_PEER_PASSWORD, "Peer password string" }, diff --git a/lib/memtypes.h b/lib/memtypes.h index be0519a5..0da48def 100644 --- a/lib/memtypes.h +++ b/lib/memtypes.h @@ -77,6 +77,7 @@ enum MTYPE_BGP_LISTENER, MTYPE_BGP_PEER, MTYPE_BGP_PEER_HOST, + MTYPE_BGP_PEER_AF, MTYPE_PEER_GROUP, MTYPE_PEER_DESC, MTYPE_PEER_PASSWORD, From fa8d8946479da1f24a1448b2c2647b8327f84e2a Mon Sep 17 00:00:00 2001 From: Sihui Han Date: Wed, 14 Jun 2017 20:59:13 +0000 Subject: [PATCH 5/6] add additional patched --- bgpd/bgp_vty.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++- bgpd/bgpd.c | 6 ++++-- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 73bdbe55..d453d6e0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -52,6 +52,9 @@ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA extern struct in_addr router_id_zebra; +static struct peer_group * +listen_range_exists (struct bgp *bgp, struct prefix *range, int exact); + /* Utility function to get address family from current node. */ afi_t bgp_node_afi (struct vty *vty) @@ -1959,6 +1962,38 @@ DEFUN (no_bgp_listen_limit, } +/* + * Check if this listen range is already configured. Check for exact + * match or overlap based on input. + */ +static struct peer_group * +listen_range_exists (struct bgp *bgp, struct prefix *range, int exact) +{ + struct listnode *node, *nnode; + struct listnode *node1, *nnode1; + struct peer_group *group; + struct prefix *lr; + afi_t afi; + int match; + + afi = family2afi(range->family); + for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group)) + { + for (ALL_LIST_ELEMENTS (group->listen_range[afi], node1, + nnode1, lr)) + { + if (exact) + match = prefix_same (range, lr); + else + match = (prefix_match (range, lr) || prefix_match (lr, range)); + if (match) + return group; + } + } + + return NULL; +} + DEFUN (bgp_listen_range, bgp_listen_range_cmd, LISTEN_RANGE_CMD "peer-group WORD" , @@ -1969,7 +2004,7 @@ DEFUN (bgp_listen_range, { struct bgp *bgp; struct prefix range; - struct peer_group *group; + struct peer_group *group, *existing_group; afi_t afi; int ret; @@ -1998,6 +2033,27 @@ DEFUN (bgp_listen_range, apply_mask (&range); + /* Check if same listen range is already configured. */ + existing_group = listen_range_exists (bgp, &range, 1); + if (existing_group) + { + if (strcmp (existing_group->name, argv[1]) == 0) + return CMD_SUCCESS; + else + { + vty_out (vty, "%% Same listen range is attached to peer-group %s%s", + existing_group->name, VTY_NEWLINE); + return CMD_WARNING; + } + } + + /* Check if an overlapping listen range exists. */ + if (listen_range_exists (bgp, &range, 0)) + { + vty_out (vty, "%% Listen range overlaps with existing listen range%s", + VTY_NEWLINE); + return CMD_WARNING; + } group = peer_group_lookup (bgp, argv[1]); if (! group) diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 31de89bc..d922085f 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1802,11 +1802,12 @@ peer_group_listen_range_add (struct peer_group *group, struct prefix *range) 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; + return 0; } prefix = prefix_new(); @@ -2480,9 +2481,10 @@ peer_group_lookup_dynamic_neighbor (struct bgp *bgp, struct prefix *prefix, 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; + goto found_range; } + found_range: *listen_range = range; return (group && range) ? group : NULL; } From c21cb3925d8ebc019836733114ee000c2147b894 Mon Sep 17 00:00:00 2001 From: Sihui Han Date: Wed, 14 Jun 2017 21:05:07 +0000 Subject: [PATCH 6/6] rm extra space --- bgpd/bgp_vty.c | 2 -- bgpd/bgpd.c | 1 - 2 files changed, 3 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index d453d6e0..c1eea3e8 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1859,7 +1859,6 @@ DEFUN (neighbor_set_peer_group, return CMD_WARNING; } - ret = peer_group_bind (bgp, &su, group, bgp_node_afi (vty), bgp_node_safi (vty), &as); @@ -1961,7 +1960,6 @@ DEFUN (no_bgp_listen_limit, return CMD_SUCCESS; } - /* * Check if this listen range is already configured. Check for exact * match or overlap based on input. diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index d922085f..a9e1f662 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1802,7 +1802,6 @@ peer_group_listen_range_add (struct peer_group *group, struct prefix *range) 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)) {