github.com/osrg/gobgp/v3@v3.30.0/pkg/config/oc/default.go (about) 1 package oc 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "math" 7 "net" 8 "reflect" 9 "strconv" 10 11 "github.com/osrg/gobgp/v3/internal/pkg/version" 12 "github.com/osrg/gobgp/v3/pkg/packet/bgp" 13 "github.com/osrg/gobgp/v3/pkg/packet/bmp" 14 "github.com/osrg/gobgp/v3/pkg/packet/rtr" 15 "github.com/osrg/gobgp/v3/pkg/zebra" 16 "github.com/spf13/viper" 17 ) 18 19 const ( 20 DEFAULT_HOLDTIME = 90 21 DEFAULT_IDLE_HOLDTIME_AFTER_RESET = 30 22 DEFAULT_CONNECT_RETRY = 120 23 ) 24 25 var forcedOverwrittenConfig = []string{ 26 "neighbor.config.peer-as", 27 "neighbor.timers.config.minimum-advertisement-interval", 28 } 29 30 var configuredFields map[string]interface{} 31 32 func RegisterConfiguredFields(addr string, n interface{}) { 33 if configuredFields == nil { 34 configuredFields = make(map[string]interface{}) 35 } 36 configuredFields[addr] = n 37 } 38 39 func defaultAfiSafi(typ AfiSafiType, enable bool) AfiSafi { 40 return AfiSafi{ 41 Config: AfiSafiConfig{ 42 AfiSafiName: typ, 43 Enabled: enable, 44 }, 45 State: AfiSafiState{ 46 AfiSafiName: typ, 47 Family: bgp.AddressFamilyValueMap[string(typ)], 48 }, 49 } 50 } 51 52 func SetDefaultNeighborConfigValues(n *Neighbor, pg *PeerGroup, g *Global) error { 53 // Determines this function is called against the same Neighbor struct, 54 // and if already called, returns immediately. 55 if n.State.LocalAs != 0 { 56 return nil 57 } 58 59 return setDefaultNeighborConfigValuesWithViper(nil, n, g, pg) 60 } 61 62 func setDefaultNeighborConfigValuesWithViper(v *viper.Viper, n *Neighbor, g *Global, pg *PeerGroup) error { 63 if n == nil { 64 return fmt.Errorf("neighbor config is nil") 65 } 66 if g == nil { 67 return fmt.Errorf("global config is nil") 68 } 69 70 if v == nil { 71 v = viper.New() 72 } 73 74 if pg != nil { 75 if err := OverwriteNeighborConfigWithPeerGroup(n, pg); err != nil { 76 return err 77 } 78 } 79 80 if n.Config.LocalAs == 0 { 81 n.Config.LocalAs = g.Config.As 82 if !g.Confederation.Config.Enabled || n.IsConfederation(g) { 83 n.Config.LocalAs = g.Config.As 84 } else { 85 n.Config.LocalAs = g.Confederation.Config.Identifier 86 } 87 } 88 n.State.LocalAs = n.Config.LocalAs 89 90 if n.Config.PeerAs != n.Config.LocalAs { 91 n.Config.PeerType = PEER_TYPE_EXTERNAL 92 n.State.PeerType = PEER_TYPE_EXTERNAL 93 n.State.RemovePrivateAs = n.Config.RemovePrivateAs 94 n.AsPathOptions.State.ReplacePeerAs = n.AsPathOptions.Config.ReplacePeerAs 95 } else { 96 n.Config.PeerType = PEER_TYPE_INTERNAL 97 n.State.PeerType = PEER_TYPE_INTERNAL 98 if string(n.Config.RemovePrivateAs) != "" { 99 return fmt.Errorf("can't set remove-private-as for iBGP peer") 100 } 101 if n.AsPathOptions.Config.ReplacePeerAs { 102 return fmt.Errorf("can't set replace-peer-as for iBGP peer") 103 } 104 } 105 106 if n.State.NeighborAddress == "" { 107 n.State.NeighborAddress = n.Config.NeighborAddress 108 } 109 110 n.State.PeerAs = n.Config.PeerAs 111 n.AsPathOptions.State.AllowOwnAs = n.AsPathOptions.Config.AllowOwnAs 112 113 if !v.IsSet("neighbor.error-handling.config.treat-as-withdraw") { 114 n.ErrorHandling.Config.TreatAsWithdraw = true 115 } 116 117 if !v.IsSet("neighbor.timers.config.connect-retry") && n.Timers.Config.ConnectRetry == 0 { 118 n.Timers.Config.ConnectRetry = float64(DEFAULT_CONNECT_RETRY) 119 } 120 if !v.IsSet("neighbor.timers.config.hold-time") && n.Timers.Config.HoldTime == 0 { 121 n.Timers.Config.HoldTime = float64(DEFAULT_HOLDTIME) 122 } 123 if !v.IsSet("neighbor.timers.config.keepalive-interval") && n.Timers.Config.KeepaliveInterval == 0 { 124 n.Timers.Config.KeepaliveInterval = n.Timers.Config.HoldTime / 3 125 } 126 if !v.IsSet("neighbor.timers.config.idle-hold-time-after-reset") && n.Timers.Config.IdleHoldTimeAfterReset == 0 { 127 n.Timers.Config.IdleHoldTimeAfterReset = float64(DEFAULT_IDLE_HOLDTIME_AFTER_RESET) 128 } 129 130 if n.Config.NeighborInterface != "" { 131 if n.RouteServer.Config.RouteServerClient { 132 return fmt.Errorf("configuring route server client as unnumbered peer is not supported") 133 } 134 addr, err := GetIPv6LinkLocalNeighborAddress(n.Config.NeighborInterface) 135 if err != nil { 136 return err 137 } 138 n.State.NeighborAddress = addr 139 } 140 141 if n.Transport.Config.LocalAddress == "" { 142 if n.State.NeighborAddress == "" { 143 return fmt.Errorf("no neighbor address/interface specified") 144 } 145 ipAddr, err := net.ResolveIPAddr("ip", n.State.NeighborAddress) 146 if err != nil { 147 return err 148 } 149 localAddress := "0.0.0.0" 150 if ipAddr.IP.To4() == nil { 151 localAddress = "::" 152 if ipAddr.Zone != "" { 153 localAddress, err = getIPv6LinkLocalAddress(ipAddr.Zone) 154 if err != nil { 155 return err 156 } 157 } 158 } 159 n.Transport.Config.LocalAddress = localAddress 160 } 161 162 if len(n.AfiSafis) == 0 { 163 if n.Config.NeighborInterface != "" { 164 n.AfiSafis = []AfiSafi{ 165 defaultAfiSafi(AFI_SAFI_TYPE_IPV4_UNICAST, true), 166 defaultAfiSafi(AFI_SAFI_TYPE_IPV6_UNICAST, true), 167 } 168 } else if ipAddr, err := net.ResolveIPAddr("ip", n.State.NeighborAddress); err != nil { 169 return fmt.Errorf("invalid neighbor address: %s", n.State.NeighborAddress) 170 } else if ipAddr.IP.To4() != nil { 171 n.AfiSafis = []AfiSafi{defaultAfiSafi(AFI_SAFI_TYPE_IPV4_UNICAST, true)} 172 } else { 173 n.AfiSafis = []AfiSafi{defaultAfiSafi(AFI_SAFI_TYPE_IPV6_UNICAST, true)} 174 } 175 for i := range n.AfiSafis { 176 n.AfiSafis[i].AddPaths.Config.Receive = n.AddPaths.Config.Receive 177 n.AfiSafis[i].AddPaths.State.Receive = n.AddPaths.Config.Receive 178 n.AfiSafis[i].AddPaths.Config.SendMax = n.AddPaths.Config.SendMax 179 n.AfiSafis[i].AddPaths.State.SendMax = n.AddPaths.Config.SendMax 180 } 181 } else { 182 afs, err := extractArray(v.Get("neighbor.afi-safis")) 183 if err != nil { 184 return err 185 } 186 for i := range n.AfiSafis { 187 vv := viper.New() 188 if len(afs) > i { 189 vv.Set("afi-safi", afs[i]) 190 } 191 rf, err := bgp.GetRouteFamily(string(n.AfiSafis[i].Config.AfiSafiName)) 192 if err != nil { 193 return err 194 } 195 n.AfiSafis[i].State.Family = rf 196 n.AfiSafis[i].State.AfiSafiName = n.AfiSafis[i].Config.AfiSafiName 197 if !vv.IsSet("afi-safi.config.enabled") { 198 n.AfiSafis[i].Config.Enabled = true 199 } 200 n.AfiSafis[i].MpGracefulRestart.State.Enabled = n.AfiSafis[i].MpGracefulRestart.Config.Enabled 201 if !vv.IsSet("afi-safi.add-paths.config.receive") { 202 if n.AddPaths.Config.Receive { 203 n.AfiSafis[i].AddPaths.Config.Receive = n.AddPaths.Config.Receive 204 } 205 } 206 n.AfiSafis[i].AddPaths.State.Receive = n.AfiSafis[i].AddPaths.Config.Receive 207 if !vv.IsSet("afi-safi.add-paths.config.send-max") { 208 if n.AddPaths.Config.SendMax != 0 { 209 n.AfiSafis[i].AddPaths.Config.SendMax = n.AddPaths.Config.SendMax 210 } 211 } 212 n.AfiSafis[i].AddPaths.State.SendMax = n.AfiSafis[i].AddPaths.Config.SendMax 213 } 214 } 215 216 n.State.Description = n.Config.Description 217 n.State.AdminDown = n.Config.AdminDown 218 219 if n.GracefulRestart.Config.Enabled { 220 if !v.IsSet("neighbor.graceful-restart.config.restart-time") && n.GracefulRestart.Config.RestartTime == 0 { 221 // RFC 4724 4. Operation 222 // A suggested default for the Restart Time is a value less than or 223 // equal to the HOLDTIME carried in the OPEN. 224 n.GracefulRestart.Config.RestartTime = uint16(n.Timers.Config.HoldTime) 225 } 226 if !v.IsSet("neighbor.graceful-restart.config.deferral-time") && n.GracefulRestart.Config.DeferralTime == 0 { 227 // RFC 4724 4.1. Procedures for the Restarting Speaker 228 // The value of this timer should be large 229 // enough, so as to provide all the peers of the Restarting Speaker with 230 // enough time to send all the routes to the Restarting Speaker 231 n.GracefulRestart.Config.DeferralTime = uint16(360) 232 } 233 } 234 235 if n.EbgpMultihop.Config.Enabled { 236 if n.TtlSecurity.Config.Enabled { 237 return fmt.Errorf("ebgp-multihop and ttl-security are mututally exclusive") 238 } 239 if n.EbgpMultihop.Config.MultihopTtl == 0 { 240 n.EbgpMultihop.Config.MultihopTtl = 255 241 } 242 } else if n.TtlSecurity.Config.Enabled { 243 if n.TtlSecurity.Config.TtlMin == 0 { 244 n.TtlSecurity.Config.TtlMin = 255 245 } 246 } 247 248 if n.RouteReflector.Config.RouteReflectorClient { 249 if n.RouteReflector.Config.RouteReflectorClusterId == "" { 250 n.RouteReflector.State.RouteReflectorClusterId = RrClusterIdType(g.Config.RouterId) 251 } else { 252 id := string(n.RouteReflector.Config.RouteReflectorClusterId) 253 if ip := net.ParseIP(id).To4(); ip != nil { 254 n.RouteReflector.State.RouteReflectorClusterId = n.RouteReflector.Config.RouteReflectorClusterId 255 } else if num, err := strconv.ParseUint(id, 10, 32); err == nil { 256 ip = make(net.IP, 4) 257 binary.BigEndian.PutUint32(ip, uint32(num)) 258 n.RouteReflector.State.RouteReflectorClusterId = RrClusterIdType(ip.String()) 259 } else { 260 return fmt.Errorf("route-reflector-cluster-id should be specified as IPv4 address or 32-bit unsigned integer") 261 } 262 } 263 } 264 265 return nil 266 } 267 268 func SetDefaultGlobalConfigValues(g *Global) error { 269 if len(g.AfiSafis) == 0 { 270 g.AfiSafis = []AfiSafi{} 271 for k := range AfiSafiTypeToIntMap { 272 g.AfiSafis = append(g.AfiSafis, defaultAfiSafi(k, true)) 273 } 274 } 275 276 if g.Config.Port == 0 { 277 g.Config.Port = bgp.BGP_PORT 278 } 279 280 if len(g.Config.LocalAddressList) == 0 { 281 g.Config.LocalAddressList = []string{"0.0.0.0", "::"} 282 } 283 return nil 284 } 285 286 func setDefaultVrfConfigValues(v *Vrf) error { 287 if v == nil { 288 return fmt.Errorf("cannot set default values for nil vrf config") 289 } 290 291 if v.Config.Name == "" { 292 return fmt.Errorf("specify vrf name") 293 } 294 295 _, err := bgp.ParseRouteDistinguisher(v.Config.Rd) 296 if err != nil { 297 return fmt.Errorf("invalid rd for vrf %s: %s", v.Config.Name, v.Config.Rd) 298 } 299 300 if len(v.Config.ImportRtList) == 0 { 301 v.Config.ImportRtList = v.Config.BothRtList 302 } 303 for _, rtString := range v.Config.ImportRtList { 304 _, err := bgp.ParseRouteTarget(rtString) 305 if err != nil { 306 return fmt.Errorf("invalid import rt for vrf %s: %s", v.Config.Name, rtString) 307 } 308 } 309 310 if len(v.Config.ExportRtList) == 0 { 311 v.Config.ExportRtList = v.Config.BothRtList 312 } 313 for _, rtString := range v.Config.ExportRtList { 314 _, err := bgp.ParseRouteTarget(rtString) 315 if err != nil { 316 return fmt.Errorf("invalid export rt for vrf %s: %s", v.Config.Name, rtString) 317 } 318 } 319 320 return nil 321 } 322 323 func SetDefaultConfigValues(b *BgpConfigSet) error { 324 return setDefaultConfigValuesWithViper(nil, b) 325 } 326 327 func setDefaultPolicyConfigValuesWithViper(v *viper.Viper, p *PolicyDefinition) error { 328 stmts, err := extractArray(v.Get("policy.statements")) 329 if err != nil { 330 return err 331 } 332 for i := range p.Statements { 333 vv := viper.New() 334 if len(stmts) > i { 335 vv.Set("statement", stmts[i]) 336 } 337 if !vv.IsSet("statement.actions.route-disposition") { 338 p.Statements[i].Actions.RouteDisposition = ROUTE_DISPOSITION_NONE 339 } 340 } 341 return nil 342 } 343 344 func setDefaultConfigValuesWithViper(v *viper.Viper, b *BgpConfigSet) error { 345 if v == nil { 346 v = viper.New() 347 } 348 349 if err := SetDefaultGlobalConfigValues(&b.Global); err != nil { 350 return err 351 } 352 353 for idx, server := range b.BmpServers { 354 if server.Config.SysName == "" { 355 server.Config.SysName = "GoBGP" 356 } 357 if server.Config.SysDescr == "" { 358 server.Config.SysDescr = version.Version() 359 } 360 if server.Config.Port == 0 { 361 server.Config.Port = bmp.BMP_DEFAULT_PORT 362 } 363 if server.Config.RouteMonitoringPolicy == "" { 364 server.Config.RouteMonitoringPolicy = BMP_ROUTE_MONITORING_POLICY_TYPE_PRE_POLICY 365 } 366 // statistics-timeout is uint16 value and implicitly less than 65536 367 if server.Config.StatisticsTimeout != 0 && server.Config.StatisticsTimeout < 15 { 368 return fmt.Errorf("too small statistics-timeout value: %d", server.Config.StatisticsTimeout) 369 } 370 b.BmpServers[idx] = server 371 } 372 373 vrfNames := make(map[string]struct{}) 374 vrfIDs := make(map[uint32]struct{}) 375 for idx, vrf := range b.Vrfs { 376 if err := setDefaultVrfConfigValues(&vrf); err != nil { 377 return err 378 } 379 380 if _, ok := vrfNames[vrf.Config.Name]; ok { 381 return fmt.Errorf("duplicated vrf name: %s", vrf.Config.Name) 382 } 383 vrfNames[vrf.Config.Name] = struct{}{} 384 385 if vrf.Config.Id != 0 { 386 if _, ok := vrfIDs[vrf.Config.Id]; ok { 387 return fmt.Errorf("duplicated vrf id: %d", vrf.Config.Id) 388 } 389 vrfIDs[vrf.Config.Id] = struct{}{} 390 } 391 392 b.Vrfs[idx] = vrf 393 } 394 // Auto assign VRF identifier 395 for idx, vrf := range b.Vrfs { 396 if vrf.Config.Id == 0 { 397 for id := uint32(1); id < math.MaxUint32; id++ { 398 if _, ok := vrfIDs[id]; !ok { 399 vrf.Config.Id = id 400 vrfIDs[id] = struct{}{} 401 break 402 } 403 } 404 } 405 b.Vrfs[idx] = vrf 406 } 407 408 if b.Zebra.Config.Url == "" { 409 b.Zebra.Config.Url = "unix:/var/run/quagga/zserv.api" 410 } 411 if b.Zebra.Config.Version < zebra.MinZapiVer { 412 b.Zebra.Config.Version = zebra.MinZapiVer 413 } else if b.Zebra.Config.Version > zebra.MaxZapiVer { 414 b.Zebra.Config.Version = zebra.MaxZapiVer 415 } 416 417 if !v.IsSet("zebra.config.nexthop-trigger-enable") && !b.Zebra.Config.NexthopTriggerEnable && b.Zebra.Config.Version > 2 { 418 b.Zebra.Config.NexthopTriggerEnable = true 419 } 420 if b.Zebra.Config.NexthopTriggerDelay == 0 { 421 b.Zebra.Config.NexthopTriggerDelay = 5 422 } 423 424 list, err := extractArray(v.Get("neighbors")) 425 if err != nil { 426 return err 427 } 428 429 for idx, n := range b.Neighbors { 430 vv := viper.New() 431 if len(list) > idx { 432 vv.Set("neighbor", list[idx]) 433 } 434 435 pg, err := b.getPeerGroup(n.Config.PeerGroup) 436 if err != nil { 437 return nil 438 } 439 440 if pg != nil { 441 identifier := vv.Get("neighbor.config.neighbor-address") 442 if identifier == nil { 443 identifier = vv.Get("neighbor.config.neighbor-interface") 444 } 445 RegisterConfiguredFields(identifier.(string), list[idx]) 446 } 447 448 if err := setDefaultNeighborConfigValuesWithViper(vv, &n, &b.Global, pg); err != nil { 449 return err 450 } 451 b.Neighbors[idx] = n 452 } 453 454 for _, d := range b.DynamicNeighbors { 455 if err := d.validate(b); err != nil { 456 return err 457 } 458 } 459 460 for idx, r := range b.RpkiServers { 461 if r.Config.Port == 0 { 462 b.RpkiServers[idx].Config.Port = rtr.RPKI_DEFAULT_PORT 463 } 464 } 465 466 list, err = extractArray(v.Get("policy-definitions")) 467 if err != nil { 468 return err 469 } 470 471 for idx, p := range b.PolicyDefinitions { 472 vv := viper.New() 473 if len(list) > idx { 474 vv.Set("policy", list[idx]) 475 } 476 if err := setDefaultPolicyConfigValuesWithViper(vv, &p); err != nil { 477 return err 478 } 479 b.PolicyDefinitions[idx] = p 480 } 481 482 return nil 483 } 484 485 func OverwriteNeighborConfigWithPeerGroup(c *Neighbor, pg *PeerGroup) error { 486 v := viper.New() 487 488 val, ok := configuredFields[c.Config.NeighborAddress] 489 if ok { 490 v.Set("neighbor", val) 491 } else { 492 v.Set("neighbor.config.peer-group", c.Config.PeerGroup) 493 } 494 495 overwriteConfig(&c.Config, &pg.Config, "neighbor.config", v) 496 overwriteConfig(&c.Timers.Config, &pg.Timers.Config, "neighbor.timers.config", v) 497 overwriteConfig(&c.Transport.Config, &pg.Transport.Config, "neighbor.transport.config", v) 498 overwriteConfig(&c.ErrorHandling.Config, &pg.ErrorHandling.Config, "neighbor.error-handling.config", v) 499 overwriteConfig(&c.LoggingOptions.Config, &pg.LoggingOptions.Config, "neighbor.logging-options.config", v) 500 overwriteConfig(&c.EbgpMultihop.Config, &pg.EbgpMultihop.Config, "neighbor.ebgp-multihop.config", v) 501 overwriteConfig(&c.RouteReflector.Config, &pg.RouteReflector.Config, "neighbor.route-reflector.config", v) 502 overwriteConfig(&c.AsPathOptions.Config, &pg.AsPathOptions.Config, "neighbor.as-path-options.config", v) 503 overwriteConfig(&c.AddPaths.Config, &pg.AddPaths.Config, "neighbor.add-paths.config", v) 504 overwriteConfig(&c.GracefulRestart.Config, &pg.GracefulRestart.Config, "neighbor.gradeful-restart.config", v) 505 overwriteConfig(&c.ApplyPolicy.Config, &pg.ApplyPolicy.Config, "neighbor.apply-policy.config", v) 506 overwriteConfig(&c.UseMultiplePaths.Config, &pg.UseMultiplePaths.Config, "neighbor.use-multiple-paths.config", v) 507 overwriteConfig(&c.RouteServer.Config, &pg.RouteServer.Config, "neighbor.route-server.config", v) 508 overwriteConfig(&c.TtlSecurity.Config, &pg.TtlSecurity.Config, "neighbor.ttl-security.config", v) 509 510 if !v.IsSet("neighbor.afi-safis") { 511 c.AfiSafis = append([]AfiSafi{}, pg.AfiSafis...) 512 } 513 514 return nil 515 } 516 517 func overwriteConfig(c, pg interface{}, tagPrefix string, v *viper.Viper) { 518 nValue := reflect.Indirect(reflect.ValueOf(c)) 519 nType := reflect.Indirect(nValue).Type() 520 pgValue := reflect.Indirect(reflect.ValueOf(pg)) 521 pgType := reflect.Indirect(pgValue).Type() 522 523 for i := 0; i < pgType.NumField(); i++ { 524 field := pgType.Field(i).Name 525 tag := tagPrefix + "." + nType.Field(i).Tag.Get("mapstructure") 526 if func() bool { 527 for _, t := range forcedOverwrittenConfig { 528 if t == tag { 529 return true 530 } 531 } 532 return false 533 }() || !v.IsSet(tag) { 534 nValue.FieldByName(field).Set(pgValue.FieldByName(field)) 535 } 536 } 537 }