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