How to configure loopback-detection per MPLS VSI AC circuit subIF on Huawei S6730H switch

Huawei S6730-H: Test Loop Detection on a VSI Sub-Interface

A customer loop can interrupt a Layer 2 service even when the physical port stays up. This guide shows how to enable loop detection on a Huawei S6730-H VSI sub-interface and verify that it reacts to returned detection frames.

The key result is UP (LOOP-DETECT BLOCK): the sub-interface reports UP, but loop detection has blocked the service attachment. The commands and output below come from a working lab, with generic device names.

Before You Start

The lab uses two PEs connected through an existing MPLS/LDP network. Both ends carry VLAN 2323 in VSI FRA-AMS_TEST, with VSI ID 2323232323 and MTU 9216.

PE1: 10.1.160.240, customer sub-interface XGigabitEthernet0/0/36.2323. Its Linux host, linux-host1, uses 10.23.23.1/24.

PE2: 10.1.105.241, customer sub-interface XGigabitEthernet0/0/30.2323. Its Linux host, linux-host2, uses 10.23.23.2/24.

MPLS, LDP, MPLS L2VPN and the parent interface mode must already be configured. Replace the lab addresses and interface names with your own. Record your software release with display version; the original capture does not specify it.

Use a test service and keep management access available. The reflection test is intended to trigger a forwarding block on PE1. It returns selected probes from linux-host1 without creating a physical cable loop.

1. Configure the VSI Service

On PE1, configure the service and enable loop detection on its VLAN 2323 sub-interface:

system-view
vsi FRA-AMS_TEST
pwsignal ldp
vsi-id 2323232323
peer 10.1.105.241
quit
mtu 9216
quit
mpls ldp remote-peer PE2
remote-ip 10.1.105.241
quit
interface XGigabitEthernet0/0/36.2323
description FRA-AMS_TEST
mtu 9216
dot1q termination vid 2323
l2 binding vsi FRA-AMS_TEST
loop-detect enable
loop-detect recovery-time 60
loop-detect detection vid 2323
quit
return

The three loop-detection commands enable the feature, configure a 60-second recovery period and select VLAN 2323 for the probes. These settings belong to the sub-interface carrying this service.

On PE2, configure the other end. Loop detection is enabled only on PE1 in this test:

system-view
vsi FRA-AMS_TEST
pwsignal ldp
vsi-id 2323232323
peer 10.1.160.240
quit
mtu 9216
quit
mpls ldp remote-peer PE1
remote-ip 10.1.160.240
quit
interface XGigabitEthernet0/0/30.2323
description FRA-AMS_TEST
mtu 9216
dot1q termination vid 2323
l2 binding vsi FRA-AMS_TEST
quit
return

2. Confirm Connectivity Between the Hosts

The Linux hosts need iproute2, ping, tcpdump and Python 3. Run the host configuration commands as root. The examples assume eth0 is already up and connected to the tagged service.

On linux-host1:

ip link add link eth0 name vlan2323 type vlan id 2323
ip link set vlan2323 up
ip address add 10.23.23.1/24 dev vlan2323

On linux-host2:

ip link add link eth0 name vlan2323 type vlan id 2323
ip link set vlan2323 up
ip address add 10.23.23.2/24 dev vlan2323

If vlan2323 or its address already exists, reuse it. Once both hosts are configured, check connectivity from linux-host1:

ping 10.23.23.2

Recorded replies:

64 bytes from 10.23.23.2: icmp_seq=1 ttl=64 time=14.2 ms
64 bytes from 10.23.23.2: icmp_seq=2 ttl=64 time=7.07 ms
64 bytes from 10.23.23.2: icmp_seq=3 ttl=64 time=7.08 ms

Stop ping with Ctrl+C. Confirm connectivity before testing protection so an existing service problem is not mistaken for a loop-detection block.

3. Find the Detection Frames

On linux-host1, capture the probes:

tcpdump -i vlan2323 -n

One frame from the lab capture:

