summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldpd/l2vpn.c2
-rw-r--r--ldpd/lde.c57
-rw-r--r--ldpd/lde.h5
-rw-r--r--ldpd/lde_lib.c108
-rw-r--r--ldpd/ldp_zebra.c46
-rw-r--r--ldpd/ldpd.h3
6 files changed, 121 insertions, 100 deletions
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index c1d0437fb..792608d42 100644
--- a/ldpd/l2vpn.c
+++ b/ldpd/l2vpn.c
@@ -211,6 +211,7 @@ l2vpn_pw_init(struct l2vpn_pw *pw)
l2vpn_pw_fec(pw, &fec);
lde_kernel_insert(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0,
0, (void *)pw);
+ lde_kernel_update(&fec);
}
void
@@ -220,6 +221,7 @@ l2vpn_pw_exit(struct l2vpn_pw *pw)
l2vpn_pw_fec(pw, &fec);
lde_kernel_remove(&fec, AF_INET, (union ldpd_addr*)&pw->lsr_id, 0, 0);
+ lde_kernel_update(&fec);
}
static void
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 05267a82c..1323ba3d0 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -414,8 +414,7 @@ lde_dispatch_parent(struct thread *thread)
switch (imsg.hdr.type) {
case IMSG_NETWORK_ADD:
- case IMSG_NETWORK_ADD_END:
- case IMSG_NETWORK_DEL:
+ case IMSG_NETWORK_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(kr)) {
log_warnx("%s: wrong imsg len", __func__);
break;
@@ -443,12 +442,8 @@ lde_dispatch_parent(struct thread *thread)
kr.ifindex, kr.priority,
kr.flags & F_CONNECTED, NULL);
break;
- case IMSG_NETWORK_ADD_END:
- lde_kernel_reevaluate(&fec);
- break;
- case IMSG_NETWORK_DEL:
- lde_kernel_remove(&fec, kr.af, &kr.nexthop,
- kr.ifindex, kr.priority);
+ case IMSG_NETWORK_UPDATE:
+ lde_kernel_update(&fec);
break;
}
break;
@@ -584,28 +579,37 @@ lde_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen)
}
uint32_t
-lde_assign_label(struct fec *fec, int connected)
+lde_update_label(struct fec_node *fn)
{
- static uint32_t label = MPLS_LABEL_RESERVED_MAX;
+ static uint32_t label = MPLS_LABEL_RESERVED_MAX;
+ struct fec_nh *fnh;
+ int connected = 0;
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ if (fnh->flags & F_FEC_NH_CONNECTED) {
+ connected = 1;
+ break;
+ }
+ }
/* should we allocate a label for this fec? */
- switch (fec->type) {
+ switch (fn->fec.type) {
case FEC_TYPE_IPV4:
if ((ldeconf->ipv4.flags & F_LDPD_AF_ALLOCHOSTONLY) &&
- fec->u.ipv4.prefixlen != 32)
+ fn->fec.u.ipv4.prefixlen != 32)
return (NO_LABEL);
if (lde_acl_check(ldeconf->ipv4.acl_label_allocate_for,
- AF_INET, (union ldpd_addr *)&fec->u.ipv4.prefix,
- fec->u.ipv4.prefixlen) != FILTER_PERMIT)
+ AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix,
+ fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT)
return (NO_LABEL);
break;
case FEC_TYPE_IPV6:
if ((ldeconf->ipv6.flags & F_LDPD_AF_ALLOCHOSTONLY) &&
- fec->u.ipv6.prefixlen != 128)
+ fn->fec.u.ipv6.prefixlen != 128)
return (NO_LABEL);
if (lde_acl_check(ldeconf->ipv6.acl_label_allocate_for,
- AF_INET6, (union ldpd_addr *)&fec->u.ipv6.prefix,
- fec->u.ipv6.prefixlen) != FILTER_PERMIT)
+ AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix,
+ fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT)
return (NO_LABEL);
break;
default:
@@ -614,29 +618,34 @@ lde_assign_label(struct fec *fec, int connected)
if (connected) {
/* choose implicit or explicit-null depending on configuration */
- switch (fec->type) {
+ switch (fn->fec.type) {
case FEC_TYPE_IPV4:
if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL))
return (MPLS_LABEL_IMPLNULL);
if (lde_acl_check(ldeconf->ipv4.acl_label_expnull_for,
- AF_INET, (union ldpd_addr *)&fec->u.ipv4.prefix,
- fec->u.ipv4.prefixlen) != FILTER_PERMIT)
+ AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix,
+ fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT)
return (MPLS_LABEL_IMPLNULL);
return (MPLS_LABEL_IPV4NULL);
case FEC_TYPE_IPV6:
if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL))
return (MPLS_LABEL_IMPLNULL);
if (lde_acl_check(ldeconf->ipv6.acl_label_expnull_for,
- AF_INET6, (union ldpd_addr *)&fec->u.ipv6.prefix,
- fec->u.ipv6.prefixlen) != FILTER_PERMIT)
+ AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix,
+ fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT)
return (MPLS_LABEL_IMPLNULL);
return (MPLS_LABEL_IPV6NULL);
default:
- fatalx("lde_assign_label: unexpected fec type");
+ fatalx("lde_update_label: unexpected fec type");
break;
}
}
+ /* preserve current label if there's no need to update it */
+ if (fn->local_label != NO_LABEL &&
+ fn->local_label > MPLS_LABEL_RESERVED_MAX)
+ return (fn->local_label);
+
/*
* TODO: request label to zebra or define a range of labels for ldpd.
*/
@@ -1371,7 +1380,7 @@ lde_change_egress_label(int af)
fatalx("lde_change_egress_label: unknown af");
}
- fn->local_label = lde_assign_label(&fn->fec, 1);
+ fn->local_label = lde_update_label(fn);
if (fn->local_label != NO_LABEL)
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_send_labelmapping(ln, fn, 0);
diff --git a/ldpd/lde.h b/ldpd/lde.h
index 7fa5219b1..e0e9873d5 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -110,6 +110,7 @@ struct fec_nh {
uint8_t flags;
};
#define F_FEC_NH_NEW 0x01
+#define F_FEC_NH_CONNECTED 0x02
struct fec_node {
struct fec fec;
@@ -134,7 +135,7 @@ void lde(const char *, const char *);
int lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
int lde_acl_check(char *, int, union ldpd_addr *, uint8_t);
-uint32_t lde_assign_label(struct fec *, int);
+uint32_t lde_update_label(struct fec_node *);
void lde_send_change_klabel(struct fec_node *, struct fec_nh *);
void lde_send_delete_klabel(struct fec_node *, struct fec_nh *);
void lde_fec2map(struct fec *, struct map *);
@@ -174,7 +175,7 @@ void lde_kernel_insert(struct fec *, int, union ldpd_addr *,
ifindex_t, uint8_t, int, void *);
void lde_kernel_remove(struct fec *, int, union ldpd_addr *,
ifindex_t, uint8_t);
-void lde_kernel_reevaluate(struct fec *);
+void lde_kernel_update(struct fec *);
void lde_check_mapping(struct map *, struct lde_nbr *);
void lde_check_request(struct map *, struct lde_nbr *);
void lde_check_release(struct map *, struct lde_nbr *);
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);
+ }
}
}
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
index 79c4f5b37..12954b91a 100644
--- a/ldpd/ldp_zebra.c
+++ b/ldpd/ldp_zebra.c
@@ -353,7 +353,7 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
u_char type;
u_char message_flags;
struct kroute kr;
- int nhnum, nhlen;
+ int nhnum = 0, nhlen;
size_t nhmark;
memset(&kr, 0, sizeof(kr));
@@ -374,8 +374,6 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
stream_getl(s); /* flags, unused */
stream_getw(s); /* instance, unused */
message_flags = stream_getc(s);
- if (!CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP))
- return (0);
switch (command) {
case ZEBRA_REDISTRIBUTE_IPV4_ADD:
@@ -409,16 +407,35 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
return (0);
}
- nhnum = stream_getc(s);
- nhmark = stream_get_getp(s);
- stream_set_getp(s, nhmark + nhnum * (nhlen + 5));
+ if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) {
+ nhnum = stream_getc(s);
+ nhmark = stream_get_getp(s);
+ stream_set_getp(s, nhmark + nhnum * (nhlen + 5));
+ }
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE))
kr.priority = stream_getc(s);
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC))
stream_getl(s); /* metric, not used */
- stream_set_getp(s, nhmark);
+ if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP))
+ stream_set_getp(s, nhmark);
+
+ if (nhnum == 0) {
+ switch (command) {
+ case ZEBRA_REDISTRIBUTE_IPV4_ADD:
+ case ZEBRA_REDISTRIBUTE_IPV6_ADD:
+ return (0);
+ case ZEBRA_REDISTRIBUTE_IPV4_DEL:
+ case ZEBRA_REDISTRIBUTE_IPV6_DEL:
+ debug_zebra_in("route delete %s/%d (%s)",
+ log_addr(kr.af, &kr.prefix), kr.prefixlen,
+ zebra_route_string(type));
+ break;
+ default:
+ fatalx("ldp_zebra_read_route: unknown command");
+ }
+ }
/* loop through all the nexthops */
for (; nhnum > 0; nhnum--) {
@@ -445,23 +462,12 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr,
sizeof(kr));
break;
- case ZEBRA_REDISTRIBUTE_IPV4_DEL:
- case ZEBRA_REDISTRIBUTE_IPV6_DEL:
- debug_zebra_in("route delete %s/%d nexthop %s "
- "ifindex %u (%s)", log_addr(kr.af, &kr.prefix),
- kr.prefixlen, log_addr(kr.af, &kr.nexthop),
- kr.ifindex, zebra_route_string(type));
- main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, &kr,
- sizeof(kr));
- break;
default:
- fatalx("ldp_zebra_read_route: unknown command");
+ break;
}
}
- if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD ||
- command == ZEBRA_REDISTRIBUTE_IPV6_ADD)
- main_imsg_compose_lde(IMSG_NETWORK_ADD_END, 0, &kr, sizeof(kr));
+ main_imsg_compose_lde(IMSG_NETWORK_UPDATE, 0, &kr, sizeof(kr));
return (0);
}
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index fa3789a83..ff3af19db 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -122,8 +122,7 @@ enum imsg_type {
IMSG_NEIGHBOR_UP,
IMSG_NEIGHBOR_DOWN,
IMSG_NETWORK_ADD,
- IMSG_NETWORK_ADD_END,
- IMSG_NETWORK_DEL,
+ IMSG_NETWORK_UPDATE,
IMSG_SOCKET_IPC,
IMSG_SOCKET_NET,
IMSG_CLOSE_SOCKETS,