mirror of
https://github.com/luscis/openlan.git
synced 2025-10-17 06:20:40 +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)
|
||||
Rate{}.Commands(app)
|
||||
Ceci{}.Commands(app)
|
||||
BGP{}.Commands(app)
|
||||
}
|
||||
|
@@ -206,12 +206,12 @@ func (s SNAT) Commands() *cli.Command {
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "enable",
|
||||
Usage: "enable snat",
|
||||
Usage: "Enable snat",
|
||||
Action: s.Enable,
|
||||
},
|
||||
{
|
||||
Name: "disable",
|
||||
Usage: "disable snat",
|
||||
Usage: "Disable snat",
|
||||
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 install -y epel-release
|
||||
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
|
||||
apt-get update -y
|
||||
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
|
||||
## Install libreswan from github.
|
||||
if [ "$sys"x == "redhat"x ]; then
|
||||
|
@@ -11,12 +11,13 @@ services:
|
||||
- /opt/openlan/run/pluto:/run/pluto
|
||||
frr:
|
||||
restart: always
|
||||
image: "quay.io/frrouting/frr:10.2.1"
|
||||
image: "luscis/openlan:latest.x86_64"
|
||||
network_mode: host
|
||||
privileged: true
|
||||
entrypoint: ["/usr/lib/frr/docker-start"]
|
||||
entrypoint: ["/var/openlan/script/frr.sh"]
|
||||
volumes:
|
||||
- /opt/openlan/etc/frr:/etc/frr
|
||||
- /opt/openlan/var/openlan/frr:/var/openlan/frr
|
||||
switch:
|
||||
restart: always
|
||||
image: "luscis/openlan:latest.x86_64"
|
||||
@@ -27,8 +28,11 @@ services:
|
||||
- /opt/openlan/etc/openlan:/etc/openlan
|
||||
- /opt/openlan/etc/ipsec.d:/etc/ipsec.d
|
||||
- /opt/openlan/run/pluto:/run/pluto
|
||||
- /opt/openlan/etc/frr:/etc/frr
|
||||
- /opt/openlan/var/openlan/frr:/var/openlan/frr
|
||||
depends_on:
|
||||
- ipsec
|
||||
- frr
|
||||
proxy:
|
||||
restart: always
|
||||
image: "luscis/openlan:latest.x86_64"
|
||||
|
@@ -125,9 +125,18 @@ type IPSecer interface {
|
||||
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 {
|
||||
workers map[string]Networker
|
||||
secer IPSecer
|
||||
bgper Bgper
|
||||
workers map[string]Networker
|
||||
}
|
||||
|
||||
func (i *APICall) AddWorker(name string, obj Networker) {
|
||||
@@ -152,6 +161,14 @@ func (i *APICall) GetIPSecer() IPSecer {
|
||||
return i.secer
|
||||
}
|
||||
|
||||
func (i *APICall) SetBgper(value Bgper) {
|
||||
i.bgper = value
|
||||
}
|
||||
|
||||
func (i *APICall) GetBgper() Bgper {
|
||||
return i.bgper
|
||||
}
|
||||
|
||||
var Call = &APICall{
|
||||
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"`
|
||||
}
|
||||
|
||||
func (n *Network) NewSpecifies() interface{} {
|
||||
func (n *Network) NewSpecifies() any {
|
||||
switch n.Provider {
|
||||
case "ipsec":
|
||||
n.Specifies = &IPSecSpecifies{}
|
||||
case "router":
|
||||
n.Specifies = &RouterSpecifies{}
|
||||
case "bgp":
|
||||
n.Specifies = &BgpSpecifies{}
|
||||
default:
|
||||
n.Specifies = nil
|
||||
}
|
||||
@@ -64,6 +66,12 @@ func (n *Network) Correct(sw *Switch) {
|
||||
obj.Correct()
|
||||
obj.Name = n.Name
|
||||
}
|
||||
case "bgp":
|
||||
spec := n.Specifies
|
||||
if obj, ok := spec.(*BgpSpecifies); ok {
|
||||
obj.Correct()
|
||||
obj.Name = n.Name
|
||||
}
|
||||
default:
|
||||
br := n.Bridge
|
||||
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) {
|
||||
name := tun.Name
|
||||
if tun.Transport == "vxlan" {
|
||||
switch tun.Transport {
|
||||
case "vxlan":
|
||||
w.startConn(name + "-c1")
|
||||
w.startConn(name + "-c2")
|
||||
} else if tun.Transport == "gre" {
|
||||
case "gre":
|
||||
w.startConn(name + "-c1")
|
||||
}
|
||||
}
|
||||
@@ -156,10 +157,11 @@ func (w *IPSecWorker) addTunnel(tun *co.IPSecTunnel) error {
|
||||
secTmpl := ""
|
||||
|
||||
name := tun.Name
|
||||
if tun.Transport == "vxlan" {
|
||||
switch tun.Transport {
|
||||
case "vxlan":
|
||||
connTmpl = ipsecTmpl["vxlan"]
|
||||
secTmpl = ipsecTmpl["secret"]
|
||||
} else if tun.Transport == "gre" {
|
||||
case "gre":
|
||||
connTmpl = ipsecTmpl["gre"]
|
||||
secTmpl = ipsecTmpl["secret"]
|
||||
}
|
||||
@@ -192,10 +194,11 @@ func (w *IPSecWorker) Start(v api.Switcher) {
|
||||
|
||||
func (w *IPSecWorker) removeTunnel(tun *co.IPSecTunnel) error {
|
||||
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+"-c2")
|
||||
} else if tun.Transport == "gre" {
|
||||
case "gre":
|
||||
libol.Exec(IPSecBin, "auto", "--delete", "--asynchronous", name+"-c1")
|
||||
}
|
||||
cfile := fmt.Sprintf("%s/%s.conf", IPSecEtcDir, name)
|
||||
|
@@ -24,6 +24,10 @@ func NewNetworker(c *co.Network) api.Networker {
|
||||
secer := NewIPSecWorker(c)
|
||||
api.Call.SetIPSecer(secer)
|
||||
obj = secer
|
||||
case "bgp":
|
||||
bgper := NewBgpWorker(c)
|
||||
api.Call.SetBgper(bgper)
|
||||
obj = bgper
|
||||
case "router":
|
||||
obj = NewRouterWorker(c)
|
||||
default:
|
||||
|
Reference in New Issue
Block a user