From 89f40dfa4a015d000489a1ffa70824722e7eafed Mon Sep 17 00:00:00 2001 From: IWASE Yusuke Date: Thu, 22 Feb 2018 13:29:52 +0900 Subject: packet/bgp: Flatten structure of OpaqueExtended Currently, to instantiate sub types of the Opaque Extended Community, it is required to instantiate "OpaqueExtended" and its value type (e.g., "ValidationExtended" or "EncapExtended") and also specify its sub type. This can cause the confusion of the outer and inner (value) structures and the unmatch of the value structure and its sub type. This patch makes the "OpaqueExtended" into more flat structure and introduces "NewXxxExtended()" function to improve usability. Signed-off-by: IWASE Yusuke --- packet/bgp/bgp.go | 304 +++++++++++++++++++++++++++++++++------------------ packet/bgp/helper.go | 8 +- 2 files changed, 197 insertions(+), 115 deletions(-) (limited to 'packet') diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go index d59ce441..c013f23a 100644 --- a/packet/bgp/bgp.go +++ b/packet/bgp/bgp.go @@ -6319,22 +6319,19 @@ func NewFourOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uin func ParseExtendedCommunity(subtype ExtendedCommunityAttrSubType, com string) (ExtendedCommunityInterface, error) { if subtype == EC_SUBTYPE_ORIGIN_VALIDATION { - var value ValidationState + var state ValidationState switch com { case VALIDATION_STATE_VALID.String(): - value = VALIDATION_STATE_VALID + state = VALIDATION_STATE_VALID case VALIDATION_STATE_NOT_FOUND.String(): - value = VALIDATION_STATE_NOT_FOUND + state = VALIDATION_STATE_NOT_FOUND case VALIDATION_STATE_INVALID.String(): - value = VALIDATION_STATE_INVALID + state = VALIDATION_STATE_INVALID default: return nil, fmt.Errorf("invalid validation state") } - return &OpaqueExtended{ - SubType: EC_SUBTYPE_ORIGIN_VALIDATION, - Value: &ValidationExtended{ - Value: value, - }, + return &ValidationExtended{ + State: state, }, nil } elems, err := parseRdAndRt(com) @@ -6364,27 +6361,6 @@ func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) { return ParseExtendedCommunity(EC_SUBTYPE_ROUTE_TARGET, rt) } -type OpaqueExtendedValueInterface interface { - Serialize() ([]byte, error) - String() string -} - -type DefaultOpaqueExtendedValue struct { - Value []byte -} - -func (v *DefaultOpaqueExtendedValue) Serialize() ([]byte, error) { - v.Value = v.Value[:7] - return v.Value[:7], nil -} - -func (v *DefaultOpaqueExtendedValue) String() string { - buf := make([]byte, 8) - copy(buf[1:], v.Value) - d := binary.BigEndian.Uint64(buf) - return fmt.Sprintf("%d", d) -} - type ValidationState uint8 const ( @@ -6406,33 +6382,83 @@ func (s ValidationState) String() string { } type ValidationExtended struct { - Value ValidationState + State ValidationState } func (e *ValidationExtended) Serialize() ([]byte, error) { - buf := make([]byte, 7) - buf[0] = byte(EC_SUBTYPE_ORIGIN_VALIDATION) - buf[6] = byte(e.Value) + buf := make([]byte, 8, 8) + typ, subType := e.GetTypes() + buf[0] = byte(typ) + buf[1] = byte(subType) + buf[7] = byte(e.State) return buf, nil } func (e *ValidationExtended) String() string { - return e.Value.String() + return e.State.String() +} + +func (e *ValidationExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { + return EC_TYPE_NON_TRANSITIVE_OPAQUE, EC_SUBTYPE_ORIGIN_VALIDATION +} + +func (e *ValidationExtended) MarshalJSON() ([]byte, error) { + t, s := e.GetTypes() + return json.Marshal(struct { + Type ExtendedCommunityAttrType `json:"type"` + SubType ExtendedCommunityAttrSubType `json:"subtype"` + State ValidationState `json:"value"` + }{ + Type: t, + SubType: s, + State: e.State, + }) +} + +func NewValidationExtended(state ValidationState) *ValidationExtended { + return &ValidationExtended{ + State: state, + } } type ColorExtended struct { - Value uint32 + Color uint32 } func (e *ColorExtended) Serialize() ([]byte, error) { - buf := make([]byte, 7) - buf[0] = byte(EC_SUBTYPE_COLOR) - binary.BigEndian.PutUint32(buf[3:], uint32(e.Value)) + buf := make([]byte, 8, 8) + typ, subType := e.GetTypes() + buf[0] = byte(typ) + buf[1] = byte(subType) + binary.BigEndian.PutUint32(buf[4:8], uint32(e.Color)) return buf, nil } func (e *ColorExtended) String() string { - return fmt.Sprintf("%d", e.Value) + return fmt.Sprintf("%d", e.Color) +} + +func (e *ColorExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { + return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_COLOR +} + +func (e *ColorExtended) MarshalJSON() ([]byte, error) { + t, s := e.GetTypes() + return json.Marshal(struct { + Type ExtendedCommunityAttrType `json:"type"` + SubType ExtendedCommunityAttrSubType `json:"subtype"` + Color uint32 `json:"color"` + }{ + Type: t, + SubType: s, + Color: e.Color, + }) +} + +func NewColorExtended(color uint32) *ColorExtended { + return &ColorExtended{ + Color: color, + } } type EncapExtended struct { @@ -6440,9 +6466,11 @@ type EncapExtended struct { } func (e *EncapExtended) Serialize() ([]byte, error) { - buf := make([]byte, 7) - buf[0] = byte(EC_SUBTYPE_ENCAPSULATION) - binary.BigEndian.PutUint16(buf[5:], uint16(e.TunnelType)) + buf := make([]byte, 8, 8) + typ, subType := e.GetTypes() + buf[0] = byte(typ) + buf[1] = byte(subType) + binary.BigEndian.PutUint16(buf[6:8], uint16(e.TunnelType)) return buf, nil } @@ -6471,12 +6499,37 @@ func (e *EncapExtended) String() string { } } +func (e *EncapExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { + return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_ENCAPSULATION +} + +func (e *EncapExtended) MarshalJSON() ([]byte, error) { + t, s := e.GetTypes() + return json.Marshal(struct { + Type ExtendedCommunityAttrType `json:"type"` + SubType ExtendedCommunityAttrSubType `json:"subtype"` + TunnelType TunnelType `json:"tunnel_type"` + }{ + Type: t, + SubType: s, + TunnelType: e.TunnelType, + }) +} + +func NewEncapExtended(tunnelType TunnelType) *EncapExtended { + return &EncapExtended{ + TunnelType: tunnelType, + } +} + type DefaultGatewayExtended struct { } func (e *DefaultGatewayExtended) Serialize() ([]byte, error) { - buf := make([]byte, 7) - buf[0] = byte(EC_SUBTYPE_DEFAULT_GATEWAY) + buf := make([]byte, 8, 8) + typ, subType := e.GetTypes() + buf[0] = byte(typ) + buf[1] = byte(subType) return buf, nil } @@ -6484,70 +6537,60 @@ func (e *DefaultGatewayExtended) String() string { return "default-gateway" } -type OpaqueExtended struct { - IsTransitive bool - Value OpaqueExtendedValueInterface - SubType ExtendedCommunityAttrSubType +func (e *DefaultGatewayExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { + return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_DEFAULT_GATEWAY } -func (e *OpaqueExtended) DecodeFromBytes(data []byte) error { - if len(data) != 7 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid OpaqueExtended bytes len: %d", len(data))) - } - e.SubType = ExtendedCommunityAttrSubType(data[0]) +func (e *DefaultGatewayExtended) MarshalJSON() ([]byte, error) { + t, s := e.GetTypes() + return json.Marshal(struct { + Type ExtendedCommunityAttrType `json:"type"` + SubType ExtendedCommunityAttrSubType `json:"subtype"` + }{ + Type: t, + SubType: s, + }) +} - if e.IsTransitive { - switch e.SubType { - case EC_SUBTYPE_COLOR: - v := binary.BigEndian.Uint32(data[3:7]) - e.Value = &ColorExtended{ - Value: v, - } - case EC_SUBTYPE_ENCAPSULATION: - t := TunnelType(binary.BigEndian.Uint16(data[5:7])) - e.Value = &EncapExtended{ - TunnelType: t, - } - case EC_SUBTYPE_DEFAULT_GATEWAY: - e.Value = &DefaultGatewayExtended{} - default: - e.Value = &DefaultOpaqueExtendedValue{ - Value: data, //7byte - } - } - } else { - switch e.SubType { - case EC_SUBTYPE_ORIGIN_VALIDATION: - e.Value = &ValidationExtended{ - Value: ValidationState(data[6]), - } - default: - e.Value = &DefaultOpaqueExtendedValue{ - Value: data, //7byte - } - } - } - return nil +func NewDefaultGatewayExtended() *DefaultGatewayExtended { + return &DefaultGatewayExtended{} +} + +type OpaqueExtended struct { + IsTransitive bool + Value []byte } func (e *OpaqueExtended) Serialize() ([]byte, error) { - buf := make([]byte, 1, 7) + if len(e.Value) != 7 { + return nil, fmt.Errorf("invalid value length for opaque extended community: %d", len(e.Value)) + } + buf := make([]byte, 8, 8) if e.IsTransitive { buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) } else { buf[0] = byte(EC_TYPE_NON_TRANSITIVE_OPAQUE) } - bbuf, err := e.Value.Serialize() - e.SubType = ExtendedCommunityAttrSubType(bbuf[0]) - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) + copy(buf[1:], e.Value) return buf, nil } func (e *OpaqueExtended) String() string { - return e.Value.String() + buf := make([]byte, 8, 8) + copy(buf[1:], e.Value) + return fmt.Sprintf("%d", binary.BigEndian.Uint64(buf)) +} + +func (e *OpaqueExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { + var subType ExtendedCommunityAttrSubType + if len(e.Value) > 0 { + // Use the first byte of value as the sub type + subType = ExtendedCommunityAttrSubType(e.Value[0]) + } + if e.IsTransitive { + return EC_TYPE_TRANSITIVE_OPAQUE, subType + } + return EC_TYPE_NON_TRANSITIVE_OPAQUE, subType } func (e *OpaqueExtended) MarshalJSON() ([]byte, error) { @@ -6555,7 +6598,7 @@ func (e *OpaqueExtended) MarshalJSON() ([]byte, error) { return json.Marshal(struct { Type ExtendedCommunityAttrType `json:"type"` Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value OpaqueExtendedValueInterface `json:"value"` + Value []byte `json:"value"` }{ Type: t, Subtype: s, @@ -6563,18 +6606,50 @@ func (e *OpaqueExtended) MarshalJSON() ([]byte, error) { }) } -func (e *OpaqueExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_OPAQUE - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_OPAQUE +func NewOpaqueExtended(isTransitive bool, value []byte) *OpaqueExtended { + v := make([]byte, 7, 7) + copy(v, value) + return &OpaqueExtended{ + IsTransitive: isTransitive, + Value: v, } - return t, e.SubType } -func NewOpaqueExtended(isTransitive bool) *OpaqueExtended { - return &OpaqueExtended{ - IsTransitive: isTransitive, +func parseOpaqueExtended(data []byte) (ExtendedCommunityInterface, error) { + typ := ExtendedCommunityAttrType(data[0]) + isTransitive := false + switch typ { + case EC_TYPE_TRANSITIVE_OPAQUE: + isTransitive = true + case EC_TYPE_NON_TRANSITIVE_OPAQUE: + // isTransitive = false + default: + return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid opaque extended community type: %d", data[0])) } + subType := ExtendedCommunityAttrSubType(data[1]) + + if isTransitive { + switch subType { + case EC_SUBTYPE_COLOR: + return &ColorExtended{ + Color: binary.BigEndian.Uint32(data[4:8]), + }, nil + case EC_SUBTYPE_ENCAPSULATION: + return &EncapExtended{ + TunnelType: TunnelType(binary.BigEndian.Uint16(data[6:8])), + }, nil + case EC_SUBTYPE_DEFAULT_GATEWAY: + return &DefaultGatewayExtended{}, nil + } + } else { + switch subType { + case EC_SUBTYPE_ORIGIN_VALIDATION: + return &ValidationExtended{ + State: ValidationState(data[7]), + }, nil + } + } + return NewOpaqueExtended(isTransitive, data[1:8]), nil } type ESILabelExtended struct { @@ -7211,9 +7286,7 @@ func ParseExtended(data []byte) (ExtendedCommunityInterface, error) { transitive = true fallthrough case EC_TYPE_NON_TRANSITIVE_OPAQUE: - e := NewOpaqueExtended(transitive) - err := e.DecodeFromBytes(data[1:8]) - return e, err + return parseOpaqueExtended(data) case EC_TYPE_EVPN: return parseEvpnExtended(data) case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2, EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3: @@ -8956,10 +9029,23 @@ func (e *TwoOctetAsSpecificExtended) Flat() map[string]string { return map[string]string{} } +func (e *ColorExtended) Flat() map[string]string { + return map[string]string{} +} + +func (e *EncapExtended) Flat() map[string]string { + return map[string]string{"encaspulation": e.TunnelType.String()} +} + +func (e *DefaultGatewayExtended) Flat() map[string]string { + return map[string]string{} +} + +func (e *ValidationExtended) Flat() map[string]string { + return map[string]string{} +} + func (e *OpaqueExtended) Flat() map[string]string { - if e.SubType == EC_SUBTYPE_ENCAPSULATION { - return map[string]string{"encaspulation": e.Value.String()} - } return map[string]string{} } diff --git a/packet/bgp/helper.go b/packet/bgp/helper.go index 79229d92..851332fd 100644 --- a/packet/bgp/helper.go +++ b/packet/bgp/helper.go @@ -65,12 +65,8 @@ func NewTestBGPUpdateMessage() *BGPMessage { NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 10003, 3<<20, isTransitive), NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 1<<20, 300, isTransitive), NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, "192.2.1.2", 3000, isTransitive), - &OpaqueExtended{ - Value: &DefaultOpaqueExtendedValue{[]byte{255, 1, 2, 3, 4, 5, 6, 7}}, - }, - &OpaqueExtended{ - Value: &ValidationExtended{Value: VALIDATION_STATE_INVALID}, - }, + NewOpaqueExtended(false, []byte{1, 2, 3, 4, 5, 6, 7}), + NewValidationExtended(VALIDATION_STATE_INVALID), &UnknownExtended{Type: 99, Value: []byte{0, 1, 2, 3, 4, 5, 6, 7}}, NewESILabelExtended(1000, true), NewESImportRouteTarget("11:22:33:44:55:66"), -- cgit v1.2.3