mirror of
https://github.com/luscis/openlan.git
synced 2025-10-19 07:14:32 +08:00
fea: support bgp as external.
This commit is contained in:
106
cmd/api/v5/bgp.go
Normal file
106
cmd/api/v5/bgp.go
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package v5
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/luscis/openlan/cmd/api"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// openlan bgp enable --route-id 1.1.1.1 --as-path 30
|
||||||
|
// openlan bgp disable
|
||||||
|
// openlan bgp add neighbor --address 1.1.1.2 --remote-as 32
|
||||||
|
|
||||||
|
type BGP struct {
|
||||||
|
Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BGP) Url(prefix string) string {
|
||||||
|
return prefix + "/api/bgp"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BGP) List(c *cli.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BGP) Enable(c *cli.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BGP) Disable(c *cli.Context) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b BGP) Commands(app *api.App) {
|
||||||
|
app.Command(&cli.Command{
|
||||||
|
Name: "bgp",
|
||||||
|
Usage: "External BGP",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "ls",
|
||||||
|
Usage: "Display bgp",
|
||||||
|
Aliases: []string{"ls"},
|
||||||
|
Action: b.List,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "enable",
|
||||||
|
Usage: "Enable bgp",
|
||||||
|
Action: b.Enable,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "disable",
|
||||||
|
Usage: "Disable bgp",
|
||||||
|
Action: b.Disable,
|
||||||
|
},
|
||||||
|
Neighbor{}.Commands(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type Neighbor struct {
|
||||||
|
Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Neighbor) Url(prefix string) string {
|
||||||
|
return prefix + "/api/bgp/neighbor/"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Neighbor) Add(c *cli.Context) error {
|
||||||
|
url := s.Url(c.String("url"))
|
||||||
|
|
||||||
|
clt := s.NewHttp(c.String("token"))
|
||||||
|
if err := clt.PostJSON(url, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Neighbor) Remove(c *cli.Context) error {
|
||||||
|
url := s.Url(c.String("url"))
|
||||||
|
|
||||||
|
clt := s.NewHttp(c.String("token"))
|
||||||
|
if err := clt.DeleteJSON(url, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Neighbor) Commands() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "neighbor",
|
||||||
|
Usage: "BGP neighbor",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "Add BGP neighbor",
|
||||||
|
Action: s.Add,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Aliases: []string{"rm"},
|
||||||
|
Usage: "Remove BGP neighbor",
|
||||||
|
Action: s.Remove,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@@ -41,4 +41,5 @@ func Commands(app *api.App) {
|
|||||||
ZTrust{}.Commands(app)
|
ZTrust{}.Commands(app)
|
||||||
Rate{}.Commands(app)
|
Rate{}.Commands(app)
|
||||||
Ceci{}.Commands(app)
|
Ceci{}.Commands(app)
|
||||||
|
BGP{}.Commands(app)
|
||||||
}
|
}
|
||||||
|
@@ -206,12 +206,12 @@ func (s SNAT) Commands() *cli.Command {
|
|||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "enable",
|
Name: "enable",
|
||||||
Usage: "enable snat",
|
Usage: "Enable snat",
|
||||||
Action: s.Enable,
|
Action: s.Enable,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "disable",
|
Name: "disable",
|
||||||
Usage: "disable snat",
|
Usage: "Disable snat",
|
||||||
Action: s.Disable,
|
Action: s.Disable,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
41
dist/rootfs/etc/frr/daemons
vendored
41
dist/rootfs/etc/frr/daemons
vendored
@@ -1,41 +0,0 @@
|
|||||||
bgpd=yes
|
|
||||||
ospfd=no
|
|
||||||
ospf6d=no
|
|
||||||
ripd=no
|
|
||||||
ripngd=no
|
|
||||||
isisd=no
|
|
||||||
pimd=no
|
|
||||||
pim6d=no
|
|
||||||
ldpd=no
|
|
||||||
nhrpd=no
|
|
||||||
eigrpd=no
|
|
||||||
babeld=no
|
|
||||||
sharpd=no
|
|
||||||
pbrd=no
|
|
||||||
bfdd=no
|
|
||||||
fabricd=no
|
|
||||||
vrrpd=no
|
|
||||||
pathd=no
|
|
||||||
|
|
||||||
vtysh_enable=yes
|
|
||||||
zebra_options=" -A 127.0.0.1 --limit-fds=100000 -s 90000000 --limit-fds=100000"
|
|
||||||
mgmtd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
bgpd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
ospfd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
ospf6d_options=" -A ::1 --limit-fds=100000"
|
|
||||||
ripd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
ripngd_options=" -A ::1 --limit-fds=100000"
|
|
||||||
isisd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
pimd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
pim6d_options=" -A ::1 --limit-fds=100000"
|
|
||||||
ldpd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
nhrpd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
eigrpd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
babeld_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
sharpd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
pbrd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
staticd_options="-A 127.0.0.1 --limit-fds=100000"
|
|
||||||
bfdd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
fabricd_options="-A 127.0.0.1 --limit-fds=100000"
|
|
||||||
vrrpd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
||||||
pathd_options=" -A 127.0.0.1 --limit-fds=100000"
|
|
25
dist/rootfs/etc/openlan/frr/bgpip4.conf.1
vendored
Normal file
25
dist/rootfs/etc/openlan/frr/bgpip4.conf.1
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
!
|
||||||
|
ip prefix-list 192.168.11.252-out seq 10 permit 192.168.44.0/24
|
||||||
|
ip prefix-list 192.168.11.252-out seq 11 permit 192.168.45.0/24
|
||||||
|
!
|
||||||
|
router bgp 1
|
||||||
|
bgp router-id 192.168.11.254
|
||||||
|
no bgp default ipv4-unicast
|
||||||
|
neighbor 192.168.11.252 remote-as 2
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
redistribute kernel
|
||||||
|
neighbor 192.168.11.252 activate
|
||||||
|
neighbor 192.168.11.252 route-map 192.168.11.252-in in
|
||||||
|
neighbor 192.168.11.252 route-map 192.168.11.252-out out
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
route-map 192.168.11.252-in permit 10
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
route-map 192.168.11.252-out permit 10
|
||||||
|
match ip address prefix-list 192.168.11.252-out
|
||||||
|
exit
|
||||||
|
!
|
25
dist/rootfs/etc/openlan/frr/bgpip4.conf.2
vendored
Normal file
25
dist/rootfs/etc/openlan/frr/bgpip4.conf.2
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
!
|
||||||
|
ip prefix-list 192.168.11.254-out.1 seq 5 permit 192.168.33.0/24
|
||||||
|
!
|
||||||
|
router bgp 2
|
||||||
|
bgp router-id 192.168.11.252
|
||||||
|
no bgp default ipv4-unicast
|
||||||
|
neighbor 192.168.11.254 remote-as 1
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
redistribute kernel
|
||||||
|
neighbor 192.168.11.254 activate
|
||||||
|
neighbor 192.168.11.254 route-map 192.168.11.254-in in
|
||||||
|
neighbor 192.168.11.254 route-map 192.168.11.254-out out
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
route-map 192.168.11.254-out permit 10
|
||||||
|
match ip address prefix-list 192.168.11.254-out.1
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
route-map 192.168.11.254-in permit 10
|
||||||
|
exit
|
||||||
|
!
|
||||||
|
end
|
41
dist/rootfs/etc/openlan/frr/daemons
vendored
Normal file
41
dist/rootfs/etc/openlan/frr/daemons
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
bgpd=yes
|
||||||
|
ospfd=no
|
||||||
|
ospf6d=no
|
||||||
|
ripd=no
|
||||||
|
ripngd=no
|
||||||
|
isisd=no
|
||||||
|
pimd=no
|
||||||
|
pim6d=no
|
||||||
|
ldpd=no
|
||||||
|
nhrpd=no
|
||||||
|
eigrpd=no
|
||||||
|
babeld=no
|
||||||
|
sharpd=no
|
||||||
|
pbrd=no
|
||||||
|
bfdd=no
|
||||||
|
fabricd=no
|
||||||
|
vrrpd=no
|
||||||
|
pathd=no
|
||||||
|
|
||||||
|
vtysh_enable=yes
|
||||||
|
zebra_options=" -A 127.0.0.1 -s 90000000"
|
||||||
|
mgmtd_options=" -A 127.0.0.1"
|
||||||
|
bgpd_options=" -A 127.0.0.1"
|
||||||
|
ospfd_options=" -A 127.0.0.1"
|
||||||
|
ospf6d_options=" -A ::1"
|
||||||
|
ripd_options=" -A 127.0.0.1"
|
||||||
|
ripngd_options=" -A ::1"
|
||||||
|
isisd_options=" -A 127.0.0.1"
|
||||||
|
pimd_options=" -A 127.0.0.1"
|
||||||
|
pim6d_options=" -A ::1"
|
||||||
|
ldpd_options=" -A 127.0.0.1"
|
||||||
|
nhrpd_options=" -A 127.0.0.1"
|
||||||
|
eigrpd_options=" -A 127.0.0.1"
|
||||||
|
babeld_options=" -A 127.0.0.1"
|
||||||
|
sharpd_options=" -A 127.0.0.1"
|
||||||
|
pbrd_options=" -A 127.0.0.1"
|
||||||
|
staticd_options="-A 127.0.0.1"
|
||||||
|
bfdd_options=" -A 127.0.0.1"
|
||||||
|
fabricd_options="-A 127.0.0.1"
|
||||||
|
vrrpd_options=" -A 127.0.0.1"
|
||||||
|
pathd_options=" -A 127.0.0.1"
|
14
dist/rootfs/etc/openlan/switch/network/bgp.json.example
vendored
Executable file
14
dist/rootfs/etc/openlan/switch/network/bgp.json.example
vendored
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "bgp",
|
||||||
|
"provider": "bgp",
|
||||||
|
"specifies": {
|
||||||
|
"localas": 30,
|
||||||
|
"routeid": "192.168.11.1",
|
||||||
|
"neighbors": [
|
||||||
|
{
|
||||||
|
"remoteas": 32,
|
||||||
|
"address": "192.168.11.11"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
33
dist/rootfs/var/openlan/script/frr-reload
vendored
Executable file
33
dist/rootfs/var/openlan/script/frr-reload
vendored
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import logging
|
||||||
|
|
||||||
|
SOCKET_PATH = "/var/openlan/frr/reloader.sock"
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s [%(levelname)s] %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def client():
|
||||||
|
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
|
||||||
|
try:
|
||||||
|
client.connect(SOCKET_PATH)
|
||||||
|
|
||||||
|
message = "reload"
|
||||||
|
logger.debug(f"Sent action: {message}")
|
||||||
|
client.send(message.encode('utf-8'))
|
||||||
|
|
||||||
|
response = client.recv(1024).decode('utf-8')
|
||||||
|
logger.debug(f"Received response: {response}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error: {e}")
|
||||||
|
finally:
|
||||||
|
client.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
client()
|
65
dist/rootfs/var/openlan/script/frr-server
vendored
Executable file
65
dist/rootfs/var/openlan/script/frr-server
vendored
Executable file
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
SOCKET_PATH = "/var/openlan/frr/reloader.sock"
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s [%(levelname)s] %(message)s',
|
||||||
|
datefmt='%Y-%m-%d %H:%M:%S',
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def handle_reload():
|
||||||
|
code = os.system("/usr/lib/frr/frr-reload")
|
||||||
|
if code == 0:
|
||||||
|
return "success"
|
||||||
|
return "fail"
|
||||||
|
|
||||||
|
def handle_client(server):
|
||||||
|
try:
|
||||||
|
client, _ = server.accept()
|
||||||
|
with client:
|
||||||
|
data = client.recv(1024)
|
||||||
|
message = data.decode('utf-8')
|
||||||
|
logger.debug(f"Received action: {message}")
|
||||||
|
|
||||||
|
response = "unsupport"
|
||||||
|
if message == "reload":
|
||||||
|
response = handle_reload()
|
||||||
|
|
||||||
|
client.send(response.encode('utf-8'))
|
||||||
|
logger.debug(f"Sent response: {response}")
|
||||||
|
client.close()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error handling client: {e}")
|
||||||
|
|
||||||
|
def start_server():
|
||||||
|
if os.path.exists(SOCKET_PATH):
|
||||||
|
os.unlink(SOCKET_PATH)
|
||||||
|
|
||||||
|
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
try:
|
||||||
|
server.bind(SOCKET_PATH)
|
||||||
|
server.listen(5)
|
||||||
|
logger.info(f"Start server at {SOCKET_PATH}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
handle_client(server)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Server error: {e}")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
server.close()
|
||||||
|
if os.path.exists(SOCKET_PATH):
|
||||||
|
os.unlink(SOCKET_PATH)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
start_server()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
logger.info("\nServer terminated by user")
|
24
dist/rootfs/var/openlan/script/frr.sh
vendored
Executable file
24
dist/rootfs/var/openlan/script/frr.sh
vendored
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
sed -i 's/is\ not\ "/\!=\ "/' /usr/lib/frr/frr-reload.py
|
||||||
|
|
||||||
|
if [ ! -e /var/run/frr ]; then
|
||||||
|
mkdir -p /var/run/frr
|
||||||
|
chown frr:frr /var/run/frr
|
||||||
|
fi
|
||||||
|
|
||||||
|
for file in daemons frr.conf vtysh.conf; do
|
||||||
|
if [ -e "/etc/frr/$file" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ -e "/var/openlan/frr/$file" ]; then
|
||||||
|
cp -rvf /var/openlan/frr/$file /etc/frr/$file
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Start reloader server for FRR
|
||||||
|
exec /var/openlan/script/frr-server &
|
||||||
|
|
||||||
|
# Start daemons
|
||||||
|
source /usr/lib/frr/frrcommon.sh
|
||||||
|
/usr/lib/frr/watchfrr $(daemon_list)
|
4
dist/rootfs/var/openlan/script/install.sh
vendored
4
dist/rootfs/var/openlan/script/install.sh
vendored
@@ -33,11 +33,11 @@ function requires() {
|
|||||||
yum update -y
|
yum update -y
|
||||||
yum install -y epel-release
|
yum install -y epel-release
|
||||||
yum install -y openssl net-tools iptables iputils iperf3 tcpdump
|
yum install -y openssl net-tools iptables iputils iperf3 tcpdump
|
||||||
yum install -y openvpn dnsmasq bridge-utils ipset procps wget
|
yum install -y openvpn dnsmasq bridge-utils ipset procps wget frr
|
||||||
elif [ "$sys"x == "debian"x ]; then
|
elif [ "$sys"x == "debian"x ]; then
|
||||||
apt-get update -y
|
apt-get update -y
|
||||||
apt install -y net-tools iptables iproute2 tcpdump ca-certificates iperf3
|
apt install -y net-tools iptables iproute2 tcpdump ca-certificates iperf3
|
||||||
apt install -y openvpn dnsmasq bridge-utils ipset procps wget iputils-ping
|
apt install -y openvpn dnsmasq bridge-utils ipset procps wget iputils-ping frr
|
||||||
fi
|
fi
|
||||||
## Install libreswan from github.
|
## Install libreswan from github.
|
||||||
if [ "$sys"x == "redhat"x ]; then
|
if [ "$sys"x == "redhat"x ]; then
|
||||||
|
@@ -11,12 +11,13 @@ services:
|
|||||||
- /opt/openlan/run/pluto:/run/pluto
|
- /opt/openlan/run/pluto:/run/pluto
|
||||||
frr:
|
frr:
|
||||||
restart: always
|
restart: always
|
||||||
image: "quay.io/frrouting/frr:10.2.1"
|
image: "luscis/openlan:latest.x86_64"
|
||||||
network_mode: host
|
network_mode: host
|
||||||
privileged: true
|
privileged: true
|
||||||
entrypoint: ["/usr/lib/frr/docker-start"]
|
entrypoint: ["/var/openlan/script/frr.sh"]
|
||||||
volumes:
|
volumes:
|
||||||
- /opt/openlan/etc/frr:/etc/frr
|
- /opt/openlan/etc/frr:/etc/frr
|
||||||
|
- /opt/openlan/var/openlan/frr:/var/openlan/frr
|
||||||
switch:
|
switch:
|
||||||
restart: always
|
restart: always
|
||||||
image: "luscis/openlan:latest.x86_64"
|
image: "luscis/openlan:latest.x86_64"
|
||||||
@@ -27,8 +28,11 @@ services:
|
|||||||
- /opt/openlan/etc/openlan:/etc/openlan
|
- /opt/openlan/etc/openlan:/etc/openlan
|
||||||
- /opt/openlan/etc/ipsec.d:/etc/ipsec.d
|
- /opt/openlan/etc/ipsec.d:/etc/ipsec.d
|
||||||
- /opt/openlan/run/pluto:/run/pluto
|
- /opt/openlan/run/pluto:/run/pluto
|
||||||
|
- /opt/openlan/etc/frr:/etc/frr
|
||||||
|
- /opt/openlan/var/openlan/frr:/var/openlan/frr
|
||||||
depends_on:
|
depends_on:
|
||||||
- ipsec
|
- ipsec
|
||||||
|
- frr
|
||||||
proxy:
|
proxy:
|
||||||
restart: always
|
restart: always
|
||||||
image: "luscis/openlan:latest.x86_64"
|
image: "luscis/openlan:latest.x86_64"
|
||||||
|
@@ -125,9 +125,18 @@ type IPSecer interface {
|
|||||||
ListTunnels(call func(obj schema.IPSecTunnel))
|
ListTunnels(call func(obj schema.IPSecTunnel))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Bgper interface {
|
||||||
|
Enable(data schema.Bgp)
|
||||||
|
Disable()
|
||||||
|
AddNeighbor(data schema.BgpNeighbor)
|
||||||
|
DelNeighbor(data schema.BgpNeighbor)
|
||||||
|
ListNeighbor(call func(obj schema.BgpNeighbor))
|
||||||
|
}
|
||||||
|
|
||||||
type APICall struct {
|
type APICall struct {
|
||||||
workers map[string]Networker
|
|
||||||
secer IPSecer
|
secer IPSecer
|
||||||
|
bgper Bgper
|
||||||
|
workers map[string]Networker
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *APICall) AddWorker(name string, obj Networker) {
|
func (i *APICall) AddWorker(name string, obj Networker) {
|
||||||
@@ -152,6 +161,14 @@ func (i *APICall) GetIPSecer() IPSecer {
|
|||||||
return i.secer
|
return i.secer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *APICall) SetBgper(value Bgper) {
|
||||||
|
i.bgper = value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *APICall) GetBgper() Bgper {
|
||||||
|
return i.bgper
|
||||||
|
}
|
||||||
|
|
||||||
var Call = &APICall{
|
var Call = &APICall{
|
||||||
workers: make(map[string]Networker),
|
workers: make(map[string]Networker),
|
||||||
}
|
}
|
||||||
|
59
pkg/config/bgp.go
Normal file
59
pkg/config/bgp.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type BgpNeighbor struct {
|
||||||
|
Name string `json:"-" yaml:"-"`
|
||||||
|
Address string `json:"address" yaml:"address"`
|
||||||
|
RemoteAs int `json:"remoteas" yaml:"remoteas"`
|
||||||
|
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
|
||||||
|
State string `json:"state,omitempty" yaml:"state,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BgpNeighbor) Correct() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BgpNeighbor) Id() string {
|
||||||
|
return fmt.Sprintf("%s", s.Address)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BgpSpecifies struct {
|
||||||
|
Name string `json:"-" yaml:"-"`
|
||||||
|
LocalAs int `json:"localas" yaml:"localas"`
|
||||||
|
RouteId string `json:"routeid" yaml:"routeid"`
|
||||||
|
Neighbors []*BgpNeighbor `json:"neighbors" yaml:"neighbors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BgpSpecifies) Correct() {
|
||||||
|
if s.Neighbors == nil {
|
||||||
|
s.Neighbors = make([]*BgpNeighbor, 0)
|
||||||
|
}
|
||||||
|
for _, t := range s.Neighbors {
|
||||||
|
t.Correct()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BgpSpecifies) FindNeighbor(value *BgpNeighbor) (*BgpNeighbor, int) {
|
||||||
|
for index, obj := range s.Neighbors {
|
||||||
|
if obj.Id() == value.Id() {
|
||||||
|
return obj, index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BgpSpecifies) AddNeighbor(value *BgpNeighbor) bool {
|
||||||
|
_, find := s.FindNeighbor(value)
|
||||||
|
if find == -1 {
|
||||||
|
s.Neighbors = append(s.Neighbors, value)
|
||||||
|
}
|
||||||
|
return find == -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BgpSpecifies) DelNeighbor(value *BgpNeighbor) (*BgpNeighbor, bool) {
|
||||||
|
obj, find := s.FindNeighbor(value)
|
||||||
|
if find != -1 {
|
||||||
|
s.Neighbors = append(s.Neighbors[:find], s.Neighbors[find+1:]...)
|
||||||
|
}
|
||||||
|
return obj, find != -1
|
||||||
|
}
|
@@ -30,12 +30,14 @@ type Network struct {
|
|||||||
FindHop map[string]*FindHop `json:"findhop,omitempty" yaml:"findhop,omitempty"`
|
FindHop map[string]*FindHop `json:"findhop,omitempty" yaml:"findhop,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Network) NewSpecifies() interface{} {
|
func (n *Network) NewSpecifies() any {
|
||||||
switch n.Provider {
|
switch n.Provider {
|
||||||
case "ipsec":
|
case "ipsec":
|
||||||
n.Specifies = &IPSecSpecifies{}
|
n.Specifies = &IPSecSpecifies{}
|
||||||
case "router":
|
case "router":
|
||||||
n.Specifies = &RouterSpecifies{}
|
n.Specifies = &RouterSpecifies{}
|
||||||
|
case "bgp":
|
||||||
|
n.Specifies = &BgpSpecifies{}
|
||||||
default:
|
default:
|
||||||
n.Specifies = nil
|
n.Specifies = nil
|
||||||
}
|
}
|
||||||
@@ -64,6 +66,12 @@ func (n *Network) Correct(sw *Switch) {
|
|||||||
obj.Correct()
|
obj.Correct()
|
||||||
obj.Name = n.Name
|
obj.Name = n.Name
|
||||||
}
|
}
|
||||||
|
case "bgp":
|
||||||
|
spec := n.Specifies
|
||||||
|
if obj, ok := spec.(*BgpSpecifies); ok {
|
||||||
|
obj.Correct()
|
||||||
|
obj.Name = n.Name
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
br := n.Bridge
|
br := n.Bridge
|
||||||
br.Network = n.Name
|
br.Network = n.Name
|
||||||
|
13
pkg/schema/bgp.go
Normal file
13
pkg/schema/bgp.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package schema
|
||||||
|
|
||||||
|
type BgpNeighbor struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
RemoteAs int `json:"remoteas"`
|
||||||
|
State string `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Bgp struct {
|
||||||
|
LocalAs int `json:"localas"`
|
||||||
|
RouteId string `json:"routeid"`
|
||||||
|
Neighbors []BgpNeighbor `json:"neighbors"`
|
||||||
|
}
|
154
pkg/switch/bgp_linux.go
Normal file
154
pkg/switch/bgp_linux.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package cswitch
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/luscis/openlan/pkg/api"
|
||||||
|
co "github.com/luscis/openlan/pkg/config"
|
||||||
|
"github.com/luscis/openlan/pkg/libol"
|
||||||
|
"github.com/luscis/openlan/pkg/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BgpBin = "/var/openlan/script/frr-reload"
|
||||||
|
BgpEtc = "/etc/frr/frr.conf"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BgpWorker struct {
|
||||||
|
*WorkerImpl
|
||||||
|
spec *co.BgpSpecifies
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBgpWorker(c *co.Network) *BgpWorker {
|
||||||
|
w := &BgpWorker{
|
||||||
|
WorkerImpl: NewWorkerApi(c),
|
||||||
|
}
|
||||||
|
w.spec, _ = c.Specifies.(*co.BgpSpecifies)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
var BgpTmpl = `! GENERATE BY OPENALN
|
||||||
|
{{- range .Neighbors }}
|
||||||
|
!
|
||||||
|
ip prefix-list {{ .Address }}-out seq 10 permit any
|
||||||
|
ip prefix-list {{ .Address }}-in seq 10 permit any
|
||||||
|
{{- end }}
|
||||||
|
!
|
||||||
|
router bgp {{ .LocalAs }}
|
||||||
|
bgp router-id {{ .RouteId }}
|
||||||
|
no bgp default ipv4-unicast
|
||||||
|
{{- range .Neighbors }}
|
||||||
|
neighbor {{ .Address }} remote-as {{ .RemoteAs }}
|
||||||
|
{{- end }}
|
||||||
|
!
|
||||||
|
address-family ipv4 unicast
|
||||||
|
redistribute connected
|
||||||
|
redistribute kernel
|
||||||
|
{{- range .Neighbors }}
|
||||||
|
neighbor {{ .Address }} activate
|
||||||
|
neighbor {{ .Address }} route-map {{ .Address }}-in in
|
||||||
|
neighbor {{ .Address }} route-map {{ .Address }}-out out
|
||||||
|
{{- end }}
|
||||||
|
exit-address-family
|
||||||
|
exit
|
||||||
|
{{- range .Neighbors }}
|
||||||
|
!
|
||||||
|
route-map {{ .Address }}-in permit 10
|
||||||
|
match ip address prefix-list {{ .Address }}-in
|
||||||
|
exit
|
||||||
|
{{- end }}
|
||||||
|
{{- range .Neighbors }}
|
||||||
|
!
|
||||||
|
route-map {{ .Address }}-out permit 10
|
||||||
|
match ip address prefix-list {{ .Address }}-out
|
||||||
|
exit
|
||||||
|
{{- end }}
|
||||||
|
!
|
||||||
|
`
|
||||||
|
|
||||||
|
func (w *BgpWorker) Initialize() {
|
||||||
|
w.out.Info("BgpWorker.Initialize")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) save() {
|
||||||
|
file := BgpEtc
|
||||||
|
out, err := libol.CreateFile(file)
|
||||||
|
if err != nil || out == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
if obj, err := template.New("main").Parse(BgpTmpl); err != nil {
|
||||||
|
w.out.Warn("BgpWorker.save: %s", err)
|
||||||
|
} else {
|
||||||
|
if err := obj.Execute(out, w.spec); err != nil {
|
||||||
|
w.out.Warn("BgpWorker.save: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) reload() {
|
||||||
|
w.save()
|
||||||
|
cmd := exec.Command(BgpBin)
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
w.out.Warn("BgpWorker.reload: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) Start(v api.Switcher) {
|
||||||
|
w.uuid = v.UUID()
|
||||||
|
w.out.Info("BgpWorker.Start")
|
||||||
|
w.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) Stop() {
|
||||||
|
w.out.Info("BgpWorker.Stop")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) Enable(data schema.Bgp) {
|
||||||
|
w.spec.LocalAs = data.LocalAs
|
||||||
|
w.spec.RouteId = data.RouteId
|
||||||
|
w.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) Disable() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) Reload(v api.Switcher) {
|
||||||
|
w.Stop()
|
||||||
|
w.Initialize()
|
||||||
|
w.Start(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) AddNeighbor(data schema.BgpNeighbor) {
|
||||||
|
cfg := &co.BgpNeighbor{
|
||||||
|
Address: data.Address,
|
||||||
|
RemoteAs: data.RemoteAs,
|
||||||
|
}
|
||||||
|
cfg.Correct()
|
||||||
|
if w.spec.AddNeighbor(cfg) {
|
||||||
|
w.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) DelNeighbor(data schema.BgpNeighbor) {
|
||||||
|
cfg := &co.BgpNeighbor{
|
||||||
|
Address: data.Address,
|
||||||
|
RemoteAs: data.RemoteAs,
|
||||||
|
}
|
||||||
|
cfg.Correct()
|
||||||
|
if _, removed := w.spec.DelNeighbor(cfg); removed {
|
||||||
|
w.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *BgpWorker) ListNeighbor(call func(obj schema.BgpNeighbor)) {
|
||||||
|
for _, nei := range w.spec.Neighbors {
|
||||||
|
obj := schema.BgpNeighbor{
|
||||||
|
Address: nei.Address,
|
||||||
|
RemoteAs: nei.RemoteAs,
|
||||||
|
}
|
||||||
|
call(obj)
|
||||||
|
}
|
||||||
|
}
|
@@ -143,10 +143,11 @@ func (w *IPSecWorker) startConn(name string) {
|
|||||||
|
|
||||||
func (w *IPSecWorker) restartTunnel(tun *co.IPSecTunnel) {
|
func (w *IPSecWorker) restartTunnel(tun *co.IPSecTunnel) {
|
||||||
name := tun.Name
|
name := tun.Name
|
||||||
if tun.Transport == "vxlan" {
|
switch tun.Transport {
|
||||||
|
case "vxlan":
|
||||||
w.startConn(name + "-c1")
|
w.startConn(name + "-c1")
|
||||||
w.startConn(name + "-c2")
|
w.startConn(name + "-c2")
|
||||||
} else if tun.Transport == "gre" {
|
case "gre":
|
||||||
w.startConn(name + "-c1")
|
w.startConn(name + "-c1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,10 +157,11 @@ func (w *IPSecWorker) addTunnel(tun *co.IPSecTunnel) error {
|
|||||||
secTmpl := ""
|
secTmpl := ""
|
||||||
|
|
||||||
name := tun.Name
|
name := tun.Name
|
||||||
if tun.Transport == "vxlan" {
|
switch tun.Transport {
|
||||||
|
case "vxlan":
|
||||||
connTmpl = ipsecTmpl["vxlan"]
|
connTmpl = ipsecTmpl["vxlan"]
|
||||||
secTmpl = ipsecTmpl["secret"]
|
secTmpl = ipsecTmpl["secret"]
|
||||||
} else if tun.Transport == "gre" {
|
case "gre":
|
||||||
connTmpl = ipsecTmpl["gre"]
|
connTmpl = ipsecTmpl["gre"]
|
||||||
secTmpl = ipsecTmpl["secret"]
|
secTmpl = ipsecTmpl["secret"]
|
||||||
}
|
}
|
||||||
@@ -192,10 +194,11 @@ func (w *IPSecWorker) Start(v api.Switcher) {
|
|||||||
|
|
||||||
func (w *IPSecWorker) removeTunnel(tun *co.IPSecTunnel) error {
|
func (w *IPSecWorker) removeTunnel(tun *co.IPSecTunnel) error {
|
||||||
name := tun.Name
|
name := tun.Name
|
||||||
if tun.Transport == "vxlan" {
|
switch tun.Transport {
|
||||||
|
case "vxlan":
|
||||||
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c1")
|
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c1")
|
||||||
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c2")
|
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c2")
|
||||||
} else if tun.Transport == "gre" {
|
case "gre":
|
||||||
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c1")
|
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c1")
|
||||||
}
|
}
|
||||||
cfile := fmt.Sprintf("%s/%s.conf", IPSecEtcDir, name)
|
cfile := fmt.Sprintf("%s/%s.conf", IPSecEtcDir, name)
|
||||||
|
@@ -24,6 +24,10 @@ func NewNetworker(c *co.Network) api.Networker {
|
|||||||
secer := NewIPSecWorker(c)
|
secer := NewIPSecWorker(c)
|
||||||
api.Call.SetIPSecer(secer)
|
api.Call.SetIPSecer(secer)
|
||||||
obj = secer
|
obj = secer
|
||||||
|
case "bgp":
|
||||||
|
bgper := NewBgpWorker(c)
|
||||||
|
api.Call.SetBgper(bgper)
|
||||||
|
obj = bgper
|
||||||
case "router":
|
case "router":
|
||||||
obj = NewRouterWorker(c)
|
obj = NewRouterWorker(c)
|
||||||
default:
|
default:
|
||||||
|
Reference in New Issue
Block a user