diff --git a/glide.lock b/glide.lock index 2e00457538..e5ddad4d3a 100644 --- a/glide.lock +++ b/glide.lock @@ -1,5 +1,5 @@ -hash: aa4807befbaa3fa5d489feed6ecaca17a92edb6761f7a3aebfbb053f1c636754 -updated: 2017-07-12T21:49:20.87386587-05:00 +hash: addbb83ea36694c5fd610831309d4791ab9493be88a8b650aa0bc921dc4b3c32 +updated: 2017-07-14T02:15:33.292128568+05:30 imports: - name: github.com/armon/go-radix version: 4239b77079c7b5d1243b7b4736304ce8ddb6f0f2 @@ -125,7 +125,7 @@ imports: - name: github.com/opencontainers/go-digest version: 279bed98673dd5bef374d3b6e4b09e2af76183bf - name: github.com/osrg/gobgp - version: 9f9a71eab2bc9f2fed0d7c32a05f74d4c42b12ae + version: 4b5e13376c70481aacc1c2c508738279f8cc9e5c subpackages: - api - config @@ -147,7 +147,7 @@ imports: - name: github.com/satori/go.uuid version: 5bf94b69c6b68ee1b541973bb8e1144db23a194b - name: github.com/sirupsen/logrus - version: 1fe8319fcaef78ef9220c9b05178df0f871dbc5d + version: 51dc0fc64317a2861273909081f9c315786533eb - name: github.com/spf13/afero version: 9be650865eab0c12963d8753212f4f9c66cdcf12 subpackages: diff --git a/glide.yaml b/glide.yaml index fdf513aec2..c46197e198 100644 --- a/glide.yaml +++ b/glide.yaml @@ -15,7 +15,7 @@ import: - package: github.com/mqliang/libipvs version: master - package: github.com/osrg/gobgp - version: ^1.17.0 + version: master subpackages: - api - config diff --git a/vendor/github.com/osrg/gobgp/.travis.yml b/vendor/github.com/osrg/gobgp/.travis.yml index 2814e5b06b..17a91b876b 100644 --- a/vendor/github.com/osrg/gobgp/.travis.yml +++ b/vendor/github.com/osrg/gobgp/.travis.yml @@ -173,6 +173,11 @@ matrix: sudo: required services: - docker + - env: + - TEST=addpath_test.py + sudo: required + services: + - docker cache: pip: true diff --git a/vendor/github.com/osrg/gobgp/api/gobgp.pb.go b/vendor/github.com/osrg/gobgp/api/gobgp.pb.go index 162e5d42dc..10bdebdef2 100644 --- a/vendor/github.com/osrg/gobgp/api/gobgp.pb.go +++ b/vendor/github.com/osrg/gobgp/api/gobgp.pb.go @@ -2182,6 +2182,7 @@ type Path struct { NeighborIp string `protobuf:"bytes,14,opt,name=neighbor_ip,json=neighborIp" json:"neighbor_ip,omitempty"` Uuid []byte `protobuf:"bytes,15,opt,name=uuid,proto3" json:"uuid,omitempty"` IsNexthopInvalid bool `protobuf:"varint,16,opt,name=is_nexthop_invalid,json=isNexthopInvalid" json:"is_nexthop_invalid,omitempty"` + Identifier uint32 `protobuf:"varint,17,opt,name=identifier" json:"identifier,omitempty"` } func (m *Path) Reset() { *m = Path{} } @@ -2301,6 +2302,13 @@ func (m *Path) GetIsNexthopInvalid() bool { return false } +func (m *Path) GetIdentifier() uint32 { + if m != nil { + return m.Identifier + } + return 0 +} + type Destination struct { Prefix string `protobuf:"bytes,1,opt,name=prefix" json:"prefix,omitempty"` Paths []*Path `protobuf:"bytes,2,rep,name=paths" json:"paths,omitempty"` @@ -6872,428 +6880,429 @@ var _GobgpApi_serviceDesc = grpc.ServiceDesc{ func init() { proto.RegisterFile("gobgp.proto", fileDescriptor0) } var fileDescriptor0 = []byte{ - // 6761 bytes of a gzipped FileDescriptorProto + // 6775 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xec, 0x7c, 0x4b, 0x8f, 0x1b, 0x49, 0x72, 0x70, 0xf3, 0xd1, 0x6c, 0x32, 0x48, 0x36, 0xd9, 0xd9, 0x2f, 0x8a, 0x3d, 0x7a, 0xd5, 0x8e, 0x46, 0x1a, 0x8d, 0x46, 0x33, 0xd2, 0xcc, 0x68, 0x66, 0x47, 0xab, 0xd9, 0xa5, 0xba, 0xa9, 0x16, 0x77, 0xfa, 0xc1, 0xc9, 0xa6, 0xb4, 0x9a, 0xfd, 0x76, 0xbf, 0x72, 0x35, 0x2b, 0xc9, 0x2e, 0x4f, 0xb1, 0xaa, 0xa6, 0xaa, 0xd8, 0xea, 0x86, 0x01, 0x1b, 0x58, 0x03, 0x86, 0x01, 0xc3, 0x17, 0x5f, 0x6d, 0xc0, 0xf7, 0x85, 0x7d, 0xf0, 0xc9, 0x80, 0xcf, 0x5e, 0xc3, 0xc0, 0x02, 0xbe, 0xd8, 0x47, - 0x63, 0x7d, 0xf0, 0x0f, 0xf0, 0xc5, 0x07, 0x1f, 0x7c, 0x30, 0xf2, 0x51, 0x55, 0x59, 0x0f, 0x76, - 0xb7, 0xb4, 0x5a, 0x1b, 0x06, 0x7c, 0x22, 0x2b, 0x22, 0x32, 0x32, 0x32, 0x33, 0x22, 0x32, 0xf2, - 0x15, 0x50, 0x1d, 0xdb, 0x87, 0x63, 0xe7, 0xae, 0xe3, 0xda, 0xbe, 0x8d, 0xca, 0xec, 0x43, 0x73, - 0x0c, 0xe5, 0xc7, 0x80, 0xb6, 0x89, 0xbf, 0x47, 0x8c, 0xf1, 0xd1, 0xa1, 0xed, 0x62, 0xf2, 0xed, - 0x94, 0x78, 0x3e, 0xba, 0x0d, 0x4d, 0x62, 0x69, 0x87, 0x26, 0xe9, 0xe8, 0xc7, 0xc4, 0xf5, 0x0d, - 0x8f, 0xe8, 0xad, 0xdc, 0xb5, 0xdc, 0xad, 0x32, 0x4e, 0xc1, 0x51, 0x0b, 0x16, 0x34, 0x5d, 0x77, - 0x89, 0xe7, 0xb5, 0xf2, 0xd7, 0x72, 0xb7, 0x2a, 0x38, 0xf8, 0x54, 0x1e, 0xc2, 0x72, 0x8c, 0xb7, - 0xe7, 0xd8, 0x96, 0x47, 0xd0, 0xdb, 0x30, 0xef, 0x10, 0xe2, 0x7a, 0xad, 0xdc, 0xb5, 0xc2, 0xad, - 0xea, 0xfd, 0xc5, 0xbb, 0x81, 0x30, 0x77, 0xfb, 0x84, 0xb8, 0x98, 0x23, 0x95, 0x31, 0x54, 0x3a, - 0xee, 0x78, 0x3a, 0x21, 0x96, 0xef, 0xa1, 0xbb, 0x50, 0x76, 0x89, 0x67, 0x4f, 0xdd, 0x21, 0x61, - 0x72, 0x2c, 0xde, 0x47, 0x51, 0x29, 0x2c, 0x30, 0x38, 0xa4, 0x41, 0x6b, 0x50, 0x1a, 0x69, 0x13, - 0xc3, 0x3c, 0x65, 0x22, 0xd5, 0xb1, 0xf8, 0x42, 0x08, 0x8a, 0x96, 0x36, 0x21, 0xad, 0x02, 0x13, - 0x94, 0xfd, 0x57, 0x7e, 0x07, 0x16, 0x3b, 0xba, 0xde, 0xd7, 0xfc, 0xa3, 0xa0, 0xf5, 0xaf, 0x5a, - 0xdb, 0x2a, 0x94, 0x8e, 0xdd, 0x91, 0x6a, 0xe8, 0xa2, 0x03, 0xe6, 0x8f, 0xdd, 0x51, 0x4f, 0x47, - 0x0a, 0x14, 0x1d, 0xcd, 0x3f, 0x62, 0x95, 0xc5, 0x9b, 0x49, 0xeb, 0x62, 0x38, 0xe5, 0x06, 0x34, - 0xc2, 0xca, 0x45, 0xf7, 0x20, 0x28, 0x4e, 0xa7, 0x06, 0xef, 0xef, 0x1a, 0x66, 0xff, 0x95, 0x9f, - 0xe7, 0x60, 0x69, 0x8b, 0x98, 0xc4, 0x27, 0xbf, 0x01, 0x39, 0xa3, 0xce, 0x2a, 0xc4, 0x3a, 0x2b, - 0x90, 0xbf, 0x38, 0x5b, 0xfe, 0x50, 0xd8, 0x79, 0x49, 0xd8, 0x15, 0x40, 0xb2, 0xac, 0xbc, 0x59, - 0xca, 0x67, 0x80, 0x3a, 0xba, 0x9e, 0x54, 0x34, 0x5a, 0x07, 0x21, 0x2e, 0x13, 0x3f, 0xad, 0x0a, - 0x0c, 0xa7, 0xac, 0xc2, 0x72, 0xac, 0xa4, 0x60, 0xf8, 0x10, 0x56, 0x79, 0x35, 0xaf, 0xc3, 0xb3, - 0x05, 0x6b, 0xc9, 0xc2, 0x82, 0xed, 0x73, 0x58, 0xc1, 0xc4, 0x4b, 0x9b, 0x84, 0xa4, 0xe6, 0xb9, - 0x98, 0x9a, 0xa3, 0xb7, 0xa1, 0x3e, 0xb4, 0x27, 0x93, 0xa9, 0x65, 0x0c, 0x35, 0xdf, 0xb0, 0x2d, - 0xd1, 0xbb, 0x71, 0xa0, 0xb2, 0x0e, 0xab, 0x09, 0xbe, 0xa2, 0xc2, 0xbf, 0xc9, 0x41, 0xeb, 0xc0, - 0x1e, 0xf9, 0xaf, 0x58, 0xeb, 0x01, 0x54, 0x74, 0xc3, 0x25, 0xc3, 0xb0, 0xc6, 0xc5, 0xfb, 0x9f, - 0x44, 0x4d, 0x9d, 0xc5, 0x30, 0x42, 0x6c, 0x05, 0x85, 0x71, 0xc4, 0x47, 0xf9, 0x00, 0x50, 0x9a, - 0x00, 0x95, 0x20, 0xdf, 0xdb, 0x6b, 0xce, 0xa1, 0x05, 0x28, 0xec, 0x3f, 0x1b, 0x34, 0x73, 0xa8, - 0x0c, 0xc5, 0xc7, 0xfb, 0x83, 0xa7, 0xcd, 0xbc, 0xb2, 0x01, 0x97, 0x32, 0xaa, 0x12, 0x2d, 0xfb, - 0x1a, 0xd6, 0x0f, 0x8e, 0xa6, 0xbe, 0x6e, 0xbf, 0xb4, 0xde, 0x74, 0x6f, 0xb6, 0xa1, 0x95, 0x66, - 0x2d, 0xaa, 0xbd, 0x07, 0xab, 0x5d, 0xe6, 0xa4, 0x2e, 0x5c, 0x29, 0x55, 0x87, 0x64, 0x11, 0xc1, - 0xec, 0x05, 0xac, 0x6d, 0x19, 0xde, 0x2b, 0x71, 0xbb, 0x60, 0x13, 0x2e, 0xc1, 0x7a, 0x8a, 0xb3, - 0xa8, 0x74, 0x0c, 0x4d, 0x2e, 0xce, 0xae, 0xeb, 0x07, 0xd5, 0x6d, 0x40, 0x45, 0x9f, 0x4e, 0x1c, - 0xd5, 0x3f, 0x75, 0xb8, 0xb5, 0xcf, 0xe3, 0x32, 0x05, 0x0c, 0x4e, 0x1d, 0x82, 0xda, 0x50, 0x1e, - 0x19, 0x26, 0x61, 0xbe, 0x8d, 0x57, 0x16, 0x7e, 0x53, 0x9c, 0x61, 0xf9, 0xc4, 0x3d, 0xd6, 0x4c, - 0x66, 0xe0, 0x45, 0x1c, 0x7e, 0x2b, 0xcb, 0xb0, 0x24, 0x55, 0x24, 0x6a, 0x5f, 0x86, 0x25, 0x21, - 0x58, 0x54, 0x3d, 0x33, 0x6a, 0x09, 0x28, 0x48, 0x7f, 0x0f, 0x9a, 0x3d, 0xeb, 0xb7, 0xc9, 0xd0, - 0x97, 0x04, 0x7d, 0x43, 0x5e, 0x89, 0xce, 0x12, 0x9a, 0x7f, 0xe4, 0xb5, 0x0a, 0xa9, 0x59, 0x82, - 0xba, 0x15, 0x8e, 0xa4, 0xb2, 0x4a, 0x02, 0x08, 0xa9, 0xfe, 0x22, 0x07, 0xf5, 0x8e, 0xae, 0x3f, - 0x9e, 0x38, 0xe7, 0x8f, 0x15, 0x82, 0xa2, 0x63, 0xbb, 0xbe, 0x98, 0x27, 0xd8, 0x7f, 0xf4, 0x3d, - 0x28, 0xb2, 0x5e, 0x2e, 0x30, 0xe9, 0x6f, 0x45, 0x35, 0xc7, 0x98, 0xde, 0xdd, 0xb5, 0x2d, 0xc3, - 0xb7, 0x5d, 0xc3, 0x1a, 0xf7, 0x6d, 0xd3, 0x18, 0x9e, 0x62, 0x56, 0x4a, 0xf9, 0x00, 0x9a, 0x49, - 0x0c, 0xb5, 0x9c, 0x3e, 0xee, 0x36, 0xe7, 0xa8, 0xe5, 0xf4, 0xf7, 0x0f, 0xe2, 0x36, 0xd4, 0x64, - 0x13, 0x10, 0x63, 0x2c, 0x1a, 0xf0, 0x03, 0x68, 0x72, 0xef, 0xf4, 0xba, 0x4d, 0x60, 0x63, 0x18, - 0x71, 0x10, 0x6c, 0x07, 0xb0, 0x24, 0x24, 0xc3, 0xc6, 0x61, 0xc0, 0xf7, 0x06, 0xcc, 0xfb, 0x74, - 0x58, 0x85, 0xbb, 0x6c, 0x44, 0xad, 0x1d, 0x50, 0x30, 0xe6, 0x58, 0x5a, 0xfd, 0x70, 0xea, 0xba, - 0xc4, 0xe2, 0xf5, 0x94, 0x71, 0xf0, 0xa9, 0x74, 0xa1, 0x8c, 0xfb, 0x5f, 0xf6, 0x36, 0x6d, 0x6b, - 0x74, 0x86, 0x90, 0x57, 0xa1, 0xea, 0x92, 0x89, 0xed, 0x13, 0x35, 0x94, 0xb5, 0x82, 0x81, 0x83, - 0xfa, 0x54, 0xe2, 0x3f, 0x2b, 0x42, 0x85, 0xf2, 0x39, 0xf0, 0x35, 0x9f, 0x4d, 0xe0, 0x53, 0xc7, - 0x37, 0x26, 0x5c, 0xac, 0x02, 0x16, 0x5f, 0x54, 0x99, 0xa9, 0xcd, 0x33, 0x4c, 0x9e, 0x61, 0xc2, - 0x6f, 0xb4, 0x08, 0xf9, 0xa9, 0xc3, 0x06, 0xad, 0x8c, 0xf3, 0x53, 0x87, 0x57, 0x39, 0xb4, 0x5d, - 0x5d, 0x35, 0x9c, 0xe3, 0x8f, 0xd9, 0x34, 0x56, 0xa7, 0x55, 0x52, 0x50, 0xcf, 0x39, 0xfe, 0x38, - 0x4e, 0xf0, 0x80, 0xcd, 0x61, 0x32, 0xc1, 0x03, 0x4a, 0xe0, 0xb8, 0x64, 0x64, 0x9c, 0x70, 0x0e, - 0x25, 0x4e, 0xc0, 0x41, 0x01, 0x87, 0x88, 0xe0, 0x41, 0x6b, 0x21, 0x41, 0xf0, 0x80, 0xb6, 0xc3, - 0x23, 0xae, 0xa1, 0x99, 0xad, 0x32, 0x9f, 0x5b, 0xf9, 0x17, 0xfa, 0x0e, 0xd4, 0x5d, 0x32, 0x24, - 0xc6, 0x31, 0x11, 0xd2, 0x55, 0x58, 0x63, 0x6a, 0x01, 0x90, 0x71, 0x4f, 0x10, 0x3d, 0x68, 0x41, - 0x8a, 0xe8, 0x01, 0x25, 0xe2, 0x3c, 0x55, 0xcb, 0xf6, 0x8d, 0xd1, 0x69, 0xab, 0xca, 0x89, 0x38, - 0x70, 0x8f, 0xc1, 0xa8, 0x9c, 0x43, 0x6d, 0x78, 0x44, 0x54, 0x97, 0x3a, 0xea, 0x56, 0x8d, 0x91, - 0x00, 0x03, 0x31, 0xd7, 0x8d, 0x6e, 0xc0, 0x62, 0x48, 0xc0, 0x94, 0xa5, 0x55, 0x67, 0x34, 0xf5, - 0x80, 0x86, 0xc7, 0x26, 0x57, 0xa0, 0x4a, 0x2c, 0x5d, 0xb5, 0x47, 0xaa, 0xae, 0xf9, 0x5a, 0x6b, - 0x91, 0xd1, 0x54, 0x88, 0xa5, 0xef, 0x8f, 0xb6, 0x34, 0x5f, 0x43, 0x2b, 0x30, 0x4f, 0x5c, 0xd7, - 0x76, 0x5b, 0x0d, 0x86, 0xe1, 0x1f, 0xe8, 0x3a, 0x08, 0x69, 0xd4, 0x6f, 0xa7, 0xc4, 0x3d, 0x6d, - 0x35, 0x19, 0xb2, 0xca, 0x61, 0x5f, 0x51, 0x10, 0x1f, 0x0a, 0x8f, 0xf8, 0x82, 0x62, 0x89, 0x0b, - 0xc8, 0x40, 0x8c, 0x40, 0xf9, 0x1a, 0x8a, 0xd8, 0xf9, 0xc6, 0x40, 0xef, 0x40, 0x71, 0x68, 0x5b, - 0x23, 0xa1, 0xad, 0xb2, 0x67, 0x11, 0x3a, 0x88, 0x19, 0x1e, 0xbd, 0x0b, 0xf3, 0x1e, 0xd5, 0x24, - 0xa6, 0x25, 0xd5, 0xfb, 0xcb, 0x71, 0x42, 0xa6, 0x64, 0x98, 0x53, 0x28, 0xb7, 0x60, 0x71, 0x9b, - 0xf8, 0x94, 0x7b, 0x60, 0x13, 0x51, 0x44, 0x94, 0x93, 0x23, 0x22, 0xe5, 0x21, 0x34, 0x42, 0x4a, - 0xd1, 0x23, 0xb7, 0x60, 0xc1, 0x23, 0xee, 0x71, 0x66, 0x38, 0xcb, 0x08, 0x03, 0xb4, 0xf2, 0x63, - 0x66, 0xe6, 0x72, 0x35, 0xaf, 0xe6, 0x95, 0xda, 0x50, 0x36, 0x8d, 0x11, 0x61, 0xaa, 0x5f, 0xe0, - 0xaa, 0x1f, 0x7c, 0x2b, 0x4b, 0x2c, 0x8c, 0x94, 0x05, 0x53, 0x3a, 0x81, 0x07, 0x78, 0xed, 0x1a, - 0xa3, 0x40, 0x2e, 0xc6, 0xf8, 0xfd, 0x60, 0xce, 0xb8, 0x10, 0x63, 0xca, 0x44, 0x26, 0x17, 0x4c, - 0xee, 0x86, 0xd3, 0xc9, 0xc5, 0xb8, 0xac, 0xc2, 0x72, 0x8c, 0x5e, 0xb0, 0xb9, 0x03, 0x4d, 0xa6, - 0xbf, 0x17, 0x63, 0xb2, 0x0c, 0x4b, 0x12, 0xb5, 0x60, 0xf1, 0x21, 0xac, 0x84, 0x11, 0xcc, 0xc5, - 0xd8, 0xac, 0xc3, 0x6a, 0xa2, 0x84, 0x60, 0xf5, 0xcb, 0x5c, 0xd0, 0xd6, 0x1f, 0x93, 0x43, 0x57, - 0x0b, 0x38, 0x35, 0xa1, 0x30, 0x75, 0x4d, 0xc1, 0x85, 0xfe, 0x65, 0xda, 0x6e, 0x4f, 0x7d, 0xc2, - 0x26, 0x73, 0xba, 0x6c, 0x2a, 0x30, 0x67, 0x48, 0x41, 0x74, 0x3a, 0xf7, 0x68, 0xe5, 0x54, 0x67, - 0x68, 0xec, 0xc0, 0x63, 0xf2, 0xe0, 0x13, 0x7d, 0x0c, 0x6b, 0x16, 0x39, 0xf1, 0x8f, 0x6c, 0x47, - 0xf5, 0x5d, 0x63, 0x3c, 0x26, 0xae, 0xca, 0x57, 0x64, 0xcc, 0xbf, 0x95, 0xf1, 0x8a, 0xc0, 0x0e, - 0x38, 0x92, 0x8b, 0x83, 0xee, 0xc3, 0x6a, 0xb2, 0x94, 0x4e, 0x4c, 0xed, 0x54, 0xf8, 0xbc, 0xe5, - 0x78, 0xa1, 0x2d, 0x8a, 0xa2, 0x5d, 0x1e, 0x6b, 0x8c, 0x68, 0x64, 0x03, 0xea, 0xdb, 0xc4, 0x7f, - 0xee, 0x8e, 0x82, 0xc8, 0xe0, 0x23, 0x66, 0x3e, 0x0c, 0x20, 0x6c, 0xe2, 0x3a, 0x14, 0x8f, 0xdd, - 0x51, 0x60, 0x10, 0xf5, 0xc8, 0x20, 0x28, 0x11, 0x43, 0x29, 0x1f, 0xb2, 0x19, 0x3a, 0xe2, 0x82, - 0xae, 0x42, 0xe1, 0xd8, 0x0d, 0xcc, 0x3a, 0x51, 0x84, 0x62, 0xc4, 0x2c, 0x29, 0x55, 0xa3, 0x7c, - 0x14, 0xcc, 0x92, 0xaf, 0xc2, 0x26, 0x9c, 0x18, 0x65, 0x4e, 0xcf, 0x60, 0x65, 0x9b, 0xf8, 0x5b, - 0x64, 0x64, 0x58, 0x44, 0x3f, 0x20, 0x61, 0x28, 0xf3, 0xae, 0x08, 0x04, 0x78, 0x18, 0xb3, 0x1a, - 0xb1, 0x13, 0xa4, 0x74, 0xb0, 0xf8, 0xac, 0x1f, 0xae, 0x2c, 0xf3, 0xd2, 0xca, 0xb2, 0x03, 0xab, - 0x09, 0xb6, 0xa1, 0xd3, 0x28, 0x7a, 0xc4, 0x0f, 0x3a, 0x68, 0x25, 0xc5, 0x97, 0xd2, 0x32, 0x0a, - 0xe5, 0x0b, 0x58, 0xe9, 0xe8, 0x7a, 0x5a, 0xb2, 0x77, 0xa0, 0x40, 0x1d, 0x39, 0x6f, 0x67, 0x36, - 0x03, 0x4a, 0x40, 0x75, 0x35, 0x51, 0x5e, 0x34, 0xf9, 0x00, 0xd6, 0x79, 0x3f, 0xbc, 0x36, 0x6f, - 0xaa, 0xd7, 0x9a, 0x69, 0x8a, 0x70, 0x80, 0xfe, 0xa5, 0x51, 0x79, 0x9a, 0xa9, 0xa8, 0xf0, 0x31, - 0xb4, 0x30, 0x71, 0x4c, 0x6d, 0xf8, 0xfa, 0x35, 0xd2, 0xd5, 0x46, 0x06, 0x0f, 0x51, 0xc1, 0x2a, - 0xdb, 0x6d, 0x60, 0x9e, 0x7d, 0x42, 0xac, 0x30, 0x70, 0xfd, 0x92, 0x8d, 0xad, 0x04, 0x16, 0x63, - 0xf0, 0x11, 0x80, 0x17, 0x00, 0x83, 0x91, 0x90, 0x66, 0x89, 0xa8, 0x80, 0x44, 0xa6, 0x3c, 0x65, - 0x4b, 0xd1, 0x64, 0x1d, 0xe8, 0x1e, 0x54, 0x42, 0x22, 0xd1, 0x8a, 0x4c, 0x56, 0x11, 0x95, 0xb2, - 0xc6, 0x06, 0x36, 0x25, 0x96, 0xf2, 0xd3, 0x60, 0x61, 0xfa, 0x06, 0x2a, 0xc9, 0x18, 0xa1, 0x4b, - 0xc1, 0xb0, 0xa7, 0x6b, 0xde, 0x81, 0x75, 0xd1, 0xb9, 0x6f, 0xa2, 0x7d, 0xed, 0x70, 0xb8, 0xd3, - 0x35, 0x21, 0x68, 0x6e, 0x13, 0x5f, 0x04, 0xcd, 0x62, 0x98, 0x3a, 0xb0, 0x24, 0xc1, 0xc4, 0x18, - 0xdd, 0x81, 0xb2, 0x43, 0x21, 0x06, 0x09, 0x46, 0xa8, 0x29, 0x2d, 0x03, 0x38, 0x6d, 0x48, 0xa1, - 0x9c, 0x40, 0xb3, 0xa3, 0xeb, 0x31, 0xb6, 0xe8, 0x16, 0x94, 0x18, 0xfe, 0x54, 0x88, 0x9d, 0x2e, - 0x2f, 0xf0, 0xe8, 0x73, 0xb8, 0xe4, 0x92, 0x11, 0x75, 0xa7, 0x27, 0x86, 0xe7, 0x1b, 0xd6, 0x58, - 0x95, 0xd4, 0x83, 0xf7, 0xe0, 0x3a, 0x23, 0xe8, 0x0a, 0xfc, 0x41, 0xa4, 0x16, 0xcb, 0xb0, 0x24, - 0xd5, 0x2c, 0x5a, 0xf9, 0xb3, 0x1c, 0x2c, 0x8b, 0x7d, 0x90, 0xd7, 0x14, 0xe9, 0x03, 0x58, 0x76, - 0x68, 0x08, 0xe4, 0x1e, 0x93, 0xb4, 0x30, 0x28, 0x40, 0x45, 0x72, 0x04, 0xe3, 0x5d, 0x88, 0xc6, - 0x7b, 0x0d, 0x56, 0xe2, 0x32, 0x08, 0xe1, 0xfe, 0x32, 0x07, 0x2b, 0x62, 0x7c, 0xfe, 0x07, 0x3a, - 0x6c, 0x56, 0xcb, 0x0a, 0xb3, 0x5a, 0xc6, 0x77, 0x4f, 0x62, 0xe2, 0x86, 0xeb, 0xf3, 0x76, 0xa8, - 0x37, 0x1d, 0xcf, 0x33, 0xc6, 0x96, 0xac, 0xb8, 0x9f, 0x03, 0x68, 0x21, 0x50, 0xb4, 0xa8, 0x9d, - 0x6c, 0x91, 0x54, 0x4c, 0xa2, 0x56, 0xbe, 0x86, 0x8d, 0x4c, 0xce, 0x42, 0x37, 0x7f, 0x1d, 0xd6, - 0x2f, 0xa0, 0x1d, 0xea, 0xcb, 0x9b, 0x15, 0xfa, 0x32, 0x6c, 0x64, 0x72, 0x16, 0xbd, 0x35, 0x81, - 0xcb, 0xb2, 0x3a, 0xbc, 0xd1, 0xba, 0x33, 0xbc, 0xcd, 0x35, 0xb8, 0x32, 0xab, 0x3a, 0x21, 0xd0, - 0x4f, 0xe0, 0x4a, 0x6c, 0x5c, 0xdf, 0x6c, 0x6f, 0x5c, 0x87, 0xab, 0x33, 0xb9, 0xc7, 0x7c, 0xd1, - 0x01, 0x8b, 0xd1, 0x03, 0x5f, 0xf4, 0x88, 0xf9, 0xa2, 0x00, 0x16, 0xce, 0xd9, 0xa5, 0xb1, 0x69, - 0x1f, 0x6a, 0x66, 0xda, 0x30, 0xb6, 0x19, 0x1c, 0x0b, 0xbc, 0xf2, 0x05, 0xa0, 0x03, 0x5f, 0x73, - 0xe3, 0x4c, 0x5f, 0xa1, 0xfc, 0x2a, 0x2c, 0xc7, 0xca, 0x47, 0xdb, 0x32, 0x07, 0xbe, 0xed, 0xc4, - 0x45, 0x5d, 0xa1, 0x75, 0x45, 0x40, 0x41, 0xfa, 0xab, 0x02, 0x14, 0xfb, 0x62, 0x7b, 0xd6, 0x32, - 0x5d, 0x23, 0xd8, 0x4b, 0xa6, 0xff, 0xe9, 0xe2, 0xc6, 0xd1, 0x7c, 0xdf, 0xe5, 0x71, 0x67, 0x0d, - 0x8b, 0x2f, 0x36, 0x7c, 0xe3, 0x60, 0x69, 0x41, 0xff, 0xd2, 0xd2, 0x87, 0xc4, 0xf3, 0x45, 0x64, - 0xc9, 0xfe, 0xd3, 0xd0, 0xd5, 0xf0, 0xd4, 0x97, 0x86, 0x7f, 0xa4, 0xbb, 0xda, 0x4b, 0x16, 0x3f, - 0x96, 0x31, 0x18, 0xde, 0x8f, 0x04, 0x04, 0x5d, 0x01, 0x38, 0xd6, 0x4c, 0x43, 0xe7, 0x3b, 0x5f, - 0x25, 0xb6, 0x51, 0x25, 0x41, 0xd0, 0x87, 0xb0, 0x62, 0xd9, 0xaa, 0x31, 0x71, 0xa8, 0xd7, 0xf6, - 0x23, 0x4e, 0x0b, 0xdc, 0xf6, 0x2d, 0xbb, 0x27, 0x50, 0x21, 0xc7, 0x68, 0x35, 0x56, 0x8e, 0xed, - 0x4f, 0x5f, 0x06, 0xe0, 0x5b, 0x48, 0xaa, 0xe6, 0x59, 0x6c, 0x01, 0x5d, 0xc7, 0x15, 0x0e, 0xe9, - 0x78, 0x16, 0xda, 0x00, 0xf1, 0xa1, 0x1a, 0x3a, 0x5b, 0x39, 0x57, 0x70, 0x99, 0x03, 0x7a, 0xba, - 0xd8, 0x30, 0xf3, 0x89, 0x4b, 0x74, 0xb6, 0x60, 0x2e, 0xe3, 0xf0, 0x9b, 0x2e, 0x62, 0x3d, 0x5f, - 0x33, 0x09, 0x5b, 0x26, 0x97, 0x31, 0xff, 0x40, 0xb7, 0xa0, 0x69, 0x78, 0xea, 0xc8, 0xb5, 0x27, - 0x2a, 0x39, 0xf1, 0x89, 0x6b, 0x69, 0x26, 0x5b, 0x23, 0x97, 0xf1, 0xa2, 0xe1, 0x3d, 0x71, 0xed, - 0x49, 0x57, 0x40, 0x69, 0x17, 0x59, 0x62, 0x47, 0x4f, 0x35, 0x1c, 0xb6, 0x48, 0xae, 0x60, 0x08, - 0x40, 0x3d, 0x27, 0xdc, 0x34, 0x6f, 0x44, 0x9b, 0xe6, 0xe8, 0x0e, 0x20, 0xc3, 0x53, 0x83, 0x20, - 0xdd, 0xb0, 0x58, 0x8f, 0xb1, 0x95, 0x72, 0x19, 0x37, 0x0d, 0x6f, 0x8f, 0x23, 0x7a, 0x1c, 0xae, - 0xfc, 0x79, 0x0e, 0xaa, 0x5b, 0x84, 0x7a, 0x55, 0xde, 0xa9, 0x74, 0x4c, 0xd9, 0xa6, 0x83, 0x58, - 0x65, 0x88, 0xaf, 0x68, 0x13, 0x2d, 0x7f, 0xc6, 0x26, 0x1a, 0xba, 0x09, 0x0d, 0xd3, 0xb6, 0xe8, - 0xa2, 0x80, 0x17, 0x23, 0x81, 0x27, 0x5e, 0xe4, 0xe0, 0xbe, 0x80, 0xa2, 0x77, 0xa1, 0xe9, 0x1d, - 0xd9, 0xae, 0x2f, 0x53, 0x72, 0xe5, 0x68, 0x08, 0x78, 0x40, 0xaa, 0xfc, 0x75, 0x0e, 0xe6, 0xd9, - 0x06, 0x12, 0x5d, 0xb1, 0x4b, 0x41, 0x74, 0xd6, 0x5e, 0xe0, 0xcc, 0x08, 0x7a, 0xe6, 0xd1, 0xc4, - 0x77, 0xa1, 0xa6, 0x47, 0xcd, 0xa7, 0x42, 0xd0, 0xe6, 0xc5, 0x02, 0xf4, 0x10, 0x8b, 0x63, 0xa4, - 0x6c, 0xcb, 0xc6, 0xf6, 0x7c, 0x55, 0xcc, 0x72, 0x42, 0x81, 0x29, 0x88, 0xfb, 0x08, 0xe5, 0x01, - 0x5b, 0xe0, 0xbc, 0xf2, 0x0e, 0x99, 0xf2, 0x29, 0xdf, 0x46, 0xa0, 0xe5, 0x84, 0xcb, 0xb8, 0x60, - 0x41, 0x13, 0xd0, 0x73, 0x6e, 0x1f, 0x44, 0xaa, 0xf5, 0xa2, 0xdd, 0x36, 0xeb, 0xa8, 0x2b, 0x52, - 0x89, 0x82, 0xac, 0x12, 0xd4, 0xbb, 0xc4, 0x6a, 0x0b, 0x4e, 0x21, 0x8a, 0x50, 0xec, 0x13, 0xe2, - 0x32, 0xcb, 0xa0, 0x1c, 0x82, 0x98, 0xab, 0x8e, 0xc3, 0x6f, 0xf4, 0x19, 0xd4, 0x34, 0xc7, 0x31, - 0x4f, 0x83, 0xce, 0xe3, 0x7b, 0x2b, 0x52, 0xb7, 0x77, 0x28, 0x56, 0xcc, 0xd0, 0x55, 0x2d, 0xfa, - 0x08, 0xb7, 0x6d, 0x0a, 0xc9, 0x6d, 0x1b, 0x5a, 0xa7, 0xb4, 0x6d, 0xf3, 0x10, 0xea, 0xe4, 0x70, - 0xec, 0xa8, 0x93, 0xa9, 0xe9, 0x1b, 0x47, 0xb6, 0x23, 0x0e, 0x9f, 0xd6, 0xa2, 0x02, 0xdd, 0xc3, - 0xb1, 0xb3, 0x2b, 0xb0, 0xb8, 0x46, 0xa4, 0x2f, 0xd4, 0x81, 0x06, 0x5f, 0x56, 0xbb, 0x64, 0x64, - 0x92, 0xa1, 0x6f, 0xbb, 0x6c, 0x78, 0xab, 0xf7, 0x5b, 0x52, 0xef, 0x51, 0x02, 0x1c, 0xe0, 0xf1, - 0xa2, 0x1b, 0xfb, 0x46, 0x37, 0xa1, 0x68, 0x58, 0x23, 0x9b, 0xf9, 0xad, 0x58, 0x90, 0x4b, 0xe5, - 0xe4, 0xbb, 0x46, 0x8c, 0x80, 0xba, 0x73, 0xdf, 0x98, 0x10, 0xd7, 0x63, 0x8e, 0x2b, 0xe6, 0xce, - 0x07, 0x0c, 0x8e, 0x05, 0x9e, 0x06, 0xcf, 0xbe, 0xab, 0x59, 0x1e, 0xdb, 0x5e, 0x29, 0x27, 0xf9, - 0x0e, 0x02, 0x14, 0x8e, 0xa8, 0x68, 0x3f, 0xf3, 0x86, 0xf0, 0xbd, 0x23, 0xe6, 0xdb, 0x62, 0xfd, - 0xcc, 0x5a, 0x21, 0x9c, 0x3e, 0xdf, 0x4a, 0xe0, 0x1f, 0x68, 0x0b, 0x9a, 0x63, 0x57, 0x1b, 0x92, - 0xd1, 0xd4, 0x54, 0x5d, 0xe2, 0xd1, 0x69, 0x84, 0xf9, 0xbe, 0xea, 0xfd, 0x4b, 0xd2, 0x7c, 0x23, - 0x28, 0x30, 0x27, 0xc0, 0x8d, 0x71, 0x1c, 0x80, 0xee, 0x42, 0x45, 0x1b, 0x19, 0xaa, 0xa7, 0x8d, - 0x0c, 0xaf, 0x55, 0x65, 0xb6, 0xb5, 0x24, 0x0d, 0xf2, 0xc8, 0x38, 0xd0, 0x46, 0x06, 0x2e, 0x6b, - 0xfc, 0x8f, 0xa7, 0xfc, 0x7d, 0x0e, 0xaa, 0xd2, 0xd0, 0xa3, 0x4f, 0xa1, 0x62, 0x58, 0x6a, 0x2c, - 0x8e, 0x3c, 0x6b, 0xca, 0x2e, 0x1b, 0x96, 0x28, 0xf8, 0x7d, 0xa8, 0x93, 0x13, 0xda, 0x05, 0x71, - 0x0d, 0x3b, 0xab, 0x70, 0x8d, 0x17, 0x88, 0x18, 0x18, 0x13, 0x99, 0x41, 0xe1, 0x7c, 0x06, 0xbc, - 0x80, 0xb0, 0xfe, 0xdf, 0x85, 0x2a, 0xf7, 0x61, 0x3b, 0xc6, 0xc4, 0x98, 0xb9, 0x13, 0x88, 0xae, - 0x43, 0x6d, 0xa2, 0x9d, 0x44, 0x5e, 0x90, 0xdb, 0x5e, 0x75, 0xa2, 0x9d, 0x84, 0xce, 0xf2, 0x63, - 0x58, 0xf3, 0xc4, 0x11, 0x95, 0xea, 0x1f, 0xb9, 0xc4, 0x3b, 0xb2, 0x4d, 0x5d, 0x75, 0x86, 0xbe, - 0xf0, 0x65, 0x2b, 0x01, 0x76, 0x10, 0x20, 0xfb, 0x43, 0x5f, 0xf9, 0xcf, 0x79, 0x28, 0x07, 0x36, - 0x81, 0xbe, 0x03, 0x75, 0x6d, 0xea, 0x1f, 0xa9, 0x8e, 0xe6, 0x79, 0x2f, 0x6d, 0x57, 0x17, 0xde, - 0xbd, 0x46, 0x81, 0x7d, 0x01, 0x43, 0xd7, 0xa0, 0xaa, 0x13, 0x6f, 0xe8, 0x1a, 0x8e, 0x74, 0xd6, - 0x24, 0x83, 0xd0, 0x25, 0x28, 0x9b, 0xf6, 0x50, 0x33, 0x55, 0xcd, 0x0b, 0xb6, 0x93, 0xd8, 0x77, - 0x87, 0x79, 0xf4, 0x70, 0xae, 0x0a, 0xb6, 0xbb, 0x8a, 0x8c, 0x43, 0x23, 0x80, 0x77, 0xc4, 0x0e, - 0xe1, 0x3a, 0x2c, 0x38, 0x84, 0xb8, 0x94, 0x09, 0xdf, 0x35, 0x2a, 0xd1, 0xcf, 0x8e, 0x47, 0xe7, - 0x61, 0x86, 0x18, 0xbb, 0xf6, 0xd4, 0x61, 0x96, 0x53, 0xc1, 0x15, 0x0a, 0xd9, 0xa6, 0x00, 0x3a, - 0x0f, 0x33, 0x34, 0xf3, 0x66, 0x7c, 0x87, 0xbc, 0x4c, 0x01, 0xec, 0xe0, 0x6a, 0x0f, 0x96, 0x5c, - 0x32, 0xb1, 0x8f, 0x89, 0xea, 0xb8, 0xc6, 0xb1, 0xe6, 0xd3, 0xb9, 0x9c, 0x19, 0xc9, 0xe2, 0x7d, - 0x25, 0xed, 0x24, 0xee, 0x62, 0x46, 0xdb, 0xe7, 0xa4, 0x1d, 0x0f, 0x37, 0xdc, 0x38, 0x80, 0x4e, - 0xa3, 0xdc, 0x72, 0x46, 0xa6, 0xe6, 0xa8, 0xba, 0x36, 0x71, 0x0c, 0x6b, 0xcc, 0xec, 0xa7, 0x8c, - 0x9b, 0x0c, 0xf3, 0xc4, 0xd4, 0x9c, 0x2d, 0x0e, 0x47, 0x37, 0x60, 0xd1, 0x23, 0x96, 0xae, 0x8a, - 0x83, 0x39, 0xff, 0x94, 0xd9, 0x4a, 0x1d, 0xd7, 0x29, 0x74, 0x33, 0x00, 0xd2, 0x06, 0x8a, 0xb3, - 0x8b, 0xa1, 0xe6, 0x30, 0x7b, 0xa8, 0xe1, 0x0a, 0x87, 0x6c, 0x6a, 0xac, 0x81, 0xbc, 0x7b, 0x29, - 0xb6, 0xc6, 0xb0, 0xbc, 0xbf, 0x29, 0x72, 0x11, 0xf2, 0x86, 0xce, 0x02, 0x85, 0x0a, 0xce, 0x1b, - 0x3a, 0xfa, 0x1c, 0xea, 0xe2, 0xc4, 0xc0, 0xa4, 0x0a, 0xe6, 0xb5, 0x16, 0x93, 0x53, 0x97, 0xa4, - 0x7e, 0xb8, 0xe6, 0x44, 0x1f, 0x1e, 0x55, 0x07, 0x31, 0x8e, 0x62, 0xa4, 0x1a, 0x5c, 0x1d, 0xf8, - 0x60, 0x8a, 0x61, 0x7a, 0x1f, 0x50, 0x14, 0x7d, 0x58, 0x3e, 0x71, 0x47, 0xda, 0x90, 0xb0, 0x40, - 0xa2, 0x82, 0x97, 0xc2, 0x20, 0x24, 0x40, 0xd0, 0xa8, 0xef, 0xd8, 0x1d, 0xb1, 0x0d, 0xf7, 0x0a, - 0xdb, 0x21, 0x43, 0xd7, 0xa0, 0xa6, 0x99, 0xa6, 0xfd, 0x52, 0xa5, 0x8a, 0xab, 0x79, 0x2d, 0xc4, - 0x0f, 0x35, 0x18, 0x6c, 0xff, 0xa5, 0xd5, 0xf1, 0xd0, 0x3b, 0xd0, 0x70, 0x79, 0x58, 0xad, 0x06, - 0x1a, 0xb1, 0xcc, 0x7a, 0xb8, 0x2e, 0xc0, 0x7d, 0xa6, 0x18, 0xca, 0x3d, 0x68, 0x24, 0x06, 0x0c, - 0x95, 0xa1, 0xb8, 0xb7, 0xbf, 0xd7, 0xe5, 0x87, 0xc9, 0x9d, 0x9d, 0x9d, 0x66, 0x0e, 0x55, 0x61, - 0x01, 0x77, 0xfb, 0x3b, 0x9d, 0xcd, 0x6e, 0x33, 0xaf, 0x7c, 0x09, 0x35, 0xd9, 0xc1, 0xa3, 0x16, - 0x2c, 0xf0, 0xed, 0xcd, 0xe0, 0xfe, 0x49, 0xf0, 0xc9, 0x2c, 0x50, 0x50, 0xa9, 0xbe, 0x6f, 0x86, - 0x16, 0x28, 0x60, 0x03, 0xdf, 0x54, 0x7e, 0x3f, 0x07, 0x8b, 0x71, 0x7f, 0x4f, 0x8d, 0x32, 0x31, - 0x45, 0xa8, 0x43, 0xd3, 0x08, 0x56, 0x16, 0x65, 0xbc, 0x12, 0x9f, 0x0f, 0x36, 0x19, 0x0e, 0x3d, - 0x84, 0x76, 0xba, 0xd4, 0xd4, 0xa3, 0x71, 0x50, 0x78, 0x6c, 0xb9, 0x9e, 0x2c, 0xc9, 0xf0, 0x3d, - 0x5d, 0xf9, 0xab, 0x12, 0x54, 0xc2, 0xd9, 0xe3, 0xbf, 0xc1, 0xa4, 0xef, 0x42, 0x79, 0x42, 0x3c, - 0x4f, 0x1b, 0x8b, 0xe0, 0x2c, 0x36, 0xdd, 0xee, 0x0a, 0x0c, 0x0e, 0x69, 0x32, 0x5d, 0xc0, 0xfc, - 0xb9, 0x2e, 0xa0, 0x74, 0x86, 0x0b, 0x58, 0x38, 0xd3, 0x05, 0x94, 0x13, 0x2e, 0xe0, 0x16, 0x94, - 0xbe, 0x9d, 0x92, 0x29, 0xf1, 0xc4, 0x34, 0x27, 0xcd, 0xa4, 0x5f, 0x31, 0x38, 0x16, 0x78, 0x74, - 0x3b, 0xcb, 0x59, 0x70, 0x8b, 0xbd, 0xa0, 0x23, 0xa8, 0x5e, 0xd8, 0x11, 0xd4, 0xb2, 0x1c, 0x01, - 0x3b, 0x6b, 0xf3, 0x3c, 0xc3, 0xb6, 0xf8, 0xae, 0x05, 0xb3, 0xeb, 0x3a, 0xae, 0x09, 0x20, 0x1f, - 0xe1, 0x4f, 0x60, 0xcd, 0x9b, 0x3a, 0x74, 0x4a, 0x21, 0x3a, 0x75, 0x09, 0xda, 0xa1, 0x61, 0x1a, - 0x3e, 0x0d, 0xa7, 0x16, 0xd9, 0x3e, 0xff, 0x6a, 0x88, 0xdd, 0x94, 0x90, 0xb4, 0x8f, 0x68, 0xe0, - 0xc3, 0xf9, 0x72, 0xc3, 0x2e, 0x1f, 0x8e, 0x1d, 0xce, 0xf3, 0xfb, 0x50, 0xd5, 0xf4, 0x89, 0x11, - 0x54, 0xdb, 0x64, 0x0e, 0xf2, 0x4a, 0x46, 0x74, 0x72, 0xb7, 0x43, 0xc9, 0x78, 0xa0, 0x02, 0x5a, - 0xf8, 0x9f, 0x46, 0x75, 0xc1, 0xa9, 0x21, 0xb3, 0xf5, 0x3a, 0x0e, 0xbf, 0x29, 0x4e, 0x1b, 0x0e, - 0x89, 0xe3, 0x13, 0x5d, 0x18, 0x7b, 0xf8, 0x4d, 0x57, 0x73, 0x5a, 0x74, 0x05, 0x6c, 0x59, 0xb8, - 0x82, 0xe8, 0xf2, 0xd7, 0x32, 0xcc, 0xdb, 0x53, 0x5f, 0xfd, 0xb6, 0xb5, 0xc2, 0xcf, 0x8d, 0xec, - 0xa9, 0xff, 0x15, 0x5d, 0x40, 0x8d, 0x4c, 0xdb, 0xf1, 0x5a, 0xab, 0x0c, 0xc8, 0x3f, 0x94, 0xdb, - 0x00, 0x91, 0x70, 0xa8, 0x04, 0xf9, 0x67, 0x7d, 0x7e, 0x20, 0xbe, 0xb5, 0xff, 0xa3, 0xbd, 0x66, - 0x0e, 0x01, 0x94, 0xfa, 0x4f, 0x5e, 0xa8, 0x9b, 0x83, 0x66, 0x5e, 0xf9, 0x2d, 0x28, 0x07, 0x9a, - 0x8a, 0xde, 0x97, 0x44, 0xe7, 0xb1, 0xc4, 0x52, 0x4a, 0x9f, 0xa5, 0xd6, 0xdc, 0x80, 0xa2, 0x17, - 0x9c, 0x52, 0x67, 0x92, 0x32, 0xb4, 0xf2, 0x8b, 0x1c, 0x2c, 0x08, 0x08, 0x52, 0xa0, 0xb6, 0xb7, - 0x3f, 0xe8, 0x3d, 0xe9, 0x6d, 0x76, 0x06, 0xbd, 0xfd, 0x3d, 0x56, 0x4b, 0x11, 0xc7, 0x60, 0x34, - 0x10, 0x78, 0xd6, 0xdf, 0xea, 0x0c, 0xba, 0x8c, 0x71, 0x11, 0x8b, 0x2f, 0xba, 0x6a, 0xd9, 0xef, - 0x77, 0xf7, 0xc4, 0xcd, 0x0a, 0xf6, 0x1f, 0xbd, 0x05, 0x95, 0x2f, 0xbb, 0xdd, 0x7e, 0x67, 0xa7, - 0xf7, 0xbc, 0xcb, 0x4c, 0xb0, 0x88, 0x23, 0x00, 0x75, 0x69, 0xb8, 0xfb, 0x04, 0x77, 0x0f, 0x9e, - 0x32, 0x33, 0x2b, 0xe2, 0xe0, 0x93, 0x96, 0xdb, 0xea, 0x1d, 0x6c, 0x76, 0xf0, 0x56, 0x77, 0x8b, - 0x19, 0x58, 0x11, 0x47, 0x00, 0xda, 0xab, 0x83, 0xfd, 0x41, 0x67, 0x87, 0x99, 0x57, 0x11, 0xf3, - 0x0f, 0xe5, 0x01, 0x94, 0xb8, 0x95, 0x50, 0xbc, 0x61, 0x39, 0x53, 0x5f, 0x44, 0x2a, 0xfc, 0x83, - 0xca, 0x6d, 0x4f, 0x7d, 0x0a, 0x16, 0xcb, 0x03, 0xfe, 0xa5, 0x10, 0x28, 0xf1, 0x38, 0x15, 0xdd, - 0x85, 0x12, 0x0d, 0xbd, 0x8d, 0xb1, 0xe8, 0xdd, 0xb5, 0x64, 0x24, 0xbb, 0xc9, 0xb0, 0x58, 0x50, - 0xa1, 0xf7, 0xe2, 0x27, 0xab, 0xab, 0x49, 0xf2, 0xd8, 0xd9, 0xea, 0x2f, 0x72, 0x50, 0x93, 0xb9, - 0x50, 0x13, 0x1a, 0xda, 0x96, 0x45, 0x86, 0xbe, 0xea, 0x12, 0xdf, 0x3d, 0x0d, 0x3a, 0x5b, 0x00, - 0x31, 0x85, 0x51, 0x5b, 0x60, 0xc1, 0x52, 0x78, 0xcc, 0x5f, 0xc4, 0x65, 0x0a, 0xa0, 0x9c, 0xe8, - 0x04, 0xf7, 0x0d, 0x21, 0x8e, 0x66, 0x1a, 0xc7, 0x44, 0x4d, 0xdc, 0x6c, 0x59, 0x0a, 0x31, 0x3d, - 0x81, 0x40, 0x5b, 0x70, 0x65, 0x62, 0x58, 0xc6, 0x64, 0x3a, 0x51, 0x43, 0xbd, 0xa5, 0x71, 0x5f, - 0x54, 0x94, 0x8f, 0xd0, 0x5b, 0x82, 0xaa, 0x23, 0x13, 0x05, 0x5c, 0x94, 0x9f, 0xe7, 0xa1, 0x2a, - 0x35, 0xef, 0x7f, 0x69, 0x33, 0xd8, 0xe6, 0x0b, 0x19, 0xdb, 0xbe, 0xa1, 0x51, 0xe7, 0x14, 0x09, - 0xc7, 0x15, 0x11, 0x45, 0xb8, 0xa7, 0x81, 0x98, 0xd1, 0x45, 0x0c, 0xae, 0x90, 0x59, 0x17, 0x31, - 0xb8, 0x42, 0x86, 0xdf, 0xca, 0x7f, 0xe4, 0xa0, 0x12, 0xae, 0x6b, 0xd2, 0x51, 0x4b, 0x2e, 0x23, - 0x6a, 0xb9, 0x0c, 0xc0, 0x89, 0xa4, 0x43, 0x68, 0x1e, 0x55, 0xf5, 0x05, 0x8f, 0x89, 0x3f, 0x55, - 0x75, 0xc3, 0x1b, 0xda, 0xc7, 0xc4, 0x3d, 0x15, 0xfb, 0x13, 0xb5, 0x89, 0x3f, 0xdd, 0x0a, 0x60, - 0x34, 0x22, 0xa0, 0xb3, 0x2a, 0xed, 0xcf, 0x89, 0xad, 0x07, 0x07, 0xa2, 0x55, 0x01, 0xdb, 0xb5, - 0x75, 0xba, 0x22, 0x5f, 0x14, 0x91, 0x5c, 0x7c, 0xa6, 0xab, 0x73, 0x68, 0x27, 0xfb, 0xb2, 0x4a, - 0x29, 0xb8, 0x18, 0x12, 0x5c, 0x56, 0xa1, 0x13, 0xa1, 0x3f, 0x74, 0xd4, 0x89, 0xe7, 0x89, 0x88, - 0xb6, 0xe4, 0x0f, 0x9d, 0x5d, 0xcf, 0x53, 0x1e, 0x41, 0x55, 0x5a, 0x9b, 0xa1, 0xbb, 0xb0, 0x2c, - 0x2f, 0xe4, 0xe2, 0xb1, 0xc6, 0x92, 0xb4, 0x70, 0xe3, 0x81, 0x86, 0xf2, 0xef, 0x39, 0x68, 0x24, - 0x56, 0x67, 0x67, 0x87, 0x40, 0x62, 0x8d, 0x17, 0xa9, 0x58, 0x1d, 0x57, 0x05, 0x8c, 0x0d, 0xdf, - 0x55, 0xa8, 0x1e, 0x11, 0xd3, 0x21, 0xae, 0x6a, 0x5b, 0x66, 0xd0, 0x6d, 0xc0, 0x41, 0xfb, 0x96, - 0xc9, 0xa6, 0x34, 0x9d, 0x8c, 0x88, 0xeb, 0x6a, 0x26, 0x67, 0xc2, 0xaf, 0xc9, 0xd4, 0x02, 0x20, - 0xe3, 0x72, 0x0f, 0x56, 0xd8, 0xe5, 0x12, 0x71, 0x75, 0x4d, 0x0d, 0xe4, 0xe1, 0x9b, 0x27, 0xcb, - 0x32, 0xae, 0x2b, 0x64, 0x7b, 0x0f, 0x96, 0x4c, 0xdb, 0x1a, 0x9b, 0xec, 0xf2, 0x4a, 0x40, 0x5f, - 0xe2, 0xd3, 0x6f, 0x88, 0x10, 0xc4, 0xca, 0x47, 0xb0, 0xbe, 0xeb, 0x24, 0xda, 0x2d, 0xfc, 0xc5, - 0xcc, 0xd6, 0x2b, 0x7f, 0x9b, 0x83, 0xb5, 0x54, 0x29, 0x6e, 0x9d, 0xb3, 0xbb, 0x4c, 0x9e, 0x07, - 0xf9, 0x46, 0x75, 0x34, 0x73, 0xc4, 0xe7, 0x3a, 0xd1, 0x55, 0xd2, 0x5c, 0xf7, 0x3e, 0x2c, 0x8b, - 0xcb, 0x2f, 0xae, 0x71, 0xa8, 0x86, 0x6c, 0x8a, 0xc1, 0xbd, 0x68, 0x7d, 0x7f, 0xc4, 0x76, 0x54, - 0xc2, 0x89, 0xa8, 0x21, 0x91, 0xb3, 0x39, 0x89, 0xf7, 0x57, 0x2d, 0x20, 0x3d, 0xa0, 0x43, 0xfe, - 0x07, 0x39, 0x58, 0x4a, 0x35, 0x03, 0x7d, 0x37, 0xe1, 0x94, 0xaf, 0x4b, 0xf3, 0x58, 0x76, 0x4f, - 0x85, 0xfe, 0xf9, 0x41, 0xdc, 0x3f, 0x5f, 0x3b, 0xa3, 0x64, 0xcc, 0x55, 0x77, 0xa0, 0x2e, 0x56, - 0xf6, 0xa2, 0xeb, 0x67, 0xad, 0x7d, 0xa5, 0xde, 0xcd, 0xc7, 0x87, 0xe4, 0x0f, 0x73, 0x50, 0x13, - 0x3c, 0xc2, 0x6b, 0x5c, 0xaf, 0xc6, 0x82, 0x2a, 0xac, 0x6f, 0xfb, 0xd4, 0x11, 0x88, 0xcb, 0x7f, - 0xcc, 0xf4, 0x18, 0xa8, 0xcf, 0x36, 0x2b, 0x6f, 0xc0, 0xa2, 0x20, 0x90, 0x77, 0x20, 0xeb, 0xb8, - 0xce, 0x69, 0x82, 0xfd, 0xc7, 0x7f, 0xca, 0xc3, 0x86, 0xb0, 0x44, 0x93, 0x5f, 0x63, 0xdd, 0x67, - 0x91, 0x73, 0x30, 0x0f, 0xdd, 0x01, 0xa4, 0x99, 0x2f, 0xb5, 0x53, 0x8f, 0xc6, 0x7c, 0x8e, 0xe6, - 0x12, 0x75, 0x12, 0xdd, 0x71, 0xe7, 0x98, 0x4d, 0x8e, 0xd8, 0x25, 0x3a, 0xba, 0x07, 0xab, 0xc6, - 0xd8, 0xb2, 0x5d, 0x1a, 0x71, 0x32, 0xc9, 0x54, 0x93, 0x58, 0x63, 0xff, 0x28, 0x38, 0x8b, 0xe3, - 0xc8, 0x8e, 0x47, 0x45, 0xdc, 0x61, 0x18, 0xba, 0x66, 0x08, 0xf6, 0x89, 0xc3, 0x2a, 0x98, 0xc1, - 0xb3, 0x35, 0x03, 0xd7, 0xae, 0xf5, 0x80, 0x42, 0x54, 0xc5, 0x04, 0x76, 0x7b, 0x74, 0x95, 0x78, - 0x29, 0x54, 0x3c, 0xd5, 0xb0, 0xb4, 0xa1, 0x4f, 0xbd, 0x1a, 0x2b, 0x1e, 0xec, 0xb8, 0xae, 0x87, - 0x04, 0x3d, 0x81, 0x67, 0xa5, 0x99, 0xf3, 0xe2, 0x9d, 0xa9, 0x6a, 0xc6, 0xd8, 0x09, 0x36, 0x38, - 0xc5, 0xb5, 0x7d, 0x63, 0xec, 0xa0, 0xcf, 0xa1, 0x2d, 0x1a, 0x63, 0x91, 0x13, 0x5f, 0x65, 0xfb, - 0xcd, 0x63, 0x47, 0x9d, 0x10, 0xdf, 0x35, 0x86, 0xc2, 0x46, 0xd7, 0x38, 0xc5, 0x1e, 0x39, 0xf1, - 0x9f, 0xda, 0x4e, 0x6f, 0xec, 0xec, 0x32, 0xac, 0xf2, 0x8f, 0x79, 0x68, 0x67, 0x76, 0x2b, 0x1f, - 0xef, 0xff, 0xeb, 0xd5, 0xd7, 0xea, 0xd5, 0x3f, 0xc9, 0xc1, 0x6a, 0x66, 0xaf, 0xa2, 0x47, 0x09, - 0x3f, 0x70, 0x23, 0xb5, 0x07, 0x98, 0xa5, 0xdd, 0xa1, 0x2f, 0xf8, 0x3c, 0xee, 0x0b, 0xde, 0x3e, - 0xa7, 0x74, 0xcc, 0x1f, 0xdc, 0x87, 0xb5, 0x67, 0x1e, 0x61, 0x2b, 0x71, 0xc7, 0x64, 0x77, 0xf9, - 0xbd, 0x73, 0x7d, 0xf2, 0x3d, 0x58, 0x4d, 0x96, 0x39, 0xc7, 0x23, 0x2b, 0x3f, 0x05, 0xa0, 0x2b, - 0x7e, 0xc1, 0xfa, 0x36, 0x2c, 0xf1, 0xcd, 0x87, 0x89, 0xe0, 0x41, 0x97, 0x78, 0xbc, 0x44, 0x83, - 0x21, 0x02, 0xde, 0x1d, 0xb6, 0x1d, 0x32, 0xd1, 0x4e, 0x58, 0x48, 0x14, 0x1c, 0x72, 0xb0, 0xa9, - 0x4b, 0x00, 0x59, 0xed, 0xca, 0x4f, 0xa0, 0xd2, 0x0d, 0x97, 0x51, 0x6f, 0x9c, 0xbb, 0x0a, 0x45, - 0xca, 0x1d, 0xdd, 0x49, 0x0c, 0xd3, 0x4a, 0x7c, 0xbf, 0x3a, 0x31, 0x2a, 0xb3, 0xef, 0x26, 0x86, - 0xa2, 0x06, 0x83, 0x70, 0x0f, 0xa0, 0x17, 0xf5, 0x4e, 0x4a, 0xa6, 0x5c, 0x86, 0x4c, 0x1f, 0x42, - 0xa5, 0x17, 0xb6, 0xf8, 0x42, 0x25, 0x54, 0x28, 0xf6, 0xce, 0x69, 0x45, 0xef, 0x55, 0x5a, 0xd1, - 0x4b, 0xb6, 0xe2, 0x97, 0x39, 0x68, 0x26, 0xf5, 0x02, 0x7d, 0x96, 0xa8, 0x4d, 0x9a, 0xa8, 0xb2, - 0xf5, 0x2e, 0xac, 0xf9, 0x93, 0x78, 0xcd, 0x57, 0x67, 0x17, 0x94, 0xa5, 0x40, 0x0a, 0x14, 0xc9, - 0xe1, 0xd8, 0x49, 0xbf, 0xc7, 0xa1, 0xbd, 0x8e, 0x19, 0x8e, 0xd2, 0x18, 0x94, 0x26, 0xf5, 0xe6, - 0xa5, 0xc7, 0x68, 0x28, 0x4e, 0x79, 0x2c, 0x66, 0x96, 0x81, 0xe6, 0x8e, 0x89, 0xbf, 0x4b, 0x26, - 0x87, 0xc4, 0xf5, 0x8e, 0x0c, 0x69, 0x90, 0xe2, 0x11, 0x55, 0x2e, 0x1d, 0x51, 0x29, 0x1d, 0xe1, - 0x46, 0x93, 0x3c, 0xc2, 0x51, 0x3b, 0x9f, 0x45, 0xe8, 0x34, 0x92, 0x3c, 0xce, 0x75, 0x1a, 0xd9, - 0x82, 0x5f, 0xd4, 0x69, 0x64, 0x8a, 0x1c, 0x8c, 0xf4, 0x4f, 0xe1, 0xca, 0x8e, 0x6d, 0x8d, 0x77, - 0x68, 0x04, 0xf4, 0x8a, 0x01, 0xdd, 0x05, 0xc2, 0x59, 0xe5, 0x57, 0x39, 0xb8, 0x3c, 0x8b, 0xff, - 0x6f, 0x32, 0xf4, 0xbb, 0x0d, 0x4b, 0x6c, 0x03, 0x2b, 0x26, 0x1f, 0x8f, 0x3b, 0x1a, 0x14, 0x81, - 0xa5, 0x90, 0xfb, 0x21, 0xb4, 0x53, 0xb4, 0xae, 0x4a, 0x4e, 0x1c, 0xc3, 0x0d, 0x43, 0xe6, 0xf5, - 0x44, 0x21, 0xb7, 0xcb, 0xd1, 0xca, 0x9f, 0xe6, 0xa0, 0x35, 0xab, 0x81, 0xe8, 0x07, 0x89, 0x71, - 0x95, 0x5e, 0x26, 0x9c, 0xdd, 0xe9, 0xe1, 0xd0, 0x3e, 0x8a, 0x0f, 0xed, 0xcd, 0xf3, 0x19, 0xc4, - 0x46, 0xf7, 0x9f, 0x8b, 0xb0, 0x20, 0xe2, 0x3b, 0xf4, 0x25, 0x2c, 0x4f, 0x1c, 0x35, 0x75, 0xd8, - 0xc4, 0x25, 0xdb, 0x38, 0x23, 0xe8, 0xc4, 0x4b, 0x93, 0x54, 0xb8, 0xfb, 0x41, 0xd8, 0x32, 0x2e, - 0xd8, 0x7a, 0xea, 0xb4, 0x29, 0xd1, 0x90, 0xe4, 0x49, 0x64, 0xe1, 0xc2, 0x27, 0x91, 0x3f, 0x82, - 0xf5, 0x60, 0x49, 0x26, 0x26, 0x3f, 0xd5, 0x76, 0x82, 0x53, 0xe4, 0x84, 0x3b, 0xc9, 0x9c, 0x24, - 0xf1, 0xaa, 0x9b, 0x39, 0x55, 0x3f, 0x05, 0x34, 0xf5, 0x48, 0x34, 0xb5, 0x70, 0x7f, 0x3b, 0x9f, - 0x3c, 0x7f, 0x4a, 0xba, 0x28, 0xdc, 0x9c, 0x26, 0x3d, 0x63, 0xea, 0x8c, 0xa0, 0x94, 0x6c, 0xdd, - 0xec, 0x33, 0x82, 0xb0, 0x79, 0x3e, 0x33, 0x53, 0x75, 0x12, 0xda, 0xa9, 0x38, 0xa8, 0xbc, 0x7a, - 0x8e, 0x39, 0x8b, 0xe6, 0xa5, 0x9c, 0x8a, 0x06, 0x1b, 0x74, 0xdd, 0xa6, 0xf2, 0x15, 0x5d, 0x6a, - 0xdc, 0xf9, 0xc1, 0xa6, 0x72, 0xbe, 0x42, 0xe1, 0x96, 0x39, 0x03, 0xa3, 0x4c, 0xa1, 0xc4, 0x1b, - 0x86, 0x36, 0xa0, 0x62, 0x38, 0x6a, 0xec, 0x4a, 0x43, 0xd9, 0x70, 0x04, 0xf2, 0x1d, 0x68, 0x4c, - 0x34, 0xef, 0x1b, 0x11, 0x2c, 0xaa, 0x13, 0xc3, 0x12, 0xae, 0xa2, 0x4e, 0xc1, 0x3c, 0x50, 0xdc, - 0x35, 0xac, 0x14, 0x9d, 0x76, 0x22, 0x96, 0x13, 0x32, 0x9d, 0x76, 0xa2, 0xfc, 0x71, 0x0e, 0x20, - 0xba, 0x4f, 0xfa, 0x6b, 0x5e, 0xfa, 0xa5, 0x30, 0xd3, 0xf0, 0x7c, 0xf6, 0x6c, 0xa9, 0x82, 0xd9, - 0x7f, 0x76, 0x8f, 0x31, 0x5a, 0xad, 0x24, 0xef, 0x31, 0x32, 0x0c, 0x0e, 0x29, 0x94, 0x6d, 0x28, - 0xef, 0x6a, 0xfe, 0xf0, 0x88, 0x0a, 0x73, 0x33, 0x26, 0x8c, 0x34, 0xc7, 0x32, 0x8a, 0x73, 0xee, - 0x1f, 0x3f, 0x87, 0x5a, 0x2c, 0x78, 0xbe, 0x1b, 0x63, 0x26, 0xe9, 0xa4, 0x4c, 0x25, 0xf1, 0x5c, - 0x83, 0x92, 0x14, 0x90, 0xd7, 0xb1, 0xf8, 0x52, 0xfe, 0xad, 0x08, 0xb0, 0x69, 0x5b, 0xba, 0xc1, - 0x15, 0xff, 0x1e, 0x88, 0x17, 0x2f, 0x6a, 0x74, 0x89, 0x17, 0x25, 0x24, 0x3d, 0x20, 0x3e, 0xae, - 0x70, 0x2a, 0xda, 0xac, 0x4f, 0xa0, 0x16, 0x9e, 0x39, 0xd0, 0x42, 0xf9, 0x99, 0x85, 0xc2, 0xab, - 0x34, 0xb4, 0xd8, 0xf7, 0x60, 0x31, 0xb1, 0x52, 0x28, 0x24, 0xb7, 0x2c, 0xe5, 0xa6, 0xe0, 0x9a, - 0x26, 0x37, 0xff, 0x3e, 0x54, 0x83, 0xd2, 0xb4, 0xce, 0xe2, 0x6c, 0x41, 0x79, 0x31, 0x5a, 0xe3, - 0xa7, 0xe1, 0x53, 0x3e, 0xff, 0x94, 0x95, 0x9a, 0x9f, 0x59, 0xaa, 0x16, 0x12, 0xd2, 0x82, 0x5f, - 0xc0, 0x12, 0x5d, 0x06, 0xc4, 0x0b, 0x97, 0x66, 0x16, 0x6e, 0x90, 0x13, 0x7f, 0x53, 0x2e, 0x7f, - 0x15, 0xaa, 0xae, 0xf3, 0x8d, 0x41, 0xed, 0x6b, 0x6a, 0xfa, 0xcc, 0x76, 0xe7, 0x31, 0xb8, 0xfc, - 0xb9, 0xc1, 0xd4, 0xf4, 0xd1, 0x23, 0x80, 0xe8, 0x0d, 0x81, 0x38, 0x32, 0x95, 0x4e, 0x04, 0xa2, - 0xf1, 0x11, 0x66, 0x4e, 0x87, 0xb5, 0x12, 0x3e, 0x31, 0x40, 0x8f, 0x61, 0xd9, 0xa4, 0x26, 0x9e, - 0x90, 0xb0, 0x32, 0x53, 0xc2, 0x25, 0x46, 0x2e, 0xcb, 0xa8, 0x1c, 0x41, 0x25, 0xe4, 0x8d, 0x96, - 0xa1, 0x81, 0xf7, 0x9f, 0x0d, 0xba, 0xea, 0xe0, 0xeb, 0x7e, 0x57, 0x15, 0x87, 0x7c, 0xeb, 0xb0, - 0x2c, 0x01, 0x7b, 0x7b, 0x83, 0x2e, 0xde, 0xeb, 0xec, 0x34, 0x73, 0x09, 0x44, 0xf7, 0x85, 0x40, - 0xe4, 0xd1, 0x0a, 0x34, 0x25, 0xc4, 0xce, 0xfe, 0x66, 0x67, 0xa7, 0x59, 0x50, 0x46, 0xd0, 0x08, - 0x6b, 0xee, 0xf0, 0x47, 0xa9, 0xf7, 0x62, 0xca, 0x7c, 0x59, 0x6e, 0x79, 0x8c, 0x50, 0xd2, 0xe7, - 0x6b, 0x50, 0x0d, 0x5a, 0x6b, 0x84, 0xcf, 0x2e, 0x64, 0x90, 0xb2, 0x07, 0x95, 0x5d, 0xa2, 0x8b, - 0x1a, 0xde, 0x8b, 0xd5, 0xb0, 0x2e, 0x9f, 0x24, 0xe8, 0x29, 0xde, 0x2b, 0x30, 0x7f, 0xac, 0x99, - 0xd3, 0xe0, 0x55, 0x1a, 0xff, 0x50, 0x54, 0x68, 0x74, 0xbc, 0xbe, 0x4b, 0x1c, 0x62, 0x05, 0x5c, - 0x9b, 0x50, 0xd0, 0x3c, 0x4b, 0x44, 0x74, 0xf4, 0x2f, 0x35, 0x33, 0x4a, 0xa1, 0x85, 0x5b, 0xf4, - 0xfc, 0x0b, 0x29, 0x50, 0xa7, 0x13, 0x8a, 0x49, 0x46, 0xbe, 0x3a, 0xb1, 0x3d, 0x5f, 0xc4, 0x25, - 0xd5, 0xa9, 0x47, 0x76, 0xc8, 0xc8, 0xdf, 0xb5, 0xd9, 0x55, 0xc5, 0xba, 0xb8, 0x1a, 0x26, 0xd8, - 0x9f, 0xf9, 0xc2, 0xc7, 0x23, 0xe6, 0x48, 0xc4, 0x3e, 0xec, 0xbf, 0x72, 0x13, 0x1a, 0x3b, 0x6c, - 0x93, 0xd5, 0x25, 0x23, 0xc1, 0x20, 0x6c, 0x88, 0x38, 0x46, 0xe0, 0x0d, 0xf9, 0x87, 0x02, 0x2c, - 0x70, 0x02, 0x2f, 0xba, 0x9d, 0xa2, 0xf1, 0xc7, 0xc7, 0x29, 0x47, 0xc9, 0x94, 0x82, 0x53, 0x8b, - 0xdb, 0x29, 0x82, 0xf7, 0xa7, 0x50, 0x89, 0x4e, 0xd8, 0xf2, 0xc9, 0x6b, 0x29, 0x89, 0x81, 0xc3, - 0x11, 0x2d, 0xba, 0x01, 0x85, 0x89, 0x08, 0xcc, 0x62, 0x2b, 0x8d, 0x70, 0x24, 0x30, 0xc5, 0xa3, - 0xcf, 0x00, 0xa8, 0x85, 0xf3, 0xfe, 0x16, 0x06, 0x7e, 0x29, 0xe6, 0x1b, 0xe4, 0xa1, 0x60, 0x76, - 0xce, 0x01, 0xe8, 0x0b, 0xa8, 0xc7, 0xcc, 0x55, 0xd8, 0xf9, 0x19, 0xd2, 0xd5, 0x64, 0x8b, 0x45, - 0xf7, 0x60, 0x41, 0xdc, 0xdd, 0x13, 0x46, 0x2e, 0xa9, 0x4b, 0x6c, 0x80, 0x70, 0x40, 0x47, 0x85, - 0x15, 0x5b, 0xde, 0x2e, 0x19, 0x89, 0xc9, 0xf9, 0x92, 0x3c, 0x7f, 0xc6, 0xc6, 0x25, 0xd8, 0x0d, - 0x77, 0xc9, 0x08, 0x3d, 0x86, 0x46, 0xc2, 0x76, 0xc5, 0xf4, 0x7b, 0x86, 0xb8, 0x8b, 0x71, 0xf3, - 0x55, 0x7e, 0x96, 0x83, 0x4a, 0x78, 0xbf, 0x3a, 0x9c, 0x3d, 0x72, 0xd2, 0x44, 0xf6, 0x31, 0xc0, - 0x30, 0x74, 0x22, 0x62, 0xb4, 0x56, 0xb2, 0x1c, 0x0c, 0x96, 0xe8, 0xd0, 0x7b, 0xb0, 0xc0, 0xd5, - 0xc2, 0x13, 0xa3, 0x25, 0x5f, 0x1c, 0xe2, 0x08, 0x1c, 0x50, 0x28, 0x5f, 0x41, 0x49, 0x44, 0x65, - 0x59, 0x02, 0xc4, 0x5f, 0x68, 0xe4, 0x2f, 0xf6, 0x42, 0xe3, 0x5f, 0x72, 0xd0, 0x4c, 0x5e, 0xf1, - 0x41, 0xb7, 0x62, 0x96, 0xbc, 0x92, 0xbc, 0x0c, 0x24, 0x99, 0xb1, 0xfc, 0x78, 0x39, 0x7f, 0x81, - 0xc7, 0xcb, 0x19, 0x09, 0x25, 0x62, 0xaf, 0x16, 0x8a, 0xe7, 0xbd, 0x5a, 0x40, 0x1f, 0xc0, 0x82, - 0x4e, 0x46, 0x1a, 0x75, 0xf2, 0xf3, 0x67, 0x19, 0x52, 0x40, 0xa5, 0xfc, 0x51, 0x0e, 0x0a, 0xd8, - 0xd6, 0xd0, 0x22, 0xe4, 0xb5, 0x60, 0x3d, 0x9f, 0xd7, 0x3c, 0xf4, 0x16, 0x88, 0x09, 0xd6, 0x24, - 0x41, 0x40, 0x14, 0x01, 0xa8, 0x93, 0x99, 0x68, 0x0c, 0x25, 0x6e, 0x52, 0xf2, 0x2f, 0xe9, 0x9a, - 0x60, 0x31, 0x76, 0x73, 0x34, 0xb8, 0xb0, 0x37, 0x7f, 0xf6, 0x3b, 0x4b, 0xe5, 0x26, 0xbf, 0x2d, - 0x69, 0x6b, 0xe7, 0xbd, 0x9d, 0xe4, 0xcf, 0xc4, 0x18, 0x61, 0xf4, 0x4c, 0xcc, 0xb5, 0xb5, 0x8c, - 0x67, 0x62, 0x94, 0x88, 0xa1, 0x14, 0x0f, 0x0a, 0xcf, 0xdd, 0x51, 0xa6, 0x76, 0x2c, 0x42, 0xde, - 0xe5, 0x0b, 0xb9, 0x1a, 0xce, 0xbb, 0x3a, 0x0b, 0x19, 0xf9, 0xcd, 0x2f, 0x97, 0x07, 0x5f, 0x35, - 0x5c, 0xe6, 0x00, 0xcc, 0x1e, 0xcf, 0x8b, 0x7b, 0x65, 0xae, 0xcf, 0xc6, 0xa4, 0x86, 0xcb, 0x1c, - 0x80, 0x7d, 0x71, 0x45, 0x87, 0xdf, 0x69, 0xca, 0x1b, 0xba, 0xf2, 0xcb, 0x1c, 0x94, 0xf8, 0x95, - 0xec, 0x54, 0x1f, 0x6f, 0x40, 0x25, 0xda, 0x6d, 0x14, 0x0f, 0xed, 0xdd, 0x60, 0x7b, 0xf1, 0x2a, - 0x54, 0x69, 0xb4, 0x47, 0x2c, 0x7e, 0x6a, 0x54, 0xe0, 0x53, 0x36, 0x07, 0xb1, 0x53, 0xa3, 0x77, - 0xa1, 0x29, 0x08, 0x84, 0x4f, 0x16, 0x0a, 0x52, 0xc1, 0x0d, 0x0e, 0xef, 0x04, 0xe0, 0xd8, 0x2d, - 0xcc, 0xf9, 0xc4, 0x2d, 0xcc, 0x3b, 0x99, 0x0b, 0x0d, 0x71, 0xb6, 0x92, 0x5c, 0x4c, 0x28, 0x7f, - 0x97, 0x83, 0x0a, 0xbb, 0x6e, 0xda, 0xb3, 0x46, 0xf6, 0x6f, 0xe4, 0x32, 0xee, 0x4d, 0x68, 0x58, - 0xd3, 0x89, 0x2a, 0xdd, 0xb2, 0x15, 0x67, 0x91, 0x8b, 0xd6, 0x74, 0x22, 0xdf, 0x52, 0xbe, 0x04, - 0x65, 0x4b, 0x6c, 0x44, 0x05, 0x47, 0xdf, 0x16, 0xdf, 0x83, 0xa2, 0x6b, 0x7f, 0x8a, 0x0a, 0xef, - 0x21, 0xf0, 0xc3, 0xc6, 0xaa, 0x35, 0x9d, 0x74, 0x04, 0x48, 0xf9, 0x1e, 0xbb, 0x95, 0x8f, 0x8d, - 0x43, 0xda, 0x90, 0x40, 0xdb, 0x82, 0xfb, 0x9a, 0xa9, 0x47, 0x49, 0x61, 0x93, 0xf9, 0x7d, 0x4d, - 0xe5, 0x11, 0xcb, 0x73, 0x13, 0x96, 0x16, 0x2a, 0x78, 0xd1, 0xe2, 0xb7, 0x37, 0xa1, 0x1c, 0xf4, - 0x10, 0x02, 0x28, 0x6d, 0xef, 0xec, 0x3f, 0xee, 0xec, 0x34, 0xe7, 0x50, 0x05, 0xe6, 0x79, 0x8c, - 0xc2, 0xee, 0x2f, 0x74, 0xb6, 0x7e, 0xa8, 0xf6, 0xf6, 0x9a, 0x79, 0x54, 0x85, 0x05, 0xfa, 0x7f, - 0xff, 0xd9, 0xa0, 0x59, 0x40, 0x0b, 0x50, 0x78, 0x8e, 0x9f, 0x34, 0x8b, 0xb7, 0x7d, 0xa8, 0x4a, - 0x6b, 0x08, 0x76, 0xe1, 0x01, 0x77, 0x9f, 0xf4, 0x5e, 0x34, 0xe7, 0x50, 0x0d, 0xca, 0x7b, 0xdd, - 0xde, 0xf6, 0xd3, 0xc7, 0xfb, 0xb8, 0x99, 0xa3, 0x25, 0x06, 0x9d, 0x6d, 0xc1, 0xe7, 0x40, 0xed, - 0x77, 0x06, 0x4f, 0x9b, 0x05, 0x54, 0x87, 0xca, 0xe6, 0xfe, 0xee, 0xee, 0xb3, 0xbd, 0xde, 0xe0, - 0xeb, 0x66, 0x11, 0x2d, 0x41, 0xbd, 0xfb, 0x62, 0xa0, 0x46, 0xa0, 0x79, 0x1a, 0x83, 0xed, 0x74, - 0xf0, 0x76, 0x57, 0x02, 0x96, 0x6e, 0xbf, 0x0b, 0x95, 0x70, 0xb1, 0xc0, 0x6e, 0x5d, 0xed, 0x7d, - 0x2d, 0x5f, 0xbf, 0x02, 0x28, 0xf5, 0xf6, 0x9e, 0x77, 0xf1, 0xa0, 0x99, 0xbf, 0x7d, 0x1b, 0x9a, - 0xc9, 0xa5, 0x00, 0x2a, 0x41, 0xbe, 0xfb, 0x55, 0x73, 0x8e, 0xfe, 0x6e, 0x77, 0x9b, 0x39, 0xfa, - 0xbb, 0xd3, 0x6d, 0xe6, 0x6f, 0x7f, 0x20, 0x4e, 0x3a, 0xc5, 0xd4, 0x1e, 0x5d, 0xec, 0xa2, 0xfd, - 0xb0, 0xb9, 0xd9, 0xed, 0x0f, 0x38, 0x73, 0xdc, 0xfd, 0x61, 0x77, 0x93, 0x32, 0x7f, 0x06, 0xcb, - 0x19, 0xa1, 0x19, 0x6d, 0x46, 0x28, 0xad, 0xda, 0xd9, 0xda, 0x6a, 0xce, 0xd1, 0x18, 0x30, 0x02, - 0xe1, 0xee, 0xee, 0xfe, 0x73, 0x5a, 0xf1, 0x2a, 0x2c, 0xc9, 0x50, 0x71, 0x63, 0xec, 0xf6, 0xfb, - 0x50, 0x8f, 0xc5, 0x63, 0xb4, 0xcf, 0x76, 0xbb, 0x5b, 0xea, 0xee, 0x3e, 0x65, 0xd5, 0x80, 0x2a, - 0xfd, 0x08, 0xc8, 0x73, 0xb7, 0xef, 0x00, 0x44, 0x4e, 0x3f, 0xcc, 0x6c, 0x42, 0x3b, 0x61, 0xb7, - 0xbf, 0x8f, 0x85, 0xcc, 0xdd, 0x17, 0xec, 0x7f, 0xfe, 0xfe, 0xbf, 0x5e, 0x85, 0xf2, 0x36, 0xd5, - 0x89, 0x8e, 0x63, 0xa0, 0x1d, 0xa8, 0x4a, 0xef, 0x32, 0xd0, 0x5b, 0xb1, 0xa9, 0x28, 0xf1, 0xdc, - 0xa3, 0x7d, 0x79, 0x06, 0x56, 0x5c, 0xb7, 0x9e, 0x43, 0x3d, 0x80, 0xe8, 0xe5, 0x06, 0xda, 0x90, - 0xc9, 0x13, 0x8f, 0x3c, 0xda, 0x6f, 0x65, 0x23, 0x43, 0x56, 0x4f, 0xa0, 0x12, 0xbe, 0x57, 0x41, - 0xd2, 0xb2, 0x2e, 0xf9, 0xb0, 0xa5, 0xbd, 0x91, 0x89, 0x0b, 0xf9, 0xec, 0x40, 0x55, 0x4a, 0xb4, - 0x23, 0x37, 0x30, 0x9d, 0xb9, 0x47, 0x6e, 0x60, 0x56, 0x76, 0x9e, 0x39, 0xf4, 0x0c, 0x16, 0xe3, - 0x29, 0x76, 0xd0, 0x55, 0x79, 0x2d, 0x9d, 0x91, 0xb9, 0xa7, 0x7d, 0x6d, 0x36, 0x81, 0x2c, 0xa4, - 0x94, 0x54, 0x4a, 0x16, 0x32, 0x9d, 0xc7, 0x4a, 0x16, 0x32, 0x23, 0x13, 0x95, 0x32, 0x87, 0x30, - 0xd4, 0x63, 0xb9, 0x6b, 0xd0, 0x95, 0x98, 0x4b, 0x4c, 0x73, 0xbc, 0x3a, 0x13, 0x1f, 0xf2, 0xfc, - 0xff, 0xb0, 0x94, 0xca, 0x89, 0x83, 0x94, 0xf3, 0x73, 0xf3, 0xb4, 0xbf, 0x73, 0x26, 0x4d, 0xc8, - 0xff, 0xff, 0x41, 0x33, 0x99, 0xfb, 0x06, 0x49, 0xe7, 0xc3, 0x33, 0x52, 0xee, 0xb4, 0x95, 0xb3, - 0x48, 0xe4, 0x51, 0x8b, 0x67, 0xc2, 0x91, 0x47, 0x2d, 0x33, 0xad, 0x8e, 0x3c, 0x6a, 0x33, 0x92, - 0xe8, 0xcc, 0xa1, 0x17, 0xd0, 0x48, 0x24, 0xbb, 0x41, 0xf2, 0x60, 0x67, 0x66, 0xd8, 0x69, 0x5f, - 0x3f, 0x83, 0x22, 0xe4, 0xfc, 0x08, 0x4a, 0xdc, 0xb1, 0xa3, 0xf5, 0xd8, 0x60, 0x47, 0x4f, 0x29, - 0xda, 0xad, 0x34, 0x42, 0x56, 0x27, 0xe9, 0x39, 0x84, 0xac, 0x4e, 0xe9, 0x37, 0x19, 0xb2, 0x3a, - 0x65, 0xbd, 0xa1, 0x98, 0x43, 0x3f, 0x80, 0x05, 0x91, 0xce, 0x0b, 0xb5, 0x62, 0xf6, 0x21, 0xa5, - 0xed, 0x6a, 0x5f, 0xca, 0xc0, 0xc8, 0x6e, 0x21, 0x4a, 0x9e, 0x25, 0xbb, 0x85, 0x54, 0xfa, 0x2f, - 0xd9, 0x2d, 0x64, 0xe4, 0xdb, 0x9a, 0x43, 0x5b, 0x00, 0x51, 0xba, 0x17, 0x99, 0x55, 0x2a, 0x09, - 0x4c, 0x3b, 0xfb, 0xe5, 0x8c, 0x32, 0xf7, 0x61, 0x0e, 0x3d, 0x0c, 0xd3, 0xd9, 0x44, 0x97, 0x58, - 0xa5, 0x89, 0x32, 0xcc, 0xd1, 0xd6, 0x4e, 0x24, 0xda, 0x62, 0x85, 0x9f, 0x40, 0x25, 0xcc, 0x2f, - 0x24, 0x7b, 0xa6, 0x64, 0x76, 0x23, 0xd9, 0x33, 0xa5, 0x13, 0x12, 0xf1, 0x5e, 0x09, 0xb3, 0x0f, - 0xc5, 0x7a, 0x25, 0x99, 0xa8, 0x28, 0xd6, 0x2b, 0xe9, 0x84, 0x45, 0x73, 0xe8, 0x29, 0x54, 0xc2, - 0x8c, 0x41, 0xb2, 0x48, 0xc9, 0x3c, 0x46, 0xb2, 0x48, 0xe9, 0x14, 0x43, 0x73, 0xb7, 0x72, 0x54, - 0xf3, 0x78, 0xde, 0x1e, 0x59, 0xf3, 0x62, 0x29, 0x82, 0xda, 0xad, 0x34, 0x42, 0xf6, 0xda, 0x61, - 0x8a, 0x1e, 0x59, 0x90, 0x64, 0xe6, 0x9f, 0xf6, 0x46, 0x26, 0x4e, 0xd6, 0x39, 0x91, 0x94, 0x04, - 0x25, 0x14, 0x3d, 0xca, 0x66, 0x21, 0xeb, 0x5c, 0x22, 0x83, 0x49, 0xa8, 0xb5, 0x49, 0x0e, 0xf1, - 0x64, 0x25, 0x09, 0xad, 0x4d, 0x70, 0x08, 0xb5, 0x96, 0x31, 0x49, 0x09, 0x2c, 0xf3, 0x79, 0x2b, - 0x1b, 0x29, 0xb3, 0x8a, 0xf2, 0x85, 0xa0, 0x94, 0x5e, 0xcc, 0x60, 0x95, 0x91, 0x62, 0x84, 0xd9, - 0xb6, 0x94, 0x34, 0x04, 0xa5, 0x35, 0x43, 0x66, 0x76, 0x79, 0x06, 0x56, 0x1e, 0xaf, 0x30, 0xe5, - 0x87, 0x3c, 0x5e, 0xc9, 0xcc, 0x21, 0xf2, 0x78, 0xa5, 0x73, 0x84, 0xb0, 0x29, 0x27, 0x96, 0x3e, - 0x44, 0x9e, 0x72, 0xb2, 0x32, 0x91, 0xc8, 0x53, 0x4e, 0x76, 0xde, 0x91, 0xd0, 0x09, 0xda, 0x5a, - 0xd2, 0x09, 0x86, 0xeb, 0xb2, 0xa4, 0x13, 0x8c, 0xd6, 0x61, 0xbc, 0xa3, 0xa4, 0x54, 0x1f, 0x28, - 0xd5, 0xaf, 0x72, 0x3a, 0x13, 0xb9, 0xa3, 0xb2, 0xf2, 0x83, 0xcc, 0x09, 0xbb, 0xa0, 0xeb, 0xb6, - 0xb8, 0x5d, 0x44, 0x69, 0x3a, 0x12, 0x76, 0x21, 0xa7, 0xe2, 0x90, 0xec, 0x82, 0x72, 0x48, 0xd9, - 0x85, 0xc4, 0x64, 0x23, 0x13, 0x97, 0xe8, 0x93, 0x84, 0x18, 0xb1, 0xd4, 0x25, 0x89, 0x3e, 0x89, - 0x17, 0xc7, 0x6c, 0x61, 0x2b, 0x9d, 0x0b, 0x5c, 0x89, 0x11, 0xa7, 0x92, 0x58, 0xc8, 0xc3, 0x94, - 0x99, 0xf5, 0x83, 0xf3, 0x8c, 0x65, 0xe3, 0x90, 0x79, 0x66, 0xa5, 0xf9, 0x90, 0x79, 0x66, 0xa7, - 0xf1, 0x60, 0xd1, 0x40, 0x32, 0xe7, 0x86, 0x1c, 0x0d, 0xcc, 0x48, 0xf2, 0x21, 0x47, 0x03, 0x33, - 0x53, 0x76, 0xb0, 0x50, 0x26, 0x95, 0x70, 0x43, 0x0e, 0x65, 0x66, 0x65, 0xf4, 0x90, 0x43, 0x99, - 0xd9, 0x19, 0x3b, 0xe6, 0xd0, 0x3e, 0xd4, 0xe4, 0xe4, 0x1c, 0x28, 0x1e, 0xaf, 0x25, 0xf3, 0x50, - 0xb4, 0xaf, 0xcc, 0x42, 0xcb, 0x0c, 0xe5, 0xb4, 0x1a, 0x28, 0x1e, 0xa5, 0x9e, 0xc5, 0x30, 0x33, - 0x1b, 0x07, 0x0f, 0x5c, 0xe2, 0x09, 0x33, 0x50, 0x2a, 0x4a, 0x4d, 0xb1, 0xbd, 0x7e, 0x06, 0x85, - 0x3c, 0x70, 0xc9, 0x0c, 0x19, 0xf2, 0xc0, 0xcd, 0xc8, 0xc5, 0xd1, 0x56, 0xce, 0x22, 0x49, 0x2c, - 0x09, 0xc4, 0xe6, 0x5a, 0x7c, 0x49, 0x10, 0xcb, 0xf7, 0x90, 0x58, 0x12, 0x24, 0x92, 0x2b, 0x30, - 0x3e, 0x61, 0x3e, 0x01, 0x99, 0x4f, 0x32, 0xd1, 0x86, 0xcc, 0x27, 0x9d, 0x0a, 0x83, 0x8d, 0x8b, - 0x9c, 0x09, 0x40, 0x1e, 0x97, 0x8c, 0x1c, 0x19, 0xf2, 0xb8, 0x64, 0xa6, 0xaf, 0x10, 0x81, 0xbb, - 0xf4, 0xb4, 0x3f, 0x1e, 0xb8, 0xa7, 0x13, 0x5b, 0xc4, 0x03, 0xf7, 0xac, 0x4c, 0x12, 0x73, 0x48, - 0x67, 0x19, 0x64, 0x52, 0xbb, 0x87, 0x6f, 0x67, 0x74, 0x51, 0x2a, 0x4f, 0x41, 0xfb, 0xc6, 0x39, - 0x54, 0x72, 0x2d, 0x19, 0x29, 0x1a, 0xe4, 0x5a, 0x66, 0xe7, 0x86, 0x90, 0x6b, 0x39, 0x2b, 0xcf, - 0xc3, 0x1c, 0x9a, 0x04, 0x79, 0x64, 0x52, 0x15, 0xdd, 0xcc, 0xee, 0xdb, 0x74, 0x5d, 0xb7, 0xce, - 0x27, 0x0c, 0xab, 0x73, 0xc2, 0xe4, 0x31, 0xe9, 0xcd, 0xd7, 0x19, 0x1d, 0x9f, 0xae, 0xf0, 0xdd, - 0x0b, 0x50, 0xca, 0x71, 0x42, 0xb4, 0xa1, 0x83, 0x36, 0x92, 0x21, 0xbe, 0xb4, 0x49, 0xd4, 0x7e, - 0x2b, 0x1b, 0x19, 0xb0, 0x3a, 0x2c, 0xb1, 0xa4, 0xc8, 0x1f, 0xfd, 0x57, 0x00, 0x00, 0x00, 0xff, - 0xff, 0x0c, 0xb2, 0x36, 0x62, 0x23, 0x59, 0x00, 0x00, + 0xc3, 0x3e, 0xf8, 0x07, 0xf8, 0xe2, 0x83, 0x0f, 0x86, 0x61, 0xe4, 0xa3, 0xaa, 0xb2, 0x1e, 0xec, + 0x6e, 0x69, 0xb5, 0x36, 0x0c, 0xf8, 0x44, 0x56, 0x44, 0x64, 0x64, 0x64, 0x66, 0x44, 0x64, 0xe4, + 0x2b, 0xa0, 0x3a, 0xb6, 0x0f, 0xc7, 0xce, 0x5d, 0xc7, 0xb5, 0x7d, 0x1b, 0x95, 0xd9, 0x87, 0xe6, + 0x18, 0xca, 0x8f, 0x01, 0x6d, 0x13, 0x7f, 0x8f, 0x18, 0xe3, 0xa3, 0x43, 0xdb, 0xc5, 0xe4, 0xdb, + 0x29, 0xf1, 0x7c, 0x74, 0x1b, 0x9a, 0xc4, 0xd2, 0x0e, 0x4d, 0xd2, 0xd1, 0x8f, 0x89, 0xeb, 0x1b, + 0x1e, 0xd1, 0x5b, 0xb9, 0x6b, 0xb9, 0x5b, 0x65, 0x9c, 0x82, 0xa3, 0x16, 0x2c, 0x68, 0xba, 0xee, + 0x12, 0xcf, 0x6b, 0xe5, 0xaf, 0xe5, 0x6e, 0x55, 0x70, 0xf0, 0xa9, 0x3c, 0x84, 0xe5, 0x18, 0x6f, + 0xcf, 0xb1, 0x2d, 0x8f, 0xa0, 0xb7, 0x61, 0xde, 0x21, 0xc4, 0xf5, 0x5a, 0xb9, 0x6b, 0x85, 0x5b, + 0xd5, 0xfb, 0x8b, 0x77, 0x03, 0x61, 0xee, 0xf6, 0x09, 0x71, 0x31, 0x47, 0x2a, 0x63, 0xa8, 0x74, + 0xdc, 0xf1, 0x74, 0x42, 0x2c, 0xdf, 0x43, 0x77, 0xa1, 0xec, 0x12, 0xcf, 0x9e, 0xba, 0x43, 0xc2, + 0xe4, 0x58, 0xbc, 0x8f, 0xa2, 0x52, 0x58, 0x60, 0x70, 0x48, 0x83, 0xd6, 0xa0, 0x34, 0xd2, 0x26, + 0x86, 0x79, 0xca, 0x44, 0xaa, 0x63, 0xf1, 0x85, 0x10, 0x14, 0x2d, 0x6d, 0x42, 0x5a, 0x05, 0x26, + 0x28, 0xfb, 0xaf, 0xfc, 0x16, 0x2c, 0x76, 0x74, 0xbd, 0xaf, 0xf9, 0x47, 0x41, 0xeb, 0x5f, 0xb5, + 0xb6, 0x55, 0x28, 0x1d, 0xbb, 0x23, 0xd5, 0xd0, 0x45, 0x07, 0xcc, 0x1f, 0xbb, 0xa3, 0x9e, 0x8e, + 0x14, 0x28, 0x3a, 0x9a, 0x7f, 0xc4, 0x2a, 0x8b, 0x37, 0x93, 0xd6, 0xc5, 0x70, 0xca, 0x0d, 0x68, + 0x84, 0x95, 0x8b, 0xee, 0x41, 0x50, 0x9c, 0x4e, 0x0d, 0xde, 0xdf, 0x35, 0xcc, 0xfe, 0x2b, 0x3f, + 0xcf, 0xc1, 0xd2, 0x16, 0x31, 0x89, 0x4f, 0x7e, 0x0d, 0x72, 0x46, 0x9d, 0x55, 0x88, 0x75, 0x56, + 0x20, 0x7f, 0x71, 0xb6, 0xfc, 0xa1, 0xb0, 0xf3, 0x92, 0xb0, 0x2b, 0x80, 0x64, 0x59, 0x79, 0xb3, + 0x94, 0xcf, 0x00, 0x75, 0x74, 0x3d, 0xa9, 0x68, 0xb4, 0x0e, 0x42, 0x5c, 0x26, 0x7e, 0x5a, 0x15, + 0x18, 0x4e, 0x59, 0x85, 0xe5, 0x58, 0x49, 0xc1, 0xf0, 0x21, 0xac, 0xf2, 0x6a, 0x5e, 0x87, 0x67, + 0x0b, 0xd6, 0x92, 0x85, 0x05, 0xdb, 0xe7, 0xb0, 0x82, 0x89, 0x97, 0x36, 0x09, 0x49, 0xcd, 0x73, + 0x31, 0x35, 0x47, 0x6f, 0x43, 0x7d, 0x68, 0x4f, 0x26, 0x53, 0xcb, 0x18, 0x6a, 0xbe, 0x61, 0x5b, + 0xa2, 0x77, 0xe3, 0x40, 0x65, 0x1d, 0x56, 0x13, 0x7c, 0x45, 0x85, 0x7f, 0x95, 0x83, 0xd6, 0x81, + 0x3d, 0xf2, 0x5f, 0xb1, 0xd6, 0x03, 0xa8, 0xe8, 0x86, 0x4b, 0x86, 0x61, 0x8d, 0x8b, 0xf7, 0x3f, + 0x89, 0x9a, 0x3a, 0x8b, 0x61, 0x84, 0xd8, 0x0a, 0x0a, 0xe3, 0x88, 0x8f, 0xf2, 0x01, 0xa0, 0x34, + 0x01, 0x2a, 0x41, 0xbe, 0xb7, 0xd7, 0x9c, 0x43, 0x0b, 0x50, 0xd8, 0x7f, 0x36, 0x68, 0xe6, 0x50, + 0x19, 0x8a, 0x8f, 0xf7, 0x07, 0x4f, 0x9b, 0x79, 0x65, 0x03, 0x2e, 0x65, 0x54, 0x25, 0x5a, 0xf6, + 0x35, 0xac, 0x1f, 0x1c, 0x4d, 0x7d, 0xdd, 0x7e, 0x69, 0xbd, 0xe9, 0xde, 0x6c, 0x43, 0x2b, 0xcd, + 0x5a, 0x54, 0x7b, 0x0f, 0x56, 0xbb, 0xcc, 0x49, 0x5d, 0xb8, 0x52, 0xaa, 0x0e, 0xc9, 0x22, 0x82, + 0xd9, 0x0b, 0x58, 0xdb, 0x32, 0xbc, 0x57, 0xe2, 0x76, 0xc1, 0x26, 0x5c, 0x82, 0xf5, 0x14, 0x67, + 0x51, 0xe9, 0x18, 0x9a, 0x5c, 0x9c, 0x5d, 0xd7, 0x0f, 0xaa, 0xdb, 0x80, 0x8a, 0x3e, 0x9d, 0x38, + 0xaa, 0x7f, 0xea, 0x70, 0x6b, 0x9f, 0xc7, 0x65, 0x0a, 0x18, 0x9c, 0x3a, 0x04, 0xb5, 0xa1, 0x3c, + 0x32, 0x4c, 0xc2, 0x7c, 0x1b, 0xaf, 0x2c, 0xfc, 0xa6, 0x38, 0xc3, 0xf2, 0x89, 0x7b, 0xac, 0x99, + 0xcc, 0xc0, 0x8b, 0x38, 0xfc, 0x56, 0x96, 0x61, 0x49, 0xaa, 0x48, 0xd4, 0xbe, 0x0c, 0x4b, 0x42, + 0xb0, 0xa8, 0x7a, 0x66, 0xd4, 0x12, 0x50, 0x90, 0xfe, 0x0e, 0x34, 0x7b, 0xd6, 0x6f, 0x92, 0xa1, + 0x2f, 0x09, 0xfa, 0x86, 0xbc, 0x12, 0x9d, 0x25, 0x34, 0xff, 0xc8, 0x6b, 0x15, 0x52, 0xb3, 0x04, + 0x75, 0x2b, 0x1c, 0x49, 0x65, 0x95, 0x04, 0x10, 0x52, 0xfd, 0x59, 0x0e, 0xea, 0x1d, 0x5d, 0x7f, + 0x3c, 0x71, 0xce, 0x1f, 0x2b, 0x04, 0x45, 0xc7, 0x76, 0x7d, 0x31, 0x4f, 0xb0, 0xff, 0xe8, 0x7b, + 0x50, 0x64, 0xbd, 0x5c, 0x60, 0xd2, 0xdf, 0x8a, 0x6a, 0x8e, 0x31, 0xbd, 0xbb, 0x6b, 0x5b, 0x86, + 0x6f, 0xbb, 0x86, 0x35, 0xee, 0xdb, 0xa6, 0x31, 0x3c, 0xc5, 0xac, 0x94, 0xf2, 0x01, 0x34, 0x93, + 0x18, 0x6a, 0x39, 0x7d, 0xdc, 0x6d, 0xce, 0x51, 0xcb, 0xe9, 0xef, 0x1f, 0xc4, 0x6d, 0xa8, 0xc9, + 0x26, 0x20, 0xc6, 0x58, 0x34, 0xe0, 0x07, 0xd0, 0xe4, 0xde, 0xe9, 0x75, 0x9b, 0xc0, 0xc6, 0x30, + 0xe2, 0x20, 0xd8, 0x0e, 0x60, 0x49, 0x48, 0x86, 0x8d, 0xc3, 0x80, 0xef, 0x0d, 0x98, 0xf7, 0xe9, + 0xb0, 0x0a, 0x77, 0xd9, 0x88, 0x5a, 0x3b, 0xa0, 0x60, 0xcc, 0xb1, 0xb4, 0xfa, 0xe1, 0xd4, 0x75, + 0x89, 0xc5, 0xeb, 0x29, 0xe3, 0xe0, 0x53, 0xe9, 0x42, 0x19, 0xf7, 0xbf, 0xec, 0x6d, 0xda, 0xd6, + 0xe8, 0x0c, 0x21, 0xaf, 0x42, 0xd5, 0x25, 0x13, 0xdb, 0x27, 0x6a, 0x28, 0x6b, 0x05, 0x03, 0x07, + 0xf5, 0xa9, 0xc4, 0x7f, 0x52, 0x84, 0x0a, 0xe5, 0x73, 0xe0, 0x6b, 0x3e, 0x9b, 0xc0, 0xa7, 0x8e, + 0x6f, 0x4c, 0xb8, 0x58, 0x05, 0x2c, 0xbe, 0xa8, 0x32, 0x53, 0x9b, 0x67, 0x98, 0x3c, 0xc3, 0x84, + 0xdf, 0x68, 0x11, 0xf2, 0x53, 0x87, 0x0d, 0x5a, 0x19, 0xe7, 0xa7, 0x0e, 0xaf, 0x72, 0x68, 0xbb, + 0xba, 0x6a, 0x38, 0xc7, 0x1f, 0xb3, 0x69, 0xac, 0x4e, 0xab, 0xa4, 0xa0, 0x9e, 0x73, 0xfc, 0x71, + 0x9c, 0xe0, 0x01, 0x9b, 0xc3, 0x64, 0x82, 0x07, 0x94, 0xc0, 0x71, 0xc9, 0xc8, 0x38, 0xe1, 0x1c, + 0x4a, 0x9c, 0x80, 0x83, 0x02, 0x0e, 0x11, 0xc1, 0x83, 0xd6, 0x42, 0x82, 0xe0, 0x01, 0x6d, 0x87, + 0x47, 0x5c, 0x43, 0x33, 0x5b, 0x65, 0x3e, 0xb7, 0xf2, 0x2f, 0xf4, 0x1d, 0xa8, 0xbb, 0x64, 0x48, + 0x8c, 0x63, 0x22, 0xa4, 0xab, 0xb0, 0xc6, 0xd4, 0x02, 0x20, 0xe3, 0x9e, 0x20, 0x7a, 0xd0, 0x82, + 0x14, 0xd1, 0x03, 0x4a, 0xc4, 0x79, 0xaa, 0x96, 0xed, 0x1b, 0xa3, 0xd3, 0x56, 0x95, 0x13, 0x71, + 0xe0, 0x1e, 0x83, 0x51, 0x39, 0x87, 0xda, 0xf0, 0x88, 0xa8, 0x2e, 0x75, 0xd4, 0xad, 0x1a, 0x23, + 0x01, 0x06, 0x62, 0xae, 0x1b, 0xdd, 0x80, 0xc5, 0x90, 0x80, 0x29, 0x4b, 0xab, 0xce, 0x68, 0xea, + 0x01, 0x0d, 0x8f, 0x4d, 0xae, 0x40, 0x95, 0x58, 0xba, 0x6a, 0x8f, 0x54, 0x5d, 0xf3, 0xb5, 0xd6, + 0x22, 0xa3, 0xa9, 0x10, 0x4b, 0xdf, 0x1f, 0x6d, 0x69, 0xbe, 0x86, 0x56, 0x60, 0x9e, 0xb8, 0xae, + 0xed, 0xb6, 0x1a, 0x0c, 0xc3, 0x3f, 0xd0, 0x75, 0x10, 0xd2, 0xa8, 0xdf, 0x4e, 0x89, 0x7b, 0xda, + 0x6a, 0x32, 0x64, 0x95, 0xc3, 0xbe, 0xa2, 0x20, 0x3e, 0x14, 0x1e, 0xf1, 0x05, 0xc5, 0x12, 0x17, + 0x90, 0x81, 0x18, 0x81, 0xf2, 0x35, 0x14, 0xb1, 0xf3, 0x8d, 0x81, 0xde, 0x81, 0xe2, 0xd0, 0xb6, + 0x46, 0x42, 0x5b, 0x65, 0xcf, 0x22, 0x74, 0x10, 0x33, 0x3c, 0x7a, 0x17, 0xe6, 0x3d, 0xaa, 0x49, + 0x4c, 0x4b, 0xaa, 0xf7, 0x97, 0xe3, 0x84, 0x4c, 0xc9, 0x30, 0xa7, 0x50, 0x6e, 0xc1, 0xe2, 0x36, + 0xf1, 0x29, 0xf7, 0xc0, 0x26, 0xa2, 0x88, 0x28, 0x27, 0x47, 0x44, 0xca, 0x43, 0x68, 0x84, 0x94, + 0xa2, 0x47, 0x6e, 0xc1, 0x82, 0x47, 0xdc, 0xe3, 0xcc, 0x70, 0x96, 0x11, 0x06, 0x68, 0xe5, 0xc7, + 0xcc, 0xcc, 0xe5, 0x6a, 0x5e, 0xcd, 0x2b, 0xb5, 0xa1, 0x6c, 0x1a, 0x23, 0xc2, 0x54, 0xbf, 0xc0, + 0x55, 0x3f, 0xf8, 0x56, 0x96, 0x58, 0x18, 0x29, 0x0b, 0xa6, 0x74, 0x02, 0x0f, 0xf0, 0xda, 0x35, + 0x46, 0x81, 0x5c, 0x8c, 0xf1, 0xfb, 0xc1, 0x9c, 0x71, 0x21, 0xc6, 0x94, 0x89, 0x4c, 0x2e, 0x98, + 0xdc, 0x0d, 0xa7, 0x93, 0x8b, 0x71, 0x59, 0x85, 0xe5, 0x18, 0xbd, 0x60, 0x73, 0x07, 0x9a, 0x4c, + 0x7f, 0x2f, 0xc6, 0x64, 0x19, 0x96, 0x24, 0x6a, 0xc1, 0xe2, 0x43, 0x58, 0x09, 0x23, 0x98, 0x8b, + 0xb1, 0x59, 0x87, 0xd5, 0x44, 0x09, 0xc1, 0xea, 0x97, 0xb9, 0xa0, 0xad, 0x3f, 0x26, 0x87, 0xae, + 0x16, 0x70, 0x6a, 0x42, 0x61, 0xea, 0x9a, 0x82, 0x0b, 0xfd, 0xcb, 0xb4, 0xdd, 0x9e, 0xfa, 0x84, + 0x4d, 0xe6, 0x74, 0xd9, 0x54, 0x60, 0xce, 0x90, 0x82, 0xe8, 0x74, 0xee, 0xd1, 0xca, 0xa9, 0xce, + 0xd0, 0xd8, 0x81, 0xc7, 0xe4, 0xc1, 0x27, 0xfa, 0x18, 0xd6, 0x2c, 0x72, 0xe2, 0x1f, 0xd9, 0x8e, + 0xea, 0xbb, 0xc6, 0x78, 0x4c, 0x5c, 0x95, 0xaf, 0xc8, 0x98, 0x7f, 0x2b, 0xe3, 0x15, 0x81, 0x1d, + 0x70, 0x24, 0x17, 0x07, 0xdd, 0x87, 0xd5, 0x64, 0x29, 0x9d, 0x98, 0xda, 0xa9, 0xf0, 0x79, 0xcb, + 0xf1, 0x42, 0x5b, 0x14, 0x45, 0xbb, 0x3c, 0xd6, 0x18, 0xd1, 0xc8, 0x06, 0xd4, 0xb7, 0x89, 0xff, + 0xdc, 0x1d, 0x05, 0x91, 0xc1, 0x47, 0xcc, 0x7c, 0x18, 0x40, 0xd8, 0xc4, 0x75, 0x28, 0x1e, 0xbb, + 0xa3, 0xc0, 0x20, 0xea, 0x91, 0x41, 0x50, 0x22, 0x86, 0x52, 0x3e, 0x64, 0x33, 0x74, 0xc4, 0x05, + 0x5d, 0x85, 0xc2, 0xb1, 0x1b, 0x98, 0x75, 0xa2, 0x08, 0xc5, 0x88, 0x59, 0x52, 0xaa, 0x46, 0xf9, + 0x28, 0x98, 0x25, 0x5f, 0x85, 0x4d, 0x38, 0x31, 0xca, 0x9c, 0x9e, 0xc1, 0xca, 0x36, 0xf1, 0xb7, + 0xc8, 0xc8, 0xb0, 0x88, 0x7e, 0x40, 0xc2, 0x50, 0xe6, 0x5d, 0x11, 0x08, 0xf0, 0x30, 0x66, 0x35, + 0x62, 0x27, 0x48, 0xe9, 0x60, 0xf1, 0x59, 0x3f, 0x5c, 0x59, 0xe6, 0xa5, 0x95, 0x65, 0x07, 0x56, + 0x13, 0x6c, 0x43, 0xa7, 0x51, 0xf4, 0x88, 0x1f, 0x74, 0xd0, 0x4a, 0x8a, 0x2f, 0xa5, 0x65, 0x14, + 0xca, 0x17, 0xb0, 0xd2, 0xd1, 0xf5, 0xb4, 0x64, 0xef, 0x40, 0x81, 0x3a, 0x72, 0xde, 0xce, 0x6c, + 0x06, 0x94, 0x80, 0xea, 0x6a, 0xa2, 0xbc, 0x68, 0xf2, 0x01, 0xac, 0xf3, 0x7e, 0x78, 0x6d, 0xde, + 0x54, 0xaf, 0x35, 0xd3, 0x14, 0xe1, 0x00, 0xfd, 0x4b, 0xa3, 0xf2, 0x34, 0x53, 0x51, 0xe1, 0x63, + 0x68, 0x61, 0xe2, 0x98, 0xda, 0xf0, 0xf5, 0x6b, 0xa4, 0xab, 0x8d, 0x0c, 0x1e, 0xa2, 0x82, 0x55, + 0xb6, 0xdb, 0xc0, 0x3c, 0xfb, 0x84, 0x58, 0x61, 0xe0, 0xfa, 0x25, 0x1b, 0x5b, 0x09, 0x2c, 0xc6, + 0xe0, 0x23, 0x00, 0x2f, 0x00, 0x06, 0x23, 0x21, 0xcd, 0x12, 0x51, 0x01, 0x89, 0x4c, 0x79, 0xca, + 0x96, 0xa2, 0xc9, 0x3a, 0xd0, 0x3d, 0xa8, 0x84, 0x44, 0xa2, 0x15, 0x99, 0xac, 0x22, 0x2a, 0x65, + 0x8d, 0x0d, 0x6c, 0x4a, 0x2c, 0xe5, 0xa7, 0xc1, 0xc2, 0xf4, 0x0d, 0x54, 0x92, 0x31, 0x42, 0x97, + 0x82, 0x61, 0x4f, 0xd7, 0xbc, 0x03, 0xeb, 0xa2, 0x73, 0xdf, 0x44, 0xfb, 0xda, 0xe1, 0x70, 0xa7, + 0x6b, 0x42, 0xd0, 0xdc, 0x26, 0xbe, 0x08, 0x9a, 0xc5, 0x30, 0x75, 0x60, 0x49, 0x82, 0x89, 0x31, + 0xba, 0x03, 0x65, 0x87, 0x42, 0x0c, 0x12, 0x8c, 0x50, 0x53, 0x5a, 0x06, 0x70, 0xda, 0x90, 0x42, + 0x39, 0x81, 0x66, 0x47, 0xd7, 0x63, 0x6c, 0xd1, 0x2d, 0x28, 0x31, 0xfc, 0xa9, 0x10, 0x3b, 0x5d, + 0x5e, 0xe0, 0xd1, 0xe7, 0x70, 0xc9, 0x25, 0x23, 0xea, 0x4e, 0x4f, 0x0c, 0xcf, 0x37, 0xac, 0xb1, + 0x2a, 0xa9, 0x07, 0xef, 0xc1, 0x75, 0x46, 0xd0, 0x15, 0xf8, 0x83, 0x48, 0x2d, 0x96, 0x61, 0x49, + 0xaa, 0x59, 0xb4, 0xf2, 0x67, 0x39, 0x58, 0x16, 0xfb, 0x20, 0xaf, 0x29, 0xd2, 0x07, 0xb0, 0xec, + 0xd0, 0x10, 0xc8, 0x3d, 0x26, 0x69, 0x61, 0x50, 0x80, 0x8a, 0xe4, 0x08, 0xc6, 0xbb, 0x10, 0x8d, + 0xf7, 0x1a, 0xac, 0xc4, 0x65, 0x10, 0xc2, 0xfd, 0x79, 0x0e, 0x56, 0xc4, 0xf8, 0xfc, 0x0f, 0x74, + 0xd8, 0xac, 0x96, 0x15, 0x66, 0xb5, 0x8c, 0xef, 0x9e, 0xc4, 0xc4, 0x0d, 0xd7, 0xe7, 0xed, 0x50, + 0x6f, 0x3a, 0x9e, 0x67, 0x8c, 0x2d, 0x59, 0x71, 0x3f, 0x07, 0xd0, 0x42, 0xa0, 0x68, 0x51, 0x3b, + 0xd9, 0x22, 0xa9, 0x98, 0x44, 0xad, 0x7c, 0x0d, 0x1b, 0x99, 0x9c, 0x85, 0x6e, 0xfe, 0x2a, 0xac, + 0x5f, 0x40, 0x3b, 0xd4, 0x97, 0x37, 0x2b, 0xf4, 0x65, 0xd8, 0xc8, 0xe4, 0x2c, 0x7a, 0x6b, 0x02, + 0x97, 0x65, 0x75, 0x78, 0xa3, 0x75, 0x67, 0x78, 0x9b, 0x6b, 0x70, 0x65, 0x56, 0x75, 0x42, 0xa0, + 0x9f, 0xc0, 0x95, 0xd8, 0xb8, 0xbe, 0xd9, 0xde, 0xb8, 0x0e, 0x57, 0x67, 0x72, 0x8f, 0xf9, 0xa2, + 0x03, 0x16, 0xa3, 0x07, 0xbe, 0xe8, 0x11, 0xf3, 0x45, 0x01, 0x2c, 0x9c, 0xb3, 0x4b, 0x63, 0xd3, + 0x3e, 0xd4, 0xcc, 0xb4, 0x61, 0x6c, 0x33, 0x38, 0x16, 0x78, 0xe5, 0x0b, 0x40, 0x07, 0xbe, 0xe6, + 0xc6, 0x99, 0xbe, 0x42, 0xf9, 0x55, 0x58, 0x8e, 0x95, 0x8f, 0xb6, 0x65, 0x0e, 0x7c, 0xdb, 0x89, + 0x8b, 0xba, 0x42, 0xeb, 0x8a, 0x80, 0x82, 0xf4, 0x3f, 0x0b, 0x50, 0xec, 0x8b, 0xed, 0x59, 0xcb, + 0x74, 0x8d, 0x60, 0x2f, 0x99, 0xfe, 0xa7, 0x8b, 0x1b, 0x47, 0xf3, 0x7d, 0x97, 0xc7, 0x9d, 0x35, + 0x2c, 0xbe, 0xd8, 0xf0, 0x8d, 0x83, 0xa5, 0x05, 0xfd, 0x4b, 0x4b, 0x1f, 0x12, 0xcf, 0x17, 0x91, + 0x25, 0xfb, 0x4f, 0x43, 0x57, 0xc3, 0x53, 0x5f, 0x1a, 0xfe, 0x91, 0xee, 0x6a, 0x2f, 0x59, 0xfc, + 0x58, 0xc6, 0x60, 0x78, 0x3f, 0x12, 0x10, 0x74, 0x05, 0xe0, 0x58, 0x33, 0x0d, 0x9d, 0xef, 0x7c, + 0x95, 0xd8, 0x46, 0x95, 0x04, 0x41, 0x1f, 0xc2, 0x8a, 0x65, 0xab, 0xc6, 0xc4, 0xa1, 0x5e, 0xdb, + 0x8f, 0x38, 0x2d, 0x70, 0xdb, 0xb7, 0xec, 0x9e, 0x40, 0x85, 0x1c, 0xa3, 0xd5, 0x58, 0x39, 0xb6, + 0x3f, 0x7d, 0x19, 0x80, 0x6f, 0x21, 0xa9, 0x9a, 0x67, 0xb1, 0x05, 0x74, 0x1d, 0x57, 0x38, 0xa4, + 0xe3, 0x59, 0x68, 0x03, 0xc4, 0x87, 0x6a, 0xe8, 0x6c, 0xe5, 0x5c, 0xc1, 0x65, 0x0e, 0xe8, 0xe9, + 0x62, 0xc3, 0xcc, 0x27, 0x2e, 0xd1, 0xd9, 0x82, 0xb9, 0x8c, 0xc3, 0x6f, 0xba, 0x88, 0xf5, 0x7c, + 0xcd, 0x24, 0x6c, 0x99, 0x5c, 0xc6, 0xfc, 0x03, 0xdd, 0x82, 0xa6, 0xe1, 0xa9, 0x23, 0xd7, 0x9e, + 0xa8, 0xe4, 0xc4, 0x27, 0xae, 0xa5, 0x99, 0x6c, 0x8d, 0x5c, 0xc6, 0x8b, 0x86, 0xf7, 0xc4, 0xb5, + 0x27, 0x5d, 0x01, 0xa5, 0x5d, 0x64, 0x89, 0x1d, 0x3d, 0xd5, 0x70, 0xd8, 0x22, 0xb9, 0x82, 0x21, + 0x00, 0xf5, 0x9c, 0x70, 0xd3, 0xbc, 0x11, 0x6d, 0x9a, 0xa3, 0x3b, 0x80, 0x0c, 0x4f, 0x0d, 0x82, + 0x74, 0xc3, 0x62, 0x3d, 0xc6, 0x56, 0xca, 0x65, 0xdc, 0x34, 0xbc, 0x3d, 0x8e, 0xe8, 0x71, 0x38, + 0xed, 0x64, 0x43, 0x27, 0x96, 0x6f, 0x8c, 0x0c, 0xe2, 0xb2, 0xd5, 0x72, 0x1d, 0x4b, 0x10, 0xe5, + 0x4f, 0x73, 0x50, 0xdd, 0x22, 0xd4, 0xeb, 0xf2, 0x4e, 0xa7, 0x63, 0xce, 0x36, 0x25, 0xc4, 0x2a, + 0x44, 0x7c, 0x45, 0x9b, 0x6c, 0xf9, 0x33, 0x36, 0xd9, 0xd0, 0x4d, 0x68, 0x98, 0xb6, 0x45, 0x17, + 0x0d, 0xbc, 0x18, 0x09, 0x3c, 0xf5, 0x22, 0x07, 0xf7, 0x05, 0x14, 0xbd, 0x0b, 0x4d, 0xef, 0xc8, + 0x76, 0x7d, 0x99, 0x92, 0x2b, 0x4f, 0x43, 0xc0, 0x03, 0x52, 0xe5, 0x2f, 0x73, 0x30, 0xcf, 0x36, + 0x98, 0xe8, 0x8a, 0x5e, 0x0a, 0xb2, 0xb3, 0xf6, 0x0a, 0x67, 0x46, 0xd8, 0x33, 0x8f, 0x2e, 0xbe, + 0x0b, 0x35, 0x3d, 0x6a, 0x3e, 0x15, 0x82, 0x36, 0x2f, 0x16, 0xc0, 0x87, 0x58, 0x1c, 0x23, 0x65, + 0x5b, 0x3a, 0xb6, 0xe7, 0xab, 0x62, 0x16, 0x14, 0x0a, 0x4e, 0x41, 0xdc, 0x87, 0x28, 0x0f, 0xd8, + 0x02, 0xe8, 0x95, 0x77, 0xd0, 0x94, 0x4f, 0xf9, 0x36, 0x03, 0x2d, 0x27, 0x5c, 0xca, 0x05, 0x0b, + 0x9a, 0x80, 0x9e, 0x73, 0xfb, 0x21, 0x52, 0xad, 0x17, 0xed, 0xb6, 0x59, 0x47, 0x61, 0x91, 0x4a, + 0x14, 0x64, 0x95, 0xa0, 0xde, 0x27, 0x56, 0x5b, 0x70, 0x4a, 0x51, 0x84, 0x62, 0x9f, 0x10, 0x97, + 0x59, 0x0e, 0xe5, 0x10, 0xc4, 0x64, 0x75, 0x1c, 0x7e, 0xa3, 0xcf, 0xa0, 0xa6, 0x39, 0x8e, 0x79, + 0x1a, 0x74, 0x1e, 0xdf, 0x7b, 0x91, 0xba, 0xbd, 0x43, 0xb1, 0x62, 0x06, 0xaf, 0x6a, 0xd1, 0x47, + 0xb8, 0xad, 0x53, 0x48, 0x6e, 0xeb, 0xd0, 0x3a, 0xa5, 0x6d, 0x9d, 0x87, 0x50, 0x27, 0x87, 0x63, + 0x47, 0x9d, 0x4c, 0x4d, 0xdf, 0x38, 0xb2, 0x1d, 0x71, 0x38, 0xb5, 0x16, 0x15, 0xe8, 0x1e, 0x8e, + 0x9d, 0x5d, 0x81, 0xc5, 0x35, 0x22, 0x7d, 0xa1, 0x0e, 0x34, 0xf8, 0xb2, 0xdb, 0x25, 0x23, 0x93, + 0x0c, 0x7d, 0xdb, 0x65, 0xc3, 0x5b, 0xbd, 0xdf, 0x92, 0x7a, 0x8f, 0x12, 0xe0, 0x00, 0x8f, 0x17, + 0xdd, 0xd8, 0x37, 0xba, 0x09, 0x45, 0xc3, 0x1a, 0xd9, 0xcc, 0xaf, 0xc5, 0x82, 0x60, 0x2a, 0x27, + 0xdf, 0x55, 0x62, 0x04, 0xd4, 0xdd, 0xfb, 0xc6, 0x84, 0xb8, 0x1e, 0x73, 0x6c, 0x31, 0x77, 0x3f, + 0x60, 0x70, 0x2c, 0xf0, 0x34, 0xb8, 0xf6, 0x5d, 0xcd, 0xf2, 0xd8, 0xf6, 0x4b, 0x39, 0xc9, 0x77, + 0x10, 0xa0, 0x70, 0x44, 0x45, 0xfb, 0x99, 0x37, 0x84, 0xef, 0x2d, 0x31, 0xdf, 0x17, 0xeb, 0x67, + 0xd6, 0x0a, 0x31, 0x29, 0xf0, 0xad, 0x06, 0xfe, 0x81, 0xb6, 0xa0, 0x39, 0x76, 0xb5, 0x21, 0x19, + 0x4d, 0x4d, 0xd5, 0x25, 0x1e, 0x9d, 0x66, 0x98, 0x6f, 0xac, 0xde, 0xbf, 0x24, 0xcd, 0x47, 0x82, + 0x02, 0x73, 0x02, 0xdc, 0x18, 0xc7, 0x01, 0xe8, 0x2e, 0x54, 0xb4, 0x91, 0xa1, 0x7a, 0xda, 0xc8, + 0xf0, 0x5a, 0x55, 0x66, 0x5b, 0x4b, 0xd2, 0x20, 0x8f, 0x8c, 0x03, 0x6d, 0x64, 0xe0, 0xb2, 0xc6, + 0xff, 0x78, 0xca, 0xdf, 0xe6, 0xa0, 0x2a, 0x0d, 0x3d, 0xfa, 0x14, 0x2a, 0x86, 0xa5, 0xc6, 0xe2, + 0xcc, 0xb3, 0xa6, 0xf4, 0xb2, 0x61, 0x89, 0x82, 0xdf, 0x87, 0x3a, 0x39, 0xa1, 0x5d, 0x10, 0xd7, + 0xb0, 0xb3, 0x0a, 0xd7, 0x78, 0x81, 0x88, 0x81, 0x31, 0x91, 0x19, 0x14, 0xce, 0x67, 0xc0, 0x0b, + 0x08, 0xeb, 0xff, 0x6d, 0xa8, 0x72, 0x1f, 0xb6, 0x63, 0x4c, 0x8c, 0x99, 0x3b, 0x85, 0xe8, 0x3a, + 0xd4, 0x26, 0xda, 0x49, 0xe4, 0x05, 0xb9, 0xed, 0x55, 0x27, 0xda, 0x49, 0xe8, 0x2c, 0x3f, 0x86, + 0x35, 0x4f, 0x1c, 0x61, 0xa9, 0xfe, 0x91, 0x4b, 0xbc, 0x23, 0xdb, 0xd4, 0x55, 0x67, 0xe8, 0x0b, + 0x5f, 0xb6, 0x12, 0x60, 0x07, 0x01, 0xb2, 0x3f, 0xf4, 0x95, 0xff, 0x98, 0x87, 0x72, 0x60, 0x13, + 0xe8, 0x3b, 0x50, 0xd7, 0xa6, 0xfe, 0x91, 0xea, 0x68, 0x9e, 0xf7, 0xd2, 0x76, 0x75, 0xe1, 0xdd, + 0x6b, 0x14, 0xd8, 0x17, 0x30, 0x74, 0x0d, 0xaa, 0x3a, 0xf1, 0x86, 0xae, 0xe1, 0x48, 0x67, 0x51, + 0x32, 0x08, 0x5d, 0x82, 0xb2, 0x69, 0x0f, 0x35, 0x53, 0xd5, 0xbc, 0x60, 0xbb, 0x89, 0x7d, 0x77, + 0x98, 0x47, 0x0f, 0xe7, 0xb2, 0x60, 0x3b, 0xac, 0xc8, 0x38, 0x34, 0x02, 0x78, 0x47, 0xec, 0x20, + 0xae, 0xc3, 0x82, 0x43, 0x88, 0x4b, 0x99, 0xf0, 0x5d, 0xa5, 0x12, 0xfd, 0xec, 0x78, 0x74, 0x9e, + 0x66, 0x88, 0xb1, 0x6b, 0x4f, 0x1d, 0x66, 0x39, 0x15, 0x5c, 0xa1, 0x90, 0x6d, 0x0a, 0xa0, 0xf3, + 0x34, 0x43, 0x33, 0x6f, 0xc6, 0x77, 0xd0, 0xcb, 0x14, 0xc0, 0x0e, 0xb6, 0xf6, 0x60, 0xc9, 0x25, + 0x13, 0xfb, 0x98, 0xa8, 0x8e, 0x6b, 0x1c, 0x6b, 0x3e, 0x9d, 0xeb, 0x99, 0x91, 0x2c, 0xde, 0x57, + 0xd2, 0x4e, 0xe2, 0x2e, 0x66, 0xb4, 0x7d, 0x4e, 0xda, 0xf1, 0x70, 0xc3, 0x8d, 0x03, 0xe8, 0x34, + 0xcb, 0x2d, 0x67, 0x64, 0x6a, 0x8e, 0xaa, 0x6b, 0x13, 0xc7, 0xb0, 0xc6, 0xcc, 0x7e, 0xca, 0xb8, + 0xc9, 0x30, 0x4f, 0x4c, 0xcd, 0xd9, 0xe2, 0x70, 0x74, 0x03, 0x16, 0x3d, 0x62, 0xe9, 0xaa, 0x38, + 0xb8, 0xf3, 0x4f, 0x99, 0xad, 0xd4, 0x71, 0x9d, 0x42, 0x37, 0x03, 0x20, 0x6d, 0xa0, 0x38, 0xdb, + 0x18, 0x6a, 0x0e, 0xb3, 0x87, 0x1a, 0xae, 0x70, 0xc8, 0xa6, 0xc6, 0x1a, 0xc8, 0xbb, 0x97, 0x62, + 0x6b, 0x0c, 0xcb, 0xfb, 0x9b, 0x22, 0x17, 0x21, 0x6f, 0xe8, 0x2c, 0x90, 0xa8, 0xe0, 0xbc, 0xa1, + 0xa3, 0xcf, 0xa1, 0x2e, 0x4e, 0x14, 0x4c, 0xaa, 0x60, 0x5e, 0x6b, 0x31, 0x39, 0x75, 0x49, 0xea, + 0x87, 0x6b, 0x4e, 0xf4, 0xe1, 0x51, 0x75, 0x10, 0xe3, 0x28, 0x46, 0xaa, 0xc1, 0xd5, 0x81, 0x0f, + 0xa6, 0x18, 0xa6, 0xf7, 0x01, 0x45, 0xd1, 0x89, 0xe5, 0x13, 0x77, 0xa4, 0x0d, 0x09, 0x0b, 0x34, + 0x2a, 0x78, 0x29, 0x0c, 0x52, 0x02, 0x04, 0x8d, 0x0a, 0x8f, 0xdd, 0x11, 0x0b, 0x31, 0x2a, 0x6c, + 0x07, 0x0d, 0x5d, 0x83, 0x9a, 0x66, 0x9a, 0xf6, 0x4b, 0x95, 0x2a, 0xae, 0xe6, 0xb5, 0x10, 0x8f, + 0x3e, 0x18, 0x6c, 0xff, 0xa5, 0xd5, 0xf1, 0xd0, 0x3b, 0xd0, 0x70, 0x79, 0xd8, 0xad, 0x06, 0x1a, + 0xb1, 0xcc, 0x7a, 0xb8, 0x2e, 0xc0, 0x7d, 0xa6, 0x18, 0xca, 0x3d, 0x68, 0x24, 0x06, 0x0c, 0x95, + 0xa1, 0xb8, 0xb7, 0xbf, 0xd7, 0xe5, 0x87, 0xcd, 0x9d, 0x9d, 0x9d, 0x66, 0x0e, 0x55, 0x61, 0x01, + 0x77, 0xfb, 0x3b, 0x9d, 0xcd, 0x6e, 0x33, 0xaf, 0x7c, 0x09, 0x35, 0xd9, 0xc1, 0xa3, 0x16, 0x2c, + 0xf0, 0xed, 0xcf, 0xe0, 0x7e, 0x4a, 0xf0, 0xc9, 0x2c, 0x50, 0x50, 0xa9, 0xbe, 0x6f, 0x86, 0x16, + 0x28, 0x60, 0x03, 0xdf, 0x54, 0x7e, 0x37, 0x07, 0x8b, 0x71, 0x7f, 0x4f, 0x8d, 0x32, 0x31, 0x45, + 0xa8, 0x43, 0xd3, 0x08, 0x56, 0x1e, 0x65, 0xbc, 0x12, 0x9f, 0x0f, 0x36, 0x19, 0x0e, 0x3d, 0x84, + 0x76, 0xba, 0xd4, 0xd4, 0xa3, 0x71, 0x50, 0x78, 0xac, 0xb9, 0x9e, 0x2c, 0xc9, 0xf0, 0x3d, 0x5d, + 0xf9, 0x8b, 0x12, 0x54, 0xc2, 0xd9, 0xe3, 0xbf, 0xc1, 0xa4, 0xef, 0x42, 0x79, 0x42, 0x3c, 0x4f, + 0x1b, 0x8b, 0xe0, 0x2c, 0x36, 0xdd, 0xee, 0x0a, 0x0c, 0x0e, 0x69, 0x32, 0x5d, 0xc0, 0xfc, 0xb9, + 0x2e, 0xa0, 0x74, 0x86, 0x0b, 0x58, 0x38, 0xd3, 0x05, 0x94, 0x13, 0x2e, 0xe0, 0x16, 0x94, 0xbe, + 0x9d, 0x92, 0x29, 0xf1, 0xc4, 0x34, 0x27, 0xcd, 0xa4, 0x5f, 0x31, 0x38, 0x16, 0x78, 0x74, 0x3b, + 0xcb, 0x59, 0x70, 0x8b, 0xbd, 0xa0, 0x23, 0xa8, 0x5e, 0xd8, 0x11, 0xd4, 0xb2, 0x1c, 0x01, 0x3b, + 0x8b, 0xf3, 0x3c, 0xc3, 0xb6, 0xf8, 0xae, 0x06, 0xb3, 0xeb, 0x3a, 0xae, 0x09, 0x20, 0x1f, 0xe1, + 0x4f, 0x60, 0xcd, 0x9b, 0x3a, 0x74, 0x4a, 0x21, 0x3a, 0x75, 0x09, 0xda, 0xa1, 0x61, 0x1a, 0x3e, + 0x0d, 0xa7, 0x16, 0xd9, 0x39, 0xc0, 0x6a, 0x88, 0xdd, 0x94, 0x90, 0xb4, 0x8f, 0x68, 0xe0, 0xc3, + 0xf9, 0x72, 0xc3, 0x2e, 0x1f, 0x8e, 0x1d, 0xce, 0xf3, 0xfb, 0x50, 0xd5, 0xf4, 0x89, 0x11, 0x54, + 0xdb, 0x64, 0x0e, 0xf2, 0x4a, 0x46, 0x74, 0x72, 0xb7, 0x43, 0xc9, 0x78, 0xa0, 0x02, 0x5a, 0xf8, + 0x9f, 0x46, 0x75, 0xc1, 0xa9, 0xa2, 0x58, 0x4e, 0x84, 0xdf, 0x14, 0xa7, 0x0d, 0x87, 0xc4, 0xf1, + 0x89, 0x2e, 0x8c, 0x3d, 0xfc, 0xa6, 0x0b, 0x11, 0x2d, 0xba, 0x22, 0xb6, 0x2c, 0x5c, 0x41, 0x74, + 0x39, 0x6c, 0x19, 0xe6, 0xed, 0xa9, 0xaf, 0x7e, 0xdb, 0x5a, 0xe1, 0xe7, 0x4a, 0xf6, 0xd4, 0xff, + 0x8a, 0x2e, 0xb0, 0x46, 0xa6, 0xed, 0x78, 0xad, 0x55, 0x06, 0xe4, 0x1f, 0xca, 0x6d, 0x80, 0x48, + 0x38, 0x54, 0x82, 0xfc, 0xb3, 0x3e, 0x3f, 0x30, 0xdf, 0xda, 0xff, 0xd1, 0x5e, 0x33, 0x87, 0x00, + 0x4a, 0xfd, 0x27, 0x2f, 0xd4, 0xcd, 0x41, 0x33, 0xaf, 0xfc, 0x06, 0x94, 0x03, 0x4d, 0x45, 0xef, + 0x4b, 0xa2, 0xf3, 0x58, 0x62, 0x29, 0xa5, 0xcf, 0x52, 0x6b, 0x6e, 0x40, 0xd1, 0x0b, 0x4e, 0xb1, + 0x33, 0x49, 0x19, 0x5a, 0xf9, 0x45, 0x0e, 0x16, 0x04, 0x04, 0x29, 0x50, 0xdb, 0xdb, 0x1f, 0xf4, + 0x9e, 0xf4, 0x36, 0x3b, 0x83, 0xde, 0xfe, 0x1e, 0xab, 0xa5, 0x88, 0x63, 0x30, 0x1a, 0x08, 0x3c, + 0xeb, 0x6f, 0x75, 0x06, 0x5d, 0xc6, 0xb8, 0x88, 0xc5, 0x17, 0x5d, 0xb5, 0xec, 0xf7, 0xbb, 0x7b, + 0xe2, 0xe6, 0x05, 0xfb, 0x8f, 0xde, 0x82, 0xca, 0x97, 0xdd, 0x6e, 0xbf, 0xb3, 0xd3, 0x7b, 0xde, + 0x65, 0x26, 0x58, 0xc4, 0x11, 0x80, 0xba, 0x34, 0xdc, 0x7d, 0x82, 0xbb, 0x07, 0x4f, 0x99, 0x99, + 0x15, 0x71, 0xf0, 0x49, 0xcb, 0x6d, 0xf5, 0x0e, 0x36, 0x3b, 0x78, 0xab, 0xbb, 0xc5, 0x0c, 0xac, + 0x88, 0x23, 0x00, 0xed, 0xd5, 0xc1, 0xfe, 0xa0, 0xb3, 0xc3, 0xcc, 0xab, 0x88, 0xf9, 0x87, 0xf2, + 0x00, 0x4a, 0xdc, 0x4a, 0x28, 0xde, 0xb0, 0x9c, 0xa9, 0x2f, 0x22, 0x15, 0xfe, 0x41, 0xe5, 0xb6, + 0xa7, 0x3e, 0x05, 0x8b, 0xe5, 0x01, 0xff, 0x52, 0x08, 0x94, 0x78, 0x9c, 0x8a, 0xee, 0x42, 0x89, + 0x86, 0xde, 0xc6, 0x58, 0xf4, 0xee, 0x5a, 0x32, 0x92, 0xdd, 0x64, 0x58, 0x2c, 0xa8, 0xd0, 0x7b, + 0xf1, 0x93, 0xd7, 0xd5, 0x24, 0x79, 0xec, 0xec, 0xf5, 0x17, 0x39, 0xa8, 0xc9, 0x5c, 0xa8, 0x09, + 0x0d, 0x6d, 0xcb, 0x22, 0x43, 0x5f, 0x75, 0x89, 0xef, 0x9e, 0x06, 0x9d, 0x2d, 0x80, 0x98, 0xc2, + 0xa8, 0x2d, 0xb0, 0x60, 0x29, 0xbc, 0x06, 0x50, 0xc4, 0x65, 0x0a, 0xa0, 0x9c, 0xe8, 0x04, 0xf7, + 0x0d, 0x21, 0x8e, 0x66, 0x1a, 0xc7, 0x44, 0x4d, 0xdc, 0x7c, 0x59, 0x0a, 0x31, 0x3d, 0x81, 0x40, + 0x5b, 0x70, 0x65, 0x62, 0x58, 0xc6, 0x64, 0x3a, 0x51, 0x43, 0xbd, 0xa5, 0x71, 0x5f, 0x54, 0x94, + 0x8f, 0xd0, 0x5b, 0x82, 0xaa, 0x23, 0x13, 0x05, 0x5c, 0x94, 0x9f, 0xe7, 0xa1, 0x2a, 0x35, 0xef, + 0x7f, 0x69, 0x33, 0xd8, 0xe6, 0x0c, 0x19, 0xdb, 0xbe, 0xa1, 0x51, 0xe7, 0x14, 0x09, 0xc7, 0x15, + 0x11, 0x45, 0xb8, 0xa7, 0x81, 0x98, 0xd1, 0x45, 0x0d, 0xae, 0x90, 0x59, 0x17, 0x35, 0xb8, 0x42, + 0x86, 0xdf, 0xca, 0xbf, 0xe7, 0xa0, 0x12, 0xae, 0x6b, 0xd2, 0x51, 0x4b, 0x2e, 0x23, 0x6a, 0xb9, + 0x0c, 0xc0, 0x89, 0xa4, 0x43, 0x6a, 0x1e, 0x55, 0xf5, 0x05, 0x8f, 0x89, 0x3f, 0x55, 0x75, 0xc3, + 0x1b, 0xda, 0xc7, 0xc4, 0x3d, 0x15, 0xfb, 0x13, 0xb5, 0x89, 0x3f, 0xdd, 0x0a, 0x60, 0x34, 0x22, + 0xa0, 0xb3, 0x2a, 0xed, 0xcf, 0x89, 0xad, 0x07, 0x07, 0xa6, 0x55, 0x01, 0xdb, 0xb5, 0x75, 0xba, + 0x22, 0x5f, 0x14, 0x91, 0x5c, 0x7c, 0xa6, 0xab, 0x73, 0x68, 0x27, 0xfb, 0x32, 0x4b, 0x29, 0xb8, + 0x38, 0x12, 0x5c, 0x66, 0xa1, 0x13, 0xa1, 0x3f, 0x74, 0xd4, 0x89, 0xe7, 0x89, 0x88, 0xb6, 0xe4, + 0x0f, 0x9d, 0x5d, 0xcf, 0x53, 0x1e, 0x41, 0x55, 0x5a, 0x9b, 0xa1, 0xbb, 0xb0, 0x2c, 0x2f, 0xe4, + 0xe2, 0xb1, 0xc6, 0x92, 0xb4, 0x70, 0xe3, 0x81, 0x86, 0xf2, 0x6f, 0x39, 0x68, 0x24, 0x56, 0x67, + 0x67, 0x87, 0x40, 0x62, 0x8d, 0x17, 0xa9, 0x58, 0x1d, 0x57, 0x05, 0x8c, 0x0d, 0xdf, 0x55, 0xa8, + 0x1e, 0x11, 0xd3, 0x21, 0xae, 0x6a, 0x5b, 0x66, 0xd0, 0x6d, 0xc0, 0x41, 0xfb, 0x96, 0xc9, 0xa6, + 0x34, 0x9d, 0x8c, 0x88, 0xeb, 0x6a, 0x26, 0x67, 0xc2, 0xaf, 0xd1, 0xd4, 0x02, 0x20, 0xe3, 0x72, + 0x0f, 0x56, 0xd8, 0xe5, 0x13, 0x71, 0xb5, 0x4d, 0x0d, 0xe4, 0xe1, 0x9b, 0x27, 0xcb, 0x32, 0xae, + 0x2b, 0x64, 0x7b, 0x0f, 0x96, 0x4c, 0xdb, 0x1a, 0x9b, 0xec, 0x72, 0x4b, 0x40, 0x5f, 0xe2, 0xd3, + 0x6f, 0x88, 0x10, 0xc4, 0xca, 0x47, 0xb0, 0xbe, 0xeb, 0x24, 0xda, 0x2d, 0xfc, 0xc5, 0xcc, 0xd6, + 0x2b, 0x7f, 0x9d, 0x83, 0xb5, 0x54, 0x29, 0x6e, 0x9d, 0xb3, 0xbb, 0x4c, 0x9e, 0x07, 0xf9, 0x46, + 0x76, 0x34, 0x73, 0xc4, 0xe7, 0x3a, 0xd1, 0x55, 0xd2, 0x5c, 0xf7, 0x3e, 0x2c, 0x8b, 0xcb, 0x31, + 0xae, 0x71, 0xa8, 0x86, 0x6c, 0x8a, 0xc1, 0xbd, 0x69, 0x7d, 0x7f, 0xc4, 0x76, 0x54, 0xc2, 0x89, + 0xa8, 0x21, 0x91, 0xb3, 0x39, 0x89, 0xf7, 0x57, 0x2d, 0x20, 0x3d, 0xa0, 0x43, 0xfe, 0x7b, 0x39, + 0x58, 0x4a, 0x35, 0x03, 0x7d, 0x37, 0xe1, 0x94, 0xaf, 0x4b, 0xf3, 0x58, 0x76, 0x4f, 0x85, 0xfe, + 0xf9, 0x41, 0xdc, 0x3f, 0x5f, 0x3b, 0xa3, 0x64, 0xcc, 0x55, 0x77, 0xa0, 0x2e, 0x56, 0xf6, 0xa2, + 0xeb, 0x67, 0xad, 0x7d, 0xa5, 0xde, 0xcd, 0xc7, 0x87, 0xe4, 0xf7, 0x73, 0x50, 0x13, 0x3c, 0xc2, + 0x6b, 0x5e, 0xaf, 0xc6, 0x82, 0x2a, 0xac, 0x6f, 0xfb, 0xd4, 0x11, 0x88, 0xcb, 0x81, 0xcc, 0xf4, + 0x18, 0xa8, 0xcf, 0x36, 0x2b, 0x6f, 0xc0, 0xa2, 0x20, 0x90, 0x77, 0x20, 0xeb, 0xb8, 0xce, 0x69, + 0x82, 0xfd, 0xc7, 0x7f, 0xc8, 0xc3, 0x86, 0xb0, 0x44, 0x93, 0x5f, 0x73, 0xdd, 0x67, 0x91, 0x73, + 0x30, 0x0f, 0xdd, 0x01, 0xa4, 0x99, 0x2f, 0xb5, 0x53, 0x8f, 0xc6, 0x7c, 0x8e, 0xe6, 0x12, 0x75, + 0x12, 0xdd, 0x81, 0xe7, 0x98, 0x4d, 0x8e, 0xd8, 0x25, 0x3a, 0xba, 0x07, 0xab, 0xc6, 0xd8, 0xb2, + 0x5d, 0x1a, 0x71, 0x32, 0xc9, 0x54, 0x93, 0x58, 0x63, 0xff, 0x28, 0x38, 0xab, 0xe3, 0xc8, 0x8e, + 0x47, 0x45, 0xdc, 0x61, 0x18, 0xba, 0x66, 0x08, 0xf6, 0x91, 0xc3, 0x2a, 0x98, 0xc1, 0xb3, 0x35, + 0x03, 0xd7, 0xae, 0xf5, 0x80, 0x42, 0x54, 0xc5, 0x04, 0x76, 0x7b, 0x74, 0x95, 0x78, 0x29, 0x54, + 0x3c, 0xd5, 0xb0, 0xb4, 0xa1, 0x4f, 0xbd, 0x1a, 0x2b, 0x1e, 0xec, 0xb8, 0xae, 0x87, 0x04, 0x3d, + 0x81, 0x67, 0xa5, 0x99, 0xf3, 0xe2, 0x9d, 0xa9, 0x6a, 0xc6, 0xd8, 0x09, 0x36, 0x38, 0xc5, 0xb5, + 0x7e, 0x63, 0xec, 0xa0, 0xcf, 0xa1, 0x2d, 0x1a, 0x63, 0x91, 0x13, 0x5f, 0x65, 0xfb, 0xd1, 0x63, + 0x47, 0x9d, 0x10, 0xdf, 0x35, 0x86, 0xc2, 0x46, 0xd7, 0x38, 0xc5, 0x1e, 0x39, 0xf1, 0x9f, 0xda, + 0x4e, 0x6f, 0xec, 0xec, 0x32, 0xac, 0xf2, 0xf7, 0x79, 0x68, 0x67, 0x76, 0x2b, 0x1f, 0xef, 0xff, + 0xeb, 0xd5, 0xd7, 0xea, 0xd5, 0x3f, 0xca, 0xc1, 0x6a, 0x66, 0xaf, 0xa2, 0x47, 0x09, 0x3f, 0x70, + 0x23, 0xb5, 0x07, 0x98, 0xa5, 0xdd, 0xa1, 0x2f, 0xf8, 0x3c, 0xee, 0x0b, 0xde, 0x3e, 0xa7, 0x74, + 0xcc, 0x1f, 0xdc, 0x87, 0xb5, 0x67, 0x1e, 0x61, 0x2b, 0x71, 0xc7, 0x64, 0x77, 0xfd, 0xbd, 0x73, + 0x7d, 0xf2, 0x3d, 0x58, 0x4d, 0x96, 0x39, 0xc7, 0x23, 0x2b, 0x3f, 0x05, 0xa0, 0x2b, 0x7e, 0xc1, + 0xfa, 0x36, 0x2c, 0xf1, 0xcd, 0x87, 0x89, 0xe0, 0x41, 0x97, 0x78, 0xbc, 0x44, 0x83, 0x21, 0x02, + 0xde, 0x1d, 0xb6, 0x1d, 0x32, 0xd1, 0x4e, 0x58, 0x48, 0x14, 0x1c, 0x72, 0xb0, 0xa9, 0x4b, 0x00, + 0x59, 0xed, 0xca, 0x4f, 0xa0, 0xd2, 0x0d, 0x97, 0x51, 0x6f, 0x9c, 0xbb, 0x0a, 0x45, 0xca, 0x1d, + 0xdd, 0x49, 0x0c, 0xd3, 0x4a, 0x7c, 0xbf, 0x3a, 0x31, 0x2a, 0xb3, 0xef, 0x2e, 0x86, 0xa2, 0x06, + 0x83, 0x70, 0x0f, 0xa0, 0x17, 0xf5, 0x4e, 0x4a, 0xa6, 0x5c, 0x86, 0x4c, 0x1f, 0x42, 0xa5, 0x17, + 0xb6, 0xf8, 0x42, 0x25, 0x54, 0x28, 0xf6, 0xce, 0x69, 0x45, 0xef, 0x55, 0x5a, 0xd1, 0x4b, 0xb6, + 0xe2, 0x97, 0x39, 0x68, 0x26, 0xf5, 0x02, 0x7d, 0x96, 0xa8, 0x4d, 0x9a, 0xa8, 0xb2, 0xf5, 0x2e, + 0xac, 0xf9, 0x93, 0x78, 0xcd, 0x57, 0x67, 0x17, 0x94, 0xa5, 0x40, 0x0a, 0x14, 0xc9, 0xe1, 0xd8, + 0x49, 0xbf, 0xd7, 0xa1, 0xbd, 0x8e, 0x19, 0x8e, 0xd2, 0x18, 0x94, 0x26, 0xf5, 0x26, 0xa6, 0xc7, + 0x68, 0x28, 0x4e, 0x79, 0x2c, 0x66, 0x96, 0x81, 0xe6, 0x8e, 0x89, 0xbf, 0x4b, 0x26, 0x87, 0xc4, + 0xf5, 0x8e, 0x0c, 0x69, 0x90, 0xe2, 0x11, 0x55, 0x2e, 0x1d, 0x51, 0x29, 0x1d, 0xe1, 0x46, 0x93, + 0x3c, 0xc2, 0x51, 0x3b, 0x9f, 0x45, 0xe8, 0x34, 0x92, 0x3c, 0xce, 0x75, 0x1a, 0xd9, 0x82, 0x5f, + 0xd4, 0x69, 0x64, 0x8a, 0x1c, 0x8c, 0xf4, 0x4f, 0xe1, 0xca, 0x8e, 0x6d, 0x8d, 0x77, 0x68, 0x04, + 0xf4, 0x8a, 0x01, 0xdd, 0x05, 0xc2, 0x59, 0xe5, 0x9f, 0x72, 0x70, 0x79, 0x16, 0xff, 0x5f, 0x67, + 0xe8, 0x77, 0x1b, 0x96, 0xd8, 0x06, 0x56, 0x4c, 0x3e, 0x1e, 0x77, 0x34, 0x28, 0x02, 0x4b, 0x21, + 0xf7, 0x43, 0x68, 0xa7, 0x68, 0x5d, 0x95, 0x9c, 0x38, 0x86, 0x1b, 0x86, 0xcc, 0xeb, 0x89, 0x42, + 0x6e, 0x97, 0xa3, 0x95, 0x3f, 0xce, 0x41, 0x6b, 0x56, 0x03, 0xd1, 0x0f, 0x12, 0xe3, 0x2a, 0xbd, + 0x5c, 0x38, 0xbb, 0xd3, 0xc3, 0xa1, 0x7d, 0x14, 0x1f, 0xda, 0x9b, 0xe7, 0x33, 0x88, 0x8d, 0xee, + 0x3f, 0x16, 0x61, 0x41, 0xc4, 0x77, 0xe8, 0x4b, 0x58, 0x9e, 0x38, 0x6a, 0xea, 0xb0, 0x89, 0x4b, + 0xb6, 0x71, 0x46, 0xd0, 0x89, 0x97, 0x26, 0xa9, 0x70, 0xf7, 0x83, 0xb0, 0x65, 0x5c, 0xb0, 0xf5, + 0xd4, 0x69, 0x53, 0xa2, 0x21, 0xc9, 0x93, 0xc8, 0xc2, 0x85, 0x4f, 0x22, 0x7f, 0x04, 0xeb, 0xc1, + 0x92, 0x4c, 0x4c, 0x7e, 0xaa, 0xed, 0x04, 0xa7, 0xc8, 0x09, 0x77, 0x92, 0x39, 0x49, 0xe2, 0x55, + 0x37, 0x73, 0xaa, 0x7e, 0x0a, 0x68, 0xea, 0x91, 0x68, 0x6a, 0xe1, 0xfe, 0x76, 0x3e, 0x79, 0xfe, + 0x94, 0x74, 0x51, 0xb8, 0x39, 0x4d, 0x7a, 0xc6, 0xd4, 0x19, 0x41, 0x29, 0xd9, 0xba, 0xd9, 0x67, + 0x04, 0x61, 0xf3, 0x7c, 0x66, 0xa6, 0xea, 0x24, 0xb4, 0x53, 0x71, 0x50, 0x79, 0xf5, 0x1c, 0x73, + 0x16, 0xcd, 0x4b, 0x39, 0x15, 0x0d, 0x36, 0xe8, 0xba, 0x4d, 0xe5, 0x2b, 0xba, 0xd4, 0xb8, 0xf3, + 0x83, 0x4d, 0xe5, 0x7c, 0x85, 0xc2, 0x2d, 0x73, 0x06, 0x46, 0x99, 0x42, 0x89, 0x37, 0x0c, 0x6d, + 0x40, 0xc5, 0x70, 0xd4, 0xd8, 0x95, 0x86, 0xb2, 0xe1, 0x08, 0xe4, 0x3b, 0xd0, 0x98, 0x68, 0xde, + 0x37, 0x22, 0x58, 0x54, 0x27, 0x86, 0x25, 0x5c, 0x45, 0x9d, 0x82, 0x79, 0xa0, 0xb8, 0x6b, 0x58, + 0x29, 0x3a, 0xed, 0x44, 0x2c, 0x27, 0x64, 0x3a, 0xed, 0x44, 0xf9, 0xc3, 0x1c, 0x40, 0x74, 0xdf, + 0xf4, 0x57, 0xbc, 0x14, 0x4c, 0x61, 0xa6, 0xe1, 0xf9, 0xec, 0x59, 0x53, 0x05, 0xb3, 0xff, 0xec, + 0x9e, 0x63, 0xb4, 0x5a, 0x49, 0xde, 0x73, 0x64, 0x18, 0x1c, 0x52, 0x28, 0xdb, 0x50, 0xde, 0xd5, + 0xfc, 0xe1, 0x11, 0x15, 0xe6, 0x66, 0x4c, 0x18, 0x69, 0x8e, 0x65, 0x14, 0xe7, 0xdc, 0x4f, 0x7e, + 0x0e, 0xb5, 0x58, 0xf0, 0x7c, 0x37, 0xc6, 0x4c, 0xd2, 0x49, 0x99, 0x4a, 0xe2, 0xb9, 0x06, 0x25, + 0x29, 0x20, 0xaf, 0x63, 0xf1, 0xa5, 0xfc, 0x6b, 0x11, 0x60, 0xd3, 0xb6, 0x74, 0x83, 0x2b, 0xfe, + 0x3d, 0x10, 0x2f, 0x62, 0xd4, 0xe8, 0x92, 0x2f, 0x4a, 0x48, 0x7a, 0x40, 0x7c, 0x5c, 0xe1, 0x54, + 0xb4, 0x59, 0x9f, 0x40, 0x2d, 0x3c, 0x73, 0xa0, 0x85, 0xf2, 0x33, 0x0b, 0x85, 0x57, 0x6d, 0x68, + 0xb1, 0xef, 0xc1, 0x62, 0x62, 0xa5, 0x50, 0x48, 0x6e, 0x59, 0xca, 0x4d, 0xc1, 0x35, 0x4d, 0x6e, + 0xfe, 0x7d, 0xa8, 0x06, 0xa5, 0x69, 0x9d, 0xc5, 0xd9, 0x82, 0xf2, 0x62, 0xb4, 0xc6, 0x4f, 0xc3, + 0xa7, 0x7e, 0xfe, 0x29, 0x2b, 0x35, 0x3f, 0xb3, 0x54, 0x2d, 0x24, 0xa4, 0x05, 0xbf, 0x80, 0x25, + 0xba, 0x0c, 0x88, 0x17, 0x2e, 0xcd, 0x2c, 0xdc, 0x20, 0x27, 0xfe, 0xa6, 0x5c, 0xfe, 0x2a, 0x54, + 0x5d, 0xe7, 0x1b, 0x83, 0xda, 0xd7, 0xd4, 0xf4, 0x99, 0xed, 0xce, 0x63, 0x70, 0xf9, 0x73, 0x84, + 0xa9, 0xe9, 0xa3, 0x47, 0x00, 0xd1, 0x1b, 0x03, 0x71, 0x64, 0x2a, 0x9d, 0x08, 0x44, 0xe3, 0x23, + 0xcc, 0x9c, 0x0e, 0x6b, 0x25, 0x7c, 0x82, 0x80, 0x1e, 0xc3, 0xb2, 0x49, 0x4d, 0x3c, 0x21, 0x61, + 0x65, 0xa6, 0x84, 0x4b, 0x8c, 0x5c, 0x96, 0x51, 0x39, 0x82, 0x4a, 0xc8, 0x1b, 0x2d, 0x43, 0x03, + 0xef, 0x3f, 0x1b, 0x74, 0xd5, 0xc1, 0xd7, 0xfd, 0xae, 0x2a, 0x0e, 0xf9, 0xd6, 0x61, 0x59, 0x02, + 0xf6, 0xf6, 0x06, 0x5d, 0xbc, 0xd7, 0xd9, 0x69, 0xe6, 0x12, 0x88, 0xee, 0x0b, 0x81, 0xc8, 0xa3, + 0x15, 0x68, 0x4a, 0x88, 0x9d, 0xfd, 0xcd, 0xce, 0x4e, 0xb3, 0xa0, 0x8c, 0xa0, 0x11, 0xd6, 0xdc, + 0xe1, 0x8f, 0x56, 0xef, 0xc5, 0x94, 0xf9, 0xb2, 0xdc, 0xf2, 0x18, 0xa1, 0xa4, 0xcf, 0xd7, 0xa0, + 0x1a, 0xb4, 0xd6, 0x08, 0x9f, 0x65, 0xc8, 0x20, 0x65, 0x0f, 0x2a, 0xbb, 0x44, 0x17, 0x35, 0xbc, + 0x17, 0xab, 0x61, 0x5d, 0x3e, 0x49, 0xd0, 0x53, 0xbc, 0x57, 0x60, 0xfe, 0x58, 0x33, 0xa7, 0xc1, + 0xab, 0x35, 0xfe, 0xa1, 0xa8, 0xd0, 0xe8, 0x78, 0x7d, 0x97, 0x38, 0xc4, 0x0a, 0xb8, 0x36, 0xa1, + 0xa0, 0x79, 0x96, 0x88, 0xe8, 0xe8, 0x5f, 0x6a, 0x66, 0x94, 0x42, 0x0b, 0xb7, 0xe8, 0xf9, 0x17, + 0x52, 0xa0, 0x4e, 0x27, 0x14, 0x93, 0x8c, 0x7c, 0x75, 0x62, 0x7b, 0xbe, 0x88, 0x4b, 0xaa, 0x53, + 0x8f, 0xec, 0x90, 0x91, 0xbf, 0x6b, 0xb3, 0xab, 0x8c, 0x75, 0x71, 0x75, 0x4c, 0xb0, 0x3f, 0xf3, + 0x05, 0x90, 0x47, 0xcc, 0x91, 0x88, 0x7d, 0xd8, 0x7f, 0xe5, 0x26, 0x34, 0x76, 0xd8, 0x26, 0xab, + 0x4b, 0x46, 0x82, 0x41, 0xd8, 0x10, 0x71, 0x8c, 0xc0, 0x1b, 0xf2, 0x77, 0x05, 0x58, 0xe0, 0x04, + 0x5e, 0x74, 0x3b, 0x45, 0xe3, 0x8f, 0x93, 0x53, 0x8e, 0x92, 0x29, 0x05, 0xa7, 0x16, 0xb7, 0x53, + 0x04, 0xef, 0x4f, 0xa1, 0x12, 0x9d, 0xb0, 0xe5, 0x93, 0xd7, 0x52, 0x12, 0x03, 0x87, 0x23, 0x5a, + 0x74, 0x03, 0x0a, 0x13, 0x11, 0x98, 0xc5, 0x56, 0x1a, 0xe1, 0x48, 0x60, 0x8a, 0x47, 0x9f, 0x01, + 0x50, 0x0b, 0xe7, 0xfd, 0x2d, 0x0c, 0xfc, 0x52, 0xcc, 0x37, 0xc8, 0x43, 0xc1, 0xec, 0x9c, 0x03, + 0xd0, 0x17, 0x50, 0x8f, 0x99, 0xab, 0xb0, 0xf3, 0x33, 0xa4, 0xab, 0xc9, 0x16, 0x8b, 0xee, 0xc1, + 0x82, 0xb8, 0xdb, 0x27, 0x8c, 0x5c, 0x52, 0x97, 0xd8, 0x00, 0xe1, 0x80, 0x8e, 0x0a, 0x2b, 0xb6, + 0xbc, 0x5d, 0x32, 0x12, 0x93, 0xf3, 0x25, 0x79, 0xfe, 0x8c, 0x8d, 0x4b, 0xb0, 0x1b, 0xee, 0x92, + 0x11, 0x7a, 0x0c, 0x8d, 0x84, 0xed, 0x8a, 0xe9, 0xf7, 0x0c, 0x71, 0x17, 0xe3, 0xe6, 0xab, 0xfc, + 0x2c, 0x07, 0x95, 0xf0, 0xfe, 0x75, 0x38, 0x7b, 0xe4, 0xa4, 0x89, 0xec, 0x63, 0x80, 0x61, 0xe8, + 0x44, 0xc4, 0x68, 0xad, 0x64, 0x39, 0x18, 0x2c, 0xd1, 0xa1, 0xf7, 0x60, 0x81, 0xab, 0x85, 0x27, + 0x46, 0x4b, 0xbe, 0x38, 0xc4, 0x11, 0x38, 0xa0, 0x50, 0xbe, 0x82, 0x92, 0x88, 0xca, 0xb2, 0x04, + 0x88, 0xbf, 0xe0, 0xc8, 0x5f, 0xec, 0x05, 0xc7, 0x3f, 0xe7, 0xa0, 0x99, 0xbc, 0xe2, 0x83, 0x6e, + 0xc5, 0x2c, 0x79, 0x25, 0x79, 0x19, 0x48, 0x32, 0x63, 0xf9, 0x71, 0x73, 0xfe, 0x02, 0x8f, 0x9b, + 0x33, 0x12, 0x4e, 0xc4, 0x5e, 0x35, 0x14, 0xcf, 0x7b, 0xd5, 0x80, 0x3e, 0x80, 0x05, 0x9d, 0x8c, + 0x34, 0xea, 0xe4, 0xe7, 0xcf, 0x32, 0xa4, 0x80, 0x4a, 0xf9, 0x83, 0x1c, 0x14, 0xb0, 0xad, 0xa1, + 0x45, 0xc8, 0x6b, 0xc1, 0x7a, 0x3e, 0xaf, 0x79, 0xe8, 0x2d, 0x10, 0x13, 0xac, 0x49, 0x82, 0x80, + 0x28, 0x02, 0x50, 0x27, 0x33, 0xd1, 0x18, 0x4a, 0xdc, 0xa4, 0xe4, 0x5f, 0xd2, 0x35, 0xc1, 0x62, + 0xec, 0xe6, 0x68, 0x70, 0x61, 0x6f, 0xfe, 0xec, 0x77, 0x98, 0xca, 0x4d, 0x7e, 0x5b, 0xd2, 0xd6, + 0xce, 0x7b, 0x5b, 0xc9, 0x9f, 0x91, 0x31, 0xc2, 0xe8, 0x19, 0x99, 0x6b, 0x6b, 0x19, 0xcf, 0xc8, + 0x28, 0x11, 0x43, 0x29, 0x1e, 0x14, 0x9e, 0xbb, 0xa3, 0x4c, 0xed, 0x58, 0x84, 0xbc, 0xcb, 0x17, + 0x72, 0x35, 0x9c, 0x77, 0x75, 0x16, 0x32, 0xf2, 0x9b, 0x5f, 0x2e, 0x0f, 0xbe, 0x6a, 0xb8, 0xcc, + 0x01, 0x98, 0x3d, 0xae, 0x17, 0xf7, 0xca, 0x5c, 0x9f, 0x8d, 0x49, 0x0d, 0x97, 0x39, 0x00, 0xfb, + 0xe2, 0x8a, 0x0e, 0xbf, 0xd3, 0x94, 0x37, 0x74, 0xe5, 0x97, 0x39, 0x28, 0xf1, 0x2b, 0xdb, 0xa9, + 0x3e, 0xde, 0x80, 0x4a, 0xb4, 0xdb, 0x28, 0x1e, 0xe2, 0xbb, 0xc1, 0xf6, 0xe2, 0x55, 0xa8, 0xd2, + 0x68, 0x8f, 0x58, 0xfc, 0xd4, 0xa8, 0xc0, 0xa7, 0x6c, 0x0e, 0x62, 0xa7, 0x46, 0xef, 0x42, 0x53, + 0x10, 0x08, 0x9f, 0x2c, 0x14, 0xa4, 0x82, 0x1b, 0x1c, 0xde, 0x09, 0xc0, 0xb1, 0x5b, 0x98, 0xf3, + 0x89, 0x5b, 0x98, 0x77, 0x32, 0x17, 0x1a, 0xe2, 0x6c, 0x25, 0xb9, 0x98, 0x50, 0xfe, 0x26, 0x07, + 0x15, 0x76, 0xdd, 0xb4, 0x67, 0x8d, 0xec, 0x5f, 0xcb, 0x65, 0xdc, 0x9b, 0xd0, 0xb0, 0xa6, 0x13, + 0x55, 0xba, 0x65, 0x2b, 0xce, 0x22, 0x17, 0xad, 0xe9, 0x44, 0xbe, 0xa5, 0x7c, 0x09, 0xca, 0x96, + 0xd8, 0x88, 0x0a, 0x8e, 0xbe, 0x2d, 0xbe, 0x07, 0x45, 0xd7, 0xfe, 0x14, 0x15, 0xde, 0x43, 0xe0, + 0x87, 0x8d, 0x55, 0x6b, 0x3a, 0xe9, 0x08, 0x90, 0xf2, 0x3d, 0x76, 0x6b, 0x1f, 0x1b, 0x87, 0xb4, + 0x21, 0x81, 0xb6, 0x05, 0xf7, 0x35, 0x53, 0x8f, 0x96, 0xc2, 0x26, 0xf3, 0xfb, 0x9a, 0xca, 0x23, + 0x96, 0x07, 0x27, 0x2c, 0x2d, 0x54, 0xf0, 0xa2, 0xc5, 0x6f, 0x6f, 0x42, 0x39, 0xe8, 0x21, 0x04, + 0x50, 0xda, 0xde, 0xd9, 0x7f, 0xdc, 0xd9, 0x69, 0xce, 0xa1, 0x0a, 0xcc, 0xf3, 0x18, 0x85, 0xdd, + 0x5f, 0xe8, 0x6c, 0xfd, 0x50, 0xed, 0xed, 0x35, 0xf3, 0xa8, 0x0a, 0x0b, 0xf4, 0xff, 0xfe, 0xb3, + 0x41, 0xb3, 0x80, 0x16, 0xa0, 0xf0, 0x1c, 0x3f, 0x69, 0x16, 0x6f, 0xfb, 0x50, 0x95, 0xd6, 0x10, + 0xec, 0xc2, 0x03, 0xee, 0x3e, 0xe9, 0xbd, 0x68, 0xce, 0xa1, 0x1a, 0x94, 0xf7, 0xba, 0xbd, 0xed, + 0xa7, 0x8f, 0xf7, 0x71, 0x33, 0x47, 0x4b, 0x0c, 0x3a, 0xdb, 0x82, 0xcf, 0x81, 0xda, 0xef, 0x0c, + 0x9e, 0x36, 0x0b, 0xa8, 0x0e, 0x95, 0xcd, 0xfd, 0xdd, 0xdd, 0x67, 0x7b, 0xbd, 0xc1, 0xd7, 0xcd, + 0x22, 0x5a, 0x82, 0x7a, 0xf7, 0xc5, 0x40, 0x8d, 0x40, 0xf3, 0x34, 0x06, 0xdb, 0xe9, 0xe0, 0xed, + 0xae, 0x04, 0x2c, 0xdd, 0x7e, 0x17, 0x2a, 0xe1, 0x62, 0x81, 0xdd, 0xba, 0xda, 0xfb, 0x5a, 0xbe, + 0x7e, 0x05, 0x50, 0xea, 0xed, 0x3d, 0xef, 0xe2, 0x41, 0x33, 0x7f, 0xfb, 0x36, 0x34, 0x93, 0x4b, + 0x01, 0x54, 0x82, 0x7c, 0xf7, 0xab, 0xe6, 0x1c, 0xfd, 0xdd, 0xee, 0x36, 0x73, 0xf4, 0x77, 0xa7, + 0xdb, 0xcc, 0xdf, 0xfe, 0x40, 0x9c, 0x74, 0x8a, 0xa9, 0x3d, 0xba, 0xd8, 0x45, 0xfb, 0x61, 0x73, + 0xb3, 0xdb, 0x1f, 0x70, 0xe6, 0xb8, 0xfb, 0xc3, 0xee, 0x26, 0x65, 0xfe, 0x0c, 0x96, 0x33, 0x42, + 0x33, 0xda, 0x8c, 0x50, 0x5a, 0xb5, 0xb3, 0xb5, 0xd5, 0x9c, 0xa3, 0x31, 0x60, 0x04, 0xc2, 0xdd, + 0xdd, 0xfd, 0xe7, 0xb4, 0xe2, 0x55, 0x58, 0x92, 0xa1, 0xe2, 0xc6, 0xd8, 0xed, 0xf7, 0xa1, 0x1e, + 0x8b, 0xc7, 0x68, 0x9f, 0xed, 0x76, 0xb7, 0xd4, 0xdd, 0x7d, 0xca, 0xaa, 0x01, 0x55, 0xfa, 0x11, + 0x90, 0xe7, 0x6e, 0xdf, 0x01, 0x88, 0x9c, 0x7e, 0x98, 0xf9, 0x84, 0x76, 0xc2, 0x6e, 0x7f, 0x1f, + 0x0b, 0x99, 0xbb, 0x2f, 0xd8, 0xff, 0xfc, 0xfd, 0x7f, 0xb9, 0x0a, 0xe5, 0x6d, 0xaa, 0x13, 0x1d, + 0xc7, 0x40, 0x3b, 0x50, 0x95, 0xde, 0x6d, 0xa0, 0xb7, 0x62, 0x53, 0x51, 0xe2, 0x39, 0x48, 0xfb, + 0xf2, 0x0c, 0xac, 0xb8, 0x6e, 0x3d, 0x87, 0x7a, 0x00, 0xd1, 0xcb, 0x0e, 0xb4, 0x21, 0x93, 0x27, + 0x1e, 0x81, 0xb4, 0xdf, 0xca, 0x46, 0x86, 0xac, 0x9e, 0x40, 0x25, 0x7c, 0xcf, 0x82, 0xa4, 0x65, + 0x5d, 0xf2, 0xe1, 0x4b, 0x7b, 0x23, 0x13, 0x17, 0xf2, 0xd9, 0x81, 0xaa, 0x94, 0x88, 0x47, 0x6e, + 0x60, 0x3a, 0xb3, 0x8f, 0xdc, 0xc0, 0xac, 0xec, 0x3d, 0x73, 0xe8, 0x19, 0x2c, 0xc6, 0x53, 0xf0, + 0xa0, 0xab, 0xf2, 0x5a, 0x3a, 0x23, 0xb3, 0x4f, 0xfb, 0xda, 0x6c, 0x02, 0x59, 0x48, 0x29, 0xe9, + 0x94, 0x2c, 0x64, 0x3a, 0xcf, 0x95, 0x2c, 0x64, 0x46, 0xa6, 0x2a, 0x65, 0x0e, 0x61, 0xa8, 0xc7, + 0x72, 0xdb, 0xa0, 0x2b, 0x31, 0x97, 0x98, 0xe6, 0x78, 0x75, 0x26, 0x3e, 0xe4, 0xf9, 0xff, 0x61, + 0x29, 0x95, 0x33, 0x07, 0x29, 0xe7, 0xe7, 0xee, 0x69, 0x7f, 0xe7, 0x4c, 0x9a, 0x90, 0xff, 0xff, + 0x83, 0x66, 0x32, 0x37, 0x0e, 0x92, 0xce, 0x87, 0x67, 0xa4, 0xe4, 0x69, 0x2b, 0x67, 0x91, 0xc8, + 0xa3, 0x16, 0xcf, 0x94, 0x23, 0x8f, 0x5a, 0x66, 0xda, 0x1d, 0x79, 0xd4, 0x66, 0x24, 0xd9, 0x99, + 0x43, 0x2f, 0xa0, 0x91, 0x48, 0x86, 0x83, 0xe4, 0xc1, 0xce, 0xcc, 0xc0, 0xd3, 0xbe, 0x7e, 0x06, + 0x45, 0xc8, 0xf9, 0x11, 0x94, 0xb8, 0x63, 0x47, 0xeb, 0xb1, 0xc1, 0x8e, 0x9e, 0x52, 0xb4, 0x5b, + 0x69, 0x84, 0xac, 0x4e, 0xd2, 0x73, 0x08, 0x59, 0x9d, 0xd2, 0x6f, 0x32, 0x64, 0x75, 0xca, 0x7a, + 0x43, 0x31, 0x87, 0x7e, 0x00, 0x0b, 0x22, 0xdd, 0x17, 0x6a, 0xc5, 0xec, 0x43, 0x4a, 0xeb, 0xd5, + 0xbe, 0x94, 0x81, 0x91, 0xdd, 0x42, 0x94, 0x5c, 0x4b, 0x76, 0x0b, 0xa9, 0xf4, 0x60, 0xb2, 0x5b, + 0xc8, 0xc8, 0xc7, 0x35, 0x87, 0xb6, 0x00, 0xa2, 0x74, 0x30, 0x32, 0xab, 0x54, 0x92, 0x98, 0x76, + 0xf6, 0xcb, 0x19, 0x65, 0xee, 0xc3, 0x1c, 0x7a, 0x18, 0xa6, 0xbb, 0x89, 0x2e, 0xb1, 0x4a, 0x13, + 0x65, 0x98, 0xc3, 0xad, 0x9d, 0x48, 0xc4, 0xc5, 0x0a, 0x3f, 0x81, 0x4a, 0x98, 0x7f, 0x48, 0xf6, + 0x4c, 0xc9, 0xec, 0x47, 0xb2, 0x67, 0x4a, 0x27, 0x2c, 0xe2, 0xbd, 0x12, 0x66, 0x27, 0x8a, 0xf5, + 0x4a, 0x32, 0x91, 0x51, 0xac, 0x57, 0xd2, 0x09, 0x8d, 0xe6, 0xd0, 0x53, 0xa8, 0x84, 0x19, 0x85, + 0x64, 0x91, 0x92, 0x79, 0x8e, 0x64, 0x91, 0xd2, 0x29, 0x88, 0xe6, 0x6e, 0xe5, 0xa8, 0xe6, 0xf1, + 0xbc, 0x3e, 0xb2, 0xe6, 0xc5, 0x52, 0x08, 0xb5, 0x5b, 0x69, 0x84, 0xec, 0xb5, 0xc3, 0x14, 0x3e, + 0xb2, 0x20, 0xc9, 0xcc, 0x40, 0xed, 0x8d, 0x4c, 0x9c, 0xac, 0x73, 0x22, 0x69, 0x09, 0x4a, 0x28, + 0x7a, 0x94, 0xed, 0x42, 0xd6, 0xb9, 0x44, 0x86, 0x93, 0x50, 0x6b, 0x93, 0x1c, 0xe2, 0xc9, 0x4c, + 0x12, 0x5a, 0x9b, 0xe0, 0x10, 0x6a, 0x2d, 0x63, 0x92, 0x12, 0x58, 0xe6, 0xf3, 0x56, 0x36, 0x52, + 0x66, 0x15, 0xe5, 0x13, 0x41, 0x29, 0xbd, 0x98, 0xc1, 0x2a, 0x23, 0x05, 0x09, 0xb3, 0x6d, 0x29, + 0xa9, 0x08, 0x4a, 0x6b, 0x86, 0xcc, 0xec, 0xf2, 0x0c, 0xac, 0x3c, 0x5e, 0x61, 0x4a, 0x10, 0x79, + 0xbc, 0x92, 0x99, 0x45, 0xe4, 0xf1, 0x4a, 0xe7, 0x10, 0x61, 0x53, 0x4e, 0x2c, 0xbd, 0x88, 0x3c, + 0xe5, 0x64, 0x65, 0x2a, 0x91, 0xa7, 0x9c, 0xec, 0xbc, 0x24, 0xa1, 0x13, 0xb4, 0xb5, 0xa4, 0x13, + 0x0c, 0xd7, 0x65, 0x49, 0x27, 0x18, 0xad, 0xc3, 0x78, 0x47, 0x49, 0xa9, 0x40, 0x50, 0xaa, 0x5f, + 0xe5, 0x74, 0x27, 0x72, 0x47, 0x65, 0xe5, 0x0f, 0x99, 0x13, 0x76, 0x41, 0xd7, 0x6d, 0x71, 0xbb, + 0x88, 0xd2, 0x78, 0x24, 0xec, 0x42, 0x4e, 0xd5, 0x21, 0xd9, 0x05, 0xe5, 0x90, 0xb2, 0x0b, 0x89, + 0xc9, 0x46, 0x26, 0x2e, 0xd1, 0x27, 0x09, 0x31, 0x62, 0xa9, 0x4d, 0x12, 0x7d, 0x12, 0x2f, 0x8e, + 0xd9, 0xc2, 0x56, 0x3a, 0x17, 0xb8, 0x12, 0x23, 0x4e, 0x25, 0xb9, 0x90, 0x87, 0x29, 0x33, 0x2b, + 0x08, 0xe7, 0x19, 0xcb, 0xd6, 0x21, 0xf3, 0xcc, 0x4a, 0x03, 0x22, 0xf3, 0xcc, 0x4e, 0xf3, 0xc1, + 0xa2, 0x81, 0x64, 0x4e, 0x0e, 0x39, 0x1a, 0x98, 0x91, 0x04, 0x44, 0x8e, 0x06, 0x66, 0xa6, 0xf4, + 0x60, 0xa1, 0x4c, 0x2a, 0x21, 0x87, 0x1c, 0xca, 0xcc, 0xca, 0xf8, 0x21, 0x87, 0x32, 0xb3, 0x33, + 0x7a, 0xcc, 0xa1, 0x7d, 0xa8, 0xc9, 0xc9, 0x3b, 0x50, 0x3c, 0x5e, 0x4b, 0xe6, 0xa9, 0x68, 0x5f, + 0x99, 0x85, 0x96, 0x19, 0xca, 0x69, 0x37, 0x50, 0x3c, 0x4a, 0x3d, 0x8b, 0x61, 0x66, 0xb6, 0x0e, + 0x1e, 0xb8, 0xc4, 0x13, 0x6a, 0xa0, 0x54, 0x94, 0x9a, 0x62, 0x7b, 0xfd, 0x0c, 0x0a, 0x79, 0xe0, + 0x92, 0x19, 0x34, 0xe4, 0x81, 0x9b, 0x91, 0xab, 0xa3, 0xad, 0x9c, 0x45, 0x92, 0x58, 0x12, 0x88, + 0xcd, 0xb5, 0xf8, 0x92, 0x20, 0x96, 0x0f, 0x22, 0xb1, 0x24, 0x48, 0x24, 0x5f, 0x60, 0x7c, 0xc2, + 0x7c, 0x03, 0x32, 0x9f, 0x64, 0x22, 0x0e, 0x99, 0x4f, 0x3a, 0x55, 0x06, 0x1b, 0x17, 0x39, 0x53, + 0x80, 0x3c, 0x2e, 0x19, 0x39, 0x34, 0xe4, 0x71, 0xc9, 0x4c, 0x6f, 0x21, 0x02, 0x77, 0xe9, 0xe9, + 0x7f, 0x3c, 0x70, 0x4f, 0x27, 0xbe, 0x88, 0x07, 0xee, 0x59, 0x99, 0x26, 0xe6, 0x90, 0xce, 0x32, + 0xcc, 0xa4, 0x76, 0x0f, 0xdf, 0xce, 0xe8, 0xa2, 0x54, 0x1e, 0x83, 0xf6, 0x8d, 0x73, 0xa8, 0xe4, + 0x5a, 0x32, 0x52, 0x38, 0xc8, 0xb5, 0xcc, 0xce, 0x1d, 0x21, 0xd7, 0x72, 0x56, 0x1e, 0x88, 0x39, + 0x34, 0x09, 0xf2, 0xcc, 0xa4, 0x2a, 0xba, 0x99, 0xdd, 0xb7, 0xe9, 0xba, 0x6e, 0x9d, 0x4f, 0x18, + 0x56, 0xe7, 0x84, 0xc9, 0x65, 0xd2, 0x9b, 0xaf, 0x33, 0x3a, 0x3e, 0x5d, 0xe1, 0xbb, 0x17, 0xa0, + 0x94, 0xe3, 0x84, 0x68, 0x43, 0x07, 0x6d, 0x24, 0x43, 0x7c, 0x69, 0x93, 0xa8, 0xfd, 0x56, 0x36, + 0x32, 0x60, 0x75, 0x58, 0x62, 0x49, 0x93, 0x3f, 0xfa, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xb8, + 0xc6, 0x49, 0x53, 0x43, 0x59, 0x00, 0x00, } diff --git a/vendor/github.com/osrg/gobgp/api/gobgp.proto b/vendor/github.com/osrg/gobgp/api/gobgp.proto index ded9487d89..c8b02a4a83 100644 --- a/vendor/github.com/osrg/gobgp/api/gobgp.proto +++ b/vendor/github.com/osrg/gobgp/api/gobgp.proto @@ -509,6 +509,7 @@ message Path { string neighbor_ip = 14; bytes uuid = 15; // only paths installed by AddPath API have this bool is_nexthop_invalid = 16; + uint32 identifier = 17; } message Destination { diff --git a/vendor/github.com/osrg/gobgp/api/grpc_server.go b/vendor/github.com/osrg/gobgp/api/grpc_server.go index cb83b132c8..3b8f2fe40e 100644 --- a/vendor/github.com/osrg/gobgp/api/grpc_server.go +++ b/vendor/github.com/osrg/gobgp/api/grpc_server.go @@ -370,6 +370,7 @@ func ToPathApi(path *table.Path) *Path { NoImplicitWithdraw: path.NoImplicitWithdraw(), Uuid: path.UUID().Bytes(), IsNexthopInvalid: path.IsNexthopInvalid, + Identifier: nlri.PathIdentifier(), } if s := path.GetSource(); s != nil { p.SourceAsn = s.AS diff --git a/vendor/github.com/osrg/gobgp/api/util.go b/vendor/github.com/osrg/gobgp/api/util.go index ea385862aa..dabb65b7ce 100644 --- a/vendor/github.com/osrg/gobgp/api/util.go +++ b/vendor/github.com/osrg/gobgp/api/util.go @@ -70,7 +70,13 @@ func (d *Destination) ToNativeDestination(option ...ToNativeOption) (*table.Dest }) paths := make([]*table.Path, 0, len(d.Paths)) for _, p := range d.Paths { - path, err := p.ToNativePath(option...) + var path *table.Path + var err error + if p.Identifier > 0 { + path, err = p.ToNativePath() + } else { + path, err = p.ToNativePath(option...) + } if err != nil { return nil, err } @@ -113,6 +119,7 @@ func (p *Path) ToNativePath(option ...ToNativeOption) (*table.Path, error) { pattr = append(pattr, p) } t := time.Unix(p.Age, 0) + nlri.SetPathIdentifier(p.Identifier) path := table.NewPath(info, nlri, p.IsWithdraw, pattr, t, false) path.SetValidation(config.IntToRpkiValidationResultTypeMap[int(p.Validation)]) path.MarkStale(p.Stale) diff --git a/vendor/github.com/osrg/gobgp/config/util.go b/vendor/github.com/osrg/gobgp/config/util.go index 8ecf56d5f5..ab7ebfe382 100644 --- a/vendor/github.com/osrg/gobgp/config/util.go +++ b/vendor/github.com/osrg/gobgp/config/util.go @@ -69,11 +69,18 @@ func (c AfiSafis) ToRfList() ([]bgp.RouteFamily, error) { return rfs, nil } -func CreateRfMap(p *Neighbor) map[bgp.RouteFamily]bool { +func CreateRfMap(p *Neighbor) map[bgp.RouteFamily]bgp.BGPAddPathMode { rfs, _ := AfiSafis(p.AfiSafis).ToRfList() - rfMap := make(map[bgp.RouteFamily]bool) + mode := bgp.BGP_ADD_PATH_NONE + if p.AddPaths.Config.Receive { + mode |= bgp.BGP_ADD_PATH_RECEIVE + } + if p.AddPaths.Config.SendMax > 0 { + mode |= bgp.BGP_ADD_PATH_SEND + } + rfMap := make(map[bgp.RouteFamily]bgp.BGPAddPathMode) for _, rf := range rfs { - rfMap[rf] = true + rfMap[rf] = mode } return rfMap } diff --git a/vendor/github.com/osrg/gobgp/docs/sources/configuration.md b/vendor/github.com/osrg/gobgp/docs/sources/configuration.md index 71e654fbdb..54811840a4 100644 --- a/vendor/github.com/osrg/gobgp/docs/sources/configuration.md +++ b/vendor/github.com/osrg/gobgp/docs/sources/configuration.md @@ -72,6 +72,8 @@ [neighbors.route-reflector.config] route-reflector-client = true route-reflector-cluster-id = "192.168.0.1" + [neighbors.add-paths.config] + receive = true [neighbors.graceful-restart.config] enabled = true notification-enabled = true @@ -123,6 +125,8 @@ [[neighbors.afi-safis]] [neighbors.afi-safis.config] afi-safi-name = "ipv6-flowspec" + [[neighbors.afi-safis]] + afi-safi-name = "opaque" [neighbors.apply-policy.config] import-policy-list = ["policy1"] default-import-policy = "reject-route" diff --git a/vendor/github.com/osrg/gobgp/docs/sources/flowspec.md b/vendor/github.com/osrg/gobgp/docs/sources/flowspec.md index da7d17f071..6d48d8a663 100644 --- a/vendor/github.com/osrg/gobgp/docs/sources/flowspec.md +++ b/vendor/github.com/osrg/gobgp/docs/sources/flowspec.md @@ -45,7 +45,7 @@ CLI syntax to add ipv4/ipv6 flowspec rule is ```shell % global rib add match then -a [ipv4-flowspec|ipv6-flowspec] : { destination [] | source [] | - protocol ... | fragment | tcp-flags [!] [=] ... | + protocol ... | fragment [!] [=] | tcp-flags [!] [=] ... | { port | destination-port | source-port | icmp-type | icmp-code | packet-length | dscp | label } ... }... : ospf, pim, igp, udp, igmp, tcp, egp, rsvp, gre, ipip, unknown, icmp, sctp, : dont-fragment, is-fragment, first-fragment, last-fragment, not-a-fragment @@ -98,22 +98,26 @@ All decimal values like ports, destination port, source port, procotol number ca Network Next Hop AS_PATH Age Attrs *> [destination:10.0.0.0/24][source:20.0.0.0/24] 0.0.0.0 00:00:04 [{Origin: i} {Extcomms: [redirect: 10:10]}] -# add another flowspec rule which discard flows whose ip protocol is tcp and destination port is 80 or greater than or equal to 8080 and lesser than or equal to 8888 -% gobgp global rib -a ipv4-flowspec add match protocol tcp destination-port '==80' '>=8080&<=8888' then discard +# add another flowspec rule which discard flows whose + # ip protocol is tcp and + # destination port is 80 or greater than or equal to 8080 and lesser than or equal to 8888 and + # packet is a first fragment or a last fragment +% gobgp global rib -a ipv4-flowspec add match protocol tcp destination-port '==80' '>=8080&<=8888' fragment '=first-fragment =last-fragment' then discard # add flowspec rule to drop traffic not going to destination port 80, 443 or 22 gobgp global rib -a ipv4-flowspec add match destination 2.2.2.2/32 dest-port '!=80&!=443&!=22' then discard % gobgp global rib -a ipv4-flowspec - Network Next Hop AS_PATH Age Attrs -*> [destination:10.0.0.0/24][source:20.0.0.0/24] 0.0.0.0 00:03:19 [{Origin: i} {Extcomms: [redirect: 10:10]}] -*> [protocol: tcp][destination-port: ==80 >=8080&<=8888] 0.0.0.0 00:00:03 [{Origin: i} {Extcomms: [discard]}] + Network Next Hop AS_PATH Age Attrs +*> [destination:10.0.0.0/24][source:20.0.0.0/24] 0.0.0.0 00:03:19 [{Origin: i} {Extcomms: [redirect: 10:10]}] +*> [protocol:==tcp ][destination-port: ==80 >=8080&<=8888][fragment:=first-fragment =last-fragment ]0.0.0.0 00:00:05 [{Origin: ?} {Extcomms: [discard]}] + # delete a flowspec rule % gobgp global rib -a ipv4-flowspec del match destination 10.0.0.0/24 source 20.0.0.0/24 then redirect 10:10 % gobgp global rib -a ipv4-flowspec - Network Next Hop AS_PATH Age Attrs -*> [protocol: tcp][destination-port: ==80 >=8080&<=8888] 0.0.0.0 00:00:03 [{Origin: i} {Extcomms: [discard]}] + Network Next Hop AS_PATH Age Attrs +*> [protocol:==tcp ][destination-port: ==80 >=8080&<=8888][fragment:=first-fragment =last-fragment ]0.0.0.0 00:00:05 [{Origin: ?} {Extcomms: [discard]}] ``` diff --git a/vendor/github.com/osrg/gobgp/gobgp/cmd/global.go b/vendor/github.com/osrg/gobgp/gobgp/cmd/global.go index 3c09e7dd46..a53ce0c76d 100644 --- a/vendor/github.com/osrg/gobgp/gobgp/cmd/global.go +++ b/vendor/github.com/osrg/gobgp/gobgp/cmd/global.go @@ -881,7 +881,7 @@ usage: %s rib %s%%smatch then -a %%s ExtCommNameMap[RATE], ExtCommNameMap[REDIRECT], ExtCommNameMap[MARK], ExtCommNameMap[ACTION], ExtCommNameMap[RT]) ipFsMatchExpr := fmt.Sprintf(` : { %s [] | %s [] | - %s ... | %s | %s [!] [=] ... | + %s ... | %s [!] [=] | %s [!] [=] ... | { %s | %s | %s | %s | %s | %s | %s | %s } ... }... : %s : dont-fragment, is-fragment, first-fragment, last-fragment, not-a-fragment diff --git a/vendor/github.com/osrg/gobgp/gobgp/cmd/monitor.go b/vendor/github.com/osrg/gobgp/gobgp/cmd/monitor.go index 9d2d841fc0..2ba2e95b77 100644 --- a/vendor/github.com/osrg/gobgp/gobgp/cmd/monitor.go +++ b/vendor/github.com/osrg/gobgp/gobgp/cmd/monitor.go @@ -32,7 +32,7 @@ func NewMonitorCmd() *cobra.Command { monitor := func(recver interface { Recv() (*table.Destination, error) - }) { + }, showIdentifier bool) { for { dst, err := recver.Recv() if err == io.EOF { @@ -44,7 +44,7 @@ func NewMonitorCmd() *cobra.Command { j, _ := json.Marshal(dst.GetAllKnownPathList()) fmt.Println(string(j)) } else { - ShowRoute(dst.GetAllKnownPathList(), false, false, false, true, false) + ShowRoute(dst.GetAllKnownPathList(), false, false, false, showIdentifier, true, false) } } } @@ -60,7 +60,7 @@ func NewMonitorCmd() *cobra.Command { if err != nil { exitWithError(err) } - monitor(recver) + monitor(recver, false) }, } ribCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family") @@ -118,7 +118,7 @@ func NewMonitorCmd() *cobra.Command { if err != nil { exitWithError(err) } - monitor(recver) + monitor(recver, true) }, } adjInCmd.PersistentFlags().StringVarP(&subOpts.AddressFamily, "address-family", "a", "", "address family") diff --git a/vendor/github.com/osrg/gobgp/gobgp/cmd/mrt.go b/vendor/github.com/osrg/gobgp/gobgp/cmd/mrt.go index f89e801f10..8aa6be95c7 100644 --- a/vendor/github.com/osrg/gobgp/gobgp/cmd/mrt.go +++ b/vendor/github.com/osrg/gobgp/gobgp/cmd/mrt.go @@ -112,11 +112,11 @@ func injectMrt(filename string, count int, skip int, onlyBest bool) error { for _, p := range paths { dst.AddNewPath(p) } - best, _, _ := dst.Calculate([]string{table.GLOBAL_RIB_NAME}, false) - if best[table.GLOBAL_RIB_NAME] == nil { + best, _, _ := dst.Calculate().GetChanges(table.GLOBAL_RIB_NAME, false) + if best == nil { exitWithError(fmt.Errorf("Can't find the best %v", nlri)) } - paths = []*table.Path{best[table.GLOBAL_RIB_NAME]} + paths = []*table.Path{best} } if idx >= skip { diff --git a/vendor/github.com/osrg/gobgp/gobgp/cmd/neighbor.go b/vendor/github.com/osrg/gobgp/gobgp/cmd/neighbor.go index ffd835fcb8..d63e599bbb 100644 --- a/vendor/github.com/osrg/gobgp/gobgp/cmd/neighbor.go +++ b/vendor/github.com/osrg/gobgp/gobgp/cmd/neighbor.go @@ -185,7 +185,7 @@ func showNeighbor(args []string) error { elems := make([]string, 0, 3) if as := p.AsPathOptions.Config.AllowOwnAs; as > 0 { - elems = append(elems, fmt.Sprintf("Allow Own AS: %d\n", as)) + elems = append(elems, fmt.Sprintf("Allow Own AS: %d", as)) } switch p.Config.RemovePrivateAs { case config.REMOVE_PRIVATE_AS_OPTION_ALL: @@ -197,7 +197,7 @@ func showNeighbor(args []string) error { elems = append(elems, "Replace peer AS: enabled") } - fmt.Println(" %s", strings.Join(elems, ", ")) + fmt.Printf(" %s\n", strings.Join(elems, ", ")) fmt.Printf(" Neighbor capabilities:\n") caps := capabilities{} @@ -350,6 +350,20 @@ func showNeighbor(args []string) error { fmt.Printf(" Remote: %s\n", s) } } + case bgp.BGP_CAP_ADD_PATH: + fmt.Printf(" %s:\t%s\n", c.Code(), support) + if m := lookup(c, p.State.LocalCapabilityList); m != nil { + fmt.Println(" Local:") + for _, item := range m.(*bgp.CapAddPath).Tuples { + fmt.Printf(" %s:\t%s\n", item.RouteFamily, item.Mode) + } + } + if m := lookup(c, p.State.RemoteCapabilityList); m != nil { + fmt.Println(" Remote:") + for _, item := range m.(*bgp.CapAddPath).Tuples { + fmt.Printf(" %s:\t%s\n", item.RouteFamily, item.Mode) + } + } default: fmt.Printf(" %s:\t%s\n", c.Code(), support) } @@ -391,7 +405,7 @@ type AsPathFormat struct { separator string } -func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, isMonitor, printHeader bool) { +func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, showIdentifier, isMonitor, printHeader bool) { var pathStrs [][]interface{} maxPrefixLen := 20 @@ -455,9 +469,17 @@ func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, isMonitor, if p.IsWithdraw { title = "DELROUTE" } - pathStrs = append(pathStrs, []interface{}{title, nlri, nexthop, aspathstr, pattrstr}) + if showIdentifier { + pathStrs = append(pathStrs, []interface{}{title, nlri.PathIdentifier(), nlri, nexthop, aspathstr, pattrstr}) + } else { + pathStrs = append(pathStrs, []interface{}{title, nlri, nexthop, aspathstr, pattrstr}) + } } else { - args := []interface{}{best, nlri} + args := []interface{}{best} + if showIdentifier { + args = append(args, fmt.Sprint(nlri.PathIdentifier())) + } + args = append(args, nlri) if showLabel { label := "" switch nlri.(type) { @@ -486,9 +508,13 @@ func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, isMonitor, var format string if isMonitor { - format = "[%s] %s via %s aspath [%s] attrs %s\n" + format = "[%s] %d:%s via %s aspath [%s] attrs %s\n" } else { - format = fmt.Sprintf("%%-3s %%-%ds", maxPrefixLen) + format = fmt.Sprintf("%%-3s") + if showIdentifier { + format += "%-3s " + } + format += fmt.Sprintf("%%-%ds ", maxPrefixLen) if showLabel { format += fmt.Sprintf("%%-%ds ", maxLabelLen) } @@ -497,11 +523,14 @@ func ShowRoute(pathList []*table.Path, showAge, showBest, showLabel, isMonitor, format += "%-10s " } format += "%-s\n" - } if printHeader { - args := []interface{}{"", "Network"} + args := []interface{}{""} + if showIdentifier { + args = append(args, "ID") + } + args = append(args, "Network") if showLabel { args = append(args, "Labels") } @@ -573,6 +602,7 @@ func showNeighborRib(r string, name string, args []string) error { showBest := false showAge := true showLabel := false + showIdentifier := false def := addr2AddressFamily(net.ParseIP(name)) switch r { case CMD_GLOBAL: @@ -623,8 +653,10 @@ func showNeighborRib(r string, name string, args []string) error { case CMD_LOCAL: rib, err = client.GetLocalRIB(name, family, filter) case CMD_ADJ_IN, CMD_ACCEPTED, CMD_REJECTED: + showIdentifier = true rib, err = client.GetAdjRIBIn(name, family, filter) case CMD_ADJ_OUT: + showIdentifier = true rib, err = client.GetAdjRIBOut(name, family, filter) case CMD_VRF: rib, err = client.GetVRFRIB(name, family, filter) @@ -673,11 +705,11 @@ func showNeighborRib(r string, name string, args []string) error { } else { ps = d.GetAllKnownPathList() } + showHeader := false if counter == 0 { - ShowRoute(ps, showAge, showBest, showLabel, false, true) - } else { - ShowRoute(ps, showAge, showBest, showLabel, false, false) + showHeader = true } + ShowRoute(ps, showAge, showBest, showLabel, showIdentifier, false, showHeader) counter++ } diff --git a/vendor/github.com/osrg/gobgp/packet/bgp/bgp.go b/vendor/github.com/osrg/gobgp/packet/bgp/bgp.go index a32ce069f0..a07cd5e514 100644 --- a/vendor/github.com/osrg/gobgp/packet/bgp/bgp.go +++ b/vendor/github.com/osrg/gobgp/packet/bgp/bgp.go @@ -28,6 +28,26 @@ import ( "strings" ) +type MarshallingOption struct { + AddPath map[RouteFamily]BGPAddPathMode +} + +func handleAddPath(decode bool, f RouteFamily, options []*MarshallingOption) bool { + for _, opt := range options { + if opt == nil { + continue + } + if o := opt.AddPath; o != nil { + if decode && o[f]&BGP_ADD_PATH_RECEIVE > 0 { + return true + } else if !decode && o[f]&BGP_ADD_PATH_SEND > 0 { + return true + } + } + } + return false +} + const ( AFI_IP = 1 AFI_IP6 = 2 @@ -572,13 +592,16 @@ func NewCapFourOctetASNumber(asnum uint32) *CapFourOctetASNumber { type BGPAddPathMode uint8 const ( - BGP_ADD_PATH_RECEIVE BGPAddPathMode = 1 - BGP_ADD_PATH_SEND BGPAddPathMode = 2 - BGP_ADD_PATH_BOTH BGPAddPathMode = 3 + BGP_ADD_PATH_NONE BGPAddPathMode = iota + BGP_ADD_PATH_RECEIVE + BGP_ADD_PATH_SEND + BGP_ADD_PATH_BOTH ) func (m BGPAddPathMode) String() string { switch m { + case BGP_ADD_PATH_NONE: + return "none" case BGP_ADD_PATH_RECEIVE: return "receive" case BGP_ADD_PATH_SEND: @@ -891,7 +914,7 @@ type BGPOpen struct { OptParams []OptionParameterInterface } -func (msg *BGPOpen) DecodeFromBytes(data []byte) error { +func (msg *BGPOpen) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { msg.Version = data[0] msg.MyAS = binary.BigEndian.Uint16(data[1:3]) msg.HoldTime = binary.BigEndian.Uint16(data[3:5]) @@ -932,7 +955,7 @@ func (msg *BGPOpen) DecodeFromBytes(data []byte) error { return nil } -func (msg *BGPOpen) Serialize() ([]byte, error) { +func (msg *BGPOpen) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 10) buf[0] = msg.Version binary.BigEndian.PutUint16(buf[1:3], msg.MyAS) @@ -959,20 +982,50 @@ func NewBGPOpenMessage(myas uint16, holdtime uint16, id string, optparams []Opti } type AddrPrefixInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) + DecodeFromBytes([]byte, ...*MarshallingOption) error + Serialize(...*MarshallingOption) ([]byte, error) AFI() uint16 SAFI() uint8 - Len() int + Len(...*MarshallingOption) int String() string MarshalJSON() ([]byte, error) - // Create a flat map to describe attributes and their // values. This can be used to create structured outputs. Flat() map[string]string + PathIdentifier() uint32 + SetPathIdentifier(uint32) +} + +type PrefixDefault struct { + id uint32 +} + +func (p *PrefixDefault) PathIdentifier() uint32 { + return p.id +} + +func (p *PrefixDefault) SetPathIdentifier(id uint32) { + p.id = id +} + +func (p *PrefixDefault) decodePathIdentifier(data []byte) ([]byte, error) { + if len(data) < 4 { + code := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) + subcode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) + return nil, NewMessageError(code, subcode, nil, "prefix misses path identifier field") + } + p.SetPathIdentifier(binary.BigEndian.Uint32(data[:4])) + return data[4:], nil +} + +func (p *PrefixDefault) serializeIdentifier() ([]byte, error) { + buf := make([]byte, 4) + binary.BigEndian.PutUint32(buf, p.PathIdentifier()) + return buf, nil } type IPAddrPrefixDefault struct { + PrefixDefault Length uint8 Prefix net.IP } @@ -1007,7 +1060,7 @@ func (r *IPAddrPrefixDefault) serializePrefix(bitlen uint8) ([]byte, error) { return buf, nil } -func (r *IPAddrPrefixDefault) Len() int { +func (r *IPAddrPrefixDefault) Len(options ...*MarshallingOption) int { return 1 + ((int(r.Length) + 7) / 8) } @@ -1028,22 +1081,44 @@ type IPAddrPrefix struct { addrlen uint8 } -func (r *IPAddrPrefix) DecodeFromBytes(data []byte) error { +func (r *IPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + if r.addrlen == 0 { + r.addrlen = 4 + } + f := RF_IPv4_UC + if r.addrlen == 16 { + f = RF_IPv6_UC + } + if handleAddPath(true, f, options) { + var err error + data, err = r.decodePathIdentifier(data) + if err != nil { + return err + } + } if len(data) < 1 { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) return NewMessageError(eCode, eSubCode, nil, "prefix misses length field") } r.Length = data[0] - if r.addrlen == 0 { - r.addrlen = 4 - } return r.decodePrefix(data[1:], r.Length, r.addrlen) } -func (r *IPAddrPrefix) Serialize() ([]byte, error) { - buf := make([]byte, 1) - buf[0] = r.Length +func (r *IPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { + f := RF_IPv4_UC + if r.addrlen == 16 { + f = RF_IPv6_UC + } + var buf []byte + if handleAddPath(false, f, options) { + var err error + buf, err = r.serializeIdentifier() + if err != nil { + return nil, err + } + } + buf = append(buf, r.Length) pbuf, err := r.serializePrefix(r.Length) if err != nil { return nil, err @@ -1061,7 +1136,10 @@ func (r *IPAddrPrefix) SAFI() uint8 { func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix { return &IPAddrPrefix{ - IPAddrPrefixDefault{length, net.ParseIP(prefix).To4()}, + IPAddrPrefixDefault{ + Length: length, + Prefix: net.ParseIP(prefix).To4(), + }, 4, } } @@ -1089,7 +1167,10 @@ func (r *IPv6AddrPrefix) String() string { func NewIPv6AddrPrefix(length uint8, prefix string) *IPv6AddrPrefix { return &IPv6AddrPrefix{ IPAddrPrefix{ - IPAddrPrefixDefault{length, net.ParseIP(prefix)}, + IPAddrPrefixDefault{ + Length: length, + Prefix: net.ParseIP(prefix), + }, 16, }, } @@ -1465,7 +1546,21 @@ type LabeledVPNIPAddrPrefix struct { addrlen uint8 } -func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte) error { +func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + f := RF_IPv4_VPN + if l.addrlen == 16 { + f = RF_IPv6_VPN + } + if handleAddPath(true, f, options) { + var err error + data, err = l.decodePathIdentifier(data) + if err != nil { + return err + } + } + if len(data) < 1 { + return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field") + } l.Length = uint8(data[0]) data = data[1:] l.Labels.DecodeFromBytes(data) @@ -1476,13 +1571,23 @@ func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte) error { l.RD = GetRouteDistinguisher(data) data = data[l.RD.Len():] restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len()) - l.decodePrefix(data, uint8(restbits), l.addrlen) - return nil + return l.decodePrefix(data, uint8(restbits), l.addrlen) } -func (l *LabeledVPNIPAddrPrefix) Serialize() ([]byte, error) { - buf := make([]byte, 1) - buf[0] = l.Length +func (l *LabeledVPNIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { + f := RF_IPv4_VPN + if l.addrlen == 16 { + f = RF_IPv6_VPN + } + var buf []byte + if handleAddPath(false, f, options) { + var err error + buf, err = l.serializeIdentifier() + if err != nil { + return nil, err + } + } + buf = append(buf, l.Length) lbuf, err := l.Labels.Serialize() if err != nil { return nil, err @@ -1538,7 +1643,10 @@ func NewLabeledVPNIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack rdlen = rd.Len() } return &LabeledVPNIPAddrPrefix{ - IPAddrPrefixDefault{length + uint8(8*(label.Len()+rdlen)), net.ParseIP(prefix).To4()}, + IPAddrPrefixDefault{ + Length: length + uint8(8*(label.Len()+rdlen)), + Prefix: net.ParseIP(prefix).To4(), + }, label, rd, 4, @@ -1560,7 +1668,10 @@ func NewLabeledVPNIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelSta } return &LabeledVPNIPv6AddrPrefix{ LabeledVPNIPAddrPrefix{ - IPAddrPrefixDefault{length + uint8(8*(label.Len()+rdlen)), net.ParseIP(prefix)}, + IPAddrPrefixDefault{ + Length: length + uint8(8*(label.Len()+rdlen)), + Prefix: net.ParseIP(prefix), + }, label, rd, 16, @@ -1582,7 +1693,18 @@ func (r *LabeledIPAddrPrefix) SAFI() uint8 { return SAFI_MPLS_LABEL } -func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte) error { +func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + f := RF_IPv4_MPLS + if l.addrlen == 16 { + f = RF_IPv6_MPLS + } + if handleAddPath(true, f, options) { + var err error + data, err = l.decodePathIdentifier(data) + if err != nil { + return err + } + } l.Length = uint8(data[0]) data = data[1:] l.Labels.DecodeFromBytes(data) @@ -1595,9 +1717,20 @@ func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte) error { return nil } -func (l *LabeledIPAddrPrefix) Serialize() ([]byte, error) { - buf := make([]byte, 1) - buf[0] = l.Length +func (l *LabeledIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { + f := RF_IPv4_MPLS + if l.addrlen == 16 { + f = RF_IPv6_MPLS + } + var buf []byte + if handleAddPath(false, f, options) { + var err error + buf, err = l.serializeIdentifier() + if err != nil { + return nil, err + } + } + buf = append(buf, l.Length) restbits := int(l.Length) - 8*(l.Labels.Len()) lbuf, err := l.Labels.Serialize() if err != nil { @@ -1632,7 +1765,10 @@ func (l *LabeledIPAddrPrefix) MarshalJSON() ([]byte, error) { func NewLabeledIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPAddrPrefix { return &LabeledIPAddrPrefix{ - IPAddrPrefixDefault{length + uint8(label.Len()*8), net.ParseIP(prefix).To4()}, + IPAddrPrefixDefault{ + Length: length + uint8(label.Len()*8), + Prefix: net.ParseIP(prefix).To4(), + }, label, 4, } @@ -1649,7 +1785,10 @@ func (l *LabeledIPv6AddrPrefix) AFI() uint16 { func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPv6AddrPrefix { return &LabeledIPv6AddrPrefix{ LabeledIPAddrPrefix{ - IPAddrPrefixDefault{length + uint8(label.Len()*8), net.ParseIP(prefix)}, + IPAddrPrefixDefault{ + Length: length + uint8(label.Len()*8), + Prefix: net.ParseIP(prefix), + }, label, 16, }, @@ -1657,12 +1796,23 @@ func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack) } type RouteTargetMembershipNLRI struct { + PrefixDefault Length uint8 AS uint32 RouteTarget ExtendedCommunityInterface } -func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte) error { +func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + if handleAddPath(true, RF_RTC_UC, options) { + var err error + data, err = n.decodePathIdentifier(data) + if err != nil { + return err + } + } + if len(data) < 1 { + return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field") + } n.Length = data[0] data = data[1:] if len(data) == 0 { @@ -1679,19 +1829,27 @@ func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte) error { return nil } -func (n *RouteTargetMembershipNLRI) Serialize() ([]byte, error) { +func (n *RouteTargetMembershipNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { + var buf []byte + if handleAddPath(false, RF_RTC_UC, options) { + var err error + buf, err = n.serializeIdentifier() + if err != nil { + return nil, err + } + } if n.RouteTarget == nil { - return []byte{0}, nil + return append(buf, 0), nil } - buf := make([]byte, 5) - buf[0] = 12 * 8 - binary.BigEndian.PutUint32(buf[1:], n.AS) + offset := len(buf) + buf = append(buf, make([]byte, 5)...) + buf[offset] = 12 * 8 + binary.BigEndian.PutUint32(buf[offset+1:], n.AS) ebuf, err := n.RouteTarget.Serialize() if err != nil { return nil, err } - buf = append(buf, ebuf...) - return buf, nil + return append(buf, ebuf...), nil } func (n *RouteTargetMembershipNLRI) AFI() uint16 { @@ -1702,7 +1860,7 @@ func (n *RouteTargetMembershipNLRI) SAFI() uint8 { return SAFI_ROUTE_TARGET_CONSTRAINTS } -func (n *RouteTargetMembershipNLRI) Len() int { +func (n *RouteTargetMembershipNLRI) Len(options ...*MarshallingOption) int { if n.AS == 0 && n.RouteTarget == nil { return 1 } @@ -2309,12 +2467,20 @@ const ( ) type EVPNNLRI struct { + PrefixDefault RouteType uint8 Length uint8 RouteTypeData EVPNRouteTypeInterface } -func (n *EVPNNLRI) DecodeFromBytes(data []byte) error { +func (n *EVPNNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + if handleAddPath(true, RF_EVPN, options) { + var err error + data, err = n.decodePathIdentifier(data) + if err != nil { + return err + } + } if len(data) < 2 { return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI bytes available") } @@ -2332,17 +2498,25 @@ func (n *EVPNNLRI) DecodeFromBytes(data []byte) error { return n.RouteTypeData.DecodeFromBytes(data[:n.Length]) } -func (n *EVPNNLRI) Serialize() ([]byte, error) { - buf := make([]byte, 2) - buf[0] = n.RouteType +func (n *EVPNNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { + var buf []byte + if handleAddPath(false, RF_EVPN, options) { + var err error + buf, err = n.serializeIdentifier() + if err != nil { + return nil, err + } + } + offset := len(buf) + buf = append(buf, make([]byte, 2)...) + buf[offset] = n.RouteType tbuf, err := n.RouteTypeData.Serialize() n.Length = uint8(len(tbuf)) - buf[1] = n.Length + buf[offset+1] = n.Length if err != nil { return nil, err } - buf = append(buf, tbuf...) - return buf, nil + return append(buf, tbuf...), nil } func (n *EVPNNLRI) AFI() uint16 { @@ -2353,7 +2527,7 @@ func (n *EVPNNLRI) SAFI() uint8 { return SAFI_EVPN } -func (n *EVPNNLRI) Len() int { +func (n *EVPNNLRI) Len(options ...*MarshallingOption) int { return int(n.Length) + 2 } @@ -2380,9 +2554,9 @@ func (n *EVPNNLRI) RD() RouteDistinguisherInterface { func NewEVPNNLRI(routetype uint8, length uint8, routetypedata EVPNRouteTypeInterface) *EVPNNLRI { return &EVPNNLRI{ - routetype, - length, - routetypedata, + RouteType: routetype, + Length: length, + RouteTypeData: routetypedata, } } @@ -2391,7 +2565,21 @@ type EncapNLRI struct { addrlen uint8 } -func (n *EncapNLRI) DecodeFromBytes(data []byte) error { +func (n *EncapNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + if n.addrlen == 0 { + n.addrlen = 4 + } + f := RF_IPv4_ENCAP + if n.addrlen == 16 { + f = RF_IPv6_ENCAP + } + if handleAddPath(true, f, options) { + var err error + data, err = n.decodePathIdentifier(data) + if err != nil { + return err + } + } if len(data) < 4 { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) @@ -2404,9 +2592,26 @@ func (n *EncapNLRI) DecodeFromBytes(data []byte) error { return n.decodePrefix(data[1:], n.Length, n.addrlen) } -func (n *EncapNLRI) Serialize() ([]byte, error) { - buf := make([]byte, 1) - buf[0] = n.Length +func (n *EncapNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { + var buf []byte + f := RF_IPv4_ENCAP + if n.addrlen == 16 { + f = RF_IPv6_ENCAP + } + if handleAddPath(false, f, options) { + var err error + buf, err = n.serializeIdentifier() + if err != nil { + return nil, err + } + } + if n.Prefix.To4() != nil { + buf = append(buf, net.IPv4len*8) + n.Prefix = n.Prefix.To4() + } else { + buf = append(buf, net.IPv6len*8) + } + n.Length = buf[len(buf)-1] pbuf, err := n.serializePrefix(n.Length) if err != nil { return nil, err @@ -2428,7 +2633,7 @@ func (n *EncapNLRI) SAFI() uint8 { func NewEncapNLRI(endpoint string) *EncapNLRI { return &EncapNLRI{ - IPAddrPrefixDefault{32, net.ParseIP(endpoint).To4()}, + IPAddrPrefixDefault{Length: 32, Prefix: net.ParseIP(endpoint).To4()}, 4, } } @@ -2444,7 +2649,7 @@ func (n *Encapv6NLRI) AFI() uint16 { func NewEncapv6NLRI(endpoint string) *Encapv6NLRI { return &Encapv6NLRI{ EncapNLRI{ - IPAddrPrefixDefault{128, net.ParseIP(endpoint)}, + IPAddrPrefixDefault{Length: 128, Prefix: net.ParseIP(endpoint)}, 16, }, } @@ -2622,27 +2827,26 @@ func parseTcpFlagCmd(myCmd string) ([][2]int, error) { for index < len(myCmd) { myCmdChar := myCmd[index : index+1] switch myCmdChar { - case TCPFlagOpNameMap[TCP_FLAG_OP_MATCH]: - if bit := TCPFlagOpValueMap[myCmdChar]; bit&TCPFlagOp(operatorValue[0]) == 0 { + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]: + if bit := BitmaskFlagOpValueMap[myCmdChar]; bit&BitmaskFlagOp(operatorValue[0]) == 0 { operatorValue[0] |= int(bit) index++ } else { err := fmt.Errorf("Match flag appears multiple time") return nil, err } - case TCPFlagOpNameMap[TCP_FLAG_OP_NOT]: - if bit := TCPFlagOpValueMap[myCmdChar]; bit&TCPFlagOp(operatorValue[0]) == 0 { + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]: + if bit := BitmaskFlagOpValueMap[myCmdChar]; bit&BitmaskFlagOp(operatorValue[0]) == 0 { operatorValue[0] |= int(bit) index++ } else { err := fmt.Errorf("Not flag appears multiple time") return nil, err } - case TCPFlagOpNameMap[TCP_FLAG_OP_AND], TCPFlagOpNameMap[TCP_FLAG_OP_OR]: - if bit := TCPFlagOpValueMap[myCmdChar]; bit&TCPFlagOp(operatorValue[0]) == 0 { - operatorValue[0] |= int(bit) + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND], BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR]: + if bit := BitmaskFlagOpValueMap[myCmdChar]; bit&BitmaskFlagOp(operatorValue[0]) == 0 { tcpOperatorsFlagsValues = append(tcpOperatorsFlagsValues, operatorValue) - operatorValue[0] = 0 + operatorValue[0] = int(bit) operatorValue[1] = 0 index++ } else { @@ -2657,7 +2861,7 @@ func parseTcpFlagCmd(myCmd string) ([][2]int, error) { // we loop till we reach the end of TCP flags description // exit conditions : we reach the end of tcp flags (we find & or ' ') or we reach the end of the line for loopIndex < len(myCmd) && - (myLoopChar != TCPFlagOpNameMap[TCP_FLAG_OP_AND] && myLoopChar != TCPFlagOpNameMap[TCP_FLAG_OP_OR]) { + (myLoopChar != BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND] && myLoopChar != BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR]) { // we check if inspected charater is a well known tcp flag and if it doesn't appear twice if bit, isPresent := TCPFlagValueMap[myLoopChar]; isPresent && (bit&TCPFlag(operatorValue[1]) == 0) { operatorValue[1] |= int(bit) // we set this flag @@ -2677,7 +2881,7 @@ func parseTcpFlagCmd(myCmd string) ([][2]int, error) { return nil, err } } - operatorValue[0] |= int(TCPFlagOpValueMap["E"]) + operatorValue[0] |= int(BitmaskFlagOpValueMap["E"]) tcpOperatorsFlagsValues = append(tcpOperatorsFlagsValues, operatorValue) return tcpOperatorsFlagsValues, nil } @@ -2853,27 +3057,48 @@ func flowSpecFragmentParser(rf RouteFamily, args []string) (FlowSpecComponentInt return nil, fmt.Errorf("invalid flowspec fragment specifier") } items := make([]*FlowSpecComponentItem, 0) - for _, a := range args[1:] { - value := 0 - switch a { - case "dont-fragment": - if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP6 { - return nil, fmt.Errorf("can't specify dont-fragment for ipv6") + cmd := strings.Join(args[1:], " ") + var op byte + var flags byte + for cmd != "" { + next := 1 + c := cmd[0:1] + switch c { + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]: + if op&BITMASK_FLAG_OP_MATCH != 0 { + err := fmt.Errorf("invalid flowspec fragment specifier: '=' flag appears multiple time", cmd) + return nil, err + } + op |= BITMASK_FLAG_OP_MATCH + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]: + if op&BITMASK_FLAG_OP_NOT != 0 { + err := fmt.Errorf("invalid flowspec fragment specifier: '!' flag appears multiple time", cmd) + return nil, err } - value = 0x1 - case "is-fragment": - value = 0x2 - case "first-fragment": - value = 0x4 - case "last-fragment": - value = 0x8 - case "not-a-fragment": - value = 0x0 + op = op | BITMASK_FLAG_OP_NOT + case BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND], BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR]: + operand := BitmaskFlagOpValueMap[c] + items = append(items, NewFlowSpecComponentItem(int(op), int(flags))) + op = byte(operand) + flags = byte(0) default: - return nil, fmt.Errorf("invalid flowspec fragment specifier") + for k, v := range FragmentFlagNameMap { + length := len(v) + if (len(cmd) >= length) && (cmd[:length] == v) { + flags = flags | byte(k) + next = length + break + } + } + // if not matched with any of FragmentFlags + if next == 1 { + return nil, fmt.Errorf("invalid flowspec fragment specifier: %s", cmd) + } } - items = append(items, NewFlowSpecComponentItem(0, value)) + cmd = cmd[next:] } + op = op | BITMASK_FLAG_OP_END + items = append(items, NewFlowSpecComponentItem(int(op), int(flags))) return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil } @@ -2969,9 +3194,9 @@ func (t BGPFlowSpecType) String() string { } type FlowSpecComponentInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int + DecodeFromBytes([]byte, ...*MarshallingOption) error + Serialize(...*MarshallingOption) ([]byte, error) + Len(...*MarshallingOption) int Type() BGPFlowSpecType String() string } @@ -2981,22 +3206,22 @@ type flowSpecPrefix struct { type_ BGPFlowSpecType } -func (p *flowSpecPrefix) DecodeFromBytes(data []byte) error { +func (p *flowSpecPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { p.type_ = BGPFlowSpecType(data[0]) - return p.Prefix.DecodeFromBytes(data[1:]) + return p.Prefix.DecodeFromBytes(data[1:], options...) } -func (p *flowSpecPrefix) Serialize() ([]byte, error) { +func (p *flowSpecPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := []byte{byte(p.Type())} - bbuf, err := p.Prefix.Serialize() + bbuf, err := p.Prefix.Serialize(options...) if err != nil { return nil, err } return append(buf, bbuf...), nil } -func (p *flowSpecPrefix) Len() int { - buf, _ := p.Serialize() +func (p *flowSpecPrefix) Len(options ...*MarshallingOption) int { + buf, _ := p.Serialize(options...) return len(buf) } @@ -3026,16 +3251,16 @@ type flowSpecPrefix6 struct { // draft-ietf-idr-flow-spec-v6-06 // -func (p *flowSpecPrefix6) DecodeFromBytes(data []byte) error { +func (p *flowSpecPrefix6) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { p.type_ = BGPFlowSpecType(data[0]) p.Offset = data[2] prefix := append([]byte{data[1]}, data[3:]...) - return p.Prefix.DecodeFromBytes(prefix) + return p.Prefix.DecodeFromBytes(prefix, options...) } -func (p *flowSpecPrefix6) Serialize() ([]byte, error) { +func (p *flowSpecPrefix6) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := []byte{byte(p.Type())} - bbuf, err := p.Prefix.Serialize() + bbuf, err := p.Prefix.Serialize(options...) if err != nil { return nil, err } @@ -3044,8 +3269,8 @@ func (p *flowSpecPrefix6) Serialize() ([]byte, error) { return append(buf, bbuf[1:]...), nil } -func (p *flowSpecPrefix6) Len() int { - buf, _ := p.Serialize() +func (p *flowSpecPrefix6) Len(options ...*MarshallingOption) int { + buf, _ := p.Serialize(options...) return len(buf) } @@ -3106,7 +3331,7 @@ type flowSpecMac struct { type_ BGPFlowSpecType } -func (p *flowSpecMac) DecodeFromBytes(data []byte) error { +func (p *flowSpecMac) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { if len(data) < 2 || len(data) < 2+int(data[1]) { return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all mac bits available") } @@ -3115,7 +3340,7 @@ func (p *flowSpecMac) DecodeFromBytes(data []byte) error { return nil } -func (p *flowSpecMac) Serialize() ([]byte, error) { +func (p *flowSpecMac) Serialize(options ...*MarshallingOption) ([]byte, error) { if len(p.Mac) == 0 { return nil, fmt.Errorf("mac unset") } @@ -3123,7 +3348,7 @@ func (p *flowSpecMac) Serialize() ([]byte, error) { return append(buf, []byte(p.Mac)...), nil } -func (p *flowSpecMac) Len() int { +func (p *flowSpecMac) Len(options ...*MarshallingOption) int { return 2 + len(p.Mac) } @@ -3224,7 +3449,7 @@ type FlowSpecComponent struct { type_ BGPFlowSpecType } -func (p *FlowSpecComponent) DecodeFromBytes(data []byte) error { +func (p *FlowSpecComponent) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { p.type_ = BGPFlowSpecType(data[0]) data = data[1:] p.Items = make([]*FlowSpecComponentItem, 0) @@ -3248,7 +3473,7 @@ func (p *FlowSpecComponent) DecodeFromBytes(data []byte) error { return nil } -func (p *FlowSpecComponent) Serialize() ([]byte, error) { +func (p *FlowSpecComponent) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := []byte{byte(p.Type())} for i, v := range p.Items { //set end-of-list bit @@ -3266,7 +3491,7 @@ func (p *FlowSpecComponent) Serialize() ([]byte, error) { return buf, nil } -func (p *FlowSpecComponent) Len() int { +func (p *FlowSpecComponent) Len(options ...*MarshallingOption) int { l := 1 for _, item := range p.Items { l += (item.Len() + 1) @@ -3326,46 +3551,44 @@ func formatProto(op int, value int) string { func formatFlag(op int, value int) string { var retString string - if op&TCP_FLAG_OP_MATCH > 0 { - retString = fmt.Sprintf("%s%s", retString, TCPFlagOpNameMap[TCP_FLAG_OP_MATCH]) + if op&BITMASK_FLAG_OP_MATCH > 0 { + retString = fmt.Sprintf("%s%s", retString, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]) } - if op&TCP_FLAG_OP_NOT > 0 { - retString = fmt.Sprintf("%s%s", retString, TCPFlagOpNameMap[TCP_FLAG_OP_NOT]) + if op&BITMASK_FLAG_OP_NOT > 0 { + retString = fmt.Sprintf("%s%s", retString, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]) } for flag, valueFlag := range TCPFlagValueMap { if value&int(valueFlag) > 0 { retString = fmt.Sprintf("%s%s", retString, flag) } } - if op&TCP_FLAG_OP_AND > 0 { - retString = fmt.Sprintf("%s%s", retString, TCPFlagOpNameMap[TCP_FLAG_OP_AND]) + if op&BITMASK_FLAG_OP_AND > 0 { + retString = fmt.Sprintf("%s%s", BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND], retString) } else { // default is or - retString = fmt.Sprintf("%s%s", retString, TCPFlagOpNameMap[TCP_FLAG_OP_OR]) + retString = fmt.Sprintf("%s%s", BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR], retString) } return retString } func formatFragment(op int, value int) string { - ss := make([]string, 0) - if value == 0 { - ss = append(ss, "not-a-fragment") - } - if value&0x1 > 0 { - ss = append(ss, "dont-fragment") - } - if value&0x2 > 0 { - ss = append(ss, "is-fragment") + var retString string + if op&BITMASK_FLAG_OP_MATCH > 0 { + retString = fmt.Sprintf("%s%s", retString, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]) } - if value&0x4 > 0 { - ss = append(ss, "first-fragment") + if op&BITMASK_FLAG_OP_NOT > 0 { + retString = fmt.Sprintf("%s%s", retString, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]) } - if value&0x8 > 0 { - ss = append(ss, "last-fragment") + for flag, valueFlag := range FragmentFlagValueMap { + if value&int(valueFlag) > 0 { + retString = fmt.Sprintf("%s%s", retString, flag) + } } - if len(ss) > 1 { - return fmt.Sprintf("%s(%s)", formatNumericOp(op), strings.Join(ss, "|")) + if op&BITMASK_FLAG_OP_AND > 0 { + retString = fmt.Sprintf("%s%s", BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND], retString) + } else { // default is or + retString = fmt.Sprintf("%s%s", BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR], retString) } - return fmt.Sprintf("%s%s", formatNumericOp(op), ss[0]) + return retString } func formatEtherType(op int, value int) string { @@ -3429,16 +3652,16 @@ type FlowSpecUnknown struct { Value []byte } -func (p *FlowSpecUnknown) DecodeFromBytes(data []byte) error { +func (p *FlowSpecUnknown) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { p.Value = data return nil } -func (p *FlowSpecUnknown) Serialize() ([]byte, error) { +func (p *FlowSpecUnknown) Serialize(options ...*MarshallingOption) ([]byte, error) { return p.Value, nil } -func (p *FlowSpecUnknown) Len() int { +func (p *FlowSpecUnknown) Len(options ...*MarshallingOption) int { return len(p.Value) } @@ -3464,6 +3687,7 @@ func (p *FlowSpecUnknown) MarshalJSON() ([]byte, error) { } type FlowSpecNLRI struct { + PrefixDefault Value []FlowSpecComponentInterface rf RouteFamily rd RouteDistinguisherInterface @@ -3483,7 +3707,14 @@ func (n *FlowSpecNLRI) RD() RouteDistinguisherInterface { return n.rd } -func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error { +func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...*MarshallingOption) error { + if handleAddPath(true, rf, options) { + var err error + data, err = n.decodePathIdentifier(data) + if err != nil { + return err + } + } var length int if (data[0]>>4) == 0xf && len(data) > 2 { length = int(binary.BigEndian.Uint16(data[0:2])) @@ -3555,19 +3786,19 @@ func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error { i = &FlowSpecUnknown{} } - err := i.DecodeFromBytes(data) + err := i.DecodeFromBytes(data, options...) if err != nil { i = &FlowSpecUnknown{data} } - l -= i.Len() - data = data[i.Len():] + l -= i.Len(options...) + data = data[i.Len(options...):] n.Value = append(n.Value, i) } return nil } -func (n *FlowSpecNLRI) Serialize() ([]byte, error) { +func (n *FlowSpecNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0, 32) if n.SAFI() == SAFI_FLOW_SPEC_VPN { if n.rd == nil { @@ -3580,13 +3811,13 @@ func (n *FlowSpecNLRI) Serialize() ([]byte, error) { buf = append(buf, b...) } for _, v := range n.Value { - b, err := v.Serialize() + b, err := v.Serialize(options...) if err != nil { return nil, err } buf = append(buf, b...) } - length := n.Len() + length := n.Len(options...) if length > 0xfff { return nil, fmt.Errorf("Too large: %d", length) } else if length < 0xf0 { @@ -3599,16 +3830,23 @@ func (n *FlowSpecNLRI) Serialize() ([]byte, error) { buf = append(b, buf...) } + if handleAddPath(false, n.rf, options) { + id, err := n.serializeIdentifier() + if err != nil { + return nil, err + } + return append(id, buf...), nil + } return buf, nil } -func (n *FlowSpecNLRI) Len() int { +func (n *FlowSpecNLRI) Len(options ...*MarshallingOption) int { l := 0 if n.SAFI() == SAFI_FLOW_SPEC_VPN { l += n.RD().Len() } for _, v := range n.Value { - l += v.Len() + l += v.Len(options...) } if l < 0xf0 { return l + 1 @@ -3771,32 +4009,32 @@ type FlowSpecIPv4Unicast struct { FlowSpecNLRI } -func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) +func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) } func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast { - return &FlowSpecIPv4Unicast{FlowSpecNLRI{value, RF_FS_IPv4_UC, nil}} + return &FlowSpecIPv4Unicast{FlowSpecNLRI{Value: value, rf: RF_FS_IPv4_UC}} } type FlowSpecIPv4VPN struct { FlowSpecNLRI } -func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) +func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) } func NewFlowSpecIPv4VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv4VPN { - return &FlowSpecIPv4VPN{FlowSpecNLRI{value, RF_FS_IPv4_VPN, rd}} + return &FlowSpecIPv4VPN{FlowSpecNLRI{Value: value, rf: RF_FS_IPv4_VPN, rd: rd}} } type FlowSpecIPv6Unicast struct { FlowSpecNLRI } -func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) +func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) } func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast { @@ -3810,8 +4048,8 @@ type FlowSpecIPv6VPN struct { FlowSpecNLRI } -func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) +func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) } func NewFlowSpecIPv6VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv6VPN { @@ -3826,7 +4064,7 @@ type FlowSpecL2VPN struct { FlowSpecNLRI } -func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte) error { +func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) } @@ -3839,15 +4077,23 @@ func NewFlowSpecL2VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentI } type OpaqueNLRI struct { + PrefixDefault Length uint16 Key []byte Value []byte } -func (n *OpaqueNLRI) DecodeFromBytes(data []byte) error { +func (n *OpaqueNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { if len(data) < 2 { return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available") } + if handleAddPath(true, RF_OPAQUE, options) { + var err error + data, err = n.decodePathIdentifier(data) + if err != nil { + return err + } + } n.Length = binary.BigEndian.Uint16(data[0:2]) if len(data)-2 < int(n.Length) { return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available") @@ -3857,14 +4103,22 @@ func (n *OpaqueNLRI) DecodeFromBytes(data []byte) error { return nil } -func (n *OpaqueNLRI) Serialize() ([]byte, error) { +func (n *OpaqueNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { if len(n.Key) > math.MaxUint16 { return nil, fmt.Errorf("Key length too big") } buf := make([]byte, 2) binary.BigEndian.PutUint16(buf, uint16(len(n.Key))) buf = append(buf, n.Key...) - return append(buf, n.Value...), nil + buf = append(buf, n.Value...) + if handleAddPath(false, RF_OPAQUE, options) { + id, err := n.serializeIdentifier() + if err != nil { + return nil, err + } + return append(id, buf...), nil + } + return buf, nil } func (n *OpaqueNLRI) AFI() uint16 { @@ -3875,7 +4129,7 @@ func (n *OpaqueNLRI) SAFI() uint8 { return SAFI_KEY_VALUE } -func (n *OpaqueNLRI) Len() int { +func (n *OpaqueNLRI) Len(options ...*MarshallingOption) int { return 2 + len(n.Key) + len(n.Value) } @@ -4289,9 +4543,9 @@ var PathAttrFlags map[BGPAttrType]BGPAttrFlag = map[BGPAttrType]BGPAttrFlag{ } type PathAttributeInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int + DecodeFromBytes([]byte, ...*MarshallingOption) error + Serialize(...*MarshallingOption) ([]byte, error) + Len(...*MarshallingOption) int GetFlags() BGPAttrFlag GetType() BGPAttrType String() string @@ -4306,7 +4560,7 @@ type PathAttribute struct { Value []byte } -func (p *PathAttribute) Len() int { +func (p *PathAttribute) Len(options ...*MarshallingOption) int { if p.Length == 0 { p.Length = uint16(len(p.Value)) } @@ -4327,7 +4581,7 @@ func (p *PathAttribute) GetType() BGPAttrType { return p.Type } -func (p *PathAttribute) DecodeFromBytes(data []byte) error { +func (p *PathAttribute) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { odata := data eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) @@ -4359,19 +4613,19 @@ func (p *PathAttribute) DecodeFromBytes(data []byte) error { ok, eMsg := ValidateFlags(p.Type, p.Flags) if !ok { - return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, odata[:p.Len()], eMsg) + return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, odata[:p.Len(options...)], eMsg) } return nil } -func (p *PathAttribute) Serialize() ([]byte, error) { +func (p *PathAttribute) Serialize(options ...*MarshallingOption) ([]byte, error) { p.Length = uint16(len(p.Value)) if p.Length > 255 { p.Flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH } else { p.Flags &^= BGP_ATTR_FLAG_EXTENDED_LENGTH } - buf := make([]byte, p.Len()) + buf := make([]byte, p.Len(options...)) buf[0] = uint8(p.Flags) buf[1] = uint8(p.Type) if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { @@ -4688,8 +4942,8 @@ type PathAttributeAsPath struct { Value []AsPathParamInterface } -func (p *PathAttributeAsPath) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeAsPath) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -4699,7 +4953,7 @@ func (p *PathAttributeAsPath) DecodeFromBytes(data []byte) error { } as4Bytes, err := p.DefaultAsPath.isValidAspath(p.PathAttribute.Value) if err != nil { - err.(*MessageError).Data = data[:p.Len()] + err.(*MessageError).Data = data[:p.Len(options...)] return err } v := p.PathAttribute.Value @@ -4723,7 +4977,7 @@ func (p *PathAttributeAsPath) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeAsPath) Serialize() ([]byte, error) { +func (p *PathAttributeAsPath) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, v := range p.Value { vbuf, err := v.Serialize() @@ -4733,7 +4987,7 @@ func (p *PathAttributeAsPath) Serialize() ([]byte, error) { buf = append(buf, vbuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeAsPath) String() string { @@ -4770,8 +5024,8 @@ type PathAttributeNextHop struct { Value net.IP } -func (p *PathAttributeNextHop) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeNextHop) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -4784,9 +5038,9 @@ func (p *PathAttributeNextHop) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeNextHop) Serialize() ([]byte, error) { +func (p *PathAttributeNextHop) Serialize(options ...*MarshallingOption) ([]byte, error) { p.PathAttribute.Value = p.Value - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeNextHop) String() string { @@ -4823,8 +5077,8 @@ type PathAttributeMultiExitDisc struct { Value uint32 } -func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -4837,11 +5091,11 @@ func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeMultiExitDisc) Serialize() ([]byte, error) { +func (p *PathAttributeMultiExitDisc) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 4) binary.BigEndian.PutUint32(buf, p.Value) p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeMultiExitDisc) String() string { @@ -4874,8 +5128,8 @@ type PathAttributeLocalPref struct { Value uint32 } -func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -4888,11 +5142,11 @@ func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeLocalPref) Serialize() ([]byte, error) { +func (p *PathAttributeLocalPref) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 4) binary.BigEndian.PutUint32(buf, p.Value) p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeLocalPref) String() string { @@ -4957,8 +5211,8 @@ type PathAttributeAggregator struct { Value PathAttributeAggregatorParam } -func (p *PathAttributeAggregator) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeAggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -4979,7 +5233,7 @@ func (p *PathAttributeAggregator) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeAggregator) Serialize() ([]byte, error) { +func (p *PathAttributeAggregator) Serialize(options ...*MarshallingOption) ([]byte, error) { var buf []byte switch p.Value.Askind { case reflect.Uint16: @@ -4993,7 +5247,7 @@ func (p *PathAttributeAggregator) Serialize() ([]byte, error) { } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeAggregator) String() string { @@ -5033,8 +5287,8 @@ type PathAttributeCommunities struct { Value []uint32 } -func (p *PathAttributeCommunities) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -5051,13 +5305,13 @@ func (p *PathAttributeCommunities) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeCommunities) Serialize() ([]byte, error) { +func (p *PathAttributeCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, len(p.Value)*4) for i, v := range p.Value { binary.BigEndian.PutUint32(buf[i*4:], v) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } type WellKnownCommunity uint32 @@ -5153,8 +5407,8 @@ type PathAttributeOriginatorId struct { Value net.IP } -func (p *PathAttributeOriginatorId) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeOriginatorId) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -5181,11 +5435,11 @@ func (p *PathAttributeOriginatorId) MarshalJSON() ([]byte, error) { }) } -func (p *PathAttributeOriginatorId) Serialize() ([]byte, error) { +func (p *PathAttributeOriginatorId) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 4) copy(buf, p.Value) p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func NewPathAttributeOriginatorId(value string) *PathAttributeOriginatorId { @@ -5205,8 +5459,8 @@ type PathAttributeClusterList struct { Value []net.IP } -func (p *PathAttributeClusterList) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeClusterList) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -5223,13 +5477,13 @@ func (p *PathAttributeClusterList) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeClusterList) Serialize() ([]byte, error) { +func (p *PathAttributeClusterList) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, len(p.Value)*4) for i, v := range p.Value { copy(buf[i*4:], v) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeClusterList) String() string { @@ -5275,8 +5529,8 @@ type PathAttributeMpReachNLRI struct { Value []AddrPrefixInterface } -func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -5292,7 +5546,7 @@ func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte) error { p.SAFI = safi _, err = NewPrefixFromRouteFamily(afi, safi) if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error()) + return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len(options...)], err.Error()) } nexthoplen := int(value[3]) if len(value) < 4+nexthoplen { @@ -5324,25 +5578,29 @@ func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte) error { return NewMessageError(eCode, eSubCode, value, "no skip byte") } value = value[1:] + addpathLen := 0 + if handleAddPath(true, AfiSafiToRouteFamily(afi, safi), options) { + addpathLen = 4 + } for len(value) > 0 { prefix, err := NewPrefixFromRouteFamily(afi, safi) if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error()) + return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len(options...)], err.Error()) } - err = prefix.DecodeFromBytes(value) + err = prefix.DecodeFromBytes(value, options...) if err != nil { return err } - if prefix.Len() > len(value) { + if prefix.Len(options...)+addpathLen > len(value) { return NewMessageError(eCode, eSubCode, value, "prefix length is incorrect") } - value = value[prefix.Len():] + value = value[prefix.Len(options...)+addpathLen:] p.Value = append(p.Value, prefix) } return nil } -func (p *PathAttributeMpReachNLRI) Serialize() ([]byte, error) { +func (p *PathAttributeMpReachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { afi := p.AFI safi := p.SAFI nexthoplen := 4 @@ -5376,14 +5634,14 @@ func (p *PathAttributeMpReachNLRI) Serialize() ([]byte, error) { } buf = append(buf, make([]byte, 1)...) for _, prefix := range p.Value { - pbuf, err := prefix.Serialize() + pbuf, err := prefix.Serialize(options...) if err != nil { return nil, err } buf = append(buf, pbuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeMpReachNLRI) MarshalJSON() ([]byte, error) { @@ -5445,8 +5703,8 @@ type PathAttributeMpUnreachNLRI struct { Value []AddrPrefixInterface } -func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -5461,42 +5719,46 @@ func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte) error { safi := value[2] _, err = NewPrefixFromRouteFamily(afi, safi) if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error()) + return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len(options...)], err.Error()) } value = value[3:] p.AFI = afi p.SAFI = safi + addpathLen := 0 + if handleAddPath(true, AfiSafiToRouteFamily(afi, safi), options) { + addpathLen = 4 + } for len(value) > 0 { prefix, err := NewPrefixFromRouteFamily(afi, safi) if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error()) + return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len(options...)], err.Error()) } - err = prefix.DecodeFromBytes(value) + err = prefix.DecodeFromBytes(value, options...) if err != nil { return err } - if prefix.Len() > len(value) { - return NewMessageError(eCode, eSubCode, data[:p.PathAttribute.Len()], "prefix length is incorrect") + if prefix.Len(options...)+addpathLen > len(value) { + return NewMessageError(eCode, eSubCode, data[:p.PathAttribute.Len(options...)], "prefix length is incorrect") } - value = value[prefix.Len():] + value = value[prefix.Len(options...)+addpathLen:] p.Value = append(p.Value, prefix) } return nil } -func (p *PathAttributeMpUnreachNLRI) Serialize() ([]byte, error) { +func (p *PathAttributeMpUnreachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 3) binary.BigEndian.PutUint16(buf, p.AFI) buf[2] = p.SAFI for _, prefix := range p.Value { - pbuf, err := prefix.Serialize() + pbuf, err := prefix.Serialize(options...) if err != nil { return nil, err } buf = append(buf, pbuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeMpUnreachNLRI) String() string { @@ -6598,8 +6860,8 @@ func ParseExtended(data []byte) (ExtendedCommunityInterface, error) { } } -func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -6620,7 +6882,7 @@ func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeExtendedCommunities) Serialize() ([]byte, error) { +func (p *PathAttributeExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, p := range p.Value { ebuf, err := p.Serialize() @@ -6630,7 +6892,7 @@ func (p *PathAttributeExtendedCommunities) Serialize() ([]byte, error) { buf = append(buf, ebuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeExtendedCommunities) String() string { @@ -6673,8 +6935,8 @@ type PathAttributeAs4Path struct { DefaultAsPath } -func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -6700,7 +6962,7 @@ func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeAs4Path) Serialize() ([]byte, error) { +func (p *PathAttributeAs4Path) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, v := range p.Value { vbuf, err := v.Serialize() @@ -6710,7 +6972,7 @@ func (p *PathAttributeAs4Path) Serialize() ([]byte, error) { buf = append(buf, vbuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeAs4Path) String() string { @@ -6737,8 +6999,8 @@ type PathAttributeAs4Aggregator struct { Value PathAttributeAggregatorParam } -func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -6752,12 +7014,12 @@ func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeAs4Aggregator) Serialize() ([]byte, error) { +func (p *PathAttributeAs4Aggregator) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 8) binary.BigEndian.PutUint32(buf[0:], p.Value.AS) copy(buf[4:], p.Value.Address.To4()) p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func NewPathAttributeAs4Aggregator(as uint32, address string) *PathAttributeAs4Aggregator { @@ -6918,8 +7180,8 @@ type PathAttributeTunnelEncap struct { Value []*TunnelEncapTLV } -func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -6949,7 +7211,7 @@ func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeTunnelEncap) Serialize() ([]byte, error) { +func (p *PathAttributeTunnelEncap) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, t := range p.Value { bbuf, err := t.Serialize() @@ -6959,7 +7221,7 @@ func (p *PathAttributeTunnelEncap) Serialize() ([]byte, error) { buf = append(buf, bbuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func NewPathAttributeTunnelEncap(value []*TunnelEncapTLV) *PathAttributeTunnelEncap { @@ -7013,8 +7275,8 @@ type PathAttributePmsiTunnel struct { TunnelID PmsiTunnelIDInterface } -func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -7039,7 +7301,7 @@ func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributePmsiTunnel) Serialize() ([]byte, error) { +func (p *PathAttributePmsiTunnel) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 2) if p.IsLeafInfoRequired { buf[0] = 0x01 @@ -7054,7 +7316,7 @@ func (p *PathAttributePmsiTunnel) Serialize() ([]byte, error) { } buf = append(buf, ibuf...) p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributePmsiTunnel) String() string { @@ -7208,7 +7470,7 @@ func ParseIP6Extended(data []byte) (ExtendedCommunityInterface, error) { } } -func (p *PathAttributeIP6ExtendedCommunities) DecodeFromBytes(data []byte) error { +func (p *PathAttributeIP6ExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { err := p.PathAttribute.DecodeFromBytes(data) if err != nil { return err @@ -7230,7 +7492,7 @@ func (p *PathAttributeIP6ExtendedCommunities) DecodeFromBytes(data []byte) error return nil } -func (p *PathAttributeIP6ExtendedCommunities) Serialize() ([]byte, error) { +func (p *PathAttributeIP6ExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, p := range p.Value { ebuf, err := p.Serialize() @@ -7277,8 +7539,8 @@ type PathAttributeAigp struct { Values []AigpTLV } -func (p *PathAttributeAigp) DecodeFromBytes(data []byte) error { - err := p.PathAttribute.DecodeFromBytes(data) +func (p *PathAttributeAigp) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { + err := p.PathAttribute.DecodeFromBytes(data, options...) if err != nil { return err } @@ -7317,7 +7579,7 @@ func (p *PathAttributeAigp) DecodeFromBytes(data []byte) error { return NewMessageError(eCode, eSubCode, nil, "Aigp length is incorrect") } -func (p *PathAttributeAigp) Serialize() ([]byte, error) { +func (p *PathAttributeAigp) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, t := range p.Values { bbuf, err := t.Serialize() @@ -7327,7 +7589,7 @@ func (p *PathAttributeAigp) Serialize() ([]byte, error) { buf = append(buf, bbuf...) } p.PathAttribute.Value = buf - return p.PathAttribute.Serialize() + return p.PathAttribute.Serialize(options...) } func (p *PathAttributeAigp) String() string { @@ -7408,7 +7670,7 @@ type PathAttributeLargeCommunities struct { Values []*LargeCommunity } -func (p *PathAttributeLargeCommunities) DecodeFromBytes(data []byte) error { +func (p *PathAttributeLargeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { err := p.PathAttribute.DecodeFromBytes(data) if err != nil { return err @@ -7434,7 +7696,7 @@ func (p *PathAttributeLargeCommunities) DecodeFromBytes(data []byte) error { return nil } -func (p *PathAttributeLargeCommunities) Serialize() ([]byte, error) { +func (p *PathAttributeLargeCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 0) for _, t := range p.Values { bbuf, err := t.Serialize() @@ -7543,7 +7805,7 @@ type BGPUpdate struct { NLRI []*IPAddrPrefix } -func (msg *BGPUpdate) DecodeFromBytes(data []byte) error { +func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { // cache error codes eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) @@ -7562,18 +7824,23 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte) error { return NewMessageError(eCode, eSubCode, nil, "withdrawn route length exceeds message length") } + addpathLen := 0 + if handleAddPath(true, RF_IPv4_UC, options) { + addpathLen = 4 + } + msg.WithdrawnRoutes = make([]*IPAddrPrefix, 0, msg.WithdrawnRoutesLen) for routelen := msg.WithdrawnRoutesLen; routelen > 0; { w := &IPAddrPrefix{} - err := w.DecodeFromBytes(data) + err := w.DecodeFromBytes(data, options...) if err != nil { return err } - routelen -= uint16(w.Len()) - if len(data) < w.Len() { + routelen -= uint16(w.Len(options...) + addpathLen) + if len(data) < w.Len(options...)+addpathLen { return NewMessageError(eCode, eSubCode, nil, "Withdrawn route length is short") } - data = data[w.Len():] + data = data[w.Len(options...)+addpathLen:] msg.WithdrawnRoutes = append(msg.WithdrawnRoutes, w) } @@ -7596,40 +7863,40 @@ func (msg *BGPUpdate) DecodeFromBytes(data []byte) error { if err != nil { return err } - err = p.DecodeFromBytes(data) + err = p.DecodeFromBytes(data, options...) if err != nil { return err } - pathlen -= uint16(p.Len()) - if len(data) < p.Len() { + pathlen -= uint16(p.Len(options...)) + if len(data) < p.Len(options...) { return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, "attribute length is short") } - data = data[p.Len():] + data = data[p.Len(options...):] msg.PathAttributes = append(msg.PathAttributes, p) } msg.NLRI = make([]*IPAddrPrefix, 0) for restlen := len(data); restlen > 0; { n := &IPAddrPrefix{} - err := n.DecodeFromBytes(data) + err := n.DecodeFromBytes(data, options...) if err != nil { return err } - restlen -= n.Len() - if len(data) < n.Len() { + restlen -= n.Len(options...) + addpathLen + if len(data) < n.Len(options...)+addpathLen { return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is short") } - data = data[n.Len():] + data = data[n.Len(options...)+addpathLen:] msg.NLRI = append(msg.NLRI, n) } return nil } -func (msg *BGPUpdate) Serialize() ([]byte, error) { +func (msg *BGPUpdate) Serialize(options ...*MarshallingOption) ([]byte, error) { wbuf := make([]byte, 2) for _, w := range msg.WithdrawnRoutes { - onewbuf, err := w.Serialize() + onewbuf, err := w.Serialize(options...) if err != nil { return nil, err } @@ -7640,7 +7907,7 @@ func (msg *BGPUpdate) Serialize() ([]byte, error) { pbuf := make([]byte, 2) for _, p := range msg.PathAttributes { - onepbuf, err := p.Serialize() + onepbuf, err := p.Serialize(options...) if err != nil { return nil, err } @@ -7651,7 +7918,7 @@ func (msg *BGPUpdate) Serialize() ([]byte, error) { buf := append(wbuf, pbuf...) for _, n := range msg.NLRI { - nbuf, err := n.Serialize() + nbuf, err := n.Serialize(options...) if err != nil { return nil, err } @@ -7706,7 +7973,7 @@ type BGPNotification struct { Data []byte } -func (msg *BGPNotification) DecodeFromBytes(data []byte) error { +func (msg *BGPNotification) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { if len(data) < 2 { return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all Notificaiton bytes available") } @@ -7718,7 +7985,7 @@ func (msg *BGPNotification) DecodeFromBytes(data []byte) error { return nil } -func (msg *BGPNotification) Serialize() ([]byte, error) { +func (msg *BGPNotification) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 2) buf[0] = msg.ErrorCode buf[1] = msg.ErrorSubcode @@ -7736,11 +8003,11 @@ func NewBGPNotificationMessage(errcode uint8, errsubcode uint8, data []byte) *BG type BGPKeepAlive struct { } -func (msg *BGPKeepAlive) DecodeFromBytes(data []byte) error { +func (msg *BGPKeepAlive) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { return nil } -func (msg *BGPKeepAlive) Serialize() ([]byte, error) { +func (msg *BGPKeepAlive) Serialize(options ...*MarshallingOption) ([]byte, error) { return nil, nil } @@ -7757,7 +8024,7 @@ type BGPRouteRefresh struct { SAFI uint8 } -func (msg *BGPRouteRefresh) DecodeFromBytes(data []byte) error { +func (msg *BGPRouteRefresh) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { if len(data) < 4 { return NewMessageError(BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR, BGP_ERROR_SUB_INVALID_MESSAGE_LENGTH, nil, "Not all RouteRefresh bytes available") } @@ -7767,7 +8034,7 @@ func (msg *BGPRouteRefresh) DecodeFromBytes(data []byte) error { return nil } -func (msg *BGPRouteRefresh) Serialize() ([]byte, error) { +func (msg *BGPRouteRefresh) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 4) binary.BigEndian.PutUint16(buf[0:2], msg.AFI) buf[2] = msg.Demarcation @@ -7783,8 +8050,8 @@ func NewBGPRouteRefreshMessage(afi uint16, demarcation uint8, safi uint8) *BGPMe } type BGPBody interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) + DecodeFromBytes([]byte, ...*MarshallingOption) error + Serialize(...*MarshallingOption) ([]byte, error) } const ( @@ -7798,7 +8065,7 @@ type BGPHeader struct { Type uint8 } -func (msg *BGPHeader) DecodeFromBytes(data []byte) error { +func (msg *BGPHeader) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { // minimum BGP message length if uint16(len(data)) < BGP_HEADER_LENGTH { return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "not all BGP message header") @@ -7811,7 +8078,7 @@ func (msg *BGPHeader) DecodeFromBytes(data []byte) error { return nil } -func (msg *BGPHeader) Serialize() ([]byte, error) { +func (msg *BGPHeader) Serialize(options ...*MarshallingOption) ([]byte, error) { buf := make([]byte, 19) for i := range buf[:16] { buf[i] = 0xff @@ -7826,7 +8093,7 @@ type BGPMessage struct { Body BGPBody } -func parseBody(h *BGPHeader, data []byte) (*BGPMessage, error) { +func parseBody(h *BGPHeader, data []byte, options ...*MarshallingOption) (*BGPMessage, error) { if len(data) < int(h.Len)-BGP_HEADER_LENGTH { return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP message bytes available") } @@ -7846,28 +8113,28 @@ func parseBody(h *BGPHeader, data []byte) (*BGPMessage, error) { default: return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE, nil, "unknown message type") } - err := msg.Body.DecodeFromBytes(data) + err := msg.Body.DecodeFromBytes(data, options...) if err != nil { return nil, err } return msg, nil } -func ParseBGPMessage(data []byte) (*BGPMessage, error) { +func ParseBGPMessage(data []byte, options ...*MarshallingOption) (*BGPMessage, error) { h := &BGPHeader{} - err := h.DecodeFromBytes(data) + err := h.DecodeFromBytes(data, options...) if err != nil { return nil, err } - return parseBody(h, data[19:h.Len]) + return parseBody(h, data[19:h.Len], options...) } -func ParseBGPBody(h *BGPHeader, data []byte) (*BGPMessage, error) { - return parseBody(h, data) +func ParseBGPBody(h *BGPHeader, data []byte, options ...*MarshallingOption) (*BGPMessage, error) { + return parseBody(h, data, options...) } -func (msg *BGPMessage) Serialize() ([]byte, error) { - b, err := msg.Body.Serialize() +func (msg *BGPMessage) Serialize(options ...*MarshallingOption) ([]byte, error) { + b, err := msg.Body.Serialize(options...) if err != nil { return nil, err } @@ -7877,7 +8144,7 @@ func (msg *BGPMessage) Serialize() ([]byte, error) { } msg.Header.Len = 19 + uint16(len(b)) } - h, err := msg.Header.Serialize() + h, err := msg.Header.Serialize(options...) if err != nil { return nil, err } diff --git a/vendor/github.com/osrg/gobgp/packet/bgp/bgp_test.go b/vendor/github.com/osrg/gobgp/packet/bgp/bgp_test.go index 8fedf5fe05..5731dd32ad 100644 --- a/vendor/github.com/osrg/gobgp/packet/bgp/bgp_test.go +++ b/vendor/github.com/osrg/gobgp/packet/bgp/bgp_test.go @@ -305,11 +305,14 @@ func Test_FlowSpecNlri(t *testing.T) { cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PKT_LEN, []*FlowSpecComponentItem{item2, item3, item4})) cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DSCP, []*FlowSpecComponentItem{item2, item3, item4})) isFlagment := 0x02 - item5 := NewFlowSpecComponentItem(isFlagment, 0) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5})) - item6 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK) - item7 := NewFlowSpecComponentItem(and|not, TCP_FLAG_URGENT) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item6, item7})) + lastFlagment := 0x08 + match := 0x1 + item5 := NewFlowSpecComponentItem(match, isFlagment) + item6 := NewFlowSpecComponentItem(and, lastFlagment) + cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5, item6})) + item7 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK) + item8 := NewFlowSpecComponentItem(and|not, TCP_FLAG_URGENT) + cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item7, item8})) n1 := NewFlowSpecIPv4Unicast(cmp) buf1, err := n1.Serialize() assert.Nil(err) @@ -553,6 +556,150 @@ func Test_CapExtendedNexthop(t *testing.T) { t.Error(len(buf2), n2, buf2) t.Log(bytes.Equal(buf1, buf2)) } +} + +func Test_AddPath(t *testing.T) { + assert := assert.New(t) + opt := &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}} + { + n1 := NewIPAddrPrefix(24, "10.10.10.0") + assert.Equal(n1.PathIdentifier(), uint32(0)) + n1.SetPathIdentifier(10) + assert.Equal(n1.PathIdentifier(), uint32(10)) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := &IPAddrPrefix{} + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(10)) + } + { + n1 := NewIPv6AddrPrefix(64, "2001::") + n1.SetPathIdentifier(10) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewIPv6AddrPrefix(0, "") + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(0)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH, RF_IPv6_UC: BGP_ADD_PATH_BOTH}} + { + n1 := NewIPv6AddrPrefix(64, "2001::") + n1.SetPathIdentifier(10) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewIPv6AddrPrefix(0, "") + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(10)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_VPN: BGP_ADD_PATH_BOTH, RF_IPv6_VPN: BGP_ADD_PATH_BOTH}} + { + rd, _ := ParseRouteDistinguisher("100:100") + labels := NewMPLSLabelStack(100, 200) + n1 := NewLabeledVPNIPAddrPrefix(24, "10.10.10.0", *labels, rd) + n1.SetPathIdentifier(20) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewLabeledVPNIPAddrPrefix(0, "", MPLSLabelStack{}, nil) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(20)) + } + { + rd, _ := ParseRouteDistinguisher("100:100") + labels := NewMPLSLabelStack(100, 200) + n1 := NewLabeledVPNIPv6AddrPrefix(64, "2001::", *labels, rd) + n1.SetPathIdentifier(20) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewLabeledVPNIPAddrPrefix(0, "", MPLSLabelStack{}, nil) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(20)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_MPLS: BGP_ADD_PATH_BOTH, RF_IPv6_MPLS: BGP_ADD_PATH_BOTH}} + { + labels := NewMPLSLabelStack(100, 200) + n1 := NewLabeledIPAddrPrefix(24, "10.10.10.0", *labels) + n1.SetPathIdentifier(20) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewLabeledIPAddrPrefix(0, "", MPLSLabelStack{}) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(20)) + } + { + labels := NewMPLSLabelStack(100, 200) + n1 := NewLabeledIPv6AddrPrefix(64, "2001::", *labels) + n1.SetPathIdentifier(20) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewLabeledIPAddrPrefix(0, "", MPLSLabelStack{}) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(20)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_RTC_UC: BGP_ADD_PATH_BOTH}} + { + rt, _ := ParseRouteTarget("100:100") + n1 := NewRouteTargetMembershipNLRI(65000, rt) + n1.SetPathIdentifier(30) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewRouteTargetMembershipNLRI(0, nil) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(30)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_EVPN: BGP_ADD_PATH_BOTH}} + { + n1 := NewEVPNNLRI(EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY, 0, + &EVPNEthernetAutoDiscoveryRoute{NewRouteDistinguisherFourOctetAS(5, 6), + EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2}) + n1.SetPathIdentifier(40) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewEVPNNLRI(0, 0, nil) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(40)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_ENCAP: BGP_ADD_PATH_BOTH}} + { + n1 := NewEncapNLRI("10.10.10.0") + n1.SetPathIdentifier(50) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewEncapNLRI("") + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(50)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_BOTH}} + { + n1 := NewFlowSpecIPv4Unicast([]FlowSpecComponentInterface{NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))}) + n1.SetPathIdentifier(60) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := NewFlowSpecIPv4Unicast(nil) + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(60)) + } + opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_OPAQUE: BGP_ADD_PATH_BOTH}} + { + n1 := NewOpaqueNLRI([]byte("key"), []byte("value")) + n1.SetPathIdentifier(70) + bits, err := n1.Serialize(opt) + assert.Nil(err) + n2 := &OpaqueNLRI{} + err = n2.DecodeFromBytes(bits, opt) + assert.Nil(err) + assert.Equal(n2.PathIdentifier(), uint32(70)) + } } diff --git a/vendor/github.com/osrg/gobgp/packet/bgp/constant.go b/vendor/github.com/osrg/gobgp/packet/bgp/constant.go index faa156e1c5..0741d8e88b 100644 --- a/vendor/github.com/osrg/gobgp/packet/bgp/constant.go +++ b/vendor/github.com/osrg/gobgp/packet/bgp/constant.go @@ -128,30 +128,56 @@ var TCPFlagValueMap = map[string]TCPFlag{ TCPFlagNameMap[TCP_FLAG_ECE]: TCP_FLAG_ECE, } -type TCPFlagOp int +type BitmaskFlagOp int const ( - TCP_FLAG_OP_OR = 0x00 - TCP_FLAG_OP_AND = 0x40 - TCP_FLAG_OP_END = 0x80 - TCP_FLAG_OP_NOT = 0x02 - TCP_FLAG_OP_MATCH = 0x01 + BITMASK_FLAG_OP_OR = 0x00 + BITMASK_FLAG_OP_AND = 0x40 + BITMASK_FLAG_OP_END = 0x80 + BITMASK_FLAG_OP_NOT = 0x02 + BITMASK_FLAG_OP_MATCH = 0x01 ) -var TCPFlagOpNameMap = map[TCPFlagOp]string{ - TCP_FLAG_OP_OR: " ", - TCP_FLAG_OP_AND: "&", - TCP_FLAG_OP_END: "E", - TCP_FLAG_OP_NOT: "!", - TCP_FLAG_OP_MATCH: "=", +var BitmaskFlagOpNameMap = map[BitmaskFlagOp]string{ + BITMASK_FLAG_OP_OR: " ", + BITMASK_FLAG_OP_AND: "&", + BITMASK_FLAG_OP_END: "E", + BITMASK_FLAG_OP_NOT: "!", + BITMASK_FLAG_OP_MATCH: "=", } -var TCPFlagOpValueMap = map[string]TCPFlagOp{ - TCPFlagOpNameMap[TCP_FLAG_OP_OR]: TCP_FLAG_OP_OR, - TCPFlagOpNameMap[TCP_FLAG_OP_AND]: TCP_FLAG_OP_AND, - TCPFlagOpNameMap[TCP_FLAG_OP_END]: TCP_FLAG_OP_END, - TCPFlagOpNameMap[TCP_FLAG_OP_NOT]: TCP_FLAG_OP_NOT, - TCPFlagOpNameMap[TCP_FLAG_OP_MATCH]: TCP_FLAG_OP_MATCH, +var BitmaskFlagOpValueMap = map[string]BitmaskFlagOp{ + BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR]: BITMASK_FLAG_OP_OR, + BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND]: BITMASK_FLAG_OP_AND, + BitmaskFlagOpNameMap[BITMASK_FLAG_OP_END]: BITMASK_FLAG_OP_END, + BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]: BITMASK_FLAG_OP_NOT, + BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]: BITMASK_FLAG_OP_MATCH, +} + +type FragmentFlag int + +const ( + FRAG_FLAG_NOT = 0x00 + FRAG_FLAG_DONT = 0x01 + FRAG_FLAG_IS = 0x02 + FRAG_FLAG_FIRST = 0x04 + FRAG_FLAG_LAST = 0x08 +) + +var FragmentFlagNameMap = map[FragmentFlag]string{ + FRAG_FLAG_NOT: "not-a-fragment", + FRAG_FLAG_DONT: "dont-fragment", + FRAG_FLAG_IS: "is-fragment", + FRAG_FLAG_FIRST: "first-fragment", + FRAG_FLAG_LAST: "last-fragment", +} + +var FragmentFlagValueMap = map[string]FragmentFlag{ + FragmentFlagNameMap[FRAG_FLAG_NOT]: FRAG_FLAG_NOT, + FragmentFlagNameMap[FRAG_FLAG_DONT]: FRAG_FLAG_DONT, + FragmentFlagNameMap[FRAG_FLAG_IS]: FRAG_FLAG_IS, + FragmentFlagNameMap[FRAG_FLAG_FIRST]: FRAG_FLAG_FIRST, + FragmentFlagNameMap[FRAG_FLAG_LAST]: FRAG_FLAG_LAST, } type DECNumOp int diff --git a/vendor/github.com/osrg/gobgp/packet/bgp/validate.go b/vendor/github.com/osrg/gobgp/packet/bgp/validate.go index 13c66a771c..77a125b951 100644 --- a/vendor/github.com/osrg/gobgp/packet/bgp/validate.go +++ b/vendor/github.com/osrg/gobgp/packet/bgp/validate.go @@ -8,7 +8,7 @@ import ( ) // Validator for BGPUpdate -func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]bool, doConfedCheck bool) (bool, error) { +func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, doConfedCheck bool) (bool, error) { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE) @@ -58,7 +58,7 @@ func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]bool, doConfedCheck boo return true, nil } -func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]bool, doConfedCheck bool) (bool, error) { +func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, doConfedCheck bool) (bool, error) { eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE) diff --git a/vendor/github.com/osrg/gobgp/packet/bgp/validate_test.go b/vendor/github.com/osrg/gobgp/packet/bgp/validate_test.go index 225f941d26..05b2fed7e7 100644 --- a/vendor/github.com/osrg/gobgp/packet/bgp/validate_test.go +++ b/vendor/github.com/osrg/gobgp/packet/bgp/validate_test.go @@ -41,29 +41,29 @@ func bgpupdateV6() *BGPMessage { func Test_Validate_CapV4(t *testing.T) { assert := assert.New(t) message := bgpupdate().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv6_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) } func Test_Validate_CapV6(t *testing.T) { assert := assert.New(t) message := bgpupdateV6().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv6_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) assert.NoError(err) - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) } func Test_Validate_OK(t *testing.T) { assert := assert.New(t) message := bgpupdate().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) assert.NoError(err) @@ -151,7 +151,7 @@ func Test_Validate_duplicate_attribute(t *testing.T) { origin.DecodeFromBytes(originBytes) message.PathAttributes = append(message.PathAttributes, origin) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -164,7 +164,7 @@ func Test_Validate_mandatory_missing(t *testing.T) { assert := assert.New(t) message := bgpupdate().Body.(*BGPUpdate) message.PathAttributes = message.PathAttributes[1:] - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -180,7 +180,7 @@ func Test_Validate_mandatory_missing_nocheck(t *testing.T) { message.PathAttributes = message.PathAttributes[1:] message.NLRI = nil - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(true, res) assert.NoError(err) } @@ -194,7 +194,7 @@ func Test_Validate_invalid_origin(t *testing.T) { origin.DecodeFromBytes(originBytes) message.PathAttributes[0] = origin - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -215,7 +215,7 @@ func Test_Validate_invalid_nexthop_zero(t *testing.T) { nexthop.DecodeFromBytes(nexthopBytes) message.PathAttributes[2] = nexthop - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -236,7 +236,7 @@ func Test_Validate_invalid_nexthop_lo(t *testing.T) { nexthop.DecodeFromBytes(nexthopBytes) message.PathAttributes[2] = nexthop - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -257,7 +257,7 @@ func Test_Validate_invalid_nexthop_de(t *testing.T) { nexthop.DecodeFromBytes(nexthopBytes) message.PathAttributes[2] = nexthop - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -277,7 +277,7 @@ func Test_Validate_unrecognized_well_known(t *testing.T) { unknown.DecodeFromBytes(unknownBytes) message.PathAttributes = append(message.PathAttributes, unknown) - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, false) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -292,7 +292,7 @@ func Test_Validate_aspath(t *testing.T) { message := bgpupdate().Body.(*BGPUpdate) // VALID AS_PATH - res, err := ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, true) + res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true) assert.Equal(true, res) // CONFED_SET @@ -310,7 +310,7 @@ func Test_Validate_aspath(t *testing.T) { } message.PathAttributes = newAttrs - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, true) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true) assert.Equal(false, res) assert.Error(err) e := err.(*MessageError) @@ -333,7 +333,7 @@ func Test_Validate_aspath(t *testing.T) { } message.PathAttributes = newAttrs - res, err = ValidateUpdateMsg(message, map[RouteFamily]bool{RF_IPv4_UC: true}, true) + res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true) assert.Equal(false, res) assert.Error(err) e = err.(*MessageError) @@ -372,7 +372,7 @@ func Test_Validate_flowspec(t *testing.T) { cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item7})) n1 := NewFlowSpecIPv4Unicast(cmp) a := NewPathAttributeMpReachNLRI("", []AddrPrefixInterface{n1}) - m := map[RouteFamily]bool{RF_FS_IPv4_UC: true} + m := map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_NONE} _, err := ValidateAttribute(a, m, false) assert.Nil(err) diff --git a/vendor/github.com/osrg/gobgp/server/fsm.go b/vendor/github.com/osrg/gobgp/server/fsm.go index afd04b3ebe..953e2f7da3 100644 --- a/vendor/github.com/osrg/gobgp/server/fsm.go +++ b/vendor/github.com/osrg/gobgp/server/fsm.go @@ -124,7 +124,7 @@ type FSM struct { adminStateCh chan AdminStateOperation getActiveCh chan struct{} h *FSMHandler - rfMap map[bgp.RouteFamily]bool + rfMap map[bgp.RouteFamily]bgp.BGPAddPathMode capMap map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface recvOpen *bgp.BGPMessage peerInfo *table.PeerInfo @@ -132,6 +132,7 @@ type FSM struct { gracefulRestartTimer *time.Timer twoByteAsTrans bool version uint + marshallingOptions *bgp.MarshallingOption } func (fsm *FSM) bgpMessageStateUpdate(MessageType uint8, isIn bool) { @@ -212,7 +213,7 @@ func NewFSM(gConf *config.Global, pConf *config.Neighbor, policy *table.RoutingP adminState: adminState, adminStateCh: make(chan AdminStateOperation, 1), getActiveCh: make(chan struct{}), - rfMap: make(map[bgp.RouteFamily]bool), + rfMap: make(map[bgp.RouteFamily]bgp.BGPAddPathMode), capMap: make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface), peerInfo: table.NewPeerInfo(gConf, pConf), policy: policy, @@ -614,6 +615,23 @@ func capabilitiesFromConfig(pConf *config.Neighbor) []bgp.ParameterCapabilityInt cap := bgp.NewCapExtendedNexthop(tuples) caps = append(caps, cap) } + + var mode bgp.BGPAddPathMode + if pConf.AddPaths.Config.Receive { + mode |= bgp.BGP_ADD_PATH_RECEIVE + } + if pConf.AddPaths.Config.SendMax > 0 { + mode |= bgp.BGP_ADD_PATH_SEND + } + if uint8(mode) > 0 { + items := make([]*bgp.CapAddPathTuple, 0, len(pConf.AfiSafis)) + for _, rf := range pConf.AfiSafis { + k, _ := bgp.GetRouteFamily(string(rf.Config.AfiSafiName)) + items = append(items, bgp.NewCapAddPathTuple(k, mode)) + } + caps = append(caps, bgp.NewCapAddPath(items)) + } + return caps } @@ -703,7 +721,7 @@ func (h *FSMHandler) recvMessageWithError() (*FsmMsg, error) { } now := time.Now() - m, err := bgp.ParseBGPBody(hd, bodyBuf) + m, err := bgp.ParseBGPBody(hd, bodyBuf, h.fsm.marshallingOptions) if err == nil { h.fsm.bgpMessageStateUpdate(m.Header.Type, true) err = bgp.ValidateBGPMessage(m) @@ -841,10 +859,8 @@ func (h *FSMHandler) recvMessage() error { return nil } -func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface, map[bgp.RouteFamily]bool) { +func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface, map[bgp.RouteFamily]bgp.BGPAddPathMode) { capMap := make(map[bgp.BGPCapabilityCode][]bgp.ParameterCapabilityInterface) - rfMap := config.CreateRfMap(n) - r := make(map[bgp.RouteFamily]bool) for _, p := range open.OptParams { if paramCap, y := p.(*bgp.OptionParameterCapability); y { for _, c := range paramCap.Capability { @@ -853,26 +869,53 @@ func open2Cap(open *bgp.BGPOpen, n *config.Neighbor) (map[bgp.BGPCapabilityCode] m = make([]bgp.ParameterCapabilityInterface, 0, 1) } capMap[c.Code()] = append(m, c) + } + } + } - if c.Code() == bgp.BGP_CAP_MULTIPROTOCOL { - m := c.(*bgp.CapMultiProtocol) - r[m.CapValue] = true - } + // squash add path cap + if caps, y := capMap[bgp.BGP_CAP_ADD_PATH]; y { + items := make([]*bgp.CapAddPathTuple, 0, len(caps)) + for _, c := range caps { + for _, i := range c.(*bgp.CapAddPath).Tuples { + items = append(items, i) } } + capMap[bgp.BGP_CAP_ADD_PATH] = []bgp.ParameterCapabilityInterface{bgp.NewCapAddPath(items)} } - if len(r) > 0 { - for rf, _ := range rfMap { - if _, y := r[rf]; !y { - delete(rfMap, rf) + // remote open message may not include multi-protocol capability + if _, y := capMap[bgp.BGP_CAP_MULTIPROTOCOL]; !y { + capMap[bgp.BGP_CAP_MULTIPROTOCOL] = []bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(bgp.RF_IPv4_UC)} + } + + local := config.CreateRfMap(n) + remote := make(map[bgp.RouteFamily]bgp.BGPAddPathMode) + for _, c := range capMap[bgp.BGP_CAP_MULTIPROTOCOL] { + family := c.(*bgp.CapMultiProtocol).CapValue + remote[family] = bgp.BGP_ADD_PATH_NONE + for _, a := range capMap[bgp.BGP_CAP_ADD_PATH] { + for _, i := range a.(*bgp.CapAddPath).Tuples { + if i.RouteFamily == family { + remote[family] = i.Mode + } } } - } else { - rfMap = make(map[bgp.RouteFamily]bool) - rfMap[bgp.RF_IPv4_UC] = true } - return capMap, rfMap + negotiated := make(map[bgp.RouteFamily]bgp.BGPAddPathMode) + for family, mode := range local { + if m, y := remote[family]; y { + n := bgp.BGP_ADD_PATH_NONE + if mode&bgp.BGP_ADD_PATH_SEND > 0 && m&bgp.BGP_ADD_PATH_RECEIVE > 0 { + n |= bgp.BGP_ADD_PATH_SEND + } + if mode&bgp.BGP_ADD_PATH_RECEIVE > 0 && m&bgp.BGP_ADD_PATH_SEND > 0 { + n |= bgp.BGP_ADD_PATH_RECEIVE + } + negotiated[family] = n + } + } + return capMap, negotiated } func (h *FSMHandler) opensent() (bgp.FSMState, FsmStateReason) { @@ -955,6 +998,12 @@ func (h *FSMHandler) opensent() (bgp.FSMState, FsmStateReason) { fsm.peerInfo.ID = body.ID fsm.capMap, fsm.rfMap = open2Cap(body, fsm.pConf) + if _, y := fsm.capMap[bgp.BGP_CAP_ADD_PATH]; y { + fsm.marshallingOptions = &bgp.MarshallingOption{ + AddPath: fsm.rfMap, + } + } + // calculate HoldTime // RFC 4271 P.13 // a BGP speaker MUST calculate the value of the Hold Timer @@ -1202,7 +1251,7 @@ func (h *FSMHandler) sendMessageloop() error { table.UpdatePathAttrs2ByteAs(m.Body.(*bgp.BGPUpdate)) table.UpdatePathAggregator2ByteAs(m.Body.(*bgp.BGPUpdate)) } - b, err := m.Serialize() + b, err := m.Serialize(h.fsm.marshallingOptions) if err != nil { log.WithFields(log.Fields{ "Topic": "Peer", diff --git a/vendor/github.com/osrg/gobgp/server/server.go b/vendor/github.com/osrg/gobgp/server/server.go index 1ecbedf010..bbbfb52478 100644 --- a/vendor/github.com/osrg/gobgp/server/server.go +++ b/vendor/github.com/osrg/gobgp/server/server.go @@ -98,6 +98,7 @@ type BgpServer struct { neighborMap map[string]*Peer peerGroupMap map[string]*PeerGroup globalRib *table.TableManager + rsRib *table.TableManager roaManager *roaManager shutdown bool watcherMap map[WatchEventType][]*Watcher @@ -345,7 +346,7 @@ func filterpath(peer *Peer, path, old *table.Path) *table.Path { if peer.isIBGPPeer() { ignore := false //RFC4684 Constrained Route Distribution - if peer.fsm.rfMap[bgp.RF_RTC_UC] && path.GetRouteFamily() != bgp.RF_RTC_UC { + if _, y := peer.fsm.rfMap[bgp.RF_RTC_UC]; y && path.GetRouteFamily() != bgp.RF_RTC_UC { ignore = true for _, ext := range path.GetExtCommunities() { for _, path := range peer.adjRibIn.PathList([]bgp.RouteFamily{bgp.RF_RTC_UC}, true) { @@ -466,12 +467,12 @@ func clonePathList(pathList []*table.Path) []*table.Path { return l } -func (server *BgpServer) notifyBestWatcher(best map[string][]*table.Path, multipath [][]*table.Path) { +func (server *BgpServer) notifyBestWatcher(best []*table.Path, multipath [][]*table.Path) { clonedM := make([][]*table.Path, len(multipath)) for i, pathList := range multipath { clonedM[i] = clonePathList(pathList) } - clonedB := clonePathList(best[table.GLOBAL_RIB_NAME]) + clonedB := clonePathList(best) for _, p := range clonedB { switch p.GetRouteFamily() { case bgp.RF_IPv4_VPN, bgp.RF_IPv6_VPN: @@ -509,32 +510,45 @@ func (server *BgpServer) notifyPostPolicyUpdateWatcher(peer *Peer, pathList []*t server.notifyWatcher(WATCH_EVENT_TYPE_POST_UPDATE, ev) } -func (server *BgpServer) dropPeerAllRoutes(peer *Peer, families []bgp.RouteFamily) { +func dstsToPaths(id string, dsts []*table.Destination) ([]*table.Path, []*table.Path, [][]*table.Path) { + bestList := make([]*table.Path, 0, len(dsts)) + oldList := make([]*table.Path, 0, len(dsts)) + mpathList := make([][]*table.Path, 0, len(dsts)) - families = peer.toGlobalFamilies(families) + for _, dst := range dsts { + best, old, mpath := dst.GetChanges(id, false) + bestList = append(bestList, best) + oldList = append(oldList, old) + if mpath != nil { + mpathList = append(mpathList, mpath) + } + } + return bestList, oldList, mpathList +} - ids := make([]string, 0, len(server.neighborMap)) +func (server *BgpServer) dropPeerAllRoutes(peer *Peer, families []bgp.RouteFamily) { + var bestList []*table.Path + var mpathList [][]*table.Path + families = peer.toGlobalFamilies(families) + rib := server.globalRib if peer.isRouteServerClient() { - for _, targetPeer := range server.neighborMap { - if !targetPeer.isRouteServerClient() || targetPeer == peer || targetPeer.fsm.state != bgp.BGP_FSM_ESTABLISHED { - continue - } - ids = append(ids, targetPeer.TableID()) - } - } else { - ids = append(ids, table.GLOBAL_RIB_NAME) + rib = server.rsRib } for _, rf := range families { - best, _, multipath := server.globalRib.DeletePathsByPeer(ids, peer.fsm.peerInfo, rf) + dsts := rib.DeletePathsByPeer(peer.fsm.peerInfo, rf) if !peer.isRouteServerClient() { - server.notifyBestWatcher(best, multipath) + bestList, _, mpathList = dstsToPaths(table.GLOBAL_RIB_NAME, dsts) + server.notifyBestWatcher(bestList, mpathList) } for _, targetPeer := range server.neighborMap { if peer.isRouteServerClient() != targetPeer.isRouteServerClient() || targetPeer == peer { continue } - if paths := targetPeer.processOutgoingPaths(best[targetPeer.TableID()], nil); len(paths) > 0 { + if targetPeer.isRouteServerClient() { + bestList, _, _ = dstsToPaths(targetPeer.TableID(), dsts) + } + if paths := targetPeer.processOutgoingPaths(bestList, nil); len(paths) > 0 { sendFsmOutgoingMsg(targetPeer, paths, nil, false) } } @@ -622,8 +636,12 @@ func (server *BgpServer) RSimportPaths(peer *Peer, pathList []*table.Path) []*ta } func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) { + var dsts []*table.Destination + + var bestList, oldList []*table.Path + var mpathList [][]*table.Path + rib := server.globalRib - var best, old map[string][]*table.Path if peer != nil && peer.fsm.pConf.Config.Vrf != "" { vrf := server.globalRib.Vrfs[peer.fsm.pConf.Config.Vrf] @@ -633,6 +651,7 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) { } if peer != nil && peer.isRouteServerClient() { + rib = server.rsRib for _, path := range pathList { path.Filter(peer.ID(), table.POLICY_DIRECTION_IMPORT) path.Filter(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT) @@ -644,17 +663,7 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) { } moded = append(moded, server.RSimportPaths(targetPeer, pathList)...) } - isTarget := func(p *Peer) bool { - return p.isRouteServerClient() && p.fsm.state == bgp.BGP_FSM_ESTABLISHED && !p.fsm.pConf.GracefulRestart.State.LocalRestarting - } - - ids := make([]string, 0, len(server.neighborMap)) - for _, targetPeer := range server.neighborMap { - if isTarget(targetPeer) { - ids = append(ids, targetPeer.TableID()) - } - } - best, old, _ = rib.ProcessPaths(ids, append(pathList, moded...)) + dsts = rib.ProcessPaths(append(pathList, moded...)) } else { for idx, path := range pathList { if p := server.policy.ApplyPolicy(table.GLOBAL_RIB_NAME, table.POLICY_DIRECTION_IMPORT, path, nil); p != nil { @@ -709,20 +718,23 @@ func (server *BgpServer) propagateUpdate(peer *Peer, pathList []*table.Path) { } } server.notifyPostPolicyUpdateWatcher(peer, pathList) - var multipath [][]*table.Path - best, old, multipath = rib.ProcessPaths([]string{table.GLOBAL_RIB_NAME}, pathList) + dsts = rib.ProcessPaths(pathList) - if len(best[table.GLOBAL_RIB_NAME]) == 0 { + bestList, oldList, mpathList = dstsToPaths(table.GLOBAL_RIB_NAME, dsts) + if len(bestList) == 0 { return } - server.notifyBestWatcher(best, multipath) + server.notifyBestWatcher(bestList, mpathList) } for _, targetPeer := range server.neighborMap { if (peer == nil && targetPeer.isRouteServerClient()) || (peer != nil && peer.isRouteServerClient() != targetPeer.isRouteServerClient()) { continue } - if paths := targetPeer.processOutgoingPaths(best[targetPeer.TableID()], old[targetPeer.TableID()]); len(paths) > 0 { + if targetPeer.isRouteServerClient() { + bestList, oldList, _ = dstsToPaths(targetPeer.TableID(), dsts) + } + if paths := targetPeer.processOutgoingPaths(bestList, oldList); len(paths) > 0 { sendFsmOutgoingMsg(targetPeer, paths, nil, false) } } @@ -858,7 +870,8 @@ func (server *BgpServer) handleFSMMessage(peer *Peer, e *FsmMsg) { // waiting sending non-route-target NLRIs since the peer won't send // any routes (and EORs) before we send ours (or deferral-timer expires). var pathList []*table.Path - if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); !peer.fsm.pConf.GracefulRestart.State.PeerRestarting && peer.fsm.rfMap[bgp.RF_RTC_UC] && c.RouteTargetMembership.Config.DeferralTime > 0 { + _, y := peer.fsm.rfMap[bgp.RF_RTC_UC] + if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); y && !peer.fsm.pConf.GracefulRestart.State.PeerRestarting && c.RouteTargetMembership.Config.DeferralTime > 0 { pathList, _ = peer.getBestFromLocal([]bgp.RouteFamily{bgp.RF_RTC_UC}) t := c.RouteTargetMembership.Config.DeferralTime for _, f := range peer.configuredRFlist() { @@ -1304,6 +1317,7 @@ func (s *BgpServer) Start(c *config.Global) error { rfs, _ := config.AfiSafis(c.AfiSafis).ToRfList() s.globalRib = table.NewTableManager(rfs) + s.rsRib = table.NewTableManager(rfs) if err := s.policy.Reset(&config.RoutingPolicy{}, map[string]config.ApplyPolicy{}); err != nil { return err @@ -1443,6 +1457,7 @@ func (s *BgpServer) softResetOut(addr string, family bgp.RouteFamily, deferral b } if deferral { + _, y := peer.fsm.rfMap[bgp.RF_RTC_UC] if peer.fsm.pConf.GracefulRestart.State.LocalRestarting { peer.fsm.pConf.GracefulRestart.State.LocalRestarting = false log.WithFields(log.Fields{ @@ -1450,7 +1465,7 @@ func (s *BgpServer) softResetOut(addr string, family bgp.RouteFamily, deferral b "Key": peer.ID(), "Families": families, }).Debug("deferral timer expired") - } else if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); peer.fsm.rfMap[bgp.RF_RTC_UC] && !c.MpGracefulRestart.State.EndOfRibReceived { + } else if c := config.GetAfiSafi(peer.fsm.pConf, bgp.RF_RTC_UC); y && !c.MpGracefulRestart.State.EndOfRibReceived { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.ID(), @@ -1523,6 +1538,7 @@ func (s *BgpServer) GetRib(addr string, family bgp.RouteFamily, prefixes []*tabl return fmt.Errorf("Neighbor %v doesn't have local rib", addr) } id = peer.ID() + m = s.rsRib } af := bgp.RouteFamily(family) tbl, ok := m.Tables[af] @@ -1596,6 +1612,7 @@ func (s *BgpServer) GetRibInfo(addr string, family bgp.RouteFamily) (info *table return fmt.Errorf("Neighbor %v doesn't have local rib", addr) } id = peer.ID() + m = s.rsRib } info, err = m.TableInfo(id, family) return err @@ -1720,7 +1737,11 @@ func (server *BgpServer) addNeighbor(c *config.Neighbor) error { "Topic": "Peer", }).Infof("Add a peer configuration for:%s", addr) - peer := NewPeer(&server.bgpConfig.Global, c, server.globalRib, server.policy) + rib := server.globalRib + if c.RouteServer.Config.RouteServerClient { + rib = server.rsRib + } + peer := NewPeer(&server.bgpConfig.Global, c, rib, server.policy) server.policy.Reset(nil, map[string]config.ApplyPolicy{peer.ID(): c.ApplyPolicy}) if peer.isRouteServerClient() { pathList := make([]*table.Path, 0) @@ -1733,7 +1754,7 @@ func (server *BgpServer) addNeighbor(c *config.Neighbor) error { } moded := server.RSimportPaths(peer, pathList) if len(moded) > 0 { - server.globalRib.ProcessPaths(nil, moded) + server.rsRib.ProcessPaths(moded) } } server.neighborMap[addr] = peer @@ -2446,6 +2467,7 @@ func (w *Watcher) Generate(t WatchEventType) error { } w.notify(&WatchEventAdjIn{PathList: clonePathList(pathList)}) case WATCH_EVENT_TYPE_TABLE: + rib := w.s.globalRib id := table.GLOBAL_RIB_NAME if len(w.opts.tableName) > 0 { peer, ok := w.s.neighborMap[w.opts.tableName] @@ -2456,11 +2478,12 @@ func (w *Watcher) Generate(t WatchEventType) error { return fmt.Errorf("Neighbor %v doesn't have local rib", w.opts.tableName) } id = peer.ID() + rib = w.s.rsRib } pathList := func() map[string][]*table.Path { pathList := make(map[string][]*table.Path) - for _, t := range w.s.globalRib.Tables { + for _, t := range rib.Tables { for _, dst := range t.GetSortedDestinations() { if paths := dst.GetKnownPathList(id); len(paths) > 0 { pathList[dst.GetNlri().String()] = clonePathList(paths) diff --git a/vendor/github.com/osrg/gobgp/server/server_test.go b/vendor/github.com/osrg/gobgp/server/server_test.go index e5deb975cc..b8dc58f554 100644 --- a/vendor/github.com/osrg/gobgp/server/server_test.go +++ b/vendor/github.com/osrg/gobgp/server/server_test.go @@ -16,15 +16,16 @@ package server import ( + "net" + "runtime" + "testing" + "time" + "github.com/osrg/gobgp/config" "github.com/osrg/gobgp/packet/bgp" "github.com/osrg/gobgp/table" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" - "net" - "runtime" - "testing" - "time" ) func TestModPolicyAssign(t *testing.T) { @@ -208,20 +209,20 @@ func newPeerandInfo(myAs, as uint32, address string, rib *table.TableManager) (* rib, policy) for _, f := range rib.GetRFlist() { - p.fsm.rfMap[f] = true + p.fsm.rfMap[f] = bgp.BGP_ADD_PATH_NONE } return p, &table.PeerInfo{AS: as, Address: net.ParseIP(address)} } func process(rib *table.TableManager, l []*table.Path) (*table.Path, *table.Path) { - news, olds, _ := rib.ProcessPaths([]string{table.GLOBAL_RIB_NAME}, l) + news, olds, _ := dstsToPaths(table.GLOBAL_RIB_NAME, rib.ProcessPaths(l)) if len(news) != 1 { panic("can't handle multiple paths") } - for idx, path := range news[table.GLOBAL_RIB_NAME] { + for idx, path := range news { var old *table.Path if olds != nil { - old = olds[table.GLOBAL_RIB_NAME][idx] + old = olds[idx] } return path, old } diff --git a/vendor/github.com/osrg/gobgp/table/adj.go b/vendor/github.com/osrg/gobgp/table/adj.go index 5ef540f6b2..05a795be40 100644 --- a/vendor/github.com/osrg/gobgp/table/adj.go +++ b/vendor/github.com/osrg/gobgp/table/adj.go @@ -17,6 +17,7 @@ package table import ( "fmt" + "github.com/osrg/gobgp/packet/bgp" ) @@ -44,7 +45,7 @@ func (adj *AdjRib) Update(pathList []*Path) { continue } rf := path.GetRouteFamily() - key := path.getPrefix() + key := fmt.Sprintf("%d:%s", path.GetNlri().PathIdentifier(), path.getPrefix()) old, found := adj.table[rf][key] if path.IsWithdraw { diff --git a/vendor/github.com/osrg/gobgp/table/destination.go b/vendor/github.com/osrg/gobgp/table/destination.go index af74f8fd96..cef2086f64 100644 --- a/vendor/github.com/osrg/gobgp/table/destination.go +++ b/vendor/github.com/osrg/gobgp/table/destination.go @@ -140,12 +140,13 @@ func NewPeerInfo(g *config.Global, p *config.Neighbor) *PeerInfo { } type Destination struct { - routeFamily bgp.RouteFamily - nlri bgp.AddrPrefixInterface - knownPathList paths - withdrawList paths - newPathList paths - RadixKey string + routeFamily bgp.RouteFamily + nlri bgp.AddrPrefixInterface + knownPathList paths + withdrawList paths + newPathList paths + oldKnownPathList paths + RadixKey string } func NewDestination(nlri bgp.AddrPrefixInterface, known ...*Path) *Destination { @@ -226,50 +227,10 @@ func (dd *Destination) GetMultiBestPath(id string) []*Path { return getMultiBestPath(id, &dd.knownPathList) } -func (dd *Destination) AddWithdraw(withdraw *Path) { - dd.validatePath(withdraw) - dd.withdrawList = append(dd.withdrawList, withdraw) -} - -func (dd *Destination) AddNewPath(newPath *Path) { - dd.validatePath(newPath) - dd.newPathList = append(dd.newPathList, newPath) -} - -func (dd *Destination) validatePath(path *Path) { - if path == nil || path.GetRouteFamily() != dd.routeFamily { - - log.WithFields(log.Fields{ - "Topic": "Table", - "Key": dd.GetNlri().String(), - "Path": path, - "ExpectedRF": dd.routeFamily, - }).Error("path is nil or invalid route family") - } -} - -// Calculates best-path among known paths for this destination. -// -// Modifies destination's state related to stored paths. Removes withdrawn -// paths from known paths. Also, adds new paths to known paths. -func (dest *Destination) Calculate(ids []string, peerDown bool) (map[string]*Path, map[string]*Path, []*Path) { - bestList := make(map[string]*Path, len(ids)) - oldList := make(map[string]*Path, len(ids)) - oldKnownPathList := dest.knownPathList - // First remove the withdrawn paths. - dest.explicitWithdraw() - // Do implicit withdrawal - dest.implicitWithdraw() - // Collect all new paths into known paths. - dest.knownPathList = append(dest.knownPathList, dest.newPathList...) - // Clear new paths as we copied them. - dest.newPathList = make([]*Path, 0) - // Compute new best path - dest.computeKnownBestPath() - - f := func(id string) (*Path, *Path) { - old := getBestPath(id, &oldKnownPathList) - best := dest.GetBestPath(id) +func (dd *Destination) GetChanges(id string, peerDown bool) (*Path, *Path, []*Path) { + best, old := func(id string) (*Path, *Path) { + old := getBestPath(id, &dd.oldKnownPathList) + best := dd.GetBestPath(id) if best != nil && best.Equal(old) { // RFC4684 3.2. Intra-AS VPN Route Distribution // When processing RT membership NLRIs received from internal iBGP @@ -300,35 +261,79 @@ func (dest *Destination) Calculate(ids []string, peerDown bool) (map[string]*Pat return old.Clone(true), old } return best, old - } + }(id) var multi []*Path - for _, id := range ids { - bestList[id], oldList[id] = f(id) - if id == GLOBAL_RIB_NAME && UseMultiplePaths.Enabled { - diff := func(lhs, rhs []*Path) bool { - if len(lhs) != len(rhs) { + + if id == GLOBAL_RIB_NAME && UseMultiplePaths.Enabled { + diff := func(lhs, rhs []*Path) bool { + if len(lhs) != len(rhs) { + return true + } + for idx, l := range lhs { + if !l.Equal(rhs[idx]) { return true } - for idx, l := range lhs { - if !l.Equal(rhs[idx]) { - return true - } - } - return false } - oldM := getMultiBestPath(id, &oldKnownPathList) - newM := dest.GetMultiBestPath(id) - if diff(oldM, newM) { - multi = newM - if len(newM) == 0 { - multi = []*Path{bestList[id]} - } + return false + } + oldM := getMultiBestPath(id, &dd.oldKnownPathList) + newM := dd.GetMultiBestPath(id) + if diff(oldM, newM) { + multi = newM + if len(newM) == 0 { + multi = []*Path{best} } } } + return best, old, multi +} + +func (dd *Destination) AddWithdraw(withdraw *Path) { + dd.validatePath(withdraw) + dd.withdrawList = append(dd.withdrawList, withdraw) +} + +func (dd *Destination) AddNewPath(newPath *Path) { + dd.validatePath(newPath) + dd.newPathList = append(dd.newPathList, newPath) +} + +func (dd *Destination) validatePath(path *Path) { + if path == nil || path.GetRouteFamily() != dd.routeFamily { - return bestList, oldList, multi + log.WithFields(log.Fields{ + "Topic": "Table", + "Key": dd.GetNlri().String(), + "Path": path, + "ExpectedRF": dd.routeFamily, + }).Error("path is nil or invalid route family") + } +} + +// Calculates best-path among known paths for this destination. +// +// Modifies destination's state related to stored paths. Removes withdrawn +// paths from known paths. Also, adds new paths to known paths. +func (dest *Destination) Calculate() *Destination { + oldKnownPathList := dest.knownPathList + // First remove the withdrawn paths. + dest.explicitWithdraw() + // Do implicit withdrawal + dest.implicitWithdraw() + // Collect all new paths into known paths. + dest.knownPathList = append(dest.knownPathList, dest.newPathList...) + // Clear new paths as we copied them. + dest.newPathList = make([]*Path, 0) + // Compute new best path + dest.computeKnownBestPath() + + return &Destination{ + routeFamily: dest.routeFamily, + nlri: dest.nlri, + knownPathList: dest.knownPathList, + oldKnownPathList: oldKnownPathList, + } } // Removes withdrawn paths. @@ -373,8 +378,8 @@ func (dest *Destination) explicitWithdraw() paths { for _, withdraw := range dest.withdrawList { isFound := false for _, path := range dest.knownPathList { - // We have a match if the source are same. - if path.GetSource().Equal(withdraw.GetSource()) { + // We have a match if the source and path-id are same. + if path.GetSource().Equal(withdraw.GetSource()) && path.GetNlri().PathIdentifier() == withdraw.GetNlri().PathIdentifier() { isFound = true // this path is referenced in peer's adj-rib-in // when there was no policy modification applied. @@ -425,7 +430,7 @@ func (dest *Destination) implicitWithdraw() paths { // version num. as newPaths are implicit withdrawal of old // paths and when doing RouteRefresh (not EnhancedRouteRefresh) // we get same paths again. - if newPath.GetSource().Equal(path.GetSource()) { + if newPath.GetSource().Equal(path.GetSource()) && newPath.GetNlri().PathIdentifier() == path.GetNlri().PathIdentifier() { log.WithFields(log.Fields{ "Topic": "Table", "Key": dest.GetNlri().String(), diff --git a/vendor/github.com/osrg/gobgp/table/destination_test.go b/vendor/github.com/osrg/gobgp/table/destination_test.go index e1f1341057..d1124b4bc5 100644 --- a/vendor/github.com/osrg/gobgp/table/destination_test.go +++ b/vendor/github.com/osrg/gobgp/table/destination_test.go @@ -92,7 +92,7 @@ func TestCalculate(t *testing.T) { d.AddNewPath(path1) d.AddNewPath(path2) - d.Calculate([]string{"1", "2"}, false) + d.Calculate() assert.Equal(t, len(d.GetKnownPathList("1")), 0) assert.Equal(t, len(d.GetKnownPathList("2")), 1) @@ -100,7 +100,7 @@ func TestCalculate(t *testing.T) { d.AddWithdraw(path1.Clone(true)) - d.Calculate([]string{"1", "2"}, false) + d.Calculate() assert.Equal(t, len(d.GetKnownPathList("1")), 0) assert.Equal(t, len(d.GetKnownPathList("2")), 0) @@ -124,7 +124,7 @@ func TestCalculate2(t *testing.T) { d := NewDestination(nlri) d.AddNewPath(path1) - d.Calculate(nil, false) + d.Calculate() // suppose peer2 sends grammaatically correct but semantically flawed update message // which has a withdrawal nlri not advertised before @@ -134,7 +134,7 @@ func TestCalculate2(t *testing.T) { assert.Equal(t, path2.IsWithdraw, true) d.AddWithdraw(path2) - d.Calculate(nil, false) + d.Calculate() // we have a path from peer1 here assert.Equal(t, len(d.knownPathList), 1) @@ -145,7 +145,7 @@ func TestCalculate2(t *testing.T) { assert.Equal(t, path3.IsWithdraw, false) d.AddNewPath(path3) - d.Calculate(nil, false) + d.Calculate() // this time, we have paths from peer1 and peer2 assert.Equal(t, len(d.knownPathList), 2) @@ -156,7 +156,7 @@ func TestCalculate2(t *testing.T) { path4 := ProcessMessage(update4, peer3, time.Now())[0] d.AddNewPath(path4) - d.Calculate(nil, false) + d.Calculate() // we must have paths from peer1, peer2 and peer3 assert.Equal(t, len(d.knownPathList), 3) @@ -190,7 +190,7 @@ func TestImplicitWithdrawCalculate(t *testing.T) { d.AddNewPath(path1) d.AddNewPath(path2) - d.Calculate(nil, false) + d.Calculate() assert.Equal(t, len(d.GetKnownPathList("1")), 0) // peer "1" is the originator assert.Equal(t, len(d.GetKnownPathList("2")), 1) @@ -209,7 +209,7 @@ func TestImplicitWithdrawCalculate(t *testing.T) { path3.Filter("1", POLICY_DIRECTION_IMPORT) d.AddNewPath(path3) - d.Calculate(nil, false) + d.Calculate() assert.Equal(t, len(d.GetKnownPathList("1")), 0) // peer "1" is the originator assert.Equal(t, len(d.GetKnownPathList("2")), 1) @@ -294,7 +294,7 @@ func TestTimeTieBreaker(t *testing.T) { d.AddNewPath(path1) d.AddNewPath(path2) - d.Calculate(nil, false) + d.Calculate() assert.Equal(t, len(d.knownPathList), 2) assert.Equal(t, true, d.GetBestPath("").GetSource().ID.Equal(net.IP{2, 2, 2, 2})) // path from peer2 win @@ -305,7 +305,7 @@ func TestTimeTieBreaker(t *testing.T) { d.AddNewPath(path1) d.AddNewPath(path2) - d.Calculate(nil, false) + d.Calculate() assert.Equal(t, len(d.knownPathList), 2) assert.Equal(t, true, d.GetBestPath("").GetSource().ID.Equal(net.IP{1, 1, 1, 1})) // path from peer1 win @@ -462,17 +462,18 @@ func TestMultipath(t *testing.T) { d.AddNewPath(path1) d.AddNewPath(path2) - best, old, multi := d.Calculate([]string{GLOBAL_RIB_NAME}, false) - assert.Equal(t, len(best), 1) - assert.Equal(t, old[GLOBAL_RIB_NAME], (*Path)(nil)) + best, old, multi := d.Calculate().GetChanges(GLOBAL_RIB_NAME, false) + assert.NotNil(t, best) + assert.Equal(t, old, (*Path)(nil)) assert.Equal(t, len(multi), 2) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 2) path3 := path2.Clone(true) d.AddWithdraw(path3) - best, old, multi = d.Calculate([]string{GLOBAL_RIB_NAME}, false) - assert.Equal(t, len(best), 1) - assert.Equal(t, old[GLOBAL_RIB_NAME], path1) + dd := d.Calculate() + best, old, multi = dd.GetChanges(GLOBAL_RIB_NAME, false) + assert.Nil(t, best) + assert.Equal(t, old, path1) assert.Equal(t, len(multi), 1) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 1) @@ -489,8 +490,8 @@ func TestMultipath(t *testing.T) { path4 := ProcessMessage(updateMsg, peer3, time.Now())[0] d.AddNewPath(path4) - best, _, multi = d.Calculate([]string{GLOBAL_RIB_NAME}, false) - assert.Equal(t, len(best), 1) + best, _, multi = d.Calculate().GetChanges(GLOBAL_RIB_NAME, false) + assert.NotNil(t, best) assert.Equal(t, len(multi), 1) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 2) @@ -505,8 +506,8 @@ func TestMultipath(t *testing.T) { path5 := ProcessMessage(updateMsg, peer2, time.Now())[0] d.AddNewPath(path5) - best, _, multi = d.Calculate([]string{GLOBAL_RIB_NAME}, false) - assert.Equal(t, len(best), 1) + best, _, multi = d.Calculate().GetChanges(GLOBAL_RIB_NAME, false) + assert.NotNil(t, best) assert.Equal(t, len(multi), 2) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 3) diff --git a/vendor/github.com/osrg/gobgp/table/path.go b/vendor/github.com/osrg/gobgp/table/path.go index b97ca40c0a..0ff1afce0e 100644 --- a/vendor/github.com/osrg/gobgp/table/path.go +++ b/vendor/github.com/osrg/gobgp/table/path.go @@ -971,6 +971,7 @@ func (path *Path) MarshalJSON() ([]byte, error) { Stale bool `json:"stale,omitempty"` Filtered bool `json:"filtered,omitempty"` UUID string `json:"uuid,omitempty"` + ID uint32 `json:"id,omitempty"` }{ Nlri: path.GetNlri(), PathAttrs: path.GetPathAttrs(), @@ -982,6 +983,7 @@ func (path *Path) MarshalJSON() ([]byte, error) { Stale: path.IsStale(), Filtered: path.Filtered("") > POLICY_DIRECTION_NONE, UUID: path.UUID().String(), + ID: path.GetNlri().PathIdentifier(), }) } diff --git a/vendor/github.com/osrg/gobgp/table/table_manager.go b/vendor/github.com/osrg/gobgp/table/table_manager.go index e41c279888..023672fc3e 100644 --- a/vendor/github.com/osrg/gobgp/table/table_manager.go +++ b/vendor/github.com/osrg/gobgp/table/table_manager.go @@ -18,10 +18,11 @@ package table import ( "bytes" "fmt" - "github.com/osrg/gobgp/packet/bgp" - log "github.com/sirupsen/logrus" "net" "time" + + "github.com/osrg/gobgp/packet/bgp" + log "github.com/sirupsen/logrus" ) const ( @@ -185,29 +186,17 @@ func (manager *TableManager) DeleteVrf(name string) ([]*Path, error) { return msgs, nil } -func (manager *TableManager) calculate(ids []string, destinations []*Destination, peerDown bool) (map[string][]*Path, map[string][]*Path, [][]*Path) { - best := make(map[string][]*Path, len(ids)) - old := make(map[string][]*Path, len(ids)) +func (manager *TableManager) calculate(dsts []*Destination) []*Destination { + emptyDsts := make([]*Destination, 0, len(dsts)) + clonedDsts := make([]*Destination, 0, len(dsts)) - emptyDsts := make([]*Destination, 0, len(destinations)) - var multi [][]*Path - if UseMultiplePaths.Enabled && len(ids) == 1 && ids[0] == GLOBAL_RIB_NAME { - multi = make([][]*Path, 0, len(destinations)) - } - - for _, dst := range destinations { + for _, dst := range dsts { log.WithFields(log.Fields{ "Topic": "table", "Key": dst.GetNlri().String(), }).Debug("Processing destination") - paths, olds, m := dst.Calculate(ids, peerDown) - for id, path := range paths { - best[id] = append(best[id], path) - old[id] = append(old[id], olds[id]) - } - if m != nil { - multi = append(multi, m) - } + + clonedDsts = append(clonedDsts, dst.Calculate()) if len(dst.knownPathList) == 0 { emptyDsts = append(emptyDsts, dst) @@ -218,18 +207,18 @@ func (manager *TableManager) calculate(ids []string, destinations []*Destination t := manager.Tables[dst.Family()] t.deleteDest(dst) } - return best, old, multi + return clonedDsts } -func (manager *TableManager) DeletePathsByPeer(ids []string, info *PeerInfo, rf bgp.RouteFamily) (map[string][]*Path, map[string][]*Path, [][]*Path) { +func (manager *TableManager) DeletePathsByPeer(info *PeerInfo, rf bgp.RouteFamily) []*Destination { if t, ok := manager.Tables[rf]; ok { dsts := t.DeleteDestByPeer(info) - return manager.calculate(ids, dsts, true) + return manager.calculate(dsts) } - return nil, nil, nil + return nil } -func (manager *TableManager) ProcessPaths(ids []string, pathList []*Path) (map[string][]*Path, map[string][]*Path, [][]*Path) { +func (manager *TableManager) ProcessPaths(pathList []*Path) []*Destination { m := make(map[string]bool, len(pathList)) dsts := make([]*Destination, 0, len(pathList)) for _, path := range pathList { @@ -255,7 +244,7 @@ func (manager *TableManager) ProcessPaths(ids []string, pathList []*Path) (map[s } } } - return manager.calculate(ids, dsts, false) + return manager.calculate(dsts) } // EVPN MAC MOBILITY HANDLING diff --git a/vendor/github.com/osrg/gobgp/table/table_manager_test.go b/vendor/github.com/osrg/gobgp/table/table_manager_test.go index 2a8ed2f6c0..ec979bf6f9 100644 --- a/vendor/github.com/osrg/gobgp/table/table_manager_test.go +++ b/vendor/github.com/osrg/gobgp/table/table_manager_test.go @@ -29,15 +29,12 @@ import ( // process BGPUpdate message // this function processes only BGPUpdate func (manager *TableManager) ProcessUpdate(fromPeer *PeerInfo, message *bgp.BGPMessage) ([]*Path, error) { - paths := ProcessMessage(message, fromPeer, time.Now()) - best, _, _ := manager.ProcessPaths([]string{GLOBAL_RIB_NAME}, paths) - paths2 := make([]*Path, 0, len(paths)) - for _, p := range best[GLOBAL_RIB_NAME] { - if p != nil { - paths2 = append(paths2, p) - } + pathList := make([]*Path, 0) + for _, d := range manager.ProcessPaths(ProcessMessage(message, fromPeer, time.Now())) { + b, _, _ := d.GetChanges(GLOBAL_RIB_NAME, false) + pathList = append(pathList, b) } - return paths2, nil + return pathList, nil } func getLogger(lv log.Level) *log.Logger { diff --git a/vendor/github.com/osrg/gobgp/test/lib/base.py b/vendor/github.com/osrg/gobgp/test/lib/base.py index 0421e9d7f8..6306ccf657 100644 --- a/vendor/github.com/osrg/gobgp/test/lib/base.py +++ b/vendor/github.com/osrg/gobgp/test/lib/base.py @@ -311,7 +311,7 @@ def add_peer(self, peer, passwd=None, vpn=False, is_rs_client=False, flowspec=False, bridge='', reload_config=True, as2=False, graceful_restart=None, local_as=None, prefix_limit=None, v6=False, llgr=None, vrf='', interface='', allow_as_in=0, - remove_private_as=None, replace_peer_as=False): + remove_private_as=None, replace_peer_as=False, addpath=False): neigh_addr = '' local_addr = '' it = itertools.product(self.ip_addrs, peer.ip_addrs) @@ -355,7 +355,8 @@ def add_peer(self, peer, passwd=None, vpn=False, is_rs_client=False, 'vrf': vrf, 'allow_as_in': allow_as_in, 'remove_private_as': remove_private_as, - 'replace_peer_as': replace_peer_as} + 'replace_peer_as': replace_peer_as, + 'addpath': addpath} if self.is_running and reload_config: self.create_config() self.reload_config() @@ -378,8 +379,10 @@ def log(self): def add_route(self, route, rf='ipv4', attribute=None, aspath=None, community=None, med=None, extendedcommunity=None, nexthop=None, matchs=None, thens=None, - local_pref=None, reload_config=True): - self.routes[route] = {'prefix': route, + local_pref=None, identifier=None, reload_config=True): + if route not in self.routes: + self.routes[route] = [] + self.routes[route].append({'prefix': route, 'rf': rf, 'attr': attribute, 'next-hop': nexthop, @@ -388,8 +391,9 @@ def add_route(self, route, rf='ipv4', attribute=None, aspath=None, 'med': med, 'local-pref': local_pref, 'extended-community': extendedcommunity, + 'identifier': identifier, 'matchs': matchs, - 'thens': thens} + 'thens': thens}) if self.is_running and reload_config: self.create_config() self.reload_config() diff --git a/vendor/github.com/osrg/gobgp/test/lib/exabgp.py b/vendor/github.com/osrg/gobgp/test/lib/exabgp.py index dbf8f023d7..efc39ac1f9 100644 --- a/vendor/github.com/osrg/gobgp/test/lib/exabgp.py +++ b/vendor/github.com/osrg/gobgp/test/lib/exabgp.py @@ -19,6 +19,7 @@ from fabric import colors from fabric.api import local +from itertools import chain from lib.base import ( BGPContainer, @@ -92,7 +93,10 @@ def create_config(self): if info['passive']: cmd << ' passive;' - routes = [r for r in self.routes.values() if r['rf'] == 'ipv4' or r['rf'] == 'ipv6'] + if info['addpath']: + cmd << ' add-path send/receive;' + + routes = [r for r in chain.from_iterable(self.routes.itervalues()) if r['rf'] == 'ipv4' or r['rf'] == 'ipv6'] if len(routes) > 0: cmd << ' static {' @@ -114,11 +118,13 @@ def create_config(self): r << 'extended-community [{0}]'.format(route['extended-community']) if route['attr']: r << 'attribute [ {0} ]'.format(route['attr']) + if route['identifier']: + r << 'path-information {0}'.format(route['identifier']) cmd << '{0};'.format(str(r)) cmd << ' }' - routes = [r for r in self.routes.itervalues() if 'flowspec' in r['rf']] + routes = [r for r in chain.from_iterable(self.routes.itervalues()) if 'flowspec' in r['rf']] if len(routes) > 0: cmd << ' flow {' for route in routes: diff --git a/vendor/github.com/osrg/gobgp/test/lib/gobgp.py b/vendor/github.com/osrg/gobgp/test/lib/gobgp.py index 26847c77ad..a54428e33a 100644 --- a/vendor/github.com/osrg/gobgp/test/lib/gobgp.py +++ b/vendor/github.com/osrg/gobgp/test/lib/gobgp.py @@ -398,6 +398,11 @@ def _create_config_bgp(self): n['route-reflector'] = {'config': {'route-reflector-client': True, 'route-reflector-cluster-id': cluster_id}} + if info['addpath']: + n['add-paths'] = {'config' : {'receive': True, + 'send-max': 16}} + + if len(info.get('default-policy', [])) + len(info.get('policies', [])) > 0: n['apply-policy'] = {'config': {}} @@ -495,7 +500,7 @@ def reload_config(self): for d in daemon: cmd = '/usr/bin/pkill {0} -SIGHUP'.format(d) self.local(cmd) - for v in self.routes.itervalues(): + for v in chain.from_iterable(self.routes.itervalues()): if v['rf'] == 'ipv4' or v['rf'] == 'ipv6': r = CmdBuffer(' ') r << 'gobgp global -a {0}'.format(v['rf']) diff --git a/vendor/github.com/osrg/gobgp/test/lib/quagga.py b/vendor/github.com/osrg/gobgp/test/lib/quagga.py index e7b9f9bf7b..d37c2dbc6f 100644 --- a/vendor/github.com/osrg/gobgp/test/lib/quagga.py +++ b/vendor/github.com/osrg/gobgp/test/lib/quagga.py @@ -17,6 +17,7 @@ from fabric import colors from fabric.utils import indent +from itertools import chain import netaddr from lib.base import ( @@ -191,7 +192,7 @@ def _create_config_bgp(self): c << 'neighbor {0} activate'.format(n_addr) c << 'exit-address-family' - for route in self.routes.itervalues(): + for route in chain.from_iterable(self.routes.itervalues()): if route['rf'] == 'ipv4': c << 'network {0}'.format(route['prefix']) elif route['rf'] == 'ipv6': diff --git a/vendor/github.com/osrg/gobgp/test/scenario_test/addpath_test.py b/vendor/github.com/osrg/gobgp/test/scenario_test/addpath_test.py new file mode 100644 index 0000000000..82b848a6a3 --- /dev/null +++ b/vendor/github.com/osrg/gobgp/test/scenario_test/addpath_test.py @@ -0,0 +1,77 @@ +# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import unittest +from fabric.api import local +from lib import base +from lib.base import BGP_FSM_ESTABLISHED +from lib.gobgp import * +from lib.exabgp import * +import sys +import os +import time +import nose +from lib.noseplugin import OptionParser, parser_option +from itertools import combinations + + +class GoBGPTestBase(unittest.TestCase): + + @classmethod + def setUpClass(cls): + gobgp_ctn_image_name = parser_option.gobgp_image + base.TEST_PREFIX = parser_option.test_prefix + + g1 = GoBGPContainer(name='g1', asn=65000, router_id='192.168.0.1', + ctn_image_name=gobgp_ctn_image_name, + log_level=parser_option.gobgp_log_level) + e1 = ExaBGPContainer(name='e1', asn=65000, router_id='192.168.0.2') + + ctns = [g1, e1] + + e1.add_route(route='192.168.100.0/24', identifier=10, aspath=[100, 200, 300]) + e1.add_route(route='192.168.100.0/24', identifier=20, aspath=[100, 200]) + e1.add_route(route='192.168.100.0/24', identifier=30, aspath=[100]) + + initial_wait_time = max(ctn.run() for ctn in ctns) + + time.sleep(initial_wait_time) + + g1.add_peer(e1, addpath=True) + e1.add_peer(g1, addpath=True) + cls.g1 = g1 + cls.e1 = e1 + + # test each neighbor state is turned establish + def test_01_neighbor_established(self): + self.g1.wait_for(expected_state=BGP_FSM_ESTABLISHED, peer=self.e1) + + # test three routes are installed to the rib due to add-path feature + def test_02_check_g1_global_rib(self): + rib = self.g1.get_global_rib() + self.assertTrue(len(rib) == 1) + self.assertTrue(len(rib[0]['paths']) == 3) + +if __name__ == '__main__': + if os.geteuid() is not 0: + print "you are not root." + sys.exit(1) + output = local("which docker 2>&1 > /dev/null ; echo $?", capture=True) + if int(output) is not 0: + print "docker not found" + sys.exit(1) + + nose.main(argv=sys.argv, addplugins=[OptionParser()], + defaultTest=sys.argv[0]) diff --git a/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/vendor/github.com/sirupsen/logrus/CHANGELOG.md index 03fe4b15f1..c443aed097 100644 --- a/vendor/github.com/sirupsen/logrus/CHANGELOG.md +++ b/vendor/github.com/sirupsen/logrus/CHANGELOG.md @@ -1,6 +1,7 @@ # 1.0.2 * bug: quote non-string values in text formatter (#583) +* Make (*Logger) SetLevel a public method # 1.0.1 diff --git a/vendor/github.com/sirupsen/logrus/exported.go b/vendor/github.com/sirupsen/logrus/exported.go index 1aeaa90ba2..013183edab 100644 --- a/vendor/github.com/sirupsen/logrus/exported.go +++ b/vendor/github.com/sirupsen/logrus/exported.go @@ -31,7 +31,7 @@ func SetFormatter(formatter Formatter) { func SetLevel(level Level) { std.mu.Lock() defer std.mu.Unlock() - std.setLevel(level) + std.SetLevel(level) } // GetLevel returns the standard logger level. diff --git a/vendor/github.com/sirupsen/logrus/logger.go b/vendor/github.com/sirupsen/logrus/logger.go index 370fff5d1b..b44966f973 100644 --- a/vendor/github.com/sirupsen/logrus/logger.go +++ b/vendor/github.com/sirupsen/logrus/logger.go @@ -312,6 +312,6 @@ func (logger *Logger) level() Level { return Level(atomic.LoadUint32((*uint32)(&logger.Level))) } -func (logger *Logger) setLevel(level Level) { +func (logger *Logger) SetLevel(level Level) { atomic.StoreUint32((*uint32)(&logger.Level), uint32(level)) } diff --git a/vendor/github.com/sirupsen/logrus/text_formatter.go b/vendor/github.com/sirupsen/logrus/text_formatter.go index 6aa48cfb62..cf3f17f2f8 100644 --- a/vendor/github.com/sirupsen/logrus/text_formatter.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter.go @@ -52,10 +52,6 @@ type TextFormatter struct { // QuoteEmptyFields will wrap empty fields in quotes if true QuoteEmptyFields bool - // QuoteCharacter can be set to the override the default quoting character " - // with something else. For example: ', or `. - QuoteCharacter string - // Whether the logger's out is to a terminal isTerminal bool @@ -63,9 +59,6 @@ type TextFormatter struct { } func (f *TextFormatter) init(entry *Entry) { - if len(f.QuoteCharacter) == 0 { - f.QuoteCharacter = "\"" - } if entry.Logger != nil { f.isTerminal = IsTerminal(entry.Logger.Out) } @@ -177,13 +170,6 @@ func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) { if !f.needsQuoting(stringVal) { b.WriteString(stringVal) } else { - b.WriteString(f.quoteString(stringVal)) + b.WriteString(fmt.Sprintf("%q", stringVal)) } } - -func (f *TextFormatter) quoteString(v string) string { - escapedQuote := fmt.Sprintf("\\%s", f.QuoteCharacter) - escapedValue := strings.Replace(v, f.QuoteCharacter, escapedQuote, -1) - - return fmt.Sprintf("%s%v%s", f.QuoteCharacter, escapedValue, f.QuoteCharacter) -} diff --git a/vendor/github.com/sirupsen/logrus/text_formatter_test.go b/vendor/github.com/sirupsen/logrus/text_formatter_test.go index d7b3bcb14e..ecb8f12714 100644 --- a/vendor/github.com/sirupsen/logrus/text_formatter_test.go +++ b/vendor/github.com/sirupsen/logrus/text_formatter_test.go @@ -3,10 +3,10 @@ package logrus import ( "bytes" "errors" + "fmt" "strings" "testing" "time" - "fmt" ) func TestQuoting(t *testing.T) { @@ -15,7 +15,7 @@ func TestQuoting(t *testing.T) { checkQuoting := func(q bool, value interface{}) { b, _ := tf.Format(WithField("test", value)) idx := bytes.Index(b, ([]byte)("test=")) - cont := bytes.Contains(b[idx+5:], []byte(tf.QuoteCharacter)) + cont := bytes.Contains(b[idx+5:], []byte("\"")) if cont != q { if q { t.Errorf("quoting expected for: %#v", value) @@ -41,23 +41,6 @@ func TestQuoting(t *testing.T) { checkQuoting(false, errors.New("invalid")) checkQuoting(true, errors.New("invalid argument")) - // Test for custom quote character. - tf.QuoteCharacter = "`" - checkQuoting(false, "") - checkQuoting(false, "abcd") - checkQuoting(false, "/foobar") - checkQuoting(false, "foo_bar") - checkQuoting(false, "foo@bar") - checkQuoting(false, "foobar^") - checkQuoting(true, "foobar$") - checkQuoting(true, "&foobar") - checkQuoting(true, errors.New("invalid argument")) - - // Test for multi-character quotes. - tf.QuoteCharacter = "§~±" - checkQuoting(false, "abcd") - checkQuoting(true, errors.New("invalid argument")) - // Test for quoting empty fields. tf.QuoteEmptyFields = true checkQuoting(true, "") @@ -65,7 +48,7 @@ func TestQuoting(t *testing.T) { checkQuoting(true, errors.New("invalid argument")) } -func TestEscaping_DefaultQuoteCharacter(t *testing.T) { +func TestEscaping(t *testing.T) { tf := &TextFormatter{DisableColors: true} testCases := []struct { @@ -105,35 +88,13 @@ func TestEscaping_Interface(t *testing.T) { } } -func TestEscaping_CustomQuoteCharacter(t *testing.T) { - tf := &TextFormatter{DisableColors: true} - - testCases := []struct { - value string - expected string - quoteChar string - }{ - {`ba"r`, `ba"r`, `'`}, - {`ba'r`, `ba\'r`, `'`}, - {`ba'r`, `ba'r`, `^`}, - } - - for _, tc := range testCases { - tf.QuoteCharacter = tc.quoteChar - b, _ := tf.Format(WithField("test", tc.value)) - if !bytes.Contains(b, []byte(tc.expected)) { - t.Errorf("escaping expected for %q (result was %q instead of %q)", tc.value, string(b), tc.expected) - } - } -} - func TestTimestampFormat(t *testing.T) { checkTimeStr := func(format string) { customFormatter := &TextFormatter{DisableColors: true, TimestampFormat: format} customStr, _ := customFormatter.Format(WithField("test", "test")) timeStart := bytes.Index(customStr, ([]byte)("time=")) timeEnd := bytes.Index(customStr, ([]byte)("level=")) - timeStr := customStr[timeStart+5+len(customFormatter.QuoteCharacter) : timeEnd-1-len(customFormatter.QuoteCharacter)] + timeStr := customStr[timeStart+5+len("\"") : timeEnd-1-len("\"")] if format == "" { format = time.RFC3339 }