diff options
Diffstat (limited to 'ldpd/lde_lib.c')
| -rw-r--r-- | ldpd/lde_lib.c | 138 |
1 files changed, 121 insertions, 17 deletions
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 234d373fbb..4444a1e1ac 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -374,7 +374,8 @@ lde_kernel_update(struct fec *fec) } if (LIST_EMPTY(&fn->nexthops)) { - lde_send_labelwithdraw_all(fn, NO_LABEL); + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelwithdraw(ln, fn, NULL, NULL); fn->local_label = NO_LABEL; fn->data = NULL; } else { @@ -478,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 @@ -554,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? */ @@ -561,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; } @@ -575,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; @@ -605,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; @@ -612,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); @@ -624,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); } @@ -651,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); @@ -682,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); @@ -707,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); @@ -730,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) { @@ -751,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)) /* @@ -767,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 */ |
