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

     1  // Copyright (C) 2014 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 table
    17  
    18  import (
    19  	"bytes"
    20  	"encoding/json"
    21  	"fmt"
    22  	"math"
    23  	"net"
    24  	"sort"
    25  	"time"
    26  
    27  	"github.com/osrg/gobgp/internal/pkg/config"
    28  	"github.com/osrg/gobgp/pkg/packet/bgp"
    29  
    30  	log "github.com/sirupsen/logrus"
    31  )
    32  
    33  const (
    34  	DEFAULT_LOCAL_PREF = 100
    35  )
    36  
    37  type Bitmap struct {
    38  	bitmap []uint64
    39  }
    40  
    41  func (b *Bitmap) Flag(i uint) {
    42  	b.bitmap[i/64] |= 1 << uint(i%64)
    43  }
    44  
    45  func (b *Bitmap) Unflag(i uint) {
    46  	b.bitmap[i/64] &^= 1 << uint(i%64)
    47  }
    48  
    49  func (b *Bitmap) GetFlag(i uint) bool {
    50  	return b.bitmap[i/64]&(1<<uint(i%64)) > 0
    51  }
    52  
    53  func (b *Bitmap) FindandSetZeroBit() (uint, error) {
    54  	for i := 0; i < len(b.bitmap); i++ {
    55  		if b.bitmap[i] == math.MaxUint64 {
    56  			continue
    57  		}
    58  		// replace this with TrailingZero64() when gobgp drops go 1.8 support.
    59  		for j := 0; j < 64; j++ {
    60  			v := ^b.bitmap[i]
    61  			if v&(1<<uint64(j)) > 0 {
    62  				r := i*64 + j
    63  				b.Flag(uint(r))
    64  				return uint(r), nil
    65  			}
    66  		}
    67  	}
    68  	return 0, fmt.Errorf("no space")
    69  }
    70  
    71  func (b *Bitmap) Expand() {
    72  	old := b.bitmap
    73  	new := make([]uint64, len(old)+1)
    74  	for i := 0; i < len(old); i++ {
    75  		new[i] = old[i]
    76  	}
    77  	b.bitmap = new
    78  }
    79  
    80  func NewBitmap(size int) *Bitmap {
    81  	b := &Bitmap{}
    82  	if size != 0 {
    83  		b.bitmap = make([]uint64, (size+64-1)/64)
    84  	}
    85  	return b
    86  }
    87  
    88  type originInfo struct {
    89  	nlri               bgp.AddrPrefixInterface
    90  	source             *PeerInfo
    91  	timestamp          int64
    92  	validation         *Validation
    93  	noImplicitWithdraw bool
    94  	isFromExternal     bool
    95  	eor                bool
    96  	stale              bool
    97  }
    98  
    99  type RpkiValidationReasonType string
   100  
   101  const (
   102  	RPKI_VALIDATION_REASON_TYPE_NONE   RpkiValidationReasonType = "none"
   103  	RPKI_VALIDATION_REASON_TYPE_AS     RpkiValidationReasonType = "as"
   104  	RPKI_VALIDATION_REASON_TYPE_LENGTH RpkiValidationReasonType = "length"
   105  )
   106  
   107  var RpkiValidationReasonTypeToIntMap = map[RpkiValidationReasonType]int{
   108  	RPKI_VALIDATION_REASON_TYPE_NONE:   0,
   109  	RPKI_VALIDATION_REASON_TYPE_AS:     1,
   110  	RPKI_VALIDATION_REASON_TYPE_LENGTH: 2,
   111  }
   112  
   113  func (v RpkiValidationReasonType) ToInt() int {
   114  	i, ok := RpkiValidationReasonTypeToIntMap[v]
   115  	if !ok {
   116  		return -1
   117  	}
   118  	return i
   119  }
   120  
   121  var IntToRpkiValidationReasonTypeMap = map[int]RpkiValidationReasonType{
   122  	0: RPKI_VALIDATION_REASON_TYPE_NONE,
   123  	1: RPKI_VALIDATION_REASON_TYPE_AS,
   124  	2: RPKI_VALIDATION_REASON_TYPE_LENGTH,
   125  }
   126  
   127  type Validation struct {
   128  	Status          config.RpkiValidationResultType
   129  	Reason          RpkiValidationReasonType
   130  	Matched         []*ROA
   131  	UnmatchedAs     []*ROA
   132  	UnmatchedLength []*ROA
   133  }
   134  
   135  type Path struct {
   136  	info      *originInfo
   137  	parent    *Path
   138  	pathAttrs []bgp.PathAttributeInterface
   139  	dels      []bgp.BGPAttrType
   140  	attrsHash uint32
   141  	aslooped  bool
   142  	reason    BestPathReason
   143  
   144  	// For BGP Nexthop Tracking, this field shows if nexthop is invalidated by IGP.
   145  	IsNexthopInvalid bool
   146  	IsWithdraw       bool
   147  }
   148  
   149  var localSource = &PeerInfo{}
   150  
   151  func NewPath(source *PeerInfo, nlri bgp.AddrPrefixInterface, isWithdraw bool, pattrs []bgp.PathAttributeInterface, timestamp time.Time, noImplicitWithdraw bool) *Path {
   152  	if source == nil {
   153  		source = localSource
   154  	}
   155  	if !isWithdraw && pattrs == nil {
   156  		log.WithFields(log.Fields{
   157  			"Topic": "Table",
   158  			"Key":   nlri.String(),
   159  		}).Error("Need to provide path attributes for non-withdrawn path.")
   160  		return nil
   161  	}
   162  
   163  	return &Path{
   164  		info: &originInfo{
   165  			nlri:               nlri,
   166  			source:             source,
   167  			timestamp:          timestamp.Unix(),
   168  			noImplicitWithdraw: noImplicitWithdraw,
   169  		},
   170  		IsWithdraw: isWithdraw,
   171  		pathAttrs:  pattrs,
   172  	}
   173  }
   174  
   175  func NewEOR(family bgp.RouteFamily) *Path {
   176  	afi, safi := bgp.RouteFamilyToAfiSafi(family)
   177  	nlri, _ := bgp.NewPrefixFromRouteFamily(afi, safi)
   178  	return &Path{
   179  		info: &originInfo{
   180  			nlri: nlri,
   181  			eor:  true,
   182  		},
   183  	}
   184  }
   185  
   186  func (path *Path) IsEOR() bool {
   187  	if path.info != nil && path.info.eor {
   188  		return true
   189  	}
   190  	return false
   191  }
   192  
   193  func cloneAsPath(asAttr *bgp.PathAttributeAsPath) *bgp.PathAttributeAsPath {
   194  	newASparams := make([]bgp.AsPathParamInterface, len(asAttr.Value))
   195  	for i, param := range asAttr.Value {
   196  		asList := param.GetAS()
   197  		as := make([]uint32, len(asList))
   198  		copy(as, asList)
   199  		newASparams[i] = bgp.NewAs4PathParam(param.GetType(), as)
   200  	}
   201  	return bgp.NewPathAttributeAsPath(newASparams)
   202  }
   203  
   204  func UpdatePathAttrs(global *config.Global, peer *config.Neighbor, info *PeerInfo, original *Path) *Path {
   205  	if peer.RouteServer.Config.RouteServerClient {
   206  		return original
   207  	}
   208  	path := original.Clone(original.IsWithdraw)
   209  
   210  	for _, a := range path.GetPathAttrs() {
   211  		if _, y := bgp.PathAttrFlags[a.GetType()]; !y {
   212  			if a.GetFlags()&bgp.BGP_ATTR_FLAG_TRANSITIVE == 0 {
   213  				path.delPathAttr(a.GetType())
   214  			}
   215  		} else {
   216  			switch a.GetType() {
   217  			case bgp.BGP_ATTR_TYPE_CLUSTER_LIST, bgp.BGP_ATTR_TYPE_ORIGINATOR_ID:
   218  				if !(peer.State.PeerType == config.PEER_TYPE_INTERNAL && peer.RouteReflector.Config.RouteReflectorClient) {
   219  					// send these attributes to only rr clients
   220  					path.delPathAttr(a.GetType())
   221  				}
   222  			}
   223  		}
   224  	}
   225  
   226  	localAddress := info.LocalAddress
   227  	nexthop := path.GetNexthop()
   228  	if peer.State.PeerType == config.PEER_TYPE_EXTERNAL {
   229  		// NEXTHOP handling
   230  		if !path.IsLocal() || nexthop.IsUnspecified() {
   231  			path.SetNexthop(localAddress)
   232  		}
   233  
   234  		// remove-private-as handling
   235  		path.RemovePrivateAS(peer.Config.LocalAs, peer.State.RemovePrivateAs)
   236  
   237  		// AS_PATH handling
   238  		confed := peer.IsConfederationMember(global)
   239  		path.PrependAsn(peer.Config.LocalAs, 1, confed)
   240  		if !confed {
   241  			path.removeConfedAs()
   242  		}
   243  
   244  		// MED Handling
   245  		if med := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC); med != nil && !path.IsLocal() {
   246  			path.delPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
   247  		}
   248  
   249  	} else if peer.State.PeerType == config.PEER_TYPE_INTERNAL {
   250  		// NEXTHOP handling for iBGP
   251  		// if the path generated locally set local address as nexthop.
   252  		// if not, don't modify it.
   253  		// TODO: NEXT-HOP-SELF support
   254  		if path.IsLocal() && nexthop.IsUnspecified() {
   255  			path.SetNexthop(localAddress)
   256  		}
   257  
   258  		// AS_PATH handling for iBGP
   259  		// if the path has AS_PATH path attribute, don't modify it.
   260  		// if not, attach *empty* AS_PATH path attribute.
   261  		if nh := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH); nh == nil {
   262  			path.PrependAsn(0, 0, false)
   263  		}
   264  
   265  		// For iBGP peers we are required to send local-pref attribute
   266  		// for connected or local prefixes.
   267  		// We set default local-pref 100.
   268  		if pref := path.getPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF); pref == nil {
   269  			path.setPathAttr(bgp.NewPathAttributeLocalPref(DEFAULT_LOCAL_PREF))
   270  		}
   271  
   272  		// RFC4456: BGP Route Reflection
   273  		// 8. Avoiding Routing Information Loops
   274  		info := path.GetSource()
   275  		if peer.RouteReflector.Config.RouteReflectorClient {
   276  			// This attribute will carry the BGP Identifier of the originator of the route in the local AS.
   277  			// A BGP speaker SHOULD NOT create an ORIGINATOR_ID attribute if one already exists.
   278  			//
   279  			// RFC4684 3.2 Intra-AS VPN Route Distribution
   280  			// When advertising RT membership NLRI to a route-reflector client,
   281  			// the Originator attribute shall be set to the router-id of the
   282  			// advertiser, and the Next-hop attribute shall be set of the local
   283  			// address for that session.
   284  			if path.GetRouteFamily() == bgp.RF_RTC_UC {
   285  				path.SetNexthop(localAddress)
   286  				path.setPathAttr(bgp.NewPathAttributeOriginatorId(info.LocalID.String()))
   287  			} else if path.getPathAttr(bgp.BGP_ATTR_TYPE_ORIGINATOR_ID) == nil {
   288  				if path.IsLocal() {
   289  					path.setPathAttr(bgp.NewPathAttributeOriginatorId(global.Config.RouterId))
   290  				} else {
   291  					path.setPathAttr(bgp.NewPathAttributeOriginatorId(info.ID.String()))
   292  				}
   293  			}
   294  			// When an RR reflects a route, it MUST prepend the local CLUSTER_ID to the CLUSTER_LIST.
   295  			// If the CLUSTER_LIST is empty, it MUST create a new one.
   296  			clusterID := string(peer.RouteReflector.State.RouteReflectorClusterId)
   297  			if p := path.getPathAttr(bgp.BGP_ATTR_TYPE_CLUSTER_LIST); p == nil {
   298  				path.setPathAttr(bgp.NewPathAttributeClusterList([]string{clusterID}))
   299  			} else {
   300  				clusterList := p.(*bgp.PathAttributeClusterList)
   301  				newClusterList := make([]string, 0, len(clusterList.Value))
   302  				for _, ip := range clusterList.Value {
   303  					newClusterList = append(newClusterList, ip.String())
   304  				}
   305  				path.setPathAttr(bgp.NewPathAttributeClusterList(append([]string{clusterID}, newClusterList...)))
   306  			}
   307  		}
   308  
   309  	} else {
   310  		log.WithFields(log.Fields{
   311  			"Topic": "Peer",
   312  			"Key":   peer.State.NeighborAddress,
   313  		}).Warnf("invalid peer type: %v", peer.State.PeerType)
   314  	}
   315  	return path
   316  }
   317  
   318  func (path *Path) GetTimestamp() time.Time {
   319  	return time.Unix(path.OriginInfo().timestamp, 0)
   320  }
   321  
   322  func (path *Path) setTimestamp(t time.Time) {
   323  	path.OriginInfo().timestamp = t.Unix()
   324  }
   325  
   326  func (path *Path) IsLocal() bool {
   327  	return path.GetSource().Address == nil
   328  }
   329  
   330  func (path *Path) IsIBGP() bool {
   331  	as := path.GetSource().AS
   332  	return (as == path.GetSource().LocalAS) && as != 0
   333  }
   334  
   335  // create new PathAttributes
   336  func (path *Path) Clone(isWithdraw bool) *Path {
   337  	return &Path{
   338  		parent:           path,
   339  		IsWithdraw:       isWithdraw,
   340  		IsNexthopInvalid: path.IsNexthopInvalid,
   341  		attrsHash:        path.attrsHash,
   342  	}
   343  }
   344  
   345  func (path *Path) root() *Path {
   346  	p := path
   347  	for p.parent != nil {
   348  		p = p.parent
   349  	}
   350  	return p
   351  }
   352  
   353  func (path *Path) OriginInfo() *originInfo {
   354  	return path.root().info
   355  }
   356  
   357  func (path *Path) NoImplicitWithdraw() bool {
   358  	return path.OriginInfo().noImplicitWithdraw
   359  }
   360  
   361  func (path *Path) Validation() *Validation {
   362  	return path.OriginInfo().validation
   363  }
   364  
   365  func (path *Path) ValidationStatus() config.RpkiValidationResultType {
   366  	if v := path.OriginInfo().validation; v != nil {
   367  		return v.Status
   368  	} else {
   369  		return config.RPKI_VALIDATION_RESULT_TYPE_NONE
   370  	}
   371  }
   372  
   373  func (path *Path) SetValidation(v *Validation) {
   374  	path.OriginInfo().validation = v
   375  }
   376  
   377  func (path *Path) IsFromExternal() bool {
   378  	return path.OriginInfo().isFromExternal
   379  }
   380  
   381  func (path *Path) SetIsFromExternal(y bool) {
   382  	path.OriginInfo().isFromExternal = y
   383  }
   384  
   385  func (path *Path) GetRouteFamily() bgp.RouteFamily {
   386  	return bgp.AfiSafiToRouteFamily(path.OriginInfo().nlri.AFI(), path.OriginInfo().nlri.SAFI())
   387  }
   388  
   389  func (path *Path) GetSource() *PeerInfo {
   390  	return path.OriginInfo().source
   391  }
   392  
   393  func (path *Path) MarkStale(s bool) {
   394  	path.OriginInfo().stale = s
   395  }
   396  
   397  func (path *Path) IsStale() bool {
   398  	return path.OriginInfo().stale
   399  }
   400  
   401  func (path *Path) IsAsLooped() bool {
   402  	return path.aslooped
   403  }
   404  
   405  func (path *Path) SetAsLooped(y bool) {
   406  	path.aslooped = y
   407  }
   408  
   409  func (path *Path) IsLLGRStale() bool {
   410  	for _, c := range path.GetCommunities() {
   411  		if c == uint32(bgp.COMMUNITY_LLGR_STALE) {
   412  			return true
   413  		}
   414  	}
   415  	return false
   416  }
   417  
   418  func (path *Path) GetSourceAs() uint32 {
   419  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH)
   420  	if attr != nil {
   421  		asPathParam := attr.(*bgp.PathAttributeAsPath).Value
   422  		if len(asPathParam) == 0 {
   423  			return 0
   424  		}
   425  		asList := asPathParam[len(asPathParam)-1].GetAS()
   426  		if len(asList) == 0 {
   427  			return 0
   428  		}
   429  		return asList[len(asList)-1]
   430  	}
   431  	return 0
   432  }
   433  
   434  func (path *Path) GetNexthop() net.IP {
   435  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
   436  	if attr != nil {
   437  		return attr.(*bgp.PathAttributeNextHop).Value
   438  	}
   439  	attr = path.getPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI)
   440  	if attr != nil {
   441  		return attr.(*bgp.PathAttributeMpReachNLRI).Nexthop
   442  	}
   443  	return net.IP{}
   444  }
   445  
   446  func (path *Path) SetNexthop(nexthop net.IP) {
   447  	if path.GetRouteFamily() == bgp.RF_IPv4_UC && nexthop.To4() == nil {
   448  		path.delPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
   449  		mpreach := bgp.NewPathAttributeMpReachNLRI(nexthop.String(), []bgp.AddrPrefixInterface{path.GetNlri()})
   450  		path.setPathAttr(mpreach)
   451  		return
   452  	}
   453  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
   454  	if attr != nil {
   455  		path.setPathAttr(bgp.NewPathAttributeNextHop(nexthop.String()))
   456  	}
   457  	attr = path.getPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI)
   458  	if attr != nil {
   459  		oldNlri := attr.(*bgp.PathAttributeMpReachNLRI)
   460  		path.setPathAttr(bgp.NewPathAttributeMpReachNLRI(nexthop.String(), oldNlri.Value))
   461  	}
   462  }
   463  
   464  func (path *Path) GetNlri() bgp.AddrPrefixInterface {
   465  	return path.OriginInfo().nlri
   466  }
   467  
   468  type PathAttrs []bgp.PathAttributeInterface
   469  
   470  func (a PathAttrs) Len() int {
   471  	return len(a)
   472  }
   473  
   474  func (a PathAttrs) Swap(i, j int) {
   475  	a[i], a[j] = a[j], a[i]
   476  }
   477  
   478  func (a PathAttrs) Less(i, j int) bool {
   479  	return a[i].GetType() < a[j].GetType()
   480  }
   481  
   482  func (path *Path) GetPathAttrs() []bgp.PathAttributeInterface {
   483  	deleted := NewBitmap(math.MaxUint8)
   484  	modified := make(map[uint]bgp.PathAttributeInterface)
   485  	p := path
   486  	for {
   487  		for _, t := range p.dels {
   488  			deleted.Flag(uint(t))
   489  		}
   490  		if p.parent == nil {
   491  			list := PathAttrs(make([]bgp.PathAttributeInterface, 0, len(p.pathAttrs)))
   492  			// we assume that the original pathAttrs are
   493  			// in order, that is, other bgp speakers send
   494  			// attributes in order.
   495  			for _, a := range p.pathAttrs {
   496  				typ := uint(a.GetType())
   497  				if m, ok := modified[typ]; ok {
   498  					list = append(list, m)
   499  					delete(modified, typ)
   500  				} else if !deleted.GetFlag(typ) {
   501  					list = append(list, a)
   502  				}
   503  			}
   504  			if len(modified) > 0 {
   505  				// Huh, some attributes were newly
   506  				// added. So we need to sort...
   507  				for _, m := range modified {
   508  					list = append(list, m)
   509  				}
   510  				sort.Sort(list)
   511  			}
   512  			return list
   513  		} else {
   514  			for _, a := range p.pathAttrs {
   515  				typ := uint(a.GetType())
   516  				if _, ok := modified[typ]; !deleted.GetFlag(typ) && !ok {
   517  					modified[typ] = a
   518  				}
   519  			}
   520  		}
   521  		p = p.parent
   522  	}
   523  }
   524  
   525  func (path *Path) getPathAttr(typ bgp.BGPAttrType) bgp.PathAttributeInterface {
   526  	p := path
   527  	for {
   528  		for _, t := range p.dels {
   529  			if t == typ {
   530  				return nil
   531  			}
   532  		}
   533  		for _, a := range p.pathAttrs {
   534  			if a.GetType() == typ {
   535  				return a
   536  			}
   537  		}
   538  		if p.parent == nil {
   539  			return nil
   540  		}
   541  		p = p.parent
   542  	}
   543  }
   544  
   545  func (path *Path) setPathAttr(a bgp.PathAttributeInterface) {
   546  	if len(path.pathAttrs) == 0 {
   547  		path.pathAttrs = []bgp.PathAttributeInterface{a}
   548  	} else {
   549  		for i, b := range path.pathAttrs {
   550  			if a.GetType() == b.GetType() {
   551  				path.pathAttrs[i] = a
   552  				return
   553  			}
   554  		}
   555  		path.pathAttrs = append(path.pathAttrs, a)
   556  	}
   557  }
   558  
   559  func (path *Path) delPathAttr(typ bgp.BGPAttrType) {
   560  	if len(path.dels) == 0 {
   561  		path.dels = []bgp.BGPAttrType{typ}
   562  	} else {
   563  		path.dels = append(path.dels, typ)
   564  	}
   565  }
   566  
   567  // return Path's string representation
   568  func (path *Path) String() string {
   569  	s := bytes.NewBuffer(make([]byte, 0, 64))
   570  	if path.IsEOR() {
   571  		s.WriteString(fmt.Sprintf("{ %s EOR | src: %s }", path.GetRouteFamily(), path.GetSource()))
   572  		return s.String()
   573  	}
   574  	s.WriteString(fmt.Sprintf("{ %s | ", path.getPrefix()))
   575  	s.WriteString(fmt.Sprintf("src: %s", path.GetSource()))
   576  	s.WriteString(fmt.Sprintf(", nh: %s", path.GetNexthop()))
   577  	if path.IsNexthopInvalid {
   578  		s.WriteString(" (not reachable)")
   579  	}
   580  	if path.IsWithdraw {
   581  		s.WriteString(", withdraw")
   582  	}
   583  	s.WriteString(" }")
   584  	return s.String()
   585  }
   586  
   587  func (path *Path) getPrefix() string {
   588  	return path.GetNlri().String()
   589  }
   590  
   591  func (path *Path) GetAsPath() *bgp.PathAttributeAsPath {
   592  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH)
   593  	if attr != nil {
   594  		return attr.(*bgp.PathAttributeAsPath)
   595  	}
   596  	return nil
   597  }
   598  
   599  // GetAsPathLen returns the number of AS_PATH
   600  func (path *Path) GetAsPathLen() int {
   601  
   602  	var length int = 0
   603  	if aspath := path.GetAsPath(); aspath != nil {
   604  		for _, as := range aspath.Value {
   605  			length += as.ASLen()
   606  		}
   607  	}
   608  	return length
   609  }
   610  
   611  func (path *Path) GetAsString() string {
   612  	s := bytes.NewBuffer(make([]byte, 0, 64))
   613  	if aspath := path.GetAsPath(); aspath != nil {
   614  		return bgp.AsPathString(aspath)
   615  	}
   616  	return s.String()
   617  }
   618  
   619  func (path *Path) GetAsList() []uint32 {
   620  	return path.getAsListOfSpecificType(true, true)
   621  
   622  }
   623  
   624  func (path *Path) GetAsSeqList() []uint32 {
   625  	return path.getAsListOfSpecificType(true, false)
   626  
   627  }
   628  
   629  func (path *Path) getAsListOfSpecificType(getAsSeq, getAsSet bool) []uint32 {
   630  	asList := []uint32{}
   631  	if aspath := path.GetAsPath(); aspath != nil {
   632  		for _, param := range aspath.Value {
   633  			segType := param.GetType()
   634  			if getAsSeq && segType == bgp.BGP_ASPATH_ATTR_TYPE_SEQ {
   635  				asList = append(asList, param.GetAS()...)
   636  				continue
   637  			}
   638  			if getAsSet && segType == bgp.BGP_ASPATH_ATTR_TYPE_SET {
   639  				asList = append(asList, param.GetAS()...)
   640  			} else {
   641  				asList = append(asList, 0)
   642  			}
   643  		}
   644  	}
   645  	return asList
   646  }
   647  
   648  func (path *Path) GetLabelString() string {
   649  	return bgp.LabelString(path.GetNlri())
   650  }
   651  
   652  // PrependAsn prepends AS number.
   653  // This function updates the AS_PATH attribute as follows.
   654  // (If the peer is in the confederation member AS,
   655  //  replace AS_SEQUENCE in the following sentence with AS_CONFED_SEQUENCE.)
   656  //  1) if the first path segment of the AS_PATH is of type
   657  //     AS_SEQUENCE, the local system prepends the specified AS num as
   658  //     the last element of the sequence (put it in the left-most
   659  //     position with respect to the position of  octets in the
   660  //     protocol message) the specified number of times.
   661  //     If the act of prepending will cause an overflow in the AS_PATH
   662  //     segment (i.e.,  more than 255 ASes),
   663  //     it SHOULD prepend a new segment of type AS_SEQUENCE
   664  //     and prepend its own AS number to this new segment.
   665  //
   666  //  2) if the first path segment of the AS_PATH is of other than type
   667  //     AS_SEQUENCE, the local system prepends a new path segment of type
   668  //     AS_SEQUENCE to the AS_PATH, including the specified AS number in
   669  //     that segment.
   670  //
   671  //  3) if the AS_PATH is empty, the local system creates a path
   672  //     segment of type AS_SEQUENCE, places the specified AS number
   673  //     into that segment, and places that segment into the AS_PATH.
   674  func (path *Path) PrependAsn(asn uint32, repeat uint8, confed bool) {
   675  	var segType uint8
   676  	if confed {
   677  		segType = bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ
   678  	} else {
   679  		segType = bgp.BGP_ASPATH_ATTR_TYPE_SEQ
   680  	}
   681  
   682  	original := path.GetAsPath()
   683  
   684  	asns := make([]uint32, repeat)
   685  	for i := range asns {
   686  		asns[i] = asn
   687  	}
   688  
   689  	var asPath *bgp.PathAttributeAsPath
   690  	if original == nil {
   691  		asPath = bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{})
   692  	} else {
   693  		asPath = cloneAsPath(original)
   694  	}
   695  
   696  	if len(asPath.Value) > 0 {
   697  		param := asPath.Value[0]
   698  		asList := param.GetAS()
   699  		if param.GetType() == segType {
   700  			if int(repeat)+len(asList) > 255 {
   701  				repeat = uint8(255 - len(asList))
   702  			}
   703  			newAsList := append(asns[:int(repeat)], asList...)
   704  			asPath.Value[0] = bgp.NewAs4PathParam(segType, newAsList)
   705  			asns = asns[int(repeat):]
   706  		}
   707  	}
   708  
   709  	if len(asns) > 0 {
   710  		p := bgp.NewAs4PathParam(segType, asns)
   711  		asPath.Value = append([]bgp.AsPathParamInterface{p}, asPath.Value...)
   712  	}
   713  	path.setPathAttr(asPath)
   714  }
   715  
   716  func isPrivateAS(as uint32) bool {
   717  	return (64512 <= as && as <= 65534) || (4200000000 <= as && as <= 4294967294)
   718  }
   719  
   720  func (path *Path) RemovePrivateAS(localAS uint32, option config.RemovePrivateAsOption) {
   721  	original := path.GetAsPath()
   722  	if original == nil {
   723  		return
   724  	}
   725  	switch option {
   726  	case config.REMOVE_PRIVATE_AS_OPTION_ALL, config.REMOVE_PRIVATE_AS_OPTION_REPLACE:
   727  		newASParams := make([]bgp.AsPathParamInterface, 0, len(original.Value))
   728  		for _, param := range original.Value {
   729  			asList := param.GetAS()
   730  			newASParam := make([]uint32, 0, len(asList))
   731  			for _, as := range asList {
   732  				if isPrivateAS(as) {
   733  					if option == config.REMOVE_PRIVATE_AS_OPTION_REPLACE {
   734  						newASParam = append(newASParam, localAS)
   735  					}
   736  				} else {
   737  					newASParam = append(newASParam, as)
   738  				}
   739  			}
   740  			if len(newASParam) > 0 {
   741  				newASParams = append(newASParams, bgp.NewAs4PathParam(param.GetType(), newASParam))
   742  			}
   743  		}
   744  		path.setPathAttr(bgp.NewPathAttributeAsPath(newASParams))
   745  	}
   746  }
   747  
   748  func (path *Path) removeConfedAs() {
   749  	original := path.GetAsPath()
   750  	if original == nil {
   751  		return
   752  	}
   753  	newAsParams := make([]bgp.AsPathParamInterface, 0, len(original.Value))
   754  	for _, param := range original.Value {
   755  		switch param.GetType() {
   756  		case bgp.BGP_ASPATH_ATTR_TYPE_SEQ, bgp.BGP_ASPATH_ATTR_TYPE_SET:
   757  			newAsParams = append(newAsParams, param)
   758  		}
   759  	}
   760  	path.setPathAttr(bgp.NewPathAttributeAsPath(newAsParams))
   761  }
   762  
   763  func (path *Path) ReplaceAS(localAS, peerAS uint32) *Path {
   764  	original := path.GetAsPath()
   765  	if original == nil {
   766  		return path
   767  	}
   768  	newASParams := make([]bgp.AsPathParamInterface, 0, len(original.Value))
   769  	changed := false
   770  	for _, param := range original.Value {
   771  		segType := param.GetType()
   772  		asList := param.GetAS()
   773  		newASParam := make([]uint32, 0, len(asList))
   774  		for _, as := range asList {
   775  			if as == peerAS {
   776  				as = localAS
   777  				changed = true
   778  			}
   779  			newASParam = append(newASParam, as)
   780  		}
   781  		newASParams = append(newASParams, bgp.NewAs4PathParam(segType, newASParam))
   782  	}
   783  	if changed {
   784  		path = path.Clone(path.IsWithdraw)
   785  		path.setPathAttr(bgp.NewPathAttributeAsPath(newASParams))
   786  	}
   787  	return path
   788  }
   789  
   790  func (path *Path) GetCommunities() []uint32 {
   791  	communityList := []uint32{}
   792  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES); attr != nil {
   793  		communities := attr.(*bgp.PathAttributeCommunities)
   794  		communityList = append(communityList, communities.Value...)
   795  	}
   796  	return communityList
   797  }
   798  
   799  // SetCommunities adds or replaces communities with new ones.
   800  // If the length of communities is 0 and doReplace is true, it clears communities.
   801  func (path *Path) SetCommunities(communities []uint32, doReplace bool) {
   802  
   803  	if len(communities) == 0 && doReplace {
   804  		// clear communities
   805  		path.delPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
   806  		return
   807  	}
   808  
   809  	newList := make([]uint32, 0)
   810  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
   811  	if attr != nil {
   812  		c := attr.(*bgp.PathAttributeCommunities)
   813  		if doReplace {
   814  			newList = append(newList, communities...)
   815  		} else {
   816  			newList = append(newList, c.Value...)
   817  			newList = append(newList, communities...)
   818  		}
   819  	} else {
   820  		newList = append(newList, communities...)
   821  	}
   822  	path.setPathAttr(bgp.NewPathAttributeCommunities(newList))
   823  
   824  }
   825  
   826  // RemoveCommunities removes specific communities.
   827  // If the length of communities is 0, it does nothing.
   828  // If all communities are removed, it removes Communities path attribute itself.
   829  func (path *Path) RemoveCommunities(communities []uint32) int {
   830  
   831  	if len(communities) == 0 {
   832  		// do nothing
   833  		return 0
   834  	}
   835  
   836  	find := func(val uint32) bool {
   837  		for _, com := range communities {
   838  			if com == val {
   839  				return true
   840  			}
   841  		}
   842  		return false
   843  	}
   844  
   845  	count := 0
   846  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
   847  	if attr != nil {
   848  		newList := make([]uint32, 0)
   849  		c := attr.(*bgp.PathAttributeCommunities)
   850  
   851  		for _, value := range c.Value {
   852  			if find(value) {
   853  				count += 1
   854  			} else {
   855  				newList = append(newList, value)
   856  			}
   857  		}
   858  
   859  		if len(newList) != 0 {
   860  			path.setPathAttr(bgp.NewPathAttributeCommunities(newList))
   861  		} else {
   862  			path.delPathAttr(bgp.BGP_ATTR_TYPE_COMMUNITIES)
   863  		}
   864  	}
   865  	return count
   866  }
   867  
   868  func (path *Path) GetExtCommunities() []bgp.ExtendedCommunityInterface {
   869  	eCommunityList := make([]bgp.ExtendedCommunityInterface, 0)
   870  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES); attr != nil {
   871  		eCommunities := attr.(*bgp.PathAttributeExtendedCommunities).Value
   872  		eCommunityList = append(eCommunityList, eCommunities...)
   873  	}
   874  	return eCommunityList
   875  }
   876  
   877  func (path *Path) SetExtCommunities(exts []bgp.ExtendedCommunityInterface, doReplace bool) {
   878  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES)
   879  	if attr != nil {
   880  		l := attr.(*bgp.PathAttributeExtendedCommunities).Value
   881  		if doReplace {
   882  			l = exts
   883  		} else {
   884  			l = append(l, exts...)
   885  		}
   886  		path.setPathAttr(bgp.NewPathAttributeExtendedCommunities(l))
   887  	} else {
   888  		path.setPathAttr(bgp.NewPathAttributeExtendedCommunities(exts))
   889  	}
   890  }
   891  
   892  func (path *Path) GetLargeCommunities() []*bgp.LargeCommunity {
   893  	if a := path.getPathAttr(bgp.BGP_ATTR_TYPE_LARGE_COMMUNITY); a != nil {
   894  		v := a.(*bgp.PathAttributeLargeCommunities).Values
   895  		ret := make([]*bgp.LargeCommunity, 0, len(v))
   896  		ret = append(ret, v...)
   897  		return ret
   898  	}
   899  	return nil
   900  }
   901  
   902  func (path *Path) SetLargeCommunities(cs []*bgp.LargeCommunity, doReplace bool) {
   903  	a := path.getPathAttr(bgp.BGP_ATTR_TYPE_LARGE_COMMUNITY)
   904  	if a == nil || doReplace {
   905  		path.setPathAttr(bgp.NewPathAttributeLargeCommunities(cs))
   906  	} else {
   907  		l := a.(*bgp.PathAttributeLargeCommunities).Values
   908  		path.setPathAttr(bgp.NewPathAttributeLargeCommunities(append(l, cs...)))
   909  	}
   910  }
   911  
   912  func (path *Path) GetMed() (uint32, error) {
   913  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC)
   914  	if attr == nil {
   915  		return 0, fmt.Errorf("no med path attr")
   916  	}
   917  	return attr.(*bgp.PathAttributeMultiExitDisc).Value, nil
   918  }
   919  
   920  // SetMed replace, add or subtraction med with new ones.
   921  func (path *Path) SetMed(med int64, doReplace bool) error {
   922  	parseMed := func(orgMed uint32, med int64, doReplace bool) (*bgp.PathAttributeMultiExitDisc, error) {
   923  		if doReplace {
   924  			return bgp.NewPathAttributeMultiExitDisc(uint32(med)), nil
   925  		}
   926  
   927  		medVal := int64(orgMed) + med
   928  		if medVal < 0 {
   929  			return nil, fmt.Errorf("med value invalid. it's underflow threshold: %v", medVal)
   930  		} else if medVal > int64(math.MaxUint32) {
   931  			return nil, fmt.Errorf("med value invalid. it's overflow threshold: %v", medVal)
   932  		}
   933  
   934  		return bgp.NewPathAttributeMultiExitDisc(uint32(int64(orgMed) + med)), nil
   935  	}
   936  
   937  	m := uint32(0)
   938  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC); attr != nil {
   939  		m = attr.(*bgp.PathAttributeMultiExitDisc).Value
   940  	}
   941  	newMed, err := parseMed(m, med, doReplace)
   942  	if err != nil {
   943  		return err
   944  	}
   945  	path.setPathAttr(newMed)
   946  	return nil
   947  }
   948  
   949  func (path *Path) RemoveLocalPref() {
   950  	if path.getPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF) != nil {
   951  		path.delPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF)
   952  	}
   953  }
   954  
   955  func (path *Path) GetOriginatorID() net.IP {
   956  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_ORIGINATOR_ID); attr != nil {
   957  		return attr.(*bgp.PathAttributeOriginatorId).Value
   958  	}
   959  	return nil
   960  }
   961  
   962  func (path *Path) GetClusterList() []net.IP {
   963  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_CLUSTER_LIST); attr != nil {
   964  		return attr.(*bgp.PathAttributeClusterList).Value
   965  	}
   966  	return nil
   967  }
   968  
   969  func (path *Path) GetOrigin() (uint8, error) {
   970  	if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_ORIGIN); attr != nil {
   971  		return attr.(*bgp.PathAttributeOrigin).Value, nil
   972  	}
   973  	return 0, fmt.Errorf("no origin path attr")
   974  }
   975  
   976  func (path *Path) GetLocalPref() (uint32, error) {
   977  	lp := uint32(DEFAULT_LOCAL_PREF)
   978  	attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF)
   979  	if attr != nil {
   980  		lp = attr.(*bgp.PathAttributeLocalPref).Value
   981  	}
   982  	return lp, nil
   983  }
   984  
   985  func (lhs *Path) Equal(rhs *Path) bool {
   986  	if rhs == nil {
   987  		return false
   988  	}
   989  
   990  	if !lhs.GetSource().Equal(rhs.GetSource()) {
   991  		return false
   992  	}
   993  
   994  	pattrs := func(arg []bgp.PathAttributeInterface) []byte {
   995  		ret := make([]byte, 0)
   996  		for _, a := range arg {
   997  			aa, _ := a.Serialize()
   998  			ret = append(ret, aa...)
   999  		}
  1000  		return ret
  1001  	}
  1002  	return bytes.Equal(pattrs(lhs.GetPathAttrs()), pattrs(rhs.GetPathAttrs()))
  1003  }
  1004  
  1005  func (path *Path) MarshalJSON() ([]byte, error) {
  1006  	return json.Marshal(struct {
  1007  		Nlri       bgp.AddrPrefixInterface      `json:"nlri"`
  1008  		PathAttrs  []bgp.PathAttributeInterface `json:"attrs"`
  1009  		Age        int64                        `json:"age"`
  1010  		Withdrawal bool                         `json:"withdrawal,omitempty"`
  1011  		Validation string                       `json:"validation,omitempty"`
  1012  		SourceID   net.IP                       `json:"source-id,omitempty"`
  1013  		NeighborIP net.IP                       `json:"neighbor-ip,omitempty"`
  1014  		Stale      bool                         `json:"stale,omitempty"`
  1015  		UUID       string                       `json:"uuid,omitempty"`
  1016  		ID         uint32                       `json:"id,omitempty"`
  1017  	}{
  1018  		Nlri:       path.GetNlri(),
  1019  		PathAttrs:  path.GetPathAttrs(),
  1020  		Age:        path.GetTimestamp().Unix(),
  1021  		Withdrawal: path.IsWithdraw,
  1022  		Validation: string(path.ValidationStatus()),
  1023  		SourceID:   path.GetSource().ID,
  1024  		NeighborIP: path.GetSource().Address,
  1025  		Stale:      path.IsStale(),
  1026  		ID:         path.GetNlri().PathIdentifier(),
  1027  	})
  1028  }
  1029  
  1030  func (lhs *Path) Compare(rhs *Path) int {
  1031  	if lhs.IsLocal() && !rhs.IsLocal() {
  1032  		return 1
  1033  	} else if !lhs.IsLocal() && rhs.IsLocal() {
  1034  		return -1
  1035  	}
  1036  
  1037  	if !lhs.IsIBGP() && rhs.IsIBGP() {
  1038  		return 1
  1039  	} else if lhs.IsIBGP() && !rhs.IsIBGP() {
  1040  		return -1
  1041  	}
  1042  
  1043  	lp1, _ := lhs.GetLocalPref()
  1044  	lp2, _ := rhs.GetLocalPref()
  1045  	if lp1 != lp2 {
  1046  		return int(lp1 - lp2)
  1047  	}
  1048  
  1049  	l1 := lhs.GetAsPathLen()
  1050  	l2 := rhs.GetAsPathLen()
  1051  	if l1 != l2 {
  1052  		return int(l2 - l1)
  1053  	}
  1054  
  1055  	o1, _ := lhs.GetOrigin()
  1056  	o2, _ := rhs.GetOrigin()
  1057  	if o1 != o2 {
  1058  		return int(o2 - o1)
  1059  	}
  1060  
  1061  	m1, _ := lhs.GetMed()
  1062  	m2, _ := rhs.GetMed()
  1063  	return int(m2 - m1)
  1064  }
  1065  
  1066  func (v *Vrf) ToGlobalPath(path *Path) error {
  1067  	nlri := path.GetNlri()
  1068  	switch rf := path.GetRouteFamily(); rf {
  1069  	case bgp.RF_IPv4_UC:
  1070  		n := nlri.(*bgp.IPAddrPrefix)
  1071  		pathIdentifier := path.GetNlri().PathIdentifier()
  1072  		path.OriginInfo().nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), v.Rd)
  1073  		path.GetNlri().SetPathIdentifier(pathIdentifier)
  1074  	case bgp.RF_IPv6_UC:
  1075  		n := nlri.(*bgp.IPv6AddrPrefix)
  1076  		pathIdentifier := path.GetNlri().PathIdentifier()
  1077  		path.OriginInfo().nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), v.Rd)
  1078  		path.GetNlri().SetPathIdentifier(pathIdentifier)
  1079  	case bgp.RF_EVPN:
  1080  		n := nlri.(*bgp.EVPNNLRI)
  1081  		switch n.RouteType {
  1082  		case bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT:
  1083  			n.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute).RD = v.Rd
  1084  		case bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG:
  1085  			n.RouteTypeData.(*bgp.EVPNMulticastEthernetTagRoute).RD = v.Rd
  1086  		}
  1087  	default:
  1088  		return fmt.Errorf("unsupported route family for vrf: %s", rf)
  1089  	}
  1090  	path.SetExtCommunities(v.ExportRt, false)
  1091  	return nil
  1092  }
  1093  
  1094  func (p *Path) ToGlobal(vrf *Vrf) *Path {
  1095  	nlri := p.GetNlri()
  1096  	nh := p.GetNexthop()
  1097  	pathId := nlri.PathIdentifier()
  1098  	switch rf := p.GetRouteFamily(); rf {
  1099  	case bgp.RF_IPv4_UC:
  1100  		n := nlri.(*bgp.IPAddrPrefix)
  1101  		nlri = bgp.NewLabeledVPNIPAddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), vrf.Rd)
  1102  		nlri.SetPathIdentifier(pathId)
  1103  	case bgp.RF_IPv6_UC:
  1104  		n := nlri.(*bgp.IPv6AddrPrefix)
  1105  		nlri = bgp.NewLabeledVPNIPv6AddrPrefix(n.Length, n.Prefix.String(), *bgp.NewMPLSLabelStack(0), vrf.Rd)
  1106  		nlri.SetPathIdentifier(pathId)
  1107  	case bgp.RF_EVPN:
  1108  		n := nlri.(*bgp.EVPNNLRI)
  1109  		switch n.RouteType {
  1110  		case bgp.EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT:
  1111  			old := n.RouteTypeData.(*bgp.EVPNMacIPAdvertisementRoute)
  1112  			new := &bgp.EVPNMacIPAdvertisementRoute{
  1113  				RD:               vrf.Rd,
  1114  				ESI:              old.ESI,
  1115  				ETag:             old.ETag,
  1116  				MacAddressLength: old.MacAddressLength,
  1117  				MacAddress:       old.MacAddress,
  1118  				IPAddressLength:  old.IPAddressLength,
  1119  				IPAddress:        old.IPAddress,
  1120  				Labels:           old.Labels,
  1121  			}
  1122  			nlri = bgp.NewEVPNNLRI(n.RouteType, new)
  1123  		case bgp.EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG:
  1124  			old := n.RouteTypeData.(*bgp.EVPNMulticastEthernetTagRoute)
  1125  			new := &bgp.EVPNMulticastEthernetTagRoute{
  1126  				RD:              vrf.Rd,
  1127  				ETag:            old.ETag,
  1128  				IPAddressLength: old.IPAddressLength,
  1129  				IPAddress:       old.IPAddress,
  1130  			}
  1131  			nlri = bgp.NewEVPNNLRI(n.RouteType, new)
  1132  		}
  1133  	default:
  1134  		return p
  1135  	}
  1136  	path := NewPath(p.OriginInfo().source, nlri, p.IsWithdraw, p.GetPathAttrs(), p.GetTimestamp(), false)
  1137  	path.SetExtCommunities(vrf.ExportRt, false)
  1138  	path.delPathAttr(bgp.BGP_ATTR_TYPE_NEXT_HOP)
  1139  	path.setPathAttr(bgp.NewPathAttributeMpReachNLRI(nh.String(), []bgp.AddrPrefixInterface{nlri}))
  1140  	path.IsNexthopInvalid = p.IsNexthopInvalid
  1141  	return path
  1142  }
  1143  
  1144  func (p *Path) ToLocal() *Path {
  1145  	nlri := p.GetNlri()
  1146  	f := p.GetRouteFamily()
  1147  	pathId := nlri.PathLocalIdentifier()
  1148  	switch f {
  1149  	case bgp.RF_IPv4_VPN:
  1150  		n := nlri.(*bgp.LabeledVPNIPAddrPrefix)
  1151  		_, c, _ := net.ParseCIDR(n.IPPrefix())
  1152  		ones, _ := c.Mask.Size()
  1153  		nlri = bgp.NewIPAddrPrefix(uint8(ones), c.IP.String())
  1154  		nlri.SetPathLocalIdentifier(pathId)
  1155  	case bgp.RF_IPv6_VPN:
  1156  		n := nlri.(*bgp.LabeledVPNIPv6AddrPrefix)
  1157  		_, c, _ := net.ParseCIDR(n.IPPrefix())
  1158  		ones, _ := c.Mask.Size()
  1159  		nlri = bgp.NewIPv6AddrPrefix(uint8(ones), c.IP.String())
  1160  		nlri.SetPathLocalIdentifier(pathId)
  1161  	default:
  1162  		return p
  1163  	}
  1164  	path := NewPath(p.OriginInfo().source, nlri, p.IsWithdraw, p.GetPathAttrs(), p.GetTimestamp(), false)
  1165  	path.delPathAttr(bgp.BGP_ATTR_TYPE_EXTENDED_COMMUNITIES)
  1166  
  1167  	if f == bgp.RF_IPv4_VPN {
  1168  		nh := path.GetNexthop()
  1169  		path.delPathAttr(bgp.BGP_ATTR_TYPE_MP_REACH_NLRI)
  1170  		path.setPathAttr(bgp.NewPathAttributeNextHop(nh.String()))
  1171  	}
  1172  	path.IsNexthopInvalid = p.IsNexthopInvalid
  1173  	return path
  1174  }
  1175  
  1176  func (p *Path) SetHash(v uint32) {
  1177  	p.attrsHash = v
  1178  }
  1179  
  1180  func (p *Path) GetHash() uint32 {
  1181  	return p.attrsHash
  1182  }