Add ldpd, a RFC 3036 compatible LDP speaker.

This commit is contained in:
kefren 2010-12-08 07:20:14 +00:00
parent fc8e4c2763
commit e7341ada4c
31 changed files with 5890 additions and 2 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.248 2010/12/05 05:59:17 christos Exp $
# $NetBSD: Makefile,v 1.249 2010/12/08 07:20:14 kefren Exp $
# from: @(#)Makefile 5.20 (Berkeley) 6/12/93
.include <bsd.own.mk>
@ -11,7 +11,7 @@ SUBDIR= ac accton acpitools altq apm apmd arp bad144 bootp \
gpioctl grfconfig grfinfo gspa hdaudioctl hilinfo ifwatchd inetd \
installboot \
iopctl iostat ipwctl irdaattach isdn iteconfig iwictl\
kgmon lastlogin link lmcconfig lockstat lpr mailwrapper makefs \
kgmon lastlogin ldpd link lmcconfig lockstat lpr mailwrapper makefs \
map-mbone mdconfig memswitch mlxctl mmcformat mopd mountd moused \
mrinfo mrouted mscdlabel mtrace \
mtree ndbootd ndiscvt netgroup_mkdb nfsd ofctl paxctl pcictl \

26
usr.sbin/ldpd/Makefile Normal file
View File

@ -0,0 +1,26 @@
# $NetBSD: Makefile,v 1.1 2010/12/08 07:20:14 kefren Exp $
.include <bsd.own.mk>
PROG= ldpd
MAN= ldpd.8
SRCS= fsm.c \
label.c \
ldp_command.c \
ldp_errors.c \
ldp_peer.c \
main.c \
mpls_interface.c \
mpls_routes.c \
notifications.c \
pdu.c \
socketops.c \
tlv.c \
tlv_stack.c
CFLAGS= -Wall -g
LDADD+= -lcrypt
.include <bsd.prog.mk>

12
usr.sbin/ldpd/TODO Normal file
View File

@ -0,0 +1,12 @@
# $NetBSD: TODO,v 1.1 2010/12/08 07:20:14 kefren Exp $
TODO
====
* send notifications for every error I encounter - kefren
* document better Label Distribution (downstream on demand or
unsolicited downstream), distribution control (independent or
ordered) and retention mode (liberal or conservative) - kefren
* config/options file
* future: IPv6 support. Have no infrastructure to test right
now - kefren

220
usr.sbin/ldpd/fsm.c Normal file
View File

@ -0,0 +1,220 @@
/* $NetBSD: fsm.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include "ldp.h"
#include "ldp_peer.h"
#include "socketops.h"
#include "ldp_errors.h"
#include "fsm.h"
char my_ldp_id[20];
struct sockaddr mplssockaddr;
/* Processing a hello */
void
run_ldp_hello(struct ldp_pdu * pduid, struct hello_tlv * ht,
struct in_addr * padd, struct in_addr * ladd, int mysock)
{
struct ldp_peer *peer = NULL;
struct in_addr peer_addr;
struct transport_address_tlv *trtlv;
struct hello_info *hi;
if ((!pduid) || (!ht))
return;
debugp("Received it on address: %s\n", inet_ntoa(*ladd));
debugp("Hello: Type: 0x%.4X Length: %.2d ID: %.8X\n", ht->type,
ht->length, ht->messageid);
/* Add it to hello list or just update timer */
SLIST_FOREACH(hi, &hello_info_head, infos)
if (hi->ldp_id.s_addr == pduid->ldp_id.s_addr)
break;
if (hi == NULL) {
hi = (struct hello_info *)malloc(sizeof(struct hello_info));
if (!hi) {
fatalp("Cannot alloc a hello info");
return;
}
hi->ldp_id.s_addr = pduid->ldp_id.s_addr;
SLIST_INSERT_HEAD(&hello_info_head, hi, infos);
} else
/* Just update timer */
hi->keepalive = LDP_HELLO_KEEP;
if (ht->length > 4) { /* Common hello parameters */
ht->ch.type = ntohs(ht->ch.type);
ht->ch.length = ntohs(ht->ch.length);
ht->ch.holdtime = ntohs(ht->ch.holdtime);
ht->ch.res = ntohs(ht->ch.res);
debugp("Common hello Type: 0x%.4X Length: %.2d R:%d T:%d"
"Hold time: %d\n", ht->ch.type, ht->ch.length,
ht->ch.tr / 2, ht->ch.tr % 2, ht->ch.holdtime);
if (ht->ch.holdtime)
hi->keepalive = ht->ch.holdtime;
if (!get_ldp_peer(&pduid->ldp_id)) {
/* First of all set peer_addr to announced LDP_ID */
memcpy(&peer_addr, &pduid->ldp_id,
sizeof(struct in_addr));
/*
* Now let's see if there is any transport TLV in
* there
*/
if (pduid->length - PDU_PAYLOAD_LENGTH -
sizeof(struct hello_tlv) > 3) {
trtlv = (struct transport_address_tlv *) &ht[1];
if (trtlv->type == TLV_IPV4_TRANSPORT)
memcpy(&peer_addr, &trtlv->address,
sizeof(struct in_addr));
}
/*
* RFC says: If A1 > A2, LSR1 plays the active role;
* otherwise it is passive.
*/
if (ntohl(peer_addr.s_addr) < ntohl(ladd->s_addr)) {
#define TRADDR (trtlv && trtlv->type == TLV_IPV4_TRANSPORT) ? &peer_addr : NULL
peer = ldp_peer_new(&pduid->ldp_id, padd,
TRADDR, ht->ch.holdtime, 0);
if (!peer)
return;
if (peer && peer->state == LDP_PEER_CONNECTED)
send_initialize(peer);
}
}
}
}
struct address_list_tlv *
build_address_list_tlv(void)
{
struct address_list_tlv *t;
struct ifaddrs *ifa, *ifb;
struct sockaddr_in *sa;
struct in_addr *ia;
uint16_t adrcount = 0;
if (getifaddrs(&ifa) == -1)
return NULL;
/* Find out the number of addresses */
/* Ignore loopback */
for (ifb = ifa; ifb; ifb = ifb->ifa_next)
if ((ifb->ifa_addr->sa_family == AF_INET) &&
(ifb->ifa_flags & IFF_UP)) {
sa = (struct sockaddr_in *) ifb->ifa_addr;
if (sa->sin_addr.s_addr << 24 >> 24 != 127)
adrcount++;
}
t = (struct address_list_tlv *) malloc(sizeof(struct address_list_tlv)
+ (adrcount - 1) * sizeof(struct in_addr));
if (!t) {
fatalp("build_address_list_tlv: malloc problem\n");
return NULL;
}
t->type = htons(LDP_ADDRESS);
t->length = htons(sizeof(struct address_list_tlv) - TLV_TYPE_LENGTH
+ (adrcount - 1) * sizeof(struct in_addr));
t->messageid = htonl(get_message_id());
t->a_type = htons(TLV_ADDRESS_LIST);
t->a_length = htons(sizeof(t->a_af) +
adrcount * sizeof(struct in_addr));
t->a_af = htons(LDP_AF_INET);
ia = &t->a_address;
for (adrcount = 0, ifb = ifa; ifb; ifb = ifb->ifa_next) {
if ((ifb->ifa_addr->sa_family != AF_INET) ||
(!(ifb->ifa_flags & IFF_UP)) ||
(ifb->ifa_flags & IFF_LOOPBACK))
continue;
sa = (struct sockaddr_in *) ifb->ifa_addr;
memcpy(&ia[adrcount], &sa->sin_addr, sizeof(struct in_addr));
adrcount++;
}
freeifaddrs(ifa);
add_my_if_addrs(ia, adrcount);
return t;
}
/*
* Calculate LDP ID
* Get also mpls pseudo-interface address
*/
int
set_my_ldp_id()
{
struct ifaddrs *ifa, *ifb;
struct in_addr a;
struct sockaddr_in *sa;
a.s_addr = 0;
my_ldp_id[0] = 0;
mplssockaddr.sa_len = 0;
if (getifaddrs(&ifa) == -1)
return LDP_E_GENERIC;
for (ifb = ifa; ifb; ifb = ifb->ifa_next)
if(ifb->ifa_flags & IFF_UP) {
if (strncmp("mpls", ifb->ifa_name, 4) == 0 &&
ifb->ifa_addr->sa_family == AF_LINK)
memcpy(&mplssockaddr, ifb->ifa_addr,
ifb->ifa_addr->sa_len);
if (ifb->ifa_addr->sa_family != AF_INET)
continue;
sa = (struct sockaddr_in *) ifb->ifa_addr;
if (ntohl(sa->sin_addr.s_addr) >> 24 == 127)
continue; /* No 127/8 */
if (ntohl(sa->sin_addr.s_addr) > ntohl(a.s_addr))
a.s_addr = sa->sin_addr.s_addr;
}
freeifaddrs(ifa);
debugp("LDP ID: %s\n", inet_ntoa(a));
strlcpy(my_ldp_id, inet_ntoa(a), INET_ADDRSTRLEN);
return LDP_E_OK;
}

43
usr.sbin/ldpd/fsm.h Normal file
View File

@ -0,0 +1,43 @@
/* $NetBSD: fsm.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _FSM_H_
#define _FSM_H_
#include "tlv.h"
#include "pdu.h"
void run_ldp_hello(struct ldp_pdu *, struct hello_tlv *,
struct in_addr *, struct in_addr *, int);
struct address_list_tlv * build_address_list_tlv(void);
int set_my_ldp_id(void);
#endif /* !_FSM_H_ */

279
usr.sbin/ldpd/label.c Normal file
View File

@ -0,0 +1,279 @@
/* $NetBSD: label.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <netmpls/mpls.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "ldp.h"
#include "tlv_stack.h"
#include "mpls_routes.h"
#include "label.h"
#include "ldp_errors.h"
void
label_init()
{
SLIST_INIT(&label_head);
}
/*
* if binding == 0 it receives a free one
*/
struct label *
label_add(union sockunion * so_dest, union sockunion * so_pref,
union sockunion * so_gate, uint32_t binding, struct ldp_peer * p,
uint32_t label)
{
struct label *l;
char spreftmp[INET_ADDRSTRLEN];
l = (struct label *) malloc(sizeof(struct label));
memset(l, 0, sizeof(struct label));
if (!l) {
fatalp("label_add: malloc problem\n");
return NULL;
}
assert(so_dest);
assert(so_pref);
assert(so_dest->sa.sa_family == so_pref->sa.sa_family);
memcpy(&l->so_dest, so_dest, sizeof(union sockunion));
memcpy(&l->so_pref, so_pref, sizeof(union sockunion));
if (so_gate)
memcpy(&l->so_gate, so_gate, sizeof(union sockunion));
if (binding)
l->binding = binding;
else
l->binding = get_free_local_label();
l->p = p;
l->label = label;
SLIST_INSERT_HEAD(&label_head, l, labels);
strlcpy(spreftmp, union_ntoa(so_pref), INET_ADDRSTRLEN);
warnp("[label_add] added binding %d for %s/%s\n", l->binding,
union_ntoa(so_dest), spreftmp);
send_label_tlv_to_all(&(so_dest->sin.sin_addr),
from_union_to_cidr(so_pref), l->binding);
return l;
}
/* Unlink a label */
void
label_del(struct label * l)
{
warnp("[label_del] deleted binding %d for %s\n", l->binding,
union_ntoa(&l->so_dest));
SLIST_REMOVE(&label_head, l, label, labels);
free(l);
}
/*
* Delete or Reuse the old IPv4 route, delete MPLS route (if any)
*/
void
label_reattach_route(struct label *l, int readd)
{
union sockunion *u;
union sockunion emptysu;
struct rt_msg rg;
int oldbinding = l->binding;
warnp("[label_reattach_route] binding %d deleted\n",
l->binding);
l->p = NULL;
l->binding = MPLS_LABEL_IMPLNULL;
/* No gateway ? */
memset(&emptysu, 0, sizeof (union sockunion));
if (memcmp(&l->so_gate, &emptysu, sizeof(union sockunion)) == 0)
return;
if (l->label != MPLS_LABEL_IMPLNULL && readd == LDP_READD_CHANGE) {
/* Delete and re-add IPv4 route */
if (get_route(&rg, &l->so_dest, &l->so_pref, 1) == LDP_E_OK) {
delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
add_route(&l->so_dest, &l->so_pref, &l->so_gate, NULL, NULL,
NO_FREESO, RTM_READD);
} else if (from_union_to_cidr(&l->so_pref) == 32 &&
l->so_dest.sa.sa_family == AF_INET &&
get_route(&rg, &l->so_dest, NULL, 1) == LDP_E_OK) {
delete_route(&l->so_dest, NULL, NO_FREESO);
add_route(&l->so_dest, NULL, &l->so_gate, NULL, NULL,
NO_FREESO, RTM_READD);
} else
add_route(&l->so_dest, &l->so_pref,
&l->so_gate, NULL, NULL, NO_FREESO, RTM_READD);
} else
if (readd != LDP_READD_NODEL)
delete_route(&l->so_dest, &l->so_pref, NO_FREESO);
l->label = 0;
/* Deletes pure MPLS route */
if (oldbinding >= MIN_LABEL) {
u = make_mpls_union(oldbinding);
delete_route(u, NULL, FREESO);
}
}
/*
* Get a label by dst and pref
*/
struct label*
label_get(union sockunion *sodest, union sockunion *sopref)
{
struct label *l;
SLIST_FOREACH (l, &label_head, labels)
if (sodest->sin.sin_addr.s_addr ==
l->so_dest.sin.sin_addr.s_addr &&
sopref->sin.sin_addr.s_addr ==
l->so_pref.sin.sin_addr.s_addr)
return l;
return NULL;
}
/*
* Find all labels that points to a peer
* and reattach them to IPv4
*/
void
label_reattach_all_peer_labels(struct ldp_peer *p, int readd)
{
struct label *l;
SLIST_FOREACH(l, &label_head, labels)
if (l->p == p)
label_reattach_route(l, readd);
}
/*
* Find all labels that points to a peer
* and delete them
*/
void
del_all_peer_labels(struct ldp_peer * p, int readd)
{
struct label *l;
int do_remove = 1;
while(do_remove == 1) {
do_remove = 0;
SLIST_FOREACH(l, &label_head, labels) {
if(l->p != p)
continue;
label_reattach_route(l, readd);
label_del(l);
/* remove must not interact with foreach */
SLIST_REMOVE(&label_head, l, label, labels);
do_remove = 1;
break; /* XXX: suboptimal */
}
} // while
}
/*
* Finds a label by its binding and deletes it
*/
void
label_del_by_binding(uint32_t binding, int readd)
{
struct label *l;
SLIST_FOREACH(l, &label_head, labels)
if ((uint32_t)l->binding == binding) {
label_reattach_route(l, readd);
label_del(l);
SLIST_REMOVE(&label_head, l, label, labels);
break;
}
}
/*
* For Compatibility with old bindinds code
*/
struct label*
label_get_by_prefix(struct in_addr *a, int prefixlen)
{
union sockunion *so_dest, *so_pref;
struct label *l;
so_dest = make_inet_union(inet_ntoa(*a));
so_pref = from_cidr_to_union(prefixlen);
l = label_get(so_dest, so_pref);
free(so_dest);
free(so_pref);
return l;
}
/*
* Get a free binding
*/
uint32_t
get_free_local_label()
{
struct label *l;
uint32_t lbl;
for (lbl = MIN_LABEL; lbl <= MAX_LABEL; lbl++) {
SLIST_FOREACH(l, &label_head, labels)
if ((uint32_t)l->binding == lbl)
break;
if (l == NULL)
return lbl;
}
return 0;
}
/*
* Change local binding
*/
void
change_local_label(struct label *l, uint32_t newbind)
{
send_withdraw_tlv_to_all(&(l->so_dest.sin.sin_addr),
from_union_to_cidr(&(l->so_pref)));
l->binding = newbind;
send_label_tlv_to_all(&(l->so_dest.sin.sin_addr),
from_union_to_cidr(&(l->so_pref)),
l->binding);
}

