#include "bgpd/bgp_flowspec.h"
#include "bgpd/bgp_labelpool.h"
#include "bgpd/bgp_pbr.h"
+#include "bgpd/bgp_addpath.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_QOBJ_TYPE(bgp_master)
case BGP_OPT_MULTIPLE_INSTANCE:
case BGP_OPT_CONFIG_CISCO:
case BGP_OPT_NO_LISTEN:
+ case BGP_OPT_NO_ZEBRA:
SET_FLAG(bm->options, flag);
break;
default:
if (listcount(bm->bgp) > 1)
return BGP_ERR_MULTIPLE_INSTANCE_USED;
/* Fall through. */
+ case BGP_OPT_NO_ZEBRA:
case BGP_OPT_NO_FIB:
case BGP_OPT_CONFIG_CISCO:
UNSET_FLAG(bm->options, flag);
{
struct listnode *node, *nnode;
struct bgp *bgp;
+ struct in_addr *addr = NULL;
+
+ if (router_id != NULL)
+ addr = (struct in_addr *)&(router_id->u.prefix4);
if (vrf_id == VRF_DEFAULT) {
/* Router-id change for default VRF has to also update all
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);
+ if (addr)
+ bgp->router_id_zebra = *addr;
+ else
+ addr = &bgp->router_id_zebra;
+
+ if (!bgp->router_id_static.s_addr) {
+ /* Router ID is updated if there are no active
+ * peer sessions
+ */
+ if (bgp->established_peers == 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("RID change : vrf %u, RTR ID %s",
+ bgp->vrf_id, inet_ntoa(*addr));
+ bgp_router_id_set(bgp, addr);
+ }
+ }
}
} else {
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (bgp) {
- bgp->router_id_zebra = router_id->u.prefix4;
+ if (addr)
+ bgp->router_id_zebra = *addr;
+ else
+ addr = &bgp->router_id_zebra;
+
+ if (!bgp->router_id_static.s_addr) {
+ /* Router ID is updated if there are no active
+ * peer sessions
+ */
+ if (bgp->established_peers == 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("RID change : vrf %u, RTR ID %s",
+ bgp->vrf_id, inet_ntoa(*addr));
+ bgp_router_id_set(bgp, addr);
+ }
+ }
- if (!bgp->router_id_static.s_addr)
- bgp_router_id_set(bgp, &router_id->u.prefix4);
}
}
}
return sockunion_hash(&peer->su);
}
-static int peer_hash_same(const void *p1, const void *p2)
+static bool peer_hash_same(const void *p1, const void *p2)
{
const struct peer *peer1 = p1;
const struct peer *peer2 = p2;
}
}
+/* Return true if the addpath type is set for peer and different from
+ * peer-group.
+ */
+static int peergroup_af_addpath_check(struct peer *peer, afi_t afi, safi_t safi)
+{
+ enum bgp_addpath_strat type, g_type;
+
+ type = peer->addpath_type[afi][safi];
+
+ if (type != BGP_ADDPATH_NONE) {
+ if (peer_group_active(peer)) {
+ g_type = peer->group->conf->addpath_type[afi][safi];
+
+ if (type != g_type)
+ return 1;
+ else
+ return 0;
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
/* Check peer's AS number and determines if this peer is IBGP or EBGP */
static inline bgp_peer_sort_t peer_calc_sort(struct peer *peer)
{
static void peer_free(struct peer *peer)
{
+ afi_t afi;
+ safi_t safi;
+
assert(peer->status == Deleted);
QOBJ_UNREG(peer);
bfd_info_free(&(peer->bfd_info));
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+ bgp_addpath_set_peer_type(peer, afi, safi,
+ BGP_ADDPATH_NONE);
+ }
+ }
+
bgp_unlock(peer->bgp);
memset(peer, 0, sizeof(struct peer));
SET_FLAG(peer->af_flags_invert[afi][safi],
PEER_FLAG_SEND_LARGE_COMMUNITY);
}
+ peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
}
/* set nexthop-unchanged for l2vpn evpn by default */
peer_dst->allowas_in[afi][safi] =
peer_src->allowas_in[afi][safi];
peer_dst->weight[afi][safi] = peer_src->weight[afi][safi];
+ peer_dst->addpath_type[afi][safi] =
+ peer_src->addpath_type[afi][safi];
}
for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) {
}
}
-/* Create new BGP peer. */
+/*
+ * Create new BGP peer.
+ *
+ * conf_if and su are mutually exclusive if configuring from the cli.
+ * If we are handing a doppelganger, then we *must* pass in both
+ * the original peer's su and conf_if, so that we can appropriately
+ * track the bgp->peerhash( ie we don't want to remove the current
+ * one from the config ).
+ */
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,
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 (su)
+ peer->su = *su;
+ else
+ 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);
MTYPE_BGP_FILTER_NAME);
PEER_ATTR_INHERIT(peer, group, filter[afi][safi].usmap.map);
}
+
+ if (peer->addpath_type[afi][safi] == BGP_ADDPATH_NONE) {
+ peer->addpath_type[afi][safi] = conf->addpath_type[afi][safi];
+ bgp_addpath_type_changed(conf->bgp);
+ }
}
static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
{
int active;
+ struct peer *other;
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
flog_err(EC_BGP_PEER_GROUP, "%s was called for peer-group %s",
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
}
+ /*
+ * If we are turning on a AFI/SAFI locally and we've
+ * started bringing a peer up, we need to tell
+ * the other peer to restart because we might loose
+ * configuration here because when the doppelganger
+ * gets to a established state due to how
+ * we resolve we could just overwrite the afi/safi
+ * activation.
+ */
+ other = peer->doppelganger;
+ if (other
+ && (other->status == OpenSent
+ || other->status == OpenConfirm)) {
+ other->last_reset = PEER_DOWN_AF_ACTIVATE;
+ bgp_notify_send(other, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_CONFIG_CHANGE);
+ }
}
return 0;
peer_delete(other);
}
}
- list_delete_and_null(&group->peer);
+ list_delete(&group->peer);
for (afi = AFI_IP; afi < AFI_MAX; afi++) {
for (ALL_LIST_ELEMENTS(group->listen_range[afi], node, nnode,
prefix)) {
prefix_free(prefix);
}
- list_delete_and_null(&group->listen_range[afi]);
+ list_delete(&group->listen_range[afi]);
}
XFREE(MTYPE_PEER_GROUP_HOST, group->name);
#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_addpath_init_bgp_data(&bgp->tx_addpath);
bgp->as = *as;
}
bgp = bgp_create(as, name, inst_type);
+ if (bgp_option_check(BGP_OPT_NO_ZEBRA) && name)
+ bgp->vrf_id = vrf_generate_id();
bgp_router_id_set(bgp, &bgp->router_id_zebra);
bgp_address_init(bgp);
bgp_tip_hash_init(bgp);
bgp_handle_socket(bgp, vrf, VRF_UNKNOWN, true);
listnode_add(bm->bgp, bgp);
- if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: Registering BGP instance %s to zebra",
+ __PRETTY_FUNCTION__, name);
bgp_zebra_instance_register(bgp);
-
+ }
return 0;
}
}
/* Deregister from Zebra, if needed */
- if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+ if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("%s: deregistering this bgp %s instance from zebra",
+ __PRETTY_FUNCTION__, bgp->name);
bgp_zebra_instance_deregister(bgp);
+ }
/* Remove visibility via the master list - there may however still be
* routes to be processed still referencing the struct bgp.
QOBJ_UNREG(bgp);
- list_delete_and_null(&bgp->group);
- list_delete_and_null(&bgp->peer);
+ list_delete(&bgp->group);
+ list_delete(&bgp->peer);
if (bgp->peerhash) {
hash_free(bgp->peerhash);
vpn_policy_direction_t dir;
if (bgp->vpn_policy[afi].import_vrf)
- list_delete_and_null(&bgp->vpn_policy[afi].import_vrf);
+ list_delete(&bgp->vpn_policy[afi].import_vrf);
if (bgp->vpn_policy[afi].export_vrf)
- list_delete_and_null(&bgp->vpn_policy[afi].export_vrf);
+ list_delete(&bgp->vpn_policy[afi].export_vrf);
dir = BGP_VPN_POLICY_DIR_FROMVPN;
if (bgp->vpn_policy[afi].rtlist[dir])
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,
+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))
{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}};
return 0;
}
+ if (set && flag == PEER_FLAG_CAPABILITY_ENHE)
+ bgp_nht_register_enhe_capability_interfaces(peer);
+
/*
* Update peer-group members, unless they are explicitely overriding
* peer-group configuration.
/* Update flag on peer-group member. */
COND_FLAG(member->flags, flag, set != member_invert);
+ if (set && flag == PEER_FLAG_CAPABILITY_ENHE)
+ bgp_nht_register_enhe_capability_interfaces(member);
+
/* Execute flag action on peer-group member. */
if (action.type == peer_change_reset)
peer_flag_modify_action(member, flag);
{
int found;
int size;
- int addpath_tx_used;
bool invert, member_invert;
- struct bgp *bgp;
struct peer *member;
struct listnode *node, *nnode;
struct peer_flag_action action;
}
}
- /* 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_info(
- "%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,
- member)) {
- if (CHECK_FLAG(member->af_flags[afi][safi],
- PEER_FLAG_ADDPATH_TX_ALL_PATHS)
- || CHECK_FLAG(
- member->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_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
- const char *rmap)
+ const char *rmap, struct route_map *route_map)
{
struct peer *member;
struct listnode *node, *nnode;
peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
- peer->default_rmap[afi][safi].map =
- route_map_lookup_by_name(rmap);
+ peer->default_rmap[afi][safi].map = route_map;
}
} else if (!rmap) {
if (peer->default_rmap[afi][safi].name)
member->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
- member->default_rmap[afi][safi].map =
- route_map_lookup_by_name(rmap);
+ member->default_rmap[afi][safi].map = route_map;
}
/* Update peer route announcements. */
int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
- const char *name)
+ const char *name, struct route_map *route_map)
{
struct peer *member;
struct bgp_filter *filter;
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);
+ filter->map[direct].map = route_map;
/* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
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);
+ filter->map[direct].map = route_map;
/* Process peer route updates. */
peer_on_policy_change(member, afi, safi,
/* Set unsuppress-map to the peer. */
int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
- const char *name)
+ const char *name, struct route_map *route_map)
{
struct peer *member;
struct bgp_filter *filter;
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);
+ filter->usmap.map = route_map;
/* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
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);
+ filter->usmap.map = route_map;
/* Process peer route updates. */
peer_on_policy_change(member, afi, safi, 1);
int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi)
{
- struct peer *member;
- struct listnode *node, *nnode;
-
/* Inherit configuration from peer-group if peer is member. */
if (peer_group_active(peer)) {
peer_af_flag_inherit(peer, afi, safi, PEER_FLAG_MAX_PREFIX);
* Remove flags and configuration from all peer-group members, unless
* they are explicitely overriding peer-group configuration.
*/
- for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
- /* Skip peers with overridden configuration. */
- if (CHECK_FLAG(member->af_flags_override[afi][safi],
- PEER_FLAG_MAX_PREFIX))
- continue;
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ struct peer *member;
+ struct listnode *node;
- /* Remove flag and configuration on peer-group member. */
- UNSET_FLAG(member->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX);
- UNSET_FLAG(member->af_flags[afi][safi],
- PEER_FLAG_MAX_PREFIX_WARNING);
- member->pmax[afi][safi] = 0;
- member->pmax_threshold[afi][safi] = 0;
- member->pmax_restart[afi][safi] = 0;
+ for (ALL_LIST_ELEMENTS_RO(peer->group->peer, node, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->af_flags_override[afi][safi],
+ PEER_FLAG_MAX_PREFIX))
+ continue;
+
+ /* Remove flag and configuration on peer-group member.
+ */
+ UNSET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX);
+ UNSET_FLAG(member->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_WARNING);
+ member->pmax[afi][safi] = 0;
+ member->pmax_threshold[afi][safi] = 0;
+ member->pmax_restart[afi][safi] = 0;
+ }
}
return 0;
}
/* addpath TX knobs */
- if (peergroup_af_flag_check(peer, afi, safi,
- PEER_FLAG_ADDPATH_TX_ALL_PATHS)) {
- vty_out(vty, " neighbor %s addpath-tx-all-paths\n", addr);
- }
-
- if (peergroup_af_flag_check(peer, afi, safi,
- PEER_FLAG_ADDPATH_TX_BESTPATH_PER_AS)) {
- vty_out(vty, " neighbor %s addpath-tx-bestpath-per-AS\n",
- addr);
+ if (peergroup_af_addpath_check(peer, afi, safi)) {
+ switch (peer->addpath_type[afi][safi]) {
+ case BGP_ADDPATH_ALL:
+ vty_out(vty, " neighbor %s addpath-tx-all-paths\n",
+ addr);
+ break;
+ case BGP_ADDPATH_BEST_PER_AS:
+ vty_out(vty,
+ " neighbor %s addpath-tx-bestpath-per-AS\n",
+ addr);
+ break;
+ case BGP_ADDPATH_MAX:
+ case BGP_ADDPATH_NONE:
+ break;
+ }
}
/* ORF capability. */
frr_pthread_finish();
}
-void bgp_init(void)
+void bgp_init(unsigned short instance)
{
/* allocates some vital data structures used by peer commands in
bgp_pthreads_init();
/* Init zebra. */
- bgp_zebra_init(bm->master);
+ bgp_zebra_init(bm->master, instance);
#if ENABLE_BGP_VNC
vnc_zebra_init(bm->master);
bgp_close();
if (bm->listen_sockets)
- list_delete_and_null(&bm->listen_sockets);
+ list_delete(&bm->listen_sockets);
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp))
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))