]> git.proxmox.com Git - mirror_frr.git/commitdiff
ldpd: adapt the code for Quagga
authorRenato Westphal <renato@opensourcerouting.org>
Tue, 1 Mar 2016 18:31:28 +0000 (15:31 -0300)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 23 Sep 2016 13:31:09 +0000 (09:31 -0400)
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
57 files changed:
Makefile.am
configure.ac
doc/Makefile.am
doc/ldpd-basic-test-setup.md [new file with mode: 0644]
doc/ldpd.8 [new file with mode: 0644]
ldpd/.gitignore [new file with mode: 0644]
ldpd/Makefile.am [new file with mode: 0644]
ldpd/accept.c
ldpd/address.c
ldpd/adjacency.c
ldpd/control.c
ldpd/control.h
ldpd/hello.c
ldpd/init.c
ldpd/interface.c
ldpd/keepalive.c
ldpd/l2vpn.c
ldpd/labelmapping.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp.h
ldpd/ldp_debug.c [new file with mode: 0644]
ldpd/ldp_debug.h [new file with mode: 0644]
ldpd/ldp_vty.h [new file with mode: 0644]
ldpd/ldp_vty.xml [new file with mode: 0644]
ldpd/ldp_vty_cmds.c [new file with mode: 0644]
ldpd/ldp_vty_conf.c [new file with mode: 0644]
ldpd/ldp_vty_exec.c [new file with mode: 0644]
ldpd/ldp_zebra.c [new file with mode: 0644]
ldpd/ldpd.c
ldpd/ldpd.conf.sample [new file with mode: 0644]
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h
ldpd/log.c
ldpd/log.h
ldpd/neighbor.c
ldpd/notification.c
ldpd/packet.c
ldpd/pfkey.c
ldpd/socket.c
ldpd/util.c
lib/Makefile.am
lib/command.c
lib/command.h
lib/imsg-buffer.c
lib/imsg.c
lib/log.c
lib/log.h
lib/mpls.h
lib/privs.c
lib/route_types.txt
lib/vty.c
lib/vty.h
tools/xml2cli.pl [new file with mode: 0755]
zebra/zserv.c

index 1a39844cb193c5f0f8073f545722158f7f367a26..a3cbdc919c7082ef13236ce33d892c1d00b1e70c 100644 (file)
@@ -1,10 +1,10 @@
 ## Process this file with automake to produce Makefile.in.
 
-SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
+SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \
          @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
          redhat @SOLARIS@ tests tools cumulus
 
-DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
+DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d ldpd \
          isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
          solaris pimd tools cumulus
 
index 937d7b8d0f3ca38b05e35ca44388e29bda18f1e6..eb1f1de6c1852f10442c3b860ff77ea1fa999496 100755 (executable)
@@ -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
index 4a39f0b011d42f95b4a64974a23b6891b276f07d..ffb0bf46512cdde04b25a1eaab99c4a69ea1aff6 100644 (file)
@@ -87,6 +87,10 @@ if OSPFD
 man_MANS += ospfd.8
 endif
 
+if LDPD
+man_MANS += ldpd.8
+endif
+
 if RIPD
 man_MANS += ripd.8
 endif
@@ -108,7 +112,7 @@ man_MANS += zebra.8
 endif
 
 EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \
-       bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \
+       bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ldpd.8 ripd.8 \
        ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 quagga.1 \
        mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \
        mpls/opaque_lsa.txt mpls/ospfd.conf \
diff --git a/doc/ldpd-basic-test-setup.md b/doc/ldpd-basic-test-setup.md
new file mode 100644 (file)
index 0000000..e5e987f
--- /dev/null
@@ -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 (file)
index 0000000..092ff39
--- /dev/null
@@ -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 (file)
index 0000000..be90d42
--- /dev/null
@@ -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 (file)
index 0000000..c292adf
--- /dev/null
@@ -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
index bc13ad49e7c09efb145ccc1e5fa12cc3efb2c8c2..4cb461b9088686bed4126b0f23f965132b74eb01 100644 (file)
@@ -16,8 +16,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
-#include <stdlib.h>
+#include <zebra.h>
 
 #include "ldpd.h"
 #include "ldpe.h"
 
 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);
 }
index 5e95fcc2715335992c8f8459f5e7236ad6a4c322..1c4c116f216f7ecd6d1cad73a473620bd88dec35 100644 (file)
  * 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));
index 266717729fc0d214b25a681b48f507f70fea9dad..3607ee96b3a29d093006b53cf84e417d6bd70ca6 100644 (file)
  * 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 *
index b7cb3f10639813e5a3ce2bd5c5b5b258ad74ec99..ba303cc12cdf62694b4f555589f27e1b1e8eea3e 100644 (file)
  * 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"
 
 #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
index fd6e47071dbdadf327f5a85fbb7585f593de7f82..32c49fdf8760cfd7782210ea1da5bc4092a24d39 100644 (file)
@@ -19,8 +19,7 @@
 #ifndef _CONTROL_H_
 #define        _CONTROL_H_
 
-#include <sys/types.h>
-#include <sys/queue.h>
+#include "openbsd-queue.h"
 
 struct ctl_conn {
        TAILQ_ENTRY(ctl_conn)   entry;
index d0daed347da5c2f6f253343208bd1457bed0a7b1..755b25aa85e639944fe13a005bd258304f998d42 100644 (file)
  * 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);
index eb22bf52acfb13c3dd54cc6e028f272d9479d26d..ed6b53c02db95995a5b031015f0cac91d8f8e13c 100644 (file)
  * 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);
