summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rwxr-xr-xconfigure.ac43
-rw-r--r--doc/Makefile.am6
-rw-r--r--doc/ldpd-basic-test-setup.md681
-rw-r--r--doc/ldpd.8109
-rw-r--r--ldpd/.gitignore18
-rw-r--r--ldpd/Makefile.am26
-rw-r--r--ldpd/accept.c55
-rw-r--r--ldpd/address.c13
-rw-r--r--ldpd/adjacency.c84
-rw-r--r--ldpd/control.c96
-rw-r--r--ldpd/control.h3
-rw-r--r--ldpd/hello.c35
-rw-r--r--ldpd/init.c11
-rw-r--r--ldpd/interface.c128
-rw-r--r--ldpd/keepalive.c8
-rw-r--r--ldpd/l2vpn.c51
-rw-r--r--ldpd/labelmapping.c17
-rw-r--r--ldpd/lde.c251
-rw-r--r--ldpd/lde.h14
-rw-r--r--ldpd/lde_lib.c38
-rw-r--r--ldpd/ldp.h12
-rw-r--r--ldpd/ldp_debug.c198
-rw-r--r--ldpd/ldp_debug.h131
-rw-r--r--ldpd/ldp_vty.h81
-rw-r--r--ldpd/ldp_vty.xml379
-rw-r--r--ldpd/ldp_vty_cmds.c1738
-rw-r--r--ldpd/ldp_vty_conf.c1637
-rw-r--r--ldpd/ldp_vty_exec.c667
-rw-r--r--ldpd/ldp_zebra.c466
-rw-r--r--ldpd/ldpd.c966
-rw-r--r--ldpd/ldpd.conf.sample46
-rw-r--r--ldpd/ldpd.h134
-rw-r--r--ldpd/ldpe.c386
-rw-r--r--ldpd/ldpe.h43
-rw-r--r--ldpd/log.c162
-rw-r--r--ldpd/log.h12
-rw-r--r--ldpd/neighbor.c192
-rw-r--r--ldpd/notification.c11
-rw-r--r--ldpd/packet.c224
-rw-r--r--ldpd/pfkey.c3
-rw-r--r--ldpd/socket.c207
-rw-r--r--ldpd/util.c47
-rw-r--r--lib/Makefile.am5
-rw-r--r--lib/command.c35
-rw-r--r--lib/command.h7
-rw-r--r--lib/imsg-buffer.c14
-rw-r--r--lib/imsg.c50
-rw-r--r--lib/log.c3
-rw-r--r--lib/log.h2
-rw-r--r--lib/mpls.h9
-rw-r--r--lib/privs.c9
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/vty.c40
-rw-r--r--lib/vty.h11
-rwxr-xr-xtools/xml2cli.pl436
-rw-r--r--zebra/zserv.c6
57 files changed, 8862 insertions, 1200 deletions
diff --git a/Makefile.am b/Makefile.am
index 1a39844cb..a3cbdc919 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
diff --git a/configure.ac b/configure.ac
index 937d7b8d0..eb1f1de6c 100755
--- a/configure.ac
+++ b/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
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 4a39f0b01..ffb0bf465 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -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 \
diff --git a/doc/ldpd-basic-test-setup.md b/doc/ldpd-basic-test-setup.md
new file mode 100644
index 000000000..e5e987f9e
--- /dev/null
+++ b/doc/ldpd-basic-test-setup.md
@@ -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
+```
diff --git a/doc/ldpd.8 b/doc/ldpd.8
new file mode 100644
index 000000000..092ff39d4
--- /dev/null
+++ b/doc/ldpd.8
@@ -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.
+
diff --git a/ldpd/.gitignore b/ldpd/.gitignore
new file mode 100644
index 000000000..be90d4211
--- /dev/null
+++ b/ldpd/.gitignore
@@ -0,0 +1,18 @@
+Makefile
+Makefile.in
+*.o
+ldpd
+ldpd.conf
+tags
+TAGS
+.deps
+.nfs*
+*.lo
+*.la
+*.a
+*.libs
+.arch-inventory
+.arch-ids
+*~
+*.loT
+
diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am
new file mode 100644
index 000000000..c292adf6f
--- /dev/null
+++ b/ldpd/Makefile.am
@@ -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
diff --git a/ldpd/accept.c b/ldpd/accept.c
index bc13ad49e..4cb461b90 100644
--- a/ldpd/accept.c
+++ b/ldpd/accept.c
@@ -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);
}
diff --git a/ldpd/address.c b/ldpd/address.c
index 5e95fcc27..1c4c116f2 100644
--- a/ldpd/address.c
+++ b/ldpd/address.c
@@ -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));
diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c
index 266717729..3607ee96b 100644
--- a/ldpd/adjacency.c
+++ b/ldpd/adjacency.c
@@ -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 *
diff --git a/ldpd/control.c b/ldpd/control.c
index b7cb3f106..ba303cc12 100644
--- a/ldpd/control.c
+++ b/ldpd/control.c
@@ -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
diff --git a/ldpd/control.h b/ldpd/control.h
index fd6e47071..32c49fdf8 100644
--- a/ldpd/control.h
+++ b/ldpd/control.h
@@ -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;
diff --git a/ldpd/hello.c b/ldpd/hello.c
index d0daed347..755b25aa8 100644
--- a/ldpd/hello.c
+++ b/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);
diff --git a/ldpd/init.c b/ldpd/init.c
index eb22bf52a..ed6b53c02 100644
--- a/ldpd/init.c
+++ b/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);
diff --git a/ldpd/interface.c b/ldpd/interface.c
index ff4c8f169..b6472fe5e 100644
--- a/ldpd/interface.c
+++ b/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);
diff --git a/ldpd/keepalive.c b/ldpd/keepalive.c
index 4cd49d485..f9a7d850f 100644
--- a/ldpd/keepalive.c
+++ b/ldpd/keepalive.c
@@ -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);
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index 22c98745e..db382e484 100644
--- a/ldpd/l2vpn.c
+++ b/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);
}
diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c
index 88e64071b..62f2a620d 100644
--- a/ldpd/labelmapping.c
+++ b/ldpd/labelmapping.c
@@ -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));
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 8859ed25b..ae29ef6a7 100644
--- a/ldpd/lde.c
+++ b/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)
+/* Master of threads. */
+struct thread_master *master;
+
+/* lde privileges */
+static zebra_capabilities_t _caps_p [] =
{
- /*
- * signal handler rules don't apply, libevent decouples for us
- */
+ /* none */
+};
- switch (sig) {
- case SIGINT:
- case SIGTERM:
- lde_shutdown();
- /* NOTREACHED */
- default:
- fatalx("unexpected signal");
- }
+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);
-
- /* setup and start the LIB garbage collector */
- evtimer_set(&gc_timer, lde_gc_timer, 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;
+
+ /* 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);
}
diff --git a/ldpd/lde.h b/ldpd/lde.h
index b0f7b2043..0fce5565a 100644
--- a/ldpd/lde.h
+++ b/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 *);
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index d9c1f544f..568761bd6 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -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);
}
diff --git a/ldpd/ldp.h b/ldpd/ldp.h
index 77034b30a..c421cddc3 100644
--- a/ldpd/ldp.h
+++ b/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
diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c
new file mode 100644
index 000000000..15dd06a0f
--- /dev/null
+++ b/ldpd/ldp_debug.c
@@ -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);
+}
diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h
new file mode 100644
index 000000000..aa0cd47e7
--- /dev/null
+++ b/ldpd/ldp_debug.h
@@ -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_ */
diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h
new file mode 100644
index 000000000..735554bad
--- /dev/null
+++ b/ldpd/ldp_vty.h
@@ -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_ */
diff --git a/ldpd/ldp_vty.xml b/ldpd/ldp_vty.xml
new file mode 100644
index 000000000..8742f9c1b
--- /dev/null
+++ b/ldpd/ldp_vty.xml
@@ -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>
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
new file mode 100644
index 000000000..716083572
--- /dev/null
+++ b/ldpd/ldp_vty_cmds.c
@@ -0,0 +1,1738 @@
+/* Auto-generated from ldp_vty.xml. */
+/* Do not edit! */
+
+#include <zebra.h>
+
+#include "command.h"
+#include "vty.h"
+#include "ldp_vty.h"
+
+DEFUN (ldp_mpls_ldp,
+ ldp_mpls_ldp_cmd,
+ "mpls ldp",
+ "Global MPLS configuration subcommands\n"
+ "Label Distribution Protocol\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_mpls_ldp (vty, args);
+}
+
+DEFUN (ldp_l2vpn_word_type_vpls,
+ ldp_l2vpn_word_type_vpls_cmd,
+ "l2vpn WORD type vpls",
+ "Configure l2vpn commands\n"
+ "L2VPN name\n"
+ "L2VPN type\n"
+ "Virtual Private LAN Service\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "name", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn (vty, args);
+}
+
+DEFUN (ldp_no_mpls_ldp,
+ ldp_no_mpls_ldp_cmd,
+ "no mpls ldp",
+ "Negate a command or set its defaults\n"
+ "Global MPLS configuration subcommands\n"
+ "Label Distribution Protocol\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ NULL
+ };
+ return ldp_vty_mpls_ldp (vty, args);
+}
+
+DEFUN (ldp_no_l2vpn_word_type_vpls,
+ ldp_no_l2vpn_word_type_vpls_cmd,
+ "no l2vpn WORD type vpls",
+ "Negate a command or set its defaults\n"
+ "Configure l2vpn commands\n"
+ "L2VPN name\n"
+ "L2VPN type\n"
+ "Virtual Private LAN Service\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "name", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn (vty, args);
+}
+
+DEFUN (ldp_address_family_ipv4,
+ ldp_address_family_ipv4_cmd,
+ "address-family ipv4",
+ "Configure Address Family and its parameters\n"
+ "IPv4\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "address-family", .value = "ipv4" },
+ NULL
+ };
+ return ldp_vty_address_family (vty, args);
+}
+
+DEFUN (ldp_address_family_ipv6,
+ ldp_address_family_ipv6_cmd,
+ "address-family ipv6",
+ "Configure Address Family and its parameters\n"
+ "IPv6\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "address-family", .value = "ipv6" },
+ NULL
+ };
+ return ldp_vty_address_family (vty, args);
+}
+
+DEFUN (ldp_discovery_hello_holdtime_disc_time,
+ ldp_discovery_hello_holdtime_disc_time_cmd,
+ "discovery hello holdtime <1-65535>",
+ "Configure discovery parameters\n"
+ "LDP Link Hellos\n"
+ "Hello holdtime\n"
+ "Time (seconds) - 65535 implies infinite\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "hello_type", .value = "hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_holdtime (vty, args);
+}
+
+DEFUN (ldp_discovery_hello_interval_disc_time,
+ ldp_discovery_hello_interval_disc_time_cmd,
+ "discovery hello interval <1-65535>",
+ "Configure discovery parameters\n"
+ "LDP Link Hellos\n"
+ "Hello interval\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "hello_type", .value = "hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_interval (vty, args);
+}
+
+DEFUN (ldp_discovery_targeted_hello_holdtime_disc_time,
+ ldp_discovery_targeted_hello_holdtime_disc_time_cmd,
+ "discovery targeted-hello holdtime <1-65535>",
+ "Configure discovery parameters\n"
+ "LDP Targeted Hellos\n"
+ "Targeted hello holdtime\n"
+ "Time (seconds) - 65535 implies infinite\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_holdtime (vty, args);
+}
+
+DEFUN (ldp_discovery_targeted_hello_interval_disc_time,
+ ldp_discovery_targeted_hello_interval_disc_time_cmd,
+ "discovery targeted-hello interval <1-65535>",
+ "Configure discovery parameters\n"
+ "LDP Targeted Hellos\n"
+ "Targeted hello interval\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_interval (vty, args);
+}
+
+DEFUN (ldp_dual_stack_transport_connection_prefer_ipv4,
+ ldp_dual_stack_transport_connection_prefer_ipv4_cmd,
+ "dual-stack transport-connection prefer ipv4",
+ "Configure dual stack parameters\n"
+ "Configure TCP transport parameters\n"
+ "Configure prefered address family for TCP transport connection with neighbor\n"
+ "IPv4\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_trans_pref_ipv4 (vty, args);
+}
+
+DEFUN (ldp_dual_stack_cisco_interop,
+ ldp_dual_stack_cisco_interop_cmd,
+ "dual-stack cisco-interop",
+ "Configure dual stack parameters\n"
+ "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_ds_cisco_interop (vty, args);
+}
+
+DEFUN (ldp_neighbor_ipv4_password_word,
+ ldp_neighbor_ipv4_password_word_cmd,
+ "neighbor A.B.C.D password WORD",
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "Configure password for MD5 authentication\n"
+ "The password\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ &(struct vty_arg) { .name = "password", .value = argv[1] },
+ NULL
+ };
+ return ldp_vty_neighbor_password (vty, args);
+}
+
+DEFUN (ldp_neighbor_ipv4_session_holdtime_session_time,
+ ldp_neighbor_ipv4_session_holdtime_session_time_cmd,
+ "neighbor A.B.C.D session holdtime <15-65535>",
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "Configure session parameters\n"
+ "Configure session holdtime\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ &(struct vty_arg) { .name = "seconds", .value = argv[1] },
+ NULL
+ };
+ return ldp_vty_session_holdtime (vty, args);
+}
+
+DEFUN (ldp_neighbor_ipv4_ttl_security_disable,
+ ldp_neighbor_ipv4_ttl_security_disable_cmd,
+ "neighbor A.B.C.D ttl-security disable",
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "LDP ttl security check\n"
+ "Disable ttl security\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_neighbor_ttl_security (vty, args);
+}
+
+DEFUN (ldp_neighbor_ipv4_ttl_security_hops_hops,
+ ldp_neighbor_ipv4_ttl_security_hops_hops_cmd,
+ "neighbor A.B.C.D ttl-security hops <1-254>",
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "LDP ttl security check\n"
+ "IP hops\n"
+ "maximum number of hops\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ &(struct vty_arg) { .name = "hops", .value = argv[1] },
+ NULL
+ };
+ return ldp_vty_neighbor_ttl_security (vty, args);
+}
+
+DEFUN (ldp_router_id_ipv4,
+ ldp_router_id_ipv4_cmd,
+ "router-id A.B.C.D",
+ "Configure router Id\n"
+ "LSR Id (in form of an IPv4 address)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_router_id (vty, args);
+}
+
+DEFUN (ldp_no_address_family_ipv4,
+ ldp_no_address_family_ipv4_cmd,
+ "no address-family ipv4",
+ "Negate a command or set its defaults\n"
+ "Configure Address Family and its parameters\n"
+ "IPv4\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "address-family", .value = "ipv4" },
+ NULL
+ };
+ return ldp_vty_address_family (vty, args);
+}
+
+DEFUN (ldp_no_address_family_ipv6,
+ ldp_no_address_family_ipv6_cmd,
+ "no address-family ipv6",
+ "Negate a command or set its defaults\n"
+ "Configure Address Family and its parameters\n"
+ "IPv6\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "address-family", .value = "ipv6" },
+ NULL
+ };
+ return ldp_vty_address_family (vty, args);
+}
+
+DEFUN (ldp_no_discovery_hello_holdtime_disc_time,
+ ldp_no_discovery_hello_holdtime_disc_time_cmd,
+ "no discovery hello holdtime <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "LDP Link Hellos\n"
+ "Hello holdtime\n"
+ "Time (seconds) - 65535 implies infinite\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "hello_type", .value = "hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_holdtime (vty, args);
+}
+
+DEFUN (ldp_no_discovery_hello_interval_disc_time,
+ ldp_no_discovery_hello_interval_disc_time_cmd,
+ "no discovery hello interval <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "LDP Link Hellos\n"
+ "Hello interval\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "hello_type", .value = "hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_interval (vty, args);
+}
+
+DEFUN (ldp_no_discovery_targeted_hello_holdtime_disc_time,
+ ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd,
+ "no discovery targeted-hello holdtime <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "LDP Targeted Hellos\n"
+ "Targeted hello holdtime\n"
+ "Time (seconds) - 65535 implies infinite\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_holdtime (vty, args);
+}
+
+DEFUN (ldp_no_discovery_targeted_hello_interval_disc_time,
+ ldp_no_discovery_targeted_hello_interval_disc_time_cmd,
+ "no discovery targeted-hello interval <1-65535>",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "LDP Targeted Hellos\n"
+ "Targeted hello interval\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_disc_interval (vty, args);
+}
+
+DEFUN (ldp_no_dual_stack_transport_connection_prefer_ipv4,
+ ldp_no_dual_stack_transport_connection_prefer_ipv4_cmd,
+ "no dual-stack transport-connection prefer ipv4",
+ "Negate a command or set its defaults\n"
+ "Configure dual stack parameters\n"
+ "Configure TCP transport parameters\n"
+ "Configure prefered address family for TCP transport connection with neighbor\n"
+ "IPv4\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ NULL
+ };
+ return ldp_vty_trans_pref_ipv4 (vty, args);
+}
+
+DEFUN (ldp_no_dual_stack_cisco_interop,
+ ldp_no_dual_stack_cisco_interop_cmd,
+ "no dual-stack cisco-interop",
+ "Negate a command or set its defaults\n"
+ "Configure dual stack parameters\n"
+ "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ NULL
+ };
+ return ldp_vty_ds_cisco_interop (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_ipv4_password_word,
+ ldp_no_neighbor_ipv4_password_word_cmd,
+ "no neighbor A.B.C.D password WORD",
+ "Negate a command or set its defaults\n"
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "Configure password for MD5 authentication\n"
+ "The password\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ &(struct vty_arg) { .name = "password", .value = argv[1] },
+ NULL
+ };
+ return ldp_vty_neighbor_password (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_ipv4_session_holdtime_session_time,
+ ldp_no_neighbor_ipv4_session_holdtime_session_time_cmd,
+ "no neighbor A.B.C.D session holdtime <15-65535>",
+ "Negate a command or set its defaults\n"
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "Configure session parameters\n"
+ "Configure session holdtime\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ &(struct vty_arg) { .name = "seconds", .value = argv[1] },
+ NULL
+ };
+ return ldp_vty_session_holdtime (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_ipv4_ttl_security_disable,
+ ldp_no_neighbor_ipv4_ttl_security_disable_cmd,
+ "no neighbor A.B.C.D ttl-security disable",
+ "Negate a command or set its defaults\n"
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "LDP ttl security check\n"
+ "Disable ttl security\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_neighbor_ttl_security (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_ipv4_ttl_security_hops_hops,
+ ldp_no_neighbor_ipv4_ttl_security_hops_hops_cmd,
+ "no neighbor A.B.C.D ttl-security hops <1-254>",
+ "Negate a command or set its defaults\n"
+ "Configure neighbor parameters\n"
+ "LDP Id of neighbor\n"
+ "LDP ttl security check\n"
+ "IP hops\n"
+ "maximum number of hops\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "lsr_id", .value = argv[0] },
+ &(struct vty_arg) { .name = "hops", .value = argv[1] },
+ NULL
+ };
+ return ldp_vty_neighbor_ttl_security (vty, args);
+}
+
+DEFUN (ldp_no_router_id_ipv4,
+ ldp_no_router_id_ipv4_cmd,
+ "no router-id A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Configure router Id\n"
+ "LSR Id (in form of an IPv4 address)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_router_id (vty, args);
+}
+
+DEFUN (ldp_discovery_targeted_hello_accept,
+ ldp_discovery_targeted_hello_accept_cmd,
+ "discovery targeted-hello accept",
+ "Configure discovery parameters\n"
+ "LDP Targeted Hellos\n"
+ "Accept and respond to targeted hellos\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" },
+ NULL
+ };
+ return ldp_vty_targeted_hello_accept (vty, args);
+}
+
+DEFUN (ldp_label_local_advertise_explicit_null,
+ ldp_label_local_advertise_explicit_null_cmd,
+ "label local advertise explicit-null",
+ "Configure label control and policies\n"
+ "Configure local label control and policies\n"
+ "Configure outbound label advertisement control\n"
+ "Configure explicit-null advertisement\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_explicit_null (vty, args);
+}
+
+DEFUN (ldp_ttl_security_disable,
+ ldp_ttl_security_disable_cmd,
+ "ttl-security disable",
+ "LDP ttl security check\n"
+ "Disable ttl security\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_ttl_security (vty, args);
+}
+
+DEFUN (ldp_session_holdtime_session_time,
+ ldp_session_holdtime_session_time_cmd,
+ "session holdtime <15-65535>",
+ "Configure session parameters\n"
+ "Configure session holdtime\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_session_holdtime (vty, args);
+}
+
+DEFUN (ldp_interface_ifname,
+ ldp_interface_ifname_cmd,
+ "interface IFNAME",
+ "Enable LDP on an interface and enter interface submode\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_interface (vty, args);
+}
+
+DEFUN (ldp_discovery_transport_address_ipv4,
+ ldp_discovery_transport_address_ipv4_cmd,
+ "discovery transport-address A.B.C.D",
+ "Configure discovery parameters\n"
+ "Specify transport address for TCP connection\n"
+ "IP address to be used as transport address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_trans_addr (vty, args);
+}
+
+DEFUN (ldp_neighbor_ipv4_targeted,
+ ldp_neighbor_ipv4_targeted_cmd,
+ "neighbor A.B.C.D targeted",
+ "Configure neighbor parameters\n"
+ "IP address of neighbor\n"
+ "Establish targeted session\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_neighbor_targeted (vty, args);
+}
+
+DEFUN (ldp_no_discovery_targeted_hello_accept,
+ ldp_no_discovery_targeted_hello_accept_cmd,
+ "no discovery targeted-hello accept",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "LDP Targeted Hellos\n"
+ "Accept and respond to targeted hellos\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" },
+ NULL
+ };
+ return ldp_vty_targeted_hello_accept (vty, args);
+}
+
+DEFUN (ldp_no_label_local_advertise_explicit_null,
+ ldp_no_label_local_advertise_explicit_null_cmd,
+ "no label local advertise explicit-null",
+ "Negate a command or set its defaults\n"
+ "Configure label control and policies\n"
+ "Configure local label control and policies\n"
+ "Configure outbound label advertisement control\n"
+ "Configure explicit-null advertisement\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ NULL
+ };
+ return ldp_vty_explicit_null (vty, args);
+}
+
+DEFUN (ldp_no_ttl_security_disable,
+ ldp_no_ttl_security_disable_cmd,
+ "no ttl-security disable",
+ "Negate a command or set its defaults\n"
+ "LDP ttl security check\n"
+ "Disable ttl security\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ NULL
+ };
+ return ldp_vty_ttl_security (vty, args);
+}
+
+DEFUN (ldp_no_session_holdtime_session_time,
+ ldp_no_session_holdtime_session_time_cmd,
+ "no session holdtime <15-65535>",
+ "Negate a command or set its defaults\n"
+ "Configure session parameters\n"
+ "Configure session holdtime\n"
+ "Time (seconds)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "seconds", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_session_holdtime (vty, args);
+}
+
+DEFUN (ldp_no_interface_ifname,
+ ldp_no_interface_ifname_cmd,
+ "no interface IFNAME",
+ "Negate a command or set its defaults\n"
+ "Enable LDP on an interface and enter interface submode\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_interface (vty, args);
+}
+
+DEFUN (ldp_no_discovery_transport_address_ipv4,
+ ldp_no_discovery_transport_address_ipv4_cmd,
+ "no discovery transport-address A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "Specify transport address for TCP connection\n"
+ "IP address to be used as transport address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_trans_addr (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_ipv4_targeted,
+ ldp_no_neighbor_ipv4_targeted_cmd,
+ "no neighbor A.B.C.D targeted",
+ "Negate a command or set its defaults\n"
+ "Configure neighbor parameters\n"
+ "IP address of neighbor\n"
+ "Establish targeted session\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_neighbor_targeted (vty, args);
+}
+
+DEFUN (ldp_discovery_transport_address_ipv6,
+ ldp_discovery_transport_address_ipv6_cmd,
+ "discovery transport-address X:X::X:X",
+ "Configure discovery parameters\n"
+ "Specify transport address for TCP connection\n"
+ "IPv6 address to be used as transport address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_trans_addr (vty, args);
+}
+
+DEFUN (ldp_neighbor_ipv6_targeted,
+ ldp_neighbor_ipv6_targeted_cmd,
+ "neighbor X:X::X:X targeted",
+ "Configure neighbor parameters\n"
+ "IPv6 address of neighbor\n"
+ "Establish targeted session\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_neighbor_targeted (vty, args);
+}
+
+DEFUN (ldp_no_discovery_transport_address_ipv6,
+ ldp_no_discovery_transport_address_ipv6_cmd,
+ "no discovery transport-address X:X::X:X",
+ "Negate a command or set its defaults\n"
+ "Configure discovery parameters\n"
+ "Specify transport address for TCP connection\n"
+ "IPv6 address to be used as transport address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_trans_addr (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_ipv6_targeted,
+ ldp_no_neighbor_ipv6_targeted_cmd,
+ "no neighbor X:X::X:X targeted",
+ "Negate a command or set its defaults\n"
+ "Configure neighbor parameters\n"
+ "IPv6 address of neighbor\n"
+ "Establish targeted session\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_neighbor_targeted (vty, args);
+}
+
+DEFUN (ldp_bridge_ifname,
+ ldp_bridge_ifname_cmd,
+ "bridge IFNAME",
+ "Bridge interface\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_bridge (vty, args);
+}
+
+DEFUN (ldp_mtu_mtu,
+ ldp_mtu_mtu_cmd,
+ "mtu <1500-9180>",
+ "set Maximum Transmission Unit\n"
+ "Maximum Transmission Unit value\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "mtu", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_mtu (vty, args);
+}
+
+DEFUN (ldp_member_interface_ifname,
+ ldp_member_interface_ifname_cmd,
+ "member interface IFNAME",
+ "L2VPN member configuration\n"
+ "Local interface\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_interface (vty, args);
+}
+
+DEFUN (ldp_member_pseudowire_ifname,
+ ldp_member_pseudowire_ifname_cmd,
+ "member pseudowire IFNAME",
+ "L2VPN member configuration\n"
+ "Pseudowire interface\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pseudowire (vty, args);
+}
+
+DEFUN (ldp_vc_type_pwtype,
+ ldp_vc_type_pwtype_cmd,
+ "vc type (ethernet|ethernet-tagged)",
+ "Virtual Circuit options\n"
+ "Virtual Circuit type to use\n"
+ "Ethernet (type 5)\n"
+ "Ethernet-tagged (type 4)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pwtype (vty, args);
+}
+
+DEFUN (ldp_no_bridge_ifname,
+ ldp_no_bridge_ifname_cmd,
+ "no bridge IFNAME",
+ "Negate a command or set its defaults\n"
+ "Bridge interface\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_bridge (vty, args);
+}
+
+DEFUN (ldp_no_mtu_mtu,
+ ldp_no_mtu_mtu_cmd,
+ "no mtu <1500-9180>",
+ "Negate a command or set its defaults\n"
+ "set Maximum Transmission Unit\n"
+ "Maximum Transmission Unit value\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "mtu", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_mtu (vty, args);
+}
+
+DEFUN (ldp_no_member_interface_ifname,
+ ldp_no_member_interface_ifname_cmd,
+ "no member interface IFNAME",
+ "Negate a command or set its defaults\n"
+ "L2VPN member configuration\n"
+ "Local interface\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_interface (vty, args);
+}
+
+DEFUN (ldp_no_member_pseudowire_ifname,
+ ldp_no_member_pseudowire_ifname_cmd,
+ "no member pseudowire IFNAME",
+ "Negate a command or set its defaults\n"
+ "L2VPN member configuration\n"
+ "Pseudowire interface\n"
+ "Interface's name\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "ifname", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pseudowire (vty, args);
+}
+
+DEFUN (ldp_no_vc_type_pwtype,
+ ldp_no_vc_type_pwtype_cmd,
+ "no vc type (ethernet|ethernet-tagged)",
+ "Negate a command or set its defaults\n"
+ "Virtual Circuit options\n"
+ "Virtual Circuit type to use\n"
+ "Ethernet (type 5)\n"
+ "Ethernet-tagged (type 4)\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pwtype (vty, args);
+}
+
+DEFUN (ldp_control_word_cword,
+ ldp_control_word_cword_cmd,
+ "control-word (exclude|include)",
+ "Control-word options\n"
+ "Exclude control-word in pseudowire packets\n"
+ "Include control-word in pseudowire packets\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "preference", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_cword (vty, args);
+}
+
+DEFUN (ldp_neighbor_address_addr,
+ ldp_neighbor_address_addr_cmd,
+ "neighbor address (A.B.C.D|X:X::X:X)",
+ "Remote endpoint configuration\n"
+ "Specify the IPv4 or IPv6 address of the remote endpoint\n"
+ "IPv4 address\n"
+ "IPv6 address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_nbr_addr (vty, args);
+}
+
+DEFUN (ldp_neighbor_lsr_id_ipv4,
+ ldp_neighbor_lsr_id_ipv4_cmd,
+ "neighbor lsr-id A.B.C.D",
+ "Remote endpoint configuration\n"
+ "Specify the LSR-ID of the remote endpoint\n"
+ "IPv4 address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "lsr-id", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_nbr_id (vty, args);
+}
+
+DEFUN (ldp_pw_id_pwid,
+ ldp_pw_id_pwid_cmd,
+ "pw-id <1-4294967295>",
+ "Set the Virtual Circuit ID\n"
+ "Virtual Circuit ID value\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "pwid", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_pwid (vty, args);
+}
+
+DEFUN (ldp_pw_status_disable,
+ ldp_pw_status_disable_cmd,
+ "pw-status disable",
+ "Configure PW status\n"
+ "Disable PW status\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_l2vpn_pw_pwstatus (vty, args);
+}
+
+DEFUN (ldp_no_control_word_cword,
+ ldp_no_control_word_cword_cmd,
+ "no control-word (exclude|include)",
+ "Negate a command or set its defaults\n"
+ "Control-word options\n"
+ "Exclude control-word in pseudowire packets\n"
+ "Include control-word in pseudowire packets\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "preference", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_cword (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_address_addr,
+ ldp_no_neighbor_address_addr_cmd,
+ "no neighbor address (A.B.C.D|X:X::X:X)",
+ "Negate a command or set its defaults\n"
+ "Remote endpoint configuration\n"
+ "Specify the IPv4 or IPv6 address of the remote endpoint\n"
+ "IPv4 address\n"
+ "IPv6 address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_nbr_addr (vty, args);
+}
+
+DEFUN (ldp_no_neighbor_lsr_id_ipv4,
+ ldp_no_neighbor_lsr_id_ipv4_cmd,
+ "no neighbor lsr-id A.B.C.D",
+ "Negate a command or set its defaults\n"
+ "Remote endpoint configuration\n"
+ "Specify the LSR-ID of the remote endpoint\n"
+ "IPv4 address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "lsr-id", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_nbr_id (vty, args);
+}
+
+DEFUN (ldp_no_pw_id_pwid,
+ ldp_no_pw_id_pwid_cmd,
+ "no pw-id <1-4294967295>",
+ "Negate a command or set its defaults\n"
+ "Set the Virtual Circuit ID\n"
+ "Virtual Circuit ID value\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "pwid", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_pwid (vty, args);
+}
+
+DEFUN (ldp_no_pw_status_disable,
+ ldp_no_pw_status_disable_cmd,
+ "no pw-status disable",
+ "Negate a command or set its defaults\n"
+ "Configure PW status\n"
+ "Disable PW status\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ NULL
+ };
+ return ldp_vty_l2vpn_pw_pwstatus (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_neighbor,
+ ldp_show_mpls_ldp_neighbor_cmd,
+ "show mpls ldp neighbor",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Neighbor information\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_neighbor (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_binding,
+ ldp_show_mpls_ldp_binding_cmd,
+ "show mpls ldp binding",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Label Information Base (LIB) information\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_binding (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_discovery,
+ ldp_show_mpls_ldp_discovery_cmd,
+ "show mpls ldp discovery",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Discovery Hello Information\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_discovery (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_interface,
+ ldp_show_mpls_ldp_interface_cmd,
+ "show mpls ldp interface",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "interface information\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_interface (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_address_family_binding,
+ ldp_show_mpls_ldp_address_family_binding_cmd,
+ "show mpls ldp (ipv4|ipv6) binding",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "IPv4 Address Family\n"
+ "IPv6 Address Family\n"
+ "Label Information Base (LIB) information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "address-family", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_show_binding (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_address_family_discovery,
+ ldp_show_mpls_ldp_address_family_discovery_cmd,
+ "show mpls ldp (ipv4|ipv6) discovery",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "IPv4 Address Family\n"
+ "IPv6 Address Family\n"
+ "Discovery Hello Information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "address-family", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_show_discovery (vty, args);
+}
+
+DEFUN (ldp_show_mpls_ldp_address_family_interface,
+ ldp_show_mpls_ldp_address_family_interface_cmd,
+ "show mpls ldp (ipv4|ipv6) interface",
+ "Show running system information\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "IPv4 Address Family\n"
+ "IPv6 Address Family\n"
+ "interface information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "address-family", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_show_interface (vty, args);
+}
+
+DEFUN (ldp_show_l2vpn_atom_binding,
+ ldp_show_l2vpn_atom_binding_cmd,
+ "show l2vpn atom binding",
+ "Show running system information\n"
+ "Show information about Layer2 VPN\n"
+ "Show Any Transport over MPLS information\n"
+ "Show AToM label binding information\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_atom_binding (vty, args);
+}
+
+DEFUN (ldp_show_l2vpn_atom_vc,
+ ldp_show_l2vpn_atom_vc_cmd,
+ "show l2vpn atom vc",
+ "Show running system information\n"
+ "Show information about Layer2 VPN\n"
+ "Show Any Transport over MPLS information\n"
+ "Show AToM virtual circuit information\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_atom_vc (vty, args);
+}
+
+DEFUN (ldp_show_debugging_mpls_ldp,
+ ldp_show_debugging_mpls_ldp_cmd,
+ "show debugging mpls ldp",
+ "Show running system information\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_show_debugging (vty, args);
+}
+
+DEFUN (ldp_clear_mpls_ldp_neighbor,
+ ldp_clear_mpls_ldp_neighbor_cmd,
+ "clear mpls ldp neighbor",
+ "Reset functions\n"
+ "Reset MPLS statistical information\n"
+ "Clear LDP state\n"
+ "Clear LDP neighbor sessions\n")
+{
+ struct vty_arg *args[] = { NULL };
+ return ldp_vty_clear_nbr (vty, args);
+}
+
+DEFUN (ldp_clear_mpls_ldp_neighbor_addr,
+ ldp_clear_mpls_ldp_neighbor_addr_cmd,
+ "clear mpls ldp neighbor (A.B.C.D|X:X::X:X)",
+ "Reset functions\n"
+ "Reset MPLS statistical information\n"
+ "Clear LDP state\n"
+ "Clear LDP neighbor sessions\n"
+ "IPv4 address\n"
+ "IPv6 address\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "addr", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_clear_nbr (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_discovery_hello_dir,
+ ldp_debug_mpls_ldp_discovery_hello_dir_cmd,
+ "debug mpls ldp discovery hello (recv|sent)",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Discovery messages\n"
+ "Discovery hello message\n"
+ "Received messages\n"
+ "Sent messages\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "discovery" },
+ &(struct vty_arg) { .name = "dir", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_errors,
+ ldp_debug_mpls_ldp_errors_cmd,
+ "debug mpls ldp errors",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Errors\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "errors" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_event,
+ ldp_debug_mpls_ldp_event_cmd,
+ "debug mpls ldp event",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "LDP event information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "event" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_messages_recv,
+ ldp_debug_mpls_ldp_messages_recv_cmd,
+ "debug mpls ldp messages recv",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Received messages, excluding periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "recv" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_messages_recv_all,
+ ldp_debug_mpls_ldp_messages_recv_all_cmd,
+ "debug mpls ldp messages recv all",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Received messages, excluding periodic Keep Alives\n"
+ "Received messages, including periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "recv" },
+ &(struct vty_arg) { .name = "all", .value = "all" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_messages_sent,
+ ldp_debug_mpls_ldp_messages_sent_cmd,
+ "debug mpls ldp messages sent",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Sent messages, excluding periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "sent" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_messages_sent_all,
+ ldp_debug_mpls_ldp_messages_sent_all_cmd,
+ "debug mpls ldp messages sent all",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Sent messages, excluding periodic Keep Alives\n"
+ "Sent messages, including periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "sent" },
+ &(struct vty_arg) { .name = "all", .value = "all" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_debug_mpls_ldp_zebra,
+ ldp_debug_mpls_ldp_zebra_cmd,
+ "debug mpls ldp zebra",
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "LDP zebra information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "type", .value = "zebra" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_discovery_hello_dir,
+ ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd,
+ "no debug mpls ldp discovery hello (recv|sent)",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Discovery messages\n"
+ "Discovery hello message\n"
+ "Received messages\n"
+ "Sent messages\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "discovery" },
+ &(struct vty_arg) { .name = "dir", .value = argv[0] },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_errors,
+ ldp_no_debug_mpls_ldp_errors_cmd,
+ "no debug mpls ldp errors",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Errors\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "errors" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_event,
+ ldp_no_debug_mpls_ldp_event_cmd,
+ "no debug mpls ldp event",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "LDP event information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "event" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_messages_recv,
+ ldp_no_debug_mpls_ldp_messages_recv_cmd,
+ "no debug mpls ldp messages recv",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Received messages, excluding periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "recv" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_messages_recv_all,
+ ldp_no_debug_mpls_ldp_messages_recv_all_cmd,
+ "no debug mpls ldp messages recv all",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Received messages, excluding periodic Keep Alives\n"
+ "Received messages, including periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "recv" },
+ &(struct vty_arg) { .name = "all", .value = "all" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_messages_sent,
+ ldp_no_debug_mpls_ldp_messages_sent_cmd,
+ "no debug mpls ldp messages sent",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Sent messages, excluding periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "sent" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_messages_sent_all,
+ ldp_no_debug_mpls_ldp_messages_sent_all_cmd,
+ "no debug mpls ldp messages sent all",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "Messages\n"
+ "Sent messages, excluding periodic Keep Alives\n"
+ "Sent messages, including periodic Keep Alives\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "messages" },
+ &(struct vty_arg) { .name = "dir", .value = "sent" },
+ &(struct vty_arg) { .name = "all", .value = "all" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+DEFUN (ldp_no_debug_mpls_ldp_zebra,
+ ldp_no_debug_mpls_ldp_zebra_cmd,
+ "no debug mpls ldp zebra",
+ "Negate a command or set its defaults\n"
+ "Debugging functions\n"
+ "MPLS information\n"
+ "Label Distribution Protocol\n"
+ "LDP zebra information\n")
+{
+ struct vty_arg *args[] =
+ {
+ &(struct vty_arg) { .name = "no", .value = "no" },
+ &(struct vty_arg) { .name = "type", .value = "zebra" },
+ NULL
+ };
+ return ldp_vty_debug (vty, args);
+}
+
+void
+ldp_vty_init (void)
+{
+ install_element (CONFIG_NODE, &ldp_mpls_ldp_cmd);
+ install_element (CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd);
+ install_element (CONFIG_NODE, &ldp_no_mpls_ldp_cmd);
+ install_element (CONFIG_NODE, &ldp_no_l2vpn_word_type_vpls_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_discovery_hello_dir_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_errors_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_event_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_recv_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_recv_all_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_sent_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_sent_all_cmd);
+ install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_zebra_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_errors_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_event_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_recv_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_recv_all_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_sent_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_sent_all_cmd);
+ install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_zebra_cmd);
+ install_node (&ldp_node, ldp_config_write);
+ install_default (LDP_NODE);
+ install_element (LDP_NODE, &ldp_address_family_ipv4_cmd);
+ install_element (LDP_NODE, &ldp_address_family_ipv6_cmd);
+ install_element (LDP_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_dual_stack_transport_connection_prefer_ipv4_cmd);
+ install_element (LDP_NODE, &ldp_dual_stack_cisco_interop_cmd);
+ install_element (LDP_NODE, &ldp_neighbor_ipv4_password_word_cmd);
+ install_element (LDP_NODE, &ldp_neighbor_ipv4_session_holdtime_session_time_cmd);
+ install_element (LDP_NODE, &ldp_neighbor_ipv4_ttl_security_disable_cmd);
+ install_element (LDP_NODE, &ldp_neighbor_ipv4_ttl_security_hops_hops_cmd);
+ install_element (LDP_NODE, &ldp_router_id_ipv4_cmd);
+ install_element (LDP_NODE, &ldp_no_address_family_ipv4_cmd);
+ install_element (LDP_NODE, &ldp_no_address_family_ipv6_cmd);
+ install_element (LDP_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd);
+ install_element (LDP_NODE, &ldp_no_dual_stack_transport_connection_prefer_ipv4_cmd);
+ install_element (LDP_NODE, &ldp_no_dual_stack_cisco_interop_cmd);
+ install_element (LDP_NODE, &ldp_no_neighbor_ipv4_password_word_cmd);
+ install_element (LDP_NODE, &ldp_no_neighbor_ipv4_session_holdtime_session_time_cmd);
+ install_element (LDP_NODE, &ldp_no_neighbor_ipv4_ttl_security_disable_cmd);
+ install_element (LDP_NODE, &ldp_no_neighbor_ipv4_ttl_security_hops_hops_cmd);
+ install_element (LDP_NODE, &ldp_no_router_id_ipv4_cmd);
+ install_node (&ldp_ipv4_node, NULL);
+ install_default (LDP_IPV4_NODE);
+ install_element (LDP_IPV4_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_accept_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_label_local_advertise_explicit_null_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_ttl_security_disable_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_session_holdtime_session_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_interface_ifname_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_discovery_transport_address_ipv4_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_neighbor_ipv4_targeted_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_accept_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_label_local_advertise_explicit_null_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_ttl_security_disable_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_session_holdtime_session_time_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_interface_ifname_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_discovery_transport_address_ipv4_cmd);
+ install_element (LDP_IPV4_NODE, &ldp_no_neighbor_ipv4_targeted_cmd);
+ install_node (&ldp_ipv6_node, NULL);
+ install_default (LDP_IPV6_NODE);
+ install_element (LDP_IPV6_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_accept_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_label_local_advertise_explicit_null_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_ttl_security_disable_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_session_holdtime_session_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_interface_ifname_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_discovery_transport_address_ipv6_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_neighbor_ipv6_targeted_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_accept_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_label_local_advertise_explicit_null_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_ttl_security_disable_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_session_holdtime_session_time_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_interface_ifname_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_discovery_transport_address_ipv6_cmd);
+ install_element (LDP_IPV6_NODE, &ldp_no_neighbor_ipv6_targeted_cmd);
+ install_node (&ldp_ipv4_iface_node, NULL);
+ install_default (LDP_IPV4_IFACE_NODE);
+ install_element (LDP_IPV4_IFACE_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV4_IFACE_NODE, &ldp_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV4_IFACE_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV4_IFACE_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd);
+ install_node (&ldp_ipv6_iface_node, NULL);
+ install_default (LDP_IPV6_IFACE_NODE);
+ install_element (LDP_IPV6_IFACE_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV6_IFACE_NODE, &ldp_discovery_hello_interval_disc_time_cmd);
+ install_element (LDP_IPV6_IFACE_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd);
+ install_element (LDP_IPV6_IFACE_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd);
+ install_node (&ldp_l2vpn_node, ldp_l2vpn_config_write);
+ install_default (LDP_L2VPN_NODE);
+ install_element (LDP_L2VPN_NODE, &ldp_bridge_ifname_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_mtu_mtu_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_member_interface_ifname_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_vc_type_pwtype_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_no_bridge_ifname_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_no_mtu_mtu_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_no_member_interface_ifname_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_no_member_pseudowire_ifname_cmd);
+ install_element (LDP_L2VPN_NODE, &ldp_no_vc_type_pwtype_cmd);
+ install_node (&ldp_pseudowire_node, NULL);
+ install_default (LDP_PSEUDOWIRE_NODE);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_control_word_cword_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_neighbor_address_addr_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_neighbor_lsr_id_ipv4_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_pw_id_pwid_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_pw_status_disable_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_control_word_cword_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_neighbor_address_addr_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_neighbor_lsr_id_ipv4_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_pw_id_pwid_cmd);
+ install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_pw_status_disable_cmd);
+ install_node (&ldp_debug_node, ldp_debug_config_write);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_neighbor_cmd);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_binding_cmd);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_discovery_cmd);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_interface_cmd);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_binding_cmd);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_discovery_cmd);
+ install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_interface_cmd);
+ install_element (ENABLE_NODE, &ldp_show_l2vpn_atom_binding_cmd);
+ install_element (ENABLE_NODE, &ldp_show_l2vpn_atom_vc_cmd);
+ install_element (ENABLE_NODE, &ldp_show_debugging_mpls_ldp_cmd);
+ install_element (ENABLE_NODE, &ldp_clear_mpls_ldp_neighbor_cmd);
+ install_element (ENABLE_NODE, &ldp_clear_mpls_ldp_neighbor_addr_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_discovery_hello_dir_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_errors_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_event_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_recv_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_recv_all_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_sent_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_sent_all_cmd);
+ install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_zebra_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_errors_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_event_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_recv_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_recv_all_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_sent_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_sent_all_cmd);
+ install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_zebra_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_neighbor_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_binding_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_discovery_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_interface_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_binding_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_discovery_cmd);
+ install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_interface_cmd);
+ install_element (VIEW_NODE, &ldp_show_l2vpn_atom_binding_cmd);
+ install_element (VIEW_NODE, &ldp_show_l2vpn_atom_vc_cmd);
+ install_element (VIEW_NODE, &ldp_show_debugging_mpls_ldp_cmd);
+ install_element (VIEW_NODE, &ldp_clear_mpls_ldp_neighbor_cmd);
+ install_element (VIEW_NODE, &ldp_clear_mpls_ldp_neighbor_addr_cmd);
+} \ No newline at end of file
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
new file mode 100644
index 000000000..a3e1b9a25
--- /dev/null
+++ b/ldpd/ldp_vty_conf.c
@@ -0,0 +1,1637 @@
+/*
+ * 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 "ldpd.h"
+#include "ldpe.h"
+#include "lde.h"
+#include "log.h"
+
+#include "command.h"
+#include "vrf.h"
+#include "if.h"
+#include "vty.h"
+#include "ldp_vty.h"
+
+static int interface_config_write(struct vty *);
+static void ldp_af_iface_config_write(struct vty *, int);
+static void ldp_af_config_write(struct vty *, int, struct ldpd_conf *,
+ struct ldpd_af_conf *);
+static void ldp_l2vpn_pw_config_write(struct vty *, struct l2vpn_pw *);
+static int ldp_vty_get_af(struct vty *);
+static int ldp_iface_is_configured(struct ldpd_conf *, const char *);
+static int ldp_vty_nbr_session_holdtime(struct vty *, struct vty_arg *[]);
+static int ldp_vty_af_session_holdtime(struct vty *, struct vty_arg *[]);
+
+static char vty_ifname[IF_NAMESIZE];
+static char vty_l2vpn_name[L2VPN_NAME_LEN];
+static char vty_pw_ifname[IF_NAMESIZE];
+
+static struct cmd_node interface_node =
+{
+ INTERFACE_NODE,
+ "%s(config-if)# ",
+ 1
+};
+
+struct cmd_node ldp_node =
+{
+ LDP_NODE,
+ "%s(config-ldp)# ",
+ 1,
+};
+
+struct cmd_node ldp_ipv4_node =
+{
+ LDP_IPV4_NODE,
+ "%s(config-ldp-af)# ",
+ 1,
+};
+
+struct cmd_node ldp_ipv6_node =
+{
+ LDP_IPV6_NODE,
+ "%s(config-ldp-af)# ",
+ 1,
+};
+
+struct cmd_node ldp_ipv4_iface_node =
+{
+ LDP_IPV4_IFACE_NODE,
+ "%s(config-ldp-af-if)# ",
+ 1,
+};
+
+struct cmd_node ldp_ipv6_iface_node =
+{
+ LDP_IPV6_IFACE_NODE,
+ "%s(config-ldp-af-if)# ",
+ 1,
+};
+
+struct cmd_node ldp_l2vpn_node =
+{
+ LDP_L2VPN_NODE,
+ "%s(config-l2vpn)# ",
+ 1,
+};
+
+struct cmd_node ldp_pseudowire_node =
+{
+ LDP_PSEUDOWIRE_NODE,
+ "%s(config-l2vpn-pw)# ",
+ 1,
+};
+
+int
+ldp_get_address(const char *str, int *af, union ldpd_addr *addr)
+{
+ memset(addr, 0, sizeof(*addr));
+
+ if (inet_pton(AF_INET, str, &addr->v4) == 1) {
+ *af = AF_INET;
+ return (0);
+ }
+
+ if (inet_pton(AF_INET6, str, &addr->v6) == 1) {
+ *af = AF_INET6;
+ return (0);
+ }
+
+ return (-1);
+}
+
+static int
+interface_config_write(struct vty *vty)
+{
+ struct listnode *node;
+ struct interface *ifp;
+ int write = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT), node, ifp)) {
+ vty_out(vty, "!%s", VTY_NEWLINE);
+ vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE);
+ if (ifp->desc)
+ vty_out(vty, " description %s%s", ifp->desc,
+ VTY_NEWLINE);
+
+ write++;
+ }
+
+ return (write);
+}
+
+static void
+ldp_af_iface_config_write(struct vty *vty, int af)
+{
+ struct iface *iface;
+ struct iface_af *ia;
+
+ LIST_FOREACH(iface, &ldpd_conf->iface_list, entry) {
+ ia = iface_af_get(iface, af);
+ if (!ia->enabled)
+ continue;
+
+ vty_out(vty, " !%s", VTY_NEWLINE);
+ vty_out(vty, " interface %s%s", iface->name, VTY_NEWLINE);
+
+ if (ia->hello_holdtime != LINK_DFLT_HOLDTIME &&
+ ia->hello_holdtime != 0)
+ vty_out(vty, " discovery hello holdtime %u%s",
+ ia->hello_holdtime, VTY_NEWLINE);
+ if (ia->hello_interval != DEFAULT_HELLO_INTERVAL &&
+ ia->hello_interval != 0)
+ vty_out(vty, " discovery hello interval %u%s",
+ ia->hello_interval, VTY_NEWLINE);
+ }
+}
+
+static void
+ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf,
+ struct ldpd_af_conf *af_conf)
+{
+ struct tnbr *tnbr;
+
+ if (!(af_conf->flags & F_LDPD_AF_ENABLED))
+ return;
+
+ vty_out(vty, " !%s", VTY_NEWLINE);
+ vty_out(vty, " address-family %s%s", af_name(af), VTY_NEWLINE);
+
+ if (af_conf->lhello_holdtime != LINK_DFLT_HOLDTIME &&
+ af_conf->lhello_holdtime != 0 )
+ vty_out(vty, " discovery hello holdtime %u%s",
+ af_conf->lhello_holdtime, VTY_NEWLINE);
+ if (af_conf->lhello_interval != DEFAULT_HELLO_INTERVAL &&
+ af_conf->lhello_interval != 0)
+ vty_out(vty, " discovery hello interval %u%s",
+ af_conf->lhello_interval, VTY_NEWLINE);
+
+ if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT)
+ vty_out(vty, " discovery targeted-hello accept%s",
+ VTY_NEWLINE);
+
+ if (af_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME &&
+ af_conf->thello_holdtime != 0)
+ vty_out(vty, " discovery targeted-hello holdtime %u%s",
+ af_conf->thello_holdtime, VTY_NEWLINE);
+ if (af_conf->thello_interval != DEFAULT_HELLO_INTERVAL &&
+ af_conf->thello_interval != 0)
+ vty_out(vty, " discovery targeted-hello interval %u%s",
+ af_conf->thello_interval, VTY_NEWLINE);
+
+ if (ldp_addrisset(af, &af_conf->trans_addr))
+ vty_out(vty, " discovery transport-address %s%s",
+ log_addr(af, &af_conf->trans_addr), VTY_NEWLINE);
+ else
+ vty_out(vty, " ! Incomplete config, specify a discovery "
+ "transport-address%s", VTY_NEWLINE);
+
+ if (af_conf->flags & F_LDPD_AF_EXPNULL)
+ vty_out(vty, " label local advertise explicit-null%s",
+ VTY_NEWLINE);
+
+ if (af_conf->flags & F_LDPD_AF_NO_GTSM)
+ vty_out(vty, " ttl-security disable%s", VTY_NEWLINE);
+
+ if (af_conf->keepalive != DEFAULT_KEEPALIVE)
+ vty_out(vty, " session holdtime %u%s", af_conf->keepalive,
+ VTY_NEWLINE);
+
+ LIST_FOREACH(tnbr, &ldpd_conf->tnbr_list, entry) {
+ if (tnbr->af == af) {
+ vty_out(vty, " !%s", VTY_NEWLINE);
+ vty_out(vty, " neighbor %s targeted%s",
+ log_addr(tnbr->af, &tnbr->addr), VTY_NEWLINE);
+ }
+ }
+
+ ldp_af_iface_config_write(vty, af);
+
+ vty_out(vty, " !%s", VTY_NEWLINE);
+}
+
+int
+ldp_config_write(struct vty *vty)
+{
+ struct nbr_params *nbrp;
+
+ if (!(ldpd_conf->flags & F_LDPD_ENABLED))
+ return (0);
+
+ vty_out(vty, "mpls ldp%s", VTY_NEWLINE);
+
+ if (ldpd_conf->rtr_id.s_addr != 0)
+ vty_out(vty, " router-id %s%s",
+ inet_ntoa(ldpd_conf->rtr_id), VTY_NEWLINE);
+
+ if (ldpd_conf->lhello_holdtime != LINK_DFLT_HOLDTIME &&
+ ldpd_conf->lhello_holdtime != 0)
+ vty_out(vty, " discovery hello holdtime %u%s",
+ ldpd_conf->lhello_holdtime, VTY_NEWLINE);
+ if (ldpd_conf->lhello_interval != DEFAULT_HELLO_INTERVAL &&
+ ldpd_conf->lhello_interval != 0)
+ vty_out(vty, " discovery hello interval %u%s",
+ ldpd_conf->lhello_interval, VTY_NEWLINE);
+
+ if (ldpd_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME &&
+ ldpd_conf->thello_holdtime != 0)
+ vty_out(vty, " discovery targeted-hello holdtime %u%s",
+ ldpd_conf->thello_holdtime, VTY_NEWLINE);
+ if (ldpd_conf->thello_interval != DEFAULT_HELLO_INTERVAL &&
+ ldpd_conf->thello_interval != 0)
+ vty_out(vty, " discovery targeted-hello interval %u%s",
+ ldpd_conf->thello_interval, VTY_NEWLINE);
+
+ if (ldpd_conf->trans_pref == DUAL_STACK_LDPOV4)
+ vty_out(vty, " dual-stack transport-connection prefer ipv4%s",
+ VTY_NEWLINE);
+
+ if (ldpd_conf->flags & F_LDPD_DS_CISCO_INTEROP)
+ vty_out(vty, " dual-stack cisco-interop%s", VTY_NEWLINE);
+
+ LIST_FOREACH(nbrp, &ldpd_conf->nbrp_list, entry) {
+ if (nbrp->flags & F_NBRP_KEEPALIVE)
+ vty_out(vty, " neighbor %s session holdtime %u%s",
+ inet_ntoa(nbrp->lsr_id), nbrp->keepalive,
+ VTY_NEWLINE);
+
+ if (nbrp->flags & F_NBRP_GTSM) {
+ if (nbrp->gtsm_enabled)
+ vty_out(vty, " neighbor %s ttl-security hops "
+ "%u%s", inet_ntoa(nbrp->lsr_id),
+ nbrp->gtsm_hops, VTY_NEWLINE);
+ else
+ vty_out(vty, " neighbor %s ttl-security "
+ "disable%s", inet_ntoa(nbrp->lsr_id),
+ VTY_NEWLINE);
+ }
+
+ if (nbrp->auth.method == AUTH_MD5SIG)
+ vty_out(vty, " neighbor %s password %s%s",
+ inet_ntoa(nbrp->lsr_id), nbrp->auth.md5key,
+ VTY_NEWLINE);
+ }
+
+ ldp_af_config_write(vty, AF_INET, ldpd_conf, &ldpd_conf->ipv4);
+ ldp_af_config_write(vty, AF_INET6, ldpd_conf, &ldpd_conf->ipv6);
+ vty_out(vty, " !%s", VTY_NEWLINE);
+ vty_out(vty, "!%s", VTY_NEWLINE);
+
+ return (1);
+}
+
+static void
+ldp_l2vpn_pw_config_write(struct vty *vty, struct l2vpn_pw *pw)
+{
+ int missing_lsrid = 0;
+ int missing_pwid = 0;
+
+ vty_out(vty, " !%s", VTY_NEWLINE);
+ vty_out(vty, " member pseudowire %s%s", pw->ifname, VTY_NEWLINE);
+
+ if (pw->lsr_id.s_addr != INADDR_ANY)
+ vty_out(vty, " neighbor lsr-id %s%s", inet_ntoa(pw->lsr_id),
+ VTY_NEWLINE);
+ else
+ missing_lsrid = 1;
+
+ if (pw->flags & F_PW_STATIC_NBR_ADDR)
+ vty_out(vty, " neighbor address %s%s", log_addr(pw->af,
+ &pw->addr), VTY_NEWLINE);
+
+ if (pw->pwid != 0)
+ vty_out(vty, " pw-id %u%s", pw->pwid, VTY_NEWLINE);
+ else
+ missing_pwid = 1;
+
+ if (!(pw->flags & F_PW_CWORD_CONF))
+ vty_out(vty, " control-word exclude%s", VTY_NEWLINE);
+
+ if (!(pw->flags & F_PW_STATUSTLV_CONF))
+ vty_out(vty, " pw-status disable%s", VTY_NEWLINE);
+
+ if (missing_lsrid)
+ vty_out(vty, " ! Incomplete config, specify a neighbor "
+ "lsr-id%s", VTY_NEWLINE);
+ if (missing_pwid)
+ vty_out(vty, " ! Incomplete config, specify a pw-id%s",
+ VTY_NEWLINE);
+}
+
+int
+ldp_l2vpn_config_write(struct vty *vty)
+{
+ struct l2vpn *l2vpn;
+ struct l2vpn_if *lif;
+ struct l2vpn_pw *pw;
+
+ LIST_FOREACH(l2vpn, &ldpd_conf->l2vpn_list, entry) {
+ vty_out(vty, "l2vpn %s type vpls%s", l2vpn->name, VTY_NEWLINE);
+
+ if (l2vpn->pw_type != DEFAULT_PW_TYPE)
+ vty_out(vty, " vc type ethernet-tagged%s", VTY_NEWLINE);
+
+ if (l2vpn->mtu != DEFAULT_L2VPN_MTU)
+ vty_out(vty, " mtu %u%s", l2vpn->mtu, VTY_NEWLINE);
+
+ if (l2vpn->br_ifname[0] != '\0')
+ vty_out(vty, " bridge %s%s", l2vpn->br_ifname,
+ VTY_NEWLINE);
+
+ LIST_FOREACH(lif, &l2vpn->if_list, entry)
+ vty_out(vty, " member interface %s%s", lif->ifname,
+ VTY_NEWLINE);
+
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry)
+ ldp_l2vpn_pw_config_write(vty, pw);
+ LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry)
+ ldp_l2vpn_pw_config_write(vty, pw);
+
+ vty_out(vty, " !%s", VTY_NEWLINE);
+ vty_out(vty, "!%s", VTY_NEWLINE);
+ }
+
+ return (0);
+}
+
+static int
+ldp_vty_get_af(struct vty *vty)
+{
+ switch (vty->node) {
+ case LDP_IPV4_NODE:
+ case LDP_IPV4_IFACE_NODE:
+ return (AF_INET);
+ case LDP_IPV6_NODE:
+ case LDP_IPV6_IFACE_NODE:
+ return (AF_INET6);
+ default:
+ fatalx("ldp_vty_get_af: unexpected node");
+ }
+}
+
+static int
+ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname)
+{
+ struct l2vpn *l2vpn;
+
+ if (if_lookup_name(xconf, ifname))
+ return (1);
+
+ LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) {
+ if (l2vpn_if_find_name(l2vpn, ifname))
+ return (1);
+ if (l2vpn_pw_find_name(l2vpn, ifname))
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+ldp_vty_mpls_ldp(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ int disable;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ if (disable)
+ vty_conf->flags &= ~F_LDPD_ENABLED;
+ else {
+ vty->node = LDP_NODE;
+ vty_conf->flags |= F_LDPD_ENABLED;
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_address_family(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ int af;
+ const char *af_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ af_str = vty_get_arg_value(args, "address-family");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ if (strcmp(af_str, "ipv4") == 0) {
+ af = AF_INET;
+ af_conf = &vty_conf->ipv4;
+ } else if (strcmp(af_str, "ipv6") == 0) {
+ af = AF_INET6;
+ af_conf = &vty_conf->ipv6;
+ } else
+ return (CMD_WARNING);
+
+ if (disable) {
+ af_conf->flags &= ~F_LDPD_AF_ENABLED;
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+ }
+
+ switch (af) {
+ case AF_INET:
+ vty->node = LDP_IPV4_NODE;
+ break;
+ case AF_INET6:
+ vty->node = LDP_IPV6_NODE;
+ break;
+ default:
+ fatalx("ldp_vty_address_family: unknown af");
+ }
+ af_conf->flags |= F_LDPD_AF_ENABLED;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ struct iface *iface;
+ struct iface_af *ia;
+ int af;
+ char *ep;
+ long int secs;
+ enum hello_type hello_type;
+ const char *seconds_str;
+ const char *hello_type_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ seconds_str = vty_get_arg_value(args, "seconds");
+ hello_type_str = vty_get_arg_value(args, "hello_type");
+
+ secs = strtol(seconds_str, &ep, 10);
+ if (*ep != '\0' || secs < MIN_HOLDTIME || secs > MAX_HOLDTIME) {
+ vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ if (hello_type_str[0] == 'h')
+ hello_type = HELLO_LINK;
+ else
+ hello_type = HELLO_TARGETED;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ switch (vty->node) {
+ case LDP_NODE:
+ if (disable) {
+ switch (hello_type) {
+ case HELLO_LINK:
+ vty_conf->lhello_holdtime = LINK_DFLT_HOLDTIME;
+ break;
+ case HELLO_TARGETED:
+ vty_conf->thello_holdtime =
+ TARGETED_DFLT_HOLDTIME;
+ break;
+ }
+ } else {
+ switch (hello_type) {
+ case HELLO_LINK:
+ vty_conf->lhello_holdtime = secs;
+ break;
+ case HELLO_TARGETED:
+ vty_conf->thello_holdtime = secs;
+ break;
+ }
+ }
+ break;
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable) {
+ switch (hello_type) {
+ case HELLO_LINK:
+ af_conf->lhello_holdtime = 0;
+ break;
+ case HELLO_TARGETED:
+ af_conf->thello_holdtime = 0;
+ break;
+ }
+ } else {
+ switch (hello_type) {
+ case HELLO_LINK:
+ af_conf->lhello_holdtime = secs;
+ break;
+ case HELLO_TARGETED:
+ af_conf->thello_holdtime = secs;
+ break;
+ }
+ }
+ break;
+ case LDP_IPV4_IFACE_NODE:
+ case LDP_IPV6_IFACE_NODE:
+ af = ldp_vty_get_af(vty);
+ iface = if_lookup_name(vty_conf, vty_ifname);
+ ia = iface_af_get(iface, af);
+
+ if (disable)
+ ia->hello_holdtime = 0;
+ else
+ ia->hello_holdtime = secs;
+ break;
+ default:
+ fatalx("ldp_vty_disc_holdtime: unexpected node");
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ struct iface *iface;
+ struct iface_af *ia;
+ int af;
+ char *ep;
+ long int secs;
+ enum hello_type hello_type;
+ const char *seconds_str;
+ const char *hello_type_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ seconds_str = vty_get_arg_value(args, "seconds");
+ hello_type_str = vty_get_arg_value(args, "hello_type");
+
+ secs = strtol(seconds_str, &ep, 10);
+ if (*ep != '\0' || secs < MIN_HELLO_INTERVAL ||
+ secs > MAX_HELLO_INTERVAL) {
+ vty_out(vty, "%% Invalid interval%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ if (hello_type_str[0] == 'h')
+ hello_type = HELLO_LINK;
+ else
+ hello_type = HELLO_TARGETED;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ switch (vty->node) {
+ case LDP_NODE:
+ if (disable) {
+ switch (hello_type) {
+ case HELLO_LINK:
+ vty_conf->lhello_interval = LINK_DFLT_HOLDTIME;
+ break;
+ case HELLO_TARGETED:
+ vty_conf->thello_interval =
+ TARGETED_DFLT_HOLDTIME;
+ break;
+ }
+ } else {
+ switch (hello_type) {
+ case HELLO_LINK:
+ vty_conf->lhello_interval = secs;
+ break;
+ case HELLO_TARGETED:
+ vty_conf->thello_interval = secs;
+ break;
+ }
+ }
+ break;
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable) {
+ switch (hello_type) {
+ case HELLO_LINK:
+ af_conf->lhello_interval = 0;
+ break;
+ case HELLO_TARGETED:
+ af_conf->thello_interval = 0;
+ break;
+ }
+ } else {
+ switch (hello_type) {
+ case HELLO_LINK:
+ af_conf->lhello_interval = secs;
+ break;
+ case HELLO_TARGETED:
+ af_conf->thello_interval = secs;
+ break;
+ }
+ }
+ break;
+ case LDP_IPV4_IFACE_NODE:
+ case LDP_IPV6_IFACE_NODE:
+ af = ldp_vty_get_af(vty);
+ iface = if_lookup_name(vty_conf, vty_ifname);
+ ia = iface_af_get(iface, af);
+
+ if (disable)
+ ia->hello_interval = 0;
+ else
+ ia->hello_interval = secs;
+ break;
+ default:
+ fatalx("ldp_vty_disc_interval: unexpected node");
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_targeted_hello_accept(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ int af;
+ int disable;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable)
+ af_conf->flags &= ~F_LDPD_AF_THELLO_ACCEPT;
+ else
+ af_conf->flags |= F_LDPD_AF_THELLO_ACCEPT;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+static int
+ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ char *ep;
+ long int secs;
+ struct in_addr lsr_id;
+ struct nbr_params *nbrp;
+ const char *seconds_str;
+ const char *lsr_id_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ seconds_str = vty_get_arg_value(args, "seconds");
+ lsr_id_str = vty_get_arg_value(args, "lsr_id");
+
+ if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 ||
+ bad_addr_v4(lsr_id)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ nbrp = nbr_params_find(vty_conf, lsr_id);
+
+ secs = strtol(seconds_str, &ep, 10);
+ if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) {
+ vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE);
+ goto cancel;
+ }
+
+ if (disable) {
+ if (nbrp == NULL)
+ goto cancel;
+
+ nbrp->keepalive = 0;
+ nbrp->flags &= ~F_NBRP_KEEPALIVE;
+ } else {
+ if (nbrp == NULL) {
+ nbrp = nbr_params_new(lsr_id);
+ LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry);
+ } else if (nbrp->keepalive == secs)
+ goto cancel;
+
+ nbrp->keepalive = secs;
+ nbrp->flags |= F_NBRP_KEEPALIVE;
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+static int
+ldp_vty_af_session_holdtime(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ int af;
+ char *ep;
+ long int secs;
+ const char *seconds_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ seconds_str = vty_get_arg_value(args, "seconds");
+
+ secs = strtol(seconds_str, &ep, 10);
+ if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) {
+ vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE);
+ return (CMD_SUCCESS);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable)
+ af_conf->keepalive = DEFAULT_KEEPALIVE;
+ else
+ af_conf->keepalive = secs;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_session_holdtime(struct vty *vty, struct vty_arg *args[])
+{
+ switch (vty->node) {
+ case LDP_NODE:
+ return (ldp_vty_nbr_session_holdtime(vty, args));
+ case LDP_IPV4_NODE:
+ case LDP_IPV6_NODE:
+ return (ldp_vty_af_session_holdtime(vty, args));
+ default:
+ fatalx("ldp_vty_session_holdtime: unexpected node");
+ }
+}
+
+int
+ldp_vty_interface(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ int af;
+ struct iface *iface;
+ struct iface_af *ia;
+ struct interface *ifp;
+ struct kif kif;
+ const char *ifname;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ ifname = vty_get_arg_value(args, "ifname");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ af = ldp_vty_get_af(vty);
+ iface = if_lookup_name(vty_conf, ifname);
+
+ if (disable) {
+ if (iface == NULL)
+ goto cancel;
+
+ ia = iface_af_get(iface, af);
+ if (ia->enabled == 0)
+ goto cancel;
+
+ ia->enabled = 0;
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+ }
+
+ switch (af) {
+ case AF_INET:
+ vty->node = LDP_IPV4_IFACE_NODE;
+ break;
+ case AF_INET6:
+ vty->node = LDP_IPV6_IFACE_NODE;
+ break;
+ default:
+ break;
+ }
+ strlcpy(vty_ifname, ifname, sizeof(vty_ifname));
+
+ if (iface == NULL) {
+ if (ldp_iface_is_configured(vty_conf, ifname)) {
+ vty_out(vty, "%% Interface is already in use%s",
+ VTY_NEWLINE);
+ goto cancel;
+ }
+
+ ifp = if_lookup_by_name(ifname);
+ memset(&kif, 0, sizeof(kif));
+ strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
+ if (ifp) {
+ kif.ifindex = ifp->ifindex;
+ kif.flags = ifp->flags;
+ }
+ iface = if_new(&kif);
+
+ ia = iface_af_get(iface, af);
+ ia->enabled = 1;
+ LIST_INSERT_HEAD(&vty_conf->iface_list, iface, entry);
+ } else {
+ memset(&kif, 0, sizeof(kif));
+ strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
+
+ ia = iface_af_get(iface, af);
+ if (ia->enabled)
+ goto cancel;
+ ia->enabled = 1;
+ }
+
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_trans_addr(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ int af;
+ const char *addr_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ addr_str = vty_get_arg_value(args, "addr");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable)
+ memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr));
+ else {
+ if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 ||
+ bad_addr(af, &af_conf->trans_addr)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ goto cancel;
+ }
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ int af;
+ union ldpd_addr addr;
+ struct tnbr *tnbr;
+ const char *addr_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ addr_str = vty_get_arg_value(args, "addr");
+
+ af = ldp_vty_get_af(vty);
+
+ if (inet_pton(af, addr_str, &addr) != 1 ||
+ bad_addr(af, &addr)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+ if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&addr.v6)) {
+ vty_out(vty, "%% Address can not be link-local%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ tnbr = tnbr_find(vty_conf, af, &addr);
+
+ if (disable) {
+ if (tnbr == NULL)
+ goto cancel;
+
+ LIST_REMOVE(tnbr, entry);
+ free(tnbr);
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+ }
+
+ if (tnbr)
+ goto cancel;
+
+ tnbr = tnbr_new(af, &addr);
+ tnbr->flags |= F_TNBR_CONFIGURED;
+ LIST_INSERT_HEAD(&vty_conf->tnbr_list, tnbr, entry);
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_explicit_null(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ int af;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable)
+ af_conf->flags &= ~F_LDPD_AF_EXPNULL;
+ else
+ af_conf->flags |= F_LDPD_AF_EXPNULL;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_ttl_security(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct ldpd_af_conf *af_conf;
+ int af;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ af = ldp_vty_get_af(vty);
+ af_conf = ldp_af_conf_get(vty_conf, af);
+
+ if (disable)
+ af_conf->flags &= ~F_LDPD_AF_NO_GTSM;
+ else
+ af_conf->flags |= F_LDPD_AF_NO_GTSM;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_router_id(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ const char *addr_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ addr_str = vty_get_arg_value(args, "addr");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ if (disable)
+ vty_conf->rtr_id.s_addr = INADDR_ANY;
+ else {
+ if (inet_pton(AF_INET, addr_str, &vty_conf->rtr_id) != 1 ||
+ bad_addr_v4(vty_conf->rtr_id)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ goto cancel;
+ }
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_ds_cisco_interop(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ if (disable)
+ vty_conf->flags &= ~F_LDPD_DS_CISCO_INTEROP;
+ else
+ vty_conf->flags |= F_LDPD_DS_CISCO_INTEROP;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_trans_pref_ipv4(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+
+ if (disable)
+ vty_conf->trans_pref = DUAL_STACK_LDPOV6;
+ else
+ vty_conf->trans_pref = DUAL_STACK_LDPOV4;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct in_addr lsr_id;
+ size_t password_len;
+ struct nbr_params *nbrp;
+ const char *lsr_id_str;
+ const char *password_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ lsr_id_str = vty_get_arg_value(args, "lsr_id");
+ password_str = vty_get_arg_value(args, "password");
+
+ if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 ||
+ bad_addr_v4(lsr_id)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ nbrp = nbr_params_find(vty_conf, lsr_id);
+
+ if (disable) {
+ if (nbrp == NULL)
+ goto cancel;
+
+ memset(&nbrp->auth, 0, sizeof(nbrp->auth));
+ nbrp->auth.method = AUTH_NONE;
+ } else {
+ if (nbrp == NULL) {
+ nbrp = nbr_params_new(lsr_id);
+ LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry);
+ } else if (nbrp->auth.method == AUTH_MD5SIG &&
+ strcmp(nbrp->auth.md5key, password_str) == 0)
+ goto cancel;
+
+ password_len = strlcpy(nbrp->auth.md5key, password_str,
+ sizeof(nbrp->auth.md5key));
+ if (password_len >= sizeof(nbrp->auth.md5key))
+ vty_out(vty, "%% password has been truncated to %zu "
+ "characters.", sizeof(nbrp->auth.md5key) - 1);
+ nbrp->auth.md5key_len = password_len;
+ nbrp->auth.method = AUTH_MD5SIG;
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct in_addr lsr_id;
+ struct nbr_params *nbrp;
+ long int hops = 0;
+ char *ep;
+ const char *lsr_id_str;
+ const char *hops_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ lsr_id_str = vty_get_arg_value(args, "lsr_id");
+ hops_str = vty_get_arg_value(args, "hops");
+
+ if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 ||
+ bad_addr_v4(lsr_id)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ if (hops_str) {
+ hops = strtol(hops_str, &ep, 10);
+ if (*ep != '\0' || hops < 1 || hops > 254) {
+ vty_out(vty, "%% Invalid hop count%s", VTY_NEWLINE);
+ return (CMD_SUCCESS);
+ }
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ nbrp = nbr_params_find(vty_conf, lsr_id);
+
+ if (disable) {
+ if (nbrp == NULL)
+ goto cancel;
+
+ nbrp->flags &= ~(F_NBRP_GTSM|F_NBRP_GTSM_HOPS);
+ nbrp->gtsm_enabled = 0;
+ nbrp->gtsm_hops = 0;
+ } else {
+ if (nbrp == NULL) {
+ nbrp = nbr_params_new(lsr_id);
+ LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry);
+ }
+
+ nbrp->flags |= F_NBRP_GTSM;
+ nbrp->flags &= ~F_NBRP_GTSM_HOPS;
+ if (hops_str) {
+ nbrp->gtsm_enabled = 1;
+ nbrp->gtsm_hops = hops;
+ nbrp->flags |= F_NBRP_GTSM_HOPS;
+ } else
+ nbrp->gtsm_enabled = 0;
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ const char *name_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ name_str = vty_get_arg_value(args, "name");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, name_str);
+
+ if (disable) {
+ if (l2vpn == NULL)
+ goto cancel;
+
+ LIST_REMOVE(l2vpn, entry);
+ l2vpn_del(l2vpn);
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+ }
+
+ vty->node = LDP_L2VPN_NODE;
+ strlcpy(vty_l2vpn_name, name_str, sizeof(vty_l2vpn_name));
+ if (l2vpn)
+ goto cancel;
+
+ l2vpn = l2vpn_new(name_str);
+ l2vpn->type = L2VPN_TYPE_VPLS;
+ LIST_INSERT_HEAD(&vty_conf->l2vpn_list, l2vpn, entry);
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_bridge(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ const char *ifname;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ ifname = vty_get_arg_value(args, "ifname");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+
+ if (disable)
+ memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname));
+ else
+ strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname));
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_mtu(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ char *ep;
+ int mtu;
+ const char *mtu_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ mtu_str = vty_get_arg_value(args, "mtu");
+
+ mtu = strtol(mtu_str, &ep, 10);
+ if (*ep != '\0' || mtu < MIN_L2VPN_MTU || mtu > MAX_L2VPN_MTU) {
+ vty_out(vty, "%% Invalid MTU%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+
+ if (disable)
+ l2vpn->mtu = DEFAULT_L2VPN_MTU;
+ else
+ l2vpn->mtu = mtu;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pwtype(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ int pw_type;
+ const char *type_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ type_str = vty_get_arg_value(args, "type");
+
+ if (strcmp(type_str, "ethernet") == 0)
+ pw_type = PW_TYPE_ETHERNET;
+ else
+ pw_type = PW_TYPE_ETHERNET_TAGGED;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+
+ if (disable)
+ l2vpn->pw_type = DEFAULT_PW_TYPE;
+ else
+ l2vpn->pw_type = pw_type;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_interface(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_if *lif;
+ struct interface *ifp;
+ struct kif kif;
+ const char *ifname;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ ifname = vty_get_arg_value(args, "ifname");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ lif = l2vpn_if_find_name(l2vpn, ifname);
+
+ if (disable) {
+ if (lif == NULL)
+ goto cancel;
+
+ LIST_REMOVE(lif, entry);
+ free(lif);
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+ }
+
+ if (lif)
+ goto cancel;
+
+ if (ldp_iface_is_configured(vty_conf, ifname)) {
+ vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE);
+ goto cancel;
+ }
+
+ ifp = if_lookup_by_name(ifname);
+ memset(&kif, 0, sizeof(kif));
+ strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
+ if (ifp) {
+ kif.ifindex = ifp->ifindex;
+ kif.flags = ifp->flags;
+ }
+
+ lif = l2vpn_if_new(l2vpn, &kif);
+ LIST_INSERT_HEAD(&l2vpn->if_list, lif, entry);
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pseudowire(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ struct interface *ifp;
+ struct kif kif;
+ const char *ifname;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ ifname = vty_get_arg_value(args, "ifname");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ pw = l2vpn_pw_find_name(l2vpn, ifname);
+
+ if (disable) {
+ if (pw == NULL)
+ goto cancel;
+
+ LIST_REMOVE(pw, entry);
+ free(pw);
+ ldp_reload(vty_conf);
+ return (CMD_SUCCESS);
+ }
+
+ if (pw) {
+ vty->node = LDP_PSEUDOWIRE_NODE;
+ strlcpy(vty_pw_ifname, ifname, sizeof(vty_pw_ifname));
+ goto cancel;
+ }
+
+ if (ldp_iface_is_configured(vty_conf, ifname)) {
+ vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE);
+ goto cancel;
+ }
+
+ ifp = if_lookup_by_name(ifname);
+ memset(&kif, 0, sizeof(kif));
+ strlcpy(kif.ifname, ifname, sizeof(kif.ifname));
+ if (ifp) {
+ kif.ifindex = ifp->ifindex;
+ kif.flags = ifp->flags;
+ }
+
+ pw = l2vpn_pw_new(l2vpn, &kif);
+ pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF;
+ LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, pw, entry);
+
+ ldp_reload(vty_conf);
+
+ vty->node = LDP_PSEUDOWIRE_NODE;
+ strlcpy(vty_pw_ifname, ifname, sizeof(vty_pw_ifname));
+ return (CMD_SUCCESS);
+
+cancel:
+ ldp_clear_config(vty_conf);
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pw_cword(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ const char *preference_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ preference_str = vty_get_arg_value(args, "preference");
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname);
+
+ if (disable)
+ pw->flags |= F_PW_CWORD_CONF;
+ else {
+ if (preference_str[0] == 'e')
+ pw->flags &= ~F_PW_CWORD_CONF;
+ else
+ pw->flags |= F_PW_CWORD_CONF;
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ int af;
+ union ldpd_addr addr;
+ const char *addr_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ addr_str = vty_get_arg_value(args, "addr");
+
+ if (ldp_get_address(addr_str, &af, &addr) == -1 ||
+ bad_addr(af, &addr)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname);
+
+ if (disable) {
+ pw->af = AF_UNSPEC;
+ memset(&pw->addr, 0, sizeof(pw->addr));
+ pw->flags &= ~F_PW_STATIC_NBR_ADDR;
+ } else {
+ pw->af = af;
+ pw->addr = addr;
+ pw->flags |= F_PW_STATIC_NBR_ADDR;
+ }
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ struct in_addr lsr_id;
+ const char *lsr_id_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ lsr_id_str = vty_get_arg_value(args, "lsr-id");
+
+ if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 ||
+ bad_addr_v4(lsr_id)) {
+ vty_out(vty, "%% Malformed address%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname);
+
+ if (disable)
+ pw->lsr_id.s_addr = INADDR_ANY;
+ else
+ pw->lsr_id = lsr_id;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pw_pwid(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ char *ep;
+ uint32_t pwid;
+ const char *pwid_str;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+ pwid_str = vty_get_arg_value(args, "pwid");
+
+ pwid = strtol(pwid_str, &ep, 10);
+ if (*ep != '\0' || pwid < MIN_PWID_ID || pwid > MAX_PWID_ID) {
+ vty_out(vty, "%% Invalid pw-id%s", VTY_NEWLINE);
+ return (CMD_WARNING);
+ }
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname);
+
+ if (disable)
+ pw->pwid = 0;
+ else
+ pw->pwid = pwid;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+int
+ldp_vty_l2vpn_pw_pwstatus(struct vty *vty, struct vty_arg *args[])
+{
+ struct ldpd_conf *vty_conf;
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+ int disable;
+
+ disable = (vty_get_arg_value(args, "no")) ? 1 : 0;
+
+ vty_conf = ldp_dup_config(ldpd_conf);
+ l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name);
+ pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname);
+
+ if (disable)
+ pw->flags |= F_PW_STATUSTLV_CONF;
+ else
+ pw->flags &= ~F_PW_STATUSTLV_CONF;
+
+ ldp_reload(vty_conf);
+
+ return (CMD_SUCCESS);
+}
+
+void
+ldp_vty_if_init(void)
+{
+ /* Install interface node. */
+ install_node (&interface_node, interface_config_write);
+
+ install_element(CONFIG_NODE, &interface_cmd);
+ install_element(CONFIG_NODE, &no_interface_cmd);
+ install_default(INTERFACE_NODE);
+
+ /* "description" commands. */
+ install_element(INTERFACE_NODE, &interface_desc_cmd);
+ install_element(INTERFACE_NODE, &no_interface_desc_cmd);
+}
diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
new file mode 100644
index 000000000..a57cf3c3f
--- /dev/null
+++ b/ldpd/ldp_vty_exec.c
@@ -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);
+}
diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c
new file mode 100644
index 000000000..41ff47fba
--- /dev/null
+++ b/ldpd/ldp_zebra.c
@@ -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;
+}
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 4e1449198..1eaa7df4a 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -19,36 +19,40 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/types.h>
+#include <zebra.h>
#include <sys/wait.h>
-#include <err.h>
-#include <errno.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
#include "ldpd.h"
#include "ldpe.h"
#include "lde.h"
#include "log.h"
-
-static void main_sig_handler(int, short, void *);
-static __dead void usage(void);
-static __dead void ldpd_shutdown(void);
-static pid_t start_child(enum ldpd_process, char *, int, int, int);
-static void main_dispatch_ldpe(int, short, void *);
-static void main_dispatch_lde(int, short, void *);
-static int main_imsg_compose_both(enum imsg_type, void *,
- uint16_t);
+#include "ldp_vty.h"
+#include "ldp_debug.h"
+
+#include <lib/version.h>
+#include <lib/log.h>
+#include "getopt.h"
+#include "vty.h"
+#include "command.h"
+#include "memory.h"
+#include "privs.h"
+#include "sigevent.h"
+#include "zclient.h"
+#include "vrf.h"
+
+static void ldpd_shutdown(void);
+static pid_t start_child(enum ldpd_process, char *, int,
+ const char *, const char *);
+static int main_dispatch_ldpe(struct thread *);
+static int main_dispatch_lde(struct thread *);
static int main_imsg_send_ipc_sockets(struct imsgbuf *,
struct imsgbuf *);
static void main_imsg_send_net_sockets(int);
static void main_imsg_send_net_socket(int, enum socket_type);
static int main_imsg_send_config(struct ldpd_conf *);
-static int ldp_reload(void);
+static void ldp_config_normalize(struct ldpd_conf *);
+static void ldp_config_reset_main(struct ldpd_conf *);
+static void ldp_config_reset_af(struct ldpd_conf *, int);
static void merge_global(struct ldpd_conf *, struct ldpd_conf *);
static void merge_af(int, struct ldpd_af_conf *,
struct ldpd_af_conf *);
@@ -63,84 +67,216 @@ static void merge_l2vpn(struct ldpd_conf *, struct l2vpn *,
struct ldpd_global global;
struct ldpd_conf *ldpd_conf;
-static char *conffile;
static struct imsgev *iev_ldpe;
static struct imsgev *iev_lde;
static pid_t ldpe_pid;
static pid_t lde_pid;
-/* ARGSUSED */
-static void
-main_sig_handler(int sig, short event, void *arg)
+#define LDP_DEFAULT_CONFIG "ldpd.conf"
+#define LDP_VTY_PORT 2612
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* Process ID saved for use by init system */
+static const char *pid_file = PATH_LDPD_PID;
+
+/* Configuration filename and directory. */
+static char config_default[] = SYSCONFDIR LDP_DEFAULT_CONFIG;
+
+/* ldpd privileges */
+static zebra_capabilities_t _caps_p [] =
{
- /* signal handler rules don't apply, libevent decouples for us */
- switch (sig) {
- case SIGTERM:
- case SIGINT:
- ldpd_shutdown();
- /* NOTREACHED */
- case SIGHUP:
- if (ldp_reload() == -1)
- log_warnx("configuration reload failed");
- else
- log_debug("configuration reloaded");
- break;
- default:
- fatalx("unexpected signal");
- /* NOTREACHED */
+ ZCAP_BIND,
+ ZCAP_NET_ADMIN
+};
+
+struct zebra_privs_t ldpd_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
+};
+
+/* LDPd options. */
+static struct option longopts[] =
+{
+ { "daemon", no_argument, NULL, 'd'},
+ { "config_file", required_argument, NULL, 'f'},
+ { "pid_file", required_argument, NULL, 'i'},
+ { "socket", required_argument, NULL, 'z'},
+ { "dryrun", no_argument, NULL, 'C'},
+ { "help", no_argument, NULL, 'h'},
+ { "vty_addr", required_argument, NULL, 'A'},
+ { "vty_port", required_argument, NULL, 'P'},
+ { "user", required_argument, NULL, 'u'},
+ { "group", required_argument, NULL, 'g'},
+ { "version", no_argument, NULL, 'v'},
+ { 0 }
+};
+
+/* Help information display. */
+static void __attribute__ ((noreturn))
+usage(char *progname, int status)
+{
+ if (status != 0)
+ fprintf(stderr, "Try `%s --help' for more information.\n",
+ progname);
+ else {
+ printf("Usage : %s [OPTION...]\n\
+Daemon which manages LDP.\n\n\
+-d, --daemon Runs in daemon mode\n\
+-f, --config_file Set configuration file name\n\
+-i, --pid_file Set process identifier file name\n\
+-z, --socket Set path of zebra socket\n\
+-A, --vty_addr Set vty's bind address\n\
+-P, --vty_port Set vty's port number\n\
+-u, --user User to run as\n\
+-g, --group Group to run as\n\
+-v, --version Print program version\n\
+-C, --dryrun Check configuration for validity and exit\n\
+-h, --help Display this help and exit\n\
+\n\
+Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);
}
+
+ exit(status);
}
-static __dead void
-usage(void)
+/* SIGHUP handler. */
+static void
+sighup(void)
{
- extern char *__progname;
+ log_info("SIGHUP received");
+}
+
+/* SIGINT / SIGTERM handler. */
+static void
+sigint(void)
+{
+ log_info("SIGINT received");
+ ldpd_shutdown();
+}
- fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
- __progname);
- exit(1);
+/* SIGUSR1 handler. */
+static void
+sigusr1(void)
+{
+ zlog_rotate(NULL);
}
+static struct quagga_signal_t ldp_signals[] =
+{
+ {
+ .signal = SIGHUP,
+ .handler = &sighup,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ }
+};
+
int
main(int argc, char *argv[])
{
- struct event ev_sigint, ev_sigterm, ev_sighup;
char *saved_argv0;
- int ch;
- int debug = 0, lflag = 0, eflag = 0;
+ int lflag = 0, eflag = 0;
int pipe_parent2ldpe[2];
int pipe_parent2lde[2];
+ char *p;
+ char *vty_addr = NULL;
+ int vty_port = LDP_VTY_PORT;
+ int daemon_mode = 0;
+ const char *user = NULL;
+ const char *group = NULL;
+ char *config_file = NULL;
+ char *progname;
+ struct thread thread;
+ int dryrun = 0;
- conffile = CONF_FILE;
ldpd_process = PROC_MAIN;
- log_init(1); /* log to stderr until daemonized */
- log_verbose(1);
+ /* Set umask before anything for security */
+ umask(0027);
+
+ /* get program name */
+ progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
saved_argv0 = argv[0];
if (saved_argv0 == NULL)
- saved_argv0 = "ldpd";
+ saved_argv0 = (char *)"ldpd";
- while ((ch = getopt(argc, argv, "dD:f:nvLE")) != -1) {
- switch (ch) {
- case 'd':
- debug = 1;
+ while (1) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:vCLE",
+ longopts, 0);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt) {
+ case 0:
break;
- case 'D':
- if (cmdline_symset(optarg) < 0)
- log_warnx("could not parse macro definition %s",
- optarg);
+ case 'd':
+ daemon_mode = 1;
break;
case 'f':
- conffile = optarg;
+ config_file = optarg;
+ break;
+ case 'A':
+ vty_addr = optarg;
+ break;
+ case 'i':
+ pid_file = optarg;
+ break;
+ case 'z':
+ zclient_serv_path_set(optarg);
+ break;
+ case 'P':
+ /*
+ * Deal with atoi() returning 0 on failure, and ldpd
+ * not listening on ldpd port.
+ */
+ if (strcmp(optarg, "0") == 0) {
+ vty_port = 0;
+ break;
+ }
+ vty_port = atoi(optarg);
+ if (vty_port <= 0 || vty_port > 0xffff)
+ vty_port = LDP_VTY_PORT;
+ break;
+ case 'u':
+ user = optarg;
break;
- case 'n':
- global.cmd_opts |= LDPD_OPT_NOACTION;
+ case 'g':
+ group = optarg;
break;
case 'v':
- if (global.cmd_opts & LDPD_OPT_VERBOSE)
- global.cmd_opts |= LDPD_OPT_VERBOSE2;
- global.cmd_opts |= LDPD_OPT_VERBOSE;
+ print_version(progname);
+ exit(0);
+ break;
+ case 'C':
+ dryrun = 1;
+ break;
+ case 'h':
+ usage(progname, 0);
break;
case 'L':
lflag = 1;
@@ -149,125 +285,132 @@ main(int argc, char *argv[])
eflag = 1;
break;
default:
- usage();
- /* NOTREACHED */
+ usage(progname, 1);
+ break;
}
}
argc -= optind;
argv += optind;
if (argc > 0 || (lflag && eflag))
- usage();
-
- if (lflag)
- lde(debug, global.cmd_opts & LDPD_OPT_VERBOSE);
- else if (eflag)
- ldpe(debug, global.cmd_opts & LDPD_OPT_VERBOSE);
+ usage(progname, 1);
- /* fetch interfaces early */
- kif_init();
-
- /* parse config file */
- if ((ldpd_conf = parse_config(conffile)) == NULL ) {
- kif_clear();
+ /* check for root privileges */
+ if (geteuid() != 0) {
+ errno = EPERM;
+ perror(progname);
exit(1);
}
- if (global.cmd_opts & LDPD_OPT_NOACTION) {
- if (global.cmd_opts & LDPD_OPT_VERBOSE)
- print_config(ldpd_conf);
- else
- fprintf(stderr, "configuration OK\n");
- kif_clear();
- exit(0);
- }
+ zlog_default = openzlog(progname, ZLOG_LDP, 0,
+ LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
- /* check for root privileges */
- if (geteuid())
- errx(1, "need root privileges");
+ if (lflag)
+ lde(user, group);
+ else if (eflag)
+ ldpe(user, group);
- /* check for ldpd user */
- if (getpwnam(LDPD_USER) == NULL)
- errx(1, "unknown user %s", LDPD_USER);
+ master = thread_master_create();
- log_init(debug);
- log_verbose(global.cmd_opts & (LDPD_OPT_VERBOSE | LDPD_OPT_VERBOSE2));
+ cmd_init(1);
+ vty_init(master);
+ vrf_init();
+ ldp_vty_init();
+ ldp_vty_if_init();
- if (!debug)
- daemon(1, 0);
+ /* Get configuration file. */
+ ldpd_conf = config_new_empty();
+ ldp_config_reset_main(ldpd_conf);
+ vty_read_config(config_file, config_default);
+
+ /* Start execution only if not in dry-run mode */
+ if (dryrun)
+ exit(0);
- log_info("startup");
+ if (daemon_mode && daemon(0, 0) < 0) {
+ log_warn("LDPd daemon failed");
+ exit(1);
+ }
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
- PF_UNSPEC, pipe_parent2ldpe) == -1)
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1)
fatal("socketpair");
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
- PF_UNSPEC, pipe_parent2lde) == -1)
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1)
fatal("socketpair");
+ sock_set_nonblock(pipe_parent2ldpe[0]);
+ sock_set_cloexec(pipe_parent2ldpe[0]);
+ sock_set_nonblock(pipe_parent2ldpe[1]);
+ sock_set_cloexec(pipe_parent2ldpe[1]);
+ sock_set_nonblock(pipe_parent2lde[0]);
+ sock_set_cloexec(pipe_parent2lde[0]);
+ sock_set_nonblock(pipe_parent2lde[1]);
+ sock_set_cloexec(pipe_parent2lde[1]);
/* start children */
lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0,
- pipe_parent2lde[1], debug, global.cmd_opts & LDPD_OPT_VERBOSE);
+ pipe_parent2lde[1], user, group);
ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0,
- pipe_parent2ldpe[1], debug, global.cmd_opts & LDPD_OPT_VERBOSE);
+ pipe_parent2ldpe[1], user, group);
- event_init();
+ /* drop privileges */
+ if (user)
+ ldpd_privs.user = user;
+ if (group)
+ ldpd_privs.group = group;
+ zprivs_init(&ldpd_privs);
/* setup signal handler */
- signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL);
- signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL);
- signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL);
- signal_add(&ev_sigint, NULL);
- signal_add(&ev_sigterm, NULL);
- signal_add(&ev_sighup, NULL);
- signal(SIGPIPE, SIG_IGN);
+ signal_init(master, array_size(ldp_signals), ldp_signals);
+
+ /* library inits */
+ ldp_zebra_init(master);
/* setup pipes to children */
if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL ||
(iev_lde = malloc(sizeof(struct imsgev))) == NULL)
fatal(NULL);
imsg_init(&iev_ldpe->ibuf, pipe_parent2ldpe[0]);
- iev_ldpe->handler = main_dispatch_ldpe;
- imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]);
- iev_lde->handler = main_dispatch_lde;
+ iev_ldpe->handler_read = main_dispatch_ldpe;
+ 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;
- /* setup event handler */
- 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_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);
+ imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]);
+ iev_lde->handler_read = main_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;
if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf))
fatal("could not establish imsg links");
+ main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug,
+ sizeof(ldp_debug));
main_imsg_send_config(ldpd_conf);
- /* notify ldpe about existing interfaces and addresses */
- kif_redistribute(NULL);
-
- if (kr_init(!(ldpd_conf->flags & F_LDPD_NO_FIB_UPDATE)) == -1)
- fatalx("kr_init failed");
-
if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)
main_imsg_send_net_sockets(AF_INET);
if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)
main_imsg_send_net_sockets(AF_INET6);
- /* remove unneded stuff from config */
- /* ... */
+ /* Process id file create. */
+ pid_output(pid_file);
- event_dispatch();
+ /* Create VTY socket */
+ vty_serv_sock(vty_addr, vty_port, LDP_VTYSH_PATH);
+
+ /* Print banner. */
+ log_notice("LDPd %s starting: vty@%d", QUAGGA_VERSION, vty_port);
+
+ /* Fetch next active thread. */
+ while (thread_fetch(master, &thread))
+ thread_call(&thread);
- ldpd_shutdown();
/* NOTREACHED */
return (0);
}
-static __dead void
+static void
ldpd_shutdown(void)
{
pid_t pid;
@@ -279,7 +422,6 @@ ldpd_shutdown(void)
msgbuf_clear(&iev_lde->ibuf.w);
close(iev_lde->ibuf.fd);
- kr_shutdown();
config_clear(ldpd_conf);
log_debug("waiting for children to terminate");
@@ -302,9 +444,10 @@ ldpd_shutdown(void)
}
static pid_t
-start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose)
+start_child(enum ldpd_process p, char *argv0, int fd, const char *user,
+ const char *group)
{
- char *argv[5];
+ char *argv[7];
int argc = 0;
pid_t pid;
@@ -326,16 +469,20 @@ start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose)
case PROC_MAIN:
fatalx("Can not start main process");
case PROC_LDE_ENGINE:
- argv[argc++] = "-L";
+ argv[argc++] = (char *)"-L";
break;
case PROC_LDP_ENGINE:
- argv[argc++] = "-E";
+ argv[argc++] = (char *)"-E";
break;
}
- if (debug)
- argv[argc++] = "-d";
- if (verbose)
- argv[argc++] = "-v";
+ if (user) {
+ argv[argc++] = (char *)"-u";
+ argv[argc++] = (char *)user;
+ }
+ if (group) {
+ argv[argc++] = (char *)"-g";
+ argv[argc++] = (char *)group;
+ }
argv[argc++] = NULL;
execvp(argv0, argv);
@@ -344,28 +491,22 @@ start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose)
/* imsg handling */
/* ARGSUSED */
-static void
-main_dispatch_ldpe(int fd, short event, void *bula)
+static int
+main_dispatch_ldpe(struct thread *thread)
{
- struct imsgev *iev = bula;
+ struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
int af;
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)
- 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)
@@ -375,39 +516,13 @@ main_dispatch_ldpe(int fd, short event, void *bula)
break;
switch (imsg.hdr.type) {
+ case IMSG_LOG:
+ logit(imsg.hdr.pid, "%s", (const char *)imsg.data);
+ break;
case IMSG_REQUEST_SOCKETS:
af = imsg.hdr.pid;
main_imsg_send_net_sockets(af);
break;
- case IMSG_CTL_RELOAD:
- if (ldp_reload() == -1)
- log_warnx("configuration reload failed");
- else
- log_debug("configuration reloaded");
- break;
- case IMSG_CTL_FIB_COUPLE:
- kr_fib_couple();
- break;
- case IMSG_CTL_FIB_DECOUPLE:
- kr_fib_decouple();
- break;
- case IMSG_CTL_KROUTE:
- case IMSG_CTL_KROUTE_ADDR:
- kr_show_route(&imsg);
- break;
- case IMSG_CTL_IFINFO:
- if (imsg.hdr.len == IMSG_HEADER_SIZE)
- kr_ifinfo(NULL, imsg.hdr.pid);
- else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ)
- kr_ifinfo(imsg.data, imsg.hdr.pid);
- else
- log_warnx("IFINFO request with wrong len");
- break;
- case IMSG_CTL_LOG_VERBOSE:
- /* already checked by ldpe */
- memcpy(&verbose, imsg.data, sizeof(verbose));
- log_verbose(verbose);
- break;
default:
log_debug("%s: error handling imsg %d", __func__,
imsg.hdr.type);
@@ -418,34 +533,35 @@ main_dispatch_ldpe(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_pid = 0;
+ if (lde_pid == 0)
+ ldpd_shutdown();
+ else
+ kill(lde_pid, SIGTERM);
}
+
+ return (0);
}
/* ARGSUSED */
-static void
-main_dispatch_lde(int fd, short event, void *bula)
+static int
+main_dispatch_lde(struct thread *thread)
{
- struct imsgev *iev = bula;
+ struct imsgev *iev = THREAD_ARG(thread);
struct imsgbuf *ibuf = &iev->ibuf;
struct imsg imsg;
ssize_t n;
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)
- 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)
@@ -455,6 +571,9 @@ main_dispatch_lde(int fd, short event, void *bula)
break;
switch (imsg.hdr.type) {
+ case IMSG_LOG:
+ logit(imsg.hdr.pid, "%s", (const char *)imsg.data);
+ break;
case IMSG_KLABEL_CHANGE:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct kroute))
@@ -495,10 +614,41 @@ main_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);
+ lde_pid = 0;
+ if (ldpe_pid == 0)
+ ldpd_shutdown();
+ else
+ kill(ldpe_pid, SIGTERM);
}
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+ldp_write_handler(struct thread *thread)
+{
+ struct imsgev *iev = THREAD_ARG(thread);
+ struct imsgbuf *ibuf = &iev->ibuf;
+ ssize_t n;
+
+ iev->ev_write = NULL;
+
+ if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0) {
+ /* this pipe is dead, so remove the event handlers */
+ THREAD_READ_OFF(iev->ev_read);
+ THREAD_WRITE_OFF(iev->ev_write);
+ return (0);
+ }
+
+ imsg_event_add(iev);
+
+ return (0);
}
void
@@ -515,9 +665,11 @@ main_imsg_compose_lde(int type, pid_t pid, void *data, uint16_t datalen)
imsg_compose_event(iev_lde, type, 0, pid, -1, data, datalen);
}
-static int
+int
main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len)
{
+ if (iev_ldpe == NULL || iev_lde == NULL)
+ return (0);
if (imsg_compose_event(iev_ldpe, type, 0, 0, -1, buf, len) == -1)
return (-1);
if (imsg_compose_event(iev_lde, type, 0, 0, -1, buf, len) == -1)
@@ -528,13 +680,12 @@ main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len)
void
imsg_event_add(struct imsgev *iev)
{
- iev->events = EV_READ;
- if (iev->ibuf.w.queued)
- iev->events |= EV_WRITE;
+ THREAD_READ_ON(master, iev->ev_read, iev->handler_read, iev,
+ iev->ibuf.fd);
- event_del(&iev->ev);
- event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev);
- event_add(&iev->ev, NULL);
+ if (iev->ibuf.w.queued)
+ THREAD_WRITE_ON(master, iev->ev_write, iev->handler_write, iev,
+ iev->ibuf.fd);
}
int
@@ -560,22 +711,24 @@ void
evbuf_event_add(struct evbuf *eb)
{
if (eb->wbuf.queued)
- event_add(&eb->ev, NULL);
+ THREAD_WRITE_ON(master, eb->ev, eb->handler, eb->arg,
+ eb->wbuf.fd);
}
void
-evbuf_init(struct evbuf *eb, int fd, void (*handler)(int, short, void *),
+evbuf_init(struct evbuf *eb, int fd, int (*handler)(struct thread *),
void *arg)
{
msgbuf_init(&eb->wbuf);
eb->wbuf.fd = fd;
- event_set(&eb->ev, eb->wbuf.fd, EV_WRITE, handler, arg);
+ eb->handler = handler;
+ eb->arg = arg;
}
void
evbuf_clear(struct evbuf *eb)
{
- event_del(&eb->ev);
+ THREAD_WRITE_OFF(eb->ev);
msgbuf_clear(&eb->wbuf);
eb->wbuf.fd = -1;
}
@@ -585,9 +738,10 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf)
{
int pipe_ldpe2lde[2];
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- PF_UNSPEC, pipe_ldpe2lde) == -1)
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_ldpe2lde) == -1)
return (-1);
+ sock_set_nonblock(pipe_ldpe2lde[0]);
+ sock_set_nonblock(pipe_ldpe2lde[1]);
if (imsg_compose(ldpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_ldpe2lde[0],
NULL, 0) == -1)
@@ -602,6 +756,9 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf)
static void
main_imsg_send_net_sockets(int af)
{
+ if (!ldp_addrisset(af, &(ldp_af_conf_get(ldpd_conf, af))->trans_addr))
+ return;
+
main_imsg_send_net_socket(af, LDP_SOCKET_DISC);
main_imsg_send_net_socket(af, LDP_SOCKET_EDISC);
main_imsg_send_net_socket(af, LDP_SOCKET_SESSION);
@@ -657,6 +814,15 @@ ldp_is_dual_stack(struct ldpd_conf *xconf)
(xconf->ipv6.flags & F_LDPD_AF_ENABLED));
}
+in_addr_t
+ldp_rtr_id_get(struct ldpd_conf *xconf)
+{
+ if (xconf->rtr_id.s_addr != INADDR_ANY)
+ return (xconf->rtr_id.s_addr);
+ else
+ return (global.rtr_id.s_addr);
+}
+
static int
main_imsg_send_config(struct ldpd_conf *xconf)
{
@@ -704,6 +870,11 @@ main_imsg_send_config(struct ldpd_conf *xconf)
sizeof(*pw)) == -1)
return (-1);
}
+ LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) {
+ if (main_imsg_compose_both(IMSG_RECONF_L2VPN_IPW, pw,
+ sizeof(*pw)) == -1)
+ return (-1);
+ }
}
if (main_imsg_compose_both(IMSG_RECONF_END, NULL, 0) == -1)
@@ -712,13 +883,10 @@ main_imsg_send_config(struct ldpd_conf *xconf)
return (0);
}
-static int
-ldp_reload(void)
+int
+ldp_reload(struct ldpd_conf *xconf)
{
- struct ldpd_conf *xconf;
-
- if ((xconf = parse_config(conffile)) == NULL)
- return (-1);
+ ldp_config_normalize(xconf);
if (main_imsg_send_config(xconf) == -1)
return (-1);
@@ -728,6 +896,205 @@ ldp_reload(void)
return (0);
}
+static void
+ldp_config_normalize(struct ldpd_conf *xconf)
+{
+ struct l2vpn *l2vpn;
+ struct l2vpn_pw *pw;
+
+ if (!(xconf->flags & F_LDPD_ENABLED))
+ ldp_config_reset_main(xconf);
+ else {
+ if (!(xconf->ipv4.flags & F_LDPD_AF_ENABLED))
+ ldp_config_reset_af(xconf, AF_INET);
+ if (!(xconf->ipv6.flags & F_LDPD_AF_ENABLED))
+ ldp_config_reset_af(xconf, AF_INET6);
+ }
+
+ LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) {
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
+ if (pw->flags & F_PW_STATIC_NBR_ADDR)
+ continue;
+
+ pw->af = AF_INET;
+ pw->addr.v4 = pw->lsr_id;
+ }
+ LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) {
+ if (pw->flags & F_PW_STATIC_NBR_ADDR)
+ continue;
+
+ pw->af = AF_INET;
+ pw->addr.v4 = pw->lsr_id;
+ }
+ }
+}
+
+static void
+ldp_config_reset_main(struct ldpd_conf *conf)
+{
+ struct iface *iface;
+ struct nbr_params *nbrp;
+
+ while ((iface = LIST_FIRST(&conf->iface_list)) != NULL) {
+ LIST_REMOVE(iface, entry);
+ free(iface);
+ }
+
+ while ((nbrp = LIST_FIRST(&conf->nbrp_list)) != NULL) {
+ LIST_REMOVE(nbrp, entry);
+ free(nbrp);
+ }
+
+ conf->rtr_id.s_addr = INADDR_ANY;
+ ldp_config_reset_af(conf, AF_INET);
+ ldp_config_reset_af(conf, AF_INET6);
+ conf->lhello_holdtime = LINK_DFLT_HOLDTIME;
+ conf->lhello_interval = DEFAULT_HELLO_INTERVAL;
+ conf->thello_holdtime = TARGETED_DFLT_HOLDTIME;
+ conf->thello_interval = DEFAULT_HELLO_INTERVAL;
+ conf->trans_pref = DUAL_STACK_LDPOV6;
+ conf->flags = 0;
+}
+
+static void
+ldp_config_reset_af(struct ldpd_conf *conf, int af)
+{
+ struct ldpd_af_conf *af_conf;
+ struct iface *iface;
+ struct iface_af *ia;
+ struct tnbr *tnbr, *ttmp;
+
+ LIST_FOREACH(iface, &conf->iface_list, entry) {
+ ia = iface_af_get(iface, af);
+ ia->enabled = 0;
+ }
+
+ LIST_FOREACH_SAFE(tnbr, &conf->tnbr_list, entry, ttmp) {
+ if (tnbr->af != af)
+ continue;
+
+ LIST_REMOVE(tnbr, entry);
+ free(tnbr);
+ }
+
+ af_conf = ldp_af_conf_get(conf, af);
+ af_conf->keepalive = 180;
+ af_conf->lhello_holdtime = 0;
+ af_conf->lhello_interval = 0;
+ af_conf->thello_holdtime = 0;
+ af_conf->thello_interval = 0;
+ memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr));
+ af_conf->flags = 0;
+}
+
+struct ldpd_conf *
+ldp_dup_config(struct ldpd_conf *conf)
+{
+ struct ldpd_conf *xconf;
+ struct iface *iface, *xi;
+ struct tnbr *tnbr, *xt;
+ struct nbr_params *nbrp, *xn;
+ struct l2vpn *l2vpn, *xl;
+ struct l2vpn_if *lif, *xf;
+ struct l2vpn_pw *pw, *xp;
+
+ xconf = malloc(sizeof(*xconf));
+ *xconf = *conf;
+ LIST_INIT(&xconf->iface_list);
+ LIST_INIT(&xconf->tnbr_list);
+ LIST_INIT(&xconf->nbrp_list);
+ LIST_INIT(&xconf->l2vpn_list);
+
+ LIST_FOREACH(iface, &conf->iface_list, entry) {
+ xi = calloc(1, sizeof(*xi));
+ if (xi == NULL)
+ fatal(__func__);
+ *xi = *iface;
+ xi->ipv4.iface = xi;
+ xi->ipv6.iface = xi;
+ LIST_INSERT_HEAD(&xconf->iface_list, xi, entry);
+ }
+ LIST_FOREACH(tnbr, &conf->tnbr_list, entry) {
+ xt = calloc(1, sizeof(*xt));
+ if (xt == NULL)
+ fatal(__func__);
+ *xt = *tnbr;
+ LIST_INSERT_HEAD(&xconf->tnbr_list, xt, entry);
+ }
+ LIST_FOREACH(nbrp, &conf->nbrp_list, entry) {
+ xn = calloc(1, sizeof(*xn));
+ if (xn == NULL)
+ fatal(__func__);
+ *xn = *nbrp;
+ LIST_INSERT_HEAD(&xconf->nbrp_list, xn, entry);
+ }
+ LIST_FOREACH(l2vpn, &conf->l2vpn_list, entry) {
+ xl = calloc(1, sizeof(*xl));
+ if (xl == NULL)
+ fatal(__func__);
+ *xl = *l2vpn;
+ LIST_INIT(&xl->if_list);
+ LIST_INIT(&xl->pw_list);
+ LIST_INIT(&xl->pw_inactive_list);
+ LIST_INSERT_HEAD(&xconf->l2vpn_list, xl, entry);
+
+ LIST_FOREACH(lif, &l2vpn->if_list, entry) {
+ xf = calloc(1, sizeof(*xf));
+ if (xf == NULL)
+ fatal(__func__);
+ *xf = *lif;
+ xf->l2vpn = xl;
+ LIST_INSERT_HEAD(&xl->if_list, xf, entry);
+ }
+ LIST_FOREACH(pw, &l2vpn->pw_list, entry) {
+ xp = calloc(1, sizeof(*xp));
+ if (xp == NULL)
+ fatal(__func__);
+ *xp = *pw;
+ xp->l2vpn = xl;
+ LIST_INSERT_HEAD(&xl->pw_list, xp, entry);
+ }
+ LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) {
+ xp = calloc(1, sizeof(*xp));
+ if (xp == NULL)
+ fatal(__func__);
+ *xp = *pw;
+ xp->l2vpn = xl;
+ LIST_INSERT_HEAD(&xl->pw_inactive_list, xp, entry);
+ }
+ }
+
+ return (xconf);
+}
+
+void
+ldp_clear_config(struct ldpd_conf *xconf)
+{
+ struct iface *iface;
+ struct tnbr *tnbr;
+ struct nbr_params *nbrp;
+ struct l2vpn *l2vpn;
+
+ while ((iface = LIST_FIRST(&xconf->iface_list)) != NULL) {
+ LIST_REMOVE(iface, entry);
+ free(iface);
+ }
+ while ((tnbr = LIST_FIRST(&xconf->tnbr_list)) != NULL) {
+ LIST_REMOVE(tnbr, entry);
+ free(tnbr);
+ }
+ while ((nbrp = LIST_FIRST(&xconf->nbrp_list)) != NULL) {
+ LIST_REMOVE(nbrp, entry);
+ free(nbrp);
+ }
+ while ((l2vpn = LIST_FIRST(&xconf->l2vpn_list)) != NULL) {
+ LIST_REMOVE(l2vpn, entry);
+ l2vpn_del(l2vpn);
+ }
+
+ free(xconf);
+}
+
void
merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)
{
@@ -758,6 +1125,11 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)
conf->rtr_id = xconf->rtr_id;
}
+ conf->lhello_holdtime = xconf->lhello_holdtime;
+ conf->lhello_interval = xconf->lhello_interval;
+ conf->thello_holdtime = xconf->thello_holdtime;
+ conf->thello_interval = xconf->thello_interval;
+
if (conf->trans_pref != xconf->trans_pref) {
if (ldpd_process == PROC_LDP_ENGINE)
ldpe_reset_ds_nbrs();
@@ -784,6 +1156,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
if (ldpd_process == PROC_LDP_ENGINE)
ldpe_stop_init_backoff(af);
}
+
+ af_conf->lhello_holdtime = xa->lhello_holdtime;
+ af_conf->lhello_interval = xa->lhello_interval;
af_conf->thello_holdtime = xa->thello_holdtime;
af_conf->thello_interval = xa->thello_interval;
@@ -815,10 +1190,6 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
lde_change_egress_label(af, af_conf->flags &
F_LDPD_AF_EXPNULL);
break;
- case PROC_MAIN:
- kr_change_egress_label(af, af_conf->flags &
- F_LDPD_AF_EXPNULL);
- break;
default:
break;
}
@@ -829,7 +1200,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)
update_sockets = 1;
}
- if (ldpd_process == PROC_MAIN && update_sockets)
+ if (ldpd_process == PROC_MAIN && iev_ldpe && update_sockets)
imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, 0, -1,
NULL, 0);
}
@@ -841,7 +1212,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
LIST_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) {
/* find deleted interfaces */
- if ((xi = if_lookup(xconf, iface->ifindex)) == NULL) {
+ if ((xi = if_lookup_name(xconf, iface->name)) == NULL) {
LIST_REMOVE(iface, entry);
if (ldpd_process == PROC_LDP_ENGINE)
if_exit(iface);
@@ -850,7 +1221,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)
}
LIST_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) {
/* find new interfaces */
- if ((iface = if_lookup(conf, xi->ifindex)) == NULL) {
+ if ((iface = if_lookup_name(conf, xi->name)) == NULL) {
LIST_REMOVE(xi, entry);
LIST_INSERT_HEAD(&conf->iface_list, xi, entry);
@@ -914,8 +1285,6 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)
/* update existing tnbrs */
if (!(tnbr->flags & F_TNBR_CONFIGURED))
tnbr->flags |= F_TNBR_CONFIGURED;
- tnbr->hello_holdtime = xt->hello_holdtime;
- tnbr->hello_interval = xt->hello_interval;
LIST_REMOVE(xt, entry);
free(xt);
}
@@ -935,7 +1304,14 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);
if (nbr) {
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
+#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_session_active_role(nbr))
nbr_establish_connection(nbr);
}
@@ -954,8 +1330,16 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
nbr = nbr_find_ldpid(xn->lsr_id.s_addr);
if (nbr) {
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
+#ifdef __OpenBSD__
if (pfkey_establish(nbr, xn) == -1)
fatalx("pfkey setup failed");
+#else
+ sock_set_md5sig(
+ (ldp_af_global_get(&global,
+ nbr->af))->ldp_session_socket,
+ nbr->af, &nbr->raddr,
+ xn->auth.md5key);
+#endif
if (nbr_session_active_role(nbr))
nbr_establish_connection(nbr);
}
@@ -987,9 +1371,15 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)
nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);
if (nbr && nbrp_changed) {
session_shutdown(nbr, S_SHUTDOWN, 0, 0);
+#ifdef __OpenBSD__
pfkey_remove(nbr);
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
if (nbr_session_active_role(nbr))
nbr_establish_connection(nbr);
}
@@ -1055,6 +1445,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
struct l2vpn_pw *pw, *ptmp, *xp;
struct nbr *nbr;
int reset_nbr, reinstall_pwfec, reinstall_tnbr;
+ LIST_HEAD(, l2vpn_pw) pw_aux_list;
int previous_pw_type, previous_mtu;
previous_pw_type = l2vpn->pw_type;
@@ -1063,14 +1454,14 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
/* merge intefaces */
LIST_FOREACH_SAFE(lif, &l2vpn->if_list, entry, ftmp) {
/* find deleted interfaces */
- if ((xf = l2vpn_if_find(xl, lif->ifindex)) == NULL) {
+ if ((xf = l2vpn_if_find_name(xl, lif->ifname)) == NULL) {
LIST_REMOVE(lif, entry);
free(lif);
}
}
LIST_FOREACH_SAFE(xf, &xl->if_list, entry, ftmp) {
/* find new interfaces */
- if ((lif = l2vpn_if_find(l2vpn, xf->ifindex)) == NULL) {
+ if ((lif = l2vpn_if_find_name(l2vpn, xf->ifname)) == NULL) {
LIST_REMOVE(xf, entry);
LIST_INSERT_HEAD(&l2vpn->if_list, xf, entry);
xf->l2vpn = l2vpn;
@@ -1081,10 +1472,11 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
free(xf);
}
- /* merge pseudowires */
+ /* merge active pseudowires */
+ LIST_INIT(&pw_aux_list);
LIST_FOREACH_SAFE(pw, &l2vpn->pw_list, entry, ptmp) {
- /* find deleted pseudowires */
- if ((xp = l2vpn_pw_find(xl, pw->ifindex)) == NULL) {
+ /* find deleted active pseudowires */
+ if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) {
switch (ldpd_process) {
case PROC_LDE_ENGINE:
l2vpn_pw_exit(pw);
@@ -1101,8 +1493,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
}
}
LIST_FOREACH_SAFE(xp, &xl->pw_list, entry, ptmp) {
- /* find new pseudowires */
- if ((pw = l2vpn_pw_find(l2vpn, xp->ifindex)) == NULL) {
+ /* find new active pseudowires */
+ if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) {
LIST_REMOVE(xp, entry);
LIST_INSERT_HEAD(&l2vpn->pw_list, xp, entry);
xp->l2vpn = l2vpn;
@@ -1120,7 +1512,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
continue;
}
- /* update existing pseudowire */
+ /* update existing active pseudowire */
if (pw->af != xp->af ||
ldp_addrcmp(pw->af, &pw->addr, &xp->addr))
reinstall_tnbr = 1;
@@ -1141,6 +1533,28 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
else
reinstall_pwfec = 0;
+ /* check if the pseudowire should be disabled */
+ if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0) {
+ reinstall_tnbr = 0;
+ reset_nbr = 0;
+ reinstall_pwfec = 0;
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_pw_exit(pw);
+ break;
+ case PROC_LDP_ENGINE:
+ ldpe_l2vpn_pw_exit(pw);
+ break;
+ case PROC_MAIN:
+ break;
+ }
+
+ /* remove from active list */
+ LIST_REMOVE(pw, entry);
+ LIST_INSERT_HEAD(&pw_aux_list, pw, entry);
+ }
+
if (ldpd_process == PROC_LDP_ENGINE) {
if (reinstall_tnbr)
ldpe_l2vpn_pw_exit(pw);
@@ -1167,6 +1581,10 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
pw->flags |= F_PW_STATUSTLV_CONF;
else
pw->flags &= ~F_PW_STATUSTLV_CONF;
+ if (xp->flags & F_PW_STATIC_NBR_ADDR)
+ pw->flags |= F_PW_STATIC_NBR_ADDR;
+ else
+ pw->flags &= ~F_PW_STATIC_NBR_ADDR;
if (ldpd_process == PROC_LDP_ENGINE && reinstall_tnbr)
ldpe_l2vpn_pw_init(pw);
if (ldpd_process == PROC_LDE_ENGINE &&
@@ -1182,6 +1600,60 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)
free(xp);
}
+ /* merge inactive pseudowires */
+ LIST_FOREACH_SAFE(pw, &l2vpn->pw_inactive_list, entry, ptmp) {
+ /* find deleted inactive pseudowires */
+ if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) {
+ LIST_REMOVE(pw, entry);
+ free(pw);
+ }
+ }
+ LIST_FOREACH_SAFE(xp, &xl->pw_inactive_list, entry, ptmp) {
+ /* find new inactive pseudowires */
+ if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) {
+ LIST_REMOVE(xp, entry);
+ LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, xp, entry);
+ xp->l2vpn = l2vpn;
+ continue;
+ }
+
+ /* update existing inactive pseudowire */
+ pw->lsr_id.s_addr = xp->lsr_id.s_addr;
+ pw->af = xp->af;
+ pw->addr = xp->addr;
+ pw->pwid = xp->pwid;
+ strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname));
+ pw->ifindex = xp->ifindex;
+ pw->flags = xp->flags;
+
+ /* check if the pseudowire should be activated */
+ if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0) {
+ /* remove from inactive list */
+ LIST_REMOVE(pw, entry);
+ LIST_INSERT_HEAD(&l2vpn->pw_list, pw, entry);
+
+ switch (ldpd_process) {
+ case PROC_LDE_ENGINE:
+ l2vpn_pw_init(pw);
+ break;
+ case PROC_LDP_ENGINE:
+ ldpe_l2vpn_pw_init(pw);
+ break;
+ case PROC_MAIN:
+ break;
+ }
+ }
+
+ LIST_REMOVE(xp, entry);
+ free(xp);
+ }
+
+ /* insert pseudowires that were disabled in the inactive list */
+ LIST_FOREACH_SAFE(pw, &pw_aux_list, entry, ptmp) {
+ LIST_REMOVE(pw, entry);
+ LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, pw, entry);
+ }
+
l2vpn->pw_type = xl->pw_type;
l2vpn->mtu = xl->mtu;
strlcpy(l2vpn->br_ifname, xl->br_ifname, sizeof(l2vpn->br_ifname));
diff --git a/ldpd/ldpd.conf.sample b/ldpd/ldpd.conf.sample
new file mode 100644
index 000000000..49da35c28
--- /dev/null
+++ b/ldpd/ldpd.conf.sample
@@ -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
+!
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index d32d23c6c..9601f25f7 100644
--- a/ldpd/ldpd.h
+++ b/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_ */
diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c
index 1b4d2a67e..aef33c8e3 100644
--- a/ldpd/ldpe.c
+++ b/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"
-
-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 "ldp_debug.h"
+
+#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 */
+/* Master of threads. */
+struct thread_master *master;
+
+/* ldpe privileges */
+static zebra_capabilities_t _caps_p [] =
+{
+ 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
-ldpe_sig_handler(int sig, short event, void *bula)
+sigint(void)
{
- switch (sig) {
- case SIGINT:
- case SIGTERM:
- ldpe_shutdown();
- /* NOTREACHED */
- default:
- fatalx("unexpected signal");
- }
+ 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");
-
- if (chroot(pw->pw_dir) == -1)
- fatal("chroot");
- if (chdir("/") == -1)
- fatal("chdir(\"/\")");
+ /* drop privileges */
+ if (user)
+ ldpe_privs.user = user;
+ if (group)
+ ldpe_privs.group = group;
+ zprivs_init(&ldpe_privs);
- 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);
-
- if (sysdep.no_pfkey == 0) {
- event_set(&pfkey_ev, global.pfkeysock, EV_READ | EV_PERSIST,
- ldpe_dispatch_pfkey, NULL);
- event_add(&pfkey_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;
+
+#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);
}
diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h
index e640dd67d..aab1a7fd9 100644
--- a/ldpd/ldpe.h
+++ b/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 *);
diff --git a/ldpd/log.c b/ldpd/log.c
index e14b6e51e..77efdb471 100644
--- a/ldpd/log.c
+++ b/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
@@ -138,15 +109,23 @@ log_info(const char *emsg, ...)
}
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);
-}
diff --git a/ldpd/log.h b/ldpd/log.h
index 94c463041..4d6da43ca 100644
--- a/ldpd/log.h
+++ b/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_ */
diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c
index d3f83734f..8376a0154 100644
--- a/ldpd/neighbor.c
+++ b/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;
-
- timerclear(&tv);
+ int secs;
- 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);
diff --git a/ldpd/notification.c b/ldpd/notification.c
index f30646bb8..d306361d5 100644
--- a/ldpd/notification.c
+++ b/ldpd/notification.c
@@ -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)) {
diff --git a/ldpd/packet.c b/ldpd/packet.c
index 7cc375c31..9b3151d72 100644
--- a/ldpd/packet.c
+++ b/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);
- if (bad_addr(af, &src)) {
- log_debug("%s: invalid source address: %s", __func__,
- log_addr(af, &src));
- return;
- }
-
+#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_RECVIF) {
- ifindex = ((struct sockaddr_dl *)
- CMSG_DATA(cmsg))->sdl_index;
+ 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) {
- ifindex = ((struct in6_pktinfo *)
- CMSG_DATA(cmsg))->ipi6_ifindex;
+ 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 (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);
}
diff --git a/ldpd/pfkey.c b/ldpd/pfkey.c
index f0f16c867..29f763e6a 100644
--- a/ldpd/pfkey.c
+++ b/ldpd/pfkey.c
@@ -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__ */
diff --git a/ldpd/socket.c b/ldpd/socket.c
index 8f26771df..cf352d720 100644
--- a/ldpd/socket.c
+++ b/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,6 +201,7 @@ ldp_create_socket(int af, enum socket_type type)
return (-1);
}
}
+#endif
break;
}
@@ -181,6 +209,34 @@ ldp_create_socket(int af, enum socket_type type)
}
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)
{
int bsize;
@@ -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
diff --git a/ldpd/util.c b/ldpd/util.c
index 981a5c8c2..e735263f5 100644
--- a/ldpd/util.c
+++ b/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
+}
diff --git a/lib/Makefile.am b/lib/Makefile.am
index dbb80076c..17be655a1 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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
diff --git a/lib/command.c b/lib/command.c
index cfdb91a5b..bf8b1b1d3 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -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:
diff --git a/lib/command.h b/lib/command.h
index 808e74205..7a4c53a61 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -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. */
diff --git a/lib/imsg-buffer.c b/lib/imsg-buffer.c
index 61b2c095a..a486fc17c 100644
--- a/lib/imsg-buffer.c
+++ b/lib/imsg-buffer.c
@@ -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:
diff --git a/lib/imsg.c b/lib/imsg.c
index 0c1cb8220..246430cdd 100644
--- a/lib/imsg.c
+++ b/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);
diff --git a/lib/log.c b/lib/log.c
index b9edb12fb..14fa81a9d 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -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];
diff --git a/lib/log.h b/lib/log.h
index 951fa124c..31bf2b67c 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -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);
diff --git a/lib/mpls.h b/lib/mpls.h
index 888986897..5a67b915d 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -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
diff --git a/lib/privs.c b/lib/privs.c
index 9228a56d3..6cf87c18d 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -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)
{
@@ -266,6 +260,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
exit (1);
}
}
+
+ if ( !zprivs_state.syscaps_p )
+ return;
if ( !(zprivs_state.caps = cap_init()) )
{
diff --git a/lib/route_types.txt b/lib/route_types.txt
index 8fc3092ca..0ac442d85 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -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)"
diff --git a/lib/vty.c b/lib/vty.c
index 48b64a95c..3f1350044 100644
--- a/lib/vty.c
+++ b/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;
+}
diff --git a/lib/vty.h b/lib/vty.h
index 599882a38..4f1dbe653 100644
--- a/lib/vty.h
+++ b/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 */
diff --git a/tools/xml2cli.pl b/tools/xml2cli.pl
new file mode 100755
index 000000000..43789131c
--- /dev/null
+++ b/tools/xml2cli.pl
@@ -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);
+}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 3402bf1df..e617ae28a 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -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;
}
}