diff --git a/config/peer.go b/config/peer.go index 82a9f61f56fea089384b18ada019d4192834d6ea..fa963092ec84cf76d3db5ce05c45672131cd3f93 100644 --- a/config/peer.go +++ b/config/peer.go @@ -21,8 +21,6 @@ type Peer struct { PeerAS uint32 Passive bool RouterID uint32 - AddPathSend routingtable.ClientOptions - AddPathRecv bool RouteServerClient bool RouteReflectorClient bool RouteReflectorClusterID uint32 @@ -35,4 +33,6 @@ type AddressFamilyConfig struct { RIB *locRIB.LocRIB ImportFilter *filter.Filter ExportFilter *filter.Filter + AddPathSend routingtable.ClientOptions + AddPathRecv bool } diff --git a/main_ipv4.go b/main_ipv4.go index 0d3c5a7cd4b0ce93fbe645136bd588cfbc872c2b..c280c0723e28449664dcf2692f0150e4a60c5fc2 100644 --- a/main_ipv4.go +++ b/main_ipv4.go @@ -40,13 +40,13 @@ func startServer(b server.BGPServer, rib *locRIB.LocRIB) { KeepAlive: time.Second * 30, Passive: true, RouterID: b.RouterID(), - AddPathSend: routingtable.ClientOptions{ - MaxPaths: 10, - }, IPv4: &config.AddressFamilyConfig{ RIB: rib, ImportFilter: filter.NewAcceptAllFilter(), ExportFilter: filter.NewAcceptAllFilter(), + AddPathSend: routingtable.ClientOptions{ + MaxPaths: 10, + }, }, RouteServerClient: true, }) @@ -62,15 +62,15 @@ func startServer(b server.BGPServer, rib *locRIB.LocRIB) { KeepAlive: time.Second * 30, Passive: true, RouterID: b.RouterID(), - AddPathSend: routingtable.ClientOptions{ - MaxPaths: 10, - }, - AddPathRecv: true, RouteServerClient: true, IPv4: &config.AddressFamilyConfig{ RIB: rib, ImportFilter: filter.NewAcceptAllFilter(), ExportFilter: filter.NewAcceptAllFilter(), + AddPathSend: routingtable.ClientOptions{ + MaxPaths: 10, + }, + AddPathRecv: true, }, }) } diff --git a/main_ipv6.go b/main_ipv6.go index 2d4a24100e2e1eea680fa63368235495846456ac..30467c00d23fb2d367f8110c0c02fd0e431f4ab6 100644 --- a/main_ipv6.go +++ b/main_ipv6.go @@ -38,13 +38,13 @@ func startServer(b server.BGPServer, rib *locRIB.LocRIB) { KeepAlive: time.Second * 30, Passive: true, RouterID: b.RouterID(), - AddPathSend: routingtable.ClientOptions{ - BestOnly: true, - }, IPv6: &config.AddressFamilyConfig{ RIB: rib, ImportFilter: filter.NewAcceptAllFilter(), ExportFilter: filter.NewDrainFilter(), + AddPathSend: routingtable.ClientOptions{ + BestOnly: true, + }, }, }) @@ -59,13 +59,13 @@ func startServer(b server.BGPServer, rib *locRIB.LocRIB) { KeepAlive: time.Second * 30, Passive: true, RouterID: b.RouterID(), - AddPathSend: routingtable.ClientOptions{ - BestOnly: true, - }, IPv6: &config.AddressFamilyConfig{ RIB: rib, ImportFilter: filter.NewDrainFilter(), ExportFilter: filter.NewAcceptAllFilter(), + AddPathSend: routingtable.ClientOptions{ + BestOnly: true, + }, }, }) } diff --git a/protocols/bgp/packet/BUILD.bazel b/protocols/bgp/packet/BUILD.bazel index f9886e41d0eea9ee21bac03dc902ad7f4218b131..9ea14d6607ee4dfe18b135e29c8de7c9d3a4b8a3 100644 --- a/protocols/bgp/packet/BUILD.bazel +++ b/protocols/bgp/packet/BUILD.bazel @@ -4,7 +4,9 @@ go_library( name = "go_default_library", srcs = [ "bgp.go", + "decode_options.go", "decoder.go", + "encode_options.go", "encoder.go", "helper.go", "mp_reach_nlri.go", diff --git a/protocols/bgp/packet/bgp.go b/protocols/bgp/packet/bgp.go index 2ef1009d179cc98c0f197cfa827b21c5ac859016..80c79ae74fe72e38a5afb2267bc32a35a021d38b 100644 --- a/protocols/bgp/packet/bgp.go +++ b/protocols/bgp/packet/bgp.go @@ -158,3 +158,15 @@ type PathAttribute struct { Value interface{} Next *PathAttribute } + +// AFIName returns the name of an address family +func AFIName(afi uint16) string { + switch afi { + case IPv4AFI: + return "IPv4" + case IPv6AFI: + return "IPv6" + default: + return "Unknown AFI" + } +} diff --git a/protocols/bgp/packet/decode_options.go b/protocols/bgp/packet/decode_options.go new file mode 100644 index 0000000000000000000000000000000000000000..9cea580caaccdd2c2176bae4ab5081f281a6f729 --- /dev/null +++ b/protocols/bgp/packet/decode_options.go @@ -0,0 +1,5 @@ +package packet + +type DecodeOptions struct { + Use32BitASN bool +} diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go index cd951463a15215bd6aaa43e8799e59c95cee549b..0d719fc04c20779ae818e21e756ba925c4bb4e5e 100644 --- a/protocols/bgp/packet/decoder.go +++ b/protocols/bgp/packet/decoder.go @@ -6,12 +6,11 @@ import ( "fmt" "net" - "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/taktv6/tflow2/convert" ) // Decode decodes a BGP message -func Decode(buf *bytes.Buffer, opt *types.Options) (*BGPMessage, error) { +func Decode(buf *bytes.Buffer, opt *DecodeOptions) (*BGPMessage, error) { hdr, err := decodeHeader(buf) if err != nil { return nil, fmt.Errorf("Failed to decode header: %v", err) @@ -28,7 +27,7 @@ func Decode(buf *bytes.Buffer, opt *types.Options) (*BGPMessage, error) { }, nil } -func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *types.Options) (interface{}, error) { +func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *DecodeOptions) (interface{}, error) { switch msgType { case OpenMsg: return decodeOpenMsg(buf) @@ -42,7 +41,7 @@ func decodeMsgBody(buf *bytes.Buffer, msgType uint8, l uint16, opt *types.Option return nil, fmt.Errorf("Unknown message type: %d", msgType) } -func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *types.Options) (*BGPUpdate, error) { +func decodeUpdateMsg(buf *bytes.Buffer, l uint16, opt *DecodeOptions) (*BGPUpdate, error) { msg := &BGPUpdate{} err := decode(buf, []interface{}{&msg.WithdrawnRoutesLen}) diff --git a/protocols/bgp/packet/decoder_test.go b/protocols/bgp/packet/decoder_test.go index ac611ceff133e4375e70995a2b564900671ed8aa..74e5b84f978f084c38360b85b72030fe79fe945e 100644 --- a/protocols/bgp/packet/decoder_test.go +++ b/protocols/bgp/packet/decoder_test.go @@ -74,7 +74,7 @@ func BenchmarkDecodeUpdateMsg(b *testing.B) { for i := 0; i < b.N; i++ { buf := bytes.NewBuffer(input) - _, err := decodeUpdateMsg(buf, uint16(len(input)), &types.Options{}) + _, err := decodeUpdateMsg(buf, uint16(len(input)), &DecodeOptions{}) if err != nil { fmt.Printf("decodeUpdateMsg failed: %v\n", err) } @@ -255,7 +255,7 @@ func TestDecode(t *testing.T) { for _, test := range tests { buf := bytes.NewBuffer(test.input) - msg, err := Decode(buf, &types.Options{}) + msg, err := Decode(buf, &DecodeOptions{}) if err != nil && !test.wantFail { t.Errorf("Unexpected error in test %d: %v", test.testNum, err) @@ -1369,7 +1369,7 @@ func TestDecodeUpdateMsg(t *testing.T) { if l == 0 { l = uint16(len(test.input)) } - msg, err := decodeUpdateMsg(buf, l, &types.Options{}) + msg, err := decodeUpdateMsg(buf, l, &DecodeOptions{}) if err != nil && !test.wantFail { t.Fatalf("Unexpected error in test %d: %v", test.testNum, err) @@ -1405,7 +1405,7 @@ func TestDecodeMsgBody(t *testing.T) { } for _, test := range tests { - res, err := decodeMsgBody(test.buffer, test.msgType, test.length, &types.Options{}) + res, err := decodeMsgBody(test.buffer, test.msgType, test.length, &DecodeOptions{}) if test.wantFail && err == nil { t.Errorf("Expected error dit not happen in test %q", test.name) } diff --git a/protocols/bgp/packet/encode_options.go b/protocols/bgp/packet/encode_options.go new file mode 100644 index 0000000000000000000000000000000000000000..6cf08a5e6175f90b98fec9d79e9a416c5c93ff67 --- /dev/null +++ b/protocols/bgp/packet/encode_options.go @@ -0,0 +1,6 @@ +package packet + +type EncodeOptions struct { + Use32BitASN bool + UseAddPath bool +} diff --git a/protocols/bgp/packet/fuzzing.go b/protocols/bgp/packet/fuzzing.go index 9f829cc89c3dcfb7566287fa9c6c3ffbab11ce5b..d821b53f99b275b05ef15f246f725ab1a8977936 100644 --- a/protocols/bgp/packet/fuzzing.go +++ b/protocols/bgp/packet/fuzzing.go @@ -1,11 +1,12 @@ -// foobar -// +bu ild go fuzz +// +build go fuzz package packet import ( "bytes" + "github.com/bio-routing/bio-rd/protocols/bgp/packet" + "github.com/bio-routing/bio-rd/protocols/bgp/types" ) @@ -16,9 +17,8 @@ const ( ) func Fuzz(data []byte) int { - buf := bytes.NewBuffer(data) - for _, option := range getAllOptions() { + for _, option := range getAllDecodingOptions() { msg, err := Decode(buf, &option) if err != nil { if msg != nil { @@ -26,27 +26,21 @@ func Fuzz(data []byte) int { } } + return INC_PRIO } + return KEEP } -func getAllOptions() []types.Options { +func getAllDecodingOptions() []DecodeOptions { parameters := []bool{true, false} - var ret []types.Options + var ret []DecodeOptions for _, octet := range parameters { - for _, mpbgp4 := range parameters { - for _, mpbgp6 := range parameters { - for _, addPathX := range parameters { - ret = append(ret, types.Options{ - Supports4OctetASN: octet, - MultiProtocolIPv4: mpbgp4, - MultiProtocolIPv6: mpbgp6, - AddPathRX: addPathX, - }) - } - } - } + ret = append(ret, DecodeOptions{ + Use32BitASN: octet + }) } + return ret } diff --git a/protocols/bgp/packet/mp_reach_nlri.go b/protocols/bgp/packet/mp_reach_nlri.go index 65665f29182e3b81e337d2f1bc8e25d2afbc8b50..32009637f8b17fd282392ad0a7231a67940ce44b 100644 --- a/protocols/bgp/packet/mp_reach_nlri.go +++ b/protocols/bgp/packet/mp_reach_nlri.go @@ -15,9 +15,10 @@ type MultiProtocolReachNLRI struct { SAFI uint8 NextHop bnet.IP Prefixes []bnet.Prefix + PathID uint32 } -func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer) uint16 { +func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 { nextHop := n.NextHop.Bytes() tempBuf := bytes.NewBuffer(nil) @@ -27,6 +28,9 @@ func (n *MultiProtocolReachNLRI) serialize(buf *bytes.Buffer) uint16 { tempBuf.Write(nextHop) tempBuf.WriteByte(0) // RESERVED for _, pfx := range n.Prefixes { + if opt.UseAddPath { + tempBuf.Write(convert.Uint32Byte(n.PathID)) + } tempBuf.Write(serializePrefix(pfx)) } diff --git a/protocols/bgp/packet/mp_reach_nlri_test.go b/protocols/bgp/packet/mp_reach_nlri_test.go index f16ac3c4a181eb3bd0534f0e831bbb00eb09c8cf..cb6e5b544333d76f3244c8ef6895acb40783f149 100644 --- a/protocols/bgp/packet/mp_reach_nlri_test.go +++ b/protocols/bgp/packet/mp_reach_nlri_test.go @@ -13,6 +13,7 @@ func TestSerializeMultiProtocolReachNLRI(t *testing.T) { name string nlri MultiProtocolReachNLRI expected []byte + addPath bool }{ { name: "Simple IPv6 prefix", @@ -32,12 +33,35 @@ func TestSerializeMultiProtocolReachNLRI(t *testing.T) { 0x30, 0x26, 0x00, 0x00, 0x06, 0xff, 0x05, // Prefix }, }, + { + name: "IPv6 prefix with ADD-PATH", + nlri: MultiProtocolReachNLRI{ + AFI: IPv6AFI, + SAFI: UnicastSAFI, + NextHop: bnet.IPv6FromBlocks(0x2001, 0x678, 0x1e0, 0, 0, 0, 0, 0x2), + Prefixes: []bnet.Prefix{ + bnet.NewPfx(bnet.IPv6FromBlocks(0x2600, 0x6, 0xff05, 0, 0, 0, 0, 0), 48), + }, + PathID: 100, + }, + expected: []byte{ + 0x00, 0x02, // AFI + 0x01, // SAFI + 0x10, 0x20, 0x01, 0x06, 0x78, 0x01, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // NextHop + 0x00, // RESERVED + 0x00, 0x00, 0x00, 100, // PathID + 0x30, 0x26, 0x00, 0x00, 0x06, 0xff, 0x05, // Prefix + }, + addPath: true, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { buf := &bytes.Buffer{} - test.nlri.serialize(buf) + test.nlri.serialize(buf, &EncodeOptions{ + UseAddPath: test.addPath, + }) assert.Equal(t, test.expected, buf.Bytes()) }) } diff --git a/protocols/bgp/packet/mp_unreach_nlri.go b/protocols/bgp/packet/mp_unreach_nlri.go index 63cccd580dfe79e474c1be33f96485eebec1d43b..fd72618c51b58fe3437b5f7445f827f0b3820bcd 100644 --- a/protocols/bgp/packet/mp_unreach_nlri.go +++ b/protocols/bgp/packet/mp_unreach_nlri.go @@ -13,13 +13,17 @@ type MultiProtocolUnreachNLRI struct { AFI uint16 SAFI uint8 Prefixes []bnet.Prefix + PathID uint32 } -func (n *MultiProtocolUnreachNLRI) serialize(buf *bytes.Buffer) uint16 { +func (n *MultiProtocolUnreachNLRI) serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 { tempBuf := bytes.NewBuffer(nil) tempBuf.Write(convert.Uint16Byte(n.AFI)) tempBuf.WriteByte(n.SAFI) for _, pfx := range n.Prefixes { + if opt.UseAddPath { + tempBuf.Write(convert.Uint32Byte(n.PathID)) + } tempBuf.Write(serializePrefix(pfx)) } diff --git a/protocols/bgp/packet/mp_unreach_nlri_test.go b/protocols/bgp/packet/mp_unreach_nlri_test.go index 02e1b00fff6d161b37509e1748d20bd04dcb3d35..467b19e030dd208f5e1103d81465107f531591ec 100644 --- a/protocols/bgp/packet/mp_unreach_nlri_test.go +++ b/protocols/bgp/packet/mp_unreach_nlri_test.go @@ -13,6 +13,7 @@ func TestSerializeMultiProtocolUnreachNLRI(t *testing.T) { name string nlri MultiProtocolUnreachNLRI expected []byte + addPath bool }{ { name: "Simple IPv6 prefix", @@ -29,12 +30,32 @@ func TestSerializeMultiProtocolUnreachNLRI(t *testing.T) { 0x2c, 0x26, 0x20, 0x01, 0x10, 0x90, 0x00, // Prefix }, }, + { + name: "IPv6 prefix with ADD-PATH", + nlri: MultiProtocolUnreachNLRI{ + AFI: IPv6AFI, + SAFI: UnicastSAFI, + Prefixes: []bnet.Prefix{ + bnet.NewPfx(bnet.IPv6FromBlocks(0x2620, 0x110, 0x9000, 0, 0, 0, 0, 0), 44), + }, + PathID: 100, + }, + expected: []byte{ + 0x00, 0x02, // AFI + 0x01, // SAFI + 0x00, 0x00, 0x00, 100, // PathID + 0x2c, 0x26, 0x20, 0x01, 0x10, 0x90, 0x00, // Prefix + }, + addPath: true, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { buf := &bytes.Buffer{} - test.nlri.serialize(buf) + test.nlri.serialize(buf, &EncodeOptions{ + UseAddPath: test.addPath, + }) assert.Equal(t, test.expected, buf.Bytes()) }) } diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go index 22ea8a8c3e1c0ba253e98c87296a7bdde0b92f02..3f2f48e089ba6614b0a06234eb1cc3e4875e5ff5 100644 --- a/protocols/bgp/packet/path_attributes.go +++ b/protocols/bgp/packet/path_attributes.go @@ -11,7 +11,7 @@ import ( "github.com/taktv6/tflow2/convert" ) -func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *types.Options) (*PathAttribute, error) { +func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *DecodeOptions) (*PathAttribute, error) { var ret *PathAttribute var eol *PathAttribute var pa *PathAttribute @@ -38,7 +38,7 @@ func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *types.Options) (*PathA return ret, nil } -func decodePathAttr(buf *bytes.Buffer, opt *types.Options) (pa *PathAttribute, consumed uint16, err error) { +func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, consumed uint16, err error) { pa = &PathAttribute{} err = decodePathAttrFlags(buf, pa) @@ -66,7 +66,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *types.Options) (pa *PathAttribute, c } case ASPathAttr: asnLength := uint8(2) - if opt.Supports4OctetASN { + if opt.Use32BitASN { asnLength = 4 } @@ -445,7 +445,7 @@ func dumpNBytes(buf *bytes.Buffer, n uint16) error { } // Serialize serializes a path attribute -func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *types.Options) uint16 { +func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *EncodeOptions) uint16 { pathAttrLen := uint16(0) switch pa.TypeCode { @@ -468,9 +468,9 @@ func (pa *PathAttribute) Serialize(buf *bytes.Buffer, opt *types.Options) uint16 case LargeCommunitiesAttr: pathAttrLen = uint16(pa.serializeLargeCommunities(buf)) case MultiProtocolReachNLRICode: - pathAttrLen = pa.serializeMultiProtocolReachNLRI(buf) + pathAttrLen = pa.serializeMultiProtocolReachNLRI(buf, opt) case MultiProtocolUnreachNLRICode: - pathAttrLen = pa.serializeMultiProtocolUnreachNLRI(buf) + pathAttrLen = pa.serializeMultiProtocolUnreachNLRI(buf, opt) case OriginatorIDAttr: pathAttrLen = uint16(pa.serializeOriginatorID(buf)) case ClusterListAttr: @@ -493,14 +493,14 @@ func (pa *PathAttribute) serializeOrigin(buf *bytes.Buffer) uint8 { return 4 } -func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *types.Options) uint8 { +func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *EncodeOptions) uint8 { attrFlags := uint8(0) attrFlags = setTransitive(attrFlags) buf.WriteByte(attrFlags) buf.WriteByte(ASPathAttr) asnLength := uint8(2) - if opt.Supports4OctetASN { + if opt.Use32BitASN { asnLength = 4 } @@ -511,10 +511,10 @@ func (pa *PathAttribute) serializeASPath(buf *bytes.Buffer, opt *types.Options) segmentsBuf.WriteByte(uint8(len(segment.ASNs))) for _, asn := range segment.ASNs { - if asnLength == 2 { - segmentsBuf.Write(convert.Uint16Byte(uint16(asn))) - } else { + if opt.Use32BitASN { segmentsBuf.Write(convert.Uint32Byte(asn)) + } else { + segmentsBuf.Write(convert.Uint16Byte(uint16(asn))) } } length += 2 + uint8(len(segment.ASNs))*asnLength @@ -695,22 +695,22 @@ func (pa *PathAttribute) serializeUnknownAttribute(buf *bytes.Buffer) uint16 { return uint16(len(b) + 2) } -func (pa *PathAttribute) serializeMultiProtocolReachNLRI(buf *bytes.Buffer) uint16 { +func (pa *PathAttribute) serializeMultiProtocolReachNLRI(buf *bytes.Buffer, opt *EncodeOptions) uint16 { v := pa.Value.(MultiProtocolReachNLRI) pa.Optional = true tempBuf := bytes.NewBuffer(nil) - v.serialize(tempBuf) + v.serialize(tempBuf, opt) return pa.serializeGeneric(tempBuf.Bytes(), buf) } -func (pa *PathAttribute) serializeMultiProtocolUnreachNLRI(buf *bytes.Buffer) uint16 { +func (pa *PathAttribute) serializeMultiProtocolUnreachNLRI(buf *bytes.Buffer, opt *EncodeOptions) uint16 { v := pa.Value.(MultiProtocolUnreachNLRI) pa.Optional = true tempBuf := bytes.NewBuffer(nil) - v.serialize(tempBuf) + v.serialize(tempBuf, opt) return pa.serializeGeneric(tempBuf.Bytes(), buf) } diff --git a/protocols/bgp/packet/path_attributes_test.go b/protocols/bgp/packet/path_attributes_test.go index 762d604d885a3135c4aff72c874a8f8dbfc5c51f..958da99b783d20121e89fe4b85c4d213891bf550 100644 --- a/protocols/bgp/packet/path_attributes_test.go +++ b/protocols/bgp/packet/path_attributes_test.go @@ -52,7 +52,7 @@ func TestDecodePathAttrs(t *testing.T) { } for _, test := range tests { - res, err := decodePathAttrs(bytes.NewBuffer(test.input), uint16(len(test.input)), &types.Options{}) + res, err := decodePathAttrs(bytes.NewBuffer(test.input), uint16(len(test.input)), &DecodeOptions{}) if test.wantFail && err == nil { t.Errorf("Expected error did not happen for test %q", test.name) @@ -249,7 +249,7 @@ func TestDecodePathAttr(t *testing.T) { } for _, test := range tests { - res, _, err := decodePathAttr(bytes.NewBuffer(test.input), &types.Options{}) + res, _, err := decodePathAttr(bytes.NewBuffer(test.input), &DecodeOptions{}) if test.wantFail && err == nil { t.Errorf("Expected error did not happen for test %q", test.name) @@ -1577,8 +1577,8 @@ func TestSerializeASPath(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { buf := bytes.NewBuffer(nil) - opt := &types.Options{ - Supports4OctetASN: test.use32BitASN, + opt := &EncodeOptions{ + Use32BitASN: test.use32BitASN, } n := test.input.serializeASPath(buf, opt) if n != test.expectedLen { @@ -2081,10 +2081,7 @@ func TestSerialize(t *testing.T) { } for _, test := range tests { - opt := &types.Options{ - AddPathRX: false, - } - res, err := test.msg.SerializeUpdate(opt) + res, err := test.msg.SerializeUpdate(&EncodeOptions{}) if err != nil { if test.wantFail { continue @@ -2294,8 +2291,8 @@ func TestSerializeAddPath(t *testing.T) { } for _, test := range tests { - opt := &types.Options{ - AddPathRX: true, + opt := &EncodeOptions{ + UseAddPath: true, } res, err := test.msg.SerializeUpdate(opt) if err != nil { diff --git a/protocols/bgp/packet/update.go b/protocols/bgp/packet/update.go index 55b0cc0b9099076edbaef35fcfab1cfc83443330..167439ab06b77d669c5de258a252b5c2105794a6 100644 --- a/protocols/bgp/packet/update.go +++ b/protocols/bgp/packet/update.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" - "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/taktv6/tflow2/convert" ) @@ -17,14 +16,14 @@ type BGPUpdate struct { } // SerializeUpdate serializes an BGPUpdate to wire format -func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) { +func (b *BGPUpdate) SerializeUpdate(opt *EncodeOptions) ([]byte, error) { budget := MaxLen - MinLen nlriLen := 0 buf := bytes.NewBuffer(nil) withdrawBuf := bytes.NewBuffer(nil) for withdraw := b.WithdrawnRoutes; withdraw != nil; withdraw = withdraw.Next { - if opt.AddPathRX { + if opt.UseAddPath { nlriLen = int(withdraw.serializeAddPath(withdrawBuf)) } else { nlriLen = int(withdraw.serialize(withdrawBuf)) @@ -47,7 +46,7 @@ func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) { nlriBuf := bytes.NewBuffer(nil) for nlri := b.NLRI; nlri != nil; nlri = nlri.Next { - if opt.AddPathRX { + if opt.UseAddPath { nlriLen = int(nlri.serializeAddPath(nlriBuf)) } else { nlriLen = int(nlri.serialize(nlriBuf)) @@ -87,7 +86,7 @@ func (b *BGPUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) { return buf.Bytes(), nil } -func (b *BGPUpdate) SerializeUpdateAddPath(opt *types.Options) ([]byte, error) { +func (b *BGPUpdate) SerializeUpdateAddPath(opt *EncodeOptions) ([]byte, error) { budget := MaxLen - MinLen buf := bytes.NewBuffer(nil) diff --git a/protocols/bgp/server/BUILD.bazel b/protocols/bgp/server/BUILD.bazel index 78bdeb1f3635cabb3ead2855ae4431ee20a3c04c..bd45a72d0abd1f419175febf884094109f6eb982 100644 --- a/protocols/bgp/server/BUILD.bazel +++ b/protocols/bgp/server/BUILD.bazel @@ -21,7 +21,6 @@ go_library( "update_helper.go", "update_sender.go", "util.go", - "withdraw.go", ], importpath = "github.com/bio-routing/bio-rd/protocols/bgp/server", visibility = ["//visibility:public"], @@ -49,7 +48,6 @@ go_test( "server_test.go", "update_helper_test.go", "update_sender_test.go", - "withdraw_test.go", ], embed = [":go_default_library"], deps = [ diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go index 60eb417202135a54f1488f0fd10af620c997b2ec..c0697f1afc7686031b151055ba45a7c831761a3b 100644 --- a/protocols/bgp/server/fsm.go +++ b/protocols/bgp/server/fsm.go @@ -9,7 +9,6 @@ import ( "time" "github.com/bio-routing/bio-rd/protocols/bgp/packet" - "github.com/bio-routing/bio-rd/protocols/bgp/types" log "github.com/sirupsen/logrus" ) @@ -55,14 +54,14 @@ type FSM struct { msgRecvFailCh chan error stopMsgRecvCh chan struct{} - options *types.Options - local net.IP ribsInitialized bool ipv4Unicast *fsmAddressFamily ipv6Unicast *fsmAddressFamily + supports4OctetASN bool + neighborID uint32 state state stateMu sync.RWMutex @@ -99,7 +98,6 @@ func newFSM(peer *peer) *FSM { msgRecvCh: make(chan []byte), msgRecvFailCh: make(chan error), stopMsgRecvCh: make(chan struct{}), - options: &types.Options{}, } if peer.ipv4 != nil { @@ -113,6 +111,21 @@ func newFSM(peer *peer) *FSM { return f } +func (fsm *FSM) addressFamily(afi uint16, safi uint8) *fsmAddressFamily { + if safi != packet.UnicastSAFI { + return nil + } + + switch afi { + case packet.IPv4AFI: + return fsm.ipv4Unicast + case packet.IPv6AFI: + return fsm.ipv6Unicast + default: + return nil + } +} + func (fsm *FSM) start() { ctx, cancel := context.WithCancel(context.Background()) fsm.connectionCancelFunc = cancel @@ -228,6 +241,12 @@ func (fsm *FSM) msgReceiver() error { } } +func (fsm *FSM) decodeOptions() *packet.DecodeOptions { + return &packet.DecodeOptions{ + Use32BitASN: fsm.supports4OctetASN, + } +} + func (fsm *FSM) startConnectRetryTimer() { fsm.connectRetryTimer = time.NewTimer(fsm.connectRetryTime) } diff --git a/protocols/bgp/server/fsm_address_family.go b/protocols/bgp/server/fsm_address_family.go index f81f4d82905f3aeb9f60157cb2cad611859b18ec..092572c50463ff4109efa669f798e484d218e5ee 100644 --- a/protocols/bgp/server/fsm_address_family.go +++ b/protocols/bgp/server/fsm_address_family.go @@ -29,17 +29,25 @@ type fsmAddressFamily struct { updateSender *UpdateSender + addPathSend routingtable.ClientOptions + addPathTXConfigured bool + addPathTX bool + + multiProtocol bool + initialized bool } -func newFSMAddressFamily(afi uint16, safi uint8, params *familyParameters, fsm *FSM) *fsmAddressFamily { +func newFSMAddressFamily(afi uint16, safi uint8, family *peerAddressFamily, fsm *FSM) *fsmAddressFamily { return &fsmAddressFamily{ - afi: afi, - safi: safi, - fsm: fsm, - rib: params.rib, - importFilter: params.importFilter, - exportFilter: params.exportFilter, + afi: afi, + safi: safi, + fsm: fsm, + rib: family.rib, + importFilter: family.importFilter, + exportFilter: family.exportFilter, + addPathTXConfigured: family.addPathReceive, // at this point we switch from peers view to our view + addPathSend: family.addPathSend, } } @@ -50,18 +58,19 @@ func (f *fsmAddressFamily) init(n *routingtable.Neighbor) { contributingASNs.Add(f.fsm.peer.localASN) f.adjRIBIn.Register(f.rib) - f.adjRIBOut = adjRIBOut.New(n, f.exportFilter) - clientOptions := routingtable.ClientOptions{ - BestOnly: true, - } - if f.fsm.options.AddPathRX { - clientOptions = f.fsm.peer.addPathSend - } + f.adjRIBOut = adjRIBOut.New(n, f.exportFilter, f.addPathTX) f.updateSender = newUpdateSender(f.fsm, f.afi, f.safi) f.updateSender.Start(time.Millisecond * 5) f.adjRIBOut.Register(f.updateSender) + + clientOptions := routingtable.ClientOptions{ + BestOnly: true, + } + if f.addPathTX { + clientOptions = f.addPathSend + } f.rib.RegisterWithOptions(f.adjRIBOut, clientOptions) } @@ -87,19 +96,7 @@ func (f *fsmAddressFamily) processUpdate(u *packet.BGPUpdate) { return } - mp := false - switch f.afi { - case packet.IPv4AFI: - if f.fsm.options.MultiProtocolIPv4 { - mp = true - } - case packet.IPv6AFI: - if f.fsm.options.MultiProtocolIPv6 { - mp = true - } - } - - if mp { + if f.multiProtocol { f.multiProtocolUpdates(u) return } diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go index 246c7cbf6a9df6018c33fe135b2eae2fcf2e2ae2..c2e1f3a9576f6287029dff70dae09c6f73530198 100644 --- a/protocols/bgp/server/fsm_established.go +++ b/protocols/bgp/server/fsm_established.go @@ -30,6 +30,8 @@ func (s establishedState) run() (state, string) { } } + opt := s.fsm.decodeOptions() + for { select { case e := <-s.fsm.eventCh: @@ -48,7 +50,7 @@ func (s establishedState) run() (state, string) { case <-s.fsm.keepaliveTimer.C: return s.keepaliveTimerExpired() case recvMsg := <-s.fsm.msgRecvCh: - return s.msgReceived(recvMsg) + return s.msgReceived(recvMsg, opt) } } } @@ -74,7 +76,6 @@ func (s *establishedState) init() error { LocalASN: s.fsm.peer.localASN, RouteServerClient: s.fsm.peer.routeServerClient, LocalAddress: localAddr, - CapAddPathRX: s.fsm.options.AddPathRX, RouteReflectorClient: s.fsm.peer.routeReflectorClient, ClusterID: s.fsm.peer.clusterID, } @@ -148,8 +149,8 @@ func (s *establishedState) keepaliveTimerExpired() (state, string) { return newEstablishedState(s.fsm), s.fsm.reason } -func (s *establishedState) msgReceived(data []byte) (state, string) { - msg, err := packet.Decode(bytes.NewBuffer(data), s.fsm.options) +func (s *establishedState) msgReceived(data []byte, opt *packet.DecodeOptions) (state, string) { + msg, err := packet.Decode(bytes.NewBuffer(data), opt) if err != nil { switch bgperr := err.(type) { case packet.BGPError: diff --git a/protocols/bgp/server/fsm_open_confirm.go b/protocols/bgp/server/fsm_open_confirm.go index 07b8a6152dd64c56055c7cbd0745980e462c3886..17df63c1a3481b09f6b1671ce412d761e27cf240 100644 --- a/protocols/bgp/server/fsm_open_confirm.go +++ b/protocols/bgp/server/fsm_open_confirm.go @@ -18,6 +18,8 @@ func newOpenConfirmState(fsm *FSM) *openConfirmState { } func (s openConfirmState) run() (state, string) { + opt := s.fsm.decodeOptions() + for { select { case e := <-s.fsm.eventCh: @@ -34,7 +36,7 @@ func (s openConfirmState) run() (state, string) { case <-s.fsm.keepaliveTimer.C: return s.keepaliveTimerExpired() case recvMsg := <-s.fsm.msgRecvCh: - return s.msgReceived(recvMsg) + return s.msgReceived(recvMsg, opt) } } } @@ -81,8 +83,8 @@ func (s *openConfirmState) keepaliveTimerExpired() (state, string) { return newOpenConfirmState(s.fsm), s.fsm.reason } -func (s *openConfirmState) msgReceived(data []byte) (state, string) { - msg, err := packet.Decode(bytes.NewBuffer(data), s.fsm.options) +func (s *openConfirmState) msgReceived(data []byte, opt *packet.DecodeOptions) (state, string) { + msg, err := packet.Decode(bytes.NewBuffer(data), opt) if err != nil { switch bgperr := err.(type) { case packet.BGPError: diff --git a/protocols/bgp/server/fsm_open_sent.go b/protocols/bgp/server/fsm_open_sent.go index be9be952ff27b615f0d24f1ec8920198a1b813be..664e0d19399efd933fef5ee42330c7b5f2016a48 100644 --- a/protocols/bgp/server/fsm_open_sent.go +++ b/protocols/bgp/server/fsm_open_sent.go @@ -22,6 +22,9 @@ func newOpenSentState(fsm *FSM) *openSentState { func (s openSentState) run() (state, string) { go s.fsm.msgReceiver() + + opt := s.fsm.decodeOptions() + for { select { case e := <-s.fsm.eventCh: @@ -38,7 +41,7 @@ func (s openSentState) run() (state, string) { case <-s.fsm.holdTimer.C: return s.holdTimerExpired() case recvMsg := <-s.fsm.msgRecvCh: - return s.msgReceived(recvMsg) + return s.msgReceived(recvMsg, opt) } } } @@ -73,8 +76,8 @@ func (s *openSentState) holdTimerExpired() (state, string) { return newIdleState(s.fsm), "Holdtimer expired" } -func (s *openSentState) msgReceived(data []byte) (state, string) { - msg, err := packet.Decode(bytes.NewBuffer(data), s.fsm.options) +func (s *openSentState) msgReceived(data []byte, opt *packet.DecodeOptions) (state, string) { + msg, err := packet.Decode(bytes.NewBuffer(data), opt) if err != nil { switch bgperr := err.(type) { case packet.BGPError: @@ -175,47 +178,47 @@ func (s *openSentState) processCapability(cap packet.Capability) { } func (s *openSentState) processMultiProtocolCapability(cap packet.MultiProtocolCapability) { - if cap.SAFI != 0 { + if cap.SAFI != packet.UnicastSAFI { return } - switch cap.AFI { - case packet.IPv4AFI: - s.fsm.options.MultiProtocolIPv4 = true - case packet.IPv6AFI: - s.fsm.options.MultiProtocolIPv6 = true + f := s.fsm.addressFamily(cap.AFI, cap.SAFI) + if f != nil { + f.multiProtocol = true } } func (s *openSentState) processAddPathCapability(addPathCap packet.AddPathCapability) { - if addPathCap.AFI != 1 { + if addPathCap.SAFI != packet.UnicastSAFI { return } - if addPathCap.SAFI != 1 { + + f := s.fsm.addressFamily(addPathCap.AFI, addPathCap.SAFI) + if f == nil { return } switch addPathCap.SendReceive { case packet.AddPathReceive: - if !s.fsm.peer.addPathSend.BestOnly { - s.fsm.options.AddPathRX = true + if !f.addPathSend.BestOnly { + f.addPathTX = true } case packet.AddPathSend: - if s.fsm.peer.addPathRecv { - s.fsm.options.AddPathRX = true + if f.addPathTXConfigured { + f.addPathTX = true } case packet.AddPathSendReceive: - if !s.fsm.peer.addPathSend.BestOnly { - s.fsm.options.AddPathRX = true + if !f.addPathSend.BestOnly { + f.addPathTX = true } - if s.fsm.peer.addPathRecv { - s.fsm.options.AddPathRX = true + if f.addPathTXConfigured { + f.addPathTX = true } } } func (s *openSentState) processASN4Capability(cap packet.ASN4Capability) { - s.fsm.options.Supports4OctetASN = true + s.fsm.supports4OctetASN = true if s.peerASNRcvd == packet.ASTransASN { s.peerASNRcvd = cap.ASN4 diff --git a/protocols/bgp/server/fsm_test.go b/protocols/bgp/server/fsm_test.go index 5cddf8aee4663202b1ad716e59e922486dd45019..ba0e1429e41d4ccd4d65837142a8a7d456d6df6a 100644 --- a/protocols/bgp/server/fsm_test.go +++ b/protocols/bgp/server/fsm_test.go @@ -18,7 +18,7 @@ func TestFSM255UpdatesIPv4(t *testing.T) { fsmA := newFSM(&peer{ addr: bnet.IPv4FromOctets(169, 254, 100, 100), routerID: bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(), - ipv4: &familyParameters{ + ipv4: &peerAddressFamily{ rib: locRIB.New(), importFilter: filter.NewAcceptAllFilter(), exportFilter: filter.NewAcceptAllFilter(), @@ -132,14 +132,14 @@ func TestFSM255UpdatesIPv6(t *testing.T) { fsmA := newFSM(&peer{ addr: bnet.IPv6FromBlocks(0x2001, 0x678, 0x1e0, 0xffff, 0, 0, 0, 1), routerID: bnet.IPv4FromOctets(1, 1, 1, 1).ToUint32(), - ipv6: &familyParameters{ + ipv6: &peerAddressFamily{ rib: locRIB.New(), importFilter: filter.NewAcceptAllFilter(), exportFilter: filter.NewAcceptAllFilter(), }, }) - fsmA.options.MultiProtocolIPv6 = true + fsmA.ipv6Unicast.multiProtocol = true fsmA.holdTimer = time.NewTimer(time.Second * 90) fsmA.keepaliveTimer = time.NewTimer(time.Second * 30) fsmA.connectRetryTimer = time.NewTimer(time.Second * 120) diff --git a/protocols/bgp/server/peer.go b/protocols/bgp/server/peer.go index b70534b0898a2c3b3a68d4509e47e4ae17039a97..dd877d77f4eee02eb6a21578b9dbaf54a58336a9 100644 --- a/protocols/bgp/server/peer.go +++ b/protocols/bgp/server/peer.go @@ -30,8 +30,6 @@ type peer struct { fsmsMu sync.Mutex routerID uint32 - addPathSend routingtable.ClientOptions - addPathRecv bool reconnectInterval time.Duration keepaliveTime time.Duration holdTime time.Duration @@ -40,14 +38,18 @@ type peer struct { routeReflectorClient bool clusterID uint32 - ipv4 *familyParameters - ipv6 *familyParameters + ipv4 *peerAddressFamily + ipv6 *peerAddressFamily } -type familyParameters struct { - rib *locRIB.LocRIB +type peerAddressFamily struct { + rib *locRIB.LocRIB + importFilter *filter.Filter exportFilter *filter.Filter + + addPathSend routingtable.ClientOptions + addPathReceive bool } func (p *peer) snapshot() PeerInfo { @@ -130,8 +132,6 @@ func newPeer(c config.Peer, server *bgpServer) (*peer, error) { peerASN: c.PeerAS, localASN: c.LocalAS, fsms: make([]*FSM, 0), - addPathSend: c.AddPathSend, - addPathRecv: c.AddPathRecv, reconnectInterval: c.ReconnectInterval, keepaliveTime: c.KeepAlive, holdTime: c.HoldTime, @@ -142,10 +142,12 @@ func newPeer(c config.Peer, server *bgpServer) (*peer, error) { } if c.IPv4 != nil { - p.ipv4 = &familyParameters{ - rib: c.IPv4.RIB, - importFilter: filterOrDefault(c.IPv4.ImportFilter), - exportFilter: filterOrDefault(c.IPv4.ExportFilter), + p.ipv4 = &peerAddressFamily{ + rib: c.IPv4.RIB, + importFilter: filterOrDefault(c.IPv4.ImportFilter), + exportFilter: filterOrDefault(c.IPv4.ExportFilter), + addPathReceive: c.IPv4.AddPathRecv, + addPathSend: c.IPv4.AddPathSend, } } @@ -156,18 +158,17 @@ func newPeer(c config.Peer, server *bgpServer) (*peer, error) { caps := make(packet.Capabilities, 0) - addPathEnabled, addPathCap := handleAddPathCapability(c) - if addPathEnabled { - caps = append(caps, addPathCap) - } + caps = append(caps, addPathCapabilities(c)...) caps = append(caps, asn4Capability(c)) if c.IPv6 != nil { - p.ipv6 = &familyParameters{ - rib: c.IPv6.RIB, - importFilter: filterOrDefault(c.IPv6.ImportFilter), - exportFilter: filterOrDefault(c.IPv6.ExportFilter), + p.ipv6 = &peerAddressFamily{ + rib: c.IPv6.RIB, + importFilter: filterOrDefault(c.IPv6.ImportFilter), + exportFilter: filterOrDefault(c.IPv6.ExportFilter), + addPathReceive: c.IPv6.AddPathRecv, + addPathSend: c.IPv6.AddPathSend, } caps = append(caps, multiProtocolCapability(packet.IPv6AFI)) } @@ -201,12 +202,32 @@ func multiProtocolCapability(afi uint16) packet.Capability { } } -func handleAddPathCapability(c config.Peer) (bool, packet.Capability) { +func addPathCapabilities(c config.Peer) []packet.Capability { + caps := make([]packet.Capability, 0) + + enabled, cap := addPathCapabilityForFamily(c.IPv4, packet.IPv4AFI, packet.UnicastSAFI) + if enabled { + caps = append(caps, cap) + } + + enabled, cap = addPathCapabilityForFamily(c.IPv6, packet.IPv6AFI, packet.UnicastSAFI) + if enabled { + caps = append(caps, cap) + } + + return caps +} + +func addPathCapabilityForFamily(f *config.AddressFamilyConfig, afi uint16, safi uint8) (enabled bool, cap packet.Capability) { + if f == nil { + return false, packet.Capability{} + } + addPath := uint8(0) - if c.AddPathRecv { + if f.AddPathRecv { addPath += packet.AddPathReceive } - if !c.AddPathSend.BestOnly { + if !f.AddPathSend.BestOnly { addPath += packet.AddPathSend } @@ -217,8 +238,8 @@ func handleAddPathCapability(c config.Peer) (bool, packet.Capability) { return true, packet.Capability{ Code: packet.AddPathCapabilityCode, Value: packet.AddPathCapability{ - AFI: packet.IPv4AFI, - SAFI: packet.UnicastSAFI, + AFI: afi, + SAFI: safi, SendReceive: addPath, }, } diff --git a/protocols/bgp/server/server_test.go b/protocols/bgp/server/server_test.go index 2b4e8385204a411fed304e847c3c18c4c107cc7c..9d9248c4d8e1f574e3cc3f519d412de3bbf5140a 100644 --- a/protocols/bgp/server/server_test.go +++ b/protocols/bgp/server/server_test.go @@ -39,13 +39,13 @@ func TestBgpServerPeerSnapshot(t *testing.T) { KeepAlive: time.Second * 30, Passive: true, RouterID: s.RouterID(), - AddPathSend: routingtable.ClientOptions{ - MaxPaths: 10, - }, IPv4: &config.AddressFamilyConfig{ RIB: rib, ImportFilter: filter.NewDrainFilter(), ExportFilter: filter.NewAcceptAllFilter(), + AddPathSend: routingtable.ClientOptions{ + MaxPaths: 10, + }, }, } s.AddPeer(pc) diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go index 2cb82934a0a12d2f25243db2bc82cd60fca10e02..a510e54e98c10e8db673b1156c26e3de1cf19f24 100644 --- a/protocols/bgp/server/update_helper.go +++ b/protocols/bgp/server/update_helper.go @@ -4,11 +4,12 @@ import ( "fmt" "io" - "github.com/bio-routing/bio-rd/protocols/bgp/types" + "github.com/bio-routing/bio-rd/protocols/bgp/packet" + log "github.com/sirupsen/logrus" ) -func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *types.Options) error { +func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *packet.EncodeOptions) error { updateBytes, err := update.SerializeUpdate(opt) if err != nil { log.Errorf("Unable to serialize BGP Update: %v", err) @@ -23,5 +24,5 @@ func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *type } type serializeAbleUpdate interface { - SerializeUpdate(opt *types.Options) ([]byte, error) + SerializeUpdate(opt *packet.EncodeOptions) ([]byte, error) } diff --git a/protocols/bgp/server/update_helper_test.go b/protocols/bgp/server/update_helper_test.go index 6c599f18c965d55a9a611509ea10e2c5d5ffa35e..86a70f64d5626c4cbb38fb4eca5b793d7a548093 100644 --- a/protocols/bgp/server/update_helper_test.go +++ b/protocols/bgp/server/update_helper_test.go @@ -7,7 +7,6 @@ import ( "testing" "github.com/bio-routing/bio-rd/protocols/bgp/packet" - "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/net" "github.com/stretchr/testify/assert" @@ -15,7 +14,7 @@ import ( type failingUpdate struct{} -func (f *failingUpdate) SerializeUpdate(opt *types.Options) ([]byte, error) { +func (f *failingUpdate) SerializeUpdate(opt *packet.EncodeOptions) ([]byte, error) { return nil, errors.New("general error") } @@ -93,7 +92,7 @@ func TestSerializeAndSendUpdate(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - opt := &types.Options{} + opt := &packet.EncodeOptions{} err := serializeAndSendUpdate(test.buf, test.testUpdate, opt) assert.Equal(t, test.err, err) diff --git a/protocols/bgp/server/update_sender.go b/protocols/bgp/server/update_sender.go index ffcfae44d649c424731e0f7983961d7af5215a02..9e40303fc4e52aa36b3678026bf855be8992b931 100644 --- a/protocols/bgp/server/update_sender.go +++ b/protocols/bgp/server/update_sender.go @@ -1,7 +1,9 @@ package server import ( + "errors" "fmt" + "io" "sync" "time" @@ -16,14 +18,14 @@ import ( // UpdateSender converts table changes into BGP update messages type UpdateSender struct { routingtable.ClientManager - fsm *FSM - afi uint16 - safi uint8 - iBGP bool - rrClient bool - toSendMu sync.Mutex - toSend map[string]*pathPfxs - destroyCh chan struct{} + fsm *FSM + addressFamily *fsmAddressFamily + options *packet.EncodeOptions + iBGP bool + rrClient bool + toSendMu sync.Mutex + toSend map[string]*pathPfxs + destroyCh chan struct{} } type pathPfxs struct { @@ -32,14 +34,19 @@ type pathPfxs struct { } func newUpdateSender(fsm *FSM, afi uint16, safi uint8) *UpdateSender { + f := fsm.addressFamily(afi, safi) + return &UpdateSender{ - fsm: fsm, - afi: afi, - safi: safi, - iBGP: fsm.peer.localASN == fsm.peer.peerASN, - rrClient: fsm.peer.routeReflectorClient, - destroyCh: make(chan struct{}), - toSend: make(map[string]*pathPfxs), + fsm: fsm, + addressFamily: f, + iBGP: fsm.peer.localASN == fsm.peer.peerASN, + rrClient: fsm.peer.routeReflectorClient, + destroyCh: make(chan struct{}), + toSend: make(map[string]*pathPfxs), + options: &packet.EncodeOptions{ + Use32BitASN: fsm.supports4OctetASN, + UseAddPath: f.addPathTX, + }, } } @@ -107,6 +114,10 @@ func (u *UpdateSender) sender(aggrTime time.Duration) { for _, pfx := range pathNLRIs.pfxs { budget -= int(packet.BytesInAddr(pfx.Pfxlen())) + 1 + if u.options.UseAddPath { + budget -= 4 + } + if budget < 0 { updatesPrefixes = append(updatesPrefixes, prefixes) prefixes = make([]bnet.Prefix, 0, 1) @@ -130,12 +141,12 @@ func (u *UpdateSender) sender(aggrTime time.Duration) { } func (u *UpdateSender) updateOverhead() int { - if u.afi == packet.IPv4AFI && !u.fsm.options.MultiProtocolIPv4 { + if u.addressFamily.afi == packet.IPv4AFI && !u.addressFamily.multiProtocol { return 0 } addrLen := packet.IPv4AFI - if u.afi == packet.IPv6AFI { + if u.addressFamily.afi == packet.IPv6AFI { addrLen = packet.IPv6Len } @@ -152,7 +163,7 @@ func (u *UpdateSender) sendUpdates(pathAttrs *packet.PathAttribute, updatePrefix return } - err = serializeAndSendUpdate(u.fsm.con, update, u.fsm.options) + err = serializeAndSendUpdate(u.fsm.con, update, u.options) if err != nil { log.Errorf("Failed to serialize and send: %v", err) } @@ -160,18 +171,14 @@ func (u *UpdateSender) sendUpdates(pathAttrs *packet.PathAttribute, updatePrefix } func (u *UpdateSender) updateMessageForPrefixes(pfxs []bnet.Prefix, pa *packet.PathAttribute, pathID uint32) *packet.BGPUpdate { - switch u.afi { - case packet.IPv4AFI: - if u.fsm.options.MultiProtocolIPv4 { - return u.bgpUpdateMultiProtocol(pfxs, pa, pathID) - } + if u.addressFamily.afi == packet.IPv4AFI && !u.addressFamily.multiProtocol { return u.bgpUpdate(pfxs, pa, pathID) - case packet.IPv6AFI: - if u.fsm.options.MultiProtocolIPv6 { - return u.bgpUpdateMultiProtocol(pfxs, pa, pathID) - } - return nil } + + if u.addressFamily.multiProtocol { + return u.bgpUpdateMultiProtocol(pfxs, pa, pathID) + } + return nil } @@ -200,10 +207,11 @@ func (u *UpdateSender) bgpUpdateMultiProtocol(pfxs []bnet.Prefix, pa *packet.Pat attrs := &packet.PathAttribute{ TypeCode: packet.MultiProtocolReachNLRICode, Value: packet.MultiProtocolReachNLRI{ - AFI: u.afi, - SAFI: u.safi, + AFI: u.addressFamily.afi, + SAFI: u.addressFamily.safi, NextHop: nextHop, Prefixes: pfxs, + PathID: pathID, }, } attrs.Next = pa @@ -235,40 +243,66 @@ func (u *UpdateSender) copyAttributesWithoutNextHop(pa *packet.PathAttribute) (a // RemovePath withdraws prefix `pfx` from a peer func (u *UpdateSender) RemovePath(pfx bnet.Prefix, p *route.Path) bool { - err := u.withdrawPrefix(pfx, p) + err := u.withdrawPrefix(u.fsm.con, pfx, p) if err != nil { log.Errorf("Unable to withdraw prefix: %v", err) return false } + return true } -func (u *UpdateSender) withdrawPrefix(pfx bnet.Prefix, p *route.Path) error { - if u.afi == packet.IPv4AFI { - return u.withdrawPrefixIPv4(pfx, p) +func (u *UpdateSender) withdrawPrefix(out io.Writer, pfx bnet.Prefix, p *route.Path) error { + if p.Type != route.BGPPathType { + return errors.New("wrong path type, expected BGPPathType") } - if u.afi == packet.IPv6AFI { - return u.withdrawPrefixIPv6(pfx, p) + if p.BGPPath == nil { + return errors.New("got nil BGPPath") } - return fmt.Errorf("Unsupported AFI: %v", u.afi) + if u.addressFamily.afi == packet.IPv4AFI && !u.addressFamily.multiProtocol { + return u.withdrawPrefixIPv4(out, pfx, p) + } + + if !u.addressFamily.multiProtocol { + return fmt.Errorf(packet.AFIName(u.addressFamily.afi) + " was not negotiated") + } + + return u.withdrawPrefixMultiProtocol(out, pfx, p) } -func (u *UpdateSender) withdrawPrefixIPv4(pfx bnet.Prefix, p *route.Path) error { - if u.fsm.options.MultiProtocolIPv4 { - return withdrawPrefixesMultiProtocol(u.fsm.con, u.fsm.options, pfx, u.afi, u.safi) +func (u *UpdateSender) withdrawPrefixIPv4(out io.Writer, pfx bnet.Prefix, p *route.Path) error { + update := &packet.BGPUpdate{ + WithdrawnRoutes: &packet.NLRI{ + PathIdentifier: p.BGPPath.PathIdentifier, + IP: pfx.Addr().ToUint32(), + Pfxlen: pfx.Pfxlen(), + }, } - return withdrawPrefixesAddPath(u.fsm.con, u.fsm.options, pfx, p) + return serializeAndSendUpdate(out, update, u.options) } -func (u *UpdateSender) withdrawPrefixIPv6(pfx bnet.Prefix, p *route.Path) error { - if !u.fsm.options.MultiProtocolIPv6 { - return fmt.Errorf("IPv6 was not negotiated") +func (u *UpdateSender) withdrawPrefixMultiProtocol(out io.Writer, pfx bnet.Prefix, p *route.Path) error { + pathID := uint32(0) + if p.BGPPath != nil { + pathID = p.BGPPath.PathIdentifier + } + + update := &packet.BGPUpdate{ + PathAttributes: &packet.PathAttribute{ + TypeCode: packet.MultiProtocolUnreachNLRICode, + Value: packet.MultiProtocolUnreachNLRI{ + AFI: u.addressFamily.afi, + SAFI: u.addressFamily.safi, + Prefixes: []bnet.Prefix{pfx}, + PathID: pathID, + }, + }, } - return withdrawPrefixesAddPath(u.fsm.con, u.fsm.options, pfx, p) + return serializeAndSendUpdate(out, update, u.options) } // UpdateNewClient does nothing diff --git a/protocols/bgp/server/update_sender_test.go b/protocols/bgp/server/update_sender_test.go index 6085dd8f4441f05ee7ebe7b803700a28ac9261fc..4b6ae30722018a287f86aaa046d30252008bd944 100644 --- a/protocols/bgp/server/update_sender_test.go +++ b/protocols/bgp/server/update_sender_test.go @@ -1,6 +1,8 @@ package server import ( + "bytes" + "errors" "reflect" "testing" "time" @@ -10,7 +12,6 @@ import ( "github.com/stretchr/testify/assert" bnet "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/protocols/bgp/types" "github.com/bio-routing/bio-rd/route" "github.com/bio-routing/bio-rd/routingtable/filter" "github.com/bio-routing/bio-rd/routingtable/locRIB" @@ -873,18 +874,20 @@ func TestSender(t *testing.T) { rib := locRIB.New() if test.afi == packet.IPv6AFI { - fsmA.options.MultiProtocolIPv6 = true - fsmA.ipv6Unicast = newFSMAddressFamily(packet.IPv6AFI, packet.UnicastSAFI, &familyParameters{ + fsmA.ipv6Unicast = newFSMAddressFamily(packet.IPv6AFI, packet.UnicastSAFI, &peerAddressFamily{ rib: rib, importFilter: filter.NewAcceptAllFilter(), exportFilter: filter.NewAcceptAllFilter(), }, fsmA) + fsmA.ipv6Unicast.multiProtocol = true + fsmA.ipv6Unicast.addPathTX = test.addPath } else { - fsmA.ipv4Unicast = newFSMAddressFamily(packet.IPv4AFI, packet.UnicastSAFI, &familyParameters{ + fsmA.ipv4Unicast = newFSMAddressFamily(packet.IPv4AFI, packet.UnicastSAFI, &peerAddressFamily{ rib: rib, importFilter: filter.NewAcceptAllFilter(), exportFilter: filter.NewAcceptAllFilter(), }, fsmA) + fsmA.ipv4Unicast.addPathTX = test.addPath } fsmA.holdTimer = time.NewTimer(time.Second * 90) @@ -893,12 +896,6 @@ func TestSender(t *testing.T) { fsmA.state = newEstablishedState(fsmA) fsmA.con = btest.NewMockConn() - if test.addPath { - fsmA.options = &types.Options{ - AddPathRX: true, - } - } - updateSender := newUpdateSender(fsmA, test.afi, packet.UnicastSAFI) for _, pathPfx := range test.paths { @@ -945,3 +942,179 @@ func TestSender(t *testing.T) { } } } + +func TestWithdrawPrefix(t *testing.T) { + testcases := []struct { + name string + addPathTX bool + afi uint16 + multiProtocol bool + prefix bnet.Prefix + path *route.Path + expected []byte + expectedError error + }{ + { + name: "Non bgp withdraw with ADD-PATH", + afi: packet.IPv4AFI, + multiProtocol: false, + addPathTX: true, + prefix: bnet.NewPfx(bnet.IPv4(1413010532), 24), + path: &route.Path{ + Type: route.StaticPathType, + }, + expected: []byte{}, + expectedError: errors.New("wrong path type, expected BGPPathType"), + }, + { + name: "Nil BGPPathType with ADD-PATH", + afi: packet.IPv4AFI, + multiProtocol: false, + addPathTX: true, + prefix: bnet.NewPfx(bnet.IPv4(1413010532), 24), + path: &route.Path{ + Type: route.BGPPathType, + }, + expected: []byte{}, + expectedError: errors.New("got nil BGPPath"), + }, + { + name: "Normal withdraw with ADD-PATH", + afi: packet.IPv4AFI, + multiProtocol: false, + addPathTX: true, + prefix: bnet.NewPfx(bnet.IPv4(1413010532), 24), + path: &route.Path{ + Type: route.BGPPathType, + BGPPath: &route.BGPPath{ + PathIdentifier: 1, + }, + }, + expected: []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker + 0x00, 0x1f, // BGP Message Length + 0x02, // BGP Message Type == Update + 0x00, 0x08, // WithDraw Octet length + 0x00, 0x00, 0x00, 0x01, // NLRI Path Identifier + 0x18, // Prefix Length + 0x54, 0x38, 0xd4, // Prefix, + 0x00, 0x00, // Total Path Attribute Length + }, + expectedError: nil, + }, + { + name: "Normal withdraw without ADD-PATH", + afi: packet.IPv4AFI, + multiProtocol: false, + addPathTX: false, + prefix: bnet.NewPfx(bnet.IPv4(1413010532), 24), + path: &route.Path{ + Type: route.BGPPathType, + BGPPath: &route.BGPPath{ + PathIdentifier: 1, + }, + }, + expected: []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker + 0x00, 0x1b, // BGP Message Length + 0x02, // BGP Message Type == Update + 0x00, 0x04, // WithDraw Octet length + 0x18, // Prefix Length + 0x54, 0x38, 0xd4, // Prefix, + 0x00, 0x00, // Total Path Attribute Length + }, + expectedError: nil, + }, + { + name: "IPv6 MP_UNREACH_NLRI", + afi: packet.IPv6AFI, + multiProtocol: true, + addPathTX: false, + prefix: bnet.NewPfx(bnet.IPv6FromBlocks(0x2804, 0x148c, 0, 0, 0, 0, 0, 0), 32), + path: &route.Path{ + Type: route.BGPPathType, + BGPPath: &route.BGPPath{}, + }, + expected: []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker + 0x00, 0x22, // BGP Message Length + 0x02, // BGP Message Type == Update + 0x00, 0x00, // WithDraw Octet length + 0x00, 0x0b, // Length + 0x80, // Flags + 0x0f, // Attribute Code + 0x08, // Attribute length + 0x00, 0x02, // AFI + 0x01, // SAFI + 0x20, 0x28, 0x04, 0x14, 0x8c, // Prefix + }, + }, + { + name: "IPv6 MP_UNREACH_NLRI with ADD-PATH", + afi: packet.IPv6AFI, + multiProtocol: true, + addPathTX: true, + prefix: bnet.NewPfx(bnet.IPv6FromBlocks(0x2804, 0x148c, 0, 0, 0, 0, 0, 0), 32), + path: &route.Path{ + Type: route.BGPPathType, + BGPPath: &route.BGPPath{ + PathIdentifier: 100, + }, + }, + expected: []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker + 0x00, 0x26, // BGP Message Length + 0x02, // BGP Message Type == Update + 0x00, 0x00, // WithDraw Octet length + 0x00, 0x0f, // Length + 0x80, // Flags + 0x0f, // Attribute Code + 0x0c, // Attribute length + 0x00, 0x02, // AFI + 0x01, // SAFI + 0x00, 0x00, 0x00, 100, // Path Identifier + 0x20, 0x28, 0x04, 0x14, 0x8c, // Prefix + }, + }, + { + name: "IPv6 MP_UNREACH_NLRI without multi protocol beeing negotiated", + afi: packet.IPv6AFI, + multiProtocol: false, + addPathTX: false, + prefix: bnet.NewPfx(bnet.IPv6FromBlocks(0x2804, 0x148c, 0, 0, 0, 0, 0, 0), 32), + path: &route.Path{ + Type: route.BGPPathType, + BGPPath: &route.BGPPath{ + PathIdentifier: 1, + }, + }, + expected: []byte{}, + expectedError: errors.New("IPv6 was not negotiated"), + }, + } + + t.Parallel() + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + buf := bytes.NewBuffer([]byte{}) + + u := &UpdateSender{ + fsm: &FSM{}, + addressFamily: &fsmAddressFamily{ + addPathTX: tc.addPathTX, + multiProtocol: tc.multiProtocol, + afi: tc.afi, + safi: packet.UnicastSAFI, + }, + options: &packet.EncodeOptions{ + UseAddPath: tc.addPathTX, + }, + } + + err := u.withdrawPrefix(buf, tc.prefix, tc.path) + assert.Equal(t, tc.expectedError, err, "error mismatch") + assert.Equal(t, tc.expected, buf.Bytes(), "expected different bytes") + }) + } +} diff --git a/protocols/bgp/server/withdraw.go b/protocols/bgp/server/withdraw.go deleted file mode 100644 index 842d50f5497a31ff6562342f0f31eed79b5c32aa..0000000000000000000000000000000000000000 --- a/protocols/bgp/server/withdraw.go +++ /dev/null @@ -1,75 +0,0 @@ -package server - -import ( - "errors" - "io" - - "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" - "github.com/bio-routing/bio-rd/protocols/bgp/types" - "github.com/bio-routing/bio-rd/route" -) - -// withdrawPrefixes generates a BGPUpdate message and write it to the given -// io.Writer. -func withdrawPrefixes(out io.Writer, opt *types.Options, prefixes ...net.Prefix) error { - if len(prefixes) < 1 { - return nil - } - var rootNLRI *packet.NLRI - var currentNLRI *packet.NLRI - for _, pfx := range prefixes { - if rootNLRI == nil { - rootNLRI = &packet.NLRI{ - IP: pfx.Addr().ToUint32(), - Pfxlen: pfx.Pfxlen(), - } - currentNLRI = rootNLRI - } else { - currentNLRI.Next = &packet.NLRI{ - IP: pfx.Addr().ToUint32(), - Pfxlen: pfx.Pfxlen(), - } - currentNLRI = currentNLRI.Next - } - } - update := &packet.BGPUpdate{ - WithdrawnRoutes: rootNLRI, - } - return serializeAndSendUpdate(out, update, opt) - -} - -// withdrawPrefixesAddPath generates a BGPUpdateAddPath message and write it to the given -// io.Writer. -func withdrawPrefixesAddPath(out io.Writer, opt *types.Options, pfx net.Prefix, p *route.Path) error { - if p.Type != route.BGPPathType { - return errors.New("wrong path type, expected BGPPathType") - } - if p.BGPPath == nil { - return errors.New("got nil BGPPath") - } - update := &packet.BGPUpdate{ - WithdrawnRoutes: &packet.NLRI{ - PathIdentifier: p.BGPPath.PathIdentifier, - IP: pfx.Addr().ToUint32(), - Pfxlen: pfx.Pfxlen(), - }, - } - return serializeAndSendUpdate(out, update, opt) -} - -func withdrawPrefixesMultiProtocol(out io.Writer, opt *types.Options, pfx net.Prefix, afi uint16, safi uint8) error { - update := &packet.BGPUpdate{ - PathAttributes: &packet.PathAttribute{ - TypeCode: packet.MultiProtocolUnreachNLRICode, - Value: packet.MultiProtocolUnreachNLRI{ - AFI: afi, - SAFI: safi, - Prefixes: []net.Prefix{pfx}, - }, - }, - } - - return serializeAndSendUpdate(out, update, opt) -} diff --git a/protocols/bgp/server/withdraw_test.go b/protocols/bgp/server/withdraw_test.go deleted file mode 100644 index b379e2a00bf106fe8ff86c4866a351a2ddae8968..0000000000000000000000000000000000000000 --- a/protocols/bgp/server/withdraw_test.go +++ /dev/null @@ -1,160 +0,0 @@ -package server - -import ( - "bytes" - "errors" - "testing" - - "github.com/bio-routing/bio-rd/net" - "github.com/bio-routing/bio-rd/protocols/bgp/packet" - "github.com/bio-routing/bio-rd/protocols/bgp/types" - "github.com/bio-routing/bio-rd/route" - - "github.com/stretchr/testify/assert" -) - -func TestWithdrawPrefixes(t *testing.T) { - testcases := []struct { - Name string - Prefix []net.Prefix - Expected []byte - ExpectedError error - }{ - { - Name: "One withdraw", - Prefix: []net.Prefix{net.NewPfx(net.IPv4(1413010532), 24)}, - Expected: []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker - 0x00, 0x1b, // BGP Message Length - 0x02, // BGP Message Type == Update - 0x00, 0x04, // WithDraw Octet length - 0x18, // Prefix Length - 0x54, 0x38, 0xd4, // Prefix, - 0x00, 0x00, // Total Path Attribute Length - }, - ExpectedError: nil, - }, - { - Name: "two withdraws", - Prefix: []net.Prefix{net.NewPfx(net.IPv4(1413010532), 24), net.NewPfx(net.IPv4(1413010534), 25)}, - Expected: []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker - 0x00, 0x20, // BGP Message Length - 0x02, // BGP Message Type == Update - 0x00, 0x09, // WithDraw Octet length - 0x18, // Prefix Length first - 0x54, 0x38, 0xd4, // Prefix, - 0x19, // Prefix Length second - 0x54, 0x38, 0xd4, 0x66, // Prefix, - 0x00, 0x00, // Total Path Attribute Length - }, - ExpectedError: nil, - }, - } - for _, tc := range testcases { - buf := bytes.NewBuffer([]byte{}) - opt := &types.Options{} - err := withdrawPrefixes(buf, opt, tc.Prefix...) - assert.Equal(t, tc.ExpectedError, err, "error mismatch in testcase %v", tc.Name) - assert.Equal(t, tc.Expected, buf.Bytes(), "expected different bytes in testcase %v", tc.Name) - } -} - -func TestWithDrawPrefixesMultiProtocol(t *testing.T) { - tests := []struct { - Name string - Prefix net.Prefix - Expected []byte - }{ - { - Name: "IPv6 MP_UNREACH_NLRI", - Prefix: net.NewPfx(net.IPv6FromBlocks(0x2804, 0x148c, 0, 0, 0, 0, 0, 0), 32), - Expected: []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker - 0x00, 0x22, // BGP Message Length - 0x02, // BGP Message Type == Update - 0x00, 0x00, // WithDraw Octet length - 0x00, 0x0b, // Length - 0x80, // Flags - 0x0f, // Attribute Code - 0x08, // Attribute length - 0x00, 0x02, // AFI - 0x01, // SAFI - 0x20, 0x28, 0x04, 0x14, 0x8c, // Prefix - }, - }, - } - for _, test := range tests { - t.Run(test.Name, func(t *testing.T) { - buf := bytes.NewBuffer([]byte{}) - opt := &types.Options{ - AddPathRX: false, - } - err := withdrawPrefixesMultiProtocol(buf, opt, test.Prefix, packet.IPv6AFI, packet.UnicastSAFI) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - assert.Equal(t, test.Expected, buf.Bytes()) - }) - } -} - -func TestWithDrawPrefixesAddPath(t *testing.T) { - testcases := []struct { - Name string - Prefix net.Prefix - Path *route.Path - Expected []byte - ExpectedError error - }{ - { - Name: "Normal withdraw", - Prefix: net.NewPfx(net.IPv4(1413010532), 24), - Path: &route.Path{ - Type: route.BGPPathType, - BGPPath: &route.BGPPath{ - PathIdentifier: 1, - }, - }, - Expected: []byte{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // BGP Marker - 0x00, 0x1f, // BGP Message Length - 0x02, // BGP Message Type == Update - 0x00, 0x08, // WithDraw Octet length - 0x00, 0x00, 0x00, 0x01, // NLRI Path Identifier - 0x18, // Prefix Length - 0x54, 0x38, 0xd4, // Prefix, - 0x00, 0x00, // Total Path Attribute Length - }, - ExpectedError: nil, - }, - { - Name: "Non bgp withdraw", - Prefix: net.NewPfx(net.IPv4(1413010532), 24), - Path: &route.Path{ - Type: route.StaticPathType, - }, - Expected: []byte{}, - ExpectedError: errors.New("wrong path type, expected BGPPathType"), - }, - { - Name: "Nil BGPPathType", - Prefix: net.NewPfx(net.IPv4(1413010532), 24), - Path: &route.Path{ - Type: route.BGPPathType, - }, - Expected: []byte{}, - ExpectedError: errors.New("got nil BGPPath"), - }, - } - for _, tc := range testcases { - buf := bytes.NewBuffer([]byte{}) - opt := &types.Options{ - AddPathRX: true, - } - err := withdrawPrefixesAddPath(buf, opt, tc.Prefix, tc.Path) - assert.Equal(t, tc.ExpectedError, err, "error mismatch in testcase %v", tc.Name) - assert.Equal(t, tc.Expected, buf.Bytes(), "expected different bytes in testcase %v", tc.Name) - } -} diff --git a/protocols/bgp/types/BUILD.bazel b/protocols/bgp/types/BUILD.bazel index 5f94662087b2e46f593e4386d2bac21e65896225..50a86ef428ad5e92ffbb6365f30e566c0267873b 100644 --- a/protocols/bgp/types/BUILD.bazel +++ b/protocols/bgp/types/BUILD.bazel @@ -7,7 +7,6 @@ go_library( "as_path.go", "community.go", "large_community.go", - "options.go", "unknown_attribute.go", ], importpath = "github.com/bio-routing/bio-rd/protocols/bgp/types", diff --git a/protocols/bgp/types/options.go b/protocols/bgp/types/options.go deleted file mode 100644 index 5bc87827dc6faff3948b0ec817d8151bdbc34d03..0000000000000000000000000000000000000000 --- a/protocols/bgp/types/options.go +++ /dev/null @@ -1,9 +0,0 @@ -package types - -// Options represents options to the update sender, decoder and encoder -type Options struct { - Supports4OctetASN bool - AddPathRX bool - MultiProtocolIPv4 bool - MultiProtocolIPv6 bool -} diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go index b4271ea3c82734d6dd8f5e8dae7f2fb48db34c4b..a93a5cfe44ab570ce41873b7b6ad416dbd9fb8c3 100644 --- a/routingtable/adjRIBOut/adj_rib_out.go +++ b/routingtable/adjRIBOut/adj_rib_out.go @@ -17,18 +17,20 @@ type AdjRIBOut struct { routingtable.ClientManager rt *routingtable.RoutingTable neighbor *routingtable.Neighbor + addPathTX bool pathIDManager *pathIDManager - mu sync.RWMutex exportFilter *filter.Filter + mu sync.RWMutex } // New creates a new Adjacency RIB Out with BGP add path -func New(neighbor *routingtable.Neighbor, exportFilter *filter.Filter) *AdjRIBOut { +func New(neighbor *routingtable.Neighbor, exportFilter *filter.Filter, addPathTX bool) *AdjRIBOut { a := &AdjRIBOut{ rt: routingtable.NewRoutingTable(), neighbor: neighbor, pathIDManager: newPathIDManager(), exportFilter: exportFilter, + addPathTX: addPathTX, } a.ClientManager = routingtable.NewClientManager(a) return a @@ -47,7 +49,7 @@ func (a *AdjRIBOut) RouteCount() int64 { // AddPath adds path p to prefix `pfx` func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error { if !routingtable.ShouldPropagateUpdate(pfx, p, a.neighbor) { - if a.neighbor.CapAddPathRX { + if a.addPathTX { a.removePathsForPrefix(pfx) } return nil @@ -94,8 +96,7 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error { a.mu.Lock() defer a.mu.Unlock() - // AddPathRX capable neighbor - if a.neighbor.CapAddPathRX { + if a.addPathTX { pathID, err := a.pathIDManager.addPath(p) if err != nil { return fmt.Errorf("Unable to get path ID: %v", err) @@ -140,7 +141,7 @@ func (a *AdjRIBOut) RemovePath(pfx bnet.Prefix, p *route.Path) bool { a.rt.RemovePath(pfx, p) // If the neighbar has AddPath capabilities, try to find the PathID - if a.neighbor.CapAddPathRX { + if a.addPathTX { pathID, err := a.pathIDManager.releasePath(p) if err != nil { log.Warningf("Unable to release path for prefix %s: %v", pfx.String(), err) diff --git a/routingtable/adjRIBOut/adj_rib_out_test.go b/routingtable/adjRIBOut/adj_rib_out_test.go index 26eceeeed34b37d62303a9156f9074ba28411129..51465849d2e14bfb17086cbff14561c4f8b7eefe 100644 --- a/routingtable/adjRIBOut/adj_rib_out_test.go +++ b/routingtable/adjRIBOut/adj_rib_out_test.go @@ -22,10 +22,9 @@ func TestBestPathOnlyEBGP(t *testing.T) { IBGP: false, LocalASN: 41981, RouteServerClient: false, - CapAddPathRX: false, } - adjRIBOut := New(neighborBestOnlyEBGP, filter.NewAcceptAllFilter()) + adjRIBOut := New(neighborBestOnlyEBGP, filter.NewAcceptAllFilter(), false) tests := []struct { name string @@ -329,10 +328,9 @@ func TestBestPathOnlyIBGP(t *testing.T) { IBGP: true, LocalASN: 41981, RouteServerClient: false, - CapAddPathRX: false, } - adjRIBOut := New(neighborBestOnlyEBGP, filter.NewAcceptAllFilter()) + adjRIBOut := New(neighborBestOnlyEBGP, filter.NewAcceptAllFilter(), false) tests := []struct { name string @@ -544,12 +542,11 @@ func TestBestPathOnlyRRClient(t *testing.T) { IBGP: true, LocalASN: 41981, RouteServerClient: false, - CapAddPathRX: false, RouteReflectorClient: true, ClusterID: net.IPv4FromOctets(2, 2, 2, 2).ToUint32(), } - adjRIBOut := New(neighborBestOnlyRR, filter.NewAcceptAllFilter()) + adjRIBOut := New(neighborBestOnlyRR, filter.NewAcceptAllFilter(), false) tests := []struct { name string @@ -875,10 +872,9 @@ func TestAddPathIBGP(t *testing.T) { IBGP: true, LocalASN: 41981, RouteServerClient: false, - CapAddPathRX: true, } - adjRIBOut := New(neighborBestOnlyEBGP, filter.NewAcceptAllFilter()) + adjRIBOut := New(neighborBestOnlyEBGP, filter.NewAcceptAllFilter(), true) tests := []struct { name string diff --git a/routingtable/neighbor.go b/routingtable/neighbor.go index 8b320636806792a2091cdc3cb4556c1b55a842bc..b72c7a193bbf5f0867ea573aa0e0d0f94e319aab 100644 --- a/routingtable/neighbor.go +++ b/routingtable/neighbor.go @@ -27,7 +27,4 @@ type Neighbor struct { // ClusterID is our route reflectors clusterID ClusterID uint32 - - // CapAddPathRX indicates if the peer supports receiving multiple BGP paths - CapAddPathRX bool }