diff options
Diffstat (limited to 'packet/bgp/bgp.go')
-rw-r--r-- | packet/bgp/bgp.go | 9674 |
1 files changed, 0 insertions, 9674 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 - } -} |