index ff4c8f169c8583b57aefacb2307fc84378f63b44..b6472fe5e8c661405c9f40225267466b8416adbe 100644 (file)
  * 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);
index 4cd49d485bbc303abcdc04ca4a7f71e6db05dd0f..f9a7d850fd2cbf1a7a6f2ade78b5d6e2e6c6d5c1 100644 (file)
  * 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);
 
index 22c98745e2b62392a0fd216202e16cd99dc4aa07..db382e484f983209a3d26ef118289e55c4f62b62 100644 (file)
  * 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);
        }
index 88e64071bbd75ee9f11b11a717d3fc942184b0fa..62f2a620d22c0c59f376f4bc40b00b19abaf3765 100644 (file)
  * 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));
 
index 8859ed25b8936c61b297cd29f14b876c3f8ae720..ae29ef6a7dab43d6bc1f543ae8d7d8f830c18c28 100644 (file)
  * 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);
 }
index b0f7b204390f09745b87abf637667fdc9eccfbb9..0fce5565a2ae21acec8bc394e51a13128b48dfda 100644 (file)
@@ -21,9 +21,8 @@
 #ifndef _LDE_H_
 #define _LDE_H_
 
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
+#include "openbsd-queue.h"
+#include "openbsd-tree.h"
 
 enum fec_type {
        FEC_TYPE_IPV4,
@@ -121,10 +120,11 @@ struct fec_node {
 extern struct ldpd_conf        *ldeconf;
 extern struct fec_tree  ft;
 extern struct nbr_tree  lde_nbrs;
-extern struct event     gc_timer;
+extern struct thread   *gc_timer;
 
 /* lde.c */
-void            lde(int, int);
+void            lde(const char *, const char *);
+int             lde_imsg_compose_parent(int, pid_t, void *, uint16_t);
 int             lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);
 uint32_t        lde_assign_label(void);
 void            lde_send_change_klabel(struct fec_node *, struct fec_nh *);
@@ -173,7 +173,7 @@ void                 lde_check_release(struct map *, struct lde_nbr *);
 void            lde_check_release_wcard(struct map *, struct lde_nbr *);
 void            lde_check_withdraw(struct map *, struct lde_nbr *);
 void            lde_check_withdraw_wcard(struct map *, struct lde_nbr *);
-void            lde_gc_timer(int, short, void *);
+int             lde_gc_timer(struct thread *);
 void            lde_gc_start_timer(void);
 void            lde_gc_stop_timer(void);
 
@@ -185,8 +185,10 @@ void                l2vpn_init(struct l2vpn *);
 void            l2vpn_exit(struct l2vpn *);
 struct l2vpn_if        *l2vpn_if_new(struct l2vpn *, struct kif *);
 struct l2vpn_if        *l2vpn_if_find(struct l2vpn *, unsigned int);
+struct l2vpn_if        *l2vpn_if_find_name(struct l2vpn *, const char *);
 struct l2vpn_pw        *l2vpn_pw_new(struct l2vpn *, struct kif *);
 struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int);
+struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);
 void            l2vpn_pw_init(struct l2vpn_pw *);
 void            l2vpn_pw_exit(struct l2vpn_pw *);
 void            l2vpn_pw_reset(struct l2vpn_pw *);
index d9c1f544f183ea37744b531cf3815f308718276f..568761bd613f0626cdd17f543f93ca7a26ffc070 100644 (file)
  * 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);
 }
index 77034b30a57df84ee42d8a1d2256361235431e79..c421cddc386f8fb9bbcedf4bd91a907fa45c4b09 100644 (file)
@@ -23,8 +23,6 @@
 #ifndef _LDP_H_
 #define _LDP_H_
 
-#include <sys/types.h>
-
 /* misc */
 #define LDP_VERSION            1
 #define LDP_PORT               646
@@ -106,7 +104,7 @@ struct ldp_hdr {
        uint16_t        length;
        uint32_t        lsr_id;
        uint16_t        lspace_id;
-} __packed;
+} __attribute__ ((packed));
 
 #define        LDP_HDR_SIZE            10      /* actual size of the LDP header */
 #define        LDP_HDR_PDU_LEN         6       /* minimum "PDU Length" */
@@ -125,7 +123,7 @@ struct ldp_msg {
        uint32_t        id;
        /* Mandatory Parameters */
        /* Optional Parameters */
-} __packed;
+} __attribute__ ((packed));
 
 #define LDP_MSG_SIZE           8       /* minimum size of LDP message */
 #define LDP_MSG_LEN            4       /* minimum "Message Length" */
@@ -212,7 +210,7 @@ struct sess_prms_tlv {
        uint16_t        max_pdu_len;
        uint32_t        lsr_id;
        uint16_t        lspace_id;
-} __packed;
+} __attribute__ ((packed));
 
 #define SESS_PRMS_SIZE         18
 #define SESS_PRMS_LEN          14
@@ -223,7 +221,7 @@ struct status_tlv {
        uint32_t        status_code;
        uint32_t        msg_id;
        uint16_t        msg_type;
-} __packed;
+} __attribute__ ((packed));
 
 #define STATUS_SIZE            14
 #define STATUS_TLV_LEN         10
@@ -237,7 +235,7 @@ struct address_list_tlv {
        uint16_t        length;
        uint16_t        family;
        /* address entries */
-} __packed;
+} __attribute__ ((packed));
 
 #define ADDR_LIST_SIZE         6
 
diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c
new file mode 100644 (file)
index 0000000..15dd06a
--- /dev/null
@@ -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 (file)
index 0000000..aa0cd47
--- /dev/null
@@ -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 (file)
index 0000000..735554b
--- /dev/null
@@ -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 (file)
index 0000000..8742f9c
--- /dev/null
@@ -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 (file)
index 0000000..7160835
--- /dev/null
@@ -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 (file)
index 0000000..a3e1b9a
--- /dev/null
@@ -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 (file)
index 0000000..a57cf3c
--- /dev/null
@@ -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 (file)
index 0000000..41ff47f
--- /dev/null
@@ -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;
+}
index 4e1449198990d0d08ea2005c5a4fb51f1fd5d500..1eaa7df4a5a4c09f29592187af71b26520872e8d 100644 (file)
  * 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 (file)
index 0000000..49da35c
--- /dev/null
@@ -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
+!
index d32d23c6c9cd0ca6d285b595aa0714a8a5a8ada5..9601f25f70e05aa7265d3020f08c35e65ec59c8e 100644 (file)
 #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
 #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_ */
index 1b4d2a67e78ddb70343f3db1fbaf554aaefb4c86..aef33c8e373c048caf40daa981c17ae8a70519b4 100644 (file)
  * 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);
 }
index e640dd67db94b76de6fa03cf891e8a67e4094b5f..aab1a7fd9b918cebf6f4f90fb7ee79ff675776b2 100644 (file)
 #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 *);
index e14b6e51eaa53f8310199ea37d7ef9a8f1ec6ab9..77efdb47140c19fe7dacde80a0bf68a0570e8f74 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <netmpls/mpls.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <netdb.h>
-#include <limits.h>
+#include <zebra.h>
 
 #include "ldpd.h"
 #include "ldpe.h"
 #include "lde.h"
 #include "log.h"
 
+#include <lib/log.h>
+#include "mpls.h"
+
 static const char * const procnames[] = {
        "parent",
        "ldpe",
        "lde"
 };
 
-static void     vlog(int, const char *, va_list);
-
-static int      debug;
-static int      verbose;
-
-void
-log_init(int n_debug)
-{
-       extern char     *__progname;
-
-       debug = n_debug;
-
-       if (!debug)
-               openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
-
-       tzset();
-}
-
-void
-log_verbose(int v)
-{
-       verbose = v;
-}
+void            vlog(int, const char *, va_list);
 
 void
 logit(int pri, const char *fmt, ...)
@@ -74,23 +44,24 @@ logit(int pri, const char *fmt, ...)
        va_end(ap);
 }
 
-static void
+void
 vlog(int pri, const char *fmt, va_list ap)
 {
-       char    *nfmt;
+       char     buf[1024];
 
-       if (debug) {
-               /* best effort in out of mem situations */
-               if (asprintf(&nfmt, "%s\n", fmt) == -1) {
-                       vfprintf(stderr, fmt, ap);
-                       fprintf(stderr, "\n");
-               } else {
-                       vfprintf(stderr, nfmt, ap);
-                       free(nfmt);
-               }
-               fflush(stderr);
-       } else
-               vsyslog(pri, fmt, ap);
+       switch (ldpd_process) {
+       case PROC_LDE_ENGINE:
+               vsnprintf(buf, sizeof(buf), fmt, ap);
+               lde_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1);
+               break;
+       case PROC_LDP_ENGINE:
+               vsnprintf(buf, sizeof(buf), fmt, ap);
+               ldpe_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1);
+               break;
+       case PROC_MAIN:
+               vzlog(NULL, pri, fmt, ap);
+               break;
+       }
 }
 
 void
@@ -137,16 +108,24 @@ log_info(const char *emsg, ...)
        va_end(ap);
 }
 
+void
+log_notice(const char *emsg, ...)
+{
+       va_list  ap;
+
+       va_start(ap, emsg);
+       vlog(LOG_NOTICE, emsg, ap);
+       va_end(ap);
+}
+
 void
 log_debug(const char *emsg, ...)
 {
        va_list  ap;
 
-       if (verbose & LDPD_OPT_VERBOSE) {
-               va_start(ap, emsg);
-               vlog(LOG_DEBUG, emsg, ap);
-               va_end(ap);
-       }
+       va_start(ap, emsg);
+       vlog(LOG_DEBUG, emsg, ap);
+       va_end(ap);
 }
 
 void
@@ -183,7 +162,7 @@ log_sockaddr(void *vp)
 
        round = (round + 1) % NUM_LOGS;
 
-       if (getnameinfo(sa, sa->sa_len, buf[round], NI_MAXHOST, NULL, 0,
+       if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0,
            NI_NUMERICHOST))
                return ("(unknown)");
        else
@@ -196,7 +175,9 @@ log_in6addr(const struct in6_addr *addr)
        struct sockaddr_in6     sa_in6;
 
        memset(&sa_in6, 0, sizeof(sa_in6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        sa_in6.sin6_len = sizeof(sa_in6);
+#endif
        sa_in6.sin6_family = AF_INET6;
        sa_in6.sin6_addr = *addr;
 
@@ -211,7 +192,9 @@ log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex)
        struct sockaddr_in6     sa_in6;
 
        memset(&sa_in6, 0, sizeof(sa_in6));
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
        sa_in6.sin6_len = sizeof(sa_in6);
+#endif
        sa_in6.sin6_family = AF_INET6;
        sa_in6.sin6_addr = *addr;
 
@@ -275,6 +258,39 @@ log_label(uint32_t label)
        return (buf);
 }
 
