bgpd: rework BFD integration

Remove old BFD API usage and replace it with the new one.

Highlights:

 - More shared code: the daemon gets notified with callbacks instead of
   having to roll its own code to find the notified sessions.

 - Less code to integrate with BFD.

 - Remove hidden commands to configure single / multi hop. Use
   protocol data instead.

   BGP can determine if a peer is single/multi hop according to the
   following criteria:

    a. If the IP address is a link-local address (single hop)

    b. The network is shared with peer (single hop)

    c. BGP is configured for eBGP multi hop / TTL security (multi hop)

 - Respect the configuration hierarchy:

    a. Peer configuration take precendence over peer-group
       configuration.

    b. When peer group configuration is removed, reset peer
       BFD configurations to defaults (unless peer had specific
       configs).

       Example:

         neighbor foo peer-group
         neighbor foo bfd profile X
         neighbor 192.168.0.2 peer-group foo
         neighbor 192.168.0.2 bfd
         ! If peer-group is removed the profile configuration gets
         ! removed from peer 192.168.0.2, but BFD will still enabled
         ! because of the neighbor specific bfd configuration.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
Rafael Zalamena 2021-02-26 16:50:51 -03:00
parent 50bd8995d4
commit 21bfce9827
7 changed files with 473 additions and 773 deletions

File diff suppressed because it is too large Load Diff

View File

@ -23,22 +23,55 @@
#ifndef _QUAGGA_BGP_BFD_H
#define _QUAGGA_BGP_BFD_H
extern void bgp_bfd_init(void);
#define PEER_IS_MULTIHOP(peer) \
((((peer)->sort == BGP_PEER_IBGP) && !(peer)->shared_network) \
|| is_ebgp_multihop_configured((peer)))
extern void bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer);
extern void bgp_bfd_init(struct thread_master *tm);
extern void bgp_bfd_register_peer(struct peer *peer);
extern void bgp_bfd_peer_config_write(struct vty *vty, const struct peer *peer,
const char *addr);
extern void bgp_bfd_deregister_peer(struct peer *peer);
extern void bgp_bfd_reset_peer(struct peer *peer);
extern void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer,
char *addr);
extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, bool use_json,
/**
* Show BFD information helper.
*
* \param vty the VTY pointer.
* \param peer the BGP configuration pointer.
* \param use_json unused.
* \param json_neigh JSON object when called as JSON command.
*/
extern void bgp_bfd_show_info(struct vty *vty, const struct peer *peer,
json_object *json_neigh);
extern bool bgp_bfd_is_peer_multihop(struct peer *peer);
/**
* When called on a group it applies configuration to all peers in that group,
* otherwise just applies the configuration to a single peer.
*
* This function should be called when configuration changes either on group
* or peer.
*
* \param p the BGP peer pointer.
* \param pg the BGP group to copy configuration from (it is usually
* `p->group` exception when copying new group configuration
* see `peer_group2peer_config_copy` function case).
*/
extern void bgp_peer_config_apply(struct peer *p, struct peer_group *pg);
/**
* Allocates and configure BFD session for peer. If it is already configured,
* then it does nothing.
*/
extern void bgp_peer_configure_bfd(struct peer *p, bool manual);
/**
* Removes BFD configuration from either peer or peer group.
*/
extern void bgp_peer_remove_bfd_config(struct peer *p);
/**
* Special function to handle the case of changing source address. This
* happens when the peer/group is configured with `neigbor X update-source Y`.
*/
extern void bgp_peer_bfd_update_source(struct peer *p);
#endif /* _QUAGGA_BGP_BFD_H */

View File

@ -1215,8 +1215,9 @@ int bgp_stop(struct peer *peer)
peer->nsf_af_count = 0;
/* deregister peer */
if (peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE)
bgp_bfd_deregister_peer(peer);
if (peer->bfd_config
&& peer->last_reset == PEER_DOWN_UPDATE_SOURCE_CHANGE)
bfd_sess_uninstall(peer->bfd_config->session);
if (peer_dynamic_neighbor(peer)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
@ -2122,7 +2123,10 @@ static int bgp_establish(struct peer *peer)
hash_release(peer->bgp->peerhash, peer);
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
bgp_bfd_reset_peer(peer);
/* Start BFD peer if not already running. */
if (peer->bfd_config)
bgp_peer_bfd_update_source(peer);
return ret;
}

