diff options
Diffstat (limited to 'bgpd/bgp_updgrp.h')
-rw-r--r-- | bgpd/bgp_updgrp.h | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h new file mode 100644 index 0000000..0d866f3 --- /dev/null +++ b/bgpd/bgp_updgrp.h @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** + * bgp_updgrp.c: BGP update group structures + * + * @copyright Copyright (C) 2014 Cumulus Networks, Inc. + * + * @author Avneesh Sachdev <avneesh@sproute.net> + * @author Rajesh Varadarajan <rajesh@sproute.net> + * @author Pradosh Mohapatra <pradosh@sproute.net> + */ + +#ifndef _QUAGGA_BGP_UPDGRP_H +#define _QUAGGA_BGP_UPDGRP_H + +#include "bgp_advertise.h" + +/* + * The following three heuristic constants determine how long advertisement to + * a subgroup will be delayed after it is created. The intent is to allow + * transient changes in peer state (primarily session establishment) to settle, + * so that more peers can be grouped together and benefit from sharing + * advertisement computations with the subgroup. + * + * These values have a very large impact on initial convergence time; any + * changes should be accompanied by careful performance testing at all scales. + * + * The coalesce time 'C' for a new subgroup within a particular BGP instance + * 'B' with total number of known peers 'P', established or not, is computed as + * follows: + * + * C = MIN(BGP_MAX_SUBGROUP_COALESCE_TIME, + * BGP_DEFAULT_SUBGROUP_COALESCE_TIME + + * (P*BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME)) + */ +#define BGP_DEFAULT_SUBGROUP_COALESCE_TIME 1000 +#define BGP_MAX_SUBGROUP_COALESCE_TIME 10000 +#define BGP_PEER_ADJUST_SUBGROUP_COALESCE_TIME 50 + +#define PEER_UPDGRP_FLAGS \ + (PEER_FLAG_LOCAL_AS_NO_PREPEND | PEER_FLAG_LOCAL_AS_REPLACE_AS) + +#define PEER_UPDGRP_AF_FLAGS \ + (PEER_FLAG_SEND_COMMUNITY | PEER_FLAG_SEND_EXT_COMMUNITY \ + | PEER_FLAG_SEND_LARGE_COMMUNITY \ + | PEER_FLAG_DEFAULT_ORIGINATE | PEER_FLAG_REFLECTOR_CLIENT \ + | PEER_FLAG_RSERVER_CLIENT | PEER_FLAG_NEXTHOP_SELF \ + | PEER_FLAG_NEXTHOP_UNCHANGED | PEER_FLAG_FORCE_NEXTHOP_SELF \ + | PEER_FLAG_AS_PATH_UNCHANGED | PEER_FLAG_MED_UNCHANGED \ + | PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED | PEER_FLAG_REMOVE_PRIVATE_AS \ + | PEER_FLAG_REMOVE_PRIVATE_AS_ALL \ + | PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE \ + | PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE \ + | PEER_FLAG_AS_OVERRIDE) + +#define PEER_UPDGRP_CAP_FLAGS (PEER_CAP_AS4_RCV) + +#define PEER_UPDGRP_AF_CAP_FLAGS \ + (PEER_CAP_ORF_PREFIX_SM_RCV | PEER_CAP_ADDPATH_AF_TX_ADV | \ + PEER_CAP_ADDPATH_AF_RX_RCV | PEER_CAP_ENHE_AF_NEGO) + +enum bpacket_attr_vec_type { BGP_ATTR_VEC_NH = 0, BGP_ATTR_VEC_MAX }; + +typedef struct { + uint32_t flags; + unsigned long offset; +} bpacket_attr_vec; + +#define BPKT_ATTRVEC_FLAGS_UPDATED (1 << 0) +#define BPKT_ATTRVEC_FLAGS_RMAP_NH_PEER_ADDRESS (1 << 1) +#define BPKT_ATTRVEC_FLAGS_REFLECTED (1 << 2) +#define BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED (1 << 3) +#define BPKT_ATTRVEC_FLAGS_RMAP_IPV4_NH_CHANGED (1 << 4) +#define BPKT_ATTRVEC_FLAGS_RMAP_IPV6_GNH_CHANGED (1 << 5) +#define BPKT_ATTRVEC_FLAGS_RMAP_IPV6_LNH_CHANGED (1 << 6) +#define BPKT_ATTRVEC_FLAGS_RMAP_VPNV4_NH_CHANGED (1 << 7) +#define BPKT_ATTRVEC_FLAGS_RMAP_VPNV6_GNH_CHANGED (1 << 8) + +typedef struct bpacket_attr_vec_arr { + bpacket_attr_vec entries[BGP_ATTR_VEC_MAX]; +} bpacket_attr_vec_arr; + +struct bpacket { + /* for being part of an update subgroup's message list */ + TAILQ_ENTRY(bpacket) pkt_train; + + /* list of peers (well, peer_afs) that the packet needs to be sent to */ + LIST_HEAD(pkt_peer_list, peer_af) peers; + + struct stream *buffer; + bpacket_attr_vec_arr arr; + + unsigned int ver; +}; + +struct bpacket_queue { + TAILQ_HEAD(pkt_queue, bpacket) pkts; + + unsigned int conf_max_count; + unsigned int curr_count; + unsigned int hwm_count; + unsigned int max_count_reached_count; +}; + +struct update_group { + /* back pointer to the BGP instance */ + struct bgp *bgp; + + /* list of subgroups that belong to the update group */ + LIST_HEAD(subgrp_list, update_subgroup) subgrps; + + /* lazy way to store configuration common to all peers + hash function will compute from this data */ + struct peer *conf; + + afi_t afi; + safi_t safi; + int afid; + + uint64_t id; + time_t uptime; + + uint32_t join_events; + uint32_t prune_events; + uint32_t merge_events; + uint32_t updgrp_switch_events; + uint32_t peer_refreshes_combined; + uint32_t adj_count; + uint32_t split_events; + uint32_t merge_checks_triggered; + + uint32_t subgrps_created; + uint32_t subgrps_deleted; + + uint32_t num_dbg_en_peers; +}; + +/* + * Shorthand for a global statistics counter. + */ +#define UPDGRP_GLOBAL_STAT(updgrp, stat) \ + ((updgrp)->bgp->update_group_stats.stat) + +/* + * Add the given value to a counter on an update group and the bgp + * instance. + */ +#define UPDGRP_INCR_STAT_BY(updgrp, stat, value) \ + do { \ + (updgrp)->stat += (value); \ + UPDGRP_GLOBAL_STAT(updgrp, stat) += (value); \ + } while (0) + +/* + * Increment a counter on a update group and its parent structures. + */ +#define UPDGRP_INCR_STAT(subgrp, stat) UPDGRP_INCR_STAT_BY(subgrp, stat, 1) + +struct update_subgroup { + /* back pointer to the parent update group */ + struct update_group *update_group; + + /* list of peers that belong to the subgroup */ + LIST_HEAD(peer_list, peer_af) peers; + int peer_count; + + /* for being part of an update group's subgroup list */ + LIST_ENTRY(update_subgroup) updgrp_train; + + struct bpacket_queue pkt_queue; + + /* + * List of adj-out structures for this subgroup. + * It essentially represents the snapshot of every prefix that + * has been advertised to the members of the subgroup + */ + TAILQ_HEAD(adjout_queue, bgp_adj_out) adjq; + + /* packet buffer for update generation */ + struct stream *work; + + /* We use a separate stream to encode MP_REACH_NLRI for efficient + * NLRI packing. peer->obuf_work stores all the other attributes. The + * actual packet is then constructed by concatenating the two. + */ + struct stream *scratch; + + /* synchronization list and time */ + struct bgp_synchronize *sync; + + /* send prefix count */ + uint32_t scount; + + /* send prefix count prior to packet update */ + uint32_t pscount; + + /* announcement attribute hash */ + struct hash *hash; + + struct event *t_coalesce; + uint32_t v_coalesce; + + struct event *t_merge_check; + + /* table version that the subgroup has caught up to. */ + uint64_t version; + + /* version maintained to record adj changes */ + uint64_t adj_version; + + time_t uptime; + + /* + * Identifying information about the subgroup that this subgroup was + * split + * from, if any. + */ + struct { + uint64_t update_group_id; + uint64_t subgroup_id; + } split_from; + + uint32_t join_events; + uint32_t prune_events; + + /* + * This is bumped up when another subgroup merges into this one. + */ + uint32_t merge_events; + uint32_t updgrp_switch_events; + uint32_t peer_refreshes_combined; + uint32_t adj_count; + uint32_t split_events; + uint32_t merge_checks_triggered; + + uint64_t id; + + uint16_t sflags; +#define SUBGRP_STATUS_DEFAULT_ORIGINATE (1 << 0) +#define SUBGRP_STATUS_FORCE_UPDATES (1 << 1) +#define SUBGRP_STATUS_TABLE_REPARSING (1 << 2) +/* + * This flag has been added to ensure that the SNT counters + * gets incremented and decremented only during the creation + * and deletion workflows of default originate, + * not during the update workflow. + */ +#define SUBGRP_STATUS_PEER_DEFAULT_ORIGINATED (1 << 3) + + uint16_t flags; +#define SUBGRP_FLAG_NEEDS_REFRESH (1 << 0) +}; + +/* + * Add the given value to the specified counter on a subgroup and its + * parent structures. + */ +#define SUBGRP_INCR_STAT_BY(subgrp, stat, value) \ + do { \ + (subgrp)->stat += (value); \ + if ((subgrp)->update_group) \ + UPDGRP_INCR_STAT_BY((subgrp)->update_group, stat, \ + value); \ + } while (0) + +/* + * Increment a counter on a subgroup and its parent structures. + */ +#define SUBGRP_INCR_STAT(subgrp, stat) SUBGRP_INCR_STAT_BY(subgrp, stat, 1) + +/* + * Decrement a counter on a subgroup and its parent structures. + */ +#define SUBGRP_DECR_STAT(subgrp, stat) SUBGRP_INCR_STAT_BY(subgrp, stat, -1) + +typedef int (*updgrp_walkcb)(struct update_group *updgrp, void *ctx); + +/* really a private structure */ +struct updwalk_context { + struct vty *vty; + struct bgp_dest *dest; + struct bgp_path_info *pi; + uint64_t updgrp_id; + uint64_t subgrp_id; + enum bgp_policy_type policy_type; + const char *policy_name; + int policy_event_start_flag; + bool policy_route_update; + updgrp_walkcb cb; + void *context; + uint8_t flags; + bool uj; + json_object *json_updategrps; + +#define UPDWALK_FLAGS_ADVQUEUE (1 << 0) +#define UPDWALK_FLAGS_ADVERTISED (1 << 1) +}; + +#define UPDWALK_CONTINUE HASHWALK_CONTINUE +#define UPDWALK_ABORT HASHWALK_ABORT + +#define PAF_PEER(p) ((p)->peer) +#define PAF_SUBGRP(p) ((p)->subgroup) +#define PAF_UPDGRP(p) ((p)->subgroup->update_group) +#define PAF_PKTQ(f) SUBGRP_PKTQ((f)->subgroup) + +#define UPDGRP_PEER(u) ((u)->conf) +#define UPDGRP_AFI(u) ((u)->afi) +#define UPDGRP_SAFI(u) ((u)->safi) +#define UPDGRP_INST(u) ((u)->bgp) +#define UPDGRP_AFFLAGS(u) ((u)->conf->af_flags[UPDGRP_AFI(u)][UPDGRP_SAFI(u)]) +#define UPDGRP_DBG_ON(u) ((u)->num_dbg_en_peers) +#define UPDGRP_PEER_DBG_EN(u) (((u)->num_dbg_en_peers)++) +#define UPDGRP_PEER_DBG_DIS(u) (((u)->num_dbg_en_peers)--) +#define UPDGRP_PEER_DBG_OFF(u) (u)->num_dbg_en_peers = 0 + +#define SUBGRP_AFI(s) UPDGRP_AFI((s)->update_group) +#define SUBGRP_SAFI(s) UPDGRP_SAFI((s)->update_group) +#define SUBGRP_PEER(s) UPDGRP_PEER((s)->update_group) +#define SUBGRP_PCOUNT(s) ((s)->peer_count) +#define SUBGRP_PFIRST(s) LIST_FIRST(&((s)->peers)) +#define SUBGRP_PKTQ(s) &((s)->pkt_queue) +#define SUBGRP_INST(s) UPDGRP_INST((s)->update_group) +#define SUBGRP_AFFLAGS(s) UPDGRP_AFFLAGS((s)->update_group) +#define SUBGRP_UPDGRP(s) ((s)->update_group) + +/* + * Walk all subgroups in an update group. + */ +#define UPDGRP_FOREACH_SUBGRP(updgrp, subgrp) \ + LIST_FOREACH (subgrp, &((updgrp)->subgrps), updgrp_train) + +#define UPDGRP_FOREACH_SUBGRP_SAFE(updgrp, subgrp, tmp_subgrp) \ + LIST_FOREACH_SAFE (subgrp, &((updgrp)->subgrps), updgrp_train, \ + tmp_subgrp) + +#define SUBGRP_FOREACH_PEER(subgrp, paf) \ + LIST_FOREACH (paf, &(subgrp->peers), subgrp_train) + +#define SUBGRP_FOREACH_PEER_SAFE(subgrp, paf, temp_paf) \ + LIST_FOREACH_SAFE (paf, &(subgrp->peers), subgrp_train, temp_paf) + +#define SUBGRP_FOREACH_ADJ(subgrp, adj) \ + TAILQ_FOREACH (adj, &(subgrp->adjq), subgrp_adj_train) + +#define SUBGRP_FOREACH_ADJ_SAFE(subgrp, adj, adj_temp) \ + TAILQ_FOREACH_SAFE (adj, &(subgrp->adjq), subgrp_adj_train, adj_temp) + +/* Prototypes. */ +/* bgp_updgrp.c */ +extern void update_bgp_group_init(struct bgp *); +extern void udpate_bgp_group_free(struct bgp *); + +extern void update_group_show(struct bgp *bgp, afi_t afi, safi_t safi, + struct vty *vty, uint64_t subgrp_id, bool uj); +extern void update_group_show_stats(struct bgp *bgp, struct vty *vty); +extern void update_group_adjust_peer(struct peer_af *paf); +extern int update_group_adjust_soloness(struct peer *peer, int set); + +extern void update_subgroup_remove_peer(struct update_subgroup *, + struct peer_af *); +extern struct bgp_table *update_subgroup_rib(struct update_subgroup *); +extern void update_subgroup_split_peer(struct peer_af *, struct update_group *); +extern bool update_subgroup_check_merge(struct update_subgroup *, const char *); +extern bool update_subgroup_trigger_merge_check(struct update_subgroup *, + int force); +extern void update_group_policy_update(struct bgp *bgp, + enum bgp_policy_type ptype, + const char *pname, bool route_update, + int start_event); +extern void update_group_af_walk(struct bgp *bgp, afi_t afi, safi_t safi, + updgrp_walkcb cb, void *ctx); +extern void update_group_walk(struct bgp *bgp, updgrp_walkcb cb, void *ctx); +extern void update_group_periodic_merge(struct bgp *bgp); +extern void +update_group_refresh_default_originate_route_map(struct event *thread); +extern void update_group_start_advtimer(struct bgp *bgp); + +extern void update_subgroup_inherit_info(struct update_subgroup *to, + struct update_subgroup *from); + +/* bgp_updgrp_packet.c */ +extern struct bpacket *bpacket_alloc(void); +extern void bpacket_free(struct bpacket *pkt); +extern void bpacket_queue_init(struct bpacket_queue *q); +extern void bpacket_queue_cleanup(struct bpacket_queue *q); +extern void bpacket_queue_sanity_check(struct bpacket_queue *q); +extern struct bpacket *bpacket_queue_add(struct bpacket_queue *q, + struct stream *s, + struct bpacket_attr_vec_arr *vecarr); +struct bpacket *bpacket_queue_remove(struct bpacket_queue *q); +extern struct bpacket *bpacket_queue_first(struct bpacket_queue *q); +struct bpacket *bpacket_queue_last(struct bpacket_queue *q); +unsigned int bpacket_queue_length(struct bpacket_queue *q); +unsigned int bpacket_queue_hwm_length(struct bpacket_queue *q); +bool bpacket_queue_is_full(struct bgp *bgp, struct bpacket_queue *q); +extern void bpacket_queue_advance_peer(struct peer_af *paf); +extern void bpacket_queue_remove_peer(struct peer_af *paf); +extern void bpacket_add_peer(struct bpacket *pkt, struct peer_af *paf); +unsigned int bpacket_queue_virtual_length(struct peer_af *paf); +extern void bpacket_queue_show_vty(struct bpacket_queue *q, struct vty *vty); +bool subgroup_packets_to_build(struct update_subgroup *subgrp); +extern struct bpacket *subgroup_update_packet(struct update_subgroup *s); +extern struct bpacket *subgroup_withdraw_packet(struct update_subgroup *s); +extern struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, + struct peer_af *paf); +extern void bpacket_attr_vec_arr_reset(struct bpacket_attr_vec_arr *vecarr); +extern void bpacket_attr_vec_arr_set_vec(struct bpacket_attr_vec_arr *vecarr, + enum bpacket_attr_vec_type type, + struct stream *s, struct attr *attr); +extern void subgroup_default_update_packet(struct update_subgroup *subgrp, + struct attr *attr, + struct peer *from); +extern void subgroup_default_withdraw_packet(struct update_subgroup *subgrp); + +/* bgp_updgrp_adv.c */ +extern struct bgp_advertise * +bgp_advertise_clean_subgroup(struct update_subgroup *subgrp, + struct bgp_adj_out *adj); +extern void update_group_show_adj_queue(struct bgp *bgp, afi_t afi, safi_t safi, + struct vty *vty, uint64_t id); +extern void update_group_show_advertised(struct bgp *bgp, afi_t afi, + safi_t safi, struct vty *vty, + uint64_t id); +extern void update_group_show_packet_queue(struct bgp *bgp, afi_t afi, + safi_t safi, struct vty *vty, + uint64_t id); +extern void subgroup_announce_route(struct update_subgroup *subgrp); +extern void subgroup_announce_all(struct update_subgroup *subgrp); + +extern void subgroup_default_originate(struct update_subgroup *subgrp, + int withdraw); +extern void group_announce_route(struct bgp *bgp, afi_t afi, safi_t safi, + struct bgp_dest *dest, + struct bgp_path_info *pi); +extern void subgroup_clear_table(struct update_subgroup *subgrp); +extern void update_group_announce(struct bgp *bgp); +extern void update_group_announce_rrclients(struct bgp *bgp); +extern void peer_af_announce_route(struct peer_af *paf, int combine); +extern struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp, + struct bgp_dest *dest, + uint32_t addpath_tx_id); +extern void bgp_adj_out_remove_subgroup(struct bgp_dest *dest, + struct bgp_adj_out *adj, + struct update_subgroup *subgrp); +extern void bgp_adj_out_set_subgroup(struct bgp_dest *dest, + struct update_subgroup *subgrp, + struct attr *attr, + struct bgp_path_info *path); +extern void bgp_adj_out_unset_subgroup(struct bgp_dest *dest, + struct update_subgroup *subgrp, + char withdraw, uint32_t addpath_tx_id); +void subgroup_announce_table(struct update_subgroup *subgrp, + struct bgp_table *table); +extern void subgroup_trigger_write(struct update_subgroup *subgrp); + +extern int update_group_clear_update_dbg(struct update_group *updgrp, + void *arg); + +extern void update_bgp_group_free(struct bgp *bgp); +extern bool bgp_addpath_encode_tx(struct peer *peer, afi_t afi, safi_t safi); +extern bool bgp_check_selected(struct bgp_path_info *bpi, struct peer *peer, + bool addpath_capable, afi_t afi, safi_t safi); +extern bool bgp_addpath_capable(struct bgp_path_info *bpi, struct peer *peer, + afi_t afi, safi_t safi); + +/* + * Inline functions + */ + +/* + * bpacket_queue_is_empty + */ +static inline int bpacket_queue_is_empty(struct bpacket_queue *queue) +{ + + /* + * The packet queue is empty if it only contains a sentinel. + */ + if (queue->curr_count != 1) + return 0; + + assert(bpacket_queue_first(queue)->buffer == NULL); + return 1; +} + +/* + * bpacket_next + * + * Returns the packet after the given packet in a bpacket queue. + */ +static inline struct bpacket *bpacket_next(struct bpacket *pkt) +{ + return TAILQ_NEXT(pkt, pkt_train); +} + +/* + * update_group_adjust_peer_afs + * + * Adjust all peer_af structures for the given peer. + */ +static inline void update_group_adjust_peer_afs(struct peer *peer) +{ + struct peer_af *paf; + int afidx; + + for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { + paf = peer->peer_af_array[afidx]; + if (paf != NULL) + update_group_adjust_peer(paf); + } +} + +/* + * update_group_remove_peer_afs + * + * Remove all peer_af structures for the given peer from their subgroups. + */ +static inline void update_group_remove_peer_afs(struct peer *peer) +{ + struct peer_af *paf; + int afidx; + + for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { + paf = peer->peer_af_array[afidx]; + if (paf != NULL) + update_subgroup_remove_peer(PAF_SUBGRP(paf), paf); + } +} + +/* + * update_subgroup_needs_refresh + */ +static inline int +update_subgroup_needs_refresh(const struct update_subgroup *subgrp) +{ + if (CHECK_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH)) + return 1; + else + return 0; +} + +/* + * update_subgroup_set_needs_refresh + */ +static inline void +update_subgroup_set_needs_refresh(struct update_subgroup *subgrp, int value) +{ + if (value) + SET_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH); + else + UNSET_FLAG(subgrp->flags, SUBGRP_FLAG_NEEDS_REFRESH); +} + +static inline struct update_subgroup *peer_subgroup(struct peer *peer, + afi_t afi, safi_t safi) +{ + struct peer_af *paf; + + paf = peer_af_find(peer, afi, safi); + if (paf) + return PAF_SUBGRP(paf); + return NULL; +} + +/* + * update_group_adjust_peer_afs + * + * Adjust all peer_af structures for the given peer. + */ +static inline void bgp_announce_peer(struct peer *peer) +{ + struct peer_af *paf; + int afidx; + + for (afidx = BGP_AF_START; afidx < BGP_AF_MAX; afidx++) { + paf = peer->peer_af_array[afidx]; + if (paf != NULL) + subgroup_announce_all(PAF_SUBGRP(paf)); + } +} + +/** + * advertise_list_is_empty + */ +static inline int advertise_list_is_empty(struct update_subgroup *subgrp) +{ + if (bgp_adv_fifo_count(&subgrp->sync->update) || + bgp_adv_fifo_count(&subgrp->sync->withdraw)) + return 0; + + return 1; +} + +#endif /* _QUAGGA_BGP_UPDGRP_H */ |