+const char *
+log_time(time_t t)
+{
+       char            *buf;
+       static char      tfbuf[TF_BUFS][TF_LEN];        /* ring buffer */
+       static int       idx = 0;
+       unsigned int     sec, min, hrs, day, week;
+
+       buf = tfbuf[idx++];
+       if (idx == TF_BUFS)
+               idx = 0;
+
+       week = t;
+
+       sec = week % 60;
+       week /= 60;
+       min = week % 60;
+       week /= 60;
+       hrs = week % 24;
+       week /= 24;
+       day = week % 7;
+       week /= 7;
+
+       if (week > 0)
+               snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs);
+       else if (day > 0)
+               snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min);
+       else
+               snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec);
+
+       return (buf);
+}
+
 char *
 log_hello_src(const struct hello_source *src)
 {
@@ -365,8 +381,10 @@ af_name(int af)
                return ("ipv4");
        case AF_INET6:
                return ("ipv6");
+#ifdef AF_MPLS
        case AF_MPLS:
                return ("mpls");
+#endif
        default:
                return ("UNKNOWN");
        }
@@ -564,37 +582,3 @@ pw_type_name(uint16_t pw_type)
                return (buf);
        }
 }
-
-static char *msgtypes[] = {
-       "",
-       "RTM_ADD: Add Route",
-       "RTM_DELETE: Delete Route",
-       "RTM_CHANGE: Change Metrics or flags",
-       "RTM_GET: Report Metrics",
-       "RTM_LOSING: Kernel Suspects Partitioning",
-       "RTM_REDIRECT: Told to use different route",
-       "RTM_MISS: Lookup failed on this address",
-       "RTM_LOCK: fix specified metrics",
-       "RTM_OLDADD: caused by SIOCADDRT",
-       "RTM_OLDDEL: caused by SIOCDELRT",
-       "RTM_RESOLVE: Route created by cloning",
-       "RTM_NEWADDR: address being added to iface",
-       "RTM_DELADDR: address being removed from iface",
-       "RTM_IFINFO: iface status change",
-       "RTM_IFANNOUNCE: iface arrival/departure",
-       "RTM_DESYNC: route socket overflow",
-};
-
-void
-log_rtmsg(unsigned char rtm_type)
-{
-       if (!(verbose & LDPD_OPT_VERBOSE2))
-               return;
-
-       if (rtm_type > 0 &&
-           rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0]))
-               log_debug("kernel message: %s", msgtypes[rtm_type]);
-       else
-               log_debug("kernel message: rtm_type %d out of range",
-                   rtm_type);
-}
index 94c463041d5d1737184cef63e678633c30a6b8dd..4d6da43cac9b6c6e411cdbf142e5434f6d350ad7 100644 (file)
@@ -26,8 +26,6 @@ union ldpd_addr;
 struct hello_source;
 struct fec;
 
-void            log_init(int);
-void            log_verbose(int);
 void            logit(int, const char *, ...)
                        __attribute__((__format__ (printf, 2, 3)));
 void            log_warn(const char *, ...)
@@ -36,17 +34,22 @@ void                 log_warnx(const char *, ...)
                        __attribute__((__format__ (printf, 1, 2)));
 void            log_info(const char *, ...)
                        __attribute__((__format__ (printf, 1, 2)));
+void            log_notice(const char *, ...)
+                       __attribute__((__format__ (printf, 1, 2)));
 void            log_debug(const char *, ...)
                        __attribute__((__format__ (printf, 1, 2)));
-void            fatal(const char *) __dead
+void            fatal(const char *)
+                       __attribute__ ((noreturn))
                        __attribute__((__format__ (printf, 1, 0)));
-void            fatalx(const char *) __dead
+void            fatalx(const char *)
+                       __attribute__ ((noreturn))
                        __attribute__((__format__ (printf, 1, 0)));
 const char     *log_sockaddr(void *);
 const char     *log_in6addr(const struct in6_addr *);
 const char     *log_in6addr_scope(const struct in6_addr *, unsigned int);
 const char     *log_addr(int, const union ldpd_addr *);
 char           *log_label(uint32_t);
+const char     *log_time(time_t);
 char           *log_hello_src(const struct hello_source *);
 const char     *log_map(const struct map *);
 const char     *log_fec(const struct fec *);
@@ -58,6 +61,5 @@ const char    *if_type_name(enum iface_type);
 const char     *msg_name(uint16_t);
 const char     *status_code_name(uint32_t);
 const char     *pw_type_name(uint16_t);
-void            log_rtmsg(unsigned char);
 
 #endif /* _LOG_H_ */
index d3f83734f5e7be276382d068f66dc4a78516d47b..8376a01549cff4574eedee983b0c550fbcca8f1b 100644 (file)
  * 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);
index f30646bb83b0517ba161931a6dcf5d01510eda3d..d306361d5c2d78a4280107d13aa4ecd0197ac662 100644 (file)
  * 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)) {
index 7cc375c31741f7c484eda7f6cdcf4631b86bc970..9b3151d720e6d82e8708af57b6a3631b718cfb7e 100644 (file)
  * 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);
 }
index f0f16c867f53528351360f6e245a28a849f5e458..29f763e6a620bda546a6b85e35af0a98d836148e 100644 (file)
@@ -17,7 +17,9 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#ifdef __OpenBSD__
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
@@ -464,3 +466,4 @@ pfkey_init(void)
        }
        return (fd);
 }
