diff options
Diffstat (limited to 'packet')
-rw-r--r-- | packet/bgp/bgp.go | 9674 | ||||
-rw-r--r-- | packet/bgp/bgp_race_test.go | 46 | ||||
-rw-r--r-- | packet/bgp/bgp_test.go | 1194 | ||||
-rw-r--r-- | packet/bgp/bgpattrtype_string.go | 28 | ||||
-rw-r--r-- | packet/bgp/constant.go | 327 | ||||
-rw-r--r-- | packet/bgp/esitype_string.go | 16 | ||||
-rw-r--r-- | packet/bgp/fsmstate_string.go | 16 | ||||
-rw-r--r-- | packet/bgp/helper.go | 126 | ||||
-rw-r--r-- | packet/bgp/validate.go | 337 | ||||
-rw-r--r-- | packet/bgp/validate_test.go | 423 | ||||
-rw-r--r-- | packet/bmp/bmp.go | 1071 | ||||
-rw-r--r-- | packet/bmp/bmp_test.go | 107 | ||||
-rw-r--r-- | packet/mrt/mrt.go | 1006 | ||||
-rw-r--r-- | packet/mrt/mrt_test.go | 301 | ||||
-rw-r--r-- | packet/rtr/rtr.go | 392 | ||||
-rw-r--r-- | packet/rtr/rtr_test.go | 118 |
16 files changed, 0 insertions, 15182 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go deleted file mode 100644 index 01251167..00000000 --- a/packet/bgp/bgp.go +++ /dev/null @@ -1,9674 +0,0 @@ -// Copyright (C) 2014 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. - -package bgp - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "fmt" - "math" - "net" - "reflect" - "regexp" - "sort" - "strconv" - "strings" -) - -type MarshallingOption struct { - AddPath map[RouteFamily]BGPAddPathMode -} - -func IsAddPathEnabled(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 - AFI_L2VPN = 25 - AFI_OPAQUE = 16397 -) - -const ( - SAFI_UNICAST = 1 - SAFI_MULTICAST = 2 - SAFI_MPLS_LABEL = 4 - SAFI_ENCAPSULATION = 7 - SAFI_VPLS = 65 - SAFI_EVPN = 70 - SAFI_MPLS_VPN = 128 - SAFI_MPLS_VPN_MULTICAST = 129 - SAFI_ROUTE_TARGET_CONSTRAINTS = 132 - SAFI_FLOW_SPEC_UNICAST = 133 - SAFI_FLOW_SPEC_VPN = 134 - SAFI_KEY_VALUE = 241 -) - -const ( - BGP_ORIGIN_ATTR_TYPE_IGP uint8 = 0 - BGP_ORIGIN_ATTR_TYPE_EGP uint8 = 1 - BGP_ORIGIN_ATTR_TYPE_INCOMPLETE uint8 = 2 -) - -const ( - BGP_ASPATH_ATTR_TYPE_SET = 1 - BGP_ASPATH_ATTR_TYPE_SEQ = 2 - BGP_ASPATH_ATTR_TYPE_CONFED_SEQ = 3 - BGP_ASPATH_ATTR_TYPE_CONFED_SET = 4 -) - -// RFC7153 5.1. Registries for the "Type" Field -// RANGE REGISTRATION PROCEDURES -// 0x00-0x3F Transitive First Come First Served -// 0x40-0x7F Non-Transitive First Come First Served -// 0x80-0x8F Transitive Experimental Use -// 0x90-0xBF Transitive Standards Action -// 0xC0-0xCF Non-Transitive Experimental Use -// 0xD0-0xFF Non-Transitive Standards Action -type ExtendedCommunityAttrType uint8 - -const ( - EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x00 - EC_TYPE_TRANSITIVE_IP6_SPECIFIC ExtendedCommunityAttrType = 0x00 // RFC5701 - EC_TYPE_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x01 - EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x02 - EC_TYPE_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x03 - EC_TYPE_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x04 - EC_TYPE_COS_CAPABILITY ExtendedCommunityAttrType = 0x05 - EC_TYPE_EVPN ExtendedCommunityAttrType = 0x06 - EC_TYPE_FLOWSPEC_REDIRECT_MIRROR ExtendedCommunityAttrType = 0x08 - EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x40 - EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC ExtendedCommunityAttrType = 0x40 // RFC5701 - EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x41 - EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x42 - EC_TYPE_NON_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x43 - EC_TYPE_NON_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x44 - EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL ExtendedCommunityAttrType = 0x80 - EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 ExtendedCommunityAttrType = 0x81 // RFC7674 - EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 ExtendedCommunityAttrType = 0x82 // RFC7674 -) - -// RFC7153 5.2. Registries for the "Sub-Type" Field -// RANGE REGISTRATION PROCEDURES -// 0x00-0xBF First Come First Served -// 0xC0-0xFF IETF Review -type ExtendedCommunityAttrSubType uint8 - -const ( - EC_SUBTYPE_ROUTE_TARGET ExtendedCommunityAttrSubType = 0x02 // EC_TYPE: 0x00, 0x01, 0x02 - EC_SUBTYPE_ROUTE_ORIGIN ExtendedCommunityAttrSubType = 0x03 // EC_TYPE: 0x00, 0x01, 0x02 - EC_SUBTYPE_LINK_BANDWIDTH ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x40 - EC_SUBTYPE_GENERIC ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x02, 0x42 - EC_SUBTYPE_OSPF_DOMAIN_ID ExtendedCommunityAttrSubType = 0x05 // EC_TYPE: 0x00, 0x01, 0x02 - EC_SUBTYPE_OSPF_ROUTE_ID ExtendedCommunityAttrSubType = 0x07 // EC_TYPE: 0x01 - EC_SUBTYPE_BGP_DATA_COLLECTION ExtendedCommunityAttrSubType = 0x08 // EC_TYPE: 0x00, 0x02 - EC_SUBTYPE_SOURCE_AS ExtendedCommunityAttrSubType = 0x09 // EC_TYPE: 0x00, 0x02 - EC_SUBTYPE_L2VPN_ID ExtendedCommunityAttrSubType = 0x0A // EC_TYPE: 0x00, 0x01 - EC_SUBTYPE_VRF_ROUTE_IMPORT ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x01 - EC_SUBTYPE_CISCO_VPN_DISTINGUISHER ExtendedCommunityAttrSubType = 0x10 // EC_TYPE: 0x00, 0x01, 0x02 - - EC_SUBTYPE_OSPF_ROUTE_TYPE ExtendedCommunityAttrSubType = 0x06 // EC_TYPE: 0x03 - EC_SUBTYPE_COLOR ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x03 - EC_SUBTYPE_ENCAPSULATION ExtendedCommunityAttrSubType = 0x0C // EC_TYPE: 0x03 - EC_SUBTYPE_DEFAULT_GATEWAY ExtendedCommunityAttrSubType = 0x0D // EC_TYPE: 0x03 - - EC_SUBTYPE_ORIGIN_VALIDATION ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x43 - - EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE ExtendedCommunityAttrSubType = 0x06 // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION ExtendedCommunityAttrSubType = 0x07 // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_REDIRECT ExtendedCommunityAttrSubType = 0x08 // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK ExtendedCommunityAttrSubType = 0x09 // EC_TYPE: 0x80 - EC_SUBTYPE_L2_INFO ExtendedCommunityAttrSubType = 0x0A // EC_TYPE: 0x80 - EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6 ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x80 - - EC_SUBTYPE_MAC_MOBILITY ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x06 - EC_SUBTYPE_ESI_LABEL ExtendedCommunityAttrSubType = 0x01 // EC_TYPE: 0x06 - EC_SUBTYPE_ES_IMPORT ExtendedCommunityAttrSubType = 0x02 // EC_TYPE: 0x06 - EC_SUBTYPE_ROUTER_MAC ExtendedCommunityAttrSubType = 0x03 // EC_TYPE: 0x06 - - EC_SUBTYPE_UUID_BASED_RT ExtendedCommunityAttrSubType = 0x11 -) - -type TunnelType uint16 - -const ( - TUNNEL_TYPE_L2TP3 TunnelType = 1 - TUNNEL_TYPE_GRE TunnelType = 2 - TUNNEL_TYPE_IP_IN_IP TunnelType = 7 - TUNNEL_TYPE_VXLAN TunnelType = 8 - TUNNEL_TYPE_NVGRE TunnelType = 9 - TUNNEL_TYPE_MPLS TunnelType = 10 - TUNNEL_TYPE_MPLS_IN_GRE TunnelType = 11 - TUNNEL_TYPE_VXLAN_GRE TunnelType = 12 - TUNNEL_TYPE_MPLS_IN_UDP TunnelType = 13 -) - -func (p TunnelType) String() string { - switch p { - case TUNNEL_TYPE_L2TP3: - return "l2tp3" - case TUNNEL_TYPE_GRE: - return "gre" - case TUNNEL_TYPE_IP_IN_IP: - return "ip-in-ip" - case TUNNEL_TYPE_VXLAN: - return "vxlan" - case TUNNEL_TYPE_NVGRE: - return "nvgre" - case TUNNEL_TYPE_MPLS: - return "mpls" - case TUNNEL_TYPE_MPLS_IN_GRE: - return "mpls-in-gre" - case TUNNEL_TYPE_VXLAN_GRE: - return "vxlan-gre" - case TUNNEL_TYPE_MPLS_IN_UDP: - return "mpls-in-udp" - default: - return fmt.Sprintf("TunnelType(%d)", uint8(p)) - } -} - -type PmsiTunnelType uint8 - -const ( - PMSI_TUNNEL_TYPE_NO_TUNNEL PmsiTunnelType = 0 - PMSI_TUNNEL_TYPE_RSVP_TE_P2MP PmsiTunnelType = 1 - PMSI_TUNNEL_TYPE_MLDP_P2MP PmsiTunnelType = 2 - PMSI_TUNNEL_TYPE_PIM_SSM_TREE PmsiTunnelType = 3 - PMSI_TUNNEL_TYPE_PIM_SM_TREE PmsiTunnelType = 4 - PMSI_TUNNEL_TYPE_BIDIR_PIM_TREE PmsiTunnelType = 5 - PMSI_TUNNEL_TYPE_INGRESS_REPL PmsiTunnelType = 6 - PMSI_TUNNEL_TYPE_MLDP_MP2MP PmsiTunnelType = 7 -) - -func (p PmsiTunnelType) String() string { - switch p { - case PMSI_TUNNEL_TYPE_NO_TUNNEL: - return "no-tunnel" - case PMSI_TUNNEL_TYPE_RSVP_TE_P2MP: - return "rsvp-te-p2mp" - case PMSI_TUNNEL_TYPE_MLDP_P2MP: - return "mldp-p2mp" - case PMSI_TUNNEL_TYPE_PIM_SSM_TREE: - return "pim-ssm-tree" - case PMSI_TUNNEL_TYPE_PIM_SM_TREE: - return "pim-sm-tree" - case PMSI_TUNNEL_TYPE_BIDIR_PIM_TREE: - return "bidir-pim-tree" - case PMSI_TUNNEL_TYPE_INGRESS_REPL: - return "ingress-repl" - case PMSI_TUNNEL_TYPE_MLDP_MP2MP: - return "mldp-mp2mp" - default: - return fmt.Sprintf("PmsiTunnelType(%d)", uint8(p)) - } -} - -type EncapSubTLVType uint8 - -const ( - ENCAP_SUBTLV_TYPE_ENCAPSULATION EncapSubTLVType = 1 - ENCAP_SUBTLV_TYPE_PROTOCOL EncapSubTLVType = 2 - ENCAP_SUBTLV_TYPE_COLOR EncapSubTLVType = 4 -) - -const ( - _ = iota - BGP_MSG_OPEN - BGP_MSG_UPDATE - BGP_MSG_NOTIFICATION - BGP_MSG_KEEPALIVE - BGP_MSG_ROUTE_REFRESH -) - -const ( - BGP_OPT_CAPABILITY = 2 -) - -type BGPCapabilityCode uint8 - -const ( - BGP_CAP_MULTIPROTOCOL BGPCapabilityCode = 1 - BGP_CAP_ROUTE_REFRESH BGPCapabilityCode = 2 - BGP_CAP_CARRYING_LABEL_INFO BGPCapabilityCode = 4 - BGP_CAP_EXTENDED_NEXTHOP BGPCapabilityCode = 5 - BGP_CAP_GRACEFUL_RESTART BGPCapabilityCode = 64 - BGP_CAP_FOUR_OCTET_AS_NUMBER BGPCapabilityCode = 65 - BGP_CAP_ADD_PATH BGPCapabilityCode = 69 - BGP_CAP_ENHANCED_ROUTE_REFRESH BGPCapabilityCode = 70 - BGP_CAP_LONG_LIVED_GRACEFUL_RESTART BGPCapabilityCode = 71 - BGP_CAP_ROUTE_REFRESH_CISCO BGPCapabilityCode = 128 -) - -var CapNameMap = map[BGPCapabilityCode]string{ - BGP_CAP_MULTIPROTOCOL: "multiprotocol", - BGP_CAP_ROUTE_REFRESH: "route-refresh", - BGP_CAP_CARRYING_LABEL_INFO: "carrying-label-info", - BGP_CAP_GRACEFUL_RESTART: "graceful-restart", - BGP_CAP_EXTENDED_NEXTHOP: "extended-nexthop", - BGP_CAP_FOUR_OCTET_AS_NUMBER: "4-octet-as", - BGP_CAP_ADD_PATH: "add-path", - BGP_CAP_ENHANCED_ROUTE_REFRESH: "enhanced-route-refresh", - BGP_CAP_ROUTE_REFRESH_CISCO: "cisco-route-refresh", - BGP_CAP_LONG_LIVED_GRACEFUL_RESTART: "long-lived-graceful-restart", -} - -func (c BGPCapabilityCode) String() string { - if n, y := CapNameMap[c]; y { - return n - } - return fmt.Sprintf("UnknownCapability(%d)", c) -} - -var ( - // Used parsing RouteDistinguisher - _regexpRouteDistinguisher = regexp.MustCompile(`^((\d+)\.(\d+)\.(\d+)\.(\d+)|((\d+)\.)?(\d+)|([\w]+:[\w:]*:[\w]+)):(\d+)$`) - - // Used for operator and value for the FlowSpec numeric type - // Example: - // re.FindStringSubmatch("&==80") - // >>> ["&==80" "&" "==" "80"] - _regexpFlowSpecNumericType = regexp.MustCompile(`(&?)(==|=|>|>=|<|<=|!|!=|=!)?(\d+|-\d|true|false)`) - - // - "=!" is used in the old style format of "tcp-flags" and "fragment". - // - The value field should be one of the followings: - // * Decimal value (e.g., 80) - // * Combination of the small letters, decimals, "-" and "+" - // (e.g., tcp, ipv4, is-fragment+first-fragment) - // * Capital letters (e.g., SA) - _regexpFlowSpecOperator = regexp.MustCompile(`&|=|>|<|!|[\w\-+]+`) - _regexpFlowSpecOperatorValue = regexp.MustCompile(`[\w\-+]+`) - - // Note: "(-*)" and "(.*)" catch the invalid flags - // Example: In this case, "Z" is unsupported flag type. - // re.FindStringSubmatch("&==-SZU") - // >>> ["&==-SZU" "&" "==" "-" "S" "ZU"] - _regexpFlowSpecTCPFlag = regexp.MustCompile("(&?)(==|=|!|!=|=!)?(-*)([FSRPAUCE]+)(.*)") - - // Note: "(.*)" catches the invalid flags - // re.FindStringSubmatch("&!=+first-fragment+last-fragment+invalid-fragment") - // >>> ["&!=+first-fragment+last-fragment+invalid-fragment" "&" "!=" "+first-fragment+last-fragment" "+last-fragment" "+" "last" "+invalid-fragment"] - _regexpFlowSpecFragment = regexp.MustCompile(`(&?)(==|=|!|!=|=!)?(((\+)?(dont|is|first|last|not-a)-fragment)+)(.*)`) - - // re.FindStringSubmatch("192.168.0.0/24") - // >>> ["192.168.0.0/24" "192.168.0.0" "/24" "24"] - // re.FindStringSubmatch("192.168.0.1") - // >>> ["192.168.0.1" "192.168.0.1" "" ""] - _regexpFindIPv4Prefix = regexp.MustCompile(`^([\d.]+)(/(\d{1,2}))?`) - - // re.FindStringSubmatch("2001:dB8::/64") - // >>> ["2001:dB8::/64" "2001:dB8::" "/64" "64" "" ""] - // re.FindStringSubmatch("2001:dB8::/64/8") - // >>> ["2001:dB8::/64/8" "2001:dB8::" "/64" "64" "/8" "8"] - // re.FindStringSubmatch("2001:dB8::1") - // >>> ["2001:dB8::1" "2001:dB8::1" "" "" "" ""] - _regexpFindIPv6Prefix = regexp.MustCompile(`^([a-fA-F\d:.]+)(/(\d{1,3}))?(/(\d{1,3}))?`) -) - -type ParameterCapabilityInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int - Code() BGPCapabilityCode -} - -type DefaultParameterCapability struct { - CapCode BGPCapabilityCode `json:"code"` - CapLen uint8 `json:"-"` - CapValue []byte `json:"value,omitempty"` -} - -func (c *DefaultParameterCapability) Code() BGPCapabilityCode { - return c.CapCode -} - -func (c *DefaultParameterCapability) DecodeFromBytes(data []byte) error { - c.CapCode = BGPCapabilityCode(data[0]) - c.CapLen = data[1] - if len(data) < 2+int(c.CapLen) { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all OptionParameterCapability bytes available") - } - if c.CapLen > 0 { - c.CapValue = data[2 : 2+c.CapLen] - } - return nil -} - -func (c *DefaultParameterCapability) Serialize() ([]byte, error) { - c.CapLen = uint8(len(c.CapValue)) - buf := make([]byte, 2) - buf[0] = uint8(c.CapCode) - buf[1] = c.CapLen - buf = append(buf, c.CapValue...) - return buf, nil -} - -func (c *DefaultParameterCapability) Len() int { - return int(c.CapLen + 2) -} - -type CapMultiProtocol struct { - DefaultParameterCapability - CapValue RouteFamily -} - -func (c *CapMultiProtocol) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 4 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityMultiProtocol bytes available") - } - c.CapValue = AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[0:2]), data[3]) - return nil -} - -func (c *CapMultiProtocol) Serialize() ([]byte, error) { - buf := make([]byte, 4) - afi, safi := RouteFamilyToAfiSafi(c.CapValue) - binary.BigEndian.PutUint16(buf[0:], afi) - buf[3] = safi - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapMultiProtocol) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Value RouteFamily `json:"value"` - }{ - Code: c.Code(), - Value: c.CapValue, - }) -} - -func NewCapMultiProtocol(rf RouteFamily) *CapMultiProtocol { - return &CapMultiProtocol{ - DefaultParameterCapability{ - CapCode: BGP_CAP_MULTIPROTOCOL, - }, - rf, - } -} - -type CapRouteRefresh struct { - DefaultParameterCapability -} - -func NewCapRouteRefresh() *CapRouteRefresh { - return &CapRouteRefresh{ - DefaultParameterCapability{ - CapCode: BGP_CAP_ROUTE_REFRESH, - }, - } -} - -type CapCarryingLabelInfo struct { - DefaultParameterCapability -} - -func NewCapCarryingLabelInfo() *CapCarryingLabelInfo { - return &CapCarryingLabelInfo{ - DefaultParameterCapability{ - CapCode: BGP_CAP_CARRYING_LABEL_INFO, - }, - } -} - -type CapExtendedNexthopTuple struct { - NLRIAFI uint16 - NLRISAFI uint16 - NexthopAFI uint16 -} - -func (c *CapExtendedNexthopTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - NLRIAddressFamily RouteFamily `json:"nlri_address_family"` - NexthopAddressFamily uint16 `json:"nexthop_address_family"` - }{ - NLRIAddressFamily: AfiSafiToRouteFamily(c.NLRIAFI, uint8(c.NLRISAFI)), - NexthopAddressFamily: c.NexthopAFI, - }) -} - -func NewCapExtendedNexthopTuple(af RouteFamily, nexthop uint16) *CapExtendedNexthopTuple { - afi, safi := RouteFamilyToAfiSafi(af) - return &CapExtendedNexthopTuple{ - NLRIAFI: afi, - NLRISAFI: uint16(safi), - NexthopAFI: nexthop, - } -} - -type CapExtendedNexthop struct { - DefaultParameterCapability - Tuples []*CapExtendedNexthopTuple -} - -func (c *CapExtendedNexthop) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 6 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityExtendedNexthop bytes available") - } - c.Tuples = []*CapExtendedNexthopTuple{} - for len(data) >= 6 { - t := &CapExtendedNexthopTuple{ - binary.BigEndian.Uint16(data[0:2]), - binary.BigEndian.Uint16(data[2:4]), - binary.BigEndian.Uint16(data[4:6]), - } - c.Tuples = append(c.Tuples, t) - data = data[6:] - } - return nil -} - -func (c *CapExtendedNexthop) Serialize() ([]byte, error) { - buf := make([]byte, len(c.Tuples)*6) - for i, t := range c.Tuples { - binary.BigEndian.PutUint16(buf[i*6:i*6+2], t.NLRIAFI) - binary.BigEndian.PutUint16(buf[i*6+2:i*6+4], t.NLRISAFI) - binary.BigEndian.PutUint16(buf[i*6+4:i*6+6], t.NexthopAFI) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapExtendedNexthop) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Tuples []*CapExtendedNexthopTuple `json:"tuples"` - }{ - Code: c.Code(), - Tuples: c.Tuples, - }) -} - -func NewCapExtendedNexthop(tuples []*CapExtendedNexthopTuple) *CapExtendedNexthop { - return &CapExtendedNexthop{ - DefaultParameterCapability{ - CapCode: BGP_CAP_EXTENDED_NEXTHOP, - }, - tuples, - } -} - -type CapGracefulRestartTuple struct { - AFI uint16 - SAFI uint8 - Flags uint8 -} - -func (c *CapGracefulRestartTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RouteFamily RouteFamily `json:"route_family"` - Flags uint8 `json:"flags"` - }{ - RouteFamily: AfiSafiToRouteFamily(c.AFI, c.SAFI), - Flags: c.Flags, - }) -} - -func NewCapGracefulRestartTuple(rf RouteFamily, forward bool) *CapGracefulRestartTuple { - afi, safi := RouteFamilyToAfiSafi(rf) - flags := 0 - if forward { - flags = 0x80 - } - return &CapGracefulRestartTuple{ - AFI: afi, - SAFI: safi, - Flags: uint8(flags), - } -} - -type CapGracefulRestart struct { - DefaultParameterCapability - Flags uint8 - Time uint16 - Tuples []*CapGracefulRestartTuple -} - -func (c *CapGracefulRestart) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 2 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityGracefulRestart bytes available") - } - restart := binary.BigEndian.Uint16(data[0:2]) - c.Flags = uint8(restart >> 12) - c.Time = restart & 0xfff - data = data[2:] - - valueLen := int(c.CapLen) - 2 - - if valueLen >= 4 && len(data) >= valueLen { - c.Tuples = make([]*CapGracefulRestartTuple, 0, valueLen/4) - - for i := valueLen; i >= 4; i -= 4 { - t := &CapGracefulRestartTuple{binary.BigEndian.Uint16(data[0:2]), - data[2], data[3]} - c.Tuples = append(c.Tuples, t) - data = data[4:] - } - } - return nil -} - -func (c *CapGracefulRestart) Serialize() ([]byte, error) { - buf := make([]byte, 2) - binary.BigEndian.PutUint16(buf[0:], uint16(c.Flags)<<12|c.Time) - for _, t := range c.Tuples { - tbuf := make([]byte, 4) - binary.BigEndian.PutUint16(tbuf[0:2], t.AFI) - tbuf[2] = t.SAFI - tbuf[3] = t.Flags - buf = append(buf, tbuf...) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapGracefulRestart) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Flags uint8 `json:"flags"` - Time uint16 `json:"time"` - Tuples []*CapGracefulRestartTuple `json:"tuples"` - }{ - Code: c.Code(), - Flags: c.Flags, - Time: c.Time, - Tuples: c.Tuples, - }) -} - -func NewCapGracefulRestart(restarting, notification bool, time uint16, tuples []*CapGracefulRestartTuple) *CapGracefulRestart { - flags := 0 - if restarting { - flags = 0x08 - } - if notification { - flags |= 0x04 - } - return &CapGracefulRestart{ - DefaultParameterCapability: DefaultParameterCapability{ - CapCode: BGP_CAP_GRACEFUL_RESTART, - }, - Flags: uint8(flags), - Time: time, - Tuples: tuples, - } -} - -type CapFourOctetASNumber struct { - DefaultParameterCapability - CapValue uint32 -} - -func (c *CapFourOctetASNumber) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 4 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFourOctetASNumber bytes available") - } - c.CapValue = binary.BigEndian.Uint32(data[0:4]) - return nil -} - -func (c *CapFourOctetASNumber) Serialize() ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, c.CapValue) - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapFourOctetASNumber) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Value uint32 `json:"value"` - }{ - Code: c.Code(), - Value: c.CapValue, - }) -} - -func NewCapFourOctetASNumber(asnum uint32) *CapFourOctetASNumber { - return &CapFourOctetASNumber{ - DefaultParameterCapability{ - CapCode: BGP_CAP_FOUR_OCTET_AS_NUMBER, - }, - asnum, - } -} - -type BGPAddPathMode uint8 - -const ( - 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: - return "send" - case BGP_ADD_PATH_BOTH: - return "receive/send" - default: - return fmt.Sprintf("unknown(%d)", m) - } -} - -type CapAddPathTuple struct { - RouteFamily RouteFamily - Mode BGPAddPathMode -} - -func (t *CapAddPathTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RouteFamily RouteFamily `json:"family"` - Mode uint8 `json:"mode"` - }{ - RouteFamily: t.RouteFamily, - Mode: uint8(t.Mode), - }) -} - -func NewCapAddPathTuple(family RouteFamily, mode BGPAddPathMode) *CapAddPathTuple { - return &CapAddPathTuple{ - RouteFamily: family, - Mode: mode, - } -} - -type CapAddPath struct { - DefaultParameterCapability - Tuples []*CapAddPathTuple -} - -func (c *CapAddPath) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - if len(data) < 4 { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityAddPath bytes available") - } - c.Tuples = []*CapAddPathTuple{} - for len(data) >= 4 { - t := &CapAddPathTuple{ - RouteFamily: AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[:2]), data[2]), - Mode: BGPAddPathMode(data[3]), - } - c.Tuples = append(c.Tuples, t) - data = data[4:] - } - return nil -} - -func (c *CapAddPath) Serialize() ([]byte, error) { - buf := make([]byte, len(c.Tuples)*4) - for i, t := range c.Tuples { - afi, safi := RouteFamilyToAfiSafi(t.RouteFamily) - binary.BigEndian.PutUint16(buf[i*4:i*4+2], afi) - buf[i*4+2] = safi - buf[i*4+3] = byte(t.Mode) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapAddPath) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Tuples []*CapAddPathTuple `json:"tuples"` - }{ - Code: c.Code(), - Tuples: c.Tuples, - }) -} - -func NewCapAddPath(tuples []*CapAddPathTuple) *CapAddPath { - return &CapAddPath{ - DefaultParameterCapability: DefaultParameterCapability{ - CapCode: BGP_CAP_ADD_PATH, - }, - Tuples: tuples, - } -} - -type CapEnhancedRouteRefresh struct { - DefaultParameterCapability -} - -func NewCapEnhancedRouteRefresh() *CapEnhancedRouteRefresh { - return &CapEnhancedRouteRefresh{ - DefaultParameterCapability{ - CapCode: BGP_CAP_ENHANCED_ROUTE_REFRESH, - }, - } -} - -type CapRouteRefreshCisco struct { - DefaultParameterCapability -} - -func NewCapRouteRefreshCisco() *CapRouteRefreshCisco { - return &CapRouteRefreshCisco{ - DefaultParameterCapability{ - CapCode: BGP_CAP_ROUTE_REFRESH_CISCO, - }, - } -} - -type CapLongLivedGracefulRestartTuple struct { - AFI uint16 - SAFI uint8 - Flags uint8 - RestartTime uint32 -} - -func (c *CapLongLivedGracefulRestartTuple) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RouteFamily RouteFamily `json:"route_family"` - Flags uint8 `json:"flags"` - RestartTime uint32 `json:"restart_time"` - }{ - RouteFamily: AfiSafiToRouteFamily(c.AFI, c.SAFI), - Flags: c.Flags, - RestartTime: c.RestartTime, - }) -} - -func NewCapLongLivedGracefulRestartTuple(rf RouteFamily, forward bool, restartTime uint32) *CapLongLivedGracefulRestartTuple { - afi, safi := RouteFamilyToAfiSafi(rf) - flags := 0 - if forward { - flags = 0x80 - } - return &CapLongLivedGracefulRestartTuple{ - AFI: afi, - SAFI: safi, - Flags: uint8(flags), - RestartTime: restartTime, - } -} - -type CapLongLivedGracefulRestart struct { - DefaultParameterCapability - Tuples []*CapLongLivedGracefulRestartTuple -} - -func (c *CapLongLivedGracefulRestart) DecodeFromBytes(data []byte) error { - c.DefaultParameterCapability.DecodeFromBytes(data) - data = data[2:] - - valueLen := int(c.CapLen) - if valueLen%7 != 0 || len(data) < valueLen { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "invalid length of long lived graceful restart capablity") - } - for i := valueLen; i >= 7; i -= 7 { - t := &CapLongLivedGracefulRestartTuple{ - binary.BigEndian.Uint16(data), - data[2], - data[3], - uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]), - } - c.Tuples = append(c.Tuples, t) - data = data[7:] - } - return nil -} - -func (c *CapLongLivedGracefulRestart) Serialize() ([]byte, error) { - buf := make([]byte, 7*len(c.Tuples)) - for idx, t := range c.Tuples { - binary.BigEndian.PutUint16(buf[idx*7:], t.AFI) - buf[idx*7+2] = t.SAFI - buf[idx*7+3] = t.Flags - buf[idx*7+4] = uint8((t.RestartTime >> 16) & 0xff) - buf[idx*7+5] = uint8((t.RestartTime >> 8) & 0xff) - buf[idx*7+6] = uint8(t.RestartTime & 0xff) - } - c.DefaultParameterCapability.CapValue = buf - return c.DefaultParameterCapability.Serialize() -} - -func (c *CapLongLivedGracefulRestart) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Code BGPCapabilityCode `json:"code"` - Tuples []*CapLongLivedGracefulRestartTuple `json:"tuples"` - }{ - Code: c.Code(), - Tuples: c.Tuples, - }) -} - -func NewCapLongLivedGracefulRestart(tuples []*CapLongLivedGracefulRestartTuple) *CapLongLivedGracefulRestart { - return &CapLongLivedGracefulRestart{ - DefaultParameterCapability: DefaultParameterCapability{ - CapCode: BGP_CAP_LONG_LIVED_GRACEFUL_RESTART, - }, - Tuples: tuples, - } -} - -type CapUnknown struct { - DefaultParameterCapability -} - -func NewCapUnknown(code BGPCapabilityCode, value []byte) *CapUnknown { - return &CapUnknown{ - DefaultParameterCapability{ - CapCode: code, - CapValue: value, - }, - } -} - -func DecodeCapability(data []byte) (ParameterCapabilityInterface, error) { - if len(data) < 2 { - return nil, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all ParameterCapability bytes available") - } - var c ParameterCapabilityInterface - switch BGPCapabilityCode(data[0]) { - case BGP_CAP_MULTIPROTOCOL: - c = &CapMultiProtocol{} - case BGP_CAP_ROUTE_REFRESH: - c = &CapRouteRefresh{} - case BGP_CAP_CARRYING_LABEL_INFO: - c = &CapCarryingLabelInfo{} - case BGP_CAP_EXTENDED_NEXTHOP: - c = &CapExtendedNexthop{} - case BGP_CAP_GRACEFUL_RESTART: - c = &CapGracefulRestart{} - case BGP_CAP_FOUR_OCTET_AS_NUMBER: - c = &CapFourOctetASNumber{} - case BGP_CAP_ADD_PATH: - c = &CapAddPath{} - case BGP_CAP_ENHANCED_ROUTE_REFRESH: - c = &CapEnhancedRouteRefresh{} - case BGP_CAP_ROUTE_REFRESH_CISCO: - c = &CapRouteRefreshCisco{} - case BGP_CAP_LONG_LIVED_GRACEFUL_RESTART: - c = &CapLongLivedGracefulRestart{} - default: - c = &CapUnknown{} - } - err := c.DecodeFromBytes(data) - return c, err -} - -type OptionParameterInterface interface { - Serialize() ([]byte, error) -} - -type OptionParameterCapability struct { - ParamType uint8 - ParamLen uint8 - Capability []ParameterCapabilityInterface -} - -func (o *OptionParameterCapability) DecodeFromBytes(data []byte) error { - if uint8(len(data)) < o.ParamLen { - return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_OPTIONAL_PARAMETER, nil, "Not all OptionParameterCapability bytes available") - } - for len(data) >= 2 { - c, err := DecodeCapability(data) - if err != nil { - return err - } - o.Capability = append(o.Capability, c) - data = data[c.Len():] - } - return nil -} - -func (o *OptionParameterCapability) Serialize() ([]byte, error) { - buf := make([]byte, 2) - buf[0] = o.ParamType - for _, p := range o.Capability { - pbuf, err := p.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - o.ParamLen = uint8(len(buf) - 2) - buf[1] = o.ParamLen - return buf, nil -} - -func NewOptionParameterCapability(capability []ParameterCapabilityInterface) *OptionParameterCapability { - return &OptionParameterCapability{ - ParamType: BGP_OPT_CAPABILITY, - Capability: capability, - } -} - -type OptionParameterUnknown struct { - ParamType uint8 - ParamLen uint8 - Value []byte -} - -func (o *OptionParameterUnknown) Serialize() ([]byte, error) { - buf := make([]byte, 2) - buf[0] = o.ParamType - if o.ParamLen == 0 { - o.ParamLen = uint8(len(o.Value)) - } - buf[1] = o.ParamLen - return append(buf, o.Value...), nil -} - -type BGPOpen struct { - Version uint8 - MyAS uint16 - HoldTime uint16 - ID net.IP - OptParamLen uint8 - OptParams []OptionParameterInterface -} - -func (msg *BGPOpen) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if len(data) < 10 { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP Open message bytes available") - } - msg.Version = data[0] - msg.MyAS = binary.BigEndian.Uint16(data[1:3]) - msg.HoldTime = binary.BigEndian.Uint16(data[3:5]) - msg.ID = net.IP(data[5:9]).To4() - msg.OptParamLen = data[9] - data = data[10:] - if len(data) < int(msg.OptParamLen) { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP Open message bytes available") - } - - msg.OptParams = []OptionParameterInterface{} - for rest := msg.OptParamLen; rest > 0; { - if rest < 2 { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Malformed BGP Open message") - } - paramtype := data[0] - paramlen := data[1] - if rest < paramlen+2 { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Malformed BGP Open message") - } - rest -= paramlen + 2 - - if paramtype == BGP_OPT_CAPABILITY { - p := &OptionParameterCapability{} - p.ParamType = paramtype - p.ParamLen = paramlen - p.DecodeFromBytes(data[2 : 2+paramlen]) - msg.OptParams = append(msg.OptParams, p) - } else { - p := &OptionParameterUnknown{} - p.ParamType = paramtype - p.ParamLen = paramlen - p.Value = data[2 : 2+paramlen] - msg.OptParams = append(msg.OptParams, p) - } - data = data[2+paramlen:] - } - return nil -} - -func (msg *BGPOpen) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 10) - buf[0] = msg.Version - binary.BigEndian.PutUint16(buf[1:3], msg.MyAS) - binary.BigEndian.PutUint16(buf[3:5], msg.HoldTime) - copy(buf[5:9], msg.ID.To4()) - pbuf := make([]byte, 0) - for _, p := range msg.OptParams { - onepbuf, err := p.Serialize() - if err != nil { - return nil, err - } - pbuf = append(pbuf, onepbuf...) - } - msg.OptParamLen = uint8(len(pbuf)) - buf[9] = msg.OptParamLen - return append(buf, pbuf...), nil -} - -func NewBGPOpenMessage(myas uint16, holdtime uint16, id string, optparams []OptionParameterInterface) *BGPMessage { - return &BGPMessage{ - Header: BGPHeader{Type: BGP_MSG_OPEN}, - Body: &BGPOpen{4, myas, holdtime, net.ParseIP(id).To4(), 0, optparams}, - } -} - -type AddrPrefixInterface interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) - AFI() uint16 - SAFI() uint8 - 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) - PathLocalIdentifier() uint32 - SetPathLocalIdentifier(uint32) -} - -func LabelString(nlri AddrPrefixInterface) string { - label := "" - switch n := nlri.(type) { - case *LabeledIPAddrPrefix: - label = n.Labels.String() - case *LabeledIPv6AddrPrefix: - label = n.Labels.String() - case *LabeledVPNIPAddrPrefix: - label = n.Labels.String() - case *LabeledVPNIPv6AddrPrefix: - label = n.Labels.String() - case *EVPNNLRI: - switch route := n.RouteTypeData.(type) { - case *EVPNEthernetAutoDiscoveryRoute: - label = fmt.Sprintf("[%d]", route.Label) - case *EVPNMacIPAdvertisementRoute: - var l []string - for _, i := range route.Labels { - l = append(l, strconv.Itoa(int(i))) - } - label = fmt.Sprintf("[%s]", strings.Join(l, ",")) - case *EVPNIPPrefixRoute: - label = fmt.Sprintf("[%d]", route.Label) - } - } - return label -} - -type PrefixDefault struct { - id uint32 - localId uint32 -} - -func (p *PrefixDefault) PathIdentifier() uint32 { - return p.id -} - -func (p *PrefixDefault) SetPathIdentifier(id uint32) { - p.id = id -} - -func (p *PrefixDefault) PathLocalIdentifier() uint32 { - return p.localId -} - -func (p *PrefixDefault) SetPathLocalIdentifier(id uint32) { - p.localId = 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.PathLocalIdentifier()) - return buf, nil -} - -type IPAddrPrefixDefault struct { - PrefixDefault - Length uint8 - Prefix net.IP -} - -func (r *IPAddrPrefixDefault) decodePrefix(data []byte, bitlen uint8, addrlen uint8) error { - bytelen := (int(bitlen) + 7) / 8 - if len(data) < bytelen { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "network bytes is short") - } - b := make([]byte, addrlen) - copy(b, data[:bytelen]) - // clear trailing bits in the last byte. rfc doesn't require - // this but some bgp implementations need this... - rem := bitlen % 8 - if rem != 0 { - mask := 0xff00 >> rem - lastByte := b[bytelen-1] & byte(mask) - b[bytelen-1] = lastByte - } - r.Prefix = b - return nil -} - -func (r *IPAddrPrefixDefault) serializePrefix(bitLen uint8) ([]byte, error) { - byteLen := (int(bitLen) + 7) / 8 - buf := make([]byte, byteLen) - copy(buf, r.Prefix) - return buf, nil -} - -func (r *IPAddrPrefixDefault) String() string { - return fmt.Sprintf("%s/%d", r.Prefix.String(), r.Length) -} - -func (r *IPAddrPrefixDefault) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Prefix string `json:"prefix"` - }{ - Prefix: r.String(), - }) -} - -type IPAddrPrefix struct { - IPAddrPrefixDefault - addrlen uint8 -} - -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 IsAddPathEnabled(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] - return r.decodePrefix(data[1:], r.Length, r.addrlen) -} - -func (r *IPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - f := RF_IPv4_UC - if r.addrlen == 16 { - f = RF_IPv6_UC - } - var buf []byte - if IsAddPathEnabled(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 - } - return append(buf, pbuf...), nil -} - -func (r *IPAddrPrefix) AFI() uint16 { - return AFI_IP -} - -func (r *IPAddrPrefix) SAFI() uint8 { - return SAFI_UNICAST -} - -func (r *IPAddrPrefix) Len(options ...*MarshallingOption) int { - return 1 + ((int(r.Length) + 7) / 8) -} - -func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix { - p := &IPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length, - }, - 4, - } - p.IPAddrPrefixDefault.decodePrefix(net.ParseIP(prefix).To4(), length, 4) - return p -} - -func isIPv4MappedIPv6(ip net.IP) bool { - return len(ip) == net.IPv6len && ip.To4() != nil -} - -type IPv6AddrPrefix struct { - IPAddrPrefix -} - -func (r *IPv6AddrPrefix) AFI() uint16 { - return AFI_IP6 -} - -func (r *IPv6AddrPrefix) String() string { - prefix := r.Prefix.String() - if isIPv4MappedIPv6(r.Prefix) { - prefix = "::ffff:" + prefix - } - return fmt.Sprintf("%s/%d", prefix, r.Length) -} - -func NewIPv6AddrPrefix(length uint8, prefix string) *IPv6AddrPrefix { - p := &IPv6AddrPrefix{ - IPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length, - }, - 16, - }, - } - p.IPAddrPrefixDefault.decodePrefix(net.ParseIP(prefix), length, 16) - return p -} - -const ( - BGP_RD_TWO_OCTET_AS = iota - BGP_RD_IPV4_ADDRESS - BGP_RD_FOUR_OCTET_AS -) - -type RouteDistinguisherInterface interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - Len() int - String() string - MarshalJSON() ([]byte, error) -} - -type DefaultRouteDistinguisher struct { - Type uint16 -} - -func (rd *DefaultRouteDistinguisher) serialize(value []byte) ([]byte, error) { - buf := make([]byte, 8) - binary.BigEndian.PutUint16(buf, rd.Type) - copy(buf[2:], value) - return buf, nil -} - -func (rd *DefaultRouteDistinguisher) Len() int { - return 8 -} - -type RouteDistinguisherTwoOctetAS struct { - DefaultRouteDistinguisher - Admin uint16 - Assigned uint32 -} - -func (rd *RouteDistinguisherTwoOctetAS) DecodeFromBytes(data []byte) error { - rd.Admin = binary.BigEndian.Uint16(data[0:2]) - rd.Assigned = binary.BigEndian.Uint32(data[2:6]) - return nil -} - -func (rd *RouteDistinguisherTwoOctetAS) Serialize() ([]byte, error) { - buf := make([]byte, 6) - binary.BigEndian.PutUint16(buf[0:2], rd.Admin) - binary.BigEndian.PutUint32(buf[2:6], rd.Assigned) - return rd.serialize(buf) -} - -func (rd *RouteDistinguisherTwoOctetAS) String() string { - return fmt.Sprintf("%d:%d", rd.Admin, rd.Assigned) -} - -func (rd *RouteDistinguisherTwoOctetAS) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Admin uint16 `json:"admin"` - Assigned uint32 `json:"assigned"` - }{ - Type: rd.Type, - Admin: rd.Admin, - Assigned: rd.Assigned, - }) -} - -func NewRouteDistinguisherTwoOctetAS(admin uint16, assigned uint32) *RouteDistinguisherTwoOctetAS { - return &RouteDistinguisherTwoOctetAS{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: BGP_RD_TWO_OCTET_AS, - }, - Admin: admin, - Assigned: assigned, - } -} - -type RouteDistinguisherIPAddressAS struct { - DefaultRouteDistinguisher - Admin net.IP - Assigned uint16 -} - -func (rd *RouteDistinguisherIPAddressAS) DecodeFromBytes(data []byte) error { - rd.Admin = data[0:4] - rd.Assigned = binary.BigEndian.Uint16(data[4:6]) - return nil -} - -func (rd *RouteDistinguisherIPAddressAS) Serialize() ([]byte, error) { - buf := make([]byte, 6) - copy(buf[0:4], rd.Admin.To4()) - binary.BigEndian.PutUint16(buf[4:6], rd.Assigned) - return rd.serialize(buf) -} - -func (rd *RouteDistinguisherIPAddressAS) String() string { - return fmt.Sprintf("%s:%d", rd.Admin.String(), rd.Assigned) -} - -func (rd *RouteDistinguisherIPAddressAS) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Admin string `json:"admin"` - Assigned uint16 `json:"assigned"` - }{ - Type: rd.Type, - Admin: rd.Admin.String(), - Assigned: rd.Assigned, - }) -} - -func NewRouteDistinguisherIPAddressAS(admin string, assigned uint16) *RouteDistinguisherIPAddressAS { - return &RouteDistinguisherIPAddressAS{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: BGP_RD_IPV4_ADDRESS, - }, - Admin: net.ParseIP(admin).To4(), - Assigned: assigned, - } -} - -type RouteDistinguisherFourOctetAS struct { - DefaultRouteDistinguisher - Admin uint32 - Assigned uint16 -} - -func (rd *RouteDistinguisherFourOctetAS) DecodeFromBytes(data []byte) error { - rd.Admin = binary.BigEndian.Uint32(data[0:4]) - rd.Assigned = binary.BigEndian.Uint16(data[4:6]) - return nil -} - -func (rd *RouteDistinguisherFourOctetAS) Serialize() ([]byte, error) { - buf := make([]byte, 6) - binary.BigEndian.PutUint32(buf[0:4], rd.Admin) - binary.BigEndian.PutUint16(buf[4:6], rd.Assigned) - return rd.serialize(buf) -} - -func (rd *RouteDistinguisherFourOctetAS) String() string { - fst := rd.Admin >> 16 & 0xffff - snd := rd.Admin & 0xffff - return fmt.Sprintf("%d.%d:%d", fst, snd, rd.Assigned) -} - -func (rd *RouteDistinguisherFourOctetAS) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Admin uint32 `json:"admin"` - Assigned uint16 `json:"assigned"` - }{ - Type: rd.Type, - Admin: rd.Admin, - Assigned: rd.Assigned, - }) -} - -func NewRouteDistinguisherFourOctetAS(admin uint32, assigned uint16) *RouteDistinguisherFourOctetAS { - return &RouteDistinguisherFourOctetAS{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: BGP_RD_FOUR_OCTET_AS, - }, - Admin: admin, - Assigned: assigned, - } -} - -type RouteDistinguisherUnknown struct { - DefaultRouteDistinguisher - Value []byte -} - -func (rd *RouteDistinguisherUnknown) DecodeFromBytes(data []byte) error { - rd.Value = data[0:6] - return nil -} - -func (rd *RouteDistinguisherUnknown) Serialize() ([]byte, error) { - return rd.DefaultRouteDistinguisher.serialize(rd.Value) -} - -func (rd *RouteDistinguisherUnknown) String() string { - return fmt.Sprintf("%v", rd.Value) -} - -func (rd *RouteDistinguisherUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint16 `json:"type"` - Value []byte `json:"value"` - }{ - Type: rd.Type, - Value: rd.Value, - }) -} - -func GetRouteDistinguisher(data []byte) RouteDistinguisherInterface { - typ := binary.BigEndian.Uint16(data[0:2]) - switch typ { - case BGP_RD_TWO_OCTET_AS: - return NewRouteDistinguisherTwoOctetAS(binary.BigEndian.Uint16(data[2:4]), binary.BigEndian.Uint32(data[4:8])) - case BGP_RD_IPV4_ADDRESS: - return NewRouteDistinguisherIPAddressAS(net.IP(data[2:6]).String(), binary.BigEndian.Uint16(data[6:8])) - case BGP_RD_FOUR_OCTET_AS: - return NewRouteDistinguisherFourOctetAS(binary.BigEndian.Uint32(data[2:6]), binary.BigEndian.Uint16(data[6:8])) - } - rd := &RouteDistinguisherUnknown{ - DefaultRouteDistinguisher: DefaultRouteDistinguisher{ - Type: typ, - }, - } - return rd -} - -func parseRdAndRt(input string) ([]string, error) { - elems := _regexpRouteDistinguisher.FindStringSubmatch(input) - if len(elems) != 11 { - return nil, fmt.Errorf("failed to parse") - } - return elems, nil -} - -func ParseRouteDistinguisher(rd string) (RouteDistinguisherInterface, error) { - elems, err := parseRdAndRt(rd) - if err != nil { - return nil, err - } - assigned, _ := strconv.ParseUint(elems[10], 10, 32) - ip := net.ParseIP(elems[1]) - switch { - case ip.To4() != nil: - return NewRouteDistinguisherIPAddressAS(elems[1], uint16(assigned)), nil - case elems[6] == "" && elems[7] == "": - asn, _ := strconv.ParseUint(elems[8], 10, 16) - return NewRouteDistinguisherTwoOctetAS(uint16(asn), uint32(assigned)), nil - default: - fst, _ := strconv.ParseUint(elems[7], 10, 16) - snd, _ := strconv.ParseUint(elems[8], 10, 16) - asn := fst<<16 | snd - return NewRouteDistinguisherFourOctetAS(uint32(asn), uint16(assigned)), nil - } -} - -// -// RFC3107 Carrying Label Information in BGP-4 -// -// 3. Carrying Label Mapping Information -// -// b) Label: -// -// The Label field carries one or more labels (that corresponds to -// the stack of labels [MPLS-ENCAPS(RFC3032)]). Each label is encoded as -// 4 octets, where the high-order 20 bits contain the label value, and -// the low order bit contains "Bottom of Stack" -// -// RFC3032 MPLS Label Stack Encoding -// -// 2.1. Encoding the Label Stack -// -// 0 1 2 3 -// 0 ... 9 0 ... 9 0 1 2 3 4 ... 9 0 1 -// +-----+-+-+---+-+-+-+-+-+-----+-+-+-+ -// | Label | Exp |S| TTL | -// +-----+-+-+---+-+-+-+-+-+-----+-+-+-+ -// - -// RFC3107 Carrying Label Information in BGP-4 -// -// 3. Carrying Label Mapping Information -// -// The label information carried (as part of NLRI) in the Withdrawn -// Routes field should be set to 0x800000. -const WITHDRAW_LABEL = uint32(0x800000) -const ZERO_LABEL = uint32(0) // some platform uses this as withdraw label - -type MPLSLabelStack struct { - Labels []uint32 -} - -func (l *MPLSLabelStack) DecodeFromBytes(data []byte) error { - labels := []uint32{} - foundBottom := false - for len(data) >= 3 { - label := uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]) - if label == WITHDRAW_LABEL || label == ZERO_LABEL { - l.Labels = []uint32{label} - return nil - } - data = data[3:] - labels = append(labels, label>>4) - if label&1 == 1 { - foundBottom = true - break - } - } - - if !foundBottom { - l.Labels = []uint32{} - return nil - } - l.Labels = labels - return nil -} - -func (l *MPLSLabelStack) Serialize() ([]byte, error) { - buf := make([]byte, len(l.Labels)*3) - for i, label := range l.Labels { - if label == WITHDRAW_LABEL { - return []byte{128, 0, 0}, nil - } - label = label << 4 - buf[i*3] = byte((label >> 16) & 0xff) - buf[i*3+1] = byte((label >> 8) & 0xff) - buf[i*3+2] = byte(label & 0xff) - } - buf[len(buf)-1] |= 1 - return buf, nil -} - -func (l *MPLSLabelStack) Len() int { return 3 * len(l.Labels) } - -func (l *MPLSLabelStack) String() string { - if len(l.Labels) == 0 { - return "" - } - s := bytes.NewBuffer(make([]byte, 0, 64)) - s.WriteString("[") - ss := make([]string, 0, len(l.Labels)) - for _, label := range l.Labels { - ss = append(ss, fmt.Sprintf("%d", label)) - } - s.WriteString(strings.Join(ss, ", ")) - s.WriteString("]") - return s.String() -} - -func NewMPLSLabelStack(labels ...uint32) *MPLSLabelStack { - if len(labels) == 0 { - labels = []uint32{0} - } - return &MPLSLabelStack{labels} -} - -func ParseMPLSLabelStack(buf string) (*MPLSLabelStack, error) { - elems := strings.Split(buf, "/") - labels := make([]uint32, 0, len(elems)) - if len(elems) == 0 { - goto ERR - } - for _, elem := range elems { - i, err := strconv.ParseUint(elem, 10, 32) - if err != nil { - goto ERR - } - if i > ((1 << 20) - 1) { - goto ERR - } - labels = append(labels, uint32(i)) - } - return NewMPLSLabelStack(labels...), nil -ERR: - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "invalid mpls label stack format") -} - -// -// RFC3107 Carrying Label Information in BGP-4 -// -// 3. Carrying Label Mapping Information -// -// +----------------------+ -// | Length (1 octet) | -// +----------------------+ -// | Label (3 octets) | -// +----------------------+ -// ....................... -// +----------------------+ -// | Prefix (variable) | -// +----------------------+ -// -// RFC4364 BGP/MPLS IP VPNs -// -// 4.3.4. How VPN-IPv4 NLRI Is Carried in BGP -// -// The labeled VPN-IPv4 NLRI itself is encoded as specified in -// [MPLS-BGP(RFC3107)], where the prefix consists of an 8-byte RD -// followed by an IPv4 prefix. -// - -type LabeledVPNIPAddrPrefix struct { - IPAddrPrefixDefault - Labels MPLSLabelStack - RD RouteDistinguisherInterface - addrlen uint8 -} - -func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - f := RF_IPv4_VPN - if l.addrlen == 16 { - f = RF_IPv6_VPN - } - if IsAddPathEnabled(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) - if int(l.Length)-8*(l.Labels.Len()) < 0 { - l.Labels.Labels = []uint32{} - } - data = data[l.Labels.Len():] - l.RD = GetRouteDistinguisher(data) - data = data[l.RD.Len():] - restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len()) - return l.decodePrefix(data, uint8(restbits), l.addrlen) -} - -func (l *LabeledVPNIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - f := RF_IPv4_VPN - if l.addrlen == 16 { - f = RF_IPv6_VPN - } - var buf []byte - if IsAddPathEnabled(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 - } - buf = append(buf, lbuf...) - rbuf, err := l.RD.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, rbuf...) - restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len()) - pbuf, err := l.serializePrefix(uint8(restbits)) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - return buf, nil -} - -func (l *LabeledVPNIPAddrPrefix) AFI() uint16 { - return AFI_IP -} - -func (l *LabeledVPNIPAddrPrefix) SAFI() uint8 { - return SAFI_MPLS_VPN -} - -func (l *LabeledVPNIPAddrPrefix) IPPrefixLen() uint8 { - return l.Length - 8*uint8(l.Labels.Len()+l.RD.Len()) -} - -func (l *LabeledVPNIPAddrPrefix) Len(options ...*MarshallingOption) int { - return 1 + l.Labels.Len() + l.RD.Len() + int((l.IPPrefixLen()+7)/8) -} - -func (l *LabeledVPNIPAddrPrefix) String() string { - return fmt.Sprintf("%s:%s", l.RD, l.IPPrefix()) -} - -func (l *LabeledVPNIPAddrPrefix) IPPrefix() string { - masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len())) - return fmt.Sprintf("%s/%d", l.IPAddrPrefixDefault.Prefix, masklen) -} - -func (l *LabeledVPNIPAddrPrefix) MarshalJSON() ([]byte, error) { - masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len())) - return json.Marshal(struct { - Prefix string `json:"prefix"` - Labels []uint32 `json:"labels"` - RD RouteDistinguisherInterface `json:"rd"` - }{ - Prefix: fmt.Sprintf("%s/%d", l.IPAddrPrefixDefault.Prefix, masklen), - Labels: l.Labels.Labels, - RD: l.RD, - }) -} - -func NewLabeledVPNIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack, rd RouteDistinguisherInterface) *LabeledVPNIPAddrPrefix { - rdlen := 0 - if rd != nil { - rdlen = rd.Len() - } - return &LabeledVPNIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(8*(label.Len()+rdlen)), - Prefix: net.ParseIP(prefix).To4(), - }, - label, - rd, - 4, - } -} - -type LabeledVPNIPv6AddrPrefix struct { - LabeledVPNIPAddrPrefix -} - -func (l *LabeledVPNIPv6AddrPrefix) AFI() uint16 { - return AFI_IP6 -} - -func NewLabeledVPNIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack, rd RouteDistinguisherInterface) *LabeledVPNIPv6AddrPrefix { - rdlen := 0 - if rd != nil { - rdlen = rd.Len() - } - return &LabeledVPNIPv6AddrPrefix{ - LabeledVPNIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(8*(label.Len()+rdlen)), - Prefix: net.ParseIP(prefix), - }, - label, - rd, - 16, - }, - } -} - -type LabeledIPAddrPrefix struct { - IPAddrPrefixDefault - Labels MPLSLabelStack - addrlen uint8 -} - -func (r *LabeledIPAddrPrefix) AFI() uint16 { - return AFI_IP -} - -func (r *LabeledIPAddrPrefix) SAFI() uint8 { - return SAFI_MPLS_LABEL -} - -func (l *LabeledIPAddrPrefix) IPPrefixLen() uint8 { - return l.Length - 8*uint8(l.Labels.Len()) -} - -func (l *LabeledIPAddrPrefix) Len(options ...*MarshallingOption) int { - return 1 + l.Labels.Len() + int((l.IPPrefixLen()+7)/8) -} - -func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - f := RF_IPv4_MPLS - if l.addrlen == 16 { - f = RF_IPv6_MPLS - } - if IsAddPathEnabled(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) - - if int(l.Length)-8*(l.Labels.Len()) < 0 { - l.Labels.Labels = []uint32{} - } - restbits := int(l.Length) - 8*(l.Labels.Len()) - data = data[l.Labels.Len():] - return l.decodePrefix(data, uint8(restbits), l.addrlen) -} - -func (l *LabeledIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - f := RF_IPv4_MPLS - if l.addrlen == 16 { - f = RF_IPv6_MPLS - } - var buf []byte - if IsAddPathEnabled(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 { - return nil, err - } - buf = append(buf, lbuf...) - pbuf, err := l.serializePrefix(uint8(restbits)) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - return buf, nil -} - -func (l *LabeledIPAddrPrefix) String() string { - prefix := l.Prefix.String() - if isIPv4MappedIPv6(l.Prefix) { - prefix = "::ffff:" + prefix - } - return fmt.Sprintf("%s/%d", prefix, int(l.Length)-l.Labels.Len()*8) -} - -func (l *LabeledIPAddrPrefix) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Prefix string `json:"prefix"` - Labels []uint32 `json:"labels"` - }{ - Prefix: l.String(), - Labels: l.Labels.Labels, - }) -} - -func NewLabeledIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPAddrPrefix { - return &LabeledIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(label.Len()*8), - Prefix: net.ParseIP(prefix).To4(), - }, - label, - 4, - } -} - -type LabeledIPv6AddrPrefix struct { - LabeledIPAddrPrefix -} - -func (l *LabeledIPv6AddrPrefix) AFI() uint16 { - return AFI_IP6 -} - -func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPv6AddrPrefix { - return &LabeledIPv6AddrPrefix{ - LabeledIPAddrPrefix{ - IPAddrPrefixDefault{ - Length: length + uint8(label.Len()*8), - Prefix: net.ParseIP(prefix), - }, - label, - 16, - }, - } -} - -type RouteTargetMembershipNLRI struct { - PrefixDefault - Length uint8 - AS uint32 - RouteTarget ExtendedCommunityInterface -} - -func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if IsAddPathEnabled(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 : n.Length/8+1] - if len(data) == 0 { - return nil - } else if len(data) != 12 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all RouteTargetMembershipNLRI bytes available") - } - n.AS = binary.BigEndian.Uint32(data[0:4]) - rt, err := ParseExtended(data[4:]) - n.RouteTarget = rt - if err != nil { - return err - } - return nil -} - -func (n *RouteTargetMembershipNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - if IsAddPathEnabled(false, RF_RTC_UC, options) { - var err error - buf, err = n.serializeIdentifier() - if err != nil { - return nil, err - } - } - if n.RouteTarget == nil { - return append(buf, 0), nil - } - offset := len(buf) - buf = append(buf, make([]byte, 5)...) - buf[offset] = 96 - binary.BigEndian.PutUint32(buf[offset+1:], n.AS) - ebuf, err := n.RouteTarget.Serialize() - if err != nil { - return nil, err - } - return append(buf, ebuf...), nil -} - -func (n *RouteTargetMembershipNLRI) AFI() uint16 { - return AFI_IP -} - -func (n *RouteTargetMembershipNLRI) SAFI() uint8 { - return SAFI_ROUTE_TARGET_CONSTRAINTS -} - -func (n *RouteTargetMembershipNLRI) Len(options ...*MarshallingOption) int { - if n.AS == 0 && n.RouteTarget == nil { - return 1 - } - return 13 -} - -func (n *RouteTargetMembershipNLRI) String() string { - target := "default" - if n.RouteTarget != nil { - target = n.RouteTarget.String() - } - return fmt.Sprintf("%d:%s", n.AS, target) -} - -func (n *RouteTargetMembershipNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Prefix string `json:"prefix"` - }{ - Prefix: n.String(), - }) -} - -func NewRouteTargetMembershipNLRI(as uint32, target ExtendedCommunityInterface) *RouteTargetMembershipNLRI { - l := 12 * 8 - if as == 0 && target == nil { - l = 1 - } - return &RouteTargetMembershipNLRI{ - Length: uint8(l), - AS: as, - RouteTarget: target, - } -} - -type ESIType uint8 - -const ( - ESI_ARBITRARY ESIType = iota - ESI_LACP - ESI_MSTP - ESI_MAC - ESI_ROUTERID - ESI_AS -) - -type EthernetSegmentIdentifier struct { - Type ESIType - Value []byte -} - -func (esi *EthernetSegmentIdentifier) DecodeFromBytes(data []byte) error { - esi.Type = ESIType(data[0]) - esi.Value = data[1:10] - switch esi.Type { - case ESI_LACP, ESI_MSTP, ESI_ROUTERID, ESI_AS: - if esi.Value[8] != 0x00 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid %s. last octet must be 0x00 (0x%02x)", esi.Type.String(), esi.Value[8])) - } - } - return nil -} - -func (esi *EthernetSegmentIdentifier) Serialize() ([]byte, error) { - buf := make([]byte, 10) - buf[0] = uint8(esi.Type) - copy(buf[1:], esi.Value) - return buf, nil -} - -func isZeroBuf(buf []byte) bool { - for _, b := range buf { - if b != 0 { - return false - } - } - return true -} - -func (esi *EthernetSegmentIdentifier) String() string { - toHexArray := func(data []byte) string { - // Converts byte slice into the colon separated hex values and the - // number of elements are 9 at most (excluding Type field). - values := make([]string, 0, 9) - for _, v := range data { - values = append(values, fmt.Sprintf("%02x", v)) - } - return strings.Join(values, ":") - } - - s := bytes.NewBuffer(make([]byte, 0, 64)) - s.WriteString(fmt.Sprintf("%s | ", esi.Type.String())) - switch esi.Type { - case ESI_LACP: - s.WriteString(fmt.Sprintf("system mac %s, ", net.HardwareAddr(esi.Value[:6]).String())) - s.WriteString(fmt.Sprintf("port key %d", binary.BigEndian.Uint16(esi.Value[6:8]))) - case ESI_MSTP: - s.WriteString(fmt.Sprintf("bridge mac %s, ", net.HardwareAddr(esi.Value[:6]).String())) - s.WriteString(fmt.Sprintf("priority %d", binary.BigEndian.Uint16(esi.Value[6:8]))) - case ESI_MAC: - s.WriteString(fmt.Sprintf("system mac %s, ", net.HardwareAddr(esi.Value[:6]).String())) - s.WriteString(fmt.Sprintf("local discriminator %d", uint32(esi.Value[6])<<16|uint32(esi.Value[7])<<8|uint32(esi.Value[8]))) - case ESI_ROUTERID: - s.WriteString(fmt.Sprintf("router id %s, ", net.IP(esi.Value[:4]))) - s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8]))) - case ESI_AS: - s.WriteString(fmt.Sprintf("as %d, ", binary.BigEndian.Uint32(esi.Value[:4]))) - s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8]))) - case ESI_ARBITRARY: - if isZeroBuf(esi.Value) { - return "single-homed" - } - fallthrough - default: - s.WriteString(toHexArray(esi.Value)) - } - return s.String() -} - -// Decode Ethernet Segment Identifier (ESI) from string slice. -// -// The first element of args should be the Type field (e.g., "ARBITRARY", -// "arbitrary", "ESI_ARBITRARY" or "esi_arbitrary") and "single-homed" is -// the special keyword for all zeroed ESI. -// For the "ARBITRARY" Value field (Type 0), it should be the colon separated -// hex values and the number of elements should be 9 at most. -// e.g.) args := []string{"ARBITRARY", "11:22:33:44:55:66:77:88:99"} -// For the other types, the Value field format is the similar to the string -// format of ESI. -// e.g.) args := []string{"lacp", "aa:bb:cc:dd:ee:ff", "100"} -func ParseEthernetSegmentIdentifier(args []string) (EthernetSegmentIdentifier, error) { - esi := EthernetSegmentIdentifier{} - argLen := len(args) - if argLen == 0 || args[0] == "single-homed" { - return esi, nil - } - - typeStr := strings.TrimPrefix(strings.ToUpper(args[0]), "ESI_") - switch typeStr { - case "ARBITRARY": - esi.Type = ESI_ARBITRARY - case "LACP": - esi.Type = ESI_LACP - case "MSTP": - esi.Type = ESI_MSTP - case "MAC": - esi.Type = ESI_MAC - case "ROUTERID": - esi.Type = ESI_ROUTERID - case "AS": - esi.Type = ESI_AS - default: - typ, err := strconv.ParseUint(args[0], 10, 8) - if err != nil { - return esi, fmt.Errorf("invalid esi type: %s", args[0]) - } - esi.Type = ESIType(typ) - } - - invalidEsiValuesError := fmt.Errorf("invalid esi values for type %s: %s", esi.Type.String(), args[1:]) - esi.Value = make([]byte, 9) - switch esi.Type { - case ESI_LACP: - fallthrough - case ESI_MSTP: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // MAC - mac, err := net.ParseMAC(args[1]) - if err != nil { - return esi, invalidEsiValuesError - } - copy(esi.Value[0:6], mac) - // Port Key or Bridge Priority - i, err := strconv.ParseUint(args[2], 10, 16) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint16(esi.Value[6:8], uint16(i)) - case ESI_MAC: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // MAC - mac, err := net.ParseMAC(args[1]) - if err != nil { - return esi, invalidEsiValuesError - } - copy(esi.Value[0:6], mac) - // Local Discriminator - i, err := strconv.ParseUint(args[2], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - iBuf := make([]byte, 4) - binary.BigEndian.PutUint32(iBuf, uint32(i)) - copy(esi.Value[6:9], iBuf[1:4]) - case ESI_ROUTERID: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // Router ID - ip := net.ParseIP(args[1]) - if ip == nil || ip.To4() == nil { - return esi, invalidEsiValuesError - } - copy(esi.Value[0:4], ip.To4()) - // Local Discriminator - i, err := strconv.ParseUint(args[2], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint32(esi.Value[4:8], uint32(i)) - case ESI_AS: - if argLen < 3 { - return esi, invalidEsiValuesError - } - // AS - as, err := strconv.ParseUint(args[1], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint32(esi.Value[0:4], uint32(as)) - // Local Discriminator - i, err := strconv.ParseUint(args[2], 10, 32) - if err != nil { - return esi, invalidEsiValuesError - } - binary.BigEndian.PutUint32(esi.Value[4:8], uint32(i)) - case ESI_ARBITRARY: - fallthrough - default: - if argLen < 2 { - // Assumes the Value field is omitted - break - } - values := make([]byte, 0, 9) - for _, e := range strings.SplitN(args[1], ":", 9) { - v, err := strconv.ParseUint(e, 16, 16) - if err != nil { - return esi, invalidEsiValuesError - } - values = append(values, byte(v)) - } - copy(esi.Value, values) - } - - return esi, nil -} - -// -// I-D bess-evpn-overlay-01 -// -// 5.1.3 Constructing EVPN BGP Routes -// -// For the balance of this memo, the MPLS label field will be -// referred to as the VNI/VSID field. The VNI/VSID field is used for -// both local and global VNIs/VSIDs, and for either case the entire 24- -// bit field is used to encode the VNI/VSID value. -// -// We can't use type MPLSLabelStack for EVPN NLRI, because EVPN NLRI's MPLS -// field can be filled with VXLAN VNI. In that case, we must avoid modifying -// bottom of stack bit. -// - -func labelDecode(data []byte) (uint32, error) { - if len(data) < 3 { - return 0, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all Label bytes available") - } - return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]), nil -} - -func labelSerialize(label uint32) ([]byte, error) { - if label > 0xffffff { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Out of range Label: %d", label)) - } - buf := make([]byte, 3) - buf[0] = byte((label >> 16) & 0xff) - buf[1] = byte((label >> 8) & 0xff) - buf[2] = byte(label & 0xff) - return buf, nil -} - -type EVPNEthernetAutoDiscoveryRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - ETag uint32 - Label uint32 -} - -func (er *EVPNEthernetAutoDiscoveryRoute) Len() int { - // RD(8) + ESI(10) + ETag(4) + Label(3) - return 25 -} - -func (er *EVPNEthernetAutoDiscoveryRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - data = data[er.RD.Len():] - err := er.ESI.DecodeFromBytes(data) - if err != nil { - return err - } - data = data[10:] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - data = data[4:] - if er.Label, err = labelDecode(data); err != nil { - return err - } - return nil -} - -func (er *EVPNEthernetAutoDiscoveryRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - - tbuf = make([]byte, 4) - binary.BigEndian.PutUint32(tbuf, er.ETag) - buf = append(buf, tbuf...) - - tbuf, err = labelSerialize(er.Label) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - - return buf, nil -} - -func (er *EVPNEthernetAutoDiscoveryRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.1. Ethernet Auto-discovery Route - // For the purpose of BGP route key processing, only the Ethernet - // Segment Identifier and the Ethernet Tag ID are considered to be part - // of the prefix in the NLRI. The MPLS Label field is to be treated as - // a route attribute as opposed to being part of the route. - return fmt.Sprintf("[type:A-D][rd:%s][esi:%s][etag:%d]", er.RD, er.ESI.String(), er.ETag) -} - -func (er *EVPNEthernetAutoDiscoveryRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - Etag uint32 `json:"etag"` - Label uint32 `json:"label"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - Etag: er.ETag, - Label: er.Label, - }) -} - -func (er *EVPNEthernetAutoDiscoveryRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNEthernetAutoDiscoveryRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, label uint32) *EVPNNLRI { - return NewEVPNNLRI(EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY, &EVPNEthernetAutoDiscoveryRoute{ - RD: rd, - ESI: esi, - ETag: etag, - Label: label, - }) -} - -type EVPNMacIPAdvertisementRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - ETag uint32 - MacAddressLength uint8 - MacAddress net.HardwareAddr - IPAddressLength uint8 - IPAddress net.IP - Labels []uint32 -} - -func (er *EVPNMacIPAdvertisementRoute) Len() int { - // RD(8) + ESI(10) + ETag(4) + MacAddressLength(1) + MacAddress(6) - // + IPAddressLength(1) + IPAddress(0, 4 or 16) + Labels(3 or 6) - return 30 + int(er.IPAddressLength)/8 + len(er.Labels)*3 -} - -func (er *EVPNMacIPAdvertisementRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - data = data[er.RD.Len():] - err := er.ESI.DecodeFromBytes(data) - if err != nil { - return err - } - data = data[10:] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - data = data[4:] - er.MacAddressLength = data[0] - er.MacAddress = net.HardwareAddr(data[1:7]) - er.IPAddressLength = data[7] - data = data[8:] - if er.IPAddressLength == 32 || er.IPAddressLength == 128 { - er.IPAddress = net.IP(data[0:((er.IPAddressLength) / 8)]) - } else if er.IPAddressLength != 0 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength)) - } - data = data[(er.IPAddressLength / 8):] - var label uint32 - if label, err = labelDecode(data); err != nil { - return err - } - er.Labels = append(er.Labels, label) - data = data[3:] - if len(data) == 3 { - if label, err = labelDecode(data); err != nil { - return err - } - er.Labels = append(er.Labels, label) - } - return nil -} - -func (er *EVPNMacIPAdvertisementRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - - buf = append(buf, tbuf...) - tbuf = make([]byte, 4) - binary.BigEndian.PutUint32(tbuf, er.ETag) - buf = append(buf, tbuf...) - tbuf = make([]byte, 7) - tbuf[0] = er.MacAddressLength - copy(tbuf[1:], er.MacAddress) - buf = append(buf, tbuf...) - - buf = append(buf, er.IPAddressLength) - switch er.IPAddressLength { - case 0: - // IP address omitted - case 32: - buf = append(buf, []byte(er.IPAddress.To4())...) - case 128: - buf = append(buf, []byte(er.IPAddress.To16())...) - default: - return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength) - } - - for _, l := range er.Labels { - tbuf, err = labelSerialize(l) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - } - return buf, nil -} - -func (er *EVPNMacIPAdvertisementRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.2. MAC/IP Advertisement Route - // For the purpose of BGP route key processing, only the Ethernet Tag - // ID, MAC Address Length, MAC Address, IP Address Length, and IP - // Address fields are considered to be part of the prefix in the NLRI. - // The Ethernet Segment Identifier, MPLS Label1, and MPLS Label2 fields - // are to be treated as route attributes as opposed to being part of the - // "route". - return fmt.Sprintf("[type:macadv][rd:%s][etag:%d][mac:%s][ip:%s]", er.RD, er.ETag, er.MacAddress, er.IPAddress) -} - -func (er *EVPNMacIPAdvertisementRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - Etag uint32 `json:"etag"` - MacAddress string `json:"mac"` - IPAddress string `json:"ip"` - Labels []uint32 `json:"labels"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - Etag: er.ETag, - MacAddress: er.MacAddress.String(), - IPAddress: er.IPAddress.String(), - Labels: er.Labels, - }) -} - -func (er *EVPNMacIPAdvertisementRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNMacIPAdvertisementRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, macAddress string, ipAddress string, labels []uint32) *EVPNNLRI { - mac, _ := net.ParseMAC(macAddress) - var ipLen uint8 - ip := net.ParseIP(ipAddress) - if ip != nil { - if ipv4 := ip.To4(); ipv4 != nil { - ipLen = 32 - ip = ipv4 - } else { - ipLen = 128 - } - } - return NewEVPNNLRI(EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, &EVPNMacIPAdvertisementRoute{ - RD: rd, - ESI: esi, - ETag: etag, - MacAddressLength: 6, - MacAddress: mac, - IPAddressLength: ipLen, - IPAddress: ip, - Labels: labels, - }) -} - -type EVPNMulticastEthernetTagRoute struct { - RD RouteDistinguisherInterface - ETag uint32 - IPAddressLength uint8 - IPAddress net.IP -} - -func (er *EVPNMulticastEthernetTagRoute) Len() int { - // RD(8) + ETag(4) + IPAddressLength(1) + IPAddress(4 or 16) - return 13 + int(er.IPAddressLength)/8 -} - -func (er *EVPNMulticastEthernetTagRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - data = data[er.RD.Len():] - er.ETag = binary.BigEndian.Uint32(data[0:4]) - er.IPAddressLength = data[4] - data = data[5:] - if er.IPAddressLength == 32 || er.IPAddressLength == 128 { - er.IPAddress = net.IP(data[:er.IPAddressLength/8]) - } else { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength)) - } - return nil -} - -func (er *EVPNMulticastEthernetTagRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - tbuf := make([]byte, 4) - binary.BigEndian.PutUint32(tbuf, er.ETag) - buf = append(buf, tbuf...) - buf = append(buf, er.IPAddressLength) - switch er.IPAddressLength { - case 32: - buf = append(buf, []byte(er.IPAddress.To4())...) - case 128: - buf = append(buf, []byte(er.IPAddress.To16())...) - default: - return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength) - } - if err != nil { - return nil, err - } - return buf, nil -} - -func (er *EVPNMulticastEthernetTagRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.3. Inclusive Multicast Ethernet Tag Route - // ...(snip)... For the purpose of BGP route key - // processing, only the Ethernet Tag ID, IP Address Length, and - // Originating Router's IP Address fields are considered to be part of - // the prefix in the NLRI. - return fmt.Sprintf("[type:multicast][rd:%s][etag:%d][ip:%s]", er.RD, er.ETag, er.IPAddress) -} - -func (er *EVPNMulticastEthernetTagRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - Etag uint32 `json:"etag"` - IPAddress string `json:"ip"` - }{ - RD: er.RD, - Etag: er.ETag, - IPAddress: er.IPAddress.String(), - }) -} - -func (er *EVPNMulticastEthernetTagRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNMulticastEthernetTagRoute(rd RouteDistinguisherInterface, etag uint32, ipAddress string) *EVPNNLRI { - ipLen := uint8(32) - ip := net.ParseIP(ipAddress) - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } else { - ipLen = 128 - } - return NewEVPNNLRI(EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, &EVPNMulticastEthernetTagRoute{ - RD: rd, - ETag: etag, - IPAddressLength: ipLen, - IPAddress: ip, - }) -} - -type EVPNEthernetSegmentRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - IPAddressLength uint8 - IPAddress net.IP -} - -func (er *EVPNEthernetSegmentRoute) Len() int { - // RD(8) + ESI(10) + IPAddressLength(1) + IPAddress(4 or 16) - return 19 + int(er.IPAddressLength)/8 -} - -func (er *EVPNEthernetSegmentRoute) DecodeFromBytes(data []byte) error { - er.RD = GetRouteDistinguisher(data) - data = data[er.RD.Len():] - er.ESI.DecodeFromBytes(data) - data = data[10:] - er.IPAddressLength = data[0] - data = data[1:] - if er.IPAddressLength == 32 || er.IPAddressLength == 128 { - er.IPAddress = net.IP(data[:er.IPAddressLength/8]) - } else { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength)) - } - return nil -} - -func (er *EVPNEthernetSegmentRoute) Serialize() ([]byte, error) { - var buf []byte - var err error - if er.RD != nil { - buf, err = er.RD.Serialize() - if err != nil { - return nil, err - } - } else { - buf = make([]byte, 8) - } - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - buf = append(buf, er.IPAddressLength) - switch er.IPAddressLength { - case 32: - buf = append(buf, []byte(er.IPAddress.To4())...) - case 128: - buf = append(buf, []byte(er.IPAddress.To16())...) - default: - return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength) - } - return buf, nil -} - -func (er *EVPNEthernetSegmentRoute) String() string { - // RFC7432: BGP MPLS-Based Ethernet VPN - // 7.4. Ethernet Segment Route - // For the purpose of BGP route key processing, only the Ethernet - // Segment ID, IP Address Length, and Originating Router's IP Address - // fields are considered to be part of the prefix in the NLRI. - return fmt.Sprintf("[type:esi][rd:%s][esi:%s][ip:%s]", er.RD, er.ESI.String(), er.IPAddress) -} - -func (er *EVPNEthernetSegmentRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - IPAddress string `json:"ip"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - IPAddress: er.IPAddress.String(), - }) -} - -func (er *EVPNEthernetSegmentRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNEthernetSegmentRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, ipAddress string) *EVPNNLRI { - ipLen := uint8(32) - ip := net.ParseIP(ipAddress) - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - } else { - ipLen = 128 - } - return NewEVPNNLRI(EVPN_ETHERNET_SEGMENT_ROUTE, &EVPNEthernetSegmentRoute{ - RD: rd, - ESI: esi, - IPAddressLength: ipLen, - IPAddress: ip, - }) -} - -type EVPNIPPrefixRoute struct { - RD RouteDistinguisherInterface - ESI EthernetSegmentIdentifier - ETag uint32 - IPPrefixLength uint8 - IPPrefix net.IP - GWIPAddress net.IP - Label uint32 -} - -func (er *EVPNIPPrefixRoute) Len() int { - if er.IPPrefix.To4() != nil { - return 34 - } - return 58 -} - -func (er *EVPNIPPrefixRoute) DecodeFromBytes(data []byte) error { - addrLen := net.IPv4len - switch len(data) { - case 34: - // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) + IPv4 Prefix(4) + GW IPv4(4) + Label(3) - case 58: - // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) + IPv6 Prefix(16) + GW IPv6(16) + Label(3) - addrLen = net.IPv6len - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPN IP Prefix Route bytes available") - } - - er.RD = GetRouteDistinguisher(data[0:8]) - - err := er.ESI.DecodeFromBytes(data[8:18]) - if err != nil { - return err - } - - er.ETag = binary.BigEndian.Uint32(data[18:22]) - - er.IPPrefixLength = data[22] - - offset := 23 // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) - er.IPPrefix = data[offset : offset+addrLen] - offset += addrLen - - er.GWIPAddress = data[offset : offset+addrLen] - offset += addrLen - - if er.Label, err = labelDecode(data[offset : offset+3]); err != nil { - return err - } - //offset += 3 - - return nil -} - -func (er *EVPNIPPrefixRoute) Serialize() ([]byte, error) { - buf := make([]byte, 23) // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) - - if er.RD != nil { - tbuf, err := er.RD.Serialize() - if err != nil { - return nil, err - } - copy(buf[0:8], tbuf) - } - - tbuf, err := er.ESI.Serialize() - if err != nil { - return nil, err - } - copy(buf[8:18], tbuf) - - binary.BigEndian.PutUint32(buf[18:22], er.ETag) - - buf[22] = er.IPPrefixLength - - if er.IPPrefix == nil { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("IP Prefix is nil")) - } else if er.IPPrefix.To4() != nil { - buf = append(buf, er.IPPrefix.To4()...) - if er.GWIPAddress == nil { - // draft-ietf-bess-evpn-prefix-advertisement: IP Prefix Advertisement in EVPN - // The GW IP field SHOULD be zero if it is not used as an Overlay Index. - er.GWIPAddress = net.IPv4zero - } - buf = append(buf, er.GWIPAddress.To4()...) - } else { - buf = append(buf, er.IPPrefix.To16()...) - if er.GWIPAddress == nil { - er.GWIPAddress = net.IPv6zero - } - buf = append(buf, er.GWIPAddress.To16()...) - } - - tbuf, err = labelSerialize(er.Label) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - - return buf, nil -} - -func (er *EVPNIPPrefixRoute) String() string { - // draft-ietf-bess-evpn-prefix-advertisement: IP Prefix Advertisement in EVPN - // 3.1 IP Prefix Route Encoding - // The RD, Eth-Tag ID, IP Prefix Length and IP Prefix will be part of - // the route key used by BGP to compare routes. The rest of the fields - // will not be part of the route key. - return fmt.Sprintf("[type:Prefix][rd:%s][etag:%d][prefix:%s/%d]", er.RD, er.ETag, er.IPPrefix, er.IPPrefixLength) -} - -func (er *EVPNIPPrefixRoute) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - ESI string `json:"esi"` - Etag uint32 `json:"etag"` - Prefix string `json:"prefix"` - Gateway string `json:"gateway"` - Label uint32 `json:"label"` - }{ - RD: er.RD, - ESI: er.ESI.String(), - Etag: er.ETag, - Prefix: fmt.Sprintf("%s/%d", er.IPPrefix, er.IPPrefixLength), - Gateway: er.GWIPAddress.String(), - Label: er.Label, - }) -} - -func (er *EVPNIPPrefixRoute) rd() RouteDistinguisherInterface { - return er.RD -} - -func NewEVPNIPPrefixRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, ipPrefixLength uint8, ipPrefix string, gateway string, label uint32) *EVPNNLRI { - ip := net.ParseIP(ipPrefix) - gw := net.ParseIP(gateway) - if ipv4 := ip.To4(); ipv4 != nil { - ip = ipv4 - gw = gw.To4() - } - return NewEVPNNLRI(EVPN_IP_PREFIX, &EVPNIPPrefixRoute{ - RD: rd, - ESI: esi, - ETag: etag, - IPPrefixLength: ipPrefixLength, - IPPrefix: ip, - GWIPAddress: gw, - Label: label, - }) -} - -type EVPNRouteTypeInterface interface { - Len() int - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - String() string - rd() RouteDistinguisherInterface - MarshalJSON() ([]byte, error) -} - -func getEVPNRouteType(t uint8) (EVPNRouteTypeInterface, error) { - switch t { - case EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY: - return &EVPNEthernetAutoDiscoveryRoute{}, nil - case EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT: - return &EVPNMacIPAdvertisementRoute{}, nil - case EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG: - return &EVPNMulticastEthernetTagRoute{}, nil - case EVPN_ETHERNET_SEGMENT_ROUTE: - return &EVPNEthernetSegmentRoute{}, nil - case EVPN_IP_PREFIX: - return &EVPNIPPrefixRoute{}, nil - } - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Unknown EVPN Route type: %d", t)) -} - -const ( - EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY = 1 - EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT = 2 - EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG = 3 - EVPN_ETHERNET_SEGMENT_ROUTE = 4 - EVPN_IP_PREFIX = 5 -) - -type EVPNNLRI struct { - PrefixDefault - RouteType uint8 - Length uint8 - RouteTypeData EVPNRouteTypeInterface -} - -func (n *EVPNNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - if IsAddPathEnabled(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") - } - n.RouteType = data[0] - n.Length = data[1] - data = data[2:] - if len(data) < int(n.Length) { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI Route type bytes available") - } - r, err := getEVPNRouteType(n.RouteType) - if err != nil { - return err - } - n.RouteTypeData = r - return n.RouteTypeData.DecodeFromBytes(data[:n.Length]) -} - -func (n *EVPNNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - if IsAddPathEnabled(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() - buf[offset+1] = n.Length - if err != nil { - return nil, err - } - return append(buf, tbuf...), nil -} - -func (n *EVPNNLRI) AFI() uint16 { - return AFI_L2VPN -} - -func (n *EVPNNLRI) SAFI() uint8 { - return SAFI_EVPN -} - -func (n *EVPNNLRI) Len(options ...*MarshallingOption) int { - return int(n.Length) + 2 -} - -func (n *EVPNNLRI) String() string { - if n.RouteTypeData != nil { - return n.RouteTypeData.String() - } - return fmt.Sprintf("%d:%d", n.RouteType, n.Length) -} - -func (n *EVPNNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint8 `json:"type"` - Value EVPNRouteTypeInterface `json:"value"` - }{ - Type: n.RouteType, - Value: n.RouteTypeData, - }) -} - -func (n *EVPNNLRI) RD() RouteDistinguisherInterface { - return n.RouteTypeData.rd() -} - -func NewEVPNNLRI(routeType uint8, routeTypeData EVPNRouteTypeInterface) *EVPNNLRI { - var l uint8 - if routeTypeData != nil { - l = uint8(routeTypeData.Len()) - } - return &EVPNNLRI{ - RouteType: routeType, - Length: l, - RouteTypeData: routeTypeData, - } -} - -type EncapNLRI struct { - IPAddrPrefixDefault - addrlen uint8 -} - -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 IsAddPathEnabled(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) - return NewMessageError(eCode, eSubCode, nil, "prefix misses length field") - } - n.Length = data[0] - if n.addrlen == 0 { - n.addrlen = 4 - } - return n.decodePrefix(data[1:], n.Length, n.addrlen) -} - -func (n *EncapNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - f := RF_IPv4_ENCAP - if n.addrlen == 16 { - f = RF_IPv6_ENCAP - } - if IsAddPathEnabled(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 - } - return append(buf, pbuf...), nil -} - -func (n *EncapNLRI) String() string { - return n.Prefix.String() -} - -func (n *EncapNLRI) AFI() uint16 { - return AFI_IP -} - -func (n *EncapNLRI) SAFI() uint8 { - return SAFI_ENCAPSULATION -} - -func (n *EncapNLRI) Len(options ...*MarshallingOption) int { - return 1 + len(n.Prefix) -} - -func NewEncapNLRI(endpoint string) *EncapNLRI { - return &EncapNLRI{ - IPAddrPrefixDefault{Length: 32, Prefix: net.ParseIP(endpoint).To4()}, - 4, - } -} - -type Encapv6NLRI struct { - EncapNLRI -} - -func (n *Encapv6NLRI) AFI() uint16 { - return AFI_IP6 -} - -func NewEncapv6NLRI(endpoint string) *Encapv6NLRI { - return &Encapv6NLRI{ - EncapNLRI{ - IPAddrPrefixDefault{Length: 128, Prefix: net.ParseIP(endpoint)}, - 16, - }, - } -} - -type BGPFlowSpecType uint8 - -const ( - FLOW_SPEC_TYPE_UNKNOWN BGPFlowSpecType = iota - FLOW_SPEC_TYPE_DST_PREFIX - FLOW_SPEC_TYPE_SRC_PREFIX - FLOW_SPEC_TYPE_IP_PROTO - FLOW_SPEC_TYPE_PORT - FLOW_SPEC_TYPE_DST_PORT - FLOW_SPEC_TYPE_SRC_PORT - FLOW_SPEC_TYPE_ICMP_TYPE - FLOW_SPEC_TYPE_ICMP_CODE - FLOW_SPEC_TYPE_TCP_FLAG - FLOW_SPEC_TYPE_PKT_LEN - FLOW_SPEC_TYPE_DSCP - FLOW_SPEC_TYPE_FRAGMENT - FLOW_SPEC_TYPE_LABEL - FLOW_SPEC_TYPE_ETHERNET_TYPE // 14 - FLOW_SPEC_TYPE_SRC_MAC - FLOW_SPEC_TYPE_DST_MAC - FLOW_SPEC_TYPE_LLC_DSAP - FLOW_SPEC_TYPE_LLC_SSAP - FLOW_SPEC_TYPE_LLC_CONTROL - FLOW_SPEC_TYPE_SNAP - FLOW_SPEC_TYPE_VID - FLOW_SPEC_TYPE_COS - FLOW_SPEC_TYPE_INNER_VID - FLOW_SPEC_TYPE_INNER_COS -) - -var FlowSpecNameMap = map[BGPFlowSpecType]string{ - FLOW_SPEC_TYPE_UNKNOWN: "unknown", - FLOW_SPEC_TYPE_DST_PREFIX: "destination", - FLOW_SPEC_TYPE_SRC_PREFIX: "source", - FLOW_SPEC_TYPE_IP_PROTO: "protocol", - FLOW_SPEC_TYPE_PORT: "port", - FLOW_SPEC_TYPE_DST_PORT: "destination-port", - FLOW_SPEC_TYPE_SRC_PORT: "source-port", - FLOW_SPEC_TYPE_ICMP_TYPE: "icmp-type", - FLOW_SPEC_TYPE_ICMP_CODE: "icmp-code", - FLOW_SPEC_TYPE_TCP_FLAG: "tcp-flags", - FLOW_SPEC_TYPE_PKT_LEN: "packet-length", - FLOW_SPEC_TYPE_DSCP: "dscp", - FLOW_SPEC_TYPE_FRAGMENT: "fragment", - FLOW_SPEC_TYPE_LABEL: "label", - FLOW_SPEC_TYPE_ETHERNET_TYPE: "ether-type", - FLOW_SPEC_TYPE_SRC_MAC: "source-mac", - FLOW_SPEC_TYPE_DST_MAC: "destination-mac", - FLOW_SPEC_TYPE_LLC_DSAP: "llc-dsap", - FLOW_SPEC_TYPE_LLC_SSAP: "llc-ssap", - FLOW_SPEC_TYPE_LLC_CONTROL: "llc-control", - FLOW_SPEC_TYPE_SNAP: "snap", - FLOW_SPEC_TYPE_VID: "vid", - FLOW_SPEC_TYPE_COS: "cos", - FLOW_SPEC_TYPE_INNER_VID: "inner-vid", - FLOW_SPEC_TYPE_INNER_COS: "inner-cos", -} - -var FlowSpecValueMap = map[string]BGPFlowSpecType{ - FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]: FLOW_SPEC_TYPE_DST_PREFIX, - FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]: FLOW_SPEC_TYPE_SRC_PREFIX, - FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO]: FLOW_SPEC_TYPE_IP_PROTO, - FlowSpecNameMap[FLOW_SPEC_TYPE_PORT]: FLOW_SPEC_TYPE_PORT, - FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PORT]: FLOW_SPEC_TYPE_DST_PORT, - FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PORT]: FLOW_SPEC_TYPE_SRC_PORT, - FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_TYPE]: FLOW_SPEC_TYPE_ICMP_TYPE, - FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_CODE]: FLOW_SPEC_TYPE_ICMP_CODE, - FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG]: FLOW_SPEC_TYPE_TCP_FLAG, - FlowSpecNameMap[FLOW_SPEC_TYPE_PKT_LEN]: FLOW_SPEC_TYPE_PKT_LEN, - FlowSpecNameMap[FLOW_SPEC_TYPE_DSCP]: FLOW_SPEC_TYPE_DSCP, - FlowSpecNameMap[FLOW_SPEC_TYPE_FRAGMENT]: FLOW_SPEC_TYPE_FRAGMENT, - FlowSpecNameMap[FLOW_SPEC_TYPE_LABEL]: FLOW_SPEC_TYPE_LABEL, - FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE]: FLOW_SPEC_TYPE_ETHERNET_TYPE, - FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]: FLOW_SPEC_TYPE_SRC_MAC, - FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]: FLOW_SPEC_TYPE_DST_MAC, - FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_DSAP]: FLOW_SPEC_TYPE_LLC_DSAP, - FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_SSAP]: FLOW_SPEC_TYPE_LLC_SSAP, - FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_CONTROL]: FLOW_SPEC_TYPE_LLC_CONTROL, - FlowSpecNameMap[FLOW_SPEC_TYPE_SNAP]: FLOW_SPEC_TYPE_SNAP, - FlowSpecNameMap[FLOW_SPEC_TYPE_VID]: FLOW_SPEC_TYPE_VID, - FlowSpecNameMap[FLOW_SPEC_TYPE_COS]: FLOW_SPEC_TYPE_COS, - FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_VID]: FLOW_SPEC_TYPE_INNER_VID, - FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_COS]: FLOW_SPEC_TYPE_INNER_COS, -} - -// Joins the given and args into a single string and normalize it. -// Example: -// args := []string{" & <=80", " tcp != udp ", " =! SA & =U! F", " = is-fragment+last-fragment"} -// fmt.Printf("%q", normalizeFlowSpecOpValues(args)) -// >>> ["<=80" "tcp" "!=udp" "=!SA" "&=U" "!F" "=is-fragment+last-fragment"] -func normalizeFlowSpecOpValues(args []string) []string { - // Extracts keywords from the given args. - sub := "" - subs := make([]string, 0) - for _, s := range _regexpFlowSpecOperator.FindAllString(strings.Join(args, " "), -1) { - sub += s - if _regexpFlowSpecOperatorValue.MatchString(s) { - subs = append(subs, sub) - sub = "" - } - } - - // RFC5575 says "It should be unset in the first operator byte of a - // sequence". - if len(subs) > 0 { - subs[0] = strings.TrimPrefix(subs[0], "&") - } - - return subs -} - -// Parses the FlowSpec numeric operator using the given submatch which should be -// the return value of func (*Regexp) FindStringSubmatch. -func parseFlowSpecNumericOperator(submatch []string) (operator uint8, err error) { - if submatch[1] == "&" { - operator = DEC_NUM_OP_AND - } - value, ok := DECNumOpValueMap[submatch[2]] - if !ok { - return 0, fmt.Errorf("invalid numeric operator: %s%s", submatch[1], submatch[2]) - } - operator |= uint8(value) - return operator, nil -} - -// Parses the pairs of operator and value for the FlowSpec numeric type. The -// given validationFunc is applied to evaluate whether the parsed value is -// valid or not (e.g., if exceeds range or not). -// Note: Each of the args should be formatted in single pair of operator and -// value before calling this function. -// e.g.) "&==100", ">=200" or "&<300" -func parseFlowSpecNumericOpValues(typ BGPFlowSpecType, args []string, validationFunc func(uint64) error) (FlowSpecComponentInterface, error) { - argsLen := len(args) - items := make([]*FlowSpecComponentItem, 0, argsLen) - for idx, arg := range args { - m := _regexpFlowSpecNumericType.FindStringSubmatch(arg) - if len(m) < 4 { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } - operator, err := parseFlowSpecNumericOperator(m) - if err != nil { - return nil, err - } - // "true" and "false" is operator, but here handles them as value. - var value uint64 - switch m[3] { - case "true", "false": - if idx != argsLen-1 { - return nil, fmt.Errorf("%s should be the last of each rule", m[3]) - } - operator = uint8(DECNumOpValueMap[m[3]]) - default: - if value, err = strconv.ParseUint(m[3], 10, 64); err != nil { - return nil, fmt.Errorf("invalid numeric value: %s", m[3]) - } - if err = validationFunc(value); err != nil { - return nil, err - } - } - items = append(items, NewFlowSpecComponentItem(operator, value)) - } - - // Marks end-of-list bit - items[argsLen-1].Op |= uint8(DEC_NUM_OP_END) - - return NewFlowSpecComponent(typ, items), nil -} - -func flowSpecNumeric1ByteParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xff { // 1 byte - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecNumeric2BytesParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xffff { // 2 bytes - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -// Parses the FlowSpec bitmask operand using the given submatch which should be -// the return value of func (*Regexp) FindStringSubmatch. -func parseFlowSpecBitmaskOperand(submatch []string) (operand uint8, err error) { - if submatch[1] == "&" { - operand = BITMASK_FLAG_OP_AND - } - value, ok := BitmaskFlagOpValueMap[submatch[2]] - if !ok { - return 0, fmt.Errorf("invalid bitmask operand: %s%s", submatch[1], submatch[2]) - } - operand |= uint8(value) - return operand, nil -} - -func flowSpecPrefixParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args[0]: IP Prefix or IP Address (suppose prefix length is 32) - // args[1]: Offset in bit (IPv6 only) - // - // Example: - // - IPv4 Prefix - // args := []string{"192.168.0.0/24"} - // - IPv4 Address - // args := []string{"192.168.0.1"} - // - IPv6 Prefix - // args := []string{"2001:db8:1::/64"} - // - IPv6 Prefix with offset - // args := []string{"0:db8:1::/64/16"} - // args := []string{"0:db8:1::/64", "16"} - // - IPv6 Address - // args := []string{"2001:db8:1::1"} - // - IPv6 Address with offset - // args := []string{"0:db8:1::1", "16"} - afi, _ := RouteFamilyToAfiSafi(rf) - switch afi { - case AFI_IP: - if len(args) > 1 { - return nil, fmt.Errorf("cannot specify offset for ipv4 prefix") - } - invalidIPv4PrefixError := fmt.Errorf("invalid ipv4 prefix: %s", args[0]) - m := _regexpFindIPv4Prefix.FindStringSubmatch(args[0]) - if len(m) < 4 { - return nil, invalidIPv4PrefixError - } - prefix := net.ParseIP(m[1]) - if prefix.To4() == nil { - return nil, invalidIPv4PrefixError - } - var prefixLen uint64 = 32 - if m[3] != "" { - var err error - prefixLen, err = strconv.ParseUint(m[3], 10, 8) - if err != nil || prefixLen > 32 { - return nil, invalidIPv4PrefixError - } - } - switch typ { - case FLOW_SPEC_TYPE_DST_PREFIX: - return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil - case FLOW_SPEC_TYPE_SRC_PREFIX: - return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil - } - return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) - case AFI_IP6: - if len(args) > 2 { - return nil, fmt.Errorf("invalid arguments for ipv6 prefix: %q", args) - } - invalidIPv6PrefixError := fmt.Errorf("invalid ipv6 prefix: %s", args[0]) - m := _regexpFindIPv6Prefix.FindStringSubmatch(args[0]) - if len(m) < 4 { - return nil, invalidIPv6PrefixError - } - prefix := net.ParseIP(m[1]) - if prefix.To16() == nil { - return nil, invalidIPv6PrefixError - } - var prefixLen uint64 = 128 - if m[3] != "" { - var err error - prefixLen, err = strconv.ParseUint(m[3], 10, 8) - if err != nil || prefixLen > 128 { - return nil, invalidIPv6PrefixError - } - } - var offset uint64 - if len(args) == 1 && m[5] != "" { - var err error - offset, err = strconv.ParseUint(m[5], 10, 8) - if err != nil || offset > 128 { - return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", m[5]) - } - } else if len(args) == 2 { - if m[5] != "" { - return nil, fmt.Errorf("multiple ipv6 prefix offset arguments detected: %q", args) - } - var err error - offset, err = strconv.ParseUint(args[1], 10, 8) - if err != nil || offset > 128 { - return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", args[1]) - } - } - switch typ { - case FLOW_SPEC_TYPE_DST_PREFIX: - return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil - case FLOW_SPEC_TYPE_SRC_PREFIX: - return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil - } - return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) - } - return nil, fmt.Errorf("invalid address family: %s", rf.String()) -} - -func flowSpecIpProtoParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operator and IP protocol type - // - // Example: - // - TCP or UDP - // args := []string{"tcp", "==udp"} - // - Not TCP and not UDP - // args := []string{"!=tcp", "&!=udp"} - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range ProtocolNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 0xff { // 1 byte - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecTcpFlagParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operand and TCP Flags - // - // Example: - // - SYN or SYN/ACK - // args := []string{"==S", "==SA"} - // - Not FIN and not URG - // args := []string{"!=F", "&!=U"} - args = normalizeFlowSpecOpValues(args) - - argsLen := len(args) - items := make([]*FlowSpecComponentItem, 0, argsLen) - - for _, arg := range args { - m := _regexpFlowSpecTCPFlag.FindStringSubmatch(arg) - if len(m) < 6 { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } else if mLast := m[len(m)-1]; mLast != "" || m[3] != "" { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } - operand, err := parseFlowSpecBitmaskOperand(m) - if err != nil { - return nil, err - } - var value uint64 - for flag, name := range TCPFlagNameMap { - if strings.Contains(m[4], name) { - value |= uint64(flag) - } - } - items = append(items, NewFlowSpecComponentItem(operand, value)) - } - - // Marks end-of-list bit - items[argsLen-1].Op |= BITMASK_FLAG_OP_END - - return NewFlowSpecComponent(typ, items), nil -} - -func flowSpecDscpParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i < 64 { // 6 bits - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecFragmentParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operator and Fragment flags - // - // Example: - // - is-fragment or last-fragment - // args := []string{"==is-fragment", "==last-fragment"} - // - is-fragment and last-fragment (exact match) - // args := []string{"==is-fragment+last-fragment"} - args = normalizeFlowSpecOpValues(args) - - argsLen := len(args) - items := make([]*FlowSpecComponentItem, 0, argsLen) - - for _, arg := range args { - m := _regexpFlowSpecFragment.FindStringSubmatch(arg) - if len(m) < 4 { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } else if mLast := m[len(m)-1]; mLast != "" { - return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args) - } - operand, err := parseFlowSpecBitmaskOperand(m) - if err != nil { - return nil, err - } - var value uint64 - // Example: - // m[3] = "first-fragment+last-fragment" - for flag, name := range FragmentFlagNameMap { - if strings.Contains(m[3], name) { - value |= uint64(flag) - } - } - items = append(items, NewFlowSpecComponentItem(operand, value)) - } - - // Marks end-of-list bit - items[argsLen-1].Op |= BITMASK_FLAG_OP_END - - return NewFlowSpecComponent(typ, items), nil -} - -func flowSpecLabelParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - afi, _ := RouteFamilyToAfiSafi(rf) - if afi == AFI_IP { - return nil, fmt.Errorf("%s is not supported for ipv4", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xfffff { // 20 bits - return nil - } - return fmt.Errorf("flow label range exceeded") - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecEtherTypeParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args: List of pairs of Operator and Ether Types - // - // Example: - // - ARP or IPv4 - // args := []string{"==arp", "==ipv4"} - // - Not IPv4 and not IPv6 - // args := []string{"!=ipv4", "&!=ipv6"} - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range EthernetTypeNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 0xffff { // 2 bytes - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecMacParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - // args[0]: MAC address - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - mac, err := net.ParseMAC(args[0]) - if err != nil { - return nil, fmt.Errorf("invalid mac address: %s", args[0]) - } - - switch typ { - case FLOW_SPEC_TYPE_DST_MAC: - return NewFlowSpecDestinationMac(mac), nil - case FLOW_SPEC_TYPE_SRC_MAC: - return NewFlowSpecSourceMac(mac), nil - } - return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String()) -} - -func flowSpecLlcParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - return flowSpecNumeric1ByteParser(rf, typ, args) -} - -func flowSpecSnapParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - - f := func(i uint64) error { - if i <= 0xffffffffff { // 5 bytes - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecVlanIDParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range EthernetTypeNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 4095 { // 12 bits - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -func flowSpecVlanCosParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) { - if rf != RF_FS_L2_VPN { - return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String()) - } - - args = normalizeFlowSpecOpValues(args) - s := strings.Join(args, " ") - for i, name := range EthernetTypeNameMap { - s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1) - } - args = strings.Split(s, " ") - - f := func(i uint64) error { - if i <= 7 { // 3 bits - return nil - } - return fmt.Errorf("%s range exceeded", typ.String()) - } - - return parseFlowSpecNumericOpValues(typ, args, f) -} - -var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, BGPFlowSpecType, []string) (FlowSpecComponentInterface, error){ - FLOW_SPEC_TYPE_DST_PREFIX: flowSpecPrefixParser, - FLOW_SPEC_TYPE_SRC_PREFIX: flowSpecPrefixParser, - FLOW_SPEC_TYPE_IP_PROTO: flowSpecIpProtoParser, - FLOW_SPEC_TYPE_PORT: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_DST_PORT: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_SRC_PORT: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_ICMP_TYPE: flowSpecNumeric1ByteParser, - FLOW_SPEC_TYPE_ICMP_CODE: flowSpecNumeric1ByteParser, - FLOW_SPEC_TYPE_TCP_FLAG: flowSpecTcpFlagParser, - FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumeric2BytesParser, - FLOW_SPEC_TYPE_DSCP: flowSpecDscpParser, - FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser, - FLOW_SPEC_TYPE_LABEL: flowSpecLabelParser, - FLOW_SPEC_TYPE_ETHERNET_TYPE: flowSpecEtherTypeParser, - FLOW_SPEC_TYPE_DST_MAC: flowSpecMacParser, - FLOW_SPEC_TYPE_SRC_MAC: flowSpecMacParser, - FLOW_SPEC_TYPE_LLC_DSAP: flowSpecLlcParser, - FLOW_SPEC_TYPE_LLC_SSAP: flowSpecLlcParser, - FLOW_SPEC_TYPE_LLC_CONTROL: flowSpecLlcParser, - FLOW_SPEC_TYPE_SNAP: flowSpecSnapParser, - FLOW_SPEC_TYPE_VID: flowSpecVlanIDParser, - FLOW_SPEC_TYPE_COS: flowSpecVlanCosParser, - FLOW_SPEC_TYPE_INNER_VID: flowSpecVlanIDParser, - FLOW_SPEC_TYPE_INNER_COS: flowSpecVlanCosParser, -} - -func extractFlowSpecArgs(args []string) map[BGPFlowSpecType][]string { - m := make(map[BGPFlowSpecType][]string, len(FlowSpecValueMap)) - var typ BGPFlowSpecType - for _, arg := range args { - if t, ok := FlowSpecValueMap[arg]; ok { - typ = t - m[typ] = make([]string, 0) - } else { - m[typ] = append(m[typ], arg) - } - } - return m -} - -func ParseFlowSpecComponents(rf RouteFamily, arg string) ([]FlowSpecComponentInterface, error) { - _, safi := RouteFamilyToAfiSafi(rf) - switch safi { - case SAFI_FLOW_SPEC_UNICAST, SAFI_FLOW_SPEC_VPN: - // Valid - default: - return nil, fmt.Errorf("invalid address family: %s", rf.String()) - } - - typeArgs := extractFlowSpecArgs(strings.Split(arg, " ")) - rules := make([]FlowSpecComponentInterface, 0, len(typeArgs)) - for typ, args := range typeArgs { - parser, ok := flowSpecParserMap[typ] - if !ok { - return nil, fmt.Errorf("unsupported traffic filtering rule type: %s", typ.String()) - } - if len(args) == 0 { - return nil, fmt.Errorf("specify traffic filtering rules for %s", typ.String()) - } - rule, err := parser(rf, typ, args) - if err != nil { - return nil, err - } - rules = append(rules, rule) - } - return rules, nil -} - -func (t BGPFlowSpecType) String() string { - name, ok := FlowSpecNameMap[t] - if !ok { - return fmt.Sprintf("%s(%d)", FlowSpecNameMap[FLOW_SPEC_TYPE_UNKNOWN], t) - } - return name -} - -type FlowSpecComponentInterface interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) - Len(...*MarshallingOption) int - Type() BGPFlowSpecType - String() string -} - -type flowSpecPrefix struct { - Prefix AddrPrefixInterface - typ BGPFlowSpecType -} - -func (p *flowSpecPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.typ = BGPFlowSpecType(data[0]) - return p.Prefix.DecodeFromBytes(data[1:], options...) -} - -func (p *flowSpecPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{byte(p.Type())} - bbuf, err := p.Prefix.Serialize(options...) - if err != nil { - return nil, err - } - return append(buf, bbuf...), nil -} - -func (p *flowSpecPrefix) Len(options ...*MarshallingOption) int { - buf, _ := p.Serialize(options...) - return len(buf) -} - -func (p *flowSpecPrefix) Type() BGPFlowSpecType { - return p.typ -} - -func (p *flowSpecPrefix) String() string { - return fmt.Sprintf("[%s: %s]", p.Type(), p.Prefix.String()) -} - -func (p *flowSpecPrefix) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value AddrPrefixInterface `json:"value"` - }{ - Type: p.Type(), - Value: p.Prefix, - }) -} - -type flowSpecPrefix6 struct { - Prefix AddrPrefixInterface - Offset uint8 - typ BGPFlowSpecType -} - -// draft-ietf-idr-flow-spec-v6-06 -// <type (1 octet), prefix length (1 octet), prefix offset(1 octet), prefix> -func (p *flowSpecPrefix6) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.typ = BGPFlowSpecType(data[0]) - p.Offset = data[2] - prefix := append([]byte{data[1]}, data[3:]...) - return p.Prefix.DecodeFromBytes(prefix, options...) -} - -func (p *flowSpecPrefix6) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{byte(p.Type())} - bbuf, err := p.Prefix.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, bbuf[0]) - buf = append(buf, p.Offset) - return append(buf, bbuf[1:]...), nil -} - -func (p *flowSpecPrefix6) Len(options ...*MarshallingOption) int { - buf, _ := p.Serialize(options...) - return len(buf) -} - -func (p *flowSpecPrefix6) Type() BGPFlowSpecType { - return p.typ -} - -func (p *flowSpecPrefix6) String() string { - return fmt.Sprintf("[%s: %s/%d]", p.Type(), p.Prefix.String(), p.Offset) -} - -func (p *flowSpecPrefix6) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value AddrPrefixInterface `json:"value"` - Offset uint8 `json:"offset"` - }{ - Type: p.Type(), - Value: p.Prefix, - Offset: p.Offset, - }) -} - -type FlowSpecDestinationPrefix struct { - flowSpecPrefix -} - -func NewFlowSpecDestinationPrefix(prefix AddrPrefixInterface) *FlowSpecDestinationPrefix { - return &FlowSpecDestinationPrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_DST_PREFIX}} -} - -type FlowSpecSourcePrefix struct { - flowSpecPrefix -} - -func NewFlowSpecSourcePrefix(prefix AddrPrefixInterface) *FlowSpecSourcePrefix { - return &FlowSpecSourcePrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_SRC_PREFIX}} -} - -type FlowSpecDestinationPrefix6 struct { - flowSpecPrefix6 -} - -func NewFlowSpecDestinationPrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecDestinationPrefix6 { - return &FlowSpecDestinationPrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_DST_PREFIX}} -} - -type FlowSpecSourcePrefix6 struct { - flowSpecPrefix6 -} - -func NewFlowSpecSourcePrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecSourcePrefix6 { - return &FlowSpecSourcePrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_SRC_PREFIX}} -} - -type flowSpecMac struct { - Mac net.HardwareAddr - typ BGPFlowSpecType -} - -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") - } - p.typ = BGPFlowSpecType(data[0]) - p.Mac = net.HardwareAddr(data[2 : 2+int(data[1])]) - return nil -} - -func (p *flowSpecMac) Serialize(options ...*MarshallingOption) ([]byte, error) { - if len(p.Mac) == 0 { - return nil, fmt.Errorf("mac unset") - } - buf := []byte{byte(p.Type()), byte(len(p.Mac))} - return append(buf, []byte(p.Mac)...), nil -} - -func (p *flowSpecMac) Len(options ...*MarshallingOption) int { - return 2 + len(p.Mac) -} - -func (p *flowSpecMac) Type() BGPFlowSpecType { - return p.typ -} - -func (p *flowSpecMac) String() string { - return fmt.Sprintf("[%s: %s]", p.Type(), p.Mac.String()) -} - -func (p *flowSpecMac) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value string `json:"value"` - }{ - Type: p.Type(), - Value: p.Mac.String(), - }) -} - -type FlowSpecSourceMac struct { - flowSpecMac -} - -func NewFlowSpecSourceMac(mac net.HardwareAddr) *FlowSpecSourceMac { - return &FlowSpecSourceMac{flowSpecMac{Mac: mac, typ: FLOW_SPEC_TYPE_SRC_MAC}} -} - -type FlowSpecDestinationMac struct { - flowSpecMac -} - -func NewFlowSpecDestinationMac(mac net.HardwareAddr) *FlowSpecDestinationMac { - return &FlowSpecDestinationMac{flowSpecMac{Mac: mac, typ: FLOW_SPEC_TYPE_DST_MAC}} -} - -type FlowSpecComponentItem struct { - Op uint8 `json:"op"` - Value uint64 `json:"value"` -} - -func (v *FlowSpecComponentItem) Len() int { - return 1 << ((uint32(v.Op) >> 4) & 0x3) -} - -func (v *FlowSpecComponentItem) Serialize() ([]byte, error) { - if v.Op > math.MaxUint8 { - return nil, fmt.Errorf("invalid op size: %d", v.Op) - } - - order := uint32(math.Log2(float64(v.Len()))) - buf := make([]byte, 1+(1<<order)) - buf[0] = byte(uint32(v.Op) | order<<4) - switch order { - case 0: - buf[1] = byte(v.Value) - case 1: - binary.BigEndian.PutUint16(buf[1:], uint16(v.Value)) - case 2: - binary.BigEndian.PutUint32(buf[1:], uint32(v.Value)) - case 3: - binary.BigEndian.PutUint64(buf[1:], uint64(v.Value)) - default: - return nil, fmt.Errorf("invalid value size(too big): %d", v.Value) - } - return buf, nil -} - -func NewFlowSpecComponentItem(op uint8, value uint64) *FlowSpecComponentItem { - v := &FlowSpecComponentItem{op, value} - order := uint32(math.Log2(float64(v.Len()))) - // we don't know if not initialized properly or initialized to - // zero... - if order == 0 { - order = func() uint32 { - for i := 0; i < 3; i++ { - if v.Value < (1 << ((1 << uint(i)) * 8)) { - return uint32(i) - } - } - // return invalid order - return 4 - }() - } - if order > 3 { - return nil - } - v.Op = uint8(uint32(v.Op) | order<<4) - return v -} - -type FlowSpecComponent struct { - Items []*FlowSpecComponentItem - typ BGPFlowSpecType -} - -func (p *FlowSpecComponent) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.typ = BGPFlowSpecType(data[0]) - data = data[1:] - p.Items = make([]*FlowSpecComponentItem, 0) - for { - if len(data) < 2 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - op := data[0] - end := op & 0x80 - l := 1 << ((op >> 4) & 0x3) // (min, max) = (1, 8) - v := make([]byte, 8) - copy(v[8-l:], data[1:1+l]) - i := binary.BigEndian.Uint64(v) - item := &FlowSpecComponentItem{op, i} - p.Items = append(p.Items, item) - if end > 0 { - break - } - data = data[1+l:] - } - return nil -} - -func (p *FlowSpecComponent) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := []byte{byte(p.Type())} - for _, v := range p.Items { - bbuf, err := v.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return buf, nil -} - -func (p *FlowSpecComponent) Len(options ...*MarshallingOption) int { - l := 1 - for _, item := range p.Items { - l += item.Len() + 1 - } - return l -} - -func (p *FlowSpecComponent) Type() BGPFlowSpecType { - return p.typ -} - -func formatRaw(op uint8, value uint64) string { - return fmt.Sprintf("op:%b,value:%d", op, value) -} - -func formatNumeric(op uint8, value uint64) string { - cmpFlag := DECNumOp(op & 0x7) // lower 3 bits - if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE { - // Omit value field - return DECNumOp(op).String() - } - return fmt.Sprint(DECNumOp(op).String(), value) -} - -func formatProto(op uint8, value uint64) string { - cmpFlag := DECNumOp(op & 0x7) // lower 3 bits - if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE { - // Omit value field - return DECNumOp(op).String() - } - return fmt.Sprint(DECNumOp(op).String(), Protocol(value).String()) -} - -func formatTCPFlag(op uint8, value uint64) string { - return fmt.Sprint(BitmaskFlagOp(op).String(), TCPFlag(value).String()) -} - -func formatFragment(op uint8, value uint64) string { - return fmt.Sprint(BitmaskFlagOp(op).String(), FragmentFlag(value).String()) -} - -func formatEtherType(op uint8, value uint64) string { - cmpFlag := DECNumOp(op & 0x7) // lower 3 bits - if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE { - // Omit value field - return DECNumOp(op).String() - } - return fmt.Sprint(DECNumOp(op).String(), EthernetType(value).String()) -} - -var flowSpecFormatMap = map[BGPFlowSpecType]func(op uint8, value uint64) string{ - FLOW_SPEC_TYPE_UNKNOWN: formatRaw, - FLOW_SPEC_TYPE_IP_PROTO: formatProto, - FLOW_SPEC_TYPE_PORT: formatNumeric, - FLOW_SPEC_TYPE_DST_PORT: formatNumeric, - FLOW_SPEC_TYPE_SRC_PORT: formatNumeric, - FLOW_SPEC_TYPE_ICMP_TYPE: formatNumeric, - FLOW_SPEC_TYPE_ICMP_CODE: formatNumeric, - FLOW_SPEC_TYPE_TCP_FLAG: formatTCPFlag, - FLOW_SPEC_TYPE_PKT_LEN: formatNumeric, - FLOW_SPEC_TYPE_DSCP: formatNumeric, - FLOW_SPEC_TYPE_FRAGMENT: formatFragment, - FLOW_SPEC_TYPE_LABEL: formatNumeric, - FLOW_SPEC_TYPE_ETHERNET_TYPE: formatEtherType, - FLOW_SPEC_TYPE_LLC_DSAP: formatNumeric, - FLOW_SPEC_TYPE_LLC_SSAP: formatNumeric, - FLOW_SPEC_TYPE_LLC_CONTROL: formatNumeric, - FLOW_SPEC_TYPE_SNAP: formatNumeric, - FLOW_SPEC_TYPE_VID: formatNumeric, - FLOW_SPEC_TYPE_COS: formatNumeric, - FLOW_SPEC_TYPE_INNER_VID: formatNumeric, - FLOW_SPEC_TYPE_INNER_COS: formatNumeric, -} - -func (p *FlowSpecComponent) String() string { - f := flowSpecFormatMap[FLOW_SPEC_TYPE_UNKNOWN] - if _, ok := flowSpecFormatMap[p.typ]; ok { - f = flowSpecFormatMap[p.typ] - } - - items := make([]string, 0, len(p.Items)) - for _, i := range p.Items { - items = append(items, f(i.Op, i.Value)) - } - // Removes leading and tailing spaces - value := strings.TrimSpace(strings.Join(items, "")) - - return fmt.Sprintf("[%s: %s]", p.typ, value) -} - -func (p *FlowSpecComponent) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value []*FlowSpecComponentItem `json:"value"` - }{ - Type: p.Type(), - Value: p.Items, - }) -} - -func NewFlowSpecComponent(typ BGPFlowSpecType, items []*FlowSpecComponentItem) *FlowSpecComponent { - // Set end-of-list bit on the last item and unset them on the others. - for i, v := range items { - if i == len(items)-1 { - v.Op |= 0x80 - } else { - v.Op &^= 0x80 - } - - } - return &FlowSpecComponent{ - Items: items, - typ: typ, - } -} - -type FlowSpecUnknown struct { - Value []byte -} - -func (p *FlowSpecUnknown) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - p.Value = data - return nil -} - -func (p *FlowSpecUnknown) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.Value, nil -} - -func (p *FlowSpecUnknown) Len(options ...*MarshallingOption) int { - return len(p.Value) -} - -func (p *FlowSpecUnknown) Type() BGPFlowSpecType { - if len(p.Value) > 0 { - return BGPFlowSpecType(p.Value[0]) - } - return FLOW_SPEC_TYPE_UNKNOWN -} - -func (p *FlowSpecUnknown) String() string { - return fmt.Sprintf("[unknown:%v]", p.Value) -} - -func (p *FlowSpecUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPFlowSpecType `json:"type"` - Value string `json:"value"` - }{ - Type: p.Type(), - Value: string(p.Value), - }) -} - -type FlowSpecNLRI struct { - PrefixDefault - Value []FlowSpecComponentInterface - rf RouteFamily - rd RouteDistinguisherInterface -} - -func (n *FlowSpecNLRI) AFI() uint16 { - afi, _ := RouteFamilyToAfiSafi(n.rf) - return afi -} - -func (n *FlowSpecNLRI) SAFI() uint8 { - _, safi := RouteFamilyToAfiSafi(n.rf) - return safi -} - -func (n *FlowSpecNLRI) RD() RouteDistinguisherInterface { - return n.rd -} - -func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...*MarshallingOption) error { - if IsAddPathEnabled(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])) - data = data[2:] - } else if len(data) > 1 { - length = int(data[0]) - data = data[1:] - } else { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - - n.rf = rf - - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - if length < 8 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - n.rd = GetRouteDistinguisher(data[:8]) - data = data[8:] - length -= 8 - } - - for l := length; l > 0; { - if len(data) == 0 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available") - } - t := BGPFlowSpecType(data[0]) - var i FlowSpecComponentInterface - switch t { - case FLOW_SPEC_TYPE_DST_PREFIX: - switch { - case rf>>16 == AFI_IP: - i = NewFlowSpecDestinationPrefix(NewIPAddrPrefix(0, "")) - case rf>>16 == AFI_IP6: - i = NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(0, ""), 0) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_SRC_PREFIX: - switch { - case rf>>16 == AFI_IP: - i = NewFlowSpecSourcePrefix(NewIPAddrPrefix(0, "")) - case rf>>16 == AFI_IP6: - i = NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(0, ""), 0) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_SRC_MAC: - switch rf { - case RF_FS_L2_VPN: - i = NewFlowSpecSourceMac(nil) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_DST_MAC: - switch rf { - case RF_FS_L2_VPN: - i = NewFlowSpecDestinationMac(nil) - default: - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf)) - } - case FLOW_SPEC_TYPE_IP_PROTO, FLOW_SPEC_TYPE_PORT, FLOW_SPEC_TYPE_DST_PORT, FLOW_SPEC_TYPE_SRC_PORT, - FLOW_SPEC_TYPE_ICMP_TYPE, FLOW_SPEC_TYPE_ICMP_CODE, FLOW_SPEC_TYPE_TCP_FLAG, FLOW_SPEC_TYPE_PKT_LEN, - FLOW_SPEC_TYPE_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL, FLOW_SPEC_TYPE_ETHERNET_TYPE, - FLOW_SPEC_TYPE_LLC_DSAP, FLOW_SPEC_TYPE_LLC_SSAP, FLOW_SPEC_TYPE_LLC_CONTROL, FLOW_SPEC_TYPE_SNAP, - FLOW_SPEC_TYPE_VID, FLOW_SPEC_TYPE_COS, FLOW_SPEC_TYPE_INNER_VID, FLOW_SPEC_TYPE_INNER_COS: - i = NewFlowSpecComponent(t, nil) - default: - i = &FlowSpecUnknown{} - } - - err := i.DecodeFromBytes(data, options...) - if err != nil { - i = &FlowSpecUnknown{data} - } - l -= i.Len(options...) - data = data[i.Len(options...):] - n.Value = append(n.Value, i) - } - - // Sort Traffic Filtering Rules in types order to avoid the unordered rules - // are determined different. - sort.SliceStable(n.Value, func(i, j int) bool { return n.Value[i].Type() < n.Value[j].Type() }) - - return nil -} - -func (n *FlowSpecNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0, 32) - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - if n.rd == nil { - return nil, fmt.Errorf("RD is nil") - } - b, err := n.rd.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, b...) - } - for _, v := range n.Value { - b, err := v.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, b...) - } - length := n.Len(options...) - if length > 0xfff { - return nil, fmt.Errorf("Too large: %d", length) - } else if length < 0xf0 { - length -= 1 - buf = append([]byte{byte(length)}, buf...) - } else { - length -= 2 - b := make([]byte, 2) - binary.BigEndian.PutUint16(buf, uint16(length)) - buf = append(b, buf...) - } - - if IsAddPathEnabled(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(options ...*MarshallingOption) int { - l := 0 - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - l += n.RD().Len() - } - for _, v := range n.Value { - l += v.Len(options...) - } - if l < 0xf0 { - return l + 1 - } else { - return l + 2 - } -} - -func (n *FlowSpecNLRI) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - buf.WriteString(fmt.Sprintf("[rd: %s]", n.rd)) - } - for _, v := range n.Value { - buf.WriteString(v.String()) - } - return buf.String() -} - -func (n *FlowSpecNLRI) MarshalJSON() ([]byte, error) { - if n.rd != nil { - return json.Marshal(struct { - RD RouteDistinguisherInterface `json:"rd"` - Value []FlowSpecComponentInterface `json:"value"` - }{ - RD: n.rd, - Value: n.Value, - }) - } - return json.Marshal(struct { - Value []FlowSpecComponentInterface `json:"value"` - }{ - Value: n.Value, - }) - -} - -// -// CompareFlowSpecNLRI(n, m) returns -// -1 when m has precedence -// 0 when n and m have same precedence -// 1 when n has precedence -// -func CompareFlowSpecNLRI(n, m *FlowSpecNLRI) (int, error) { - family := AfiSafiToRouteFamily(n.AFI(), n.SAFI()) - if family != AfiSafiToRouteFamily(m.AFI(), m.SAFI()) { - return 0, fmt.Errorf("address family mismatch") - } - longer := n.Value - shorter := m.Value - invert := 1 - if n.SAFI() == SAFI_FLOW_SPEC_VPN { - k, _ := n.Serialize() - l, _ := m.Serialize() - if result := bytes.Compare(k, l); result != 0 { - return result, nil - } - } - if len(n.Value) < len(m.Value) { - longer = m.Value - shorter = n.Value - invert = -1 - } - for idx, v := range longer { - if len(shorter) < idx+1 { - return invert, nil - } - w := shorter[idx] - if v.Type() < w.Type() { - return invert, nil - } else if v.Type() > w.Type() { - return invert * -1, nil - } else if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX || v.Type() == FLOW_SPEC_TYPE_SRC_PREFIX { - // RFC5575 5.1 - // - // For IP prefix values (IP destination and source prefix) precedence is - // given to the lowest IP value of the common prefix length; if the - // common prefix is equal, then the most specific prefix has precedence. - var p, q *IPAddrPrefixDefault - var pCommon, qCommon uint64 - if n.AFI() == AFI_IP { - if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX { - p = &v.(*FlowSpecDestinationPrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecDestinationPrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - } else { - p = &v.(*FlowSpecSourcePrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecSourcePrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault - } - min := p.Length - if q.Length < p.Length { - min = q.Length - } - pCommon = uint64(binary.BigEndian.Uint32([]byte(p.Prefix.To4())) >> (32 - min)) - qCommon = uint64(binary.BigEndian.Uint32([]byte(q.Prefix.To4())) >> (32 - min)) - } else if n.AFI() == AFI_IP6 { - if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX { - p = &v.(*FlowSpecDestinationPrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecDestinationPrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - } else { - p = &v.(*FlowSpecSourcePrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - q = &w.(*FlowSpecSourcePrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault - } - min := uint(p.Length) - if q.Length < p.Length { - min = uint(q.Length) - } - var mask uint - if min-64 > 0 { - mask = min - 64 - } - pCommon = binary.BigEndian.Uint64([]byte(p.Prefix.To16()[:8])) >> mask - qCommon = binary.BigEndian.Uint64([]byte(q.Prefix.To16()[:8])) >> mask - if pCommon == qCommon && mask == 0 { - mask = 64 - min - pCommon = binary.BigEndian.Uint64([]byte(p.Prefix.To16()[8:])) >> mask - qCommon = binary.BigEndian.Uint64([]byte(q.Prefix.To16()[8:])) >> mask - } - } - - if pCommon < qCommon { - return invert, nil - } else if pCommon > qCommon { - return invert * -1, nil - } else if p.Length > q.Length { - return invert, nil - } else if p.Length < q.Length { - return invert * -1, nil - } - - } else { - // RFC5575 5.1 - // - // For all other component types, unless otherwise specified, the - // comparison is performed by comparing the component data as a binary - // string using the memcmp() function as defined by the ISO C standard. - // For strings of different lengths, the common prefix is compared. If - // equal, the longest string is considered to have higher precedence - // than the shorter one. - p, _ := v.Serialize() - q, _ := w.Serialize() - min := len(p) - if len(q) < len(p) { - min = len(q) - } - if result := bytes.Compare(p[:min], q[:min]); result < 0 { - return invert, nil - } else if result > 0 { - return invert * -1, nil - } else if len(p) > len(q) { - return invert, nil - } else if len(q) > len(p) { - return invert * -1, nil - } - } - } - return 0, nil -} - -type FlowSpecIPv4Unicast struct { - FlowSpecNLRI -} - -func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) -} - -func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv4Unicast{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv4_UC, - }, - } -} - -type FlowSpecIPv4VPN struct { - FlowSpecNLRI -} - -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 { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv4VPN{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv4_VPN, - rd: rd, - }, - } -} - -type FlowSpecIPv6Unicast struct { - FlowSpecNLRI -} - -func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...) -} - -func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv6Unicast{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv6_UC, - }, - } -} - -type FlowSpecIPv6VPN struct { - FlowSpecNLRI -} - -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 { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecIPv6VPN{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_IPv6_VPN, - rd: rd, - }, - } -} - -type FlowSpecL2VPN struct { - FlowSpecNLRI -} - -func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data) -} - -func NewFlowSpecL2VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecL2VPN { - sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() }) - return &FlowSpecL2VPN{ - FlowSpecNLRI: FlowSpecNLRI{ - Value: value, - rf: RF_FS_L2_VPN, - rd: rd, - }, - } -} - -type OpaqueNLRI struct { - PrefixDefault - Length uint16 - Key []byte - Value []byte -} - -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 IsAddPathEnabled(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") - } - n.Key = data[2 : 2+n.Length] - n.Value = data[2+n.Length:] - return nil -} - -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...) - buf = append(buf, n.Value...) - if IsAddPathEnabled(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 { - return AFI_OPAQUE -} - -func (n *OpaqueNLRI) SAFI() uint8 { - return SAFI_KEY_VALUE -} - -func (n *OpaqueNLRI) Len(options ...*MarshallingOption) int { - return 2 + len(n.Key) + len(n.Value) -} - -func (n *OpaqueNLRI) String() string { - return fmt.Sprintf("%s", n.Key) -} - -func (n *OpaqueNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Key string `json:"key"` - Value string `json:"value"` - }{ - Key: string(n.Key), - Value: string(n.Value), - }) -} - -func NewOpaqueNLRI(key, value []byte) *OpaqueNLRI { - return &OpaqueNLRI{ - Key: key, - Value: value, - } -} - -func AfiSafiToRouteFamily(afi uint16, safi uint8) RouteFamily { - return RouteFamily(int(afi)<<16 | int(safi)) -} - -func RouteFamilyToAfiSafi(rf RouteFamily) (uint16, uint8) { - return uint16(int(rf) >> 16), uint8(int(rf) & 0xff) -} - -type RouteFamily int - -func (f RouteFamily) String() string { - if n, y := AddressFamilyNameMap[f]; y { - return n - } - return fmt.Sprintf("UnknownFamily(%d)", f) -} - -const ( - RF_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_UNICAST - RF_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_UNICAST - RF_IPv4_MC RouteFamily = AFI_IP<<16 | SAFI_MULTICAST - RF_IPv6_MC RouteFamily = AFI_IP6<<16 | SAFI_MULTICAST - RF_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN - RF_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN - RF_IPv4_VPN_MC RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN_MULTICAST - RF_IPv6_VPN_MC RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN_MULTICAST - RF_IPv4_MPLS RouteFamily = AFI_IP<<16 | SAFI_MPLS_LABEL - RF_IPv6_MPLS RouteFamily = AFI_IP6<<16 | SAFI_MPLS_LABEL - RF_VPLS RouteFamily = AFI_L2VPN<<16 | SAFI_VPLS - RF_EVPN RouteFamily = AFI_L2VPN<<16 | SAFI_EVPN - RF_RTC_UC RouteFamily = AFI_IP<<16 | SAFI_ROUTE_TARGET_CONSTRAINTS - RF_IPv4_ENCAP RouteFamily = AFI_IP<<16 | SAFI_ENCAPSULATION - RF_IPv6_ENCAP RouteFamily = AFI_IP6<<16 | SAFI_ENCAPSULATION - RF_FS_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_UNICAST - RF_FS_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_VPN - RF_FS_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_UNICAST - RF_FS_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_VPN - RF_FS_L2_VPN RouteFamily = AFI_L2VPN<<16 | SAFI_FLOW_SPEC_VPN - RF_OPAQUE RouteFamily = AFI_OPAQUE<<16 | SAFI_KEY_VALUE -) - -var AddressFamilyNameMap = map[RouteFamily]string{ - RF_IPv4_UC: "ipv4-unicast", - RF_IPv6_UC: "ipv6-unicast", - RF_IPv4_MC: "ipv4-multicast", - RF_IPv6_MC: "ipv6-multicast", - RF_IPv4_MPLS: "ipv4-labelled-unicast", - RF_IPv6_MPLS: "ipv6-labelled-unicast", - RF_IPv4_VPN: "l3vpn-ipv4-unicast", - RF_IPv6_VPN: "l3vpn-ipv6-unicast", - RF_IPv4_VPN_MC: "l3vpn-ipv4-multicast", - RF_IPv6_VPN_MC: "l3vpn-ipv6-multicast", - RF_VPLS: "l2vpn-vpls", - RF_EVPN: "l2vpn-evpn", - RF_RTC_UC: "rtc", - RF_IPv4_ENCAP: "ipv4-encap", - RF_IPv6_ENCAP: "ipv6-encap", - RF_FS_IPv4_UC: "ipv4-flowspec", - RF_FS_IPv4_VPN: "l3vpn-ipv4-flowspec", - RF_FS_IPv6_UC: "ipv6-flowspec", - RF_FS_IPv6_VPN: "l3vpn-ipv6-flowspec", - RF_FS_L2_VPN: "l2vpn-flowspec", - RF_OPAQUE: "opaque", -} - -var AddressFamilyValueMap = map[string]RouteFamily{ - AddressFamilyNameMap[RF_IPv4_UC]: RF_IPv4_UC, - AddressFamilyNameMap[RF_IPv6_UC]: RF_IPv6_UC, - AddressFamilyNameMap[RF_IPv4_MC]: RF_IPv4_MC, - AddressFamilyNameMap[RF_IPv6_MC]: RF_IPv6_MC, - AddressFamilyNameMap[RF_IPv4_MPLS]: RF_IPv4_MPLS, - AddressFamilyNameMap[RF_IPv6_MPLS]: RF_IPv6_MPLS, - AddressFamilyNameMap[RF_IPv4_VPN]: RF_IPv4_VPN, - AddressFamilyNameMap[RF_IPv6_VPN]: RF_IPv6_VPN, - AddressFamilyNameMap[RF_IPv4_VPN_MC]: RF_IPv4_VPN_MC, - AddressFamilyNameMap[RF_IPv6_VPN_MC]: RF_IPv6_VPN_MC, - AddressFamilyNameMap[RF_VPLS]: RF_VPLS, - AddressFamilyNameMap[RF_EVPN]: RF_EVPN, - AddressFamilyNameMap[RF_RTC_UC]: RF_RTC_UC, - AddressFamilyNameMap[RF_IPv4_ENCAP]: RF_IPv4_ENCAP, - AddressFamilyNameMap[RF_IPv6_ENCAP]: RF_IPv6_ENCAP, - AddressFamilyNameMap[RF_FS_IPv4_UC]: RF_FS_IPv4_UC, - AddressFamilyNameMap[RF_FS_IPv4_VPN]: RF_FS_IPv4_VPN, - AddressFamilyNameMap[RF_FS_IPv6_UC]: RF_FS_IPv6_UC, - AddressFamilyNameMap[RF_FS_IPv6_VPN]: RF_FS_IPv6_VPN, - AddressFamilyNameMap[RF_FS_L2_VPN]: RF_FS_L2_VPN, - AddressFamilyNameMap[RF_OPAQUE]: RF_OPAQUE, -} - -func GetRouteFamily(name string) (RouteFamily, error) { - if v, ok := AddressFamilyValueMap[name]; ok { - return v, nil - } - return RouteFamily(0), fmt.Errorf("%s isn't a valid route family name", name) -} - -func NewPrefixFromRouteFamily(afi uint16, safi uint8, prefixStr ...string) (prefix AddrPrefixInterface, err error) { - family := AfiSafiToRouteFamily(afi, safi) - - f := func(s string) AddrPrefixInterface { - addr, net, _ := net.ParseCIDR(s) - len, _ := net.Mask.Size() - switch family { - case RF_IPv4_UC, RF_IPv4_MC: - return NewIPAddrPrefix(uint8(len), addr.String()) - } - return NewIPv6AddrPrefix(uint8(len), addr.String()) - } - - switch family { - case RF_IPv4_UC, RF_IPv4_MC: - if len(prefixStr) > 0 { - prefix = f(prefixStr[0]) - } else { - prefix = NewIPAddrPrefix(0, "") - } - case RF_IPv6_UC, RF_IPv6_MC: - if len(prefixStr) > 0 { - prefix = f(prefixStr[0]) - } else { - prefix = NewIPv6AddrPrefix(0, "") - } - case RF_IPv4_VPN: - prefix = NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil) - case RF_IPv6_VPN: - prefix = NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil) - case RF_IPv4_MPLS: - prefix = NewLabeledIPAddrPrefix(0, "", *NewMPLSLabelStack()) - case RF_IPv6_MPLS: - prefix = NewLabeledIPv6AddrPrefix(0, "", *NewMPLSLabelStack()) - case RF_EVPN: - prefix = NewEVPNNLRI(0, nil) - case RF_RTC_UC: - prefix = &RouteTargetMembershipNLRI{} - case RF_IPv4_ENCAP: - prefix = NewEncapNLRI("") - case RF_IPv6_ENCAP: - prefix = NewEncapv6NLRI("") - case RF_FS_IPv4_UC: - prefix = &FlowSpecIPv4Unicast{FlowSpecNLRI{rf: RF_FS_IPv4_UC}} - case RF_FS_IPv4_VPN: - prefix = &FlowSpecIPv4VPN{FlowSpecNLRI{rf: RF_FS_IPv4_VPN}} - case RF_FS_IPv6_UC: - prefix = &FlowSpecIPv6Unicast{FlowSpecNLRI{rf: RF_FS_IPv6_UC}} - case RF_FS_IPv6_VPN: - prefix = &FlowSpecIPv6VPN{FlowSpecNLRI{rf: RF_FS_IPv6_VPN}} - case RF_FS_L2_VPN: - prefix = &FlowSpecL2VPN{FlowSpecNLRI{rf: RF_FS_L2_VPN}} - case RF_OPAQUE: - prefix = &OpaqueNLRI{} - default: - err = fmt.Errorf("unknown route family. AFI: %d, SAFI: %d", afi, safi) - } - return prefix, err -} - -type BGPAttrFlag uint8 - -const ( - BGP_ATTR_FLAG_EXTENDED_LENGTH BGPAttrFlag = 1 << 4 - BGP_ATTR_FLAG_PARTIAL BGPAttrFlag = 1 << 5 - BGP_ATTR_FLAG_TRANSITIVE BGPAttrFlag = 1 << 6 - BGP_ATTR_FLAG_OPTIONAL BGPAttrFlag = 1 << 7 -) - -func (f BGPAttrFlag) String() string { - strs := make([]string, 0, 4) - if f&BGP_ATTR_FLAG_EXTENDED_LENGTH > 0 { - strs = append(strs, "EXTENDED_LENGTH") - } - if f&BGP_ATTR_FLAG_PARTIAL > 0 { - strs = append(strs, "PARTIAL") - } - if f&BGP_ATTR_FLAG_TRANSITIVE > 0 { - strs = append(strs, "TRANSITIVE") - } - if f&BGP_ATTR_FLAG_OPTIONAL > 0 { - strs = append(strs, "OPTIONAL") - } - return strings.Join(strs, "|") -} - -type BGPAttrType uint8 - -const ( - _ BGPAttrType = iota - BGP_ATTR_TYPE_ORIGIN - BGP_ATTR_TYPE_AS_PATH - BGP_ATTR_TYPE_NEXT_HOP - BGP_ATTR_TYPE_MULTI_EXIT_DISC - BGP_ATTR_TYPE_LOCAL_PREF - BGP_ATTR_TYPE_ATOMIC_AGGREGATE - BGP_ATTR_TYPE_AGGREGATOR - BGP_ATTR_TYPE_COMMUNITIES - BGP_ATTR_TYPE_ORIGINATOR_ID - BGP_ATTR_TYPE_CLUSTER_LIST - _ - _ - _ - BGP_ATTR_TYPE_MP_REACH_NLRI // = 14 - BGP_ATTR_TYPE_MP_UNREACH_NLRI - BGP_ATTR_TYPE_EXTENDED_COMMUNITIES - BGP_ATTR_TYPE_AS4_PATH - BGP_ATTR_TYPE_AS4_AGGREGATOR - _ - _ - _ - BGP_ATTR_TYPE_PMSI_TUNNEL // = 22 - BGP_ATTR_TYPE_TUNNEL_ENCAP - _ - BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES // = 25 - BGP_ATTR_TYPE_AIGP // = 26 - BGP_ATTR_TYPE_LARGE_COMMUNITY BGPAttrType = 32 -) - -// NOTIFICATION Error Code RFC 4271 4.5. -const ( - _ = iota - BGP_ERROR_MESSAGE_HEADER_ERROR - BGP_ERROR_OPEN_MESSAGE_ERROR - BGP_ERROR_UPDATE_MESSAGE_ERROR - BGP_ERROR_HOLD_TIMER_EXPIRED - BGP_ERROR_FSM_ERROR - BGP_ERROR_CEASE - BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR -) - -// NOTIFICATION Error Subcode for BGP_ERROR_MESSAGE_HEADER_ERROR -const ( - _ = iota - BGP_ERROR_SUB_CONNECTION_NOT_SYNCHRONIZED - BGP_ERROR_SUB_BAD_MESSAGE_LENGTH - BGP_ERROR_SUB_BAD_MESSAGE_TYPE -) - -// NOTIFICATION Error Subcode for BGP_ERROR_OPEN_MESSAGE_ERROR -const ( - _ = iota - BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER - BGP_ERROR_SUB_BAD_PEER_AS - BGP_ERROR_SUB_BAD_BGP_IDENTIFIER - BGP_ERROR_SUB_UNSUPPORTED_OPTIONAL_PARAMETER - BGP_ERROR_SUB_DEPRECATED_AUTHENTICATION_FAILURE - BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME - BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY -) - -// NOTIFICATION Error Subcode for BGP_ERROR_UPDATE_MESSAGE_ERROR -const ( - _ = iota - BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST - BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE - BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE - BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR - BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR - BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE - BGP_ERROR_SUB_DEPRECATED_ROUTING_LOOP - BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE - BGP_ERROR_SUB_OPTIONAL_ATTRIBUTE_ERROR - BGP_ERROR_SUB_INVALID_NETWORK_FIELD - BGP_ERROR_SUB_MALFORMED_AS_PATH -) - -// NOTIFICATION Error Subcode for BGP_ERROR_HOLD_TIMER_EXPIRED -const ( - _ = iota - BGP_ERROR_SUB_HOLD_TIMER_EXPIRED -) - -// NOTIFICATION Error Subcode for BGP_ERROR_FSM_ERROR -const ( - _ = iota - BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_STATE - BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE - BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_ESTABLISHED_STATE -) - -// NOTIFICATION Error Subcode for BGP_ERROR_CEASE (RFC 4486) -const ( - _ = iota - BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED - BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN - BGP_ERROR_SUB_PEER_DECONFIGURED - BGP_ERROR_SUB_ADMINISTRATIVE_RESET - BGP_ERROR_SUB_CONNECTION_REJECTED - BGP_ERROR_SUB_OTHER_CONFIGURATION_CHANGE - BGP_ERROR_SUB_CONNECTION_COLLISION_RESOLUTION - BGP_ERROR_SUB_OUT_OF_RESOURCES - BGP_ERROR_SUB_HARD_RESET //draft-ietf-idr-bgp-gr-notification-07 -) - -// Constants for BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN and BGP_ERROR_SUB_ADMINISTRATIVE_RESET -const ( - BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX = 128 -) - -// NOTIFICATION Error Subcode for BGP_ERROR_ROUTE_REFRESH -const ( - _ = iota - BGP_ERROR_SUB_INVALID_MESSAGE_LENGTH -) - -type NotificationErrorCode uint16 - -func (c NotificationErrorCode) String() string { - code := uint8(uint16(c) >> 8) - subcode := uint8(uint16(c) & 0xff) - UNDEFINED := "undefined" - codeStr := UNDEFINED - subcodeList := []string{} - switch code { - case BGP_ERROR_MESSAGE_HEADER_ERROR: - codeStr = "header" - subcodeList = []string{ - UNDEFINED, - "connection not synchronized", - "bad message length", - "bad message type"} - case BGP_ERROR_OPEN_MESSAGE_ERROR: - codeStr = "open" - subcodeList = []string{ - UNDEFINED, - "unsupported version number", - "bad peer as", - "bad bgp identifier", - "unsupported optional parameter", - "deprecated authentication failure", - "unacceptable hold time", - "unsupported capability"} - case BGP_ERROR_UPDATE_MESSAGE_ERROR: - codeStr = "update" - subcodeList = []string{ - UNDEFINED, - "malformed attribute list", - "unrecognized well known attribute", - "missing well known attribute", - "attribute flags error", - "attribute length error", - "invalid origin attribute", - "deprecated routing loop", - "invalid next hop attribute", - "optional attribute error", - "invalid network field", - "sub malformed as path"} - case BGP_ERROR_HOLD_TIMER_EXPIRED: - codeStr = "hold timer expired" - subcodeList = []string{ - UNDEFINED, - "hold timer expired"} - case BGP_ERROR_FSM_ERROR: - codeStr = "fsm" - subcodeList = []string{ - UNDEFINED, - "receive unexpected message in opensent state", - "receive unexpected message in openconfirm state", - "receive unexpected message in established state"} - case BGP_ERROR_CEASE: - codeStr = "cease" - subcodeList = []string{ - UNDEFINED, - "maximum number of prefixes reached", - "administrative shutdown", - "peer deconfigured", - "administrative reset", - "connection rejected", - "other configuration change", - "connection collision resolution", - "out of resources"} - case BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR: - codeStr = "route refresh" - subcodeList = []string{"invalid message length"} - } - subcodeStr := func(idx uint8, l []string) string { - if len(l) == 0 || int(idx) > len(l)-1 { - return UNDEFINED - } - return l[idx] - }(subcode, subcodeList) - return fmt.Sprintf("code %v(%v) subcode %v(%v)", code, codeStr, subcode, subcodeStr) -} - -func NewNotificationErrorCode(code, subcode uint8) NotificationErrorCode { - return NotificationErrorCode(uint16(code)<<8 | uint16(subcode)) -} - -var PathAttrFlags map[BGPAttrType]BGPAttrFlag = map[BGPAttrType]BGPAttrFlag{ - BGP_ATTR_TYPE_ORIGIN: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_AS_PATH: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_NEXT_HOP: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_MULTI_EXIT_DISC: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_LOCAL_PREF: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_ATOMIC_AGGREGATE: BGP_ATTR_FLAG_TRANSITIVE, - BGP_ATTR_TYPE_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_ORIGINATOR_ID: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_CLUSTER_LIST: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_MP_REACH_NLRI: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_MP_UNREACH_NLRI: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_AS4_PATH: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_AS4_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_PMSI_TUNNEL: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_TUNNEL_ENCAP: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_AIGP: BGP_ATTR_FLAG_OPTIONAL, - BGP_ATTR_TYPE_LARGE_COMMUNITY: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL, -} - -// getPathAttrFlags returns BGP Path Attribute flags value from its type and -// length (byte length of value field). -func getPathAttrFlags(typ BGPAttrType, length int) BGPAttrFlag { - flags := PathAttrFlags[typ] - if length > 255 { - flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH - } - return flags -} - -type PathAttributeInterface interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) - Len(...*MarshallingOption) int - GetFlags() BGPAttrFlag - GetType() BGPAttrType - String() string - MarshalJSON() ([]byte, error) - Flat() map[string]string -} - -type PathAttribute struct { - Flags BGPAttrFlag - Type BGPAttrType - Length uint16 // length of Value -} - -func (p *PathAttribute) Len(options ...*MarshallingOption) int { - if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { - return 4 + int(p.Length) - } - return 3 + int(p.Length) -} - -func (p *PathAttribute) GetFlags() BGPAttrFlag { - return p.Flags -} - -func (p *PathAttribute) GetType() BGPAttrType { - return p.Type -} - -func (p *PathAttribute) DecodeFromBytes(data []byte, options ...*MarshallingOption) (value []byte, err error) { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - if len(data) < 2 { - return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short") - } - p.Flags = BGPAttrFlag(data[0]) - p.Type = BGPAttrType(data[1]) - if eMsg := validatePathAttributeFlags(p.Type, p.Flags); eMsg != "" { - return nil, NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data, eMsg) - } - - if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { - if len(data) < 4 { - return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short") - } - p.Length = binary.BigEndian.Uint16(data[2:4]) - data = data[4:] - } else { - if len(data) < 3 { - return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short") - } - p.Length = uint16(data[2]) - data = data[3:] - } - if len(data) < int(p.Length) { - return nil, NewMessageError(eCode, eSubCode, data, "attribute value length is short") - } - - return data[:p.Length], nil -} - -func (p *PathAttribute) Serialize(value []byte, options ...*MarshallingOption) ([]byte, error) { - // Note: Do not update "p.Flags" and "p.Length" to avoid data race. - flags := p.Flags - length := uint16(len(value)) - if flags&BGP_ATTR_FLAG_EXTENDED_LENGTH == 0 && length > 255 { - flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH - } - var buf []byte - if flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 { - buf = append(make([]byte, 4), value...) - binary.BigEndian.PutUint16(buf[2:4], length) - } else { - buf = append(make([]byte, 3), value...) - buf[2] = byte(length) - } - buf[0] = uint8(flags) - buf[1] = uint8(p.Type) - return buf, nil -} - -type PathAttributeOrigin struct { - PathAttribute - Value uint8 -} - -func (p *PathAttributeOrigin) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 1 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "Origin attribute length is incorrect") - } - p.Value = value[0] - return nil -} - -func (p *PathAttributeOrigin) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize([]byte{p.Value}, options...) -} - -func (p *PathAttributeOrigin) String() string { - typ := "-" - switch p.Value { - case BGP_ORIGIN_ATTR_TYPE_IGP: - typ = "i" - case BGP_ORIGIN_ATTR_TYPE_EGP: - typ = "e" - case BGP_ORIGIN_ATTR_TYPE_INCOMPLETE: - typ = "?" - } - return fmt.Sprintf("{Origin: %s}", typ) -} - -func (p *PathAttributeOrigin) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value uint8 `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeOrigin(value uint8) *PathAttributeOrigin { - t := BGP_ATTR_TYPE_ORIGIN - return &PathAttributeOrigin{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 1, - }, - Value: value, - } -} - -type AsPathParamFormat struct { - start string - end string - separator string -} - -var asPathParamFormatMap = map[uint8]*AsPathParamFormat{ - BGP_ASPATH_ATTR_TYPE_SET: {"{", "}", ","}, - BGP_ASPATH_ATTR_TYPE_SEQ: {"", "", " "}, - BGP_ASPATH_ATTR_TYPE_CONFED_SET: {"(", ")", " "}, - BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: {"[", "]", ","}, -} - -type AsPathParamInterface interface { - GetType() uint8 - GetAS() []uint32 - Serialize() ([]byte, error) - DecodeFromBytes([]byte) error - Len() int - ASLen() int - MarshalJSON() ([]byte, error) - String() string -} - -func AsPathString(aspath *PathAttributeAsPath) string { - s := bytes.NewBuffer(make([]byte, 0, 64)) - for i, param := range aspath.Value { - segType := param.GetType() - asList := param.GetAS() - if i != 0 { - s.WriteString(" ") - } - - sep := " " - switch segType { - case BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - s.WriteString("(") - case BGP_ASPATH_ATTR_TYPE_CONFED_SET: - s.WriteString("[") - sep = "," - case BGP_ASPATH_ATTR_TYPE_SET: - s.WriteString("{") - sep = "," - } - for j, as := range asList { - s.WriteString(fmt.Sprintf("%d", as)) - if j != len(asList)-1 { - s.WriteString(sep) - } - } - switch segType { - case BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - s.WriteString(")") - case BGP_ASPATH_ATTR_TYPE_CONFED_SET: - s.WriteString("]") - case BGP_ASPATH_ATTR_TYPE_SET: - s.WriteString("}") - } - } - return s.String() -} - -type AsPathParam struct { - Type uint8 - Num uint8 - AS []uint16 -} - -func (a *AsPathParam) GetType() uint8 { - return a.Type -} - -func (a *AsPathParam) GetAS() []uint32 { - nums := make([]uint32, 0, len(a.AS)) - for _, as := range a.AS { - nums = append(nums, uint32(as)) - } - return nums -} - -func (a *AsPathParam) Serialize() ([]byte, error) { - buf := make([]byte, 2+len(a.AS)*2) - buf[0] = uint8(a.Type) - buf[1] = a.Num - for j, as := range a.AS { - binary.BigEndian.PutUint16(buf[2+j*2:], as) - } - return buf, nil -} - -func (a *AsPathParam) DecodeFromBytes(data []byte) error { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) - if len(data) < 2 { - return NewMessageError(eCode, eSubCode, nil, "AS param header length is short") - } - a.Type = data[0] - a.Num = data[1] - data = data[2:] - if len(data) < int(a.Num*2) { - return NewMessageError(eCode, eSubCode, nil, "AS param data length is short") - } - for i := 0; i < int(a.Num); i++ { - a.AS = append(a.AS, binary.BigEndian.Uint16(data)) - data = data[2:] - } - return nil -} - -func (a *AsPathParam) Len() int { - return 2 + len(a.AS)*2 -} - -func (a *AsPathParam) ASLen() int { - switch a.Type { - case BGP_ASPATH_ATTR_TYPE_SEQ: - return len(a.AS) - case BGP_ASPATH_ATTR_TYPE_SET: - return 1 - case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - return 0 - } - return 0 -} - -func (a *AsPathParam) String() string { - format, ok := asPathParamFormatMap[a.Type] - if !ok { - return fmt.Sprintf("%v", a.AS) - } - aspath := make([]string, 0, len(a.AS)) - for _, asn := range a.AS { - aspath = append(aspath, fmt.Sprintf("%d", asn)) - } - s := bytes.NewBuffer(make([]byte, 0, 32)) - s.WriteString(format.start) - s.WriteString(strings.Join(aspath, format.separator)) - s.WriteString(format.end) - return s.String() -} - -func (a *AsPathParam) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint8 `json:"segment_type"` - Num uint8 `json:"num"` - AS []uint16 `json:"asns"` - }{ - Type: a.Type, - Num: a.Num, - AS: a.AS, - }) -} - -func NewAsPathParam(segType uint8, as []uint16) *AsPathParam { - return &AsPathParam{ - Type: segType, - Num: uint8(len(as)), - AS: as, - } -} - -type As4PathParam struct { - Type uint8 - Num uint8 - AS []uint32 -} - -func (a *As4PathParam) GetType() uint8 { - return a.Type -} - -func (a *As4PathParam) GetAS() []uint32 { - return a.AS -} - -func (a *As4PathParam) Serialize() ([]byte, error) { - buf := make([]byte, 2+len(a.AS)*4) - buf[0] = a.Type - buf[1] = a.Num - for j, as := range a.AS { - binary.BigEndian.PutUint32(buf[2+j*4:], as) - } - return buf, nil -} - -func (a *As4PathParam) DecodeFromBytes(data []byte) error { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) - if len(data) < 2 { - return NewMessageError(eCode, eSubCode, nil, "AS4 param header length is short") - } - a.Type = data[0] - a.Num = data[1] - data = data[2:] - if len(data) < int(a.Num)*4 { - return NewMessageError(eCode, eSubCode, nil, "AS4 param data length is short") - } - for i := 0; i < int(a.Num); i++ { - a.AS = append(a.AS, binary.BigEndian.Uint32(data)) - data = data[4:] - } - return nil -} - -func (a *As4PathParam) Len() int { - return 2 + len(a.AS)*4 -} - -func (a *As4PathParam) ASLen() int { - switch a.Type { - case BGP_ASPATH_ATTR_TYPE_SEQ: - return len(a.AS) - case BGP_ASPATH_ATTR_TYPE_SET: - return 1 - case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - return 0 - } - return 0 -} - -func (a *As4PathParam) String() string { - format, ok := asPathParamFormatMap[a.Type] - if !ok { - return fmt.Sprintf("%v", a.AS) - } - aspath := make([]string, 0, len(a.AS)) - for _, asn := range a.AS { - aspath = append(aspath, fmt.Sprintf("%d", asn)) - } - s := bytes.NewBuffer(make([]byte, 0, 32)) - s.WriteString(format.start) - s.WriteString(strings.Join(aspath, format.separator)) - s.WriteString(format.end) - return s.String() -} - -func (a *As4PathParam) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type uint8 `json:"segment_type"` - Num uint8 `json:"num"` - AS []uint32 `json:"asns"` - }{ - Type: a.Type, - Num: a.Num, - AS: a.AS, - }) -} - -func NewAs4PathParam(segType uint8, as []uint32) *As4PathParam { - return &As4PathParam{ - Type: segType, - Num: uint8(len(as)), - AS: as, - } -} - -type PathAttributeAsPath struct { - PathAttribute - Value []AsPathParamInterface -} - -func (p *PathAttributeAsPath) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length == 0 { - // ibgp or something - return nil - } - isAs4, err := validateAsPathValueBytes(value) - if err != nil { - err.(*MessageError).Data, _ = p.PathAttribute.Serialize(value, options...) - return err - } - for len(value) > 0 { - var tuple AsPathParamInterface - if isAs4 { - tuple = &As4PathParam{} - } else { - tuple = &AsPathParam{} - } - err := tuple.DecodeFromBytes(value) - if err != nil { - return err - } - p.Value = append(p.Value, tuple) - value = value[tuple.Len():] - } - return nil -} - -func (p *PathAttributeAsPath) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, v := range p.Value { - vbuf, err := v.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, vbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAsPath) String() string { - params := make([]string, 0, len(p.Value)) - for _, param := range p.Value { - params = append(params, param.String()) - } - return strings.Join(params, " ") -} - -func (p *PathAttributeAsPath) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []AsPathParamInterface `json:"as_paths"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeAsPath(value []AsPathParamInterface) *PathAttributeAsPath { - var l int - for _, v := range value { - l += v.Len() - } - t := BGP_ATTR_TYPE_AS_PATH - return &PathAttributeAsPath{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeNextHop struct { - PathAttribute - Value net.IP -} - -func (p *PathAttributeNextHop) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 && p.Length != 16 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "nexthop length isn't correct") - } - p.Value = value - return nil -} - -func (p *PathAttributeNextHop) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize(p.Value, options...) -} - -func (p *PathAttributeNextHop) String() string { - return fmt.Sprintf("{Nexthop: %s}", p.Value) -} - -func (p *PathAttributeNextHop) MarshalJSON() ([]byte, error) { - value := "0.0.0.0" - if p.Value != nil { - value = p.Value.String() - } - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value string `json:"nexthop"` - }{ - Type: p.GetType(), - Value: value, - }) -} - -func NewPathAttributeNextHop(value string) *PathAttributeNextHop { - t := BGP_ATTR_TYPE_NEXT_HOP - return &PathAttributeNextHop{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: net.ParseIP(value).To4(), - } -} - -type PathAttributeMultiExitDisc struct { - PathAttribute - Value uint32 -} - -func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "med length isn't correct") - } - p.Value = binary.BigEndian.Uint32(value) - return nil -} - -func (p *PathAttributeMultiExitDisc) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, p.Value) - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeMultiExitDisc) String() string { - return fmt.Sprintf("{Med: %d}", p.Value) -} - -func (p *PathAttributeMultiExitDisc) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value uint32 `json:"metric"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeMultiExitDisc(value uint32) *PathAttributeMultiExitDisc { - t := BGP_ATTR_TYPE_MULTI_EXIT_DISC - return &PathAttributeMultiExitDisc{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: value, - } -} - -type PathAttributeLocalPref struct { - PathAttribute - Value uint32 -} - -func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "local pref length isn't correct") - } - p.Value = binary.BigEndian.Uint32(value) - return nil -} - -func (p *PathAttributeLocalPref) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, p.Value) - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeLocalPref) String() string { - return fmt.Sprintf("{LocalPref: %d}", p.Value) -} - -func (p *PathAttributeLocalPref) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value uint32 `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeLocalPref(value uint32) *PathAttributeLocalPref { - t := BGP_ATTR_TYPE_LOCAL_PREF - return &PathAttributeLocalPref{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: value, - } -} - -type PathAttributeAtomicAggregate struct { - PathAttribute -} - -func (p *PathAttributeAtomicAggregate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - _, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "atomic aggregate should have no value") - } - return nil -} - -func (p *PathAttributeAtomicAggregate) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize(nil, options...) -} - -func (p *PathAttributeAtomicAggregate) String() string { - return "{AtomicAggregate}" -} - -func (p *PathAttributeAtomicAggregate) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - }{ - Type: p.GetType(), - }) -} - -func NewPathAttributeAtomicAggregate() *PathAttributeAtomicAggregate { - t := BGP_ATTR_TYPE_ATOMIC_AGGREGATE - return &PathAttributeAtomicAggregate{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 0, - }, - } -} - -type PathAttributeAggregatorParam struct { - AS uint32 - Askind reflect.Kind - Address net.IP -} - -type PathAttributeAggregator struct { - PathAttribute - Value PathAttributeAggregatorParam -} - -func (p *PathAttributeAggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - switch p.Length { - case 6: - p.Value.Askind = reflect.Uint16 - p.Value.AS = uint32(binary.BigEndian.Uint16(value[0:2])) - p.Value.Address = value[2:] - case 8: - p.Value.Askind = reflect.Uint32 - p.Value.AS = binary.BigEndian.Uint32(value[0:4]) - p.Value.Address = value[4:] - default: - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "aggregator length isn't correct") - } - return nil -} - -func (p *PathAttributeAggregator) Serialize(options ...*MarshallingOption) ([]byte, error) { - var buf []byte - switch p.Value.Askind { - case reflect.Uint16: - buf = make([]byte, 6) - binary.BigEndian.PutUint16(buf, uint16(p.Value.AS)) - copy(buf[2:], p.Value.Address) - case reflect.Uint32: - buf = make([]byte, 8) - binary.BigEndian.PutUint32(buf, p.Value.AS) - copy(buf[4:], p.Value.Address) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAggregator) String() string { - return fmt.Sprintf("{Aggregate: {AS: %d, Address: %s}}", p.Value.AS, p.Value.Address) -} - -func (p *PathAttributeAggregator) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - AS uint32 `json:"as"` - Address string `json:"address"` - }{ - Type: p.GetType(), - AS: p.Value.AS, - Address: p.Value.Address.String(), - }) -} - -func NewPathAttributeAggregator(as interface{}, address string) *PathAttributeAggregator { - v := reflect.ValueOf(as) - asKind := v.Kind() - var l uint16 - switch asKind { - case reflect.Uint16: - l = 6 - case reflect.Uint32: - l = 8 - default: - // Invalid type - return nil - } - t := BGP_ATTR_TYPE_AGGREGATOR - return &PathAttributeAggregator{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: l, - }, - Value: PathAttributeAggregatorParam{ - AS: uint32(v.Uint()), - Askind: asKind, - Address: net.ParseIP(address).To4(), - }, - } -} - -type PathAttributeCommunities struct { - PathAttribute - Value []uint32 -} - -func (p *PathAttributeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length%4 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "communities length isn't correct") - } - for len(value) >= 4 { - p.Value = append(p.Value, binary.BigEndian.Uint32(value)) - value = value[4:] - } - return nil -} - -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) - } - return p.PathAttribute.Serialize(buf, options...) -} - -type WellKnownCommunity uint32 - -const ( - COMMUNITY_INTERNET WellKnownCommunity = 0x00000000 - COMMUNITY_PLANNED_SHUT WellKnownCommunity = 0xffff0000 - COMMUNITY_ACCEPT_OWN WellKnownCommunity = 0xffff0001 - COMMUNITY_ROUTE_FILTER_TRANSLATED_v4 WellKnownCommunity = 0xffff0002 - COMMUNITY_ROUTE_FILTER_v4 WellKnownCommunity = 0xffff0003 - COMMUNITY_ROUTE_FILTER_TRANSLATED_v6 WellKnownCommunity = 0xffff0004 - COMMUNITY_ROUTE_FILTER_v6 WellKnownCommunity = 0xffff0005 - COMMUNITY_LLGR_STALE WellKnownCommunity = 0xffff0006 - COMMUNITY_NO_LLGR WellKnownCommunity = 0xffff0007 - COMMUNITY_BLACKHOLE WellKnownCommunity = 0xffff029a - COMMUNITY_NO_EXPORT WellKnownCommunity = 0xffffff01 - COMMUNITY_NO_ADVERTISE WellKnownCommunity = 0xffffff02 - COMMUNITY_NO_EXPORT_SUBCONFED WellKnownCommunity = 0xffffff03 - COMMUNITY_NO_PEER WellKnownCommunity = 0xffffff04 -) - -var WellKnownCommunityNameMap = map[WellKnownCommunity]string{ - COMMUNITY_INTERNET: "internet", - COMMUNITY_PLANNED_SHUT: "planned-shut", - COMMUNITY_ACCEPT_OWN: "accept-own", - COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: "route-filter-translated-v4", - COMMUNITY_ROUTE_FILTER_v4: "route-filter-v4", - COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: "route-filter-translated-v6", - COMMUNITY_ROUTE_FILTER_v6: "route-filter-v6", - COMMUNITY_LLGR_STALE: "llgr-stale", - COMMUNITY_NO_LLGR: "no-llgr", - COMMUNITY_BLACKHOLE: "blackhole", - COMMUNITY_NO_EXPORT: "no-export", - COMMUNITY_NO_ADVERTISE: "no-advertise", - COMMUNITY_NO_EXPORT_SUBCONFED: "no-export-subconfed", - COMMUNITY_NO_PEER: "no-peer", -} - -var WellKnownCommunityValueMap = map[string]WellKnownCommunity{ - WellKnownCommunityNameMap[COMMUNITY_INTERNET]: COMMUNITY_INTERNET, - WellKnownCommunityNameMap[COMMUNITY_PLANNED_SHUT]: COMMUNITY_PLANNED_SHUT, - WellKnownCommunityNameMap[COMMUNITY_ACCEPT_OWN]: COMMUNITY_ACCEPT_OWN, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_TRANSLATED_v4]: COMMUNITY_ROUTE_FILTER_TRANSLATED_v4, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_v4]: COMMUNITY_ROUTE_FILTER_v4, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_TRANSLATED_v6]: COMMUNITY_ROUTE_FILTER_TRANSLATED_v6, - WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_v6]: COMMUNITY_ROUTE_FILTER_v6, - WellKnownCommunityNameMap[COMMUNITY_LLGR_STALE]: COMMUNITY_LLGR_STALE, - WellKnownCommunityNameMap[COMMUNITY_NO_LLGR]: COMMUNITY_NO_LLGR, - WellKnownCommunityNameMap[COMMUNITY_NO_EXPORT]: COMMUNITY_NO_EXPORT, - WellKnownCommunityNameMap[COMMUNITY_BLACKHOLE]: COMMUNITY_BLACKHOLE, - WellKnownCommunityNameMap[COMMUNITY_NO_ADVERTISE]: COMMUNITY_NO_ADVERTISE, - WellKnownCommunityNameMap[COMMUNITY_NO_EXPORT_SUBCONFED]: COMMUNITY_NO_EXPORT_SUBCONFED, - WellKnownCommunityNameMap[COMMUNITY_NO_PEER]: COMMUNITY_NO_PEER, -} - -func (p *PathAttributeCommunities) String() string { - l := []string{} - for _, v := range p.Value { - n, ok := WellKnownCommunityNameMap[WellKnownCommunity(v)] - if ok { - l = append(l, n) - } else { - l = append(l, fmt.Sprintf("%d:%d", (0xffff0000&v)>>16, 0xffff&v)) - } - } - return fmt.Sprintf("{Communities: %s}", strings.Join(l, ", ")) -} - -func (p *PathAttributeCommunities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []uint32 `json:"communities"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeCommunities(value []uint32) *PathAttributeCommunities { - l := len(value) * 4 - t := BGP_ATTR_TYPE_COMMUNITIES - return &PathAttributeCommunities{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeOriginatorId struct { - PathAttribute - Value net.IP -} - -func (p *PathAttributeOriginatorId) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 4 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "originator id length isn't correct") - } - p.Value = value - return nil -} - -func (p *PathAttributeOriginatorId) String() string { - return fmt.Sprintf("{Originator: %s}", p.Value) -} - -func (p *PathAttributeOriginatorId) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value string `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value.String(), - }) -} - -func (p *PathAttributeOriginatorId) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 4) - copy(buf, p.Value) - return p.PathAttribute.Serialize(buf, options...) -} - -func NewPathAttributeOriginatorId(value string) *PathAttributeOriginatorId { - t := BGP_ATTR_TYPE_ORIGINATOR_ID - return &PathAttributeOriginatorId{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 4, - }, - Value: net.ParseIP(value).To4(), - } -} - -type PathAttributeClusterList struct { - PathAttribute - Value []net.IP -} - -func (p *PathAttributeClusterList) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length%4 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "clusterlist length isn't correct") - } - for len(value) >= 4 { - p.Value = append(p.Value, value[:4]) - value = value[4:] - } - return nil -} - -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) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeClusterList) String() string { - return fmt.Sprintf("{ClusterList: %v}", p.Value) -} - -func (p *PathAttributeClusterList) MarshalJSON() ([]byte, error) { - value := make([]string, 0, len(p.Value)) - for _, v := range p.Value { - value = append(value, v.String()) - } - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []string `json:"value"` - }{ - Type: p.GetType(), - Value: value, - }) -} - -func NewPathAttributeClusterList(value []string) *PathAttributeClusterList { - l := len(value) * 4 - list := make([]net.IP, len(value)) - for i, v := range value { - list[i] = net.ParseIP(v).To4() - } - t := BGP_ATTR_TYPE_CLUSTER_LIST - return &PathAttributeClusterList{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: list, - } -} - -type PathAttributeMpReachNLRI struct { - PathAttribute - Nexthop net.IP - LinkLocalNexthop net.IP - AFI uint16 - SAFI uint8 - Value []AddrPrefixInterface -} - -func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - eData, _ := p.PathAttribute.Serialize(value, options...) - if p.Length < 3 { - return NewMessageError(eCode, eSubCode, value, "mpreach header length is short") - } - afi := binary.BigEndian.Uint16(value[0:2]) - safi := value[2] - p.AFI = afi - p.SAFI = safi - _, err = NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error()) - } - nexthoplen := int(value[3]) - if len(value) < 4+nexthoplen { - return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is short") - } - nexthopbin := value[4 : 4+nexthoplen] - if nexthoplen > 0 { - v4addrlen := 4 - v6addrlen := 16 - offset := 0 - if safi == SAFI_MPLS_VPN { - offset = 8 - } - switch nexthoplen { - case 2 * (offset + v6addrlen): - p.LinkLocalNexthop = nexthopbin[offset+v6addrlen+offset : 2*(offset+v6addrlen)] - fallthrough - case offset + v6addrlen: - p.Nexthop = nexthopbin[offset : offset+v6addrlen] - case offset + v4addrlen: - p.Nexthop = nexthopbin[offset : offset+v4addrlen] - default: - return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is incorrect") - } - } - value = value[4+nexthoplen:] - // skip reserved - if len(value) == 0 { - return NewMessageError(eCode, eSubCode, value, "no skip byte") - } - value = value[1:] - addpathLen := 0 - if IsAddPathEnabled(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_INVALID_NETWORK_FIELD, eData, err.Error()) - } - err = prefix.DecodeFromBytes(value, options...) - if err != nil { - return err - } - if prefix.Len(options...)+addpathLen > len(value) { - return NewMessageError(eCode, eSubCode, value, "prefix length is incorrect") - } - value = value[prefix.Len(options...)+addpathLen:] - p.Value = append(p.Value, prefix) - } - return nil -} - -func (p *PathAttributeMpReachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) { - afi := p.AFI - safi := p.SAFI - nexthoplen := 4 - if afi == AFI_IP6 || p.Nexthop.To4() == nil { - nexthoplen = 16 - } - offset := 0 - switch safi { - case SAFI_MPLS_VPN: - offset = 8 - nexthoplen += offset - case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST: - nexthoplen = 0 - } - if p.LinkLocalNexthop != nil { - nexthoplen *= 2 - } - buf := make([]byte, 4+nexthoplen) - binary.BigEndian.PutUint16(buf[0:], afi) - buf[2] = safi - buf[3] = uint8(nexthoplen) - if nexthoplen != 0 { - if p.Nexthop.To4() == nil { - copy(buf[4+offset:], p.Nexthop.To16()) - if p.LinkLocalNexthop != nil { - copy(buf[4+offset+16:], p.LinkLocalNexthop.To16()) - } - } else { - copy(buf[4+offset:], p.Nexthop) - } - } - buf = append(buf, make([]byte, 1)...) - for _, prefix := range p.Value { - pbuf, err := prefix.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeMpReachNLRI) MarshalJSON() ([]byte, error) { - nexthop := p.Nexthop.String() - if p.Nexthop == nil { - switch p.AFI { - case AFI_IP: - nexthop = "0.0.0.0" - case AFI_IP6: - nexthop = "::" - default: - nexthop = "fictitious" - } - } - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Nexthop string `json:"nexthop"` - AFI uint16 `json:"afi"` - SAFI uint8 `json:"safi"` - Value []AddrPrefixInterface `json:"value"` - }{ - Type: p.GetType(), - Nexthop: nexthop, - AFI: p.AFI, - SAFI: p.SAFI, - Value: p.Value, - }) -} - -func (p *PathAttributeMpReachNLRI) String() string { - return fmt.Sprintf("{MpReach(%s): {Nexthop: %s, NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Nexthop, p.Value) -} - -func NewPathAttributeMpReachNLRI(nexthop string, nlri []AddrPrefixInterface) *PathAttributeMpReachNLRI { - // AFI(2) + SAFI(1) + NexthopLength(1) + Nexthop(variable) - // + Reserved(1) + NLRI(variable) - l := 5 - var afi uint16 - var safi uint8 - if len(nlri) > 0 { - afi = nlri[0].AFI() - safi = nlri[0].SAFI() - } - nh := net.ParseIP(nexthop) - if nh.To4() != nil && afi != AFI_IP6 { - nh = nh.To4() - switch safi { - case SAFI_MPLS_VPN: - l += 12 - case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST: - // Should not have Nexthop - default: - l += 4 - } - } else { - switch safi { - case SAFI_MPLS_VPN: - l += 24 - case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST: - // Should not have Nexthop - default: - l += 16 - } - } - var nlriLen int - for _, n := range nlri { - l += n.Len() - nBuf, _ := n.Serialize() - nlriLen += len(nBuf) - } - t := BGP_ATTR_TYPE_MP_REACH_NLRI - return &PathAttributeMpReachNLRI{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Nexthop: nh, - AFI: afi, - SAFI: safi, - Value: nlri, - } -} - -type PathAttributeMpUnreachNLRI struct { - PathAttribute - AFI uint16 - SAFI uint8 - Value []AddrPrefixInterface -} - -func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - eData, _ := p.PathAttribute.Serialize(value, options...) - if p.Length < 3 { - return NewMessageError(eCode, eSubCode, value, "unreach header length is incorrect") - } - afi := binary.BigEndian.Uint16(value[0:2]) - safi := value[2] - _, err = NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error()) - } - value = value[3:] - p.AFI = afi - p.SAFI = safi - addpathLen := 0 - if IsAddPathEnabled(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_INVALID_NETWORK_FIELD, eData, err.Error()) - } - err = prefix.DecodeFromBytes(value, options...) - if err != nil { - return err - } - if prefix.Len(options...)+addpathLen > len(value) { - return NewMessageError(eCode, eSubCode, eData, "prefix length is incorrect") - } - value = value[prefix.Len(options...)+addpathLen:] - p.Value = append(p.Value, prefix) - } - return nil -} - -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(options...) - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeMpUnreachNLRI) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - AFI uint16 `json:"afi"` - SAFI uint8 `json:"safi"` - Value []AddrPrefixInterface `json:"value"` - }{ - Type: p.GetType(), - AFI: p.AFI, - SAFI: p.SAFI, - Value: p.Value, - }) -} - -func (p *PathAttributeMpUnreachNLRI) String() string { - if len(p.Value) > 0 { - return fmt.Sprintf("{MpUnreach(%s): {NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Value) - } - return fmt.Sprintf("{MpUnreach(%s): End-of-Rib}", AfiSafiToRouteFamily(p.AFI, p.SAFI)) -} - -func NewPathAttributeMpUnreachNLRI(nlri []AddrPrefixInterface) *PathAttributeMpUnreachNLRI { - // AFI(2) + SAFI(1) + NLRI(variable) - l := 3 - var afi uint16 - var safi uint8 - if len(nlri) > 0 { - afi = nlri[0].AFI() - safi = nlri[0].SAFI() - } - for _, n := range nlri { - l += n.Len() - } - t := BGP_ATTR_TYPE_MP_UNREACH_NLRI - return &PathAttributeMpUnreachNLRI{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - AFI: afi, - SAFI: safi, - Value: nlri, - } -} - -type ExtendedCommunityInterface interface { - Serialize() ([]byte, error) - String() string - GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) - MarshalJSON() ([]byte, error) - Flat() map[string]string -} - -type TwoOctetAsSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - AS uint16 - LocalAdmin uint32 - IsTransitive bool -} - -func (e *TwoOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) - } - buf[1] = byte(e.SubType) - binary.BigEndian.PutUint16(buf[2:], e.AS) - binary.BigEndian.PutUint32(buf[4:], e.LocalAdmin) - return buf, nil -} - -func (e *TwoOctetAsSpecificExtended) String() string { - return fmt.Sprintf("%d:%d", e.AS, e.LocalAdmin) -} - -func (e *TwoOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *TwoOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC - } - return t, e.SubType -} - -func NewTwoOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uint16, localAdmin uint32, isTransitive bool) *TwoOctetAsSpecificExtended { - return &TwoOctetAsSpecificExtended{ - SubType: subtype, - AS: as, - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -type IPv4AddressSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - IPv4 net.IP - LocalAdmin uint16 - IsTransitive bool -} - -func (e *IPv4AddressSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC) - } - buf[1] = byte(e.SubType) - copy(buf[2:6], e.IPv4) - binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin) - return buf, nil -} - -func (e *IPv4AddressSpecificExtended) String() string { - return fmt.Sprintf("%s:%d", e.IPv4.String(), e.LocalAdmin) -} - -func (e *IPv4AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *IPv4AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_IP4_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC - } - return t, e.SubType -} - -func NewIPv4AddressSpecificExtended(subtype ExtendedCommunityAttrSubType, ip string, localAdmin uint16, isTransitive bool) *IPv4AddressSpecificExtended { - ipv4 := net.ParseIP(ip) - if ipv4.To4() == nil { - return nil - } - return &IPv4AddressSpecificExtended{ - SubType: subtype, - IPv4: ipv4.To4(), - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -type IPv6AddressSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - IPv6 net.IP - LocalAdmin uint16 - IsTransitive bool -} - -func (e *IPv6AddressSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 20) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_IP6_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC) - } - buf[1] = byte(e.SubType) - copy(buf[2:18], e.IPv6) - binary.BigEndian.PutUint16(buf[18:], e.LocalAdmin) - return buf, nil -} - -func (e *IPv6AddressSpecificExtended) String() string { - return fmt.Sprintf("%s:%d", e.IPv6.String(), e.LocalAdmin) -} - -func (e *IPv6AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *IPv6AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_IP6_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC - } - return t, e.SubType -} - -func NewIPv6AddressSpecificExtended(subtype ExtendedCommunityAttrSubType, ip string, localAdmin uint16, isTransitive bool) *IPv6AddressSpecificExtended { - ipv6 := net.ParseIP(ip) - if ipv6.To16() == nil { - return nil - } - return &IPv6AddressSpecificExtended{ - SubType: subtype, - IPv6: ipv6.To16(), - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -type FourOctetAsSpecificExtended struct { - SubType ExtendedCommunityAttrSubType - AS uint32 - LocalAdmin uint16 - IsTransitive bool -} - -func (e *FourOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) - } - buf[1] = byte(e.SubType) - binary.BigEndian.PutUint32(buf[2:], e.AS) - binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin) - return buf, nil -} - -func (e *FourOctetAsSpecificExtended) String() string { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, e.AS) - asUpper := binary.BigEndian.Uint16(buf[0:2]) - asLower := binary.BigEndian.Uint16(buf[2:]) - return fmt.Sprintf("%d.%d:%d", asUpper, asLower, e.LocalAdmin) -} - -func (e *FourOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.String(), - }) -} - -func (e *FourOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - t := EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC - if !e.IsTransitive { - t = EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC - } - return t, e.SubType -} - -func NewFourOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uint32, localAdmin uint16, isTransitive bool) *FourOctetAsSpecificExtended { - return &FourOctetAsSpecificExtended{ - SubType: subtype, - AS: as, - LocalAdmin: localAdmin, - IsTransitive: isTransitive, - } -} - -func ParseExtendedCommunity(subtype ExtendedCommunityAttrSubType, com string) (ExtendedCommunityInterface, error) { - if subtype == EC_SUBTYPE_ORIGIN_VALIDATION { - var state ValidationState - switch com { - case VALIDATION_STATE_VALID.String(): - state = VALIDATION_STATE_VALID - case VALIDATION_STATE_NOT_FOUND.String(): - state = VALIDATION_STATE_NOT_FOUND - case VALIDATION_STATE_INVALID.String(): - state = VALIDATION_STATE_INVALID - default: - return nil, fmt.Errorf("invalid validation state") - } - return &ValidationExtended{ - State: state, - }, nil - } - elems, err := parseRdAndRt(com) - if err != nil { - return nil, err - } - localAdmin, _ := strconv.ParseUint(elems[10], 10, 32) - ip := net.ParseIP(elems[1]) - isTransitive := true - switch { - case ip.To4() != nil: - return NewIPv4AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil - case ip.To16() != nil: - return NewIPv6AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil - case elems[6] == "" && elems[7] == "": - asn, _ := strconv.ParseUint(elems[8], 10, 16) - return NewTwoOctetAsSpecificExtended(subtype, uint16(asn), uint32(localAdmin), isTransitive), nil - default: - fst, _ := strconv.ParseUint(elems[7], 10, 16) - snd, _ := strconv.ParseUint(elems[8], 10, 16) - asn := fst<<16 | snd - return NewFourOctetAsSpecificExtended(subtype, uint32(asn), uint16(localAdmin), isTransitive), nil - } -} - -func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) { - return ParseExtendedCommunity(EC_SUBTYPE_ROUTE_TARGET, rt) -} - -func SerializeExtendedCommunities(comms []ExtendedCommunityInterface) ([][]byte, error) { - var bufs [][]byte - var err error - for _, c := range comms { - buf, err := c.Serialize() - if err != nil { - return nil, err - } - bufs = append(bufs, buf) - } - return bufs, err -} - -type ValidationState uint8 - -const ( - VALIDATION_STATE_VALID ValidationState = 0 - VALIDATION_STATE_NOT_FOUND ValidationState = 1 - VALIDATION_STATE_INVALID ValidationState = 2 -) - -func (s ValidationState) String() string { - switch s { - case VALIDATION_STATE_VALID: - return "valid" - case VALIDATION_STATE_NOT_FOUND: - return "not-found" - case VALIDATION_STATE_INVALID: - return "invalid" - } - return fmt.Sprintf("unknown validation state(%d)", s) -} - -type ValidationExtended struct { - State ValidationState -} - -func (e *ValidationExtended) Serialize() ([]byte, error) { - buf := make([]byte, 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.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 { - Color uint32 -} - -func (e *ColorExtended) Serialize() ([]byte, error) { - buf := make([]byte, 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.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 { - TunnelType TunnelType -} - -func (e *EncapExtended) Serialize() ([]byte, error) { - buf := make([]byte, 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 -} - -func (e *EncapExtended) String() string { - switch e.TunnelType { - case TUNNEL_TYPE_L2TP3: - return "L2TPv3 over IP" - case TUNNEL_TYPE_GRE: - return "GRE" - case TUNNEL_TYPE_IP_IN_IP: - return "IP in IP" - case TUNNEL_TYPE_VXLAN: - return "VXLAN" - case TUNNEL_TYPE_NVGRE: - return "NVGRE" - case TUNNEL_TYPE_MPLS: - return "MPLS" - case TUNNEL_TYPE_MPLS_IN_GRE: - return "MPLS in GRE" - case TUNNEL_TYPE_VXLAN_GRE: - return "VXLAN GRE" - case TUNNEL_TYPE_MPLS_IN_UDP: - return "MPLS in UDP" - default: - return fmt.Sprintf("tunnel: %d", e.TunnelType) - } -} - -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, 8) - typ, subType := e.GetTypes() - buf[0] = byte(typ) - buf[1] = byte(subType) - return buf, nil -} - -func (e *DefaultGatewayExtended) String() string { - return "default-gateway" -} - -func (e *DefaultGatewayExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_DEFAULT_GATEWAY -} - -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, - }) -} - -func NewDefaultGatewayExtended() *DefaultGatewayExtended { - return &DefaultGatewayExtended{} -} - -type OpaqueExtended struct { - IsTransitive bool - Value []byte -} - -func (e *OpaqueExtended) Serialize() ([]byte, error) { - if len(e.Value) != 7 { - return nil, fmt.Errorf("invalid value length for opaque extended community: %d", len(e.Value)) - } - buf := make([]byte, 8) - if e.IsTransitive { - buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) - } else { - buf[0] = byte(EC_TYPE_NON_TRANSITIVE_OPAQUE) - } - copy(buf[1:], e.Value) - return buf, nil -} - -func (e *OpaqueExtended) String() string { - buf := make([]byte, 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) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value []byte `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.Value, - }) -} - -func NewOpaqueExtended(isTransitive bool, value []byte) *OpaqueExtended { - v := make([]byte, 7) - copy(v, value) - return &OpaqueExtended{ - IsTransitive: isTransitive, - Value: v, - } -} - -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 { - Label uint32 - IsSingleActive bool -} - -func (e *ESILabelExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_ESI_LABEL) - if e.IsSingleActive { - buf[2] = byte(1) - } - buf[3] = 0 - buf[4] = 0 - buf[5] = byte((e.Label >> 16) & 0xff) - buf[6] = byte((e.Label >> 8) & 0xff) - buf[7] = byte(e.Label & 0xff) - return buf, nil -} - -func (e *ESILabelExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString(fmt.Sprintf("esi-label: %d", e.Label)) - if e.IsSingleActive { - buf.WriteString(", single-active") - } - return buf.String() -} - -func (e *ESILabelExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Label uint32 `json:"label"` - IsSingleActive bool `json:"is_single_active"` - }{ - Type: t, - Subtype: s, - Label: e.Label, - IsSingleActive: e.IsSingleActive, - }) -} - -func (e *ESILabelExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_ESI_LABEL -} - -func NewESILabelExtended(label uint32, isSingleActive bool) *ESILabelExtended { - return &ESILabelExtended{ - Label: label, - IsSingleActive: isSingleActive, - } -} - -type ESImportRouteTarget struct { - ESImport net.HardwareAddr -} - -func (e *ESImportRouteTarget) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_ES_IMPORT) - copy(buf[2:], e.ESImport) - return buf, nil -} - -func (e *ESImportRouteTarget) String() string { - return fmt.Sprintf("es-import rt: %s", e.ESImport.String()) -} - -func (e *ESImportRouteTarget) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.ESImport.String(), - }) -} - -func (e *ESImportRouteTarget) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_ES_IMPORT -} - -func NewESImportRouteTarget(mac string) *ESImportRouteTarget { - esImport, err := net.ParseMAC(mac) - if err != nil { - return nil - } - return &ESImportRouteTarget{ - ESImport: esImport, - } -} - -type MacMobilityExtended struct { - Sequence uint32 - IsSticky bool -} - -func (e *MacMobilityExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_MAC_MOBILITY) - if e.IsSticky { - buf[2] = byte(1) - } - binary.BigEndian.PutUint32(buf[4:], e.Sequence) - return buf, nil -} - -func (e *MacMobilityExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString(fmt.Sprintf("mac-mobility: %d", e.Sequence)) - if e.IsSticky { - buf.WriteString(", sticky") - } - return buf.String() -} - -func (e *MacMobilityExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Sequence uint32 `json:"sequence"` - IsSticky bool `json:"is_sticky"` - }{ - Type: t, - Subtype: s, - Sequence: e.Sequence, - IsSticky: e.IsSticky, - }) -} - -func (e *MacMobilityExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_MAC_MOBILITY -} - -func NewMacMobilityExtended(seq uint32, isSticky bool) *MacMobilityExtended { - return &MacMobilityExtended{ - Sequence: seq, - IsSticky: isSticky, - } -} - -type RouterMacExtended struct { - Mac net.HardwareAddr -} - -func (e *RouterMacExtended) Serialize() ([]byte, error) { - buf := make([]byte, 2, 8) - buf[0] = byte(EC_TYPE_EVPN) - buf[1] = byte(EC_SUBTYPE_ROUTER_MAC) - buf = append(buf, e.Mac...) - return buf, nil -} - -func (e *RouterMacExtended) String() string { - return fmt.Sprintf("router's mac: %s", e.Mac.String()) -} - -func (e *RouterMacExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Mac string `json:"mac"` - }{ - Type: t, - Subtype: s, - Mac: e.Mac.String(), - }) -} - -func (e *RouterMacExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_EVPN, EC_SUBTYPE_ROUTER_MAC -} - -func NewRoutersMacExtended(mac string) *RouterMacExtended { - hw, err := net.ParseMAC(mac) - if err != nil { - return nil - } - return &RouterMacExtended{ - Mac: hw, - } -} - -func parseEvpnExtended(data []byte) (ExtendedCommunityInterface, error) { - if ExtendedCommunityAttrType(data[0]) != EC_TYPE_EVPN { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_EVPN: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - switch subType { - case EC_SUBTYPE_ESI_LABEL: - var isSingleActive bool - if data[2] > 0 { - isSingleActive = true - } - label := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) - return &ESILabelExtended{ - IsSingleActive: isSingleActive, - Label: label, - }, nil - case EC_SUBTYPE_ES_IMPORT: - return &ESImportRouteTarget{ - ESImport: net.HardwareAddr(data[2:8]), - }, nil - case EC_SUBTYPE_MAC_MOBILITY: - var isSticky bool - if data[2] > 0 { - isSticky = true - } - seq := binary.BigEndian.Uint32(data[4:8]) - return &MacMobilityExtended{ - Sequence: seq, - IsSticky: isSticky, - }, nil - case EC_SUBTYPE_ROUTER_MAC: - return &RouterMacExtended{ - Mac: net.HardwareAddr(data[2:8]), - }, nil - } - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("unknown evpn subtype: %d", subType)) -} - -type TrafficRateExtended struct { - AS uint16 - Rate float32 -} - -func (e *TrafficRateExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE) - binary.BigEndian.PutUint16(buf[2:4], e.AS) - binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(e.Rate)) - return buf, nil -} - -func (e *TrafficRateExtended) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - if e.Rate == 0 { - buf.WriteString("discard") - } else { - buf.WriteString(fmt.Sprintf("rate: %f", e.Rate)) - } - if e.AS != 0 { - buf.WriteString(fmt.Sprintf("(as: %d)", e.AS)) - } - return buf.String() -} - -func (e *TrafficRateExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - As uint16 `json:"as"` - Rate float32 `json:"rate"` - }{t, s, e.AS, e.Rate}) -} - -func (e *TrafficRateExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE -} - -func NewTrafficRateExtended(as uint16, rate float32) *TrafficRateExtended { - return &TrafficRateExtended{ - AS: as, - Rate: rate, - } -} - -type TrafficActionExtended struct { - Terminal bool - Sample bool -} - -func (e *TrafficActionExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION) - if e.Terminal { - buf[7] = 0x01 - } - if e.Sample { - buf[7] = buf[7] | 0x2 - } - return buf, nil -} - -func (e *TrafficActionExtended) String() string { - ss := make([]string, 0, 2) - if e.Terminal { - ss = append(ss, "terminal") - } - if e.Sample { - ss = append(ss, "sample") - } - return fmt.Sprintf("action: %s", strings.Join(ss, "-")) -} - -func (e *TrafficActionExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Terminal bool `json:"terminal"` - Sample bool `json:"sample"` - }{t, s, e.Terminal, e.Sample}) -} - -func (e *TrafficActionExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION -} - -func NewTrafficActionExtended(terminal bool, sample bool) *TrafficActionExtended { - return &TrafficActionExtended{ - Terminal: terminal, - Sample: sample, - } -} - -type RedirectTwoOctetAsSpecificExtended struct { - TwoOctetAsSpecificExtended -} - -func (e *RedirectTwoOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.TwoOctetAsSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT) - return buf, err -} - -func (e *RedirectTwoOctetAsSpecificExtended) String() string { - return fmt.Sprintf("redirect: %s", e.TwoOctetAsSpecificExtended.String()) -} - -func (e *RedirectTwoOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.TwoOctetAsSpecificExtended.String()}) -} - -func (e *RedirectTwoOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_REDIRECT -} - -func NewRedirectTwoOctetAsSpecificExtended(as uint16, localAdmin uint32) *RedirectTwoOctetAsSpecificExtended { - return &RedirectTwoOctetAsSpecificExtended{*NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, as, localAdmin, false)} -} - -type RedirectIPv4AddressSpecificExtended struct { - IPv4AddressSpecificExtended -} - -func (e *RedirectIPv4AddressSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.IPv4AddressSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT) - return buf, err -} - -func (e *RedirectIPv4AddressSpecificExtended) String() string { - return fmt.Sprintf("redirect: %s", e.IPv4AddressSpecificExtended.String()) -} - -func (e *RedirectIPv4AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.IPv4AddressSpecificExtended.String()}) -} - -func (e *RedirectIPv4AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2, EC_SUBTYPE_FLOWSPEC_REDIRECT -} - -func NewRedirectIPv4AddressSpecificExtended(ipv4 string, localAdmin uint16) *RedirectIPv4AddressSpecificExtended { - e := NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv4, localAdmin, false) - if e == nil { - return nil - } - return &RedirectIPv4AddressSpecificExtended{*e} -} - -type RedirectIPv6AddressSpecificExtended struct { - IPv6AddressSpecificExtended -} - -func (e *RedirectIPv6AddressSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.IPv6AddressSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6) - return buf, err -} - -func (e *RedirectIPv6AddressSpecificExtended) String() string { - return fmt.Sprintf("redirect: %s", e.IPv6AddressSpecificExtended.String()) -} - -func (e *RedirectIPv6AddressSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.IPv6AddressSpecificExtended.String()}) -} - -func (e *RedirectIPv6AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6 -} - -func NewRedirectIPv6AddressSpecificExtended(ipv6 string, localAdmin uint16) *RedirectIPv6AddressSpecificExtended { - e := NewIPv6AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv6, localAdmin, false) - if e == nil { - return nil - } - return &RedirectIPv6AddressSpecificExtended{*e} -} - -type RedirectFourOctetAsSpecificExtended struct { - FourOctetAsSpecificExtended -} - -func (e *RedirectFourOctetAsSpecificExtended) Serialize() ([]byte, error) { - buf, err := e.FourOctetAsSpecificExtended.Serialize() - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT) - return buf, err -} - -func (e *RedirectFourOctetAsSpecificExtended) String() string { - return fmt.Sprintf("redirect: %s", e.FourOctetAsSpecificExtended.String()) -} - -func (e *RedirectFourOctetAsSpecificExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value string `json:"value"` - }{t, s, e.FourOctetAsSpecificExtended.String()}) -} - -func (e *RedirectFourOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3, EC_SUBTYPE_FLOWSPEC_REDIRECT -} - -func NewRedirectFourOctetAsSpecificExtended(as uint32, localAdmin uint16) *RedirectFourOctetAsSpecificExtended { - return &RedirectFourOctetAsSpecificExtended{*NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, as, localAdmin, false)} -} - -type TrafficRemarkExtended struct { - DSCP uint8 -} - -func (e *TrafficRemarkExtended) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL) - buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK) - buf[7] = byte(e.DSCP) - return buf, nil -} - -func (e *TrafficRemarkExtended) String() string { - return fmt.Sprintf("remark: %d", e.DSCP) -} - -func (e *TrafficRemarkExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value uint8 `json:"value"` - }{t, s, e.DSCP}) -} - -func (e *TrafficRemarkExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) { - return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK -} - -func NewTrafficRemarkExtended(dscp uint8) *TrafficRemarkExtended { - return &TrafficRemarkExtended{ - DSCP: dscp, - } -} - -func parseFlowSpecExtended(data []byte) (ExtendedCommunityInterface, error) { - typ := ExtendedCommunityAttrType(data[0]) - if typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_FLOWSPEC: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - switch subType { - case EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE: - asn := binary.BigEndian.Uint16(data[2:4]) - bits := binary.BigEndian.Uint32(data[4:8]) - rate := math.Float32frombits(bits) - return NewTrafficRateExtended(asn, rate), nil - case EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION: - terminal := data[7]&0x1 == 1 - sample := (data[7]>>1)&0x1 == 1 - return NewTrafficActionExtended(terminal, sample), nil - case EC_SUBTYPE_FLOWSPEC_REDIRECT: - // RFC7674 - switch typ { - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL: - as := binary.BigEndian.Uint16(data[2:4]) - localAdmin := binary.BigEndian.Uint32(data[4:8]) - return NewRedirectTwoOctetAsSpecificExtended(as, localAdmin), nil - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2: - ipv4 := net.IP(data[2:6]).String() - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewRedirectIPv4AddressSpecificExtended(ipv4, localAdmin), nil - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3: - as := binary.BigEndian.Uint32(data[2:6]) - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewRedirectFourOctetAsSpecificExtended(as, localAdmin), nil - } - case EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK: - dscp := data[7] - return NewTrafficRemarkExtended(dscp), nil - case EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6: - ipv6 := net.IP(data[2:18]).String() - localAdmin := binary.BigEndian.Uint16(data[18:20]) - return NewRedirectIPv6AddressSpecificExtended(ipv6, localAdmin), nil - } - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:8], - }, nil -} - -func parseIP6FlowSpecExtended(data []byte) (ExtendedCommunityInterface, error) { - typ := ExtendedCommunityAttrType(data[0]) - if typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_FLOWSPEC: %d", data[0])) - } - subType := ExtendedCommunityAttrSubType(data[1]) - switch subType { - case EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6: - // RFC7674 - switch typ { - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL: - ipv6 := net.IP(data[2:18]).String() - localAdmin := binary.BigEndian.Uint16(data[18:20]) - return NewRedirectIPv6AddressSpecificExtended(ipv6, localAdmin), nil - } - } - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:20], - }, nil -} - -type UnknownExtended struct { - Type ExtendedCommunityAttrType - Value []byte -} - -func (e *UnknownExtended) Serialize() ([]byte, error) { - if len(e.Value) != 7 { - return nil, fmt.Errorf("invalid value length for unknown extended community: %d", len(e.Value)) - } - buf := make([]byte, 8) - buf[0] = uint8(e.Type) - copy(buf[1:], e.Value) - return buf, nil -} - -func (e *UnknownExtended) String() string { - buf := make([]byte, 8) - copy(buf[1:], e.Value) - return fmt.Sprintf("%d", binary.BigEndian.Uint64(buf)) -} - -func (e *UnknownExtended) MarshalJSON() ([]byte, error) { - t, s := e.GetTypes() - return json.Marshal(struct { - Type ExtendedCommunityAttrType `json:"type"` - Subtype ExtendedCommunityAttrSubType `json:"subtype"` - Value []byte `json:"value"` - }{ - Type: t, - Subtype: s, - Value: e.Value, - }) -} - -func (e *UnknownExtended) 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]) - } - return e.Type, subType -} - -func NewUnknownExtended(typ ExtendedCommunityAttrType, value []byte) *UnknownExtended { - v := make([]byte, 7) - copy(v, value) - return &UnknownExtended{ - Type: typ, - Value: v, - } -} - -type PathAttributeExtendedCommunities struct { - PathAttribute - Value []ExtendedCommunityInterface -} - -func ParseExtended(data []byte) (ExtendedCommunityInterface, error) { - if len(data) < 8 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all extended community bytes are available") - } - attrType := ExtendedCommunityAttrType(data[0]) - subtype := ExtendedCommunityAttrSubType(data[1]) - transitive := false - switch attrType { - case EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC: - as := binary.BigEndian.Uint16(data[2:4]) - localAdmin := binary.BigEndian.Uint32(data[4:8]) - return NewTwoOctetAsSpecificExtended(subtype, as, localAdmin, transitive), nil - case EC_TYPE_TRANSITIVE_IP4_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC: - ipv4 := net.IP(data[2:6]).String() - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewIPv4AddressSpecificExtended(subtype, ipv4, localAdmin, transitive), nil - case EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC: - as := binary.BigEndian.Uint32(data[2:6]) - localAdmin := binary.BigEndian.Uint16(data[6:8]) - return NewFourOctetAsSpecificExtended(subtype, as, localAdmin, transitive), nil - case EC_TYPE_TRANSITIVE_OPAQUE: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_OPAQUE: - 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: - return parseFlowSpecExtended(data) - default: - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:8], - }, nil - } -} - -func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length%8 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "extendedcommunities length isn't correct") - } - for len(value) >= 8 { - e, err := ParseExtended(value) - if err != nil { - return err - } - p.Value = append(p.Value, e) - value = value[8:] - } - return nil -} - -func (p *PathAttributeExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, p := range p.Value { - ebuf, err := p.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, ebuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeExtendedCommunities) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - for idx, v := range p.Value { - buf.WriteString("[") - buf.WriteString(v.String()) - buf.WriteString("]") - if idx < len(p.Value)-1 { - buf.WriteString(", ") - } - } - return fmt.Sprintf("{Extcomms: %s}", buf.String()) -} - -func (p *PathAttributeExtendedCommunities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []ExtendedCommunityInterface `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeExtendedCommunities(value []ExtendedCommunityInterface) *PathAttributeExtendedCommunities { - l := len(value) * 8 - t := BGP_ATTR_TYPE_EXTENDED_COMMUNITIES - return &PathAttributeExtendedCommunities{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeAs4Path struct { - PathAttribute - Value []*As4PathParam -} - -func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - isAs4, err := validateAsPathValueBytes(value) - if err != nil { - return err - } - - if !isAs4 { - return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed") - } - - for len(value) > 0 { - tuple := &As4PathParam{} - tuple.DecodeFromBytes(value) - p.Value = append(p.Value, tuple) - if len(value) < tuple.Len() { - return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed") - } - value = value[tuple.Len():] - } - return nil -} - -func (p *PathAttributeAs4Path) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, v := range p.Value { - vbuf, err := v.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, vbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAs4Path) String() string { - params := make([]string, 0, len(p.Value)) - for _, param := range p.Value { - params = append(params, param.String()) - } - return strings.Join(params, " ") -} - -func (p *PathAttributeAs4Path) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []*As4PathParam `json:"as_paths"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeAs4Path(value []*As4PathParam) *PathAttributeAs4Path { - var l int - for _, v := range value { - l += v.Len() - } - t := BGP_ATTR_TYPE_AS4_PATH - return &PathAttributeAs4Path{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PathAttributeAs4Aggregator struct { - PathAttribute - Value PathAttributeAggregatorParam -} - -func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length != 8 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "AS4 Aggregator length is incorrect") - } - p.Value.AS = binary.BigEndian.Uint32(value[0:4]) - p.Value.Address = value[4:] - return nil -} - -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()) - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAs4Aggregator) String() string { - return fmt.Sprintf("{As4Aggregator: {AS: %d, Address: %s}}", p.Value.AS, p.Value.Address) -} - -func (p *PathAttributeAs4Aggregator) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - AS uint32 `json:"as"` - Address string `json:"address"` - }{ - Type: p.GetType(), - AS: p.Value.AS, - Address: p.Value.Address.String(), - }) -} - -func NewPathAttributeAs4Aggregator(as uint32, address string) *PathAttributeAs4Aggregator { - t := BGP_ATTR_TYPE_AS4_AGGREGATOR - return &PathAttributeAs4Aggregator{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - Length: 8, - }, - Value: PathAttributeAggregatorParam{ - AS: as, - Address: net.ParseIP(address).To4(), - }, - } -} - -type TunnelEncapSubTLVInterface interface { - Len() int - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) - String() string - MarshalJSON() ([]byte, error) -} - -type TunnelEncapSubTLV struct { - Type EncapSubTLVType - Length uint16 -} - -func (t *TunnelEncapSubTLV) Len() int { - if t.Type >= 0x80 { - return 3 + int(t.Length) - } - return 2 + int(t.Length) -} - -func (t *TunnelEncapSubTLV) DecodeFromBytes(data []byte) (value []byte, err error) { - t.Type = EncapSubTLVType(data[0]) - if t.Type >= 0x80 { - t.Length = binary.BigEndian.Uint16(data[1:3]) - data = data[3:] - } else { - t.Length = uint16(data[1]) - data = data[2:] - } - if len(data) < int(t.Length) { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLV bytes available") - } - return data, nil -} - -func (t *TunnelEncapSubTLV) Serialize(value []byte) (buf []byte, err error) { - t.Length = uint16(len(value)) - if t.Type >= 0x80 { - buf = append(make([]byte, 3), value...) - binary.BigEndian.PutUint16(buf[1:3], t.Length) - } else { - buf = append(make([]byte, 2), value...) - buf[1] = uint8(t.Length) - } - buf[0] = uint8(t.Type) - return buf, nil -} - -type TunnelEncapSubTLVUnknown struct { - TunnelEncapSubTLV - Value []byte -} - -func (t *TunnelEncapSubTLVUnknown) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - t.Value = value - return nil -} - -func (t *TunnelEncapSubTLVUnknown) Serialize() ([]byte, error) { - return t.TunnelEncapSubTLV.Serialize(t.Value) -} - -func (t *TunnelEncapSubTLVUnknown) String() string { - return fmt.Sprintf("{Type: %d, Value: %x}", t.Type, t.Value) -} - -func (t *TunnelEncapSubTLVUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Value []byte `json:"value"` - }{ - Type: t.Type, - Value: t.Value, - }) -} - -func NewTunnelEncapSubTLVUnknown(typ EncapSubTLVType, value []byte) *TunnelEncapSubTLVUnknown { - return &TunnelEncapSubTLVUnknown{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: typ, - }, - Value: value, - } -} - -type TunnelEncapSubTLVEncapsulation struct { - TunnelEncapSubTLV - Key uint32 // this represent both SessionID for L2TPv3 case and GRE-key for GRE case (RFC5512 4.) - Cookie []byte -} - -func (t *TunnelEncapSubTLVEncapsulation) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length < 4 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVEncapsulation bytes available") - } - t.Key = binary.BigEndian.Uint32(value[0:4]) - t.Cookie = value[4:] - return nil -} - -func (t *TunnelEncapSubTLVEncapsulation) Serialize() ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, t.Key) - buf = append(buf, t.Cookie...) - return t.TunnelEncapSubTLV.Serialize(buf) -} - -func (t *TunnelEncapSubTLVEncapsulation) String() string { - return fmt.Sprintf("{Key: %d, Cookie: %x}", t.Key, t.Cookie) -} - -func (t *TunnelEncapSubTLVEncapsulation) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Key uint32 `json:"key"` - Cookie []byte `json:"cookie"` - }{ - Type: t.Type, - Key: t.Key, - Cookie: t.Cookie, - }) -} - -func NewTunnelEncapSubTLVEncapsulation(key uint32, cookie []byte) *TunnelEncapSubTLVEncapsulation { - return &TunnelEncapSubTLVEncapsulation{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_ENCAPSULATION, - }, - Key: key, - Cookie: cookie, - } -} - -type TunnelEncapSubTLVProtocol struct { - TunnelEncapSubTLV - Protocol uint16 -} - -func (t *TunnelEncapSubTLVProtocol) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length < 2 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVProtocol bytes available") - } - t.Protocol = binary.BigEndian.Uint16(value[0:2]) - return nil -} - -func (t *TunnelEncapSubTLVProtocol) Serialize() ([]byte, error) { - buf := make([]byte, 2) - binary.BigEndian.PutUint16(buf, t.Protocol) - return t.TunnelEncapSubTLV.Serialize(buf) -} - -func (t *TunnelEncapSubTLVProtocol) String() string { - return fmt.Sprintf("{Protocol: %d}", t.Protocol) -} - -func (t *TunnelEncapSubTLVProtocol) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Protocol uint16 `json:"protocol"` - }{ - Type: t.Type, - Protocol: t.Protocol, - }) -} - -func NewTunnelEncapSubTLVProtocol(protocol uint16) *TunnelEncapSubTLVProtocol { - return &TunnelEncapSubTLVProtocol{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_PROTOCOL, - }, - Protocol: protocol, - } -} - -type TunnelEncapSubTLVColor struct { - TunnelEncapSubTLV - Color uint32 -} - -func (t *TunnelEncapSubTLVColor) DecodeFromBytes(data []byte) error { - value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data) - if err != nil { - return err - } - if t.Length != 8 { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Invalid TunnelEncapSubTLVColor length") - } - t.Color = binary.BigEndian.Uint32(value[4:8]) - return nil -} - -func (t *TunnelEncapSubTLVColor) Serialize() ([]byte, error) { - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) - buf[1] = byte(EC_SUBTYPE_COLOR) - binary.BigEndian.PutUint32(buf[4:8], t.Color) - return t.TunnelEncapSubTLV.Serialize(buf) -} - -func (t *TunnelEncapSubTLVColor) String() string { - return fmt.Sprintf("{Color: %d}", t.Color) -} - -func (t *TunnelEncapSubTLVColor) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type EncapSubTLVType `json:"type"` - Color uint32 `json:"color"` - }{ - Type: t.Type, - Color: t.Color, - }) -} - -func NewTunnelEncapSubTLVColor(color uint32) *TunnelEncapSubTLVColor { - return &TunnelEncapSubTLVColor{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: ENCAP_SUBTLV_TYPE_COLOR, - }, - Color: color, - } -} - -type TunnelEncapTLV struct { - Type TunnelType - Length uint16 - Value []TunnelEncapSubTLVInterface -} - -func (t *TunnelEncapTLV) Len() int { - var l int - for _, v := range t.Value { - l += v.Len() - } - return 4 + l // Type(2) + Length(2) + Value(variable) -} - -func (t *TunnelEncapTLV) DecodeFromBytes(data []byte) error { - t.Type = TunnelType(binary.BigEndian.Uint16(data[0:2])) - t.Length = binary.BigEndian.Uint16(data[2:4]) - data = data[4:] - if len(data) < int(t.Length) { - return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Not all TunnelEncapTLV bytes available")) - } - value := data[:t.Length] - for len(value) > 2 { - subType := EncapSubTLVType(value[0]) - var subTlv TunnelEncapSubTLVInterface - switch subType { - case ENCAP_SUBTLV_TYPE_ENCAPSULATION: - subTlv = &TunnelEncapSubTLVEncapsulation{} - case ENCAP_SUBTLV_TYPE_PROTOCOL: - subTlv = &TunnelEncapSubTLVProtocol{} - case ENCAP_SUBTLV_TYPE_COLOR: - subTlv = &TunnelEncapSubTLVColor{} - default: - subTlv = &TunnelEncapSubTLVUnknown{ - TunnelEncapSubTLV: TunnelEncapSubTLV{ - Type: subType, - }, - } - } - err := subTlv.DecodeFromBytes(value) - if err != nil { - return err - } - t.Value = append(t.Value, subTlv) - value = value[subTlv.Len():] - } - return nil -} - -func (p *TunnelEncapTLV) Serialize() ([]byte, error) { - buf := make([]byte, 4) - for _, t := range p.Value { - tBuf, err := t.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tBuf...) - } - binary.BigEndian.PutUint16(buf, uint16(p.Type)) - binary.BigEndian.PutUint16(buf[2:], uint16(len(buf)-4)) - return buf, nil -} - -func (p *TunnelEncapTLV) String() string { - tlvList := make([]string, len(p.Value)) - for i, v := range p.Value { - tlvList[i] = v.String() - } - return fmt.Sprintf("{%s: %s}", p.Type, strings.Join(tlvList, ", ")) -} - -func (p *TunnelEncapTLV) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type TunnelType `json:"type"` - Value []TunnelEncapSubTLVInterface `json:"value"` - }{ - Type: p.Type, - Value: p.Value, - }) -} - -func NewTunnelEncapTLV(typ TunnelType, value []TunnelEncapSubTLVInterface) *TunnelEncapTLV { - return &TunnelEncapTLV{ - Type: typ, - Value: value, - } -} - -type PathAttributeTunnelEncap struct { - PathAttribute - Value []*TunnelEncapTLV -} - -func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - for len(value) > 4 { - tlv := &TunnelEncapTLV{} - err = tlv.DecodeFromBytes(value) - if err != nil { - return err - } - p.Value = append(p.Value, tlv) - value = value[4+tlv.Length:] - } - return nil -} - -func (p *PathAttributeTunnelEncap) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, t := range p.Value { - bbuf, err := t.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeTunnelEncap) String() string { - tlvList := make([]string, len(p.Value)) - for i, v := range p.Value { - tlvList[i] = v.String() - } - return fmt.Sprintf("{TunnelEncap: %s}", strings.Join(tlvList, ", ")) -} - -func (p *PathAttributeTunnelEncap) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []*TunnelEncapTLV `json:"value"` - }{ - Type: p.Type, - Value: p.Value, - }) -} - -func NewPathAttributeTunnelEncap(value []*TunnelEncapTLV) *PathAttributeTunnelEncap { - var l int - for _, v := range value { - l += v.Len() - } - t := BGP_ATTR_TYPE_TUNNEL_ENCAP - return &PathAttributeTunnelEncap{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type PmsiTunnelIDInterface interface { - Len() int - Serialize() ([]byte, error) - String() string -} - -type DefaultPmsiTunnelID struct { - Value []byte -} - -func (i *DefaultPmsiTunnelID) Len() int { - return len(i.Value) -} - -func (i *DefaultPmsiTunnelID) Serialize() ([]byte, error) { - return i.Value, nil -} - -func (i *DefaultPmsiTunnelID) String() string { - return string(i.Value) -} - -func NewDefaultPmsiTunnelID(value []byte) *DefaultPmsiTunnelID { - return &DefaultPmsiTunnelID{ - Value: value, - } -} - -type IngressReplTunnelID struct { - Value net.IP -} - -func (i *IngressReplTunnelID) Len() int { - return len(i.Value) -} - -func (i *IngressReplTunnelID) Serialize() ([]byte, error) { - if i.Value.To4() != nil { - return []byte(i.Value.To4()), nil - } - return []byte(i.Value), nil -} - -func (i *IngressReplTunnelID) String() string { - return i.Value.String() -} - -func NewIngressReplTunnelID(value string) *IngressReplTunnelID { - ip := net.ParseIP(value) - if ip == nil { - return nil - } - return &IngressReplTunnelID{ - Value: ip, - } -} - -type PathAttributePmsiTunnel struct { - PathAttribute - IsLeafInfoRequired bool - TunnelType PmsiTunnelType - Label uint32 - TunnelID PmsiTunnelIDInterface -} - -func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - if p.Length < 5 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "PMSI Tunnel length is incorrect") - } - - if (value[0] & 0x01) > 0 { - p.IsLeafInfoRequired = true - } - p.TunnelType = PmsiTunnelType(value[1]) - if p.Label, err = labelDecode(value[2:5]); err != nil { - return err - } - - switch p.TunnelType { - case PMSI_TUNNEL_TYPE_INGRESS_REPL: - p.TunnelID = &IngressReplTunnelID{net.IP(value[5:])} - default: - p.TunnelID = &DefaultPmsiTunnelID{value[5:]} - } - return nil -} - -func (p *PathAttributePmsiTunnel) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 2) - if p.IsLeafInfoRequired { - buf[0] = 0x01 - } - buf[1] = byte(p.TunnelType) - tbuf, err := labelSerialize(p.Label) - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - tbuf, err = p.TunnelID.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tbuf...) - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributePmsiTunnel) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString(fmt.Sprintf("{Pmsi: type: %s,", p.TunnelType)) - if p.IsLeafInfoRequired { - buf.WriteString(" leaf-info-required,") - } - buf.WriteString(fmt.Sprintf(" label: %d, tunnel-id: %s}", p.Label, p.TunnelID)) - return buf.String() -} - -func (p *PathAttributePmsiTunnel) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - IsLeafInfoRequired bool `json:"is-leaf-info-required"` - TunnelType uint8 `json:"tunnel-type"` - Label uint32 `json:"label"` - TunnelID string `json:"tunnel-id"` - }{ - Type: p.Type, - IsLeafInfoRequired: p.IsLeafInfoRequired, - TunnelType: uint8(p.TunnelType), - Label: p.Label, - TunnelID: p.TunnelID.String(), - }) -} - -func NewPathAttributePmsiTunnel(typ PmsiTunnelType, isLeafInfoRequired bool, label uint32, id PmsiTunnelIDInterface) *PathAttributePmsiTunnel { - // Flags(1) + TunnelType(1) + Label(3) + TunnelID(variable) - l := 5 + id.Len() - t := BGP_ATTR_TYPE_PMSI_TUNNEL - return &PathAttributePmsiTunnel{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - IsLeafInfoRequired: isLeafInfoRequired, - TunnelType: typ, - Label: label, - TunnelID: id, - } -} - -func ParsePmsiTunnel(args []string) (*PathAttributePmsiTunnel, error) { - // Format: - // "<type>" ["leaf-info-required"] "<label>" "<tunnel-id>" - if len(args) < 3 { - return nil, fmt.Errorf("invalid pmsi tunnel arguments: %s", args) - } - - pmsi := NewPathAttributePmsiTunnel(0, false, 0, nil) - - switch args[0] { - case "ingress-repl": - pmsi.TunnelType = PMSI_TUNNEL_TYPE_INGRESS_REPL - default: - typ, err := strconv.ParseUint(args[0], 10, 8) - if err != nil { - return nil, fmt.Errorf("invalid pmsi tunnel type: %s", args[0]) - } - pmsi.TunnelType = PmsiTunnelType(typ) - } - - indx := 1 - if args[indx] == "leaf-info-required" { - pmsi.IsLeafInfoRequired = true - indx++ - } - - label, err := strconv.ParseUint(args[indx], 10, 32) - if err != nil { - return nil, fmt.Errorf("invalid pmsi tunnel label: %s", args[indx]) - } - pmsi.Label = uint32(label) - indx++ - - switch pmsi.TunnelType { - case PMSI_TUNNEL_TYPE_INGRESS_REPL: - ip := net.ParseIP(args[indx]) - if ip == nil { - return nil, fmt.Errorf("invalid pmsi tunnel identifier: %s", args[indx]) - } - pmsi.TunnelID = &IngressReplTunnelID{Value: ip} - default: - pmsi.TunnelID = &DefaultPmsiTunnelID{Value: []byte(args[indx])} - } - - return pmsi, nil -} - -type PathAttributeIP6ExtendedCommunities struct { - PathAttribute - Value []ExtendedCommunityInterface -} - -func ParseIP6Extended(data []byte) (ExtendedCommunityInterface, error) { - if len(data) < 8 { - return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all extended community bytes are available") - } - attrType := ExtendedCommunityAttrType(data[0]) - subtype := ExtendedCommunityAttrSubType(data[1]) - transitive := false - switch attrType { - case EC_TYPE_TRANSITIVE_IP6_SPECIFIC: - transitive = true - fallthrough - case EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC: - ipv6 := net.IP(data[2:18]).String() - localAdmin := binary.BigEndian.Uint16(data[18:20]) - return NewIPv6AddressSpecificExtended(subtype, ipv6, localAdmin, transitive), nil - case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL: - return parseIP6FlowSpecExtended(data) - default: - return &UnknownExtended{ - Type: ExtendedCommunityAttrType(data[0]), - Value: data[1:8], - }, nil - } -} - -func (p *PathAttributeIP6ExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data) - if err != nil { - return err - } - if p.Length%20 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "extendedcommunities length isn't correct") - } - for len(value) >= 20 { - e, err := ParseIP6Extended(value) - if err != nil { - return err - } - p.Value = append(p.Value, e) - value = value[20:] - } - return nil -} - -func (p *PathAttributeIP6ExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, p := range p.Value { - ebuf, err := p.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, ebuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeIP6ExtendedCommunities) String() string { - var buf []string - for _, v := range p.Value { - buf = append(buf, fmt.Sprintf("[%s]", v.String())) - } - return fmt.Sprintf("{Extcomms: %s}", strings.Join(buf, ",")) -} - -func (p *PathAttributeIP6ExtendedCommunities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []ExtendedCommunityInterface `json:"value"` - }{ - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeIP6ExtendedCommunities(value []ExtendedCommunityInterface) *PathAttributeIP6ExtendedCommunities { - l := len(value) * 20 - t := BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES - return &PathAttributeIP6ExtendedCommunities{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Value: value, - } -} - -type AigpTLVType uint8 - -const ( - AIGP_TLV_UNKNOWN AigpTLVType = iota - AIGP_TLV_IGP_METRIC -) - -type AigpTLVInterface interface { - Serialize() ([]byte, error) - String() string - MarshalJSON() ([]byte, error) - Type() AigpTLVType - Len() int -} - -type AigpTLVDefault struct { - typ AigpTLVType - Value []byte -} - -func (t *AigpTLVDefault) Serialize() ([]byte, error) { - buf := make([]byte, 3+len(t.Value)) - buf[0] = uint8(t.Type()) - binary.BigEndian.PutUint16(buf[1:], uint16(3+len(t.Value))) - copy(buf[3:], t.Value) - return buf, nil -} - -func (t *AigpTLVDefault) String() string { - return fmt.Sprintf("{Type: %d, Value: %v}", t.Type(), t.Value) -} - -func (t *AigpTLVDefault) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type AigpTLVType `json:"type"` - Value []byte `json:"value"` - }{ - Type: t.Type(), - Value: t.Value, - }) -} - -func (t *AigpTLVDefault) Type() AigpTLVType { - return t.typ -} - -func (t *AigpTLVDefault) Len() int { - return 3 + len(t.Value) // Type(1) + Length(2) + Value(variable) -} - -func NewAigpTLVDefault(typ AigpTLVType, value []byte) *AigpTLVDefault { - return &AigpTLVDefault{ - typ: typ, - Value: value, - } -} - -type AigpTLVIgpMetric struct { - Metric uint64 -} - -func (t *AigpTLVIgpMetric) Serialize() ([]byte, error) { - buf := make([]byte, 11) - buf[0] = uint8(AIGP_TLV_IGP_METRIC) - binary.BigEndian.PutUint16(buf[1:], uint16(11)) - binary.BigEndian.PutUint64(buf[3:], t.Metric) - return buf, nil -} - -func (t *AigpTLVIgpMetric) String() string { - return fmt.Sprintf("{Metric: %d}", t.Metric) -} - -func (t *AigpTLVIgpMetric) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type AigpTLVType `json:"type"` - Metric uint64 `json:"metric"` - }{ - Type: AIGP_TLV_IGP_METRIC, - Metric: t.Metric, - }) -} - -func NewAigpTLVIgpMetric(metric uint64) *AigpTLVIgpMetric { - return &AigpTLVIgpMetric{ - Metric: metric, - } -} - -func (t *AigpTLVIgpMetric) Type() AigpTLVType { - return AIGP_TLV_IGP_METRIC -} - -func (t *AigpTLVIgpMetric) Len() int { - return 11 -} - -type PathAttributeAigp struct { - PathAttribute - Values []AigpTLVInterface -} - -func (p *PathAttributeAigp) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data, options...) - if err != nil { - return err - } - for len(value) > 3 { - typ := value[0] - length := binary.BigEndian.Uint16(value[1:3]) - if len(value) < int(length) { - break - } - v := value[3:length] - switch AigpTLVType(typ) { - case AIGP_TLV_IGP_METRIC: - if len(v) < 8 { - break - } - metric := binary.BigEndian.Uint64(v) - p.Values = append(p.Values, NewAigpTLVIgpMetric(metric)) - default: - p.Values = append(p.Values, NewAigpTLVDefault(AigpTLVType(typ), v)) - } - value = value[length:] - } - if len(value) != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - return NewMessageError(eCode, eSubCode, nil, "Aigp length is incorrect") - } - return nil -} - -func (p *PathAttributeAigp) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0) - for _, t := range p.Values { - bbuf, err := t.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeAigp) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString("{Aigp: [") - for _, v := range p.Values { - buf.WriteString(v.String()) - } - buf.WriteString("]}") - return buf.String() -} - -func (p *PathAttributeAigp) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []AigpTLVInterface `json:"value"` - }{ - Type: p.GetType(), - Value: p.Values, - }) -} - -func NewPathAttributeAigp(values []AigpTLVInterface) *PathAttributeAigp { - var l int - for _, v := range values { - l += v.Len() - } - t := BGP_ATTR_TYPE_AIGP - return &PathAttributeAigp{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Values: values, - } -} - -type LargeCommunity struct { - ASN uint32 - LocalData1 uint32 - LocalData2 uint32 -} - -func (c *LargeCommunity) Serialize() ([]byte, error) { - buf := make([]byte, 12) - binary.BigEndian.PutUint32(buf, c.ASN) - binary.BigEndian.PutUint32(buf[4:], c.LocalData1) - binary.BigEndian.PutUint32(buf[8:], c.LocalData2) - return buf, nil -} - -func (c *LargeCommunity) String() string { - return fmt.Sprintf("%d:%d:%d", c.ASN, c.LocalData1, c.LocalData2) -} - -func NewLargeCommunity(asn, data1, data2 uint32) *LargeCommunity { - return &LargeCommunity{ - ASN: asn, - LocalData1: data1, - LocalData2: data2, - } -} - -func ParseLargeCommunity(value string) (*LargeCommunity, error) { - elems := strings.Split(value, ":") - if len(elems) != 3 { - return nil, fmt.Errorf("invalid large community format") - } - v := make([]uint32, 0, 3) - for _, elem := range elems { - e, err := strconv.ParseUint(elem, 10, 32) - if err != nil { - return nil, fmt.Errorf("invalid large community format") - } - v = append(v, uint32(e)) - } - return NewLargeCommunity(v[0], v[1], v[2]), nil -} - -type PathAttributeLargeCommunities struct { - PathAttribute - Values []*LargeCommunity -} - -func (p *PathAttributeLargeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data) - if err != nil { - return err - } - if p.Length%12 != 0 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return NewMessageError(eCode, eSubCode, nil, "large communities length isn't correct") - } - p.Values = make([]*LargeCommunity, 0, p.Length/12) - for len(value) >= 12 { - asn := binary.BigEndian.Uint32(value[:4]) - data1 := binary.BigEndian.Uint32(value[4:8]) - data2 := binary.BigEndian.Uint32(value[8:12]) - p.Values = append(p.Values, NewLargeCommunity(asn, data1, data2)) - value = value[12:] - } - return nil -} - -func (p *PathAttributeLargeCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 0, len(p.Values)*12) - for _, t := range p.Values { - bbuf, err := t.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return p.PathAttribute.Serialize(buf, options...) -} - -func (p *PathAttributeLargeCommunities) String() string { - buf := bytes.NewBuffer(make([]byte, 0, 32)) - buf.WriteString("{LargeCommunity: [ ") - ss := []string{} - for _, v := range p.Values { - ss = append(ss, v.String()) - } - buf.WriteString(strings.Join(ss, ", ")) - buf.WriteString("]}") - return buf.String() -} - -func (p *PathAttributeLargeCommunities) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Type BGPAttrType `json:"type"` - Value []*LargeCommunity `json:"value"` - }{ - Type: p.GetType(), - Value: p.Values, - }) -} - -func NewPathAttributeLargeCommunities(values []*LargeCommunity) *PathAttributeLargeCommunities { - l := len(values) * 12 - t := BGP_ATTR_TYPE_LARGE_COMMUNITY - return &PathAttributeLargeCommunities{ - PathAttribute: PathAttribute{ - Flags: getPathAttrFlags(t, l), - Type: t, - Length: uint16(l), - }, - Values: values, - } -} - -type PathAttributeUnknown struct { - PathAttribute - Value []byte -} - -func (p *PathAttributeUnknown) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - value, err := p.PathAttribute.DecodeFromBytes(data) - if err != nil { - return err - } - p.Value = value - return nil -} - -func (p *PathAttributeUnknown) Serialize(options ...*MarshallingOption) ([]byte, error) { - return p.PathAttribute.Serialize(p.Value, options...) -} - -func (p *PathAttributeUnknown) String() string { - return fmt.Sprintf("{Flags: %s, Type: %s, Value: %s}", p.Flags, p.Type, p.Value) -} - -func (p *PathAttributeUnknown) MarshalJSON() ([]byte, error) { - return json.Marshal(struct { - Flags BGPAttrFlag `json:"flags"` - Type BGPAttrType `json:"type"` - Value []byte `json:"value"` - }{ - Flags: p.GetFlags(), - Type: p.GetType(), - Value: p.Value, - }) -} - -func NewPathAttributeUnknown(flags BGPAttrFlag, typ BGPAttrType, value []byte) *PathAttributeUnknown { - l := len(value) - if l > 255 { - flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH - } - return &PathAttributeUnknown{ - PathAttribute: PathAttribute{ - Flags: flags, - Type: typ, - Length: uint16(l), - }, - Value: value, - } -} - -func GetPathAttribute(data []byte) (PathAttributeInterface, error) { - if len(data) < 2 { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR) - return nil, NewMessageError(eCode, eSubCode, data, "attribute type length is short") - } - switch BGPAttrType(data[1]) { - case BGP_ATTR_TYPE_ORIGIN: - return &PathAttributeOrigin{}, nil - case BGP_ATTR_TYPE_AS_PATH: - return &PathAttributeAsPath{}, nil - case BGP_ATTR_TYPE_NEXT_HOP: - return &PathAttributeNextHop{}, nil - case BGP_ATTR_TYPE_MULTI_EXIT_DISC: - return &PathAttributeMultiExitDisc{}, nil - case BGP_ATTR_TYPE_LOCAL_PREF: - return &PathAttributeLocalPref{}, nil - case BGP_ATTR_TYPE_ATOMIC_AGGREGATE: - return &PathAttributeAtomicAggregate{}, nil - case BGP_ATTR_TYPE_AGGREGATOR: - return &PathAttributeAggregator{}, nil - case BGP_ATTR_TYPE_COMMUNITIES: - return &PathAttributeCommunities{}, nil - case BGP_ATTR_TYPE_ORIGINATOR_ID: - return &PathAttributeOriginatorId{}, nil - case BGP_ATTR_TYPE_CLUSTER_LIST: - return &PathAttributeClusterList{}, nil - case BGP_ATTR_TYPE_MP_REACH_NLRI: - return &PathAttributeMpReachNLRI{}, nil - case BGP_ATTR_TYPE_MP_UNREACH_NLRI: - return &PathAttributeMpUnreachNLRI{}, nil - case BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: - return &PathAttributeExtendedCommunities{}, nil - case BGP_ATTR_TYPE_AS4_PATH: - return &PathAttributeAs4Path{}, nil - case BGP_ATTR_TYPE_AS4_AGGREGATOR: - return &PathAttributeAs4Aggregator{}, nil - case BGP_ATTR_TYPE_TUNNEL_ENCAP: - return &PathAttributeTunnelEncap{}, nil - case BGP_ATTR_TYPE_PMSI_TUNNEL: - return &PathAttributePmsiTunnel{}, nil - case BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES: - return &PathAttributeIP6ExtendedCommunities{}, nil - case BGP_ATTR_TYPE_AIGP: - return &PathAttributeAigp{}, nil - case BGP_ATTR_TYPE_LARGE_COMMUNITY: - return &PathAttributeLargeCommunities{}, nil - } - return &PathAttributeUnknown{}, nil -} - -type BGPUpdate struct { - WithdrawnRoutesLen uint16 - WithdrawnRoutes []*IPAddrPrefix - TotalPathAttributeLen uint16 - PathAttributes []PathAttributeInterface - NLRI []*IPAddrPrefix -} - -func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - var strongestError error - - // cache error codes - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST) - - // check withdrawn route length - if len(data) < 2 { - return NewMessageError(eCode, eSubCode, nil, "message length isn't enough for withdrawn route length") - } - - msg.WithdrawnRoutesLen = binary.BigEndian.Uint16(data[0:2]) - data = data[2:] - - // check withdrawn route - if len(data) < int(msg.WithdrawnRoutesLen) { - return NewMessageError(eCode, eSubCode, nil, "withdrawn route length exceeds message length") - } - - addpathLen := 0 - if IsAddPathEnabled(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, options...) - if err != nil { - return err - } - 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(options...)+addpathLen:] - msg.WithdrawnRoutes = append(msg.WithdrawnRoutes, w) - } - - // check path total attribute length - if len(data) < 2 { - return NewMessageError(eCode, eSubCode, nil, "message length isn't enough for path total attribute length") - } - - msg.TotalPathAttributeLen = binary.BigEndian.Uint16(data[0:2]) - data = data[2:] - - // check path attribute - if len(data) < int(msg.TotalPathAttributeLen) { - return NewMessageError(eCode, eSubCode, nil, "path total attribute length exceeds message length") - } - - msg.PathAttributes = []PathAttributeInterface{} - for pathlen := msg.TotalPathAttributeLen; pathlen > 0; { - var e error - if pathlen < 3 { - e = NewMessageErrorWithErrorHandling( - eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, "insufficient data to decode") - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - data = data[pathlen:] - break - } - p, err := GetPathAttribute(data) - if err != nil { - return err - } - - err = p.DecodeFromBytes(data, options...) - if err != nil { - e = err.(*MessageError) - if e.(*MessageError).SubTypeCode == BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR { - e.(*MessageError).ErrorHandling = ERROR_HANDLING_TREAT_AS_WITHDRAW - } else { - e.(*MessageError).ErrorHandling = getErrorHandlingFromPathAttribute(p.GetType()) - e.(*MessageError).ErrorAttribute = &p - } - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - } - pathlen -= uint16(p.Len(options...)) - if len(data) < p.Len(options...) { - e = NewMessageErrorWithErrorHandling( - eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, "attribute length is short") - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - } - data = data[p.Len(options...):] - if e == nil || e.(*MessageError).ErrorHandling != ERROR_HANDLING_ATTRIBUTE_DISCARD { - msg.PathAttributes = append(msg.PathAttributes, p) - } - } - - msg.NLRI = make([]*IPAddrPrefix, 0) - for restlen := len(data); restlen > 0; { - n := &IPAddrPrefix{} - err := n.DecodeFromBytes(data, options...) - if err != nil { - return err - } - 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") - } - if n.Len(options...) > 32 { - return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is too long") - } - data = data[n.Len(options...)+addpathLen:] - msg.NLRI = append(msg.NLRI, n) - } - - return strongestError -} - -func (msg *BGPUpdate) Serialize(options ...*MarshallingOption) ([]byte, error) { - wbuf := make([]byte, 2) - for _, w := range msg.WithdrawnRoutes { - onewbuf, err := w.Serialize(options...) - if err != nil { - return nil, err - } - wbuf = append(wbuf, onewbuf...) - } - msg.WithdrawnRoutesLen = uint16(len(wbuf) - 2) - binary.BigEndian.PutUint16(wbuf, msg.WithdrawnRoutesLen) - - pbuf := make([]byte, 2) - for _, p := range msg.PathAttributes { - onepbuf, err := p.Serialize(options...) - if err != nil { - return nil, err - } - pbuf = append(pbuf, onepbuf...) - } - msg.TotalPathAttributeLen = uint16(len(pbuf) - 2) - binary.BigEndian.PutUint16(pbuf, msg.TotalPathAttributeLen) - - buf := append(wbuf, pbuf...) - for _, n := range msg.NLRI { - nbuf, err := n.Serialize(options...) - if err != nil { - return nil, err - } - buf = append(buf, nbuf...) - } - return buf, nil -} - -func (msg *BGPUpdate) IsEndOfRib() (bool, RouteFamily) { - if len(msg.WithdrawnRoutes) == 0 && len(msg.NLRI) == 0 { - if len(msg.PathAttributes) == 0 { - return true, RF_IPv4_UC - } else if len(msg.PathAttributes) == 1 && msg.PathAttributes[0].GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI { - unreach := msg.PathAttributes[0].(*PathAttributeMpUnreachNLRI) - if len(unreach.Value) == 0 { - return true, AfiSafiToRouteFamily(unreach.AFI, unreach.SAFI) - } - } - } - return false, RouteFamily(0) -} - -func TreatAsWithdraw(msg *BGPUpdate) *BGPUpdate { - withdraw := &BGPUpdate{ - WithdrawnRoutesLen: 0, - WithdrawnRoutes: []*IPAddrPrefix{}, - TotalPathAttributeLen: 0, - PathAttributes: make([]PathAttributeInterface, 0, len(msg.PathAttributes)), - NLRI: []*IPAddrPrefix{}, - } - withdraw.WithdrawnRoutes = append(msg.WithdrawnRoutes, msg.NLRI...) - var unreach []AddrPrefixInterface - - for _, p := range msg.PathAttributes { - switch nlri := p.(type) { - case *PathAttributeMpReachNLRI: - unreach = append(unreach, nlri.Value...) - case *PathAttributeMpUnreachNLRI: - unreach = append(unreach, nlri.Value...) - } - } - if len(unreach) != 0 { - withdraw.PathAttributes = append(withdraw.PathAttributes, NewPathAttributeMpUnreachNLRI(unreach)) - } - return withdraw -} - -func NewBGPUpdateMessage(withdrawnRoutes []*IPAddrPrefix, pathattrs []PathAttributeInterface, nlri []*IPAddrPrefix) *BGPMessage { - return &BGPMessage{ - Header: BGPHeader{Type: BGP_MSG_UPDATE}, - Body: &BGPUpdate{0, withdrawnRoutes, 0, pathattrs, nlri}, - } -} - -func NewEndOfRib(family RouteFamily) *BGPMessage { - if family == RF_IPv4_UC { - return NewBGPUpdateMessage(nil, nil, nil) - } else { - afi, safi := RouteFamilyToAfiSafi(family) - t := BGP_ATTR_TYPE_MP_UNREACH_NLRI - unreach := &PathAttributeMpUnreachNLRI{ - PathAttribute: PathAttribute{ - Flags: PathAttrFlags[t], - Type: t, - }, - AFI: afi, - SAFI: safi, - } - return NewBGPUpdateMessage(nil, []PathAttributeInterface{unreach}, nil) - } -} - -type BGPNotification struct { - ErrorCode uint8 - ErrorSubcode uint8 - Data []byte -} - -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") - } - msg.ErrorCode = data[0] - msg.ErrorSubcode = data[1] - if len(data) > 2 { - msg.Data = data[2:] - } - return nil -} - -func (msg *BGPNotification) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 2) - buf[0] = msg.ErrorCode - buf[1] = msg.ErrorSubcode - buf = append(buf, msg.Data...) - return buf, nil -} - -func NewBGPNotificationMessage(errcode uint8, errsubcode uint8, data []byte) *BGPMessage { - return &BGPMessage{ - Header: BGPHeader{Type: BGP_MSG_NOTIFICATION}, - Body: &BGPNotification{errcode, errsubcode, data}, - } -} - -type BGPKeepAlive struct { -} - -func (msg *BGPKeepAlive) DecodeFromBytes(data []byte, options ...*MarshallingOption) error { - return nil -} - -func (msg *BGPKeepAlive) Serialize(options ...*MarshallingOption) ([]byte, error) { - return nil, nil -} - -func NewBGPKeepAliveMessage() *BGPMessage { - return &BGPMessage{ - Header: BGPHeader{Len: 19, Type: BGP_MSG_KEEPALIVE}, - Body: &BGPKeepAlive{}, - } -} - -type BGPRouteRefresh struct { - AFI uint16 - Demarcation uint8 - SAFI uint8 -} - -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") - } - msg.AFI = binary.BigEndian.Uint16(data[0:2]) - msg.Demarcation = data[2] - msg.SAFI = data[3] - return nil -} - -func (msg *BGPRouteRefresh) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], msg.AFI) - buf[2] = msg.Demarcation - buf[3] = msg.SAFI - return buf, nil -} - -func NewBGPRouteRefreshMessage(afi uint16, demarcation uint8, safi uint8) *BGPMessage { - return &BGPMessage{ - Header: BGPHeader{Type: BGP_MSG_ROUTE_REFRESH}, - Body: &BGPRouteRefresh{afi, demarcation, safi}, - } -} - -type BGPBody interface { - DecodeFromBytes([]byte, ...*MarshallingOption) error - Serialize(...*MarshallingOption) ([]byte, error) -} - -const ( - BGP_HEADER_LENGTH = 19 - BGP_MAX_MESSAGE_LENGTH = 4096 -) - -type BGPHeader struct { - Marker []byte - Len uint16 - Type uint8 -} - -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") - } - - msg.Len = binary.BigEndian.Uint16(data[16:18]) - if int(msg.Len) < BGP_HEADER_LENGTH { - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "unknown message type") - } - - msg.Type = data[18] - return nil -} - -func (msg *BGPHeader) Serialize(options ...*MarshallingOption) ([]byte, error) { - buf := make([]byte, 19) - for i := range buf[:16] { - buf[i] = 0xff - } - binary.BigEndian.PutUint16(buf[16:18], msg.Len) - buf[18] = msg.Type - return buf, nil -} - -type BGPMessage struct { - Header BGPHeader - Body BGPBody -} - -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") - } - msg := &BGPMessage{Header: *h} - - switch msg.Header.Type { - case BGP_MSG_OPEN: - msg.Body = &BGPOpen{} - case BGP_MSG_UPDATE: - msg.Body = &BGPUpdate{} - case BGP_MSG_NOTIFICATION: - msg.Body = &BGPNotification{} - case BGP_MSG_KEEPALIVE: - msg.Body = &BGPKeepAlive{} - case BGP_MSG_ROUTE_REFRESH: - msg.Body = &BGPRouteRefresh{} - default: - return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE, nil, "unknown message type") - } - err := msg.Body.DecodeFromBytes(data, options...) - return msg, err -} - -func ParseBGPMessage(data []byte, options ...*MarshallingOption) (*BGPMessage, error) { - h := &BGPHeader{} - err := h.DecodeFromBytes(data, options...) - if err != nil { - return nil, err - } - - if int(h.Len) > len(data) { - return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "unknown message type") - } - - return parseBody(h, data[19:h.Len], options...) -} - -func ParseBGPBody(h *BGPHeader, data []byte, options ...*MarshallingOption) (*BGPMessage, error) { - return parseBody(h, data, options...) -} - -func (msg *BGPMessage) Serialize(options ...*MarshallingOption) ([]byte, error) { - b, err := msg.Body.Serialize(options...) - if err != nil { - return nil, err - } - if msg.Header.Len == 0 { - if 19+len(b) > BGP_MAX_MESSAGE_LENGTH { - return nil, NewMessageError(0, 0, nil, fmt.Sprintf("too long message length %d", 19+len(b))) - } - msg.Header.Len = 19 + uint16(len(b)) - } - h, err := msg.Header.Serialize(options...) - if err != nil { - return nil, err - } - return append(h, b...), nil -} - -type ErrorHandling int - -const ( - ERROR_HANDLING_NONE ErrorHandling = iota - ERROR_HANDLING_ATTRIBUTE_DISCARD - ERROR_HANDLING_TREAT_AS_WITHDRAW - ERROR_HANDLING_AFISAFI_DISABLE - ERROR_HANDLING_SESSION_RESET -) - -func getErrorHandlingFromPathAttribute(t BGPAttrType) ErrorHandling { - switch t { - case BGP_ATTR_TYPE_ORIGIN: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_AS_PATH: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_AS4_PATH: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_NEXT_HOP: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_MULTI_EXIT_DISC: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_LOCAL_PREF: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_ATOMIC_AGGREGATE: - return ERROR_HANDLING_ATTRIBUTE_DISCARD - case BGP_ATTR_TYPE_AGGREGATOR: - return ERROR_HANDLING_ATTRIBUTE_DISCARD - case BGP_ATTR_TYPE_AS4_AGGREGATOR: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_COMMUNITIES: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_ORIGINATOR_ID: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_CLUSTER_LIST: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_MP_REACH_NLRI: - return ERROR_HANDLING_AFISAFI_DISABLE - case BGP_ATTR_TYPE_MP_UNREACH_NLRI: - return ERROR_HANDLING_AFISAFI_DISABLE - case BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_PMSI_TUNNEL: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_LARGE_COMMUNITY: - return ERROR_HANDLING_TREAT_AS_WITHDRAW - case BGP_ATTR_TYPE_TUNNEL_ENCAP: - return ERROR_HANDLING_ATTRIBUTE_DISCARD - case BGP_ATTR_TYPE_AIGP: - return ERROR_HANDLING_ATTRIBUTE_DISCARD - default: - return ERROR_HANDLING_ATTRIBUTE_DISCARD - } -} - -type MessageError struct { - TypeCode uint8 - SubTypeCode uint8 - Data []byte - Message string - ErrorHandling ErrorHandling - ErrorAttribute *PathAttributeInterface -} - -func NewMessageError(typeCode, subTypeCode uint8, data []byte, msg string) error { - return &MessageError{ - TypeCode: typeCode, - SubTypeCode: subTypeCode, - Data: data, - ErrorHandling: ERROR_HANDLING_SESSION_RESET, - ErrorAttribute: nil, - Message: msg, - } -} - -func NewMessageErrorWithErrorHandling(typeCode, subTypeCode uint8, data []byte, errorHandling ErrorHandling, errorAttribute *PathAttributeInterface, msg string) error { - return &MessageError{ - TypeCode: typeCode, - SubTypeCode: subTypeCode, - Data: data, - ErrorHandling: errorHandling, - ErrorAttribute: errorAttribute, - Message: msg, - } -} - -func (e *MessageError) Error() string { - return e.Message -} - -func (e *MessageError) Stronger(err error) bool { - if err == nil { - return true - } - if msgErr, ok := err.(*MessageError); ok { - return e.ErrorHandling > msgErr.ErrorHandling - } - return false -} - -func (e *TwoOctetAsSpecificExtended) Flat() map[string]string { - if e.SubType == EC_SUBTYPE_ROUTE_TARGET { - return map[string]string{"routeTarget": e.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 { - return map[string]string{} -} - -func (e *IPv4AddressSpecificExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *IPv6AddressSpecificExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *FourOctetAsSpecificExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *ESILabelExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *ESImportRouteTarget) Flat() map[string]string { - return map[string]string{} -} - -func (e *MacMobilityExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *RouterMacExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *TrafficRateExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *TrafficRemarkExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *RedirectIPv4AddressSpecificExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *RedirectIPv6AddressSpecificExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *RedirectFourOctetAsSpecificExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *UnknownExtended) Flat() map[string]string { - return map[string]string{} -} - -func (e *TrafficActionExtended) Flat() map[string]string { - return map[string]string{} -} - -func (p *PathAttributeExtendedCommunities) Flat() map[string]string { - flat := map[string]string{} - for _, ec := range p.Value { - FlatUpdate(flat, ec.Flat()) - } - return flat -} - -func (p *PathAttribute) Flat() map[string]string { - return map[string]string{} -} - -func (l *LabeledVPNIPAddrPrefix) Flat() map[string]string { - prefixLen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len())) - return map[string]string{ - "Prefix": l.IPAddrPrefixDefault.Prefix.String(), - "PrefixLen": fmt.Sprintf("%d", prefixLen), - "NLRI": l.String(), - "Label": l.Labels.String(), - } -} - -func (p *IPAddrPrefixDefault) Flat() map[string]string { - l := strings.Split(p.String(), "/") - if len(l) == 2 { - return map[string]string{ - "Prefix": l[0], - "PrefixLen": l[1], - } - } - return map[string]string{} -} - -func (l *EVPNNLRI) Flat() map[string]string { - return map[string]string{} -} -func (l *RouteTargetMembershipNLRI) Flat() map[string]string { - return map[string]string{} -} -func (l *FlowSpecIPv4Unicast) Flat() map[string]string { - return map[string]string{} -} -func (l *FlowSpecIPv4VPN) Flat() map[string]string { - return map[string]string{} -} -func (l *FlowSpecIPv6Unicast) Flat() map[string]string { - return map[string]string{} -} -func (l *FlowSpecIPv6VPN) Flat() map[string]string { - return map[string]string{} -} -func (l *FlowSpecL2VPN) Flat() map[string]string { - return map[string]string{} -} -func (l *OpaqueNLRI) Flat() map[string]string { - return map[string]string{} -} - -// Update a Flat representation by adding elements of the second -// one. If two elements use same keys, values are separated with -// ';'. In this case, it returns an error but the update has been -// realized. -func FlatUpdate(f1, f2 map[string]string) error { - conflict := false - for k2, v2 := range f2 { - if v1, ok := f1[k2]; ok { - f1[k2] = v1 + ";" + v2 - conflict = true - } else { - f1[k2] = v2 - } - } - if conflict { - return fmt.Errorf("Keys conflict") - } else { - return nil - } -} diff --git a/packet/bgp/bgp_race_test.go b/packet/bgp/bgp_race_test.go deleted file mode 100644 index 08038200..00000000 --- a/packet/bgp/bgp_race_test.go +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2018 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. - -// +build race - -package bgp - -import ( - "testing" - "time" -) - -// Test_RaceCondition detects data races when serialization. -// Currently tests only attributes contained in UPDATE message. -func Test_RaceCondition(t *testing.T) { - m := NewTestBGPUpdateMessage() - updateBody := m.Body.(*BGPUpdate) - - go func(body *BGPUpdate) { - for _, v := range body.WithdrawnRoutes { - v.Serialize() - } - for _, v := range body.PathAttributes { - v.Serialize() - } - for _, v := range body.NLRI { - v.Serialize() - } - }(updateBody) - - time.Sleep(time.Second) - - updateBody.Serialize() -} diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go deleted file mode 100644 index a4801f27..00000000 --- a/packet/bgp/bgp_test.go +++ /dev/null @@ -1,1194 +0,0 @@ -// 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. - -package bgp - -import ( - "bytes" - "encoding/binary" - "net" - "reflect" - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func keepalive() *BGPMessage { - return NewBGPKeepAliveMessage() -} - -func notification() *BGPMessage { - return NewBGPNotificationMessage(1, 2, nil) -} - -func refresh() *BGPMessage { - return NewBGPRouteRefreshMessage(1, 2, 10) -} - -var result []string - -func BenchmarkNormalizeFlowSpecOpValues(b *testing.B) { - var r []string - for n := 0; n < b.N; n++ { - r = normalizeFlowSpecOpValues([]string{"&<=80"}) - } - result = r -} - -func Test_Message(t *testing.T) { - l := []*BGPMessage{keepalive(), notification(), refresh(), NewTestBGPOpenMessage(), NewTestBGPUpdateMessage()} - - for _, m1 := range l { - buf1, err := m1.Serialize() - assert.NoError(t, err) - - t.Log("LEN =", len(buf1)) - m2, err := ParseBGPMessage(buf1) - assert.NoError(t, err) - - // FIXME: shouldn't but workaround for some structs. - _, err = m2.Serialize() - assert.NoError(t, err) - - assert.True(t, reflect.DeepEqual(m1, m2)) - } -} - -func Test_IPAddrPrefixString(t *testing.T) { - ipv4 := NewIPAddrPrefix(24, "129.6.10.0") - assert.Equal(t, "129.6.10.0/24", ipv4.String()) - ipv4 = NewIPAddrPrefix(24, "129.6.10.1") - assert.Equal(t, "129.6.10.0/24", ipv4.String()) - ipv4 = NewIPAddrPrefix(22, "129.6.129.0") - assert.Equal(t, "129.6.128.0/22", ipv4.String()) - - ipv6 := NewIPv6AddrPrefix(64, "3343:faba:3903::0") - assert.Equal(t, "3343:faba:3903::/64", ipv6.String()) - ipv6 = NewIPv6AddrPrefix(64, "3343:faba:3903::1") - assert.Equal(t, "3343:faba:3903::/64", ipv6.String()) - ipv6 = NewIPv6AddrPrefix(63, "3343:faba:3903:129::0") - assert.Equal(t, "3343:faba:3903:128::/63", ipv6.String()) -} - -func Test_RouteTargetMembershipNLRIString(t *testing.T) { - assert := assert.New(t) - - // TwoOctetAsSpecificExtended - buf := make([]byte, 13) - buf[0] = 96 // in bit length - binary.BigEndian.PutUint32(buf[1:5], 65546) - buf[5] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) // typehigh - binary.BigEndian.PutUint16(buf[7:9], 65000) - binary.BigEndian.PutUint32(buf[9:], 65546) - r := &RouteTargetMembershipNLRI{} - err := r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:65000:65546", r.String()) - buf, err = r.Serialize() - assert.Equal(nil, err) - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:65000:65546", r.String()) - - // IPv4AddressSpecificExtended - buf = make([]byte, 13) - buf[0] = 96 // in bit length - binary.BigEndian.PutUint32(buf[1:5], 65546) - buf[5] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC) // typehigh - ip := net.ParseIP("10.0.0.1").To4() - copy(buf[7:11], []byte(ip)) - binary.BigEndian.PutUint16(buf[11:], 65000) - r = &RouteTargetMembershipNLRI{} - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:10.0.0.1:65000", r.String()) - buf, err = r.Serialize() - assert.Equal(nil, err) - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:10.0.0.1:65000", r.String()) - - // FourOctetAsSpecificExtended - buf = make([]byte, 13) - buf[0] = 96 // in bit length - binary.BigEndian.PutUint32(buf[1:5], 65546) - buf[5] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) // typehigh - buf[6] = byte(EC_SUBTYPE_ROUTE_TARGET) // subtype - binary.BigEndian.PutUint32(buf[7:], 65546) - binary.BigEndian.PutUint16(buf[11:], 65000) - r = &RouteTargetMembershipNLRI{} - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:1.10:65000", r.String()) - buf, err = r.Serialize() - assert.Equal(nil, err) - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:1.10:65000", r.String()) - - // OpaqueExtended - buf = make([]byte, 13) - buf[0] = 96 // in bit length - binary.BigEndian.PutUint32(buf[1:5], 65546) - buf[5] = byte(EC_TYPE_TRANSITIVE_OPAQUE) // typehigh - binary.BigEndian.PutUint32(buf[9:], 1000000) - r = &RouteTargetMembershipNLRI{} - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:1000000", r.String()) - buf, err = r.Serialize() - assert.Equal(nil, err) - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:1000000", r.String()) - - // Unknown - buf = make([]byte, 13) - buf[0] = 96 // in bit length - binary.BigEndian.PutUint32(buf[1:5], 65546) - buf[5] = 0x04 // typehigh - binary.BigEndian.PutUint32(buf[9:], 1000000) - r = &RouteTargetMembershipNLRI{} - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:1000000", r.String()) - buf, err = r.Serialize() - assert.Equal(nil, err) - err = r.DecodeFromBytes(buf) - assert.Equal(nil, err) - assert.Equal("65546:1000000", r.String()) - -} - -func Test_MalformedUpdateMsg(t *testing.T) { - assert := assert.New(t) - - // Invalid AGGREGATOR - bufin := []byte{ - 0x00, 0x00, // Withdraws(0) - 0x00, 0x16, // Attrs Len(22) - 0xc0, 0x07, 0x05, // Flag, Type(7), Length(5) - 0x00, 0x00, 0x00, 0x64, // aggregator - invalid length - 0x00, - 0x40, 0x01, 0x01, 0x00, // Attr(ORIGIN) - 0x40, 0x03, 0x04, 0xc0, // Attr(NEXT_HOP) - 0xa8, 0x01, 0x64, - 0x40, 0x02, 0x00, // Attr(AS_PATH) - } - - u := &BGPUpdate{} - err := u.DecodeFromBytes(bufin) - assert.Error(err) - assert.Equal(ERROR_HANDLING_ATTRIBUTE_DISCARD, err.(*MessageError).ErrorHandling) - - // Invalid MP_REACH_NLRI - bufin = []byte{ - 0x00, 0x00, // Withdraws(0) - 0x00, 0x27, // Attrs Len(39) - 0x80, 0x0e, 0x1d, // Flag, Type(14), Length(29) - 0x00, 0x02, 0x01, // afi(2), safi(1) - 0x0f, 0x00, 0x00, 0x00, // nexthop - invalid nexthop length - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xff, - 0xff, 0x0a, 0x00, 0x00, - 0x00, // SNPA(0) - 0x40, 0x20, 0x01, 0x0d, // NLRI - 0xb8, 0x00, 0x01, 0x00, - 0x00, - 0x40, 0x01, 0x01, 0x00, // Attr(ORIGIN) - 0x40, 0x02, 0x00, // Attr(AS_PATH) - } - - err = u.DecodeFromBytes(bufin) - assert.Error(err) - assert.Equal(ERROR_HANDLING_AFISAFI_DISABLE, err.(*MessageError).ErrorHandling) - - // Invalid flag - bufin = []byte{ - 0x00, 0x00, // Withdraws(0) - 0x00, 0x0e, // Attrs Len(14) - 0xc0, 0x01, 0x01, 0x00, // Attr(ORIGIN) - invalid flag - 0x40, 0x03, 0x04, 0xc0, // Attr(NEXT_HOP) - 0xa8, 0x01, 0x64, - 0x40, 0x02, 0x00, // Attr(AS_PATH) - } - - err = u.DecodeFromBytes(bufin) - assert.Error(err) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, err.(*MessageError).ErrorHandling) - - // Invalid AGGREGATOR and MULTI_EXIT_DESC - bufin = []byte{ - 0x00, 0x00, // Withdraws(0) - 0x00, 0x1e, // Attrs Len(30) - 0xc0, 0x07, 0x05, 0x00, // Attr(AGGREGATOR) - invalid length - 0x00, 0x00, 0x64, 0x00, - 0x80, 0x04, 0x05, 0x00, // Attr(MULTI_EXIT_DESC) - invalid length - 0x00, 0x00, 0x00, 0x64, - 0x40, 0x01, 0x01, 0x00, // Attr(ORIGIN) - 0x40, 0x02, 0x00, // Attr(AS_PATH) - 0x40, 0x03, 0x04, 0xc0, // Attr(NEXT_HOP) - 0xa8, 0x01, 0x64, - 0x20, 0xc8, 0xc8, 0xc8, // NLRI - 0xc8, - } - - err = u.DecodeFromBytes(bufin) - assert.Error(err) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, err.(*MessageError).ErrorHandling) -} - -func Test_RFC5512(t *testing.T) { - assert := assert.New(t) - - buf := make([]byte, 8) - buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) - buf[1] = byte(EC_SUBTYPE_COLOR) - binary.BigEndian.PutUint32(buf[4:], 1000000) - ec, err := ParseExtended(buf) - assert.Equal(nil, err) - assert.Equal("1000000", ec.String()) - buf, err = ec.Serialize() - assert.Equal(nil, err) - assert.Equal([]byte{0x3, 0xb, 0x0, 0x0, 0x0, 0xf, 0x42, 0x40}, buf) - - buf = make([]byte, 8) - buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE) - buf[1] = byte(EC_SUBTYPE_ENCAPSULATION) - binary.BigEndian.PutUint16(buf[6:], uint16(TUNNEL_TYPE_VXLAN)) - ec, err = ParseExtended(buf) - assert.Equal(nil, err) - assert.Equal("VXLAN", ec.String()) - buf, err = ec.Serialize() - assert.Equal(nil, err) - assert.Equal([]byte{0x3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, buf) - - tlv := NewTunnelEncapTLV(TUNNEL_TYPE_VXLAN, []TunnelEncapSubTLVInterface{NewTunnelEncapSubTLVColor(10)}) - attr := NewPathAttributeTunnelEncap([]*TunnelEncapTLV{tlv}) - - buf1, err := attr.Serialize() - assert.Equal(nil, err) - - p, err := GetPathAttribute(buf1) - assert.Equal(nil, err) - - err = p.DecodeFromBytes(buf1) - assert.Equal(nil, err) - - buf2, err := p.Serialize() - assert.Equal(nil, err) - assert.Equal(buf1, buf2) - - n1 := NewEncapNLRI("10.0.0.1") - buf1, err = n1.Serialize() - assert.Equal(nil, err) - - n2 := NewEncapNLRI("") - err = n2.DecodeFromBytes(buf1) - assert.Equal(nil, err) - assert.Equal("10.0.0.1", n2.String()) - - n3 := NewEncapv6NLRI("2001::1") - buf1, err = n3.Serialize() - assert.Equal(nil, err) - - n4 := NewEncapv6NLRI("") - err = n4.DecodeFromBytes(buf1) - assert.Equal(nil, err) - assert.Equal("2001::1", n4.String()) -} - -func Test_ASLen(t *testing.T) { - assert := assert.New(t) - - aspath := AsPathParam{ - Num: 2, - AS: []uint16{65000, 65001}, - } - aspath.Type = BGP_ASPATH_ATTR_TYPE_SEQ - assert.Equal(2, aspath.ASLen()) - - aspath.Type = BGP_ASPATH_ATTR_TYPE_SET - assert.Equal(1, aspath.ASLen()) - - aspath.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SEQ - assert.Equal(0, aspath.ASLen()) - - aspath.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SET - assert.Equal(0, aspath.ASLen()) - - as4path := As4PathParam{ - Num: 2, - AS: []uint32{65000, 65001}, - } - as4path.Type = BGP_ASPATH_ATTR_TYPE_SEQ - assert.Equal(2, as4path.ASLen()) - - as4path.Type = BGP_ASPATH_ATTR_TYPE_SET - assert.Equal(1, as4path.ASLen()) - - as4path.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SEQ - assert.Equal(0, as4path.ASLen()) - - as4path.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SET - assert.Equal(0, as4path.ASLen()) - -} - -func Test_MPLSLabelStack(t *testing.T) { - assert := assert.New(t) - mpls := NewMPLSLabelStack() - buf, err := mpls.Serialize() - assert.Nil(err) - assert.Equal(true, bytes.Equal(buf, []byte{0, 0, 1})) - - mpls = &MPLSLabelStack{} - assert.Nil(mpls.DecodeFromBytes(buf)) - assert.Equal(1, len(mpls.Labels)) - assert.Equal(uint32(0), mpls.Labels[0]) - - mpls = NewMPLSLabelStack(WITHDRAW_LABEL) - buf, err = mpls.Serialize() - assert.Nil(err) - assert.Equal(true, bytes.Equal(buf, []byte{128, 0, 0})) - - mpls = &MPLSLabelStack{} - assert.Nil(mpls.DecodeFromBytes(buf)) - assert.Equal(1, len(mpls.Labels)) - assert.Equal(WITHDRAW_LABEL, mpls.Labels[0]) -} - -func Test_FlowSpecNlri(t *testing.T) { - assert := assert.New(t) - cmp := make([]FlowSpecComponentInterface, 0) - cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, TCP) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1})) - item2 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 20) - item3 := NewFlowSpecComponentItem(DEC_NUM_OP_AND|DEC_NUM_OP_LT_EQ, 30) - item4 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 10) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4})) - 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})) - isFragment := uint64(0x02) - lastFragment := uint64(0x08) - item5 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_MATCH, isFragment) - item6 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND, lastFragment) - - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5, item6})) - item7 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK) - item8 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND|BITMASK_FLAG_OP_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) - - n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv4_UC)) - assert.Nil(err) - - err = n2.DecodeFromBytes(buf1) - assert.Nil(err) - // should be equal - assert.Equal(n1, n2) -} - -func Test_FlowSpecExtended(t *testing.T) { - assert := assert.New(t) - exts := make([]ExtendedCommunityInterface, 0) - exts = append(exts, NewTrafficRateExtended(100, 9600.0)) - exts = append(exts, NewTrafficActionExtended(true, false)) - exts = append(exts, NewRedirectTwoOctetAsSpecificExtended(1000, 1000)) - exts = append(exts, NewRedirectIPv4AddressSpecificExtended("10.0.0.1", 1000)) - exts = append(exts, NewRedirectFourOctetAsSpecificExtended(10000000, 1000)) - exts = append(exts, NewTrafficRemarkExtended(10)) - m1 := NewPathAttributeExtendedCommunities(exts) - buf1, err := m1.Serialize() - require.NoError(t, err) - - m2 := NewPathAttributeExtendedCommunities(nil) - err = m2.DecodeFromBytes(buf1) - require.NoError(t, err) - - _, err = m2.Serialize() - require.NoError(t, err) - - assert.Equal(m1, m2) -} - -func Test_IP6FlowSpecExtended(t *testing.T) { - exts := make([]ExtendedCommunityInterface, 0) - exts = append(exts, NewRedirectIPv6AddressSpecificExtended("2001:db8::68", 1000)) - m1 := NewPathAttributeIP6ExtendedCommunities(exts) - buf1, err := m1.Serialize() - require.NoError(t, err) - - m2 := NewPathAttributeIP6ExtendedCommunities(nil) - err = m2.DecodeFromBytes(buf1) - require.NoError(t, err) - - _, err = m2.Serialize() - require.NoError(t, err) - - assert.Equal(t, m1, m2) -} - -func Test_FlowSpecNlriv6(t *testing.T) { - cmp := make([]FlowSpecComponentInterface, 0) - cmp = append(cmp, NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(64, "2001::"), 12)) - cmp = append(cmp, NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(64, "2001::"), 12)) - item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, TCP) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1})) - item2 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 20) - item3 := NewFlowSpecComponentItem(DEC_NUM_OP_AND|DEC_NUM_OP_LT_EQ, 30) - item4 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, 10) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4})) - 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})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_LABEL, []*FlowSpecComponentItem{item2, item3, item4})) - isFragment := uint64(0x02) - item5 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_MATCH, isFragment) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5})) - item6 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK) - item7 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND|BITMASK_FLAG_OP_NOT, TCP_FLAG_URGENT) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item6, item7})) - n1 := NewFlowSpecIPv6Unicast(cmp) - buf1, err := n1.Serialize() - require.NoError(t, err) - - n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv6_UC)) - require.NoError(t, err) - - err = n2.DecodeFromBytes(buf1) - require.NoError(t, err) - - _, err = n2.Serialize() - require.NoError(t, err) - - assert.Equal(t, n1, n2) -} - -func Test_Aigp(t *testing.T) { - assert := assert.New(t) - m := NewAigpTLVIgpMetric(1000) - a1 := NewPathAttributeAigp([]AigpTLVInterface{m}) - buf1, err := a1.Serialize() - require.NoError(t, err) - - a2 := NewPathAttributeAigp(nil) - err = a2.DecodeFromBytes(buf1) - require.NoError(t, err) - - assert.Equal(a1, a2) -} - -func Test_FlowSpecNlriL2(t *testing.T) { - assert := assert.New(t) - mac, _ := net.ParseMAC("01:23:45:67:89:ab") - cmp := make([]FlowSpecComponentInterface, 0) - cmp = append(cmp, NewFlowSpecDestinationMac(mac)) - cmp = append(cmp, NewFlowSpecSourceMac(mac)) - item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, uint64(IPv4)) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ETHERNET_TYPE, []*FlowSpecComponentItem{item1})) - rd, _ := ParseRouteDistinguisher("100:100") - n1 := NewFlowSpecL2VPN(rd, cmp) - buf1, err := n1.Serialize() - assert.Nil(err) - n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_L2_VPN)) - assert.Nil(err) - err = n2.DecodeFromBytes(buf1) - assert.Nil(err) - - assert.Equal(n1, n2) -} - -func Test_NotificationErrorCode(t *testing.T) { - // boundary check - t.Log(NewNotificationErrorCode(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE).String()) - t.Log(NewNotificationErrorCode(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE+1).String()) - t.Log(NewNotificationErrorCode(BGP_ERROR_MESSAGE_HEADER_ERROR, 0).String()) - t.Log(NewNotificationErrorCode(0, BGP_ERROR_SUB_BAD_MESSAGE_TYPE).String()) - t.Log(NewNotificationErrorCode(BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR+1, 0).String()) -} - -func Test_FlowSpecNlriVPN(t *testing.T) { - assert := assert.New(t) - cmp := make([]FlowSpecComponentInterface, 0) - cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - rd, _ := ParseRouteDistinguisher("100:100") - n1 := NewFlowSpecIPv4VPN(rd, cmp) - buf1, err := n1.Serialize() - assert.Nil(err) - n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv4_VPN)) - assert.Nil(err) - err = n2.DecodeFromBytes(buf1) - require.NoError(t, err) - - assert.Equal(n1, n2) -} - -func Test_EVPNIPPrefixRoute(t *testing.T) { - assert := assert.New(t) - rd, _ := ParseRouteDistinguisher("100:100") - r := &EVPNIPPrefixRoute{ - RD: rd, - ESI: EthernetSegmentIdentifier{ - Type: ESI_ARBITRARY, - Value: make([]byte, 9), - }, - ETag: 10, - IPPrefixLength: 24, - IPPrefix: net.IP{10, 10, 10, 0}, - GWIPAddress: net.IP{10, 10, 10, 10}, - Label: 1000, - } - n1 := NewEVPNNLRI(EVPN_IP_PREFIX, r) - buf1, err := n1.Serialize() - assert.Nil(err) - n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_EVPN)) - assert.Nil(err) - err = n2.DecodeFromBytes(buf1) - assert.Nil(err) - - assert.Equal(n1, n2) -} - -func Test_CapExtendedNexthop(t *testing.T) { - assert := assert.New(t) - tuple := NewCapExtendedNexthopTuple(RF_IPv4_UC, AFI_IP6) - n1 := NewCapExtendedNexthop([]*CapExtendedNexthopTuple{tuple}) - buf1, err := n1.Serialize() - assert.Nil(err) - n2, err := DecodeCapability(buf1) - assert.Nil(err) - - assert.Equal(n1, n2) -} - -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.SetPathLocalIdentifier(10) - assert.Equal(n1.PathLocalIdentifier(), 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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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, - &EVPNEthernetAutoDiscoveryRoute{NewRouteDistinguisherFourOctetAS(5, 6), - EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2}) - n1.SetPathLocalIdentifier(40) - bits, err := n1.Serialize(opt) - assert.Nil(err) - n2 := NewEVPNNLRI(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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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.SetPathLocalIdentifier(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)) - } - -} - -func Test_CompareFlowSpecNLRI(t *testing.T) { - assert := assert.New(t) - cmp, err := ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 10.0.0.2/32 source 10.0.0.1/32 destination-port ==3128 protocol tcp") - assert.Nil(err) - // Note: Use NewFlowSpecIPv4Unicast() for the consistent ordered rules. - n1 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI - cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.0/24 destination-port ==3128 protocol tcp") - assert.Nil(err) - n2 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI - r, err := CompareFlowSpecNLRI(&n1, &n2) - assert.Nil(err) - assert.True(r > 0) - cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.9/32 port ==80 ==8080 destination-port >8080&<8080 ==3128 source-port >1024 protocol ==udp ==tcp") - n3 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI - assert.Nil(err) - cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 192.168.0.2/32") - n4 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI - assert.Nil(err) - r, err = CompareFlowSpecNLRI(&n3, &n4) - assert.Nil(err) - assert.True(r < 0) -} - -func Test_MpReachNLRIWithIPv4MappedIPv6Prefix(t *testing.T) { - assert := assert.New(t) - n1 := NewIPv6AddrPrefix(120, "::ffff:10.0.0.0") - buf1, err := n1.Serialize() - assert.Nil(err) - n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_IPv6_UC)) - assert.Nil(err) - err = n2.DecodeFromBytes(buf1) - assert.Nil(err) - - assert.Equal(n1, n2) - - label := NewMPLSLabelStack(2) - - n3 := NewLabeledIPv6AddrPrefix(120, "::ffff:10.0.0.0", *label) - buf1, err = n3.Serialize() - assert.Nil(err) - n4, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_IPv6_MPLS)) - assert.Nil(err) - err = n4.DecodeFromBytes(buf1) - assert.Nil(err) - - assert.Equal(n3, n4) -} - -func Test_MpReachNLRIWithIPv6PrefixWithIPv4Peering(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x80, 0x0e, 0x1e, // flags(1), type(1), length(1) - 0x00, 0x02, 0x01, 0x10, // afi(2), safi(1), nexthoplen(1) - 0x00, 0x00, 0x00, 0x00, // nexthop(16) - 0x00, 0x00, 0x00, 0x00, // = "::ffff:172.20.0.1" - 0x00, 0x00, 0xff, 0xff, - 0xac, 0x14, 0x00, 0x01, - 0x00, // reserved(1) - 0x40, 0x20, 0x01, 0x0d, // nlri(9) - 0xb8, 0x00, 0x01, 0x00, // = "2001:db8:1:1::/64" - 0x01, - } - // Test DecodeFromBytes() - p := &PathAttributeMpReachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x80), p.Flags) - assert.Equal(BGPAttrType(0xe), p.Type) - assert.Equal(uint16(0x1e), p.Length) - assert.Equal(uint16(AFI_IP6), p.AFI) - assert.Equal(uint8(SAFI_UNICAST), p.SAFI) - assert.Equal(net.ParseIP("::ffff:172.20.0.1"), p.Nexthop) - assert.Equal(net.ParseIP(""), p.LinkLocalNexthop) - value := []AddrPrefixInterface{ - NewIPv6AddrPrefix(64, "2001:db8:1:1::"), - } - assert.Equal(value, p.Value) - // Set NextHop as IPv4 address (because IPv4 peering) - p.Nexthop = net.ParseIP("172.20.0.1") - // Test Serialize() - bufout, err := p.Serialize() - assert.Nil(err) - // Test serialised value - assert.Equal(bufin, bufout) -} - -func Test_MpReachNLRIWithIPv6(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x90, 0x0e, 0x00, 0x1e, // flags(1), type(1), length(2), - 0x00, 0x02, 0x01, 0x10, // afi(2), safi(1), nexthoplen(1) - 0x20, 0x01, 0x0d, 0xb8, // nexthop(16) - 0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1" - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, // reserved(1) - 0x40, 0x20, 0x01, 0x0d, // nlri(9) - 0xb8, 0x00, 0x53, 0x00, // = "2001:db8:53::/64" - 0x00, - } - // Test DecodeFromBytes() - p := &PathAttributeMpReachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x90), p.Flags) - assert.Equal(BGPAttrType(0xe), p.Type) - assert.Equal(uint16(0x1e), p.Length) - assert.Equal(uint16(AFI_IP6), p.AFI) - assert.Equal(uint8(SAFI_UNICAST), p.SAFI) - assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop) - value := []AddrPrefixInterface{ - NewIPv6AddrPrefix(64, "2001:db8:53::"), - } - assert.Equal(value, p.Value) -} - -func Test_MpUnreachNLRIWithIPv6(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x90, 0x0f, 0x00, 0x0c, // flags(1), type(1), length(2), - 0x00, 0x02, 0x01, // afi(2), safi(1), - 0x40, 0x20, 0x01, 0x0d, // nlri(9) - 0xb8, 0x00, 0x53, 0x00, // = "2001:db8:53::/64" - 0x00, - } - // Test DecodeFromBytes() - p := &PathAttributeMpUnreachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x90), p.Flags) - assert.Equal(BGPAttrType(0xf), p.Type) - assert.Equal(uint16(0x0c), p.Length) - assert.Equal(uint16(AFI_IP6), p.AFI) - assert.Equal(uint8(SAFI_UNICAST), p.SAFI) - value := []AddrPrefixInterface{ - NewIPv6AddrPrefix(64, "2001:db8:53::"), - } - assert.Equal(value, p.Value) -} - -func Test_MpReachNLRIWithIPv6PrefixWithLinkLocalNexthop(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x80, 0x0e, 0x2c, // flags(1), type(1), length(1) - 0x00, 0x02, 0x01, 0x20, // afi(2), safi(1), nexthoplen(1) - 0x20, 0x01, 0x0d, 0xb8, // nexthop(32) - 0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1" - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0xfe, 0x80, 0x00, 0x00, // + "fe80::1" (link local) - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, // reserved(1) - 0x30, 0x20, 0x10, 0x0a, // nlri(7) - 0xb8, 0x00, 0x01, // = "2010:ab8:1::/48" - } - // Test DecodeFromBytes() - p := &PathAttributeMpReachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x80), p.Flags) - assert.Equal(BGPAttrType(0xe), p.Type) - assert.Equal(uint16(0x2c), p.Length) - assert.Equal(uint16(AFI_IP6), p.AFI) - assert.Equal(uint8(SAFI_UNICAST), p.SAFI) - assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop) - assert.Equal(net.ParseIP("fe80::1"), p.LinkLocalNexthop) - value := []AddrPrefixInterface{ - NewIPv6AddrPrefix(48, "2010:ab8:1::"), - } - assert.Equal(value, p.Value) - // Test Serialize() - bufout, err := p.Serialize() - assert.Nil(err) - // Test serialised value - assert.Equal(bufin, bufout) -} - -func Test_MpReachNLRIWithVPNv4Prefix(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x80, 0x0e, 0x20, // flags(1), type(1), length(1) - 0x00, 0x01, 0x80, 0x0c, // afi(2), safi(1), nexthoplen(1) - 0x00, 0x00, 0x00, 0x00, // nexthop(12) - 0x00, 0x00, 0x00, 0x00, // = (rd:"0:0",) "172.20.0.1" - 0xac, 0x14, 0x00, 0x01, - 0x00, // reserved(1) - 0x70, 0x00, 0x01, 0x01, // nlri(15) - 0x00, 0x00, 0xfd, 0xe8, // = label:16, rd:"65000:100", prefix:"10.1.1.0/24" - 0x00, 0x00, 0x00, 0x64, - 0x0a, 0x01, 0x01, - } - // Test DecodeFromBytes() - p := &PathAttributeMpReachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x80), p.Flags) - assert.Equal(BGPAttrType(0xe), p.Type) - assert.Equal(uint16(0x20), p.Length) - assert.Equal(uint16(AFI_IP), p.AFI) - assert.Equal(uint8(SAFI_MPLS_VPN), p.SAFI) - assert.Equal(net.ParseIP("172.20.0.1").To4(), p.Nexthop) - assert.Equal(net.ParseIP(""), p.LinkLocalNexthop) - value := []AddrPrefixInterface{ - NewLabeledVPNIPAddrPrefix(24, "10.1.1.0", *NewMPLSLabelStack(16), - NewRouteDistinguisherTwoOctetAS(65000, 100)), - } - assert.Equal(value, p.Value) - // Test Serialize() - bufout, err := p.Serialize() - assert.Nil(err) - // Test serialised value - assert.Equal(bufin, bufout) -} - -func Test_MpReachNLRIWithVPNv6Prefix(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x80, 0x0e, 0x39, // flags(1), type(1), length(1) - 0x00, 0x02, 0x80, 0x18, // afi(2), safi(1), nexthoplen(1) - 0x00, 0x00, 0x00, 0x00, // nexthop(24) - 0x00, 0x00, 0x00, 0x00, // = (rd:"0:0",) "2001:db8:1::1" - 0x20, 0x01, 0x0d, 0xb8, - 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, // reserved(1) - 0xd4, 0x00, 0x01, 0x01, // nlri(28) - 0x00, 0x00, 0xfd, 0xe8, // = label:16, rd:"65000:100", prefix:"2001:1::/124" - 0x00, 0x00, 0x00, 0x64, - 0x20, 0x01, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - } - // Test DecodeFromBytes() - p := &PathAttributeMpReachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x80), p.Flags) - assert.Equal(BGPAttrType(0xe), p.Type) - assert.Equal(uint16(0x39), p.Length) - assert.Equal(uint16(AFI_IP6), p.AFI) - assert.Equal(uint8(SAFI_MPLS_VPN), p.SAFI) - assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop) - assert.Equal(net.ParseIP(""), p.LinkLocalNexthop) - value := []AddrPrefixInterface{ - NewLabeledVPNIPv6AddrPrefix(124, "2001:1::", *NewMPLSLabelStack(16), - NewRouteDistinguisherTwoOctetAS(65000, 100)), - } - assert.Equal(value, p.Value) - // Test Serialize() - bufout, err := p.Serialize() - assert.Nil(err) - // Test serialised value - assert.Equal(bufin, bufout) -} - -func Test_MpReachNLRIWithIPv4PrefixWithIPv6Nexthop(t *testing.T) { - assert := assert.New(t) - bufin := []byte{ - 0x80, 0x0e, 0x19, // flags(1), type(1), length(1) - 0x00, 0x01, 0x01, 0x10, // afi(1), safi(1), nexthoplen(1) - 0x20, 0x01, 0x0d, 0xb8, // nexthop(32) - 0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1" - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, // reserved(1) - 0x18, 0xc0, 0xa8, 0x0a, // nlri(7) - } - // Test DecodeFromBytes() - p := &PathAttributeMpReachNLRI{} - err := p.DecodeFromBytes(bufin) - assert.Nil(err) - // Test decoded values - assert.Equal(BGPAttrFlag(0x80), p.Flags) - assert.Equal(BGPAttrType(0xe), p.Type) - assert.Equal(uint16(0x19), p.Length) - assert.Equal(uint16(AFI_IP), p.AFI) - assert.Equal(uint8(SAFI_UNICAST), p.SAFI) - assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop) - value := []AddrPrefixInterface{ - NewIPAddrPrefix(24, "192.168.10.0"), - } - assert.Equal(value, p.Value) - // Test Serialize() - bufout, err := p.Serialize() - assert.Nil(err) - // Test serialised value - assert.Equal(bufin, bufout) -} - -func Test_ParseRouteDistinguisher(t *testing.T) { - assert := assert.New(t) - - rd, _ := ParseRouteDistinguisher("100:1000") - rdType0, ok := rd.(*RouteDistinguisherTwoOctetAS) - if !ok { - t.Fatal("Type of RD interface is not RouteDistinguisherTwoOctetAS") - } - - assert.Equal(uint16(100), rdType0.Admin) - assert.Equal(uint32(1000), rdType0.Assigned) - - rd, _ = ParseRouteDistinguisher("10.0.0.0:100") - rdType1, ok := rd.(*RouteDistinguisherIPAddressAS) - if !ok { - t.Fatal("Type of RD interface is not RouteDistinguisherIPAddressAS") - } - - assert.Equal("10.0.0.0", rdType1.Admin.String()) - assert.Equal(uint16(100), rdType1.Assigned) - - rd, _ = ParseRouteDistinguisher("100.1000:10000") - rdType2, ok := rd.(*RouteDistinguisherFourOctetAS) - if !ok { - t.Fatal("Type of RD interface is not RouteDistinguisherFourOctetAS") - } - - assert.Equal(uint32((100<<16)|1000), rdType2.Admin) - assert.Equal(uint16(10000), rdType2.Assigned) -} - -func Test_ParseEthernetSegmentIdentifier(t *testing.T) { - assert := assert.New(t) - - // "single-homed" - esiZero := EthernetSegmentIdentifier{} - args := make([]string, 0) - esi, err := ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(esiZero, esi) - args = []string{"single-homed"} - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(esiZero, esi) - - // ESI_ARBITRARY - args = []string{"ARBITRARY", "11:22:33:44:55:66:77:88:99"} // omit "ESI_" - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESI_ARBITRARY, - Value: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, - }, esi) - - // ESI_LACP - args = []string{"lacp", "aa:bb:cc:dd:ee:ff", strconv.FormatInt(0x1122, 10)} // lower case - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESI_LACP, - Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x00}, - }, esi) - - // ESI_MSTP - args = []string{"esi_mstp", "aa:bb:cc:dd:ee:ff", strconv.FormatInt(0x1122, 10)} // omit "ESI_" + lower case - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESI_MSTP, - Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x00}, - }, esi) - - // ESI_MAC - args = []string{"ESI_MAC", "aa:bb:cc:dd:ee:ff", strconv.FormatInt(0x112233, 10)} - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESI_MAC, - Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33}, - }, esi) - - // ESI_ROUTERID - args = []string{"ESI_ROUTERID", "1.1.1.1", strconv.FormatInt(0x11223344, 10)} - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESI_ROUTERID, - Value: []byte{0x01, 0x01, 0x01, 0x01, 0x11, 0x22, 0x33, 0x44, 0x00}, - }, esi) - - // ESI_AS - args = []string{"ESI_AS", strconv.FormatInt(0xaabbccdd, 10), strconv.FormatInt(0x11223344, 10)} - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESI_AS, - Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22, 0x33, 0x44, 0x00}, - }, esi) - - // Other - args = []string{"99", "11:22:33:44:55:66:77:88:99"} - esi, err = ParseEthernetSegmentIdentifier(args) - assert.Nil(err) - assert.Equal(EthernetSegmentIdentifier{ - Type: ESIType(99), - Value: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99}, - }, esi) -} - -func TestParseBogusShortData(t *testing.T) { - var bodies = []BGPBody{ - &BGPOpen{}, - &BGPUpdate{}, - &BGPNotification{}, - &BGPKeepAlive{}, - &BGPRouteRefresh{}, - } - - for _, b := range bodies { - b.DecodeFromBytes([]byte{0}) - } -} - -func TestFuzzCrashers(t *testing.T) { - var crashers = []string{ - "000000000000000000\x01", - } - - for _, f := range crashers { - ParseBGPMessage([]byte(f)) - } -} - -func TestNormalizeFlowSpecOpValues(t *testing.T) { - tests := []struct { - msg string - args []string - want []string - }{ - { - msg: "valid match", - args: []string{" & <=80", " tcp != udp ", " =! SA & =U! F", " = is-fragment+last-fragment"}, - want: []string{"<=80", "tcp", "!=udp", "=!SA", "&=U", "!F", "=is-fragment+last-fragment"}, - }, - { - msg: "RFC5575 trims & prefix", - args: []string{"&<=80"}, - want: []string{"<=80"}, - }, - } - - for _, tt := range tests { - t.Run(tt.msg, func(t *testing.T) { - got := normalizeFlowSpecOpValues(tt.args) - assert.Equal(t, tt.want, got) - }) - } -} diff --git a/packet/bgp/bgpattrtype_string.go b/packet/bgp/bgpattrtype_string.go deleted file mode 100644 index 1a2cf1d0..00000000 --- a/packet/bgp/bgpattrtype_string.go +++ /dev/null @@ -1,28 +0,0 @@ -// generated by stringer -type BGPAttrType bgp.go; DO NOT EDIT - -package bgp - -import "fmt" - -const ( - _BGPAttrType_name_0 = "BGP_ATTR_TYPE_ORIGINBGP_ATTR_TYPE_AS_PATHBGP_ATTR_TYPE_NEXT_HOPBGP_ATTR_TYPE_MULTI_EXIT_DISCBGP_ATTR_TYPE_LOCAL_PREFBGP_ATTR_TYPE_ATOMIC_AGGREGATEBGP_ATTR_TYPE_AGGREGATORBGP_ATTR_TYPE_COMMUNITIESBGP_ATTR_TYPE_ORIGINATOR_IDBGP_ATTR_TYPE_CLUSTER_LIST" - _BGPAttrType_name_1 = "BGP_ATTR_TYPE_MP_REACH_NLRIBGP_ATTR_TYPE_MP_UNREACH_NLRIBGP_ATTR_TYPE_EXTENDED_COMMUNITIESBGP_ATTR_TYPE_AS4_PATHBGP_ATTR_TYPE_AS4_AGGREGATOR" -) - -var ( - _BGPAttrType_index_0 = [...]uint8{0, 20, 41, 63, 92, 116, 146, 170, 195, 222, 248} - _BGPAttrType_index_1 = [...]uint8{0, 27, 56, 90, 112, 140} -) - -func (i BGPAttrType) String() string { - switch { - case 1 <= i && i <= 10: - i -= 1 - return _BGPAttrType_name_0[_BGPAttrType_index_0[i]:_BGPAttrType_index_0[i+1]] - case 14 <= i && i <= 18: - i -= 14 - return _BGPAttrType_name_1[_BGPAttrType_index_1[i]:_BGPAttrType_index_1[i+1]] - default: - return fmt.Sprintf("BGPAttrType(%d)", i) - } -} diff --git a/packet/bgp/constant.go b/packet/bgp/constant.go deleted file mode 100644 index 5ea7b414..00000000 --- a/packet/bgp/constant.go +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (C) 2014 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. - -package bgp - -import ( - "fmt" - "strings" -) - -const AS_TRANS = 23456 - -const BGP_PORT = 179 - -type FSMState int - -const ( - BGP_FSM_IDLE FSMState = iota - BGP_FSM_CONNECT - BGP_FSM_ACTIVE - BGP_FSM_OPENSENT - BGP_FSM_OPENCONFIRM - BGP_FSM_ESTABLISHED -) - -// partially taken from http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml -type Protocol int - -const ( - Unknown Protocol = iota - ICMP = 0x01 - IGMP = 0x02 - TCP = 0x06 - EGP = 0x08 - IGP = 0x09 - UDP = 0x11 - RSVP = 0x2e - GRE = 0x2f - OSPF = 0x59 - IPIP = 0x5e - PIM = 0x67 - SCTP = 0x84 -) - -var ProtocolNameMap = map[Protocol]string{ - Unknown: "unknown", - ICMP: "icmp", - IGMP: "igmp", - TCP: "tcp", - EGP: "egp", - IGP: "igp", - UDP: "udp", - RSVP: "rsvp", - GRE: "gre", - OSPF: "ospf", - IPIP: "ipip", - PIM: "pim", - SCTP: "sctp", -} - -func (p Protocol) String() string { - name, ok := ProtocolNameMap[p] - if !ok { - return fmt.Sprintf("%d", p) - } - return name -} - -type TCPFlag int - -const ( - _ TCPFlag = iota - TCP_FLAG_FIN = 0x01 - TCP_FLAG_SYN = 0x02 - TCP_FLAG_RST = 0x04 - TCP_FLAG_PUSH = 0x08 - TCP_FLAG_ACK = 0x10 - TCP_FLAG_URGENT = 0x20 - TCP_FLAG_ECE = 0x40 - TCP_FLAG_CWR = 0x80 -) - -var TCPFlagNameMap = map[TCPFlag]string{ - TCP_FLAG_FIN: "F", - TCP_FLAG_SYN: "S", - TCP_FLAG_RST: "R", - TCP_FLAG_PUSH: "P", - TCP_FLAG_ACK: "A", - TCP_FLAG_URGENT: "U", - TCP_FLAG_CWR: "C", - TCP_FLAG_ECE: "E", -} - -// Prepares a sorted list of flags because map iterations does not happen -// in a consistent order in Golang. -var TCPSortedFlags = []TCPFlag{ - TCP_FLAG_FIN, - TCP_FLAG_SYN, - TCP_FLAG_RST, - TCP_FLAG_PUSH, - TCP_FLAG_ACK, - TCP_FLAG_URGENT, - TCP_FLAG_ECE, - TCP_FLAG_CWR, -} - -func (f TCPFlag) String() string { - flags := make([]string, 0, len(TCPSortedFlags)) - for _, v := range TCPSortedFlags { - if f&v > 0 { - flags = append(flags, TCPFlagNameMap[v]) - } - } - return strings.Join(flags, "") -} - -type BitmaskFlagOp uint8 - -const ( - BITMASK_FLAG_OP_OR BitmaskFlagOp = iota - BITMASK_FLAG_OP_MATCH = 0x01 - BITMASK_FLAG_OP_NOT = 0x02 - BITMASK_FLAG_OP_NOT_MATCH = 0x03 - BITMASK_FLAG_OP_AND = 0x40 - BITMASK_FLAG_OP_END = 0x80 -) - -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: "=", -} - -// Note: Meaning of "" is different from that of the numeric operator because -// RFC5575 says if the Match bit in the bitmask operand is set, it should be -// "strictly" matching against the given value. -var BitmaskFlagOpValueMap = map[string]BitmaskFlagOp{ - " ": BITMASK_FLAG_OP_OR, - "": BITMASK_FLAG_OP_OR, - "==": BITMASK_FLAG_OP_MATCH, - "=": BITMASK_FLAG_OP_MATCH, - "!": BITMASK_FLAG_OP_NOT, - "!=": BITMASK_FLAG_OP_NOT_MATCH, - "=!": BITMASK_FLAG_OP_NOT_MATCH, // For the backward compatibility - "&": BITMASK_FLAG_OP_AND, - "E": BITMASK_FLAG_OP_END, -} - -func (f BitmaskFlagOp) String() string { - ops := make([]string, 0) - if f&BITMASK_FLAG_OP_AND > 0 { - ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND]) - } else { - ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR]) - } - if f&BITMASK_FLAG_OP_NOT > 0 { - ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT]) - } - if f&BITMASK_FLAG_OP_MATCH > 0 { - ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH]) - } - return strings.Join(ops, "") -} - -type FragmentFlag int - -const ( - FRAG_FLAG_NOT FragmentFlag = iota - 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", -} - -// Prepares a sorted list of flags because map iterations does not happen -// in a consistent order in Golang. -var FragmentSortedFlags = []FragmentFlag{ - FRAG_FLAG_NOT, - FRAG_FLAG_DONT, - FRAG_FLAG_IS, - FRAG_FLAG_FIRST, - FRAG_FLAG_LAST, -} - -func (f FragmentFlag) String() string { - flags := make([]string, 0, len(FragmentSortedFlags)) - for _, v := range FragmentSortedFlags { - if f&v > 0 { - flags = append(flags, FragmentFlagNameMap[v]) - } - } - // Note: If multiple bits are set, joins them with "+". - return strings.Join(flags, "+") -} - -type DECNumOp uint8 - -const ( - DEC_NUM_OP_TRUE DECNumOp = iota // true always with END bit set - DEC_NUM_OP_EQ = 0x01 - DEC_NUM_OP_GT = 0x02 - DEC_NUM_OP_GT_EQ = 0x03 - DEC_NUM_OP_LT = 0x04 - DEC_NUM_OP_LT_EQ = 0x05 - DEC_NUM_OP_NOT_EQ = 0x06 - DEC_NUM_OP_FALSE = 0x07 // false always with END bit set - DEC_NUM_OP_OR = 0x00 - DEC_NUM_OP_AND = 0x40 - DEC_NUM_OP_END = 0x80 -) - -var DECNumOpNameMap = map[DECNumOp]string{ - DEC_NUM_OP_TRUE: "true", - DEC_NUM_OP_EQ: "==", - DEC_NUM_OP_GT: ">", - DEC_NUM_OP_GT_EQ: ">=", - DEC_NUM_OP_LT: "<", - DEC_NUM_OP_LT_EQ: "<=", - DEC_NUM_OP_NOT_EQ: "!=", - DEC_NUM_OP_FALSE: "false", - //DEC_NUM_OP_OR: " ", // duplicate with DEC_NUM_OP_TRUE - DEC_NUM_OP_AND: "&", - DEC_NUM_OP_END: "E", -} - -var DECNumOpValueMap = map[string]DECNumOp{ - "true": DEC_NUM_OP_TRUE, - "": DEC_NUM_OP_EQ, - "==": DEC_NUM_OP_EQ, - "=": DEC_NUM_OP_EQ, - ">": DEC_NUM_OP_GT, - ">=": DEC_NUM_OP_GT_EQ, - "<": DEC_NUM_OP_LT, - "<=": DEC_NUM_OP_LT_EQ, - "!=": DEC_NUM_OP_NOT_EQ, - "=!": DEC_NUM_OP_NOT_EQ, - "!": DEC_NUM_OP_NOT_EQ, - "false": DEC_NUM_OP_FALSE, - " ": DEC_NUM_OP_OR, - "&": DEC_NUM_OP_AND, - "E": DEC_NUM_OP_END, -} - -func (f DECNumOp) String() string { - ops := make([]string, 0) - logicFlag := DECNumOp(f & 0xc0) // higher 2 bits - if logicFlag&DEC_NUM_OP_AND > 0 { - ops = append(ops, DECNumOpNameMap[DEC_NUM_OP_AND]) - } else { - ops = append(ops, " ") // DEC_NUM_OP_OR - } - // Omits DEC_NUM_OP_END - cmpFlag := DECNumOp(f & 0x7) // lower 3 bits - for v, s := range DECNumOpNameMap { - if cmpFlag == v { - ops = append(ops, s) - break - } - } - return strings.Join(ops, "") -} - -// Potentially taken from https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml -type EthernetType int - -const ( - IPv4 EthernetType = 0x0800 - ARP EthernetType = 0x0806 - RARP EthernetType = 0x8035 - VMTP EthernetType = 0x805B - APPLE_TALK EthernetType = 0x809B - AARP EthernetType = 0x80F3 - IPX EthernetType = 0x8137 - SNMP EthernetType = 0x814C - NET_BIOS EthernetType = 0x8191 - XTP EthernetType = 0x817D - IPv6 EthernetType = 0x86DD - PPPoE_DISCOVERY EthernetType = 0x8863 - PPPoE_SESSION EthernetType = 0x8864 - LOOPBACK EthernetType = 0x9000 -) - -var EthernetTypeNameMap = map[EthernetType]string{ - IPv4: "ipv4", - ARP: "arp", - RARP: "rarp", - VMTP: "vmtp", - APPLE_TALK: "apple-talk", - AARP: "aarp", - IPX: "ipx", - SNMP: "snmp", - NET_BIOS: "net-bios", - XTP: "xtp", - IPv6: "ipv6", - PPPoE_DISCOVERY: "pppoe-discovery", - PPPoE_SESSION: "pppoe-session", - LOOPBACK: "loopback", -} - -func (t EthernetType) String() string { - if name, ok := EthernetTypeNameMap[t]; ok { - return name - } - return fmt.Sprintf("%d", t) -} diff --git a/packet/bgp/esitype_string.go b/packet/bgp/esitype_string.go deleted file mode 100644 index 5651bda8..00000000 --- a/packet/bgp/esitype_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// generated by stringer -type=ESIType bgp.go validate.go; DO NOT EDIT - -package bgp - -import "fmt" - -const _ESIType_name = "ESI_ARBITRARYESI_LACPESI_MSTPESI_MACESI_ROUTERIDESI_AS" - -var _ESIType_index = [...]uint8{0, 13, 21, 29, 36, 48, 54} - -func (i ESIType) String() string { - if i+1 >= ESIType(len(_ESIType_index)) { - return fmt.Sprintf("ESIType(%d)", i) - } - return _ESIType_name[_ESIType_index[i]:_ESIType_index[i+1]] -} diff --git a/packet/bgp/fsmstate_string.go b/packet/bgp/fsmstate_string.go deleted file mode 100644 index 4416afc1..00000000 --- a/packet/bgp/fsmstate_string.go +++ /dev/null @@ -1,16 +0,0 @@ -// generated by stringer -type=FSMState -output=fsmstate_string.go bgp.go validate.go mrt.go rtr.go constant.go bmp.go esitype_string.go bgpattrtype_string.go; DO NOT EDIT - -package bgp - -import "fmt" - -const _FSMState_name = "BGP_FSM_IDLEBGP_FSM_CONNECTBGP_FSM_ACTIVEBGP_FSM_OPENSENTBGP_FSM_OPENCONFIRMBGP_FSM_ESTABLISHED" - -var _FSMState_index = [...]uint8{0, 12, 27, 41, 57, 76, 95} - -func (i FSMState) String() string { - if i < 0 || i >= FSMState(len(_FSMState_index)-1) { - return fmt.Sprintf("FSMState(%d)", i) - } - return _FSMState_name[_FSMState_index[i]:_FSMState_index[i+1]] -} diff --git a/packet/bgp/helper.go b/packet/bgp/helper.go deleted file mode 100644 index 34648b2d..00000000 --- a/packet/bgp/helper.go +++ /dev/null @@ -1,126 +0,0 @@ -// 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. - -package bgp - -func NewTestBGPOpenMessage() *BGPMessage { - p1 := NewOptionParameterCapability( - []ParameterCapabilityInterface{NewCapRouteRefresh()}) - p2 := NewOptionParameterCapability( - []ParameterCapabilityInterface{NewCapMultiProtocol(RF_IPv4_UC)}) - g := &CapGracefulRestartTuple{4, 2, 3} - p3 := NewOptionParameterCapability( - []ParameterCapabilityInterface{NewCapGracefulRestart(false, true, 100, - []*CapGracefulRestartTuple{g})}) - p4 := NewOptionParameterCapability( - []ParameterCapabilityInterface{NewCapFourOctetASNumber(100000)}) - p5 := NewOptionParameterCapability( - []ParameterCapabilityInterface{NewCapAddPath([]*CapAddPathTuple{NewCapAddPathTuple(RF_IPv4_UC, BGP_ADD_PATH_BOTH)})}) - return NewBGPOpenMessage(11033, 303, "100.4.10.3", - []OptionParameterInterface{p1, p2, p3, p4, p5}) -} - -func NewTestBGPUpdateMessage() *BGPMessage { - w1 := NewIPAddrPrefix(23, "121.1.3.2") - w2 := NewIPAddrPrefix(17, "100.33.3.0") - w := []*IPAddrPrefix{w1, w2} - - aspath1 := []AsPathParamInterface{ - NewAsPathParam(2, []uint16{1000}), - NewAsPathParam(1, []uint16{1001, 1002}), - NewAsPathParam(2, []uint16{1003, 1004}), - } - - aspath2 := []AsPathParamInterface{ - NewAs4PathParam(2, []uint32{1000000}), - NewAs4PathParam(1, []uint32{1000001, 1002}), - NewAs4PathParam(2, []uint32{1003, 100004}), - } - - aspath3 := []*As4PathParam{ - NewAs4PathParam(2, []uint32{1000000}), - NewAs4PathParam(1, []uint32{1000001, 1002}), - NewAs4PathParam(2, []uint32{1003, 100004}), - } - - isTransitive := true - - ecommunities := []ExtendedCommunityInterface{ - 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), - NewOpaqueExtended(false, []byte{1, 2, 3, 4, 5, 6, 7}), - NewValidationExtended(VALIDATION_STATE_INVALID), - NewUnknownExtended(99, []byte{0, 1, 2, 3, 4, 5, 6, 7}), - NewESILabelExtended(1000, true), - NewESImportRouteTarget("11:22:33:44:55:66"), - NewMacMobilityExtended(123, false), - } - - prefixes1 := []AddrPrefixInterface{ - NewLabeledVPNIPAddrPrefix(24, "192.0.9.0", *NewMPLSLabelStack(1, 2, 3), - NewRouteDistinguisherTwoOctetAS(256, 10000)), - NewLabeledVPNIPAddrPrefix(24, "192.10.8.0", *NewMPLSLabelStack(5, 6, 7, 8), - NewRouteDistinguisherIPAddressAS("10.0.1.1", 10001)), - } - - prefixes2 := []AddrPrefixInterface{NewIPv6AddrPrefix(128, - "fe80:1234:1234:5667:8967:af12:8912:1023")} - - prefixes3 := []AddrPrefixInterface{NewLabeledVPNIPv6AddrPrefix(128, - "fe80:1234:1234:5667:8967:af12:1203:33a1", *NewMPLSLabelStack(5, 6), - NewRouteDistinguisherFourOctetAS(5, 6))} - - prefixes4 := []AddrPrefixInterface{NewLabeledIPAddrPrefix(25, "192.168.0.0", - *NewMPLSLabelStack(5, 6, 7))} - - prefixes5 := []AddrPrefixInterface{ - NewEVPNEthernetAutoDiscoveryRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2), - NewEVPNMacIPAdvertisementRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 3, "01:23:45:67:89:ab", "192.2.1.2", []uint32{3, 4}), - NewEVPNMulticastEthernetTagRoute(NewRouteDistinguisherFourOctetAS(5, 6), 3, "192.2.1.2"), - NewEVPNEthernetSegmentRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, "192.2.1.1"), - NewEVPNIPPrefixRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 5, 24, "192.2.1.0", "192.3.1.1", 5), - } - - p := []PathAttributeInterface{ - NewPathAttributeOrigin(3), - NewPathAttributeAsPath(aspath1), - NewPathAttributeAsPath(aspath2), - NewPathAttributeNextHop("129.1.1.2"), - NewPathAttributeMultiExitDisc(1 << 20), - NewPathAttributeLocalPref(1 << 22), - NewPathAttributeAtomicAggregate(), - NewPathAttributeAggregator(uint16(30002), "129.0.2.99"), - NewPathAttributeAggregator(uint32(30002), "129.0.2.99"), - NewPathAttributeAggregator(uint32(300020), "129.0.2.99"), - NewPathAttributeCommunities([]uint32{1, 3}), - NewPathAttributeOriginatorId("10.10.0.1"), - NewPathAttributeClusterList([]string{"10.10.0.2", "10.10.0.3"}), - NewPathAttributeExtendedCommunities(ecommunities), - NewPathAttributeAs4Path(aspath3), - NewPathAttributeAs4Aggregator(10000, "112.22.2.1"), - NewPathAttributeMpReachNLRI("112.22.2.0", prefixes1), - NewPathAttributeMpReachNLRI("1023::", prefixes2), - NewPathAttributeMpReachNLRI("fe80::", prefixes3), - NewPathAttributeMpReachNLRI("129.1.1.1", prefixes4), - NewPathAttributeMpReachNLRI("129.1.1.1", prefixes5), - NewPathAttributeMpUnreachNLRI(prefixes1), - //NewPathAttributeMpReachNLRI("112.22.2.0", []AddrPrefixInterface{}), - //NewPathAttributeMpUnreachNLRI([]AddrPrefixInterface{}), - NewPathAttributeUnknown(BGP_ATTR_FLAG_TRANSITIVE, 100, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}), - } - n := []*IPAddrPrefix{NewIPAddrPrefix(24, "13.2.3.1")} - return NewBGPUpdateMessage(w, p, n) -} diff --git a/packet/bgp/validate.go b/packet/bgp/validate.go deleted file mode 100644 index 60cf26e4..00000000 --- a/packet/bgp/validate.go +++ /dev/null @@ -1,337 +0,0 @@ -package bgp - -import ( - "encoding/binary" - "fmt" - "math" - "net" - "strconv" -) - -// Validator for BGPUpdate -func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) { - var strongestError 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) - - if len(m.NLRI) > 0 || len(m.WithdrawnRoutes) > 0 { - if _, ok := rfs[RF_IPv4_UC]; !ok { - return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", RF_IPv4_UC)) - } - } - - seen := make(map[BGPAttrType]PathAttributeInterface) - newAttrs := make([]PathAttributeInterface, 0, len(seen)) - // check path attribute - for _, a := range m.PathAttributes { - // check duplication - if _, ok := seen[a.GetType()]; !ok { - seen[a.GetType()] = a - newAttrs = append(newAttrs, a) - //check specific path attribute - ok, err := ValidateAttribute(a, rfs, isEBGP, isConfed) - if !ok { - if err.(*MessageError).ErrorHandling == ERROR_HANDLING_SESSION_RESET { - return false, err - } else if err.(*MessageError).Stronger(strongestError) { - strongestError = err - } - } - } else if a.GetType() == BGP_ATTR_TYPE_MP_REACH_NLRI || a.GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI { - eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType())) - return false, NewMessageError(eCode, eSubCodeAttrList, nil, eMsg) - } else { - eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType())) - e := NewMessageErrorWithErrorHandling(eCode, eSubCodeAttrList, nil, ERROR_HANDLING_ATTRIBUTE_DISCARD, nil, eMsg) - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - } - } - m.PathAttributes = newAttrs - - if _, ok := seen[BGP_ATTR_TYPE_MP_REACH_NLRI]; ok || len(m.NLRI) > 0 { - // check the existence of well-known mandatory attributes - exist := func(attrs []BGPAttrType) (bool, BGPAttrType) { - for _, attr := range attrs { - _, ok := seen[attr] - if !ok { - return false, attr - } - } - return true, 0 - } - mandatory := []BGPAttrType{BGP_ATTR_TYPE_ORIGIN, BGP_ATTR_TYPE_AS_PATH} - if len(m.NLRI) > 0 { - mandatory = append(mandatory, BGP_ATTR_TYPE_NEXT_HOP) - } - if ok, t := exist(mandatory); !ok { - eMsg := "well-known mandatory attributes are not present. type : " + strconv.Itoa(int(t)) - data := []byte{byte(t)} - e := NewMessageErrorWithErrorHandling(eCode, eSubCodeMissing, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, eMsg) - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - } - } - - return strongestError == nil, strongestError -} - -func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) { - var strongestError error - - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE) - eSubCodeBadNextHop := uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE) - eSubCodeUnknown := uint8(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE) - eSubCodeMalformedAspath := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) - - checkPrefix := func(l []AddrPrefixInterface) error { - for _, prefix := range l { - rf := AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI()) - if _, ok := rfs[rf]; !ok { - return NewMessageError(0, 0, nil, fmt.Sprintf("Address-family %s not available for this session", rf)) - } - switch rf { - case RF_FS_IPv4_UC, RF_FS_IPv6_UC, RF_FS_IPv4_VPN, RF_FS_IPv6_VPN, RF_FS_L2_VPN: - t := BGPFlowSpecType(0) - value := make([]FlowSpecComponentInterface, 0) - switch rf { - case RF_FS_IPv4_UC: - value = prefix.(*FlowSpecIPv4Unicast).Value - case RF_FS_IPv6_UC: - value = prefix.(*FlowSpecIPv6Unicast).Value - case RF_FS_IPv4_VPN: - value = prefix.(*FlowSpecIPv4VPN).Value - case RF_FS_IPv6_VPN: - value = prefix.(*FlowSpecIPv6VPN).Value - case RF_FS_L2_VPN: - value = prefix.(*FlowSpecL2VPN).Value - } - for _, v := range value { - if v.Type() <= t { - return NewMessageError(0, 0, nil, fmt.Sprintf("%s nlri violate strict type ordering", rf)) - } - t = v.Type() - } - } - } - return nil - } - - switch p := a.(type) { - case *PathAttributeMpUnreachNLRI: - rf := AfiSafiToRouteFamily(p.AFI, p.SAFI) - if _, ok := rfs[rf]; !ok { - return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf)) - } - if err := checkPrefix(p.Value); err != nil { - return false, err - } - case *PathAttributeMpReachNLRI: - rf := AfiSafiToRouteFamily(p.AFI, p.SAFI) - if _, ok := rfs[rf]; !ok { - return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf)) - } - if err := checkPrefix(p.Value); err != nil { - return false, err - } - case *PathAttributeOrigin: - v := uint8(p.Value) - if v != BGP_ORIGIN_ATTR_TYPE_IGP && - v != BGP_ORIGIN_ATTR_TYPE_EGP && - v != BGP_ORIGIN_ATTR_TYPE_INCOMPLETE { - data, _ := a.Serialize() - eMsg := "invalid origin attribute. value : " + strconv.Itoa(int(v)) - e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadOrigin, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg) - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - } - case *PathAttributeNextHop: - - isZero := func(ip net.IP) bool { - res := ip[0] & 0xff - return res == 0x00 - } - - isClassDorE := func(ip net.IP) bool { - res := ip[0] & 0xe0 - return res == 0xe0 - } - - //check IP address represents host address - if p.Value.IsLoopback() || isZero(p.Value) || isClassDorE(p.Value) { - eMsg := "invalid nexthop address" - data, _ := a.Serialize() - e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadNextHop, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg) - if e.(*MessageError).Stronger(strongestError) { - strongestError = e - } - } - case *PathAttributeAsPath: - if isEBGP { - if isConfed { - if segType := p.Value[0].GetType(); segType != BGP_ASPATH_ATTR_TYPE_CONFED_SEQ { - return false, NewMessageError(eCode, eSubCodeMalformedAspath, nil, fmt.Sprintf("segment type is not confederation seq (%d)", segType)) - } - } else { - for _, param := range p.Value { - segType := param.GetType() - switch segType { - case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: - err := NewMessageErrorWithErrorHandling( - eCode, eSubCodeMalformedAspath, nil, getErrorHandlingFromPathAttribute(p.GetType()), nil, fmt.Sprintf("segment type confederation(%d) found", segType)) - if err.(*MessageError).Stronger(strongestError) { - strongestError = err - } - } - } - } - } - case *PathAttributeLargeCommunities: - uniq := make([]*LargeCommunity, 0, len(p.Values)) - for _, x := range p.Values { - found := false - for _, y := range uniq { - if x.String() == y.String() { - found = true - break - } - } - if !found { - uniq = append(uniq, x) - } - } - p.Values = uniq - - case *PathAttributeUnknown: - if p.GetFlags()&BGP_ATTR_FLAG_OPTIONAL == 0 { - eMsg := fmt.Sprintf("unrecognized well-known attribute %s", p.GetType()) - data, _ := a.Serialize() - return false, NewMessageError(eCode, eSubCodeUnknown, data, eMsg) - } - } - - return strongestError == nil, strongestError -} - -// validator for PathAttribute -func validatePathAttributeFlags(t BGPAttrType, flags BGPAttrFlag) string { - - /* - * RFC 4271 P.17 For well-known attributes, the Transitive bit MUST be set to 1. - */ - if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 { - eMsg := fmt.Sprintf("well-known attribute %s must have transitive flag 1", t) - return eMsg - } - /* - * RFC 4271 P.17 For well-known attributes and for optional non-transitive attributes, - * the Partial bit MUST be set to 0. - */ - if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 { - eMsg := fmt.Sprintf("well-known attribute %s must have partial bit 0", t) - return eMsg - } - if flags&BGP_ATTR_FLAG_OPTIONAL != 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 { - eMsg := fmt.Sprintf("optional non-transitive attribute %s must have partial bit 0", t) - return eMsg - } - - // check flags are correct - if f, ok := PathAttrFlags[t]; ok { - if f != flags & ^BGP_ATTR_FLAG_EXTENDED_LENGTH & ^BGP_ATTR_FLAG_PARTIAL { - eMsg := fmt.Sprintf("flags are invalid. attribute type: %s, expect: %s, actual: %s", t, f, flags) - return eMsg - } - } - return "" -} - -func validateAsPathValueBytes(data []byte) (bool, error) { - eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR) - eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH) - if len(data)%2 != 0 { - return false, NewMessageError(eCode, eSubCode, nil, "AS PATH length is not odd") - } - - tryParse := func(data []byte, use4byte bool) (bool, error) { - for len(data) > 0 { - if len(data) < 2 { - return false, NewMessageError(eCode, eSubCode, nil, "AS PATH header is short") - } - segType := data[0] - if segType == 0 || segType > 4 { - return false, NewMessageError(eCode, eSubCode, nil, "unknown AS_PATH seg type") - } - asNum := data[1] - data = data[2:] - if asNum == 0 || int(asNum) > math.MaxUint8 { - return false, NewMessageError(eCode, eSubCode, nil, "AS PATH the number of AS is incorrect") - } - segLength := int(asNum) - if use4byte { - segLength *= 4 - } else { - segLength *= 2 - } - if int(segLength) > len(data) { - return false, NewMessageError(eCode, eSubCode, nil, "seg length is short") - } - data = data[segLength:] - } - return true, nil - } - _, err := tryParse(data, true) - if err == nil { - return true, nil - } - - _, err = tryParse(data, false) - if err == nil { - return false, nil - } - return false, NewMessageError(eCode, eSubCode, nil, "can't parse AS_PATH") -} - -func ValidateBGPMessage(m *BGPMessage) error { - if m.Header.Len > BGP_MAX_MESSAGE_LENGTH { - buf := make([]byte, 2) - binary.BigEndian.PutUint16(buf, m.Header.Len) - return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, buf, "too long length") - } - - return nil -} - -func ValidateOpenMsg(m *BGPOpen, expectedAS uint32) (uint32, error) { - if m.Version != 4 { - return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER, nil, fmt.Sprintf("unsupported version %d", m.Version)) - } - - as := uint32(m.MyAS) - for _, p := range m.OptParams { - paramCap, y := p.(*OptionParameterCapability) - if !y { - continue - } - for _, c := range paramCap.Capability { - if c.Code() == BGP_CAP_FOUR_OCTET_AS_NUMBER { - cap := c.(*CapFourOctetASNumber) - as = cap.CapValue - } - } - } - if expectedAS != 0 && as != expectedAS { - return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_BAD_PEER_AS, nil, fmt.Sprintf("as number mismatch expected %d, received %d", expectedAS, as)) - } - - if m.HoldTime < 3 && m.HoldTime != 0 { - return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME, nil, fmt.Sprintf("unacceptable hold time %d", m.HoldTime)) - } - return as, nil -} diff --git a/packet/bgp/validate_test.go b/packet/bgp/validate_test.go deleted file mode 100644 index 8bdec550..00000000 --- a/packet/bgp/validate_test.go +++ /dev/null @@ -1,423 +0,0 @@ -package bgp - -import ( - "encoding/binary" - "net" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func bgpupdate() *BGPMessage { - aspath := []AsPathParamInterface{ - NewAsPathParam(2, []uint16{65001}), - } - - p := []PathAttributeInterface{ - NewPathAttributeOrigin(1), - NewPathAttributeAsPath(aspath), - NewPathAttributeNextHop("192.168.1.1"), - } - - n := []*IPAddrPrefix{NewIPAddrPrefix(24, "10.10.10.0")} - return NewBGPUpdateMessage(nil, p, n) -} - -func bgpupdateV6() *BGPMessage { - aspath := []AsPathParamInterface{ - NewAsPathParam(2, []uint16{65001}), - } - - prefixes := []AddrPrefixInterface{NewIPv6AddrPrefix(100, - "fe80:1234:1234:5667:8967:af12:8912:1023")} - - p := []PathAttributeInterface{ - NewPathAttributeOrigin(1), - NewPathAttributeAsPath(aspath), - NewPathAttributeMpReachNLRI("1023::", prefixes), - } - return NewBGPUpdateMessage(nil, p, nil) -} - -func Test_Validate_CapV4(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - - res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - require.NoError(t, err) - 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]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.NoError(err) - assert.True(res) - - res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Error(err) - assert.False(res) -} - -func Test_Validate_OK(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(true, res) - assert.NoError(err) - -} - -// func Test_Validate_wellknown_but_nontransitive(t *testing.T) { -// assert := assert.New(t) -// message := bgpupdate().Body.(*BGPUpdate) - -// originBytes := []byte{0, 1, 1, 1} // 0 means Flags -// origin := &PathAttributeOrigin{} -// origin.DecodeFromBytes(originBytes) -// message.PathAttributes[0] = origin - -// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,}) -// assert.Equal(false, res) -// assert.Error(err) -// e := err.(*MessageError) -// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) -// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) -// assert.Equal(originBytes, e.Data) -// } - -// func Test_Validate_wellknown_but_partial(t *testing.T) { -// assert := assert.New(t) -// message := bgpupdate().Body.(*BGPUpdate) - -// originBytes := []byte{BGP_ATTR_FLAG_PARTIAL, 1, 1, 1} -// origin := &PathAttributeOrigin{} -// origin.DecodeFromBytes(originBytes) -// message.PathAttributes[0] = origin - -// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,}) -// assert.Equal(false, res) -// assert.Error(err) -// e := err.(*MessageError) -// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) -// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) -// assert.Equal(originBytes, e.Data) -// } - -// func Test_Validate_optional_nontransitive_but_partial(t *testing.T) { -// assert := assert.New(t) -// message := bgpupdate().Body.(*BGPUpdate) -// f := BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_PARTIAL -// originBytes := []byte{byte(f), 1, 1, 1} -// origin := &PathAttributeOrigin{} -// origin.DecodeFromBytes(originBytes) -// message.PathAttributes[0] = origin - -// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,}) -// assert.Equal(false, res) -// assert.Error(err) -// e := err.(*MessageError) -// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) -// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) -// assert.Equal(originBytes, e.Data) -// } - -// func Test_Validate_flag_mismatch(t *testing.T) { -// assert := assert.New(t) -// message := bgpupdate().Body.(*BGPUpdate) -// f := BGP_ATTR_FLAG_OPTIONAL -// // origin needs to be well-known -// originBytes := []byte{byte(f), 1, 1, 1} -// origin := &PathAttributeOrigin{} -// origin.DecodeFromBytes(originBytes) -// message.PathAttributes[0] = origin - -// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,}) -// assert.Equal(false, res) -// assert.Error(err) -// e := err.(*MessageError) -// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode) -// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode) -// assert.Equal(originBytes, e.Data) -// } - -func Test_Validate_duplicate_attribute(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - // duplicate origin path attribute - originBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_ORIGIN]), 1, 1, 1} - origin := &PathAttributeOrigin{} - origin.DecodeFromBytes(originBytes) - message.PathAttributes = append(message.PathAttributes, origin) - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_ATTRIBUTE_DISCARD, e.ErrorHandling) - assert.Nil(e.Data) -} - -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]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - missing, _ := binary.Uvarint(e.Data) - assert.Equal(uint64(1), missing) -} - -func Test_Validate_mandatory_missing_nocheck(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - message.PathAttributes = message.PathAttributes[1:] - message.NLRI = nil - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(true, res) - assert.NoError(err) -} - -func Test_Validate_invalid_origin(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - // origin needs to be well-known - originBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_ORIGIN]), 1, 1, 5} - origin := &PathAttributeOrigin{} - origin.DecodeFromBytes(originBytes) - message.PathAttributes[0] = origin - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - assert.Equal(originBytes, e.Data) -} - -func Test_Validate_invalid_nexthop_zero(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - - // invalid nexthop - addr := net.ParseIP("0.0.0.1").To4() - nexthopBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP]), 3, 4} - nexthopBytes = append(nexthopBytes, addr...) - nexthop := &PathAttributeNextHop{} - nexthop.DecodeFromBytes(nexthopBytes) - message.PathAttributes[2] = nexthop - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - assert.Equal(nexthopBytes, e.Data) -} - -func Test_Validate_invalid_nexthop_lo(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - - // invalid nexthop - addr := net.ParseIP("127.0.0.1").To4() - nexthopBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP]), 3, 4} - nexthopBytes = append(nexthopBytes, addr...) - nexthop := &PathAttributeNextHop{} - nexthop.DecodeFromBytes(nexthopBytes) - message.PathAttributes[2] = nexthop - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - assert.Equal(nexthopBytes, e.Data) -} - -func Test_Validate_invalid_nexthop_de(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - - // invalid nexthop - addr := net.ParseIP("224.0.0.1").To4() - nexthopBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP]), 3, 4} - nexthopBytes = append(nexthopBytes, addr...) - nexthop := &PathAttributeNextHop{} - nexthop.DecodeFromBytes(nexthopBytes) - message.PathAttributes[2] = nexthop - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - assert.Equal(nexthopBytes, e.Data) - -} - -func Test_Validate_unrecognized_well_known(t *testing.T) { - - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - f := BGP_ATTR_FLAG_TRANSITIVE - unknownBytes := []byte{byte(f), 30, 1, 1} - unknown := &PathAttributeUnknown{} - unknown.DecodeFromBytes(unknownBytes) - message.PathAttributes = append(message.PathAttributes, unknown) - - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_SESSION_RESET, e.ErrorHandling) - assert.Equal(unknownBytes, e.Data) -} - -func Test_Validate_aspath(t *testing.T) { - assert := assert.New(t) - message := bgpupdate().Body.(*BGPUpdate) - - // VALID AS_PATH - res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, false) - require.NoError(t, err) - assert.Equal(true, res) - - // CONFED_SET - newAttrs := make([]PathAttributeInterface, 0) - attrs := message.PathAttributes - for _, attr := range attrs { - if _, y := attr.(*PathAttributeAsPath); y { - aspath := []AsPathParamInterface{ - NewAsPathParam(BGP_ASPATH_ATTR_TYPE_CONFED_SET, []uint16{65001}), - } - newAttrs = append(newAttrs, NewPathAttributeAsPath(aspath)) - } else { - newAttrs = append(newAttrs, attr) - } - } - - message.PathAttributes = newAttrs - res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, false) - assert.Equal(false, res) - assert.Error(err) - e := err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - assert.Nil(e.Data) - - res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, true) - assert.Equal(false, res) - assert.Error(err) - e = err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH), e.SubTypeCode) - assert.Nil(e.Data) - - // CONFED_SEQ - newAttrs = make([]PathAttributeInterface, 0) - attrs = message.PathAttributes - for _, attr := range attrs { - if _, y := attr.(*PathAttributeAsPath); y { - aspath := []AsPathParamInterface{ - NewAsPathParam(BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint16{65001}), - } - newAttrs = append(newAttrs, NewPathAttributeAsPath(aspath)) - } else { - newAttrs = append(newAttrs, attr) - } - } - - message.PathAttributes = newAttrs - res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, false) - assert.Equal(false, res) - assert.Error(err) - e = err.(*MessageError) - assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode) - assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH), e.SubTypeCode) - assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling) - assert.Nil(e.Data) - - res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, true) - require.NoError(t, err) - assert.Equal(true, res) -} - -func Test_Validate_flowspec(t *testing.T) { - assert := assert.New(t) - cmp := make([]FlowSpecComponentInterface, 0) - cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, TCP) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1})) - item2 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 20) - item3 := NewFlowSpecComponentItem(DEC_NUM_OP_AND|DEC_NUM_OP_LT_EQ, 30) - item4 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, 10) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4})) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4})) - item5 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK) - item6 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND|BITMASK_FLAG_OP_NOT, TCP_FLAG_URGENT) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item5, item6})) - 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})) - isFragment := uint64(0x02) - item7 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_MATCH, isFragment) - cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item7})) - n1 := NewFlowSpecIPv4Unicast(cmp) - a := NewPathAttributeMpReachNLRI("", []AddrPrefixInterface{n1}) - m := map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_NONE} - _, err := ValidateAttribute(a, m, false, false) - assert.Nil(err) - - cmp = make([]FlowSpecComponentInterface, 0) - cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))) - n1 = NewFlowSpecIPv4Unicast(cmp) - a = NewPathAttributeMpReachNLRI("", []AddrPrefixInterface{n1}) - // Swaps components order to reproduce the rules order violation. - n1.Value[0], n1.Value[1] = n1.Value[1], n1.Value[0] - _, err = ValidateAttribute(a, m, false, false) - assert.NotNil(err) -} - -func TestValidateLargeCommunities(t *testing.T) { - assert := assert.New(t) - c1, err := ParseLargeCommunity("10:10:10") - assert.Nil(err) - c2, err := ParseLargeCommunity("10:10:10") - assert.Nil(err) - c3, err := ParseLargeCommunity("10:10:20") - assert.Nil(err) - a := NewPathAttributeLargeCommunities([]*LargeCommunity{c1, c2, c3}) - assert.True(len(a.Values) == 3) - _, err = ValidateAttribute(a, nil, false, false) - assert.Nil(err) - assert.True(len(a.Values) == 2) -} diff --git a/packet/bmp/bmp.go b/packet/bmp/bmp.go deleted file mode 100644 index eb2ce185..00000000 --- a/packet/bmp/bmp.go +++ /dev/null @@ -1,1071 +0,0 @@ -// Copyright (C) 2014,2015 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. - -package bmp - -import ( - "encoding/binary" - "fmt" - "github.com/osrg/gobgp/packet/bgp" - "math" - "net" -) - -type BMPHeader struct { - Version uint8 - Length uint32 - Type uint8 -} - -const ( - BMP_VERSION = 3 - BMP_HEADER_SIZE = 6 - BMP_PEER_HEADER_SIZE = 42 -) - -const ( - BMP_DEFAULT_PORT = 11019 -) - -const ( - BMP_PEER_TYPE_GLOBAL uint8 = iota - BMP_PEER_TYPE_L3VPN - BMP_PEER_TYPE_LOCAL - BMP_PEER_TYPE_LOCAL_RIB -) - -const ( - BMP_PEER_FLAG_IPV6 = 1 << 7 - BMP_PEER_FLAG_POST_POLICY = 1 << 6 - BMP_PEER_FLAG_TWO_AS = 1 << 5 - BMP_PEER_FLAG_FILTERED = 1 << 6 -) - -func (h *BMPHeader) DecodeFromBytes(data []byte) error { - h.Version = data[0] - if data[0] != BMP_VERSION { - return fmt.Errorf("error version") - } - h.Length = binary.BigEndian.Uint32(data[1:5]) - h.Type = data[5] - return nil -} - -func (h *BMPHeader) Serialize() ([]byte, error) { - buf := make([]byte, BMP_HEADER_SIZE) - buf[0] = h.Version - binary.BigEndian.PutUint32(buf[1:], h.Length) - buf[5] = h.Type - return buf, nil -} - -type BMPPeerHeader struct { - PeerType uint8 - Flags uint8 - PeerDistinguisher uint64 - PeerAddress net.IP - PeerAS uint32 - PeerBGPID net.IP - Timestamp float64 -} - -func NewBMPPeerHeader(t uint8, flags uint8, dist uint64, address string, as uint32, id string, stamp float64) *BMPPeerHeader { - h := &BMPPeerHeader{ - PeerType: t, - Flags: flags, - PeerDistinguisher: dist, - PeerAS: as, - PeerBGPID: net.ParseIP(id).To4(), - Timestamp: stamp, - } - if net.ParseIP(address).To4() != nil { - h.PeerAddress = net.ParseIP(address).To4() - } else { - h.PeerAddress = net.ParseIP(address).To16() - h.Flags |= BMP_PEER_FLAG_IPV6 - } - return h -} - -func (h *BMPPeerHeader) IsPostPolicy() bool { - if h.Flags&BMP_PEER_FLAG_POST_POLICY != 0 { - return true - } else { - return false - } -} - -func (h *BMPPeerHeader) DecodeFromBytes(data []byte) error { - h.PeerType = data[0] - h.Flags = data[1] - h.PeerDistinguisher = binary.BigEndian.Uint64(data[2:10]) - if h.Flags&BMP_PEER_FLAG_IPV6 != 0 { - h.PeerAddress = net.IP(data[10:26]).To16() - } else { - h.PeerAddress = net.IP(data[22:26]).To4() - } - h.PeerAS = binary.BigEndian.Uint32(data[26:30]) - h.PeerBGPID = data[30:34] - - timestamp1 := binary.BigEndian.Uint32(data[34:38]) - timestamp2 := binary.BigEndian.Uint32(data[38:42]) - h.Timestamp = float64(timestamp1) + float64(timestamp2)*math.Pow10(-6) - return nil -} - -func (h *BMPPeerHeader) Serialize() ([]byte, error) { - buf := make([]byte, BMP_PEER_HEADER_SIZE) - buf[0] = h.PeerType - buf[1] = h.Flags - binary.BigEndian.PutUint64(buf[2:10], h.PeerDistinguisher) - if h.Flags&BMP_PEER_FLAG_IPV6 != 0 { - copy(buf[10:26], h.PeerAddress) - } else { - copy(buf[22:26], h.PeerAddress.To4()) - } - binary.BigEndian.PutUint32(buf[26:30], h.PeerAS) - copy(buf[30:34], h.PeerBGPID) - t1, t2 := math.Modf(h.Timestamp) - t2 = math.Ceil(t2 * math.Pow10(6)) - binary.BigEndian.PutUint32(buf[34:38], uint32(t1)) - binary.BigEndian.PutUint32(buf[38:42], uint32(t2)) - return buf, nil -} - -type BMPRouteMonitoring struct { - BGPUpdate *bgp.BGPMessage - BGPUpdatePayload []byte -} - -func NewBMPRouteMonitoring(p BMPPeerHeader, update *bgp.BGPMessage) *BMPMessage { - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_ROUTE_MONITORING, - }, - PeerHeader: p, - Body: &BMPRouteMonitoring{ - BGPUpdate: update, - }, - } -} - -func (body *BMPRouteMonitoring) ParseBody(msg *BMPMessage, data []byte) error { - update, err := bgp.ParseBGPMessage(data) - if err != nil { - return err - } - body.BGPUpdate = update - return nil -} - -func (body *BMPRouteMonitoring) Serialize() ([]byte, error) { - if body.BGPUpdatePayload != nil { - return body.BGPUpdatePayload, nil - } - return body.BGPUpdate.Serialize() -} - -const ( - BMP_STAT_TYPE_REJECTED = iota - BMP_STAT_TYPE_DUPLICATE_PREFIX - BMP_STAT_TYPE_DUPLICATE_WITHDRAW - BMP_STAT_TYPE_INV_UPDATE_DUE_TO_CLUSTER_LIST_LOOP - BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_PATH_LOOP - BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID - BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP - BMP_STAT_TYPE_ADJ_RIB_IN - BMP_STAT_TYPE_LOC_RIB - BMP_STAT_TYPE_PER_AFI_SAFI_ADJ_RIB_IN - BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB - BMP_STAT_TYPE_WITHDRAW_UPDATE - BMP_STAT_TYPE_WITHDRAW_PREFIX - BMP_STAT_TYPE_DUPLICATE_UPDATE -) - -type BMPStatsTLVInterface interface { - ParseValue([]byte) error - Serialize() ([]byte, error) -} - -type BMPStatsTLV struct { - Type uint16 - Length uint16 -} - -type BMPStatsTLV32 struct { - BMPStatsTLV - Value uint32 -} - -func NewBMPStatsTLV32(t uint16, v uint32) *BMPStatsTLV32 { - return &BMPStatsTLV32{ - BMPStatsTLV: BMPStatsTLV{ - Type: t, - Length: 4, - }, - Value: v, - } -} - -func (s *BMPStatsTLV32) ParseValue(data []byte) error { - if s.Length != 4 { - return fmt.Errorf("invalid length: %d bytes (%d bytes expected)", s.Length, 4) - } - s.Value = binary.BigEndian.Uint32(data[:8]) - return nil -} - -func (s *BMPStatsTLV32) Serialize() ([]byte, error) { - buf := make([]byte, 8) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], 4) - binary.BigEndian.PutUint32(buf[4:8], s.Value) - return buf, nil -} - -type BMPStatsTLV64 struct { - BMPStatsTLV - Value uint64 -} - -func NewBMPStatsTLV64(t uint16, v uint64) *BMPStatsTLV64 { - return &BMPStatsTLV64{ - BMPStatsTLV: BMPStatsTLV{ - Type: t, - Length: 8, - }, - Value: v, - } -} - -func (s *BMPStatsTLV64) ParseValue(data []byte) error { - if s.Length != 8 { - return fmt.Errorf("invalid length: %d bytes (%d bytes expected)", s.Length, 8) - } - s.Value = binary.BigEndian.Uint64(data[:8]) - return nil -} - -func (s *BMPStatsTLV64) Serialize() ([]byte, error) { - buf := make([]byte, 12) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], 8) - binary.BigEndian.PutUint64(buf[4:12], s.Value) - return buf, nil -} - -type BMPStatsTLVPerAfiSafi64 struct { - BMPStatsTLV - AFI uint16 - SAFI uint8 - Value uint64 -} - -func NewBMPStatsTLVPerAfiSafi64(t uint16, afi uint16, safi uint8, v uint64) *BMPStatsTLVPerAfiSafi64 { - return &BMPStatsTLVPerAfiSafi64{ - BMPStatsTLV: BMPStatsTLV{ - Type: t, - Length: 11, - }, - AFI: afi, - SAFI: safi, - Value: v, - } -} - -func (s *BMPStatsTLVPerAfiSafi64) ParseValue(data []byte) error { - if s.Length != 11 { - return fmt.Errorf("invalid length: %d bytes (%d bytes expected)", s.Length, 11) - } - s.AFI = binary.BigEndian.Uint16(data[0:2]) - s.SAFI = data[2] - s.Value = binary.BigEndian.Uint64(data[3:11]) - return nil -} - -func (s *BMPStatsTLVPerAfiSafi64) Serialize() ([]byte, error) { - buf := make([]byte, 15) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], 11) - binary.BigEndian.PutUint16(buf[4:6], s.AFI) - buf[6] = s.SAFI - binary.BigEndian.PutUint64(buf[7:15], s.Value) - return buf, nil -} - -type BMPStatisticsReport struct { - Count uint32 - Stats []BMPStatsTLVInterface -} - -func NewBMPStatisticsReport(p BMPPeerHeader, stats []BMPStatsTLVInterface) *BMPMessage { - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_STATISTICS_REPORT, - }, - PeerHeader: p, - Body: &BMPStatisticsReport{ - Count: uint32(len(stats)), - Stats: stats, - }, - } -} - -func (body *BMPStatisticsReport) ParseBody(msg *BMPMessage, data []byte) error { - body.Count = binary.BigEndian.Uint32(data[0:4]) - data = data[4:] - for len(data) >= 4 { - tl := BMPStatsTLV{ - Type: binary.BigEndian.Uint16(data[0:2]), - Length: binary.BigEndian.Uint16(data[2:4]), - } - data = data[4:] - if len(data) < int(tl.Length) { - return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length) - } - var s BMPStatsTLVInterface - switch tl.Type { - case BMP_STAT_TYPE_ADJ_RIB_IN, BMP_STAT_TYPE_LOC_RIB: - s = &BMPStatsTLV64{BMPStatsTLV: tl} - case BMP_STAT_TYPE_PER_AFI_SAFI_ADJ_RIB_IN, BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB: - s = &BMPStatsTLVPerAfiSafi64{BMPStatsTLV: tl} - default: - s = &BMPStatsTLV32{BMPStatsTLV: tl} - } - if err := s.ParseValue(data); err != nil { - return err - } - body.Stats = append(body.Stats, s) - data = data[tl.Length:] - } - return nil -} - -func (body *BMPStatisticsReport) Serialize() ([]byte, error) { - buf := make([]byte, 4) - body.Count = uint32(len(body.Stats)) - binary.BigEndian.PutUint32(buf[0:4], body.Count) - for _, tlv := range body.Stats { - tlvBuf, err := tlv.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, tlvBuf...) - } - return buf, nil -} - -const ( - BMP_PEER_DOWN_REASON_UNKNOWN = iota - BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION - BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION - BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION - BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION - BMP_PEER_DOWN_REASON_PEER_DE_CONFIGURED -) - -type BMPPeerDownNotification struct { - Reason uint8 - BGPNotification *bgp.BGPMessage - Data []byte -} - -func NewBMPPeerDownNotification(p BMPPeerHeader, reason uint8, notification *bgp.BGPMessage, data []byte) *BMPMessage { - b := &BMPPeerDownNotification{ - Reason: reason, - } - switch reason { - case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION: - b.BGPNotification = notification - case BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION: - b.Data = data - default: - } - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_PEER_DOWN_NOTIFICATION, - }, - PeerHeader: p, - Body: b, - } -} - -func (body *BMPPeerDownNotification) ParseBody(msg *BMPMessage, data []byte) error { - body.Reason = data[0] - data = data[1:] - if body.Reason == BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION || body.Reason == BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION { - notification, err := bgp.ParseBGPMessage(data) - if err != nil { - return err - } - body.BGPNotification = notification - } else { - body.Data = data - } - return nil -} - -func (body *BMPPeerDownNotification) Serialize() ([]byte, error) { - buf := make([]byte, 1) - buf[0] = body.Reason - switch body.Reason { - case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION: - if body.BGPNotification != nil { - b, err := body.BGPNotification.Serialize() - if err != nil { - return nil, err - } else { - buf = append(buf, b...) - } - } - default: - if body.Data != nil { - buf = append(buf, body.Data...) - } - } - return buf, nil -} - -type BMPPeerUpNotification struct { - LocalAddress net.IP - LocalPort uint16 - RemotePort uint16 - SentOpenMsg *bgp.BGPMessage - ReceivedOpenMsg *bgp.BGPMessage -} - -func NewBMPPeerUpNotification(p BMPPeerHeader, lAddr string, lPort, rPort uint16, sent, recv *bgp.BGPMessage) *BMPMessage { - b := &BMPPeerUpNotification{ - LocalPort: lPort, - RemotePort: rPort, - SentOpenMsg: sent, - ReceivedOpenMsg: recv, - } - addr := net.ParseIP(lAddr) - if addr.To4() != nil { - b.LocalAddress = addr.To4() - } else { - b.LocalAddress = addr.To16() - } - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_PEER_UP_NOTIFICATION, - }, - PeerHeader: p, - Body: b, - } -} - -func (body *BMPPeerUpNotification) ParseBody(msg *BMPMessage, data []byte) error { - if msg.PeerHeader.Flags&BMP_PEER_FLAG_IPV6 != 0 { - body.LocalAddress = net.IP(data[:16]).To16() - } else { - body.LocalAddress = net.IP(data[12:16]).To4() - } - - body.LocalPort = binary.BigEndian.Uint16(data[16:18]) - body.RemotePort = binary.BigEndian.Uint16(data[18:20]) - - data = data[20:] - sentopen, err := bgp.ParseBGPMessage(data) - if err != nil { - return err - } - body.SentOpenMsg = sentopen - data = data[body.SentOpenMsg.Header.Len:] - body.ReceivedOpenMsg, err = bgp.ParseBGPMessage(data) - if err != nil { - return err - } - return nil -} - -func (body *BMPPeerUpNotification) Serialize() ([]byte, error) { - buf := make([]byte, 20) - if body.LocalAddress.To4() != nil { - copy(buf[12:16], body.LocalAddress.To4()) - } else { - copy(buf[:16], body.LocalAddress.To16()) - } - - binary.BigEndian.PutUint16(buf[16:18], body.LocalPort) - binary.BigEndian.PutUint16(buf[18:20], body.RemotePort) - - m, _ := body.SentOpenMsg.Serialize() - buf = append(buf, m...) - m, _ = body.ReceivedOpenMsg.Serialize() - buf = append(buf, m...) - return buf, nil -} - -const ( - BMP_INIT_TLV_TYPE_STRING = iota - BMP_INIT_TLV_TYPE_SYS_DESCR - BMP_INIT_TLV_TYPE_SYS_NAME -) - -type BMPInfoTLVInterface interface { - ParseValue([]byte) error - Serialize() ([]byte, error) -} - -type BMPInfoTLV struct { - Type uint16 - Length uint16 -} - -type BMPInfoTLVString struct { - BMPInfoTLV - Value string -} - -func NewBMPInfoTLVString(t uint16, v string) *BMPInfoTLVString { - return &BMPInfoTLVString{ - BMPInfoTLV: BMPInfoTLV{Type: t}, - Value: v, - } -} - -func (s *BMPInfoTLVString) ParseValue(data []byte) error { - s.Value = string(data[:s.Length]) - return nil -} - -func (s *BMPInfoTLVString) Serialize() ([]byte, error) { - s.Length = uint16(len([]byte(s.Value))) - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - buf = append(buf, []byte(s.Value)...) - return buf, nil -} - -type BMPInfoTLVUnknown struct { - BMPInfoTLV - Value []byte -} - -func NewBMPInfoTLVUnknown(t uint16, v []byte) *BMPInfoTLVUnknown { - return &BMPInfoTLVUnknown{ - BMPInfoTLV: BMPInfoTLV{Type: t}, - Value: v, - } -} - -func (s *BMPInfoTLVUnknown) ParseValue(data []byte) error { - s.Value = data[:s.Length] - return nil -} - -func (s *BMPInfoTLVUnknown) Serialize() ([]byte, error) { - s.Length = uint16(len([]byte(s.Value))) - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - buf = append(buf, s.Value...) - return buf, nil -} - -type BMPInitiation struct { - Info []BMPInfoTLVInterface -} - -func NewBMPInitiation(info []BMPInfoTLVInterface) *BMPMessage { - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_INITIATION, - }, - Body: &BMPInitiation{ - Info: info, - }, - } -} - -func (body *BMPInitiation) ParseBody(msg *BMPMessage, data []byte) error { - for len(data) >= 4 { - tl := BMPInfoTLV{ - Type: binary.BigEndian.Uint16(data[0:2]), - Length: binary.BigEndian.Uint16(data[2:4]), - } - data = data[4:] - if len(data) < int(tl.Length) { - return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length) - } - var tlv BMPInfoTLVInterface - switch tl.Type { - case BMP_INIT_TLV_TYPE_STRING, BMP_INIT_TLV_TYPE_SYS_DESCR, BMP_INIT_TLV_TYPE_SYS_NAME: - tlv = &BMPInfoTLVString{BMPInfoTLV: tl} - default: - tlv = &BMPInfoTLVUnknown{BMPInfoTLV: tl} - } - if err := tlv.ParseValue(data); err != nil { - return err - } - body.Info = append(body.Info, tlv) - data = data[tl.Length:] - } - return nil -} - -func (body *BMPInitiation) Serialize() ([]byte, error) { - buf := make([]byte, 0) - for _, tlv := range body.Info { - b, err := tlv.Serialize() - if err != nil { - return buf, err - } - buf = append(buf, b...) - } - return buf, nil -} - -const ( - BMP_TERM_TLV_TYPE_STRING = iota - BMP_TERM_TLV_TYPE_REASON -) - -const ( - BMP_TERM_REASON_ADMIN = iota - BMP_TERM_REASON_UNSPEC - BMP_TERM_REASON_OUT_OF_RESOURCES - BMP_TERM_REASON_REDUNDANT_CONNECTION - BMP_TERM_REASON_PERMANENTLY_ADMIN -) - -type BMPTermTLVInterface interface { - ParseValue([]byte) error - Serialize() ([]byte, error) -} - -type BMPTermTLV struct { - Type uint16 - Length uint16 -} - -type BMPTermTLVString struct { - BMPTermTLV - Value string -} - -func NewBMPTermTLVString(t uint16, v string) *BMPTermTLVString { - return &BMPTermTLVString{ - BMPTermTLV: BMPTermTLV{Type: t}, - Value: v, - } -} - -func (s *BMPTermTLVString) ParseValue(data []byte) error { - s.Value = string(data[:s.Length]) - return nil -} - -func (s *BMPTermTLVString) Serialize() ([]byte, error) { - s.Length = uint16(len([]byte(s.Value))) - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - buf = append(buf, []byte(s.Value)...) - return buf, nil -} - -type BMPTermTLV16 struct { - BMPTermTLV - Value uint16 -} - -func NewBMPTermTLV16(t uint16, v uint16) *BMPTermTLV16 { - return &BMPTermTLV16{ - BMPTermTLV: BMPTermTLV{Type: t}, - Value: v, - } -} - -func (s *BMPTermTLV16) ParseValue(data []byte) error { - s.Value = binary.BigEndian.Uint16(data[:2]) - return nil -} - -func (s *BMPTermTLV16) Serialize() ([]byte, error) { - s.Length = 2 - buf := make([]byte, 6) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - binary.BigEndian.PutUint16(buf[4:6], s.Value) - return buf, nil -} - -type BMPTermTLVUnknown struct { - BMPTermTLV - Value []byte -} - -func NewBMPTermTLVUnknown(t uint16, v []byte) *BMPTermTLVUnknown { - return &BMPTermTLVUnknown{ - BMPTermTLV: BMPTermTLV{Type: t}, - Value: v, - } -} - -func (s *BMPTermTLVUnknown) ParseValue(data []byte) error { - s.Value = data[:s.Length] - return nil -} - -func (s *BMPTermTLVUnknown) Serialize() ([]byte, error) { - s.Length = uint16(len([]byte(s.Value))) - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - buf = append(buf, s.Value...) - return buf, nil -} - -type BMPTermination struct { - Info []BMPTermTLVInterface -} - -func NewBMPTermination(info []BMPTermTLVInterface) *BMPMessage { - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_TERMINATION, - }, - Body: &BMPTermination{ - Info: info, - }, - } -} - -func (body *BMPTermination) ParseBody(msg *BMPMessage, data []byte) error { - for len(data) >= 4 { - tl := BMPTermTLV{ - Type: binary.BigEndian.Uint16(data[0:2]), - Length: binary.BigEndian.Uint16(data[2:4]), - } - data = data[4:] - if len(data) < int(tl.Length) { - return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length) - } - var tlv BMPTermTLVInterface - switch tl.Type { - case BMP_TERM_TLV_TYPE_STRING: - tlv = &BMPTermTLVString{BMPTermTLV: tl} - case BMP_TERM_TLV_TYPE_REASON: - tlv = &BMPTermTLV16{BMPTermTLV: tl} - default: - tlv = &BMPTermTLVUnknown{BMPTermTLV: tl} - } - if err := tlv.ParseValue(data); err != nil { - return err - } - body.Info = append(body.Info, tlv) - data = data[tl.Length:] - } - return nil -} - -func (body *BMPTermination) Serialize() ([]byte, error) { - buf := make([]byte, 0) - for _, tlv := range body.Info { - b, err := tlv.Serialize() - if err != nil { - return buf, err - } - buf = append(buf, b...) - } - return buf, nil -} - -const ( - BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG = iota - BMP_ROUTE_MIRRORING_TLV_TYPE_INFO -) - -const ( - BMP_ROUTE_MIRRORING_INFO_ERR_PDU = iota - BMP_ROUTE_MIRRORING_INFO_MSG_LOST -) - -type BMPRouteMirrTLVInterface interface { - ParseValue([]byte) error - Serialize() ([]byte, error) -} - -type BMPRouteMirrTLV struct { - Type uint16 - Length uint16 -} - -type BMPRouteMirrTLVBGPMsg struct { - BMPRouteMirrTLV - Value *bgp.BGPMessage -} - -func NewBMPRouteMirrTLVBGPMsg(t uint16, v *bgp.BGPMessage) *BMPRouteMirrTLVBGPMsg { - return &BMPRouteMirrTLVBGPMsg{ - BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t}, - Value: v, - } -} - -func (s *BMPRouteMirrTLVBGPMsg) ParseValue(data []byte) error { - v, err := bgp.ParseBGPMessage(data) - if err != nil { - return err - } - s.Value = v - return nil -} - -func (s *BMPRouteMirrTLVBGPMsg) Serialize() ([]byte, error) { - m, err := s.Value.Serialize() - if err != nil { - return nil, err - } - s.Length = uint16(len(m)) - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - buf = append(buf, m...) - return buf, nil -} - -type BMPRouteMirrTLV16 struct { - BMPRouteMirrTLV - Value uint16 -} - -func NewBMPRouteMirrTLV16(t uint16, v uint16) *BMPRouteMirrTLV16 { - return &BMPRouteMirrTLV16{ - BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t}, - Value: v, - } -} - -func (s *BMPRouteMirrTLV16) ParseValue(data []byte) error { - s.Value = binary.BigEndian.Uint16(data[:2]) - return nil -} - -func (s *BMPRouteMirrTLV16) Serialize() ([]byte, error) { - s.Length = 2 - buf := make([]byte, 6) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - binary.BigEndian.PutUint16(buf[4:6], s.Value) - return buf, nil -} - -type BMPRouteMirrTLVUnknown struct { - BMPRouteMirrTLV - Value []byte -} - -func NewBMPRouteMirrTLVUnknown(t uint16, v []byte) *BMPRouteMirrTLVUnknown { - return &BMPRouteMirrTLVUnknown{ - BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t}, - Value: v, - } -} - -func (s *BMPRouteMirrTLVUnknown) ParseValue(data []byte) error { - s.Value = data[:s.Length] - return nil -} - -func (s *BMPRouteMirrTLVUnknown) Serialize() ([]byte, error) { - s.Length = uint16(len([]byte(s.Value))) - buf := make([]byte, 4) - binary.BigEndian.PutUint16(buf[0:2], s.Type) - binary.BigEndian.PutUint16(buf[2:4], s.Length) - buf = append(buf, s.Value...) - return buf, nil -} - -type BMPRouteMirroring struct { - Info []BMPRouteMirrTLVInterface -} - -func NewBMPRouteMirroring(p BMPPeerHeader, info []BMPRouteMirrTLVInterface) *BMPMessage { - return &BMPMessage{ - Header: BMPHeader{ - Version: BMP_VERSION, - Type: BMP_MSG_ROUTE_MIRRORING, - }, - PeerHeader: p, - Body: &BMPRouteMirroring{ - Info: info, - }, - } -} - -func (body *BMPRouteMirroring) ParseBody(msg *BMPMessage, data []byte) error { - for len(data) >= 4 { - tl := BMPRouteMirrTLV{ - Type: binary.BigEndian.Uint16(data[0:2]), - Length: binary.BigEndian.Uint16(data[2:4]), - } - data = data[4:] - if len(data) < int(tl.Length) { - return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length) - } - var tlv BMPRouteMirrTLVInterface - switch tl.Type { - case BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG: - tlv = &BMPRouteMirrTLVBGPMsg{BMPRouteMirrTLV: tl} - case BMP_ROUTE_MIRRORING_TLV_TYPE_INFO: - tlv = &BMPRouteMirrTLV16{BMPRouteMirrTLV: tl} - default: - tlv = &BMPRouteMirrTLVUnknown{BMPRouteMirrTLV: tl} - } - if err := tlv.ParseValue(data); err != nil { - return err - } - body.Info = append(body.Info, tlv) - data = data[tl.Length:] - } - return nil -} - -func (body *BMPRouteMirroring) Serialize() ([]byte, error) { - buf := make([]byte, 0) - for _, tlv := range body.Info { - b, err := tlv.Serialize() - if err != nil { - return buf, err - } - buf = append(buf, b...) - } - return buf, nil -} - -type BMPBody interface { - // Sigh, some body messages need a BMPHeader to parse the body - // data so we need to pass BMPHeader (avoid DecodeFromBytes - // function name). - ParseBody(*BMPMessage, []byte) error - Serialize() ([]byte, error) -} - -type BMPMessage struct { - Header BMPHeader - PeerHeader BMPPeerHeader - Body BMPBody -} - -func (msg *BMPMessage) Serialize() ([]byte, error) { - buf := make([]byte, 0) - if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION { - p, err := msg.PeerHeader.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, p...) - } - - b, err := msg.Body.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, b...) - - if msg.Header.Length == 0 { - msg.Header.Length = uint32(BMP_HEADER_SIZE + len(buf)) - } - - h, err := msg.Header.Serialize() - if err != nil { - return nil, err - } - return append(h, buf...), nil -} - -func (msg *BMPMessage) Len() int { - return int(msg.Header.Length) -} - -const ( - BMP_MSG_ROUTE_MONITORING = iota - BMP_MSG_STATISTICS_REPORT - BMP_MSG_PEER_DOWN_NOTIFICATION - BMP_MSG_PEER_UP_NOTIFICATION - BMP_MSG_INITIATION - BMP_MSG_TERMINATION - BMP_MSG_ROUTE_MIRRORING -) - -func ParseBMPMessage(data []byte) (msg *BMPMessage, err error) { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("not all data bytes are available") - } - }() - - msg = &BMPMessage{} - err = msg.Header.DecodeFromBytes(data) - if err != nil { - return nil, err - } - data = data[BMP_HEADER_SIZE:msg.Header.Length] - - switch msg.Header.Type { - case BMP_MSG_ROUTE_MONITORING: - msg.Body = &BMPRouteMonitoring{} - case BMP_MSG_STATISTICS_REPORT: - msg.Body = &BMPStatisticsReport{} - case BMP_MSG_PEER_DOWN_NOTIFICATION: - msg.Body = &BMPPeerDownNotification{} - case BMP_MSG_PEER_UP_NOTIFICATION: - msg.Body = &BMPPeerUpNotification{} - case BMP_MSG_INITIATION: - msg.Body = &BMPInitiation{} - case BMP_MSG_TERMINATION: - msg.Body = &BMPTermination{} - case BMP_MSG_ROUTE_MIRRORING: - msg.Body = &BMPRouteMirroring{} - default: - return nil, fmt.Errorf("unsupported BMP message type: %d", msg.Header.Type) - } - - if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION { - msg.PeerHeader.DecodeFromBytes(data) - data = data[BMP_PEER_HEADER_SIZE:] - } - - err = msg.Body.ParseBody(msg, data) - if err != nil { - return nil, err - } - return msg, nil -} - -func SplitBMP(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 || len(data) < BMP_HEADER_SIZE { - return 0, nil, nil - } - - msg := &BMPMessage{} - msg.Header.DecodeFromBytes(data) - if uint32(len(data)) < msg.Header.Length { - return 0, nil, nil - } - - return int(msg.Header.Length), data[0:msg.Header.Length], nil -} diff --git a/packet/bmp/bmp_test.go b/packet/bmp/bmp_test.go deleted file mode 100644 index fde4cd0f..00000000 --- a/packet/bmp/bmp_test.go +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (C) 2015 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. - -package bmp - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/osrg/gobgp/packet/bgp" - - "github.com/stretchr/testify/assert" -) - -func verify(t *testing.T, m1 *BMPMessage) { - buf1, _ := m1.Serialize() - m2, err := ParseBMPMessage(buf1) - require.NoError(t, err) - - assert.Equal(t, m1, m2) -} - -func Test_Initiation(t *testing.T) { - verify(t, NewBMPInitiation(nil)) - m := NewBMPInitiation([]BMPInfoTLVInterface{ - NewBMPInfoTLVString(BMP_INIT_TLV_TYPE_STRING, "free-form UTF-8 string"), - NewBMPInfoTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}), - }) - verify(t, m) -} - -func Test_Termination(t *testing.T) { - verify(t, NewBMPTermination(nil)) - m := NewBMPTermination([]BMPTermTLVInterface{ - NewBMPTermTLVString(BMP_TERM_TLV_TYPE_STRING, "free-form UTF-8 string"), - NewBMPTermTLV16(BMP_TERM_TLV_TYPE_REASON, BMP_TERM_REASON_ADMIN), - NewBMPTermTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}), - }) - verify(t, m) -} - -func Test_PeerUpNotification(t *testing.T) { - m := bgp.NewTestBGPOpenMessage() - p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1) - verify(t, NewBMPPeerUpNotification(*p0, "10.0.0.3", 10, 100, m, m)) - p1 := NewBMPPeerHeader(0, 0, 1000, "fe80::6e40:8ff:feab:2c2a", 70000, "10.0.0.2", 1) - verify(t, NewBMPPeerUpNotification(*p1, "fe80::6e40:8ff:feab:2c2a", 10, 100, m, m)) -} - -func Test_PeerDownNotification(t *testing.T) { - p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1) - verify(t, NewBMPPeerDownNotification(*p0, BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION, nil, []byte{0x3, 0xb})) - m := bgp.NewBGPNotificationMessage(1, 2, nil) - verify(t, NewBMPPeerDownNotification(*p0, BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION, m, nil)) -} - -func Test_RouteMonitoring(t *testing.T) { - m := bgp.NewTestBGPUpdateMessage() - p0 := NewBMPPeerHeader(0, 0, 1000, "fe80::6e40:8ff:feab:2c2a", 70000, "10.0.0.2", 1) - verify(t, NewBMPRouteMonitoring(*p0, m)) -} - -func Test_StatisticsReport(t *testing.T) { - p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1) - s0 := NewBMPStatisticsReport( - *p0, - []BMPStatsTLVInterface{ - NewBMPStatsTLV32(BMP_STAT_TYPE_REJECTED, 100), - NewBMPStatsTLV64(BMP_STAT_TYPE_ADJ_RIB_IN, 200), - NewBMPStatsTLVPerAfiSafi64(BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB, bgp.AFI_IP, bgp.SAFI_UNICAST, 300), - }, - ) - verify(t, s0) -} - -func Test_RouteMirroring(t *testing.T) { - p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1) - s0 := NewBMPRouteMirroring( - *p0, - []BMPRouteMirrTLVInterface{ - NewBMPRouteMirrTLV16(BMP_ROUTE_MIRRORING_TLV_TYPE_INFO, BMP_ROUTE_MIRRORING_INFO_MSG_LOST), - NewBMPRouteMirrTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}), - // RFC7854: BGP Message TLV MUST occur last in the list of TLVs - NewBMPRouteMirrTLVBGPMsg(BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG, bgp.NewTestBGPOpenMessage()), - }, - ) - verify(t, s0) -} - -func Test_BogusHeader(t *testing.T) { - h, err := ParseBMPMessage(make([]byte, 10)) - assert.Nil(t, h) - assert.NotNil(t, err) -} diff --git a/packet/mrt/mrt.go b/packet/mrt/mrt.go deleted file mode 100644 index 9c6fef6d..00000000 --- a/packet/mrt/mrt.go +++ /dev/null @@ -1,1006 +0,0 @@ -// Copyright (C) 2015 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. - -package mrt - -import ( - "bytes" - "encoding/binary" - "fmt" - "math" - "net" - "time" - - "github.com/osrg/gobgp/packet/bgp" -) - -const ( - MRT_COMMON_HEADER_LEN = 12 -) - -type MRTType uint16 - -const ( - NULL MRTType = 0 // deprecated - START MRTType = 1 // deprecated - DIE MRTType = 2 // deprecated - I_AM_DEAD MRTType = 3 // deprecated - PEER_DOWN MRTType = 4 // deprecated - BGP MRTType = 5 // deprecated - RIP MRTType = 6 // deprecated - IDRP MRTType = 7 // deprecated - RIPNG MRTType = 8 // deprecated - BGP4PLUS MRTType = 9 // deprecated - BGP4PLUS01 MRTType = 10 // deprecated - OSPFv2 MRTType = 11 - TABLE_DUMP MRTType = 12 - TABLE_DUMPv2 MRTType = 13 - BGP4MP MRTType = 16 - BGP4MP_ET MRTType = 17 - ISIS MRTType = 32 - ISIS_ET MRTType = 33 - OSPFv3 MRTType = 48 - OSPFv3_ET MRTType = 49 -) - -type MRTSubTyper interface { - ToUint16() uint16 -} - -type MRTSubTypeTableDumpv2 uint16 - -const ( - PEER_INDEX_TABLE MRTSubTypeTableDumpv2 = 1 - RIB_IPV4_UNICAST MRTSubTypeTableDumpv2 = 2 - RIB_IPV4_MULTICAST MRTSubTypeTableDumpv2 = 3 - RIB_IPV6_UNICAST MRTSubTypeTableDumpv2 = 4 - RIB_IPV6_MULTICAST MRTSubTypeTableDumpv2 = 5 - RIB_GENERIC MRTSubTypeTableDumpv2 = 6 - GEO_PEER_TABLE MRTSubTypeTableDumpv2 = 7 // RFC6397 - RIB_IPV4_UNICAST_ADDPATH MRTSubTypeTableDumpv2 = 8 // RFC8050 - RIB_IPV4_MULTICAST_ADDPATH MRTSubTypeTableDumpv2 = 9 // RFC8050 - RIB_IPV6_UNICAST_ADDPATH MRTSubTypeTableDumpv2 = 10 // RFC8050 - RIB_IPV6_MULTICAST_ADDPATH MRTSubTypeTableDumpv2 = 11 // RFC8050 - RIB_GENERIC_ADDPATH MRTSubTypeTableDumpv2 = 12 // RFC8050 -) - -func (t MRTSubTypeTableDumpv2) ToUint16() uint16 { - return uint16(t) -} - -type MRTSubTypeBGP4MP uint16 - -const ( - STATE_CHANGE MRTSubTypeBGP4MP = 0 - MESSAGE MRTSubTypeBGP4MP = 1 - MESSAGE_AS4 MRTSubTypeBGP4MP = 4 - STATE_CHANGE_AS4 MRTSubTypeBGP4MP = 5 - MESSAGE_LOCAL MRTSubTypeBGP4MP = 6 - MESSAGE_AS4_LOCAL MRTSubTypeBGP4MP = 7 - MESSAGE_ADDPATH MRTSubTypeBGP4MP = 8 // RFC8050 - MESSAGE_AS4_ADDPATH MRTSubTypeBGP4MP = 9 // RFC8050 - MESSAGE_LOCAL_ADDPATH MRTSubTypeBGP4MP = 10 // RFC8050 - MESSAGE_AS4_LOCAL_ADDPATH MRTSubTypeBGP4MP = 11 // RFC8050 -) - -func (t MRTSubTypeBGP4MP) ToUint16() uint16 { - return uint16(t) -} - -type BGPState uint16 - -const ( - IDLE BGPState = 1 - CONNECT BGPState = 2 - ACTIVE BGPState = 3 - OPENSENT BGPState = 4 - OPENCONFIRM BGPState = 5 - ESTABLISHED BGPState = 6 -) - -func packValues(values []interface{}) ([]byte, error) { - b := new(bytes.Buffer) - for _, v := range values { - err := binary.Write(b, binary.BigEndian, v) - if err != nil { - return nil, err - } - } - return b.Bytes(), nil -} - -type MRTHeader struct { - Timestamp uint32 - Type MRTType - SubType uint16 - Len uint32 -} - -func (h *MRTHeader) DecodeFromBytes(data []byte) error { - if len(data) < MRT_COMMON_HEADER_LEN { - return fmt.Errorf("not all MRTHeader bytes are available. expected: %d, actual: %d", MRT_COMMON_HEADER_LEN, len(data)) - } - h.Timestamp = binary.BigEndian.Uint32(data[:4]) - h.Type = MRTType(binary.BigEndian.Uint16(data[4:6])) - h.SubType = binary.BigEndian.Uint16(data[6:8]) - h.Len = binary.BigEndian.Uint32(data[8:12]) - return nil -} - -func (h *MRTHeader) Serialize() ([]byte, error) { - return packValues([]interface{}{h.Timestamp, h.Type, h.SubType, h.Len}) -} - -func NewMRTHeader(timestamp uint32, t MRTType, subtype MRTSubTyper, l uint32) (*MRTHeader, error) { - return &MRTHeader{ - Timestamp: timestamp, - Type: t, - SubType: subtype.ToUint16(), - Len: l, - }, nil -} - -func (h *MRTHeader) GetTime() time.Time { - t := int64(h.Timestamp) - return time.Unix(t, 0) -} - -type MRTMessage struct { - Header MRTHeader - Body Body -} - -func (m *MRTMessage) Serialize() ([]byte, error) { - buf, err := m.Body.Serialize() - if err != nil { - return nil, err - } - m.Header.Len = uint32(len(buf)) - bbuf, err := m.Header.Serialize() - if err != nil { - return nil, err - } - return append(bbuf, buf...), nil -} - -func NewMRTMessage(timestamp uint32, t MRTType, subtype MRTSubTyper, body Body) (*MRTMessage, error) { - header, err := NewMRTHeader(timestamp, t, subtype, 0) - if err != nil { - return nil, err - } - return &MRTMessage{ - Header: *header, - Body: body, - }, nil -} - -type Body interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) -} - -type Peer struct { - Type uint8 - BgpId net.IP - IpAddress net.IP - AS uint32 -} - -func (p *Peer) DecodeFromBytes(data []byte) ([]byte, error) { - notAllBytesAvail := fmt.Errorf("not all Peer bytes are available") - if len(data) < 5 { - return nil, notAllBytesAvail - } - p.Type = uint8(data[0]) - p.BgpId = net.IP(data[1:5]) - data = data[5:] - - if p.Type&1 > 0 { - if len(data) < 16 { - return nil, notAllBytesAvail - } - p.IpAddress = net.IP(data[:16]) - data = data[16:] - } else { - if len(data) < 4 { - return nil, notAllBytesAvail - } - p.IpAddress = net.IP(data[:4]) - data = data[4:] - } - - if p.Type&(1<<1) > 0 { - if len(data) < 4 { - return nil, notAllBytesAvail - } - p.AS = binary.BigEndian.Uint32(data[:4]) - data = data[4:] - } else { - if len(data) < 2 { - return nil, notAllBytesAvail - } - p.AS = uint32(binary.BigEndian.Uint16(data[:2])) - data = data[2:] - } - - return data, nil -} - -func (p *Peer) Serialize() ([]byte, error) { - var err error - var bbuf []byte - buf := make([]byte, 5) - buf[0] = uint8(p.Type) - copy(buf[1:], p.BgpId.To4()) - if p.Type&1 > 0 { - buf = append(buf, p.IpAddress.To16()...) - } else { - buf = append(buf, p.IpAddress.To4()...) - } - if p.Type&(1<<1) > 0 { - bbuf, err = packValues([]interface{}{p.AS}) - } else { - if p.AS > uint32(math.MaxUint16) { - return nil, fmt.Errorf("AS number is beyond 2 octet. %d > %d", p.AS, math.MaxUint16) - } - bbuf, err = packValues([]interface{}{uint16(p.AS)}) - } - if err != nil { - return nil, err - } - return append(buf, bbuf...), nil -} - -func NewPeer(bgpid string, ipaddr string, asn uint32, isAS4 bool) *Peer { - t := 0 - addr := net.ParseIP(ipaddr).To4() - if addr == nil { - t |= 1 - addr = net.ParseIP(ipaddr).To16() - } - if isAS4 { - t |= (1 << 1) - } - return &Peer{ - Type: uint8(t), - BgpId: net.ParseIP(bgpid).To4(), - IpAddress: addr, - AS: asn, - } -} - -func (p *Peer) String() string { - return fmt.Sprintf("PEER ENTRY: ID [%s] Addr [%s] AS [%d]", p.BgpId, p.IpAddress, p.AS) -} - -type PeerIndexTable struct { - CollectorBgpId net.IP - ViewName string - Peers []*Peer -} - -func (t *PeerIndexTable) DecodeFromBytes(data []byte) error { - notAllBytesAvail := fmt.Errorf("not all PeerIndexTable bytes are available") - if len(data) < 6 { - return notAllBytesAvail - } - t.CollectorBgpId = net.IP(data[:4]) - viewLen := binary.BigEndian.Uint16(data[4:6]) - if len(data) < 6+int(viewLen) { - return notAllBytesAvail - } - t.ViewName = string(data[6 : 6+viewLen]) - - data = data[6+viewLen:] - - if len(data) < 2 { - return notAllBytesAvail - } - peerNum := binary.BigEndian.Uint16(data[:2]) - data = data[2:] - t.Peers = make([]*Peer, 0, peerNum) - var err error - for i := 0; i < int(peerNum); i++ { - p := &Peer{} - data, err = p.DecodeFromBytes(data) - if err != nil { - return err - } - t.Peers = append(t.Peers, p) - } - - return nil -} - -func (t *PeerIndexTable) Serialize() ([]byte, error) { - buf := make([]byte, 8+len(t.ViewName)) - copy(buf, t.CollectorBgpId.To4()) - binary.BigEndian.PutUint16(buf[4:], uint16(len(t.ViewName))) - copy(buf[6:], t.ViewName) - binary.BigEndian.PutUint16(buf[6+len(t.ViewName):], uint16(len(t.Peers))) - for _, peer := range t.Peers { - bbuf, err := peer.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return buf, nil -} - -func NewPeerIndexTable(bgpid string, viewname string, peers []*Peer) *PeerIndexTable { - return &PeerIndexTable{ - CollectorBgpId: net.ParseIP(bgpid).To4(), - ViewName: viewname, - Peers: peers, - } -} - -func (t *PeerIndexTable) String() string { - return fmt.Sprintf("PEER_INDEX_TABLE: CollectorBgpId [%s] ViewName [%s] Peers [%s]", t.CollectorBgpId, t.ViewName, t.Peers) -} - -type RibEntry struct { - PeerIndex uint16 - OriginatedTime uint32 - PathIdentifier uint32 - PathAttributes []bgp.PathAttributeInterface - isAddPath bool -} - -func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) { - notAllBytesAvail := fmt.Errorf("not all RibEntry bytes are available") - if len(data) < 8 { - return nil, notAllBytesAvail - } - e.PeerIndex = binary.BigEndian.Uint16(data[:2]) - e.OriginatedTime = binary.BigEndian.Uint32(data[2:6]) - if e.isAddPath { - e.PathIdentifier = binary.BigEndian.Uint32(data[6:10]) - data = data[10:] - } else { - data = data[6:] - } - totalLen := binary.BigEndian.Uint16(data[:2]) - data = data[2:] - for attrLen := totalLen; attrLen > 0; { - p, err := bgp.GetPathAttribute(data) - if err != nil { - return nil, err - } - err = p.DecodeFromBytes(data) - if err != nil { - return nil, err - } - attrLen -= uint16(p.Len()) - if len(data) < p.Len() { - return nil, notAllBytesAvail - } - data = data[p.Len():] - e.PathAttributes = append(e.PathAttributes, p) - } - return data, nil -} - -func (e *RibEntry) Serialize() ([]byte, error) { - pbuf := make([]byte, 0) - totalLen := 0 - for _, pattr := range e.PathAttributes { - // TODO special modification is needed for MP_REACH_NLRI - // but also Quagga doesn't implement this. - // - // RFC 6396 4.3.4 - // There is one exception to the encoding of BGP attributes for the BGP - // MP_REACH_NLRI attribute (BGP Type Code 14). - // Since the AFI, SAFI, and NLRI information is already encoded - // in the RIB Entry Header or RIB_GENERIC Entry Header, - // only the Next Hop Address Length and Next Hop Address fields are included. - - pb, err := pattr.Serialize() - if err != nil { - return nil, err - } - pbuf = append(pbuf, pb...) - totalLen += len(pb) - } - var buf []byte - if e.isAddPath { - buf = make([]byte, 12) - binary.BigEndian.PutUint16(buf, e.PeerIndex) - binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime) - binary.BigEndian.PutUint32(buf[6:], e.PathIdentifier) - binary.BigEndian.PutUint16(buf[10:], uint16(totalLen)) - } else { - buf = make([]byte, 8) - binary.BigEndian.PutUint16(buf, e.PeerIndex) - binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime) - binary.BigEndian.PutUint16(buf[6:], uint16(totalLen)) - } - buf = append(buf, pbuf...) - return buf, nil -} - -func NewRibEntry(index uint16, time uint32, pathId uint32, pathAttrs []bgp.PathAttributeInterface, isAddPath bool) *RibEntry { - return &RibEntry{ - PeerIndex: index, - OriginatedTime: time, - PathIdentifier: pathId, - PathAttributes: pathAttrs, - isAddPath: isAddPath, - } -} - -func (e *RibEntry) String() string { - if e.isAddPath { - return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathIdentifier[%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathIdentifier, e.PathAttributes) - } else { - return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathAttributes) - } - -} - -type Rib struct { - SequenceNumber uint32 - Prefix bgp.AddrPrefixInterface - Entries []*RibEntry - RouteFamily bgp.RouteFamily - isAddPath bool -} - -func (u *Rib) DecodeFromBytes(data []byte) error { - if len(data) < 4 { - return fmt.Errorf("Not all RibIpv4Unicast message bytes available") - } - u.SequenceNumber = binary.BigEndian.Uint32(data[:4]) - data = data[4:] - afi, safi := bgp.RouteFamilyToAfiSafi(u.RouteFamily) - if afi == 0 && safi == 0 { - afi = binary.BigEndian.Uint16(data[:2]) - safi = data[2] - data = data[3:] - } - prefix, err := bgp.NewPrefixFromRouteFamily(afi, safi) - if err != nil { - return err - } - err = prefix.DecodeFromBytes(data) - if err != nil { - return err - } - u.Prefix = prefix - data = data[prefix.Len():] - entryNum := binary.BigEndian.Uint16(data[:2]) - data = data[2:] - u.Entries = make([]*RibEntry, 0, entryNum) - for i := 0; i < int(entryNum); i++ { - e := &RibEntry{ - isAddPath: u.isAddPath, - } - data, err = e.DecodeFromBytes(data) - if err != nil { - return err - } - u.Entries = append(u.Entries, e) - } - return nil -} - -func (u *Rib) Serialize() ([]byte, error) { - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, u.SequenceNumber) - rf := bgp.AfiSafiToRouteFamily(u.Prefix.AFI(), u.Prefix.SAFI()) - switch rf { - case bgp.RF_IPv4_UC, bgp.RF_IPv4_MC, bgp.RF_IPv6_UC, bgp.RF_IPv6_MC: - default: - bbuf := make([]byte, 2) - binary.BigEndian.PutUint16(bbuf, u.Prefix.AFI()) - buf = append(buf, bbuf...) - buf = append(buf, u.Prefix.SAFI()) - } - bbuf, err := u.Prefix.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - bbuf, err = packValues([]interface{}{uint16(len(u.Entries))}) - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - for _, entry := range u.Entries { - bbuf, err = entry.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, bbuf...) - } - return buf, nil -} - -func NewRib(seq uint32, prefix bgp.AddrPrefixInterface, entries []*RibEntry) *Rib { - rf := bgp.AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI()) - return &Rib{ - SequenceNumber: seq, - Prefix: prefix, - Entries: entries, - RouteFamily: rf, - isAddPath: entries[0].isAddPath, - } -} - -func (u *Rib) String() string { - return fmt.Sprintf("RIB: Seq [%d] Prefix [%s] Entries [%s]", u.SequenceNumber, u.Prefix, u.Entries) -} - -type GeoPeer struct { - Type uint8 - BgpId net.IP - Latitude float32 - Longitude float32 -} - -func (p *GeoPeer) DecodeFromBytes(data []byte) ([]byte, error) { - if len(data) < 13 { - return nil, fmt.Errorf("not all GeoPeer bytes are available") - } - // Peer IP Address and Peer AS should not be included - p.Type = uint8(data[0]) - if p.Type != uint8(0) { - return nil, fmt.Errorf("unsupported peer type for GeoPeer: %d", p.Type) - } - p.BgpId = net.IP(data[1:5]) - p.Latitude = math.Float32frombits(binary.BigEndian.Uint32(data[5:9])) - p.Longitude = math.Float32frombits(binary.BigEndian.Uint32(data[9:13])) - return data[13:], nil -} - -func (p *GeoPeer) Serialize() ([]byte, error) { - buf := make([]byte, 13) - buf[0] = uint8(0) // Peer IP Address and Peer AS should not be included - bgpId := p.BgpId.To4() - if bgpId == nil { - return nil, fmt.Errorf("invalid BgpId: %s", p.BgpId) - } - copy(buf[1:5], bgpId) - binary.BigEndian.PutUint32(buf[5:9], math.Float32bits(p.Latitude)) - binary.BigEndian.PutUint32(buf[9:13], math.Float32bits(p.Longitude)) - return buf, nil -} - -func NewGeoPeer(bgpid string, latitude float32, longitude float32) *GeoPeer { - return &GeoPeer{ - Type: 0, // Peer IP Address and Peer AS should not be included - BgpId: net.ParseIP(bgpid).To4(), - Latitude: latitude, - Longitude: longitude, - } -} - -func (p *GeoPeer) String() string { - return fmt.Sprintf("PEER ENTRY: ID [%s] Latitude [%f] Longitude [%f]", p.BgpId, p.Latitude, p.Longitude) -} - -type GeoPeerTable struct { - CollectorBgpId net.IP - CollectorLatitude float32 - CollectorLongitude float32 - Peers []*GeoPeer -} - -func (t *GeoPeerTable) DecodeFromBytes(data []byte) error { - if len(data) < 14 { - return fmt.Errorf("not all GeoPeerTable bytes are available") - } - t.CollectorBgpId = net.IP(data[0:4]) - t.CollectorLatitude = math.Float32frombits(binary.BigEndian.Uint32(data[4:8])) - t.CollectorLongitude = math.Float32frombits(binary.BigEndian.Uint32(data[8:12])) - peerCount := binary.BigEndian.Uint16(data[12:14]) - data = data[14:] - t.Peers = make([]*GeoPeer, 0, peerCount) - var err error - for i := 0; i < int(peerCount); i++ { - p := &GeoPeer{} - if data, err = p.DecodeFromBytes(data); err != nil { - return err - } - t.Peers = append(t.Peers, p) - } - return nil -} - -func (t *GeoPeerTable) Serialize() ([]byte, error) { - buf := make([]byte, 14) - collectorBgpId := t.CollectorBgpId.To4() - if collectorBgpId == nil { - return nil, fmt.Errorf("invalid CollectorBgpId: %s", t.CollectorBgpId) - } - copy(buf[0:4], collectorBgpId) - binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(t.CollectorLatitude)) - binary.BigEndian.PutUint32(buf[8:12], math.Float32bits(t.CollectorLongitude)) - binary.BigEndian.PutUint16(buf[12:14], uint16(len(t.Peers))) - for _, peer := range t.Peers { - pbuf, err := peer.Serialize() - if err != nil { - return nil, err - } - buf = append(buf, pbuf...) - } - return buf, nil -} - -func NewGeoPeerTable(bgpid string, latitude float32, longitude float32, peers []*GeoPeer) *GeoPeerTable { - return &GeoPeerTable{ - CollectorBgpId: net.ParseIP(bgpid).To4(), - CollectorLatitude: latitude, - CollectorLongitude: longitude, - Peers: peers, - } -} - -func (t *GeoPeerTable) String() string { - return fmt.Sprintf("GEO_PEER_TABLE: CollectorBgpId [%s] CollectorLatitude [%f] CollectorLongitude [%f] Peers [%s]", t.CollectorBgpId, t.CollectorLatitude, t.CollectorLongitude, t.Peers) -} - -type BGP4MPHeader struct { - PeerAS uint32 - LocalAS uint32 - InterfaceIndex uint16 - AddressFamily uint16 - PeerIpAddress net.IP - LocalIpAddress net.IP - isAS4 bool -} - -func (m *BGP4MPHeader) decodeFromBytes(data []byte) ([]byte, error) { - if m.isAS4 && len(data) < 8 { - return nil, fmt.Errorf("Not all BGP4MPMessageAS4 bytes available") - } else if !m.isAS4 && len(data) < 4 { - return nil, fmt.Errorf("Not all BGP4MPMessageAS bytes available") - } - - if m.isAS4 { - m.PeerAS = binary.BigEndian.Uint32(data[:4]) - m.LocalAS = binary.BigEndian.Uint32(data[4:8]) - data = data[8:] - } else { - m.PeerAS = uint32(binary.BigEndian.Uint16(data[:2])) - m.LocalAS = uint32(binary.BigEndian.Uint16(data[2:4])) - data = data[4:] - } - m.InterfaceIndex = binary.BigEndian.Uint16(data[:2]) - m.AddressFamily = binary.BigEndian.Uint16(data[2:4]) - switch m.AddressFamily { - case bgp.AFI_IP: - m.PeerIpAddress = net.IP(data[4:8]).To4() - m.LocalIpAddress = net.IP(data[8:12]).To4() - data = data[12:] - case bgp.AFI_IP6: - m.PeerIpAddress = net.IP(data[4:20]) - m.LocalIpAddress = net.IP(data[20:36]) - data = data[36:] - default: - return nil, fmt.Errorf("unsupported address family: %d", m.AddressFamily) - } - return data, nil -} - -func (m *BGP4MPHeader) serialize() ([]byte, error) { - var values []interface{} - if m.isAS4 { - values = []interface{}{m.PeerAS, m.LocalAS, m.InterfaceIndex, m.AddressFamily} - } else { - values = []interface{}{uint16(m.PeerAS), uint16(m.LocalAS), m.InterfaceIndex, m.AddressFamily} - } - buf, err := packValues(values) - if err != nil { - return nil, err - } - var bbuf []byte - switch m.AddressFamily { - case bgp.AFI_IP: - bbuf = make([]byte, 8) - copy(bbuf, m.PeerIpAddress.To4()) - copy(bbuf[4:], m.LocalIpAddress.To4()) - case bgp.AFI_IP6: - bbuf = make([]byte, 32) - copy(bbuf, m.PeerIpAddress) - copy(bbuf[16:], m.LocalIpAddress) - default: - return nil, fmt.Errorf("unsupported address family: %d", m.AddressFamily) - } - return append(buf, bbuf...), nil -} - -func newBGP4MPHeader(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool) (*BGP4MPHeader, error) { - var af uint16 - paddr := net.ParseIP(peerip).To4() - laddr := net.ParseIP(localip).To4() - if paddr != nil && laddr != nil { - af = bgp.AFI_IP - } else { - paddr = net.ParseIP(peerip).To16() - laddr = net.ParseIP(localip).To16() - if paddr != nil && laddr != nil { - af = bgp.AFI_IP6 - } else { - return nil, fmt.Errorf("Peer IP Address and Local IP Address must have the same address family") - } - } - return &BGP4MPHeader{ - PeerAS: peeras, - LocalAS: localas, - InterfaceIndex: intfindex, - AddressFamily: af, - PeerIpAddress: paddr, - LocalIpAddress: laddr, - isAS4: isAS4, - }, nil -} - -type BGP4MPStateChange struct { - *BGP4MPHeader - OldState BGPState - NewState BGPState -} - -func (m *BGP4MPStateChange) DecodeFromBytes(data []byte) error { - rest, err := m.decodeFromBytes(data) - if err != nil { - return err - } - if len(rest) < 4 { - return fmt.Errorf("Not all BGP4MPStateChange bytes available") - } - m.OldState = BGPState(binary.BigEndian.Uint16(rest[:2])) - m.NewState = BGPState(binary.BigEndian.Uint16(rest[2:4])) - return nil -} - -func (m *BGP4MPStateChange) Serialize() ([]byte, error) { - buf, err := m.serialize() - if err != nil { - return nil, err - } - bbuf, err := packValues([]interface{}{m.OldState, m.NewState}) - if err != nil { - return nil, err - } - return append(buf, bbuf...), nil -} - -func NewBGP4MPStateChange(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, oldstate, newstate BGPState) *BGP4MPStateChange { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPStateChange{ - BGP4MPHeader: header, - OldState: oldstate, - NewState: newstate, - } -} - -type BGP4MPMessage struct { - *BGP4MPHeader - BGPMessage *bgp.BGPMessage - BGPMessagePayload []byte - isLocal bool - isAddPath bool -} - -func (m *BGP4MPMessage) DecodeFromBytes(data []byte) error { - rest, err := m.decodeFromBytes(data) - if err != nil { - return err - } - - if len(rest) < bgp.BGP_HEADER_LENGTH { - return fmt.Errorf("Not all BGP4MPMessageAS4 bytes available") - } - - msg, err := bgp.ParseBGPMessage(rest) - if err != nil { - return err - } - m.BGPMessage = msg - return nil -} - -func (m *BGP4MPMessage) Serialize() ([]byte, error) { - buf, err := m.serialize() - if err != nil { - return nil, err - } - if m.BGPMessagePayload != nil { - return append(buf, m.BGPMessagePayload...), nil - } - bbuf, err := m.BGPMessage.Serialize() - if err != nil { - return nil, err - } - return append(buf, bbuf...), nil -} - -func NewBGP4MPMessage(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - } -} - -func NewBGP4MPMessageLocal(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - isLocal: true, - } -} - -func NewBGP4MPMessageAddPath(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - isAddPath: true, - } -} - -func NewBGP4MPMessageLocalAddPath(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage { - header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4) - return &BGP4MPMessage{ - BGP4MPHeader: header, - BGPMessage: msg, - isLocal: true, - isAddPath: true, - } -} - -func (m *BGP4MPMessage) String() string { - title := "BGP4MP_MSG" - if m.isAS4 { - title += "_AS4" - } - if m.isLocal { - title += "_LOCAL" - } - if m.isAddPath { - title += "_ADDPATH" - } - return fmt.Sprintf("%s: PeerAS [%d] LocalAS [%d] InterfaceIndex [%d] PeerIP [%s] LocalIP [%s] BGPMessage [%v]", title, m.PeerAS, m.LocalAS, m.InterfaceIndex, m.PeerIpAddress, m.LocalIpAddress, m.BGPMessage) -} - -//This function can be passed into a bufio.Scanner.Split() to read buffered mrt msgs -func SplitMrt(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 { - return 0, nil, nil - } - if cap(data) < MRT_COMMON_HEADER_LEN { // read more - return 0, nil, nil - } - //this reads the data - hdr := &MRTHeader{} - errh := hdr.DecodeFromBytes(data[:MRT_COMMON_HEADER_LEN]) - if errh != nil { - return 0, nil, errh - } - totlen := int(hdr.Len + MRT_COMMON_HEADER_LEN) - if len(data) < totlen { //need to read more - return 0, nil, nil - } - return totlen, data[0:totlen], nil -} - -func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) { - if len(data) < int(h.Len) { - return nil, fmt.Errorf("Not all MRT message bytes available. expected: %d, actual: %d", int(h.Len), len(data)) - } - msg := &MRTMessage{Header: *h} - switch h.Type { - case TABLE_DUMPv2: - subType := MRTSubTypeTableDumpv2(h.SubType) - rf := bgp.RouteFamily(0) - isAddPath := false - switch subType { - case PEER_INDEX_TABLE: - msg.Body = &PeerIndexTable{} - case RIB_IPV4_UNICAST: - rf = bgp.RF_IPv4_UC - case RIB_IPV4_MULTICAST: - rf = bgp.RF_IPv4_MC - case RIB_IPV6_UNICAST: - rf = bgp.RF_IPv6_UC - case RIB_IPV6_MULTICAST: - rf = bgp.RF_IPv6_MC - case RIB_GENERIC: - case GEO_PEER_TABLE: - msg.Body = &GeoPeerTable{} - case RIB_IPV4_UNICAST_ADDPATH: - rf = bgp.RF_IPv4_UC - isAddPath = true - case RIB_IPV4_MULTICAST_ADDPATH: - rf = bgp.RF_IPv4_MC - isAddPath = true - case RIB_IPV6_UNICAST_ADDPATH: - rf = bgp.RF_IPv6_UC - isAddPath = true - case RIB_IPV6_MULTICAST_ADDPATH: - rf = bgp.RF_IPv6_MC - isAddPath = true - case RIB_GENERIC_ADDPATH: - isAddPath = true - default: - return nil, fmt.Errorf("unsupported table dumpv2 subtype: %v\n", subType) - } - - if msg.Body == nil { - msg.Body = &Rib{ - RouteFamily: rf, - isAddPath: isAddPath, - } - } - case BGP4MP: - subType := MRTSubTypeBGP4MP(h.SubType) - isAS4 := true - switch subType { - case STATE_CHANGE: - isAS4 = false - fallthrough - case STATE_CHANGE_AS4: - msg.Body = &BGP4MPStateChange{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - } - case MESSAGE: - isAS4 = false - fallthrough - case MESSAGE_AS4: - msg.Body = &BGP4MPMessage{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - } - case MESSAGE_LOCAL: - isAS4 = false - fallthrough - case MESSAGE_AS4_LOCAL: - msg.Body = &BGP4MPMessage{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - isLocal: true, - } - case MESSAGE_ADDPATH: - isAS4 = false - fallthrough - case MESSAGE_AS4_ADDPATH: - msg.Body = &BGP4MPMessage{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - isAddPath: true, - } - case MESSAGE_LOCAL_ADDPATH: - isAS4 = false - fallthrough - case MESSAGE_AS4_LOCAL_ADDPATH: - msg.Body = &BGP4MPMessage{ - BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4}, - isLocal: true, - isAddPath: true, - } - default: - return nil, fmt.Errorf("unsupported bgp4mp subtype: %v\n", subType) - } - default: - return nil, fmt.Errorf("unsupported type: %v\n", h.Type) - } - err := msg.Body.DecodeFromBytes(data) - if err != nil { - return nil, err - } - return msg, nil -} diff --git a/packet/mrt/mrt_test.go b/packet/mrt/mrt_test.go deleted file mode 100644 index 30edd496..00000000 --- a/packet/mrt/mrt_test.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (C) 2015 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. - -package mrt - -import ( - "bufio" - "bytes" - "github.com/osrg/gobgp/packet/bgp" - "github.com/stretchr/testify/assert" - "reflect" - "testing" - "time" -) - -func TestMrtHdr(t *testing.T) { - h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20) - if err != nil { - t.Fatal(err) - } - b1, err := h1.Serialize() - if err != nil { - t.Fatal(err) - } - h2 := &MRTHeader{} - err = h2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(h1, h2), true) -} - -func TestMrtHdrTime(t *testing.T) { - h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20) - if err != nil { - t.Fatal(err) - } - ttime := time.Unix(10, 0) - htime := h1.GetTime() - t.Logf("this timestamp should be 10s after epoch:%v", htime) - assert.Equal(t, h1.GetTime(), ttime) -} - -func testPeer(t *testing.T, p1 *Peer) { - b1, err := p1.Serialize() - if err != nil { - t.Fatal(err) - } - p2 := &Peer{} - rest, err := p2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, len(rest), 0) - assert.Equal(t, reflect.DeepEqual(p1, p2), true) -} - -func TestMrtPeer(t *testing.T) { - p := NewPeer("192.168.0.1", "10.0.0.1", 65000, false) - testPeer(t, p) -} - -func TestMrtPeerv6(t *testing.T) { - p := NewPeer("192.168.0.1", "2001::1", 65000, false) - testPeer(t, p) -} - -func TestMrtPeerAS4(t *testing.T) { - p := NewPeer("192.168.0.1", "2001::1", 135500, true) - testPeer(t, p) -} - -func TestMrtPeerIndexTable(t *testing.T) { - p1 := NewPeer("192.168.0.1", "10.0.0.1", 65000, false) - p2 := NewPeer("192.168.0.1", "2001::1", 65000, false) - p3 := NewPeer("192.168.0.1", "2001::1", 135500, true) - pt1 := NewPeerIndexTable("192.168.0.1", "test", []*Peer{p1, p2, p3}) - b1, err := pt1.Serialize() - if err != nil { - t.Fatal(err) - } - pt2 := &PeerIndexTable{} - err = pt2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(pt1, pt2), true) -} - -func TestMrtRibEntry(t *testing.T) { - aspath1 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false) - b1, err := e1.Serialize() - if err != nil { - t.Fatal(err) - } - - e2 := &RibEntry{} - rest, err := e2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, len(rest), 0) - assert.Equal(t, reflect.DeepEqual(e1, e2), true) -} - -func TestMrtRibEntryWithAddPath(t *testing.T) { - aspath1 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 200, p, true) - b1, err := e1.Serialize() - if err != nil { - t.Fatal(err) - } - - e2 := &RibEntry{isAddPath: true} - rest, err := e2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, len(rest), 0) - assert.Equal(t, reflect.DeepEqual(e1, e2), true) -} - -func TestMrtRib(t *testing.T) { - aspath1 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false) - e2 := NewRibEntry(2, uint32(time.Now().Unix()), 0, p, false) - e3 := NewRibEntry(3, uint32(time.Now().Unix()), 0, p, false) - - r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3}) - b1, err := r1.Serialize() - if err != nil { - t.Fatal(err) - } - r2 := &Rib{ - RouteFamily: bgp.RF_IPv4_UC, - } - err = r2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(r1, r2), true) -} - -func TestMrtRibWithAddPath(t *testing.T) { - aspath1 := []bgp.AsPathParamInterface{ - bgp.NewAsPathParam(2, []uint16{1000}), - bgp.NewAsPathParam(1, []uint16{1001, 1002}), - bgp.NewAsPathParam(2, []uint16{1003, 1004}), - } - - p := []bgp.PathAttributeInterface{ - bgp.NewPathAttributeOrigin(3), - bgp.NewPathAttributeAsPath(aspath1), - bgp.NewPathAttributeNextHop("129.1.1.2"), - bgp.NewPathAttributeMultiExitDisc(1 << 20), - bgp.NewPathAttributeLocalPref(1 << 22), - } - - e1 := NewRibEntry(1, uint32(time.Now().Unix()), 100, p, true) - e2 := NewRibEntry(2, uint32(time.Now().Unix()), 200, p, true) - e3 := NewRibEntry(3, uint32(time.Now().Unix()), 300, p, true) - - r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3}) - b1, err := r1.Serialize() - if err != nil { - t.Fatal(err) - } - r2 := &Rib{ - RouteFamily: bgp.RF_IPv4_UC, - isAddPath: true, - } - err = r2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(r1, r2), true) -} - -func TestMrtGeoPeerTable(t *testing.T) { - p1 := NewGeoPeer("192.168.0.1", 28.031157, 86.899684) - p2 := NewGeoPeer("192.168.0.1", 35.360556, 138.727778) - pt1 := NewGeoPeerTable("192.168.0.1", 12.345678, 98.765432, []*GeoPeer{p1, p2}) - b1, err := pt1.Serialize() - if err != nil { - t.Fatal(err) - } - pt2 := &GeoPeerTable{} - err = pt2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(pt1, pt2), true) -} - -func TestMrtBgp4mpStateChange(t *testing.T) { - c1 := NewBGP4MPStateChange(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, ACTIVE, ESTABLISHED) - b1, err := c1.Serialize() - if err != nil { - t.Fatal(err) - } - c2 := &BGP4MPStateChange{BGP4MPHeader: &BGP4MPHeader{}} - err = c2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - _, err = c2.Serialize() - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(c1, c2), true) -} - -func TestMrtBgp4mpMessage(t *testing.T) { - msg := bgp.NewBGPKeepAliveMessage() - m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg) - b1, err := m1.Serialize() - if err != nil { - t.Fatal(err) - } - m2 := &BGP4MPMessage{BGP4MPHeader: &BGP4MPHeader{}} - err = m2.DecodeFromBytes(b1) - if err != nil { - t.Fatal(err) - } - assert.Equal(t, reflect.DeepEqual(m1, m2), true) -} - -func TestMrtSplit(t *testing.T) { - var b bytes.Buffer - numwrite, numread := 10, 0 - for i := 0; i < numwrite; i++ { - msg := bgp.NewBGPKeepAliveMessage() - m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg) - mm, _ := NewMRTMessage(1234, BGP4MP, MESSAGE, m1) - b1, err := mm.Serialize() - if err != nil { - t.Fatal(err) - } - b.Write(b1) - } - t.Logf("wrote %d serialized MRT keepalives in the buffer", numwrite) - r := bytes.NewReader(b.Bytes()) - scanner := bufio.NewScanner(r) - scanner.Split(SplitMrt) - for scanner.Scan() { - numread += 1 - } - t.Logf("scanner scanned %d serialized keepalives from the buffer", numread) - assert.Equal(t, numwrite, numread) -} diff --git a/packet/rtr/rtr.go b/packet/rtr/rtr.go deleted file mode 100644 index 902f1e62..00000000 --- a/packet/rtr/rtr.go +++ /dev/null @@ -1,392 +0,0 @@ -// Copyright (C) 2015 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. - -package rtr - -import ( - "encoding/binary" - "fmt" - "net" -) - -const ( - RPKI_DEFAULT_PORT = 323 -) - -const ( - RTR_SERIAL_NOTIFY = iota - RTR_SERIAL_QUERY - RTR_RESET_QUERY - RTR_CACHE_RESPONSE - RTR_IPV4_PREFIX - _ - RTR_IPV6_PREFIX - RTR_END_OF_DATA - RTR_CACHE_RESET - _ - RTR_ERROR_REPORT -) - -const ( - RTR_SERIAL_NOTIFY_LEN = 12 - RTR_SERIAL_QUERY_LEN = 12 - RTR_RESET_QUERY_LEN = 8 - RTR_CACHE_RESPONSE_LEN = 8 - RTR_IPV4_PREFIX_LEN = 20 - RTR_IPV6_PREFIX_LEN = 32 - RTR_END_OF_DATA_LEN = 12 - RTR_CACHE_RESET_LEN = 8 - RTR_MIN_LEN = 8 - RTR_ERROR_REPORT_ERR_PDU_LEN = 4 - RTR_ERROR_REPORT_ERR_TEXT_LEN = 4 -) - -const ( - WITHDRAWAL uint8 = iota - ANNOUNCEMENT -) - -const ( - CORRUPT_DATA uint16 = iota - INTERNAL_ERROR - NO_DATA_AVAILABLE - INVALID_REQUEST - UNSUPPORTED_PROTOCOL_VERSION - UNSUPPORTED_PDU_TYPE - WITHDRAWAL_OF_UNKNOWN_RECORD - DUPLICATE_ANNOUNCEMENT_RECORD -) - -type RTRMessage interface { - DecodeFromBytes([]byte) error - Serialize() ([]byte, error) -} - -type RTRCommon struct { - Version uint8 - Type uint8 - SessionID uint16 - Len uint32 - SerialNumber uint32 -} - -func (m *RTRCommon) DecodeFromBytes(data []byte) error { - m.Version = data[0] - m.Type = data[1] - m.SessionID = binary.BigEndian.Uint16(data[2:4]) - m.Len = binary.BigEndian.Uint32(data[4:8]) - m.SerialNumber = binary.BigEndian.Uint32(data[8:12]) - return nil -} - -func (m *RTRCommon) Serialize() ([]byte, error) { - data := make([]byte, m.Len) - data[0] = m.Version - data[1] = m.Type - binary.BigEndian.PutUint16(data[2:4], m.SessionID) - binary.BigEndian.PutUint32(data[4:8], m.Len) - binary.BigEndian.PutUint32(data[8:12], m.SerialNumber) - return data, nil -} - -type RTRSerialNotify struct { - RTRCommon -} - -func NewRTRSerialNotify(id uint16, sn uint32) *RTRSerialNotify { - return &RTRSerialNotify{ - RTRCommon{ - Type: RTR_SERIAL_NOTIFY, - SessionID: id, - Len: RTR_SERIAL_NOTIFY_LEN, - SerialNumber: sn, - }, - } -} - -type RTRSerialQuery struct { - RTRCommon -} - -func NewRTRSerialQuery(id uint16, sn uint32) *RTRSerialQuery { - return &RTRSerialQuery{ - RTRCommon{ - Type: RTR_SERIAL_QUERY, - SessionID: id, - Len: RTR_SERIAL_QUERY_LEN, - SerialNumber: sn, - }, - } -} - -type RTRReset struct { - Version uint8 - Type uint8 - Len uint32 -} - -func (m *RTRReset) DecodeFromBytes(data []byte) error { - m.Version = data[0] - m.Type = data[1] - m.Len = binary.BigEndian.Uint32(data[4:8]) - return nil -} - -func (m *RTRReset) Serialize() ([]byte, error) { - data := make([]byte, m.Len) - data[0] = m.Version - data[1] = m.Type - binary.BigEndian.PutUint32(data[4:8], m.Len) - return data, nil -} - -type RTRResetQuery struct { - RTRReset -} - -func NewRTRResetQuery() *RTRResetQuery { - return &RTRResetQuery{ - RTRReset{ - Type: RTR_RESET_QUERY, - Len: RTR_RESET_QUERY_LEN, - }, - } -} - -type RTRCacheResponse struct { - Version uint8 - Type uint8 - SessionID uint16 - Len uint32 -} - -func (m *RTRCacheResponse) DecodeFromBytes(data []byte) error { - m.Version = data[0] - m.Type = data[1] - m.SessionID = binary.BigEndian.Uint16(data[2:4]) - m.Len = binary.BigEndian.Uint32(data[4:8]) - return nil -} - -func (m *RTRCacheResponse) Serialize() ([]byte, error) { - data := make([]byte, m.Len) - data[0] = m.Version - data[1] = m.Type - binary.BigEndian.PutUint16(data[2:4], m.SessionID) - binary.BigEndian.PutUint32(data[4:8], m.Len) - return data, nil -} - -func NewRTRCacheResponse(id uint16) *RTRCacheResponse { - return &RTRCacheResponse{ - Type: RTR_CACHE_RESPONSE, - SessionID: id, - Len: RTR_CACHE_RESPONSE_LEN, - } -} - -type RTRIPPrefix struct { - Version uint8 - Type uint8 - Len uint32 - Flags uint8 - PrefixLen uint8 - MaxLen uint8 - Prefix net.IP - AS uint32 -} - -func (m *RTRIPPrefix) DecodeFromBytes(data []byte) error { - m.Version = data[0] - m.Type = data[1] - m.Len = binary.BigEndian.Uint32(data[4:8]) - m.Flags = data[8] - m.PrefixLen = data[9] - m.MaxLen = data[10] - if m.Type == RTR_IPV4_PREFIX { - m.Prefix = net.IP(data[12:16]).To4() - m.AS = binary.BigEndian.Uint32(data[16:20]) - } else { - m.Prefix = net.IP(data[12:28]).To16() - m.AS = binary.BigEndian.Uint32(data[28:32]) - } - return nil -} - -func (m *RTRIPPrefix) Serialize() ([]byte, error) { - data := make([]byte, m.Len) - data[0] = m.Version - data[1] = m.Type - binary.BigEndian.PutUint32(data[4:8], m.Len) - data[8] = m.Flags - data[9] = m.PrefixLen - data[10] = m.MaxLen - if m.Type == RTR_IPV4_PREFIX { - copy(data[12:16], m.Prefix.To4()) - binary.BigEndian.PutUint32(data[16:20], m.AS) - } else { - copy(data[12:28], m.Prefix.To16()) - binary.BigEndian.PutUint32(data[28:32], m.AS) - } - return data, nil -} - -func NewRTRIPPrefix(prefix net.IP, prefixLen, maxLen uint8, as uint32, flags uint8) *RTRIPPrefix { - var pduType uint8 - var pduLen uint32 - if prefix.To4() != nil && prefixLen <= 32 { - pduType = RTR_IPV4_PREFIX - pduLen = RTR_IPV4_PREFIX_LEN - } else { - pduType = RTR_IPV6_PREFIX - pduLen = RTR_IPV6_PREFIX_LEN - } - - return &RTRIPPrefix{ - Type: pduType, - Len: pduLen, - Flags: flags, - PrefixLen: prefixLen, - MaxLen: maxLen, - Prefix: prefix, - AS: as, - } -} - -type RTREndOfData struct { - RTRCommon -} - -func NewRTREndOfData(id uint16, sn uint32) *RTREndOfData { - return &RTREndOfData{ - RTRCommon{ - Type: RTR_END_OF_DATA, - SessionID: id, - Len: RTR_END_OF_DATA_LEN, - SerialNumber: sn, - }, - } -} - -type RTRCacheReset struct { - RTRReset -} - -func NewRTRCacheReset() *RTRCacheReset { - return &RTRCacheReset{ - RTRReset{ - Type: RTR_CACHE_RESET, - Len: RTR_CACHE_RESET_LEN, - }, - } -} - -type RTRErrorReport struct { - Version uint8 - Type uint8 - ErrorCode uint16 - Len uint32 - PDULen uint32 - PDU []byte - TextLen uint32 - Text []byte -} - -func (m *RTRErrorReport) DecodeFromBytes(data []byte) error { - m.Version = data[0] - m.Type = data[1] - m.ErrorCode = binary.BigEndian.Uint16(data[2:4]) - m.Len = binary.BigEndian.Uint32(data[4:8]) - m.PDULen = binary.BigEndian.Uint32(data[8:12]) - m.PDU = make([]byte, m.PDULen) - copy(m.PDU, data[12:12+m.PDULen]) - m.TextLen = binary.BigEndian.Uint32(data[12+m.PDULen : 16+m.PDULen]) - m.Text = make([]byte, m.TextLen) - copy(m.Text, data[16+m.PDULen:]) - return nil -} - -func (m *RTRErrorReport) Serialize() ([]byte, error) { - data := make([]byte, m.Len) - data[0] = m.Version - data[1] = m.Type - binary.BigEndian.PutUint16(data[2:4], m.ErrorCode) - binary.BigEndian.PutUint32(data[4:8], m.Len) - binary.BigEndian.PutUint32(data[8:12], m.PDULen) - copy(data[12:], m.PDU) - binary.BigEndian.PutUint32(data[12+m.PDULen:16+m.PDULen], m.TextLen) - copy(data[16+m.PDULen:], m.Text) - return data, nil -} - -func NewRTRErrorReport(errCode uint16, errPDU []byte, errMsg []byte) *RTRErrorReport { - pdu := &RTRErrorReport{Type: RTR_ERROR_REPORT, ErrorCode: errCode} - if errPDU != nil { - if errPDU[1] == RTR_ERROR_REPORT { - return nil - } - pdu.PDULen = uint32(len(errPDU)) - pdu.PDU = errPDU - } - if errMsg != nil { - pdu.Text = errMsg - pdu.TextLen = uint32(len(errMsg)) - } - pdu.Len = uint32(RTR_MIN_LEN) + uint32(RTR_ERROR_REPORT_ERR_PDU_LEN) + pdu.PDULen + uint32(RTR_ERROR_REPORT_ERR_TEXT_LEN) + pdu.TextLen - return pdu -} - -func SplitRTR(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 || len(data) < RTR_MIN_LEN { - return 0, nil, nil - } - - totalLen := binary.BigEndian.Uint32(data[4:8]) - if totalLen < RTR_MIN_LEN { - return 0, nil, fmt.Errorf("Invalid length: %d", totalLen) - } - if uint32(len(data)) < totalLen { - return 0, nil, nil - } - return int(totalLen), data[0:totalLen], nil -} - -func ParseRTR(data []byte) (RTRMessage, error) { - var msg RTRMessage - switch data[1] { - case RTR_SERIAL_NOTIFY: - msg = &RTRSerialNotify{} - case RTR_SERIAL_QUERY: - msg = &RTRSerialQuery{} - case RTR_RESET_QUERY: - msg = &RTRResetQuery{} - case RTR_CACHE_RESPONSE: - msg = &RTRCacheResponse{} - case RTR_IPV4_PREFIX: - msg = &RTRIPPrefix{} - case RTR_IPV6_PREFIX: - msg = &RTRIPPrefix{} - case RTR_END_OF_DATA: - msg = &RTREndOfData{} - case RTR_CACHE_RESET: - msg = &RTRCacheReset{} - case RTR_ERROR_REPORT: - msg = &RTRErrorReport{} - default: - return nil, fmt.Errorf("unknown RTR message type %d:", data[1]) - } - err := msg.DecodeFromBytes(data) - return msg, err -} diff --git a/packet/rtr/rtr_test.go b/packet/rtr/rtr_test.go deleted file mode 100644 index 08f930b2..00000000 --- a/packet/rtr/rtr_test.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright (C) 2015 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. - -package rtr - -import ( - "encoding/hex" - "math/rand" - "net" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func verifyRTRMessage(t *testing.T, m1 RTRMessage) { - buf1, _ := m1.Serialize() - m2, err := ParseRTR(buf1) - require.NoError(t, err) - - buf2, err := m2.Serialize() - require.NoError(t, err) - - assert.Equal(t, buf1, buf2, "buf1: %v buf2: %v", hex.EncodeToString(buf1), hex.EncodeToString(buf2)) -} - -func randUint32() uint32 { - rand.Seed(time.Now().UnixNano()) - return rand.Uint32() -} - -func Test_RTRSerialNotify(t *testing.T) { - id := uint16(time.Now().Unix()) - sn := randUint32() - verifyRTRMessage(t, NewRTRSerialNotify(id, sn)) -} - -func Test_RTRSerialQuery(t *testing.T) { - id := uint16(time.Now().Unix()) - sn := randUint32() - verifyRTRMessage(t, NewRTRSerialQuery(id, sn)) -} - -func Test_RTRResetQuery(t *testing.T) { - verifyRTRMessage(t, NewRTRResetQuery()) -} - -func Test_RTRCacheResponse(t *testing.T) { - id := uint16(time.Now().Unix()) - verifyRTRMessage(t, NewRTRCacheResponse(id)) -} - -type rtrIPPrefixTestCase struct { - pString string - pLen uint8 - mLen uint8 - asn uint32 - flags uint8 -} - -var rtrIPPrefixTestCases = []rtrIPPrefixTestCase{ - {"192.168.0.0", 16, 32, 65001, ANNOUNCEMENT}, - {"192.168.0.0", 16, 32, 65001, WITHDRAWAL}, - {"2001:db8::", 32, 128, 65001, ANNOUNCEMENT}, - {"2001:db8::", 32, 128, 65001, WITHDRAWAL}, - {"::ffff:0.0.0.0", 96, 128, 65001, ANNOUNCEMENT}, - {"::ffff:0.0.0.0", 96, 128, 65001, WITHDRAWAL}, -} - -func Test_RTRIPPrefix(t *testing.T) { - for i := range rtrIPPrefixTestCases { - test := &rtrIPPrefixTestCases[i] - addr := net.ParseIP(test.pString) - verifyRTRMessage(t, NewRTRIPPrefix(addr, test.pLen, test.mLen, test.asn, test.flags)) - } -} - -func Test_RTREndOfData(t *testing.T) { - id := uint16(time.Now().Unix()) - sn := randUint32() - verifyRTRMessage(t, NewRTREndOfData(id, sn)) -} - -func Test_RTRCacheReset(t *testing.T) { - verifyRTRMessage(t, NewRTRCacheReset()) -} - -func Test_RTRErrorReport(t *testing.T) { - errPDU, _ := NewRTRResetQuery().Serialize() - errText1 := []byte("Couldn't send CacheResponce PDU") - errText2 := []byte("Wrong Length of PDU: 10 bytes") - - // See 5.10 ErrorReport in RFC6810 - // when it doesn't have both "erroneous PDU" and "Arbitrary Text" - verifyRTRMessage(t, NewRTRErrorReport(NO_DATA_AVAILABLE, nil, nil)) - - // when it has "erroneous PDU" - verifyRTRMessage(t, NewRTRErrorReport(UNSUPPORTED_PROTOCOL_VERSION, errPDU, nil)) - - // when it has "ArbitaryText" - verifyRTRMessage(t, NewRTRErrorReport(INTERNAL_ERROR, nil, errText1)) - - // when it has both "erroneous PDU" and "Arbitrary Text" - verifyRTRMessage(t, NewRTRErrorReport(CORRUPT_DATA, errPDU, errText2)) -} |