73
usr.sbin/ldpd/label.h Normal file
View File

@ -0,0 +1,73 @@
/* $NetBSD: label.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LABEL_H_
#define _LABEL_H_
#include <sys/queue.h>
#include "mpls_routes.h"
#include "ldp_peer.h"
#define LDP_READD_NODEL 0
#define LDP_READD_CHANGE 1
#define LDP_READD_NOCHANGE 2
/*
* MPLS label descriptor
*
* so_dest and so_pref are obvious
* so_gate is the IPV4 gate
* binding is the local label
* label is the peer associated label
*/
struct label {
union sockunion so_dest, so_pref, so_gate;
int binding, label;
struct ldp_peer *p;
SLIST_ENTRY(label) labels;
};
SLIST_HEAD(,label) label_head;
void label_init(void);
struct label * label_add(union sockunion *, union sockunion *,
union sockunion *, uint32_t, struct ldp_peer *, uint32_t);
void label_del(struct label *);
void del_all_peer_labels(struct ldp_peer*, int);
void label_reattach_all_peer_labels(struct ldp_peer*, int);
void label_del_by_binding(uint32_t, int);
struct label * label_get(union sockunion *sodest, union sockunion *sopref);
struct label * label_get_by_prefix(struct in_addr*, int);
uint32_t get_free_local_label(void);
void change_local_label(struct label*, uint32_t);
void label_reattach_route(struct label*, int);
#endif /* !_LABEL_H_ */

50
usr.sbin/ldpd/ldp.d Normal file
View File

@ -0,0 +1,50 @@
ldp.o: ldp.c /usr/include/netinet/in.h /usr/include/machine/int_types.h \
/usr/include/sys/cdefs.h /usr/include/machine/cdefs.h \
/usr/include/sys/cdefs_elf.h /usr/include/sys/ansi.h \
/usr/include/machine/ansi.h /usr/include/netinet6/in6.h \
/usr/include/sys/socket.h /usr/include/sys/featuretest.h \
/usr/include/sys/uio.h /usr/include/sys/stat.h /usr/include/sys/types.h \
/usr/include/machine/types.h /usr/include/machine/endian.h \
/usr/include/sys/endian.h /usr/include/machine/endian_machdep.h \
/usr/include/machine/bswap.h /usr/include/machine/byte_swap.h \
/usr/include/sys/bswap.h /usr/include/sys/fd_set.h \
/usr/include/pthread_types.h /usr/include/sys/time.h \
/usr/include/sys/select.h /usr/include/sys/sigtypes.h \
/usr/include/sys/satypes.h /usr/include/time.h /usr/include/sys/null.h \
/usr/include/arpa/inet.h /usr/include/stdio.h /usr/include/stdlib.h \
/usr/include/strings.h /usr/include/stdint.h \
/usr/include/machine/int_mwgwtypes.h /usr/include/machine/int_limits.h \
/usr/include/machine/int_const.h /usr/include/machine/wchar_limits.h \
/usr/include/string.h /usr/include/unistd.h /usr/include/sys/unistd.h \
ldp.h ldp_command.h socketops.h mpls_routes.h /usr/include/net/if.h \
/usr/include/sys/mutex.h /usr/include/sys/inttypes.h \
/usr/include/sys/stdint.h /usr/include/machine/int_fmtio.h \
/usr/include/machine/mutex.h /usr/include/x86/mutex.h \
/usr/include/sys/condvar.h /usr/include/sys/queue.h \
/usr/include/net/dlt.h /usr/include/net/pfil.h \
/usr/include/altq/if_altq.h /usr/include/net/if_arp.h \
/usr/include/net/route.h /usr/include/stdbool.h \
/usr/include/net/radix.h /usr/include/netmpls/mpls.h \
/usr/include/sys/param.h /usr/include/sys/syslimits.h \
/usr/include/sys/signal.h /usr/include/sys/siginfo.h \
/usr/include/machine/signal.h /usr/include/machine/trap.h \
/usr/include/x86/trap.h /usr/include/machine/fpu.h \
/usr/include/machine/mcontext.h /usr/include/machine/frame_regs.h \
/usr/include/sys/ucontext.h /usr/include/machine/param.h \
/usr/include/machine/limits.h /usr/include/sys/proc.h \
/usr/include/machine/proc.h /usr/include/sys/user.h \
/usr/include/machine/pcb.h /usr/include/machine/segments.h \
/usr/include/machine/tss.h /usr/include/machine/sysarch.h \
/usr/include/x86/sysarch.h /usr/include/machine/frame.h \
/usr/include/sys/aio.h /usr/include/sys/rwlock.h \
/usr/include/machine/rwlock.h /usr/include/x86/rwlock.h \
/usr/include/sys/mqueue.h /usr/include/sys/lwp.h \
/usr/include/sys/callout.h /usr/include/sys/signalvar.h \
/usr/include/sys/sched.h /usr/include/sys/specificdata.h \
/usr/include/sys/syncobj.h /usr/include/sys/resource.h \
/usr/include/sys/event.h /usr/include/sys/ioctl.h \
/usr/include/sys/ttycom.h /usr/include/sys/ioccom.h \
/usr/include/sys/dkio.h /usr/include/prop/plistref.h \
/usr/include/sys/filio.h /usr/include/sys/sockio.h \
/usr/include/net/if_dl.h ldp_peer.h tlv.h pdu.h fsm.h ldp_errors.h \
mpls_interface.h

79
usr.sbin/ldpd/ldp.h Normal file
View File

@ -0,0 +1,79 @@
/* $NetBSD: ldp.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LDP_H_
#define _LDP_H_
#include <sys/types.h>
#include <netinet/in.h>
#define ALL_ROUTERS "224.0.0.2"
#define LDP_PORT 646
#define LDP_COMMAND_PORT 2626
#define LDPD_VER "0.3.0"
extern char my_ldp_id[20];
#define LDP_ID my_ldp_id
/* LDP Messages */
#define LDP_NOTIFICATION 0x0001
#define LDP_HELLO 0x0100
#define LDP_INITIALIZE 0x0200
#define LDP_KEEPALIVE 0x0201
#define LDP_ADDRESS 0x0300
#define LDP_ADDRESS_WITHDRAW 0x0301
#define LDP_LABEL_MAPPING 0x0400
#define LDP_LABEL_REQUEST 0x0401
#define LDP_LABEL_WITHDRAW 0x0402
#define LDP_LABEL_RELEASE 0x0403
#define LDP_LABEL_ABORT 0x0404
/* Protocol version */
#define LDP_VERSION 1
/* Various timers */
#define LDP_HELLO_TIME 5
#define LDP_HELLO_KEEP 15
#define LDP_KEEPALIVE_TIME 4
#define LDP_HOLDTIME 15
#define MIN_LABEL 16
#define MAX_LABEL 1048576
#define ROUTE_LOOKUP_LOOP 6
#define REPLAY_MAX 100
#define MAX_POLL_FDS 200
void print_usage(char*);
#endif /* !_LDP_H_ */

564
usr.sbin/ldpd/ldp_command.c Normal file
View File

@ -0,0 +1,564 @@
/* $NetBSD: ldp_command.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "label.h"
#include "ldp.h"
#include "ldp_command.h"
#include "ldp_errors.h"
#include "ldp_peer.h"
#include "socketops.h"
struct com_sock csockets[MAX_COMMAND_SOCKETS];
extern int ldp_hello_time, debug_f, warn_f;
#define writestr(soc, str) write(soc, str, strlen(str))
#define MAXSEND 1024
char sendspace[MAXSEND];
static int verify_root_pwd(char *);
static void echo_on(int s);
static void echo_off(int s);
struct com_func main_commands[] = {
{ "show", show_func },
{ "set", set_func },
{ "quit", exit_func },
{ "exit", exit_func },
{ "", NULL }
};
struct com_func show_commands[] = {
{ "neighbours", show_neighbours },
{ "bindings", show_bindings },
{ "debug", show_debug },
{ "hellos", show_hellos },
{ "parameters", show_parameters },
{ "version", show_version },
{ "warning", show_warning },
{ "", NULL }
};
struct com_func set_commands[] = {
{ "debug", set_debug },
{ "hello-time", set_hello_time },
{ "warning", set_warning },
{ "", NULL }
};
int
verify_root_pwd(char *pw)
{
struct passwd *p;
if ((p = getpwuid(0)) == NULL)
return 0;
if (strcmp(crypt(pw, p->pw_passwd), p->pw_passwd))
return 0;
return 1;
}
void
init_command_sockets()
{
int i;
for (i = 0; i<MAX_COMMAND_SOCKETS; i++) {
csockets[i].socket = -1;
csockets[i].auth = 0;
}
}
int
create_command_socket(int port)
{
struct sockaddr_in sin;
int s;
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = ntohl(INADDR_LOOPBACK);
s = socket(PF_INET, SOCK_STREAM, 6);
if (s < 0)
return s;
if (bind(s, (struct sockaddr *) &sin, sizeof(sin))) {
fatalp("bind: %s", strerror(errno));
close(s);
return -1;
}
if (listen(s, 5) == -1) {
fatalp("listen: %s", strerror(errno));
close(s);
return -1;
}
return s;
}
void
command_accept(int s)
{
int as = accept(s, NULL, 0);
if (as < 0) {
fatalp("Cannot accept new command socket %s",
strerror(errno));
return;
}
if (add_command_socket(as) != 0) {
fatalp("Cannot accept command. Too many connections\n");
close(as);
return;
}
/* auth */
send_pwd_prompt(as);
}
struct com_sock *
is_command_socket(int s)
{
int i;
if (s == -1)
return NULL;
for (i=0; i<MAX_COMMAND_SOCKETS; i++)
if (s == csockets[i].socket)
return &csockets[i];
return NULL;
}
int
add_command_socket(int s)
{
int i;
for (i=0; i<MAX_COMMAND_SOCKETS; i++)
if (csockets[i].socket == -1) {
csockets[i].socket = s;
csockets[i].auth = 0;
return 0;
}
return -1;
}
void
command_dispatch(struct com_sock *cs)
{
char recvspace[MAX_COMMAND_SIZE + 1];
char *nextc = recvspace;
int r = recv(cs->socket, recvspace, MAX_COMMAND_SIZE, MSG_PEEK);
if (r < 0) {
command_close(cs->socket);
return;
}
recv(cs->socket, recvspace, r, MSG_WAITALL);
if (r < 3) { /*at least \r\n */
if (cs->auth) {
/*writestr(cs->socket, "Unknown command. Use ? for help\n");*/
send_prompt(cs->socket);
} else {
writestr(cs->socket, "Bad password\n");
command_close(cs->socket);
}
return;
}
recvspace[r - 2] = '\0';
if (!cs->auth) {
if (verify_root_pwd(recvspace)) {
echo_on(cs->socket);
cs->auth = 1;
writestr(cs->socket, "\n");
send_prompt(cs->socket);
} else {
echo_on(cs->socket);
writestr(cs->socket, "Bad password\n");
command_close(cs->socket);
}
return;
}
strsep(&nextc, " ");
command_match(main_commands, cs->socket, recvspace, nextc);
}
void
command_close(int s)
{
int i;
for (i=0; i<MAX_COMMAND_SOCKETS; i++)
if (s == csockets[i].socket) {
close(s);
csockets[i].socket = -1;
csockets[i].auth = 0;
break;
}
}
void
send_prompt(int s) {
writestr(s, "LDP> ");
}
void
send_pwd_prompt(int s) {
echo_off(s);
writestr(s, "Password: ");
}
static void echo_off(int s)
{
char iac_will_echo[3] = { 0xff, 0xfb, 0x01 }, bf[32];
write(s, iac_will_echo, sizeof(iac_will_echo));
read(s, bf, sizeof(bf));
}
static void echo_on(int s)
{
char iac_wont_echo[3] = { 0xff, 0xfc, 0x01 }, bf[32];
write(s, iac_wont_echo, sizeof(iac_wont_echo));
read(s, bf, sizeof(bf));
}
/*
* Matching function
* Returns 1 if matched anything
*/
int
command_match(struct com_func *cf, int s, char *orig, char *next)
{
int i, matched = 0, last_match;
if (orig == NULL || orig[0] == '\0') {
send_prompt(s);
return 0;
}
if (!strcmp(orig, "?")) {
for (i=0; cf[i].func != NULL; i++) {
snprintf(sendspace, MAXSEND, "\t%s\n", cf[i].com);
writestr(s, sendspace);
}
send_prompt(s);
return 0;
}
for (i=0; cf[i].func != NULL; i++)
if(strncasecmp(orig, cf[i].com, strlen(orig)) == 0) {
matched++;
last_match = i;
}
if (!matched) {
writestr(s, "Unknown command. Use ? for help\n");
send_prompt(s);
return 0;
}
if (matched > 1) {
writestr(s, "Ambiguous command. Use ? for help\n");
send_prompt(s);
return 0;
}
if(cf[last_match].func(s, next) != 0)
send_prompt(s);
return 1;
}
/*
* Main CLI functions
*/
int
set_func(int s, char *recvspace)
{
char *nextc = recvspace;
if (recvspace == NULL || recvspace[0] == '\0') {
writestr(s, "Unknown set command. Use set ? for help\n");
return 1;
}
strsep(&nextc, " ");
command_match(set_commands, s, recvspace, nextc);
return 0;
}
int
show_func(int s, char *recvspace)
{
char *nextc = recvspace;
if (recvspace == NULL || recvspace[0] == '\0') {
writestr(s, "Unknown show command. Use show ? for help\n");
return 1;
}
strsep(&nextc, " ");
command_match(show_commands, s, recvspace, nextc);
return 0;
}
int
exit_func(int s, char *recvspace)
{
command_close(s);
return 0;
}
/*
* Show functions
*/
int
show_neighbours(int s, char *recvspace)
{
struct ldp_peer *p;
struct ldp_peer_address *wp;
struct sockaddr_in ssin;
socklen_t sin_len = sizeof(struct sockaddr_in);
SLIST_FOREACH(p, &ldp_peer_head, peers) {
snprintf(sendspace, MAXSEND, "LDP peer: %s\n",
inet_ntoa(p->ldp_id));
writestr(s, sendspace);
snprintf(sendspace, MAXSEND, "Transport address: %s\n",
inet_ntoa(p->transport_address));
writestr(s, sendspace);
snprintf(sendspace, MAXSEND, "Next-hop address: %s\n",
inet_ntoa(p->address));
writestr(s, sendspace);
snprintf(sendspace, MAXSEND, "State: %s\n",
ldp_state_to_name(p->state));
writestr(s, sendspace);
if (p->state == LDP_PEER_ESTABLISHED) {
snprintf(sendspace, MAXSEND, "Since: %s",
ctime(&p->established_t));
writestr(s, sendspace);
}
snprintf(sendspace, MAXSEND, "Holdtime: %d\nTimeout: %d\n",
p->holdtime, p->timeout);
writestr(s, sendspace);
switch(p->state) {
case LDP_PEER_CONNECTING:
case LDP_PEER_CONNECTED:
case LDP_PEER_ESTABLISHED:
if (getsockname(p->socket,(struct sockaddr *) &ssin,
&sin_len))
break;
snprintf(sendspace, MAXSEND,"Socket: %d\nLocal %s:%d\n",
p->socket, inet_ntoa(ssin.sin_addr),
ntohs(ssin.sin_port));
writestr(s, sendspace);
if (getpeername(p->socket,(struct sockaddr *) &ssin,
&sin_len))
break;
snprintf(sendspace, MAXSEND, "Remote %s:%d\n",
inet_ntoa(ssin.sin_addr), ntohs(ssin.sin_port));
writestr(s, sendspace);
}
snprintf(sendspace, MAXSEND,"Addresses bounded to this peer: ");
writestr(s, sendspace);
SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) {
snprintf(sendspace, MAXSEND, "%s ",
inet_ntoa(wp->address));
writestr(s, sendspace);
}
sendspace[0] = sendspace[1] = '\n';
write(s, sendspace, 2);
}
return 1;
}
int
show_bindings(int s, char *recvspace)
{
struct label *l;
snprintf(sendspace, MAXSEND, "Local label\tNetwork\t\t\t\tNexthop\n");
writestr(s, sendspace);
SLIST_FOREACH (l, &label_head, labels) {
snprintf(sendspace, MAXSEND, "%d\t\t%s/", l->binding,
union_ntoa(&l->so_dest));
writestr(s, sendspace);
snprintf(sendspace, MAXSEND, "%s", union_ntoa(&l->so_pref));
writestr(s, sendspace);
if (l->p)
snprintf(sendspace, MAXSEND, "\t%s:%d\n",
inet_ntoa(l->p->address), l->label);
else
snprintf(sendspace, MAXSEND, "\n");
writestr(s, sendspace);
}
return 1;
}
int
show_debug(int s, char *recvspace)
{
if (recvspace) {
writestr(s, "Invalid command\n");
return 1;
}
snprintf(sendspace, MAXSEND, "Debug: %s\n",
debug_f ? "YES" : "NO");
writestr(s, sendspace);
return 1;
}
int
show_hellos(int s, char *recvspace)
{
struct hello_info *hi;
SLIST_FOREACH(hi, &hello_info_head, infos) {
snprintf(sendspace, MAXSEND, "%s: %ds\n", inet_ntoa(hi->ldp_id),
hi->keepalive);
writestr(s, sendspace);
}
return 1;
}
int
show_parameters(int s, char *recvspace)
{
snprintf(sendspace, MAXSEND, "LDP ID: %s\nProtocol version: %d\n"
"Hello time: %d\nKeepalive time: %d\nHoldtime: %d\n"
"Minimum label: %d\nMaximum label: %d\n",
my_ldp_id,
LDP_VERSION,
ldp_hello_time,
LDP_KEEPALIVE_TIME,
LDP_HOLDTIME,
MIN_LABEL,
MAX_LABEL);
writestr(s, sendspace);
return 1;
}
int
show_version(int s, char *recvspace)
{
if (recvspace) { /* Nothing more after this */
writestr(s, "Invalid command\n");
return 1;
}
snprintf(sendspace, MAXSEND, "NetBSD LDP daemon version: %s\n",
LDPD_VER);
writestr(s, sendspace);
return 1;
}
int
show_warning(int s, char *recvspace)
{
if (recvspace) {
writestr(s, "Invalid command\n");
return 1;
}
snprintf(sendspace, MAXSEND, "Warnings: %s\n",
warn_f ? "YES" : "NO");
writestr(s, sendspace);
return 1;
}
/* Set commands */
int
set_hello_time(int s, char *recvspace)
{
if (!recvspace || atoi(recvspace) < 1) {
writestr(s, "Invalid timeout\n");
return 1;
}
ldp_hello_time = atoi(recvspace);
return 1;
}
int
set_debug(int s, char *recvspace)
{
if (!recvspace || atoi(recvspace) < 0) {
writestr(s, "Invalid command\n");
return 1;
}
debug_f = atoi(recvspace);
return 1;
}
int
set_warning(int s, char *recvspace)
{
if (!recvspace || atoi(recvspace) < 0) {
writestr(s, "Invalid command\n");
return 1;
}
warn_f = atoi(recvspace);
return 1;
}