+#endif /* __OpenBSD__ */
index 8f26771df717edbd252f19c7c81f277a1858c6c2..cf352d7204f64aa8f2294052337eaf40a359e296 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
+#include <zebra.h>
 
 #include "ldpd.h"
 #include "ldpe.h"
 #include "log.h"
 
+#include "lib/log.h"
+#include "privs.h"
+#include "sockopt.h"
+
+extern struct zebra_privs_t     ldpd_privs;
+extern struct zebra_privs_t     ldpe_privs;
+
 int
 ldp_create_socket(int af, enum socket_type type)
 {
        int                      fd, domain, proto;
        union ldpd_addr          addr;
        struct sockaddr_storage  local_sa;
+#ifdef __OpenBSD__
        int                      opt;
+#endif
+       int                      save_errno;
 
        /* create socket */
        switch (type) {
@@ -53,11 +57,13 @@ ldp_create_socket(int af, enum socket_type type)
        default:
                fatalx("ldp_create_socket: unknown socket type");
        }
-       fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto);
+       fd = socket(af, domain, proto);
        if (fd == -1) {
                log_warn("%s: error creating socket", __func__);
                return (-1);
        }
+       sock_set_nonblock(fd);
+       sockopt_v6only(af, fd);
 
        /* bind to a local address/port */
        switch (type) {
@@ -72,21 +78,28 @@ ldp_create_socket(int af, enum socket_type type)
                addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;
                memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),
                    sizeof(local_sa));
-               if (sock_set_bindany(fd, 1) == -1) {
-                       close(fd);
-                       return (-1);
-               }
+               /* ignore any possible error */
+               sock_set_bindany(fd, 1);
                break;
        }
+       if (ldpd_privs.change(ZPRIVS_RAISE))
+               log_warn("%s: could not raise privs", __func__);
        if (sock_set_reuse(fd, 1) == -1) {
                close(fd);
                return (-1);
        }
-       if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) {
-               log_warn("%s: error binding socket", __func__);
+       if (bind(fd, (struct sockaddr *)&local_sa,
+           sockaddr_len((struct sockaddr *)&local_sa)) == -1) {
+               save_errno = errno;
+               if (ldpd_privs.change(ZPRIVS_LOWER))
+                       log_warn("%s: could not lower privs", __func__);
+               log_warnx("%s: error binding socket: %s", __func__,
+                   safe_strerror(save_errno));
                close(fd);
                return (-1);
        }
+       if (ldpd_privs.change(ZPRIVS_LOWER))
+               log_warn("%s: could not lower privs", __func__);
 
        /* set options */
        switch (af) {
@@ -111,6 +124,21 @@ ldp_create_socket(int af, enum socket_type type)
                                close(fd);
                                return (-1);
                        }
+#ifndef MSG_MCAST
+#if defined(HAVE_IP_PKTINFO)
+                       if (sock_set_ipv4_pktinfo(fd, 1) == -1) {
+                               close(fd);
+                               return (-1);
+                       }
+#elif defined(HAVE_IP_RECVDSTADDR)
+                       if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) {
+                               close(fd);
+                               return (-1);
+                       }
+#else
+#error "Unsupported socket API"
+#endif
+#endif /* MSG_MCAST */
                }
                if (type == LDP_SOCKET_SESSION) {
                        if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) {
@@ -134,10 +162,8 @@ ldp_create_socket(int af, enum socket_type type)
                                return (-1);
                        }
                        if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) {
-                               if (sock_set_ipv6_minhopcount(fd, 255) == -1) {
-                                       close(fd);
-                                       return (-1);
-                               }
+                               /* ignore any possible error */
+                               sock_set_ipv6_minhopcount(fd, 255);
                        }
                }
                if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) {
@@ -163,6 +189,7 @@ ldp_create_socket(int af, enum socket_type type)
                if (listen(fd, LDP_BACKLOG) == -1)
                        log_warn("%s: error listening on socket", __func__);
 
+#ifdef __OpenBSD__
                opt = 1;
                if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,
                    sizeof(opt)) == -1) {
@@ -174,12 +201,41 @@ ldp_create_socket(int af, enum socket_type type)
                                return (-1);
                        }
                }
+#endif
                break;
        }
 
        return (fd);
 }
 
+void
+sock_set_nonblock(int fd)
+{
+       int     flags;
+
+       if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
+               fatal("fcntl F_GETFL");
+
+       flags |= O_NONBLOCK;
+
+       if ((flags = fcntl(fd, F_SETFL, flags)) == -1)
+               fatal("fcntl F_SETFL");
+}
+
+void
+sock_set_cloexec(int fd)
+{
+       int     flags;
+
+       if ((flags = fcntl(fd, F_GETFD, 0)) == -1)
+               fatal("fcntl F_GETFD");
+
+       flags |= FD_CLOEXEC;
+
+       if ((flags = fcntl(fd, F_SETFD, flags)) == -1)
+               fatal("fcntl F_SETFD");
+}
+
 void
 sock_set_recvbuf(int fd)
 {
@@ -206,15 +262,68 @@ sock_set_reuse(int fd, int enable)
 int
 sock_set_bindany(int fd, int enable)
 {
+#ifdef HAVE_SO_BINDANY
+       if (ldpd_privs.change(ZPRIVS_RAISE))
+               log_warn("%s: could not raise privs", __func__);
        if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
            sizeof(int)) < 0) {
+               if (ldpd_privs.change(ZPRIVS_LOWER))
+                       log_warn("%s: could not lower privs", __func__);
                log_warn("%s: error setting SO_BINDANY", __func__);
                return (-1);
        }
