ldpd: adapt the code for Quagga

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2016-03-01 15:31:28 -03:00 committed by Donald Sharp
parent e30090a678
commit eac6e3f027
57 changed files with 8870 additions and 1208 deletions

View file

@ -1,10 +1,10 @@
## Process this file with automake to produce Makefile.in.
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \
@ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
redhat @SOLARIS@ tests tools cumulus
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d ldpd \
isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
solaris pimd tools cumulus

View file

@ -246,6 +246,8 @@ AC_ARG_ENABLE(ospfd,
AS_HELP_STRING([--disable-ospfd], [do not build ospfd]))
AC_ARG_ENABLE(ospf6d,
AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d]))
AC_ARG_ENABLE(ldpd,
AS_HELP_STRING([--enable-ldpd], [build ldpd]))
AC_ARG_ENABLE(watchquagga,
AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga]))
AC_ARG_ENABLE(isisd,
@ -838,7 +840,7 @@ AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \
strtol strtoul strlcat strlcpy \
daemon snprintf vsnprintf \
if_nametoindex if_indextoname getifaddrs \
uname fcntl getgrouplist])
uname fcntl getgrouplist pledge])
AC_CHECK_HEADER([asm-generic/unistd.h],
[AC_CHECK_DECL(__NR_setns,
@ -1231,6 +1233,13 @@ else
fi
AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd")
if test "${enable_ldpd}" = "yes";then
LDPD="ldpd"
else
LDPD=""
fi
AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd")
if test "${enable_watchquagga}" = "no";then
WATCHQUAGGA=""
else
@ -1286,6 +1295,7 @@ AC_SUBST(RIPD)
AC_SUBST(RIPNGD)
AC_SUBST(OSPFD)
AC_SUBST(OSPF6D)
AC_SUBST(LDPD)
AC_SUBST(WATCHQUAGGA)
AC_SUBST(ISISD)
AC_SUBST(PIMD)
@ -1432,6 +1442,32 @@ AC_TRY_COMPILE([#include <netinet/in.h>], [
AC_MSG_RESULT(no)
])
dnl ----------------------
dnl checking for SO_BINDANY
dnl ----------------------
AC_MSG_CHECKING(for SO_BINDANY)
AC_TRY_COMPILE([#include <sys/socket.h>], [
int opt = SO_BINDANY;
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SO_BINDANY, 1, [Have SO_BINDANY])
], [
AC_MSG_RESULT(no)
])
dnl ----------------------
dnl checking for IP_FREEBIND
dnl ----------------------
AC_MSG_CHECKING(for IP_FREEBIND)
AC_TRY_COMPILE([#include <netinet/in.h>], [
int opt = IP_FREEBIND;
], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_IP_FREEBIND, 1, [Have IP_FREEBIND])
], [
AC_MSG_RESULT(no)
])
dnl --------------------------------------
dnl checking for getrusage struct and call
dnl --------------------------------------
@ -1580,6 +1616,8 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID)
AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID)
AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID)
AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID)
AC_DEFINE_UNQUOTED(PATH_LDPD_PID, "$quagga_statedir/ldpd.pid",ldpd PID)
AC_DEFINE_UNQUOTED(LDPD_SOCKET, "$quagga_statedir/ldpd.sock",ldpd control socket)
AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID)
AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID)
AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID)
@ -1590,6 +1628,7 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc
AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket)
AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket)
AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket)
AC_DEFINE_UNQUOTED(LDP_VTYSH_PATH, "$quagga_statedir/ldpd.vty",ldpd vty socket)
AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket)
AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket)
AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory)
@ -1615,7 +1654,7 @@ AC_MSG_RESULT($ac_cv_htonl_works)
AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile
ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile
ospf6d/Makefile isisd/Makefile vtysh/Makefile
ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
pimd/Makefile
tests/bgpd.tests/Makefile

View file

@ -87,6 +87,10 @@ if OSPFD
man_MANS += ospfd.8
endif
if LDPD
man_MANS += ldpd.8
endif
if RIPD
man_MANS += ripd.8
endif
@ -108,7 +112,7 @@ man_MANS += zebra.8
endif
EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \
bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ldpd.8 ripd.8 \
ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 quagga.1 \
mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \
mpls/opaque_lsa.txt mpls/ospfd.conf \

View file

@ -0,0 +1,681 @@
## Topology
The goal of this test is to verify that the all the basic functionality
of ldpd is working as expected, be it running on Linux or OpenBSD. In
addition to that, more advanced features are also tested, like LDP
sessions over IPv6, MD5 authentication and pseudowire signaling.
In the topology below there are 3 PE routers, 3 CE routers and one P
router (not attached to any consumer site).
All routers have IPv4 addresses and OSPF is used as the IGP. The
three routers from the bottom of the picture, P, PE2 and PE3, are also
configured for IPv6 (dual-stack) and static IPv6 routes are used to
provide connectivity among them.
The three CEs share the same VPLS membership. LDP is used to set up the
LSPs among the PEs and to signal the pseudowires. MD5 authentication is
used to protect all LDP sessions.
```
CE1 172.16.1.1/24
+
|
+---+---+
| PE1 |
| IOS XE|
| |
+---+---+
|
| 10.0.1.0/24
|
+---+---+
| P |
+------+ IOS XR+------+
| | | |
| +-------+ |
10.0.2.0/24 | | 10.0.3.0/24
2001:db8:2::/64 | | 2001:db8:3::/64
| |
+---+---+ +---+---+
| PE2 | | PE3 |
|OpenBSD+-------------+ Linux |
| | | |
+---+---+ 10.0.4.0/24 +---+---+
| 2001:db8:4::/64 |
+ +
172.16.1.2/24 CE2 CE3 172.16.1.3/24
```
## Configuration
#### Linux
1 - Enable IPv4/v6 forwarding:
```
# sysctl -w net.ipv4.ip_forward=1
# sysctl -w net.ipv6.conf.all.forwarding=1
```
2 - Enable MPLS forwarding:
```
# modprobe mpls-router
# modprobe mpls-iptunnel
# echo 100000 > /proc/sys/net/mpls/platform_labels
# echo 1 > /proc/sys/net/mpls/conf/eth1/input
# echo 1 > /proc/sys/net/mpls/conf/eth2/input
```
3 - Set up the interfaces:
```
# ip link add name lo1 type dummy
# ip link set dev lo1 up
# ip addr add 4.4.4.4/32 dev lo1
# ip -6 addr add 4:4:4::4/128 dev lo1
# ip link set dev eth1 up
# ip addr add 10.0.4.4/24 dev eth1
# ip -6 addr add 2001:db8:4::4/64 dev eth1
# ip link set dev eth2 up
# ip addr add 10.0.3.4/24 dev eth2
# ip -6 addr add 2001:db8:3::4/64 dev eth2
```
4 - Set up the bridge and pseudowire interfaces:
```
# ip link add type bridge
# ip link set dev bridge0 up
# ip link set dev eth0 up
# ip link set dev eth0 master bridge0
# ip link add name mpw0 type dummy
# ip link set dev mpw0 up
# ip link set dev mpw0 master bridge0
# ip link add name mpw1 type dummy
# ip link set dev mpw1 up
# ip link set dev mpw1 master bridge0
```
> NOTE: MPLS support in the Linux kernel is very recent and it still
doesn't support pseudowire interfaces. We are using here dummy interfaces
just to show how the VPLS configuration should look like in the future.
5 - Add static IPv6 routes for the remote loopbacks:
```
# ip -6 route add 2:2:2::2/128 via 2001:db8:3::2
# ip -6 route add 3:3:3::3/128 via 2001:db8:4::3
```
6 - Edit /etc/quagga/ospfd.conf:
```
router ospf
network 4.4.4.4/32 area 0.0.0.0
network 10.0.3.4/24 area 0.0.0.0
network 10.0.4.4/24 area 0.0.0.0
!
```
7 - Edit /etc/quagga/ldpd.conf:
```
debug mpls ldp messages recv
debug mpls ldp messages sent
debug mpls ldp zebra
!
mpls ldp
router-id 4.4.4.4
dual-stack cisco-interop
neighbor 1.1.1.1 password opensourcerouting
neighbor 2.2.2.2 password opensourcerouting
neighbor 3.3.3.3 password opensourcerouting
!
address-family ipv4
discovery transport-address 4.4.4.4
label local advertise explicit-null
!
interface eth2
!
interface eth1
!
!
address-family ipv6
discovery transport-address 4:4:4::4
ttl-security disable
!
interface eth2
!
interface eth1
!
!
!
l2vpn ENG type vpls
bridge br0
member interface eth0
!
member pseudowire mpw0
neighbor lsr-id 1.1.1.1
pw-id 100
!
member pseudowire mpw1
neighbor lsr-id 3.3.3.3
neighbor address 3:3:3::3
pw-id 100
!
!
```
> NOTE: We have to disable ttl-security under the ipv6 address-family
in order to interoperate with the IOS-XR router. GTSM is mandatory for
LDPv6 but the IOS-XR implementation is not RFC compliant in this regard.
8 - Run zebra, ospfd and ldpd.
#### OpenBSD
1 - Enable IPv4/v6 forwarding:
```
# sysctl net.inet.ip.forwarding=1
# sysctl net.inet6.ip6.forwarding=1
```
2 - Enable MPLS forwarding:
```
# ifconfig em2 10.0.2.3/24 mpls
# ifconfig em3 10.0.4.3/24 mpls
```
3 - Set up the interfaces:
```
# ifconfig lo1 alias 3.3.3.3 netmask 255.255.255.255
# ifconfig lo1 inet6 3:3:3::3/128
# ifconfig em2 inet6 2001:db8:2::3/64
# ifconfig em3 inet6 2001:db8:4::3/64
```
4 - Set up the bridge and pseudowire interfaces:
```
# ifconfig bridge0 create
# ifconfig bridge0 up
# ifconfig em1 up
# ifconfig bridge0 add em1
# ifconfig mpw0 create
# ifconfig mpw0 up
# ifconfig bridge0 add mpw0
# ifconfig mpw1 create
# ifconfig mpw1 up
# ifconfig bridge0 add mpw1
```
5 - Add static IPv6 routes for the remote loopbacks:
```
# route -n add 4:4:4::4/128 2001:db8:4::4
# route -n add 2:2:2::2/128 2001:db8:2::2
```
6 - Edit /etc/quagga/ospfd.conf:
```
router ospf
network 10.0.2.3/24 area 0
network 10.0.4.3/24 area 0
network 3.3.3.3/32 area 0
!
```
7 - Edit /etc/quagga/ldpd.conf:
```
debug mpls ldp messages recv
debug mpls ldp messages sent
debug mpls ldp zebra
!
mpls ldp
router-id 3.3.3.3
dual-stack cisco-interop
neighbor 1.1.1.1 password opensourcerouting
neighbor 2.2.2.2 password opensourcerouting
neighbor 4.4.4.4 password opensourcerouting
!
address-family ipv4
discovery transport-address 3.3.3.3
label local advertise explicit-null
!
interface em3
!
interface em2
!
!
address-family ipv6
discovery transport-address 3:3:3::3
ttl-security disable
!
interface em3
!
interface em2
!
!
!
l2vpn ENG type vpls
bridge br0
member interface em1
!
member pseudowire mpw0
neighbor lsr-id 1.1.1.1
pw-id 100
!
member pseudowire mpw1
neighbor lsr-id 4.4.4.4
neighbor address 4:4:4::4
pw-id 100
!
!
```
8 - Run zebra, ospfd and ldpd.
#### Cisco routers
CE1 (IOS):
```
interface FastEthernet0/0
ip address 172.16.1.1 255.255.255.0
!
!
```
CE2 (IOS):
```
interface FastEthernet0/0
ip address 172.16.1.2 255.255.255.0
!
!
```
CE3 (IOS):
```
interface FastEthernet0/0
ip address 172.16.1.3 255.255.255.0
!
!
```
PE1 - IOS-XE (1):
```
mpls ldp neighbor 2.2.2.2 password opensourcerouting
mpls ldp neighbor 3.3.3.3 password opensourcerouting
mpls ldp neighbor 4.4.4.4 password opensourcerouting
!
l2vpn vfi context VFI
vpn id 1
member pseudowire2
member pseudowire1
!
bridge-domain 1
member GigabitEthernet1 service-instance 1
member vfi VFI
!
interface Loopback1
ip address 1.1.1.1 255.255.255.255
!
interface pseudowire1
encapsulation mpls
neighbor 3.3.3.3 100
!
interface pseudowire2
encapsulation mpls
neighbor 4.4.4.4 100
!
interface GigabitEthernet3
ip address 10.0.1.1 255.255.255.0
mpls ip
!
router ospf 1
network 0.0.0.0 255.255.255.255 area 0
!
```
P - IOS-XR (2):
```
interface Loopback1
ipv4 address 2.2.2.2 255.255.255.255
ipv6 address 2:2:2::2/128
!
interface GigabitEthernet0/0/0/0
ipv4 address 10.0.1.2 255.255.255.0
!
interface GigabitEthernet0/0/0/1
ipv4 address 10.0.2.2 255.255.255.0
ipv6 address 2001:db8:2::2/64
ipv6 enable
!
interface GigabitEthernet0/0/0/2
ipv4 address 10.0.3.2 255.255.255.0
ipv6 address 2001:db8:3::2/64
ipv6 enable
!
router static
address-family ipv6 unicast
3:3:3::3/128 2001:db8:2::3
4:4:4::4/128 2001:db8:3::4
!
!
router ospf 1
router-id 2.2.2.2
address-family ipv4 unicast
area 0
interface Loopback1
!
interface GigabitEthernet0/0/0/0
!
interface GigabitEthernet0/0/0/1
!
interface GigabitEthernet0/0/0/2
!
!
!
mpls ldp
router-id 2.2.2.2
neighbor
1.1.1.1:0 password clear opensourcerouting
3.3.3.3:0 password clear opensourcerouting
4.4.4.4:0 password clear opensourcerouting
!
address-family ipv4
!
address-family ipv6
discovery transport-address 2:2:2::2
!
interface GigabitEthernet0/0/0/0
address-family ipv4
!
!
interface GigabitEthernet0/0/0/1
address-family ipv4
!
address-family ipv6
!
!
interface GigabitEthernet0/0/0/2
address-family ipv4
!
address-family ipv6
!
!
!
```
## Verification - Control Plane
Using the CLI on the Linux box, the goal is to ensure that everything
is working as expected.
First, verify that all the required adjacencies and neighborships sessions
were established:
```
linux# show mpls ldp discovery
Local LDP Identifier: 4.4.4.4:0
Discovery Sources:
Interfaces:
eth1: xmit/recv
LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3
Hold time: 15 sec
LDP Id: 3.3.3.3:0, Transport address: 3:3:3::3
Hold time: 15 sec
eth2: xmit/recv
LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2
Hold time: 15 sec
LDP Id: 2.2.2.2:0, Transport address: 2:2:2::2
Hold time: 15 sec
Targeted Hellos:
4.4.4.4 -> 1.1.1.1: xmit/recv
LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1
Hold time: 45 sec
4:4:4::4 -> 3:3:3::3: xmit/recv
LDP Id: 3.3.3.3:0, Transport address: 3:3:3::3
Hold time: 45 sec
linux# show mpls ldp neighbor
Peer LDP Identifier: 1.1.1.1:0
TCP connection: 4.4.4.4:40921 - 1.1.1.1:646
Session Holdtime: 180 sec
State: OPERATIONAL; Downstream-Unsolicited
Up time: 00:06:02
LDP Discovery Sources:
IPv4:
Targeted Hello: 1.1.1.1
Peer LDP Identifier: 2.2.2.2:0
TCP connection: 4:4:4::4:52286 - 2:2:2::2:646
Session Holdtime: 180 sec
State: OPERATIONAL; Downstream-Unsolicited
Up time: 00:06:02
LDP Discovery Sources:
IPv4:
Interface: eth2
IPv6:
Interface: eth2
Peer LDP Identifier: 3.3.3.3:0
TCP connection: 4:4:4::4:60575 - 3:3:3::3:646
Session Holdtime: 180 sec
State: OPERATIONAL; Downstream-Unsolicited
Up time: 00:05:57
LDP Discovery Sources:
IPv4:
Interface: eth1
IPv6:
Targeted Hello: 3:3:3::3
Interface: eth1
```
Note that the neighborships with the P and PE2 routers were established
over IPv6, since this is the default behavior for dual-stack LSRs, as
specified in RFC 7552. If desired, the **dual-stack transport-connection
prefer ipv4** command can be used to establish these sessions over IPv4
(the command should be applied an all routers).
Now, verify that there's a remote label for each PE address:
```
linux# show mpls ldp binding
1.1.1.1/32
Local binding: label: 20
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 imp-null
2.2.2.2 24000
3.3.3.3 20
2.2.2.2/32
Local binding: label: 21
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 18
2.2.2.2 imp-null
3.3.3.3 21
3.3.3.3/32
Local binding: label: 22
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 21
2.2.2.2 24003
3.3.3.3 imp-null
4.4.4.4/32
Local binding: label: imp-null
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 22
2.2.2.2 24001
3.3.3.3 22
10.0.1.0/24
Local binding: label: 23
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 imp-null
2.2.2.2 imp-null
3.3.3.3 23
10.0.2.0/24
Local binding: label: 24
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 20
2.2.2.2 imp-null
3.3.3.3 imp-null
10.0.3.0/24
Local binding: label: imp-null
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 19
2.2.2.2 imp-null
3.3.3.3 24
10.0.4.0/24
Local binding: label: imp-null
Remote bindings:
Peer Label
----------------- ---------
1.1.1.1 23
2.2.2.2 24002
3.3.3.3 imp-null
2:2:2::2/128
Local binding: label: 18
Remote bindings:
Peer Label
----------------- ---------
2.2.2.2 imp-null
3.3.3.3 18
3:3:3::3/128
Local binding: label: 19
Remote bindings:
Peer Label
----------------- ---------
2.2.2.2 24007
4:4:4::4/128
Local binding: label: imp-null
Remote bindings:
Peer Label
----------------- ---------
2.2.2.2 24006
3.3.3.3 19
2001:db8:2::/64
Local binding: label: -
Remote bindings:
Peer Label
----------------- ---------
2.2.2.2 imp-null
3.3.3.3 imp-null
2001:db8:3::/64
Local binding: label: imp-null
Remote bindings:
Peer Label
----------------- ---------
2.2.2.2 imp-null
2001:db8:4::/64
Local binding: label: imp-null
Remote bindings:
Peer Label
----------------- ---------
3.3.3.3 imp-null
```
Check if the pseudowires are up:
```
linux# show l2vpn atom vc
Interface Peer ID VC ID Name Status
--------- --------------- ---------- ---------------- ----------
mpw1 3.3.3.3 100 ENG UP
mpw0 1.1.1.1 100 ENG UP
```
Check the label bindings of the pseudowires:
```
linux# show l2vpn atom binding
Destination Address: 1.1.1.1, VC ID: 100
Local Label: 25
Cbit: 1, VC Type: Ethernet, GroupID: 0
MTU: 1500
Remote Label: 16
Cbit: 1, VC Type: Ethernet, GroupID: 0
MTU: 1500
Destination Address: 3.3.3.3, VC ID: 100
Local Label: 26
Cbit: 1, VC Type: Ethernet, GroupID: 0
MTU: 1500
Remote Label: 26
Cbit: 1, VC Type: Ethernet, GroupID: 0
MTU: 1500
```
## Verification - Data Plane
Verify that all the exchanged label mappings were installed in zebra:
```
linux# show mpls table
Inbound Outbound
Label Type Nexthop Label
-------- ------- --------------- --------
17 LDP 2001:db8:3::2 3
19 LDP 2001:db8:3::2 24005
20 LDP 10.0.3.2 24000
21 LDP 10.0.3.2 3
22 LDP 10.0.3.2 24001
23 LDP 10.0.3.2 3
24 LDP 10.0.3.2 3
25 LDP 10.0.3.2 3
linux# show ip route ldp
Codes: K - kernel route, C - connected, S - static, R - RIP,
O - OSPF, I - IS-IS, B - BGP, P - PIM, A - Babel, L - LDP,
> - selected route, * - FIB route
L>* 1.1.1.1/32 [0/0] via 10.0.3.2, eth2 label 24000
L>* 3.3.3.3/32 [0/0] via 10.0.3.2, eth2 label 24001
```
Verify that all the exchanged label mappings were installed in the kernel:
```
$ ip -M ro
17 via inet6 2001:db8:3::2 dev eth2 proto zebra
19 as to 24005 via inet6 2001:db8:3::2 dev eth2 proto zebra
20 as to 24000 via inet 10.0.3.2 dev eth2 proto zebra
21 via inet 10.0.3.2 dev eth2 proto zebra
22 as to 24001 via inet 10.0.3.2 dev eth2 proto zebra
23 via inet 10.0.3.2 dev eth2 proto zebra
24 via inet 10.0.3.2 dev eth2 proto zebra
25 via inet 10.0.3.2 dev eth2 proto zebra
$
$ ip route | grep mpls
1.1.1.1 encap mpls 24000 via 10.0.3.2 dev eth2 proto zebra metric 20
3.3.3.3 encap mpls 24001 via 10.0.3.2 dev eth2 proto zebra metric 20
```
Now ping PE1's loopback using lo1's address as a source address:
```
$ ping -c 5 -I 4.4.4.4 1.1.1.1
PING 1.1.1.1 (1.1.1.1) from 4.4.4.4 : 56(84) bytes of data.
64 bytes from 1.1.1.1: icmp_seq=1 ttl=253 time=3.02 ms
64 bytes from 1.1.1.1: icmp_seq=2 ttl=253 time=3.13 ms
64 bytes from 1.1.1.1: icmp_seq=3 ttl=253 time=3.19 ms
64 bytes from 1.1.1.1: icmp_seq=4 ttl=253 time=3.07 ms
64 bytes from 1.1.1.1: icmp_seq=5 ttl=253 time=3.27 ms
--- 1.1.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4005ms
rtt min/avg/max/mdev = 3.022/3.140/3.278/0.096 ms
```
Verify that the ICMP echo request packets are leaving with the MPLS
label advertised by the P router. Also, verify that the ICMP echo reply
packets are arriving with an explicit-null MPLS label:
```
# tcpdump -n -i eth2 mpls and icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth2, link-type EN10MB (Ethernet), capture size 262144 bytes
10:01:40.758771 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 1, length 64
10:01:40.761777 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 1, length 64
10:01:41.760343 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 2, length 64
10:01:41.763448 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 2, length 64
10:01:42.761758 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 3, length 64
10:01:42.764924 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 3, length 64
10:01:43.763193 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 4, length 64
10:01:43.766237 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 4, length 64
10:01:44.764552 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 5, length 64
10:01:44.767803 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 5, length 64
```

109
doc/ldpd.8 Normal file
View file

@ -0,0 +1,109 @@
.TH LDPD 8 "29 March 2016" "Quagga LDP daemon" "Version 1.0.20160309"
.SH NAME
ldpd \- an LDP engine for use with Quagga routing software.
.SH SYNOPSIS
.B ldpd
[
.B \-dhv
] [
.B \-f
.I config-file
] [
.B \-i
.I pid-file
] [
.B \-P
.I port-number
] [
.B \-A
.I vty-address
] [
.B \-u
.I user
] [
.B \-g
.I group
]
.SH DESCRIPTION
.B ldpd
is a component that works with the
.B Quagga
routing engine.
.SH OPTIONS
Options available for the
.B ldpd
command:
.TP
\fB\-d\fR, \fB\-\-daemon\fR
Runs in daemon mode, forking and exiting from tty.
.TP
\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR
Specifies the config file to use for startup. If not specified this
option will likely default to \fB\fI/usr/local/etc/ldpd.conf\fR.
.TP
\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR
Specify the group to run as. Default is \fIquagga\fR.
.TP
\fB\-h\fR, \fB\-\-help\fR
A brief message.
.TP
\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR
When ldpd starts its process identifier is written to
\fB\fIpid-file\fR. The init system uses the recorded PID to stop or
restart ldpd. The likely default is \fB\fI/var/run/ldpd.pid\fR.
.TP
\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR
Specify the port that the ldpd VTY will listen on. This defaults to
2612, as specified in \fB\fI/etc/services\fR.
.TP
\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR
Specify the address that the ldpd VTY will listen on. Default is all
interfaces.
.TP
\fB\-u\fR, \fB\-\-user \fR\fIuser\fR
Specify the user to run as. Default is \fIquagga\fR.
.TP
\fB\-v\fR, \fB\-\-version\fR
Print the version and exit.
.SH FILES
.TP
.BI /usr/local/sbin/ldpd
The default location of the
.B ldpd
binary.
.TP
.BI /usr/local/etc/ldpd.conf
The default location of the
.B ldpd
config file.
.TP
.BI $(PWD)/ldpd.log
If the
.B ldpd
process is config'd to output logs to a file, then you will find this
file in the directory where you started \fBldpd\fR.
.SH WARNING
This man page is intended to be a quick reference for command line
options. The definitive document is the Info file \fBQuagga\fR.
.SH DIAGNOSTICS
The ldpd process may log to standard output, to a VTY, to a log
file, or through syslog to the system logs. \fBldpd\fR supports many
debugging options, see the Info file, or the source for details.
.SH "SEE ALSO"
.BR bgpd (8),
.BR ripd (8),
.BR ripngd (8),
.BR ospfd (8),
.BR ospf6d (8),
.BR isisd (8),
.BR zebra (8),
.BR vtysh (1)
.SH BUGS
.B ldpd
eats bugs for breakfast. If you have food for the maintainers try
.BI http://bugzilla.quagga.net
.SH AUTHORS
See
.BI http://www.quagga.net
or the Info file for an accurate list of authors.

18
ldpd/.gitignore vendored Normal file
View file

@ -0,0 +1,18 @@
Makefile
Makefile.in
*.o
ldpd
ldpd.conf
tags
TAGS
.deps
.nfs*
*.lo
*.la
*.a
*.libs
.arch-inventory
.arch-ids
*~
*.loT

26
ldpd/Makefile.am Normal file
View file

@ -0,0 +1,26 @@
## Process this file with automake to produce Makefile.in.
AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
INSTALL_SDATA=@INSTALL@ -m 600
AM_CFLAGS = $(WERROR)
noinst_LIBRARIES = libldp.a
sbin_PROGRAMS = ldpd
libldp_a_SOURCES = \
accept.c address.c adjacency.c control.c hello.c init.c interface.c \
keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \
ldpe.c log.c neighbor.c notification.c packet.c pfkey.c \
socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \
ldp_debug.c ldp_zebra.c
noinst_HEADERS = \
control.h lde.h ldpd.h ldpe.h ldp.h log.h ldp_debug.h ldp_vty.h
ldpd_SOURCES = ldpd.c
ldpd_LDADD = libldp.a ../lib/libzebra.la @LIBCAP@
examplesdir = $(exampledir)
dist_examples_DATA = ldpd.conf.sample

View file

