diff options
Diffstat (limited to 'ldpd/lde_lib.c')
| -rw-r--r-- | ldpd/lde_lib.c | 303 |
1 files changed, 208 insertions, 95 deletions
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index faadd566ad..4444a1e1ac 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -31,7 +31,7 @@ static int lde_nbr_is_nexthop(struct fec_node *, static void fec_free(void *); static struct fec_node *fec_add(struct fec *fec); static struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *, - uint8_t priority); + ifindex_t, uint8_t); static void fec_nh_del(struct fec_nh *); RB_GENERATE(fec_tree, fec, entry, fec_compare) @@ -264,13 +264,14 @@ fec_add(struct fec *fec) struct fec_nh * fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, - uint8_t priority) + ifindex_t ifindex, uint8_t priority) { struct fec_nh *fnh; LIST_FOREACH(fnh, &fn->nexthops, entry) if (fnh->af == af && ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 && + fnh->ifindex == ifindex && fnh->priority == priority) return (fnh); @@ -279,7 +280,7 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop, static struct fec_nh * fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, - uint8_t priority) + ifindex_t ifindex, uint8_t priority) { struct fec_nh *fnh; @@ -289,6 +290,7 @@ fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop, fnh->af = af; fnh->nexthop = *nexthop; + fnh->ifindex = ifindex; fnh->remote_label = NO_LABEL; fnh->priority = priority; LIST_INSERT_HEAD(&fn->nexthops, fnh, entry); @@ -303,87 +305,30 @@ fec_nh_del(struct fec_nh *fnh) free(fnh); } -uint32_t -egress_label(enum fec_type fec_type) -{ - switch (fec_type) { - case FEC_TYPE_IPV4: - if (ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL) - return (MPLS_LABEL_IPV4NULL); - break; - case FEC_TYPE_IPV6: - if (ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL) - return (MPLS_LABEL_IPV6NULL); - break; - default: - fatalx("egress_label: unexpected fec type"); - } - - return (MPLS_LABEL_IMPLNULL); -} - void lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, - uint8_t priority, int connected, void *data) + ifindex_t ifindex, uint8_t priority, int connected, void *data) { 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, 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) { - if (connected) - fn->local_label = egress_label(fn->fec.type); - else - fn->local_label = lde_assign_label(); - - /* FEC.1: perform lsr label distribution procedure */ - RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelmapping(ln, fn, 1); - } - - fnh = fec_nh_add(fn, af, nexthop, 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 lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, - uint8_t priority) + ifindex_t ifindex, uint8_t priority) { struct fec_node *fn; struct fec_nh *fnh; @@ -392,19 +337,13 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, if (fn == NULL) /* route lost */ return; - fnh = fec_nh_find(fn, af, nexthop, priority); + fnh = fec_nh_find(fn, af, nexthop, ifindex, priority); if (fnh == NULL) /* route lost */ return; 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; - } } /* @@ -414,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) @@ -426,9 +367,54 @@ 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->priority); + else { + lde_send_delete_klabel(fn, fnh); + fec_nh_del(fnh); + } + } + + if (LIST_EMPTY(&fn->nexthops)) { + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, fn, NULL, NULL); + 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); + } } } @@ -444,6 +430,30 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) int msgsource = 0; lde_map2fec(map, ln->id, &fec); + + switch (fec.type) { + case FEC_TYPE_IPV4: + if (lde_acl_check(ldeconf->ipv4.acl_label_accept_from, + AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) + return; + if (lde_acl_check(ldeconf->ipv4.acl_label_accept_for, + AF_INET, (union ldpd_addr *)&fec.u.ipv4.prefix, + fec.u.ipv4.prefixlen) != FILTER_PERMIT) + return; + break; + case FEC_TYPE_IPV6: + if (lde_acl_check(ldeconf->ipv6.acl_label_accept_from, + AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) + return; + if (lde_acl_check(ldeconf->ipv6.acl_label_accept_for, + AF_INET6, (union ldpd_addr *)&fec.u.ipv6.prefix, + fec.u.ipv6.prefixlen) != FILTER_PERMIT) + return; + break; + default: + break; + } + fn = (struct fec_node *)fec_find(&ft, &fec); if (fn == NULL) fn = fec_add(&fec); @@ -469,7 +479,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) /* LMp.10 */ if (me->map.label != map->label && lre == NULL) { /* LMp.10a */ - lde_send_labelrelease(ln, fn, me->map.label); + lde_send_labelrelease(ln, fn, NULL, me->map.label); /* * Can not use lde_nbr_find_by_addr() because there's @@ -545,6 +555,12 @@ lde_check_request(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct fec_nh *fnh; + /* wildcard label request */ + if (map->type == MAP_TYPE_TYPED_WCARD) { + lde_check_request_wcard(map, ln); + return; + } + /* LRq.1: skip loop detection (not necessary) */ /* LRq.2: is there a next hop for fec? */ @@ -552,7 +568,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln) fn = (struct fec_node *)fec_find(&ft, &fec); if (fn == NULL || LIST_EMPTY(&fn->nexthops)) { /* LRq.5: send No Route notification */ - lde_send_notification(ln->peerid, S_NO_ROUTE, map->msg_id, + lde_send_notification(ln, S_NO_ROUTE, map->msg_id, htons(MSG_TYPE_LABELREQUEST)); return; } @@ -566,8 +582,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln) continue; /* LRq.4: send Loop Detected notification */ - lde_send_notification(ln->peerid, S_LOOP_DETECTED, - map->msg_id, htons(MSG_TYPE_LABELREQUEST)); + lde_send_notification(ln, S_LOOP_DETECTED, map->msg_id, + htons(MSG_TYPE_LABELREQUEST)); return; default: break; @@ -596,6 +612,40 @@ lde_check_request(struct map *map, struct lde_nbr *ln) } void +lde_check_request_wcard(struct map *map, struct lde_nbr *ln) +{ + struct fec *f; + struct fec_node *fn; + struct lde_req *lre; + + RB_FOREACH(f, fec_tree, &ft) { + fn = (struct fec_node *)f; + + /* only a typed wildcard is possible here */ + if (lde_wildcard_apply(map, &fn->fec, NULL) == 0) + continue; + + /* LRq.2: is there a next hop for fec? */ + if (LIST_EMPTY(&fn->nexthops)) + continue; + + /* LRq.6: first check if we have a pending request running */ + lre = (struct lde_req *)fec_find(&ln->recv_req, &fn->fec); + if (lre != NULL) + /* LRq.7: duplicate request */ + continue; + + /* LRq.8: record label request */ + lre = lde_req_add(ln, &fn->fec, 0); + if (lre != NULL) + lre->msg_id = ntohl(map->msg_id); + + /* LRq.9: perform LSR label distribution */ + lde_send_labelmapping(ln, fn, 1); + } +} + +void lde_check_release(struct map *map, struct lde_nbr *ln) { struct fec fec; @@ -603,9 +653,13 @@ lde_check_release(struct map *map, struct lde_nbr *ln) struct lde_wdraw *lw; struct lde_map *me; - /* TODO group wildcard */ - if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) + /* wildcard label release */ + if (map->type == MAP_TYPE_WILDCARD || + map->type == MAP_TYPE_TYPED_WCARD || + (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { + lde_check_release_wcard(map, ln); return; + } lde_map2fec(map, ln->id, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); @@ -615,8 +669,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln) /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); - if (lw && (map->label == NO_LABEL || - (lw->label != NO_LABEL && map->label == lw->label))) { + if (lw && (map->label == NO_LABEL || map->label == lw->label)) { /* LRl.4: delete record of outstanding label withdraw */ lde_wdraw_del(ln, lw); } @@ -642,17 +695,20 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; + me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); + + /* LRl.1: does FEC match a known FEC? */ + if (lde_wildcard_apply(map, &fn->fec, me) == 0) + continue; /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); - if (lw && (map->label == NO_LABEL || - (lw->label != NO_LABEL && map->label == lw->label))) { + if (lw && (map->label == NO_LABEL || map->label == lw->label)) { /* LRl.4: delete record of outstanding lbl withdraw */ lde_wdraw_del(ln, lw); } /* LRl.6: check sent map list and remove it if available */ - me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); if (me && (map->label == NO_LABEL || map->label == me->map.label)) lde_map_del(ln, me, 1); @@ -673,9 +729,13 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) struct lde_map *me; struct l2vpn_pw *pw; - /* TODO group wildcard */ - if (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID)) + /* wildcard label withdraw */ + if (map->type == MAP_TYPE_WILDCARD || + map->type == MAP_TYPE_TYPED_WCARD || + (map->type == MAP_TYPE_PWID && !(map->flags & F_MAP_PW_ID))) { + lde_check_withdraw_wcard(map, ln); return; + } lde_map2fec(map, ln->id, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); @@ -698,12 +758,15 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) default: break; } + if (map->label != NO_LABEL && map->label != fnh->remote_label) + continue; + lde_send_delete_klabel(fn, fnh); fnh->remote_label = NO_LABEL; } /* LWd.2: send label release */ - lde_send_labelrelease(ln, fn, map->label); + lde_send_labelrelease(ln, fn, NULL, map->label); /* LWd.3: check previously received label mapping */ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); @@ -721,10 +784,14 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) struct lde_map *me; /* LWd.2: send label release */ - lde_send_labelrelease(ln, NULL, map->label); + lde_send_labelrelease(ln, NULL, map, map->label); RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; + me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); + + if (lde_wildcard_apply(map, &fn->fec, me) == 0) + continue; /* LWd.1: remove label from forwarding/switching use */ LIST_FOREACH(fnh, &fn->nexthops, entry) { @@ -742,12 +809,15 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) default: break; } + if (map->label != NO_LABEL && map->label != + fnh->remote_label) + continue; + lde_send_delete_klabel(fn, fnh); fnh->remote_label = NO_LABEL; } /* LWd.3: check previously received label mapping */ - me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); if (me && (map->label == NO_LABEL || map->label == me->map.label)) /* @@ -758,6 +828,49 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) } } +int +lde_wildcard_apply(struct map *wcard, struct fec *fec, struct lde_map *me) +{ + switch (wcard->type) { + case MAP_TYPE_WILDCARD: + /* full wildcard */ + return (1); + case MAP_TYPE_TYPED_WCARD: + switch (wcard->fec.twcard.type) { + case MAP_TYPE_PREFIX: + if (wcard->fec.twcard.u.prefix_af == AF_INET && + fec->type != FEC_TYPE_IPV4) + return (0); + if (wcard->fec.twcard.u.prefix_af == AF_INET6 && + fec->type != FEC_TYPE_IPV6) + return (0); + return (1); + case MAP_TYPE_PWID: + if (fec->type != FEC_TYPE_PWID) + return (0); + if (wcard->fec.twcard.u.pw_type != PW_TYPE_WILDCARD && + wcard->fec.twcard.u.pw_type != fec->u.pwid.type) + return (0); + return (1); + default: + fatalx("lde_wildcard_apply: unexpected fec type"); + } + break; + case MAP_TYPE_PWID: + /* RFC4447 pw-id group wildcard */ + if (fec->type != FEC_TYPE_PWID) + return (0); + if (fec->u.pwid.type != wcard->fec.pwid.type) + return (0); + if (me == NULL || (me->map.fec.pwid.group_id != + wcard->fec.pwid.group_id)) + return (0); + return (1); + default: + fatalx("lde_wildcard_apply: unexpected fec type"); + } +} + /* gabage collector timer: timer to remove dead entries from the LIB */ /* ARGSUSED */ |