View File

@ -0,0 +1,79 @@
/* $NetBSD: ldp_command.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LDP_COMMAND_H_
#define _LDP_COMMAND_H_
#define MAX_COMMAND_SOCKETS 64
#define MAX_COMMAND_SIZE 512
struct com_sock {
int socket;
int auth; /* 1 if socket is authenticated */
};
struct com_func {
char com[64];
int (* func)(int, char *);
};
void init_command_sockets(void);
int create_command_socket(int);
struct com_sock * is_command_socket(int);
void command_accept(int);
int add_command_socket(int);
void command_dispatch(struct com_sock *);
void command_close(int);
void send_prompt(int);
void send_pwd_prompt(int);
int command_match(struct com_func*, int, char*, char*);
/* Main functions */
int show_func(int, char *);
int set_func(int, char *);
int exit_func(int, char *);
/* Show functions */
int show_neighbours(int, char *);
int show_bindings(int, char *);
int show_debug(int, char *);
int show_hellos(int, char *);
int show_parameters(int, char *);
int show_version(int, char *);
int show_warning(int, char *);
/* Set functions */
int set_hello_time(int, char *);
int set_debug(int, char *);
int set_warning(int, char *);
#endif /* !_LDP_COMMAND_H_ */

110
usr.sbin/ldpd/ldp_errors.c Normal file
View File

@ -0,0 +1,110 @@
/* $NetBSD: ldp_errors.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include <unistd.h>
#include "ldp.h"
#include "ldp_errors.h"
int debug_f = 0, warn_f = 0, syslog_f = 0;
static void do_syslog(int, const char*, va_list);
void
debugp(const char *fmt, ...)
{
va_list va;
if (!debug_f)
return;
va_start(va, fmt);
if (syslog_f)
do_syslog(LOG_DEBUG, fmt, va);
else
vprintf(fmt, va);
va_end(va);
}
void
warnp(const char *fmt, ...)
{
va_list va;
if (!debug_f && !warn_f)
return;
va_start(va, fmt);
if (syslog_f)
do_syslog(LOG_WARNING, fmt, va);
else
vprintf(fmt, va);
va_end(va);
}
void
fatalp(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
if (syslog_f)
do_syslog(LOG_ERR, fmt, va);
else
vprintf(fmt, va);
va_end(va);
}
static void
do_syslog(int prio, const char *fmt, va_list va)
{
vsyslog(prio, fmt, va);
}
void
printtime()
{
time_t t;
char buf[26];
int i;
time(&t);
ctime_r(&t, buf);
for (i = 0; (i < 26 && buf[i] != 0); i++)
if (buf[i] == '\n')
buf[i] = 0;
printf("%s ", buf);
}

View File

@ -0,0 +1,58 @@
/* $NetBSD: ldp_errors.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LDP_ERRORS_H_
#define _LDP_ERRORS_H_
#define LDP_E_OK 0
#define LDP_E_BAD_VERSION 1
#define LDP_E_BAD_LENGTH 2
#define LDP_E_MEMORY 3
#define LDP_E_NOENT 4
#define LDP_E_ALREADY_DONE 5
#define LDP_E_BAD_AF 6
#define LDP_E_BAD_FEC 7
#define LDP_E_BAD_LABEL 8
#define LDP_E_NO_SUCH_ROUTE LDP_E_ROUTE_ERROR
/* 9, 10 Free */
#define LDP_E_ROUTE_ERROR 11
#define LDP_E_NO_BINDING 12
#define LDP_E_TOO_MANY_LABELS 13
#define LDP_E_INVAL 14
#define LDP_E_GENERIC 255
void printtime(void);
void debugp(const char *, ...);
void fatalp(const char *, ...);
void warnp(const char *, ...);
#endif /* !_LDP_ERRORS_H_ */

498
usr.sbin/ldpd/ldp_peer.c Normal file
View File

