diff options
-rw-r--r-- | ldpd/l2vpn.c | 71 | ||||
-rw-r--r-- | ldpd/lde.c | 68 | ||||
-rw-r--r-- | ldpd/lde.h | 16 | ||||
-rw-r--r-- | ldpd/lde_lib.c | 56 | ||||
-rw-r--r-- | ldpd/log.c | 6 |
5 files changed, 165 insertions, 52 deletions
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 792608d42..ad3e8199c 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -330,7 +330,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) st.status_code = S_WRONG_CBIT; st.msg_id = map->msg_id; st.msg_type = htons(MSG_TYPE_LABELMAPPING); - lde_send_labelwithdraw(ln, fn, NO_LABEL, &st); + lde_send_labelwithdraw(ln, fn, NULL, &st); pw->flags &= ~F_PW_CWORD; lde_send_labelmapping(ln, fn, 1); @@ -353,7 +353,7 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) } void -l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec) +l2vpn_send_pw_status(struct lde_nbr *ln, uint32_t status, struct fec *fec) { struct notify_msg nm; @@ -364,8 +364,27 @@ l2vpn_send_pw_status(uint32_t peerid, uint32_t status, struct fec *fec) lde_fec2map(fec, &nm.fec); nm.flags |= F_NOTIF_FEC; - lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, peerid, 0, - &nm, sizeof(nm)); + lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, + sizeof(nm)); +} + +void +l2vpn_send_pw_status_wcard(struct lde_nbr *ln, uint32_t status, + uint16_t pw_type, uint32_t group_id) +{ + struct notify_msg nm; + + memset(&nm, 0, sizeof(nm)); + nm.status_code = S_PW_STATUS; + nm.pw_status = status; + nm.flags |= F_NOTIF_PW_STATUS; + nm.fec.type = MAP_TYPE_PWID; + nm.fec.fec.pwid.type = pw_type; + nm.fec.fec.pwid.group_id = group_id; + nm.flags |= F_NOTIF_FEC; + + lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, + sizeof(nm)); } void @@ -376,9 +395,10 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) struct fec_nh *fnh; struct l2vpn_pw *pw; - /* TODO group wildcard */ - if (!(nm->fec.flags & F_MAP_PW_ID)) + if (!(nm->fec.flags & F_MAP_PW_ID)) { + l2vpn_recv_pw_status_wcard(ln, nm); return; + } lde_map2fec(&nm->fec, ln->id, &fec); fn = (struct fec_node *)fec_find(&ft, &fec); @@ -406,6 +426,45 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg *nm) lde_send_delete_klabel(fn, fnh); } +/* RFC4447 PWid group wildcard */ +void +l2vpn_recv_pw_status_wcard(struct lde_nbr *ln, struct notify_msg *nm) +{ + struct fec *f; + struct fec_node *fn; + struct fec_nh *fnh; + struct l2vpn_pw *pw; + + RB_FOREACH(f, fec_tree, &ft) { + fn = (struct fec_node *)f; + if (fn->fec.type != FEC_TYPE_PWID) + continue; + if (fn->fec.u.pwid.type != nm->fec.fec.pwid.type) + continue; + + pw = (struct l2vpn_pw *) fn->data; + if (pw == NULL) + continue; + if (pw->remote_group != nm->fec.fec.pwid.group_id) + continue; + + fnh = fec_nh_find(fn, AF_INET, (union ldpd_addr *)&ln->id, + 0, 0); + if (fnh == NULL) + continue; + + /* remote status didn't change */ + if (pw->remote_status == nm->pw_status) + continue; + pw->remote_status = nm->pw_status; + + if (l2vpn_pw_ok(pw, fnh)) + lde_send_change_klabel(fn, fnh); + else + lde_send_delete_klabel(fn, fnh); + } +} + void l2vpn_sync_pws(int af, union ldpd_addr *addr) { diff --git a/ldpd/lde.c b/ldpd/lde.c index 6ac0f07da..3041c44bd 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -259,16 +259,10 @@ lde_dispatch_imsg(struct thread *thread) lde_check_request(&map, ln); break; case IMSG_LABEL_RELEASE: - if (map.type == MAP_TYPE_WILDCARD) - lde_check_release_wcard(&map, ln); - else - lde_check_release(&map, ln); + lde_check_release(&map, ln); break; case IMSG_LABEL_WITHDRAW: - if (map.type == MAP_TYPE_WILDCARD) - lde_check_withdraw_wcard(&map, ln); - else - lde_check_withdraw(&map, ln); + lde_check_withdraw(&map, ln); break; case IMSG_LABEL_ABORT: /* not necessary */ @@ -929,8 +923,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) } void -lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, - struct status_tlv *st) +lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, + struct map *wcard, struct status_tlv *st) { struct lde_wdraw *lw; struct map map; @@ -959,11 +953,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, break; } map.label = fn->local_label; - } else { - memset(&map, 0, sizeof(map)); - map.type = MAP_TYPE_WILDCARD; - map.label = label; - } + } else + memcpy(&map, wcard, sizeof(map)); if (st) { map.st.status_code = st->status_code; @@ -984,8 +975,13 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, lw = lde_wdraw_add(ln, fn); lw->label = map.label; } else { + struct lde_map *me; + RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; + me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); + if (lde_wildcard_apply(wcard, &fn->fec, me) == 0) + continue; lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); @@ -997,16 +993,34 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, } void -lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label) +lde_send_labelwithdraw_wcard(struct lde_nbr *ln, uint32_t label) { - struct lde_nbr *ln; + struct map wcard; - RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelwithdraw(ln, fn, label, NULL); + memset(&wcard, 0, sizeof(wcard)); + wcard.type = MAP_TYPE_WILDCARD; + wcard.label = label; + lde_send_labelwithdraw(ln, NULL, &wcard, NULL); } void -lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) +lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *ln, uint16_t pw_type, + uint32_t group_id) +{ + struct map wcard; + + memset(&wcard, 0, sizeof(wcard)); + wcard.type = MAP_TYPE_PWID; + wcard.fec.pwid.type = pw_type; + wcard.fec.pwid.group_id = group_id; + /* we can not append a Label TLV when using PWid group wildcards. */ + wcard.label = NO_LABEL; + lde_send_labelwithdraw(ln, NULL, &wcard, NULL); +} + +void +lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, + struct map *wcard, uint32_t label) { struct map map; struct l2vpn_pw *pw; @@ -1032,10 +1046,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) map.flags |= F_MAP_PW_CWORD; break; } - } else { - memset(&map, 0, sizeof(map)); - map.type = MAP_TYPE_WILDCARD; - } + } else + memcpy(&map, wcard, sizeof(map)); map.label = label; lde_imsg_compose_ldpe(IMSG_RELEASE_ADD, ln->peerid, 0, @@ -1352,13 +1364,11 @@ lde_change_egress_label(int af) /* explicitly withdraw all null labels */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) { - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL); if (ln->v4_enabled) - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL, - NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4NULL); if (ln->v6_enabled) - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL, - NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6NULL); } /* update label of connected routes */ diff --git a/ldpd/lde.h b/ldpd/lde.h index b3fa2d469..367ba254d 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -143,10 +143,12 @@ void lde_map2fec(struct map *, struct in_addr, struct fec *); void lde_send_labelmapping(struct lde_nbr *, struct fec_node *, int); void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, - uint32_t, struct status_tlv *); -void lde_send_labelwithdraw_all(struct fec_node *, uint32_t); -void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, + struct map *, struct status_tlv *); +void lde_send_labelwithdraw_wcard(struct lde_nbr *, uint32_t); +void lde_send_labelwithdraw_pwid_wcard(struct lde_nbr *, uint16_t, uint32_t); +void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, + struct map *, uint32_t); void lde_send_notification(struct lde_nbr *, uint32_t, uint32_t, uint16_t); struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr); @@ -183,6 +185,8 @@ void lde_check_release(struct map *, struct lde_nbr *); void lde_check_release_wcard(struct map *, struct lde_nbr *); void lde_check_withdraw(struct map *, struct lde_nbr *); void lde_check_withdraw_wcard(struct map *, struct lde_nbr *); +int lde_wildcard_apply(struct map *, struct fec *, + struct lde_map *); int lde_gc_timer(struct thread *); void lde_gc_start_timer(void); void lde_gc_stop_timer(void); @@ -205,8 +209,12 @@ void l2vpn_pw_reset(struct l2vpn_pw *); int l2vpn_pw_ok(struct l2vpn_pw *, struct fec_nh *); int l2vpn_pw_negotiate(struct lde_nbr *, struct fec_node *, struct map *); -void l2vpn_send_pw_status(uint32_t, uint32_t, struct fec *); +void l2vpn_send_pw_status(struct lde_nbr *, uint32_t, struct fec *); +void l2vpn_send_pw_status_wcard(struct lde_nbr *, uint32_t, + uint16_t, uint32_t); void l2vpn_recv_pw_status(struct lde_nbr *, struct notify_msg *); +void l2vpn_recv_pw_status_wcard(struct lde_nbr *, + struct notify_msg *); void l2vpn_sync_pws(int, union ldpd_addr *); void l2vpn_pw_ctl(pid_t); void l2vpn_binding_ctl(pid_t); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index 02730189a..c37a9e966 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 @@ -612,9 +613,12 @@ 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_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); @@ -650,6 +654,11 @@ 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); @@ -659,7 +668,6 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) } /* 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); @@ -680,9 +688,12 @@ 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_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); @@ -713,7 +724,7 @@ lde_check_withdraw(struct map *map, struct lde_nbr *ln) } /* 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); @@ -731,10 +742,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) { @@ -761,7 +776,6 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) } /* 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)) /* @@ -772,6 +786,28 @@ 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_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 */ diff --git a/ldpd/log.c b/ldpd/log.c index 77efdb471..661fe04b1 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -313,7 +313,7 @@ log_hello_src(const struct hello_source *src) const char * log_map(const struct map *map) { - static char buf[64]; + static char buf[128]; switch (map->type) { case MAP_TYPE_WILDCARD: @@ -327,8 +327,8 @@ log_map(const struct map *map) return ("???"); break; case MAP_TYPE_PWID: - if (snprintf(buf, sizeof(buf), "pwid %u (%s)", - map->fec.pwid.pwid, + if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)", + map->fec.pwid.pwid, map->fec.pwid.group_id, pw_type_name(map->fec.pwid.type)) == -1) return ("???"); break; |