diff options
author | Renato Westphal <renato@opensourcerouting.org> | 2017-03-03 21:50:22 +0100 |
---|---|---|
committer | Renato Westphal <renato@opensourcerouting.org> | 2017-03-03 21:50:22 +0100 |
commit | 0bcc2916a08dfb762d8a5775e6b01a4885c8936a (patch) | |
tree | 09d352749f431edd8c51ba9ade3dd2b64ac4b2dc /ldpd | |
parent | ldpd: fix processing of Label Withdraw messages (diff) | |
download | frr-0bcc2916a08dfb762d8a5775e6b01a4885c8936a.tar.xz frr-0bcc2916a08dfb762d8a5775e6b01a4885c8936a.zip |
ldpd: implement support for PWid group wildcards
This was missing from our original RFC 4447 VPLS implementation. Now
ldpd understands group wildcards as mandated by the RFC, but we still
don't send them ourselves. I can't see any case in which sending a group
wildcard would be useful, but nonetheless this patch provides a function
called lde_send_labelwithdraw_pwid_wcard() which is ready to be used in
the future anytime we feel like it might be useful.
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
Diffstat (limited to 'ldpd')
-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; |