github.com/osrg/gobgp/v3@v3.30.0/pkg/config/oc/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 oc
    17  
    18  import (
    19  	"fmt"
    20  	"net"
    21  	"path/filepath"
    22  	"regexp"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	tspb "google.golang.org/protobuf/types/known/timestamppb"
    28  
    29  	api "github.com/osrg/gobgp/v3/api"
    30  	"github.com/osrg/gobgp/v3/pkg/apiutil"
    31  	"github.com/osrg/gobgp/v3/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 != n.Config.LocalAs
   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) || !v.MpGracefulRestart.Config.Equal(&e.MpGracefulRestart.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.AsPathOptions.Config.Equal(&new.AsPathOptions.Config) ||
   229  		!n.GracefulRestart.Config.Equal(&new.GracefulRestart.Config) ||
   230  		isAfiSafiChanged(n.AfiSafis, new.AfiSafis)
   231  }
   232  
   233  // TODO: these regexp are duplicated in api
   234  var _regexpPrefixMaskLengthRange = regexp.MustCompile(`(\d+)\.\.(\d+)`)
   235  
   236  func ParseMaskLength(prefix, mask string) (int, int, error) {
   237  	_, ipNet, err := net.ParseCIDR(prefix)
   238  	if err != nil {
   239  		return 0, 0, fmt.Errorf("invalid prefix: %s", prefix)
   240  	}
   241  	if mask == "" {
   242  		l, _ := ipNet.Mask.Size()
   243  		return l, l, nil
   244  	}
   245  	elems := _regexpPrefixMaskLengthRange.FindStringSubmatch(mask)
   246  	if len(elems) != 3 {
   247  		return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
   248  	}
   249  	// we've already checked the range is sane by regexp
   250  	min, _ := strconv.ParseUint(elems[1], 10, 8)
   251  	max, _ := strconv.ParseUint(elems[2], 10, 8)
   252  	if min > max {
   253  		return 0, 0, fmt.Errorf("invalid mask length range: %s", mask)
   254  	}
   255  	if ipv4 := ipNet.IP.To4(); ipv4 != nil {
   256  		f := func(i uint64) bool {
   257  			return i <= 32
   258  		}
   259  		if !f(min) || !f(max) {
   260  			return 0, 0, fmt.Errorf("ipv4 mask length range outside scope :%s", mask)
   261  		}
   262  	} else {
   263  		f := func(i uint64) bool {
   264  			return i <= 128
   265  		}
   266  		if !f(min) || !f(max) {
   267  			return 0, 0, fmt.Errorf("ipv6 mask length range outside scope :%s", mask)
   268  		}
   269  	}
   270  	return int(min), int(max), nil
   271  }
   272  
   273  func extractFamilyFromConfigAfiSafi(c *AfiSafi) uint32 {
   274  	if c == nil {
   275  		return 0
   276  	}
   277  	// If address family value is already stored in AfiSafiState structure,
   278  	// we prefer to use this value.
   279  	if c.State.Family != 0 {
   280  		return uint32(c.State.Family)
   281  	}
   282  	// In case that Neighbor structure came from CLI or gRPC, address family
   283  	// value in AfiSafiState structure can be omitted.
   284  	// Here extracts value from AfiSafiName field in AfiSafiConfig structure.
   285  	if rf, err := bgp.GetRouteFamily(string(c.Config.AfiSafiName)); err == nil {
   286  		return uint32(rf)
   287  	}
   288  	// Ignores invalid address family name
   289  	return 0
   290  }
   291  
   292  func newAfiSafiConfigFromConfigStruct(c *AfiSafi) *api.AfiSafiConfig {
   293  	rf := extractFamilyFromConfigAfiSafi(c)
   294  	afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(rf))
   295  	return &api.AfiSafiConfig{
   296  		Family:  &api.Family{Afi: api.Family_Afi(afi), Safi: api.Family_Safi(safi)},
   297  		Enabled: c.Config.Enabled,
   298  	}
   299  }
   300  
   301  func newApplyPolicyFromConfigStruct(c *ApplyPolicy) *api.ApplyPolicy {
   302  	f := func(t DefaultPolicyType) api.RouteAction {
   303  		if t == DEFAULT_POLICY_TYPE_ACCEPT_ROUTE {
   304  			return api.RouteAction_ACCEPT
   305  		} else if t == DEFAULT_POLICY_TYPE_REJECT_ROUTE {
   306  			return api.RouteAction_REJECT
   307  		}
   308  		return api.RouteAction_NONE
   309  	}
   310  	applyPolicy := &api.ApplyPolicy{
   311  		ImportPolicy: &api.PolicyAssignment{
   312  			Direction:     api.PolicyDirection_IMPORT,
   313  			DefaultAction: f(c.Config.DefaultImportPolicy),
   314  		},
   315  		ExportPolicy: &api.PolicyAssignment{
   316  			Direction:     api.PolicyDirection_EXPORT,
   317  			DefaultAction: f(c.Config.DefaultExportPolicy),
   318  		},
   319  	}
   320  
   321  	for _, pname := range c.Config.ImportPolicyList {
   322  		applyPolicy.ImportPolicy.Policies = append(applyPolicy.ImportPolicy.Policies, &api.Policy{Name: pname})
   323  	}
   324  	for _, pname := range c.Config.ExportPolicyList {
   325  		applyPolicy.ExportPolicy.Policies = append(applyPolicy.ExportPolicy.Policies, &api.Policy{Name: pname})
   326  	}
   327  
   328  	return applyPolicy
   329  }
   330  
   331  func newPrefixLimitFromConfigStruct(c *AfiSafi) *api.PrefixLimit {
   332  	if c.PrefixLimit.Config.MaxPrefixes == 0 {
   333  		return nil
   334  	}
   335  	afi, safi := bgp.RouteFamilyToAfiSafi(bgp.RouteFamily(c.State.Family))
   336  	return &api.PrefixLimit{
   337  		Family:               &api.Family{Afi: api.Family_Afi(afi), Safi: api.Family_Safi(safi)},
   338  		MaxPrefixes:          c.PrefixLimit.Config.MaxPrefixes,
   339  		ShutdownThresholdPct: uint32(c.PrefixLimit.Config.ShutdownThresholdPct),
   340  	}
   341  }
   342  
   343  func newRouteTargetMembershipFromConfigStruct(c *RouteTargetMembership) *api.RouteTargetMembership {
   344  	return &api.RouteTargetMembership{
   345  		Config: &api.RouteTargetMembershipConfig{
   346  			DeferralTime: uint32(c.Config.DeferralTime),
   347  		},
   348  	}
   349  }
   350  
   351  func newLongLivedGracefulRestartFromConfigStruct(c *LongLivedGracefulRestart) *api.LongLivedGracefulRestart {
   352  	return &api.LongLivedGracefulRestart{
   353  		Config: &api.LongLivedGracefulRestartConfig{
   354  			Enabled:     c.Config.Enabled,
   355  			RestartTime: c.Config.RestartTime,
   356  		},
   357  	}
   358  }
   359  
   360  func newAddPathsFromConfigStruct(c *AddPaths) *api.AddPaths {
   361  	return &api.AddPaths{
   362  		Config: &api.AddPathsConfig{
   363  			Receive: c.Config.Receive,
   364  			SendMax: uint32(c.Config.SendMax),
   365  		},
   366  	}
   367  }
   368  
   369  func newRouteSelectionOptionsFromConfigStruct(c *RouteSelectionOptions) *api.RouteSelectionOptions {
   370  	return &api.RouteSelectionOptions{
   371  		Config: &api.RouteSelectionOptionsConfig{
   372  			AlwaysCompareMed:        c.Config.AlwaysCompareMed,
   373  			IgnoreAsPathLength:      c.Config.IgnoreAsPathLength,
   374  			ExternalCompareRouterId: c.Config.ExternalCompareRouterId,
   375  			AdvertiseInactiveRoutes: c.Config.AdvertiseInactiveRoutes,
   376  			EnableAigp:              c.Config.EnableAigp,
   377  			IgnoreNextHopIgpMetric:  c.Config.IgnoreNextHopIgpMetric,
   378  		},
   379  	}
   380  }
   381  
   382  func newMpGracefulRestartFromConfigStruct(c *MpGracefulRestart) *api.MpGracefulRestart {
   383  	return &api.MpGracefulRestart{
   384  		Config: &api.MpGracefulRestartConfig{
   385  			Enabled: c.Config.Enabled,
   386  		},
   387  		State: &api.MpGracefulRestartState{
   388  			Enabled:          c.State.Enabled,
   389  			Received:         c.State.Received,
   390  			Advertised:       c.State.Advertised,
   391  			EndOfRibReceived: c.State.EndOfRibReceived,
   392  			EndOfRibSent:     c.State.EndOfRibSent,
   393  		},
   394  	}
   395  }
   396  
   397  func newUseMultiplePathsFromConfigStruct(c *UseMultiplePaths) *api.UseMultiplePaths {
   398  	return &api.UseMultiplePaths{
   399  		Config: &api.UseMultiplePathsConfig{
   400  			Enabled: c.Config.Enabled,
   401  		},
   402  		Ebgp: &api.Ebgp{
   403  			Config: &api.EbgpConfig{
   404  				AllowMultipleAsn: c.Ebgp.Config.AllowMultipleAs,
   405  				MaximumPaths:     c.Ebgp.Config.MaximumPaths,
   406  			},
   407  		},
   408  		Ibgp: &api.Ibgp{
   409  			Config: &api.IbgpConfig{
   410  				MaximumPaths: c.Ibgp.Config.MaximumPaths,
   411  			},
   412  		},
   413  	}
   414  }
   415  
   416  func newAfiSafiFromConfigStruct(c *AfiSafi) *api.AfiSafi {
   417  	return &api.AfiSafi{
   418  		MpGracefulRestart:        newMpGracefulRestartFromConfigStruct(&c.MpGracefulRestart),
   419  		Config:                   newAfiSafiConfigFromConfigStruct(c),
   420  		ApplyPolicy:              newApplyPolicyFromConfigStruct(&c.ApplyPolicy),
   421  		RouteSelectionOptions:    newRouteSelectionOptionsFromConfigStruct(&c.RouteSelectionOptions),
   422  		UseMultiplePaths:         newUseMultiplePathsFromConfigStruct(&c.UseMultiplePaths),
   423  		PrefixLimits:             newPrefixLimitFromConfigStruct(c),
   424  		RouteTargetMembership:    newRouteTargetMembershipFromConfigStruct(&c.RouteTargetMembership),
   425  		LongLivedGracefulRestart: newLongLivedGracefulRestartFromConfigStruct(&c.LongLivedGracefulRestart),
   426  		AddPaths:                 newAddPathsFromConfigStruct(&c.AddPaths),
   427  	}
   428  }
   429  
   430  func ProtoTimestamp(secs int64) *tspb.Timestamp {
   431  	if secs == 0 {
   432  		return nil
   433  	}
   434  	return tspb.New(time.Unix(secs, 0))
   435  }
   436  
   437  func NewPeerFromConfigStruct(pconf *Neighbor) *api.Peer {
   438  	afiSafis := make([]*api.AfiSafi, 0, len(pconf.AfiSafis))
   439  	for _, f := range pconf.AfiSafis {
   440  		if afiSafi := newAfiSafiFromConfigStruct(&f); afiSafi != nil {
   441  			afiSafis = append(afiSafis, afiSafi)
   442  		}
   443  	}
   444  
   445  	timer := pconf.Timers
   446  	s := pconf.State
   447  	localAddress := pconf.Transport.Config.LocalAddress
   448  	if pconf.Transport.State.LocalAddress != "" {
   449  		localAddress = pconf.Transport.State.LocalAddress
   450  	}
   451  	remoteCap, err := apiutil.MarshalCapabilities(pconf.State.RemoteCapabilityList)
   452  	if err != nil {
   453  		return nil
   454  	}
   455  	localCap, err := apiutil.MarshalCapabilities(pconf.State.LocalCapabilityList)
   456  	if err != nil {
   457  		return nil
   458  	}
   459  	var removePrivate api.RemovePrivate
   460  	switch pconf.Config.RemovePrivateAs {
   461  	case REMOVE_PRIVATE_AS_OPTION_ALL:
   462  		removePrivate = api.RemovePrivate_REMOVE_ALL
   463  	case REMOVE_PRIVATE_AS_OPTION_REPLACE:
   464  		removePrivate = api.RemovePrivate_REPLACE
   465  	}
   466  	return &api.Peer{
   467  		ApplyPolicy: newApplyPolicyFromConfigStruct(&pconf.ApplyPolicy),
   468  		Conf: &api.PeerConf{
   469  			NeighborAddress:     pconf.Config.NeighborAddress,
   470  			PeerAsn:             pconf.Config.PeerAs,
   471  			LocalAsn:            pconf.Config.LocalAs,
   472  			Type:                api.PeerType(pconf.Config.PeerType.ToInt()),
   473  			AuthPassword:        pconf.Config.AuthPassword,
   474  			RouteFlapDamping:    pconf.Config.RouteFlapDamping,
   475  			Description:         pconf.Config.Description,
   476  			PeerGroup:           pconf.Config.PeerGroup,
   477  			NeighborInterface:   pconf.Config.NeighborInterface,
   478  			Vrf:                 pconf.Config.Vrf,
   479  			AllowOwnAsn:         uint32(pconf.AsPathOptions.Config.AllowOwnAs),
   480  			RemovePrivate:       removePrivate,
   481  			ReplacePeerAsn:      pconf.AsPathOptions.Config.ReplacePeerAs,
   482  			AdminDown:           pconf.Config.AdminDown,
   483  			SendSoftwareVersion: pconf.Config.SendSoftwareVersion,
   484  		},
   485  		State: &api.PeerState{
   486  			SessionState: api.PeerState_SessionState(api.PeerState_SessionState_value[strings.ToUpper(string(s.SessionState))]),
   487  			AdminState:   api.PeerState_AdminState(s.AdminState.ToInt()),
   488  			Messages: &api.Messages{
   489  				Received: &api.Message{
   490  					Notification:   s.Messages.Received.Notification,
   491  					Update:         s.Messages.Received.Update,
   492  					Open:           s.Messages.Received.Open,
   493  					Keepalive:      s.Messages.Received.Keepalive,
   494  					Refresh:        s.Messages.Received.Refresh,
   495  					Discarded:      s.Messages.Received.Discarded,
   496  					Total:          s.Messages.Received.Total,
   497  					WithdrawUpdate: uint64(s.Messages.Received.WithdrawUpdate),
   498  					WithdrawPrefix: uint64(s.Messages.Received.WithdrawPrefix),
   499  				},
   500  				Sent: &api.Message{
   501  					Notification: s.Messages.Sent.Notification,
   502  					Update:       s.Messages.Sent.Update,
   503  					Open:         s.Messages.Sent.Open,
   504  					Keepalive:    s.Messages.Sent.Keepalive,
   505  					Refresh:      s.Messages.Sent.Refresh,
   506  					Discarded:    s.Messages.Sent.Discarded,
   507  					Total:        s.Messages.Sent.Total,
   508  				},
   509  			},
   510  			PeerAsn:         s.PeerAs,
   511  			LocalAsn:        s.LocalAs,
   512  			Type:            api.PeerType(s.PeerType.ToInt()),
   513  			NeighborAddress: pconf.State.NeighborAddress,
   514  			Queues:          &api.Queues{},
   515  			RemoteCap:       remoteCap,
   516  			LocalCap:        localCap,
   517  			RouterId:        s.RemoteRouterId,
   518  			Flops:           s.Flops,
   519  		},
   520  		EbgpMultihop: &api.EbgpMultihop{
   521  			Enabled:     pconf.EbgpMultihop.Config.Enabled,
   522  			MultihopTtl: uint32(pconf.EbgpMultihop.Config.MultihopTtl),
   523  		},
   524  		TtlSecurity: &api.TtlSecurity{
   525  			Enabled: pconf.TtlSecurity.Config.Enabled,
   526  			TtlMin:  uint32(pconf.TtlSecurity.Config.TtlMin),
   527  		},
   528  		Timers: &api.Timers{
   529  			Config: &api.TimersConfig{
   530  				ConnectRetry:           uint64(timer.Config.ConnectRetry),
   531  				HoldTime:               uint64(timer.Config.HoldTime),
   532  				KeepaliveInterval:      uint64(timer.Config.KeepaliveInterval),
   533  				IdleHoldTimeAfterReset: uint64(timer.Config.IdleHoldTimeAfterReset),
   534  			},
   535  			State: &api.TimersState{
   536  				KeepaliveInterval:  uint64(timer.State.KeepaliveInterval),
   537  				NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
   538  				Uptime:             ProtoTimestamp(timer.State.Uptime),
   539  				Downtime:           ProtoTimestamp(timer.State.Downtime),
   540  			},
   541  		},
   542  		RouteReflector: &api.RouteReflector{
   543  			RouteReflectorClient:    pconf.RouteReflector.Config.RouteReflectorClient,
   544  			RouteReflectorClusterId: string(pconf.RouteReflector.State.RouteReflectorClusterId),
   545  		},
   546  		RouteServer: &api.RouteServer{
   547  			RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
   548  			SecondaryRoute:    pconf.RouteServer.Config.SecondaryRoute,
   549  		},
   550  		GracefulRestart: &api.GracefulRestart{
   551  			Enabled:             pconf.GracefulRestart.Config.Enabled,
   552  			RestartTime:         uint32(pconf.GracefulRestart.Config.RestartTime),
   553  			HelperOnly:          pconf.GracefulRestart.Config.HelperOnly,
   554  			DeferralTime:        uint32(pconf.GracefulRestart.Config.DeferralTime),
   555  			NotificationEnabled: pconf.GracefulRestart.Config.NotificationEnabled,
   556  			LonglivedEnabled:    pconf.GracefulRestart.Config.LongLivedEnabled,
   557  			LocalRestarting:     pconf.GracefulRestart.State.LocalRestarting,
   558  			PeerRestartTime:     uint32(pconf.GracefulRestart.State.PeerRestartTime),
   559  			PeerRestarting:      pconf.GracefulRestart.State.PeerRestarting,
   560  		},
   561  		Transport: &api.Transport{
   562  			RemotePort:    uint32(pconf.Transport.Config.RemotePort),
   563  			LocalPort:     uint32(pconf.Transport.Config.LocalPort),
   564  			LocalAddress:  localAddress,
   565  			PassiveMode:   pconf.Transport.Config.PassiveMode,
   566  			BindInterface: pconf.Transport.Config.BindInterface,
   567  			TcpMss:        uint32(pconf.Transport.Config.TcpMss),
   568  		},
   569  		AfiSafis: afiSafis,
   570  	}
   571  }
   572  
   573  func NewPeerGroupFromConfigStruct(pconf *PeerGroup) *api.PeerGroup {
   574  	afiSafis := make([]*api.AfiSafi, 0, len(pconf.AfiSafis))
   575  	for _, f := range pconf.AfiSafis {
   576  		if afiSafi := newAfiSafiFromConfigStruct(&f); afiSafi != nil {
   577  			afiSafi.AddPaths.Config.Receive = pconf.AddPaths.Config.Receive
   578  			afiSafi.AddPaths.Config.SendMax = uint32(pconf.AddPaths.Config.SendMax)
   579  			afiSafis = append(afiSafis, afiSafi)
   580  		}
   581  	}
   582  
   583  	timer := pconf.Timers
   584  	s := pconf.State
   585  	return &api.PeerGroup{
   586  		ApplyPolicy: newApplyPolicyFromConfigStruct(&pconf.ApplyPolicy),
   587  		Conf: &api.PeerGroupConf{
   588  			PeerAsn:             pconf.Config.PeerAs,
   589  			LocalAsn:            pconf.Config.LocalAs,
   590  			Type:                api.PeerType(pconf.Config.PeerType.ToInt()),
   591  			AuthPassword:        pconf.Config.AuthPassword,
   592  			RouteFlapDamping:    pconf.Config.RouteFlapDamping,
   593  			Description:         pconf.Config.Description,
   594  			PeerGroupName:       pconf.Config.PeerGroupName,
   595  			SendSoftwareVersion: pconf.Config.SendSoftwareVersion,
   596  		},
   597  		Info: &api.PeerGroupState{
   598  			PeerAsn:       s.PeerAs,
   599  			Type:          api.PeerType(s.PeerType.ToInt()),
   600  			TotalPaths:    s.TotalPaths,
   601  			TotalPrefixes: s.TotalPrefixes,
   602  		},
   603  		EbgpMultihop: &api.EbgpMultihop{
   604  			Enabled:     pconf.EbgpMultihop.Config.Enabled,
   605  			MultihopTtl: uint32(pconf.EbgpMultihop.Config.MultihopTtl),
   606  		},
   607  		TtlSecurity: &api.TtlSecurity{
   608  			Enabled: pconf.TtlSecurity.Config.Enabled,
   609  			TtlMin:  uint32(pconf.TtlSecurity.Config.TtlMin),
   610  		},
   611  		Timers: &api.Timers{
   612  			Config: &api.TimersConfig{
   613  				ConnectRetry:           uint64(timer.Config.ConnectRetry),
   614  				HoldTime:               uint64(timer.Config.HoldTime),
   615  				KeepaliveInterval:      uint64(timer.Config.KeepaliveInterval),
   616  				IdleHoldTimeAfterReset: uint64(timer.Config.IdleHoldTimeAfterReset),
   617  			},
   618  			State: &api.TimersState{
   619  				KeepaliveInterval:  uint64(timer.State.KeepaliveInterval),
   620  				NegotiatedHoldTime: uint64(timer.State.NegotiatedHoldTime),
   621  				Uptime:             ProtoTimestamp(timer.State.Uptime),
   622  				Downtime:           ProtoTimestamp(timer.State.Downtime),
   623  			},
   624  		},
   625  		RouteReflector: &api.RouteReflector{
   626  			RouteReflectorClient:    pconf.RouteReflector.Config.RouteReflectorClient,
   627  			RouteReflectorClusterId: string(pconf.RouteReflector.Config.RouteReflectorClusterId),
   628  		},
   629  		RouteServer: &api.RouteServer{
   630  			RouteServerClient: pconf.RouteServer.Config.RouteServerClient,
   631  			SecondaryRoute:    pconf.RouteServer.Config.SecondaryRoute,
   632  		},
   633  		GracefulRestart: &api.GracefulRestart{
   634  			Enabled:             pconf.GracefulRestart.Config.Enabled,
   635  			RestartTime:         uint32(pconf.GracefulRestart.Config.RestartTime),
   636  			HelperOnly:          pconf.GracefulRestart.Config.HelperOnly,
   637  			DeferralTime:        uint32(pconf.GracefulRestart.Config.DeferralTime),
   638  			NotificationEnabled: pconf.GracefulRestart.Config.NotificationEnabled,
   639  			LonglivedEnabled:    pconf.GracefulRestart.Config.LongLivedEnabled,
   640  			LocalRestarting:     pconf.GracefulRestart.State.LocalRestarting,
   641  		},
   642  		Transport: &api.Transport{
   643  			RemotePort:   uint32(pconf.Transport.Config.RemotePort),
   644  			LocalAddress: pconf.Transport.Config.LocalAddress,
   645  			PassiveMode:  pconf.Transport.Config.PassiveMode,
   646  			TcpMss:       uint32(pconf.Transport.Config.TcpMss),
   647  		},
   648  		AfiSafis: afiSafis,
   649  	}
   650  }
   651  
   652  func NewGlobalFromConfigStruct(c *Global) *api.Global {
   653  	families := make([]uint32, 0, len(c.AfiSafis))
   654  	for _, f := range c.AfiSafis {
   655  		families = append(families, uint32(AfiSafiTypeToIntMap[f.Config.AfiSafiName]))
   656  	}
   657  
   658  	applyPolicy := newApplyPolicyFromConfigStruct(&c.ApplyPolicy)
   659  
   660  	return &api.Global{
   661  		Asn:              c.Config.As,
   662  		RouterId:         c.Config.RouterId,
   663  		ListenPort:       c.Config.Port,
   664  		ListenAddresses:  c.Config.LocalAddressList,
   665  		Families:         families,
   666  		UseMultiplePaths: c.UseMultiplePaths.Config.Enabled,
   667  		RouteSelectionOptions: &api.RouteSelectionOptionsConfig{
   668  			AlwaysCompareMed:         c.RouteSelectionOptions.Config.AlwaysCompareMed,
   669  			IgnoreAsPathLength:       c.RouteSelectionOptions.Config.IgnoreAsPathLength,
   670  			ExternalCompareRouterId:  c.RouteSelectionOptions.Config.ExternalCompareRouterId,
   671  			AdvertiseInactiveRoutes:  c.RouteSelectionOptions.Config.AdvertiseInactiveRoutes,
   672  			EnableAigp:               c.RouteSelectionOptions.Config.EnableAigp,
   673  			IgnoreNextHopIgpMetric:   c.RouteSelectionOptions.Config.IgnoreNextHopIgpMetric,
   674  			DisableBestPathSelection: c.RouteSelectionOptions.Config.DisableBestPathSelection,
   675  		},
   676  		DefaultRouteDistance: &api.DefaultRouteDistance{
   677  			ExternalRouteDistance: uint32(c.DefaultRouteDistance.Config.ExternalRouteDistance),
   678  			InternalRouteDistance: uint32(c.DefaultRouteDistance.Config.InternalRouteDistance),
   679  		},
   680  		Confederation: &api.Confederation{
   681  			Enabled:      c.Confederation.Config.Enabled,
   682  			Identifier:   c.Confederation.Config.Identifier,
   683  			MemberAsList: c.Confederation.Config.MemberAsList,
   684  		},
   685  		GracefulRestart: &api.GracefulRestart{
   686  			Enabled:             c.GracefulRestart.Config.Enabled,
   687  			RestartTime:         uint32(c.GracefulRestart.Config.RestartTime),
   688  			StaleRoutesTime:     uint32(c.GracefulRestart.Config.StaleRoutesTime),
   689  			HelperOnly:          c.GracefulRestart.Config.HelperOnly,
   690  			DeferralTime:        uint32(c.GracefulRestart.Config.DeferralTime),
   691  			NotificationEnabled: c.GracefulRestart.Config.NotificationEnabled,
   692  			LonglivedEnabled:    c.GracefulRestart.Config.LongLivedEnabled,
   693  		},
   694  		ApplyPolicy: applyPolicy,
   695  	}
   696  }
   697  
   698  func newAPIPrefixFromConfigStruct(c Prefix) (*api.Prefix, error) {
   699  	min, max, err := ParseMaskLength(c.IpPrefix, c.MasklengthRange)
   700  	if err != nil {
   701  		return nil, err
   702  	}
   703  	return &api.Prefix{
   704  		IpPrefix:      c.IpPrefix,
   705  		MaskLengthMin: uint32(min),
   706  		MaskLengthMax: uint32(max),
   707  	}, nil
   708  }
   709  
   710  func NewAPIDefinedSetsFromConfigStruct(t *DefinedSets) ([]*api.DefinedSet, error) {
   711  	definedSets := make([]*api.DefinedSet, 0)
   712  
   713  	for _, ps := range t.PrefixSets {
   714  		prefixes := make([]*api.Prefix, 0)
   715  		for _, p := range ps.PrefixList {
   716  			ap, err := newAPIPrefixFromConfigStruct(p)
   717  			if err != nil {
   718  				return nil, err
   719  			}
   720  			prefixes = append(prefixes, ap)
   721  		}
   722  		definedSets = append(definedSets, &api.DefinedSet{
   723  			DefinedType: api.DefinedType_PREFIX,
   724  			Name:        ps.PrefixSetName,
   725  			Prefixes:    prefixes,
   726  		})
   727  	}
   728  
   729  	for _, ns := range t.NeighborSets {
   730  		definedSets = append(definedSets, &api.DefinedSet{
   731  			DefinedType: api.DefinedType_NEIGHBOR,
   732  			Name:        ns.NeighborSetName,
   733  			List:        ns.NeighborInfoList,
   734  		})
   735  	}
   736  
   737  	bs := t.BgpDefinedSets
   738  	for _, cs := range bs.CommunitySets {
   739  		definedSets = append(definedSets, &api.DefinedSet{
   740  			DefinedType: api.DefinedType_COMMUNITY,
   741  			Name:        cs.CommunitySetName,
   742  			List:        cs.CommunityList,
   743  		})
   744  	}
   745  
   746  	for _, es := range bs.ExtCommunitySets {
   747  		definedSets = append(definedSets, &api.DefinedSet{
   748  			DefinedType: api.DefinedType_EXT_COMMUNITY,
   749  			Name:        es.ExtCommunitySetName,
   750  			List:        es.ExtCommunityList,
   751  		})
   752  	}
   753  
   754  	for _, ls := range bs.LargeCommunitySets {
   755  		definedSets = append(definedSets, &api.DefinedSet{
   756  			DefinedType: api.DefinedType_LARGE_COMMUNITY,
   757  			Name:        ls.LargeCommunitySetName,
   758  			List:        ls.LargeCommunityList,
   759  		})
   760  	}
   761  
   762  	for _, as := range bs.AsPathSets {
   763  		definedSets = append(definedSets, &api.DefinedSet{
   764  			DefinedType: api.DefinedType_AS_PATH,
   765  			Name:        as.AsPathSetName,
   766  			List:        as.AsPathList,
   767  		})
   768  	}
   769  
   770  	return definedSets, nil
   771  }