forked from Mirror/frr
ldpd: adapt the code for Quagga
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
This commit is contained in:
parent
e30090a678
commit
eac6e3f027
|
@ -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
|
||||
|
||||
|
|
43
configure.ac
43
configure.ac
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
681
doc/ldpd-basic-test-setup.md
Normal file
681
doc/ldpd-basic-test-setup.md
Normal 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
109
doc/ldpd.8
Normal 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
18
ldpd/.gitignore
vendored
Normal 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
26
ldpd/Makefile.am
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
35
ldpd/hello.c
35
ldpd/hello.c
|
@ -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);
|
||||
|
|
11
ldpd/init.c
11
ldpd/init.c
|
@ -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);
|
||||
|
|
128
ldpd/interface.c
128
ldpd/interface.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
51
ldpd/l2vpn.c
51
ldpd/l2vpn.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
251
ldpd/lde.c
251
ldpd/lde.c
|
@ -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);
|
||||
}
|
||||
|
|
14
ldpd/lde.h
14
ldpd/lde.h
|
@ -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 *);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
12
ldpd/ldp.h
12
ldpd/ldp.h
|
@ -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
198
ldpd/ldp_debug.c
Normal 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
131
ldpd/ldp_debug.h
Normal 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
81
ldpd/ldp_vty.h
Normal 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
379
ldpd/ldp_vty.xml
Normal 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
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
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
667
ldpd/ldp_vty_exec.c
Normal 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
466
ldpd/ldp_zebra.c
Normal 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;
|
||||
}
|
972
ldpd/ldpd.c
972
ldpd/ldpd.c
File diff suppressed because it is too large
Load diff
46
ldpd/ldpd.conf.sample
Normal file
46
ldpd/ldpd.conf.sample
Normal 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
|
||||
!
|
134
ldpd/ldpd.h
134
ldpd/ldpd.h
|
@ -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_ */
|
||||
|
|
384
ldpd/ldpe.c
384
ldpd/ldpe.c
|
@ -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);
|
||||
}
|
||||
|
|
43
ldpd/ldpe.h
43
ldpd/ldpe.h
|
@ -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 *);
|
||||
|
|
162
ldpd/log.c
162
ldpd/log.c
|
@ -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);
|
||||
}
|
||||
|
|
12
ldpd/log.h
12
ldpd/log.h
|
@ -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_ */
|
||||
|
|
192
ldpd/neighbor.c
192
ldpd/neighbor.c
|
@ -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);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
236
ldpd/packet.c
236
ldpd/packet.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
207
ldpd/socket.c
207
ldpd/socket.c
|
@ -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
|
||||
|
|
47
ldpd/util.c
47
ldpd/util.c
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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:
|
||||
|
|
50
lib/imsg.c
50
lib/imsg.c
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)"
|
||||
|
|
40
lib/vty.c
40
lib/vty.c
|
@ -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;
|
||||
}
|
||||
|
|
11
lib/vty.h
11
lib/vty.h
|
@ -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
436
tools/xml2cli.pl
Executable 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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue