github.com/osrg/gobgp@v2.0.0+incompatible/internal/pkg/config/util.go (about)

     1  // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package config
    17  
    18  import (
    19  	"fmt"
    20  	"net"
    21  	"path/filepath"
    22  	"regexp"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/golang/protobuf/ptypes"
    28  	"github.com/golang/protobuf/ptypes/timestamp"
    29  	api "github.com/osrg/gobgp/api"
    30  	"github.com/osrg/gobgp/internal/pkg/apiutil"
    31  	"github.com/osrg/gobgp/pkg/packet/bgp"
    32  )
    33  
    34  // Returns config file type by retrieving extension from the given path.
    35  // If no corresponding type found, returns the given def as the default value.
    36  func detectConfigFileType(path, def string) string {
    37  	switch ext := filepath.Ext(path); ext {
    38  	case ".toml":
    39  		return "toml"
    40  	case ".yaml", ".yml":
    41  		return "yaml"
    42  	case ".json":
    43  		return "json"
    44  	default:
    45  		return def
    46  	}
    47  }
    48  
    49  // yaml is decoded as []interface{}
    50  // but toml is decoded as []map[string]interface{}.
    51  // currently, viper can't hide this difference.
    52  // handle the difference here.
    53  func extractArray(intf interface{}) ([]interface{}, error) {
    54  	if intf != nil {
    55  		list, ok := intf.([]interface{})
    56  		if ok {
    57  			return list, nil
    58  		}
    59  		l, ok := intf.([]map[string]interface{})
    60  		if !ok {
    61  			return nil, fmt.Errorf("invalid configuration: neither []interface{} nor []map[string]interface{}")
    62  		}
    63  		list = make([]interface{}, 0, len(l))
    64  		for _, m := range l {
    65  			list = append(list, m)
    66  		}
    67  		return list, nil
    68  	}
    69  	return nil, nil
    70  }
    71  
    72  func getIPv6LinkLocalAddress(ifname string) (string, error) {
    73  	ifi, err := net.InterfaceByName(ifname)
    74  	if err != nil {
    75  		return "", err
    76  	}
    77  	addrs, err := ifi.Addrs()
    78  	if err != nil {
    79  		return "", err
    80  	}
    81  	for _, addr := range addrs {
    82  		ip := addr.(*net.IPNet).IP
    83  		if ip.To4() == nil && ip.IsLinkLocalUnicast() {
    84  			return fmt.Sprintf("%s%%%s", ip.String(), ifname), nil
    85  		}
    86  	}
    87  	return "", fmt.Errorf("no ipv6 link local address for %s", ifname)
    88  }
    89  
    90  func (b *BgpConfigSet) getPeerGroup(n string) (*PeerGroup, error) {
    91  	if n == "" {
    92  		return nil, nil
    93  	}
    94  	for _, pg := range b.PeerGroups {
    95  		if n == pg.Config.PeerGroupName {
    96  			return &pg, nil
    97  		}
    98  	}
    99  	return nil, fmt.Errorf("no such peer-group: %s", n)
   100  }
   101  
   102  func (d *DynamicNeighbor) validate(b *BgpConfigSet) error {
   103  	if d.Config.PeerGroup == "" {
   104  		return fmt.Errorf("dynamic neighbor requires the peer group config")
   105  	}
   106  
   107  	if _, err := b.getPeerGroup(d.Config.PeerGroup); err != nil {
   108  		return err
   109  	}
   110  	if _, _, err := net.ParseCIDR(d.Config.Prefix); err != nil {
   111  		return fmt.Errorf("invalid dynamic neighbor prefix %s", d.Config.Prefix)
   112  	}
   113  	return nil
   114  }
   115  
   116  func (n *Neighbor) IsConfederationMember(g *Global) bool {
   117  	for _, member := range g.Confederation.Config.MemberAsList {
   118  		if member == n.Config.PeerAs {
   119  			return true
   120  		}
   121  	}
   122  	return false
   123  }
   124  
   125  func (n *Neighbor) IsConfederation(g *Global) bool {
   126  	if n.Config.PeerAs == g.Config.As {
   127  		return true
   128  	}
   129  	return n.IsConfederationMember(g)
   130  }
   131  
   132  func (n *Neighbor) IsEBGPPeer(g *Global) bool {
   133  	return n.Config.PeerAs != g.Config.As
   134  }
   135  
   136  func (n *Neighbor) CreateRfMap() map[bgp.RouteFamily]bgp.BGPAddPathMode {
   137  	rfMap := make(map[bgp.RouteFamily]bgp.BGPAddPathMode)
   138  	for _, af := range n.AfiSafis {
   139  		mode := bgp.BGP_ADD_PATH_NONE
   140  		if af.AddPaths.State.Receive {
   141  			mode |= bgp.BGP_ADD_PATH_RECEIVE
   142  		}
   143  		if af.AddPaths.State.SendMax > 0 {
   144  			mode |= bgp.BGP_ADD_PATH_SEND
   145  		}
   146  		rfMap[af.State.Family] = mode
   147  	}
   148  	return rfMap
   149  }
   150  
   151  func (n *Neighbor) GetAfiSafi(family bgp.RouteFamily) *AfiSafi {
   152  	for _, a := range n.AfiSafis {
   153  		if string(a.Config.AfiSafiName) == family.String() {
   154  			return &a
   155  		}
   156  	}
   157  	return nil
   158  }
   159  
   160  func (n *Neighbor) ExtractNeighborAddress() (string, error) {
   161  	addr := n.State.NeighborAddress
   162  	if addr == "" {
   163  		addr = n.Config.NeighborAddress
   164  		if addr == "" {
   165  			return "", fmt.Errorf("NeighborAddress is not configured")
   166  		}
   167  	}
   168  	return addr, nil
   169  }
   170  
   171  func (n *Neighbor) IsAddPathReceiveEnabled(family bgp.RouteFamily) bool {
   172  	for _, af := range n.AfiSafis {
   173  		if af.State.Family == family {
   174  			return af.AddPaths.State.Receive
   175  		}
   176  	}
   177  	return false
   178  }
   179  
   180  type AfiSafis []AfiSafi
   181  
   182  func (c AfiSafis) ToRfList() ([]bgp.RouteFamily, error) {
   183  	rfs := make([]bgp.RouteFamily, 0, len(c))
   184  	for _, af := range c {
   185  		rfs = append(rfs, af.State.Family)
   186  	}
   187  	return rfs, nil
   188  }
   189  
   190  func inSlice(n Neighbor, b []Neighbor) int {
   191  	for i, nb := range b {
   192  		if nb.State.NeighborAddress == n.State.NeighborAddress {
   193  			return i
   194  		}
   195  	}
   196  	return -1
   197  }
   198  
   199  func existPeerGroup(n string, b []PeerGroup) int {
   200  	for i, nb := range b {
   201  		if nb.Config.PeerGroupName == n {
   202  			return i
   203  		}
   204  	}
   205  	return -1
   206  }
   207  
   208  func isAfiSafiChanged(x, y []AfiSafi) bool {
   209  	if len(x) != len(y) {
   210  		return true
   211  	}
   212  	m := make(map[string]AfiSafi)
   213  	for i, e := range x {
   214  		m[string(e.Config.AfiSafiName)] = x[i]
   215  	}
   216  	for _, e := range y {
   217  		if v, ok := m[string(e.Config.AfiSafiName)]; !ok || !v.Config.Equal(&e.Config) || !v.AddPaths.Config.Equal(&e.AddPaths.Config) {
   218  			return true
   219  		}
   220  	}
   221  	return false
   222  }
   223  
   224  func (n *Neighbor) NeedsResendOpenMessage(new *Neighbor) bool {
   225  	return !n.Config.Equal(&new.Config) ||
   226  		!n.Transport.Config.Equal(&new.Transport.Config) ||
   227  		!n.AddPaths.Config.Equal(&new.AddPaths.Config) ||
   228  		!n.GracefulRestart.Config.Equal(&new.GracefulRestart.Config) ||
   229  		isAfiSafiChanged(n.AfiSafis, new.AfiSafis)
   230  }
   231  
   232  // TODO: these regexp are duplicated in api
   233  var _regexpPrefixMaskLengthRange = regexp.MustCompile(`(\d+)\.\.(\d+)`)
   234  
   235  func ParseMaskLength(prefix, mask string) (int, int, error) {
   236  	_, ipNet, err := net.ParseCIDR(prefix)
   237  	if err != nil {
   238  		return 0, 0, fmt.Errorf("invalid prefix: %s", prefix)
   239  	}
   240  	if mask == "" {
   241  		l, _ := ipNet.Mask.Size()
   242  		return l, l, nil
   243  	}
   244  	elems := _regexpPrefixMaskLengthRange.FindStringSubmatch(mask)
   245  	if len(elems) != 3 {
   246  		return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
   247  	}
   248  	// we've already checked the range is sane by regexp
   249  	min, _ := strconv.ParseUint(elems[1], 10, 8)
   250  	max, _ := strconv.ParseUint(elems[2], 10, 8)
   251  	if min > max {
   252  		return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
   253  	}
   254  	if ipv4 := ipNet.IP.To4(); ipv4 != nil {
   255  		f := func(i uint64) bool {
   256  			return i <= 32
   257  		}
   258  		if !f(min) || !f(max) {
   259  			return 0, 0, fmt.Errorf("ipv4 mask length range outside scope :%s", mask)
   260  		}
   261  	} else {
   262  		f := func(i uint64) bool {
   263  			return i <= 128
   264  		}
   265  		if !f(min) || !f(max) {
   266  			return 0, 0, fmt.Errorf("ipv6 mask length range outside scope :%s", mask)
   267  		}
   268  	}
   269  	return int(min), int(max), nil
   270  }
   271  
   272  func extractFamilyFromConfigAfiSafi(c *AfiSafi) uint32 {
   273  	if c == nil {
   274  		return 0
   275  	}
   276  	// If address family value is already stored in AfiSafiState structure,
   277  	// we prefer to use this value.
   278  	if c.State.Family != 0 {
   279  		return uint32(c.State.Family)
   280  	}
   281  	// In case that Neighbor structure came from CLI or gRPC, address family
   282  	// value in AfiSafiState structure can be omitted.
   283  	// Here extracts value from AfiSafiName field in AfiSafiConfig structure.
   284  	if rf, err := bgp.GetRouteFamily(string(c.Config.AfiSafiName)); err == nil {
   285  		return uint32(rf)
   286  	}
   287  	// Ignores invalid address family name
   288  	return 0
   289  }
   290  
   291  func newAfiSafiConfigFromConfigStruct(c *AfiSafi) *api.AfiSafiConfig {
   292  	rf := extractFamilyFromConfigAfiSafi(c)
   293  	afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(rf))
   294  	return &api.AfiSafiConfig{
   295  		Family:  &api.Family{Afi: api.Family_Afi(afi), Safi: api.Family_Safi(safi)},
   296  		Enabled: c.Config.Enabled,
   297  	}
   298  }
   299  
   300  func newApplyPolicyFromConfigStruct(c *ApplyPolicy) *api.ApplyPolicy {
   301  	applyPolicy := &api.ApplyPolicy{
   302  		ImportPolicy: &api.PolicyAssignment{
   303  			Direction:     api.PolicyDirection_IMPORT,
   304  			DefaultAction: api.RouteAction(c.Config.DefaultImportPolicy.ToInt()),
   305  		},
   306  		ExportPolicy: &api.PolicyAssignment{
   307  			Direction:     api.PolicyDirection_EXPORT,
   308  			DefaultAction: api.RouteAction(c.Config.DefaultExportPolicy.ToInt()),
   309  		},
   310  	}
   311  
   312  	for _, pname := range c.Config.ImportPolicyList {
   313  		applyPolicy.ImportPolicy.Policies = append(applyPolicy.ImportPolicy.Policies, &api.Policy{Name: pname})
   314  	}
   315  	for _, pname := range c.Config.ExportPolicyList {
   316  		applyPolicy.ExportPolicy.Policies = append(applyPolicy.ExportPolicy.Policies, &api.Policy{Name: pname})
   317  	}
   318  
   319  	return applyPolicy
   320  }
   321  
   322  func newPrefixLimitFromConfigStruct(c *AfiSafi) *api.PrefixLimit {
   323  	if c.PrefixLimit.Config.MaxPrefixes == 0 {
   324  		return nil
   325  	}
   326  	afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(c.State.Family))
   327  	return &api.PrefixLimit{
   328  		Family:               &api.Family{Afi: api.Family_Afi(afi), Safi: api.Family_Safi(safi)},
   329  		MaxPrefixes:          c.PrefixLimit.Config.MaxPrefixes,
   330  		ShutdownThresholdPct: uint32(c.PrefixLimit.Config.ShutdownThresholdPct),
   331  	}
   332  }
   333  
   334  func newRouteTargetMembershipFromConfigStruct(c *RouteTargetMembership) *api.RouteTargetMembership {
   335  	return &api.RouteTargetMembership{
   336  		Config: &api.RouteTargetMembershipConfig{
   337  			DeferralTime: uint32(c.Config.DeferralTime),
   338  		},
   339  	}
   340  }
   341  
   342  func newLongLivedGracefulRestartFromConfigStruct(c *LongLivedGracefulRestart) *api.LongLivedGracefulRestart {
   343  	return &api.LongLivedGracefulRestart{
   344  		Config: &api.LongLivedGracefulRestartConfig{
   345  			Enabled:     c.Config.Enabled,
   346  			RestartTime: c.Config.RestartTime,
   347  		},
   348  	}
   349  }
   350  
   351  func newAddPathsFromConfigStruct(c *AddPaths) *api.AddPaths {
   352  	return &api.AddPaths{
   353  		Config: &api.AddPathsConfig{
   354  			Receive: c.Config.Receive,
   355  			SendMax: uint32(c.Config.SendMax),
   356  		},
   357  	}
   358  }
   359  
   360  func newRouteSelectionOptionsFromConfigStruct(c *RouteSelectionOptions) *api.RouteSelectionOptions {
   361  	return &api.RouteSelectionOptions{
   362  		Config: &api.RouteSelectionOptionsConfig{
   363  			AlwaysCompareMed:        c.Config.AlwaysCompareMed,
   364  			IgnoreAsPathLength:      c.Config.IgnoreAsPathLength,
   365  			ExternalCompareRouterId: c.Config.ExternalCompareRouterId,
   366  			AdvertiseInactiveRoutes: c.Config.AdvertiseInactiveRoutes,
   367  			EnableAigp:              c.Config.EnableAigp,
   368  			IgnoreNextHopIgpMetric:  c.Config.IgnoreNextHopIgpMetric,
   369  		},
   370  	}
   371  }
   372  
   373  func newMpGracefulRestartFromConfigStruct(c *MpGracefulRestart) *api.MpGracefulRestart {
   374  	return &api.MpGracefulRestart{
   375  		Config: &api.MpGracefulRestartConfig{
   376  			Enabled: c.Config.Enabled,
   377  		},
   378  	}
   379  }
   380  
   381  func newUseMultiplePathsFromConfigStruct(c *UseMultiplePaths) *api.UseMultiplePaths {
   382  	return &api.UseMultiplePaths{
   383  		Config: &api.UseMultiplePathsConfig{
   384  			Enabled: c.Config.Enabled,
   385  		},
   386  		Ebgp: &api.Ebgp{
   387  			Config: &api.EbgpConfig{
   388  				AllowMultipleAs: c.Ebgp.Config.AllowMultipleAs,
   389  				MaximumPaths:    c.Ebgp.Config.MaximumPaths,
   390  			},
   391  		},
   392  		Ibgp: &api.Ibgp{
   393  			Config: &api.IbgpConfig{
   394  				MaximumPaths: c.Ibgp.Config.MaximumPaths,
   395  			},
   396  		},
   397  	}
   398  }
   399  
   400  func newAfiSafiFromConfigStruct(c *AfiSafi) *api.AfiSafi {
   401  	return &api.AfiSafi{
   402  		MpGracefulRestart:        newMpGracefulRestartFromConfigStruct(&c.MpGracefulRestart),
   403  		Config:                   newAfiSafiConfigFromConfigStruct(c),
   404  		ApplyPolicy:              newApplyPolicyFromConfigStruct(&c.ApplyPolicy),
   405  		RouteSelectionOptions:    newRouteSelectionOptionsFromConfigStruct(&c.RouteSelectionOptions),
   406  		UseMultiplePaths:         newUseMultiplePathsFromConfigStruct(&c.UseMultiplePaths),
   407  		PrefixLimits:             newPrefixLimitFromConfigStruct(c),
   408  		RouteTargetMembership:    newRouteTargetMembershipFromConfigStruct(&c.RouteTargetMembership),
   409  		LongLivedGracefulRestart: newLongLivedGracefulRestartFromConfigStruct(&c.LongLivedGracefulRestart),
   410  		AddPaths:                 newAddPathsFromConfigStruct(&c.AddPaths),
   411  	}
   412  }
   413  
   414  func ProtoTimestamp(secs int64) *timestamp.Timestamp {
   415  	if secs == 0 {
   416  		return nil
   417  	}
   418  	t, _ := ptypes.TimestampProto(time.Unix(secs, 0))
   419  	return t
   420  }
   421  
   422  func NewPeerFromConfigStruct(pconf *Neighbor) *api.Peer {
   423  	afiSafis := make([]*api.AfiSafi, 0, len(pconf.AfiSafis))
   424  	for _, f := range pconf.AfiSafis {
   425  		if afiSafi := newAfiSafiFromConfigStruct(&f); afiSafi != nil {
   426  			afiSafis = append(afiSafis, afiSafi)
   427  		}
   428  	}
   429  
   430  	timer := pconf.Timers
   431  	s := pconf.State
   432  	localAddress := pconf.Transport.Config.LocalAddress
   433  	if pconf.Transport.State.LocalAddress != "" {
   434  		localAddress = pconf.Transport.State.LocalAddress
   435  	}
   436  	remoteCap, err := apiutil.MarshalCapabilities(pconf.State.RemoteCapabilityList)
   437  	if err != nil {
   438  		return nil
   439  	}
   440  	localCap, err := apiutil.MarshalCapabilities(pconf.State.LocalCapabilityList)
   441  	if err != nil {
   442  		return nil
   443  	}
   444  	var removePrivateAs api.PeerConf_RemovePrivateAs
   445  	switch pconf.Config.RemovePrivateAs {
   446  	case REMOVE_PRIVATE_AS_OPTION_ALL:
   447  		removePrivateAs = api.PeerConf_ALL
   448  	case REMOVE_PRIVATE_AS_OPTION_REPLACE:
   449  		removePrivateAs = api.PeerConf_REPLACE
   450  	}
   451  	return &api.Peer{
   452  		ApplyPolicy: newApplyPolicyFromConfigStruct(&pconf.ApplyPolicy),
   453  		Conf: &api.PeerConf{
   454  			NeighborAddress:   pconf.Config.NeighborAddress,
   455  			PeerAs:            pconf.Config.PeerAs,
   456  			LocalAs:           pconf.Config.LocalAs,
   457  			PeerType:          uint32(pconf.Config.PeerType.ToInt()),
   458  			AuthPassword:      pconf.Config.AuthPassword,
   459  			RouteFlapDamping:  pconf.Config.RouteFlapDamping,
   460  			Description:       pconf.Config.Description,
   461  			PeerGroup:         pconf.Config.PeerGroup,
   462  			NeighborInterface: pconf.Config.NeighborInterface,
   463  			Vrf:               pconf.Config.Vrf,
   464  			AllowOwnAs:        uint32(pconf.AsPathOptions.Config.AllowOwnAs),
   465  			RemovePrivateAs:   removePrivateAs,
   466  			ReplacePeerAs:     pconf.AsPathOptions.Config.ReplacePeerAs,
   467  			AdminDown:         pconf.Config.AdminDown,
   468  		},
   469  		State: &api.PeerState{
   470  			SessionState: api.PeerState_SessionState(api.PeerState_SessionState_value[strings.ToUpper(string(s.SessionState))]),
   471  			AdminState:   api.PeerState_AdminState(s.AdminState.ToInt()),
   472  			Messages: &api.Messages{
   473  				Received: &api.Message{
   474  					Notification:   s.Messages.Received.Notification,
   475  					Update:         s.Messages.Received.Update,
   476  					Open:           s.Messages.Received.Open,
   477  					Keepalive:      s.Messages.Received.Keepalive,
   478  					Refresh:        s.Messages.Received.Refresh,
   479  					Discarded:      s.Messages.Received.Discarded,
   480  					Total:          s.Messages.Received.Total,
   481  					WithdrawUpdate: uint64(s.Messages.Received.WithdrawUpdate),
   482  					WithdrawPrefix: uint64(s.Messages.Received.WithdrawPrefix),
   483  				},
   484  				Sent: &api.Message{
   485  					Notification: s.Messages.Sent.Notification,
   486  					Update:       s.Messages.Sent.Update,
   487  					Open:         s.Messages.Sent.Open,
   488  					Keepalive:    s.Messages.Sent.Keepalive,
   489  					Refresh:      s.Messages.Sent.Refresh,
   490  					Discarded:    s.Messages.Sent.Discarded,
   491  					Total:        s.Messages.Sent.Total,
   492  				},
   493  			},
   494  			PeerAs:          s.PeerAs,
   495  			PeerType:        uint32(s.PeerType.ToInt()),
   496  			NeighborAddress: pconf.State.NeighborAddress,
   497  			Queues:          &api.Queues{},
   498  			RemoteCap:       remoteCap,
   499  			LocalCap:        localCap,
   500  			RouterId:        s.RemoteRouterId,
   501  		},
   502  		EbgpMultihop: &api.EbgpMultihop{
   503  			Enabled:     pconf.EbgpMultihop.Config.Enabled,
   504  			MultihopTtl: uint32(pconf.EbgpMultihop.Config.MultihopTtl),
   505  		},
   506  		Timers: &api.Timers{
   507  			Config: &api.TimersConfig{
   508  				ConnectRetry:      uint64(timer.Config.ConnectRetry),
   509  				HoldTime:          uint64(timer.Config.HoldTime),
   510  				KeepaliveInterval: uint64(timer.Config.KeepaliveInterval),
   511  			},
   512  			State: &api.TimersState{
   513  				KeepaliveInterval:  uint64(timer.State.KeepaliveInterval),
   514  				NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
   515  				Uptime:             ProtoTimestamp(timer.State.Uptime),
   516  				Downtime:           ProtoTimestamp(timer.State.Downtime),
   517  			},
   518  		},
   519  		RouteReflector: &api.RouteReflector{
   520  			RouteReflectorClient:    pconf.RouteReflector.Config.RouteReflectorClient,
   521  			RouteReflectorClusterId: string(pconf.RouteReflector.State.RouteReflectorClusterId),
   522  		},
   523  		RouteServer: &api.RouteServer{
   524  			RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
   525  		},
   526  		GracefulRestart: &api.GracefulRestart{
   527  			Enabled:             pconf.GracefulRestart.Config.Enabled,
   528  			RestartTime:         uint32(pconf.GracefulRestart.Config.RestartTime),
   529  			HelperOnly:          pconf.GracefulRestart.Config.HelperOnly,
   530  			DeferralTime:        uint32(pconf.GracefulRestart.Config.DeferralTime),
   531  			NotificationEnabled: pconf.GracefulRestart.Config.NotificationEnabled,
   532  			LonglivedEnabled:    pconf.GracefulRestart.Config.LongLivedEnabled,
   533  			LocalRestarting:     pconf.GracefulRestart.State.LocalRestarting,
   534  		},
   535  		Transport: &api.Transport{
   536  			RemotePort:   uint32(pconf.Transport.Config.RemotePort),
   537  			LocalAddress: localAddress,
   538  			PassiveMode:  pconf.Transport.Config.PassiveMode,
   539  		},
   540  		AfiSafis: afiSafis,
   541  	}
   542  }
   543  
   544  func NewPeerGroupFromConfigStruct(pconf *PeerGroup) *api.PeerGroup {
   545  	afiSafis := make([]*api.AfiSafi, 0, len(pconf.AfiSafis))
   546  	for _, f := range pconf.AfiSafis {
   547  		if afiSafi := newAfiSafiFromConfigStruct(&f); afiSafi != nil {
   548  			afiSafis = append(afiSafis, afiSafi)
   549  		}
   550  	}
   551  
   552  	timer := pconf.Timers
   553  	s := pconf.State
   554  	return &api.PeerGroup{
   555  		ApplyPolicy: newApplyPolicyFromConfigStruct(&pconf.ApplyPolicy),
   556  		Conf: &api.PeerGroupConf{
   557  			PeerAs:           pconf.Config.PeerAs,
   558  			LocalAs:          pconf.Config.LocalAs,
   559  			PeerType:         uint32(pconf.Config.PeerType.ToInt()),
   560  			AuthPassword:     pconf.Config.AuthPassword,
   561  			RouteFlapDamping: pconf.Config.RouteFlapDamping,
   562  			Description:      pconf.Config.Description,
   563  			PeerGroupName:    pconf.Config.PeerGroupName,
   564  		},
   565  		Info: &api.PeerGroupState{
   566  			PeerAs:        s.PeerAs,
   567  			PeerType:      uint32(s.PeerType.ToInt()),
   568  			TotalPaths:    s.TotalPaths,
   569  			TotalPrefixes: s.TotalPrefixes,
   570  		},
   571  		Timers: &api.Timers{
   572  			Config: &api.TimersConfig{
   573  				ConnectRetry:      uint64(timer.Config.ConnectRetry),
   574  				HoldTime:          uint64(timer.Config.HoldTime),
   575  				KeepaliveInterval: uint64(timer.Config.KeepaliveInterval),
   576  			},
   577  			State: &api.TimersState{
   578  				KeepaliveInterval:  uint64(timer.State.KeepaliveInterval),
   579  				NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
   580  				Uptime:             ProtoTimestamp(timer.State.Uptime),
   581  				Downtime:           ProtoTimestamp(timer.State.Downtime),
   582  			},
   583  		},
   584  		RouteReflector: &api.RouteReflector{
   585  			RouteReflectorClient:    pconf.RouteReflector.Config.RouteReflectorClient,
   586  			RouteReflectorClusterId: string(pconf.RouteReflector.Config.RouteReflectorClusterId),
   587  		},
   588  		RouteServer: &api.RouteServer{
   589  			RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
   590  		},
   591  		GracefulRestart: &api.GracefulRestart{
   592  			Enabled:             pconf.GracefulRestart.Config.Enabled,
   593  			RestartTime:         uint32(pconf.GracefulRestart.Config.RestartTime),
   594  			HelperOnly:          pconf.GracefulRestart.Config.HelperOnly,
   595  			DeferralTime:        uint32(pconf.GracefulRestart.Config.DeferralTime),
   596  			NotificationEnabled: pconf.GracefulRestart.Config.NotificationEnabled,
   597  			LonglivedEnabled:    pconf.GracefulRestart.Config.LongLivedEnabled,
   598  			LocalRestarting:     pconf.GracefulRestart.State.LocalRestarting,
   599  		},
   600  		Transport: &api.Transport{
   601  			RemotePort:   uint32(pconf.Transport.Config.RemotePort),
   602  			LocalAddress: pconf.Transport.Config.LocalAddress,
   603  			PassiveMode:  pconf.Transport.Config.PassiveMode,
   604  		},
   605  		AfiSafis: afiSafis,
   606  	}
   607  }
   608  
   609  func NewGlobalFromConfigStruct(c *Global) *api.Global {
   610  	families := make([]uint32, 0, len(c.AfiSafis))
   611  	for _, f := range c.AfiSafis {
   612  		families = append(families, uint32(AfiSafiTypeToIntMap[f.Config.AfiSafiName]))
   613  	}
   614  
   615  	applyPolicy := newApplyPolicyFromConfigStruct(&c.ApplyPolicy)
   616  
   617  	return &api.Global{
   618  		As:               c.Config.As,
   619  		RouterId:         c.Config.RouterId,
   620  		ListenPort:       c.Config.Port,
   621  		ListenAddresses:  c.Config.LocalAddressList,
   622  		Families:         families,
   623  		UseMultiplePaths: c.UseMultiplePaths.Config.Enabled,
   624  		RouteSelectionOptions: &api.RouteSelectionOptionsConfig{
   625  			AlwaysCompareMed:         c.RouteSelectionOptions.Config.AlwaysCompareMed,
   626  			IgnoreAsPathLength:       c.RouteSelectionOptions.Config.IgnoreAsPathLength,
   627  			ExternalCompareRouterId:  c.RouteSelectionOptions.Config.ExternalCompareRouterId,
   628  			AdvertiseInactiveRoutes:  c.RouteSelectionOptions.Config.AdvertiseInactiveRoutes,
   629  			EnableAigp:               c.RouteSelectionOptions.Config.EnableAigp,
   630  			IgnoreNextHopIgpMetric:   c.RouteSelectionOptions.Config.IgnoreNextHopIgpMetric,
   631  			DisableBestPathSelection: c.RouteSelectionOptions.Config.DisableBestPathSelection,
   632  		},
   633  		DefaultRouteDistance: &api.DefaultRouteDistance{
   634  			ExternalRouteDistance: uint32(c.DefaultRouteDistance.Config.ExternalRouteDistance),
   635  			InternalRouteDistance: uint32(c.DefaultRouteDistance.Config.InternalRouteDistance),
   636  		},
   637  		Confederation: &api.Confederation{
   638  			Enabled:      c.Confederation.Config.Enabled,
   639  			Identifier:   c.Confederation.Config.Identifier,
   640  			MemberAsList: c.Confederation.Config.MemberAsList,
   641  		},
   642  		GracefulRestart: &api.GracefulRestart{
   643  			Enabled:             c.GracefulRestart.Config.Enabled,
   644  			RestartTime:         uint32(c.GracefulRestart.Config.RestartTime),
   645  			StaleRoutesTime:     uint32(c.GracefulRestart.Config.StaleRoutesTime),
   646  			HelperOnly:          c.GracefulRestart.Config.HelperOnly,
   647  			DeferralTime:        uint32(c.GracefulRestart.Config.DeferralTime),
   648  			NotificationEnabled: c.GracefulRestart.Config.NotificationEnabled,
   649  			LonglivedEnabled:    c.GracefulRestart.Config.LongLivedEnabled,
   650  		},
   651  		ApplyPolicy: applyPolicy,
   652  	}
   653  }
   654  
   655  func newAPIPrefixFromConfigStruct(c Prefix) (*api.Prefix, error) {
   656  	min, max, err := ParseMaskLength(c.IpPrefix, c.MasklengthRange)
   657  	if err != nil {
   658  		return nil, err
   659  	}
   660  	return &api.Prefix{
   661  		IpPrefix:      c.IpPrefix,
   662  		MaskLengthMin: uint32(min),
   663  		MaskLengthMax: uint32(max),
   664  	}, nil
   665  }
   666  
   667  func NewAPIDefinedSetsFromConfigStruct(t *DefinedSets) ([]*api.DefinedSet, error) {
   668  	definedSets := make([]*api.DefinedSet, 0)
   669  
   670  	for _, ps := range t.PrefixSets {
   671  		prefixes := make([]*api.Prefix, 0)
   672  		for _, p := range ps.PrefixList {
   673  			ap, err := newAPIPrefixFromConfigStruct(p)
   674  			if err != nil {
   675  				return nil, err
   676  			}
   677  			prefixes = append(prefixes, ap)
   678  		}
   679  		definedSets = append(definedSets, &api.DefinedSet{
   680  			DefinedType: api.DefinedType_PREFIX,
   681  			Name:        ps.PrefixSetName,
   682  			Prefixes:    prefixes,
   683  		})
   684  	}
   685  
   686  	for _, ns := range t.NeighborSets {
   687  		definedSets = append(definedSets, &api.DefinedSet{
   688  			DefinedType: api.DefinedType_NEIGHBOR,
   689  			Name:        ns.NeighborSetName,
   690  			List:        ns.NeighborInfoList,
   691  		})
   692  	}
   693  
   694  	bs := t.BgpDefinedSets
   695  	for _, cs := range bs.CommunitySets {
   696  		definedSets = append(definedSets, &api.DefinedSet{
   697  			DefinedType: api.DefinedType_COMMUNITY,
   698  			Name:        cs.CommunitySetName,
   699  			List:        cs.CommunityList,
   700  		})
   701  	}
   702  
   703  	for _, es := range bs.ExtCommunitySets {
   704  		definedSets = append(definedSets, &api.DefinedSet{
   705  			DefinedType: api.DefinedType_EXT_COMMUNITY,
   706  			Name:        es.ExtCommunitySetName,
   707  			List:        es.ExtCommunityList,
   708  		})
   709  	}
   710  
   711  	for _, ls := range bs.LargeCommunitySets {
   712  		definedSets = append(definedSets, &api.DefinedSet{
   713  			DefinedType: api.DefinedType_LARGE_COMMUNITY,
   714  			Name:        ls.LargeCommunitySetName,
   715  			List:        ls.LargeCommunityList,
   716  		})
   717  	}
   718  
   719  	for _, as := range bs.AsPathSets {
   720  		definedSets = append(definedSets, &api.DefinedSet{
   721  			DefinedType: api.DefinedType_AS_PATH,
   722  			Name:        as.AsPathSetName,
   723  			List:        as.AsPathList,
   724  		})
   725  	}
   726  
   727  	return definedSets, nil
   728  }