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 }