Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 107 additions & 1 deletion bgpd/bgp_evpn.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "zclient.h"

#include "lib/printfrr.h"
#include "libfrr.h"

#include "bgpd/bgp_attr_evpn.h"
#include "bgpd/bgpd.h"
Expand All @@ -42,6 +43,7 @@
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_mpath.h"
#include "bgpd/bgp_packet.h"
#include "bitfield.h"

/*
* Definitions and external declarations.
Expand All @@ -55,6 +57,7 @@ DEFINE_MTYPE_STATIC(BGPD, VRF_ROUTE_TARGET, "L3 Route Target");
/*
* Static function declarations
*/
static void bgp_evpn_log_vni_rd_to_statefile(uint32_t vni, uint16_t rd_id);
static void bgp_evpn_remote_ip_hash_init(struct bgpevpn *evpn);
static void bgp_evpn_remote_ip_hash_destroy(struct bgpevpn *evpn);
static void bgp_evpn_remote_ip_hash_add(struct bgpevpn *vpn,
Expand Down Expand Up @@ -103,6 +106,90 @@ static const char *vxlan_flood_control_str(enum vxlan_flood_control flood_ctrl)
}
}


/* Ensure vpn->rd_id is restored from cache or allocated and persisted */
static void bgp_evpn_assign_rd_id_for_vni(struct bgp *bgp, struct bgpevpn *vpn)
{
struct vni_rd_state_entry key = { .vni = vpn->vni, .rd_id = 0 };
struct vni_rd_state_entry *found;

found = vni_rd_state_hash_find(&bm->vni_rd_state, &key);
if (found) {
vpn->rd_id = found->rd_id;
found->used = true;
if (!bf_test_index(bm->rd_idspace, vpn->rd_id))
bf_set_bit(bm->rd_idspace, vpn->rd_id);
return;
}

{
struct vni_rd_state_entry *entry;

bf_assign_index(bm->rd_idspace, vpn->rd_id);
bgp_evpn_log_vni_rd_to_statefile(vpn->vni, vpn->rd_id);

entry = XCALLOC(MTYPE_BGP_RD_STATE, sizeof(*entry));
entry->vni = vpn->vni;
entry->rd_id = vpn->rd_id;
entry->used = true;
vni_rd_state_hash_add(&bm->vni_rd_state, entry);
}
}

/*
* Append a single line with L2 VNI and RD-ID info to a file in frr_libstatedir.
* Line format: "<vni> <rd_id>\n".
*/
static void bgp_evpn_log_vni_rd_to_statefile(uint32_t vni, uint16_t rd_id)
{
char path[512];
FILE *fp;

snprintf(path, sizeof(path), "%s/%s", frr_libstatedir, BGP_EVPN_VNI_RD_STATEFILE);

fp = fopen(path, "a");
if (!fp) {
zlog_err("EVPN: failed to open %s for append: %s", path, safe_strerror(errno));
return;
}

fprintf(fp, "%u %hu\n", vni, rd_id);
fclose(fp);
}

/*
* Rewrite VNI RD state file from in-memory hash.
*/
void bgp_evpn_rewrite_vni_rd_statefile(void)
{
char path[512];
char tmp[512];
FILE *fp;
struct vni_rd_state_entry *entry;

snprintf(path, sizeof(path), "%s/%s", frr_libstatedir, BGP_EVPN_VNI_RD_STATEFILE);
snprintf(tmp, sizeof(tmp), "%s/%s.tmp", frr_libstatedir, BGP_EVPN_VNI_RD_STATEFILE);

fp = fopen(tmp, "w");
if (!fp) {
zlog_err("EVPN: failed to open %s for writing: %s", tmp, safe_strerror(errno));
return;
}

frr_each (vni_rd_state_hash, &bm->vni_rd_state, entry)
fprintf(fp, "%u %hu\n", entry->vni, entry->rd_id);

if (fclose(fp) != 0) {
remove(tmp);
return;
}

if (rename(tmp, path) != 0) {
zlog_err("EVPN: failed to replace %s: %s", path, safe_strerror(errno));
remove(tmp);
}
}