@ -0,0 +1,498 @@
/* $NetBSD: ldp_peer.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netmpls/mpls.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include "socketops.h"
#include "ldp_errors.h"
#include "ldp.h"
#include "tlv_stack.h"
#include "mpls_interface.h"
#include "notifications.h"
#include "ldp_peer.h"
struct in_addr *myaddresses;
void
ldp_peer_init(void)
{
SLIST_INIT(&ldp_peer_head);
myaddresses = NULL;
}
/*
* soc should be > 1 if there is already a TCP socket for this else we'll
* initiate a new one
*/
struct ldp_peer *
ldp_peer_new(struct in_addr * ldp_id, struct in_addr * a,
struct in_addr * tradd, uint16_t holdtime, int soc)
{
struct ldp_peer *p;
int s = soc;
struct sockaddr_in sa;
if (s < 1) {
s = socket(PF_INET, SOCK_STREAM, 0);
memset(&sa, 0, sizeof(sa));
sa.sin_len = sizeof(sa);
sa.sin_family = AF_INET;
if (tradd)
memcpy(&sa.sin_addr, tradd,
sizeof(struct in_addr));
else
memcpy(&sa.sin_addr, a,
sizeof(struct in_addr));
sa.sin_port = htons(LDP_PORT);
set_ttl(s);
}
/* Set the peer in CONNECTING/CONNECTED state */
p = (struct ldp_peer *) malloc(sizeof(struct ldp_peer));
if (!p) {
fatalp("ldp_peer_new: malloc problem\n");
return NULL;
}
memset(p, 0, sizeof(struct ldp_peer));
SLIST_INSERT_HEAD(&ldp_peer_head, p, peers);
memcpy(&p->address, a, sizeof(struct in_addr));
memcpy(&p->ldp_id, ldp_id, sizeof(struct in_addr));
if (tradd)
memcpy(&p->transport_address, tradd,
sizeof(struct in_addr));
else
memcpy(&p->transport_address, a,
sizeof(struct in_addr));
p->holdtime = holdtime > LDP_HOLDTIME ? holdtime : LDP_HOLDTIME;
p->socket = s;
if (soc < 1) {
p->state = LDP_PEER_CONNECTING;
p->master = 1;
} else {
p->state = LDP_PEER_CONNECTED;
p->master = 0;
set_ttl(p->socket);
}
SLIST_INIT(&p->ldp_peer_address_head);
SLIST_INIT(&p->label_mapping_head);
p->timeout = p->holdtime;
/* And connect to peer */
if (soc < 1)
if (connect(s, (struct sockaddr *) & sa, sizeof(sa)) == -1) {
if (errno == EINTR) {
return p; /* We take care of this in
* big_loop */
}
warnp("connect to %s failed: %s\n",
inet_ntoa(sa.sin_addr), strerror(errno));
ldp_peer_holddown(p);
return NULL;
}
p->state = LDP_PEER_CONNECTED;
return p;
}
void
ldp_peer_holddown(struct ldp_peer * p)
{
if (!p)
return;
if (p->state == LDP_PEER_ESTABLISHED)
mpls_delete_ldp_peer(p);
p->state = LDP_PEER_HOLDDOWN;
p->timeout = LDP_HOLDTIME;
shutdown(p->socket, SHUT_RDWR);
ldp_peer_delete_all_mappings(p);
del_all_ifaddr(p);
fatalp("LDP Neighbour %s is DOWN\n", inet_ntoa(p->ldp_id));
}
void
ldp_peer_holddown_all()
{
struct ldp_peer *p;
SLIST_FOREACH(p, &ldp_peer_head, peers) {
if ((p->state == LDP_PEER_ESTABLISHED) ||
(p->state == LDP_PEER_CONNECTED))
send_notification(p, get_message_id(), NOTIF_SHUTDOWN);
ldp_peer_holddown(p);
}
}
void
ldp_peer_delete(struct ldp_peer * p)
{
if (!p)
return;
SLIST_REMOVE(&ldp_peer_head, p, ldp_peer, peers);
close(p->socket);
warnp("LDP Neighbor %s holddown timer expired\n", inet_ntoa(p->ldp_id));
free(p);
}
struct ldp_peer *
get_ldp_peer(struct in_addr * a)
{
struct ldp_peer *p;
SLIST_FOREACH(p, &ldp_peer_head, peers) {
if (!memcmp((void *) a, (void *) &p->ldp_id,
sizeof(struct in_addr)))
return p;
if (!memcmp((void *) a, (void *) &p->address,
sizeof(struct in_addr)))
return p;
if (check_ifaddr(p, a))
return p;
}
return NULL;
}
struct ldp_peer *
get_ldp_peer_by_socket(int s)
{
struct ldp_peer *p;
SLIST_FOREACH(p, &ldp_peer_head, peers)
if (p->socket == s)
return p;
return NULL;
}
/*
* Adds address list bounded to a specific peer
* Returns the number of addresses inserted successfuly
*/
int
add_ifaddresses(struct ldp_peer * p, struct al_tlv * a)
{
int i, c, n;
struct in_addr *ia;
/*
* Check if tlv is Address type, if it's correct size (at least one
* address) and if it's IPv4
*/
if ((ntohs(a->type) != TLV_ADDRESS_LIST) ||
(ntohs(a->length) < sizeof(a->af) + sizeof(struct in_addr)) ||
(ntohs(a->af) != LDP_AF_INET))
return 0;
/* Number of addresses to insert */
n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
debugp("Trying to add %d addresses to peer %s ... \n", n,
inet_ntoa(p->ldp_id));
for (ia = (struct in_addr *) & a->address, c = 0, i = 0; i < n; i++) {
if (add_ifaddr(p, &ia[i]) == LDP_E_OK)
c++;
}
debugp("Added %d addresses\n", c);
return c;
}
int
del_ifaddresses(struct ldp_peer * p, struct al_tlv * a)
{
int i, c, n;
struct in_addr *ia;
/*
* Check if tlv is Address type, if it's correct size (at least one
* address) and if it's IPv4
*/
if (ntohs(a->type) != TLV_ADDRESS_LIST ||
ntohs(a->length) > sizeof(a->af) + sizeof(struct in_addr) ||
ntohs(a->af) != LDP_AF_INET)
return -1;
n = (ntohs(a->length) - sizeof(a->af)) / sizeof(struct in_addr);
debugp("Trying to delete %d addresses from peer %s ... \n", n,
inet_ntoa(p->ldp_id));
for (ia = (struct in_addr *) & a[1], c = 0, i = 0; i < n; i++) {
if (del_ifaddr(p, &ia[i]) == LDP_E_OK)
c++;
}
debugp("Deleted %d addresses\n", c);
return c;
}
/* Adds a _SINGLE_ address to a specific peer */
int
add_ifaddr(struct ldp_peer * p, struct in_addr * a)
{
struct ldp_peer_address *lpa;
/* Is it already there ? */
if (check_ifaddr(p, a))
return LDP_E_ALREADY_DONE;
lpa = (struct ldp_peer_address*)malloc(sizeof(struct ldp_peer_address));
if (!lpa) {
fatalp("add_ifaddr: malloc problem\n");
return LDP_E_MEMORY;
}
memset(lpa, 0, sizeof(struct ldp_peer_address));
memcpy(&lpa->address, a, sizeof(struct in_addr));
SLIST_INSERT_HEAD(&p->ldp_peer_address_head, lpa, addresses);
return LDP_E_OK;
}
/* Deletes an address bounded to a specific peer */
int
del_ifaddr(struct ldp_peer * p, struct in_addr * a)
{
struct ldp_peer_address *wp;
wp = check_ifaddr(p, a);
if (!wp)
return LDP_E_NOENT;
SLIST_REMOVE(&p->ldp_peer_address_head, wp, ldp_peer_address,
addresses);
free(wp);
return LDP_E_OK;
}
/* Checks if an address is already bounded */
struct ldp_peer_address *
check_ifaddr(struct ldp_peer * p, struct in_addr * a)
{
struct ldp_peer_address *wp;
SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses)
if (memcmp(a, &wp->address, sizeof(struct in_addr)) == 0)
return wp;
return NULL;
}
void
del_all_ifaddr(struct ldp_peer * p)
{
struct ldp_peer_address *wp;
while (!SLIST_EMPTY(&p->ldp_peer_address_head)) {
wp = SLIST_FIRST(&p->ldp_peer_address_head);
SLIST_REMOVE_HEAD(&p->ldp_peer_address_head, addresses);
free(wp);
}
}
void
print_bounded_addresses(struct ldp_peer * p)
{
struct ldp_peer_address *wp;
char abuf[512];
snprintf(abuf, sizeof(abuf), "Addresses bounded to peer %s: ",
inet_ntoa(p->address));
SLIST_FOREACH(wp, &p->ldp_peer_address_head, addresses) {
strncat(abuf, inet_ntoa(wp->address), sizeof(abuf) -1);
strncat(abuf, " ", sizeof(abuf) -1);
}
warnp("%s\n", abuf);
}
void
add_my_if_addrs(struct in_addr * a, int count)
{
myaddresses = (struct in_addr *) malloc((count + 1) *
(sizeof(struct in_addr)));
if (!myaddresses) {
fatalp("add_my_if_addrs: malloc problem\n");
return;
}
memcpy(myaddresses, a, count * sizeof(struct in_addr));
myaddresses[count].s_addr = 0;
}
/* Adds a label and a prefix to a specific peer */
int
ldp_peer_add_mapping(struct ldp_peer * p, struct in_addr * a, int prefix,
int label)
{
struct label_mapping *lma;
if (!p)
return -1;
if (ldp_peer_get_lm(p, a, prefix))
return LDP_E_ALREADY_DONE;
lma = (struct label_mapping *) malloc(sizeof(struct label_mapping));
if (!lma) {
fatalp("ldp_peer_add_mapping: malloc problem\n");
return LDP_E_MEMORY;
}
memcpy(&lma->address, a, sizeof(struct in_addr));
lma->prefix = prefix;
lma->label = label;
SLIST_INSERT_HEAD(&p->label_mapping_head, lma, mappings);
return LDP_E_OK;
}
int
ldp_peer_delete_mapping(struct ldp_peer * p, struct in_addr * a, int prefix)
{
struct label_mapping *lma;
if (!a)
return ldp_peer_delete_all_mappings(p);
lma = ldp_peer_get_lm(p, a, prefix);
if (!lma)
return LDP_E_NOENT;
SLIST_REMOVE(&p->label_mapping_head, lma, label_mapping, mappings);
free(lma);
return LDP_E_OK;
}
struct label_mapping *
ldp_peer_get_lm(struct ldp_peer * p, struct in_addr * a, int prefix)
{
struct label_mapping *rv;
if (!p)
return NULL;
SLIST_FOREACH(rv, &p->label_mapping_head, mappings)
if ((rv->prefix == prefix) && (!memcmp(a, &rv->address,
sizeof(struct in_addr))))
break;
return rv;
}
int
ldp_peer_delete_all_mappings(struct ldp_peer * p)
{
struct label_mapping *lma;
while(!SLIST_EMPTY(&p->label_mapping_head)) {
lma = SLIST_FIRST(&p->label_mapping_head);
SLIST_REMOVE_HEAD(&p->label_mapping_head, mappings);
free(lma);
}
return LDP_E_OK;
}
/* returns a mapping and its peer */
struct peer_map *
ldp_test_mapping(struct in_addr * a, int prefix, struct in_addr * gate)
{
struct ldp_peer *lpeer;
struct peer_map *rv = NULL;
struct label_mapping *lm = NULL;
/* Checks if it's LPDID, else checks if it's an interface */
lpeer = get_ldp_peer(gate);
if (!lpeer) {
debugp("Gateway %s is not an LDP peer\n", inet_ntoa(*gate));
return NULL;
}
if (lpeer->state != LDP_PEER_ESTABLISHED) {
warnp("ldp_test_mapping: peer is down ?!\n");
return NULL;
}
lm = ldp_peer_get_lm(lpeer, a, prefix);
if (!lm) {
debugp("Cannot match that prefix to the specified peer\n");
return NULL;
}
rv = (struct peer_map *) malloc(sizeof(struct peer_map));
if (!rv) {
fatalp("ldp_test_mapping: malloc problem\n");
return NULL;
}
rv->lm = lm;
rv->peer = lpeer;
return rv;
}
/* Name from state */
const char * ldp_state_to_name(int state)
{
switch(state) {
case LDP_PEER_CONNECTING:
return "CONNECTING";
case LDP_PEER_CONNECTED:
return "CONNECTED";
case LDP_PEER_ESTABLISHED:
return "ESTABLISHED";
case LDP_PEER_HOLDDOWN:
return "HOLDDOWN";
}
return "UNKNOWN";
}

118
usr.sbin/ldpd/ldp_peer.h Normal file
View File

@ -0,0 +1,118 @@
/* $NetBSD: ldp_peer.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LDP_PEER_H_
#define _LDP_PEER_H_
#include "sys/types.h"
#include "sys/queue.h"
#include "netinet/in.h"
#include "tlv.h"
struct ldp_peer_address {
struct in_addr address;
SLIST_ENTRY(ldp_peer_address) addresses;
};
struct label_mapping {
struct in_addr address;
int prefix;
int label;
SLIST_ENTRY(label_mapping) mappings;
};
struct ldp_peer {
/*
* I add routes to address.
* I maintain LDP TCP connection on transport_address.
* I use ldp_id as peer identificator.
*/
struct in_addr address, transport_address, ldp_id;
/* TCP socket */
int socket;
/* Usual peer parameters */
uint16_t holdtime, timeout;
int master; /* 0 if we're passive */
int state; /* see below for possible states */
time_t established_t; /* time when it did connected */
/* Here I maintain all the addresses announced by a peer */
SLIST_HEAD(,ldp_peer_address) ldp_peer_address_head;
SLIST_HEAD(,label_mapping) label_mapping_head;
SLIST_ENTRY(ldp_peer) peers;
};
SLIST_HEAD(,ldp_peer) ldp_peer_head;
struct peer_map {
struct ldp_peer *peer;
struct label_mapping *lm;
};
/* LDP Peers States */
#define LDP_PEER_CONNECTING 0
#define LDP_PEER_CONNECTED 1
#define LDP_PEER_ESTABLISHED 2
#define LDP_PEER_HOLDDOWN 3
void ldp_peer_init(void);
struct ldp_peer * ldp_peer_new(struct in_addr *, struct in_addr *,
struct in_addr *, uint16_t, int);
void ldp_peer_holddown(struct ldp_peer *);
void ldp_peer_delete(struct ldp_peer *);
struct ldp_peer * get_ldp_peer(struct in_addr *);
struct ldp_peer * get_ldp_peer_by_socket(int);
int add_ifaddresses(struct ldp_peer *, struct al_tlv *);
int add_ifaddr(struct ldp_peer *, struct in_addr *);
int del_ifaddr(struct ldp_peer *, struct in_addr *);
struct ldp_peer_address * check_ifaddr(struct ldp_peer *,
struct in_addr *);
void print_bounded_addresses(struct ldp_peer *);
void del_all_ifaddr(struct ldp_peer *);
int del_ifaddresses(struct ldp_peer *, struct al_tlv *);
void add_my_if_addrs(struct in_addr *, int);
int ldp_peer_add_mapping(struct ldp_peer *, struct in_addr *,
int, int);
int ldp_peer_delete_mapping(struct ldp_peer *, struct in_addr *,
int);
struct label_mapping * ldp_peer_get_lm(struct ldp_peer *, struct in_addr *,
int);
int ldp_peer_delete_all_mappings(struct ldp_peer *);
void ldp_peer_holddown_all(void);
struct peer_map * ldp_test_mapping(struct in_addr *, int,
struct in_addr *);
const char * ldp_state_to_name(int);
#endif /* !_LDP_PEER_H_ */

94
usr.sbin/ldpd/ldpd.8 Normal file
View File

@ -0,0 +1,94 @@
.\" $NetBSD: ldpd.8,v 1.1 2010/12/08 07:20:14 kefren Exp $
.\"
.\" Copyright (c) 2010 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd December 7, 2010
.Dt ldpd 8
.Os
.Sh NAME
.Nm ldpd
.Nd Label Distribution Protocol Daemon
.Sh SYNOPSIS
.Nm
.Op Fl dDW
.Bk -words
.Op Fl p Ar port
.Ek
.Sh DESCRIPTION
.Nm
is a utility used to automatically distribute labels between two MPLS LSRs
almost conforming to RFC3036. Right now is in BETA stage and many features
are not implemented or may not work. As a security measure you SHOULD filter
the LDP well-known ( 646 ) TCP and UDP ports before starting
.Nm
using your favourite packet filter. Also this is the current measure used
to filter neighbours. You should see some logs reported via
.Xr syslog 3
interface.
.Pp
You can increase the log verbosity using -W and -D parameters.
Also you can telnet on control port (default: 2626) and use this interface
in order to get informations about protocol, neighbours etc. but also to
set runtime parameters. The required password is the same as root password.
.Pp
.Nm
computes existing routes and try to match them on MPLS labels announced by
other LDP peers. This means that 'normal' routes will be changed into tagged
routes, and MPLS routing table will be populated. It will also announce
peers about its mappings.
.Nm
will also listen on a route socket and compute the necessary changes in
order to change untagged routes into tagged routes. This means that one may
use his favourite dynamic routing protocol daemon without modifications.
.Pp
The options are as follows:
.Bl -tag -width 15n
.It Fl d
Don't use route interception code.
.It Fl D
Enable debug mode.
.It Fl f
Run in foreground. Use STDOUT for warning and debug messages.
.It Fl h
Outputs supported flags.
.It Fl p Ar port
Changes the TCP control port (default: 2626).
.It Fl W
Enable warning messages output.
.El
.Sh SEE ALSO
.Rs
.%R RFC
.%N 3036
.%D January 2001
.%T LDP Specification
.Re
.Sh HISTORY
The
.Nm
command appeared in NetBSD 6.0
.Sh BUGS
.Nm
supports only IPv4

146
usr.sbin/ldpd/main.c Normal file
View File

@ -0,0 +1,146 @@
/* $NetBSD: main.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include "ldp.h"
#include "ldp_command.h"
#include "socketops.h"
#include "tlv.h"
#include "pdu.h"
#include "fsm.h"
#include "ldp_errors.h"
#include "mpls_interface.h"
extern int ls; /* TCP listening socket */
extern int dont_catch;
extern int command_port;
extern int command_socket;
extern int debug_f, warn_f, syslog_f;
extern struct sockaddr mplssockaddr;
void print_usage(char *myself)
{
printf("\nUsage: %s [-hdDW] [-p PORT]\n\n", myself);
}
int
main(int argc, char *argv[])
{
int ch, forkres, dontfork = 0;
while((ch = getopt(argc, argv, "dDfhp:W")) != -1)
switch(ch) {
case 'd':
dont_catch = 1;
break;
case 'D':
debug_f = 1;
break;
case 'f':
dontfork = 1;
break;
case 'p':
if ((command_port = atoi(optarg)) < 1) {
print_usage(argv[0]);
return -1;
}
break;
case 'W':
warn_f = 1;
break;
case 'h':
default:
print_usage(argv[0]);
return -1;
break;
}
if (geteuid()) {
fatalp("You have to run this as ROOT\n");
return -1;
}
if (set_my_ldp_id()) {
fatalp("Cannot set LDP ID\n");
return -1;
}
if (mplssockaddr.sa_len == 0) {
fatalp("You need one mpls interface up and an IP "
"address set for it\n");
return -1;
}
if (mpls_start_ldp() == -1)
return -1;
if (!strcmp(LDP_ID, "0.0.0.0")) {
fatalp("Cannot set my LDP ID.\nAre you sure you've "
"got a non-loopback INET interface UP ?\n");
return -1;
}
init_command_sockets();
if ((command_socket = create_command_socket(command_port)) < 1) {
fatalp("Cannot create command socket\n");
return -1;
}
if (create_hello_socket() < 1) {
fatalp("Cannot create hello socket\n");
return -1;
}
ls = create_listening_socket();
if (ls < 0) {
fatalp("Cannot create listening socket\n");
return -1;
}
if (dontfork == 1)
the_big_loop();
forkres = fork();
if (forkres == 0) {
syslog_f = 1;
the_big_loop();
}
if (forkres < 0)
perror("fork");
return 0;
}

