fea: ip prefix rules for route-map.
Some checks failed
Coverage CI / build (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
Ubuntu CI / build (push) Has been cancelled

This commit is contained in:
Daniel Ding
2025-09-03 16:31:09 +08:00
parent d6821af047
commit 8edfdc646b
6 changed files with 323 additions and 13 deletions

View File

@@ -8,7 +8,9 @@ import (
// openlan bgp enable --router-id 1.1.1.1 --local-as 30 // openlan bgp enable --router-id 1.1.1.1 --local-as 30
// openlan bgp disable // openlan bgp disable
// openlan bgp add neighbor --address 1.1.1.2 --remote-as 32 // openlan bgp neighbor add --address 1.1.1.2 --remote-as 32
// openlan bgp advertis add --neighbor 1.1.1.2 --prefix 192.168.1.0/24
// openlan bgp receives add --neighbor 1.1.1.2 --prefix 192.168.2.0/24
type BGP struct { type BGP struct {
Cmd Cmd
@@ -76,6 +78,8 @@ func (b BGP) Commands(app *api.App) {
Action: b.Disable, Action: b.Disable,
}, },
Neighbor{}.Commands(), Neighbor{}.Commands(),
Advertis{}.Commands(),
Receives{}.Commands(),
}, },
}) })
} }
@@ -139,3 +143,127 @@ func (s Neighbor) Commands() *cli.Command {
}, },
} }
} }
type Advertis struct {
Cmd
}
func (s Advertis) Url(prefix string) string {
return prefix + "/api/network/bgp/advertis"
}
func (s Advertis) Add(c *cli.Context) error {
data := &schema.BgpPrefix{
Prefix: c.String("prefix"),
Neighbor: c.String("neighbor"),
}
url := s.Url(c.String("url"))
clt := s.NewHttp(c.String("token"))
if err := clt.PostJSON(url, data, nil); err != nil {
return err
}
return nil
}
func (s Advertis) Remove(c *cli.Context) error {
data := &schema.BgpPrefix{
Prefix: c.String("prefix"),
Neighbor: c.String("neighbor"),
}
url := s.Url(c.String("url"))
clt := s.NewHttp(c.String("token"))
if err := clt.DeleteJSON(url, data, nil); err != nil {
return err
}
return nil
}
func (s Advertis) Commands() *cli.Command {
return &cli.Command{
Name: "advertis",
Usage: "Neighbor advertised routes",
Subcommands: []*cli.Command{
{
Name: "add",
Usage: "Add advertis prefix",
Flags: []cli.Flag{
&cli.StringFlag{Name: "neighbor", Required: true},
&cli.StringFlag{Name: "prefix", Required: true},
},
Action: s.Add,
},
{
Name: "remove",
Aliases: []string{"rm"},
Usage: "Remove advertis prefix",
Flags: []cli.Flag{
&cli.StringFlag{Name: "neighbor", Required: true},
&cli.StringFlag{Name: "prefix", Required: true},
},
Action: s.Remove,
},
},
}
}
type Receives struct {
Cmd
}
func (s Receives) Url(prefix string) string {
return prefix + "/api/network/bgp/receives"
}
func (s Receives) Add(c *cli.Context) error {
data := &schema.BgpPrefix{
Prefix: c.String("prefix"),
Neighbor: c.String("neighbor"),
}
url := s.Url(c.String("url"))
clt := s.NewHttp(c.String("token"))
if err := clt.PostJSON(url, data, nil); err != nil {
return err
}
return nil
}
func (s Receives) Remove(c *cli.Context) error {
data := &schema.BgpPrefix{
Prefix: c.String("prefix"),
Neighbor: c.String("neighbor"),
}
url := s.Url(c.String("url"))
clt := s.NewHttp(c.String("token"))
if err := clt.DeleteJSON(url, data, nil); err != nil {
return err
}
return nil
}
func (s Receives) Commands() *cli.Command {
return &cli.Command{
Name: "receives",
Usage: "Neighbor received prefix",
Subcommands: []*cli.Command{
{
Name: "add",
Usage: "Add received prefix",
Flags: []cli.Flag{
&cli.StringFlag{Name: "neighbor", Required: true},
&cli.StringFlag{Name: "prefix", Required: true},
},
Action: s.Add,
},
{
Name: "remove",
Aliases: []string{"rm"},
Usage: "Remove received prefix",
Flags: []cli.Flag{
&cli.StringFlag{Name: "neighbor", Required: true},
&cli.StringFlag{Name: "prefix", Required: true},
},
Action: s.Remove,
},
},
}
}