/*
* Private functions.
*/
Expand Down Expand Up @@ -6721,7 +6808,8 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni,
vpn->export_rtl->cmp =
(int (*)(void *, void *))bgp_evpn_route_target_cmp;
vpn->export_rtl->del = bgp_evpn_xxport_delete_ecomm;
bf_assign_index(bm->rd_idspace, vpn->rd_id);
/* Restore or allocate RD-ID for this VNI */
bgp_evpn_assign_rd_id_for_vni(bgp, vpn);
derive_rd_rt_for_vni(bgp, vpn);

/* Initialize EVPN route tables. */
Expand Down Expand Up @@ -6759,6 +6847,24 @@ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn)
bgp_evpn_unmap_vni_from_its_rts(bgp, vpn);
list_delete(&vpn->import_rtl);
list_delete(&vpn->export_rtl);
/*
* Remove this VNI's entry from cache; rewrite file only on normal
* deletion. TODO: batch the rewrite when multiple VNIs are deleted
* in one pass (e.g. no advertise-all-vni) to avoid O(n) full
* file rewrites.
*/
{
struct vni_rd_state_entry key = { .vni = vpn->vni, .rd_id = 0 };
struct vni_rd_state_entry *found;

found = vni_rd_state_hash_find(&bm->vni_rd_state, &key);
if (found) {
vni_rd_state_hash_del(&bm->vni_rd_state, found);
XFREE(MTYPE_BGP_RD_STATE, found);
}
}
if (!bm->terminating)
bgp_evpn_rewrite_vni_rd_statefile();
bf_release_index(bm->rd_idspace, vpn->rd_id);
hash_release(bgp->vni_svi_hash, vpn);
hash_release(bgp->vnihash, vpn);
Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_evpn.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ static inline bool evpn_resolve_overlay_index(void)
return bgp ? bgp->resolve_overlay_index : false;
}

extern void bgp_evpn_rewrite_vni_rd_statefile(void);
extern void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_path_info *originator,
const struct prefix *p, struct attr *src_attr,
afi_t afi, safi_t safi, uint32_t addpath_id);
Expand Down
16 changes: 16 additions & 0 deletions bgpd/bgp_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,22 @@ static FRR_NORETURN void bgp_exit(int status)
bgp_zebra_destroy();

bf_free(bm->rd_idspace);
{
struct vrf_rd_state_entry *ve;

while ((ve = vrf_rd_state_hash_pop(&bm->vrf_rd_state))) {
XFREE(MTYPE_BGP_NAME, ve->name);
XFREE(MTYPE_BGP_RD_STATE, ve);
}
vrf_rd_state_hash_fini(&bm->vrf_rd_state);
}
{
struct vni_rd_state_entry *ne;

while ((ne = vni_rd_state_hash_pop(&bm->vni_rd_state)))
XFREE(MTYPE_BGP_RD_STATE, ne);
vni_rd_state_hash_fini(&bm->vni_rd_state);
}
list_delete(&bm->bgp);
list_delete(&bm->addresses);

Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

DEFINE_MGROUP(BGPD, "bgpd");
DEFINE_MTYPE(BGPD, BGP, "BGP instance");
DEFINE_MTYPE(BGPD, BGP_RD_STATE, "BGP RD state entry");
DEFINE_MTYPE(BGPD, BGP_NAME, "BGP Name data");
DEFINE_MTYPE(BGPD, BGP_LISTENER, "BGP listen socket details");
DEFINE_MTYPE(BGPD, BGP_PEER, "BGP peer");
Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

DECLARE_MGROUP(BGPD);
DECLARE_MTYPE(BGP);
DECLARE_MTYPE(BGP_RD_STATE);
DECLARE_MTYPE(BGP_NAME);
DECLARE_MTYPE(BGP_LISTENER);
DECLARE_MTYPE(BGP_PEER);
Expand Down
Loading
Loading