netcons_basic.sh 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #!/usr/bin/env bash
  2. # SPDX-License-Identifier: GPL-2.0
  3. # This test creates two netdevsim virtual interfaces, assigns one of them (the
  4. # "destination interface") to a new namespace, and assigns IP addresses to both
  5. # interfaces.
  6. #
  7. # It listens on the destination interface using socat and configures a dynamic
  8. # target on netconsole, pointing to the destination IP address.
  9. #
  10. # Finally, it checks whether the message was received properly on the
  11. # destination interface. Note that this test may pollute the kernel log buffer
  12. # (dmesg) and relies on dynamic configuration and namespaces being configured.
  13. #
  14. # Author: Breno Leitao <leitao@debian.org>
  15. set -euo pipefail
  16. SCRIPTDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
  17. # Simple script to test dynamic targets in netconsole
  18. SRCIF="" # to be populated later
  19. SRCIP=192.168.1.1
  20. DSTIF="" # to be populated later
  21. DSTIP=192.168.1.2
  22. PORT="6666"
  23. MSG="netconsole selftest"
  24. TARGET=$(mktemp -u netcons_XXXXX)
  25. DEFAULT_PRINTK_VALUES=$(cat /proc/sys/kernel/printk)
  26. NETCONS_CONFIGFS="/sys/kernel/config/netconsole"
  27. NETCONS_PATH="${NETCONS_CONFIGFS}"/"${TARGET}"
  28. # NAMESPACE will be populated by setup_ns with a random value
  29. NAMESPACE=""
  30. # IDs for netdevsim
  31. NSIM_DEV_1_ID=$((256 + RANDOM % 256))
  32. NSIM_DEV_2_ID=$((512 + RANDOM % 256))
  33. # Used to create and delete namespaces
  34. source "${SCRIPTDIR}"/../../net/lib.sh
  35. source "${SCRIPTDIR}"/../../net/net_helper.sh
  36. # Create netdevsim interfaces
  37. create_ifaces() {
  38. local NSIM_DEV_SYS_NEW=/sys/bus/netdevsim/new_device
  39. echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_NEW"
  40. echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_NEW"
  41. udevadm settle 2> /dev/null || true
  42. local NSIM1=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_1_ID"
  43. local NSIM2=/sys/bus/netdevsim/devices/netdevsim"$NSIM_DEV_2_ID"
  44. # These are global variables
  45. SRCIF=$(find "$NSIM1"/net -maxdepth 1 -type d ! \
  46. -path "$NSIM1"/net -exec basename {} \;)
  47. DSTIF=$(find "$NSIM2"/net -maxdepth 1 -type d ! \
  48. -path "$NSIM2"/net -exec basename {} \;)
  49. }
  50. link_ifaces() {
  51. local NSIM_DEV_SYS_LINK="/sys/bus/netdevsim/link_device"
  52. local SRCIF_IFIDX=$(cat /sys/class/net/"$SRCIF"/ifindex)
  53. local DSTIF_IFIDX=$(cat /sys/class/net/"$DSTIF"/ifindex)
  54. exec {NAMESPACE_FD}</var/run/netns/"${NAMESPACE}"
  55. exec {INITNS_FD}</proc/self/ns/net
  56. # Bind the dst interface to namespace
  57. ip link set "${DSTIF}" netns "${NAMESPACE}"
  58. # Linking one device to the other one (on the other namespace}
  59. if ! echo "${INITNS_FD}:$SRCIF_IFIDX $NAMESPACE_FD:$DSTIF_IFIDX" > $NSIM_DEV_SYS_LINK
  60. then
  61. echo "linking netdevsim1 with netdevsim2 should succeed"
  62. cleanup
  63. exit "${ksft_skip}"
  64. fi
  65. }
  66. function configure_ip() {
  67. # Configure the IPs for both interfaces
  68. ip netns exec "${NAMESPACE}" ip addr add "${DSTIP}"/24 dev "${DSTIF}"
  69. ip netns exec "${NAMESPACE}" ip link set "${DSTIF}" up
  70. ip addr add "${SRCIP}"/24 dev "${SRCIF}"
  71. ip link set "${SRCIF}" up
  72. }
  73. function set_network() {
  74. # setup_ns function is coming from lib.sh
  75. setup_ns NAMESPACE
  76. # Create both interfaces, and assign the destination to a different
  77. # namespace
  78. create_ifaces
  79. # Link both interfaces back to back
  80. link_ifaces
  81. configure_ip
  82. }
  83. function create_dynamic_target() {
  84. DSTMAC=$(ip netns exec "${NAMESPACE}" \
  85. ip link show "${DSTIF}" | awk '/ether/ {print $2}')
  86. # Create a dynamic target
  87. mkdir "${NETCONS_PATH}"
  88. echo "${DSTIP}" > "${NETCONS_PATH}"/remote_ip
  89. echo "${SRCIP}" > "${NETCONS_PATH}"/local_ip
  90. echo "${DSTMAC}" > "${NETCONS_PATH}"/remote_mac
  91. echo "${SRCIF}" > "${NETCONS_PATH}"/dev_name
  92. echo 1 > "${NETCONS_PATH}"/enabled
  93. }
  94. function cleanup() {
  95. local NSIM_DEV_SYS_DEL="/sys/bus/netdevsim/del_device"
  96. # delete netconsole dynamic reconfiguration
  97. echo 0 > "${NETCONS_PATH}"/enabled
  98. # Remove the configfs entry
  99. rmdir "${NETCONS_PATH}"
  100. # Delete netdevsim devices
  101. echo "$NSIM_DEV_2_ID" > "$NSIM_DEV_SYS_DEL"
  102. echo "$NSIM_DEV_1_ID" > "$NSIM_DEV_SYS_DEL"
  103. # this is coming from lib.sh
  104. cleanup_all_ns
  105. # Restoring printk configurations
  106. echo "${DEFAULT_PRINTK_VALUES}" > /proc/sys/kernel/printk
  107. }
  108. function listen_port_and_save_to() {
  109. local OUTPUT=${1}
  110. # Just wait for 2 seconds
  111. timeout 2 ip netns exec "${NAMESPACE}" \
  112. socat UDP-LISTEN:"${PORT}",fork "${OUTPUT}"
  113. }
  114. function validate_result() {
  115. local TMPFILENAME="$1"
  116. # Check if the file exists
  117. if [ ! -f "$TMPFILENAME" ]; then
  118. echo "FAIL: File was not generated." >&2
  119. exit "${ksft_fail}"
  120. fi
  121. if ! grep -q "${MSG}" "${TMPFILENAME}"; then
  122. echo "FAIL: ${MSG} not found in ${TMPFILENAME}" >&2
  123. cat "${TMPFILENAME}" >&2
  124. exit "${ksft_fail}"
  125. fi
  126. # Delete the file once it is validated, otherwise keep it
  127. # for debugging purposes
  128. rm "${TMPFILENAME}"
  129. exit "${ksft_pass}"
  130. }
  131. function check_for_dependencies() {
  132. if [ "$(id -u)" -ne 0 ]; then
  133. echo "This test must be run as root" >&2
  134. exit "${ksft_skip}"
  135. fi
  136. if ! which socat > /dev/null ; then
  137. echo "SKIP: socat(1) is not available" >&2
  138. exit "${ksft_skip}"
  139. fi
  140. if ! which ip > /dev/null ; then
  141. echo "SKIP: ip(1) is not available" >&2
  142. exit "${ksft_skip}"
  143. fi
  144. if ! which udevadm > /dev/null ; then
  145. echo "SKIP: udevadm(1) is not available" >&2
  146. exit "${ksft_skip}"
  147. fi
  148. if [ ! -d "${NETCONS_CONFIGFS}" ]; then
  149. echo "SKIP: directory ${NETCONS_CONFIGFS} does not exist. Check if NETCONSOLE_DYNAMIC is enabled" >&2
  150. exit "${ksft_skip}"
  151. fi
  152. if ip link show "${DSTIF}" 2> /dev/null; then
  153. echo "SKIP: interface ${DSTIF} exists in the system. Not overwriting it." >&2
  154. exit "${ksft_skip}"
  155. fi
  156. if ip addr list | grep -E "inet.*(${SRCIP}|${DSTIP})" 2> /dev/null; then
  157. echo "SKIP: IPs already in use. Skipping it" >&2
  158. exit "${ksft_skip}"
  159. fi
  160. }
  161. # ========== #
  162. # Start here #
  163. # ========== #
  164. modprobe netdevsim 2> /dev/null || true
  165. modprobe netconsole 2> /dev/null || true
  166. # The content of kmsg will be save to the following file
  167. OUTPUT_FILE="/tmp/${TARGET}"
  168. # Check for basic system dependency and exit if not found
  169. check_for_dependencies
  170. # Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5)
  171. echo "6 5" > /proc/sys/kernel/printk
  172. # Remove the namespace, interfaces and netconsole target on exit
  173. trap cleanup EXIT
  174. # Create one namespace and two interfaces
  175. set_network
  176. # Create a dynamic target for netconsole
  177. create_dynamic_target
  178. # Listed for netconsole port inside the namespace and destination interface
  179. listen_port_and_save_to "${OUTPUT_FILE}" &
  180. # Wait for socat to start and listen to the port.
  181. wait_local_port_listen "${NAMESPACE}" "${PORT}" udp
  182. # Send the message
  183. echo "${MSG}: ${TARGET}" > /dev/kmsg
  184. # Wait until socat saves the file to disk
  185. busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}"
  186. # Make sure the message was received in the dst part
  187. # and exit
  188. validate_result "${OUTPUT_FILE}"