View File

@ -162,6 +162,9 @@ __attribute__((__noreturn__)) void sigint(void)
assert(bm->terminating == false);
bm->terminating = true; /* global flag that shutting down */
/* Disable BFD events to avoid wasting processing. */
bfd_protocol_integration_set_shutdown(true);
bgp_terminate();
bgp_exit(0);

View File

@ -14411,7 +14411,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
vty_out(vty, "\n");
/* BFD information. */
bgp_bfd_show_info(vty, p, use_json, json_neigh);
if (p->bfd_config)
bgp_bfd_show_info(vty, p, json_neigh);
if (use_json) {
if (p->conf_if) /* Configured interface name. */
@ -16818,11 +16819,8 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
peer->rtt_expected, peer->rtt_keepalive_conf);
/* bfd */
if (peer->bfd_info) {
if (!peer_group_active(peer) || !g_peer->bfd_info) {
bgp_bfd_peer_config_write(vty, peer, addr);
}
}
if (peer->bfd_config)
bgp_bfd_peer_config_write(vty, peer, addr);
/* password */
if (peergroup_flag_check(peer, PEER_FLAG_PASSWORD))

View File

@ -1161,7 +1161,9 @@ static void peer_free(struct peer *peer)
XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
bfd_info_free(&(peer->bfd_info));
/* Remove BFD configuration. */
if (peer->bfd_config)
bgp_peer_remove_bfd_config(peer);
FOREACH_AFI_SAFI (afi, safi)
bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE);
@ -2394,7 +2396,9 @@ int peer_delete(struct peer *peer)
SET_FLAG(peer->flags, PEER_FLAG_DELETE);
bgp_bfd_deregister_peer(peer);
/* Remove BFD settings. */
if (peer->bfd_config)
bgp_peer_remove_bfd_config(peer);
/* Delete peer route flap dampening configuration. This needs to happen
* before removing the peer from peer groups.
@ -2678,7 +2682,11 @@ static void peer_group2peer_config_copy(struct peer_group *group,
/* Update GR flags for the peer. */
bgp_peer_gr_flags_update(peer);
bgp_bfd_peer_group2peer_copy(conf, peer);
/* Apply BFD settings from group to peer if it exists. */
if (conf->bfd_config) {
bgp_peer_configure_bfd(peer, false);
bgp_peer_config_apply(peer, group);
}
}
/* Peer group's remote AS configuration. */
@ -2768,7 +2776,8 @@ int peer_group_delete(struct peer_group *group)
XFREE(MTYPE_PEER_GROUP_HOST, group->name);
group->name = NULL;
bfd_info_free(&(group->conf->bfd_info));
if (group->conf->bfd_config)
bgp_peer_remove_bfd_config(group->conf);
group->conf->group = NULL;
peer_delete(group->conf);
@ -7700,7 +7709,7 @@ void bgp_init(unsigned short instance)
bgp_clist = community_list_init();
/* BFD init */
bgp_bfd_init();
bgp_bfd_init(bm->master);
bgp_lp_vty_init();

View File

@ -45,6 +45,8 @@
#include "bgp_nexthop.h"
#include "bgp_damp.h"
#include "lib/bfd.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
@ -1558,8 +1560,29 @@ struct peer {
#define PEER_RMAP_TYPE_EXPORT (1U << 7) /* neighbor route-map export */
#define PEER_RMAP_TYPE_AGGREGATE (1U << 8) /* aggregate-address route-map */
/* peer specific BFD information */
struct bfd_info *bfd_info;
/** Peer overwrite configuration. */
struct bfd_session_config {
/**
* Manual configuration bit.
*
* This flag only makes sense for real peers (and not groups),
* it keeps track if the user explicitly configured BFD for a
* peer.
*/
bool manual;
/** Control Plane Independent. */
bool cbit;
/** Detection multiplier. */
uint8_t detection_multiplier;
/** Minimum required RX interval. */
uint32_t min_rx;
/** Minimum required TX interval. */
uint32_t min_tx;
/** Profile name. */
char profile[BFD_PROFILE_NAME_LEN];
/** Peer BFD session */
struct bfd_session_params *session;
} * bfd_config;
/* hostname and domainname advertised by host */
char *hostname;