@ -16,8 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
@ -25,31 +24,30 @@
struct accept_ev {
LIST_ENTRY(accept_ev) entry;
struct event ev;
void (*accept_cb)(int, short, void *);
struct thread *ev;
int (*accept_cb)(struct thread *);
void *arg;
int fd;
};
struct {
LIST_HEAD(, accept_ev) queue;
struct event evt;
LIST_HEAD(, accept_ev) queue;
struct thread *evt;
} accept_queue;
static void accept_arm(void);
static void accept_unarm(void);
static void accept_cb(int, short, void *);
static void accept_timeout(int, short, void *);
static int accept_cb(struct thread *);
static int accept_timeout(struct thread *);
void
accept_init(void)
{
LIST_INIT(&accept_queue.queue);
evtimer_set(&accept_queue.evt, accept_timeout, NULL);
}
int
accept_add(int fd, void (*cb)(int, short, void *), void *arg)
accept_add(int fd, int (*cb)(struct thread *), void *arg)
{
struct accept_ev *av;
@ -60,8 +58,7 @@ accept_add(int fd, void (*cb)(int, short, void *), void *arg)
av->arg = arg;
LIST_INSERT_HEAD(&accept_queue.queue, av, entry);
event_set(&av->ev, av->fd, EV_READ, accept_cb, av);
event_add(&av->ev, NULL);
av->ev = thread_add_read(master, accept_cb, av, av->fd);
log_debug("%s: accepting on fd %d", __func__, fd);
@ -76,7 +73,7 @@ accept_del(int fd)
LIST_FOREACH(av, &accept_queue.queue, entry)
if (av->fd == fd) {
log_debug("%s: %d removed from queue", __func__, fd);
event_del(&av->ev);
THREAD_READ_OFF(av->ev);
LIST_REMOVE(av, entry);
free(av);
return;
@ -86,19 +83,17 @@ accept_del(int fd)
void
accept_pause(void)
{
struct timeval evtpause = { 1, 0 };
log_debug(__func__);
accept_unarm();
evtimer_add(&accept_queue.evt, &evtpause);
accept_queue.evt = thread_add_timer(master, accept_timeout, NULL, 1);
}
void
accept_unpause(void)
{
if (evtimer_pending(&accept_queue.evt, NULL)) {
if (accept_queue.evt != NULL) {
log_debug(__func__);
evtimer_del(&accept_queue.evt);
THREAD_TIMER_OFF(accept_queue.evt);
accept_arm();
}
}
@ -108,7 +103,7 @@ accept_arm(void)
{
struct accept_ev *av;
LIST_FOREACH(av, &accept_queue.queue, entry)
event_add(&av->ev, NULL);
av->ev = thread_add_read(master, accept_cb, av, av->fd);
}
static void
@ -116,20 +111,26 @@ accept_unarm(void)
{
struct accept_ev *av;
LIST_FOREACH(av, &accept_queue.queue, entry)
event_del(&av->ev);
THREAD_READ_OFF(av->ev);
}
static void
accept_cb(int fd, short event, void *arg)
static int
accept_cb(struct thread *thread)
{
struct accept_ev *av = arg;
event_add(&av->ev, NULL);
av->accept_cb(fd, event, av->arg);
struct accept_ev *av = THREAD_ARG(thread);
av->ev = thread_add_read(master, accept_cb, av, av->fd);
av->accept_cb(thread);
return (0);
}
static void
accept_timeout(int fd, short event, void *bula)
static int
accept_timeout(struct thread *thread)
{
accept_queue.evt = NULL;
log_debug(__func__);
accept_arm();
return (0);
}

View file

@ -16,15 +16,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "log.h"
#include "ldp_debug.h"
static void send_address(struct nbr *, int, struct if_addr_head *,
unsigned int, int);
@ -94,7 +92,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,
}
while ((if_addr = LIST_FIRST(addr_list)) != NULL) {
log_debug("msg-out: %s: lsr-id %s, address %s",
debug_msg_send("%s: lsr-id %s address %s",
msg_name(msg_type), inet_ntoa(nbr->id),
log_addr(af, &if_addr->addr));
@ -225,9 +223,8 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)
fatalx("recv_address: unknown af");
}
log_debug("msg-in: %s: lsr-id %s, address %s",
msg_name(msg_type), inet_ntoa(nbr->id),
log_addr(lde_addr.af, &lde_addr.addr));
debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type),
inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));
ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,
sizeof(lde_addr));

View file

@ -19,19 +19,15 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
static void adj_del_single(struct adj *);
static void adj_itimer(int, short, void *);
static int adj_itimer(struct thread *);
static void tnbr_del(struct tnbr *);
static void tnbr_hello_timer(int, short, void *);
static int tnbr_hello_timer(struct thread *);
static void tnbr_start_hello_timer(struct tnbr *);
static void tnbr_stop_hello_timer(struct tnbr *);
@ -52,8 +48,6 @@ adj_new(struct in_addr lsr_id, struct hello_source *source,
adj->source = *source;
adj->trans_addr = *addr;
evtimer_set(&adj->inactivity_timer, adj_itimer, adj);
LIST_INSERT_HEAD(&global.adj_list, adj, global_entry);
switch (source->type) {
@ -154,10 +148,12 @@ adj_get_af(struct adj *adj)
/* adjacency timers */
/* ARGSUSED */
static void
adj_itimer(int fd, short event, void *arg)
static int
adj_itimer(struct thread *thread)
{
struct adj *adj = arg;
struct adj *adj = THREAD_ARG(thread);
adj->inactivity_timer = NULL;
log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id));
@ -166,37 +162,34 @@ adj_itimer(int fd, short event, void *arg)
adj->source.target->pw_count == 0) {
/* remove dynamic targeted neighbor */
tnbr_del(adj->source.target);
return;
return (0);
}
adj->source.target->adj = NULL;
}
adj_del(adj, S_HOLDTIME_EXP);
return (0);
}
void
adj_start_itimer(struct adj *adj)
{
struct timeval tv;
timerclear(&tv);
tv.tv_sec = adj->holdtime;
if (evtimer_add(&adj->inactivity_timer, &tv) == -1)
fatal(__func__);
THREAD_TIMER_OFF(adj->inactivity_timer);
adj->inactivity_timer = thread_add_timer(master, adj_itimer, adj,
adj->holdtime);
}
void
adj_stop_itimer(struct adj *adj)
{
if (evtimer_pending(&adj->inactivity_timer, NULL) &&
evtimer_del(&adj->inactivity_timer) == -1)
fatal(__func__);
THREAD_TIMER_OFF(adj->inactivity_timer);
}
/* targeted neighbors */
struct tnbr *
tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
tnbr_new(int af, union ldpd_addr *addr)
{
struct tnbr *tnbr;
@ -206,8 +199,6 @@ tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)
tnbr->af = af;
tnbr->addr = *addr;
tnbr->state = TNBR_STA_DOWN;
tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime;
tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval;
return (tnbr);
}
@ -257,7 +248,7 @@ tnbr_update(struct tnbr *tnbr)
else
socket_ok = 0;
if (leconf->rtr_id.s_addr != INADDR_ANY)
if (ldp_rtr_id_get(leconf) != INADDR_ANY)
rtr_id_ok = 1;
else
rtr_id_ok = 0;
@ -269,7 +260,6 @@ tnbr_update(struct tnbr *tnbr)
tnbr->state = TNBR_STA_ACTIVE;
send_hello(HELLO_TARGETED, NULL, tnbr);
evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);
tnbr_start_hello_timer(tnbr);
} else if (tnbr->state == TNBR_STA_ACTIVE) {
if (socket_ok && rtr_id_ok)
@ -291,35 +281,51 @@ tnbr_update_all(int af)
tnbr_update(tnbr);
}
uint16_t
tnbr_get_hello_holdtime(struct tnbr *tnbr)
{
if ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime != 0)
return ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime);
return (leconf->thello_holdtime);
}
uint16_t
tnbr_get_hello_interval(struct tnbr *tnbr)
{
if ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval != 0)
return ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval);
return (leconf->thello_interval);
}
/* target neighbors timers */
/* ARGSUSED */
static void
tnbr_hello_timer(int fd, short event, void *arg)
static int
tnbr_hello_timer(struct thread *thread)
{
struct tnbr *tnbr = arg;
struct tnbr *tnbr = THREAD_ARG(thread);
tnbr->hello_timer = NULL;
send_hello(HELLO_TARGETED, NULL, tnbr);
tnbr_start_hello_timer(tnbr);
return (0);
}
static void
tnbr_start_hello_timer(struct tnbr *tnbr)
{
struct timeval tv;
timerclear(&tv);
tv.tv_sec = tnbr->hello_interval;
if (evtimer_add(&tnbr->hello_timer, &tv) == -1)
fatal(__func__);
THREAD_TIMER_OFF(tnbr->hello_timer);
tnbr->hello_timer = thread_add_timer(master, tnbr_hello_timer, tnbr,
tnbr_get_hello_interval(tnbr));
}
static void
tnbr_stop_hello_timer(struct tnbr *tnbr)
{
if (evtimer_pending(&tnbr->hello_timer, NULL) &&
evtimer_del(&tnbr->hello_timer) == -1)
fatal(__func__);
THREAD_TIMER_OFF(tnbr->hello_timer);
}
struct ctl_adj *

View file

@ -16,13 +16,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <zebra.h>
#include <sys/un.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ldpd.h"
#include "ldpe.h"
@ -31,11 +26,11 @@
#define CONTROL_BACKLOG 5
static void control_accept(int, short, void *);
static int control_accept(struct thread *);
static struct ctl_conn *control_connbyfd(int);
static struct ctl_conn *control_connbypid(pid_t);
static void control_close(int);
static void control_dispatch_imsg(int, short, void *);
static int control_dispatch_imsg(struct thread *);
struct ctl_conns ctl_conns;
@ -48,11 +43,11 @@ control_init(void)
int fd;
mode_t old_umask;
if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0)) == -1) {
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
log_warn("%s: socket", __func__);
return (-1);
}
sock_set_nonblock(fd);
memset(&s_un, 0, sizeof(s_un));
s_un.sun_family = AF_UNIX;
@ -106,8 +101,8 @@ control_cleanup(void)
}
/* ARGSUSED */
static void
control_accept(int listenfd, short event, void *bula)
static int
control_accept(struct thread *thread)
{
int connfd;
socklen_t len;
@ -115,8 +110,8 @@ control_accept(int listenfd, short event, void *bula)
struct ctl_conn *c;
len = sizeof(s_un);
if ((connfd = accept4(listenfd, (struct sockaddr *)&s_un, &len,
SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) {
if ((connfd = accept(THREAD_FD(thread), (struct sockaddr *)&s_un,
&len)) == -1) {
/*
* Pause accept if we are out of file descriptors, or
* libevent will haunt us here too.
@ -125,24 +120,27 @@ control_accept(int listenfd, short event, void *bula)
accept_pause();
else if (errno != EWOULDBLOCK && errno != EINTR &&
errno != ECONNABORTED)
log_warn("%s: accept4", __func__);
return;
log_warn("%s: accept", __func__);
return (0);
}
sock_set_nonblock(connfd);
if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {
log_warn(__func__);
close(connfd);
return;
return (0);
}
imsg_init(&c->iev.ibuf, connfd);
c->iev.handler = control_dispatch_imsg;
c->iev.events = EV_READ;
event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events,
c->iev.handler, &c->iev);
event_add(&c->iev.ev, NULL);
c->iev.handler_read = control_dispatch_imsg;
c->iev.ev_read = thread_add_read(master, c->iev.handler_read,
&c->iev, c->iev.ibuf.fd);
c->iev.handler_write = ldp_write_handler;
c->iev.ev_write = NULL;
TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
return (0);
}
static struct ctl_conn *
@ -182,45 +180,40 @@ control_close(int fd)
msgbuf_clear(&c->iev.ibuf.w);
TAILQ_REMOVE(&ctl_conns, c, entry);
event_del(&c->iev.ev);
THREAD_READ_OFF(c->iev.ev_read);
THREAD_WRITE_OFF(c->iev.ev_write);
close(c->iev.ibuf.fd);
accept_unpause();
free(c);
}
/* ARGSUSED */
static void
control_dispatch_imsg(int fd, short event, void *bula)
static int
control_dispatch_imsg(struct thread *thread)
{
int fd = THREAD_FD(thread);
struct ctl_conn *c;
struct imsg imsg;
ssize_t n;
unsigned int ifidx;
int verbose;
if ((c = control_connbyfd(fd)) == NULL) {
log_warnx("%s: fd %d: not found", __func__, fd);
return;
return (0);
}
if (event & EV_READ) {
if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
n == 0) {
control_close(fd);
return;
}
}
if (event & EV_WRITE) {
if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) {
control_close(fd);
return;
}
c->iev.ev_read = NULL;
if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) ||
n == 0) {
control_close(fd);
return (0);
}
for (;;) {
if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {
control_close(fd);
return;
return (0);
}
if (n == 0)
@ -230,16 +223,10 @@ control_dispatch_imsg(int fd, short event, void *bula)
case IMSG_CTL_FIB_COUPLE:
case IMSG_CTL_FIB_DECOUPLE:
case IMSG_CTL_RELOAD:
c->iev.ibuf.pid = imsg.hdr.pid;
ldpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0);
break;
case IMSG_CTL_KROUTE:
case IMSG_CTL_KROUTE_ADDR:
case IMSG_CTL_IFINFO:
c->iev.ibuf.pid = imsg.hdr.pid;
ldpe_imsg_compose_parent(imsg.hdr.type,
imsg.hdr.pid, imsg.data,
imsg.hdr.len - IMSG_HEADER_SIZE);
/* ignore */
break;
case IMSG_CTL_SHOW_INTERFACE:
if (imsg.hdr.len == IMSG_HEADER_SIZE +
@ -271,18 +258,7 @@ control_dispatch_imsg(int fd, short event, void *bula)
nbr_clear_ctl(imsg.data);
break;
case IMSG_CTL_LOG_VERBOSE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(verbose))
break;
/* forward to other processes */
ldpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
memcpy(&verbose, imsg.data, sizeof(verbose));
log_verbose(verbose);
/* ignore */
break;
default:
log_debug("%s: error handling imsg %d", __func__,
@ -293,6 +269,8 @@ control_dispatch_imsg(int fd, short event, void *bula)
}
imsg_event_add(&c->iev);
return (0);
}
int

View file

@ -19,8 +19,7 @@
#ifndef _CONTROL_H_
#define _CONTROL_H_
#include <sys/types.h>
#include <sys/queue.h>
#include "openbsd-queue.h"
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;

View file

@ -17,13 +17,12 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "ldp_debug.h"
static int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t);
static int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t);
@ -46,7 +45,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
switch (type) {
case HELLO_LINK:
af = ia->af;
holdtime = ia->hello_holdtime;
holdtime = if_get_hello_holdtime(ia);
flags = 0;
fd = (ldp_af_global_get(&global, af))->ldp_disc_socket;
@ -66,7 +65,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
break;
case HELLO_TARGETED:
af = tnbr->af;
holdtime = tnbr->hello_holdtime;
holdtime = tnbr_get_hello_holdtime(tnbr);
flags = F_HELLO_TARGETED;
if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)
flags |= F_HELLO_REQ_TARG;
@ -139,6 +138,20 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)
return (-1);
}
switch (type) {
case HELLO_LINK:
debug_hello_send("iface %s (%s) holdtime %u", ia->iface->name,
af_name(ia->af), holdtime);
break;
case HELLO_TARGETED:
debug_hello_send("targeted-neighbor %s (%s) holdtime %u",
log_addr(tnbr->af, &tnbr->addr), af_name(tnbr->af),
holdtime);
break;
default:
fatalx("send_hello: unknown hello type");
}
send_packet(fd, af, &dst, ia, buf->buf, buf->wpos);
ibuf_free(buf);
@ -152,7 +165,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
{
struct adj *adj = NULL;
struct nbr *nbr, *nbrt;
uint16_t holdtime, flags;
uint16_t holdtime = 0, flags = 0;
int tlvs_rcvd;
int ds_tlv;
union ldpd_addr trans_addr;
@ -257,7 +270,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
F_LDPD_AF_THELLO_ACCEPT)))
return;
tnbr = tnbr_new(leconf, af, src);
tnbr = tnbr_new(af, src);
tnbr->flags |= F_TNBR_DYNAMIC;
tnbr_update(tnbr);
LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
@ -387,19 +400,23 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,
if (holdtime == 0)
holdtime = LINK_DFLT_HOLDTIME;
adj->holdtime = min(ia->hello_holdtime, holdtime);
adj->holdtime = min(if_get_hello_holdtime(ia), holdtime);
break;
case HELLO_TARGETED:
if (holdtime == 0)
holdtime = TARGETED_DFLT_HOLDTIME;
adj->holdtime = min(tnbr->hello_holdtime, holdtime);
adj->holdtime = min(tnbr_get_hello_holdtime(tnbr), holdtime);
}
if (adj->holdtime != INFINITE_HOLDTIME)
adj_start_itimer(adj);
else
adj_stop_itimer(adj);
debug_hello_recv("%s lsr-id %s transport-address %s holdtime %u%s",
log_hello_src(&source), inet_ntoa(lsr_id), log_addr(af, &trans_addr),
holdtime, (ds_tlv) ? " (dual stack TLV present)" : "");
if (nbr && nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr) &&
nbr_session_active_role(nbr) && !nbr_pending_connect(nbr))
nbr_establish_connection(nbr);

View file

@ -16,13 +16,12 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "ldp_debug.h"
static int gen_init_prms_tlv(struct ibuf *, struct nbr *);
@ -33,7 +32,7 @@ send_init(struct nbr *nbr)
uint16_t size;
int err = 0;
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id));
size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;
if ((buf = ibuf_open(size)) == NULL)
@ -59,7 +58,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
struct sess_prms_tlv sess;
uint16_t max_pdu_len;
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id));
memcpy(&msg, buf, sizeof(msg));
buf += LDP_MSG_SIZE;
@ -82,7 +81,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)
session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type);
return (-1);
}
if (sess.lsr_id != leconf->rtr_id.s_addr ||
if (sess.lsr_id != ldp_rtr_id_get(leconf) ||
ntohs(sess.lspace_id) != 0) {
session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type);
return (-1);

View file

@ -18,22 +18,20 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "sockopt.h"
static struct if_addr *if_addr_new(struct kaddr *);
static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *);
static int if_start(struct iface *, int);
static int if_reset(struct iface *, int);
static void if_update_af(struct iface_af *, int);
static void if_hello_timer(int, short, void *);
static int if_hello_timer(struct thread *);
static void if_start_hello_timer(struct iface_af *);
static void if_stop_hello_timer(struct iface_af *);
static int if_join_ipv4_group(struct iface *, struct in_addr *);
@ -50,20 +48,9 @@ if_new(struct kif *kif)
fatal("if_new: calloc");
strlcpy(iface->name, kif->ifname, sizeof(iface->name));
/* get type */
if (kif->flags & IFF_POINTOPOINT)
iface->type = IF_TYPE_POINTOPOINT;
if (kif->flags & IFF_BROADCAST &&
kif->flags & IFF_MULTICAST)
iface->type = IF_TYPE_BROADCAST;
/* get index and flags */
LIST_INIT(&iface->addr_list);
iface->ifindex = kif->ifindex;
iface->flags = kif->flags;
iface->linkstate = kif->link_state;
iface->if_type = kif->if_type;
if (kif->ifindex)
if_update_info(iface, kif);
/* ipv4 */
iface->ipv4.af = AF_INET;
@ -112,6 +99,33 @@ if_exit(struct iface *iface)
}
}
struct iface *
if_lookup_name(struct ldpd_conf *xconf, const char *ifname)
{
struct iface *iface;
LIST_FOREACH(iface, &xconf->iface_list, entry)
if (strcmp(iface->name, ifname) == 0)
return (iface);
return (NULL);
}
void
if_update_info(struct iface *iface, struct kif *kif)
{
/* get type */
if (kif->flags & IFF_POINTOPOINT)
iface->type = IF_TYPE_POINTOPOINT;
if (kif->flags & IFF_BROADCAST &&
kif->flags & IFF_MULTICAST)
iface->type = IF_TYPE_BROADCAST;
/* get index and flags */
iface->ifindex = kif->ifindex;
iface->flags = kif->flags;
}
struct iface_af *
iface_af_get(struct iface *iface, int af)
{
@ -258,7 +272,6 @@ if_start(struct iface *iface, int af)
send_hello(HELLO_LINK, ia, NULL);
evtimer_set(&ia->hello_timer, if_hello_timer, ia);
if_start_hello_timer(ia);
return (0);
}
@ -328,7 +341,7 @@ if_update_af(struct iface_af *ia, int link_ok)
else
socket_ok = 0;
if (leconf->rtr_id.s_addr != INADDR_ANY)
if (ldp_rtr_id_get(leconf) != INADDR_ANY)
rtr_id_ok = 1;
else
rtr_id_ok = 0;
@ -354,8 +367,7 @@ if_update(struct iface *iface, int af)
{
int link_ok;
link_ok = (iface->flags & IFF_UP) &&
LINK_STATE_IS_UP(iface->linkstate);
link_ok = (iface->flags & IFF_UP) && (iface->flags & IFF_RUNNING);
if (af == AF_INET || af == AF_UNSPEC)
if_update_af(&iface->ipv4, link_ok);
@ -372,34 +384,56 @@ if_update_all(int af)
if_update(iface, af);
}
uint16_t
if_get_hello_holdtime(struct iface_af *ia)
{
if (ia->hello_holdtime != 0)
return (ia->hello_holdtime);
if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0)
return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime);
return (leconf->lhello_holdtime);
}
uint16_t
if_get_hello_interval(struct iface_af *ia)
{
if (ia->hello_interval != 0)
return (ia->hello_interval);
if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0)
return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval);
return (leconf->lhello_interval);
}
/* timers */
/* ARGSUSED */
static void
if_hello_timer(int fd, short event, void *arg)
static int
if_hello_timer(struct thread *thread)
{
struct iface_af *ia = arg;
struct iface_af *ia = THREAD_ARG(thread);
ia->hello_timer = NULL;
send_hello(HELLO_LINK, ia, NULL);
if_start_hello_timer(ia);
return (0);
}
static void
if_start_hello_timer(struct iface_af *ia)
{
struct timeval tv;
timerclear(&tv);
tv.tv_sec = ia->hello_interval;
if (evtimer_add(&ia->hello_timer, &tv) == -1)
fatal(__func__);
THREAD_TIMER_OFF(ia->hello_timer);
ia->hello_timer = thread_add_timer(master, if_hello_timer, ia,
if_get_hello_interval(ia));
}
static void
if_stop_hello_timer(struct iface_af *ia)
{
if (evtimer_pending(&ia->hello_timer, NULL) &&
evtimer_del(&ia->hello_timer) == -1)
fatal(__func__);
THREAD_TIMER_OFF(ia->hello_timer);
}
struct ctl_iface *
@ -414,11 +448,9 @@ if_to_ctl(struct iface_af *ia)
ictl.ifindex = ia->iface->ifindex;
ictl.state = ia->state;
ictl.flags = ia->iface->flags;
ictl.linkstate = ia->iface->linkstate;
ictl.type = ia->iface->type;
ictl.if_type = ia->iface->if_type;
ictl.hello_holdtime = ia->hello_holdtime;
ictl.hello_interval = ia->hello_interval;
ictl.hello_holdtime = if_get_hello_holdtime(ia);
ictl.hello_interval = if_get_hello_interval(ia);
gettimeofday(&now, NULL);
if (ia->state != IF_STA_DOWN &&
@ -450,16 +482,15 @@ if_get_ipv4_addr(struct iface *iface)
static int
if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
{
struct ip_mreq mreq;
struct in_addr if_addr;
log_debug("%s: interface %s addr %s", __func__, iface->name,
inet_ntoa(*addr));
mreq.imr_multiaddr = *addr;
mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
if_addr.s_addr = if_get_ipv4_addr(iface);
if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",
__func__, iface->name, inet_ntoa(*addr));
return (-1);
@ -470,16 +501,15 @@ if_join_ipv4_group(struct iface *iface, struct in_addr *addr)
static int
if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)
{
struct ip_mreq mreq;
struct in_addr if_addr;
log_debug("%s: interface %s addr %s", __func__, iface->name,
inet_ntoa(*addr));
mreq.imr_multiaddr = *addr;
mreq.imr_interface.s_addr = if_get_ipv4_addr(iface);
if_addr.s_addr = if_get_ipv4_addr(iface);
if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP,
IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) {
if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket,
IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {
log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "
"address %s", __func__, iface->name, inet_ntoa(*addr));
return (-1);

View file

@ -16,12 +16,12 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "ldp_debug.h"
void
send_keepalive(struct nbr *nbr)
@ -37,6 +37,8 @@ send_keepalive(struct nbr *nbr)
size -= LDP_HDR_SIZE;
gen_msg_hdr(buf, MSG_TYPE_KEEPALIVE, size);
debug_kalive_send("keepalive: lsr-id %s", inet_ntoa(nbr->id));
evbuf_enqueue(&nbr->tcp->wbuf, buf);
}
@ -51,6 +53,8 @@ recv_keepalive(struct nbr *nbr, char *buf, uint16_t len)
return (-1);
}
debug_kalive_recv("keepalive: lsr-id %s", inet_ntoa(nbr->id));
if (nbr->state != NBR_STA_OPER)
nbr_fsm(nbr, NBR_EVT_KEEPALIVE_RCVD);

View file

@ -19,10 +19,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
@ -47,6 +44,7 @@ l2vpn_new(const char *name)
LIST_INIT(&l2vpn->if_list);
LIST_INIT(&l2vpn->pw_list);
LIST_INIT(&l2vpn->pw_inactive_list);
return (l2vpn);
}
@ -77,6 +75,10 @@ l2vpn_del(struct l2vpn *l2vpn)
LIST_REMOVE(pw, entry);
free(pw);
}
while ((pw = LIST_FIRST(&l2vpn->pw_inactive_list)) != NULL) {
LIST_REMOVE(pw, entry);
free(pw);
}
free(l2vpn);
}
@ -111,7 +113,6 @@ l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)
strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));
lif->ifindex = kif->ifindex;
lif->flags = kif->flags;
lif->link_state = kif->link_state;
return (lif);
}
@ -128,6 +129,19 @@ l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)
return (NULL);
}
struct l2vpn_if *
l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname)
{
struct l2vpn_if *lif;
LIST_FOREACH(lif, &l2vpn->if_list, entry)
if (strcmp(lif->ifname, ifname) == 0)
return (lif);
return (NULL);
}
struct l2vpn_pw *
l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)
{
@ -151,6 +165,24 @@ l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)
LIST_FOREACH(pw, &l2vpn->pw_list, entry)
if (pw->ifindex == ifindex)
return (pw);
LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry)
if (pw->ifindex == ifindex)
return (pw);
return (NULL);
}
struct l2vpn_pw *
l2vpn_pw_find_name(struct l2vpn *l2vpn, const char *ifname)
{
struct l2vpn_pw *pw;
LIST_FOREACH(pw, &l2vpn->pw_list, entry)
if (strcmp(pw->ifname, ifname) == 0)
return (pw);
LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry)
if (strcmp(pw->ifname, ifname) == 0)
return (pw);
return (NULL);
}
@ -399,6 +431,8 @@ l2vpn_pw_ctl(pid_t pid)
LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)
LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
memset(&pwctl, 0, sizeof(pwctl));
strlcpy(pwctl.l2vpn_name, pw->l2vpn->name,
sizeof(pwctl.l2vpn_name));
strlcpy(pwctl.ifname, pw->ifname,
sizeof(pwctl.ifname));
pwctl.pwid = pw->pwid;
@ -438,6 +472,8 @@ l2vpn_binding_ctl(pid_t pid)
pwctl.local_label = fn->local_label;
pwctl.local_gid = 0;
pwctl.local_ifmtu = pw->l2vpn->mtu;
pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ?
1 : 0;
} else
pwctl.local_label = NO_LABEL;
@ -450,6 +486,9 @@ l2vpn_binding_ctl(pid_t pid)
pwctl.remote_gid = me->map.fec.pwid.group_id;
if (me->map.flags & F_MAP_PW_IFMTU)
pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu;
if (pw)
pwctl.remote_cword = (pw->flags & F_PW_CWORD) ?
1 : 0;
lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,
0, pid, &pwctl, sizeof(pwctl));
@ -489,7 +528,7 @@ ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)
tnbr = tnbr_find(leconf, pw->af, &pw->addr);
if (tnbr == NULL) {
tnbr = tnbr_new(leconf, pw->af, &pw->addr);
tnbr = tnbr_new(pw->af, &pw->addr);
tnbr_update(tnbr);
LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);
}

View file

@ -17,17 +17,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netmpls/mpls.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "ldp_debug.h"
#include "mpls.h"
static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);
static int gen_label_tlv(struct ibuf *, uint32_t);
@ -127,8 +124,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)
return;
}
log_debug("msg-out: %s: lsr-id %s, fec %s, label %s",
msg_name(type), inet_ntoa(nbr->id), log_map(&me->map),
debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type),
inet_ntoa(nbr->id), log_map(&me->map),
log_label(me->map.label));
TAILQ_REMOVE(mh, me, entry);
@ -399,7 +396,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)
if (me->map.flags & F_MAP_REQ_ID)
me->map.requestid = reqid;
log_debug("msg-in: label mapping: lsr-id %s, fec %s, label %s",
debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type),
inet_ntoa(nbr->id), log_map(&me->map),
log_label(me->map.label));

View file

