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  }