diff options
Diffstat (limited to 'pkg/config')
-rw-r--r-- | pkg/config/config.go | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 00000000..4a4394df --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,323 @@ +package config + +import ( + "github.com/golang/protobuf/ptypes/any" + log "github.com/sirupsen/logrus" + "golang.org/x/net/context" + + api "github.com/osrg/gobgp/api" + "github.com/osrg/gobgp/internal/pkg/apiutil" + "github.com/osrg/gobgp/internal/pkg/config" + "github.com/osrg/gobgp/internal/pkg/table" + "github.com/osrg/gobgp/pkg/packet/bgp" + "github.com/osrg/gobgp/pkg/server" +) + +func marshalRouteTargets(l []string) ([]*any.Any, error) { + rtList := make([]*any.Any, 0, len(l)) + for _, rtString := range l { + rt, err := bgp.ParseRouteTarget(rtString) + if err != nil { + return nil, err + } + rtList = append(rtList, apiutil.MarshalRT(rt)) + } + return rtList, nil +} + +func assignGlobalpolicy(bgpServer *server.BgpServer, a *config.ApplyPolicyConfig) { + toDefaultTable := func(r config.DefaultPolicyType) table.RouteType { + var def table.RouteType + switch r { + case config.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE: + def = table.ROUTE_TYPE_ACCEPT + case config.DEFAULT_POLICY_TYPE_REJECT_ROUTE: + def = table.ROUTE_TYPE_REJECT + } + return def + } + toPolicies := func(r []string) []*table.Policy { + p := make([]*table.Policy, 0, len(r)) + for _, n := range r { + p = append(p, &table.Policy{ + Name: n, + }) + } + return p + } + + def := toDefaultTable(a.DefaultImportPolicy) + ps := toPolicies(a.ImportPolicyList) + bgpServer.SetPolicyAssignment(context.Background(), &api.SetPolicyAssignmentRequest{ + Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{ + Name: table.GLOBAL_RIB_NAME, + Type: table.POLICY_DIRECTION_IMPORT, + Policies: ps, + Default: def, + }), + }) + + def = toDefaultTable(a.DefaultExportPolicy) + ps = toPolicies(a.ExportPolicyList) + bgpServer.SetPolicyAssignment(context.Background(), &api.SetPolicyAssignmentRequest{ + Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{ + Name: table.GLOBAL_RIB_NAME, + Type: table.POLICY_DIRECTION_EXPORT, + Policies: ps, + Default: def, + }), + }) + +} + +func addPeerGroups(bgpServer *server.BgpServer, addedPg []config.PeerGroup) { + for _, pg := range addedPg { + log.Infof("PeerGroup %s is added", pg.Config.PeerGroupName) + if err := bgpServer.AddPeerGroup(context.Background(), &api.AddPeerGroupRequest{ + PeerGroup: config.NewPeerGroupFromConfigStruct(&pg), + }); err != nil { + log.Warn(err) + } + } +} + +func deletePeerGroups(bgpServer *server.BgpServer, deletedPg []config.PeerGroup) { + for _, pg := range deletedPg { + log.Infof("PeerGroup %s is deleted", pg.Config.PeerGroupName) + if err := bgpServer.DeletePeerGroup(context.Background(), &api.DeletePeerGroupRequest{ + Name: pg.Config.PeerGroupName, + }); err != nil { + log.Warn(err) + } + } +} + +func updatePeerGroups(bgpServer *server.BgpServer, updatedPg []config.PeerGroup) bool { + for _, pg := range updatedPg { + log.Infof("PeerGroup %s is updated", pg.Config.PeerGroupName) + if u, err := bgpServer.UpdatePeerGroup(context.Background(), &api.UpdatePeerGroupRequest{ + PeerGroup: config.NewPeerGroupFromConfigStruct(&pg), + }); err != nil { + log.Warn(err) + } else { + return u.NeedsSoftResetIn + } + } + return false +} + +func addDynamicNeighbors(bgpServer *server.BgpServer, dynamicNeighbors []config.DynamicNeighbor) { + for _, dn := range dynamicNeighbors { + log.Infof("Dynamic Neighbor %s is added to PeerGroup %s", dn.Config.Prefix, dn.Config.PeerGroup) + if err := bgpServer.AddDynamicNeighbor(context.Background(), &api.AddDynamicNeighborRequest{ + DynamicNeighbor: &api.DynamicNeighbor{ + Prefix: dn.Config.Prefix, + PeerGroup: dn.Config.PeerGroup, + }, + }); err != nil { + log.Warn(err) + } + } +} + +func addNeighbors(bgpServer *server.BgpServer, added []config.Neighbor) { + for _, p := range added { + log.Infof("Peer %v is added", p.State.NeighborAddress) + if err := bgpServer.AddPeer(context.Background(), &api.AddPeerRequest{ + Peer: config.NewPeerFromConfigStruct(&p), + }); err != nil { + log.Warn(err) + } + } +} + +func deleteNeighbors(bgpServer *server.BgpServer, deleted []config.Neighbor) { + for _, p := range deleted { + log.Infof("Peer %v is deleted", p.State.NeighborAddress) + if err := bgpServer.DeletePeer(context.Background(), &api.DeletePeerRequest{ + Address: p.State.NeighborAddress, + }); err != nil { + log.Warn(err) + } + } +} + +func updateNeighbors(bgpServer *server.BgpServer, updated []config.Neighbor) bool { + for _, p := range updated { + log.Infof("Peer %v is updated", p.State.NeighborAddress) + if u, err := bgpServer.UpdatePeer(context.Background(), &api.UpdatePeerRequest{ + Peer: config.NewPeerFromConfigStruct(&p), + }); err != nil { + log.Warn(err) + } else { + return u.NeedsSoftResetIn + } + } + return false +} + +func ApplyInitialConfig(bgpServer *server.BgpServer, newConfig *config.BgpConfigSet, isGracefulRestart bool) *config.BgpConfigSet { + if err := bgpServer.StartBgp(context.Background(), &api.StartBgpRequest{ + Global: config.NewGlobalFromConfigStruct(&newConfig.Global), + }); err != nil { + log.Fatalf("failed to set global config: %s", err) + } + + if newConfig.Zebra.Config.Enabled { + tps := newConfig.Zebra.Config.RedistributeRouteTypeList + l := make([]string, 0, len(tps)) + for _, t := range tps { + l = append(l, string(t)) + } + if err := bgpServer.EnableZebra(context.Background(), &api.EnableZebraRequest{ + Url: newConfig.Zebra.Config.Url, + RouteTypes: l, + Version: uint32(newConfig.Zebra.Config.Version), + NexthopTriggerEnable: newConfig.Zebra.Config.NexthopTriggerEnable, + NexthopTriggerDelay: uint32(newConfig.Zebra.Config.NexthopTriggerDelay), + MplsLabelRangeSize: uint32(newConfig.Zebra.Config.MplsLabelRangeSize), + SoftwareName: newConfig.Zebra.Config.SoftwareName, + }); err != nil { + log.Fatalf("failed to set zebra config: %s", err) + } + } + + if len(newConfig.Collector.Config.Url) > 0 { + log.Fatal("collector feature is not supported") + } + + for _, c := range newConfig.RpkiServers { + if err := bgpServer.AddRpki(context.Background(), &api.AddRpkiRequest{ + Address: c.Config.Address, + Port: c.Config.Port, + Lifetime: c.Config.RecordLifetime, + }); err != nil { + log.Fatalf("failed to set rpki config: %s", err) + } + } + for _, c := range newConfig.BmpServers { + if err := bgpServer.AddBmp(context.Background(), &api.AddBmpRequest{ + Address: c.Config.Address, + Port: c.Config.Port, + SysName: c.Config.SysName, + SysDescr: c.Config.SysDescr, + Policy: api.AddBmpRequest_MonitoringPolicy(c.Config.RouteMonitoringPolicy.ToInt()), + StatisticsTimeout: int32(c.Config.StatisticsTimeout), + }); err != nil { + 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, err := marshalRouteTargets(vrf.Config.ImportRtList) + if err != nil { + log.Fatalf("failed to load vrf import rt config: %s", err) + } + exportRtList, err := marshalRouteTargets(vrf.Config.ExportRtList) + if err != nil { + log.Fatalf("failed to load vrf export rt config: %s", err) + } + + if err := bgpServer.AddVrf(context.Background(), &api.AddVrfRequest{ + Vrf: &api.Vrf{ + Name: vrf.Config.Name, + Rd: apiutil.MarshalRD(rd), + Id: uint32(vrf.Config.Id), + ImportRt: importRtList, + ExportRt: exportRtList, + }, + }); err != nil { + log.Fatalf("failed to set vrf config: %s", err) + } + } + for _, c := range newConfig.MrtDump { + if len(c.Config.FileName) == 0 { + continue + } + if err := bgpServer.EnableMrt(context.Background(), &api.EnableMrtRequest{ + DumpType: int32(c.Config.DumpType.ToInt()), + Filename: c.Config.FileName, + DumpInterval: c.Config.DumpInterval, + RotationInterval: c.Config.RotationInterval, + }); err != nil { + log.Fatalf("failed to set mrt config: %s", err) + } + } + p := config.ConfigSetToRoutingPolicy(newConfig) + rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p) + if err != nil { + log.Warn(err) + } else { + bgpServer.SetPolicies(context.Background(), &api.SetPoliciesRequest{ + DefinedSets: rp.DefinedSets, + Policies: rp.Policies, + }) + } + + assignGlobalpolicy(bgpServer, &newConfig.Global.ApplyPolicy.Config) + + added := newConfig.Neighbors + addedPg := newConfig.PeerGroups + if isGracefulRestart { + for i, n := range added { + if n.GracefulRestart.Config.Enabled { + added[i].GracefulRestart.State.LocalRestarting = true + } + } + } + + addPeerGroups(bgpServer, addedPg) + addDynamicNeighbors(bgpServer, newConfig.DynamicNeighbors) + addNeighbors(bgpServer, added) + return newConfig +} + +func UpdateConfig(bgpServer *server.BgpServer, c, newConfig *config.BgpConfigSet) *config.BgpConfigSet { + addedPg, deletedPg, updatedPg := config.UpdatePeerGroupConfig(c, newConfig) + added, deleted, updated := config.UpdateNeighborConfig(c, newConfig) + updatePolicy := config.CheckPolicyDifference(config.ConfigSetToRoutingPolicy(c), config.ConfigSetToRoutingPolicy(newConfig)) + + if updatePolicy { + log.Info("Policy config is updated") + p := config.ConfigSetToRoutingPolicy(newConfig) + rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p) + if err != nil { + log.Warn(err) + } else { + bgpServer.SetPolicies(context.Background(), &api.SetPoliciesRequest{ + DefinedSets: rp.DefinedSets, + Policies: rp.Policies, + }) + } + } + // global policy update + if !newConfig.Global.ApplyPolicy.Config.Equal(&c.Global.ApplyPolicy.Config) { + assignGlobalpolicy(bgpServer, &newConfig.Global.ApplyPolicy.Config) + updatePolicy = true + } + + addPeerGroups(bgpServer, addedPg) + deletePeerGroups(bgpServer, deletedPg) + needsSoftResetIn := updatePeerGroups(bgpServer, updatedPg) + updatePolicy = updatePolicy || needsSoftResetIn + addDynamicNeighbors(bgpServer, newConfig.DynamicNeighbors) + addNeighbors(bgpServer, added) + deleteNeighbors(bgpServer, deleted) + needsSoftResetIn = updateNeighbors(bgpServer, updated) + updatePolicy = updatePolicy || needsSoftResetIn + + if updatePolicy { + if err := bgpServer.ResetPeer(context.Background(), &api.ResetPeerRequest{ + Address: "", + Direction: api.ResetPeerRequest_IN, + Soft: true, + }); err != nil { + log.Warn(err) + } + } + return newConfig +} |