16:13:56.758238 14:eb:08:27:71:90 > ff:ff:ff:ff:ff:ff, ethertype Unknown (0x9998), length 60:

Look for EtherType 0x9998, a broadcast destination and the probe source MAC. Here the source is 14:eb:08:27:71:90. Use the MAC from your own capture in the next step.

Probes arrived approximately every five seconds in this lab. The Unknown label simply means tcpdump did not decode the protocol. Stop the capture with Ctrl+C.

4. Run the Probe Reflection Test

Save the script from the final section as huawei_loop_test.py on linux-host1. It uses only the Python standard library. Start in listening mode:

sudo python3 huawei_loop_test.py -i vlan2323 --timeout 20

The recorded run ended with:

16:34:13 Finished: matched=4, reflected=0

matched=4 means four probes were received. reflected=0 confirms that this passive check sent nothing back.

Now return up to three probes from the selected source MAC:

sudo python3 huawei_loop_test.py \
-i vlan2323 \
--src-mac 14:eb:08:27:71:90 \
--reflect \
--count 3 \
--timeout 20

Recorded output, shortened to the transmission results:

16:36:08 REFLECTED 1/3: unchanged frame
16:36:13 REFLECTED 2/3: unchanged frame
16:36:18 REFLECTED 3/3: unchanged frame
16:36:18 Finished: matched=3, reflected=3

The script returns matching frames unchanged and stops after the requested count or timeout. --count 3 limits the script; it does not define the switch's detection threshold.

5. Check the Protected Sub-Interface

Immediately after reflection, run this command on PE1:

display interface XGigabitEthernet 0/0/36.2323

Recorded result, with the hostname changed to PE1:

<PE1>display interface XGigabitEthernet 0/0/36.2323
XGigabitEthernet0/0/36.2323 current state : UP
Line protocol current state : UP (LOOP-DETECT BLOCK)
Description:FRA-AMS_TEST
Route Port,The Maximum Transmit Unit is 9216

LOOP-DETECT BLOCK is the confirmation. Checking only the first UP line would miss it. The returned probes triggered protection on .2323.

To verify isolation on a shared physical port, also monitor an independent VLAN during the test. The recorded result confirms the block on this sub-interface; it contains no traffic measurements for other services.

6. Check Recovery

Once the reflector has stopped, allow the configured 60-second recovery period to pass. On PE1, inspect the sub-interface again:

display interface XGigabitEthernet 0/0/36.2323

Then check connectivity from linux-host1:

ping -c 5 10.23.23.2

Confirm that LOOP-DETECT BLOCK disappears and replies resume. The original log does not include this follow-up, so recovery is a check to complete in your lab, rather than a measured result from this test.

Quick Troubleshooting

No probes: check VLAN tagging, the VSI binding and loop-detect detection vid 2323. Confirm baseline connectivity first.

Script refuses the interface: use vlan2323, not eth0, and run with sudo. The script verifies the Linux VLAN ID before opening the test.

No reflection or block: verify the source MAC and include --reflect. Check PE1 promptly, before recovery can clear the block.

Still blocked: confirm the script has exited and investigate any other path returning probes.

Test Script

Use this command on linux-host1 to create the script. It listens by default, requires an explicit source MAC for reflection and limits each active run to five frames at most. It ignores its own outgoing packet copies.

cat > huawei_loop_test.py <<'PY'
#!/usr/bin/env python3
"""Bounded Huawei 0x9998 probe reflector for a Linux VLAN interface.

Listen only by default. --reflect requires one explicit source MAC.
Use only on an authorized test service: a successful test can block it.
"""

import argparse
import re
import socket
import sys
import time
from pathlib import Path

ETHERTYPE = 0x9998
BROADCAST = b"\xff" * 6
MIN_INTERVAL = 1.0 # Never reflect more than one frame per second.


