From db26f4881feb6a97ee5135b99bcebc95b14a68c6 Mon Sep 17 00:00:00 2001 From: Daniel Ding Date: Thu, 4 Sep 2025 16:39:49 +0800 Subject: [PATCH] fea: state for bgp neighbor. --- dist/rootfs/var/openlan/script/frr-client | 51 +++++++++++++++++++++++ dist/rootfs/var/openlan/script/frr-reload | 27 ------------ dist/rootfs/var/openlan/script/frr-server | 23 ++++++++++ pkg/switch/bgp_linux.go | 21 +++++++++- 4 files changed, 93 insertions(+), 29 deletions(-) create mode 100755 dist/rootfs/var/openlan/script/frr-client delete mode 100755 dist/rootfs/var/openlan/script/frr-reload diff --git a/dist/rootfs/var/openlan/script/frr-client b/dist/rootfs/var/openlan/script/frr-client new file mode 100755 index 0000000..45f903e --- /dev/null +++ b/dist/rootfs/var/openlan/script/frr-client @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +import argparse +import socket +import sys + +SOCKET_PATH = "/var/openlan/frr/reloader.sock" + +def receive_message(conn, buffer_size=1024): + data = [] + while True: + chunk = conn.recv(buffer_size) + if not chunk: + break + data.append(chunk) + return b''.join(data).decode('utf-8') + +def client(action): + code = 0 + client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + + try: + client.connect(SOCKET_PATH) + client.send(action.encode('utf-8')) + + response = receive_message(client) + print(f"{response}") + + if action == "reload" and response != "success": + code = 1 + return + except Exception as e: + print(f"Error: {e}") + code = 2 + finally: + client.close() + + return code + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('--reload', action='store_true', help='reload frr') + parser.add_argument('--show-neighbors', action='store_true', help='show bgp neighbor') + args = parser.parse_args() + + code = 0 + if args.reload: + code = client("reload") + elif args.show_neighbors: + code = client("show-neighbors") + sys.exit(code) \ No newline at end of file diff --git a/dist/rootfs/var/openlan/script/frr-reload b/dist/rootfs/var/openlan/script/frr-reload deleted file mode 100755 index 9e4bcd8..0000000 --- a/dist/rootfs/var/openlan/script/frr-reload +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 - -import socket -import sys -import logging - -SOCKET_PATH = "/var/openlan/frr/reloader.sock" - -def client(): - client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - - try: - client.connect(SOCKET_PATH) - message = "reload" - client.send(message.encode('utf-8')) - - response = client.recv(1024).decode('utf-8') - print(f"{response}") - if response != "success": - sys,exit(1) - except Exception as e: - print(f"Error: {e}") - finally: - client.close() - -if __name__ == "__main__": - client() \ No newline at end of file diff --git a/dist/rootfs/var/openlan/script/frr-server b/dist/rootfs/var/openlan/script/frr-server index 16a82eb..9b5d09f 100755 --- a/dist/rootfs/var/openlan/script/frr-server +++ b/dist/rootfs/var/openlan/script/frr-server @@ -3,6 +3,8 @@ import socket import os import logging +import subprocess +import json SOCKET_PATH = "/var/openlan/frr/reloader.sock" @@ -13,12 +15,31 @@ logging.basicConfig( ) logger = logging.getLogger(__name__) +def do_vtyshell(command): + proc = subprocess.Popen(['vtysh', '-c', command], stdout=subprocess.PIPE, text=True) + stdout, stderr = proc.communicate() + if proc.returncode == 0: + return True, stdout + return False, stderr + def handle_reload(): code = os.system("/usr/lib/frr/frr-reload") if code == 0: return "success" return "fail" +def handle_show_neighbors(): + ok, data = do_vtyshell('show bgp neighbor json') + if not ok: + return "" + + neighbors = json.loads(data) + status = {} + for addr, nei in neighbors.items(): + status[addr] = {"state": nei.get('bgpState')} + + return json.dumps(status) + def handle_client(server): try: client, _ = server.accept() @@ -30,6 +51,8 @@ def handle_client(server): response = "unsupport" if message == "reload": response = handle_reload() + elif message == "show-neighbors": + response = handle_show_neighbors() client.send(response.encode('utf-8')) logger.debug(f"Sent response: {response}") diff --git a/pkg/switch/bgp_linux.go b/pkg/switch/bgp_linux.go index 1673d7f..fc770df 100644 --- a/pkg/switch/bgp_linux.go +++ b/pkg/switch/bgp_linux.go @@ -2,6 +2,7 @@ package cswitch import ( "os/exec" + "strings" "text/template" "github.com/luscis/openlan/pkg/api" @@ -11,7 +12,7 @@ import ( ) const ( - BgpBin = "/var/openlan/script/frr-reload" + BgpBin = "/var/openlan/script/frr-client" BgpEtc = "/etc/frr/frr.conf" ) @@ -108,7 +109,7 @@ func (w *BgpWorker) save() { func (w *BgpWorker) reload() { w.save() - cmd := exec.Command(BgpBin) + cmd := exec.Command(BgpBin, "--reload") if err := cmd.Run(); err != nil { w.out.Warn("BgpWorker.reload: %s", err) return @@ -142,6 +143,19 @@ func (w *BgpWorker) Get() *schema.Bgp { LocalAs: w.spec.LocalAs, RouterId: w.spec.RouterId, } + + show := map[string]struct { + State string `json:"state"` + }{} + out, err := exec.Command(BgpBin, "--show-neighbors").CombinedOutput() + if err == nil { + if err := libol.Unmarshal(&show, out); err != nil { + w.out.Warn("BgpWorker.Get.Status: %s", err) + } + } else { + w.out.Warn("BgpWorker.Get.Status: %s", err) + } + for _, nei := range w.spec.Neighbors { obj := schema.BgpNeighbor{ Address: nei.Address, @@ -150,6 +164,9 @@ func (w *BgpWorker) Get() *schema.Bgp { Receives: nei.Receives, Advertis: nei.Advertis, } + if state, ok := show[nei.Address]; ok { + obj.State = strings.ToLower(state.State) + } data.Neighbors = append(data.Neighbors, obj) } return data