openwrt/package/network/services/lldpd/files/lldpd.init
Paul Donald 708101c141 lldpd: fix reload bug: advertisements shall default to on
Because these capability advertisements default to on in lldpd, they
became absent at reload, and not restart, due to how the reload logic
works ( keep daemon running, send unconfigured and then the new config
via socket ), and it was not evident unless you happened to be looking
for it (e.g. via pcap or tcpdump). It was also not evident from the
manpage ( have now sent patches upstream ).

At reload time, the unconfigure logic disabled them unless they were
explicitly enabled (compare with other settings where 'unconfigure' just
resets them). Now they default to on/enabled at init time, and are
explicitly 'unconfigure'd at startup if the user disables them via:

lldp_mgmt_addr_advertisements=0
lldp_capability_advertisements=0

In other words: explicit is necessary to disable the advertisements.

The same applies to 'configure system capabilities enabled'. Technically
'unconfigure'd is the default but now it is explicit at reload.

Tested on: 23.05.3

Signed-off-by: Paul Donald <newtwen+github@gmail.com>
2024-04-27 12:11:27 +02:00

409 lines
13 KiB
Bash

#!/bin/sh /etc/rc.common
# Copyright (C) 2008-2015 OpenWrt.org
# shellcheck disable=1091,2034,3037,3043,3045
START=90
STOP=01
CONFIG_LLDPD_WITH_CDP=y
CONFIG_LLDPD_WITH_EDP=y
CONFIG_LLDPD_WITH_FDP=y
CONFIG_LLDPD_WITH_LLDPMED=y
CONFIG_LLDPD_WITH_SNMP=y
CONFIG_LLDPD_WITH_SONMP=y
USE_PROCD=1
LLDPDBIN=/usr/sbin/lldpd
LLDPCLI=/usr/sbin/lldpcli
LLDPSOCKET=/var/run/lldpd.socket
LLDPD_CONF=/tmp/lldpd.conf
LLDPD_CONFS_DIR=/tmp/lldpd.d
LLDPD_RUN=/var/run/lldpd
LLDPD_RESTART_HASH=${LLDPD_RUN}/lldpd.restart_hash
. "$IPKG_INSTROOT/lib/functions/network.sh"
find_release_info()
{
[ -s /etc/os-release ] && . /etc/os-release
[ -z "$PRETTY_NAME" ] && [ -s /etc/openwrt_version ] && \
PRETTY_NAME="$(cat /etc/openwrt_version)"
echo "${PRETTY_NAME:-Unknown OpenWrt release} @ $(cat /proc/sys/kernel/hostname)"
}
get_config_restart_hash() {
local var="$1"
local _string _hash v
config_load 'lldpd'
config_get v 'config' 'lldp_class'; append _string "$v" ","
if [ "$CONFIG_LLDPD_WITH_SNMP" = "y" ]; then
config_get v 'config' 'agentxsocket'; append _string "$v" ","
fi
config_get v 'config' 'cid_interface'; append _string "$v" ","
config_get v 'config' 'filter'; append _string "$v" ","
config_get_bool v 'config' 'readonly_mode'; append _string "$v" ","
config_get_bool v 'config' 'lldp_no_version'; append _string "$v" ","
if [ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ]; then
config_get_bool v 'config' 'lldpmed_no_inventory'; append _string "$v" ","
fi
config_get_bool v 'config' 'enable_lldp' 1; append _string "$v" ","
config_get_bool v 'config' 'force_lldp'; append _string "$v" ","
if [ "$CONFIG_LLDPD_WITH_CDP" = "y" ]; then
config_get_bool v 'config' 'enable_cdp'; append _string "$v" ","
config_get v 'config' 'cdp_version'; append _string "$v" ","
config_get_bool v 'config' 'force_cdp'; append _string "$v" ","
config_get_bool v 'config' 'force_cdpv2'; append _string "$v" ","
fi
if [ "$CONFIG_LLDPD_WITH_EDP" = "y" ]; then
config_get_bool v 'config' 'enable_edp'; append _string "$v" ","
config_get_bool v 'config' 'force_edp'; append _string "$v" ","
fi
if [ "$CONFIG_LLDPD_WITH_FDP" = "y" ]; then
config_get_bool v 'config' 'enable_fdp'; append _string "$v" ","
config_get_bool v 'config' 'force_fdp'; append _string "$v" ","
fi
if [ "$CONFIG_LLDPD_WITH_SONMP" = "y" ]; then
config_get_bool v 'config' 'enable_sonmp'; append _string "$v" ","
config_get_bool v 'config' 'force_sonmp'; append _string "$v" ","
fi
_hash=$(echo -n "${_string}" | md5sum | awk '{ print $1 }')
export -n "$var=$_hash"
}
get_config_cid_ifaces() {
local _ifaces
config_get _ifaces 'config' "$2"
local _iface _ifnames=""
# Set noglob to prevent '*' capturing diverse file names in the for ... in
set -o noglob
for _iface in $_ifaces; do
local _l2device=""
if network_get_physdev _l2device "$_iface" || [ -e "/sys/class/net/$_iface" ]; then
append _ifnames "${_l2device:-$_iface}" ","
else
# Glob case (interface is e.g. '!eth1' or 'eth*' or '*')
append _ifnames "$_iface" ","
fi
done
# Turn noglob off i.e. enable glob again
set +o noglob
export -n "${1}=$_ifnames"
}
write_lldpd_conf()
{
local lldp_description
config_load 'lldpd'
config_get lldp_description 'config' 'lldp_description' "$(find_release_info)"
local lldp_hostname
config_get lldp_hostname 'config' 'lldp_hostname' "$(cat /proc/sys/kernel/hostname)"
local ifnames
get_config_cid_ifaces ifnames "interface"
local lldp_mgmt_ip
config_get lldp_mgmt_ip 'config' 'lldp_mgmt_ip'
# Configurable capabilities in lldpd >= v1.0.15: defaults to 'unconfigured' i.e. kernel info
local lldp_syscapabilities
config_get lldp_syscapabilities 'config' 'lldp_syscapabilities'
# Configurable capabilities in lldpd >= v1.0.15: defaults to on in lldpd
local lldp_capability_advertisements
config_get_bool lldp_capability_advertisements 'config' 'lldp_capability_advertisements' 1
# Broadcast management address in lldpd >= 0.7.15: defaults to on in lldpd
local lldp_mgmt_addr_advertisements
config_get_bool lldp_mgmt_addr_advertisements 'config' 'lldp_mgmt_addr_advertisements' 1
if [ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ]; then
local lldpmed_fast_start
config_get_bool lldpmed_fast_start 'config' 'lldpmed_fast_start' 0
local lldpmed_fast_start_tx_interval
config_get lldpmed_fast_start_tx_interval 'config' 'lldpmed_fast_start_tx_interval' 0
local lldp_location
config_get lldp_location 'config' 'lldp_location'
local lldp_class
config_get lldp_class 'config' 'lldp_class'
local lldp_policy
config_get lldp_policy 'config' 'lldp_policy'
fi
local lldp_agenttype
config_get lldp_agenttype 'config' 'lldp_agenttype' 'nearest-bridge'
local lldp_portidsubtype
config_get lldp_portidsubtype 'config' 'lldp_portidsubtype' 'macaddress'
local lldp_platform
config_get lldp_platform 'config' 'lldp_platform' ""
local lldp_tx_interval
config_get lldp_tx_interval 'config' 'lldp_tx_interval' 0
local lldp_tx_hold
config_get lldp_tx_hold 'config' 'lldp_tx_hold' 0
# Clear out the config file first
echo -n > "$LLDPD_CONF"
[ -n "$ifnames" ] && echo "configure system interface pattern $ifnames" >> "$LLDPD_CONF"
[ -n "$lldp_description" ] && echo "configure system description" "\"$lldp_description\"" >> "$LLDPD_CONF"
[ -n "$lldp_hostname" ] && echo "configure system hostname" "\"$lldp_hostname\"" >> "$LLDPD_CONF"
[ -n "$lldp_mgmt_ip" ] && echo "configure system ip management pattern" "\"$lldp_mgmt_ip\"" >> "$LLDPD_CONF"
[ -n "$lldp_syscapabilities" ] && echo "configure system capabilities enabled $lldp_syscapabilities" >> "$LLDPD_CONF"
if [ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ] && [ "$lldpmed_fast_start" -gt 0 ]; then
if [ "$lldpmed_fast_start_tx_interval" -gt 0 ]; then
echo "configure med fast-start tx-interval $lldpmed_fast_start_tx_interval" >> "$LLDPD_CONF"
else
echo "configure med fast-start enable" >> "$LLDPD_CONF"
fi
fi
if [ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ]; then
# other 'configure med xxx' statements go here
[ -n "$lldp_location" ] && echo "configure med location" "$lldp_location" >> "$LLDPD_CONF"
# Manual states that if Class (-M) is 2 or 3, at least one network policy must be defined
case "$lldp_class" in
2 | 3 ) [ -n "$lldp_policy" ] && echo "configure med policy $lldp_policy" >> "$LLDPD_CONF"
;;
esac
fi
[ -n "$lldp_agenttype" ] && echo "configure lldp agent-type" "\"$lldp_agenttype\"" >> "$LLDPD_CONF"
[ -n "$lldp_portidsubtype" ] && echo "configure lldp portidsubtype" "\"$lldp_portidsubtype\"" >> "$LLDPD_CONF"
[ -n "$lldp_platform" ] && echo "configure system platform" "\"$lldp_platform\"" >> "$LLDPD_CONF"
[ -n "$lldp_tx_interval" ] && echo "configure lldp tx-interval $lldp_tx_interval" >> "$LLDPD_CONF"
[ "$lldp_tx_hold" -gt 0 ] && echo "configure lldp tx-hold $lldp_tx_hold" >> "$LLDPD_CONF"
[ "$lldp_capability_advertisements" -gt 0 ] && echo "configure lldp capabilities-advertisements" >> "$LLDPD_CONF" ||\
echo "unconfigure lldp capabilities-advertisements" >> "$LLDPD_CONF"
[ "$lldp_mgmt_addr_advertisements" -gt 0 ] && echo "configure lldp management-addresses-advertisements" >> "$LLDPD_CONF" ||\
echo "unconfigure lldp management-addresses-advertisements" >> "$LLDPD_CONF"
# Since lldpd's sysconfdir is /tmp, we'll symlink /etc/lldpd.d to /tmp/$LLDPD_CONFS_DIR
[ -e "$LLDPD_CONFS_DIR" ] || ln -s /etc/lldpd.d "$LLDPD_CONFS_DIR"
}
start_service() {
local enable_lldp
local force_lldp
local enable_cdp
local cdp_version
local force_cdp
local force_cdpv2
local enable_fdp
local force_fdp
local enable_sonmp
local force_sonmp
local enable_edp
local force_edp
local lldp_class
local lldp_no_version
local lldpmed_no_inventory
local readonly_mode
local agentxsocket
local filter
config_load 'lldpd'
config_get_bool enable_lldp 'config' 'enable_lldp' 1
config_get_bool force_lldp 'config' 'force_lldp' 0
if [ "$CONFIG_LLDPD_WITH_CDP" = "y" ]; then
config_get_bool enable_cdp 'config' 'enable_cdp' 0
config_get cdp_version 'config' 'cdp_version' 'cdpv1v2'
config_get_bool force_cdp 'config' 'force_cdp' 0
config_get_bool force_cdpv2 'config' 'force_cdpv2' 0
fi
if [ "$CONFIG_LLDPD_WITH_FDP" = "y" ]; then
config_get_bool enable_fdp 'config' 'enable_fdp' 0
config_get_bool force_fdp 'config' 'force_fdp' 0
fi
if [ "$CONFIG_LLDPD_WITH_SONMP" = "y" ]; then
config_get_bool enable_sonmp 'config' 'enable_sonmp' 0
config_get_bool force_sonmp 'config' 'force_sonmp' 0
fi
if [ "$CONFIG_LLDPD_WITH_EDP" = "y" ]; then
config_get_bool enable_edp 'config' 'enable_edp' 0
config_get_bool force_edp 'config' 'force_edp' 0
fi
config_get lldp_class 'config' 'lldp_class'
config_get_bool lldp_no_version 'config' 'lldp_no_version' 0
if [ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ]; then
config_get_bool lldpmed_no_inventory 'config' 'lldpmed_no_inventory' 0
fi
config_get_bool readonly_mode 'config' 'readonly_mode' 0
if [ "$CONFIG_LLDPD_WITH_SNMP" = "y" ]; then
config_get agentxsocket 'config' 'agentxsocket'
fi
config_get filter 'config' 'filter' 15
mkdir -p ${LLDPD_RUN}
chown lldp:lldp ${LLDPD_RUN}
# When lldpd starts, it also loads up what we write in this config file
write_lldpd_conf
procd_open_instance
procd_set_param command ${LLDPDBIN}
procd_append_param command -d
if [ "$enable_lldp" -gt 0 ]; then
if [ "$force_lldp" -gt 0 ]; then
procd_append_param command '-l'
fi
else
# Disable LLDP
procd_append_param command '-ll'
fi
if [ "$CONFIG_LLDPD_WITH_CDP" = "y" ] && [ "$enable_cdp" -gt 0 ]; then
if [ "$cdp_version" = "cdpv2" ]; then
if [ "$force_cdp" -gt 0 ]; then
# CDPv1 disabled, CDPv2 forced
procd_append_param command '-ccccc'
else
# CDPv1 disabled, CDPv2 enabled
procd_append_param command '-cccc'
fi
elif [ "$cdp_version" = "cdpv1v2" ]; then
if [ "$force_cdp" -gt 0 ] && [ "$force_cdpv2" -gt 0 ]; then
# CDPv1 enabled, CDPv2 forced
procd_append_param command '-ccc'
elif [ "$force_cdp" -gt 0 ]; then
# CDPv1 forced, CDPv2 enabled
procd_append_param command '-cc'
else
# CDPv1 and CDPv2 enabled
procd_append_param command '-c'
fi
fi
fi
if [ "$CONFIG_LLDPD_WITH_FDP" = "y" ] && [ "$enable_fdp" -gt 0 ]; then
if [ "$force_fdp" -gt 0 ]; then
# FDP enabled and forced
procd_append_param command '-ff'
else
# FDP enabled
procd_append_param command '-f'
fi
fi
if [ "$CONFIG_LLDPD_WITH_SONMP" = "y" ] && [ "$enable_sonmp" -gt 0 ]; then
if [ "$force_sonmp" -gt 0 ]; then
# SONMP enabled and forced
procd_append_param command '-ss'
else
# SONMP enabled
procd_append_param command '-s'
fi
fi
if [ "$CONFIG_LLDPD_WITH_EDP" = "y" ] && [ "$enable_edp" -gt 0 ]; then
if [ "$force_edp" -gt 0 ]; then
# EDP enabled and forced
procd_append_param command '-ee'
else
# EDP enabled
procd_append_param command '-e'
fi
fi
[ "$readonly_mode" -gt 0 ] && procd_append_param command '-r'
[ "$lldp_no_version" -gt 0 ] && procd_append_param command '-k'
[ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ] && [ "$lldpmed_no_inventory" -gt 0 ] && procd_append_param command '-i'
[ -n "$lldp_class" ] && procd_append_param command -M "$lldp_class"
[ "$CONFIG_LLDPD_WITH_SNMP" = "y" ] && [ -n "$agentxsocket" ] && procd_append_param command -x -X "$agentxsocket"
[ -n "$filter" ] && procd_append_param command -H "$filter"
# ChassisID interfaces
local ifnames
get_config_cid_ifaces ifnames "cid_interface"
[ -n "$ifnames" ] && procd_append_param command -C "$ifnames"
# Overwrite default configuration locations processed by lldpcli at start
procd_append_param command -O "$LLDPD_CONF"
local restart_hash
get_config_restart_hash restart_hash
echo -n "$restart_hash" > "$LLDPD_RESTART_HASH"
# set auto respawn behavior
procd_set_param respawn
procd_close_instance
}
service_triggers() {
procd_add_config_trigger "config.change" "lldpd" /etc/init.d/lldpd reload
}
reload_service() {
running || return 1
local running_hash=""
local config_hash=""
get_config_restart_hash config_hash
[ -f ${LLDPD_RESTART_HASH} ] && running_hash=$(cat "$LLDPD_RESTART_HASH")
if [ "x$running_hash" != "x$config_hash" ]; then
# Restart LLDPd
# Some parameters can't be configured at runtime
restart
return 0
fi
$LLDPCLI -u "$LLDPSOCKET" >/dev/null 2>&1 <<-EOF
pause
unconfigure lldp custom-tlv
unconfigure lldp capabilities-advertisements
unconfigure lldp management-addresses-advertisements
# unconfigures user-configured system capabilities, and instead uses the kernel information:
unconfigure system capabilities enabled
unconfigure system interface pattern
unconfigure system description
unconfigure system hostname
unconfigure system ip management pattern
unconfigure system platform
EOF
if [ "$CONFIG_LLDPD_WITH_LLDPMED" = "y" ]; then
$LLDPCLI -u "$LLDPSOCKET" >/dev/null 2>&1 <<-EOF
unconfigure med fast-start
EOF
fi
# Rewrite lldpd.conf
# If something changed it should be included by the lldpcli call
write_lldpd_conf
$LLDPCLI -u "$LLDPSOCKET" -c "$LLDPD_CONF" -c "$LLDPD_CONFS_DIR" >/dev/null 2>&1
# Broadcast update over the wire
$LLDPCLI -u "$LLDPSOCKET" >/dev/null 2>&1 <<-EOF
resume
update
EOF
return 0
}
stop_service() {
rm -rf ${LLDPD_RUN} "$LLDPSOCKET" >/dev/null 2>&1
}