diff options
author | IWASE Yusuke <iwase.yusuke0@gmail.com> | 2018-04-27 11:28:32 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2018-05-10 21:12:30 +0900 |
commit | 32f7faa8e7f83c20e50a37e44ba01a498939f574 (patch) | |
tree | 014b7755fb5cd873f2ea7bfd9ece4c9f846475ad | |
parent | 0f88373949e2eed7a9dbcd1ebac64d76e54f6d40 (diff) |
config: Enable to configure VRF via config file
This patch enables to configure VRF tables by using config file. This
feature is useful when using VRF-Neighbor feature.
Example of Usage:
```toml
[[vrfs]]
[vrfs.config]
name = "vrf1"
id = 1
rd = "65000:100"
both-rt-list = ["65000:100"]
```
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
-rw-r--r-- | config/bgp_configs.go | 124 | ||||
-rw-r--r-- | config/default.go | 76 | ||||
-rw-r--r-- | config/serve.go | 6 | ||||
-rw-r--r-- | docs/sources/configuration.md | 12 | ||||
-rw-r--r-- | gobgpd/main.go | 25 | ||||
-rw-r--r-- | tools/pyang_plugins/gobgp.yang | 93 |
6 files changed, 331 insertions, 5 deletions
diff --git a/config/bgp_configs.go b/config/bgp_configs.go index 402bff40..062ef8f7 100644 --- a/config/bgp_configs.go +++ b/config/bgp_configs.go @@ -1250,6 +1250,112 @@ func (lhs *Mrt) Equal(rhs *Mrt) bool { } // struct for container gobgp:state. +// Configured states of VRF. +type VrfState struct { + // original -> gobgp:name + // Unique name among all VRF instances. + Name string `mapstructure:"name" json:"name,omitempty"` + // original -> gobgp:id + // Unique identifier among all VRF instances. + Id uint32 `mapstructure:"id" json:"id,omitempty"` + // original -> gobgp:rd + // Route Distinguisher for this VRF. + Rd string `mapstructure:"rd" json:"rd,omitempty"` + // original -> gobgp:import-rt + // List of import Route Targets for this VRF. + ImportRtList []string `mapstructure:"import-rt-list" json:"import-rt-list,omitempty"` + // original -> gobgp:export-rt + // List of export Route Targets for this VRF. + ExportRtList []string `mapstructure:"export-rt-list" json:"export-rt-list,omitempty"` +} + +// struct for container gobgp:config. +// Configuration parameters for VRF. +type VrfConfig struct { + // original -> gobgp:name + // Unique name among all VRF instances. + Name string `mapstructure:"name" json:"name,omitempty"` + // original -> gobgp:id + // Unique identifier among all VRF instances. + Id uint32 `mapstructure:"id" json:"id,omitempty"` + // original -> gobgp:rd + // Route Distinguisher for this VRF. + Rd string `mapstructure:"rd" json:"rd,omitempty"` + // original -> gobgp:import-rt + // List of import Route Targets for this VRF. + ImportRtList []string `mapstructure:"import-rt-list" json:"import-rt-list,omitempty"` + // original -> gobgp:export-rt + // List of export Route Targets for this VRF. + ExportRtList []string `mapstructure:"export-rt-list" json:"export-rt-list,omitempty"` + // original -> gobgp:both-rt + // List of both import and export Route Targets for this VRF. Each + // configuration for import and export Route Targets will be preferred. + BothRtList []string `mapstructure:"both-rt-list" json:"both-rt-list,omitempty"` +} + +func (lhs *VrfConfig) Equal(rhs *VrfConfig) bool { + if lhs == nil || rhs == nil { + return false + } + if lhs.Name != rhs.Name { + return false + } + if lhs.Id != rhs.Id { + return false + } + if lhs.Rd != rhs.Rd { + return false + } + if len(lhs.ImportRtList) != len(rhs.ImportRtList) { + return false + } + for idx, l := range lhs.ImportRtList { + if l != rhs.ImportRtList[idx] { + return false + } + } + if len(lhs.ExportRtList) != len(rhs.ExportRtList) { + return false + } + for idx, l := range lhs.ExportRtList { + if l != rhs.ExportRtList[idx] { + return false + } + } + if len(lhs.BothRtList) != len(rhs.BothRtList) { + return false + } + for idx, l := range lhs.BothRtList { + if l != rhs.BothRtList[idx] { + return false + } + } + return true +} + +// struct for container gobgp:vrf. +// VRF instance configurations on the local system. +type Vrf struct { + // original -> gobgp:name + // original -> gobgp:vrf-config + // Configuration parameters for VRF. + Config VrfConfig `mapstructure:"config" json:"config,omitempty"` + // original -> gobgp:vrf-state + // Configured states of VRF. + State VrfState `mapstructure:"state" json:"state,omitempty"` +} + +func (lhs *Vrf) Equal(rhs *Vrf) bool { + if lhs == nil || rhs == nil { + return false + } + if !lhs.Config.Equal(&(rhs.Config)) { + return false + } + return true +} + +// struct for container gobgp:state. // Configuration parameters relating to BMP server. type BmpServerState struct { // original -> gobgp:address @@ -4785,6 +4891,8 @@ type Bgp struct { RpkiServers []RpkiServer `mapstructure:"rpki-servers" json:"rpki-servers,omitempty"` // original -> gobgp:bmp-servers BmpServers []BmpServer `mapstructure:"bmp-servers" json:"bmp-servers,omitempty"` + // original -> gobgp:vrfs + Vrfs []Vrf `mapstructure:"vrfs" json:"vrfs,omitempty"` // original -> gobgp:mrt-dump MrtDump []Mrt `mapstructure:"mrt-dump" json:"mrt-dump,omitempty"` // original -> gobgp:zebra @@ -4866,6 +4974,22 @@ func (lhs *Bgp) Equal(rhs *Bgp) bool { } } } + if len(lhs.Vrfs) != len(rhs.Vrfs) { + return false + } + { + lmap := make(map[string]*Vrf) + for i, l := range lhs.Vrfs { + lmap[mapkey(i, string(l.Config.Name))] = &lhs.Vrfs[i] + } + for i, r := range rhs.Vrfs { + if l, y := lmap[mapkey(i, string(r.Config.Name))]; !y { + return false + } else if !r.Equal(l) { + return false + } + } + } if len(lhs.MrtDump) != len(rhs.MrtDump) { return false } diff --git a/config/default.go b/config/default.go index 5c472909..f5bf809e 100644 --- a/config/default.go +++ b/config/default.go @@ -2,13 +2,15 @@ package config import ( "fmt" + "math" "net" "reflect" + "github.com/spf13/viper" + "github.com/osrg/gobgp/packet/bgp" "github.com/osrg/gobgp/packet/bmp" "github.com/osrg/gobgp/packet/rtr" - "github.com/spf13/viper" ) const ( @@ -265,6 +267,43 @@ func SetDefaultGlobalConfigValues(g *Global) error { return nil } +func setDefaultVrfConfigValues(v *Vrf) error { + if v == nil { + return fmt.Errorf("cannot set default values for nil vrf config") + } + + if v.Config.Name == "" { + return fmt.Errorf("specify vrf name") + } + + _, err := bgp.ParseRouteDistinguisher(v.Config.Rd) + if err != nil { + return fmt.Errorf("invalid rd for vrf %s: %s", v.Config.Name, v.Config.Rd) + } + + if len(v.Config.ImportRtList) == 0 { + v.Config.ImportRtList = v.Config.BothRtList + } + for _, rtString := range v.Config.ImportRtList { + _, err := bgp.ParseRouteTarget(rtString) + if err != nil { + return fmt.Errorf("invalid import rt for vrf %s: %s", v.Config.Name, rtString) + } + } + + if len(v.Config.ExportRtList) == 0 { + v.Config.ExportRtList = v.Config.BothRtList + } + for _, rtString := range v.Config.ExportRtList { + _, err := bgp.ParseRouteTarget(rtString) + if err != nil { + return fmt.Errorf("invalid export rt for vrf %s: %s", v.Config.Name, rtString) + } + } + + return nil +} + func SetDefaultConfigValues(b *BgpConfigSet) error { return setDefaultConfigValuesWithViper(nil, b) } @@ -309,6 +348,41 @@ func setDefaultConfigValuesWithViper(v *viper.Viper, b *BgpConfigSet) error { b.BmpServers[idx] = server } + vrfNames := make(map[string]struct{}) + vrfIDs := make(map[uint32]struct{}) + for idx, vrf := range b.Vrfs { + if err := setDefaultVrfConfigValues(&vrf); err != nil { + return err + } + + if _, ok := vrfNames[vrf.Config.Name]; ok { + return fmt.Errorf("duplicated vrf name: %s", vrf.Config.Name) + } + vrfNames[vrf.Config.Name] = struct{}{} + + if vrf.Config.Id != 0 { + if _, ok := vrfIDs[vrf.Config.Id]; ok { + return fmt.Errorf("duplicated vrf id: %d", vrf.Config.Id) + } + vrfIDs[vrf.Config.Id] = struct{}{} + } + + b.Vrfs[idx] = vrf + } + // Auto assign VRF identifier + for idx, vrf := range b.Vrfs { + if vrf.Config.Id == 0 { + for id := uint32(1); id < math.MaxUint32; id++ { + if _, ok := vrfIDs[id]; !ok { + vrf.Config.Id = id + vrfIDs[id] = struct{}{} + break + } + } + } + b.Vrfs[idx] = vrf + } + if b.Zebra.Config.Url == "" { b.Zebra.Config.Url = "unix:/var/run/quagga/zserv.api" } diff --git a/config/serve.go b/config/serve.go index 45c70ea9..7705b1f8 100644 --- a/config/serve.go +++ b/config/serve.go @@ -1,11 +1,12 @@ package config import ( - log "github.com/sirupsen/logrus" - "github.com/spf13/viper" "os" "os/signal" "syscall" + + log "github.com/sirupsen/logrus" + "github.com/spf13/viper" ) type BgpConfigSet struct { @@ -14,6 +15,7 @@ type BgpConfigSet struct { PeerGroups []PeerGroup `mapstructure:"peer-groups"` RpkiServers []RpkiServer `mapstructure:"rpki-servers"` BmpServers []BmpServer `mapstructure:"bmp-servers"` + Vrfs []Vrf `mapstructure:"vrfs"` MrtDump []Mrt `mapstructure:"mrt-dump"` Zebra Zebra `mapstructure:"zebra"` Collector Collector `mapstructure:"collector"` diff --git a/docs/sources/configuration.md b/docs/sources/configuration.md index 15a86761..9bef5ec3 100644 --- a/docs/sources/configuration.md +++ b/docs/sources/configuration.md @@ -30,6 +30,18 @@ route-monitoring-policy = "pre-policy" statistics-timeout = 3600 +[[vrfs]] + [vrfs.config] + name = "vrf1" + # If id is omitted, automatically assigned. + id = 1 + rd = "65000:100" + # Each configuration for import and export RTs; + # import-rt-list + # export-rt-list + # are preferred than both-rt-list. + both-rt-list = ["65000:100"] + [[mrt-dump]] [mrt-dump.config] dump-type = "updates" diff --git a/gobgpd/main.go b/gobgpd/main.go index fdfb8cca..9b504441 100644 --- a/gobgpd/main.go +++ b/gobgpd/main.go @@ -188,6 +188,31 @@ func main() { log.Fatalf("failed to set bmp config: %s", err) } } + for _, vrf := range newConfig.Vrfs { + rd, err := bgp.ParseRouteDistinguisher(vrf.Config.Rd) + if err != nil { + log.Fatalf("failed to load vrf rd config: %s", err) + } + importRtList := make([]bgp.ExtendedCommunityInterface, 0, len(vrf.Config.ImportRtList)) + for _, rtString := range vrf.Config.ImportRtList { + rt, err := bgp.ParseRouteTarget(rtString) + if err != nil { + log.Fatalf("failed to load vrf import rt config: %s", err) + } + importRtList = append(importRtList, rt) + } + exportRtList := make([]bgp.ExtendedCommunityInterface, 0, len(vrf.Config.ExportRtList)) + for _, rtString := range vrf.Config.ExportRtList { + rt, err := bgp.ParseRouteTarget(rtString) + if err != nil { + log.Fatalf("failed to load vrf export rt config: %s", err) + } + exportRtList = append(exportRtList, rt) + } + if err := bgpServer.AddVrf(vrf.Config.Name, vrf.Config.Id, rd, importRtList, exportRtList); err != nil { + log.Fatalf("failed to set vrf config: %s", err) + } + } for i, _ := range newConfig.MrtDump { if len(newConfig.MrtDump[i].Config.FileName) == 0 { continue diff --git a/tools/pyang_plugins/gobgp.yang b/tools/pyang_plugins/gobgp.yang index 9022d680..053ef0a0 100644 --- a/tools/pyang_plugins/gobgp.yang +++ b/tools/pyang_plugins/gobgp.yang @@ -618,6 +618,90 @@ module gobgp { } } } + grouping gobgp-vrf-common { + description + "Common parameters for VRF configuration and state."; + + leaf name { + description + "Unique name among all VRF instances."; + type string; + } + + leaf id { + description + "Unique identifier among all VRF instances."; + type uint32; + } + + leaf rd { + description + "Route Distinguisher for this VRF."; + type string; + } + + leaf-list import-rt { + description + "List of import Route Targets for this VRF."; + type string; + } + + leaf-list export-rt { + description + "List of export Route Targets for this VRF."; + type string; + } + } + + grouping gobgp-vrf-config { + description + "Configuration parameters for VRF."; + + leaf-list both-rt { + description + "List of both import and export Route Targets for this VRF. Each + configuration for import and export Route Targets will be preferred."; + type string; + } + } + + grouping gobgp-vrf-set { + description "Set of VRF instance configuration and state"; + + container config { + description + "Configuration parameters for VRF."; + uses gobgp-vrf-common; + uses gobgp-vrf-config; + } + + container state { + description + "Configured states of VRF."; + uses gobgp-vrf-common; + } + } + + grouping gobgp-vrfs { + description + "Virtual Routing and Forwarding (VRF) instances."; + + container vrfs { + list vrf { + description + "VRF instance configurations on the local system."; + + key "name"; + leaf name { + type leafref { + path "../config/name"; + } + } + + uses gobgp-vrf-set; + } + } + } grouping long-lived-graceful-restart { container long-lived-graceful-restart { @@ -1025,15 +1109,20 @@ module gobgp { } augment "/bgp:bgp" { - description "additional rpki configuration and state"; + description "Additional RPKI configuration and state"; uses gobgp-rpki-servers; } augment "/bgp:bgp" { - description "additional bmp configuration"; + description "Additional BMP configuration and state"; uses gobgp-bmp-servers; } + augment "/bgp:bgp" { + description "Additional VRF configuration and state"; + uses gobgp-vrfs; + } + typedef mrt-type { type enumeration { enum UPDATES { |