@ -19,31 +19,24 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netmpls/mpls.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <limits.h>
#include <zebra.h>
#include "ldp.h"
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "lde.h"
#include "ldp_debug.h"
static void lde_sig_handler(int sig, short, void *);
static __dead void lde_shutdown(void);
static int lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
static void lde_dispatch_imsg(int, short, void *);
static void lde_dispatch_parent(int, short, void *);
#include <lib/log.h>
#include "memory.h"
#include "privs.h"
#include "sigevent.h"
#include "mpls.h"
static void lde_shutdown(void);
static int lde_dispatch_imsg(struct thread *);
static int lde_dispatch_parent(struct thread *);
static __inline int lde_nbr_compare(struct lde_nbr *,
struct lde_nbr *);
static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *);
@ -65,89 +58,101 @@ struct nbr_tree lde_nbrs = RB_INITIALIZER(&lde_nbrs);
static struct imsgev *iev_ldpe;
static struct imsgev *iev_main;
/* ARGSUSED */
static void
lde_sig_handler(int sig, short event, void *arg)
{
/*
* signal handler rules don't apply, libevent decouples for us
*/
/* Master of threads. */
struct thread_master *master;
switch (sig) {
case SIGINT:
case SIGTERM:
lde_shutdown();
/* NOTREACHED */
default:
fatalx("unexpected signal");
}
/* lde privileges */
static zebra_capabilities_t _caps_p [] =
{
/* none */
};
static struct zebra_privs_t lde_privs =
{
#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP)
.user = QUAGGA_USER,
.group = QUAGGA_GROUP,
#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0
};
/* SIGINT / SIGTERM handler. */
static void
sigint(void)
{
lde_shutdown();
}
static struct quagga_signal_t lde_signals[] =
{
{
.signal = SIGINT,
.handler = &sigint,
},
{
.signal = SIGTERM,
.handler = &sigint,
},
};
/* label decision engine */
void
lde(int debug, int verbose)
lde(const char *user, const char *group)
{
struct event ev_sigint, ev_sigterm;
struct thread thread;
struct timeval now;
struct passwd *pw;
ldeconf = config_new_empty();
log_init(debug);
log_verbose(verbose);
#ifdef HAVE_SETPROCTITLE
setproctitle("label decision engine");
#endif
ldpd_process = PROC_LDE_ENGINE;
if ((pw = getpwnam(LDPD_USER)) == NULL)
fatal("getpwnam");
if (chroot(pw->pw_dir) == -1)
fatal("chroot");
if (chdir("/") == -1)
fatal("chdir(\"/\")");
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("can't drop privileges");
/* drop privileges */
if (user)
lde_privs.user = user;
if (group)
lde_privs.group = group;
zprivs_init(&lde_privs);
#ifdef HAVE_PLEDGE
if (pledge("stdio recvfd", NULL) == -1)
fatal("pledge");
#endif
event_init();
master = thread_master_create();
/* setup signal handler */
signal_set(&ev_sigint, SIGINT, lde_sig_handler, NULL);
signal_set(&ev_sigterm, SIGTERM, lde_sig_handler, NULL);
signal_add(&ev_sigint, NULL);
signal_add(&ev_sigterm, NULL);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal_init(master, array_size(lde_signals), lde_signals);
/* setup pipe and event handler to the parent process */
if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_main->ibuf, 3);
iev_main->handler = lde_dispatch_parent;
iev_main->events = EV_READ;
event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
iev_main->handler, iev_main);
event_add(&iev_main->ev, NULL);
iev_main->handler_read = lde_dispatch_parent;
iev_main->ev_read = thread_add_read(master, iev_main->handler_read,
iev_main, iev_main->ibuf.fd);
iev_main->handler_write = ldp_write_handler;
iev_main->ev_write = NULL;
/* setup and start the LIB garbage collector */
evtimer_set(&gc_timer, lde_gc_timer, NULL);
/* start the LIB garbage collector */
lde_gc_start_timer();
gettimeofday(&now, NULL);
global.uptime = now.tv_sec;
event_dispatch();
lde_shutdown();
/* Fetch next active thread. */
while (thread_fetch(master, &thread))
thread_call(&thread);
}
static __dead void
static void
lde_shutdown(void)
{
/* close pipes */
@ -170,7 +175,7 @@ lde_shutdown(void)
}
/* imesg */
static int
int
lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)
{
return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen));
@ -185,10 +190,10 @@ lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data,
}
/* ARGSUSED */
static void
lde_dispatch_imsg(int fd, short event, void *bula)
static int
lde_dispatch_imsg(struct thread *thread)
{
struct imsgev *iev = bula;
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
struct lde_nbr *ln;
@ -196,20 +201,14 @@ lde_dispatch_imsg(int fd, short event, void *bula)
struct lde_addr lde_addr;
struct notify_msg nm;
ssize_t n;
int shut = 0, verbose;
int shut = 0;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
}
if (event & EV_WRITE) {
if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
fatal("msgbuf_write");
if (n == 0) /* connection closed */
shut = 1;
}
iev->ev_read = NULL;
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
@ -353,11 +352,6 @@ lde_dispatch_imsg(int fd, short event, void *bula)
lde_imsg_compose_ldpe(IMSG_CTL_END, 0,
imsg.hdr.pid, NULL, 0);
break;
case IMSG_CTL_LOG_VERBOSE:
/* already checked by ldpe */
memcpy(&verbose, imsg.data, sizeof(verbose));
log_verbose(verbose);
break;
default:
log_debug("%s: unexpected imsg %d", __func__,
imsg.hdr.type);
@ -368,15 +362,18 @@ lde_dispatch_imsg(int fd, short event, void *bula)
if (!shut)
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handler */
event_del(&iev->ev);
event_loopexit(NULL);
/* this pipe is dead, so remove the event handlers and exit */
THREAD_READ_OFF(iev->ev_read);
THREAD_WRITE_OFF(iev->ev_write);
lde_shutdown();
}
return (0);
}
/* ARGSUSED */
static void
lde_dispatch_parent(int fd, short event, void *bula)
static int
lde_dispatch_parent(struct thread *thread)
{
static struct ldpd_conf *nconf;
struct iface *niface;
@ -387,24 +384,19 @@ lde_dispatch_parent(int fd, short event, void *bula)
struct l2vpn_pw *npw;
struct imsg imsg;
struct kroute kr;
struct imsgev *iev = bula;
int fd = THREAD_FD(thread);
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
ssize_t n;
int shut = 0;
struct fec fec;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
}
if (event & EV_WRITE) {
if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
fatal("msgbuf_write");
if (n == 0) /* connection closed */
shut = 1;
}
iev->ev_read = NULL;
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
@ -462,11 +454,11 @@ lde_dispatch_parent(int fd, short event, void *bula)
if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_ldpe->ibuf, fd);
iev_ldpe->handler = lde_dispatch_imsg;
iev_ldpe->events = EV_READ;
event_set(&iev_ldpe->ev, iev_ldpe->ibuf.fd,
iev_ldpe->events, iev_ldpe->handler, iev_ldpe);
event_add(&iev_ldpe->ev, NULL);
iev_ldpe->handler_read = lde_dispatch_imsg;
iev_ldpe->ev_read = thread_add_read(master,
iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd);
iev_ldpe->handler_write = ldp_write_handler;
iev_ldpe->ev_write = NULL;
break;
case IMSG_RECONF_CONF:
if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
@ -513,6 +505,7 @@ lde_dispatch_parent(int fd, short event, void *bula)
LIST_INIT(&nl2vpn->if_list);
LIST_INIT(&nl2vpn->pw_list);
LIST_INIT(&nl2vpn->pw_inactive_list);
LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
break;
@ -532,10 +525,26 @@ lde_dispatch_parent(int fd, short event, void *bula)
npw->l2vpn = nl2vpn;
LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
break;
case IMSG_RECONF_L2VPN_IPW:
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
fatal(NULL);
memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
npw->l2vpn = nl2vpn;
LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry);
break;
case IMSG_RECONF_END:
merge_config(ldeconf, nconf);
nconf = NULL;
break;
case IMSG_DEBUG_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(ldp_debug)) {
log_warnx("%s: wrong imsg len", __func__);
break;
}
memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug));
break;
default:
log_debug("%s: unexpected imsg %d", __func__,
imsg.hdr.type);
@ -546,10 +555,13 @@ lde_dispatch_parent(int fd, short event, void *bula)
if (!shut)
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handler */
event_del(&iev->ev);
event_loopexit(NULL);
/* this pipe is dead, so remove the event handlers and exit */
THREAD_READ_OFF(iev->ev_read);
THREAD_WRITE_OFF(iev->ev_write);
lde_shutdown();
}
return (0);
}
uint32_t
@ -557,7 +569,10 @@ lde_assign_label(void)
{
static uint32_t label = MPLS_LABEL_RESERVED_MAX;
/* XXX some checks needed */
/*
* TODO: request label to zebra or define a range of labels for ldpd.
*/
label++;
return (label);
}

View file

@ -21,9 +21,8 @@
#ifndef _LDE_H_
#define _LDE_H_
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include "openbsd-queue.h"
#include "openbsd-tree.h"
enum fec_type {
FEC_TYPE_IPV4,
@ -121,10 +120,11 @@ struct fec_node {
extern struct ldpd_conf *ldeconf;
extern struct fec_tree ft;
extern struct nbr_tree lde_nbrs;
extern struct event gc_timer;
extern struct thread *gc_timer;
/* lde.c */
void lde(int, int);
void lde(const char *, const char *);
int lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
uint32_t lde_assign_label(void);
void lde_send_change_klabel(struct fec_node *, struct fec_nh *);
@ -173,7 +173,7 @@ void lde_check_release(struct map *, struct lde_nbr *);
void lde_check_release_wcard(struct map *, struct lde_nbr *);
void lde_check_withdraw(struct map *, struct lde_nbr *);
void lde_check_withdraw_wcard(struct map *, struct lde_nbr *);
void lde_gc_timer(int, short, void *);
int lde_gc_timer(struct thread *);
void lde_gc_start_timer(void);
void lde_gc_stop_timer(void);
@ -185,8 +185,10 @@ void l2vpn_init(struct l2vpn *);
void l2vpn_exit(struct l2vpn *);
struct l2vpn_if *l2vpn_if_new(struct l2vpn *, struct kif *);
struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int);
struct l2vpn_if *l2vpn_if_find_name(struct l2vpn *, const char *);
struct l2vpn_pw *l2vpn_pw_new(struct l2vpn *, struct kif *);
struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);
void l2vpn_pw_init(struct l2vpn_pw *);
void l2vpn_pw_exit(struct l2vpn_pw *);
void l2vpn_pw_reset(struct l2vpn_pw *);

View file

@ -17,17 +17,14 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netmpls/mpls.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <zebra.h>
#include "ldpd.h"
#include "lde.h"
#include "log.h"
#include "mpls.h"
static __inline int fec_compare(struct fec *, struct fec *);
static int lde_nbr_is_nexthop(struct fec_node *,
struct lde_nbr *);
@ -40,7 +37,7 @@ static void fec_nh_del(struct fec_nh *);
RB_GENERATE(fec_tree, fec, entry, fec_compare)
struct fec_tree ft = RB_INITIALIZER(&ft);
struct event gc_timer;
struct thread *gc_timer;
/* FEC tree functions */
void
@ -165,6 +162,7 @@ rt_dump(pid_t pid)
LIST_EMPTY(&fn->downstream))
continue;
rtctl.first = 1;
switch (fn->fec.type) {
case FEC_TYPE_IPV4:
rtctl.af = AF_INET;
@ -188,6 +186,7 @@ rt_dump(pid_t pid)
lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,
&rtctl, sizeof(rtctl));
rtctl.first = 0;
}
if (LIST_EMPTY(&fn->downstream)) {
rtctl.in_use = 0;
@ -338,9 +337,6 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
if (fec_nh_find(fn, af, nexthop, priority) != NULL)
return;
log_debug("lde add fec %s nexthop %s",
log_fec(&fn->fec), log_addr(af, nexthop));
if (fn->fec.type == FEC_TYPE_PWID)
fn->data = data;
@ -396,9 +392,6 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,
/* route lost */
return;
log_debug("lde remove fec %s nexthop %s",
log_fec(&fn->fec), log_addr(af, nexthop));
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
if (LIST_EMPTY(&fn->nexthops)) {
@ -738,8 +731,8 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)
/* gabage collector timer: timer to remove dead entries from the LIB */
/* ARGSUSED */
void
lde_gc_timer(int fd, short event, void *arg)
int
lde_gc_timer(struct thread *thread)
{
struct fec *fec, *safe;
struct fec_node *fn;
@ -762,23 +755,20 @@ lde_gc_timer(int fd, short event, void *arg)
log_debug("%s: %u entries removed", __func__, count);
lde_gc_start_timer();
return (0);
}
void
lde_gc_start_timer(void)
{
struct timeval tv;
timerclear(&tv);
tv.tv_sec = LDE_GC_INTERVAL;
if (evtimer_add(&gc_timer, &tv) == -1)
fatal(__func__);
THREAD_TIMER_OFF(gc_timer);
gc_timer = thread_add_timer(master, lde_gc_timer, NULL,
LDE_GC_INTERVAL);
}
void
lde_gc_stop_timer(void)
{
if (evtimer_pending(&gc_timer, NULL) &&
evtimer_del(&gc_timer) == -1)
fatal(__func__);
THREAD_TIMER_OFF(gc_timer);
}

View file

@ -23,8 +23,6 @@
#ifndef _LDP_H_
#define _LDP_H_
#include <sys/types.h>
/* misc */
#define LDP_VERSION 1
#define LDP_PORT 646
@ -106,7 +104,7 @@ struct ldp_hdr {
uint16_t length;
uint32_t lsr_id;
uint16_t lspace_id;
} __packed;
} __attribute__ ((packed));
#define LDP_HDR_SIZE 10 /* actual size of the LDP header */
#define LDP_HDR_PDU_LEN 6 /* minimum "PDU Length" */
@ -125,7 +123,7 @@ struct ldp_msg {
uint32_t id;
/* Mandatory Parameters */
/* Optional Parameters */
} __packed;
} __attribute__ ((packed));
#define LDP_MSG_SIZE 8 /* minimum size of LDP message */
#define LDP_MSG_LEN 4 /* minimum "Message Length" */
@ -212,7 +210,7 @@ struct sess_prms_tlv {
uint16_t max_pdu_len;
uint32_t lsr_id;
uint16_t lspace_id;
} __packed;
} __attribute__ ((packed));
#define SESS_PRMS_SIZE 18
#define SESS_PRMS_LEN 14
@ -223,7 +221,7 @@ struct status_tlv {
uint32_t status_code;
uint32_t msg_id;
uint16_t msg_type;
} __packed;
} __attribute__ ((packed));
#define STATUS_SIZE 14
#define STATUS_TLV_LEN 10
@ -237,7 +235,7 @@ struct address_list_tlv {
uint16_t length;
uint16_t family;
/* address entries */
} __packed;
} __attribute__ ((packed));
#define ADDR_LIST_SIZE 6

198
ldpd/ldp_debug.c Normal file
View file

@ -0,0 +1,198 @@
/*
* Copyright (C) 2016 by Open Source Routing.
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <zebra.h>
#include "command.h"
#include "vty.h"
#include "ldpd.h"
#include "ldp_debug.h"
#include "ldp_vty.h"
struct ldp_debug conf_ldp_debug;
struct ldp_debug ldp_debug;
/* Debug node. */
struct cmd_node ldp_debug_node =
{
DEBUG_NODE,
"",
1
};
int
ldp_vty_debug(struct vty *vty, struct vty_arg *args[])
{
const char *type_str, *dir_str;
int disable, all;
disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
type_str = vty_get_arg_value(args, "type");
if (strcmp(type_str, "discovery") == 0) {
dir_str = vty_get_arg_value(args, "dir");
if (dir_str == NULL)
return (CMD_WARNING);
if (dir_str[0] == 'r') {
if (disable)
DEBUG_OFF(hello, HELLO_RECV);
else
DEBUG_ON(hello, HELLO_RECV);
} else {
if (disable)
DEBUG_OFF(hello, HELLO_SEND);
else
DEBUG_ON(hello, HELLO_SEND);
}
} else if (strcmp(type_str, "errors") == 0) {
if (disable)
DEBUG_OFF(errors, ERRORS);
else
DEBUG_ON(errors, ERRORS);
} else if (strcmp(type_str, "event") == 0) {
if (disable)
DEBUG_OFF(event, EVENT);
else
DEBUG_ON(event, EVENT);
} else if (strcmp(type_str, "messages") == 0) {
all = (vty_get_arg_value(args, "all")) ? 1 : 0;
dir_str = vty_get_arg_value(args, "dir");
if (dir_str == NULL)
return (CMD_WARNING);
if (dir_str[0] == 'r') {
if (disable) {
DEBUG_OFF(msg, MSG_RECV);
DEBUG_OFF(msg, MSG_RECV_ALL);
} else {
DEBUG_ON(msg, MSG_RECV);
if (all)
DEBUG_ON(msg, MSG_RECV_ALL);
}
} else {
if (disable) {
DEBUG_OFF(msg, MSG_SEND);
DEBUG_OFF(msg, MSG_SEND_ALL);
} else {
DEBUG_ON(msg, MSG_SEND);
if (all)
DEBUG_ON(msg, MSG_SEND_ALL);
}
}
} else if (strcmp(type_str, "zebra") == 0) {
if (disable)
DEBUG_OFF(zebra, ZEBRA);
else
DEBUG_ON(zebra, ZEBRA);
}
main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
sizeof(ldp_debug));
return (CMD_SUCCESS);
}
int
ldp_vty_show_debugging(struct vty *vty, struct vty_arg *args[])
{
vty_out(vty, "LDP debugging status:%s", VTY_NEWLINE);
if (LDP_DEBUG(hello, HELLO_RECV))
vty_out(vty, " LDP discovery debugging is on (inbound)%s",
VTY_NEWLINE);
if (LDP_DEBUG(hello, HELLO_SEND))
vty_out(vty, " LDP discovery debugging is on (outbound)%s",
VTY_NEWLINE);
if (LDP_DEBUG(errors, ERRORS))
vty_out(vty, " LDP errors debugging is on%s", VTY_NEWLINE);
if (LDP_DEBUG(event, EVENT))
vty_out(vty, " LDP events debugging is on%s", VTY_NEWLINE);
if (LDP_DEBUG(msg, MSG_RECV_ALL))
vty_out(vty, " LDP detailed messages debugging is on "
"(inbound)%s", VTY_NEWLINE);
else if (LDP_DEBUG(msg, MSG_RECV))
vty_out(vty, " LDP messages debugging is on (inbound)%s",
VTY_NEWLINE);
if (LDP_DEBUG(msg, MSG_SEND_ALL))
vty_out(vty, " LDP detailed messages debugging is on "
"(outbound)%s", VTY_NEWLINE);
else if (LDP_DEBUG(msg, MSG_SEND))
vty_out(vty, " LDP messages debugging is on (outbound)%s",
VTY_NEWLINE);
if (LDP_DEBUG(zebra, ZEBRA))
vty_out(vty, " LDP zebra debugging is on%s", VTY_NEWLINE);
vty_out (vty, "%s", VTY_NEWLINE);
return (CMD_SUCCESS);
}
int
ldp_debug_config_write(struct vty *vty)
{
int write = 0;
if (CONF_LDP_DEBUG(hello, HELLO_RECV)) {
vty_out(vty, "debug mpls ldp discovery hello recv%s",
VTY_NEWLINE);
write = 1;
}
if (CONF_LDP_DEBUG(hello, HELLO_SEND)) {
vty_out(vty, "debug mpls ldp discovery hello sent%s",
VTY_NEWLINE);
write = 1;
}
if (CONF_LDP_DEBUG(errors, ERRORS)) {
vty_out(vty, "debug mpls ldp errors%s", VTY_NEWLINE);
write = 1;
}
if (CONF_LDP_DEBUG(event, EVENT)) {
vty_out(vty, "debug mpls ldp event%s", VTY_NEWLINE);
write = 1;
}
if (CONF_LDP_DEBUG(msg, MSG_RECV_ALL)) {
vty_out(vty, "debug mpls ldp messages recv all%s", VTY_NEWLINE);
write = 1;
} else if (CONF_LDP_DEBUG(msg, MSG_RECV)) {
vty_out(vty, "debug mpls ldp messages recv%s", VTY_NEWLINE);
write = 1;
}
if (CONF_LDP_DEBUG(msg, MSG_SEND_ALL)) {
vty_out(vty, "debug mpls ldp messages sent all%s", VTY_NEWLINE);
write = 1;
} else if (CONF_LDP_DEBUG(msg, MSG_SEND)) {
vty_out(vty, "debug mpls ldp messages sent%s", VTY_NEWLINE);
write = 1;
}
if (CONF_LDP_DEBUG(zebra, ZEBRA)) {
vty_out(vty, "debug mpls ldp zebra%s", VTY_NEWLINE);
write = 1;
}
return (write);
}

131
ldpd/ldp_debug.h Normal file
View file

@ -0,0 +1,131 @@
/*
* Copyright (C) 2016 by Open Source Routing.
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _LDP_DEBUG_H_
#define _LDP_DEBUG_H_
struct ldp_debug {
int hello;
#define LDP_DEBUG_HELLO_RECV 0x01
#define LDP_DEBUG_HELLO_SEND 0x02
int errors;
#define LDP_DEBUG_ERRORS 0x01
int event;
#define LDP_DEBUG_EVENT 0x01
int msg;
#define LDP_DEBUG_MSG_RECV 0x01
#define LDP_DEBUG_MSG_RECV_ALL 0x02
#define LDP_DEBUG_MSG_SEND 0x04
#define LDP_DEBUG_MSG_SEND_ALL 0x08
int zebra;
#define LDP_DEBUG_ZEBRA 0x01
};
extern struct ldp_debug conf_ldp_debug;
extern struct ldp_debug ldp_debug;
#define CONF_DEBUG_ON(a, b) (conf_ldp_debug.a |= (LDP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_ldp_debug.a &= ~(LDP_DEBUG_ ## b))
#define TERM_DEBUG_ON(a, b) (ldp_debug.a |= (LDP_DEBUG_ ## b))
#define TERM_DEBUG_OFF(a, b) (ldp_debug.a &= ~(LDP_DEBUG_ ## b))
#define DEBUG_ON(a, b) \
do { \
if (vty->node == CONFIG_NODE) { \
CONF_DEBUG_ON(a, b); \
TERM_DEBUG_ON(a, b); \
} else \
TERM_DEBUG_ON(a, b); \
} while (0)
#define DEBUG_OFF(a, b) \
do { \
CONF_DEBUG_OFF(a, b); \
TERM_DEBUG_OFF(a, b); \
} while (0)
#define LDP_DEBUG(a, b) (ldp_debug.a & LDP_DEBUG_ ## b)
#define CONF_LDP_DEBUG(a, b) (conf_ldp_debug.a & LDP_DEBUG_ ## b)
#define debug_hello_recv(emsg, ...) \
do { \
if (LDP_DEBUG(hello, HELLO_RECV)) \
log_debug("discovery[recv]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_hello_send(emsg, ...) \
do { \
if (LDP_DEBUG(hello, HELLO_SEND)) \
log_debug("discovery[send]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_err(emsg, ...) \
do { \
if (LDP_DEBUG(errors, ERRORS)) \
log_debug("error: " emsg, __VA_ARGS__); \
} while (0)
#define debug_evt(emsg, ...) \
do { \
if (LDP_DEBUG(event, EVENT)) \
log_debug("event: " emsg, __VA_ARGS__); \
} while (0)
#define debug_msg_recv(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_RECV)) \
log_debug("msg[in]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_msg_send(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_SEND)) \
log_debug("msg[out]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_kalive_recv(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_RECV_ALL)) \
log_debug("kalive[in]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_kalive_send(emsg, ...) \
do { \
if (LDP_DEBUG(msg, MSG_SEND_ALL)) \
log_debug("kalive[out]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_zebra_in(emsg, ...) \
do { \
if (LDP_DEBUG(zebra, ZEBRA)) \
log_debug("zebra[in]: " emsg, __VA_ARGS__); \
} while (0)
#define debug_zebra_out(emsg, ...) \
do { \
if (LDP_DEBUG(zebra, ZEBRA)) \
log_debug("zebra[out]: " emsg, __VA_ARGS__); \
} while (0)
#endif /* _LDP_DEBUG_H_ */

