summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ldpd/l2vpn.c71
-rw-r--r--ldpd/lde.c68
-rw-r--r--ldpd/lde.h16
-rw-r--r--ldpd/lde_lib.c56
-rw-r--r--ldpd/log.c6
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;