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