LIBDIR=$(dirname "$(readlink -e "${BASH_SOURCE[0]}")")
 
 SRCIF="" # to be populated later
-SRCIP=192.0.2.1
+SRCIP4="192.0.2.1"
+SRCIP6="fc00::1"
 DSTIF="" # to be populated later
-DSTIP=192.0.2.2
+DSTIP4="192.0.2.2"
+DSTIP6="fc00::2"
 
 PORT="6666"
 MSG="netconsole selftest"
        ip link set "${SRCIF}" up
 }
 
+function select_ipv4_or_ipv6()
+{
+       local VERSION=${1}
+
+       if [[ "$VERSION" == "ipv6" ]]
+       then
+               DSTIP="${DSTIP6}"
+               SRCIP="${SRCIP6}"
+       else
+               DSTIP="${DSTIP4}"
+               SRCIP="${SRCIP4}"
+       fi
+}
+
 function set_network() {
+       local IP_VERSION=${1:-"ipv4"}
+
        # setup_ns function is coming from lib.sh
        setup_ns NAMESPACE
 
        # Link both interfaces back to back
        link_ifaces
 
+       select_ipv4_or_ipv6 "${IP_VERSION}"
        configure_ip
 }
 
        fi
 
        echo 1 > "${NETCONS_PATH}"/enabled
+
+       # This will make sure that the kernel was able to
+       # load the netconsole driver configuration. The console message
+       # gets more organized/sequential as well.
+       sleep 1
 }
 
 # Generate the command line argument for netconsole following:
 
 function listen_port_and_save_to() {
        local OUTPUT=${1}
+       local IPVERSION=${2:-"ipv4"}
+
+       if [ "${IPVERSION}" == "ipv4" ]
+       then
+               SOCAT_MODE="UDP-LISTEN"
+       else
+               SOCAT_MODE="UDP6-LISTEN"
+       fi
+
        # Just wait for 2 seconds
        timeout 2 ip netns exec "${NAMESPACE}" \
-               socat UDP-LISTEN:"${PORT}",fork "${OUTPUT}"
+               socat "${SOCAT_MODE}":"${PORT}",fork "${OUTPUT}"
 }
 
 # Only validate that the message arrived properly
                exit "${ksft_skip}"
        fi
 
-       if ip addr list | grep -E "inet.*(${SRCIP}|${DSTIP})" 2> /dev/null; then
-               echo "SKIP: IPs already in use. Skipping it" >&2
+       REGEXP4="inet.*(${SRCIP4}|${DSTIP4})"
+       REGEXP6="inet.*(${SRCIP6}|${DSTIP6})"
+       if ip addr list | grep -E "${REGEXP4}" 2> /dev/null; then
+               echo "SKIP: IPv4s already in use. Skipping it" >&2
+               exit "${ksft_skip}"
+       fi
+
+       if ip addr list | grep -E "${REGEXP6}" 2> /dev/null; then
+               echo "SKIP: IPv6s already in use. Skipping it" >&2
                exit "${ksft_skip}"
        fi
 }
 
 # This is necessary if running multiple tests in a row
 function pkill_socat() {
-       PROCESS_NAME="socat UDP-LISTEN:6666,fork ${OUTPUT_FILE}"
+       PROCESS_NAME4="socat UDP-LISTEN:6666,fork ${OUTPUT_FILE}"
+       PROCESS_NAME6="socat UDP6-LISTEN:6666,fork ${OUTPUT_FILE}"
        # socat runs under timeout(1), kill it if it is still alive
        # do not fail if socat doesn't exist anymore
        set +e
-       pkill -f "${PROCESS_NAME}"
+       pkill -f "${PROCESS_NAME4}"
+       pkill -f "${PROCESS_NAME6}"
        set -e
 }
 
                exit "${ksft_skip}"
        fi
 }
+
+# A wrapper to translate protocol version to udp version
+function wait_for_port() {
+       local NAMESPACE=${1}
+       local PORT=${2}
+       IP_VERSION=${3}
+
+       if [ "${IP_VERSION}" == "ipv6" ]
+       then
+               PROTOCOL="udp6"
+       else
+               PROTOCOL="udp"
+       fi
+
+       wait_local_port_listen "${NAMESPACE}" "${PORT}" "${PROTOCOL}"
+       # even after the port is open, let's wait 1 second before writing
+       # otherwise the packet could be missed, and the test will fail. Happens
+       # more frequently on IPv6
+       sleep 1
+}
 
 # Run the test twice, with different format modes
 for FORMAT in "basic" "extended"
 do
-       echo "Running with target mode: ${FORMAT}"
-       # Create one namespace and two interfaces
-       set_network
-       # Create a dynamic target for netconsole
-       create_dynamic_target "${FORMAT}"
-       # Only set userdata for extended format
-       if [ "$FORMAT" == "extended" ]
-       then
-               # Set userdata "key" with the "value" value
-               set_user_data
-       fi
-       # Listed for netconsole port inside the namespace and destination interface
-       listen_port_and_save_to "${OUTPUT_FILE}" &
-       # Wait for socat to start and listen to the port.
-       wait_local_port_listen "${NAMESPACE}" "${PORT}" udp
-       # Send the message
-       echo "${MSG}: ${TARGET}" > /dev/kmsg
-       # Wait until socat saves the file to disk
-       busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}"
+       for IP_VERSION in "ipv6" "ipv4"
+       do
+               echo "Running with target mode: ${FORMAT} (${IP_VERSION})"
+               # Create one namespace and two interfaces
+               set_network "${IP_VERSION}"
+               # Create a dynamic target for netconsole
+               create_dynamic_target "${FORMAT}"
+               # Only set userdata for extended format
+               if [ "$FORMAT" == "extended" ]
+               then
+                       # Set userdata "key" with the "value" value
+                       set_user_data
+               fi
+               # Listed for netconsole port inside the namespace and
+               # destination interface
+               listen_port_and_save_to "${OUTPUT_FILE}" "${IP_VERSION}" &
+               # Wait for socat to start and listen to the port.
+               wait_for_port "${NAMESPACE}" "${PORT}" "${IP_VERSION}"
+               # Send the message
+               echo "${MSG}: ${TARGET}" > /dev/kmsg
+               # Wait until socat saves the file to disk
+               busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}"
 
-       # Make sure the message was received in the dst part
-       # and exit
-       validate_result "${OUTPUT_FILE}" "${FORMAT}"
-       cleanup
+               # Make sure the message was received in the dst part
+               # and exit
+               validate_result "${OUTPUT_FILE}" "${FORMAT}"
+               # kill socat in case it is still running
+               pkill_socat
+               cleanup
+               echo "${FORMAT} : ${IP_VERSION} : Test passed" >&2
+       done
 done
 
 trap - EXIT