diff options
author | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-21 04:52:30 +0000 |
---|---|---|
committer | Renato Westphal <renato@cvs.openbsd.org> | 2015-07-21 04:52:30 +0000 |
commit | a2ae921ed55c91e98ece8ee7f0b365851fb30633 (patch) | |
tree | 40369cff7366d5b45e4df63f807681b223eb63f8 /usr.sbin/ldpd/lde_lib.c | |
parent | 6e1f964c76fe64a2e4d55765a578dbb338c18266 (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.c | 211 |
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) { |