github.com/osrg/gobgp@v2.0.0+incompatible/internal/pkg/table/message.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  	"reflect"
    21  
    22  	"github.com/osrg/gobgp/pkg/packet/bgp"
    23  	log "github.com/sirupsen/logrus"
    24  )
    25  
    26  func UpdatePathAttrs2ByteAs(msg *bgp.BGPUpdate) error {
    27  	ps := msg.PathAttributes
    28  	msg.PathAttributes = make([]bgp.PathAttributeInterface, len(ps))
    29  	copy(msg.PathAttributes, ps)
    30  	var asAttr *bgp.PathAttributeAsPath
    31  	idx := 0
    32  	for i, attr := range msg.PathAttributes {
    33  		if a, ok := attr.(*bgp.PathAttributeAsPath); ok {
    34  			asAttr = a
    35  			idx = i
    36  			break
    37  		}
    38  	}
    39  
    40  	if asAttr == nil {
    41  		return nil
    42  	}
    43  
    44  	as4Params := make([]*bgp.As4PathParam, 0, len(asAttr.Value))
    45  	as2Params := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
    46  	mkAs4 := false
    47  	for _, param := range asAttr.Value {
    48  		segType := param.GetType()
    49  		asList := param.GetAS()
    50  		as2Path := make([]uint16, 0, len(asList))
    51  		for _, as := range asList {
    52  			if as > (1<<16)-1 {
    53  				mkAs4 = true
    54  				as2Path = append(as2Path, bgp.AS_TRANS)
    55  			} else {
    56  				as2Path = append(as2Path, uint16(as))
    57  			}
    58  		}
    59  		as2Params = append(as2Params, bgp.NewAsPathParam(segType, as2Path))
    60  
    61  		// RFC 6793 4.2.2 Generating Updates
    62  		//
    63  		// Whenever the AS path information contains the AS_CONFED_SEQUENCE or
    64  		// AS_CONFED_SET path segment, the NEW BGP speaker MUST exclude such
    65  		// path segments from the AS4_PATH attribute being constructed.
    66  		switch segType {
    67  		case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET:
    68  			// pass
    69  		default:
    70  			if as4param, ok := param.(*bgp.As4PathParam); ok {
    71  				as4Params = append(as4Params, as4param)
    72  			}
    73  		}
    74  	}
    75  	msg.PathAttributes[idx] = bgp.NewPathAttributeAsPath(as2Params)
    76  	if mkAs4 {
    77  		msg.PathAttributes = append(msg.PathAttributes, bgp.NewPathAttributeAs4Path(as4Params))
    78  	}
    79  	return nil
    80  }
    81  
    82  func UpdatePathAttrs4ByteAs(msg *bgp.BGPUpdate) error {
    83  	var asAttr *bgp.PathAttributeAsPath
    84  	var as4Attr *bgp.PathAttributeAs4Path
    85  	asAttrPos := 0
    86  	as4AttrPos := 0
    87  	for i, attr := range msg.PathAttributes {
    88  		switch attr.(type) {
    89  		case *bgp.PathAttributeAsPath:
    90  			asAttr = attr.(*bgp.PathAttributeAsPath)
    91  			for j, param := range asAttr.Value {
    92  				as2Param, ok := param.(*bgp.AsPathParam)
    93  				if ok {
    94  					asPath := make([]uint32, 0, len(as2Param.AS))
    95  					for _, as := range as2Param.AS {
    96  						asPath = append(asPath, uint32(as))
    97  					}
    98  					as4Param := bgp.NewAs4PathParam(as2Param.Type, asPath)
    99  					asAttr.Value[j] = as4Param
   100  				}
   101  			}
   102  			asAttrPos = i
   103  			msg.PathAttributes[i] = asAttr
   104  		case *bgp.PathAttributeAs4Path:
   105  			as4AttrPos = i
   106  			as4Attr = attr.(*bgp.PathAttributeAs4Path)
   107  		}
   108  	}
   109  
   110  	if as4Attr != nil {
   111  		msg.PathAttributes = append(msg.PathAttributes[:as4AttrPos], msg.PathAttributes[as4AttrPos+1:]...)
   112  	}
   113  
   114  	if asAttr == nil || as4Attr == nil {
   115  		return nil
   116  	}
   117  
   118  	asLen := 0
   119  	asConfedLen := 0
   120  	asParams := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
   121  	for _, param := range asAttr.Value {
   122  		asLen += param.ASLen()
   123  		switch param.GetType() {
   124  		case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET:
   125  			asConfedLen++
   126  		case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
   127  			asConfedLen += len(param.GetAS())
   128  		}
   129  		asParams = append(asParams, param)
   130  	}
   131  
   132  	as4Len := 0
   133  	as4Params := make([]bgp.AsPathParamInterface, 0, len(as4Attr.Value))
   134  	if as4Attr != nil {
   135  		for _, p := range as4Attr.Value {
   136  			// RFC 6793 6. Error Handling
   137  			//
   138  			// the path segment types AS_CONFED_SEQUENCE and AS_CONFED_SET [RFC5065]
   139  			// MUST NOT be carried in the AS4_PATH attribute of an UPDATE message.
   140  			// A NEW BGP speaker that receives these path segment types in the AS4_PATH
   141  			// attribute of an UPDATE message from an OLD BGP speaker MUST discard
   142  			// these path segments, adjust the relevant attribute fields accordingly,
   143  			// and continue processing the UPDATE message.
   144  			// This case SHOULD be logged locally for analysis.
   145  			switch p.Type {
   146  			case bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET:
   147  				typ := "CONFED_SEQ"
   148  				if p.Type == bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET {
   149  					typ = "CONFED_SET"
   150  				}
   151  				log.WithFields(log.Fields{
   152  					"Topic": "Table",
   153  				}).Warnf("AS4_PATH contains %s segment %s. ignore", typ, p.String())
   154  				continue
   155  			}
   156  			as4Len += p.ASLen()
   157  			as4Params = append(as4Params, p)
   158  		}
   159  	}
   160  
   161  	if asLen+asConfedLen < as4Len {
   162  		log.WithFields(log.Fields{
   163  			"Topic": "Table",
   164  		}).Warn("AS4_PATH is longer than AS_PATH. ignore AS4_PATH")
   165  		return nil
   166  	}
   167  
   168  	keepNum := asLen + asConfedLen - as4Len
   169  
   170  	newParams := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
   171  	for _, param := range asParams {
   172  		if keepNum-param.ASLen() >= 0 {
   173  			newParams = append(newParams, param)
   174  			keepNum -= param.ASLen()
   175  		} else {
   176  			// only SEQ param reaches here
   177  			newParams = append(newParams, bgp.NewAs4PathParam(param.GetType(), param.GetAS()[:keepNum]))
   178  			keepNum = 0
   179  		}
   180  
   181  		if keepNum <= 0 {
   182  			break
   183  		}
   184  	}
   185  
   186  	for _, param := range as4Params {
   187  		lastParam := newParams[len(newParams)-1]
   188  		lastParamAS := lastParam.GetAS()
   189  		paramType := param.GetType()
   190  		paramAS := param.GetAS()
   191  		if paramType == lastParam.GetType() && paramType == bgp.BGP_ASPATH_ATTR_TYPE_SEQ {
   192  			if len(lastParamAS)+len(paramAS) > 255 {
   193  				newParams[len(newParams)-1] = bgp.NewAs4PathParam(paramType, append(lastParamAS, paramAS[:255-len(lastParamAS)]...))
   194  				newParams = append(newParams, bgp.NewAs4PathParam(paramType, paramAS[255-len(lastParamAS):]))
   195  			} else {
   196  				newParams[len(newParams)-1] = bgp.NewAs4PathParam(paramType, append(lastParamAS, paramAS...))
   197  			}
   198  		} else {
   199  			newParams = append(newParams, param)
   200  		}
   201  	}
   202  
   203  	newIntfParams := make([]bgp.AsPathParamInterface, 0, len(asAttr.Value))
   204  	newIntfParams = append(newIntfParams, newParams...)
   205  
   206  	msg.PathAttributes[asAttrPos] = bgp.NewPathAttributeAsPath(newIntfParams)
   207  	return nil
   208  }
   209  
   210  func UpdatePathAggregator2ByteAs(msg *bgp.BGPUpdate) {
   211  	as := uint32(0)
   212  	var addr string
   213  	for i, attr := range msg.PathAttributes {
   214  		switch attr.(type) {
   215  		case *bgp.PathAttributeAggregator:
   216  			agg := attr.(*bgp.PathAttributeAggregator)
   217  			addr = agg.Value.Address.String()
   218  			if agg.Value.AS > (1<<16)-1 {
   219  				as = agg.Value.AS
   220  				msg.PathAttributes[i] = bgp.NewPathAttributeAggregator(uint16(bgp.AS_TRANS), addr)
   221  			} else {
   222  				msg.PathAttributes[i] = bgp.NewPathAttributeAggregator(uint16(agg.Value.AS), addr)
   223  			}
   224  		}
   225  	}
   226  	if as != 0 {
   227  		msg.PathAttributes = append(msg.PathAttributes, bgp.NewPathAttributeAs4Aggregator(as, addr))
   228  	}
   229  }
   230  
   231  func UpdatePathAggregator4ByteAs(msg *bgp.BGPUpdate) error {
   232  	var aggAttr *bgp.PathAttributeAggregator
   233  	var agg4Attr *bgp.PathAttributeAs4Aggregator
   234  	agg4AttrPos := 0
   235  	for i, attr := range msg.PathAttributes {
   236  		switch attr.(type) {
   237  		case *bgp.PathAttributeAggregator:
   238  			attr := attr.(*bgp.PathAttributeAggregator)
   239  			if attr.Value.Askind == reflect.Uint16 {
   240  				aggAttr = attr
   241  				aggAttr.Value.Askind = reflect.Uint32
   242  			}
   243  		case *bgp.PathAttributeAs4Aggregator:
   244  			agg4Attr = attr.(*bgp.PathAttributeAs4Aggregator)
   245  			agg4AttrPos = i
   246  		}
   247  	}
   248  	if aggAttr == nil && agg4Attr == nil {
   249  		return nil
   250  	}
   251  
   252  	if aggAttr == nil && agg4Attr != nil {
   253  		return bgp.NewMessageError(bgp.BGP_ERROR_UPDATE_MESSAGE_ERROR, bgp.BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "AS4 AGGREGATOR attribute exists, but AGGREGATOR doesn't")
   254  	}
   255  
   256  	if agg4Attr != nil {
   257  		msg.PathAttributes = append(msg.PathAttributes[:agg4AttrPos], msg.PathAttributes[agg4AttrPos+1:]...)
   258  		aggAttr.Value.AS = agg4Attr.Value.AS
   259  	}
   260  	return nil
   261  }
   262  
   263  type cage struct {
   264  	attrsBytes []byte
   265  	paths      []*Path
   266  }
   267  
   268  func newCage(b []byte, path *Path) *cage {
   269  	return &cage{
   270  		attrsBytes: b,
   271  		paths:      []*Path{path},
   272  	}
   273  }
   274  
   275  type packerInterface interface {
   276  	add(*Path)
   277  	pack(options ...*bgp.MarshallingOption) []*bgp.BGPMessage
   278  }
   279  
   280  type packer struct {
   281  	eof    bool
   282  	family bgp.RouteFamily
   283  	total  uint32
   284  }
   285  
   286  type packerMP struct {
   287  	packer
   288  	paths       []*Path
   289  	withdrawals []*Path
   290  }
   291  
   292  func (p *packerMP) add(path *Path) {
   293  	p.packer.total++
   294  
   295  	if path.IsEOR() {
   296  		p.packer.eof = true
   297  		return
   298  	}
   299  
   300  	if path.IsWithdraw {
   301  		p.withdrawals = append(p.withdrawals, path)
   302  		return
   303  	}
   304  
   305  	p.paths = append(p.paths, path)
   306  }
   307  
   308  func createMPReachMessage(path *Path) *bgp.BGPMessage {
   309  	oattrs := path.GetPathAttrs()
   310  	attrs := make([]bgp.PathAttributeInterface, 0, len(oattrs))
   311  	for _, a := range oattrs {
   312  		if a.GetType() == bgp.BGP_ATTR_TYPE_MP_REACH_NLRI {
   313  			attrs = append(attrs, bgp.NewPathAttributeMpReachNLRI(path.GetNexthop().String(), []bgp.AddrPrefixInterface{path.GetNlri()}))
   314  		} else {
   315  			attrs = append(attrs, a)
   316  		}
   317  	}
   318  	return bgp.NewBGPUpdateMessage(nil, attrs, nil)
   319  }
   320  
   321  func (p *packerMP) pack(options ...*bgp.MarshallingOption) []*bgp.BGPMessage {
   322  	msgs := make([]*bgp.BGPMessage, 0, p.packer.total)
   323  
   324  	for _, path := range p.withdrawals {
   325  		nlris := []bgp.AddrPrefixInterface{path.GetNlri()}
   326  		msgs = append(msgs, bgp.NewBGPUpdateMessage(nil, []bgp.PathAttributeInterface{bgp.NewPathAttributeMpUnreachNLRI(nlris)}, nil))
   327  	}
   328  
   329  	for _, path := range p.paths {
   330  		msgs = append(msgs, createMPReachMessage(path))
   331  	}
   332  
   333  	if p.eof {
   334  		msgs = append(msgs, bgp.NewEndOfRib(p.family))
   335  	}
   336  	return msgs
   337  }
   338  
   339  func newPackerMP(f bgp.RouteFamily) *packerMP {
   340  	return &packerMP{
   341  		packer: packer{
   342  			family: f,
   343  		},
   344  		withdrawals: make([]*Path, 0),
   345  		paths:       make([]*Path, 0),
   346  	}
   347  }
   348  
   349  type packerV4 struct {
   350  	packer
   351  	hashmap     map[uint32][]*cage
   352  	mpPaths     []*Path
   353  	withdrawals []*Path
   354  }
   355  
   356  func (p *packerV4) add(path *Path) {
   357  	p.packer.total++
   358  
   359  	if path.IsEOR() {
   360  		p.packer.eof = true
   361  		return
   362  	}
   363  
   364  	if path.IsWithdraw {
   365  		p.withdrawals = append(p.withdrawals, path)
   366  		return
   367  	}
   368  
   369  	if path.GetNexthop().To4() == nil {
   370  		// RFC 5549
   371  		p.mpPaths = append(p.mpPaths, path)
   372  		return
   373  	}
   374  
   375  	key := path.GetHash()
   376  	attrsB := bytes.NewBuffer(make([]byte, 0))
   377  	for _, v := range path.GetPathAttrs() {
   378  		b, _ := v.Serialize()
   379  		attrsB.Write(b)
   380  	}
   381  
   382  	if cages, y := p.hashmap[key]; y {
   383  		added := false
   384  		for _, c := range cages {
   385  			if bytes.Equal(c.attrsBytes, attrsB.Bytes()) {
   386  				c.paths = append(c.paths, path)
   387  				added = true
   388  				break
   389  			}
   390  		}
   391  		if !added {
   392  			p.hashmap[key] = append(p.hashmap[key], newCage(attrsB.Bytes(), path))
   393  		}
   394  	} else {
   395  		p.hashmap[key] = []*cage{newCage(attrsB.Bytes(), path)}
   396  	}
   397  }
   398  
   399  func (p *packerV4) pack(options ...*bgp.MarshallingOption) []*bgp.BGPMessage {
   400  	split := func(max int, paths []*Path) ([]*bgp.IPAddrPrefix, []*Path) {
   401  		nlris := make([]*bgp.IPAddrPrefix, 0, max)
   402  		i := 0
   403  		if max > len(paths) {
   404  			max = len(paths)
   405  		}
   406  		for ; i < max; i++ {
   407  			nlris = append(nlris, paths[i].GetNlri().(*bgp.IPAddrPrefix))
   408  		}
   409  		return nlris, paths[i:]
   410  	}
   411  	addpathNLRILen := 0
   412  	if bgp.IsAddPathEnabled(false, p.packer.family, options) {
   413  		addpathNLRILen = 4
   414  	}
   415  	// Header + Update (WithdrawnRoutesLen +
   416  	// TotalPathAttributeLen + attributes + maxlen of NLRI).
   417  	// the max size of NLRI is 5bytes (plus 4bytes with addpath enabled)
   418  	maxNLRIs := func(attrsLen int) int {
   419  		return (bgp.BGP_MAX_MESSAGE_LENGTH - (19 + 2 + 2 + attrsLen)) / (5 + addpathNLRILen)
   420  	}
   421  
   422  	loop := func(attrsLen int, paths []*Path, cb func([]*bgp.IPAddrPrefix)) {
   423  		max := maxNLRIs(attrsLen)
   424  		var nlris []*bgp.IPAddrPrefix
   425  		for {
   426  			nlris, paths = split(max, paths)
   427  			if len(nlris) == 0 {
   428  				break
   429  			}
   430  			cb(nlris)
   431  		}
   432  	}
   433  
   434  	msgs := make([]*bgp.BGPMessage, 0, p.packer.total)
   435  
   436  	loop(0, p.withdrawals, func(nlris []*bgp.IPAddrPrefix) {
   437  		msgs = append(msgs, bgp.NewBGPUpdateMessage(nlris, nil, nil))
   438  	})
   439  
   440  	for _, cages := range p.hashmap {
   441  		for _, c := range cages {
   442  			paths := c.paths
   443  
   444  			attrs := paths[0].GetPathAttrs()
   445  			attrsLen := 0
   446  			for _, a := range attrs {
   447  				attrsLen += a.Len()
   448  			}
   449  
   450  			loop(attrsLen, paths, func(nlris []*bgp.IPAddrPrefix) {
   451  				msgs = append(msgs, bgp.NewBGPUpdateMessage(nil, attrs, nlris))
   452  			})
   453  		}
   454  	}
   455  
   456  	for _, path := range p.mpPaths {
   457  		msgs = append(msgs, createMPReachMessage(path))
   458  	}
   459  
   460  	if p.eof {
   461  		msgs = append(msgs, bgp.NewEndOfRib(p.family))
   462  	}
   463  	return msgs
   464  }
   465  
   466  func newPackerV4(f bgp.RouteFamily) *packerV4 {
   467  	return &packerV4{
   468  		packer: packer{
   469  			family: f,
   470  		},
   471  		hashmap:     make(map[uint32][]*cage),
   472  		withdrawals: make([]*Path, 0),
   473  		mpPaths:     make([]*Path, 0),
   474  	}
   475  }
   476  
   477  func newPacker(f bgp.RouteFamily) packerInterface {
   478  	switch f {
   479  	case bgp.RF_IPv4_UC:
   480  		return newPackerV4(bgp.RF_IPv4_UC)
   481  	default:
   482  		return newPackerMP(f)
   483  	}
   484  }
   485  
   486  func CreateUpdateMsgFromPaths(pathList []*Path, options ...*bgp.MarshallingOption) []*bgp.BGPMessage {
   487  	msgs := make([]*bgp.BGPMessage, 0, len(pathList))
   488  
   489  	m := make(map[bgp.RouteFamily]packerInterface)
   490  	for _, path := range pathList {
   491  		f := path.GetRouteFamily()
   492  		if _, y := m[f]; !y {
   493  			m[f] = newPacker(f)
   494  		}
   495  		m[f].add(path)
   496  	}
   497  
   498  	for _, p := range m {
   499  		msgs = append(msgs, p.pack(options...)...)
   500  	}
   501  	return msgs
   502  }