-
+       if (ldpd_privs.change(ZPRIVS_LOWER))
+               log_warn("%s: could not lower privs", __func__);
        return (0);
+#elif defined(HAVE_IP_FREEBIND)
+       if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) {
+               log_warn("%s: error setting IP_FREEBIND", __func__);
+               return (-1);
+       }
+       return (0);
+#else
+       log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind "
+           "to a nonlocal IP address", __func__);
+       return (-1);
+#endif /* HAVE_SO_BINDANY */
 }
 
+#ifndef __OpenBSD__
+/*
+ * Set MD5 key for the socket, for the given peer address. If the password
+ * is NULL or zero-length, the option will be disabled.
+ */
+int
+sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
+{
+       int              ret = -1;
+       int              save_errno = ENOSYS;
+#if HAVE_DECL_TCP_MD5SIG
+       union sockunion  su;
+#endif
+
+       if (fd == -1)
+               return (0);
+#if HAVE_DECL_TCP_MD5SIG
+       memcpy(&su, addr2sa(af, addr, 0), sizeof(su));
+
+       if (ldpe_privs.change(ZPRIVS_RAISE)) {
+               log_warn("%s: could not raise privs", __func__);
+               return (-1);
+       }
+       ret = sockopt_tcp_signature(fd, &su, password);
+       save_errno = errno;
+       if (ldpe_privs.change(ZPRIVS_LOWER))
+               log_warn("%s: could not lower privs", __func__);
+#endif /* HAVE_TCP_MD5SIG */
+       if (ret < 0)
+               log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
+                   __func__, fd, safe_strerror(save_errno));
+
+       return (ret);
+}
+#endif
+
 int
 sock_set_ipv4_tos(int fd, int tos)
 {
@@ -229,23 +338,13 @@ sock_set_ipv4_tos(int fd, int tos)
 int
 sock_set_ipv4_recvif(int fd, int enable)
 {
-       if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
-           sizeof(enable)) < 0) {
-               log_warn("%s: error setting IP_RECVIF", __func__);
-               return (-1);
-       }
-       return (0);
+       return (setsockopt_ifindex(AF_INET, fd, enable));
 }
 
 int
 sock_set_ipv4_minttl(int fd, int ttl)
 {
-       if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) {
-               log_warn("%s: error setting IP_MINTTL", __func__);
-               return (-1);
-       }
-
-       return (0);
+       return (sockopt_minttl(AF_INET, fd, ttl));
 }
 
 int
@@ -272,15 +371,45 @@ sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)
        return (0);
 }
 
+#ifndef MSG_MCAST
+#if defined(HAVE_IP_PKTINFO)
+int
+sock_set_ipv4_pktinfo(int fd, int enable)
+{
+       if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable,
+           sizeof(enable)) < 0) {
+               log_warn("%s: error setting IP_PKTINFO", __func__);
+               return (-1);
+       }
+
+       return (0);
+}
+#elif defined(HAVE_IP_RECVDSTADDR)
+int
+sock_set_ipv4_recvdstaddr(int fd, int enable)
+{
+       if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable,
+           sizeof(enable)) < 0) {
+               log_warn("%s: error setting IP_RECVDSTADDR", __func__);
+               return (-1);
+       }
+
+       return (0);
+}
+#else
+#error "Unsupported socket API"
+#endif
+#endif /* MSG_MCAST */
+
 int
 sock_set_ipv4_mcast(struct iface *iface)
 {
-       in_addr_t                addr;
+       struct in_addr           if_addr;
 
-       addr = if_get_ipv4_addr(iface);
+       if_addr.s_addr = if_get_ipv4_addr(iface);
 
-       if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF,
-           &addr, sizeof(addr)) < 0) {
+       if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket,
+           if_addr, iface->ifindex) < 0) {
                log_warn("%s: error setting IP_MULTICAST_IF, interface %s",
                    __func__, iface->name);
                return (-1);
@@ -330,13 +459,7 @@ sock_set_ipv6_pktinfo(int fd, int enable)
 int
 sock_set_ipv6_minhopcount(int fd, int hoplimit)
 {
-       if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT,
-           &hoplimit, sizeof(hoplimit)) < 0) {
-               log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__);
-               return (-1);
-       }
-
-       return (0);
+       return (sockopt_minttl(AF_INET6, fd, hoplimit));
 }
 
 int
index 981a5c8c21154682197f915f16a6f4dc2614034e..e735263f5fdcd316cb575ce10756286ccf206edd 100644 (file)
@@ -19,8 +19,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
-#include <string.h>
+#include <zebra.h>
 
 #include "ldpd.h"
 #include "log.h"
@@ -44,7 +43,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_in6)
         * the possibly truncated sin6_addr struct.
         */
        ap = (uint8_t *)&sa_in6->sin6_addr;
-       ep = (uint8_t *)sa_in6 + sa_in6->sin6_len;
+       ep = (uint8_t *)sa_in6 + sockaddr_len((struct sockaddr *)sa_in6);
        for (; ap < ep; ap++) {
                /* this "beauty" is adopted from sbin/route/show.c ... */
                switch (*ap) {
@@ -317,13 +316,17 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port)
        switch (af) {
        case AF_INET:
                sa_in->sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
                sa_in->sin_len = sizeof(struct sockaddr_in);
+#endif
                sa_in->sin_addr = addr->v4;
                sa_in->sin_port = htons(port);
                break;
        case AF_INET6:
                sa_in6->sin6_family = AF_INET6;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
                sa_in6->sin6_len = sizeof(struct sockaddr_in6);
+#endif
                sa_in6->sin6_addr = addr->v6;
                sa_in6->sin6_port = htons(port);
                break;
@@ -335,22 +338,48 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port)
 }
 
 void
-sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr)
+sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr, in_port_t *port)
 {
        struct sockaddr_in              *sa_in = (struct sockaddr_in *)sa;
        struct sockaddr_in6             *sa_in6 = (struct sockaddr_in6 *)sa;
 
-       memset(addr, 0, sizeof(*addr));
+       if (addr)
+               memset(addr, 0, sizeof(*addr));
        switch (sa->sa_family) {
        case AF_INET:
-               *af = AF_INET;
-               addr->v4 = sa_in->sin_addr;
+               if (af)
+                       *af = AF_INET;
+               if (addr)
+                       addr->v4 = sa_in->sin_addr;
+               if (port)
+                       *port = sa_in->sin_port;
                break;
        case AF_INET6:
-               *af = AF_INET6;
-               addr->v6 = sa_in6->sin6_addr;
+               if (af)
+                       *af = AF_INET6;
+               if (addr)
+                       addr->v6 = sa_in6->sin6_addr;
+               if (port)
+                       *port = sa_in6->sin6_port;
                break;
        default:
                fatalx("sa2addr: unknown af");
        }
 }
+
+socklen_t
+sockaddr_len(struct sockaddr *sa)
+{
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       return (sa->sa_len);
+#else
+       switch (sa->sa_family) {
+       case AF_INET:
+               return (sizeof(struct sockaddr_in));
+       case AF_INET6:
+               return (sizeof(struct sockaddr_in6));
+       default:
+               fatalx("sockaddr_len: unknown af");
+       }
+#endif
+}
index dbb80076c57ff1a21a5ed82079cc3c6655e74b00..17be655a1778393f75e68f0142aa40088952e667 100644 (file)
@@ -14,7 +14,8 @@ libzebra_la_SOURCES = \
        filter.c routemap.c distribute.c stream.c str.c log.c plist.c \
        zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \
        sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \
-       ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c
+       ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \
+       imsg-buffer.c imsg.c
 
 BUILT_SOURCES = route_types.h gitversion.h
 
@@ -31,7 +32,7 @@ pkginclude_HEADERS = \
        privs.h sigevent.h pqueue.h jhash.h zassert.h \
        workqueue.h route_types.h libospf.h nexthop.h json.h \
        ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \
-       fifo.h memory_vty.h
+       fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h
 
 noinst_HEADERS = \
        plist_int.h
index cfdb91a5b9ae34039cfb7183f63a0baad0ea05aa..bf8b1b1d3385abd7f51620cc82f2bdee9a980e2e 100644 (file)
@@ -2550,6 +2550,19 @@ node_parent ( enum node_type node )
     case LINK_PARAMS_NODE:
       ret = INTERFACE_NODE;
       break;
+    case LDP_IPV4_NODE:
+    case LDP_IPV6_NODE:
+      ret = LDP_NODE;
+      break;
+    case LDP_IPV4_IFACE_NODE:
+      ret = LDP_IPV4_NODE;
+      break;
+    case LDP_IPV6_IFACE_NODE:
+      ret = LDP_IPV6_NODE;
+      break;
+    case LDP_PSEUDOWIRE_NODE:
+      ret = LDP_L2VPN_NODE;
+      break;
     default:
       ret = CONFIG_NODE;
       break;
@@ -2920,6 +2933,8 @@ DEFUN (config_exit,
     case RIPNG_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
+    case LDP_NODE:
+    case LDP_L2VPN_NODE:
     case ISIS_NODE:
     case KEYCHAIN_NODE:
     case MASC_NODE:
@@ -2938,6 +2953,19 @@ DEFUN (config_exit,
     case BGP_IPV6M_NODE:
       vty->node = BGP_NODE;
       break;
+    case LDP_IPV4_NODE:
+    case LDP_IPV6_NODE:
+      vty->node = LDP_NODE;
+      break;
+    case LDP_IPV4_IFACE_NODE:
+      vty->node = LDP_IPV4_NODE;
+      break;
+    case LDP_IPV6_IFACE_NODE:
+      vty->node = LDP_IPV6_NODE;
+      break;
+    case LDP_PSEUDOWIRE_NODE:
+      vty->node = LDP_L2VPN_NODE;
+      break;
     case KEYCHAIN_KEY_NODE:
       vty->node = KEYCHAIN_NODE;
       break;
@@ -2988,6 +3016,13 @@ DEFUN (config_end,
     case RMAP_NODE:
     case OSPF_NODE:
     case OSPF6_NODE:
+    case LDP_NODE:
+    case LDP_IPV4_NODE:
+    case LDP_IPV6_NODE:
+    case LDP_IPV4_IFACE_NODE:
+    case LDP_IPV6_IFACE_NODE:
+    case LDP_L2VPN_NODE:
+    case LDP_PSEUDOWIRE_NODE:
     case ISIS_NODE:
     case KEYCHAIN_NODE:
     case KEYCHAIN_KEY_NODE:
index 808e742059fb91b441d500fa98d8a0ff2e191084..7a4c53a616cfd99ed32c7d990ff78c4dd382cddd 100644 (file)
@@ -98,6 +98,13 @@ enum node_type
   BGP_ENCAPV6_NODE,            /* BGP ENCAP SAFI */
   OSPF_NODE,                   /* OSPF protocol mode */
   OSPF6_NODE,                  /* OSPF protocol for IPv6 mode */
+  LDP_NODE,                    /* LDP protocol mode */
+  LDP_IPV4_NODE,               /* LDP IPv4 address family */
+  LDP_IPV6_NODE,               /* LDP IPv6 address family */
+  LDP_IPV4_IFACE_NODE,         /* LDP IPv4 Interface */
+  LDP_IPV6_IFACE_NODE,         /* LDP IPv6 Interface */
+  LDP_L2VPN_NODE,              /* LDP L2VPN node */
+  LDP_PSEUDOWIRE_NODE,         /* LDP Pseudowire node */
   ISIS_NODE,                   /* ISIS protocol mode */
   PIM_NODE,                    /* PIM protocol mode */
   MASC_NODE,                   /* MASC for multicast.  */
index 61b2c095ae658bfc3c89a59c97f049115b6c30bf..a486fc17c18d35329eb245ca2d4a051ba3e3fb03 100644 (file)
  * 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:
index 0c1cb8220c2b0ddaecf313f592d061f1fafbe74d..246430cdd5a56c026c2d0494be9a53b78a3c9246 100644 (file)
  * 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);
index b9edb12fbd38d73bd9b4741a3a828cd7835a63fa..14fa81a9d75a221f0ada53c90cc7f92e9b798177 100644 (file)
--- 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];
index 951fa124c80f3fae796a645d90a578ad00042536..31bf2b67cfb24874bfc0fbca101b900aef063da7 100644 (file)
--- 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);
index 8889868970f58bfab1808276767804c9da862b2e..5a67b915d1988aa9a9f7ce0ed326c83556d47ec6 100644 (file)
@@ -169,4 +169,13 @@ label2str (mpls_label_t label, char *buf, int len)
   return(buf);
 }
 