def log(message: str) -> None:
print(time.strftime("%H:%M:%S"), message, flush=True)


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("-i", "--interface", required=True,
help="Linux VLAN interface, e.g. vlan2323")
parser.add_argument("--vlan", type=int, default=2323,
help="Required VLAN ID (default: 2323)")
parser.add_argument("--src-mac", help="Reflect only this probe source MAC")
parser.add_argument("--reflect", action="store_true",
help="Transmit matching probes back; otherwise listen only")
parser.add_argument("--count", type=int, default=1,
help="Maximum frames to reflect: 1-5 (default: 1)")
parser.add_argument("--timeout", type=int, default=20,
help="Maximum run time: 1-30 seconds (default: 20)")
args = parser.parse_args()

if not 1 <= args.count <= 5 or not 1 <= args.timeout <= 30:
parser.error("--count must be 1-5 and --timeout must be 1-30")
if not 1 <= args.vlan <= 4094:
parser.error("--vlan must be 1-4094")
if args.reflect and not args.src_mac:
parser.error("--reflect requires --src-mac")

source = None
if args.src_mac:
if not re.fullmatch(r"(?:[0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}", args.src_mac):
parser.error("Use MAC format aa:bb:cc:dd:ee:ff")
source = bytes.fromhex(args.src_mac.replace(":", ""))
if source == b"\x00" * 6 or source[0] & 1:
parser.error("The source MAC must be a nonzero unicast MAC")

# Refuse a physical trunk or an interface on the wrong VLAN.
socket.if_nametoindex(args.interface)
try:
vlan_info = Path("/proc/net/vlan", args.interface).read_text()
except OSError:
parser.error("Use an existing Linux VLAN interface, not its parent trunk")
match = re.search(r"\bVID:\s*(\d+)", vlan_info)
if not match or int(match.group(1)) != args.vlan:
parser.error(f"{args.interface} is not VLAN {args.vlan}")

matched = sent = 0
last_sent = float("-inf")
mode = "REFLECT" if args.reflect else "LISTEN ONLY"
log(f"{mode}: {args.interface}, VLAN {args.vlan}, "
f"source={args.src_mac or 'any'}, timeout={args.timeout}s")
if args.reflect:
log(f"WARNING: service may be blocked. Maximum reflections: {args.count}")

# Start with protocol 0 (receive nothing), then bind to this interface
# and EtherType only. The Python AF_PACKET bind protocol is host-order.
with socket.socket(socket.AF_PACKET, socket.SOCK_RAW, 0) as sock:
sock.bind((args.interface, ETHERTYPE))
deadline = time.monotonic() + args.timeout
try:
while time.monotonic() < deadline:
sock.settimeout(max(0.001, min(1.0, deadline - time.monotonic())))
try:
frame, address = sock.recvfrom(65535)
except socket.timeout:
continue

# Only incoming Ethernet broadcasts, never our own TX copies.
if address[0] != args.interface or address[2] != socket.PACKET_BROADCAST:
continue
if len(frame) < 14 or frame[:6] != BROADCAST:
continue
if frame[12:14] != b"\x99\x98":
continue
if source is not None and frame[6:12] != source:
continue

matched += 1
mac = frame[6:12].hex(":")
log(f"RX #{matched}: src={mac}, length={len(frame)}")
now = time.monotonic()
if not args.reflect or now >= deadline:
continue
if now - last_sent < MIN_INTERVAL:
log("Skipped: rate limit")
continue

# Preserve destination, source, EtherType, and payload exactly.
# The VLAN device supplies its VLAN tag on egress.
if sock.send(frame) != len(frame):
raise OSError("Incomplete frame transmission")
sent += 1
last_sent = time.monotonic()
log(f"REFLECTED {sent}/{args.count}: unchanged frame")
if sent >= args.count:
break
except KeyboardInterrupt:
log("Stopped by Ctrl+C")
finally:
log(f"Finished: matched={matched}, reflected={sent}")
return 0


if __name__ == "__main__":
try:
sys.exit(main())
except PermissionError:
sys.exit("ERROR: run with sudo/root (CAP_NET_RAW is required)")
except OSError as exc:
sys.exit(f"ERROR: {exc}")
PY