summaryrefslogtreecommitdiffstats
path: root/ldpd/lde_lib.c
diff options
context:
space:
mode:
authorRenato Westphal <renato@opensourcerouting.org>2017-02-03 14:09:27 +0100
committerRenato Westphal <renato@opensourcerouting.org>2017-02-06 16:05:41 +0100
commit8cb1fc4537e2bc44a021c988b4c5d08618975924 (patch)
treeddd9e48906f3d622515e1fa37a6fedbe2d4f61ef /ldpd/lde_lib.c
parentldpd: fix silly bug introduced by a recent commit (diff)
downloadfrr-8cb1fc4537e2bc44a021c988b4c5d08618975924.tar.xz
frr-8cb1fc4537e2bc44a021c988b4c5d08618975924.zip
ldpd: update local labels when necessary
ldpd allocates null labels for directly connected routes. If a connected route is removed (interface goes down) and an IGP learned route takes its place in the RIB, ldpd must update the local label of the associated FEC entry with a non-null label. The same applies for the other way around (an interface goes up and a connected route is selected in favour of an IGP route). Labels should be dynamic and change when necessary. Additionally, this patch fixes the processing of route delete messages from zebra. Route delete messages don't contain any nexthop, meaning that whenever we receive such messages we must delete all nexthop previously received. Based on a patch from Bingen Eguzkitza <bingen@voltanet.io>. Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
Diffstat (limited to 'ldpd/lde_lib.c')
-rw-r--r--ldpd/lde_lib.c108
1 files changed, 56 insertions, 52 deletions
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 7a4cb760f..234d373fb 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -311,55 +311,19 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
{
struct fec_node *fn;
struct fec_nh *fnh;
- struct lde_map *me;
- struct lde_nbr *ln;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
fn = fec_add(fec);
- fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
- if (fnh != NULL) {
- lde_send_change_klabel(fn, fnh);
- fnh->flags |= F_FEC_NH_NEW;
- return;
- }
-
- if (fn->fec.type == FEC_TYPE_PWID)
+ if (data)
fn->data = data;
- if (fn->local_label == NO_LABEL) {
- fn->local_label = lde_assign_label(&fn->fec, connected);
-
- /* FEC.1: perform lsr label distribution procedure */
- if (fn->local_label != NO_LABEL)
- RB_FOREACH(ln, nbr_tree, &lde_nbrs)
- lde_send_labelmapping(ln, fn, 1);
- }
-
- fnh = fec_nh_add(fn, af, nexthop, ifindex, priority);
+ fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
+ if (fnh == NULL)
+ fnh = fec_nh_add(fn, af, nexthop, ifindex, priority);
fnh->flags |= F_FEC_NH_NEW;
- lde_send_change_klabel(fn, fnh);
-
- switch (fn->fec.type) {
- case FEC_TYPE_IPV4:
- case FEC_TYPE_IPV6:
- ln = lde_nbr_find_by_addr(af, &fnh->nexthop);
- break;
- case FEC_TYPE_PWID:
- ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
- break;
- default:
- ln = NULL;
- break;
- }
-
- if (ln) {
- /* FEC.2 */
- me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
- if (me)
- /* FEC.5 */
- lde_check_mapping(&me->map, ln);
- }
+ if (connected)
+ fnh->flags |= F_FEC_NH_CONNECTED;
}
void
@@ -380,12 +344,6 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
- if (LIST_EMPTY(&fn->nexthops)) {
- lde_send_labelwithdraw_all(fn, NO_LABEL);
- fn->local_label = NO_LABEL;
- if (fn->fec.type == FEC_TYPE_PWID)
- fn->data = NULL;
- }
}
/*
@@ -395,10 +353,12 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
* them (if any), withdraw the associated labels from zebra.
*/
void
-lde_kernel_reevaluate(struct fec *fec)
+lde_kernel_update(struct fec *fec)
{
struct fec_node *fn;
struct fec_nh *fnh, *safe;
+ struct lde_nbr *ln;
+ struct lde_map *me;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
@@ -407,9 +367,53 @@ lde_kernel_reevaluate(struct fec *fec)
LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) {
if (fnh->flags & F_FEC_NH_NEW)
fnh->flags &= ~F_FEC_NH_NEW;
- else
- lde_kernel_remove(fec, fnh->af, &fnh->nexthop,
- fnh->ifindex, fnh->priority);
+ else {
+ lde_send_delete_klabel(fn, fnh);
+ fec_nh_del(fnh);
+ }
+ }
+
+ if (LIST_EMPTY(&fn->nexthops)) {
+ lde_send_labelwithdraw_all(fn, NO_LABEL);
+ fn->local_label = NO_LABEL;
+ fn->data = NULL;
+ } else {
+ uint32_t previous_label;
+
+ previous_label = fn->local_label;
+ fn->local_label = lde_update_label(fn);
+
+ if (fn->local_label != NO_LABEL &&
+ fn->local_label != previous_label) {
+ /* FEC.1: perform lsr label distribution procedure */
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 1);
+ }
+ }
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ lde_send_change_klabel(fn, fnh);
+
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ case FEC_TYPE_IPV6:
+ ln = lde_nbr_find_by_addr(fnh->af, &fnh->nexthop);
+ break;
+ case FEC_TYPE_PWID:
+ ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
+ break;
+ default:
+ ln = NULL;
+ break;
+ }
+
+ if (ln) {
+ /* FEC.2 */
+ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
+ if (me)
+ /* FEC.5 */
+ lde_check_mapping(&me->map, ln);
+ }
}
}