summaryrefslogtreecommitdiff
path: root/usr.sbin/ldpd/lde_lib.c
diff options
context:
space:
mode:
authorRenato Westphal <renato@cvs.openbsd.org>2015-07-21 04:52:30 +0000
committerRenato Westphal <renato@cvs.openbsd.org>2015-07-21 04:52:30 +0000
commita2ae921ed55c91e98ece8ee7f0b365851fb30633 (patch)
tree40369cff7366d5b45e4df63f807681b223eb63f8 /usr.sbin/ldpd/lde_lib.c
parent6e1f964c76fe64a2e4d55765a578dbb338c18266 (diff)
VPLS signaling support.
This patch introduces full support for pseudowire signaling in ldpd(8), including Control Word and Status TLV negotiation. As of now it's not possible to configure a VPWS, but the signaling is the same. In the future, when VPWS support is available in the kernel, ldpd(8) can be extended to support VPWS with only a few modifications. Limitations: * No support for FEC 129, only FEC 128 (more widely deployed); * No support for group withdraws (not widely deployed); * No support for MAC withdraws (not widely deployed). Related RFCs: * RFC 3916: Requirements for Pseudo-Wire Emulation Edge-to-Edge (PWE3) * RFC 3985: Pseudo Wire Emulation Edge-to-Edge (PWE3) Architecture * RFC 4385: Pseudowire Emulation Edge-to-Edge (PWE3) Control Word for Use over an MPLS PSN * RFC 4446: IANA Allocations for Pseudowire Edge to Edge Emulation (PWE3) * RFC 4447: Pseudowire Setup and Maintenance Using the Label Distribution Protocol (LDP) * RFC 4448: Encapsulation Methods for Transport of Ethernet over MPLS Networks * RFC 4905: Encapsulation Methods for Transport of Layer 2 Frames over MPLS Networks * RFC 4906: Transport of Layer 2 Frames Over MPLS ok claudio@
Diffstat (limited to 'usr.sbin/ldpd/lde_lib.c')
-rw-r--r--usr.sbin/ldpd/lde_lib.c211
1 files changed, 124 insertions, 87 deletions
diff --git a/usr.sbin/ldpd/lde_lib.c b/usr.sbin/ldpd/lde_lib.c
index b21c1d92477..d95da676cf7 100644
--- a/usr.sbin/ldpd/lde_lib.c
+++ b/usr.sbin/ldpd/lde_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lde_lib.c,v 1.39 2015/07/21 04:48:42 renato Exp $ */
+/* $OpenBSD: lde_lib.c,v 1.40 2015/07/21 04:52:29 renato Exp $ */
/*
* Copyright (c) 2009 Michele Marchetto <michele@openbsd.org>
@@ -41,8 +41,7 @@
static int fec_compare(struct fec *, struct fec *);
void fec_free(void *);
-struct fec_node *fec_add(struct in_addr, u_int8_t);
-struct fec_nh *fec_nh_find(struct fec_node *, struct in_addr);
+struct fec_node *fec_add(struct fec *fec);
struct fec_nh *fec_nh_add(struct fec_node *, struct in_addr);
void fec_nh_del(struct fec_nh *);
int lde_nbr_is_nexthop(struct fec_node *, struct lde_nbr *);
@@ -66,27 +65,45 @@ fec_init(struct fec_tree *fh)
static int
fec_compare(struct fec *a, struct fec *b)
{
- if (ntohl(a->prefix.s_addr) < ntohl(b->prefix.s_addr))
+ if (a->type < b->type)
return (-1);
- if (ntohl(a->prefix.s_addr) > ntohl(b->prefix.s_addr))
+ if (a->type > b->type)
return (1);
- if (a->prefixlen < b->prefixlen)
- return (-1);
- if (a->prefixlen > b->prefixlen)
- return (1);
-
- return (0);
-}
-struct fec *
-fec_find_prefix(struct fec_tree *fh, in_addr_t prefix, u_int8_t prefixlen)
-{
- struct fec s;
-
- s.prefix.s_addr = prefix;
- s.prefixlen = prefixlen;
+ switch (a->type) {
+ case FEC_TYPE_IPV4:
+ if (ntohl(a->u.ipv4.prefix.s_addr) <
+ ntohl(b->u.ipv4.prefix.s_addr))
+ return (-1);
+ if (ntohl(a->u.ipv4.prefix.s_addr) >
+ ntohl(b->u.ipv4.prefix.s_addr))
+ return (1);
+ if (a->u.ipv4.prefixlen < b->u.ipv4.prefixlen)
+ return (-1);
+ if (a->u.ipv4.prefixlen > b->u.ipv4.prefixlen)
+ return (1);
+ return (0);
+ break;
+ case FEC_TYPE_PWID:
+ if (a->u.pwid.type < b->u.pwid.type)
+ return (-1);
+ if (a->u.pwid.type > b->u.pwid.type)
+ return (1);
+ if (a->u.pwid.pwid < b->u.pwid.pwid)
+ return (-1);
+ if (a->u.pwid.pwid > b->u.pwid.pwid)
+ return (1);
+ if (ntohl(a->u.pwid.nexthop.s_addr) <
+ ntohl(b->u.pwid.nexthop.s_addr))
+ return (-1);
+ if (ntohl(a->u.pwid.nexthop.s_addr) >
+ ntohl(b->u.pwid.nexthop.s_addr))
+ return (1);
+ return (0);
+ break;
+ }
- return (fec_find(fh, &s));
+ return (-1);
}
struct fec *
@@ -107,8 +124,7 @@ int
fec_remove(struct fec_tree *fh, struct fec *f)
{
if (RB_REMOVE(fec_tree, fh, f) == NULL) {
- log_warnx("fec_remove failed for %s/%u",
- inet_ntoa(f->prefix), f->prefixlen);
+ log_warnx("fec_remove failed for %s", log_fec(f));
return (-1);
}
return (0);
@@ -148,13 +164,15 @@ rt_dump(pid_t pid)
RB_FOREACH(f, fec_tree, &ft) {
fn = (struct fec_node *)f;
+ if (fn->fec.type != FEC_TYPE_IPV4)
+ continue;
+
if (fn->local_label == NO_LABEL &&
LIST_EMPTY(&fn->downstream))
continue;
- rtctl.prefix = fn->fec.prefix;
- rtctl.prefixlen = fn->fec.prefixlen;
- rtctl.flags = fn->flags;
+ rtctl.prefix = fn->fec.u.ipv4.prefix;
+ rtctl.prefixlen = fn->fec.u.ipv4.prefixlen;
rtctl.local_label = fn->local_label;
LIST_FOREACH(me, &fn->downstream, entry) {
@@ -188,7 +206,7 @@ fec_snap(struct lde_nbr *ln)
if (fn->local_label == NO_LABEL)
continue;
- lde_send_labelmapping(ln, fn);
+ lde_send_labelmapping(ln, fn, 0);
count++;
}
if (count > 0)
@@ -205,11 +223,11 @@ fec_free(void *arg)
while ((fnh = LIST_FIRST(&fn->nexthops)))
fec_nh_del(fnh);
if (!LIST_EMPTY(&fn->downstream))
- log_warnx("fec_free: fec %s/%u downstream list not empty",
- inet_ntoa(fn->fec.prefix), fn->fec.prefixlen);
+ log_warnx("fec_free: fec %s downstream list not empty",
+ log_fec(&fn->fec));
if (!LIST_EMPTY(&fn->upstream))
- log_warnx("fec_free: fec %s/%u upstream list not empty",
- inet_ntoa(fn->fec.prefix), fn->fec.prefixlen);
+ log_warnx("fec_free: fec %s upstream list not empty",
+ log_fec(&fn->fec));
free(fn);
}
@@ -221,7 +239,7 @@ fec_tree_clear(void)
}
struct fec_node *
-fec_add(struct in_addr prefix, u_int8_t prefixlen)
+fec_add(struct fec *fec)
{
struct fec_node *fn;
@@ -229,16 +247,15 @@ fec_add(struct in_addr prefix, u_int8_t prefixlen)
if (fn == NULL)
fatal("fec_add");
- fn->fec.prefix.s_addr = prefix.s_addr;
- fn->fec.prefixlen = prefixlen;
+ memcpy(&fn->fec, fec, sizeof(fn->fec));
fn->local_label = NO_LABEL;
LIST_INIT(&fn->upstream);
LIST_INIT(&fn->downstream);
LIST_INIT(&fn->nexthops);
if (fec_insert(&ft, &fn->fec))
- log_warnx("failed to add %s/%u to ft tree",
- inet_ntoa(fn->fec.prefix), fn->fec.prefixlen);
+ log_warnx("failed to add %s to ft tree",
+ log_fec(&fn->fec));
return (fn);
}
@@ -278,35 +295,33 @@ fec_nh_del(struct fec_nh *fnh)
}
void
-lde_kernel_insert(struct kroute *kr)
+lde_kernel_insert(struct fec *fec, struct in_addr nexthop, int connected,
+ void *data)
{
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_map *me;
struct lde_nbr *ln;
- char buf[16];
- log_debug("kernel add route %s/%u nexthop %s",
- inet_ntoa(kr->prefix), kr->prefixlen,
- inet_ntop(AF_INET, &kr->nexthop, buf, sizeof(buf)));
+ log_debug("lde add fec %s nexthop %s",
+ log_fec(fec), inet_ntoa(nexthop));
- fn = (struct fec_node *)fec_find_prefix(&ft, kr->prefix.s_addr,
- kr->prefixlen);
+ fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
- fn = fec_add(kr->prefix, kr->prefixlen);
+ fn = fec_add(fec);
- if (fec_nh_find(fn, kr->nexthop) != NULL)
+ if (fec_nh_find(fn, nexthop) != NULL)
return;
if (LIST_EMPTY(&fn->nexthops)) {
if (fn->local_label == NO_LABEL) {
- if (kr->flags & F_CONNECTED)
+ if (connected)
fn->local_label = MPLS_LABEL_IMPLNULL;
else
fn->local_label = lde_assign_label();
} else {
/* Handle local label changes */
- if ((kr->flags & F_CONNECTED) &&
+ if (connected &&
fn->local_label != MPLS_LABEL_IMPLNULL) {
/* explicit withdraw of the previous label */
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
@@ -314,7 +329,7 @@ lde_kernel_insert(struct kroute *kr)
fn->local_label = MPLS_LABEL_IMPLNULL;
}
- if (!(kr->flags & F_CONNECTED) &&
+ if (!connected &&
fn->local_label == MPLS_LABEL_IMPLNULL) {
/* explicit withdraw of the previous label */
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
@@ -324,16 +339,13 @@ lde_kernel_insert(struct kroute *kr)
}
/* FEC.1: perform lsr label distribution procedure */
- RB_FOREACH(ln, nbr_tree, &lde_nbrs) {
- lde_send_labelmapping(ln, fn);
- lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END,
- ln->peerid, 0, NULL, 0);
- }
+ RB_FOREACH(ln, nbr_tree, &lde_nbrs)
+ lde_send_labelmapping(ln, fn, 1);
}
- fnh = fec_nh_add(fn, kr->nexthop);
+ fnh = fec_nh_add(fn, nexthop);
+ fnh->data = data;
lde_send_change_klabel(fn, fnh);
-
ln = lde_find_address(fnh->nexthop);
if (ln) {
/* FEC.2 */
@@ -345,28 +357,26 @@ lde_kernel_insert(struct kroute *kr)
}
void
-lde_kernel_remove(struct kroute *kr)
+lde_kernel_remove(struct fec *fec, struct in_addr nexthop)
{
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_nbr *ln;
- char buf[16];
- log_debug("kernel remove route %s/%u nexthop %s",
- inet_ntoa(kr->prefix), kr->prefixlen,
- inet_ntop(AF_INET, &kr->nexthop, buf, sizeof(buf)));
+ log_debug("lde remove fec %s nexthop %s",
+ log_fec(fec), inet_ntoa(nexthop));
- fn = (struct fec_node *)fec_find_prefix(&ft, kr->prefix.s_addr,
- kr->prefixlen);
+ fn = (struct fec_node *)fec_find(&ft, fec);
if (fn == NULL)
/* route lost */
return;
- fnh = fec_nh_find(fn, kr->nexthop);
+ fnh = fec_nh_find(fn, nexthop);
if (fnh == NULL)
/* route lost */
return;
+ lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
if (LIST_EMPTY(&fn->nexthops))
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
@@ -376,17 +386,19 @@ lde_kernel_remove(struct kroute *kr)
void
lde_check_mapping(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_req *lre;
struct lde_nbr_address *addr;
struct lde_map *me;
+ struct l2vpn_pw *pw;
int msgsource = 0;
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL)
- fn = fec_add(map->prefix, map->prefixlen);
+ fn = fec_add(&fec);
/* LMp.1: first check if we have a pending request running */
lre = (struct lde_req *)fec_find(&ln->sent_req, &fn->fec);
@@ -394,6 +406,10 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
/* LMp.2: delete record of outstanding label request */
lde_req_del(ln, lre, 1);
+ /* RFC 4447 control word and status tlv negotiation */
+ if (map->type == FEC_PWID && l2vpn_pw_negotiate(ln, fn, map))
+ return;
+
/*
* LMp.3 - LMp.8: Loop detection LMp.3 - unecessary for frame-mode
* mpls networks
@@ -422,27 +438,38 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
* support multipath
*/
LIST_FOREACH(fnh, &fn->nexthops, entry) {
- if (lde_address_find(ln, &fnh->nexthop)) {
- msgsource = 1;
+ if (lde_address_find(ln, &fnh->nexthop) == NULL)
+ continue;
- /* LMp.15: install FEC in FIB */
- fnh->remote_label = map->label;
+ msgsource = 1;
+
+ /* LMp.15: install FEC in FIB */
+ fnh->remote_label = map->label;
+ switch (map->type) {
+ case FEC_PREFIX:
lde_send_change_klabel(fn, fnh);
+ break;
+ case FEC_PWID:
+ pw = (struct l2vpn_pw *) fnh->data;
+ pw->remote_group = map->fec.pwid.group_id;
+ if (map->flags & F_MAP_PW_IFMTU)
+ pw->remote_mtu = map->fec.pwid.ifmtu;
+ if (map->flags & F_MAP_PW_STATUS)
+ pw->remote_status = map->pw_status;
+ if (l2vpn_pw_ok(pw, fnh))
+ lde_send_change_klabel(fn, fnh);
+ break;
}
}
- if (msgsource == 0) {
- /* LMp.13: perform lsr label release procedure */
- if (me == NULL)
- me = lde_map_add(ln, fn, 0);
- memcpy(&me->map, map, sizeof(*map));
- return;
- }
-
- /* LMp.16: Record the mapping from this peer */
+ /* LMp.13 & LMp.16: Record the mapping from this peer */
if (me == NULL)
me = lde_map_add(ln, fn, 0);
memcpy(&me->map, map, sizeof(*map));
+ if (msgsource == 0)
+ /* LMp.13: just return since we use liberal lbl retention */
+ return;
+
/*
* LMp.17 - LMp.27 are unnecessary since we don't need to implement
* loop detection. LMp.28 - LMp.30 are unnecessary because we are
@@ -453,6 +480,7 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln)
void
lde_check_request(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct lde_req *lre;
struct fec_node *fn;
struct fec_nh *fnh;
@@ -460,8 +488,8 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
/* TODO LRq.1: loop detection */
/* LRq.2: is there a next hop for fec? */
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL || LIST_EMPTY(&fn->nexthops)) {
lde_send_notification(ln->peerid, S_NO_ROUTE, map->messageid,
MSG_TYPE_LABELREQUEST);
@@ -489,8 +517,7 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
lre->msgid = map->messageid;
/* LRq.9: perform LSR label distribution */
- lde_send_labelmapping(ln, fn);
- lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0);
+ lde_send_labelmapping(ln, fn, 1);
/*
* LRq.10: do nothing (Request Never) since we use liberal
@@ -502,12 +529,17 @@ lde_check_request(struct map *map, struct lde_nbr *ln)
void
lde_check_release(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct fec_node *fn;
struct lde_wdraw *lw;
struct lde_map *me;
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ /* TODO group wildcard */
+ if (!(map->flags & F_MAP_PW_ID))
+ return;
+
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
/* LRl.1: does FEC match a known FEC? */
if (fn == NULL)
return;
@@ -567,14 +599,19 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln)
void
lde_check_withdraw(struct map *map, struct lde_nbr *ln)
{
+ struct fec fec;
struct fec_node *fn;
struct fec_nh *fnh;
struct lde_map *me;
- fn = (struct fec_node *)fec_find_prefix(&ft, map->prefix.s_addr,
- map->prefixlen);
+ /* TODO group wildcard */
+ if (!(map->flags & F_MAP_PW_ID))
+ return;
+
+ lde_map2fec(map, ln->id, &fec);
+ fn = (struct fec_node *)fec_find(&ft, &fec);
if (fn == NULL)
- fn = fec_add(map->prefix, map->prefixlen);
+ fn = fec_add(&fec);
/* LWd.1: remove label from forwarding/switching use */
LIST_FOREACH(fnh, &fn->nexthops, entry) {