View File

@ -0,0 +1,226 @@
/* $NetBSD: mpls_interface.c,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netmpls/mpls.h>
#include <sys/param.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "ldp.h"
#include "ldp_peer.h"
#include "ldp_errors.h"
#include "tlv_stack.h"
#include "label.h"
#include "mpls_interface.h"
#include "mpls_routes.h"
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
int
mpls_add_label(struct ldp_peer * p, struct rt_msg * inh_rg,
struct in_addr * addr, int len, int label, int rlookup)
{
char padd[20];
int kount = 0, rv;
union sockunion *so_dest, *so_pref = NULL, *so_gate, *so_nexthop, *so_tag,
*so_oldifa = NULL, *so_ifa;
struct rt_msg rg;
struct rt_msg *rgp = &rg;
struct label *lab;
strlcpy(padd, inet_ntoa(p->address), 20);
debugp("Trying to add %s/%d as label %d to peer %s\n", inet_ntoa(*addr),
len, label, padd);
/* Don't accept default route XXX: should be option-able */
if (!len)
return LDP_E_BAD_AF;
/* Is there a label mapping for this ? */
if (ldp_peer_get_lm(p, addr, len) == NULL)
return LDP_E_NOENT;
if (!inh_rg || (inh_rg->m_rtm.rtm_addrs & RTA_IFA) == 0) {
/*
* XXX: Check if we have a route for that.
* Why the hell isn't kernel inserting the route immediatly ?
* let's loop until we have it..
*/
so_dest = make_inet_union(inet_ntoa(*addr));
if (len != 32)
so_pref = from_cidr_to_union(len);
do {
if (kount == rlookup) {
debugp("No route for this prefix\n");
return LDP_E_NO_SUCH_ROUTE;
}
kount++;
/* Last time give it a higher chance */
if (kount == rlookup)
usleep(5000);
rv = get_route(rgp, so_dest, so_pref, 1);
if (rv != LDP_E_OK && len == 32)
/* Host maybe ? */
rv = get_route(rgp, so_dest, NULL, 1);
} while (rv != LDP_E_OK);
free(so_dest);
if (so_pref)
free(so_pref);
} else
rgp = inh_rg;
/* Check if it's an IPv4 route */
so_gate = (union sockunion *) rgp->m_space;
so_gate = (union sockunion *)((char*)so_gate +
ROUNDUP(so_gate->sa.sa_len));
if (rgp->m_rtm.rtm_addrs & RTA_IFA) {
int li = 1;
so_oldifa = so_gate;
if (rgp->m_rtm.rtm_addrs & RTA_NETMASK)
li++;
if (rgp->m_rtm.rtm_addrs & RTA_GENMASK)
li++;
if (rgp->m_rtm.rtm_addrs & RTA_IFP)
li++;
for (int i = 0; i < li; i++)
so_oldifa = (union sockunion *)((char*)so_oldifa +
ROUNDUP(so_oldifa->sa.sa_len));
}
if (so_gate->sa.sa_family != AF_INET) {
debugp("Failed at family check - only INET supoprted for now\n");
return LDP_E_BAD_AF;
}
/* Check if the address is bounded to the peer */
if (check_ifaddr(p, &so_gate->sin.sin_addr) == NULL) {
debugp("Failed at next-hop check\n");
return LDP_E_ROUTE_ERROR;
}
/* CHECK IF WE HAVE A BINDING FOR THAT */
lab = label_get_by_prefix(addr, len);
/* We should have a label because we have a route */
assert (lab);
if (lab->binding == MPLS_LABEL_IMPLNULL) {
change_local_label(lab, get_free_local_label());
if (!lab->binding) {
fatalp("No more free labels !!!\n");
return LDP_E_TOO_MANY_LABELS;
}
}
warnp("[mpls_add_label] Adding %s/%d as local binding %d, label %d"
" to peer %s\n",
inet_ntoa(*addr), len, lab->binding, label, padd);
/* Modify existing label */
lab->label = label;
lab->p = p;
/* Add switching route */
so_dest = make_mpls_union(lab->binding);
so_nexthop = (union sockunion *)malloc(sizeof(union sockunion));
memcpy(so_nexthop, so_gate, so_gate->sa.sa_len);
so_tag = make_mpls_union(label);
if (add_route(so_dest, NULL, so_nexthop, NULL, so_tag, FREESO, RTM_ADD) != LDP_E_OK)
return LDP_E_ROUTE_ERROR;
/* Now, let's add tag to IPv4 route and point it to mpls interface */
so_dest = make_inet_union(inet_ntoa(*addr));
/* if prefixlen == 32 check if it's inserted as host
* and treat it as host. It may also be set as /32 prefix
* (thanks mlelstv for heads-up about this)
*/
if ((len == 32) && (rgp->m_rtm.rtm_flags & RTF_HOST))
so_pref = NULL;
else
so_pref = from_cidr_to_union(len);
/* Add tag to route */
so_nexthop = (union sockunion *)malloc(sizeof(union sockunion));
memcpy(so_nexthop, so_gate, so_gate->sa.sa_len);
so_tag = make_mpls_union(label);
if (so_oldifa != NULL) {
so_ifa = (union sockunion *)malloc(sizeof(union sockunion));
memcpy(so_ifa, so_oldifa, so_oldifa->sa.sa_len);
} else
so_ifa = NULL;
if (add_route(so_dest, so_pref, so_nexthop, so_ifa, so_tag, FREESO, RTM_CHANGE) != LDP_E_OK)
return LDP_E_ROUTE_ERROR;
debugp("Added %s/%d as label %d to peer %s\n", inet_ntoa(*addr), len,
label, padd);
return LDP_E_OK;
}
int
mpls_add_ldp_peer(struct ldp_peer * p)
{
return LDP_E_OK;
}
int
mpls_delete_ldp_peer(struct ldp_peer * p)
{
/* Reput all the routes also to IPv4 */
label_reattach_all_peer_labels(p, LDP_READD_CHANGE);
return LDP_E_OK;
}
int
mpls_start_ldp()
{
ldp_peer_init();
label_init();
return LDP_E_OK;
}

View File

@ -0,0 +1,43 @@
/* $NetBSD: mpls_interface.h,v 1.1 2010/12/08 07:20:14 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MPLS_INTERFACE_H_
#define _MPLS_INTERFACE_H_
#include "mpls_routes.h"
int mpls_add_label(struct ldp_peer *, struct rt_msg *,
struct in_addr *, int, int, int);
int mpls_add_ldp_peer(struct ldp_peer *);
int mpls_delete_ldp_peer(struct ldp_peer *);
int mpls_start_ldp(void);
#endif /* _MPLS_INTERFACE_H_ */

893
usr.sbin/ldpd/mpls_routes.c Normal file
View File