+/* constants used by ldpd */
+#define MPLS_LABEL_IPV4NULL    0               /* IPv4 Explicit NULL Label */
+#define MPLS_LABEL_RTALERT     1               /* Router Alert Label       */
+#define MPLS_LABEL_IPV6NULL    2               /* IPv6 Explicit NULL Label */
+#define MPLS_LABEL_IMPLNULL    3               /* Implicit NULL Label      */
+/*      MPLS_LABEL_RESERVED    4-15 */         /* Values 4-15 are reserved */
+#define MPLS_LABEL_RESERVED_MAX 15
+#define MPLS_LABEL_MAX         ((1 << 20) - 1)
+
 #endif
index 9228a56d356315c460ab522cb66b8fb693b32eb6..6cf87c18d424df52b67c8297b709a567d6e862f2 100644 (file)
@@ -250,12 +250,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)
       exit(1);
     }
 
-  if ( !zprivs_state.syscaps_p )
-    {
-      fprintf (stderr, "privs_init: capabilities enabled, "
-                       "but no capabilities supplied\n");
-    }
-
   /* we have caps, we have no need to ever change back the original user */
   if (zprivs_state.zuid)
     {
@@ -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()) )
     {
index 8fc3092cacc465444bd844c3837e798fb627f44a..0ac442d85d1164ffec69f525c3b3248ed1dd84a7 100644 (file)
@@ -60,6 +60,7 @@ ZEBRA_ROUTE_PIM,      pim,       pimd,   'P', 1, 0, "PIM"
 ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 0, 0, "HSLS"
 ZEBRA_ROUTE_OLSR,       olsr,      olsrd,  'o', 0, 0, "OLSR"
 ZEBRA_ROUTE_TABLE,      table,     zebra,  'T', 1, 1, "Table"
+ZEBRA_ROUTE_LDP,        ldp,       ldpd,   'L', 0, 0, "LDP"
 
 ## help strings
 ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only"
@@ -76,3 +77,4 @@ ZEBRA_ROUTE_PIM,    "Protocol Independent Multicast (PIM)"
 ZEBRA_ROUTE_HSLS,   "Hazy-Sighted Link State Protocol (HSLS)"
 ZEBRA_ROUTE_OLSR,   "Optimised Link State Routing (OLSR)"
 ZEBRA_ROUTE_TABLE,  "Non-main Kernel Routing Table"
+ZEBRA_ROUTE_LDP,    "Label Distribution Protocol (LDP)"
index 48b64a95c4461c5e752b6ff71c591e93874b4a03..3f135004494ff73806435b6abf0a33dce9135720 100644 (file)
--- 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;
+}
index 599882a382b49f8b38669e7792354d4571da07d2..4f1dbe653ec89b967c4b4fe696e151395a3b1ca1 100644 (file)
--- 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 (executable)
index 0000000..4378913
--- /dev/null
@@ -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);
+}
index 3402bf1dfb883013ecb35969e693995a21ec70ce..e617ae28a2d306a6ab9e9b140eee6b85d1afde80 100644 (file)
@@ -641,7 +641,7 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
     {
       /* We don't send any nexthops when there's a multipath */
-      if (rib->nexthop_active_num > 1)
+      if (rib->nexthop_active_num > 1 && client->proto != ZEBRA_ROUTE_LDP)
        {
           SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);
           SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX);
@@ -713,7 +713,9 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,
           stream_putc (s, 1);
           stream_putl (s, nexthop->ifindex);
 
-          break;
+         /* ldpd needs all nexthops */
+         if (client->proto != ZEBRA_ROUTE_LDP)
+           break;
         }
     }