diff options
| author | Renato Westphal <renato@opensourcerouting.org> | 2016-03-01 15:31:28 -0300 | 
|---|---|---|
| committer | Donald Sharp <sharpd@cumulusnetworks.com> | 2016-09-23 09:31:09 -0400 | 
| commit | eac6e3f027356c25a8c8fddf921f769b79945fcc (patch) | |
| tree | 69d5a17fb3f95934bafa22f8a3aee28c92780d62 | |
| parent | e30090a678e45aee2755c492212c5a478b9dcfcc (diff) | |
ldpd: adapt the code for Quagga
Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
57 files changed, 8862 insertions, 1200 deletions
diff --git a/Makefile.am b/Makefile.am index 1a39844cb1..a3cbdc919c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@  ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \           @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \           redhat @SOLARIS@ tests tools cumulus -DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \ +DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d ldpd \  	  isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \  	  solaris pimd tools cumulus diff --git a/configure.ac b/configure.ac index 937d7b8d0f..eb1f1de6c1 100755 --- a/configure.ac +++ b/configure.ac @@ -246,6 +246,8 @@ AC_ARG_ENABLE(ospfd,    AS_HELP_STRING([--disable-ospfd], [do not build ospfd]))  AC_ARG_ENABLE(ospf6d,    AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) +AC_ARG_ENABLE(ldpd, +  AS_HELP_STRING([--enable-ldpd], [build ldpd]))  AC_ARG_ENABLE(watchquagga,    AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga]))  AC_ARG_ENABLE(isisd, @@ -838,7 +840,7 @@ AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \  	strtol strtoul strlcat strlcpy \  	daemon snprintf vsnprintf \  	if_nametoindex if_indextoname getifaddrs \ -	uname fcntl getgrouplist]) +	uname fcntl getgrouplist pledge])  AC_CHECK_HEADER([asm-generic/unistd.h],                  [AC_CHECK_DECL(__NR_setns, @@ -1231,6 +1233,13 @@ else  fi  AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") +if test "${enable_ldpd}" = "yes";then +  LDPD="ldpd" +else +  LDPD="" +fi +AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd") +  if test "${enable_watchquagga}" = "no";then    WATCHQUAGGA=""  else @@ -1286,6 +1295,7 @@ AC_SUBST(RIPD)  AC_SUBST(RIPNGD)  AC_SUBST(OSPFD)  AC_SUBST(OSPF6D) +AC_SUBST(LDPD)  AC_SUBST(WATCHQUAGGA)  AC_SUBST(ISISD)  AC_SUBST(PIMD) @@ -1432,6 +1442,32 @@ AC_TRY_COMPILE([#include <netinet/in.h>], [    AC_MSG_RESULT(no)  ]) +dnl ---------------------- +dnl checking for SO_BINDANY +dnl ---------------------- +AC_MSG_CHECKING(for SO_BINDANY) +AC_TRY_COMPILE([#include <sys/socket.h>], [ +  int opt = SO_BINDANY; +], [ +  AC_MSG_RESULT(yes) +  AC_DEFINE(HAVE_SO_BINDANY, 1, [Have SO_BINDANY]) +], [ +  AC_MSG_RESULT(no) +]) + +dnl ---------------------- +dnl checking for IP_FREEBIND +dnl ---------------------- +AC_MSG_CHECKING(for IP_FREEBIND) +AC_TRY_COMPILE([#include <netinet/in.h>], [ +  int opt = IP_FREEBIND; +], [ +  AC_MSG_RESULT(yes) +  AC_DEFINE(HAVE_IP_FREEBIND, 1, [Have IP_FREEBIND]) +], [ +  AC_MSG_RESULT(no) +]) +  dnl --------------------------------------  dnl checking for getrusage struct and call  dnl -------------------------------------- @@ -1580,6 +1616,8 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID)  AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID)  AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID)  AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID) +AC_DEFINE_UNQUOTED(PATH_LDPD_PID, "$quagga_statedir/ldpd.pid",ldpd PID) +AC_DEFINE_UNQUOTED(LDPD_SOCKET, "$quagga_statedir/ldpd.sock",ldpd control socket)  AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID)  AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID)  AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID) @@ -1590,6 +1628,7 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc  AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket)  AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket)  AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket) +AC_DEFINE_UNQUOTED(LDP_VTYSH_PATH, "$quagga_statedir/ldpd.vty",ldpd vty socket)  AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket)  AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket)  AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory) @@ -1615,7 +1654,7 @@ AC_MSG_RESULT($ac_cv_htonl_works)  AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile   	  ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile -	  ospf6d/Makefile isisd/Makefile vtysh/Makefile +	  ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile  	  doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile  	  pimd/Makefile  	  tests/bgpd.tests/Makefile diff --git a/doc/Makefile.am b/doc/Makefile.am index 4a39f0b011..ffb0bf4651 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -87,6 +87,10 @@ if OSPFD  man_MANS += ospfd.8  endif +if LDPD +man_MANS += ldpd.8 +endif +  if RIPD  man_MANS += ripd.8  endif @@ -108,7 +112,7 @@ man_MANS += zebra.8  endif  EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ -	bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ +	bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ldpd.8 ripd.8 \  	ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 quagga.1 \  	mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \  	mpls/opaque_lsa.txt mpls/ospfd.conf \ diff --git a/doc/ldpd-basic-test-setup.md b/doc/ldpd-basic-test-setup.md new file mode 100644 index 0000000000..e5e987f9e3 --- /dev/null +++ b/doc/ldpd-basic-test-setup.md @@ -0,0 +1,681 @@ +## Topology + +The goal of this test is to verify that the all the basic functionality +of ldpd is working as expected, be it running on Linux or OpenBSD. In +addition to that, more advanced features are also tested, like LDP +sessions over IPv6, MD5 authentication and pseudowire signaling. + +In the topology below there are 3 PE routers, 3 CE routers and one P +router (not attached to any consumer site). + +All routers have IPv4 addresses and OSPF is used as the IGP. The +three routers from the bottom of the picture, P, PE2 and PE3, are also +configured for IPv6 (dual-stack) and static IPv6 routes are used to +provide connectivity among them. + +The three CEs share the same VPLS membership. LDP is used to set up the +LSPs among the PEs and to signal the pseudowires. MD5 authentication is +used to protect all LDP sessions. + +``` +                          CE1 172.16.1.1/24 +                           + +                           | +                       +---+---+ +                       |  PE1  | +                       | IOS XE| +                       |       | +                       +---+---+ +                           | +                           | 10.0.1.0/24 +                           | +                       +---+---+ +                       |   P   | +                +------+ IOS XR+------+ +                |      |       |      | +                |      +-------+      | +    10.0.2.0/24 |                     | 10.0.3.0/24 +2001:db8:2::/64 |                     | 2001:db8:3::/64 +                |                     | +            +---+---+             +---+---+ +            |  PE2  |             |  PE3  | +            |OpenBSD+-------------+ Linux | +            |       |             |       | +            +---+---+ 10.0.4.0/24 +---+---+ +                |   2001:db8:4::/64   | +                +                     + + 172.16.1.2/24 CE2                   CE3 172.16.1.3/24 +``` + +## Configuration + +#### Linux +1 - Enable IPv4/v6 forwarding: +``` +# sysctl -w net.ipv4.ip_forward=1 +# sysctl -w net.ipv6.conf.all.forwarding=1 +``` + +2 - Enable MPLS forwarding: +``` +# modprobe mpls-router +# modprobe mpls-iptunnel +# echo 100000 > /proc/sys/net/mpls/platform_labels +# echo 1 > /proc/sys/net/mpls/conf/eth1/input +# echo 1 > /proc/sys/net/mpls/conf/eth2/input +``` + +3 - Set up the interfaces: +``` +# ip link add name lo1 type dummy +# ip link set dev lo1 up +# ip addr add 4.4.4.4/32 dev lo1 +# ip -6 addr add 4:4:4::4/128 dev lo1 +# ip link set dev eth1 up +# ip addr add 10.0.4.4/24 dev eth1 +# ip -6 addr add 2001:db8:4::4/64 dev eth1 +# ip link set dev eth2 up +# ip addr add 10.0.3.4/24 dev eth2 +# ip -6 addr add 2001:db8:3::4/64 dev eth2 +``` + +4 - Set up the bridge and pseudowire interfaces: +``` +# ip link add type bridge +# ip link set dev bridge0 up +# ip link set dev eth0 up +# ip link set dev eth0 master bridge0 +# ip link add name mpw0 type dummy +# ip link set dev mpw0 up +# ip link set dev mpw0 master bridge0 +# ip link add name mpw1 type dummy +# ip link set dev mpw1 up +# ip link set dev mpw1 master bridge0 +``` + +> NOTE: MPLS support in the Linux kernel is very recent and it still +doesn't support pseudowire interfaces. We are using here dummy interfaces +just to show how the VPLS configuration should look like in the future. + +5 - Add static IPv6 routes for the remote loopbacks: +``` +# ip -6 route add 2:2:2::2/128 via 2001:db8:3::2 +# ip -6 route add 3:3:3::3/128 via 2001:db8:4::3 +``` + +6 - Edit /etc/quagga/ospfd.conf: +``` +router ospf + network 4.4.4.4/32 area 0.0.0.0 + network 10.0.3.4/24 area 0.0.0.0 + network 10.0.4.4/24 area 0.0.0.0 +! +``` + +7 - Edit /etc/quagga/ldpd.conf: +``` +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 4.4.4.4 + dual-stack cisco-interop + neighbor 1.1.1.1 password opensourcerouting + neighbor 2.2.2.2 password opensourcerouting + neighbor 3.3.3.3 password opensourcerouting + ! + address-family ipv4 +  discovery transport-address 4.4.4.4 +  label local advertise explicit-null +  ! +  interface eth2 +  ! +  interface eth1 +  ! + ! + address-family ipv6 +  discovery transport-address 4:4:4::4 +  ttl-security disable +  ! +  interface eth2 +  ! +  interface eth1 +  ! + ! +! +l2vpn ENG type vpls + bridge br0 + member interface eth0 + ! + member pseudowire mpw0 +  neighbor lsr-id 1.1.1.1 +  pw-id 100 + ! + member pseudowire mpw1 +  neighbor lsr-id 3.3.3.3 +  neighbor address 3:3:3::3 +  pw-id 100 + ! +! +``` + +> NOTE: We have to disable ttl-security under the ipv6 address-family +in order to interoperate with the IOS-XR router. GTSM is mandatory for +LDPv6 but the IOS-XR implementation is not RFC compliant in this regard. + +8 - Run zebra, ospfd and ldpd. + +#### OpenBSD +1 - Enable IPv4/v6 forwarding: +``` +# sysctl net.inet.ip.forwarding=1 +# sysctl net.inet6.ip6.forwarding=1 +``` + +2 - Enable MPLS forwarding: +``` +# ifconfig em2 10.0.2.3/24 mpls +# ifconfig em3 10.0.4.3/24 mpls +``` + +3 - Set up the interfaces: +``` +# ifconfig lo1 alias 3.3.3.3 netmask 255.255.255.255 +# ifconfig lo1 inet6 3:3:3::3/128 +# ifconfig em2 inet6 2001:db8:2::3/64 +# ifconfig em3 inet6 2001:db8:4::3/64 +``` + +4 - Set up the bridge and pseudowire interfaces: +``` +# ifconfig bridge0 create +# ifconfig bridge0 up +# ifconfig em1 up +# ifconfig bridge0 add em1 +# ifconfig mpw0 create +# ifconfig mpw0 up +# ifconfig bridge0 add mpw0 +# ifconfig mpw1 create +# ifconfig mpw1 up +# ifconfig bridge0 add mpw1 +``` + +5 - Add static IPv6 routes for the remote loopbacks: +``` +# route -n add 4:4:4::4/128 2001:db8:4::4 +# route -n add 2:2:2::2/128 2001:db8:2::2 +``` + +6 - Edit /etc/quagga/ospfd.conf: +``` +router ospf + network 10.0.2.3/24 area 0 + network 10.0.4.3/24 area 0 + network 3.3.3.3/32 area 0 +! +``` + +7 - Edit /etc/quagga/ldpd.conf: +``` +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 3.3.3.3 + dual-stack cisco-interop + neighbor 1.1.1.1 password opensourcerouting + neighbor 2.2.2.2 password opensourcerouting + neighbor 4.4.4.4 password opensourcerouting + ! + address-family ipv4 +  discovery transport-address 3.3.3.3 +  label local advertise explicit-null +  ! +  interface em3 +  ! +  interface em2 +  ! + ! + address-family ipv6 +  discovery transport-address 3:3:3::3 +  ttl-security disable +  ! +  interface em3 +  ! +  interface em2 +  ! + ! +! +l2vpn ENG type vpls + bridge br0 + member interface em1 + ! + member pseudowire mpw0 +  neighbor lsr-id 1.1.1.1 +  pw-id 100 + ! + member pseudowire mpw1 +  neighbor lsr-id 4.4.4.4 +  neighbor address 4:4:4::4 +  pw-id 100 + ! +! +``` + +8 - Run zebra, ospfd and ldpd. + +#### Cisco routers +CE1 (IOS): +``` +interface FastEthernet0/0 + ip address 172.16.1.1 255.255.255.0 + ! +! +``` + +CE2 (IOS): +``` +interface FastEthernet0/0 + ip address 172.16.1.2 255.255.255.0 + ! +! +``` + +CE3 (IOS): +``` +interface FastEthernet0/0 + ip address 172.16.1.3 255.255.255.0 + ! +! +``` + +PE1 - IOS-XE (1): +``` +mpls ldp neighbor 2.2.2.2 password opensourcerouting +mpls ldp neighbor 3.3.3.3 password opensourcerouting +mpls ldp neighbor 4.4.4.4 password opensourcerouting +! +l2vpn vfi context VFI + vpn id 1 + member pseudowire2 + member pseudowire1 +! +bridge-domain 1 + member GigabitEthernet1 service-instance 1 + member vfi VFI +! +interface Loopback1 + ip address 1.1.1.1 255.255.255.255 +! +interface pseudowire1 + encapsulation mpls + neighbor 3.3.3.3 100 +! +interface pseudowire2 + encapsulation mpls + neighbor 4.4.4.4 100 +! +interface GigabitEthernet3 + ip address 10.0.1.1 255.255.255.0 + mpls ip +! +router ospf 1 + network 0.0.0.0 255.255.255.255 area 0 +! +``` + +P - IOS-XR (2): +``` +interface Loopback1 + ipv4 address 2.2.2.2 255.255.255.255 + ipv6 address 2:2:2::2/128 +! +interface GigabitEthernet0/0/0/0 + ipv4 address 10.0.1.2 255.255.255.0 +! +interface GigabitEthernet0/0/0/1 + ipv4 address 10.0.2.2 255.255.255.0 + ipv6 address 2001:db8:2::2/64 + ipv6 enable +! +interface GigabitEthernet0/0/0/2 + ipv4 address 10.0.3.2 255.255.255.0 + ipv6 address 2001:db8:3::2/64 + ipv6 enable +! +router static + address-family ipv6 unicast +  3:3:3::3/128 2001:db8:2::3 +  4:4:4::4/128 2001:db8:3::4 + ! +! +router ospf 1 + router-id 2.2.2.2 + address-family ipv4 unicast + area 0 +  interface Loopback1 +  ! +  interface GigabitEthernet0/0/0/0 +  ! +  interface GigabitEthernet0/0/0/1 +  ! +  interface GigabitEthernet0/0/0/2 +  ! + ! +! +mpls ldp + router-id 2.2.2.2 + neighbor +  1.1.1.1:0 password clear opensourcerouting +  3.3.3.3:0 password clear opensourcerouting +  4.4.4.4:0 password clear opensourcerouting + ! + address-family ipv4 + ! + address-family ipv6 +  discovery transport-address 2:2:2::2 + ! + interface GigabitEthernet0/0/0/0 +  address-family ipv4 +  ! + ! + interface GigabitEthernet0/0/0/1 +  address-family ipv4 +  ! +  address-family ipv6 +  ! + ! + interface GigabitEthernet0/0/0/2 +  address-family ipv4 +  ! +  address-family ipv6 +  ! + ! +! +``` + +## Verification - Control Plane + +Using the CLI on the Linux box, the goal is to ensure that everything +is working as expected. + +First, verify that all the required adjacencies and neighborships sessions +were established: + +``` +linux# show mpls ldp discovery +Local LDP Identifier: 4.4.4.4:0 +Discovery Sources: +  Interfaces: +    eth1: xmit/recv +      LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 +          Hold time: 15 sec +      LDP Id: 3.3.3.3:0, Transport address: 3:3:3::3 +          Hold time: 15 sec +    eth2: xmit/recv +      LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 +          Hold time: 15 sec +      LDP Id: 2.2.2.2:0, Transport address: 2:2:2::2 +          Hold time: 15 sec +  Targeted Hellos: +    4.4.4.4 -> 1.1.1.1: xmit/recv +      LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 +          Hold time: 45 sec +    4:4:4::4 -> 3:3:3::3: xmit/recv +      LDP Id: 3.3.3.3:0, Transport address: 3:3:3::3 +          Hold time: 45 sec + +linux# show mpls ldp neighbor +Peer LDP Identifier: 1.1.1.1:0 +  TCP connection: 4.4.4.4:40921 - 1.1.1.1:646 +  Session Holdtime: 180 sec +  State: OPERATIONAL; Downstream-Unsolicited +  Up time: 00:06:02 +  LDP Discovery Sources: +    IPv4: +      Targeted Hello: 1.1.1.1 + +Peer LDP Identifier: 2.2.2.2:0 +  TCP connection: 4:4:4::4:52286 - 2:2:2::2:646 +  Session Holdtime: 180 sec +  State: OPERATIONAL; Downstream-Unsolicited +  Up time: 00:06:02 +  LDP Discovery Sources: +    IPv4: +      Interface: eth2 +    IPv6: +      Interface: eth2 + +Peer LDP Identifier: 3.3.3.3:0 +  TCP connection: 4:4:4::4:60575 - 3:3:3::3:646 +  Session Holdtime: 180 sec +  State: OPERATIONAL; Downstream-Unsolicited +  Up time: 00:05:57 +  LDP Discovery Sources: +    IPv4: +      Interface: eth1 +    IPv6: +      Targeted Hello: 3:3:3::3 +      Interface: eth1 +``` + +Note that the neighborships with the P and PE2 routers were established +over IPv6, since this is the default behavior for dual-stack LSRs, as +specified in RFC 7552. If desired, the **dual-stack transport-connection +prefer ipv4** command can be used to establish these sessions over IPv4 +(the command should be applied an all routers). + +Now, verify that there's a remote label for each PE address: +``` +linux# show mpls ldp binding +1.1.1.1/32 +        Local binding: label: 20 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             imp-null +            2.2.2.2             24000 +            3.3.3.3             20 +2.2.2.2/32 +        Local binding: label: 21 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             18 +            2.2.2.2             imp-null +            3.3.3.3             21 +3.3.3.3/32 +        Local binding: label: 22 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             21 +            2.2.2.2             24003 +            3.3.3.3             imp-null +4.4.4.4/32 +        Local binding: label: imp-null +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             22 +            2.2.2.2             24001 +            3.3.3.3             22 +10.0.1.0/24 +        Local binding: label: 23 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             imp-null +            2.2.2.2             imp-null +            3.3.3.3             23 +10.0.2.0/24 +        Local binding: label: 24 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             20 +            2.2.2.2             imp-null +            3.3.3.3             imp-null +10.0.3.0/24 +        Local binding: label: imp-null +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             19 +            2.2.2.2             imp-null +            3.3.3.3             24 +10.0.4.0/24 +        Local binding: label: imp-null +        Remote bindings: +            Peer                Label +            -----------------   --------- +            1.1.1.1             23 +            2.2.2.2             24002 +            3.3.3.3             imp-null +2:2:2::2/128 +        Local binding: label: 18 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            2.2.2.2             imp-null +            3.3.3.3             18 +3:3:3::3/128 +        Local binding: label: 19 +        Remote bindings: +            Peer                Label +            -----------------   --------- +            2.2.2.2             24007 +4:4:4::4/128 +        Local binding: label: imp-null +        Remote bindings: +            Peer                Label +            -----------------   --------- +            2.2.2.2             24006 +            3.3.3.3             19 +2001:db8:2::/64 +        Local binding: label: - +        Remote bindings: +            Peer                Label +            -----------------   --------- +            2.2.2.2             imp-null +            3.3.3.3             imp-null +2001:db8:3::/64 +        Local binding: label: imp-null +        Remote bindings: +            Peer                Label +            -----------------   --------- +            2.2.2.2             imp-null +2001:db8:4::/64 +        Local binding: label: imp-null +        Remote bindings: +            Peer                Label +            -----------------   --------- +            3.3.3.3             imp-null +``` + +Check if the pseudowires are up: +``` +linux# show l2vpn atom vc +Interface Peer ID         VC ID      Name             Status +--------- --------------- ---------- ---------------- ---------- +mpw1      3.3.3.3         100        ENG              UP +mpw0      1.1.1.1         100        ENG              UP +``` + +Check the label bindings of the pseudowires: +``` +linux# show l2vpn atom binding +  Destination Address: 1.1.1.1, VC ID: 100 +    Local Label:  25 +        Cbit: 1,    VC Type: Ethernet,    GroupID: 0 +        MTU: 1500 +    Remote Label:  16 +        Cbit: 1,    VC Type: Ethernet,    GroupID: 0 +        MTU: 1500 +  Destination Address: 3.3.3.3, VC ID: 100 +    Local Label:  26 +        Cbit: 1,    VC Type: Ethernet,    GroupID: 0 +        MTU: 1500 +    Remote Label:  26 +        Cbit: 1,    VC Type: Ethernet,    GroupID: 0 +        MTU: 1500 +``` + +## Verification - Data Plane + +Verify that all the exchanged label mappings were installed in zebra: +``` +linux# show mpls table + Inbound                            Outbound +   Label     Type          Nexthop     Label +--------  -------  ---------------  -------- +      17      LDP    2001:db8:3::2         3 +      19      LDP    2001:db8:3::2     24005 +      20      LDP         10.0.3.2     24000 +      21      LDP         10.0.3.2         3 +      22      LDP         10.0.3.2     24001 +      23      LDP         10.0.3.2         3 +      24      LDP         10.0.3.2         3 +      25      LDP         10.0.3.2         3 + +linux# show ip route ldp +Codes: K - kernel route, C - connected, S - static, R - RIP, +       O - OSPF, I - IS-IS, B - BGP, P - PIM, A - Babel, L - LDP, +       > - selected route, * - FIB route + +L>* 1.1.1.1/32 [0/0] via 10.0.3.2, eth2 label 24000 +L>* 3.3.3.3/32 [0/0] via 10.0.3.2, eth2 label 24001 +``` + +Verify that all the exchanged label mappings were installed in the kernel: +``` +$ ip -M ro +17 via inet6 2001:db8:3::2 dev eth2  proto zebra +19 as to 24005 via inet6 2001:db8:3::2 dev eth2  proto zebra +20 as to 24000 via inet 10.0.3.2 dev eth2  proto zebra +21 via inet 10.0.3.2 dev eth2  proto zebra +22 as to 24001 via inet 10.0.3.2 dev eth2  proto zebra +23 via inet 10.0.3.2 dev eth2  proto zebra +24 via inet 10.0.3.2 dev eth2  proto zebra +25 via inet 10.0.3.2 dev eth2  proto zebra +$ +$ ip route | grep mpls +1.1.1.1  encap mpls  24000 via 10.0.3.2 dev eth2  proto zebra  metric 20 +3.3.3.3  encap mpls  24001 via 10.0.3.2 dev eth2  proto zebra  metric 20 +``` + +Now ping PE1's loopback using lo1's address as a source address: +``` +$ ping -c 5 -I 4.4.4.4 1.1.1.1 +PING 1.1.1.1 (1.1.1.1) from 4.4.4.4 : 56(84) bytes of data. +64 bytes from 1.1.1.1: icmp_seq=1 ttl=253 time=3.02 ms +64 bytes from 1.1.1.1: icmp_seq=2 ttl=253 time=3.13 ms +64 bytes from 1.1.1.1: icmp_seq=3 ttl=253 time=3.19 ms +64 bytes from 1.1.1.1: icmp_seq=4 ttl=253 time=3.07 ms +64 bytes from 1.1.1.1: icmp_seq=5 ttl=253 time=3.27 ms + +--- 1.1.1.1 ping statistics --- +5 packets transmitted, 5 received, 0% packet loss, time 4005ms +rtt min/avg/max/mdev = 3.022/3.140/3.278/0.096 ms +``` + +Verify that the ICMP echo request packets are leaving with the MPLS +label advertised by the P router. Also, verify that the ICMP echo reply +packets are arriving with an explicit-null MPLS label: +``` +# tcpdump -n -i eth2 mpls and icmp +tcpdump: verbose output suppressed, use -v or -vv for full protocol decode +listening on eth2, link-type EN10MB (Ethernet), capture size 262144 bytes +10:01:40.758771 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 1, length 64 +10:01:40.761777 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 1, length 64 +10:01:41.760343 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 2, length 64 +10:01:41.763448 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 2, length 64 +10:01:42.761758 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 3, length 64 +10:01:42.764924 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 3, length 64 +10:01:43.763193 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 4, length 64 +10:01:43.766237 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 4, length 64 +10:01:44.764552 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 5, length 64 +10:01:44.767803 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 5, length 64 +``` diff --git a/doc/ldpd.8 b/doc/ldpd.8 new file mode 100644 index 0000000000..092ff39d49 --- /dev/null +++ b/doc/ldpd.8 @@ -0,0 +1,109 @@ +.TH LDPD 8 "29 March 2016" "Quagga LDP daemon" "Version 1.0.20160309" +.SH NAME +ldpd \- an LDP engine for use with Quagga routing software. +.SH SYNOPSIS +.B ldpd +[ +.B \-dhv +] [ +.B \-f +.I config-file +] [ +.B \-i +.I pid-file +] [ +.B \-P +.I port-number +] [ +.B \-A +.I vty-address +] [ +.B \-u +.I user +] [ +.B \-g +.I group +] +.SH DESCRIPTION +.B ldpd +is a component that works with the +.B Quagga +routing engine. +.SH OPTIONS +Options available for the +.B ldpd +command: +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR  +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ldpd.conf\fR. +.TP +\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR +Specify the group to run as. Default is \fIquagga\fR. +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ldpd starts its process identifier is written to +\fB\fIpid-file\fR.  The init system uses the recorded PID to stop or +restart ldpd.  The likely default is \fB\fI/var/run/ldpd.pid\fR. +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR  +Specify the port that the ldpd VTY will listen on. This defaults to +2612, as specified in \fB\fI/etc/services\fR. +.TP +\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR +Specify the address that the ldpd VTY will listen on. Default is all +interfaces. +.TP +\fB\-u\fR, \fB\-\-user \fR\fIuser\fR +Specify the user to run as. Default is \fIquagga\fR. +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. +.SH FILES +.TP +.BI /usr/local/sbin/ldpd +The default location of the  +.B ldpd +binary. +.TP +.BI /usr/local/etc/ldpd.conf +The default location of the  +.B ldpd +config file. +.TP +.BI $(PWD)/ldpd.log  +If the  +.B ldpd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBldpd\fR. +.SH WARNING +This man page is intended to be a quick reference for command line +options. The definitive document is the Info file \fBQuagga\fR. +.SH DIAGNOSTICS +The ldpd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBldpd\fR supports many +debugging options, see the Info file, or the source for details. +.SH "SEE ALSO" +.BR bgpd (8), +.BR ripd (8), +.BR ripngd (8), +.BR ospfd (8), +.BR ospf6d (8), +.BR isisd (8), +.BR zebra (8), +.BR vtysh (1) +.SH BUGS +.B ldpd +eats bugs for breakfast. If you have food for the maintainers try +.BI http://bugzilla.quagga.net +.SH AUTHORS +See +.BI http://www.quagga.net +or the Info file for an accurate list of authors. + diff --git a/ldpd/.gitignore b/ldpd/.gitignore new file mode 100644 index 0000000000..be90d42119 --- /dev/null +++ b/ldpd/.gitignore @@ -0,0 +1,18 @@ +Makefile +Makefile.in +*.o +ldpd +ldpd.conf +tags +TAGS +.deps +.nfs* +*.lo +*.la +*.a +*.libs +.arch-inventory +.arch-ids +*~ +*.loT + diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am new file mode 100644 index 0000000000..c292adf6fc --- /dev/null +++ b/ldpd/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in. + +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +AM_CFLAGS = $(WERROR) + +noinst_LIBRARIES = libldp.a +sbin_PROGRAMS = ldpd + +libldp_a_SOURCES = \ +	accept.c address.c adjacency.c control.c hello.c init.c interface.c \ +	keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \ +	ldpe.c log.c neighbor.c notification.c packet.c pfkey.c \ +	socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \ +	ldp_debug.c ldp_zebra.c + +noinst_HEADERS = \ +	control.h lde.h ldpd.h ldpe.h ldp.h log.h ldp_debug.h ldp_vty.h + +ldpd_SOURCES = ldpd.c +ldpd_LDADD = libldp.a ../lib/libzebra.la @LIBCAP@ + +examplesdir = $(exampledir) +dist_examples_DATA = ldpd.conf.sample diff --git a/ldpd/accept.c b/ldpd/accept.c index bc13ad49e7..4cb461b908 100644 --- a/ldpd/accept.c +++ b/ldpd/accept.c @@ -16,8 +16,7 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <stdlib.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h" @@ -25,31 +24,30 @@  struct accept_ev {  	LIST_ENTRY(accept_ev)	 entry; -	struct event		 ev; -	void			(*accept_cb)(int, short, void *); +	struct thread		*ev; +	int			(*accept_cb)(struct thread *);  	void			*arg;  	int			 fd;  };  struct { -	LIST_HEAD(, accept_ev)	queue; -	struct event		evt; +	LIST_HEAD(, accept_ev)	 queue; +	struct thread		*evt;  } accept_queue;  static void	accept_arm(void);  static void	accept_unarm(void); -static void	accept_cb(int, short, void *); -static void	accept_timeout(int, short, void *); +static int	accept_cb(struct thread *); +static int	accept_timeout(struct thread *);  void  accept_init(void)  {  	LIST_INIT(&accept_queue.queue); -	evtimer_set(&accept_queue.evt, accept_timeout, NULL);  }  int -accept_add(int fd, void (*cb)(int, short, void *), void *arg) +accept_add(int fd, int (*cb)(struct thread *), void *arg)  {  	struct accept_ev	*av; @@ -60,8 +58,7 @@ accept_add(int fd, void (*cb)(int, short, void *), void *arg)  	av->arg = arg;  	LIST_INSERT_HEAD(&accept_queue.queue, av, entry); -	event_set(&av->ev, av->fd, EV_READ, accept_cb, av); -	event_add(&av->ev, NULL); +	av->ev = thread_add_read(master, accept_cb, av, av->fd);  	log_debug("%s: accepting on fd %d", __func__, fd); @@ -76,7 +73,7 @@ accept_del(int fd)  	LIST_FOREACH(av, &accept_queue.queue, entry)  		if (av->fd == fd) {  			log_debug("%s: %d removed from queue", __func__, fd); -			event_del(&av->ev); +			THREAD_READ_OFF(av->ev);  			LIST_REMOVE(av, entry);  			free(av);  			return; @@ -86,19 +83,17 @@ accept_del(int fd)  void  accept_pause(void)  { -	struct timeval evtpause = { 1, 0 }; -  	log_debug(__func__);  	accept_unarm(); -	evtimer_add(&accept_queue.evt, &evtpause); +	accept_queue.evt = thread_add_timer(master, accept_timeout, NULL, 1);  }  void  accept_unpause(void)  { -	if (evtimer_pending(&accept_queue.evt, NULL)) { +	if (accept_queue.evt != NULL) {  		log_debug(__func__); -		evtimer_del(&accept_queue.evt); +		THREAD_TIMER_OFF(accept_queue.evt);  		accept_arm();  	}  } @@ -108,7 +103,7 @@ accept_arm(void)  {  	struct accept_ev	*av;  	LIST_FOREACH(av, &accept_queue.queue, entry) -		event_add(&av->ev, NULL); +		av->ev = thread_add_read(master, accept_cb, av, av->fd);  }  static void @@ -116,20 +111,26 @@ accept_unarm(void)  {  	struct accept_ev	*av;  	LIST_FOREACH(av, &accept_queue.queue, entry) -		event_del(&av->ev); +		THREAD_READ_OFF(av->ev);  } -static void -accept_cb(int fd, short event, void *arg) +static int +accept_cb(struct thread *thread)  { -	struct accept_ev	*av = arg; -	event_add(&av->ev, NULL); -	av->accept_cb(fd, event, av->arg); +	struct accept_ev	*av = THREAD_ARG(thread); +	av->ev = thread_add_read(master, accept_cb, av, av->fd); +	av->accept_cb(thread); + +	return (0);  } -static void -accept_timeout(int fd, short event, void *bula) +static int +accept_timeout(struct thread *thread)  { +	accept_queue.evt = NULL; +  	log_debug(__func__);  	accept_arm(); + +	return (0);  } diff --git a/ldpd/address.c b/ldpd/address.c index 5e95fcc271..1c4c116f21 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -16,15 +16,13 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "lde.h"  #include "log.h" +#include "ldp_debug.h"  static void	 send_address(struct nbr *, int, struct if_addr_head *,  		    unsigned int, int); @@ -94,7 +92,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list,  		}  		while ((if_addr = LIST_FIRST(addr_list)) != NULL) { -			log_debug("msg-out: %s: lsr-id %s, address %s", +			debug_msg_send("%s: lsr-id %s address %s",  			    msg_name(msg_type), inet_ntoa(nbr->id),  			    log_addr(af, &if_addr->addr)); @@ -225,9 +223,8 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len)  			fatalx("recv_address: unknown af");  		} -		log_debug("msg-in: %s: lsr-id %s, address %s", -		    msg_name(msg_type), inet_ntoa(nbr->id), -		    log_addr(lde_addr.af, &lde_addr.addr)); +		debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type), +		    inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr));  		ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr,  		    sizeof(lde_addr)); diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 266717729f..3607ee96b3 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -19,19 +19,15 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" -static void	 adj_del_single(struct adj *); -static void	 adj_itimer(int, short, void *); +static int	 adj_itimer(struct thread *);  static void	 tnbr_del(struct tnbr *); -static void	 tnbr_hello_timer(int, short, void *); +static int	 tnbr_hello_timer(struct thread *);  static void	 tnbr_start_hello_timer(struct tnbr *);  static void	 tnbr_stop_hello_timer(struct tnbr *); @@ -52,8 +48,6 @@ adj_new(struct in_addr lsr_id, struct hello_source *source,  	adj->source = *source;  	adj->trans_addr = *addr; -	evtimer_set(&adj->inactivity_timer, adj_itimer, adj); -  	LIST_INSERT_HEAD(&global.adj_list, adj, global_entry);  	switch (source->type) { @@ -154,10 +148,12 @@ adj_get_af(struct adj *adj)  /* adjacency timers */  /* ARGSUSED */ -static void -adj_itimer(int fd, short event, void *arg) +static int +adj_itimer(struct thread *thread)  { -	struct adj *adj = arg; +	struct adj *adj = THREAD_ARG(thread); + +	adj->inactivity_timer = NULL;  	log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id)); @@ -166,37 +162,34 @@ adj_itimer(int fd, short event, void *arg)  		    adj->source.target->pw_count == 0) {  			/* remove dynamic targeted neighbor */  			tnbr_del(adj->source.target); -			return; +			return (0);  		}  		adj->source.target->adj = NULL;  	}  	adj_del(adj, S_HOLDTIME_EXP); + +	return (0);  }  void  adj_start_itimer(struct adj *adj)  { -	struct timeval	tv; - -	timerclear(&tv); -	tv.tv_sec = adj->holdtime; -	if (evtimer_add(&adj->inactivity_timer, &tv) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(adj->inactivity_timer); +	adj->inactivity_timer = thread_add_timer(master, adj_itimer, adj, +	    adj->holdtime);  }  void  adj_stop_itimer(struct adj *adj)  { -	if (evtimer_pending(&adj->inactivity_timer, NULL) && -	    evtimer_del(&adj->inactivity_timer) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(adj->inactivity_timer);  }  /* targeted neighbors */  struct tnbr * -tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) +tnbr_new(int af, union ldpd_addr *addr)  {  	struct tnbr		*tnbr; @@ -206,8 +199,6 @@ tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr)  	tnbr->af = af;  	tnbr->addr = *addr;  	tnbr->state = TNBR_STA_DOWN; -	tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime; -	tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval;  	return (tnbr);  } @@ -257,7 +248,7 @@ tnbr_update(struct tnbr *tnbr)  	else  		socket_ok = 0; -	if (leconf->rtr_id.s_addr != INADDR_ANY) +	if (ldp_rtr_id_get(leconf) != INADDR_ANY)  		rtr_id_ok = 1;  	else  		rtr_id_ok = 0; @@ -269,7 +260,6 @@ tnbr_update(struct tnbr *tnbr)  		tnbr->state = TNBR_STA_ACTIVE;  		send_hello(HELLO_TARGETED, NULL, tnbr); -		evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr);  		tnbr_start_hello_timer(tnbr);  	} else if (tnbr->state == TNBR_STA_ACTIVE) {  		if (socket_ok && rtr_id_ok) @@ -291,35 +281,51 @@ tnbr_update_all(int af)  			tnbr_update(tnbr);  } +uint16_t +tnbr_get_hello_holdtime(struct tnbr *tnbr) +{ +	if ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime != 0) +		return ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime); + +	return (leconf->thello_holdtime); +} + +uint16_t +tnbr_get_hello_interval(struct tnbr *tnbr) +{ +	if ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval != 0) +		return ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval); + +	return (leconf->thello_interval); +} +  /* target neighbors timers */  /* ARGSUSED */ -static void -tnbr_hello_timer(int fd, short event, void *arg) +static int +tnbr_hello_timer(struct thread *thread)  { -	struct tnbr	*tnbr = arg; +	struct tnbr	*tnbr = THREAD_ARG(thread); +	tnbr->hello_timer = NULL;  	send_hello(HELLO_TARGETED, NULL, tnbr);  	tnbr_start_hello_timer(tnbr); + +	return (0);  }  static void  tnbr_start_hello_timer(struct tnbr *tnbr)  { -	struct timeval	 tv; - -	timerclear(&tv); -	tv.tv_sec = tnbr->hello_interval; -	if (evtimer_add(&tnbr->hello_timer, &tv) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(tnbr->hello_timer); +	tnbr->hello_timer = thread_add_timer(master, tnbr_hello_timer, tnbr, +	    tnbr_get_hello_interval(tnbr));  }  static void  tnbr_stop_hello_timer(struct tnbr *tnbr)  { -	if (evtimer_pending(&tnbr->hello_timer, NULL) && -	    evtimer_del(&tnbr->hello_timer) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(tnbr->hello_timer);  }  struct ctl_adj * diff --git a/ldpd/control.c b/ldpd/control.c index b7cb3f1063..ba303cc12c 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -16,13 +16,8 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/stat.h> +#include <zebra.h>  #include <sys/un.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h>  #include "ldpd.h"  #include "ldpe.h" @@ -31,11 +26,11 @@  #define	CONTROL_BACKLOG	5 -static void		 control_accept(int, short, void *); +static int		 control_accept(struct thread *);  static struct ctl_conn	*control_connbyfd(int);  static struct ctl_conn	*control_connbypid(pid_t);  static void		 control_close(int); -static void		 control_dispatch_imsg(int, short, void *); +static int		 control_dispatch_imsg(struct thread *);  struct ctl_conns	 ctl_conns; @@ -48,11 +43,11 @@ control_init(void)  	int			 fd;  	mode_t			 old_umask; -	if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, -	    0)) == -1) { +	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {  		log_warn("%s: socket", __func__);  		return (-1);  	} +	sock_set_nonblock(fd);  	memset(&s_un, 0, sizeof(s_un));  	s_un.sun_family = AF_UNIX; @@ -106,8 +101,8 @@ control_cleanup(void)  }  /* ARGSUSED */ -static void -control_accept(int listenfd, short event, void *bula) +static int +control_accept(struct thread *thread)  {  	int			 connfd;  	socklen_t		 len; @@ -115,8 +110,8 @@ control_accept(int listenfd, short event, void *bula)  	struct ctl_conn		*c;  	len = sizeof(s_un); -	if ((connfd = accept4(listenfd, (struct sockaddr *)&s_un, &len, -	    SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) { +	if ((connfd = accept(THREAD_FD(thread), (struct sockaddr *)&s_un, +	    &len)) == -1) {  		/*  		 * Pause accept if we are out of file descriptors, or  		 * libevent will haunt us here too. @@ -125,24 +120,27 @@ control_accept(int listenfd, short event, void *bula)  			accept_pause();  		else if (errno != EWOULDBLOCK && errno != EINTR &&  		    errno != ECONNABORTED) -			log_warn("%s: accept4", __func__); -		return; +			log_warn("%s: accept", __func__); +		return (0);  	} +	sock_set_nonblock(connfd);  	if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) {  		log_warn(__func__);  		close(connfd); -		return; +		return (0);  	}  	imsg_init(&c->iev.ibuf, connfd); -	c->iev.handler = control_dispatch_imsg; -	c->iev.events = EV_READ; -	event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, -	    c->iev.handler, &c->iev); -	event_add(&c->iev.ev, NULL); +	c->iev.handler_read = control_dispatch_imsg; +	c->iev.ev_read = thread_add_read(master, c->iev.handler_read, +	    &c->iev, c->iev.ibuf.fd); +	c->iev.handler_write = ldp_write_handler; +	c->iev.ev_write = NULL;  	TAILQ_INSERT_TAIL(&ctl_conns, c, entry); + +	return (0);  }  static struct ctl_conn * @@ -182,45 +180,40 @@ control_close(int fd)  	msgbuf_clear(&c->iev.ibuf.w);  	TAILQ_REMOVE(&ctl_conns, c, entry); -	event_del(&c->iev.ev); +	THREAD_READ_OFF(c->iev.ev_read); +	THREAD_WRITE_OFF(c->iev.ev_write);  	close(c->iev.ibuf.fd);  	accept_unpause();  	free(c);  }  /* ARGSUSED */ -static void -control_dispatch_imsg(int fd, short event, void *bula) +static int +control_dispatch_imsg(struct thread *thread)  { +	int		 fd = THREAD_FD(thread);  	struct ctl_conn	*c;  	struct imsg	 imsg;  	ssize_t		 n;  	unsigned int	 ifidx; -	int		 verbose;  	if ((c = control_connbyfd(fd)) == NULL) {  		log_warnx("%s: fd %d: not found", __func__, fd); -		return; +		return (0);  	} -	if (event & EV_READ) { -		if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || -		    n == 0) { -			control_close(fd); -			return; -		} -	} -	if (event & EV_WRITE) { -		if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { -			control_close(fd); -			return; -		} +	c->iev.ev_read = NULL; + +	if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || +	    n == 0) { +		control_close(fd); +		return (0);  	}  	for (;;) {  		if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) {  			control_close(fd); -			return; +			return (0);  		}  		if (n == 0) @@ -230,16 +223,10 @@ control_dispatch_imsg(int fd, short event, void *bula)  		case IMSG_CTL_FIB_COUPLE:  		case IMSG_CTL_FIB_DECOUPLE:  		case IMSG_CTL_RELOAD: -			c->iev.ibuf.pid = imsg.hdr.pid; -			ldpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); -			break;  		case IMSG_CTL_KROUTE:  		case IMSG_CTL_KROUTE_ADDR:  		case IMSG_CTL_IFINFO: -			c->iev.ibuf.pid = imsg.hdr.pid; -			ldpe_imsg_compose_parent(imsg.hdr.type, -			    imsg.hdr.pid, imsg.data, -			    imsg.hdr.len - IMSG_HEADER_SIZE); +			/* ignore */  			break;  		case IMSG_CTL_SHOW_INTERFACE:  			if (imsg.hdr.len == IMSG_HEADER_SIZE + @@ -271,18 +258,7 @@ control_dispatch_imsg(int fd, short event, void *bula)  			nbr_clear_ctl(imsg.data);  			break;  		case IMSG_CTL_LOG_VERBOSE: -			if (imsg.hdr.len != IMSG_HEADER_SIZE + -			    sizeof(verbose)) -				break; - -			/* forward to other processes */ -			ldpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, -			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); -			ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid, -			    imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - -			memcpy(&verbose, imsg.data, sizeof(verbose)); -			log_verbose(verbose); +			/* ignore */  			break;  		default:  			log_debug("%s: error handling imsg %d", __func__, @@ -293,6 +269,8 @@ control_dispatch_imsg(int fd, short event, void *bula)  	}  	imsg_event_add(&c->iev); + +	return (0);  }  int diff --git a/ldpd/control.h b/ldpd/control.h index fd6e47071d..32c49fdf87 100644 --- a/ldpd/control.h +++ b/ldpd/control.h @@ -19,8 +19,7 @@  #ifndef _CONTROL_H_  #define	_CONTROL_H_ -#include <sys/types.h> -#include <sys/queue.h> +#include "openbsd-queue.h"  struct ctl_conn {  	TAILQ_ENTRY(ctl_conn)	entry; diff --git a/ldpd/hello.c b/ldpd/hello.c index d0daed347d..755b25aa85 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -17,13 +17,12 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "ldp_debug.h"  static int	gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t);  static int	gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t); @@ -46,7 +45,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)  	switch (type) {  	case HELLO_LINK:  		af = ia->af; -		holdtime = ia->hello_holdtime; +		holdtime = if_get_hello_holdtime(ia);  		flags = 0;  		fd = (ldp_af_global_get(&global, af))->ldp_disc_socket; @@ -66,7 +65,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)  		break;  	case HELLO_TARGETED:  		af = tnbr->af; -		holdtime = tnbr->hello_holdtime; +		holdtime = tnbr_get_hello_holdtime(tnbr);  		flags = F_HELLO_TARGETED;  		if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count)  			flags |= F_HELLO_REQ_TARG; @@ -139,6 +138,20 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr)  		return (-1);  	} +	switch (type) { +	case HELLO_LINK: +		debug_hello_send("iface %s (%s) holdtime %u", ia->iface->name, +		    af_name(ia->af), holdtime); +		break; +	case HELLO_TARGETED: +		debug_hello_send("targeted-neighbor %s (%s) holdtime %u", +		    log_addr(tnbr->af, &tnbr->addr), af_name(tnbr->af), +		    holdtime); +		break; +	default: +		fatalx("send_hello: unknown hello type"); +	} +  	send_packet(fd, af, &dst, ia, buf->buf, buf->wpos);  	ibuf_free(buf); @@ -152,7 +165,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,  {  	struct adj		*adj = NULL;  	struct nbr		*nbr, *nbrt; -	uint16_t		 holdtime, flags; +	uint16_t		 holdtime = 0, flags = 0;  	int			 tlvs_rcvd;  	int			 ds_tlv;  	union ldpd_addr		 trans_addr; @@ -257,7 +270,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,  			    F_LDPD_AF_THELLO_ACCEPT)))  				return; -			tnbr = tnbr_new(leconf, af, src); +			tnbr = tnbr_new(af, src);  			tnbr->flags |= F_TNBR_DYNAMIC;  			tnbr_update(tnbr);  			LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); @@ -387,19 +400,23 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af,  		if (holdtime == 0)  			holdtime = LINK_DFLT_HOLDTIME; -		adj->holdtime = min(ia->hello_holdtime, holdtime); +		adj->holdtime = min(if_get_hello_holdtime(ia), holdtime);  		break;  	case HELLO_TARGETED:  		if (holdtime == 0)  			holdtime = TARGETED_DFLT_HOLDTIME; -		adj->holdtime = min(tnbr->hello_holdtime, holdtime); +		adj->holdtime = min(tnbr_get_hello_holdtime(tnbr), holdtime);  	}  	if (adj->holdtime != INFINITE_HOLDTIME)  		adj_start_itimer(adj);  	else  		adj_stop_itimer(adj); +	debug_hello_recv("%s lsr-id %s transport-address %s holdtime %u%s", +	    log_hello_src(&source), inet_ntoa(lsr_id), log_addr(af, &trans_addr), +	     holdtime, (ds_tlv) ? " (dual stack TLV present)" : ""); +  	if (nbr && nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr) &&  	    nbr_session_active_role(nbr) && !nbr_pending_connect(nbr))  		nbr_establish_connection(nbr); diff --git a/ldpd/init.c b/ldpd/init.c index eb22bf52ac..ed6b53c02d 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -16,13 +16,12 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "ldp_debug.h"  static int	gen_init_prms_tlv(struct ibuf *, struct nbr *); @@ -33,7 +32,7 @@ send_init(struct nbr *nbr)  	uint16_t		 size;  	int			 err = 0; -	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); +	debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id));  	size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE;  	if ((buf = ibuf_open(size)) == NULL) @@ -59,7 +58,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)  	struct sess_prms_tlv	sess;  	uint16_t		max_pdu_len; -	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); +	debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id));  	memcpy(&msg, buf, sizeof(msg));  	buf += LDP_MSG_SIZE; @@ -82,7 +81,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len)  		session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type);  		return (-1);  	} -	if (sess.lsr_id != leconf->rtr_id.s_addr || +	if (sess.lsr_id != ldp_rtr_id_get(leconf) ||  	    ntohs(sess.lspace_id) != 0) {  		session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type);  		return (-1); diff --git a/ldpd/interface.c b/ldpd/interface.c index ff4c8f169c..b6472fe5e8 100644 --- a/ldpd/interface.c +++ b/ldpd/interface.c @@ -18,22 +18,20 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/time.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "sockopt.h" +  static struct if_addr	*if_addr_new(struct kaddr *);  static struct if_addr	*if_addr_lookup(struct if_addr_head *, struct kaddr *);  static int		 if_start(struct iface *, int);  static int		 if_reset(struct iface *, int);  static void		 if_update_af(struct iface_af *, int); -static void		 if_hello_timer(int, short, void *); +static int		 if_hello_timer(struct thread *);  static void		 if_start_hello_timer(struct iface_af *);  static void		 if_stop_hello_timer(struct iface_af *);  static int		 if_join_ipv4_group(struct iface *, struct in_addr *); @@ -50,20 +48,9 @@ if_new(struct kif *kif)  		fatal("if_new: calloc");  	strlcpy(iface->name, kif->ifname, sizeof(iface->name)); - -	/* get type */ -	if (kif->flags & IFF_POINTOPOINT) -		iface->type = IF_TYPE_POINTOPOINT; -	if (kif->flags & IFF_BROADCAST && -	    kif->flags & IFF_MULTICAST) -		iface->type = IF_TYPE_BROADCAST; - -	/* get index and flags */  	LIST_INIT(&iface->addr_list); -	iface->ifindex = kif->ifindex; -	iface->flags = kif->flags; -	iface->linkstate = kif->link_state; -	iface->if_type = kif->if_type; +	if (kif->ifindex) +		if_update_info(iface, kif);  	/* ipv4 */  	iface->ipv4.af = AF_INET; @@ -112,6 +99,33 @@ if_exit(struct iface *iface)  	}  } +struct iface * +if_lookup_name(struct ldpd_conf *xconf, const char *ifname) +{ +	struct iface *iface; + +	LIST_FOREACH(iface, &xconf->iface_list, entry) +		if (strcmp(iface->name, ifname) == 0) +			return (iface); + +	return (NULL); +} + +void +if_update_info(struct iface *iface, struct kif *kif) +{ +	/* get type */ +	if (kif->flags & IFF_POINTOPOINT) +		iface->type = IF_TYPE_POINTOPOINT; +	if (kif->flags & IFF_BROADCAST && +	    kif->flags & IFF_MULTICAST) +		iface->type = IF_TYPE_BROADCAST; + +	/* get index and flags */ +	iface->ifindex = kif->ifindex; +	iface->flags = kif->flags; +} +  struct iface_af *  iface_af_get(struct iface *iface, int af)  { @@ -258,7 +272,6 @@ if_start(struct iface *iface, int af)  	send_hello(HELLO_LINK, ia, NULL); -	evtimer_set(&ia->hello_timer, if_hello_timer, ia);  	if_start_hello_timer(ia);  	return (0);  } @@ -328,7 +341,7 @@ if_update_af(struct iface_af *ia, int link_ok)  	else  		socket_ok = 0; -	if (leconf->rtr_id.s_addr != INADDR_ANY) +	if (ldp_rtr_id_get(leconf) != INADDR_ANY)  		rtr_id_ok = 1;  	else  		rtr_id_ok = 0; @@ -354,8 +367,7 @@ if_update(struct iface *iface, int af)  {  	int			 link_ok; -	link_ok = (iface->flags & IFF_UP) && -	    LINK_STATE_IS_UP(iface->linkstate); +	link_ok = (iface->flags & IFF_UP) && (iface->flags & IFF_RUNNING);  	if (af == AF_INET || af == AF_UNSPEC)  		if_update_af(&iface->ipv4, link_ok); @@ -372,34 +384,56 @@ if_update_all(int af)  		if_update(iface, af);  } +uint16_t +if_get_hello_holdtime(struct iface_af *ia) +{ +	if (ia->hello_holdtime != 0) +		return (ia->hello_holdtime); + +	if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0) +		return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime); + +	return (leconf->lhello_holdtime); +} + +uint16_t +if_get_hello_interval(struct iface_af *ia) +{ +	if (ia->hello_interval != 0) +		return (ia->hello_interval); + +	if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0) +		return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval); + +	return (leconf->lhello_interval); +} +  /* timers */  /* ARGSUSED */ -static void -if_hello_timer(int fd, short event, void *arg) +static int +if_hello_timer(struct thread *thread)  { -	struct iface_af		*ia = arg; +	struct iface_af		*ia = THREAD_ARG(thread); +	ia->hello_timer = NULL;  	send_hello(HELLO_LINK, ia, NULL);  	if_start_hello_timer(ia); + +	return (0);  }  static void  if_start_hello_timer(struct iface_af *ia)  { -	struct timeval		 tv; - -	timerclear(&tv); -	tv.tv_sec = ia->hello_interval; -	if (evtimer_add(&ia->hello_timer, &tv) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(ia->hello_timer); +	ia->hello_timer = thread_add_timer(master, if_hello_timer, ia, +	    if_get_hello_interval(ia));  }  static void  if_stop_hello_timer(struct iface_af *ia)  { -	if (evtimer_pending(&ia->hello_timer, NULL) && -	    evtimer_del(&ia->hello_timer) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(ia->hello_timer);  }  struct ctl_iface * @@ -414,11 +448,9 @@ if_to_ctl(struct iface_af *ia)  	ictl.ifindex = ia->iface->ifindex;  	ictl.state = ia->state;  	ictl.flags = ia->iface->flags; -	ictl.linkstate = ia->iface->linkstate;  	ictl.type = ia->iface->type; -	ictl.if_type = ia->iface->if_type; -	ictl.hello_holdtime = ia->hello_holdtime; -	ictl.hello_interval = ia->hello_interval; +	ictl.hello_holdtime = if_get_hello_holdtime(ia); +	ictl.hello_interval = if_get_hello_interval(ia);  	gettimeofday(&now, NULL);  	if (ia->state != IF_STA_DOWN && @@ -450,16 +482,15 @@ if_get_ipv4_addr(struct iface *iface)  static int  if_join_ipv4_group(struct iface *iface, struct in_addr *addr)  { -	struct ip_mreq		 mreq; +	struct in_addr		 if_addr;  	log_debug("%s: interface %s addr %s", __func__, iface->name,  	    inet_ntoa(*addr)); -	mreq.imr_multiaddr = *addr; -	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); +	if_addr.s_addr = if_get_ipv4_addr(iface); -	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, -	    IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { +	if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket, +	    IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {  		log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s",  		     __func__, iface->name, inet_ntoa(*addr));  		return (-1); @@ -470,16 +501,15 @@ if_join_ipv4_group(struct iface *iface, struct in_addr *addr)  static int  if_leave_ipv4_group(struct iface *iface, struct in_addr *addr)  { -	struct ip_mreq		 mreq; +	struct in_addr		 if_addr;  	log_debug("%s: interface %s addr %s", __func__, iface->name,  	    inet_ntoa(*addr)); -	mreq.imr_multiaddr = *addr; -	mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); +	if_addr.s_addr = if_get_ipv4_addr(iface); -	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, -	    IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { +	if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket, +	    IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) {  		log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s "  		    "address %s", __func__, iface->name, inet_ntoa(*addr));  		return (-1); diff --git a/ldpd/keepalive.c b/ldpd/keepalive.c index 4cd49d485b..f9a7d850fd 100644 --- a/ldpd/keepalive.c +++ b/ldpd/keepalive.c @@ -16,12 +16,12 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "ldp_debug.h"  void  send_keepalive(struct nbr *nbr) @@ -37,6 +37,8 @@ send_keepalive(struct nbr *nbr)  	size -= LDP_HDR_SIZE;  	gen_msg_hdr(buf, MSG_TYPE_KEEPALIVE, size); +	debug_kalive_send("keepalive: lsr-id %s", inet_ntoa(nbr->id)); +  	evbuf_enqueue(&nbr->tcp->wbuf, buf);  } @@ -51,6 +53,8 @@ recv_keepalive(struct nbr *nbr, char *buf, uint16_t len)  		return (-1);  	} +	debug_kalive_recv("keepalive: lsr-id %s", inet_ntoa(nbr->id)); +  	if (nbr->state != NBR_STA_OPER)  		nbr_fsm(nbr, NBR_EVT_KEEPALIVE_RCVD); diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 22c98745e2..db382e484f 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -19,10 +19,7 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h" @@ -47,6 +44,7 @@ l2vpn_new(const char *name)  	LIST_INIT(&l2vpn->if_list);  	LIST_INIT(&l2vpn->pw_list); +	LIST_INIT(&l2vpn->pw_inactive_list);  	return (l2vpn);  } @@ -77,6 +75,10 @@ l2vpn_del(struct l2vpn *l2vpn)  		LIST_REMOVE(pw, entry);  		free(pw);  	} +	while ((pw = LIST_FIRST(&l2vpn->pw_inactive_list)) != NULL) { +		LIST_REMOVE(pw, entry); +		free(pw); +	}  	free(l2vpn);  } @@ -111,7 +113,6 @@ l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif)  	strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname));  	lif->ifindex = kif->ifindex;  	lif->flags = kif->flags; -	lif->link_state = kif->link_state;  	return (lif);  } @@ -128,6 +129,19 @@ l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex)  	return (NULL);  } +struct l2vpn_if * +l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname) +{ +	struct l2vpn_if	*lif; + +	LIST_FOREACH(lif, &l2vpn->if_list, entry) +		if (strcmp(lif->ifname, ifname) == 0) +			return (lif); + +	return (NULL); +} + +  struct l2vpn_pw *  l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif)  { @@ -151,6 +165,24 @@ l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex)  	LIST_FOREACH(pw, &l2vpn->pw_list, entry)  		if (pw->ifindex == ifindex)  			return (pw); +	LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) +		if (pw->ifindex == ifindex) +			return (pw); + +	return (NULL); +} + +struct l2vpn_pw * +l2vpn_pw_find_name(struct l2vpn *l2vpn, const char *ifname) +{ +	struct l2vpn_pw	*pw; + +	LIST_FOREACH(pw, &l2vpn->pw_list, entry) +		if (strcmp(pw->ifname, ifname) == 0) +			return (pw); +	LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) +		if (strcmp(pw->ifname, ifname) == 0) +			return (pw);  	return (NULL);  } @@ -399,6 +431,8 @@ l2vpn_pw_ctl(pid_t pid)  	LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry)  		LIST_FOREACH(pw, &l2vpn->pw_list, entry) {  			memset(&pwctl, 0, sizeof(pwctl)); +			strlcpy(pwctl.l2vpn_name, pw->l2vpn->name, +			    sizeof(pwctl.l2vpn_name));  			strlcpy(pwctl.ifname, pw->ifname,  			    sizeof(pwctl.ifname));  			pwctl.pwid = pw->pwid; @@ -438,6 +472,8 @@ l2vpn_binding_ctl(pid_t pid)  			pwctl.local_label = fn->local_label;  			pwctl.local_gid = 0;  			pwctl.local_ifmtu = pw->l2vpn->mtu; +			pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ? +			    1 : 0;  		} else  			pwctl.local_label = NO_LABEL; @@ -450,6 +486,9 @@ l2vpn_binding_ctl(pid_t pid)  			pwctl.remote_gid = me->map.fec.pwid.group_id;  			if (me->map.flags & F_MAP_PW_IFMTU)  				pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu; +			if (pw) +				pwctl.remote_cword = (pw->flags & F_PW_CWORD) ? +				    1 : 0;  			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING,  			    0, pid, &pwctl, sizeof(pwctl)); @@ -489,7 +528,7 @@ ldpe_l2vpn_pw_init(struct l2vpn_pw *pw)  	tnbr = tnbr_find(leconf, pw->af, &pw->addr);  	if (tnbr == NULL) { -		tnbr = tnbr_new(leconf, pw->af, &pw->addr); +		tnbr = tnbr_new(pw->af, &pw->addr);  		tnbr_update(tnbr);  		LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry);  	} diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 88e64071bb..62f2a620d2 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -17,17 +17,14 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netmpls/mpls.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "ldp_debug.h" + +#include "mpls.h"  static void	 enqueue_pdu(struct nbr *, struct ibuf *, uint16_t);  static int	 gen_label_tlv(struct ibuf *, uint32_t); @@ -127,8 +124,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh)  			return;  		} -		log_debug("msg-out: %s: lsr-id %s, fec %s, label %s", -		    msg_name(type), inet_ntoa(nbr->id), log_map(&me->map), +		debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type), +		    inet_ntoa(nbr->id), log_map(&me->map),  		    log_label(me->map.label));  		TAILQ_REMOVE(mh, me, entry); @@ -399,7 +396,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type)  		if (me->map.flags & F_MAP_REQ_ID)  			me->map.requestid = reqid; -		log_debug("msg-in: label mapping: lsr-id %s, fec %s, label %s", +		debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type),  		    inet_ntoa(nbr->id), log_map(&me->map),  		    log_label(me->map.label)); diff --git a/ldpd/lde.c b/ldpd/lde.c index 8859ed25b8..ae29ef6a7d 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -19,31 +19,24 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netmpls/mpls.h> -#include <arpa/inet.h> -#include <errno.h> -#include <stdlib.h> -#include <signal.h> -#include <string.h> -#include <pwd.h> -#include <unistd.h> -#include <limits.h> +#include <zebra.h>  #include "ldp.h"  #include "ldpd.h"  #include "ldpe.h"  #include "log.h"  #include "lde.h" +#include "ldp_debug.h" -static void		 lde_sig_handler(int sig, short, void *); -static __dead void	 lde_shutdown(void); -static int		 lde_imsg_compose_parent(int, pid_t, void *, uint16_t); -static void		 lde_dispatch_imsg(int, short, void *); -static void		 lde_dispatch_parent(int, short, void *); +#include <lib/log.h> +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "mpls.h" + +static void		 lde_shutdown(void); +static int		 lde_dispatch_imsg(struct thread *); +static int		 lde_dispatch_parent(struct thread *);  static __inline		 int lde_nbr_compare(struct lde_nbr *,  			    struct lde_nbr *);  static struct lde_nbr	*lde_nbr_new(uint32_t, struct lde_nbr *); @@ -65,89 +58,101 @@ struct nbr_tree		 lde_nbrs = RB_INITIALIZER(&lde_nbrs);  static struct imsgev	*iev_ldpe;  static struct imsgev	*iev_main; -/* ARGSUSED */ -static void -lde_sig_handler(int sig, short event, void *arg) +/* Master of threads. */ +struct thread_master *master; + +/* lde privileges */ +static zebra_capabilities_t _caps_p [] =  { -	/* -	 * signal handler rules don't apply, libevent decouples for us -	 */ +	/* none */ +}; -	switch (sig) { -	case SIGINT: -	case SIGTERM: -		lde_shutdown(); -		/* NOTREACHED */ -	default: -		fatalx("unexpected signal"); -	} +static struct zebra_privs_t lde_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) +	.user = QUAGGA_USER, +	.group = QUAGGA_GROUP, +#endif +#if defined(VTY_GROUP) +	.vty_group = VTY_GROUP, +#endif +	.caps_p = _caps_p, +	.cap_num_p = array_size(_caps_p), +	.cap_num_i = 0 +}; + +/* SIGINT / SIGTERM handler. */ +static void +sigint(void) +{ +	lde_shutdown();  } +static struct quagga_signal_t lde_signals[] = +{ +	{ +		.signal = SIGINT, +		.handler = &sigint, +	}, +	{ +		.signal = SIGTERM, +		.handler = &sigint, +	}, +}; +  /* label decision engine */  void -lde(int debug, int verbose) +lde(const char *user, const char *group)  { -	struct event		 ev_sigint, ev_sigterm; +	struct thread		 thread;  	struct timeval		 now; -	struct passwd		*pw;  	ldeconf = config_new_empty(); -	log_init(debug); -	log_verbose(verbose); - +#ifdef HAVE_SETPROCTITLE  	setproctitle("label decision engine"); +#endif  	ldpd_process = PROC_LDE_ENGINE; -	if ((pw = getpwnam(LDPD_USER)) == NULL) -		fatal("getpwnam"); - -	if (chroot(pw->pw_dir) == -1) -		fatal("chroot"); -	if (chdir("/") == -1) -		fatal("chdir(\"/\")"); - -	if (setgroups(1, &pw->pw_gid) || -	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || -	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) -		fatal("can't drop privileges"); +	/* drop privileges */ +	if (user) +		lde_privs.user = user; +	if (group) +		lde_privs.group = group; +	zprivs_init(&lde_privs); +#ifdef HAVE_PLEDGE  	if (pledge("stdio recvfd", NULL) == -1)  		fatal("pledge"); +#endif -	event_init(); +	master = thread_master_create();  	/* setup signal handler */ -	signal_set(&ev_sigint, SIGINT, lde_sig_handler, NULL); -	signal_set(&ev_sigterm, SIGTERM, lde_sig_handler, NULL); -	signal_add(&ev_sigint, NULL); -	signal_add(&ev_sigterm, NULL); -	signal(SIGPIPE, SIG_IGN); -	signal(SIGHUP, SIG_IGN); +	signal_init(master, array_size(lde_signals), lde_signals);  	/* setup pipe and event handler to the parent process */  	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)  		fatal(NULL);  	imsg_init(&iev_main->ibuf, 3); -	iev_main->handler = lde_dispatch_parent; -	iev_main->events = EV_READ; -	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, -	    iev_main->handler, iev_main); -	event_add(&iev_main->ev, NULL); - -	/* setup and start the LIB garbage collector */ -	evtimer_set(&gc_timer, lde_gc_timer, NULL); +	iev_main->handler_read = lde_dispatch_parent; +	iev_main->ev_read = thread_add_read(master, iev_main->handler_read, +	    iev_main, iev_main->ibuf.fd); +	iev_main->handler_write = ldp_write_handler; +	iev_main->ev_write = NULL; + +	/* start the LIB garbage collector */  	lde_gc_start_timer();  	gettimeofday(&now, NULL);  	global.uptime = now.tv_sec; -	event_dispatch(); - -	lde_shutdown(); +	/* Fetch next active thread. */ +	while (thread_fetch(master, &thread)) +		thread_call(&thread);  } -static __dead void +static void  lde_shutdown(void)  {  	/* close pipes */ @@ -170,7 +175,7 @@ lde_shutdown(void)  }  /* imesg */ -static int +int  lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen)  {  	return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); @@ -185,10 +190,10 @@ lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data,  }  /* ARGSUSED */ -static void -lde_dispatch_imsg(int fd, short event, void *bula) +static int +lde_dispatch_imsg(struct thread *thread)  { -	struct imsgev		*iev = bula; +	struct imsgev		*iev = THREAD_ARG(thread);  	struct imsgbuf		*ibuf = &iev->ibuf;  	struct imsg		 imsg;  	struct lde_nbr		*ln; @@ -196,20 +201,14 @@ lde_dispatch_imsg(int fd, short event, void *bula)  	struct lde_addr		 lde_addr;  	struct notify_msg	 nm;  	ssize_t			 n; -	int			 shut = 0, verbose; +	int			 shut = 0; -	if (event & EV_READ) { -		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) -			fatal("imsg_read error"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} -	if (event & EV_WRITE) { -		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) -			fatal("msgbuf_write"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} +	iev->ev_read = NULL; + +	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) +		fatal("imsg_read error"); +	if (n == 0)	/* connection closed */ +		shut = 1;  	for (;;) {  		if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -353,11 +352,6 @@ lde_dispatch_imsg(int fd, short event, void *bula)  			lde_imsg_compose_ldpe(IMSG_CTL_END, 0,  			    imsg.hdr.pid, NULL, 0);  			break; -		case IMSG_CTL_LOG_VERBOSE: -			/* already checked by ldpe */ -			memcpy(&verbose, imsg.data, sizeof(verbose)); -			log_verbose(verbose); -			break;  		default:  			log_debug("%s: unexpected imsg %d", __func__,  			    imsg.hdr.type); @@ -368,15 +362,18 @@ lde_dispatch_imsg(int fd, short event, void *bula)  	if (!shut)  		imsg_event_add(iev);  	else { -		/* this pipe is dead, so remove the event handler */ -		event_del(&iev->ev); -		event_loopexit(NULL); +		/* this pipe is dead, so remove the event handlers and exit */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		lde_shutdown();  	} + +	return (0);  }  /* ARGSUSED */ -static void -lde_dispatch_parent(int fd, short event, void *bula) +static int +lde_dispatch_parent(struct thread *thread)  {  	static struct ldpd_conf	*nconf;  	struct iface		*niface; @@ -387,24 +384,19 @@ lde_dispatch_parent(int fd, short event, void *bula)  	struct l2vpn_pw		*npw;  	struct imsg		 imsg;  	struct kroute		 kr; -	struct imsgev		*iev = bula; +	int			 fd = THREAD_FD(thread); +	struct imsgev		*iev = THREAD_ARG(thread);  	struct imsgbuf		*ibuf = &iev->ibuf;  	ssize_t			 n;  	int			 shut = 0;  	struct fec		 fec; -	if (event & EV_READ) { -		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) -			fatal("imsg_read error"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} -	if (event & EV_WRITE) { -		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) -			fatal("msgbuf_write"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} +	iev->ev_read = NULL; + +	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) +		fatal("imsg_read error"); +	if (n == 0)	/* connection closed */ +		shut = 1;  	for (;;) {  		if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -462,11 +454,11 @@ lde_dispatch_parent(int fd, short event, void *bula)  			if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL)  				fatal(NULL);  			imsg_init(&iev_ldpe->ibuf, fd); -			iev_ldpe->handler = lde_dispatch_imsg; -			iev_ldpe->events = EV_READ; -			event_set(&iev_ldpe->ev, iev_ldpe->ibuf.fd, -			    iev_ldpe->events, iev_ldpe->handler, iev_ldpe); -			event_add(&iev_ldpe->ev, NULL); +			iev_ldpe->handler_read = lde_dispatch_imsg; +			iev_ldpe->ev_read = thread_add_read(master, +			    iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd); +			iev_ldpe->handler_write = ldp_write_handler; +			iev_ldpe->ev_write = NULL;  			break;  		case IMSG_RECONF_CONF:  			if ((nconf = malloc(sizeof(struct ldpd_conf))) == @@ -513,6 +505,7 @@ lde_dispatch_parent(int fd, short event, void *bula)  			LIST_INIT(&nl2vpn->if_list);  			LIST_INIT(&nl2vpn->pw_list); +			LIST_INIT(&nl2vpn->pw_inactive_list);  			LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);  			break; @@ -532,10 +525,26 @@ lde_dispatch_parent(int fd, short event, void *bula)  			npw->l2vpn = nl2vpn;  			LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);  			break; +		case IMSG_RECONF_L2VPN_IPW: +			if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) +				fatal(NULL); +			memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); + +			npw->l2vpn = nl2vpn; +			LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry); +			break;  		case IMSG_RECONF_END:  			merge_config(ldeconf, nconf);  			nconf = NULL;  			break; +		case IMSG_DEBUG_UPDATE: +			if (imsg.hdr.len != IMSG_HEADER_SIZE + +			    sizeof(ldp_debug)) { +				log_warnx("%s: wrong imsg len", __func__); +				break; +			} +			memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug)); +			break;  		default:  			log_debug("%s: unexpected imsg %d", __func__,  			    imsg.hdr.type); @@ -546,10 +555,13 @@ lde_dispatch_parent(int fd, short event, void *bula)  	if (!shut)  		imsg_event_add(iev);  	else { -		/* this pipe is dead, so remove the event handler */ -		event_del(&iev->ev); -		event_loopexit(NULL); +		/* this pipe is dead, so remove the event handlers and exit */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		lde_shutdown();  	} + +	return (0);  }  uint32_t @@ -557,7 +569,10 @@ lde_assign_label(void)  {  	static uint32_t label = MPLS_LABEL_RESERVED_MAX; -	/* XXX some checks needed */ +	/* +	 * TODO: request label to zebra or define a range of labels for ldpd. +	 */ +  	label++;  	return (label);  } diff --git a/ldpd/lde.h b/ldpd/lde.h index b0f7b20439..0fce5565a2 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -21,9 +21,8 @@  #ifndef _LDE_H_  #define _LDE_H_ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> +#include "openbsd-queue.h" +#include "openbsd-tree.h"  enum fec_type {  	FEC_TYPE_IPV4, @@ -121,10 +120,11 @@ struct fec_node {  extern struct ldpd_conf	*ldeconf;  extern struct fec_tree	 ft;  extern struct nbr_tree	 lde_nbrs; -extern struct event	 gc_timer; +extern struct thread	*gc_timer;  /* lde.c */ -void		 lde(int, int); +void		 lde(const char *, const char *); +int		 lde_imsg_compose_parent(int, pid_t, void *, uint16_t);  int		 lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t);  uint32_t	 lde_assign_label(void);  void		 lde_send_change_klabel(struct fec_node *, struct fec_nh *); @@ -173,7 +173,7 @@ void		 lde_check_release(struct map *, struct lde_nbr *);  void		 lde_check_release_wcard(struct map *, struct lde_nbr *);  void		 lde_check_withdraw(struct map *, struct lde_nbr *);  void		 lde_check_withdraw_wcard(struct map *, struct lde_nbr *); -void		 lde_gc_timer(int, short, void *); +int		 lde_gc_timer(struct thread *);  void		 lde_gc_start_timer(void);  void		 lde_gc_stop_timer(void); @@ -185,8 +185,10 @@ void		 l2vpn_init(struct l2vpn *);  void		 l2vpn_exit(struct l2vpn *);  struct l2vpn_if	*l2vpn_if_new(struct l2vpn *, struct kif *);  struct l2vpn_if	*l2vpn_if_find(struct l2vpn *, unsigned int); +struct l2vpn_if	*l2vpn_if_find_name(struct l2vpn *, const char *);  struct l2vpn_pw	*l2vpn_pw_new(struct l2vpn *, struct kif *);  struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int); +struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *);  void		 l2vpn_pw_init(struct l2vpn_pw *);  void		 l2vpn_pw_exit(struct l2vpn_pw *);  void		 l2vpn_pw_reset(struct l2vpn_pw *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index d9c1f544f1..568761bd61 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -17,17 +17,14 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/socket.h> -#include <netmpls/mpls.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> +#include <zebra.h>  #include "ldpd.h"  #include "lde.h"  #include "log.h" +#include "mpls.h" +  static __inline int	 fec_compare(struct fec *, struct fec *);  static int		 lde_nbr_is_nexthop(struct fec_node *,  			    struct lde_nbr *); @@ -40,7 +37,7 @@ static void		 fec_nh_del(struct fec_nh *);  RB_GENERATE(fec_tree, fec, entry, fec_compare)  struct fec_tree		 ft = RB_INITIALIZER(&ft); -struct event		 gc_timer; +struct thread		*gc_timer;  /* FEC tree functions */  void @@ -165,6 +162,7 @@ rt_dump(pid_t pid)  		    LIST_EMPTY(&fn->downstream))  			continue; +		rtctl.first = 1;  		switch (fn->fec.type) {  		case FEC_TYPE_IPV4:  			rtctl.af = AF_INET; @@ -188,6 +186,7 @@ rt_dump(pid_t pid)  			lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid,  			    &rtctl, sizeof(rtctl)); +			rtctl.first = 0;  		}  		if (LIST_EMPTY(&fn->downstream)) {  			rtctl.in_use = 0; @@ -338,9 +337,6 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,  	if (fec_nh_find(fn, af, nexthop, priority) != NULL)  		return; -	log_debug("lde add fec %s nexthop %s", -	    log_fec(&fn->fec), log_addr(af, nexthop)); -  	if (fn->fec.type == FEC_TYPE_PWID)  		fn->data = data; @@ -396,9 +392,6 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop,  		/* route lost */  		return; -	log_debug("lde remove fec %s nexthop %s", -	    log_fec(&fn->fec), log_addr(af, nexthop)); -  	lde_send_delete_klabel(fn, fnh);  	fec_nh_del(fnh);  	if (LIST_EMPTY(&fn->nexthops)) { @@ -738,8 +731,8 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln)  /* gabage collector timer: timer to remove dead entries from the LIB */  /* ARGSUSED */ -void -lde_gc_timer(int fd, short event, void *arg) +int +lde_gc_timer(struct thread *thread)  {  	struct fec	*fec, *safe;  	struct fec_node	*fn; @@ -762,23 +755,20 @@ lde_gc_timer(int fd, short event, void *arg)  		log_debug("%s: %u entries removed", __func__, count);  	lde_gc_start_timer(); + +	return (0);  }  void  lde_gc_start_timer(void)  { -	struct timeval	 tv; - -	timerclear(&tv); -	tv.tv_sec = LDE_GC_INTERVAL; -	if (evtimer_add(&gc_timer, &tv) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(gc_timer); +	gc_timer = thread_add_timer(master, lde_gc_timer, NULL, +	    LDE_GC_INTERVAL);  }  void  lde_gc_stop_timer(void)  { -	if (evtimer_pending(&gc_timer, NULL) && -	    evtimer_del(&gc_timer) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(gc_timer);  } diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 77034b30a5..c421cddc38 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -23,8 +23,6 @@  #ifndef _LDP_H_  #define _LDP_H_ -#include <sys/types.h> -  /* misc */  #define LDP_VERSION		1  #define LDP_PORT		646 @@ -106,7 +104,7 @@ struct ldp_hdr {  	uint16_t	length;  	uint32_t	lsr_id;  	uint16_t	lspace_id; -} __packed; +} __attribute__ ((packed));  #define	LDP_HDR_SIZE		10	/* actual size of the LDP header */  #define	LDP_HDR_PDU_LEN		6	/* minimum "PDU Length" */ @@ -125,7 +123,7 @@ struct ldp_msg {  	uint32_t	id;  	/* Mandatory Parameters */  	/* Optional Parameters */ -} __packed; +} __attribute__ ((packed));  #define LDP_MSG_SIZE		8	/* minimum size of LDP message */  #define LDP_MSG_LEN		4	/* minimum "Message Length" */ @@ -212,7 +210,7 @@ struct sess_prms_tlv {  	uint16_t	max_pdu_len;  	uint32_t	lsr_id;  	uint16_t	lspace_id; -} __packed; +} __attribute__ ((packed));  #define SESS_PRMS_SIZE		18  #define SESS_PRMS_LEN		14 @@ -223,7 +221,7 @@ struct status_tlv {  	uint32_t	status_code;  	uint32_t	msg_id;  	uint16_t	msg_type; -} __packed; +} __attribute__ ((packed));  #define STATUS_SIZE		14  #define STATUS_TLV_LEN		10 @@ -237,7 +235,7 @@ struct address_list_tlv {  	uint16_t	length;  	uint16_t	family;  	/* address entries */ -} __packed; +} __attribute__ ((packed));  #define ADDR_LIST_SIZE		6 diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c new file mode 100644 index 0000000000..15dd06a0f3 --- /dev/null +++ b/ldpd/ldp_debug.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "command.h" +#include "vty.h" + +#include "ldpd.h" +#include "ldp_debug.h" +#include "ldp_vty.h" + +struct ldp_debug conf_ldp_debug; +struct ldp_debug ldp_debug; + +/* Debug node. */ +struct cmd_node ldp_debug_node = +{ +	DEBUG_NODE, +	"", +	1 +}; + +int +ldp_vty_debug(struct vty *vty, struct vty_arg *args[]) +{ + 	const char		*type_str, *dir_str; +	int			 disable, all; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	type_str = vty_get_arg_value(args, "type"); + +	if (strcmp(type_str, "discovery") == 0) { +		dir_str = vty_get_arg_value(args, "dir"); +		if (dir_str == NULL) +			return (CMD_WARNING); + +		if (dir_str[0] == 'r') { +			if (disable) +				DEBUG_OFF(hello, HELLO_RECV); +			else +				DEBUG_ON(hello, HELLO_RECV); +		} else { +			if (disable) +				DEBUG_OFF(hello, HELLO_SEND); +			else +				DEBUG_ON(hello, HELLO_SEND); +		} +	} else if (strcmp(type_str, "errors") == 0) { +		if (disable) +			DEBUG_OFF(errors, ERRORS); +		else +			DEBUG_ON(errors, ERRORS); +	} else if (strcmp(type_str, "event") == 0) { +		if (disable) +			DEBUG_OFF(event, EVENT); +		else +			DEBUG_ON(event, EVENT); +	} else 	if (strcmp(type_str, "messages") == 0) { +		all = (vty_get_arg_value(args, "all")) ? 1 : 0; +		dir_str = vty_get_arg_value(args, "dir"); +		if (dir_str == NULL) +			return (CMD_WARNING); + +		if (dir_str[0] == 'r') { +			if (disable) { +				DEBUG_OFF(msg, MSG_RECV); +				DEBUG_OFF(msg, MSG_RECV_ALL); +			} else { +				DEBUG_ON(msg, MSG_RECV); +				if (all) +					DEBUG_ON(msg, MSG_RECV_ALL); +			} +		} else { +			if (disable) { +				DEBUG_OFF(msg, MSG_SEND); +				DEBUG_OFF(msg, MSG_SEND_ALL); +			} else { +				DEBUG_ON(msg, MSG_SEND); +				if (all) +					DEBUG_ON(msg, MSG_SEND_ALL); +			} +		} +	} else 	if (strcmp(type_str, "zebra") == 0) { +		if (disable) +			DEBUG_OFF(zebra, ZEBRA); +		else +			DEBUG_ON(zebra, ZEBRA); +	} + +	main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug, +	    sizeof(ldp_debug)); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_show_debugging(struct vty *vty, struct vty_arg *args[]) +{ +	vty_out(vty, "LDP debugging status:%s", VTY_NEWLINE); + +	if (LDP_DEBUG(hello, HELLO_RECV)) +		vty_out(vty, "  LDP discovery debugging is on (inbound)%s", +		    VTY_NEWLINE); +	if (LDP_DEBUG(hello, HELLO_SEND)) +		vty_out(vty, "  LDP discovery debugging is on (outbound)%s", +		    VTY_NEWLINE); +	if (LDP_DEBUG(errors, ERRORS)) +		vty_out(vty, "  LDP errors debugging is on%s", VTY_NEWLINE); +	if (LDP_DEBUG(event, EVENT)) +		vty_out(vty, "  LDP events debugging is on%s", VTY_NEWLINE); +	if (LDP_DEBUG(msg, MSG_RECV_ALL)) +		vty_out(vty, "  LDP detailed messages debugging is on " +		    "(inbound)%s", VTY_NEWLINE); +	else if (LDP_DEBUG(msg, MSG_RECV)) +		vty_out(vty, "  LDP messages debugging is on (inbound)%s", +		    VTY_NEWLINE); +	if (LDP_DEBUG(msg, MSG_SEND_ALL)) +		vty_out(vty, "  LDP detailed messages debugging is on " +		    "(outbound)%s", VTY_NEWLINE); +	else if (LDP_DEBUG(msg, MSG_SEND)) +		vty_out(vty, "  LDP messages debugging is on (outbound)%s", +		    VTY_NEWLINE); +	if (LDP_DEBUG(zebra, ZEBRA)) +		vty_out(vty, "  LDP zebra debugging is on%s", VTY_NEWLINE); +	vty_out (vty, "%s", VTY_NEWLINE); + +	return (CMD_SUCCESS); +} + +int +ldp_debug_config_write(struct vty *vty) +{ +	int write = 0; + +	if (CONF_LDP_DEBUG(hello, HELLO_RECV)) { +		vty_out(vty, "debug mpls ldp discovery hello recv%s", +		    VTY_NEWLINE); +		write = 1; +	} + +	if (CONF_LDP_DEBUG(hello, HELLO_SEND)) { +		vty_out(vty, "debug mpls ldp discovery hello sent%s", +		    VTY_NEWLINE); +		write = 1; +	} + +	if (CONF_LDP_DEBUG(errors, ERRORS)) { +		vty_out(vty, "debug mpls ldp errors%s", VTY_NEWLINE); +		write = 1; +	} + +	if (CONF_LDP_DEBUG(event, EVENT)) { +		vty_out(vty, "debug mpls ldp event%s", VTY_NEWLINE); +		write = 1; +	} + +	if (CONF_LDP_DEBUG(msg, MSG_RECV_ALL)) { +		vty_out(vty, "debug mpls ldp messages recv all%s", VTY_NEWLINE); +		write = 1; +	} else if (CONF_LDP_DEBUG(msg, MSG_RECV)) { +		vty_out(vty, "debug mpls ldp messages recv%s", VTY_NEWLINE); +		write = 1; +	} + +	if (CONF_LDP_DEBUG(msg, MSG_SEND_ALL)) { +		vty_out(vty, "debug mpls ldp messages sent all%s", VTY_NEWLINE); +		write = 1; +	} else if (CONF_LDP_DEBUG(msg, MSG_SEND)) { +		vty_out(vty, "debug mpls ldp messages sent%s", VTY_NEWLINE); +		write = 1; +	} + +	if (CONF_LDP_DEBUG(zebra, ZEBRA)) { +		vty_out(vty, "debug mpls ldp zebra%s", VTY_NEWLINE); +		write = 1; +	} + +	return (write); +} diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h new file mode 100644 index 0000000000..aa0cd47e7b --- /dev/null +++ b/ldpd/ldp_debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _LDP_DEBUG_H_ +#define	_LDP_DEBUG_H_ + +struct ldp_debug { +	int	 hello; +#define LDP_DEBUG_HELLO_RECV	0x01 +#define LDP_DEBUG_HELLO_SEND	0x02 + +	int	 errors; +#define LDP_DEBUG_ERRORS	0x01 + +	int	 event; +#define LDP_DEBUG_EVENT		0x01 + +	int	 msg; +#define LDP_DEBUG_MSG_RECV	0x01 +#define LDP_DEBUG_MSG_RECV_ALL	0x02 +#define LDP_DEBUG_MSG_SEND	0x04 +#define LDP_DEBUG_MSG_SEND_ALL	0x08 + +	int	 zebra; +#define LDP_DEBUG_ZEBRA		0x01 +}; +extern struct ldp_debug	 conf_ldp_debug; +extern struct ldp_debug	 ldp_debug; + +#define CONF_DEBUG_ON(a, b)	(conf_ldp_debug.a |= (LDP_DEBUG_ ## b)) +#define CONF_DEBUG_OFF(a, b)	(conf_ldp_debug.a &= ~(LDP_DEBUG_ ## b)) + +#define TERM_DEBUG_ON(a, b)	(ldp_debug.a |= (LDP_DEBUG_ ## b)) +#define TERM_DEBUG_OFF(a, b)	(ldp_debug.a &= ~(LDP_DEBUG_ ## b)) + +#define DEBUG_ON(a, b)			\ +    do {				\ +	if (vty->node == CONFIG_NODE) { \ +		CONF_DEBUG_ON(a, b);	\ +		TERM_DEBUG_ON(a, b);	\ +	} else				\ +		TERM_DEBUG_ON(a, b);	\ +    } while (0) +#define DEBUG_OFF(a, b)			\ +    do {				\ +	CONF_DEBUG_OFF(a, b);		\ +	TERM_DEBUG_OFF(a, b);		\ +    } while (0) + +#define LDP_DEBUG(a, b)		(ldp_debug.a & LDP_DEBUG_ ## b) +#define CONF_LDP_DEBUG(a, b)    (conf_ldp_debug.a & LDP_DEBUG_ ## b) + +#define		 debug_hello_recv(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(hello, HELLO_RECV))				\ +		log_debug("discovery[recv]: " emsg, __VA_ARGS__);	\ +} while (0) + +#define		 debug_hello_send(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(hello, HELLO_SEND))				\ +		log_debug("discovery[send]: " emsg, __VA_ARGS__);	\ +} while (0) + +#define		 debug_err(emsg, ...)					\ +do {									\ +	if (LDP_DEBUG(errors, ERRORS))					\ +		log_debug("error: " emsg, __VA_ARGS__);			\ +} while (0) + +#define		 debug_evt(emsg, ...)					\ +do {									\ +	if (LDP_DEBUG(event, EVENT))					\ +		log_debug("event: " emsg, __VA_ARGS__);			\ +} while (0) + +#define		 debug_msg_recv(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(msg, MSG_RECV))					\ +		log_debug("msg[in]: " emsg, __VA_ARGS__);		\ +} while (0) + +#define		 debug_msg_send(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(msg, MSG_SEND))					\ +		log_debug("msg[out]: " emsg, __VA_ARGS__);		\ +} while (0) + +#define		 debug_kalive_recv(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(msg, MSG_RECV_ALL))				\ +		log_debug("kalive[in]: " emsg, __VA_ARGS__);		\ +} while (0) + +#define		 debug_kalive_send(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(msg, MSG_SEND_ALL))				\ +		log_debug("kalive[out]: " emsg, __VA_ARGS__);		\ +} while (0) + +#define		 debug_zebra_in(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(zebra, ZEBRA))					\ +		log_debug("zebra[in]: " emsg, __VA_ARGS__);		\ +} while (0) + +#define		 debug_zebra_out(emsg, ...)				\ +do {									\ +	if (LDP_DEBUG(zebra, ZEBRA))					\ +		log_debug("zebra[out]: " emsg, __VA_ARGS__);		\ +} while (0) + +#endif /* _LDP_DEBUG_H_ */ diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h new file mode 100644 index 0000000000..735554badf --- /dev/null +++ b/ldpd/ldp_vty.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _LDP_VTY_H_ +#define _LDP_VTY_H_ + +#include "vty.h" + +extern struct cmd_node ldp_node; +extern struct cmd_node ldp_ipv4_node; +extern struct cmd_node ldp_ipv6_node; +extern struct cmd_node ldp_ipv4_iface_node; +extern struct cmd_node ldp_ipv6_iface_node; +extern struct cmd_node ldp_l2vpn_node; +extern struct cmd_node ldp_pseudowire_node; +extern struct cmd_node ldp_debug_node; + +union ldpd_addr; +int	 ldp_get_address(const char *, int *, union ldpd_addr *); +int	 ldp_config_write(struct vty *); +int	 ldp_l2vpn_config_write(struct vty *); +int	 ldp_debug_config_write(struct vty *); +int	 ldp_vty_mpls_ldp (struct vty *, struct vty_arg *[]); +int	 ldp_vty_address_family (struct vty *, struct vty_arg *[]); +int	 ldp_vty_disc_holdtime(struct vty *, struct vty_arg *[]); +int	 ldp_vty_disc_interval(struct vty *, struct vty_arg *[]); +int	 ldp_vty_targeted_hello_accept(struct vty *, struct vty_arg *[]); +int	 ldp_vty_session_holdtime(struct vty *, struct vty_arg *[]); +int	 ldp_vty_interface(struct vty *, struct vty_arg *[]); +int	 ldp_vty_trans_addr(struct vty *, struct vty_arg *[]); +int	 ldp_vty_neighbor_targeted(struct vty *, struct vty_arg *[]); +int	 ldp_vty_explicit_null(struct vty *, struct vty_arg *[]); +int	 ldp_vty_ttl_security(struct vty *, struct vty_arg *[]); +int	 ldp_vty_router_id(struct vty *, struct vty_arg *[]); +int	 ldp_vty_ds_cisco_interop(struct vty *, struct vty_arg *[]); +int	 ldp_vty_trans_pref_ipv4(struct vty *, struct vty_arg *[]); +int	 ldp_vty_neighbor_password(struct vty *, struct vty_arg *[]); +int	 ldp_vty_neighbor_ttl_security(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_bridge(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_mtu(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pwtype(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_interface(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pseudowire(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pw_cword(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pw_nbr_addr(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pw_nbr_id(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pw_pwid(struct vty *, struct vty_arg *[]); +int	 ldp_vty_l2vpn_pw_pwstatus(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_binding(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_discovery(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_interface(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_neighbor(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_atom_binding(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_atom_vc(struct vty *, struct vty_arg *[]); +int	 ldp_vty_clear_nbr(struct vty *, struct vty_arg *[]); +int	 ldp_vty_debug(struct vty *, struct vty_arg *[]); +int	 ldp_vty_show_debugging(struct vty *, struct vty_arg *[]); + +void	 ldp_vty_init(void); +void	 ldp_vty_if_init(void); + +#endif	/* _LDP_VTY_H_ */ diff --git a/ldpd/ldp_vty.xml b/ldpd/ldp_vty.xml new file mode 100644 index 0000000000..8742f9c1be --- /dev/null +++ b/ldpd/ldp_vty.xml @@ -0,0 +1,379 @@ +<?xml version="1.0"?> +<file init="ldp_vty_init" cmdprefix="ldp" header="ldp_vty.h"> +  <!-- address-family --> +  <options name="address-family"> +    <option name="ipv4" help="IPv4 Address Family"/> +    <option name="ipv6" help="IPv6 Address Family"/> +  </options> + +  <!-- ipv4/ipv6 address --> +  <options name="addr"> +    <option input="ipv4" help="IPv4 address"/> +    <option input="ipv6" help="IPv6 address"/> +  </options> + +  <!-- pseudowire control-word options --> +  <options name="cword"> +    <option name="exclude" help="Exclude control-word in pseudowire packets"/> +    <option name="include" help="Include control-word in pseudowire packets"/> +  </options> + +  <!-- pseudowire types --> +  <options name="pwtype"> +    <option name="ethernet" help="Ethernet (type 5)"/> +    <option name="ethernet-tagged" help="Ethernet-tagged (type 4)"/> +  </options> + +  <!-- packet direction --> +  <options name="dir"> +    <option name="recv" help="Received messages"/> +    <option name="sent" help="Sent messages"/> +  </options> + +  <!-- shared subtrees --> +  <subtree name="discovery_link"> +    <option name="discovery" help="Configure discovery parameters"> +      <option name="hello" arg="hello_type" help="LDP Link Hellos"> +        <option name="holdtime" help="Hello holdtime"> +          <option input="disc_time" arg="seconds" help="Time (seconds) - 65535 implies infinite" function="ldp_vty_disc_holdtime"/> +        </option> +        <option name="interval" help="Hello interval"> +          <option input="disc_time" arg="seconds" help="Time (seconds)" function="ldp_vty_disc_interval"/> +        </option> +      </option> +    </option> +  </subtree> + +  <subtree name="discovery_targeted"> +    <option name="discovery" help="Configure discovery parameters"> +      <option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos"> +        <option name="holdtime" help="Targeted hello holdtime"> +          <option input="disc_time" arg="seconds" help="Time (seconds) - 65535 implies infinite" function="ldp_vty_disc_holdtime"/> +        </option> +        <option name="interval" help="Targeted hello interval"> +          <option input="disc_time" arg="seconds" help="Time (seconds)" function="ldp_vty_disc_interval"/> +        </option> +      </option> +    </option> +  </subtree> + +  <subtree name="session_holdtime"> +    <option name="session" help="Configure session parameters"> +      <option name="holdtime" help="Configure session holdtime"> +        <option input="session_time" arg="seconds" help="Time (seconds)" function="ldp_vty_session_holdtime"/> +      </option> +    </option> +  </subtree> + +  <subtree name="af_common"> +    <include subtree="discovery_link"/> +    <include subtree="discovery_targeted"/> +    <option name="discovery" help="Configure discovery parameters"> +      <option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos"> +        <option name="accept" help="Accept and respond to targeted hellos" function="ldp_vty_targeted_hello_accept"/> +      </option> +    </option> +    <option name="label" help="Configure label control and policies"> +      <option name="local" help="Configure local label control and policies"> +        <option name="advertise" help="Configure outbound label advertisement control"> +          <option name="explicit-null" help="Configure explicit-null advertisement" function="ldp_vty_explicit_null"/> +        </option> +      </option> +    </option> +    <option name="ttl-security" help="LDP ttl security check"> +      <option name="disable" help="Disable ttl security" function="ldp_vty_ttl_security"/> +    </option> +    <include subtree="session_holdtime"/> +    <option name="interface" help="Enable LDP on an interface and enter interface submode"> +      <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_interface"/> +    </option> +  </subtree> + +  <!-- global --> +  <subtree name="__global"> +    <option name="mpls" help="Global MPLS configuration subcommands"> +      <option name="ldp" help="Label Distribution Protocol" function="ldp_vty_mpls_ldp"/> +    </option> +    <option name="l2vpn" help="Configure l2vpn commands"> +      <option input="word" arg="name" help="L2VPN name"> +        <option name="type" help="L2VPN type"> +          <option name="vpls" help="Virtual Private LAN Service" function="ldp_vty_l2vpn"/> +        </option> +      </option> +    </option> +  </subtree> +  <tree name="global"> +    <include subtree="__global"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +        <include subtree="__global"/> +    </option> +  </tree> + +  <!-- ldp node --> +  <subtree name="__ldp_node"> +    <option name="address-family" help="Configure Address Family and its parameters"> +      <option name="ipv4" arg="address-family" help="IPv4" function="ldp_vty_address_family"/> +      <option name="ipv6" arg="address-family" help="IPv6" function="ldp_vty_address_family"/> +    </option> +    <include subtree="discovery_link"/> +    <include subtree="discovery_targeted"/> +    <option name="dual-stack" help="Configure dual stack parameters"> +      <option name="transport-connection" help="Configure TCP transport parameters"> +        <option name="prefer" help="Configure prefered address family for TCP transport connection with neighbor"> +          <option name="ipv4" help="IPv4" function="ldp_vty_trans_pref_ipv4"/> +        </option> +      </option> +      <option name="cisco-interop" help="Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV" function="ldp_vty_ds_cisco_interop"/> +    </option> +    <option name="neighbor" help="Configure neighbor parameters"> +      <option input="ipv4" arg="lsr_id" help="LDP Id of neighbor"> +        <option name="password" help="Configure password for MD5 authentication"> +          <option input="word" arg="password" help="The password" function="ldp_vty_neighbor_password"/> +        </option> +        <include subtree="session_holdtime"/> +        <option name="ttl-security" help="LDP ttl security check"> +          <option name="disable" help="Disable ttl security" function="ldp_vty_neighbor_ttl_security"/> +          <option name="hops" help="IP hops"> +            <option input="hops" arg="hops" help="maximum number of hops" function="ldp_vty_neighbor_ttl_security"/> +          </option> +        </option> +      </option> +    </option> +    <option name="router-id" help="Configure router Id"> +      <option input="ipv4" arg="addr" help="LSR Id (in form of an IPv4 address)" function="ldp_vty_router_id"/> +    </option> +  </subtree> +  <tree name="ldp_node"> +    <include subtree="__ldp_node"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +        <include subtree="__ldp_node"/> +    </option> +  </tree> + +  <!-- address-family ipv4 --> +  <subtree name="__ldp_ipv4_node"> +    <include subtree="af_common"/> +    <option name="discovery" help="Configure discovery parameters"> +      <option name="transport-address" help="Specify transport address for TCP connection"> +        <option input="ipv4" arg="addr" help="IP address to be used as transport address" function="ldp_vty_trans_addr"/> +      </option> +     </option> +     <option name="neighbor" help="Configure neighbor parameters"> +       <option input="ipv4" arg="addr" help="IP address of neighbor"> +         <option name="targeted" help="Establish targeted session" function="ldp_vty_neighbor_targeted"/> +       </option> +     </option> +  </subtree> +  <tree name="ldp_ipv4_node"> +    <include subtree="__ldp_ipv4_node"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +      <include subtree="__ldp_ipv4_node"/> +    </option> +  </tree> + +  <!-- address-family ipv6 --> +  <subtree name="__ldp_ipv6_node"> +    <include subtree="af_common"/> +    <option name="discovery" help="Configure discovery parameters"> +      <option name="transport-address" help="Specify transport address for TCP connection"> +        <option input="ipv6" arg="addr" help="IPv6 address to be used as transport address" function="ldp_vty_trans_addr"/> +      </option> +    </option> +     <option name="neighbor" help="Configure neighbor parameters"> +       <option input="ipv6" arg="addr" help="IPv6 address of neighbor"> +         <option name="targeted" help="Establish targeted session" function="ldp_vty_neighbor_targeted"/> +       </option> +     </option> +  </subtree> +  <tree name="ldp_ipv6_node"> +    <include subtree="__ldp_ipv6_node"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +      <include subtree="__ldp_ipv6_node"/> +    </option> +  </tree> + +  <!-- ldp ipv4 interface node --> +  <subtree name="__ldp_ipv4_iface_node"> +    <include subtree="discovery_link"/> +  </subtree> +  <tree name="ldp_ipv4_iface_node"> +    <include subtree="__ldp_ipv4_iface_node"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +      <include subtree="__ldp_ipv4_iface_node"/> +    </option> +  </tree> + +  <!-- ldp ipv6 interface node --> +  <subtree name="__ldp_ipv6_iface_node"> +    <include subtree="discovery_link"/> +  </subtree> +  <tree name="ldp_ipv6_iface_node"> +    <include subtree="__ldp_ipv6_iface_node"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +      <include subtree="__ldp_ipv6_iface_node"/> +    </option> +  </tree> + +  <!-- l2vpn --> +  <subtree name="__ldp_l2vpn"> +    <option name="bridge" help="Bridge interface"> +      <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_bridge"/> +    </option> +    <option name="mtu" help="set Maximum Transmission Unit"> +      <option input="mtu" arg="mtu" help="Maximum Transmission Unit value" function="ldp_vty_l2vpn_mtu"/> +    </option> +    <option name="member" help="L2VPN member configuration"> +      <option name="interface" help="Local interface"> +        <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_interface"/> +      </option> +      <option name="pseudowire" help="Pseudowire interface"> +        <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_pseudowire"/> +      </option> +    </option> +    <option name="vc" help="Virtual Circuit options"> +      <option name="type" help="Virtual Circuit type to use"> +        <select options="pwtype" arg="type" function="ldp_vty_l2vpn_pwtype"/> +      </option> +    </option> +  </subtree> +  <tree name="ldp_l2vpn"> +    <include subtree="__ldp_l2vpn"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +      <include subtree="__ldp_l2vpn"/> +    </option> +  </tree> + +  <!-- l2vpn pseudowire --> +  <subtree name="__ldp_pseudowire"> +    <option name="control-word" help="Control-word options"> +      <select options="cword" arg="preference" function="ldp_vty_l2vpn_pw_cword"/> +    </option> +    <option name="neighbor" help="Remote endpoint configuration"> +      <option name="address" help="Specify the IPv4 or IPv6 address of the remote endpoint"> +        <select options="addr" arg="addr" function="ldp_vty_l2vpn_pw_nbr_addr"/> +      </option> +      <option name="lsr-id" help="Specify the LSR-ID of the remote endpoint"> +        <option input="ipv4" arg="lsr-id" help="IPv4 address" function="ldp_vty_l2vpn_pw_nbr_id"/> +      </option> +    </option> +    <option name="pw-id" help="Set the Virtual Circuit ID"> +      <option input="pwid" arg="pwid" help="Virtual Circuit ID value" function="ldp_vty_l2vpn_pw_pwid"/> +    </option> +    <option name="pw-status" help="Configure PW status"> +      <option name="disable" help="Disable PW status" function="ldp_vty_l2vpn_pw_pwstatus"/> +    </option> +  </subtree> +  <tree name="ldp_pseudowire"> +    <include subtree="__ldp_pseudowire"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +      <include subtree="__ldp_pseudowire"/> +    </option> +  </tree> + +  <!-- exec mode commands --> +  <subtree name="ldp_show_af"> +    <option name="binding" help="Label Information Base (LIB) information" function="ldp_vty_show_binding"/> +    <option name="discovery" help="Discovery Hello Information" function="ldp_vty_show_discovery"/> +    <option name="interface" help="interface information" function="ldp_vty_show_interface"/> +  </subtree> +  <tree name="ldp_exec"> +    <option name="show" help="Show running system information"> +      <option name="mpls" help="MPLS information"> +        <option name="ldp" help="Label Distribution Protocol"> +          <option name="neighbor" help="Neighbor information" function="ldp_vty_show_neighbor"/> +          <include subtree="ldp_show_af"/> +          <select options="address-family" arg="address-family"> +            <include subtree="ldp_show_af"/> +          </select> +        </option> +      </option> +      <option name="l2vpn" help="Show information about Layer2 VPN"> +        <option name="atom" help="Show Any Transport over MPLS information"> +          <option name="binding" help="Show AToM label binding information" function="ldp_vty_show_atom_binding"/> +          <option name="vc" help="Show AToM virtual circuit information" function="ldp_vty_show_atom_vc"/> +        </option> +      </option> +      <option name="debugging" help="Debugging functions"> +        <option name="mpls" help="MPLS information"> +          <option name="ldp" help="Label Distribution Protocol" function="ldp_vty_show_debugging"/> +        </option> +      </option> +    </option> +    <option name="clear" help="Reset functions"> +      <option name="mpls" help="Reset MPLS statistical information"> +        <option name="ldp" help="Clear LDP state"> +          <option name="neighbor" help="Clear LDP neighbor sessions" function="ldp_vty_clear_nbr"> +            <select options="addr" arg="addr" function="ldp_vty_clear_nbr"/> +          </option> +        </option> +      </option> +    </option> +  </tree> + +  <!-- debug commands --> +  <subtree name="__ldp_debug"> +    <option name="debug" help="Debugging functions"> +      <option name="mpls" help="MPLS information"> +        <option name="ldp" help="Label Distribution Protocol"> +          <option name="discovery" arg="type" help="Discovery messages"> +            <option name="hello" help="Discovery hello message"> +              <select options="dir" arg="dir" function="ldp_vty_debug"/> +            </option> +          </option> +          <option name="errors" arg="type" help="Errors" function="ldp_vty_debug"/> +          <option name="event" arg="type" help="LDP event information" function="ldp_vty_debug"/> +          <option name="messages" arg="type" help="Messages"> +            <option name="recv" arg="dir" help="Received messages, excluding periodic Keep Alives" function="ldp_vty_debug"> +              <option name="all" arg="all" help="Received messages, including periodic Keep Alives" function="ldp_vty_debug"/> +            </option> +            <option name="sent" arg="dir" help="Sent messages, excluding periodic Keep Alives" function="ldp_vty_debug"> +              <option name="all" arg="all" help="Sent messages, including periodic Keep Alives" function="ldp_vty_debug"/> +            </option> +          </option> +          <option name="zebra" arg="type" help="LDP zebra information" function="ldp_vty_debug"/> +        </option> +      </option> +    </option> +  </subtree> +  <tree name="ldp_debug"> +    <include subtree="__ldp_debug"/> +    <option name="no" arg="no" help="Negate a command or set its defaults"> +        <include subtree="__ldp_debug"/> +    </option> +  </tree> + +  <!-- nodes --> +  <node name="CONFIG"> +    <include tree="global"/> +    <include tree="ldp_debug"/> +  </node> +  <node install="1" install_default="1" config_write="ldp_config_write" name="LDP"> +    <include tree="ldp_node"/> +  </node> +  <node install="1" install_default="1" config_write="NULL" name="LDP_IPV4"> +    <include tree="ldp_ipv4_node"/> +  </node> +  <node install="1" install_default="1" config_write="NULL" name="LDP_IPV6"> +    <include tree="ldp_ipv6_node"/> +  </node> +  <node install="1" install_default="1" config_write="NULL" name="LDP_IPV4_IFACE"> +    <include tree="ldp_ipv4_iface_node"/> +  </node> +  <node install="1" install_default="1" config_write="NULL" name="LDP_IPV6_IFACE"> +    <include tree="ldp_ipv6_iface_node"/> +  </node> +  <node install="1" install_default="1" config_write="ldp_l2vpn_config_write" name="LDP_L2VPN"> +    <include tree="ldp_l2vpn"/> +  </node> +  <node install="1" install_default="1" config_write="NULL" name="LDP_PSEUDOWIRE"> +    <include tree="ldp_pseudowire"/> +  </node> +  <node install="1" config_write="ldp_debug_config_write" name="LDP_DEBUG"/> +  <node name="ENABLE"> +    <include tree="ldp_exec"/> +    <include tree="ldp_debug"/> +  </node> +  <node name="VIEW"> +    <include tree="ldp_exec"/> +  </node> +</file> diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c new file mode 100644 index 0000000000..7160835726 --- /dev/null +++ b/ldpd/ldp_vty_cmds.c @@ -0,0 +1,1738 @@ +/* Auto-generated from ldp_vty.xml. */ +/* Do not edit! */ + +#include <zebra.h> + +#include "command.h" +#include "vty.h" +#include "ldp_vty.h" + +DEFUN (ldp_mpls_ldp, +       ldp_mpls_ldp_cmd, +       "mpls ldp", +       "Global MPLS configuration subcommands\n" +       "Label Distribution Protocol\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_mpls_ldp (vty, args); +} + +DEFUN (ldp_l2vpn_word_type_vpls, +       ldp_l2vpn_word_type_vpls_cmd, +       "l2vpn WORD type vpls", +       "Configure l2vpn commands\n" +       "L2VPN name\n" +       "L2VPN type\n" +       "Virtual Private LAN Service\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "name", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn (vty, args); +} + +DEFUN (ldp_no_mpls_ldp, +       ldp_no_mpls_ldp_cmd, +       "no mpls ldp", +       "Negate a command or set its defaults\n" +       "Global MPLS configuration subcommands\n" +       "Label Distribution Protocol\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      NULL +    }; +  return ldp_vty_mpls_ldp (vty, args); +} + +DEFUN (ldp_no_l2vpn_word_type_vpls, +       ldp_no_l2vpn_word_type_vpls_cmd, +       "no l2vpn WORD type vpls", +       "Negate a command or set its defaults\n" +       "Configure l2vpn commands\n" +       "L2VPN name\n" +       "L2VPN type\n" +       "Virtual Private LAN Service\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "name", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn (vty, args); +} + +DEFUN (ldp_address_family_ipv4, +       ldp_address_family_ipv4_cmd, +       "address-family ipv4", +       "Configure Address Family and its parameters\n" +       "IPv4\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "address-family", .value = "ipv4" }, +      NULL +    }; +  return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_address_family_ipv6, +       ldp_address_family_ipv6_cmd, +       "address-family ipv6", +       "Configure Address Family and its parameters\n" +       "IPv6\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "address-family", .value = "ipv6" }, +      NULL +    }; +  return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_discovery_hello_holdtime_disc_time, +       ldp_discovery_hello_holdtime_disc_time_cmd, +       "discovery hello holdtime <1-65535>", +       "Configure discovery parameters\n" +       "LDP Link Hellos\n" +       "Hello holdtime\n" +       "Time (seconds) - 65535 implies infinite\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "hello_type", .value = "hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_discovery_hello_interval_disc_time, +       ldp_discovery_hello_interval_disc_time_cmd, +       "discovery hello interval <1-65535>", +       "Configure discovery parameters\n" +       "LDP Link Hellos\n" +       "Hello interval\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "hello_type", .value = "hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_discovery_targeted_hello_holdtime_disc_time, +       ldp_discovery_targeted_hello_holdtime_disc_time_cmd, +       "discovery targeted-hello holdtime <1-65535>", +       "Configure discovery parameters\n" +       "LDP Targeted Hellos\n" +       "Targeted hello holdtime\n" +       "Time (seconds) - 65535 implies infinite\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_discovery_targeted_hello_interval_disc_time, +       ldp_discovery_targeted_hello_interval_disc_time_cmd, +       "discovery targeted-hello interval <1-65535>", +       "Configure discovery parameters\n" +       "LDP Targeted Hellos\n" +       "Targeted hello interval\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_dual_stack_transport_connection_prefer_ipv4, +       ldp_dual_stack_transport_connection_prefer_ipv4_cmd, +       "dual-stack transport-connection prefer ipv4", +       "Configure dual stack parameters\n" +       "Configure TCP transport parameters\n" +       "Configure prefered address family for TCP transport connection with neighbor\n" +       "IPv4\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_trans_pref_ipv4 (vty, args); +} + +DEFUN (ldp_dual_stack_cisco_interop, +       ldp_dual_stack_cisco_interop_cmd, +       "dual-stack cisco-interop", +       "Configure dual stack parameters\n" +       "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_ds_cisco_interop (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_password_word, +       ldp_neighbor_ipv4_password_word_cmd, +       "neighbor A.B.C.D password WORD", +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "Configure password for MD5 authentication\n" +       "The password\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      &(struct vty_arg) { .name = "password", .value = argv[1] }, +      NULL +    }; +  return ldp_vty_neighbor_password (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_session_holdtime_session_time, +       ldp_neighbor_ipv4_session_holdtime_session_time_cmd, +       "neighbor A.B.C.D session holdtime <15-65535>", +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "Configure session parameters\n" +       "Configure session holdtime\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      &(struct vty_arg) { .name = "seconds", .value = argv[1] }, +      NULL +    }; +  return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_ttl_security_disable, +       ldp_neighbor_ipv4_ttl_security_disable_cmd, +       "neighbor A.B.C.D ttl-security disable", +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "LDP ttl security check\n" +       "Disable ttl security\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_ttl_security_hops_hops, +       ldp_neighbor_ipv4_ttl_security_hops_hops_cmd, +       "neighbor A.B.C.D ttl-security hops <1-254>", +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "LDP ttl security check\n" +       "IP hops\n" +       "maximum number of hops\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      &(struct vty_arg) { .name = "hops", .value = argv[1] }, +      NULL +    }; +  return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_router_id_ipv4, +       ldp_router_id_ipv4_cmd, +       "router-id A.B.C.D", +       "Configure router Id\n" +       "LSR Id (in form of an IPv4 address)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_router_id (vty, args); +} + +DEFUN (ldp_no_address_family_ipv4, +       ldp_no_address_family_ipv4_cmd, +       "no address-family ipv4", +       "Negate a command or set its defaults\n" +       "Configure Address Family and its parameters\n" +       "IPv4\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "address-family", .value = "ipv4" }, +      NULL +    }; +  return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_no_address_family_ipv6, +       ldp_no_address_family_ipv6_cmd, +       "no address-family ipv6", +       "Negate a command or set its defaults\n" +       "Configure Address Family and its parameters\n" +       "IPv6\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "address-family", .value = "ipv6" }, +      NULL +    }; +  return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_no_discovery_hello_holdtime_disc_time, +       ldp_no_discovery_hello_holdtime_disc_time_cmd, +       "no discovery hello holdtime <1-65535>", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "LDP Link Hellos\n" +       "Hello holdtime\n" +       "Time (seconds) - 65535 implies infinite\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "hello_type", .value = "hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_no_discovery_hello_interval_disc_time, +       ldp_no_discovery_hello_interval_disc_time_cmd, +       "no discovery hello interval <1-65535>", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "LDP Link Hellos\n" +       "Hello interval\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "hello_type", .value = "hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_no_discovery_targeted_hello_holdtime_disc_time, +       ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd, +       "no discovery targeted-hello holdtime <1-65535>", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "LDP Targeted Hellos\n" +       "Targeted hello holdtime\n" +       "Time (seconds) - 65535 implies infinite\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_no_discovery_targeted_hello_interval_disc_time, +       ldp_no_discovery_targeted_hello_interval_disc_time_cmd, +       "no discovery targeted-hello interval <1-65535>", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "LDP Targeted Hellos\n" +       "Targeted hello interval\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_no_dual_stack_transport_connection_prefer_ipv4, +       ldp_no_dual_stack_transport_connection_prefer_ipv4_cmd, +       "no dual-stack transport-connection prefer ipv4", +       "Negate a command or set its defaults\n" +       "Configure dual stack parameters\n" +       "Configure TCP transport parameters\n" +       "Configure prefered address family for TCP transport connection with neighbor\n" +       "IPv4\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      NULL +    }; +  return ldp_vty_trans_pref_ipv4 (vty, args); +} + +DEFUN (ldp_no_dual_stack_cisco_interop, +       ldp_no_dual_stack_cisco_interop_cmd, +       "no dual-stack cisco-interop", +       "Negate a command or set its defaults\n" +       "Configure dual stack parameters\n" +       "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      NULL +    }; +  return ldp_vty_ds_cisco_interop (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_password_word, +       ldp_no_neighbor_ipv4_password_word_cmd, +       "no neighbor A.B.C.D password WORD", +       "Negate a command or set its defaults\n" +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "Configure password for MD5 authentication\n" +       "The password\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      &(struct vty_arg) { .name = "password", .value = argv[1] }, +      NULL +    }; +  return ldp_vty_neighbor_password (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_session_holdtime_session_time, +       ldp_no_neighbor_ipv4_session_holdtime_session_time_cmd, +       "no neighbor A.B.C.D session holdtime <15-65535>", +       "Negate a command or set its defaults\n" +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "Configure session parameters\n" +       "Configure session holdtime\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      &(struct vty_arg) { .name = "seconds", .value = argv[1] }, +      NULL +    }; +  return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_ttl_security_disable, +       ldp_no_neighbor_ipv4_ttl_security_disable_cmd, +       "no neighbor A.B.C.D ttl-security disable", +       "Negate a command or set its defaults\n" +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "LDP ttl security check\n" +       "Disable ttl security\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_ttl_security_hops_hops, +       ldp_no_neighbor_ipv4_ttl_security_hops_hops_cmd, +       "no neighbor A.B.C.D ttl-security hops <1-254>", +       "Negate a command or set its defaults\n" +       "Configure neighbor parameters\n" +       "LDP Id of neighbor\n" +       "LDP ttl security check\n" +       "IP hops\n" +       "maximum number of hops\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, +      &(struct vty_arg) { .name = "hops", .value = argv[1] }, +      NULL +    }; +  return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_no_router_id_ipv4, +       ldp_no_router_id_ipv4_cmd, +       "no router-id A.B.C.D", +       "Negate a command or set its defaults\n" +       "Configure router Id\n" +       "LSR Id (in form of an IPv4 address)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_router_id (vty, args); +} + +DEFUN (ldp_discovery_targeted_hello_accept, +       ldp_discovery_targeted_hello_accept_cmd, +       "discovery targeted-hello accept", +       "Configure discovery parameters\n" +       "LDP Targeted Hellos\n" +       "Accept and respond to targeted hellos\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, +      NULL +    }; +  return ldp_vty_targeted_hello_accept (vty, args); +} + +DEFUN (ldp_label_local_advertise_explicit_null, +       ldp_label_local_advertise_explicit_null_cmd, +       "label local advertise explicit-null", +       "Configure label control and policies\n" +       "Configure local label control and policies\n" +       "Configure outbound label advertisement control\n" +       "Configure explicit-null advertisement\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_explicit_null (vty, args); +} + +DEFUN (ldp_ttl_security_disable, +       ldp_ttl_security_disable_cmd, +       "ttl-security disable", +       "LDP ttl security check\n" +       "Disable ttl security\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_ttl_security (vty, args); +} + +DEFUN (ldp_session_holdtime_session_time, +       ldp_session_holdtime_session_time_cmd, +       "session holdtime <15-65535>", +       "Configure session parameters\n" +       "Configure session holdtime\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_interface_ifname, +       ldp_interface_ifname_cmd, +       "interface IFNAME", +       "Enable LDP on an interface and enter interface submode\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_interface (vty, args); +} + +DEFUN (ldp_discovery_transport_address_ipv4, +       ldp_discovery_transport_address_ipv4_cmd, +       "discovery transport-address A.B.C.D", +       "Configure discovery parameters\n" +       "Specify transport address for TCP connection\n" +       "IP address to be used as transport address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_targeted, +       ldp_neighbor_ipv4_targeted_cmd, +       "neighbor A.B.C.D targeted", +       "Configure neighbor parameters\n" +       "IP address of neighbor\n" +       "Establish targeted session\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_no_discovery_targeted_hello_accept, +       ldp_no_discovery_targeted_hello_accept_cmd, +       "no discovery targeted-hello accept", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "LDP Targeted Hellos\n" +       "Accept and respond to targeted hellos\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, +      NULL +    }; +  return ldp_vty_targeted_hello_accept (vty, args); +} + +DEFUN (ldp_no_label_local_advertise_explicit_null, +       ldp_no_label_local_advertise_explicit_null_cmd, +       "no label local advertise explicit-null", +       "Negate a command or set its defaults\n" +       "Configure label control and policies\n" +       "Configure local label control and policies\n" +       "Configure outbound label advertisement control\n" +       "Configure explicit-null advertisement\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      NULL +    }; +  return ldp_vty_explicit_null (vty, args); +} + +DEFUN (ldp_no_ttl_security_disable, +       ldp_no_ttl_security_disable_cmd, +       "no ttl-security disable", +       "Negate a command or set its defaults\n" +       "LDP ttl security check\n" +       "Disable ttl security\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      NULL +    }; +  return ldp_vty_ttl_security (vty, args); +} + +DEFUN (ldp_no_session_holdtime_session_time, +       ldp_no_session_holdtime_session_time_cmd, +       "no session holdtime <15-65535>", +       "Negate a command or set its defaults\n" +       "Configure session parameters\n" +       "Configure session holdtime\n" +       "Time (seconds)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "seconds", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_no_interface_ifname, +       ldp_no_interface_ifname_cmd, +       "no interface IFNAME", +       "Negate a command or set its defaults\n" +       "Enable LDP on an interface and enter interface submode\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_interface (vty, args); +} + +DEFUN (ldp_no_discovery_transport_address_ipv4, +       ldp_no_discovery_transport_address_ipv4_cmd, +       "no discovery transport-address A.B.C.D", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "Specify transport address for TCP connection\n" +       "IP address to be used as transport address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_targeted, +       ldp_no_neighbor_ipv4_targeted_cmd, +       "no neighbor A.B.C.D targeted", +       "Negate a command or set its defaults\n" +       "Configure neighbor parameters\n" +       "IP address of neighbor\n" +       "Establish targeted session\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_discovery_transport_address_ipv6, +       ldp_discovery_transport_address_ipv6_cmd, +       "discovery transport-address X:X::X:X", +       "Configure discovery parameters\n" +       "Specify transport address for TCP connection\n" +       "IPv6 address to be used as transport address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_neighbor_ipv6_targeted, +       ldp_neighbor_ipv6_targeted_cmd, +       "neighbor X:X::X:X targeted", +       "Configure neighbor parameters\n" +       "IPv6 address of neighbor\n" +       "Establish targeted session\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_no_discovery_transport_address_ipv6, +       ldp_no_discovery_transport_address_ipv6_cmd, +       "no discovery transport-address X:X::X:X", +       "Negate a command or set its defaults\n" +       "Configure discovery parameters\n" +       "Specify transport address for TCP connection\n" +       "IPv6 address to be used as transport address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv6_targeted, +       ldp_no_neighbor_ipv6_targeted_cmd, +       "no neighbor X:X::X:X targeted", +       "Negate a command or set its defaults\n" +       "Configure neighbor parameters\n" +       "IPv6 address of neighbor\n" +       "Establish targeted session\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_bridge_ifname, +       ldp_bridge_ifname_cmd, +       "bridge IFNAME", +       "Bridge interface\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_bridge (vty, args); +} + +DEFUN (ldp_mtu_mtu, +       ldp_mtu_mtu_cmd, +       "mtu <1500-9180>", +       "set Maximum Transmission Unit\n" +       "Maximum Transmission Unit value\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "mtu", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_mtu (vty, args); +} + +DEFUN (ldp_member_interface_ifname, +       ldp_member_interface_ifname_cmd, +       "member interface IFNAME", +       "L2VPN member configuration\n" +       "Local interface\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_interface (vty, args); +} + +DEFUN (ldp_member_pseudowire_ifname, +       ldp_member_pseudowire_ifname_cmd, +       "member pseudowire IFNAME", +       "L2VPN member configuration\n" +       "Pseudowire interface\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pseudowire (vty, args); +} + +DEFUN (ldp_vc_type_pwtype, +       ldp_vc_type_pwtype_cmd, +       "vc type (ethernet|ethernet-tagged)", +       "Virtual Circuit options\n" +       "Virtual Circuit type to use\n" +       "Ethernet (type 5)\n" +       "Ethernet-tagged (type 4)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pwtype (vty, args); +} + +DEFUN (ldp_no_bridge_ifname, +       ldp_no_bridge_ifname_cmd, +       "no bridge IFNAME", +       "Negate a command or set its defaults\n" +       "Bridge interface\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_bridge (vty, args); +} + +DEFUN (ldp_no_mtu_mtu, +       ldp_no_mtu_mtu_cmd, +       "no mtu <1500-9180>", +       "Negate a command or set its defaults\n" +       "set Maximum Transmission Unit\n" +       "Maximum Transmission Unit value\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "mtu", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_mtu (vty, args); +} + +DEFUN (ldp_no_member_interface_ifname, +       ldp_no_member_interface_ifname_cmd, +       "no member interface IFNAME", +       "Negate a command or set its defaults\n" +       "L2VPN member configuration\n" +       "Local interface\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_interface (vty, args); +} + +DEFUN (ldp_no_member_pseudowire_ifname, +       ldp_no_member_pseudowire_ifname_cmd, +       "no member pseudowire IFNAME", +       "Negate a command or set its defaults\n" +       "L2VPN member configuration\n" +       "Pseudowire interface\n" +       "Interface's name\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "ifname", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pseudowire (vty, args); +} + +DEFUN (ldp_no_vc_type_pwtype, +       ldp_no_vc_type_pwtype_cmd, +       "no vc type (ethernet|ethernet-tagged)", +       "Negate a command or set its defaults\n" +       "Virtual Circuit options\n" +       "Virtual Circuit type to use\n" +       "Ethernet (type 5)\n" +       "Ethernet-tagged (type 4)\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pwtype (vty, args); +} + +DEFUN (ldp_control_word_cword, +       ldp_control_word_cword_cmd, +       "control-word (exclude|include)", +       "Control-word options\n" +       "Exclude control-word in pseudowire packets\n" +       "Include control-word in pseudowire packets\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "preference", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_cword (vty, args); +} + +DEFUN (ldp_neighbor_address_addr, +       ldp_neighbor_address_addr_cmd, +       "neighbor address (A.B.C.D|X:X::X:X)", +       "Remote endpoint configuration\n" +       "Specify the IPv4 or IPv6 address of the remote endpoint\n" +       "IPv4 address\n" +       "IPv6 address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_nbr_addr (vty, args); +} + +DEFUN (ldp_neighbor_lsr_id_ipv4, +       ldp_neighbor_lsr_id_ipv4_cmd, +       "neighbor lsr-id A.B.C.D", +       "Remote endpoint configuration\n" +       "Specify the LSR-ID of the remote endpoint\n" +       "IPv4 address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "lsr-id", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_nbr_id (vty, args); +} + +DEFUN (ldp_pw_id_pwid, +       ldp_pw_id_pwid_cmd, +       "pw-id <1-4294967295>", +       "Set the Virtual Circuit ID\n" +       "Virtual Circuit ID value\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "pwid", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_pwid (vty, args); +} + +DEFUN (ldp_pw_status_disable, +       ldp_pw_status_disable_cmd, +       "pw-status disable", +       "Configure PW status\n" +       "Disable PW status\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_l2vpn_pw_pwstatus (vty, args); +} + +DEFUN (ldp_no_control_word_cword, +       ldp_no_control_word_cword_cmd, +       "no control-word (exclude|include)", +       "Negate a command or set its defaults\n" +       "Control-word options\n" +       "Exclude control-word in pseudowire packets\n" +       "Include control-word in pseudowire packets\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "preference", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_cword (vty, args); +} + +DEFUN (ldp_no_neighbor_address_addr, +       ldp_no_neighbor_address_addr_cmd, +       "no neighbor address (A.B.C.D|X:X::X:X)", +       "Negate a command or set its defaults\n" +       "Remote endpoint configuration\n" +       "Specify the IPv4 or IPv6 address of the remote endpoint\n" +       "IPv4 address\n" +       "IPv6 address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_nbr_addr (vty, args); +} + +DEFUN (ldp_no_neighbor_lsr_id_ipv4, +       ldp_no_neighbor_lsr_id_ipv4_cmd, +       "no neighbor lsr-id A.B.C.D", +       "Negate a command or set its defaults\n" +       "Remote endpoint configuration\n" +       "Specify the LSR-ID of the remote endpoint\n" +       "IPv4 address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "lsr-id", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_nbr_id (vty, args); +} + +DEFUN (ldp_no_pw_id_pwid, +       ldp_no_pw_id_pwid_cmd, +       "no pw-id <1-4294967295>", +       "Negate a command or set its defaults\n" +       "Set the Virtual Circuit ID\n" +       "Virtual Circuit ID value\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "pwid", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_pwid (vty, args); +} + +DEFUN (ldp_no_pw_status_disable, +       ldp_no_pw_status_disable_cmd, +       "no pw-status disable", +       "Negate a command or set its defaults\n" +       "Configure PW status\n" +       "Disable PW status\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      NULL +    }; +  return ldp_vty_l2vpn_pw_pwstatus (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_neighbor, +       ldp_show_mpls_ldp_neighbor_cmd, +       "show mpls ldp neighbor", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Neighbor information\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_neighbor (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_binding, +       ldp_show_mpls_ldp_binding_cmd, +       "show mpls ldp binding", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Label Information Base (LIB) information\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_binding (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_discovery, +       ldp_show_mpls_ldp_discovery_cmd, +       "show mpls ldp discovery", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Discovery Hello Information\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_discovery (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_interface, +       ldp_show_mpls_ldp_interface_cmd, +       "show mpls ldp interface", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "interface information\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_interface (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_address_family_binding, +       ldp_show_mpls_ldp_address_family_binding_cmd, +       "show mpls ldp (ipv4|ipv6) binding", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "IPv4 Address Family\n" +       "IPv6 Address Family\n" +       "Label Information Base (LIB) information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "address-family", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_show_binding (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_address_family_discovery, +       ldp_show_mpls_ldp_address_family_discovery_cmd, +       "show mpls ldp (ipv4|ipv6) discovery", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "IPv4 Address Family\n" +       "IPv6 Address Family\n" +       "Discovery Hello Information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "address-family", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_show_discovery (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_address_family_interface, +       ldp_show_mpls_ldp_address_family_interface_cmd, +       "show mpls ldp (ipv4|ipv6) interface", +       "Show running system information\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "IPv4 Address Family\n" +       "IPv6 Address Family\n" +       "interface information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "address-family", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_show_interface (vty, args); +} + +DEFUN (ldp_show_l2vpn_atom_binding, +       ldp_show_l2vpn_atom_binding_cmd, +       "show l2vpn atom binding", +       "Show running system information\n" +       "Show information about Layer2 VPN\n" +       "Show Any Transport over MPLS information\n" +       "Show AToM label binding information\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_atom_binding (vty, args); +} + +DEFUN (ldp_show_l2vpn_atom_vc, +       ldp_show_l2vpn_atom_vc_cmd, +       "show l2vpn atom vc", +       "Show running system information\n" +       "Show information about Layer2 VPN\n" +       "Show Any Transport over MPLS information\n" +       "Show AToM virtual circuit information\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_atom_vc (vty, args); +} + +DEFUN (ldp_show_debugging_mpls_ldp, +       ldp_show_debugging_mpls_ldp_cmd, +       "show debugging mpls ldp", +       "Show running system information\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_show_debugging (vty, args); +} + +DEFUN (ldp_clear_mpls_ldp_neighbor, +       ldp_clear_mpls_ldp_neighbor_cmd, +       "clear mpls ldp neighbor", +       "Reset functions\n" +       "Reset MPLS statistical information\n" +       "Clear LDP state\n" +       "Clear LDP neighbor sessions\n") +{ +  struct vty_arg *args[] = { NULL }; +  return ldp_vty_clear_nbr (vty, args); +} + +DEFUN (ldp_clear_mpls_ldp_neighbor_addr, +       ldp_clear_mpls_ldp_neighbor_addr_cmd, +       "clear mpls ldp neighbor (A.B.C.D|X:X::X:X)", +       "Reset functions\n" +       "Reset MPLS statistical information\n" +       "Clear LDP state\n" +       "Clear LDP neighbor sessions\n" +       "IPv4 address\n" +       "IPv6 address\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "addr", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_clear_nbr (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_discovery_hello_dir, +       ldp_debug_mpls_ldp_discovery_hello_dir_cmd, +       "debug mpls ldp discovery hello (recv|sent)", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Discovery messages\n" +       "Discovery hello message\n" +       "Received messages\n" +       "Sent messages\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "discovery" }, +      &(struct vty_arg) { .name = "dir", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_errors, +       ldp_debug_mpls_ldp_errors_cmd, +       "debug mpls ldp errors", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Errors\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "errors" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_event, +       ldp_debug_mpls_ldp_event_cmd, +       "debug mpls ldp event", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "LDP event information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "event" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_recv, +       ldp_debug_mpls_ldp_messages_recv_cmd, +       "debug mpls ldp messages recv", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Received messages, excluding periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "recv" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_recv_all, +       ldp_debug_mpls_ldp_messages_recv_all_cmd, +       "debug mpls ldp messages recv all", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Received messages, excluding periodic Keep Alives\n" +       "Received messages, including periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "recv" }, +      &(struct vty_arg) { .name = "all", .value = "all" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_sent, +       ldp_debug_mpls_ldp_messages_sent_cmd, +       "debug mpls ldp messages sent", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Sent messages, excluding periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "sent" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_sent_all, +       ldp_debug_mpls_ldp_messages_sent_all_cmd, +       "debug mpls ldp messages sent all", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Sent messages, excluding periodic Keep Alives\n" +       "Sent messages, including periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "sent" }, +      &(struct vty_arg) { .name = "all", .value = "all" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_zebra, +       ldp_debug_mpls_ldp_zebra_cmd, +       "debug mpls ldp zebra", +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "LDP zebra information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "type", .value = "zebra" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_discovery_hello_dir, +       ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd, +       "no debug mpls ldp discovery hello (recv|sent)", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Discovery messages\n" +       "Discovery hello message\n" +       "Received messages\n" +       "Sent messages\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "discovery" }, +      &(struct vty_arg) { .name = "dir", .value = argv[0] }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_errors, +       ldp_no_debug_mpls_ldp_errors_cmd, +       "no debug mpls ldp errors", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Errors\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "errors" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_event, +       ldp_no_debug_mpls_ldp_event_cmd, +       "no debug mpls ldp event", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "LDP event information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "event" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_recv, +       ldp_no_debug_mpls_ldp_messages_recv_cmd, +       "no debug mpls ldp messages recv", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Received messages, excluding periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "recv" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_recv_all, +       ldp_no_debug_mpls_ldp_messages_recv_all_cmd, +       "no debug mpls ldp messages recv all", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Received messages, excluding periodic Keep Alives\n" +       "Received messages, including periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "recv" }, +      &(struct vty_arg) { .name = "all", .value = "all" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_sent, +       ldp_no_debug_mpls_ldp_messages_sent_cmd, +       "no debug mpls ldp messages sent", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Sent messages, excluding periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "sent" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_sent_all, +       ldp_no_debug_mpls_ldp_messages_sent_all_cmd, +       "no debug mpls ldp messages sent all", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "Messages\n" +       "Sent messages, excluding periodic Keep Alives\n" +       "Sent messages, including periodic Keep Alives\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "messages" }, +      &(struct vty_arg) { .name = "dir", .value = "sent" }, +      &(struct vty_arg) { .name = "all", .value = "all" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_zebra, +       ldp_no_debug_mpls_ldp_zebra_cmd, +       "no debug mpls ldp zebra", +       "Negate a command or set its defaults\n" +       "Debugging functions\n" +       "MPLS information\n" +       "Label Distribution Protocol\n" +       "LDP zebra information\n") +{ +  struct vty_arg *args[] = +    { +      &(struct vty_arg) { .name = "no", .value = "no" }, +      &(struct vty_arg) { .name = "type", .value = "zebra" }, +      NULL +    }; +  return ldp_vty_debug (vty, args); +} + +void +ldp_vty_init (void) +{ +  install_element (CONFIG_NODE, &ldp_mpls_ldp_cmd); +  install_element (CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); +  install_element (CONFIG_NODE, &ldp_no_mpls_ldp_cmd); +  install_element (CONFIG_NODE, &ldp_no_l2vpn_word_type_vpls_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_discovery_hello_dir_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_errors_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_event_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_recv_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_recv_all_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_sent_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_sent_all_cmd); +  install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_zebra_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_errors_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_event_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_recv_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_recv_all_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_sent_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_sent_all_cmd); +  install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_zebra_cmd); +  install_node (&ldp_node, ldp_config_write); +  install_default (LDP_NODE); +  install_element (LDP_NODE, &ldp_address_family_ipv4_cmd); +  install_element (LDP_NODE, &ldp_address_family_ipv6_cmd); +  install_element (LDP_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_NODE, &ldp_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd); +  install_element (LDP_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd); +  install_element (LDP_NODE, &ldp_dual_stack_transport_connection_prefer_ipv4_cmd); +  install_element (LDP_NODE, &ldp_dual_stack_cisco_interop_cmd); +  install_element (LDP_NODE, &ldp_neighbor_ipv4_password_word_cmd); +  install_element (LDP_NODE, &ldp_neighbor_ipv4_session_holdtime_session_time_cmd); +  install_element (LDP_NODE, &ldp_neighbor_ipv4_ttl_security_disable_cmd); +  install_element (LDP_NODE, &ldp_neighbor_ipv4_ttl_security_hops_hops_cmd); +  install_element (LDP_NODE, &ldp_router_id_ipv4_cmd); +  install_element (LDP_NODE, &ldp_no_address_family_ipv4_cmd); +  install_element (LDP_NODE, &ldp_no_address_family_ipv6_cmd); +  install_element (LDP_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd); +  install_element (LDP_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd); +  install_element (LDP_NODE, &ldp_no_dual_stack_transport_connection_prefer_ipv4_cmd); +  install_element (LDP_NODE, &ldp_no_dual_stack_cisco_interop_cmd); +  install_element (LDP_NODE, &ldp_no_neighbor_ipv4_password_word_cmd); +  install_element (LDP_NODE, &ldp_no_neighbor_ipv4_session_holdtime_session_time_cmd); +  install_element (LDP_NODE, &ldp_no_neighbor_ipv4_ttl_security_disable_cmd); +  install_element (LDP_NODE, &ldp_no_neighbor_ipv4_ttl_security_hops_hops_cmd); +  install_element (LDP_NODE, &ldp_no_router_id_ipv4_cmd); +  install_node (&ldp_ipv4_node, NULL); +  install_default (LDP_IPV4_NODE); +  install_element (LDP_IPV4_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_accept_cmd); +  install_element (LDP_IPV4_NODE, &ldp_label_local_advertise_explicit_null_cmd); +  install_element (LDP_IPV4_NODE, &ldp_ttl_security_disable_cmd); +  install_element (LDP_IPV4_NODE, &ldp_session_holdtime_session_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_interface_ifname_cmd); +  install_element (LDP_IPV4_NODE, &ldp_discovery_transport_address_ipv4_cmd); +  install_element (LDP_IPV4_NODE, &ldp_neighbor_ipv4_targeted_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_accept_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_label_local_advertise_explicit_null_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_ttl_security_disable_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_session_holdtime_session_time_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_interface_ifname_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_discovery_transport_address_ipv4_cmd); +  install_element (LDP_IPV4_NODE, &ldp_no_neighbor_ipv4_targeted_cmd); +  install_node (&ldp_ipv6_node, NULL); +  install_default (LDP_IPV6_NODE); +  install_element (LDP_IPV6_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_accept_cmd); +  install_element (LDP_IPV6_NODE, &ldp_label_local_advertise_explicit_null_cmd); +  install_element (LDP_IPV6_NODE, &ldp_ttl_security_disable_cmd); +  install_element (LDP_IPV6_NODE, &ldp_session_holdtime_session_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_interface_ifname_cmd); +  install_element (LDP_IPV6_NODE, &ldp_discovery_transport_address_ipv6_cmd); +  install_element (LDP_IPV6_NODE, &ldp_neighbor_ipv6_targeted_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_accept_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_label_local_advertise_explicit_null_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_ttl_security_disable_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_session_holdtime_session_time_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_interface_ifname_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_discovery_transport_address_ipv6_cmd); +  install_element (LDP_IPV6_NODE, &ldp_no_neighbor_ipv6_targeted_cmd); +  install_node (&ldp_ipv4_iface_node, NULL); +  install_default (LDP_IPV4_IFACE_NODE); +  install_element (LDP_IPV4_IFACE_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV4_IFACE_NODE, &ldp_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_IPV4_IFACE_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV4_IFACE_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); +  install_node (&ldp_ipv6_iface_node, NULL); +  install_default (LDP_IPV6_IFACE_NODE); +  install_element (LDP_IPV6_IFACE_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV6_IFACE_NODE, &ldp_discovery_hello_interval_disc_time_cmd); +  install_element (LDP_IPV6_IFACE_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); +  install_element (LDP_IPV6_IFACE_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); +  install_node (&ldp_l2vpn_node, ldp_l2vpn_config_write); +  install_default (LDP_L2VPN_NODE); +  install_element (LDP_L2VPN_NODE, &ldp_bridge_ifname_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_mtu_mtu_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_member_interface_ifname_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_vc_type_pwtype_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_no_bridge_ifname_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_no_mtu_mtu_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_no_member_interface_ifname_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_no_member_pseudowire_ifname_cmd); +  install_element (LDP_L2VPN_NODE, &ldp_no_vc_type_pwtype_cmd); +  install_node (&ldp_pseudowire_node, NULL); +  install_default (LDP_PSEUDOWIRE_NODE); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_control_word_cword_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_neighbor_address_addr_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_neighbor_lsr_id_ipv4_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_pw_id_pwid_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_pw_status_disable_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_control_word_cword_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_neighbor_address_addr_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_neighbor_lsr_id_ipv4_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_pw_id_pwid_cmd); +  install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_pw_status_disable_cmd); +  install_node (&ldp_debug_node, ldp_debug_config_write); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_neighbor_cmd); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_binding_cmd); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_discovery_cmd); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_interface_cmd); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_binding_cmd); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_discovery_cmd); +  install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_interface_cmd); +  install_element (ENABLE_NODE, &ldp_show_l2vpn_atom_binding_cmd); +  install_element (ENABLE_NODE, &ldp_show_l2vpn_atom_vc_cmd); +  install_element (ENABLE_NODE, &ldp_show_debugging_mpls_ldp_cmd); +  install_element (ENABLE_NODE, &ldp_clear_mpls_ldp_neighbor_cmd); +  install_element (ENABLE_NODE, &ldp_clear_mpls_ldp_neighbor_addr_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_discovery_hello_dir_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_errors_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_event_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_recv_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_recv_all_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_sent_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_sent_all_cmd); +  install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_zebra_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_errors_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_event_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_recv_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_recv_all_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_sent_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_sent_all_cmd); +  install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_zebra_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_neighbor_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_binding_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_discovery_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_interface_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_binding_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_discovery_cmd); +  install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_interface_cmd); +  install_element (VIEW_NODE, &ldp_show_l2vpn_atom_binding_cmd); +  install_element (VIEW_NODE, &ldp_show_l2vpn_atom_vc_cmd); +  install_element (VIEW_NODE, &ldp_show_debugging_mpls_ldp_cmd); +  install_element (VIEW_NODE, &ldp_clear_mpls_ldp_neighbor_cmd); +  install_element (VIEW_NODE, &ldp_clear_mpls_ldp_neighbor_addr_cmd); +}
\ No newline at end of file diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c new file mode 100644 index 0000000000..a3e1b9a250 --- /dev/null +++ b/ldpd/ldp_vty_conf.c @@ -0,0 +1,1637 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" +#include "log.h" + +#include "command.h" +#include "vrf.h" +#include "if.h" +#include "vty.h" +#include "ldp_vty.h" + +static int	 interface_config_write(struct vty *); +static void	 ldp_af_iface_config_write(struct vty *, int); +static void	 ldp_af_config_write(struct vty *, int, struct ldpd_conf *, +		    struct ldpd_af_conf *); +static void	 ldp_l2vpn_pw_config_write(struct vty *, struct l2vpn_pw *); +static int	 ldp_vty_get_af(struct vty *); +static int	 ldp_iface_is_configured(struct ldpd_conf *, const char *); +static int	 ldp_vty_nbr_session_holdtime(struct vty *, struct vty_arg *[]); +static int	 ldp_vty_af_session_holdtime(struct vty *, struct vty_arg *[]); + +static char	 vty_ifname[IF_NAMESIZE]; +static char	 vty_l2vpn_name[L2VPN_NAME_LEN]; +static char	 vty_pw_ifname[IF_NAMESIZE]; + +static struct cmd_node interface_node = +{ +	INTERFACE_NODE, +	"%s(config-if)# ", +	1 +}; + +struct cmd_node ldp_node = +{ +	LDP_NODE, +	"%s(config-ldp)# ", +	1, +}; + +struct cmd_node ldp_ipv4_node = +{ +	LDP_IPV4_NODE, +	"%s(config-ldp-af)# ", +	1, +}; + +struct cmd_node ldp_ipv6_node = +{ +	LDP_IPV6_NODE, +	"%s(config-ldp-af)# ", +	1, +}; + +struct cmd_node ldp_ipv4_iface_node = +{ +	LDP_IPV4_IFACE_NODE, +	"%s(config-ldp-af-if)# ", +	1, +}; + +struct cmd_node ldp_ipv6_iface_node = +{ +	LDP_IPV6_IFACE_NODE, +	"%s(config-ldp-af-if)# ", +	1, +}; + +struct cmd_node ldp_l2vpn_node = +{ +	LDP_L2VPN_NODE, +	"%s(config-l2vpn)# ", +	1, +}; + +struct cmd_node ldp_pseudowire_node = +{ +	LDP_PSEUDOWIRE_NODE, +	"%s(config-l2vpn-pw)# ", +	1, +}; + +int +ldp_get_address(const char *str, int *af, union ldpd_addr *addr) +{ +	memset(addr, 0, sizeof(*addr)); + +	if (inet_pton(AF_INET, str, &addr->v4) == 1) { +		*af = AF_INET; +		return (0); +	} + +	if (inet_pton(AF_INET6, str, &addr->v6) == 1) { +		*af = AF_INET6; +		return (0); +	} + +	return (-1); +} + +static int +interface_config_write(struct vty *vty) +{ +	struct listnode		*node; +	struct interface	*ifp; +	int			 write = 0; + +	for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT), node, ifp)) { +		vty_out(vty, "!%s", VTY_NEWLINE); +		vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); +		if (ifp->desc) +			vty_out(vty, " description %s%s", ifp->desc, +			    VTY_NEWLINE); + +		write++; +	} + +	return (write); +} + +static void +ldp_af_iface_config_write(struct vty *vty, int af) +{ +	struct iface		*iface; +	struct iface_af		*ia; + +	LIST_FOREACH(iface, &ldpd_conf->iface_list, entry) { +		ia = iface_af_get(iface, af); +		if (!ia->enabled) +			continue; + +		vty_out(vty, "  !%s", VTY_NEWLINE); +		vty_out(vty, "  interface %s%s", iface->name, VTY_NEWLINE); + +		if (ia->hello_holdtime != LINK_DFLT_HOLDTIME && +		    ia->hello_holdtime != 0) +			vty_out(vty, "   discovery hello holdtime %u%s", +			    ia->hello_holdtime, VTY_NEWLINE); +		if (ia->hello_interval != DEFAULT_HELLO_INTERVAL && +		    ia->hello_interval != 0) +			vty_out(vty, "   discovery hello interval %u%s", +			    ia->hello_interval, VTY_NEWLINE); +	} +} + +static void +ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf, +    struct ldpd_af_conf *af_conf) +{ +	struct tnbr		*tnbr; + +	if (!(af_conf->flags & F_LDPD_AF_ENABLED)) +		return; + +	vty_out(vty, " !%s", VTY_NEWLINE); +	vty_out(vty, " address-family %s%s", af_name(af), VTY_NEWLINE); + +	if (af_conf->lhello_holdtime != LINK_DFLT_HOLDTIME && +	    af_conf->lhello_holdtime != 0 ) +		vty_out(vty, "  discovery hello holdtime %u%s", +		    af_conf->lhello_holdtime, VTY_NEWLINE); +	if (af_conf->lhello_interval != DEFAULT_HELLO_INTERVAL && +	    af_conf->lhello_interval != 0) +		vty_out(vty, "  discovery hello interval %u%s", +		    af_conf->lhello_interval, VTY_NEWLINE); + +	if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) +		vty_out(vty, "  discovery targeted-hello accept%s", +		    VTY_NEWLINE); + +	if (af_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && +	    af_conf->thello_holdtime != 0) +		vty_out(vty, "  discovery targeted-hello holdtime %u%s", +		    af_conf->thello_holdtime, VTY_NEWLINE); +	if (af_conf->thello_interval != DEFAULT_HELLO_INTERVAL && +	    af_conf->thello_interval != 0) +		vty_out(vty, "  discovery targeted-hello interval %u%s", +		    af_conf->thello_interval, VTY_NEWLINE); + +	if (ldp_addrisset(af, &af_conf->trans_addr)) +		vty_out(vty, "  discovery transport-address %s%s", +		    log_addr(af, &af_conf->trans_addr), VTY_NEWLINE); +	else +		vty_out(vty, "  ! Incomplete config, specify a discovery " +		    "transport-address%s", VTY_NEWLINE); + +	if (af_conf->flags & F_LDPD_AF_EXPNULL) +		vty_out(vty, "  label local advertise explicit-null%s", +		    VTY_NEWLINE); + +	if (af_conf->flags & F_LDPD_AF_NO_GTSM) +		vty_out(vty, "  ttl-security disable%s", VTY_NEWLINE); + +	if (af_conf->keepalive != DEFAULT_KEEPALIVE) +		vty_out(vty, "  session holdtime %u%s", af_conf->keepalive, +		    VTY_NEWLINE); + +	LIST_FOREACH(tnbr, &ldpd_conf->tnbr_list, entry) { +		if (tnbr->af == af) { +			vty_out(vty, "  !%s", VTY_NEWLINE); +			vty_out(vty, "  neighbor %s targeted%s", +			    log_addr(tnbr->af, &tnbr->addr), VTY_NEWLINE); +		} +	} + +	ldp_af_iface_config_write(vty, af); + +	vty_out(vty, "  !%s", VTY_NEWLINE); +} + +int +ldp_config_write(struct vty *vty) +{ +	struct nbr_params	*nbrp; + +	if (!(ldpd_conf->flags & F_LDPD_ENABLED)) +		return (0); + +	vty_out(vty, "mpls ldp%s", VTY_NEWLINE); + +	if (ldpd_conf->rtr_id.s_addr != 0) +		vty_out(vty, " router-id %s%s", +		    inet_ntoa(ldpd_conf->rtr_id), VTY_NEWLINE); + +	if (ldpd_conf->lhello_holdtime != LINK_DFLT_HOLDTIME && +	    ldpd_conf->lhello_holdtime != 0) +		vty_out(vty, " discovery hello holdtime %u%s", +		    ldpd_conf->lhello_holdtime, VTY_NEWLINE); +	if (ldpd_conf->lhello_interval != DEFAULT_HELLO_INTERVAL && +	    ldpd_conf->lhello_interval != 0) +		vty_out(vty, " discovery hello interval %u%s", +		    ldpd_conf->lhello_interval, VTY_NEWLINE); + +	if (ldpd_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && +	    ldpd_conf->thello_holdtime != 0) +		vty_out(vty, " discovery targeted-hello holdtime %u%s", +		    ldpd_conf->thello_holdtime, VTY_NEWLINE); +	if (ldpd_conf->thello_interval != DEFAULT_HELLO_INTERVAL && +	    ldpd_conf->thello_interval != 0) +		vty_out(vty, " discovery targeted-hello interval %u%s", +		    ldpd_conf->thello_interval, VTY_NEWLINE); + +	if (ldpd_conf->trans_pref == DUAL_STACK_LDPOV4) +		vty_out(vty, " dual-stack transport-connection prefer ipv4%s", +		    VTY_NEWLINE); + +	if (ldpd_conf->flags & F_LDPD_DS_CISCO_INTEROP) +		vty_out(vty, " dual-stack cisco-interop%s", VTY_NEWLINE); + +	LIST_FOREACH(nbrp, &ldpd_conf->nbrp_list, entry) { +		if (nbrp->flags & F_NBRP_KEEPALIVE) +			vty_out(vty, " neighbor %s session holdtime %u%s", +			    inet_ntoa(nbrp->lsr_id), nbrp->keepalive, +			    VTY_NEWLINE); + +		if (nbrp->flags & F_NBRP_GTSM) { +			if (nbrp->gtsm_enabled) +				vty_out(vty, " neighbor %s ttl-security hops " +				    "%u%s",  inet_ntoa(nbrp->lsr_id), +				    nbrp->gtsm_hops, VTY_NEWLINE); +			else +				vty_out(vty, " neighbor %s ttl-security " +				    "disable%s", inet_ntoa(nbrp->lsr_id), +				    VTY_NEWLINE); +		} + +		if (nbrp->auth.method == AUTH_MD5SIG) +			vty_out(vty, " neighbor %s password %s%s", +			    inet_ntoa(nbrp->lsr_id), nbrp->auth.md5key, +			    VTY_NEWLINE); +	} + +	ldp_af_config_write(vty, AF_INET, ldpd_conf, &ldpd_conf->ipv4); +	ldp_af_config_write(vty, AF_INET6, ldpd_conf, &ldpd_conf->ipv6); +	vty_out(vty, " !%s", VTY_NEWLINE); +	vty_out(vty, "!%s", VTY_NEWLINE); + +	return (1); +} + +static void +ldp_l2vpn_pw_config_write(struct vty *vty, struct l2vpn_pw *pw) +{ +	int	 missing_lsrid = 0; +	int	 missing_pwid = 0; + +	vty_out(vty, " !%s", VTY_NEWLINE); +	vty_out(vty, " member pseudowire %s%s", pw->ifname, VTY_NEWLINE); + +	if (pw->lsr_id.s_addr != INADDR_ANY) +		vty_out(vty, "  neighbor lsr-id %s%s", inet_ntoa(pw->lsr_id), +		    VTY_NEWLINE); +	else +		missing_lsrid = 1; + +	if (pw->flags & F_PW_STATIC_NBR_ADDR) +		vty_out(vty, "  neighbor address %s%s", log_addr(pw->af, +		    &pw->addr), VTY_NEWLINE); + +	if (pw->pwid != 0) +		vty_out(vty, "  pw-id %u%s", pw->pwid, VTY_NEWLINE); +	else +		missing_pwid = 1; + +	if (!(pw->flags & F_PW_CWORD_CONF)) +		vty_out(vty, "  control-word exclude%s", VTY_NEWLINE); + +	if (!(pw->flags & F_PW_STATUSTLV_CONF)) +		vty_out(vty, "  pw-status disable%s", VTY_NEWLINE); + +	if (missing_lsrid) +		vty_out(vty, "  ! Incomplete config, specify a neighbor " +		    "lsr-id%s", VTY_NEWLINE); +	if (missing_pwid) +		vty_out(vty, "  ! Incomplete config, specify a pw-id%s", +		    VTY_NEWLINE); +} + +int +ldp_l2vpn_config_write(struct vty *vty) +{ +	struct l2vpn		*l2vpn; +	struct l2vpn_if		*lif; +	struct l2vpn_pw		*pw; + +	LIST_FOREACH(l2vpn, &ldpd_conf->l2vpn_list, entry) { +		vty_out(vty, "l2vpn %s type vpls%s", l2vpn->name, VTY_NEWLINE); + +		if (l2vpn->pw_type != DEFAULT_PW_TYPE) +			vty_out(vty, " vc type ethernet-tagged%s", VTY_NEWLINE); + +		if (l2vpn->mtu != DEFAULT_L2VPN_MTU) +			vty_out(vty, " mtu %u%s", l2vpn->mtu, VTY_NEWLINE); + +		if (l2vpn->br_ifname[0] != '\0') +			vty_out(vty, " bridge %s%s", l2vpn->br_ifname, +			    VTY_NEWLINE); + +		LIST_FOREACH(lif, &l2vpn->if_list, entry) +			vty_out(vty, " member interface %s%s", lif->ifname, +			    VTY_NEWLINE); + +		LIST_FOREACH(pw, &l2vpn->pw_list, entry) +			ldp_l2vpn_pw_config_write(vty, pw); +		LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) +			ldp_l2vpn_pw_config_write(vty, pw); + +		vty_out(vty, " !%s", VTY_NEWLINE); +		vty_out(vty, "!%s", VTY_NEWLINE); +	} + +	return (0); +} + +static int +ldp_vty_get_af(struct vty *vty) +{ +	switch (vty->node) { +	case LDP_IPV4_NODE: +	case LDP_IPV4_IFACE_NODE: +		return (AF_INET); +	case LDP_IPV6_NODE: +	case LDP_IPV6_IFACE_NODE: +		return (AF_INET6); +	default: +		fatalx("ldp_vty_get_af: unexpected node"); +	} +} + +static int +ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname) +{ +	struct l2vpn	*l2vpn; + +	if (if_lookup_name(xconf, ifname)) +		return (1); + +	LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) { +		if (l2vpn_if_find_name(l2vpn, ifname)) +			return (1); +		if (l2vpn_pw_find_name(l2vpn, ifname)) +			return (1); +	} + +	return (0); +} + +int +ldp_vty_mpls_ldp(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	int			 disable; + +	vty_conf = ldp_dup_config(ldpd_conf); + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	if (disable) +		vty_conf->flags &= ~F_LDPD_ENABLED; +	else { +		vty->node = LDP_NODE; +		vty_conf->flags |= F_LDPD_ENABLED; +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_address_family(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	int			 af; + 	const char		*af_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	af_str = vty_get_arg_value(args, "address-family"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	if (strcmp(af_str, "ipv4") == 0) { +		af = AF_INET; +		af_conf = &vty_conf->ipv4; +	} else if (strcmp(af_str, "ipv6") == 0) { +		af = AF_INET6; +		af_conf = &vty_conf->ipv6; +	} else +		return (CMD_WARNING); + +	if (disable) { +		af_conf->flags &= ~F_LDPD_AF_ENABLED; +		ldp_reload(vty_conf); +		return (CMD_SUCCESS); +	} + +	switch (af) { +	case AF_INET: +		vty->node = LDP_IPV4_NODE; +		break; +	case AF_INET6: +		vty->node = LDP_IPV6_NODE; +		break; +	default: +		fatalx("ldp_vty_address_family: unknown af"); +	} +	af_conf->flags |= F_LDPD_AF_ENABLED; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	struct iface		*iface; +	struct iface_af		*ia; +	int			 af; +	char			*ep; +	long int		 secs; +	enum hello_type		 hello_type; +	const char		*seconds_str; +	const char		*hello_type_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	seconds_str = vty_get_arg_value(args, "seconds"); +	hello_type_str = vty_get_arg_value(args, "hello_type"); + +	secs = strtol(seconds_str, &ep, 10); +	if (*ep != '\0' || secs < MIN_HOLDTIME || secs > MAX_HOLDTIME) { +		vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	if (hello_type_str[0] == 'h') +		hello_type = HELLO_LINK; +	else +		hello_type = HELLO_TARGETED; + +	vty_conf = ldp_dup_config(ldpd_conf); + +	switch (vty->node) { +	case LDP_NODE: +		if (disable) { +			switch (hello_type) { +			case HELLO_LINK: +				vty_conf->lhello_holdtime = LINK_DFLT_HOLDTIME; +				break; +			case HELLO_TARGETED: +				vty_conf->thello_holdtime = +				    TARGETED_DFLT_HOLDTIME; +				break; +			} +		} else { +			switch (hello_type) { +			case HELLO_LINK: +				vty_conf->lhello_holdtime = secs; +				break; +			case HELLO_TARGETED: +				vty_conf->thello_holdtime = secs; +				break; +			} +		} +		break; +	case LDP_IPV4_NODE: +	case LDP_IPV6_NODE: +		af = ldp_vty_get_af(vty); +		af_conf = ldp_af_conf_get(vty_conf, af); + +		if (disable) { +			switch (hello_type) { +			case HELLO_LINK: +				af_conf->lhello_holdtime = 0; +				break; +			case HELLO_TARGETED: +				af_conf->thello_holdtime = 0; +				break; +			} +		} else { +			switch (hello_type) { +			case HELLO_LINK: +				af_conf->lhello_holdtime = secs; +				break; +			case HELLO_TARGETED: +				af_conf->thello_holdtime = secs; +				break; +			} +		} +		break; +	case LDP_IPV4_IFACE_NODE: +	case LDP_IPV6_IFACE_NODE: +		af = ldp_vty_get_af(vty); +		iface = if_lookup_name(vty_conf, vty_ifname); +		ia = iface_af_get(iface, af); + +		if (disable) +			ia->hello_holdtime = 0; +		else +			ia->hello_holdtime = secs; +		break; +	default: +		fatalx("ldp_vty_disc_holdtime: unexpected node"); +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	struct iface		*iface; +	struct iface_af		*ia; +	int			 af; +	char			*ep; +	long int		 secs; +	enum hello_type		 hello_type; +	const char		*seconds_str; +	const char		*hello_type_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	seconds_str = vty_get_arg_value(args, "seconds"); +	hello_type_str = vty_get_arg_value(args, "hello_type"); + +	secs = strtol(seconds_str, &ep, 10); +	if (*ep != '\0' || secs < MIN_HELLO_INTERVAL || +	    secs > MAX_HELLO_INTERVAL) { +		vty_out(vty, "%% Invalid interval%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	if (hello_type_str[0] == 'h') +		hello_type = HELLO_LINK; +	else +		hello_type = HELLO_TARGETED; + +	vty_conf = ldp_dup_config(ldpd_conf); + +	switch (vty->node) { +	case LDP_NODE: +		if (disable) { +			switch (hello_type) { +			case HELLO_LINK: +				vty_conf->lhello_interval = LINK_DFLT_HOLDTIME; +				break; +			case HELLO_TARGETED: +				vty_conf->thello_interval = +				    TARGETED_DFLT_HOLDTIME; +				break; +			} +		} else { +			switch (hello_type) { +			case HELLO_LINK: +				vty_conf->lhello_interval = secs; +				break; +			case HELLO_TARGETED: +				vty_conf->thello_interval = secs; +				break; +			} +		} +		break; +	case LDP_IPV4_NODE: +	case LDP_IPV6_NODE: +		af = ldp_vty_get_af(vty); +		af_conf = ldp_af_conf_get(vty_conf, af); + +		if (disable) { +			switch (hello_type) { +			case HELLO_LINK: +				af_conf->lhello_interval = 0; +				break; +			case HELLO_TARGETED: +				af_conf->thello_interval = 0; +				break; +			} +		} else { +			switch (hello_type) { +			case HELLO_LINK: +				af_conf->lhello_interval = secs; +				break; +			case HELLO_TARGETED: +				af_conf->thello_interval = secs; +				break; +			} +		} +		break; +	case LDP_IPV4_IFACE_NODE: +	case LDP_IPV6_IFACE_NODE: +		af = ldp_vty_get_af(vty); +		iface = if_lookup_name(vty_conf, vty_ifname); +		ia = iface_af_get(iface, af); + +		if (disable) +			ia->hello_interval = 0; +		else +			ia->hello_interval = secs; +		break; +	default: +		fatalx("ldp_vty_disc_interval: unexpected node"); +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_targeted_hello_accept(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	int			 af; +	int			 disable; + +	vty_conf = ldp_dup_config(ldpd_conf); + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	af = ldp_vty_get_af(vty); +	af_conf = ldp_af_conf_get(vty_conf, af); + +	if (disable) +		af_conf->flags &= ~F_LDPD_AF_THELLO_ACCEPT; +	else +		af_conf->flags |= F_LDPD_AF_THELLO_ACCEPT; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +static int +ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	char			*ep; +	long int		 secs; +	struct in_addr		 lsr_id; +	struct nbr_params	*nbrp; +	const char		*seconds_str; +	const char		*lsr_id_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	seconds_str = vty_get_arg_value(args, "seconds"); +	lsr_id_str = vty_get_arg_value(args, "lsr_id"); + +	if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || +	    bad_addr_v4(lsr_id)) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	nbrp = nbr_params_find(vty_conf, lsr_id); + +	secs = strtol(seconds_str, &ep, 10); +	if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) { +		vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE); +		goto cancel; +	} + +	if (disable) { +		if (nbrp == NULL) +			goto cancel; + +		nbrp->keepalive = 0; +		nbrp->flags &= ~F_NBRP_KEEPALIVE; +	} else { +		if (nbrp == NULL) { +			nbrp = nbr_params_new(lsr_id); +			LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry); +		} else if (nbrp->keepalive == secs) +			goto cancel; + +		nbrp->keepalive = secs; +		nbrp->flags |= F_NBRP_KEEPALIVE; +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +static int +ldp_vty_af_session_holdtime(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	int			 af; +	char			*ep; +	long int		 secs; +	const char		*seconds_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	seconds_str = vty_get_arg_value(args, "seconds"); + +	secs = strtol(seconds_str, &ep, 10); +	if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) { +		vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE); +		return (CMD_SUCCESS); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	af = ldp_vty_get_af(vty); +	af_conf = ldp_af_conf_get(vty_conf, af); + +	if (disable) +		af_conf->keepalive = DEFAULT_KEEPALIVE; +	else +		af_conf->keepalive = secs; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_session_holdtime(struct vty *vty, struct vty_arg *args[]) +{ +	switch (vty->node) { +	case LDP_NODE: +		return (ldp_vty_nbr_session_holdtime(vty, args)); +	case LDP_IPV4_NODE: +	case LDP_IPV6_NODE: +		return (ldp_vty_af_session_holdtime(vty, args)); +	default: +		fatalx("ldp_vty_session_holdtime: unexpected node"); +	} +} + +int +ldp_vty_interface(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	int			 af; +	struct iface		*iface; +	struct iface_af		*ia; +	struct interface	*ifp; +	struct kif		 kif; +	const char		*ifname; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	ifname = vty_get_arg_value(args, "ifname"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	af = ldp_vty_get_af(vty); +	iface = if_lookup_name(vty_conf, ifname); + +	if (disable) { +		if (iface == NULL) +			goto cancel; + +		ia = iface_af_get(iface, af); +		if (ia->enabled == 0) +			goto cancel; + +		ia->enabled = 0; +		ldp_reload(vty_conf); +		return (CMD_SUCCESS); +	} + +	switch (af) { +	case AF_INET: +		vty->node = LDP_IPV4_IFACE_NODE; +		break; +	case AF_INET6: +		vty->node = LDP_IPV6_IFACE_NODE; +		break; +	default: +		break; +	} +	strlcpy(vty_ifname, ifname, sizeof(vty_ifname)); + +	if (iface == NULL) { +		if (ldp_iface_is_configured(vty_conf, ifname)) { +			vty_out(vty, "%% Interface is already in use%s", +			    VTY_NEWLINE); +			goto cancel; +		} + +		ifp = if_lookup_by_name(ifname); +		memset(&kif, 0, sizeof(kif)); +		strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); +		if (ifp) { +			kif.ifindex = ifp->ifindex; +			kif.flags = ifp->flags; +		} +		iface = if_new(&kif); + +		ia = iface_af_get(iface, af); +		ia->enabled = 1; +		LIST_INSERT_HEAD(&vty_conf->iface_list, iface, entry); +	} else { +		memset(&kif, 0, sizeof(kif)); +		strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); + +		ia = iface_af_get(iface, af); +		if (ia->enabled) +			goto cancel; +		ia->enabled = 1; +	} + +	ldp_reload(vty_conf); +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_trans_addr(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	int			 af; +	const char		*addr_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	addr_str = vty_get_arg_value(args, "addr"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	af = ldp_vty_get_af(vty); +	af_conf = ldp_af_conf_get(vty_conf, af); + +	if (disable) +		memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr)); +	else { +		if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 || +		    bad_addr(af, &af_conf->trans_addr)) { +			vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +			goto cancel; +		} +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	int			 af; +	union ldpd_addr		 addr; +	struct tnbr		*tnbr; +	const char		*addr_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	addr_str = vty_get_arg_value(args, "addr"); + +	af = ldp_vty_get_af(vty); + +	if (inet_pton(af, addr_str, &addr) != 1 || +	    bad_addr(af, &addr)) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} +	if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&addr.v6)) { +		vty_out(vty, "%% Address can not be link-local%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	tnbr = tnbr_find(vty_conf, af, &addr); + +	if (disable) { +		if (tnbr == NULL) +			goto cancel; + +		LIST_REMOVE(tnbr, entry); +		free(tnbr); +		ldp_reload(vty_conf); +		return (CMD_SUCCESS); +	} + +	if (tnbr) +		goto cancel; + +	tnbr = tnbr_new(af, &addr); +	tnbr->flags |= F_TNBR_CONFIGURED; +	LIST_INSERT_HEAD(&vty_conf->tnbr_list, tnbr, entry); + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_explicit_null(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	int			 af; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	vty_conf = ldp_dup_config(ldpd_conf); +	af = ldp_vty_get_af(vty); +	af_conf = ldp_af_conf_get(vty_conf, af); + +	if (disable) +		af_conf->flags &= ~F_LDPD_AF_EXPNULL; +	else +		af_conf->flags |= F_LDPD_AF_EXPNULL; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_ttl_security(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct ldpd_af_conf	*af_conf; +	int			 af; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	vty_conf = ldp_dup_config(ldpd_conf); +	af = ldp_vty_get_af(vty); +	af_conf = ldp_af_conf_get(vty_conf, af); + +	if (disable) +		af_conf->flags &= ~F_LDPD_AF_NO_GTSM; +	else +		af_conf->flags |= F_LDPD_AF_NO_GTSM; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_router_id(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	const char		*addr_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	addr_str = vty_get_arg_value(args, "addr"); + +	vty_conf = ldp_dup_config(ldpd_conf); + +	if (disable) +		vty_conf->rtr_id.s_addr = INADDR_ANY; +	else { +		if (inet_pton(AF_INET, addr_str, &vty_conf->rtr_id) != 1 || +		    bad_addr_v4(vty_conf->rtr_id)) { +			vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +			goto cancel; +		} +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_ds_cisco_interop(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	vty_conf = ldp_dup_config(ldpd_conf); + +	if (disable) +		vty_conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; +	else +		vty_conf->flags |= F_LDPD_DS_CISCO_INTEROP; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_trans_pref_ipv4(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	vty_conf = ldp_dup_config(ldpd_conf); + +	if (disable) +		vty_conf->trans_pref = DUAL_STACK_LDPOV6; +	else +		vty_conf->trans_pref = DUAL_STACK_LDPOV4; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct in_addr		 lsr_id; +	size_t			 password_len; +	struct nbr_params	*nbrp; +	const char		*lsr_id_str; +	const char		*password_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	lsr_id_str = vty_get_arg_value(args, "lsr_id"); +	password_str = vty_get_arg_value(args, "password"); + +	if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || +	    bad_addr_v4(lsr_id)) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	nbrp = nbr_params_find(vty_conf, lsr_id); + +	if (disable) { +		if (nbrp == NULL) +			goto cancel; + +		memset(&nbrp->auth, 0, sizeof(nbrp->auth)); +		nbrp->auth.method = AUTH_NONE; +	} else { +		if (nbrp == NULL) { +			nbrp = nbr_params_new(lsr_id); +			LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry); +		} else if (nbrp->auth.method == AUTH_MD5SIG && +		    strcmp(nbrp->auth.md5key, password_str) == 0) +			goto cancel; + +		password_len = strlcpy(nbrp->auth.md5key, password_str, +		    sizeof(nbrp->auth.md5key)); +		if (password_len >= sizeof(nbrp->auth.md5key)) +			vty_out(vty, "%% password has been truncated to %zu " +			    "characters.", sizeof(nbrp->auth.md5key) - 1); +		nbrp->auth.md5key_len = password_len; +		nbrp->auth.method = AUTH_MD5SIG; +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct in_addr		 lsr_id; +	struct nbr_params	*nbrp; +	long int		 hops = 0; +	char			*ep; +	const char		*lsr_id_str; +	const char		*hops_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	lsr_id_str = vty_get_arg_value(args, "lsr_id"); +	hops_str = vty_get_arg_value(args, "hops"); + +	if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || +	    bad_addr_v4(lsr_id)) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	if (hops_str) { +		hops = strtol(hops_str, &ep, 10); +		if (*ep != '\0' || hops < 1 || hops > 254) { +			vty_out(vty, "%% Invalid hop count%s", VTY_NEWLINE); +			return (CMD_SUCCESS); +		} +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	nbrp = nbr_params_find(vty_conf, lsr_id); + +	if (disable) { +		if (nbrp == NULL) +			goto cancel; + +		nbrp->flags &= ~(F_NBRP_GTSM|F_NBRP_GTSM_HOPS); +		nbrp->gtsm_enabled = 0; +		nbrp->gtsm_hops = 0; +	} else { +		if (nbrp == NULL) { +			nbrp = nbr_params_new(lsr_id); +			LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry); +		} + +		nbrp->flags |= F_NBRP_GTSM; +		nbrp->flags &= ~F_NBRP_GTSM_HOPS; +		if (hops_str) { +			nbrp->gtsm_enabled = 1; +			nbrp->gtsm_hops = hops; +			nbrp->flags |= F_NBRP_GTSM_HOPS; +		} else +			nbrp->gtsm_enabled = 0; +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	const char		*name_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	name_str = vty_get_arg_value(args, "name"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, name_str); + +	if (disable) { +		if (l2vpn == NULL) +			goto cancel; + +		LIST_REMOVE(l2vpn, entry); +		l2vpn_del(l2vpn); +		ldp_reload(vty_conf); +		return (CMD_SUCCESS); +	} + +	vty->node = LDP_L2VPN_NODE; +	strlcpy(vty_l2vpn_name, name_str, sizeof(vty_l2vpn_name)); +	if (l2vpn) +		goto cancel; + +	l2vpn = l2vpn_new(name_str); +	l2vpn->type = L2VPN_TYPE_VPLS; +	LIST_INSERT_HEAD(&vty_conf->l2vpn_list, l2vpn, entry); + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_bridge(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	const char		*ifname; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	ifname = vty_get_arg_value(args, "ifname"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + +	if (disable) +		memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname)); +	else +		strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname)); + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_mtu(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	char			*ep; +	int			 mtu; +	const char		*mtu_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	mtu_str = vty_get_arg_value(args, "mtu"); + +	mtu = strtol(mtu_str, &ep, 10); +	if (*ep != '\0' || mtu < MIN_L2VPN_MTU || mtu > MAX_L2VPN_MTU) { +		vty_out(vty, "%% Invalid MTU%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + +	if (disable) +		l2vpn->mtu = DEFAULT_L2VPN_MTU; +	else +		l2vpn->mtu = mtu; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pwtype(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	int			 pw_type; +	const char		*type_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	type_str = vty_get_arg_value(args, "type"); + +	if (strcmp(type_str, "ethernet") == 0) +		pw_type = PW_TYPE_ETHERNET; +	else +		pw_type = PW_TYPE_ETHERNET_TAGGED; + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + +	if (disable) +		l2vpn->pw_type = DEFAULT_PW_TYPE; +	else +		l2vpn->pw_type = pw_type; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_interface(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_if		*lif; +	struct interface	*ifp; +	struct kif		 kif; +	const char		*ifname; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	ifname = vty_get_arg_value(args, "ifname"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	lif = l2vpn_if_find_name(l2vpn, ifname); + +	if (disable) { +		if (lif == NULL) +			goto cancel; + +		LIST_REMOVE(lif, entry); +		free(lif); +		ldp_reload(vty_conf); +		return (CMD_SUCCESS); +	} + +	if (lif) +		goto cancel; + +	if (ldp_iface_is_configured(vty_conf, ifname)) { +		vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE); +		goto cancel; +	} + +	ifp = if_lookup_by_name(ifname); +	memset(&kif, 0, sizeof(kif)); +	strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); +	if (ifp) { +		kif.ifindex = ifp->ifindex; +		kif.flags = ifp->flags; +	} + +	lif = l2vpn_if_new(l2vpn, &kif); +	LIST_INSERT_HEAD(&l2vpn->if_list, lif, entry); + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pseudowire(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; +	struct interface	*ifp; +	struct kif		 kif; +	const char		*ifname; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	ifname = vty_get_arg_value(args, "ifname"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	pw = l2vpn_pw_find_name(l2vpn, ifname); + +	if (disable) { +		if (pw == NULL) +			goto cancel; + +		LIST_REMOVE(pw, entry); +		free(pw); +		ldp_reload(vty_conf); +		return (CMD_SUCCESS); +	} + +	if (pw) { +		vty->node = LDP_PSEUDOWIRE_NODE; +		strlcpy(vty_pw_ifname, ifname, sizeof(vty_pw_ifname)); +		goto cancel; +	} + +	if (ldp_iface_is_configured(vty_conf, ifname)) { +		vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE); +		goto cancel; +	} + +	ifp = if_lookup_by_name(ifname); +	memset(&kif, 0, sizeof(kif)); +	strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); +	if (ifp) { +		kif.ifindex = ifp->ifindex; +		kif.flags = ifp->flags; +	} + +	pw = l2vpn_pw_new(l2vpn, &kif); +	pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; +	LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, pw, entry); + +	ldp_reload(vty_conf); + +	vty->node = LDP_PSEUDOWIRE_NODE; +	strlcpy(vty_pw_ifname, ifname, sizeof(vty_pw_ifname)); +	return (CMD_SUCCESS); + +cancel: +	ldp_clear_config(vty_conf); +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_cword(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; +	const char		*preference_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	preference_str = vty_get_arg_value(args, "preference"); + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + +	if (disable) +		pw->flags |= F_PW_CWORD_CONF; +	else { +		if (preference_str[0] == 'e') +			pw->flags &= ~F_PW_CWORD_CONF; +		else +			pw->flags |= F_PW_CWORD_CONF; +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; +	int			 af; +	union ldpd_addr		 addr; +	const char		*addr_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	addr_str = vty_get_arg_value(args, "addr"); + +	if (ldp_get_address(addr_str, &af, &addr) == -1 || +	    bad_addr(af, &addr)) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + +	if (disable) { +		pw->af = AF_UNSPEC; +		memset(&pw->addr, 0, sizeof(pw->addr)); +		pw->flags &= ~F_PW_STATIC_NBR_ADDR; +	} else { +		pw->af = af; +		pw->addr = addr; +		pw->flags |= F_PW_STATIC_NBR_ADDR; +	} + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; +	struct in_addr		 lsr_id; +	const char		*lsr_id_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	lsr_id_str = vty_get_arg_value(args, "lsr-id"); + +	if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || +	    bad_addr_v4(lsr_id)) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + +	if (disable) +		pw->lsr_id.s_addr = INADDR_ANY; +	else +		pw->lsr_id = lsr_id; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_pwid(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; +	char			*ep; +	uint32_t		 pwid; +	const char		*pwid_str; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; +	pwid_str = vty_get_arg_value(args, "pwid"); + +	pwid = strtol(pwid_str, &ep, 10); +	if (*ep != '\0' || pwid < MIN_PWID_ID || pwid > MAX_PWID_ID) { +		vty_out(vty, "%% Invalid pw-id%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + +	if (disable) +		pw->pwid = 0; +	else +		pw->pwid = pwid; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_pwstatus(struct vty *vty, struct vty_arg *args[]) +{ +	struct ldpd_conf	*vty_conf; +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; +	int			 disable; + +	disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + +	vty_conf = ldp_dup_config(ldpd_conf); +	l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); +	pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + +	if (disable) +		pw->flags |= F_PW_STATUSTLV_CONF; +	else +		pw->flags &= ~F_PW_STATUSTLV_CONF; + +	ldp_reload(vty_conf); + +	return (CMD_SUCCESS); +} + +void +ldp_vty_if_init(void) +{ +	/* Install interface node. */ +	install_node (&interface_node, interface_config_write); + +	install_element(CONFIG_NODE, &interface_cmd); +	install_element(CONFIG_NODE, &no_interface_cmd); +	install_default(INTERFACE_NODE); + +	/* "description" commands. */ +	install_element(INTERFACE_NODE, &interface_desc_cmd); +	install_element(INTERFACE_NODE, &no_interface_desc_cmd); +} diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c new file mode 100644 index 0000000000..a57cf3c3f6 --- /dev/null +++ b/ldpd/ldp_vty_exec.c @@ -0,0 +1,667 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> +#include <sys/un.h> + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" +#include "log.h" +#include "ldp_vty.h" + +#include "command.h" +#include "vty.h" +#include "mpls.h" + +enum show_command { +	SHOW_DISC, +	SHOW_IFACE, +	SHOW_NBR, +	SHOW_LIB, +	SHOW_L2VPN_PW, +	SHOW_L2VPN_BINDING +}; + +struct show_filter { +	int		family; +	union ldpd_addr	addr; +	uint8_t		prefixlen; +}; + +#define LDPBUFSIZ	65535 + +static int		 show_interface_msg(struct vty *, struct imsg *, +			    struct show_filter *); +static void		 show_discovery_adj(struct vty *, char *, +			    struct ctl_adj *); +static int		 show_discovery_msg(struct vty *, struct imsg *, +			    struct show_filter *); +static void		 show_nbr_adj(struct vty *, char *, struct ctl_adj *); +static int		 show_nbr_msg(struct vty *, struct imsg *, +			    struct show_filter *); +static int		 show_lib_msg(struct vty *, struct imsg *, +			    struct show_filter *); +static int		 show_l2vpn_binding_msg(struct vty *, struct imsg *); +static int		 show_l2vpn_pw_msg(struct vty *, struct imsg *); +static int		 ldp_vty_connect(struct imsgbuf *); +static int		 ldp_vty_dispatch(struct vty *, struct imsgbuf *, +			    enum show_command, struct show_filter *); +static int		 ldp_vty_get_af(const char *, int *); + +static int +show_interface_msg(struct vty *vty, struct imsg *imsg, +    struct show_filter *filter) +{ +	struct ctl_iface	*iface; +	char			 timers[BUFSIZ]; + +	switch (imsg->hdr.type) { +	case IMSG_CTL_SHOW_INTERFACE: +		iface = imsg->data; + +		if (filter->family != AF_UNSPEC && filter->family != iface->af) +			break; + +		snprintf(timers, sizeof(timers), "%u/%u", +		    iface->hello_interval, iface->hello_holdtime); + +		vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3u%s", +		    af_name(iface->af), iface->name, +		    if_state_name(iface->state), iface->uptime == 0 ? +		    "00:00:00" : log_time(iface->uptime), timers, +		    iface->adj_cnt, VTY_NEWLINE); +		break; +	case IMSG_CTL_END: +		vty_out(vty, "%s", VTY_NEWLINE); +		return (1); +	default: +		break; +	} + +	return (0); +} + +static void +show_discovery_adj(struct vty *vty, char *buffer, struct ctl_adj *adj) +{ +	size_t	 buflen = strlen(buffer); + +	snprintf(buffer + buflen, LDPBUFSIZ - buflen, +	    "      LDP Id: %s:0, Transport address: %s%s", +	    inet_ntoa(adj->id), log_addr(adj->af, +	    &adj->trans_addr), VTY_NEWLINE); +	buflen = strlen(buffer); +	snprintf(buffer + buflen, LDPBUFSIZ - buflen, +	    "          Hold time: %u sec%s", adj->holdtime, VTY_NEWLINE); +} + +static int +show_discovery_msg(struct vty *vty, struct imsg *imsg, +    struct show_filter *filter) +{ +	struct ctl_adj		*adj; +	struct ctl_disc_if	*iface; +	struct ctl_disc_tnbr	*tnbr; +	struct in_addr		 rtr_id; +	union ldpd_addr		*trans_addr; +	size_t			 buflen; +	static char		 ifaces_buffer[LDPBUFSIZ]; +	static char		 tnbrs_buffer[LDPBUFSIZ]; + +	switch (imsg->hdr.type) { +	case IMSG_CTL_SHOW_DISCOVERY: +		ifaces_buffer[0] = '\0'; +		tnbrs_buffer[0] = '\0'; +		break; +	case IMSG_CTL_SHOW_DISC_IFACE: +		iface = imsg->data; + +		if (filter->family != AF_UNSPEC && +		    ((filter->family == AF_INET && !iface->active_v4) || +		    (filter->family == AF_INET6 && !iface->active_v6))) +			break; + +		buflen = strlen(ifaces_buffer); +		snprintf(ifaces_buffer + buflen, LDPBUFSIZ - buflen, +		     "    %s: %s%s", iface->name, (iface->no_adj) ? +		    "xmit" : "xmit/recv", VTY_NEWLINE); +		break; +	case IMSG_CTL_SHOW_DISC_TNBR: +		tnbr = imsg->data; + +		if (filter->family != AF_UNSPEC && filter->family != tnbr->af) +			break; + +		trans_addr = &(ldp_af_conf_get(ldpd_conf, +		    tnbr->af))->trans_addr; +		buflen = strlen(tnbrs_buffer); +		snprintf(tnbrs_buffer + buflen, LDPBUFSIZ - buflen, +		    "    %s -> %s: %s%s", log_addr(tnbr->af, trans_addr), +		    log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ? "xmit" : +		    "xmit/recv", VTY_NEWLINE); +		break; +	case IMSG_CTL_SHOW_DISC_ADJ: +		adj = imsg->data; + +		if (filter->family != AF_UNSPEC && filter->family != adj->af) +			break; + +		switch(adj->type) { +		case HELLO_LINK: +			show_discovery_adj(vty, ifaces_buffer, adj); +			break; +		case HELLO_TARGETED: +			show_discovery_adj(vty, tnbrs_buffer, adj); +			break; +		} +		break; +	case IMSG_CTL_END: +		rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); +		vty_out(vty, "Local LDP Identifier: %s:0%s", inet_ntoa(rtr_id), +		    VTY_NEWLINE); +		vty_out(vty, "Discovery Sources:%s", VTY_NEWLINE); +		vty_out(vty, "  Interfaces:%s", VTY_NEWLINE); +		vty_out(vty, "%s", ifaces_buffer); +		vty_out(vty, "  Targeted Hellos:%s", VTY_NEWLINE); +		vty_out(vty, "%s", tnbrs_buffer); +		vty_out(vty, "%s", VTY_NEWLINE); +		return (1); +	default: +		break; +	} + +	return (0); +} + +static void +show_nbr_adj(struct vty *vty, char *buffer, struct ctl_adj *adj) +{ +	size_t	 buflen = strlen(buffer); + +	switch (adj->type) { +	case HELLO_LINK: +		snprintf(buffer + buflen, LDPBUFSIZ - buflen, +		    "      Interface: %s%s", adj->ifname, VTY_NEWLINE); +		break; +	case HELLO_TARGETED: +		snprintf(buffer + buflen, LDPBUFSIZ - buflen, +		    "      Targeted Hello: %s%s", log_addr(adj->af, +		    &adj->src_addr), VTY_NEWLINE); +		break; +	} +} + +static int +show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter) +{ +	struct ctl_adj		*adj; +	struct ctl_nbr		*nbr; +	static char		 v4adjs_buffer[LDPBUFSIZ]; +	static char		 v6adjs_buffer[LDPBUFSIZ]; + +	switch (imsg->hdr.type) { +	case IMSG_CTL_SHOW_NBR: +		nbr = imsg->data; + +		v4adjs_buffer[0] = '\0'; +		v6adjs_buffer[0] = '\0'; +		vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id), +		    VTY_NEWLINE); +		vty_out(vty, "  TCP connection: %s:%u - %s:%u%s", +		    log_addr(nbr->af, &nbr->laddr), ntohs(nbr->lport), +		    log_addr(nbr->af, &nbr->raddr), ntohs(nbr->rport), +		    VTY_NEWLINE); +		vty_out(vty, "  Session Holdtime: %u sec%s", nbr->holdtime, +		    VTY_NEWLINE); +		vty_out(vty, "  State: %s; Downstream-Unsolicited%s", +		    nbr_state_name(nbr->nbr_state), VTY_NEWLINE); +		vty_out(vty, "  Up time: %s%s", log_time(nbr->uptime), +		    VTY_NEWLINE); +		break; +	case IMSG_CTL_SHOW_NBR_DISC: +		adj = imsg->data; + +		switch (adj->af) { +		case AF_INET: +			show_nbr_adj(vty, v4adjs_buffer, adj); +			break; +		case AF_INET6: +			show_nbr_adj(vty, v6adjs_buffer, adj); +			break; +		default: +			fatalx("show_nbr_msg: unknown af"); +		} +		break; +	case IMSG_CTL_SHOW_NBR_END: +		vty_out(vty, "  LDP Discovery Sources:%s", VTY_NEWLINE); +		if (v4adjs_buffer[0] != '\0') { +			vty_out(vty, "    IPv4:%s", VTY_NEWLINE); +			vty_out(vty, "%s", v4adjs_buffer); +		} +		if (v6adjs_buffer[0] != '\0') { +			vty_out(vty, "    IPv6:%s", VTY_NEWLINE); +			vty_out(vty, "%s", v6adjs_buffer); +		} +		vty_out(vty, "%s", VTY_NEWLINE); +		break; +	case IMSG_CTL_END: +		return (1); +	default: +		break; +	} + +	return (0); +} + +static int +show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter) +{ +	struct ctl_rt	*rt; +	char		 dstnet[BUFSIZ]; + +	switch (imsg->hdr.type) { +	case IMSG_CTL_SHOW_LIB: +		rt = imsg->data; + +		if (filter->family != AF_UNSPEC && filter->family != rt->af) +			break; + +		snprintf(dstnet, sizeof(dstnet), "%s/%d", +		    log_addr(rt->af, &rt->prefix), rt->prefixlen); + +		if (rt->first) { +			vty_out(vty, "%s%s", dstnet, VTY_NEWLINE); +			vty_out(vty, "%-8sLocal binding: label: %s%s", "", +			    log_label(rt->local_label), VTY_NEWLINE); + +			if (rt->remote_label != NO_LABEL) { +				vty_out(vty, "%-8sRemote bindings:%s", "", +				    VTY_NEWLINE); +				vty_out(vty, "%-12sPeer                Label%s", +				    "", VTY_NEWLINE); +				vty_out(vty, "%-12s-----------------   " +				    "---------%s", "", VTY_NEWLINE); +			} else +				vty_out(vty, "%-8sNo remote bindings%s", "", +				    VTY_NEWLINE); +		} +		if (rt->remote_label != NO_LABEL) +			vty_out(vty, "%12s%-20s%s%s", "", inet_ntoa(rt->nexthop), +			    log_label(rt->remote_label), VTY_NEWLINE); +		break; +	case IMSG_CTL_END: +		vty_out(vty, "%s", VTY_NEWLINE); +		return (1); +	default: +		break; +	} + +	return (0); +} + +static int +show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg) +{ +	struct ctl_pw	*pw; + +	switch (imsg->hdr.type) { +	case IMSG_CTL_SHOW_L2VPN_BINDING: +		pw = imsg->data; + +		vty_out(vty, "  Destination Address: %s, VC ID: %u%s", +		    inet_ntoa(pw->lsr_id), pw->pwid, VTY_NEWLINE); + +		/* local binding */ +		if (pw->local_label != NO_LABEL) { +			vty_out(vty, "    Local Label:  %u%s", pw->local_label, +			    VTY_NEWLINE); +			vty_out(vty, "%-8sCbit: %u,    VC Type: %s,    " +			    "GroupID: %u%s", "", pw->local_cword, +			    pw_type_name(pw->type), pw->local_gid, +			    VTY_NEWLINE); +			vty_out(vty, "%-8sMTU: %u%s", "", pw->local_ifmtu, +			    VTY_NEWLINE); +		} else +			vty_out(vty, "    Local Label: unassigned%s", +			    VTY_NEWLINE); + +		/* remote binding */ +		if (pw->remote_label != NO_LABEL) { +			vty_out(vty, "    Remote Label: %u%s", +			    pw->remote_label,  VTY_NEWLINE); +			vty_out(vty, "%-8sCbit: %u,    VC Type: %s,    " +			    "GroupID: %u%s", "", pw->remote_cword, +			    pw_type_name(pw->type), pw->remote_gid, +			    VTY_NEWLINE); +			vty_out(vty, "%-8sMTU: %u%s", "", pw->remote_ifmtu, +			    VTY_NEWLINE); +		} else +			vty_out(vty, "    Remote Label: unassigned%s", +			    VTY_NEWLINE); +		break; +	case IMSG_CTL_END: +		vty_out(vty, "%s", VTY_NEWLINE); +		return (1); +	default: +		break; +	} + +	return (0); +} + +static int +show_l2vpn_pw_msg(struct vty *vty, struct imsg *imsg) +{ +	struct ctl_pw	*pw; + +	switch (imsg->hdr.type) { +	case IMSG_CTL_SHOW_L2VPN_PW: +		pw = imsg->data; + +		vty_out(vty, "%-9s %-15s %-10u %-16s %-10s%s", pw->ifname, +		    inet_ntoa(pw->lsr_id), pw->pwid, pw->l2vpn_name, +		    (pw->status ? "UP" : "DOWN"), VTY_NEWLINE); +		break; +	case IMSG_CTL_END: +		vty_out(vty, "%s", VTY_NEWLINE); +		return (1); +	default: +		break; +	} + +	return (0); +} + +static int +ldp_vty_connect(struct imsgbuf *ibuf) +{ +	struct sockaddr_un	 s_un; +	int			 ctl_sock; + +	/* connect to ldpd control socket */ +	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { +		log_warn("%s: socket", __func__); +		return (-1); +	} + +	memset(&s_un, 0, sizeof(s_un)); +	s_un.sun_family = AF_UNIX; +	strlcpy(s_un.sun_path, LDPD_SOCKET, sizeof(s_un.sun_path)); +	if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { +		log_warn("%s: connect: %s", __func__, LDPD_SOCKET); +		close(ctl_sock); +		return (-1); +	} + +	imsg_init(ibuf, ctl_sock); + +	return (0); +} + +static int +ldp_vty_dispatch(struct vty *vty, struct imsgbuf *ibuf, enum show_command cmd, +    struct show_filter *filter) +{ +	struct imsg		 imsg; +	int			 n, done = 0; + +	while (ibuf->w.queued) +		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) { +			log_warn("write error"); +			close(ibuf->fd); +			return (CMD_WARNING); +		} + +	while (!done) { +		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) { +			log_warnx("imsg_read error"); +			close(ibuf->fd); +			return (CMD_WARNING); +		} +		if (n == 0) { +			log_warnx("pipe closed"); +			close(ibuf->fd); +			return (CMD_WARNING); +		} + +		while (!done) { +			if ((n = imsg_get(ibuf, &imsg)) == -1) { +				log_warnx("imsg_get error"); +				close(ibuf->fd); +				return (CMD_WARNING); +			} +			if (n == 0) +				break; +			switch (cmd) { +			case SHOW_IFACE: +				done = show_interface_msg(vty, &imsg, filter); +				break; +			case SHOW_DISC: +				done = show_discovery_msg(vty, &imsg, filter); +				break; +			case SHOW_NBR: +				done = show_nbr_msg(vty, &imsg, filter); +				break; +			case SHOW_LIB: +				done = show_lib_msg(vty, &imsg, filter); +				break; +			case SHOW_L2VPN_PW: +				done = show_l2vpn_pw_msg(vty, &imsg); +				break; +			case SHOW_L2VPN_BINDING: +				done = show_l2vpn_binding_msg(vty, &imsg); +				break; +			default: +				break; +			} +			imsg_free(&imsg); +		} +	} + +	close(ibuf->fd); + +	return (CMD_SUCCESS); +} + +static int +ldp_vty_get_af(const char *str, int *af) +{ +	if (str == NULL) { +		*af = AF_UNSPEC; +		return (0); +	} else if (strcmp(str, "ipv4") == 0) { +		*af = AF_INET; +		return (0); +	} else if (strcmp(str, "ipv6") == 0) { +		*af = AF_INET6; +		return (0); +	} + +	return (-1); +} + +int +ldp_vty_show_binding(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	struct show_filter	 filter; +	const char		*af_str; +	int			 af; + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0); + +	af_str = vty_get_arg_value(args, "address-family"); +	if (ldp_vty_get_af(af_str, &af) < 0) +		return (CMD_ERR_NO_MATCH); + +	memset(&filter, 0, sizeof(filter)); +	filter.family = af; + +	return (ldp_vty_dispatch(vty, &ibuf, SHOW_LIB, &filter)); +} + +int +ldp_vty_show_discovery(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	struct show_filter	 filter; +	const char		*af_str; +	int			 af; + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0); + +	af_str = vty_get_arg_value(args, "address-family"); +	if (ldp_vty_get_af(af_str, &af) < 0) +		return (CMD_ERR_NO_MATCH); + +	memset(&filter, 0, sizeof(filter)); +	filter.family = af; + +	return (ldp_vty_dispatch(vty, &ibuf, SHOW_DISC, &filter)); +} + +int +ldp_vty_show_interface(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	struct show_filter	 filter; +	unsigned int		 ifidx = 0; +	const char		*af_str; +	int			 af; + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, &ifidx, +	    sizeof(ifidx)); + +	af_str = vty_get_arg_value(args, "address-family"); +	if (ldp_vty_get_af(af_str, &af) < 0) +		return (CMD_ERR_NO_MATCH); + +	memset(&filter, 0, sizeof(filter)); +	filter.family = af; + +	/* header */ +	vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3s%s", "AF", +	    "Interface", "State", "Uptime", "Hello Timers", "ac", VTY_NEWLINE); + +	return (ldp_vty_dispatch(vty, &ibuf, SHOW_IFACE, &filter)); +} + +int +ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	struct show_filter	 filter; + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); + +	/* not used */ +	memset(&filter, 0, sizeof(filter)); + +	return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, &filter)); +} + +int +ldp_vty_show_atom_binding(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	struct show_filter	 filter; + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1, NULL, 0); + +	/* not used */ +	memset(&filter, 0, sizeof(filter)); + +	return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_BINDING, &filter)); +} + +int +ldp_vty_show_atom_vc(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	struct show_filter	 filter; + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0); + +	/* not used */ +	memset(&filter, 0, sizeof(filter)); + +	/* header */ +	vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s", +	    "Interface", "Peer ID", "VC ID", "Name", "Status", VTY_NEWLINE); +	vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s", +	    "---------", "---------------", "----------", +	    "----------------", "----------", VTY_NEWLINE); + +	return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_PW, &filter)); +} + +int +ldp_vty_clear_nbr(struct vty *vty, struct vty_arg *args[]) +{ +	struct imsgbuf		 ibuf; +	const char		*addr_str; +	struct ctl_nbr		 nbr; + +	addr_str = vty_get_arg_value(args, "addr"); + +	memset(&nbr, 0, sizeof(nbr)); +	if (addr_str && +	    (ldp_get_address(addr_str, &nbr.af, &nbr.raddr) == -1 || +	    bad_addr(nbr.af, &nbr.raddr))) { +		vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); +		return (CMD_WARNING); +	} + +	if (ldp_vty_connect(&ibuf) < 0) +		return (CMD_WARNING); + +	imsg_compose(&ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, sizeof(nbr)); + +	while (ibuf.w.queued) +		if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) { +			log_warn("write error"); +			close(ibuf.fd); +			return (CMD_WARNING); +		} + +	close(ibuf.fd); + +	return (CMD_SUCCESS); +} diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c new file mode 100644 index 0000000000..41ff47fba3 --- /dev/null +++ b/ldpd/ldp_zebra.c @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING.  If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "prefix.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "command.h" +#include "network.h" +#include "linklist.h" + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" +#include "log.h" +#include "ldp_debug.h" + +static void	 ifp2kif(struct interface *, struct kif *); +static void	 ifc2kaddr(struct interface *, struct connected *, +		    struct kaddr *); +static int	 ldp_router_id_update(int, struct zclient *, zebra_size_t, +		    vrf_id_t); +static int	 ldp_interface_add(int, struct zclient *, zebra_size_t, +		    vrf_id_t); +static int	 ldp_interface_delete(int, struct zclient *, zebra_size_t, +		    vrf_id_t); +static int	 ldp_interface_status_change(int command, struct zclient *, +		    zebra_size_t, vrf_id_t); +static int	 ldp_interface_address_add(int, struct zclient *, zebra_size_t, +		    vrf_id_t); +static int	 ldp_interface_address_delete(int, struct zclient *, +		    zebra_size_t, vrf_id_t); +static int	 ldp_zebra_read_route(int, struct zclient *, zebra_size_t, +		    vrf_id_t); +static void	 ldp_zebra_connected(struct zclient *); + +static struct zclient	*zclient; + +static void +ifp2kif(struct interface *ifp, struct kif *kif) +{ +	memset(kif, 0, sizeof(*kif)); +	strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname)); +	kif->ifindex = ifp->ifindex; +	kif->flags = ifp->flags; +} + +static void +ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) +{ +	memset(ka, 0, sizeof(*ka)); +	ka->ifindex = ifp->ifindex; +	ka->af = ifc->address->family; +	ka->prefixlen = ifc->address->prefixlen; + +	switch (ka->af) { +	case AF_INET: +		ka->addr.v4 = ifc->address->u.prefix4; +		if (ifc->destination) +			ka->dstbrd.v4 = ifc->destination->u.prefix4; +		break; +	case AF_INET6: +		ka->addr.v6 = ifc->address->u.prefix6; +		if (ifc->destination) +			ka->dstbrd.v6 = ifc->destination->u.prefix6; +		break; +	default: +		break; +	} +} + +int +kr_change(struct kroute *kr) +{ +	/* TODO */ +	return (0); +} + +int +kr_delete(struct kroute *kr) +{ +	/* TODO */ +	return (0); +} + +int +kmpw_set(struct kpw *kpw) +{ +	/* TODO */ +	return (0); +} + +int +kmpw_unset(struct kpw *kpw) +{ +	/* TODO */ +	return (0); +} + +void +kif_redistribute(const char *ifname) +{ +	struct listnode		*node, *cnode; +	struct interface	*ifp; +	struct connected	*ifc; +	struct kif		 kif; +	struct kaddr		 ka; + +	for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { +		if (ifname && strcmp(ifname, ifp->name) != 0) +			continue; + +		ifp2kif(ifp, &kif); +		main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif)); + +		for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { +			ifc2kaddr(ifp, ifc, &ka); +			main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, +			    sizeof(ka)); +		} +	} +} + +static int +ldp_router_id_update(int command, struct zclient *zclient, zebra_size_t length, +    vrf_id_t vrf_id) +{ +	struct prefix	 router_id; + +	zebra_router_id_update_read(zclient->ibuf, &router_id); + +	if (bad_addr_v4(router_id.u.prefix4)) +		return (0); + +	debug_zebra_in("router-id update %s", inet_ntoa(router_id.u.prefix4)); + +	global.rtr_id.s_addr = router_id.u.prefix4.s_addr; +	main_imsg_compose_ldpe(IMSG_RTRID_UPDATE, 0, &global.rtr_id, +	    sizeof(global.rtr_id)); + +	return (0); +} + +static int +ldp_interface_add(int command, struct zclient *zclient, zebra_size_t length, +    vrf_id_t vrf_id) +{ +	struct interface	*ifp; +	struct kif		 kif; + +	ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); +	debug_zebra_in("interface add %s index %d mtu %d", ifp->name, +	    ifp->ifindex, ifp->mtu); + +	ifp2kif(ifp, &kif); +	main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif)); + +	return (0); +} + +static int +ldp_interface_delete(int command, struct zclient *zclient, zebra_size_t length, +    vrf_id_t vrf_id) +{ +	struct interface	*ifp; + +	/* zebra_interface_state_read() updates interface structure in iflist */ +	ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); +	if (ifp == NULL) +		return (0); + +	debug_zebra_in("interface delete %s index %d mtu %d", ifp->name, +	    ifp->ifindex, ifp->mtu); + +	/* To support pseudo interface do not free interface structure.  */ +	/* if_delete(ifp); */ +	ifp->ifindex = IFINDEX_INTERNAL; + +	return (0); +} + +static int +ldp_interface_status_change(int command, struct zclient *zclient, +    zebra_size_t length, vrf_id_t vrf_id) +{ +	struct interface	*ifp; +	struct listnode		*node; +	struct connected	*ifc; +	struct kif		 kif; +	struct kaddr		 ka; +	int			 link_new; + +	/* +	 * zebra_interface_state_read() updates interface structure in +	 * iflist. +	 */ +	ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); +	if (ifp == NULL) +		return (0); + +	debug_zebra_in("interface %s state update", ifp->name); + +	ifp2kif(ifp, &kif); +	main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif)); + +	link_new = (ifp->flags & IFF_UP) && (ifp->flags & IFF_RUNNING); +	if (link_new) { +		for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { +			ifc2kaddr(ifp, ifc, &ka); +			main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, +			    sizeof(ka)); +		} +	} else { +		for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { +			ifc2kaddr(ifp, ifc, &ka); +			main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, +			    sizeof(ka)); +		} +	} + +	return (0); +} + +static int +ldp_interface_address_add(int command, struct zclient *zclient, +    zebra_size_t length, vrf_id_t vrf_id) +{ +	struct connected	*ifc; +	struct interface	*ifp; +	struct kaddr		 ka; + +	ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id); +	if (ifc == NULL) +		return (0); + +	ifp = ifc->ifp; +	ifc2kaddr(ifp, ifc, &ka); + +	/* Filter invalid addresses.  */ +	if (bad_addr(ka.af, &ka.addr)) +		return (0); + +	debug_zebra_in("address add %s/%u", log_addr(ka.af, &ka.addr), +	    ka.prefixlen); + +	/* notify ldpe about new address */ +	main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka)); + +	return (0); +} + +static int +ldp_interface_address_delete(int command, struct zclient *zclient, +    zebra_size_t length, vrf_id_t vrf_id) +{ +	struct connected	*ifc; +	struct interface	*ifp; +	struct kaddr		 ka; + +	ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id); +	if (ifc == NULL) +		return (0); + +	ifp = ifc->ifp; +	ifc2kaddr(ifp, ifc, &ka); +	connected_free(ifc); + +	/* Filter invalid addresses.  */ +	if (bad_addr(ka.af, &ka.addr)) +		return (0); + +	debug_zebra_in("address delete %s/%u", log_addr(ka.af, &ka.addr), +	    ka.prefixlen); + +	/* notify ldpe about removed address */ +	main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka)); + +	return (0); +} + +static int +ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, +    vrf_id_t vrf_id) +{ +	struct stream		*s; +	u_char			 type; +	u_char			 message_flags; +	struct kroute		 kr; +	int			 nhnum, nhlen; +	size_t			 nhmark; + +	memset(&kr, 0, sizeof(kr)); +	s = zclient->ibuf; + +	type = stream_getc(s); +	if (type == ZEBRA_ROUTE_CONNECT) +		kr.flags |= F_CONNECTED; +	stream_getc(s); /* flags, unused */ +	stream_getw(s); /* instance, unused */ +	message_flags = stream_getc(s); +	if (!CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) +		return (0); + +	switch (command) { +	case ZEBRA_IPV4_ROUTE_ADD: +	case ZEBRA_REDISTRIBUTE_IPV4_ADD: +	case ZEBRA_IPV4_ROUTE_DELETE: +	case ZEBRA_REDISTRIBUTE_IPV4_DEL: +		kr.af = AF_INET; +		nhlen = sizeof(struct in_addr); +		break; +	case ZEBRA_IPV6_ROUTE_ADD: +	case ZEBRA_REDISTRIBUTE_IPV6_ADD: +	case ZEBRA_IPV6_ROUTE_DELETE: +	case ZEBRA_REDISTRIBUTE_IPV6_DEL: +		kr.af = AF_INET6; +		nhlen = sizeof(struct in6_addr); +		break; +	default: +		fatalx("ldp_zebra_read_route: unknown command"); +	} +	kr.prefixlen = stream_getc(s); +	stream_get(&kr.prefix, s, PSIZE(kr.prefixlen)); + +	if (bad_addr(kr.af, &kr.prefix) || +	    (kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6))) +		return (0); + +	nhnum = stream_getc(s); +	nhmark = stream_get_getp(s); +	stream_set_getp(s, nhmark + nhnum * (nhlen + 5)); + +	if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE)) +		kr.priority = stream_getc(s); +	if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC)) +		stream_getl(s);	/* metric, not used */ + +	stream_set_getp(s, nhmark); + +	/* loop through all the nexthops */ +	for (; nhnum > 0; nhnum--) { +		switch (kr.af) { +		case AF_INET: +			kr.nexthop.v4.s_addr = stream_get_ipv4(s); +			break; +		case AF_INET6: +			stream_get(&kr.nexthop.v6, s, sizeof(kr.nexthop.v6)); +			break; +		default: +			break; +		} +		stream_getc(s);	/* ifindex_num, unused. */ +		kr.ifindex = stream_getl(s); + +		switch (command) { +		case ZEBRA_IPV4_ROUTE_ADD: +		case ZEBRA_REDISTRIBUTE_IPV4_ADD: +		case ZEBRA_IPV6_ROUTE_ADD: +		case ZEBRA_REDISTRIBUTE_IPV6_ADD: +			debug_zebra_in("route add %s/%d nexthop %s (%s)", +			    log_addr(kr.af, &kr.prefix), kr.prefixlen, +			    log_addr(kr.af, &kr.nexthop), +			    zebra_route_string(type)); +			main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr, +			    sizeof(kr)); +			break; +		case ZEBRA_IPV4_ROUTE_DELETE: +		case ZEBRA_REDISTRIBUTE_IPV4_DEL: +		case ZEBRA_IPV6_ROUTE_DELETE: +		case ZEBRA_REDISTRIBUTE_IPV6_DEL: +			debug_zebra_in("route delete %s/%d nexthop %s (%s)", +			    log_addr(kr.af, &kr.prefix), kr.prefixlen, +			    log_addr(kr.af, &kr.nexthop), +			    zebra_route_string(type)); +			main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, &kr, +			    sizeof(kr)); +			break; +		default: +			fatalx("ldp_zebra_read_route: unknown command"); +		} +	} + +	return (0); +} + +static void +ldp_zebra_connected(struct zclient *zclient) +{ +	int	i; + +	zclient_send_reg_requests(zclient, VRF_DEFAULT); + +	for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { +		switch (i) { +		case ZEBRA_ROUTE_KERNEL: +		case ZEBRA_ROUTE_CONNECT: +		case ZEBRA_ROUTE_STATIC: +		case ZEBRA_ROUTE_ISIS: +			zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, +			    AFI_IP, i, 0, VRF_DEFAULT); +			zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, +			    AFI_IP6, i, 0, VRF_DEFAULT); +			break; +		case ZEBRA_ROUTE_RIP: +		case ZEBRA_ROUTE_OSPF: +			zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, +			    AFI_IP, i, 0, VRF_DEFAULT); +			break; +		case ZEBRA_ROUTE_RIPNG: +		case ZEBRA_ROUTE_OSPF6: +			zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, +			    AFI_IP6, i, 0, VRF_DEFAULT); +			break; +		case ZEBRA_ROUTE_BGP: +			/* LDP should follow the IGP and ignore BGP routes */ +		default: +			break; +		} +	} +} + +void +ldp_zebra_init(struct thread_master *master) +{ +	/* Set default values. */ +	zclient = zclient_new(master); +	zclient_init(zclient, ZEBRA_ROUTE_LDP, 0); + +	/* set callbacks */ +	zclient->zebra_connected = ldp_zebra_connected; +	zclient->router_id_update = ldp_router_id_update; +	zclient->interface_add = ldp_interface_add; +	zclient->interface_delete = ldp_interface_delete; +	zclient->interface_up = ldp_interface_status_change; +	zclient->interface_down = ldp_interface_status_change; +	zclient->interface_address_add = ldp_interface_address_add; +	zclient->interface_address_delete = ldp_interface_address_delete; +	zclient->ipv4_route_add = ldp_zebra_read_route; +	zclient->ipv4_route_delete = ldp_zebra_read_route; +	zclient->redistribute_route_ipv4_add = ldp_zebra_read_route; +	zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; +	zclient->ipv6_route_add = ldp_zebra_read_route; +	zclient->ipv6_route_delete = ldp_zebra_read_route; +	zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; +	zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; +} diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 4e14491989..1eaa7df4a5 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -19,36 +19,40 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> +#include <zebra.h>  #include <sys/wait.h> -#include <err.h> -#include <errno.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <unistd.h>  #include "ldpd.h"  #include "ldpe.h"  #include "lde.h"  #include "log.h" - -static void		 main_sig_handler(int, short, void *); -static __dead void	 usage(void); -static __dead void	 ldpd_shutdown(void); -static pid_t		 start_child(enum ldpd_process, char *, int, int, int); -static void		 main_dispatch_ldpe(int, short, void *); -static void		 main_dispatch_lde(int, short, void *); -static int		 main_imsg_compose_both(enum imsg_type, void *, -			    uint16_t); +#include "ldp_vty.h" +#include "ldp_debug.h" + +#include <lib/version.h> +#include <lib/log.h> +#include "getopt.h" +#include "vty.h" +#include "command.h" +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "zclient.h" +#include "vrf.h" + +static void		 ldpd_shutdown(void); +static pid_t		 start_child(enum ldpd_process, char *, int, +			    const char *, const char *); +static int		 main_dispatch_ldpe(struct thread *); +static int		 main_dispatch_lde(struct thread *);  static int		 main_imsg_send_ipc_sockets(struct imsgbuf *,  			    struct imsgbuf *);  static void		 main_imsg_send_net_sockets(int);  static void		 main_imsg_send_net_socket(int, enum socket_type);  static int		 main_imsg_send_config(struct ldpd_conf *); -static int		 ldp_reload(void); +static void		 ldp_config_normalize(struct ldpd_conf *); +static void		 ldp_config_reset_main(struct ldpd_conf *); +static void		 ldp_config_reset_af(struct ldpd_conf *, int);  static void		 merge_global(struct ldpd_conf *, struct ldpd_conf *);  static void		 merge_af(int, struct ldpd_af_conf *,  			    struct ldpd_af_conf *); @@ -63,84 +67,216 @@ static void		 merge_l2vpn(struct ldpd_conf *, struct l2vpn *,  struct ldpd_global	 global;  struct ldpd_conf	*ldpd_conf; -static char		*conffile;  static struct imsgev	*iev_ldpe;  static struct imsgev	*iev_lde;  static pid_t		 ldpe_pid;  static pid_t		 lde_pid; -/* ARGSUSED */ -static void -main_sig_handler(int sig, short event, void *arg) +#define LDP_DEFAULT_CONFIG	"ldpd.conf" +#define LDP_VTY_PORT		2612 + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +static const char *pid_file = PATH_LDPD_PID; + +/* Configuration filename and directory. */ +static char config_default[] = SYSCONFDIR LDP_DEFAULT_CONFIG; + +/* ldpd privileges */ +static zebra_capabilities_t _caps_p [] =  { -	/* signal handler rules don't apply, libevent decouples for us */ -	switch (sig) { -	case SIGTERM: -	case SIGINT: -		ldpd_shutdown(); -		/* NOTREACHED */ -	case SIGHUP: -		if (ldp_reload() == -1) -			log_warnx("configuration reload failed"); -		else -			log_debug("configuration reloaded"); -		break; -	default: -		fatalx("unexpected signal"); -		/* NOTREACHED */ +	ZCAP_BIND, +	ZCAP_NET_ADMIN +}; + +struct zebra_privs_t ldpd_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) +	.user = QUAGGA_USER, +	.group = QUAGGA_GROUP, +#endif +#if defined(VTY_GROUP) +	.vty_group = VTY_GROUP, +#endif +	.caps_p = _caps_p, +	.cap_num_p = array_size(_caps_p), +	.cap_num_i = 0 +}; + +/* LDPd options. */ +static struct option longopts[] = +{ +	{ "daemon",      no_argument,       NULL, 'd'}, +	{ "config_file", required_argument, NULL, 'f'}, +	{ "pid_file",    required_argument, NULL, 'i'}, +	{ "socket",      required_argument, NULL, 'z'}, +	{ "dryrun",      no_argument,       NULL, 'C'}, +	{ "help",        no_argument,       NULL, 'h'}, +	{ "vty_addr",    required_argument, NULL, 'A'}, +	{ "vty_port",    required_argument, NULL, 'P'}, +	{ "user",        required_argument, NULL, 'u'}, +	{ "group",       required_argument, NULL, 'g'}, +	{ "version",     no_argument,       NULL, 'v'}, +	{ 0 } +}; + +/* Help information display. */ +static void __attribute__ ((noreturn)) +usage(char *progname, int status) +{ +	if (status != 0) +		fprintf(stderr, "Try `%s --help' for more information.\n", +		    progname); +	else { +		printf("Usage : %s [OPTION...]\n\ +Daemon which manages LDP.\n\n\ +-d, --daemon       Runs in daemon mode\n\ +-f, --config_file  Set configuration file name\n\ +-i, --pid_file     Set process identifier file name\n\ +-z, --socket       Set path of zebra socket\n\ +-A, --vty_addr     Set vty's bind address\n\ +-P, --vty_port     Set vty's port number\n\ +-u, --user         User to run as\n\ +-g, --group        Group to run as\n\ +-v, --version      Print program version\n\ +-C, --dryrun       Check configuration for validity and exit\n\ +-h, --help         Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS);  	} + +	exit(status);  } -static __dead void -usage(void) +/* SIGHUP handler. */ +static void +sighup(void)  { -	extern char *__progname; +	log_info("SIGHUP received"); +} + +/* SIGINT / SIGTERM handler. */ +static void +sigint(void) +{ +	log_info("SIGINT received"); +	ldpd_shutdown(); +} -	fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", -	    __progname); -	exit(1); +/* SIGUSR1 handler. */ +static void +sigusr1(void) +{ +	zlog_rotate(NULL);  } +static struct quagga_signal_t ldp_signals[] = +{ +	{ +		.signal = SIGHUP, +		.handler = &sighup, +	}, +	{ +		.signal = SIGINT, +		.handler = &sigint, +	}, +	{ +		.signal = SIGTERM, +		.handler = &sigint, +	}, +	{ +		.signal = SIGUSR1, +		.handler = &sigusr1, +	} +}; +  int  main(int argc, char *argv[])  { -	struct event		 ev_sigint, ev_sigterm, ev_sighup;  	char			*saved_argv0; -	int			 ch; -	int			 debug = 0, lflag = 0, eflag = 0; +	int			 lflag = 0, eflag = 0;  	int			 pipe_parent2ldpe[2];  	int			 pipe_parent2lde[2]; +	char			*p; +	char			*vty_addr = NULL; +	int			 vty_port = LDP_VTY_PORT; +	int			 daemon_mode = 0; +	const char		*user = NULL; +	const char		*group = NULL; +	char			*config_file = NULL; +	char			*progname; +	struct thread		 thread; +	int			 dryrun = 0; -	conffile = CONF_FILE;  	ldpd_process = PROC_MAIN; -	log_init(1);	/* log to stderr until daemonized */ -	log_verbose(1); +	/* Set umask before anything for security */ +	umask(0027); + +	/* get program name */ +	progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);  	saved_argv0 = argv[0];  	if (saved_argv0 == NULL) -		saved_argv0 = "ldpd"; +		saved_argv0 = (char *)"ldpd"; -	while ((ch = getopt(argc, argv, "dD:f:nvLE")) != -1) { -		switch (ch) { -		case 'd': -			debug = 1; +	while (1) { +		int opt; + +		opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:vCLE", +		    longopts, 0); + +		if (opt == EOF) +			break; + +		switch (opt) { +		case 0:  			break; -		case 'D': -			if (cmdline_symset(optarg) < 0) -				log_warnx("could not parse macro definition %s", -				    optarg); +		case 'd': +			daemon_mode = 1;  			break;  		case 'f': -			conffile = optarg; +			config_file = optarg; +			break; +		case 'A': +			vty_addr = optarg; +			break; +		case 'i': +			pid_file = optarg; +			break; +		case 'z': +			zclient_serv_path_set(optarg); +			break; +		case 'P': +			/* +			 * Deal with atoi() returning 0 on failure, and ldpd +			 * not listening on ldpd port. +			 */ +			if (strcmp(optarg, "0") == 0) { +				vty_port = 0; +				break; +			} +			vty_port = atoi(optarg); +			if (vty_port <= 0 || vty_port > 0xffff) +				vty_port = LDP_VTY_PORT; +			break; +		case 'u': +			user = optarg;  			break; -		case 'n': -			global.cmd_opts |= LDPD_OPT_NOACTION; +		case 'g': +			group = optarg;  			break;  		case 'v': -			if (global.cmd_opts & LDPD_OPT_VERBOSE) -				global.cmd_opts |= LDPD_OPT_VERBOSE2; -			global.cmd_opts |= LDPD_OPT_VERBOSE; +			print_version(progname); +			exit(0); +			break; +		case 'C': +			dryrun = 1; +			break; +		case 'h': +			usage(progname, 0);  			break;  		case 'L':  			lflag = 1; @@ -149,125 +285,132 @@ main(int argc, char *argv[])  			eflag = 1;  			break;  		default: -			usage(); -			/* NOTREACHED */ +			usage(progname, 1); +			break;  		}  	}  	argc -= optind;  	argv += optind;  	if (argc > 0 || (lflag && eflag)) -		usage(); - -	if (lflag) -		lde(debug, global.cmd_opts & LDPD_OPT_VERBOSE); -	else if (eflag) -		ldpe(debug, global.cmd_opts & LDPD_OPT_VERBOSE); +		usage(progname, 1); -	/* fetch interfaces early */ -	kif_init(); - -	/* parse config file */ -	if ((ldpd_conf = parse_config(conffile)) == NULL ) { -		kif_clear(); +	/* check for root privileges  */ +	if (geteuid() != 0) { +		errno = EPERM; +		perror(progname);  		exit(1);  	} -	if (global.cmd_opts & LDPD_OPT_NOACTION) { -		if (global.cmd_opts & LDPD_OPT_VERBOSE) -			print_config(ldpd_conf); -		else -			fprintf(stderr, "configuration OK\n"); -		kif_clear(); -		exit(0); -	} +	zlog_default = openzlog(progname, ZLOG_LDP, 0, +	    LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); -	/* check for root privileges  */ -	if (geteuid()) -		errx(1, "need root privileges"); +	if (lflag) +		lde(user, group); +	else if (eflag) +		ldpe(user, group); -	/* check for ldpd user */ -	if (getpwnam(LDPD_USER) == NULL) -		errx(1, "unknown user %s", LDPD_USER); +  	master = thread_master_create(); -	log_init(debug); -	log_verbose(global.cmd_opts & (LDPD_OPT_VERBOSE | LDPD_OPT_VERBOSE2)); +	cmd_init(1); +	vty_init(master); +	vrf_init(); +	ldp_vty_init(); +	ldp_vty_if_init(); -	if (!debug) -		daemon(1, 0); +	/* Get configuration file. */ +	ldpd_conf = config_new_empty(); +	ldp_config_reset_main(ldpd_conf); +	vty_read_config(config_file, config_default); + +	/* Start execution only if not in dry-run mode */ +	if (dryrun) +		exit(0); -	log_info("startup"); +	if (daemon_mode && daemon(0, 0) < 0) { +		log_warn("LDPd daemon failed"); +		exit(1); +	} -	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, -	    PF_UNSPEC, pipe_parent2ldpe) == -1) +	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1)  		fatal("socketpair"); -	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, -	    PF_UNSPEC, pipe_parent2lde) == -1) +	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1)  		fatal("socketpair"); +	sock_set_nonblock(pipe_parent2ldpe[0]); +	sock_set_cloexec(pipe_parent2ldpe[0]); +	sock_set_nonblock(pipe_parent2ldpe[1]); +	sock_set_cloexec(pipe_parent2ldpe[1]); +	sock_set_nonblock(pipe_parent2lde[0]); +	sock_set_cloexec(pipe_parent2lde[0]); +	sock_set_nonblock(pipe_parent2lde[1]); +	sock_set_cloexec(pipe_parent2lde[1]);  	/* start children */  	lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0, -	    pipe_parent2lde[1], debug, global.cmd_opts & LDPD_OPT_VERBOSE); +	    pipe_parent2lde[1], user, group);  	ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0, -	    pipe_parent2ldpe[1], debug, global.cmd_opts & LDPD_OPT_VERBOSE); +	    pipe_parent2ldpe[1], user, group); -	event_init(); +	/* drop privileges */ +	if (user) +		ldpd_privs.user = user; +	if (group) +		ldpd_privs.group = group; +	zprivs_init(&ldpd_privs);  	/* setup signal handler */ -	signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); -	signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); -	signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); -	signal_add(&ev_sigint, NULL); -	signal_add(&ev_sigterm, NULL); -	signal_add(&ev_sighup, NULL); -	signal(SIGPIPE, SIG_IGN); +	signal_init(master, array_size(ldp_signals), ldp_signals); + +	/* library inits */ +	ldp_zebra_init(master);  	/* setup pipes to children */  	if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL ||  	    (iev_lde = malloc(sizeof(struct imsgev))) == NULL)  		fatal(NULL);  	imsg_init(&iev_ldpe->ibuf, pipe_parent2ldpe[0]); -	iev_ldpe->handler = main_dispatch_ldpe; -	imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]); -	iev_lde->handler = main_dispatch_lde; +	iev_ldpe->handler_read = main_dispatch_ldpe; +	iev_ldpe->ev_read = thread_add_read(master, iev_ldpe->handler_read, +	    iev_ldpe, iev_ldpe->ibuf.fd); +	iev_ldpe->handler_write = ldp_write_handler; +	iev_ldpe->ev_write = NULL; -	/* setup event handler */ -	iev_ldpe->events = EV_READ; -	event_set(&iev_ldpe->ev, iev_ldpe->ibuf.fd, iev_ldpe->events, -	    iev_ldpe->handler, iev_ldpe); -	event_add(&iev_ldpe->ev, NULL); - -	iev_lde->events = EV_READ; -	event_set(&iev_lde->ev, iev_lde->ibuf.fd, iev_lde->events, -	    iev_lde->handler, iev_lde); -	event_add(&iev_lde->ev, NULL); +	imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]); +	iev_lde->handler_read = main_dispatch_lde; +	iev_lde->ev_read = thread_add_read(master, iev_lde->handler_read, +	    iev_lde, iev_lde->ibuf.fd); +	iev_lde->handler_write = ldp_write_handler; +	iev_lde->ev_write = NULL;  	if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf))  		fatal("could not establish imsg links"); +	main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug, +	    sizeof(ldp_debug));  	main_imsg_send_config(ldpd_conf); -	/* notify ldpe about existing interfaces and addresses */ -	kif_redistribute(NULL); - -	if (kr_init(!(ldpd_conf->flags & F_LDPD_NO_FIB_UPDATE)) == -1) -		fatalx("kr_init failed"); -  	if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)  		main_imsg_send_net_sockets(AF_INET);  	if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)  		main_imsg_send_net_sockets(AF_INET6); -	/* remove unneded stuff from config */ -		/* ... */ +	/* Process id file create. */ +	pid_output(pid_file); -	event_dispatch(); +	/* Create VTY socket */ +	vty_serv_sock(vty_addr, vty_port, LDP_VTYSH_PATH); + +	/* Print banner. */ +	log_notice("LDPd %s starting: vty@%d", QUAGGA_VERSION, vty_port); + +	/* Fetch next active thread. */ +	while (thread_fetch(master, &thread)) +		thread_call(&thread); -	ldpd_shutdown();  	/* NOTREACHED */  	return (0);  } -static __dead void +static void  ldpd_shutdown(void)  {  	pid_t		 pid; @@ -279,7 +422,6 @@ ldpd_shutdown(void)  	msgbuf_clear(&iev_lde->ibuf.w);  	close(iev_lde->ibuf.fd); -	kr_shutdown();  	config_clear(ldpd_conf);  	log_debug("waiting for children to terminate"); @@ -302,9 +444,10 @@ ldpd_shutdown(void)  }  static pid_t -start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose) +start_child(enum ldpd_process p, char *argv0, int fd, const char *user, +    const char *group)  { -	char	*argv[5]; +	char	*argv[7];  	int	 argc = 0;  	pid_t	 pid; @@ -326,16 +469,20 @@ start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose)  	case PROC_MAIN:  		fatalx("Can not start main process");  	case PROC_LDE_ENGINE: -		argv[argc++] = "-L"; +		argv[argc++] = (char *)"-L";  		break;  	case PROC_LDP_ENGINE: -		argv[argc++] = "-E"; +		argv[argc++] = (char *)"-E";  		break;  	} -	if (debug) -		argv[argc++] = "-d"; -	if (verbose) -		argv[argc++] = "-v"; +	if (user) { +		argv[argc++] = (char *)"-u"; +		argv[argc++] = (char *)user; +	} +	if (group) { +		argv[argc++] = (char *)"-g"; +		argv[argc++] = (char *)group; +	}  	argv[argc++] = NULL;  	execvp(argv0, argv); @@ -344,28 +491,22 @@ start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose)  /* imsg handling */  /* ARGSUSED */ -static void -main_dispatch_ldpe(int fd, short event, void *bula) +static int +main_dispatch_ldpe(struct thread *thread)  { -	struct imsgev		*iev = bula; +	struct imsgev		*iev = THREAD_ARG(thread);  	struct imsgbuf		*ibuf = &iev->ibuf;  	struct imsg		 imsg;  	int			 af;  	ssize_t			 n; -	int			 shut = 0, verbose; +	int			 shut = 0; -	if (event & EV_READ) { -		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) -			fatal("imsg_read error"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} -	if (event & EV_WRITE) { -		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) -			fatal("msgbuf_write"); -		if (n == 0) -			shut = 1; -	} +	iev->ev_read = NULL; + +	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) +		fatal("imsg_read error"); +	if (n == 0)	/* connection closed */ +		shut = 1;  	for (;;) {  		if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -375,39 +516,13 @@ main_dispatch_ldpe(int fd, short event, void *bula)  			break;  		switch (imsg.hdr.type) { +		case IMSG_LOG: +			logit(imsg.hdr.pid, "%s", (const char *)imsg.data); +			break;  		case IMSG_REQUEST_SOCKETS:  			af = imsg.hdr.pid;  			main_imsg_send_net_sockets(af);  			break; -		case IMSG_CTL_RELOAD: -			if (ldp_reload() == -1) -				log_warnx("configuration reload failed"); -			else -				log_debug("configuration reloaded"); -			break; -		case IMSG_CTL_FIB_COUPLE: -			kr_fib_couple(); -			break; -		case IMSG_CTL_FIB_DECOUPLE: -			kr_fib_decouple(); -			break; -		case IMSG_CTL_KROUTE: -		case IMSG_CTL_KROUTE_ADDR: -			kr_show_route(&imsg); -			break; -		case IMSG_CTL_IFINFO: -			if (imsg.hdr.len == IMSG_HEADER_SIZE) -				kr_ifinfo(NULL, imsg.hdr.pid); -			else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) -				kr_ifinfo(imsg.data, imsg.hdr.pid); -			else -				log_warnx("IFINFO request with wrong len"); -			break; -		case IMSG_CTL_LOG_VERBOSE: -			/* already checked by ldpe */ -			memcpy(&verbose, imsg.data, sizeof(verbose)); -			log_verbose(verbose); -			break;  		default:  			log_debug("%s: error handling imsg %d", __func__,  			    imsg.hdr.type); @@ -418,34 +533,35 @@ main_dispatch_ldpe(int fd, short event, void *bula)  	if (!shut)  		imsg_event_add(iev);  	else { -		/* this pipe is dead, so remove the event handler */ -		event_del(&iev->ev); -		event_loopexit(NULL); +		/* this pipe is dead, so remove the event handlers and exit */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		ldpe_pid = 0; +		if (lde_pid == 0) +			ldpd_shutdown(); +		else +			kill(lde_pid, SIGTERM);  	} + +	return (0);  }  /* ARGSUSED */ -static void -main_dispatch_lde(int fd, short event, void *bula) +static int +main_dispatch_lde(struct thread *thread)  { -	struct imsgev	*iev = bula; +	struct imsgev	*iev = THREAD_ARG(thread);  	struct imsgbuf	*ibuf = &iev->ibuf;  	struct imsg	 imsg;  	ssize_t		 n;  	int		 shut = 0; -	if (event & EV_READ) { -		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) -			fatal("imsg_read error"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} -	if (event & EV_WRITE) { -		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) -			fatal("msgbuf_write"); -		if (n == 0) -			shut = 1; -	} +	iev->ev_read = NULL; + +	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) +		fatal("imsg_read error"); +	if (n == 0)	/* connection closed */ +		shut = 1;  	for (;;) {  		if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -455,6 +571,9 @@ main_dispatch_lde(int fd, short event, void *bula)  			break;  		switch (imsg.hdr.type) { +		case IMSG_LOG: +			logit(imsg.hdr.pid, "%s", (const char *)imsg.data); +			break;  		case IMSG_KLABEL_CHANGE:  			if (imsg.hdr.len - IMSG_HEADER_SIZE !=  			    sizeof(struct kroute)) @@ -495,10 +614,41 @@ main_dispatch_lde(int fd, short event, void *bula)  	if (!shut)  		imsg_event_add(iev);  	else { -		/* this pipe is dead, so remove the event handler */ -		event_del(&iev->ev); -		event_loopexit(NULL); +		/* this pipe is dead, so remove the event handlers and exit */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		lde_pid = 0; +		if (ldpe_pid == 0) +			ldpd_shutdown(); +		else +			kill(ldpe_pid, SIGTERM);  	} + +	return (0); +} + +/* ARGSUSED */ +int +ldp_write_handler(struct thread *thread) +{ +	struct imsgev	*iev = THREAD_ARG(thread); +	struct imsgbuf	*ibuf = &iev->ibuf; +	ssize_t		 n; + +	iev->ev_write = NULL; + +	if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) +		fatal("msgbuf_write"); +	if (n == 0) { +		/* this pipe is dead, so remove the event handlers */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		return (0); +	} + +	imsg_event_add(iev); + +	return (0);  }  void @@ -515,9 +665,11 @@ main_imsg_compose_lde(int type, pid_t pid, void *data, uint16_t datalen)  	imsg_compose_event(iev_lde, type, 0, pid, -1, data, datalen);  } -static int +int  main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len)  { +	if (iev_ldpe == NULL || iev_lde == NULL) +		return (0);  	if (imsg_compose_event(iev_ldpe, type, 0, 0, -1, buf, len) == -1)  		return (-1);  	if (imsg_compose_event(iev_lde, type, 0, 0, -1, buf, len) == -1) @@ -528,13 +680,12 @@ main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len)  void  imsg_event_add(struct imsgev *iev)  { -	iev->events = EV_READ; -	if (iev->ibuf.w.queued) -		iev->events |= EV_WRITE; +	THREAD_READ_ON(master, iev->ev_read, iev->handler_read, iev, +	    iev->ibuf.fd); -	event_del(&iev->ev); -	event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); -	event_add(&iev->ev, NULL); +	if (iev->ibuf.w.queued) +		THREAD_WRITE_ON(master, iev->ev_write, iev->handler_write, iev, +		    iev->ibuf.fd);  }  int @@ -560,22 +711,24 @@ void  evbuf_event_add(struct evbuf *eb)  {  	if (eb->wbuf.queued) -		event_add(&eb->ev, NULL); +		THREAD_WRITE_ON(master, eb->ev, eb->handler, eb->arg, +		    eb->wbuf.fd);  }  void -evbuf_init(struct evbuf *eb, int fd, void (*handler)(int, short, void *), +evbuf_init(struct evbuf *eb, int fd, int (*handler)(struct thread *),      void *arg)  {  	msgbuf_init(&eb->wbuf);  	eb->wbuf.fd = fd; -	event_set(&eb->ev, eb->wbuf.fd, EV_WRITE, handler, arg); +	eb->handler = handler; +	eb->arg = arg;  }  void  evbuf_clear(struct evbuf *eb)  { -	event_del(&eb->ev); +	THREAD_WRITE_OFF(eb->ev);  	msgbuf_clear(&eb->wbuf);  	eb->wbuf.fd = -1;  } @@ -585,9 +738,10 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf)  {  	int pipe_ldpe2lde[2]; -	if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, -	    PF_UNSPEC, pipe_ldpe2lde) == -1) +	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_ldpe2lde) == -1)  		return (-1); +	sock_set_nonblock(pipe_ldpe2lde[0]); +	sock_set_nonblock(pipe_ldpe2lde[1]);  	if (imsg_compose(ldpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_ldpe2lde[0],  	    NULL, 0) == -1) @@ -602,6 +756,9 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf)  static void  main_imsg_send_net_sockets(int af)  { +	if (!ldp_addrisset(af, &(ldp_af_conf_get(ldpd_conf, af))->trans_addr)) +		return; +  	main_imsg_send_net_socket(af, LDP_SOCKET_DISC);  	main_imsg_send_net_socket(af, LDP_SOCKET_EDISC);  	main_imsg_send_net_socket(af, LDP_SOCKET_SESSION); @@ -657,6 +814,15 @@ ldp_is_dual_stack(struct ldpd_conf *xconf)  	    (xconf->ipv6.flags & F_LDPD_AF_ENABLED));  } +in_addr_t +ldp_rtr_id_get(struct ldpd_conf *xconf) +{ +	if (xconf->rtr_id.s_addr != INADDR_ANY) +		return (xconf->rtr_id.s_addr); +	else +		return (global.rtr_id.s_addr); +} +  static int  main_imsg_send_config(struct ldpd_conf *xconf)  { @@ -704,6 +870,11 @@ main_imsg_send_config(struct ldpd_conf *xconf)  			    sizeof(*pw)) == -1)  				return (-1);  		} +		LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) { +			if (main_imsg_compose_both(IMSG_RECONF_L2VPN_IPW, pw, +			    sizeof(*pw)) == -1) +				return (-1); +		}  	}  	if (main_imsg_compose_both(IMSG_RECONF_END, NULL, 0) == -1) @@ -712,13 +883,10 @@ main_imsg_send_config(struct ldpd_conf *xconf)  	return (0);  } -static int -ldp_reload(void) +int +ldp_reload(struct ldpd_conf *xconf)  { -	struct ldpd_conf	*xconf; - -	if ((xconf = parse_config(conffile)) == NULL) -		return (-1); +	ldp_config_normalize(xconf);  	if (main_imsg_send_config(xconf) == -1)  		return (-1); @@ -728,6 +896,205 @@ ldp_reload(void)  	return (0);  } +static void +ldp_config_normalize(struct ldpd_conf *xconf) +{ +	struct l2vpn		*l2vpn; +	struct l2vpn_pw		*pw; + +	if (!(xconf->flags & F_LDPD_ENABLED)) +		ldp_config_reset_main(xconf); +	else { +		if (!(xconf->ipv4.flags & F_LDPD_AF_ENABLED)) +			ldp_config_reset_af(xconf, AF_INET); +		if (!(xconf->ipv6.flags & F_LDPD_AF_ENABLED)) +			ldp_config_reset_af(xconf, AF_INET6); +	} + +	LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) { +		LIST_FOREACH(pw, &l2vpn->pw_list, entry) { +			if (pw->flags & F_PW_STATIC_NBR_ADDR) +				continue; + +			pw->af = AF_INET; +			pw->addr.v4 = pw->lsr_id; +		} +		LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) { +			if (pw->flags & F_PW_STATIC_NBR_ADDR) +				continue; + +			pw->af = AF_INET; +			pw->addr.v4 = pw->lsr_id; +		} +	} +} + +static void +ldp_config_reset_main(struct ldpd_conf *conf) +{ +	struct iface		*iface; +	struct nbr_params	*nbrp; + +	while ((iface = LIST_FIRST(&conf->iface_list)) != NULL) { +		LIST_REMOVE(iface, entry); +		free(iface); +	} + +	while ((nbrp = LIST_FIRST(&conf->nbrp_list)) != NULL) { +		LIST_REMOVE(nbrp, entry); +		free(nbrp); +	} + +	conf->rtr_id.s_addr = INADDR_ANY; +	ldp_config_reset_af(conf, AF_INET); +	ldp_config_reset_af(conf, AF_INET6); +	conf->lhello_holdtime = LINK_DFLT_HOLDTIME; +	conf->lhello_interval = DEFAULT_HELLO_INTERVAL; +	conf->thello_holdtime = TARGETED_DFLT_HOLDTIME; +	conf->thello_interval = DEFAULT_HELLO_INTERVAL; +	conf->trans_pref = DUAL_STACK_LDPOV6; +	conf->flags = 0; +} + +static void +ldp_config_reset_af(struct ldpd_conf *conf, int af) +{ +	struct ldpd_af_conf	*af_conf; +	struct iface		*iface; +	struct iface_af		*ia; +	struct tnbr		*tnbr, *ttmp; + +	LIST_FOREACH(iface, &conf->iface_list, entry) { +		ia = iface_af_get(iface, af); +		ia->enabled = 0; +	} + +	LIST_FOREACH_SAFE(tnbr, &conf->tnbr_list, entry, ttmp) { +		if (tnbr->af != af) +			continue; + +		LIST_REMOVE(tnbr, entry); +		free(tnbr); +	} + +	af_conf = ldp_af_conf_get(conf, af); +	af_conf->keepalive = 180; +	af_conf->lhello_holdtime = 0; +	af_conf->lhello_interval = 0; +	af_conf->thello_holdtime = 0; +	af_conf->thello_interval = 0; +	memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr)); +	af_conf->flags = 0; +} + +struct ldpd_conf * +ldp_dup_config(struct ldpd_conf *conf) +{ +	struct ldpd_conf	*xconf; +	struct iface		*iface, *xi; +	struct tnbr		*tnbr, *xt; +	struct nbr_params	*nbrp, *xn; +	struct l2vpn		*l2vpn, *xl; +	struct l2vpn_if		*lif, *xf; +	struct l2vpn_pw		*pw, *xp; + +	xconf = malloc(sizeof(*xconf)); +	*xconf = *conf; +	LIST_INIT(&xconf->iface_list); +	LIST_INIT(&xconf->tnbr_list); +	LIST_INIT(&xconf->nbrp_list); +	LIST_INIT(&xconf->l2vpn_list); + +	LIST_FOREACH(iface, &conf->iface_list, entry) { +		xi = calloc(1, sizeof(*xi)); +		if (xi == NULL) +			fatal(__func__); +		*xi = *iface; +		xi->ipv4.iface = xi; +		xi->ipv6.iface = xi; +		LIST_INSERT_HEAD(&xconf->iface_list, xi, entry); +	} +	LIST_FOREACH(tnbr, &conf->tnbr_list, entry) { +		xt = calloc(1, sizeof(*xt)); +		if (xt == NULL) +			fatal(__func__); +		*xt = *tnbr; +		LIST_INSERT_HEAD(&xconf->tnbr_list, xt, entry); +	} +	LIST_FOREACH(nbrp, &conf->nbrp_list, entry) { +		xn = calloc(1, sizeof(*xn)); +		if (xn == NULL) +			fatal(__func__); +		*xn = *nbrp; +		LIST_INSERT_HEAD(&xconf->nbrp_list, xn, entry); +	} +	LIST_FOREACH(l2vpn, &conf->l2vpn_list, entry) { +		xl = calloc(1, sizeof(*xl)); +		if (xl == NULL) +			fatal(__func__); +		*xl = *l2vpn; +		LIST_INIT(&xl->if_list); +		LIST_INIT(&xl->pw_list); +		LIST_INIT(&xl->pw_inactive_list); +		LIST_INSERT_HEAD(&xconf->l2vpn_list, xl, entry); + +		LIST_FOREACH(lif, &l2vpn->if_list, entry) { +			xf = calloc(1, sizeof(*xf)); +			if (xf == NULL) +				fatal(__func__); +			*xf = *lif; +			xf->l2vpn = xl; +			LIST_INSERT_HEAD(&xl->if_list, xf, entry); +		} +		LIST_FOREACH(pw, &l2vpn->pw_list, entry) { +			xp = calloc(1, sizeof(*xp)); +			if (xp == NULL) +				fatal(__func__); +			*xp = *pw; +			xp->l2vpn = xl; +			LIST_INSERT_HEAD(&xl->pw_list, xp, entry); +		} +		LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) { +			xp = calloc(1, sizeof(*xp)); +			if (xp == NULL) +				fatal(__func__); +			*xp = *pw; +			xp->l2vpn = xl; +			LIST_INSERT_HEAD(&xl->pw_inactive_list, xp, entry); +		} +	} + +	return (xconf); +} + +void +ldp_clear_config(struct ldpd_conf *xconf) +{ +	struct iface		*iface; +	struct tnbr		*tnbr; +	struct nbr_params	*nbrp; +	struct l2vpn		*l2vpn; + +	while ((iface = LIST_FIRST(&xconf->iface_list)) != NULL) { +		LIST_REMOVE(iface, entry); +		free(iface); +	} +	while ((tnbr = LIST_FIRST(&xconf->tnbr_list)) != NULL) { +		LIST_REMOVE(tnbr, entry); +		free(tnbr); +	} +	while ((nbrp = LIST_FIRST(&xconf->nbrp_list)) != NULL) { +		LIST_REMOVE(nbrp, entry); +		free(nbrp); +	} +	while ((l2vpn = LIST_FIRST(&xconf->l2vpn_list)) != NULL) { +		LIST_REMOVE(l2vpn, entry); +		l2vpn_del(l2vpn); +	} + +	free(xconf); +} +  void  merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf)  { @@ -758,6 +1125,11 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf)  		conf->rtr_id = xconf->rtr_id;  	} +	conf->lhello_holdtime = xconf->lhello_holdtime; +	conf->lhello_interval = xconf->lhello_interval; +	conf->thello_holdtime = xconf->thello_holdtime; +	conf->thello_interval = xconf->thello_interval; +  	if (conf->trans_pref != xconf->trans_pref) {  		if (ldpd_process == PROC_LDP_ENGINE)  			ldpe_reset_ds_nbrs(); @@ -784,6 +1156,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)  		if (ldpd_process == PROC_LDP_ENGINE)  			ldpe_stop_init_backoff(af);  	} + +	af_conf->lhello_holdtime = xa->lhello_holdtime; +	af_conf->lhello_interval = xa->lhello_interval;  	af_conf->thello_holdtime = xa->thello_holdtime;  	af_conf->thello_interval = xa->thello_interval; @@ -815,10 +1190,6 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)  			lde_change_egress_label(af, af_conf->flags &  			    F_LDPD_AF_EXPNULL);  			break; -		case PROC_MAIN: -			kr_change_egress_label(af, af_conf->flags & -			    F_LDPD_AF_EXPNULL); -			break;  		default:  			break;  		} @@ -829,7 +1200,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa)  		update_sockets = 1;  	} -	if (ldpd_process == PROC_MAIN && update_sockets) +	if (ldpd_process == PROC_MAIN && iev_ldpe && update_sockets)  		imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, 0, -1,  		    NULL, 0);  } @@ -841,7 +1212,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)  	LIST_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) {  		/* find deleted interfaces */ -		if ((xi = if_lookup(xconf, iface->ifindex)) == NULL) { +		if ((xi = if_lookup_name(xconf, iface->name)) == NULL) {  			LIST_REMOVE(iface, entry);  			if (ldpd_process == PROC_LDP_ENGINE)  				if_exit(iface); @@ -850,7 +1221,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf)  	}  	LIST_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) {  		/* find new interfaces */ -		if ((iface = if_lookup(conf, xi->ifindex)) == NULL) { +		if ((iface = if_lookup_name(conf, xi->name)) == NULL) {  			LIST_REMOVE(xi, entry);  			LIST_INSERT_HEAD(&conf->iface_list, xi, entry); @@ -914,8 +1285,6 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf)  		/* update existing tnbrs */  		if (!(tnbr->flags & F_TNBR_CONFIGURED))  			tnbr->flags |= F_TNBR_CONFIGURED; -		tnbr->hello_holdtime = xt->hello_holdtime; -		tnbr->hello_interval = xt->hello_interval;  		LIST_REMOVE(xt, entry);  		free(xt);  	} @@ -935,7 +1304,14 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)  				nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);  				if (nbr) {  					session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__  					pfkey_remove(nbr); +#else +					sock_set_md5sig( +					    (ldp_af_global_get(&global, +					    nbr->af))->ldp_session_socket, +					    nbr->af, &nbr->raddr, NULL); +#endif  					if (nbr_session_active_role(nbr))  						nbr_establish_connection(nbr);  				} @@ -954,8 +1330,16 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)  				nbr = nbr_find_ldpid(xn->lsr_id.s_addr);  				if (nbr) {  					session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__  					if (pfkey_establish(nbr, xn) == -1)  						fatalx("pfkey setup failed"); +#else +					sock_set_md5sig( +					    (ldp_af_global_get(&global, +					    nbr->af))->ldp_session_socket, +					    nbr->af, &nbr->raddr, +					    xn->auth.md5key); +#endif  					if (nbr_session_active_role(nbr))  						nbr_establish_connection(nbr);  				} @@ -987,9 +1371,15 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf)  			nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr);  			if (nbr && nbrp_changed) {  				session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__  				pfkey_remove(nbr);  				if (pfkey_establish(nbr, nbrp) == -1)  					fatalx("pfkey setup failed"); +#else +				sock_set_md5sig((ldp_af_global_get(&global, +				    nbr->af))->ldp_session_socket, nbr->af, +				    &nbr->raddr, nbrp->auth.md5key); +#endif  				if (nbr_session_active_role(nbr))  					nbr_establish_connection(nbr);  			} @@ -1055,6 +1445,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  	struct l2vpn_pw		*pw, *ptmp, *xp;  	struct nbr		*nbr;  	int			 reset_nbr, reinstall_pwfec, reinstall_tnbr; +	LIST_HEAD(, l2vpn_pw)	 pw_aux_list;  	int			 previous_pw_type, previous_mtu;  	previous_pw_type = l2vpn->pw_type; @@ -1063,14 +1454,14 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  	/* merge intefaces */  	LIST_FOREACH_SAFE(lif, &l2vpn->if_list, entry, ftmp) {  		/* find deleted interfaces */ -		if ((xf = l2vpn_if_find(xl, lif->ifindex)) == NULL) { +		if ((xf = l2vpn_if_find_name(xl, lif->ifname)) == NULL) {  			LIST_REMOVE(lif, entry);  			free(lif);  		}  	}  	LIST_FOREACH_SAFE(xf, &xl->if_list, entry, ftmp) {  		/* find new interfaces */ -		if ((lif = l2vpn_if_find(l2vpn, xf->ifindex)) == NULL) { +		if ((lif = l2vpn_if_find_name(l2vpn, xf->ifname)) == NULL) {  			LIST_REMOVE(xf, entry);  			LIST_INSERT_HEAD(&l2vpn->if_list, xf, entry);  			xf->l2vpn = l2vpn; @@ -1081,10 +1472,11 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  		free(xf);  	} -	/* merge pseudowires */ +	/* merge active pseudowires */ +	LIST_INIT(&pw_aux_list);  	LIST_FOREACH_SAFE(pw, &l2vpn->pw_list, entry, ptmp) { -		/* find deleted pseudowires */ -		if ((xp = l2vpn_pw_find(xl, pw->ifindex)) == NULL) { +		/* find deleted active pseudowires */ +		if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) {  			switch (ldpd_process) {  			case PROC_LDE_ENGINE:  				l2vpn_pw_exit(pw); @@ -1101,8 +1493,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  		}  	}  	LIST_FOREACH_SAFE(xp, &xl->pw_list, entry, ptmp) { -		/* find new pseudowires */ -		if ((pw = l2vpn_pw_find(l2vpn, xp->ifindex)) == NULL) { +		/* find new active pseudowires */ +		if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) {  			LIST_REMOVE(xp, entry);  			LIST_INSERT_HEAD(&l2vpn->pw_list, xp, entry);  			xp->l2vpn = l2vpn; @@ -1120,7 +1512,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  			continue;  		} -		/* update existing pseudowire */ +		/* update existing active pseudowire */      		if (pw->af != xp->af ||  		    ldp_addrcmp(pw->af, &pw->addr, &xp->addr))  			reinstall_tnbr = 1; @@ -1141,6 +1533,28 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  		else  			reinstall_pwfec = 0; +		/* check if the pseudowire should be disabled */ +		if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0) { +			reinstall_tnbr = 0; +			reset_nbr = 0; +			reinstall_pwfec = 0; + +			switch (ldpd_process) { +			case PROC_LDE_ENGINE: +				l2vpn_pw_exit(pw); +				break; +			case PROC_LDP_ENGINE: +				ldpe_l2vpn_pw_exit(pw); +				break; +			case PROC_MAIN: +				break; +			} + +			/* remove from active list */ +			LIST_REMOVE(pw, entry); +			LIST_INSERT_HEAD(&pw_aux_list, pw, entry); +		} +  		if (ldpd_process == PROC_LDP_ENGINE) {  			if (reinstall_tnbr)  				ldpe_l2vpn_pw_exit(pw); @@ -1167,6 +1581,10 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  			pw->flags |= F_PW_STATUSTLV_CONF;  		else  			pw->flags &= ~F_PW_STATUSTLV_CONF; +		if (xp->flags & F_PW_STATIC_NBR_ADDR) +			pw->flags |= F_PW_STATIC_NBR_ADDR; +		else +			pw->flags &= ~F_PW_STATIC_NBR_ADDR;  		if (ldpd_process == PROC_LDP_ENGINE && reinstall_tnbr)  			ldpe_l2vpn_pw_init(pw);  		if (ldpd_process == PROC_LDE_ENGINE && @@ -1182,6 +1600,60 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl)  		free(xp);  	} +	/* merge inactive pseudowires */ +	LIST_FOREACH_SAFE(pw, &l2vpn->pw_inactive_list, entry, ptmp) { +		/* find deleted inactive pseudowires */ +		if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) { +			LIST_REMOVE(pw, entry); +			free(pw); +		} +	} +	LIST_FOREACH_SAFE(xp, &xl->pw_inactive_list, entry, ptmp) { +		/* find new inactive pseudowires */ +		if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) { +			LIST_REMOVE(xp, entry); +			LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, xp, entry); +			xp->l2vpn = l2vpn; +			continue; +		} + +		/* update existing inactive pseudowire */ +		pw->lsr_id.s_addr = xp->lsr_id.s_addr; +		pw->af = xp->af; +		pw->addr = xp->addr; +		pw->pwid = xp->pwid; +		strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname)); +		pw->ifindex = xp->ifindex; +		pw->flags = xp->flags; + +		/* check if the pseudowire should be activated */ +		if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0) { +			/* remove from inactive list */ +			LIST_REMOVE(pw, entry); +			LIST_INSERT_HEAD(&l2vpn->pw_list, pw, entry); + +			switch (ldpd_process) { +			case PROC_LDE_ENGINE: +				l2vpn_pw_init(pw); +				break; +			case PROC_LDP_ENGINE: +				ldpe_l2vpn_pw_init(pw); +				break; +			case PROC_MAIN: +				break; +			} +		} + +		LIST_REMOVE(xp, entry); +		free(xp); +	} + +	/* insert pseudowires that were disabled in the inactive list */ +	LIST_FOREACH_SAFE(pw, &pw_aux_list, entry, ptmp) { +		LIST_REMOVE(pw, entry); +		LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, pw, entry); +	} +  	l2vpn->pw_type = xl->pw_type;  	l2vpn->mtu = xl->mtu;  	strlcpy(l2vpn->br_ifname, xl->br_ifname, sizeof(l2vpn->br_ifname)); diff --git a/ldpd/ldpd.conf.sample b/ldpd/ldpd.conf.sample new file mode 100644 index 0000000000..49da35c284 --- /dev/null +++ b/ldpd/ldpd.conf.sample @@ -0,0 +1,46 @@ +! -*- ldp -*- +! +! LDPd sample configuration file +! +hostname ldpd +password zebra +log stdout +! +interface eth0 +! +interface eth1 +! +interface lo +! +mpls ldp + dual-stack cisco-interop + neighbor 10.0.1.5 password opensourcerouting + neighbor 172.16.0.1 password opensourcerouting + ! + address-family ipv4 +  discovery transport-address 10.0.1.1 +  label local advertise explicit-null +  ! +  interface eth0 +  ! +  interface eth1 +  ! + ! + address-family ipv6 +  discovery transport-address 2001:db8::1 +  ! +  interface eth1 +  ! + ! +! +l2vpn ENG type vpls + bridge br0 + member interface eth2 + ! + member pseudowire mpw0 +  neighbor lsr-id 1.1.1.1 +  pw-id 100 + ! +! +line vty +! diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index d32d23c6c9..9601f25f70 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -22,19 +22,14 @@  #ifndef _LDPD_H_  #define _LDPD_H_ -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/tree.h> -#include <net/if.h> -#include <netinet/in.h> -#include <event.h> -#include <imsg.h> +#include "openbsd-queue.h" +#include "openbsd-tree.h" +#include "imsg.h" +#include "thread.h"  #include "ldp.h"  #define CONF_FILE		"/etc/ldpd.conf" -#define	LDPD_SOCKET		"/var/run/ldpd.sock"  #define LDPD_USER		"_ldpd"  #define LDPD_OPT_VERBOSE	0x00000001 @@ -57,15 +52,18 @@  #define	F_REDISTRIBUTED		0x0040  struct evbuf { -	struct msgbuf		wbuf; -	struct event		ev; +	struct msgbuf		 wbuf; +	struct thread		*ev; +	int			 (*handler)(struct thread *); +	void			*arg;  };  struct imsgev {  	struct imsgbuf		 ibuf; -	void			(*handler)(int, short, void *); -	struct event		 ev; -	short			 events; +	int			(*handler_write)(struct thread *); +	struct thread		*ev_write; +	int			(*handler_read)(struct thread *); +	struct thread		*ev_read;  };  enum imsg_type { @@ -73,7 +71,12 @@ enum imsg_type {  	IMSG_CTL_RELOAD,  	IMSG_CTL_SHOW_INTERFACE,  	IMSG_CTL_SHOW_DISCOVERY, +	IMSG_CTL_SHOW_DISC_IFACE, +	IMSG_CTL_SHOW_DISC_TNBR, +	IMSG_CTL_SHOW_DISC_ADJ,  	IMSG_CTL_SHOW_NBR, +	IMSG_CTL_SHOW_NBR_DISC, +	IMSG_CTL_SHOW_NBR_END,  	IMSG_CTL_SHOW_LIB,  	IMSG_CTL_SHOW_L2VPN_PW,  	IMSG_CTL_SHOW_L2VPN_BINDING, @@ -92,6 +95,7 @@ enum imsg_type {  	IMSG_IFSTATUS,  	IMSG_NEWADDR,  	IMSG_DELADDR, +	IMSG_RTRID_UPDATE,  	IMSG_LABEL_MAPPING,  	IMSG_LABEL_MAPPING_FULL,  	IMSG_LABEL_REQUEST, @@ -126,7 +130,10 @@ enum imsg_type {  	IMSG_RECONF_L2VPN,  	IMSG_RECONF_L2VPN_IF,  	IMSG_RECONF_L2VPN_PW, -	IMSG_RECONF_END +	IMSG_RECONF_L2VPN_IPW, +	IMSG_RECONF_END, +	IMSG_DEBUG_UPDATE, +	IMSG_LOG  };  union ldpd_addr { @@ -249,7 +256,7 @@ struct iface_af {  	int			 state;  	LIST_HEAD(, adj)	 adj_list;  	time_t			 uptime; -	struct event		 hello_timer; +	struct thread		*hello_timer;  	uint16_t		 hello_holdtime;  	uint16_t		 hello_interval;  }; @@ -261,9 +268,7 @@ struct iface {  	struct if_addr_head	 addr_list;  	struct in6_addr		 linklocal;  	enum iface_type		 type; -	uint8_t			 if_type;  	uint16_t		 flags; -	uint8_t			 linkstate;  	struct iface_af		 ipv4;  	struct iface_af		 ipv6;  }; @@ -271,13 +276,11 @@ struct iface {  /* source of targeted hellos */  struct tnbr {  	LIST_ENTRY(tnbr)	 entry; -	struct event		 hello_timer; +	struct thread		*hello_timer;  	struct adj		*adj;  	int			 af;  	union ldpd_addr		 addr;  	int			 state; -	uint16_t		 hello_holdtime; -	uint16_t		 hello_interval;  	uint16_t		 pw_count;  	uint8_t			 flags;  }; @@ -313,7 +316,6 @@ struct l2vpn_if {  	char			 ifname[IF_NAMESIZE];  	unsigned int		 ifindex;  	uint16_t		 flags; -	uint8_t			 link_state;  };  struct l2vpn_pw { @@ -335,6 +337,7 @@ struct l2vpn_pw {  #define F_PW_CWORD_CONF		0x04	/* control word configured */  #define F_PW_CWORD		0x08	/* control word negotiated */  #define F_PW_STATUS_UP		0x10	/* pseudowire is operational */ +#define F_PW_STATIC_NBR_ADDR	0x20	/* static neighbor address configured */  struct l2vpn {  	LIST_ENTRY(l2vpn)	 entry; @@ -346,6 +349,7 @@ struct l2vpn {  	unsigned int		 br_ifindex;  	LIST_HEAD(, l2vpn_if)	 if_list;  	LIST_HEAD(, l2vpn_pw)	 pw_list; +	LIST_HEAD(, l2vpn_pw)	 pw_inactive_list;  };  #define L2VPN_TYPE_VPWS		1  #define L2VPN_TYPE_VPLS		2 @@ -370,6 +374,8 @@ enum hello_type {  struct ldpd_af_conf {  	uint16_t		 keepalive; +	uint16_t		 lhello_holdtime; +	uint16_t		 lhello_interval;  	uint16_t		 thello_holdtime;  	uint16_t		 thello_interval;  	union ldpd_addr		 trans_addr; @@ -388,15 +394,20 @@ struct ldpd_conf {  	LIST_HEAD(, tnbr)	 tnbr_list;  	LIST_HEAD(, nbr_params)	 nbrp_list;  	LIST_HEAD(, l2vpn)	 l2vpn_list; +	uint16_t		 lhello_holdtime; +	uint16_t		 lhello_interval; +	uint16_t		 thello_holdtime; +	uint16_t		 thello_interval;  	uint16_t		 trans_pref;  	int			 flags;  };  #define	F_LDPD_NO_FIB_UPDATE	0x0001  #define	F_LDPD_DS_CISCO_INTEROP	0x0002 +#define	F_LDPD_ENABLED		0x0004  struct ldpd_af_global { -	struct event		 disc_ev; -	struct event		 edisc_ev; +	struct thread		*disc_ev; +	struct thread		*edisc_ev;  	int			 ldp_disc_socket;  	int			 ldp_edisc_socket;  	int			 ldp_session_socket; @@ -405,6 +416,7 @@ struct ldpd_af_global {  struct ldpd_global {  	int			 cmd_opts;  	time_t			 uptime; +	struct in_addr		 rtr_id;  	struct ldpd_af_global	 ipv4;  	struct ldpd_af_global	 ipv6;  	uint32_t		 conf_seqnum; @@ -451,10 +463,7 @@ struct kif {  	char			 ifname[IF_NAMESIZE];  	unsigned short		 ifindex;  	int			 flags; -	uint8_t			 link_state;  	int			 mtu; -	uint8_t			 if_type; -	uint64_t		 baudrate;  };  /* control data structures */ @@ -464,15 +473,26 @@ struct ctl_iface {  	unsigned int		 ifindex;  	int			 state;  	uint16_t		 flags; -	uint8_t			 linkstate;  	enum iface_type		 type; -	uint8_t			 if_type;  	uint16_t		 hello_holdtime;  	uint16_t		 hello_interval;  	time_t			 uptime;  	uint16_t		 adj_cnt;  }; +struct ctl_disc_if { +	char			 name[IF_NAMESIZE]; +	int			 active_v4; +	int			 active_v6; +	int			 no_adj; +}; + +struct ctl_disc_tnbr { +	int			 af; +	union ldpd_addr		 addr; +	int			 no_adj; +}; +  struct ctl_adj {  	int			 af;  	struct in_addr		 id; @@ -487,7 +507,10 @@ struct ctl_nbr {  	int			 af;  	struct in_addr		 id;  	union ldpd_addr		 laddr; +	in_port_t		 lport;  	union ldpd_addr		 raddr; +	in_port_t		 rport; +	uint16_t		 holdtime;  	time_t			 uptime;  	int			 nbr_state;  }; @@ -501,19 +524,23 @@ struct ctl_rt {  	uint32_t		 remote_label;  	uint8_t			 flags;  	uint8_t			 in_use; +	int			 first;  };  struct ctl_pw {  	uint16_t		 type; +	char			 l2vpn_name[L2VPN_NAME_LEN];  	char			 ifname[IF_NAMESIZE];  	uint32_t		 pwid;  	struct in_addr		 lsr_id;  	uint32_t		 local_label;  	uint32_t		 local_gid;  	uint16_t		 local_ifmtu; +	uint8_t			 local_cword;  	uint32_t		 remote_label;  	uint32_t		 remote_gid;  	uint16_t		 remote_ifmtu; +	uint8_t			 remote_cword;  	uint32_t		 status;  }; @@ -525,19 +552,9 @@ struct ldpd_conf	*parse_config(char *);  int			 cmdline_symset(char *);  /* kroute.c */ -int		 kif_init(void); -int		 kr_init(int);  void		 kif_redistribute(const char *);  int		 kr_change(struct kroute *);  int		 kr_delete(struct kroute *); -void		 kr_shutdown(void); -void		 kr_fib_couple(void); -void		 kr_fib_decouple(void); -void		 kr_change_egress_label(int, int); -void		 kr_show_route(struct imsg *); -void		 kr_ifinfo(char *, pid_t); -struct kif	*kif_findname(char *); -void		 kif_clear(void);  int		 kmpw_set(struct kpw *);  int		 kmpw_unset(struct kpw *); @@ -561,31 +578,46 @@ void		 recoverscope(struct sockaddr_in6 *);  void		 addscope(struct sockaddr_in6 *, uint32_t);  void		 clearscope(struct in6_addr *);  struct sockaddr	*addr2sa(int af, union ldpd_addr *, uint16_t); -void		 sa2addr(struct sockaddr *, int *, union ldpd_addr *); +void		 sa2addr(struct sockaddr *, int *, union ldpd_addr *, +		    in_port_t *); +socklen_t	 sockaddr_len(struct sockaddr *);  /* ldpd.c */ +int			 ldp_write_handler(struct thread *);  void			 main_imsg_compose_ldpe(int, pid_t, void *, uint16_t);  void			 main_imsg_compose_lde(int, pid_t, void *, uint16_t); +int			 main_imsg_compose_both(enum imsg_type, void *, +			    uint16_t);  void			 imsg_event_add(struct imsgev *); -int			 imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, -			    int, void *, uint16_t); +int			 imsg_compose_event(struct imsgev *, uint16_t, uint32_t, +			    pid_t, int, void *, uint16_t);  void			 evbuf_enqueue(struct evbuf *, struct ibuf *);  void			 evbuf_event_add(struct evbuf *); -void			 evbuf_init(struct evbuf *, int, void (*)(int, short, void *), void *); +void			 evbuf_init(struct evbuf *, int, +			    int (*)(struct thread *), void *);  void			 evbuf_clear(struct evbuf *);  struct ldpd_af_conf	*ldp_af_conf_get(struct ldpd_conf *, int);  struct ldpd_af_global	*ldp_af_global_get(struct ldpd_global *, int);  int			 ldp_is_dual_stack(struct ldpd_conf *); +in_addr_t		 ldp_rtr_id_get(struct ldpd_conf *); +int			 ldp_reload(struct ldpd_conf *); +struct ldpd_conf	*ldp_dup_config(struct ldpd_conf *); +void			 ldp_clear_config(struct ldpd_conf *);  void			 merge_config(struct ldpd_conf *, struct ldpd_conf *);  struct ldpd_conf	*config_new_empty(void);  void			 config_clear(struct ldpd_conf *);  /* socket.c */  int		 ldp_create_socket(int, enum socket_type); +void		 sock_set_nonblock(int); +void		 sock_set_cloexec(int);  void		 sock_set_recvbuf(int);  int		 sock_set_reuse(int, int);  int		 sock_set_bindany(int, int); +int		 sock_set_md5sig(int, int, union ldpd_addr *, const char *);  int		 sock_set_ipv4_tos(int, int); +int		 sock_set_ipv4_pktinfo(int, int); +int		 sock_set_ipv4_recvdstaddr(int, int);  int		 sock_set_ipv4_recvif(int, int);  int		 sock_set_ipv4_minttl(int, int);  int		 sock_set_ipv4_ucast_ttl(int fd, int); @@ -600,7 +632,19 @@ int		 sock_set_ipv6_mcast_hops(int, int);  int		 sock_set_ipv6_mcast(struct iface *);  int		 sock_set_ipv6_mcast_loop(int); -/* printconf.c */ -void	print_config(struct ldpd_conf *); +/* quagga */ +extern struct thread_master	*master; + +/* ldp_zebra.c */ +void		ldp_zebra_init(struct thread_master *); + +/* compatibility */ +#ifndef __OpenBSD__ +#define __IPV6_ADDR_MC_SCOPE(a)		((a)->s6_addr[1] & 0x0f) +#define __IPV6_ADDR_SCOPE_INTFACELOCAL	0x01 +#define	IN6_IS_ADDR_MC_INTFACELOCAL(a)	\ +	(IN6_IS_ADDR_MULTICAST(a) &&	\ +	(__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL)) +#endif  #endif	/* _LDPD_H_ */ diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 1b4d2a67e7..aef33c8e37 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -19,70 +19,97 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <stdlib.h> -#include <signal.h> -#include <string.h> -#include <pwd.h> -#include <unistd.h> -#include <arpa/inet.h> -#include <errno.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "lde.h"  #include "control.h"  #include "log.h" - -static void	 ldpe_sig_handler(int, short, void *); -static __dead void ldpe_shutdown(void); -static void	 ldpe_dispatch_main(int, short, void *); -static void	 ldpe_dispatch_lde(int, short, void *); -static void	 ldpe_dispatch_pfkey(int, short, void *); +#include "ldp_debug.h" + +#include <lib/log.h> +#include "memory.h" +#include "privs.h" +#include "sigevent.h" + +static void	 ldpe_shutdown(void); +static int	 ldpe_dispatch_main(struct thread *); +static int	 ldpe_dispatch_lde(struct thread *); +#ifdef __OpenBSD__ +static int	 ldpe_dispatch_pfkey(struct thread *); +#endif  static void	 ldpe_setup_sockets(int, int, int, int);  static void	 ldpe_close_sockets(int);  static void	 ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int);  struct ldpd_conf	*leconf; +#ifdef __OpenBSD__  struct ldpd_sysdep	 sysdep; +#endif  static struct imsgev	*iev_main;  static struct imsgev	*iev_lde; -static struct event	 pfkey_ev; +#ifdef __OpenBSD__ +static struct thread	*pfkey_ev; +#endif -/* ARGSUSED */ +/* Master of threads. */ +struct thread_master *master; + +/* ldpe privileges */ +static zebra_capabilities_t _caps_p [] = +{ +	ZCAP_BIND, +	ZCAP_NET_ADMIN +}; + +struct zebra_privs_t ldpe_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) +	.user = QUAGGA_USER, +	.group = QUAGGA_GROUP, +#endif +#if defined(VTY_GROUP) +	.vty_group = VTY_GROUP, +#endif +	.caps_p = _caps_p, +	.cap_num_p = array_size(_caps_p), +	.cap_num_i = 0 +}; + +/* SIGINT / SIGTERM handler. */  static void -ldpe_sig_handler(int sig, short event, void *bula) +sigint(void)  { -	switch (sig) { -	case SIGINT: -	case SIGTERM: -		ldpe_shutdown(); -		/* NOTREACHED */ -	default: -		fatalx("unexpected signal"); -	} +	ldpe_shutdown();  } +static struct quagga_signal_t ldpe_signals[] = +{ +	{ +		.signal = SIGINT, +		.handler = &sigint, +	}, +	{ +		.signal = SIGTERM, +		.handler = &sigint, +	}, +}; +  /* label distribution protocol engine */  void -ldpe(int debug, int verbose) +ldpe(const char *user, const char *group)  { -	struct passwd		*pw; -	struct event		 ev_sigint, ev_sigterm; +	struct thread		 thread;  	leconf = config_new_empty(); -	log_init(debug); -	log_verbose(verbose); - +#ifdef HAVE_SETPROCTITLE  	setproctitle("ldp engine"); +#endif  	ldpd_process = PROC_LDP_ENGINE; -	/* create ldpd control socket outside chroot */ -	if (control_init() == -1) -		fatalx("control socket setup failed"); -  	LIST_INIT(&global.addr_list);  	LIST_INIT(&global.adj_list);  	TAILQ_INIT(&global.pending_conns); @@ -90,50 +117,46 @@ ldpe(int debug, int verbose)  		fatal("inet_pton");  	if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1)  		fatal("inet_pton"); +#ifdef __OpenBSD__  	global.pfkeysock = pfkey_init(); +#endif -	if ((pw = getpwnam(LDPD_USER)) == NULL) -		fatal("getpwnam"); - -	if (chroot(pw->pw_dir) == -1) -		fatal("chroot"); -	if (chdir("/") == -1) -		fatal("chdir(\"/\")"); +	/* drop privileges */ +	if (user) +		ldpe_privs.user = user; +	if (group) +		ldpe_privs.group = group; +	zprivs_init(&ldpe_privs); -	if (setgroups(1, &pw->pw_gid) || -	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || -	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) -		fatal("can't drop privileges"); +	if (control_init() == -1) +		fatalx("control socket setup failed"); +#ifdef HAVE_PLEDGE  	if (pledge("stdio cpath inet mcast recvfd", NULL) == -1)  		fatal("pledge"); +#endif -	event_init(); +  	master = thread_master_create();  	accept_init();  	/* setup signal handler */ -	signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL); -	signal_set(&ev_sigterm, SIGTERM, ldpe_sig_handler, NULL); -	signal_add(&ev_sigint, NULL); -	signal_add(&ev_sigterm, NULL); -	signal(SIGPIPE, SIG_IGN); -	signal(SIGHUP, SIG_IGN); +	signal_init(master, array_size(ldpe_signals), ldpe_signals);  	/* setup pipe and event handler to the parent process */  	if ((iev_main = malloc(sizeof(struct imsgev))) == NULL)  		fatal(NULL);  	imsg_init(&iev_main->ibuf, 3); -	iev_main->handler = ldpe_dispatch_main; -	iev_main->events = EV_READ; -	event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, -	    iev_main->handler, iev_main); -	event_add(&iev_main->ev, NULL); - -	if (sysdep.no_pfkey == 0) { -		event_set(&pfkey_ev, global.pfkeysock, EV_READ | EV_PERSIST, -		    ldpe_dispatch_pfkey, NULL); -		event_add(&pfkey_ev, NULL); -	} +	iev_main->handler_read = ldpe_dispatch_main; +	iev_main->ev_read = thread_add_read(master, iev_main->handler_read, +	    iev_main, iev_main->ibuf.fd); +	iev_main->handler_write = ldp_write_handler; +	iev_main->ev_write = NULL; + +#ifdef __OpenBSD__ +	if (sysdep.no_pfkey == 0) +		pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, +		    NULL, global.pfkeysock); +#endif  	/* mark sockets as closed */  	global.ipv4.ldp_disc_socket = -1; @@ -150,12 +173,12 @@ ldpe(int debug, int verbose)  	if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL)  		fatal(__func__); -	event_dispatch(); - -	ldpe_shutdown(); +	/* Fetch next active thread. */ +	while (thread_fetch(master, &thread)) +		thread_call(&thread);  } -static __dead void +static void  ldpe_shutdown(void)  {  	struct if_addr		*if_addr; @@ -172,10 +195,12 @@ ldpe_shutdown(void)  	control_cleanup();  	config_clear(leconf); +#ifdef __OpenBSD__  	if (sysdep.no_pfkey == 0) { -		event_del(&pfkey_ev); +		THREAD_READ_OFF(pfkey_ev);  		close(global.pfkeysock);  	} +#endif  	ldpe_close_sockets(AF_INET);  	ldpe_close_sockets(AF_INET6); @@ -212,8 +237,8 @@ ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data,  }  /* ARGSUSED */ -static void -ldpe_dispatch_main(int fd, short event, void *bula) +static int +ldpe_dispatch_main(struct thread *thread)  {  	static struct ldpd_conf	*nconf;  	struct iface		*niface; @@ -223,7 +248,8 @@ ldpe_dispatch_main(int fd, short event, void *bula)  	struct l2vpn_if		*nlif;  	struct l2vpn_pw		*npw;  	struct imsg		 imsg; -	struct imsgev		*iev = bula; +	int			 fd = THREAD_FD(thread); +	struct imsgev		*iev = THREAD_ARG(thread);  	struct imsgbuf		*ibuf = &iev->ibuf;  	struct iface		*iface = NULL;  	struct kif		*kif; @@ -233,21 +259,17 @@ ldpe_dispatch_main(int fd, short event, void *bula)  	static int		 edisc_socket = -1;  	static int		 session_socket = -1;  	struct nbr		*nbr; +#ifdef __OpenBSD__  	struct nbr_params	*nbrp; +#endif  	int			 n, shut = 0; -	if (event & EV_READ) { -		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) -			fatal("imsg_read error"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} -	if (event & EV_WRITE) { -		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) -			fatal("ldpe_dispatch_main: msgbuf_write"); -		if (n == 0) -			shut = 1; -	} +	iev->ev_read = NULL; + +	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) +		fatal("imsg_read error"); +	if (n == 0)	/* connection closed */ +		shut = 1;  	for (;;) {  		if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -262,12 +284,11 @@ ldpe_dispatch_main(int fd, short event, void *bula)  				fatalx("IFSTATUS imsg with wrong len");  			kif = imsg.data; -			iface = if_lookup(leconf, kif->ifindex); +			iface = if_lookup_name(leconf, kif->ifname);  			if (!iface)  				break; -			iface->flags = kif->flags; -			iface->linkstate = kif->link_state; +			if_update_info(iface, kif);  			if_update(iface, AF_UNSPEC);  			break;  		case IMSG_NEWADDR: @@ -299,11 +320,11 @@ ldpe_dispatch_main(int fd, short event, void *bula)  			if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL)  				fatal(NULL);  			imsg_init(&iev_lde->ibuf, fd); -			iev_lde->handler = ldpe_dispatch_lde; -			iev_lde->events = EV_READ; -			event_set(&iev_lde->ev, iev_lde->ibuf.fd, -			    iev_lde->events, iev_lde->handler, iev_lde); -			event_add(&iev_lde->ev, NULL); +			iev_lde->handler_read = ldpe_dispatch_lde; +			iev_lde->ev_read = thread_add_read(master, +			    iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd); +			iev_lde->handler_write = ldp_write_handler; +			iev_lde->ev_write = NULL;  			break;  		case IMSG_CLOSE_SOCKETS:  			af = imsg.hdr.peerid; @@ -312,7 +333,9 @@ ldpe_dispatch_main(int fd, short event, void *bula)  				if (nbr->af != af)  					continue;  				session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__  				pfkey_remove(nbr); +#endif  			}  			ldpe_close_sockets(af);  			if_update_all(af); @@ -366,13 +389,25 @@ ldpe_dispatch_main(int fd, short event, void *bula)  					continue;  				nbr->laddr = (ldp_af_conf_get(leconf,  				    af))->trans_addr; +#ifdef __OpenBSD__  				nbrp = nbr_params_find(leconf, nbr->id);  				if (nbrp && pfkey_establish(nbr, nbrp) == -1)  					fatalx("pfkey setup failed"); +#endif  				if (nbr_session_active_role(nbr))  					nbr_establish_connection(nbr);  			}  			break; +		case IMSG_RTRID_UPDATE: +			memcpy(&global.rtr_id, imsg.data, +			    sizeof(global.rtr_id)); +			if (leconf->rtr_id.s_addr == INADDR_ANY) { +				ldpe_reset_nbrs(AF_INET); +				ldpe_reset_nbrs(AF_INET6); +			} +			if_update_all(AF_UNSPEC); +			tnbr_update_all(AF_UNSPEC); +			break;  		case IMSG_RECONF_CONF:  			if ((nconf = malloc(sizeof(struct ldpd_conf))) ==  			    NULL) @@ -418,6 +453,7 @@ ldpe_dispatch_main(int fd, short event, void *bula)  			LIST_INIT(&nl2vpn->if_list);  			LIST_INIT(&nl2vpn->pw_list); +			LIST_INIT(&nl2vpn->pw_inactive_list);  			LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry);  			break; @@ -437,17 +473,30 @@ ldpe_dispatch_main(int fd, short event, void *bula)  			npw->l2vpn = nl2vpn;  			LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry);  			break; +		case IMSG_RECONF_L2VPN_IPW: +			if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) +				fatal(NULL); +			memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); + +			npw->l2vpn = nl2vpn; +			LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry); +			break;  		case IMSG_RECONF_END:  			merge_config(leconf, nconf);  			nconf = NULL;  			global.conf_seqnum++;  			break; -		case IMSG_CTL_KROUTE: -		case IMSG_CTL_KROUTE_ADDR: -		case IMSG_CTL_IFINFO:  		case IMSG_CTL_END:  			control_imsg_relay(&imsg);  			break; +		case IMSG_DEBUG_UPDATE: +			if (imsg.hdr.len != IMSG_HEADER_SIZE + +			    sizeof(ldp_debug)) { +				log_warnx("%s: wrong imsg len", __func__); +				break; +			} +			memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug)); +			break;  		default:  			log_debug("ldpe_dispatch_main: error handling imsg %d",  			    imsg.hdr.type); @@ -458,17 +507,20 @@ ldpe_dispatch_main(int fd, short event, void *bula)  	if (!shut)  		imsg_event_add(iev);  	else { -		/* this pipe is dead, so remove the event handler */ -		event_del(&iev->ev); -		event_loopexit(NULL); +		/* this pipe is dead, so remove the event handlers and exit */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		ldpe_shutdown();  	} + +	return (0);  }  /* ARGSUSED */ -static void -ldpe_dispatch_lde(int fd, short event, void *bula) +static int +ldpe_dispatch_lde(struct thread *thread)  { -	struct imsgev		*iev = bula; +	struct imsgev		*iev = THREAD_ARG(thread);  	struct imsgbuf		*ibuf = &iev->ibuf;  	struct imsg		 imsg;  	struct map		 map; @@ -476,18 +528,12 @@ ldpe_dispatch_lde(int fd, short event, void *bula)  	int			 n, shut = 0;  	struct nbr		*nbr = NULL; -	if (event & EV_READ) { -		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) -			fatal("imsg_read error"); -		if (n == 0)	/* connection closed */ -			shut = 1; -	} -	if (event & EV_WRITE) { -		if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) -			fatal("ldpe_dispatch_lde: msgbuf_write"); -		if (n == 0) -			shut = 1; -	} +	iev->ev_read = NULL; + +	if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) +		fatal("imsg_read error"); +	if (n == 0)	/* connection closed */ +		shut = 1;  	for (;;) {  		if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -592,22 +638,31 @@ ldpe_dispatch_lde(int fd, short event, void *bula)  	if (!shut)  		imsg_event_add(iev);  	else { -		/* this pipe is dead, so remove the event handler */ -		event_del(&iev->ev); -		event_loopexit(NULL); +		/* this pipe is dead, so remove the event handlers and exit */ +		THREAD_READ_OFF(iev->ev_read); +		THREAD_WRITE_OFF(iev->ev_write); +		ldpe_shutdown();  	} + +	return (0);  } +#ifdef __OpenBSD__  /* ARGSUSED */ -static void -ldpe_dispatch_pfkey(int fd, short event, void *bula) +static int +ldpe_dispatch_pfkey(struct thread *thread)  { -	if (event & EV_READ) { -		if (pfkey_read(fd, NULL) == -1) { -			fatal("pfkey_read failed, exiting..."); -		} -	} +	int	 fd = THREAD_FD(thread); + +	pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, +	    NULL, global.pfkeysock); + +	if (pfkey_read(fd, NULL) == -1) +		fatal("pfkey_read failed, exiting..."); + +	return (0);  } +#endif /* __OpenBSD__ */  static void  ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, @@ -619,15 +674,13 @@ ldpe_setup_sockets(int af, int disc_socket, int edisc_socket,  	/* discovery socket */  	af_global->ldp_disc_socket = disc_socket; -	event_set(&af_global->disc_ev, af_global->ldp_disc_socket, -	    EV_READ|EV_PERSIST, disc_recv_packet, NULL); -	event_add(&af_global->disc_ev, NULL); +	af_global->disc_ev = thread_add_read(master, disc_recv_packet, +	    &af_global->disc_ev, af_global->ldp_disc_socket);  	/* extended discovery socket */  	af_global->ldp_edisc_socket = edisc_socket; -	event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket, -	    EV_READ|EV_PERSIST, disc_recv_packet, NULL); -	event_add(&af_global->edisc_ev, NULL); +	af_global->edisc_ev = thread_add_read(master, disc_recv_packet, +	    &af_global->edisc_ev, af_global->ldp_edisc_socket);  	/* session socket */  	af_global->ldp_session_socket = session_socket; @@ -642,16 +695,14 @@ ldpe_close_sockets(int af)  	af_global = ldp_af_global_get(&global, af);  	/* discovery socket */ -	if (event_initialized(&af_global->disc_ev)) -		event_del(&af_global->disc_ev); +	THREAD_READ_OFF(af_global->disc_ev);  	if (af_global->ldp_disc_socket != -1) {  		close(af_global->ldp_disc_socket);  		af_global->ldp_disc_socket = -1;  	}  	/* extended discovery socket */ -	if (event_initialized(&af_global->edisc_ev)) -		event_del(&af_global->edisc_ev); +	THREAD_READ_OFF(af_global->edisc_ev);  	if (af_global->ldp_edisc_socket != -1) {  		close(af_global->ldp_edisc_socket);  		af_global->ldp_edisc_socket = -1; @@ -745,24 +796,57 @@ ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx)  void  ldpe_adj_ctl(struct ctl_conn *c)  { -	struct nbr	*nbr; -	struct adj	*adj; -	struct ctl_adj	*actl; +	struct iface		*iface; +	struct tnbr		*tnbr; +	struct adj		*adj; +	struct ctl_adj		*actl; +	struct ctl_disc_if	 ictl; +	struct ctl_disc_tnbr	 tctl; -	RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { -		LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { +	imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0); + +	LIST_FOREACH(iface, &leconf->iface_list, entry) { +		memset(&ictl, 0, sizeof(ictl)); +		ictl.active_v4 = (iface->ipv4.state == IF_STA_ACTIVE); +		ictl.active_v6 = (iface->ipv6.state == IF_STA_ACTIVE); + +		if (!ictl.active_v4 && !ictl.active_v6) +			continue; + +		strlcpy(ictl.name, iface->name, sizeof(ictl.name)); +		if (LIST_EMPTY(&iface->ipv4.adj_list) && +		    LIST_EMPTY(&iface->ipv6.adj_list)) +			ictl.no_adj = 1; +		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_IFACE, 0, 0, +		    -1, &ictl, sizeof(ictl)); + +		LIST_FOREACH(adj, &iface->ipv4.adj_list, ia_entry) {  			actl = adj_to_ctl(adj); -			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, +			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, +			    0, 0, -1, actl, sizeof(struct ctl_adj)); +		} +		LIST_FOREACH(adj, &iface->ipv6.adj_list, ia_entry) { +			actl = adj_to_ctl(adj); +			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ,  			    0, 0, -1, actl, sizeof(struct ctl_adj));  		}  	} -	/* show adjacencies not associated with any neighbor */ -	LIST_FOREACH(adj, &global.adj_list, global_entry) { -		if (adj->nbr != NULL) + +	LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) { +		memset(&tctl, 0, sizeof(tctl)); +		tctl.af = tnbr->af; +		tctl.addr = tnbr->addr; +		if (tnbr->adj == NULL) +			tctl.no_adj = 1; + +		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_TNBR, 0, 0, +		    -1, &tctl, sizeof(tctl)); + +		if (tnbr->adj == NULL)  			continue; -		actl = adj_to_ctl(adj); -		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, +		actl = adj_to_ctl(tnbr->adj); +		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, 0, 0,  		    -1, actl, sizeof(struct ctl_adj));  	} @@ -772,13 +856,27 @@ ldpe_adj_ctl(struct ctl_conn *c)  void  ldpe_nbr_ctl(struct ctl_conn *c)  { +	struct adj	*adj; +	struct ctl_adj	*actl;  	struct nbr	*nbr;  	struct ctl_nbr	*nctl;  	RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { +		if (nbr->state == NBR_STA_PRESENT) +			continue; +  		nctl = nbr_to_ctl(nbr);  		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl,  		    sizeof(struct ctl_nbr)); + +		LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { +			actl = adj_to_ctl(adj); +			imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_DISC, +			    0, 0, -1, actl, sizeof(struct ctl_adj)); +		} + +		imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_END, 0, 0, -1, +		    NULL, 0);  	}  	imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0);  } diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index e640dd67db..aab1a7fd9b 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -21,10 +21,11 @@  #ifndef _LDPE_H_  #define _LDPE_H_ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> +#include "openbsd-queue.h" +#include "openbsd-tree.h" +#ifdef __OpenBSD__  #include <net/pfkeyv2.h> +#endif  #include "ldpd.h" @@ -48,7 +49,7 @@ struct adj {  	struct nbr		*nbr;  	int			 ds_tlv;  	struct hello_source	 source; -	struct event		 inactivity_timer; +	struct thread		*inactivity_timer;  	uint16_t		 holdtime;  	union ldpd_addr		 trans_addr;  }; @@ -58,18 +59,20 @@ struct tcp_conn {  	int			 fd;  	struct ibuf_read	*rbuf;  	struct evbuf		 wbuf; -	struct event		 rev; +	struct thread		*rev; +	in_port_t		 lport; +	in_port_t		 rport;  };  struct nbr {  	RB_ENTRY(nbr)		 id_tree, addr_tree, pid_tree;  	struct tcp_conn		*tcp;  	LIST_HEAD(, adj)	 adj_list;	/* adjacencies */ -	struct event		 ev_connect; -	struct event		 keepalive_timer; -	struct event		 keepalive_timeout; -	struct event		 init_timeout; -	struct event		 initdelay_timer; +	struct thread		*ev_connect; +	struct thread		*keepalive_timer; +	struct thread		*keepalive_timeout; +	struct thread		*init_timeout; +	struct thread		*initdelay_timer;  	struct mapping_head	 mapping_list;  	struct mapping_head	 withdraw_list; @@ -117,7 +120,7 @@ struct pending_conn {  	int				 fd;  	int				 af;  	union ldpd_addr			 addr; -	struct event			 ev_timeout; +	struct thread			*ev_timeout;  };  #define PENDING_CONN_TIMEOUT	5 @@ -139,7 +142,7 @@ extern struct nbr_pid_head	 nbrs_by_pid;  /* accept.c */  void	accept_init(void); -int	accept_add(int, void (*)(int, short, void *), void *); +int	accept_add(int, int (*)(struct thread *), void *);  void	accept_del(int);  void	accept_pause(void);  void	accept_unpause(void); @@ -180,7 +183,7 @@ int	 tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *,  	    uint16_t, struct map *);  /* ldpe.c */ -void		 ldpe(int, int); +void		 ldpe(const char *, const char *);  int		 ldpe_imsg_compose_parent(int, pid_t, void *,  		    uint16_t);  int		 ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, @@ -200,11 +203,15 @@ void		 mapping_list_clr(struct mapping_head *);  struct iface	*if_new(struct kif *);  void		 if_exit(struct iface *);  struct iface	*if_lookup(struct ldpd_conf *, unsigned short); +struct iface	*if_lookup_name(struct ldpd_conf *, const char *); +void		 if_update_info(struct iface *, struct kif *);  struct iface_af *iface_af_get(struct iface *, int);  void		 if_addr_add(struct kaddr *);  void		 if_addr_del(struct kaddr *);  void		 if_update(struct iface *, int);  void		 if_update_all(int); +uint16_t	 if_get_hello_holdtime(struct iface_af *); +uint16_t	 if_get_hello_interval(struct iface_af *);  struct ctl_iface *if_to_ctl(struct iface_af *);  in_addr_t	 if_get_ipv4_addr(struct iface *); @@ -216,11 +223,13 @@ struct adj	*adj_find(struct hello_source *);  int		 adj_get_af(struct adj *adj);  void		 adj_start_itimer(struct adj *);  void		 adj_stop_itimer(struct adj *); -struct tnbr	*tnbr_new(struct ldpd_conf *, int, union ldpd_addr *); +struct tnbr	*tnbr_new(int, union ldpd_addr *);  struct tnbr	*tnbr_find(struct ldpd_conf *, int, union ldpd_addr *);  struct tnbr	*tnbr_check(struct tnbr *);  void		 tnbr_update(struct tnbr *);  void		 tnbr_update_all(int); +uint16_t	 tnbr_get_hello_holdtime(struct tnbr *); +uint16_t	 tnbr_get_hello_interval(struct tnbr *);  struct ctl_adj	*adj_to_ctl(struct adj *);  /* neighbor.c */ @@ -255,8 +264,8 @@ int			 gen_ldp_hdr(struct ibuf *, uint16_t);  int			 gen_msg_hdr(struct ibuf *, uint16_t, uint16_t);  int			 send_packet(int, int, union ldpd_addr *,  			    struct iface_af *, void *, size_t); -void			 disc_recv_packet(int, short, void *); -void			 session_accept(int, short, void *); +int			 disc_recv_packet(struct thread *); +int			 session_accept(struct thread *);  void			 session_accept_nbr(struct nbr *, int);  void			 session_shutdown(struct nbr *, uint32_t, uint32_t,  			    uint32_t); @@ -268,10 +277,12 @@ struct pending_conn	*pending_conn_find(int, union ldpd_addr *);  char	*pkt_ptr;	/* packet buffer */  /* pfkey.c */ +#ifdef __OpenBSD__  int	pfkey_read(int, struct sadb_msg *);  int	pfkey_establish(struct nbr *, struct nbr_params *);  int	pfkey_remove(struct nbr *);  int	pfkey_init(void); +#endif  /* l2vpn.c */  void	ldpe_l2vpn_init(struct l2vpn *); diff --git a/ldpd/log.c b/ldpd/log.c index e14b6e51ea..77efdb4714 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -16,53 +16,23 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netmpls/mpls.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <netdb.h> -#include <limits.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "lde.h"  #include "log.h" +#include <lib/log.h> +#include "mpls.h" +  static const char * const procnames[] = {  	"parent",  	"ldpe",  	"lde"  }; -static void	 vlog(int, const char *, va_list); - -static int	 debug; -static int	 verbose; - -void -log_init(int n_debug) -{ -	extern char	*__progname; - -	debug = n_debug; - -	if (!debug) -		openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); - -	tzset(); -} - -void -log_verbose(int v) -{ -	verbose = v; -} +void		 vlog(int, const char *, va_list);  void  logit(int pri, const char *fmt, ...) @@ -74,23 +44,24 @@ logit(int pri, const char *fmt, ...)  	va_end(ap);  } -static void +void  vlog(int pri, const char *fmt, va_list ap)  { -	char	*nfmt; +	char	 buf[1024]; -	if (debug) { -		/* best effort in out of mem situations */ -		if (asprintf(&nfmt, "%s\n", fmt) == -1) { -			vfprintf(stderr, fmt, ap); -			fprintf(stderr, "\n"); -		} else { -			vfprintf(stderr, nfmt, ap); -			free(nfmt); -		} -		fflush(stderr); -	} else -		vsyslog(pri, fmt, ap); +	switch (ldpd_process) { +	case PROC_LDE_ENGINE: +		vsnprintf(buf, sizeof(buf), fmt, ap); +		lde_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1); +		break; +	case PROC_LDP_ENGINE: +		vsnprintf(buf, sizeof(buf), fmt, ap); +		ldpe_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1); +		break; +	case PROC_MAIN: +		vzlog(NULL, pri, fmt, ap); +		break; +	}  }  void @@ -138,15 +109,23 @@ log_info(const char *emsg, ...)  }  void +log_notice(const char *emsg, ...) +{ +	va_list	 ap; + +	va_start(ap, emsg); +	vlog(LOG_NOTICE, emsg, ap); +	va_end(ap); +} + +void  log_debug(const char *emsg, ...)  {  	va_list	 ap; -	if (verbose & LDPD_OPT_VERBOSE) { -		va_start(ap, emsg); -		vlog(LOG_DEBUG, emsg, ap); -		va_end(ap); -	} +	va_start(ap, emsg); +	vlog(LOG_DEBUG, emsg, ap); +	va_end(ap);  }  void @@ -183,7 +162,7 @@ log_sockaddr(void *vp)  	round = (round + 1) % NUM_LOGS; -	if (getnameinfo(sa, sa->sa_len, buf[round], NI_MAXHOST, NULL, 0, +	if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0,  	    NI_NUMERICHOST))  		return ("(unknown)");  	else @@ -196,7 +175,9 @@ log_in6addr(const struct in6_addr *addr)  	struct sockaddr_in6	sa_in6;  	memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN  	sa_in6.sin6_len = sizeof(sa_in6); +#endif  	sa_in6.sin6_family = AF_INET6;  	sa_in6.sin6_addr = *addr; @@ -211,7 +192,9 @@ log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex)  	struct sockaddr_in6	sa_in6;  	memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN  	sa_in6.sin6_len = sizeof(sa_in6); +#endif  	sa_in6.sin6_family = AF_INET6;  	sa_in6.sin6_addr = *addr; @@ -275,6 +258,39 @@ log_label(uint32_t label)  	return (buf);  } +const char * +log_time(time_t t) +{ +	char		*buf; +	static char	 tfbuf[TF_BUFS][TF_LEN];	/* ring buffer */ +	static int	 idx = 0; +	unsigned int	 sec, min, hrs, day, week; + +	buf = tfbuf[idx++]; +	if (idx == TF_BUFS) +		idx = 0; + +	week = t; + +	sec = week % 60; +	week /= 60; +	min = week % 60; +	week /= 60; +	hrs = week % 24; +	week /= 24; +	day = week % 7; +	week /= 7; + +	if (week > 0) +		snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs); +	else if (day > 0) +		snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); +	else +		snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); + +	return (buf); +} +  char *  log_hello_src(const struct hello_source *src)  { @@ -365,8 +381,10 @@ af_name(int af)  		return ("ipv4");  	case AF_INET6:  		return ("ipv6"); +#ifdef AF_MPLS  	case AF_MPLS:  		return ("mpls"); +#endif  	default:  		return ("UNKNOWN");  	} @@ -564,37 +582,3 @@ pw_type_name(uint16_t pw_type)  		return (buf);  	}  } - -static char *msgtypes[] = { -	"", -	"RTM_ADD: Add Route", -	"RTM_DELETE: Delete Route", -	"RTM_CHANGE: Change Metrics or flags", -	"RTM_GET: Report Metrics", -	"RTM_LOSING: Kernel Suspects Partitioning", -	"RTM_REDIRECT: Told to use different route", -	"RTM_MISS: Lookup failed on this address", -	"RTM_LOCK: fix specified metrics", -	"RTM_OLDADD: caused by SIOCADDRT", -	"RTM_OLDDEL: caused by SIOCDELRT", -	"RTM_RESOLVE: Route created by cloning", -	"RTM_NEWADDR: address being added to iface", -	"RTM_DELADDR: address being removed from iface", -	"RTM_IFINFO: iface status change", -	"RTM_IFANNOUNCE: iface arrival/departure", -	"RTM_DESYNC: route socket overflow", -}; - -void -log_rtmsg(unsigned char rtm_type) -{ -	if (!(verbose & LDPD_OPT_VERBOSE2)) -		return; - -	if (rtm_type > 0 && -	    rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0])) -		log_debug("kernel message: %s", msgtypes[rtm_type]); -	else -		log_debug("kernel message: rtm_type %d out of range", -		    rtm_type); -} diff --git a/ldpd/log.h b/ldpd/log.h index 94c463041d..4d6da43cac 100644 --- a/ldpd/log.h +++ b/ldpd/log.h @@ -26,8 +26,6 @@ union ldpd_addr;  struct hello_source;  struct fec; -void		 log_init(int); -void		 log_verbose(int);  void		 logit(int, const char *, ...)  			__attribute__((__format__ (printf, 2, 3)));  void		 log_warn(const char *, ...) @@ -36,17 +34,22 @@ void		 log_warnx(const char *, ...)  			__attribute__((__format__ (printf, 1, 2)));  void		 log_info(const char *, ...)  			__attribute__((__format__ (printf, 1, 2))); +void		 log_notice(const char *, ...) +			__attribute__((__format__ (printf, 1, 2)));  void		 log_debug(const char *, ...)  			__attribute__((__format__ (printf, 1, 2))); -void		 fatal(const char *) __dead +void		 fatal(const char *) +			__attribute__ ((noreturn))  			__attribute__((__format__ (printf, 1, 0))); -void		 fatalx(const char *) __dead +void		 fatalx(const char *) +			__attribute__ ((noreturn))  			__attribute__((__format__ (printf, 1, 0)));  const char	*log_sockaddr(void *);  const char	*log_in6addr(const struct in6_addr *);  const char	*log_in6addr_scope(const struct in6_addr *, unsigned int);  const char	*log_addr(int, const union ldpd_addr *);  char		*log_label(uint32_t); +const char	*log_time(time_t);  char		*log_hello_src(const struct hello_source *);  const char	*log_map(const struct map *);  const char	*log_fec(const struct fec *); @@ -58,6 +61,5 @@ const char	*if_type_name(enum iface_type);  const char	*msg_name(uint16_t);  const char	*status_code_name(uint32_t);  const char	*pw_type_name(uint16_t); -void		 log_rtmsg(unsigned char);  #endif /* _LOG_H_ */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index d3f83734f5..8376a01549 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -19,14 +19,7 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/time.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h" @@ -37,13 +30,13 @@ static __inline int	 nbr_id_compare(struct nbr *, struct nbr *);  static __inline int	 nbr_addr_compare(struct nbr *, struct nbr *);  static __inline int	 nbr_pid_compare(struct nbr *, struct nbr *);  static void		 nbr_update_peerid(struct nbr *); -static void		 nbr_ktimer(int, short, void *); +static int		 nbr_ktimer(struct thread *);  static void		 nbr_start_ktimer(struct nbr *); -static void		 nbr_ktimeout(int, short, void *); +static int		 nbr_ktimeout(struct thread *);  static void		 nbr_start_ktimeout(struct nbr *); -static void		 nbr_itimeout(int, short, void *); +static int		 nbr_itimeout(struct thread *);  static void		 nbr_start_itimeout(struct nbr *); -static void		 nbr_idtimer(int, short, void *); +static int		 nbr_idtimer(struct thread *);  static int		 nbr_act_session_operational(struct nbr *);  static void		 nbr_send_labelmappings(struct nbr *); @@ -266,15 +259,17 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr,  	TAILQ_INIT(&nbr->release_list);  	TAILQ_INIT(&nbr->abortreq_list); -	/* set event structures */ -	evtimer_set(&nbr->keepalive_timeout, nbr_ktimeout, nbr); -	evtimer_set(&nbr->keepalive_timer, nbr_ktimer, nbr); -	evtimer_set(&nbr->init_timeout, nbr_itimeout, nbr); -	evtimer_set(&nbr->initdelay_timer, nbr_idtimer, nbr); -  	nbrp = nbr_params_find(leconf, nbr->id); -	if (nbrp && pfkey_establish(nbr, nbrp) == -1) -		fatalx("pfkey setup failed"); +	if (nbrp) { +#ifdef __OpenBSD__ +		if (pfkey_establish(nbr, nbrp) == -1) +			fatalx("pfkey setup failed"); +#else +		sock_set_md5sig( +		    (ldp_af_global_get(&global, nbr->af))->ldp_session_socket, +		    nbr->af, &nbr->raddr, nbrp->auth.md5key); +#endif +	}  	pconn = pending_conn_find(nbr->af, &nbr->raddr);  	if (pconn) { @@ -291,10 +286,16 @@ nbr_del(struct nbr *nbr)  	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));  	nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); +#ifdef __OpenBSD__  	pfkey_remove(nbr); +#else +	sock_set_md5sig( +	    (ldp_af_global_get(&global, nbr->af))->ldp_session_socket, +	    nbr->af, &nbr->raddr, NULL); +#endif  	if (nbr_pending_connect(nbr)) -		event_del(&nbr->ev_connect); +		THREAD_WRITE_OFF(nbr->ev_connect);  	nbr_stop_ktimer(nbr);  	nbr_stop_ktimeout(nbr);  	nbr_stop_itimeout(nbr); @@ -382,176 +383,168 @@ nbr_session_active_role(struct nbr *nbr)  /* Keepalive timer: timer to send keepalive message to neighbors */ -static void -nbr_ktimer(int fd, short event, void *arg) +static int +nbr_ktimer(struct thread *thread)  { -	struct nbr	*nbr = arg; +	struct nbr	*nbr = THREAD_ARG(thread); +	nbr->keepalive_timer = NULL;  	send_keepalive(nbr);  	nbr_start_ktimer(nbr); + +	return (0);  }  static void  nbr_start_ktimer(struct nbr *nbr)  { -	struct timeval	 tv; +	int		 secs;  	/* send three keepalives per period */ -	timerclear(&tv); -	tv.tv_sec = (time_t)(nbr->keepalive / KEEPALIVE_PER_PERIOD); -	if (evtimer_add(&nbr->keepalive_timer, &tv) == -1) -		fatal(__func__); +	secs = nbr->keepalive / KEEPALIVE_PER_PERIOD; +	THREAD_TIMER_OFF(nbr->keepalive_timer); +	nbr->keepalive_timer = thread_add_timer(master, nbr_ktimer, nbr, secs);  }  void  nbr_stop_ktimer(struct nbr *nbr)  { -	if (evtimer_pending(&nbr->keepalive_timer, NULL) && -	    evtimer_del(&nbr->keepalive_timer) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(nbr->keepalive_timer);  }  /* Keepalive timeout: if the nbr hasn't sent keepalive */ -static void -nbr_ktimeout(int fd, short event, void *arg) +static int +nbr_ktimeout(struct thread *thread)  { -	struct nbr *nbr = arg; +	struct nbr *nbr = THREAD_ARG(thread); + +	nbr->keepalive_timeout = NULL;  	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));  	session_shutdown(nbr, S_KEEPALIVE_TMR, 0, 0); + +	return (0);  }  static void  nbr_start_ktimeout(struct nbr *nbr)  { -	struct timeval	tv; - -	timerclear(&tv); -	tv.tv_sec = nbr->keepalive; - -	if (evtimer_add(&nbr->keepalive_timeout, &tv) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(nbr->keepalive_timeout); +	nbr->keepalive_timeout = thread_add_timer(master, nbr_ktimeout, nbr, +	    nbr->keepalive);  }  void  nbr_stop_ktimeout(struct nbr *nbr)  { -	if (evtimer_pending(&nbr->keepalive_timeout, NULL) && -	    evtimer_del(&nbr->keepalive_timeout) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(nbr->keepalive_timeout);  }  /* Session initialization timeout: if nbr got stuck in the initialization FSM */ -static void -nbr_itimeout(int fd, short event, void *arg) +static int +nbr_itimeout(struct thread *thread)  { -	struct nbr *nbr = arg; +	struct nbr	*nbr = THREAD_ARG(thread);  	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));  	nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); + +	return (0);  }  static void  nbr_start_itimeout(struct nbr *nbr)  { -	struct timeval	 tv; +	int		 secs; -	timerclear(&tv); -	tv.tv_sec = INIT_FSM_TIMEOUT; -	if (evtimer_add(&nbr->init_timeout, &tv) == -1) -		fatal(__func__); +	secs = INIT_FSM_TIMEOUT; +	THREAD_TIMER_OFF(nbr->init_timeout); +	nbr->init_timeout = thread_add_timer(master, nbr_itimeout, nbr, secs);  }  void  nbr_stop_itimeout(struct nbr *nbr)  { -	if (evtimer_pending(&nbr->init_timeout, NULL) && -	    evtimer_del(&nbr->init_timeout) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(nbr->init_timeout);  }  /* Init delay timer: timer to retry to iniziatize session */ -static void -nbr_idtimer(int fd, short event, void *arg) +static int +nbr_idtimer(struct thread *thread)  { -	struct nbr *nbr = arg; +	struct nbr *nbr = THREAD_ARG(thread); + +	nbr->initdelay_timer = NULL;  	log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id));  	nbr_establish_connection(nbr); + +	return (0);  }  void  nbr_start_idtimer(struct nbr *nbr)  { -	struct timeval	tv; - -	timerclear(&tv); +	int	secs; -	tv.tv_sec = INIT_DELAY_TMR; +	secs = INIT_DELAY_TMR;  	switch(nbr->idtimer_cnt) {  	default:  		/* do not further increase the counter */ -		tv.tv_sec = MAX_DELAY_TMR; +		secs = MAX_DELAY_TMR;  		break;  	case 2: -		tv.tv_sec *= 2; +		secs *= 2;  		/* FALLTHROUGH */  	case 1: -		tv.tv_sec *= 2; +		secs *= 2;  		/* FALLTHROUGH */  	case 0:  		nbr->idtimer_cnt++;  		break;  	} -	if (evtimer_add(&nbr->initdelay_timer, &tv) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(nbr->initdelay_timer); +	nbr->initdelay_timer = thread_add_timer(master, nbr_idtimer, nbr, secs);  }  void  nbr_stop_idtimer(struct nbr *nbr)  { -	if (evtimer_pending(&nbr->initdelay_timer, NULL) && -	    evtimer_del(&nbr->initdelay_timer) == -1) -		fatal(__func__); +	THREAD_TIMER_OFF(nbr->initdelay_timer);  }  int  nbr_pending_idtimer(struct nbr *nbr)  { -	if (evtimer_pending(&nbr->initdelay_timer, NULL)) -		return (1); - -	return (0); +	return (nbr->initdelay_timer != NULL);  }  int  nbr_pending_connect(struct nbr *nbr)  { -	if (event_initialized(&nbr->ev_connect) && -	    event_pending(&nbr->ev_connect, EV_WRITE, NULL)) -		return (1); - -	return (0); +	return (nbr->ev_connect != NULL);  } -static void -nbr_connect_cb(int fd, short event, void *arg) +static int +nbr_connect_cb(struct thread *thread)  { -	struct nbr	*nbr = arg; +	struct nbr	*nbr = THREAD_ARG(thread);  	int		 error;  	socklen_t	 len; +	nbr->ev_connect = NULL; +  	len = sizeof(error);  	if (getsockopt(nbr->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {  		log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__); -		return; +		return (0);  	}  	if (error) { @@ -559,10 +552,12 @@ nbr_connect_cb(int fd, short event, void *arg)  		errno = error;  		log_debug("%s: error while connecting to %s: %s", __func__,  		    log_addr(nbr->af, &nbr->raddr), strerror(errno)); -		return; +		return (0);  	}  	nbr_fsm(nbr, NBR_EVT_CONNECT_UP); + +	return (0);  }  int @@ -572,17 +567,20 @@ nbr_establish_connection(struct nbr *nbr)  	struct sockaddr_storage	 remote_sa;  	struct adj		*adj;  	struct nbr_params	*nbrp; +#ifdef __OpenBSD__  	int			 opt = 1; +#endif -	nbr->fd = socket(nbr->af, -	    SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); +	nbr->fd = socket(nbr->af, SOCK_STREAM, 0);  	if (nbr->fd == -1) {  		log_warn("%s: error while creating socket", __func__);  		return (-1);  	} +	sock_set_nonblock(nbr->fd);  	nbrp = nbr_params_find(leconf, nbr->id);  	if (nbrp && nbrp->auth.method == AUTH_MD5SIG) { +#ifdef __OpenBSD__  		if (sysdep.no_pfkey || sysdep.no_md5sig) {  			log_warnx("md5sig configured but not available");  			close(nbr->fd); @@ -594,6 +592,10 @@ nbr_establish_connection(struct nbr *nbr)  			close(nbr->fd);  			return (-1);  		} +#else +		sock_set_md5sig(nbr->fd, nbr->af, &nbr->raddr, +		    nbrp->auth.md5key); +#endif  	}  	memcpy(&local_sa, addr2sa(nbr->af, &nbr->laddr, 0), sizeof(local_sa)); @@ -603,7 +605,7 @@ nbr_establish_connection(struct nbr *nbr)  		addscope((struct sockaddr_in6 *)&remote_sa, nbr->raddr_scope);  	if (bind(nbr->fd, (struct sockaddr *)&local_sa, -	    local_sa.ss_len) == -1) { +	    sockaddr_len((struct sockaddr *)&local_sa)) == -1) {  		log_warn("%s: error while binding socket to %s", __func__,  		    log_sockaddr((struct sockaddr *)&local_sa));  		close(nbr->fd); @@ -624,11 +626,10 @@ nbr_establish_connection(struct nbr *nbr)  		    adj->source.target);  	if (connect(nbr->fd, (struct sockaddr *)&remote_sa, -	    remote_sa.ss_len) == -1) { +	    sockaddr_len((struct sockaddr *)&remote_sa)) == -1) {  		if (errno == EINPROGRESS) { -			event_set(&nbr->ev_connect, nbr->fd, EV_WRITE, -			    nbr_connect_cb, nbr); -			event_add(&nbr->ev_connect, NULL); +			THREAD_WRITE_ON(master, nbr->ev_connect, nbr_connect_cb, +			    nbr, nbr->fd);  			return (0);  		}  		log_warn("%s: error while connecting to %s", __func__, @@ -682,8 +683,8 @@ nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp)  			return (-1);  		break;  	case AF_INET6: -		if (sock_set_ipv6_minhopcount(fd, ttl) == -1) -			return (-1); +		/* ignore any possible error */ +		sock_set_ipv6_minhopcount(fd, ttl);  		ttl = 255;  		if (sock_set_ipv6_ucast_hops(fd, ttl) == -1)  			return (-1); @@ -798,7 +799,10 @@ nbr_to_ctl(struct nbr *nbr)  	nctl.af = nbr->af;  	nctl.id = nbr->id;  	nctl.laddr = nbr->laddr; +	nctl.lport = nbr->tcp->lport;  	nctl.raddr = nbr->raddr; +	nctl.rport = nbr->tcp->rport; +	nctl.holdtime = nbr->keepalive;  	nctl.nbr_state = nbr->state;  	gettimeofday(&now, NULL); diff --git a/ldpd/notification.c b/ldpd/notification.c index f30646bb83..d306361d5c 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -16,14 +16,13 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldp.h"  #include "log.h"  #include "ldpe.h" +#include "ldp_debug.h"  void  send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) @@ -65,7 +64,7 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm)  	}  	if (tcp->nbr) -		log_debug("msg-out: notification: lsr-id %s, status %s%s", +		debug_msg_send("notification: lsr-id %s status %s%s",  		    inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code),  		    (nm->status_code & STATUS_FATAL) ? " (fatal)" : ""); @@ -199,8 +198,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len)  		}  	} -	log_warnx("msg-in: notification: lsr-id %s, status %s%s", -	    inet_ntoa(nbr->id), status_code_name(ntohl(st.status_code)), +	debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id), +	    status_code_name(ntohl(st.status_code)),  	    (st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : "");  	if (st.status_code & htonl(STATUS_FATAL)) { diff --git a/ldpd/packet.c b/ldpd/packet.c index 7cc375c317..9b3151d720 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -18,28 +18,22 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <net/if_dl.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "sockopt.h" +  static struct iface		*disc_find_iface(unsigned int, int,  				    union ldpd_addr *, int); -static void			 session_read(int, short, void *); -static void			 session_write(int, short, void *); +static int			 session_read(struct thread *); +static int			 session_write(struct thread *);  static ssize_t			 session_get_pdu(struct ibuf_read *, char **);  static void			 tcp_close(struct tcp_conn *);  static struct pending_conn	*pending_conn_new(int, int, union ldpd_addr *); -static void			 pending_conn_timeout(int, short, void *); +static int			 pending_conn_timeout(struct thread *);  int  gen_ldp_hdr(struct ibuf *buf, uint16_t size) @@ -50,7 +44,7 @@ gen_ldp_hdr(struct ibuf *buf, uint16_t size)  	ldp_hdr.version = htons(LDP_VERSION);  	/* exclude the 'Version' and 'PDU Length' fields from the total */  	ldp_hdr.length = htons(size - LDP_HDR_DEAD_LEN); -	ldp_hdr.lsr_id = leconf->rtr_id.s_addr; +	ldp_hdr.lsr_id = ldp_rtr_id_get(leconf);  	ldp_hdr.lspace_id = 0;  	return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE)); @@ -104,7 +98,7 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia,  	}  	sa = addr2sa(af, dst, LDP_PORT); -	if (sendto(fd, pkt, len, 0, sa, sa->sa_len) == -1) { +	if (sendto(fd, pkt, len, 0, sa, sockaddr_len(sa)) == -1) {  		log_warn("%s: error sending packet to %s", __func__,  		    log_sockaddr(sa));  		return (-1); @@ -114,19 +108,27 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia,  }  /* Discovery functions */ -#define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo)) -void -disc_recv_packet(int fd, short event, void *bula) +int +disc_recv_packet(struct thread *thread)  { +	int			 fd = THREAD_FD(thread); +	struct thread		**threadp = THREAD_ARG(thread); +  	union {  		struct	cmsghdr hdr; -		char	buf[CMSG_SPACE(CMSG_MAXLEN)]; +#ifdef HAVE_STRUCT_SOCKADDR_DL +		char	buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; +#else +		char	buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; +#endif  	} cmsgbuf;  	struct msghdr		 m;  	struct sockaddr_storage	 from;  	struct iovec		 iov;  	char			*buf; +#ifndef MSG_MCAST  	struct cmsghdr		*cmsg; +#endif  	ssize_t			 r;  	int			 multicast;  	int			 af; @@ -140,8 +142,8 @@ disc_recv_packet(int fd, short event, void *bula)  	uint16_t		 msg_len;  	struct in_addr		 lsr_id; -	if (event != EV_READ) -		return; +	/* reschedule read */ +	*threadp = thread_add_read(master, disc_recv_packet, threadp, fd);  	/* setup buffer */  	memset(&m, 0, sizeof(m)); @@ -158,44 +160,68 @@ disc_recv_packet(int fd, short event, void *bula)  		if (errno != EAGAIN && errno != EINTR)  			log_debug("%s: read error: %s", __func__,  			    strerror(errno)); -		return; +		return (0);  	} +	sa2addr((struct sockaddr *)&from, &af, &src, NULL); +#ifdef MSG_MCAST  	multicast = (m.msg_flags & MSG_MCAST) ? 1 : 0; -	sa2addr((struct sockaddr *)&from, &af, &src); -	if (bad_addr(af, &src)) { -		log_debug("%s: invalid source address: %s", __func__, -		    log_addr(af, &src)); -		return; -	} - +#else +	multicast = 0;  	for (cmsg = CMSG_FIRSTHDR(&m); cmsg != NULL;  	    cmsg = CMSG_NXTHDR(&m, cmsg)) { +#if defined(HAVE_IP_PKTINFO) +		if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && +		    cmsg->cmsg_type == IP_PKTINFO) { +			struct in_pktinfo	*pktinfo; + +			pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); +			if (IN_MULTICAST(ntohl(pktinfo->ipi_addr.s_addr))) +				multicast = 1; +			break; +		} +#elif defined(HAVE_IP_RECVDSTADDR)  		if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && -		    cmsg->cmsg_type == IP_RECVIF) { -			ifindex = ((struct sockaddr_dl *) -			    CMSG_DATA(cmsg))->sdl_index; +		    cmsg->cmsg_type == IP_RECVDSTADDR) { +			struct in_addr		*addr; + +			addr = (struct in_addr *)CMSG_DATA(cmsg); +			if (IN_MULTICAST(ntohl(addr->s_addr))) +				multicast = 1;  			break;  		} +#else +#error "Unsupported socket API" +#endif  		if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 &&  		    cmsg->cmsg_type == IPV6_PKTINFO) { -			ifindex = ((struct in6_pktinfo *) -			    CMSG_DATA(cmsg))->ipi6_ifindex; +			struct in6_pktinfo	*pktinfo; + +			pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); +			if (IN6_IS_ADDR_MULTICAST(&pktinfo->ipi6_addr)) +				multicast = 1;  			break;  		}  	} +#endif /* MSG_MCAST */ +	if (bad_addr(af, &src)) { +		log_debug("%s: invalid source address: %s", __func__, +		    log_addr(af, &src)); +		return (0); +	} +	ifindex = getsockopt_ifindex(af, &m);  	/* find a matching interface */  	iface = disc_find_iface(ifindex, af, &src, multicast);  	if (iface == NULL) -		return; +		return (0);  	/* check packet size */  	len = (uint16_t)r;  	if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) {  		log_debug("%s: bad packet size, source %s", __func__,  		    log_addr(af, &src)); -		return; +		return (0);  	}  	/* LDP header sanity checks */ @@ -203,12 +229,12 @@ disc_recv_packet(int fd, short event, void *bula)  	if (ntohs(ldp_hdr.version) != LDP_VERSION) {  		log_debug("%s: invalid LDP version %d, source %s", __func__,  		    ntohs(ldp_hdr.version), log_addr(af, &src)); -		return; +		return (0);  	}  	if (ntohs(ldp_hdr.lspace_id) != 0) {  		log_debug("%s: invalid label space %u, source %s", __func__,  		    ntohs(ldp_hdr.lspace_id), log_addr(af, &src)); -		return; +		return (0);  	}  	/* check "PDU Length" field */  	pdu_len = ntohs(ldp_hdr.length); @@ -216,7 +242,7 @@ disc_recv_packet(int fd, short event, void *bula)  	    (pdu_len > (len - LDP_HDR_DEAD_LEN))) {  		log_debug("%s: invalid LDP packet length %u, source %s",  		    __func__, ntohs(ldp_hdr.length), log_addr(af, &src)); -		return; +		return (0);  	}  	buf += LDP_HDR_SIZE;  	len -= LDP_HDR_SIZE; @@ -235,7 +261,7 @@ disc_recv_packet(int fd, short event, void *bula)  	if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) {  		log_debug("%s: invalid LDP message length %u, source %s",  		    __func__, ntohs(msg.length), log_addr(af, &src)); -		return; +		return (0);  	}  	buf += LDP_MSG_SIZE;  	len -= LDP_MSG_SIZE; @@ -249,6 +275,8 @@ disc_recv_packet(int fd, short event, void *bula)  		log_debug("%s: unknown LDP packet type, source %s", __func__,  		    log_addr(af, &src));  	} + +	return (0);  }  static struct iface * @@ -306,9 +334,10 @@ disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src,  	return (NULL);  } -void -session_accept(int fd, short event, void *bula) +int +session_accept(struct thread *thread)  { +	int			 fd = THREAD_FD(thread);  	struct sockaddr_storage	 src;  	socklen_t		 len = sizeof(src);  	int			 newfd; @@ -317,11 +346,7 @@ session_accept(int fd, short event, void *bula)  	struct nbr		*nbr;  	struct pending_conn	*pconn; -	if (!(event & EV_READ)) -		return; - -	newfd = accept4(fd, (struct sockaddr *)&src, &len, -	    SOCK_NONBLOCK | SOCK_CLOEXEC); +	newfd = accept(fd, (struct sockaddr *)&src, &len);  	if (newfd == -1) {  		/*  		 * Pause accept if we are out of file descriptors, or @@ -333,10 +358,11 @@ session_accept(int fd, short event, void *bula)  		    errno != ECONNABORTED)  			log_debug("%s: accept error: %s", __func__,  			    strerror(errno)); -		return; +		return (0);  	} +	sock_set_nonblock(newfd); -	sa2addr((struct sockaddr *)&src, &af, &addr); +	sa2addr((struct sockaddr *)&src, &af, &addr, NULL);  	/*  	 * Since we don't support label spaces, we can identify this neighbor @@ -361,26 +387,29 @@ session_accept(int fd, short event, void *bula)  			close(newfd);  		else  			pending_conn_new(newfd, af, &addr); -		return; +		return (0);  	}  	/* protection against buggy implementations */  	if (nbr_session_active_role(nbr)) {  		close(newfd); -		return; +		return (0);  	}  	if (nbr->state != NBR_STA_PRESENT) {  		log_debug("%s: lsr-id %s: rejecting additional transport "  		    "connection", __func__, inet_ntoa(nbr->id));  		close(newfd); -		return; +		return (0);  	}  	session_accept_nbr(nbr, newfd); + +	return (0);  }  void  session_accept_nbr(struct nbr *nbr, int fd)  { +#ifdef __OpenBSD__  	struct nbr_params	*nbrp;  	int			 opt;  	socklen_t		 len; @@ -407,41 +436,42 @@ session_accept_nbr(struct nbr *nbr, int fd)  			return;  		}  	} +#endif  	nbr->tcp = tcp_new(fd, nbr);  	nbr_fsm(nbr, NBR_EVT_MATCH_ADJ);  } -static void -session_read(int fd, short event, void *arg) +static int +session_read(struct thread *thread)  { -	struct nbr	*nbr = arg; +	int		 fd = THREAD_FD(thread); +	struct nbr	*nbr = THREAD_ARG(thread);  	struct tcp_conn	*tcp = nbr->tcp;  	struct ldp_hdr	*ldp_hdr;  	struct ldp_msg	*msg; -	char		*buf, *pdu; +	char		*buf = NULL, *pdu;  	ssize_t		 n, len;  	uint16_t	 pdu_len, msg_len, msg_size, max_pdu_len;  	int		 ret; -	if (event != EV_READ) -		return; +	tcp->rev = thread_add_read(master, session_read, nbr, fd);  	if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos,  	    sizeof(tcp->rbuf->buf) - tcp->rbuf->wpos)) == -1) {  		if (errno != EINTR && errno != EAGAIN) {  			log_warn("%s: read error", __func__);  			nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); -			return; +			return (0);  		}  		/* retry read */ -		return; +		return (0);  	}  	if (n == 0) {  		/* connection closed */  		log_debug("%s: connection closed by remote end", __func__);  		nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); -		return; +		return (0);  	}  	tcp->rbuf->wpos += n; @@ -451,7 +481,7 @@ session_read(int fd, short event, void *arg)  		if (ntohs(ldp_hdr->version) != LDP_VERSION) {  			session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0);  			free(buf); -			return; +			return (0);  		}  		pdu_len = ntohs(ldp_hdr->length); @@ -468,14 +498,14 @@ session_read(int fd, short event, void *arg)  		    pdu_len > max_pdu_len) {  			session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0);  			free(buf); -			return; +			return (0);  		}  		pdu_len -= LDP_HDR_PDU_LEN;  		if (ldp_hdr->lsr_id != nbr->id.s_addr ||  		    ldp_hdr->lspace_id != 0) {  			session_shutdown(nbr, S_BAD_LDP_ID, 0, 0);  			free(buf); -			return; +			return (0);  		}  		pdu += LDP_HDR_SIZE;  		len -= LDP_HDR_SIZE; @@ -493,7 +523,7 @@ session_read(int fd, short event, void *arg)  				session_shutdown(nbr, S_BAD_TLV_LEN, msg->id,  				    msg->type);  				free(buf); -				return; +				return (0);  			}  			msg_size = msg_len + LDP_MSG_DEAD_LEN;  			pdu_len -= msg_size; @@ -506,7 +536,7 @@ session_read(int fd, short event, void *arg)  					session_shutdown(nbr, S_SHUTDOWN,  					    msg->id, msg->type);  					free(buf); -					return; +					return (0);  				}  				break;  			case MSG_TYPE_KEEPALIVE: @@ -515,7 +545,7 @@ session_read(int fd, short event, void *arg)  					session_shutdown(nbr, S_SHUTDOWN,  					    msg->id, msg->type);  					free(buf); -					return; +					return (0);  				}  				break;  			case MSG_TYPE_ADDR: @@ -529,7 +559,7 @@ session_read(int fd, short event, void *arg)  					session_shutdown(nbr, S_SHUTDOWN,  					    msg->id, msg->type);  					free(buf); -					return; +					return (0);  				}  				break;  			default: @@ -573,7 +603,7 @@ session_read(int fd, short event, void *arg)  			if (ret == -1) {  				/* parser failed, giving up */  				free(buf); -				return; +				return (0);  			}  			/* Analyse the next message */ @@ -583,19 +613,20 @@ session_read(int fd, short event, void *arg)  		free(buf);  		if (len != 0) {  			session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); -			return; +			return (0);  		}  	} + +	return (0);  } -static void -session_write(int fd, short event, void *arg) +static int +session_write(struct thread *thread)  { -	struct tcp_conn *tcp = arg; +	struct tcp_conn *tcp = THREAD_ARG(thread);  	struct nbr	*nbr = tcp->nbr; -	if (!(event & EV_WRITE)) -		return; +	tcp->wbuf.ev = NULL;  	if (msgbuf_write(&tcp->wbuf.wbuf) <= 0)  		if (errno != EAGAIN && nbr) @@ -607,10 +638,12 @@ session_write(int fd, short event, void *arg)  		 * close the socket.  		 */  		tcp_close(tcp); -		return; +		return (0);  	}  	evbuf_event_add(&tcp->wbuf); + +	return (0);  }  void @@ -620,7 +653,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id,  	switch (nbr->state) {  	case NBR_STA_PRESENT:  		if (nbr_pending_connect(nbr)) -			event_del(&nbr->ev_connect); +			THREAD_WRITE_OFF(nbr->ev_connect);  		break;  	case NBR_STA_INITIAL:  	case NBR_STA_OPENREC: @@ -681,7 +714,9 @@ session_get_pdu(struct ibuf_read *r, char **b)  struct tcp_conn *  tcp_new(int fd, struct nbr *nbr)  { -	struct tcp_conn *tcp; +	struct tcp_conn		*tcp; +	struct sockaddr_storage	 src; +	socklen_t		 len = sizeof(src);  	if ((tcp = calloc(1, sizeof(*tcp))) == NULL)  		fatal(__func__); @@ -693,12 +728,15 @@ tcp_new(int fd, struct nbr *nbr)  		if ((tcp->rbuf = calloc(1, sizeof(struct ibuf_read))) == NULL)  			fatal(__func__); -		event_set(&tcp->rev, tcp->fd, EV_READ | EV_PERSIST, -		    session_read, nbr); -		event_add(&tcp->rev, NULL); +		tcp->rev = thread_add_read(master, session_read, nbr, tcp->fd);  		tcp->nbr = nbr;  	} +	getsockname(fd, (struct sockaddr *)&src, &len); +	sa2addr((struct sockaddr *)&src, NULL, NULL, &tcp->lport); +	getpeername(fd, (struct sockaddr *)&src, &len); +	sa2addr((struct sockaddr *)&src, NULL, NULL, &tcp->rport); +  	return (tcp);  } @@ -710,7 +748,7 @@ tcp_close(struct tcp_conn *tcp)  	evbuf_clear(&tcp->wbuf);  	if (tcp->nbr) { -		event_del(&tcp->rev); +		THREAD_READ_OFF(tcp->rev);  		free(tcp->rbuf);  		tcp->nbr->tcp = NULL;  	} @@ -724,7 +762,6 @@ static struct pending_conn *  pending_conn_new(int fd, int af, union ldpd_addr *addr)  {  	struct pending_conn	*pconn; -	struct timeval		 tv;  	if ((pconn = calloc(1, sizeof(*pconn))) == NULL)  		fatal(__func__); @@ -732,13 +769,9 @@ pending_conn_new(int fd, int af, union ldpd_addr *addr)  	pconn->fd = fd;  	pconn->af = af;  	pconn->addr = *addr; -	evtimer_set(&pconn->ev_timeout, pending_conn_timeout, pconn);  	TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry); - -	timerclear(&tv); -	tv.tv_sec = PENDING_CONN_TIMEOUT; -	if (evtimer_add(&pconn->ev_timeout, &tv) == -1) -		fatal(__func__); +	pconn->ev_timeout = thread_add_timer(master, pending_conn_timeout, +	    pconn, PENDING_CONN_TIMEOUT);  	return (pconn);  } @@ -746,10 +779,7 @@ pending_conn_new(int fd, int af, union ldpd_addr *addr)  void  pending_conn_del(struct pending_conn *pconn)  { -	if (evtimer_pending(&pconn->ev_timeout, NULL) && -	    evtimer_del(&pconn->ev_timeout) == -1) -		fatal(__func__); - +	THREAD_TIMER_OFF(pconn->ev_timeout);  	TAILQ_REMOVE(&global.pending_conns, pconn, entry);  	free(pconn);  } @@ -767,12 +797,14 @@ pending_conn_find(int af, union ldpd_addr *addr)  	return (NULL);  } -static void -pending_conn_timeout(int fd, short event, void *arg) +static int +pending_conn_timeout(struct thread *thread)  { -	struct pending_conn	*pconn = arg; +	struct pending_conn	*pconn = THREAD_ARG(thread);  	struct tcp_conn		*tcp; +	pconn->ev_timeout = NULL; +  	log_debug("%s: no adjacency with remote end: %s", __func__,  	    log_addr(pconn->af, &pconn->addr)); @@ -785,4 +817,6 @@ pending_conn_timeout(int fd, short event, void *arg)  	msgbuf_write(&tcp->wbuf.wbuf);  	pending_conn_del(pconn); + +	return (0);  } diff --git a/ldpd/pfkey.c b/ldpd/pfkey.c index f0f16c867f..29f763e6a6 100644 --- a/ldpd/pfkey.c +++ b/ldpd/pfkey.c @@ -17,7 +17,9 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ +#ifdef __OpenBSD__  #include <sys/types.h> +#include <sys/socket.h>  #include <errno.h>  #include <stdlib.h>  #include <string.h> @@ -464,3 +466,4 @@ pfkey_init(void)  	}  	return (fd);  } +#endif /* __OpenBSD__ */ diff --git a/ldpd/socket.c b/ldpd/socket.c index 8f26771df7..cf352d7204 100644 --- a/ldpd/socket.c +++ b/ldpd/socket.c @@ -19,25 +19,29 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> +#include <zebra.h>  #include "ldpd.h"  #include "ldpe.h"  #include "log.h" +#include "lib/log.h" +#include "privs.h" +#include "sockopt.h" + +extern struct zebra_privs_t	 ldpd_privs; +extern struct zebra_privs_t	 ldpe_privs; +  int  ldp_create_socket(int af, enum socket_type type)  {  	int			 fd, domain, proto;  	union ldpd_addr		 addr;  	struct sockaddr_storage	 local_sa; +#ifdef __OpenBSD__  	int			 opt; +#endif +	int			 save_errno;  	/* create socket */  	switch (type) { @@ -53,11 +57,13 @@ ldp_create_socket(int af, enum socket_type type)  	default:  		fatalx("ldp_create_socket: unknown socket type");  	} -	fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto); +	fd = socket(af, domain, proto);  	if (fd == -1) {  		log_warn("%s: error creating socket", __func__);  		return (-1);  	} +	sock_set_nonblock(fd); +	sockopt_v6only(af, fd);  	/* bind to a local address/port */  	switch (type) { @@ -72,21 +78,28 @@ ldp_create_socket(int af, enum socket_type type)  		addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr;  		memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT),  		    sizeof(local_sa)); -		if (sock_set_bindany(fd, 1) == -1) { -			close(fd); -			return (-1); -		} +		/* ignore any possible error */ +		sock_set_bindany(fd, 1);  		break;  	} +	if (ldpd_privs.change(ZPRIVS_RAISE)) +		log_warn("%s: could not raise privs", __func__);  	if (sock_set_reuse(fd, 1) == -1) {  		close(fd);  		return (-1);  	} -	if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) { -		log_warn("%s: error binding socket", __func__); +	if (bind(fd, (struct sockaddr *)&local_sa, +	    sockaddr_len((struct sockaddr *)&local_sa)) == -1) { +		save_errno = errno; +		if (ldpd_privs.change(ZPRIVS_LOWER)) +			log_warn("%s: could not lower privs", __func__); +		log_warnx("%s: error binding socket: %s", __func__, +		    safe_strerror(save_errno));  		close(fd);  		return (-1);  	} +	if (ldpd_privs.change(ZPRIVS_LOWER)) +		log_warn("%s: could not lower privs", __func__);  	/* set options */  	switch (af) { @@ -111,6 +124,21 @@ ldp_create_socket(int af, enum socket_type type)  				close(fd);  				return (-1);  			} +#ifndef MSG_MCAST +#if defined(HAVE_IP_PKTINFO) +			if (sock_set_ipv4_pktinfo(fd, 1) == -1) { +				close(fd); +				return (-1); +			} +#elif defined(HAVE_IP_RECVDSTADDR) +			if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) { +				close(fd); +				return (-1); +			} +#else +#error "Unsupported socket API" +#endif +#endif /* MSG_MCAST */  		}  		if (type == LDP_SOCKET_SESSION) {  			if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) { @@ -134,10 +162,8 @@ ldp_create_socket(int af, enum socket_type type)  				return (-1);  			}  			if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) { -				if (sock_set_ipv6_minhopcount(fd, 255) == -1) { -					close(fd); -					return (-1); -				} +				/* ignore any possible error */ +				sock_set_ipv6_minhopcount(fd, 255);  			}  		}  		if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) { @@ -163,6 +189,7 @@ ldp_create_socket(int af, enum socket_type type)  		if (listen(fd, LDP_BACKLOG) == -1)  			log_warn("%s: error listening on socket", __func__); +#ifdef __OpenBSD__  		opt = 1;  		if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt,  		    sizeof(opt)) == -1) { @@ -174,6 +201,7 @@ ldp_create_socket(int af, enum socket_type type)  				return (-1);  			}  		} +#endif  		break;  	} @@ -181,6 +209,34 @@ ldp_create_socket(int af, enum socket_type type)  }  void +sock_set_nonblock(int fd) +{ +	int	flags; + +	if ((flags = fcntl(fd, F_GETFL, 0)) == -1) +		fatal("fcntl F_GETFL"); + +	flags |= O_NONBLOCK; + +	if ((flags = fcntl(fd, F_SETFL, flags)) == -1) +		fatal("fcntl F_SETFL"); +} + +void +sock_set_cloexec(int fd) +{ +	int	flags; + +	if ((flags = fcntl(fd, F_GETFD, 0)) == -1) +		fatal("fcntl F_GETFD"); + +	flags |= FD_CLOEXEC; + +	if ((flags = fcntl(fd, F_SETFD, flags)) == -1) +		fatal("fcntl F_SETFD"); +} + +void  sock_set_recvbuf(int fd)  {  	int	bsize; @@ -206,15 +262,68 @@ sock_set_reuse(int fd, int enable)  int  sock_set_bindany(int fd, int enable)  { +#ifdef HAVE_SO_BINDANY +	if (ldpd_privs.change(ZPRIVS_RAISE)) +		log_warn("%s: could not raise privs", __func__);  	if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,  	    sizeof(int)) < 0) { +		if (ldpd_privs.change(ZPRIVS_LOWER)) +			log_warn("%s: could not lower privs", __func__);  		log_warn("%s: error setting SO_BINDANY", __func__);  		return (-1);  	} - +	if (ldpd_privs.change(ZPRIVS_LOWER)) +		log_warn("%s: could not lower privs", __func__);  	return (0); +#elif defined(HAVE_IP_FREEBIND) +	if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) { +		log_warn("%s: error setting IP_FREEBIND", __func__); +		return (-1); +	} +	return (0); +#else +	log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind " +	    "to a nonlocal IP address", __func__); +	return (-1); +#endif /* HAVE_SO_BINDANY */  } +#ifndef __OpenBSD__ +/* + * Set MD5 key for the socket, for the given peer address. If the password + * is NULL or zero-length, the option will be disabled. + */ +int +sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password) +{ +	int		 ret = -1; +	int		 save_errno = ENOSYS; +#if HAVE_DECL_TCP_MD5SIG +	union sockunion	 su; +#endif + +	if (fd == -1) +		return (0); +#if HAVE_DECL_TCP_MD5SIG +	memcpy(&su, addr2sa(af, addr, 0), sizeof(su)); + +	if (ldpe_privs.change(ZPRIVS_RAISE)) { +		log_warn("%s: could not raise privs", __func__); +		return (-1); +	} +	ret = sockopt_tcp_signature(fd, &su, password); +	save_errno = errno; +	if (ldpe_privs.change(ZPRIVS_LOWER)) +		log_warn("%s: could not lower privs", __func__); +#endif /* HAVE_TCP_MD5SIG */ +	if (ret < 0) +		log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s", +		    __func__, fd, safe_strerror(save_errno)); + +	return (ret); +} +#endif +  int  sock_set_ipv4_tos(int fd, int tos)  { @@ -229,23 +338,13 @@ sock_set_ipv4_tos(int fd, int tos)  int  sock_set_ipv4_recvif(int fd, int enable)  { -	if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, -	    sizeof(enable)) < 0) { -		log_warn("%s: error setting IP_RECVIF", __func__); -		return (-1); -	} -	return (0); +	return (setsockopt_ifindex(AF_INET, fd, enable));  }  int  sock_set_ipv4_minttl(int fd, int ttl)  { -	if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) { -		log_warn("%s: error setting IP_MINTTL", __func__); -		return (-1); -	} - -	return (0); +	return (sockopt_minttl(AF_INET, fd, ttl));  }  int @@ -272,15 +371,45 @@ sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl)  	return (0);  } +#ifndef MSG_MCAST +#if defined(HAVE_IP_PKTINFO) +int +sock_set_ipv4_pktinfo(int fd, int enable) +{ +	if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable, +	    sizeof(enable)) < 0) { +		log_warn("%s: error setting IP_PKTINFO", __func__); +		return (-1); +	} + +	return (0); +} +#elif defined(HAVE_IP_RECVDSTADDR) +int +sock_set_ipv4_recvdstaddr(int fd, int enable) +{ +	if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable, +	    sizeof(enable)) < 0) { +		log_warn("%s: error setting IP_RECVDSTADDR", __func__); +		return (-1); +	} + +	return (0); +} +#else +#error "Unsupported socket API" +#endif +#endif /* MSG_MCAST */ +  int  sock_set_ipv4_mcast(struct iface *iface)  { -	in_addr_t		 addr; +	struct in_addr		 if_addr; -	addr = if_get_ipv4_addr(iface); +	if_addr.s_addr = if_get_ipv4_addr(iface); -	if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF, -	    &addr, sizeof(addr)) < 0) { +	if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket, +	    if_addr, iface->ifindex) < 0) {  		log_warn("%s: error setting IP_MULTICAST_IF, interface %s",  		    __func__, iface->name);  		return (-1); @@ -330,13 +459,7 @@ sock_set_ipv6_pktinfo(int fd, int enable)  int  sock_set_ipv6_minhopcount(int fd, int hoplimit)  { -	if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, -	    &hoplimit, sizeof(hoplimit)) < 0) { -		log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__); -		return (-1); -	} - -	return (0); +	return (sockopt_minttl(AF_INET6, fd, hoplimit));  }  int diff --git a/ldpd/util.c b/ldpd/util.c index 981a5c8c21..e735263f5f 100644 --- a/ldpd/util.c +++ b/ldpd/util.c @@ -19,8 +19,7 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <string.h> +#include <zebra.h>  #include "ldpd.h"  #include "log.h" @@ -44,7 +43,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_in6)  	 * the possibly truncated sin6_addr struct.  	 */  	ap = (uint8_t *)&sa_in6->sin6_addr; -	ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; +	ep = (uint8_t *)sa_in6 + sockaddr_len((struct sockaddr *)sa_in6);  	for (; ap < ep; ap++) {  		/* this "beauty" is adopted from sbin/route/show.c ... */  		switch (*ap) { @@ -317,13 +316,17 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port)  	switch (af) {  	case AF_INET:  		sa_in->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN  		sa_in->sin_len = sizeof(struct sockaddr_in); +#endif  		sa_in->sin_addr = addr->v4;  		sa_in->sin_port = htons(port);  		break;  	case AF_INET6:  		sa_in6->sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN  		sa_in6->sin6_len = sizeof(struct sockaddr_in6); +#endif  		sa_in6->sin6_addr = addr->v6;  		sa_in6->sin6_port = htons(port);  		break; @@ -335,22 +338,48 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port)  }  void -sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr) +sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr, in_port_t *port)  {  	struct sockaddr_in		*sa_in = (struct sockaddr_in *)sa;  	struct sockaddr_in6		*sa_in6 = (struct sockaddr_in6 *)sa; -	memset(addr, 0, sizeof(*addr)); +	if (addr) +		memset(addr, 0, sizeof(*addr));  	switch (sa->sa_family) {  	case AF_INET: -		*af = AF_INET; -		addr->v4 = sa_in->sin_addr; +		if (af) +			*af = AF_INET; +		if (addr) +			addr->v4 = sa_in->sin_addr; +		if (port) +			*port = sa_in->sin_port;  		break;  	case AF_INET6: -		*af = AF_INET6; -		addr->v6 = sa_in6->sin6_addr; +		if (af) +			*af = AF_INET6; +		if (addr) +			addr->v6 = sa_in6->sin6_addr; +		if (port) +			*port = sa_in6->sin6_port;  		break;  	default:  		fatalx("sa2addr: unknown af");  	}  } + +socklen_t +sockaddr_len(struct sockaddr *sa) +{ +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN +	return (sa->sa_len); +#else +	switch (sa->sa_family) { +	case AF_INET: +		return (sizeof(struct sockaddr_in)); +	case AF_INET6: +		return (sizeof(struct sockaddr_in6)); +	default: +		fatalx("sockaddr_len: unknown af"); +	} +#endif +} diff --git a/lib/Makefile.am b/lib/Makefile.am index dbb80076c5..17be655a17 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,7 +14,8 @@ libzebra_la_SOURCES = \  	filter.c routemap.c distribute.c stream.c str.c log.c plist.c \  	zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \  	sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \ -	ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c +	ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \ +	imsg-buffer.c imsg.c  BUILT_SOURCES = route_types.h gitversion.h @@ -31,7 +32,7 @@ pkginclude_HEADERS = \  	privs.h sigevent.h pqueue.h jhash.h zassert.h \  	workqueue.h route_types.h libospf.h nexthop.h json.h \  	ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \ -	fifo.h memory_vty.h +	fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h  noinst_HEADERS = \  	plist_int.h diff --git a/lib/command.c b/lib/command.c index cfdb91a5b9..bf8b1b1d33 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2550,6 +2550,19 @@ node_parent ( enum node_type node )      case LINK_PARAMS_NODE:        ret = INTERFACE_NODE;        break; +    case LDP_IPV4_NODE: +    case LDP_IPV6_NODE: +      ret = LDP_NODE; +      break; +    case LDP_IPV4_IFACE_NODE: +      ret = LDP_IPV4_NODE; +      break; +    case LDP_IPV6_IFACE_NODE: +      ret = LDP_IPV6_NODE; +      break; +    case LDP_PSEUDOWIRE_NODE: +      ret = LDP_L2VPN_NODE; +      break;      default:        ret = CONFIG_NODE;        break; @@ -2920,6 +2933,8 @@ DEFUN (config_exit,      case RIPNG_NODE:      case OSPF_NODE:      case OSPF6_NODE: +    case LDP_NODE: +    case LDP_L2VPN_NODE:      case ISIS_NODE:      case KEYCHAIN_NODE:      case MASC_NODE: @@ -2938,6 +2953,19 @@ DEFUN (config_exit,      case BGP_IPV6M_NODE:        vty->node = BGP_NODE;        break; +    case LDP_IPV4_NODE: +    case LDP_IPV6_NODE: +      vty->node = LDP_NODE; +      break; +    case LDP_IPV4_IFACE_NODE: +      vty->node = LDP_IPV4_NODE; +      break; +    case LDP_IPV6_IFACE_NODE: +      vty->node = LDP_IPV6_NODE; +      break; +    case LDP_PSEUDOWIRE_NODE: +      vty->node = LDP_L2VPN_NODE; +      break;      case KEYCHAIN_KEY_NODE:        vty->node = KEYCHAIN_NODE;        break; @@ -2988,6 +3016,13 @@ DEFUN (config_end,      case RMAP_NODE:      case OSPF_NODE:      case OSPF6_NODE: +    case LDP_NODE: +    case LDP_IPV4_NODE: +    case LDP_IPV6_NODE: +    case LDP_IPV4_IFACE_NODE: +    case LDP_IPV6_IFACE_NODE: +    case LDP_L2VPN_NODE: +    case LDP_PSEUDOWIRE_NODE:      case ISIS_NODE:      case KEYCHAIN_NODE:      case KEYCHAIN_KEY_NODE: diff --git a/lib/command.h b/lib/command.h index 808e742059..7a4c53a616 100644 --- a/lib/command.h +++ b/lib/command.h @@ -98,6 +98,13 @@ enum node_type    BGP_ENCAPV6_NODE,		/* BGP ENCAP SAFI */    OSPF_NODE,			/* OSPF protocol mode */    OSPF6_NODE,			/* OSPF protocol for IPv6 mode */ +  LDP_NODE,			/* LDP protocol mode */ +  LDP_IPV4_NODE,		/* LDP IPv4 address family */ +  LDP_IPV6_NODE,		/* LDP IPv6 address family */ +  LDP_IPV4_IFACE_NODE,		/* LDP IPv4 Interface */ +  LDP_IPV6_IFACE_NODE,		/* LDP IPv6 Interface */ +  LDP_L2VPN_NODE,		/* LDP L2VPN node */ +  LDP_PSEUDOWIRE_NODE,		/* LDP Pseudowire node */    ISIS_NODE,			/* ISIS protocol mode */    PIM_NODE,			/* PIM protocol mode */    MASC_NODE,			/* MASC for multicast.  */ diff --git a/lib/imsg-buffer.c b/lib/imsg-buffer.c index 61b2c095ae..a486fc17c1 100644 --- a/lib/imsg-buffer.c +++ b/lib/imsg-buffer.c @@ -16,17 +16,9 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <limits.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <zebra.h> +#include "openbsd-queue.h"  #include "imsg.h"  int	ibuf_realloc(struct ibuf *, size_t); @@ -258,7 +250,7 @@ msgbuf_write(struct msgbuf *msgbuf)  		cmsg->cmsg_len = CMSG_LEN(sizeof(int));  		cmsg->cmsg_level = SOL_SOCKET;  		cmsg->cmsg_type = SCM_RIGHTS; -		*(int *)CMSG_DATA(cmsg) = buf->fd; +		memcpy(CMSG_DATA(cmsg), &buf->fd, sizeof(int));  	}  again: diff --git a/lib/imsg.c b/lib/imsg.c index 0c1cb8220c..246430cdd5 100644 --- a/lib/imsg.c +++ b/lib/imsg.c @@ -16,22 +16,49 @@   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   */ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <zebra.h> +#include "openbsd-queue.h"  #include "imsg.h"  int	 imsg_fd_overhead = 0;  int	 imsg_get_fd(struct imsgbuf *); +#ifndef __OpenBSD__ +/* + * The original code calls getdtablecount() which is OpenBSD specific. Use + * available_fds() from OpenSMTPD instead. + */ +static int +available_fds(unsigned int n) +{ +	unsigned int	i; +	int		ret, fds[256]; + +	if (n > (sizeof(fds)/sizeof(fds[0]))) +		return (1); + +	ret = 0; +	for (i = 0; i < n; i++) { +		fds[i] = -1; +		if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { +			if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) +				fds[i] = socket(AF_INET6, SOCK_DGRAM, 0); +			if (fds[i] < 0) { +				ret = 1; +				break; +			} +		} +	} + +	for (i = 0; i < n && fds[i] >= 0; i++) +		close(fds[i]); + +	return (ret); +} +#endif +  void  imsg_init(struct imsgbuf *ibuf, int fd)  { @@ -71,9 +98,14 @@ imsg_read(struct imsgbuf *ibuf)  		return (-1);  again: +#ifdef __OpenBSD__  	if (getdtablecount() + imsg_fd_overhead +  	    (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))  	    >= getdtablesize()) { +#else +	if (available_fds(imsg_fd_overhead + +	    (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) { +#endif  		errno = EAGAIN;  		free(ifd);  		return (-1); @@ -51,6 +51,7 @@ const char *zlog_proto_names[] =    "OSPF",    "RIPNG",    "OSPF6", +  "LDP",    "ISIS",    "PIM",    "MASC", @@ -177,7 +178,7 @@ time_print(FILE *fp, struct timestamp_control *ctl)  /* va_list version of zlog. */ -static void +void  vzlog (struct zlog *zl, int priority, const char *format, va_list args)  {    char proto_str[32]; @@ -51,6 +51,7 @@ typedef enum    ZLOG_OSPF,    ZLOG_RIPNG,    ZLOG_OSPF6, +  ZLOG_LDP,    ZLOG_ISIS,    ZLOG_PIM,    ZLOG_MASC @@ -115,6 +116,7 @@ extern void zlog (struct zlog *zl, int priority, const char *format, ...)    PRINTF_ATTRIBUTE(3, 4);  /* Handy zlog functions. */ +extern void vzlog (struct zlog *zl, int priority, const char *format, va_list args);  extern void zlog_err (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);  extern void zlog_warn (const char *format, ...) PRINTF_ATTRIBUTE(1, 2);  extern void zlog_info (const char *format, ...) PRINTF_ATTRIBUTE(1, 2); diff --git a/lib/mpls.h b/lib/mpls.h index 8889868970..5a67b915d1 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -169,4 +169,13 @@ label2str (mpls_label_t label, char *buf, int len)    return(buf);  } +/* constants used by ldpd */ +#define MPLS_LABEL_IPV4NULL	0               /* IPv4 Explicit NULL Label */ +#define MPLS_LABEL_RTALERT	1               /* Router Alert Label       */ +#define MPLS_LABEL_IPV6NULL	2               /* IPv6 Explicit NULL Label */ +#define MPLS_LABEL_IMPLNULL	3               /* Implicit NULL Label      */ +/*      MPLS_LABEL_RESERVED	4-15 */		/* Values 4-15 are reserved */ +#define MPLS_LABEL_RESERVED_MAX 15 +#define MPLS_LABEL_MAX		((1 << 20) - 1) +  #endif diff --git a/lib/privs.c b/lib/privs.c index 9228a56d35..6cf87c18d4 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -250,12 +250,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)        exit(1);      } -  if ( !zprivs_state.syscaps_p ) -    { -      fprintf (stderr, "privs_init: capabilities enabled, " -                       "but no capabilities supplied\n"); -    } -    /* we have caps, we have no need to ever change back the original user */    if (zprivs_state.zuid)      { @@ -266,6 +260,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs)            exit (1);          }      } + +  if ( !zprivs_state.syscaps_p ) +    return;    if ( !(zprivs_state.caps = cap_init()) )      { diff --git a/lib/route_types.txt b/lib/route_types.txt index 8fc3092cac..0ac442d85d 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -60,6 +60,7 @@ ZEBRA_ROUTE_PIM,	pim,	   pimd,   'P', 1, 0, "PIM"  ZEBRA_ROUTE_HSLS,       hsls,      hslsd,  'H', 0, 0, "HSLS"  ZEBRA_ROUTE_OLSR,       olsr,      olsrd,  'o', 0, 0, "OLSR"  ZEBRA_ROUTE_TABLE,      table,     zebra,  'T', 1, 1, "Table" +ZEBRA_ROUTE_LDP,        ldp,       ldpd,   'L', 0, 0, "LDP"  ## help strings  ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" @@ -76,3 +77,4 @@ ZEBRA_ROUTE_PIM,    "Protocol Independent Multicast (PIM)"  ZEBRA_ROUTE_HSLS,   "Hazy-Sighted Link State Protocol (HSLS)"  ZEBRA_ROUTE_OLSR,   "Optimised Link State Routing (OLSR)"  ZEBRA_ROUTE_TABLE,  "Non-main Kernel Routing Table" +ZEBRA_ROUTE_LDP,    "Label Distribution Protocol (LDP)" @@ -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; +} @@ -127,6 +127,14 @@ struct vty    char address[SU_ADDRSTRLEN];  }; +struct vty_arg +{ +  const char *name; +  const char *value; +  const char **argv; +  int argc; +}; +  /* Integrated configuration file. */  #define INTEGRATE_DEFAULT_CONFIG "Quagga.conf" @@ -292,4 +300,7 @@ extern void vty_hello (struct vty *);     an async-signal-safe function. */  extern void vty_log_fixed (char *buf, size_t len); +extern const char *vty_get_arg_value (struct vty_arg **, const char *); +extern struct vty_arg *vty_get_arg (struct vty_arg **, const char *); +  #endif /* _ZEBRA_VTY_H */ diff --git a/tools/xml2cli.pl b/tools/xml2cli.pl new file mode 100755 index 0000000000..43789131c3 --- /dev/null +++ b/tools/xml2cli.pl @@ -0,0 +1,436 @@ +#!/usr/bin/perl +## +## Parse a XML file containing a tree-like representation of Quagga CLI +## commands and generate a file with: +## +## - a DEFUN function for each command; +## - an initialization function. +## +## +## Copyright (C) 2012 Renato Westphal <renatow@digistar.com.br> +## This file is part of GNU Zebra. +## +## GNU Zebra is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## GNU Zebra is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Zebra; see the file COPYING.  If not, write to the Free +## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA. +## + +use strict; +use warnings; +use Getopt::Std; +use vars qw($opt_d); +use File::Basename qw(fileparse); +use XML::LibXML; + +%::input_strs = ( +		"ifname"		=> "IFNAME", +		"word"			=> "WORD", +		"line"			=> ".LINE", +		"ipv4"			=> "A.B.C.D", +		"ipv4m"			=> "A.B.C.D/M", +		"ipv6"			=> "X:X::X:X", +		"ipv6m"			=> "X:X::X:X/M", +		"mtu"			=> "<1500-9180>", +		# BGP specific +		"rd"			=> "ASN:nn_or_IP-address:nn", +		"asn"			=> "<1-4294967295>", +		"community"		=> "AA:NN", +		"clist"			=> "<1-500>", +		# LDP specific +		"disc_time"		=> "<1-65535>", +		"session_time"		=> "<15-65535>", +		"pwid"			=> "<1-4294967295>", +		"hops"			=> "<1-254>" +		); + +# parse options node and store the corresponding information +# into a global hash of hashes +sub parse_options { +	my $xml_node = $_[0]; +	my @cmdstr; + +	my $options_name = $xml_node->findvalue('./@name'); +	if (not $options_name) { +		die('error: "options" node without "name" attribute'); +	} + +	# initialize hash +	$::options{$options_name}{'cmdstr'} = ""; +	$::options{$options_name}{'help'} = ""; + +	my @children = $xml_node->getChildnodes(); +	foreach my $child(@children) { +		# skip comments, random text, etc +		if ($child->getType() != XML_ELEMENT_NODE) { +			next; +		} + +		# check for error/special conditions +		if ($child->getName() ne "option") { +			die('error: invalid node type: "' . $child->getName() . '"'); +		} + +		my $name = $child->findvalue('./@name'); +		my $input = $child->findvalue('./@input'); +		my $help = $child->findvalue('./@help'); +		if ($input) { +			$name = $::input_strs{$input}; +		} + +		push (@cmdstr, $name); +		$::options{$options_name}{'help'} .= "\n       \"" . $help . "\\n\""; +	} +	$::options{$options_name}{'cmdstr'} = "(" . join('|', @cmdstr) . ")"; +} + +# given a subtree, replace all the corresponding include nodes by +# this subtree +sub subtree_replace_includes { +	my $subtree = $_[0]; + +	my $subtree_name = $subtree->findvalue('./@name'); +	if (not $subtree_name) { +		die("subtree without \"name\" attribute"); +	} + +	my $query = "//include[\@subtree='$subtree_name']"; +	foreach my $include_node($::xml->findnodes($query)) { +		my @children = $subtree->getChildnodes(); +		foreach my $child(reverse @children) { +			my $include_node_parent = $include_node->getParentNode(); +			$include_node_parent->insertAfter($child->cloneNode(1), +					$include_node); +		} +		$include_node->unbindNode(); +	} +	$subtree->unbindNode(); +} + +# generate arguments for a given command +sub generate_arguments { +	my @nodes = @_; +	my $arguments; +	my $no_args = 1; +	my $argc = 0; + +	$arguments .= "  struct vty_arg *args[] =\n"; +	$arguments .= "    {\n"; +	for (my $i = 0; $i < @nodes; $i++) { +		my %node = %{$nodes[$i]}; +		my $arg_value; + +		if (not $node{'arg'}) { +			next; +		} +		$no_args = 0; + +		# for input and select nodes, the value of the argument is an +		# argv[] element. for the other types of nodes, the value of the +		# argument is the name of the node +		if ($node{'input'} or $node{'type'} eq "select") { +			$arg_value = "argv[" . $argc++ . "]"; +		} else { +			$arg_value = '"' . $node{'name'} . '"'; +		} + +		if ($node{'input'} and $node{'input'} eq "line") { +			# arguments of the type 'line' may have multiple spaces (i.e +			# they don't fit into a single argv[] element).	to properly +			# handle these arguments, we need to provide direct access +			# to the argv[] array and the argc variable. +			my $argc_str = "argc" . (($argc > 1) ? " - " . ($argc - 1) : ""); +			my $argv_str = "argv" . (($argc > 1) ? " + " . ($argc - 1) : ""); +			$arguments .= "      &(struct vty_arg) { " +				. ".name = \"" . $node{'arg'} . "\", " +				. ".argc = $argc_str, " +				. ".argv = $argv_str },\n"; +		} else { +			# common case - each argument has a name and a single value +			$arguments .= "      &(struct vty_arg) { " +				. ".name = \"" . $node{'arg'} . "\", " +				. ".value = " . $arg_value . " },\n"; +		} +	} +	$arguments .= "      NULL\n"; +	$arguments .= "    };\n"; + +	# handle special case +	if ($no_args) { +		return "  struct vty_arg *args[] = { NULL };\n"; +	} + +	return $arguments; +} + +# generate C code +sub generate_code { +	my @nodes = @_; +	my $funcname = ''; +	my $cmdstr = ''; +	my $cmdname = ''; +	my $helpstr = ''; +	my $function = ''; + +	for (my $i = 0; $i < @nodes; $i++) { +		my %node = %{$nodes[$i]}; +		if ($node{'input'}) { +			$funcname .= $node{'input'} . " "; +			$cmdstr .= $::input_strs{$node{'input'}} . " "; +			$helpstr .= "\n       \"" . $node{'help'} . "\\n\""; +		} elsif ($node{'type'} eq "select") { +			my $options_name = $node{'options'}; +			$funcname .= $options_name . " "; +			$cmdstr .= $::options{$options_name}{'cmdstr'} . " "; +			$helpstr .= $::options{$options_name}{'help'}; +		} else { +			$funcname .= $node{'name'} . " "; +			$cmdstr .= $node{'name'} . " "; +			$helpstr .= "\n       \"" . $node{'help'} . "\\n\""; +		} + +		# update the command string +		if ($node{'function'} ne "inherited") { +			$function = $node{'function'}; +		} +	} + +	# rtrim +	$funcname =~ s/\s+$//; +	$cmdstr =~ s/\s+$//; +	# lowercase +	$funcname = lc($funcname); +	# replace " " by "_" +	$funcname =~ tr/ /_/; +	# replace "-" by "_" +	$funcname =~ tr/-/_/; +	# add prefix +	$funcname = $::cmdprefix . '_' . $funcname; + +	# generate DEFUN +	$cmdname = $funcname . "_cmd"; + +	# don't generate same command more than once +	if ($::commands{$cmdname}) { +		return $cmdname; +	} +	$::commands{$cmdname} = "1"; + +	print STDOUT "DEFUN (" . $funcname . ",\n" +		   . "       " . $cmdname . ",\n" +		   . "       \"" . $cmdstr . "\"," +		   . $helpstr . ")\n" +		   . "{\n" +		   . generate_arguments(@nodes) +		   . "  return " . $function . " (vty, args);\n" +		   . "}\n\n"; + +	return $cmdname; +} + +# parse tree node (recursive function) +sub parse_tree { +	# get args +	my $xml_node = $_[0]; +	my @nodes = @{$_[1]}; +	my $tree_name = $_[2]; + +	# hash containing all the node attributes +	my %node; +	$node{'type'} = $xml_node->getName(); + +	# check for error/special conditions +	if ($node{'type'} eq "tree") { +		goto end; +	} +	if ($node{'type'} eq "include") { +		die('error: can not include "' +				. $xml_node->findvalue('./@subtree') . '"'); +	} +	if (not $node{'type'} ~~ [qw(option select)]) { +		die('error: invalid node type: "' . $node{'type'} . '"'); +	} +	if ($node{'type'} eq "select") { +		my $options_name = $xml_node->findvalue('./@options'); +		if (not $options_name) { +			die('error: "select" node without "name" attribute'); +		} +		if (not $::options{$options_name}) { +			die('error: can not find options'); +		} +		$node{'options'} = $options_name; +	} + +	# get node attributes +	$node{'name'} = $xml_node->findvalue('./@name'); +	$node{'input'} = $xml_node->findvalue('./@input'); +	$node{'arg'} = $xml_node->findvalue('./@arg'); +	$node{'help'} = $xml_node->findvalue('./@help'); +	$node{'function'} = $xml_node->findvalue('./@function'); +	$node{'ifdef'} = $xml_node->findvalue('./@ifdef'); + +	# push node to stack +	push (@nodes, \%node); + +	# generate C code +	if ($node{'function'}) { +		my $cmdname = generate_code(@nodes); +		push (@{$::trees{$tree_name}}, [0, $cmdname, 0]); +	} + +	if ($node{'ifdef'}) { +		push (@{$::trees{$tree_name}}, [$node{'ifdef'}, 0, 0]); +	} + +end: +	# recursively process child nodes +	my @children = $xml_node->getChildnodes(); +	foreach my $child(@children) { +		# skip comments, random text, etc +		if ($child->getType() != XML_ELEMENT_NODE) { +			next; +		} +		parse_tree($child, \@nodes, $tree_name); +	} + +	if ($node{'ifdef'}) { +		push (@{$::trees{$tree_name}}, [0, 0, $node{'ifdef'}]); +	} +} + +sub parse_node { +	# get args +	my $xml_node = $_[0]; + +	my $node_name = $xml_node->findvalue('./@name'); +	if (not $node_name) { +		die('missing the "name" attribute'); +	} + +	my $install = $xml_node->findvalue('./@install'); +	my $config_write = $xml_node->findvalue('./@config_write'); +	if ($install and $install eq "1") { +		print "  install_node (&" .lc( $node_name) . "_node, " . $config_write . ");\n"; +	} + +	my $install_default = $xml_node->findvalue('./@install_default'); +	if ($install_default and $install_default eq "1") { +  		print "  install_default (" . $node_name . "_NODE);\n"; +	} + +	my @children = $xml_node->getChildnodes(); +	foreach my $child(@children) { +		# skip comments, random text, etc +		if ($child->getType() != XML_ELEMENT_NODE) { +			next; +		} + +		if ($child->getName() ne "include") { +			die('error: invalid node type: "' . $child->getName() . '"'); +		} +		my $tree_name = $child->findvalue('./@tree'); +		if (not $tree_name) { +			die('missing the "tree" attribute'); +		} + +		foreach my $entry (@{$::trees{$tree_name}}) { +			my ($ifdef, $cmdname, $endif) = @{$entry}; + +			if ($ifdef) { +				print ("#ifdef " . $ifdef . "\n"); +			} + +			if ($cmdname) { +				print "  install_element (" . $node_name . "_NODE, &" . $cmdname . ");\n"; +			} + +			if ($endif) { +				print ("#endif /* " . $endif . " */\n"); +			} +		} +	} +} + +# parse command-line arguments +if (not getopts('d')) { +	die("Usage: xml2cli.pl [-d] FILE\n"); +} +my $file = shift; + +# initialize the XML parser +my $parser = new XML::LibXML; +$parser->keep_blanks(0); + +# parse XML file +$::xml = $parser->parse_file($file); +my $xmlroot = $::xml->getDocumentElement(); +if ($xmlroot->getName() ne "file") { +	die('XML root element name must be "file"'); +} + +# read file attributes +my $init_function = $xmlroot->findvalue('./@init'); +if (not $init_function) { +	die('missing the "init" attribute in the "file" node'); +} +$::cmdprefix = $xmlroot->findvalue('./@cmdprefix'); +if (not $::cmdprefix) { +	die('missing the "cmdprefix" attribute in the "file" node'); +} +my $header = $xmlroot->findvalue('./@header'); +if (not $header) { +	die('missing the "header" attribute in the "file" node'); +} + +# generate source header +print STDOUT "/* Auto-generated from " . fileparse($file) . ". */\n" +	   . "/* Do not edit! */\n\n" +	   . "#include <zebra.h>\n\n" +	   . "#include \"command.h\"\n" +	   . "#include \"vty.h\"\n" +	   . "#include \"$header\"\n\n"; + +# Parse options +foreach my $options($::xml->findnodes("/file/options")) { +	parse_options($options); +} + +# replace include nodes by the corresponding subtrees +foreach my $subtree(reverse $::xml->findnodes("/file/subtree")) { +	subtree_replace_includes($subtree); +} + +# Parse trees +foreach my $tree($::xml->findnodes("/file/tree")) { +	my @nodes = (); +	my $tree_name = $tree->findvalue('./@name'); +	parse_tree($tree, \@nodes, $tree_name); +} + +# install function header +print STDOUT "void\n" +	   . $init_function . " (void)\n" +	   . "{\n"; + +# Parse nodes +foreach my $node($::xml->findnodes("/file/node")) { +	parse_node($node); +} + +# closing braces for the install function +print STDOUT "}"; + +# print to stderr the expanded XML file if the debug flag (-d) is given +if ($opt_d) { +	print STDERR $::xml->toString(1); +} diff --git a/zebra/zserv.c b/zebra/zserv.c index 3402bf1dfb..e617ae28a2 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -641,7 +641,7 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,    for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)      {        /* We don't send any nexthops when there's a multipath */ -      if (rib->nexthop_active_num > 1) +      if (rib->nexthop_active_num > 1 && client->proto != ZEBRA_ROUTE_LDP)  	{            SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP);            SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX); @@ -713,7 +713,9 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p,            stream_putc (s, 1);            stream_putl (s, nexthop->ifindex); -          break; +	  /* ldpd needs all nexthops */ +	  if (client->proto != ZEBRA_ROUTE_LDP) +	    break;          }      }  | 