@ -0,0 +1,893 @@
/* $NetBSD: mpls_routes.c,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netmpls/mpls.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ldp.h"
#include "ldp_errors.h"
#include "ldp_peer.h"
#include "mpls_interface.h"
#include "tlv_stack.h"
#include "label.h"
#include "mpls_routes.h"
extern int route_socket;
int rt_seq = 0;
int dont_catch = 0;
struct rt_msg replay_rt[REPLAY_MAX];
int replay_index = 0;
int read_route_socket(char *, int);
void mask_addr(union sockunion *);
int compare_sockunion(union sockunion *, union sockunion *);
char * mpls_ntoa(union mpls_shim);
extern struct sockaddr mplssockaddr;
/* Many lines inspired or shamelessly stolen from sbin/route/route.c */
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
#define NEXTADDR(u) \
do { l = ROUNDUP(u->sa.sa_len); memcpy(cp, u, l); cp += l; } while(0);
#define NEXTADDR2(u) \
do { l = ROUNDUP(u.sa_len); memcpy(cp, &u, l); cp += l; } while(0);
#define GETNEXT(sunion) \
(union sockunion *) ((char *) (sunion) + ROUNDUP((sunion)->sa.sa_len))
int
read_route_socket(char *s, int max)
{
int rv, to_read;
fd_set fs;
struct timeval tv;
struct rt_msghdr *rhdr;
tv.tv_sec = 0;
tv.tv_usec = 5000;
FD_ZERO(&fs);
FD_SET(route_socket, &fs);
errno = 0;
do {
rv = select(route_socket + 1, &fs, NULL, &fs, &tv);
} while ((rv == -1) && (errno == EINTR));
if (rv < 1) {
if (rv == 0) {
fatalp("read_route_socket: select timeout\n");
} else
fatalp("read_route_socket: select: %s",
strerror(errno));
return 0;
}
do {
rv = recv(route_socket, s, max, MSG_PEEK);
} while((rv == -1) && (errno == EINTR));
if (rv < 1) {
debugp("read_route_socket: recv error\n");
return 0;
}
if (rv > max) {
rv = max;
debugp("read_route_socket: rv > max\n");
}
rhdr = (struct rt_msghdr *)s;
to_read = rhdr->rtm_msglen > max ? max : rhdr->rtm_msglen;
rv = 0;
do {
rv += recv(route_socket, s, to_read - rv, 0);
} while (rv != to_read);
return rv;
}
/* Recalculate length */
void
mask_addr(union sockunion * su)
{
/*
int olen = su->sa.sa_len;
char *cp1 = olen + (char *) su;
for (su->sa.sa_len = 0; cp1 > (char *) su;)
if (*--cp1 != 0) {
su->sa.sa_len = 1 + cp1 - (char *) su;
break;
}
*/
/* Let's use INET only version for the moment */
su->sa.sa_len = 4 + from_union_to_cidr(su) / 8 +
( from_union_to_cidr(su) % 8 ? 1 : 0 );
}
/* creates a sockunion from an IP address */
union sockunion *
make_inet_union(char *s)
{
union sockunion *so_inet;
so_inet = (union sockunion *) malloc(sizeof(union sockunion));
if (!so_inet) {
fatalp("make_inet_union: malloc problem\n");
return NULL;
}
memset(so_inet, 0, sizeof(union sockunion));
so_inet->sin.sin_len = sizeof(struct sockaddr_in);
so_inet->sin.sin_family = AF_INET;
inet_aton(s, &so_inet->sin.sin_addr);
return so_inet;
}
/* creates a sockunion from a label */
union sockunion *
make_mpls_union(uint32_t label)
{
union sockunion *so_mpls;
so_mpls = (union sockunion *) malloc(sizeof(union sockunion));
if (!so_mpls) {
fatalp("make_mpls_union: malloc problem\n");
return NULL;
}
memset(so_mpls, 0, sizeof(union sockunion));
so_mpls->smpls.smpls_len = sizeof(struct sockaddr_mpls);
so_mpls->smpls.smpls_family = AF_MPLS;
so_mpls->smpls.smpls_addr.shim.label = label;
so_mpls->smpls.smpls_addr.s_addr =
htonl(so_mpls->smpls.smpls_addr.s_addr);
return so_mpls;
}
int
compare_sockunion(union sockunion * __restrict a,
union sockunion * __restrict b)
{
if (a->sa.sa_len != b->sa.sa_len)
return 1;
return memcmp(a, b, a->sa.sa_len);
}
union sockunion *
from_cidr_to_union(uint8_t prefixlen)
{
union sockunion *u;
int32_t n = -1;
uint32_t *m = (uint32_t*)&n;
*m = (*m >> (32 - prefixlen) ) << (32 - prefixlen);
*m = ntohl(*m);
u = (union sockunion *) malloc(sizeof(union sockunion));
if (!u) {
fatalp("from_cidr_to_union: malloc problem\n");
return NULL;
}
memset (u, 0, sizeof(union sockunion));
u->sin.sin_len = sizeof(struct sockaddr_in);
u->sin.sin_family = AF_INET;
u->sin.sin_addr.s_addr = *m;
return u;
}
uint8_t
from_mask_to_cidr(char *mask)
{
/* LoL (although I don't think about something faster right now) */
char mtest[20];
uint8_t i;
for (i = 1; i < 32; i++) {
from_cidr_to_mask(i, mtest);
if (!strcmp(mask, mtest))
break;
}
return i;
}
uint8_t
from_union_to_cidr(union sockunion *so_pref)
{
struct sockaddr_in *sin = (struct sockaddr_in*)so_pref;
uint32_t a;
uint8_t r;
a = ntohl(sin->sin_addr.s_addr);
for (r=0; a ; a = a << 1, r++);
return r;
}
/* returns in mask the netmask created from CIDR prefixlen */
void
from_cidr_to_mask(uint8_t prefixlen, char *mask)
{
uint32_t a = 0, p = prefixlen;
if (prefixlen > 32) {
strlcpy(mask, "255.255.255.255", 16);
return;
}
for (; p > 0; p--) {
a = a >> (p - 1);
a += 1;
a = a << (p - 1);
}
/* is this OK ? */
#if _BYTE_ORDER == _LITTLE_ENDIAN
a = a << (32 - prefixlen);
#endif
snprintf(mask, 16, "%d.%d.%d.%d", a >> 24, (a << 8) >> 24,
(a << 16) >> 24, (a << 24) >> 24);
}
char *
mpls_ntoa(union mpls_shim ms)
{
static char ret[255];
union mpls_shim ms2;
ms2.s_addr = ntohl(ms.s_addr);
snprintf(ret, sizeof(ret), "%d", ms2.shim.label);
return ret;
}
char *
union_ntoa(union sockunion * so)
{
static char defret[] = "Unknown family address";
switch (so->sa.sa_family) {
case AF_INET:
return inet_ntoa(so->sin.sin_addr);
case AF_LINK:
return link_ntoa(&so->sdl);
case AF_MPLS:
return mpls_ntoa(so->smpls.smpls_addr);
}
fatalp("Unknown family address in union_ntoa: %d\n",
so->sa.sa_family);
return defret;
}
/* From src/sbin/route/route.c */
static const char *
route_strerror(int error)
{
switch (error) {
case ESRCH:
return "not in table";
case EBUSY:
return "entry in use";
case ENOBUFS:
return "routing table overflow";
default:
return strerror(error);
}
}
/* Adds a route. Or changes it. */
int
add_route(union sockunion *so_dest, union sockunion *so_prefix,
union sockunion *so_gate, union sockunion *so_ifa, union sockunion *so_tag,
int fr, int optype)
{
int l, rlen, rv = LDP_E_OK;
struct rt_msg rm;
char *cp;
if(dont_catch)
return LDP_E_OK;
memset(&rm, 0, sizeof(rm));
cp = rm.m_space;
rm.m_rtm.rtm_type = (optype == RTM_READD) ? RTM_ADD : optype;
rm.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
rm.m_rtm.rtm_version = RTM_VERSION;
rm.m_rtm.rtm_seq = ++rt_seq;
rm.m_rtm.rtm_addrs = RTA_DST;
if (so_gate)
rm.m_rtm.rtm_addrs |= RTA_GATEWAY;
assert(so_dest);
/* Order is: destination, gateway, netmask, genmask, ifp, ifa, tag */
NEXTADDR(so_dest);
if (so_gate)
NEXTADDR(so_gate);
if (so_prefix) {
mask_addr(so_prefix);
NEXTADDR(so_prefix);
/* XXX: looks like nobody cares about this */
rm.m_rtm.rtm_flags |= RTF_MASK;
rm.m_rtm.rtm_addrs |= RTA_NETMASK;
} else
rm.m_rtm.rtm_flags |= RTF_HOST;
/* route to mpls interface */
if (optype != RTM_READD && so_dest->sa.sa_family != AF_MPLS) {
NEXTADDR2(mplssockaddr);
rm.m_rtm.rtm_addrs |= RTA_IFP;
}
if (so_ifa != NULL) {
NEXTADDR(so_ifa);
rm.m_rtm.rtm_addrs |= RTA_IFA;
}
if (so_tag) {
NEXTADDR(so_tag);
rm.m_rtm.rtm_addrs |= RTA_TAG;
}
rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
warnp("Error adding a route: %s\n", route_strerror(errno));
warnp("Destination was: %s\n", union_ntoa(so_dest));
if (so_prefix)
warnp("Prefix was: %s\n", union_ntoa(so_prefix));
if (so_gate)
warnp("Gateway was: %s\n", union_ntoa(so_gate));
rv = LDP_E_ROUTE_ERROR;
}
if (fr) {
free(so_dest);
if (so_prefix)
free(so_prefix);
if (so_gate)
free(so_gate);
if (so_ifa)
free(so_ifa);
if (so_tag)
free(so_tag);
}
return rv;
}
/* Deletes a route */
int
delete_route(union sockunion * so_dest, union sockunion * so_pref, int freeso)
{
int l, rlen;
struct rt_msg rm;
char *cp;
if(dont_catch)
return LDP_E_OK;
memset(&rm, 0, sizeof(struct rt_msg));
cp = rm.m_space;
rm.m_rtm.rtm_type = RTM_DELETE;
rm.m_rtm.rtm_version = RTM_VERSION;
rm.m_rtm.rtm_seq = ++rt_seq;
if (so_pref)
rm.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
else
rm.m_rtm.rtm_addrs = RTA_DST;
/* destination, gateway, netmask, genmask, ifp, ifa */
NEXTADDR(so_dest);
if (so_pref) {
mask_addr(so_pref);
NEXTADDR(so_pref);
}
rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
if (freeso == FREESO) {
free(so_dest);
if (so_pref)
free(so_pref);
}
if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
if(so_pref) {
char spreftmp[INET_ADDRSTRLEN];
strlcpy(spreftmp, inet_ntoa(so_pref->sin.sin_addr),
INET_ADDRSTRLEN);
warnp("Error deleting route(%s): %s/%s",
route_strerror(errno), union_ntoa(so_dest),
spreftmp);
} else
warnp("Error deleting route(%s) : %s",
route_strerror(errno), union_ntoa(so_dest));
return LDP_E_NO_SUCH_ROUTE;
}
return LDP_E_OK;
}
/*
* Check for a route and returns it in rg
* If exact_match is set it compares also the so_dest and so_pref
* with the returned result
*/
int
get_route(struct rt_msg * rg, union sockunion * so_dest,
union sockunion * so_pref, int exact_match)
{
int l, rlen, myseq;
struct rt_msg rm;
char *cp;
union sockunion *su;
memset(&rm, 0, sizeof(struct rt_msg));
cp = rm.m_space;
myseq = ++rt_seq;
rm.m_rtm.rtm_type = RTM_GET;
rm.m_rtm.rtm_version = RTM_VERSION;
rm.m_rtm.rtm_seq = myseq;
/*
* rtm_addrs should contain what we provide into this message but
* RTA_DST | RTA_IFP trick is allowed in order to find out the
* interface.
*/
rm.m_rtm.rtm_addrs = RTA_DST | RTA_IFP;
/*
* ORDER of fields is: destination, gateway, netmask, genmask, ifp,
* ifa
*/
NEXTADDR(so_dest);
if (so_pref) {
rm.m_rtm.rtm_addrs |= RTA_NETMASK;
mask_addr(so_pref);
NEXTADDR(so_pref);
}
rm.m_rtm.rtm_msglen = l = cp - (char *) &rm;
if ((rlen = write(route_socket, (char *) &rm, l)) < l) {
debugp("Cannot get a route !(rlen=%d instead of %d) - %s\n",
rlen, l, strerror(errno));
return LDP_E_NO_SUCH_ROUTE;
} else
do {
rlen = read_route_socket((char *) rg,
sizeof(struct rt_msg));
if (rlen < 1)
break;
/*
* We might lose important messages here. WORKAROUND:
* For now I just try to save this messages and replay
* them later
*/
if ((rg->m_rtm.rtm_pid != getpid()) ||
(rg->m_rtm.rtm_seq != myseq)) {
/*
* Shortcut: my pid but not
* the expected sequence
*/
if (rg->m_rtm.rtm_pid == getpid())
continue;
debugp("Added to replay PID: %d, SEQ: %d\n",
rg->m_rtm.rtm_pid, rg->m_rtm.rtm_seq);
memcpy(&replay_rt[replay_index], rg,
sizeof(struct rt_msg));
if (replay_index < REPLAY_MAX - 1)
replay_index++;
continue;
}
} while ((rg->m_rtm.rtm_seq != myseq) ||
(rg->m_rtm.rtm_pid != getpid()));
if ((uint)rlen <= sizeof(struct rt_msghdr)) {
debugp("Got only %d bytes, expecting at least %u\n", rlen,
sizeof(struct rt_msghdr));
return LDP_E_ROUTE_ERROR;
}
/* Check if we don't have a less specific route */
if (exact_match) {
su = (union sockunion*)(rg->m_space);
if (compare_sockunion(so_dest, su)) {
debugp("Dest %s ", union_ntoa(so_dest));
debugp("not like %s\n", union_ntoa(su));
return LDP_E_NO_SUCH_ROUTE;
}
}
return LDP_E_OK;
}
/* triggered when a route event occurs */
int
check_route(struct rt_msg * rg, uint rlen)
{
union sockunion *so_dest = NULL, *so_gate = NULL, *so_pref = NULL;
int so_pref_allocated = 0;
int prefixlen;
struct peer_map *pm;
struct label *lab;
char dest[50], gate[50], pref[50], oper[50];
dest[0] = 0;
gate[0] = 0;
pref[0] = 0;
if (rlen <= sizeof(struct rt_msghdr))
return LDP_E_ROUTE_ERROR;
if (rg->m_rtm.rtm_version != RTM_VERSION)
return LDP_E_ROUTE_ERROR;
if ((rg->m_rtm.rtm_flags & RTF_DONE) == 0)
return LDP_E_OK;
if (rg->m_rtm.rtm_pid == getpid()) /* We did it.. */
return LDP_E_OK;
else
debugp("Check route triggered by PID: %d\n", rg->m_rtm.rtm_pid);
so_dest = (union sockunion *) rg->m_space;
if (so_dest->sa.sa_family != AF_INET)
return LDP_E_OK;/* We don't care about non-IP changes */
if (rg->m_rtm.rtm_addrs & RTA_GATEWAY) {
so_gate = GETNEXT(so_dest);
if ((so_gate->sa.sa_family != AF_INET) &&
(so_gate->sa.sa_family != AF_MPLS))
return LDP_E_OK;
}
if (rg->m_rtm.rtm_addrs & RTA_NETMASK) {
if (so_gate)
so_pref = so_gate;
else
so_pref = so_dest;
so_pref = GETNEXT(so_pref);
}
if (!(rg->m_rtm.rtm_flags & RTF_GATEWAY)) {
if (rg->m_rtm.rtm_addrs & RTA_GENMASK) {
debugp("Used GENMASK\n");
} else
debugp("No GENMASK to use\n");
}
/* Calculate prefixlen */
if (so_pref)
prefixlen = from_mask_to_cidr(inet_ntoa(so_pref->sin.sin_addr));
else {
prefixlen = 32;
so_pref = from_cidr_to_union(32);
so_pref_allocated = 1;
}
so_pref->sa.sa_family = AF_INET;
so_pref->sa.sa_len = sizeof(struct sockaddr_in);
switch (rg->m_rtm.rtm_type) {
case RTM_CHANGE:
warnp("XXX: RTM_CHANGE\n");
/* Fallthrough */
case RTM_ADD:
/*
* Check if the route is connected. If so, bind it to
* POP_LABEL and send announce. If not, check if the prefix
* was announced by a LDP neighbour and route it there
*/
/* First of all check if we already know this one */
lab = label_get(so_dest, so_pref);
if (!lab) {
if (!(rg->m_rtm.rtm_flags & RTF_GATEWAY))
lab = label_add(so_dest, so_pref, NULL,
MPLS_LABEL_IMPLNULL, NULL, 0);
else {
pm = ldp_test_mapping(&so_dest->sin.sin_addr,
prefixlen, &so_gate->sin.sin_addr);
if (pm) {
lab = label_add(so_dest, so_pref,
so_gate, 0, NULL, 0);
mpls_add_label(pm->peer, rg,
&so_dest->sin.sin_addr, prefixlen,
pm->lm->label, ROUTE_LOOKUP_LOOP);
free(pm);
} else
lab = label_add(so_dest, so_pref,
so_gate, MPLS_LABEL_IMPLNULL,
NULL, 0);
}
} else /* We already know about this prefix */
debugp("Binding already there for prefix %s/%d !\n",
union_ntoa(so_dest), prefixlen);
break;
case RTM_DELETE:
if (!so_gate)
break; /* Non-existent route XXX ?! */
/*
* Send withdraw check the binding, delete the route, delete
* the binding
*/
lab = label_get(so_dest, so_pref);
if (!lab)
break;
send_withdraw_tlv_to_all(&so_dest->sin.sin_addr, prefixlen);
/* No readd as IPv4. Also don't even try to delete it */
label_reattach_route(lab, LDP_READD_NODEL);
label_del(lab);
break;
}
/* Rest is just for debug */
if (so_dest)
strlcpy(dest, union_ntoa(so_dest), 16);
if (so_pref)
snprintf(pref, 3, "%d", prefixlen);
if (so_gate)
strlcpy(gate, union_ntoa(so_gate), 16);
switch (rg->m_rtm.rtm_type) {
case RTM_ADD:
strlcpy(oper, "added", 20);
break;
case RTM_DELETE:
strlcpy(oper, "delete", 20);
break;
case RTM_GET:
strlcpy(oper, "get", 20);
break;
case RTM_CHANGE:
strlcpy(oper, "change", 20);
break;
case RTM_LOSING:
strlcpy(oper, "losing", 20);
break;
case RTM_NEWADDR:
strlcpy(oper, "new address", 20);
break;
case RTM_DELADDR:
strlcpy(oper, "del address", 20);
break;
default:
snprintf(oper, 50, "unknown 0x%X operation",
rg->m_rtm.rtm_type);
}
warnp("[check_route] Route %s: %s / %s -> %s by PID:%d\n", oper, dest,
pref, gate, rg->m_rtm.rtm_pid);
if(so_pref_allocated)
free(so_pref);
return LDP_E_OK;
}
int
bind_current_routes()
{
size_t needed;
int mib[6];
char *buf, *next, *lim;
struct rt_msghdr *rtmes;
union sockunion *so_dst, *so_pref, *so_gate;
struct label *lab;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
fatalp("route-sysctl-estimate: %s",
strerror(errno));
return LDP_E_ROUTE_ERROR;
}
if ((buf = malloc(needed)) == 0)
return LDP_E_ROUTE_ERROR;
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
free(buf);
return LDP_E_ROUTE_ERROR;
}
lim = buf + needed;
for (next = buf; next < lim; next += rtmes->rtm_msglen) {
rtmes = (struct rt_msghdr *) next;
so_pref = NULL;
so_gate = NULL;
if (rtmes->rtm_flags & RTF_LLINFO) /* No need for arps */
continue;
if (!(rtmes->rtm_addrs & RTA_DST)) {
debugp("No dst\n");
continue;
}
so_dst = (union sockunion *) & rtmes[1];
/*
* As this function is call only at startup use this ocassion
* to delete all MPLS routes
*/
if (so_dst->sa.sa_family == AF_MPLS) {
delete_route(so_dst, NULL, NO_FREESO);
debugp("MPLS route deleted.\n");
continue;
}
if (so_dst->sa.sa_family != AF_INET) {
debugp("sa_dst is not AF_INET\n");
continue;
}
/* Check if it's the default gateway */
if (so_dst->sin.sin_addr.s_addr == 0)
continue;
/* XXX: Check if it's loopback */
if ((ntohl(so_dst->sin.sin_addr.s_addr) >> 24)==IN_LOOPBACKNET)
continue;
/* Get Gateway */
if (rtmes->rtm_addrs & RTA_GATEWAY)
so_gate = GETNEXT(so_dst);
/* Get prefix */
if (rtmes->rtm_flags & RTF_HOST)
so_pref = from_cidr_to_union(32);
else if (rtmes->rtm_addrs & RTA_GATEWAY)
so_pref = GETNEXT(so_gate);
else
so_pref = GETNEXT(so_dst);
so_pref->sa.sa_family = AF_INET;
so_pref->sa.sa_len = sizeof(struct sockaddr_in);
/* Also deletes when dest is IPv4 and gateway MPLS */
if ((rtmes->rtm_addrs & RTA_GATEWAY) &&
(so_gate->sa.sa_family == AF_MPLS)) {
debugp("MPLS route to %s deleted.\n",
inet_ntoa(so_dst->sin.sin_addr));
delete_route(so_dst, so_pref, NO_FREESO);
if (rtmes->rtm_flags & RTF_HOST)
free(so_pref);
continue;
}
if (so_gate->sa.sa_family == AF_INET)
lab = label_add(so_dst, so_pref, so_gate,
MPLS_LABEL_IMPLNULL, NULL, 0);
if (rtmes->rtm_flags & RTF_HOST)
free(so_pref);
}
free(buf);
return LDP_E_OK;
}
int
flush_mpls_routes()
{
size_t needed;
int mib[6];
char *buf, *next, *lim;
struct rt_msghdr *rtm;
union sockunion *so_dst, *so_pref, *so_gate;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0;
mib[3] = 0;
mib[4] = NET_RT_DUMP;
mib[5] = 0;
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
fatalp("route-sysctl-estimate: %s", strerror(errno));
return LDP_E_ROUTE_ERROR;
}
if ((buf = malloc(needed)) == 0)
return LDP_E_ROUTE_ERROR;
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
free(buf);
return LDP_E_ROUTE_ERROR;
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *) next;
so_pref = NULL;
so_gate = NULL;
if (rtm->rtm_flags & RTF_LLINFO) /* No need for arps */
continue;
if (!(rtm->rtm_addrs & RTA_DST)) {
debugp("No dst\n");
continue;
}
so_dst = (union sockunion *) & rtm[1];
if (so_dst->sa.sa_family == AF_MPLS) {
delete_route(so_dst, NULL, NO_FREESO);
debugp("MPLS route deleted.\n");
continue;
}
if (rtm->rtm_addrs & RTA_GATEWAY) {
so_gate = GETNEXT(so_dst);
so_pref = GETNEXT(so_gate);
} else
so_pref = GETNEXT(so_dst);
if (so_gate->sa.sa_family == AF_MPLS) {
debugp("MPLS route to %s deleted.\n",
inet_ntoa(so_dst->sin.sin_addr));
delete_route(so_dst, so_pref, NO_FREESO);
continue;
}
}
free(buf);
return LDP_E_OK;
}

