summaryrefslogtreecommitdiff
path: root/ldpd/lde_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldpd/lde_lib.c')
-rw-r--r--ldpd/lde_lib.c303
1 files changed, 208 insertions, 95 deletions
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index faadd566ad..4444a1e1ac 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -31,7 +31,7 @@ static int lde_nbr_is_nexthop(struct fec_node *,
static void fec_free(void *);
static struct fec_node *fec_add(struct fec *fec);
static struct fec_nh *fec_nh_add(struct fec_node *, int, union ldpd_addr *,
- uint8_t priority);
+ ifindex_t, uint8_t);
static void fec_nh_del(struct fec_nh *);
RB_GENERATE(fec_tree, fec, entry, fec_compare)
@@ -264,13 +264,14 @@ fec_add(struct fec *fec)
struct fec_nh *
fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
- uint8_t priority)
+ ifindex_t ifindex, uint8_t priority)
{
struct fec_nh *fnh;
LIST_FOREACH(fnh, &fn->nexthops, entry)
if (fnh->af == af &&
ldp_addrcmp(af, &fnh->nexthop, nexthop) == 0 &&
+ fnh->ifindex == ifindex &&
fnh->priority == priority)
return (fnh);
@@ -279,7 +280,7 @@ fec_nh_find(struct fec_node *fn, int af, union ldpd_addr *nexthop,
static struct fec_nh *
fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
- uint8_t priority)
+ ifindex_t ifindex, uint8_t priority)
{
struct fec_nh *fnh;
@@ -289,6 +290,7 @@ fec_nh_add(struct fec_node *fn, int af, union ldpd_addr *nexthop,
fnh->af = af;
fnh->nexthop = *nexthop;
+ fnh->ifindex = ifindex;
fnh->remote_label = NO_LABEL;
fnh->priority = priority;
LIST_INSERT_HEAD(&fn->nexthops, fnh, entry);
@@ -303,87 +305,30 @@ fec_nh_del(struct fec_nh *fnh)
free(fnh);
}
-uint32_t
-egress_label(enum fec_type fec_type)
-{
- switch (fec_type) {
- case FEC_TYPE_IPV4:
- if (ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL)
- return (MPLS_LABEL_IPV4NULL);
- break;
- case FEC_TYPE_IPV6:
- if (ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL)
- return (MPLS_LABEL_IPV6NULL);
- break;
- default:
- fatalx("egress_label: unexpected fec type");
- }
-
- return (MPLS_LABEL_IMPLNULL);
-}
-
void
lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
- uint8_t priority, int connected, void *data)
+ ifindex_t ifindex, uint8_t priority, int connected, void *data)
{
struct fec_node *fn;
struct fec_nh *fnh;
- struct lde_map *me;
- struct lde_nbr *ln;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
fn = fec_add(fec);
- fnh = fec_nh_find(fn, af, nexthop, priority);
- if (fnh != NULL) {
- lde_send_change_klabel(fn, fnh);
- fnh->flags |= F_FEC_NH_NEW;
- return;
- }
-
- if (fn->fec.type == FEC_TYPE_PWID)
+ if (data)
fn->data = data;
- if (fn->local_label == NO_LABEL) {
- if (connected)
- fn->local_label = egress_label(fn->fec.type);
- else
- fn->local_label = lde_assign_label();
-
- /* FEC.1: perform lsr label distribution procedure */
- RB_FOREACH(ln, nbr_tree, &lde_nbrs)
- lde_send_labelmapping(ln, fn, 1);
- }
-
- fnh = fec_nh_add(fn, af, nexthop, priority);
+ fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
+ if (fnh == NULL)
+ fnh = fec_nh_add(fn, af, nexthop, ifindex, priority);
fnh->flags |= F_FEC_NH_NEW;
- lde_send_change_klabel(fn, fnh);
-
- switch (fn->fec.type) {
- case FEC_TYPE_IPV4:
- case FEC_TYPE_IPV6:
- ln = lde_nbr_find_by_addr(af, &fnh->nexthop);
- break;
- case FEC_TYPE_PWID:
- ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
- break;
- default:
- ln = NULL;
- break;
- }
-
- if (ln) {
- /* FEC.2 */
- me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
- if (me)
- /* FEC.5 */
- lde_check_mapping(&me->map, ln);
- }
+ if (connected)
+ fnh->flags |= F_FEC_NH_CONNECTED;
}
void
lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
- uint8_t priority)
+ ifindex_t ifindex, uint8_t priority)
{
struct fec_node *fn;
struct fec_nh *fnh;
@@ -392,19 +337,13 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
if (fn == NULL)
/* route lost */
return;
- fnh = fec_nh_find(fn, af, nexthop, priority);
+ fnh = fec_nh_find(fn, af, nexthop, ifindex, priority);
if (fnh == NULL)
/* route lost */
return;
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
- if (LIST_EMPTY(&fn->nexthops)) {
- lde_send_labelwithdraw_all(fn, NO_LABEL);
- fn->local_label = NO_LABEL;
- if (fn->fec.type == FEC_TYPE_PWID)
- fn->data = NULL;
- }
}
/*
@@ -414,10 +353,12 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
* them (if any), withdraw the associated labels from zebra.
*/
void
-lde_kernel_reevaluate(struct fec *fec)
+lde_kernel_update(struct fec *fec)
{
struct fec_node *fn;
struct fec_nh *fnh, *safe;
+ struct lde_nbr *ln;
+ struct lde_map *me;
fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
@@ -426,9 +367,54 @@ lde_kernel_reevaluate(struct fec *fec)
LIST_FOREACH_SAFE(fnh, &fn->nexthops, entry, safe) {
if (fnh->flags & F_FEC_NH_NEW)
fnh->flags &= ~F_FEC_NH_NEW;
- else
- lde_kernel_remove(fec, fnh->af, &fnh->nexthop,
- fnh->priority);
+ else {
+ lde_send_delete_klabel(fn, fnh);
+ fec_nh_del(fnh);
+ }
+ }
+
+ if (LIST_EMPTY(&fn->nexthops)) {
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelwithdraw(ln, fn, NULL, NULL);
+ fn->local_label = NO_LABEL;
+ fn->data = NULL;
+ } else {
+ uint32_t previous_label;
+
+ previous_label = fn->local_label;
+ fn->local_label = lde_update_label(fn);
+
+ if (fn->local_label != NO_LABEL &&
+ fn->local_label != previous_label) {
+ /* FEC.1: perform lsr label distribution procedure */
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 1);
+ }
+ }
+
+ LIST_FOREACH(fnh, &fn->nexthops, entry) {
+ lde_send_change_klabel(fn, fnh);
+
+ switch (fn->fec.type) {
+ case FEC_TYPE_IPV4:
+ case FEC_TYPE_IPV6:
+ ln = lde_nbr_find_by_addr(fnh->af, &fnh->nexthop);
+ break;
+ case FEC_TYPE_PWID:
+ ln = lde_nbr_find_by_lsrid(fn->fec.u.pwid.lsr_id);
+ break;
+ default:
+ ln = NULL;
+ break;
+ }
+
+ if (ln) {
+ /* FEC.2 */
+ me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec);
+ if (me)
+ /* FEC.5 */
+ lde_check_mapping(&me->map, ln);
+ }
}
}
@@ -444,6 +430,30 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
int msgsource = 0;
lde_map2fec(map, ln->id, &fec);
+
+ switch (fec.type) {
+ case FEC_TYPE_IPV4:
+ if (lde_acl_check(ldeconf->ipv4.acl_label_accept_from,
+ AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT)
+ return;
+ if (lde_acl_check(ldeconf->ipv4.acl_label_accept_for,
+ AF_INET, (union ldpd_addr *)&fec.u.ipv4.prefix,
+ fec.u.ipv4.prefixlen) != FILTER_PERMIT)
+ return;
+ break;
+ case FEC_TYPE_IPV6:
+ if (lde_acl_check(ldeconf->ipv6.acl_label_accept_from,
+ AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT)
+ return;
+ if (lde_acl_check(ldeconf->ipv6.acl_label_accept_for,
+ AF_INET6, (union ldpd_addr *)&fec.u.ipv6.prefix,
+ fec.u.ipv6.prefixlen) != FILTER_PERMIT)
+ return;
+ break;
+ default:
+ break;
+ }
+
fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL)
fn = fec_add(&fec);
@@ -469,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
@@ -545,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? */
@@ -552,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;
}
@@ -566,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;
@@ -596,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;
@@ -603,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);
@@ -615,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);
}
@@ -642,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);
@@ -673,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);
@@ -698,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);
@@ -721,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) {
@@ -742,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))
/*
@@ -758,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 */