PNG IHDR x sBIT|d pHYs + tEXtSoftware www.inkscape.org< ,tEXtComment
"""Rt files parser
iproute2 got lot of "map" files, called rt_xxx for most of them,
this module is an helper for all files
"""
from dataclasses import dataclass, field, fields
from pathlib import Path
from typing import Union
@dataclass
class IPRouteRtFile:
filename: str
id2name: dict[int, Union[str, int]] = field(default_factory=dict)
name2id: dict[str, int] = field(default_factory=dict)
# like iproute2 stop at first existing directory
DIRECTORIES = (Path("/etc/iproute2/"), Path("/usr/share/iproute2/"))
def __post_init__(self):
self.load_files()
@classmethod
def get_rt_filename(cls):
"""Helper to get filename when dataclass is not instancied"""
for rt_field in fields(cls):
if rt_field.name == 'filename':
return rt_field.default
raise KeyError(f"no filename in {cls}")
def _iter_files(self, filepath):
d_folder = Path(f'{filepath}.d')
if filepath.exists():
yield filepath
if d_folder.exists():
yield from (p for p in d_folder.iterdir() if p.suffix == '.conf')
def iter_files(self):
next_folder = True
for folder in self.DIRECTORIES:
for filepath in self._iter_files(folder / self.filename):
next_folder = False
yield filepath
if not next_folder:
return
def load_files(self):
self.id2name = {}
self.name2id = {}
for filename in self.iter_files():
with filename.open(encoding='utf-8') as fp:
for line in fp.readlines():
line = line.strip()
if not line or line[0] == '#':
continue
rt_id_as_str, rt_name = line.split()
if rt_id_as_str.startswith("0x"):
rt_id = int(rt_id_as_str[2:], 16)
elif ':' in rt_id_as_str:
# tc handle as class_id string
(major, minor) = [
int(x if x else '0', 16)
for x in rt_id_as_str.split(':')
]
rt_id = (major << 16) | minor
else:
rt_id = int(rt_id_as_str)
if rt_id in self.id2name:
continue # Accept only one rt_name by rt_id
self.id2name[rt_id] = rt_name
self.name2id[rt_name] = rt_id
def get_rt_id(
self, rt_name: Union[str, int], default: Union[int, None] = None
) -> Union[int, None]:
"""Return id from the name.
if rt_name is an int or digits() return it as int
"""
if isinstance(rt_name, int):
return rt_name
if rt_name.isdigit():
return int(rt_name)
if default is None:
return self.name2id[rt_name]
return self.name2id.get(rt_name, default)
def get_rt_name(
self, rt_id: Union[str, int], default: Union[str, None] = None
) -> Union[int, str, None]:
"""Return name from the id.
name not found return id as str
if the id is already a string return it
"""
if isinstance(rt_id, str):
return rt_id
if default is None:
return self.id2name.get(rt_id, rt_id)
return self.id2name.get(rt_id, default)
def __iter__(self):
yield from self.id2name.items()
@dataclass
class EmatchMapFile(IPRouteRtFile):
filename: str = 'ematch_map'
@dataclass
class NlProtosFile(IPRouteRtFile):
filename: str = 'nl_protos'
@dataclass
class RtAddrProtosFile(IPRouteRtFile):
filename: str = 'rt_addrprotos'
@dataclass
class RtDsfieldFile(IPRouteRtFile):
filename: str = 'rt_dsfield'
@dataclass
class GroupFile(IPRouteRtFile):
filename: str = 'group'
@dataclass
class RtProtosFile(IPRouteRtFile):
filename: str = 'rt_protos'
@dataclass
class RtRealmsFile(IPRouteRtFile):
filename: str = 'rt_realms'
@dataclass
class RtScopesFile(IPRouteRtFile):
filename: str = 'rt_scopes'
@dataclass
class RtTablesFile(IPRouteRtFile):
filename: str = 'rt_tables'
@dataclass
class TcClsFile(IPRouteRtFile):
filename: str = 'tc_cls'
def main(cls_list):
for cls in cls_list.values():
try:
assert issubclass(cls, IPRouteRtFile) and cls is not IPRouteRtFile
except (TypeError, AssertionError):
continue
cls = cls()
print(f"==== Show rt maps for: {cls.filename} ===")
print("get_rt_id('default') ==", cls.get_rt_id("default", "not found"))
for rt_id, rt_name in cls:
print(f"{rt_id} {rt_name}")
if __name__ == "__main__":
main(locals())
b IDATxytVսϓ22 A@IR:hCiZ[v*E:WũZA ^dQeQ @ !jZ'>gsV仿$|?g)&x-E