diff options
-rw-r--r-- | ldpd/l2vpn.c | 2 | ||||
-rw-r--r-- | ldpd/lde.c | 57 | ||||
-rw-r--r-- | ldpd/lde.h | 5 | ||||
-rw-r--r-- | ldpd/lde_lib.c | 108 | ||||
-rw-r--r-- | ldpd/ldp_zebra.c | 46 | ||||
-rw-r--r-- | ldpd/ldpd.h | 3 |
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, |