View File

@ -0,0 +1,78 @@
/* $NetBSD: mpls_routes.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MPLS_ROUTES_H_
#define _MPLS_ROUTES_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netmpls/mpls.h>
#include <arpa/inet.h>
#define NO_FREESO 0
#define FREESO 1
#define RTM_READD -1
union sockunion {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_mpls smpls;
struct sockaddr_dl sdl;
};
struct rt_msg {
struct rt_msghdr m_rtm;
char m_space[512];
} __packed;
union sockunion * make_inet_union(char *);
union sockunion * make_mpls_union(uint32_t);
union sockunion * make_mplsinet_union(uint16_t peer, uint32_t label,
struct in_addr *addr);
uint8_t from_mask_to_cidr(char *);
void from_cidr_to_mask(uint8_t, char *);
int add_route(union sockunion *, union sockunion *, union sockunion *,
union sockunion *, union sockunion *, int, int);
int delete_route(union sockunion *, union sockunion *, int);
int get_route(struct rt_msg *, union sockunion *, union sockunion *, int);
int bind_current_routes(void);
int flush_mpls_routes(void);
int check_route(struct rt_msg *, uint);
char* union_ntoa(union sockunion *);
uint8_t from_union_to_cidr(union sockunion *);
union sockunion * from_cidr_to_union(uint8_t);
#endif /* !_MPLS_ROUTES_H_ */

View File

@ -0,0 +1,79 @@
/* $NetBSD: notifications.c,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <stdlib.h>
#include "ldp.h"
#include "socketops.h"
#include "tlv.h"
#include "ldp_errors.h"
#include "notifications.h"
/* builds a notification TLV. Do not forget to free the result */
struct notification_tlv *
build_notification(uint32_t msg, uint32_t n)
{
struct notification_tlv *t;
t = (struct notification_tlv *) malloc(sizeof(struct notification_tlv));
if (!t) {
fatalp("build_notification: malloc problem\n");
return NULL;
}
t->type = htons(LDP_NOTIFICATION);
t->length = htons(sizeof(struct notification_tlv) - TLV_TYPE_LENGTH);
t->status = htons(TLV_STATUS);
t->st_len = sizeof(struct notification_tlv) - 2 * TLV_TYPE_LENGTH;
t->st_code = htonl(n);
t->msg_id = htonl(msg);
t->msg_type = 0;
return t;
}
int
send_notification(struct ldp_peer * p, uint32_t msg, uint32_t code)
{
struct notification_tlv *nt;
int rv;
if (p->state != LDP_PEER_CONNECTED && p->state != LDP_PEER_ESTABLISHED)
return -1;
nt = build_notification(msg, code);
rv = send_tlv(p, (struct tlv *) nt);
free(nt);
return rv;
}

View File

@ -0,0 +1,98 @@
/* $NetBSD: notifications.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _NOTIFICATIONS_H_
#define _NOTIFICATIONS_H_
/* Notifications codes RFC3036 2.9 */
#define NOTIF_SUCCESS 0x00000000
#define NOTIF_BAD_LDP_ID 0x00000001
#define NOTIF_BAD_LDP_VER 0x00000002
#define NOTIF_BAD_PDU_LEN 0x00000003
#define NOTIF_UNKNOWN_MESSAGE 0x00000004
#define NOTIF_BAD_MSG_LEN 0x00000005
#define NOTIF_UNKNOWN_TLV 0x00000006
#define NOTIF_BAD_TLV_LEN 0x00000007
#define NOTIF_MALFORMED_TLV_VALUE 0x00000008
#define NOTIF_HOLD_TIME_EXPIRED 0x00000009
#define NOTIF_SHUTDOWN 0x0000000A
#define NOTIF_LOOP_DETECTED 0x0000000B
#define NOTIF_UNKNOWN_FEC 0x0000000C
#define NOTIF_NO_ROUTE 0x0000000D
#define NOTIF_NO_LABEL_RESOURCES 0x0000000E
#define NOTIF_LABEL_RESOURCES_AVAIL 0x0000000F
#define NOTIF_SESSION_REJECTED_NO_HELLO 0x00000010
#define NOTIF_SESSION_REJECTED_ADV_MODE 0x00000011
#define NOTIF_SESSION_REJECTED_MAX_PDU 0x00000012
#define NOTIF_SESSION_REJECTED_LRANGE 0x00000013
#define NOTIF_KEEP_ALIVE_TIMER_EXPIRED 0x00000014
#define NOTIF_LABEL_REQUEST_ABORTED 0x00000015
#define NOTIF_MISSING_MESSAGE 0x00000016
#define NOTIF_UNSUPPORTED_AF 0x00000017
#define NOTIF_SESSION_REJECTED_BAD_KEEP 0x00000018
#define NOTIF_INTERNAL_ERROR 0x00000019
#define NOTIF_FATAL 0x80000000
static const char *NOTIF_STR[] __unused =
{
"Success",
"Bad LDP ID",
"Bad LDP Version",
"Bad PDU Length",
"Unknown message",
"Bad message length",
"Unknown TLV",
"Bad TLV Length",
"Malformed TLV Value",
"Hold time expired",
"Shutdown",
"Loop detected",
"Unknown FEC",
"No route",
"No label resources",
"Label resources available",
"Session rejected: No hello",
"Session rejected: Parameters Advertising Mode",
"Session rejected: Max PDU Length",
"Session rejected: Label range",
"Keepalive timer expired",
"Label request aborted",
"Missing message",
"Unsupported Address Family",
"Session rejected: Bad keepalive time",
"Internal error"
};
struct notification_tlv * build_notification(uint32_t, uint32_t);
int send_notification(struct ldp_peer *, uint32_t, uint32_t);
#endif /* !_NOTIFICATIONS_H_ */

90
usr.sbin/ldpd/pdu.c Normal file
View File

@ -0,0 +1,90 @@
/* $NetBSD: pdu.c,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include "socketops.h"
#include "ldp_errors.h"
#include "ldp.h"
#include "ldp_peer.h"
#include "notifications.h"
#include "pdu.h"
uint
get_pdu(unsigned char *s, struct ldp_pdu * p)
{
struct ldp_pdu *p1;
p1 = (struct ldp_pdu *) s;
p->version = ntohs(p1->version);
p->length = ntohs(p1->length);
memcpy(&p->ldp_id, &p1->ldp_id, sizeof(struct in_addr));
p->label_space = ntohs(p1->label_space);
return MIN_PDU_SIZE;
}
/* Checks an incoming PDU for size and version */
int
check_recv_pdu(struct ldp_peer * p, struct ldp_pdu * rpdu, int c)
{
struct notification_tlv *notiftlv;
/* Avoid underflow */
if (c < MIN_PDU_SIZE)
return LDP_E_BAD_LENGTH;
/* Check PDU for right LDP version */
if (ntohs(rpdu->version) != LDP_VERSION) {
fatalp("Invalid PDU version received from %s (%d)\n",
inet_ntoa(p->address), ntohs(rpdu->version));
notiftlv = build_notification(0, NOTIF_BAD_LDP_VER);
send_tlv(p, (struct tlv *) notiftlv);
free(notiftlv);
return LDP_E_BAD_VERSION;
}
/* Check PDU for length validity */
if (ntohs(rpdu->length) > c - PDU_VER_LENGTH) {
fatalp("Invalid PDU length received from %s (announced %d, "
"received %d)\n", inet_ntoa(p->address),
ntohs(rpdu->length), (int) (c - PDU_VER_LENGTH));
notiftlv = build_notification(0, NOTIF_BAD_PDU_LEN);
send_tlv(p, (struct tlv *) notiftlv);
free(notiftlv);
return LDP_E_BAD_LENGTH;
}
return LDP_E_OK;
}

58
usr.sbin/ldpd/pdu.h Normal file
View File

@ -0,0 +1,58 @@
/* $NetBSD: pdu.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _PDU_H_
#define _PDU_H_
#include <sys/types.h>
#include <netinet/in.h>
#include "ldp_peer.h"
#define MIN_PDU_SIZE 10
#define MAX_PDU_SIZE 1300
#define PDU_VER_LENGTH (sizeof(uint16_t) + sizeof(uint16_t))
#define PDU_PAYLOAD_LENGTH (sizeof(struct in_addr) + sizeof(uint16_t))
struct ldp_pdu {
uint16_t version;
uint16_t length;
struct in_addr ldp_id;
uint16_t label_space;
} __packed;
uint get_pdu(unsigned char *, struct ldp_pdu *);
int check_recv_pdu(struct ldp_peer *, struct ldp_pdu *, int);
#endif /* !_PDU_H_ */

1055
usr.sbin/ldpd/socketops.c Normal file

File diff suppressed because it is too large Load Diff

69
usr.sbin/ldpd/socketops.h Normal file
View File

@ -0,0 +1,69 @@
/* $NetBSD: socketops.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SOCKETOPS_H_
#define _SOCKETOPS_H_
#include "mpls_routes.h"
#include "ldp_peer.h"
#include "pdu.h"
#include "tlv.h"
/* Address families from RFC1700 */
#define LDP_AF_INET 1
#define LDP_AF_INET6 2
int set_ttl(int);
int set_mcast_ttl(int);
int set_tos(int);
int socket_reuse_port(int);
int bind_socket(int, uint32_t);
int create_hello_socket(void);
int create_listening_socket(void);
void send_hello(void);
int get_message_id(void);
void the_big_loop(void);
void new_peer_connection(void);
void send_initialize(struct ldp_peer *);
void keep_alive(struct ldp_peer *);
void recv_session_pdu(struct ldp_peer *);
int send_message(struct ldp_peer *, struct ldp_pdu *, struct tlv *);
int send_tlv(struct ldp_peer *, struct tlv *);
int send_addresses(struct ldp_peer *);
struct hello_info {
struct in_addr address, transport_address, ldp_id;
int keepalive;
SLIST_ENTRY(hello_info) infos;
};
SLIST_HEAD(,hello_info) hello_info_head;
#endif /* !_SOCKETOPS_H_ */

75
usr.sbin/ldpd/tlv.c Normal file
View File

@ -0,0 +1,75 @@
/* $NetBSD: tlv.c,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/stat.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#include "ldp.h"
#include "fsm.h"
#include "ldp_errors.h"
#include "tlv.h"
/* Reads and checks a tlv struct from a buffer */
struct hello_tlv *
get_hello_tlv(unsigned char *s, uint max)
{
struct hello_tlv *t;
/* Do we have at least Type + Length + MSG_ID ? */
if (max <= TLV_TYPE_LENGTH + MSGID_SIZE)
return NULL;
t = (struct hello_tlv *) s;
if (ntohs(t->type) != LDP_HELLO)
return NULL;
/* Does its size fit into max ? */
if (ntohs(t->length) + TLV_TYPE_LENGTH > max)
return NULL;
t->type = ntohs(t->type);
t->length = ntohs(t->length);
t->messageid = ntohl(t->messageid);
return t;
/* We don't check for Common Hello Params here */
}
/* Prints out some information about TLV */
void
debug_tlv(struct tlv * t)
{
warnp("TLV type %.4X, Length %d, Message ID %.8X\n", ntohs(t->type),
ntohs(t->length), ntohs(t->messageid));
}

206
usr.sbin/ldpd/tlv.h Normal file
View File

@ -0,0 +1,206 @@
/* $NetBSD: tlv.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TLV_H_
#define _TLV_H_
/* TLV messages */
#define TLV_FEC 0x0100
#define TLV_ADDRESS_LIST 0x0101
#define TLV_HOP_COUNT 0x0103
#define TLV_PATH_VECTOR 0x0104
#define TLV_GENERIC_LABEL 0x0200
#define TLV_ATM_LABEL 0x0201
#define TLV_FR_LABEL 0x0202
#define TLV_STATUS 0x0300
#define TLV_EXTENDED_STATUS 0x0301
#define TLV_RETURNED_PDU 0x0302
#define TLV_RETURNED_MESSAGE 0x0303
#define TLV_COMMON_HELLO 0x0400
#define TLV_IPV4_TRANSPORT 0x0401
#define TLV_CONFIGURATION_SEQ 0x0402
#define TLV_IPV6_TRANSPORT 0x0403
#define TLV_COMMON_SESSION 0x0500
#define TLV_ATM_SESSION 0x0501
#define TLV_FR_SESSION 0x0502
#define TLV_LABEL_REQUEST 0x0600
/* Some common lengths in order to avoid writing them every time */
#define TLV_TYPE_LENGTH (sizeof(uint16_t) + sizeof(uint16_t))
#define MSGID_SIZE (sizeof(uint32_t))
/* General TLV structure */
struct tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
void *value;
struct ldp_pdu *pdu;
} __packed;
/* Common Hello TLV structure */
struct common_hello_tlv {
uint16_t type;
uint16_t length;
uint16_t holdtime;
union {
/* XXX: Endianness ?! */
uint8_t tr:2;
uint16_t res;
};
} __packed;
/* Hello TLV structure */
struct hello_tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
struct common_hello_tlv ch;
/* XXX: optional parameters */
} __packed;
/* IPv4 Transport address TLV */
struct transport_address_tlv {
uint16_t type;
uint16_t length;
struct in_addr address;
} __packed;
#define CS_LEN (sizeof(struct init_tlv) - TLV_TYPE_LENGTH - MSGID_SIZE - \
sizeof(uint32_t))
/* Initialization TLV structure */
struct init_tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
/*
* Common Session Parameters
*/
uint16_t cs_type;
uint16_t cs_len;
uint16_t cs_version;
uint16_t cs_keepalive;
uint16_t cs_adpvlim; /* XXX */
uint16_t cs_maxpdulen;
struct in_addr cs_peeraddress;
uint16_t cs_peeraddrspace;
} __packed;
/* Keepalive TLV */
struct ka_tlv { /* Keepalive message */
uint16_t type;
uint16_t length;
uint32_t messageid;
} __packed;
/* Notification TLV */
struct notification_tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
uint16_t status;
uint16_t st_len;
uint32_t st_code;
uint32_t msg_id;
uint32_t msg_type;
} __packed;
/* Address LIST TLV for SEND */
struct address_list_tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
uint16_t a_type;
uint16_t a_length;
uint16_t a_af;
struct in_addr a_address;
} __packed;
/* Real AL TLV used for RCV for now */
struct al_tlv {
uint16_t type;
uint16_t length;
uint16_t af;
struct in_addr address;
} __packed;
struct address_tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
} __packed;
/* Label map TLV */
struct label_map_tlv {
uint16_t type;
uint16_t length;
uint32_t messageid;
} __packed;
/* FEC TLV */
struct fec_tlv {
uint16_t type;
uint16_t length;
} __packed;
struct prefix_tlv {
uint8_t type;
uint16_t af;
uint8_t prelen;
struct in_addr prefix;
} __packed;
struct host_tlv {
uint8_t type;
uint16_t af;
uint8_t length;
struct in_addr address;
} __packed;
struct label_tlv {
uint16_t type;
uint16_t length;
uint32_t label;
} __packed;
/* Label Request Message ID TLV */
struct label_request_tlv {
uint16_t type;
uint16_t length; /* 4 */
uint32_t messageid;
} __packed;
struct hello_tlv * get_hello_tlv(unsigned char *, uint);
void debug_tlv(struct tlv *);
#endif /* !_TLV_H_ */

