unsigned int multipath_num = MULTIPATH_NUM;
-static void bgp_if_finish (struct bgp *bgp);
+static void bgp_if_finish(struct bgp *bgp);
extern struct zclient *zclient;
-void
-bgp_session_reset(struct peer *peer)
+void bgp_session_reset(struct peer *peer)
{
- if (peer->doppelganger && (peer->doppelganger->status != Deleted)
- && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
- peer_delete(peer->doppelganger);
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted)
+ && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
- BGP_EVENT_ADD (peer, BGP_Stop);
+ BGP_EVENT_ADD(peer, BGP_Stop);
}
/*
* during walk of peer list, we would end up accessing the freed next
* node. This function moves the next node along.
*/
-static void
-bgp_session_reset_safe(struct peer *peer, struct listnode **nnode)
+static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode)
{
- struct listnode *n;
- struct peer *npeer;
+ struct listnode *n;
+ struct peer *npeer;
- n = (nnode) ? *nnode : NULL;
- npeer = (n) ? listgetdata(n) : NULL;
+ n = (nnode) ? *nnode : NULL;
+ npeer = (n) ? listgetdata(n) : NULL;
- if (peer->doppelganger && (peer->doppelganger->status != Deleted)
- && !(CHECK_FLAG(peer->doppelganger->flags, PEER_FLAG_CONFIG_NODE)))
- {
- if (peer->doppelganger == npeer)
- /* nnode and *nnode are confirmed to be non-NULL here */
- *nnode = (*nnode)->next;
- peer_delete(peer->doppelganger);
- }
+ if (peer->doppelganger && (peer->doppelganger->status != Deleted)
+ && !(CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE))) {
+ if (peer->doppelganger == npeer)
+ /* nnode and *nnode are confirmed to be non-NULL here */
+ *nnode = (*nnode)->next;
+ peer_delete(peer->doppelganger);
+ }
- BGP_EVENT_ADD (peer, BGP_Stop);
+ BGP_EVENT_ADD(peer, BGP_Stop);
}
/* BGP global flag manipulation. */
-int
-bgp_option_set (int flag)
-{
- switch (flag)
- {
- case BGP_OPT_NO_FIB:
- case BGP_OPT_MULTIPLE_INSTANCE:
- case BGP_OPT_CONFIG_CISCO:
- case BGP_OPT_NO_LISTEN:
- SET_FLAG (bm->options, flag);
- break;
- default:
- return BGP_ERR_INVALID_FLAG;
- }
- return 0;
-}
-
-int
-bgp_option_unset (int flag)
-{
- switch (flag)
- {
- case BGP_OPT_MULTIPLE_INSTANCE:
- if (listcount (bm->bgp) > 1)
- return BGP_ERR_MULTIPLE_INSTANCE_USED;
- /* Fall through. */
- case BGP_OPT_NO_FIB:
- case BGP_OPT_CONFIG_CISCO:
- UNSET_FLAG (bm->options, flag);
- break;
- default:
- return BGP_ERR_INVALID_FLAG;
- }
- return 0;
-}
-
-int
-bgp_option_check (int flag)
-{
- return CHECK_FLAG (bm->options, flag);
+int bgp_option_set(int flag)
+{
+ switch (flag) {
+ case BGP_OPT_NO_FIB:
+ case BGP_OPT_MULTIPLE_INSTANCE:
+ case BGP_OPT_CONFIG_CISCO:
+ case BGP_OPT_NO_LISTEN:
+ SET_FLAG(bm->options, flag);
+ break;
+ default:
+ return BGP_ERR_INVALID_FLAG;
+ }
+ return 0;
+}
+
+int bgp_option_unset(int flag)
+{
+ switch (flag) {
+ case BGP_OPT_MULTIPLE_INSTANCE:
+ if (listcount(bm->bgp) > 1)
+ return BGP_ERR_MULTIPLE_INSTANCE_USED;
+ /* Fall through. */
+ case BGP_OPT_NO_FIB:
+ case BGP_OPT_CONFIG_CISCO:
+ UNSET_FLAG(bm->options, flag);
+ break;
+ default:
+ return BGP_ERR_INVALID_FLAG;
+ }
+ return 0;
+}
+
+int bgp_option_check(int flag)
+{
+ return CHECK_FLAG(bm->options, flag);
}
/* BGP flag manipulation. */
-int
-bgp_flag_set (struct bgp *bgp, int flag)
+int bgp_flag_set(struct bgp *bgp, int flag)
{
- SET_FLAG (bgp->flags, flag);
- return 0;
+ SET_FLAG(bgp->flags, flag);
+ return 0;
}
-int
-bgp_flag_unset (struct bgp *bgp, int flag)
+int bgp_flag_unset(struct bgp *bgp, int flag)
{
- UNSET_FLAG (bgp->flags, flag);
- return 0;
+ UNSET_FLAG(bgp->flags, flag);
+ return 0;
}
-int
-bgp_flag_check (struct bgp *bgp, int flag)
+int bgp_flag_check(struct bgp *bgp, int flag)
{
- return CHECK_FLAG (bgp->flags, flag);
+ return CHECK_FLAG(bgp->flags, flag);
}
/* Internal function to set BGP structure configureation flag. */
-static void
-bgp_config_set (struct bgp *bgp, int config)
+static void bgp_config_set(struct bgp *bgp, int config)
{
- SET_FLAG (bgp->config, config);
+ SET_FLAG(bgp->config, config);
}
-static void
-bgp_config_unset (struct bgp *bgp, int config)
+static void bgp_config_unset(struct bgp *bgp, int config)
{
- UNSET_FLAG (bgp->config, config);
+ UNSET_FLAG(bgp->config, config);
}
-static int
-bgp_config_check (struct bgp *bgp, int config)
+static int bgp_config_check(struct bgp *bgp, int config)
{
- return CHECK_FLAG (bgp->config, config);
+ return CHECK_FLAG(bgp->config, config);
}
/* Set BGP router identifier. */
-static int
-bgp_router_id_set (struct bgp *bgp, const struct in_addr *id)
+static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id)
{
- struct peer *peer;
- struct listnode *node, *nnode;
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ if (IPV4_ADDR_SAME(&bgp->router_id, id))
+ return 0;
+
+ /* EVPN uses router id in RD, withdraw them */
+ if (bgp->advertise_all_vni)
+ bgp_evpn_handle_router_id_update(bgp, TRUE);
+
+ IPV4_ADDR_COPY(&bgp->router_id, id);
- if (IPV4_ADDR_SAME (&bgp->router_id, id))
- return 0;
+ /* Set all peer's local identifier with this value. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ IPV4_ADDR_COPY(&peer->local_id, id);
- IPV4_ADDR_COPY (&bgp->router_id, id);
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_RID_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ }
- /* Set all peer's local identifier with this value. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- IPV4_ADDR_COPY (&peer->local_id, id);
+ /* EVPN uses router id in RD, update them */
+ if (bgp->advertise_all_vni)
+ bgp_evpn_handle_router_id_update(bgp, FALSE);
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_RID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- return 0;
+ return 0;
}
-void
-bgp_router_id_zebra_bump (vrf_id_t vrf_id, const struct prefix *router_id)
+void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id)
{
- struct listnode *node, *nnode;
- struct bgp *bgp;
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
- if (vrf_id == VRF_DEFAULT)
- {
- /* Router-id change for default VRF has to also update all views. */
- for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
- {
- if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- continue;
+ if (vrf_id == VRF_DEFAULT) {
+ /* Router-id change for default VRF has to also update all
+ * views. */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ continue;
- bgp->router_id_zebra = router_id->u.prefix4;
- if (!bgp->router_id_static.s_addr)
- bgp_router_id_set (bgp, &router_id->u.prefix4);
- }
- }
- else
- {
- bgp = bgp_lookup_by_vrf_id (vrf_id);
- if (bgp)
- {
- bgp->router_id_zebra = router_id->u.prefix4;
+ bgp->router_id_zebra = router_id->u.prefix4;
+ if (!bgp->router_id_static.s_addr)
+ bgp_router_id_set(bgp, &router_id->u.prefix4);
+ }
+ } else {
+ bgp = bgp_lookup_by_vrf_id(vrf_id);
+ if (bgp) {
+ bgp->router_id_zebra = router_id->u.prefix4;
- if (!bgp->router_id_static.s_addr)
- bgp_router_id_set (bgp, &router_id->u.prefix4);
- }
- }
+ if (!bgp->router_id_static.s_addr)
+ bgp_router_id_set(bgp, &router_id->u.prefix4);
+ }
+ }
}
-int
-bgp_router_id_static_set (struct bgp *bgp, struct in_addr id)
+int bgp_router_id_static_set(struct bgp *bgp, struct in_addr id)
{
- bgp->router_id_static = id;
- bgp_router_id_set (bgp, id.s_addr ? &id : &bgp->router_id_zebra);
- return 0;
+ bgp->router_id_static = id;
+ bgp_router_id_set(bgp, id.s_addr ? &id : &bgp->router_id_zebra);
+ return 0;
}
/* BGP's cluster-id control. */
-int
-bgp_cluster_id_set (struct bgp *bgp, struct in_addr *cluster_id)
+int bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id)
{
- struct peer *peer;
- struct listnode *node, *nnode;
+ struct peer *peer;
+ struct listnode *node, *nnode;
- if (bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID)
- && IPV4_ADDR_SAME (&bgp->cluster_id, cluster_id))
- return 0;
+ if (bgp_config_check(bgp, BGP_CONFIG_CLUSTER_ID)
+ && IPV4_ADDR_SAME(&bgp->cluster_id, cluster_id))
+ return 0;
- IPV4_ADDR_COPY (&bgp->cluster_id, cluster_id);
- bgp_config_set (bgp, BGP_CONFIG_CLUSTER_ID);
+ IPV4_ADDR_COPY(&bgp->cluster_id, cluster_id);
+ bgp_config_set(bgp, BGP_CONFIG_CLUSTER_ID);
- /* Clear all IBGP peer. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (peer->sort != BGP_PEER_IBGP)
- continue;
+ /* Clear all IBGP peer. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (peer->sort != BGP_PEER_IBGP)
+ continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CLID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- return 0;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_CLID_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ }
+ return 0;
}
-int
-bgp_cluster_id_unset (struct bgp *bgp)
+int bgp_cluster_id_unset(struct bgp *bgp)
{
- struct peer *peer;
- struct listnode *node, *nnode;
+ struct peer *peer;
+ struct listnode *node, *nnode;
- if (! bgp_config_check (bgp, BGP_CONFIG_CLUSTER_ID))
- return 0;
+ if (!bgp_config_check(bgp, BGP_CONFIG_CLUSTER_ID))
+ return 0;
- bgp->cluster_id.s_addr = 0;
- bgp_config_unset (bgp, BGP_CONFIG_CLUSTER_ID);
+ bgp->cluster_id.s_addr = 0;
+ bgp_config_unset(bgp, BGP_CONFIG_CLUSTER_ID);
- /* Clear all IBGP peer. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (peer->sort != BGP_PEER_IBGP)
- continue;
+ /* Clear all IBGP peer. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (peer->sort != BGP_PEER_IBGP)
+ continue;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CLID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- return 0;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_CLID_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ }
+ return 0;
}
/* time_t value that is monotonicly increasing
* and uneffected by adjustments to system clock
*/
-time_t bgp_clock (void)
+time_t bgp_clock(void)
{
- struct timeval tv;
+ struct timeval tv;
- monotime(&tv);
- return tv.tv_sec;
+ monotime(&tv);
+ return tv.tv_sec;
}
/* BGP timer configuration. */
-int
-bgp_timers_set (struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime)
+int bgp_timers_set(struct bgp *bgp, u_int32_t keepalive, u_int32_t holdtime)
{
- bgp->default_keepalive = (keepalive < holdtime / 3
- ? keepalive : holdtime / 3);
- bgp->default_holdtime = holdtime;
+ bgp->default_keepalive =
+ (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
+ bgp->default_holdtime = holdtime;
- return 0;
+ return 0;
}
-int
-bgp_timers_unset (struct bgp *bgp)
+int bgp_timers_unset(struct bgp *bgp)
{
- bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
- bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
+ bgp->default_keepalive = BGP_DEFAULT_KEEPALIVE;
+ bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
- return 0;
+ return 0;
}
/* BGP confederation configuration. */
-int
-bgp_confederation_id_set (struct bgp *bgp, as_t as)
-{
- struct peer *peer;
- struct listnode *node, *nnode;
- int already_confed;
-
- if (as == 0)
- return BGP_ERR_INVALID_AS;
-
- /* Remember - were we doing confederation before? */
- already_confed = bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION);
- bgp->confed_id = as;
- bgp_config_set (bgp, BGP_CONFIG_CONFEDERATION);
-
- /* If we were doing confederation already, this is just an external
- AS change. Just Reset EBGP sessions, not CONFED sessions. If we
- were not doing confederation before, reset all EBGP sessions. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- /* We're looking for peers who's AS is not local or part of our
- confederation. */
- if (already_confed)
- {
- if (peer_sort (peer) == BGP_PEER_EBGP)
- {
- peer->local_as = as;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset_safe(peer, &nnode);
- }
- }
- else
- {
- /* Not doign confederation before, so reset every non-local
- session */
- if (peer_sort (peer) != BGP_PEER_IBGP)
- {
- /* Reset the local_as to be our EBGP one */
- if (peer_sort (peer) == BGP_PEER_EBGP)
- peer->local_as = as;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset_safe(peer, &nnode);
- }
- }
- }
- return 0;
-}
-
-int
-bgp_confederation_id_unset (struct bgp *bgp)
-{
- struct peer *peer;
- struct listnode *node, *nnode;
-
- bgp->confed_id = 0;
- bgp_config_unset (bgp, BGP_CONFIG_CONFEDERATION);
-
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- /* We're looking for peers who's AS is not local */
- if (peer_sort (peer) != BGP_PEER_IBGP)
- {
- peer->local_as = bgp->as;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
-
- else
- bgp_session_reset_safe(peer, &nnode);
+int bgp_confederation_id_set(struct bgp *bgp, as_t as)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+ int already_confed;
+
+ if (as == 0)
+ return BGP_ERR_INVALID_AS;
+
+ /* Remember - were we doing confederation before? */
+ already_confed = bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION);
+ bgp->confed_id = as;
+ bgp_config_set(bgp, BGP_CONFIG_CONFEDERATION);
+
+ /* If we were doing confederation already, this is just an external
+ AS change. Just Reset EBGP sessions, not CONFED sessions. If we
+ were not doing confederation before, reset all EBGP sessions. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ /* We're looking for peers who's AS is not local or part of our
+ confederation. */
+ if (already_confed) {
+ if (peer_sort(peer) == BGP_PEER_EBGP) {
+ peer->local_as = as;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(
+ peer->status)) {
+ peer->last_reset =
+ PEER_DOWN_CONFED_ID_CHANGE;
+ bgp_notify_send(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset_safe(peer, &nnode);
+ }
+ } else {
+ /* Not doign confederation before, so reset every
+ non-local
+ session */
+ if (peer_sort(peer) != BGP_PEER_IBGP) {
+ /* Reset the local_as to be our EBGP one */
+ if (peer_sort(peer) == BGP_PEER_EBGP)
+ peer->local_as = as;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(
+ peer->status)) {
+ peer->last_reset =
+ PEER_DOWN_CONFED_ID_CHANGE;
+ bgp_notify_send(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset_safe(peer, &nnode);
+ }
+ }
}
- }
- return 0;
+ return 0;
}
-/* Is an AS part of the confed or not? */
-int
-bgp_confederation_peers_check (struct bgp *bgp, as_t as)
+int bgp_confederation_id_unset(struct bgp *bgp)
{
- int i;
+ struct peer *peer;
+ struct listnode *node, *nnode;
- if (! bgp)
- return 0;
+ bgp->confed_id = 0;
+ bgp_config_unset(bgp, BGP_CONFIG_CONFEDERATION);
- for (i = 0; i < bgp->confed_peers_cnt; i++)
- if (bgp->confed_peers[i] == as)
- return 1;
-
- return 0;
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ /* We're looking for peers who's AS is not local */
+ if (peer_sort(peer) != BGP_PEER_IBGP) {
+ peer->local_as = bgp->as;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+
+ else
+ bgp_session_reset_safe(peer, &nnode);
+ }
+ }
+ return 0;
}
-/* Add an AS to the confederation set. */
-int
-bgp_confederation_peers_add (struct bgp *bgp, as_t as)
+/* Is an AS part of the confed or not? */
+int bgp_confederation_peers_check(struct bgp *bgp, as_t as)
{
- struct peer *peer;
- struct listnode *node, *nnode;
+ int i;
- if (! bgp)
- return BGP_ERR_INVALID_BGP;
+ if (!bgp)
+ return 0;
- if (bgp->as == as)
- return BGP_ERR_INVALID_AS;
+ for (i = 0; i < bgp->confed_peers_cnt; i++)
+ if (bgp->confed_peers[i] == as)
+ return 1;
- if (bgp_confederation_peers_check (bgp, as))
- return -1;
-
- if (bgp->confed_peers)
- bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST,
- bgp->confed_peers,
- (bgp->confed_peers_cnt + 1) * sizeof (as_t));
- else
- bgp->confed_peers = XMALLOC (MTYPE_BGP_CONFED_LIST,
- (bgp->confed_peers_cnt + 1) * sizeof (as_t));
-
- bgp->confed_peers[bgp->confed_peers_cnt] = as;
- bgp->confed_peers_cnt++;
+ return 0;
+}
- if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION))
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (peer->as == as)
- {
- peer->local_as = bgp->as;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset_safe(peer, &nnode);
- }
- }
- }
- return 0;
+/* Add an AS to the confederation set. */
+int bgp_confederation_peers_add(struct bgp *bgp, as_t as)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ if (!bgp)
+ return BGP_ERR_INVALID_BGP;
+
+ if (bgp->as == as)
+ return BGP_ERR_INVALID_AS;
+
+ if (bgp_confederation_peers_check(bgp, as))
+ return -1;
+
+ if (bgp->confed_peers)
+ bgp->confed_peers =
+ XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+ (bgp->confed_peers_cnt + 1) * sizeof(as_t));
+ else
+ bgp->confed_peers =
+ XMALLOC(MTYPE_BGP_CONFED_LIST,
+ (bgp->confed_peers_cnt + 1) * sizeof(as_t));
+
+ bgp->confed_peers[bgp->confed_peers_cnt] = as;
+ bgp->confed_peers_cnt++;
+
+ if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (peer->as == as) {
+ peer->local_as = bgp->as;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(
+ peer->status)) {
+ peer->last_reset =
+ PEER_DOWN_CONFED_PEER_CHANGE;
+ bgp_notify_send(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset_safe(peer, &nnode);
+ }
+ }
+ }
+ return 0;
}
/* Delete an AS from the confederation set. */
-int
-bgp_confederation_peers_remove (struct bgp *bgp, as_t as)
-{
- int i;
- int j;
- struct peer *peer;
- struct listnode *node, *nnode;
-
- if (! bgp)
- return -1;
-
- if (! bgp_confederation_peers_check (bgp, as))
- return -1;
-
- for (i = 0; i < bgp->confed_peers_cnt; i++)
- if (bgp->confed_peers[i] == as)
- for(j = i + 1; j < bgp->confed_peers_cnt; j++)
- bgp->confed_peers[j - 1] = bgp->confed_peers[j];
-
- bgp->confed_peers_cnt--;
-
- if (bgp->confed_peers_cnt == 0)
- {
- if (bgp->confed_peers)
- XFREE (MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
- bgp->confed_peers = NULL;
- }
- else
- bgp->confed_peers = XREALLOC (MTYPE_BGP_CONFED_LIST,
- bgp->confed_peers,
- bgp->confed_peers_cnt * sizeof (as_t));
-
- /* Now reset any peer who's remote AS has just been removed from the
- CONFED */
- if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION))
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (peer->as == as)
- {
- peer->local_as = bgp->confed_id;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_CONFED_PEER_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset_safe(peer, &nnode);
- }
+int bgp_confederation_peers_remove(struct bgp *bgp, as_t as)
+{
+ int i;
+ int j;
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ if (!bgp)
+ return -1;
+
+ if (!bgp_confederation_peers_check(bgp, as))
+ return -1;
+
+ for (i = 0; i < bgp->confed_peers_cnt; i++)
+ if (bgp->confed_peers[i] == as)
+ for (j = i + 1; j < bgp->confed_peers_cnt; j++)
+ bgp->confed_peers[j - 1] = bgp->confed_peers[j];
+
+ bgp->confed_peers_cnt--;
+
+ if (bgp->confed_peers_cnt == 0) {
+ if (bgp->confed_peers)
+ XFREE(MTYPE_BGP_CONFED_LIST, bgp->confed_peers);
+ bgp->confed_peers = NULL;
+ } else
+ bgp->confed_peers =
+ XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers,
+ bgp->confed_peers_cnt * sizeof(as_t));
+
+ /* Now reset any peer who's remote AS has just been removed from the
+ CONFED */
+ if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)) {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (peer->as == as) {
+ peer->local_as = bgp->confed_id;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(
+ peer->status)) {
+ peer->last_reset =
+ PEER_DOWN_CONFED_PEER_CHANGE;
+ bgp_notify_send(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset_safe(peer, &nnode);
+ }
+ }
}
- }
- return 0;
+ return 0;
}
/* Local preference configuration. */
-int
-bgp_default_local_preference_set (struct bgp *bgp, u_int32_t local_pref)
+int bgp_default_local_preference_set(struct bgp *bgp, u_int32_t local_pref)
{
- if (! bgp)
- return -1;
+ if (!bgp)
+ return -1;
- bgp->default_local_pref = local_pref;
+ bgp->default_local_pref = local_pref;
- return 0;
+ return 0;
}
-int
-bgp_default_local_preference_unset (struct bgp *bgp)
+int bgp_default_local_preference_unset(struct bgp *bgp)
{
- if (! bgp)
- return -1;
+ if (!bgp)
+ return -1;
- bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
+ bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
- return 0;
+ return 0;
}
/* Local preference configuration. */
-int
-bgp_default_subgroup_pkt_queue_max_set (struct bgp *bgp, u_int32_t queue_size)
+int bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp,
+ u_int32_t queue_size)
{
- if (! bgp)
- return -1;
+ if (!bgp)
+ return -1;
- bgp->default_subgroup_pkt_queue_max = queue_size;
+ bgp->default_subgroup_pkt_queue_max = queue_size;
- return 0;
+ return 0;
}
-int
-bgp_default_subgroup_pkt_queue_max_unset (struct bgp *bgp)
+int bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp)
{
- if (! bgp)
- return -1;
- bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
+ if (!bgp)
+ return -1;
+ bgp->default_subgroup_pkt_queue_max =
+ BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
- return 0;
+ return 0;
}
/* Listen limit configuration. */
-int
-bgp_listen_limit_set (struct bgp *bgp, int listen_limit)
+int bgp_listen_limit_set(struct bgp *bgp, int listen_limit)
{
- if (! bgp)
- return -1;
+ if (!bgp)
+ return -1;
- bgp->dynamic_neighbors_limit = listen_limit;
+ bgp->dynamic_neighbors_limit = listen_limit;
- return 0;
+ return 0;
}
-int
-bgp_listen_limit_unset (struct bgp *bgp)
+int bgp_listen_limit_unset(struct bgp *bgp)
{
- if (! bgp)
- return -1;
+ if (!bgp)
+ return -1;
- bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
+ bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
- return 0;
+ return 0;
}
-int
-bgp_map_afi_safi_iana2int (iana_afi_t pkt_afi, safi_t pkt_safi,
- afi_t *afi, safi_t *safi)
+int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi,
+ afi_t *afi, safi_t *safi)
{
- /* Map from IANA values to internal values, return error if
- * values are unrecognized.
- */
- *afi = afi_iana2int (pkt_afi);
- *safi = safi_iana2int (pkt_safi);
- if (*afi == AFI_MAX || *safi == SAFI_MAX)
- return -1;
+ /* Map from IANA values to internal values, return error if
+ * values are unrecognized.
+ */
+ *afi = afi_iana2int(pkt_afi);
+ *safi = safi_iana2int(pkt_safi);
+ if (*afi == AFI_MAX || *safi == SAFI_MAX)
+ return -1;
- return 0;
+ return 0;
}
-int
-bgp_map_afi_safi_int2iana (afi_t afi, safi_t safi,
- iana_afi_t *pkt_afi, safi_t *pkt_safi)
+int bgp_map_afi_safi_int2iana(afi_t afi, safi_t safi, iana_afi_t *pkt_afi,
+ iana_safi_t *pkt_safi)
{
- /* Map from internal values to IANA values, return error if
- * internal values are bad (unexpected).
- */
- if (afi == AFI_MAX || safi == SAFI_MAX)
- return -1;
- *pkt_afi = afi_int2iana (afi);
- *pkt_safi = safi_int2iana (safi);
- return 0;
+ /* Map from internal values to IANA values, return error if
+ * internal values are bad (unexpected).
+ */
+ if (afi == AFI_MAX || safi == SAFI_MAX)
+ return -1;
+ *pkt_afi = afi_int2iana(afi);
+ *pkt_safi = safi_int2iana(safi);
+ return 0;
}
-struct peer_af *
-peer_af_create (struct peer *peer, afi_t afi, safi_t safi)
+struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_af *af;
- int afid;
+ struct peer_af *af;
+ int afid;
- if (!peer)
- return NULL;
+ if (!peer)
+ return NULL;
- afid = afindex(afi, safi);
- if (afid >= BGP_AF_MAX)
- return NULL;
+ afid = afindex(afi, safi);
+ if (afid >= BGP_AF_MAX)
+ return NULL;
- assert(peer->peer_af_array[afid] == NULL);
+ assert(peer->peer_af_array[afid] == NULL);
- /* Allocate new peer af */
- af = XCALLOC (MTYPE_BGP_PEER_AF, sizeof (struct peer_af));
+ /* Allocate new peer af */
+ af = XCALLOC(MTYPE_BGP_PEER_AF, sizeof(struct peer_af));
- if (af == NULL)
- {
- zlog_err("Could not create af structure for peer %s", peer->host);
- return NULL;
- }
+ if (af == NULL) {
+ zlog_err("Could not create af structure for peer %s",
+ peer->host);
+ return NULL;
+ }
- peer->peer_af_array[afid] = af;
- af->afi = afi;
- af->safi = safi;
- af->afid = afid;
- af->peer = peer;
+ peer->peer_af_array[afid] = af;
+ af->afi = afi;
+ af->safi = safi;
+ af->afid = afid;
+ af->peer = peer;
- return af;
+ return af;
}
-struct peer_af *
-peer_af_find (struct peer *peer, afi_t afi, safi_t safi)
+struct peer_af *peer_af_find(struct peer *peer, afi_t afi, safi_t safi)
{
- int afid;
+ int afid;
- if (!peer)
- return NULL;
+ if (!peer)
+ return NULL;
- afid = afindex(afi, safi);
- if (afid >= BGP_AF_MAX)
- return NULL;
+ afid = afindex(afi, safi);
+ if (afid >= BGP_AF_MAX)
+ return NULL;
- return peer->peer_af_array[afid];
+ return peer->peer_af_array[afid];
}
-int
-peer_af_delete (struct peer *peer, afi_t afi, safi_t safi)
+int peer_af_delete(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_af *af;
- int afid;
+ struct peer_af *af;
+ int afid;
- if (!peer)
- return -1;
+ if (!peer)
+ return -1;
- afid = afindex(afi, safi);
- if (afid >= BGP_AF_MAX)
- return -1;
+ afid = afindex(afi, safi);
+ if (afid >= BGP_AF_MAX)
+ return -1;
- af = peer->peer_af_array[afid];
- if (!af)
- return -1;
+ af = peer->peer_af_array[afid];
+ if (!af)
+ return -1;
- bgp_stop_announce_route_timer (af);
+ bgp_stop_announce_route_timer(af);
- if (PAF_SUBGRP(af))
- {
- if (BGP_DEBUG (update_groups, UPDATE_GROUPS))
- zlog_debug ("u%" PRIu64 ":s%" PRIu64 " remove peer %s",
- af->subgroup->update_group->id, af->subgroup->id, peer->host);
- }
+ if (PAF_SUBGRP(af)) {
+ if (BGP_DEBUG(update_groups, UPDATE_GROUPS))
+ zlog_debug("u%" PRIu64 ":s%" PRIu64 " remove peer %s",
+ af->subgroup->update_group->id,
+ af->subgroup->id, peer->host);
+ }
- update_subgroup_remove_peer (af->subgroup, af);
+ update_subgroup_remove_peer(af->subgroup, af);
- peer->peer_af_array[afid] = NULL;
- XFREE(MTYPE_BGP_PEER_AF, af);
- return 0;
+ peer->peer_af_array[afid] = NULL;
+ XFREE(MTYPE_BGP_PEER_AF, af);
+ return 0;
}
/* Peer comparison function for sorting. */
-int
-peer_cmp (struct peer *p1, struct peer *p2)
+int peer_cmp(struct peer *p1, struct peer *p2)
{
- if (p1->group && !p2->group)
- return -1;
+ if (p1->group && !p2->group)
+ return -1;
- if (!p1->group && p2->group)
- return 1;
+ if (!p1->group && p2->group)
+ return 1;
- if (p1->group == p2->group)
- {
- if (p1->conf_if && !p2->conf_if)
- return -1;
+ if (p1->group == p2->group) {
+ if (p1->conf_if && !p2->conf_if)
+ return -1;
- if (!p1->conf_if && p2->conf_if)
- return 1;
+ if (!p1->conf_if && p2->conf_if)
+ return 1;
- if (p1->conf_if && p2->conf_if)
- return if_cmp_name_func (p1->conf_if, p2->conf_if);
- }
- else
- return strcmp (p1->group->name, p2->group->name);
+ if (p1->conf_if && p2->conf_if)
+ return if_cmp_name_func(p1->conf_if, p2->conf_if);
+ } else
+ return strcmp(p1->group->name, p2->group->name);
- return sockunion_cmp (&p1->su, &p2->su);
+ return sockunion_cmp(&p1->su, &p2->su);
}
-static unsigned int
-peer_hash_key_make(void *p)
+static unsigned int peer_hash_key_make(void *p)
{
- struct peer *peer = p;
- return sockunion_hash(&peer->su);
+ struct peer *peer = p;
+ return sockunion_hash(&peer->su);
}
-static int
-peer_hash_cmp (const void *p1, const void *p2)
+static int peer_hash_same(const void *p1, const void *p2)
{
- const struct peer *peer1 = p1;
- const struct peer *peer2 = p2;
- return (sockunion_same (&peer1->su, &peer2->su) &&
- CHECK_FLAG (peer1->flags, PEER_FLAG_CONFIG_NODE) == CHECK_FLAG (peer2->flags, PEER_FLAG_CONFIG_NODE));
+ const struct peer *peer1 = p1;
+ const struct peer *peer2 = p2;
+ return (sockunion_same(&peer1->su, &peer2->su)
+ && CHECK_FLAG(peer1->flags, PEER_FLAG_CONFIG_NODE)
+ == CHECK_FLAG(peer2->flags, PEER_FLAG_CONFIG_NODE));
}
-int
-peer_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
+ u_int32_t flag)
{
- return CHECK_FLAG (peer->af_flags[afi][safi], flag);
+ return CHECK_FLAG(peer->af_flags[afi][safi], flag);
}
/* Return true if flag is set for the peer but not the peer-group */
-static int
-peergroup_af_flag_check (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+static int peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi,
+ u_int32_t flag)
{
- struct peer *g_peer = NULL;
+ struct peer *g_peer = NULL;
- if (peer_af_flag_check (peer, afi, safi, flag))
- {
- if (peer_group_active (peer))
- {
- g_peer = peer->group->conf;
+ if (peer_af_flag_check(peer, afi, safi, flag)) {
+ if (peer_group_active(peer)) {
+ g_peer = peer->group->conf;
- /* If this flag is not set for the peer's peer-group then return true */
- if (!peer_af_flag_check (g_peer, afi, safi, flag))
- {
- return 1;
- }
- }
+ /* If this flag is not set for the peer's peer-group
+ * then return true */
+ if (!peer_af_flag_check(g_peer, afi, safi, flag)) {
+ return 1;
+ }
+ }
- /* peer is not in a peer-group but the flag is set to return true */
- else
- {
- return 1;
- }
- }
+ /* peer is not in a peer-group but the flag is set to return
+ true */
+ else {
+ return 1;
+ }
+ }
- return 0;
+ return 0;
}
/* Reset all address family specific configuration. */
-static void
-peer_af_flag_reset (struct peer *peer, afi_t afi, safi_t safi)
+static void peer_af_flag_reset(struct peer *peer, afi_t afi, safi_t safi)
{
- int i;
- struct bgp_filter *filter;
- char orf_name[BUFSIZ];
+ int i;
+ struct bgp_filter *filter;
+ char orf_name[BUFSIZ];
- filter = &peer->filter[afi][safi];
+ filter = &peer->filter[afi][safi];
- /* Clear neighbor filter and route-map */
- for (i = FILTER_IN; i < FILTER_MAX; i++)
- {
- if (filter->dlist[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[i].name);
- filter->dlist[i].name = NULL;
- }
- if (filter->plist[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[i].name);
- filter->plist[i].name = NULL;
- }
- if (filter->aslist[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[i].name);
- filter->aslist[i].name = NULL;
+ /* Clear neighbor filter and route-map */
+ for (i = FILTER_IN; i < FILTER_MAX; i++) {
+ if (filter->dlist[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[i].name);
+ filter->dlist[i].name = NULL;
+ }
+ if (filter->plist[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[i].name);
+ filter->plist[i].name = NULL;
+ }
+ if (filter->aslist[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[i].name);
+ filter->aslist[i].name = NULL;
+ }
}
- }
- for (i = RMAP_IN; i < RMAP_MAX; i++)
- {
- if (filter->map[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[i].name);
- filter->map[i].name = NULL;
+ for (i = RMAP_IN; i < RMAP_MAX; i++) {
+ if (filter->map[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[i].name);
+ filter->map[i].name = NULL;
+ }
}
- }
- /* Clear unsuppress map. */
- if (filter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = NULL;
- filter->usmap.map = NULL;
-
- /* Clear neighbor's all address family flags. */
- peer->af_flags[afi][safi] = 0;
+ /* Clear unsuppress map. */
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ filter->usmap.name = NULL;
+ filter->usmap.map = NULL;
- /* Clear neighbor's all address family sflags. */
- peer->af_sflags[afi][safi] = 0;
+ /* Clear neighbor's all address family flags. */
+ peer->af_flags[afi][safi] = 0;
- /* Clear neighbor's all address family capabilities. */
- peer->af_cap[afi][safi] = 0;
+ /* Clear neighbor's all address family sflags. */
+ peer->af_sflags[afi][safi] = 0;
- /* Clear ORF info */
- peer->orf_plist[afi][safi] = NULL;
- sprintf (orf_name, "%s.%d.%d", peer->host, afi, safi);
- prefix_bgp_orf_remove_all (afi, orf_name);
+ /* Clear neighbor's all address family capabilities. */
+ peer->af_cap[afi][safi] = 0;
- /* Set default neighbor send-community. */
- if (! bgp_option_check (BGP_OPT_CONFIG_CISCO))
- {
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
- }
+ /* Clear ORF info */
+ peer->orf_plist[afi][safi] = NULL;
+ sprintf(orf_name, "%s.%d.%d", peer->host, afi, safi);
+ prefix_bgp_orf_remove_all(afi, orf_name);
+
+ /* Set default neighbor send-community. */
+ if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
+ }
- /* Clear neighbor default_originate_rmap */
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = NULL;
- peer->default_rmap[afi][safi].map = NULL;
+ /* Clear neighbor default_originate_rmap */
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name = NULL;
+ peer->default_rmap[afi][safi].map = NULL;
- /* Clear neighbor maximum-prefix */
- peer->pmax[afi][safi] = 0;
- peer->pmax_threshold[afi][safi] = MAXIMUM_PREFIX_THRESHOLD_DEFAULT;
+ /* Clear neighbor maximum-prefix */
+ peer->pmax[afi][safi] = 0;
+ peer->pmax_threshold[afi][safi] = MAXIMUM_PREFIX_THRESHOLD_DEFAULT;
}
/* peer global config reset */
-static void
-peer_global_config_reset (struct peer *peer)
+static void peer_global_config_reset(struct peer *peer)
{
- int v6only;
+ int v6only;
- peer->change_local_as = 0;
- peer->ttl = (peer_sort (peer) == BGP_PEER_IBGP ? MAXTTL : 1);
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
- }
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
+ peer->change_local_as = 0;
+ peer->ttl = (peer_sort(peer) == BGP_PEER_IBGP ? MAXTTL : 1);
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ if (peer_sort(peer) == BGP_PEER_IBGP)
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- /* This is a per-peer specific flag and so we must preserve it */
- v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+ /* This is a per-peer specific flag and so we must preserve it */
+ v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
- peer->flags = 0;
+ peer->flags = 0;
- if (v6only)
- SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
+ if (v6only)
+ SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
- peer->config = 0;
- peer->holdtime = 0;
- peer->keepalive = 0;
- peer->connect = 0;
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ peer->config = 0;
+ peer->holdtime = 0;
+ peer->keepalive = 0;
+ peer->connect = 0;
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- /* Reset some other configs back to defaults. */
- peer->v_start = BGP_INIT_START_TIMER;
- peer->password = NULL;
- peer->local_id = peer->bgp->router_id;
- peer->v_holdtime = peer->bgp->default_holdtime;
- peer->v_keepalive = peer->bgp->default_keepalive;
+ /* Reset some other configs back to defaults. */
+ peer->v_start = BGP_INIT_START_TIMER;
+ peer->password = NULL;
+ peer->local_id = peer->bgp->router_id;
+ peer->v_holdtime = peer->bgp->default_holdtime;
+ peer->v_keepalive = peer->bgp->default_keepalive;
- bfd_info_free(&(peer->bfd_info));
+ bfd_info_free(&(peer->bfd_info));
- /* Set back the CONFIG_NODE flag. */
- SET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
+ /* Set back the CONFIG_NODE flag. */
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
}
/* Check peer's AS number and determines if this peer is IBGP or EBGP */
-static bgp_peer_sort_t
-peer_calc_sort (struct peer *peer)
+static bgp_peer_sort_t peer_calc_sort(struct peer *peer)
{
- struct bgp *bgp;
+ struct bgp *bgp;
- bgp = peer->bgp;
+ bgp = peer->bgp;
- /* Peer-group */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (peer->as_type == AS_INTERNAL)
- return BGP_PEER_IBGP;
+ /* Peer-group */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (peer->as_type == AS_INTERNAL)
+ return BGP_PEER_IBGP;
- else if (peer->as_type == AS_EXTERNAL)
- return BGP_PEER_EBGP;
+ else if (peer->as_type == AS_EXTERNAL)
+ return BGP_PEER_EBGP;
- else if (peer->as_type == AS_SPECIFIED && peer->as)
- return (bgp->as == peer->as ? BGP_PEER_IBGP : BGP_PEER_EBGP);
+ else if (peer->as_type == AS_SPECIFIED && peer->as)
+ return (bgp->as == peer->as ? BGP_PEER_IBGP
+ : BGP_PEER_EBGP);
- else
- {
- struct peer *peer1;
- peer1 = listnode_head (peer->group->peer);
-
- if (peer1)
- return peer1->sort;
- }
- return BGP_PEER_INTERNAL;
- }
-
- /* Normal peer */
- if (bgp && CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
- {
- if (peer->local_as == 0)
- return BGP_PEER_INTERNAL;
-
- if (peer->local_as == peer->as)
- {
- if (bgp->as == bgp->confed_id)
- {
- if (peer->local_as == bgp->as)
- return BGP_PEER_IBGP;
- else
- return BGP_PEER_EBGP;
- }
- else
- {
- if (peer->local_as == bgp->confed_id)
- return BGP_PEER_EBGP;
- else
- return BGP_PEER_IBGP;
- }
- }
-
- if (bgp_confederation_peers_check (bgp, peer->as))
- return BGP_PEER_CONFED;
-
- return BGP_PEER_EBGP;
- }
- else
- {
- if (peer->as_type != AS_SPECIFIED)
- return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP : BGP_PEER_EBGP);
-
- return (peer->local_as == 0
- ? BGP_PEER_INTERNAL : peer->local_as == peer->as
- ? BGP_PEER_IBGP : BGP_PEER_EBGP);
- }
+ else {
+ struct peer *peer1;
+ peer1 = listnode_head(peer->group->peer);
+
+ if (peer1)
+ return peer1->sort;
+ }
+ return BGP_PEER_INTERNAL;
+ }
+
+ /* Normal peer */
+ if (bgp && CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
+ if (peer->local_as == 0)
+ return BGP_PEER_INTERNAL;
+
+ if (peer->local_as == peer->as) {
+ if (bgp->as == bgp->confed_id) {
+ if (peer->local_as == bgp->as)
+ return BGP_PEER_IBGP;
+ else
+ return BGP_PEER_EBGP;
+ } else {
+ if (peer->local_as == bgp->confed_id)
+ return BGP_PEER_EBGP;
+ else
+ return BGP_PEER_IBGP;
+ }
+ }
+
+ if (bgp_confederation_peers_check(bgp, peer->as))
+ return BGP_PEER_CONFED;
+
+ return BGP_PEER_EBGP;
+ } else {
+ if (peer->as_type != AS_SPECIFIED)
+ return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP
+ : BGP_PEER_EBGP);
+
+ return (peer->local_as == 0
+ ? BGP_PEER_INTERNAL
+ : peer->local_as == peer->as ? BGP_PEER_IBGP
+ : BGP_PEER_EBGP);
+ }
}
/* Calculate and cache the peer "sort" */
-bgp_peer_sort_t
-peer_sort (struct peer *peer)
-{
- peer->sort = peer_calc_sort (peer);
- return peer->sort;
-}
-
-static void
-peer_free (struct peer *peer)
-{
- assert (peer->status == Deleted);
-
- QOBJ_UNREG (peer);
-
- /* this /ought/ to have been done already through bgp_stop earlier,
- * but just to be sure..
- */
- bgp_timer_set (peer);
- BGP_READ_OFF (peer->t_read);
- BGP_WRITE_OFF (peer->t_write);
- BGP_EVENT_FLUSH (peer);
-
- /* Free connected nexthop, if present */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE) &&
- !peer_dynamic_neighbor (peer))
- bgp_delete_connected_nexthop (family2afi(peer->su.sa.sa_family), peer);
-
- XFREE (MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
-
- if (peer->desc)
- {
- XFREE (MTYPE_PEER_DESC, peer->desc);
- peer->desc = NULL;
- }
-
- /* Free allocated host character. */
- if (peer->host)
- {
- XFREE (MTYPE_BGP_PEER_HOST, peer->host);
- peer->host = NULL;
- }
-
- if (peer->domainname)
- {
- XFREE (MTYPE_BGP_PEER_HOST, peer->domainname);
- peer->domainname = NULL;
- }
-
- if (peer->ifname)
- {
- XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
- peer->ifname = NULL;
- }
-
- /* Update source configuration. */
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
- }
-
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
-
- if (peer->notify.data)
- XFREE(MTYPE_TMP, peer->notify.data);
- memset (&peer->notify, 0, sizeof (struct bgp_notify));
-
- if (peer->clear_node_queue)
- {
- work_queue_free(peer->clear_node_queue);
- peer->clear_node_queue = NULL;
- }
-
- bgp_sync_delete (peer);
-
- if (peer->conf_if)
- {
- XFREE (MTYPE_PEER_CONF_IF, peer->conf_if);
- peer->conf_if = NULL;
- }
-
- bfd_info_free(&(peer->bfd_info));
-
- bgp_unlock(peer->bgp);
-
- memset (peer, 0, sizeof (struct peer));
-
- XFREE (MTYPE_BGP_PEER, peer);
-}
-
+bgp_peer_sort_t peer_sort(struct peer *peer)
+{
+ peer->sort = peer_calc_sort(peer);
+ return peer->sort;
+}
+
+static void peer_free(struct peer *peer)
+{
+ assert(peer->status == Deleted);
+
+ QOBJ_UNREG(peer);
+
+ /* this /ought/ to have been done already through bgp_stop earlier,
+ * but just to be sure..
+ */
+ bgp_timer_set(peer);
+ BGP_READ_OFF(peer->t_read);
+ BGP_WRITE_OFF(peer->t_write);
+ BGP_EVENT_FLUSH(peer);
+
+ /* Free connected nexthop, if present */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)
+ && !peer_dynamic_neighbor(peer))
+ bgp_delete_connected_nexthop(family2afi(peer->su.sa.sa_family),
+ peer);
+
+ XFREE(MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
+
+ if (peer->desc) {
+ XFREE(MTYPE_PEER_DESC, peer->desc);
+ peer->desc = NULL;
+ }
+
+ /* Free allocated host character. */
+ if (peer->host) {
+ XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+ peer->host = NULL;
+ }
+
+ if (peer->domainname) {
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+ peer->domainname = NULL;
+ }
+
+ if (peer->ifname) {
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
+ peer->ifname = NULL;
+ }
+
+ /* Update source configuration. */
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ if (peer->notify.data)
+ XFREE(MTYPE_TMP, peer->notify.data);
+ memset(&peer->notify, 0, sizeof(struct bgp_notify));
+
+ if (peer->clear_node_queue) {
+ work_queue_free(peer->clear_node_queue);
+ peer->clear_node_queue = NULL;
+ }
+
+ bgp_sync_delete(peer);
+
+ if (peer->conf_if) {
+ XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
+ peer->conf_if = NULL;
+ }
+
+ bfd_info_free(&(peer->bfd_info));
+
+ bgp_unlock(peer->bgp);
+
+ memset(peer, 0, sizeof(struct peer));
+
+ XFREE(MTYPE_BGP_PEER, peer);
+}
+
/* increase reference count on a struct peer */
-struct peer *
-peer_lock_with_caller (const char *name, struct peer *peer)
+struct peer *peer_lock_with_caller(const char *name, struct peer *peer)
{
- assert (peer && (peer->lock >= 0));
+ assert(peer && (peer->lock >= 0));
#if 0
zlog_debug("%s peer_lock %p %d", name, peer, peer->lock);
#endif
-
- peer->lock++;
-
- return peer;
+
+ peer->lock++;
+
+ return peer;
}
/* decrease reference count on a struct peer
* struct peer is freed and NULL returned if last reference
*/
-struct peer *
-peer_unlock_with_caller (const char *name, struct peer *peer)
+struct peer *peer_unlock_with_caller(const char *name, struct peer *peer)
{
- assert (peer && (peer->lock > 0));
+ assert(peer && (peer->lock > 0));
#if 0
zlog_debug("%s peer_unlock %p %d", name, peer, peer->lock);
#endif
-
- peer->lock--;
-
- if (peer->lock == 0)
- {
- peer_free (peer);
- return NULL;
- }
- return peer;
+ peer->lock--;
+
+ if (peer->lock == 0) {
+ peer_free(peer);
+ return NULL;
+ }
+
+ return peer;
}
/* Allocate new peer object, implicitely locked. */
-struct peer *
-peer_new (struct bgp *bgp)
-{
- afi_t afi;
- safi_t safi;
- struct peer *peer;
- struct servent *sp;
-
- /* bgp argument is absolutely required */
- assert (bgp);
- if (!bgp)
- return NULL;
-
- /* Allocate new peer. */
- peer = XCALLOC (MTYPE_BGP_PEER, sizeof (struct peer));
-
- /* Set default value. */
- peer->fd = -1;
- peer->v_start = BGP_INIT_START_TIMER;
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- peer->status = Idle;
- peer->ostatus = Idle;
- peer->cur_event = peer->last_event = peer->last_major_event = 0;
- peer->bgp = bgp;
- peer = peer_lock (peer); /* initial reference */
- bgp_lock (bgp);
- peer->password = NULL;
-
- /* Set default flags. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (! bgp_option_check (BGP_OPT_CONFIG_CISCO))
- {
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY);
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_LARGE_COMMUNITY);
- }
- peer->orf_plist[afi][safi] = NULL;
- }
- SET_FLAG (peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+struct peer *peer_new(struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ struct servent *sp;
+
+ /* bgp argument is absolutely required */
+ assert(bgp);
+ if (!bgp)
+ return NULL;
+
+ /* Allocate new peer. */
+ peer = XCALLOC(MTYPE_BGP_PEER, sizeof(struct peer));
+
+ /* Set default value. */
+ peer->fd = -1;
+ peer->v_start = BGP_INIT_START_TIMER;
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ peer->status = Idle;
+ peer->ostatus = Idle;
+ peer->cur_event = peer->last_event = peer->last_major_event = 0;
+ peer->bgp = bgp;
+ peer = peer_lock(peer); /* initial reference */
+ bgp_lock(bgp);
+ peer->password = NULL;
+
+ /* Set default flags. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
+ }
+ peer->orf_plist[afi][safi] = NULL;
+ }
+ SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
- /* Create buffers. */
- peer->ibuf = stream_new (BGP_MAX_PACKET_SIZE);
- peer->obuf = stream_fifo_new ();
+ /* Create buffers. */
+ peer->ibuf = stream_new(BGP_MAX_PACKET_SIZE);
+ peer->obuf = stream_fifo_new();
- /* We use a larger buffer for peer->work in the event that:
- * - We RX a BGP_UPDATE where the attributes alone are just
- * under BGP_MAX_PACKET_SIZE
- * - The user configures an outbound route-map that does many as-path
- * prepends or adds many communities. At most they can have CMD_ARGC_MAX
- * args in a route-map so there is a finite limit on how large they can
- * make the attributes.
- *
- * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid bounds
- * checking for every single attribute as we construct an UPDATE.
- */
- peer->work = stream_new (BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
- peer->scratch = stream_new (BGP_MAX_PACKET_SIZE);
+ /* We use a larger buffer for peer->work in the event that:
+ * - We RX a BGP_UPDATE where the attributes alone are just
+ * under BGP_MAX_PACKET_SIZE
+ * - The user configures an outbound route-map that does many as-path
+ * prepends or adds many communities. At most they can have
+ * CMD_ARGC_MAX
+ * args in a route-map so there is a finite limit on how large they
+ * can
+ * make the attributes.
+ *
+ * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
+ * bounds
+ * checking for every single attribute as we construct an UPDATE.
+ */
+ peer->work =
+ stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
+ peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
- bgp_sync_init (peer);
+ bgp_sync_init(peer);
- /* Get service port number. */
- sp = getservbyname ("bgp", "tcp");
- peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs (sp->s_port);
+ /* Get service port number. */
+ sp = getservbyname("bgp", "tcp");
+ peer->port = (sp == NULL) ? BGP_PORT_DEFAULT : ntohs(sp->s_port);
- QOBJ_REG (peer, peer);
- return peer;
+ QOBJ_REG(peer, peer);
+ return peer;
}
/*
* a neighbor is being deleted. If this about-to-be-deleted structure is
* the one with all the config, then we have to copy over the info.
*/
-void
-peer_xfer_config (struct peer *peer_dst, struct peer *peer_src)
-{
- struct peer_af *paf;
- afi_t afi;
- safi_t safi;
- int afidx;
-
- assert(peer_src);
- assert(peer_dst);
-
- /* The following function is used by both peer group config copy to
- * individual peer and when we transfer config
- */
- if (peer_src->change_local_as)
- peer_dst->change_local_as = peer_src->change_local_as;
-
- /* peer flags apply */
- peer_dst->flags = peer_src->flags;
- peer_dst->cap = peer_src->cap;
- peer_dst->config = peer_src->config;
-
- peer_dst->local_as = peer_src->local_as;
- peer_dst->ifindex = peer_src->ifindex;
- peer_dst->port = peer_src->port;
- peer_sort(peer_dst);
- peer_dst->rmap_type = peer_src->rmap_type;
-
- /* Timers */
- peer_dst->holdtime = peer_src->holdtime;
- peer_dst->keepalive = peer_src->keepalive;
- peer_dst->connect = peer_src->connect;
- peer_dst->v_holdtime = peer_src->v_holdtime;
- peer_dst->v_keepalive = peer_src->v_keepalive;
- peer_dst->routeadv = peer_src->routeadv;
- peer_dst->v_routeadv = peer_src->v_routeadv;
-
- /* password apply */
- if (peer_src->password && !peer_dst->password)
- peer_dst->password = XSTRDUP (MTYPE_PEER_PASSWORD, peer_src->password);
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
- peer_dst->af_flags[afi][safi] = peer_src->af_flags[afi][safi];
- peer_dst->allowas_in[afi][safi] = peer_src->allowas_in[afi][safi];
- peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
- }
-
- for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++)
- {
- paf = peer_src->peer_af_array[afidx];
- if (paf != NULL)
- peer_af_create(peer_dst, paf->afi, paf->safi);
- }
-
- /* update-source apply */
- if (peer_src->update_source)
- {
- if (peer_dst->update_source)
- sockunion_free (peer_dst->update_source);
- if (peer_dst->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
- peer_dst->update_if = NULL;
- }
- peer_dst->update_source = sockunion_dup (peer_src->update_source);
- }
- else if (peer_src->update_if)
- {
- if (peer_dst->update_if)
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
- if (peer_dst->update_source)
- {
- sockunion_free (peer_dst->update_source);
- peer_dst->update_source = NULL;
- }
- peer_dst->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, peer_src->update_if);
- }
-
- if (peer_src->ifname)
- {
- if (peer_dst->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, peer_dst->ifname);
-
- peer_dst->ifname = XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname);
- }
-}
-
-static int
-bgp_peer_conf_if_to_su_update_v4 (struct peer *peer, struct interface *ifp)
-{
- struct connected *ifc;
- struct prefix p;
- u_int32_t addr;
- struct listnode *node;
-
- /* If our IPv4 address on the interface is /30 or /31, we can derive the
- * IPv4 address of the other end.
- */
- for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc))
- {
- if (ifc->address && (ifc->address->family == AF_INET))
- {
- PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
- if (p.prefixlen == 30)
- {
- peer->su.sa.sa_family = AF_INET;
- addr = ntohl(p.u.prefix4.s_addr);
- if (addr % 4 == 1)
- peer->su.sin.sin_addr.s_addr = htonl(addr+1);
- else if (addr % 4 == 2)
- peer->su.sin.sin_addr.s_addr = htonl(addr-1);
+void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
+{
+ struct peer_af *paf;
+ afi_t afi;
+ safi_t safi;
+ int afidx;
+
+ assert(peer_src);
+ assert(peer_dst);
+
+ /* The following function is used by both peer group config copy to
+ * individual peer and when we transfer config
+ */
+ if (peer_src->change_local_as)
+ peer_dst->change_local_as = peer_src->change_local_as;
+
+ /* peer flags apply */
+ peer_dst->flags = peer_src->flags;
+ peer_dst->cap = peer_src->cap;
+ peer_dst->config = peer_src->config;
+
+ peer_dst->local_as = peer_src->local_as;
+ peer_dst->ifindex = peer_src->ifindex;
+ peer_dst->port = peer_src->port;
+ peer_sort(peer_dst);
+ peer_dst->rmap_type = peer_src->rmap_type;
+
+ /* Timers */
+ peer_dst->holdtime = peer_src->holdtime;
+ peer_dst->keepalive = peer_src->keepalive;
+ peer_dst->connect = peer_src->connect;
+ peer_dst->v_holdtime = peer_src->v_holdtime;
+ peer_dst->v_keepalive = peer_src->v_keepalive;
+ peer_dst->routeadv = peer_src->routeadv;
+ peer_dst->v_routeadv = peer_src->v_routeadv;
+
+ /* password apply */
+ if (peer_src->password && !peer_dst->password)
+ peer_dst->password =
+ XSTRDUP(MTYPE_PEER_PASSWORD, peer_src->password);
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ peer_dst->afc[afi][safi] = peer_src->afc[afi][safi];
+ peer_dst->af_flags[afi][safi] =
+ peer_src->af_flags[afi][safi];
+ peer_dst->allowas_in[afi][safi] =
+ peer_src->allowas_in[afi][safi];
+ peer_dst->weight[afi][safi] =
+ peer_src->weight[afi][safi];
+ }
+
+ for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
+ paf = peer_src->peer_af_array[afidx];
+ if (paf != NULL)
+ peer_af_create(peer_dst, paf->afi, paf->safi);
+ }
+
+ /* update-source apply */
+ if (peer_src->update_source) {
+ if (peer_dst->update_source)
+ sockunion_free(peer_dst->update_source);
+ if (peer_dst->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ peer_dst->update_if = NULL;
+ }
+ peer_dst->update_source =
+ sockunion_dup(peer_src->update_source);
+ } else if (peer_src->update_if) {
+ if (peer_dst->update_if)
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer_dst->update_if);
+ if (peer_dst->update_source) {
+ sockunion_free(peer_dst->update_source);
+ peer_dst->update_source = NULL;
+ }
+ peer_dst->update_if =
+ XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, peer_src->update_if);
+ }
+
+ if (peer_src->ifname) {
+ if (peer_dst->ifname)
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer_dst->ifname);
+
+ peer_dst->ifname =
+ XSTRDUP(MTYPE_BGP_PEER_IFNAME, peer_src->ifname);
+ }
+}
+
+static int bgp_peer_conf_if_to_su_update_v4(struct peer *peer,
+ struct interface *ifp)
+{
+ struct connected *ifc;
+ struct prefix p;
+ u_int32_t addr;
+ struct listnode *node;
+
+ /* If our IPv4 address on the interface is /30 or /31, we can derive the
+ * IPv4 address of the other end.
+ */
+ for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
+ if (ifc->address && (ifc->address->family == AF_INET)) {
+ PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
+ if (p.prefixlen == 30) {
+ peer->su.sa.sa_family = AF_INET;
+ addr = ntohl(p.u.prefix4.s_addr);
+ if (addr % 4 == 1)
+ peer->su.sin.sin_addr.s_addr =
+ htonl(addr + 1);
+ else if (addr % 4 == 2)
+ peer->su.sin.sin_addr.s_addr =
+ htonl(addr - 1);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- peer->su.sin.sin_len = sizeof(struct sockaddr_in);
+ peer->su.sin.sin_len =
+ sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- return 1;
- }
- else if (p.prefixlen == 31)
- {
- peer->su.sa.sa_family = AF_INET;
- addr = ntohl(p.u.prefix4.s_addr);
- if (addr % 2 == 0)
- peer->su.sin.sin_addr.s_addr = htonl(addr+1);
- else
- peer->su.sin.sin_addr.s_addr = htonl(addr-1);
+ return 1;
+ } else if (p.prefixlen == 31) {
+ peer->su.sa.sa_family = AF_INET;
+ addr = ntohl(p.u.prefix4.s_addr);
+ if (addr % 2 == 0)
+ peer->su.sin.sin_addr.s_addr =
+ htonl(addr + 1);
+ else
+ peer->su.sin.sin_addr.s_addr =
+ htonl(addr - 1);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- peer->su.sin.sin_len = sizeof(struct sockaddr_in);
+ peer->su.sin.sin_len =
+ sizeof(struct sockaddr_in);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- return 1;
- }
- else
- if (bgp_debug_neighbor_events(peer))
- zlog_debug("%s: IPv4 interface address is not /30 or /31, v4 session not started",
- peer->conf_if);
- }
- }
-
- return 0;
-}
-
-static int
-bgp_peer_conf_if_to_su_update_v6 (struct peer *peer, struct interface *ifp)
-{
- struct nbr_connected *ifc_nbr;
-
- /* Have we learnt the peer's IPv6 link-local address? */
- if (ifp->nbr_connected &&
- (ifc_nbr = listnode_head(ifp->nbr_connected)))
- {
- peer->su.sa.sa_family = AF_INET6;
- memcpy(&peer->su.sin6.sin6_addr, &ifc_nbr->address->u.prefix,
- sizeof (struct in6_addr));
+ return 1;
+ } else if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s: IPv4 interface address is not /30 or /31, v4 session not started",
+ peer->conf_if);
+ }
+ }
+
+ return 0;
+}
+
+static int bgp_peer_conf_if_to_su_update_v6(struct peer *peer,
+ struct interface *ifp)
+{
+ struct nbr_connected *ifc_nbr;
+
+ /* Have we learnt the peer's IPv6 link-local address? */
+ if (ifp->nbr_connected
+ && (ifc_nbr = listnode_head(ifp->nbr_connected))) {
+ peer->su.sa.sa_family = AF_INET6;
+ memcpy(&peer->su.sin6.sin6_addr, &ifc_nbr->address->u.prefix,
+ sizeof(struct in6_addr));
#ifdef SIN6_LEN
- peer->su.sin6.sin6_len = sizeof (struct sockaddr_in6);
+ peer->su.sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
- peer->su.sin6.sin6_scope_id = ifp->ifindex;
- return 1;
- }
+ peer->su.sin6.sin6_scope_id = ifp->ifindex;
+ return 1;
+ }
- return 0;
+ return 0;
}
/*
* learnt/derived peer address. If the address has changed, update the
* password on the listen socket, if needed.
*/
-void
-bgp_peer_conf_if_to_su_update (struct peer *peer)
-{
- struct interface *ifp;
- int prev_family;
- int peer_addr_updated = 0;
-
- if (!peer->conf_if)
- return;
-
- prev_family = peer->su.sa.sa_family;
- if ((ifp = if_lookup_by_name (peer->conf_if, peer->bgp->vrf_id)))
- {
- peer->ifp = ifp;
- /* If BGP unnumbered is not "v6only", we first see if we can derive the
- * peer's IPv4 address.
- */
- if (!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
- peer_addr_updated = bgp_peer_conf_if_to_su_update_v4 (peer, ifp);
-
- /* If "v6only" or we can't derive peer's IPv4 address, see if we've
- * learnt the peer's IPv6 link-local address. This is from the source
- * IPv6 address in router advertisement.
- */
- if (!peer_addr_updated)
- peer_addr_updated = bgp_peer_conf_if_to_su_update_v6 (peer, ifp);
- }
- /* If we could derive the peer address, we may need to install the password
- * configured for the peer, if any, on the listen socket. Otherwise, mark
- * that peer's address is not available and uninstall the password, if
- * needed.
- */
- if (peer_addr_updated)
- {
- if (peer->password && prev_family == AF_UNSPEC)
- bgp_md5_set (peer);
- }
- else
- {
- if (peer->password && prev_family != AF_UNSPEC)
- bgp_md5_unset (peer);
- peer->su.sa.sa_family = AF_UNSPEC;
- memset(&peer->su.sin6.sin6_addr, 0, sizeof (struct in6_addr));
- }
-
- /* Since our su changed we need to del/add peer to the peerhash */
- hash_release(peer->bgp->peerhash, peer);
- hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
+void bgp_peer_conf_if_to_su_update(struct peer *peer)
+{
+ struct interface *ifp;
+ int prev_family;
+ int peer_addr_updated = 0;
+
+ if (!peer->conf_if)
+ return;
+
+ prev_family = peer->su.sa.sa_family;
+ if ((ifp = if_lookup_by_name(peer->conf_if, peer->bgp->vrf_id))) {
+ peer->ifp = ifp;
+ /* If BGP unnumbered is not "v6only", we first see if we can
+ * derive the
+ * peer's IPv4 address.
+ */
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
+ peer_addr_updated =
+ bgp_peer_conf_if_to_su_update_v4(peer, ifp);
+
+ /* If "v6only" or we can't derive peer's IPv4 address, see if
+ * we've
+ * learnt the peer's IPv6 link-local address. This is from the
+ * source
+ * IPv6 address in router advertisement.
+ */
+ if (!peer_addr_updated)
+ peer_addr_updated =
+ bgp_peer_conf_if_to_su_update_v6(peer, ifp);
+ }
+ /* If we could derive the peer address, we may need to install the
+ * password
+ * configured for the peer, if any, on the listen socket. Otherwise,
+ * mark
+ * that peer's address is not available and uninstall the password, if
+ * needed.
+ */
+ if (peer_addr_updated) {
+ if (peer->password && prev_family == AF_UNSPEC)
+ bgp_md5_set(peer);
+ } else {
+ if (peer->password && prev_family != AF_UNSPEC)
+ bgp_md5_unset(peer);
+ peer->su.sa.sa_family = AF_UNSPEC;
+ memset(&peer->su.sin6.sin6_addr, 0, sizeof(struct in6_addr));
+ }
+
+ /* Since our su changed we need to del/add peer to the peerhash */
+ hash_release(peer->bgp->peerhash, peer);
+ hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
}
/* Force a bestpath recalculation for all prefixes. This is used
* when 'bgp bestpath' commands are entered.
*/
-void
-bgp_recalculate_all_bestpaths (struct bgp *bgp)
-{
- afi_t afi;
- safi_t safi;
- struct bgp_node *rn;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- {
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- for (rn = bgp_table_top (bgp->rib[afi][safi]); rn; rn = bgp_route_next (rn))
- {
- if (rn->info != NULL)
- {
- bgp_process (bgp, rn, afi, safi);
- }
- }
- }
- }
+void bgp_recalculate_all_bestpaths(struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_node *rn, *nrn;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
+ rn = bgp_route_next(rn)) {
+ if (rn->info != NULL) {
+ /* Special handling for 2-level routing
+ * tables. */
+ if (safi == SAFI_MPLS_VPN
+ || safi == SAFI_ENCAP
+ || safi == SAFI_EVPN) {
+ for (nrn = bgp_table_top((
+ struct bgp_table
+ *)(rn->info));
+ nrn;
+ nrn = bgp_route_next(nrn))
+ bgp_process(bgp, nrn,
+ afi, safi);
+ } else
+ bgp_process(bgp, rn, afi, safi);
+ }
+ }
+ }
+ }
}
/* Create new BGP peer. */
-struct peer *
-peer_create (union sockunion *su, const char *conf_if, struct bgp *bgp,
- as_t local_as, as_t remote_as, int as_type, afi_t afi, safi_t safi, struct peer_group *group)
-{
- int active;
- struct peer *peer;
- char buf[SU_ADDRSTRLEN];
-
- peer = peer_new (bgp);
- if (conf_if)
- {
- peer->conf_if = XSTRDUP (MTYPE_PEER_CONF_IF, conf_if);
- bgp_peer_conf_if_to_su_update(peer);
- if (peer->host)
- XFREE(MTYPE_BGP_PEER_HOST, peer->host);
- peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, conf_if);
- }
- else if (su)
- {
- peer->su = *su;
- sockunion2str (su, buf, SU_ADDRSTRLEN);
- if (peer->host)
- XFREE(MTYPE_BGP_PEER_HOST, peer->host);
- peer->host = XSTRDUP (MTYPE_BGP_PEER_HOST, buf);
- }
- peer->local_as = local_as;
- peer->as = remote_as;
- peer->as_type = as_type;
- peer->local_id = bgp->router_id;
- peer->v_holdtime = bgp->default_holdtime;
- peer->v_keepalive = bgp->default_keepalive;
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
- peer = peer_lock (peer); /* bgp peer list reference */
- peer->group = group;
- listnode_add_sort (bgp->peer, peer);
- hash_get(bgp->peerhash, peer, hash_alloc_intern);
-
- active = peer_active (peer);
-
- /* Last read and reset time set */
- peer->readtime = peer->resettime = bgp_clock ();
-
- /* Default TTL set. */
- peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : 1;
-
- SET_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE);
-
- if (afi && safi)
- {
- peer->afc[afi][safi] = 1;
- peer_af_create(peer, afi, safi);
- }
-
- /* Set up peer's events and timers. */
- if (! active && peer_active (peer))
- bgp_timer_set (peer);
-
- return peer;
+struct peer *peer_create(union sockunion *su, const char *conf_if,
+ struct bgp *bgp, as_t local_as, as_t remote_as,
+ int as_type, afi_t afi, safi_t safi,
+ struct peer_group *group)
+{
+ int active;
+ struct peer *peer;
+ char buf[SU_ADDRSTRLEN];
+
+ peer = peer_new(bgp);
+ if (conf_if) {
+ peer->conf_if = XSTRDUP(MTYPE_PEER_CONF_IF, conf_if);
+ bgp_peer_conf_if_to_su_update(peer);
+ if (peer->host)
+ XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+ peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, conf_if);
+ } else if (su) {
+ peer->su = *su;
+ sockunion2str(su, buf, SU_ADDRSTRLEN);
+ if (peer->host)
+ XFREE(MTYPE_BGP_PEER_HOST, peer->host);
+ peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf);
+ }
+ peer->local_as = local_as;
+ peer->as = remote_as;
+ peer->as_type = as_type;
+ peer->local_id = bgp->router_id;
+ peer->v_holdtime = bgp->default_holdtime;
+ peer->v_keepalive = bgp->default_keepalive;
+ if (peer_sort(peer) == BGP_PEER_IBGP)
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+ peer = peer_lock(peer); /* bgp peer list reference */
+ peer->group = group;
+ listnode_add_sort(bgp->peer, peer);
+ hash_get(bgp->peerhash, peer, hash_alloc_intern);
+
+ active = peer_active(peer);
+
+ /* Last read and reset time set */
+ peer->readtime = peer->resettime = bgp_clock();
+
+ /* Default TTL set. */
+ peer->ttl = (peer->sort == BGP_PEER_IBGP) ? MAXTTL : 1;
+
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
+
+ if (afi && safi) {
+ peer->afc[afi][safi] = 1;
+ peer_af_create(peer, afi, safi);
+ }
+
+ /* Set up peer's events and timers. */
+ if (!active && peer_active(peer))
+ bgp_timer_set(peer);
+
+ return peer;
}
/* Make accept BGP peer. This function is only called from the test code */
-struct peer *
-peer_create_accept (struct bgp *bgp)
+struct peer *peer_create_accept(struct bgp *bgp)
{
- struct peer *peer;
+ struct peer *peer;
- peer = peer_new (bgp);
+ peer = peer_new(bgp);
- peer = peer_lock (peer); /* bgp peer list reference */
- listnode_add_sort (bgp->peer, peer);
+ peer = peer_lock(peer); /* bgp peer list reference */
+ listnode_add_sort(bgp->peer, peer);
- return peer;
+ return peer;
}
/* Change peer's AS number. */
-void
-peer_as_change (struct peer *peer, as_t as, int as_specified)
-{
- bgp_peer_sort_t type;
- struct peer *conf;
-
- /* Stop peer. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- }
- type = peer_sort (peer);
- peer->as = as;
- peer->as_type = as_specified;
-
- if (bgp_config_check (peer->bgp, BGP_CONFIG_CONFEDERATION)
- && ! bgp_confederation_peers_check (peer->bgp, as)
- && peer->bgp->as != as)
- peer->local_as = peer->bgp->confed_id;
- else
- peer->local_as = peer->bgp->as;
-
- /* Advertisement-interval reset */
- conf = NULL;
- if (peer->group)
- conf = peer->group->conf;
-
- if (conf && CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV))
- {
- peer->v_routeadv = conf->routeadv;
- }
- /* Only go back to the default advertisement-interval if the user had not
- * already configured it */
- else if (!CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV))
- {
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- }
- /* TTL reset */
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->ttl = MAXTTL;
- else if (type == BGP_PEER_IBGP)
- peer->ttl = 1;
-
- /* reflector-client reset */
- if (peer_sort (peer) != BGP_PEER_IBGP)
- {
- UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_UNICAST],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MULTICAST],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP][SAFI_ENCAP],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_UNICAST],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MULTICAST],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_MPLS_VPN],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_IP6][SAFI_ENCAP],
- PEER_FLAG_REFLECTOR_CLIENT);
- UNSET_FLAG (peer->af_flags[AFI_L2VPN][SAFI_EVPN],
- PEER_FLAG_REFLECTOR_CLIENT);
- }
-
- /* local-as reset */
- if (peer_sort (peer) != BGP_PEER_EBGP)
- {
- peer->change_local_as = 0;
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- }
+void peer_as_change(struct peer *peer, as_t as, int as_specified)
+{
+ bgp_peer_sort_t type;
+ struct peer *conf;
+
+ /* Stop peer. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ }
+ type = peer_sort(peer);
+ peer->as = as;
+ peer->as_type = as_specified;
+
+ if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION)
+ && !bgp_confederation_peers_check(peer->bgp, as)
+ && peer->bgp->as != as)
+ peer->local_as = peer->bgp->confed_id;
+ else
+ peer->local_as = peer->bgp->as;
+
+ /* Advertisement-interval reset */
+ conf = NULL;
+ if (peer->group)
+ conf = peer->group->conf;
+
+ if (conf && CHECK_FLAG(conf->config, PEER_CONFIG_ROUTEADV)) {
+ peer->v_routeadv = conf->routeadv;
+ }
+ /* Only go back to the default advertisement-interval if the user had
+ * not
+ * already configured it */
+ else if (!CHECK_FLAG(peer->config, PEER_CONFIG_ROUTEADV)) {
+ if (peer_sort(peer) == BGP_PEER_IBGP)
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ }
+ /* TTL reset */
+ if (peer_sort(peer) == BGP_PEER_IBGP)
+ peer->ttl = MAXTTL;
+ else if (type == BGP_PEER_IBGP)
+ peer->ttl = 1;
+
+ /* reflector-client reset */
+ if (peer_sort(peer) != BGP_PEER_IBGP) {
+ UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_LABELED_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MPLS_VPN],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_ENCAP],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_MULTICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_LABELED_UNICAST],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_MPLS_VPN],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_IP6][SAFI_ENCAP],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ UNSET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN],
+ PEER_FLAG_REFLECTOR_CLIENT);
+ }
+
+ /* local-as reset */
+ if (peer_sort(peer) != BGP_PEER_EBGP) {
+ peer->change_local_as = 0;
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ }
}
/* If peer does not exist, create new one. If peer already exists,
set AS number to the peer. */
-int
-peer_remote_as (struct bgp *bgp, union sockunion *su, const char *conf_if,
- as_t *as, int as_type, afi_t afi, safi_t safi)
-{
- struct peer *peer;
- as_t local_as;
-
- if (conf_if)
- peer = peer_lookup_by_conf_if (bgp, conf_if);
- else
- peer = peer_lookup (bgp, su);
-
- 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)
- {
- if (peer->group->conf->as)
- {
- /* Return peer group's AS number. */
- *as = peer->group->conf->as;
- return BGP_ERR_PEER_GROUP_MEMBER;
- }
- if (peer_sort (peer->group->conf) == BGP_PEER_IBGP)
- {
- if ((as_type != AS_INTERNAL) && (bgp->as != *as))
- {
- *as = peer->as;
- return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
- }
- }
- else
- {
- if ((as_type != AS_EXTERNAL) && (bgp->as == *as))
- {
- *as = peer->as;
- return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
- }
- }
- }
-
- /* Existing peer's AS number change. */
- if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) ||
- (peer->as_type != as_type))
- peer_as_change (peer, *as, as_type);
- }
- else
- {
- if (conf_if)
- return BGP_ERR_NO_INTERFACE_CONFIG;
-
- /* If the peer is not part of our confederation, and its not an
- iBGP peer then spoof the source AS */
- if (bgp_config_check (bgp, BGP_CONFIG_CONFEDERATION)
- && ! bgp_confederation_peers_check (bgp, *as)
- && bgp->as != *as)
- local_as = bgp->confed_id;
- else
- local_as = bgp->as;
-
- /* If this is IPv4 unicast configuration and "no bgp default
- ipv4-unicast" is specified. */
-
- if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4)
- && afi == AFI_IP && safi == SAFI_UNICAST)
- peer_create (su, conf_if, bgp, local_as, *as, as_type, 0, 0, NULL);
- else
- peer_create (su, conf_if, bgp, local_as, *as, as_type, afi, safi, NULL);
- }
-
- return 0;
-}
-
-static int
-non_peergroup_activate_af (struct peer *peer, afi_t afi, safi_t safi)
-{
- int active;
-
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- zlog_err("%s was called for peer-group %s", __func__, peer->host);
- return 1;
- }
-
- /* Nothing to do if we've already activated this peer */
- if (peer->afc[afi][safi])
- return 0;
-
- if (peer_af_create(peer, afi, safi) == NULL)
- return 1;
-
- active = peer_active (peer);
- peer->afc[afi][safi] = 1;
-
- if (!active && peer_active (peer))
- {
- bgp_timer_set (peer);
- }
- else
- {
- if (peer->status == Established)
- {
- if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
- {
- peer->afc_adv[afi][safi] = 1;
- bgp_capability_send (peer, afi, safi,
- CAPABILITY_CODE_MP,
- CAPABILITY_ACTION_SET);
- if (peer->afc_recv[afi][safi])
- {
- peer->afc_nego[afi][safi] = 1;
- bgp_announce_route (peer, afi, safi);
- }
- }
- else
- {
- peer->last_reset = PEER_DOWN_AF_ACTIVATE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- }
-
- return 0;
-}
+int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if,
+ as_t *as, int as_type, afi_t afi, safi_t safi)
+{
+ struct peer *peer;
+ as_t local_as;
+
+ if (conf_if)
+ peer = peer_lookup_by_conf_if(bgp, conf_if);
+ else
+ peer = peer_lookup(bgp, su);
+
+ if (peer) {
+ /* Not allowed for a dynamic peer. */
+ if (peer_dynamic_neighbor(peer)) {
+ *as = peer->as;
+ return BGP_ERR_INVALID_FOR_DYNAMIC_PEER;
+ }
-/* Activate the peer or peer group for specified AFI and SAFI. */
-int
-peer_activate (struct peer *peer, afi_t afi, safi_t safi)
-{
- int ret = 0;
- struct peer_group *group;
- struct listnode *node, *nnode;
- struct peer *tmp_peer;
-
- /* Nothing to do if we've already activated this peer */
- if (peer->afc[afi][safi])
- return ret;
-
- /* This is a peer-group so activate all of the members of the
- * peer-group as well */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer->afc[afi][safi] = 1;
- group = peer->group;
-
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
- {
- ret |= non_peergroup_activate_af (tmp_peer, afi, safi);
- }
- }
- else
- {
- ret |= non_peergroup_activate_af (peer, afi, safi);
- }
-
- return ret;
-}
-
-static int
-non_peergroup_deactivate_af (struct peer *peer, afi_t afi, safi_t safi)
-{
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- zlog_err("%s was called for peer-group %s", __func__, peer->host);
- return 1;
- }
-
- /* Nothing to do if we've already deactivated this peer */
- if (! peer->afc[afi][safi])
- return 0;
-
- /* De-activate the address family configuration. */
- peer->afc[afi][safi] = 0;
-
- if (peer_af_delete(peer, afi, safi) != 0)
- {
- zlog_err("couldn't delete af structure for peer %s", peer->host);
- return 1;
- }
-
- if (peer->status == Established)
- {
- if (CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_RCV))
- {
- peer->afc_adv[afi][safi] = 0;
- peer->afc_nego[afi][safi] = 0;
-
- if (peer_active_nego (peer))
- {
- bgp_capability_send (peer, afi, safi,
- CAPABILITY_CODE_MP,
- CAPABILITY_ACTION_UNSET);
- bgp_clear_route (peer, afi, safi);
- peer->pcount[afi][safi] = 0;
- }
- else
- {
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
- else
- {
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- }
-
- return 0;
-}
-
-int
-peer_deactivate (struct peer *peer, afi_t afi, safi_t safi)
-{
- int ret = 0;
- struct peer_group *group;
- struct peer *tmp_peer;
- struct listnode *node, *nnode;
-
- /* Nothing to do if we've already de-activated this peer */
- if (! peer->afc[afi][safi])
- return ret;
-
- /* This is a peer-group so de-activate all of the members of the
- * peer-group as well */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer->afc[afi][safi] = 0;
- group = peer->group;
-
- if (peer_af_delete(peer, afi, safi) != 0)
- {
- zlog_err("couldn't delete af structure for peer %s", peer->host);
- }
-
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
- {
- ret |= non_peergroup_deactivate_af (tmp_peer, afi, safi);
- }
- }
- else
- {
- ret |= non_peergroup_deactivate_af (peer, afi, safi);
- }
-
- return ret;
-}
-
-int
-peer_afc_set (struct peer *peer, afi_t afi, safi_t safi, int enable)
-{
- if (enable)
- return peer_activate (peer, afi, safi);
- else
- return peer_deactivate (peer, afi, safi);
-}
-
-static void
-peer_nsf_stop (struct peer *peer)
-{
- afi_t afi;
- safi_t safi;
-
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);
- UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);
-
- for (afi = AFI_IP ; afi < AFI_MAX ; afi++)
- for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_4 ; safi++)
- peer->nsf[afi][safi] = 0;
-
- if (peer->t_gr_restart)
- {
- BGP_TIMER_OFF (peer->t_gr_restart);
- if (bgp_debug_neighbor_events(peer))
- zlog_debug ("%s graceful restart timer stopped", peer->host);
- }
- if (peer->t_gr_stale)
- {
- BGP_TIMER_OFF (peer->t_gr_stale);
- if (bgp_debug_neighbor_events(peer))
- zlog_debug ("%s graceful restart stalepath timer stopped", peer->host);
- }
- bgp_clear_route_all (peer);
-}
+ /* When this peer is a member of peer-group. */
+ if (peer->group) {
+ if (peer->group->conf->as) {
+ /* Return peer group's AS number. */
+ *as = peer->group->conf->as;
+ return BGP_ERR_PEER_GROUP_MEMBER;
+ }
+ if (peer_sort(peer->group->conf) == BGP_PEER_IBGP) {
+ if ((as_type != AS_INTERNAL)
+ && (bgp->as != *as)) {
+ *as = peer->as;
+ return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+ }
+ } else {
+ if ((as_type != AS_EXTERNAL)
+ && (bgp->as == *as)) {
+ *as = peer->as;
+ return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+ }
+ }
+ }
-/* Delete peer from confguration.
- *
- * The peer is moved to a dead-end "Deleted" neighbour-state, to allow
- * it to "cool off" and refcounts to hit 0, at which state it is freed.
- *
- * This function /should/ take care to be idempotent, to guard against
- * it being called multiple times through stray events that come in
- * that happen to result in this function being called again. That
- * said, getting here for a "Deleted" peer is a bug in the neighbour
- * FSM.
- */
-int
-peer_delete (struct peer *peer)
-{
- int i;
- afi_t afi;
- safi_t safi;
- struct bgp *bgp;
- struct bgp_filter *filter;
- struct listnode *pn;
- int accept_peer;
-
- assert (peer->status != Deleted);
-
- bgp = peer->bgp;
- accept_peer = CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_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)
- {
- 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 */
- list_delete_node (peer->group->peer, pn);
- }
- peer->group = NULL;
- }
-
- /* Withdraw all information from routing table. We can not use
- * BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is
- * executed after peer structure is deleted.
- */
- peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
- bgp_stop (peer);
- UNSET_FLAG(peer->flags, PEER_FLAG_DELETE);
-
- if (peer->doppelganger)
- {
- peer->doppelganger->doppelganger = NULL;
- peer->doppelganger = NULL;
- }
-
- UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
- bgp_fsm_change_status (peer, Deleted);
-
- /* Remove from NHT */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
- bgp_unlink_nexthop_by_peer (peer);
-
- /* Password configuration */
- if (peer->password)
- {
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
-
- if (!accept_peer &&
- ! BGP_PEER_SU_UNSPEC(peer) &&
- ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- bgp_md5_unset (peer);
- }
-
- bgp_timer_set (peer); /* stops all timers for Deleted */
-
- /* Delete from all peer list. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && (pn = listnode_lookup (bgp->peer, peer)))
- {
- peer_unlock (peer); /* bgp peer list reference */
- list_delete_node (bgp->peer, pn);
- hash_release(bgp->peerhash, peer);
- }
-
- /* Buffers. */
- if (peer->ibuf)
- {
- stream_free (peer->ibuf);
- peer->ibuf = NULL;
- }
-
- if (peer->obuf)
- {
- stream_fifo_free (peer->obuf);
- peer->obuf = NULL;
- }
-
- if (peer->work)
- {
- stream_free (peer->work);
- peer->work = NULL;
- }
-
- if (peer->scratch)
- {
- stream_free(peer->scratch);
- peer->scratch = NULL;
- }
-
- /* Local and remote addresses. */
- if (peer->su_local)
- {
- sockunion_free (peer->su_local);
- peer->su_local = NULL;
- }
-
- if (peer->su_remote)
- {
- sockunion_free (peer->su_remote);
- peer->su_remote = NULL;
- }
-
- /* Free filter related memory. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
+ /* Existing peer's AS number change. */
+ if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
+ || (peer->as_type != as_type))
+ peer_as_change(peer, *as, as_type);
+ } else {
+ if (conf_if)
+ return BGP_ERR_NO_INTERFACE_CONFIG;
+
+ /* If the peer is not part of our confederation, and its not an
+ iBGP peer then spoof the source AS */
+ if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION)
+ && !bgp_confederation_peers_check(bgp, *as)
+ && bgp->as != *as)
+ local_as = bgp->confed_id;
+ else
+ local_as = bgp->as;
+
+ /* If this is IPv4 unicast configuration and "no bgp default
+ ipv4-unicast" is specified. */
+
+ if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4)
+ && afi == AFI_IP && safi == SAFI_UNICAST)
+ peer_create(su, conf_if, bgp, local_as, *as, as_type, 0,
+ 0, NULL);
+ else
+ peer_create(su, conf_if, bgp, local_as, *as, as_type,
+ afi, safi, NULL);
+ }
- for (i = FILTER_IN; i < FILTER_MAX; i++)
- {
- if (filter->dlist[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[i].name);
- filter->dlist[i].name = NULL;
- }
-
- if (filter->plist[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[i].name);
- filter->plist[i].name = NULL;
- }
-
- if (filter->aslist[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[i].name);
- filter->aslist[i].name = NULL;
- }
- }
-
- for (i = RMAP_IN; i < RMAP_MAX; i++)
- {
- if (filter->map[i].name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[i].name);
- filter->map[i].name = NULL;
- }
- }
+ return 0;
+}
- if (filter->usmap.name)
- {
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = NULL;
- }
+static int non_peergroup_activate_af(struct peer *peer, afi_t afi, safi_t safi)
+{
+ int active;
- if (peer->default_rmap[afi][safi].name)
- {
- XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = NULL;
- }
- }
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ zlog_err("%s was called for peer-group %s", __func__,
+ peer->host);
+ return 1;
+ }
- FOREACH_AFI_SAFI (afi, safi)
- peer_af_delete (peer, afi, safi);
+ /* Do not activate a peer for both SAFI_UNICAST and SAFI_LABELED_UNICAST
+ */
+ if ((safi == SAFI_UNICAST && peer->afc[afi][SAFI_LABELED_UNICAST])
+ || (safi == SAFI_LABELED_UNICAST && peer->afc[afi][SAFI_UNICAST]))
+ return BGP_ERR_PEER_SAFI_CONFLICT;
+
+ /* Nothing to do if we've already activated this peer */
+ if (peer->afc[afi][safi])
+ return 0;
+
+ if (peer_af_create(peer, afi, safi) == NULL)
+ return 1;
+
+ active = peer_active(peer);
+ peer->afc[afi][safi] = 1;
+
+ if (!active && peer_active(peer)) {
+ bgp_timer_set(peer);
+ } else {
+ if (peer->status == Established) {
+ if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) {
+ peer->afc_adv[afi][safi] = 1;
+ bgp_capability_send(peer, afi, safi,
+ CAPABILITY_CODE_MP,
+ CAPABILITY_ACTION_SET);
+ if (peer->afc_recv[afi][safi]) {
+ peer->afc_nego[afi][safi] = 1;
+ bgp_announce_route(peer, afi, safi);
+ }
+ } else {
+ peer->last_reset = PEER_DOWN_AF_ACTIVATE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ }
+ }
- if (peer->hostname)
- {
- XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
- peer->hostname = NULL;
- }
+ return 0;
+}
- if (peer->domainname)
- {
- XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
- peer->domainname = NULL;
- }
-
- peer_unlock (peer); /* initial reference */
+/* Activate the peer or peer group for specified AFI and SAFI. */
+int peer_activate(struct peer *peer, afi_t afi, safi_t safi)
+{
+ int ret = 0;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer *tmp_peer;
+
+ /* Nothing to do if we've already activated this peer */
+ if (peer->afc[afi][safi])
+ return ret;
+
+ /* This is a peer-group so activate all of the members of the
+ * peer-group as well */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+
+ /* Do not activate a peer for both SAFI_UNICAST and
+ * SAFI_LABELED_UNICAST */
+ if ((safi == SAFI_UNICAST
+ && peer->afc[afi][SAFI_LABELED_UNICAST])
+ || (safi == SAFI_LABELED_UNICAST
+ && peer->afc[afi][SAFI_UNICAST]))
+ return BGP_ERR_PEER_SAFI_CONFLICT;
+
+ peer->afc[afi][safi] = 1;
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+ ret |= non_peergroup_activate_af(tmp_peer, afi, safi);
+ }
+ } else {
+ ret |= non_peergroup_activate_af(peer, afi, safi);
+ }
- return 0;
+ return ret;
}
-static int
-peer_group_cmp (struct peer_group *g1, struct peer_group *g2)
+static int non_peergroup_deactivate_af(struct peer *peer, afi_t afi,
+ safi_t safi)
{
- return strcmp (g1->name, g2->name);
-}
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ zlog_err("%s was called for peer-group %s", __func__,
+ peer->host);
+ return 1;
+ }
-/* Peer group cofiguration. */
-static struct peer_group *
-peer_group_new (void)
-{
- return (struct peer_group *) XCALLOC (MTYPE_PEER_GROUP,
- sizeof (struct peer_group));
-}
+ /* Nothing to do if we've already deactivated this peer */
+ if (!peer->afc[afi][safi])
+ return 0;
-static void
-peer_group_free (struct peer_group *group)
-{
- XFREE (MTYPE_PEER_GROUP, group);
-}
+ /* De-activate the address family configuration. */
+ peer->afc[afi][safi] = 0;
-struct peer_group *
-peer_group_lookup (struct bgp *bgp, const char *name)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
+ if (peer_af_delete(peer, afi, safi) != 0) {
+ zlog_err("couldn't delete af structure for peer %s",
+ peer->host);
+ return 1;
+ }
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- {
- if (strcmp (group->name, name) == 0)
- return group;
- }
- return NULL;
-}
+ if (peer->status == Established) {
+ if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) {
+ peer->afc_adv[afi][safi] = 0;
+ peer->afc_nego[afi][safi] = 0;
+
+ if (peer_active_nego(peer)) {
+ bgp_capability_send(peer, afi, safi,
+ CAPABILITY_CODE_MP,
+ CAPABILITY_ACTION_UNSET);
+ bgp_clear_route(peer, afi, safi);
+ peer->pcount[afi][safi] = 0;
+ } else {
+ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ } else {
+ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ }
-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)
- return group;
-
- group = peer_group_new ();
- group->bgp = bgp;
- if (group->name)
- XFREE(MTYPE_PEER_GROUP_HOST, group->name);
- group->name = XSTRDUP(MTYPE_PEER_GROUP_HOST, 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;
- if (group->conf->host)
- XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
- group->conf->host = XSTRDUP (MTYPE_BGP_PEER_HOST, name);
- group->conf->group = group;
- group->conf->as = 0;
- group->conf->ttl = 1;
- group->conf->gtsm_hops = 0;
- group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER);
- UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT);
- group->conf->keepalive = 0;
- group->conf->holdtime = 0;
- group->conf->connect = 0;
- SET_FLAG (group->conf->sflags, PEER_STATUS_GROUP);
- listnode_add_sort (bgp->group, group);
-
- return 0;
-}
-
-static void
-peer_group2peer_config_copy (struct peer_group *group, struct peer *peer)
-{
- struct peer *conf;
- int v6only;
-
- conf = group->conf;
-
- /* remote-as */
- if (conf->as)
- peer->as = conf->as;
-
- /* remote-as */
- if (conf->change_local_as)
- peer->change_local_as = conf->change_local_as;
-
- /* TTL */
- peer->ttl = conf->ttl;
-
- /* GTSM hops */
- peer->gtsm_hops = conf->gtsm_hops;
-
- /* this flag is per-neighbor and so has to be preserved */
- v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
-
- /* peer flags apply */
- peer->flags = conf->flags;
-
- if (v6only)
- SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
-
- /* peer config apply */
- peer->config = conf->config;
-
- /* peer timers apply */
- peer->holdtime = conf->holdtime;
- peer->keepalive = conf->keepalive;
- peer->connect = conf->connect;
- if (CHECK_FLAG (conf->config, PEER_CONFIG_CONNECT))
- peer->v_connect = conf->connect;
- else
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
-
- /* advertisement-interval reset */
- if (CHECK_FLAG (conf->config, PEER_CONFIG_ROUTEADV))
- peer->v_routeadv = conf->routeadv;
- else
- if (peer_sort (peer) == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
- /* password apply */
- if (conf->password && !peer->password)
- peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, conf->password);
-
- if (! BGP_PEER_SU_UNSPEC(peer))
- bgp_md5_set (peer);
-
- /* update-source apply */
- if (conf->update_source)
- {
- if (peer->update_source)
- sockunion_free (peer->update_source);
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
- peer->update_source = sockunion_dup (conf->update_source);
- }
- else if (conf->update_if)
- {
- if (peer->update_if)
- XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
- }
- peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, conf->update_if);
- }
-
- bgp_bfd_peer_group2peer_copy(conf, peer);
-}
-
-static void
-peer_group2peer_config_copy_af (struct peer_group *group, struct peer *peer,
- afi_t afi, safi_t safi)
-{
- int in = FILTER_IN;
- int out = FILTER_OUT;
- struct peer *conf;
- struct bgp_filter *pfilter;
- struct bgp_filter *gfilter;
-
- conf = group->conf;
- pfilter = &peer->filter[afi][safi];
- gfilter = &conf->filter[afi][safi];
-
- /* peer af_flags apply */
- peer->af_flags[afi][safi] = conf->af_flags[afi][safi];
-
- /* maximum-prefix */
- peer->pmax[afi][safi] = conf->pmax[afi][safi];
- peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi];
- peer->pmax_restart[afi][safi] = conf->pmax_restart[afi][safi];
-
- /* allowas-in */
- peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi];
-
- /* weight */
- peer->weight[afi][safi] = conf->weight[afi][safi];
-
- /* default-originate route-map */
- if (conf->default_rmap[afi][safi].name)
- {
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_BGP_FILTER_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, conf->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].map = conf->default_rmap[afi][safi].map;
- }
-
- /* inbound filter apply */
- if (gfilter->dlist[in].name && ! pfilter->dlist[in].name)
- {
- if (pfilter->dlist[in].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[in].name);
- pfilter->dlist[in].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->dlist[in].name);
- pfilter->dlist[in].alist = gfilter->dlist[in].alist;
- }
-
- if (gfilter->plist[in].name && ! pfilter->plist[in].name)
- {
- if (pfilter->plist[in].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[in].name);
- pfilter->plist[in].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[in].name);
- pfilter->plist[in].plist = gfilter->plist[in].plist;
- }
-
- if (gfilter->aslist[in].name && ! pfilter->aslist[in].name)
- {
- if (pfilter->aslist[in].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[in].name);
- pfilter->aslist[in].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->aslist[in].name);
- pfilter->aslist[in].aslist = gfilter->aslist[in].aslist;
- }
-
- if (gfilter->map[RMAP_IN].name && ! pfilter->map[RMAP_IN].name)
- {
- if (pfilter->map[RMAP_IN].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->map[RMAP_IN].name);
- pfilter->map[RMAP_IN].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_IN].name);
- pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map;
- }
-
- /* outbound filter apply */
- if (gfilter->dlist[out].name)
- {
- if (pfilter->dlist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
- pfilter->dlist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->dlist[out].name);
- pfilter->dlist[out].alist = gfilter->dlist[out].alist;
- }
- else
- {
- if (pfilter->dlist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
- pfilter->dlist[out].name = NULL;
- pfilter->dlist[out].alist = NULL;
- }
-
- if (gfilter->plist[out].name)
- {
- if (pfilter->plist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
- pfilter->plist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[out].name);
- pfilter->plist[out].plist = gfilter->plist[out].plist;
- }
- else
- {
- if (pfilter->plist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
- pfilter->plist[out].name = NULL;
- pfilter->plist[out].plist = NULL;
- }
-
- if (gfilter->aslist[out].name)
- {
- if (pfilter->aslist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
- pfilter->aslist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->aslist[out].name);
- pfilter->aslist[out].aslist = gfilter->aslist[out].aslist;
- }
- else
- {
- if (pfilter->aslist[out].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
- pfilter->aslist[out].name = NULL;
- pfilter->aslist[out].aslist = NULL;
- }
-
- if (gfilter->map[RMAP_OUT].name)
- {
- if (pfilter->map[RMAP_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->map[RMAP_OUT].name);
- pfilter->map[RMAP_OUT].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_OUT].name);
- pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map;
- }
- else
- {
- if (pfilter->map[RMAP_OUT].name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->map[RMAP_OUT].name);
- pfilter->map[RMAP_OUT].name = NULL;
- pfilter->map[RMAP_OUT].map = NULL;
- }
-
- if (gfilter->usmap.name)
- {
- if (pfilter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
- pfilter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->usmap.name);
- pfilter->usmap.map = gfilter->usmap.map;
- }
- else
- {
- if (pfilter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
- pfilter->usmap.name = NULL;
- pfilter->usmap.map = NULL;
- }
-}
+ return 0;
+}
-/* Peer group's remote AS configuration. */
-int
-peer_group_remote_as (struct bgp *bgp, const char *group_name,
- as_t *as, int as_type)
+int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer_group *group;
- struct peer *peer;
- struct listnode *node, *nnode;
+ int ret = 0;
+ struct peer_group *group;
+ struct peer *tmp_peer;
+ struct listnode *node, *nnode;
- group = peer_group_lookup (bgp, group_name);
- if (! group)
- return -1;
+ /* Nothing to do if we've already de-activated this peer */
+ if (!peer->afc[afi][safi])
+ return ret;
- if ((as_type == group->conf->as_type) && (group->conf->as == *as))
- return 0;
+ /* This is a peer-group so de-activate all of the members of the
+ * peer-group as well */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer->afc[afi][safi] = 0;
+ group = peer->group;
+ if (peer_af_delete(peer, afi, safi) != 0) {
+ zlog_err("couldn't delete af structure for peer %s",
+ peer->host);
+ }
- /* When we setup peer-group AS number all peer group member's AS
- number must be updated to same number. */
- peer_as_change (group->conf, *as, as_type);
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+ ret |= non_peergroup_deactivate_af(tmp_peer, afi, safi);
+ }
+ } else {
+ ret |= non_peergroup_deactivate_af(peer, afi, safi);
+ }
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (((peer->as_type == AS_SPECIFIED) && peer->as != *as) ||
- (peer->as_type != as_type))
- peer_as_change (peer, *as, as_type);
- }
+ return ret;
+}
- return 0;
+int peer_afc_set(struct peer *peer, afi_t afi, safi_t safi, int enable)
+{
+ if (enable)
+ return peer_activate(peer, afi, safi);
+ else
+ return peer_deactivate(peer, afi, safi);
}
-int
-peer_group_delete (struct peer_group *group)
+static void peer_nsf_stop(struct peer *peer)
{
- struct bgp *bgp;
- struct peer *peer;
- struct prefix *prefix;
- struct peer *other;
- struct listnode *node, *nnode;
- afi_t afi;
+ afi_t afi;
+ safi_t safi;
- bgp = group->bgp;
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- other = peer->doppelganger;
- peer_delete (peer);
- if (other && other->status != Deleted)
- {
- other->group = NULL;
- peer_delete(other);
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++)
+ peer->nsf[afi][safi] = 0;
+
+ if (peer->t_gr_restart) {
+ BGP_TIMER_OFF(peer->t_gr_restart);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s graceful restart timer stopped",
+ peer->host);
+ }
+ if (peer->t_gr_stale) {
+ BGP_TIMER_OFF(peer->t_gr_stale);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s graceful restart stalepath timer stopped",
+ peer->host);
}
- }
- list_delete (group->peer);
+ bgp_clear_route_all(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]);
- }
+/* Delete peer from confguration.
+ *
+ * The peer is moved to a dead-end "Deleted" neighbour-state, to allow
+ * it to "cool off" and refcounts to hit 0, at which state it is freed.
+ *
+ * This function /should/ take care to be idempotent, to guard against
+ * it being called multiple times through stray events that come in
+ * that happen to result in this function being called again. That
+ * said, getting here for a "Deleted" peer is a bug in the neighbour
+ * FSM.
+ */
+int peer_delete(struct peer *peer)
+{
+ int i;
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+ struct bgp_filter *filter;
+ struct listnode *pn;
+ int accept_peer;
- XFREE(MTYPE_PEER_GROUP_HOST, group->name);
- group->name = NULL;
+ assert(peer->status != Deleted);
- bfd_info_free(&(group->conf->bfd_info));
+ bgp = peer->bgp;
+ accept_peer = CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
- group->conf->group = NULL;
- peer_delete (group->conf);
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop(peer);
- /* Delete from all peer_group list. */
- listnode_delete (bgp->group, group);
+ SET_FLAG(peer->flags, PEER_FLAG_DELETE);
- peer_group_free (group);
+ /* If this peer belongs to peer group, clear up the
+ relationship. */
+ if (peer->group) {
+ if (peer_dynamic_neighbor(peer))
+ peer_drop_dynamic_neighbor(peer);
- return 0;
-}
+ if ((pn = listnode_lookup(peer->group->peer, peer))) {
+ peer = peer_unlock(
+ peer); /* group->peer list reference */
+ list_delete_node(peer->group->peer, pn);
+ }
+ peer->group = NULL;
+ }
-int
-peer_group_remote_as_delete (struct peer_group *group)
-{
- struct peer *peer, *other;
- struct listnode *node, *nnode;
+ /* Withdraw all information from routing table. We can not use
+ * BGP_EVENT_ADD (peer, BGP_Stop) at here. Because the event is
+ * executed after peer structure is deleted.
+ */
+ peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE;
+ bgp_stop(peer);
+ UNSET_FLAG(peer->flags, PEER_FLAG_DELETE);
+
+ if (peer->doppelganger) {
+ peer->doppelganger->doppelganger = NULL;
+ peer->doppelganger = NULL;
+ }
- if ((group->conf->as_type == AS_UNSPECIFIED) ||
- ((! group->conf->as) && (group->conf->as_type == AS_SPECIFIED)))
- return 0;
+ UNSET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
+ bgp_fsm_change_status(peer, Deleted);
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- other = peer->doppelganger;
+ /* Remove from NHT */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ bgp_unlink_nexthop_by_peer(peer);
- peer_delete (peer);
+ /* Password configuration */
+ if (peer->password) {
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+ peer->password = NULL;
- if (other && other->status != Deleted)
- {
- other->group = NULL;
- peer_delete(other);
+ if (!accept_peer && !BGP_PEER_SU_UNSPEC(peer)
+ && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ bgp_md5_unset(peer);
}
- }
- list_delete_all_node (group->peer);
-
- group->conf->as = 0;
- group->conf->as_type = AS_UNSPECIFIED;
-
- 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_type == AS_UNSPECIFIED)
- 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 0;
- }
+ bgp_timer_set(peer); /* stops all timers for Deleted */
- 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[PREFIX2STR_BUFFER];
-
- 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));
+ /* Delete from all peer list. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && (pn = listnode_lookup(bgp->peer, peer))) {
+ peer_unlock(peer); /* bgp peer list reference */
+ list_delete_node(bgp->peer, pn);
+ hash_release(bgp->peerhash, peer);
+ }
- /* 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;
+ /* Buffers. */
+ if (peer->ibuf) {
+ stream_free(peer->ibuf);
+ peer->ibuf = NULL;
+ }
- sockunion2hostprefix(&peer->su, &prefix2);
- 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);
- }
- }
+ if (peer->obuf) {
+ stream_fifo_free(peer->obuf);
+ peer->obuf = NULL;
+ }
- /* Get rid of the listen range */
- listnode_delete(group->listen_range[afi], prefix);
+ if (peer->work) {
+ stream_free(peer->work);
+ peer->work = NULL;
+ }
- return 0;
-}
+ if (peer->scratch) {
+ stream_free(peer->scratch);
+ peer->scratch = NULL;
+ }
-/* Bind specified peer to peer group. */
-int
-peer_group_bind (struct bgp *bgp, union sockunion *su, struct peer *peer,
- struct peer_group *group, as_t *as)
-{
- int first_member = 0;
- afi_t afi;
- safi_t safi;
- int cap_enhe_preset = 0;
-
- /* Lookup the peer. */
- if (!peer)
- peer = peer_lookup (bgp, su);
-
- /* The peer exist, bind it to the peer-group */
- if (peer)
- {
- /* When the peer already belongs to peer group, check the consistency. */
- if (peer_group_active (peer) && strcmp (peer->group->name, group->name) != 0)
- return BGP_ERR_PEER_GROUP_CANT_CHANGE;
-
- /* The peer has not specified a remote-as, inherit it from the
- * peer-group */
- if (peer->as_type == AS_UNSPECIFIED)
- {
- peer->as_type = group->conf->as_type;
- peer->as = group->conf->as;
- }
-
- if (! group->conf->as)
- {
- if (peer_sort (group->conf) != BGP_PEER_INTERNAL
- && peer_sort (group->conf) != peer_sort (peer))
- {
- if (as)
- *as = peer->as;
- return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
- }
-
- if (peer_sort (group->conf) == BGP_PEER_INTERNAL)
- first_member = 1;
- }
-
- if (CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- cap_enhe_preset = 1;
-
- peer_group2peer_config_copy(group, peer);
-
- /*
- * Capability extended-nexthop is enabled for an interface neighbor by
- * default. So, fix that up here.
- */
- if (peer->conf_if && cap_enhe_preset)
- peer_flag_set (peer, PEER_FLAG_CAPABILITY_ENHE);
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (group->conf->afc[afi][safi])
- {
- peer->afc[afi][safi] = 1;
-
- if (peer_af_find(peer, afi, safi) || peer_af_create(peer, afi, safi))
- {
- peer_group2peer_config_copy_af (group, peer, afi, safi);
- }
- }
- }
-
- if (peer->group)
- {
- assert (group && peer->group == group);
- }
- else
- {
- struct listnode *pn;
- pn = listnode_lookup (bgp->peer, peer);
- list_delete_node (bgp->peer, pn);
- peer->group = group;
- listnode_add_sort (bgp->peer, peer);
-
- peer = peer_lock (peer); /* group->peer list reference */
- listnode_add (group->peer, peer);
- }
-
- if (first_member)
- {
- /* Advertisement-interval reset */
- if (! CHECK_FLAG (group->conf->config, PEER_CONFIG_ROUTEADV))
- {
- if (peer_sort (group->conf) == BGP_PEER_IBGP)
- group->conf->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- }
-
- /* ebgp-multihop reset */
- if (peer_sort (group->conf) == BGP_PEER_IBGP)
- group->conf->ttl = MAXTTL;
-
- /* local-as reset */
- if (peer_sort (group->conf) != BGP_PEER_EBGP)
- {
- group->conf->change_local_as = 0;
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- }
- }
-
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_RMAP_BIND;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- {
- bgp_session_reset(peer);
- }
- }
-
- /* Create a new peer. */
- else
- {
- if ((group->conf->as_type == AS_SPECIFIED) && (! group->conf->as))
- {
- return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
- }
-
- peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, group->conf->as_type, 0, 0, group);
-
- peer = peer_lock (peer); /* group->peer list reference */
- listnode_add (group->peer, peer);
-
- peer_group2peer_config_copy(group, peer);
-
- /* If the peer-group is active for this afi/safi then activate for this peer */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- if (group->conf->afc[afi][safi])
- {
- peer->afc[afi][safi] = 1;
- peer_af_create(peer, afi, safi);
- peer_group2peer_config_copy_af (group, peer, afi, safi);
- }
-
- SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-
- /* Set up peer's events and timers. */
- if (peer_active (peer))
- bgp_timer_set (peer);
- }
-
- return 0;
-}
-
-int
-peer_group_unbind (struct bgp *bgp, struct peer *peer,
- struct peer_group *group)
-{
- struct peer *other;
- afi_t afi;
- safi_t safi;
-
- if (group != peer->group)
- return BGP_ERR_PEER_GROUP_MISMATCH;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (peer->afc[afi][safi])
- {
- peer->afc[afi][safi] = 0;
- peer_af_flag_reset (peer, afi, safi);
-
- if (peer_af_delete(peer, afi, safi) != 0)
- {
- zlog_err("couldn't delete af structure for peer %s", peer->host);
- }
- }
- }
-
- assert (listnode_lookup (group->peer, peer));
- peer_unlock (peer); /* peer group list reference */
- listnode_delete (group->peer, peer);
- peer->group = NULL;
- other = peer->doppelganger;
-
- if (group->conf->as)
- {
- peer_delete (peer);
- if (other && other->status != Deleted)
- {
- if (other->group)
- {
- peer_unlock(other);
- listnode_delete(group->peer, other);
- }
- other->group = NULL;
- peer_delete(other);
- }
- return 0;
- }
-
- bgp_bfd_deregister_peer(peer);
- peer_global_config_reset (peer);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_RMAP_UNBIND;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
-
- return 0;
-}
-
-static int
-bgp_startup_timer_expire (struct thread *thread)
-{
- struct bgp *bgp;
-
- bgp = THREAD_ARG (thread);
- bgp->t_startup = NULL;
-
- return 0;
-}
+ /* Local and remote addresses. */
+ if (peer->su_local) {
+ sockunion_free(peer->su_local);
+ peer->su_local = NULL;
+ }
-/* BGP instance creation by `router bgp' commands. */
-static struct bgp *
-bgp_create (as_t *as, const char *name, enum bgp_instance_type inst_type)
-{
- struct bgp *bgp;
- afi_t afi;
- safi_t safi;
-
- if ( (bgp = XCALLOC (MTYPE_BGP, sizeof (struct bgp))) == NULL)
- return NULL;
-
- if (BGP_DEBUG (zebra, ZEBRA))
- {
- if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
- zlog_debug("Creating Default VRF, AS %u", *as);
- else
- zlog_debug("Creating %s %s, AS %u",
- (inst_type == BGP_INSTANCE_TYPE_VRF) ? "VRF" : "VIEW",
- name, *as);
- }
-
- bgp_lock (bgp);
- bgp->inst_type = inst_type;
- bgp->vrf_id = (inst_type == BGP_INSTANCE_TYPE_DEFAULT) ?
- VRF_DEFAULT : VRF_UNKNOWN;
- bgp->peer_self = peer_new (bgp);
- if (bgp->peer_self->host)
- XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
- bgp->peer_self->host = XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
- bgp->peer = list_new ();
- bgp->peer->cmp = (int (*)(void *, void *)) peer_cmp;
- bgp->peerhash = hash_create (peer_hash_key_make, peer_hash_cmp);
-
- bgp->group = list_new ();
- bgp->group->cmp = (int (*)(void *, void *)) peer_group_cmp;
-
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- bgp->route[afi][safi] = bgp_table_init (afi, safi);
- bgp->aggregate[afi][safi] = bgp_table_init (afi, safi);
- bgp->rib[afi][safi] = bgp_table_init (afi, safi);
-
- /* Enable maximum-paths */
- bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_EBGP, multipath_num, 0);
- bgp_maximum_paths_set (bgp, afi, safi, BGP_PEER_IBGP, multipath_num, 0);
- }
-
- bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
- bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
- bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
- bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
- 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;
-#if DFLT_BGP_IMPORT_CHECK
- bgp_flag_set (bgp, BGP_FLAG_IMPORT_CHECK);
-#endif
-#if DFLT_BGP_SHOW_HOSTNAME
- bgp_flag_set (bgp, BGP_FLAG_SHOW_HOSTNAME);
-#endif
-#if DFLT_BGP_LOG_NEIGHBOR_CHANGES
- bgp_flag_set (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
-#endif
-#if DFLT_BGP_DETERMINISTIC_MED
- bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
-#endif
- bgp->addpath_tx_id = BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE;
+ if (peer->su_remote) {
+ sockunion_free(peer->su_remote);
+ peer->su_remote = NULL;
+ }
- bgp->as = *as;
+ /* Free filter related memory. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ filter = &peer->filter[afi][safi];
+
+ for (i = FILTER_IN; i < FILTER_MAX; i++) {
+ if (filter->dlist[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->dlist[i].name);
+ filter->dlist[i].name = NULL;
+ }
+
+ if (filter->plist[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->plist[i].name);
+ filter->plist[i].name = NULL;
+ }
+
+ if (filter->aslist[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->aslist[i].name);
+ filter->aslist[i].name = NULL;
+ }
+ }
+
+ for (i = RMAP_IN; i < RMAP_MAX; i++) {
+ if (filter->map[i].name) {
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->map[i].name);
+ filter->map[i].name = NULL;
+ }
+ }
+
+ if (filter->usmap.name) {
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->usmap.name);
+ filter->usmap.name = NULL;
+ }
+
+ if (peer->default_rmap[afi][safi].name) {
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name = NULL;
+ }
+ }
-#if ENABLE_BGP_VNC
- if (inst_type != BGP_INSTANCE_TYPE_VRF)
- {
- bgp->rfapi = bgp_rfapi_new(bgp);
- assert(bgp->rfapi);
- assert(bgp->rfapi_cfg);
- }
-#endif /* ENABLE_BGP_VNC */
+ FOREACH_AFI_SAFI(afi, safi)
+ peer_af_delete(peer, afi, safi);
- if (name)
- {
- bgp->name = XSTRDUP(MTYPE_BGP, name);
- }
- else
- {
- /* TODO - The startup timer needs to be run for the whole of BGP */
- thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
- bgp->restart_time, &bgp->t_startup);
- }
+ if (peer->hostname) {
+ XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
+ peer->hostname = NULL;
+ }
- bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
- bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
+ if (peer->domainname) {
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+ peer->domainname = NULL;
+ }
- QOBJ_REG (bgp, bgp);
+ peer_unlock(peer); /* initial reference */
- update_bgp_group_init(bgp);
- return bgp;
+ return 0;
}
-/* Return the "default VRF" instance of BGP. */
-struct bgp *
-bgp_get_default (void)
+static int peer_group_cmp(struct peer_group *g1, struct peer_group *g2)
{
- struct bgp *bgp;
- struct listnode *node, *nnode;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
- if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
- return bgp;
- return NULL;
+ return strcmp(g1->name, g2->name);
}
-/* Lookup BGP entry. */
-struct bgp *
-bgp_lookup (as_t as, const char *name)
+/* Peer group cofiguration. */
+static struct peer_group *peer_group_new(void)
{
- struct bgp *bgp;
- struct listnode *node, *nnode;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
- if (bgp->as == as
- && ((bgp->name == NULL && name == NULL)
- || (bgp->name && name && strcmp (bgp->name, name) == 0)))
- return bgp;
- return NULL;
+ return (struct peer_group *)XCALLOC(MTYPE_PEER_GROUP,
+ sizeof(struct peer_group));
}
-/* Lookup BGP structure by view name. */
-struct bgp *
-bgp_lookup_by_name (const char *name)
+static void peer_group_free(struct peer_group *group)
{
- struct bgp *bgp;
- struct listnode *node, *nnode;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, node, nnode, bgp))
- if ((bgp->name == NULL && name == NULL)
- || (bgp->name && name && strcmp (bgp->name, name) == 0))
- return bgp;
- return NULL;
+ XFREE(MTYPE_PEER_GROUP, group);
}
-/* Lookup BGP instance based on VRF id. */
-/* Note: Only to be used for incoming messages from Zebra. */
-struct bgp *
-bgp_lookup_by_vrf_id (vrf_id_t vrf_id)
+struct peer_group *peer_group_lookup(struct bgp *bgp, const char *name)
{
- struct vrf *vrf;
-
- /* Lookup VRF (in tree) and follow link. */
- vrf = vrf_lookup_by_id (vrf_id);
- if (!vrf)
- return NULL;
- return (vrf->info) ? (struct bgp *)vrf->info : NULL;
-}
+ struct peer_group *group;
+ struct listnode *node, *nnode;
-/* Called from VTY commands. */
-int
-bgp_get (struct bgp **bgp_val, as_t *as, const char *name,
- enum bgp_instance_type inst_type)
-{
- struct bgp *bgp;
-
- /* Multiple instance check. */
- if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
- {
- if (name)
- bgp = bgp_lookup_by_name (name);
- else
- bgp = bgp_get_default ();
-
- /* Already exists. */
- if (bgp)
- {
- if (bgp->as != *as)
- {
- *as = bgp->as;
- return BGP_ERR_INSTANCE_MISMATCH;
- }
- if (bgp->inst_type != inst_type)
- return BGP_ERR_INSTANCE_MISMATCH;
- *bgp_val = bgp;
- return 0;
- }
- }
- else
- {
- /* BGP instance name can not be specified for single instance. */
- if (name)
- return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET;
-
- /* Get default BGP structure if exists. */
- bgp = bgp_get_default ();
-
- if (bgp)
- {
- if (bgp->as != *as)
- {
- *as = bgp->as;
- return BGP_ERR_AS_MISMATCH;
- }
- *bgp_val = bgp;
- return 0;
+ for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
+ if (strcmp(group->name, name) == 0)
+ return group;
}
- }
-
- bgp = bgp_create (as, name, inst_type);
- bgp_router_id_set(bgp, &bgp->router_id_zebra);
- bgp_address_init (bgp);
- bgp_scan_init (bgp);
- *bgp_val = bgp;
-
- bgp->t_rmap_def_originate_eval = NULL;
+ return NULL;
+}
+
+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)
+ return group;
+
+ group = peer_group_new();
+ group->bgp = bgp;
+ if (group->name)
+ XFREE(MTYPE_PEER_GROUP_HOST, group->name);
+ group->name = XSTRDUP(MTYPE_PEER_GROUP_HOST, 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;
+ if (group->conf->host)
+ XFREE(MTYPE_BGP_PEER_HOST, group->conf->host);
+ group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name);
+ group->conf->group = group;
+ group->conf->as = 0;
+ group->conf->ttl = 1;
+ group->conf->gtsm_hops = 0;
+ group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+ UNSET_FLAG(group->conf->config, PEER_CONFIG_TIMER);
+ UNSET_FLAG(group->conf->config, PEER_CONFIG_CONNECT);
+ group->conf->keepalive = 0;
+ group->conf->holdtime = 0;
+ group->conf->connect = 0;
+ SET_FLAG(group->conf->sflags, PEER_STATUS_GROUP);
+ listnode_add_sort(bgp->group, group);
- /* Create BGP server socket, if first instance. */
- if (list_isempty(bm->bgp)
- && !bgp_option_check (BGP_OPT_NO_LISTEN))
- {
- if (bgp_socket (bm->port, bm->address) < 0)
- return BGP_ERR_INVALID_VALUE;
- }
-
- listnode_add (bm->bgp, bgp);
-
- /* If Default instance or VRF, link to the VRF structure, if present. */
- if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ||
- bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- {
- struct vrf *vrf;
-
- vrf = bgp_vrf_lookup_by_instance_type (bgp);
- if (vrf)
- bgp_vrf_link (bgp, vrf);
- }
-
- /* Register with Zebra, if needed */
- if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
- bgp_zebra_instance_register (bgp);
-
-
- return 0;
+ return group;
}
-/*
- * Make BGP instance "up". Applies only to VRFs (non-default) and
- * implies the VRF has been learnt from Zebra.
- */
-void
-bgp_instance_up (struct bgp *bgp)
+static void peer_group2peer_config_copy(struct peer_group *group,
+ struct peer *peer)
{
- struct peer *peer;
- struct listnode *node, *next;
-
- /* Register with zebra. */
- bgp_zebra_instance_register (bgp);
+ struct peer *conf;
+ int v6only;
- /* Kick off any peers that may have been configured. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- {
- if (!BGP_PEER_START_SUPPRESSED (peer))
- BGP_EVENT_ADD (peer, BGP_Start);
- }
+ conf = group->conf;
- /* Process any networks that have been configured. */
- bgp_static_add (bgp);
-}
-
-/*
- * Make BGP instance "down". Applies only to VRFs (non-default) and
- * implies the VRF has been deleted by Zebra.
- */
-void
-bgp_instance_down (struct bgp *bgp)
-{
- struct peer *peer;
- struct listnode *node;
- struct listnode *next;
+ /* remote-as */
+ if (conf->as)
+ peer->as = conf->as;
- /* Stop timers. */
- if (bgp->t_rmap_def_originate_eval)
- {
- BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
- bgp_unlock(bgp); /* TODO - This timer is started with a lock - why? */
- }
+ /* remote-as */
+ if (conf->change_local_as)
+ peer->change_local_as = conf->change_local_as;
- /* Bring down peers, so corresponding routes are purged. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- else
- bgp_session_reset(peer);
- }
+ /* TTL */
+ peer->ttl = conf->ttl;
- /* Purge network and redistributed routes. */
- bgp_purge_static_redist_routes (bgp);
-}
+ /* GTSM hops */
+ peer->gtsm_hops = conf->gtsm_hops;
-/* Delete BGP instance. */
-int
-bgp_delete (struct bgp *bgp)
-{
- struct peer *peer;
- struct peer_group *group;
- struct listnode *node, *next;
- struct vrf *vrf;
- afi_t afi;
- int i;
-
- THREAD_OFF (bgp->t_startup);
-
- if (BGP_DEBUG (zebra, ZEBRA))
- {
- if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
- zlog_debug("Deleting Default VRF");
- else
- zlog_debug("Deleting %s %s",
- (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) ? "VRF" : "VIEW",
- bgp->name);
- }
-
- /* Stop timers. */
- if (bgp->t_rmap_def_originate_eval)
- {
- BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
- bgp_unlock(bgp); /* TODO - This timer is started with a lock - why? */
- }
-
- /* Inform peers we're going down. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
-
- /* Delete static routes (networks). */
- bgp_static_delete (bgp);
-
- /* Unset redistribution. */
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
- if (i != ZEBRA_ROUTE_BGP)
- bgp_redistribute_unset (bgp, afi, i, 0);
-
- /* Free peers and peer-groups. */
- for (ALL_LIST_ELEMENTS (bgp->group, node, next, group))
- peer_group_delete (group);
-
- for (ALL_LIST_ELEMENTS (bgp->peer, node, next, peer))
- peer_delete (peer);
-
- if (bgp->peer_self) {
- peer_delete(bgp->peer_self);
- bgp->peer_self = NULL;
- }
-
- update_bgp_group_free (bgp);
-
- /* TODO - Other memory may need to be freed - e.g., NHT */
+ /* this flag is per-neighbor and so has to be preserved */
+ v6only = CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
-#if ENABLE_BGP_VNC
- rfapi_delete(bgp);
-#endif
- bgp_cleanup_routes(bgp);
+ /* peer flags apply */
+ peer->flags = conf->flags;
- /* Remove visibility via the master list - there may however still be
- * routes to be processed still referencing the struct bgp.
- */
- listnode_delete (bm->bgp, bgp);
+ if (v6only)
+ SET_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY);
- /* Deregister from Zebra, if needed */
- if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
- bgp_zebra_instance_deregister (bgp);
+ /* peer config apply */
+ peer->config = conf->config;
- /* Free interfaces in this instance. */
- bgp_if_finish (bgp);
+ /* peer timers apply */
+ peer->holdtime = conf->holdtime;
+ peer->keepalive = conf->keepalive;
+ peer->connect = conf->connect;
+ if (CHECK_FLAG(conf->config, PEER_CONFIG_CONNECT))
+ peer->v_connect = conf->connect;
+ else
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- vrf = bgp_vrf_lookup_by_instance_type (bgp);
- if (vrf)
- bgp_vrf_unlink (bgp, vrf);
+ /* advertisement-interval reset */
+ if (CHECK_FLAG(conf->config, PEER_CONFIG_ROUTEADV))
+ peer->v_routeadv = conf->routeadv;
+ else if (peer_sort(peer) == BGP_PEER_IBGP)
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
- thread_master_free_unused(bm->master);
- bgp_unlock(bgp); /* initial reference */
+ /* password apply */
+ if (conf->password && !peer->password)
+ peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, conf->password);
- return 0;
-}
+ if (!BGP_PEER_SU_UNSPEC(peer))
+ bgp_md5_set(peer);
-static void bgp_free (struct bgp *);
+ /* update-source apply */
+ if (conf->update_source) {
+ if (peer->update_source)
+ sockunion_free(peer->update_source);
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+ peer->update_source = sockunion_dup(conf->update_source);
+ } else if (conf->update_if) {
+ if (peer->update_if)
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+ peer->update_if =
+ XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, conf->update_if);
+ }
-void
-bgp_lock (struct bgp *bgp)
-{
- ++bgp->lock;
+ bgp_bfd_peer_group2peer_copy(conf, peer);
}
-void
-bgp_unlock(struct bgp *bgp)
+static void peer_group2peer_config_copy_af(struct peer_group *group,
+ struct peer *peer, afi_t afi,
+ safi_t safi)
{
- assert(bgp->lock > 0);
- if (--bgp->lock == 0)
- bgp_free (bgp);
-}
+ int in = FILTER_IN;
+ int out = FILTER_OUT;
+ struct peer *conf;
+ struct bgp_filter *pfilter;
+ struct bgp_filter *gfilter;
-static void
-bgp_free (struct bgp *bgp)
-{
- afi_t afi;
- safi_t safi;
+ conf = group->conf;
+ pfilter = &peer->filter[afi][safi];
+ gfilter = &conf->filter[afi][safi];
- QOBJ_UNREG (bgp);
+ /* peer af_flags apply */
+ peer->af_flags[afi][safi] = conf->af_flags[afi][safi];
- list_delete (bgp->group);
- list_delete (bgp->peer);
+ /* maximum-prefix */
+ peer->pmax[afi][safi] = conf->pmax[afi][safi];
+ peer->pmax_threshold[afi][safi] = conf->pmax_threshold[afi][safi];
+ peer->pmax_restart[afi][safi] = conf->pmax_restart[afi][safi];
- if (bgp->peerhash)
- {
- hash_free(bgp->peerhash);
- bgp->peerhash = NULL;
- }
+ /* allowas-in */
+ peer->allowas_in[afi][safi] = conf->allowas_in[afi][safi];
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- if (bgp->route[afi][safi])
- bgp_table_finish (&bgp->route[afi][safi]);
- if (bgp->aggregate[afi][safi])
- bgp_table_finish (&bgp->aggregate[afi][safi]) ;
- if (bgp->rib[afi][safi])
- bgp_table_finish (&bgp->rib[afi][safi]);
- }
+ /* weight */
+ peer->weight[afi][safi] = conf->weight[afi][safi];
- bgp_scan_finish (bgp);
- bgp_address_destroy (bgp);
+ /* default-originate route-map */
+ if (conf->default_rmap[afi][safi].name) {
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ conf->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].map =
+ conf->default_rmap[afi][safi].map;
+ }
- if (bgp->name)
- XFREE(MTYPE_BGP, bgp->name);
-
- XFREE (MTYPE_BGP, bgp);
-}
+ /* inbound filter apply */
+ if (gfilter->dlist[in].name && !pfilter->dlist[in].name) {
+ if (pfilter->dlist[in].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[in].name);
+ pfilter->dlist[in].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->dlist[in].name);
+ pfilter->dlist[in].alist = gfilter->dlist[in].alist;
+ }
-struct peer *
-peer_lookup_by_conf_if (struct bgp *bgp, const char *conf_if)
-{
- struct peer *peer;
- struct listnode *node, *nnode;
+ if (gfilter->plist[in].name && !pfilter->plist[in].name) {
+ if (pfilter->plist[in].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[in].name);
+ pfilter->plist[in].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[in].name);
+ pfilter->plist[in].plist = gfilter->plist[in].plist;
+ }
- if (!conf_if)
- return NULL;
+ if (gfilter->aslist[in].name && !pfilter->aslist[in].name) {
+ if (pfilter->aslist[in].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[in].name);
+ pfilter->aslist[in].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->aslist[in].name);
+ pfilter->aslist[in].aslist = gfilter->aslist[in].aslist;
+ }
- if (bgp != NULL)
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- return peer;
- }
- else if (bm->bgp != NULL)
- {
- struct listnode *bgpnode, *nbgpnode;
+ if (gfilter->map[RMAP_IN].name && !pfilter->map[RMAP_IN].name) {
+ if (pfilter->map[RMAP_IN].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ pfilter->map[RMAP_IN].name);
+ pfilter->map[RMAP_IN].name = XSTRDUP(
+ MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_IN].name);
+ pfilter->map[RMAP_IN].map = gfilter->map[RMAP_IN].map;
+ }
- for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- return peer;
- }
- return NULL;
-}
+ /* outbound filter apply */
+ if (gfilter->dlist[out].name) {
+ if (pfilter->dlist[out].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
+ pfilter->dlist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->dlist[out].name);
+ pfilter->dlist[out].alist = gfilter->dlist[out].alist;
+ } else {
+ if (pfilter->dlist[out].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->dlist[out].name);
+ pfilter->dlist[out].name = NULL;
+ pfilter->dlist[out].alist = NULL;
+ }
-struct peer *
-peer_lookup_by_hostname (struct bgp *bgp, const char *hostname)
-{
- struct peer *peer;
- struct listnode *node, *nnode;
+ if (gfilter->plist[out].name) {
+ if (pfilter->plist[out].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
+ pfilter->plist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->plist[out].name);
+ pfilter->plist[out].plist = gfilter->plist[out].plist;
+ } else {
+ if (pfilter->plist[out].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->plist[out].name);
+ pfilter->plist[out].name = NULL;
+ pfilter->plist[out].plist = NULL;
+ }
- if (!hostname)
- return NULL;
+ if (gfilter->aslist[out].name) {
+ if (pfilter->aslist[out].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
+ pfilter->aslist[out].name = XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->aslist[out].name);
+ pfilter->aslist[out].aslist = gfilter->aslist[out].aslist;
+ } else {
+ if (pfilter->aslist[out].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->aslist[out].name);
+ pfilter->aslist[out].name = NULL;
+ pfilter->aslist[out].aslist = NULL;
+ }
- if (bgp != NULL)
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->hostname && !strcmp(peer->hostname, hostname)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- return peer;
- }
- else if (bm->bgp != NULL)
- {
- struct listnode *bgpnode, *nbgpnode;
+ if (gfilter->map[RMAP_OUT].name) {
+ if (pfilter->map[RMAP_OUT].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ pfilter->map[RMAP_OUT].name);
+ pfilter->map[RMAP_OUT].name = XSTRDUP(
+ MTYPE_BGP_FILTER_NAME, gfilter->map[RMAP_OUT].name);
+ pfilter->map[RMAP_OUT].map = gfilter->map[RMAP_OUT].map;
+ } else {
+ if (pfilter->map[RMAP_OUT].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ pfilter->map[RMAP_OUT].name);
+ pfilter->map[RMAP_OUT].name = NULL;
+ pfilter->map[RMAP_OUT].map = NULL;
+ }
- for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->hostname && !strcmp(peer->hostname, hostname)
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER))
- return peer;
- }
- return NULL;
-}
-
-struct peer *
-peer_lookup (struct bgp *bgp, union sockunion *su)
-{
- struct peer *peer = NULL;
- struct peer tmp_peer;
-
- memset(&tmp_peer, 0, sizeof(struct peer));
-
- /*
- * We do not want to find the doppelganger peer so search for the peer in
- * the hash that has PEER_FLAG_CONFIG_NODE
- */
- SET_FLAG (tmp_peer.flags, PEER_FLAG_CONFIG_NODE);
-
- tmp_peer.su = *su;
-
- if (bgp != NULL)
- {
- peer = hash_lookup(bgp->peerhash, &tmp_peer);
- }
- else if (bm->bgp != NULL)
- {
- struct listnode *bgpnode, *nbgpnode;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, bgpnode, nbgpnode, bgp))
- {
- /* Skip VRFs, this function will not be invoked without an instance
- * when examining VRFs.
- */
- if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
- continue;
-
- peer = hash_lookup(bgp->peerhash, &tmp_peer);
-
- if (peer)
- break;
- }
- }
-
- return peer;
-}
-
-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;
-
- /* Create peer first; we've already checked group config is valid. */
- peer = peer_create (su, NULL, bgp, bgp->as, group->conf->as, group->conf->as_type, 0, 0, group);
- if (!peer)
- return NULL;
-
- /* Link to group */
- peer = peer_lock (peer);
- listnode_add (group->peer, peer);
-
- peer_group2peer_config_copy(group, 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->afc[afi][safi] = 1;
-
- if (!peer_af_find(peer, afi, safi))
- peer_af_create(peer, afi, safi);
-
- peer_group2peer_config_copy_af (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;
+ if (gfilter->usmap.name) {
+ if (pfilter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
+ pfilter->usmap.name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->usmap.name);
+ pfilter->usmap.map = gfilter->usmap.map;
+ } else {
+ if (pfilter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, pfilter->usmap.name);
+ pfilter->usmap.name = NULL;
+ pfilter->usmap.map = NULL;
+ }
}
-struct prefix *
-peer_group_lookup_dynamic_neighbor_range (struct peer_group * group,
- struct prefix * prefix)
+/* Peer group's remote AS configuration. */
+int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as,
+ int as_type)
{
- struct listnode *node, *nnode;
- struct prefix *range;
- afi_t afi;
+ struct peer_group *group;
+ struct peer *peer;
+ struct listnode *node, *nnode;
- afi = family2afi(prefix->family);
+ group = peer_group_lookup(bgp, group_name);
+ if (!group)
+ return -1;
- if (group->listen_range[afi])
- for (ALL_LIST_ELEMENTS (group->listen_range[afi], node, nnode, range))
- if (prefix_match(range, prefix))
- return range;
+ if ((as_type == group->conf->as_type) && (group->conf->as == *as))
+ return 0;
- 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;
+ /* When we setup peer-group AS number all peer group member's AS
+ number must be updated to same number. */
+ peer_as_change(group->conf, *as, as_type);
- *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)))
- goto found_range;
- }
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (((peer->as_type == AS_SPECIFIED) && peer->as != *as)
+ || (peer->as_type != as_type))
+ peer_as_change(peer, *as, as_type);
+ }
- found_range:
- *listen_range = range;
- return (group && range) ? group : NULL;
+ return 0;
}
-struct peer *
-peer_lookup_dynamic_neighbor (struct bgp *bgp, union sockunion *su)
+int peer_group_delete(struct peer_group *group)
{
- struct peer_group *group;
- struct bgp *gbgp;
- struct peer *peer;
- struct prefix prefix;
- struct prefix *listen_range;
- int dncount;
- char buf[PREFIX2STR_BUFFER];
- char buf1[PREFIX2STR_BUFFER];
+ struct bgp *bgp;
+ struct peer *peer;
+ struct prefix *prefix;
+ struct peer *other;
+ struct listnode *node, *nnode;
+ afi_t afi;
- sockunion2hostprefix(su, &prefix);
+ bgp = group->bgp;
- /* See if incoming connection matches a configured listen range. */
- group = peer_group_lookup_dynamic_neighbor (bgp, &prefix, &listen_range);
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ other = peer->doppelganger;
+ peer_delete(peer);
+ if (other && other->status != Deleted) {
+ other->group = NULL;
+ peer_delete(other);
+ }
+ }
+ list_delete(group->peer);
- if (! group)
- return NULL;
+ 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]);
+ }
+ XFREE(MTYPE_PEER_GROUP_HOST, group->name);
+ group->name = NULL;
- gbgp = group->bgp;
+ bfd_info_free(&(group->conf->bfd_info));
- if (! gbgp)
- return NULL;
+ group->conf->group = NULL;
+ peer_delete(group->conf);
- prefix2str(&prefix, buf, sizeof(buf));
- prefix2str(listen_range, buf1, sizeof(buf1));
+ /* Delete from all peer_group list. */
+ listnode_delete(bgp->group, group);
- if (bgp_debug_neighbor_events(NULL))
- zlog_debug ("Dynamic Neighbor %s matches group %s listen range %s",
- buf, group->name, buf1);
+ peer_group_free(group);
- /* Are we within the listen limit? */
- dncount = gbgp->dynamic_neighbors_count;
+ return 0;
+}
- 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;
- }
+int peer_group_remote_as_delete(struct peer_group *group)
+{
+ struct peer *peer, *other;
+ struct listnode *node, *nnode;
- /* 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;
- }
+ if ((group->conf->as_type == AS_UNSPECIFIED)
+ || ((!group->conf->as) && (group->conf->as_type == AS_SPECIFIED)))
+ return 0;
- /* 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;
- }
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ other = peer->doppelganger;
- /* Create dynamic peer and bind to associated group. */
- peer = peer_create_bind_dynamic_neighbor (gbgp, su, group);
- assert (peer);
+ peer_delete(peer);
- gbgp->dynamic_neighbors_count = ++dncount;
+ if (other && other->status != Deleted) {
+ other->group = NULL;
+ peer_delete(other);
+ }
+ }
+ list_delete_all_node(group->peer);
- if (bgp_debug_neighbor_events(peer))
- zlog_debug ("%s Dynamic Neighbor added, group %s count %d",
- peer->host, group->name, dncount);
+ group->conf->as = 0;
+ group->conf->as_type = AS_UNSPECIFIED;
- return peer;
+ return 0;
}
-
-void peer_drop_dynamic_neighbor (struct peer *peer)
+
+int peer_group_listen_range_add(struct peer_group *group, struct prefix *range)
{
- 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);
-}
+ struct prefix *prefix;
+ struct listnode *node, *nnode;
+ afi_t afi;
+ afi = family2afi(range->family);
-/* If peer is configured at least one address family return 1. */
-int
-peer_active (struct peer *peer)
-{
- if (BGP_PEER_SU_UNSPEC(peer))
- return 0;
- if (peer->afc[AFI_IP][SAFI_UNICAST]
- || peer->afc[AFI_IP][SAFI_MULTICAST]
- || peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
- || peer->afc[AFI_IP][SAFI_MPLS_VPN]
- || peer->afc[AFI_IP][SAFI_ENCAP]
- || peer->afc[AFI_IP6][SAFI_UNICAST]
- || peer->afc[AFI_IP6][SAFI_MULTICAST]
- || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
- || peer->afc[AFI_IP6][SAFI_MPLS_VPN]
- || peer->afc[AFI_IP6][SAFI_ENCAP])
- return 1;
- return 0;
-}
+ /* Group needs remote AS configured. */
+ if (group->conf->as_type == AS_UNSPECIFIED)
+ return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
-/* If peer is negotiated at least one address family return 1. */
-int
-peer_active_nego (struct peer *peer)
-{
- if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
- || peer->afc_nego[AFI_IP][SAFI_MULTICAST]
- || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
- || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
- || peer->afc_nego[AFI_IP][SAFI_ENCAP]
- || peer->afc_nego[AFI_IP6][SAFI_UNICAST]
- || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
- || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
- || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
- || peer->afc_nego[AFI_IP6][SAFI_ENCAP])
- return 1;
- return 0;
+ /* 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 0;
+ }
+
+ prefix = prefix_new();
+ prefix_copy(prefix, range);
+ listnode_add(group->listen_range[afi], prefix);
+ return 0;
}
-/* peer_flag_change_type. */
-enum peer_change_type
+int peer_group_listen_range_del(struct peer_group *group, struct prefix *range)
{
- peer_change_none,
- peer_change_reset,
- peer_change_reset_in,
- peer_change_reset_out,
-};
+ struct prefix *prefix, prefix2;
+ struct listnode *node, *nnode;
+ struct peer *peer;
+ afi_t afi;
+ char buf[PREFIX2STR_BUFFER];
-static void
-peer_change_action (struct peer *peer, afi_t afi, safi_t safi,
- enum peer_change_type type)
-{
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return;
-
- if (peer->status != Established)
- return;
-
- if (type == peer_change_reset)
- {
- /* If we're resetting session, we've to delete both peer struct */
- if ((peer->doppelganger) && (peer->doppelganger->status != Deleted)
- && (!CHECK_FLAG(peer->doppelganger->flags,
- PEER_FLAG_CONFIG_NODE)))
- peer_delete(peer->doppelganger);
-
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else if (type == peer_change_reset_in)
- {
- if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- else
- {
- if ((peer->doppelganger) && (peer->doppelganger->status != Deleted)
- && (!CHECK_FLAG(peer->doppelganger->flags,
- PEER_FLAG_CONFIG_NODE)))
- peer_delete(peer->doppelganger);
+ afi = family2afi(range->family);
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ /* Identify the listen range. */
+ for (ALL_LIST_ELEMENTS(group->listen_range[afi], node, nnode, prefix)) {
+ if (prefix_same(range, prefix))
+ break;
}
- }
- else if (type == peer_change_reset_out)
- {
- update_group_adjust_peer(peer_af_find(peer, afi, safi));
- bgp_announce_route (peer, afi, safi);
- }
-}
-struct peer_flag_action
-{
- /* Peer's flag. */
- u_int32_t flag;
+ 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;
+
+ sockunion2hostprefix(&peer->su, &prefix2);
+ 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);
+ }
+ }
- /* This flag can be set for peer-group member. */
- u_char not_for_member;
+ /* Get rid of the listen range */
+ listnode_delete(group->listen_range[afi], prefix);
- /* Action when the flag is changed. */
- enum peer_change_type type;
+ return 0;
+}
- /* Peer down cause */
- u_char peer_down;
-};
+/* Bind specified peer to peer group. */
+int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
+ struct peer_group *group, as_t *as)
+{
+ int first_member = 0;
+ afi_t afi;
+ safi_t safi;
+ int cap_enhe_preset = 0;
+
+ /* Lookup the peer. */
+ if (!peer)
+ peer = peer_lookup(bgp, su);
+
+ /* The peer exist, bind it to the peer-group */
+ if (peer) {
+ /* When the peer already belongs to peer group, check the
+ * consistency. */
+ if (peer_group_active(peer)
+ && strcmp(peer->group->name, group->name) != 0)
+ return BGP_ERR_PEER_GROUP_CANT_CHANGE;
+
+ /* The peer has not specified a remote-as, inherit it from the
+ * peer-group */
+ if (peer->as_type == AS_UNSPECIFIED) {
+ peer->as_type = group->conf->as_type;
+ peer->as = group->conf->as;
+ }
-static const struct peer_flag_action peer_flag_action_list[] =
- {
- { PEER_FLAG_PASSIVE, 0, peer_change_reset },
- { PEER_FLAG_SHUTDOWN, 0, peer_change_reset },
- { PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none },
- { PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none },
- { PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none },
- { PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset },
- { PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset },
- { PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset },
- { 0, 0, 0 }
- };
-
-static const struct peer_flag_action peer_af_flag_action_list[] =
- {
- { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
- { PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
- { PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out },
- { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
- { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
- { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
- { PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in },
- { PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out },
- { PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out },
- // PEER_FLAG_DEFAULT_ORIGINATE
- { PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out },
- { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in },
- { PEER_FLAG_ALLOWAS_IN_ORIGIN, 0, peer_change_reset_in },
- { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset },
- { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset },
- // PEER_FLAG_MAX_PREFIX
- // PEER_FLAG_MAX_PREFIX_WARNING
- { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out },
- { PEER_FLAG_FORCE_NEXTHOP_SELF, 1, peer_change_reset_out },
- { PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out },
- { PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE,1, peer_change_reset_out },
- { PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out },
- { PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE,1, peer_change_reset_out },
- { PEER_FLAG_ADDPATH_TX_ALL_PATHS, 1, peer_change_reset },
- { PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, 1, peer_change_reset },
- { PEER_FLAG_WEIGHT, 0, peer_change_reset_in },
- { 0, 0, 0 }
- };
+ if (!group->conf->as) {
+ if (peer_sort(group->conf) != BGP_PEER_INTERNAL
+ && peer_sort(group->conf) != peer_sort(peer)) {
+ if (as)
+ *as = peer->as;
+ return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT;
+ }
-/* Proper action set. */
-static int
-peer_flag_action_set (const struct peer_flag_action *action_list, int size,
- struct peer_flag_action *action, u_int32_t flag)
-{
- int i;
- int found = 0;
- int reset_in = 0;
- int reset_out = 0;
- const struct peer_flag_action *match = NULL;
+ if (peer_sort(group->conf) == BGP_PEER_INTERNAL)
+ first_member = 1;
+ }
- /* Check peer's frag action. */
- for (i = 0; i < size; i++)
- {
- match = &action_list[i];
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
+ cap_enhe_preset = 1;
+
+ peer_group2peer_config_copy(group, peer);
+
+ /*
+ * Capability extended-nexthop is enabled for an interface
+ * neighbor by
+ * default. So, fix that up here.
+ */
+ if (peer->conf_if && cap_enhe_preset)
+ peer_flag_set(peer, PEER_FLAG_CAPABILITY_ENHE);
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ if (group->conf->afc[afi][safi]) {
+ peer->afc[afi][safi] = 1;
+
+ if (peer_af_find(peer, afi, safi)
+ || peer_af_create(peer, afi,
+ safi)) {
+ peer_group2peer_config_copy_af(
+ group, peer, afi, safi);
+ }
+ } else if (peer->afc[afi][safi])
+ peer_deactivate(peer, afi, safi);
+ }
+
+ if (peer->group) {
+ assert(group && peer->group == group);
+ } else {
+ struct listnode *pn;
+ pn = listnode_lookup(bgp->peer, peer);
+ list_delete_node(bgp->peer, pn);
+ peer->group = group;
+ listnode_add_sort(bgp->peer, peer);
+
+ peer = peer_lock(peer); /* group->peer list reference */
+ listnode_add(group->peer, peer);
+ }
- if (match->flag == 0)
- break;
+ if (first_member) {
+ /* Advertisement-interval reset */
+ if (!CHECK_FLAG(group->conf->config,
+ PEER_CONFIG_ROUTEADV)) {
+ if (peer_sort(group->conf) == BGP_PEER_IBGP)
+ group->conf->v_routeadv =
+ BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ group->conf->v_routeadv =
+ BGP_DEFAULT_EBGP_ROUTEADV;
+ }
+
+ /* ebgp-multihop reset */
+ if (peer_sort(group->conf) == BGP_PEER_IBGP)
+ group->conf->ttl = MAXTTL;
+
+ /* local-as reset */
+ if (peer_sort(group->conf) != BGP_PEER_EBGP) {
+ group->conf->change_local_as = 0;
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ }
+ }
- if (match->flag & flag)
- {
- found = 1;
-
- if (match->type == peer_change_reset_in)
- reset_in = 1;
- if (match->type == peer_change_reset_out)
- reset_out = 1;
- if (match->type == peer_change_reset)
- {
- reset_in = 1;
- reset_out = 1;
- }
- if (match->not_for_member)
- action->not_for_member = 1;
- }
- }
-
- /* Set peer clear type. */
- if (reset_in && reset_out)
- action->type = peer_change_reset;
- else if (reset_in)
- action->type = peer_change_reset_in;
- else if (reset_out)
- action->type = peer_change_reset_out;
- else
- action->type = peer_change_none;
-
- return found;
-}
-
-static void
-peer_flag_modify_action (struct peer *peer, u_int32_t flag)
-{
- if (flag == PEER_FLAG_SHUTDOWN)
- {
- if (CHECK_FLAG (peer->flags, flag))
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
-
- UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart)
- {
- BGP_TIMER_OFF (peer->t_pmax_restart);
- if (bgp_debug_neighbor_events(peer))
- zlog_debug ("%s Maximum-prefix restart timer canceled",
- peer->host);
- }
-
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT))
- peer_nsf_stop (peer);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- char *msg = peer->tx_shutdown_message;
- size_t msglen;
-
- if (!msg && peer_group_active (peer))
- msg = peer->group->conf->tx_shutdown_message;
- msglen = msg ? strlen(msg) : 0;
- if (msglen > 128)
- msglen = 128;
-
- if (msglen)
- {
- u_char msgbuf[129];
-
- msgbuf[0] = msglen;
- memcpy(msgbuf + 1, msg, msglen);
-
- bgp_notify_send_with_data (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN,
- msgbuf, msglen + 1);
- }
- else
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
- else
- bgp_session_reset(peer);
- }
- else
- {
- peer->v_start = BGP_INIT_START_TIMER;
- BGP_EVENT_ADD (peer, BGP_Stop);
- }
- }
- else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- if (flag == PEER_FLAG_DYNAMIC_CAPABILITY)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_PASSIVE)
- peer->last_reset = PEER_DOWN_PASSIVE_CHANGE;
- else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)
- peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE;
-
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
-}
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
-/* Change specified peer flag. */
-static int
-peer_flag_modify (struct peer *peer, u_int32_t flag, int set)
-{
- int found;
- int size;
- struct peer_group *group;
- struct peer *tmp_peer;
- struct listnode *node, *nnode;
- struct peer_flag_action action;
-
- memset (&action, 0, sizeof (struct peer_flag_action));
- size = sizeof peer_flag_action_list / sizeof (struct peer_flag_action);
-
- found = peer_flag_action_set (peer_flag_action_list, size, &action, flag);
-
- /* No flag action is found. */
- if (! found)
- return BGP_ERR_INVALID_FLAG;
-
- /* When unset the peer-group member's flag we have to check
- peer-group configuration. */
- if (! set && peer_group_active (peer))
- if (CHECK_FLAG (peer->group->conf->flags, flag))
- {
- if (flag == PEER_FLAG_SHUTDOWN)
- return BGP_ERR_PEER_GROUP_SHUTDOWN;
- }
-
- /* Flag conflict check. */
- if (set
- && CHECK_FLAG (peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH)
- && CHECK_FLAG (peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY))
- return BGP_ERR_PEER_FLAG_CONFLICT;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (set && CHECK_FLAG (peer->flags, flag) == flag)
- return 0;
- if (! set && ! CHECK_FLAG (peer->flags, flag))
- return 0;
- }
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_RMAP_BIND;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else {
+ bgp_session_reset(peer);
+ }
+ }
- if (set)
- SET_FLAG (peer->flags, flag);
- else
- UNSET_FLAG (peer->flags, flag);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (action.type == peer_change_reset)
- peer_flag_modify_action (peer, flag);
+ /* Create a new peer. */
+ else {
+ if ((group->conf->as_type == AS_SPECIFIED)
+ && (!group->conf->as)) {
+ return BGP_ERR_PEER_GROUP_NO_REMOTE_AS;
+ }
- return 0;
- }
+ peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
+ group->conf->as_type, 0, 0, group);
- /* peer-group member updates. */
- group = peer->group;
+ peer = peer_lock(peer); /* group->peer list reference */
+ listnode_add(group->peer, peer);
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
- {
+ peer_group2peer_config_copy(group, peer);
- if (set && CHECK_FLAG (tmp_peer->flags, flag) == flag)
- continue;
+ /* If the peer-group is active for this afi/safi then activate
+ * for this peer */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
+ if (group->conf->afc[afi][safi]) {
+ peer->afc[afi][safi] = 1;
+ peer_af_create(peer, afi, safi);
+ peer_group2peer_config_copy_af(
+ group, peer, afi, safi);
+ } else if (peer->afc[afi][safi])
+ peer_deactivate(peer, afi, safi);
- if (! set && ! CHECK_FLAG (tmp_peer->flags, flag))
- continue;
+ SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
- if (set)
- SET_FLAG (tmp_peer->flags, flag);
- else
- UNSET_FLAG (tmp_peer->flags, flag);
+ /* Set up peer's events and timers. */
+ if (peer_active(peer))
+ bgp_timer_set(peer);
+ }
- if (action.type == peer_change_reset)
- peer_flag_modify_action (tmp_peer, flag);
- }
- return 0;
+ return 0;
}
-int
-peer_flag_set (struct peer *peer, u_int32_t flag)
+int peer_group_unbind(struct bgp *bgp, struct peer *peer,
+ struct peer_group *group)
{
- return peer_flag_modify (peer, flag, 1);
-}
+ struct peer *other;
+ afi_t afi;
+ safi_t safi;
-int
-peer_flag_unset (struct peer *peer, u_int32_t flag)
-{
- return peer_flag_modify (peer, flag, 0);
-}
+ if (group != peer->group)
+ return BGP_ERR_PEER_GROUP_MISMATCH;
-static int
-peer_af_flag_modify (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag,
- int set)
-{
- int found;
- int size;
- struct listnode *node, *nnode;
- struct peer_group *group;
- struct peer_flag_action action;
- struct peer *tmp_peer;
- struct bgp *bgp;
- int addpath_tx_used;
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ if (peer->afc[afi][safi]) {
+ peer->afc[afi][safi] = 0;
+ peer_af_flag_reset(peer, afi, safi);
- memset (&action, 0, sizeof (struct peer_flag_action));
- size = sizeof peer_af_flag_action_list / sizeof (struct peer_flag_action);
-
- found = peer_flag_action_set (peer_af_flag_action_list, size, &action, flag);
-
- /* No flag action is found. */
- if (! found)
- return BGP_ERR_INVALID_FLAG;
+ if (peer_af_delete(peer, afi, safi) != 0) {
+ zlog_err(
+ "couldn't delete af structure for peer %s",
+ peer->host);
+ }
+ }
+ }
- /* Special check for reflector client. */
- if (flag & PEER_FLAG_REFLECTOR_CLIENT
- && peer_sort (peer) != BGP_PEER_IBGP)
- return BGP_ERR_NOT_INTERNAL_PEER;
+ assert(listnode_lookup(group->peer, peer));
+ peer_unlock(peer); /* peer group list reference */
+ listnode_delete(group->peer, peer);
+ peer->group = NULL;
+ other = peer->doppelganger;
+
+ if (group->conf->as) {
+ peer_delete(peer);
+ if (other && other->status != Deleted) {
+ if (other->group) {
+ peer_unlock(other);
+ listnode_delete(group->peer, other);
+ }
+ other->group = NULL;
+ peer_delete(other);
+ }
+ return 0;
+ }
- /* Special check for remove-private-AS. */
- if (flag & PEER_FLAG_REMOVE_PRIVATE_AS
- && peer_sort (peer) == BGP_PEER_IBGP)
- return BGP_ERR_REMOVE_PRIVATE_AS;
+ bgp_bfd_deregister_peer(peer);
+ peer_global_config_reset(peer);
- /* as-override is not allowed for IBGP peers */
- if (flag & PEER_FLAG_AS_OVERRIDE
- && peer_sort (peer) == BGP_PEER_IBGP)
- return BGP_ERR_AS_OVERRIDE;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_RMAP_UNBIND;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
- /* When current flag configuration is same as requested one. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (set && CHECK_FLAG (peer->af_flags[afi][safi], flag) == flag)
- return 0;
- if (! set && ! CHECK_FLAG (peer->af_flags[afi][safi], flag))
return 0;
- }
-
- if (set)
- SET_FLAG (peer->af_flags[afi][safi], flag);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], flag);
-
- /* Execute action when peer is established. */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && peer->status == Established)
- {
- if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in (peer, afi, safi);
- else
- {
- if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_RSERVER_CLIENT)
- peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_SM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_RM)
- peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
-
- peer_change_action (peer, afi, safi, action.type);
- }
-
- }
-
- /* Peer group member updates. */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- group = peer->group;
-
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
- {
- if (set && CHECK_FLAG (tmp_peer->af_flags[afi][safi], flag) == flag)
- continue;
+}
- if (! set && ! CHECK_FLAG (tmp_peer->af_flags[afi][safi], flag))
- continue;
+static int bgp_startup_timer_expire(struct thread *thread)
+{
+ struct bgp *bgp;
- if (set)
- SET_FLAG (tmp_peer->af_flags[afi][safi], flag);
- else
- UNSET_FLAG (tmp_peer->af_flags[afi][safi], flag);
+ bgp = THREAD_ARG(thread);
+ bgp->t_startup = NULL;
- if (tmp_peer->status == Established)
- {
- if (! set && flag == PEER_FLAG_SOFT_RECONFIG)
- bgp_clear_adj_in (tmp_peer, afi, safi);
- else
- {
- if (flag == PEER_FLAG_REFLECTOR_CLIENT)
- tmp_peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_RSERVER_CLIENT)
- tmp_peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_SM)
- tmp_peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
- else if (flag == PEER_FLAG_ORF_PREFIX_RM)
- tmp_peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ return 0;
+}
- peer_change_action (tmp_peer, afi, safi, action.type);
- }
- }
+/* BGP instance creation by `router bgp' commands. */
+static struct bgp *bgp_create(as_t *as, const char *name,
+ enum bgp_instance_type inst_type)
+{
+ struct bgp *bgp;
+ afi_t afi;
+ safi_t safi;
+
+ if ((bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp))) == NULL)
+ return NULL;
+
+ if (BGP_DEBUG(zebra, ZEBRA)) {
+ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ zlog_debug("Creating Default VRF, AS %u", *as);
+ else
+ zlog_debug("Creating %s %s, AS %u",
+ (inst_type == BGP_INSTANCE_TYPE_VRF)
+ ? "VRF"
+ : "VIEW",
+ name, *as);
}
- }
- /* Track if addpath TX is in use */
- if (flag & (PEER_FLAG_ADDPATH_TX_ALL_PATHS|PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
- {
- bgp = peer->bgp;
- addpath_tx_used = 0;
+ bgp_lock(bgp);
+ bgp->inst_type = inst_type;
+ bgp->vrf_id = (inst_type == BGP_INSTANCE_TYPE_DEFAULT) ? VRF_DEFAULT
+ : VRF_UNKNOWN;
+ bgp->peer_self = peer_new(bgp);
+ if (bgp->peer_self->host)
+ XFREE(MTYPE_BGP_PEER_HOST, bgp->peer_self->host);
+ bgp->peer_self->host =
+ XSTRDUP(MTYPE_BGP_PEER_HOST, "Static announcement");
+ bgp->peer = list_new();
+ bgp->peer->cmp = (int (*)(void *, void *))peer_cmp;
+ bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, NULL);
+ bgp->peerhash->max_size = BGP_PEER_MAX_HASH_SIZE;
+
+ bgp->group = list_new();
+ bgp->group->cmp = (int (*)(void *, void *))peer_group_cmp;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ bgp->route[afi][safi] = bgp_table_init(afi, safi);
+ bgp->aggregate[afi][safi] = bgp_table_init(afi, safi);
+ bgp->rib[afi][safi] = bgp_table_init(afi, safi);
+
+ /* Enable maximum-paths */
+ bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_EBGP,
+ multipath_num, 0);
+ bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
+ multipath_num, 0);
+ }
+
+ bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
+ bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
+ bgp->default_subgroup_pkt_queue_max =
+ BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
+ bgp->default_holdtime = BGP_DEFAULT_HOLDTIME;
+ 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;
+#if DFLT_BGP_IMPORT_CHECK
+ bgp_flag_set(bgp, BGP_FLAG_IMPORT_CHECK);
+#endif
+#if DFLT_BGP_SHOW_HOSTNAME
+ bgp_flag_set(bgp, BGP_FLAG_SHOW_HOSTNAME);
+#endif
+#if DFLT_BGP_LOG_NEIGHBOR_CHANGES
+ bgp_flag_set(bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES);
+#endif
+#if DFLT_BGP_DETERMINISTIC_MED
+ bgp_flag_set(bgp, BGP_FLAG_DETERMINISTIC_MED);
+#endif
+ bgp->addpath_tx_id = BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE;
+
+ bgp->as = *as;
+
+#if ENABLE_BGP_VNC
+ if (inst_type != BGP_INSTANCE_TYPE_VRF) {
+ bgp->rfapi = bgp_rfapi_new(bgp);
+ assert(bgp->rfapi);
+ assert(bgp->rfapi_cfg);
+ }
+#endif /* ENABLE_BGP_VNC */
- if (set)
- {
- addpath_tx_used = 1;
+ if (name) {
+ bgp->name = XSTRDUP(MTYPE_BGP, name);
+ } else {
+ /* TODO - The startup timer needs to be run for the whole of BGP
+ */
+ thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
+ bgp->restart_time, &bgp->t_startup);
+ }
- if (flag & PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)
- {
- if (!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED))
- {
- zlog_warn("%s: enabling bgp deterministic-med, this is required"\
- " for addpath-tx-bestpath-per-AS",
- peer->host);
- bgp_flag_set (bgp, BGP_FLAG_DETERMINISTIC_MED);
- bgp_recalculate_all_bestpaths (bgp);
- }
- }
- }
- else
- {
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, tmp_peer))
- {
- if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_ALL_PATHS) ||
- CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
- {
- addpath_tx_used = 1;
- break;
- }
- }
- }
+ bgp->wpkt_quanta = BGP_WRITE_PACKET_MAX;
+ bgp->coalesce_time = BGP_DEFAULT_SUBGROUP_COALESCE_TIME;
- bgp->addpath_tx_used[afi][safi] = addpath_tx_used;
- }
+ QOBJ_REG(bgp, bgp);
- return 0;
+ update_bgp_group_init(bgp);
+ bgp_evpn_init(bgp);
+ return bgp;
}
-int
-peer_af_flag_set (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+/* Return the "default VRF" instance of BGP. */
+struct bgp *bgp_get_default(void)
{
- return peer_af_flag_modify (peer, afi, safi, flag, 1);
+ struct bgp *bgp;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ return bgp;
+ return NULL;
}
-int
-peer_af_flag_unset (struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+/* Lookup BGP entry. */
+struct bgp *bgp_lookup(as_t as, const char *name)
{
- return peer_af_flag_modify (peer, afi, safi, flag, 0);
-}
+ struct bgp *bgp;
+ struct listnode *node, *nnode;
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ if (bgp->as == as
+ && ((bgp->name == NULL && name == NULL)
+ || (bgp->name && name && strcmp(bgp->name, name) == 0)))
+ return bgp;
+ return NULL;
+}
-int peer_tx_shutdown_message_set (struct peer *peer, const char *msg)
+/* Lookup BGP structure by view name. */
+struct bgp *bgp_lookup_by_name(const char *name)
{
- XFREE (MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
- peer->tx_shutdown_message = msg ? XSTRDUP (MTYPE_PEER_TX_SHUTDOWN_MSG, msg) : NULL;
- return 0;
+ struct bgp *bgp;
+ struct listnode *node, *nnode;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
+ if ((bgp->name == NULL && name == NULL)
+ || (bgp->name && name && strcmp(bgp->name, name) == 0))
+ return bgp;
+ return NULL;
}
-int peer_tx_shutdown_message_unset (struct peer *peer)
+/* Lookup BGP instance based on VRF id. */
+/* Note: Only to be used for incoming messages from Zebra. */
+struct bgp *bgp_lookup_by_vrf_id(vrf_id_t vrf_id)
{
- XFREE (MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
- return 0;
+ struct vrf *vrf;
+
+ /* Lookup VRF (in tree) and follow link. */
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (!vrf)
+ return NULL;
+ return (vrf->info) ? (struct bgp *)vrf->info : NULL;
}
+/* Called from VTY commands. */
+int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
+ enum bgp_instance_type inst_type)
+{
+ struct bgp *bgp;
+
+ /* Multiple instance check. */
+ if (bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
+ if (name)
+ bgp = bgp_lookup_by_name(name);
+ else
+ bgp = bgp_get_default();
+
+ /* Already exists. */
+ if (bgp) {
+ if (bgp->as != *as) {
+ *as = bgp->as;
+ return BGP_ERR_INSTANCE_MISMATCH;
+ }
+ if (bgp->inst_type != inst_type)
+ return BGP_ERR_INSTANCE_MISMATCH;
+ *bgp_val = bgp;
+ return 0;
+ }
+ } else {
+ /* BGP instance name can not be specified for single instance.
+ */
+ if (name)
+ return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET;
+
+ /* Get default BGP structure if exists. */
+ bgp = bgp_get_default();
+
+ if (bgp) {
+ if (bgp->as != *as) {
+ *as = bgp->as;
+ return BGP_ERR_AS_MISMATCH;
+ }
+ *bgp_val = bgp;
+ return 0;
+ }
+ }
-/* EBGP multihop configuration. */
-int
-peer_ebgp_multihop_set (struct peer *peer, int ttl)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
- struct peer *peer1;
-
- if (peer->sort == BGP_PEER_IBGP || peer->conf_if)
- return 0;
-
- /* see comment in peer_ttl_security_hops_set() */
- if (ttl != MAXTTL)
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- group = peer->group;
- if (group->conf->gtsm_hops != 0)
- return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
-
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
- {
- if (peer1->sort == BGP_PEER_IBGP)
- continue;
-
- if (peer1->gtsm_hops != 0)
- return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
- }
- }
- else
- {
- if (peer->gtsm_hops != 0)
- return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
- }
- }
-
- peer->ttl = ttl;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP)
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
- }
- }
- else
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->sort == BGP_PEER_IBGP)
- continue;
-
- peer->ttl = group->conf->ttl;
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
- }
- }
- return 0;
-}
-
-int
-peer_ebgp_multihop_unset (struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (peer->sort == BGP_PEER_IBGP)
- return 0;
-
- if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL)
- return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
-
- if (peer_group_active (peer))
- peer->ttl = peer->group->conf->ttl;
- else
- peer->ttl = 1;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
- }
- else
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->sort == BGP_PEER_IBGP)
- continue;
+ bgp = bgp_create(as, name, inst_type);
+ bgp_router_id_set(bgp, &bgp->router_id_zebra);
+ bgp_address_init(bgp);
+ bgp_scan_init(bgp);
+ *bgp_val = bgp;
- peer->ttl = 1;
+ bgp->t_rmap_def_originate_eval = NULL;
- if (peer->fd >= 0)
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
- }
+ /* Create BGP server socket, if first instance. */
+ if (list_isempty(bm->bgp) && !bgp_option_check(BGP_OPT_NO_LISTEN)) {
+ if (bgp_socket(bm->port, bm->address) < 0)
+ return BGP_ERR_INVALID_VALUE;
}
- }
- return 0;
-}
-/* Neighbor description. */
-int
-peer_description_set (struct peer *peer, const char *desc)
-{
- if (peer->desc)
- XFREE (MTYPE_PEER_DESC, peer->desc);
+ listnode_add(bm->bgp, bgp);
- peer->desc = XSTRDUP (MTYPE_PEER_DESC, desc);
+ /* If Default instance or VRF, link to the VRF structure, if present. */
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT
+ || bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
+ struct vrf *vrf;
- return 0;
-}
+ vrf = bgp_vrf_lookup_by_instance_type(bgp);
+ if (vrf)
+ bgp_vrf_link(bgp, vrf);
+ }
-int
-peer_description_unset (struct peer *peer)
-{
- if (peer->desc)
- XFREE (MTYPE_PEER_DESC, peer->desc);
+ /* Register with Zebra, if needed */
+ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ bgp_zebra_instance_register(bgp);
- peer->desc = NULL;
- return 0;
+ return 0;
}
-/* Neighbor update-source. */
-int
-peer_update_source_if_set (struct peer *peer, const char *ifname)
+/*
+ * Make BGP instance "up". Applies only to VRFs (non-default) and
+ * implies the VRF has been learnt from Zebra.
+ */
+void bgp_instance_up(struct bgp *bgp)
{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (peer->update_if)
- {
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && strcmp (peer->update_if, ifname) == 0)
- return 0;
+ struct peer *peer;
+ struct listnode *node, *next;
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
-
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
- }
-
- peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- return 0;
- }
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->update_if)
- {
- if (strcmp (peer->update_if, ifname) == 0)
- continue;
+ /* Register with zebra. */
+ bgp_zebra_instance_register(bgp);
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
+ /* Kick off any peers that may have been configured. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) {
+ if (!BGP_PEER_START_SUPPRESSED(peer))
+ BGP_EVENT_ADD(peer, BGP_Start);
}
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
+ /* Process any networks that have been configured. */
+ bgp_static_add(bgp);
+}
+
+/*
+ * Make BGP instance "down". Applies only to VRFs (non-default) and
+ * implies the VRF has been deleted by Zebra.
+ */
+void bgp_instance_down(struct bgp *bgp)
+{
+ struct peer *peer;
+ struct listnode *node;
+ struct listnode *next;
+
+ /* Stop timers. */
+ if (bgp->t_rmap_def_originate_eval) {
+ BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
+ bgp_unlock(bgp); /* TODO - This timer is started with a lock -
+ why? */
}
- peer->update_if = XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, ifname);
+ /* Bring down peers, so corresponding routes are purged. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
+ else
+ bgp_session_reset(peer);
+ }
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- }
- return 0;
+ /* Purge network and redistributed routes. */
+ bgp_purge_static_redist_routes(bgp);
}
-int
-peer_update_source_addr_set (struct peer *peer, const union sockunion *su)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (peer->update_source)
- {
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && sockunion_cmp (peer->update_source, su) == 0)
- return 0;
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
- }
-
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
-
- }
-
- peer->update_source = sockunion_dup (su);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- return 0;
- }
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->update_source)
- {
- if (sockunion_cmp (peer->update_source, su) == 0)
- continue;
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
+/* Delete BGP instance. */
+int bgp_delete(struct bgp *bgp)
+{
+ struct peer *peer;
+ struct peer_group *group;
+ struct listnode *node, *next;
+ struct vrf *vrf;
+ afi_t afi;
+ int i;
+
+ THREAD_OFF(bgp->t_startup);
+
+ if (BGP_DEBUG(zebra, ZEBRA)) {
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ zlog_debug("Deleting Default VRF");
+ else
+ zlog_debug("Deleting %s %s",
+ (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ ? "VRF"
+ : "VIEW",
+ bgp->name);
}
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
-
- peer->update_source = sockunion_dup (su);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- }
- return 0;
-}
-
-int
-peer_update_source_unset (struct peer *peer)
-{
- union sockunion *su;
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)
- && ! peer->update_source
- && ! peer->update_if)
- return 0;
-
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
- }
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
- }
-
- if (peer_group_active (peer))
- {
- group = peer->group;
-
- if (group->conf->update_source)
- {
- su = sockunion_dup (group->conf->update_source);
- peer->update_source = su;
- }
- else if (group->conf->update_if)
- peer->update_if =
- XSTRDUP (MTYPE_PEER_UPDATE_SOURCE, group->conf->update_if);
- }
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- return 0;
- }
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (! peer->update_source && ! peer->update_if)
- continue;
-
- if (peer->update_source)
- {
- sockunion_free (peer->update_source);
- peer->update_source = NULL;
+ /* Stop timers. */
+ if (bgp->t_rmap_def_originate_eval) {
+ BGP_TIMER_OFF(bgp->t_rmap_def_originate_eval);
+ bgp_unlock(bgp); /* TODO - This timer is started with a lock -
+ why? */
}
- if (peer->update_if)
- {
- XFREE (MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
- peer->update_if = NULL;
+ /* Inform peers we're going down. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
}
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- }
- return 0;
-}
+ /* Delete static routes (networks). */
+ bgp_static_delete(bgp);
-int
-peer_default_originate_set (struct peer *peer, afi_t afi, safi_t safi,
- const char *rmap)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
+ /* Unset redistribution. */
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ if (i != ZEBRA_ROUTE_BGP)
+ bgp_redistribute_unset(bgp, afi, i, 0);
- if (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
- || (rmap && ! peer->default_rmap[afi][safi].name)
- || (rmap && strcmp (rmap, peer->default_rmap[afi][safi].name) != 0))
- {
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+ /* Free peers and peer-groups. */
+ for (ALL_LIST_ELEMENTS(bgp->group, node, next, group))
+ peer_group_delete(group);
- if (rmap)
- {
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
- peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
- }
- }
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (peer->status == Established && peer->afc_nego[afi][safi]) {
- update_group_adjust_peer(peer_af_find(peer, afi, safi));
- bgp_default_originate (peer, afi, safi, 0);
- bgp_announce_route (peer, afi, safi);
- }
- return 0;
- }
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
-
- if (rmap)
- {
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
- peer->default_rmap[afi][safi].map = route_map_lookup_by_name (rmap);
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer))
+ peer_delete(peer);
+
+ if (bgp->peer_self) {
+ peer_delete(bgp->peer_self);
+ bgp->peer_self = NULL;
}
- if (peer->status == Established && peer->afc_nego[afi][safi]) {
- update_group_adjust_peer(peer_af_find(peer, afi, safi));
- bgp_default_originate (peer, afi, safi, 0);
- bgp_announce_route (peer, afi, safi);
- }
- }
- return 0;
-}
+ update_bgp_group_free(bgp);
-int
-peer_default_originate_unset (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
+/* TODO - Other memory may need to be freed - e.g., NHT */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE))
- {
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+#if ENABLE_BGP_VNC
+ rfapi_delete(bgp);
+#endif
+ bgp_cleanup_routes(bgp);
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = NULL;
- peer->default_rmap[afi][safi].map = NULL;
- }
+ /* Remove visibility via the master list - there may however still be
+ * routes to be processed still referencing the struct bgp.
+ */
+ listnode_delete(bm->bgp, bgp);
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (peer->status == Established && peer->afc_nego[afi][safi]) {
- update_group_adjust_peer(peer_af_find(peer, afi, safi));
- bgp_default_originate (peer, afi, safi, 1);
- bgp_announce_route (peer, afi, safi);
- }
- return 0;
- }
+ /* Deregister from Zebra, if needed */
+ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ bgp_zebra_instance_deregister(bgp);
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE);
+ /* Free interfaces in this instance. */
+ bgp_if_finish(bgp);
- if (peer->default_rmap[afi][safi].name)
- XFREE(MTYPE_ROUTE_MAP_NAME, peer->default_rmap[afi][safi].name);
- peer->default_rmap[afi][safi].name = NULL;
- peer->default_rmap[afi][safi].map = NULL;
+ vrf = bgp_vrf_lookup_by_instance_type(bgp);
+ if (vrf)
+ bgp_vrf_unlink(bgp, vrf);
- if (peer->status == Established && peer->afc_nego[afi][safi]) {
- update_group_adjust_peer(peer_af_find(peer, afi, safi));
- bgp_default_originate (peer, afi, safi, 1);
- bgp_announce_route (peer, afi, safi);
- }
- }
- return 0;
+ thread_master_free_unused(bm->master);
+ bgp_unlock(bgp); /* initial reference */
+
+ return 0;
}
-int
-peer_port_set (struct peer *peer, u_int16_t port)
+static void bgp_free(struct bgp *);
+
+void bgp_lock(struct bgp *bgp)
{
- peer->port = port;
- return 0;
+ ++bgp->lock;
}
-int
-peer_port_unset (struct peer *peer)
+void bgp_unlock(struct bgp *bgp)
{
- peer->port = BGP_PORT_DEFAULT;
- return 0;
+ assert(bgp->lock > 0);
+ if (--bgp->lock == 0)
+ bgp_free(bgp);
}
-/*
- * Helper function that is called after the name of the policy
- * being used by a peer has changed (AF specific). Automatically
- * initiates inbound or outbound processing as needed.
- */
-static void
-peer_on_policy_change (struct peer *peer, afi_t afi, safi_t safi, int outbound)
+static void bgp_free(struct bgp *bgp)
{
- if (outbound)
- {
- update_group_adjust_peer (peer_af_find (peer, afi, safi));
- if (peer->status == Established)
- bgp_announce_route(peer, afi, safi);
- }
- else
- {
- if (peer->status != Established)
- return;
+ afi_t afi;
+ safi_t safi;
+ struct bgp_table *table;
+ struct bgp_node *rn;
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
- bgp_soft_reconfig_in (peer, afi, safi);
- else if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- }
-}
+ QOBJ_UNREG(bgp);
+ list_delete(bgp->group);
+ list_delete(bgp->peer);
-/* neighbor weight. */
-int
-peer_weight_set (struct peer *peer, afi_t afi, safi_t safi, u_int16_t weight)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (peer->weight[afi][safi] != weight)
- {
- peer->weight[afi][safi] = weight;
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_WEIGHT);
- peer_on_policy_change (peer, afi, safi, 0);
- }
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->weight[afi][safi] != weight)
- {
- peer->weight[afi][safi] = weight;
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_WEIGHT);
- peer_on_policy_change (peer, afi, safi, 0);
- }
- }
- return 0;
-}
-
-int
-peer_weight_unset (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- /* not the peer-group itself but a peer in a peer-group */
- if (peer_group_active (peer))
- {
- group = peer->group;
-
- /* inherit weight from the peer-group */
- if (CHECK_FLAG (group->conf->af_flags[afi][safi], PEER_FLAG_WEIGHT))
- {
- peer->weight[afi][safi] = group->conf->weight[afi][safi];
- peer_af_flag_set (peer, afi, safi, PEER_FLAG_WEIGHT);
- peer_on_policy_change (peer, afi, safi, 0);
- }
- else
- {
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_WEIGHT))
- {
- peer->weight[afi][safi] = 0;
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_WEIGHT);
- peer_on_policy_change (peer, afi, safi, 0);
- }
- }
- }
-
- else
- {
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_WEIGHT))
- {
- peer->weight[afi][safi] = 0;
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_WEIGHT);
- peer_on_policy_change (peer, afi, safi, 0);
- }
-
- /* peer-group member updates. */
- group = peer->group;
-
- if (group)
- {
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_WEIGHT))
- {
- peer->weight[afi][safi] = 0;
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_WEIGHT);
- peer_on_policy_change (peer, afi, safi, 0);
- }
- }
- }
- }
- return 0;
-}
-
-int
-peer_timers_set (struct peer *peer, u_int32_t keepalive, u_int32_t holdtime)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- /* keepalive value check. */
- if (keepalive > 65535)
- return BGP_ERR_INVALID_VALUE;
-
- /* Holdtime value check. */
- if (holdtime > 65535)
- return BGP_ERR_INVALID_VALUE;
-
- /* Holdtime value must be either 0 or greater than 3. */
- if (holdtime < 3 && holdtime != 0)
- return BGP_ERR_INVALID_VALUE;
-
- /* Set value to the configuration. */
- SET_FLAG (peer->config, PEER_CONFIG_TIMER);
- peer->holdtime = holdtime;
- peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- SET_FLAG (peer->config, PEER_CONFIG_TIMER);
- peer->holdtime = group->conf->holdtime;
- peer->keepalive = group->conf->keepalive;
- }
- return 0;
-}
-
-int
-peer_timers_unset (struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- /* Clear configuration. */
- UNSET_FLAG (peer->config, PEER_CONFIG_TIMER);
- peer->keepalive = 0;
- peer->holdtime = 0;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- UNSET_FLAG (peer->config, PEER_CONFIG_TIMER);
- peer->holdtime = 0;
- peer->keepalive = 0;
- }
-
- return 0;
-}
-
-int
-peer_timers_connect_set (struct peer *peer, u_int32_t connect)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (connect > 65535)
- return BGP_ERR_INVALID_VALUE;
-
- /* Set value to the configuration. */
- SET_FLAG (peer->config, PEER_CONFIG_CONNECT);
- peer->connect = connect;
-
- /* Set value to timer setting. */
- peer->v_connect = connect;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- SET_FLAG (peer->config, PEER_CONFIG_CONNECT);
- peer->connect = connect;
- peer->v_connect = connect;
- }
- return 0;
-}
-
-int
-peer_timers_connect_unset (struct peer *peer)
+ if (bgp->peerhash) {
+ hash_free(bgp->peerhash);
+ bgp->peerhash = NULL;
+ }
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ /* Special handling for 2-level routing tables. */
+ if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
+ || safi == SAFI_EVPN) {
+ for (rn = bgp_table_top(bgp->rib[afi][safi]);
+ rn; rn = bgp_route_next(rn)) {
+ table = (struct bgp_table *)rn->info;
+ bgp_table_finish(&table);
+ }
+ }
+ if (bgp->route[afi][safi])
+ bgp_table_finish(&bgp->route[afi][safi]);
+ if (bgp->aggregate[afi][safi])
+ bgp_table_finish(&bgp->aggregate[afi][safi]);
+ if (bgp->rib[afi][safi])
+ bgp_table_finish(&bgp->rib[afi][safi]);
+ }
+
+ bgp_scan_finish(bgp);
+ bgp_address_destroy(bgp);
+
+ bgp_evpn_cleanup(bgp);
+
+ if (bgp->name)
+ XFREE(MTYPE_BGP, bgp->name);
+
+ XFREE(MTYPE_BGP, bgp);
+}
+
+struct peer *peer_lookup_by_conf_if(struct bgp *bgp, const char *conf_if)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ if (!conf_if)
+ return NULL;
+
+ if (bgp != NULL) {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ if (peer->conf_if && !strcmp(peer->conf_if, conf_if)
+ && !CHECK_FLAG(peer->sflags,
+ PEER_STATUS_ACCEPT_PEER))
+ return peer;
+ } else if (bm->bgp != NULL) {
+ struct listnode *bgpnode, *nbgpnode;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp))
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ if (peer->conf_if
+ && !strcmp(peer->conf_if, conf_if)
+ && !CHECK_FLAG(peer->sflags,
+ PEER_STATUS_ACCEPT_PEER))
+ return peer;
+ }
+ return NULL;
+}
+
+struct peer *peer_lookup_by_hostname(struct bgp *bgp, const char *hostname)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ if (!hostname)
+ return NULL;
+
+ if (bgp != NULL) {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ if (peer->hostname && !strcmp(peer->hostname, hostname)
+ && !CHECK_FLAG(peer->sflags,
+ PEER_STATUS_ACCEPT_PEER))
+ return peer;
+ } else if (bm->bgp != NULL) {
+ struct listnode *bgpnode, *nbgpnode;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp))
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ if (peer->hostname
+ && !strcmp(peer->hostname, hostname)
+ && !CHECK_FLAG(peer->sflags,
+ PEER_STATUS_ACCEPT_PEER))
+ return peer;
+ }
+ return NULL;
+}
+
+struct peer *peer_lookup(struct bgp *bgp, union sockunion *su)
+{
+ struct peer *peer = NULL;
+ struct peer tmp_peer;
+
+ memset(&tmp_peer, 0, sizeof(struct peer));
+
+ /*
+ * We do not want to find the doppelganger peer so search for the peer
+ * in
+ * the hash that has PEER_FLAG_CONFIG_NODE
+ */
+ SET_FLAG(tmp_peer.flags, PEER_FLAG_CONFIG_NODE);
+
+ tmp_peer.su = *su;
+
+ if (bgp != NULL) {
+ peer = hash_lookup(bgp->peerhash, &tmp_peer);
+ } else if (bm->bgp != NULL) {
+ struct listnode *bgpnode, *nbgpnode;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, bgpnode, nbgpnode, bgp)) {
+ /* Skip VRFs, this function will not be invoked without
+ * an instance
+ * when examining VRFs.
+ */
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ peer = hash_lookup(bgp->peerhash, &tmp_peer);
+
+ if (peer)
+ break;
+ }
+ }
+
+ return peer;
+}
+
+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;
+
+ /* Create peer first; we've already checked group config is valid. */
+ peer = peer_create(su, NULL, bgp, bgp->as, group->conf->as,
+ group->conf->as_type, 0, 0, group);
+ if (!peer)
+ return NULL;
+
+ /* Link to group */
+ peer = peer_lock(peer);
+ listnode_add(group->peer, peer);
+
+ peer_group2peer_config_copy(group, 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->afc[afi][safi] = 1;
+
+ if (!peer_af_find(peer, afi, safi))
+ peer_af_create(peer, afi, safi);
+
+ peer_group2peer_config_copy_af(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)))
+ goto found_range;
+ }
+
+found_range:
+ *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[PREFIX2STR_BUFFER];
+ char buf1[PREFIX2STR_BUFFER];
+
+ sockunion2hostprefix(su, &prefix);
+
+ /* 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)
+{
+ if (BGP_PEER_SU_UNSPEC(peer))
+ return 0;
+ if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST]
+ || peer->afc[AFI_IP][SAFI_LABELED_UNICAST]
+ || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP]
+ || peer->afc[AFI_IP6][SAFI_UNICAST]
+ || peer->afc[AFI_IP6][SAFI_MULTICAST]
+ || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
+ || peer->afc[AFI_IP6][SAFI_MPLS_VPN]
+ || peer->afc[AFI_IP6][SAFI_ENCAP]
+ || peer->afc[AFI_L2VPN][SAFI_EVPN])
+ return 1;
+ return 0;
+}
+
+/* If peer is negotiated at least one address family return 1. */
+int peer_active_nego(struct peer *peer)
+{
+ if (peer->afc_nego[AFI_IP][SAFI_UNICAST]
+ || peer->afc_nego[AFI_IP][SAFI_MULTICAST]
+ || peer->afc_nego[AFI_IP][SAFI_LABELED_UNICAST]
+ || peer->afc_nego[AFI_IP][SAFI_MPLS_VPN]
+ || peer->afc_nego[AFI_IP][SAFI_ENCAP]
+ || peer->afc_nego[AFI_IP6][SAFI_UNICAST]
+ || peer->afc_nego[AFI_IP6][SAFI_MULTICAST]
+ || peer->afc_nego[AFI_IP6][SAFI_LABELED_UNICAST]
+ || peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN]
+ || peer->afc_nego[AFI_IP6][SAFI_ENCAP]
+ || peer->afc_nego[AFI_L2VPN][SAFI_EVPN])
+ return 1;
+ return 0;
+}
+
+/* peer_flag_change_type. */
+enum peer_change_type {
+ peer_change_none,
+ peer_change_reset,
+ peer_change_reset_in,
+ peer_change_reset_out,
+};
+
+static void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
+ enum peer_change_type type)
+{
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return;
+
+ if (peer->status != Established)
+ return;
+
+ if (type == peer_change_reset) {
+ /* If we're resetting session, we've to delete both peer struct
+ */
+ if ((peer->doppelganger)
+ && (peer->doppelganger->status != Deleted)
+ && (!CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else if (type == peer_change_reset_in) {
+ if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send(peer, afi, safi, 0, 0, 0);
+ else {
+ if ((peer->doppelganger)
+ && (peer->doppelganger->status != Deleted)
+ && (!CHECK_FLAG(peer->doppelganger->flags,
+ PEER_FLAG_CONFIG_NODE)))
+ peer_delete(peer->doppelganger);
+
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
+ } else if (type == peer_change_reset_out) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ bgp_announce_route(peer, afi, safi);
+ }
+}
+
+struct peer_flag_action {
+ /* Peer's flag. */
+ u_int32_t flag;
+
+ /* This flag can be set for peer-group member. */
+ u_char not_for_member;
+
+ /* Action when the flag is changed. */
+ enum peer_change_type type;
+
+ /* Peer down cause */
+ u_char peer_down;
+};
+
+static const struct peer_flag_action peer_flag_action_list[] = {
+ {PEER_FLAG_PASSIVE, 0, peer_change_reset},
+ {PEER_FLAG_SHUTDOWN, 0, peer_change_reset},
+ {PEER_FLAG_DONT_CAPABILITY, 0, peer_change_none},
+ {PEER_FLAG_OVERRIDE_CAPABILITY, 0, peer_change_none},
+ {PEER_FLAG_STRICT_CAP_MATCH, 0, peer_change_none},
+ {PEER_FLAG_DYNAMIC_CAPABILITY, 0, peer_change_reset},
+ {PEER_FLAG_DISABLE_CONNECTED_CHECK, 0, peer_change_reset},
+ {PEER_FLAG_CAPABILITY_ENHE, 0, peer_change_reset},
+ {0, 0, 0}};
+
+static const struct peer_flag_action peer_af_flag_action_list[] = {
+ {PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out},
+ {PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out},
+ {PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out},
+ {PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out},
+ {PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset},
+ {PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset},
+ {PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in},
+ {PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out},
+ {PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out},
+ {PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out},
+ // PEER_FLAG_DEFAULT_ORIGINATE
+ {PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out},
+ {PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in},
+ {PEER_FLAG_ALLOWAS_IN_ORIGIN, 0, peer_change_reset_in},
+ {PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset},
+ {PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset},
+ // PEER_FLAG_MAX_PREFIX
+ // PEER_FLAG_MAX_PREFIX_WARNING
+ {PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out},
+ {PEER_FLAG_FORCE_NEXTHOP_SELF, 1, peer_change_reset_out},
+ {PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out},
+ {PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE, 1, peer_change_reset_out},
+ {PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out},
+ {PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out},
+ {PEER_FLAG_ADDPATH_TX_ALL_PATHS, 1, peer_change_reset},
+ {PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS, 1, peer_change_reset},
+ {PEER_FLAG_WEIGHT, 0, peer_change_reset_in},
+ {0, 0, 0}};
+
+/* Proper action set. */
+static int peer_flag_action_set(const struct peer_flag_action *action_list,
+ int size, struct peer_flag_action *action,
+ u_int32_t flag)
+{
+ int i;
+ int found = 0;
+ int reset_in = 0;
+ int reset_out = 0;
+ const struct peer_flag_action *match = NULL;
+
+ /* Check peer's frag action. */
+ for (i = 0; i < size; i++) {
+ match = &action_list[i];
+
+ if (match->flag == 0)
+ break;
+
+ if (match->flag & flag) {
+ found = 1;
+
+ if (match->type == peer_change_reset_in)
+ reset_in = 1;
+ if (match->type == peer_change_reset_out)
+ reset_out = 1;
+ if (match->type == peer_change_reset) {
+ reset_in = 1;
+ reset_out = 1;
+ }
+ if (match->not_for_member)
+ action->not_for_member = 1;
+ }
+ }
+
+ /* Set peer clear type. */
+ if (reset_in && reset_out)
+ action->type = peer_change_reset;
+ else if (reset_in)
+ action->type = peer_change_reset_in;
+ else if (reset_out)
+ action->type = peer_change_reset_out;
+ else
+ action->type = peer_change_none;
+
+ return found;
+}
+
+static void peer_flag_modify_action(struct peer *peer, u_int32_t flag)
+{
+ if (flag == PEER_FLAG_SHUTDOWN) {
+ if (CHECK_FLAG(peer->flags, flag)) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop(peer);
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+ if (peer->t_pmax_restart) {
+ BGP_TIMER_OFF(peer->t_pmax_restart);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Maximum-prefix restart timer canceled",
+ peer->host);
+ }
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT))
+ peer_nsf_stop(peer);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ char *msg = peer->tx_shutdown_message;
+ size_t msglen;
+
+ if (!msg && peer_group_active(peer))
+ msg = peer->group->conf
+ ->tx_shutdown_message;
+ msglen = msg ? strlen(msg) : 0;
+ if (msglen > 128)
+ msglen = 128;
+
+ if (msglen) {
+ u_char msgbuf[129];
+
+ msgbuf[0] = msglen;
+ memcpy(msgbuf + 1, msg, msglen);
+
+ bgp_notify_send_with_data(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN,
+ msgbuf, msglen + 1);
+ } else
+ bgp_notify_send(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
+ } else
+ bgp_session_reset(peer);
+ } else {
+ peer->v_start = BGP_INIT_START_TIMER;
+ BGP_EVENT_ADD(peer, BGP_Stop);
+ }
+ } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ if (flag == PEER_FLAG_DYNAMIC_CAPABILITY)
+ peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ else if (flag == PEER_FLAG_PASSIVE)
+ peer->last_reset = PEER_DOWN_PASSIVE_CHANGE;
+ else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)
+ peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE;
+
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+}
+
+/* Change specified peer flag. */
+static int peer_flag_modify(struct peer *peer, u_int32_t flag, int set)
+{
+ int found;
+ int size;
+ struct peer_group *group;
+ struct peer *tmp_peer;
+ struct listnode *node, *nnode;
+ struct peer_flag_action action;
+
+ memset(&action, 0, sizeof(struct peer_flag_action));
+ size = sizeof peer_flag_action_list / sizeof(struct peer_flag_action);
+
+ found = peer_flag_action_set(peer_flag_action_list, size, &action,
+ flag);
+
+ /* No flag action is found. */
+ if (!found)
+ return BGP_ERR_INVALID_FLAG;
+
+ /* When unset the peer-group member's flag we have to check
+ peer-group configuration. */
+ if (!set && peer_group_active(peer))
+ if (CHECK_FLAG(peer->group->conf->flags, flag)) {
+ if (flag == PEER_FLAG_SHUTDOWN)
+ return BGP_ERR_PEER_GROUP_SHUTDOWN;
+ }
+
+ /* Flag conflict check. */
+ if (set && CHECK_FLAG(peer->flags | flag, PEER_FLAG_STRICT_CAP_MATCH)
+ && CHECK_FLAG(peer->flags | flag, PEER_FLAG_OVERRIDE_CAPABILITY))
+ return BGP_ERR_PEER_FLAG_CONFLICT;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (set && CHECK_FLAG(peer->flags, flag) == flag)
+ return 0;
+ if (!set && !CHECK_FLAG(peer->flags, flag))
+ return 0;
+ }
+
+ if (set)
+ SET_FLAG(peer->flags, flag);
+ else
+ UNSET_FLAG(peer->flags, flag);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (action.type == peer_change_reset)
+ peer_flag_modify_action(peer, flag);
+
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+
+ if (set && CHECK_FLAG(tmp_peer->flags, flag) == flag)
+ continue;
+
+ if (!set && !CHECK_FLAG(tmp_peer->flags, flag))
+ continue;
+
+ if (set)
+ SET_FLAG(tmp_peer->flags, flag);
+ else
+ UNSET_FLAG(tmp_peer->flags, flag);
+
+ if (action.type == peer_change_reset)
+ peer_flag_modify_action(tmp_peer, flag);
+ }
+ return 0;
+}
+
+int peer_flag_set(struct peer *peer, u_int32_t flag)
+{
+ return peer_flag_modify(peer, flag, 1);
+}
+
+int peer_flag_unset(struct peer *peer, u_int32_t flag)
+{
+ return peer_flag_modify(peer, flag, 0);
+}
+
+static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
+ u_int32_t flag, int set)
+{
+ int found;
+ int size;
+ struct listnode *node, *nnode;
+ struct peer_group *group;
+ struct peer_flag_action action;
+ struct peer *tmp_peer;
+ struct bgp *bgp;
+ int addpath_tx_used;
+
+ memset(&action, 0, sizeof(struct peer_flag_action));
+ size = sizeof peer_af_flag_action_list
+ / sizeof(struct peer_flag_action);
+
+ found = peer_flag_action_set(peer_af_flag_action_list, size, &action,
+ flag);
+
+ /* No flag action is found. */
+ if (!found)
+ return BGP_ERR_INVALID_FLAG;
+
+ /* Special check for reflector client. */
+ if (flag & PEER_FLAG_REFLECTOR_CLIENT
+ && peer_sort(peer) != BGP_PEER_IBGP)
+ return BGP_ERR_NOT_INTERNAL_PEER;
+
+ /* Special check for remove-private-AS. */
+ if (flag & PEER_FLAG_REMOVE_PRIVATE_AS
+ && peer_sort(peer) == BGP_PEER_IBGP)
+ return BGP_ERR_REMOVE_PRIVATE_AS;
+
+ /* as-override is not allowed for IBGP peers */
+ if (flag & PEER_FLAG_AS_OVERRIDE && peer_sort(peer) == BGP_PEER_IBGP)
+ return BGP_ERR_AS_OVERRIDE;
+
+ /* When current flag configuration is same as requested one. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (set && CHECK_FLAG(peer->af_flags[afi][safi], flag) == flag)
+ return 0;
+ if (!set && !CHECK_FLAG(peer->af_flags[afi][safi], flag))
+ return 0;
+ }
+
+ if (set)
+ SET_FLAG(peer->af_flags[afi][safi], flag);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi], flag);
+
+ /* Execute action when peer is established. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && peer->status == Established) {
+ if (!set && flag == PEER_FLAG_SOFT_RECONFIG)
+ bgp_clear_adj_in(peer, afi, safi);
+ else {
+ if (flag == PEER_FLAG_REFLECTOR_CLIENT)
+ peer->last_reset = PEER_DOWN_RR_CLIENT_CHANGE;
+ else if (flag == PEER_FLAG_RSERVER_CLIENT)
+ peer->last_reset = PEER_DOWN_RS_CLIENT_CHANGE;
+ else if (flag == PEER_FLAG_ORF_PREFIX_SM)
+ peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+ else if (flag == PEER_FLAG_ORF_PREFIX_RM)
+ peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE;
+
+ peer_change_action(peer, afi, safi, action.type);
+ }
+ }
+
+ /* Peer group member updates. */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ group = peer->group;
+
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+ if (set
+ && CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag)
+ == flag)
+ continue;
+
+ if (!set
+ && !CHECK_FLAG(tmp_peer->af_flags[afi][safi], flag))
+ continue;
+
+ if (set)
+ SET_FLAG(tmp_peer->af_flags[afi][safi], flag);
+ else
+ UNSET_FLAG(tmp_peer->af_flags[afi][safi], flag);
+
+ if (tmp_peer->status == Established) {
+ if (!set && flag == PEER_FLAG_SOFT_RECONFIG)
+ bgp_clear_adj_in(tmp_peer, afi, safi);
+ else {
+ if (flag == PEER_FLAG_REFLECTOR_CLIENT)
+ tmp_peer->last_reset =
+ PEER_DOWN_RR_CLIENT_CHANGE;
+ else if (flag
+ == PEER_FLAG_RSERVER_CLIENT)
+ tmp_peer->last_reset =
+ PEER_DOWN_RS_CLIENT_CHANGE;
+ else if (flag
+ == PEER_FLAG_ORF_PREFIX_SM)
+ tmp_peer->last_reset =
+ PEER_DOWN_CAPABILITY_CHANGE;
+ else if (flag
+ == PEER_FLAG_ORF_PREFIX_RM)
+ tmp_peer->last_reset =
+ PEER_DOWN_CAPABILITY_CHANGE;
+
+ peer_change_action(tmp_peer, afi, safi,
+ action.type);
+ }
+ }
+ }
+ }
+
+ /* Track if addpath TX is in use */
+ if (flag & (PEER_FLAG_ADDPATH_TX_ALL_PATHS
+ | PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
+ bgp = peer->bgp;
+ addpath_tx_used = 0;
+
+ if (set) {
+ addpath_tx_used = 1;
+
+ if (flag & PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS) {
+ if (!bgp_flag_check(
+ bgp, BGP_FLAG_DETERMINISTIC_MED)) {
+ zlog_warn(
+ "%s: enabling bgp deterministic-med, this is required"
+ " for addpath-tx-bestpath-per-AS",
+ peer->host);
+ bgp_flag_set(
+ bgp,
+ BGP_FLAG_DETERMINISTIC_MED);
+ bgp_recalculate_all_bestpaths(bgp);
+ }
+ }
+ } else {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode,
+ tmp_peer)) {
+ if (CHECK_FLAG(tmp_peer->af_flags[afi][safi],
+ PEER_FLAG_ADDPATH_TX_ALL_PATHS)
+ || CHECK_FLAG(
+ tmp_peer->af_flags[afi][safi],
+ PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
+ addpath_tx_used = 1;
+ break;
+ }
+ }
+ }
+
+ bgp->addpath_tx_used[afi][safi] = addpath_tx_used;
+ }
+
+ return 0;
+}
+
+int peer_af_flag_set(struct peer *peer, afi_t afi, safi_t safi, u_int32_t flag)
+{
+ return peer_af_flag_modify(peer, afi, safi, flag, 1);
+}
+
+int peer_af_flag_unset(struct peer *peer, afi_t afi, safi_t safi,
+ u_int32_t flag)
+{
+ return peer_af_flag_modify(peer, afi, safi, flag, 0);
+}
+
+
+int peer_tx_shutdown_message_set(struct peer *peer, const char *msg)
+{
+ XFREE(MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
+ peer->tx_shutdown_message =
+ msg ? XSTRDUP(MTYPE_PEER_TX_SHUTDOWN_MSG, msg) : NULL;
+ return 0;
+}
+
+int peer_tx_shutdown_message_unset(struct peer *peer)
+{
+ XFREE(MTYPE_PEER_TX_SHUTDOWN_MSG, peer->tx_shutdown_message);
+ return 0;
+}
+
+
+/* EBGP multihop configuration. */
+int peer_ebgp_multihop_set(struct peer *peer, int ttl)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer *peer1;
+
+ if (peer->sort == BGP_PEER_IBGP || peer->conf_if)
+ return 0;
+
+ /* see comment in peer_ttl_security_hops_set() */
+ if (ttl != MAXTTL) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ group = peer->group;
+ if (group->conf->gtsm_hops != 0)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
+ peer1)) {
+ if (peer1->sort == BGP_PEER_IBGP)
+ continue;
+
+ if (peer1->gtsm_hops != 0)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ }
+ } else {
+ if (peer->gtsm_hops != 0)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ }
+ }
+
+ peer->ttl = ttl;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (peer->fd >= 0 && peer->sort != BGP_PEER_IBGP) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+ }
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->sort == BGP_PEER_IBGP)
+ continue;
+
+ peer->ttl = group->conf->ttl;
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+ }
+ }
+ return 0;
+}
+
+int peer_ebgp_multihop_unset(struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (peer->sort == BGP_PEER_IBGP)
+ return 0;
+
+ if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL)
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+ if (peer_group_active(peer))
+ peer->ttl = peer->group->conf->ttl;
+ else
+ peer->ttl = 1;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->sort == BGP_PEER_IBGP)
+ continue;
+
+ peer->ttl = 1;
+
+ if (peer->fd >= 0) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(
+ peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Neighbor description. */
+int peer_description_set(struct peer *peer, const char *desc)
+{
+ if (peer->desc)
+ XFREE(MTYPE_PEER_DESC, peer->desc);
+
+ peer->desc = XSTRDUP(MTYPE_PEER_DESC, desc);
+
+ return 0;
+}
+
+int peer_description_unset(struct peer *peer)
+{
+ if (peer->desc)
+ XFREE(MTYPE_PEER_DESC, peer->desc);
+
+ peer->desc = NULL;
+
+ return 0;
+}
+
+/* Neighbor update-source. */
+int peer_update_source_if_set(struct peer *peer, const char *ifname)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (peer->update_if) {
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && strcmp(peer->update_if, ifname) == 0)
+ return 0;
+
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+
+ peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->update_if) {
+ if (strcmp(peer->update_if, ifname) == 0)
+ continue;
+
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+
+ peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ }
+ return 0;
+}
+
+int peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (peer->update_source) {
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)
+ && sockunion_cmp(peer->update_source, su) == 0)
+ return 0;
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ peer->update_source = sockunion_dup(su);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->update_source) {
+ if (sockunion_cmp(peer->update_source, su) == 0)
+ continue;
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ peer->update_source = sockunion_dup(su);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ }
+ return 0;
+}
+
+int peer_update_source_unset(struct peer *peer)
+{
+ union sockunion *su;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP) && !peer->update_source
+ && !peer->update_if)
+ return 0;
+
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ if (peer_group_active(peer)) {
+ group = peer->group;
+
+ if (group->conf->update_source) {
+ su = sockunion_dup(group->conf->update_source);
+ peer->update_source = su;
+ } else if (group->conf->update_if)
+ peer->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE,
+ group->conf->update_if);
+ }
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (!peer->update_source && !peer->update_if)
+ continue;
+
+ if (peer->update_source) {
+ sockunion_free(peer->update_source);
+ peer->update_source = NULL;
+ }
+
+ if (peer->update_if) {
+ XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if);
+ peer->update_if = NULL;
+ }
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ }
+ return 0;
+}
+
+int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *rmap)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_DEFAULT_ORIGINATE)
+ || (rmap && !peer->default_rmap[afi][safi].name)
+ || (rmap
+ && strcmp(rmap, peer->default_rmap[afi][safi].name) != 0)) {
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE);
+
+ if (rmap) {
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name =
+ XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+ peer->default_rmap[afi][safi].map =
+ route_map_lookup_by_name(rmap);
+ }
+ }
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ bgp_default_originate(peer, afi, safi, 0);
+ bgp_announce_route(peer, afi, safi);
+ }
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE);
+
+ if (rmap) {
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name =
+ XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
+ peer->default_rmap[afi][safi].map =
+ route_map_lookup_by_name(rmap);
+ }
+
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ bgp_default_originate(peer, afi, safi, 0);
+ bgp_announce_route(peer, afi, safi);
+ }
+ }
+ return 0;
+}
+
+int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE)) {
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE);
+
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name = NULL;
+ peer->default_rmap[afi][safi].map = NULL;
+ }
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ bgp_default_originate(peer, afi, safi, 1);
+ bgp_announce_route(peer, afi, safi);
+ }
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_DEFAULT_ORIGINATE);
+
+ if (peer->default_rmap[afi][safi].name)
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ peer->default_rmap[afi][safi].name);
+ peer->default_rmap[afi][safi].name = NULL;
+ peer->default_rmap[afi][safi].map = NULL;
+
+ if (peer->status == Established && peer->afc_nego[afi][safi]) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ bgp_default_originate(peer, afi, safi, 1);
+ bgp_announce_route(peer, afi, safi);
+ }
+ }
+ return 0;
+}
+
+int peer_port_set(struct peer *peer, u_int16_t port)
+{
+ peer->port = port;
+ return 0;
+}
+
+int peer_port_unset(struct peer *peer)
+{
+ peer->port = BGP_PORT_DEFAULT;
+ return 0;
+}
+
+/*
+ * Helper function that is called after the name of the policy
+ * being used by a peer has changed (AF specific). Automatically
+ * initiates inbound or outbound processing as needed.
+ */
+static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
+ int outbound)
+{
+ if (outbound) {
+ update_group_adjust_peer(peer_af_find(peer, afi, safi));
+ if (peer->status == Established)
+ bgp_announce_route(peer, afi, safi);
+ } else {
+ if (peer->status != Established)
+ return;
+
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ bgp_soft_reconfig_in(peer, afi, safi);
+ else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send(peer, afi, safi, 0, 0, 0);
+ }
+}
+
+
+/* neighbor weight. */
+int peer_weight_set(struct peer *peer, afi_t afi, safi_t safi, u_int16_t weight)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (peer->weight[afi][safi] != weight) {
+ peer->weight[afi][safi] = weight;
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->weight[afi][safi] != weight) {
+ peer->weight[afi][safi] = weight;
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+ }
+ return 0;
+}
+
+int peer_weight_unset(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ /* not the peer-group itself but a peer in a peer-group */
+ if (peer_group_active(peer)) {
+ group = peer->group;
+
+ /* inherit weight from the peer-group */
+ if (CHECK_FLAG(group->conf->af_flags[afi][safi],
+ PEER_FLAG_WEIGHT)) {
+ peer->weight[afi][safi] =
+ group->conf->weight[afi][safi];
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_WEIGHT);
+ peer_on_policy_change(peer, afi, safi, 0);
+ } else {
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_WEIGHT)) {
+ peer->weight[afi][safi] = 0;
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_WEIGHT);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+ }
+ }
+
+ else {
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_WEIGHT)) {
+ peer->weight[afi][safi] = 0;
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_WEIGHT);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+
+ if (group) {
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
+ peer)) {
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_WEIGHT)) {
+ peer->weight[afi][safi] = 0;
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_WEIGHT);
+ peer_on_policy_change(peer, afi, safi,
+ 0);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int peer_timers_set(struct peer *peer, u_int32_t keepalive, u_int32_t holdtime)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ /* keepalive value check. */
+ if (keepalive > 65535)
+ return BGP_ERR_INVALID_VALUE;
+
+ /* Holdtime value check. */
+ if (holdtime > 65535)
+ return BGP_ERR_INVALID_VALUE;
+
+ /* Holdtime value must be either 0 or greater than 3. */
+ if (holdtime < 3 && holdtime != 0)
+ return BGP_ERR_INVALID_VALUE;
+
+ /* Set value to the configuration. */
+ SET_FLAG(peer->config, PEER_CONFIG_TIMER);
+ peer->holdtime = holdtime;
+ peer->keepalive = (keepalive < holdtime / 3 ? keepalive : holdtime / 3);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ SET_FLAG(peer->config, PEER_CONFIG_TIMER);
+ peer->holdtime = group->conf->holdtime;
+ peer->keepalive = group->conf->keepalive;
+ }
+ return 0;
+}
+
+int peer_timers_unset(struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ /* Clear configuration. */
+ UNSET_FLAG(peer->config, PEER_CONFIG_TIMER);
+ peer->keepalive = 0;
+ peer->holdtime = 0;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ UNSET_FLAG(peer->config, PEER_CONFIG_TIMER);
+ peer->holdtime = 0;
+ peer->keepalive = 0;
+ }
+
+ return 0;
+}
+
+int peer_timers_connect_set(struct peer *peer, u_int32_t connect)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (connect > 65535)
+ return BGP_ERR_INVALID_VALUE;
+
+ /* Set value to the configuration. */
+ SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+ peer->connect = connect;
+
+ /* Set value to timer setting. */
+ peer->v_connect = connect;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ SET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+ peer->connect = connect;
+ peer->v_connect = connect;
+ }
+ return 0;
+}
+
+int peer_timers_connect_unset(struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ /* Clear configuration. */
+ UNSET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+ peer->connect = 0;
+
+ /* Set timer setting to default value. */
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ UNSET_FLAG(peer->config, PEER_CONFIG_CONNECT);
+ peer->connect = 0;
+ peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ }
+ return 0;
+}
+
+int peer_advertise_interval_set(struct peer *peer, u_int32_t routeadv)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (routeadv > 600)
+ return BGP_ERR_INVALID_VALUE;
+
+ SET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
+ peer->routeadv = routeadv;
+ peer->v_routeadv = routeadv;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ update_group_adjust_peer_afs(peer);
+ if (peer->status == Established)
+ bgp_announce_route_all(peer);
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ SET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
+ peer->routeadv = routeadv;
+ peer->v_routeadv = routeadv;
+ update_group_adjust_peer_afs(peer);
+ if (peer->status == Established)
+ bgp_announce_route_all(peer);
+ }
+
+ return 0;
+}
+
+int peer_advertise_interval_unset(struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ UNSET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
+ peer->routeadv = 0;
+
+ if (peer->sort == BGP_PEER_IBGP)
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ update_group_adjust_peer_afs(peer);
+ if (peer->status == Established)
+ bgp_announce_route_all(peer);
+ return 0;
+ }
+
+ /* peer-group member updates. */
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ UNSET_FLAG(peer->config, PEER_CONFIG_ROUTEADV);
+ peer->routeadv = 0;
+
+ if (peer->sort == BGP_PEER_IBGP)
+ peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
+ else
+ peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
+
+ update_group_adjust_peer_afs(peer);
+ if (peer->status == Established)
+ bgp_announce_route_all(peer);
+ }
+
+ return 0;
+}
+
+/* neighbor interface */
+void peer_interface_set(struct peer *peer, const char *str)
+{
+ if (peer->ifname)
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
+ peer->ifname = XSTRDUP(MTYPE_BGP_PEER_IFNAME, str);
+}
+
+void peer_interface_unset(struct peer *peer)
+{
+ if (peer->ifname)
+ XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
+ peer->ifname = NULL;
+}
+
+/* Allow-as in. */
+int peer_allowas_in_set(struct peer *peer, afi_t afi, safi_t safi,
+ int allow_num, int origin)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (origin) {
+ if (peer->allowas_in[afi][safi]
+ || CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN)
+ || !CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ peer->allowas_in[afi][safi] = 0;
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_set(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->allowas_in[afi][safi]
+ || CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN)
+ || !CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ peer->allowas_in[afi][safi] = 0;
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_set(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+ }
+ } else {
+ if (allow_num < 1 || allow_num > 10)
+ return BGP_ERR_INVALID_VALUE;
+
+ if (peer->allowas_in[afi][safi] != allow_num
+ || CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ peer->allowas_in[afi][safi] = allow_num;
+ peer_af_flag_set(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ if (peer->allowas_in[afi][safi] != allow_num
+ || CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ peer->allowas_in[afi][safi] = allow_num;
+ peer_af_flag_set(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int peer_allowas_in_unset(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_group *group;
+ struct peer *tmp_peer;
+ struct listnode *node, *nnode;
+
+ /* If this is a peer-group we must first clear the flags for all of the
+ * peer-group members
+ */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
+ if (CHECK_FLAG(tmp_peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN)
+ || CHECK_FLAG(tmp_peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ tmp_peer->allowas_in[afi][safi] = 0;
+ peer_af_flag_unset(tmp_peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_unset(tmp_peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer_on_policy_change(tmp_peer, afi, safi, 0);
+ }
+ }
+ }
+
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)
+ || CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ peer->allowas_in[afi][safi] = 0;
+ peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
+ peer_af_flag_unset(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN);
+ peer_on_policy_change(peer, afi, safi, 0);
+ }
+
+ return 0;
+}
+
+int peer_local_as_set(struct peer *peer, as_t as, int no_prepend,
+ int replace_as)
+{
+ struct bgp *bgp = peer->bgp;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (peer_sort(peer) != BGP_PEER_EBGP
+ && peer_sort(peer) != BGP_PEER_INTERNAL)
+ return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP;
+
+ if (bgp->as == as)
+ return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS;
+
+ if (peer->as == as)
+ return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS;
+
+ if (peer->change_local_as == as
+ && ((CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
+ && no_prepend)
+ || (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
+ && !no_prepend))
+ && ((CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
+ && replace_as)
+ || (!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
+ && !replace_as)))
+ return 0;
+
+ peer->change_local_as = as;
+ if (no_prepend)
+ SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ else
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+
+ if (replace_as)
+ SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ else
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ peer->change_local_as = as;
+ if (no_prepend)
+ SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ else
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+
+ if (replace_as)
+ SET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+ else
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ BGP_EVENT_ADD(peer, BGP_Stop);
+ }
+
+ return 0;
+}
+
+int peer_local_as_unset(struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (!peer->change_local_as)
+ return 0;
+
+ peer->change_local_as = 0;
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ BGP_EVENT_ADD(peer, BGP_Stop);
+
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ peer->change_local_as = 0;
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
+ UNSET_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
+ peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ } else
+ bgp_session_reset(peer);
+ }
+ return 0;
+}
+
+/* Set password for authenticating with the peer. */
+int peer_password_set(struct peer *peer, const char *password)
+{
+ struct listnode *nn, *nnode;
+ int len = password ? strlen(password) : 0;
+ int ret = BGP_SUCCESS;
+
+ if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN))
+ return BGP_ERR_INVALID_VALUE;
+
+ if (peer->password && strcmp(peer->password, password) == 0
+ && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ if (peer->password)
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+
+ peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+
+ if (BGP_PEER_SU_UNSPEC(peer))
+ return BGP_SUCCESS;
+
+ return (bgp_md5_set(peer) >= 0) ? BGP_SUCCESS
+ : BGP_ERR_TCPSIG_FAILED;
+ }
+
+ for (ALL_LIST_ELEMENTS(peer->group->peer, nn, nnode, peer)) {
+ if (peer->password && strcmp(peer->password, password) == 0)
+ continue;
+
+ if (peer->password)
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+
+ peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+
+ if (!BGP_PEER_SU_UNSPEC(peer)) {
+ if (bgp_md5_set(peer) < 0)
+ ret = BGP_ERR_TCPSIG_FAILED;
+ }
+ }
+
+ return ret;
+}
+
+int peer_password_unset(struct peer *peer)
+{
+ struct listnode *nn, *nnode;
+
+ if (!peer->password && !CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+
+ if (peer->password)
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+
+ peer->password = NULL;
+
+ if (!BGP_PEER_SU_UNSPEC(peer))
+ bgp_md5_unset(peer);
+
+ return 0;
+ }
+
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+ peer->password = NULL;
+
+ for (ALL_LIST_ELEMENTS(peer->group->peer, nn, nnode, peer)) {
+ if (!peer->password)
+ continue;
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ else
+ bgp_session_reset(peer);
+
+ XFREE(MTYPE_PEER_PASSWORD, peer->password);
+ peer->password = NULL;
+
+ if (!BGP_PEER_SU_UNSPEC(peer))
+ bgp_md5_unset(peer);
+ }
+
+ return 0;
+}
+
+
+/* Set distribute list to the peer. */
+int peer_distribute_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
+ const char *name)
+{
+ struct bgp_filter *filter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != FILTER_IN && direct != FILTER_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ if (filter->plist[direct].name)
+ return BGP_ERR_PEER_FILTER_CONFLICT;
+
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
+ filter->dlist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->dlist[direct].alist = access_list_lookup(afi, name);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->dlist[direct].name);
+ filter->dlist[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->dlist[direct].alist = access_list_lookup(afi, name);
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ }
+
+ return 0;
+}
+
+int peer_distribute_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
+{
+ struct bgp_filter *filter;
+ struct bgp_filter *gfilter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != FILTER_IN && direct != FILTER_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ /* apply peer-group filter */
+ if (peer_group_active(peer)) {
+ gfilter = &peer->group->conf->filter[afi][safi];
+
+ if (gfilter->dlist[direct].name) {
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->dlist[direct].name);
+ filter->dlist[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->dlist[direct].name);
+ filter->dlist[direct].alist =
+ gfilter->dlist[direct].alist;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+ }
+
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
+ filter->dlist[direct].name = NULL;
+ filter->dlist[direct].alist = NULL;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->dlist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->dlist[direct].name);
+ filter->dlist[direct].name = NULL;
+ filter->dlist[direct].alist = NULL;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ }
+
+ return 0;
+}
+
+/* Update distribute list. */
+static void peer_distribute_update(struct access_list *access)
+{
+ afi_t afi;
+ safi_t safi;
+ int direct;
+ struct listnode *mnode, *mnnode;
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer_group *group;
+ struct bgp_filter *filter;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+ if (access->name)
+ update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST,
+ access->name, 0, 0);
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ filter = &peer->filter[afi][safi];
+
+ for (direct = FILTER_IN;
+ direct < FILTER_MAX; direct++) {
+ if (filter->dlist[direct].name)
+ filter->dlist[direct]
+ .alist = access_list_lookup(
+ afi,
+ filter->dlist[direct]
+ .name);
+ else
+ filter->dlist[direct]
+ .alist = NULL;
+ }
+ }
+ }
+ for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ filter =
+ &group->conf->filter[afi][safi];
+
+ for (direct = FILTER_IN;
+ direct < FILTER_MAX; direct++) {
+ if (filter->dlist[direct].name)
+ filter->dlist[direct]
+ .alist = access_list_lookup(
+ afi,
+ filter->dlist[direct]
+ .name);
+ else
+ filter->dlist[direct]
+ .alist = NULL;
+ }
+ }
+ }
+#if ENABLE_BGP_VNC
+ vnc_prefix_list_update(bgp);
+#endif
+ }
+}
+
+/* Set prefix list to the peer. */
+int peer_prefix_list_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
+ const char *name)
+{
+ struct bgp_filter *filter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != FILTER_IN && direct != FILTER_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ if (filter->dlist[direct].name)
+ return BGP_ERR_PEER_FILTER_CONFLICT;
+
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
+ filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->plist[direct].plist = prefix_list_lookup(afi, name);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->plist[direct].name);
+ filter->plist[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->plist[direct].plist = prefix_list_lookup(afi, name);
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ }
+ return 0;
+}
+
+int peer_prefix_list_unset(struct peer *peer, afi_t afi, safi_t safi,
+ int direct)
+{
+ struct bgp_filter *filter;
+ struct bgp_filter *gfilter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != FILTER_IN && direct != FILTER_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ /* apply peer-group filter */
+ if (peer_group_active(peer)) {
+ gfilter = &peer->group->conf->filter[afi][safi];
+
+ if (gfilter->plist[direct].name) {
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->plist[direct].name);
+ filter->plist[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->plist[direct].name);
+ filter->plist[direct].plist =
+ gfilter->plist[direct].plist;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+ }
+
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
+ filter->plist[direct].name = NULL;
+ filter->plist[direct].plist = NULL;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->plist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->plist[direct].name);
+ filter->plist[direct].name = NULL;
+ filter->plist[direct].plist = NULL;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ }
+
+ return 0;
+}
+
+/* Update prefix-list list. */
+static void peer_prefix_list_update(struct prefix_list *plist)
+{
+ struct listnode *mnode, *mnnode;
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer_group *group;
+ struct bgp_filter *filter;
+ afi_t afi;
+ safi_t safi;
+ int direct;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+
+ /*
+ * Update the prefix-list on update groups.
+ */
+ update_group_policy_update(
+ bgp, BGP_POLICY_PREFIX_LIST,
+ plist ? prefix_list_name(plist) : NULL, 0, 0);
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ filter = &peer->filter[afi][safi];
+
+ for (direct = FILTER_IN;
+ direct < FILTER_MAX; direct++) {
+ if (filter->plist[direct].name)
+ filter->plist[direct]
+ .plist = prefix_list_lookup(
+ afi,
+ filter->plist[direct]
+ .name);
+ else
+ filter->plist[direct]
+ .plist = NULL;
+ }
+ }
+ }
+ for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ filter =
+ &group->conf->filter[afi][safi];
+
+ for (direct = FILTER_IN;
+ direct < FILTER_MAX; direct++) {
+ if (filter->plist[direct].name)
+ filter->plist[direct]
+ .plist = prefix_list_lookup(
+ afi,
+ filter->plist[direct]
+ .name);
+ else
+ filter->plist[direct]
+ .plist = NULL;
+ }
+ }
+ }
+ }
+}
+
+int peer_aslist_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
+ const char *name)
+{
+ struct bgp_filter *filter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != FILTER_IN && direct != FILTER_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
+ filter->aslist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->aslist[direct].aslist = as_list_lookup(name);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->aslist[direct].name);
+ filter->aslist[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->aslist[direct].aslist = as_list_lookup(name);
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ }
+ return 0;
+}
+
+int peer_aslist_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
+{
+ struct bgp_filter *filter;
+ struct bgp_filter *gfilter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != FILTER_IN && direct != FILTER_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ /* apply peer-group filter */
+ if (peer_group_active(peer)) {
+ gfilter = &peer->group->conf->filter[afi][safi];
+
+ if (gfilter->aslist[direct].name) {
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->aslist[direct].name);
+ filter->aslist[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->aslist[direct].name);
+ filter->aslist[direct].aslist =
+ gfilter->aslist[direct].aslist;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+ }
+
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
+ filter->aslist[direct].name = NULL;
+ filter->aslist[direct].aslist = NULL;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->aslist[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->aslist[direct].name);
+ filter->aslist[direct].name = NULL;
+ filter->aslist[direct].aslist = NULL;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == FILTER_OUT) ? 1 : 0);
+ }
+
+ return 0;
+}
+
+static void peer_aslist_update(const char *aslist_name)
+{
+ afi_t afi;
+ safi_t safi;
+ int direct;
+ struct listnode *mnode, *mnnode;
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ struct peer *peer;
+ struct peer_group *group;
+ struct bgp_filter *filter;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+ update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST,
+ aslist_name, 0, 0);
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ filter = &peer->filter[afi][safi];
+
+ for (direct = FILTER_IN;
+ direct < FILTER_MAX; direct++) {
+ if (filter->aslist[direct].name)
+ filter->aslist[direct]
+ .aslist = as_list_lookup(
+ filter->aslist[direct]
+ .name);
+ else
+ filter->aslist[direct]
+ .aslist = NULL;
+ }
+ }
+ }
+ for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
+ for (afi = AFI_IP; afi < AFI_MAX; afi++)
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX;
+ safi++) {
+ filter =
+ &group->conf->filter[afi][safi];
+
+ for (direct = FILTER_IN;
+ direct < FILTER_MAX; direct++) {
+ if (filter->aslist[direct].name)
+ filter->aslist[direct]
+ .aslist = as_list_lookup(
+ filter->aslist[direct]
+ .name);
+ else
+ filter->aslist[direct]
+ .aslist = NULL;
+ }
+ }
+ }
+ }
+}
+
+static void peer_aslist_add(char *aslist_name)
+{
+ peer_aslist_update(aslist_name);
+ route_map_notify_dependencies((char *)aslist_name,
+ RMAP_EVENT_ASLIST_ADDED);
+}
+
+static void peer_aslist_del(const char *aslist_name)
{
- struct peer_group *group;
- struct listnode *node, *nnode;
+ peer_aslist_update(aslist_name);
+ route_map_notify_dependencies(aslist_name, RMAP_EVENT_ASLIST_DELETED);
+}
+
+
+int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
+ const char *name)
+{
+ struct bgp_filter *filter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != RMAP_IN && direct != RMAP_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+
+ filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->map[direct].map = route_map_lookup_by_name(name);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == RMAP_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->map[direct].map = route_map_lookup_by_name(name);
+ peer_on_policy_change(peer, afi, safi,
+ (direct == RMAP_OUT) ? 1 : 0);
+ }
+ return 0;
+}
+
+/* Unset route-map from the peer. */
+int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
+{
+ struct bgp_filter *filter;
+ struct bgp_filter *gfilter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ if (direct != RMAP_IN && direct != RMAP_OUT)
+ return BGP_ERR_INVALID_VALUE;
+
+ filter = &peer->filter[afi][safi];
+
+ /* apply peer-group filter */
+ if (peer_group_active(peer)) {
+ gfilter = &peer->group->conf->filter[afi][safi];
+
+ if (gfilter->map[direct].name) {
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME,
+ filter->map[direct].name);
+ filter->map[direct].name =
+ XSTRDUP(MTYPE_BGP_FILTER_NAME,
+ gfilter->map[direct].name);
+ filter->map[direct].map = gfilter->map[direct].map;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == RMAP_OUT) ? 1 : 0);
+ return 0;
+ }
+ }
+
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ filter->map[direct].name = NULL;
+ filter->map[direct].map = NULL;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi,
+ (direct == RMAP_OUT) ? 1 : 0);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->map[direct].name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ filter->map[direct].name = NULL;
+ filter->map[direct].map = NULL;
+ peer_on_policy_change(peer, afi, safi,
+ (direct == RMAP_OUT) ? 1 : 0);
+ }
+ return 0;
+}
+
+/* Set unsuppress-map to the peer. */
+int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *name)
+{
+ struct bgp_filter *filter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ filter = &peer->filter[afi][safi];
+
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+
+ filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->usmap.map = route_map_lookup_by_name(name);
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi, 1);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
+ filter->usmap.map = route_map_lookup_by_name(name);
+ peer_on_policy_change(peer, afi, safi, 1);
+ }
+ return 0;
+}
+
+/* Unset route-map from the peer. */
+int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct bgp_filter *filter;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ filter = &peer->filter[afi][safi];
+
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ filter->usmap.name = NULL;
+ filter->usmap.map = NULL;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer_on_policy_change(peer, afi, safi, 1);
+ return 0;
+ }
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ filter = &peer->filter[afi][safi];
+
+ if (filter->usmap.name)
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
+ filter->usmap.name = NULL;
+ filter->usmap.map = NULL;
+ peer_on_policy_change(peer, afi, safi, 1);
+ }
+ return 0;
+}
+
+int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
+ u_int32_t max, u_char threshold, int warning,
+ u_int16_t restart)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ peer->pmax[afi][safi] = max;
+ peer->pmax_threshold[afi][safi] = threshold;
+ peer->pmax_restart[afi][safi] = restart;
+ if (warning)
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX);
+ peer->pmax[afi][safi] = max;
+ peer->pmax_threshold[afi][safi] = threshold;
+ peer->pmax_restart[afi][safi] = restart;
+ if (warning)
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+
+ if ((peer->status == Established)
+ && (peer->afc[afi][safi]))
+ bgp_maximum_prefix_overflow(peer, afi, safi, 1);
+ }
+ } else {
+ if ((peer->status == Established) && (peer->afc[afi][safi]))
+ bgp_maximum_prefix_overflow(peer, afi, safi, 1);
+ }
+
+ return 0;
+}
- /* Clear configuration. */
- UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT);
- peer->connect = 0;
+int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ /* apply peer-group config */
+ if (peer_group_active(peer)) {
+ if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX))
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX);
+
+ if (CHECK_FLAG(peer->group->conf->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING))
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ else
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+
+ peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi];
+ peer->pmax_threshold[afi][safi] =
+ peer->group->conf->pmax_threshold[afi][safi];
+ peer->pmax_restart[afi][safi] =
+ peer->group->conf->pmax_restart[afi][safi];
+ return 0;
+ }
- /* Set timer setting to default value. */
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
+ peer->pmax[afi][safi] = 0;
+ peer->pmax_threshold[afi][safi] = 0;
+ peer->pmax_restart[afi][safi] = 0;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
+ return 0;
+
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ peer->pmax[afi][safi] = 0;
+ peer->pmax_threshold[afi][safi] = 0;
+ peer->pmax_restart[afi][safi] = 0;
+ }
+ return 0;
+}
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- UNSET_FLAG (peer->config, PEER_CONFIG_CONNECT);
- peer->connect = 0;
- peer->v_connect = BGP_DEFAULT_CONNECT_RETRY;
- }
- return 0;
-}
-
-int
-peer_advertise_interval_set (struct peer *peer, u_int32_t routeadv)
+int is_ebgp_multihop_configured(struct peer *peer)
{
- struct peer_group *group;
- struct listnode *node, *nnode;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ struct peer *peer1;
- if (routeadv > 600)
- return BGP_ERR_INVALID_VALUE;
-
- SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = routeadv;
- peer->v_routeadv = routeadv;
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ group = peer->group;
+ if ((peer_sort(peer) != BGP_PEER_IBGP)
+ && (group->conf->ttl != 1))
+ return 1;
+
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer1)) {
+ if ((peer_sort(peer1) != BGP_PEER_IBGP)
+ && (peer1->ttl != 1))
+ return 1;
+ }
+ } else {
+ if ((peer_sort(peer) != BGP_PEER_IBGP) && (peer->ttl != 1))
+ return 1;
+ }
+ return 0;
+}
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) {
- update_group_adjust_peer_afs (peer);
- if (peer->status == Established)
- bgp_announce_route_all (peer);
- return 0;
- }
+/* Set # of hops between us and BGP peer. */
+int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ int ret;
+
+ zlog_debug("peer_ttl_security_hops_set: set gtsm_hops to %d for %s",
+ gtsm_hops, peer->host);
+
+ /* We cannot configure ttl-security hops when ebgp-multihop is already
+ set. For non peer-groups, the check is simple. For peer-groups,
+ it's
+ slightly messy, because we need to check both the peer-group
+ structure
+ and all peer-group members for any trace of ebgp-multihop
+ configuration
+ before actually applying the ttl-security rules. Cisco really made a
+ mess of this configuration parameter, and OpenBGPD got it right.
+ */
+
+ if ((peer->gtsm_hops == 0) && (peer->sort != BGP_PEER_IBGP)) {
+ if (is_ebgp_multihop_configured(peer))
+ return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer->gtsm_hops = gtsm_hops;
+
+ /* Calling ebgp multihop also resets the session.
+ * On restart, NHT will get setup correctly as will the
+ * min & max ttls on the socket. The return value is
+ * irrelevant.
+ */
+ ret = peer_ebgp_multihop_set(peer, MAXTTL);
+
+ if (ret != 0)
+ return ret;
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
+ peer)) {
+ peer->gtsm_hops = group->conf->gtsm_hops;
+
+ /* Calling ebgp multihop also resets the
+ * session.
+ * On restart, NHT will get setup correctly as
+ * will the
+ * min & max ttls on the socket. The return
+ * value is
+ * irrelevant.
+ */
+ peer_ebgp_multihop_set(peer, MAXTTL);
+ }
+ }
+ } else {
+ /* Post the first gtsm setup or if its ibgp, maxttl setting
+ * isn't
+ * necessary, just set the minttl.
+ */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ peer->gtsm_hops = gtsm_hops;
+
+ if (peer->fd >= 0)
+ sockopt_minttl(peer->su.sa.sa_family, peer->fd,
+ MAXTTL + 1 - gtsm_hops);
+ if ((peer->status < Established) && peer->doppelganger
+ && (peer->doppelganger->fd >= 0))
+ sockopt_minttl(peer->su.sa.sa_family,
+ peer->doppelganger->fd,
+ MAXTTL + 1 - gtsm_hops);
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
+ peer)) {
+ peer->gtsm_hops = group->conf->gtsm_hops;
+
+ /* Change setting of existing peer
+ * established then change value (may break
+ * connectivity)
+ * not established yet (teardown session and
+ * restart)
+ * no session then do nothing (will get
+ * handled by next connection)
+ */
+ if (peer->fd >= 0 && peer->gtsm_hops != 0)
+ sockopt_minttl(
+ peer->su.sa.sa_family, peer->fd,
+ MAXTTL + 1 - peer->gtsm_hops);
+ if ((peer->status < Established)
+ && peer->doppelganger
+ && (peer->doppelganger->fd >= 0))
+ sockopt_minttl(peer->su.sa.sa_family,
+ peer->doppelganger->fd,
+ MAXTTL + 1 - gtsm_hops);
+ }
+ }
+ }
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- SET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = routeadv;
- peer->v_routeadv = routeadv;
- update_group_adjust_peer_afs (peer);
- if (peer->status == Established)
- bgp_announce_route_all (peer);
- }
-
- return 0;
+ return 0;
}
-int
-peer_advertise_interval_unset (struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
+int peer_ttl_security_hops_unset(struct peer *peer)
+{
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+ int ret = 0;
+
+ zlog_debug("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s",
+ peer->host);
+
+ /* if a peer-group member, then reset to peer-group default rather than
+ * 0 */
+ if (peer_group_active(peer))
+ peer->gtsm_hops = peer->group->conf->gtsm_hops;
+ else
+ peer->gtsm_hops = 0;
+
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Invoking ebgp_multihop_set will set the TTL back to the
+ * original
+ * value as well as restting the NHT and such. The session is
+ * reset.
+ */
+ if (peer->sort == BGP_PEER_EBGP)
+ ret = peer_ebgp_multihop_unset(peer);
+ else {
+ if (peer->fd >= 0)
+ sockopt_minttl(peer->su.sa.sa_family, peer->fd,
+ 0);
+
+ if ((peer->status < Established) && peer->doppelganger
+ && (peer->doppelganger->fd >= 0))
+ sockopt_minttl(peer->su.sa.sa_family,
+ peer->doppelganger->fd, 0);
+ }
+ } else {
+ group = peer->group;
+ for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
+ peer->gtsm_hops = 0;
+ if (peer->sort == BGP_PEER_EBGP)
+ ret = peer_ebgp_multihop_unset(peer);
+ else {
+ if (peer->fd >= 0)
+ sockopt_minttl(peer->su.sa.sa_family,
+ peer->fd, 0);
+
+ if ((peer->status < Established)
+ && peer->doppelganger
+ && (peer->doppelganger->fd >= 0))
+ sockopt_minttl(peer->su.sa.sa_family,
+ peer->doppelganger->fd,
+ 0);
+ }
+ }
+ }
- UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = 0;
-
- if (peer->sort == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP)) {
- update_group_adjust_peer_afs (peer);
- if (peer->status == Established)
- bgp_announce_route_all (peer);
- return 0;
- }
-
- /* peer-group member updates. */
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- UNSET_FLAG (peer->config, PEER_CONFIG_ROUTEADV);
- peer->routeadv = 0;
-
- if (peer->sort == BGP_PEER_IBGP)
- peer->v_routeadv = BGP_DEFAULT_IBGP_ROUTEADV;
- else
- peer->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
-
- update_group_adjust_peer_afs (peer);
- if (peer->status == Established)
- bgp_announce_route_all (peer);
- }
-
- return 0;
+ return ret;
}
-/* neighbor interface */
-void
-peer_interface_set (struct peer *peer, const char *str)
-{
- if (peer->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
- peer->ifname = XSTRDUP(MTYPE_BGP_PEER_IFNAME, str);
+/*
+ * If peer clear is invoked in a loop for all peers on the BGP instance,
+ * it may end up freeing the doppelganger, and if this was the next node
+ * to the current node, we would end up accessing the freed next node.
+ * Pass along additional parameter which can be updated if next node
+ * is freed; only required when walking the peer list on BGP instance.
+ */
+int peer_clear(struct peer *peer, struct listnode **nnode)
+{
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) {
+ UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+ if (peer->t_pmax_restart) {
+ BGP_TIMER_OFF(peer->t_pmax_restart);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Maximum-prefix restart timer canceled",
+ peer->host);
+ }
+ BGP_EVENT_ADD(peer, BGP_Start);
+ return 0;
+ }
+
+ peer->v_start = BGP_INIT_START_TIMER;
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_ADMIN_RESET);
+ else
+ bgp_session_reset_safe(peer, nnode);
+ }
+ return 0;
}
-void
-peer_interface_unset (struct peer *peer)
+int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
+ enum bgp_clear_type stype)
{
- if (peer->ifname)
- XFREE(MTYPE_BGP_PEER_IFNAME, peer->ifname);
- peer->ifname = NULL;
-}
+ struct peer_af *paf;
-/* Allow-as in. */
-int
-peer_allowas_in_set (struct peer *peer, afi_t afi, safi_t safi, int allow_num,
- int origin)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (origin)
- {
- if (peer->allowas_in[afi][safi] ||
- CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
- !CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_set (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change (peer, afi, safi, 0);
- }
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->allowas_in[afi][safi] ||
- CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
- !CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_set (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change (peer, afi, safi, 0);
- }
- }
- }
- else
- {
- if (allow_num < 1 || allow_num > 10)
- return BGP_ERR_INVALID_VALUE;
-
- if (peer->allowas_in[afi][safi] != allow_num ||
- CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- peer->allowas_in[afi][safi] = allow_num;
- peer_af_flag_set (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change (peer, afi, safi, 0);
- }
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- if (peer->allowas_in[afi][safi] != allow_num ||
- CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- peer->allowas_in[afi][safi] = allow_num;
- peer_af_flag_set (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change (peer, afi, safi, 0);
- }
- }
- }
-
- return 0;
-}
-
-int
-peer_allowas_in_unset (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct peer_group *group;
- struct peer *tmp_peer;
- struct listnode *node, *nnode;
-
- /* If this is a peer-group we must first clear the flags for all of the
- * peer-group members
- */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, tmp_peer))
- {
- if (CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
- CHECK_FLAG (tmp_peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- tmp_peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset (tmp_peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset (tmp_peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change (tmp_peer, afi, safi, 0);
- }
- }
- }
-
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN) ||
- CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- peer->allowas_in[afi][safi] = 0;
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN);
- peer_af_flag_unset (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN);
- peer_on_policy_change (peer, afi, safi, 0);
- }
-
- return 0;
-}
-
-int
-peer_local_as_set (struct peer *peer, as_t as, int no_prepend, int replace_as)
-{
- struct bgp *bgp = peer->bgp;
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (peer_sort (peer) != BGP_PEER_EBGP
- && peer_sort (peer) != BGP_PEER_INTERNAL)
- return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP;
-
- if (bgp->as == as)
- return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS;
-
- if (peer->as == as)
- return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS;
-
- if (peer->change_local_as == as &&
- ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && no_prepend)
- || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) && ! no_prepend)) &&
- ((CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && replace_as)
- || (! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) && ! replace_as)))
- return 0;
-
- peer->change_local_as = as;
- if (no_prepend)
- SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- else
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-
- if (replace_as)
- SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- else
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- peer->change_local_as = as;
- if (no_prepend)
- SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- else
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
-
- if (replace_as)
- SET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- else
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- BGP_EVENT_ADD (peer, BGP_Stop);
- }
-
- return 0;
-}
-
-int
-peer_local_as_unset (struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (! peer->change_local_as)
- return 0;
-
- peer->change_local_as = 0;
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- BGP_EVENT_ADD (peer, BGP_Stop);
-
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- peer->change_local_as = 0;
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- UNSET_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- }
- else
- bgp_session_reset(peer);
- }
- return 0;
-}
+ if (peer->status != Established)
+ return 0;
-/* Set password for authenticating with the peer. */
-int
-peer_password_set (struct peer *peer, const char *password)
-{
- struct listnode *nn, *nnode;
- int len = password ? strlen(password) : 0;
- int ret = BGP_SUCCESS;
-
- if ((len < PEER_PASSWORD_MINLEN) || (len > PEER_PASSWORD_MAXLEN))
- return BGP_ERR_INVALID_VALUE;
-
- if (peer->password && strcmp (peer->password, password) == 0
- && ! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- if (peer->password)
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
-
- peer->password = XSTRDUP (MTYPE_PEER_PASSWORD, password);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
-
- if (BGP_PEER_SU_UNSPEC(peer))
- return BGP_SUCCESS;
-
- return (bgp_md5_set (peer) >= 0) ? BGP_SUCCESS : BGP_ERR_TCPSIG_FAILED;
- }
-
- for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer))
- {
- if (peer->password && strcmp (peer->password, password) == 0)
- continue;
-
- if (peer->password)
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
-
- peer->password = XSTRDUP(MTYPE_PEER_PASSWORD, password);
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
-
- if (! BGP_PEER_SU_UNSPEC(peer))
- {
- if (bgp_md5_set (peer) < 0)
- ret = BGP_ERR_TCPSIG_FAILED;
- }
- }
-
- return ret;
-}
-
-int
-peer_password_unset (struct peer *peer)
-{
- struct listnode *nn, *nnode;
-
- if (!peer->password
- && !CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- if (!CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
-
- if (peer->password)
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
-
- peer->password = NULL;
-
- if (! BGP_PEER_SU_UNSPEC(peer))
- bgp_md5_unset (peer);
-
- return 0;
- }
-
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
-
- for (ALL_LIST_ELEMENTS (peer->group->peer, nn, nnode, peer))
- {
- if (!peer->password)
- continue;
-
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- else
- bgp_session_reset(peer);
-
- XFREE (MTYPE_PEER_PASSWORD, peer->password);
- peer->password = NULL;
-
- if (! BGP_PEER_SU_UNSPEC(peer))
- bgp_md5_unset (peer);
- }
-
- return 0;
+ if (!peer->afc[afi][safi])
+ return BGP_ERR_AF_UNCONFIGURED;
+
+ peer->rtt = sockopt_tcp_rtt(peer->fd);
+
+ if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH) {
+ /* Clear the "neighbor x.x.x.x default-originate" flag */
+ paf = peer_af_find(peer, afi, safi);
+ if (paf && paf->subgroup
+ && CHECK_FLAG(paf->subgroup->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE))
+ UNSET_FLAG(paf->subgroup->sflags,
+ SUBGRP_STATUS_DEFAULT_ORIGINATE);
+
+ bgp_announce_route(peer, afi, safi);
+ }
+
+ if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) {
+ if (CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_SM_ADV)
+ && (CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_RCV)
+ || CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_OLD_RCV))) {
+ struct bgp_filter *filter = &peer->filter[afi][safi];
+ u_char prefix_type;
+
+ if (CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_ORF_PREFIX_RM_RCV))
+ prefix_type = ORF_TYPE_PREFIX;
+ else
+ prefix_type = ORF_TYPE_PREFIX_OLD;
+
+ if (filter->plist[FILTER_IN].plist) {
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_ORF_PREFIX_SEND))
+ bgp_route_refresh_send(
+ peer, afi, safi, prefix_type,
+ REFRESH_DEFER, 1);
+ bgp_route_refresh_send(peer, afi, safi,
+ prefix_type,
+ REFRESH_IMMEDIATE, 0);
+ } else {
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_ORF_PREFIX_SEND))
+ bgp_route_refresh_send(
+ peer, afi, safi, prefix_type,
+ REFRESH_IMMEDIATE, 1);
+ else
+ bgp_route_refresh_send(peer, afi, safi,
+ 0, 0, 0);
+ }
+ return 0;
+ }
+ }
+
+ if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH
+ || stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) {
+ /* If neighbor has soft reconfiguration inbound flag.
+ Use Adj-RIB-In database. */
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG))
+ bgp_soft_reconfig_in(peer, afi, safi);
+ else {
+ /* If neighbor has route refresh capability, send route
+ refresh
+ message to the peer. */
+ if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV)
+ || CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV))
+ bgp_route_refresh_send(peer, afi, safi, 0, 0,
+ 0);
+ else
+ return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED;
+ }
+ }
+ return 0;
}
+/* Display peer uptime.*/
+char *peer_uptime(time_t uptime2, char *buf, size_t len, u_char use_json,
+ json_object *json)
+{
+ time_t uptime1, epoch_tbuf;
+ struct tm *tm;
+
+ /* Check buffer length. */
+ if (len < BGP_UPTIME_LEN) {
+ if (!use_json) {
+ zlog_warn("peer_uptime (): buffer shortage %lu",
+ (u_long)len);
+ /* XXX: should return status instead of buf... */
+ snprintf(buf, len, "<error> ");
+ }
+ return buf;
+ }
-/* Set distribute list to the peer. */
-int
-peer_distribute_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
- const char *name)
-{
- struct bgp_filter *filter;
- struct peer_group *group;
- struct listnode *node, *nnode;
+ /* If there is no connection has been done before print `never'. */
+ if (uptime2 == 0) {
+ if (use_json) {
+ json_object_string_add(json, "peerUptime", "never");
+ json_object_int_add(json, "peerUptimeMsec", 0);
+ } else
+ snprintf(buf, len, "never");
+ return buf;
+ }
- if (direct != FILTER_IN && direct != FILTER_OUT)
- return BGP_ERR_INVALID_VALUE;
+ /* Get current time. */
+ uptime1 = bgp_clock();
+ uptime1 -= uptime2;
+ tm = gmtime(&uptime1);
- filter = &peer->filter[afi][safi];
+/* Making formatted timer strings. */
+#define ONE_DAY_SECOND 60*60*24
+#define ONE_WEEK_SECOND ONE_DAY_SECOND*7
+#define ONE_YEAR_SECOND ONE_DAY_SECOND*365
- if (filter->plist[direct].name)
- return BGP_ERR_PEER_FILTER_CONFLICT;
+ if (uptime1 < ONE_DAY_SECOND)
+ snprintf(buf, len, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+ else if (uptime1 < ONE_WEEK_SECOND)
+ snprintf(buf, len, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
+ tm->tm_min);
+ else if (uptime1 < ONE_YEAR_SECOND)
+ snprintf(buf, len, "%02dw%dd%02dh", tm->tm_yday / 7,
+ tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
+ else
+ snprintf(buf, len, "%02dy%02dw%dd", tm->tm_year - 70,
+ tm->tm_yday / 7,
+ tm->tm_yday - ((tm->tm_yday / 7) * 7));
+
+ if (use_json) {
+ epoch_tbuf = time(NULL) - uptime1;
+ json_object_string_add(json, "peerUptime", buf);
+ json_object_int_add(json, "peerUptimeMsec", uptime1 * 1000);
+ json_object_int_add(json, "peerUptimeEstablishedEpoch",
+ epoch_tbuf);
+ }
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->dlist[direct].alist = access_list_lookup (afi, name);
+ return buf;
+}
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+static void afi_header_vty_out(struct vty *vty, afi_t afi, safi_t safi,
+ int *write, const char *format, ...)
+{
+ va_list args;
+ int len = 0;
+ char buf[1024];
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
+ bgp_config_write_family_header(vty, afi, safi, write);
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->dlist[direct].alist = access_list_lookup (afi, name);
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- }
+ if (vty_shell(vty)) {
+ va_start(args, format);
+ vprintf(format, args);
+ va_end(args);
+ } else {
+ va_start(args, format);
+ len = vsnprintf(buf, sizeof(buf), format, args);
+ va_end(args);
- return 0;
+ buffer_put(vty->obuf, (u_char *)buf, len);
+ }
}
-int
-peer_distribute_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
+static void bgp_config_write_filter(struct vty *vty, struct peer *peer,
+ afi_t afi, safi_t safi, int *write)
{
- struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
- struct listnode *node, *nnode;
+ struct bgp_filter *filter;
+ struct bgp_filter *gfilter = NULL;
+ char *addr;
+ int in = FILTER_IN;
+ int out = FILTER_OUT;
- if (direct != FILTER_IN && direct != FILTER_OUT)
- return BGP_ERR_INVALID_VALUE;
+ addr = peer->host;
+ filter = &peer->filter[afi][safi];
- filter = &peer->filter[afi][safi];
+ if (peer_group_active(peer))
+ gfilter = &peer->group->conf->filter[afi][safi];
+
+ /* distribute-list. */
+ if (filter->dlist[in].name)
+ if (!gfilter || !gfilter->dlist[in].name
+ || strcmp(filter->dlist[in].name, gfilter->dlist[in].name)
+ != 0) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s distribute-list %s in\n", addr,
+ filter->dlist[in].name);
+ }
- /* apply peer-group filter */
- if (peer_group_active(peer))
- {
- gfilter = &peer->group->conf->filter[afi][safi];
+ if (filter->dlist[out].name && !gfilter) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s distribute-list %s out\n",
+ addr, filter->dlist[out].name);
+ }
- if (gfilter->dlist[direct].name)
- {
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->dlist[direct].name);
- filter->dlist[direct].alist = gfilter->dlist[direct].alist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
- }
-
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = NULL;
- filter->dlist[direct].alist = NULL;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->dlist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->dlist[direct].name);
- filter->dlist[direct].name = NULL;
- filter->dlist[direct].alist = NULL;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- }
-
- return 0;
-}
+ /* prefix-list. */
+ if (filter->plist[in].name)
+ if (!gfilter || !gfilter->plist[in].name
+ || strcmp(filter->plist[in].name, gfilter->plist[in].name)
+ != 0) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s prefix-list %s in\n",
+ addr, filter->plist[in].name);
+ }
-/* Update distribute list. */
-static void
-peer_distribute_update (struct access_list *access)
-{
- afi_t afi;
- safi_t safi;
- int direct;
- struct listnode *mnode, *mnnode;
- struct listnode *node, *nnode;
- struct bgp *bgp;
- struct peer *peer;
- struct peer_group *group;
- struct bgp_filter *filter;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- {
- if (access->name)
- update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST, access->name,
- 0, 0);
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
+ if (filter->plist[out].name && !gfilter) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s prefix-list %s out\n", addr,
+ filter->plist[out].name);
+ }
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->dlist[direct].name)
- filter->dlist[direct].alist =
- access_list_lookup (afi, filter->dlist[direct].name);
- else
- filter->dlist[direct].alist = NULL;
- }
- }
- }
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &group->conf->filter[afi][safi];
-
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->dlist[direct].name)
- filter->dlist[direct].alist =
- access_list_lookup (afi, filter->dlist[direct].name);
- else
- filter->dlist[direct].alist = NULL;
- }
- }
+ /* route-map. */
+ if (filter->map[RMAP_IN].name)
+ if (!gfilter || !gfilter->map[RMAP_IN].name
+ || strcmp(filter->map[RMAP_IN].name,
+ gfilter->map[RMAP_IN].name)
+ != 0) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s route-map %s in\n",
+ addr, filter->map[RMAP_IN].name);
+ }
+
+ if (filter->map[RMAP_OUT].name)
+ if (!gfilter || !gfilter->map[RMAP_OUT].name
+ || strcmp(filter->map[RMAP_OUT].name,
+ gfilter->map[RMAP_OUT].name)
+ != 0) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s route-map %s out\n",
+ addr, filter->map[RMAP_OUT].name);
+ }
+
+ /* unsuppress-map */
+ if (filter->usmap.name && !gfilter) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s unsuppress-map %s\n", addr,
+ filter->usmap.name);
+ }
+
+ /* filter-list. */
+ if (filter->aslist[in].name)
+ if (!gfilter || !gfilter->aslist[in].name
+ || strcmp(filter->aslist[in].name, gfilter->aslist[in].name)
+ != 0) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s filter-list %s in\n",
+ addr, filter->aslist[in].name);
+ }
+
+ if (filter->aslist[out].name && !gfilter) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s filter-list %s out\n", addr,
+ filter->aslist[out].name);
}
-#if ENABLE_BGP_VNC
- vnc_prefix_list_update(bgp);
-#endif
- }
}
-/* Set prefix list to the peer. */
-int
-peer_prefix_list_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
- const char *name)
-{
- struct bgp_filter *filter;
- struct peer_group *group;
- struct listnode *node, *nnode;
+/* BGP peer configuration display function. */
+static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
+ struct peer *peer)
+{
+ struct peer *g_peer = NULL;
+ char buf[SU_ADDRSTRLEN];
+ char *addr;
+ int if_pg_printed = FALSE;
+ int if_ras_printed = FALSE;
+
+ /* Skip dynamic neighbors. */
+ if (peer_dynamic_neighbor(peer))
+ return;
+
+ if (peer->conf_if)
+ addr = peer->conf_if;
+ else
+ addr = peer->host;
+
+ /************************************
+ ****** Global to the neighbor ******
+ ************************************/
+ if (peer->conf_if) {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
+ vty_out(vty, " neighbor %s interface v6only", addr);
+ else
+ vty_out(vty, " neighbor %s interface", addr);
+
+ if (peer_group_active(peer)) {
+ vty_out(vty, " peer-group %s", peer->group->name);
+ if_pg_printed = TRUE;
+ } else if (peer->as_type == AS_SPECIFIED) {
+ vty_out(vty, " remote-as %u", peer->as);
+ if_ras_printed = TRUE;
+ } else if (peer->as_type == AS_INTERNAL) {
+ vty_out(vty, " remote-as internal");
+ if_ras_printed = TRUE;
+ } else if (peer->as_type == AS_EXTERNAL) {
+ vty_out(vty, " remote-as external");
+ if_ras_printed = TRUE;
+ }
- if (direct != FILTER_IN && direct != FILTER_OUT)
- return BGP_ERR_INVALID_VALUE;
+ vty_out(vty, "\n");
+ }
+
+ /* remote-as and peer-group */
+ /* peer is a member of a peer-group */
+ if (peer_group_active(peer)) {
+ g_peer = peer->group->conf;
+
+ if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed) {
+ if (peer->as_type == AS_SPECIFIED) {
+ vty_out(vty, " neighbor %s remote-as %u\n",
+ addr, peer->as);
+ } else if (peer->as_type == AS_INTERNAL) {
+ vty_out(vty,
+ " neighbor %s remote-as internal\n",
+ addr);
+ } else if (peer->as_type == AS_EXTERNAL) {
+ vty_out(vty,
+ " neighbor %s remote-as external\n",
+ addr);
+ }
+ }
- filter = &peer->filter[afi][safi];
+ /* For swpX peers we displayed the peer-group
+ * via 'neighbor swpX interface peer-group WORD' */
+ if (!if_pg_printed)
+ vty_out(vty, " neighbor %s peer-group %s\n", addr,
+ peer->group->name);
+ }
- if (filter->dlist[direct].name)
- return BGP_ERR_PEER_FILTER_CONFLICT;
+ /* peer is NOT a member of a peer-group */
+ else {
+ /* peer is a peer-group, declare the peer-group */
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ vty_out(vty, " neighbor %s peer-group\n", addr);
+ }
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->plist[direct].plist = prefix_list_lookup (afi, name);
+ if (!if_ras_printed) {
+ if (peer->as_type == AS_SPECIFIED) {
+ vty_out(vty, " neighbor %s remote-as %u\n",
+ addr, peer->as);
+ } else if (peer->as_type == AS_INTERNAL) {
+ vty_out(vty,
+ " neighbor %s remote-as internal\n",
+ addr);
+ } else if (peer->as_type == AS_EXTERNAL) {
+ vty_out(vty,
+ " neighbor %s remote-as external\n",
+ addr);
+ }
+ }
+ }
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
+ /* local-as */
+ if (peer->change_local_as) {
+ if (!peer_group_active(peer)
+ || peer->change_local_as != g_peer->change_local_as
+ || (CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND)
+ != CHECK_FLAG(g_peer->flags,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND))
+ || (CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)
+ != CHECK_FLAG(g_peer->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS))) {
+ vty_out(vty, " neighbor %s local-as %u%s%s\n", addr,
+ peer->change_local_as,
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_LOCAL_AS_NO_PREPEND)
+ ? " no-prepend"
+ : "",
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_LOCAL_AS_REPLACE_AS)
+ ? " replace-as"
+ : "");
+ }
+ }
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
+ /* description */
+ if (peer->desc) {
+ vty_out(vty, " neighbor %s description %s\n", addr, peer->desc);
+ }
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->plist[direct].plist = prefix_list_lookup (afi, name);
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- }
- return 0;
-}
+ /* shutdown */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags, PEER_FLAG_SHUTDOWN)
+ || peer->tx_shutdown_message) {
+ if (peer->tx_shutdown_message)
+ vty_out(vty,
+ " neighbor %s shutdown message %s\n",
+ addr, peer->tx_shutdown_message);
+ else
+ vty_out(vty, " neighbor %s shutdown\n", addr);
+ }
+ }
-int
-peer_prefix_list_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
-{
- struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
- struct listnode *node, *nnode;
+ /* bfd */
+ if (peer->bfd_info) {
+ if (!peer_group_active(peer) || !g_peer->bfd_info) {
+ bgp_bfd_peer_config_write(vty, peer, addr);
+ }
+ }
- if (direct != FILTER_IN && direct != FILTER_OUT)
- return BGP_ERR_INVALID_VALUE;
+ /* password */
+ if (peer->password) {
+ if (!peer_group_active(peer) || !g_peer->password
+ || strcmp(peer->password, g_peer->password) != 0) {
+ vty_out(vty, " neighbor %s password %s\n", addr,
+ peer->password);
+ }
+ }
- filter = &peer->filter[afi][safi];
+ /* neighbor solo */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL)) {
+ if (!peer_group_active(peer)) {
+ vty_out(vty, " neighbor %s solo\n", addr);
+ }
+ }
- /* apply peer-group filter */
- if (peer_group_active(peer))
- {
- gfilter = &peer->group->conf->filter[afi][safi];
+ /* BGP port */
+ if (peer->port != BGP_PORT_DEFAULT) {
+ vty_out(vty, " neighbor %s port %d\n", addr, peer->port);
+ }
- if (gfilter->plist[direct].name)
- {
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->plist[direct].name);
- filter->plist[direct].plist = gfilter->plist[direct].plist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
- }
-
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = NULL;
- filter->plist[direct].plist = NULL;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->plist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->plist[direct].name);
- filter->plist[direct].name = NULL;
- filter->plist[direct].plist = NULL;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- }
-
- return 0;
-}
+ /* Local interface name */
+ if (peer->ifname) {
+ vty_out(vty, " neighbor %s interface %s\n", addr, peer->ifname);
+ }
-/* Update prefix-list list. */
-static void
-peer_prefix_list_update (struct prefix_list *plist)
-{
- struct listnode *mnode, *mnnode;
- struct listnode *node, *nnode;
- struct bgp *bgp;
- struct peer *peer;
- struct peer_group *group;
- struct bgp_filter *filter;
- afi_t afi;
- safi_t safi;
- int direct;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- {
-
- /*
- * Update the prefix-list on update groups.
- */
- update_group_policy_update(bgp, BGP_POLICY_PREFIX_LIST,
- plist ? prefix_list_name(plist) : NULL, 0, 0);
-
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
+ /* passive */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_PASSIVE)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags, PEER_FLAG_PASSIVE)) {
+ vty_out(vty, " neighbor %s passive\n", addr);
+ }
+ }
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->plist[direct].name)
- filter->plist[direct].plist =
- prefix_list_lookup (afi, filter->plist[direct].name);
- else
- filter->plist[direct].plist = NULL;
- }
- }
- }
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &group->conf->filter[afi][safi];
-
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->plist[direct].name)
- filter->plist[direct].plist =
- prefix_list_lookup (afi, filter->plist[direct].name);
- else
- filter->plist[direct].plist = NULL;
- }
- }
- }
- }
-}
-
-int
-peer_aslist_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
- const char *name)
-{
- struct bgp_filter *filter;
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (direct != FILTER_IN && direct != FILTER_OUT)
- return BGP_ERR_INVALID_VALUE;
-
- filter = &peer->filter[afi][safi];
-
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->aslist[direct].aslist = as_list_lookup (name);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->aslist[direct].aslist = as_list_lookup (name);
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- }
- return 0;
-}
-
-int
-peer_aslist_unset (struct peer *peer,afi_t afi, safi_t safi, int direct)
-{
- struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- if (direct != FILTER_IN && direct != FILTER_OUT)
- return BGP_ERR_INVALID_VALUE;
-
- filter = &peer->filter[afi][safi];
-
- /* apply peer-group filter */
- if (peer_group_active(peer))
- {
- gfilter = &peer->group->conf->filter[afi][safi];
-
- if (gfilter->aslist[direct].name)
- {
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->aslist[direct].name);
- filter->aslist[direct].aslist = gfilter->aslist[direct].aslist;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
- }
-
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = NULL;
- filter->aslist[direct].aslist = NULL;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->aslist[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->aslist[direct].name);
- filter->aslist[direct].name = NULL;
- filter->aslist[direct].aslist = NULL;
- peer_on_policy_change(peer, afi, safi,
- (direct == FILTER_OUT) ? 1 : 0);
- }
-
- return 0;
-}
-
-static void
-peer_aslist_update (const char *aslist_name)
-{
- afi_t afi;
- safi_t safi;
- int direct;
- struct listnode *mnode, *mnnode;
- struct listnode *node, *nnode;
- struct bgp *bgp;
- struct peer *peer;
- struct peer_group *group;
- struct bgp_filter *filter;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- {
- update_group_policy_update(bgp, BGP_POLICY_FILTER_LIST, aslist_name,
- 0, 0);
-
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &peer->filter[afi][safi];
+ /* ebgp-multihop */
+ if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1
+ && !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL)) {
+ if (!peer_group_active(peer) || g_peer->ttl != peer->ttl) {
+ vty_out(vty, " neighbor %s ebgp-multihop %d\n", addr,
+ peer->ttl);
+ }
+ }
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->aslist[direct].name)
- filter->aslist[direct].aslist =
- as_list_lookup (filter->aslist[direct].name);
- else
- filter->aslist[direct].aslist = NULL;
- }
- }
- }
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- {
- for (afi = AFI_IP; afi < AFI_MAX; afi++)
- for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++)
- {
- filter = &group->conf->filter[afi][safi];
+ /* ttl-security hops */
+ if (peer->gtsm_hops != 0) {
+ if (!peer_group_active(peer)
+ || g_peer->gtsm_hops != peer->gtsm_hops) {
+ vty_out(vty, " neighbor %s ttl-security hops %d\n",
+ addr, peer->gtsm_hops);
+ }
+ }
- for (direct = FILTER_IN; direct < FILTER_MAX; direct++)
- {
- if (filter->aslist[direct].name)
- filter->aslist[direct].aslist =
- as_list_lookup (filter->aslist[direct].name);
- else
- filter->aslist[direct].aslist = NULL;
- }
- }
+ /* disable-connected-check */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags,
+ PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
+ vty_out(vty, " neighbor %s disable-connected-check\n",
+ addr);
+ }
}
- }
-}
-static void
-peer_aslist_add (char *aslist_name)
-{
- peer_aslist_update (aslist_name);
- route_map_notify_dependencies((char *)aslist_name, RMAP_EVENT_ASLIST_ADDED);
-}
+ /* update-source */
+ if (peer->update_if) {
+ if (!peer_group_active(peer) || !g_peer->update_if
+ || strcmp(g_peer->update_if, peer->update_if) != 0) {
+ vty_out(vty, " neighbor %s update-source %s\n", addr,
+ peer->update_if);
+ }
+ }
+ if (peer->update_source) {
+ if (!peer_group_active(peer) || !g_peer->update_source
+ || sockunion_cmp(g_peer->update_source, peer->update_source)
+ != 0) {
+ vty_out(vty, " neighbor %s update-source %s\n", addr,
+ sockunion2str(peer->update_source, buf,
+ SU_ADDRSTRLEN));
+ }
+ }
-static void
-peer_aslist_del (const char *aslist_name)
-{
- peer_aslist_update (aslist_name);
- route_map_notify_dependencies(aslist_name, RMAP_EVENT_ASLIST_DELETED);
-}
+ /* advertisement-interval */
+ if (CHECK_FLAG(peer->config, PEER_CONFIG_ROUTEADV)
+ && ((!peer_group_active(peer)
+ && peer->v_routeadv != BGP_DEFAULT_EBGP_ROUTEADV)
+ || (peer_group_active(peer)
+ && peer->v_routeadv != g_peer->v_routeadv))) {
+ vty_out(vty, " neighbor %s advertisement-interval %u\n", addr,
+ peer->v_routeadv);
+ }
+ /* timers */
+ if (CHECK_FLAG(peer->config, PEER_CONFIG_TIMER)
+ && ((!peer_group_active(peer)
+ && (peer->keepalive != BGP_DEFAULT_KEEPALIVE
+ || peer->holdtime != BGP_DEFAULT_HOLDTIME))
+ || (peer_group_active(peer)
+ && (peer->keepalive != g_peer->keepalive
+ || peer->holdtime != g_peer->holdtime)))) {
+ vty_out(vty, " neighbor %s timers %u %u\n", addr,
+ peer->keepalive, peer->holdtime);
+ }
-int
-peer_route_map_set (struct peer *peer, afi_t afi, safi_t safi, int direct,
- const char *name)
-{
- struct bgp_filter *filter;
- struct peer_group *group;
- struct listnode *node, *nnode;
+ if (CHECK_FLAG(peer->config, PEER_CONFIG_CONNECT)
+ && ((!peer_group_active(peer)
+ && peer->connect != BGP_DEFAULT_CONNECT_RETRY)
+ || (peer_group_active(peer)
+ && peer->connect != g_peer->connect)))
- if (direct != RMAP_IN && direct != RMAP_OUT)
- return BGP_ERR_INVALID_VALUE;
+ {
+ vty_out(vty, " neighbor %s timers connect %u\n", addr,
+ peer->connect);
+ }
- filter = &peer->filter[afi][safi];
+ /* capability dynamic */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags,
+ PEER_FLAG_DYNAMIC_CAPABILITY)) {
+ vty_out(vty, " neighbor %s capability dynamic\n", addr);
+ }
+ }
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
+ /* capability extended-nexthop */
+ if (peer->ifp && !CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+ vty_out(vty,
+ " no neighbor %s capability extended-nexthop\n",
+ addr);
+ }
+ }
- filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->map[direct].map = route_map_lookup_by_name (name);
+ if (!peer->ifp && CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags, PEER_FLAG_CAPABILITY_ENHE)) {
+ vty_out(vty,
+ " neighbor %s capability extended-nexthop\n",
+ addr);
+ }
+ }
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == RMAP_OUT) ? 1 : 0);
- return 0;
- }
+ /* dont-capability-negotiation */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags, PEER_FLAG_DONT_CAPABILITY)) {
+ vty_out(vty, " neighbor %s dont-capability-negotiate\n",
+ addr);
+ }
+ }
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
+ /* override-capability */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags,
+ PEER_FLAG_OVERRIDE_CAPABILITY)) {
+ vty_out(vty, " neighbor %s override-capability\n",
+ addr);
+ }
+ }
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->map[direct].map = route_map_lookup_by_name (name);
- peer_on_policy_change(peer, afi, safi,
- (direct == RMAP_OUT) ? 1 : 0);
- }
- return 0;
+ /* strict-capability-match */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
+ if (!peer_group_active(peer)
+ || !CHECK_FLAG(g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH)) {
+ vty_out(vty, " neighbor %s strict-capability-match\n",
+ addr);
+ }
+ }
}
-/* Unset route-map from the peer. */
-int
-peer_route_map_unset (struct peer *peer, afi_t afi, safi_t safi, int direct)
-{
- struct bgp_filter *filter;
- struct bgp_filter *gfilter;
- struct peer_group *group;
- struct listnode *node, *nnode;
+/* BGP peer configuration display function. */
+static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
+ struct peer *peer, afi_t afi, safi_t safi,
+ int *write)
+{
+ struct peer *g_peer = NULL;
+ char *addr;
+
+ /* Skip dynamic neighbors. */
+ if (peer_dynamic_neighbor(peer))
+ return;
+
+ if (peer->conf_if)
+ addr = peer->conf_if;
+ else
+ addr = peer->host;
+
+ /************************************
+ ****** Per AF to the neighbor ******
+ ************************************/
+ if (peer_group_active(peer)) {
+ g_peer = peer->group->conf;
+
+ /* If the peer-group is active but peer is not, print a 'no
+ * activate' */
+ if (g_peer->afc[afi][safi] && !peer->afc[afi][safi]) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " no neighbor %s activate\n", addr);
+ }
- if (direct != RMAP_IN && direct != RMAP_OUT)
- return BGP_ERR_INVALID_VALUE;
+ /* If the peer-group is not active but peer is, print an
+ 'activate' */
+ else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi]) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s activate\n", addr);
+ }
+ } else {
+ if (peer->afc[afi][safi]) {
+ if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
+ if (bgp_flag_check(bgp,
+ BGP_FLAG_NO_DEFAULT_IPV4)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s activate\n",
+ addr);
+ }
+ } else
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s activate\n",
+ addr);
+ } else {
+ if ((afi == AFI_IP) && (safi == SAFI_UNICAST)) {
+ if (!bgp_flag_check(bgp,
+ BGP_FLAG_NO_DEFAULT_IPV4)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " no neighbor %s activate\n",
+ addr);
+ }
+ }
+ }
+ }
- filter = &peer->filter[afi][safi];
+ /* addpath TX knobs */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ADDPATH_TX_ALL_PATHS)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s addpath-tx-all-paths\n",
+ addr);
+ }
- /* apply peer-group filter */
- if (peer_group_active(peer))
- {
- gfilter = &peer->group->conf->filter[afi][safi];
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s addpath-tx-bestpath-per-AS\n",
+ addr);
+ }
- if (gfilter->map[direct].name)
- {
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, gfilter->map[direct].name);
- filter->map[direct].map = gfilter->map[direct].map;
- peer_on_policy_change(peer, afi, safi,
- (direct == RMAP_OUT) ? 1 : 0);
- return 0;
- }
- }
-
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- filter->map[direct].name = NULL;
- filter->map[direct].map = NULL;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi,
- (direct == RMAP_OUT) ? 1 : 0);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->map[direct].name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- filter->map[direct].name = NULL;
- filter->map[direct].map = NULL;
- peer_on_policy_change(peer, afi, safi,
- (direct == RMAP_OUT) ? 1 : 0);
- }
- return 0;
-}
+ /* ORF capability. */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM)
+ || peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ORF_PREFIX_RM)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s capability orf prefix-list",
+ addr);
+
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ORF_PREFIX_SM)
+ && peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ORF_PREFIX_RM))
+ vty_out(vty, " both");
+ else if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ORF_PREFIX_SM))
+ vty_out(vty, " send");
+ else
+ vty_out(vty, " receive");
+ vty_out(vty, "\n");
+ }
-/* Set unsuppress-map to the peer. */
-int
-peer_unsuppress_map_set (struct peer *peer, afi_t afi, safi_t safi,
- const char *name)
-{
- struct bgp_filter *filter;
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- filter = &peer->filter[afi][safi];
-
- if (filter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
-
- filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->usmap.map = route_map_lookup_by_name (name);
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi, 1);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
- filter->usmap.map = route_map_lookup_by_name (name);
- peer_on_policy_change(peer, afi, safi, 1);
- }
- return 0;
-}
+ /* Route reflector client. */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s route-reflector-client\n",
+ addr);
+ }
-/* Unset route-map from the peer. */
-int
-peer_unsuppress_map_unset (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct bgp_filter *filter;
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- filter = &peer->filter[afi][safi];
-
- if (filter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = NULL;
- filter->usmap.map = NULL;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer_on_policy_change(peer, afi, safi, 1);
- return 0;
- }
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- filter = &peer->filter[afi][safi];
-
- if (filter->usmap.name)
- XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- filter->usmap.name = NULL;
- filter->usmap.map = NULL;
- peer_on_policy_change(peer, afi, safi, 1);
- }
- return 0;
-}
-
-int
-peer_maximum_prefix_set (struct peer *peer, afi_t afi, safi_t safi,
- u_int32_t max, u_char threshold,
- int warning, u_int16_t restart)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- peer->pmax[afi][safi] = max;
- peer->pmax_threshold[afi][safi] = threshold;
- peer->pmax_restart[afi][safi] = restart;
- if (warning)
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
-
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- peer->pmax[afi][safi] = max;
- peer->pmax_threshold[afi][safi] = threshold;
- peer->pmax_restart[afi][safi] = restart;
- if (warning)
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
-
- if ((peer->status == Established) && (peer->afc[afi][safi]))
- bgp_maximum_prefix_overflow (peer, afi, safi, 1);
- }
- }
- else
- {
- if ((peer->status == Established) && (peer->afc[afi][safi]))
- bgp_maximum_prefix_overflow (peer, afi, safi, 1);
- }
-
- return 0;
-}
-
-int
-peer_maximum_prefix_unset (struct peer *peer, afi_t afi, safi_t safi)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
-
- /* apply peer-group config */
- if (peer_group_active(peer))
- {
- if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX))
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
-
- if (CHECK_FLAG (peer->group->conf->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING))
- SET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- else
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
-
- peer->pmax[afi][safi] = peer->group->conf->pmax[afi][safi];
- peer->pmax_threshold[afi][safi] = peer->group->conf->pmax_threshold[afi][safi];
- peer->pmax_restart[afi][safi] = peer->group->conf->pmax_restart[afi][safi];
- return 0;
- }
-
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- peer->pmax[afi][safi] = 0;
- peer->pmax_threshold[afi][safi] = 0;
- peer->pmax_restart[afi][safi] = 0;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- return 0;
-
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- UNSET_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING);
- peer->pmax[afi][safi] = 0;
- peer->pmax_threshold[afi][safi] = 0;
- peer->pmax_restart[afi][safi] = 0;
- }
- return 0;
-}
-
-int is_ebgp_multihop_configured (struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
- struct peer *peer1;
-
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- group = peer->group;
- if ((peer_sort(peer) != BGP_PEER_IBGP) &&
- (group->conf->ttl != 1))
- return 1;
-
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
- {
- if ((peer_sort (peer1) != BGP_PEER_IBGP) &&
- (peer1->ttl != 1))
- return 1;
+ /* next-hop-self force */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_FORCE_NEXTHOP_SELF)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s next-hop-self force\n", addr);
}
- }
- else
- {
- if ((peer_sort(peer) != BGP_PEER_IBGP) &&
- (peer->ttl != 1))
- return 1;
- }
- return 0;
-}
-/* Set # of hops between us and BGP peer. */
-int
-peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
- int ret;
+ /* next-hop-self */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_SELF)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s next-hop-self\n", addr);
+ }
- zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host);
+ /* remove-private-AS */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s remove-private-AS all replace-AS\n",
+ addr);
+ }
- /* We cannot configure ttl-security hops when ebgp-multihop is already
- set. For non peer-groups, the check is simple. For peer-groups, it's
- slightly messy, because we need to check both the peer-group structure
- and all peer-group members for any trace of ebgp-multihop configuration
- before actually applying the ttl-security rules. Cisco really made a
- mess of this configuration parameter, and OpenBGPD got it right.
- */
+ else if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s remove-private-AS replace-AS\n", addr);
+ }
- if ((peer->gtsm_hops == 0) && (peer->sort != BGP_PEER_IBGP))
- {
- if (is_ebgp_multihop_configured (peer))
- return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+ else if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_REMOVE_PRIVATE_AS_ALL)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s remove-private-AS all\n",
+ addr);
+ }
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer->gtsm_hops = gtsm_hops;
+ else if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_REMOVE_PRIVATE_AS)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s remove-private-AS\n", addr);
+ }
- /* Calling ebgp multihop also resets the session.
- * On restart, NHT will get setup correctly as will the
- * min & max ttls on the socket. The return value is
- * irrelevant.
- */
- ret = peer_ebgp_multihop_set (peer, MAXTTL);
+ /* as-override */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_AS_OVERRIDE)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s as-override\n", addr);
+ }
- if (ret != 0)
- return ret;
+ /* send-community print. */
+ if (bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY)
+ && peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY)
+ && peergroup_af_flag_check(
+ peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s send-community all\n",
+ addr);
+ } else if (peergroup_af_flag_check(
+ peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s send-community large\n", addr);
+ } else if (peergroup_af_flag_check(
+ peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s send-community extended\n",
+ addr);
+ } else if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s send-community\n",
+ addr);
+ }
+ } else {
+ if (!peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY)
+ && (!g_peer || peer_af_flag_check(g_peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY))
+ && !peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY)
+ && (!g_peer
+ || peer_af_flag_check(g_peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY))
+ && !peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY)
+ && (!g_peer || peer_af_flag_check(
+ g_peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY))) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " no neighbor %s send-community all\n", addr);
+ } else {
+ if (!peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY)
+ && (!g_peer
+ || peer_af_flag_check(
+ g_peer, afi, safi,
+ PEER_FLAG_SEND_LARGE_COMMUNITY))) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " no neighbor %s send-community large\n",
+ addr);
+ }
+
+ if (!peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY)
+ && (!g_peer
+ || peer_af_flag_check(
+ g_peer, afi, safi,
+ PEER_FLAG_SEND_EXT_COMMUNITY))) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " no neighbor %s send-community extended\n",
+ addr);
+ }
+
+ if (!peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY)
+ && (!g_peer || peer_af_flag_check(
+ g_peer, afi, safi,
+ PEER_FLAG_SEND_COMMUNITY))) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " no neighbor %s send-community\n",
+ addr);
+ }
+ }
}
- else
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- peer->gtsm_hops = group->conf->gtsm_hops;
-
- /* Calling ebgp multihop also resets the session.
- * On restart, NHT will get setup correctly as will the
- * min & max ttls on the socket. The return value is
- * irrelevant.
- */
- peer_ebgp_multihop_set (peer, MAXTTL);
- }
- }
- }
- else
- {
- /* Post the first gtsm setup or if its ibgp, maxttl setting isn't
- * necessary, just set the minttl.
- */
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- peer->gtsm_hops = gtsm_hops;
- if (peer->fd >= 0)
- sockopt_minttl (peer->su.sa.sa_family, peer->fd,
- MAXTTL + 1 - gtsm_hops);
- if ((peer->status < Established) && peer->doppelganger &&
- (peer->doppelganger->fd >= 0))
- sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
- MAXTTL + 1 - gtsm_hops);
+ /* Default information */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_DEFAULT_ORIGINATE)
+ || (g_peer
+ && ((peer->default_rmap[afi][safi].name
+ && !g_peer->default_rmap[afi][safi].name)
+ || (!peer->default_rmap[afi][safi].name
+ && g_peer->default_rmap[afi][safi].name)
+ || (peer->default_rmap[afi][safi].name
+ && strcmp(peer->default_rmap[afi][safi].name,
+ g_peer->default_rmap[afi][safi].name))))) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s default-originate", addr);
+ if (peer->default_rmap[afi][safi].name)
+ vty_out(vty, " route-map %s",
+ peer->default_rmap[afi][safi].name);
+ vty_out(vty, "\n");
}
- else
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- peer->gtsm_hops = group->conf->gtsm_hops;
-
- /* Change setting of existing peer
- * established then change value (may break connectivity)
- * not established yet (teardown session and restart)
- * no session then do nothing (will get handled by next connection)
- */
- if (peer->fd >= 0 && peer->gtsm_hops != 0)
- sockopt_minttl (peer->su.sa.sa_family, peer->fd,
- MAXTTL + 1 - peer->gtsm_hops);
- if ((peer->status < Established) && peer->doppelganger &&
- (peer->doppelganger->fd >= 0))
- sockopt_minttl (peer->su.sa.sa_family, peer->doppelganger->fd,
- MAXTTL + 1 - gtsm_hops);
-
- }
- }
- }
-
- return 0;
-}
-
-int
-peer_ttl_security_hops_unset (struct peer *peer)
-{
- struct peer_group *group;
- struct listnode *node, *nnode;
- int ret = 0;
-
- zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host);
-
- /* if a peer-group member, then reset to peer-group default rather than 0 */
- if (peer_group_active (peer))
- peer->gtsm_hops = peer->group->conf->gtsm_hops;
- else
- peer->gtsm_hops = 0;
-
- if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- /* Invoking ebgp_multihop_set will set the TTL back to the original
- * value as well as restting the NHT and such. The session is reset.
- */
- if (peer->sort == BGP_PEER_EBGP)
- ret = peer_ebgp_multihop_unset (peer);
- else
- {
- if (peer->fd >= 0)
- sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
-
- if ((peer->status < Established) && peer->doppelganger &&
- (peer->doppelganger->fd >= 0))
- sockopt_minttl (peer->su.sa.sa_family,
- peer->doppelganger->fd, 0);
- }
- }
- else
- {
- group = peer->group;
- for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
- {
- peer->gtsm_hops = 0;
- if (peer->sort == BGP_PEER_EBGP)
- ret = peer_ebgp_multihop_unset (peer);
- else
- {
- if (peer->fd >= 0)
- sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
- if ((peer->status < Established) && peer->doppelganger &&
- (peer->doppelganger->fd >= 0))
- sockopt_minttl (peer->su.sa.sa_family,
- peer->doppelganger->fd, 0);
- }
+ /* Soft reconfiguration inbound. */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOFT_RECONFIG)) {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s soft-reconfiguration inbound\n", addr);
}
- }
- return ret;
-}
+ /* maximum-prefix. */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
+ if (!peer_group_active(peer)
+ || g_peer->pmax[afi][safi] != peer->pmax[afi][safi]
+ || g_peer->pmax_threshold[afi][safi]
+ != peer->pmax_threshold[afi][safi]
+ || CHECK_FLAG(g_peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING)
+ != CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s maximum-prefix %lu",
+ addr, peer->pmax[afi][safi]);
+ if (peer->pmax_threshold[afi][safi]
+ != MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
+ vty_out(vty, " %u",
+ peer->pmax_threshold[afi][safi]);
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING))
+ vty_out(vty, " warning-only");
+ if (peer->pmax_restart[afi][safi])
+ vty_out(vty, " restart %u",
+ peer->pmax_restart[afi][safi]);
+ vty_out(vty, "\n");
+ }
-/*
- * If peer clear is invoked in a loop for all peers on the BGP instance,
- * it may end up freeing the doppelganger, and if this was the next node
- * to the current node, we would end up accessing the freed next node.
- * Pass along additional parameter which can be updated if next node
- * is freed; only required when walking the peer list on BGP instance.
- */
-int
-peer_clear (struct peer *peer, struct listnode **nnode)
-{
- if (! CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
- {
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
- {
- UNSET_FLAG (peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart)
- {
- BGP_TIMER_OFF (peer->t_pmax_restart);
- if (bgp_debug_neighbor_events(peer))
- zlog_debug ("%s Maximum-prefix restart timer canceled",
- peer->host);
- }
- BGP_EVENT_ADD (peer, BGP_Start);
- return 0;
- }
-
- peer->v_start = BGP_INIT_START_TIMER;
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_RESET);
- else
- bgp_session_reset_safe(peer, nnode);
- }
- return 0;
-}
-
-int
-peer_clear_soft (struct peer *peer, afi_t afi, safi_t safi,
- enum bgp_clear_type stype)
-{
- struct peer_af *paf;
-
- if (peer->status != Established)
- return 0;
-
- if (! peer->afc[afi][safi])
- return BGP_ERR_AF_UNCONFIGURED;
-
- peer->rtt = sockopt_tcp_rtt (peer->fd);
-
- if (stype == BGP_CLEAR_SOFT_OUT || stype == BGP_CLEAR_SOFT_BOTH)
- {
- /* Clear the "neighbor x.x.x.x default-originate" flag */
- paf = peer_af_find (peer, afi, safi);
- if (paf && paf->subgroup &&
- CHECK_FLAG (paf->subgroup->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE))
- UNSET_FLAG (paf->subgroup->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE);
-
- bgp_announce_route (peer, afi, safi);
- }
-
- if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX)
- {
- if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_SM_ADV)
- && (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV)
- || CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_OLD_RCV)))
- {
- struct bgp_filter *filter = &peer->filter[afi][safi];
- u_char prefix_type;
-
- if (CHECK_FLAG (peer->af_cap[afi][safi], PEER_CAP_ORF_PREFIX_RM_RCV))
- prefix_type = ORF_TYPE_PREFIX;
- else
- prefix_type = ORF_TYPE_PREFIX_OLD;
-
- if (filter->plist[FILTER_IN].plist)
- {
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND))
- bgp_route_refresh_send (peer, afi, safi,
- prefix_type, REFRESH_DEFER, 1);
- bgp_route_refresh_send (peer, afi, safi, prefix_type,
- REFRESH_IMMEDIATE, 0);
- }
- else
- {
- if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND))
- bgp_route_refresh_send (peer, afi, safi,
- prefix_type, REFRESH_IMMEDIATE, 1);
- else
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- }
- return 0;
- }
- }
-
- if (stype == BGP_CLEAR_SOFT_IN || stype == BGP_CLEAR_SOFT_BOTH
- || stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX)
- {
- /* If neighbor has soft reconfiguration inbound flag.
- Use Adj-RIB-In database. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
- bgp_soft_reconfig_in (peer, afi, safi);
- else
- {
- /* If neighbor has route refresh capability, send route refresh
- message to the peer. */
- if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV)
- || CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV))
- bgp_route_refresh_send (peer, afi, safi, 0, 0, 0);
- else
- return BGP_ERR_SOFT_RECONFIG_UNCONFIGURED;
+ /* Route server client. */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_RSERVER_CLIENT)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s route-server-client\n", addr);
}
- }
- return 0;
-}
-/* Display peer uptime.*/
-char *
-peer_uptime (time_t uptime2, char *buf, size_t len, u_char use_json, json_object *json)
-{
- time_t uptime1, epoch_tbuf;
- struct tm *tm;
-
- /* Check buffer length. */
- if (len < BGP_UPTIME_LEN)
- {
- if (!use_json)
- {
- zlog_warn ("peer_uptime (): buffer shortage %lu", (u_long)len);
- /* XXX: should return status instead of buf... */
- snprintf (buf, len, "<error> ");
- }
- return buf;
- }
-
- /* If there is no connection has been done before print `never'. */
- if (uptime2 == 0)
- {
- if (use_json)
- {
- json_object_string_add(json, "peerUptime", "never");
- json_object_int_add(json, "peerUptimeMsec", 0);
- }
- else
- snprintf (buf, len, "never");
- return buf;
- }
-
- /* Get current time. */
- uptime1 = bgp_clock ();
- uptime1 -= uptime2;
- tm = gmtime (&uptime1);
-
- /* Making formatted timer strings. */
-#define ONE_DAY_SECOND 60*60*24
-#define ONE_WEEK_SECOND ONE_DAY_SECOND*7
-#define ONE_YEAR_SECOND ONE_DAY_SECOND*365
+ /* Nexthop-local unchanged. */
+ if (peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s nexthop-local unchanged\n",
+ addr);
+ }
- if (uptime1 < ONE_DAY_SECOND)
- snprintf (buf, len, "%02d:%02d:%02d",
- tm->tm_hour, tm->tm_min, tm->tm_sec);
- else if (uptime1 < ONE_WEEK_SECOND)
- snprintf (buf, len, "%dd%02dh%02dm",
- tm->tm_yday, tm->tm_hour, tm->tm_min);
- else if (uptime1 < ONE_YEAR_SECOND)
- snprintf (buf, len, "%02dw%dd%02dh",
- tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour);
- else
- snprintf (buf, len, "%02dy%02dw%dd",
- tm->tm_year - 70, tm->tm_yday/7,
- tm->tm_yday - ((tm->tm_yday/7) * 7));
-
- if (use_json)
- {
- epoch_tbuf = time(NULL) - uptime1;
- json_object_string_add(json, "peerUptime", buf);
- json_object_long_add(json, "peerUptimeMsec", uptime1 * 1000);
- json_object_int_add(json, "peerUptimeEstablishedEpoch", epoch_tbuf);
- }
-
- return buf;
-}
-
-static void
-afi_header_vty_out (struct vty *vty, afi_t afi, safi_t safi,
- int *write, const char *format, ...)
-{
- va_list args;
- int len = 0;
- char buf[1024];
-
- bgp_config_write_family_header (vty, afi, safi, write);
-
- if (vty_shell (vty))
- {
- va_start (args, format);
- vprintf (format, args);
- va_end (args);
- }
- else
- {
- va_start (args, format);
- len = vsnprintf (buf, sizeof(buf), format, args);
- va_end (args);
-
- buffer_put (vty->obuf, (u_char *) buf, len);
- }
-}
-
-static void
-bgp_config_write_filter (struct vty *vty, struct peer *peer,
- afi_t afi, safi_t safi, int *write)
-{
- struct bgp_filter *filter;
- struct bgp_filter *gfilter = NULL;
- char *addr;
- int in = FILTER_IN;
- int out = FILTER_OUT;
-
- addr = peer->host;
- filter = &peer->filter[afi][safi];
-
- if (peer_group_active(peer))
- gfilter = &peer->group->conf->filter[afi][safi];
-
- /* distribute-list. */
- if (filter->dlist[in].name)
- if (! gfilter || ! gfilter->dlist[in].name
- || strcmp (filter->dlist[in].name, gfilter->dlist[in].name) != 0)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s distribute-list %s in%s",
- addr, filter->dlist[in].name, VTY_NEWLINE);
- }
-
- if (filter->dlist[out].name && ! gfilter)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s distribute-list %s out%s",
- addr, filter->dlist[out].name, VTY_NEWLINE);
- }
-
- /* prefix-list. */
- if (filter->plist[in].name)
- if (! gfilter || ! gfilter->plist[in].name
- || strcmp (filter->plist[in].name, gfilter->plist[in].name) != 0)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s prefix-list %s in%s",
- addr, filter->plist[in].name, VTY_NEWLINE);
- }
-
- if (filter->plist[out].name && ! gfilter)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s prefix-list %s out%s",
- addr, filter->plist[out].name, VTY_NEWLINE);
- }
-
- /* route-map. */
- if (filter->map[RMAP_IN].name)
- if (! gfilter || ! gfilter->map[RMAP_IN].name
- || strcmp (filter->map[RMAP_IN].name, gfilter->map[RMAP_IN].name) != 0)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s route-map %s in%s",
- addr, filter->map[RMAP_IN].name, VTY_NEWLINE);
- }
-
- if (filter->map[RMAP_OUT].name)
- if (! gfilter || ! gfilter->map[RMAP_OUT].name
- || strcmp (filter->map[RMAP_OUT].name, gfilter->map[RMAP_OUT].name) != 0)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s route-map %s out%s",
- addr, filter->map[RMAP_OUT].name, VTY_NEWLINE);
- }
-
- /* unsuppress-map */
- if (filter->usmap.name && ! gfilter)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s unsuppress-map %s%s",
- addr, filter->usmap.name, VTY_NEWLINE);
- }
-
- /* filter-list. */
- if (filter->aslist[in].name)
- if (! gfilter || ! gfilter->aslist[in].name
- || strcmp (filter->aslist[in].name, gfilter->aslist[in].name) != 0)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s filter-list %s in%s",
- addr, filter->aslist[in].name, VTY_NEWLINE);
- }
-
- if (filter->aslist[out].name && ! gfilter)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s filter-list %s out%s",
- addr, filter->aslist[out].name, VTY_NEWLINE);
- }
-}
+ /* allowas-in <1-10> */
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ALLOWAS_IN)) {
+ if (!peer_group_active(peer)
+ || !peer_af_flag_check(g_peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN)
+ || peer->allowas_in[afi][safi]
+ != g_peer->allowas_in[afi][safi]) {
+ if (peer->allowas_in[afi][safi] == 3) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s allowas-in\n",
+ addr);
+ } else {
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s allowas-in %d\n", addr,
+ peer->allowas_in[afi][safi]);
+ }
+ }
+ }
-/* BGP peer configuration display function. */
-static void
-bgp_config_write_peer_global (struct vty *vty, struct bgp *bgp,
- struct peer *peer)
-{
- struct peer *g_peer = NULL;
- char buf[SU_ADDRSTRLEN];
- char *addr;
- int if_pg_printed = FALSE;
- int if_ras_printed = FALSE;
-
- /* Skip dynamic neighbors. */
- if (peer_dynamic_neighbor (peer))
- return;
-
- if (peer->conf_if)
- addr = peer->conf_if;
- else
- addr = peer->host;
-
- /************************************
- ****** Global to the neighbor ******
- ************************************/
- if (peer->conf_if)
- {
- if (CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY))
- vty_out (vty, " neighbor %s interface v6only", addr);
- else
- vty_out (vty, " neighbor %s interface", addr);
-
- if (peer_group_active (peer))
- {
- vty_out (vty, " peer-group %s", peer->group->name);
- if_pg_printed = TRUE;
- }
- else if (peer->as_type == AS_SPECIFIED)
- {
- vty_out (vty, " remote-as %u", peer->as);
- if_ras_printed = TRUE;
- }
- else if (peer->as_type == AS_INTERNAL)
- {
- vty_out (vty, " remote-as internal");
- if_ras_printed = TRUE;
- }
- else if (peer->as_type == AS_EXTERNAL)
- {
- vty_out (vty, " remote-as external");
- if_ras_printed = TRUE;
- }
-
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* remote-as and peer-group */
- /* peer is a member of a peer-group */
- if (peer_group_active (peer))
- {
- g_peer = peer->group->conf;
-
- if (g_peer->as_type == AS_UNSPECIFIED && !if_ras_printed)
- {
- if (peer->as_type == AS_SPECIFIED)
- {
- vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
- VTY_NEWLINE);
- }
- else if (peer->as_type == AS_INTERNAL)
- {
- vty_out (vty, " neighbor %s remote-as internal%s", addr, VTY_NEWLINE);
- }
- else if (peer->as_type == AS_EXTERNAL)
- {
- vty_out (vty, " neighbor %s remote-as external%s", addr, VTY_NEWLINE);
- }
- }
-
- /* For swpX peers we displayed the peer-group
- * via 'neighbor swpX interface peer-group WORD' */
- if (!if_pg_printed)
- vty_out (vty, " neighbor %s peer-group %s%s", addr,
- peer->group->name, VTY_NEWLINE);
- }
-
- /* peer is NOT a member of a peer-group */
- else
- {
- /* peer is a peer-group, declare the peer-group */
- if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
- {
- vty_out (vty, " neighbor %s peer-group%s", addr,
- VTY_NEWLINE);
- }
-
- if (!if_ras_printed)
- {
- if (peer->as_type == AS_SPECIFIED)
- {
- vty_out (vty, " neighbor %s remote-as %u%s", addr, peer->as,
- VTY_NEWLINE);
- }
- else if (peer->as_type == AS_INTERNAL)
- {
- vty_out (vty, " neighbor %s remote-as internal%s", addr, VTY_NEWLINE);
- }
- else if (peer->as_type == AS_EXTERNAL)
- {
- vty_out (vty, " neighbor %s remote-as external%s", addr, VTY_NEWLINE);
- }
- }
- }
-
- /* local-as */
- if (peer->change_local_as)
- {
- if (! peer_group_active (peer)
- || peer->change_local_as != g_peer->change_local_as
- || (CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) !=
- CHECK_FLAG (g_peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
- || (CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) !=
- CHECK_FLAG (g_peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS)))
- {
- vty_out (vty, " neighbor %s local-as %u%s%s%s", addr,
- peer->change_local_as,
- CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND) ?
- " no-prepend" : "",
- CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ?
- " replace-as" : "", VTY_NEWLINE);
- }
- }
-
- /* description */
- if (peer->desc)
- {
- vty_out (vty, " neighbor %s description %s%s", addr, peer->desc,
- VTY_NEWLINE);
- }
-
- /* shutdown */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_SHUTDOWN))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_SHUTDOWN) ||
- peer->tx_shutdown_message)
- {
- if (peer->tx_shutdown_message)
- vty_out (vty, " neighbor %s shutdown message %s%s", addr,
- peer->tx_shutdown_message, VTY_NEWLINE);
- else
- vty_out (vty, " neighbor %s shutdown%s", addr, VTY_NEWLINE);
- }
- }
-
- /* bfd */
- if (peer->bfd_info)
- {
- if (! peer_group_active (peer) || ! g_peer->bfd_info)
- {
- bgp_bfd_peer_config_write(vty, peer, addr);
- }
- }
-
- /* password */
- if (peer->password)
- {
- if (!peer_group_active (peer)
- || ! g_peer->password
- || strcmp (peer->password, g_peer->password) != 0)
- {
- vty_out (vty, " neighbor %s password %s%s", addr, peer->password,
- VTY_NEWLINE);
- }
- }
-
- /* neighbor solo */
- if (CHECK_FLAG(peer->flags, PEER_FLAG_LONESOUL))
- {
- if (!peer_group_active (peer))
- {
- vty_out (vty, " neighbor %s solo%s", addr, VTY_NEWLINE);
- }
- }
-
- /* BGP port */
- if (peer->port != BGP_PORT_DEFAULT)
- {
- vty_out (vty, " neighbor %s port %d%s", addr, peer->port,
- VTY_NEWLINE);
- }
-
- /* Local interface name */
- if (peer->ifname)
- {
- vty_out (vty, " neighbor %s interface %s%s", addr, peer->ifname,
- VTY_NEWLINE);
- }
-
- /* passive */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_PASSIVE))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_PASSIVE))
- {
- vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE);
- }
- }
-
- /* ebgp-multihop */
- if (peer->sort != BGP_PEER_IBGP && peer->ttl != 1 &&
- !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL))
- {
- if (! peer_group_active (peer) || g_peer->ttl != peer->ttl)
- {
- vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl,
- VTY_NEWLINE);
- }
- }
-
- /* ttl-security hops */
- if (peer->gtsm_hops != 0)
- {
- if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops)
- {
- vty_out (vty, " neighbor %s ttl-security hops %d%s", addr,
- peer->gtsm_hops, VTY_NEWLINE);
- }
- }
-
- /* disable-connected-check */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
- {
- vty_out (vty, " neighbor %s disable-connected-check%s", addr, VTY_NEWLINE);
- }
- }
-
- /* update-source */
- if (peer->update_if)
- {
- if (! peer_group_active (peer) || ! g_peer->update_if
- || strcmp (g_peer->update_if, peer->update_if) != 0)
- {
- vty_out (vty, " neighbor %s update-source %s%s", addr,
- peer->update_if, VTY_NEWLINE);
- }
- }
- if (peer->update_source)
- {
- if (! peer_group_active (peer) || ! g_peer->update_source
- || sockunion_cmp (g_peer->update_source,
- peer->update_source) != 0)
- {
- vty_out (vty, " neighbor %s update-source %s%s", addr,
- sockunion2str (peer->update_source, buf, SU_ADDRSTRLEN),
- VTY_NEWLINE);
- }
- }
-
- /* advertisement-interval */
- if (CHECK_FLAG (peer->config, PEER_CONFIG_ROUTEADV) &&
- ((! peer_group_active (peer) && peer->v_routeadv != BGP_DEFAULT_EBGP_ROUTEADV) ||
- (peer_group_active (peer) && peer->v_routeadv != g_peer->v_routeadv)))
- {
- vty_out (vty, " neighbor %s advertisement-interval %u%s",
- addr, peer->v_routeadv, VTY_NEWLINE);
- }
-
- /* timers */
- if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER) &&
- ((! peer_group_active (peer) && (peer->keepalive != BGP_DEFAULT_KEEPALIVE || peer->holdtime != BGP_DEFAULT_HOLDTIME)) ||
- (peer_group_active (peer) && (peer->keepalive != g_peer->keepalive || peer->holdtime != g_peer->holdtime))))
- {
- vty_out (vty, " neighbor %s timers %u %u%s", addr,
- peer->keepalive, peer->holdtime, VTY_NEWLINE);
- }
-
- if (CHECK_FLAG (peer->config, PEER_CONFIG_CONNECT) &&
- ((! peer_group_active (peer) && peer->connect != BGP_DEFAULT_CONNECT_RETRY) ||
- (peer_group_active (peer) && peer->connect != g_peer->connect)))
-
- {
- vty_out (vty, " neighbor %s timers connect %u%s", addr,
- peer->connect, VTY_NEWLINE);
- }
-
- /* capability dynamic */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY))
- {
- vty_out (vty, " neighbor %s capability dynamic%s", addr,
- VTY_NEWLINE);
- }
- }
-
- /* capability extended-nexthop */
- if (peer->ifp && !CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- {
- vty_out (vty, " no neighbor %s capability extended-nexthop%s", addr,
- VTY_NEWLINE);
- }
- }
-
- if (!peer->ifp && CHECK_FLAG (peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_CAPABILITY_ENHE))
- {
- vty_out (vty, " neighbor %s capability extended-nexthop%s", addr,
- VTY_NEWLINE);
- }
- }
-
- /* dont-capability-negotiation */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_DONT_CAPABILITY))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_DONT_CAPABILITY))
- {
- vty_out (vty, " neighbor %s dont-capability-negotiate%s", addr,
- VTY_NEWLINE);
- }
- }
-
- /* override-capability */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY))
- {
- vty_out (vty, " neighbor %s override-capability%s", addr,
- VTY_NEWLINE);
- }
- }
-
- /* strict-capability-match */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
- {
- if (! peer_group_active (peer) ||
- ! CHECK_FLAG (g_peer->flags, PEER_FLAG_STRICT_CAP_MATCH))
- {
- vty_out (vty, " neighbor %s strict-capability-match%s", addr,
- VTY_NEWLINE);
- }
- }
-}
+ /* allowas-in origin */
+ else if (peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ if (!peer_group_active(peer)
+ || !peer_af_flag_check(g_peer, afi, safi,
+ PEER_FLAG_ALLOWAS_IN_ORIGIN)) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s allowas-in origin\n",
+ addr);
+ }
+ }
-/* BGP peer configuration display function. */
-static void
-bgp_config_write_peer_af (struct vty *vty, struct bgp *bgp,
- struct peer *peer, afi_t afi, safi_t safi,
- int *write)
-{
- struct peer *g_peer = NULL;
- char *addr;
-
- /* Skip dynamic neighbors. */
- if (peer_dynamic_neighbor (peer))
- return;
-
- if (peer->conf_if)
- addr = peer->conf_if;
- else
- addr = peer->host;
-
- /************************************
- ****** Per AF to the neighbor ******
- ************************************/
- if (peer_group_active (peer))
- {
- g_peer = peer->group->conf;
-
- /* If the peer-group is active but peer is not, print a 'no activate' */
- if (g_peer->afc[afi][safi] && !peer->afc[afi][safi])
- {
- afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s activate%s",
- addr, VTY_NEWLINE);
- }
-
- /* If the peer-group is not active but peer is, print an 'activate' */
- else if (!g_peer->afc[afi][safi] && peer->afc[afi][safi])
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s activate%s",
- addr, VTY_NEWLINE);
- }
- }
- else
- {
- if (peer->afc[afi][safi])
- {
- if ((afi == AFI_IP) && (safi == SAFI_UNICAST))
- {
- if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
- {
- afi_header_vty_out(vty, afi, safi, write,
- " neighbor %s activate%s",
- addr, VTY_NEWLINE);
- }
- }
- else
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s activate%s",
- addr, VTY_NEWLINE);
- }
- else
- {
- if ((afi == AFI_IP) && (safi == SAFI_UNICAST))
- {
- if (!bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s activate%s",
- addr, VTY_NEWLINE);
- }
- }
- }
- }
-
- /* addpath TX knobs */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ADDPATH_TX_ALL_PATHS))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s addpath-tx-all-paths%s",
- addr, VTY_NEWLINE);
- }
-
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s addpath-tx-bestpath-per-AS%s",
- addr, VTY_NEWLINE);
- }
-
- /* ORF capability. */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) ||
- peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_RM))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s capability orf prefix-list",
- addr);
-
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM) &&
- peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_RM))
- vty_out (vty, " both");
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_ORF_PREFIX_SM))
- vty_out (vty, " send");
- else
- vty_out (vty, " receive");
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* Route reflector client. */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s route-reflector-client%s",
- addr, VTY_NEWLINE);
- }
-
- /* next-hop-self force */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_FORCE_NEXTHOP_SELF))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s next-hop-self force%s",
- addr, VTY_NEWLINE);
- }
-
- /* next-hop-self */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_SELF))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s next-hop-self%s",
- addr, VTY_NEWLINE);
- }
-
- /* remove-private-AS */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s remove-private-AS all replace-AS%s",
- addr, VTY_NEWLINE);
- }
-
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s remove-private-AS replace-AS%s",
- addr, VTY_NEWLINE);
- }
-
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS_ALL))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s remove-private-AS all%s",
- addr, VTY_NEWLINE);
- }
-
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_REMOVE_PRIVATE_AS))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s remove-private-AS%s",
- addr, VTY_NEWLINE);
- }
-
- /* as-override */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_AS_OVERRIDE))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s as-override%s",
- addr, VTY_NEWLINE);
- }
-
- /* send-community print. */
- if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
- {
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)
- && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)
- && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s send-community all%s",
- addr, VTY_NEWLINE);
- }
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s send-community large%s",
- addr, VTY_NEWLINE);
- }
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s send-community extended%s",
- addr, VTY_NEWLINE);
- }
- else if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s send-community%s",
- addr, VTY_NEWLINE);
- }
- }
- else
- {
- if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)) &&
- !peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)) &&
- !peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s send-community all%s",
- addr, VTY_NEWLINE);
- }
- else
- {
- if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_LARGE_COMMUNITY)))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s send-community large%s",
- addr, VTY_NEWLINE);
- }
-
- if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_EXT_COMMUNITY)))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s send-community extended%s",
- addr, VTY_NEWLINE);
- }
-
- if (!peer_af_flag_check (peer, afi, safi, PEER_FLAG_SEND_COMMUNITY) &&
- (!g_peer || peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_SEND_COMMUNITY)))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " no neighbor %s send-community%s",
- addr, VTY_NEWLINE);
- }
- }
- }
-
- /* Default information */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_DEFAULT_ORIGINATE) ||
- (g_peer &&
- ((peer->default_rmap[afi][safi].name && !g_peer->default_rmap[afi][safi].name) ||
- (!peer->default_rmap[afi][safi].name && g_peer->default_rmap[afi][safi].name) ||
- (peer->default_rmap[afi][safi].name &&
- strcmp(peer->default_rmap[afi][safi].name, g_peer->default_rmap[afi][safi].name)))))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s default-originate", addr);
- if (peer->default_rmap[afi][safi].name)
- vty_out (vty, " route-map %s", peer->default_rmap[afi][safi].name);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* Soft reconfiguration inbound. */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_SOFT_RECONFIG))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s soft-reconfiguration inbound%s",
- addr, VTY_NEWLINE);
- }
-
- /* maximum-prefix. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX))
- if (! peer_group_active(peer)
- || g_peer->pmax[afi][safi] != peer->pmax[afi][safi]
- || g_peer->pmax_threshold[afi][safi] != peer->pmax_threshold[afi][safi]
- || CHECK_FLAG (g_peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING)
- != CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s maximum-prefix %lu",
- addr, peer->pmax[afi][safi]);
- if (peer->pmax_threshold[afi][safi] != MAXIMUM_PREFIX_THRESHOLD_DEFAULT)
- vty_out (vty, " %u", peer->pmax_threshold[afi][safi]);
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_WARNING))
- vty_out (vty, " warning-only");
- if (peer->pmax_restart[afi][safi])
- vty_out (vty, " restart %u", peer->pmax_restart[afi][safi]);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* Route server client. */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_RSERVER_CLIENT))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s route-server-client%s",
- addr, VTY_NEWLINE);
- }
-
- /* Nexthop-local unchanged. */
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s nexthop-local unchanged%s",
- addr, VTY_NEWLINE);
- }
-
- /* allowas-in <1-10> */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN))
- {
- if (! peer_group_active (peer)
- || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN)
- || peer->allowas_in[afi][safi] != g_peer->allowas_in[afi][safi])
- {
- if (peer->allowas_in[afi][safi] == 3)
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s allowas-in%s",
- addr, VTY_NEWLINE);
- }
- else
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s allowas-in %d%s",
- addr, peer->allowas_in[afi][safi], VTY_NEWLINE);
- }
- }
- }
-
- /* allowas-in origin */
- else if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- if (! peer_group_active (peer)
- || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_ALLOWAS_IN_ORIGIN))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s allowas-in origin%s",
- addr, VTY_NEWLINE);
- }
- }
-
- /* weight */
- if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_WEIGHT))
- if (! peer_group_active (peer)
- || ! peer_af_flag_check (g_peer, afi, safi, PEER_FLAG_WEIGHT)
- || peer->weight[afi][safi] != g_peer->weight[afi][safi])
- {
- if (peer->weight[afi][safi])
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s weight %lu%s",
- addr, peer->weight[afi][safi], VTY_NEWLINE);
- }
- }
-
- /* Filter. */
- bgp_config_write_filter (vty, peer, afi, safi, write);
-
- /* atribute-unchanged. */
- if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
- || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED)
- || CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_MED_UNCHANGED))
- {
- if (peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED)
- && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_UNCHANGED)
- && peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_MED_UNCHANGED))
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s attribute-unchanged%s",
- addr, VTY_NEWLINE);
- }
- else
- {
- afi_header_vty_out (vty, afi, safi, write,
- " neighbor %s attribute-unchanged%s%s%s%s", addr,
- peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) ?
- " as-path" : "",
- peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_NEXTHOP_UNCHANGED) ?
- " next-hop" : "",
- peergroup_af_flag_check (peer, afi, safi, PEER_FLAG_MED_UNCHANGED) ?
- " med" : "", VTY_NEWLINE);
- }
- }
+ /* weight */
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_WEIGHT))
+ if (!peer_group_active(peer)
+ || !peer_af_flag_check(g_peer, afi, safi, PEER_FLAG_WEIGHT)
+ || peer->weight[afi][safi] != g_peer->weight[afi][safi]) {
+ if (peer->weight[afi][safi]) {
+ afi_header_vty_out(vty, afi, safi, write,
+ " neighbor %s weight %lu\n",
+ addr,
+ peer->weight[afi][safi]);
+ }
+ }
+
+ /* Filter. */
+ bgp_config_write_filter(vty, peer, afi, safi, write);
+
+ /* atribute-unchanged. */
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_AS_PATH_UNCHANGED) ||
+ peer_af_flag_check(peer, afi, safi, PEER_FLAG_NEXTHOP_UNCHANGED) ||
+ peer_af_flag_check(peer, afi, safi, PEER_FLAG_MED_UNCHANGED)) {
+
+ if (!peer_group_active(peer) ||
+ peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_AS_PATH_UNCHANGED) ||
+ peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_NEXTHOP_UNCHANGED) ||
+ peergroup_af_flag_check(peer, afi, safi,
+ PEER_FLAG_MED_UNCHANGED)) {
+
+ afi_header_vty_out(
+ vty, afi, safi, write,
+ " neighbor %s attribute-unchanged%s%s%s\n",
+ addr,
+ peer_af_flag_check(
+ peer, afi, safi,
+ PEER_FLAG_AS_PATH_UNCHANGED)
+ ? " as-path"
+ : "",
+ peer_af_flag_check(
+ peer, afi, safi,
+ PEER_FLAG_NEXTHOP_UNCHANGED)
+ ? " next-hop"
+ : "",
+ peer_af_flag_check(peer, afi, safi,
+ PEER_FLAG_MED_UNCHANGED)
+ ? " med"
+ : "");
+ }
+ }
}
/* Display "address-family" configuration header. */
-void
-bgp_config_write_family_header (struct vty *vty, afi_t afi, safi_t safi,
- int *write)
-{
- if (*write)
- return;
-
- vty_out (vty, " !%s address-family ", VTY_NEWLINE);
-
- if (afi == AFI_IP)
- {
- if (safi == SAFI_UNICAST)
- vty_out (vty, "ipv4 unicast");
- else if (safi == SAFI_LABELED_UNICAST)
- vty_out (vty, "ipv4 labeled-unicast");
- else if (safi == SAFI_MULTICAST)
- vty_out (vty, "ipv4 multicast");
- else if (safi == SAFI_MPLS_VPN)
- vty_out (vty, "ipv4 vpn");
- else if (safi == SAFI_ENCAP)
- vty_out (vty, "ipv4 encap");
- }
- else if (afi == AFI_IP6)
- {
- if (safi == SAFI_UNICAST)
- vty_out (vty, "ipv6 unicast");
- else if (safi == SAFI_LABELED_UNICAST)
- vty_out (vty, "ipv6 labeled-unicast");
- else if (safi == SAFI_MULTICAST)
- vty_out (vty, "ipv6 multicast");
- else if (safi == SAFI_MPLS_VPN)
- vty_out (vty, "ipv6 vpn");
- else if (safi == SAFI_ENCAP)
- vty_out (vty, "ipv6 encap");
- }
- else if (afi == AFI_L2VPN)
- {
- if (safi == SAFI_EVPN)
- vty_out (vty, "l2vpn evpn");
- }
- vty_out (vty, "%s", VTY_NEWLINE);
-
- *write = 1;
+void bgp_config_write_family_header(struct vty *vty, afi_t afi, safi_t safi,
+ int *write)
+{
+ if (*write)
+ return;
+
+ vty_out(vty, " !\n address-family ");
+
+ if (afi == AFI_IP) {
+ if (safi == SAFI_UNICAST)
+ vty_out(vty, "ipv4 unicast");
+ else if (safi == SAFI_LABELED_UNICAST)
+ vty_out(vty, "ipv4 labeled-unicast");
+ else if (safi == SAFI_MULTICAST)
+ vty_out(vty, "ipv4 multicast");
+ else if (safi == SAFI_MPLS_VPN)
+ vty_out(vty, "ipv4 vpn");
+ else if (safi == SAFI_ENCAP)
+ vty_out(vty, "ipv4 encap");
+ } else if (afi == AFI_IP6) {
+ if (safi == SAFI_UNICAST)
+ vty_out(vty, "ipv6 unicast");
+ else if (safi == SAFI_LABELED_UNICAST)
+ vty_out(vty, "ipv6 labeled-unicast");
+ else if (safi == SAFI_MULTICAST)
+ vty_out(vty, "ipv6 multicast");
+ else if (safi == SAFI_MPLS_VPN)
+ vty_out(vty, "ipv6 vpn");
+ else if (safi == SAFI_ENCAP)
+ vty_out(vty, "ipv6 encap");
+ } else if (afi == AFI_L2VPN) {
+ if (safi == SAFI_EVPN)
+ vty_out(vty, "l2vpn evpn");
+ }
+ vty_out(vty, "\n");
+
+ *write = 1;
}
/* Address family based peer configuration display. */
-static int
-bgp_config_write_family (struct vty *vty, struct bgp *bgp, afi_t afi,
- safi_t safi)
+static int bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
{
- int write = 0;
- struct peer *peer;
- struct peer_group *group;
- struct listnode *node, *nnode;
+ int write = 0;
+ struct peer *peer;
+ struct peer_group *group;
+ struct listnode *node, *nnode;
+
+ bgp_config_write_distance(vty, bgp, afi, safi, &write);
- bgp_config_write_distance (vty, bgp, afi, safi, &write);
+ bgp_config_write_network(vty, bgp, afi, safi, &write);
- bgp_config_write_network (vty, bgp, afi, safi, &write);
+ bgp_config_write_redistribute(vty, bgp, afi, safi, &write);
- bgp_config_write_redistribute (vty, bgp, afi, safi, &write);
+ for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group))
+ bgp_config_write_peer_af(vty, bgp, group->conf, afi, safi,
+ &write);
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- bgp_config_write_peer_af (vty, bgp, group->conf, afi, safi, &write);
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ /* Skip dynamic neighbors. */
+ if (peer_dynamic_neighbor(peer))
+ continue;
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- /* Skip dynamic neighbors. */
- if (peer_dynamic_neighbor (peer))
- continue;
+ /* Do not display doppelganger peers */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ bgp_config_write_peer_af(vty, bgp, peer, afi, safi,
+ &write);
+ }
- /* Do not display doppelganger peers */
- if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
- bgp_config_write_peer_af (vty, bgp, peer, afi, safi, &write);
- }
+ bgp_config_write_maxpaths(vty, bgp, afi, safi, &write);
+ bgp_config_write_table_map(vty, bgp, afi, safi, &write);
- bgp_config_write_maxpaths (vty, bgp, afi, safi, &write);
- bgp_config_write_table_map (vty, bgp, afi, safi, &write);
+ if (safi == SAFI_EVPN)
+ bgp_config_write_evpn_info(vty, bgp, afi, safi, &write);
- if (write)
- vty_out (vty, " exit-address-family%s", VTY_NEWLINE);
+ if (write)
+ vty_out(vty, " exit-address-family\n");
- return write;
+ return write;
}
-int
-bgp_config_write (struct vty *vty)
+int bgp_config_write(struct vty *vty)
{
- int write = 0;
- struct bgp *bgp;
- struct peer_group *group;
- struct peer *peer;
- struct listnode *node, *nnode;
- struct listnode *mnode, *mnnode;
+ int write = 0;
+ struct bgp *bgp;
+ struct peer_group *group;
+ struct peer *peer;
+ struct listnode *node, *nnode;
+ struct listnode *mnode, *mnnode;
- /* BGP Multiple instance. */
- if (!bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
- {
- vty_out (vty, "no bgp multiple-instance%s", VTY_NEWLINE);
- write++;
- }
+ /* BGP Multiple instance. */
+ if (!bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
+ vty_out(vty, "no bgp multiple-instance\n");
+ write++;
+ }
- /* BGP Config type. */
- if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
- {
- vty_out (vty, "bgp config-type cisco%s", VTY_NEWLINE);
- write++;
- }
+ /* BGP Config type. */
+ if (bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
+ vty_out(vty, "bgp config-type cisco\n");
+ write++;
+ }
- if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
- vty_out (vty, "bgp route-map delay-timer %u%s", bm->rmap_update_timer,
- VTY_NEWLINE);
+ if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
+ vty_out(vty, "bgp route-map delay-timer %u\n",
+ bm->rmap_update_timer);
+
+ /* BGP configuration. */
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
+ if (write)
+ vty_out(vty, "!\n");
+
+ /* Router bgp ASN */
+ vty_out(vty, "router bgp %u", bgp->as);
+
+ if (bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
+ if (bgp->name)
+ vty_out(vty, " %s %s",
+ (bgp->inst_type
+ == BGP_INSTANCE_TYPE_VIEW)
+ ? "view"
+ : "vrf",
+ bgp->name);
+ }
+ vty_out(vty, "\n");
+
+ /* No Synchronization */
+ if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
+ vty_out(vty, " no synchronization\n");
+
+ /* BGP fast-external-failover. */
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
+ vty_out(vty, " no bgp fast-external-failover\n");
+
+ /* BGP router ID. */
+ if (bgp->router_id_static.s_addr != 0)
+ vty_out(vty, " bgp router-id %s\n",
+ inet_ntoa(bgp->router_id_static));
+
+ /* BGP log-neighbor-changes. */
+ if (!!bgp_flag_check(bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)
+ != DFLT_BGP_LOG_NEIGHBOR_CHANGES)
+ vty_out(vty, " %sbgp log-neighbor-changes\n",
+ bgp_flag_check(bgp,
+ BGP_FLAG_LOG_NEIGHBOR_CHANGES)
+ ? ""
+ : "no ");
+
+ /* BGP configuration. */
+ if (bgp_flag_check(bgp, BGP_FLAG_ALWAYS_COMPARE_MED))
+ vty_out(vty, " bgp always-compare-med\n");
+
+ /* BGP default ipv4-unicast. */
+ if (bgp_flag_check(bgp, BGP_FLAG_NO_DEFAULT_IPV4))
+ vty_out(vty, " no bgp default ipv4-unicast\n");
+
+ /* BGP default local-preference. */
+ if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
+ vty_out(vty, " bgp default local-preference %u\n",
+ bgp->default_local_pref);
+
+ /* BGP default show-hostname */
+ if (!!bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME)
+ != DFLT_BGP_SHOW_HOSTNAME)
+ vty_out(vty, " %sbgp default show-hostname\n",
+ bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME)
+ ? ""
+ : "no ");
+
+ /* BGP default subgroup-pkt-queue-max. */
+ if (bgp->default_subgroup_pkt_queue_max
+ != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX)
+ vty_out(vty, " bgp default subgroup-pkt-queue-max %u\n",
+ bgp->default_subgroup_pkt_queue_max);
+
+ /* BGP client-to-client reflection. */
+ if (bgp_flag_check(bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
+ vty_out(vty, " no bgp client-to-client reflection\n");
+
+ /* BGP cluster ID. */
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CLUSTER_ID))
+ vty_out(vty, " bgp cluster-id %s\n",
+ inet_ntoa(bgp->cluster_id));
+
+ /* Disable ebgp connected nexthop check */
+ if (bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
+ vty_out(vty,
+ " bgp disable-ebgp-connected-route-check\n");
+
+ /* Confederation identifier*/
+ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
+ vty_out(vty, " bgp confederation identifier %i\n",
+ bgp->confed_id);
+
+ /* Confederation peer */
+ if (bgp->confed_peers_cnt > 0) {
+ int i;
+
+ vty_out(vty, " bgp confederation peers");
+
+ for (i = 0; i < bgp->confed_peers_cnt; i++)
+ vty_out(vty, " %u", bgp->confed_peers[i]);
+
+ vty_out(vty, "\n");
+ }
- /* BGP configuration. */
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- {
- if (write)
- vty_out (vty, "!%s", VTY_NEWLINE);
+ /* BGP enforce-first-as. */
+ if (bgp_flag_check(bgp, BGP_FLAG_ENFORCE_FIRST_AS))
+ vty_out(vty, " bgp enforce-first-as\n");
+
+ /* BGP deterministic-med. */
+ if (!!bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED)
+ != DFLT_BGP_DETERMINISTIC_MED)
+ vty_out(vty, " %sbgp deterministic-med\n",
+ bgp_flag_check(bgp, BGP_FLAG_DETERMINISTIC_MED)
+ ? ""
+ : "no ");
+
+ /* BGP update-delay. */
+ bgp_config_write_update_delay(vty, bgp);
+
+ if (bgp->v_maxmed_onstartup
+ != BGP_MAXMED_ONSTARTUP_UNCONFIGURED) {
+ vty_out(vty, " bgp max-med on-startup %u",
+ bgp->v_maxmed_onstartup);
+ if (bgp->maxmed_onstartup_value
+ != BGP_MAXMED_VALUE_DEFAULT)
+ vty_out(vty, " %u",
+ bgp->maxmed_onstartup_value);
+ vty_out(vty, "\n");
+ }
+ if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED) {
+ vty_out(vty, " bgp max-med administrative");
+ if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT)
+ vty_out(vty, " %u", bgp->maxmed_admin_value);
+ vty_out(vty, "\n");
+ }
- /* Router bgp ASN */
- vty_out (vty, "router bgp %u", bgp->as);
+ /* write quanta */
+ bgp_config_write_wpkt_quanta(vty, bgp);
+
+ /* coalesce time */
+ bgp_config_write_coalesce_time(vty, bgp);
+
+ /* BGP graceful-restart. */
+ if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
+ vty_out(vty,
+ " bgp graceful-restart stalepath-time %u\n",
+ bgp->stalepath_time);
+ if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME)
+ vty_out(vty, " bgp graceful-restart restart-time %u\n",
+ bgp->restart_time);
+ if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART))
+ vty_out(vty, " bgp graceful-restart\n");
+
+ /* BGP graceful-restart Preserve State F bit. */
+ if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD))
+ vty_out(vty,
+ " bgp graceful-restart preserve-fw-state\n");
+
+ /* BGP bestpath method. */
+ if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_IGNORE))
+ vty_out(vty, " bgp bestpath as-path ignore\n");
+ if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_CONFED))
+ vty_out(vty, " bgp bestpath as-path confed\n");
+
+ if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX)) {
+ if (bgp_flag_check(bgp,
+ BGP_FLAG_MULTIPATH_RELAX_AS_SET)) {
+ vty_out(vty,
+ " bgp bestpath as-path multipath-relax as-set\n");
+ } else {
+ vty_out(vty,
+ " bgp bestpath as-path multipath-relax\n");
+ }
+ }
- if (bgp_option_check (BGP_OPT_MULTIPLE_INSTANCE))
- {
- if (bgp->name)
- vty_out (vty, " %s %s",
- (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) ?
- "view" : "vrf", bgp->name);
- }
- vty_out (vty, "%s", VTY_NEWLINE);
-
- /* No Synchronization */
- if (bgp_option_check (BGP_OPT_CONFIG_CISCO))
- vty_out (vty, " no synchronization%s", VTY_NEWLINE);
-
- /* BGP fast-external-failover. */
- if (CHECK_FLAG (bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
- vty_out (vty, " no bgp fast-external-failover%s", VTY_NEWLINE);
-
- /* BGP router ID. */
- if (bgp->router_id_static.s_addr != 0)
- vty_out (vty, " bgp router-id %s%s",
- inet_ntoa (bgp->router_id_static), VTY_NEWLINE);
-
- /* BGP log-neighbor-changes. */
- if (!!bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)
- != DFLT_BGP_LOG_NEIGHBOR_CHANGES)
- vty_out (vty, " %sbgp log-neighbor-changes%s",
- bgp_flag_check (bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES) ? "" : "no ",
- VTY_NEWLINE);
-
- /* BGP configuration. */
- if (bgp_flag_check (bgp, BGP_FLAG_ALWAYS_COMPARE_MED))
- vty_out (vty, " bgp always-compare-med%s", VTY_NEWLINE);
-
- /* BGP default ipv4-unicast. */
- if (bgp_flag_check (bgp, BGP_FLAG_NO_DEFAULT_IPV4))
- vty_out (vty, " no bgp default ipv4-unicast%s", VTY_NEWLINE);
-
- /* BGP default local-preference. */
- if (bgp->default_local_pref != BGP_DEFAULT_LOCAL_PREF)
- vty_out (vty, " bgp default local-preference %u%s",
- bgp->default_local_pref, VTY_NEWLINE);
-
- /* BGP default show-hostname */
- if (!!bgp_flag_check(bgp, BGP_FLAG_SHOW_HOSTNAME)
- != DFLT_BGP_SHOW_HOSTNAME)
- vty_out (vty, " %sbgp default show-hostname%s",
- bgp_flag_check (bgp, BGP_FLAG_SHOW_HOSTNAME) ? "" : "no ",
- VTY_NEWLINE);
-
- /* BGP default subgroup-pkt-queue-max. */
- if (bgp->default_subgroup_pkt_queue_max != BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX)
- vty_out (vty, " bgp default subgroup-pkt-queue-max %u%s",
- bgp->default_subgroup_pkt_queue_max, VTY_NEWLINE);
-
- /* BGP client-to-client reflection. */
- if (bgp_flag_check (bgp, BGP_FLAG_NO_CLIENT_TO_CLIENT))
- vty_out (vty, " no bgp client-to-client reflection%s", VTY_NEWLINE);
-
- /* BGP cluster ID. */
- if (CHECK_FLAG (bgp->config, BGP_CONFIG_CLUSTER_ID))
- vty_out (vty, " bgp cluster-id %s%s", inet_ntoa (bgp->cluster_id),
- VTY_NEWLINE);
-
- /* Disable ebgp connected nexthop check */
- if (bgp_flag_check (bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
- vty_out (vty, " bgp disable-ebgp-connected-route-check%s", VTY_NEWLINE);
-
- /* Confederation identifier*/
- if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
- vty_out (vty, " bgp confederation identifier %i%s", bgp->confed_id,
- VTY_NEWLINE);
-
- /* Confederation peer */
- if (bgp->confed_peers_cnt > 0)
- {
- int i;
-
- vty_out (vty, " bgp confederation peers");
-
- for (i = 0; i < bgp->confed_peers_cnt; i++)
- vty_out(vty, " %u", bgp->confed_peers[i]);
-
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* BGP enforce-first-as. */
- if (bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
- vty_out (vty, " bgp enforce-first-as%s", VTY_NEWLINE);
-
- /* BGP deterministic-med. */
- if (!!bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED)
- != DFLT_BGP_DETERMINISTIC_MED)
- vty_out (vty, " %sbgp deterministic-med%s",
- bgp_flag_check (bgp, BGP_FLAG_DETERMINISTIC_MED) ? "" : "no ",
- VTY_NEWLINE);
-
- /* BGP update-delay. */
- bgp_config_write_update_delay (vty, bgp);
-
- if (bgp->v_maxmed_onstartup != BGP_MAXMED_ONSTARTUP_UNCONFIGURED)
- {
- vty_out (vty, " bgp max-med on-startup %u", bgp->v_maxmed_onstartup);
- if (bgp->maxmed_onstartup_value != BGP_MAXMED_VALUE_DEFAULT)
- vty_out (vty, " %u", bgp->maxmed_onstartup_value);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
- if (bgp->v_maxmed_admin != BGP_MAXMED_ADMIN_UNCONFIGURED)
- {
- vty_out (vty, " bgp max-med administrative");
- if (bgp->maxmed_admin_value != BGP_MAXMED_VALUE_DEFAULT)
- vty_out (vty, " %u", bgp->maxmed_admin_value);
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* write quanta */
- bgp_config_write_wpkt_quanta (vty, bgp);
-
- /* coalesce time */
- bgp_config_write_coalesce_time(vty, bgp);
-
- /* BGP graceful-restart. */
- if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
- vty_out (vty, " bgp graceful-restart stalepath-time %u%s",
- bgp->stalepath_time, VTY_NEWLINE);
- if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME)
- vty_out (vty, " bgp graceful-restart restart-time %u%s",
- bgp->restart_time, VTY_NEWLINE);
- if (bgp_flag_check (bgp, BGP_FLAG_GRACEFUL_RESTART))
- vty_out (vty, " bgp graceful-restart%s", VTY_NEWLINE);
-
- /* BGP graceful-restart Preserve State F bit. */
- if (bgp_flag_check (bgp, BGP_FLAG_GR_PRESERVE_FWD))
- vty_out (vty, " bgp graceful-restart preserve-fw-state%s", VTY_NEWLINE);
-
- /* BGP bestpath method. */
- if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_IGNORE))
- vty_out (vty, " bgp bestpath as-path ignore%s", VTY_NEWLINE);
- if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_CONFED))
- vty_out (vty, " bgp bestpath as-path confed%s", VTY_NEWLINE);
-
- if (bgp_flag_check (bgp, BGP_FLAG_ASPATH_MULTIPATH_RELAX))
- {
- if (bgp_flag_check (bgp, BGP_FLAG_MULTIPATH_RELAX_AS_SET))
- {
- vty_out (vty, " bgp bestpath as-path multipath-relax as-set%s", VTY_NEWLINE);
- }
- else
- {
- vty_out (vty, " bgp bestpath as-path multipath-relax%s", VTY_NEWLINE);
- }
- }
-
- if (bgp_flag_check (bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
- vty_out (vty, " bgp route-reflector allow-outbound-policy%s",
- VTY_NEWLINE);
- }
- if (bgp_flag_check (bgp, BGP_FLAG_COMPARE_ROUTER_ID))
- vty_out (vty, " bgp bestpath compare-routerid%s", VTY_NEWLINE);
- if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED)
- || bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST))
- {
- vty_out (vty, " bgp bestpath med");
- if (bgp_flag_check (bgp, BGP_FLAG_MED_CONFED))
- vty_out (vty, " confed");
- if (bgp_flag_check (bgp, BGP_FLAG_MED_MISSING_AS_WORST))
- vty_out (vty, " missing-as-worst");
- vty_out (vty, "%s", VTY_NEWLINE);
- }
-
- /* BGP network import check. */
- if (!!bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK)
- != DFLT_BGP_IMPORT_CHECK)
- vty_out (vty, " %sbgp network import-check%s",
- bgp_flag_check (bgp, BGP_FLAG_IMPORT_CHECK) ? "" : "no ",
- VTY_NEWLINE);
-
- /* BGP flag dampening. */
- if (CHECK_FLAG (bgp->af_flags[AFI_IP][SAFI_UNICAST],
- BGP_CONFIG_DAMPENING))
- bgp_config_write_damp (vty);
-
- /* BGP timers configuration. */
- if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE
- && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
- vty_out (vty, " timers bgp %u %u%s", bgp->default_keepalive,
- bgp->default_holdtime, VTY_NEWLINE);
-
- /* peer-group */
- for (ALL_LIST_ELEMENTS (bgp->group, node, nnode, group))
- {
- bgp_config_write_peer_global (vty, bgp, group->conf);
- }
+ if (bgp_flag_check(bgp, BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY)) {
+ vty_out(vty,
+ " bgp route-reflector allow-outbound-policy\n");
+ }
+ if (bgp_flag_check(bgp, BGP_FLAG_COMPARE_ROUTER_ID))
+ vty_out(vty, " bgp bestpath compare-routerid\n");
+ if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED)
+ || bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST)) {
+ vty_out(vty, " bgp bestpath med");
+ if (bgp_flag_check(bgp, BGP_FLAG_MED_CONFED))
+ vty_out(vty, " confed");
+ if (bgp_flag_check(bgp, BGP_FLAG_MED_MISSING_AS_WORST))
+ vty_out(vty, " missing-as-worst");
+ vty_out(vty, "\n");
+ }
- /* Normal neighbor configuration. */
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- {
- if (CHECK_FLAG (peer->flags, PEER_FLAG_CONFIG_NODE))
- bgp_config_write_peer_global (vty, bgp, peer);
- }
+ /* BGP network import check. */
+ if (!!bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)
+ != DFLT_BGP_IMPORT_CHECK)
+ vty_out(vty, " %sbgp network import-check\n",
+ bgp_flag_check(bgp, BGP_FLAG_IMPORT_CHECK)
+ ? ""
+ : "no ");
+
+ /* BGP flag dampening. */
+ if (CHECK_FLAG(bgp->af_flags[AFI_IP][SAFI_UNICAST],
+ BGP_CONFIG_DAMPENING))
+ bgp_config_write_damp(vty);
+
+ /* BGP timers configuration. */
+ if (bgp->default_keepalive != BGP_DEFAULT_KEEPALIVE
+ && bgp->default_holdtime != BGP_DEFAULT_HOLDTIME)
+ vty_out(vty, " timers bgp %u %u\n",
+ bgp->default_keepalive, bgp->default_holdtime);
+
+ /* peer-group */
+ for (ALL_LIST_ELEMENTS(bgp->group, node, nnode, group)) {
+ bgp_config_write_peer_global(vty, bgp, group->conf);
+ }
+
+ /* Normal neighbor configuration. */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ bgp_config_write_peer_global(vty, bgp, peer);
+ }
- /* listen range and limit for dynamic BGP neighbors */
- bgp_config_write_listen (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);
+ /* No auto-summary */
+ if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
+ vty_out(vty, " no auto-summary\n");
- /* IPv4 unicast configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_UNICAST);
+ /* IPv4 unicast configuration. */
+ write +=
+ bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
- /* IPv4 multicast configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MULTICAST);
+ /* IPv4 multicast configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP,
+ SAFI_MULTICAST);
- /* IPv4 labeled-unicast configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_LABELED_UNICAST);
+ /* IPv4 labeled-unicast configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP,
+ SAFI_LABELED_UNICAST);
- /* IPv4 VPN configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_MPLS_VPN);
+ /* IPv4 VPN configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP,
+ SAFI_MPLS_VPN);
- /* ENCAPv4 configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP, SAFI_ENCAP);
+ /* ENCAPv4 configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP, SAFI_ENCAP);
- /* IPv6 unicast configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_UNICAST);
+ /* IPv6 unicast configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP6,
+ SAFI_UNICAST);
- /* IPv6 multicast configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MULTICAST);
+ /* IPv6 multicast configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP6,
+ SAFI_MULTICAST);
- /* IPv6 labeled-unicast configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_LABELED_UNICAST);
+ /* IPv6 labeled-unicast configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP6,
+ SAFI_LABELED_UNICAST);
- /* IPv6 VPN configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_MPLS_VPN);
+ /* IPv6 VPN configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP6,
+ SAFI_MPLS_VPN);
- /* ENCAPv6 configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_IP6, SAFI_ENCAP);
+ /* ENCAPv6 configuration. */
+ write += bgp_config_write_family(vty, bgp, AFI_IP6, SAFI_ENCAP);
- /* EVPN configuration. */
- write += bgp_config_write_family (vty, bgp, AFI_L2VPN, SAFI_EVPN);
+ /* EVPN configuration. */
+ write +=
+ bgp_config_write_family(vty, bgp, AFI_L2VPN, SAFI_EVPN);
#if ENABLE_BGP_VNC
- write += bgp_rfapi_cfg_write(vty, bgp);
+ write += bgp_rfapi_cfg_write(vty, bgp);
#endif
- write++;
- }
- return write;
+ write++;
+ }
+ return write;
}
-void
-bgp_master_init (struct thread_master *master)
+void bgp_master_init(struct thread_master *master)
{
- qobj_init ();
+ qobj_init();
- memset (&bgp_master, 0, sizeof (struct bgp_master));
+ memset(&bgp_master, 0, sizeof(struct bgp_master));
- bm = &bgp_master;
- bm->bgp = list_new ();
- bm->listen_sockets = list_new ();
- bm->port = BGP_PORT_DEFAULT;
- bm->master = master;
- bm->start_time = bgp_clock ();
- bm->t_rmap_update = NULL;
- bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
+ bm = &bgp_master;
+ bm->bgp = list_new();
+ bm->listen_sockets = list_new();
+ bm->port = BGP_PORT_DEFAULT;
+ bm->master = master;
+ bm->start_time = bgp_clock();
+ bm->t_rmap_update = NULL;
+ bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER;
- bgp_process_queue_init();
+ bgp_process_queue_init();
- /* Enable multiple instances by default. */
- bgp_option_set (BGP_OPT_MULTIPLE_INSTANCE);
+ /* Enable multiple instances by default. */
+ bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
- QOBJ_REG (bm, bgp_master);
+ QOBJ_REG(bm, bgp_master);
}
/*
* Free up connected routes and interfaces for a BGP instance. Invoked upon
* instance delete (non-default only) or BGP exit.
*/
-static void
-bgp_if_finish (struct bgp *bgp)
+static void bgp_if_finish(struct bgp *bgp)
{
- struct listnode *ifnode, *ifnnode;
- struct interface *ifp;
-
- if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
- return;
+ struct listnode *ifnode, *ifnnode;
+ struct interface *ifp;
+
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
+ return;
- for (ALL_LIST_ELEMENTS (vrf_iflist(bgp->vrf_id), ifnode, ifnnode, ifp))
- {
- struct listnode *c_node, *c_nnode;
- struct connected *c;
+ for (ALL_LIST_ELEMENTS(vrf_iflist(bgp->vrf_id), ifnode, ifnnode, ifp)) {
+ struct listnode *c_node, *c_nnode;
+ struct connected *c;
- for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c))
- bgp_connected_delete (bgp, c);
- }
+ for (ALL_LIST_ELEMENTS(ifp->connected, c_node, c_nnode, c))
+ bgp_connected_delete(bgp, c);
+ }
}
-extern void bgp_snmp_init (void);
+extern void bgp_snmp_init(void);
-static void
-bgp_viewvrf_autocomplete (vector comps, struct cmd_token *token)
+static void bgp_viewvrf_autocomplete(vector comps, struct cmd_token *token)
{
- struct vrf *vrf = NULL;
- struct listnode *next;
- struct bgp *bgp;
+ struct vrf *vrf = NULL;
+ struct listnode *next;
+ struct bgp *bgp;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
- {
- if (vrf->vrf_id != VRF_DEFAULT)
- vector_set (comps, XSTRDUP (MTYPE_COMPLETION, vrf->name));
- }
+ RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name)
+ {
+ if (vrf->vrf_id != VRF_DEFAULT)
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, vrf->name));
+ }
- for (ALL_LIST_ELEMENTS_RO (bm->bgp, next, bgp))
- {
- if (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW)
- continue;
+ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW)
+ continue;
- vector_set (comps, XSTRDUP (MTYPE_COMPLETION, bgp->name));
- }
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, bgp->name));
+ }
}
static const struct cmd_variable_handler bgp_viewvrf_var_handlers[] = {
- {
- .tokenname = "VIEWVRFNAME",
- .completions = bgp_viewvrf_autocomplete
- },
- {
- .completions = NULL
- },
+ {.tokenname = "VIEWVRFNAME", .completions = bgp_viewvrf_autocomplete},
+ {.completions = NULL},
};
-void
-bgp_init (void)
+void bgp_init(void)
{
- /* allocates some vital data structures used by peer commands in vty_init */
+ /* allocates some vital data structures used by peer commands in
+ * vty_init */
- /* Init zebra. */
- bgp_zebra_init(bm->master);
+ /* Init zebra. */
+ bgp_zebra_init(bm->master);
#if ENABLE_BGP_VNC
- vnc_zebra_init (bm->master);
+ vnc_zebra_init(bm->master);
#endif
- /* BGP VTY commands installation. */
- bgp_vty_init ();
-
- /* BGP inits. */
- bgp_attr_init ();
- bgp_debug_init ();
- bgp_dump_init ();
- bgp_route_init ();
- bgp_route_map_init ();
- bgp_scan_vty_init();
- bgp_mplsvpn_init ();
+ /* BGP VTY commands installation. */
+ bgp_vty_init();
+
+ /* BGP inits. */
+ bgp_attr_init();
+ bgp_debug_init();
+ bgp_dump_init();
+ bgp_route_init();
+ bgp_route_map_init();
+ bgp_scan_vty_init();
+ bgp_mplsvpn_init();
#if ENABLE_BGP_VNC
- rfapi_init ();
+ rfapi_init();
#endif
- bgp_ethernetvpn_init ();
-
- /* Access list initialize. */
- access_list_init ();
- access_list_add_hook (peer_distribute_update);
- access_list_delete_hook (peer_distribute_update);
-
- /* Filter list initialize. */
- bgp_filter_init ();
- as_list_add_hook (peer_aslist_add);
- as_list_delete_hook (peer_aslist_del);
-
- /* Prefix list initialize.*/
- prefix_list_init ();
- prefix_list_add_hook (peer_prefix_list_update);
- prefix_list_delete_hook (peer_prefix_list_update);
-
- /* Community list initialize. */
- bgp_clist = community_list_init ();
-
- /* BFD init */
- bgp_bfd_init();
-
- cmd_variable_handler_register (bgp_viewvrf_var_handlers);
-}
-
-void
-bgp_terminate (void)
-{
- struct bgp *bgp;
- struct peer *peer;
- struct listnode *node, *nnode;
- struct listnode *mnode, *mnnode;
-
- QOBJ_UNREG (bm);
-
- /* Close the listener sockets first as this prevents peers from attempting
- * to reconnect on receiving the peer unconfig message. In the presence
- * of a large number of peers this will ensure that no peer is left with
- * a dangling connection
- */
- /* reverse bgp_master_init */
- bgp_close();
- if (bm->listen_sockets)
- list_free(bm->listen_sockets);
- bm->listen_sockets = NULL;
-
- for (ALL_LIST_ELEMENTS (bm->bgp, mnode, mnnode, bgp))
- for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))
- if (peer->status == Established ||
- peer->status == OpenSent ||
- peer->status == OpenConfirm)
- bgp_notify_send (peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_PEER_UNCONFIG);
-
- if (bm->process_main_queue)
- {
- work_queue_free (bm->process_main_queue);
- bm->process_main_queue = NULL;
- }
-
- if (bm->t_rmap_update)
- BGP_TIMER_OFF(bm->t_rmap_update);
+ bgp_ethernetvpn_init();
+
+ /* Access list initialize. */
+ access_list_init();
+ access_list_add_hook(peer_distribute_update);
+ access_list_delete_hook(peer_distribute_update);
+
+ /* Filter list initialize. */
+ bgp_filter_init();
+ as_list_add_hook(peer_aslist_add);
+ as_list_delete_hook(peer_aslist_del);
+
+ /* Prefix list initialize.*/
+ prefix_list_init();
+ prefix_list_add_hook(peer_prefix_list_update);
+ prefix_list_delete_hook(peer_prefix_list_update);
+
+ /* Community list initialize. */
+ bgp_clist = community_list_init();
+
+ /* BFD init */
+ bgp_bfd_init();
+
+ cmd_variable_handler_register(bgp_viewvrf_var_handlers);
+}
+
+void bgp_terminate(void)
+{
+ struct bgp *bgp;
+ struct peer *peer;
+ struct listnode *node, *nnode;
+ struct listnode *mnode, *mnnode;
+
+ QOBJ_UNREG(bm);
+
+ /* Close the listener sockets first as this prevents peers from
+ * attempting
+ * to reconnect on receiving the peer unconfig message. In the presence
+ * of a large number of peers this will ensure that no peer is left with
+ * a dangling connection
+ */
+ /* reverse bgp_master_init */
+ bgp_close();
+ if (bm->listen_sockets)
+ list_free(bm->listen_sockets);
+ bm->listen_sockets = NULL;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ if (peer->status == Established
+ || peer->status == OpenSent
+ || peer->status == OpenConfirm)
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_PEER_UNCONFIG);
+
+ if (bm->process_main_queue) {
+ work_queue_free(bm->process_main_queue);
+ bm->process_main_queue = NULL;
+ }
+
+ if (bm->t_rmap_update)
+ BGP_TIMER_OFF(bm->t_rmap_update);
}