81
ldpd/ldp_vty.h Normal file
View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2016 by Open Source Routing.
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _LDP_VTY_H_
#define _LDP_VTY_H_
#include "vty.h"
extern struct cmd_node ldp_node;
extern struct cmd_node ldp_ipv4_node;
extern struct cmd_node ldp_ipv6_node;
extern struct cmd_node ldp_ipv4_iface_node;
extern struct cmd_node ldp_ipv6_iface_node;
extern struct cmd_node ldp_l2vpn_node;
extern struct cmd_node ldp_pseudowire_node;
extern struct cmd_node ldp_debug_node;
union ldpd_addr;
int ldp_get_address(const char *, int *, union ldpd_addr *);
int ldp_config_write(struct vty *);
int ldp_l2vpn_config_write(struct vty *);
int ldp_debug_config_write(struct vty *);
int ldp_vty_mpls_ldp (struct vty *, struct vty_arg *[]);
int ldp_vty_address_family (struct vty *, struct vty_arg *[]);
int ldp_vty_disc_holdtime(struct vty *, struct vty_arg *[]);
int ldp_vty_disc_interval(struct vty *, struct vty_arg *[]);
int ldp_vty_targeted_hello_accept(struct vty *, struct vty_arg *[]);
int ldp_vty_session_holdtime(struct vty *, struct vty_arg *[]);
int ldp_vty_interface(struct vty *, struct vty_arg *[]);
int ldp_vty_trans_addr(struct vty *, struct vty_arg *[]);
int ldp_vty_neighbor_targeted(struct vty *, struct vty_arg *[]);
int ldp_vty_explicit_null(struct vty *, struct vty_arg *[]);
int ldp_vty_ttl_security(struct vty *, struct vty_arg *[]);
int ldp_vty_router_id(struct vty *, struct vty_arg *[]);
int ldp_vty_ds_cisco_interop(struct vty *, struct vty_arg *[]);
int ldp_vty_trans_pref_ipv4(struct vty *, struct vty_arg *[]);
int ldp_vty_neighbor_password(struct vty *, struct vty_arg *[]);
int ldp_vty_neighbor_ttl_security(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_bridge(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_mtu(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pwtype(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_interface(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pseudowire(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pw_cword(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pw_nbr_addr(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pw_nbr_id(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pw_pwid(struct vty *, struct vty_arg *[]);
int ldp_vty_l2vpn_pw_pwstatus(struct vty *, struct vty_arg *[]);
int ldp_vty_show_binding(struct vty *, struct vty_arg *[]);
int ldp_vty_show_discovery(struct vty *, struct vty_arg *[]);
int ldp_vty_show_interface(struct vty *, struct vty_arg *[]);
int ldp_vty_show_neighbor(struct vty *, struct vty_arg *[]);
int ldp_vty_show_atom_binding(struct vty *, struct vty_arg *[]);
int ldp_vty_show_atom_vc(struct vty *, struct vty_arg *[]);
int ldp_vty_clear_nbr(struct vty *, struct vty_arg *[]);
int ldp_vty_debug(struct vty *, struct vty_arg *[]);
int ldp_vty_show_debugging(struct vty *, struct vty_arg *[]);
void ldp_vty_init(void);
void ldp_vty_if_init(void);
#endif /* _LDP_VTY_H_ */

379
ldpd/ldp_vty.xml Normal file
View file

@ -0,0 +1,379 @@
<?xml version="1.0"?>
<file init="ldp_vty_init" cmdprefix="ldp" header="ldp_vty.h">
<!-- address-family -->
<options name="address-family">
<option name="ipv4" help="IPv4 Address Family"/>
<option name="ipv6" help="IPv6 Address Family"/>
</options>
<!-- ipv4/ipv6 address -->
<options name="addr">
<option input="ipv4" help="IPv4 address"/>
<option input="ipv6" help="IPv6 address"/>
</options>
<!-- pseudowire control-word options -->
<options name="cword">
<option name="exclude" help="Exclude control-word in pseudowire packets"/>
<option name="include" help="Include control-word in pseudowire packets"/>
</options>
<!-- pseudowire types -->
<options name="pwtype">
<option name="ethernet" help="Ethernet (type 5)"/>
<option name="ethernet-tagged" help="Ethernet-tagged (type 4)"/>
</options>
<!-- packet direction -->
<options name="dir">
<option name="recv" help="Received messages"/>
<option name="sent" help="Sent messages"/>
</options>
<!-- shared subtrees -->
<subtree name="discovery_link">
<option name="discovery" help="Configure discovery parameters">
<option name="hello" arg="hello_type" help="LDP Link Hellos">
<option name="holdtime" help="Hello holdtime">
<option input="disc_time" arg="seconds" help="Time (seconds) - 65535 implies infinite" function="ldp_vty_disc_holdtime"/>
</option>
<option name="interval" help="Hello interval">
<option input="disc_time" arg="seconds" help="Time (seconds)" function="ldp_vty_disc_interval"/>
</option>
</option>
</option>
</subtree>
<subtree name="discovery_targeted">
<option name="discovery" help="Configure discovery parameters">
<option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos">
<option name="holdtime" help="Targeted hello holdtime">
<option input="disc_time" arg="seconds" help="Time (seconds) - 65535 implies infinite" function="ldp_vty_disc_holdtime"/>
</option>
<option name="interval" help="Targeted hello interval">
<option input="disc_time" arg="seconds" help="Time (seconds)" function="ldp_vty_disc_interval"/>
</option>
</option>
</option>
</subtree>
<subtree name="session_holdtime">
<option name="session" help="Configure session parameters">
<option name="holdtime" help="Configure session holdtime">
<option input="session_time" arg="seconds" help="Time (seconds)" function="ldp_vty_session_holdtime"/>
</option>
</option>
</subtree>
<subtree name="af_common">
<include subtree="discovery_link"/>
<include subtree="discovery_targeted"/>
<option name="discovery" help="Configure discovery parameters">
<option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos">
<option name="accept" help="Accept and respond to targeted hellos" function="ldp_vty_targeted_hello_accept"/>
</option>
</option>
<option name="label" help="Configure label control and policies">
<option name="local" help="Configure local label control and policies">
<option name="advertise" help="Configure outbound label advertisement control">
<option name="explicit-null" help="Configure explicit-null advertisement" function="ldp_vty_explicit_null"/>
</option>
</option>
</option>
<option name="ttl-security" help="LDP ttl security check">
<option name="disable" help="Disable ttl security" function="ldp_vty_ttl_security"/>
</option>
<include subtree="session_holdtime"/>
<option name="interface" help="Enable LDP on an interface and enter interface submode">
<option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_interface"/>
</option>
</subtree>
<!-- global -->
<subtree name="__global">
<option name="mpls" help="Global MPLS configuration subcommands">
<option name="ldp" help="Label Distribution Protocol" function="ldp_vty_mpls_ldp"/>
</option>
<option name="l2vpn" help="Configure l2vpn commands">
<option input="word" arg="name" help="L2VPN name">
<option name="type" help="L2VPN type">
<option name="vpls" help="Virtual Private LAN Service" function="ldp_vty_l2vpn"/>
</option>
</option>
</option>
</subtree>
<tree name="global">
<include subtree="__global"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__global"/>
</option>
</tree>
<!-- ldp node -->
<subtree name="__ldp_node">
<option name="address-family" help="Configure Address Family and its parameters">
<option name="ipv4" arg="address-family" help="IPv4" function="ldp_vty_address_family"/>
<option name="ipv6" arg="address-family" help="IPv6" function="ldp_vty_address_family"/>
</option>
<include subtree="discovery_link"/>
<include subtree="discovery_targeted"/>
<option name="dual-stack" help="Configure dual stack parameters">
<option name="transport-connection" help="Configure TCP transport parameters">
<option name="prefer" help="Configure prefered address family for TCP transport connection with neighbor">
<option name="ipv4" help="IPv4" function="ldp_vty_trans_pref_ipv4"/>
</option>
</option>
<option name="cisco-interop" help="Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV" function="ldp_vty_ds_cisco_interop"/>
</option>
<option name="neighbor" help="Configure neighbor parameters">
<option input="ipv4" arg="lsr_id" help="LDP Id of neighbor">
<option name="password" help="Configure password for MD5 authentication">
<option input="word" arg="password" help="The password" function="ldp_vty_neighbor_password"/>
</option>
<include subtree="session_holdtime"/>
<option name="ttl-security" help="LDP ttl security check">
<option name="disable" help="Disable ttl security" function="ldp_vty_neighbor_ttl_security"/>
<option name="hops" help="IP hops">
<option input="hops" arg="hops" help="maximum number of hops" function="ldp_vty_neighbor_ttl_security"/>
</option>
</option>
</option>
</option>
<option name="router-id" help="Configure router Id">
<option input="ipv4" arg="addr" help="LSR Id (in form of an IPv4 address)" function="ldp_vty_router_id"/>
</option>
</subtree>
<tree name="ldp_node">
<include subtree="__ldp_node"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_node"/>
</option>
</tree>
<!-- address-family ipv4 -->
<subtree name="__ldp_ipv4_node">
<include subtree="af_common"/>
<option name="discovery" help="Configure discovery parameters">
<option name="transport-address" help="Specify transport address for TCP connection">
<option input="ipv4" arg="addr" help="IP address to be used as transport address" function="ldp_vty_trans_addr"/>
</option>
</option>
<option name="neighbor" help="Configure neighbor parameters">
<option input="ipv4" arg="addr" help="IP address of neighbor">
<option name="targeted" help="Establish targeted session" function="ldp_vty_neighbor_targeted"/>
</option>
</option>
</subtree>
<tree name="ldp_ipv4_node">
<include subtree="__ldp_ipv4_node"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_ipv4_node"/>
</option>
</tree>
<!-- address-family ipv6 -->
<subtree name="__ldp_ipv6_node">
<include subtree="af_common"/>
<option name="discovery" help="Configure discovery parameters">
<option name="transport-address" help="Specify transport address for TCP connection">
<option input="ipv6" arg="addr" help="IPv6 address to be used as transport address" function="ldp_vty_trans_addr"/>
</option>
</option>
<option name="neighbor" help="Configure neighbor parameters">
<option input="ipv6" arg="addr" help="IPv6 address of neighbor">
<option name="targeted" help="Establish targeted session" function="ldp_vty_neighbor_targeted"/>
</option>
</option>
</subtree>
<tree name="ldp_ipv6_node">
<include subtree="__ldp_ipv6_node"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_ipv6_node"/>
</option>
</tree>
<!-- ldp ipv4 interface node -->
<subtree name="__ldp_ipv4_iface_node">
<include subtree="discovery_link"/>
</subtree>
<tree name="ldp_ipv4_iface_node">
<include subtree="__ldp_ipv4_iface_node"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_ipv4_iface_node"/>
</option>
</tree>
<!-- ldp ipv6 interface node -->
<subtree name="__ldp_ipv6_iface_node">
<include subtree="discovery_link"/>
</subtree>
<tree name="ldp_ipv6_iface_node">
<include subtree="__ldp_ipv6_iface_node"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_ipv6_iface_node"/>
</option>
</tree>
<!-- l2vpn -->
<subtree name="__ldp_l2vpn">
<option name="bridge" help="Bridge interface">
<option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_bridge"/>
</option>
<option name="mtu" help="set Maximum Transmission Unit">
<option input="mtu" arg="mtu" help="Maximum Transmission Unit value" function="ldp_vty_l2vpn_mtu"/>
</option>
<option name="member" help="L2VPN member configuration">
<option name="interface" help="Local interface">
<option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_interface"/>
</option>
<option name="pseudowire" help="Pseudowire interface">
<option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_pseudowire"/>
</option>
</option>
<option name="vc" help="Virtual Circuit options">
<option name="type" help="Virtual Circuit type to use">
<select options="pwtype" arg="type" function="ldp_vty_l2vpn_pwtype"/>
</option>
</option>
</subtree>
<tree name="ldp_l2vpn">
<include subtree="__ldp_l2vpn"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_l2vpn"/>
</option>
</tree>
<!-- l2vpn pseudowire -->
<subtree name="__ldp_pseudowire">
<option name="control-word" help="Control-word options">
<select options="cword" arg="preference" function="ldp_vty_l2vpn_pw_cword"/>
</option>
<option name="neighbor" help="Remote endpoint configuration">
<option name="address" help="Specify the IPv4 or IPv6 address of the remote endpoint">
<select options="addr" arg="addr" function="ldp_vty_l2vpn_pw_nbr_addr"/>
</option>
<option name="lsr-id" help="Specify the LSR-ID of the remote endpoint">
<option input="ipv4" arg="lsr-id" help="IPv4 address" function="ldp_vty_l2vpn_pw_nbr_id"/>
</option>
</option>
<option name="pw-id" help="Set the Virtual Circuit ID">
<option input="pwid" arg="pwid" help="Virtual Circuit ID value" function="ldp_vty_l2vpn_pw_pwid"/>
</option>
<option name="pw-status" help="Configure PW status">
<option name="disable" help="Disable PW status" function="ldp_vty_l2vpn_pw_pwstatus"/>
</option>
</subtree>
<tree name="ldp_pseudowire">
<include subtree="__ldp_pseudowire"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_pseudowire"/>
</option>
</tree>
<!-- exec mode commands -->
<subtree name="ldp_show_af">
<option name="binding" help="Label Information Base (LIB) information" function="ldp_vty_show_binding"/>
<option name="discovery" help="Discovery Hello Information" function="ldp_vty_show_discovery"/>
<option name="interface" help="interface information" function="ldp_vty_show_interface"/>
</subtree>
<tree name="ldp_exec">
<option name="show" help="Show running system information">
<option name="mpls" help="MPLS information">
<option name="ldp" help="Label Distribution Protocol">
<option name="neighbor" help="Neighbor information" function="ldp_vty_show_neighbor"/>
<include subtree="ldp_show_af"/>
<select options="address-family" arg="address-family">
<include subtree="ldp_show_af"/>
</select>
</option>
</option>
<option name="l2vpn" help="Show information about Layer2 VPN">
<option name="atom" help="Show Any Transport over MPLS information">
<option name="binding" help="Show AToM label binding information" function="ldp_vty_show_atom_binding"/>
<option name="vc" help="Show AToM virtual circuit information" function="ldp_vty_show_atom_vc"/>
</option>
</option>
<option name="debugging" help="Debugging functions">
<option name="mpls" help="MPLS information">
<option name="ldp" help="Label Distribution Protocol" function="ldp_vty_show_debugging"/>
</option>
</option>
</option>
<option name="clear" help="Reset functions">
<option name="mpls" help="Reset MPLS statistical information">
<option name="ldp" help="Clear LDP state">
<option name="neighbor" help="Clear LDP neighbor sessions" function="ldp_vty_clear_nbr">
<select options="addr" arg="addr" function="ldp_vty_clear_nbr"/>
</option>
</option>
</option>
</option>
</tree>
<!-- debug commands -->
<subtree name="__ldp_debug">
<option name="debug" help="Debugging functions">
<option name="mpls" help="MPLS information">
<option name="ldp" help="Label Distribution Protocol">
<option name="discovery" arg="type" help="Discovery messages">
<option name="hello" help="Discovery hello message">
<select options="dir" arg="dir" function="ldp_vty_debug"/>
</option>
</option>
<option name="errors" arg="type" help="Errors" function="ldp_vty_debug"/>
<option name="event" arg="type" help="LDP event information" function="ldp_vty_debug"/>
<option name="messages" arg="type" help="Messages">
<option name="recv" arg="dir" help="Received messages, excluding periodic Keep Alives" function="ldp_vty_debug">
<option name="all" arg="all" help="Received messages, including periodic Keep Alives" function="ldp_vty_debug"/>
</option>
<option name="sent" arg="dir" help="Sent messages, excluding periodic Keep Alives" function="ldp_vty_debug">
<option name="all" arg="all" help="Sent messages, including periodic Keep Alives" function="ldp_vty_debug"/>
</option>
</option>
<option name="zebra" arg="type" help="LDP zebra information" function="ldp_vty_debug"/>
</option>
</option>
</option>
</subtree>
<tree name="ldp_debug">
<include subtree="__ldp_debug"/>
<option name="no" arg="no" help="Negate a command or set its defaults">
<include subtree="__ldp_debug"/>
</option>
</tree>
<!-- nodes -->
<node name="CONFIG">
<include tree="global"/>
<include tree="ldp_debug"/>
</node>
<node install="1" install_default="1" config_write="ldp_config_write" name="LDP">
<include tree="ldp_node"/>
</node>
<node install="1" install_default="1" config_write="NULL" name="LDP_IPV4">
<include tree="ldp_ipv4_node"/>
</node>
<node install="1" install_default="1" config_write="NULL" name="LDP_IPV6">
<include tree="ldp_ipv6_node"/>
</node>
<node install="1" install_default="1" config_write="NULL" name="LDP_IPV4_IFACE">
<include tree="ldp_ipv4_iface_node"/>
</node>
<node install="1" install_default="1" config_write="NULL" name="LDP_IPV6_IFACE">
<include tree="ldp_ipv6_iface_node"/>
</node>
<node install="1" install_default="1" config_write="ldp_l2vpn_config_write" name="LDP_L2VPN">
<include tree="ldp_l2vpn"/>
</node>
<node install="1" install_default="1" config_write="NULL" name="LDP_PSEUDOWIRE">
<include tree="ldp_pseudowire"/>
</node>
<node install="1" config_write="ldp_debug_config_write" name="LDP_DEBUG"/>
<node name="ENABLE">
<include tree="ldp_exec"/>
<include tree="ldp_debug"/>
</node>
<node name="VIEW">
<include tree="ldp_exec"/>
</node>
</file>

1738
ldpd/ldp_vty_cmds.c Normal file

File diff suppressed because it is too large Load diff

1637
ldpd/ldp_vty_conf.c Normal file

File diff suppressed because it is too large Load diff

667
ldpd/ldp_vty_exec.c Normal file
View file

@ -0,0 +1,667 @@
/*
* Copyright (C) 2016 by Open Source Routing.
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <zebra.h>
#include <sys/un.h>
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "log.h"
#include "ldp_vty.h"
#include "command.h"
#include "vty.h"
#include "mpls.h"
enum show_command {
SHOW_DISC,
SHOW_IFACE,
SHOW_NBR,
SHOW_LIB,
SHOW_L2VPN_PW,
SHOW_L2VPN_BINDING
};
struct show_filter {
int family;
union ldpd_addr addr;
uint8_t prefixlen;
};
#define LDPBUFSIZ 65535
static int show_interface_msg(struct vty *, struct imsg *,
struct show_filter *);
static void show_discovery_adj(struct vty *, char *,
struct ctl_adj *);
static int show_discovery_msg(struct vty *, struct imsg *,
struct show_filter *);
static void show_nbr_adj(struct vty *, char *, struct ctl_adj *);
static int show_nbr_msg(struct vty *, struct imsg *,
struct show_filter *);
static int show_lib_msg(struct vty *, struct imsg *,
struct show_filter *);
static int show_l2vpn_binding_msg(struct vty *, struct imsg *);
static int show_l2vpn_pw_msg(struct vty *, struct imsg *);
static int ldp_vty_connect(struct imsgbuf *);
static int ldp_vty_dispatch(struct vty *, struct imsgbuf *,
enum show_command, struct show_filter *);
static int ldp_vty_get_af(const char *, int *);
static int
show_interface_msg(struct vty *vty, struct imsg *imsg,
struct show_filter *filter)
{
struct ctl_iface *iface;
char timers[BUFSIZ];
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_INTERFACE:
iface = imsg->data;
if (filter->family != AF_UNSPEC && filter->family != iface->af)
break;
snprintf(timers, sizeof(timers), "%u/%u",
iface->hello_interval, iface->hello_holdtime);
vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3u%s",
af_name(iface->af), iface->name,
if_state_name(iface->state), iface->uptime == 0 ?
"00:00:00" : log_time(iface->uptime), timers,
iface->adj_cnt, VTY_NEWLINE);
break;
case IMSG_CTL_END:
vty_out(vty, "%s", VTY_NEWLINE);
return (1);
default:
break;
}
return (0);
}
static void
show_discovery_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
{
size_t buflen = strlen(buffer);
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
" LDP Id: %s:0, Transport address: %s%s",
inet_ntoa(adj->id), log_addr(adj->af,
&adj->trans_addr), VTY_NEWLINE);
buflen = strlen(buffer);
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
" Hold time: %u sec%s", adj->holdtime, VTY_NEWLINE);
}
static int
show_discovery_msg(struct vty *vty, struct imsg *imsg,
struct show_filter *filter)
{
struct ctl_adj *adj;
struct ctl_disc_if *iface;
struct ctl_disc_tnbr *tnbr;
struct in_addr rtr_id;
union ldpd_addr *trans_addr;
size_t buflen;
static char ifaces_buffer[LDPBUFSIZ];
static char tnbrs_buffer[LDPBUFSIZ];
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_DISCOVERY:
ifaces_buffer[0] = '\0';
tnbrs_buffer[0] = '\0';
break;
case IMSG_CTL_SHOW_DISC_IFACE:
iface = imsg->data;
if (filter->family != AF_UNSPEC &&
((filter->family == AF_INET && !iface->active_v4) ||
(filter->family == AF_INET6 && !iface->active_v6)))
break;
buflen = strlen(ifaces_buffer);
snprintf(ifaces_buffer + buflen, LDPBUFSIZ - buflen,
" %s: %s%s", iface->name, (iface->no_adj) ?
"xmit" : "xmit/recv", VTY_NEWLINE);
break;
case IMSG_CTL_SHOW_DISC_TNBR:
tnbr = imsg->data;
if (filter->family != AF_UNSPEC && filter->family != tnbr->af)
break;
trans_addr = &(ldp_af_conf_get(ldpd_conf,
tnbr->af))->trans_addr;
buflen = strlen(tnbrs_buffer);
snprintf(tnbrs_buffer + buflen, LDPBUFSIZ - buflen,
" %s -> %s: %s%s", log_addr(tnbr->af, trans_addr),
log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ? "xmit" :
"xmit/recv", VTY_NEWLINE);
break;
case IMSG_CTL_SHOW_DISC_ADJ:
adj = imsg->data;
if (filter->family != AF_UNSPEC && filter->family != adj->af)
break;
switch(adj->type) {
case HELLO_LINK:
show_discovery_adj(vty, ifaces_buffer, adj);
break;
case HELLO_TARGETED:
show_discovery_adj(vty, tnbrs_buffer, adj);
break;
}
break;
case IMSG_CTL_END:
rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf);
vty_out(vty, "Local LDP Identifier: %s:0%s", inet_ntoa(rtr_id),
VTY_NEWLINE);
vty_out(vty, "Discovery Sources:%s", VTY_NEWLINE);
vty_out(vty, " Interfaces:%s", VTY_NEWLINE);
vty_out(vty, "%s", ifaces_buffer);
vty_out(vty, " Targeted Hellos:%s", VTY_NEWLINE);
vty_out(vty, "%s", tnbrs_buffer);
vty_out(vty, "%s", VTY_NEWLINE);
return (1);
default:
break;
}
return (0);
}
static void
show_nbr_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
{
size_t buflen = strlen(buffer);
switch (adj->type) {
case HELLO_LINK:
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
" Interface: %s%s", adj->ifname, VTY_NEWLINE);
break;
case HELLO_TARGETED:
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
" Targeted Hello: %s%s", log_addr(adj->af,
&adj->src_addr), VTY_NEWLINE);
break;
}
}
static int
show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter)
{
struct ctl_adj *adj;
struct ctl_nbr *nbr;
static char v4adjs_buffer[LDPBUFSIZ];
static char v6adjs_buffer[LDPBUFSIZ];
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_NBR:
nbr = imsg->data;
v4adjs_buffer[0] = '\0';
v6adjs_buffer[0] = '\0';
vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id),
VTY_NEWLINE);
vty_out(vty, " TCP connection: %s:%u - %s:%u%s",
log_addr(nbr->af, &nbr->laddr), ntohs(nbr->lport),
log_addr(nbr->af, &nbr->raddr), ntohs(nbr->rport),
VTY_NEWLINE);
vty_out(vty, " Session Holdtime: %u sec%s", nbr->holdtime,
VTY_NEWLINE);
vty_out(vty, " State: %s; Downstream-Unsolicited%s",
nbr_state_name(nbr->nbr_state), VTY_NEWLINE);
vty_out(vty, " Up time: %s%s", log_time(nbr->uptime),
VTY_NEWLINE);
break;
case IMSG_CTL_SHOW_NBR_DISC:
adj = imsg->data;
switch (adj->af) {
case AF_INET:
show_nbr_adj(vty, v4adjs_buffer, adj);
break;
case AF_INET6:
show_nbr_adj(vty, v6adjs_buffer, adj);
break;
default:
fatalx("show_nbr_msg: unknown af");
}
break;
case IMSG_CTL_SHOW_NBR_END:
vty_out(vty, " LDP Discovery Sources:%s", VTY_NEWLINE);
if (v4adjs_buffer[0] != '\0') {
vty_out(vty, " IPv4:%s", VTY_NEWLINE);
vty_out(vty, "%s", v4adjs_buffer);
}
if (v6adjs_buffer[0] != '\0') {
vty_out(vty, " IPv6:%s", VTY_NEWLINE);
vty_out(vty, "%s", v6adjs_buffer);
}
vty_out(vty, "%s", VTY_NEWLINE);
break;
case IMSG_CTL_END:
return (1);
default:
break;
}
return (0);
}
static int
show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter)
{
struct ctl_rt *rt;
char dstnet[BUFSIZ];
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_LIB:
rt = imsg->data;
if (filter->family != AF_UNSPEC && filter->family != rt->af)
break;
snprintf(dstnet, sizeof(dstnet), "%s/%d",
log_addr(rt->af, &rt->prefix), rt->prefixlen);
if (rt->first) {
vty_out(vty, "%s%s", dstnet, VTY_NEWLINE);
vty_out(vty, "%-8sLocal binding: label: %s%s", "",
log_label(rt->local_label), VTY_NEWLINE);
if (rt->remote_label != NO_LABEL) {
vty_out(vty, "%-8sRemote bindings:%s", "",
VTY_NEWLINE);
vty_out(vty, "%-12sPeer Label%s",
"", VTY_NEWLINE);
vty_out(vty, "%-12s----------------- "
"---------%s", "", VTY_NEWLINE);
} else
vty_out(vty, "%-8sNo remote bindings%s", "",
VTY_NEWLINE);
}
if (rt->remote_label != NO_LABEL)
vty_out(vty, "%12s%-20s%s%s", "", inet_ntoa(rt->nexthop),
log_label(rt->remote_label), VTY_NEWLINE);
break;
case IMSG_CTL_END:
vty_out(vty, "%s", VTY_NEWLINE);
return (1);
default:
break;
}
return (0);
}
static int
show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg)
{
struct ctl_pw *pw;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_L2VPN_BINDING:
pw = imsg->data;
vty_out(vty, " Destination Address: %s, VC ID: %u%s",
inet_ntoa(pw->lsr_id), pw->pwid, VTY_NEWLINE);
/* local binding */
if (pw->local_label != NO_LABEL) {
vty_out(vty, " Local Label: %u%s", pw->local_label,
VTY_NEWLINE);
vty_out(vty, "%-8sCbit: %u, VC Type: %s, "
"GroupID: %u%s", "", pw->local_cword,
pw_type_name(pw->type), pw->local_gid,
VTY_NEWLINE);
vty_out(vty, "%-8sMTU: %u%s", "", pw->local_ifmtu,
VTY_NEWLINE);
} else
vty_out(vty, " Local Label: unassigned%s",
VTY_NEWLINE);
/* remote binding */
if (pw->remote_label != NO_LABEL) {
vty_out(vty, " Remote Label: %u%s",
pw->remote_label, VTY_NEWLINE);
vty_out(vty, "%-8sCbit: %u, VC Type: %s, "
"GroupID: %u%s", "", pw->remote_cword,
pw_type_name(pw->type), pw->remote_gid,
VTY_NEWLINE);
vty_out(vty, "%-8sMTU: %u%s", "", pw->remote_ifmtu,
VTY_NEWLINE);
} else
vty_out(vty, " Remote Label: unassigned%s",
VTY_NEWLINE);
break;
case IMSG_CTL_END:
vty_out(vty, "%s", VTY_NEWLINE);
return (1);
default:
break;
}
return (0);
}
static int
show_l2vpn_pw_msg(struct vty *vty, struct imsg *imsg)
{
struct ctl_pw *pw;
switch (imsg->hdr.type) {
case IMSG_CTL_SHOW_L2VPN_PW:
pw = imsg->data;
vty_out(vty, "%-9s %-15s %-10u %-16s %-10s%s", pw->ifname,
inet_ntoa(pw->lsr_id), pw->pwid, pw->l2vpn_name,
(pw->status ? "UP" : "DOWN"), VTY_NEWLINE);
break;
case IMSG_CTL_END:
vty_out(vty, "%s", VTY_NEWLINE);
return (1);
default:
break;
}
return (0);
}
static int
ldp_vty_connect(struct imsgbuf *ibuf)
{
struct sockaddr_un s_un;
int ctl_sock;
/* connect to ldpd control socket */
if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
log_warn("%s: socket", __func__);
return (-1);
}
memset(&s_un, 0, sizeof(s_un));
s_un.sun_family = AF_UNIX;
strlcpy(s_un.sun_path, LDPD_SOCKET, sizeof(s_un.sun_path));
if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
log_warn("%s: connect: %s", __func__, LDPD_SOCKET);
close(ctl_sock);
return (-1);
}
imsg_init(ibuf, ctl_sock);
return (0);
}
static int
ldp_vty_dispatch(struct vty *vty, struct imsgbuf *ibuf, enum show_command cmd,
struct show_filter *filter)
{
struct imsg imsg;
int n, done = 0;
while (ibuf->w.queued)
if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) {
log_warn("write error");
close(ibuf->fd);
return (CMD_WARNING);
}
while (!done) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
log_warnx("imsg_read error");
close(ibuf->fd);
return (CMD_WARNING);
}
if (n == 0) {
log_warnx("pipe closed");
close(ibuf->fd);
return (CMD_WARNING);
}
while (!done) {
if ((n = imsg_get(ibuf, &imsg)) == -1) {
log_warnx("imsg_get error");
close(ibuf->fd);
return (CMD_WARNING);
}
if (n == 0)
break;
switch (cmd) {
case SHOW_IFACE:
done = show_interface_msg(vty, &imsg, filter);
break;
case SHOW_DISC:
done = show_discovery_msg(vty, &imsg, filter);
break;
case SHOW_NBR:
done = show_nbr_msg(vty, &imsg, filter);
break;
case SHOW_LIB:
done = show_lib_msg(vty, &imsg, filter);
break;
case SHOW_L2VPN_PW:
done = show_l2vpn_pw_msg(vty, &imsg);
break;
case SHOW_L2VPN_BINDING:
done = show_l2vpn_binding_msg(vty, &imsg);
break;
default:
break;
}
imsg_free(&imsg);
}
}
close(ibuf->fd);
return (CMD_SUCCESS);
}
static int
ldp_vty_get_af(const char *str, int *af)
{
if (str == NULL) {
*af = AF_UNSPEC;
return (0);
} else if (strcmp(str, "ipv4") == 0) {
*af = AF_INET;
return (0);
} else if (strcmp(str, "ipv6") == 0) {
*af = AF_INET6;
return (0);
}
return (-1);
}
int
ldp_vty_show_binding(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
struct show_filter filter;
const char *af_str;
int af;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
af_str = vty_get_arg_value(args, "address-family");
if (ldp_vty_get_af(af_str, &af) < 0)
return (CMD_ERR_NO_MATCH);
memset(&filter, 0, sizeof(filter));
filter.family = af;
return (ldp_vty_dispatch(vty, &ibuf, SHOW_LIB, &filter));
}
int
ldp_vty_show_discovery(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
struct show_filter filter;
const char *af_str;
int af;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
af_str = vty_get_arg_value(args, "address-family");
if (ldp_vty_get_af(af_str, &af) < 0)
return (CMD_ERR_NO_MATCH);
memset(&filter, 0, sizeof(filter));
filter.family = af;
return (ldp_vty_dispatch(vty, &ibuf, SHOW_DISC, &filter));
}
int
ldp_vty_show_interface(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
struct show_filter filter;
unsigned int ifidx = 0;
const char *af_str;
int af;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, &ifidx,
sizeof(ifidx));
af_str = vty_get_arg_value(args, "address-family");
if (ldp_vty_get_af(af_str, &af) < 0)
return (CMD_ERR_NO_MATCH);
memset(&filter, 0, sizeof(filter));
filter.family = af;
/* header */
vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3s%s", "AF",
"Interface", "State", "Uptime", "Hello Timers", "ac", VTY_NEWLINE);
return (ldp_vty_dispatch(vty, &ibuf, SHOW_IFACE, &filter));
}
int
ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
struct show_filter filter;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
/* not used */
memset(&filter, 0, sizeof(filter));
return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, &filter));
}
int
ldp_vty_show_atom_binding(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
struct show_filter filter;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1, NULL, 0);
/* not used */
memset(&filter, 0, sizeof(filter));
return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_BINDING, &filter));
}
int
ldp_vty_show_atom_vc(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
struct show_filter filter;
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0);
/* not used */
memset(&filter, 0, sizeof(filter));
/* header */
vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s",
"Interface", "Peer ID", "VC ID", "Name", "Status", VTY_NEWLINE);
vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s",
"---------", "---------------", "----------",
"----------------", "----------", VTY_NEWLINE);
return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_PW, &filter));
}
int
ldp_vty_clear_nbr(struct vty *vty, struct vty_arg *args[])
{
struct imsgbuf ibuf;
const char *addr_str;
struct ctl_nbr nbr;
addr_str = vty_get_arg_value(args, "addr");
memset(&nbr, 0, sizeof(nbr));
if (addr_str &&
(ldp_get_address(addr_str, &nbr.af, &nbr.raddr) == -1 ||
bad_addr(nbr.af, &nbr.raddr))) {
vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
return (CMD_WARNING);
}
if (ldp_vty_connect(&ibuf) < 0)
return (CMD_WARNING);
imsg_compose(&ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, sizeof(nbr));
while (ibuf.w.queued)
if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) {
log_warn("write error");
close(ibuf.fd);
return (CMD_WARNING);
}
close(ibuf.fd);
return (CMD_SUCCESS);
}