415
usr.sbin/ldpd/tlv_stack.c Normal file
View File

@ -0,0 +1,415 @@
/* $NetBSD: tlv_stack.c,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <arpa/inet.h>
#include <netmpls/mpls.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "ldp.h"
#include "ldp_errors.h"
#include "ldp_peer.h"
#include "tlv.h"
#include "socketops.h"
#include "pdu.h"
#include "label.h"
#include "mpls_interface.h"
#include "tlv_stack.h"
uint8_t ldp_ceil8(int);
uint8_t
ldp_ceil8(int x)
{
if (x % 8 == 0)
return x / 8;
return x / 8 + 1;
}
int
map_label(struct ldp_peer * p, struct fec_tlv * f, struct label_tlv * l)
{
int n;
struct prefix_tlv *pref;
struct in_addr inatmp;
if (ntohs(f->type) != TLV_FEC) {
debugp("Invalid FEC TLV !\n");
return LDP_E_BAD_FEC;
}
if (ntohs(l->type) != TLV_GENERIC_LABEL) {
debugp("Invalid LABEL TLV! (0x%.4X)\n", ntohs(l->type));
return LDP_E_BAD_LABEL;
}
/*
* Actually address field length is given only in length field in
* bits !
*/
n = ntohs(f->length);
if (!n)
return LDP_E_BAD_FEC;
debugp("Label %u for:\n", ntohl(l->label));
pref = (struct prefix_tlv *) & f[1];
/*
* Section 3.4.1
* Note that this version of LDP supports the use of multiple FEC
* Elements per FEC for the Label Mapping message only. The use of
* multiple FEC Elements in other messages is not permitted in this
* version, and is a subject for future study.
*/
for (; n > 0; pref = (struct prefix_tlv *) ((unsigned char *) pref +
ldp_ceil8(pref->prelen) + TLV_TYPE_LENGTH)) {
n -= ldp_ceil8(pref->prelen) + TLV_TYPE_LENGTH;
if (ntohs(pref->af) != LDP_AF_INET) {
debugp("BAD ADDRESS FAMILY (%d) ! (prefix type %d, "
"length %d)\n", ntohs(pref->af), pref->type,
pref->prelen);
return LDP_E_BAD_AF;
}
switch(pref->type) {
case FEC_PREFIX:
case FEC_HOST:
memset(&inatmp, 0, sizeof(struct in_addr));
memcpy(&inatmp, &pref->prefix, ldp_ceil8(pref->prelen));
debugp("Prefix/Host add: %s/%d\n", inet_ntoa(inatmp),
pref->prelen);
ldp_peer_add_mapping(p, &inatmp, pref->prelen,
ntohl(l->label));
mpls_add_label(p, NULL, &inatmp, pref->prelen,
ntohl(l->label), 1);
break;
case FEC_WILDCARD:
fatalp("LDP: Wildcard add from peer %s\n",
inet_ntoa(p->address));
return LDP_E_BAD_FEC;
default:
fatalp("Unknown FEC type %d\n", pref->type);
return LDP_E_BAD_FEC;
}
}
return LDP_E_OK;
}
int
withdraw_label(struct ldp_peer * p, struct fec_tlv * f)
{
int n;
struct prefix_tlv *pref;
struct in_addr inatmp;
struct label *lab;
if (ntohs(f->type) != TLV_FEC) {
debugp("Invalid FEC TLV !\n");
return LDP_E_BAD_FEC;
}
n = ntohs(f->length);
if (!n)
return LDP_E_BAD_FEC;
pref = (struct prefix_tlv *) & f[1];
if (ntohs(pref->af) != LDP_AF_INET) {
debugp("BAD ADDRESS FAMILY (%d)! (prefix type %d, length %d)\n",
ntohs(pref->af), pref->type, pref->prelen);
return LDP_E_BAD_AF;
}
switch(pref->type) {
case FEC_PREFIX:
case FEC_HOST:
memset(&inatmp, 0, sizeof(struct in_addr));
memcpy(&inatmp, &pref->prefix, ldp_ceil8(pref->prelen));
debugp("Prefix/Host withdraw: %s/%d\n", inet_ntoa(inatmp),
pref->prelen);
/* Delete mapping */
ldp_peer_delete_mapping(p, &inatmp, pref->prelen);
/* Get label, see if we're pointing to this peer
* if so, send withdraw, reattach IP route and announce
* POP Label
*/
lab = label_get_by_prefix(&inatmp, pref->prelen);
if ((lab) && (lab->p == p)) {
change_local_label(lab, MPLS_LABEL_IMPLNULL);
label_reattach_route(lab, LDP_READD_CHANGE);
}
break;
case FEC_WILDCARD:
fatalp("LDP neighbour %s: Wildcard withdraw !!!\n",
inet_ntoa(p->address));
ldp_peer_delete_mapping(p, NULL, 0);
label_reattach_all_peer_labels(p, LDP_READD_CHANGE);
break;
default:
fatalp("Unknown FEC type %d\n", pref->type);
return LDP_E_BAD_FEC;
}
return LDP_E_OK;
}
/*
* In case of label redraw, reuse the same buffer to send label release
* Simply replace type and message id
*/
void
prepare_release(struct tlv * v)
{
struct label_map_tlv *t;
t = (struct label_map_tlv *) v;
t->type = htons(LDP_LABEL_RELEASE);
t->messageid = htonl(get_message_id());
}
/* Sends a label mapping */
void
send_label_tlv(struct ldp_peer * peer, struct in_addr * addr,
uint8_t prefixlen, uint32_t label, struct label_request_tlv *lrt)
{
struct label_map_tlv *lmt;
struct fec_tlv *fec;
struct prefix_tlv *p;
struct label_tlv *l;
/*
* Ok, so we have label map tlv that contains fec tlvs and label tlv
* but fec tlv contains prefix or host tlvs and prefix or host tlvs
* contains the network. After that we may have optional parameters
* Got it ?
*/
lmt = (struct label_map_tlv *) malloc(
sizeof(struct label_map_tlv) +
sizeof(struct fec_tlv) +
sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen) +
sizeof(struct label_tlv) +
/* Label request optional parameter */
(lrt != NULL ? sizeof(struct label_request_tlv) : 0) );
if (!lmt) {
fatalp("send_label_tlv: malloc problem\n");
return;
}
lmt->type = htons(LDP_LABEL_MAPPING);
lmt->length = htons(sizeof(struct label_map_tlv) - TLV_TYPE_LENGTH
+ sizeof(struct fec_tlv)
+ sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen)
+ sizeof(struct label_tlv) +
+ (lrt != NULL ? sizeof(struct label_request_tlv) : 0));
lmt->messageid = htonl(get_message_id());
/* FEC TLV */
fec = (struct fec_tlv *) & lmt[1];
fec->type = htons(TLV_FEC);
fec->length = htons(sizeof(struct fec_tlv) - TLV_TYPE_LENGTH
+ sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen));
/* Now let's do the even a dirtier job: PREFIX TLV */
p = (struct prefix_tlv *) & fec[1];
/* Cisco and Juniper don't support FEC type HOST
* so everything is FEC_PREFIX..
*
* if (prefixlen == 32) p->type = FEC_HOST; else
*/
p->type = FEC_PREFIX;
p->af = htons(LDP_AF_INET);
p->prelen = prefixlen;
memcpy(&p->prefix, addr, ldp_ceil8(prefixlen));
/* LABEL TLV */
l = (struct label_tlv *) ((unsigned char *) p +
sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen));
l->type = htons(TLV_GENERIC_LABEL);
l->length = htons(sizeof(l->label));
l->label = htonl(label);
/* Label request optional parameter */
if (lrt)
memcpy(((char*)l) + TLV_TYPE_LENGTH + ntohs(l->length),
lrt, htons(lrt->length) + TLV_TYPE_LENGTH);
/* Wow, seems we're ready */
send_tlv(peer, (struct tlv *) lmt);
free(lmt);
}
void
send_label_tlv_to_all(struct in_addr * addr, uint8_t prefixlen, uint32_t label)
{
struct ldp_peer *p;
SLIST_FOREACH(p, &ldp_peer_head, peers)
send_label_tlv(p, addr, prefixlen, label, NULL);
}
/*
* Send all local labels to a peer
*/
void
send_all_bindings(struct ldp_peer * peer)
{
struct label *l;
SLIST_FOREACH(l, &label_head, labels)
send_label_tlv(peer, &((struct sockaddr_in*)(&l->so_dest))->sin_addr,
from_union_to_cidr(&l->so_pref), l->binding, NULL);
}
/* Sends a label WITHDRAW */
void
send_withdraw_tlv(struct ldp_peer * peer, struct in_addr * addr,
uint8_t prefixlen)
{
struct label_map_tlv *lmt;
struct fec_tlv *fec;
struct prefix_tlv *p;
/*
* Ok, so we have label map tlv that contains fec tlvs but fec tlv
* contains prefix or host tlvs and prefix or host tlvs contains the
* network. Yes, we don't have to announce label here
*/
lmt = (struct label_map_tlv *) malloc(sizeof(struct label_map_tlv)
+ sizeof(struct fec_tlv)
+ sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen));
if (!lmt) {
fatalp("send_withdraw_tlv: malloc problem\n");
return;
}
lmt->type = htons(LDP_LABEL_WITHDRAW);
lmt->length = htons(sizeof(struct label_map_tlv) - TLV_TYPE_LENGTH
+ sizeof(struct fec_tlv)
+ sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen));
lmt->messageid = htonl(get_message_id());
/* FEC TLV */
fec = (struct fec_tlv *) & lmt[1];
fec->type = htons(TLV_FEC);
fec->length = htons(sizeof(struct fec_tlv) - TLV_TYPE_LENGTH
+ sizeof(struct prefix_tlv) - sizeof(struct in_addr) +
ldp_ceil8(prefixlen));
/* Now the even dirtier job: PREFIX TLV */
p = (struct prefix_tlv *) & fec[1];
/* See above comment
*
* if (prefixlen == 32) p->type = FEC_HOST; else
*/
p->type = FEC_PREFIX;
p->af = htons(LDP_AF_INET);
p->prelen = prefixlen;
memcpy(&p->prefix, addr, ldp_ceil8(prefixlen));
/* Wow, seems we're ready */
send_tlv(peer, (struct tlv *) lmt);
free(lmt);
}
void
send_withdraw_tlv_to_all(struct in_addr * addr, uint8_t prefixlen)
{
struct ldp_peer *p;
SLIST_FOREACH(p, &ldp_peer_head, peers)
send_withdraw_tlv(p, addr, prefixlen);
}
int
request_respond(struct ldp_peer *p, struct label_map_tlv *lmt,
struct fec_tlv *fec)
{
struct prefix_tlv *pref;
struct in_addr inatmp;
struct label *lab;
struct label_request_tlv lrm;
if (ntohs(fec->type) != TLV_FEC || fec->length == 0) {
debugp("Invalid FEC TLV !\n");
return LDP_E_BAD_FEC;
}
pref = (struct prefix_tlv *) (fec + 1);
if (ntohs(pref->af) != LDP_AF_INET) {
debugp("request_respond: Bad address family\n");
return LDP_E_BAD_AF;
}
switch (pref->type) {
case FEC_PREFIX:
case FEC_HOST:
memset(&inatmp, 0, sizeof(struct in_addr));
memcpy(&inatmp, &pref->prefix, ldp_ceil8(pref->prelen));
debugp("Prefix/Host request: %s/%d\n", inet_ntoa(inatmp),
pref->prelen);
lab = label_get_by_prefix(&inatmp, pref->prelen);
if (!lab)
return LDP_E_NO_SUCH_ROUTE;
lrm.type = htons(TLV_LABEL_REQUEST);
lrm.length = htons(sizeof(uint32_t));
lrm.messageid = lmt->messageid;
send_label_tlv(p, &inatmp, pref->prelen, lab->binding, &lrm);
break;
case FEC_WILDCARD:
/*
* Section 3.4.1
* To be used only in the Label Withdraw and Label Release
*/
/* Fallthrough */
default:
fatalp("Invalid FEC type\n");
return LDP_E_BAD_FEC;
}
return LDP_E_OK;
}

54
usr.sbin/ldpd/tlv_stack.h Normal file
View File

@ -0,0 +1,54 @@
/* $NetBSD: tlv_stack.h,v 1.1 2010/12/08 07:20:15 kefren Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Mihai Chelaru <kefren@NetBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TLV_STACK_H_
#define _TLV_STACK_H_
#include "ldp_peer.h"
#include "tlv.h"
#define FEC_WILDCARD 0x01
#define FEC_PREFIX 0x02
#define FEC_HOST 0x03
int map_label(struct ldp_peer *, struct fec_tlv *, struct label_tlv *);
int withdraw_label(struct ldp_peer *, struct fec_tlv *);
void prepare_release(struct tlv *);
void send_label_tlv(struct ldp_peer *, struct in_addr *, uint8_t,
uint32_t, struct label_request_tlv *);
void send_label_tlv_to_all(struct in_addr *, uint8_t, uint32_t);
void send_all_bindings(struct ldp_peer *);
void send_withdraw_tlv(struct ldp_peer *, struct in_addr *, uint8_t);
void send_withdraw_tlv_to_all(struct in_addr *, uint8_t);
int request_respond(struct ldp_peer *, struct label_map_tlv *,
struct fec_tlv *);
#endif /* !_TLV_STACK_H_ */