diff options
57 files changed, 8862 insertions, 1200 deletions
diff --git a/Makefile.am b/Makefile.am index 1a39844cb..a3cbdc919 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,10 +1,10 @@ ## Process this file with automake to produce Makefile.in. -SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \ +SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \ @ISISD@ @PIMD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \ redhat @SOLARIS@ tests tools cumulus -DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \ +DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d ldpd \ isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \ solaris pimd tools cumulus diff --git a/configure.ac b/configure.ac index 937d7b8d0..eb1f1de6c 100755 --- a/configure.ac +++ b/configure.ac @@ -246,6 +246,8 @@ AC_ARG_ENABLE(ospfd, AS_HELP_STRING([--disable-ospfd], [do not build ospfd])) AC_ARG_ENABLE(ospf6d, AS_HELP_STRING([--disable-ospf6d], [do not build ospf6d])) +AC_ARG_ENABLE(ldpd, + AS_HELP_STRING([--enable-ldpd], [build ldpd])) AC_ARG_ENABLE(watchquagga, AS_HELP_STRING([--disable-watchquagga], [do not build watchquagga])) AC_ARG_ENABLE(isisd, @@ -838,7 +840,7 @@ AC_CHECK_FUNCS([dup2 ftruncate getcwd gethostbyname getpagesize gettimeofday \ strtol strtoul strlcat strlcpy \ daemon snprintf vsnprintf \ if_nametoindex if_indextoname getifaddrs \ - uname fcntl getgrouplist]) + uname fcntl getgrouplist pledge]) AC_CHECK_HEADER([asm-generic/unistd.h], [AC_CHECK_DECL(__NR_setns, @@ -1231,6 +1233,13 @@ else fi AM_CONDITIONAL(OSPFD, test "x$OSPFD" = "xospfd") +if test "${enable_ldpd}" = "yes";then + LDPD="ldpd" +else + LDPD="" +fi +AM_CONDITIONAL(LDPD, test "x$LDPD" = "xldpd") + if test "${enable_watchquagga}" = "no";then WATCHQUAGGA="" else @@ -1286,6 +1295,7 @@ AC_SUBST(RIPD) AC_SUBST(RIPNGD) AC_SUBST(OSPFD) AC_SUBST(OSPF6D) +AC_SUBST(LDPD) AC_SUBST(WATCHQUAGGA) AC_SUBST(ISISD) AC_SUBST(PIMD) @@ -1432,6 +1442,32 @@ AC_TRY_COMPILE([#include <netinet/in.h>], [ AC_MSG_RESULT(no) ]) +dnl ---------------------- +dnl checking for SO_BINDANY +dnl ---------------------- +AC_MSG_CHECKING(for SO_BINDANY) +AC_TRY_COMPILE([#include <sys/socket.h>], [ + int opt = SO_BINDANY; +], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SO_BINDANY, 1, [Have SO_BINDANY]) +], [ + AC_MSG_RESULT(no) +]) + +dnl ---------------------- +dnl checking for IP_FREEBIND +dnl ---------------------- +AC_MSG_CHECKING(for IP_FREEBIND) +AC_TRY_COMPILE([#include <netinet/in.h>], [ + int opt = IP_FREEBIND; +], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_IP_FREEBIND, 1, [Have IP_FREEBIND]) +], [ + AC_MSG_RESULT(no) +]) + dnl -------------------------------------- dnl checking for getrusage struct and call dnl -------------------------------------- @@ -1580,6 +1616,8 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID) AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID) AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID) AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID) +AC_DEFINE_UNQUOTED(PATH_LDPD_PID, "$quagga_statedir/ldpd.pid",ldpd PID) +AC_DEFINE_UNQUOTED(LDPD_SOCKET, "$quagga_statedir/ldpd.sock",ldpd control socket) AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID) AC_DEFINE_UNQUOTED(PATH_PIMD_PID, "$quagga_statedir/pimd.pid",pimd PID) AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID) @@ -1590,6 +1628,7 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket) AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket) AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket) +AC_DEFINE_UNQUOTED(LDP_VTYSH_PATH, "$quagga_statedir/ldpd.vty",ldpd vty socket) AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket) AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket) AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory) @@ -1615,7 +1654,7 @@ AC_MSG_RESULT($ac_cv_htonl_works) AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile - ospf6d/Makefile isisd/Makefile vtysh/Makefile + ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile pimd/Makefile tests/bgpd.tests/Makefile diff --git a/doc/Makefile.am b/doc/Makefile.am index 4a39f0b01..ffb0bf465 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -87,6 +87,10 @@ if OSPFD man_MANS += ospfd.8 endif +if LDPD +man_MANS += ldpd.8 +endif + if RIPD man_MANS += ripd.8 endif @@ -108,7 +112,7 @@ man_MANS += zebra.8 endif EXTRA_DIST = BGP-TypeCode draft-zebra-00.ms draft-zebra-00.txt \ - bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ripd.8 \ + bgpd.8 isisd.8 ospf6d.8 ospfclient.8 ospfd.8 ldpd.8 ripd.8 \ ripngd.8 pimd.8 vtysh.1 watchquagga.8 zebra.8 quagga.1 \ mpls/ChangeLog.opaque.txt mpls/cli_summary.txt \ mpls/opaque_lsa.txt mpls/ospfd.conf \ diff --git a/doc/ldpd-basic-test-setup.md b/doc/ldpd-basic-test-setup.md new file mode 100644 index 000000000..e5e987f9e --- /dev/null +++ b/doc/ldpd-basic-test-setup.md @@ -0,0 +1,681 @@ +## Topology + +The goal of this test is to verify that the all the basic functionality +of ldpd is working as expected, be it running on Linux or OpenBSD. In +addition to that, more advanced features are also tested, like LDP +sessions over IPv6, MD5 authentication and pseudowire signaling. + +In the topology below there are 3 PE routers, 3 CE routers and one P +router (not attached to any consumer site). + +All routers have IPv4 addresses and OSPF is used as the IGP. The +three routers from the bottom of the picture, P, PE2 and PE3, are also +configured for IPv6 (dual-stack) and static IPv6 routes are used to +provide connectivity among them. + +The three CEs share the same VPLS membership. LDP is used to set up the +LSPs among the PEs and to signal the pseudowires. MD5 authentication is +used to protect all LDP sessions. + +``` + CE1 172.16.1.1/24 + + + | + +---+---+ + | PE1 | + | IOS XE| + | | + +---+---+ + | + | 10.0.1.0/24 + | + +---+---+ + | P | + +------+ IOS XR+------+ + | | | | + | +-------+ | + 10.0.2.0/24 | | 10.0.3.0/24 +2001:db8:2::/64 | | 2001:db8:3::/64 + | | + +---+---+ +---+---+ + | PE2 | | PE3 | + |OpenBSD+-------------+ Linux | + | | | | + +---+---+ 10.0.4.0/24 +---+---+ + | 2001:db8:4::/64 | + + + + 172.16.1.2/24 CE2 CE3 172.16.1.3/24 +``` + +## Configuration + +#### Linux +1 - Enable IPv4/v6 forwarding: +``` +# sysctl -w net.ipv4.ip_forward=1 +# sysctl -w net.ipv6.conf.all.forwarding=1 +``` + +2 - Enable MPLS forwarding: +``` +# modprobe mpls-router +# modprobe mpls-iptunnel +# echo 100000 > /proc/sys/net/mpls/platform_labels +# echo 1 > /proc/sys/net/mpls/conf/eth1/input +# echo 1 > /proc/sys/net/mpls/conf/eth2/input +``` + +3 - Set up the interfaces: +``` +# ip link add name lo1 type dummy +# ip link set dev lo1 up +# ip addr add 4.4.4.4/32 dev lo1 +# ip -6 addr add 4:4:4::4/128 dev lo1 +# ip link set dev eth1 up +# ip addr add 10.0.4.4/24 dev eth1 +# ip -6 addr add 2001:db8:4::4/64 dev eth1 +# ip link set dev eth2 up +# ip addr add 10.0.3.4/24 dev eth2 +# ip -6 addr add 2001:db8:3::4/64 dev eth2 +``` + +4 - Set up the bridge and pseudowire interfaces: +``` +# ip link add type bridge +# ip link set dev bridge0 up +# ip link set dev eth0 up +# ip link set dev eth0 master bridge0 +# ip link add name mpw0 type dummy +# ip link set dev mpw0 up +# ip link set dev mpw0 master bridge0 +# ip link add name mpw1 type dummy +# ip link set dev mpw1 up +# ip link set dev mpw1 master bridge0 +``` + +> NOTE: MPLS support in the Linux kernel is very recent and it still +doesn't support pseudowire interfaces. We are using here dummy interfaces +just to show how the VPLS configuration should look like in the future. + +5 - Add static IPv6 routes for the remote loopbacks: +``` +# ip -6 route add 2:2:2::2/128 via 2001:db8:3::2 +# ip -6 route add 3:3:3::3/128 via 2001:db8:4::3 +``` + +6 - Edit /etc/quagga/ospfd.conf: +``` +router ospf + network 4.4.4.4/32 area 0.0.0.0 + network 10.0.3.4/24 area 0.0.0.0 + network 10.0.4.4/24 area 0.0.0.0 +! +``` + +7 - Edit /etc/quagga/ldpd.conf: +``` +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 4.4.4.4 + dual-stack cisco-interop + neighbor 1.1.1.1 password opensourcerouting + neighbor 2.2.2.2 password opensourcerouting + neighbor 3.3.3.3 password opensourcerouting + ! + address-family ipv4 + discovery transport-address 4.4.4.4 + label local advertise explicit-null + ! + interface eth2 + ! + interface eth1 + ! + ! + address-family ipv6 + discovery transport-address 4:4:4::4 + ttl-security disable + ! + interface eth2 + ! + interface eth1 + ! + ! +! +l2vpn ENG type vpls + bridge br0 + member interface eth0 + ! + member pseudowire mpw0 + neighbor lsr-id 1.1.1.1 + pw-id 100 + ! + member pseudowire mpw1 + neighbor lsr-id 3.3.3.3 + neighbor address 3:3:3::3 + pw-id 100 + ! +! +``` + +> NOTE: We have to disable ttl-security under the ipv6 address-family +in order to interoperate with the IOS-XR router. GTSM is mandatory for +LDPv6 but the IOS-XR implementation is not RFC compliant in this regard. + +8 - Run zebra, ospfd and ldpd. + +#### OpenBSD +1 - Enable IPv4/v6 forwarding: +``` +# sysctl net.inet.ip.forwarding=1 +# sysctl net.inet6.ip6.forwarding=1 +``` + +2 - Enable MPLS forwarding: +``` +# ifconfig em2 10.0.2.3/24 mpls +# ifconfig em3 10.0.4.3/24 mpls +``` + +3 - Set up the interfaces: +``` +# ifconfig lo1 alias 3.3.3.3 netmask 255.255.255.255 +# ifconfig lo1 inet6 3:3:3::3/128 +# ifconfig em2 inet6 2001:db8:2::3/64 +# ifconfig em3 inet6 2001:db8:4::3/64 +``` + +4 - Set up the bridge and pseudowire interfaces: +``` +# ifconfig bridge0 create +# ifconfig bridge0 up +# ifconfig em1 up +# ifconfig bridge0 add em1 +# ifconfig mpw0 create +# ifconfig mpw0 up +# ifconfig bridge0 add mpw0 +# ifconfig mpw1 create +# ifconfig mpw1 up +# ifconfig bridge0 add mpw1 +``` + +5 - Add static IPv6 routes for the remote loopbacks: +``` +# route -n add 4:4:4::4/128 2001:db8:4::4 +# route -n add 2:2:2::2/128 2001:db8:2::2 +``` + +6 - Edit /etc/quagga/ospfd.conf: +``` +router ospf + network 10.0.2.3/24 area 0 + network 10.0.4.3/24 area 0 + network 3.3.3.3/32 area 0 +! +``` + +7 - Edit /etc/quagga/ldpd.conf: +``` +debug mpls ldp messages recv +debug mpls ldp messages sent +debug mpls ldp zebra +! +mpls ldp + router-id 3.3.3.3 + dual-stack cisco-interop + neighbor 1.1.1.1 password opensourcerouting + neighbor 2.2.2.2 password opensourcerouting + neighbor 4.4.4.4 password opensourcerouting + ! + address-family ipv4 + discovery transport-address 3.3.3.3 + label local advertise explicit-null + ! + interface em3 + ! + interface em2 + ! + ! + address-family ipv6 + discovery transport-address 3:3:3::3 + ttl-security disable + ! + interface em3 + ! + interface em2 + ! + ! +! +l2vpn ENG type vpls + bridge br0 + member interface em1 + ! + member pseudowire mpw0 + neighbor lsr-id 1.1.1.1 + pw-id 100 + ! + member pseudowire mpw1 + neighbor lsr-id 4.4.4.4 + neighbor address 4:4:4::4 + pw-id 100 + ! +! +``` + +8 - Run zebra, ospfd and ldpd. + +#### Cisco routers +CE1 (IOS): +``` +interface FastEthernet0/0 + ip address 172.16.1.1 255.255.255.0 + ! +! +``` + +CE2 (IOS): +``` +interface FastEthernet0/0 + ip address 172.16.1.2 255.255.255.0 + ! +! +``` + +CE3 (IOS): +``` +interface FastEthernet0/0 + ip address 172.16.1.3 255.255.255.0 + ! +! +``` + +PE1 - IOS-XE (1): +``` +mpls ldp neighbor 2.2.2.2 password opensourcerouting +mpls ldp neighbor 3.3.3.3 password opensourcerouting +mpls ldp neighbor 4.4.4.4 password opensourcerouting +! +l2vpn vfi context VFI + vpn id 1 + member pseudowire2 + member pseudowire1 +! +bridge-domain 1 + member GigabitEthernet1 service-instance 1 + member vfi VFI +! +interface Loopback1 + ip address 1.1.1.1 255.255.255.255 +! +interface pseudowire1 + encapsulation mpls + neighbor 3.3.3.3 100 +! +interface pseudowire2 + encapsulation mpls + neighbor 4.4.4.4 100 +! +interface GigabitEthernet3 + ip address 10.0.1.1 255.255.255.0 + mpls ip +! +router ospf 1 + network 0.0.0.0 255.255.255.255 area 0 +! +``` + +P - IOS-XR (2): +``` +interface Loopback1 + ipv4 address 2.2.2.2 255.255.255.255 + ipv6 address 2:2:2::2/128 +! +interface GigabitEthernet0/0/0/0 + ipv4 address 10.0.1.2 255.255.255.0 +! +interface GigabitEthernet0/0/0/1 + ipv4 address 10.0.2.2 255.255.255.0 + ipv6 address 2001:db8:2::2/64 + ipv6 enable +! +interface GigabitEthernet0/0/0/2 + ipv4 address 10.0.3.2 255.255.255.0 + ipv6 address 2001:db8:3::2/64 + ipv6 enable +! +router static + address-family ipv6 unicast + 3:3:3::3/128 2001:db8:2::3 + 4:4:4::4/128 2001:db8:3::4 + ! +! +router ospf 1 + router-id 2.2.2.2 + address-family ipv4 unicast + area 0 + interface Loopback1 + ! + interface GigabitEthernet0/0/0/0 + ! + interface GigabitEthernet0/0/0/1 + ! + interface GigabitEthernet0/0/0/2 + ! + ! +! +mpls ldp + router-id 2.2.2.2 + neighbor + 1.1.1.1:0 password clear opensourcerouting + 3.3.3.3:0 password clear opensourcerouting + 4.4.4.4:0 password clear opensourcerouting + ! + address-family ipv4 + ! + address-family ipv6 + discovery transport-address 2:2:2::2 + ! + interface GigabitEthernet0/0/0/0 + address-family ipv4 + ! + ! + interface GigabitEthernet0/0/0/1 + address-family ipv4 + ! + address-family ipv6 + ! + ! + interface GigabitEthernet0/0/0/2 + address-family ipv4 + ! + address-family ipv6 + ! + ! +! +``` + +## Verification - Control Plane + +Using the CLI on the Linux box, the goal is to ensure that everything +is working as expected. + +First, verify that all the required adjacencies and neighborships sessions +were established: + +``` +linux# show mpls ldp discovery +Local LDP Identifier: 4.4.4.4:0 +Discovery Sources: + Interfaces: + eth1: xmit/recv + LDP Id: 3.3.3.3:0, Transport address: 3.3.3.3 + Hold time: 15 sec + LDP Id: 3.3.3.3:0, Transport address: 3:3:3::3 + Hold time: 15 sec + eth2: xmit/recv + LDP Id: 2.2.2.2:0, Transport address: 2.2.2.2 + Hold time: 15 sec + LDP Id: 2.2.2.2:0, Transport address: 2:2:2::2 + Hold time: 15 sec + Targeted Hellos: + 4.4.4.4 -> 1.1.1.1: xmit/recv + LDP Id: 1.1.1.1:0, Transport address: 1.1.1.1 + Hold time: 45 sec + 4:4:4::4 -> 3:3:3::3: xmit/recv + LDP Id: 3.3.3.3:0, Transport address: 3:3:3::3 + Hold time: 45 sec + +linux# show mpls ldp neighbor +Peer LDP Identifier: 1.1.1.1:0 + TCP connection: 4.4.4.4:40921 - 1.1.1.1:646 + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: 00:06:02 + LDP Discovery Sources: + IPv4: + Targeted Hello: 1.1.1.1 + +Peer LDP Identifier: 2.2.2.2:0 + TCP connection: 4:4:4::4:52286 - 2:2:2::2:646 + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: 00:06:02 + LDP Discovery Sources: + IPv4: + Interface: eth2 + IPv6: + Interface: eth2 + +Peer LDP Identifier: 3.3.3.3:0 + TCP connection: 4:4:4::4:60575 - 3:3:3::3:646 + Session Holdtime: 180 sec + State: OPERATIONAL; Downstream-Unsolicited + Up time: 00:05:57 + LDP Discovery Sources: + IPv4: + Interface: eth1 + IPv6: + Targeted Hello: 3:3:3::3 + Interface: eth1 +``` + +Note that the neighborships with the P and PE2 routers were established +over IPv6, since this is the default behavior for dual-stack LSRs, as +specified in RFC 7552. If desired, the **dual-stack transport-connection +prefer ipv4** command can be used to establish these sessions over IPv4 +(the command should be applied an all routers). + +Now, verify that there's a remote label for each PE address: +``` +linux# show mpls ldp binding +1.1.1.1/32 + Local binding: label: 20 + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 imp-null + 2.2.2.2 24000 + 3.3.3.3 20 +2.2.2.2/32 + Local binding: label: 21 + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 18 + 2.2.2.2 imp-null + 3.3.3.3 21 +3.3.3.3/32 + Local binding: label: 22 + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 21 + 2.2.2.2 24003 + 3.3.3.3 imp-null +4.4.4.4/32 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 22 + 2.2.2.2 24001 + 3.3.3.3 22 +10.0.1.0/24 + Local binding: label: 23 + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 imp-null + 2.2.2.2 imp-null + 3.3.3.3 23 +10.0.2.0/24 + Local binding: label: 24 + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 20 + 2.2.2.2 imp-null + 3.3.3.3 imp-null +10.0.3.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 19 + 2.2.2.2 imp-null + 3.3.3.3 24 +10.0.4.0/24 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 1.1.1.1 23 + 2.2.2.2 24002 + 3.3.3.3 imp-null +2:2:2::2/128 + Local binding: label: 18 + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 18 +3:3:3::3/128 + Local binding: label: 19 + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 24007 +4:4:4::4/128 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 24006 + 3.3.3.3 19 +2001:db8:2::/64 + Local binding: label: - + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null + 3.3.3.3 imp-null +2001:db8:3::/64 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 2.2.2.2 imp-null +2001:db8:4::/64 + Local binding: label: imp-null + Remote bindings: + Peer Label + ----------------- --------- + 3.3.3.3 imp-null +``` + +Check if the pseudowires are up: +``` +linux# show l2vpn atom vc +Interface Peer ID VC ID Name Status +--------- --------------- ---------- ---------------- ---------- +mpw1 3.3.3.3 100 ENG UP +mpw0 1.1.1.1 100 ENG UP +``` + +Check the label bindings of the pseudowires: +``` +linux# show l2vpn atom binding + Destination Address: 1.1.1.1, VC ID: 100 + Local Label: 25 + Cbit: 1, VC Type: Ethernet, GroupID: 0 + MTU: 1500 + Remote Label: 16 + Cbit: 1, VC Type: Ethernet, GroupID: 0 + MTU: 1500 + Destination Address: 3.3.3.3, VC ID: 100 + Local Label: 26 + Cbit: 1, VC Type: Ethernet, GroupID: 0 + MTU: 1500 + Remote Label: 26 + Cbit: 1, VC Type: Ethernet, GroupID: 0 + MTU: 1500 +``` + +## Verification - Data Plane + +Verify that all the exchanged label mappings were installed in zebra: +``` +linux# show mpls table + Inbound Outbound + Label Type Nexthop Label +-------- ------- --------------- -------- + 17 LDP 2001:db8:3::2 3 + 19 LDP 2001:db8:3::2 24005 + 20 LDP 10.0.3.2 24000 + 21 LDP 10.0.3.2 3 + 22 LDP 10.0.3.2 24001 + 23 LDP 10.0.3.2 3 + 24 LDP 10.0.3.2 3 + 25 LDP 10.0.3.2 3 + +linux# show ip route ldp +Codes: K - kernel route, C - connected, S - static, R - RIP, + O - OSPF, I - IS-IS, B - BGP, P - PIM, A - Babel, L - LDP, + > - selected route, * - FIB route + +L>* 1.1.1.1/32 [0/0] via 10.0.3.2, eth2 label 24000 +L>* 3.3.3.3/32 [0/0] via 10.0.3.2, eth2 label 24001 +``` + +Verify that all the exchanged label mappings were installed in the kernel: +``` +$ ip -M ro +17 via inet6 2001:db8:3::2 dev eth2 proto zebra +19 as to 24005 via inet6 2001:db8:3::2 dev eth2 proto zebra +20 as to 24000 via inet 10.0.3.2 dev eth2 proto zebra +21 via inet 10.0.3.2 dev eth2 proto zebra +22 as to 24001 via inet 10.0.3.2 dev eth2 proto zebra +23 via inet 10.0.3.2 dev eth2 proto zebra +24 via inet 10.0.3.2 dev eth2 proto zebra +25 via inet 10.0.3.2 dev eth2 proto zebra +$ +$ ip route | grep mpls +1.1.1.1 encap mpls 24000 via 10.0.3.2 dev eth2 proto zebra metric 20 +3.3.3.3 encap mpls 24001 via 10.0.3.2 dev eth2 proto zebra metric 20 +``` + +Now ping PE1's loopback using lo1's address as a source address: +``` +$ ping -c 5 -I 4.4.4.4 1.1.1.1 +PING 1.1.1.1 (1.1.1.1) from 4.4.4.4 : 56(84) bytes of data. +64 bytes from 1.1.1.1: icmp_seq=1 ttl=253 time=3.02 ms +64 bytes from 1.1.1.1: icmp_seq=2 ttl=253 time=3.13 ms +64 bytes from 1.1.1.1: icmp_seq=3 ttl=253 time=3.19 ms +64 bytes from 1.1.1.1: icmp_seq=4 ttl=253 time=3.07 ms +64 bytes from 1.1.1.1: icmp_seq=5 ttl=253 time=3.27 ms + +--- 1.1.1.1 ping statistics --- +5 packets transmitted, 5 received, 0% packet loss, time 4005ms +rtt min/avg/max/mdev = 3.022/3.140/3.278/0.096 ms +``` + +Verify that the ICMP echo request packets are leaving with the MPLS +label advertised by the P router. Also, verify that the ICMP echo reply +packets are arriving with an explicit-null MPLS label: +``` +# tcpdump -n -i eth2 mpls and icmp +tcpdump: verbose output suppressed, use -v or -vv for full protocol decode +listening on eth2, link-type EN10MB (Ethernet), capture size 262144 bytes +10:01:40.758771 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 1, length 64 +10:01:40.761777 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 1, length 64 +10:01:41.760343 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 2, length 64 +10:01:41.763448 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 2, length 64 +10:01:42.761758 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 3, length 64 +10:01:42.764924 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 3, length 64 +10:01:43.763193 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 4, length 64 +10:01:43.766237 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 4, length 64 +10:01:44.764552 MPLS (label 24000, exp 0, [S], ttl 64) IP 4.4.4.4 > 1.1.1.1: ICMP echo request, id 13370, seq 5, length 64 +10:01:44.767803 MPLS (label 0, exp 0, [S], ttl 254) IP 1.1.1.1 > 4.4.4.4: ICMP echo reply, id 13370, seq 5, length 64 +``` diff --git a/doc/ldpd.8 b/doc/ldpd.8 new file mode 100644 index 000000000..092ff39d4 --- /dev/null +++ b/doc/ldpd.8 @@ -0,0 +1,109 @@ +.TH LDPD 8 "29 March 2016" "Quagga LDP daemon" "Version 1.0.20160309" +.SH NAME +ldpd \- an LDP engine for use with Quagga routing software. +.SH SYNOPSIS +.B ldpd +[ +.B \-dhv +] [ +.B \-f +.I config-file +] [ +.B \-i +.I pid-file +] [ +.B \-P +.I port-number +] [ +.B \-A +.I vty-address +] [ +.B \-u +.I user +] [ +.B \-g +.I group +] +.SH DESCRIPTION +.B ldpd +is a component that works with the +.B Quagga +routing engine. +.SH OPTIONS +Options available for the +.B ldpd +command: +.TP +\fB\-d\fR, \fB\-\-daemon\fR +Runs in daemon mode, forking and exiting from tty. +.TP +\fB\-f\fR, \fB\-\-config-file \fR\fIconfig-file\fR +Specifies the config file to use for startup. If not specified this +option will likely default to \fB\fI/usr/local/etc/ldpd.conf\fR. +.TP +\fB\-g\fR, \fB\-\-group \fR\fIgroup\fR +Specify the group to run as. Default is \fIquagga\fR. +.TP +\fB\-h\fR, \fB\-\-help\fR +A brief message. +.TP +\fB\-i\fR, \fB\-\-pid_file \fR\fIpid-file\fR +When ldpd starts its process identifier is written to +\fB\fIpid-file\fR. The init system uses the recorded PID to stop or +restart ldpd. The likely default is \fB\fI/var/run/ldpd.pid\fR. +.TP +\fB\-P\fR, \fB\-\-vty_port \fR\fIport-number\fR +Specify the port that the ldpd VTY will listen on. This defaults to +2612, as specified in \fB\fI/etc/services\fR. +.TP +\fB\-A\fR, \fB\-\-vty_addr \fR\fIvty-address\fR +Specify the address that the ldpd VTY will listen on. Default is all +interfaces. +.TP +\fB\-u\fR, \fB\-\-user \fR\fIuser\fR +Specify the user to run as. Default is \fIquagga\fR. +.TP +\fB\-v\fR, \fB\-\-version\fR +Print the version and exit. +.SH FILES +.TP +.BI /usr/local/sbin/ldpd +The default location of the +.B ldpd +binary. +.TP +.BI /usr/local/etc/ldpd.conf +The default location of the +.B ldpd +config file. +.TP +.BI $(PWD)/ldpd.log +If the +.B ldpd +process is config'd to output logs to a file, then you will find this +file in the directory where you started \fBldpd\fR. +.SH WARNING +This man page is intended to be a quick reference for command line +options. The definitive document is the Info file \fBQuagga\fR. +.SH DIAGNOSTICS +The ldpd process may log to standard output, to a VTY, to a log +file, or through syslog to the system logs. \fBldpd\fR supports many +debugging options, see the Info file, or the source for details. +.SH "SEE ALSO" +.BR bgpd (8), +.BR ripd (8), +.BR ripngd (8), +.BR ospfd (8), +.BR ospf6d (8), +.BR isisd (8), +.BR zebra (8), +.BR vtysh (1) +.SH BUGS +.B ldpd +eats bugs for breakfast. If you have food for the maintainers try +.BI http://bugzilla.quagga.net +.SH AUTHORS +See +.BI http://www.quagga.net +or the Info file for an accurate list of authors. + diff --git a/ldpd/.gitignore b/ldpd/.gitignore new file mode 100644 index 000000000..be90d4211 --- /dev/null +++ b/ldpd/.gitignore @@ -0,0 +1,18 @@ +Makefile +Makefile.in +*.o +ldpd +ldpd.conf +tags +TAGS +.deps +.nfs* +*.lo +*.la +*.a +*.libs +.arch-inventory +.arch-ids +*~ +*.loT + diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am new file mode 100644 index 000000000..c292adf6f --- /dev/null +++ b/ldpd/Makefile.am @@ -0,0 +1,26 @@ +## Process this file with automake to produce Makefile.in. + +AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +AM_CFLAGS = $(WERROR) + +noinst_LIBRARIES = libldp.a +sbin_PROGRAMS = ldpd + +libldp_a_SOURCES = \ + accept.c address.c adjacency.c control.c hello.c init.c interface.c \ + keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \ + ldpe.c log.c neighbor.c notification.c packet.c pfkey.c \ + socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \ + ldp_debug.c ldp_zebra.c + +noinst_HEADERS = \ + control.h lde.h ldpd.h ldpe.h ldp.h log.h ldp_debug.h ldp_vty.h + +ldpd_SOURCES = ldpd.c +ldpd_LDADD = libldp.a ../lib/libzebra.la @LIBCAP@ + +examplesdir = $(exampledir) +dist_examples_DATA = ldpd.conf.sample diff --git a/ldpd/accept.c b/ldpd/accept.c index bc13ad49e..4cb461b90 100644 --- a/ldpd/accept.c +++ b/ldpd/accept.c @@ -16,8 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <stdlib.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" @@ -25,31 +24,30 @@ struct accept_ev { LIST_ENTRY(accept_ev) entry; - struct event ev; - void (*accept_cb)(int, short, void *); + struct thread *ev; + int (*accept_cb)(struct thread *); void *arg; int fd; }; struct { - LIST_HEAD(, accept_ev) queue; - struct event evt; + LIST_HEAD(, accept_ev) queue; + struct thread *evt; } accept_queue; static void accept_arm(void); static void accept_unarm(void); -static void accept_cb(int, short, void *); -static void accept_timeout(int, short, void *); +static int accept_cb(struct thread *); +static int accept_timeout(struct thread *); void accept_init(void) { LIST_INIT(&accept_queue.queue); - evtimer_set(&accept_queue.evt, accept_timeout, NULL); } int -accept_add(int fd, void (*cb)(int, short, void *), void *arg) +accept_add(int fd, int (*cb)(struct thread *), void *arg) { struct accept_ev *av; @@ -60,8 +58,7 @@ accept_add(int fd, void (*cb)(int, short, void *), void *arg) av->arg = arg; LIST_INSERT_HEAD(&accept_queue.queue, av, entry); - event_set(&av->ev, av->fd, EV_READ, accept_cb, av); - event_add(&av->ev, NULL); + av->ev = thread_add_read(master, accept_cb, av, av->fd); log_debug("%s: accepting on fd %d", __func__, fd); @@ -76,7 +73,7 @@ accept_del(int fd) LIST_FOREACH(av, &accept_queue.queue, entry) if (av->fd == fd) { log_debug("%s: %d removed from queue", __func__, fd); - event_del(&av->ev); + THREAD_READ_OFF(av->ev); LIST_REMOVE(av, entry); free(av); return; @@ -86,19 +83,17 @@ accept_del(int fd) void accept_pause(void) { - struct timeval evtpause = { 1, 0 }; - log_debug(__func__); accept_unarm(); - evtimer_add(&accept_queue.evt, &evtpause); + accept_queue.evt = thread_add_timer(master, accept_timeout, NULL, 1); } void accept_unpause(void) { - if (evtimer_pending(&accept_queue.evt, NULL)) { + if (accept_queue.evt != NULL) { log_debug(__func__); - evtimer_del(&accept_queue.evt); + THREAD_TIMER_OFF(accept_queue.evt); accept_arm(); } } @@ -108,7 +103,7 @@ accept_arm(void) { struct accept_ev *av; LIST_FOREACH(av, &accept_queue.queue, entry) - event_add(&av->ev, NULL); + av->ev = thread_add_read(master, accept_cb, av, av->fd); } static void @@ -116,20 +111,26 @@ accept_unarm(void) { struct accept_ev *av; LIST_FOREACH(av, &accept_queue.queue, entry) - event_del(&av->ev); + THREAD_READ_OFF(av->ev); } -static void -accept_cb(int fd, short event, void *arg) +static int +accept_cb(struct thread *thread) { - struct accept_ev *av = arg; - event_add(&av->ev, NULL); - av->accept_cb(fd, event, av->arg); + struct accept_ev *av = THREAD_ARG(thread); + av->ev = thread_add_read(master, accept_cb, av, av->fd); + av->accept_cb(thread); + + return (0); } -static void -accept_timeout(int fd, short event, void *bula) +static int +accept_timeout(struct thread *thread) { + accept_queue.evt = NULL; + log_debug(__func__); accept_arm(); + + return (0); } diff --git a/ldpd/address.c b/ldpd/address.c index 5e95fcc27..1c4c116f2 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -16,15 +16,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "lde.h" #include "log.h" +#include "ldp_debug.h" static void send_address(struct nbr *, int, struct if_addr_head *, unsigned int, int); @@ -94,7 +92,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, } while ((if_addr = LIST_FIRST(addr_list)) != NULL) { - log_debug("msg-out: %s: lsr-id %s, address %s", + debug_msg_send("%s: lsr-id %s address %s", msg_name(msg_type), inet_ntoa(nbr->id), log_addr(af, &if_addr->addr)); @@ -225,9 +223,8 @@ recv_address(struct nbr *nbr, char *buf, uint16_t len) fatalx("recv_address: unknown af"); } - log_debug("msg-in: %s: lsr-id %s, address %s", - msg_name(msg_type), inet_ntoa(nbr->id), - log_addr(lde_addr.af, &lde_addr.addr)); + debug_msg_recv("%s: lsr-id %s address %s", msg_name(msg_type), + inet_ntoa(nbr->id), log_addr(lde_addr.af, &lde_addr.addr)); ldpe_imsg_compose_lde(type, nbr->peerid, 0, &lde_addr, sizeof(lde_addr)); diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 266717729..3607ee96b 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -19,19 +19,15 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" -static void adj_del_single(struct adj *); -static void adj_itimer(int, short, void *); +static int adj_itimer(struct thread *); static void tnbr_del(struct tnbr *); -static void tnbr_hello_timer(int, short, void *); +static int tnbr_hello_timer(struct thread *); static void tnbr_start_hello_timer(struct tnbr *); static void tnbr_stop_hello_timer(struct tnbr *); @@ -52,8 +48,6 @@ adj_new(struct in_addr lsr_id, struct hello_source *source, adj->source = *source; adj->trans_addr = *addr; - evtimer_set(&adj->inactivity_timer, adj_itimer, adj); - LIST_INSERT_HEAD(&global.adj_list, adj, global_entry); switch (source->type) { @@ -154,10 +148,12 @@ adj_get_af(struct adj *adj) /* adjacency timers */ /* ARGSUSED */ -static void -adj_itimer(int fd, short event, void *arg) +static int +adj_itimer(struct thread *thread) { - struct adj *adj = arg; + struct adj *adj = THREAD_ARG(thread); + + adj->inactivity_timer = NULL; log_debug("%s: lsr-id %s", __func__, inet_ntoa(adj->lsr_id)); @@ -166,37 +162,34 @@ adj_itimer(int fd, short event, void *arg) adj->source.target->pw_count == 0) { /* remove dynamic targeted neighbor */ tnbr_del(adj->source.target); - return; + return (0); } adj->source.target->adj = NULL; } adj_del(adj, S_HOLDTIME_EXP); + + return (0); } void adj_start_itimer(struct adj *adj) { - struct timeval tv; - - timerclear(&tv); - tv.tv_sec = adj->holdtime; - if (evtimer_add(&adj->inactivity_timer, &tv) == -1) - fatal(__func__); + THREAD_TIMER_OFF(adj->inactivity_timer); + adj->inactivity_timer = thread_add_timer(master, adj_itimer, adj, + adj->holdtime); } void adj_stop_itimer(struct adj *adj) { - if (evtimer_pending(&adj->inactivity_timer, NULL) && - evtimer_del(&adj->inactivity_timer) == -1) - fatal(__func__); + THREAD_TIMER_OFF(adj->inactivity_timer); } /* targeted neighbors */ struct tnbr * -tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) +tnbr_new(int af, union ldpd_addr *addr) { struct tnbr *tnbr; @@ -206,8 +199,6 @@ tnbr_new(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) tnbr->af = af; tnbr->addr = *addr; tnbr->state = TNBR_STA_DOWN; - tnbr->hello_holdtime = (ldp_af_conf_get(xconf, af))->thello_holdtime; - tnbr->hello_interval = (ldp_af_conf_get(xconf, af))->thello_interval; return (tnbr); } @@ -257,7 +248,7 @@ tnbr_update(struct tnbr *tnbr) else socket_ok = 0; - if (leconf->rtr_id.s_addr != INADDR_ANY) + if (ldp_rtr_id_get(leconf) != INADDR_ANY) rtr_id_ok = 1; else rtr_id_ok = 0; @@ -269,7 +260,6 @@ tnbr_update(struct tnbr *tnbr) tnbr->state = TNBR_STA_ACTIVE; send_hello(HELLO_TARGETED, NULL, tnbr); - evtimer_set(&tnbr->hello_timer, tnbr_hello_timer, tnbr); tnbr_start_hello_timer(tnbr); } else if (tnbr->state == TNBR_STA_ACTIVE) { if (socket_ok && rtr_id_ok) @@ -291,35 +281,51 @@ tnbr_update_all(int af) tnbr_update(tnbr); } +uint16_t +tnbr_get_hello_holdtime(struct tnbr *tnbr) +{ + if ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime != 0) + return ((ldp_af_conf_get(leconf, tnbr->af))->thello_holdtime); + + return (leconf->thello_holdtime); +} + +uint16_t +tnbr_get_hello_interval(struct tnbr *tnbr) +{ + if ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval != 0) + return ((ldp_af_conf_get(leconf, tnbr->af))->thello_interval); + + return (leconf->thello_interval); +} + /* target neighbors timers */ /* ARGSUSED */ -static void -tnbr_hello_timer(int fd, short event, void *arg) +static int +tnbr_hello_timer(struct thread *thread) { - struct tnbr *tnbr = arg; + struct tnbr *tnbr = THREAD_ARG(thread); + tnbr->hello_timer = NULL; send_hello(HELLO_TARGETED, NULL, tnbr); tnbr_start_hello_timer(tnbr); + + return (0); } static void tnbr_start_hello_timer(struct tnbr *tnbr) { - struct timeval tv; - - timerclear(&tv); - tv.tv_sec = tnbr->hello_interval; - if (evtimer_add(&tnbr->hello_timer, &tv) == -1) - fatal(__func__); + THREAD_TIMER_OFF(tnbr->hello_timer); + tnbr->hello_timer = thread_add_timer(master, tnbr_hello_timer, tnbr, + tnbr_get_hello_interval(tnbr)); } static void tnbr_stop_hello_timer(struct tnbr *tnbr) { - if (evtimer_pending(&tnbr->hello_timer, NULL) && - evtimer_del(&tnbr->hello_timer) == -1) - fatal(__func__); + THREAD_TIMER_OFF(tnbr->hello_timer); } struct ctl_adj * diff --git a/ldpd/control.c b/ldpd/control.c index b7cb3f106..ba303cc12 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -16,13 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/stat.h> +#include <zebra.h> #include <sys/un.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> #include "ldpd.h" #include "ldpe.h" @@ -31,11 +26,11 @@ #define CONTROL_BACKLOG 5 -static void control_accept(int, short, void *); +static int control_accept(struct thread *); static struct ctl_conn *control_connbyfd(int); static struct ctl_conn *control_connbypid(pid_t); static void control_close(int); -static void control_dispatch_imsg(int, short, void *); +static int control_dispatch_imsg(struct thread *); struct ctl_conns ctl_conns; @@ -48,11 +43,11 @@ control_init(void) int fd; mode_t old_umask; - if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - 0)) == -1) { + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { log_warn("%s: socket", __func__); return (-1); } + sock_set_nonblock(fd); memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; @@ -106,8 +101,8 @@ control_cleanup(void) } /* ARGSUSED */ -static void -control_accept(int listenfd, short event, void *bula) +static int +control_accept(struct thread *thread) { int connfd; socklen_t len; @@ -115,8 +110,8 @@ control_accept(int listenfd, short event, void *bula) struct ctl_conn *c; len = sizeof(s_un); - if ((connfd = accept4(listenfd, (struct sockaddr *)&s_un, &len, - SOCK_NONBLOCK | SOCK_CLOEXEC)) == -1) { + if ((connfd = accept(THREAD_FD(thread), (struct sockaddr *)&s_un, + &len)) == -1) { /* * Pause accept if we are out of file descriptors, or * libevent will haunt us here too. @@ -125,24 +120,27 @@ control_accept(int listenfd, short event, void *bula) accept_pause(); else if (errno != EWOULDBLOCK && errno != EINTR && errno != ECONNABORTED) - log_warn("%s: accept4", __func__); - return; + log_warn("%s: accept", __func__); + return (0); } + sock_set_nonblock(connfd); if ((c = calloc(1, sizeof(struct ctl_conn))) == NULL) { log_warn(__func__); close(connfd); - return; + return (0); } imsg_init(&c->iev.ibuf, connfd); - c->iev.handler = control_dispatch_imsg; - c->iev.events = EV_READ; - event_set(&c->iev.ev, c->iev.ibuf.fd, c->iev.events, - c->iev.handler, &c->iev); - event_add(&c->iev.ev, NULL); + c->iev.handler_read = control_dispatch_imsg; + c->iev.ev_read = thread_add_read(master, c->iev.handler_read, + &c->iev, c->iev.ibuf.fd); + c->iev.handler_write = ldp_write_handler; + c->iev.ev_write = NULL; TAILQ_INSERT_TAIL(&ctl_conns, c, entry); + + return (0); } static struct ctl_conn * @@ -182,45 +180,40 @@ control_close(int fd) msgbuf_clear(&c->iev.ibuf.w); TAILQ_REMOVE(&ctl_conns, c, entry); - event_del(&c->iev.ev); + THREAD_READ_OFF(c->iev.ev_read); + THREAD_WRITE_OFF(c->iev.ev_write); close(c->iev.ibuf.fd); accept_unpause(); free(c); } /* ARGSUSED */ -static void -control_dispatch_imsg(int fd, short event, void *bula) +static int +control_dispatch_imsg(struct thread *thread) { + int fd = THREAD_FD(thread); struct ctl_conn *c; struct imsg imsg; ssize_t n; unsigned int ifidx; - int verbose; if ((c = control_connbyfd(fd)) == NULL) { log_warnx("%s: fd %d: not found", __func__, fd); - return; + return (0); } - if (event & EV_READ) { - if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || - n == 0) { - control_close(fd); - return; - } - } - if (event & EV_WRITE) { - if (msgbuf_write(&c->iev.ibuf.w) <= 0 && errno != EAGAIN) { - control_close(fd); - return; - } + c->iev.ev_read = NULL; + + if (((n = imsg_read(&c->iev.ibuf)) == -1 && errno != EAGAIN) || + n == 0) { + control_close(fd); + return (0); } for (;;) { if ((n = imsg_get(&c->iev.ibuf, &imsg)) == -1) { control_close(fd); - return; + return (0); } if (n == 0) @@ -230,16 +223,10 @@ control_dispatch_imsg(int fd, short event, void *bula) case IMSG_CTL_FIB_COUPLE: case IMSG_CTL_FIB_DECOUPLE: case IMSG_CTL_RELOAD: - c->iev.ibuf.pid = imsg.hdr.pid; - ldpe_imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); - break; case IMSG_CTL_KROUTE: case IMSG_CTL_KROUTE_ADDR: case IMSG_CTL_IFINFO: - c->iev.ibuf.pid = imsg.hdr.pid; - ldpe_imsg_compose_parent(imsg.hdr.type, - imsg.hdr.pid, imsg.data, - imsg.hdr.len - IMSG_HEADER_SIZE); + /* ignore */ break; case IMSG_CTL_SHOW_INTERFACE: if (imsg.hdr.len == IMSG_HEADER_SIZE + @@ -271,18 +258,7 @@ control_dispatch_imsg(int fd, short event, void *bula) nbr_clear_ctl(imsg.data); break; case IMSG_CTL_LOG_VERBOSE: - if (imsg.hdr.len != IMSG_HEADER_SIZE + - sizeof(verbose)) - break; - - /* forward to other processes */ - ldpe_imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - ldpe_imsg_compose_lde(imsg.hdr.type, 0, imsg.hdr.pid, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); - - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_verbose(verbose); + /* ignore */ break; default: log_debug("%s: error handling imsg %d", __func__, @@ -293,6 +269,8 @@ control_dispatch_imsg(int fd, short event, void *bula) } imsg_event_add(&c->iev); + + return (0); } int diff --git a/ldpd/control.h b/ldpd/control.h index fd6e47071..32c49fdf8 100644 --- a/ldpd/control.h +++ b/ldpd/control.h @@ -19,8 +19,7 @@ #ifndef _CONTROL_H_ #define _CONTROL_H_ -#include <sys/types.h> -#include <sys/queue.h> +#include "openbsd-queue.h" struct ctl_conn { TAILQ_ENTRY(ctl_conn) entry; diff --git a/ldpd/hello.c b/ldpd/hello.c index d0daed347..755b25aa8 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -17,13 +17,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "ldp_debug.h" static int gen_hello_prms_tlv(struct ibuf *buf, uint16_t, uint16_t); static int gen_opt4_hello_prms_tlv(struct ibuf *, uint16_t, uint32_t); @@ -46,7 +45,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr) switch (type) { case HELLO_LINK: af = ia->af; - holdtime = ia->hello_holdtime; + holdtime = if_get_hello_holdtime(ia); flags = 0; fd = (ldp_af_global_get(&global, af))->ldp_disc_socket; @@ -66,7 +65,7 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr) break; case HELLO_TARGETED: af = tnbr->af; - holdtime = tnbr->hello_holdtime; + holdtime = tnbr_get_hello_holdtime(tnbr); flags = F_HELLO_TARGETED; if ((tnbr->flags & F_TNBR_CONFIGURED) || tnbr->pw_count) flags |= F_HELLO_REQ_TARG; @@ -139,6 +138,20 @@ send_hello(enum hello_type type, struct iface_af *ia, struct tnbr *tnbr) return (-1); } + switch (type) { + case HELLO_LINK: + debug_hello_send("iface %s (%s) holdtime %u", ia->iface->name, + af_name(ia->af), holdtime); + break; + case HELLO_TARGETED: + debug_hello_send("targeted-neighbor %s (%s) holdtime %u", + log_addr(tnbr->af, &tnbr->addr), af_name(tnbr->af), + holdtime); + break; + default: + fatalx("send_hello: unknown hello type"); + } + send_packet(fd, af, &dst, ia, buf->buf, buf->wpos); ibuf_free(buf); @@ -152,7 +165,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, { struct adj *adj = NULL; struct nbr *nbr, *nbrt; - uint16_t holdtime, flags; + uint16_t holdtime = 0, flags = 0; int tlvs_rcvd; int ds_tlv; union ldpd_addr trans_addr; @@ -257,7 +270,7 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, F_LDPD_AF_THELLO_ACCEPT))) return; - tnbr = tnbr_new(leconf, af, src); + tnbr = tnbr_new(af, src); tnbr->flags |= F_TNBR_DYNAMIC; tnbr_update(tnbr); LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); @@ -387,19 +400,23 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, if (holdtime == 0) holdtime = LINK_DFLT_HOLDTIME; - adj->holdtime = min(ia->hello_holdtime, holdtime); + adj->holdtime = min(if_get_hello_holdtime(ia), holdtime); break; case HELLO_TARGETED: if (holdtime == 0) holdtime = TARGETED_DFLT_HOLDTIME; - adj->holdtime = min(tnbr->hello_holdtime, holdtime); + adj->holdtime = min(tnbr_get_hello_holdtime(tnbr), holdtime); } if (adj->holdtime != INFINITE_HOLDTIME) adj_start_itimer(adj); else adj_stop_itimer(adj); + debug_hello_recv("%s lsr-id %s transport-address %s holdtime %u%s", + log_hello_src(&source), inet_ntoa(lsr_id), log_addr(af, &trans_addr), + holdtime, (ds_tlv) ? " (dual stack TLV present)" : ""); + if (nbr && nbr->state == NBR_STA_PRESENT && !nbr_pending_idtimer(nbr) && nbr_session_active_role(nbr) && !nbr_pending_connect(nbr)) nbr_establish_connection(nbr); diff --git a/ldpd/init.c b/ldpd/init.c index eb22bf52a..ed6b53c02 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -16,13 +16,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "ldp_debug.h" static int gen_init_prms_tlv(struct ibuf *, struct nbr *); @@ -33,7 +32,7 @@ send_init(struct nbr *nbr) uint16_t size; int err = 0; - log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); + debug_msg_send("initialization: lsr-id %s", inet_ntoa(nbr->id)); size = LDP_HDR_SIZE + LDP_MSG_SIZE + SESS_PRMS_SIZE; if ((buf = ibuf_open(size)) == NULL) @@ -59,7 +58,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) struct sess_prms_tlv sess; uint16_t max_pdu_len; - log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); + debug_msg_recv("initialization: lsr-id %s", inet_ntoa(nbr->id)); memcpy(&msg, buf, sizeof(msg)); buf += LDP_MSG_SIZE; @@ -82,7 +81,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) session_shutdown(nbr, S_KEEPALIVE_BAD, msg.id, msg.type); return (-1); } - if (sess.lsr_id != leconf->rtr_id.s_addr || + if (sess.lsr_id != ldp_rtr_id_get(leconf) || ntohs(sess.lspace_id) != 0) { session_shutdown(nbr, S_NO_HELLO, msg.id, msg.type); return (-1); diff --git a/ldpd/interface.c b/ldpd/interface.c index ff4c8f169..b6472fe5e 100644 --- a/ldpd/interface.c +++ b/ldpd/interface.c @@ -18,22 +18,20 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/time.h> -#include <arpa/inet.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "sockopt.h" + static struct if_addr *if_addr_new(struct kaddr *); static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); static int if_start(struct iface *, int); static int if_reset(struct iface *, int); static void if_update_af(struct iface_af *, int); -static void if_hello_timer(int, short, void *); +static int if_hello_timer(struct thread *); static void if_start_hello_timer(struct iface_af *); static void if_stop_hello_timer(struct iface_af *); static int if_join_ipv4_group(struct iface *, struct in_addr *); @@ -50,20 +48,9 @@ if_new(struct kif *kif) fatal("if_new: calloc"); strlcpy(iface->name, kif->ifname, sizeof(iface->name)); - - /* get type */ - if (kif->flags & IFF_POINTOPOINT) - iface->type = IF_TYPE_POINTOPOINT; - if (kif->flags & IFF_BROADCAST && - kif->flags & IFF_MULTICAST) - iface->type = IF_TYPE_BROADCAST; - - /* get index and flags */ LIST_INIT(&iface->addr_list); - iface->ifindex = kif->ifindex; - iface->flags = kif->flags; - iface->linkstate = kif->link_state; - iface->if_type = kif->if_type; + if (kif->ifindex) + if_update_info(iface, kif); /* ipv4 */ iface->ipv4.af = AF_INET; @@ -112,6 +99,33 @@ if_exit(struct iface *iface) } } +struct iface * +if_lookup_name(struct ldpd_conf *xconf, const char *ifname) +{ + struct iface *iface; + + LIST_FOREACH(iface, &xconf->iface_list, entry) + if (strcmp(iface->name, ifname) == 0) + return (iface); + + return (NULL); +} + +void +if_update_info(struct iface *iface, struct kif *kif) +{ + /* get type */ + if (kif->flags & IFF_POINTOPOINT) + iface->type = IF_TYPE_POINTOPOINT; + if (kif->flags & IFF_BROADCAST && + kif->flags & IFF_MULTICAST) + iface->type = IF_TYPE_BROADCAST; + + /* get index and flags */ + iface->ifindex = kif->ifindex; + iface->flags = kif->flags; +} + struct iface_af * iface_af_get(struct iface *iface, int af) { @@ -258,7 +272,6 @@ if_start(struct iface *iface, int af) send_hello(HELLO_LINK, ia, NULL); - evtimer_set(&ia->hello_timer, if_hello_timer, ia); if_start_hello_timer(ia); return (0); } @@ -328,7 +341,7 @@ if_update_af(struct iface_af *ia, int link_ok) else socket_ok = 0; - if (leconf->rtr_id.s_addr != INADDR_ANY) + if (ldp_rtr_id_get(leconf) != INADDR_ANY) rtr_id_ok = 1; else rtr_id_ok = 0; @@ -354,8 +367,7 @@ if_update(struct iface *iface, int af) { int link_ok; - link_ok = (iface->flags & IFF_UP) && - LINK_STATE_IS_UP(iface->linkstate); + link_ok = (iface->flags & IFF_UP) && (iface->flags & IFF_RUNNING); if (af == AF_INET || af == AF_UNSPEC) if_update_af(&iface->ipv4, link_ok); @@ -372,34 +384,56 @@ if_update_all(int af) if_update(iface, af); } +uint16_t +if_get_hello_holdtime(struct iface_af *ia) +{ + if (ia->hello_holdtime != 0) + return (ia->hello_holdtime); + + if ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime != 0) + return ((ldp_af_conf_get(leconf, ia->af))->lhello_holdtime); + + return (leconf->lhello_holdtime); +} + +uint16_t +if_get_hello_interval(struct iface_af *ia) +{ + if (ia->hello_interval != 0) + return (ia->hello_interval); + + if ((ldp_af_conf_get(leconf, ia->af))->lhello_interval != 0) + return ((ldp_af_conf_get(leconf, ia->af))->lhello_interval); + + return (leconf->lhello_interval); +} + /* timers */ /* ARGSUSED */ -static void -if_hello_timer(int fd, short event, void *arg) +static int +if_hello_timer(struct thread *thread) { - struct iface_af *ia = arg; + struct iface_af *ia = THREAD_ARG(thread); + ia->hello_timer = NULL; send_hello(HELLO_LINK, ia, NULL); if_start_hello_timer(ia); + + return (0); } static void if_start_hello_timer(struct iface_af *ia) { - struct timeval tv; - - timerclear(&tv); - tv.tv_sec = ia->hello_interval; - if (evtimer_add(&ia->hello_timer, &tv) == -1) - fatal(__func__); + THREAD_TIMER_OFF(ia->hello_timer); + ia->hello_timer = thread_add_timer(master, if_hello_timer, ia, + if_get_hello_interval(ia)); } static void if_stop_hello_timer(struct iface_af *ia) { - if (evtimer_pending(&ia->hello_timer, NULL) && - evtimer_del(&ia->hello_timer) == -1) - fatal(__func__); + THREAD_TIMER_OFF(ia->hello_timer); } struct ctl_iface * @@ -414,11 +448,9 @@ if_to_ctl(struct iface_af *ia) ictl.ifindex = ia->iface->ifindex; ictl.state = ia->state; ictl.flags = ia->iface->flags; - ictl.linkstate = ia->iface->linkstate; ictl.type = ia->iface->type; - ictl.if_type = ia->iface->if_type; - ictl.hello_holdtime = ia->hello_holdtime; - ictl.hello_interval = ia->hello_interval; + ictl.hello_holdtime = if_get_hello_holdtime(ia); + ictl.hello_interval = if_get_hello_interval(ia); gettimeofday(&now, NULL); if (ia->state != IF_STA_DOWN && @@ -450,16 +482,15 @@ if_get_ipv4_addr(struct iface *iface) static int if_join_ipv4_group(struct iface *iface, struct in_addr *addr) { - struct ip_mreq mreq; + struct in_addr if_addr; log_debug("%s: interface %s addr %s", __func__, iface->name, inet_ntoa(*addr)); - mreq.imr_multiaddr = *addr; - mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); + if_addr.s_addr = if_get_ipv4_addr(iface); - if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, - IP_ADD_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { + if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket, + IP_ADD_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) { log_warn("%s: error IP_ADD_MEMBERSHIP, interface %s address %s", __func__, iface->name, inet_ntoa(*addr)); return (-1); @@ -470,16 +501,15 @@ if_join_ipv4_group(struct iface *iface, struct in_addr *addr) static int if_leave_ipv4_group(struct iface *iface, struct in_addr *addr) { - struct ip_mreq mreq; + struct in_addr if_addr; log_debug("%s: interface %s addr %s", __func__, iface->name, inet_ntoa(*addr)); - mreq.imr_multiaddr = *addr; - mreq.imr_interface.s_addr = if_get_ipv4_addr(iface); + if_addr.s_addr = if_get_ipv4_addr(iface); - if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, - IP_DROP_MEMBERSHIP, (void *)&mreq, sizeof(mreq)) < 0) { + if (setsockopt_ipv4_multicast(global.ipv4.ldp_disc_socket, + IP_DROP_MEMBERSHIP, if_addr, addr->s_addr, iface->ifindex) < 0) { log_warn("%s: error IP_DROP_MEMBERSHIP, interface %s " "address %s", __func__, iface->name, inet_ntoa(*addr)); return (-1); diff --git a/ldpd/keepalive.c b/ldpd/keepalive.c index 4cd49d485..f9a7d850f 100644 --- a/ldpd/keepalive.c +++ b/ldpd/keepalive.c @@ -16,12 +16,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "ldp_debug.h" void send_keepalive(struct nbr *nbr) @@ -37,6 +37,8 @@ send_keepalive(struct nbr *nbr) size -= LDP_HDR_SIZE; gen_msg_hdr(buf, MSG_TYPE_KEEPALIVE, size); + debug_kalive_send("keepalive: lsr-id %s", inet_ntoa(nbr->id)); + evbuf_enqueue(&nbr->tcp->wbuf, buf); } @@ -51,6 +53,8 @@ recv_keepalive(struct nbr *nbr, char *buf, uint16_t len) return (-1); } + debug_kalive_recv("keepalive: lsr-id %s", inet_ntoa(nbr->id)); + if (nbr->state != NBR_STA_OPER) nbr_fsm(nbr, NBR_EVT_KEEPALIVE_RCVD); diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c index 22c98745e..db382e484 100644 --- a/ldpd/l2vpn.c +++ b/ldpd/l2vpn.c @@ -19,10 +19,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" @@ -47,6 +44,7 @@ l2vpn_new(const char *name) LIST_INIT(&l2vpn->if_list); LIST_INIT(&l2vpn->pw_list); + LIST_INIT(&l2vpn->pw_inactive_list); return (l2vpn); } @@ -77,6 +75,10 @@ l2vpn_del(struct l2vpn *l2vpn) LIST_REMOVE(pw, entry); free(pw); } + while ((pw = LIST_FIRST(&l2vpn->pw_inactive_list)) != NULL) { + LIST_REMOVE(pw, entry); + free(pw); + } free(l2vpn); } @@ -111,7 +113,6 @@ l2vpn_if_new(struct l2vpn *l2vpn, struct kif *kif) strlcpy(lif->ifname, kif->ifname, sizeof(lif->ifname)); lif->ifindex = kif->ifindex; lif->flags = kif->flags; - lif->link_state = kif->link_state; return (lif); } @@ -128,6 +129,19 @@ l2vpn_if_find(struct l2vpn *l2vpn, unsigned int ifindex) return (NULL); } +struct l2vpn_if * +l2vpn_if_find_name(struct l2vpn *l2vpn, const char *ifname) +{ + struct l2vpn_if *lif; + + LIST_FOREACH(lif, &l2vpn->if_list, entry) + if (strcmp(lif->ifname, ifname) == 0) + return (lif); + + return (NULL); +} + + struct l2vpn_pw * l2vpn_pw_new(struct l2vpn *l2vpn, struct kif *kif) { @@ -151,6 +165,24 @@ l2vpn_pw_find(struct l2vpn *l2vpn, unsigned int ifindex) LIST_FOREACH(pw, &l2vpn->pw_list, entry) if (pw->ifindex == ifindex) return (pw); + LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) + if (pw->ifindex == ifindex) + return (pw); + + return (NULL); +} + +struct l2vpn_pw * +l2vpn_pw_find_name(struct l2vpn *l2vpn, const char *ifname) +{ + struct l2vpn_pw *pw; + + LIST_FOREACH(pw, &l2vpn->pw_list, entry) + if (strcmp(pw->ifname, ifname) == 0) + return (pw); + LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) + if (strcmp(pw->ifname, ifname) == 0) + return (pw); return (NULL); } @@ -399,6 +431,8 @@ l2vpn_pw_ctl(pid_t pid) LIST_FOREACH(l2vpn, &ldeconf->l2vpn_list, entry) LIST_FOREACH(pw, &l2vpn->pw_list, entry) { memset(&pwctl, 0, sizeof(pwctl)); + strlcpy(pwctl.l2vpn_name, pw->l2vpn->name, + sizeof(pwctl.l2vpn_name)); strlcpy(pwctl.ifname, pw->ifname, sizeof(pwctl.ifname)); pwctl.pwid = pw->pwid; @@ -438,6 +472,8 @@ l2vpn_binding_ctl(pid_t pid) pwctl.local_label = fn->local_label; pwctl.local_gid = 0; pwctl.local_ifmtu = pw->l2vpn->mtu; + pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ? + 1 : 0; } else pwctl.local_label = NO_LABEL; @@ -450,6 +486,9 @@ l2vpn_binding_ctl(pid_t pid) pwctl.remote_gid = me->map.fec.pwid.group_id; if (me->map.flags & F_MAP_PW_IFMTU) pwctl.remote_ifmtu = me->map.fec.pwid.ifmtu; + if (pw) + pwctl.remote_cword = (pw->flags & F_PW_CWORD) ? + 1 : 0; lde_imsg_compose_ldpe(IMSG_CTL_SHOW_L2VPN_BINDING, 0, pid, &pwctl, sizeof(pwctl)); @@ -489,7 +528,7 @@ ldpe_l2vpn_pw_init(struct l2vpn_pw *pw) tnbr = tnbr_find(leconf, pw->af, &pw->addr); if (tnbr == NULL) { - tnbr = tnbr_new(leconf, pw->af, &pw->addr); + tnbr = tnbr_new(pw->af, &pw->addr); tnbr_update(tnbr); LIST_INSERT_HEAD(&leconf->tnbr_list, tnbr, entry); } diff --git a/ldpd/labelmapping.c b/ldpd/labelmapping.c index 88e64071b..62f2a620d 100644 --- a/ldpd/labelmapping.c +++ b/ldpd/labelmapping.c @@ -17,17 +17,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netmpls/mpls.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "ldp_debug.h" + +#include "mpls.h" static void enqueue_pdu(struct nbr *, struct ibuf *, uint16_t); static int gen_label_tlv(struct ibuf *, uint32_t); @@ -127,8 +124,8 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) return; } - log_debug("msg-out: %s: lsr-id %s, fec %s, label %s", - msg_name(type), inet_ntoa(nbr->id), log_map(&me->map), + debug_msg_send("%s: lsr-id %s fec %s label %s", msg_name(type), + inet_ntoa(nbr->id), log_map(&me->map), log_label(me->map.label)); TAILQ_REMOVE(mh, me, entry); @@ -399,7 +396,7 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) if (me->map.flags & F_MAP_REQ_ID) me->map.requestid = reqid; - log_debug("msg-in: label mapping: lsr-id %s, fec %s, label %s", + debug_msg_recv("%s: lsr-id %s fec %s label %s", msg_name(type), inet_ntoa(nbr->id), log_map(&me->map), log_label(me->map.label)); diff --git a/ldpd/lde.c b/ldpd/lde.c index 8859ed25b..ae29ef6a7 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -19,31 +19,24 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netmpls/mpls.h> -#include <arpa/inet.h> -#include <errno.h> -#include <stdlib.h> -#include <signal.h> -#include <string.h> -#include <pwd.h> -#include <unistd.h> -#include <limits.h> +#include <zebra.h> #include "ldp.h" #include "ldpd.h" #include "ldpe.h" #include "log.h" #include "lde.h" +#include "ldp_debug.h" -static void lde_sig_handler(int sig, short, void *); -static __dead void lde_shutdown(void); -static int lde_imsg_compose_parent(int, pid_t, void *, uint16_t); -static void lde_dispatch_imsg(int, short, void *); -static void lde_dispatch_parent(int, short, void *); +#include <lib/log.h> +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "mpls.h" + +static void lde_shutdown(void); +static int lde_dispatch_imsg(struct thread *); +static int lde_dispatch_parent(struct thread *); static __inline int lde_nbr_compare(struct lde_nbr *, struct lde_nbr *); static struct lde_nbr *lde_nbr_new(uint32_t, struct lde_nbr *); @@ -65,89 +58,101 @@ struct nbr_tree lde_nbrs = RB_INITIALIZER(&lde_nbrs); static struct imsgev *iev_ldpe; static struct imsgev *iev_main; -/* ARGSUSED */ -static void -lde_sig_handler(int sig, short event, void *arg) +/* Master of threads. */ +struct thread_master *master; + +/* lde privileges */ +static zebra_capabilities_t _caps_p [] = { - /* - * signal handler rules don't apply, libevent decouples for us - */ + /* none */ +}; - switch (sig) { - case SIGINT: - case SIGTERM: - lde_shutdown(); - /* NOTREACHED */ - default: - fatalx("unexpected signal"); - } +static struct zebra_privs_t lde_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) + .user = QUAGGA_USER, + .group = QUAGGA_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0 +}; + +/* SIGINT / SIGTERM handler. */ +static void +sigint(void) +{ + lde_shutdown(); } +static struct quagga_signal_t lde_signals[] = +{ + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, +}; + /* label decision engine */ void -lde(int debug, int verbose) +lde(const char *user, const char *group) { - struct event ev_sigint, ev_sigterm; + struct thread thread; struct timeval now; - struct passwd *pw; ldeconf = config_new_empty(); - log_init(debug); - log_verbose(verbose); - +#ifdef HAVE_SETPROCTITLE setproctitle("label decision engine"); +#endif ldpd_process = PROC_LDE_ENGINE; - if ((pw = getpwnam(LDPD_USER)) == NULL) - fatal("getpwnam"); - - if (chroot(pw->pw_dir) == -1) - fatal("chroot"); - if (chdir("/") == -1) - fatal("chdir(\"/\")"); - - if (setgroups(1, &pw->pw_gid) || - setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || - setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) - fatal("can't drop privileges"); + /* drop privileges */ + if (user) + lde_privs.user = user; + if (group) + lde_privs.group = group; + zprivs_init(&lde_privs); +#ifdef HAVE_PLEDGE if (pledge("stdio recvfd", NULL) == -1) fatal("pledge"); +#endif - event_init(); + master = thread_master_create(); /* setup signal handler */ - signal_set(&ev_sigint, SIGINT, lde_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, lde_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); + signal_init(master, array_size(lde_signals), lde_signals); /* setup pipe and event handler to the parent process */ if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) fatal(NULL); imsg_init(&iev_main->ibuf, 3); - iev_main->handler = lde_dispatch_parent; - iev_main->events = EV_READ; - event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, - iev_main->handler, iev_main); - event_add(&iev_main->ev, NULL); - - /* setup and start the LIB garbage collector */ - evtimer_set(&gc_timer, lde_gc_timer, NULL); + iev_main->handler_read = lde_dispatch_parent; + iev_main->ev_read = thread_add_read(master, iev_main->handler_read, + iev_main, iev_main->ibuf.fd); + iev_main->handler_write = ldp_write_handler; + iev_main->ev_write = NULL; + + /* start the LIB garbage collector */ lde_gc_start_timer(); gettimeofday(&now, NULL); global.uptime = now.tv_sec; - event_dispatch(); - - lde_shutdown(); + /* Fetch next active thread. */ + while (thread_fetch(master, &thread)) + thread_call(&thread); } -static __dead void +static void lde_shutdown(void) { /* close pipes */ @@ -170,7 +175,7 @@ lde_shutdown(void) } /* imesg */ -static int +int lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen) { return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); @@ -185,10 +190,10 @@ lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data, } /* ARGSUSED */ -static void -lde_dispatch_imsg(int fd, short event, void *bula) +static int +lde_dispatch_imsg(struct thread *thread) { - struct imsgev *iev = bula; + struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; struct lde_nbr *ln; @@ -196,20 +201,14 @@ lde_dispatch_imsg(int fd, short event, void *bula) struct lde_addr lde_addr; struct notify_msg nm; ssize_t n; - int shut = 0, verbose; + int shut = 0; - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* connection closed */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* connection closed */ - shut = 1; - } + iev->ev_read = NULL; + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + shut = 1; for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -353,11 +352,6 @@ lde_dispatch_imsg(int fd, short event, void *bula) lde_imsg_compose_ldpe(IMSG_CTL_END, 0, imsg.hdr.pid, NULL, 0); break; - case IMSG_CTL_LOG_VERBOSE: - /* already checked by ldpe */ - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_verbose(verbose); - break; default: log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type); @@ -368,15 +362,18 @@ lde_dispatch_imsg(int fd, short event, void *bula) if (!shut) imsg_event_add(iev); else { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + /* this pipe is dead, so remove the event handlers and exit */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + lde_shutdown(); } + + return (0); } /* ARGSUSED */ -static void -lde_dispatch_parent(int fd, short event, void *bula) +static int +lde_dispatch_parent(struct thread *thread) { static struct ldpd_conf *nconf; struct iface *niface; @@ -387,24 +384,19 @@ lde_dispatch_parent(int fd, short event, void *bula) struct l2vpn_pw *npw; struct imsg imsg; struct kroute kr; - struct imsgev *iev = bula; + int fd = THREAD_FD(thread); + struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; ssize_t n; int shut = 0; struct fec fec; - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* connection closed */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) /* connection closed */ - shut = 1; - } + iev->ev_read = NULL; + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + shut = 1; for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -462,11 +454,11 @@ lde_dispatch_parent(int fd, short event, void *bula) if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL) fatal(NULL); imsg_init(&iev_ldpe->ibuf, fd); - iev_ldpe->handler = lde_dispatch_imsg; - iev_ldpe->events = EV_READ; - event_set(&iev_ldpe->ev, iev_ldpe->ibuf.fd, - iev_ldpe->events, iev_ldpe->handler, iev_ldpe); - event_add(&iev_ldpe->ev, NULL); + iev_ldpe->handler_read = lde_dispatch_imsg; + iev_ldpe->ev_read = thread_add_read(master, + iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd); + iev_ldpe->handler_write = ldp_write_handler; + iev_ldpe->ev_write = NULL; break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == @@ -513,6 +505,7 @@ lde_dispatch_parent(int fd, short event, void *bula) LIST_INIT(&nl2vpn->if_list); LIST_INIT(&nl2vpn->pw_list); + LIST_INIT(&nl2vpn->pw_inactive_list); LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry); break; @@ -532,10 +525,26 @@ lde_dispatch_parent(int fd, short event, void *bula) npw->l2vpn = nl2vpn; LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry); break; + case IMSG_RECONF_L2VPN_IPW: + if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) + fatal(NULL); + memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); + + npw->l2vpn = nl2vpn; + LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry); + break; case IMSG_RECONF_END: merge_config(ldeconf, nconf); nconf = NULL; break; + case IMSG_DEBUG_UPDATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(ldp_debug)) { + log_warnx("%s: wrong imsg len", __func__); + break; + } + memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug)); + break; default: log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type); @@ -546,10 +555,13 @@ lde_dispatch_parent(int fd, short event, void *bula) if (!shut) imsg_event_add(iev); else { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + /* this pipe is dead, so remove the event handlers and exit */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + lde_shutdown(); } + + return (0); } uint32_t @@ -557,7 +569,10 @@ lde_assign_label(void) { static uint32_t label = MPLS_LABEL_RESERVED_MAX; - /* XXX some checks needed */ + /* + * TODO: request label to zebra or define a range of labels for ldpd. + */ + label++; return (label); } diff --git a/ldpd/lde.h b/ldpd/lde.h index b0f7b2043..0fce5565a 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -21,9 +21,8 @@ #ifndef _LDE_H_ #define _LDE_H_ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> +#include "openbsd-queue.h" +#include "openbsd-tree.h" enum fec_type { FEC_TYPE_IPV4, @@ -121,10 +120,11 @@ struct fec_node { extern struct ldpd_conf *ldeconf; extern struct fec_tree ft; extern struct nbr_tree lde_nbrs; -extern struct event gc_timer; +extern struct thread *gc_timer; /* lde.c */ -void lde(int, int); +void lde(const char *, const char *); +int lde_imsg_compose_parent(int, pid_t, void *, uint16_t); int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t); uint32_t lde_assign_label(void); void lde_send_change_klabel(struct fec_node *, struct fec_nh *); @@ -173,7 +173,7 @@ void lde_check_release(struct map *, struct lde_nbr *); void lde_check_release_wcard(struct map *, struct lde_nbr *); void lde_check_withdraw(struct map *, struct lde_nbr *); void lde_check_withdraw_wcard(struct map *, struct lde_nbr *); -void lde_gc_timer(int, short, void *); +int lde_gc_timer(struct thread *); void lde_gc_start_timer(void); void lde_gc_stop_timer(void); @@ -185,8 +185,10 @@ void l2vpn_init(struct l2vpn *); void l2vpn_exit(struct l2vpn *); struct l2vpn_if *l2vpn_if_new(struct l2vpn *, struct kif *); struct l2vpn_if *l2vpn_if_find(struct l2vpn *, unsigned int); +struct l2vpn_if *l2vpn_if_find_name(struct l2vpn *, const char *); struct l2vpn_pw *l2vpn_pw_new(struct l2vpn *, struct kif *); struct l2vpn_pw *l2vpn_pw_find(struct l2vpn *, unsigned int); +struct l2vpn_pw *l2vpn_pw_find_name(struct l2vpn *, const char *); void l2vpn_pw_init(struct l2vpn_pw *); void l2vpn_pw_exit(struct l2vpn_pw *); void l2vpn_pw_reset(struct l2vpn_pw *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index d9c1f544f..568761bd6 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -17,17 +17,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/socket.h> -#include <netmpls/mpls.h> -#include <stdlib.h> -#include <string.h> -#include <limits.h> +#include <zebra.h> #include "ldpd.h" #include "lde.h" #include "log.h" +#include "mpls.h" + static __inline int fec_compare(struct fec *, struct fec *); static int lde_nbr_is_nexthop(struct fec_node *, struct lde_nbr *); @@ -40,7 +37,7 @@ static void fec_nh_del(struct fec_nh *); RB_GENERATE(fec_tree, fec, entry, fec_compare) struct fec_tree ft = RB_INITIALIZER(&ft); -struct event gc_timer; +struct thread *gc_timer; /* FEC tree functions */ void @@ -165,6 +162,7 @@ rt_dump(pid_t pid) LIST_EMPTY(&fn->downstream)) continue; + rtctl.first = 1; switch (fn->fec.type) { case FEC_TYPE_IPV4: rtctl.af = AF_INET; @@ -188,6 +186,7 @@ rt_dump(pid_t pid) lde_imsg_compose_ldpe(IMSG_CTL_SHOW_LIB, 0, pid, &rtctl, sizeof(rtctl)); + rtctl.first = 0; } if (LIST_EMPTY(&fn->downstream)) { rtctl.in_use = 0; @@ -338,9 +337,6 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, if (fec_nh_find(fn, af, nexthop, priority) != NULL) return; - log_debug("lde add fec %s nexthop %s", - log_fec(&fn->fec), log_addr(af, nexthop)); - if (fn->fec.type == FEC_TYPE_PWID) fn->data = data; @@ -396,9 +392,6 @@ lde_kernel_remove(struct fec *fec, int af, union ldpd_addr *nexthop, /* route lost */ return; - log_debug("lde remove fec %s nexthop %s", - log_fec(&fn->fec), log_addr(af, nexthop)); - lde_send_delete_klabel(fn, fnh); fec_nh_del(fnh); if (LIST_EMPTY(&fn->nexthops)) { @@ -738,8 +731,8 @@ lde_check_withdraw_wcard(struct map *map, struct lde_nbr *ln) /* gabage collector timer: timer to remove dead entries from the LIB */ /* ARGSUSED */ -void -lde_gc_timer(int fd, short event, void *arg) +int +lde_gc_timer(struct thread *thread) { struct fec *fec, *safe; struct fec_node *fn; @@ -762,23 +755,20 @@ lde_gc_timer(int fd, short event, void *arg) log_debug("%s: %u entries removed", __func__, count); lde_gc_start_timer(); + + return (0); } void lde_gc_start_timer(void) { - struct timeval tv; - - timerclear(&tv); - tv.tv_sec = LDE_GC_INTERVAL; - if (evtimer_add(&gc_timer, &tv) == -1) - fatal(__func__); + THREAD_TIMER_OFF(gc_timer); + gc_timer = thread_add_timer(master, lde_gc_timer, NULL, + LDE_GC_INTERVAL); } void lde_gc_stop_timer(void) { - if (evtimer_pending(&gc_timer, NULL) && - evtimer_del(&gc_timer) == -1) - fatal(__func__); + THREAD_TIMER_OFF(gc_timer); } diff --git a/ldpd/ldp.h b/ldpd/ldp.h index 77034b30a..c421cddc3 100644 --- a/ldpd/ldp.h +++ b/ldpd/ldp.h @@ -23,8 +23,6 @@ #ifndef _LDP_H_ #define _LDP_H_ -#include <sys/types.h> - /* misc */ #define LDP_VERSION 1 #define LDP_PORT 646 @@ -106,7 +104,7 @@ struct ldp_hdr { uint16_t length; uint32_t lsr_id; uint16_t lspace_id; -} __packed; +} __attribute__ ((packed)); #define LDP_HDR_SIZE 10 /* actual size of the LDP header */ #define LDP_HDR_PDU_LEN 6 /* minimum "PDU Length" */ @@ -125,7 +123,7 @@ struct ldp_msg { uint32_t id; /* Mandatory Parameters */ /* Optional Parameters */ -} __packed; +} __attribute__ ((packed)); #define LDP_MSG_SIZE 8 /* minimum size of LDP message */ #define LDP_MSG_LEN 4 /* minimum "Message Length" */ @@ -212,7 +210,7 @@ struct sess_prms_tlv { uint16_t max_pdu_len; uint32_t lsr_id; uint16_t lspace_id; -} __packed; +} __attribute__ ((packed)); #define SESS_PRMS_SIZE 18 #define SESS_PRMS_LEN 14 @@ -223,7 +221,7 @@ struct status_tlv { uint32_t status_code; uint32_t msg_id; uint16_t msg_type; -} __packed; +} __attribute__ ((packed)); #define STATUS_SIZE 14 #define STATUS_TLV_LEN 10 @@ -237,7 +235,7 @@ struct address_list_tlv { uint16_t length; uint16_t family; /* address entries */ -} __packed; +} __attribute__ ((packed)); #define ADDR_LIST_SIZE 6 diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c new file mode 100644 index 000000000..15dd06a0f --- /dev/null +++ b/ldpd/ldp_debug.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "command.h" +#include "vty.h" + +#include "ldpd.h" +#include "ldp_debug.h" +#include "ldp_vty.h" + +struct ldp_debug conf_ldp_debug; +struct ldp_debug ldp_debug; + +/* Debug node. */ +struct cmd_node ldp_debug_node = +{ + DEBUG_NODE, + "", + 1 +}; + +int +ldp_vty_debug(struct vty *vty, struct vty_arg *args[]) +{ + const char *type_str, *dir_str; + int disable, all; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + type_str = vty_get_arg_value(args, "type"); + + if (strcmp(type_str, "discovery") == 0) { + dir_str = vty_get_arg_value(args, "dir"); + if (dir_str == NULL) + return (CMD_WARNING); + + if (dir_str[0] == 'r') { + if (disable) + DEBUG_OFF(hello, HELLO_RECV); + else + DEBUG_ON(hello, HELLO_RECV); + } else { + if (disable) + DEBUG_OFF(hello, HELLO_SEND); + else + DEBUG_ON(hello, HELLO_SEND); + } + } else if (strcmp(type_str, "errors") == 0) { + if (disable) + DEBUG_OFF(errors, ERRORS); + else + DEBUG_ON(errors, ERRORS); + } else if (strcmp(type_str, "event") == 0) { + if (disable) + DEBUG_OFF(event, EVENT); + else + DEBUG_ON(event, EVENT); + } else if (strcmp(type_str, "messages") == 0) { + all = (vty_get_arg_value(args, "all")) ? 1 : 0; + dir_str = vty_get_arg_value(args, "dir"); + if (dir_str == NULL) + return (CMD_WARNING); + + if (dir_str[0] == 'r') { + if (disable) { + DEBUG_OFF(msg, MSG_RECV); + DEBUG_OFF(msg, MSG_RECV_ALL); + } else { + DEBUG_ON(msg, MSG_RECV); + if (all) + DEBUG_ON(msg, MSG_RECV_ALL); + } + } else { + if (disable) { + DEBUG_OFF(msg, MSG_SEND); + DEBUG_OFF(msg, MSG_SEND_ALL); + } else { + DEBUG_ON(msg, MSG_SEND); + if (all) + DEBUG_ON(msg, MSG_SEND_ALL); + } + } + } else if (strcmp(type_str, "zebra") == 0) { + if (disable) + DEBUG_OFF(zebra, ZEBRA); + else + DEBUG_ON(zebra, ZEBRA); + } + + main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug, + sizeof(ldp_debug)); + + return (CMD_SUCCESS); +} + +int +ldp_vty_show_debugging(struct vty *vty, struct vty_arg *args[]) +{ + vty_out(vty, "LDP debugging status:%s", VTY_NEWLINE); + + if (LDP_DEBUG(hello, HELLO_RECV)) + vty_out(vty, " LDP discovery debugging is on (inbound)%s", + VTY_NEWLINE); + if (LDP_DEBUG(hello, HELLO_SEND)) + vty_out(vty, " LDP discovery debugging is on (outbound)%s", + VTY_NEWLINE); + if (LDP_DEBUG(errors, ERRORS)) + vty_out(vty, " LDP errors debugging is on%s", VTY_NEWLINE); + if (LDP_DEBUG(event, EVENT)) + vty_out(vty, " LDP events debugging is on%s", VTY_NEWLINE); + if (LDP_DEBUG(msg, MSG_RECV_ALL)) + vty_out(vty, " LDP detailed messages debugging is on " + "(inbound)%s", VTY_NEWLINE); + else if (LDP_DEBUG(msg, MSG_RECV)) + vty_out(vty, " LDP messages debugging is on (inbound)%s", + VTY_NEWLINE); + if (LDP_DEBUG(msg, MSG_SEND_ALL)) + vty_out(vty, " LDP detailed messages debugging is on " + "(outbound)%s", VTY_NEWLINE); + else if (LDP_DEBUG(msg, MSG_SEND)) + vty_out(vty, " LDP messages debugging is on (outbound)%s", + VTY_NEWLINE); + if (LDP_DEBUG(zebra, ZEBRA)) + vty_out(vty, " LDP zebra debugging is on%s", VTY_NEWLINE); + vty_out (vty, "%s", VTY_NEWLINE); + + return (CMD_SUCCESS); +} + +int +ldp_debug_config_write(struct vty *vty) +{ + int write = 0; + + if (CONF_LDP_DEBUG(hello, HELLO_RECV)) { + vty_out(vty, "debug mpls ldp discovery hello recv%s", + VTY_NEWLINE); + write = 1; + } + + if (CONF_LDP_DEBUG(hello, HELLO_SEND)) { + vty_out(vty, "debug mpls ldp discovery hello sent%s", + VTY_NEWLINE); + write = 1; + } + + if (CONF_LDP_DEBUG(errors, ERRORS)) { + vty_out(vty, "debug mpls ldp errors%s", VTY_NEWLINE); + write = 1; + } + + if (CONF_LDP_DEBUG(event, EVENT)) { + vty_out(vty, "debug mpls ldp event%s", VTY_NEWLINE); + write = 1; + } + + if (CONF_LDP_DEBUG(msg, MSG_RECV_ALL)) { + vty_out(vty, "debug mpls ldp messages recv all%s", VTY_NEWLINE); + write = 1; + } else if (CONF_LDP_DEBUG(msg, MSG_RECV)) { + vty_out(vty, "debug mpls ldp messages recv%s", VTY_NEWLINE); + write = 1; + } + + if (CONF_LDP_DEBUG(msg, MSG_SEND_ALL)) { + vty_out(vty, "debug mpls ldp messages sent all%s", VTY_NEWLINE); + write = 1; + } else if (CONF_LDP_DEBUG(msg, MSG_SEND)) { + vty_out(vty, "debug mpls ldp messages sent%s", VTY_NEWLINE); + write = 1; + } + + if (CONF_LDP_DEBUG(zebra, ZEBRA)) { + vty_out(vty, "debug mpls ldp zebra%s", VTY_NEWLINE); + write = 1; + } + + return (write); +} diff --git a/ldpd/ldp_debug.h b/ldpd/ldp_debug.h new file mode 100644 index 000000000..aa0cd47e7 --- /dev/null +++ b/ldpd/ldp_debug.h @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _LDP_DEBUG_H_ +#define _LDP_DEBUG_H_ + +struct ldp_debug { + int hello; +#define LDP_DEBUG_HELLO_RECV 0x01 +#define LDP_DEBUG_HELLO_SEND 0x02 + + int errors; +#define LDP_DEBUG_ERRORS 0x01 + + int event; +#define LDP_DEBUG_EVENT 0x01 + + int msg; +#define LDP_DEBUG_MSG_RECV 0x01 +#define LDP_DEBUG_MSG_RECV_ALL 0x02 +#define LDP_DEBUG_MSG_SEND 0x04 +#define LDP_DEBUG_MSG_SEND_ALL 0x08 + + int zebra; +#define LDP_DEBUG_ZEBRA 0x01 +}; +extern struct ldp_debug conf_ldp_debug; +extern struct ldp_debug ldp_debug; + +#define CONF_DEBUG_ON(a, b) (conf_ldp_debug.a |= (LDP_DEBUG_ ## b)) +#define CONF_DEBUG_OFF(a, b) (conf_ldp_debug.a &= ~(LDP_DEBUG_ ## b)) + +#define TERM_DEBUG_ON(a, b) (ldp_debug.a |= (LDP_DEBUG_ ## b)) +#define TERM_DEBUG_OFF(a, b) (ldp_debug.a &= ~(LDP_DEBUG_ ## b)) + +#define DEBUG_ON(a, b) \ + do { \ + if (vty->node == CONFIG_NODE) { \ + CONF_DEBUG_ON(a, b); \ + TERM_DEBUG_ON(a, b); \ + } else \ + TERM_DEBUG_ON(a, b); \ + } while (0) +#define DEBUG_OFF(a, b) \ + do { \ + CONF_DEBUG_OFF(a, b); \ + TERM_DEBUG_OFF(a, b); \ + } while (0) + +#define LDP_DEBUG(a, b) (ldp_debug.a & LDP_DEBUG_ ## b) +#define CONF_LDP_DEBUG(a, b) (conf_ldp_debug.a & LDP_DEBUG_ ## b) + +#define debug_hello_recv(emsg, ...) \ +do { \ + if (LDP_DEBUG(hello, HELLO_RECV)) \ + log_debug("discovery[recv]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_hello_send(emsg, ...) \ +do { \ + if (LDP_DEBUG(hello, HELLO_SEND)) \ + log_debug("discovery[send]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_err(emsg, ...) \ +do { \ + if (LDP_DEBUG(errors, ERRORS)) \ + log_debug("error: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_evt(emsg, ...) \ +do { \ + if (LDP_DEBUG(event, EVENT)) \ + log_debug("event: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_msg_recv(emsg, ...) \ +do { \ + if (LDP_DEBUG(msg, MSG_RECV)) \ + log_debug("msg[in]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_msg_send(emsg, ...) \ +do { \ + if (LDP_DEBUG(msg, MSG_SEND)) \ + log_debug("msg[out]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_kalive_recv(emsg, ...) \ +do { \ + if (LDP_DEBUG(msg, MSG_RECV_ALL)) \ + log_debug("kalive[in]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_kalive_send(emsg, ...) \ +do { \ + if (LDP_DEBUG(msg, MSG_SEND_ALL)) \ + log_debug("kalive[out]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_zebra_in(emsg, ...) \ +do { \ + if (LDP_DEBUG(zebra, ZEBRA)) \ + log_debug("zebra[in]: " emsg, __VA_ARGS__); \ +} while (0) + +#define debug_zebra_out(emsg, ...) \ +do { \ + if (LDP_DEBUG(zebra, ZEBRA)) \ + log_debug("zebra[out]: " emsg, __VA_ARGS__); \ +} while (0) + +#endif /* _LDP_DEBUG_H_ */ diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h new file mode 100644 index 000000000..735554bad --- /dev/null +++ b/ldpd/ldp_vty.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _LDP_VTY_H_ +#define _LDP_VTY_H_ + +#include "vty.h" + +extern struct cmd_node ldp_node; +extern struct cmd_node ldp_ipv4_node; +extern struct cmd_node ldp_ipv6_node; +extern struct cmd_node ldp_ipv4_iface_node; +extern struct cmd_node ldp_ipv6_iface_node; +extern struct cmd_node ldp_l2vpn_node; +extern struct cmd_node ldp_pseudowire_node; +extern struct cmd_node ldp_debug_node; + +union ldpd_addr; +int ldp_get_address(const char *, int *, union ldpd_addr *); +int ldp_config_write(struct vty *); +int ldp_l2vpn_config_write(struct vty *); +int ldp_debug_config_write(struct vty *); +int ldp_vty_mpls_ldp (struct vty *, struct vty_arg *[]); +int ldp_vty_address_family (struct vty *, struct vty_arg *[]); +int ldp_vty_disc_holdtime(struct vty *, struct vty_arg *[]); +int ldp_vty_disc_interval(struct vty *, struct vty_arg *[]); +int ldp_vty_targeted_hello_accept(struct vty *, struct vty_arg *[]); +int ldp_vty_session_holdtime(struct vty *, struct vty_arg *[]); +int ldp_vty_interface(struct vty *, struct vty_arg *[]); +int ldp_vty_trans_addr(struct vty *, struct vty_arg *[]); +int ldp_vty_neighbor_targeted(struct vty *, struct vty_arg *[]); +int ldp_vty_explicit_null(struct vty *, struct vty_arg *[]); +int ldp_vty_ttl_security(struct vty *, struct vty_arg *[]); +int ldp_vty_router_id(struct vty *, struct vty_arg *[]); +int ldp_vty_ds_cisco_interop(struct vty *, struct vty_arg *[]); +int ldp_vty_trans_pref_ipv4(struct vty *, struct vty_arg *[]); +int ldp_vty_neighbor_password(struct vty *, struct vty_arg *[]); +int ldp_vty_neighbor_ttl_security(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_bridge(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_mtu(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pwtype(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_interface(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pseudowire(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pw_cword(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pw_nbr_addr(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pw_nbr_id(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pw_pwid(struct vty *, struct vty_arg *[]); +int ldp_vty_l2vpn_pw_pwstatus(struct vty *, struct vty_arg *[]); +int ldp_vty_show_binding(struct vty *, struct vty_arg *[]); +int ldp_vty_show_discovery(struct vty *, struct vty_arg *[]); +int ldp_vty_show_interface(struct vty *, struct vty_arg *[]); +int ldp_vty_show_neighbor(struct vty *, struct vty_arg *[]); +int ldp_vty_show_atom_binding(struct vty *, struct vty_arg *[]); +int ldp_vty_show_atom_vc(struct vty *, struct vty_arg *[]); +int ldp_vty_clear_nbr(struct vty *, struct vty_arg *[]); +int ldp_vty_debug(struct vty *, struct vty_arg *[]); +int ldp_vty_show_debugging(struct vty *, struct vty_arg *[]); + +void ldp_vty_init(void); +void ldp_vty_if_init(void); + +#endif /* _LDP_VTY_H_ */ diff --git a/ldpd/ldp_vty.xml b/ldpd/ldp_vty.xml new file mode 100644 index 000000000..8742f9c1b --- /dev/null +++ b/ldpd/ldp_vty.xml @@ -0,0 +1,379 @@ +<?xml version="1.0"?> +<file init="ldp_vty_init" cmdprefix="ldp" header="ldp_vty.h"> + <!-- address-family --> + <options name="address-family"> + <option name="ipv4" help="IPv4 Address Family"/> + <option name="ipv6" help="IPv6 Address Family"/> + </options> + + <!-- ipv4/ipv6 address --> + <options name="addr"> + <option input="ipv4" help="IPv4 address"/> + <option input="ipv6" help="IPv6 address"/> + </options> + + <!-- pseudowire control-word options --> + <options name="cword"> + <option name="exclude" help="Exclude control-word in pseudowire packets"/> + <option name="include" help="Include control-word in pseudowire packets"/> + </options> + + <!-- pseudowire types --> + <options name="pwtype"> + <option name="ethernet" help="Ethernet (type 5)"/> + <option name="ethernet-tagged" help="Ethernet-tagged (type 4)"/> + </options> + + <!-- packet direction --> + <options name="dir"> + <option name="recv" help="Received messages"/> + <option name="sent" help="Sent messages"/> + </options> + + <!-- shared subtrees --> + <subtree name="discovery_link"> + <option name="discovery" help="Configure discovery parameters"> + <option name="hello" arg="hello_type" help="LDP Link Hellos"> + <option name="holdtime" help="Hello holdtime"> + <option input="disc_time" arg="seconds" help="Time (seconds) - 65535 implies infinite" function="ldp_vty_disc_holdtime"/> + </option> + <option name="interval" help="Hello interval"> + <option input="disc_time" arg="seconds" help="Time (seconds)" function="ldp_vty_disc_interval"/> + </option> + </option> + </option> + </subtree> + + <subtree name="discovery_targeted"> + <option name="discovery" help="Configure discovery parameters"> + <option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos"> + <option name="holdtime" help="Targeted hello holdtime"> + <option input="disc_time" arg="seconds" help="Time (seconds) - 65535 implies infinite" function="ldp_vty_disc_holdtime"/> + </option> + <option name="interval" help="Targeted hello interval"> + <option input="disc_time" arg="seconds" help="Time (seconds)" function="ldp_vty_disc_interval"/> + </option> + </option> + </option> + </subtree> + + <subtree name="session_holdtime"> + <option name="session" help="Configure session parameters"> + <option name="holdtime" help="Configure session holdtime"> + <option input="session_time" arg="seconds" help="Time (seconds)" function="ldp_vty_session_holdtime"/> + </option> + </option> + </subtree> + + <subtree name="af_common"> + <include subtree="discovery_link"/> + <include subtree="discovery_targeted"/> + <option name="discovery" help="Configure discovery parameters"> + <option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos"> + <option name="accept" help="Accept and respond to targeted hellos" function="ldp_vty_targeted_hello_accept"/> + </option> + </option> + <option name="label" help="Configure label control and policies"> + <option name="local" help="Configure local label control and policies"> + <option name="advertise" help="Configure outbound label advertisement control"> + <option name="explicit-null" help="Configure explicit-null advertisement" function="ldp_vty_explicit_null"/> + </option> + </option> + </option> + <option name="ttl-security" help="LDP ttl security check"> + <option name="disable" help="Disable ttl security" function="ldp_vty_ttl_security"/> + </option> + <include subtree="session_holdtime"/> + <option name="interface" help="Enable LDP on an interface and enter interface submode"> + <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_interface"/> + </option> + </subtree> + + <!-- global --> + <subtree name="__global"> + <option name="mpls" help="Global MPLS configuration subcommands"> + <option name="ldp" help="Label Distribution Protocol" function="ldp_vty_mpls_ldp"/> + </option> + <option name="l2vpn" help="Configure l2vpn commands"> + <option input="word" arg="name" help="L2VPN name"> + <option name="type" help="L2VPN type"> + <option name="vpls" help="Virtual Private LAN Service" function="ldp_vty_l2vpn"/> + </option> + </option> + </option> + </subtree> + <tree name="global"> + <include subtree="__global"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__global"/> + </option> + </tree> + + <!-- ldp node --> + <subtree name="__ldp_node"> + <option name="address-family" help="Configure Address Family and its parameters"> + <option name="ipv4" arg="address-family" help="IPv4" function="ldp_vty_address_family"/> + <option name="ipv6" arg="address-family" help="IPv6" function="ldp_vty_address_family"/> + </option> + <include subtree="discovery_link"/> + <include subtree="discovery_targeted"/> + <option name="dual-stack" help="Configure dual stack parameters"> + <option name="transport-connection" help="Configure TCP transport parameters"> + <option name="prefer" help="Configure prefered address family for TCP transport connection with neighbor"> + <option name="ipv4" help="IPv4" function="ldp_vty_trans_pref_ipv4"/> + </option> + </option> + <option name="cisco-interop" help="Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV" function="ldp_vty_ds_cisco_interop"/> + </option> + <option name="neighbor" help="Configure neighbor parameters"> + <option input="ipv4" arg="lsr_id" help="LDP Id of neighbor"> + <option name="password" help="Configure password for MD5 authentication"> + <option input="word" arg="password" help="The password" function="ldp_vty_neighbor_password"/> + </option> + <include subtree="session_holdtime"/> + <option name="ttl-security" help="LDP ttl security check"> + <option name="disable" help="Disable ttl security" function="ldp_vty_neighbor_ttl_security"/> + <option name="hops" help="IP hops"> + <option input="hops" arg="hops" help="maximum number of hops" function="ldp_vty_neighbor_ttl_security"/> + </option> + </option> + </option> + </option> + <option name="router-id" help="Configure router Id"> + <option input="ipv4" arg="addr" help="LSR Id (in form of an IPv4 address)" function="ldp_vty_router_id"/> + </option> + </subtree> + <tree name="ldp_node"> + <include subtree="__ldp_node"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_node"/> + </option> + </tree> + + <!-- address-family ipv4 --> + <subtree name="__ldp_ipv4_node"> + <include subtree="af_common"/> + <option name="discovery" help="Configure discovery parameters"> + <option name="transport-address" help="Specify transport address for TCP connection"> + <option input="ipv4" arg="addr" help="IP address to be used as transport address" function="ldp_vty_trans_addr"/> + </option> + </option> + <option name="neighbor" help="Configure neighbor parameters"> + <option input="ipv4" arg="addr" help="IP address of neighbor"> + <option name="targeted" help="Establish targeted session" function="ldp_vty_neighbor_targeted"/> + </option> + </option> + </subtree> + <tree name="ldp_ipv4_node"> + <include subtree="__ldp_ipv4_node"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_ipv4_node"/> + </option> + </tree> + + <!-- address-family ipv6 --> + <subtree name="__ldp_ipv6_node"> + <include subtree="af_common"/> + <option name="discovery" help="Configure discovery parameters"> + <option name="transport-address" help="Specify transport address for TCP connection"> + <option input="ipv6" arg="addr" help="IPv6 address to be used as transport address" function="ldp_vty_trans_addr"/> + </option> + </option> + <option name="neighbor" help="Configure neighbor parameters"> + <option input="ipv6" arg="addr" help="IPv6 address of neighbor"> + <option name="targeted" help="Establish targeted session" function="ldp_vty_neighbor_targeted"/> + </option> + </option> + </subtree> + <tree name="ldp_ipv6_node"> + <include subtree="__ldp_ipv6_node"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_ipv6_node"/> + </option> + </tree> + + <!-- ldp ipv4 interface node --> + <subtree name="__ldp_ipv4_iface_node"> + <include subtree="discovery_link"/> + </subtree> + <tree name="ldp_ipv4_iface_node"> + <include subtree="__ldp_ipv4_iface_node"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_ipv4_iface_node"/> + </option> + </tree> + + <!-- ldp ipv6 interface node --> + <subtree name="__ldp_ipv6_iface_node"> + <include subtree="discovery_link"/> + </subtree> + <tree name="ldp_ipv6_iface_node"> + <include subtree="__ldp_ipv6_iface_node"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_ipv6_iface_node"/> + </option> + </tree> + + <!-- l2vpn --> + <subtree name="__ldp_l2vpn"> + <option name="bridge" help="Bridge interface"> + <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_bridge"/> + </option> + <option name="mtu" help="set Maximum Transmission Unit"> + <option input="mtu" arg="mtu" help="Maximum Transmission Unit value" function="ldp_vty_l2vpn_mtu"/> + </option> + <option name="member" help="L2VPN member configuration"> + <option name="interface" help="Local interface"> + <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_interface"/> + </option> + <option name="pseudowire" help="Pseudowire interface"> + <option input="ifname" arg="ifname" help="Interface's name" function="ldp_vty_l2vpn_pseudowire"/> + </option> + </option> + <option name="vc" help="Virtual Circuit options"> + <option name="type" help="Virtual Circuit type to use"> + <select options="pwtype" arg="type" function="ldp_vty_l2vpn_pwtype"/> + </option> + </option> + </subtree> + <tree name="ldp_l2vpn"> + <include subtree="__ldp_l2vpn"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_l2vpn"/> + </option> + </tree> + + <!-- l2vpn pseudowire --> + <subtree name="__ldp_pseudowire"> + <option name="control-word" help="Control-word options"> + <select options="cword" arg="preference" function="ldp_vty_l2vpn_pw_cword"/> + </option> + <option name="neighbor" help="Remote endpoint configuration"> + <option name="address" help="Specify the IPv4 or IPv6 address of the remote endpoint"> + <select options="addr" arg="addr" function="ldp_vty_l2vpn_pw_nbr_addr"/> + </option> + <option name="lsr-id" help="Specify the LSR-ID of the remote endpoint"> + <option input="ipv4" arg="lsr-id" help="IPv4 address" function="ldp_vty_l2vpn_pw_nbr_id"/> + </option> + </option> + <option name="pw-id" help="Set the Virtual Circuit ID"> + <option input="pwid" arg="pwid" help="Virtual Circuit ID value" function="ldp_vty_l2vpn_pw_pwid"/> + </option> + <option name="pw-status" help="Configure PW status"> + <option name="disable" help="Disable PW status" function="ldp_vty_l2vpn_pw_pwstatus"/> + </option> + </subtree> + <tree name="ldp_pseudowire"> + <include subtree="__ldp_pseudowire"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_pseudowire"/> + </option> + </tree> + + <!-- exec mode commands --> + <subtree name="ldp_show_af"> + <option name="binding" help="Label Information Base (LIB) information" function="ldp_vty_show_binding"/> + <option name="discovery" help="Discovery Hello Information" function="ldp_vty_show_discovery"/> + <option name="interface" help="interface information" function="ldp_vty_show_interface"/> + </subtree> + <tree name="ldp_exec"> + <option name="show" help="Show running system information"> + <option name="mpls" help="MPLS information"> + <option name="ldp" help="Label Distribution Protocol"> + <option name="neighbor" help="Neighbor information" function="ldp_vty_show_neighbor"/> + <include subtree="ldp_show_af"/> + <select options="address-family" arg="address-family"> + <include subtree="ldp_show_af"/> + </select> + </option> + </option> + <option name="l2vpn" help="Show information about Layer2 VPN"> + <option name="atom" help="Show Any Transport over MPLS information"> + <option name="binding" help="Show AToM label binding information" function="ldp_vty_show_atom_binding"/> + <option name="vc" help="Show AToM virtual circuit information" function="ldp_vty_show_atom_vc"/> + </option> + </option> + <option name="debugging" help="Debugging functions"> + <option name="mpls" help="MPLS information"> + <option name="ldp" help="Label Distribution Protocol" function="ldp_vty_show_debugging"/> + </option> + </option> + </option> + <option name="clear" help="Reset functions"> + <option name="mpls" help="Reset MPLS statistical information"> + <option name="ldp" help="Clear LDP state"> + <option name="neighbor" help="Clear LDP neighbor sessions" function="ldp_vty_clear_nbr"> + <select options="addr" arg="addr" function="ldp_vty_clear_nbr"/> + </option> + </option> + </option> + </option> + </tree> + + <!-- debug commands --> + <subtree name="__ldp_debug"> + <option name="debug" help="Debugging functions"> + <option name="mpls" help="MPLS information"> + <option name="ldp" help="Label Distribution Protocol"> + <option name="discovery" arg="type" help="Discovery messages"> + <option name="hello" help="Discovery hello message"> + <select options="dir" arg="dir" function="ldp_vty_debug"/> + </option> + </option> + <option name="errors" arg="type" help="Errors" function="ldp_vty_debug"/> + <option name="event" arg="type" help="LDP event information" function="ldp_vty_debug"/> + <option name="messages" arg="type" help="Messages"> + <option name="recv" arg="dir" help="Received messages, excluding periodic Keep Alives" function="ldp_vty_debug"> + <option name="all" arg="all" help="Received messages, including periodic Keep Alives" function="ldp_vty_debug"/> + </option> + <option name="sent" arg="dir" help="Sent messages, excluding periodic Keep Alives" function="ldp_vty_debug"> + <option name="all" arg="all" help="Sent messages, including periodic Keep Alives" function="ldp_vty_debug"/> + </option> + </option> + <option name="zebra" arg="type" help="LDP zebra information" function="ldp_vty_debug"/> + </option> + </option> + </option> + </subtree> + <tree name="ldp_debug"> + <include subtree="__ldp_debug"/> + <option name="no" arg="no" help="Negate a command or set its defaults"> + <include subtree="__ldp_debug"/> + </option> + </tree> + + <!-- nodes --> + <node name="CONFIG"> + <include tree="global"/> + <include tree="ldp_debug"/> + </node> + <node install="1" install_default="1" config_write="ldp_config_write" name="LDP"> + <include tree="ldp_node"/> + </node> + <node install="1" install_default="1" config_write="NULL" name="LDP_IPV4"> + <include tree="ldp_ipv4_node"/> + </node> + <node install="1" install_default="1" config_write="NULL" name="LDP_IPV6"> + <include tree="ldp_ipv6_node"/> + </node> + <node install="1" install_default="1" config_write="NULL" name="LDP_IPV4_IFACE"> + <include tree="ldp_ipv4_iface_node"/> + </node> + <node install="1" install_default="1" config_write="NULL" name="LDP_IPV6_IFACE"> + <include tree="ldp_ipv6_iface_node"/> + </node> + <node install="1" install_default="1" config_write="ldp_l2vpn_config_write" name="LDP_L2VPN"> + <include tree="ldp_l2vpn"/> + </node> + <node install="1" install_default="1" config_write="NULL" name="LDP_PSEUDOWIRE"> + <include tree="ldp_pseudowire"/> + </node> + <node install="1" config_write="ldp_debug_config_write" name="LDP_DEBUG"/> + <node name="ENABLE"> + <include tree="ldp_exec"/> + <include tree="ldp_debug"/> + </node> + <node name="VIEW"> + <include tree="ldp_exec"/> + </node> +</file> diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c new file mode 100644 index 000000000..716083572 --- /dev/null +++ b/ldpd/ldp_vty_cmds.c @@ -0,0 +1,1738 @@ +/* Auto-generated from ldp_vty.xml. */ +/* Do not edit! */ + +#include <zebra.h> + +#include "command.h" +#include "vty.h" +#include "ldp_vty.h" + +DEFUN (ldp_mpls_ldp, + ldp_mpls_ldp_cmd, + "mpls ldp", + "Global MPLS configuration subcommands\n" + "Label Distribution Protocol\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_mpls_ldp (vty, args); +} + +DEFUN (ldp_l2vpn_word_type_vpls, + ldp_l2vpn_word_type_vpls_cmd, + "l2vpn WORD type vpls", + "Configure l2vpn commands\n" + "L2VPN name\n" + "L2VPN type\n" + "Virtual Private LAN Service\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "name", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn (vty, args); +} + +DEFUN (ldp_no_mpls_ldp, + ldp_no_mpls_ldp_cmd, + "no mpls ldp", + "Negate a command or set its defaults\n" + "Global MPLS configuration subcommands\n" + "Label Distribution Protocol\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + NULL + }; + return ldp_vty_mpls_ldp (vty, args); +} + +DEFUN (ldp_no_l2vpn_word_type_vpls, + ldp_no_l2vpn_word_type_vpls_cmd, + "no l2vpn WORD type vpls", + "Negate a command or set its defaults\n" + "Configure l2vpn commands\n" + "L2VPN name\n" + "L2VPN type\n" + "Virtual Private LAN Service\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "name", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn (vty, args); +} + +DEFUN (ldp_address_family_ipv4, + ldp_address_family_ipv4_cmd, + "address-family ipv4", + "Configure Address Family and its parameters\n" + "IPv4\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "address-family", .value = "ipv4" }, + NULL + }; + return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_address_family_ipv6, + ldp_address_family_ipv6_cmd, + "address-family ipv6", + "Configure Address Family and its parameters\n" + "IPv6\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "address-family", .value = "ipv6" }, + NULL + }; + return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_discovery_hello_holdtime_disc_time, + ldp_discovery_hello_holdtime_disc_time_cmd, + "discovery hello holdtime <1-65535>", + "Configure discovery parameters\n" + "LDP Link Hellos\n" + "Hello holdtime\n" + "Time (seconds) - 65535 implies infinite\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "hello_type", .value = "hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_discovery_hello_interval_disc_time, + ldp_discovery_hello_interval_disc_time_cmd, + "discovery hello interval <1-65535>", + "Configure discovery parameters\n" + "LDP Link Hellos\n" + "Hello interval\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "hello_type", .value = "hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_discovery_targeted_hello_holdtime_disc_time, + ldp_discovery_targeted_hello_holdtime_disc_time_cmd, + "discovery targeted-hello holdtime <1-65535>", + "Configure discovery parameters\n" + "LDP Targeted Hellos\n" + "Targeted hello holdtime\n" + "Time (seconds) - 65535 implies infinite\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_discovery_targeted_hello_interval_disc_time, + ldp_discovery_targeted_hello_interval_disc_time_cmd, + "discovery targeted-hello interval <1-65535>", + "Configure discovery parameters\n" + "LDP Targeted Hellos\n" + "Targeted hello interval\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_dual_stack_transport_connection_prefer_ipv4, + ldp_dual_stack_transport_connection_prefer_ipv4_cmd, + "dual-stack transport-connection prefer ipv4", + "Configure dual stack parameters\n" + "Configure TCP transport parameters\n" + "Configure prefered address family for TCP transport connection with neighbor\n" + "IPv4\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_trans_pref_ipv4 (vty, args); +} + +DEFUN (ldp_dual_stack_cisco_interop, + ldp_dual_stack_cisco_interop_cmd, + "dual-stack cisco-interop", + "Configure dual stack parameters\n" + "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_ds_cisco_interop (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_password_word, + ldp_neighbor_ipv4_password_word_cmd, + "neighbor A.B.C.D password WORD", + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "Configure password for MD5 authentication\n" + "The password\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + &(struct vty_arg) { .name = "password", .value = argv[1] }, + NULL + }; + return ldp_vty_neighbor_password (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_session_holdtime_session_time, + ldp_neighbor_ipv4_session_holdtime_session_time_cmd, + "neighbor A.B.C.D session holdtime <15-65535>", + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "Configure session parameters\n" + "Configure session holdtime\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + &(struct vty_arg) { .name = "seconds", .value = argv[1] }, + NULL + }; + return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_ttl_security_disable, + ldp_neighbor_ipv4_ttl_security_disable_cmd, + "neighbor A.B.C.D ttl-security disable", + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "LDP ttl security check\n" + "Disable ttl security\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + NULL + }; + return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_ttl_security_hops_hops, + ldp_neighbor_ipv4_ttl_security_hops_hops_cmd, + "neighbor A.B.C.D ttl-security hops <1-254>", + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "LDP ttl security check\n" + "IP hops\n" + "maximum number of hops\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + &(struct vty_arg) { .name = "hops", .value = argv[1] }, + NULL + }; + return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_router_id_ipv4, + ldp_router_id_ipv4_cmd, + "router-id A.B.C.D", + "Configure router Id\n" + "LSR Id (in form of an IPv4 address)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_router_id (vty, args); +} + +DEFUN (ldp_no_address_family_ipv4, + ldp_no_address_family_ipv4_cmd, + "no address-family ipv4", + "Negate a command or set its defaults\n" + "Configure Address Family and its parameters\n" + "IPv4\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "address-family", .value = "ipv4" }, + NULL + }; + return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_no_address_family_ipv6, + ldp_no_address_family_ipv6_cmd, + "no address-family ipv6", + "Negate a command or set its defaults\n" + "Configure Address Family and its parameters\n" + "IPv6\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "address-family", .value = "ipv6" }, + NULL + }; + return ldp_vty_address_family (vty, args); +} + +DEFUN (ldp_no_discovery_hello_holdtime_disc_time, + ldp_no_discovery_hello_holdtime_disc_time_cmd, + "no discovery hello holdtime <1-65535>", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "LDP Link Hellos\n" + "Hello holdtime\n" + "Time (seconds) - 65535 implies infinite\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "hello_type", .value = "hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_no_discovery_hello_interval_disc_time, + ldp_no_discovery_hello_interval_disc_time_cmd, + "no discovery hello interval <1-65535>", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "LDP Link Hellos\n" + "Hello interval\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "hello_type", .value = "hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_no_discovery_targeted_hello_holdtime_disc_time, + ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd, + "no discovery targeted-hello holdtime <1-65535>", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "LDP Targeted Hellos\n" + "Targeted hello holdtime\n" + "Time (seconds) - 65535 implies infinite\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_holdtime (vty, args); +} + +DEFUN (ldp_no_discovery_targeted_hello_interval_disc_time, + ldp_no_discovery_targeted_hello_interval_disc_time_cmd, + "no discovery targeted-hello interval <1-65535>", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "LDP Targeted Hellos\n" + "Targeted hello interval\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_disc_interval (vty, args); +} + +DEFUN (ldp_no_dual_stack_transport_connection_prefer_ipv4, + ldp_no_dual_stack_transport_connection_prefer_ipv4_cmd, + "no dual-stack transport-connection prefer ipv4", + "Negate a command or set its defaults\n" + "Configure dual stack parameters\n" + "Configure TCP transport parameters\n" + "Configure prefered address family for TCP transport connection with neighbor\n" + "IPv4\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + NULL + }; + return ldp_vty_trans_pref_ipv4 (vty, args); +} + +DEFUN (ldp_no_dual_stack_cisco_interop, + ldp_no_dual_stack_cisco_interop_cmd, + "no dual-stack cisco-interop", + "Negate a command or set its defaults\n" + "Configure dual stack parameters\n" + "Use Cisco non-compliant format to send and interpret the Dual-Stack capability TLV\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + NULL + }; + return ldp_vty_ds_cisco_interop (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_password_word, + ldp_no_neighbor_ipv4_password_word_cmd, + "no neighbor A.B.C.D password WORD", + "Negate a command or set its defaults\n" + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "Configure password for MD5 authentication\n" + "The password\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + &(struct vty_arg) { .name = "password", .value = argv[1] }, + NULL + }; + return ldp_vty_neighbor_password (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_session_holdtime_session_time, + ldp_no_neighbor_ipv4_session_holdtime_session_time_cmd, + "no neighbor A.B.C.D session holdtime <15-65535>", + "Negate a command or set its defaults\n" + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "Configure session parameters\n" + "Configure session holdtime\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + &(struct vty_arg) { .name = "seconds", .value = argv[1] }, + NULL + }; + return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_ttl_security_disable, + ldp_no_neighbor_ipv4_ttl_security_disable_cmd, + "no neighbor A.B.C.D ttl-security disable", + "Negate a command or set its defaults\n" + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "LDP ttl security check\n" + "Disable ttl security\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + NULL + }; + return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_ttl_security_hops_hops, + ldp_no_neighbor_ipv4_ttl_security_hops_hops_cmd, + "no neighbor A.B.C.D ttl-security hops <1-254>", + "Negate a command or set its defaults\n" + "Configure neighbor parameters\n" + "LDP Id of neighbor\n" + "LDP ttl security check\n" + "IP hops\n" + "maximum number of hops\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "lsr_id", .value = argv[0] }, + &(struct vty_arg) { .name = "hops", .value = argv[1] }, + NULL + }; + return ldp_vty_neighbor_ttl_security (vty, args); +} + +DEFUN (ldp_no_router_id_ipv4, + ldp_no_router_id_ipv4_cmd, + "no router-id A.B.C.D", + "Negate a command or set its defaults\n" + "Configure router Id\n" + "LSR Id (in form of an IPv4 address)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_router_id (vty, args); +} + +DEFUN (ldp_discovery_targeted_hello_accept, + ldp_discovery_targeted_hello_accept_cmd, + "discovery targeted-hello accept", + "Configure discovery parameters\n" + "LDP Targeted Hellos\n" + "Accept and respond to targeted hellos\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, + NULL + }; + return ldp_vty_targeted_hello_accept (vty, args); +} + +DEFUN (ldp_label_local_advertise_explicit_null, + ldp_label_local_advertise_explicit_null_cmd, + "label local advertise explicit-null", + "Configure label control and policies\n" + "Configure local label control and policies\n" + "Configure outbound label advertisement control\n" + "Configure explicit-null advertisement\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_explicit_null (vty, args); +} + +DEFUN (ldp_ttl_security_disable, + ldp_ttl_security_disable_cmd, + "ttl-security disable", + "LDP ttl security check\n" + "Disable ttl security\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_ttl_security (vty, args); +} + +DEFUN (ldp_session_holdtime_session_time, + ldp_session_holdtime_session_time_cmd, + "session holdtime <15-65535>", + "Configure session parameters\n" + "Configure session holdtime\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_interface_ifname, + ldp_interface_ifname_cmd, + "interface IFNAME", + "Enable LDP on an interface and enter interface submode\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_interface (vty, args); +} + +DEFUN (ldp_discovery_transport_address_ipv4, + ldp_discovery_transport_address_ipv4_cmd, + "discovery transport-address A.B.C.D", + "Configure discovery parameters\n" + "Specify transport address for TCP connection\n" + "IP address to be used as transport address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_neighbor_ipv4_targeted, + ldp_neighbor_ipv4_targeted_cmd, + "neighbor A.B.C.D targeted", + "Configure neighbor parameters\n" + "IP address of neighbor\n" + "Establish targeted session\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_no_discovery_targeted_hello_accept, + ldp_no_discovery_targeted_hello_accept_cmd, + "no discovery targeted-hello accept", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "LDP Targeted Hellos\n" + "Accept and respond to targeted hellos\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "hello_type", .value = "targeted-hello" }, + NULL + }; + return ldp_vty_targeted_hello_accept (vty, args); +} + +DEFUN (ldp_no_label_local_advertise_explicit_null, + ldp_no_label_local_advertise_explicit_null_cmd, + "no label local advertise explicit-null", + "Negate a command or set its defaults\n" + "Configure label control and policies\n" + "Configure local label control and policies\n" + "Configure outbound label advertisement control\n" + "Configure explicit-null advertisement\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + NULL + }; + return ldp_vty_explicit_null (vty, args); +} + +DEFUN (ldp_no_ttl_security_disable, + ldp_no_ttl_security_disable_cmd, + "no ttl-security disable", + "Negate a command or set its defaults\n" + "LDP ttl security check\n" + "Disable ttl security\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + NULL + }; + return ldp_vty_ttl_security (vty, args); +} + +DEFUN (ldp_no_session_holdtime_session_time, + ldp_no_session_holdtime_session_time_cmd, + "no session holdtime <15-65535>", + "Negate a command or set its defaults\n" + "Configure session parameters\n" + "Configure session holdtime\n" + "Time (seconds)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "seconds", .value = argv[0] }, + NULL + }; + return ldp_vty_session_holdtime (vty, args); +} + +DEFUN (ldp_no_interface_ifname, + ldp_no_interface_ifname_cmd, + "no interface IFNAME", + "Negate a command or set its defaults\n" + "Enable LDP on an interface and enter interface submode\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_interface (vty, args); +} + +DEFUN (ldp_no_discovery_transport_address_ipv4, + ldp_no_discovery_transport_address_ipv4_cmd, + "no discovery transport-address A.B.C.D", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "Specify transport address for TCP connection\n" + "IP address to be used as transport address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv4_targeted, + ldp_no_neighbor_ipv4_targeted_cmd, + "no neighbor A.B.C.D targeted", + "Negate a command or set its defaults\n" + "Configure neighbor parameters\n" + "IP address of neighbor\n" + "Establish targeted session\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_discovery_transport_address_ipv6, + ldp_discovery_transport_address_ipv6_cmd, + "discovery transport-address X:X::X:X", + "Configure discovery parameters\n" + "Specify transport address for TCP connection\n" + "IPv6 address to be used as transport address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_neighbor_ipv6_targeted, + ldp_neighbor_ipv6_targeted_cmd, + "neighbor X:X::X:X targeted", + "Configure neighbor parameters\n" + "IPv6 address of neighbor\n" + "Establish targeted session\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_no_discovery_transport_address_ipv6, + ldp_no_discovery_transport_address_ipv6_cmd, + "no discovery transport-address X:X::X:X", + "Negate a command or set its defaults\n" + "Configure discovery parameters\n" + "Specify transport address for TCP connection\n" + "IPv6 address to be used as transport address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_trans_addr (vty, args); +} + +DEFUN (ldp_no_neighbor_ipv6_targeted, + ldp_no_neighbor_ipv6_targeted_cmd, + "no neighbor X:X::X:X targeted", + "Negate a command or set its defaults\n" + "Configure neighbor parameters\n" + "IPv6 address of neighbor\n" + "Establish targeted session\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_neighbor_targeted (vty, args); +} + +DEFUN (ldp_bridge_ifname, + ldp_bridge_ifname_cmd, + "bridge IFNAME", + "Bridge interface\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_bridge (vty, args); +} + +DEFUN (ldp_mtu_mtu, + ldp_mtu_mtu_cmd, + "mtu <1500-9180>", + "set Maximum Transmission Unit\n" + "Maximum Transmission Unit value\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "mtu", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_mtu (vty, args); +} + +DEFUN (ldp_member_interface_ifname, + ldp_member_interface_ifname_cmd, + "member interface IFNAME", + "L2VPN member configuration\n" + "Local interface\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_interface (vty, args); +} + +DEFUN (ldp_member_pseudowire_ifname, + ldp_member_pseudowire_ifname_cmd, + "member pseudowire IFNAME", + "L2VPN member configuration\n" + "Pseudowire interface\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pseudowire (vty, args); +} + +DEFUN (ldp_vc_type_pwtype, + ldp_vc_type_pwtype_cmd, + "vc type (ethernet|ethernet-tagged)", + "Virtual Circuit options\n" + "Virtual Circuit type to use\n" + "Ethernet (type 5)\n" + "Ethernet-tagged (type 4)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pwtype (vty, args); +} + +DEFUN (ldp_no_bridge_ifname, + ldp_no_bridge_ifname_cmd, + "no bridge IFNAME", + "Negate a command or set its defaults\n" + "Bridge interface\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_bridge (vty, args); +} + +DEFUN (ldp_no_mtu_mtu, + ldp_no_mtu_mtu_cmd, + "no mtu <1500-9180>", + "Negate a command or set its defaults\n" + "set Maximum Transmission Unit\n" + "Maximum Transmission Unit value\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "mtu", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_mtu (vty, args); +} + +DEFUN (ldp_no_member_interface_ifname, + ldp_no_member_interface_ifname_cmd, + "no member interface IFNAME", + "Negate a command or set its defaults\n" + "L2VPN member configuration\n" + "Local interface\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_interface (vty, args); +} + +DEFUN (ldp_no_member_pseudowire_ifname, + ldp_no_member_pseudowire_ifname_cmd, + "no member pseudowire IFNAME", + "Negate a command or set its defaults\n" + "L2VPN member configuration\n" + "Pseudowire interface\n" + "Interface's name\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "ifname", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pseudowire (vty, args); +} + +DEFUN (ldp_no_vc_type_pwtype, + ldp_no_vc_type_pwtype_cmd, + "no vc type (ethernet|ethernet-tagged)", + "Negate a command or set its defaults\n" + "Virtual Circuit options\n" + "Virtual Circuit type to use\n" + "Ethernet (type 5)\n" + "Ethernet-tagged (type 4)\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pwtype (vty, args); +} + +DEFUN (ldp_control_word_cword, + ldp_control_word_cword_cmd, + "control-word (exclude|include)", + "Control-word options\n" + "Exclude control-word in pseudowire packets\n" + "Include control-word in pseudowire packets\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "preference", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_cword (vty, args); +} + +DEFUN (ldp_neighbor_address_addr, + ldp_neighbor_address_addr_cmd, + "neighbor address (A.B.C.D|X:X::X:X)", + "Remote endpoint configuration\n" + "Specify the IPv4 or IPv6 address of the remote endpoint\n" + "IPv4 address\n" + "IPv6 address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_nbr_addr (vty, args); +} + +DEFUN (ldp_neighbor_lsr_id_ipv4, + ldp_neighbor_lsr_id_ipv4_cmd, + "neighbor lsr-id A.B.C.D", + "Remote endpoint configuration\n" + "Specify the LSR-ID of the remote endpoint\n" + "IPv4 address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "lsr-id", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_nbr_id (vty, args); +} + +DEFUN (ldp_pw_id_pwid, + ldp_pw_id_pwid_cmd, + "pw-id <1-4294967295>", + "Set the Virtual Circuit ID\n" + "Virtual Circuit ID value\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "pwid", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_pwid (vty, args); +} + +DEFUN (ldp_pw_status_disable, + ldp_pw_status_disable_cmd, + "pw-status disable", + "Configure PW status\n" + "Disable PW status\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_l2vpn_pw_pwstatus (vty, args); +} + +DEFUN (ldp_no_control_word_cword, + ldp_no_control_word_cword_cmd, + "no control-word (exclude|include)", + "Negate a command or set its defaults\n" + "Control-word options\n" + "Exclude control-word in pseudowire packets\n" + "Include control-word in pseudowire packets\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "preference", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_cword (vty, args); +} + +DEFUN (ldp_no_neighbor_address_addr, + ldp_no_neighbor_address_addr_cmd, + "no neighbor address (A.B.C.D|X:X::X:X)", + "Negate a command or set its defaults\n" + "Remote endpoint configuration\n" + "Specify the IPv4 or IPv6 address of the remote endpoint\n" + "IPv4 address\n" + "IPv6 address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_nbr_addr (vty, args); +} + +DEFUN (ldp_no_neighbor_lsr_id_ipv4, + ldp_no_neighbor_lsr_id_ipv4_cmd, + "no neighbor lsr-id A.B.C.D", + "Negate a command or set its defaults\n" + "Remote endpoint configuration\n" + "Specify the LSR-ID of the remote endpoint\n" + "IPv4 address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "lsr-id", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_nbr_id (vty, args); +} + +DEFUN (ldp_no_pw_id_pwid, + ldp_no_pw_id_pwid_cmd, + "no pw-id <1-4294967295>", + "Negate a command or set its defaults\n" + "Set the Virtual Circuit ID\n" + "Virtual Circuit ID value\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "pwid", .value = argv[0] }, + NULL + }; + return ldp_vty_l2vpn_pw_pwid (vty, args); +} + +DEFUN (ldp_no_pw_status_disable, + ldp_no_pw_status_disable_cmd, + "no pw-status disable", + "Negate a command or set its defaults\n" + "Configure PW status\n" + "Disable PW status\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + NULL + }; + return ldp_vty_l2vpn_pw_pwstatus (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_neighbor, + ldp_show_mpls_ldp_neighbor_cmd, + "show mpls ldp neighbor", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Neighbor information\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_neighbor (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_binding, + ldp_show_mpls_ldp_binding_cmd, + "show mpls ldp binding", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Label Information Base (LIB) information\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_binding (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_discovery, + ldp_show_mpls_ldp_discovery_cmd, + "show mpls ldp discovery", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Discovery Hello Information\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_discovery (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_interface, + ldp_show_mpls_ldp_interface_cmd, + "show mpls ldp interface", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "interface information\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_interface (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_address_family_binding, + ldp_show_mpls_ldp_address_family_binding_cmd, + "show mpls ldp (ipv4|ipv6) binding", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "IPv4 Address Family\n" + "IPv6 Address Family\n" + "Label Information Base (LIB) information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "address-family", .value = argv[0] }, + NULL + }; + return ldp_vty_show_binding (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_address_family_discovery, + ldp_show_mpls_ldp_address_family_discovery_cmd, + "show mpls ldp (ipv4|ipv6) discovery", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "IPv4 Address Family\n" + "IPv6 Address Family\n" + "Discovery Hello Information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "address-family", .value = argv[0] }, + NULL + }; + return ldp_vty_show_discovery (vty, args); +} + +DEFUN (ldp_show_mpls_ldp_address_family_interface, + ldp_show_mpls_ldp_address_family_interface_cmd, + "show mpls ldp (ipv4|ipv6) interface", + "Show running system information\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "IPv4 Address Family\n" + "IPv6 Address Family\n" + "interface information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "address-family", .value = argv[0] }, + NULL + }; + return ldp_vty_show_interface (vty, args); +} + +DEFUN (ldp_show_l2vpn_atom_binding, + ldp_show_l2vpn_atom_binding_cmd, + "show l2vpn atom binding", + "Show running system information\n" + "Show information about Layer2 VPN\n" + "Show Any Transport over MPLS information\n" + "Show AToM label binding information\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_atom_binding (vty, args); +} + +DEFUN (ldp_show_l2vpn_atom_vc, + ldp_show_l2vpn_atom_vc_cmd, + "show l2vpn atom vc", + "Show running system information\n" + "Show information about Layer2 VPN\n" + "Show Any Transport over MPLS information\n" + "Show AToM virtual circuit information\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_atom_vc (vty, args); +} + +DEFUN (ldp_show_debugging_mpls_ldp, + ldp_show_debugging_mpls_ldp_cmd, + "show debugging mpls ldp", + "Show running system information\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_show_debugging (vty, args); +} + +DEFUN (ldp_clear_mpls_ldp_neighbor, + ldp_clear_mpls_ldp_neighbor_cmd, + "clear mpls ldp neighbor", + "Reset functions\n" + "Reset MPLS statistical information\n" + "Clear LDP state\n" + "Clear LDP neighbor sessions\n") +{ + struct vty_arg *args[] = { NULL }; + return ldp_vty_clear_nbr (vty, args); +} + +DEFUN (ldp_clear_mpls_ldp_neighbor_addr, + ldp_clear_mpls_ldp_neighbor_addr_cmd, + "clear mpls ldp neighbor (A.B.C.D|X:X::X:X)", + "Reset functions\n" + "Reset MPLS statistical information\n" + "Clear LDP state\n" + "Clear LDP neighbor sessions\n" + "IPv4 address\n" + "IPv6 address\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "addr", .value = argv[0] }, + NULL + }; + return ldp_vty_clear_nbr (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_discovery_hello_dir, + ldp_debug_mpls_ldp_discovery_hello_dir_cmd, + "debug mpls ldp discovery hello (recv|sent)", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Discovery messages\n" + "Discovery hello message\n" + "Received messages\n" + "Sent messages\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "discovery" }, + &(struct vty_arg) { .name = "dir", .value = argv[0] }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_errors, + ldp_debug_mpls_ldp_errors_cmd, + "debug mpls ldp errors", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Errors\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "errors" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_event, + ldp_debug_mpls_ldp_event_cmd, + "debug mpls ldp event", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "LDP event information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "event" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_recv, + ldp_debug_mpls_ldp_messages_recv_cmd, + "debug mpls ldp messages recv", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Received messages, excluding periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "recv" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_recv_all, + ldp_debug_mpls_ldp_messages_recv_all_cmd, + "debug mpls ldp messages recv all", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Received messages, excluding periodic Keep Alives\n" + "Received messages, including periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "recv" }, + &(struct vty_arg) { .name = "all", .value = "all" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_sent, + ldp_debug_mpls_ldp_messages_sent_cmd, + "debug mpls ldp messages sent", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Sent messages, excluding periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "sent" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_messages_sent_all, + ldp_debug_mpls_ldp_messages_sent_all_cmd, + "debug mpls ldp messages sent all", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Sent messages, excluding periodic Keep Alives\n" + "Sent messages, including periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "sent" }, + &(struct vty_arg) { .name = "all", .value = "all" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_debug_mpls_ldp_zebra, + ldp_debug_mpls_ldp_zebra_cmd, + "debug mpls ldp zebra", + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "LDP zebra information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "type", .value = "zebra" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_discovery_hello_dir, + ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd, + "no debug mpls ldp discovery hello (recv|sent)", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Discovery messages\n" + "Discovery hello message\n" + "Received messages\n" + "Sent messages\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "discovery" }, + &(struct vty_arg) { .name = "dir", .value = argv[0] }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_errors, + ldp_no_debug_mpls_ldp_errors_cmd, + "no debug mpls ldp errors", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Errors\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "errors" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_event, + ldp_no_debug_mpls_ldp_event_cmd, + "no debug mpls ldp event", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "LDP event information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "event" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_recv, + ldp_no_debug_mpls_ldp_messages_recv_cmd, + "no debug mpls ldp messages recv", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Received messages, excluding periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "recv" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_recv_all, + ldp_no_debug_mpls_ldp_messages_recv_all_cmd, + "no debug mpls ldp messages recv all", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Received messages, excluding periodic Keep Alives\n" + "Received messages, including periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "recv" }, + &(struct vty_arg) { .name = "all", .value = "all" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_sent, + ldp_no_debug_mpls_ldp_messages_sent_cmd, + "no debug mpls ldp messages sent", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Sent messages, excluding periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "sent" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_messages_sent_all, + ldp_no_debug_mpls_ldp_messages_sent_all_cmd, + "no debug mpls ldp messages sent all", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "Messages\n" + "Sent messages, excluding periodic Keep Alives\n" + "Sent messages, including periodic Keep Alives\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "messages" }, + &(struct vty_arg) { .name = "dir", .value = "sent" }, + &(struct vty_arg) { .name = "all", .value = "all" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +DEFUN (ldp_no_debug_mpls_ldp_zebra, + ldp_no_debug_mpls_ldp_zebra_cmd, + "no debug mpls ldp zebra", + "Negate a command or set its defaults\n" + "Debugging functions\n" + "MPLS information\n" + "Label Distribution Protocol\n" + "LDP zebra information\n") +{ + struct vty_arg *args[] = + { + &(struct vty_arg) { .name = "no", .value = "no" }, + &(struct vty_arg) { .name = "type", .value = "zebra" }, + NULL + }; + return ldp_vty_debug (vty, args); +} + +void +ldp_vty_init (void) +{ + install_element (CONFIG_NODE, &ldp_mpls_ldp_cmd); + install_element (CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); + install_element (CONFIG_NODE, &ldp_no_mpls_ldp_cmd); + install_element (CONFIG_NODE, &ldp_no_l2vpn_word_type_vpls_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_discovery_hello_dir_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_errors_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_event_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_recv_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_recv_all_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_sent_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_messages_sent_all_cmd); + install_element (CONFIG_NODE, &ldp_debug_mpls_ldp_zebra_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_errors_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_event_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_recv_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_recv_all_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_sent_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_messages_sent_all_cmd); + install_element (CONFIG_NODE, &ldp_no_debug_mpls_ldp_zebra_cmd); + install_node (&ldp_node, ldp_config_write); + install_default (LDP_NODE); + install_element (LDP_NODE, &ldp_address_family_ipv4_cmd); + install_element (LDP_NODE, &ldp_address_family_ipv6_cmd); + install_element (LDP_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_NODE, &ldp_discovery_hello_interval_disc_time_cmd); + install_element (LDP_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd); + install_element (LDP_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd); + install_element (LDP_NODE, &ldp_dual_stack_transport_connection_prefer_ipv4_cmd); + install_element (LDP_NODE, &ldp_dual_stack_cisco_interop_cmd); + install_element (LDP_NODE, &ldp_neighbor_ipv4_password_word_cmd); + install_element (LDP_NODE, &ldp_neighbor_ipv4_session_holdtime_session_time_cmd); + install_element (LDP_NODE, &ldp_neighbor_ipv4_ttl_security_disable_cmd); + install_element (LDP_NODE, &ldp_neighbor_ipv4_ttl_security_hops_hops_cmd); + install_element (LDP_NODE, &ldp_router_id_ipv4_cmd); + install_element (LDP_NODE, &ldp_no_address_family_ipv4_cmd); + install_element (LDP_NODE, &ldp_no_address_family_ipv6_cmd); + install_element (LDP_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); + install_element (LDP_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd); + install_element (LDP_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd); + install_element (LDP_NODE, &ldp_no_dual_stack_transport_connection_prefer_ipv4_cmd); + install_element (LDP_NODE, &ldp_no_dual_stack_cisco_interop_cmd); + install_element (LDP_NODE, &ldp_no_neighbor_ipv4_password_word_cmd); + install_element (LDP_NODE, &ldp_no_neighbor_ipv4_session_holdtime_session_time_cmd); + install_element (LDP_NODE, &ldp_no_neighbor_ipv4_ttl_security_disable_cmd); + install_element (LDP_NODE, &ldp_no_neighbor_ipv4_ttl_security_hops_hops_cmd); + install_element (LDP_NODE, &ldp_no_router_id_ipv4_cmd); + install_node (&ldp_ipv4_node, NULL); + install_default (LDP_IPV4_NODE); + install_element (LDP_IPV4_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_discovery_hello_interval_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_discovery_targeted_hello_accept_cmd); + install_element (LDP_IPV4_NODE, &ldp_label_local_advertise_explicit_null_cmd); + install_element (LDP_IPV4_NODE, &ldp_ttl_security_disable_cmd); + install_element (LDP_IPV4_NODE, &ldp_session_holdtime_session_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_interface_ifname_cmd); + install_element (LDP_IPV4_NODE, &ldp_discovery_transport_address_ipv4_cmd); + install_element (LDP_IPV4_NODE, &ldp_neighbor_ipv4_targeted_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_discovery_targeted_hello_accept_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_label_local_advertise_explicit_null_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_ttl_security_disable_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_session_holdtime_session_time_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_interface_ifname_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_discovery_transport_address_ipv4_cmd); + install_element (LDP_IPV4_NODE, &ldp_no_neighbor_ipv4_targeted_cmd); + install_node (&ldp_ipv6_node, NULL); + install_default (LDP_IPV6_NODE); + install_element (LDP_IPV6_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_discovery_hello_interval_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_interval_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_discovery_targeted_hello_accept_cmd); + install_element (LDP_IPV6_NODE, &ldp_label_local_advertise_explicit_null_cmd); + install_element (LDP_IPV6_NODE, &ldp_ttl_security_disable_cmd); + install_element (LDP_IPV6_NODE, &ldp_session_holdtime_session_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_interface_ifname_cmd); + install_element (LDP_IPV6_NODE, &ldp_discovery_transport_address_ipv6_cmd); + install_element (LDP_IPV6_NODE, &ldp_neighbor_ipv6_targeted_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_interval_disc_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_discovery_targeted_hello_accept_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_label_local_advertise_explicit_null_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_ttl_security_disable_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_session_holdtime_session_time_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_interface_ifname_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_discovery_transport_address_ipv6_cmd); + install_element (LDP_IPV6_NODE, &ldp_no_neighbor_ipv6_targeted_cmd); + install_node (&ldp_ipv4_iface_node, NULL); + install_default (LDP_IPV4_IFACE_NODE); + install_element (LDP_IPV4_IFACE_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV4_IFACE_NODE, &ldp_discovery_hello_interval_disc_time_cmd); + install_element (LDP_IPV4_IFACE_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV4_IFACE_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); + install_node (&ldp_ipv6_iface_node, NULL); + install_default (LDP_IPV6_IFACE_NODE); + install_element (LDP_IPV6_IFACE_NODE, &ldp_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV6_IFACE_NODE, &ldp_discovery_hello_interval_disc_time_cmd); + install_element (LDP_IPV6_IFACE_NODE, &ldp_no_discovery_hello_holdtime_disc_time_cmd); + install_element (LDP_IPV6_IFACE_NODE, &ldp_no_discovery_hello_interval_disc_time_cmd); + install_node (&ldp_l2vpn_node, ldp_l2vpn_config_write); + install_default (LDP_L2VPN_NODE); + install_element (LDP_L2VPN_NODE, &ldp_bridge_ifname_cmd); + install_element (LDP_L2VPN_NODE, &ldp_mtu_mtu_cmd); + install_element (LDP_L2VPN_NODE, &ldp_member_interface_ifname_cmd); + install_element (LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); + install_element (LDP_L2VPN_NODE, &ldp_vc_type_pwtype_cmd); + install_element (LDP_L2VPN_NODE, &ldp_no_bridge_ifname_cmd); + install_element (LDP_L2VPN_NODE, &ldp_no_mtu_mtu_cmd); + install_element (LDP_L2VPN_NODE, &ldp_no_member_interface_ifname_cmd); + install_element (LDP_L2VPN_NODE, &ldp_no_member_pseudowire_ifname_cmd); + install_element (LDP_L2VPN_NODE, &ldp_no_vc_type_pwtype_cmd); + install_node (&ldp_pseudowire_node, NULL); + install_default (LDP_PSEUDOWIRE_NODE); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_control_word_cword_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_neighbor_address_addr_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_neighbor_lsr_id_ipv4_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_pw_id_pwid_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_pw_status_disable_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_control_word_cword_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_neighbor_address_addr_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_neighbor_lsr_id_ipv4_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_pw_id_pwid_cmd); + install_element (LDP_PSEUDOWIRE_NODE, &ldp_no_pw_status_disable_cmd); + install_node (&ldp_debug_node, ldp_debug_config_write); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_neighbor_cmd); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_binding_cmd); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_discovery_cmd); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_interface_cmd); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_binding_cmd); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_discovery_cmd); + install_element (ENABLE_NODE, &ldp_show_mpls_ldp_address_family_interface_cmd); + install_element (ENABLE_NODE, &ldp_show_l2vpn_atom_binding_cmd); + install_element (ENABLE_NODE, &ldp_show_l2vpn_atom_vc_cmd); + install_element (ENABLE_NODE, &ldp_show_debugging_mpls_ldp_cmd); + install_element (ENABLE_NODE, &ldp_clear_mpls_ldp_neighbor_cmd); + install_element (ENABLE_NODE, &ldp_clear_mpls_ldp_neighbor_addr_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_discovery_hello_dir_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_errors_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_event_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_recv_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_recv_all_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_sent_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_messages_sent_all_cmd); + install_element (ENABLE_NODE, &ldp_debug_mpls_ldp_zebra_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_discovery_hello_dir_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_errors_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_event_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_recv_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_recv_all_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_sent_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_messages_sent_all_cmd); + install_element (ENABLE_NODE, &ldp_no_debug_mpls_ldp_zebra_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_neighbor_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_binding_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_discovery_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_interface_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_binding_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_discovery_cmd); + install_element (VIEW_NODE, &ldp_show_mpls_ldp_address_family_interface_cmd); + install_element (VIEW_NODE, &ldp_show_l2vpn_atom_binding_cmd); + install_element (VIEW_NODE, &ldp_show_l2vpn_atom_vc_cmd); + install_element (VIEW_NODE, &ldp_show_debugging_mpls_ldp_cmd); + install_element (VIEW_NODE, &ldp_clear_mpls_ldp_neighbor_cmd); + install_element (VIEW_NODE, &ldp_clear_mpls_ldp_neighbor_addr_cmd); +}
\ No newline at end of file diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c new file mode 100644 index 000000000..a3e1b9a25 --- /dev/null +++ b/ldpd/ldp_vty_conf.c @@ -0,0 +1,1637 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" +#include "log.h" + +#include "command.h" +#include "vrf.h" +#include "if.h" +#include "vty.h" +#include "ldp_vty.h" + +static int interface_config_write(struct vty *); +static void ldp_af_iface_config_write(struct vty *, int); +static void ldp_af_config_write(struct vty *, int, struct ldpd_conf *, + struct ldpd_af_conf *); +static void ldp_l2vpn_pw_config_write(struct vty *, struct l2vpn_pw *); +static int ldp_vty_get_af(struct vty *); +static int ldp_iface_is_configured(struct ldpd_conf *, const char *); +static int ldp_vty_nbr_session_holdtime(struct vty *, struct vty_arg *[]); +static int ldp_vty_af_session_holdtime(struct vty *, struct vty_arg *[]); + +static char vty_ifname[IF_NAMESIZE]; +static char vty_l2vpn_name[L2VPN_NAME_LEN]; +static char vty_pw_ifname[IF_NAMESIZE]; + +static struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 +}; + +struct cmd_node ldp_node = +{ + LDP_NODE, + "%s(config-ldp)# ", + 1, +}; + +struct cmd_node ldp_ipv4_node = +{ + LDP_IPV4_NODE, + "%s(config-ldp-af)# ", + 1, +}; + +struct cmd_node ldp_ipv6_node = +{ + LDP_IPV6_NODE, + "%s(config-ldp-af)# ", + 1, +}; + +struct cmd_node ldp_ipv4_iface_node = +{ + LDP_IPV4_IFACE_NODE, + "%s(config-ldp-af-if)# ", + 1, +}; + +struct cmd_node ldp_ipv6_iface_node = +{ + LDP_IPV6_IFACE_NODE, + "%s(config-ldp-af-if)# ", + 1, +}; + +struct cmd_node ldp_l2vpn_node = +{ + LDP_L2VPN_NODE, + "%s(config-l2vpn)# ", + 1, +}; + +struct cmd_node ldp_pseudowire_node = +{ + LDP_PSEUDOWIRE_NODE, + "%s(config-l2vpn-pw)# ", + 1, +}; + +int +ldp_get_address(const char *str, int *af, union ldpd_addr *addr) +{ + memset(addr, 0, sizeof(*addr)); + + if (inet_pton(AF_INET, str, &addr->v4) == 1) { + *af = AF_INET; + return (0); + } + + if (inet_pton(AF_INET6, str, &addr->v6) == 1) { + *af = AF_INET6; + return (0); + } + + return (-1); +} + +static int +interface_config_write(struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + int write = 0; + + for (ALL_LIST_ELEMENTS_RO(vrf_iflist (VRF_DEFAULT), node, ifp)) { + vty_out(vty, "!%s", VTY_NEWLINE); + vty_out(vty, "interface %s%s", ifp->name, VTY_NEWLINE); + if (ifp->desc) + vty_out(vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + write++; + } + + return (write); +} + +static void +ldp_af_iface_config_write(struct vty *vty, int af) +{ + struct iface *iface; + struct iface_af *ia; + + LIST_FOREACH(iface, &ldpd_conf->iface_list, entry) { + ia = iface_af_get(iface, af); + if (!ia->enabled) + continue; + + vty_out(vty, " !%s", VTY_NEWLINE); + vty_out(vty, " interface %s%s", iface->name, VTY_NEWLINE); + + if (ia->hello_holdtime != LINK_DFLT_HOLDTIME && + ia->hello_holdtime != 0) + vty_out(vty, " discovery hello holdtime %u%s", + ia->hello_holdtime, VTY_NEWLINE); + if (ia->hello_interval != DEFAULT_HELLO_INTERVAL && + ia->hello_interval != 0) + vty_out(vty, " discovery hello interval %u%s", + ia->hello_interval, VTY_NEWLINE); + } +} + +static void +ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf, + struct ldpd_af_conf *af_conf) +{ + struct tnbr *tnbr; + + if (!(af_conf->flags & F_LDPD_AF_ENABLED)) + return; + + vty_out(vty, " !%s", VTY_NEWLINE); + vty_out(vty, " address-family %s%s", af_name(af), VTY_NEWLINE); + + if (af_conf->lhello_holdtime != LINK_DFLT_HOLDTIME && + af_conf->lhello_holdtime != 0 ) + vty_out(vty, " discovery hello holdtime %u%s", + af_conf->lhello_holdtime, VTY_NEWLINE); + if (af_conf->lhello_interval != DEFAULT_HELLO_INTERVAL && + af_conf->lhello_interval != 0) + vty_out(vty, " discovery hello interval %u%s", + af_conf->lhello_interval, VTY_NEWLINE); + + if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) + vty_out(vty, " discovery targeted-hello accept%s", + VTY_NEWLINE); + + if (af_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && + af_conf->thello_holdtime != 0) + vty_out(vty, " discovery targeted-hello holdtime %u%s", + af_conf->thello_holdtime, VTY_NEWLINE); + if (af_conf->thello_interval != DEFAULT_HELLO_INTERVAL && + af_conf->thello_interval != 0) + vty_out(vty, " discovery targeted-hello interval %u%s", + af_conf->thello_interval, VTY_NEWLINE); + + if (ldp_addrisset(af, &af_conf->trans_addr)) + vty_out(vty, " discovery transport-address %s%s", + log_addr(af, &af_conf->trans_addr), VTY_NEWLINE); + else + vty_out(vty, " ! Incomplete config, specify a discovery " + "transport-address%s", VTY_NEWLINE); + + if (af_conf->flags & F_LDPD_AF_EXPNULL) + vty_out(vty, " label local advertise explicit-null%s", + VTY_NEWLINE); + + if (af_conf->flags & F_LDPD_AF_NO_GTSM) + vty_out(vty, " ttl-security disable%s", VTY_NEWLINE); + + if (af_conf->keepalive != DEFAULT_KEEPALIVE) + vty_out(vty, " session holdtime %u%s", af_conf->keepalive, + VTY_NEWLINE); + + LIST_FOREACH(tnbr, &ldpd_conf->tnbr_list, entry) { + if (tnbr->af == af) { + vty_out(vty, " !%s", VTY_NEWLINE); + vty_out(vty, " neighbor %s targeted%s", + log_addr(tnbr->af, &tnbr->addr), VTY_NEWLINE); + } + } + + ldp_af_iface_config_write(vty, af); + + vty_out(vty, " !%s", VTY_NEWLINE); +} + +int +ldp_config_write(struct vty *vty) +{ + struct nbr_params *nbrp; + + if (!(ldpd_conf->flags & F_LDPD_ENABLED)) + return (0); + + vty_out(vty, "mpls ldp%s", VTY_NEWLINE); + + if (ldpd_conf->rtr_id.s_addr != 0) + vty_out(vty, " router-id %s%s", + inet_ntoa(ldpd_conf->rtr_id), VTY_NEWLINE); + + if (ldpd_conf->lhello_holdtime != LINK_DFLT_HOLDTIME && + ldpd_conf->lhello_holdtime != 0) + vty_out(vty, " discovery hello holdtime %u%s", + ldpd_conf->lhello_holdtime, VTY_NEWLINE); + if (ldpd_conf->lhello_interval != DEFAULT_HELLO_INTERVAL && + ldpd_conf->lhello_interval != 0) + vty_out(vty, " discovery hello interval %u%s", + ldpd_conf->lhello_interval, VTY_NEWLINE); + + if (ldpd_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && + ldpd_conf->thello_holdtime != 0) + vty_out(vty, " discovery targeted-hello holdtime %u%s", + ldpd_conf->thello_holdtime, VTY_NEWLINE); + if (ldpd_conf->thello_interval != DEFAULT_HELLO_INTERVAL && + ldpd_conf->thello_interval != 0) + vty_out(vty, " discovery targeted-hello interval %u%s", + ldpd_conf->thello_interval, VTY_NEWLINE); + + if (ldpd_conf->trans_pref == DUAL_STACK_LDPOV4) + vty_out(vty, " dual-stack transport-connection prefer ipv4%s", + VTY_NEWLINE); + + if (ldpd_conf->flags & F_LDPD_DS_CISCO_INTEROP) + vty_out(vty, " dual-stack cisco-interop%s", VTY_NEWLINE); + + LIST_FOREACH(nbrp, &ldpd_conf->nbrp_list, entry) { + if (nbrp->flags & F_NBRP_KEEPALIVE) + vty_out(vty, " neighbor %s session holdtime %u%s", + inet_ntoa(nbrp->lsr_id), nbrp->keepalive, + VTY_NEWLINE); + + if (nbrp->flags & F_NBRP_GTSM) { + if (nbrp->gtsm_enabled) + vty_out(vty, " neighbor %s ttl-security hops " + "%u%s", inet_ntoa(nbrp->lsr_id), + nbrp->gtsm_hops, VTY_NEWLINE); + else + vty_out(vty, " neighbor %s ttl-security " + "disable%s", inet_ntoa(nbrp->lsr_id), + VTY_NEWLINE); + } + + if (nbrp->auth.method == AUTH_MD5SIG) + vty_out(vty, " neighbor %s password %s%s", + inet_ntoa(nbrp->lsr_id), nbrp->auth.md5key, + VTY_NEWLINE); + } + + ldp_af_config_write(vty, AF_INET, ldpd_conf, &ldpd_conf->ipv4); + ldp_af_config_write(vty, AF_INET6, ldpd_conf, &ldpd_conf->ipv6); + vty_out(vty, " !%s", VTY_NEWLINE); + vty_out(vty, "!%s", VTY_NEWLINE); + + return (1); +} + +static void +ldp_l2vpn_pw_config_write(struct vty *vty, struct l2vpn_pw *pw) +{ + int missing_lsrid = 0; + int missing_pwid = 0; + + vty_out(vty, " !%s", VTY_NEWLINE); + vty_out(vty, " member pseudowire %s%s", pw->ifname, VTY_NEWLINE); + + if (pw->lsr_id.s_addr != INADDR_ANY) + vty_out(vty, " neighbor lsr-id %s%s", inet_ntoa(pw->lsr_id), + VTY_NEWLINE); + else + missing_lsrid = 1; + + if (pw->flags & F_PW_STATIC_NBR_ADDR) + vty_out(vty, " neighbor address %s%s", log_addr(pw->af, + &pw->addr), VTY_NEWLINE); + + if (pw->pwid != 0) + vty_out(vty, " pw-id %u%s", pw->pwid, VTY_NEWLINE); + else + missing_pwid = 1; + + if (!(pw->flags & F_PW_CWORD_CONF)) + vty_out(vty, " control-word exclude%s", VTY_NEWLINE); + + if (!(pw->flags & F_PW_STATUSTLV_CONF)) + vty_out(vty, " pw-status disable%s", VTY_NEWLINE); + + if (missing_lsrid) + vty_out(vty, " ! Incomplete config, specify a neighbor " + "lsr-id%s", VTY_NEWLINE); + if (missing_pwid) + vty_out(vty, " ! Incomplete config, specify a pw-id%s", + VTY_NEWLINE); +} + +int +ldp_l2vpn_config_write(struct vty *vty) +{ + struct l2vpn *l2vpn; + struct l2vpn_if *lif; + struct l2vpn_pw *pw; + + LIST_FOREACH(l2vpn, &ldpd_conf->l2vpn_list, entry) { + vty_out(vty, "l2vpn %s type vpls%s", l2vpn->name, VTY_NEWLINE); + + if (l2vpn->pw_type != DEFAULT_PW_TYPE) + vty_out(vty, " vc type ethernet-tagged%s", VTY_NEWLINE); + + if (l2vpn->mtu != DEFAULT_L2VPN_MTU) + vty_out(vty, " mtu %u%s", l2vpn->mtu, VTY_NEWLINE); + + if (l2vpn->br_ifname[0] != '\0') + vty_out(vty, " bridge %s%s", l2vpn->br_ifname, + VTY_NEWLINE); + + LIST_FOREACH(lif, &l2vpn->if_list, entry) + vty_out(vty, " member interface %s%s", lif->ifname, + VTY_NEWLINE); + + LIST_FOREACH(pw, &l2vpn->pw_list, entry) + ldp_l2vpn_pw_config_write(vty, pw); + LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) + ldp_l2vpn_pw_config_write(vty, pw); + + vty_out(vty, " !%s", VTY_NEWLINE); + vty_out(vty, "!%s", VTY_NEWLINE); + } + + return (0); +} + +static int +ldp_vty_get_af(struct vty *vty) +{ + switch (vty->node) { + case LDP_IPV4_NODE: + case LDP_IPV4_IFACE_NODE: + return (AF_INET); + case LDP_IPV6_NODE: + case LDP_IPV6_IFACE_NODE: + return (AF_INET6); + default: + fatalx("ldp_vty_get_af: unexpected node"); + } +} + +static int +ldp_iface_is_configured(struct ldpd_conf *xconf, const char *ifname) +{ + struct l2vpn *l2vpn; + + if (if_lookup_name(xconf, ifname)) + return (1); + + LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) { + if (l2vpn_if_find_name(l2vpn, ifname)) + return (1); + if (l2vpn_pw_find_name(l2vpn, ifname)) + return (1); + } + + return (0); +} + +int +ldp_vty_mpls_ldp(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + int disable; + + vty_conf = ldp_dup_config(ldpd_conf); + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + if (disable) + vty_conf->flags &= ~F_LDPD_ENABLED; + else { + vty->node = LDP_NODE; + vty_conf->flags |= F_LDPD_ENABLED; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_address_family(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + const char *af_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + af_str = vty_get_arg_value(args, "address-family"); + + vty_conf = ldp_dup_config(ldpd_conf); + if (strcmp(af_str, "ipv4") == 0) { + af = AF_INET; + af_conf = &vty_conf->ipv4; + } else if (strcmp(af_str, "ipv6") == 0) { + af = AF_INET6; + af_conf = &vty_conf->ipv6; + } else + return (CMD_WARNING); + + if (disable) { + af_conf->flags &= ~F_LDPD_AF_ENABLED; + ldp_reload(vty_conf); + return (CMD_SUCCESS); + } + + switch (af) { + case AF_INET: + vty->node = LDP_IPV4_NODE; + break; + case AF_INET6: + vty->node = LDP_IPV6_NODE; + break; + default: + fatalx("ldp_vty_address_family: unknown af"); + } + af_conf->flags |= F_LDPD_AF_ENABLED; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_disc_holdtime(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + struct iface *iface; + struct iface_af *ia; + int af; + char *ep; + long int secs; + enum hello_type hello_type; + const char *seconds_str; + const char *hello_type_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + seconds_str = vty_get_arg_value(args, "seconds"); + hello_type_str = vty_get_arg_value(args, "hello_type"); + + secs = strtol(seconds_str, &ep, 10); + if (*ep != '\0' || secs < MIN_HOLDTIME || secs > MAX_HOLDTIME) { + vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + if (hello_type_str[0] == 'h') + hello_type = HELLO_LINK; + else + hello_type = HELLO_TARGETED; + + vty_conf = ldp_dup_config(ldpd_conf); + + switch (vty->node) { + case LDP_NODE: + if (disable) { + switch (hello_type) { + case HELLO_LINK: + vty_conf->lhello_holdtime = LINK_DFLT_HOLDTIME; + break; + case HELLO_TARGETED: + vty_conf->thello_holdtime = + TARGETED_DFLT_HOLDTIME; + break; + } + } else { + switch (hello_type) { + case HELLO_LINK: + vty_conf->lhello_holdtime = secs; + break; + case HELLO_TARGETED: + vty_conf->thello_holdtime = secs; + break; + } + } + break; + case LDP_IPV4_NODE: + case LDP_IPV6_NODE: + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) { + switch (hello_type) { + case HELLO_LINK: + af_conf->lhello_holdtime = 0; + break; + case HELLO_TARGETED: + af_conf->thello_holdtime = 0; + break; + } + } else { + switch (hello_type) { + case HELLO_LINK: + af_conf->lhello_holdtime = secs; + break; + case HELLO_TARGETED: + af_conf->thello_holdtime = secs; + break; + } + } + break; + case LDP_IPV4_IFACE_NODE: + case LDP_IPV6_IFACE_NODE: + af = ldp_vty_get_af(vty); + iface = if_lookup_name(vty_conf, vty_ifname); + ia = iface_af_get(iface, af); + + if (disable) + ia->hello_holdtime = 0; + else + ia->hello_holdtime = secs; + break; + default: + fatalx("ldp_vty_disc_holdtime: unexpected node"); + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_disc_interval(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + struct iface *iface; + struct iface_af *ia; + int af; + char *ep; + long int secs; + enum hello_type hello_type; + const char *seconds_str; + const char *hello_type_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + seconds_str = vty_get_arg_value(args, "seconds"); + hello_type_str = vty_get_arg_value(args, "hello_type"); + + secs = strtol(seconds_str, &ep, 10); + if (*ep != '\0' || secs < MIN_HELLO_INTERVAL || + secs > MAX_HELLO_INTERVAL) { + vty_out(vty, "%% Invalid interval%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + if (hello_type_str[0] == 'h') + hello_type = HELLO_LINK; + else + hello_type = HELLO_TARGETED; + + vty_conf = ldp_dup_config(ldpd_conf); + + switch (vty->node) { + case LDP_NODE: + if (disable) { + switch (hello_type) { + case HELLO_LINK: + vty_conf->lhello_interval = LINK_DFLT_HOLDTIME; + break; + case HELLO_TARGETED: + vty_conf->thello_interval = + TARGETED_DFLT_HOLDTIME; + break; + } + } else { + switch (hello_type) { + case HELLO_LINK: + vty_conf->lhello_interval = secs; + break; + case HELLO_TARGETED: + vty_conf->thello_interval = secs; + break; + } + } + break; + case LDP_IPV4_NODE: + case LDP_IPV6_NODE: + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) { + switch (hello_type) { + case HELLO_LINK: + af_conf->lhello_interval = 0; + break; + case HELLO_TARGETED: + af_conf->thello_interval = 0; + break; + } + } else { + switch (hello_type) { + case HELLO_LINK: + af_conf->lhello_interval = secs; + break; + case HELLO_TARGETED: + af_conf->thello_interval = secs; + break; + } + } + break; + case LDP_IPV4_IFACE_NODE: + case LDP_IPV6_IFACE_NODE: + af = ldp_vty_get_af(vty); + iface = if_lookup_name(vty_conf, vty_ifname); + ia = iface_af_get(iface, af); + + if (disable) + ia->hello_interval = 0; + else + ia->hello_interval = secs; + break; + default: + fatalx("ldp_vty_disc_interval: unexpected node"); + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_targeted_hello_accept(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + int disable; + + vty_conf = ldp_dup_config(ldpd_conf); + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) + af_conf->flags &= ~F_LDPD_AF_THELLO_ACCEPT; + else + af_conf->flags |= F_LDPD_AF_THELLO_ACCEPT; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +static int +ldp_vty_nbr_session_holdtime(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + char *ep; + long int secs; + struct in_addr lsr_id; + struct nbr_params *nbrp; + const char *seconds_str; + const char *lsr_id_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + seconds_str = vty_get_arg_value(args, "seconds"); + lsr_id_str = vty_get_arg_value(args, "lsr_id"); + + if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || + bad_addr_v4(lsr_id)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + nbrp = nbr_params_find(vty_conf, lsr_id); + + secs = strtol(seconds_str, &ep, 10); + if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) { + vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE); + goto cancel; + } + + if (disable) { + if (nbrp == NULL) + goto cancel; + + nbrp->keepalive = 0; + nbrp->flags &= ~F_NBRP_KEEPALIVE; + } else { + if (nbrp == NULL) { + nbrp = nbr_params_new(lsr_id); + LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry); + } else if (nbrp->keepalive == secs) + goto cancel; + + nbrp->keepalive = secs; + nbrp->flags |= F_NBRP_KEEPALIVE; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +static int +ldp_vty_af_session_holdtime(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + char *ep; + long int secs; + const char *seconds_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + seconds_str = vty_get_arg_value(args, "seconds"); + + secs = strtol(seconds_str, &ep, 10); + if (*ep != '\0' || secs < MIN_KEEPALIVE || secs > MAX_KEEPALIVE) { + vty_out(vty, "%% Invalid holdtime%s", VTY_NEWLINE); + return (CMD_SUCCESS); + } + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) + af_conf->keepalive = DEFAULT_KEEPALIVE; + else + af_conf->keepalive = secs; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_session_holdtime(struct vty *vty, struct vty_arg *args[]) +{ + switch (vty->node) { + case LDP_NODE: + return (ldp_vty_nbr_session_holdtime(vty, args)); + case LDP_IPV4_NODE: + case LDP_IPV6_NODE: + return (ldp_vty_af_session_holdtime(vty, args)); + default: + fatalx("ldp_vty_session_holdtime: unexpected node"); + } +} + +int +ldp_vty_interface(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + int af; + struct iface *iface; + struct iface_af *ia; + struct interface *ifp; + struct kif kif; + const char *ifname; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + ifname = vty_get_arg_value(args, "ifname"); + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + iface = if_lookup_name(vty_conf, ifname); + + if (disable) { + if (iface == NULL) + goto cancel; + + ia = iface_af_get(iface, af); + if (ia->enabled == 0) + goto cancel; + + ia->enabled = 0; + ldp_reload(vty_conf); + return (CMD_SUCCESS); + } + + switch (af) { + case AF_INET: + vty->node = LDP_IPV4_IFACE_NODE; + break; + case AF_INET6: + vty->node = LDP_IPV6_IFACE_NODE; + break; + default: + break; + } + strlcpy(vty_ifname, ifname, sizeof(vty_ifname)); + + if (iface == NULL) { + if (ldp_iface_is_configured(vty_conf, ifname)) { + vty_out(vty, "%% Interface is already in use%s", + VTY_NEWLINE); + goto cancel; + } + + ifp = if_lookup_by_name(ifname); + memset(&kif, 0, sizeof(kif)); + strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); + if (ifp) { + kif.ifindex = ifp->ifindex; + kif.flags = ifp->flags; + } + iface = if_new(&kif); + + ia = iface_af_get(iface, af); + ia->enabled = 1; + LIST_INSERT_HEAD(&vty_conf->iface_list, iface, entry); + } else { + memset(&kif, 0, sizeof(kif)); + strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); + + ia = iface_af_get(iface, af); + if (ia->enabled) + goto cancel; + ia->enabled = 1; + } + + ldp_reload(vty_conf); + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_trans_addr(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + const char *addr_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + addr_str = vty_get_arg_value(args, "addr"); + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) + memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr)); + else { + if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 || + bad_addr(af, &af_conf->trans_addr)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + goto cancel; + } + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_neighbor_targeted(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + int af; + union ldpd_addr addr; + struct tnbr *tnbr; + const char *addr_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + addr_str = vty_get_arg_value(args, "addr"); + + af = ldp_vty_get_af(vty); + + if (inet_pton(af, addr_str, &addr) != 1 || + bad_addr(af, &addr)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + if (af == AF_INET6 && IN6_IS_SCOPE_EMBED(&addr.v6)) { + vty_out(vty, "%% Address can not be link-local%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + tnbr = tnbr_find(vty_conf, af, &addr); + + if (disable) { + if (tnbr == NULL) + goto cancel; + + LIST_REMOVE(tnbr, entry); + free(tnbr); + ldp_reload(vty_conf); + return (CMD_SUCCESS); + } + + if (tnbr) + goto cancel; + + tnbr = tnbr_new(af, &addr); + tnbr->flags |= F_TNBR_CONFIGURED; + LIST_INSERT_HEAD(&vty_conf->tnbr_list, tnbr, entry); + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_explicit_null(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) + af_conf->flags &= ~F_LDPD_AF_EXPNULL; + else + af_conf->flags |= F_LDPD_AF_EXPNULL; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_ttl_security(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) + af_conf->flags &= ~F_LDPD_AF_NO_GTSM; + else + af_conf->flags |= F_LDPD_AF_NO_GTSM; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_router_id(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + const char *addr_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + addr_str = vty_get_arg_value(args, "addr"); + + vty_conf = ldp_dup_config(ldpd_conf); + + if (disable) + vty_conf->rtr_id.s_addr = INADDR_ANY; + else { + if (inet_pton(AF_INET, addr_str, &vty_conf->rtr_id) != 1 || + bad_addr_v4(vty_conf->rtr_id)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + goto cancel; + } + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_ds_cisco_interop(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + vty_conf = ldp_dup_config(ldpd_conf); + + if (disable) + vty_conf->flags &= ~F_LDPD_DS_CISCO_INTEROP; + else + vty_conf->flags |= F_LDPD_DS_CISCO_INTEROP; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_trans_pref_ipv4(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + vty_conf = ldp_dup_config(ldpd_conf); + + if (disable) + vty_conf->trans_pref = DUAL_STACK_LDPOV6; + else + vty_conf->trans_pref = DUAL_STACK_LDPOV4; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_neighbor_password(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct in_addr lsr_id; + size_t password_len; + struct nbr_params *nbrp; + const char *lsr_id_str; + const char *password_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + lsr_id_str = vty_get_arg_value(args, "lsr_id"); + password_str = vty_get_arg_value(args, "password"); + + if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || + bad_addr_v4(lsr_id)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + nbrp = nbr_params_find(vty_conf, lsr_id); + + if (disable) { + if (nbrp == NULL) + goto cancel; + + memset(&nbrp->auth, 0, sizeof(nbrp->auth)); + nbrp->auth.method = AUTH_NONE; + } else { + if (nbrp == NULL) { + nbrp = nbr_params_new(lsr_id); + LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry); + } else if (nbrp->auth.method == AUTH_MD5SIG && + strcmp(nbrp->auth.md5key, password_str) == 0) + goto cancel; + + password_len = strlcpy(nbrp->auth.md5key, password_str, + sizeof(nbrp->auth.md5key)); + if (password_len >= sizeof(nbrp->auth.md5key)) + vty_out(vty, "%% password has been truncated to %zu " + "characters.", sizeof(nbrp->auth.md5key) - 1); + nbrp->auth.md5key_len = password_len; + nbrp->auth.method = AUTH_MD5SIG; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_neighbor_ttl_security(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct in_addr lsr_id; + struct nbr_params *nbrp; + long int hops = 0; + char *ep; + const char *lsr_id_str; + const char *hops_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + lsr_id_str = vty_get_arg_value(args, "lsr_id"); + hops_str = vty_get_arg_value(args, "hops"); + + if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || + bad_addr_v4(lsr_id)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + if (hops_str) { + hops = strtol(hops_str, &ep, 10); + if (*ep != '\0' || hops < 1 || hops > 254) { + vty_out(vty, "%% Invalid hop count%s", VTY_NEWLINE); + return (CMD_SUCCESS); + } + } + + vty_conf = ldp_dup_config(ldpd_conf); + nbrp = nbr_params_find(vty_conf, lsr_id); + + if (disable) { + if (nbrp == NULL) + goto cancel; + + nbrp->flags &= ~(F_NBRP_GTSM|F_NBRP_GTSM_HOPS); + nbrp->gtsm_enabled = 0; + nbrp->gtsm_hops = 0; + } else { + if (nbrp == NULL) { + nbrp = nbr_params_new(lsr_id); + LIST_INSERT_HEAD(&vty_conf->nbrp_list, nbrp, entry); + } + + nbrp->flags |= F_NBRP_GTSM; + nbrp->flags &= ~F_NBRP_GTSM_HOPS; + if (hops_str) { + nbrp->gtsm_enabled = 1; + nbrp->gtsm_hops = hops; + nbrp->flags |= F_NBRP_GTSM_HOPS; + } else + nbrp->gtsm_enabled = 0; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + const char *name_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + name_str = vty_get_arg_value(args, "name"); + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, name_str); + + if (disable) { + if (l2vpn == NULL) + goto cancel; + + LIST_REMOVE(l2vpn, entry); + l2vpn_del(l2vpn); + ldp_reload(vty_conf); + return (CMD_SUCCESS); + } + + vty->node = LDP_L2VPN_NODE; + strlcpy(vty_l2vpn_name, name_str, sizeof(vty_l2vpn_name)); + if (l2vpn) + goto cancel; + + l2vpn = l2vpn_new(name_str); + l2vpn->type = L2VPN_TYPE_VPLS; + LIST_INSERT_HEAD(&vty_conf->l2vpn_list, l2vpn, entry); + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_bridge(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + const char *ifname; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + ifname = vty_get_arg_value(args, "ifname"); + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + + if (disable) + memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname)); + else + strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname)); + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_mtu(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + char *ep; + int mtu; + const char *mtu_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + mtu_str = vty_get_arg_value(args, "mtu"); + + mtu = strtol(mtu_str, &ep, 10); + if (*ep != '\0' || mtu < MIN_L2VPN_MTU || mtu > MAX_L2VPN_MTU) { + vty_out(vty, "%% Invalid MTU%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + + if (disable) + l2vpn->mtu = DEFAULT_L2VPN_MTU; + else + l2vpn->mtu = mtu; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pwtype(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + int pw_type; + const char *type_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + type_str = vty_get_arg_value(args, "type"); + + if (strcmp(type_str, "ethernet") == 0) + pw_type = PW_TYPE_ETHERNET; + else + pw_type = PW_TYPE_ETHERNET_TAGGED; + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + + if (disable) + l2vpn->pw_type = DEFAULT_PW_TYPE; + else + l2vpn->pw_type = pw_type; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_interface(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_if *lif; + struct interface *ifp; + struct kif kif; + const char *ifname; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + ifname = vty_get_arg_value(args, "ifname"); + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + lif = l2vpn_if_find_name(l2vpn, ifname); + + if (disable) { + if (lif == NULL) + goto cancel; + + LIST_REMOVE(lif, entry); + free(lif); + ldp_reload(vty_conf); + return (CMD_SUCCESS); + } + + if (lif) + goto cancel; + + if (ldp_iface_is_configured(vty_conf, ifname)) { + vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE); + goto cancel; + } + + ifp = if_lookup_by_name(ifname); + memset(&kif, 0, sizeof(kif)); + strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); + if (ifp) { + kif.ifindex = ifp->ifindex; + kif.flags = ifp->flags; + } + + lif = l2vpn_if_new(l2vpn, &kif); + LIST_INSERT_HEAD(&l2vpn->if_list, lif, entry); + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pseudowire(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + struct interface *ifp; + struct kif kif; + const char *ifname; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + ifname = vty_get_arg_value(args, "ifname"); + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + pw = l2vpn_pw_find_name(l2vpn, ifname); + + if (disable) { + if (pw == NULL) + goto cancel; + + LIST_REMOVE(pw, entry); + free(pw); + ldp_reload(vty_conf); + return (CMD_SUCCESS); + } + + if (pw) { + vty->node = LDP_PSEUDOWIRE_NODE; + strlcpy(vty_pw_ifname, ifname, sizeof(vty_pw_ifname)); + goto cancel; + } + + if (ldp_iface_is_configured(vty_conf, ifname)) { + vty_out(vty, "%% Interface is already in use%s", VTY_NEWLINE); + goto cancel; + } + + ifp = if_lookup_by_name(ifname); + memset(&kif, 0, sizeof(kif)); + strlcpy(kif.ifname, ifname, sizeof(kif.ifname)); + if (ifp) { + kif.ifindex = ifp->ifindex; + kif.flags = ifp->flags; + } + + pw = l2vpn_pw_new(l2vpn, &kif); + pw->flags = F_PW_STATUSTLV_CONF|F_PW_CWORD_CONF; + LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, pw, entry); + + ldp_reload(vty_conf); + + vty->node = LDP_PSEUDOWIRE_NODE; + strlcpy(vty_pw_ifname, ifname, sizeof(vty_pw_ifname)); + return (CMD_SUCCESS); + +cancel: + ldp_clear_config(vty_conf); + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_cword(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + const char *preference_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + preference_str = vty_get_arg_value(args, "preference"); + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + + if (disable) + pw->flags |= F_PW_CWORD_CONF; + else { + if (preference_str[0] == 'e') + pw->flags &= ~F_PW_CWORD_CONF; + else + pw->flags |= F_PW_CWORD_CONF; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_nbr_addr(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + int af; + union ldpd_addr addr; + const char *addr_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + addr_str = vty_get_arg_value(args, "addr"); + + if (ldp_get_address(addr_str, &af, &addr) == -1 || + bad_addr(af, &addr)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + + if (disable) { + pw->af = AF_UNSPEC; + memset(&pw->addr, 0, sizeof(pw->addr)); + pw->flags &= ~F_PW_STATIC_NBR_ADDR; + } else { + pw->af = af; + pw->addr = addr; + pw->flags |= F_PW_STATIC_NBR_ADDR; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_nbr_id(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + struct in_addr lsr_id; + const char *lsr_id_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + lsr_id_str = vty_get_arg_value(args, "lsr-id"); + + if (inet_pton(AF_INET, lsr_id_str, &lsr_id) != 1 || + bad_addr_v4(lsr_id)) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + + if (disable) + pw->lsr_id.s_addr = INADDR_ANY; + else + pw->lsr_id = lsr_id; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_pwid(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + char *ep; + uint32_t pwid; + const char *pwid_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + pwid_str = vty_get_arg_value(args, "pwid"); + + pwid = strtol(pwid_str, &ep, 10); + if (*ep != '\0' || pwid < MIN_PWID_ID || pwid > MAX_PWID_ID) { + vty_out(vty, "%% Invalid pw-id%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + + if (disable) + pw->pwid = 0; + else + pw->pwid = pwid; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_l2vpn_pw_pwstatus(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + + vty_conf = ldp_dup_config(ldpd_conf); + l2vpn = l2vpn_find(vty_conf, vty_l2vpn_name); + pw = l2vpn_pw_find_name(l2vpn, vty_pw_ifname); + + if (disable) + pw->flags |= F_PW_STATUSTLV_CONF; + else + pw->flags &= ~F_PW_STATUSTLV_CONF; + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +void +ldp_vty_if_init(void) +{ + /* Install interface node. */ + install_node (&interface_node, interface_config_write); + + install_element(CONFIG_NODE, &interface_cmd); + install_element(CONFIG_NODE, &no_interface_cmd); + install_default(INTERFACE_NODE); + + /* "description" commands. */ + install_element(INTERFACE_NODE, &interface_desc_cmd); + install_element(INTERFACE_NODE, &no_interface_desc_cmd); +} diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c new file mode 100644 index 000000000..a57cf3c3f --- /dev/null +++ b/ldpd/ldp_vty_exec.c @@ -0,0 +1,667 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> +#include <sys/un.h> + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" +#include "log.h" +#include "ldp_vty.h" + +#include "command.h" +#include "vty.h" +#include "mpls.h" + +enum show_command { + SHOW_DISC, + SHOW_IFACE, + SHOW_NBR, + SHOW_LIB, + SHOW_L2VPN_PW, + SHOW_L2VPN_BINDING +}; + +struct show_filter { + int family; + union ldpd_addr addr; + uint8_t prefixlen; +}; + +#define LDPBUFSIZ 65535 + +static int show_interface_msg(struct vty *, struct imsg *, + struct show_filter *); +static void show_discovery_adj(struct vty *, char *, + struct ctl_adj *); +static int show_discovery_msg(struct vty *, struct imsg *, + struct show_filter *); +static void show_nbr_adj(struct vty *, char *, struct ctl_adj *); +static int show_nbr_msg(struct vty *, struct imsg *, + struct show_filter *); +static int show_lib_msg(struct vty *, struct imsg *, + struct show_filter *); +static int show_l2vpn_binding_msg(struct vty *, struct imsg *); +static int show_l2vpn_pw_msg(struct vty *, struct imsg *); +static int ldp_vty_connect(struct imsgbuf *); +static int ldp_vty_dispatch(struct vty *, struct imsgbuf *, + enum show_command, struct show_filter *); +static int ldp_vty_get_af(const char *, int *); + +static int +show_interface_msg(struct vty *vty, struct imsg *imsg, + struct show_filter *filter) +{ + struct ctl_iface *iface; + char timers[BUFSIZ]; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_INTERFACE: + iface = imsg->data; + + if (filter->family != AF_UNSPEC && filter->family != iface->af) + break; + + snprintf(timers, sizeof(timers), "%u/%u", + iface->hello_interval, iface->hello_holdtime); + + vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3u%s", + af_name(iface->af), iface->name, + if_state_name(iface->state), iface->uptime == 0 ? + "00:00:00" : log_time(iface->uptime), timers, + iface->adj_cnt, VTY_NEWLINE); + break; + case IMSG_CTL_END: + vty_out(vty, "%s", VTY_NEWLINE); + return (1); + default: + break; + } + + return (0); +} + +static void +show_discovery_adj(struct vty *vty, char *buffer, struct ctl_adj *adj) +{ + size_t buflen = strlen(buffer); + + snprintf(buffer + buflen, LDPBUFSIZ - buflen, + " LDP Id: %s:0, Transport address: %s%s", + inet_ntoa(adj->id), log_addr(adj->af, + &adj->trans_addr), VTY_NEWLINE); + buflen = strlen(buffer); + snprintf(buffer + buflen, LDPBUFSIZ - buflen, + " Hold time: %u sec%s", adj->holdtime, VTY_NEWLINE); +} + +static int +show_discovery_msg(struct vty *vty, struct imsg *imsg, + struct show_filter *filter) +{ + struct ctl_adj *adj; + struct ctl_disc_if *iface; + struct ctl_disc_tnbr *tnbr; + struct in_addr rtr_id; + union ldpd_addr *trans_addr; + size_t buflen; + static char ifaces_buffer[LDPBUFSIZ]; + static char tnbrs_buffer[LDPBUFSIZ]; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_DISCOVERY: + ifaces_buffer[0] = '\0'; + tnbrs_buffer[0] = '\0'; + break; + case IMSG_CTL_SHOW_DISC_IFACE: + iface = imsg->data; + + if (filter->family != AF_UNSPEC && + ((filter->family == AF_INET && !iface->active_v4) || + (filter->family == AF_INET6 && !iface->active_v6))) + break; + + buflen = strlen(ifaces_buffer); + snprintf(ifaces_buffer + buflen, LDPBUFSIZ - buflen, + " %s: %s%s", iface->name, (iface->no_adj) ? + "xmit" : "xmit/recv", VTY_NEWLINE); + break; + case IMSG_CTL_SHOW_DISC_TNBR: + tnbr = imsg->data; + + if (filter->family != AF_UNSPEC && filter->family != tnbr->af) + break; + + trans_addr = &(ldp_af_conf_get(ldpd_conf, + tnbr->af))->trans_addr; + buflen = strlen(tnbrs_buffer); + snprintf(tnbrs_buffer + buflen, LDPBUFSIZ - buflen, + " %s -> %s: %s%s", log_addr(tnbr->af, trans_addr), + log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ? "xmit" : + "xmit/recv", VTY_NEWLINE); + break; + case IMSG_CTL_SHOW_DISC_ADJ: + adj = imsg->data; + + if (filter->family != AF_UNSPEC && filter->family != adj->af) + break; + + switch(adj->type) { + case HELLO_LINK: + show_discovery_adj(vty, ifaces_buffer, adj); + break; + case HELLO_TARGETED: + show_discovery_adj(vty, tnbrs_buffer, adj); + break; + } + break; + case IMSG_CTL_END: + rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); + vty_out(vty, "Local LDP Identifier: %s:0%s", inet_ntoa(rtr_id), + VTY_NEWLINE); + vty_out(vty, "Discovery Sources:%s", VTY_NEWLINE); + vty_out(vty, " Interfaces:%s", VTY_NEWLINE); + vty_out(vty, "%s", ifaces_buffer); + vty_out(vty, " Targeted Hellos:%s", VTY_NEWLINE); + vty_out(vty, "%s", tnbrs_buffer); + vty_out(vty, "%s", VTY_NEWLINE); + return (1); + default: + break; + } + + return (0); +} + +static void +show_nbr_adj(struct vty *vty, char *buffer, struct ctl_adj *adj) +{ + size_t buflen = strlen(buffer); + + switch (adj->type) { + case HELLO_LINK: + snprintf(buffer + buflen, LDPBUFSIZ - buflen, + " Interface: %s%s", adj->ifname, VTY_NEWLINE); + break; + case HELLO_TARGETED: + snprintf(buffer + buflen, LDPBUFSIZ - buflen, + " Targeted Hello: %s%s", log_addr(adj->af, + &adj->src_addr), VTY_NEWLINE); + break; + } +} + +static int +show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter) +{ + struct ctl_adj *adj; + struct ctl_nbr *nbr; + static char v4adjs_buffer[LDPBUFSIZ]; + static char v6adjs_buffer[LDPBUFSIZ]; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_NBR: + nbr = imsg->data; + + v4adjs_buffer[0] = '\0'; + v6adjs_buffer[0] = '\0'; + vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id), + VTY_NEWLINE); + vty_out(vty, " TCP connection: %s:%u - %s:%u%s", + log_addr(nbr->af, &nbr->laddr), ntohs(nbr->lport), + log_addr(nbr->af, &nbr->raddr), ntohs(nbr->rport), + VTY_NEWLINE); + vty_out(vty, " Session Holdtime: %u sec%s", nbr->holdtime, + VTY_NEWLINE); + vty_out(vty, " State: %s; Downstream-Unsolicited%s", + nbr_state_name(nbr->nbr_state), VTY_NEWLINE); + vty_out(vty, " Up time: %s%s", log_time(nbr->uptime), + VTY_NEWLINE); + break; + case IMSG_CTL_SHOW_NBR_DISC: + adj = imsg->data; + + switch (adj->af) { + case AF_INET: + show_nbr_adj(vty, v4adjs_buffer, adj); + break; + case AF_INET6: + show_nbr_adj(vty, v6adjs_buffer, adj); + break; + default: + fatalx("show_nbr_msg: unknown af"); + } + break; + case IMSG_CTL_SHOW_NBR_END: + vty_out(vty, " LDP Discovery Sources:%s", VTY_NEWLINE); + if (v4adjs_buffer[0] != '\0') { + vty_out(vty, " IPv4:%s", VTY_NEWLINE); + vty_out(vty, "%s", v4adjs_buffer); + } + if (v6adjs_buffer[0] != '\0') { + vty_out(vty, " IPv6:%s", VTY_NEWLINE); + vty_out(vty, "%s", v6adjs_buffer); + } + vty_out(vty, "%s", VTY_NEWLINE); + break; + case IMSG_CTL_END: + return (1); + default: + break; + } + + return (0); +} + +static int +show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_filter *filter) +{ + struct ctl_rt *rt; + char dstnet[BUFSIZ]; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_LIB: + rt = imsg->data; + + if (filter->family != AF_UNSPEC && filter->family != rt->af) + break; + + snprintf(dstnet, sizeof(dstnet), "%s/%d", + log_addr(rt->af, &rt->prefix), rt->prefixlen); + + if (rt->first) { + vty_out(vty, "%s%s", dstnet, VTY_NEWLINE); + vty_out(vty, "%-8sLocal binding: label: %s%s", "", + log_label(rt->local_label), VTY_NEWLINE); + + if (rt->remote_label != NO_LABEL) { + vty_out(vty, "%-8sRemote bindings:%s", "", + VTY_NEWLINE); + vty_out(vty, "%-12sPeer Label%s", + "", VTY_NEWLINE); + vty_out(vty, "%-12s----------------- " + "---------%s", "", VTY_NEWLINE); + } else + vty_out(vty, "%-8sNo remote bindings%s", "", + VTY_NEWLINE); + } + if (rt->remote_label != NO_LABEL) + vty_out(vty, "%12s%-20s%s%s", "", inet_ntoa(rt->nexthop), + log_label(rt->remote_label), VTY_NEWLINE); + break; + case IMSG_CTL_END: + vty_out(vty, "%s", VTY_NEWLINE); + return (1); + default: + break; + } + + return (0); +} + +static int +show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg) +{ + struct ctl_pw *pw; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_L2VPN_BINDING: + pw = imsg->data; + + vty_out(vty, " Destination Address: %s, VC ID: %u%s", + inet_ntoa(pw->lsr_id), pw->pwid, VTY_NEWLINE); + + /* local binding */ + if (pw->local_label != NO_LABEL) { + vty_out(vty, " Local Label: %u%s", pw->local_label, + VTY_NEWLINE); + vty_out(vty, "%-8sCbit: %u, VC Type: %s, " + "GroupID: %u%s", "", pw->local_cword, + pw_type_name(pw->type), pw->local_gid, + VTY_NEWLINE); + vty_out(vty, "%-8sMTU: %u%s", "", pw->local_ifmtu, + VTY_NEWLINE); + } else + vty_out(vty, " Local Label: unassigned%s", + VTY_NEWLINE); + + /* remote binding */ + if (pw->remote_label != NO_LABEL) { + vty_out(vty, " Remote Label: %u%s", + pw->remote_label, VTY_NEWLINE); + vty_out(vty, "%-8sCbit: %u, VC Type: %s, " + "GroupID: %u%s", "", pw->remote_cword, + pw_type_name(pw->type), pw->remote_gid, + VTY_NEWLINE); + vty_out(vty, "%-8sMTU: %u%s", "", pw->remote_ifmtu, + VTY_NEWLINE); + } else + vty_out(vty, " Remote Label: unassigned%s", + VTY_NEWLINE); + break; + case IMSG_CTL_END: + vty_out(vty, "%s", VTY_NEWLINE); + return (1); + default: + break; + } + + return (0); +} + +static int +show_l2vpn_pw_msg(struct vty *vty, struct imsg *imsg) +{ + struct ctl_pw *pw; + + switch (imsg->hdr.type) { + case IMSG_CTL_SHOW_L2VPN_PW: + pw = imsg->data; + + vty_out(vty, "%-9s %-15s %-10u %-16s %-10s%s", pw->ifname, + inet_ntoa(pw->lsr_id), pw->pwid, pw->l2vpn_name, + (pw->status ? "UP" : "DOWN"), VTY_NEWLINE); + break; + case IMSG_CTL_END: + vty_out(vty, "%s", VTY_NEWLINE); + return (1); + default: + break; + } + + return (0); +} + +static int +ldp_vty_connect(struct imsgbuf *ibuf) +{ + struct sockaddr_un s_un; + int ctl_sock; + + /* connect to ldpd control socket */ + if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { + log_warn("%s: socket", __func__); + return (-1); + } + + memset(&s_un, 0, sizeof(s_un)); + s_un.sun_family = AF_UNIX; + strlcpy(s_un.sun_path, LDPD_SOCKET, sizeof(s_un.sun_path)); + if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { + log_warn("%s: connect: %s", __func__, LDPD_SOCKET); + close(ctl_sock); + return (-1); + } + + imsg_init(ibuf, ctl_sock); + + return (0); +} + +static int +ldp_vty_dispatch(struct vty *vty, struct imsgbuf *ibuf, enum show_command cmd, + struct show_filter *filter) +{ + struct imsg imsg; + int n, done = 0; + + while (ibuf->w.queued) + if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) { + log_warn("write error"); + close(ibuf->fd); + return (CMD_WARNING); + } + + while (!done) { + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) { + log_warnx("imsg_read error"); + close(ibuf->fd); + return (CMD_WARNING); + } + if (n == 0) { + log_warnx("pipe closed"); + close(ibuf->fd); + return (CMD_WARNING); + } + + while (!done) { + if ((n = imsg_get(ibuf, &imsg)) == -1) { + log_warnx("imsg_get error"); + close(ibuf->fd); + return (CMD_WARNING); + } + if (n == 0) + break; + switch (cmd) { + case SHOW_IFACE: + done = show_interface_msg(vty, &imsg, filter); + break; + case SHOW_DISC: + done = show_discovery_msg(vty, &imsg, filter); + break; + case SHOW_NBR: + done = show_nbr_msg(vty, &imsg, filter); + break; + case SHOW_LIB: + done = show_lib_msg(vty, &imsg, filter); + break; + case SHOW_L2VPN_PW: + done = show_l2vpn_pw_msg(vty, &imsg); + break; + case SHOW_L2VPN_BINDING: + done = show_l2vpn_binding_msg(vty, &imsg); + break; + default: + break; + } + imsg_free(&imsg); + } + } + + close(ibuf->fd); + + return (CMD_SUCCESS); +} + +static int +ldp_vty_get_af(const char *str, int *af) +{ + if (str == NULL) { + *af = AF_UNSPEC; + return (0); + } else if (strcmp(str, "ipv4") == 0) { + *af = AF_INET; + return (0); + } else if (strcmp(str, "ipv6") == 0) { + *af = AF_INET6; + return (0); + } + + return (-1); +} + +int +ldp_vty_show_binding(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + struct show_filter filter; + const char *af_str; + int af; + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0); + + af_str = vty_get_arg_value(args, "address-family"); + if (ldp_vty_get_af(af_str, &af) < 0) + return (CMD_ERR_NO_MATCH); + + memset(&filter, 0, sizeof(filter)); + filter.family = af; + + return (ldp_vty_dispatch(vty, &ibuf, SHOW_LIB, &filter)); +} + +int +ldp_vty_show_discovery(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + struct show_filter filter; + const char *af_str; + int af; + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0); + + af_str = vty_get_arg_value(args, "address-family"); + if (ldp_vty_get_af(af_str, &af) < 0) + return (CMD_ERR_NO_MATCH); + + memset(&filter, 0, sizeof(filter)); + filter.family = af; + + return (ldp_vty_dispatch(vty, &ibuf, SHOW_DISC, &filter)); +} + +int +ldp_vty_show_interface(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + struct show_filter filter; + unsigned int ifidx = 0; + const char *af_str; + int af; + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, &ifidx, + sizeof(ifidx)); + + af_str = vty_get_arg_value(args, "address-family"); + if (ldp_vty_get_af(af_str, &af) < 0) + return (CMD_ERR_NO_MATCH); + + memset(&filter, 0, sizeof(filter)); + filter.family = af; + + /* header */ + vty_out(vty, "%-4s %-11s %-6s %-8s %-12s %3s%s", "AF", + "Interface", "State", "Uptime", "Hello Timers", "ac", VTY_NEWLINE); + + return (ldp_vty_dispatch(vty, &ibuf, SHOW_IFACE, &filter)); +} + +int +ldp_vty_show_neighbor(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + struct show_filter filter; + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); + + /* not used */ + memset(&filter, 0, sizeof(filter)); + + return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, &filter)); +} + +int +ldp_vty_show_atom_binding(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + struct show_filter filter; + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1, NULL, 0); + + /* not used */ + memset(&filter, 0, sizeof(filter)); + + return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_BINDING, &filter)); +} + +int +ldp_vty_show_atom_vc(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + struct show_filter filter; + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0); + + /* not used */ + memset(&filter, 0, sizeof(filter)); + + /* header */ + vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s", + "Interface", "Peer ID", "VC ID", "Name", "Status", VTY_NEWLINE); + vty_out(vty, "%-9s %-15s %-10s %-16s %-10s%s", + "---------", "---------------", "----------", + "----------------", "----------", VTY_NEWLINE); + + return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_PW, &filter)); +} + +int +ldp_vty_clear_nbr(struct vty *vty, struct vty_arg *args[]) +{ + struct imsgbuf ibuf; + const char *addr_str; + struct ctl_nbr nbr; + + addr_str = vty_get_arg_value(args, "addr"); + + memset(&nbr, 0, sizeof(nbr)); + if (addr_str && + (ldp_get_address(addr_str, &nbr.af, &nbr.raddr) == -1 || + bad_addr(nbr.af, &nbr.raddr))) { + vty_out(vty, "%% Malformed address%s", VTY_NEWLINE); + return (CMD_WARNING); + } + + if (ldp_vty_connect(&ibuf) < 0) + return (CMD_WARNING); + + imsg_compose(&ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, sizeof(nbr)); + + while (ibuf.w.queued) + if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) { + log_warn("write error"); + close(ibuf.fd); + return (CMD_WARNING); + } + + close(ibuf.fd); + + return (CMD_SUCCESS); +} diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c new file mode 100644 index 000000000..41ff47fba --- /dev/null +++ b/ldpd/ldp_zebra.c @@ -0,0 +1,466 @@ +/* + * Copyright (C) 2016 by Open Source Routing. + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#include "prefix.h" +#include "stream.h" +#include "memory.h" +#include "zclient.h" +#include "command.h" +#include "network.h" +#include "linklist.h" + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" +#include "log.h" +#include "ldp_debug.h" + +static void ifp2kif(struct interface *, struct kif *); +static void ifc2kaddr(struct interface *, struct connected *, + struct kaddr *); +static int ldp_router_id_update(int, struct zclient *, zebra_size_t, + vrf_id_t); +static int ldp_interface_add(int, struct zclient *, zebra_size_t, + vrf_id_t); +static int ldp_interface_delete(int, struct zclient *, zebra_size_t, + vrf_id_t); +static int ldp_interface_status_change(int command, struct zclient *, + zebra_size_t, vrf_id_t); +static int ldp_interface_address_add(int, struct zclient *, zebra_size_t, + vrf_id_t); +static int ldp_interface_address_delete(int, struct zclient *, + zebra_size_t, vrf_id_t); +static int ldp_zebra_read_route(int, struct zclient *, zebra_size_t, + vrf_id_t); +static void ldp_zebra_connected(struct zclient *); + +static struct zclient *zclient; + +static void +ifp2kif(struct interface *ifp, struct kif *kif) +{ + memset(kif, 0, sizeof(*kif)); + strlcpy(kif->ifname, ifp->name, sizeof(kif->ifname)); + kif->ifindex = ifp->ifindex; + kif->flags = ifp->flags; +} + +static void +ifc2kaddr(struct interface *ifp, struct connected *ifc, struct kaddr *ka) +{ + memset(ka, 0, sizeof(*ka)); + ka->ifindex = ifp->ifindex; + ka->af = ifc->address->family; + ka->prefixlen = ifc->address->prefixlen; + + switch (ka->af) { + case AF_INET: + ka->addr.v4 = ifc->address->u.prefix4; + if (ifc->destination) + ka->dstbrd.v4 = ifc->destination->u.prefix4; + break; + case AF_INET6: + ka->addr.v6 = ifc->address->u.prefix6; + if (ifc->destination) + ka->dstbrd.v6 = ifc->destination->u.prefix6; + break; + default: + break; + } +} + +int +kr_change(struct kroute *kr) +{ + /* TODO */ + return (0); +} + +int +kr_delete(struct kroute *kr) +{ + /* TODO */ + return (0); +} + +int +kmpw_set(struct kpw *kpw) +{ + /* TODO */ + return (0); +} + +int +kmpw_unset(struct kpw *kpw) +{ + /* TODO */ + return (0); +} + +void +kif_redistribute(const char *ifname) +{ + struct listnode *node, *cnode; + struct interface *ifp; + struct connected *ifc; + struct kif kif; + struct kaddr ka; + + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(VRF_DEFAULT), node, ifp)) { + if (ifname && strcmp(ifname, ifp->name) != 0) + continue; + + ifp2kif(ifp, &kif); + main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif)); + + for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) { + ifc2kaddr(ifp, ifc, &ka); + main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, + sizeof(ka)); + } + } +} + +static int +ldp_router_id_update(int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) +{ + struct prefix router_id; + + zebra_router_id_update_read(zclient->ibuf, &router_id); + + if (bad_addr_v4(router_id.u.prefix4)) + return (0); + + debug_zebra_in("router-id update %s", inet_ntoa(router_id.u.prefix4)); + + global.rtr_id.s_addr = router_id.u.prefix4.s_addr; + main_imsg_compose_ldpe(IMSG_RTRID_UPDATE, 0, &global.rtr_id, + sizeof(global.rtr_id)); + + return (0); +} + +static int +ldp_interface_add(int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) +{ + struct interface *ifp; + struct kif kif; + + ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); + debug_zebra_in("interface add %s index %d mtu %d", ifp->name, + ifp->ifindex, ifp->mtu); + + ifp2kif(ifp, &kif); + main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif)); + + return (0); +} + +static int +ldp_interface_delete(int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) +{ + struct interface *ifp; + + /* zebra_interface_state_read() updates interface structure in iflist */ + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); + if (ifp == NULL) + return (0); + + debug_zebra_in("interface delete %s index %d mtu %d", ifp->name, + ifp->ifindex, ifp->mtu); + + /* To support pseudo interface do not free interface structure. */ + /* if_delete(ifp); */ + ifp->ifindex = IFINDEX_INTERNAL; + + return (0); +} + +static int +ldp_interface_status_change(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + struct listnode *node; + struct connected *ifc; + struct kif kif; + struct kaddr ka; + int link_new; + + /* + * zebra_interface_state_read() updates interface structure in + * iflist. + */ + ifp = zebra_interface_state_read(zclient->ibuf, vrf_id); + if (ifp == NULL) + return (0); + + debug_zebra_in("interface %s state update", ifp->name); + + ifp2kif(ifp, &kif); + main_imsg_compose_ldpe(IMSG_IFSTATUS, 0, &kif, sizeof(kif)); + + link_new = (ifp->flags & IFF_UP) && (ifp->flags & IFF_RUNNING); + if (link_new) { + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + ifc2kaddr(ifp, ifc, &ka); + main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, + sizeof(ka)); + } + } else { + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) { + ifc2kaddr(ifp, ifc, &ka); + main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, + sizeof(ka)); + } + } + + return (0); +} + +static int +ldp_interface_address_add(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *ifc; + struct interface *ifp; + struct kaddr ka; + + ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + if (ifc == NULL) + return (0); + + ifp = ifc->ifp; + ifc2kaddr(ifp, ifc, &ka); + + /* Filter invalid addresses. */ + if (bad_addr(ka.af, &ka.addr)) + return (0); + + debug_zebra_in("address add %s/%u", log_addr(ka.af, &ka.addr), + ka.prefixlen); + + /* notify ldpe about new address */ + main_imsg_compose_ldpe(IMSG_NEWADDR, 0, &ka, sizeof(ka)); + + return (0); +} + +static int +ldp_interface_address_delete(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct connected *ifc; + struct interface *ifp; + struct kaddr ka; + + ifc = zebra_interface_address_read(command, zclient->ibuf, vrf_id); + if (ifc == NULL) + return (0); + + ifp = ifc->ifp; + ifc2kaddr(ifp, ifc, &ka); + connected_free(ifc); + + /* Filter invalid addresses. */ + if (bad_addr(ka.af, &ka.addr)) + return (0); + + debug_zebra_in("address delete %s/%u", log_addr(ka.af, &ka.addr), + ka.prefixlen); + + /* notify ldpe about removed address */ + main_imsg_compose_ldpe(IMSG_DELADDR, 0, &ka, sizeof(ka)); + + return (0); +} + +static int +ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, + vrf_id_t vrf_id) +{ + struct stream *s; + u_char type; + u_char message_flags; + struct kroute kr; + int nhnum, nhlen; + size_t nhmark; + + memset(&kr, 0, sizeof(kr)); + s = zclient->ibuf; + + type = stream_getc(s); + if (type == ZEBRA_ROUTE_CONNECT) + kr.flags |= F_CONNECTED; + stream_getc(s); /* flags, unused */ + stream_getw(s); /* instance, unused */ + message_flags = stream_getc(s); + if (!CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) + return (0); + + switch (command) { + case ZEBRA_IPV4_ROUTE_ADD: + case ZEBRA_REDISTRIBUTE_IPV4_ADD: + case ZEBRA_IPV4_ROUTE_DELETE: + case ZEBRA_REDISTRIBUTE_IPV4_DEL: + kr.af = AF_INET; + nhlen = sizeof(struct in_addr); + break; + case ZEBRA_IPV6_ROUTE_ADD: + case ZEBRA_REDISTRIBUTE_IPV6_ADD: + case ZEBRA_IPV6_ROUTE_DELETE: + case ZEBRA_REDISTRIBUTE_IPV6_DEL: + kr.af = AF_INET6; + nhlen = sizeof(struct in6_addr); + break; + default: + fatalx("ldp_zebra_read_route: unknown command"); + } + kr.prefixlen = stream_getc(s); + stream_get(&kr.prefix, s, PSIZE(kr.prefixlen)); + + if (bad_addr(kr.af, &kr.prefix) || + (kr.af == AF_INET6 && IN6_IS_SCOPE_EMBED(&kr.prefix.v6))) + return (0); + + nhnum = stream_getc(s); + nhmark = stream_get_getp(s); + stream_set_getp(s, nhmark + nhnum * (nhlen + 5)); + + if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_DISTANCE)) + kr.priority = stream_getc(s); + if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_METRIC)) + stream_getl(s); /* metric, not used */ + + stream_set_getp(s, nhmark); + + /* loop through all the nexthops */ + for (; nhnum > 0; nhnum--) { + switch (kr.af) { + case AF_INET: + kr.nexthop.v4.s_addr = stream_get_ipv4(s); + break; + case AF_INET6: + stream_get(&kr.nexthop.v6, s, sizeof(kr.nexthop.v6)); + break; + default: + break; + } + stream_getc(s); /* ifindex_num, unused. */ + kr.ifindex = stream_getl(s); + + switch (command) { + case ZEBRA_IPV4_ROUTE_ADD: + case ZEBRA_REDISTRIBUTE_IPV4_ADD: + case ZEBRA_IPV6_ROUTE_ADD: + case ZEBRA_REDISTRIBUTE_IPV6_ADD: + debug_zebra_in("route add %s/%d nexthop %s (%s)", + log_addr(kr.af, &kr.prefix), kr.prefixlen, + log_addr(kr.af, &kr.nexthop), + zebra_route_string(type)); + main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr, + sizeof(kr)); + break; + case ZEBRA_IPV4_ROUTE_DELETE: + case ZEBRA_REDISTRIBUTE_IPV4_DEL: + case ZEBRA_IPV6_ROUTE_DELETE: + case ZEBRA_REDISTRIBUTE_IPV6_DEL: + debug_zebra_in("route delete %s/%d nexthop %s (%s)", + log_addr(kr.af, &kr.prefix), kr.prefixlen, + log_addr(kr.af, &kr.nexthop), + zebra_route_string(type)); + main_imsg_compose_lde(IMSG_NETWORK_DEL, 0, &kr, + sizeof(kr)); + break; + default: + fatalx("ldp_zebra_read_route: unknown command"); + } + } + + return (0); +} + +static void +ldp_zebra_connected(struct zclient *zclient) +{ + int i; + + zclient_send_reg_requests(zclient, VRF_DEFAULT); + + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { + switch (i) { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + case ZEBRA_ROUTE_STATIC: + case ZEBRA_ROUTE_ISIS: + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP, i, 0, VRF_DEFAULT); + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP6, i, 0, VRF_DEFAULT); + break; + case ZEBRA_ROUTE_RIP: + case ZEBRA_ROUTE_OSPF: + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP, i, 0, VRF_DEFAULT); + break; + case ZEBRA_ROUTE_RIPNG: + case ZEBRA_ROUTE_OSPF6: + zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP6, i, 0, VRF_DEFAULT); + break; + case ZEBRA_ROUTE_BGP: + /* LDP should follow the IGP and ignore BGP routes */ + default: + break; + } + } +} + +void +ldp_zebra_init(struct thread_master *master) +{ + /* Set default values. */ + zclient = zclient_new(master); + zclient_init(zclient, ZEBRA_ROUTE_LDP, 0); + + /* set callbacks */ + zclient->zebra_connected = ldp_zebra_connected; + zclient->router_id_update = ldp_router_id_update; + zclient->interface_add = ldp_interface_add; + zclient->interface_delete = ldp_interface_delete; + zclient->interface_up = ldp_interface_status_change; + zclient->interface_down = ldp_interface_status_change; + zclient->interface_address_add = ldp_interface_address_add; + zclient->interface_address_delete = ldp_interface_address_delete; + zclient->ipv4_route_add = ldp_zebra_read_route; + zclient->ipv4_route_delete = ldp_zebra_read_route; + zclient->redistribute_route_ipv4_add = ldp_zebra_read_route; + zclient->redistribute_route_ipv4_del = ldp_zebra_read_route; + zclient->ipv6_route_add = ldp_zebra_read_route; + zclient->ipv6_route_delete = ldp_zebra_read_route; + zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; + zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; +} diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 4e1449198..1eaa7df4a 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -19,36 +19,40 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> +#include <zebra.h> #include <sys/wait.h> -#include <err.h> -#include <errno.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <signal.h> -#include <unistd.h> #include "ldpd.h" #include "ldpe.h" #include "lde.h" #include "log.h" - -static void main_sig_handler(int, short, void *); -static __dead void usage(void); -static __dead void ldpd_shutdown(void); -static pid_t start_child(enum ldpd_process, char *, int, int, int); -static void main_dispatch_ldpe(int, short, void *); -static void main_dispatch_lde(int, short, void *); -static int main_imsg_compose_both(enum imsg_type, void *, - uint16_t); +#include "ldp_vty.h" +#include "ldp_debug.h" + +#include <lib/version.h> +#include <lib/log.h> +#include "getopt.h" +#include "vty.h" +#include "command.h" +#include "memory.h" +#include "privs.h" +#include "sigevent.h" +#include "zclient.h" +#include "vrf.h" + +static void ldpd_shutdown(void); +static pid_t start_child(enum ldpd_process, char *, int, + const char *, const char *); +static int main_dispatch_ldpe(struct thread *); +static int main_dispatch_lde(struct thread *); static int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); static void main_imsg_send_net_sockets(int); static void main_imsg_send_net_socket(int, enum socket_type); static int main_imsg_send_config(struct ldpd_conf *); -static int ldp_reload(void); +static void ldp_config_normalize(struct ldpd_conf *); +static void ldp_config_reset_main(struct ldpd_conf *); +static void ldp_config_reset_af(struct ldpd_conf *, int); static void merge_global(struct ldpd_conf *, struct ldpd_conf *); static void merge_af(int, struct ldpd_af_conf *, struct ldpd_af_conf *); @@ -63,84 +67,216 @@ static void merge_l2vpn(struct ldpd_conf *, struct l2vpn *, struct ldpd_global global; struct ldpd_conf *ldpd_conf; -static char *conffile; static struct imsgev *iev_ldpe; static struct imsgev *iev_lde; static pid_t ldpe_pid; static pid_t lde_pid; -/* ARGSUSED */ -static void -main_sig_handler(int sig, short event, void *arg) +#define LDP_DEFAULT_CONFIG "ldpd.conf" +#define LDP_VTY_PORT 2612 + +/* Master of threads. */ +struct thread_master *master; + +/* Process ID saved for use by init system */ +static const char *pid_file = PATH_LDPD_PID; + +/* Configuration filename and directory. */ +static char config_default[] = SYSCONFDIR LDP_DEFAULT_CONFIG; + +/* ldpd privileges */ +static zebra_capabilities_t _caps_p [] = { - /* signal handler rules don't apply, libevent decouples for us */ - switch (sig) { - case SIGTERM: - case SIGINT: - ldpd_shutdown(); - /* NOTREACHED */ - case SIGHUP: - if (ldp_reload() == -1) - log_warnx("configuration reload failed"); - else - log_debug("configuration reloaded"); - break; - default: - fatalx("unexpected signal"); - /* NOTREACHED */ + ZCAP_BIND, + ZCAP_NET_ADMIN +}; + +struct zebra_privs_t ldpd_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) + .user = QUAGGA_USER, + .group = QUAGGA_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0 +}; + +/* LDPd options. */ +static struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, + { "dryrun", no_argument, NULL, 'C'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "user", required_argument, NULL, 'u'}, + { "group", required_argument, NULL, 'g'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* Help information display. */ +static void __attribute__ ((noreturn)) +usage(char *progname, int status) +{ + if (status != 0) + fprintf(stderr, "Try `%s --help' for more information.\n", + progname); + else { + printf("Usage : %s [OPTION...]\n\ +Daemon which manages LDP.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-u, --user User to run as\n\ +-g, --group Group to run as\n\ +-v, --version Print program version\n\ +-C, --dryrun Check configuration for validity and exit\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); } + + exit(status); } -static __dead void -usage(void) +/* SIGHUP handler. */ +static void +sighup(void) { - extern char *__progname; + log_info("SIGHUP received"); +} + +/* SIGINT / SIGTERM handler. */ +static void +sigint(void) +{ + log_info("SIGINT received"); + ldpd_shutdown(); +} - fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n", - __progname); - exit(1); +/* SIGUSR1 handler. */ +static void +sigusr1(void) +{ + zlog_rotate(NULL); } +static struct quagga_signal_t ldp_signals[] = +{ + { + .signal = SIGHUP, + .handler = &sighup, + }, + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, + { + .signal = SIGUSR1, + .handler = &sigusr1, + } +}; + int main(int argc, char *argv[]) { - struct event ev_sigint, ev_sigterm, ev_sighup; char *saved_argv0; - int ch; - int debug = 0, lflag = 0, eflag = 0; + int lflag = 0, eflag = 0; int pipe_parent2ldpe[2]; int pipe_parent2lde[2]; + char *p; + char *vty_addr = NULL; + int vty_port = LDP_VTY_PORT; + int daemon_mode = 0; + const char *user = NULL; + const char *group = NULL; + char *config_file = NULL; + char *progname; + struct thread thread; + int dryrun = 0; - conffile = CONF_FILE; ldpd_process = PROC_MAIN; - log_init(1); /* log to stderr until daemonized */ - log_verbose(1); + /* Set umask before anything for security */ + umask(0027); + + /* get program name */ + progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]); saved_argv0 = argv[0]; if (saved_argv0 == NULL) - saved_argv0 = "ldpd"; + saved_argv0 = (char *)"ldpd"; - while ((ch = getopt(argc, argv, "dD:f:nvLE")) != -1) { - switch (ch) { - case 'd': - debug = 1; + while (1) { + int opt; + + opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:vCLE", + longopts, 0); + + if (opt == EOF) + break; + + switch (opt) { + case 0: break; - case 'D': - if (cmdline_symset(optarg) < 0) - log_warnx("could not parse macro definition %s", - optarg); + case 'd': + daemon_mode = 1; break; case 'f': - conffile = optarg; + config_file = optarg; + break; + case 'A': + vty_addr = optarg; + break; + case 'i': + pid_file = optarg; + break; + case 'z': + zclient_serv_path_set(optarg); + break; + case 'P': + /* + * Deal with atoi() returning 0 on failure, and ldpd + * not listening on ldpd port. + */ + if (strcmp(optarg, "0") == 0) { + vty_port = 0; + break; + } + vty_port = atoi(optarg); + if (vty_port <= 0 || vty_port > 0xffff) + vty_port = LDP_VTY_PORT; + break; + case 'u': + user = optarg; break; - case 'n': - global.cmd_opts |= LDPD_OPT_NOACTION; + case 'g': + group = optarg; break; case 'v': - if (global.cmd_opts & LDPD_OPT_VERBOSE) - global.cmd_opts |= LDPD_OPT_VERBOSE2; - global.cmd_opts |= LDPD_OPT_VERBOSE; + print_version(progname); + exit(0); + break; + case 'C': + dryrun = 1; + break; + case 'h': + usage(progname, 0); break; case 'L': lflag = 1; @@ -149,125 +285,132 @@ main(int argc, char *argv[]) eflag = 1; break; default: - usage(); - /* NOTREACHED */ + usage(progname, 1); + break; } } argc -= optind; argv += optind; if (argc > 0 || (lflag && eflag)) - usage(); - - if (lflag) - lde(debug, global.cmd_opts & LDPD_OPT_VERBOSE); - else if (eflag) - ldpe(debug, global.cmd_opts & LDPD_OPT_VERBOSE); + usage(progname, 1); - /* fetch interfaces early */ - kif_init(); - - /* parse config file */ - if ((ldpd_conf = parse_config(conffile)) == NULL ) { - kif_clear(); + /* check for root privileges */ + if (geteuid() != 0) { + errno = EPERM; + perror(progname); exit(1); } - if (global.cmd_opts & LDPD_OPT_NOACTION) { - if (global.cmd_opts & LDPD_OPT_VERBOSE) - print_config(ldpd_conf); - else - fprintf(stderr, "configuration OK\n"); - kif_clear(); - exit(0); - } + zlog_default = openzlog(progname, ZLOG_LDP, 0, + LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); - /* check for root privileges */ - if (geteuid()) - errx(1, "need root privileges"); + if (lflag) + lde(user, group); + else if (eflag) + ldpe(user, group); - /* check for ldpd user */ - if (getpwnam(LDPD_USER) == NULL) - errx(1, "unknown user %s", LDPD_USER); + master = thread_master_create(); - log_init(debug); - log_verbose(global.cmd_opts & (LDPD_OPT_VERBOSE | LDPD_OPT_VERBOSE2)); + cmd_init(1); + vty_init(master); + vrf_init(); + ldp_vty_init(); + ldp_vty_if_init(); - if (!debug) - daemon(1, 0); + /* Get configuration file. */ + ldpd_conf = config_new_empty(); + ldp_config_reset_main(ldpd_conf); + vty_read_config(config_file, config_default); + + /* Start execution only if not in dry-run mode */ + if (dryrun) + exit(0); - log_info("startup"); + if (daemon_mode && daemon(0, 0) < 0) { + log_warn("LDPd daemon failed"); + exit(1); + } - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, - PF_UNSPEC, pipe_parent2ldpe) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1) fatal("socketpair"); - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, - PF_UNSPEC, pipe_parent2lde) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1) fatal("socketpair"); + sock_set_nonblock(pipe_parent2ldpe[0]); + sock_set_cloexec(pipe_parent2ldpe[0]); + sock_set_nonblock(pipe_parent2ldpe[1]); + sock_set_cloexec(pipe_parent2ldpe[1]); + sock_set_nonblock(pipe_parent2lde[0]); + sock_set_cloexec(pipe_parent2lde[0]); + sock_set_nonblock(pipe_parent2lde[1]); + sock_set_cloexec(pipe_parent2lde[1]); /* start children */ lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0, - pipe_parent2lde[1], debug, global.cmd_opts & LDPD_OPT_VERBOSE); + pipe_parent2lde[1], user, group); ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0, - pipe_parent2ldpe[1], debug, global.cmd_opts & LDPD_OPT_VERBOSE); + pipe_parent2ldpe[1], user, group); - event_init(); + /* drop privileges */ + if (user) + ldpd_privs.user = user; + if (group) + ldpd_privs.group = group; + zprivs_init(&ldpd_privs); /* setup signal handler */ - signal_set(&ev_sigint, SIGINT, main_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, main_sig_handler, NULL); - signal_set(&ev_sighup, SIGHUP, main_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal_add(&ev_sighup, NULL); - signal(SIGPIPE, SIG_IGN); + signal_init(master, array_size(ldp_signals), ldp_signals); + + /* library inits */ + ldp_zebra_init(master); /* setup pipes to children */ if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL || (iev_lde = malloc(sizeof(struct imsgev))) == NULL) fatal(NULL); imsg_init(&iev_ldpe->ibuf, pipe_parent2ldpe[0]); - iev_ldpe->handler = main_dispatch_ldpe; - imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]); - iev_lde->handler = main_dispatch_lde; + iev_ldpe->handler_read = main_dispatch_ldpe; + iev_ldpe->ev_read = thread_add_read(master, iev_ldpe->handler_read, + iev_ldpe, iev_ldpe->ibuf.fd); + iev_ldpe->handler_write = ldp_write_handler; + iev_ldpe->ev_write = NULL; - /* setup event handler */ - iev_ldpe->events = EV_READ; - event_set(&iev_ldpe->ev, iev_ldpe->ibuf.fd, iev_ldpe->events, - iev_ldpe->handler, iev_ldpe); - event_add(&iev_ldpe->ev, NULL); - - iev_lde->events = EV_READ; - event_set(&iev_lde->ev, iev_lde->ibuf.fd, iev_lde->events, - iev_lde->handler, iev_lde); - event_add(&iev_lde->ev, NULL); + imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]); + iev_lde->handler_read = main_dispatch_lde; + iev_lde->ev_read = thread_add_read(master, iev_lde->handler_read, + iev_lde, iev_lde->ibuf.fd); + iev_lde->handler_write = ldp_write_handler; + iev_lde->ev_write = NULL; if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf)) fatal("could not establish imsg links"); + main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug, + sizeof(ldp_debug)); main_imsg_send_config(ldpd_conf); - /* notify ldpe about existing interfaces and addresses */ - kif_redistribute(NULL); - - if (kr_init(!(ldpd_conf->flags & F_LDPD_NO_FIB_UPDATE)) == -1) - fatalx("kr_init failed"); - if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED) main_imsg_send_net_sockets(AF_INET); if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED) main_imsg_send_net_sockets(AF_INET6); - /* remove unneded stuff from config */ - /* ... */ + /* Process id file create. */ + pid_output(pid_file); - event_dispatch(); + /* Create VTY socket */ + vty_serv_sock(vty_addr, vty_port, LDP_VTYSH_PATH); + + /* Print banner. */ + log_notice("LDPd %s starting: vty@%d", QUAGGA_VERSION, vty_port); + + /* Fetch next active thread. */ + while (thread_fetch(master, &thread)) + thread_call(&thread); - ldpd_shutdown(); /* NOTREACHED */ return (0); } -static __dead void +static void ldpd_shutdown(void) { pid_t pid; @@ -279,7 +422,6 @@ ldpd_shutdown(void) msgbuf_clear(&iev_lde->ibuf.w); close(iev_lde->ibuf.fd); - kr_shutdown(); config_clear(ldpd_conf); log_debug("waiting for children to terminate"); @@ -302,9 +444,10 @@ ldpd_shutdown(void) } static pid_t -start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose) +start_child(enum ldpd_process p, char *argv0, int fd, const char *user, + const char *group) { - char *argv[5]; + char *argv[7]; int argc = 0; pid_t pid; @@ -326,16 +469,20 @@ start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose) case PROC_MAIN: fatalx("Can not start main process"); case PROC_LDE_ENGINE: - argv[argc++] = "-L"; + argv[argc++] = (char *)"-L"; break; case PROC_LDP_ENGINE: - argv[argc++] = "-E"; + argv[argc++] = (char *)"-E"; break; } - if (debug) - argv[argc++] = "-d"; - if (verbose) - argv[argc++] = "-v"; + if (user) { + argv[argc++] = (char *)"-u"; + argv[argc++] = (char *)user; + } + if (group) { + argv[argc++] = (char *)"-g"; + argv[argc++] = (char *)group; + } argv[argc++] = NULL; execvp(argv0, argv); @@ -344,28 +491,22 @@ start_child(enum ldpd_process p, char *argv0, int fd, int debug, int verbose) /* imsg handling */ /* ARGSUSED */ -static void -main_dispatch_ldpe(int fd, short event, void *bula) +static int +main_dispatch_ldpe(struct thread *thread) { - struct imsgev *iev = bula; + struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; int af; ssize_t n; - int shut = 0, verbose; + int shut = 0; - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* connection closed */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) - shut = 1; - } + iev->ev_read = NULL; + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + shut = 1; for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -375,39 +516,13 @@ main_dispatch_ldpe(int fd, short event, void *bula) break; switch (imsg.hdr.type) { + case IMSG_LOG: + logit(imsg.hdr.pid, "%s", (const char *)imsg.data); + break; case IMSG_REQUEST_SOCKETS: af = imsg.hdr.pid; main_imsg_send_net_sockets(af); break; - case IMSG_CTL_RELOAD: - if (ldp_reload() == -1) - log_warnx("configuration reload failed"); - else - log_debug("configuration reloaded"); - break; - case IMSG_CTL_FIB_COUPLE: - kr_fib_couple(); - break; - case IMSG_CTL_FIB_DECOUPLE: - kr_fib_decouple(); - break; - case IMSG_CTL_KROUTE: - case IMSG_CTL_KROUTE_ADDR: - kr_show_route(&imsg); - break; - case IMSG_CTL_IFINFO: - if (imsg.hdr.len == IMSG_HEADER_SIZE) - kr_ifinfo(NULL, imsg.hdr.pid); - else if (imsg.hdr.len == IMSG_HEADER_SIZE + IFNAMSIZ) - kr_ifinfo(imsg.data, imsg.hdr.pid); - else - log_warnx("IFINFO request with wrong len"); - break; - case IMSG_CTL_LOG_VERBOSE: - /* already checked by ldpe */ - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_verbose(verbose); - break; default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -418,34 +533,35 @@ main_dispatch_ldpe(int fd, short event, void *bula) if (!shut) imsg_event_add(iev); else { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + /* this pipe is dead, so remove the event handlers and exit */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + ldpe_pid = 0; + if (lde_pid == 0) + ldpd_shutdown(); + else + kill(lde_pid, SIGTERM); } + + return (0); } /* ARGSUSED */ -static void -main_dispatch_lde(int fd, short event, void *bula) +static int +main_dispatch_lde(struct thread *thread) { - struct imsgev *iev = bula; + struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; ssize_t n; int shut = 0; - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* connection closed */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("msgbuf_write"); - if (n == 0) - shut = 1; - } + iev->ev_read = NULL; + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + shut = 1; for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -455,6 +571,9 @@ main_dispatch_lde(int fd, short event, void *bula) break; switch (imsg.hdr.type) { + case IMSG_LOG: + logit(imsg.hdr.pid, "%s", (const char *)imsg.data); + break; case IMSG_KLABEL_CHANGE: if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct kroute)) @@ -495,10 +614,41 @@ main_dispatch_lde(int fd, short event, void *bula) if (!shut) imsg_event_add(iev); else { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + /* this pipe is dead, so remove the event handlers and exit */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + lde_pid = 0; + if (ldpe_pid == 0) + ldpd_shutdown(); + else + kill(ldpe_pid, SIGTERM); } + + return (0); +} + +/* ARGSUSED */ +int +ldp_write_handler(struct thread *thread) +{ + struct imsgev *iev = THREAD_ARG(thread); + struct imsgbuf *ibuf = &iev->ibuf; + ssize_t n; + + iev->ev_write = NULL; + + if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) + fatal("msgbuf_write"); + if (n == 0) { + /* this pipe is dead, so remove the event handlers */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + return (0); + } + + imsg_event_add(iev); + + return (0); } void @@ -515,9 +665,11 @@ main_imsg_compose_lde(int type, pid_t pid, void *data, uint16_t datalen) imsg_compose_event(iev_lde, type, 0, pid, -1, data, datalen); } -static int +int main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len) { + if (iev_ldpe == NULL || iev_lde == NULL) + return (0); if (imsg_compose_event(iev_ldpe, type, 0, 0, -1, buf, len) == -1) return (-1); if (imsg_compose_event(iev_lde, type, 0, 0, -1, buf, len) == -1) @@ -528,13 +680,12 @@ main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len) void imsg_event_add(struct imsgev *iev) { - iev->events = EV_READ; - if (iev->ibuf.w.queued) - iev->events |= EV_WRITE; + THREAD_READ_ON(master, iev->ev_read, iev->handler_read, iev, + iev->ibuf.fd); - event_del(&iev->ev); - event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev); - event_add(&iev->ev, NULL); + if (iev->ibuf.w.queued) + THREAD_WRITE_ON(master, iev->ev_write, iev->handler_write, iev, + iev->ibuf.fd); } int @@ -560,22 +711,24 @@ void evbuf_event_add(struct evbuf *eb) { if (eb->wbuf.queued) - event_add(&eb->ev, NULL); + THREAD_WRITE_ON(master, eb->ev, eb->handler, eb->arg, + eb->wbuf.fd); } void -evbuf_init(struct evbuf *eb, int fd, void (*handler)(int, short, void *), +evbuf_init(struct evbuf *eb, int fd, int (*handler)(struct thread *), void *arg) { msgbuf_init(&eb->wbuf); eb->wbuf.fd = fd; - event_set(&eb->ev, eb->wbuf.fd, EV_WRITE, handler, arg); + eb->handler = handler; + eb->arg = arg; } void evbuf_clear(struct evbuf *eb) { - event_del(&eb->ev); + THREAD_WRITE_OFF(eb->ev); msgbuf_clear(&eb->wbuf); eb->wbuf.fd = -1; } @@ -585,9 +738,10 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf) { int pipe_ldpe2lde[2]; - if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - PF_UNSPEC, pipe_ldpe2lde) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_ldpe2lde) == -1) return (-1); + sock_set_nonblock(pipe_ldpe2lde[0]); + sock_set_nonblock(pipe_ldpe2lde[1]); if (imsg_compose(ldpe_buf, IMSG_SOCKET_IPC, 0, 0, pipe_ldpe2lde[0], NULL, 0) == -1) @@ -602,6 +756,9 @@ main_imsg_send_ipc_sockets(struct imsgbuf *ldpe_buf, struct imsgbuf *lde_buf) static void main_imsg_send_net_sockets(int af) { + if (!ldp_addrisset(af, &(ldp_af_conf_get(ldpd_conf, af))->trans_addr)) + return; + main_imsg_send_net_socket(af, LDP_SOCKET_DISC); main_imsg_send_net_socket(af, LDP_SOCKET_EDISC); main_imsg_send_net_socket(af, LDP_SOCKET_SESSION); @@ -657,6 +814,15 @@ ldp_is_dual_stack(struct ldpd_conf *xconf) (xconf->ipv6.flags & F_LDPD_AF_ENABLED)); } +in_addr_t +ldp_rtr_id_get(struct ldpd_conf *xconf) +{ + if (xconf->rtr_id.s_addr != INADDR_ANY) + return (xconf->rtr_id.s_addr); + else + return (global.rtr_id.s_addr); +} + static int main_imsg_send_config(struct ldpd_conf *xconf) { @@ -704,6 +870,11 @@ main_imsg_send_config(struct ldpd_conf *xconf) sizeof(*pw)) == -1) return (-1); } + LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) { + if (main_imsg_compose_both(IMSG_RECONF_L2VPN_IPW, pw, + sizeof(*pw)) == -1) + return (-1); + } } if (main_imsg_compose_both(IMSG_RECONF_END, NULL, 0) == -1) @@ -712,13 +883,10 @@ main_imsg_send_config(struct ldpd_conf *xconf) return (0); } -static int -ldp_reload(void) +int +ldp_reload(struct ldpd_conf *xconf) { - struct ldpd_conf *xconf; - - if ((xconf = parse_config(conffile)) == NULL) - return (-1); + ldp_config_normalize(xconf); if (main_imsg_send_config(xconf) == -1) return (-1); @@ -728,6 +896,205 @@ ldp_reload(void) return (0); } +static void +ldp_config_normalize(struct ldpd_conf *xconf) +{ + struct l2vpn *l2vpn; + struct l2vpn_pw *pw; + + if (!(xconf->flags & F_LDPD_ENABLED)) + ldp_config_reset_main(xconf); + else { + if (!(xconf->ipv4.flags & F_LDPD_AF_ENABLED)) + ldp_config_reset_af(xconf, AF_INET); + if (!(xconf->ipv6.flags & F_LDPD_AF_ENABLED)) + ldp_config_reset_af(xconf, AF_INET6); + } + + LIST_FOREACH(l2vpn, &xconf->l2vpn_list, entry) { + LIST_FOREACH(pw, &l2vpn->pw_list, entry) { + if (pw->flags & F_PW_STATIC_NBR_ADDR) + continue; + + pw->af = AF_INET; + pw->addr.v4 = pw->lsr_id; + } + LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) { + if (pw->flags & F_PW_STATIC_NBR_ADDR) + continue; + + pw->af = AF_INET; + pw->addr.v4 = pw->lsr_id; + } + } +} + +static void +ldp_config_reset_main(struct ldpd_conf *conf) +{ + struct iface *iface; + struct nbr_params *nbrp; + + while ((iface = LIST_FIRST(&conf->iface_list)) != NULL) { + LIST_REMOVE(iface, entry); + free(iface); + } + + while ((nbrp = LIST_FIRST(&conf->nbrp_list)) != NULL) { + LIST_REMOVE(nbrp, entry); + free(nbrp); + } + + conf->rtr_id.s_addr = INADDR_ANY; + ldp_config_reset_af(conf, AF_INET); + ldp_config_reset_af(conf, AF_INET6); + conf->lhello_holdtime = LINK_DFLT_HOLDTIME; + conf->lhello_interval = DEFAULT_HELLO_INTERVAL; + conf->thello_holdtime = TARGETED_DFLT_HOLDTIME; + conf->thello_interval = DEFAULT_HELLO_INTERVAL; + conf->trans_pref = DUAL_STACK_LDPOV6; + conf->flags = 0; +} + +static void +ldp_config_reset_af(struct ldpd_conf *conf, int af) +{ + struct ldpd_af_conf *af_conf; + struct iface *iface; + struct iface_af *ia; + struct tnbr *tnbr, *ttmp; + + LIST_FOREACH(iface, &conf->iface_list, entry) { + ia = iface_af_get(iface, af); + ia->enabled = 0; + } + + LIST_FOREACH_SAFE(tnbr, &conf->tnbr_list, entry, ttmp) { + if (tnbr->af != af) + continue; + + LIST_REMOVE(tnbr, entry); + free(tnbr); + } + + af_conf = ldp_af_conf_get(conf, af); + af_conf->keepalive = 180; + af_conf->lhello_holdtime = 0; + af_conf->lhello_interval = 0; + af_conf->thello_holdtime = 0; + af_conf->thello_interval = 0; + memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr)); + af_conf->flags = 0; +} + +struct ldpd_conf * +ldp_dup_config(struct ldpd_conf *conf) +{ + struct ldpd_conf *xconf; + struct iface *iface, *xi; + struct tnbr *tnbr, *xt; + struct nbr_params *nbrp, *xn; + struct l2vpn *l2vpn, *xl; + struct l2vpn_if *lif, *xf; + struct l2vpn_pw *pw, *xp; + + xconf = malloc(sizeof(*xconf)); + *xconf = *conf; + LIST_INIT(&xconf->iface_list); + LIST_INIT(&xconf->tnbr_list); + LIST_INIT(&xconf->nbrp_list); + LIST_INIT(&xconf->l2vpn_list); + + LIST_FOREACH(iface, &conf->iface_list, entry) { + xi = calloc(1, sizeof(*xi)); + if (xi == NULL) + fatal(__func__); + *xi = *iface; + xi->ipv4.iface = xi; + xi->ipv6.iface = xi; + LIST_INSERT_HEAD(&xconf->iface_list, xi, entry); + } + LIST_FOREACH(tnbr, &conf->tnbr_list, entry) { + xt = calloc(1, sizeof(*xt)); + if (xt == NULL) + fatal(__func__); + *xt = *tnbr; + LIST_INSERT_HEAD(&xconf->tnbr_list, xt, entry); + } + LIST_FOREACH(nbrp, &conf->nbrp_list, entry) { + xn = calloc(1, sizeof(*xn)); + if (xn == NULL) + fatal(__func__); + *xn = *nbrp; + LIST_INSERT_HEAD(&xconf->nbrp_list, xn, entry); + } + LIST_FOREACH(l2vpn, &conf->l2vpn_list, entry) { + xl = calloc(1, sizeof(*xl)); + if (xl == NULL) + fatal(__func__); + *xl = *l2vpn; + LIST_INIT(&xl->if_list); + LIST_INIT(&xl->pw_list); + LIST_INIT(&xl->pw_inactive_list); + LIST_INSERT_HEAD(&xconf->l2vpn_list, xl, entry); + + LIST_FOREACH(lif, &l2vpn->if_list, entry) { + xf = calloc(1, sizeof(*xf)); + if (xf == NULL) + fatal(__func__); + *xf = *lif; + xf->l2vpn = xl; + LIST_INSERT_HEAD(&xl->if_list, xf, entry); + } + LIST_FOREACH(pw, &l2vpn->pw_list, entry) { + xp = calloc(1, sizeof(*xp)); + if (xp == NULL) + fatal(__func__); + *xp = *pw; + xp->l2vpn = xl; + LIST_INSERT_HEAD(&xl->pw_list, xp, entry); + } + LIST_FOREACH(pw, &l2vpn->pw_inactive_list, entry) { + xp = calloc(1, sizeof(*xp)); + if (xp == NULL) + fatal(__func__); + *xp = *pw; + xp->l2vpn = xl; + LIST_INSERT_HEAD(&xl->pw_inactive_list, xp, entry); + } + } + + return (xconf); +} + +void +ldp_clear_config(struct ldpd_conf *xconf) +{ + struct iface *iface; + struct tnbr *tnbr; + struct nbr_params *nbrp; + struct l2vpn *l2vpn; + + while ((iface = LIST_FIRST(&xconf->iface_list)) != NULL) { + LIST_REMOVE(iface, entry); + free(iface); + } + while ((tnbr = LIST_FIRST(&xconf->tnbr_list)) != NULL) { + LIST_REMOVE(tnbr, entry); + free(tnbr); + } + while ((nbrp = LIST_FIRST(&xconf->nbrp_list)) != NULL) { + LIST_REMOVE(nbrp, entry); + free(nbrp); + } + while ((l2vpn = LIST_FIRST(&xconf->l2vpn_list)) != NULL) { + LIST_REMOVE(l2vpn, entry); + l2vpn_del(l2vpn); + } + + free(xconf); +} + void merge_config(struct ldpd_conf *conf, struct ldpd_conf *xconf) { @@ -758,6 +1125,11 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) conf->rtr_id = xconf->rtr_id; } + conf->lhello_holdtime = xconf->lhello_holdtime; + conf->lhello_interval = xconf->lhello_interval; + conf->thello_holdtime = xconf->thello_holdtime; + conf->thello_interval = xconf->thello_interval; + if (conf->trans_pref != xconf->trans_pref) { if (ldpd_process == PROC_LDP_ENGINE) ldpe_reset_ds_nbrs(); @@ -784,6 +1156,9 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) if (ldpd_process == PROC_LDP_ENGINE) ldpe_stop_init_backoff(af); } + + af_conf->lhello_holdtime = xa->lhello_holdtime; + af_conf->lhello_interval = xa->lhello_interval; af_conf->thello_holdtime = xa->thello_holdtime; af_conf->thello_interval = xa->thello_interval; @@ -815,10 +1190,6 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) lde_change_egress_label(af, af_conf->flags & F_LDPD_AF_EXPNULL); break; - case PROC_MAIN: - kr_change_egress_label(af, af_conf->flags & - F_LDPD_AF_EXPNULL); - break; default: break; } @@ -829,7 +1200,7 @@ merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) update_sockets = 1; } - if (ldpd_process == PROC_MAIN && update_sockets) + if (ldpd_process == PROC_MAIN && iev_ldpe && update_sockets) imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, 0, -1, NULL, 0); } @@ -841,7 +1212,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf) LIST_FOREACH_SAFE(iface, &conf->iface_list, entry, itmp) { /* find deleted interfaces */ - if ((xi = if_lookup(xconf, iface->ifindex)) == NULL) { + if ((xi = if_lookup_name(xconf, iface->name)) == NULL) { LIST_REMOVE(iface, entry); if (ldpd_process == PROC_LDP_ENGINE) if_exit(iface); @@ -850,7 +1221,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf) } LIST_FOREACH_SAFE(xi, &xconf->iface_list, entry, itmp) { /* find new interfaces */ - if ((iface = if_lookup(conf, xi->ifindex)) == NULL) { + if ((iface = if_lookup_name(conf, xi->name)) == NULL) { LIST_REMOVE(xi, entry); LIST_INSERT_HEAD(&conf->iface_list, xi, entry); @@ -914,8 +1285,6 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf) /* update existing tnbrs */ if (!(tnbr->flags & F_TNBR_CONFIGURED)) tnbr->flags |= F_TNBR_CONFIGURED; - tnbr->hello_holdtime = xt->hello_holdtime; - tnbr->hello_interval = xt->hello_interval; LIST_REMOVE(xt, entry); free(xt); } @@ -935,7 +1304,14 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf) nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr); if (nbr) { session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__ pfkey_remove(nbr); +#else + sock_set_md5sig( + (ldp_af_global_get(&global, + nbr->af))->ldp_session_socket, + nbr->af, &nbr->raddr, NULL); +#endif if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); } @@ -954,8 +1330,16 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf) nbr = nbr_find_ldpid(xn->lsr_id.s_addr); if (nbr) { session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__ if (pfkey_establish(nbr, xn) == -1) fatalx("pfkey setup failed"); +#else + sock_set_md5sig( + (ldp_af_global_get(&global, + nbr->af))->ldp_session_socket, + nbr->af, &nbr->raddr, + xn->auth.md5key); +#endif if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); } @@ -987,9 +1371,15 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf) nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr); if (nbr && nbrp_changed) { session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__ pfkey_remove(nbr); if (pfkey_establish(nbr, nbrp) == -1) fatalx("pfkey setup failed"); +#else + sock_set_md5sig((ldp_af_global_get(&global, + nbr->af))->ldp_session_socket, nbr->af, + &nbr->raddr, nbrp->auth.md5key); +#endif if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); } @@ -1055,6 +1445,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) struct l2vpn_pw *pw, *ptmp, *xp; struct nbr *nbr; int reset_nbr, reinstall_pwfec, reinstall_tnbr; + LIST_HEAD(, l2vpn_pw) pw_aux_list; int previous_pw_type, previous_mtu; previous_pw_type = l2vpn->pw_type; @@ -1063,14 +1454,14 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) /* merge intefaces */ LIST_FOREACH_SAFE(lif, &l2vpn->if_list, entry, ftmp) { /* find deleted interfaces */ - if ((xf = l2vpn_if_find(xl, lif->ifindex)) == NULL) { + if ((xf = l2vpn_if_find_name(xl, lif->ifname)) == NULL) { LIST_REMOVE(lif, entry); free(lif); } } LIST_FOREACH_SAFE(xf, &xl->if_list, entry, ftmp) { /* find new interfaces */ - if ((lif = l2vpn_if_find(l2vpn, xf->ifindex)) == NULL) { + if ((lif = l2vpn_if_find_name(l2vpn, xf->ifname)) == NULL) { LIST_REMOVE(xf, entry); LIST_INSERT_HEAD(&l2vpn->if_list, xf, entry); xf->l2vpn = l2vpn; @@ -1081,10 +1472,11 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) free(xf); } - /* merge pseudowires */ + /* merge active pseudowires */ + LIST_INIT(&pw_aux_list); LIST_FOREACH_SAFE(pw, &l2vpn->pw_list, entry, ptmp) { - /* find deleted pseudowires */ - if ((xp = l2vpn_pw_find(xl, pw->ifindex)) == NULL) { + /* find deleted active pseudowires */ + if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) { switch (ldpd_process) { case PROC_LDE_ENGINE: l2vpn_pw_exit(pw); @@ -1101,8 +1493,8 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) } } LIST_FOREACH_SAFE(xp, &xl->pw_list, entry, ptmp) { - /* find new pseudowires */ - if ((pw = l2vpn_pw_find(l2vpn, xp->ifindex)) == NULL) { + /* find new active pseudowires */ + if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) { LIST_REMOVE(xp, entry); LIST_INSERT_HEAD(&l2vpn->pw_list, xp, entry); xp->l2vpn = l2vpn; @@ -1120,7 +1512,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) continue; } - /* update existing pseudowire */ + /* update existing active pseudowire */ if (pw->af != xp->af || ldp_addrcmp(pw->af, &pw->addr, &xp->addr)) reinstall_tnbr = 1; @@ -1141,6 +1533,28 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) else reinstall_pwfec = 0; + /* check if the pseudowire should be disabled */ + if (xp->lsr_id.s_addr == INADDR_ANY || xp->pwid == 0) { + reinstall_tnbr = 0; + reset_nbr = 0; + reinstall_pwfec = 0; + + switch (ldpd_process) { + case PROC_LDE_ENGINE: + l2vpn_pw_exit(pw); + break; + case PROC_LDP_ENGINE: + ldpe_l2vpn_pw_exit(pw); + break; + case PROC_MAIN: + break; + } + + /* remove from active list */ + LIST_REMOVE(pw, entry); + LIST_INSERT_HEAD(&pw_aux_list, pw, entry); + } + if (ldpd_process == PROC_LDP_ENGINE) { if (reinstall_tnbr) ldpe_l2vpn_pw_exit(pw); @@ -1167,6 +1581,10 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) pw->flags |= F_PW_STATUSTLV_CONF; else pw->flags &= ~F_PW_STATUSTLV_CONF; + if (xp->flags & F_PW_STATIC_NBR_ADDR) + pw->flags |= F_PW_STATIC_NBR_ADDR; + else + pw->flags &= ~F_PW_STATIC_NBR_ADDR; if (ldpd_process == PROC_LDP_ENGINE && reinstall_tnbr) ldpe_l2vpn_pw_init(pw); if (ldpd_process == PROC_LDE_ENGINE && @@ -1182,6 +1600,60 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) free(xp); } + /* merge inactive pseudowires */ + LIST_FOREACH_SAFE(pw, &l2vpn->pw_inactive_list, entry, ptmp) { + /* find deleted inactive pseudowires */ + if ((xp = l2vpn_pw_find_name(xl, pw->ifname)) == NULL) { + LIST_REMOVE(pw, entry); + free(pw); + } + } + LIST_FOREACH_SAFE(xp, &xl->pw_inactive_list, entry, ptmp) { + /* find new inactive pseudowires */ + if ((pw = l2vpn_pw_find_name(l2vpn, xp->ifname)) == NULL) { + LIST_REMOVE(xp, entry); + LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, xp, entry); + xp->l2vpn = l2vpn; + continue; + } + + /* update existing inactive pseudowire */ + pw->lsr_id.s_addr = xp->lsr_id.s_addr; + pw->af = xp->af; + pw->addr = xp->addr; + pw->pwid = xp->pwid; + strlcpy(pw->ifname, xp->ifname, sizeof(pw->ifname)); + pw->ifindex = xp->ifindex; + pw->flags = xp->flags; + + /* check if the pseudowire should be activated */ + if (pw->lsr_id.s_addr != INADDR_ANY && pw->pwid != 0) { + /* remove from inactive list */ + LIST_REMOVE(pw, entry); + LIST_INSERT_HEAD(&l2vpn->pw_list, pw, entry); + + switch (ldpd_process) { + case PROC_LDE_ENGINE: + l2vpn_pw_init(pw); + break; + case PROC_LDP_ENGINE: + ldpe_l2vpn_pw_init(pw); + break; + case PROC_MAIN: + break; + } + } + + LIST_REMOVE(xp, entry); + free(xp); + } + + /* insert pseudowires that were disabled in the inactive list */ + LIST_FOREACH_SAFE(pw, &pw_aux_list, entry, ptmp) { + LIST_REMOVE(pw, entry); + LIST_INSERT_HEAD(&l2vpn->pw_inactive_list, pw, entry); + } + l2vpn->pw_type = xl->pw_type; l2vpn->mtu = xl->mtu; strlcpy(l2vpn->br_ifname, xl->br_ifname, sizeof(l2vpn->br_ifname)); diff --git a/ldpd/ldpd.conf.sample b/ldpd/ldpd.conf.sample new file mode 100644 index 000000000..49da35c28 --- /dev/null +++ b/ldpd/ldpd.conf.sample @@ -0,0 +1,46 @@ +! -*- ldp -*- +! +! LDPd sample configuration file +! +hostname ldpd +password zebra +log stdout +! +interface eth0 +! +interface eth1 +! +interface lo +! +mpls ldp + dual-stack cisco-interop + neighbor 10.0.1.5 password opensourcerouting + neighbor 172.16.0.1 password opensourcerouting + ! + address-family ipv4 + discovery transport-address 10.0.1.1 + label local advertise explicit-null + ! + interface eth0 + ! + interface eth1 + ! + ! + address-family ipv6 + discovery transport-address 2001:db8::1 + ! + interface eth1 + ! + ! +! +l2vpn ENG type vpls + bridge br0 + member interface eth2 + ! + member pseudowire mpw0 + neighbor lsr-id 1.1.1.1 + pw-id 100 + ! +! +line vty +! diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index d32d23c6c..9601f25f7 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -22,19 +22,14 @@ #ifndef _LDPD_H_ #define _LDPD_H_ -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/queue.h> -#include <sys/tree.h> -#include <net/if.h> -#include <netinet/in.h> -#include <event.h> -#include <imsg.h> +#include "openbsd-queue.h" +#include "openbsd-tree.h" +#include "imsg.h" +#include "thread.h" #include "ldp.h" #define CONF_FILE "/etc/ldpd.conf" -#define LDPD_SOCKET "/var/run/ldpd.sock" #define LDPD_USER "_ldpd" #define LDPD_OPT_VERBOSE 0x00000001 @@ -57,15 +52,18 @@ #define F_REDISTRIBUTED 0x0040 struct evbuf { - struct msgbuf wbuf; - struct event ev; + struct msgbuf wbuf; + struct thread *ev; + int (*handler)(struct thread *); + void *arg; }; struct imsgev { struct imsgbuf ibuf; - void (*handler)(int, short, void *); - struct event ev; - short events; + int (*handler_write)(struct thread *); + struct thread *ev_write; + int (*handler_read)(struct thread *); + struct thread *ev_read; }; enum imsg_type { @@ -73,7 +71,12 @@ enum imsg_type { IMSG_CTL_RELOAD, IMSG_CTL_SHOW_INTERFACE, IMSG_CTL_SHOW_DISCOVERY, + IMSG_CTL_SHOW_DISC_IFACE, + IMSG_CTL_SHOW_DISC_TNBR, + IMSG_CTL_SHOW_DISC_ADJ, IMSG_CTL_SHOW_NBR, + IMSG_CTL_SHOW_NBR_DISC, + IMSG_CTL_SHOW_NBR_END, IMSG_CTL_SHOW_LIB, IMSG_CTL_SHOW_L2VPN_PW, IMSG_CTL_SHOW_L2VPN_BINDING, @@ -92,6 +95,7 @@ enum imsg_type { IMSG_IFSTATUS, IMSG_NEWADDR, IMSG_DELADDR, + IMSG_RTRID_UPDATE, IMSG_LABEL_MAPPING, IMSG_LABEL_MAPPING_FULL, IMSG_LABEL_REQUEST, @@ -126,7 +130,10 @@ enum imsg_type { IMSG_RECONF_L2VPN, IMSG_RECONF_L2VPN_IF, IMSG_RECONF_L2VPN_PW, - IMSG_RECONF_END + IMSG_RECONF_L2VPN_IPW, + IMSG_RECONF_END, + IMSG_DEBUG_UPDATE, + IMSG_LOG }; union ldpd_addr { @@ -249,7 +256,7 @@ struct iface_af { int state; LIST_HEAD(, adj) adj_list; time_t uptime; - struct event hello_timer; + struct thread *hello_timer; uint16_t hello_holdtime; uint16_t hello_interval; }; @@ -261,9 +268,7 @@ struct iface { struct if_addr_head addr_list; struct in6_addr linklocal; enum iface_type type; - uint8_t if_type; uint16_t flags; - uint8_t linkstate; struct iface_af ipv4; struct iface_af ipv6; }; @@ -271,13 +276,11 @@ struct iface { /* source of targeted hellos */ struct tnbr { LIST_ENTRY(tnbr) entry; - struct event hello_timer; + struct thread *hello_timer; struct adj *adj; int af; union ldpd_addr addr; int state; - uint16_t hello_holdtime; - uint16_t hello_interval; uint16_t pw_count; uint8_t flags; }; @@ -313,7 +316,6 @@ struct l2vpn_if { char ifname[IF_NAMESIZE]; unsigned int ifindex; uint16_t flags; - uint8_t link_state; }; struct l2vpn_pw { @@ -335,6 +337,7 @@ struct l2vpn_pw { #define F_PW_CWORD_CONF 0x04 /* control word configured */ #define F_PW_CWORD 0x08 /* control word negotiated */ #define F_PW_STATUS_UP 0x10 /* pseudowire is operational */ +#define F_PW_STATIC_NBR_ADDR 0x20 /* static neighbor address configured */ struct l2vpn { LIST_ENTRY(l2vpn) entry; @@ -346,6 +349,7 @@ struct l2vpn { unsigned int br_ifindex; LIST_HEAD(, l2vpn_if) if_list; LIST_HEAD(, l2vpn_pw) pw_list; + LIST_HEAD(, l2vpn_pw) pw_inactive_list; }; #define L2VPN_TYPE_VPWS 1 #define L2VPN_TYPE_VPLS 2 @@ -370,6 +374,8 @@ enum hello_type { struct ldpd_af_conf { uint16_t keepalive; + uint16_t lhello_holdtime; + uint16_t lhello_interval; uint16_t thello_holdtime; uint16_t thello_interval; union ldpd_addr trans_addr; @@ -388,15 +394,20 @@ struct ldpd_conf { LIST_HEAD(, tnbr) tnbr_list; LIST_HEAD(, nbr_params) nbrp_list; LIST_HEAD(, l2vpn) l2vpn_list; + uint16_t lhello_holdtime; + uint16_t lhello_interval; + uint16_t thello_holdtime; + uint16_t thello_interval; uint16_t trans_pref; int flags; }; #define F_LDPD_NO_FIB_UPDATE 0x0001 #define F_LDPD_DS_CISCO_INTEROP 0x0002 +#define F_LDPD_ENABLED 0x0004 struct ldpd_af_global { - struct event disc_ev; - struct event edisc_ev; + struct thread *disc_ev; + struct thread *edisc_ev; int ldp_disc_socket; int ldp_edisc_socket; int ldp_session_socket; @@ -405,6 +416,7 @@ struct ldpd_af_global { struct ldpd_global { int cmd_opts; time_t uptime; + struct in_addr rtr_id; struct ldpd_af_global ipv4; struct ldpd_af_global ipv6; uint32_t conf_seqnum; @@ -451,10 +463,7 @@ struct kif { char ifname[IF_NAMESIZE]; unsigned short ifindex; int flags; - uint8_t link_state; int mtu; - uint8_t if_type; - uint64_t baudrate; }; /* control data structures */ @@ -464,15 +473,26 @@ struct ctl_iface { unsigned int ifindex; int state; uint16_t flags; - uint8_t linkstate; enum iface_type type; - uint8_t if_type; uint16_t hello_holdtime; uint16_t hello_interval; time_t uptime; uint16_t adj_cnt; }; +struct ctl_disc_if { + char name[IF_NAMESIZE]; + int active_v4; + int active_v6; + int no_adj; +}; + +struct ctl_disc_tnbr { + int af; + union ldpd_addr addr; + int no_adj; +}; + struct ctl_adj { int af; struct in_addr id; @@ -487,7 +507,10 @@ struct ctl_nbr { int af; struct in_addr id; union ldpd_addr laddr; + in_port_t lport; union ldpd_addr raddr; + in_port_t rport; + uint16_t holdtime; time_t uptime; int nbr_state; }; @@ -501,19 +524,23 @@ struct ctl_rt { uint32_t remote_label; uint8_t flags; uint8_t in_use; + int first; }; struct ctl_pw { uint16_t type; + char l2vpn_name[L2VPN_NAME_LEN]; char ifname[IF_NAMESIZE]; uint32_t pwid; struct in_addr lsr_id; uint32_t local_label; uint32_t local_gid; uint16_t local_ifmtu; + uint8_t local_cword; uint32_t remote_label; uint32_t remote_gid; uint16_t remote_ifmtu; + uint8_t remote_cword; uint32_t status; }; @@ -525,19 +552,9 @@ struct ldpd_conf *parse_config(char *); int cmdline_symset(char *); /* kroute.c */ -int kif_init(void); -int kr_init(int); void kif_redistribute(const char *); int kr_change(struct kroute *); int kr_delete(struct kroute *); -void kr_shutdown(void); -void kr_fib_couple(void); -void kr_fib_decouple(void); -void kr_change_egress_label(int, int); -void kr_show_route(struct imsg *); -void kr_ifinfo(char *, pid_t); -struct kif *kif_findname(char *); -void kif_clear(void); int kmpw_set(struct kpw *); int kmpw_unset(struct kpw *); @@ -561,31 +578,46 @@ void recoverscope(struct sockaddr_in6 *); void addscope(struct sockaddr_in6 *, uint32_t); void clearscope(struct in6_addr *); struct sockaddr *addr2sa(int af, union ldpd_addr *, uint16_t); -void sa2addr(struct sockaddr *, int *, union ldpd_addr *); +void sa2addr(struct sockaddr *, int *, union ldpd_addr *, + in_port_t *); +socklen_t sockaddr_len(struct sockaddr *); /* ldpd.c */ +int ldp_write_handler(struct thread *); void main_imsg_compose_ldpe(int, pid_t, void *, uint16_t); void main_imsg_compose_lde(int, pid_t, void *, uint16_t); +int main_imsg_compose_both(enum imsg_type, void *, + uint16_t); void imsg_event_add(struct imsgev *); -int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, pid_t, - int, void *, uint16_t); +int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, + pid_t, int, void *, uint16_t); void evbuf_enqueue(struct evbuf *, struct ibuf *); void evbuf_event_add(struct evbuf *); -void evbuf_init(struct evbuf *, int, void (*)(int, short, void *), void *); +void evbuf_init(struct evbuf *, int, + int (*)(struct thread *), void *); void evbuf_clear(struct evbuf *); struct ldpd_af_conf *ldp_af_conf_get(struct ldpd_conf *, int); struct ldpd_af_global *ldp_af_global_get(struct ldpd_global *, int); int ldp_is_dual_stack(struct ldpd_conf *); +in_addr_t ldp_rtr_id_get(struct ldpd_conf *); +int ldp_reload(struct ldpd_conf *); +struct ldpd_conf *ldp_dup_config(struct ldpd_conf *); +void ldp_clear_config(struct ldpd_conf *); void merge_config(struct ldpd_conf *, struct ldpd_conf *); struct ldpd_conf *config_new_empty(void); void config_clear(struct ldpd_conf *); /* socket.c */ int ldp_create_socket(int, enum socket_type); +void sock_set_nonblock(int); +void sock_set_cloexec(int); void sock_set_recvbuf(int); int sock_set_reuse(int, int); int sock_set_bindany(int, int); +int sock_set_md5sig(int, int, union ldpd_addr *, const char *); int sock_set_ipv4_tos(int, int); +int sock_set_ipv4_pktinfo(int, int); +int sock_set_ipv4_recvdstaddr(int, int); int sock_set_ipv4_recvif(int, int); int sock_set_ipv4_minttl(int, int); int sock_set_ipv4_ucast_ttl(int fd, int); @@ -600,7 +632,19 @@ int sock_set_ipv6_mcast_hops(int, int); int sock_set_ipv6_mcast(struct iface *); int sock_set_ipv6_mcast_loop(int); -/* printconf.c */ -void print_config(struct ldpd_conf *); +/* quagga */ +extern struct thread_master *master; + +/* ldp_zebra.c */ +void ldp_zebra_init(struct thread_master *); + +/* compatibility */ +#ifndef __OpenBSD__ +#define __IPV6_ADDR_MC_SCOPE(a) ((a)->s6_addr[1] & 0x0f) +#define __IPV6_ADDR_SCOPE_INTFACELOCAL 0x01 +#define IN6_IS_ADDR_MC_INTFACELOCAL(a) \ + (IN6_IS_ADDR_MULTICAST(a) && \ + (__IPV6_ADDR_MC_SCOPE(a) == __IPV6_ADDR_SCOPE_INTFACELOCAL)) +#endif #endif /* _LDPD_H_ */ diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 1b4d2a67e..aef33c8e3 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -19,70 +19,97 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <stdlib.h> -#include <signal.h> -#include <string.h> -#include <pwd.h> -#include <unistd.h> -#include <arpa/inet.h> -#include <errno.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "lde.h" #include "control.h" #include "log.h" - -static void ldpe_sig_handler(int, short, void *); -static __dead void ldpe_shutdown(void); -static void ldpe_dispatch_main(int, short, void *); -static void ldpe_dispatch_lde(int, short, void *); -static void ldpe_dispatch_pfkey(int, short, void *); +#include "ldp_debug.h" + +#include <lib/log.h> +#include "memory.h" +#include "privs.h" +#include "sigevent.h" + +static void ldpe_shutdown(void); +static int ldpe_dispatch_main(struct thread *); +static int ldpe_dispatch_lde(struct thread *); +#ifdef __OpenBSD__ +static int ldpe_dispatch_pfkey(struct thread *); +#endif static void ldpe_setup_sockets(int, int, int, int); static void ldpe_close_sockets(int); static void ldpe_iface_af_ctl(struct ctl_conn *, int, unsigned int); struct ldpd_conf *leconf; +#ifdef __OpenBSD__ struct ldpd_sysdep sysdep; +#endif static struct imsgev *iev_main; static struct imsgev *iev_lde; -static struct event pfkey_ev; +#ifdef __OpenBSD__ +static struct thread *pfkey_ev; +#endif -/* ARGSUSED */ +/* Master of threads. */ +struct thread_master *master; + +/* ldpe privileges */ +static zebra_capabilities_t _caps_p [] = +{ + ZCAP_BIND, + ZCAP_NET_ADMIN +}; + +struct zebra_privs_t ldpe_privs = +{ +#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP) + .user = QUAGGA_USER, + .group = QUAGGA_GROUP, +#endif +#if defined(VTY_GROUP) + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0 +}; + +/* SIGINT / SIGTERM handler. */ static void -ldpe_sig_handler(int sig, short event, void *bula) +sigint(void) { - switch (sig) { - case SIGINT: - case SIGTERM: - ldpe_shutdown(); - /* NOTREACHED */ - default: - fatalx("unexpected signal"); - } + ldpe_shutdown(); } +static struct quagga_signal_t ldpe_signals[] = +{ + { + .signal = SIGINT, + .handler = &sigint, + }, + { + .signal = SIGTERM, + .handler = &sigint, + }, +}; + /* label distribution protocol engine */ void -ldpe(int debug, int verbose) +ldpe(const char *user, const char *group) { - struct passwd *pw; - struct event ev_sigint, ev_sigterm; + struct thread thread; leconf = config_new_empty(); - log_init(debug); - log_verbose(verbose); - +#ifdef HAVE_SETPROCTITLE setproctitle("ldp engine"); +#endif ldpd_process = PROC_LDP_ENGINE; - /* create ldpd control socket outside chroot */ - if (control_init() == -1) - fatalx("control socket setup failed"); - LIST_INIT(&global.addr_list); LIST_INIT(&global.adj_list); TAILQ_INIT(&global.pending_conns); @@ -90,50 +117,46 @@ ldpe(int debug, int verbose) fatal("inet_pton"); if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) fatal("inet_pton"); +#ifdef __OpenBSD__ global.pfkeysock = pfkey_init(); +#endif - if ((pw = getpwnam(LDPD_USER)) == NULL) - fatal("getpwnam"); - - if (chroot(pw->pw_dir) == -1) - fatal("chroot"); - if (chdir("/") == -1) - fatal("chdir(\"/\")"); + /* drop privileges */ + if (user) + ldpe_privs.user = user; + if (group) + ldpe_privs.group = group; + zprivs_init(&ldpe_privs); - if (setgroups(1, &pw->pw_gid) || - setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || - setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) - fatal("can't drop privileges"); + if (control_init() == -1) + fatalx("control socket setup failed"); +#ifdef HAVE_PLEDGE if (pledge("stdio cpath inet mcast recvfd", NULL) == -1) fatal("pledge"); +#endif - event_init(); + master = thread_master_create(); accept_init(); /* setup signal handler */ - signal_set(&ev_sigint, SIGINT, ldpe_sig_handler, NULL); - signal_set(&ev_sigterm, SIGTERM, ldpe_sig_handler, NULL); - signal_add(&ev_sigint, NULL); - signal_add(&ev_sigterm, NULL); - signal(SIGPIPE, SIG_IGN); - signal(SIGHUP, SIG_IGN); + signal_init(master, array_size(ldpe_signals), ldpe_signals); /* setup pipe and event handler to the parent process */ if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) fatal(NULL); imsg_init(&iev_main->ibuf, 3); - iev_main->handler = ldpe_dispatch_main; - iev_main->events = EV_READ; - event_set(&iev_main->ev, iev_main->ibuf.fd, iev_main->events, - iev_main->handler, iev_main); - event_add(&iev_main->ev, NULL); - - if (sysdep.no_pfkey == 0) { - event_set(&pfkey_ev, global.pfkeysock, EV_READ | EV_PERSIST, - ldpe_dispatch_pfkey, NULL); - event_add(&pfkey_ev, NULL); - } + iev_main->handler_read = ldpe_dispatch_main; + iev_main->ev_read = thread_add_read(master, iev_main->handler_read, + iev_main, iev_main->ibuf.fd); + iev_main->handler_write = ldp_write_handler; + iev_main->ev_write = NULL; + +#ifdef __OpenBSD__ + if (sysdep.no_pfkey == 0) + pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, + NULL, global.pfkeysock); +#endif /* mark sockets as closed */ global.ipv4.ldp_disc_socket = -1; @@ -150,12 +173,12 @@ ldpe(int debug, int verbose) if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL) fatal(__func__); - event_dispatch(); - - ldpe_shutdown(); + /* Fetch next active thread. */ + while (thread_fetch(master, &thread)) + thread_call(&thread); } -static __dead void +static void ldpe_shutdown(void) { struct if_addr *if_addr; @@ -172,10 +195,12 @@ ldpe_shutdown(void) control_cleanup(); config_clear(leconf); +#ifdef __OpenBSD__ if (sysdep.no_pfkey == 0) { - event_del(&pfkey_ev); + THREAD_READ_OFF(pfkey_ev); close(global.pfkeysock); } +#endif ldpe_close_sockets(AF_INET); ldpe_close_sockets(AF_INET6); @@ -212,8 +237,8 @@ ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data, } /* ARGSUSED */ -static void -ldpe_dispatch_main(int fd, short event, void *bula) +static int +ldpe_dispatch_main(struct thread *thread) { static struct ldpd_conf *nconf; struct iface *niface; @@ -223,7 +248,8 @@ ldpe_dispatch_main(int fd, short event, void *bula) struct l2vpn_if *nlif; struct l2vpn_pw *npw; struct imsg imsg; - struct imsgev *iev = bula; + int fd = THREAD_FD(thread); + struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; struct iface *iface = NULL; struct kif *kif; @@ -233,21 +259,17 @@ ldpe_dispatch_main(int fd, short event, void *bula) static int edisc_socket = -1; static int session_socket = -1; struct nbr *nbr; +#ifdef __OpenBSD__ struct nbr_params *nbrp; +#endif int n, shut = 0; - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* connection closed */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("ldpe_dispatch_main: msgbuf_write"); - if (n == 0) - shut = 1; - } + iev->ev_read = NULL; + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + shut = 1; for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -262,12 +284,11 @@ ldpe_dispatch_main(int fd, short event, void *bula) fatalx("IFSTATUS imsg with wrong len"); kif = imsg.data; - iface = if_lookup(leconf, kif->ifindex); + iface = if_lookup_name(leconf, kif->ifname); if (!iface) break; - iface->flags = kif->flags; - iface->linkstate = kif->link_state; + if_update_info(iface, kif); if_update(iface, AF_UNSPEC); break; case IMSG_NEWADDR: @@ -299,11 +320,11 @@ ldpe_dispatch_main(int fd, short event, void *bula) if ((iev_lde = malloc(sizeof(struct imsgev))) == NULL) fatal(NULL); imsg_init(&iev_lde->ibuf, fd); - iev_lde->handler = ldpe_dispatch_lde; - iev_lde->events = EV_READ; - event_set(&iev_lde->ev, iev_lde->ibuf.fd, - iev_lde->events, iev_lde->handler, iev_lde); - event_add(&iev_lde->ev, NULL); + iev_lde->handler_read = ldpe_dispatch_lde; + iev_lde->ev_read = thread_add_read(master, + iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd); + iev_lde->handler_write = ldp_write_handler; + iev_lde->ev_write = NULL; break; case IMSG_CLOSE_SOCKETS: af = imsg.hdr.peerid; @@ -312,7 +333,9 @@ ldpe_dispatch_main(int fd, short event, void *bula) if (nbr->af != af) continue; session_shutdown(nbr, S_SHUTDOWN, 0, 0); +#ifdef __OpenBSD__ pfkey_remove(nbr); +#endif } ldpe_close_sockets(af); if_update_all(af); @@ -366,13 +389,25 @@ ldpe_dispatch_main(int fd, short event, void *bula) continue; nbr->laddr = (ldp_af_conf_get(leconf, af))->trans_addr; +#ifdef __OpenBSD__ nbrp = nbr_params_find(leconf, nbr->id); if (nbrp && pfkey_establish(nbr, nbrp) == -1) fatalx("pfkey setup failed"); +#endif if (nbr_session_active_role(nbr)) nbr_establish_connection(nbr); } break; + case IMSG_RTRID_UPDATE: + memcpy(&global.rtr_id, imsg.data, + sizeof(global.rtr_id)); + if (leconf->rtr_id.s_addr == INADDR_ANY) { + ldpe_reset_nbrs(AF_INET); + ldpe_reset_nbrs(AF_INET6); + } + if_update_all(AF_UNSPEC); + tnbr_update_all(AF_UNSPEC); + break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL) @@ -418,6 +453,7 @@ ldpe_dispatch_main(int fd, short event, void *bula) LIST_INIT(&nl2vpn->if_list); LIST_INIT(&nl2vpn->pw_list); + LIST_INIT(&nl2vpn->pw_inactive_list); LIST_INSERT_HEAD(&nconf->l2vpn_list, nl2vpn, entry); break; @@ -437,17 +473,30 @@ ldpe_dispatch_main(int fd, short event, void *bula) npw->l2vpn = nl2vpn; LIST_INSERT_HEAD(&nl2vpn->pw_list, npw, entry); break; + case IMSG_RECONF_L2VPN_IPW: + if ((npw = malloc(sizeof(struct l2vpn_pw))) == NULL) + fatal(NULL); + memcpy(npw, imsg.data, sizeof(struct l2vpn_pw)); + + npw->l2vpn = nl2vpn; + LIST_INSERT_HEAD(&nl2vpn->pw_inactive_list, npw, entry); + break; case IMSG_RECONF_END: merge_config(leconf, nconf); nconf = NULL; global.conf_seqnum++; break; - case IMSG_CTL_KROUTE: - case IMSG_CTL_KROUTE_ADDR: - case IMSG_CTL_IFINFO: case IMSG_CTL_END: control_imsg_relay(&imsg); break; + case IMSG_DEBUG_UPDATE: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(ldp_debug)) { + log_warnx("%s: wrong imsg len", __func__); + break; + } + memcpy(&ldp_debug, imsg.data, sizeof(ldp_debug)); + break; default: log_debug("ldpe_dispatch_main: error handling imsg %d", imsg.hdr.type); @@ -458,17 +507,20 @@ ldpe_dispatch_main(int fd, short event, void *bula) if (!shut) imsg_event_add(iev); else { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + /* this pipe is dead, so remove the event handlers and exit */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + ldpe_shutdown(); } + + return (0); } /* ARGSUSED */ -static void -ldpe_dispatch_lde(int fd, short event, void *bula) +static int +ldpe_dispatch_lde(struct thread *thread) { - struct imsgev *iev = bula; + struct imsgev *iev = THREAD_ARG(thread); struct imsgbuf *ibuf = &iev->ibuf; struct imsg imsg; struct map map; @@ -476,18 +528,12 @@ ldpe_dispatch_lde(int fd, short event, void *bula) int n, shut = 0; struct nbr *nbr = NULL; - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) - fatal("imsg_read error"); - if (n == 0) /* connection closed */ - shut = 1; - } - if (event & EV_WRITE) { - if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN) - fatal("ldpe_dispatch_lde: msgbuf_write"); - if (n == 0) - shut = 1; - } + iev->ev_read = NULL; + + if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) + fatal("imsg_read error"); + if (n == 0) /* connection closed */ + shut = 1; for (;;) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -592,22 +638,31 @@ ldpe_dispatch_lde(int fd, short event, void *bula) if (!shut) imsg_event_add(iev); else { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + /* this pipe is dead, so remove the event handlers and exit */ + THREAD_READ_OFF(iev->ev_read); + THREAD_WRITE_OFF(iev->ev_write); + ldpe_shutdown(); } + + return (0); } +#ifdef __OpenBSD__ /* ARGSUSED */ -static void -ldpe_dispatch_pfkey(int fd, short event, void *bula) +static int +ldpe_dispatch_pfkey(struct thread *thread) { - if (event & EV_READ) { - if (pfkey_read(fd, NULL) == -1) { - fatal("pfkey_read failed, exiting..."); - } - } + int fd = THREAD_FD(thread); + + pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, + NULL, global.pfkeysock); + + if (pfkey_read(fd, NULL) == -1) + fatal("pfkey_read failed, exiting..."); + + return (0); } +#endif /* __OpenBSD__ */ static void ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, @@ -619,15 +674,13 @@ ldpe_setup_sockets(int af, int disc_socket, int edisc_socket, /* discovery socket */ af_global->ldp_disc_socket = disc_socket; - event_set(&af_global->disc_ev, af_global->ldp_disc_socket, - EV_READ|EV_PERSIST, disc_recv_packet, NULL); - event_add(&af_global->disc_ev, NULL); + af_global->disc_ev = thread_add_read(master, disc_recv_packet, + &af_global->disc_ev, af_global->ldp_disc_socket); /* extended discovery socket */ af_global->ldp_edisc_socket = edisc_socket; - event_set(&af_global->edisc_ev, af_global->ldp_edisc_socket, - EV_READ|EV_PERSIST, disc_recv_packet, NULL); - event_add(&af_global->edisc_ev, NULL); + af_global->edisc_ev = thread_add_read(master, disc_recv_packet, + &af_global->edisc_ev, af_global->ldp_edisc_socket); /* session socket */ af_global->ldp_session_socket = session_socket; @@ -642,16 +695,14 @@ ldpe_close_sockets(int af) af_global = ldp_af_global_get(&global, af); /* discovery socket */ - if (event_initialized(&af_global->disc_ev)) - event_del(&af_global->disc_ev); + THREAD_READ_OFF(af_global->disc_ev); if (af_global->ldp_disc_socket != -1) { close(af_global->ldp_disc_socket); af_global->ldp_disc_socket = -1; } /* extended discovery socket */ - if (event_initialized(&af_global->edisc_ev)) - event_del(&af_global->edisc_ev); + THREAD_READ_OFF(af_global->edisc_ev); if (af_global->ldp_edisc_socket != -1) { close(af_global->ldp_edisc_socket); af_global->ldp_edisc_socket = -1; @@ -745,24 +796,57 @@ ldpe_iface_ctl(struct ctl_conn *c, unsigned int idx) void ldpe_adj_ctl(struct ctl_conn *c) { - struct nbr *nbr; - struct adj *adj; - struct ctl_adj *actl; + struct iface *iface; + struct tnbr *tnbr; + struct adj *adj; + struct ctl_adj *actl; + struct ctl_disc_if ictl; + struct ctl_disc_tnbr tctl; - RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { - LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0); + + LIST_FOREACH(iface, &leconf->iface_list, entry) { + memset(&ictl, 0, sizeof(ictl)); + ictl.active_v4 = (iface->ipv4.state == IF_STA_ACTIVE); + ictl.active_v6 = (iface->ipv6.state == IF_STA_ACTIVE); + + if (!ictl.active_v4 && !ictl.active_v6) + continue; + + strlcpy(ictl.name, iface->name, sizeof(ictl.name)); + if (LIST_EMPTY(&iface->ipv4.adj_list) && + LIST_EMPTY(&iface->ipv6.adj_list)) + ictl.no_adj = 1; + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_IFACE, 0, 0, + -1, &ictl, sizeof(ictl)); + + LIST_FOREACH(adj, &iface->ipv4.adj_list, ia_entry) { actl = adj_to_ctl(adj); - imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, + 0, 0, -1, actl, sizeof(struct ctl_adj)); + } + LIST_FOREACH(adj, &iface->ipv6.adj_list, ia_entry) { + actl = adj_to_ctl(adj); + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, 0, 0, -1, actl, sizeof(struct ctl_adj)); } } - /* show adjacencies not associated with any neighbor */ - LIST_FOREACH(adj, &global.adj_list, global_entry) { - if (adj->nbr != NULL) + + LIST_FOREACH(tnbr, &leconf->tnbr_list, entry) { + memset(&tctl, 0, sizeof(tctl)); + tctl.af = tnbr->af; + tctl.addr = tnbr->addr; + if (tnbr->adj == NULL) + tctl.no_adj = 1; + + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_TNBR, 0, 0, + -1, &tctl, sizeof(tctl)); + + if (tnbr->adj == NULL) continue; - actl = adj_to_ctl(adj); - imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISCOVERY, 0, 0, + actl = adj_to_ctl(tnbr->adj); + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_DISC_ADJ, 0, 0, -1, actl, sizeof(struct ctl_adj)); } @@ -772,13 +856,27 @@ ldpe_adj_ctl(struct ctl_conn *c) void ldpe_nbr_ctl(struct ctl_conn *c) { + struct adj *adj; + struct ctl_adj *actl; struct nbr *nbr; struct ctl_nbr *nctl; RB_FOREACH(nbr, nbr_addr_head, &nbrs_by_addr) { + if (nbr->state == NBR_STA_PRESENT) + continue; + nctl = nbr_to_ctl(nbr); imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR, 0, 0, -1, nctl, sizeof(struct ctl_nbr)); + + LIST_FOREACH(adj, &nbr->adj_list, nbr_entry) { + actl = adj_to_ctl(adj); + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_DISC, + 0, 0, -1, actl, sizeof(struct ctl_adj)); + } + + imsg_compose_event(&c->iev, IMSG_CTL_SHOW_NBR_END, 0, 0, -1, + NULL, 0); } imsg_compose_event(&c->iev, IMSG_CTL_END, 0, 0, -1, NULL, 0); } diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index e640dd67d..aab1a7fd9 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -21,10 +21,11 @@ #ifndef _LDPE_H_ #define _LDPE_H_ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/tree.h> +#include "openbsd-queue.h" +#include "openbsd-tree.h" +#ifdef __OpenBSD__ #include <net/pfkeyv2.h> +#endif #include "ldpd.h" @@ -48,7 +49,7 @@ struct adj { struct nbr *nbr; int ds_tlv; struct hello_source source; - struct event inactivity_timer; + struct thread *inactivity_timer; uint16_t holdtime; union ldpd_addr trans_addr; }; @@ -58,18 +59,20 @@ struct tcp_conn { int fd; struct ibuf_read *rbuf; struct evbuf wbuf; - struct event rev; + struct thread *rev; + in_port_t lport; + in_port_t rport; }; struct nbr { RB_ENTRY(nbr) id_tree, addr_tree, pid_tree; struct tcp_conn *tcp; LIST_HEAD(, adj) adj_list; /* adjacencies */ - struct event ev_connect; - struct event keepalive_timer; - struct event keepalive_timeout; - struct event init_timeout; - struct event initdelay_timer; + struct thread *ev_connect; + struct thread *keepalive_timer; + struct thread *keepalive_timeout; + struct thread *init_timeout; + struct thread *initdelay_timer; struct mapping_head mapping_list; struct mapping_head withdraw_list; @@ -117,7 +120,7 @@ struct pending_conn { int fd; int af; union ldpd_addr addr; - struct event ev_timeout; + struct thread *ev_timeout; }; #define PENDING_CONN_TIMEOUT 5 @@ -139,7 +142,7 @@ extern struct nbr_pid_head nbrs_by_pid; /* accept.c */ void accept_init(void); -int accept_add(int, void (*)(int, short, void *), void *); +int accept_add(int, int (*)(struct thread *), void *); void accept_del(int); void accept_pause(void); void accept_unpause(void); @@ -180,7 +183,7 @@ int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, uint16_t, struct map *); /* ldpe.c */ -void ldpe(int, int); +void ldpe(const char *, const char *); int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t); int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, @@ -200,11 +203,15 @@ void mapping_list_clr(struct mapping_head *); struct iface *if_new(struct kif *); void if_exit(struct iface *); struct iface *if_lookup(struct ldpd_conf *, unsigned short); +struct iface *if_lookup_name(struct ldpd_conf *, const char *); +void if_update_info(struct iface *, struct kif *); struct iface_af *iface_af_get(struct iface *, int); void if_addr_add(struct kaddr *); void if_addr_del(struct kaddr *); void if_update(struct iface *, int); void if_update_all(int); +uint16_t if_get_hello_holdtime(struct iface_af *); +uint16_t if_get_hello_interval(struct iface_af *); struct ctl_iface *if_to_ctl(struct iface_af *); in_addr_t if_get_ipv4_addr(struct iface *); @@ -216,11 +223,13 @@ struct adj *adj_find(struct hello_source *); int adj_get_af(struct adj *adj); void adj_start_itimer(struct adj *); void adj_stop_itimer(struct adj *); -struct tnbr *tnbr_new(struct ldpd_conf *, int, union ldpd_addr *); +struct tnbr *tnbr_new(int, union ldpd_addr *); struct tnbr *tnbr_find(struct ldpd_conf *, int, union ldpd_addr *); struct tnbr *tnbr_check(struct tnbr *); void tnbr_update(struct tnbr *); void tnbr_update_all(int); +uint16_t tnbr_get_hello_holdtime(struct tnbr *); +uint16_t tnbr_get_hello_interval(struct tnbr *); struct ctl_adj *adj_to_ctl(struct adj *); /* neighbor.c */ @@ -255,8 +264,8 @@ int gen_ldp_hdr(struct ibuf *, uint16_t); int gen_msg_hdr(struct ibuf *, uint16_t, uint16_t); int send_packet(int, int, union ldpd_addr *, struct iface_af *, void *, size_t); -void disc_recv_packet(int, short, void *); -void session_accept(int, short, void *); +int disc_recv_packet(struct thread *); +int session_accept(struct thread *); void session_accept_nbr(struct nbr *, int); void session_shutdown(struct nbr *, uint32_t, uint32_t, uint32_t); @@ -268,10 +277,12 @@ struct pending_conn *pending_conn_find(int, union ldpd_addr *); char *pkt_ptr; /* packet buffer */ /* pfkey.c */ +#ifdef __OpenBSD__ int pfkey_read(int, struct sadb_msg *); int pfkey_establish(struct nbr *, struct nbr_params *); int pfkey_remove(struct nbr *); int pfkey_init(void); +#endif /* l2vpn.c */ void ldpe_l2vpn_init(struct l2vpn *); diff --git a/ldpd/log.c b/ldpd/log.c index e14b6e51e..77efdb471 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -16,53 +16,23 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> -#include <netmpls/mpls.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.h> -#include <unistd.h> -#include <netdb.h> -#include <limits.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "lde.h" #include "log.h" +#include <lib/log.h> +#include "mpls.h" + static const char * const procnames[] = { "parent", "ldpe", "lde" }; -static void vlog(int, const char *, va_list); - -static int debug; -static int verbose; - -void -log_init(int n_debug) -{ - extern char *__progname; - - debug = n_debug; - - if (!debug) - openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON); - - tzset(); -} - -void -log_verbose(int v) -{ - verbose = v; -} +void vlog(int, const char *, va_list); void logit(int pri, const char *fmt, ...) @@ -74,23 +44,24 @@ logit(int pri, const char *fmt, ...) va_end(ap); } -static void +void vlog(int pri, const char *fmt, va_list ap) { - char *nfmt; + char buf[1024]; - if (debug) { - /* best effort in out of mem situations */ - if (asprintf(&nfmt, "%s\n", fmt) == -1) { - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - } else { - vfprintf(stderr, nfmt, ap); - free(nfmt); - } - fflush(stderr); - } else - vsyslog(pri, fmt, ap); + switch (ldpd_process) { + case PROC_LDE_ENGINE: + vsnprintf(buf, sizeof(buf), fmt, ap); + lde_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1); + break; + case PROC_LDP_ENGINE: + vsnprintf(buf, sizeof(buf), fmt, ap); + ldpe_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1); + break; + case PROC_MAIN: + vzlog(NULL, pri, fmt, ap); + break; + } } void @@ -138,15 +109,23 @@ log_info(const char *emsg, ...) } void +log_notice(const char *emsg, ...) +{ + va_list ap; + + va_start(ap, emsg); + vlog(LOG_NOTICE, emsg, ap); + va_end(ap); +} + +void log_debug(const char *emsg, ...) { va_list ap; - if (verbose & LDPD_OPT_VERBOSE) { - va_start(ap, emsg); - vlog(LOG_DEBUG, emsg, ap); - va_end(ap); - } + va_start(ap, emsg); + vlog(LOG_DEBUG, emsg, ap); + va_end(ap); } void @@ -183,7 +162,7 @@ log_sockaddr(void *vp) round = (round + 1) % NUM_LOGS; - if (getnameinfo(sa, sa->sa_len, buf[round], NI_MAXHOST, NULL, 0, + if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0, NI_NUMERICHOST)) return ("(unknown)"); else @@ -196,7 +175,9 @@ log_in6addr(const struct in6_addr *addr) struct sockaddr_in6 sa_in6; memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_in6.sin6_len = sizeof(sa_in6); +#endif sa_in6.sin6_family = AF_INET6; sa_in6.sin6_addr = *addr; @@ -211,7 +192,9 @@ log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex) struct sockaddr_in6 sa_in6; memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_in6.sin6_len = sizeof(sa_in6); +#endif sa_in6.sin6_family = AF_INET6; sa_in6.sin6_addr = *addr; @@ -275,6 +258,39 @@ log_label(uint32_t label) return (buf); } +const char * +log_time(time_t t) +{ + char *buf; + static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ + static int idx = 0; + unsigned int sec, min, hrs, day, week; + + buf = tfbuf[idx++]; + if (idx == TF_BUFS) + idx = 0; + + week = t; + + sec = week % 60; + week /= 60; + min = week % 60; + week /= 60; + hrs = week % 24; + week /= 24; + day = week % 7; + week /= 7; + + if (week > 0) + snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs); + else if (day > 0) + snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); + else + snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); + + return (buf); +} + char * log_hello_src(const struct hello_source *src) { @@ -365,8 +381,10 @@ af_name(int af) return ("ipv4"); case AF_INET6: return ("ipv6"); +#ifdef AF_MPLS case AF_MPLS: return ("mpls"); +#endif default: return ("UNKNOWN"); } @@ -564,37 +582,3 @@ pw_type_name(uint16_t pw_type) return (buf); } } - -static char *msgtypes[] = { - "", - "RTM_ADD: Add Route", - "RTM_DELETE: Delete Route", - "RTM_CHANGE: Change Metrics or flags", - "RTM_GET: Report Metrics", - "RTM_LOSING: Kernel Suspects Partitioning", - "RTM_REDIRECT: Told to use different route", - "RTM_MISS: Lookup failed on this address", - "RTM_LOCK: fix specified metrics", - "RTM_OLDADD: caused by SIOCADDRT", - "RTM_OLDDEL: caused by SIOCDELRT", - "RTM_RESOLVE: Route created by cloning", - "RTM_NEWADDR: address being added to iface", - "RTM_DELADDR: address being removed from iface", - "RTM_IFINFO: iface status change", - "RTM_IFANNOUNCE: iface arrival/departure", - "RTM_DESYNC: route socket overflow", -}; - -void -log_rtmsg(unsigned char rtm_type) -{ - if (!(verbose & LDPD_OPT_VERBOSE2)) - return; - - if (rtm_type > 0 && - rtm_type < sizeof(msgtypes)/sizeof(msgtypes[0])) - log_debug("kernel message: %s", msgtypes[rtm_type]); - else - log_debug("kernel message: rtm_type %d out of range", - rtm_type); -} diff --git a/ldpd/log.h b/ldpd/log.h index 94c463041..4d6da43ca 100644 --- a/ldpd/log.h +++ b/ldpd/log.h @@ -26,8 +26,6 @@ union ldpd_addr; struct hello_source; struct fec; -void log_init(int); -void log_verbose(int); void logit(int, const char *, ...) __attribute__((__format__ (printf, 2, 3))); void log_warn(const char *, ...) @@ -36,17 +34,22 @@ void log_warnx(const char *, ...) __attribute__((__format__ (printf, 1, 2))); void log_info(const char *, ...) __attribute__((__format__ (printf, 1, 2))); +void log_notice(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); void log_debug(const char *, ...) __attribute__((__format__ (printf, 1, 2))); -void fatal(const char *) __dead +void fatal(const char *) + __attribute__ ((noreturn)) __attribute__((__format__ (printf, 1, 0))); -void fatalx(const char *) __dead +void fatalx(const char *) + __attribute__ ((noreturn)) __attribute__((__format__ (printf, 1, 0))); const char *log_sockaddr(void *); const char *log_in6addr(const struct in6_addr *); const char *log_in6addr_scope(const struct in6_addr *, unsigned int); const char *log_addr(int, const union ldpd_addr *); char *log_label(uint32_t); +const char *log_time(time_t); char *log_hello_src(const struct hello_source *); const char *log_map(const struct map *); const char *log_fec(const struct fec *); @@ -58,6 +61,5 @@ const char *if_type_name(enum iface_type); const char *msg_name(uint16_t); const char *status_code_name(uint32_t); const char *pw_type_name(uint16_t); -void log_rtmsg(unsigned char); #endif /* _LOG_H_ */ diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c index d3f83734f..8376a0154 100644 --- a/ldpd/neighbor.c +++ b/ldpd/neighbor.c @@ -19,14 +19,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/time.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" @@ -37,13 +30,13 @@ static __inline int nbr_id_compare(struct nbr *, struct nbr *); static __inline int nbr_addr_compare(struct nbr *, struct nbr *); static __inline int nbr_pid_compare(struct nbr *, struct nbr *); static void nbr_update_peerid(struct nbr *); -static void nbr_ktimer(int, short, void *); +static int nbr_ktimer(struct thread *); static void nbr_start_ktimer(struct nbr *); -static void nbr_ktimeout(int, short, void *); +static int nbr_ktimeout(struct thread *); static void nbr_start_ktimeout(struct nbr *); -static void nbr_itimeout(int, short, void *); +static int nbr_itimeout(struct thread *); static void nbr_start_itimeout(struct nbr *); -static void nbr_idtimer(int, short, void *); +static int nbr_idtimer(struct thread *); static int nbr_act_session_operational(struct nbr *); static void nbr_send_labelmappings(struct nbr *); @@ -266,15 +259,17 @@ nbr_new(struct in_addr id, int af, int ds_tlv, union ldpd_addr *addr, TAILQ_INIT(&nbr->release_list); TAILQ_INIT(&nbr->abortreq_list); - /* set event structures */ - evtimer_set(&nbr->keepalive_timeout, nbr_ktimeout, nbr); - evtimer_set(&nbr->keepalive_timer, nbr_ktimer, nbr); - evtimer_set(&nbr->init_timeout, nbr_itimeout, nbr); - evtimer_set(&nbr->initdelay_timer, nbr_idtimer, nbr); - nbrp = nbr_params_find(leconf, nbr->id); - if (nbrp && pfkey_establish(nbr, nbrp) == -1) - fatalx("pfkey setup failed"); + if (nbrp) { +#ifdef __OpenBSD__ + if (pfkey_establish(nbr, nbrp) == -1) + fatalx("pfkey setup failed"); +#else + sock_set_md5sig( + (ldp_af_global_get(&global, nbr->af))->ldp_session_socket, + nbr->af, &nbr->raddr, nbrp->auth.md5key); +#endif + } pconn = pending_conn_find(nbr->af, &nbr->raddr); if (pconn) { @@ -291,10 +286,16 @@ nbr_del(struct nbr *nbr) log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); +#ifdef __OpenBSD__ pfkey_remove(nbr); +#else + sock_set_md5sig( + (ldp_af_global_get(&global, nbr->af))->ldp_session_socket, + nbr->af, &nbr->raddr, NULL); +#endif if (nbr_pending_connect(nbr)) - event_del(&nbr->ev_connect); + THREAD_WRITE_OFF(nbr->ev_connect); nbr_stop_ktimer(nbr); nbr_stop_ktimeout(nbr); nbr_stop_itimeout(nbr); @@ -382,176 +383,168 @@ nbr_session_active_role(struct nbr *nbr) /* Keepalive timer: timer to send keepalive message to neighbors */ -static void -nbr_ktimer(int fd, short event, void *arg) +static int +nbr_ktimer(struct thread *thread) { - struct nbr *nbr = arg; + struct nbr *nbr = THREAD_ARG(thread); + nbr->keepalive_timer = NULL; send_keepalive(nbr); nbr_start_ktimer(nbr); + + return (0); } static void nbr_start_ktimer(struct nbr *nbr) { - struct timeval tv; + int secs; /* send three keepalives per period */ - timerclear(&tv); - tv.tv_sec = (time_t)(nbr->keepalive / KEEPALIVE_PER_PERIOD); - if (evtimer_add(&nbr->keepalive_timer, &tv) == -1) - fatal(__func__); + secs = nbr->keepalive / KEEPALIVE_PER_PERIOD; + THREAD_TIMER_OFF(nbr->keepalive_timer); + nbr->keepalive_timer = thread_add_timer(master, nbr_ktimer, nbr, secs); } void nbr_stop_ktimer(struct nbr *nbr) { - if (evtimer_pending(&nbr->keepalive_timer, NULL) && - evtimer_del(&nbr->keepalive_timer) == -1) - fatal(__func__); + THREAD_TIMER_OFF(nbr->keepalive_timer); } /* Keepalive timeout: if the nbr hasn't sent keepalive */ -static void -nbr_ktimeout(int fd, short event, void *arg) +static int +nbr_ktimeout(struct thread *thread) { - struct nbr *nbr = arg; + struct nbr *nbr = THREAD_ARG(thread); + + nbr->keepalive_timeout = NULL; log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); session_shutdown(nbr, S_KEEPALIVE_TMR, 0, 0); + + return (0); } static void nbr_start_ktimeout(struct nbr *nbr) { - struct timeval tv; - - timerclear(&tv); - tv.tv_sec = nbr->keepalive; - - if (evtimer_add(&nbr->keepalive_timeout, &tv) == -1) - fatal(__func__); + THREAD_TIMER_OFF(nbr->keepalive_timeout); + nbr->keepalive_timeout = thread_add_timer(master, nbr_ktimeout, nbr, + nbr->keepalive); } void nbr_stop_ktimeout(struct nbr *nbr) { - if (evtimer_pending(&nbr->keepalive_timeout, NULL) && - evtimer_del(&nbr->keepalive_timeout) == -1) - fatal(__func__); + THREAD_TIMER_OFF(nbr->keepalive_timeout); } /* Session initialization timeout: if nbr got stuck in the initialization FSM */ -static void -nbr_itimeout(int fd, short event, void *arg) +static int +nbr_itimeout(struct thread *thread) { - struct nbr *nbr = arg; + struct nbr *nbr = THREAD_ARG(thread); log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); + + return (0); } static void nbr_start_itimeout(struct nbr *nbr) { - struct timeval tv; + int secs; - timerclear(&tv); - tv.tv_sec = INIT_FSM_TIMEOUT; - if (evtimer_add(&nbr->init_timeout, &tv) == -1) - fatal(__func__); + secs = INIT_FSM_TIMEOUT; + THREAD_TIMER_OFF(nbr->init_timeout); + nbr->init_timeout = thread_add_timer(master, nbr_itimeout, nbr, secs); } void nbr_stop_itimeout(struct nbr *nbr) { - if (evtimer_pending(&nbr->init_timeout, NULL) && - evtimer_del(&nbr->init_timeout) == -1) - fatal(__func__); + THREAD_TIMER_OFF(nbr->init_timeout); } /* Init delay timer: timer to retry to iniziatize session */ -static void -nbr_idtimer(int fd, short event, void *arg) +static int +nbr_idtimer(struct thread *thread) { - struct nbr *nbr = arg; + struct nbr *nbr = THREAD_ARG(thread); + + nbr->initdelay_timer = NULL; log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); nbr_establish_connection(nbr); + + return (0); } void nbr_start_idtimer(struct nbr *nbr) { - struct timeval tv; - - timerclear(&tv); + int secs; - tv.tv_sec = INIT_DELAY_TMR; + secs = INIT_DELAY_TMR; switch(nbr->idtimer_cnt) { default: /* do not further increase the counter */ - tv.tv_sec = MAX_DELAY_TMR; + secs = MAX_DELAY_TMR; break; case 2: - tv.tv_sec *= 2; + secs *= 2; /* FALLTHROUGH */ case 1: - tv.tv_sec *= 2; + secs *= 2; /* FALLTHROUGH */ case 0: nbr->idtimer_cnt++; break; } - if (evtimer_add(&nbr->initdelay_timer, &tv) == -1) - fatal(__func__); + THREAD_TIMER_OFF(nbr->initdelay_timer); + nbr->initdelay_timer = thread_add_timer(master, nbr_idtimer, nbr, secs); } void nbr_stop_idtimer(struct nbr *nbr) { - if (evtimer_pending(&nbr->initdelay_timer, NULL) && - evtimer_del(&nbr->initdelay_timer) == -1) - fatal(__func__); + THREAD_TIMER_OFF(nbr->initdelay_timer); } int nbr_pending_idtimer(struct nbr *nbr) { - if (evtimer_pending(&nbr->initdelay_timer, NULL)) - return (1); - - return (0); + return (nbr->initdelay_timer != NULL); } int nbr_pending_connect(struct nbr *nbr) { - if (event_initialized(&nbr->ev_connect) && - event_pending(&nbr->ev_connect, EV_WRITE, NULL)) - return (1); - - return (0); + return (nbr->ev_connect != NULL); } -static void -nbr_connect_cb(int fd, short event, void *arg) +static int +nbr_connect_cb(struct thread *thread) { - struct nbr *nbr = arg; + struct nbr *nbr = THREAD_ARG(thread); int error; socklen_t len; + nbr->ev_connect = NULL; + len = sizeof(error); if (getsockopt(nbr->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { log_warn("%s: getsockopt SOL_SOCKET SO_ERROR", __func__); - return; + return (0); } if (error) { @@ -559,10 +552,12 @@ nbr_connect_cb(int fd, short event, void *arg) errno = error; log_debug("%s: error while connecting to %s: %s", __func__, log_addr(nbr->af, &nbr->raddr), strerror(errno)); - return; + return (0); } nbr_fsm(nbr, NBR_EVT_CONNECT_UP); + + return (0); } int @@ -572,17 +567,20 @@ nbr_establish_connection(struct nbr *nbr) struct sockaddr_storage remote_sa; struct adj *adj; struct nbr_params *nbrp; +#ifdef __OpenBSD__ int opt = 1; +#endif - nbr->fd = socket(nbr->af, - SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); + nbr->fd = socket(nbr->af, SOCK_STREAM, 0); if (nbr->fd == -1) { log_warn("%s: error while creating socket", __func__); return (-1); } + sock_set_nonblock(nbr->fd); nbrp = nbr_params_find(leconf, nbr->id); if (nbrp && nbrp->auth.method == AUTH_MD5SIG) { +#ifdef __OpenBSD__ if (sysdep.no_pfkey || sysdep.no_md5sig) { log_warnx("md5sig configured but not available"); close(nbr->fd); @@ -594,6 +592,10 @@ nbr_establish_connection(struct nbr *nbr) close(nbr->fd); return (-1); } +#else + sock_set_md5sig(nbr->fd, nbr->af, &nbr->raddr, + nbrp->auth.md5key); +#endif } memcpy(&local_sa, addr2sa(nbr->af, &nbr->laddr, 0), sizeof(local_sa)); @@ -603,7 +605,7 @@ nbr_establish_connection(struct nbr *nbr) addscope((struct sockaddr_in6 *)&remote_sa, nbr->raddr_scope); if (bind(nbr->fd, (struct sockaddr *)&local_sa, - local_sa.ss_len) == -1) { + sockaddr_len((struct sockaddr *)&local_sa)) == -1) { log_warn("%s: error while binding socket to %s", __func__, log_sockaddr((struct sockaddr *)&local_sa)); close(nbr->fd); @@ -624,11 +626,10 @@ nbr_establish_connection(struct nbr *nbr) adj->source.target); if (connect(nbr->fd, (struct sockaddr *)&remote_sa, - remote_sa.ss_len) == -1) { + sockaddr_len((struct sockaddr *)&remote_sa)) == -1) { if (errno == EINPROGRESS) { - event_set(&nbr->ev_connect, nbr->fd, EV_WRITE, - nbr_connect_cb, nbr); - event_add(&nbr->ev_connect, NULL); + THREAD_WRITE_ON(master, nbr->ev_connect, nbr_connect_cb, + nbr, nbr->fd); return (0); } log_warn("%s: error while connecting to %s", __func__, @@ -682,8 +683,8 @@ nbr_gtsm_setup(int fd, int af, struct nbr_params *nbrp) return (-1); break; case AF_INET6: - if (sock_set_ipv6_minhopcount(fd, ttl) == -1) - return (-1); + /* ignore any possible error */ + sock_set_ipv6_minhopcount(fd, ttl); ttl = 255; if (sock_set_ipv6_ucast_hops(fd, ttl) == -1) return (-1); @@ -798,7 +799,10 @@ nbr_to_ctl(struct nbr *nbr) nctl.af = nbr->af; nctl.id = nbr->id; nctl.laddr = nbr->laddr; + nctl.lport = nbr->tcp->lport; nctl.raddr = nbr->raddr; + nctl.rport = nbr->tcp->rport; + nctl.holdtime = nbr->keepalive; nctl.nbr_state = nbr->state; gettimeofday(&now, NULL); diff --git a/ldpd/notification.c b/ldpd/notification.c index f30646bb8..d306361d5 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -16,14 +16,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <arpa/inet.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldp.h" #include "log.h" #include "ldpe.h" +#include "ldp_debug.h" void send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) @@ -65,7 +64,7 @@ send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) } if (tcp->nbr) - log_debug("msg-out: notification: lsr-id %s, status %s%s", + debug_msg_send("notification: lsr-id %s status %s%s", inet_ntoa(tcp->nbr->id), status_code_name(nm->status_code), (nm->status_code & STATUS_FATAL) ? " (fatal)" : ""); @@ -199,8 +198,8 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) } } - log_warnx("msg-in: notification: lsr-id %s, status %s%s", - inet_ntoa(nbr->id), status_code_name(ntohl(st.status_code)), + debug_msg_recv("notification: lsr-id %s: %s%s", inet_ntoa(nbr->id), + status_code_name(ntohl(st.status_code)), (st.status_code & htonl(STATUS_FATAL)) ? " (fatal)" : ""); if (st.status_code & htonl(STATUS_FATAL)) { diff --git a/ldpd/packet.c b/ldpd/packet.c index 7cc375c31..9b3151d72 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -18,28 +18,22 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> -#include <net/if_dl.h> -#include <unistd.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "sockopt.h" + static struct iface *disc_find_iface(unsigned int, int, union ldpd_addr *, int); -static void session_read(int, short, void *); -static void session_write(int, short, void *); +static int session_read(struct thread *); +static int session_write(struct thread *); static ssize_t session_get_pdu(struct ibuf_read *, char **); static void tcp_close(struct tcp_conn *); static struct pending_conn *pending_conn_new(int, int, union ldpd_addr *); -static void pending_conn_timeout(int, short, void *); +static int pending_conn_timeout(struct thread *); int gen_ldp_hdr(struct ibuf *buf, uint16_t size) @@ -50,7 +44,7 @@ gen_ldp_hdr(struct ibuf *buf, uint16_t size) ldp_hdr.version = htons(LDP_VERSION); /* exclude the 'Version' and 'PDU Length' fields from the total */ ldp_hdr.length = htons(size - LDP_HDR_DEAD_LEN); - ldp_hdr.lsr_id = leconf->rtr_id.s_addr; + ldp_hdr.lsr_id = ldp_rtr_id_get(leconf); ldp_hdr.lspace_id = 0; return (ibuf_add(buf, &ldp_hdr, LDP_HDR_SIZE)); @@ -104,7 +98,7 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia, } sa = addr2sa(af, dst, LDP_PORT); - if (sendto(fd, pkt, len, 0, sa, sa->sa_len) == -1) { + if (sendto(fd, pkt, len, 0, sa, sockaddr_len(sa)) == -1) { log_warn("%s: error sending packet to %s", __func__, log_sockaddr(sa)); return (-1); @@ -114,19 +108,27 @@ send_packet(int fd, int af, union ldpd_addr *dst, struct iface_af *ia, } /* Discovery functions */ -#define CMSG_MAXLEN max(sizeof(struct sockaddr_dl), sizeof(struct in6_pktinfo)) -void -disc_recv_packet(int fd, short event, void *bula) +int +disc_recv_packet(struct thread *thread) { + int fd = THREAD_FD(thread); + struct thread **threadp = THREAD_ARG(thread); + union { struct cmsghdr hdr; - char buf[CMSG_SPACE(CMSG_MAXLEN)]; +#ifdef HAVE_STRUCT_SOCKADDR_DL + char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; +#else + char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; +#endif } cmsgbuf; struct msghdr m; struct sockaddr_storage from; struct iovec iov; char *buf; +#ifndef MSG_MCAST struct cmsghdr *cmsg; +#endif ssize_t r; int multicast; int af; @@ -140,8 +142,8 @@ disc_recv_packet(int fd, short event, void *bula) uint16_t msg_len; struct in_addr lsr_id; - if (event != EV_READ) - return; + /* reschedule read */ + *threadp = thread_add_read(master, disc_recv_packet, threadp, fd); /* setup buffer */ memset(&m, 0, sizeof(m)); @@ -158,44 +160,68 @@ disc_recv_packet(int fd, short event, void *bula) if (errno != EAGAIN && errno != EINTR) log_debug("%s: read error: %s", __func__, strerror(errno)); - return; + return (0); } + sa2addr((struct sockaddr *)&from, &af, &src, NULL); +#ifdef MSG_MCAST multicast = (m.msg_flags & MSG_MCAST) ? 1 : 0; - sa2addr((struct sockaddr *)&from, &af, &src); - if (bad_addr(af, &src)) { - log_debug("%s: invalid source address: %s", __func__, - log_addr(af, &src)); - return; - } - +#else + multicast = 0; for (cmsg = CMSG_FIRSTHDR(&m); cmsg != NULL; cmsg = CMSG_NXTHDR(&m, cmsg)) { +#if defined(HAVE_IP_PKTINFO) + if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_PKTINFO) { + struct in_pktinfo *pktinfo; + + pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); + if (IN_MULTICAST(ntohl(pktinfo->ipi_addr.s_addr))) + multicast = 1; + break; + } +#elif defined(HAVE_IP_RECVDSTADDR) if (af == AF_INET && cmsg->cmsg_level == IPPROTO_IP && - cmsg->cmsg_type == IP_RECVIF) { - ifindex = ((struct sockaddr_dl *) - CMSG_DATA(cmsg))->sdl_index; + cmsg->cmsg_type == IP_RECVDSTADDR) { + struct in_addr *addr; + + addr = (struct in_addr *)CMSG_DATA(cmsg); + if (IN_MULTICAST(ntohl(addr->s_addr))) + multicast = 1; break; } +#else +#error "Unsupported socket API" +#endif if (af == AF_INET6 && cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { - ifindex = ((struct in6_pktinfo *) - CMSG_DATA(cmsg))->ipi6_ifindex; + struct in6_pktinfo *pktinfo; + + pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg); + if (IN6_IS_ADDR_MULTICAST(&pktinfo->ipi6_addr)) + multicast = 1; break; } } +#endif /* MSG_MCAST */ + if (bad_addr(af, &src)) { + log_debug("%s: invalid source address: %s", __func__, + log_addr(af, &src)); + return (0); + } + ifindex = getsockopt_ifindex(af, &m); /* find a matching interface */ iface = disc_find_iface(ifindex, af, &src, multicast); if (iface == NULL) - return; + return (0); /* check packet size */ len = (uint16_t)r; if (len < (LDP_HDR_SIZE + LDP_MSG_SIZE) || len > LDP_MAX_LEN) { log_debug("%s: bad packet size, source %s", __func__, log_addr(af, &src)); - return; + return (0); } /* LDP header sanity checks */ @@ -203,12 +229,12 @@ disc_recv_packet(int fd, short event, void *bula) if (ntohs(ldp_hdr.version) != LDP_VERSION) { log_debug("%s: invalid LDP version %d, source %s", __func__, ntohs(ldp_hdr.version), log_addr(af, &src)); - return; + return (0); } if (ntohs(ldp_hdr.lspace_id) != 0) { log_debug("%s: invalid label space %u, source %s", __func__, ntohs(ldp_hdr.lspace_id), log_addr(af, &src)); - return; + return (0); } /* check "PDU Length" field */ pdu_len = ntohs(ldp_hdr.length); @@ -216,7 +242,7 @@ disc_recv_packet(int fd, short event, void *bula) (pdu_len > (len - LDP_HDR_DEAD_LEN))) { log_debug("%s: invalid LDP packet length %u, source %s", __func__, ntohs(ldp_hdr.length), log_addr(af, &src)); - return; + return (0); } buf += LDP_HDR_SIZE; len -= LDP_HDR_SIZE; @@ -235,7 +261,7 @@ disc_recv_packet(int fd, short event, void *bula) if (msg_len < LDP_MSG_LEN || ((msg_len + LDP_MSG_DEAD_LEN) > pdu_len)) { log_debug("%s: invalid LDP message length %u, source %s", __func__, ntohs(msg.length), log_addr(af, &src)); - return; + return (0); } buf += LDP_MSG_SIZE; len -= LDP_MSG_SIZE; @@ -249,6 +275,8 @@ disc_recv_packet(int fd, short event, void *bula) log_debug("%s: unknown LDP packet type, source %s", __func__, log_addr(af, &src)); } + + return (0); } static struct iface * @@ -306,9 +334,10 @@ disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src, return (NULL); } -void -session_accept(int fd, short event, void *bula) +int +session_accept(struct thread *thread) { + int fd = THREAD_FD(thread); struct sockaddr_storage src; socklen_t len = sizeof(src); int newfd; @@ -317,11 +346,7 @@ session_accept(int fd, short event, void *bula) struct nbr *nbr; struct pending_conn *pconn; - if (!(event & EV_READ)) - return; - - newfd = accept4(fd, (struct sockaddr *)&src, &len, - SOCK_NONBLOCK | SOCK_CLOEXEC); + newfd = accept(fd, (struct sockaddr *)&src, &len); if (newfd == -1) { /* * Pause accept if we are out of file descriptors, or @@ -333,10 +358,11 @@ session_accept(int fd, short event, void *bula) errno != ECONNABORTED) log_debug("%s: accept error: %s", __func__, strerror(errno)); - return; + return (0); } + sock_set_nonblock(newfd); - sa2addr((struct sockaddr *)&src, &af, &addr); + sa2addr((struct sockaddr *)&src, &af, &addr, NULL); /* * Since we don't support label spaces, we can identify this neighbor @@ -361,26 +387,29 @@ session_accept(int fd, short event, void *bula) close(newfd); else pending_conn_new(newfd, af, &addr); - return; + return (0); } /* protection against buggy implementations */ if (nbr_session_active_role(nbr)) { close(newfd); - return; + return (0); } if (nbr->state != NBR_STA_PRESENT) { log_debug("%s: lsr-id %s: rejecting additional transport " "connection", __func__, inet_ntoa(nbr->id)); close(newfd); - return; + return (0); } session_accept_nbr(nbr, newfd); + + return (0); } void session_accept_nbr(struct nbr *nbr, int fd) { +#ifdef __OpenBSD__ struct nbr_params *nbrp; int opt; socklen_t len; @@ -407,41 +436,42 @@ session_accept_nbr(struct nbr *nbr, int fd) return; } } +#endif nbr->tcp = tcp_new(fd, nbr); nbr_fsm(nbr, NBR_EVT_MATCH_ADJ); } -static void -session_read(int fd, short event, void *arg) +static int +session_read(struct thread *thread) { - struct nbr *nbr = arg; + int fd = THREAD_FD(thread); + struct nbr *nbr = THREAD_ARG(thread); struct tcp_conn *tcp = nbr->tcp; struct ldp_hdr *ldp_hdr; struct ldp_msg *msg; - char *buf, *pdu; + char *buf = NULL, *pdu; ssize_t n, len; uint16_t pdu_len, msg_len, msg_size, max_pdu_len; int ret; - if (event != EV_READ) - return; + tcp->rev = thread_add_read(master, session_read, nbr, fd); if ((n = read(fd, tcp->rbuf->buf + tcp->rbuf->wpos, sizeof(tcp->rbuf->buf) - tcp->rbuf->wpos)) == -1) { if (errno != EINTR && errno != EAGAIN) { log_warn("%s: read error", __func__); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); - return; + return (0); } /* retry read */ - return; + return (0); } if (n == 0) { /* connection closed */ log_debug("%s: connection closed by remote end", __func__); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); - return; + return (0); } tcp->rbuf->wpos += n; @@ -451,7 +481,7 @@ session_read(int fd, short event, void *arg) if (ntohs(ldp_hdr->version) != LDP_VERSION) { session_shutdown(nbr, S_BAD_PROTO_VER, 0, 0); free(buf); - return; + return (0); } pdu_len = ntohs(ldp_hdr->length); @@ -468,14 +498,14 @@ session_read(int fd, short event, void *arg) pdu_len > max_pdu_len) { session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); free(buf); - return; + return (0); } pdu_len -= LDP_HDR_PDU_LEN; if (ldp_hdr->lsr_id != nbr->id.s_addr || ldp_hdr->lspace_id != 0) { session_shutdown(nbr, S_BAD_LDP_ID, 0, 0); free(buf); - return; + return (0); } pdu += LDP_HDR_SIZE; len -= LDP_HDR_SIZE; @@ -493,7 +523,7 @@ session_read(int fd, short event, void *arg) session_shutdown(nbr, S_BAD_TLV_LEN, msg->id, msg->type); free(buf); - return; + return (0); } msg_size = msg_len + LDP_MSG_DEAD_LEN; pdu_len -= msg_size; @@ -506,7 +536,7 @@ session_read(int fd, short event, void *arg) session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); free(buf); - return; + return (0); } break; case MSG_TYPE_KEEPALIVE: @@ -515,7 +545,7 @@ session_read(int fd, short event, void *arg) session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); free(buf); - return; + return (0); } break; case MSG_TYPE_ADDR: @@ -529,7 +559,7 @@ session_read(int fd, short event, void *arg) session_shutdown(nbr, S_SHUTDOWN, msg->id, msg->type); free(buf); - return; + return (0); } break; default: @@ -573,7 +603,7 @@ session_read(int fd, short event, void *arg) if (ret == -1) { /* parser failed, giving up */ free(buf); - return; + return (0); } /* Analyse the next message */ @@ -583,19 +613,20 @@ session_read(int fd, short event, void *arg) free(buf); if (len != 0) { session_shutdown(nbr, S_BAD_PDU_LEN, 0, 0); - return; + return (0); } } + + return (0); } -static void -session_write(int fd, short event, void *arg) +static int +session_write(struct thread *thread) { - struct tcp_conn *tcp = arg; + struct tcp_conn *tcp = THREAD_ARG(thread); struct nbr *nbr = tcp->nbr; - if (!(event & EV_WRITE)) - return; + tcp->wbuf.ev = NULL; if (msgbuf_write(&tcp->wbuf.wbuf) <= 0) if (errno != EAGAIN && nbr) @@ -607,10 +638,12 @@ session_write(int fd, short event, void *arg) * close the socket. */ tcp_close(tcp); - return; + return (0); } evbuf_event_add(&tcp->wbuf); + + return (0); } void @@ -620,7 +653,7 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id, switch (nbr->state) { case NBR_STA_PRESENT: if (nbr_pending_connect(nbr)) - event_del(&nbr->ev_connect); + THREAD_WRITE_OFF(nbr->ev_connect); break; case NBR_STA_INITIAL: case NBR_STA_OPENREC: @@ -681,7 +714,9 @@ session_get_pdu(struct ibuf_read *r, char **b) struct tcp_conn * tcp_new(int fd, struct nbr *nbr) { - struct tcp_conn *tcp; + struct tcp_conn *tcp; + struct sockaddr_storage src; + socklen_t len = sizeof(src); if ((tcp = calloc(1, sizeof(*tcp))) == NULL) fatal(__func__); @@ -693,12 +728,15 @@ tcp_new(int fd, struct nbr *nbr) if ((tcp->rbuf = calloc(1, sizeof(struct ibuf_read))) == NULL) fatal(__func__); - event_set(&tcp->rev, tcp->fd, EV_READ | EV_PERSIST, - session_read, nbr); - event_add(&tcp->rev, NULL); + tcp->rev = thread_add_read(master, session_read, nbr, tcp->fd); tcp->nbr = nbr; } + getsockname(fd, (struct sockaddr *)&src, &len); + sa2addr((struct sockaddr *)&src, NULL, NULL, &tcp->lport); + getpeername(fd, (struct sockaddr *)&src, &len); + sa2addr((struct sockaddr *)&src, NULL, NULL, &tcp->rport); + return (tcp); } @@ -710,7 +748,7 @@ tcp_close(struct tcp_conn *tcp) evbuf_clear(&tcp->wbuf); if (tcp->nbr) { - event_del(&tcp->rev); + THREAD_READ_OFF(tcp->rev); free(tcp->rbuf); tcp->nbr->tcp = NULL; } @@ -724,7 +762,6 @@ static struct pending_conn * pending_conn_new(int fd, int af, union ldpd_addr *addr) { struct pending_conn *pconn; - struct timeval tv; if ((pconn = calloc(1, sizeof(*pconn))) == NULL) fatal(__func__); @@ -732,13 +769,9 @@ pending_conn_new(int fd, int af, union ldpd_addr *addr) pconn->fd = fd; pconn->af = af; pconn->addr = *addr; - evtimer_set(&pconn->ev_timeout, pending_conn_timeout, pconn); TAILQ_INSERT_TAIL(&global.pending_conns, pconn, entry); - - timerclear(&tv); - tv.tv_sec = PENDING_CONN_TIMEOUT; - if (evtimer_add(&pconn->ev_timeout, &tv) == -1) - fatal(__func__); + pconn->ev_timeout = thread_add_timer(master, pending_conn_timeout, + pconn, PENDING_CONN_TIMEOUT); return (pconn); } @@ -746,10 +779,7 @@ pending_conn_new(int fd, int af, union ldpd_addr *addr) void pending_conn_del(struct pending_conn *pconn) { - if (evtimer_pending(&pconn->ev_timeout, NULL) && - evtimer_del(&pconn->ev_timeout) == -1) - fatal(__func__); - + THREAD_TIMER_OFF(pconn->ev_timeout); TAILQ_REMOVE(&global.pending_conns, pconn, entry); free(pconn); } @@ -767,12 +797,14 @@ pending_conn_find(int af, union ldpd_addr *addr) return (NULL); } -static void -pending_conn_timeout(int fd, short event, void *arg) +static int +pending_conn_timeout(struct thread *thread) { - struct pending_conn *pconn = arg; + struct pending_conn *pconn = THREAD_ARG(thread); struct tcp_conn *tcp; + pconn->ev_timeout = NULL; + log_debug("%s: no adjacency with remote end: %s", __func__, log_addr(pconn->af, &pconn->addr)); @@ -785,4 +817,6 @@ pending_conn_timeout(int fd, short event, void *arg) msgbuf_write(&tcp->wbuf.wbuf); pending_conn_del(pconn); + + return (0); } diff --git a/ldpd/pfkey.c b/ldpd/pfkey.c index f0f16c867..29f763e6a 100644 --- a/ldpd/pfkey.c +++ b/ldpd/pfkey.c @@ -17,7 +17,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef __OpenBSD__ #include <sys/types.h> +#include <sys/socket.h> #include <errno.h> #include <stdlib.h> #include <string.h> @@ -464,3 +466,4 @@ pfkey_init(void) } return (fd); } +#endif /* __OpenBSD__ */ diff --git a/ldpd/socket.c b/ldpd/socket.c index 8f26771df..cf352d720 100644 --- a/ldpd/socket.c +++ b/ldpd/socket.c @@ -19,25 +19,29 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <netinet/in.h> -#include <netinet/ip.h> -#include <netinet/tcp.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> +#include <zebra.h> #include "ldpd.h" #include "ldpe.h" #include "log.h" +#include "lib/log.h" +#include "privs.h" +#include "sockopt.h" + +extern struct zebra_privs_t ldpd_privs; +extern struct zebra_privs_t ldpe_privs; + int ldp_create_socket(int af, enum socket_type type) { int fd, domain, proto; union ldpd_addr addr; struct sockaddr_storage local_sa; +#ifdef __OpenBSD__ int opt; +#endif + int save_errno; /* create socket */ switch (type) { @@ -53,11 +57,13 @@ ldp_create_socket(int af, enum socket_type type) default: fatalx("ldp_create_socket: unknown socket type"); } - fd = socket(af, domain | SOCK_NONBLOCK | SOCK_CLOEXEC, proto); + fd = socket(af, domain, proto); if (fd == -1) { log_warn("%s: error creating socket", __func__); return (-1); } + sock_set_nonblock(fd); + sockopt_v6only(af, fd); /* bind to a local address/port */ switch (type) { @@ -72,21 +78,28 @@ ldp_create_socket(int af, enum socket_type type) addr = (ldp_af_conf_get(ldpd_conf, af))->trans_addr; memcpy(&local_sa, addr2sa(af, &addr, LDP_PORT), sizeof(local_sa)); - if (sock_set_bindany(fd, 1) == -1) { - close(fd); - return (-1); - } + /* ignore any possible error */ + sock_set_bindany(fd, 1); break; } + if (ldpd_privs.change(ZPRIVS_RAISE)) + log_warn("%s: could not raise privs", __func__); if (sock_set_reuse(fd, 1) == -1) { close(fd); return (-1); } - if (bind(fd, (struct sockaddr *)&local_sa, local_sa.ss_len) == -1) { - log_warn("%s: error binding socket", __func__); + if (bind(fd, (struct sockaddr *)&local_sa, + sockaddr_len((struct sockaddr *)&local_sa)) == -1) { + save_errno = errno; + if (ldpd_privs.change(ZPRIVS_LOWER)) + log_warn("%s: could not lower privs", __func__); + log_warnx("%s: error binding socket: %s", __func__, + safe_strerror(save_errno)); close(fd); return (-1); } + if (ldpd_privs.change(ZPRIVS_LOWER)) + log_warn("%s: could not lower privs", __func__); /* set options */ switch (af) { @@ -111,6 +124,21 @@ ldp_create_socket(int af, enum socket_type type) close(fd); return (-1); } +#ifndef MSG_MCAST +#if defined(HAVE_IP_PKTINFO) + if (sock_set_ipv4_pktinfo(fd, 1) == -1) { + close(fd); + return (-1); + } +#elif defined(HAVE_IP_RECVDSTADDR) + if (sock_set_ipv4_recvdstaddr(fd, 1) == -1) { + close(fd); + return (-1); + } +#else +#error "Unsupported socket API" +#endif +#endif /* MSG_MCAST */ } if (type == LDP_SOCKET_SESSION) { if (sock_set_ipv4_ucast_ttl(fd, 255) == -1) { @@ -134,10 +162,8 @@ ldp_create_socket(int af, enum socket_type type) return (-1); } if (!(ldpd_conf->ipv6.flags & F_LDPD_AF_NO_GTSM)) { - if (sock_set_ipv6_minhopcount(fd, 255) == -1) { - close(fd); - return (-1); - } + /* ignore any possible error */ + sock_set_ipv6_minhopcount(fd, 255); } } if (type == LDP_SOCKET_DISC || type == LDP_SOCKET_EDISC) { @@ -163,6 +189,7 @@ ldp_create_socket(int af, enum socket_type type) if (listen(fd, LDP_BACKLOG) == -1) log_warn("%s: error listening on socket", __func__); +#ifdef __OpenBSD__ opt = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_MD5SIG, &opt, sizeof(opt)) == -1) { @@ -174,6 +201,7 @@ ldp_create_socket(int af, enum socket_type type) return (-1); } } +#endif break; } @@ -181,6 +209,34 @@ ldp_create_socket(int af, enum socket_type type) } void +sock_set_nonblock(int fd) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFL, 0)) == -1) + fatal("fcntl F_GETFL"); + + flags |= O_NONBLOCK; + + if ((flags = fcntl(fd, F_SETFL, flags)) == -1) + fatal("fcntl F_SETFL"); +} + +void +sock_set_cloexec(int fd) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFD, 0)) == -1) + fatal("fcntl F_GETFD"); + + flags |= FD_CLOEXEC; + + if ((flags = fcntl(fd, F_SETFD, flags)) == -1) + fatal("fcntl F_SETFD"); +} + +void sock_set_recvbuf(int fd) { int bsize; @@ -206,15 +262,68 @@ sock_set_reuse(int fd, int enable) int sock_set_bindany(int fd, int enable) { +#ifdef HAVE_SO_BINDANY + if (ldpd_privs.change(ZPRIVS_RAISE)) + log_warn("%s: could not raise privs", __func__); if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable, sizeof(int)) < 0) { + if (ldpd_privs.change(ZPRIVS_LOWER)) + log_warn("%s: could not lower privs", __func__); log_warn("%s: error setting SO_BINDANY", __func__); return (-1); } - + if (ldpd_privs.change(ZPRIVS_LOWER)) + log_warn("%s: could not lower privs", __func__); return (0); +#elif defined(HAVE_IP_FREEBIND) + if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) { + log_warn("%s: error setting IP_FREEBIND", __func__); + return (-1); + } + return (0); +#else + log_warnx("%s: missing SO_BINDANY and IP_FREEBIND, unable to bind " + "to a nonlocal IP address", __func__); + return (-1); +#endif /* HAVE_SO_BINDANY */ } +#ifndef __OpenBSD__ +/* + * Set MD5 key for the socket, for the given peer address. If the password + * is NULL or zero-length, the option will be disabled. + */ +int +sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password) +{ + int ret = -1; + int save_errno = ENOSYS; +#if HAVE_DECL_TCP_MD5SIG + union sockunion su; +#endif + + if (fd == -1) + return (0); +#if HAVE_DECL_TCP_MD5SIG + memcpy(&su, addr2sa(af, addr, 0), sizeof(su)); + + if (ldpe_privs.change(ZPRIVS_RAISE)) { + log_warn("%s: could not raise privs", __func__); + return (-1); + } + ret = sockopt_tcp_signature(fd, &su, password); + save_errno = errno; + if (ldpe_privs.change(ZPRIVS_LOWER)) + log_warn("%s: could not lower privs", __func__); +#endif /* HAVE_TCP_MD5SIG */ + if (ret < 0) + log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s", + __func__, fd, safe_strerror(save_errno)); + + return (ret); +} +#endif + int sock_set_ipv4_tos(int fd, int tos) { @@ -229,23 +338,13 @@ sock_set_ipv4_tos(int fd, int tos) int sock_set_ipv4_recvif(int fd, int enable) { - if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable, - sizeof(enable)) < 0) { - log_warn("%s: error setting IP_RECVIF", __func__); - return (-1); - } - return (0); + return (setsockopt_ifindex(AF_INET, fd, enable)); } int sock_set_ipv4_minttl(int fd, int ttl) { - if (setsockopt(fd, IPPROTO_IP, IP_MINTTL, &ttl, sizeof(ttl)) < 0) { - log_warn("%s: error setting IP_MINTTL", __func__); - return (-1); - } - - return (0); + return (sockopt_minttl(AF_INET, fd, ttl)); } int @@ -272,15 +371,45 @@ sock_set_ipv4_mcast_ttl(int fd, uint8_t ttl) return (0); } +#ifndef MSG_MCAST +#if defined(HAVE_IP_PKTINFO) +int +sock_set_ipv4_pktinfo(int fd, int enable) +{ + if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &enable, + sizeof(enable)) < 0) { + log_warn("%s: error setting IP_PKTINFO", __func__); + return (-1); + } + + return (0); +} +#elif defined(HAVE_IP_RECVDSTADDR) +int +sock_set_ipv4_recvdstaddr(int fd, int enable) +{ + if (setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &enable, + sizeof(enable)) < 0) { + log_warn("%s: error setting IP_RECVDSTADDR", __func__); + return (-1); + } + + return (0); +} +#else +#error "Unsupported socket API" +#endif +#endif /* MSG_MCAST */ + int sock_set_ipv4_mcast(struct iface *iface) { - in_addr_t addr; + struct in_addr if_addr; - addr = if_get_ipv4_addr(iface); + if_addr.s_addr = if_get_ipv4_addr(iface); - if (setsockopt(global.ipv4.ldp_disc_socket, IPPROTO_IP, IP_MULTICAST_IF, - &addr, sizeof(addr)) < 0) { + if (setsockopt_ipv4_multicast_if(global.ipv4.ldp_disc_socket, + if_addr, iface->ifindex) < 0) { log_warn("%s: error setting IP_MULTICAST_IF, interface %s", __func__, iface->name); return (-1); @@ -330,13 +459,7 @@ sock_set_ipv6_pktinfo(int fd, int enable) int sock_set_ipv6_minhopcount(int fd, int hoplimit) { - if (setsockopt(fd, IPPROTO_IPV6, IPV6_MINHOPCOUNT, - &hoplimit, sizeof(hoplimit)) < 0) { - log_warn("%s: error setting IPV6_MINHOPCOUNT", __func__); - return (-1); - } - - return (0); + return (sockopt_minttl(AF_INET6, fd, hoplimit)); } int diff --git a/ldpd/util.c b/ldpd/util.c index 981a5c8c2..e735263f5 100644 --- a/ldpd/util.c +++ b/ldpd/util.c @@ -19,8 +19,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <string.h> +#include <zebra.h> #include "ldpd.h" #include "log.h" @@ -44,7 +43,7 @@ mask2prefixlen6(struct sockaddr_in6 *sa_in6) * the possibly truncated sin6_addr struct. */ ap = (uint8_t *)&sa_in6->sin6_addr; - ep = (uint8_t *)sa_in6 + sa_in6->sin6_len; + ep = (uint8_t *)sa_in6 + sockaddr_len((struct sockaddr *)sa_in6); for (; ap < ep; ap++) { /* this "beauty" is adopted from sbin/route/show.c ... */ switch (*ap) { @@ -317,13 +316,17 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port) switch (af) { case AF_INET: sa_in->sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_in->sin_len = sizeof(struct sockaddr_in); +#endif sa_in->sin_addr = addr->v4; sa_in->sin_port = htons(port); break; case AF_INET6: sa_in6->sin6_family = AF_INET6; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN sa_in6->sin6_len = sizeof(struct sockaddr_in6); +#endif sa_in6->sin6_addr = addr->v6; sa_in6->sin6_port = htons(port); break; @@ -335,22 +338,48 @@ addr2sa(int af, union ldpd_addr *addr, uint16_t port) } void -sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr) +sa2addr(struct sockaddr *sa, int *af, union ldpd_addr *addr, in_port_t *port) { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; - memset(addr, 0, sizeof(*addr)); + if (addr) + memset(addr, 0, sizeof(*addr)); switch (sa->sa_family) { case AF_INET: - *af = AF_INET; - addr->v4 = sa_in->sin_addr; + if (af) + *af = AF_INET; + if (addr) + addr->v4 = sa_in->sin_addr; + if (port) + *port = sa_in->sin_port; break; case AF_INET6: - *af = AF_INET6; - addr->v6 = sa_in6->sin6_addr; + if (af) + *af = AF_INET6; + if (addr) + addr->v6 = sa_in6->sin6_addr; + if (port) + *port = sa_in6->sin6_port; break; default: fatalx("sa2addr: unknown af"); } } + +socklen_t +sockaddr_len(struct sockaddr *sa) +{ +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + return (sa->sa_len); +#else + switch (sa->sa_family) { + case AF_INET: + return (sizeof(struct sockaddr_in)); + case AF_INET6: + return (sizeof(struct sockaddr_in6)); + default: + fatalx("sockaddr_len: unknown af"); + } +#endif +} diff --git a/lib/Makefile.am b/lib/Makefile.am index dbb80076c..17be655a1 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -14,7 +14,8 @@ libzebra_la_SOURCES = \ filter.c routemap.c distribute.c stream.c str.c log.c plist.c \ zclient.c sockopt.c smux.c agentx.c snmp.c md5.c if_rmap.c keychain.c privs.c \ sigevent.c pqueue.c jhash.c workqueue.c nexthop.c json.c \ - ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c + ptm_lib.c csv.c bfd.c vrf.c systemd.c ns.c memory.c memory_vty.c \ + imsg-buffer.c imsg.c BUILT_SOURCES = route_types.h gitversion.h @@ -31,7 +32,7 @@ pkginclude_HEADERS = \ privs.h sigevent.h pqueue.h jhash.h zassert.h \ workqueue.h route_types.h libospf.h nexthop.h json.h \ ptm_lib.h csv.h bfd.h vrf.h ns.h systemd.h bitfield.h \ - fifo.h memory_vty.h + fifo.h memory_vty.h mpls.h imsg.h openbsd-queue.h openbsd-tree.h noinst_HEADERS = \ plist_int.h diff --git a/lib/command.c b/lib/command.c index cfdb91a5b..bf8b1b1d3 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2550,6 +2550,19 @@ node_parent ( enum node_type node ) case LINK_PARAMS_NODE: ret = INTERFACE_NODE; break; + case LDP_IPV4_NODE: + case LDP_IPV6_NODE: + ret = LDP_NODE; + break; + case LDP_IPV4_IFACE_NODE: + ret = LDP_IPV4_NODE; + break; + case LDP_IPV6_IFACE_NODE: + ret = LDP_IPV6_NODE; + break; + case LDP_PSEUDOWIRE_NODE: + ret = LDP_L2VPN_NODE; + break; default: ret = CONFIG_NODE; break; @@ -2920,6 +2933,8 @@ DEFUN (config_exit, case RIPNG_NODE: case OSPF_NODE: case OSPF6_NODE: + case LDP_NODE: + case LDP_L2VPN_NODE: case ISIS_NODE: case KEYCHAIN_NODE: case MASC_NODE: @@ -2938,6 +2953,19 @@ DEFUN (config_exit, case BGP_IPV6M_NODE: vty->node = BGP_NODE; break; + case LDP_IPV4_NODE: + case LDP_IPV6_NODE: + vty->node = LDP_NODE; + break; + case LDP_IPV4_IFACE_NODE: + vty->node = LDP_IPV4_NODE; + break; + case LDP_IPV6_IFACE_NODE: + vty->node = LDP_IPV6_NODE; + break; + case LDP_PSEUDOWIRE_NODE: + vty->node = LDP_L2VPN_NODE; + break; case KEYCHAIN_KEY_NODE: vty->node = KEYCHAIN_NODE; break; @@ -2988,6 +3016,13 @@ DEFUN (config_end, case RMAP_NODE: case OSPF_NODE: case OSPF6_NODE: + case LDP_NODE: + case LDP_IPV4_NODE: + case LDP_IPV6_NODE: + case LDP_IPV4_IFACE_NODE: + case LDP_IPV6_IFACE_NODE: + case LDP_L2VPN_NODE: + case LDP_PSEUDOWIRE_NODE: case ISIS_NODE: case KEYCHAIN_NODE: case KEYCHAIN_KEY_NODE: diff --git a/lib/command.h b/lib/command.h index 808e74205..7a4c53a61 100644 --- a/lib/command.h +++ b/lib/command.h @@ -98,6 +98,13 @@ enum node_type BGP_ENCAPV6_NODE, /* BGP ENCAP SAFI */ OSPF_NODE, /* OSPF protocol mode */ OSPF6_NODE, /* OSPF protocol for IPv6 mode */ + LDP_NODE, /* LDP protocol mode */ + LDP_IPV4_NODE, /* LDP IPv4 address family */ + LDP_IPV6_NODE, /* LDP IPv6 address family */ + LDP_IPV4_IFACE_NODE, /* LDP IPv4 Interface */ + LDP_IPV6_IFACE_NODE, /* LDP IPv6 Interface */ + LDP_L2VPN_NODE, /* LDP L2VPN node */ + LDP_PSEUDOWIRE_NODE, /* LDP Pseudowire node */ ISIS_NODE, /* ISIS protocol mode */ PIM_NODE, /* PIM protocol mode */ MASC_NODE, /* MASC for multicast. */ diff --git a/lib/imsg-buffer.c b/lib/imsg-buffer.c index 61b2c095a..a486fc17c 100644 --- a/lib/imsg-buffer.c +++ b/lib/imsg-buffer.c @@ -16,17 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <limits.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <zebra.h> +#include "openbsd-queue.h" #include "imsg.h" int ibuf_realloc(struct ibuf *, size_t); @@ -258,7 +250,7 @@ msgbuf_write(struct msgbuf *msgbuf) cmsg->cmsg_len = CMSG_LEN(sizeof(int)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(cmsg) = buf->fd; + memcpy(CMSG_DATA(cmsg), &buf->fd, sizeof(int)); } again: diff --git a/lib/imsg.c b/lib/imsg.c index 0c1cb8220..246430cdd 100644 --- a/lib/imsg.c +++ b/lib/imsg.c @@ -16,22 +16,49 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <sys/types.h> -#include <sys/queue.h> -#include <sys/socket.h> -#include <sys/uio.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> +#include <zebra.h> +#include "openbsd-queue.h" #include "imsg.h" int imsg_fd_overhead = 0; int imsg_get_fd(struct imsgbuf *); +#ifndef __OpenBSD__ +/* + * The original code calls getdtablecount() which is OpenBSD specific. Use + * available_fds() from OpenSMTPD instead. + */ +static int +available_fds(unsigned int n) +{ + unsigned int i; + int ret, fds[256]; + + if (n > (sizeof(fds)/sizeof(fds[0]))) + return (1); + + ret = 0; + for (i = 0; i < n; i++) { + fds[i] = -1; + if ((fds[i] = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) + fds[i] = socket(AF_INET6, SOCK_DGRAM, 0); + if (fds[i] < 0) { + ret = 1; + break; + } + } + } + + for (i = 0; i < n && fds[i] >= 0; i++) + close(fds[i]); + + return (ret); +} +#endif + void imsg_init(struct imsgbuf *ibuf, int fd) { @@ -71,9 +98,14 @@ imsg_read(struct imsgbuf *ibuf) return (-1); again: +#ifdef __OpenBSD__ if (getdtablecount() + imsg_fd_overhead + (int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int)) >= getdtablesize()) { +#else + if (available_fds(imsg_fd_overhead + + (CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))) { +#endif errno = EAGAIN; free(ifd); return (-1); @@ -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 888986897..5a67b915d 100644 --- a/lib/mpls.h +++ b/lib/mpls.h @@ -169,4 +169,13 @@ label2str (mpls_label_t label, char *buf, int len) return(buf); } +/* constants used by ldpd */ +#define MPLS_LABEL_IPV4NULL 0 /* IPv4 Explicit NULL Label */ +#define MPLS_LABEL_RTALERT 1 /* Router Alert Label */ +#define MPLS_LABEL_IPV6NULL 2 /* IPv6 Explicit NULL Label */ +#define MPLS_LABEL_IMPLNULL 3 /* Implicit NULL Label */ +/* MPLS_LABEL_RESERVED 4-15 */ /* Values 4-15 are reserved */ +#define MPLS_LABEL_RESERVED_MAX 15 +#define MPLS_LABEL_MAX ((1 << 20) - 1) + #endif diff --git a/lib/privs.c b/lib/privs.c index 9228a56d3..6cf87c18d 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -250,12 +250,6 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) exit(1); } - if ( !zprivs_state.syscaps_p ) - { - fprintf (stderr, "privs_init: capabilities enabled, " - "but no capabilities supplied\n"); - } - /* we have caps, we have no need to ever change back the original user */ if (zprivs_state.zuid) { @@ -266,6 +260,9 @@ zprivs_caps_init (struct zebra_privs_t *zprivs) exit (1); } } + + if ( !zprivs_state.syscaps_p ) + return; if ( !(zprivs_state.caps = cap_init()) ) { diff --git a/lib/route_types.txt b/lib/route_types.txt index 8fc3092ca..0ac442d85 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -60,6 +60,7 @@ ZEBRA_ROUTE_PIM, pim, pimd, 'P', 1, 0, "PIM" ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS" ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR" ZEBRA_ROUTE_TABLE, table, zebra, 'T', 1, 1, "Table" +ZEBRA_ROUTE_LDP, ldp, ldpd, 'L', 0, 0, "LDP" ## help strings ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only" @@ -76,3 +77,4 @@ ZEBRA_ROUTE_PIM, "Protocol Independent Multicast (PIM)" ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)" ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)" ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table" +ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)" @@ -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 000000000..43789131c --- /dev/null +++ b/tools/xml2cli.pl @@ -0,0 +1,436 @@ +#!/usr/bin/perl +## +## Parse a XML file containing a tree-like representation of Quagga CLI +## commands and generate a file with: +## +## - a DEFUN function for each command; +## - an initialization function. +## +## +## Copyright (C) 2012 Renato Westphal <renatow@digistar.com.br> +## This file is part of GNU Zebra. +## +## GNU Zebra is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by the +## Free Software Foundation; either version 2, or (at your option) any +## later version. +## +## GNU Zebra is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with GNU Zebra; see the file COPYING. If not, write to the Free +## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +## 02111-1307, USA. +## + +use strict; +use warnings; +use Getopt::Std; +use vars qw($opt_d); +use File::Basename qw(fileparse); +use XML::LibXML; + +%::input_strs = ( + "ifname" => "IFNAME", + "word" => "WORD", + "line" => ".LINE", + "ipv4" => "A.B.C.D", + "ipv4m" => "A.B.C.D/M", + "ipv6" => "X:X::X:X", + "ipv6m" => "X:X::X:X/M", + "mtu" => "<1500-9180>", + # BGP specific + "rd" => "ASN:nn_or_IP-address:nn", + "asn" => "<1-4294967295>", + "community" => "AA:NN", + "clist" => "<1-500>", + # LDP specific + "disc_time" => "<1-65535>", + "session_time" => "<15-65535>", + "pwid" => "<1-4294967295>", + "hops" => "<1-254>" + ); + +# parse options node and store the corresponding information +# into a global hash of hashes +sub parse_options { + my $xml_node = $_[0]; + my @cmdstr; + + my $options_name = $xml_node->findvalue('./@name'); + if (not $options_name) { + die('error: "options" node without "name" attribute'); + } + + # initialize hash + $::options{$options_name}{'cmdstr'} = ""; + $::options{$options_name}{'help'} = ""; + + my @children = $xml_node->getChildnodes(); + foreach my $child(@children) { + # skip comments, random text, etc + if ($child->getType() != XML_ELEMENT_NODE) { + next; + } + + # check for error/special conditions + if ($child->getName() ne "option") { + die('error: invalid node type: "' . $child->getName() . '"'); + } + + my $name = $child->findvalue('./@name'); + my $input = $child->findvalue('./@input'); + my $help = $child->findvalue('./@help'); + if ($input) { + $name = $::input_strs{$input}; + } + + push (@cmdstr, $name); + $::options{$options_name}{'help'} .= "\n \"" . $help . "\\n\""; + } + $::options{$options_name}{'cmdstr'} = "(" . join('|', @cmdstr) . ")"; +} + +# given a subtree, replace all the corresponding include nodes by +# this subtree +sub subtree_replace_includes { + my $subtree = $_[0]; + + my $subtree_name = $subtree->findvalue('./@name'); + if (not $subtree_name) { + die("subtree without \"name\" attribute"); + } + + my $query = "//include[\@subtree='$subtree_name']"; + foreach my $include_node($::xml->findnodes($query)) { + my @children = $subtree->getChildnodes(); + foreach my $child(reverse @children) { + my $include_node_parent = $include_node->getParentNode(); + $include_node_parent->insertAfter($child->cloneNode(1), + $include_node); + } + $include_node->unbindNode(); + } + $subtree->unbindNode(); +} + +# generate arguments for a given command +sub generate_arguments { + my @nodes = @_; + my $arguments; + my $no_args = 1; + my $argc = 0; + + $arguments .= " struct vty_arg *args[] =\n"; + $arguments .= " {\n"; + for (my $i = 0; $i < @nodes; $i++) { + my %node = %{$nodes[$i]}; + my $arg_value; + + if (not $node{'arg'}) { + next; + } + $no_args = 0; + + # for input and select nodes, the value of the argument is an + # argv[] element. for the other types of nodes, the value of the + # argument is the name of the node + if ($node{'input'} or $node{'type'} eq "select") { + $arg_value = "argv[" . $argc++ . "]"; + } else { + $arg_value = '"' . $node{'name'} . '"'; + } + + if ($node{'input'} and $node{'input'} eq "line") { + # arguments of the type 'line' may have multiple spaces (i.e + # they don't fit into a single argv[] element). to properly + # handle these arguments, we need to provide direct access + # to the argv[] array and the argc variable. + my $argc_str = "argc" . (($argc > 1) ? " - " . ($argc - 1) : ""); + my $argv_str = "argv" . (($argc > 1) ? " + " . ($argc - 1) : ""); + $arguments .= " &(struct vty_arg) { " + . ".name = \"" . $node{'arg'} . "\", " + . ".argc = $argc_str, " + . ".argv = $argv_str },\n"; + } else { + # common case - each argument has a name and a single value + $arguments .= " &(struct vty_arg) { " + . ".name = \"" . $node{'arg'} . "\", " + . ".value = " . $arg_value . " },\n"; + } + } + $arguments .= " NULL\n"; + $arguments .= " };\n"; + + # handle special case + if ($no_args) { + return " struct vty_arg *args[] = { NULL };\n"; + } + + return $arguments; +} + +# generate C code +sub generate_code { + my @nodes = @_; + my $funcname = ''; + my $cmdstr = ''; + my $cmdname = ''; + my $helpstr = ''; + my $function = ''; + + for (my $i = 0; $i < @nodes; $i++) { + my %node = %{$nodes[$i]}; + if ($node{'input'}) { + $funcname .= $node{'input'} . " "; + $cmdstr .= $::input_strs{$node{'input'}} . " "; + $helpstr .= "\n \"" . $node{'help'} . "\\n\""; + } elsif ($node{'type'} eq "select") { + my $options_name = $node{'options'}; + $funcname .= $options_name . " "; + $cmdstr .= $::options{$options_name}{'cmdstr'} . " "; + $helpstr .= $::options{$options_name}{'help'}; + } else { + $funcname .= $node{'name'} . " "; + $cmdstr .= $node{'name'} . " "; + $helpstr .= "\n \"" . $node{'help'} . "\\n\""; + } + + # update the command string + if ($node{'function'} ne "inherited") { + $function = $node{'function'}; + } + } + + # rtrim + $funcname =~ s/\s+$//; + $cmdstr =~ s/\s+$//; + # lowercase + $funcname = lc($funcname); + # replace " " by "_" + $funcname =~ tr/ /_/; + # replace "-" by "_" + $funcname =~ tr/-/_/; + # add prefix + $funcname = $::cmdprefix . '_' . $funcname; + + # generate DEFUN + $cmdname = $funcname . "_cmd"; + + # don't generate same command more than once + if ($::commands{$cmdname}) { + return $cmdname; + } + $::commands{$cmdname} = "1"; + + print STDOUT "DEFUN (" . $funcname . ",\n" + . " " . $cmdname . ",\n" + . " \"" . $cmdstr . "\"," + . $helpstr . ")\n" + . "{\n" + . generate_arguments(@nodes) + . " return " . $function . " (vty, args);\n" + . "}\n\n"; + + return $cmdname; +} + +# parse tree node (recursive function) +sub parse_tree { + # get args + my $xml_node = $_[0]; + my @nodes = @{$_[1]}; + my $tree_name = $_[2]; + + # hash containing all the node attributes + my %node; + $node{'type'} = $xml_node->getName(); + + # check for error/special conditions + if ($node{'type'} eq "tree") { + goto end; + } + if ($node{'type'} eq "include") { + die('error: can not include "' + . $xml_node->findvalue('./@subtree') . '"'); + } + if (not $node{'type'} ~~ [qw(option select)]) { + die('error: invalid node type: "' . $node{'type'} . '"'); + } + if ($node{'type'} eq "select") { + my $options_name = $xml_node->findvalue('./@options'); + if (not $options_name) { + die('error: "select" node without "name" attribute'); + } + if (not $::options{$options_name}) { + die('error: can not find options'); + } + $node{'options'} = $options_name; + } + + # get node attributes + $node{'name'} = $xml_node->findvalue('./@name'); + $node{'input'} = $xml_node->findvalue('./@input'); + $node{'arg'} = $xml_node->findvalue('./@arg'); + $node{'help'} = $xml_node->findvalue('./@help'); + $node{'function'} = $xml_node->findvalue('./@function'); + $node{'ifdef'} = $xml_node->findvalue('./@ifdef'); + + # push node to stack + push (@nodes, \%node); + + # generate C code + if ($node{'function'}) { + my $cmdname = generate_code(@nodes); + push (@{$::trees{$tree_name}}, [0, $cmdname, 0]); + } + + if ($node{'ifdef'}) { + push (@{$::trees{$tree_name}}, [$node{'ifdef'}, 0, 0]); + } + +end: + # recursively process child nodes + my @children = $xml_node->getChildnodes(); + foreach my $child(@children) { + # skip comments, random text, etc + if ($child->getType() != XML_ELEMENT_NODE) { + next; + } + parse_tree($child, \@nodes, $tree_name); + } + + if ($node{'ifdef'}) { + push (@{$::trees{$tree_name}}, [0, 0, $node{'ifdef'}]); + } +} + +sub parse_node { + # get args + my $xml_node = $_[0]; + + my $node_name = $xml_node->findvalue('./@name'); + if (not $node_name) { + die('missing the "name" attribute'); + } + + my $install = $xml_node->findvalue('./@install'); + my $config_write = $xml_node->findvalue('./@config_write'); + if ($install and $install eq "1") { + print " install_node (&" .lc( $node_name) . "_node, " . $config_write . ");\n"; + } + + my $install_default = $xml_node->findvalue('./@install_default'); + if ($install_default and $install_default eq "1") { + print " install_default (" . $node_name . "_NODE);\n"; + } + + my @children = $xml_node->getChildnodes(); + foreach my $child(@children) { + # skip comments, random text, etc + if ($child->getType() != XML_ELEMENT_NODE) { + next; + } + + if ($child->getName() ne "include") { + die('error: invalid node type: "' . $child->getName() . '"'); + } + my $tree_name = $child->findvalue('./@tree'); + if (not $tree_name) { + die('missing the "tree" attribute'); + } + + foreach my $entry (@{$::trees{$tree_name}}) { + my ($ifdef, $cmdname, $endif) = @{$entry}; + + if ($ifdef) { + print ("#ifdef " . $ifdef . "\n"); + } + + if ($cmdname) { + print " install_element (" . $node_name . "_NODE, &" . $cmdname . ");\n"; + } + + if ($endif) { + print ("#endif /* " . $endif . " */\n"); + } + } + } +} + +# parse command-line arguments +if (not getopts('d')) { + die("Usage: xml2cli.pl [-d] FILE\n"); +} +my $file = shift; + +# initialize the XML parser +my $parser = new XML::LibXML; +$parser->keep_blanks(0); + +# parse XML file +$::xml = $parser->parse_file($file); +my $xmlroot = $::xml->getDocumentElement(); +if ($xmlroot->getName() ne "file") { + die('XML root element name must be "file"'); +} + +# read file attributes +my $init_function = $xmlroot->findvalue('./@init'); +if (not $init_function) { + die('missing the "init" attribute in the "file" node'); +} +$::cmdprefix = $xmlroot->findvalue('./@cmdprefix'); +if (not $::cmdprefix) { + die('missing the "cmdprefix" attribute in the "file" node'); +} +my $header = $xmlroot->findvalue('./@header'); +if (not $header) { + die('missing the "header" attribute in the "file" node'); +} + +# generate source header +print STDOUT "/* Auto-generated from " . fileparse($file) . ". */\n" + . "/* Do not edit! */\n\n" + . "#include <zebra.h>\n\n" + . "#include \"command.h\"\n" + . "#include \"vty.h\"\n" + . "#include \"$header\"\n\n"; + +# Parse options +foreach my $options($::xml->findnodes("/file/options")) { + parse_options($options); +} + +# replace include nodes by the corresponding subtrees +foreach my $subtree(reverse $::xml->findnodes("/file/subtree")) { + subtree_replace_includes($subtree); +} + +# Parse trees +foreach my $tree($::xml->findnodes("/file/tree")) { + my @nodes = (); + my $tree_name = $tree->findvalue('./@name'); + parse_tree($tree, \@nodes, $tree_name); +} + +# install function header +print STDOUT "void\n" + . $init_function . " (void)\n" + . "{\n"; + +# Parse nodes +foreach my $node($::xml->findnodes("/file/node")) { + parse_node($node); +} + +# closing braces for the install function +print STDOUT "}"; + +# print to stderr the expanded XML file if the debug flag (-d) is given +if ($opt_d) { + print STDERR $::xml->toString(1); +} diff --git a/zebra/zserv.c b/zebra/zserv.c index 3402bf1df..e617ae28a 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -641,7 +641,7 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p, for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) { /* We don't send any nexthops when there's a multipath */ - if (rib->nexthop_active_num > 1) + if (rib->nexthop_active_num > 1 && client->proto != ZEBRA_ROUTE_LDP) { SET_FLAG (zapi_flags, ZAPI_MESSAGE_NEXTHOP); SET_FLAG (zapi_flags, ZAPI_MESSAGE_IFINDEX); @@ -713,7 +713,9 @@ zsend_redistribute_route (int cmd, struct zserv *client, struct prefix *p, stream_putc (s, 1); stream_putl (s, nexthop->ifindex); - break; + /* ldpd needs all nexthops */ + if (client->proto != ZEBRA_ROUTE_LDP) + break; } } |