466
ldpd/ldp_zebra.c Normal file
View file

@ -0,0 +1,466 @@
/*
* Copyright (C) 2016 by Open Source Routing.
*
* This file is part of GNU Zebra.
*
* GNU Zebra is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* GNU Zebra is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Zebra; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <zebra.h>
#include "prefix.h"
#include "stream.h"
#include "memory.h"
#include "zclient.h"
#include "command.h"
#include "network.h"
#include "linklist.h"
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "log.h"
#include "ldp_debug.h"
static void ifp2kif(struct interface *, struct kif *);
static void ifc2kaddr(struct interface *, struct connected *,
struct kaddr *);
static int ldp_router_id_update(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_interface_add(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_interface_delete(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_interface_status_change(int command, struct zclient *,
zebra_size_t, vrf_id_t);
static int ldp_interface_address_add(int, struct zclient *, zebra_size_t,
vrf_id_t);
static int ldp_interface_address_delete(int, struct zclient *,
zebra_size_t, vrf_id_t);
static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t,
vrf_id_t);
static void ldp_zebra_connected(struct zclient *);
static struct zclient *zclient;
static void
ifp2kif(struct interface *ifp, struct kif *kif)
{
memset(kif, 0, sizeof(*kif));
strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname));
kif->ifindex = ifp->ifindex;
kif->flags = ifp->flags;
}
static void
ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka)
{
memset(ka, 0, sizeof(*ka));
ka->ifindex = ifp->ifindex;
ka->af = ifc->address->family;
ka->prefixlen = ifc->address->prefixlen;
switch (ka->af) {
case AF_INET:
ka->addr.v4 = ifc->address->u.prefix4;
if (ifc->destination)
ka->dstbrd.v4 = ifc->destination->u.prefix4;
break;
case AF_INET6:
ka->addr.v6 = ifc->address->u.prefix6;
if (ifc->destination)
ka->dstbrd.v6 = ifc->destination->u.prefix6;
break;
default:
break;
}
}
int
kr_change(struct kroute *kr)
{
/* TODO */
return (0);
}
int
kr_delete(struct kroute *kr)
{
/* TODO */
return (0);
}
int
kmpw_set(struct kpw *kpw)
{
/* TODO */
return (0);
}
int
kmpw_unset(struct kpw *kpw)
{
/* TODO */
return (0);
}
void
kif_redistribute(const char *ifname)
{
struct listnode *node, *cnode;
struct interface *ifp;
struct connected *ifc;
struct kif kif;
struct kaddr ka;
for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) {
if (ifname && strcmp(ifname, ifp->name) != 0)
continue;
ifp2kif(ifp, &kif);
main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
ifc2kaddr(ifp, ifc, &ka);
main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka,
sizeof(ka));
}
}
}
static int
ldp_router_id_update(int command, struct zclient *zclient, zebra_size_t length,
vrf_id_t vrf_id)
{
struct prefix router_id;
zebra_router_id_update_read(zclient->ibuf, &router_id);
if (bad_addr_v4(router_id.u.prefix4))
return (0);
debug_zebra_in("router-id update %s", inet_ntoa(router_id.u.prefix4));
global.rtr_id.s_addr = router_id.u.prefix4.s_addr;
main_imsg_compose_ldpe(IMSG_RTRID_UPDATE, 0, &global.rtr_id,
sizeof(global.rtr_id));
return (0);
}
static int
ldp_interface_add(int command, struct zclient *zclient, zebra_size_t length,
vrf_id_t vrf_id)
{
struct interface *ifp;
struct kif kif;
ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
debug_zebra_in("interface add %s index %d mtu %d", ifp->name,
ifp->ifindex, ifp->mtu);
ifp2kif(ifp, &kif);
main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
return (0);
}
static int
ldp_interface_delete(int command, struct zclient *zclient, zebra_size_t length,
vrf_id_t vrf_id)
{
struct interface *ifp;
/* zebra_interface_state_read() updates interface structure in iflist */
ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
if (ifp == NULL)
return (0);
debug_zebra_in("interface delete %s index %d mtu %d", ifp->name,
ifp->ifindex, ifp->mtu);
/* To support pseudo interface do not free interface structure. */
/* if_delete(ifp); */
ifp->ifindex = IFINDEX_INTERNAL;
return (0);
}
static int
ldp_interface_status_change(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct interface *ifp;
struct listnode *node;
struct connected *ifc;
struct kif kif;
struct kaddr ka;
int link_new;
/*
* zebra_interface_state_read() updates interface structure in
* iflist.
*/
ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
if (ifp == NULL)
return (0);
debug_zebra_in("interface %s state update", ifp->name);
ifp2kif(ifp, &kif);
main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif));
link_new = (ifp->flags & IFF_UP) && (ifp->flags & IFF_RUNNING);
if (link_new) {
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
ifc2kaddr(ifp, ifc, &ka);
main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka,
sizeof(ka));
}
} else {
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
ifc2kaddr(ifp, ifc, &ka);
main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka,
sizeof(ka));
}
}
return (0);
}
static int
ldp_interface_address_add(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct connected *ifc;
struct interface *ifp;
struct kaddr ka;
ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
if (ifc == NULL)
return (0);
ifp = ifc->ifp;
ifc2kaddr(ifp, ifc, &ka);
/* Filter invalid addresses. */
if (bad_addr(ka.af, &ka.addr))
return (0);
debug_zebra_in("address add %s/%u", log_addr(ka.af, &ka.addr),
ka.prefixlen);
/* notify ldpe about new address */
main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka));
return (0);
}
static int
ldp_interface_address_delete(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct connected *ifc;
struct interface *ifp;
struct kaddr ka;
ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
if (ifc == NULL)
return (0);
ifp = ifc->ifp;
ifc2kaddr(ifp, ifc, &ka);
connected_free(ifc);
/* Filter invalid addresses. */
if (bad_addr(ka.af, &ka.addr))
return (0);
debug_zebra_in("address delete %s/%u", log_addr(ka.af, &ka.addr),
ka.prefixlen);
/* notify ldpe about removed address */
main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka));
return (0);
}
static int
ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length,
vrf_id_t vrf_id)
{
struct stream *s;
u_char type;
u_char message_flags;
struct kroute kr;
int nhnum, nhlen;
size_t nhmark;
memset(&kr, 0, sizeof(kr));
s = zclient->ibuf;
type = stream_getc(s);
if (type == ZEBRA_ROUTE_CONNECT)
kr.flags |= F_CONNECTED;
stream_getc(s); /* flags, unused */
stream_getw(s); /* instance, unused */
message_flags = stream_getc(s);
if (!CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP))
return (0);
switch (command) {
case ZEBRA_IPV4_ROUTE_ADD:
case ZEBRA_REDISTRIBUTE_IPV4_ADD:
case ZEBRA_IPV4_ROUTE_DELETE:
case ZEBRA_REDISTRIBUTE_IPV4_DEL:
kr.af = AF_INET;
nhlen = sizeof(struct in_addr);
break;
case ZEBRA_IPV6_ROUTE_ADD:
case ZEBRA_REDISTRIBUTE_IPV6_ADD:
case ZEBRA_IPV6_ROUTE_DELETE:
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
kr.af = AF_INET6;
nhlen = sizeof(struct in6_addr);
break;
default:
fatalx("ldp_zebra_read_route: unknown command");
}
kr.prefixlen = stream_getc(s);
stream_get(&kr.prefix, s, PSIZE(kr.prefixlen));
if (bad_addr(kr.af, &kr.prefix) ||
(kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6)))
return (0);
nhnum = stream_getc(s);
nhmark = stream_get_getp(s);
stream_set_getp(s, nhmark + nhnum * (nhlen + 5));
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE))
kr.priority = stream_getc(s);
if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC))
stream_getl(s); /* metric, not used */
stream_set_getp(s, nhmark);
/* loop through all the nexthops */
for (; nhnum > 0; nhnum--) {
switch (kr.af) {
case AF_INET:
kr.nexthop.v4.s_addr = stream_get_ipv4(s);
break;
case AF_INET6:
stream_get(&kr.nexthop.v6, s, sizeof(kr.nexthop.v6));
break;
default:
break;
}
stream_getc(s); /* ifindex_num, unused. */
kr.ifindex = stream_getl(s);
switch (command) {
case ZEBRA_IPV4_ROUTE_ADD:
case ZEBRA_REDISTRIBUTE_IPV4_ADD:
case ZEBRA_IPV6_ROUTE_ADD:
case ZEBRA_REDISTRIBUTE_IPV6_ADD:
debug_zebra_in("route add %s/%d nexthop %s (%s)",
log_addr(kr.af, &kr.prefix), kr.prefixlen,
log_addr(kr.af, &kr.nexthop),
zebra_route_string(type));
main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr,
sizeof(kr));
break;
case ZEBRA_IPV4_ROUTE_DELETE:
case ZEBRA_REDISTRIBUTE_IPV4_DEL:
case ZEBRA_IPV6_ROUTE_DELETE:
case ZEBRA_REDISTRIBUTE_IPV6_DEL:
debug_zebra_in("route delete %s/%d nexthop %s (%s)",
log_addr(kr.af, &kr.prefix), kr.prefixlen,
log_addr(kr.af, &kr.nexthop),
zebra_route_string(type));
main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, &kr,
sizeof(kr));
break;
default:
fatalx("ldp_zebra_read_route: unknown command");
}
}
return (0);
}
static void
ldp_zebra_connected(struct zclient *zclient)
{
int i;
zclient_send_reg_requests(zclient, VRF_DEFAULT);
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
switch (i) {
case ZEBRA_ROUTE_KERNEL:
case ZEBRA_ROUTE_CONNECT:
case ZEBRA_ROUTE_STATIC:
case ZEBRA_ROUTE_ISIS:
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
AFI_IP, i, 0, VRF_DEFAULT);
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
AFI_IP6, i, 0, VRF_DEFAULT);
break;
case ZEBRA_ROUTE_RIP:
case ZEBRA_ROUTE_OSPF:
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
AFI_IP, i, 0, VRF_DEFAULT);
break;
case ZEBRA_ROUTE_RIPNG:
case ZEBRA_ROUTE_OSPF6:
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient,
AFI_IP6, i, 0, VRF_DEFAULT);
break;
case ZEBRA_ROUTE_BGP:
/* LDP should follow the IGP and ignore BGP routes */
default:
break;
}
}
}
void
ldp_zebra_init(struct thread_master *master)
{
/* Set default values. */
zclient = zclient_new(master);
zclient_init(zclient, ZEBRA_ROUTE_LDP, 0);
/* set callbacks */
zclient->zebra_connected = ldp_zebra_connected;
zclient->router_id_update = ldp_router_id_update;
zclient->interface_add = ldp_interface_add;
zclient->interface_delete = ldp_interface_delete;
zclient->interface_up = ldp_interface_status_change;
zclient->interface_down = ldp_interface_status_change;
zclient->interface_address_add = ldp_interface_address_add;
zclient->interface_address_delete = ldp_interface_address_delete;
zclient->ipv4_route_add = ldp_zebra_read_route;
zclient->ipv4_route_delete = ldp_zebra_read_route;
zclient->redistribute_route_ipv4_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv4_del = ldp_zebra_read_route;
zclient->ipv6_route_add = ldp_zebra_read_route;
zclient->ipv6_route_delete = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_add = ldp_zebra_read_route;
zclient->redistribute_route_ipv6_del = ldp_zebra_read_route;
}

File diff suppressed because it is too large Load diff

46
ldpd/ldpd.conf.sample Normal file
View file

@ -0,0 +1,46 @@
! -*- ldp -*-
!
! LDPd sample configuration file
!
hostname ldpd
password zebra
log stdout
!
interface eth0
!
interface eth1
!
interface lo
!
mpls ldp
dual-stack cisco-interop
neighbor 10.0.1.5 password opensourcerouting
neighbor 172.16.0.1 password opensourcerouting
!
address-family ipv4
discovery transport-address 10.0.1.1
label local advertise explicit-null
!
interface eth0
!
interface eth1
!
!
address-family ipv6
discovery transport-address 2001:db8::1
!
interface eth1
!
!
!
l2vpn ENG type vpls
bridge br0
member interface eth2
!
member pseudowire mpw0
neighbor lsr-id 1.1.1.1
pw-id 100
!
!
line vty
!

View file

@ -22,19 +22,14 @@
#ifndef _LDPD_H_
#define _LDPD_H_
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include <net/if.h>
#include <netinet/in.h>
#include <event.h>
#include <imsg.h>
#include "openbsd-queue.h"
#include "openbsd-tree.h"
#include "imsg.h"
#include "thread.h"
#include "ldp.h"
#define CONF_FILE "/etc/ldpd.conf"
#define LDPD_SOCKET "/var/run/ldpd.sock"
#define LDPD_USER "_ldpd"
#define LDPD_OPT_VERBOSE 0x00000001
@ -57,15 +52,18 @@
#define F_REDISTRIBUTED 0x0040
struct evbuf {
struct msgbuf wbuf;
struct event ev;
struct msgbuf wbuf;
struct thread *ev;
int (*handler)(struct thread *);
void *arg;
};
struct imsgev {
struct imsgbuf ibuf;
void (*handler)(int, short, void *);
struct event ev;
short events;
int (*handler_write)(struct thread *);
struct thread *ev_write;
int (*handler_read)(struct thread *);
struct thread *ev_read;
};
enum imsg_type {
@ -73,7 +71,12 @@ enum imsg_type {
IMSG_CTL_RELOAD,
IMSG_CTL_SHOW_INTERFACE,
IMSG_CTL_SHOW_DISCOVERY,
IMSG_CTL_SHOW_DISC_IFACE,
IMSG_CTL_SHOW_DISC_TNBR,
IMSG_CTL_SHOW_DISC_ADJ,
IMSG_CTL_SHOW_NBR,
IMSG_CTL_SHOW_NBR_DISC,
IMSG_CTL_SHOW_NBR_END,
IMSG_CTL_SHOW_LIB,
IMSG_CTL_SHOW_L2VPN_PW,
IMSG_CTL_SHOW_L2VPN_BINDING,
@ -92,6 +95,7 @@ enum imsg_type {
IMSG_IFSTATUS,
IMSG_NEWADDR,
IMSG_DELADDR,
IMSG_RTRID_UPDATE,
IMSG_LABEL_MAPPING,
IMSG_LABEL_MAPPING_FULL,
IMSG_LABEL_REQUEST,
@ -126,7 +130,10 @@ enum imsg_type {
IMSG_RECONF_L2VPN,
IMSG_RECONF_L2VPN_IF,
IMSG_RECONF_L2VPN_PW,
IMSG_RECONF_END
IMSG_RECONF_L2VPN_IPW,
IMSG_RECONF_END,
IMSG_DEBUG_UPDATE,
IMSG_LOG
};
union ldpd_addr {
@ -249,7 +256,7 @@ struct iface_af {
int state;
LIST_HEAD(, adj) adj_list;
time_t uptime;
struct event hello_timer;
struct thread *hello_timer;
uint16_t hello_holdtime;
uint16_t hello_interval;
};
@ -261,9 +268,7 @@ struct iface {
struct if_addr_head addr_list;
struct in6_addr linklocal;
enum iface_type type;
uint8_t if_type;
uint16_t flags;
uint8_t linkstate;
struct iface_af ipv4;
struct iface_af ipv6;
};
@ -271,13 +276,11 @@ struct iface {
/* source of targeted hellos */
struct tnbr {
LIST_ENTRY(tnbr) entry;
struct event hello_timer;
struct thread *hello_timer;
struct adj *adj;
int af;
union ldpd_addr addr;
int state;
uint16_t hello_holdtime;
uint16_t hello_interval;
uint16_t pw_count;
uint8_t flags;
};
@ -313,7 +316,6 @@ struct l2vpn_if {
char ifname[IF_NAMESIZE];
unsigned int ifindex;
uint16_t flags;
uint8_t link_state;
};
struct l2vpn_pw {
@ -335,6 +337,7 @@ struct l2vpn_pw {
#define F_PW_CWORD_CONF 0x04 /* control word configured */
#define F_PW_CWORD 0x08 /* control word negotiated */
#define F_PW_STATUS_UP 0x10 /* pseudowire is operational */
#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */
struct l2vpn {
LIST_ENTRY(l2vpn) entry;
@ -346,6 +349,7 @@ struct l2vpn {
unsigned int br_ifindex;
LIST_HEAD(, l2vpn_if) if_list;
LIST_HEAD(, l2vpn_pw) pw_list;
LIST_HEAD(, l2vpn_pw) pw_inactive_list;
};
#define L2VPN_TYPE_VPWS 1
#define L2VPN_TYPE_VPLS 2
@ -370,6 +374,8 @@ enum hello_type {
struct ldpd_af_conf {
uint16_t keepalive;
uint16_t lhello_holdtime;
uint16_t lhello_interval;
uint16_t thello_holdtime;
uint16_t thello_interval;
union ldpd_addr trans_addr;
@ -388,15 +394,20 @@ struct ldpd_conf {
LIST_HEAD(, tnbr) tnbr_list;
LIST_HEAD(, nbr_params) nbrp_list;
LIST_HEAD(, l2vpn) l2vpn_list;
uint16_t lhello_holdtime;
uint16_t lhello_interval;
uint16_t thello_holdtime;
uint16_t thello_interval;
uint16_t trans_pref;
int flags;
};
#define F_LDPD_NO_FIB_UPDATE 0x0001
#define F_LDPD_DS_CISCO_INTEROP 0x0002
#define F_LDPD_ENABLED 0x0004
struct ldpd_af_global {
struct event disc_ev;
struct event edisc_ev;
struct thread *disc_ev;
struct thread *edisc_ev;
int ldp_disc_socket;
int ldp_edisc_socket;
int ldp_session_socket;
@ -405,6 +416,7 @@ struct ldpd_af_global {
struct ldpd_global {
int cmd_opts;
time_t uptime;
struct in_addr rtr_id;
struct ldpd_af_global ipv4;
struct ldpd_af_global ipv6;
uint32_t conf_seqnum;
@ -451,10 +463,7 @@ struct kif {
char ifname[IF_NAMESIZE];
unsigned short ifindex;
int flags;
uint8_t link_state;
int mtu;
uint8_t if_type;
uint64_t baudrate;
};
/* control data structures */
@ -464,15 +473,26 @@ struct ctl_iface {
unsigned int ifindex;
int state;
uint16_t flags;
uint8_t linkstate;
enum iface_type type;
uint8_t if_type;
uint16_t hello_holdtime;
uint16_t hello_interval;
time_t uptime;
uint16_t adj_cnt;
};
struct ctl_disc_if {
char name[IF_NAMESIZE];
int active_v4;
int active_v6;
int no_adj;
};
struct ctl_disc_tnbr {
int af;
union ldpd_addr addr;
int no_adj;
};
struct ctl_adj {
int af;
struct in_addr id;
@ -487,7 +507,10 @@ struct ctl_nbr {
int af;
struct in_addr id;
union ldpd_addr laddr;
in_port_t lport;
union ldpd_addr raddr;
in_port_t rport;
uint16_t holdtime;
time_t uptime;
int nbr_state;
};
@ -501,19 +524,23 @@ struct ctl_rt {
uint32_t remote_label;
uint8_t flags;
uint8_t in_use;
int first;
};
struct ctl_pw {
uint16_t type;
char l2vpn_name[L2VPN_NAME_LEN];
char ifname[IF_NAMESIZE];
uint32_t pwid;
struct in_addr lsr_id;
uint32_t local_label;
uint32_t local_gid;
uint16_t local_ifmtu;
uint8_t local_cword;
uint32_t remote_label;
uint32_t remote_gid;
uint16_t remote_ifmtu;
uint8_t remote_cword;
uint32_t status;
};
@ -525,19 +552,9 @@ struct ldpd_conf *parse_config(char *);
int cmdline_symset(char *);
/* kroute.c */
int kif_init(void);
int kr_init(int);
void kif_redistribute(const char *);
int kr_change(struct kroute *);
int kr_delete(struct kroute *);
void kr_shutdown(void);
void kr_fib_couple(void);
void kr_fib_decouple(void);
void kr_change_egress_label(int, int);
void kr_show_route(struct imsg *);
void kr_ifinfo(char *, pid_t);
struct kif *kif_findname(char *);
void kif_clear(void);
int kmpw_set(struct kpw *);
int kmpw_unset(struct kpw *);
@ -561,31 +578,46 @@ void recoverscope(struct sockaddr_in6 *);
void addscope(struct sockaddr_in6 *, uint32_t);
void clearscope(struct in6_addr *);
struct sockaddr *addr2sa(int af, union ldpd_addr *, uint16_t);
void sa2addr(struct sockaddr *, int *, union ldpd_addr *);
void sa2addr(struct sockaddr *, int *, union ldpd_addr *,
in_port_t *);
socklen_t sockaddr_len(struct sockaddr *);
/* ldpd.c */
int ldp_write_handler(struct thread *);
void main_imsg_compose_ldpe(int, pid_t, void *, uint16_t);
void main_imsg_compose_lde(int, pid_t, void *, uint16_t);
int main_imsg_compose_both(enum imsg_type, void *,
uint16_t);
void imsg_event_add(struct imsgev *);
int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t,
int, void *, uint16_t);
int imsg_compose_event(struct imsgev *, uint16_t, uint32_t,
pid_t, int, void *, uint16_t);
void evbuf_enqueue(struct evbuf *, struct ibuf *);
void evbuf_event_add(struct evbuf *);
void evbuf_init(struct evbuf *, int, void (*)(int, short, void *), void *);
void evbuf_init(struct evbuf *, int,
int (*)(struct thread *), void *);
void evbuf_clear(struct evbuf *);
struct ldpd_af_conf *ldp_af_conf_get(struct ldpd_conf *, int);
struct ldpd_af_global *ldp_af_global_get(struct ldpd_global *, int);
int ldp_is_dual_stack(struct ldpd_conf *);
in_addr_t ldp_rtr_id_get(struct ldpd_conf *);
int ldp_reload(struct ldpd_conf *);
struct ldpd_conf *ldp_dup_config(struct ldpd_conf *);
void ldp_clear_config(struct ldpd_conf *);
void merge_config(struct ldpd_conf *, struct ldpd_conf *);
struct ldpd_conf *config_new_empty(void);
void config_clear(struct ldpd_conf *);
/* socket.c */
int ldp_create_socket(int, enum socket_type);
void sock_set_nonblock(int);
void sock_set_cloexec(int);
void sock_set_recvbuf(int);
int sock_set_reuse(int, int);
int sock_set_bindany(int, int);
int sock_set_md5sig(int, int, union ldpd_addr *, const char *);
int sock_set_ipv4_tos(int, int);
int sock_set_ipv4_pktinfo(int, int);
int sock_set_ipv4_recvdstaddr(int, int);
int sock_set_ipv4_recvif(int, int);
int sock_set_ipv4_minttl(int, int);
int sock_set_ipv4_ucast_ttl(int fd, int);
@ -600,7 +632,19 @@ int sock_set_ipv6_mcast_hops(int, int);
int sock_set_ipv6_mcast(struct iface *);
int sock_set_ipv6_mcast_loop(int);
/* printconf.c */
void print_config(struct ldpd_conf *);
/* quagga */
extern struct thread_master *master;
/* ldp_zebra.c */
void ldp_zebra_init(struct thread_master *);
/* compatibility */
#ifndef __OpenBSD__
#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f)
#define __IPV6_ADDR_SCOPE_INTFACELOCAL 0x01
#define IN6_IS_ADDR_MC_INTFACELOCAL(a) \
(IN6_IS_ADDR_MULTICAST(a) && \
(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL))
#endif
#endif /* _LDPD_H_ */

View file

@ -19,70 +19,97 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <pwd.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "control.h"
#include "log.h"
#include "ldp_debug.h"
static void ldpe_sig_handler(int, short, void *);
static __dead void ldpe_shutdown(void);
static void ldpe_dispatch_main(int, short, void *);
static void ldpe_dispatch_lde(int, short, void *);
static void ldpe_dispatch_pfkey(int, short, void *);
#include <lib/log.h>
#include "memory.h"
#include "privs.h"
#include "sigevent.h"
static void ldpe_shutdown(void);
static int ldpe_dispatch_main(struct thread *);
static int ldpe_dispatch_lde(struct thread *);
#ifdef __OpenBSD__
static int ldpe_dispatch_pfkey(struct thread *);
#endif
static void ldpe_setup_sockets(int, int, int, int);
static void ldpe_close_sockets(int);
static void ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int);
struct ldpd_conf *leconf;
#ifdef __OpenBSD__
struct ldpd_sysdep sysdep;
#endif
static struct imsgev *iev_main;
static struct imsgev *iev_lde;
static struct event pfkey_ev;
#ifdef __OpenBSD__
static struct thread *pfkey_ev;
#endif
/* ARGSUSED */
static void
ldpe_sig_handler(int sig, short event, void *bula)
/* Master of threads. */
struct thread_master *master;
/* ldpe privileges */
static zebra_capabilities_t _caps_p [] =
{
switch (sig) {
case SIGINT:
case SIGTERM:
ldpe_shutdown();
/* NOTREACHED */
default:
fatalx("unexpected signal");
}
ZCAP_BIND,
ZCAP_NET_ADMIN
};
struct zebra_privs_t ldpe_privs =
{
#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP)
.user = QUAGGA_USER,
.group = QUAGGA_GROUP,
#endif
#if defined(VTY_GROUP)
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
.cap_num_p = array_size(_caps_p),
.cap_num_i = 0
};
/* SIGINT / SIGTERM handler. */
static void
sigint(void)
{
ldpe_shutdown();
}
static struct quagga_signal_t ldpe_signals[] =
{
{
.signal = SIGINT,
.handler = &sigint,
},
{
.signal = SIGTERM,
.handler = &sigint,
},
};
/* label distribution protocol engine */
void
ldpe(int debug, int verbose)
ldpe(const char *user, const char *group)
{
struct passwd *pw;
struct event ev_sigint, ev_sigterm;
struct thread thread;
leconf = config_new_empty();
log_init(debug);
log_verbose(verbose);
#ifdef HAVE_SETPROCTITLE
setproctitle("ldp engine");
#endif
ldpd_process = PROC_LDP_ENGINE;
/* create ldpd control socket outside chroot */
if (control_init() == -1)
fatalx("control socket setup failed");
LIST_INIT(&global.addr_list);
LIST_INIT(&global.adj_list);
TAILQ_INIT(&global.pending_conns);
@ -90,50 +117,46 @@ ldpe(int debug, int verbose)
fatal("inet_pton");
if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1)
fatal("inet_pton");
#ifdef __OpenBSD__
global.pfkeysock = pfkey_init();
#endif
if ((pw = getpwnam(LDPD_USER)) == NULL)
fatal("getpwnam");
/* drop privileges */
if (user)
ldpe_privs.user = user;
if (group)
ldpe_privs.group = group;
zprivs_init(&ldpe_privs);
if (chroot(pw->pw_dir) == -1)
fatal("chroot");
if (chdir("/") == -1)
fatal("chdir(\"/\")");
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("can't drop privileges");
if (control_init() == -1)
fatalx("control socket setup failed");
#ifdef HAVE_PLEDGE
if (pledge("stdio cpath inet mcast recvfd", NULL) == -1)
fatal("pledge");
#endif
event_init();
master = thread_master_create();
accept_init();
/* setup signal handler */
signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL);
signal_set(&ev_sigterm, SIGTERM, ldpe_sig_handler, NULL);
signal_add(&ev_sigint, NULL);
signal_add(&ev_sigterm, NULL);
signal(SIGPIPE, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal_init(master, array_size(ldpe_signals), ldpe_signals);
/* setup pipe and event handler to the parent process */
if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_main->ibuf, 3);
iev_main->handler = ldpe_dispatch_main;
iev_main->events = EV_READ;
event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events,
iev_main->handler, iev_main);
event_add(&iev_main->ev, NULL);
iev_main->handler_read = ldpe_dispatch_main;
iev_main->ev_read = thread_add_read(master, iev_main->handler_read,
iev_main, iev_main->ibuf.fd);
iev_main->handler_write = ldp_write_handler;
iev_main->ev_write = NULL;
if (sysdep.no_pfkey == 0) {
event_set(&pfkey_ev, global.pfkeysock, EV_READ | EV_PERSIST,
ldpe_dispatch_pfkey, NULL);
event_add(&pfkey_ev, NULL);
}
#ifdef __OpenBSD__
if (sysdep.no_pfkey == 0)
pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey,
NULL, global.pfkeysock);
#endif
/* mark sockets as closed */
global.ipv4.ldp_disc_socket = -1;
@ -150,12 +173,12 @@ ldpe(int debug, int verbose)
if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)
fatal(__func__);
event_dispatch();
ldpe_shutdown();
/* Fetch next active thread. */
while (thread_fetch(master, &thread))
thread_call(&thread);
}
static __dead void
static void
ldpe_shutdown(void)
{
struct if_addr *if_addr;
@ -172,10 +195,12 @@ ldpe_shutdown(void)
control_cleanup();
config_clear(leconf);
#ifdef __OpenBSD__
if (sysdep.no_pfkey == 0) {
event_del(&pfkey_ev);
THREAD_READ_OFF(pfkey_ev);
close(global.pfkeysock);
}
#endif
ldpe_close_sockets(AF_INET);
ldpe_close_sockets(AF_INET6);
@ -212,8 +237,8 @@ ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data,
}
/* ARGSUSED */
static void
ldpe_dispatch_main(int fd, short event, void *bula)
static int
ldpe_dispatch_main(struct thread *thread)
{
static struct ldpd_conf *nconf;
struct iface *niface;
@ -223,7 +248,8 @@ ldpe_dispatch_main(int fd, short event, void *bula)
struct l2vpn_if *nlif;
struct l2vpn_pw *npw;
struct imsg imsg;
struct imsgev *iev = bula;
int fd = THREAD_FD(thread);
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
struct iface *iface = NULL;
struct kif *kif;
@ -233,21 +259,17 @@ ldpe_dispatch_main(int fd, short event, void *bula)
static int edisc_socket = -1;
static int session_socket = -1;
struct nbr *nbr;
#ifdef __OpenBSD__
struct nbr_params *nbrp;
#endif
int n, shut = 0;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
}
if (event & EV_WRITE) {
if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
fatal("ldpe_dispatch_main: msgbuf_write");
if (n == 0)
shut = 1;
}
iev->ev_read = NULL;
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
@ -262,12 +284,11 @@ ldpe_dispatch_main(int fd, short event, void *bula)
fatalx("IFSTATUS imsg with wrong len");
kif = imsg.data;
iface = if_lookup(leconf, kif->ifindex);
iface = if_lookup_name(leconf, kif->ifname);
if (!iface)
break;
iface->flags = kif->flags;
iface->linkstate = kif->link_state;
if_update_info(iface, kif);
if_update(iface, AF_UNSPEC);
break;
case IMSG_NEWADDR:
@ -299,11 +320,11 @@ ldpe_dispatch_main(int fd, short event, void *bula)
if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_lde->ibuf, fd);
iev_lde->handler = ldpe_dispatch_lde;
iev_lde->events = EV_READ;
event_set(&iev_lde->ev, iev_lde->ibuf.fd,
iev_lde->events, iev_lde->handler, iev_lde);
event_add(&iev_lde->ev, NULL);
iev_lde->handler_read = ldpe_dispatch_lde;
iev_lde->ev_read = thread_add_read(master,
iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd);
iev_lde->handler_write = ldp_write_handler;
iev_lde->ev_write = NULL;
break;
case IMSG_CLOSE_SOCKETS:
af = imsg.hdr.peerid;
@ -312,7 +333,9 @@ ldpe_dispatch_main(int fd, short event, void *bula)
if (nbr->af != af)
continue;
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
#ifdef __OpenBSD__
pfkey_remove(nbr);
#endif
}
ldpe_close_sockets(af);
if_update_all(af);
@ -366,13 +389,25 @@ ldpe_dispatch_main(int fd, short event, void *bula)
continue;
nbr->laddr = (ldp_af_conf_get(leconf,
af))->trans_addr;
#ifdef __OpenBSD__
nbrp = nbr_params_find(leconf, nbr->id);
if (nbrp && pfkey_establish(nbr, nbrp) == -1)
fatalx("pfkey setup failed");
#endif
if (nbr_session_active_role(nbr))
nbr_establish_connection(nbr);
}
break;
case IMSG_RTRID_UPDATE:
memcpy(&global.rtr_id, imsg.data,
sizeof(global.rtr_id));
if (leconf->rtr_id.s_addr == INADDR_ANY) {
ldpe_reset_nbrs(AF_INET);
ldpe_reset_nbrs(AF_INET6);
}
if_update_all(AF_UNSPEC);
tnbr_update_all(AF_UNSPEC);
break;
case IMSG_RECONF_CONF:
if ((nconf = malloc(sizeof(struct ldpd_conf))) ==
NULL)
@ -418,6 +453,7 @@ ldpe_dispatch_main(int fd, short event, void *bula)
LIST_INIT(&nl2vpn->if_list);
LIST_INIT(&nl2vpn->pw_list);
LIST_INIT(&nl2vpn->pw_inactive_list);
LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);
break;
@ -437,17 +473,30 @@ ldpe_dispatch_main(int fd, short event, void *bula)
npw->l2vpn = nl2vpn;
LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);
break;
case IMSG_RECONF_L2VPN_IPW:
if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL)
fatal(NULL);
memcpy(npw, imsg.data, sizeof(struct l2vpn_pw));
npw->l2vpn = nl2vpn;
LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry);
break;
case IMSG_RECONF_END:
merge_config(leconf, nconf);
nconf = NULL;
global.conf_seqnum++;
break;
case IMSG_CTL_KROUTE:
case IMSG_CTL_KROUTE_ADDR:
case IMSG_CTL_IFINFO:
case IMSG_CTL_END:
control_imsg_relay(&imsg);
break;
case IMSG_DEBUG_UPDATE:
if (imsg.hdr.len != IMSG_HEADER_SIZE +
sizeof(ldp_debug)) {
log_warnx("%s: wrong imsg len", __func__);
break;
}
memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug));
break;
default:
log_debug("ldpe_dispatch_main: error handling imsg %d",
imsg.hdr.type);
@ -458,17 +507,20 @@ ldpe_dispatch_main(int fd, short event, void *bula)
if (!shut)
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handler */
event_del(&iev->ev);
event_loopexit(NULL);
/* this pipe is dead, so remove the event handlers and exit */
THREAD_READ_OFF(iev->ev_read);
THREAD_WRITE_OFF(iev->ev_write);
ldpe_shutdown();
}
return (0);
}
/* ARGSUSED */
static void
ldpe_dispatch_lde(int fd, short event, void *bula)
static int
ldpe_dispatch_lde(struct thread *thread)
{
struct imsgev *iev = bula;
struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
struct map map;
@ -476,18 +528,12 @@ ldpe_dispatch_lde(int fd, short event, void *bula)
int n, shut = 0;
struct nbr *nbr = NULL;
if (event & EV_READ) {
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
}
if (event & EV_WRITE) {
if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
fatal("ldpe_dispatch_lde: msgbuf_write");
if (n == 0)
shut = 1;
}
iev->ev_read = NULL;
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
fatal("imsg_read error");
if (n == 0) /* connection closed */
shut = 1;
for (;;) {
if ((n = imsg_get(ibuf, &imsg)) == -1)
@ -592,22 +638,31 @@ ldpe_dispatch_lde(int fd, short event, void *bula)
if (!shut)
imsg_event_add(iev);
else {
/* this pipe is dead, so remove the event handler */
event_del(&iev->ev);
event_loopexit(NULL);
/* this pipe is dead, so remove the event handlers and exit */
THREAD_READ_OFF(iev->ev_read);
THREAD_WRITE_OFF(iev->ev_write);
ldpe_shutdown();
}
return (0);
}
#ifdef __OpenBSD__
/* ARGSUSED */
static void
ldpe_dispatch_pfkey(int fd, short event, void *bula)
static int
ldpe_dispatch_pfkey(struct thread *thread)
{
if (event & EV_READ) {
if (pfkey_read(fd, NULL) == -1) {
fatal("pfkey_read failed, exiting...");
}
}
int fd = THREAD_FD(thread);
pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey,
NULL, global.pfkeysock);
if (pfkey_read(fd, NULL) == -1)
fatal("pfkey_read failed, exiting...");
return (0);
}
#endif /* __OpenBSD__ */
static void
ldpe_setup_sockets(int af, int disc_socket, int edisc_socket,
@ -619,15 +674,13 @@ ldpe_setup_sockets(int af, int disc_socket, int edisc_socket,
/* discovery socket */
af_global->ldp_disc_socket = disc_socket;
event_set(&af_global->disc_ev, af_global->ldp_disc_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
event_add(&af_global->disc_ev, NULL);
af_global->disc_ev = thread_add_read(master, disc_recv_packet,
&af_global->disc_ev, af_global->ldp_disc_socket);
/* extended discovery socket */
af_global->ldp_edisc_socket = edisc_socket;
event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket,
EV_READ|EV_PERSIST, disc_recv_packet, NULL);
event_add(&af_global->edisc_ev, NULL);
af_global->edisc_ev = thread_add_read(master, disc_recv_packet,
&af_global->edisc_ev, af_global->ldp_edisc_socket);
/* session socket */
af_global->ldp_session_socket = session_socket;
@ -642,16 +695,14 @@ ldpe_close_sockets(int af)
af_global = ldp_af_global_get(&global, af);
/* discovery socket */
if (event_initialized(&af_global->disc_ev))
event_del(&af_global->disc_ev);
THREAD_READ_OFF(af_global->disc_ev);
if (af_global->ldp_disc_socket != -1) {
close(af_global->ldp_disc_socket);
af_global->ldp_disc_socket = -1;
}
/* extended discovery socket */
if (event_initialized(&af_global->edisc_ev))
event_del(&af_global->edisc_ev);
THREAD_READ_OFF(af_global->edisc_ev);
if (af_global->ldp_edisc_socket != -1) {
close(af_global->ldp_edisc_socket);
af_global->ldp_edisc_socket = -1;
@ -745,24 +796,57 @@ ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)
void
ldpe_adj_ctl(struct ctl_conn *c)
{
struct nbr *nbr;
struct adj *adj;
struct ctl_adj *actl;
struct iface *iface;
struct tnbr *tnbr;
struct adj *adj;
struct ctl_adj *actl;
struct ctl_disc_if ictl;
struct ctl_disc_tnbr tctl;
RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
LIST_FOREACH(iface, &leconf->iface_list, entry) {
memset(&ictl, 0, sizeof(ictl));
ictl.active_v4 = (iface->ipv4.state == IF_STA_ACTIVE);
ictl.active_v6 = (iface->ipv6.state == IF_STA_ACTIVE);
if (!ictl.active_v4 && !ictl.active_v6)
continue;
strlcpy(ictl.name, iface->name, sizeof(ictl.name));
if (LIST_EMPTY(&iface->ipv4.adj_list) &&
LIST_EMPTY(&iface->ipv6.adj_list))
ictl.no_adj = 1;
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_IFACE, 0, 0,
-1, &ictl, sizeof(ictl));
LIST_FOREACH(adj, &iface->ipv4.adj_list, ia_entry) {
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY,
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ,
0, 0, -1, actl, sizeof(struct ctl_adj));
}
LIST_FOREACH(adj, &iface->ipv6.adj_list, ia_entry) {
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ,
0, 0, -1, actl, sizeof(struct ctl_adj));
}
}
/* show adjacencies not associated with any neighbor */
LIST_FOREACH(adj, &global.adj_list, global_entry) {
if (adj->nbr != NULL)
LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) {
memset(&tctl, 0, sizeof(tctl));
tctl.af = tnbr->af;
tctl.addr = tnbr->addr;
if (tnbr->adj == NULL)
tctl.no_adj = 1;
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_TNBR, 0, 0,
-1, &tctl, sizeof(tctl));
if (tnbr->adj == NULL)
continue;
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0,
actl = adj_to_ctl(tnbr->adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, 0, 0,
-1, actl, sizeof(struct ctl_adj));
}
@ -772,13 +856,27 @@ ldpe_adj_ctl(struct ctl_conn *c)
void
ldpe_nbr_ctl(struct ctl_conn *c)
{
struct adj *adj;
struct ctl_adj *actl;
struct nbr *nbr;
struct ctl_nbr *nctl;
RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) {
if (nbr->state == NBR_STA_PRESENT)
continue;
nctl = nbr_to_ctl(nbr);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,
sizeof(struct ctl_nbr));
LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) {
actl = adj_to_ctl(adj);
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_DISC,
0, 0, -1, actl, sizeof(struct ctl_adj));
}
imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_END, 0, 0, -1,
NULL, 0);
}
imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);
}

