mirror of
https://github.com/hansjone/netx.git
synced 2026-10-09 03:10:46 +08:00
Extract IP/MPLS/IPv6 MTU from ZTE interface detail.
Plain MTU alone missed sibling values in filtered show interface output; also clear Filldown between interfaces so optional IPv6 MTU does not leak. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
f279431c70
commit
a6ea67a8bf
4 changed files with 83 additions and 3 deletions
|
|
@ -18,6 +18,9 @@ _IF_HDR_RE = re.compile(
|
||||||
)
|
)
|
||||||
_DESC_RE = re.compile(r"^\s*Description:\s*(?P<desc>.*?)\s*$", re.I)
|
_DESC_RE = re.compile(r"^\s*Description:\s*(?P<desc>.*?)\s*$", re.I)
|
||||||
_BW_RE = re.compile(r"^\s*BW\s+(?P<bw>.+?)\s*$", re.I)
|
_BW_RE = re.compile(r"^\s*BW\s+(?P<bw>.+?)\s*$", re.I)
|
||||||
|
_IP_MTU_RE = re.compile(r"^\s*IP\s+MTU\s+(?P<mtu>\d+)\s+bytes", re.I)
|
||||||
|
_IPV6_MTU_RE = re.compile(r"^\s*IPv6\s+MTU\s+(?P<mtu>\d+)\s+bytes", re.I)
|
||||||
|
_MPLS_MTU_RE = re.compile(r"^\s*MPLS\s+MTU\s+(?P<mtu>\d+)\s+bytes", re.I)
|
||||||
_MTU_RE = re.compile(r"^\s*MTU\s+(?P<mtu>\d+)\s+bytes", re.I)
|
_MTU_RE = re.compile(r"^\s*MTU\s+(?P<mtu>\d+)\s+bytes", re.I)
|
||||||
_MEDIA_RE = re.compile(r"^\s*The\s+port\s+is\s+(?P<media>\S+)", re.I)
|
_MEDIA_RE = re.compile(r"^\s*The\s+port\s+is\s+(?P<media>\S+)", re.I)
|
||||||
_NEG_RE = re.compile(r"^\s*Negotiation\s+(?P<neg>\S+)", re.I)
|
_NEG_RE = re.compile(r"^\s*Negotiation\s+(?P<neg>\S+)", re.I)
|
||||||
|
|
@ -39,7 +42,10 @@ def _empty_row(iface: str) -> dict[str, Any]:
|
||||||
"port_media": "",
|
"port_media": "",
|
||||||
"negotiation": "",
|
"negotiation": "",
|
||||||
"bw": "",
|
"bw": "",
|
||||||
|
"ip_mtu": "",
|
||||||
"mtu": "",
|
"mtu": "",
|
||||||
|
"mpls_mtu": "",
|
||||||
|
"ipv6_mtu": "",
|
||||||
"rate_period": "",
|
"rate_period": "",
|
||||||
"input_bps": "",
|
"input_bps": "",
|
||||||
"output_bps": "",
|
"output_bps": "",
|
||||||
|
|
@ -82,7 +88,10 @@ def _map_fsm_rows(rows: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
||||||
"port_media": row_get(r, "PORT_MEDIA", "port_media")[:32],
|
"port_media": row_get(r, "PORT_MEDIA", "port_media")[:32],
|
||||||
"negotiation": row_get(r, "NEGOTIATION", "negotiation")[:32],
|
"negotiation": row_get(r, "NEGOTIATION", "negotiation")[:32],
|
||||||
"bw": row_get(r, "BW_RAW", "bw")[:64],
|
"bw": row_get(r, "BW_RAW", "bw")[:64],
|
||||||
|
"ip_mtu": row_get(r, "IP_MTU", "ip_mtu")[:16],
|
||||||
"mtu": row_get(r, "MTU", "mtu")[:16],
|
"mtu": row_get(r, "MTU", "mtu")[:16],
|
||||||
|
"mpls_mtu": row_get(r, "MPLS_MTU", "mpls_mtu")[:16],
|
||||||
|
"ipv6_mtu": row_get(r, "IPV6_MTU", "ipv6_mtu")[:16],
|
||||||
"rate_period": row_get(r, "RATE_PERIOD", "rate_period")[:16],
|
"rate_period": row_get(r, "RATE_PERIOD", "rate_period")[:16],
|
||||||
"input_bps": row_get(r, "INPUT_BPS", "input_bps")[:32],
|
"input_bps": row_get(r, "INPUT_BPS", "input_bps")[:32],
|
||||||
"output_bps": row_get(r, "OUTPUT_BPS", "output_bps")[:32],
|
"output_bps": row_get(r, "OUTPUT_BPS", "output_bps")[:32],
|
||||||
|
|
@ -136,6 +145,18 @@ def _hand_parse(*, raw_text: str, **_kw: Any) -> list[dict[str, Any]]:
|
||||||
if m:
|
if m:
|
||||||
cur["bw"] = m.group("bw").strip()[:64]
|
cur["bw"] = m.group("bw").strip()[:64]
|
||||||
continue
|
continue
|
||||||
|
m = _IP_MTU_RE.match(line)
|
||||||
|
if m:
|
||||||
|
cur["ip_mtu"] = m.group("mtu")[:16]
|
||||||
|
continue
|
||||||
|
m = _IPV6_MTU_RE.match(line)
|
||||||
|
if m:
|
||||||
|
cur["ipv6_mtu"] = m.group("mtu")[:16]
|
||||||
|
continue
|
||||||
|
m = _MPLS_MTU_RE.match(line)
|
||||||
|
if m:
|
||||||
|
cur["mpls_mtu"] = m.group("mtu")[:16]
|
||||||
|
continue
|
||||||
m = _MTU_RE.match(line)
|
m = _MTU_RE.match(line)
|
||||||
if m:
|
if m:
|
||||||
cur["mtu"] = m.group("mtu")[:16]
|
cur["mtu"] = m.group("mtu")[:16]
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,10 @@ _IFACE_DETAIL_FIELDS: list[FieldDef] = [
|
||||||
FieldDef("in_util", length=16, role="counter", display_name="In Util%"),
|
FieldDef("in_util", length=16, role="counter", display_name="In Util%"),
|
||||||
FieldDef("out_util", length=16, role="counter", display_name="Out Util%"),
|
FieldDef("out_util", length=16, role="counter", display_name="Out Util%"),
|
||||||
FieldDef("bw", length=64, role="meta", display_name="BW"),
|
FieldDef("bw", length=64, role="meta", display_name="BW"),
|
||||||
|
FieldDef("ip_mtu", length=16, role="meta", display_name="IP MTU"),
|
||||||
FieldDef("mtu", length=16, role="meta", display_name="MTU"),
|
FieldDef("mtu", length=16, role="meta", display_name="MTU"),
|
||||||
|
FieldDef("mpls_mtu", length=16, role="meta", display_name="MPLS MTU"),
|
||||||
|
FieldDef("ipv6_mtu", length=16, role="meta", display_name="IPv6 MTU"),
|
||||||
FieldDef("ifindex", length=32, role="meta", display_name="ifindex"),
|
FieldDef("ifindex", length=32, role="meta", display_name="ifindex"),
|
||||||
FieldDef("description", length=256, role="meta", display_name="描述"),
|
FieldDef("description", length=256, role="meta", display_name="描述"),
|
||||||
FieldDef("port_media", length=32, role="meta", display_name="Media"),
|
FieldDef("port_media", length=32, role="meta", display_name="Media"),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,10 @@ Value Filldown DESCRIPTION (.+?)
|
||||||
Value Filldown PORT_MEDIA (\S+)
|
Value Filldown PORT_MEDIA (\S+)
|
||||||
Value Filldown NEGOTIATION (\S+)
|
Value Filldown NEGOTIATION (\S+)
|
||||||
Value Filldown BW_RAW (\d+(?:\.\d+)?\s*[kKmMgGtT]?\s*(?:G?bit|bit)/s(?:ec)?)
|
Value Filldown BW_RAW (\d+(?:\.\d+)?\s*[kKmMgGtT]?\s*(?:G?bit|bit)/s(?:ec)?)
|
||||||
|
Value Filldown IP_MTU (\d+)
|
||||||
Value Filldown MTU (\d+)
|
Value Filldown MTU (\d+)
|
||||||
|
Value Filldown MPLS_MTU (\d+)
|
||||||
|
Value Filldown IPV6_MTU (\d+)
|
||||||
Value Filldown RATE_PERIOD (\d+)
|
Value Filldown RATE_PERIOD (\d+)
|
||||||
Value Filldown INPUT_BPS ([\d.]+)
|
Value Filldown INPUT_BPS ([\d.]+)
|
||||||
Value Filldown OUTPUT_BPS ([\d.]+)
|
Value Filldown OUTPUT_BPS ([\d.]+)
|
||||||
|
|
@ -13,11 +16,15 @@ Value IN_UTIL ([\d.]+)
|
||||||
Value OUT_UTIL ([\d.]+)
|
Value OUT_UTIL ([\d.]+)
|
||||||
|
|
||||||
Start
|
Start
|
||||||
|
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Continue.Clearall
|
||||||
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})?
|
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})?
|
||||||
^\s*Description:\s*${DESCRIPTION}\s*$$
|
^\s*Description:\s*${DESCRIPTION}\s*$$
|
||||||
^\s*The\s+port\s+is\s+${PORT_MEDIA}
|
^\s*The\s+port\s+is\s+${PORT_MEDIA}
|
||||||
^\s*Negotiation\s+${NEGOTIATION}
|
^\s*Negotiation\s+${NEGOTIATION}
|
||||||
^\s*BW\s+${BW_RAW}
|
^\s*BW\s+${BW_RAW}
|
||||||
|
^\s*IP\s+MTU\s+${IP_MTU}\s+bytes
|
||||||
|
^\s*IPv6\s+MTU\s+${IPV6_MTU}\s+bytes
|
||||||
|
^\s*MPLS\s+MTU\s+${MPLS_MTU}\s+bytes
|
||||||
^\s*MTU\s+${MTU}\s+bytes
|
^\s*MTU\s+${MTU}\s+bytes
|
||||||
^\s*Rate\s+period\s*:\s*${RATE_PERIOD}\s*s -> Rates
|
^\s*Rate\s+period\s*:\s*${RATE_PERIOD}\s*s -> Rates
|
||||||
^\s*$$
|
^\s*$$
|
||||||
|
|
@ -28,12 +35,14 @@ Rates
|
||||||
^\s*Output\s*:\s*${OUTPUT_BPS}\s*bit/s
|
^\s*Output\s*:\s*${OUTPUT_BPS}\s*bit/s
|
||||||
^\s*Peak\s+rate: -> AfterPeak
|
^\s*Peak\s+rate: -> AfterPeak
|
||||||
^\s*Intf\s+utilization:\s*input\s*${IN_UTIL}%\s+output\s*${OUT_UTIL}% -> Record Start
|
^\s*Intf\s+utilization:\s*input\s*${IN_UTIL}%\s+output\s*${OUT_UTIL}% -> Record Start
|
||||||
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Clearall Start
|
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Continue.Clearall
|
||||||
|
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Start
|
||||||
^\s*$$
|
^\s*$$
|
||||||
^.* -> Rates
|
^.* -> Rates
|
||||||
|
|
||||||
AfterPeak
|
AfterPeak
|
||||||
^\s*Intf\s+utilization:\s*input\s*${IN_UTIL}%\s+output\s*${OUT_UTIL}% -> Record Start
|
^\s*Intf\s+utilization:\s*input\s*${IN_UTIL}%\s+output\s*${OUT_UTIL}% -> Record Start
|
||||||
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Clearall Start
|
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Continue.Clearall
|
||||||
|
^${IFNAME}\s+is\s+${ADMIN_STATE}(?:,\s*ifindex:\s*${IFINDEX})? -> Start
|
||||||
^\s*$$
|
^\s*$$
|
||||||
^.* -> AfterPeak
|
^.* -> AfterPeak
|
||||||
|
|
|
||||||
|
|
@ -265,7 +265,9 @@ gei-0/0/0/1 is up, ifindex: 100
|
||||||
The port is optical
|
The port is optical
|
||||||
Negotiation force
|
Negotiation force
|
||||||
BW 1 Gbit/s
|
BW 1 Gbit/s
|
||||||
|
IP MTU 1500 bytes
|
||||||
MTU 1600 bytes
|
MTU 1600 bytes
|
||||||
|
MPLS MTU 1550 bytes
|
||||||
Rate period : 120 s
|
Rate period : 120 s
|
||||||
Input : 100 bit/s 1 packet/s
|
Input : 100 bit/s 1 packet/s
|
||||||
Output : 200 bit/s 2 packet/s
|
Output : 200 bit/s 2 packet/s
|
||||||
|
|
@ -276,7 +278,10 @@ gei-0/0/0/1 is up, ifindex: 100
|
||||||
gei-0/0/0/2 is administratively down, ifindex: 101
|
gei-0/0/0/2 is administratively down, ifindex: 101
|
||||||
Description: spare
|
Description: spare
|
||||||
BW 1 Gbit/s
|
BW 1 Gbit/s
|
||||||
MTU 1500 bytes
|
IP MTU 8978 bytes
|
||||||
|
MTU 9000 bytes
|
||||||
|
IPv6 MTU 8978 bytes
|
||||||
|
MPLS MTU 8978 bytes
|
||||||
Rate period : 120 s
|
Rate period : 120 s
|
||||||
Input : 0 bit/s 0 packet/s
|
Input : 0 bit/s 0 packet/s
|
||||||
Output : 0 bit/s 0 packet/s
|
Output : 0 bit/s 0 packet/s
|
||||||
|
|
@ -292,7 +297,47 @@ gei-0/0/0/2 is administratively down, ifindex: 101
|
||||||
self.assertEqual(rows[0]["admin"], "up")
|
self.assertEqual(rows[0]["admin"], "up")
|
||||||
self.assertEqual(rows[0]["input_bps"], "100")
|
self.assertEqual(rows[0]["input_bps"], "100")
|
||||||
self.assertEqual(rows[0]["out_util"], "2")
|
self.assertEqual(rows[0]["out_util"], "2")
|
||||||
|
self.assertEqual(rows[0]["ip_mtu"], "1500")
|
||||||
|
self.assertEqual(rows[0]["mtu"], "1600")
|
||||||
|
self.assertEqual(rows[0]["mpls_mtu"], "1550")
|
||||||
|
self.assertEqual(rows[0]["ipv6_mtu"], "")
|
||||||
self.assertEqual(rows[1]["admin"], "admin-down")
|
self.assertEqual(rows[1]["admin"], "admin-down")
|
||||||
|
self.assertEqual(rows[1]["ip_mtu"], "8978")
|
||||||
|
self.assertEqual(rows[1]["mtu"], "9000")
|
||||||
|
self.assertEqual(rows[1]["ipv6_mtu"], "8978")
|
||||||
|
self.assertEqual(rows[1]["mpls_mtu"], "8978")
|
||||||
|
|
||||||
|
# No IPv6 MTU on second iface — must not inherit from previous Filldown.
|
||||||
|
leak_sample = """
|
||||||
|
gei-0/0/0/1 is up, ifindex: 1
|
||||||
|
IP MTU 1500 bytes
|
||||||
|
MTU 1600 bytes
|
||||||
|
IPv6 MTU 8978 bytes
|
||||||
|
MPLS MTU 1550 bytes
|
||||||
|
Rate period : 120 s
|
||||||
|
Input : 1 bit/s
|
||||||
|
Output : 2 bit/s
|
||||||
|
Intf utilization: input 1% output 2%
|
||||||
|
gei-0/0/0/2 is up, ifindex: 2
|
||||||
|
IP MTU 1500 bytes
|
||||||
|
MTU 1600 bytes
|
||||||
|
MPLS MTU 1550 bytes
|
||||||
|
Rate period : 120 s
|
||||||
|
Input : 0 bit/s
|
||||||
|
Output : 0 bit/s
|
||||||
|
Intf utilization: input 0% output 0%
|
||||||
|
"""
|
||||||
|
leak_rows = normalize_interface_detail(
|
||||||
|
raw_text=leak_sample,
|
||||||
|
vendor="zte",
|
||||||
|
device_type="zte_zxros",
|
||||||
|
command="show interface",
|
||||||
|
)
|
||||||
|
self.assertEqual(len(leak_rows), 2)
|
||||||
|
self.assertEqual(leak_rows[0]["ipv6_mtu"], "8978")
|
||||||
|
self.assertEqual(leak_rows[1]["ipv6_mtu"], "")
|
||||||
|
self.assertEqual(leak_rows[1]["ip_mtu"], "1500")
|
||||||
|
self.assertEqual(leak_rows[1]["mpls_mtu"], "1550")
|
||||||
|
|
||||||
cmd = (
|
cmd = (
|
||||||
"show interface | include ifindex|BW|The port is|MTU|Negotiation|"
|
"show interface | include ifindex|BW|The port is|MTU|Negotiation|"
|
||||||
|
|
@ -302,6 +347,8 @@ gei-0/0/0/2 is administratively down, ifindex: 101
|
||||||
self.assertIsNotNone(hit)
|
self.assertIsNotNone(hit)
|
||||||
assert hit is not None
|
assert hit is not None
|
||||||
self.assertEqual(hit.profile.profile_id, "zte.interface_detail")
|
self.assertEqual(hit.profile.profile_id, "zte.interface_detail")
|
||||||
|
field_names = {f.name for f in hit.profile.fields}
|
||||||
|
self.assertTrue({"ip_mtu", "mtu", "mpls_mtu", "ipv6_mtu"} <= field_names)
|
||||||
|
|
||||||
hit6 = match_command(
|
hit6 = match_command(
|
||||||
vendor_key="zte",
|
vendor_key="zte",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue