mirror of
https://github.com/luscis/openlan.git
synced 2025-10-06 00:57:03 +08:00
251 lines
5.2 KiB
Go
251 lines
5.2 KiB
Go
package cswitch
|
|
|
|
import (
|
|
"os/exec"
|
|
"strings"
|
|
"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-client"
|
|
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
|
|
!
|
|
service integrated-vtysh-config
|
|
{{- if .RouterId }}
|
|
router bgp {{ .LocalAs }}
|
|
bgp router-id {{ .RouterId }}
|
|
no bgp default ipv4-unicast
|
|
{{- range .Neighbors }}
|
|
neighbor {{ .Address }} remote-as {{ .RemoteAs }}
|
|
{{- if .Password }}
|
|
neighbor {{ .Address }} password {{ .Password }}
|
|
{{- end }}
|
|
{{- 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
|
|
!
|
|
|
|
{{- range $nei := .Neighbors }}
|
|
{{- range $seq, $prefix := .Advertis }}
|
|
ip prefix-list {{ $nei.Address }}-out seq {{ inc $seq }} permit {{ $prefix }} le 32
|
|
{{- end }}
|
|
ip prefix-list {{ $nei.Address }}-out seq 65535 deny any
|
|
{{- range $seq, $prefix := .Receives }}
|
|
ip prefix-list {{ $nei.Address }}-in seq {{ inc $seq }} permit {{ $prefix }} le 32
|
|
{{- end }}
|
|
ip prefix-list {{ $nei.Address }}-in seq 65535 deny any
|
|
{{- end }}
|
|
!
|
|
|
|
{{- range .Neighbors }}
|
|
route-map {{ .Address }}-in permit 10
|
|
match ip address prefix-list {{ .Address }}-in
|
|
!
|
|
{{- end }}
|
|
|
|
{{- range .Neighbors }}
|
|
route-map {{ .Address }}-out permit 10
|
|
match ip address prefix-list {{ .Address }}-out
|
|
!
|
|
{{- end }}
|
|
{{- 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()
|
|
|
|
maps := template.FuncMap{
|
|
"inc": func(i int) int {
|
|
return i + 1
|
|
},
|
|
}
|
|
if obj, err := template.New("main").Funcs(maps).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, "--reload")
|
|
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.RouterId = data.RouterId
|
|
w.reload()
|
|
}
|
|
|
|
func (w *BgpWorker) Disable() {
|
|
w.spec.RouterId = ""
|
|
w.spec.LocalAs = 0
|
|
w.reload()
|
|
}
|
|
|
|
func (w *BgpWorker) Get() *schema.Bgp {
|
|
data := &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,
|
|
RemoteAs: nei.RemoteAs,
|
|
Password: nei.Password,
|
|
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
|
|
}
|
|
|
|
func (w *BgpWorker) Reload(v api.Switcher) {
|
|
w.Stop()
|
|
w.Initialize()
|
|
w.Start(v)
|
|
}
|
|
|
|
func (w *BgpWorker) AddNeighbor(data schema.BgpNeighbor) {
|
|
obj := &co.BgpNeighbor{
|
|
Address: data.Address,
|
|
RemoteAs: data.RemoteAs,
|
|
Password: data.Password,
|
|
}
|
|
obj.Correct()
|
|
if nei, _ := w.spec.FindNeighbor(obj); nei == nil {
|
|
w.spec.AddNeighbor(obj)
|
|
} else {
|
|
nei.RemoteAs = data.RemoteAs
|
|
nei.Password = data.Password
|
|
}
|
|
w.reload()
|
|
}
|
|
|
|
func (w *BgpWorker) DelNeighbor(data schema.BgpNeighbor) {
|
|
obj := &co.BgpNeighbor{
|
|
Address: data.Address,
|
|
RemoteAs: data.RemoteAs,
|
|
}
|
|
obj.Correct()
|
|
if _, removed := w.spec.DelNeighbor(obj); removed {
|
|
w.reload()
|
|
}
|
|
}
|
|
|
|
func (w *BgpWorker) AddReceives(data schema.BgpPrefix) {
|
|
obj := &co.BgpNeighbor{
|
|
Address: data.Neighbor,
|
|
}
|
|
if nei, _ := w.spec.FindNeighbor(obj); nei != nil {
|
|
if nei.AddReceives(data.Prefix) {
|
|
w.reload()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (w *BgpWorker) DelReceives(data schema.BgpPrefix) {
|
|
obj := &co.BgpNeighbor{
|
|
Address: data.Neighbor,
|
|
}
|
|
if nei, _ := w.spec.FindNeighbor(obj); nei != nil {
|
|
if nei.DelReceives(data.Prefix) {
|
|
w.reload()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (w *BgpWorker) AddAdvertis(data schema.BgpPrefix) {
|
|
obj := &co.BgpNeighbor{
|
|
Address: data.Neighbor,
|
|
}
|
|
if nei, _ := w.spec.FindNeighbor(obj); nei != nil {
|
|
if nei.AddAdvertis(data.Prefix) {
|
|
w.reload()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (w *BgpWorker) DelAdvertis(data schema.BgpPrefix) {
|
|
obj := &co.BgpNeighbor{
|
|
Address: data.Neighbor,
|
|
}
|
|
if nei, _ := w.spec.FindNeighbor(obj); nei != nil {
|
|
if nei.DelAdvertis(data.Prefix) {
|
|
w.reload()
|
|
}
|
|
}
|
|
}
|