View file

@ -21,10 +21,11 @@
#ifndef _LDPE_H_
#define _LDPE_H_
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/tree.h>
#include "openbsd-queue.h"
#include "openbsd-tree.h"
#ifdef __OpenBSD__
#include <net/pfkeyv2.h>
#endif
#include "ldpd.h"
@ -48,7 +49,7 @@ struct adj {
struct nbr *nbr;
int ds_tlv;
struct hello_source source;
struct event inactivity_timer;
struct thread *inactivity_timer;
uint16_t holdtime;
union ldpd_addr trans_addr;
};
@ -58,18 +59,20 @@ struct tcp_conn {
int fd;
struct ibuf_read *rbuf;
struct evbuf wbuf;
struct event rev;
struct thread *rev;
in_port_t lport;
in_port_t rport;
};
struct nbr {
RB_ENTRY(nbr) id_tree, addr_tree, pid_tree;
struct tcp_conn *tcp;
LIST_HEAD(, adj) adj_list; /* adjacencies */
struct event ev_connect;
struct event keepalive_timer;
struct event keepalive_timeout;
struct event init_timeout;
struct event initdelay_timer;
struct thread *ev_connect;
struct thread *keepalive_timer;
struct thread *keepalive_timeout;
struct thread *init_timeout;
struct thread *initdelay_timer;
struct mapping_head mapping_list;
struct mapping_head withdraw_list;
@ -117,7 +120,7 @@ struct pending_conn {
int fd;
int af;
union ldpd_addr addr;
struct event ev_timeout;
struct thread *ev_timeout;
};
#define PENDING_CONN_TIMEOUT 5
@ -139,7 +142,7 @@ extern struct nbr_pid_head nbrs_by_pid;
/* accept.c */
void accept_init(void);
int accept_add(int, void (*)(int, short, void *), void *);
int accept_add(int, int (*)(struct thread *), void *);
void accept_del(int);
void accept_pause(void);
void accept_unpause(void);
@ -180,7 +183,7 @@ int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,
uint16_t, struct map *);
/* ldpe.c */
void ldpe(int, int);
void ldpe(const char *, const char *);
int ldpe_imsg_compose_parent(int, pid_t, void *,
uint16_t);
int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *,
@ -200,11 +203,15 @@ void mapping_list_clr(struct mapping_head *);
struct iface *if_new(struct kif *);
void if_exit(struct iface *);
struct iface *if_lookup(struct ldpd_conf *, unsigned short);
struct iface *if_lookup_name(struct ldpd_conf *, const char *);
void if_update_info(struct iface *, struct kif *);
struct iface_af *iface_af_get(struct iface *, int);
void if_addr_add(struct kaddr *);
void if_addr_del(struct kaddr *);
void if_update(struct iface *, int);
void if_update_all(int);
uint16_t if_get_hello_holdtime(struct iface_af *);
uint16_t if_get_hello_interval(struct iface_af *);
struct ctl_iface *if_to_ctl(struct iface_af *);
in_addr_t if_get_ipv4_addr(struct iface *);
@ -216,11 +223,13 @@ struct adj *adj_find(struct hello_source *);
int adj_get_af(struct adj *adj);
void adj_start_itimer(struct adj *);
void adj_stop_itimer(struct adj *);
struct tnbr *tnbr_new(struct ldpd_conf *, int, union ldpd_addr *);
struct tnbr *tnbr_new(int, union ldpd_addr *);
struct tnbr *tnbr_find(struct ldpd_conf *, int, union ldpd_addr *);
struct tnbr *tnbr_check(struct tnbr *);
void tnbr_update(struct tnbr *);
void tnbr_update_all(int);
uint16_t tnbr_get_hello_holdtime(struct tnbr *);
uint16_t tnbr_get_hello_interval(struct tnbr *);
struct ctl_adj *adj_to_ctl(struct adj *);
/* neighbor.c */
@ -255,8 +264,8 @@ int gen_ldp_hdr(struct ibuf *, uint16_t);
int gen_msg_hdr(struct ibuf *, uint16_t, uint16_t);
int send_packet(int, int, union ldpd_addr *,
struct iface_af *, void *, size_t);
void disc_recv_packet(int, short, void *);
void session_accept(int, short, void *);
int disc_recv_packet(struct thread *);
int session_accept(struct thread *);
void session_accept_nbr(struct nbr *, int);
void session_shutdown(struct nbr *, uint32_t, uint32_t,
uint32_t);
@ -268,10 +277,12 @@ struct pending_conn *pending_conn_find(int, union ldpd_addr *);
char *pkt_ptr; /* packet buffer */
/* pfkey.c */
#ifdef __OpenBSD__
int pfkey_read(int, struct sadb_msg *);
int pfkey_establish(struct nbr *, struct nbr_params *);
int pfkey_remove(struct nbr *);
int pfkey_init(void);
#endif
/* l2vpn.c */
void ldpe_l2vpn_init(struct l2vpn *);

View file

@ -16,53 +16,23 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netmpls/mpls.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <netdb.h>
#include <limits.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "log.h"
#include <lib/log.h>
#include "mpls.h"
static const char * const procnames[] = {
"parent",
"ldpe",
"lde"
};
static void vlog(int, const char *, va_list);
static int debug;
static int verbose;
void
log_init(int n_debug)
{
extern char *__progname;
debug = n_debug;
if (!debug)
openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
tzset();
}
void
log_verbose(int v)
{
verbose = v;
}
void vlog(int, const char *, va_list);
void
logit(int pri, const char *fmt, ...)
@ -74,23 +44,24 @@ logit(int pri, const char *fmt, ...)
va_end(ap);
}
static void
void
vlog(int pri, const char *fmt, va_list ap)
{
char *nfmt;
char buf[1024];
if (debug) {
/* best effort in out of mem situations */
if (asprintf(&nfmt, "%s\n", fmt) == -1) {
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
} else {
vfprintf(stderr, nfmt, ap);
free(nfmt);
}
fflush(stderr);
} else
vsyslog(pri, fmt, ap);
switch (ldpd_process) {
case PROC_LDE_ENGINE:
vsnprintf(buf, sizeof(buf), fmt, ap);
lde_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1);
break;
case PROC_LDP_ENGINE:
vsnprintf(buf, sizeof(buf), fmt, ap);
ldpe_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1);
break;
case PROC_MAIN:
vzlog(NULL, pri, fmt, ap);
break;
}
}
void
@ -137,16 +108,24 @@ log_info(const char *emsg, ...)
va_end(ap);
}
void
log_notice(const char *emsg, ...)
{
va_list ap;
va_start(ap, emsg);
vlog(LOG_NOTICE, emsg, ap);
va_end(ap);
}
void
log_debug(const char *emsg, ...)
{
va_list ap;
if (verbose & LDPD_OPT_VERBOSE) {
va_start(ap, emsg);
vlog(LOG_DEBUG, emsg, ap);
va_end(ap);
}
va_start(ap, emsg);
vlog(LOG_DEBUG, emsg, ap);
va_end(ap);
}
void
@ -183,7 +162,7 @@ log_sockaddr(void *vp)
round = (round + 1) % NUM_LOGS;
if (getnameinfo(sa, sa->sa_len, buf[round], NI_MAXHOST, NULL, 0,
if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0,
NI_NUMERICHOST))
return ("(unknown)");
else
@ -196,7 +175,9 @@ log_in6addr(const struct in6_addr *addr)
struct sockaddr_in6 sa_in6;
memset(&sa_in6, 0, sizeof(sa_in6));
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sa_in6.sin6_len = sizeof(sa_in6);
#endif
sa_in6.sin6_family = AF_INET6;
sa_in6.sin6_addr = *addr;
@ -211,7 +192,9 @@ log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex)
struct sockaddr_in6 sa_in6;
memset(&sa_in6, 0, sizeof(sa_in6));
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sa_in6.sin6_len = sizeof(sa_in6);
#endif
sa_in6.sin6_family = AF_INET6;
sa_in6.sin6_addr = *addr;
@ -275,6 +258,39 @@ log_label(uint32_t label)
return (buf);
}
const char *
log_time(time_t t)
{
char *buf;
static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */
static int idx = 0;
unsigned int sec, min, hrs, day, week;
buf = tfbuf[idx++];
if (idx == TF_BUFS)
idx = 0;
week = t;
sec = week % 60;
week /= 60;
min = week % 60;
week /= 60;
hrs = week % 24;
week /= 24;
day = week % 7;
week /= 7;
if (week > 0)
snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
else if (day > 0)
snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
else
snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
return (buf);
}
char *
log_hello_src(const struct hello_source *src)
{
@ -365,8 +381,10 @@ af_name(int af)
return ("ipv4");
case AF_INET6:
return ("ipv6");
#ifdef AF_MPLS
case AF_MPLS:
return ("mpls");
#endif
default:
return ("UNKNOWN");
}
@ -564,37 +582,3 @@ pw_type_name(uint16_t pw_type)
return (buf);
}
}
static char *msgtypes[] = {
"",
"RTM_ADD: Add Route",
"RTM_DELETE: Delete Route",
"RTM_CHANGE: Change Metrics or flags",
"RTM_GET: Report Metrics",
"RTM_LOSING: Kernel Suspects Partitioning",
"RTM_REDIRECT: Told to use different route",
"RTM_MISS: Lookup failed on this address",
"RTM_LOCK: fix specified metrics",
"RTM_OLDADD: caused by SIOCADDRT",
"RTM_OLDDEL: caused by SIOCDELRT",
"RTM_RESOLVE: Route created by cloning",
"RTM_NEWADDR: address being added to iface",
"RTM_DELADDR: address being removed from iface",
"RTM_IFINFO: iface status change",
"RTM_IFANNOUNCE: iface arrival/departure",
"RTM_DESYNC: route socket overflow",
};
void
log_rtmsg(unsigned char rtm_type)
{
if (!(verbose & LDPD_OPT_VERBOSE2))
return;
if (rtm_type > 0 &&
rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0]))
log_debug("kernel message: %s", msgtypes[rtm_type]);
else
log_debug("kernel message: rtm_type %d out of range",
rtm_type);
}

View file