View File

@@ -131,6 +131,10 @@ type Bgper interface {
Get() *schema.Bgp Get() *schema.Bgp
AddNeighbor(data schema.BgpNeighbor) AddNeighbor(data schema.BgpNeighbor)
DelNeighbor(data schema.BgpNeighbor) DelNeighbor(data schema.BgpNeighbor)
AddReceives(data schema.BgpPrefix)
DelReceives(data schema.BgpPrefix)
AddAdvertis(data schema.BgpPrefix)
DelAdvertis(data schema.BgpPrefix)
} }
type APICall struct { type APICall struct {

View File

@@ -18,6 +18,10 @@ func (h Bgp) Router(router *mux.Router) {
router.HandleFunc("/api/network/bgp", h.Remove).Methods("DELETE") router.HandleFunc("/api/network/bgp", h.Remove).Methods("DELETE")
router.HandleFunc("/api/network/bgp/neighbor", h.RemoveNeighbor).Methods("DELETE") router.HandleFunc("/api/network/bgp/neighbor", h.RemoveNeighbor).Methods("DELETE")
router.HandleFunc("/api/network/bgp/neighbor", h.AddNeighbor).Methods("POST") router.HandleFunc("/api/network/bgp/neighbor", h.AddNeighbor).Methods("POST")
router.HandleFunc("/api/network/bgp/advertis", h.RemoveAdvertis).Methods("DELETE")
router.HandleFunc("/api/network/bgp/advertis", h.AddAdvertis).Methods("POST")
router.HandleFunc("/api/network/bgp/receives", h.RemoveReceivess).Methods("DELETE")
router.HandleFunc("/api/network/bgp/receives", h.AddReceivess).Methods("POST")
} }
func (h Bgp) Get(w http.ResponseWriter, r *http.Request) { func (h Bgp) Get(w http.ResponseWriter, r *http.Request) {
@@ -80,3 +84,59 @@ func (h Bgp) AddNeighbor(w http.ResponseWriter, r *http.Request) {
Call.bgper.AddNeighbor(nei) Call.bgper.AddNeighbor(nei)
ResponseMsg(w, 0, "") ResponseMsg(w, 0, "")
} }
func (h Bgp) RemoveAdvertis(w http.ResponseWriter, r *http.Request) {
data := schema.BgpPrefix{}
if err := GetData(r, &data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if Call.bgper == nil {
http.Error(w, "network is nil", http.StatusBadRequest)
return
}
Call.bgper.DelAdvertis(data)
ResponseMsg(w, 0, "")
}
func (h Bgp) AddAdvertis(w http.ResponseWriter, r *http.Request) {
data := schema.BgpPrefix{}
if err := GetData(r, &data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if Call.bgper == nil {
http.Error(w, "network is nil", http.StatusBadRequest)
return
}
Call.bgper.AddAdvertis(data)
ResponseMsg(w, 0, "")
}
func (h Bgp) RemoveReceivess(w http.ResponseWriter, r *http.Request) {
data := schema.BgpPrefix{}
if err := GetData(r, &data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if Call.bgper == nil {
http.Error(w, "network is nil", http.StatusBadRequest)
return
}
Call.bgper.DelReceives(data)
ResponseMsg(w, 0, "")
}
func (h Bgp) AddReceivess(w http.ResponseWriter, r *http.Request) {
data := schema.BgpPrefix{}
if err := GetData(r, &data); err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if Call.bgper == nil {
http.Error(w, "network is nil", http.StatusBadRequest)
return
}
Call.bgper.AddReceives(data)
ResponseMsg(w, 0, "")
}

View File

@@ -3,11 +3,13 @@ package config
import "fmt" import "fmt"
type BgpNeighbor struct { type BgpNeighbor struct {
Name string `json:"-" yaml:"-"` Name string `json:"-" yaml:"-"`
Address string `json:"address" yaml:"address"` Address string `json:"address" yaml:"address"`
RemoteAs int `json:"remoteas" yaml:"remoteas"` RemoteAs int `json:"remoteas" yaml:"remoteas"`
Secret string `json:"secret,omitempty" yaml:"secret,omitempty"` Secret string `json:"secret,omitempty" yaml:"secret,omitempty"`
State string `json:"state,omitempty" yaml:"state,omitempty"` State string `json:"state,omitempty" yaml:"state,omitempty"`
Advertis []string `json:"advertis,omitempty" yaml:"advertis,omitempty"`
Receives []string `json:"receives,omitempty" yaml:"receives,omitempty"`
} }
func (s *BgpNeighbor) Correct() { func (s *BgpNeighbor) Correct() {
@@ -17,6 +19,56 @@ func (s *BgpNeighbor) Id() string {
return fmt.Sprintf("%s", s.Address) return fmt.Sprintf("%s", s.Address)
} }
func (s *BgpNeighbor) FindReceives(value string) int {
for index, obj := range s.Receives {
if obj == value {
return index
}
}
return -1
}
func (s *BgpNeighbor) AddReceives(value string) bool {
find := s.FindReceives(value)
if find == -1 {
s.Receives = append(s.Receives, value)
}
return find == -1
}
func (s *BgpNeighbor) DelReceives(value string) bool {
find := s.FindReceives(value)
if find != -1 {
s.Receives = append(s.Receives[:find], s.Receives[find+1:]...)
}
return find != -1
}
func (s *BgpNeighbor) FindAdvertis(value string) int {
for index, obj := range s.Advertis {
if obj == value {
return index
}
}
return -1
}
func (s *BgpNeighbor) AddAdvertis(value string) bool {
find := s.FindAdvertis(value)
if find == -1 {
s.Advertis = append(s.Advertis, value)
}
return find == -1
}
func (s *BgpNeighbor) DelAdvertis(value string) bool {
find := s.FindAdvertis(value)
if find != -1 {
s.Advertis = append(s.Advertis[:find], s.Advertis[find+1:]...)
}
return find != -1
}
type BgpSpecifies struct { type BgpSpecifies struct {
Name string `json:"-" yaml:"-"` Name string `json:"-" yaml:"-"`
LocalAs int `json:"localas" yaml:"localas"` LocalAs int `json:"localas" yaml:"localas"`

View File

@@ -1,9 +1,11 @@
package schema package schema
type BgpNeighbor struct { type BgpNeighbor struct {
Address string `json:"address"` Address string `json:"address"`
RemoteAs int `json:"remoteas"` RemoteAs int `json:"remoteas"`
State string `json:"state"` State string `json:"state,omitempty" yaml:"state,omitempty"`
Advertis []string `json:"advertis"`
Receives []string `json:"receives"`
} }
type Bgp struct { type Bgp struct {
@@ -11,3 +13,8 @@ type Bgp struct {
RouterId string `json:"routerid"` RouterId string `json:"routerid"`
Neighbors []BgpNeighbor `json:"neighbors"` Neighbors []BgpNeighbor `json:"neighbors"`
} }
type BgpPrefix struct {
Prefix string `json:"prefix"`
Neighbor string `json:"neighbor"`
}

View File

@@ -50,10 +50,17 @@ router bgp {{ .LocalAs }}
exit-address-family exit-address-family
! !
{{- range .Neighbors }} {{- range $nei := .Neighbors }}
ip prefix-list {{ .Address }}-out seq 10 permit any {{- range $seq, $prefix := .Advertis }}
ip prefix-list {{ .Address }}-in seq 10 permit any ip prefix-list {{ $nei.Address }}-out seq {{ inc $seq }} permit {{ $prefix }} le 32
{{- end }} {{- 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 }} {{- range .Neighbors }}
route-map {{ .Address }}-in permit 10 route-map {{ .Address }}-in permit 10
@@ -81,7 +88,13 @@ func (w *BgpWorker) save() {
return return
} }
defer out.Close() defer out.Close()
if obj, err := template.New("main").Parse(BgpTmpl); err != nil {
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) w.out.Warn("BgpWorker.save: %s", err)
} else { } else {
if err := obj.Execute(out, w.spec); err != nil { if err := obj.Execute(out, w.spec); err != nil {
@@ -130,6 +143,8 @@ func (w *BgpWorker) Get() *schema.Bgp {
obj := schema.BgpNeighbor{ obj := schema.BgpNeighbor{
Address: nei.Address, Address: nei.Address,
RemoteAs: nei.RemoteAs, RemoteAs: nei.RemoteAs,
Receives: nei.Receives,
Advertis: nei.Advertis,
} }
data.Neighbors = append(data.Neighbors, obj) data.Neighbors = append(data.Neighbors, obj)
} }
@@ -163,3 +178,47 @@ func (w *BgpWorker) DelNeighbor(data schema.BgpNeighbor) {
w.reload() 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()
}
}
}