Installation & Use
------------------
-Packages are available for various distributions on our
+For source tarballs, see the
[releases page](https://github.com/FRRouting/frr/releases).
-Snaps are also available [here](https://snapcraft.io/frr).
+For Debian and its derivatives, use the APT repository at
+[https://deb.frrouting.org/](https://deb.frrouting.org/).
Instructions on building and installing from source for supported platforms may
-be found
-[here](http://docs.frrouting.org/projects/dev-guide/en/latest/building.html).
+be found in the
+[developer docs](http://docs.frrouting.org/projects/dev-guide/en/latest/building.html).
Once installed, please refer to the [user guide](http://docs.frrouting.org/)
for instructions on use.
/* Search for session without using discriminator. */
ifp = if_lookup_by_index(ifindex, vrfid);
- if (vrfid != VRF_DEFAULT)
- vrf = vrf_lookup_by_id(vrfid);
- else
- vrf = NULL;
+
+ vrf = vrf_lookup_by_id(vrfid);
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
vrf ? vrf->name : VRF_DEFAULT_NAME);
return 0;
}
+static int bfd_vrf_update(struct vrf *vrf)
+{
+ if (!vrf_is_enabled(vrf))
+ return 0;
+ log_debug("VRF update: %s(%u)", vrf->name, vrf->vrf_id);
+ /* a different name is given; update bfd list */
+ bfdd_sessions_enable_vrf(vrf);
+ return 0;
+}
+
static int bfd_vrf_enable(struct vrf *vrf)
{
struct bfd_vrf_global *bvrf;
void bfd_vrf_init(void)
{
vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable,
- bfd_vrf_delete, NULL);
+ bfd_vrf_delete, bfd_vrf_update);
}
void bfd_vrf_terminate(void)
return NULL;
return bfd->vrf->info;
}
+
+void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf)
+{
+ if (!vrf || !bs)
+ return;
+ /* update key */
+ hash_release(bfd_key_hash, bs);
+ /*
+ * HACK: Change the BFD VRF in the running configuration directly,
+ * bypassing the northbound layer. This is necessary to avoid deleting
+ * the BFD and readding it in the new VRF, which would have
+ * several implications.
+ */
+ if (yang_module_find("frr-bfdd") && bs->key.vrfname[0]) {
+ struct lyd_node *bfd_dnode;
+ char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32];
+ char addr_buf[INET6_ADDRSTRLEN];
+ int slen;
+
+ /* build xpath */
+ if (bs->key.mhop) {
+ inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf));
+ snprintf(xpath_srcaddr, sizeof(xpath_srcaddr), "[source-addr='%s']",
+ addr_buf);
+ } else
+ xpath_srcaddr[0] = 0;
+ inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf));
+ slen = snprintf(xpath, sizeof(xpath),
+ "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']",
+ bs->key.mhop ? "multi-hop" : "single-hop", xpath_srcaddr,
+ addr_buf);
+ if (bs->key.ifname[0])
+ slen += snprintf(xpath + slen, sizeof(xpath) - slen,
+ "[interface='%s']", bs->key.ifname);
+ else
+ slen += snprintf(xpath + slen, sizeof(xpath) - slen,
+ "[interface='']");
+ snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf",
+ bs->key.vrfname);
+
+ pthread_rwlock_wrlock(&running_config->lock);
+ {
+ bfd_dnode = yang_dnode_get(
+ running_config->dnode,
+ xpath, bs->key.vrfname);
+ if (bfd_dnode) {
+ yang_dnode_change_leaf(bfd_dnode, vrf->name);
+ running_config->version++;
+ }
+ pthread_rwlock_unlock(&running_config->lock);
+ }
+ }
+ memset(bs->key.vrfname, 0, sizeof(bs->key.vrfname));
+ strlcpy(bs->key.vrfname, vrf->name, sizeof(bs->key.vrfname));
+ hash_get(bfd_key_hash, bs, hash_alloc_intern);
+}
void bfdd_zclient_register(vrf_id_t vrf_id);
void bfdd_sessions_enable_vrf(struct vrf *vrf);
void bfdd_sessions_disable_vrf(struct vrf *vrf);
+void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf);
int ptm_bfd_notify(struct bfd_session *bs);
snprintf(ebuf, ebuflen, "vrf name too long");
return -1;
}
+ } else {
+ bpc->bpc_has_vrfname = true;
+ strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
}
return 0;
log_error("ptm-read: vrf id %u could not be identified", vrf_id);
return -1;
}
+ } else {
+ bpc->bpc_has_vrfname = true;
+ strlcpy(bpc->bpc_vrfname, VRF_DEFAULT_NAME, sizeof(bpc->bpc_vrfname));
}
STREAM_GETC(msg, bpc->bpc_cbit);
/* it may affect configs without interfaces */
TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) {
bs = bso->bso_bs;
+ /* update name */
+ if (bs->vrf && bs->vrf == vrf) {
+ if (!strmatch(bs->key.vrfname, vrf->name))
+ bfd_session_update_vrf_name(bs, vrf);
+ }
if (bs->vrf)
continue;
if (bs->key.vrfname[0] &&
static struct timeval tolerance = {0, 100000};
+ uint32_t v_ka = atomic_load_explicit(&pkat->peer->v_keepalive,
+ memory_order_relaxed);
+
+ /* 0 keepalive timer means no keepalives */
+ if (v_ka == 0)
+ return;
+
/* calculate elapsed time since last keepalive */
monotime_since(&pkat->last, &elapsed);
/* calculate difference between elapsed time and configured time */
- ka.tv_sec = pkat->peer->v_keepalive;
+ ka.tv_sec = v_ka;
timersub(&ka, &elapsed, &diff);
int send_keepalive =
zlog_debug("VRF enable add %s id %u", vrf->name, vrf->vrf_id);
bgp = bgp_lookup_by_name(vrf->name);
- if (bgp) {
+ if (bgp && bgp->vrf_id != vrf->vrf_id) {
if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) {
XFREE(MTYPE_BGP, bgp->name);
bgp->name = NULL;
XFREE(MTYPE_BGP, bgp->name_pretty);
bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default");
+ bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT;
+#if ENABLE_BGP_VNC
+ if (!bgp->rfapi) {
+ bgp->rfapi = bgp_rfapi_new(bgp);
+ assert(bgp->rfapi);
+ assert(bgp->rfapi_cfg);
+ }
+#endif /* ENABLE_BGP_VNC */
}
old_vrf_id = bgp->vrf_id;
/* We have instance configured, link to VRF and make it "up". */
static void bgp_vrf_init(void)
{
vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable,
- bgp_vrf_delete, NULL);
+ bgp_vrf_delete, bgp_vrf_enable);
}
static void bgp_vrf_terminate(void)
/* Set name */
if (name && vrf->name[0] != '\0' && strcmp(name, vrf->name)) {
+ /* update the vrf name */
RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf);
+ strlcpy(vrf->data.l.netns_name,
+ name, NS_NAMSIZ);
strlcpy(vrf->name, name, sizeof(vrf->name));
RB_INSERT(vrf_name_head, &vrfs_by_name, vrf);
+ if (vrf->vrf_id == VRF_DEFAULT)
+ vrf_set_default_name(vrf->name, false);
} else if (name && vrf->name[0] == '\0') {
strlcpy(vrf->name, name, sizeof(vrf->name));
RB_INSERT(vrf_name_head, &vrfs_by_name, vrf);
def_vrf->vrf_id);
return;
}
-
+ if (strmatch(vrf_default_name, default_name))
+ return;
snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name);
if (def_vrf) {
if (force)
/* OSPF errors init */
ospf_error_init();
- /* Need to initialize the default ospf structure, so the interface mode
- commands can be duly processed if they are received before 'router
- ospf',
- when quagga(ospfd) is restarted */
- if (!ospf_get_instance(instance)) {
- flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s",
- strerror(errno));
- exit(1);
- }
-
frr_config_fork();
frr_run(master);
void ospf_vrf_init(void)
{
vrf_init(ospf_vrf_new, ospf_vrf_enable, ospf_vrf_disable,
- ospf_vrf_delete, NULL);
+ ospf_vrf_delete, ospf_vrf_enable);
}
void ospf_vrf_terminate(void)
int socket;
rip = rip_lookup_by_vrf_name(vrf->name);
+ if (!rip) {
+ char *old_vrf_name = NULL;
+
+ rip = (struct rip *)vrf->info;
+ if (!rip)
+ return 0;
+ /* update vrf name */
+ if (rip->vrf_name)
+ old_vrf_name = rip->vrf_name;
+ rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf->name);
+ /*
+ * HACK: Change the RIP VRF in the running configuration directly,
+ * bypassing the northbound layer. This is necessary to avoid deleting
+ * the RIP and readding it in the new VRF, which would have
+ * several implications.
+ */
+ if (yang_module_find("frr-ripd") && old_vrf_name) {
+ struct lyd_node *rip_dnode;
+
+ pthread_rwlock_wrlock(&running_config->lock);
+ {
+ rip_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-ripd:ripd/instance[vrf='%s']/vrf",
+ old_vrf_name);
+ if (rip_dnode) {
+ yang_dnode_change_leaf(rip_dnode, vrf->name);
+ running_config->version++;
+ }
+ }
+ pthread_rwlock_unlock(&running_config->lock);
+ }
+ if (old_vrf_name)
+ XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name);
+ }
if (!rip || rip->enabled)
return 0;
void rip_vrf_init(void)
{
vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete,
- NULL);
+ rip_vrf_enable);
}
void rip_vrf_terminate(void)
int socket;
ripng = ripng_lookup_by_vrf_name(vrf->name);
- if (!ripng || ripng->enabled)
+ if (!ripng) {
+ char *old_vrf_name = NULL;
+
+ ripng = (struct ripng *)vrf->info;
+ if (!ripng)
+ return 0;
+ /* update vrf name */
+ if (ripng->vrf_name)
+ old_vrf_name = ripng->vrf_name;
+ ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name);
+ /*
+ * HACK: Change the RIPng VRF in the running configuration directly,
+ * bypassing the northbound layer. This is necessary to avoid deleting
+ * the RIPng and readding it in the new VRF, which would have
+ * several implications.
+ */
+ if (yang_module_find("frr-ripngd") && old_vrf_name) {
+ struct lyd_node *ripng_dnode;
+
+ pthread_rwlock_wrlock(&running_config->lock);
+ {
+ ripng_dnode = yang_dnode_get(
+ running_config->dnode,
+ "/frr-ripngd:ripngd/instance[vrf='%s']/vrf",
+ old_vrf_name);
+ if (ripng_dnode) {
+ yang_dnode_change_leaf(ripng_dnode, vrf->name);
+ running_config->version++;
+ }
+ }
+ pthread_rwlock_unlock(&running_config->lock);
+ }
+ if (old_vrf_name)
+ XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name);
+ }
+
+ if (ripng->enabled)
return 0;
if (IS_RIPNG_DEBUG_EVENT)
vrf->vrf_id);
/* Activate the VRF RIPng instance. */
- if (!ripng->enabled) {
- socket = ripng_make_socket(vrf);
- if (socket < 0)
- return -1;
+ socket = ripng_make_socket(vrf);
+ if (socket < 0)
+ return -1;
- ripng_instance_enable(ripng, vrf, socket);
- }
+ ripng_instance_enable(ripng, vrf, socket);
return 0;
}
void ripng_vrf_init(void)
{
vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
- ripng_vrf_delete, NULL);
+ ripng_vrf_delete, ripng_vrf_enable);
}
void ripng_vrf_terminate(void)
return 1;
}
-
-/*
- * Perform next-hop tracking processing after RIB updates.
- */
-static void do_nht_processing(void)
-{
-}
-
/* Dispatch the meta queue by picking, processing and unlocking the next RN from
* a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and
* data
} while (1);
- /* Check for nexthop tracking processing after finishing with results */
- do_nht_processing();
-
return 0;
}