Add ldpd, a RFC 3036 compatible LDP speaker.
This commit is contained in:
parent
fc8e4c2763
commit
e7341ada4c
@ -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
26
usr.sbin/ldpd/Makefile
Normal 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
12
usr.sbin/ldpd/TODO
Normal 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
220
usr.sbin/ldpd/fsm.c
Normal 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
43
usr.sbin/ldpd/fsm.h
Normal 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
279
usr.sbin/ldpd/label.c
Normal 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
73
usr.sbin/ldpd/label.h
Normal 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
50
usr.sbin/ldpd/ldp.d
Normal 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
79
usr.sbin/ldpd/ldp.h
Normal 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
564
usr.sbin/ldpd/ldp_command.c
Normal 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;
|
||||
}
|
79
usr.sbin/ldpd/ldp_command.h
Normal file
79
usr.sbin/ldpd/ldp_command.h
Normal 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
110
usr.sbin/ldpd/ldp_errors.c
Normal 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);
|
||||
}
|
58
usr.sbin/ldpd/ldp_errors.h
Normal file
58
usr.sbin/ldpd/ldp_errors.h
Normal 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
498
usr.sbin/ldpd/ldp_peer.c
Normal 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
118
usr.sbin/ldpd/ldp_peer.h
Normal 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
94
usr.sbin/ldpd/ldpd.8
Normal 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
146
usr.sbin/ldpd/main.c
Normal 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;
|
||||
}
|
226
usr.sbin/ldpd/mpls_interface.c
Normal file
226
usr.sbin/ldpd/mpls_interface.c
Normal 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;
|
||||
}
|
43
usr.sbin/ldpd/mpls_interface.h
Normal file
43
usr.sbin/ldpd/mpls_interface.h
Normal 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
893
usr.sbin/ldpd/mpls_routes.c
Normal 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;
|
||||
}
|
78
usr.sbin/ldpd/mpls_routes.h
Normal file
78
usr.sbin/ldpd/mpls_routes.h
Normal 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_ */
|
79
usr.sbin/ldpd/notifications.c
Normal file
79
usr.sbin/ldpd/notifications.c
Normal 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;
|
||||
}
|
98
usr.sbin/ldpd/notifications.h
Normal file
98
usr.sbin/ldpd/notifications.h
Normal 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
90
usr.sbin/ldpd/pdu.c
Normal 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
58
usr.sbin/ldpd/pdu.h
Normal 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
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
69
usr.sbin/ldpd/socketops.h
Normal 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
75
usr.sbin/ldpd/tlv.c
Normal 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
206
usr.sbin/ldpd/tlv.h
Normal 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
415
usr.sbin/ldpd/tlv_stack.c
Normal 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
54
usr.sbin/ldpd/tlv_stack.h
Normal 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_ */
|
Loading…
Reference in New Issue
Block a user