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.
---
l2vpn.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
lde.c | 71 ++++++++++++++++++++++++++++++++++++---------------------------
lde.h | 16 ++++++++++----
lde_lib.c | 57 +++++++++++++++++++++++++++++++++++++++++---------
logmsg.c | 6 +++---
5 files changed, 167 insertions(+), 54 deletions(-)
diff --git a/l2vpn.c b/l2vpn.c
index 22c9874..e79caa8 100644
--- a/l2vpn.c
+++ b/l2vpn.c
@@ -282,7 +282,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);
@@ -305,7 +305,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;
@@ -316,8 +316,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
@@ -328,9 +347,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);
@@ -349,7 +369,6 @@ l2vpn_recv_pw_status(struct lde_nbr *ln, struct notify_msg
*nm)
/* remote status didn't change */
if (pw->remote_status == nm->pw_status)
return;
-
pw->remote_status = nm->pw_status;
if (l2vpn_pw_ok(pw, fnh))
@@ -358,6 +377,44 @@ 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);
+ 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/lde.c b/lde.c
index 8e82523..fe44aa6 100644
--- a/lde.c
+++ b/lde.c
@@ -253,16 +253,10 @@ lde_dispatch_imsg(int fd, short event, void *bula)
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 */
@@ -820,8 +814,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;
@@ -850,11 +844,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;
@@ -875,8 +866,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);
@@ -888,16 +884,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;
@@ -923,10 +937,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,
@@ -1235,15 +1247,14 @@ lde_change_egress_label(int af, int was_implicit)
RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
/* explicit withdraw */
if (was_implicit)
- lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL,
- NULL);
+ lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLNULL);
else {
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);
}
/* advertise new label of connected prefixes */
diff --git a/lde.h b/lde.h
index 881a4d0..2fcb614 100644
--- a/lde.h
+++ b/lde.h
@@ -134,10 +134,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);
@@ -174,6 +176,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 *);
void lde_gc_timer(int, short, void *);
void lde_gc_start_timer(void);
void lde_gc_stop_timer(void);
@@ -194,8 +198,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/lde_lib.c b/lde_lib.c
index 8d0e974..6a3ac7e 100644
--- a/lde_lib.c
+++ b/lde_lib.c
@@ -386,6 +386,7 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr
*nexthop,
{
struct fec_node *fn;
struct fec_nh *fnh;
+ struct lde_nbr *ln;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
@@ -402,7 +403,8 @@ 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);
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
fn->local_label = NO_LABEL;
if (fn->fec.type == FEC_TYPE_PWID)
fn->data = NULL;
@@ -446,7 +448,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
@@ -580,9 +582,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);
@@ -618,6 +623,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);
@@ -627,7 +637,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);
@@ -648,9 +657,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);
@@ -681,7 +693,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);
@@ -699,10 +711,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) {
@@ -729,7 +745,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))
/*
@@ -740,6 +755,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/logmsg.c b/logmsg.c
index 0778672..2999446 100644
--- a/logmsg.c
+++ b/logmsg.c
@@ -154,7 +154,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:
@@ -168,8 +168,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;
--
1.9.1