github.com/osrg/gobgp/v3@v3.30.0/pkg/config/config.go (about) 1 package config 2 3 import ( 4 "context" 5 6 apb "google.golang.org/protobuf/types/known/anypb" 7 8 api "github.com/osrg/gobgp/v3/api" 9 "github.com/osrg/gobgp/v3/internal/pkg/table" 10 "github.com/osrg/gobgp/v3/pkg/apiutil" 11 "github.com/osrg/gobgp/v3/pkg/config/oc" 12 "github.com/osrg/gobgp/v3/pkg/log" 13 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 14 "github.com/osrg/gobgp/v3/pkg/server" 15 ) 16 17 // ReadConfigFile parses a config file into a BgpConfigSet which can be applied 18 // using InitialConfig and UpdateConfig. 19 func ReadConfigFile(configFile, configType string) (*oc.BgpConfigSet, error) { 20 return oc.ReadConfigfile(configFile, configType) 21 } 22 23 // WatchConfigFile calls the callback function anytime an update to the 24 // config file is detected. 25 func WatchConfigFile(configFile, configType string, callBack func()) { 26 oc.WatchConfigFile(configFile, configType, callBack) 27 } 28 29 func marshalRouteTargets(l []string) ([]*apb.Any, error) { 30 rtList := make([]*apb.Any, 0, len(l)) 31 for _, rtString := range l { 32 rt, err := bgp.ParseRouteTarget(rtString) 33 if err != nil { 34 return nil, err 35 } 36 a, err := apiutil.MarshalRT(rt) 37 if err != nil { 38 return nil, err 39 } 40 rtList = append(rtList, a) 41 } 42 return rtList, nil 43 } 44 45 func assignGlobalpolicy(ctx context.Context, bgpServer *server.BgpServer, a *oc.ApplyPolicyConfig) { 46 toDefaultTable := func(r oc.DefaultPolicyType) table.RouteType { 47 var def table.RouteType 48 switch r { 49 case oc.DEFAULT_POLICY_TYPE_ACCEPT_ROUTE: 50 def = table.ROUTE_TYPE_ACCEPT 51 case oc.DEFAULT_POLICY_TYPE_REJECT_ROUTE: 52 def = table.ROUTE_TYPE_REJECT 53 } 54 return def 55 } 56 toPolicies := func(r []string) []*table.Policy { 57 p := make([]*table.Policy, 0, len(r)) 58 for _, n := range r { 59 p = append(p, &table.Policy{ 60 Name: n, 61 }) 62 } 63 return p 64 } 65 66 def := toDefaultTable(a.DefaultImportPolicy) 67 ps := toPolicies(a.ImportPolicyList) 68 bgpServer.SetPolicyAssignment(ctx, &api.SetPolicyAssignmentRequest{ 69 Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{ 70 Name: table.GLOBAL_RIB_NAME, 71 Type: table.POLICY_DIRECTION_IMPORT, 72 Policies: ps, 73 Default: def, 74 }), 75 }) 76 77 def = toDefaultTable(a.DefaultExportPolicy) 78 ps = toPolicies(a.ExportPolicyList) 79 bgpServer.SetPolicyAssignment(ctx, &api.SetPolicyAssignmentRequest{ 80 Assignment: table.NewAPIPolicyAssignmentFromTableStruct(&table.PolicyAssignment{ 81 Name: table.GLOBAL_RIB_NAME, 82 Type: table.POLICY_DIRECTION_EXPORT, 83 Policies: ps, 84 Default: def, 85 }), 86 }) 87 88 } 89 90 func addPeerGroups(ctx context.Context, bgpServer *server.BgpServer, addedPg []oc.PeerGroup) { 91 for _, pg := range addedPg { 92 bgpServer.Log().Info("Add PeerGroup", 93 log.Fields{ 94 "Topic": "config", 95 "Key": pg.Config.PeerGroupName, 96 }) 97 98 if err := bgpServer.AddPeerGroup(ctx, &api.AddPeerGroupRequest{ 99 PeerGroup: oc.NewPeerGroupFromConfigStruct(&pg), 100 }); err != nil { 101 bgpServer.Log().Warn("Failed to add PeerGroup", 102 log.Fields{ 103 "Topic": "config", 104 "Key": pg.Config.PeerGroupName, 105 "Error": err}) 106 } 107 } 108 } 109 110 func deletePeerGroups(ctx context.Context, bgpServer *server.BgpServer, deletedPg []oc.PeerGroup) { 111 for _, pg := range deletedPg { 112 bgpServer.Log().Info("delete PeerGroup", 113 log.Fields{ 114 "Topic": "config", 115 "Key": pg.Config.PeerGroupName}) 116 if err := bgpServer.DeletePeerGroup(ctx, &api.DeletePeerGroupRequest{ 117 Name: pg.Config.PeerGroupName, 118 }); err != nil { 119 bgpServer.Log().Warn("Failed to delete PeerGroup", 120 log.Fields{ 121 "Topic": "config", 122 "Key": pg.Config.PeerGroupName, 123 "Error": err}) 124 } 125 } 126 } 127 128 func updatePeerGroups(ctx context.Context, bgpServer *server.BgpServer, updatedPg []oc.PeerGroup) bool { 129 for _, pg := range updatedPg { 130 bgpServer.Log().Info("update PeerGroup", 131 log.Fields{ 132 "Topic": "config", 133 "Key": pg.Config.PeerGroupName}) 134 if u, err := bgpServer.UpdatePeerGroup(ctx, &api.UpdatePeerGroupRequest{ 135 PeerGroup: oc.NewPeerGroupFromConfigStruct(&pg), 136 }); err != nil { 137 bgpServer.Log().Warn("Failed to update PeerGroup", 138 log.Fields{ 139 "Topic": "config", 140 "Key": pg.Config.PeerGroupName, 141 "Error": err}) 142 } else { 143 return u.NeedsSoftResetIn 144 } 145 } 146 return false 147 } 148 149 func addDynamicNeighbors(ctx context.Context, bgpServer *server.BgpServer, dynamicNeighbors []oc.DynamicNeighbor) { 150 for _, dn := range dynamicNeighbors { 151 bgpServer.Log().Info("Add Dynamic Neighbor to PeerGroup", 152 log.Fields{ 153 "Topic": "config", 154 "Key": dn.Config.PeerGroup, 155 "Prefix": dn.Config.Prefix}) 156 if err := bgpServer.AddDynamicNeighbor(ctx, &api.AddDynamicNeighborRequest{ 157 DynamicNeighbor: &api.DynamicNeighbor{ 158 Prefix: dn.Config.Prefix, 159 PeerGroup: dn.Config.PeerGroup, 160 }, 161 }); err != nil { 162 bgpServer.Log().Warn("Failed to add Dynamic Neighbor to PeerGroup", 163 log.Fields{ 164 "Topic": "config", 165 "Key": dn.Config.PeerGroup, 166 "Prefix": dn.Config.Prefix, 167 "Error": err}) 168 } 169 } 170 } 171 172 func addNeighbors(ctx context.Context, bgpServer *server.BgpServer, added []oc.Neighbor) { 173 for _, p := range added { 174 bgpServer.Log().Info("Add Peer", 175 log.Fields{ 176 "Topic": "config", 177 "Key": p.State.NeighborAddress}) 178 if err := bgpServer.AddPeer(ctx, &api.AddPeerRequest{ 179 Peer: oc.NewPeerFromConfigStruct(&p), 180 }); err != nil { 181 bgpServer.Log().Warn("Failed to add Peer", 182 log.Fields{ 183 "Topic": "config", 184 "Key": p.State.NeighborAddress, 185 "Error": err}) 186 } 187 } 188 } 189 190 func deleteNeighbors(ctx context.Context, bgpServer *server.BgpServer, deleted []oc.Neighbor) { 191 for _, p := range deleted { 192 bgpServer.Log().Info("Delete Peer", 193 log.Fields{ 194 "Topic": "config", 195 "Key": p.State.NeighborAddress}) 196 if err := bgpServer.DeletePeer(ctx, &api.DeletePeerRequest{ 197 Address: p.State.NeighborAddress, 198 }); err != nil { 199 bgpServer.Log().Warn("Failed to delete Peer", 200 log.Fields{ 201 "Topic": "config", 202 "Key": p.State.NeighborAddress, 203 "Error": err}) 204 } 205 } 206 } 207 208 func updateNeighbors(ctx context.Context, bgpServer *server.BgpServer, updated []oc.Neighbor) bool { 209 for _, p := range updated { 210 bgpServer.Log().Info("Update Peer", 211 log.Fields{ 212 "Topic": "config", 213 "Key": p.State.NeighborAddress}) 214 if u, err := bgpServer.UpdatePeer(ctx, &api.UpdatePeerRequest{ 215 Peer: oc.NewPeerFromConfigStruct(&p), 216 }); err != nil { 217 bgpServer.Log().Warn("Failed to update Peer", 218 log.Fields{ 219 "Topic": "config", 220 "Key": p.State.NeighborAddress, 221 "Error": err}) 222 } else { 223 return u.NeedsSoftResetIn 224 } 225 } 226 return false 227 } 228 229 // InitialConfig applies initial configuration to a pristine gobgp instance. It 230 // can only be called once for an instance. Subsequent changes to the 231 // configuration can be applied using UpdateConfig. The BgpConfigSet can be 232 // obtained by calling ReadConfigFile. If graceful restart behavior is desired, 233 // pass true for isGracefulRestart. Otherwise, pass false. 234 func InitialConfig(ctx context.Context, bgpServer *server.BgpServer, newConfig *oc.BgpConfigSet, isGracefulRestart bool) (*oc.BgpConfigSet, error) { 235 if err := bgpServer.StartBgp(ctx, &api.StartBgpRequest{ 236 Global: oc.NewGlobalFromConfigStruct(&newConfig.Global), 237 }); err != nil { 238 bgpServer.Log().Fatal("failed to set global config", 239 log.Fields{"Topic": "config", "Error": err}) 240 } 241 242 if newConfig.Zebra.Config.Enabled { 243 tps := newConfig.Zebra.Config.RedistributeRouteTypeList 244 l := make([]string, 0, len(tps)) 245 l = append(l, tps...) 246 if err := bgpServer.EnableZebra(ctx, &api.EnableZebraRequest{ 247 Url: newConfig.Zebra.Config.Url, 248 RouteTypes: l, 249 Version: uint32(newConfig.Zebra.Config.Version), 250 NexthopTriggerEnable: newConfig.Zebra.Config.NexthopTriggerEnable, 251 NexthopTriggerDelay: uint32(newConfig.Zebra.Config.NexthopTriggerDelay), 252 MplsLabelRangeSize: uint32(newConfig.Zebra.Config.MplsLabelRangeSize), 253 SoftwareName: newConfig.Zebra.Config.SoftwareName, 254 }); err != nil { 255 bgpServer.Log().Fatal("failed to set zebra config", 256 log.Fields{"Topic": "config", "Error": err}) 257 } 258 } 259 260 if len(newConfig.Collector.Config.Url) > 0 { 261 bgpServer.Log().Fatal("collector feature is not supported", 262 log.Fields{"Topic": "config"}) 263 } 264 265 for _, c := range newConfig.RpkiServers { 266 if err := bgpServer.AddRpki(ctx, &api.AddRpkiRequest{ 267 Address: c.Config.Address, 268 Port: c.Config.Port, 269 Lifetime: c.Config.RecordLifetime, 270 }); err != nil { 271 bgpServer.Log().Fatal("failed to set rpki config", 272 log.Fields{"Topic": "config", "Error": err}) 273 } 274 } 275 for _, c := range newConfig.BmpServers { 276 if err := bgpServer.AddBmp(ctx, &api.AddBmpRequest{ 277 Address: c.Config.Address, 278 Port: c.Config.Port, 279 SysName: c.Config.SysName, 280 SysDescr: c.Config.SysDescr, 281 Policy: api.AddBmpRequest_MonitoringPolicy(c.Config.RouteMonitoringPolicy.ToInt()), 282 StatisticsTimeout: int32(c.Config.StatisticsTimeout), 283 }); err != nil { 284 bgpServer.Log().Fatal("failed to set bmp config", 285 log.Fields{"Topic": "config", "Error": err}) 286 } 287 } 288 for _, vrf := range newConfig.Vrfs { 289 rd, err := bgp.ParseRouteDistinguisher(vrf.Config.Rd) 290 if err != nil { 291 bgpServer.Log().Fatal("failed to load vrf rd config", 292 log.Fields{"Topic": "config", "Error": err}) 293 } 294 295 importRtList, err := marshalRouteTargets(vrf.Config.ImportRtList) 296 if err != nil { 297 bgpServer.Log().Fatal("failed to load vrf import rt config", 298 log.Fields{"Topic": "config", "Error": err}) 299 } 300 exportRtList, err := marshalRouteTargets(vrf.Config.ExportRtList) 301 if err != nil { 302 bgpServer.Log().Fatal("failed to load vrf export rt config", 303 log.Fields{"Topic": "config", "Error": err}) 304 } 305 306 a, err := apiutil.MarshalRD(rd) 307 if err != nil { 308 bgpServer.Log().Fatal("failed to set vrf config", 309 log.Fields{"Topic": "config", "Error": err}) 310 } 311 if err := bgpServer.AddVrf(ctx, &api.AddVrfRequest{ 312 Vrf: &api.Vrf{ 313 Name: vrf.Config.Name, 314 Rd: a, 315 Id: uint32(vrf.Config.Id), 316 ImportRt: importRtList, 317 ExportRt: exportRtList, 318 }, 319 }); err != nil { 320 bgpServer.Log().Fatal("failed to set vrf config", 321 log.Fields{"Topic": "config", "Error": err}) 322 } 323 } 324 for _, c := range newConfig.MrtDump { 325 if len(c.Config.FileName) == 0 { 326 continue 327 } 328 if err := bgpServer.EnableMrt(ctx, &api.EnableMrtRequest{ 329 Type: api.EnableMrtRequest_DumpType(c.Config.DumpType.ToInt()), 330 Filename: c.Config.FileName, 331 DumpInterval: c.Config.DumpInterval, 332 RotationInterval: c.Config.RotationInterval, 333 }); err != nil { 334 bgpServer.Log().Fatal("failed to set mrt config", 335 log.Fields{"Topic": "config", "Error": err}) 336 } 337 } 338 p := oc.ConfigSetToRoutingPolicy(newConfig) 339 rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p) 340 if err != nil { 341 bgpServer.Log().Fatal("failed to update policy config", 342 log.Fields{"Topic": "config", "Error": err}) 343 } else { 344 bgpServer.SetPolicies(ctx, &api.SetPoliciesRequest{ 345 DefinedSets: rp.DefinedSets, 346 Policies: rp.Policies, 347 }) 348 } 349 350 assignGlobalpolicy(ctx, bgpServer, &newConfig.Global.ApplyPolicy.Config) 351 352 added := newConfig.Neighbors 353 addedPg := newConfig.PeerGroups 354 if isGracefulRestart { 355 for i, n := range added { 356 if n.GracefulRestart.Config.Enabled { 357 added[i].GracefulRestart.State.LocalRestarting = true 358 } 359 } 360 } 361 362 addPeerGroups(ctx, bgpServer, addedPg) 363 addDynamicNeighbors(ctx, bgpServer, newConfig.DynamicNeighbors) 364 addNeighbors(ctx, bgpServer, added) 365 return newConfig, nil 366 } 367 368 // UpdateConfig updates the configuration of a running gobgp instance. 369 // InitialConfig must have been called once before this can be called for 370 // subsequent changes to config. The differences are that this call 1) does not 371 // hangle graceful restart and 2) requires a BgpConfigSet for the previous 372 // configuration so that it can compute the delta between it and the new 373 // config. The new BgpConfigSet can be obtained using ReadConfigFile. 374 func UpdateConfig(ctx context.Context, bgpServer *server.BgpServer, c, newConfig *oc.BgpConfigSet) (*oc.BgpConfigSet, error) { 375 addedPg, deletedPg, updatedPg := oc.UpdatePeerGroupConfig(bgpServer.Log(), c, newConfig) 376 added, deleted, updated := oc.UpdateNeighborConfig(bgpServer.Log(), c, newConfig) 377 updatePolicy := oc.CheckPolicyDifference(bgpServer.Log(), oc.ConfigSetToRoutingPolicy(c), oc.ConfigSetToRoutingPolicy(newConfig)) 378 379 if updatePolicy { 380 bgpServer.Log().Info("policy config is update", log.Fields{"Topic": "config"}) 381 p := oc.ConfigSetToRoutingPolicy(newConfig) 382 rp, err := table.NewAPIRoutingPolicyFromConfigStruct(p) 383 if err != nil { 384 bgpServer.Log().Warn("failed to update policy config", 385 log.Fields{ 386 "Topic": "config", 387 "Error": err}) 388 } else { 389 bgpServer.SetPolicies(ctx, &api.SetPoliciesRequest{ 390 DefinedSets: rp.DefinedSets, 391 Policies: rp.Policies, 392 }) 393 } 394 } 395 // global policy update 396 if !newConfig.Global.ApplyPolicy.Config.Equal(&c.Global.ApplyPolicy.Config) { 397 assignGlobalpolicy(ctx, bgpServer, &newConfig.Global.ApplyPolicy.Config) 398 updatePolicy = true 399 } 400 401 addPeerGroups(ctx, bgpServer, addedPg) 402 deletePeerGroups(ctx, bgpServer, deletedPg) 403 needsSoftResetIn := updatePeerGroups(ctx, bgpServer, updatedPg) 404 updatePolicy = updatePolicy || needsSoftResetIn 405 addDynamicNeighbors(ctx, bgpServer, newConfig.DynamicNeighbors) 406 addNeighbors(ctx, bgpServer, added) 407 deleteNeighbors(ctx, bgpServer, deleted) 408 needsSoftResetIn = updateNeighbors(ctx, bgpServer, updated) 409 updatePolicy = updatePolicy || needsSoftResetIn 410 411 if updatePolicy { 412 if err := bgpServer.ResetPeer(ctx, &api.ResetPeerRequest{ 413 Address: "", 414 Direction: api.ResetPeerRequest_IN, 415 Soft: true, 416 }); err != nil { 417 bgpServer.Log().Fatal("failed to update policy config", 418 log.Fields{"Topic": "config", "Error": err}) 419 } 420 } 421 return newConfig, nil 422 }