@ -26,8 +26,6 @@ union ldpd_addr;
struct hello_source;
struct fec;
void log_init(int);
void log_verbose(int);
void logit(int, const char *, ...)
__attribute__((__format__ (printf, 2, 3)));
void log_warn(const char *, ...)
@ -36,17 +34,22 @@ void log_warnx(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_info(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_notice(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void log_debug(const char *, ...)
__attribute__((__format__ (printf, 1, 2)));
void fatal(const char *) __dead
void fatal(const char *)
__attribute__ ((noreturn))
__attribute__((__format__ (printf, 1, 0)));
void fatalx(const char *) __dead
void fatalx(const char *)
__attribute__ ((noreturn))
__attribute__((__format__ (printf, 1, 0)));
const char *log_sockaddr(void *);
const char *log_in6addr(const struct in6_addr *);
const char *log_in6addr_scope(const struct in6_addr *, unsigned int);
const char *log_addr(int, const union ldpd_addr *);
char *log_label(uint32_t);
const char *log_time(time_t);
char *log_hello_src(const struct hello_source *);
const char *log_map(const struct map *);
const char *log_fec(const struct fec *);
@ -58,6 +61,5 @@ const char *if_type_name(enum iface_type);
const char *msg_name(uint16_t);
const char *status_code_name(uint32_t);
const char *pw_type_name(uint16_t);
void log_rtmsg(unsigned char);
#endif /* _LOG_H_ */

View file

@ -19,14 +19,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/time.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
@ -37,13 +30,13 @@ static __inline int nbr_id_compare(struct nbr *, struct nbr *);
static __inline int nbr_addr_compare(struct nbr *, struct nbr *);
static __inline int nbr_pid_compare(struct nbr *, struct nbr *);
static void nbr_update_peerid(struct nbr *);
static void nbr_ktimer(int, short, void *);
static int nbr_ktimer(struct thread *);
static void nbr_start_ktimer(struct nbr *);
static void nbr_ktimeout(int, short, void *);
static int nbr_ktimeout(struct thread *);
static void nbr_start_ktimeout(struct nbr *);
static void nbr_itimeout(int, short, void *);
static int nbr_itimeout(struct thread *);
static void nbr_start_itimeout(struct nbr *);
static void nbr_idtimer(int, short, void *);
static int nbr_idtimer(struct thread *);
static int nbr_act_session_operational(struct nbr *);
static void nbr_send_labelmappings(struct nbr *);
@ -266,15 +259,17 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,
TAILQ_INIT(&nbr->release_list);
TAILQ_INIT(&nbr->abortreq_list);
/* set event structures */
evtimer_set(&nbr->keepalive_timeout, nbr_ktimeout, nbr);
evtimer_set(&nbr->keepalive_timer, nbr_ktimer, nbr);
evtimer_set(&nbr->init_timeout, nbr_itimeout, nbr);
evtimer_set(&nbr->initdelay_timer, nbr_idtimer, nbr);
nbrp = nbr_params_find(leconf, nbr->id);
if (nbrp && pfkey_establish(nbr, nbrp) == -1)
fatalx("pfkey setup failed");
if (nbrp) {
#ifdef __OpenBSD__
if (pfkey_establish(nbr, nbrp) == -1)
fatalx("pfkey setup failed");
#else
sock_set_md5sig(
(ldp_af_global_get(&global, nbr->af))->ldp_session_socket,
nbr->af, &nbr->raddr, nbrp->auth.md5key);
#endif
}
pconn = pending_conn_find(nbr->af, &nbr->raddr);
if (pconn) {
@ -291,10 +286,16 @@ nbr_del(struct nbr *nbr)
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
#ifdef __OpenBSD__
pfkey_remove(nbr);
#else
sock_set_md5sig(
(ldp_af_global_get(&global, nbr->af))->ldp_session_socket,
nbr->af, &nbr->raddr, NULL);
#endif
if (nbr_pending_connect(nbr))
event_del(&nbr->ev_connect);
THREAD_WRITE_OFF(nbr->ev_connect);
nbr_stop_ktimer(nbr);
nbr_stop_ktimeout(nbr);
nbr_stop_itimeout(nbr);
@ -382,176 +383,168 @@ nbr_session_active_role(struct nbr *nbr)
/* Keepalive timer: timer to send keepalive message to neighbors */
static void
nbr_ktimer(int fd, short event, void *arg)
static int
nbr_ktimer(struct thread *thread)
{
struct nbr *nbr = arg;
struct nbr *nbr = THREAD_ARG(thread);
nbr->keepalive_timer = NULL;
send_keepalive(nbr);
nbr_start_ktimer(nbr);
return (0);
}
static void
nbr_start_ktimer(struct nbr *nbr)
{
struct timeval tv;
int secs;
/* send three keepalives per period */
timerclear(&tv);
tv.tv_sec = (time_t)(nbr->keepalive / KEEPALIVE_PER_PERIOD);
if (evtimer_add(&nbr->keepalive_timer, &tv) == -1)
fatal(__func__);
secs = nbr->keepalive / KEEPALIVE_PER_PERIOD;
THREAD_TIMER_OFF(nbr->keepalive_timer);
nbr->keepalive_timer = thread_add_timer(master, nbr_ktimer, nbr, secs);
}
void
nbr_stop_ktimer(struct nbr *nbr)
{
if (evtimer_pending(&nbr->keepalive_timer, NULL) &&
evtimer_del(&nbr->keepalive_timer) == -1)
fatal(__func__);
THREAD_TIMER_OFF(nbr->keepalive_timer);
}
/* Keepalive timeout: if the nbr hasn't sent keepalive */
static void
nbr_ktimeout(int fd, short event, void *arg)
static int
nbr_ktimeout(struct thread *thread)
{
struct nbr *nbr = arg;
struct nbr *nbr = THREAD_ARG(thread);
nbr->keepalive_timeout = NULL;
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
session_shutdown(nbr, S_KEEPALIVE_TMR, 0, 0);
return (0);
}
static void
nbr_start_ktimeout(struct nbr *nbr)
{
struct timeval tv;
timerclear(&tv);
tv.tv_sec = nbr->keepalive;
if (evtimer_add(&nbr->keepalive_timeout, &tv) == -1)
fatal(__func__);
THREAD_TIMER_OFF(nbr->keepalive_timeout);
nbr->keepalive_timeout = thread_add_timer(master, nbr_ktimeout, nbr,
nbr->keepalive);
}
void
nbr_stop_ktimeout(struct nbr *nbr)
{
if (evtimer_pending(&nbr->keepalive_timeout, NULL) &&
evtimer_del(&nbr->keepalive_timeout) == -1)
fatal(__func__);
THREAD_TIMER_OFF(nbr->keepalive_timeout);
}
/* Session initialization timeout: if nbr got stuck in the initialization FSM */
static void
nbr_itimeout(int fd, short event, void *arg)
static int
nbr_itimeout(struct thread *thread)
{
struct nbr *nbr = arg;
struct nbr *nbr = THREAD_ARG(thread);
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
return (0);
}
static void
nbr_start_itimeout(struct nbr *nbr)
{
struct timeval tv;
int secs;
timerclear(&tv);
tv.tv_sec = INIT_FSM_TIMEOUT;
if (evtimer_add(&nbr->init_timeout, &tv) == -1)
fatal(__func__);
secs = INIT_FSM_TIMEOUT;
THREAD_TIMER_OFF(nbr->init_timeout);
nbr->init_timeout = thread_add_timer(master, nbr_itimeout, nbr, secs);
}
void
nbr_stop_itimeout(struct nbr *nbr)
{
if (evtimer_pending(&nbr->init_timeout, NULL) &&
evtimer_del(&nbr->init_timeout) == -1)
fatal(__func__);
THREAD_TIMER_OFF(nbr->init_timeout);
}
/* Init delay timer: timer to retry to iniziatize session */
static void
nbr_idtimer(int fd, short event, void *arg)
static int
nbr_idtimer(struct thread *thread)
{
struct nbr *nbr = arg;
struct nbr *nbr = THREAD_ARG(thread);
nbr->initdelay_timer = NULL;
log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));
nbr_establish_connection(nbr);
return (0);
}
void
nbr_start_idtimer(struct nbr *nbr)
{
struct timeval tv;
int secs;
timerclear(&tv);
tv.tv_sec = INIT_DELAY_TMR;
secs = INIT_DELAY_TMR;
switch(nbr->idtimer_cnt) {
default:
/* do not further increase the counter */
tv.tv_sec = MAX_DELAY_TMR;
secs = MAX_DELAY_TMR;
break;
case 2:
tv.tv_sec *= 2;
secs *= 2;
/* FALLTHROUGH */
case 1:
tv.tv_sec *= 2;
secs *= 2;
/* FALLTHROUGH */
case 0:
nbr->idtimer_cnt++;
break;
}
if (evtimer_add(&nbr->initdelay_timer, &tv) == -1)
fatal(__func__);
THREAD_TIMER_OFF(nbr->initdelay_timer);
nbr->initdelay_timer = thread_add_timer(master, nbr_idtimer, nbr, secs);
}
void
nbr_stop_idtimer(struct nbr *nbr)
{
if (evtimer_pending(&nbr->initdelay_timer, NULL) &&
evtimer_del(&nbr->initdelay_timer) == -1)
fatal(__func__);
THREAD_TIMER_OFF(nbr->initdelay_timer);
}
int
nbr_pending_idtimer(struct nbr *nbr)
{
if (evtimer_pending(&nbr->initdelay_timer, NULL))
return (1);
return (0);
return (nbr->initdelay_timer != NULL);
}
int
nbr_pending_connect(struct nbr *nbr)
{
if (event_initialized(&nbr->ev_connect) &&
event_pending(&nbr->ev_connect, EV_WRITE, NULL))
return (1);
return (0);
return (nbr->ev_connect != NULL);
}
static void
nbr_connect_cb(int fd, short event, void *arg)
static int
nbr_connect_cb(struct thread *thread)
{
struct nbr *nbr = arg;
struct nbr *nbr = THREAD_ARG(thread);
int error;
socklen_t len;
nbr->ev_connect = NULL;
len = sizeof(error);
if (getsockopt(nbr->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__);
return;
return (0);
}
if (error) {
@ -559,10 +552,12 @@ nbr_connect_cb(int fd, short event, void *arg)
errno = error;
log_debug("%s: error while connecting to %s: %s", __func__,
log_addr(nbr->af, &nbr->raddr), strerror(errno));
return;
return (0);
}
nbr_fsm(nbr, NBR_EVT_CONNECT_UP);
return (0);
}
int
@ -572,17 +567,20 @@ nbr_establish_connection(struct nbr *nbr)
struct sockaddr_storage remote_sa;
struct adj *adj;
struct nbr_params *nbrp;
#ifdef __OpenBSD__
int opt = 1;
#endif
nbr->fd = socket(nbr->af,
SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
nbr->fd = socket(nbr->af, SOCK_STREAM, 0);
if (nbr->fd == -1) {
log_warn("%s: error while creating socket", __func__);
return (-1);
}
sock_set_nonblock(nbr->fd);
nbrp = nbr_params_find(leconf, nbr->id);
if (nbrp && nbrp->auth.method == AUTH_MD5SIG) {
#ifdef __OpenBSD__
if (sysdep.no_pfkey || sysdep.no_md5sig) {
log_warnx("md5sig configured but not available");
close(nbr->fd);
@ -594,6 +592,10 @@ nbr_establish_connection(struct nbr *nbr)
close(nbr->fd);
return (-1);
}
#else
sock_set_md5sig(nbr->fd, nbr->af, &nbr->raddr,
nbrp->auth.md5key);
#endif
}
memcpy(&local_sa, addr2sa(nbr->af, &nbr->laddr, 0), sizeof(local_sa));
@ -603,7 +605,7 @@ nbr_establish_connection(struct nbr *nbr)
addscope((struct sockaddr_in6 *)&remote_sa, nbr->raddr_scope);
if (bind(nbr->fd, (struct sockaddr *)&local_sa,
local_sa.ss_len) == -1) {
sockaddr_len((struct sockaddr *)&local_sa)) == -1) {
log_warn("%s: error while binding socket to %s", __func__,
log_sockaddr((struct sockaddr *)&local_sa));
close(nbr->fd);
@ -624,11 +626,10 @@ nbr_establish_connection(struct nbr *nbr)
adj->source.target);
if (connect(nbr->fd, (struct sockaddr *)&remote_sa,
remote_sa.ss_len) == -1) {
sockaddr_len((struct sockaddr *)&remote_sa)) == -1) {
if (errno == EINPROGRESS) {
event_set(&nbr->ev_connect, nbr->fd, EV_WRITE,
nbr_connect_cb, nbr);
event_add(&nbr->ev_connect, NULL);
THREAD_WRITE_ON(master, nbr->ev_connect, nbr_connect_cb,
nbr, nbr->fd);
return (0);
}
log_warn("%s: error while connecting to %s", __func__,
@ -682,8 +683,8 @@ nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp)
return (-1);
break;
case AF_INET6:
if (sock_set_ipv6_minhopcount(fd, ttl) == -1)
return (-1);
/* ignore any possible error */
sock_set_ipv6_minhopcount(fd, ttl);
ttl = 255;
if (sock_set_ipv6_ucast_hops(fd, ttl) == -1)
return (-1);
@ -798,7 +799,10 @@ nbr_to_ctl(struct nbr *nbr)
nctl.af = nbr->af;
nctl.id = nbr->id;
nctl.laddr = nbr->laddr;
nctl.lport = nbr->tcp->lport;
nctl.raddr = nbr->raddr;
nctl.rport = nbr->tcp->rport;
nctl.holdtime = nbr->keepalive;
nctl.nbr_state = nbr->state;
gettimeofday(&now, NULL);

View file

@ -16,14 +16,13 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldp.h"
#include "log.h"
#include "ldpe.h"
#include "ldp_debug.h"
void
send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
@ -65,7 +64,7 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)
}
if (tcp->nbr)
log_debug("msg-out: notification: lsr-id %s, status %s%s",
debug_msg_send("notification: lsr-id %s status %s%s",
inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code),
(nm->status_code & STATUS_FATAL) ? " (fatal)" : "");
@ -199,8 +198,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)
}
}
log_warnx("msg-in: notification: lsr-id %s, status %s%s",
inet_ntoa(nbr->id), status_code_name(ntohl(st.status_code)),
debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id),
status_code_name(ntohl(st.status_code)),
(st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : "");
if (st.status_code & htonl(STATUS_FATAL)) {

View file

@ -18,28 +18,22 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <net/if_dl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "sockopt.h"
static struct iface *disc_find_iface(unsigned int, int,
union ldpd_addr *, int);
static void session_read(int, short, void *);
static void session_write(int, short, void *);
static int session_read(struct thread *);
static int session_write(struct thread *);
static ssize_t session_get_pdu(struct ibuf_read *, char **);
static void tcp_close(struct tcp_conn *);
static struct pending_conn *pending_conn_new(int, int, union ldpd_addr *);
static void pending_conn_timeout(int, short, void *);
static int pending_conn_timeout(struct thread *);
int
gen_ldp_hdr(struct ibuf *buf, uint16_t size)
@ -50,7 +44,7 @@ gen_ldp_hdr(struct ibuf *buf, uint16_t size)
ldp_hdr.version = htons(LDP_VERSION);
/* exclude the 'Version' and 'PDU Length' fields from the total */
ldp_hdr.length = htons(size - LDP_HDR_DEAD_LEN);
ldp_hdr.lsr_id = leconf->rtr_id.s_addr;
ldp_hdr.lsr_id = ldp_rtr_id_get(leconf);
ldp_hdr.lspace_id = 0;
return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE));
@ -104,7 +98,7 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia,
}
sa = addr2sa(af, dst, LDP_PORT);
if (sendto(fd, pkt, len, 0, sa, sa->sa_len) == -1) {
if (sendto(fd, pkt, len, 0, sa, sockaddr_len(sa)) == -1) {
log_warn("%s: error sending packet to %s", __func__,
log_sockaddr(sa));
return (-1);
@ -114,19 +108,27 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia,
}
/* Discovery functions */
#define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo))
void
disc_recv_packet(int fd, short event, void *bula)
int
disc_recv_packet(struct thread *thread)
{
int fd = THREAD_FD(thread);
struct thread **threadp = THREAD_ARG(thread);
union {
struct cmsghdr hdr;
char buf[CMSG_SPACE(CMSG_MAXLEN)];
#ifdef HAVE_STRUCT_SOCKADDR_DL
char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))];
#else
char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
#endif
} cmsgbuf;
struct msghdr m;
struct sockaddr_storage from;
struct iovec iov;
char *buf;
#ifndef MSG_MCAST
struct cmsghdr *cmsg;
#endif
ssize_t r;
int multicast;
int af;
@ -140,8 +142,8 @@ disc_recv_packet(int fd, short event, void *bula)
uint16_t msg_len;
struct in_addr lsr_id;
if (event != EV_READ)
return;
/* reschedule read */
*threadp = thread_add_read(master, disc_recv_packet, threadp, fd);
/* setup buffer */
memset(&m, 0, sizeof(m));
@ -158,44 +160,68 @@ disc_recv_packet(int fd, short event, void *bula)
if (errno != EAGAIN && errno != EINTR)
log_debug("%s: read error: %s", __func__,
strerror(errno));
return;
return (0);
}
sa2addr((struct sockaddr *)&from, &af, &src, NULL);
#ifdef MSG_MCAST
multicast = (m.msg_flags & MSG_MCAST) ? 1 : 0;
sa2addr((struct sockaddr *)&from, &af, &src);
#else
multicast = 0;
for (cmsg = CMSG_FIRSTHDR(&m); cmsg != NULL;
cmsg = CMSG_NXTHDR(&m, cmsg)) {
#if defined(HAVE_IP_PKTINFO)
if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_PKTINFO) {
struct in_pktinfo *pktinfo;
pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
if (IN_MULTICAST(ntohl(pktinfo->ipi_addr.s_addr)))
multicast = 1;
break;
}
#elif defined(HAVE_IP_RECVDSTADDR)
if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_RECVDSTADDR) {
struct in_addr *addr;
addr = (struct in_addr *)CMSG_DATA(cmsg);
if (IN_MULTICAST(ntohl(addr->s_addr)))
multicast = 1;
break;
}
#else
#error "Unsupported socket API"
#endif
if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo *pktinfo;
pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
if (IN6_IS_ADDR_MULTICAST(&pktinfo->ipi6_addr))
multicast = 1;
break;
}
}
#endif /* MSG_MCAST */
if (bad_addr(af, &src)) {
log_debug("%s: invalid source address: %s", __func__,
log_addr(af, &src));
return;
}
for (cmsg = CMSG_FIRSTHDR(&m); cmsg != NULL;
cmsg = CMSG_NXTHDR(&m, cmsg)) {
if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_RECVIF) {
ifindex = ((struct sockaddr_dl *)
CMSG_DATA(cmsg))->sdl_index;
break;
}
if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&
cmsg->cmsg_type == IPV6_PKTINFO) {
ifindex = ((struct in6_pktinfo *)
CMSG_DATA(cmsg))->ipi6_ifindex;
break;
}
return (0);
}
ifindex = getsockopt_ifindex(af, &m);
/* find a matching interface */
iface = disc_find_iface(ifindex, af, &src, multicast);
if (iface == NULL)
return;
return (0);
/* check packet size */
len = (uint16_t)r;
if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) {
log_debug("%s: bad packet size, source %s", __func__,
log_addr(af, &src));
return;
return (0);
}
/* LDP header sanity checks */
@ -203,12 +229,12 @@ disc_recv_packet(int fd, short event, void *bula)
if (ntohs(ldp_hdr.version) != LDP_VERSION) {
log_debug("%s: invalid LDP version %d, source %s", __func__,
ntohs(ldp_hdr.version), log_addr(af, &src));
return;
return (0);
}
if (ntohs(ldp_hdr.lspace_id) != 0) {
log_debug("%s: invalid label space %u, source %s", __func__,
ntohs(ldp_hdr.lspace_id), log_addr(af, &src));
return;
return (0);
}
/* check "PDU Length" field */
pdu_len = ntohs(ldp_hdr.length);
@ -216,7 +242,7 @@ disc_recv_packet(int fd, short event, void *bula)
(pdu_len > (len - LDP_HDR_DEAD_LEN))) {
log_debug("%s: invalid LDP packet length %u, source %s",
__func__, ntohs(ldp_hdr.length), log_addr(af, &src));
return;
return (0);
}
buf += LDP_HDR_SIZE;
len -= LDP_HDR_SIZE;
@ -235,7 +261,7 @@ disc_recv_packet(int fd, short event, void *bula)
if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) {
log_debug("%s: invalid LDP message length %u, source %s",
__func__, ntohs(msg.length), log_addr(af, &src));
return;
return (0);
}
buf += LDP_MSG_SIZE;
len -= LDP_MSG_SIZE;
@ -249,6 +275,8 @@ disc_recv_packet(int fd, short event, void *bula)
log_debug("%s: unknown LDP packet type, source %s", __func__,
log_addr(af, &src));
}
return (0);
}
static struct iface *
@ -306,9 +334,10 @@ disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src,
return (NULL);
}
void
session_accept(int fd, short event, void *bula)
int
session_accept(struct thread *thread)
{
int fd = THREAD_FD(thread);
struct sockaddr_storage src;
socklen_t len = sizeof(src);
int newfd;
@ -317,11 +346,7 @@ session_accept(int fd, short event, void *bula)
struct nbr *nbr;
struct pending_conn *pconn;
if (!(event & EV_READ))
return;
newfd = accept4(fd, (struct sockaddr *)&src, &len,
SOCK_NONBLOCK | SOCK_CLOEXEC);
newfd = accept(fd, (struct sockaddr *)&src, &len);
if (newfd == -1) {
/*
* Pause accept if we are out of file descriptors, or
@ -333,10 +358,11 @@ session_accept(int fd, short event, void *bula)
errno != ECONNABORTED)
log_debug("%s: accept error: %s", __func__,
strerror(errno));
return;
return (0);
}
sock_set_nonblock(newfd);
sa2addr((struct sockaddr *)&src, &af, &addr);
sa2addr((struct sockaddr *)&src, &af, &addr, NULL);
/*
* Since we don't support label spaces, we can identify this neighbor
@ -361,26 +387,29 @@ session_accept(int fd, short event, void *bula)
close(newfd);
else
pending_conn_new(newfd, af, &addr);
return;
return (0);
}
/* protection against buggy implementations */
if (nbr_session_active_role(nbr)) {
close(newfd);
return;
return (0);
}
if (nbr->state != NBR_STA_PRESENT) {
log_debug("%s: lsr-id %s: rejecting additional transport "
"connection", __func__, inet_ntoa(nbr->id));
close(newfd);
return;
return (0);
}
session_accept_nbr(nbr, newfd);
return (0);
}
void
session_accept_nbr(struct nbr *nbr, int fd)
{
#ifdef __OpenBSD__
struct nbr_params *nbrp;
int opt;
socklen_t len;
@ -407,41 +436,42 @@ session_accept_nbr(struct nbr *nbr, int fd)
return;
}
}
#endif
nbr->tcp = tcp_new(fd, nbr);
nbr_fsm(nbr, NBR_EVT_MATCH_ADJ);
}
static void
session_read(int fd, short event, void *arg)
static int
session_read(struct thread *thread)
{
struct nbr *nbr = arg;
int fd = THREAD_FD(thread);
struct nbr *nbr = THREAD_ARG(thread);
struct tcp_conn *tcp = nbr->tcp;
struct ldp_hdr *ldp_hdr;
struct ldp_msg *msg;
char *buf, *pdu;
char *buf = NULL, *pdu;
ssize_t n, len;
uint16_t pdu_len, msg_len, msg_size, max_pdu_len;
int ret;
if (event != EV_READ)
return;
tcp->rev = thread_add_read(master, session_read, nbr, fd);
if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos,
sizeof(tcp->rbuf->buf) - tcp->rbuf->wpos)) == -1) {
if (errno != EINTR && errno != EAGAIN) {
log_warn("%s: read error", __func__);
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
return;
return (0);
}
/* retry read */
return;
return (0);
}
if (n == 0) {
/* connection closed */
log_debug("%s: connection closed by remote end", __func__);
nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION);
return;
return (0);
}
tcp->rbuf->wpos += n;
@ -451,7 +481,7 @@ session_read(int fd, short event, void *arg)
if (ntohs(ldp_hdr->version) != LDP_VERSION) {
session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0);
free(buf);
return;
return (0);
}
pdu_len = ntohs(ldp_hdr->length);
@ -468,14 +498,14 @@ session_read(int fd, short event, void *arg)
pdu_len > max_pdu_len) {
session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);
free(buf);
return;
return (0);
}
pdu_len -= LDP_HDR_PDU_LEN;
if (ldp_hdr->lsr_id != nbr->id.s_addr ||
ldp_hdr->lspace_id != 0) {
session_shutdown(nbr, S_BAD_LDP_ID, 0, 0);
free(buf);
return;
return (0);
}
pdu += LDP_HDR_SIZE;
len -= LDP_HDR_SIZE;
@ -493,7 +523,7 @@ session_read(int fd, short event, void *arg)
session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,
msg->type);
free(buf);
return;
return (0);
}
msg_size = msg_len + LDP_MSG_DEAD_LEN;
pdu_len -= msg_size;
@ -506,7 +536,7 @@ session_read(int fd, short event, void *arg)
session_shutdown(nbr, S_SHUTDOWN,
msg->id, msg->type);
free(buf);
return;
return (0);
}
break;
case MSG_TYPE_KEEPALIVE:
@ -515,7 +545,7 @@ session_read(int fd, short event, void *arg)
session_shutdown(nbr, S_SHUTDOWN,
msg->id, msg->type);
free(buf);
return;
return (0);
}
break;
case MSG_TYPE_ADDR:
@ -529,7 +559,7 @@ session_read(int fd, short event, void *arg)
session_shutdown(nbr, S_SHUTDOWN,
msg->id, msg->type);
free(buf);
return;
return (0);
}
break;
default:
@ -573,7 +603,7 @@ session_read(int fd, short event, void *arg)
if (ret == -1) {
/* parser failed, giving up */
free(buf);
return;
return (0);
}
/* Analyse the next message */
@ -583,19 +613,20 @@ session_read(int fd, short event, void *arg)
free(buf);
if (len != 0) {
session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);
return;
return (0);
}
}
return (0);
}
static void
session_write(int fd, short event, void *arg)
static int
session_write(struct thread *thread)
{
struct tcp_conn *tcp = arg;
struct tcp_conn *tcp = THREAD_ARG(thread);
struct nbr *nbr = tcp->nbr;
if (!(event & EV_WRITE))
return;
tcp->wbuf.ev = NULL;
if (msgbuf_write(&tcp->wbuf.wbuf) <= 0)
if (errno != EAGAIN && nbr)
@ -607,10 +638,12 @@ session_write(int fd, short event, void *arg)
* close the socket.
*/
tcp_close(tcp);
return;
return (0);
}
evbuf_event_add(&tcp->wbuf);
return (0);
}
void
@ -620,7 +653,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,
switch (nbr->state) {
case NBR_STA_PRESENT:
if (nbr_pending_connect(nbr))
event_del(&nbr->ev_connect);
THREAD_WRITE_OFF(nbr->ev_connect);
break;
case NBR_STA_INITIAL:
case NBR_STA_OPENREC:
@ -681,7 +714,9 @@ session_get_pdu(struct ibuf_read *r, char **b)
struct tcp_conn *
tcp_new(int fd, struct nbr *nbr)
{
struct tcp_conn *tcp;
struct tcp_conn *tcp;
struct sockaddr_storage src;
socklen_t len = sizeof(src);
if ((tcp = calloc(1, sizeof(*tcp))) == NULL)
fatal(__func__);
@ -693,12 +728,15 @@ tcp_new(int fd, struct nbr *nbr)
if ((tcp->rbuf = calloc(1, sizeof(struct ibuf_read))) == NULL)
fatal(__func__);
event_set(&tcp->rev, tcp->fd, EV_READ | EV_PERSIST,
session_read, nbr);
event_add(&tcp->rev, NULL);
tcp->rev = thread_add_read(master, session_read, nbr, tcp->fd);
tcp->nbr = nbr;
}
getsockname(fd, (struct sockaddr *)&src, &len);
sa2addr((struct sockaddr *)&src, NULL, NULL, &tcp->lport);
getpeername(fd, (struct sockaddr *)&src, &len);
sa2addr((struct sockaddr *)&src, NULL, NULL, &tcp->rport);
return (tcp);
}
@ -710,7 +748,7 @@ tcp_close(struct tcp_conn *tcp)
evbuf_clear(&tcp->wbuf);
if (tcp->nbr) {
event_del(&tcp->rev);
THREAD_READ_OFF(tcp->rev);
free(tcp->rbuf);
tcp->nbr->tcp = NULL;
}
@ -724,7 +762,6 @@ static struct pending_conn *
pending_conn_new(int fd, int af, union ldpd_addr *addr)
{
struct pending_conn *pconn;
struct timeval tv;
if ((pconn = calloc(1, sizeof(*pconn))) == NULL)
fatal(__func__);
@ -732,13 +769,9 @@ pending_conn_new(int fd, int af, union ldpd_addr *addr)
pconn->fd = fd;
pconn->af = af;
pconn->addr = *addr;
evtimer_set(&pconn->ev_timeout, pending_conn_timeout, pconn);
TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry);
timerclear(&tv);
tv.tv_sec = PENDING_CONN_TIMEOUT;
if (evtimer_add(&pconn->ev_timeout, &tv) == -1)
fatal(__func__);
pconn->ev_timeout = thread_add_timer(master, pending_conn_timeout,
pconn, PENDING_CONN_TIMEOUT);
return (pconn);
}
@ -746,10 +779,7 @@ pending_conn_new(int fd, int af, union ldpd_addr *addr)
void
pending_conn_del(struct pending_conn *pconn)
{
if (evtimer_pending(&pconn->ev_timeout, NULL) &&
evtimer_del(&pconn->ev_timeout) == -1)
fatal(__func__);
THREAD_TIMER_OFF(pconn->ev_timeout);
TAILQ_REMOVE(&global.pending_conns, pconn, entry);
free(pconn);
}
@ -767,12 +797,14 @@ pending_conn_find(int af, union ldpd_addr *addr)
return (NULL);
}
static void
pending_conn_timeout(int fd, short event, void *arg)
static int
pending_conn_timeout(struct thread *thread)
{
struct pending_conn *pconn = arg;
struct pending_conn *pconn = THREAD_ARG(thread);
struct tcp_conn *tcp;
pconn->ev_timeout = NULL;
log_debug("%s: no adjacency with remote end: %s", __func__,
log_addr(pconn->af, &pconn->addr));
@ -785,4 +817,6 @@ pending_conn_timeout(int fd, short event, void *arg)
msgbuf_write(&tcp->wbuf.wbuf);
pending_conn_del(pconn);
return (0);
}

View file

@ -17,7 +17,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef __OpenBSD__
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@ -464,3 +466,4 @@ pfkey_init(void)
}
return (fd);
}
#endif /* __OpenBSD__ */

View file

