]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Python CLI Package: Protocol scaffolding for Kernel, Device, Direct, Babel and RAdv
authorMaria Matejka <mq@ucw.cz>
Sat, 20 May 2023 09:51:40 +0000 (11:51 +0200)
committerMaria Matejka <mq@ucw.cz>
Tue, 23 May 2023 11:44:48 +0000 (13:44 +0200)
This choice comes from my own local setup where I use exactly these protocols.
Other protocols will be added later.

python/BIRD/Basic.py
python/BIRD/Protocol/Babel.py [new file with mode: 0644]
python/BIRD/Protocol/Device.py [new file with mode: 0644]
python/BIRD/Protocol/Kernel.py [new file with mode: 0644]
python/BIRD/Protocol/RAdv.py [new file with mode: 0644]
python/BIRD/Protocol/__init__.py [new file with mode: 0644]
python/BIRD/__init__.py
python/test.py

index 413da117eefb640a65c61f0872980834f0082f8b..01ff0d6f4b9e5f5ae1ac92708ee83d8f76ce8d3e 100644 (file)
@@ -29,3 +29,6 @@ class Code:
     Welcome = 1
     Status = 13
     Version = 1000
+    ProtocolInfo = 1002
+    ProtocolDetails = 1006
+    ProtocolListHeader = 2002
diff --git a/python/BIRD/Protocol/Babel.py b/python/BIRD/Protocol/Babel.py
new file mode 100644 (file)
index 0000000..b2f31d8
--- /dev/null
@@ -0,0 +1,6 @@
+from BIRD.Protocol import Protocol, ProtocolList
+
+class BabelProtocol(Protocol):
+    match = "Babel"
+
+ProtocolList.register(BabelProtocol)
diff --git a/python/BIRD/Protocol/Device.py b/python/BIRD/Protocol/Device.py
new file mode 100644 (file)
index 0000000..521bf6f
--- /dev/null
@@ -0,0 +1,4 @@
+import asyncio
+
+from BIRD.Basic import Basic
+from BIRD.Protocol import Protocol
diff --git a/python/BIRD/Protocol/Kernel.py b/python/BIRD/Protocol/Kernel.py
new file mode 100644 (file)
index 0000000..bbbf41a
--- /dev/null
@@ -0,0 +1,16 @@
+from BIRD.Protocol import Protocol, ProtocolList
+
+class DeviceProtocol(Protocol):
+    match = "Device"
+
+ProtocolList.register(DeviceProtocol)
+
+class DirectProtocol(Protocol):
+    match = "Direct"
+
+ProtocolList.register(DirectProtocol)
+
+class KernelProtocol(Protocol):
+    match = "Kernel"
+
+ProtocolList.register(KernelProtocol)
diff --git a/python/BIRD/Protocol/RAdv.py b/python/BIRD/Protocol/RAdv.py
new file mode 100644 (file)
index 0000000..0792d87
--- /dev/null
@@ -0,0 +1,6 @@
+from BIRD.Protocol import Protocol, ProtocolList
+
+class RAdvProtocol(Protocol):
+    match = "RAdv"
+
+ProtocolList.register(RAdvProtocol)
diff --git a/python/BIRD/Protocol/__init__.py b/python/BIRD/Protocol/__init__.py
new file mode 100644 (file)
index 0000000..beaf66e
--- /dev/null
@@ -0,0 +1,78 @@
+import asyncio
+
+from BIRD.Basic import Basic, BIRDException, Code
+
+class ProtocolException(Exception):
+    def __init__(self, msg):
+        Exception.__init__(self, f"Failed to parse protocol {self.protocol_name}: {msg}")
+
+class ProtocolListException(Exception):
+    def __init__(self, msg):
+        Exception.__init__(self, f"Failed to parse protocol list: {msg}")
+
+class ProtocolList(Basic):
+    match = {}
+#    def __init__(self, **kwargs):
+#        super().__init__(**kwargs)
+
+    def register(sub):
+        if sub.match in ProtocolList.match:
+            raise BIRDException(f"Protocol match {sub.match} already registered for {ProtocolList.match[sub.match]}") 
+
+        ProtocolList.match[sub.match] = sub
+
+    async def update(self):
+        self.data = {}
+
+        await self.bird.cli.open()
+        data = await self.bird.cli.socket.command("show protocols all")
+
+        # Get header
+        if data[0]["code"] != Code.ProtocolListHeader:
+            raise ProtocolListException(f"First line is not protocol list header, got {data[0]}")
+
+        if data[0]["data"].split() != ['Name', 'Proto', 'Table', 'State', 'Since', 'Info']:
+            raise ProtocolListException(f"Strange protocol list header: {data[0]['data']}")
+
+        data.pop(0)
+
+        for line in data:
+            if line["code"] == Code.ProtocolInfo:
+                kwargs = Protocol.parse_info(line["data"])
+                
+                if (name := kwargs["name"]) in self.data:
+                    raise ProtocolListException(f"Duplicate protocol {name}")
+
+                if (m := kwargs["match"]) in self.match:
+                    del kwargs["match"]
+                    kwargs["bird"] = self.bird
+                    self.data[name] = self.match[m](**kwargs)
+                else:
+                    raise ProtocolListException(f"Unknown protocol kind {m}")
+
+
+class Protocol(Basic):
+    def __init__(self, name, state, last_change, info, **kwargs):
+        super().__init__(**kwargs)
+
+        self.name = name
+        self.state = state
+        self.last_change = last_change
+        self.info = info
+
+    def parse_info(data):
+        s = data.split(maxsplit=5) + [None]
+        assert(len(s) <= 7)
+        if len(s) < 6:
+            raise ProtocolListException(f"Strange protocol info: {data}")
+
+        s.append(None)
+        s.pop(2) # drop the default table name, it's a BIRD 1 anachronism
+        return dict(zip(
+            ["name", "match", "state", "last_change", "info"],
+            s
+            ))
+
+import BIRD.Protocol.Kernel
+import BIRD.Protocol.Babel
+import BIRD.Protocol.RAdv
index 2d49ef49f5050afded9e6efffcc8725a142ae995..5511be8949b87762a46986dd23cab687e06ffb4b 100644 (file)
@@ -5,6 +5,7 @@ from datetime import datetime
 from BIRD.Basic import BIRDException
 from BIRD.Socket import Socket
 from BIRD.Status import Status, Version
+from BIRD.Protocol import ProtocolList
 
 from BIRD.Config import Timestamp, ProtocolConfig, DeviceProtocolConfig
 
@@ -111,8 +112,9 @@ class CLI:
 class BIRD:
     def __init__(self, socket=Path("bird.ctl")):
         self.cli = CLI(socket)
-        self.version = Version(self)
-        self.status = Status(self)
+        self.version = Version(bird=self)
+        self.status = Status(bird=self)
+        self.protocols = ProtocolList(bird=self)
 
         self.within = False
 
index 31131bfcf7850c7ba49969ad065145ea5cfac6e2..ede00810edc063d40b3998ec082f8144517c1eca 100644 (file)
@@ -9,4 +9,7 @@ async def main():
         await b.status.update()
         print(b.status)
 
+        await b.protocols.update()
+        print(b.protocols)
+
 asyncio.run(main())