mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
MPLS: Implement FEC map reconfiguration
This allows changing label policy or label range without restart.
This commit is contained in:
parent
9b775859cd
commit
a7a9df8639
167
nest/mpls.c
167
nest/mpls.c
@ -76,8 +76,6 @@
|
|||||||
* and withdrawal of MPLS routes.
|
* and withdrawal of MPLS routes.
|
||||||
*
|
*
|
||||||
* TODO:
|
* TODO:
|
||||||
* - protocols should do route refresh instead of restart when reconfiguration
|
|
||||||
* requires changing labels (e.g. different label range)
|
|
||||||
* - special handling of reserved labels
|
* - special handling of reserved labels
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -254,7 +252,8 @@ mpls_reconfigure_domain(struct mpls_domain *m, struct mpls_domain_config *cf)
|
|||||||
|
|
||||||
struct mpls_range *r, *r2;
|
struct mpls_range *r, *r2;
|
||||||
WALK_LIST_DELSAFE(r, r2, old_ranges)
|
WALK_LIST_DELSAFE(r, r2, old_ranges)
|
||||||
mpls_remove_range(r);
|
if (!r->removed)
|
||||||
|
mpls_remove_range(r);
|
||||||
|
|
||||||
add_tail_list(&m->ranges, &old_ranges);
|
add_tail_list(&m->ranges, &old_ranges);
|
||||||
|
|
||||||
@ -384,7 +383,7 @@ mpls_find_range_(list *l, const char *name)
|
|||||||
struct mpls_range *r;
|
struct mpls_range *r;
|
||||||
|
|
||||||
WALK_LIST(r, *l)
|
WALK_LIST(r, *l)
|
||||||
if (!strcmp(r->name, name))
|
if (!strcmp(r->name, name) && !r->removed)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -415,7 +414,6 @@ mpls_free_range(struct mpls_range *r)
|
|||||||
ASSERT(r->use_count == 0);
|
ASSERT(r->use_count == 0);
|
||||||
ASSERT(r->label_count == 0);
|
ASSERT(r->label_count == 0);
|
||||||
|
|
||||||
r->cf->range = NULL;
|
|
||||||
rem_node(&r->n);
|
rem_node(&r->n);
|
||||||
mb_free(r);
|
mb_free(r);
|
||||||
}
|
}
|
||||||
@ -423,7 +421,11 @@ mpls_free_range(struct mpls_range *r)
|
|||||||
static void
|
static void
|
||||||
mpls_remove_range(struct mpls_range *r)
|
mpls_remove_range(struct mpls_range *r)
|
||||||
{
|
{
|
||||||
|
ASSERT(!r->removed);
|
||||||
|
|
||||||
r->removed = 1;
|
r->removed = 1;
|
||||||
|
r->cf->range = NULL;
|
||||||
|
r->cf = NULL;
|
||||||
|
|
||||||
if (!r->use_count)
|
if (!r->use_count)
|
||||||
mpls_free_range(r);
|
mpls_free_range(r);
|
||||||
@ -515,6 +517,26 @@ mpls_free_label(struct mpls_domain *m, struct mpls_handle *h, uint n)
|
|||||||
h->label_count--;
|
h->label_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mpls_move_label(struct mpls_domain *m, struct mpls_handle *fh, struct mpls_handle *th, uint n)
|
||||||
|
{
|
||||||
|
struct mpls_range *fr = fh->range;
|
||||||
|
struct mpls_range *tr = th->range;
|
||||||
|
|
||||||
|
ASSERT(lmap_test(&m->labels, n));
|
||||||
|
ASSERT((n >= fr->lo) && (n < fr->hi));
|
||||||
|
ASSERT((n >= tr->lo) && (n < tr->hi));
|
||||||
|
|
||||||
|
ASSERT(fr->label_count);
|
||||||
|
fr->label_count--;
|
||||||
|
|
||||||
|
ASSERT(fh->label_count);
|
||||||
|
fh->label_count--;
|
||||||
|
|
||||||
|
tr->label_count++;
|
||||||
|
th->label_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MPLS channel
|
* MPLS channel
|
||||||
@ -561,16 +583,32 @@ mpls_channel_cleanup(struct channel *C)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mpls_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed UNUSED, int *export_changed UNUSED)
|
mpls_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed, int *export_changed UNUSED)
|
||||||
{
|
{
|
||||||
struct mpls_channel *c = (void *) C;
|
struct mpls_channel *c = (void *) C;
|
||||||
struct mpls_channel_config *new = (void *) CC;
|
struct mpls_channel_config *new = (void *) CC;
|
||||||
|
|
||||||
if ((new->domain->domain != c->domain) ||
|
if (new->domain->domain != c->domain)
|
||||||
(new->range->range != c->range) ||
|
|
||||||
(new->label_policy != c->label_policy))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (new->range->range != c->range)
|
||||||
|
{
|
||||||
|
if (c->c.channel_state != CS_DOWN)
|
||||||
|
mpls_unlock_range(c->range);
|
||||||
|
|
||||||
|
c->range = new->range->range;
|
||||||
|
*import_changed = 1;
|
||||||
|
|
||||||
|
if (c->c.channel_state != CS_DOWN)
|
||||||
|
mpls_lock_range(c->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new->label_policy != c->label_policy)
|
||||||
|
{
|
||||||
|
c->label_policy = new->label_policy;
|
||||||
|
*import_changed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,6 +677,7 @@ HASH_DEFINE_REHASH_FN(RTA, struct mpls_fec)
|
|||||||
HASH_DEFINE_REHASH_FN(LABEL, struct mpls_fec)
|
HASH_DEFINE_REHASH_FN(LABEL, struct mpls_fec)
|
||||||
|
|
||||||
|
|
||||||
|
static void mpls_unlink_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
|
||||||
static void mpls_withdraw_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
|
static void mpls_withdraw_fec(struct mpls_fec_map *m, struct mpls_fec *fec);
|
||||||
static rta * mpls_get_key_rta(struct mpls_fec_map *m, const rta *src);
|
static rta * mpls_get_key_rta(struct mpls_fec_map *m, const rta *src);
|
||||||
|
|
||||||
@ -666,6 +705,67 @@ mpls_fec_map_new(pool *pp, struct channel *C, uint rts)
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C)
|
||||||
|
{
|
||||||
|
struct mpls_channel *c = (void *) C;
|
||||||
|
|
||||||
|
struct mpls_handle *old_d = NULL;
|
||||||
|
struct mpls_handle *old_s = NULL;
|
||||||
|
|
||||||
|
/* Reallocate dynamic handle */
|
||||||
|
if (m->handle->range != c->range)
|
||||||
|
{
|
||||||
|
old_d = m->handle;
|
||||||
|
m->handle = mpls_new_handle(m->domain, c->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reallocate static handle */
|
||||||
|
if (m->static_handle && (m->static_handle->range != m->domain->cf->static_range->range))
|
||||||
|
{
|
||||||
|
old_s = m->static_handle;
|
||||||
|
m->static_handle = mpls_new_handle(m->domain, m->domain->cf->static_range->range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip rest if there is no change */
|
||||||
|
if (!old_d && !old_s)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Process existing FECs */
|
||||||
|
HASH_WALK(m->label_hash, next_l, fec)
|
||||||
|
{
|
||||||
|
/* Skip already dead FECs */
|
||||||
|
if (fec->policy == MPLS_POLICY_NONE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Skip FECs with valid handle */
|
||||||
|
if ((fec->handle == m->handle) || (fec->handle == m->static_handle))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Try new handle for the FEC */
|
||||||
|
struct mpls_handle *new = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
|
||||||
|
if ((fec->label >= new->range->lo) && (fec->label < new->range->hi))
|
||||||
|
{
|
||||||
|
mpls_move_label(m->domain, fec->handle, new, fec->label);
|
||||||
|
fec->handle = new;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlink the FEC while keep it in the label hash */
|
||||||
|
mpls_unlink_fec(m, fec);
|
||||||
|
fec->policy = MPLS_POLICY_NONE;
|
||||||
|
}
|
||||||
|
HASH_WALK_END;
|
||||||
|
|
||||||
|
/* Remove old unused handles */
|
||||||
|
|
||||||
|
if (old_d && !old_d->label_count)
|
||||||
|
mpls_free_handle(m->domain, old_d);
|
||||||
|
|
||||||
|
if (old_s && !old_s->label_count)
|
||||||
|
mpls_free_handle(m->domain, old_s);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mpls_fec_map_free(struct mpls_fec_map *m)
|
mpls_fec_map_free(struct mpls_fec_map *m)
|
||||||
{
|
{
|
||||||
@ -683,8 +783,10 @@ mpls_fec_map_free(struct mpls_fec_map *m)
|
|||||||
/* Free allocated labels */
|
/* Free allocated labels */
|
||||||
HASH_WALK(m->label_hash, next_l, fec)
|
HASH_WALK(m->label_hash, next_l, fec)
|
||||||
{
|
{
|
||||||
struct mpls_handle *h = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
|
mpls_free_label(m->domain, fec->handle, fec->label);
|
||||||
mpls_free_label(m->domain, h, fec->label);
|
|
||||||
|
if (!fec->policy && !fec->handle->label_count)
|
||||||
|
mpls_free_handle(m->domain, fec->handle);
|
||||||
}
|
}
|
||||||
HASH_WALK_END;
|
HASH_WALK_END;
|
||||||
|
|
||||||
@ -720,12 +822,12 @@ mpls_get_fec_by_label(struct mpls_fec_map *m, u32 label)
|
|||||||
{
|
{
|
||||||
struct mpls_fec *fec = HASH_FIND(m->label_hash, LABEL, label);
|
struct mpls_fec *fec = HASH_FIND(m->label_hash, LABEL, label);
|
||||||
|
|
||||||
if (!m->static_handle)
|
|
||||||
m->static_handle = mpls_new_handle(m->domain, m->domain->cf->static_range->range);
|
|
||||||
|
|
||||||
if (fec)
|
if (fec)
|
||||||
return (fec->policy == MPLS_POLICY_STATIC) ? fec : NULL;
|
return (fec->policy == MPLS_POLICY_STATIC) ? fec : NULL;
|
||||||
|
|
||||||
|
if (!m->static_handle)
|
||||||
|
m->static_handle = mpls_new_handle(m->domain, m->domain->cf->static_range->range);
|
||||||
|
|
||||||
label = mpls_new_label(m->domain, m->static_handle, label);
|
label = mpls_new_label(m->domain, m->static_handle, label);
|
||||||
|
|
||||||
if (!label)
|
if (!label)
|
||||||
@ -735,6 +837,7 @@ mpls_get_fec_by_label(struct mpls_fec_map *m, u32 label)
|
|||||||
|
|
||||||
fec->label = label;
|
fec->label = label;
|
||||||
fec->policy = MPLS_POLICY_STATIC;
|
fec->policy = MPLS_POLICY_STATIC;
|
||||||
|
fec->handle = m->static_handle;
|
||||||
|
|
||||||
DBG("New FEC lab %u\n", fec->label);
|
DBG("New FEC lab %u\n", fec->label);
|
||||||
|
|
||||||
@ -768,6 +871,7 @@ mpls_get_fec_by_net(struct mpls_fec_map *m, const net_addr *net, u32 path_id)
|
|||||||
|
|
||||||
fec->label = label;
|
fec->label = label;
|
||||||
fec->policy = MPLS_POLICY_PREFIX;
|
fec->policy = MPLS_POLICY_PREFIX;
|
||||||
|
fec->handle = m->handle;
|
||||||
|
|
||||||
DBG("New FEC net %u\n", fec->label);
|
DBG("New FEC net %u\n", fec->label);
|
||||||
|
|
||||||
@ -809,6 +913,7 @@ mpls_get_fec_by_rta(struct mpls_fec_map *m, const rta *src, u32 class_id)
|
|||||||
|
|
||||||
fec->label = label;
|
fec->label = label;
|
||||||
fec->policy = MPLS_POLICY_AGGREGATE;
|
fec->policy = MPLS_POLICY_AGGREGATE;
|
||||||
|
fec->handle = m->handle;
|
||||||
|
|
||||||
DBG("New FEC rta %u\n", fec->label);
|
DBG("New FEC rta %u\n", fec->label);
|
||||||
|
|
||||||
@ -835,6 +940,7 @@ mpls_get_fec_for_vrf(struct mpls_fec_map *m)
|
|||||||
|
|
||||||
fec->label = label;
|
fec->label = label;
|
||||||
fec->policy = MPLS_POLICY_VRF;
|
fec->policy = MPLS_POLICY_VRF;
|
||||||
|
fec->handle = m->handle;
|
||||||
fec->iface = m->vrf_iface;
|
fec->iface = m->vrf_iface;
|
||||||
|
|
||||||
DBG("New FEC vrf %u\n", fec->label);
|
DBG("New FEC vrf %u\n", fec->label);
|
||||||
@ -845,21 +951,12 @@ mpls_get_fec_for_vrf(struct mpls_fec_map *m)
|
|||||||
return fec;
|
return fec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
|
mpls_unlink_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
|
||||||
{
|
{
|
||||||
if (fec->state != MPLS_FEC_DOWN)
|
|
||||||
mpls_withdraw_fec(m, fec);
|
|
||||||
|
|
||||||
DBG("Free FEC %u\n", fec->label);
|
|
||||||
|
|
||||||
struct mpls_handle *h = (fec->policy != MPLS_POLICY_STATIC) ? m->handle : m->static_handle;
|
|
||||||
mpls_free_label(m->domain, h, fec->label);
|
|
||||||
|
|
||||||
HASH_REMOVE2(m->label_hash, LABEL, m->pool, fec);
|
|
||||||
|
|
||||||
switch (fec->policy)
|
switch (fec->policy)
|
||||||
{
|
{
|
||||||
|
case MPLS_POLICY_NONE:
|
||||||
case MPLS_POLICY_STATIC:
|
case MPLS_POLICY_STATIC:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -880,6 +977,24 @@ mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
|
|||||||
default:
|
default:
|
||||||
bug("Unknown fec type");
|
bug("Unknown fec type");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mpls_free_fec(struct mpls_fec_map *m, struct mpls_fec *fec)
|
||||||
|
{
|
||||||
|
if (fec->state != MPLS_FEC_DOWN)
|
||||||
|
mpls_withdraw_fec(m, fec);
|
||||||
|
|
||||||
|
DBG("Free FEC %u\n", fec->label);
|
||||||
|
|
||||||
|
mpls_free_label(m->domain, fec->handle, fec->label);
|
||||||
|
|
||||||
|
if (!fec->policy && !fec->handle->label_count)
|
||||||
|
mpls_free_handle(m->domain, fec->handle);
|
||||||
|
|
||||||
|
HASH_REMOVE2(m->label_hash, LABEL, m->pool, fec);
|
||||||
|
|
||||||
|
mpls_unlink_fec(m, fec);
|
||||||
|
|
||||||
sl_free(fec);
|
sl_free(fec);
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,7 @@ void mpls_preconfig(struct config *c);
|
|||||||
void mpls_commit(struct config *new, struct config *old);
|
void mpls_commit(struct config *new, struct config *old);
|
||||||
uint mpls_new_label(struct mpls_domain *m, struct mpls_handle *h, uint n);
|
uint mpls_new_label(struct mpls_domain *m, struct mpls_handle *h, uint n);
|
||||||
void mpls_free_label(struct mpls_domain *m, struct mpls_handle *h, uint n);
|
void mpls_free_label(struct mpls_domain *m, struct mpls_handle *h, uint n);
|
||||||
|
void mpls_move_label(struct mpls_domain *m, struct mpls_handle *fh, struct mpls_handle *th, uint n);
|
||||||
|
|
||||||
static inline struct mpls_domain_config *cf_default_mpls_domain(struct config *cfg)
|
static inline struct mpls_domain_config *cf_default_mpls_domain(struct config *cfg)
|
||||||
{ return EMPTY_LIST(cfg->mpls_domains) ? NULL : HEAD(cfg->mpls_domains); }
|
{ return EMPTY_LIST(cfg->mpls_domains) ? NULL : HEAD(cfg->mpls_domains); }
|
||||||
@ -133,6 +134,8 @@ struct mpls_fec {
|
|||||||
u8 state; /* FEC state (MPLS_FEC_*) */
|
u8 state; /* FEC state (MPLS_FEC_*) */
|
||||||
u8 policy; /* Label policy (MPLS_POLICY_*) */
|
u8 policy; /* Label policy (MPLS_POLICY_*) */
|
||||||
|
|
||||||
|
struct mpls_handle *handle; /* Handle holding the label */
|
||||||
|
|
||||||
struct mpls_fec *next_k; /* Next in mpls_fec.net_hash/rta_hash */
|
struct mpls_fec *next_k; /* Next in mpls_fec.net_hash/rta_hash */
|
||||||
struct mpls_fec *next_l; /* Next in mpls_fec.label_hash */
|
struct mpls_fec *next_l; /* Next in mpls_fec.label_hash */
|
||||||
union { /* Primary key */
|
union { /* Primary key */
|
||||||
@ -152,7 +155,7 @@ struct mpls_fec_map {
|
|||||||
|
|
||||||
struct channel *channel; /* MPLS channel for FEC announcement */
|
struct channel *channel; /* MPLS channel for FEC announcement */
|
||||||
struct mpls_domain *domain; /* MPLS domain, keeping reference */
|
struct mpls_domain *domain; /* MPLS domain, keeping reference */
|
||||||
struct mpls_handle *handle; /* Handle for allocation of labels */
|
struct mpls_handle *handle; /* Handle for dynamic allocation of labels */
|
||||||
struct mpls_handle *static_handle; /* Handle for static label allocations, optional */
|
struct mpls_handle *static_handle; /* Handle for static label allocations, optional */
|
||||||
struct iface *vrf_iface;
|
struct iface *vrf_iface;
|
||||||
|
|
||||||
@ -162,6 +165,7 @@ struct mpls_fec_map {
|
|||||||
|
|
||||||
|
|
||||||
struct mpls_fec_map *mpls_fec_map_new(pool *p, struct channel *c, uint rts);
|
struct mpls_fec_map *mpls_fec_map_new(pool *p, struct channel *c, uint rts);
|
||||||
|
void mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C);
|
||||||
void mpls_fec_map_free(struct mpls_fec_map *m);
|
void mpls_fec_map_free(struct mpls_fec_map *m);
|
||||||
struct mpls_fec *mpls_find_fec_by_label(struct mpls_fec_map *x, u32 label);
|
struct mpls_fec *mpls_find_fec_by_label(struct mpls_fec_map *x, u32 label);
|
||||||
struct mpls_fec *mpls_get_fec_by_label(struct mpls_fec_map *m, u32 label);
|
struct mpls_fec *mpls_get_fec_by_label(struct mpls_fec_map *m, u32 label);
|
||||||
|
@ -997,7 +997,7 @@ proto_setup_mpls_map(struct proto *p, uint rts, int hooks)
|
|||||||
}
|
}
|
||||||
else if (m && c)
|
else if (m && c)
|
||||||
{
|
{
|
||||||
// mpls_fec_map_reconfigure(m, c);
|
mpls_fec_map_reconfigure(m, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hooks)
|
if (hooks)
|
||||||
|
Loading…
Reference in New Issue
Block a user