@ -19,25 +19,29 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <zebra.h>
#include "ldpd.h"
#include "ldpe.h"
#include "log.h"
#include "lib/log.h"
#include "privs.h"
#include "sockopt.h"
extern struct zebra_privs_t ldpd_privs;
extern struct zebra_privs_t ldpe_privs;
int
ldp_create_socket(int af, enum socket_type type)
{
int fd, domain, proto;
union ldpd_addr addr;
struct sockaddr_storage local_sa;
#ifdef __OpenBSD__
int opt;
#endif
int save_errno;
/* create socket */
switch (type) {
@ -53,11 +57,13 @@ ldp_create_socket(int af, enum socket_type type)
default:
fatalx("ldp_create_socket: unknown socket type");
}
fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
fd = socket(af, domain, proto);
if (fd == -1) {
log_warn("%s: error creating socket", __func__);
return (-1);
}
sock_set_nonblock(fd);
sockopt_v6only(af, fd);
/* bind to a local address/port */
switch (type) {
@ -72,21 +78,28 @@ ldp_create_socket(int af, enum socket_type type)
addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
sizeof(local_sa));
if (sock_set_bindany(fd, 1) == -1) {
close(fd);
return (-1);
}
/* ignore any possible error */
sock_set_bindany(fd, 1);
break;
}
if (ldpd_privs.change(ZPRIVS_RAISE))
log_warn("%s: could not raise privs", __func__);
if (sock_set_reuse(fd, 1) == -1) {
close(fd);
return (-1);
}
if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) {
log_warn("%s: error binding socket", __func__);
if (bind(fd, (struct sockaddr *)&local_sa,
sockaddr_len((struct sockaddr *)&local_sa)) == -1) {
save_errno = errno;
if (ldpd_privs.change(ZPRIVS_LOWER))
log_warn("%s: could not lower privs", __func__);
log_warnx("%s: error binding socket: %s", __func__,
safe_strerror(save_errno));
close(fd);
return (-1);
}
if (ldpd_privs.change(ZPRIVS_LOWER))
log_warn("%s: could not lower privs", __func__);
/* set options */
switch (af) {
@ -111,6 +124,21 @@ ldp_create_socket(int af, enum socket_type type)
close(fd);
return (-1);
}
#ifndef MSG_MCAST
#if defined(HAVE_IP_PKTINFO)
if (sock_set_ipv4_pktinfo(fd, 1) == -1) {
close(fd);
return (-1);
}
#elif defined(HAVE_IP_RECVDSTADDR)
if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) {
close(fd);
return (-1);
}
#else
#error "Unsupported socket API"
#endif
#endif /* MSG_MCAST */
}
if (type == LDP_SOCKET_SESSION) {
if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
@ -134,10 +162,8 @@ ldp_create_socket(int af, enum socket_type type)
return (-1);
}
if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
if (sock_set_ipv6_minhopcount(fd, 255) == -1) {
close(fd);
return (-1);
}
/* ignore any possible error */
sock_set_ipv6_minhopcount(fd, 255);
}
}
if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
@ -163,6 +189,7 @@ ldp_create_socket(int af, enum socket_type type)
if (listen(fd, LDP_BACKLOG) == -1)
log_warn("%s: error listening on socket", __func__);
#ifdef __OpenBSD__
opt = 1;
if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,
sizeof(opt)) == -1) {
@ -174,12 +201,41 @@ ldp_create_socket(int af, enum socket_type type)
return (-1);
}
}
#endif
break;
}
return (fd);
}
void
sock_set_nonblock(int fd)
{
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
fatal("fcntl F_GETFL");
flags |= O_NONBLOCK;
if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
fatal("fcntl F_SETFL");
}
void
sock_set_cloexec(int fd)
{
int flags;
if ((flags = fcntl(fd, F_GETFD, 0)) == -1)
fatal("fcntl F_GETFD");
flags |= FD_CLOEXEC;
if ((flags = fcntl(fd, F_SETFD, flags)) == -1)
fatal("fcntl F_SETFD");
}
void
sock_set_recvbuf(int fd)
{
@ -206,15 +262,68 @@ sock_set_reuse(int fd, int enable)
int
sock_set_bindany(int fd, int enable)
{
#ifdef HAVE_SO_BINDANY
if (ldpd_privs.change(ZPRIVS_RAISE))
log_warn("%s: could not raise privs", __func__);
if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
sizeof(int)) < 0) {
if (ldpd_privs.change(ZPRIVS_LOWER))
log_warn("%s: could not lower privs", __func__);
log_warn("%s: error setting SO_BINDANY", __func__);
return (-1);
}
if (ldpd_privs.change(ZPRIVS_LOWER))
log_warn("%s: could not lower privs", __func__);
return (0);
#elif defined(HAVE_IP_FREEBIND)
if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) {
log_warn("%s: error setting IP_FREEBIND", __func__);
return (-1);
}
return (0);
#else
log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind "
"to a nonlocal IP address", __func__);
return (-1);
#endif /* HAVE_SO_BINDANY */
}
#ifndef __OpenBSD__
/*
* Set MD5 key for the socket, for the given peer address. If the password
* is NULL or zero-length, the option will be disabled.
*/
int
sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
{
int ret = -1;
int save_errno = ENOSYS;
#if HAVE_DECL_TCP_MD5SIG
union sockunion su;
#endif
if (fd == -1)
return (0);
#if HAVE_DECL_TCP_MD5SIG
memcpy(&su, addr2sa(af, addr, 0), sizeof(su));
if (ldpe_privs.change(ZPRIVS_RAISE)) {
log_warn("%s: could not raise privs", __func__);
return (-1);
}
ret = sockopt_tcp_signature(fd, &su, password);
save_errno = errno;
if (ldpe_privs.change(ZPRIVS_LOWER))
log_warn("%s: could not lower privs", __func__);
#endif /* HAVE_TCP_MD5SIG */
if (ret < 0)
log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
__func__, fd, safe_strerror(save_errno));
return (ret);
}
#endif
int
sock_set_ipv4_tos(int fd, int tos)
{
@ -229,23 +338,13 @@ sock_set_ipv4_tos(int fd, int tos)
int
sock_set_ipv4_recvif(int fd, int enable)
{
if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
sizeof(enable)) < 0) {
log_warn("%s: error setting IP_RECVIF", __func__);
return (-1);
}
return (0);
return (setsockopt_ifindex(AF_INET, fd, enable));
}
int
sock_set_ipv4_minttl(int fd, int ttl)
{
if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) {
log_warn("%s: error setting IP_MINTTL", __func__);
return (-1);
}
return (0);
return (sockopt_minttl(AF_INET, fd, ttl));
}
int
@ -272,15 +371,45 @@ sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
return (0);
}
#ifndef MSG_MCAST
#if defined(HAVE_IP_PKTINFO)
int
sock_set_ipv4_pktinfo(int fd, int enable)
{
if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable,
sizeof(enable)) < 0) {
log_warn("%s: error setting IP_PKTINFO", __func__);
return (-1);
}
return (0);
}
#elif defined(HAVE_IP_RECVDSTADDR)
int
sock_set_ipv4_recvdstaddr(int fd, int enable)
{
if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable,
sizeof(enable)) < 0) {
log_warn("%s: error setting IP_RECVDSTADDR", __func__);
return (-1);
}
return (0);
}
#else
#error "Unsupported socket API"
#endif
#endif /* MSG_MCAST */
int
sock_set_ipv4_mcast(struct iface *iface)
{
in_addr_t addr;
struct in_addr if_addr;
addr = if_get_ipv4_addr(iface);
if_addr.s_addr = if_get_ipv4_addr(iface);
if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
&addr, sizeof(addr)) < 0) {
if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket,
if_addr, iface->ifindex) < 0) {
log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
__func__, iface->name);
return (-1);
@ -330,13 +459,7 @@ sock_set_ipv6_pktinfo(int fd, int enable)
int
sock_set_ipv6_minhopcount(int fd, int hoplimit)
{
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
&hoplimit, sizeof(hoplimit)) < 0) {
log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
return (-1);
}
return (0);
return (sockopt_minttl(AF_INET6, fd, hoplimit));
}
int

View file

@ -19,8 +19,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
#include <zebra.h>
#include "ldpd.h"
#include "log.h"
@ -44,7 +43,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_in6)
* the possibly truncated sin6_addr struct.
*/
ap = (uint8_t *)&sa_in6->sin6_addr;
ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
ep = (uint8_t *)sa_in6 + sockaddr_len((struct sockaddr *)sa_in6);
for (; ap < ep; ap++) {
/* this "beauty" is adopted from sbin/route/show.c ... */
switch (*ap) {
@ -317,13 +316,17 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port)
switch (af) {
case AF_INET:
sa_in->sin_family = AF_INET;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sa_in->sin_len = sizeof(struct sockaddr_in);
#endif
sa_in->sin_addr = addr->v4;
sa_in->sin_port = htons(port);
break;
case AF_INET6:
sa_in6->sin6_family = AF_INET6;
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
sa_in6->sin6_len = sizeof(struct sockaddr_in6);
#endif
sa_in6->sin6_addr = addr->v6;
sa_in6->sin6_port = htons(port);
break;
@ -335,22 +338,48 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port)
}
void
sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr)
sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr, in_port_t *port)
{
struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
memset(addr, 0, sizeof(*addr));
if (addr)
memset(addr, 0, sizeof(*addr));
switch (sa->sa_family) {
case AF_INET:
*af = AF_INET;
addr->v4 = sa_in->sin_addr;
if (af)
*af = AF_INET;
if (addr)
addr->v4 = sa_in->sin_addr;
if (port)
*port = sa_in->sin_port;
break;
case AF_INET6:
*af = AF_INET6;
addr->v6 = sa_in6->sin6_addr;
if (af)
*af = AF_INET6;
if (addr)
addr->v6 = sa_in6->sin6_addr;
if (port)
*port = sa_in6->sin6_port;
break;
default:
fatalx("sa2addr: unknown af");
}
}
socklen_t
sockaddr_len(struct sockaddr *sa)
{
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
return (sa->sa_len);
#else
switch (sa->sa_family) {
case AF_INET:
return (sizeof(struct sockaddr_in));
case AF_INET6:
return (sizeof(struct sockaddr_in6));
default:
fatalx("sockaddr_len: unknown af");
}
#endif
}

View file

@ -14,7 +14,8 @@ libzebra_la_SOURCES = \
filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \
ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c
ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \
imsg-buffer.c imsg.c
BUILT_SOURCES = route_types.h gitversion.h
@ -31,7 +32,7 @@ pkginclude_HEADERS = \
privs.h sigevent.h pqueue.h jhash.h zassert.h \
workqueue.h route_types.h libospf.h nexthop.h json.h \
ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
fifo.h memory_vty.h
fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h
noinst_HEADERS = \
plist_int.h

View file

@ -2550,6 +2550,19 @@ node_parent ( enum node_type node )
case LINK_PARAMS_NODE:
ret = INTERFACE_NODE;
break;
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
ret = LDP_NODE;
break;
case LDP_IPV4_IFACE_NODE:
ret = LDP_IPV4_NODE;
break;
case LDP_IPV6_IFACE_NODE:
ret = LDP_IPV6_NODE;
break;
case LDP_PSEUDOWIRE_NODE:
ret = LDP_L2VPN_NODE;
break;
default:
ret = CONFIG_NODE;
break;
@ -2920,6 +2933,8 @@ DEFUN (config_exit,
case RIPNG_NODE:
case OSPF_NODE:
case OSPF6_NODE:
case LDP_NODE:
case LDP_L2VPN_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case MASC_NODE:
@ -2938,6 +2953,19 @@ DEFUN (config_exit,
case BGP_IPV6M_NODE:
vty->node = BGP_NODE;
break;
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
vty->node = LDP_NODE;
break;
case LDP_IPV4_IFACE_NODE:
vty->node = LDP_IPV4_NODE;
break;
case LDP_IPV6_IFACE_NODE:
vty->node = LDP_IPV6_NODE;
break;
case LDP_PSEUDOWIRE_NODE:
vty->node = LDP_L2VPN_NODE;
break;
case KEYCHAIN_KEY_NODE:
vty->node = KEYCHAIN_NODE;
break;
@ -2988,6 +3016,13 @@ DEFUN (config_end,
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
case LDP_NODE:
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
case LDP_IPV4_IFACE_NODE:
case LDP_IPV6_IFACE_NODE:
case LDP_L2VPN_NODE:
case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:

View file

@ -98,6 +98,13 @@ enum node_type
BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */
OSPF_NODE, /* OSPF protocol mode */
OSPF6_NODE, /* OSPF protocol for IPv6 mode */
LDP_NODE, /* LDP protocol mode */
LDP_IPV4_NODE, /* LDP IPv4 address family */
LDP_IPV6_NODE, /* LDP IPv6 address family */
LDP_IPV4_IFACE_NODE, /* LDP IPv4 Interface */
LDP_IPV6_IFACE_NODE, /* LDP IPv6 Interface */
LDP_L2VPN_NODE, /* LDP L2VPN node */
LDP_PSEUDOWIRE_NODE, /* LDP Pseudowire node */
ISIS_NODE, /* ISIS protocol mode */
PIM_NODE, /* PIM protocol mode */
MASC_NODE, /* MASC for multicast. */

View file

@ -16,17 +16,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zebra.h>
#include "openbsd-queue.h"
#include "imsg.h"
int ibuf_realloc(struct ibuf *, size_t);
@ -258,7 +250,7 @@ msgbuf_write(struct msgbuf *msgbuf)
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int *)CMSG_DATA(cmsg) = buf->fd;
memcpy(CMSG_DATA(cmsg), &buf->fd, sizeof(int));
}
again:

View file

@ -16,22 +16,49 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <zebra.h>
#include "openbsd-queue.h"
#include "imsg.h"
int imsg_fd_overhead = 0;
int imsg_get_fd(struct imsgbuf *);
#ifndef __OpenBSD__
/*
* The original code calls getdtablecount() which is OpenBSD specific. Use
* available_fds() from OpenSMTPD instead.
*/
static int
available_fds(unsigned int n)
{
unsigned int i;
int ret, fds[256];
if (n > (sizeof(fds)/sizeof(fds[0])))
return (1);
ret = 0;
for (i = 0; i < n; i++) {
fds[i] = -1;
if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
fds[i] = socket(AF_INET6, SOCK_DGRAM, 0);
if (fds[i] < 0) {
ret = 1;
break;
}
}
}
for (i = 0; i < n && fds[i] >= 0; i++)
close(fds[i]);
return (ret);
}
#endif
void
imsg_init(struct imsgbuf *ibuf, int fd)
{
@ -71,9 +98,14 @@ imsg_read(struct imsgbuf *ibuf)
return (-1);
again:
#ifdef __OpenBSD__
if (getdtablecount() + imsg_fd_overhead +
(int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
>= getdtablesize()) {
#else
if (available_fds(imsg_fd_overhead +
(CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) {
#endif
errno = EAGAIN;
free(ifd);
return (-1);

View file

@ -51,6 +51,7 @@ const char *zlog_proto_names[] =
"OSPF",
"RIPNG",
"OSPF6",
"LDP",
"ISIS",
"PIM",
"MASC",
@ -177,7 +178,7 @@ time_print(FILE *fp, struct timestamp_control *ctl)
/* va_list version of zlog. */
static void
void
vzlog (struct zlog *zl, int priority, const char *format, va_list args)
{
char proto_str[32];

View file

@ -51,6 +51,7 @@ typedef enum
ZLOG_OSPF,
ZLOG_RIPNG,
ZLOG_OSPF6,
ZLOG_LDP,
ZLOG_ISIS,
ZLOG_PIM,
ZLOG_MASC
@ -115,6 +116,7 @@ extern void zlog (struct zlog *zl, int priority, const char *format, ...)
PRINTF_ATTRIBUTE(3, 4);
/* Handy zlog functions. */
extern void vzlog (struct zlog *zl, int priority, const char *format, va_list args);
extern void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);

View file

@ -169,4 +169,13 @@ label2str (mpls_label_t label, char *buf, int len)
return(buf);
}
/* constants used by ldpd */
#define MPLS_LABEL_IPV4NULL 0 /* IPv4 Explicit NULL Label */
#define MPLS_LABEL_RTALERT 1 /* Router Alert Label */
#define MPLS_LABEL_IPV6NULL 2 /* IPv6 Explicit NULL Label */
#define MPLS_LABEL_IMPLNULL 3 /* Implicit NULL Label */
/* MPLS_LABEL_RESERVED 4-15 */ /* Values 4-15 are reserved */
#define MPLS_LABEL_RESERVED_MAX 15
#define MPLS_LABEL_MAX ((1 << 20) - 1)
#endif

View file

@ -250,12 +250,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
exit(1);
}
if ( !zprivs_state.syscaps_p )
{
fprintf (stderr, "privs_init: capabilities enabled, "
"but no capabilities supplied\n");
}
/* we have caps, we have no need to ever change back the original user */
if (zprivs_state.zuid)
{
@ -267,6 +261,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
}
}
if ( !zprivs_state.syscaps_p )
return;
if ( !(zprivs_state.caps = cap_init()) )
{
fprintf (stderr, "privs_init: failed to cap_init, %s\n",

View file

@ -60,6 +60,7 @@ ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM"
ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
ZEBRA_ROUTE_TABLE, table, zebra, 'T', 1, 1, "Table"
ZEBRA_ROUTE_LDP, ldp, ldpd, 'L', 0, 0, "LDP"
## help strings
ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only"
@ -76,3 +77,4 @@ ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)"
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table"
ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"

View file

@ -754,6 +754,13 @@ vty_end_config (struct vty *vty)
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
case LDP_NODE:
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
case LDP_IPV4_IFACE_NODE:
case LDP_IPV6_IFACE_NODE:
case LDP_L2VPN_NODE:
case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
@ -1158,6 +1165,13 @@ vty_stop_input (struct vty *vty)
case RMAP_NODE:
case OSPF_NODE:
case OSPF6_NODE:
case LDP_NODE:
case LDP_IPV4_NODE:
case LDP_IPV6_NODE:
case LDP_IPV4_IFACE_NODE:
case LDP_IPV6_IFACE_NODE:
case LDP_L2VPN_NODE:
case LDP_PSEUDOWIRE_NODE:
case ISIS_NODE:
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
@ -3180,3 +3194,29 @@ vty_terminate (void)
vector_free (Vvty_serv_thread);
}
}
/* Utility functions to get arguments from commands generated
by the xml2cli.pl script. */
const char *
vty_get_arg_value (struct vty_arg *args[], const char *arg)
{
while (*args)
{
if (strcmp ((*args)->name, arg) == 0)
return (*args)->value;
args++;
}
return NULL;
}
struct vty_arg *
vty_get_arg (struct vty_arg *args[], const char *arg)
{
while (*args)
{
if (strcmp ((*args)->name, arg) == 0)
return *args;
args++;
}
return NULL;
}

View file

@ -127,6 +127,14 @@ struct vty
char address[SU_ADDRSTRLEN];
};
struct vty_arg
{
const char *name;
const char *value;
const char **argv;
int argc;
};
/* Integrated configuration file. */
#define INTEGRATE_DEFAULT_CONFIG "Quagga.conf"
@ -292,4 +300,7 @@ extern void vty_hello (struct vty *);
an async-signal-safe function. */
extern void vty_log_fixed (char *buf, size_t len);
extern const char *vty_get_arg_value (struct vty_arg **, const char *);
extern struct vty_arg *vty_get_arg (struct vty_arg **, const char *);
#endif /* _ZEBRA_VTY_H */

436
tools/xml2cli.pl Executable file
View file

@ -0,0 +1,436 @@
#!/usr/bin/perl
##
## Parse a XML file containing a tree-like representation of Quagga CLI
## commands and generate a file with:
##
## - a DEFUN function for each command;
## - an initialization function.
##
##
## Copyright (C) 2012 Renato Westphal <renatow@digistar.com.br>
## This file is part of GNU Zebra.
##
## GNU Zebra is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by the
## Free Software Foundation; either version 2, or (at your option) any
## later version.
##
## GNU Zebra is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
## General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with GNU Zebra; see the file COPYING. If not, write to the Free
## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
## 02111-1307, USA.
##
use strict;
use warnings;
use Getopt::Std;
use vars qw($opt_d);
use File::Basename qw(fileparse);
use XML::LibXML;
%::input_strs = (
"ifname" => "IFNAME",
"word" => "WORD",
"line" => ".LINE",
"ipv4" => "A.B.C.D",
"ipv4m" => "A.B.C.D/M",
"ipv6" => "X:X::X:X",
"ipv6m" => "X:X::X:X/M",
"mtu" => "<1500-9180>",
# BGP specific
"rd" => "ASN:nn_or_IP-address:nn",
"asn" => "<1-4294967295>",
"community" => "AA:NN",
"clist" => "<1-500>",
# LDP specific
"disc_time" => "<1-65535>",
"session_time" => "<15-65535>",
"pwid" => "<1-4294967295>",
"hops" => "<1-254>"
);
# parse options node and store the corresponding information
# into a global hash of hashes
sub parse_options {
my $xml_node = $_[0];
my @cmdstr;
my $options_name = $xml_node->findvalue('./@name');
if (not $options_name) {
die('error: "options" node without "name" attribute');
}
# initialize hash
$::options{$options_name}{'cmdstr'} = "";
$::options{$options_name}{'help'} = "";
my @children = $xml_node->getChildnodes();
foreach my $child(@children) {
# skip comments, random text, etc
if ($child->getType() != XML_ELEMENT_NODE) {
next;
}
# check for error/special conditions
if ($child->getName() ne "option") {
die('error: invalid node type: "' . $child->getName() . '"');
}
my $name = $child->findvalue('./@name');
my $input = $child->findvalue('./@input');
my $help = $child->findvalue('./@help');
if ($input) {
$name = $::input_strs{$input};
}
push (@cmdstr, $name);
$::options{$options_name}{'help'} .= "\n \"" . $help . "\\n\"";
}
$::options{$options_name}{'cmdstr'} = "(" . join('|', @cmdstr) . ")";
}
# given a subtree, replace all the corresponding include nodes by
# this subtree
sub subtree_replace_includes {
my $subtree = $_[0];
my $subtree_name = $subtree->findvalue('./@name');
if (not $subtree_name) {
die("subtree without \"name\" attribute");
}
my $query = "//include[\@subtree='$subtree_name']";
foreach my $include_node($::xml->findnodes($query)) {
my @children = $subtree->getChildnodes();
foreach my $child(reverse @children) {
my $include_node_parent = $include_node->getParentNode();
$include_node_parent->insertAfter($child->cloneNode(1),
$include_node);
}
$include_node->unbindNode();
}
$subtree->unbindNode();
}
# generate arguments for a given command
sub generate_arguments {
my @nodes = @_;
my $arguments;
my $no_args = 1;
my $argc = 0;
$arguments .= " struct vty_arg *args[] =\n";
$arguments .= " {\n";
for (my $i = 0; $i < @nodes; $i++) {
my %node = %{$nodes[$i]};
my $arg_value;
if (not $node{'arg'}) {
next;
}
$no_args = 0;
# for input and select nodes, the value of the argument is an
# argv[] element. for the other types of nodes, the value of the
# argument is the name of the node
if ($node{'input'} or $node{'type'} eq "select") {
$arg_value = "argv[" . $argc++ . "]";
} else {
$arg_value = '"' . $node{'name'} . '"';
}
if ($node{'input'} and $node{'input'} eq "line") {
# arguments of the type 'line' may have multiple spaces (i.e
# they don't fit into a single argv[] element). to properly
# handle these arguments, we need to provide direct access
# to the argv[] array and the argc variable.
my $argc_str = "argc" . (($argc > 1) ? " - " . ($argc - 1) : "");
my $argv_str = "argv" . (($argc > 1) ? " + " . ($argc - 1) : "");
$arguments .= " &(struct vty_arg) { "
. ".name = \"" . $node{'arg'} . "\", "
. ".argc = $argc_str, "
. ".argv = $argv_str },\n";
} else {
# common case - each argument has a name and a single value
$arguments .= " &(struct vty_arg) { "
. ".name = \"" . $node{'arg'} . "\", "
. ".value = " . $arg_value . " },\n";
}
}
$arguments .= " NULL\n";
$arguments .= " };\n";
# handle special case
if ($no_args) {
return " struct vty_arg *args[] = { NULL };\n";
}
return $arguments;
}
# generate C code
sub generate_code {
my @nodes = @_;
my $funcname = '';
my $cmdstr = '';
my $cmdname = '';
my $helpstr = '';
my $function = '';
for (my $i = 0; $i < @nodes; $i++) {
my %node = %{$nodes[$i]};
if ($node{'input'}) {
$funcname .= $node{'input'} . " ";
$cmdstr .= $::input_strs{$node{'input'}} . " ";
$helpstr .= "\n \"" . $node{'help'} . "\\n\"";
} elsif ($node{'type'} eq "select") {
my $options_name = $node{'options'};
$funcname .= $options_name . " ";
$cmdstr .= $::options{$options_name}{'cmdstr'} . " ";
$helpstr .= $::options{$options_name}{'help'};
} else {
$funcname .= $node{'name'} . " ";
$cmdstr .= $node{'name'} . " ";
$helpstr .= "\n \"" . $node{'help'} . "\\n\"";
}
# update the command string
if ($node{'function'} ne "inherited") {
$function = $node{'function'};
}
}
# rtrim
$funcname =~ s/\s+$//;
$cmdstr =~ s/\s+$//;
# lowercase
$funcname = lc($funcname);
# replace " " by "_"
$funcname =~ tr/ /_/;
# replace "-" by "_"
$funcname =~ tr/-/_/;
# add prefix
$funcname = $::cmdprefix . '_' . $funcname;
# generate DEFUN
$cmdname = $funcname . "_cmd";
# don't generate same command more than once
if ($::commands{$cmdname}) {
return $cmdname;
}
$::commands{$cmdname} = "1";
print STDOUT "DEFUN (" . $funcname . ",\n"
. " " . $cmdname . ",\n"
. " \"" . $cmdstr . "\","
. $helpstr . ")\n"
. "{\n"
. generate_arguments(@nodes)
. " return " . $function . " (vty, args);\n"
. "}\n\n";
return $cmdname;
}
# parse tree node (recursive function)
sub parse_tree {
# get args
my $xml_node = $_[0];
my @nodes = @{$_[1]};
my $tree_name = $_[2];
# hash containing all the node attributes
my %node;
$node{'type'} = $xml_node->getName();
# check for error/special conditions
if ($node{'type'} eq "tree") {
goto end;
}
if ($node{'type'} eq "include") {
die('error: can not include "'
. $xml_node->findvalue('./@subtree') . '"');
}
if (not $node{'type'} ~~ [qw(option select)]) {
die('error: invalid node type: "' . $node{'type'} . '"');
}
if ($node{'type'} eq "select") {
my $options_name = $xml_node->findvalue('./@options');
if (not $options_name) {
die('error: "select" node without "name" attribute');
}
if (not $::options{$options_name}) {
die('error: can not find options');
}
$node{'options'} = $options_name;
}
# get node attributes
$node{'name'} = $xml_node->findvalue('./@name');
$node{'input'} = $xml_node->findvalue('./@input');
$node{'arg'} = $xml_node->findvalue('./@arg');
$node{'help'} = $xml_node->findvalue('./@help');
$node{'function'} = $xml_node->findvalue('./@function');
$node{'ifdef'} = $xml_node->findvalue('./@ifdef');
# push node to stack
push (@nodes, \%node);
# generate C code
if ($node{'function'}) {
my $cmdname = generate_code(@nodes);
push (@{$::trees{$tree_name}}, [0, $cmdname, 0]);
}
if ($node{'ifdef'}) {
push (@{$::trees{$tree_name}}, [$node{'ifdef'}, 0, 0]);
}
end:
# recursively process child nodes
my @children = $xml_node->getChildnodes();
foreach my $child(@children) {
# skip comments, random text, etc
if ($child->getType() != XML_ELEMENT_NODE) {
next;
}
parse_tree($child, \@nodes, $tree_name);
}
if ($node{'ifdef'}) {
push (@{$::trees{$tree_name}}, [0, 0, $node{'ifdef'}]);
}
}
sub parse_node {
# get args
my $xml_node = $_[0];
my $node_name = $xml_node->findvalue('./@name');
if (not $node_name) {
die('missing the "name" attribute');
}
my $install = $xml_node->findvalue('./@install');
my $config_write = $xml_node->findvalue('./@config_write');
if ($install and $install eq "1") {
print " install_node (&" .lc( $node_name) . "_node, " . $config_write . ");\n";
}
my $install_default = $xml_node->findvalue('./@install_default');
if ($install_default and $install_default eq "1") {
print " install_default (" . $node_name . "_NODE);\n";
}
my @children = $xml_node->getChildnodes();
foreach my $child(@children) {
# skip comments, random text, etc
if ($child->getType() != XML_ELEMENT_NODE) {
next;
}
if ($child->getName() ne "include") {
die('error: invalid node type: "' . $child->getName() . '"');
}
my $tree_name = $child->findvalue('./@tree');
if (not $tree_name) {
die('missing the "tree" attribute');
}
foreach my $entry (@{$::trees{$tree_name}}) {
my ($ifdef, $cmdname, $endif) = @{$entry};
if ($ifdef) {
print ("#ifdef " . $ifdef . "\n");
}
if ($cmdname) {
print " install_element (" . $node_name . "_NODE, &" . $cmdname . ");\n";
}
if ($endif) {
print ("#endif /* " . $endif . " */\n");
}
}
}
}
# parse command-line arguments
if (not getopts('d')) {
die("Usage: xml2cli.pl [-d] FILE\n");
}
my $file = shift;
# initialize the XML parser
my $parser = new XML::LibXML;
$parser->keep_blanks(0);
# parse XML file
$::xml = $parser->parse_file($file);
my $xmlroot = $::xml->getDocumentElement();
if ($xmlroot->getName() ne "file") {
die('XML root element name must be "file"');
}
# read file attributes
my $init_function = $xmlroot->findvalue('./@init');
if (not $init_function) {
die('missing the "init" attribute in the "file" node');
}
$::cmdprefix = $xmlroot->findvalue('./@cmdprefix');
if (not $::cmdprefix) {
die('missing the "cmdprefix" attribute in the "file" node');
}
my $header = $xmlroot->findvalue('./@header');
if (not $header) {
die('missing the "header" attribute in the "file" node');
}
# generate source header
print STDOUT "/* Auto-generated from " . fileparse($file) . ". */\n"
. "/* Do not edit! */\n\n"
. "#include <zebra.h>\n\n"
. "#include \"command.h\"\n"
. "#include \"vty.h\"\n"
. "#include \"$header\"\n\n";
# Parse options
foreach my $options($::xml->findnodes("/file/options")) {
parse_options($options);
}
# replace include nodes by the corresponding subtrees
foreach my $subtree(reverse $::xml->findnodes("/file/subtree")) {
subtree_replace_includes($subtree);
}
# Parse trees
foreach my $tree($::xml->findnodes("/file/tree")) {
my @nodes = ();
my $tree_name = $tree->findvalue('./@name');
parse_tree($tree, \@nodes, $tree_name);
}
# install function header
print STDOUT "void\n"
. $init_function . " (void)\n"
. "{\n";
# Parse nodes
foreach my $node($::xml->findnodes("/file/node")) {
parse_node($node);
}
# closing braces for the install function
print STDOUT "}";
# print to stderr the expanded XML file if the debug flag (-d) is given
if ($opt_d) {
print STDERR $::xml->toString(1);
}

View file

@ -641,7 +641,7 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
{
/* We don't send any nexthops when there's a multipath */
if (rib->nexthop_active_num > 1)
if (rib->nexthop_active_num > 1 && client->proto != ZEBRA_ROUTE_LDP)
{
SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
@ -713,7 +713,9 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
stream_putc (s, 1);
stream_putl (s, nexthop->ifindex);
break;
/* ldpd needs all nexthops */
if (client->proto != ZEBRA_ROUTE_LDP)
break;
}
}