summaryrefslogtreecommitdiffhomepage
path: root/packet
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2018-07-07 13:48:38 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2018-07-07 20:44:25 +0900
commitc4775c42510d1f1ddd55036dc19e982712fa6a0b (patch)
tree6ec8b61d4338c809e239e3003a2d32d480898e22 /packet
parentb3079759aa13172fcb548a83da9a9653d8d5fed4 (diff)
follow Standard Go Project Layout
https://github.com/golang-standards/project-layout Now you can see clearly what are private and public library code. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'packet')
-rw-r--r--packet/bgp/bgp.go9674
-rw-r--r--packet/bgp/bgp_race_test.go46
-rw-r--r--packet/bgp/bgp_test.go1194
-rw-r--r--packet/bgp/bgpattrtype_string.go28
-rw-r--r--packet/bgp/constant.go327
-rw-r--r--packet/bgp/esitype_string.go16
-rw-r--r--packet/bgp/fsmstate_string.go16
-rw-r--r--packet/bgp/helper.go126
-rw-r--r--packet/bgp/validate.go337
-rw-r--r--packet/bgp/validate_test.go423
-rw-r--r--packet/bmp/bmp.go1071
-rw-r--r--packet/bmp/bmp_test.go107
-rw-r--r--packet/mrt/mrt.go1006
-rw-r--r--packet/mrt/mrt_test.go301
-rw-r--r--packet/rtr/rtr.go392
-rw-r--r--packet/rtr/rtr_test.go118
16 files changed, 0 insertions, 15182 deletions
diff --git a/packet/bgp/bgp.go b/packet/bgp/bgp.go
deleted file mode 100644
index 01251167..00000000
--- a/packet/bgp/bgp.go
+++ /dev/null
@@ -1,9674 +0,0 @@
-// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bgp
-
-import (
- "bytes"
- "encoding/binary"
- "encoding/json"
- "fmt"
- "math"
- "net"
- "reflect"
- "regexp"
- "sort"
- "strconv"
- "strings"
-)
-
-type MarshallingOption struct {
- AddPath map[RouteFamily]BGPAddPathMode
-}
-
-func IsAddPathEnabled(decode bool, f RouteFamily, options []*MarshallingOption) bool {
- for _, opt := range options {
- if opt == nil {
- continue
- }
- if o := opt.AddPath; o != nil {
- if decode && o[f]&BGP_ADD_PATH_RECEIVE > 0 {
- return true
- } else if !decode && o[f]&BGP_ADD_PATH_SEND > 0 {
- return true
- }
- }
- }
- return false
-}
-
-const (
- AFI_IP = 1
- AFI_IP6 = 2
- AFI_L2VPN = 25
- AFI_OPAQUE = 16397
-)
-
-const (
- SAFI_UNICAST = 1
- SAFI_MULTICAST = 2
- SAFI_MPLS_LABEL = 4
- SAFI_ENCAPSULATION = 7
- SAFI_VPLS = 65
- SAFI_EVPN = 70
- SAFI_MPLS_VPN = 128
- SAFI_MPLS_VPN_MULTICAST = 129
- SAFI_ROUTE_TARGET_CONSTRAINTS = 132
- SAFI_FLOW_SPEC_UNICAST = 133
- SAFI_FLOW_SPEC_VPN = 134
- SAFI_KEY_VALUE = 241
-)
-
-const (
- BGP_ORIGIN_ATTR_TYPE_IGP uint8 = 0
- BGP_ORIGIN_ATTR_TYPE_EGP uint8 = 1
- BGP_ORIGIN_ATTR_TYPE_INCOMPLETE uint8 = 2
-)
-
-const (
- BGP_ASPATH_ATTR_TYPE_SET = 1
- BGP_ASPATH_ATTR_TYPE_SEQ = 2
- BGP_ASPATH_ATTR_TYPE_CONFED_SEQ = 3
- BGP_ASPATH_ATTR_TYPE_CONFED_SET = 4
-)
-
-// RFC7153 5.1. Registries for the "Type" Field
-// RANGE REGISTRATION PROCEDURES
-// 0x00-0x3F Transitive First Come First Served
-// 0x40-0x7F Non-Transitive First Come First Served
-// 0x80-0x8F Transitive Experimental Use
-// 0x90-0xBF Transitive Standards Action
-// 0xC0-0xCF Non-Transitive Experimental Use
-// 0xD0-0xFF Non-Transitive Standards Action
-type ExtendedCommunityAttrType uint8
-
-const (
- EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x00
- EC_TYPE_TRANSITIVE_IP6_SPECIFIC ExtendedCommunityAttrType = 0x00 // RFC5701
- EC_TYPE_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x01
- EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x02
- EC_TYPE_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x03
- EC_TYPE_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x04
- EC_TYPE_COS_CAPABILITY ExtendedCommunityAttrType = 0x05
- EC_TYPE_EVPN ExtendedCommunityAttrType = 0x06
- EC_TYPE_FLOWSPEC_REDIRECT_MIRROR ExtendedCommunityAttrType = 0x08
- EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x40
- EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC ExtendedCommunityAttrType = 0x40 // RFC5701
- EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC ExtendedCommunityAttrType = 0x41
- EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC ExtendedCommunityAttrType = 0x42
- EC_TYPE_NON_TRANSITIVE_OPAQUE ExtendedCommunityAttrType = 0x43
- EC_TYPE_NON_TRANSITIVE_QOS_MARKING ExtendedCommunityAttrType = 0x44
- EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL ExtendedCommunityAttrType = 0x80
- EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 ExtendedCommunityAttrType = 0x81 // RFC7674
- EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 ExtendedCommunityAttrType = 0x82 // RFC7674
-)
-
-// RFC7153 5.2. Registries for the "Sub-Type" Field
-// RANGE REGISTRATION PROCEDURES
-// 0x00-0xBF First Come First Served
-// 0xC0-0xFF IETF Review
-type ExtendedCommunityAttrSubType uint8
-
-const (
- EC_SUBTYPE_ROUTE_TARGET ExtendedCommunityAttrSubType = 0x02 // EC_TYPE: 0x00, 0x01, 0x02
- EC_SUBTYPE_ROUTE_ORIGIN ExtendedCommunityAttrSubType = 0x03 // EC_TYPE: 0x00, 0x01, 0x02
- EC_SUBTYPE_LINK_BANDWIDTH ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x40
- EC_SUBTYPE_GENERIC ExtendedCommunityAttrSubType = 0x04 // EC_TYPE: 0x02, 0x42
- EC_SUBTYPE_OSPF_DOMAIN_ID ExtendedCommunityAttrSubType = 0x05 // EC_TYPE: 0x00, 0x01, 0x02
- EC_SUBTYPE_OSPF_ROUTE_ID ExtendedCommunityAttrSubType = 0x07 // EC_TYPE: 0x01
- EC_SUBTYPE_BGP_DATA_COLLECTION ExtendedCommunityAttrSubType = 0x08 // EC_TYPE: 0x00, 0x02
- EC_SUBTYPE_SOURCE_AS ExtendedCommunityAttrSubType = 0x09 // EC_TYPE: 0x00, 0x02
- EC_SUBTYPE_L2VPN_ID ExtendedCommunityAttrSubType = 0x0A // EC_TYPE: 0x00, 0x01
- EC_SUBTYPE_VRF_ROUTE_IMPORT ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x01
- EC_SUBTYPE_CISCO_VPN_DISTINGUISHER ExtendedCommunityAttrSubType = 0x10 // EC_TYPE: 0x00, 0x01, 0x02
-
- EC_SUBTYPE_OSPF_ROUTE_TYPE ExtendedCommunityAttrSubType = 0x06 // EC_TYPE: 0x03
- EC_SUBTYPE_COLOR ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x03
- EC_SUBTYPE_ENCAPSULATION ExtendedCommunityAttrSubType = 0x0C // EC_TYPE: 0x03
- EC_SUBTYPE_DEFAULT_GATEWAY ExtendedCommunityAttrSubType = 0x0D // EC_TYPE: 0x03
-
- EC_SUBTYPE_ORIGIN_VALIDATION ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x43
-
- EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE ExtendedCommunityAttrSubType = 0x06 // EC_TYPE: 0x80
- EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION ExtendedCommunityAttrSubType = 0x07 // EC_TYPE: 0x80
- EC_SUBTYPE_FLOWSPEC_REDIRECT ExtendedCommunityAttrSubType = 0x08 // EC_TYPE: 0x80
- EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK ExtendedCommunityAttrSubType = 0x09 // EC_TYPE: 0x80
- EC_SUBTYPE_L2_INFO ExtendedCommunityAttrSubType = 0x0A // EC_TYPE: 0x80
- EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6 ExtendedCommunityAttrSubType = 0x0B // EC_TYPE: 0x80
-
- EC_SUBTYPE_MAC_MOBILITY ExtendedCommunityAttrSubType = 0x00 // EC_TYPE: 0x06
- EC_SUBTYPE_ESI_LABEL ExtendedCommunityAttrSubType = 0x01 // EC_TYPE: 0x06
- EC_SUBTYPE_ES_IMPORT ExtendedCommunityAttrSubType = 0x02 // EC_TYPE: 0x06
- EC_SUBTYPE_ROUTER_MAC ExtendedCommunityAttrSubType = 0x03 // EC_TYPE: 0x06
-
- EC_SUBTYPE_UUID_BASED_RT ExtendedCommunityAttrSubType = 0x11
-)
-
-type TunnelType uint16
-
-const (
- TUNNEL_TYPE_L2TP3 TunnelType = 1
- TUNNEL_TYPE_GRE TunnelType = 2
- TUNNEL_TYPE_IP_IN_IP TunnelType = 7
- TUNNEL_TYPE_VXLAN TunnelType = 8
- TUNNEL_TYPE_NVGRE TunnelType = 9
- TUNNEL_TYPE_MPLS TunnelType = 10
- TUNNEL_TYPE_MPLS_IN_GRE TunnelType = 11
- TUNNEL_TYPE_VXLAN_GRE TunnelType = 12
- TUNNEL_TYPE_MPLS_IN_UDP TunnelType = 13
-)
-
-func (p TunnelType) String() string {
- switch p {
- case TUNNEL_TYPE_L2TP3:
- return "l2tp3"
- case TUNNEL_TYPE_GRE:
- return "gre"
- case TUNNEL_TYPE_IP_IN_IP:
- return "ip-in-ip"
- case TUNNEL_TYPE_VXLAN:
- return "vxlan"
- case TUNNEL_TYPE_NVGRE:
- return "nvgre"
- case TUNNEL_TYPE_MPLS:
- return "mpls"
- case TUNNEL_TYPE_MPLS_IN_GRE:
- return "mpls-in-gre"
- case TUNNEL_TYPE_VXLAN_GRE:
- return "vxlan-gre"
- case TUNNEL_TYPE_MPLS_IN_UDP:
- return "mpls-in-udp"
- default:
- return fmt.Sprintf("TunnelType(%d)", uint8(p))
- }
-}
-
-type PmsiTunnelType uint8
-
-const (
- PMSI_TUNNEL_TYPE_NO_TUNNEL PmsiTunnelType = 0
- PMSI_TUNNEL_TYPE_RSVP_TE_P2MP PmsiTunnelType = 1
- PMSI_TUNNEL_TYPE_MLDP_P2MP PmsiTunnelType = 2
- PMSI_TUNNEL_TYPE_PIM_SSM_TREE PmsiTunnelType = 3
- PMSI_TUNNEL_TYPE_PIM_SM_TREE PmsiTunnelType = 4
- PMSI_TUNNEL_TYPE_BIDIR_PIM_TREE PmsiTunnelType = 5
- PMSI_TUNNEL_TYPE_INGRESS_REPL PmsiTunnelType = 6
- PMSI_TUNNEL_TYPE_MLDP_MP2MP PmsiTunnelType = 7
-)
-
-func (p PmsiTunnelType) String() string {
- switch p {
- case PMSI_TUNNEL_TYPE_NO_TUNNEL:
- return "no-tunnel"
- case PMSI_TUNNEL_TYPE_RSVP_TE_P2MP:
- return "rsvp-te-p2mp"
- case PMSI_TUNNEL_TYPE_MLDP_P2MP:
- return "mldp-p2mp"
- case PMSI_TUNNEL_TYPE_PIM_SSM_TREE:
- return "pim-ssm-tree"
- case PMSI_TUNNEL_TYPE_PIM_SM_TREE:
- return "pim-sm-tree"
- case PMSI_TUNNEL_TYPE_BIDIR_PIM_TREE:
- return "bidir-pim-tree"
- case PMSI_TUNNEL_TYPE_INGRESS_REPL:
- return "ingress-repl"
- case PMSI_TUNNEL_TYPE_MLDP_MP2MP:
- return "mldp-mp2mp"
- default:
- return fmt.Sprintf("PmsiTunnelType(%d)", uint8(p))
- }
-}
-
-type EncapSubTLVType uint8
-
-const (
- ENCAP_SUBTLV_TYPE_ENCAPSULATION EncapSubTLVType = 1
- ENCAP_SUBTLV_TYPE_PROTOCOL EncapSubTLVType = 2
- ENCAP_SUBTLV_TYPE_COLOR EncapSubTLVType = 4
-)
-
-const (
- _ = iota
- BGP_MSG_OPEN
- BGP_MSG_UPDATE
- BGP_MSG_NOTIFICATION
- BGP_MSG_KEEPALIVE
- BGP_MSG_ROUTE_REFRESH
-)
-
-const (
- BGP_OPT_CAPABILITY = 2
-)
-
-type BGPCapabilityCode uint8
-
-const (
- BGP_CAP_MULTIPROTOCOL BGPCapabilityCode = 1
- BGP_CAP_ROUTE_REFRESH BGPCapabilityCode = 2
- BGP_CAP_CARRYING_LABEL_INFO BGPCapabilityCode = 4
- BGP_CAP_EXTENDED_NEXTHOP BGPCapabilityCode = 5
- BGP_CAP_GRACEFUL_RESTART BGPCapabilityCode = 64
- BGP_CAP_FOUR_OCTET_AS_NUMBER BGPCapabilityCode = 65
- BGP_CAP_ADD_PATH BGPCapabilityCode = 69
- BGP_CAP_ENHANCED_ROUTE_REFRESH BGPCapabilityCode = 70
- BGP_CAP_LONG_LIVED_GRACEFUL_RESTART BGPCapabilityCode = 71
- BGP_CAP_ROUTE_REFRESH_CISCO BGPCapabilityCode = 128
-)
-
-var CapNameMap = map[BGPCapabilityCode]string{
- BGP_CAP_MULTIPROTOCOL: "multiprotocol",
- BGP_CAP_ROUTE_REFRESH: "route-refresh",
- BGP_CAP_CARRYING_LABEL_INFO: "carrying-label-info",
- BGP_CAP_GRACEFUL_RESTART: "graceful-restart",
- BGP_CAP_EXTENDED_NEXTHOP: "extended-nexthop",
- BGP_CAP_FOUR_OCTET_AS_NUMBER: "4-octet-as",
- BGP_CAP_ADD_PATH: "add-path",
- BGP_CAP_ENHANCED_ROUTE_REFRESH: "enhanced-route-refresh",
- BGP_CAP_ROUTE_REFRESH_CISCO: "cisco-route-refresh",
- BGP_CAP_LONG_LIVED_GRACEFUL_RESTART: "long-lived-graceful-restart",
-}
-
-func (c BGPCapabilityCode) String() string {
- if n, y := CapNameMap[c]; y {
- return n
- }
- return fmt.Sprintf("UnknownCapability(%d)", c)
-}
-
-var (
- // Used parsing RouteDistinguisher
- _regexpRouteDistinguisher = regexp.MustCompile(`^((\d+)\.(\d+)\.(\d+)\.(\d+)|((\d+)\.)?(\d+)|([\w]+:[\w:]*:[\w]+)):(\d+)$`)
-
- // Used for operator and value for the FlowSpec numeric type
- // Example:
- // re.FindStringSubmatch("&==80")
- // >>> ["&==80" "&" "==" "80"]
- _regexpFlowSpecNumericType = regexp.MustCompile(`(&?)(==|=|>|>=|<|<=|!|!=|=!)?(\d+|-\d|true|false)`)
-
- // - "=!" is used in the old style format of "tcp-flags" and "fragment".
- // - The value field should be one of the followings:
- // * Decimal value (e.g., 80)
- // * Combination of the small letters, decimals, "-" and "+"
- // (e.g., tcp, ipv4, is-fragment+first-fragment)
- // * Capital letters (e.g., SA)
- _regexpFlowSpecOperator = regexp.MustCompile(`&|=|>|<|!|[\w\-+]+`)
- _regexpFlowSpecOperatorValue = regexp.MustCompile(`[\w\-+]+`)
-
- // Note: "(-*)" and "(.*)" catch the invalid flags
- // Example: In this case, "Z" is unsupported flag type.
- // re.FindStringSubmatch("&==-SZU")
- // >>> ["&==-SZU" "&" "==" "-" "S" "ZU"]
- _regexpFlowSpecTCPFlag = regexp.MustCompile("(&?)(==|=|!|!=|=!)?(-*)([FSRPAUCE]+)(.*)")
-
- // Note: "(.*)" catches the invalid flags
- // re.FindStringSubmatch("&!=+first-fragment+last-fragment+invalid-fragment")
- // >>> ["&!=+first-fragment+last-fragment+invalid-fragment" "&" "!=" "+first-fragment+last-fragment" "+last-fragment" "+" "last" "+invalid-fragment"]
- _regexpFlowSpecFragment = regexp.MustCompile(`(&?)(==|=|!|!=|=!)?(((\+)?(dont|is|first|last|not-a)-fragment)+)(.*)`)
-
- // re.FindStringSubmatch("192.168.0.0/24")
- // >>> ["192.168.0.0/24" "192.168.0.0" "/24" "24"]
- // re.FindStringSubmatch("192.168.0.1")
- // >>> ["192.168.0.1" "192.168.0.1" "" ""]
- _regexpFindIPv4Prefix = regexp.MustCompile(`^([\d.]+)(/(\d{1,2}))?`)
-
- // re.FindStringSubmatch("2001:dB8::/64")
- // >>> ["2001:dB8::/64" "2001:dB8::" "/64" "64" "" ""]
- // re.FindStringSubmatch("2001:dB8::/64/8")
- // >>> ["2001:dB8::/64/8" "2001:dB8::" "/64" "64" "/8" "8"]
- // re.FindStringSubmatch("2001:dB8::1")
- // >>> ["2001:dB8::1" "2001:dB8::1" "" "" "" ""]
- _regexpFindIPv6Prefix = regexp.MustCompile(`^([a-fA-F\d:.]+)(/(\d{1,3}))?(/(\d{1,3}))?`)
-)
-
-type ParameterCapabilityInterface interface {
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
- Len() int
- Code() BGPCapabilityCode
-}
-
-type DefaultParameterCapability struct {
- CapCode BGPCapabilityCode `json:"code"`
- CapLen uint8 `json:"-"`
- CapValue []byte `json:"value,omitempty"`
-}
-
-func (c *DefaultParameterCapability) Code() BGPCapabilityCode {
- return c.CapCode
-}
-
-func (c *DefaultParameterCapability) DecodeFromBytes(data []byte) error {
- c.CapCode = BGPCapabilityCode(data[0])
- c.CapLen = data[1]
- if len(data) < 2+int(c.CapLen) {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all OptionParameterCapability bytes available")
- }
- if c.CapLen > 0 {
- c.CapValue = data[2 : 2+c.CapLen]
- }
- return nil
-}
-
-func (c *DefaultParameterCapability) Serialize() ([]byte, error) {
- c.CapLen = uint8(len(c.CapValue))
- buf := make([]byte, 2)
- buf[0] = uint8(c.CapCode)
- buf[1] = c.CapLen
- buf = append(buf, c.CapValue...)
- return buf, nil
-}
-
-func (c *DefaultParameterCapability) Len() int {
- return int(c.CapLen + 2)
-}
-
-type CapMultiProtocol struct {
- DefaultParameterCapability
- CapValue RouteFamily
-}
-
-func (c *CapMultiProtocol) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
- if len(data) < 4 {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityMultiProtocol bytes available")
- }
- c.CapValue = AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[0:2]), data[3])
- return nil
-}
-
-func (c *CapMultiProtocol) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- afi, safi := RouteFamilyToAfiSafi(c.CapValue)
- binary.BigEndian.PutUint16(buf[0:], afi)
- buf[3] = safi
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapMultiProtocol) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Value RouteFamily `json:"value"`
- }{
- Code: c.Code(),
- Value: c.CapValue,
- })
-}
-
-func NewCapMultiProtocol(rf RouteFamily) *CapMultiProtocol {
- return &CapMultiProtocol{
- DefaultParameterCapability{
- CapCode: BGP_CAP_MULTIPROTOCOL,
- },
- rf,
- }
-}
-
-type CapRouteRefresh struct {
- DefaultParameterCapability
-}
-
-func NewCapRouteRefresh() *CapRouteRefresh {
- return &CapRouteRefresh{
- DefaultParameterCapability{
- CapCode: BGP_CAP_ROUTE_REFRESH,
- },
- }
-}
-
-type CapCarryingLabelInfo struct {
- DefaultParameterCapability
-}
-
-func NewCapCarryingLabelInfo() *CapCarryingLabelInfo {
- return &CapCarryingLabelInfo{
- DefaultParameterCapability{
- CapCode: BGP_CAP_CARRYING_LABEL_INFO,
- },
- }
-}
-
-type CapExtendedNexthopTuple struct {
- NLRIAFI uint16
- NLRISAFI uint16
- NexthopAFI uint16
-}
-
-func (c *CapExtendedNexthopTuple) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- NLRIAddressFamily RouteFamily `json:"nlri_address_family"`
- NexthopAddressFamily uint16 `json:"nexthop_address_family"`
- }{
- NLRIAddressFamily: AfiSafiToRouteFamily(c.NLRIAFI, uint8(c.NLRISAFI)),
- NexthopAddressFamily: c.NexthopAFI,
- })
-}
-
-func NewCapExtendedNexthopTuple(af RouteFamily, nexthop uint16) *CapExtendedNexthopTuple {
- afi, safi := RouteFamilyToAfiSafi(af)
- return &CapExtendedNexthopTuple{
- NLRIAFI: afi,
- NLRISAFI: uint16(safi),
- NexthopAFI: nexthop,
- }
-}
-
-type CapExtendedNexthop struct {
- DefaultParameterCapability
- Tuples []*CapExtendedNexthopTuple
-}
-
-func (c *CapExtendedNexthop) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
- if len(data) < 6 {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityExtendedNexthop bytes available")
- }
- c.Tuples = []*CapExtendedNexthopTuple{}
- for len(data) >= 6 {
- t := &CapExtendedNexthopTuple{
- binary.BigEndian.Uint16(data[0:2]),
- binary.BigEndian.Uint16(data[2:4]),
- binary.BigEndian.Uint16(data[4:6]),
- }
- c.Tuples = append(c.Tuples, t)
- data = data[6:]
- }
- return nil
-}
-
-func (c *CapExtendedNexthop) Serialize() ([]byte, error) {
- buf := make([]byte, len(c.Tuples)*6)
- for i, t := range c.Tuples {
- binary.BigEndian.PutUint16(buf[i*6:i*6+2], t.NLRIAFI)
- binary.BigEndian.PutUint16(buf[i*6+2:i*6+4], t.NLRISAFI)
- binary.BigEndian.PutUint16(buf[i*6+4:i*6+6], t.NexthopAFI)
- }
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapExtendedNexthop) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Tuples []*CapExtendedNexthopTuple `json:"tuples"`
- }{
- Code: c.Code(),
- Tuples: c.Tuples,
- })
-}
-
-func NewCapExtendedNexthop(tuples []*CapExtendedNexthopTuple) *CapExtendedNexthop {
- return &CapExtendedNexthop{
- DefaultParameterCapability{
- CapCode: BGP_CAP_EXTENDED_NEXTHOP,
- },
- tuples,
- }
-}
-
-type CapGracefulRestartTuple struct {
- AFI uint16
- SAFI uint8
- Flags uint8
-}
-
-func (c *CapGracefulRestartTuple) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RouteFamily RouteFamily `json:"route_family"`
- Flags uint8 `json:"flags"`
- }{
- RouteFamily: AfiSafiToRouteFamily(c.AFI, c.SAFI),
- Flags: c.Flags,
- })
-}
-
-func NewCapGracefulRestartTuple(rf RouteFamily, forward bool) *CapGracefulRestartTuple {
- afi, safi := RouteFamilyToAfiSafi(rf)
- flags := 0
- if forward {
- flags = 0x80
- }
- return &CapGracefulRestartTuple{
- AFI: afi,
- SAFI: safi,
- Flags: uint8(flags),
- }
-}
-
-type CapGracefulRestart struct {
- DefaultParameterCapability
- Flags uint8
- Time uint16
- Tuples []*CapGracefulRestartTuple
-}
-
-func (c *CapGracefulRestart) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
- if len(data) < 2 {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityGracefulRestart bytes available")
- }
- restart := binary.BigEndian.Uint16(data[0:2])
- c.Flags = uint8(restart >> 12)
- c.Time = restart & 0xfff
- data = data[2:]
-
- valueLen := int(c.CapLen) - 2
-
- if valueLen >= 4 && len(data) >= valueLen {
- c.Tuples = make([]*CapGracefulRestartTuple, 0, valueLen/4)
-
- for i := valueLen; i >= 4; i -= 4 {
- t := &CapGracefulRestartTuple{binary.BigEndian.Uint16(data[0:2]),
- data[2], data[3]}
- c.Tuples = append(c.Tuples, t)
- data = data[4:]
- }
- }
- return nil
-}
-
-func (c *CapGracefulRestart) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf[0:], uint16(c.Flags)<<12|c.Time)
- for _, t := range c.Tuples {
- tbuf := make([]byte, 4)
- binary.BigEndian.PutUint16(tbuf[0:2], t.AFI)
- tbuf[2] = t.SAFI
- tbuf[3] = t.Flags
- buf = append(buf, tbuf...)
- }
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapGracefulRestart) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Flags uint8 `json:"flags"`
- Time uint16 `json:"time"`
- Tuples []*CapGracefulRestartTuple `json:"tuples"`
- }{
- Code: c.Code(),
- Flags: c.Flags,
- Time: c.Time,
- Tuples: c.Tuples,
- })
-}
-
-func NewCapGracefulRestart(restarting, notification bool, time uint16, tuples []*CapGracefulRestartTuple) *CapGracefulRestart {
- flags := 0
- if restarting {
- flags = 0x08
- }
- if notification {
- flags |= 0x04
- }
- return &CapGracefulRestart{
- DefaultParameterCapability: DefaultParameterCapability{
- CapCode: BGP_CAP_GRACEFUL_RESTART,
- },
- Flags: uint8(flags),
- Time: time,
- Tuples: tuples,
- }
-}
-
-type CapFourOctetASNumber struct {
- DefaultParameterCapability
- CapValue uint32
-}
-
-func (c *CapFourOctetASNumber) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
- if len(data) < 4 {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityFourOctetASNumber bytes available")
- }
- c.CapValue = binary.BigEndian.Uint32(data[0:4])
- return nil
-}
-
-func (c *CapFourOctetASNumber) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, c.CapValue)
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapFourOctetASNumber) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Value uint32 `json:"value"`
- }{
- Code: c.Code(),
- Value: c.CapValue,
- })
-}
-
-func NewCapFourOctetASNumber(asnum uint32) *CapFourOctetASNumber {
- return &CapFourOctetASNumber{
- DefaultParameterCapability{
- CapCode: BGP_CAP_FOUR_OCTET_AS_NUMBER,
- },
- asnum,
- }
-}
-
-type BGPAddPathMode uint8
-
-const (
- BGP_ADD_PATH_NONE BGPAddPathMode = iota
- BGP_ADD_PATH_RECEIVE
- BGP_ADD_PATH_SEND
- BGP_ADD_PATH_BOTH
-)
-
-func (m BGPAddPathMode) String() string {
- switch m {
- case BGP_ADD_PATH_NONE:
- return "none"
- case BGP_ADD_PATH_RECEIVE:
- return "receive"
- case BGP_ADD_PATH_SEND:
- return "send"
- case BGP_ADD_PATH_BOTH:
- return "receive/send"
- default:
- return fmt.Sprintf("unknown(%d)", m)
- }
-}
-
-type CapAddPathTuple struct {
- RouteFamily RouteFamily
- Mode BGPAddPathMode
-}
-
-func (t *CapAddPathTuple) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RouteFamily RouteFamily `json:"family"`
- Mode uint8 `json:"mode"`
- }{
- RouteFamily: t.RouteFamily,
- Mode: uint8(t.Mode),
- })
-}
-
-func NewCapAddPathTuple(family RouteFamily, mode BGPAddPathMode) *CapAddPathTuple {
- return &CapAddPathTuple{
- RouteFamily: family,
- Mode: mode,
- }
-}
-
-type CapAddPath struct {
- DefaultParameterCapability
- Tuples []*CapAddPathTuple
-}
-
-func (c *CapAddPath) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
- if len(data) < 4 {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all CapabilityAddPath bytes available")
- }
- c.Tuples = []*CapAddPathTuple{}
- for len(data) >= 4 {
- t := &CapAddPathTuple{
- RouteFamily: AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[:2]), data[2]),
- Mode: BGPAddPathMode(data[3]),
- }
- c.Tuples = append(c.Tuples, t)
- data = data[4:]
- }
- return nil
-}
-
-func (c *CapAddPath) Serialize() ([]byte, error) {
- buf := make([]byte, len(c.Tuples)*4)
- for i, t := range c.Tuples {
- afi, safi := RouteFamilyToAfiSafi(t.RouteFamily)
- binary.BigEndian.PutUint16(buf[i*4:i*4+2], afi)
- buf[i*4+2] = safi
- buf[i*4+3] = byte(t.Mode)
- }
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapAddPath) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Tuples []*CapAddPathTuple `json:"tuples"`
- }{
- Code: c.Code(),
- Tuples: c.Tuples,
- })
-}
-
-func NewCapAddPath(tuples []*CapAddPathTuple) *CapAddPath {
- return &CapAddPath{
- DefaultParameterCapability: DefaultParameterCapability{
- CapCode: BGP_CAP_ADD_PATH,
- },
- Tuples: tuples,
- }
-}
-
-type CapEnhancedRouteRefresh struct {
- DefaultParameterCapability
-}
-
-func NewCapEnhancedRouteRefresh() *CapEnhancedRouteRefresh {
- return &CapEnhancedRouteRefresh{
- DefaultParameterCapability{
- CapCode: BGP_CAP_ENHANCED_ROUTE_REFRESH,
- },
- }
-}
-
-type CapRouteRefreshCisco struct {
- DefaultParameterCapability
-}
-
-func NewCapRouteRefreshCisco() *CapRouteRefreshCisco {
- return &CapRouteRefreshCisco{
- DefaultParameterCapability{
- CapCode: BGP_CAP_ROUTE_REFRESH_CISCO,
- },
- }
-}
-
-type CapLongLivedGracefulRestartTuple struct {
- AFI uint16
- SAFI uint8
- Flags uint8
- RestartTime uint32
-}
-
-func (c *CapLongLivedGracefulRestartTuple) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RouteFamily RouteFamily `json:"route_family"`
- Flags uint8 `json:"flags"`
- RestartTime uint32 `json:"restart_time"`
- }{
- RouteFamily: AfiSafiToRouteFamily(c.AFI, c.SAFI),
- Flags: c.Flags,
- RestartTime: c.RestartTime,
- })
-}
-
-func NewCapLongLivedGracefulRestartTuple(rf RouteFamily, forward bool, restartTime uint32) *CapLongLivedGracefulRestartTuple {
- afi, safi := RouteFamilyToAfiSafi(rf)
- flags := 0
- if forward {
- flags = 0x80
- }
- return &CapLongLivedGracefulRestartTuple{
- AFI: afi,
- SAFI: safi,
- Flags: uint8(flags),
- RestartTime: restartTime,
- }
-}
-
-type CapLongLivedGracefulRestart struct {
- DefaultParameterCapability
- Tuples []*CapLongLivedGracefulRestartTuple
-}
-
-func (c *CapLongLivedGracefulRestart) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
-
- valueLen := int(c.CapLen)
- if valueLen%7 != 0 || len(data) < valueLen {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "invalid length of long lived graceful restart capablity")
- }
- for i := valueLen; i >= 7; i -= 7 {
- t := &CapLongLivedGracefulRestartTuple{
- binary.BigEndian.Uint16(data),
- data[2],
- data[3],
- uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6]),
- }
- c.Tuples = append(c.Tuples, t)
- data = data[7:]
- }
- return nil
-}
-
-func (c *CapLongLivedGracefulRestart) Serialize() ([]byte, error) {
- buf := make([]byte, 7*len(c.Tuples))
- for idx, t := range c.Tuples {
- binary.BigEndian.PutUint16(buf[idx*7:], t.AFI)
- buf[idx*7+2] = t.SAFI
- buf[idx*7+3] = t.Flags
- buf[idx*7+4] = uint8((t.RestartTime >> 16) & 0xff)
- buf[idx*7+5] = uint8((t.RestartTime >> 8) & 0xff)
- buf[idx*7+6] = uint8(t.RestartTime & 0xff)
- }
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapLongLivedGracefulRestart) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Tuples []*CapLongLivedGracefulRestartTuple `json:"tuples"`
- }{
- Code: c.Code(),
- Tuples: c.Tuples,
- })
-}
-
-func NewCapLongLivedGracefulRestart(tuples []*CapLongLivedGracefulRestartTuple) *CapLongLivedGracefulRestart {
- return &CapLongLivedGracefulRestart{
- DefaultParameterCapability: DefaultParameterCapability{
- CapCode: BGP_CAP_LONG_LIVED_GRACEFUL_RESTART,
- },
- Tuples: tuples,
- }
-}
-
-type CapUnknown struct {
- DefaultParameterCapability
-}
-
-func NewCapUnknown(code BGPCapabilityCode, value []byte) *CapUnknown {
- return &CapUnknown{
- DefaultParameterCapability{
- CapCode: code,
- CapValue: value,
- },
- }
-}
-
-func DecodeCapability(data []byte) (ParameterCapabilityInterface, error) {
- if len(data) < 2 {
- return nil, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY, nil, "Not all ParameterCapability bytes available")
- }
- var c ParameterCapabilityInterface
- switch BGPCapabilityCode(data[0]) {
- case BGP_CAP_MULTIPROTOCOL:
- c = &CapMultiProtocol{}
- case BGP_CAP_ROUTE_REFRESH:
- c = &CapRouteRefresh{}
- case BGP_CAP_CARRYING_LABEL_INFO:
- c = &CapCarryingLabelInfo{}
- case BGP_CAP_EXTENDED_NEXTHOP:
- c = &CapExtendedNexthop{}
- case BGP_CAP_GRACEFUL_RESTART:
- c = &CapGracefulRestart{}
- case BGP_CAP_FOUR_OCTET_AS_NUMBER:
- c = &CapFourOctetASNumber{}
- case BGP_CAP_ADD_PATH:
- c = &CapAddPath{}
- case BGP_CAP_ENHANCED_ROUTE_REFRESH:
- c = &CapEnhancedRouteRefresh{}
- case BGP_CAP_ROUTE_REFRESH_CISCO:
- c = &CapRouteRefreshCisco{}
- case BGP_CAP_LONG_LIVED_GRACEFUL_RESTART:
- c = &CapLongLivedGracefulRestart{}
- default:
- c = &CapUnknown{}
- }
- err := c.DecodeFromBytes(data)
- return c, err
-}
-
-type OptionParameterInterface interface {
- Serialize() ([]byte, error)
-}
-
-type OptionParameterCapability struct {
- ParamType uint8
- ParamLen uint8
- Capability []ParameterCapabilityInterface
-}
-
-func (o *OptionParameterCapability) DecodeFromBytes(data []byte) error {
- if uint8(len(data)) < o.ParamLen {
- return NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_OPTIONAL_PARAMETER, nil, "Not all OptionParameterCapability bytes available")
- }
- for len(data) >= 2 {
- c, err := DecodeCapability(data)
- if err != nil {
- return err
- }
- o.Capability = append(o.Capability, c)
- data = data[c.Len():]
- }
- return nil
-}
-
-func (o *OptionParameterCapability) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- buf[0] = o.ParamType
- for _, p := range o.Capability {
- pbuf, err := p.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- }
- o.ParamLen = uint8(len(buf) - 2)
- buf[1] = o.ParamLen
- return buf, nil
-}
-
-func NewOptionParameterCapability(capability []ParameterCapabilityInterface) *OptionParameterCapability {
- return &OptionParameterCapability{
- ParamType: BGP_OPT_CAPABILITY,
- Capability: capability,
- }
-}
-
-type OptionParameterUnknown struct {
- ParamType uint8
- ParamLen uint8
- Value []byte
-}
-
-func (o *OptionParameterUnknown) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- buf[0] = o.ParamType
- if o.ParamLen == 0 {
- o.ParamLen = uint8(len(o.Value))
- }
- buf[1] = o.ParamLen
- return append(buf, o.Value...), nil
-}
-
-type BGPOpen struct {
- Version uint8
- MyAS uint16
- HoldTime uint16
- ID net.IP
- OptParamLen uint8
- OptParams []OptionParameterInterface
-}
-
-func (msg *BGPOpen) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if len(data) < 10 {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP Open message bytes available")
- }
- msg.Version = data[0]
- msg.MyAS = binary.BigEndian.Uint16(data[1:3])
- msg.HoldTime = binary.BigEndian.Uint16(data[3:5])
- msg.ID = net.IP(data[5:9]).To4()
- msg.OptParamLen = data[9]
- data = data[10:]
- if len(data) < int(msg.OptParamLen) {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP Open message bytes available")
- }
-
- msg.OptParams = []OptionParameterInterface{}
- for rest := msg.OptParamLen; rest > 0; {
- if rest < 2 {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Malformed BGP Open message")
- }
- paramtype := data[0]
- paramlen := data[1]
- if rest < paramlen+2 {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Malformed BGP Open message")
- }
- rest -= paramlen + 2
-
- if paramtype == BGP_OPT_CAPABILITY {
- p := &OptionParameterCapability{}
- p.ParamType = paramtype
- p.ParamLen = paramlen
- p.DecodeFromBytes(data[2 : 2+paramlen])
- msg.OptParams = append(msg.OptParams, p)
- } else {
- p := &OptionParameterUnknown{}
- p.ParamType = paramtype
- p.ParamLen = paramlen
- p.Value = data[2 : 2+paramlen]
- msg.OptParams = append(msg.OptParams, p)
- }
- data = data[2+paramlen:]
- }
- return nil
-}
-
-func (msg *BGPOpen) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 10)
- buf[0] = msg.Version
- binary.BigEndian.PutUint16(buf[1:3], msg.MyAS)
- binary.BigEndian.PutUint16(buf[3:5], msg.HoldTime)
- copy(buf[5:9], msg.ID.To4())
- pbuf := make([]byte, 0)
- for _, p := range msg.OptParams {
- onepbuf, err := p.Serialize()
- if err != nil {
- return nil, err
- }
- pbuf = append(pbuf, onepbuf...)
- }
- msg.OptParamLen = uint8(len(pbuf))
- buf[9] = msg.OptParamLen
- return append(buf, pbuf...), nil
-}
-
-func NewBGPOpenMessage(myas uint16, holdtime uint16, id string, optparams []OptionParameterInterface) *BGPMessage {
- return &BGPMessage{
- Header: BGPHeader{Type: BGP_MSG_OPEN},
- Body: &BGPOpen{4, myas, holdtime, net.ParseIP(id).To4(), 0, optparams},
- }
-}
-
-type AddrPrefixInterface interface {
- DecodeFromBytes([]byte, ...*MarshallingOption) error
- Serialize(...*MarshallingOption) ([]byte, error)
- AFI() uint16
- SAFI() uint8
- Len(...*MarshallingOption) int
- String() string
- MarshalJSON() ([]byte, error)
- // Create a flat map to describe attributes and their
- // values. This can be used to create structured outputs.
- Flat() map[string]string
- PathIdentifier() uint32
- SetPathIdentifier(uint32)
- PathLocalIdentifier() uint32
- SetPathLocalIdentifier(uint32)
-}
-
-func LabelString(nlri AddrPrefixInterface) string {
- label := ""
- switch n := nlri.(type) {
- case *LabeledIPAddrPrefix:
- label = n.Labels.String()
- case *LabeledIPv6AddrPrefix:
- label = n.Labels.String()
- case *LabeledVPNIPAddrPrefix:
- label = n.Labels.String()
- case *LabeledVPNIPv6AddrPrefix:
- label = n.Labels.String()
- case *EVPNNLRI:
- switch route := n.RouteTypeData.(type) {
- case *EVPNEthernetAutoDiscoveryRoute:
- label = fmt.Sprintf("[%d]", route.Label)
- case *EVPNMacIPAdvertisementRoute:
- var l []string
- for _, i := range route.Labels {
- l = append(l, strconv.Itoa(int(i)))
- }
- label = fmt.Sprintf("[%s]", strings.Join(l, ","))
- case *EVPNIPPrefixRoute:
- label = fmt.Sprintf("[%d]", route.Label)
- }
- }
- return label
-}
-
-type PrefixDefault struct {
- id uint32
- localId uint32
-}
-
-func (p *PrefixDefault) PathIdentifier() uint32 {
- return p.id
-}
-
-func (p *PrefixDefault) SetPathIdentifier(id uint32) {
- p.id = id
-}
-
-func (p *PrefixDefault) PathLocalIdentifier() uint32 {
- return p.localId
-}
-
-func (p *PrefixDefault) SetPathLocalIdentifier(id uint32) {
- p.localId = id
-}
-
-func (p *PrefixDefault) decodePathIdentifier(data []byte) ([]byte, error) {
- if len(data) < 4 {
- code := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- subcode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return nil, NewMessageError(code, subcode, nil, "prefix misses path identifier field")
- }
- p.SetPathIdentifier(binary.BigEndian.Uint32(data[:4]))
- return data[4:], nil
-}
-
-func (p *PrefixDefault) serializeIdentifier() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, p.PathLocalIdentifier())
- return buf, nil
-}
-
-type IPAddrPrefixDefault struct {
- PrefixDefault
- Length uint8
- Prefix net.IP
-}
-
-func (r *IPAddrPrefixDefault) decodePrefix(data []byte, bitlen uint8, addrlen uint8) error {
- bytelen := (int(bitlen) + 7) / 8
- if len(data) < bytelen {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "network bytes is short")
- }
- b := make([]byte, addrlen)
- copy(b, data[:bytelen])
- // clear trailing bits in the last byte. rfc doesn't require
- // this but some bgp implementations need this...
- rem := bitlen % 8
- if rem != 0 {
- mask := 0xff00 >> rem
- lastByte := b[bytelen-1] & byte(mask)
- b[bytelen-1] = lastByte
- }
- r.Prefix = b
- return nil
-}
-
-func (r *IPAddrPrefixDefault) serializePrefix(bitLen uint8) ([]byte, error) {
- byteLen := (int(bitLen) + 7) / 8
- buf := make([]byte, byteLen)
- copy(buf, r.Prefix)
- return buf, nil
-}
-
-func (r *IPAddrPrefixDefault) String() string {
- return fmt.Sprintf("%s/%d", r.Prefix.String(), r.Length)
-}
-
-func (r *IPAddrPrefixDefault) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Prefix string `json:"prefix"`
- }{
- Prefix: r.String(),
- })
-}
-
-type IPAddrPrefix struct {
- IPAddrPrefixDefault
- addrlen uint8
-}
-
-func (r *IPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if r.addrlen == 0 {
- r.addrlen = 4
- }
- f := RF_IPv4_UC
- if r.addrlen == 16 {
- f = RF_IPv6_UC
- }
- if IsAddPathEnabled(true, f, options) {
- var err error
- data, err = r.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- if len(data) < 1 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "prefix misses length field")
- }
- r.Length = data[0]
- return r.decodePrefix(data[1:], r.Length, r.addrlen)
-}
-
-func (r *IPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- f := RF_IPv4_UC
- if r.addrlen == 16 {
- f = RF_IPv6_UC
- }
- var buf []byte
- if IsAddPathEnabled(false, f, options) {
- var err error
- buf, err = r.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- }
- buf = append(buf, r.Length)
- pbuf, err := r.serializePrefix(r.Length)
- if err != nil {
- return nil, err
- }
- return append(buf, pbuf...), nil
-}
-
-func (r *IPAddrPrefix) AFI() uint16 {
- return AFI_IP
-}
-
-func (r *IPAddrPrefix) SAFI() uint8 {
- return SAFI_UNICAST
-}
-
-func (r *IPAddrPrefix) Len(options ...*MarshallingOption) int {
- return 1 + ((int(r.Length) + 7) / 8)
-}
-
-func NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix {
- p := &IPAddrPrefix{
- IPAddrPrefixDefault{
- Length: length,
- },
- 4,
- }
- p.IPAddrPrefixDefault.decodePrefix(net.ParseIP(prefix).To4(), length, 4)
- return p
-}
-
-func isIPv4MappedIPv6(ip net.IP) bool {
- return len(ip) == net.IPv6len && ip.To4() != nil
-}
-
-type IPv6AddrPrefix struct {
- IPAddrPrefix
-}
-
-func (r *IPv6AddrPrefix) AFI() uint16 {
- return AFI_IP6
-}
-
-func (r *IPv6AddrPrefix) String() string {
- prefix := r.Prefix.String()
- if isIPv4MappedIPv6(r.Prefix) {
- prefix = "::ffff:" + prefix
- }
- return fmt.Sprintf("%s/%d", prefix, r.Length)
-}
-
-func NewIPv6AddrPrefix(length uint8, prefix string) *IPv6AddrPrefix {
- p := &IPv6AddrPrefix{
- IPAddrPrefix{
- IPAddrPrefixDefault{
- Length: length,
- },
- 16,
- },
- }
- p.IPAddrPrefixDefault.decodePrefix(net.ParseIP(prefix), length, 16)
- return p
-}
-
-const (
- BGP_RD_TWO_OCTET_AS = iota
- BGP_RD_IPV4_ADDRESS
- BGP_RD_FOUR_OCTET_AS
-)
-
-type RouteDistinguisherInterface interface {
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
- Len() int
- String() string
- MarshalJSON() ([]byte, error)
-}
-
-type DefaultRouteDistinguisher struct {
- Type uint16
-}
-
-func (rd *DefaultRouteDistinguisher) serialize(value []byte) ([]byte, error) {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint16(buf, rd.Type)
- copy(buf[2:], value)
- return buf, nil
-}
-
-func (rd *DefaultRouteDistinguisher) Len() int {
- return 8
-}
-
-type RouteDistinguisherTwoOctetAS struct {
- DefaultRouteDistinguisher
- Admin uint16
- Assigned uint32
-}
-
-func (rd *RouteDistinguisherTwoOctetAS) DecodeFromBytes(data []byte) error {
- rd.Admin = binary.BigEndian.Uint16(data[0:2])
- rd.Assigned = binary.BigEndian.Uint32(data[2:6])
- return nil
-}
-
-func (rd *RouteDistinguisherTwoOctetAS) Serialize() ([]byte, error) {
- buf := make([]byte, 6)
- binary.BigEndian.PutUint16(buf[0:2], rd.Admin)
- binary.BigEndian.PutUint32(buf[2:6], rd.Assigned)
- return rd.serialize(buf)
-}
-
-func (rd *RouteDistinguisherTwoOctetAS) String() string {
- return fmt.Sprintf("%d:%d", rd.Admin, rd.Assigned)
-}
-
-func (rd *RouteDistinguisherTwoOctetAS) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint16 `json:"type"`
- Admin uint16 `json:"admin"`
- Assigned uint32 `json:"assigned"`
- }{
- Type: rd.Type,
- Admin: rd.Admin,
- Assigned: rd.Assigned,
- })
-}
-
-func NewRouteDistinguisherTwoOctetAS(admin uint16, assigned uint32) *RouteDistinguisherTwoOctetAS {
- return &RouteDistinguisherTwoOctetAS{
- DefaultRouteDistinguisher: DefaultRouteDistinguisher{
- Type: BGP_RD_TWO_OCTET_AS,
- },
- Admin: admin,
- Assigned: assigned,
- }
-}
-
-type RouteDistinguisherIPAddressAS struct {
- DefaultRouteDistinguisher
- Admin net.IP
- Assigned uint16
-}
-
-func (rd *RouteDistinguisherIPAddressAS) DecodeFromBytes(data []byte) error {
- rd.Admin = data[0:4]
- rd.Assigned = binary.BigEndian.Uint16(data[4:6])
- return nil
-}
-
-func (rd *RouteDistinguisherIPAddressAS) Serialize() ([]byte, error) {
- buf := make([]byte, 6)
- copy(buf[0:4], rd.Admin.To4())
- binary.BigEndian.PutUint16(buf[4:6], rd.Assigned)
- return rd.serialize(buf)
-}
-
-func (rd *RouteDistinguisherIPAddressAS) String() string {
- return fmt.Sprintf("%s:%d", rd.Admin.String(), rd.Assigned)
-}
-
-func (rd *RouteDistinguisherIPAddressAS) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint16 `json:"type"`
- Admin string `json:"admin"`
- Assigned uint16 `json:"assigned"`
- }{
- Type: rd.Type,
- Admin: rd.Admin.String(),
- Assigned: rd.Assigned,
- })
-}
-
-func NewRouteDistinguisherIPAddressAS(admin string, assigned uint16) *RouteDistinguisherIPAddressAS {
- return &RouteDistinguisherIPAddressAS{
- DefaultRouteDistinguisher: DefaultRouteDistinguisher{
- Type: BGP_RD_IPV4_ADDRESS,
- },
- Admin: net.ParseIP(admin).To4(),
- Assigned: assigned,
- }
-}
-
-type RouteDistinguisherFourOctetAS struct {
- DefaultRouteDistinguisher
- Admin uint32
- Assigned uint16
-}
-
-func (rd *RouteDistinguisherFourOctetAS) DecodeFromBytes(data []byte) error {
- rd.Admin = binary.BigEndian.Uint32(data[0:4])
- rd.Assigned = binary.BigEndian.Uint16(data[4:6])
- return nil
-}
-
-func (rd *RouteDistinguisherFourOctetAS) Serialize() ([]byte, error) {
- buf := make([]byte, 6)
- binary.BigEndian.PutUint32(buf[0:4], rd.Admin)
- binary.BigEndian.PutUint16(buf[4:6], rd.Assigned)
- return rd.serialize(buf)
-}
-
-func (rd *RouteDistinguisherFourOctetAS) String() string {
- fst := rd.Admin >> 16 & 0xffff
- snd := rd.Admin & 0xffff
- return fmt.Sprintf("%d.%d:%d", fst, snd, rd.Assigned)
-}
-
-func (rd *RouteDistinguisherFourOctetAS) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint16 `json:"type"`
- Admin uint32 `json:"admin"`
- Assigned uint16 `json:"assigned"`
- }{
- Type: rd.Type,
- Admin: rd.Admin,
- Assigned: rd.Assigned,
- })
-}
-
-func NewRouteDistinguisherFourOctetAS(admin uint32, assigned uint16) *RouteDistinguisherFourOctetAS {
- return &RouteDistinguisherFourOctetAS{
- DefaultRouteDistinguisher: DefaultRouteDistinguisher{
- Type: BGP_RD_FOUR_OCTET_AS,
- },
- Admin: admin,
- Assigned: assigned,
- }
-}
-
-type RouteDistinguisherUnknown struct {
- DefaultRouteDistinguisher
- Value []byte
-}
-
-func (rd *RouteDistinguisherUnknown) DecodeFromBytes(data []byte) error {
- rd.Value = data[0:6]
- return nil
-}
-
-func (rd *RouteDistinguisherUnknown) Serialize() ([]byte, error) {
- return rd.DefaultRouteDistinguisher.serialize(rd.Value)
-}
-
-func (rd *RouteDistinguisherUnknown) String() string {
- return fmt.Sprintf("%v", rd.Value)
-}
-
-func (rd *RouteDistinguisherUnknown) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint16 `json:"type"`
- Value []byte `json:"value"`
- }{
- Type: rd.Type,
- Value: rd.Value,
- })
-}
-
-func GetRouteDistinguisher(data []byte) RouteDistinguisherInterface {
- typ := binary.BigEndian.Uint16(data[0:2])
- switch typ {
- case BGP_RD_TWO_OCTET_AS:
- return NewRouteDistinguisherTwoOctetAS(binary.BigEndian.Uint16(data[2:4]), binary.BigEndian.Uint32(data[4:8]))
- case BGP_RD_IPV4_ADDRESS:
- return NewRouteDistinguisherIPAddressAS(net.IP(data[2:6]).String(), binary.BigEndian.Uint16(data[6:8]))
- case BGP_RD_FOUR_OCTET_AS:
- return NewRouteDistinguisherFourOctetAS(binary.BigEndian.Uint32(data[2:6]), binary.BigEndian.Uint16(data[6:8]))
- }
- rd := &RouteDistinguisherUnknown{
- DefaultRouteDistinguisher: DefaultRouteDistinguisher{
- Type: typ,
- },
- }
- return rd
-}
-
-func parseRdAndRt(input string) ([]string, error) {
- elems := _regexpRouteDistinguisher.FindStringSubmatch(input)
- if len(elems) != 11 {
- return nil, fmt.Errorf("failed to parse")
- }
- return elems, nil
-}
-
-func ParseRouteDistinguisher(rd string) (RouteDistinguisherInterface, error) {
- elems, err := parseRdAndRt(rd)
- if err != nil {
- return nil, err
- }
- assigned, _ := strconv.ParseUint(elems[10], 10, 32)
- ip := net.ParseIP(elems[1])
- switch {
- case ip.To4() != nil:
- return NewRouteDistinguisherIPAddressAS(elems[1], uint16(assigned)), nil
- case elems[6] == "" && elems[7] == "":
- asn, _ := strconv.ParseUint(elems[8], 10, 16)
- return NewRouteDistinguisherTwoOctetAS(uint16(asn), uint32(assigned)), nil
- default:
- fst, _ := strconv.ParseUint(elems[7], 10, 16)
- snd, _ := strconv.ParseUint(elems[8], 10, 16)
- asn := fst<<16 | snd
- return NewRouteDistinguisherFourOctetAS(uint32(asn), uint16(assigned)), nil
- }
-}
-
-//
-// RFC3107 Carrying Label Information in BGP-4
-//
-// 3. Carrying Label Mapping Information
-//
-// b) Label:
-//
-// The Label field carries one or more labels (that corresponds to
-// the stack of labels [MPLS-ENCAPS(RFC3032)]). Each label is encoded as
-// 4 octets, where the high-order 20 bits contain the label value, and
-// the low order bit contains "Bottom of Stack"
-//
-// RFC3032 MPLS Label Stack Encoding
-//
-// 2.1. Encoding the Label Stack
-//
-// 0 1 2 3
-// 0 ... 9 0 ... 9 0 1 2 3 4 ... 9 0 1
-// +-----+-+-+---+-+-+-+-+-+-----+-+-+-+
-// | Label | Exp |S| TTL |
-// +-----+-+-+---+-+-+-+-+-+-----+-+-+-+
-//
-
-// RFC3107 Carrying Label Information in BGP-4
-//
-// 3. Carrying Label Mapping Information
-//
-// The label information carried (as part of NLRI) in the Withdrawn
-// Routes field should be set to 0x800000.
-const WITHDRAW_LABEL = uint32(0x800000)
-const ZERO_LABEL = uint32(0) // some platform uses this as withdraw label
-
-type MPLSLabelStack struct {
- Labels []uint32
-}
-
-func (l *MPLSLabelStack) DecodeFromBytes(data []byte) error {
- labels := []uint32{}
- foundBottom := false
- for len(data) >= 3 {
- label := uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
- if label == WITHDRAW_LABEL || label == ZERO_LABEL {
- l.Labels = []uint32{label}
- return nil
- }
- data = data[3:]
- labels = append(labels, label>>4)
- if label&1 == 1 {
- foundBottom = true
- break
- }
- }
-
- if !foundBottom {
- l.Labels = []uint32{}
- return nil
- }
- l.Labels = labels
- return nil
-}
-
-func (l *MPLSLabelStack) Serialize() ([]byte, error) {
- buf := make([]byte, len(l.Labels)*3)
- for i, label := range l.Labels {
- if label == WITHDRAW_LABEL {
- return []byte{128, 0, 0}, nil
- }
- label = label << 4
- buf[i*3] = byte((label >> 16) & 0xff)
- buf[i*3+1] = byte((label >> 8) & 0xff)
- buf[i*3+2] = byte(label & 0xff)
- }
- buf[len(buf)-1] |= 1
- return buf, nil
-}
-
-func (l *MPLSLabelStack) Len() int { return 3 * len(l.Labels) }
-
-func (l *MPLSLabelStack) String() string {
- if len(l.Labels) == 0 {
- return ""
- }
- s := bytes.NewBuffer(make([]byte, 0, 64))
- s.WriteString("[")
- ss := make([]string, 0, len(l.Labels))
- for _, label := range l.Labels {
- ss = append(ss, fmt.Sprintf("%d", label))
- }
- s.WriteString(strings.Join(ss, ", "))
- s.WriteString("]")
- return s.String()
-}
-
-func NewMPLSLabelStack(labels ...uint32) *MPLSLabelStack {
- if len(labels) == 0 {
- labels = []uint32{0}
- }
- return &MPLSLabelStack{labels}
-}
-
-func ParseMPLSLabelStack(buf string) (*MPLSLabelStack, error) {
- elems := strings.Split(buf, "/")
- labels := make([]uint32, 0, len(elems))
- if len(elems) == 0 {
- goto ERR
- }
- for _, elem := range elems {
- i, err := strconv.ParseUint(elem, 10, 32)
- if err != nil {
- goto ERR
- }
- if i > ((1 << 20) - 1) {
- goto ERR
- }
- labels = append(labels, uint32(i))
- }
- return NewMPLSLabelStack(labels...), nil
-ERR:
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "invalid mpls label stack format")
-}
-
-//
-// RFC3107 Carrying Label Information in BGP-4
-//
-// 3. Carrying Label Mapping Information
-//
-// +----------------------+
-// | Length (1 octet) |
-// +----------------------+
-// | Label (3 octets) |
-// +----------------------+
-// .......................
-// +----------------------+
-// | Prefix (variable) |
-// +----------------------+
-//
-// RFC4364 BGP/MPLS IP VPNs
-//
-// 4.3.4. How VPN-IPv4 NLRI Is Carried in BGP
-//
-// The labeled VPN-IPv4 NLRI itself is encoded as specified in
-// [MPLS-BGP(RFC3107)], where the prefix consists of an 8-byte RD
-// followed by an IPv4 prefix.
-//
-
-type LabeledVPNIPAddrPrefix struct {
- IPAddrPrefixDefault
- Labels MPLSLabelStack
- RD RouteDistinguisherInterface
- addrlen uint8
-}
-
-func (l *LabeledVPNIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- f := RF_IPv4_VPN
- if l.addrlen == 16 {
- f = RF_IPv6_VPN
- }
- if IsAddPathEnabled(true, f, options) {
- var err error
- data, err = l.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- if len(data) < 1 {
- return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field")
- }
- l.Length = uint8(data[0])
- data = data[1:]
- l.Labels.DecodeFromBytes(data)
- if int(l.Length)-8*(l.Labels.Len()) < 0 {
- l.Labels.Labels = []uint32{}
- }
- data = data[l.Labels.Len():]
- l.RD = GetRouteDistinguisher(data)
- data = data[l.RD.Len():]
- restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len())
- return l.decodePrefix(data, uint8(restbits), l.addrlen)
-}
-
-func (l *LabeledVPNIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- f := RF_IPv4_VPN
- if l.addrlen == 16 {
- f = RF_IPv6_VPN
- }
- var buf []byte
- if IsAddPathEnabled(false, f, options) {
- var err error
- buf, err = l.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- }
- buf = append(buf, l.Length)
- lbuf, err := l.Labels.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, lbuf...)
- rbuf, err := l.RD.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, rbuf...)
- restbits := int(l.Length) - 8*(l.Labels.Len()+l.RD.Len())
- pbuf, err := l.serializePrefix(uint8(restbits))
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- return buf, nil
-}
-
-func (l *LabeledVPNIPAddrPrefix) AFI() uint16 {
- return AFI_IP
-}
-
-func (l *LabeledVPNIPAddrPrefix) SAFI() uint8 {
- return SAFI_MPLS_VPN
-}
-
-func (l *LabeledVPNIPAddrPrefix) IPPrefixLen() uint8 {
- return l.Length - 8*uint8(l.Labels.Len()+l.RD.Len())
-}
-
-func (l *LabeledVPNIPAddrPrefix) Len(options ...*MarshallingOption) int {
- return 1 + l.Labels.Len() + l.RD.Len() + int((l.IPPrefixLen()+7)/8)
-}
-
-func (l *LabeledVPNIPAddrPrefix) String() string {
- return fmt.Sprintf("%s:%s", l.RD, l.IPPrefix())
-}
-
-func (l *LabeledVPNIPAddrPrefix) IPPrefix() string {
- masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len()))
- return fmt.Sprintf("%s/%d", l.IPAddrPrefixDefault.Prefix, masklen)
-}
-
-func (l *LabeledVPNIPAddrPrefix) MarshalJSON() ([]byte, error) {
- masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len()))
- return json.Marshal(struct {
- Prefix string `json:"prefix"`
- Labels []uint32 `json:"labels"`
- RD RouteDistinguisherInterface `json:"rd"`
- }{
- Prefix: fmt.Sprintf("%s/%d", l.IPAddrPrefixDefault.Prefix, masklen),
- Labels: l.Labels.Labels,
- RD: l.RD,
- })
-}
-
-func NewLabeledVPNIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack, rd RouteDistinguisherInterface) *LabeledVPNIPAddrPrefix {
- rdlen := 0
- if rd != nil {
- rdlen = rd.Len()
- }
- return &LabeledVPNIPAddrPrefix{
- IPAddrPrefixDefault{
- Length: length + uint8(8*(label.Len()+rdlen)),
- Prefix: net.ParseIP(prefix).To4(),
- },
- label,
- rd,
- 4,
- }
-}
-
-type LabeledVPNIPv6AddrPrefix struct {
- LabeledVPNIPAddrPrefix
-}
-
-func (l *LabeledVPNIPv6AddrPrefix) AFI() uint16 {
- return AFI_IP6
-}
-
-func NewLabeledVPNIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack, rd RouteDistinguisherInterface) *LabeledVPNIPv6AddrPrefix {
- rdlen := 0
- if rd != nil {
- rdlen = rd.Len()
- }
- return &LabeledVPNIPv6AddrPrefix{
- LabeledVPNIPAddrPrefix{
- IPAddrPrefixDefault{
- Length: length + uint8(8*(label.Len()+rdlen)),
- Prefix: net.ParseIP(prefix),
- },
- label,
- rd,
- 16,
- },
- }
-}
-
-type LabeledIPAddrPrefix struct {
- IPAddrPrefixDefault
- Labels MPLSLabelStack
- addrlen uint8
-}
-
-func (r *LabeledIPAddrPrefix) AFI() uint16 {
- return AFI_IP
-}
-
-func (r *LabeledIPAddrPrefix) SAFI() uint8 {
- return SAFI_MPLS_LABEL
-}
-
-func (l *LabeledIPAddrPrefix) IPPrefixLen() uint8 {
- return l.Length - 8*uint8(l.Labels.Len())
-}
-
-func (l *LabeledIPAddrPrefix) Len(options ...*MarshallingOption) int {
- return 1 + l.Labels.Len() + int((l.IPPrefixLen()+7)/8)
-}
-
-func (l *LabeledIPAddrPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- f := RF_IPv4_MPLS
- if l.addrlen == 16 {
- f = RF_IPv6_MPLS
- }
- if IsAddPathEnabled(true, f, options) {
- var err error
- data, err = l.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- l.Length = uint8(data[0])
- data = data[1:]
- l.Labels.DecodeFromBytes(data)
-
- if int(l.Length)-8*(l.Labels.Len()) < 0 {
- l.Labels.Labels = []uint32{}
- }
- restbits := int(l.Length) - 8*(l.Labels.Len())
- data = data[l.Labels.Len():]
- return l.decodePrefix(data, uint8(restbits), l.addrlen)
-}
-
-func (l *LabeledIPAddrPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- f := RF_IPv4_MPLS
- if l.addrlen == 16 {
- f = RF_IPv6_MPLS
- }
- var buf []byte
- if IsAddPathEnabled(false, f, options) {
- var err error
- buf, err = l.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- }
- buf = append(buf, l.Length)
- restbits := int(l.Length) - 8*(l.Labels.Len())
- lbuf, err := l.Labels.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, lbuf...)
- pbuf, err := l.serializePrefix(uint8(restbits))
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- return buf, nil
-}
-
-func (l *LabeledIPAddrPrefix) String() string {
- prefix := l.Prefix.String()
- if isIPv4MappedIPv6(l.Prefix) {
- prefix = "::ffff:" + prefix
- }
- return fmt.Sprintf("%s/%d", prefix, int(l.Length)-l.Labels.Len()*8)
-}
-
-func (l *LabeledIPAddrPrefix) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Prefix string `json:"prefix"`
- Labels []uint32 `json:"labels"`
- }{
- Prefix: l.String(),
- Labels: l.Labels.Labels,
- })
-}
-
-func NewLabeledIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPAddrPrefix {
- return &LabeledIPAddrPrefix{
- IPAddrPrefixDefault{
- Length: length + uint8(label.Len()*8),
- Prefix: net.ParseIP(prefix).To4(),
- },
- label,
- 4,
- }
-}
-
-type LabeledIPv6AddrPrefix struct {
- LabeledIPAddrPrefix
-}
-
-func (l *LabeledIPv6AddrPrefix) AFI() uint16 {
- return AFI_IP6
-}
-
-func NewLabeledIPv6AddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPv6AddrPrefix {
- return &LabeledIPv6AddrPrefix{
- LabeledIPAddrPrefix{
- IPAddrPrefixDefault{
- Length: length + uint8(label.Len()*8),
- Prefix: net.ParseIP(prefix),
- },
- label,
- 16,
- },
- }
-}
-
-type RouteTargetMembershipNLRI struct {
- PrefixDefault
- Length uint8
- AS uint32
- RouteTarget ExtendedCommunityInterface
-}
-
-func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if IsAddPathEnabled(true, RF_RTC_UC, options) {
- var err error
- data, err = n.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- if len(data) < 1 {
- return NewMessageError(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), nil, "prefix misses length field")
- }
- n.Length = data[0]
- data = data[1 : n.Length/8+1]
- if len(data) == 0 {
- return nil
- } else if len(data) != 12 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all RouteTargetMembershipNLRI bytes available")
- }
- n.AS = binary.BigEndian.Uint32(data[0:4])
- rt, err := ParseExtended(data[4:])
- n.RouteTarget = rt
- if err != nil {
- return err
- }
- return nil
-}
-
-func (n *RouteTargetMembershipNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- var buf []byte
- if IsAddPathEnabled(false, RF_RTC_UC, options) {
- var err error
- buf, err = n.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- }
- if n.RouteTarget == nil {
- return append(buf, 0), nil
- }
- offset := len(buf)
- buf = append(buf, make([]byte, 5)...)
- buf[offset] = 96
- binary.BigEndian.PutUint32(buf[offset+1:], n.AS)
- ebuf, err := n.RouteTarget.Serialize()
- if err != nil {
- return nil, err
- }
- return append(buf, ebuf...), nil
-}
-
-func (n *RouteTargetMembershipNLRI) AFI() uint16 {
- return AFI_IP
-}
-
-func (n *RouteTargetMembershipNLRI) SAFI() uint8 {
- return SAFI_ROUTE_TARGET_CONSTRAINTS
-}
-
-func (n *RouteTargetMembershipNLRI) Len(options ...*MarshallingOption) int {
- if n.AS == 0 && n.RouteTarget == nil {
- return 1
- }
- return 13
-}
-
-func (n *RouteTargetMembershipNLRI) String() string {
- target := "default"
- if n.RouteTarget != nil {
- target = n.RouteTarget.String()
- }
- return fmt.Sprintf("%d:%s", n.AS, target)
-}
-
-func (n *RouteTargetMembershipNLRI) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Prefix string `json:"prefix"`
- }{
- Prefix: n.String(),
- })
-}
-
-func NewRouteTargetMembershipNLRI(as uint32, target ExtendedCommunityInterface) *RouteTargetMembershipNLRI {
- l := 12 * 8
- if as == 0 && target == nil {
- l = 1
- }
- return &RouteTargetMembershipNLRI{
- Length: uint8(l),
- AS: as,
- RouteTarget: target,
- }
-}
-
-type ESIType uint8
-
-const (
- ESI_ARBITRARY ESIType = iota
- ESI_LACP
- ESI_MSTP
- ESI_MAC
- ESI_ROUTERID
- ESI_AS
-)
-
-type EthernetSegmentIdentifier struct {
- Type ESIType
- Value []byte
-}
-
-func (esi *EthernetSegmentIdentifier) DecodeFromBytes(data []byte) error {
- esi.Type = ESIType(data[0])
- esi.Value = data[1:10]
- switch esi.Type {
- case ESI_LACP, ESI_MSTP, ESI_ROUTERID, ESI_AS:
- if esi.Value[8] != 0x00 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid %s. last octet must be 0x00 (0x%02x)", esi.Type.String(), esi.Value[8]))
- }
- }
- return nil
-}
-
-func (esi *EthernetSegmentIdentifier) Serialize() ([]byte, error) {
- buf := make([]byte, 10)
- buf[0] = uint8(esi.Type)
- copy(buf[1:], esi.Value)
- return buf, nil
-}
-
-func isZeroBuf(buf []byte) bool {
- for _, b := range buf {
- if b != 0 {
- return false
- }
- }
- return true
-}
-
-func (esi *EthernetSegmentIdentifier) String() string {
- toHexArray := func(data []byte) string {
- // Converts byte slice into the colon separated hex values and the
- // number of elements are 9 at most (excluding Type field).
- values := make([]string, 0, 9)
- for _, v := range data {
- values = append(values, fmt.Sprintf("%02x", v))
- }
- return strings.Join(values, ":")
- }
-
- s := bytes.NewBuffer(make([]byte, 0, 64))
- s.WriteString(fmt.Sprintf("%s | ", esi.Type.String()))
- switch esi.Type {
- case ESI_LACP:
- s.WriteString(fmt.Sprintf("system mac %s, ", net.HardwareAddr(esi.Value[:6]).String()))
- s.WriteString(fmt.Sprintf("port key %d", binary.BigEndian.Uint16(esi.Value[6:8])))
- case ESI_MSTP:
- s.WriteString(fmt.Sprintf("bridge mac %s, ", net.HardwareAddr(esi.Value[:6]).String()))
- s.WriteString(fmt.Sprintf("priority %d", binary.BigEndian.Uint16(esi.Value[6:8])))
- case ESI_MAC:
- s.WriteString(fmt.Sprintf("system mac %s, ", net.HardwareAddr(esi.Value[:6]).String()))
- s.WriteString(fmt.Sprintf("local discriminator %d", uint32(esi.Value[6])<<16|uint32(esi.Value[7])<<8|uint32(esi.Value[8])))
- case ESI_ROUTERID:
- s.WriteString(fmt.Sprintf("router id %s, ", net.IP(esi.Value[:4])))
- s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8])))
- case ESI_AS:
- s.WriteString(fmt.Sprintf("as %d, ", binary.BigEndian.Uint32(esi.Value[:4])))
- s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8])))
- case ESI_ARBITRARY:
- if isZeroBuf(esi.Value) {
- return "single-homed"
- }
- fallthrough
- default:
- s.WriteString(toHexArray(esi.Value))
- }
- return s.String()
-}
-
-// Decode Ethernet Segment Identifier (ESI) from string slice.
-//
-// The first element of args should be the Type field (e.g., "ARBITRARY",
-// "arbitrary", "ESI_ARBITRARY" or "esi_arbitrary") and "single-homed" is
-// the special keyword for all zeroed ESI.
-// For the "ARBITRARY" Value field (Type 0), it should be the colon separated
-// hex values and the number of elements should be 9 at most.
-// e.g.) args := []string{"ARBITRARY", "11:22:33:44:55:66:77:88:99"}
-// For the other types, the Value field format is the similar to the string
-// format of ESI.
-// e.g.) args := []string{"lacp", "aa:bb:cc:dd:ee:ff", "100"}
-func ParseEthernetSegmentIdentifier(args []string) (EthernetSegmentIdentifier, error) {
- esi := EthernetSegmentIdentifier{}
- argLen := len(args)
- if argLen == 0 || args[0] == "single-homed" {
- return esi, nil
- }
-
- typeStr := strings.TrimPrefix(strings.ToUpper(args[0]), "ESI_")
- switch typeStr {
- case "ARBITRARY":
- esi.Type = ESI_ARBITRARY
- case "LACP":
- esi.Type = ESI_LACP
- case "MSTP":
- esi.Type = ESI_MSTP
- case "MAC":
- esi.Type = ESI_MAC
- case "ROUTERID":
- esi.Type = ESI_ROUTERID
- case "AS":
- esi.Type = ESI_AS
- default:
- typ, err := strconv.ParseUint(args[0], 10, 8)
- if err != nil {
- return esi, fmt.Errorf("invalid esi type: %s", args[0])
- }
- esi.Type = ESIType(typ)
- }
-
- invalidEsiValuesError := fmt.Errorf("invalid esi values for type %s: %s", esi.Type.String(), args[1:])
- esi.Value = make([]byte, 9)
- switch esi.Type {
- case ESI_LACP:
- fallthrough
- case ESI_MSTP:
- if argLen < 3 {
- return esi, invalidEsiValuesError
- }
- // MAC
- mac, err := net.ParseMAC(args[1])
- if err != nil {
- return esi, invalidEsiValuesError
- }
- copy(esi.Value[0:6], mac)
- // Port Key or Bridge Priority
- i, err := strconv.ParseUint(args[2], 10, 16)
- if err != nil {
- return esi, invalidEsiValuesError
- }
- binary.BigEndian.PutUint16(esi.Value[6:8], uint16(i))
- case ESI_MAC:
- if argLen < 3 {
- return esi, invalidEsiValuesError
- }
- // MAC
- mac, err := net.ParseMAC(args[1])
- if err != nil {
- return esi, invalidEsiValuesError
- }
- copy(esi.Value[0:6], mac)
- // Local Discriminator
- i, err := strconv.ParseUint(args[2], 10, 32)
- if err != nil {
- return esi, invalidEsiValuesError
- }
- iBuf := make([]byte, 4)
- binary.BigEndian.PutUint32(iBuf, uint32(i))
- copy(esi.Value[6:9], iBuf[1:4])
- case ESI_ROUTERID:
- if argLen < 3 {
- return esi, invalidEsiValuesError
- }
- // Router ID
- ip := net.ParseIP(args[1])
- if ip == nil || ip.To4() == nil {
- return esi, invalidEsiValuesError
- }
- copy(esi.Value[0:4], ip.To4())
- // Local Discriminator
- i, err := strconv.ParseUint(args[2], 10, 32)
- if err != nil {
- return esi, invalidEsiValuesError
- }
- binary.BigEndian.PutUint32(esi.Value[4:8], uint32(i))
- case ESI_AS:
- if argLen < 3 {
- return esi, invalidEsiValuesError
- }
- // AS
- as, err := strconv.ParseUint(args[1], 10, 32)
- if err != nil {
- return esi, invalidEsiValuesError
- }
- binary.BigEndian.PutUint32(esi.Value[0:4], uint32(as))
- // Local Discriminator
- i, err := strconv.ParseUint(args[2], 10, 32)
- if err != nil {
- return esi, invalidEsiValuesError
- }
- binary.BigEndian.PutUint32(esi.Value[4:8], uint32(i))
- case ESI_ARBITRARY:
- fallthrough
- default:
- if argLen < 2 {
- // Assumes the Value field is omitted
- break
- }
- values := make([]byte, 0, 9)
- for _, e := range strings.SplitN(args[1], ":", 9) {
- v, err := strconv.ParseUint(e, 16, 16)
- if err != nil {
- return esi, invalidEsiValuesError
- }
- values = append(values, byte(v))
- }
- copy(esi.Value, values)
- }
-
- return esi, nil
-}
-
-//
-// I-D bess-evpn-overlay-01
-//
-// 5.1.3 Constructing EVPN BGP Routes
-//
-// For the balance of this memo, the MPLS label field will be
-// referred to as the VNI/VSID field. The VNI/VSID field is used for
-// both local and global VNIs/VSIDs, and for either case the entire 24-
-// bit field is used to encode the VNI/VSID value.
-//
-// We can't use type MPLSLabelStack for EVPN NLRI, because EVPN NLRI's MPLS
-// field can be filled with VXLAN VNI. In that case, we must avoid modifying
-// bottom of stack bit.
-//
-
-func labelDecode(data []byte) (uint32, error) {
- if len(data) < 3 {
- return 0, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all Label bytes available")
- }
- return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2]), nil
-}
-
-func labelSerialize(label uint32) ([]byte, error) {
- if label > 0xffffff {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Out of range Label: %d", label))
- }
- buf := make([]byte, 3)
- buf[0] = byte((label >> 16) & 0xff)
- buf[1] = byte((label >> 8) & 0xff)
- buf[2] = byte(label & 0xff)
- return buf, nil
-}
-
-type EVPNEthernetAutoDiscoveryRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- ETag uint32
- Label uint32
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) Len() int {
- // RD(8) + ESI(10) + ETag(4) + Label(3)
- return 25
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) DecodeFromBytes(data []byte) error {
- er.RD = GetRouteDistinguisher(data)
- data = data[er.RD.Len():]
- err := er.ESI.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- data = data[10:]
- er.ETag = binary.BigEndian.Uint32(data[0:4])
- data = data[4:]
- if er.Label, err = labelDecode(data); err != nil {
- return err
- }
- return nil
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) Serialize() ([]byte, error) {
- var buf []byte
- var err error
- if er.RD != nil {
- buf, err = er.RD.Serialize()
- if err != nil {
- return nil, err
- }
- } else {
- buf = make([]byte, 8)
- }
- tbuf, err := er.ESI.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
-
- tbuf = make([]byte, 4)
- binary.BigEndian.PutUint32(tbuf, er.ETag)
- buf = append(buf, tbuf...)
-
- tbuf, err = labelSerialize(er.Label)
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
-
- return buf, nil
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) String() string {
- // RFC7432: BGP MPLS-Based Ethernet VPN
- // 7.1. Ethernet Auto-discovery Route
- // For the purpose of BGP route key processing, only the Ethernet
- // Segment Identifier and the Ethernet Tag ID are considered to be part
- // of the prefix in the NLRI. The MPLS Label field is to be treated as
- // a route attribute as opposed to being part of the route.
- return fmt.Sprintf("[type:A-D][rd:%s][esi:%s][etag:%d]", er.RD, er.ESI.String(), er.ETag)
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RD RouteDistinguisherInterface `json:"rd"`
- ESI string `json:"esi"`
- Etag uint32 `json:"etag"`
- Label uint32 `json:"label"`
- }{
- RD: er.RD,
- ESI: er.ESI.String(),
- Etag: er.ETag,
- Label: er.Label,
- })
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) rd() RouteDistinguisherInterface {
- return er.RD
-}
-
-func NewEVPNEthernetAutoDiscoveryRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, label uint32) *EVPNNLRI {
- return NewEVPNNLRI(EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY, &EVPNEthernetAutoDiscoveryRoute{
- RD: rd,
- ESI: esi,
- ETag: etag,
- Label: label,
- })
-}
-
-type EVPNMacIPAdvertisementRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- ETag uint32
- MacAddressLength uint8
- MacAddress net.HardwareAddr
- IPAddressLength uint8
- IPAddress net.IP
- Labels []uint32
-}
-
-func (er *EVPNMacIPAdvertisementRoute) Len() int {
- // RD(8) + ESI(10) + ETag(4) + MacAddressLength(1) + MacAddress(6)
- // + IPAddressLength(1) + IPAddress(0, 4 or 16) + Labels(3 or 6)
- return 30 + int(er.IPAddressLength)/8 + len(er.Labels)*3
-}
-
-func (er *EVPNMacIPAdvertisementRoute) DecodeFromBytes(data []byte) error {
- er.RD = GetRouteDistinguisher(data)
- data = data[er.RD.Len():]
- err := er.ESI.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- data = data[10:]
- er.ETag = binary.BigEndian.Uint32(data[0:4])
- data = data[4:]
- er.MacAddressLength = data[0]
- er.MacAddress = net.HardwareAddr(data[1:7])
- er.IPAddressLength = data[7]
- data = data[8:]
- if er.IPAddressLength == 32 || er.IPAddressLength == 128 {
- er.IPAddress = net.IP(data[0:((er.IPAddressLength) / 8)])
- } else if er.IPAddressLength != 0 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength))
- }
- data = data[(er.IPAddressLength / 8):]
- var label uint32
- if label, err = labelDecode(data); err != nil {
- return err
- }
- er.Labels = append(er.Labels, label)
- data = data[3:]
- if len(data) == 3 {
- if label, err = labelDecode(data); err != nil {
- return err
- }
- er.Labels = append(er.Labels, label)
- }
- return nil
-}
-
-func (er *EVPNMacIPAdvertisementRoute) Serialize() ([]byte, error) {
- var buf []byte
- var err error
- if er.RD != nil {
- buf, err = er.RD.Serialize()
- if err != nil {
- return nil, err
- }
- } else {
- buf = make([]byte, 8)
- }
-
- tbuf, err := er.ESI.Serialize()
- if err != nil {
- return nil, err
- }
-
- buf = append(buf, tbuf...)
- tbuf = make([]byte, 4)
- binary.BigEndian.PutUint32(tbuf, er.ETag)
- buf = append(buf, tbuf...)
- tbuf = make([]byte, 7)
- tbuf[0] = er.MacAddressLength
- copy(tbuf[1:], er.MacAddress)
- buf = append(buf, tbuf...)
-
- buf = append(buf, er.IPAddressLength)
- switch er.IPAddressLength {
- case 0:
- // IP address omitted
- case 32:
- buf = append(buf, []byte(er.IPAddress.To4())...)
- case 128:
- buf = append(buf, []byte(er.IPAddress.To16())...)
- default:
- return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength)
- }
-
- for _, l := range er.Labels {
- tbuf, err = labelSerialize(l)
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
- }
- return buf, nil
-}
-
-func (er *EVPNMacIPAdvertisementRoute) String() string {
- // RFC7432: BGP MPLS-Based Ethernet VPN
- // 7.2. MAC/IP Advertisement Route
- // For the purpose of BGP route key processing, only the Ethernet Tag
- // ID, MAC Address Length, MAC Address, IP Address Length, and IP
- // Address fields are considered to be part of the prefix in the NLRI.
- // The Ethernet Segment Identifier, MPLS Label1, and MPLS Label2 fields
- // are to be treated as route attributes as opposed to being part of the
- // "route".
- return fmt.Sprintf("[type:macadv][rd:%s][etag:%d][mac:%s][ip:%s]", er.RD, er.ETag, er.MacAddress, er.IPAddress)
-}
-
-func (er *EVPNMacIPAdvertisementRoute) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RD RouteDistinguisherInterface `json:"rd"`
- ESI string `json:"esi"`
- Etag uint32 `json:"etag"`
- MacAddress string `json:"mac"`
- IPAddress string `json:"ip"`
- Labels []uint32 `json:"labels"`
- }{
- RD: er.RD,
- ESI: er.ESI.String(),
- Etag: er.ETag,
- MacAddress: er.MacAddress.String(),
- IPAddress: er.IPAddress.String(),
- Labels: er.Labels,
- })
-}
-
-func (er *EVPNMacIPAdvertisementRoute) rd() RouteDistinguisherInterface {
- return er.RD
-}
-
-func NewEVPNMacIPAdvertisementRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, macAddress string, ipAddress string, labels []uint32) *EVPNNLRI {
- mac, _ := net.ParseMAC(macAddress)
- var ipLen uint8
- ip := net.ParseIP(ipAddress)
- if ip != nil {
- if ipv4 := ip.To4(); ipv4 != nil {
- ipLen = 32
- ip = ipv4
- } else {
- ipLen = 128
- }
- }
- return NewEVPNNLRI(EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT, &EVPNMacIPAdvertisementRoute{
- RD: rd,
- ESI: esi,
- ETag: etag,
- MacAddressLength: 6,
- MacAddress: mac,
- IPAddressLength: ipLen,
- IPAddress: ip,
- Labels: labels,
- })
-}
-
-type EVPNMulticastEthernetTagRoute struct {
- RD RouteDistinguisherInterface
- ETag uint32
- IPAddressLength uint8
- IPAddress net.IP
-}
-
-func (er *EVPNMulticastEthernetTagRoute) Len() int {
- // RD(8) + ETag(4) + IPAddressLength(1) + IPAddress(4 or 16)
- return 13 + int(er.IPAddressLength)/8
-}
-
-func (er *EVPNMulticastEthernetTagRoute) DecodeFromBytes(data []byte) error {
- er.RD = GetRouteDistinguisher(data)
- data = data[er.RD.Len():]
- er.ETag = binary.BigEndian.Uint32(data[0:4])
- er.IPAddressLength = data[4]
- data = data[5:]
- if er.IPAddressLength == 32 || er.IPAddressLength == 128 {
- er.IPAddress = net.IP(data[:er.IPAddressLength/8])
- } else {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength))
- }
- return nil
-}
-
-func (er *EVPNMulticastEthernetTagRoute) Serialize() ([]byte, error) {
- var buf []byte
- var err error
- if er.RD != nil {
- buf, err = er.RD.Serialize()
- if err != nil {
- return nil, err
- }
- } else {
- buf = make([]byte, 8)
- }
- tbuf := make([]byte, 4)
- binary.BigEndian.PutUint32(tbuf, er.ETag)
- buf = append(buf, tbuf...)
- buf = append(buf, er.IPAddressLength)
- switch er.IPAddressLength {
- case 32:
- buf = append(buf, []byte(er.IPAddress.To4())...)
- case 128:
- buf = append(buf, []byte(er.IPAddress.To16())...)
- default:
- return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength)
- }
- if err != nil {
- return nil, err
- }
- return buf, nil
-}
-
-func (er *EVPNMulticastEthernetTagRoute) String() string {
- // RFC7432: BGP MPLS-Based Ethernet VPN
- // 7.3. Inclusive Multicast Ethernet Tag Route
- // ...(snip)... For the purpose of BGP route key
- // processing, only the Ethernet Tag ID, IP Address Length, and
- // Originating Router's IP Address fields are considered to be part of
- // the prefix in the NLRI.
- return fmt.Sprintf("[type:multicast][rd:%s][etag:%d][ip:%s]", er.RD, er.ETag, er.IPAddress)
-}
-
-func (er *EVPNMulticastEthernetTagRoute) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RD RouteDistinguisherInterface `json:"rd"`
- Etag uint32 `json:"etag"`
- IPAddress string `json:"ip"`
- }{
- RD: er.RD,
- Etag: er.ETag,
- IPAddress: er.IPAddress.String(),
- })
-}
-
-func (er *EVPNMulticastEthernetTagRoute) rd() RouteDistinguisherInterface {
- return er.RD
-}
-
-func NewEVPNMulticastEthernetTagRoute(rd RouteDistinguisherInterface, etag uint32, ipAddress string) *EVPNNLRI {
- ipLen := uint8(32)
- ip := net.ParseIP(ipAddress)
- if ipv4 := ip.To4(); ipv4 != nil {
- ip = ipv4
- } else {
- ipLen = 128
- }
- return NewEVPNNLRI(EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG, &EVPNMulticastEthernetTagRoute{
- RD: rd,
- ETag: etag,
- IPAddressLength: ipLen,
- IPAddress: ip,
- })
-}
-
-type EVPNEthernetSegmentRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- IPAddressLength uint8
- IPAddress net.IP
-}
-
-func (er *EVPNEthernetSegmentRoute) Len() int {
- // RD(8) + ESI(10) + IPAddressLength(1) + IPAddress(4 or 16)
- return 19 + int(er.IPAddressLength)/8
-}
-
-func (er *EVPNEthernetSegmentRoute) DecodeFromBytes(data []byte) error {
- er.RD = GetRouteDistinguisher(data)
- data = data[er.RD.Len():]
- er.ESI.DecodeFromBytes(data)
- data = data[10:]
- er.IPAddressLength = data[0]
- data = data[1:]
- if er.IPAddressLength == 32 || er.IPAddressLength == 128 {
- er.IPAddress = net.IP(data[:er.IPAddressLength/8])
- } else {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid IP address length: %d", er.IPAddressLength))
- }
- return nil
-}
-
-func (er *EVPNEthernetSegmentRoute) Serialize() ([]byte, error) {
- var buf []byte
- var err error
- if er.RD != nil {
- buf, err = er.RD.Serialize()
- if err != nil {
- return nil, err
- }
- } else {
- buf = make([]byte, 8)
- }
- tbuf, err := er.ESI.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
- buf = append(buf, er.IPAddressLength)
- switch er.IPAddressLength {
- case 32:
- buf = append(buf, []byte(er.IPAddress.To4())...)
- case 128:
- buf = append(buf, []byte(er.IPAddress.To16())...)
- default:
- return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength)
- }
- return buf, nil
-}
-
-func (er *EVPNEthernetSegmentRoute) String() string {
- // RFC7432: BGP MPLS-Based Ethernet VPN
- // 7.4. Ethernet Segment Route
- // For the purpose of BGP route key processing, only the Ethernet
- // Segment ID, IP Address Length, and Originating Router's IP Address
- // fields are considered to be part of the prefix in the NLRI.
- return fmt.Sprintf("[type:esi][rd:%s][esi:%s][ip:%s]", er.RD, er.ESI.String(), er.IPAddress)
-}
-
-func (er *EVPNEthernetSegmentRoute) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RD RouteDistinguisherInterface `json:"rd"`
- ESI string `json:"esi"`
- IPAddress string `json:"ip"`
- }{
- RD: er.RD,
- ESI: er.ESI.String(),
- IPAddress: er.IPAddress.String(),
- })
-}
-
-func (er *EVPNEthernetSegmentRoute) rd() RouteDistinguisherInterface {
- return er.RD
-}
-
-func NewEVPNEthernetSegmentRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, ipAddress string) *EVPNNLRI {
- ipLen := uint8(32)
- ip := net.ParseIP(ipAddress)
- if ipv4 := ip.To4(); ipv4 != nil {
- ip = ipv4
- } else {
- ipLen = 128
- }
- return NewEVPNNLRI(EVPN_ETHERNET_SEGMENT_ROUTE, &EVPNEthernetSegmentRoute{
- RD: rd,
- ESI: esi,
- IPAddressLength: ipLen,
- IPAddress: ip,
- })
-}
-
-type EVPNIPPrefixRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- ETag uint32
- IPPrefixLength uint8
- IPPrefix net.IP
- GWIPAddress net.IP
- Label uint32
-}
-
-func (er *EVPNIPPrefixRoute) Len() int {
- if er.IPPrefix.To4() != nil {
- return 34
- }
- return 58
-}
-
-func (er *EVPNIPPrefixRoute) DecodeFromBytes(data []byte) error {
- addrLen := net.IPv4len
- switch len(data) {
- case 34:
- // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) + IPv4 Prefix(4) + GW IPv4(4) + Label(3)
- case 58:
- // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1) + IPv6 Prefix(16) + GW IPv6(16) + Label(3)
- addrLen = net.IPv6len
- default:
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPN IP Prefix Route bytes available")
- }
-
- er.RD = GetRouteDistinguisher(data[0:8])
-
- err := er.ESI.DecodeFromBytes(data[8:18])
- if err != nil {
- return err
- }
-
- er.ETag = binary.BigEndian.Uint32(data[18:22])
-
- er.IPPrefixLength = data[22]
-
- offset := 23 // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1)
- er.IPPrefix = data[offset : offset+addrLen]
- offset += addrLen
-
- er.GWIPAddress = data[offset : offset+addrLen]
- offset += addrLen
-
- if er.Label, err = labelDecode(data[offset : offset+3]); err != nil {
- return err
- }
- //offset += 3
-
- return nil
-}
-
-func (er *EVPNIPPrefixRoute) Serialize() ([]byte, error) {
- buf := make([]byte, 23) // RD(8) + ESI(10) + ETag(4) + IPPrefixLength(1)
-
- if er.RD != nil {
- tbuf, err := er.RD.Serialize()
- if err != nil {
- return nil, err
- }
- copy(buf[0:8], tbuf)
- }
-
- tbuf, err := er.ESI.Serialize()
- if err != nil {
- return nil, err
- }
- copy(buf[8:18], tbuf)
-
- binary.BigEndian.PutUint32(buf[18:22], er.ETag)
-
- buf[22] = er.IPPrefixLength
-
- if er.IPPrefix == nil {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("IP Prefix is nil"))
- } else if er.IPPrefix.To4() != nil {
- buf = append(buf, er.IPPrefix.To4()...)
- if er.GWIPAddress == nil {
- // draft-ietf-bess-evpn-prefix-advertisement: IP Prefix Advertisement in EVPN
- // The GW IP field SHOULD be zero if it is not used as an Overlay Index.
- er.GWIPAddress = net.IPv4zero
- }
- buf = append(buf, er.GWIPAddress.To4()...)
- } else {
- buf = append(buf, er.IPPrefix.To16()...)
- if er.GWIPAddress == nil {
- er.GWIPAddress = net.IPv6zero
- }
- buf = append(buf, er.GWIPAddress.To16()...)
- }
-
- tbuf, err = labelSerialize(er.Label)
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
-
- return buf, nil
-}
-
-func (er *EVPNIPPrefixRoute) String() string {
- // draft-ietf-bess-evpn-prefix-advertisement: IP Prefix Advertisement in EVPN
- // 3.1 IP Prefix Route Encoding
- // The RD, Eth-Tag ID, IP Prefix Length and IP Prefix will be part of
- // the route key used by BGP to compare routes. The rest of the fields
- // will not be part of the route key.
- return fmt.Sprintf("[type:Prefix][rd:%s][etag:%d][prefix:%s/%d]", er.RD, er.ETag, er.IPPrefix, er.IPPrefixLength)
-}
-
-func (er *EVPNIPPrefixRoute) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- RD RouteDistinguisherInterface `json:"rd"`
- ESI string `json:"esi"`
- Etag uint32 `json:"etag"`
- Prefix string `json:"prefix"`
- Gateway string `json:"gateway"`
- Label uint32 `json:"label"`
- }{
- RD: er.RD,
- ESI: er.ESI.String(),
- Etag: er.ETag,
- Prefix: fmt.Sprintf("%s/%d", er.IPPrefix, er.IPPrefixLength),
- Gateway: er.GWIPAddress.String(),
- Label: er.Label,
- })
-}
-
-func (er *EVPNIPPrefixRoute) rd() RouteDistinguisherInterface {
- return er.RD
-}
-
-func NewEVPNIPPrefixRoute(rd RouteDistinguisherInterface, esi EthernetSegmentIdentifier, etag uint32, ipPrefixLength uint8, ipPrefix string, gateway string, label uint32) *EVPNNLRI {
- ip := net.ParseIP(ipPrefix)
- gw := net.ParseIP(gateway)
- if ipv4 := ip.To4(); ipv4 != nil {
- ip = ipv4
- gw = gw.To4()
- }
- return NewEVPNNLRI(EVPN_IP_PREFIX, &EVPNIPPrefixRoute{
- RD: rd,
- ESI: esi,
- ETag: etag,
- IPPrefixLength: ipPrefixLength,
- IPPrefix: ip,
- GWIPAddress: gw,
- Label: label,
- })
-}
-
-type EVPNRouteTypeInterface interface {
- Len() int
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
- String() string
- rd() RouteDistinguisherInterface
- MarshalJSON() ([]byte, error)
-}
-
-func getEVPNRouteType(t uint8) (EVPNRouteTypeInterface, error) {
- switch t {
- case EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY:
- return &EVPNEthernetAutoDiscoveryRoute{}, nil
- case EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT:
- return &EVPNMacIPAdvertisementRoute{}, nil
- case EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG:
- return &EVPNMulticastEthernetTagRoute{}, nil
- case EVPN_ETHERNET_SEGMENT_ROUTE:
- return &EVPNEthernetSegmentRoute{}, nil
- case EVPN_IP_PREFIX:
- return &EVPNIPPrefixRoute{}, nil
- }
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Unknown EVPN Route type: %d", t))
-}
-
-const (
- EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY = 1
- EVPN_ROUTE_TYPE_MAC_IP_ADVERTISEMENT = 2
- EVPN_INCLUSIVE_MULTICAST_ETHERNET_TAG = 3
- EVPN_ETHERNET_SEGMENT_ROUTE = 4
- EVPN_IP_PREFIX = 5
-)
-
-type EVPNNLRI struct {
- PrefixDefault
- RouteType uint8
- Length uint8
- RouteTypeData EVPNRouteTypeInterface
-}
-
-func (n *EVPNNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if IsAddPathEnabled(true, RF_EVPN, options) {
- var err error
- data, err = n.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- if len(data) < 2 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI bytes available")
- }
- n.RouteType = data[0]
- n.Length = data[1]
- data = data[2:]
- if len(data) < int(n.Length) {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all EVPNNLRI Route type bytes available")
- }
- r, err := getEVPNRouteType(n.RouteType)
- if err != nil {
- return err
- }
- n.RouteTypeData = r
- return n.RouteTypeData.DecodeFromBytes(data[:n.Length])
-}
-
-func (n *EVPNNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- var buf []byte
- if IsAddPathEnabled(false, RF_EVPN, options) {
- var err error
- buf, err = n.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- }
- offset := len(buf)
- buf = append(buf, make([]byte, 2)...)
- buf[offset] = n.RouteType
- tbuf, err := n.RouteTypeData.Serialize()
- buf[offset+1] = n.Length
- if err != nil {
- return nil, err
- }
- return append(buf, tbuf...), nil
-}
-
-func (n *EVPNNLRI) AFI() uint16 {
- return AFI_L2VPN
-}
-
-func (n *EVPNNLRI) SAFI() uint8 {
- return SAFI_EVPN
-}
-
-func (n *EVPNNLRI) Len(options ...*MarshallingOption) int {
- return int(n.Length) + 2
-}
-
-func (n *EVPNNLRI) String() string {
- if n.RouteTypeData != nil {
- return n.RouteTypeData.String()
- }
- return fmt.Sprintf("%d:%d", n.RouteType, n.Length)
-}
-
-func (n *EVPNNLRI) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint8 `json:"type"`
- Value EVPNRouteTypeInterface `json:"value"`
- }{
- Type: n.RouteType,
- Value: n.RouteTypeData,
- })
-}
-
-func (n *EVPNNLRI) RD() RouteDistinguisherInterface {
- return n.RouteTypeData.rd()
-}
-
-func NewEVPNNLRI(routeType uint8, routeTypeData EVPNRouteTypeInterface) *EVPNNLRI {
- var l uint8
- if routeTypeData != nil {
- l = uint8(routeTypeData.Len())
- }
- return &EVPNNLRI{
- RouteType: routeType,
- Length: l,
- RouteTypeData: routeTypeData,
- }
-}
-
-type EncapNLRI struct {
- IPAddrPrefixDefault
- addrlen uint8
-}
-
-func (n *EncapNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if n.addrlen == 0 {
- n.addrlen = 4
- }
- f := RF_IPv4_ENCAP
- if n.addrlen == 16 {
- f = RF_IPv6_ENCAP
- }
- if IsAddPathEnabled(true, f, options) {
- var err error
- data, err = n.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- if len(data) < 4 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "prefix misses length field")
- }
- n.Length = data[0]
- if n.addrlen == 0 {
- n.addrlen = 4
- }
- return n.decodePrefix(data[1:], n.Length, n.addrlen)
-}
-
-func (n *EncapNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- var buf []byte
- f := RF_IPv4_ENCAP
- if n.addrlen == 16 {
- f = RF_IPv6_ENCAP
- }
- if IsAddPathEnabled(false, f, options) {
- var err error
- buf, err = n.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- }
- if n.Prefix.To4() != nil {
- buf = append(buf, net.IPv4len*8)
- n.Prefix = n.Prefix.To4()
- } else {
- buf = append(buf, net.IPv6len*8)
- }
- n.Length = buf[len(buf)-1]
- pbuf, err := n.serializePrefix(n.Length)
- if err != nil {
- return nil, err
- }
- return append(buf, pbuf...), nil
-}
-
-func (n *EncapNLRI) String() string {
- return n.Prefix.String()
-}
-
-func (n *EncapNLRI) AFI() uint16 {
- return AFI_IP
-}
-
-func (n *EncapNLRI) SAFI() uint8 {
- return SAFI_ENCAPSULATION
-}
-
-func (n *EncapNLRI) Len(options ...*MarshallingOption) int {
- return 1 + len(n.Prefix)
-}
-
-func NewEncapNLRI(endpoint string) *EncapNLRI {
- return &EncapNLRI{
- IPAddrPrefixDefault{Length: 32, Prefix: net.ParseIP(endpoint).To4()},
- 4,
- }
-}
-
-type Encapv6NLRI struct {
- EncapNLRI
-}
-
-func (n *Encapv6NLRI) AFI() uint16 {
- return AFI_IP6
-}
-
-func NewEncapv6NLRI(endpoint string) *Encapv6NLRI {
- return &Encapv6NLRI{
- EncapNLRI{
- IPAddrPrefixDefault{Length: 128, Prefix: net.ParseIP(endpoint)},
- 16,
- },
- }
-}
-
-type BGPFlowSpecType uint8
-
-const (
- FLOW_SPEC_TYPE_UNKNOWN BGPFlowSpecType = iota
- FLOW_SPEC_TYPE_DST_PREFIX
- FLOW_SPEC_TYPE_SRC_PREFIX
- FLOW_SPEC_TYPE_IP_PROTO
- FLOW_SPEC_TYPE_PORT
- FLOW_SPEC_TYPE_DST_PORT
- FLOW_SPEC_TYPE_SRC_PORT
- FLOW_SPEC_TYPE_ICMP_TYPE
- FLOW_SPEC_TYPE_ICMP_CODE
- FLOW_SPEC_TYPE_TCP_FLAG
- FLOW_SPEC_TYPE_PKT_LEN
- FLOW_SPEC_TYPE_DSCP
- FLOW_SPEC_TYPE_FRAGMENT
- FLOW_SPEC_TYPE_LABEL
- FLOW_SPEC_TYPE_ETHERNET_TYPE // 14
- FLOW_SPEC_TYPE_SRC_MAC
- FLOW_SPEC_TYPE_DST_MAC
- FLOW_SPEC_TYPE_LLC_DSAP
- FLOW_SPEC_TYPE_LLC_SSAP
- FLOW_SPEC_TYPE_LLC_CONTROL
- FLOW_SPEC_TYPE_SNAP
- FLOW_SPEC_TYPE_VID
- FLOW_SPEC_TYPE_COS
- FLOW_SPEC_TYPE_INNER_VID
- FLOW_SPEC_TYPE_INNER_COS
-)
-
-var FlowSpecNameMap = map[BGPFlowSpecType]string{
- FLOW_SPEC_TYPE_UNKNOWN: "unknown",
- FLOW_SPEC_TYPE_DST_PREFIX: "destination",
- FLOW_SPEC_TYPE_SRC_PREFIX: "source",
- FLOW_SPEC_TYPE_IP_PROTO: "protocol",
- FLOW_SPEC_TYPE_PORT: "port",
- FLOW_SPEC_TYPE_DST_PORT: "destination-port",
- FLOW_SPEC_TYPE_SRC_PORT: "source-port",
- FLOW_SPEC_TYPE_ICMP_TYPE: "icmp-type",
- FLOW_SPEC_TYPE_ICMP_CODE: "icmp-code",
- FLOW_SPEC_TYPE_TCP_FLAG: "tcp-flags",
- FLOW_SPEC_TYPE_PKT_LEN: "packet-length",
- FLOW_SPEC_TYPE_DSCP: "dscp",
- FLOW_SPEC_TYPE_FRAGMENT: "fragment",
- FLOW_SPEC_TYPE_LABEL: "label",
- FLOW_SPEC_TYPE_ETHERNET_TYPE: "ether-type",
- FLOW_SPEC_TYPE_SRC_MAC: "source-mac",
- FLOW_SPEC_TYPE_DST_MAC: "destination-mac",
- FLOW_SPEC_TYPE_LLC_DSAP: "llc-dsap",
- FLOW_SPEC_TYPE_LLC_SSAP: "llc-ssap",
- FLOW_SPEC_TYPE_LLC_CONTROL: "llc-control",
- FLOW_SPEC_TYPE_SNAP: "snap",
- FLOW_SPEC_TYPE_VID: "vid",
- FLOW_SPEC_TYPE_COS: "cos",
- FLOW_SPEC_TYPE_INNER_VID: "inner-vid",
- FLOW_SPEC_TYPE_INNER_COS: "inner-cos",
-}
-
-var FlowSpecValueMap = map[string]BGPFlowSpecType{
- FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]: FLOW_SPEC_TYPE_DST_PREFIX,
- FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]: FLOW_SPEC_TYPE_SRC_PREFIX,
- FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO]: FLOW_SPEC_TYPE_IP_PROTO,
- FlowSpecNameMap[FLOW_SPEC_TYPE_PORT]: FLOW_SPEC_TYPE_PORT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PORT]: FLOW_SPEC_TYPE_DST_PORT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PORT]: FLOW_SPEC_TYPE_SRC_PORT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_TYPE]: FLOW_SPEC_TYPE_ICMP_TYPE,
- FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_CODE]: FLOW_SPEC_TYPE_ICMP_CODE,
- FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG]: FLOW_SPEC_TYPE_TCP_FLAG,
- FlowSpecNameMap[FLOW_SPEC_TYPE_PKT_LEN]: FLOW_SPEC_TYPE_PKT_LEN,
- FlowSpecNameMap[FLOW_SPEC_TYPE_DSCP]: FLOW_SPEC_TYPE_DSCP,
- FlowSpecNameMap[FLOW_SPEC_TYPE_FRAGMENT]: FLOW_SPEC_TYPE_FRAGMENT,
- FlowSpecNameMap[FLOW_SPEC_TYPE_LABEL]: FLOW_SPEC_TYPE_LABEL,
- FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE]: FLOW_SPEC_TYPE_ETHERNET_TYPE,
- FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]: FLOW_SPEC_TYPE_SRC_MAC,
- FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]: FLOW_SPEC_TYPE_DST_MAC,
- FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_DSAP]: FLOW_SPEC_TYPE_LLC_DSAP,
- FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_SSAP]: FLOW_SPEC_TYPE_LLC_SSAP,
- FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_CONTROL]: FLOW_SPEC_TYPE_LLC_CONTROL,
- FlowSpecNameMap[FLOW_SPEC_TYPE_SNAP]: FLOW_SPEC_TYPE_SNAP,
- FlowSpecNameMap[FLOW_SPEC_TYPE_VID]: FLOW_SPEC_TYPE_VID,
- FlowSpecNameMap[FLOW_SPEC_TYPE_COS]: FLOW_SPEC_TYPE_COS,
- FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_VID]: FLOW_SPEC_TYPE_INNER_VID,
- FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_COS]: FLOW_SPEC_TYPE_INNER_COS,
-}
-
-// Joins the given and args into a single string and normalize it.
-// Example:
-// args := []string{" & <=80", " tcp != udp ", " =! SA & =U! F", " = is-fragment+last-fragment"}
-// fmt.Printf("%q", normalizeFlowSpecOpValues(args))
-// >>> ["<=80" "tcp" "!=udp" "=!SA" "&=U" "!F" "=is-fragment+last-fragment"]
-func normalizeFlowSpecOpValues(args []string) []string {
- // Extracts keywords from the given args.
- sub := ""
- subs := make([]string, 0)
- for _, s := range _regexpFlowSpecOperator.FindAllString(strings.Join(args, " "), -1) {
- sub += s
- if _regexpFlowSpecOperatorValue.MatchString(s) {
- subs = append(subs, sub)
- sub = ""
- }
- }
-
- // RFC5575 says "It should be unset in the first operator byte of a
- // sequence".
- if len(subs) > 0 {
- subs[0] = strings.TrimPrefix(subs[0], "&")
- }
-
- return subs
-}
-
-// Parses the FlowSpec numeric operator using the given submatch which should be
-// the return value of func (*Regexp) FindStringSubmatch.
-func parseFlowSpecNumericOperator(submatch []string) (operator uint8, err error) {
- if submatch[1] == "&" {
- operator = DEC_NUM_OP_AND
- }
- value, ok := DECNumOpValueMap[submatch[2]]
- if !ok {
- return 0, fmt.Errorf("invalid numeric operator: %s%s", submatch[1], submatch[2])
- }
- operator |= uint8(value)
- return operator, nil
-}
-
-// Parses the pairs of operator and value for the FlowSpec numeric type. The
-// given validationFunc is applied to evaluate whether the parsed value is
-// valid or not (e.g., if exceeds range or not).
-// Note: Each of the args should be formatted in single pair of operator and
-// value before calling this function.
-// e.g.) "&==100", ">=200" or "&<300"
-func parseFlowSpecNumericOpValues(typ BGPFlowSpecType, args []string, validationFunc func(uint64) error) (FlowSpecComponentInterface, error) {
- argsLen := len(args)
- items := make([]*FlowSpecComponentItem, 0, argsLen)
- for idx, arg := range args {
- m := _regexpFlowSpecNumericType.FindStringSubmatch(arg)
- if len(m) < 4 {
- return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args)
- }
- operator, err := parseFlowSpecNumericOperator(m)
- if err != nil {
- return nil, err
- }
- // "true" and "false" is operator, but here handles them as value.
- var value uint64
- switch m[3] {
- case "true", "false":
- if idx != argsLen-1 {
- return nil, fmt.Errorf("%s should be the last of each rule", m[3])
- }
- operator = uint8(DECNumOpValueMap[m[3]])
- default:
- if value, err = strconv.ParseUint(m[3], 10, 64); err != nil {
- return nil, fmt.Errorf("invalid numeric value: %s", m[3])
- }
- if err = validationFunc(value); err != nil {
- return nil, err
- }
- }
- items = append(items, NewFlowSpecComponentItem(operator, value))
- }
-
- // Marks end-of-list bit
- items[argsLen-1].Op |= uint8(DEC_NUM_OP_END)
-
- return NewFlowSpecComponent(typ, items), nil
-}
-
-func flowSpecNumeric1ByteParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- args = normalizeFlowSpecOpValues(args)
-
- f := func(i uint64) error {
- if i <= 0xff { // 1 byte
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecNumeric2BytesParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- args = normalizeFlowSpecOpValues(args)
-
- f := func(i uint64) error {
- if i <= 0xffff { // 2 bytes
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-// Parses the FlowSpec bitmask operand using the given submatch which should be
-// the return value of func (*Regexp) FindStringSubmatch.
-func parseFlowSpecBitmaskOperand(submatch []string) (operand uint8, err error) {
- if submatch[1] == "&" {
- operand = BITMASK_FLAG_OP_AND
- }
- value, ok := BitmaskFlagOpValueMap[submatch[2]]
- if !ok {
- return 0, fmt.Errorf("invalid bitmask operand: %s%s", submatch[1], submatch[2])
- }
- operand |= uint8(value)
- return operand, nil
-}
-
-func flowSpecPrefixParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- // args[0]: IP Prefix or IP Address (suppose prefix length is 32)
- // args[1]: Offset in bit (IPv6 only)
- //
- // Example:
- // - IPv4 Prefix
- // args := []string{"192.168.0.0/24"}
- // - IPv4 Address
- // args := []string{"192.168.0.1"}
- // - IPv6 Prefix
- // args := []string{"2001:db8:1::/64"}
- // - IPv6 Prefix with offset
- // args := []string{"0:db8:1::/64/16"}
- // args := []string{"0:db8:1::/64", "16"}
- // - IPv6 Address
- // args := []string{"2001:db8:1::1"}
- // - IPv6 Address with offset
- // args := []string{"0:db8:1::1", "16"}
- afi, _ := RouteFamilyToAfiSafi(rf)
- switch afi {
- case AFI_IP:
- if len(args) > 1 {
- return nil, fmt.Errorf("cannot specify offset for ipv4 prefix")
- }
- invalidIPv4PrefixError := fmt.Errorf("invalid ipv4 prefix: %s", args[0])
- m := _regexpFindIPv4Prefix.FindStringSubmatch(args[0])
- if len(m) < 4 {
- return nil, invalidIPv4PrefixError
- }
- prefix := net.ParseIP(m[1])
- if prefix.To4() == nil {
- return nil, invalidIPv4PrefixError
- }
- var prefixLen uint64 = 32
- if m[3] != "" {
- var err error
- prefixLen, err = strconv.ParseUint(m[3], 10, 8)
- if err != nil || prefixLen > 32 {
- return nil, invalidIPv4PrefixError
- }
- }
- switch typ {
- case FLOW_SPEC_TYPE_DST_PREFIX:
- return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil
- case FLOW_SPEC_TYPE_SRC_PREFIX:
- return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(prefixLen), prefix.String())), nil
- }
- return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String())
- case AFI_IP6:
- if len(args) > 2 {
- return nil, fmt.Errorf("invalid arguments for ipv6 prefix: %q", args)
- }
- invalidIPv6PrefixError := fmt.Errorf("invalid ipv6 prefix: %s", args[0])
- m := _regexpFindIPv6Prefix.FindStringSubmatch(args[0])
- if len(m) < 4 {
- return nil, invalidIPv6PrefixError
- }
- prefix := net.ParseIP(m[1])
- if prefix.To16() == nil {
- return nil, invalidIPv6PrefixError
- }
- var prefixLen uint64 = 128
- if m[3] != "" {
- var err error
- prefixLen, err = strconv.ParseUint(m[3], 10, 8)
- if err != nil || prefixLen > 128 {
- return nil, invalidIPv6PrefixError
- }
- }
- var offset uint64
- if len(args) == 1 && m[5] != "" {
- var err error
- offset, err = strconv.ParseUint(m[5], 10, 8)
- if err != nil || offset > 128 {
- return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", m[5])
- }
- } else if len(args) == 2 {
- if m[5] != "" {
- return nil, fmt.Errorf("multiple ipv6 prefix offset arguments detected: %q", args)
- }
- var err error
- offset, err = strconv.ParseUint(args[1], 10, 8)
- if err != nil || offset > 128 {
- return nil, fmt.Errorf("invalid ipv6 prefix offset: %s", args[1])
- }
- }
- switch typ {
- case FLOW_SPEC_TYPE_DST_PREFIX:
- return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil
- case FLOW_SPEC_TYPE_SRC_PREFIX:
- return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(prefixLen), prefix.String()), uint8(offset)), nil
- }
- return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String())
- }
- return nil, fmt.Errorf("invalid address family: %s", rf.String())
-}
-
-func flowSpecIpProtoParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- // args: List of pairs of Operator and IP protocol type
- //
- // Example:
- // - TCP or UDP
- // args := []string{"tcp", "==udp"}
- // - Not TCP and not UDP
- // args := []string{"!=tcp", "&!=udp"}
- args = normalizeFlowSpecOpValues(args)
- s := strings.Join(args, " ")
- for i, name := range ProtocolNameMap {
- s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1)
- }
- args = strings.Split(s, " ")
-
- f := func(i uint64) error {
- if i <= 0xff { // 1 byte
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecTcpFlagParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- // args: List of pairs of Operand and TCP Flags
- //
- // Example:
- // - SYN or SYN/ACK
- // args := []string{"==S", "==SA"}
- // - Not FIN and not URG
- // args := []string{"!=F", "&!=U"}
- args = normalizeFlowSpecOpValues(args)
-
- argsLen := len(args)
- items := make([]*FlowSpecComponentItem, 0, argsLen)
-
- for _, arg := range args {
- m := _regexpFlowSpecTCPFlag.FindStringSubmatch(arg)
- if len(m) < 6 {
- return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args)
- } else if mLast := m[len(m)-1]; mLast != "" || m[3] != "" {
- return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args)
- }
- operand, err := parseFlowSpecBitmaskOperand(m)
- if err != nil {
- return nil, err
- }
- var value uint64
- for flag, name := range TCPFlagNameMap {
- if strings.Contains(m[4], name) {
- value |= uint64(flag)
- }
- }
- items = append(items, NewFlowSpecComponentItem(operand, value))
- }
-
- // Marks end-of-list bit
- items[argsLen-1].Op |= BITMASK_FLAG_OP_END
-
- return NewFlowSpecComponent(typ, items), nil
-}
-
-func flowSpecDscpParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- args = normalizeFlowSpecOpValues(args)
-
- f := func(i uint64) error {
- if i < 64 { // 6 bits
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecFragmentParser(_ RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- // args: List of pairs of Operator and Fragment flags
- //
- // Example:
- // - is-fragment or last-fragment
- // args := []string{"==is-fragment", "==last-fragment"}
- // - is-fragment and last-fragment (exact match)
- // args := []string{"==is-fragment+last-fragment"}
- args = normalizeFlowSpecOpValues(args)
-
- argsLen := len(args)
- items := make([]*FlowSpecComponentItem, 0, argsLen)
-
- for _, arg := range args {
- m := _regexpFlowSpecFragment.FindStringSubmatch(arg)
- if len(m) < 4 {
- return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args)
- } else if mLast := m[len(m)-1]; mLast != "" {
- return nil, fmt.Errorf("invalid argument for %s: %s in %q", typ.String(), arg, args)
- }
- operand, err := parseFlowSpecBitmaskOperand(m)
- if err != nil {
- return nil, err
- }
- var value uint64
- // Example:
- // m[3] = "first-fragment+last-fragment"
- for flag, name := range FragmentFlagNameMap {
- if strings.Contains(m[3], name) {
- value |= uint64(flag)
- }
- }
- items = append(items, NewFlowSpecComponentItem(operand, value))
- }
-
- // Marks end-of-list bit
- items[argsLen-1].Op |= BITMASK_FLAG_OP_END
-
- return NewFlowSpecComponent(typ, items), nil
-}
-
-func flowSpecLabelParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- afi, _ := RouteFamilyToAfiSafi(rf)
- if afi == AFI_IP {
- return nil, fmt.Errorf("%s is not supported for ipv4", typ.String())
- }
-
- args = normalizeFlowSpecOpValues(args)
-
- f := func(i uint64) error {
- if i <= 0xfffff { // 20 bits
- return nil
- }
- return fmt.Errorf("flow label range exceeded")
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecEtherTypeParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- // args: List of pairs of Operator and Ether Types
- //
- // Example:
- // - ARP or IPv4
- // args := []string{"==arp", "==ipv4"}
- // - Not IPv4 and not IPv6
- // args := []string{"!=ipv4", "&!=ipv6"}
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String())
- }
-
- args = normalizeFlowSpecOpValues(args)
- s := strings.Join(args, " ")
- for i, name := range EthernetTypeNameMap {
- s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1)
- }
- args = strings.Split(s, " ")
-
- f := func(i uint64) error {
- if i <= 0xffff { // 2 bytes
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecMacParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- // args[0]: MAC address
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String())
- }
-
- mac, err := net.ParseMAC(args[0])
- if err != nil {
- return nil, fmt.Errorf("invalid mac address: %s", args[0])
- }
-
- switch typ {
- case FLOW_SPEC_TYPE_DST_MAC:
- return NewFlowSpecDestinationMac(mac), nil
- case FLOW_SPEC_TYPE_SRC_MAC:
- return NewFlowSpecSourceMac(mac), nil
- }
- return nil, fmt.Errorf("invalid traffic filtering rule type: %s", typ.String())
-}
-
-func flowSpecLlcParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String())
- }
-
- return flowSpecNumeric1ByteParser(rf, typ, args)
-}
-
-func flowSpecSnapParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String())
- }
-
- args = normalizeFlowSpecOpValues(args)
-
- f := func(i uint64) error {
- if i <= 0xffffffffff { // 5 bytes
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecVlanIDParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String())
- }
-
- args = normalizeFlowSpecOpValues(args)
- s := strings.Join(args, " ")
- for i, name := range EthernetTypeNameMap {
- s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1)
- }
- args = strings.Split(s, " ")
-
- f := func(i uint64) error {
- if i <= 4095 { // 12 bits
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-func flowSpecVlanCosParser(rf RouteFamily, typ BGPFlowSpecType, args []string) (FlowSpecComponentInterface, error) {
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("%s is supported for only l2vpn", typ.String())
- }
-
- args = normalizeFlowSpecOpValues(args)
- s := strings.Join(args, " ")
- for i, name := range EthernetTypeNameMap {
- s = strings.Replace(s, name, fmt.Sprintf("%d", i), -1)
- }
- args = strings.Split(s, " ")
-
- f := func(i uint64) error {
- if i <= 7 { // 3 bits
- return nil
- }
- return fmt.Errorf("%s range exceeded", typ.String())
- }
-
- return parseFlowSpecNumericOpValues(typ, args, f)
-}
-
-var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, BGPFlowSpecType, []string) (FlowSpecComponentInterface, error){
- FLOW_SPEC_TYPE_DST_PREFIX: flowSpecPrefixParser,
- FLOW_SPEC_TYPE_SRC_PREFIX: flowSpecPrefixParser,
- FLOW_SPEC_TYPE_IP_PROTO: flowSpecIpProtoParser,
- FLOW_SPEC_TYPE_PORT: flowSpecNumeric2BytesParser,
- FLOW_SPEC_TYPE_DST_PORT: flowSpecNumeric2BytesParser,
- FLOW_SPEC_TYPE_SRC_PORT: flowSpecNumeric2BytesParser,
- FLOW_SPEC_TYPE_ICMP_TYPE: flowSpecNumeric1ByteParser,
- FLOW_SPEC_TYPE_ICMP_CODE: flowSpecNumeric1ByteParser,
- FLOW_SPEC_TYPE_TCP_FLAG: flowSpecTcpFlagParser,
- FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumeric2BytesParser,
- FLOW_SPEC_TYPE_DSCP: flowSpecDscpParser,
- FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser,
- FLOW_SPEC_TYPE_LABEL: flowSpecLabelParser,
- FLOW_SPEC_TYPE_ETHERNET_TYPE: flowSpecEtherTypeParser,
- FLOW_SPEC_TYPE_DST_MAC: flowSpecMacParser,
- FLOW_SPEC_TYPE_SRC_MAC: flowSpecMacParser,
- FLOW_SPEC_TYPE_LLC_DSAP: flowSpecLlcParser,
- FLOW_SPEC_TYPE_LLC_SSAP: flowSpecLlcParser,
- FLOW_SPEC_TYPE_LLC_CONTROL: flowSpecLlcParser,
- FLOW_SPEC_TYPE_SNAP: flowSpecSnapParser,
- FLOW_SPEC_TYPE_VID: flowSpecVlanIDParser,
- FLOW_SPEC_TYPE_COS: flowSpecVlanCosParser,
- FLOW_SPEC_TYPE_INNER_VID: flowSpecVlanIDParser,
- FLOW_SPEC_TYPE_INNER_COS: flowSpecVlanCosParser,
-}
-
-func extractFlowSpecArgs(args []string) map[BGPFlowSpecType][]string {
- m := make(map[BGPFlowSpecType][]string, len(FlowSpecValueMap))
- var typ BGPFlowSpecType
- for _, arg := range args {
- if t, ok := FlowSpecValueMap[arg]; ok {
- typ = t
- m[typ] = make([]string, 0)
- } else {
- m[typ] = append(m[typ], arg)
- }
- }
- return m
-}
-
-func ParseFlowSpecComponents(rf RouteFamily, arg string) ([]FlowSpecComponentInterface, error) {
- _, safi := RouteFamilyToAfiSafi(rf)
- switch safi {
- case SAFI_FLOW_SPEC_UNICAST, SAFI_FLOW_SPEC_VPN:
- // Valid
- default:
- return nil, fmt.Errorf("invalid address family: %s", rf.String())
- }
-
- typeArgs := extractFlowSpecArgs(strings.Split(arg, " "))
- rules := make([]FlowSpecComponentInterface, 0, len(typeArgs))
- for typ, args := range typeArgs {
- parser, ok := flowSpecParserMap[typ]
- if !ok {
- return nil, fmt.Errorf("unsupported traffic filtering rule type: %s", typ.String())
- }
- if len(args) == 0 {
- return nil, fmt.Errorf("specify traffic filtering rules for %s", typ.String())
- }
- rule, err := parser(rf, typ, args)
- if err != nil {
- return nil, err
- }
- rules = append(rules, rule)
- }
- return rules, nil
-}
-
-func (t BGPFlowSpecType) String() string {
- name, ok := FlowSpecNameMap[t]
- if !ok {
- return fmt.Sprintf("%s(%d)", FlowSpecNameMap[FLOW_SPEC_TYPE_UNKNOWN], t)
- }
- return name
-}
-
-type FlowSpecComponentInterface interface {
- DecodeFromBytes([]byte, ...*MarshallingOption) error
- Serialize(...*MarshallingOption) ([]byte, error)
- Len(...*MarshallingOption) int
- Type() BGPFlowSpecType
- String() string
-}
-
-type flowSpecPrefix struct {
- Prefix AddrPrefixInterface
- typ BGPFlowSpecType
-}
-
-func (p *flowSpecPrefix) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- p.typ = BGPFlowSpecType(data[0])
- return p.Prefix.DecodeFromBytes(data[1:], options...)
-}
-
-func (p *flowSpecPrefix) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := []byte{byte(p.Type())}
- bbuf, err := p.Prefix.Serialize(options...)
- if err != nil {
- return nil, err
- }
- return append(buf, bbuf...), nil
-}
-
-func (p *flowSpecPrefix) Len(options ...*MarshallingOption) int {
- buf, _ := p.Serialize(options...)
- return len(buf)
-}
-
-func (p *flowSpecPrefix) Type() BGPFlowSpecType {
- return p.typ
-}
-
-func (p *flowSpecPrefix) String() string {
- return fmt.Sprintf("[%s: %s]", p.Type(), p.Prefix.String())
-}
-
-func (p *flowSpecPrefix) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPFlowSpecType `json:"type"`
- Value AddrPrefixInterface `json:"value"`
- }{
- Type: p.Type(),
- Value: p.Prefix,
- })
-}
-
-type flowSpecPrefix6 struct {
- Prefix AddrPrefixInterface
- Offset uint8
- typ BGPFlowSpecType
-}
-
-// draft-ietf-idr-flow-spec-v6-06
-// <type (1 octet), prefix length (1 octet), prefix offset(1 octet), prefix>
-func (p *flowSpecPrefix6) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- p.typ = BGPFlowSpecType(data[0])
- p.Offset = data[2]
- prefix := append([]byte{data[1]}, data[3:]...)
- return p.Prefix.DecodeFromBytes(prefix, options...)
-}
-
-func (p *flowSpecPrefix6) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := []byte{byte(p.Type())}
- bbuf, err := p.Prefix.Serialize(options...)
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf[0])
- buf = append(buf, p.Offset)
- return append(buf, bbuf[1:]...), nil
-}
-
-func (p *flowSpecPrefix6) Len(options ...*MarshallingOption) int {
- buf, _ := p.Serialize(options...)
- return len(buf)
-}
-
-func (p *flowSpecPrefix6) Type() BGPFlowSpecType {
- return p.typ
-}
-
-func (p *flowSpecPrefix6) String() string {
- return fmt.Sprintf("[%s: %s/%d]", p.Type(), p.Prefix.String(), p.Offset)
-}
-
-func (p *flowSpecPrefix6) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPFlowSpecType `json:"type"`
- Value AddrPrefixInterface `json:"value"`
- Offset uint8 `json:"offset"`
- }{
- Type: p.Type(),
- Value: p.Prefix,
- Offset: p.Offset,
- })
-}
-
-type FlowSpecDestinationPrefix struct {
- flowSpecPrefix
-}
-
-func NewFlowSpecDestinationPrefix(prefix AddrPrefixInterface) *FlowSpecDestinationPrefix {
- return &FlowSpecDestinationPrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_DST_PREFIX}}
-}
-
-type FlowSpecSourcePrefix struct {
- flowSpecPrefix
-}
-
-func NewFlowSpecSourcePrefix(prefix AddrPrefixInterface) *FlowSpecSourcePrefix {
- return &FlowSpecSourcePrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_SRC_PREFIX}}
-}
-
-type FlowSpecDestinationPrefix6 struct {
- flowSpecPrefix6
-}
-
-func NewFlowSpecDestinationPrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecDestinationPrefix6 {
- return &FlowSpecDestinationPrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_DST_PREFIX}}
-}
-
-type FlowSpecSourcePrefix6 struct {
- flowSpecPrefix6
-}
-
-func NewFlowSpecSourcePrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecSourcePrefix6 {
- return &FlowSpecSourcePrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_SRC_PREFIX}}
-}
-
-type flowSpecMac struct {
- Mac net.HardwareAddr
- typ BGPFlowSpecType
-}
-
-func (p *flowSpecMac) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if len(data) < 2 || len(data) < 2+int(data[1]) {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all mac bits available")
- }
- p.typ = BGPFlowSpecType(data[0])
- p.Mac = net.HardwareAddr(data[2 : 2+int(data[1])])
- return nil
-}
-
-func (p *flowSpecMac) Serialize(options ...*MarshallingOption) ([]byte, error) {
- if len(p.Mac) == 0 {
- return nil, fmt.Errorf("mac unset")
- }
- buf := []byte{byte(p.Type()), byte(len(p.Mac))}
- return append(buf, []byte(p.Mac)...), nil
-}
-
-func (p *flowSpecMac) Len(options ...*MarshallingOption) int {
- return 2 + len(p.Mac)
-}
-
-func (p *flowSpecMac) Type() BGPFlowSpecType {
- return p.typ
-}
-
-func (p *flowSpecMac) String() string {
- return fmt.Sprintf("[%s: %s]", p.Type(), p.Mac.String())
-}
-
-func (p *flowSpecMac) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPFlowSpecType `json:"type"`
- Value string `json:"value"`
- }{
- Type: p.Type(),
- Value: p.Mac.String(),
- })
-}
-
-type FlowSpecSourceMac struct {
- flowSpecMac
-}
-
-func NewFlowSpecSourceMac(mac net.HardwareAddr) *FlowSpecSourceMac {
- return &FlowSpecSourceMac{flowSpecMac{Mac: mac, typ: FLOW_SPEC_TYPE_SRC_MAC}}
-}
-
-type FlowSpecDestinationMac struct {
- flowSpecMac
-}
-
-func NewFlowSpecDestinationMac(mac net.HardwareAddr) *FlowSpecDestinationMac {
- return &FlowSpecDestinationMac{flowSpecMac{Mac: mac, typ: FLOW_SPEC_TYPE_DST_MAC}}
-}
-
-type FlowSpecComponentItem struct {
- Op uint8 `json:"op"`
- Value uint64 `json:"value"`
-}
-
-func (v *FlowSpecComponentItem) Len() int {
- return 1 << ((uint32(v.Op) >> 4) & 0x3)
-}
-
-func (v *FlowSpecComponentItem) Serialize() ([]byte, error) {
- if v.Op > math.MaxUint8 {
- return nil, fmt.Errorf("invalid op size: %d", v.Op)
- }
-
- order := uint32(math.Log2(float64(v.Len())))
- buf := make([]byte, 1+(1<<order))
- buf[0] = byte(uint32(v.Op) | order<<4)
- switch order {
- case 0:
- buf[1] = byte(v.Value)
- case 1:
- binary.BigEndian.PutUint16(buf[1:], uint16(v.Value))
- case 2:
- binary.BigEndian.PutUint32(buf[1:], uint32(v.Value))
- case 3:
- binary.BigEndian.PutUint64(buf[1:], uint64(v.Value))
- default:
- return nil, fmt.Errorf("invalid value size(too big): %d", v.Value)
- }
- return buf, nil
-}
-
-func NewFlowSpecComponentItem(op uint8, value uint64) *FlowSpecComponentItem {
- v := &FlowSpecComponentItem{op, value}
- order := uint32(math.Log2(float64(v.Len())))
- // we don't know if not initialized properly or initialized to
- // zero...
- if order == 0 {
- order = func() uint32 {
- for i := 0; i < 3; i++ {
- if v.Value < (1 << ((1 << uint(i)) * 8)) {
- return uint32(i)
- }
- }
- // return invalid order
- return 4
- }()
- }
- if order > 3 {
- return nil
- }
- v.Op = uint8(uint32(v.Op) | order<<4)
- return v
-}
-
-type FlowSpecComponent struct {
- Items []*FlowSpecComponentItem
- typ BGPFlowSpecType
-}
-
-func (p *FlowSpecComponent) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- p.typ = BGPFlowSpecType(data[0])
- data = data[1:]
- p.Items = make([]*FlowSpecComponentItem, 0)
- for {
- if len(data) < 2 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available")
- }
- op := data[0]
- end := op & 0x80
- l := 1 << ((op >> 4) & 0x3) // (min, max) = (1, 8)
- v := make([]byte, 8)
- copy(v[8-l:], data[1:1+l])
- i := binary.BigEndian.Uint64(v)
- item := &FlowSpecComponentItem{op, i}
- p.Items = append(p.Items, item)
- if end > 0 {
- break
- }
- data = data[1+l:]
- }
- return nil
-}
-
-func (p *FlowSpecComponent) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := []byte{byte(p.Type())}
- for _, v := range p.Items {
- bbuf, err := v.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return buf, nil
-}
-
-func (p *FlowSpecComponent) Len(options ...*MarshallingOption) int {
- l := 1
- for _, item := range p.Items {
- l += item.Len() + 1
- }
- return l
-}
-
-func (p *FlowSpecComponent) Type() BGPFlowSpecType {
- return p.typ
-}
-
-func formatRaw(op uint8, value uint64) string {
- return fmt.Sprintf("op:%b,value:%d", op, value)
-}
-
-func formatNumeric(op uint8, value uint64) string {
- cmpFlag := DECNumOp(op & 0x7) // lower 3 bits
- if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE {
- // Omit value field
- return DECNumOp(op).String()
- }
- return fmt.Sprint(DECNumOp(op).String(), value)
-}
-
-func formatProto(op uint8, value uint64) string {
- cmpFlag := DECNumOp(op & 0x7) // lower 3 bits
- if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE {
- // Omit value field
- return DECNumOp(op).String()
- }
- return fmt.Sprint(DECNumOp(op).String(), Protocol(value).String())
-}
-
-func formatTCPFlag(op uint8, value uint64) string {
- return fmt.Sprint(BitmaskFlagOp(op).String(), TCPFlag(value).String())
-}
-
-func formatFragment(op uint8, value uint64) string {
- return fmt.Sprint(BitmaskFlagOp(op).String(), FragmentFlag(value).String())
-}
-
-func formatEtherType(op uint8, value uint64) string {
- cmpFlag := DECNumOp(op & 0x7) // lower 3 bits
- if cmpFlag == DEC_NUM_OP_TRUE || cmpFlag == DEC_NUM_OP_FALSE {
- // Omit value field
- return DECNumOp(op).String()
- }
- return fmt.Sprint(DECNumOp(op).String(), EthernetType(value).String())
-}
-
-var flowSpecFormatMap = map[BGPFlowSpecType]func(op uint8, value uint64) string{
- FLOW_SPEC_TYPE_UNKNOWN: formatRaw,
- FLOW_SPEC_TYPE_IP_PROTO: formatProto,
- FLOW_SPEC_TYPE_PORT: formatNumeric,
- FLOW_SPEC_TYPE_DST_PORT: formatNumeric,
- FLOW_SPEC_TYPE_SRC_PORT: formatNumeric,
- FLOW_SPEC_TYPE_ICMP_TYPE: formatNumeric,
- FLOW_SPEC_TYPE_ICMP_CODE: formatNumeric,
- FLOW_SPEC_TYPE_TCP_FLAG: formatTCPFlag,
- FLOW_SPEC_TYPE_PKT_LEN: formatNumeric,
- FLOW_SPEC_TYPE_DSCP: formatNumeric,
- FLOW_SPEC_TYPE_FRAGMENT: formatFragment,
- FLOW_SPEC_TYPE_LABEL: formatNumeric,
- FLOW_SPEC_TYPE_ETHERNET_TYPE: formatEtherType,
- FLOW_SPEC_TYPE_LLC_DSAP: formatNumeric,
- FLOW_SPEC_TYPE_LLC_SSAP: formatNumeric,
- FLOW_SPEC_TYPE_LLC_CONTROL: formatNumeric,
- FLOW_SPEC_TYPE_SNAP: formatNumeric,
- FLOW_SPEC_TYPE_VID: formatNumeric,
- FLOW_SPEC_TYPE_COS: formatNumeric,
- FLOW_SPEC_TYPE_INNER_VID: formatNumeric,
- FLOW_SPEC_TYPE_INNER_COS: formatNumeric,
-}
-
-func (p *FlowSpecComponent) String() string {
- f := flowSpecFormatMap[FLOW_SPEC_TYPE_UNKNOWN]
- if _, ok := flowSpecFormatMap[p.typ]; ok {
- f = flowSpecFormatMap[p.typ]
- }
-
- items := make([]string, 0, len(p.Items))
- for _, i := range p.Items {
- items = append(items, f(i.Op, i.Value))
- }
- // Removes leading and tailing spaces
- value := strings.TrimSpace(strings.Join(items, ""))
-
- return fmt.Sprintf("[%s: %s]", p.typ, value)
-}
-
-func (p *FlowSpecComponent) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPFlowSpecType `json:"type"`
- Value []*FlowSpecComponentItem `json:"value"`
- }{
- Type: p.Type(),
- Value: p.Items,
- })
-}
-
-func NewFlowSpecComponent(typ BGPFlowSpecType, items []*FlowSpecComponentItem) *FlowSpecComponent {
- // Set end-of-list bit on the last item and unset them on the others.
- for i, v := range items {
- if i == len(items)-1 {
- v.Op |= 0x80
- } else {
- v.Op &^= 0x80
- }
-
- }
- return &FlowSpecComponent{
- Items: items,
- typ: typ,
- }
-}
-
-type FlowSpecUnknown struct {
- Value []byte
-}
-
-func (p *FlowSpecUnknown) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- p.Value = data
- return nil
-}
-
-func (p *FlowSpecUnknown) Serialize(options ...*MarshallingOption) ([]byte, error) {
- return p.Value, nil
-}
-
-func (p *FlowSpecUnknown) Len(options ...*MarshallingOption) int {
- return len(p.Value)
-}
-
-func (p *FlowSpecUnknown) Type() BGPFlowSpecType {
- if len(p.Value) > 0 {
- return BGPFlowSpecType(p.Value[0])
- }
- return FLOW_SPEC_TYPE_UNKNOWN
-}
-
-func (p *FlowSpecUnknown) String() string {
- return fmt.Sprintf("[unknown:%v]", p.Value)
-}
-
-func (p *FlowSpecUnknown) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPFlowSpecType `json:"type"`
- Value string `json:"value"`
- }{
- Type: p.Type(),
- Value: string(p.Value),
- })
-}
-
-type FlowSpecNLRI struct {
- PrefixDefault
- Value []FlowSpecComponentInterface
- rf RouteFamily
- rd RouteDistinguisherInterface
-}
-
-func (n *FlowSpecNLRI) AFI() uint16 {
- afi, _ := RouteFamilyToAfiSafi(n.rf)
- return afi
-}
-
-func (n *FlowSpecNLRI) SAFI() uint8 {
- _, safi := RouteFamilyToAfiSafi(n.rf)
- return safi
-}
-
-func (n *FlowSpecNLRI) RD() RouteDistinguisherInterface {
- return n.rd
-}
-
-func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte, options ...*MarshallingOption) error {
- if IsAddPathEnabled(true, rf, options) {
- var err error
- data, err = n.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- var length int
- if (data[0]>>4) == 0xf && len(data) > 2 {
- length = int(binary.BigEndian.Uint16(data[0:2]))
- data = data[2:]
- } else if len(data) > 1 {
- length = int(data[0])
- data = data[1:]
- } else {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available")
- }
-
- n.rf = rf
-
- if n.SAFI() == SAFI_FLOW_SPEC_VPN {
- if length < 8 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available")
- }
- n.rd = GetRouteDistinguisher(data[:8])
- data = data[8:]
- length -= 8
- }
-
- for l := length; l > 0; {
- if len(data) == 0 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all flowspec component bytes available")
- }
- t := BGPFlowSpecType(data[0])
- var i FlowSpecComponentInterface
- switch t {
- case FLOW_SPEC_TYPE_DST_PREFIX:
- switch {
- case rf>>16 == AFI_IP:
- i = NewFlowSpecDestinationPrefix(NewIPAddrPrefix(0, ""))
- case rf>>16 == AFI_IP6:
- i = NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(0, ""), 0)
- default:
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf))
- }
- case FLOW_SPEC_TYPE_SRC_PREFIX:
- switch {
- case rf>>16 == AFI_IP:
- i = NewFlowSpecSourcePrefix(NewIPAddrPrefix(0, ""))
- case rf>>16 == AFI_IP6:
- i = NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(0, ""), 0)
- default:
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf))
- }
- case FLOW_SPEC_TYPE_SRC_MAC:
- switch rf {
- case RF_FS_L2_VPN:
- i = NewFlowSpecSourceMac(nil)
- default:
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf))
- }
- case FLOW_SPEC_TYPE_DST_MAC:
- switch rf {
- case RF_FS_L2_VPN:
- i = NewFlowSpecDestinationMac(nil)
- default:
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Invalid address family: %v", rf))
- }
- case FLOW_SPEC_TYPE_IP_PROTO, FLOW_SPEC_TYPE_PORT, FLOW_SPEC_TYPE_DST_PORT, FLOW_SPEC_TYPE_SRC_PORT,
- FLOW_SPEC_TYPE_ICMP_TYPE, FLOW_SPEC_TYPE_ICMP_CODE, FLOW_SPEC_TYPE_TCP_FLAG, FLOW_SPEC_TYPE_PKT_LEN,
- FLOW_SPEC_TYPE_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL, FLOW_SPEC_TYPE_ETHERNET_TYPE,
- FLOW_SPEC_TYPE_LLC_DSAP, FLOW_SPEC_TYPE_LLC_SSAP, FLOW_SPEC_TYPE_LLC_CONTROL, FLOW_SPEC_TYPE_SNAP,
- FLOW_SPEC_TYPE_VID, FLOW_SPEC_TYPE_COS, FLOW_SPEC_TYPE_INNER_VID, FLOW_SPEC_TYPE_INNER_COS:
- i = NewFlowSpecComponent(t, nil)
- default:
- i = &FlowSpecUnknown{}
- }
-
- err := i.DecodeFromBytes(data, options...)
- if err != nil {
- i = &FlowSpecUnknown{data}
- }
- l -= i.Len(options...)
- data = data[i.Len(options...):]
- n.Value = append(n.Value, i)
- }
-
- // Sort Traffic Filtering Rules in types order to avoid the unordered rules
- // are determined different.
- sort.SliceStable(n.Value, func(i, j int) bool { return n.Value[i].Type() < n.Value[j].Type() })
-
- return nil
-}
-
-func (n *FlowSpecNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0, 32)
- if n.SAFI() == SAFI_FLOW_SPEC_VPN {
- if n.rd == nil {
- return nil, fmt.Errorf("RD is nil")
- }
- b, err := n.rd.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, b...)
- }
- for _, v := range n.Value {
- b, err := v.Serialize(options...)
- if err != nil {
- return nil, err
- }
- buf = append(buf, b...)
- }
- length := n.Len(options...)
- if length > 0xfff {
- return nil, fmt.Errorf("Too large: %d", length)
- } else if length < 0xf0 {
- length -= 1
- buf = append([]byte{byte(length)}, buf...)
- } else {
- length -= 2
- b := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, uint16(length))
- buf = append(b, buf...)
- }
-
- if IsAddPathEnabled(false, n.rf, options) {
- id, err := n.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- return append(id, buf...), nil
- }
- return buf, nil
-}
-
-func (n *FlowSpecNLRI) Len(options ...*MarshallingOption) int {
- l := 0
- if n.SAFI() == SAFI_FLOW_SPEC_VPN {
- l += n.RD().Len()
- }
- for _, v := range n.Value {
- l += v.Len(options...)
- }
- if l < 0xf0 {
- return l + 1
- } else {
- return l + 2
- }
-}
-
-func (n *FlowSpecNLRI) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- if n.SAFI() == SAFI_FLOW_SPEC_VPN {
- buf.WriteString(fmt.Sprintf("[rd: %s]", n.rd))
- }
- for _, v := range n.Value {
- buf.WriteString(v.String())
- }
- return buf.String()
-}
-
-func (n *FlowSpecNLRI) MarshalJSON() ([]byte, error) {
- if n.rd != nil {
- return json.Marshal(struct {
- RD RouteDistinguisherInterface `json:"rd"`
- Value []FlowSpecComponentInterface `json:"value"`
- }{
- RD: n.rd,
- Value: n.Value,
- })
- }
- return json.Marshal(struct {
- Value []FlowSpecComponentInterface `json:"value"`
- }{
- Value: n.Value,
- })
-
-}
-
-//
-// CompareFlowSpecNLRI(n, m) returns
-// -1 when m has precedence
-// 0 when n and m have same precedence
-// 1 when n has precedence
-//
-func CompareFlowSpecNLRI(n, m *FlowSpecNLRI) (int, error) {
- family := AfiSafiToRouteFamily(n.AFI(), n.SAFI())
- if family != AfiSafiToRouteFamily(m.AFI(), m.SAFI()) {
- return 0, fmt.Errorf("address family mismatch")
- }
- longer := n.Value
- shorter := m.Value
- invert := 1
- if n.SAFI() == SAFI_FLOW_SPEC_VPN {
- k, _ := n.Serialize()
- l, _ := m.Serialize()
- if result := bytes.Compare(k, l); result != 0 {
- return result, nil
- }
- }
- if len(n.Value) < len(m.Value) {
- longer = m.Value
- shorter = n.Value
- invert = -1
- }
- for idx, v := range longer {
- if len(shorter) < idx+1 {
- return invert, nil
- }
- w := shorter[idx]
- if v.Type() < w.Type() {
- return invert, nil
- } else if v.Type() > w.Type() {
- return invert * -1, nil
- } else if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX || v.Type() == FLOW_SPEC_TYPE_SRC_PREFIX {
- // RFC5575 5.1
- //
- // For IP prefix values (IP destination and source prefix) precedence is
- // given to the lowest IP value of the common prefix length; if the
- // common prefix is equal, then the most specific prefix has precedence.
- var p, q *IPAddrPrefixDefault
- var pCommon, qCommon uint64
- if n.AFI() == AFI_IP {
- if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX {
- p = &v.(*FlowSpecDestinationPrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault
- q = &w.(*FlowSpecDestinationPrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault
- } else {
- p = &v.(*FlowSpecSourcePrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault
- q = &w.(*FlowSpecSourcePrefix).Prefix.(*IPAddrPrefix).IPAddrPrefixDefault
- }
- min := p.Length
- if q.Length < p.Length {
- min = q.Length
- }
- pCommon = uint64(binary.BigEndian.Uint32([]byte(p.Prefix.To4())) >> (32 - min))
- qCommon = uint64(binary.BigEndian.Uint32([]byte(q.Prefix.To4())) >> (32 - min))
- } else if n.AFI() == AFI_IP6 {
- if v.Type() == FLOW_SPEC_TYPE_DST_PREFIX {
- p = &v.(*FlowSpecDestinationPrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault
- q = &w.(*FlowSpecDestinationPrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault
- } else {
- p = &v.(*FlowSpecSourcePrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault
- q = &w.(*FlowSpecSourcePrefix6).Prefix.(*IPv6AddrPrefix).IPAddrPrefixDefault
- }
- min := uint(p.Length)
- if q.Length < p.Length {
- min = uint(q.Length)
- }
- var mask uint
- if min-64 > 0 {
- mask = min - 64
- }
- pCommon = binary.BigEndian.Uint64([]byte(p.Prefix.To16()[:8])) >> mask
- qCommon = binary.BigEndian.Uint64([]byte(q.Prefix.To16()[:8])) >> mask
- if pCommon == qCommon && mask == 0 {
- mask = 64 - min
- pCommon = binary.BigEndian.Uint64([]byte(p.Prefix.To16()[8:])) >> mask
- qCommon = binary.BigEndian.Uint64([]byte(q.Prefix.To16()[8:])) >> mask
- }
- }
-
- if pCommon < qCommon {
- return invert, nil
- } else if pCommon > qCommon {
- return invert * -1, nil
- } else if p.Length > q.Length {
- return invert, nil
- } else if p.Length < q.Length {
- return invert * -1, nil
- }
-
- } else {
- // RFC5575 5.1
- //
- // For all other component types, unless otherwise specified, the
- // comparison is performed by comparing the component data as a binary
- // string using the memcmp() function as defined by the ISO C standard.
- // For strings of different lengths, the common prefix is compared. If
- // equal, the longest string is considered to have higher precedence
- // than the shorter one.
- p, _ := v.Serialize()
- q, _ := w.Serialize()
- min := len(p)
- if len(q) < len(p) {
- min = len(q)
- }
- if result := bytes.Compare(p[:min], q[:min]); result < 0 {
- return invert, nil
- } else if result > 0 {
- return invert * -1, nil
- } else if len(p) > len(q) {
- return invert, nil
- } else if len(q) > len(p) {
- return invert * -1, nil
- }
- }
- }
- return 0, nil
-}
-
-type FlowSpecIPv4Unicast struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...)
-}
-
-func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast {
- sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() })
- return &FlowSpecIPv4Unicast{
- FlowSpecNLRI: FlowSpecNLRI{
- Value: value,
- rf: RF_FS_IPv4_UC,
- },
- }
-}
-
-type FlowSpecIPv4VPN struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...)
-}
-
-func NewFlowSpecIPv4VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv4VPN {
- sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() })
- return &FlowSpecIPv4VPN{
- FlowSpecNLRI: FlowSpecNLRI{
- Value: value,
- rf: RF_FS_IPv4_VPN,
- rd: rd,
- },
- }
-}
-
-type FlowSpecIPv6Unicast struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...)
-}
-
-func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast {
- sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() })
- return &FlowSpecIPv6Unicast{
- FlowSpecNLRI: FlowSpecNLRI{
- Value: value,
- rf: RF_FS_IPv6_UC,
- },
- }
-}
-
-type FlowSpecIPv6VPN struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data, options...)
-}
-
-func NewFlowSpecIPv6VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecIPv6VPN {
- sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() })
- return &FlowSpecIPv6VPN{
- FlowSpecNLRI: FlowSpecNLRI{
- Value: value,
- rf: RF_FS_IPv6_VPN,
- rd: rd,
- },
- }
-}
-
-type FlowSpecL2VPN struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
-}
-
-func NewFlowSpecL2VPN(rd RouteDistinguisherInterface, value []FlowSpecComponentInterface) *FlowSpecL2VPN {
- sort.SliceStable(value, func(i, j int) bool { return value[i].Type() < value[j].Type() })
- return &FlowSpecL2VPN{
- FlowSpecNLRI: FlowSpecNLRI{
- Value: value,
- rf: RF_FS_L2_VPN,
- rd: rd,
- },
- }
-}
-
-type OpaqueNLRI struct {
- PrefixDefault
- Length uint16
- Key []byte
- Value []byte
-}
-
-func (n *OpaqueNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if len(data) < 2 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available")
- }
- if IsAddPathEnabled(true, RF_OPAQUE, options) {
- var err error
- data, err = n.decodePathIdentifier(data)
- if err != nil {
- return err
- }
- }
- n.Length = binary.BigEndian.Uint16(data[0:2])
- if len(data)-2 < int(n.Length) {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all OpaqueNLRI bytes available")
- }
- n.Key = data[2 : 2+n.Length]
- n.Value = data[2+n.Length:]
- return nil
-}
-
-func (n *OpaqueNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- if len(n.Key) > math.MaxUint16 {
- return nil, fmt.Errorf("Key length too big")
- }
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, uint16(len(n.Key)))
- buf = append(buf, n.Key...)
- buf = append(buf, n.Value...)
- if IsAddPathEnabled(false, RF_OPAQUE, options) {
- id, err := n.serializeIdentifier()
- if err != nil {
- return nil, err
- }
- return append(id, buf...), nil
- }
- return buf, nil
-}
-
-func (n *OpaqueNLRI) AFI() uint16 {
- return AFI_OPAQUE
-}
-
-func (n *OpaqueNLRI) SAFI() uint8 {
- return SAFI_KEY_VALUE
-}
-
-func (n *OpaqueNLRI) Len(options ...*MarshallingOption) int {
- return 2 + len(n.Key) + len(n.Value)
-}
-
-func (n *OpaqueNLRI) String() string {
- return fmt.Sprintf("%s", n.Key)
-}
-
-func (n *OpaqueNLRI) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Key string `json:"key"`
- Value string `json:"value"`
- }{
- Key: string(n.Key),
- Value: string(n.Value),
- })
-}
-
-func NewOpaqueNLRI(key, value []byte) *OpaqueNLRI {
- return &OpaqueNLRI{
- Key: key,
- Value: value,
- }
-}
-
-func AfiSafiToRouteFamily(afi uint16, safi uint8) RouteFamily {
- return RouteFamily(int(afi)<<16 | int(safi))
-}
-
-func RouteFamilyToAfiSafi(rf RouteFamily) (uint16, uint8) {
- return uint16(int(rf) >> 16), uint8(int(rf) & 0xff)
-}
-
-type RouteFamily int
-
-func (f RouteFamily) String() string {
- if n, y := AddressFamilyNameMap[f]; y {
- return n
- }
- return fmt.Sprintf("UnknownFamily(%d)", f)
-}
-
-const (
- RF_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_UNICAST
- RF_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_UNICAST
- RF_IPv4_MC RouteFamily = AFI_IP<<16 | SAFI_MULTICAST
- RF_IPv6_MC RouteFamily = AFI_IP6<<16 | SAFI_MULTICAST
- RF_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN
- RF_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN
- RF_IPv4_VPN_MC RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN_MULTICAST
- RF_IPv6_VPN_MC RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN_MULTICAST
- RF_IPv4_MPLS RouteFamily = AFI_IP<<16 | SAFI_MPLS_LABEL
- RF_IPv6_MPLS RouteFamily = AFI_IP6<<16 | SAFI_MPLS_LABEL
- RF_VPLS RouteFamily = AFI_L2VPN<<16 | SAFI_VPLS
- RF_EVPN RouteFamily = AFI_L2VPN<<16 | SAFI_EVPN
- RF_RTC_UC RouteFamily = AFI_IP<<16 | SAFI_ROUTE_TARGET_CONSTRAINTS
- RF_IPv4_ENCAP RouteFamily = AFI_IP<<16 | SAFI_ENCAPSULATION
- RF_IPv6_ENCAP RouteFamily = AFI_IP6<<16 | SAFI_ENCAPSULATION
- RF_FS_IPv4_UC RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_UNICAST
- RF_FS_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_VPN
- RF_FS_IPv6_UC RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_UNICAST
- RF_FS_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_VPN
- RF_FS_L2_VPN RouteFamily = AFI_L2VPN<<16 | SAFI_FLOW_SPEC_VPN
- RF_OPAQUE RouteFamily = AFI_OPAQUE<<16 | SAFI_KEY_VALUE
-)
-
-var AddressFamilyNameMap = map[RouteFamily]string{
- RF_IPv4_UC: "ipv4-unicast",
- RF_IPv6_UC: "ipv6-unicast",
- RF_IPv4_MC: "ipv4-multicast",
- RF_IPv6_MC: "ipv6-multicast",
- RF_IPv4_MPLS: "ipv4-labelled-unicast",
- RF_IPv6_MPLS: "ipv6-labelled-unicast",
- RF_IPv4_VPN: "l3vpn-ipv4-unicast",
- RF_IPv6_VPN: "l3vpn-ipv6-unicast",
- RF_IPv4_VPN_MC: "l3vpn-ipv4-multicast",
- RF_IPv6_VPN_MC: "l3vpn-ipv6-multicast",
- RF_VPLS: "l2vpn-vpls",
- RF_EVPN: "l2vpn-evpn",
- RF_RTC_UC: "rtc",
- RF_IPv4_ENCAP: "ipv4-encap",
- RF_IPv6_ENCAP: "ipv6-encap",
- RF_FS_IPv4_UC: "ipv4-flowspec",
- RF_FS_IPv4_VPN: "l3vpn-ipv4-flowspec",
- RF_FS_IPv6_UC: "ipv6-flowspec",
- RF_FS_IPv6_VPN: "l3vpn-ipv6-flowspec",
- RF_FS_L2_VPN: "l2vpn-flowspec",
- RF_OPAQUE: "opaque",
-}
-
-var AddressFamilyValueMap = map[string]RouteFamily{
- AddressFamilyNameMap[RF_IPv4_UC]: RF_IPv4_UC,
- AddressFamilyNameMap[RF_IPv6_UC]: RF_IPv6_UC,
- AddressFamilyNameMap[RF_IPv4_MC]: RF_IPv4_MC,
- AddressFamilyNameMap[RF_IPv6_MC]: RF_IPv6_MC,
- AddressFamilyNameMap[RF_IPv4_MPLS]: RF_IPv4_MPLS,
- AddressFamilyNameMap[RF_IPv6_MPLS]: RF_IPv6_MPLS,
- AddressFamilyNameMap[RF_IPv4_VPN]: RF_IPv4_VPN,
- AddressFamilyNameMap[RF_IPv6_VPN]: RF_IPv6_VPN,
- AddressFamilyNameMap[RF_IPv4_VPN_MC]: RF_IPv4_VPN_MC,
- AddressFamilyNameMap[RF_IPv6_VPN_MC]: RF_IPv6_VPN_MC,
- AddressFamilyNameMap[RF_VPLS]: RF_VPLS,
- AddressFamilyNameMap[RF_EVPN]: RF_EVPN,
- AddressFamilyNameMap[RF_RTC_UC]: RF_RTC_UC,
- AddressFamilyNameMap[RF_IPv4_ENCAP]: RF_IPv4_ENCAP,
- AddressFamilyNameMap[RF_IPv6_ENCAP]: RF_IPv6_ENCAP,
- AddressFamilyNameMap[RF_FS_IPv4_UC]: RF_FS_IPv4_UC,
- AddressFamilyNameMap[RF_FS_IPv4_VPN]: RF_FS_IPv4_VPN,
- AddressFamilyNameMap[RF_FS_IPv6_UC]: RF_FS_IPv6_UC,
- AddressFamilyNameMap[RF_FS_IPv6_VPN]: RF_FS_IPv6_VPN,
- AddressFamilyNameMap[RF_FS_L2_VPN]: RF_FS_L2_VPN,
- AddressFamilyNameMap[RF_OPAQUE]: RF_OPAQUE,
-}
-
-func GetRouteFamily(name string) (RouteFamily, error) {
- if v, ok := AddressFamilyValueMap[name]; ok {
- return v, nil
- }
- return RouteFamily(0), fmt.Errorf("%s isn't a valid route family name", name)
-}
-
-func NewPrefixFromRouteFamily(afi uint16, safi uint8, prefixStr ...string) (prefix AddrPrefixInterface, err error) {
- family := AfiSafiToRouteFamily(afi, safi)
-
- f := func(s string) AddrPrefixInterface {
- addr, net, _ := net.ParseCIDR(s)
- len, _ := net.Mask.Size()
- switch family {
- case RF_IPv4_UC, RF_IPv4_MC:
- return NewIPAddrPrefix(uint8(len), addr.String())
- }
- return NewIPv6AddrPrefix(uint8(len), addr.String())
- }
-
- switch family {
- case RF_IPv4_UC, RF_IPv4_MC:
- if len(prefixStr) > 0 {
- prefix = f(prefixStr[0])
- } else {
- prefix = NewIPAddrPrefix(0, "")
- }
- case RF_IPv6_UC, RF_IPv6_MC:
- if len(prefixStr) > 0 {
- prefix = f(prefixStr[0])
- } else {
- prefix = NewIPv6AddrPrefix(0, "")
- }
- case RF_IPv4_VPN:
- prefix = NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil)
- case RF_IPv6_VPN:
- prefix = NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil)
- case RF_IPv4_MPLS:
- prefix = NewLabeledIPAddrPrefix(0, "", *NewMPLSLabelStack())
- case RF_IPv6_MPLS:
- prefix = NewLabeledIPv6AddrPrefix(0, "", *NewMPLSLabelStack())
- case RF_EVPN:
- prefix = NewEVPNNLRI(0, nil)
- case RF_RTC_UC:
- prefix = &RouteTargetMembershipNLRI{}
- case RF_IPv4_ENCAP:
- prefix = NewEncapNLRI("")
- case RF_IPv6_ENCAP:
- prefix = NewEncapv6NLRI("")
- case RF_FS_IPv4_UC:
- prefix = &FlowSpecIPv4Unicast{FlowSpecNLRI{rf: RF_FS_IPv4_UC}}
- case RF_FS_IPv4_VPN:
- prefix = &FlowSpecIPv4VPN{FlowSpecNLRI{rf: RF_FS_IPv4_VPN}}
- case RF_FS_IPv6_UC:
- prefix = &FlowSpecIPv6Unicast{FlowSpecNLRI{rf: RF_FS_IPv6_UC}}
- case RF_FS_IPv6_VPN:
- prefix = &FlowSpecIPv6VPN{FlowSpecNLRI{rf: RF_FS_IPv6_VPN}}
- case RF_FS_L2_VPN:
- prefix = &FlowSpecL2VPN{FlowSpecNLRI{rf: RF_FS_L2_VPN}}
- case RF_OPAQUE:
- prefix = &OpaqueNLRI{}
- default:
- err = fmt.Errorf("unknown route family. AFI: %d, SAFI: %d", afi, safi)
- }
- return prefix, err
-}
-
-type BGPAttrFlag uint8
-
-const (
- BGP_ATTR_FLAG_EXTENDED_LENGTH BGPAttrFlag = 1 << 4
- BGP_ATTR_FLAG_PARTIAL BGPAttrFlag = 1 << 5
- BGP_ATTR_FLAG_TRANSITIVE BGPAttrFlag = 1 << 6
- BGP_ATTR_FLAG_OPTIONAL BGPAttrFlag = 1 << 7
-)
-
-func (f BGPAttrFlag) String() string {
- strs := make([]string, 0, 4)
- if f&BGP_ATTR_FLAG_EXTENDED_LENGTH > 0 {
- strs = append(strs, "EXTENDED_LENGTH")
- }
- if f&BGP_ATTR_FLAG_PARTIAL > 0 {
- strs = append(strs, "PARTIAL")
- }
- if f&BGP_ATTR_FLAG_TRANSITIVE > 0 {
- strs = append(strs, "TRANSITIVE")
- }
- if f&BGP_ATTR_FLAG_OPTIONAL > 0 {
- strs = append(strs, "OPTIONAL")
- }
- return strings.Join(strs, "|")
-}
-
-type BGPAttrType uint8
-
-const (
- _ BGPAttrType = iota
- BGP_ATTR_TYPE_ORIGIN
- BGP_ATTR_TYPE_AS_PATH
- BGP_ATTR_TYPE_NEXT_HOP
- BGP_ATTR_TYPE_MULTI_EXIT_DISC
- BGP_ATTR_TYPE_LOCAL_PREF
- BGP_ATTR_TYPE_ATOMIC_AGGREGATE
- BGP_ATTR_TYPE_AGGREGATOR
- BGP_ATTR_TYPE_COMMUNITIES
- BGP_ATTR_TYPE_ORIGINATOR_ID
- BGP_ATTR_TYPE_CLUSTER_LIST
- _
- _
- _
- BGP_ATTR_TYPE_MP_REACH_NLRI // = 14
- BGP_ATTR_TYPE_MP_UNREACH_NLRI
- BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
- BGP_ATTR_TYPE_AS4_PATH
- BGP_ATTR_TYPE_AS4_AGGREGATOR
- _
- _
- _
- BGP_ATTR_TYPE_PMSI_TUNNEL // = 22
- BGP_ATTR_TYPE_TUNNEL_ENCAP
- _
- BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES // = 25
- BGP_ATTR_TYPE_AIGP // = 26
- BGP_ATTR_TYPE_LARGE_COMMUNITY BGPAttrType = 32
-)
-
-// NOTIFICATION Error Code RFC 4271 4.5.
-const (
- _ = iota
- BGP_ERROR_MESSAGE_HEADER_ERROR
- BGP_ERROR_OPEN_MESSAGE_ERROR
- BGP_ERROR_UPDATE_MESSAGE_ERROR
- BGP_ERROR_HOLD_TIMER_EXPIRED
- BGP_ERROR_FSM_ERROR
- BGP_ERROR_CEASE
- BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_MESSAGE_HEADER_ERROR
-const (
- _ = iota
- BGP_ERROR_SUB_CONNECTION_NOT_SYNCHRONIZED
- BGP_ERROR_SUB_BAD_MESSAGE_LENGTH
- BGP_ERROR_SUB_BAD_MESSAGE_TYPE
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_OPEN_MESSAGE_ERROR
-const (
- _ = iota
- BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER
- BGP_ERROR_SUB_BAD_PEER_AS
- BGP_ERROR_SUB_BAD_BGP_IDENTIFIER
- BGP_ERROR_SUB_UNSUPPORTED_OPTIONAL_PARAMETER
- BGP_ERROR_SUB_DEPRECATED_AUTHENTICATION_FAILURE
- BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME
- BGP_ERROR_SUB_UNSUPPORTED_CAPABILITY
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_UPDATE_MESSAGE_ERROR
-const (
- _ = iota
- BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST
- BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE
- BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE
- BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR
- BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR
- BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE
- BGP_ERROR_SUB_DEPRECATED_ROUTING_LOOP
- BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE
- BGP_ERROR_SUB_OPTIONAL_ATTRIBUTE_ERROR
- BGP_ERROR_SUB_INVALID_NETWORK_FIELD
- BGP_ERROR_SUB_MALFORMED_AS_PATH
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_HOLD_TIMER_EXPIRED
-const (
- _ = iota
- BGP_ERROR_SUB_HOLD_TIMER_EXPIRED
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_FSM_ERROR
-const (
- _ = iota
- BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_STATE
- BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE
- BGP_ERROR_SUB_RECEIVE_UNEXPECTED_MESSAGE_IN_ESTABLISHED_STATE
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_CEASE (RFC 4486)
-const (
- _ = iota
- BGP_ERROR_SUB_MAXIMUM_NUMBER_OF_PREFIXES_REACHED
- BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN
- BGP_ERROR_SUB_PEER_DECONFIGURED
- BGP_ERROR_SUB_ADMINISTRATIVE_RESET
- BGP_ERROR_SUB_CONNECTION_REJECTED
- BGP_ERROR_SUB_OTHER_CONFIGURATION_CHANGE
- BGP_ERROR_SUB_CONNECTION_COLLISION_RESOLUTION
- BGP_ERROR_SUB_OUT_OF_RESOURCES
- BGP_ERROR_SUB_HARD_RESET //draft-ietf-idr-bgp-gr-notification-07
-)
-
-// Constants for BGP_ERROR_SUB_ADMINISTRATIVE_SHUTDOWN and BGP_ERROR_SUB_ADMINISTRATIVE_RESET
-const (
- BGP_ERROR_ADMINISTRATIVE_COMMUNICATION_MAX = 128
-)
-
-// NOTIFICATION Error Subcode for BGP_ERROR_ROUTE_REFRESH
-const (
- _ = iota
- BGP_ERROR_SUB_INVALID_MESSAGE_LENGTH
-)
-
-type NotificationErrorCode uint16
-
-func (c NotificationErrorCode) String() string {
- code := uint8(uint16(c) >> 8)
- subcode := uint8(uint16(c) & 0xff)
- UNDEFINED := "undefined"
- codeStr := UNDEFINED
- subcodeList := []string{}
- switch code {
- case BGP_ERROR_MESSAGE_HEADER_ERROR:
- codeStr = "header"
- subcodeList = []string{
- UNDEFINED,
- "connection not synchronized",
- "bad message length",
- "bad message type"}
- case BGP_ERROR_OPEN_MESSAGE_ERROR:
- codeStr = "open"
- subcodeList = []string{
- UNDEFINED,
- "unsupported version number",
- "bad peer as",
- "bad bgp identifier",
- "unsupported optional parameter",
- "deprecated authentication failure",
- "unacceptable hold time",
- "unsupported capability"}
- case BGP_ERROR_UPDATE_MESSAGE_ERROR:
- codeStr = "update"
- subcodeList = []string{
- UNDEFINED,
- "malformed attribute list",
- "unrecognized well known attribute",
- "missing well known attribute",
- "attribute flags error",
- "attribute length error",
- "invalid origin attribute",
- "deprecated routing loop",
- "invalid next hop attribute",
- "optional attribute error",
- "invalid network field",
- "sub malformed as path"}
- case BGP_ERROR_HOLD_TIMER_EXPIRED:
- codeStr = "hold timer expired"
- subcodeList = []string{
- UNDEFINED,
- "hold timer expired"}
- case BGP_ERROR_FSM_ERROR:
- codeStr = "fsm"
- subcodeList = []string{
- UNDEFINED,
- "receive unexpected message in opensent state",
- "receive unexpected message in openconfirm state",
- "receive unexpected message in established state"}
- case BGP_ERROR_CEASE:
- codeStr = "cease"
- subcodeList = []string{
- UNDEFINED,
- "maximum number of prefixes reached",
- "administrative shutdown",
- "peer deconfigured",
- "administrative reset",
- "connection rejected",
- "other configuration change",
- "connection collision resolution",
- "out of resources"}
- case BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR:
- codeStr = "route refresh"
- subcodeList = []string{"invalid message length"}
- }
- subcodeStr := func(idx uint8, l []string) string {
- if len(l) == 0 || int(idx) > len(l)-1 {
- return UNDEFINED
- }
- return l[idx]
- }(subcode, subcodeList)
- return fmt.Sprintf("code %v(%v) subcode %v(%v)", code, codeStr, subcode, subcodeStr)
-}
-
-func NewNotificationErrorCode(code, subcode uint8) NotificationErrorCode {
- return NotificationErrorCode(uint16(code)<<8 | uint16(subcode))
-}
-
-var PathAttrFlags map[BGPAttrType]BGPAttrFlag = map[BGPAttrType]BGPAttrFlag{
- BGP_ATTR_TYPE_ORIGIN: BGP_ATTR_FLAG_TRANSITIVE,
- BGP_ATTR_TYPE_AS_PATH: BGP_ATTR_FLAG_TRANSITIVE,
- BGP_ATTR_TYPE_NEXT_HOP: BGP_ATTR_FLAG_TRANSITIVE,
- BGP_ATTR_TYPE_MULTI_EXIT_DISC: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_LOCAL_PREF: BGP_ATTR_FLAG_TRANSITIVE,
- BGP_ATTR_TYPE_ATOMIC_AGGREGATE: BGP_ATTR_FLAG_TRANSITIVE,
- BGP_ATTR_TYPE_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_ORIGINATOR_ID: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_CLUSTER_LIST: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_MP_REACH_NLRI: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_MP_UNREACH_NLRI: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_AS4_PATH: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_AS4_AGGREGATOR: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_PMSI_TUNNEL: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_TUNNEL_ENCAP: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_AIGP: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_LARGE_COMMUNITY: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
-}
-
-// getPathAttrFlags returns BGP Path Attribute flags value from its type and
-// length (byte length of value field).
-func getPathAttrFlags(typ BGPAttrType, length int) BGPAttrFlag {
- flags := PathAttrFlags[typ]
- if length > 255 {
- flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH
- }
- return flags
-}
-
-type PathAttributeInterface interface {
- DecodeFromBytes([]byte, ...*MarshallingOption) error
- Serialize(...*MarshallingOption) ([]byte, error)
- Len(...*MarshallingOption) int
- GetFlags() BGPAttrFlag
- GetType() BGPAttrType
- String() string
- MarshalJSON() ([]byte, error)
- Flat() map[string]string
-}
-
-type PathAttribute struct {
- Flags BGPAttrFlag
- Type BGPAttrType
- Length uint16 // length of Value
-}
-
-func (p *PathAttribute) Len(options ...*MarshallingOption) int {
- if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 {
- return 4 + int(p.Length)
- }
- return 3 + int(p.Length)
-}
-
-func (p *PathAttribute) GetFlags() BGPAttrFlag {
- return p.Flags
-}
-
-func (p *PathAttribute) GetType() BGPAttrType {
- return p.Type
-}
-
-func (p *PathAttribute) DecodeFromBytes(data []byte, options ...*MarshallingOption) (value []byte, err error) {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- if len(data) < 2 {
- return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short")
- }
- p.Flags = BGPAttrFlag(data[0])
- p.Type = BGPAttrType(data[1])
- if eMsg := validatePathAttributeFlags(p.Type, p.Flags); eMsg != "" {
- return nil, NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data, eMsg)
- }
-
- if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 {
- if len(data) < 4 {
- return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short")
- }
- p.Length = binary.BigEndian.Uint16(data[2:4])
- data = data[4:]
- } else {
- if len(data) < 3 {
- return nil, NewMessageError(eCode, eSubCode, data, "attribute header length is short")
- }
- p.Length = uint16(data[2])
- data = data[3:]
- }
- if len(data) < int(p.Length) {
- return nil, NewMessageError(eCode, eSubCode, data, "attribute value length is short")
- }
-
- return data[:p.Length], nil
-}
-
-func (p *PathAttribute) Serialize(value []byte, options ...*MarshallingOption) ([]byte, error) {
- // Note: Do not update "p.Flags" and "p.Length" to avoid data race.
- flags := p.Flags
- length := uint16(len(value))
- if flags&BGP_ATTR_FLAG_EXTENDED_LENGTH == 0 && length > 255 {
- flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH
- }
- var buf []byte
- if flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 {
- buf = append(make([]byte, 4), value...)
- binary.BigEndian.PutUint16(buf[2:4], length)
- } else {
- buf = append(make([]byte, 3), value...)
- buf[2] = byte(length)
- }
- buf[0] = uint8(flags)
- buf[1] = uint8(p.Type)
- return buf, nil
-}
-
-type PathAttributeOrigin struct {
- PathAttribute
- Value uint8
-}
-
-func (p *PathAttributeOrigin) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 1 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "Origin attribute length is incorrect")
- }
- p.Value = value[0]
- return nil
-}
-
-func (p *PathAttributeOrigin) Serialize(options ...*MarshallingOption) ([]byte, error) {
- return p.PathAttribute.Serialize([]byte{p.Value}, options...)
-}
-
-func (p *PathAttributeOrigin) String() string {
- typ := "-"
- switch p.Value {
- case BGP_ORIGIN_ATTR_TYPE_IGP:
- typ = "i"
- case BGP_ORIGIN_ATTR_TYPE_EGP:
- typ = "e"
- case BGP_ORIGIN_ATTR_TYPE_INCOMPLETE:
- typ = "?"
- }
- return fmt.Sprintf("{Origin: %s}", typ)
-}
-
-func (p *PathAttributeOrigin) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value uint8 `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeOrigin(value uint8) *PathAttributeOrigin {
- t := BGP_ATTR_TYPE_ORIGIN
- return &PathAttributeOrigin{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 1,
- },
- Value: value,
- }
-}
-
-type AsPathParamFormat struct {
- start string
- end string
- separator string
-}
-
-var asPathParamFormatMap = map[uint8]*AsPathParamFormat{
- BGP_ASPATH_ATTR_TYPE_SET: {"{", "}", ","},
- BGP_ASPATH_ATTR_TYPE_SEQ: {"", "", " "},
- BGP_ASPATH_ATTR_TYPE_CONFED_SET: {"(", ")", " "},
- BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: {"[", "]", ","},
-}
-
-type AsPathParamInterface interface {
- GetType() uint8
- GetAS() []uint32
- Serialize() ([]byte, error)
- DecodeFromBytes([]byte) error
- Len() int
- ASLen() int
- MarshalJSON() ([]byte, error)
- String() string
-}
-
-func AsPathString(aspath *PathAttributeAsPath) string {
- s := bytes.NewBuffer(make([]byte, 0, 64))
- for i, param := range aspath.Value {
- segType := param.GetType()
- asList := param.GetAS()
- if i != 0 {
- s.WriteString(" ")
- }
-
- sep := " "
- switch segType {
- case BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
- s.WriteString("(")
- case BGP_ASPATH_ATTR_TYPE_CONFED_SET:
- s.WriteString("[")
- sep = ","
- case BGP_ASPATH_ATTR_TYPE_SET:
- s.WriteString("{")
- sep = ","
- }
- for j, as := range asList {
- s.WriteString(fmt.Sprintf("%d", as))
- if j != len(asList)-1 {
- s.WriteString(sep)
- }
- }
- switch segType {
- case BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
- s.WriteString(")")
- case BGP_ASPATH_ATTR_TYPE_CONFED_SET:
- s.WriteString("]")
- case BGP_ASPATH_ATTR_TYPE_SET:
- s.WriteString("}")
- }
- }
- return s.String()
-}
-
-type AsPathParam struct {
- Type uint8
- Num uint8
- AS []uint16
-}
-
-func (a *AsPathParam) GetType() uint8 {
- return a.Type
-}
-
-func (a *AsPathParam) GetAS() []uint32 {
- nums := make([]uint32, 0, len(a.AS))
- for _, as := range a.AS {
- nums = append(nums, uint32(as))
- }
- return nums
-}
-
-func (a *AsPathParam) Serialize() ([]byte, error) {
- buf := make([]byte, 2+len(a.AS)*2)
- buf[0] = uint8(a.Type)
- buf[1] = a.Num
- for j, as := range a.AS {
- binary.BigEndian.PutUint16(buf[2+j*2:], as)
- }
- return buf, nil
-}
-
-func (a *AsPathParam) DecodeFromBytes(data []byte) error {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH)
- if len(data) < 2 {
- return NewMessageError(eCode, eSubCode, nil, "AS param header length is short")
- }
- a.Type = data[0]
- a.Num = data[1]
- data = data[2:]
- if len(data) < int(a.Num*2) {
- return NewMessageError(eCode, eSubCode, nil, "AS param data length is short")
- }
- for i := 0; i < int(a.Num); i++ {
- a.AS = append(a.AS, binary.BigEndian.Uint16(data))
- data = data[2:]
- }
- return nil
-}
-
-func (a *AsPathParam) Len() int {
- return 2 + len(a.AS)*2
-}
-
-func (a *AsPathParam) ASLen() int {
- switch a.Type {
- case BGP_ASPATH_ATTR_TYPE_SEQ:
- return len(a.AS)
- case BGP_ASPATH_ATTR_TYPE_SET:
- return 1
- case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
- return 0
- }
- return 0
-}
-
-func (a *AsPathParam) String() string {
- format, ok := asPathParamFormatMap[a.Type]
- if !ok {
- return fmt.Sprintf("%v", a.AS)
- }
- aspath := make([]string, 0, len(a.AS))
- for _, asn := range a.AS {
- aspath = append(aspath, fmt.Sprintf("%d", asn))
- }
- s := bytes.NewBuffer(make([]byte, 0, 32))
- s.WriteString(format.start)
- s.WriteString(strings.Join(aspath, format.separator))
- s.WriteString(format.end)
- return s.String()
-}
-
-func (a *AsPathParam) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint8 `json:"segment_type"`
- Num uint8 `json:"num"`
- AS []uint16 `json:"asns"`
- }{
- Type: a.Type,
- Num: a.Num,
- AS: a.AS,
- })
-}
-
-func NewAsPathParam(segType uint8, as []uint16) *AsPathParam {
- return &AsPathParam{
- Type: segType,
- Num: uint8(len(as)),
- AS: as,
- }
-}
-
-type As4PathParam struct {
- Type uint8
- Num uint8
- AS []uint32
-}
-
-func (a *As4PathParam) GetType() uint8 {
- return a.Type
-}
-
-func (a *As4PathParam) GetAS() []uint32 {
- return a.AS
-}
-
-func (a *As4PathParam) Serialize() ([]byte, error) {
- buf := make([]byte, 2+len(a.AS)*4)
- buf[0] = a.Type
- buf[1] = a.Num
- for j, as := range a.AS {
- binary.BigEndian.PutUint32(buf[2+j*4:], as)
- }
- return buf, nil
-}
-
-func (a *As4PathParam) DecodeFromBytes(data []byte) error {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH)
- if len(data) < 2 {
- return NewMessageError(eCode, eSubCode, nil, "AS4 param header length is short")
- }
- a.Type = data[0]
- a.Num = data[1]
- data = data[2:]
- if len(data) < int(a.Num)*4 {
- return NewMessageError(eCode, eSubCode, nil, "AS4 param data length is short")
- }
- for i := 0; i < int(a.Num); i++ {
- a.AS = append(a.AS, binary.BigEndian.Uint32(data))
- data = data[4:]
- }
- return nil
-}
-
-func (a *As4PathParam) Len() int {
- return 2 + len(a.AS)*4
-}
-
-func (a *As4PathParam) ASLen() int {
- switch a.Type {
- case BGP_ASPATH_ATTR_TYPE_SEQ:
- return len(a.AS)
- case BGP_ASPATH_ATTR_TYPE_SET:
- return 1
- case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
- return 0
- }
- return 0
-}
-
-func (a *As4PathParam) String() string {
- format, ok := asPathParamFormatMap[a.Type]
- if !ok {
- return fmt.Sprintf("%v", a.AS)
- }
- aspath := make([]string, 0, len(a.AS))
- for _, asn := range a.AS {
- aspath = append(aspath, fmt.Sprintf("%d", asn))
- }
- s := bytes.NewBuffer(make([]byte, 0, 32))
- s.WriteString(format.start)
- s.WriteString(strings.Join(aspath, format.separator))
- s.WriteString(format.end)
- return s.String()
-}
-
-func (a *As4PathParam) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint8 `json:"segment_type"`
- Num uint8 `json:"num"`
- AS []uint32 `json:"asns"`
- }{
- Type: a.Type,
- Num: a.Num,
- AS: a.AS,
- })
-}
-
-func NewAs4PathParam(segType uint8, as []uint32) *As4PathParam {
- return &As4PathParam{
- Type: segType,
- Num: uint8(len(as)),
- AS: as,
- }
-}
-
-type PathAttributeAsPath struct {
- PathAttribute
- Value []AsPathParamInterface
-}
-
-func (p *PathAttributeAsPath) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length == 0 {
- // ibgp or something
- return nil
- }
- isAs4, err := validateAsPathValueBytes(value)
- if err != nil {
- err.(*MessageError).Data, _ = p.PathAttribute.Serialize(value, options...)
- return err
- }
- for len(value) > 0 {
- var tuple AsPathParamInterface
- if isAs4 {
- tuple = &As4PathParam{}
- } else {
- tuple = &AsPathParam{}
- }
- err := tuple.DecodeFromBytes(value)
- if err != nil {
- return err
- }
- p.Value = append(p.Value, tuple)
- value = value[tuple.Len():]
- }
- return nil
-}
-
-func (p *PathAttributeAsPath) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0)
- for _, v := range p.Value {
- vbuf, err := v.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, vbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeAsPath) String() string {
- params := make([]string, 0, len(p.Value))
- for _, param := range p.Value {
- params = append(params, param.String())
- }
- return strings.Join(params, " ")
-}
-
-func (p *PathAttributeAsPath) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []AsPathParamInterface `json:"as_paths"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeAsPath(value []AsPathParamInterface) *PathAttributeAsPath {
- var l int
- for _, v := range value {
- l += v.Len()
- }
- t := BGP_ATTR_TYPE_AS_PATH
- return &PathAttributeAsPath{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-type PathAttributeNextHop struct {
- PathAttribute
- Value net.IP
-}
-
-func (p *PathAttributeNextHop) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 4 && p.Length != 16 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "nexthop length isn't correct")
- }
- p.Value = value
- return nil
-}
-
-func (p *PathAttributeNextHop) Serialize(options ...*MarshallingOption) ([]byte, error) {
- return p.PathAttribute.Serialize(p.Value, options...)
-}
-
-func (p *PathAttributeNextHop) String() string {
- return fmt.Sprintf("{Nexthop: %s}", p.Value)
-}
-
-func (p *PathAttributeNextHop) MarshalJSON() ([]byte, error) {
- value := "0.0.0.0"
- if p.Value != nil {
- value = p.Value.String()
- }
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value string `json:"nexthop"`
- }{
- Type: p.GetType(),
- Value: value,
- })
-}
-
-func NewPathAttributeNextHop(value string) *PathAttributeNextHop {
- t := BGP_ATTR_TYPE_NEXT_HOP
- return &PathAttributeNextHop{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 4,
- },
- Value: net.ParseIP(value).To4(),
- }
-}
-
-type PathAttributeMultiExitDisc struct {
- PathAttribute
- Value uint32
-}
-
-func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 4 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "med length isn't correct")
- }
- p.Value = binary.BigEndian.Uint32(value)
- return nil
-}
-
-func (p *PathAttributeMultiExitDisc) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, p.Value)
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeMultiExitDisc) String() string {
- return fmt.Sprintf("{Med: %d}", p.Value)
-}
-
-func (p *PathAttributeMultiExitDisc) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value uint32 `json:"metric"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeMultiExitDisc(value uint32) *PathAttributeMultiExitDisc {
- t := BGP_ATTR_TYPE_MULTI_EXIT_DISC
- return &PathAttributeMultiExitDisc{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 4,
- },
- Value: value,
- }
-}
-
-type PathAttributeLocalPref struct {
- PathAttribute
- Value uint32
-}
-
-func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 4 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "local pref length isn't correct")
- }
- p.Value = binary.BigEndian.Uint32(value)
- return nil
-}
-
-func (p *PathAttributeLocalPref) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, p.Value)
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeLocalPref) String() string {
- return fmt.Sprintf("{LocalPref: %d}", p.Value)
-}
-
-func (p *PathAttributeLocalPref) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value uint32 `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeLocalPref(value uint32) *PathAttributeLocalPref {
- t := BGP_ATTR_TYPE_LOCAL_PREF
- return &PathAttributeLocalPref{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 4,
- },
- Value: value,
- }
-}
-
-type PathAttributeAtomicAggregate struct {
- PathAttribute
-}
-
-func (p *PathAttributeAtomicAggregate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- _, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "atomic aggregate should have no value")
- }
- return nil
-}
-
-func (p *PathAttributeAtomicAggregate) Serialize(options ...*MarshallingOption) ([]byte, error) {
- return p.PathAttribute.Serialize(nil, options...)
-}
-
-func (p *PathAttributeAtomicAggregate) String() string {
- return "{AtomicAggregate}"
-}
-
-func (p *PathAttributeAtomicAggregate) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- }{
- Type: p.GetType(),
- })
-}
-
-func NewPathAttributeAtomicAggregate() *PathAttributeAtomicAggregate {
- t := BGP_ATTR_TYPE_ATOMIC_AGGREGATE
- return &PathAttributeAtomicAggregate{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 0,
- },
- }
-}
-
-type PathAttributeAggregatorParam struct {
- AS uint32
- Askind reflect.Kind
- Address net.IP
-}
-
-type PathAttributeAggregator struct {
- PathAttribute
- Value PathAttributeAggregatorParam
-}
-
-func (p *PathAttributeAggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- switch p.Length {
- case 6:
- p.Value.Askind = reflect.Uint16
- p.Value.AS = uint32(binary.BigEndian.Uint16(value[0:2]))
- p.Value.Address = value[2:]
- case 8:
- p.Value.Askind = reflect.Uint32
- p.Value.AS = binary.BigEndian.Uint32(value[0:4])
- p.Value.Address = value[4:]
- default:
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "aggregator length isn't correct")
- }
- return nil
-}
-
-func (p *PathAttributeAggregator) Serialize(options ...*MarshallingOption) ([]byte, error) {
- var buf []byte
- switch p.Value.Askind {
- case reflect.Uint16:
- buf = make([]byte, 6)
- binary.BigEndian.PutUint16(buf, uint16(p.Value.AS))
- copy(buf[2:], p.Value.Address)
- case reflect.Uint32:
- buf = make([]byte, 8)
- binary.BigEndian.PutUint32(buf, p.Value.AS)
- copy(buf[4:], p.Value.Address)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeAggregator) String() string {
- return fmt.Sprintf("{Aggregate: {AS: %d, Address: %s}}", p.Value.AS, p.Value.Address)
-}
-
-func (p *PathAttributeAggregator) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- AS uint32 `json:"as"`
- Address string `json:"address"`
- }{
- Type: p.GetType(),
- AS: p.Value.AS,
- Address: p.Value.Address.String(),
- })
-}
-
-func NewPathAttributeAggregator(as interface{}, address string) *PathAttributeAggregator {
- v := reflect.ValueOf(as)
- asKind := v.Kind()
- var l uint16
- switch asKind {
- case reflect.Uint16:
- l = 6
- case reflect.Uint32:
- l = 8
- default:
- // Invalid type
- return nil
- }
- t := BGP_ATTR_TYPE_AGGREGATOR
- return &PathAttributeAggregator{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: l,
- },
- Value: PathAttributeAggregatorParam{
- AS: uint32(v.Uint()),
- Askind: asKind,
- Address: net.ParseIP(address).To4(),
- },
- }
-}
-
-type PathAttributeCommunities struct {
- PathAttribute
- Value []uint32
-}
-
-func (p *PathAttributeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length%4 != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "communities length isn't correct")
- }
- for len(value) >= 4 {
- p.Value = append(p.Value, binary.BigEndian.Uint32(value))
- value = value[4:]
- }
- return nil
-}
-
-func (p *PathAttributeCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, len(p.Value)*4)
- for i, v := range p.Value {
- binary.BigEndian.PutUint32(buf[i*4:], v)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-type WellKnownCommunity uint32
-
-const (
- COMMUNITY_INTERNET WellKnownCommunity = 0x00000000
- COMMUNITY_PLANNED_SHUT WellKnownCommunity = 0xffff0000
- COMMUNITY_ACCEPT_OWN WellKnownCommunity = 0xffff0001
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v4 WellKnownCommunity = 0xffff0002
- COMMUNITY_ROUTE_FILTER_v4 WellKnownCommunity = 0xffff0003
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v6 WellKnownCommunity = 0xffff0004
- COMMUNITY_ROUTE_FILTER_v6 WellKnownCommunity = 0xffff0005
- COMMUNITY_LLGR_STALE WellKnownCommunity = 0xffff0006
- COMMUNITY_NO_LLGR WellKnownCommunity = 0xffff0007
- COMMUNITY_BLACKHOLE WellKnownCommunity = 0xffff029a
- COMMUNITY_NO_EXPORT WellKnownCommunity = 0xffffff01
- COMMUNITY_NO_ADVERTISE WellKnownCommunity = 0xffffff02
- COMMUNITY_NO_EXPORT_SUBCONFED WellKnownCommunity = 0xffffff03
- COMMUNITY_NO_PEER WellKnownCommunity = 0xffffff04
-)
-
-var WellKnownCommunityNameMap = map[WellKnownCommunity]string{
- COMMUNITY_INTERNET: "internet",
- COMMUNITY_PLANNED_SHUT: "planned-shut",
- COMMUNITY_ACCEPT_OWN: "accept-own",
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v4: "route-filter-translated-v4",
- COMMUNITY_ROUTE_FILTER_v4: "route-filter-v4",
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v6: "route-filter-translated-v6",
- COMMUNITY_ROUTE_FILTER_v6: "route-filter-v6",
- COMMUNITY_LLGR_STALE: "llgr-stale",
- COMMUNITY_NO_LLGR: "no-llgr",
- COMMUNITY_BLACKHOLE: "blackhole",
- COMMUNITY_NO_EXPORT: "no-export",
- COMMUNITY_NO_ADVERTISE: "no-advertise",
- COMMUNITY_NO_EXPORT_SUBCONFED: "no-export-subconfed",
- COMMUNITY_NO_PEER: "no-peer",
-}
-
-var WellKnownCommunityValueMap = map[string]WellKnownCommunity{
- WellKnownCommunityNameMap[COMMUNITY_INTERNET]: COMMUNITY_INTERNET,
- WellKnownCommunityNameMap[COMMUNITY_PLANNED_SHUT]: COMMUNITY_PLANNED_SHUT,
- WellKnownCommunityNameMap[COMMUNITY_ACCEPT_OWN]: COMMUNITY_ACCEPT_OWN,
- WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_TRANSLATED_v4]: COMMUNITY_ROUTE_FILTER_TRANSLATED_v4,
- WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_v4]: COMMUNITY_ROUTE_FILTER_v4,
- WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_TRANSLATED_v6]: COMMUNITY_ROUTE_FILTER_TRANSLATED_v6,
- WellKnownCommunityNameMap[COMMUNITY_ROUTE_FILTER_v6]: COMMUNITY_ROUTE_FILTER_v6,
- WellKnownCommunityNameMap[COMMUNITY_LLGR_STALE]: COMMUNITY_LLGR_STALE,
- WellKnownCommunityNameMap[COMMUNITY_NO_LLGR]: COMMUNITY_NO_LLGR,
- WellKnownCommunityNameMap[COMMUNITY_NO_EXPORT]: COMMUNITY_NO_EXPORT,
- WellKnownCommunityNameMap[COMMUNITY_BLACKHOLE]: COMMUNITY_BLACKHOLE,
- WellKnownCommunityNameMap[COMMUNITY_NO_ADVERTISE]: COMMUNITY_NO_ADVERTISE,
- WellKnownCommunityNameMap[COMMUNITY_NO_EXPORT_SUBCONFED]: COMMUNITY_NO_EXPORT_SUBCONFED,
- WellKnownCommunityNameMap[COMMUNITY_NO_PEER]: COMMUNITY_NO_PEER,
-}
-
-func (p *PathAttributeCommunities) String() string {
- l := []string{}
- for _, v := range p.Value {
- n, ok := WellKnownCommunityNameMap[WellKnownCommunity(v)]
- if ok {
- l = append(l, n)
- } else {
- l = append(l, fmt.Sprintf("%d:%d", (0xffff0000&v)>>16, 0xffff&v))
- }
- }
- return fmt.Sprintf("{Communities: %s}", strings.Join(l, ", "))
-}
-
-func (p *PathAttributeCommunities) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []uint32 `json:"communities"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeCommunities(value []uint32) *PathAttributeCommunities {
- l := len(value) * 4
- t := BGP_ATTR_TYPE_COMMUNITIES
- return &PathAttributeCommunities{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-type PathAttributeOriginatorId struct {
- PathAttribute
- Value net.IP
-}
-
-func (p *PathAttributeOriginatorId) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 4 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "originator id length isn't correct")
- }
- p.Value = value
- return nil
-}
-
-func (p *PathAttributeOriginatorId) String() string {
- return fmt.Sprintf("{Originator: %s}", p.Value)
-}
-
-func (p *PathAttributeOriginatorId) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value string `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Value.String(),
- })
-}
-
-func (p *PathAttributeOriginatorId) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 4)
- copy(buf, p.Value)
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func NewPathAttributeOriginatorId(value string) *PathAttributeOriginatorId {
- t := BGP_ATTR_TYPE_ORIGINATOR_ID
- return &PathAttributeOriginatorId{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 4,
- },
- Value: net.ParseIP(value).To4(),
- }
-}
-
-type PathAttributeClusterList struct {
- PathAttribute
- Value []net.IP
-}
-
-func (p *PathAttributeClusterList) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length%4 != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "clusterlist length isn't correct")
- }
- for len(value) >= 4 {
- p.Value = append(p.Value, value[:4])
- value = value[4:]
- }
- return nil
-}
-
-func (p *PathAttributeClusterList) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, len(p.Value)*4)
- for i, v := range p.Value {
- copy(buf[i*4:], v)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeClusterList) String() string {
- return fmt.Sprintf("{ClusterList: %v}", p.Value)
-}
-
-func (p *PathAttributeClusterList) MarshalJSON() ([]byte, error) {
- value := make([]string, 0, len(p.Value))
- for _, v := range p.Value {
- value = append(value, v.String())
- }
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []string `json:"value"`
- }{
- Type: p.GetType(),
- Value: value,
- })
-}
-
-func NewPathAttributeClusterList(value []string) *PathAttributeClusterList {
- l := len(value) * 4
- list := make([]net.IP, len(value))
- for i, v := range value {
- list[i] = net.ParseIP(v).To4()
- }
- t := BGP_ATTR_TYPE_CLUSTER_LIST
- return &PathAttributeClusterList{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: list,
- }
-}
-
-type PathAttributeMpReachNLRI struct {
- PathAttribute
- Nexthop net.IP
- LinkLocalNexthop net.IP
- AFI uint16
- SAFI uint8
- Value []AddrPrefixInterface
-}
-
-func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- eData, _ := p.PathAttribute.Serialize(value, options...)
- if p.Length < 3 {
- return NewMessageError(eCode, eSubCode, value, "mpreach header length is short")
- }
- afi := binary.BigEndian.Uint16(value[0:2])
- safi := value[2]
- p.AFI = afi
- p.SAFI = safi
- _, err = NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error())
- }
- nexthoplen := int(value[3])
- if len(value) < 4+nexthoplen {
- return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is short")
- }
- nexthopbin := value[4 : 4+nexthoplen]
- if nexthoplen > 0 {
- v4addrlen := 4
- v6addrlen := 16
- offset := 0
- if safi == SAFI_MPLS_VPN {
- offset = 8
- }
- switch nexthoplen {
- case 2 * (offset + v6addrlen):
- p.LinkLocalNexthop = nexthopbin[offset+v6addrlen+offset : 2*(offset+v6addrlen)]
- fallthrough
- case offset + v6addrlen:
- p.Nexthop = nexthopbin[offset : offset+v6addrlen]
- case offset + v4addrlen:
- p.Nexthop = nexthopbin[offset : offset+v4addrlen]
- default:
- return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is incorrect")
- }
- }
- value = value[4+nexthoplen:]
- // skip reserved
- if len(value) == 0 {
- return NewMessageError(eCode, eSubCode, value, "no skip byte")
- }
- value = value[1:]
- addpathLen := 0
- if IsAddPathEnabled(true, AfiSafiToRouteFamily(afi, safi), options) {
- addpathLen = 4
- }
- for len(value) > 0 {
- prefix, err := NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error())
- }
- err = prefix.DecodeFromBytes(value, options...)
- if err != nil {
- return err
- }
- if prefix.Len(options...)+addpathLen > len(value) {
- return NewMessageError(eCode, eSubCode, value, "prefix length is incorrect")
- }
- value = value[prefix.Len(options...)+addpathLen:]
- p.Value = append(p.Value, prefix)
- }
- return nil
-}
-
-func (p *PathAttributeMpReachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- afi := p.AFI
- safi := p.SAFI
- nexthoplen := 4
- if afi == AFI_IP6 || p.Nexthop.To4() == nil {
- nexthoplen = 16
- }
- offset := 0
- switch safi {
- case SAFI_MPLS_VPN:
- offset = 8
- nexthoplen += offset
- case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST:
- nexthoplen = 0
- }
- if p.LinkLocalNexthop != nil {
- nexthoplen *= 2
- }
- buf := make([]byte, 4+nexthoplen)
- binary.BigEndian.PutUint16(buf[0:], afi)
- buf[2] = safi
- buf[3] = uint8(nexthoplen)
- if nexthoplen != 0 {
- if p.Nexthop.To4() == nil {
- copy(buf[4+offset:], p.Nexthop.To16())
- if p.LinkLocalNexthop != nil {
- copy(buf[4+offset+16:], p.LinkLocalNexthop.To16())
- }
- } else {
- copy(buf[4+offset:], p.Nexthop)
- }
- }
- buf = append(buf, make([]byte, 1)...)
- for _, prefix := range p.Value {
- pbuf, err := prefix.Serialize(options...)
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeMpReachNLRI) MarshalJSON() ([]byte, error) {
- nexthop := p.Nexthop.String()
- if p.Nexthop == nil {
- switch p.AFI {
- case AFI_IP:
- nexthop = "0.0.0.0"
- case AFI_IP6:
- nexthop = "::"
- default:
- nexthop = "fictitious"
- }
- }
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Nexthop string `json:"nexthop"`
- AFI uint16 `json:"afi"`
- SAFI uint8 `json:"safi"`
- Value []AddrPrefixInterface `json:"value"`
- }{
- Type: p.GetType(),
- Nexthop: nexthop,
- AFI: p.AFI,
- SAFI: p.SAFI,
- Value: p.Value,
- })
-}
-
-func (p *PathAttributeMpReachNLRI) String() string {
- return fmt.Sprintf("{MpReach(%s): {Nexthop: %s, NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Nexthop, p.Value)
-}
-
-func NewPathAttributeMpReachNLRI(nexthop string, nlri []AddrPrefixInterface) *PathAttributeMpReachNLRI {
- // AFI(2) + SAFI(1) + NexthopLength(1) + Nexthop(variable)
- // + Reserved(1) + NLRI(variable)
- l := 5
- var afi uint16
- var safi uint8
- if len(nlri) > 0 {
- afi = nlri[0].AFI()
- safi = nlri[0].SAFI()
- }
- nh := net.ParseIP(nexthop)
- if nh.To4() != nil && afi != AFI_IP6 {
- nh = nh.To4()
- switch safi {
- case SAFI_MPLS_VPN:
- l += 12
- case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST:
- // Should not have Nexthop
- default:
- l += 4
- }
- } else {
- switch safi {
- case SAFI_MPLS_VPN:
- l += 24
- case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST:
- // Should not have Nexthop
- default:
- l += 16
- }
- }
- var nlriLen int
- for _, n := range nlri {
- l += n.Len()
- nBuf, _ := n.Serialize()
- nlriLen += len(nBuf)
- }
- t := BGP_ATTR_TYPE_MP_REACH_NLRI
- return &PathAttributeMpReachNLRI{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Nexthop: nh,
- AFI: afi,
- SAFI: safi,
- Value: nlri,
- }
-}
-
-type PathAttributeMpUnreachNLRI struct {
- PathAttribute
- AFI uint16
- SAFI uint8
- Value []AddrPrefixInterface
-}
-
-func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- eData, _ := p.PathAttribute.Serialize(value, options...)
- if p.Length < 3 {
- return NewMessageError(eCode, eSubCode, value, "unreach header length is incorrect")
- }
- afi := binary.BigEndian.Uint16(value[0:2])
- safi := value[2]
- _, err = NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error())
- }
- value = value[3:]
- p.AFI = afi
- p.SAFI = safi
- addpathLen := 0
- if IsAddPathEnabled(true, AfiSafiToRouteFamily(afi, safi), options) {
- addpathLen = 4
- }
- for len(value) > 0 {
- prefix, err := NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, eData, err.Error())
- }
- err = prefix.DecodeFromBytes(value, options...)
- if err != nil {
- return err
- }
- if prefix.Len(options...)+addpathLen > len(value) {
- return NewMessageError(eCode, eSubCode, eData, "prefix length is incorrect")
- }
- value = value[prefix.Len(options...)+addpathLen:]
- p.Value = append(p.Value, prefix)
- }
- return nil
-}
-
-func (p *PathAttributeMpUnreachNLRI) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 3)
- binary.BigEndian.PutUint16(buf, p.AFI)
- buf[2] = p.SAFI
- for _, prefix := range p.Value {
- pbuf, err := prefix.Serialize(options...)
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeMpUnreachNLRI) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- AFI uint16 `json:"afi"`
- SAFI uint8 `json:"safi"`
- Value []AddrPrefixInterface `json:"value"`
- }{
- Type: p.GetType(),
- AFI: p.AFI,
- SAFI: p.SAFI,
- Value: p.Value,
- })
-}
-
-func (p *PathAttributeMpUnreachNLRI) String() string {
- if len(p.Value) > 0 {
- return fmt.Sprintf("{MpUnreach(%s): {NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Value)
- }
- return fmt.Sprintf("{MpUnreach(%s): End-of-Rib}", AfiSafiToRouteFamily(p.AFI, p.SAFI))
-}
-
-func NewPathAttributeMpUnreachNLRI(nlri []AddrPrefixInterface) *PathAttributeMpUnreachNLRI {
- // AFI(2) + SAFI(1) + NLRI(variable)
- l := 3
- var afi uint16
- var safi uint8
- if len(nlri) > 0 {
- afi = nlri[0].AFI()
- safi = nlri[0].SAFI()
- }
- for _, n := range nlri {
- l += n.Len()
- }
- t := BGP_ATTR_TYPE_MP_UNREACH_NLRI
- return &PathAttributeMpUnreachNLRI{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- AFI: afi,
- SAFI: safi,
- Value: nlri,
- }
-}
-
-type ExtendedCommunityInterface interface {
- Serialize() ([]byte, error)
- String() string
- GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType)
- MarshalJSON() ([]byte, error)
- Flat() map[string]string
-}
-
-type TwoOctetAsSpecificExtended struct {
- SubType ExtendedCommunityAttrSubType
- AS uint16
- LocalAdmin uint32
- IsTransitive bool
-}
-
-func (e *TwoOctetAsSpecificExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- if e.IsTransitive {
- buf[0] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC)
- } else {
- buf[0] = byte(EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC)
- }
- buf[1] = byte(e.SubType)
- binary.BigEndian.PutUint16(buf[2:], e.AS)
- binary.BigEndian.PutUint32(buf[4:], e.LocalAdmin)
- return buf, nil
-}
-
-func (e *TwoOctetAsSpecificExtended) String() string {
- return fmt.Sprintf("%d:%d", e.AS, e.LocalAdmin)
-}
-
-func (e *TwoOctetAsSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.String(),
- })
-}
-
-func (e *TwoOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- t := EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC
- if !e.IsTransitive {
- t = EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC
- }
- return t, e.SubType
-}
-
-func NewTwoOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uint16, localAdmin uint32, isTransitive bool) *TwoOctetAsSpecificExtended {
- return &TwoOctetAsSpecificExtended{
- SubType: subtype,
- AS: as,
- LocalAdmin: localAdmin,
- IsTransitive: isTransitive,
- }
-}
-
-type IPv4AddressSpecificExtended struct {
- SubType ExtendedCommunityAttrSubType
- IPv4 net.IP
- LocalAdmin uint16
- IsTransitive bool
-}
-
-func (e *IPv4AddressSpecificExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- if e.IsTransitive {
- buf[0] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC)
- } else {
- buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC)
- }
- buf[1] = byte(e.SubType)
- copy(buf[2:6], e.IPv4)
- binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin)
- return buf, nil
-}
-
-func (e *IPv4AddressSpecificExtended) String() string {
- return fmt.Sprintf("%s:%d", e.IPv4.String(), e.LocalAdmin)
-}
-
-func (e *IPv4AddressSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.String(),
- })
-}
-
-func (e *IPv4AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- t := EC_TYPE_TRANSITIVE_IP4_SPECIFIC
- if !e.IsTransitive {
- t = EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC
- }
- return t, e.SubType
-}
-
-func NewIPv4AddressSpecificExtended(subtype ExtendedCommunityAttrSubType, ip string, localAdmin uint16, isTransitive bool) *IPv4AddressSpecificExtended {
- ipv4 := net.ParseIP(ip)
- if ipv4.To4() == nil {
- return nil
- }
- return &IPv4AddressSpecificExtended{
- SubType: subtype,
- IPv4: ipv4.To4(),
- LocalAdmin: localAdmin,
- IsTransitive: isTransitive,
- }
-}
-
-type IPv6AddressSpecificExtended struct {
- SubType ExtendedCommunityAttrSubType
- IPv6 net.IP
- LocalAdmin uint16
- IsTransitive bool
-}
-
-func (e *IPv6AddressSpecificExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 20)
- if e.IsTransitive {
- buf[0] = byte(EC_TYPE_TRANSITIVE_IP6_SPECIFIC)
- } else {
- buf[0] = byte(EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC)
- }
- buf[1] = byte(e.SubType)
- copy(buf[2:18], e.IPv6)
- binary.BigEndian.PutUint16(buf[18:], e.LocalAdmin)
- return buf, nil
-}
-
-func (e *IPv6AddressSpecificExtended) String() string {
- return fmt.Sprintf("%s:%d", e.IPv6.String(), e.LocalAdmin)
-}
-
-func (e *IPv6AddressSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.String(),
- })
-}
-
-func (e *IPv6AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- t := EC_TYPE_TRANSITIVE_IP6_SPECIFIC
- if !e.IsTransitive {
- t = EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC
- }
- return t, e.SubType
-}
-
-func NewIPv6AddressSpecificExtended(subtype ExtendedCommunityAttrSubType, ip string, localAdmin uint16, isTransitive bool) *IPv6AddressSpecificExtended {
- ipv6 := net.ParseIP(ip)
- if ipv6.To16() == nil {
- return nil
- }
- return &IPv6AddressSpecificExtended{
- SubType: subtype,
- IPv6: ipv6.To16(),
- LocalAdmin: localAdmin,
- IsTransitive: isTransitive,
- }
-}
-
-type FourOctetAsSpecificExtended struct {
- SubType ExtendedCommunityAttrSubType
- AS uint32
- LocalAdmin uint16
- IsTransitive bool
-}
-
-func (e *FourOctetAsSpecificExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- if e.IsTransitive {
- buf[0] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC)
- } else {
- buf[0] = byte(EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC)
- }
- buf[1] = byte(e.SubType)
- binary.BigEndian.PutUint32(buf[2:], e.AS)
- binary.BigEndian.PutUint16(buf[6:], e.LocalAdmin)
- return buf, nil
-}
-
-func (e *FourOctetAsSpecificExtended) String() string {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, e.AS)
- asUpper := binary.BigEndian.Uint16(buf[0:2])
- asLower := binary.BigEndian.Uint16(buf[2:])
- return fmt.Sprintf("%d.%d:%d", asUpper, asLower, e.LocalAdmin)
-}
-
-func (e *FourOctetAsSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.String(),
- })
-}
-
-func (e *FourOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- t := EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC
- if !e.IsTransitive {
- t = EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC
- }
- return t, e.SubType
-}
-
-func NewFourOctetAsSpecificExtended(subtype ExtendedCommunityAttrSubType, as uint32, localAdmin uint16, isTransitive bool) *FourOctetAsSpecificExtended {
- return &FourOctetAsSpecificExtended{
- SubType: subtype,
- AS: as,
- LocalAdmin: localAdmin,
- IsTransitive: isTransitive,
- }
-}
-
-func ParseExtendedCommunity(subtype ExtendedCommunityAttrSubType, com string) (ExtendedCommunityInterface, error) {
- if subtype == EC_SUBTYPE_ORIGIN_VALIDATION {
- var state ValidationState
- switch com {
- case VALIDATION_STATE_VALID.String():
- state = VALIDATION_STATE_VALID
- case VALIDATION_STATE_NOT_FOUND.String():
- state = VALIDATION_STATE_NOT_FOUND
- case VALIDATION_STATE_INVALID.String():
- state = VALIDATION_STATE_INVALID
- default:
- return nil, fmt.Errorf("invalid validation state")
- }
- return &ValidationExtended{
- State: state,
- }, nil
- }
- elems, err := parseRdAndRt(com)
- if err != nil {
- return nil, err
- }
- localAdmin, _ := strconv.ParseUint(elems[10], 10, 32)
- ip := net.ParseIP(elems[1])
- isTransitive := true
- switch {
- case ip.To4() != nil:
- return NewIPv4AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil
- case ip.To16() != nil:
- return NewIPv6AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil
- case elems[6] == "" && elems[7] == "":
- asn, _ := strconv.ParseUint(elems[8], 10, 16)
- return NewTwoOctetAsSpecificExtended(subtype, uint16(asn), uint32(localAdmin), isTransitive), nil
- default:
- fst, _ := strconv.ParseUint(elems[7], 10, 16)
- snd, _ := strconv.ParseUint(elems[8], 10, 16)
- asn := fst<<16 | snd
- return NewFourOctetAsSpecificExtended(subtype, uint32(asn), uint16(localAdmin), isTransitive), nil
- }
-}
-
-func ParseRouteTarget(rt string) (ExtendedCommunityInterface, error) {
- return ParseExtendedCommunity(EC_SUBTYPE_ROUTE_TARGET, rt)
-}
-
-func SerializeExtendedCommunities(comms []ExtendedCommunityInterface) ([][]byte, error) {
- var bufs [][]byte
- var err error
- for _, c := range comms {
- buf, err := c.Serialize()
- if err != nil {
- return nil, err
- }
- bufs = append(bufs, buf)
- }
- return bufs, err
-}
-
-type ValidationState uint8
-
-const (
- VALIDATION_STATE_VALID ValidationState = 0
- VALIDATION_STATE_NOT_FOUND ValidationState = 1
- VALIDATION_STATE_INVALID ValidationState = 2
-)
-
-func (s ValidationState) String() string {
- switch s {
- case VALIDATION_STATE_VALID:
- return "valid"
- case VALIDATION_STATE_NOT_FOUND:
- return "not-found"
- case VALIDATION_STATE_INVALID:
- return "invalid"
- }
- return fmt.Sprintf("unknown validation state(%d)", s)
-}
-
-type ValidationExtended struct {
- State ValidationState
-}
-
-func (e *ValidationExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- typ, subType := e.GetTypes()
- buf[0] = byte(typ)
- buf[1] = byte(subType)
- buf[7] = byte(e.State)
- return buf, nil
-}
-
-func (e *ValidationExtended) String() string {
- return e.State.String()
-}
-
-func (e *ValidationExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_NON_TRANSITIVE_OPAQUE, EC_SUBTYPE_ORIGIN_VALIDATION
-}
-
-func (e *ValidationExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- SubType ExtendedCommunityAttrSubType `json:"subtype"`
- State ValidationState `json:"value"`
- }{
- Type: t,
- SubType: s,
- State: e.State,
- })
-}
-
-func NewValidationExtended(state ValidationState) *ValidationExtended {
- return &ValidationExtended{
- State: state,
- }
-}
-
-type ColorExtended struct {
- Color uint32
-}
-
-func (e *ColorExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- typ, subType := e.GetTypes()
- buf[0] = byte(typ)
- buf[1] = byte(subType)
- binary.BigEndian.PutUint32(buf[4:8], uint32(e.Color))
- return buf, nil
-}
-
-func (e *ColorExtended) String() string {
- return fmt.Sprintf("%d", e.Color)
-}
-
-func (e *ColorExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_COLOR
-}
-
-func (e *ColorExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- SubType ExtendedCommunityAttrSubType `json:"subtype"`
- Color uint32 `json:"color"`
- }{
- Type: t,
- SubType: s,
- Color: e.Color,
- })
-}
-
-func NewColorExtended(color uint32) *ColorExtended {
- return &ColorExtended{
- Color: color,
- }
-}
-
-type EncapExtended struct {
- TunnelType TunnelType
-}
-
-func (e *EncapExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- typ, subType := e.GetTypes()
- buf[0] = byte(typ)
- buf[1] = byte(subType)
- binary.BigEndian.PutUint16(buf[6:8], uint16(e.TunnelType))
- return buf, nil
-}
-
-func (e *EncapExtended) String() string {
- switch e.TunnelType {
- case TUNNEL_TYPE_L2TP3:
- return "L2TPv3 over IP"
- case TUNNEL_TYPE_GRE:
- return "GRE"
- case TUNNEL_TYPE_IP_IN_IP:
- return "IP in IP"
- case TUNNEL_TYPE_VXLAN:
- return "VXLAN"
- case TUNNEL_TYPE_NVGRE:
- return "NVGRE"
- case TUNNEL_TYPE_MPLS:
- return "MPLS"
- case TUNNEL_TYPE_MPLS_IN_GRE:
- return "MPLS in GRE"
- case TUNNEL_TYPE_VXLAN_GRE:
- return "VXLAN GRE"
- case TUNNEL_TYPE_MPLS_IN_UDP:
- return "MPLS in UDP"
- default:
- return fmt.Sprintf("tunnel: %d", e.TunnelType)
- }
-}
-
-func (e *EncapExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_ENCAPSULATION
-}
-
-func (e *EncapExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- SubType ExtendedCommunityAttrSubType `json:"subtype"`
- TunnelType TunnelType `json:"tunnel_type"`
- }{
- Type: t,
- SubType: s,
- TunnelType: e.TunnelType,
- })
-}
-
-func NewEncapExtended(tunnelType TunnelType) *EncapExtended {
- return &EncapExtended{
- TunnelType: tunnelType,
- }
-}
-
-type DefaultGatewayExtended struct {
-}
-
-func (e *DefaultGatewayExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- typ, subType := e.GetTypes()
- buf[0] = byte(typ)
- buf[1] = byte(subType)
- return buf, nil
-}
-
-func (e *DefaultGatewayExtended) String() string {
- return "default-gateway"
-}
-
-func (e *DefaultGatewayExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_TRANSITIVE_OPAQUE, EC_SUBTYPE_DEFAULT_GATEWAY
-}
-
-func (e *DefaultGatewayExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- SubType ExtendedCommunityAttrSubType `json:"subtype"`
- }{
- Type: t,
- SubType: s,
- })
-}
-
-func NewDefaultGatewayExtended() *DefaultGatewayExtended {
- return &DefaultGatewayExtended{}
-}
-
-type OpaqueExtended struct {
- IsTransitive bool
- Value []byte
-}
-
-func (e *OpaqueExtended) Serialize() ([]byte, error) {
- if len(e.Value) != 7 {
- return nil, fmt.Errorf("invalid value length for opaque extended community: %d", len(e.Value))
- }
- buf := make([]byte, 8)
- if e.IsTransitive {
- buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
- } else {
- buf[0] = byte(EC_TYPE_NON_TRANSITIVE_OPAQUE)
- }
- copy(buf[1:], e.Value)
- return buf, nil
-}
-
-func (e *OpaqueExtended) String() string {
- buf := make([]byte, 8)
- copy(buf[1:], e.Value)
- return fmt.Sprintf("%d", binary.BigEndian.Uint64(buf))
-}
-
-func (e *OpaqueExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- var subType ExtendedCommunityAttrSubType
- if len(e.Value) > 0 {
- // Use the first byte of value as the sub type
- subType = ExtendedCommunityAttrSubType(e.Value[0])
- }
- if e.IsTransitive {
- return EC_TYPE_TRANSITIVE_OPAQUE, subType
- }
- return EC_TYPE_NON_TRANSITIVE_OPAQUE, subType
-}
-
-func (e *OpaqueExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value []byte `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.Value,
- })
-}
-
-func NewOpaqueExtended(isTransitive bool, value []byte) *OpaqueExtended {
- v := make([]byte, 7)
- copy(v, value)
- return &OpaqueExtended{
- IsTransitive: isTransitive,
- Value: v,
- }
-}
-
-func parseOpaqueExtended(data []byte) (ExtendedCommunityInterface, error) {
- typ := ExtendedCommunityAttrType(data[0])
- isTransitive := false
- switch typ {
- case EC_TYPE_TRANSITIVE_OPAQUE:
- isTransitive = true
- case EC_TYPE_NON_TRANSITIVE_OPAQUE:
- // isTransitive = false
- default:
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("invalid opaque extended community type: %d", data[0]))
- }
- subType := ExtendedCommunityAttrSubType(data[1])
-
- if isTransitive {
- switch subType {
- case EC_SUBTYPE_COLOR:
- return &ColorExtended{
- Color: binary.BigEndian.Uint32(data[4:8]),
- }, nil
- case EC_SUBTYPE_ENCAPSULATION:
- return &EncapExtended{
- TunnelType: TunnelType(binary.BigEndian.Uint16(data[6:8])),
- }, nil
- case EC_SUBTYPE_DEFAULT_GATEWAY:
- return &DefaultGatewayExtended{}, nil
- }
- } else {
- switch subType {
- case EC_SUBTYPE_ORIGIN_VALIDATION:
- return &ValidationExtended{
- State: ValidationState(data[7]),
- }, nil
- }
- }
- return NewOpaqueExtended(isTransitive, data[1:8]), nil
-}
-
-type ESILabelExtended struct {
- Label uint32
- IsSingleActive bool
-}
-
-func (e *ESILabelExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_EVPN)
- buf[1] = byte(EC_SUBTYPE_ESI_LABEL)
- if e.IsSingleActive {
- buf[2] = byte(1)
- }
- buf[3] = 0
- buf[4] = 0
- buf[5] = byte((e.Label >> 16) & 0xff)
- buf[6] = byte((e.Label >> 8) & 0xff)
- buf[7] = byte(e.Label & 0xff)
- return buf, nil
-}
-
-func (e *ESILabelExtended) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- buf.WriteString(fmt.Sprintf("esi-label: %d", e.Label))
- if e.IsSingleActive {
- buf.WriteString(", single-active")
- }
- return buf.String()
-}
-
-func (e *ESILabelExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Label uint32 `json:"label"`
- IsSingleActive bool `json:"is_single_active"`
- }{
- Type: t,
- Subtype: s,
- Label: e.Label,
- IsSingleActive: e.IsSingleActive,
- })
-}
-
-func (e *ESILabelExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_EVPN, EC_SUBTYPE_ESI_LABEL
-}
-
-func NewESILabelExtended(label uint32, isSingleActive bool) *ESILabelExtended {
- return &ESILabelExtended{
- Label: label,
- IsSingleActive: isSingleActive,
- }
-}
-
-type ESImportRouteTarget struct {
- ESImport net.HardwareAddr
-}
-
-func (e *ESImportRouteTarget) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_EVPN)
- buf[1] = byte(EC_SUBTYPE_ES_IMPORT)
- copy(buf[2:], e.ESImport)
- return buf, nil
-}
-
-func (e *ESImportRouteTarget) String() string {
- return fmt.Sprintf("es-import rt: %s", e.ESImport.String())
-}
-
-func (e *ESImportRouteTarget) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.ESImport.String(),
- })
-}
-
-func (e *ESImportRouteTarget) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_EVPN, EC_SUBTYPE_ES_IMPORT
-}
-
-func NewESImportRouteTarget(mac string) *ESImportRouteTarget {
- esImport, err := net.ParseMAC(mac)
- if err != nil {
- return nil
- }
- return &ESImportRouteTarget{
- ESImport: esImport,
- }
-}
-
-type MacMobilityExtended struct {
- Sequence uint32
- IsSticky bool
-}
-
-func (e *MacMobilityExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_EVPN)
- buf[1] = byte(EC_SUBTYPE_MAC_MOBILITY)
- if e.IsSticky {
- buf[2] = byte(1)
- }
- binary.BigEndian.PutUint32(buf[4:], e.Sequence)
- return buf, nil
-}
-
-func (e *MacMobilityExtended) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- buf.WriteString(fmt.Sprintf("mac-mobility: %d", e.Sequence))
- if e.IsSticky {
- buf.WriteString(", sticky")
- }
- return buf.String()
-}
-
-func (e *MacMobilityExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Sequence uint32 `json:"sequence"`
- IsSticky bool `json:"is_sticky"`
- }{
- Type: t,
- Subtype: s,
- Sequence: e.Sequence,
- IsSticky: e.IsSticky,
- })
-}
-
-func (e *MacMobilityExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_EVPN, EC_SUBTYPE_MAC_MOBILITY
-}
-
-func NewMacMobilityExtended(seq uint32, isSticky bool) *MacMobilityExtended {
- return &MacMobilityExtended{
- Sequence: seq,
- IsSticky: isSticky,
- }
-}
-
-type RouterMacExtended struct {
- Mac net.HardwareAddr
-}
-
-func (e *RouterMacExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 2, 8)
- buf[0] = byte(EC_TYPE_EVPN)
- buf[1] = byte(EC_SUBTYPE_ROUTER_MAC)
- buf = append(buf, e.Mac...)
- return buf, nil
-}
-
-func (e *RouterMacExtended) String() string {
- return fmt.Sprintf("router's mac: %s", e.Mac.String())
-}
-
-func (e *RouterMacExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Mac string `json:"mac"`
- }{
- Type: t,
- Subtype: s,
- Mac: e.Mac.String(),
- })
-}
-
-func (e *RouterMacExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_EVPN, EC_SUBTYPE_ROUTER_MAC
-}
-
-func NewRoutersMacExtended(mac string) *RouterMacExtended {
- hw, err := net.ParseMAC(mac)
- if err != nil {
- return nil
- }
- return &RouterMacExtended{
- Mac: hw,
- }
-}
-
-func parseEvpnExtended(data []byte) (ExtendedCommunityInterface, error) {
- if ExtendedCommunityAttrType(data[0]) != EC_TYPE_EVPN {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_EVPN: %d", data[0]))
- }
- subType := ExtendedCommunityAttrSubType(data[1])
- switch subType {
- case EC_SUBTYPE_ESI_LABEL:
- var isSingleActive bool
- if data[2] > 0 {
- isSingleActive = true
- }
- label := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7])
- return &ESILabelExtended{
- IsSingleActive: isSingleActive,
- Label: label,
- }, nil
- case EC_SUBTYPE_ES_IMPORT:
- return &ESImportRouteTarget{
- ESImport: net.HardwareAddr(data[2:8]),
- }, nil
- case EC_SUBTYPE_MAC_MOBILITY:
- var isSticky bool
- if data[2] > 0 {
- isSticky = true
- }
- seq := binary.BigEndian.Uint32(data[4:8])
- return &MacMobilityExtended{
- Sequence: seq,
- IsSticky: isSticky,
- }, nil
- case EC_SUBTYPE_ROUTER_MAC:
- return &RouterMacExtended{
- Mac: net.HardwareAddr(data[2:8]),
- }, nil
- }
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("unknown evpn subtype: %d", subType))
-}
-
-type TrafficRateExtended struct {
- AS uint16
- Rate float32
-}
-
-func (e *TrafficRateExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE)
- binary.BigEndian.PutUint16(buf[2:4], e.AS)
- binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(e.Rate))
- return buf, nil
-}
-
-func (e *TrafficRateExtended) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- if e.Rate == 0 {
- buf.WriteString("discard")
- } else {
- buf.WriteString(fmt.Sprintf("rate: %f", e.Rate))
- }
- if e.AS != 0 {
- buf.WriteString(fmt.Sprintf("(as: %d)", e.AS))
- }
- return buf.String()
-}
-
-func (e *TrafficRateExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- As uint16 `json:"as"`
- Rate float32 `json:"rate"`
- }{t, s, e.AS, e.Rate})
-}
-
-func (e *TrafficRateExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE
-}
-
-func NewTrafficRateExtended(as uint16, rate float32) *TrafficRateExtended {
- return &TrafficRateExtended{
- AS: as,
- Rate: rate,
- }
-}
-
-type TrafficActionExtended struct {
- Terminal bool
- Sample bool
-}
-
-func (e *TrafficActionExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION)
- if e.Terminal {
- buf[7] = 0x01
- }
- if e.Sample {
- buf[7] = buf[7] | 0x2
- }
- return buf, nil
-}
-
-func (e *TrafficActionExtended) String() string {
- ss := make([]string, 0, 2)
- if e.Terminal {
- ss = append(ss, "terminal")
- }
- if e.Sample {
- ss = append(ss, "sample")
- }
- return fmt.Sprintf("action: %s", strings.Join(ss, "-"))
-}
-
-func (e *TrafficActionExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Terminal bool `json:"terminal"`
- Sample bool `json:"sample"`
- }{t, s, e.Terminal, e.Sample})
-}
-
-func (e *TrafficActionExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION
-}
-
-func NewTrafficActionExtended(terminal bool, sample bool) *TrafficActionExtended {
- return &TrafficActionExtended{
- Terminal: terminal,
- Sample: sample,
- }
-}
-
-type RedirectTwoOctetAsSpecificExtended struct {
- TwoOctetAsSpecificExtended
-}
-
-func (e *RedirectTwoOctetAsSpecificExtended) Serialize() ([]byte, error) {
- buf, err := e.TwoOctetAsSpecificExtended.Serialize()
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT)
- return buf, err
-}
-
-func (e *RedirectTwoOctetAsSpecificExtended) String() string {
- return fmt.Sprintf("redirect: %s", e.TwoOctetAsSpecificExtended.String())
-}
-
-func (e *RedirectTwoOctetAsSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{t, s, e.TwoOctetAsSpecificExtended.String()})
-}
-
-func (e *RedirectTwoOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_REDIRECT
-}
-
-func NewRedirectTwoOctetAsSpecificExtended(as uint16, localAdmin uint32) *RedirectTwoOctetAsSpecificExtended {
- return &RedirectTwoOctetAsSpecificExtended{*NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, as, localAdmin, false)}
-}
-
-type RedirectIPv4AddressSpecificExtended struct {
- IPv4AddressSpecificExtended
-}
-
-func (e *RedirectIPv4AddressSpecificExtended) Serialize() ([]byte, error) {
- buf, err := e.IPv4AddressSpecificExtended.Serialize()
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT)
- return buf, err
-}
-
-func (e *RedirectIPv4AddressSpecificExtended) String() string {
- return fmt.Sprintf("redirect: %s", e.IPv4AddressSpecificExtended.String())
-}
-
-func (e *RedirectIPv4AddressSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{t, s, e.IPv4AddressSpecificExtended.String()})
-}
-
-func (e *RedirectIPv4AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2, EC_SUBTYPE_FLOWSPEC_REDIRECT
-}
-
-func NewRedirectIPv4AddressSpecificExtended(ipv4 string, localAdmin uint16) *RedirectIPv4AddressSpecificExtended {
- e := NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv4, localAdmin, false)
- if e == nil {
- return nil
- }
- return &RedirectIPv4AddressSpecificExtended{*e}
-}
-
-type RedirectIPv6AddressSpecificExtended struct {
- IPv6AddressSpecificExtended
-}
-
-func (e *RedirectIPv6AddressSpecificExtended) Serialize() ([]byte, error) {
- buf, err := e.IPv6AddressSpecificExtended.Serialize()
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6)
- return buf, err
-}
-
-func (e *RedirectIPv6AddressSpecificExtended) String() string {
- return fmt.Sprintf("redirect: %s", e.IPv6AddressSpecificExtended.String())
-}
-
-func (e *RedirectIPv6AddressSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{t, s, e.IPv6AddressSpecificExtended.String()})
-}
-
-func (e *RedirectIPv6AddressSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6
-}
-
-func NewRedirectIPv6AddressSpecificExtended(ipv6 string, localAdmin uint16) *RedirectIPv6AddressSpecificExtended {
- e := NewIPv6AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv6, localAdmin, false)
- if e == nil {
- return nil
- }
- return &RedirectIPv6AddressSpecificExtended{*e}
-}
-
-type RedirectFourOctetAsSpecificExtended struct {
- FourOctetAsSpecificExtended
-}
-
-func (e *RedirectFourOctetAsSpecificExtended) Serialize() ([]byte, error) {
- buf, err := e.FourOctetAsSpecificExtended.Serialize()
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_REDIRECT)
- return buf, err
-}
-
-func (e *RedirectFourOctetAsSpecificExtended) String() string {
- return fmt.Sprintf("redirect: %s", e.FourOctetAsSpecificExtended.String())
-}
-
-func (e *RedirectFourOctetAsSpecificExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value string `json:"value"`
- }{t, s, e.FourOctetAsSpecificExtended.String()})
-}
-
-func (e *RedirectFourOctetAsSpecificExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3, EC_SUBTYPE_FLOWSPEC_REDIRECT
-}
-
-func NewRedirectFourOctetAsSpecificExtended(as uint32, localAdmin uint16) *RedirectFourOctetAsSpecificExtended {
- return &RedirectFourOctetAsSpecificExtended{*NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, as, localAdmin, false)}
-}
-
-type TrafficRemarkExtended struct {
- DSCP uint8
-}
-
-func (e *TrafficRemarkExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL)
- buf[1] = byte(EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK)
- buf[7] = byte(e.DSCP)
- return buf, nil
-}
-
-func (e *TrafficRemarkExtended) String() string {
- return fmt.Sprintf("remark: %d", e.DSCP)
-}
-
-func (e *TrafficRemarkExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value uint8 `json:"value"`
- }{t, s, e.DSCP})
-}
-
-func (e *TrafficRemarkExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- return EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK
-}
-
-func NewTrafficRemarkExtended(dscp uint8) *TrafficRemarkExtended {
- return &TrafficRemarkExtended{
- DSCP: dscp,
- }
-}
-
-func parseFlowSpecExtended(data []byte) (ExtendedCommunityInterface, error) {
- typ := ExtendedCommunityAttrType(data[0])
- if typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_FLOWSPEC: %d", data[0]))
- }
- subType := ExtendedCommunityAttrSubType(data[1])
- switch subType {
- case EC_SUBTYPE_FLOWSPEC_TRAFFIC_RATE:
- asn := binary.BigEndian.Uint16(data[2:4])
- bits := binary.BigEndian.Uint32(data[4:8])
- rate := math.Float32frombits(bits)
- return NewTrafficRateExtended(asn, rate), nil
- case EC_SUBTYPE_FLOWSPEC_TRAFFIC_ACTION:
- terminal := data[7]&0x1 == 1
- sample := (data[7]>>1)&0x1 == 1
- return NewTrafficActionExtended(terminal, sample), nil
- case EC_SUBTYPE_FLOWSPEC_REDIRECT:
- // RFC7674
- switch typ {
- case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL:
- as := binary.BigEndian.Uint16(data[2:4])
- localAdmin := binary.BigEndian.Uint32(data[4:8])
- return NewRedirectTwoOctetAsSpecificExtended(as, localAdmin), nil
- case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2:
- ipv4 := net.IP(data[2:6]).String()
- localAdmin := binary.BigEndian.Uint16(data[6:8])
- return NewRedirectIPv4AddressSpecificExtended(ipv4, localAdmin), nil
- case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3:
- as := binary.BigEndian.Uint32(data[2:6])
- localAdmin := binary.BigEndian.Uint16(data[6:8])
- return NewRedirectFourOctetAsSpecificExtended(as, localAdmin), nil
- }
- case EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK:
- dscp := data[7]
- return NewTrafficRemarkExtended(dscp), nil
- case EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6:
- ipv6 := net.IP(data[2:18]).String()
- localAdmin := binary.BigEndian.Uint16(data[18:20])
- return NewRedirectIPv6AddressSpecificExtended(ipv6, localAdmin), nil
- }
- return &UnknownExtended{
- Type: ExtendedCommunityAttrType(data[0]),
- Value: data[1:8],
- }, nil
-}
-
-func parseIP6FlowSpecExtended(data []byte) (ExtendedCommunityInterface, error) {
- typ := ExtendedCommunityAttrType(data[0])
- if typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 && typ != EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("ext comm type is not EC_TYPE_FLOWSPEC: %d", data[0]))
- }
- subType := ExtendedCommunityAttrSubType(data[1])
- switch subType {
- case EC_SUBTYPE_FLOWSPEC_REDIRECT_IP6:
- // RFC7674
- switch typ {
- case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL:
- ipv6 := net.IP(data[2:18]).String()
- localAdmin := binary.BigEndian.Uint16(data[18:20])
- return NewRedirectIPv6AddressSpecificExtended(ipv6, localAdmin), nil
- }
- }
- return &UnknownExtended{
- Type: ExtendedCommunityAttrType(data[0]),
- Value: data[1:20],
- }, nil
-}
-
-type UnknownExtended struct {
- Type ExtendedCommunityAttrType
- Value []byte
-}
-
-func (e *UnknownExtended) Serialize() ([]byte, error) {
- if len(e.Value) != 7 {
- return nil, fmt.Errorf("invalid value length for unknown extended community: %d", len(e.Value))
- }
- buf := make([]byte, 8)
- buf[0] = uint8(e.Type)
- copy(buf[1:], e.Value)
- return buf, nil
-}
-
-func (e *UnknownExtended) String() string {
- buf := make([]byte, 8)
- copy(buf[1:], e.Value)
- return fmt.Sprintf("%d", binary.BigEndian.Uint64(buf))
-}
-
-func (e *UnknownExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value []byte `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.Value,
- })
-}
-
-func (e *UnknownExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- var subType ExtendedCommunityAttrSubType
- if len(e.Value) > 0 {
- // Use the first byte of value as the sub type
- subType = ExtendedCommunityAttrSubType(e.Value[0])
- }
- return e.Type, subType
-}
-
-func NewUnknownExtended(typ ExtendedCommunityAttrType, value []byte) *UnknownExtended {
- v := make([]byte, 7)
- copy(v, value)
- return &UnknownExtended{
- Type: typ,
- Value: v,
- }
-}
-
-type PathAttributeExtendedCommunities struct {
- PathAttribute
- Value []ExtendedCommunityInterface
-}
-
-func ParseExtended(data []byte) (ExtendedCommunityInterface, error) {
- if len(data) < 8 {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all extended community bytes are available")
- }
- attrType := ExtendedCommunityAttrType(data[0])
- subtype := ExtendedCommunityAttrSubType(data[1])
- transitive := false
- switch attrType {
- case EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC:
- transitive = true
- fallthrough
- case EC_TYPE_NON_TRANSITIVE_TWO_OCTET_AS_SPECIFIC:
- as := binary.BigEndian.Uint16(data[2:4])
- localAdmin := binary.BigEndian.Uint32(data[4:8])
- return NewTwoOctetAsSpecificExtended(subtype, as, localAdmin, transitive), nil
- case EC_TYPE_TRANSITIVE_IP4_SPECIFIC:
- transitive = true
- fallthrough
- case EC_TYPE_NON_TRANSITIVE_IP4_SPECIFIC:
- ipv4 := net.IP(data[2:6]).String()
- localAdmin := binary.BigEndian.Uint16(data[6:8])
- return NewIPv4AddressSpecificExtended(subtype, ipv4, localAdmin, transitive), nil
- case EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC:
- transitive = true
- fallthrough
- case EC_TYPE_NON_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC:
- as := binary.BigEndian.Uint32(data[2:6])
- localAdmin := binary.BigEndian.Uint16(data[6:8])
- return NewFourOctetAsSpecificExtended(subtype, as, localAdmin, transitive), nil
- case EC_TYPE_TRANSITIVE_OPAQUE:
- transitive = true
- fallthrough
- case EC_TYPE_NON_TRANSITIVE_OPAQUE:
- return parseOpaqueExtended(data)
- case EC_TYPE_EVPN:
- return parseEvpnExtended(data)
- case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL, EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2, EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3:
- return parseFlowSpecExtended(data)
- default:
- return &UnknownExtended{
- Type: ExtendedCommunityAttrType(data[0]),
- Value: data[1:8],
- }, nil
- }
-}
-
-func (p *PathAttributeExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length%8 != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "extendedcommunities length isn't correct")
- }
- for len(value) >= 8 {
- e, err := ParseExtended(value)
- if err != nil {
- return err
- }
- p.Value = append(p.Value, e)
- value = value[8:]
- }
- return nil
-}
-
-func (p *PathAttributeExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0)
- for _, p := range p.Value {
- ebuf, err := p.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, ebuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeExtendedCommunities) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- for idx, v := range p.Value {
- buf.WriteString("[")
- buf.WriteString(v.String())
- buf.WriteString("]")
- if idx < len(p.Value)-1 {
- buf.WriteString(", ")
- }
- }
- return fmt.Sprintf("{Extcomms: %s}", buf.String())
-}
-
-func (p *PathAttributeExtendedCommunities) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []ExtendedCommunityInterface `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeExtendedCommunities(value []ExtendedCommunityInterface) *PathAttributeExtendedCommunities {
- l := len(value) * 8
- t := BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
- return &PathAttributeExtendedCommunities{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-type PathAttributeAs4Path struct {
- PathAttribute
- Value []*As4PathParam
-}
-
-func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- isAs4, err := validateAsPathValueBytes(value)
- if err != nil {
- return err
- }
-
- if !isAs4 {
- return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed")
- }
-
- for len(value) > 0 {
- tuple := &As4PathParam{}
- tuple.DecodeFromBytes(value)
- p.Value = append(p.Value, tuple)
- if len(value) < tuple.Len() {
- return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed")
- }
- value = value[tuple.Len():]
- }
- return nil
-}
-
-func (p *PathAttributeAs4Path) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0)
- for _, v := range p.Value {
- vbuf, err := v.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, vbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeAs4Path) String() string {
- params := make([]string, 0, len(p.Value))
- for _, param := range p.Value {
- params = append(params, param.String())
- }
- return strings.Join(params, " ")
-}
-
-func (p *PathAttributeAs4Path) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []*As4PathParam `json:"as_paths"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeAs4Path(value []*As4PathParam) *PathAttributeAs4Path {
- var l int
- for _, v := range value {
- l += v.Len()
- }
- t := BGP_ATTR_TYPE_AS4_PATH
- return &PathAttributeAs4Path{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-type PathAttributeAs4Aggregator struct {
- PathAttribute
- Value PathAttributeAggregatorParam
-}
-
-func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length != 8 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "AS4 Aggregator length is incorrect")
- }
- p.Value.AS = binary.BigEndian.Uint32(value[0:4])
- p.Value.Address = value[4:]
- return nil
-}
-
-func (p *PathAttributeAs4Aggregator) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint32(buf[0:], p.Value.AS)
- copy(buf[4:], p.Value.Address.To4())
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeAs4Aggregator) String() string {
- return fmt.Sprintf("{As4Aggregator: {AS: %d, Address: %s}}", p.Value.AS, p.Value.Address)
-}
-
-func (p *PathAttributeAs4Aggregator) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- AS uint32 `json:"as"`
- Address string `json:"address"`
- }{
- Type: p.GetType(),
- AS: p.Value.AS,
- Address: p.Value.Address.String(),
- })
-}
-
-func NewPathAttributeAs4Aggregator(as uint32, address string) *PathAttributeAs4Aggregator {
- t := BGP_ATTR_TYPE_AS4_AGGREGATOR
- return &PathAttributeAs4Aggregator{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- Length: 8,
- },
- Value: PathAttributeAggregatorParam{
- AS: as,
- Address: net.ParseIP(address).To4(),
- },
- }
-}
-
-type TunnelEncapSubTLVInterface interface {
- Len() int
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
- String() string
- MarshalJSON() ([]byte, error)
-}
-
-type TunnelEncapSubTLV struct {
- Type EncapSubTLVType
- Length uint16
-}
-
-func (t *TunnelEncapSubTLV) Len() int {
- if t.Type >= 0x80 {
- return 3 + int(t.Length)
- }
- return 2 + int(t.Length)
-}
-
-func (t *TunnelEncapSubTLV) DecodeFromBytes(data []byte) (value []byte, err error) {
- t.Type = EncapSubTLVType(data[0])
- if t.Type >= 0x80 {
- t.Length = binary.BigEndian.Uint16(data[1:3])
- data = data[3:]
- } else {
- t.Length = uint16(data[1])
- data = data[2:]
- }
- if len(data) < int(t.Length) {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLV bytes available")
- }
- return data, nil
-}
-
-func (t *TunnelEncapSubTLV) Serialize(value []byte) (buf []byte, err error) {
- t.Length = uint16(len(value))
- if t.Type >= 0x80 {
- buf = append(make([]byte, 3), value...)
- binary.BigEndian.PutUint16(buf[1:3], t.Length)
- } else {
- buf = append(make([]byte, 2), value...)
- buf[1] = uint8(t.Length)
- }
- buf[0] = uint8(t.Type)
- return buf, nil
-}
-
-type TunnelEncapSubTLVUnknown struct {
- TunnelEncapSubTLV
- Value []byte
-}
-
-func (t *TunnelEncapSubTLVUnknown) DecodeFromBytes(data []byte) error {
- value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- t.Value = value
- return nil
-}
-
-func (t *TunnelEncapSubTLVUnknown) Serialize() ([]byte, error) {
- return t.TunnelEncapSubTLV.Serialize(t.Value)
-}
-
-func (t *TunnelEncapSubTLVUnknown) String() string {
- return fmt.Sprintf("{Type: %d, Value: %x}", t.Type, t.Value)
-}
-
-func (t *TunnelEncapSubTLVUnknown) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type EncapSubTLVType `json:"type"`
- Value []byte `json:"value"`
- }{
- Type: t.Type,
- Value: t.Value,
- })
-}
-
-func NewTunnelEncapSubTLVUnknown(typ EncapSubTLVType, value []byte) *TunnelEncapSubTLVUnknown {
- return &TunnelEncapSubTLVUnknown{
- TunnelEncapSubTLV: TunnelEncapSubTLV{
- Type: typ,
- },
- Value: value,
- }
-}
-
-type TunnelEncapSubTLVEncapsulation struct {
- TunnelEncapSubTLV
- Key uint32 // this represent both SessionID for L2TPv3 case and GRE-key for GRE case (RFC5512 4.)
- Cookie []byte
-}
-
-func (t *TunnelEncapSubTLVEncapsulation) DecodeFromBytes(data []byte) error {
- value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if t.Length < 4 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVEncapsulation bytes available")
- }
- t.Key = binary.BigEndian.Uint32(value[0:4])
- t.Cookie = value[4:]
- return nil
-}
-
-func (t *TunnelEncapSubTLVEncapsulation) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, t.Key)
- buf = append(buf, t.Cookie...)
- return t.TunnelEncapSubTLV.Serialize(buf)
-}
-
-func (t *TunnelEncapSubTLVEncapsulation) String() string {
- return fmt.Sprintf("{Key: %d, Cookie: %x}", t.Key, t.Cookie)
-}
-
-func (t *TunnelEncapSubTLVEncapsulation) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type EncapSubTLVType `json:"type"`
- Key uint32 `json:"key"`
- Cookie []byte `json:"cookie"`
- }{
- Type: t.Type,
- Key: t.Key,
- Cookie: t.Cookie,
- })
-}
-
-func NewTunnelEncapSubTLVEncapsulation(key uint32, cookie []byte) *TunnelEncapSubTLVEncapsulation {
- return &TunnelEncapSubTLVEncapsulation{
- TunnelEncapSubTLV: TunnelEncapSubTLV{
- Type: ENCAP_SUBTLV_TYPE_ENCAPSULATION,
- },
- Key: key,
- Cookie: cookie,
- }
-}
-
-type TunnelEncapSubTLVProtocol struct {
- TunnelEncapSubTLV
- Protocol uint16
-}
-
-func (t *TunnelEncapSubTLVProtocol) DecodeFromBytes(data []byte) error {
- value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if t.Length < 2 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Not all TunnelEncapSubTLVProtocol bytes available")
- }
- t.Protocol = binary.BigEndian.Uint16(value[0:2])
- return nil
-}
-
-func (t *TunnelEncapSubTLVProtocol) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, t.Protocol)
- return t.TunnelEncapSubTLV.Serialize(buf)
-}
-
-func (t *TunnelEncapSubTLVProtocol) String() string {
- return fmt.Sprintf("{Protocol: %d}", t.Protocol)
-}
-
-func (t *TunnelEncapSubTLVProtocol) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type EncapSubTLVType `json:"type"`
- Protocol uint16 `json:"protocol"`
- }{
- Type: t.Type,
- Protocol: t.Protocol,
- })
-}
-
-func NewTunnelEncapSubTLVProtocol(protocol uint16) *TunnelEncapSubTLVProtocol {
- return &TunnelEncapSubTLVProtocol{
- TunnelEncapSubTLV: TunnelEncapSubTLV{
- Type: ENCAP_SUBTLV_TYPE_PROTOCOL,
- },
- Protocol: protocol,
- }
-}
-
-type TunnelEncapSubTLVColor struct {
- TunnelEncapSubTLV
- Color uint32
-}
-
-func (t *TunnelEncapSubTLVColor) DecodeFromBytes(data []byte) error {
- value, err := t.TunnelEncapSubTLV.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if t.Length != 8 {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "Invalid TunnelEncapSubTLVColor length")
- }
- t.Color = binary.BigEndian.Uint32(value[4:8])
- return nil
-}
-
-func (t *TunnelEncapSubTLVColor) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
- buf[1] = byte(EC_SUBTYPE_COLOR)
- binary.BigEndian.PutUint32(buf[4:8], t.Color)
- return t.TunnelEncapSubTLV.Serialize(buf)
-}
-
-func (t *TunnelEncapSubTLVColor) String() string {
- return fmt.Sprintf("{Color: %d}", t.Color)
-}
-
-func (t *TunnelEncapSubTLVColor) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type EncapSubTLVType `json:"type"`
- Color uint32 `json:"color"`
- }{
- Type: t.Type,
- Color: t.Color,
- })
-}
-
-func NewTunnelEncapSubTLVColor(color uint32) *TunnelEncapSubTLVColor {
- return &TunnelEncapSubTLVColor{
- TunnelEncapSubTLV: TunnelEncapSubTLV{
- Type: ENCAP_SUBTLV_TYPE_COLOR,
- },
- Color: color,
- }
-}
-
-type TunnelEncapTLV struct {
- Type TunnelType
- Length uint16
- Value []TunnelEncapSubTLVInterface
-}
-
-func (t *TunnelEncapTLV) Len() int {
- var l int
- for _, v := range t.Value {
- l += v.Len()
- }
- return 4 + l // Type(2) + Length(2) + Value(variable)
-}
-
-func (t *TunnelEncapTLV) DecodeFromBytes(data []byte) error {
- t.Type = TunnelType(binary.BigEndian.Uint16(data[0:2]))
- t.Length = binary.BigEndian.Uint16(data[2:4])
- data = data[4:]
- if len(data) < int(t.Length) {
- return NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, fmt.Sprintf("Not all TunnelEncapTLV bytes available"))
- }
- value := data[:t.Length]
- for len(value) > 2 {
- subType := EncapSubTLVType(value[0])
- var subTlv TunnelEncapSubTLVInterface
- switch subType {
- case ENCAP_SUBTLV_TYPE_ENCAPSULATION:
- subTlv = &TunnelEncapSubTLVEncapsulation{}
- case ENCAP_SUBTLV_TYPE_PROTOCOL:
- subTlv = &TunnelEncapSubTLVProtocol{}
- case ENCAP_SUBTLV_TYPE_COLOR:
- subTlv = &TunnelEncapSubTLVColor{}
- default:
- subTlv = &TunnelEncapSubTLVUnknown{
- TunnelEncapSubTLV: TunnelEncapSubTLV{
- Type: subType,
- },
- }
- }
- err := subTlv.DecodeFromBytes(value)
- if err != nil {
- return err
- }
- t.Value = append(t.Value, subTlv)
- value = value[subTlv.Len():]
- }
- return nil
-}
-
-func (p *TunnelEncapTLV) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- for _, t := range p.Value {
- tBuf, err := t.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, tBuf...)
- }
- binary.BigEndian.PutUint16(buf, uint16(p.Type))
- binary.BigEndian.PutUint16(buf[2:], uint16(len(buf)-4))
- return buf, nil
-}
-
-func (p *TunnelEncapTLV) String() string {
- tlvList := make([]string, len(p.Value))
- for i, v := range p.Value {
- tlvList[i] = v.String()
- }
- return fmt.Sprintf("{%s: %s}", p.Type, strings.Join(tlvList, ", "))
-}
-
-func (p *TunnelEncapTLV) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type TunnelType `json:"type"`
- Value []TunnelEncapSubTLVInterface `json:"value"`
- }{
- Type: p.Type,
- Value: p.Value,
- })
-}
-
-func NewTunnelEncapTLV(typ TunnelType, value []TunnelEncapSubTLVInterface) *TunnelEncapTLV {
- return &TunnelEncapTLV{
- Type: typ,
- Value: value,
- }
-}
-
-type PathAttributeTunnelEncap struct {
- PathAttribute
- Value []*TunnelEncapTLV
-}
-
-func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- for len(value) > 4 {
- tlv := &TunnelEncapTLV{}
- err = tlv.DecodeFromBytes(value)
- if err != nil {
- return err
- }
- p.Value = append(p.Value, tlv)
- value = value[4+tlv.Length:]
- }
- return nil
-}
-
-func (p *PathAttributeTunnelEncap) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0)
- for _, t := range p.Value {
- bbuf, err := t.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeTunnelEncap) String() string {
- tlvList := make([]string, len(p.Value))
- for i, v := range p.Value {
- tlvList[i] = v.String()
- }
- return fmt.Sprintf("{TunnelEncap: %s}", strings.Join(tlvList, ", "))
-}
-
-func (p *PathAttributeTunnelEncap) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []*TunnelEncapTLV `json:"value"`
- }{
- Type: p.Type,
- Value: p.Value,
- })
-}
-
-func NewPathAttributeTunnelEncap(value []*TunnelEncapTLV) *PathAttributeTunnelEncap {
- var l int
- for _, v := range value {
- l += v.Len()
- }
- t := BGP_ATTR_TYPE_TUNNEL_ENCAP
- return &PathAttributeTunnelEncap{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-type PmsiTunnelIDInterface interface {
- Len() int
- Serialize() ([]byte, error)
- String() string
-}
-
-type DefaultPmsiTunnelID struct {
- Value []byte
-}
-
-func (i *DefaultPmsiTunnelID) Len() int {
- return len(i.Value)
-}
-
-func (i *DefaultPmsiTunnelID) Serialize() ([]byte, error) {
- return i.Value, nil
-}
-
-func (i *DefaultPmsiTunnelID) String() string {
- return string(i.Value)
-}
-
-func NewDefaultPmsiTunnelID(value []byte) *DefaultPmsiTunnelID {
- return &DefaultPmsiTunnelID{
- Value: value,
- }
-}
-
-type IngressReplTunnelID struct {
- Value net.IP
-}
-
-func (i *IngressReplTunnelID) Len() int {
- return len(i.Value)
-}
-
-func (i *IngressReplTunnelID) Serialize() ([]byte, error) {
- if i.Value.To4() != nil {
- return []byte(i.Value.To4()), nil
- }
- return []byte(i.Value), nil
-}
-
-func (i *IngressReplTunnelID) String() string {
- return i.Value.String()
-}
-
-func NewIngressReplTunnelID(value string) *IngressReplTunnelID {
- ip := net.ParseIP(value)
- if ip == nil {
- return nil
- }
- return &IngressReplTunnelID{
- Value: ip,
- }
-}
-
-type PathAttributePmsiTunnel struct {
- PathAttribute
- IsLeafInfoRequired bool
- TunnelType PmsiTunnelType
- Label uint32
- TunnelID PmsiTunnelIDInterface
-}
-
-func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- if p.Length < 5 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "PMSI Tunnel length is incorrect")
- }
-
- if (value[0] & 0x01) > 0 {
- p.IsLeafInfoRequired = true
- }
- p.TunnelType = PmsiTunnelType(value[1])
- if p.Label, err = labelDecode(value[2:5]); err != nil {
- return err
- }
-
- switch p.TunnelType {
- case PMSI_TUNNEL_TYPE_INGRESS_REPL:
- p.TunnelID = &IngressReplTunnelID{net.IP(value[5:])}
- default:
- p.TunnelID = &DefaultPmsiTunnelID{value[5:]}
- }
- return nil
-}
-
-func (p *PathAttributePmsiTunnel) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 2)
- if p.IsLeafInfoRequired {
- buf[0] = 0x01
- }
- buf[1] = byte(p.TunnelType)
- tbuf, err := labelSerialize(p.Label)
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
- tbuf, err = p.TunnelID.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributePmsiTunnel) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- buf.WriteString(fmt.Sprintf("{Pmsi: type: %s,", p.TunnelType))
- if p.IsLeafInfoRequired {
- buf.WriteString(" leaf-info-required,")
- }
- buf.WriteString(fmt.Sprintf(" label: %d, tunnel-id: %s}", p.Label, p.TunnelID))
- return buf.String()
-}
-
-func (p *PathAttributePmsiTunnel) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- IsLeafInfoRequired bool `json:"is-leaf-info-required"`
- TunnelType uint8 `json:"tunnel-type"`
- Label uint32 `json:"label"`
- TunnelID string `json:"tunnel-id"`
- }{
- Type: p.Type,
- IsLeafInfoRequired: p.IsLeafInfoRequired,
- TunnelType: uint8(p.TunnelType),
- Label: p.Label,
- TunnelID: p.TunnelID.String(),
- })
-}
-
-func NewPathAttributePmsiTunnel(typ PmsiTunnelType, isLeafInfoRequired bool, label uint32, id PmsiTunnelIDInterface) *PathAttributePmsiTunnel {
- // Flags(1) + TunnelType(1) + Label(3) + TunnelID(variable)
- l := 5 + id.Len()
- t := BGP_ATTR_TYPE_PMSI_TUNNEL
- return &PathAttributePmsiTunnel{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- IsLeafInfoRequired: isLeafInfoRequired,
- TunnelType: typ,
- Label: label,
- TunnelID: id,
- }
-}
-
-func ParsePmsiTunnel(args []string) (*PathAttributePmsiTunnel, error) {
- // Format:
- // "<type>" ["leaf-info-required"] "<label>" "<tunnel-id>"
- if len(args) < 3 {
- return nil, fmt.Errorf("invalid pmsi tunnel arguments: %s", args)
- }
-
- pmsi := NewPathAttributePmsiTunnel(0, false, 0, nil)
-
- switch args[0] {
- case "ingress-repl":
- pmsi.TunnelType = PMSI_TUNNEL_TYPE_INGRESS_REPL
- default:
- typ, err := strconv.ParseUint(args[0], 10, 8)
- if err != nil {
- return nil, fmt.Errorf("invalid pmsi tunnel type: %s", args[0])
- }
- pmsi.TunnelType = PmsiTunnelType(typ)
- }
-
- indx := 1
- if args[indx] == "leaf-info-required" {
- pmsi.IsLeafInfoRequired = true
- indx++
- }
-
- label, err := strconv.ParseUint(args[indx], 10, 32)
- if err != nil {
- return nil, fmt.Errorf("invalid pmsi tunnel label: %s", args[indx])
- }
- pmsi.Label = uint32(label)
- indx++
-
- switch pmsi.TunnelType {
- case PMSI_TUNNEL_TYPE_INGRESS_REPL:
- ip := net.ParseIP(args[indx])
- if ip == nil {
- return nil, fmt.Errorf("invalid pmsi tunnel identifier: %s", args[indx])
- }
- pmsi.TunnelID = &IngressReplTunnelID{Value: ip}
- default:
- pmsi.TunnelID = &DefaultPmsiTunnelID{Value: []byte(args[indx])}
- }
-
- return pmsi, nil
-}
-
-type PathAttributeIP6ExtendedCommunities struct {
- PathAttribute
- Value []ExtendedCommunityInterface
-}
-
-func ParseIP6Extended(data []byte) (ExtendedCommunityInterface, error) {
- if len(data) < 8 {
- return nil, NewMessageError(BGP_ERROR_UPDATE_MESSAGE_ERROR, BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST, nil, "not all extended community bytes are available")
- }
- attrType := ExtendedCommunityAttrType(data[0])
- subtype := ExtendedCommunityAttrSubType(data[1])
- transitive := false
- switch attrType {
- case EC_TYPE_TRANSITIVE_IP6_SPECIFIC:
- transitive = true
- fallthrough
- case EC_TYPE_NON_TRANSITIVE_IP6_SPECIFIC:
- ipv6 := net.IP(data[2:18]).String()
- localAdmin := binary.BigEndian.Uint16(data[18:20])
- return NewIPv6AddressSpecificExtended(subtype, ipv6, localAdmin, transitive), nil
- case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL:
- return parseIP6FlowSpecExtended(data)
- default:
- return &UnknownExtended{
- Type: ExtendedCommunityAttrType(data[0]),
- Value: data[1:8],
- }, nil
- }
-}
-
-func (p *PathAttributeIP6ExtendedCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if p.Length%20 != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "extendedcommunities length isn't correct")
- }
- for len(value) >= 20 {
- e, err := ParseIP6Extended(value)
- if err != nil {
- return err
- }
- p.Value = append(p.Value, e)
- value = value[20:]
- }
- return nil
-}
-
-func (p *PathAttributeIP6ExtendedCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0)
- for _, p := range p.Value {
- ebuf, err := p.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, ebuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeIP6ExtendedCommunities) String() string {
- var buf []string
- for _, v := range p.Value {
- buf = append(buf, fmt.Sprintf("[%s]", v.String()))
- }
- return fmt.Sprintf("{Extcomms: %s}", strings.Join(buf, ","))
-}
-
-func (p *PathAttributeIP6ExtendedCommunities) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []ExtendedCommunityInterface `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeIP6ExtendedCommunities(value []ExtendedCommunityInterface) *PathAttributeIP6ExtendedCommunities {
- l := len(value) * 20
- t := BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES
- return &PathAttributeIP6ExtendedCommunities{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-type AigpTLVType uint8
-
-const (
- AIGP_TLV_UNKNOWN AigpTLVType = iota
- AIGP_TLV_IGP_METRIC
-)
-
-type AigpTLVInterface interface {
- Serialize() ([]byte, error)
- String() string
- MarshalJSON() ([]byte, error)
- Type() AigpTLVType
- Len() int
-}
-
-type AigpTLVDefault struct {
- typ AigpTLVType
- Value []byte
-}
-
-func (t *AigpTLVDefault) Serialize() ([]byte, error) {
- buf := make([]byte, 3+len(t.Value))
- buf[0] = uint8(t.Type())
- binary.BigEndian.PutUint16(buf[1:], uint16(3+len(t.Value)))
- copy(buf[3:], t.Value)
- return buf, nil
-}
-
-func (t *AigpTLVDefault) String() string {
- return fmt.Sprintf("{Type: %d, Value: %v}", t.Type(), t.Value)
-}
-
-func (t *AigpTLVDefault) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type AigpTLVType `json:"type"`
- Value []byte `json:"value"`
- }{
- Type: t.Type(),
- Value: t.Value,
- })
-}
-
-func (t *AigpTLVDefault) Type() AigpTLVType {
- return t.typ
-}
-
-func (t *AigpTLVDefault) Len() int {
- return 3 + len(t.Value) // Type(1) + Length(2) + Value(variable)
-}
-
-func NewAigpTLVDefault(typ AigpTLVType, value []byte) *AigpTLVDefault {
- return &AigpTLVDefault{
- typ: typ,
- Value: value,
- }
-}
-
-type AigpTLVIgpMetric struct {
- Metric uint64
-}
-
-func (t *AigpTLVIgpMetric) Serialize() ([]byte, error) {
- buf := make([]byte, 11)
- buf[0] = uint8(AIGP_TLV_IGP_METRIC)
- binary.BigEndian.PutUint16(buf[1:], uint16(11))
- binary.BigEndian.PutUint64(buf[3:], t.Metric)
- return buf, nil
-}
-
-func (t *AigpTLVIgpMetric) String() string {
- return fmt.Sprintf("{Metric: %d}", t.Metric)
-}
-
-func (t *AigpTLVIgpMetric) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type AigpTLVType `json:"type"`
- Metric uint64 `json:"metric"`
- }{
- Type: AIGP_TLV_IGP_METRIC,
- Metric: t.Metric,
- })
-}
-
-func NewAigpTLVIgpMetric(metric uint64) *AigpTLVIgpMetric {
- return &AigpTLVIgpMetric{
- Metric: metric,
- }
-}
-
-func (t *AigpTLVIgpMetric) Type() AigpTLVType {
- return AIGP_TLV_IGP_METRIC
-}
-
-func (t *AigpTLVIgpMetric) Len() int {
- return 11
-}
-
-type PathAttributeAigp struct {
- PathAttribute
- Values []AigpTLVInterface
-}
-
-func (p *PathAttributeAigp) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- for len(value) > 3 {
- typ := value[0]
- length := binary.BigEndian.Uint16(value[1:3])
- if len(value) < int(length) {
- break
- }
- v := value[3:length]
- switch AigpTLVType(typ) {
- case AIGP_TLV_IGP_METRIC:
- if len(v) < 8 {
- break
- }
- metric := binary.BigEndian.Uint64(v)
- p.Values = append(p.Values, NewAigpTLVIgpMetric(metric))
- default:
- p.Values = append(p.Values, NewAigpTLVDefault(AigpTLVType(typ), v))
- }
- value = value[length:]
- }
- if len(value) != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "Aigp length is incorrect")
- }
- return nil
-}
-
-func (p *PathAttributeAigp) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0)
- for _, t := range p.Values {
- bbuf, err := t.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeAigp) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- buf.WriteString("{Aigp: [")
- for _, v := range p.Values {
- buf.WriteString(v.String())
- }
- buf.WriteString("]}")
- return buf.String()
-}
-
-func (p *PathAttributeAigp) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []AigpTLVInterface `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Values,
- })
-}
-
-func NewPathAttributeAigp(values []AigpTLVInterface) *PathAttributeAigp {
- var l int
- for _, v := range values {
- l += v.Len()
- }
- t := BGP_ATTR_TYPE_AIGP
- return &PathAttributeAigp{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Values: values,
- }
-}
-
-type LargeCommunity struct {
- ASN uint32
- LocalData1 uint32
- LocalData2 uint32
-}
-
-func (c *LargeCommunity) Serialize() ([]byte, error) {
- buf := make([]byte, 12)
- binary.BigEndian.PutUint32(buf, c.ASN)
- binary.BigEndian.PutUint32(buf[4:], c.LocalData1)
- binary.BigEndian.PutUint32(buf[8:], c.LocalData2)
- return buf, nil
-}
-
-func (c *LargeCommunity) String() string {
- return fmt.Sprintf("%d:%d:%d", c.ASN, c.LocalData1, c.LocalData2)
-}
-
-func NewLargeCommunity(asn, data1, data2 uint32) *LargeCommunity {
- return &LargeCommunity{
- ASN: asn,
- LocalData1: data1,
- LocalData2: data2,
- }
-}
-
-func ParseLargeCommunity(value string) (*LargeCommunity, error) {
- elems := strings.Split(value, ":")
- if len(elems) != 3 {
- return nil, fmt.Errorf("invalid large community format")
- }
- v := make([]uint32, 0, 3)
- for _, elem := range elems {
- e, err := strconv.ParseUint(elem, 10, 32)
- if err != nil {
- return nil, fmt.Errorf("invalid large community format")
- }
- v = append(v, uint32(e))
- }
- return NewLargeCommunity(v[0], v[1], v[2]), nil
-}
-
-type PathAttributeLargeCommunities struct {
- PathAttribute
- Values []*LargeCommunity
-}
-
-func (p *PathAttributeLargeCommunities) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if p.Length%12 != 0 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "large communities length isn't correct")
- }
- p.Values = make([]*LargeCommunity, 0, p.Length/12)
- for len(value) >= 12 {
- asn := binary.BigEndian.Uint32(value[:4])
- data1 := binary.BigEndian.Uint32(value[4:8])
- data2 := binary.BigEndian.Uint32(value[8:12])
- p.Values = append(p.Values, NewLargeCommunity(asn, data1, data2))
- value = value[12:]
- }
- return nil
-}
-
-func (p *PathAttributeLargeCommunities) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 0, len(p.Values)*12)
- for _, t := range p.Values {
- bbuf, err := t.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return p.PathAttribute.Serialize(buf, options...)
-}
-
-func (p *PathAttributeLargeCommunities) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- buf.WriteString("{LargeCommunity: [ ")
- ss := []string{}
- for _, v := range p.Values {
- ss = append(ss, v.String())
- }
- buf.WriteString(strings.Join(ss, ", "))
- buf.WriteString("]}")
- return buf.String()
-}
-
-func (p *PathAttributeLargeCommunities) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []*LargeCommunity `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Values,
- })
-}
-
-func NewPathAttributeLargeCommunities(values []*LargeCommunity) *PathAttributeLargeCommunities {
- l := len(values) * 12
- t := BGP_ATTR_TYPE_LARGE_COMMUNITY
- return &PathAttributeLargeCommunities{
- PathAttribute: PathAttribute{
- Flags: getPathAttrFlags(t, l),
- Type: t,
- Length: uint16(l),
- },
- Values: values,
- }
-}
-
-type PathAttributeUnknown struct {
- PathAttribute
- Value []byte
-}
-
-func (p *PathAttributeUnknown) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- value, err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- p.Value = value
- return nil
-}
-
-func (p *PathAttributeUnknown) Serialize(options ...*MarshallingOption) ([]byte, error) {
- return p.PathAttribute.Serialize(p.Value, options...)
-}
-
-func (p *PathAttributeUnknown) String() string {
- return fmt.Sprintf("{Flags: %s, Type: %s, Value: %s}", p.Flags, p.Type, p.Value)
-}
-
-func (p *PathAttributeUnknown) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Flags BGPAttrFlag `json:"flags"`
- Type BGPAttrType `json:"type"`
- Value []byte `json:"value"`
- }{
- Flags: p.GetFlags(),
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-func NewPathAttributeUnknown(flags BGPAttrFlag, typ BGPAttrType, value []byte) *PathAttributeUnknown {
- l := len(value)
- if l > 255 {
- flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH
- }
- return &PathAttributeUnknown{
- PathAttribute: PathAttribute{
- Flags: flags,
- Type: typ,
- Length: uint16(l),
- },
- Value: value,
- }
-}
-
-func GetPathAttribute(data []byte) (PathAttributeInterface, error) {
- if len(data) < 2 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return nil, NewMessageError(eCode, eSubCode, data, "attribute type length is short")
- }
- switch BGPAttrType(data[1]) {
- case BGP_ATTR_TYPE_ORIGIN:
- return &PathAttributeOrigin{}, nil
- case BGP_ATTR_TYPE_AS_PATH:
- return &PathAttributeAsPath{}, nil
- case BGP_ATTR_TYPE_NEXT_HOP:
- return &PathAttributeNextHop{}, nil
- case BGP_ATTR_TYPE_MULTI_EXIT_DISC:
- return &PathAttributeMultiExitDisc{}, nil
- case BGP_ATTR_TYPE_LOCAL_PREF:
- return &PathAttributeLocalPref{}, nil
- case BGP_ATTR_TYPE_ATOMIC_AGGREGATE:
- return &PathAttributeAtomicAggregate{}, nil
- case BGP_ATTR_TYPE_AGGREGATOR:
- return &PathAttributeAggregator{}, nil
- case BGP_ATTR_TYPE_COMMUNITIES:
- return &PathAttributeCommunities{}, nil
- case BGP_ATTR_TYPE_ORIGINATOR_ID:
- return &PathAttributeOriginatorId{}, nil
- case BGP_ATTR_TYPE_CLUSTER_LIST:
- return &PathAttributeClusterList{}, nil
- case BGP_ATTR_TYPE_MP_REACH_NLRI:
- return &PathAttributeMpReachNLRI{}, nil
- case BGP_ATTR_TYPE_MP_UNREACH_NLRI:
- return &PathAttributeMpUnreachNLRI{}, nil
- case BGP_ATTR_TYPE_EXTENDED_COMMUNITIES:
- return &PathAttributeExtendedCommunities{}, nil
- case BGP_ATTR_TYPE_AS4_PATH:
- return &PathAttributeAs4Path{}, nil
- case BGP_ATTR_TYPE_AS4_AGGREGATOR:
- return &PathAttributeAs4Aggregator{}, nil
- case BGP_ATTR_TYPE_TUNNEL_ENCAP:
- return &PathAttributeTunnelEncap{}, nil
- case BGP_ATTR_TYPE_PMSI_TUNNEL:
- return &PathAttributePmsiTunnel{}, nil
- case BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES:
- return &PathAttributeIP6ExtendedCommunities{}, nil
- case BGP_ATTR_TYPE_AIGP:
- return &PathAttributeAigp{}, nil
- case BGP_ATTR_TYPE_LARGE_COMMUNITY:
- return &PathAttributeLargeCommunities{}, nil
- }
- return &PathAttributeUnknown{}, nil
-}
-
-type BGPUpdate struct {
- WithdrawnRoutesLen uint16
- WithdrawnRoutes []*IPAddrPrefix
- TotalPathAttributeLen uint16
- PathAttributes []PathAttributeInterface
- NLRI []*IPAddrPrefix
-}
-
-func (msg *BGPUpdate) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- var strongestError error
-
- // cache error codes
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
-
- // check withdrawn route length
- if len(data) < 2 {
- return NewMessageError(eCode, eSubCode, nil, "message length isn't enough for withdrawn route length")
- }
-
- msg.WithdrawnRoutesLen = binary.BigEndian.Uint16(data[0:2])
- data = data[2:]
-
- // check withdrawn route
- if len(data) < int(msg.WithdrawnRoutesLen) {
- return NewMessageError(eCode, eSubCode, nil, "withdrawn route length exceeds message length")
- }
-
- addpathLen := 0
- if IsAddPathEnabled(true, RF_IPv4_UC, options) {
- addpathLen = 4
- }
-
- msg.WithdrawnRoutes = make([]*IPAddrPrefix, 0, msg.WithdrawnRoutesLen)
- for routelen := msg.WithdrawnRoutesLen; routelen > 0; {
- w := &IPAddrPrefix{}
- err := w.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- routelen -= uint16(w.Len(options...) + addpathLen)
- if len(data) < w.Len(options...)+addpathLen {
- return NewMessageError(eCode, eSubCode, nil, "Withdrawn route length is short")
- }
- data = data[w.Len(options...)+addpathLen:]
- msg.WithdrawnRoutes = append(msg.WithdrawnRoutes, w)
- }
-
- // check path total attribute length
- if len(data) < 2 {
- return NewMessageError(eCode, eSubCode, nil, "message length isn't enough for path total attribute length")
- }
-
- msg.TotalPathAttributeLen = binary.BigEndian.Uint16(data[0:2])
- data = data[2:]
-
- // check path attribute
- if len(data) < int(msg.TotalPathAttributeLen) {
- return NewMessageError(eCode, eSubCode, nil, "path total attribute length exceeds message length")
- }
-
- msg.PathAttributes = []PathAttributeInterface{}
- for pathlen := msg.TotalPathAttributeLen; pathlen > 0; {
- var e error
- if pathlen < 3 {
- e = NewMessageErrorWithErrorHandling(
- eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, "insufficient data to decode")
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- data = data[pathlen:]
- break
- }
- p, err := GetPathAttribute(data)
- if err != nil {
- return err
- }
-
- err = p.DecodeFromBytes(data, options...)
- if err != nil {
- e = err.(*MessageError)
- if e.(*MessageError).SubTypeCode == BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR {
- e.(*MessageError).ErrorHandling = ERROR_HANDLING_TREAT_AS_WITHDRAW
- } else {
- e.(*MessageError).ErrorHandling = getErrorHandlingFromPathAttribute(p.GetType())
- e.(*MessageError).ErrorAttribute = &p
- }
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- }
- pathlen -= uint16(p.Len(options...))
- if len(data) < p.Len(options...) {
- e = NewMessageErrorWithErrorHandling(
- eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, "attribute length is short")
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- }
- data = data[p.Len(options...):]
- if e == nil || e.(*MessageError).ErrorHandling != ERROR_HANDLING_ATTRIBUTE_DISCARD {
- msg.PathAttributes = append(msg.PathAttributes, p)
- }
- }
-
- msg.NLRI = make([]*IPAddrPrefix, 0)
- for restlen := len(data); restlen > 0; {
- n := &IPAddrPrefix{}
- err := n.DecodeFromBytes(data, options...)
- if err != nil {
- return err
- }
- restlen -= n.Len(options...) + addpathLen
- if len(data) < n.Len(options...)+addpathLen {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is short")
- }
- if n.Len(options...) > 32 {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is too long")
- }
- data = data[n.Len(options...)+addpathLen:]
- msg.NLRI = append(msg.NLRI, n)
- }
-
- return strongestError
-}
-
-func (msg *BGPUpdate) Serialize(options ...*MarshallingOption) ([]byte, error) {
- wbuf := make([]byte, 2)
- for _, w := range msg.WithdrawnRoutes {
- onewbuf, err := w.Serialize(options...)
- if err != nil {
- return nil, err
- }
- wbuf = append(wbuf, onewbuf...)
- }
- msg.WithdrawnRoutesLen = uint16(len(wbuf) - 2)
- binary.BigEndian.PutUint16(wbuf, msg.WithdrawnRoutesLen)
-
- pbuf := make([]byte, 2)
- for _, p := range msg.PathAttributes {
- onepbuf, err := p.Serialize(options...)
- if err != nil {
- return nil, err
- }
- pbuf = append(pbuf, onepbuf...)
- }
- msg.TotalPathAttributeLen = uint16(len(pbuf) - 2)
- binary.BigEndian.PutUint16(pbuf, msg.TotalPathAttributeLen)
-
- buf := append(wbuf, pbuf...)
- for _, n := range msg.NLRI {
- nbuf, err := n.Serialize(options...)
- if err != nil {
- return nil, err
- }
- buf = append(buf, nbuf...)
- }
- return buf, nil
-}
-
-func (msg *BGPUpdate) IsEndOfRib() (bool, RouteFamily) {
- if len(msg.WithdrawnRoutes) == 0 && len(msg.NLRI) == 0 {
- if len(msg.PathAttributes) == 0 {
- return true, RF_IPv4_UC
- } else if len(msg.PathAttributes) == 1 && msg.PathAttributes[0].GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI {
- unreach := msg.PathAttributes[0].(*PathAttributeMpUnreachNLRI)
- if len(unreach.Value) == 0 {
- return true, AfiSafiToRouteFamily(unreach.AFI, unreach.SAFI)
- }
- }
- }
- return false, RouteFamily(0)
-}
-
-func TreatAsWithdraw(msg *BGPUpdate) *BGPUpdate {
- withdraw := &BGPUpdate{
- WithdrawnRoutesLen: 0,
- WithdrawnRoutes: []*IPAddrPrefix{},
- TotalPathAttributeLen: 0,
- PathAttributes: make([]PathAttributeInterface, 0, len(msg.PathAttributes)),
- NLRI: []*IPAddrPrefix{},
- }
- withdraw.WithdrawnRoutes = append(msg.WithdrawnRoutes, msg.NLRI...)
- var unreach []AddrPrefixInterface
-
- for _, p := range msg.PathAttributes {
- switch nlri := p.(type) {
- case *PathAttributeMpReachNLRI:
- unreach = append(unreach, nlri.Value...)
- case *PathAttributeMpUnreachNLRI:
- unreach = append(unreach, nlri.Value...)
- }
- }
- if len(unreach) != 0 {
- withdraw.PathAttributes = append(withdraw.PathAttributes, NewPathAttributeMpUnreachNLRI(unreach))
- }
- return withdraw
-}
-
-func NewBGPUpdateMessage(withdrawnRoutes []*IPAddrPrefix, pathattrs []PathAttributeInterface, nlri []*IPAddrPrefix) *BGPMessage {
- return &BGPMessage{
- Header: BGPHeader{Type: BGP_MSG_UPDATE},
- Body: &BGPUpdate{0, withdrawnRoutes, 0, pathattrs, nlri},
- }
-}
-
-func NewEndOfRib(family RouteFamily) *BGPMessage {
- if family == RF_IPv4_UC {
- return NewBGPUpdateMessage(nil, nil, nil)
- } else {
- afi, safi := RouteFamilyToAfiSafi(family)
- t := BGP_ATTR_TYPE_MP_UNREACH_NLRI
- unreach := &PathAttributeMpUnreachNLRI{
- PathAttribute: PathAttribute{
- Flags: PathAttrFlags[t],
- Type: t,
- },
- AFI: afi,
- SAFI: safi,
- }
- return NewBGPUpdateMessage(nil, []PathAttributeInterface{unreach}, nil)
- }
-}
-
-type BGPNotification struct {
- ErrorCode uint8
- ErrorSubcode uint8
- Data []byte
-}
-
-func (msg *BGPNotification) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if len(data) < 2 {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all Notificaiton bytes available")
- }
- msg.ErrorCode = data[0]
- msg.ErrorSubcode = data[1]
- if len(data) > 2 {
- msg.Data = data[2:]
- }
- return nil
-}
-
-func (msg *BGPNotification) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 2)
- buf[0] = msg.ErrorCode
- buf[1] = msg.ErrorSubcode
- buf = append(buf, msg.Data...)
- return buf, nil
-}
-
-func NewBGPNotificationMessage(errcode uint8, errsubcode uint8, data []byte) *BGPMessage {
- return &BGPMessage{
- Header: BGPHeader{Type: BGP_MSG_NOTIFICATION},
- Body: &BGPNotification{errcode, errsubcode, data},
- }
-}
-
-type BGPKeepAlive struct {
-}
-
-func (msg *BGPKeepAlive) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- return nil
-}
-
-func (msg *BGPKeepAlive) Serialize(options ...*MarshallingOption) ([]byte, error) {
- return nil, nil
-}
-
-func NewBGPKeepAliveMessage() *BGPMessage {
- return &BGPMessage{
- Header: BGPHeader{Len: 19, Type: BGP_MSG_KEEPALIVE},
- Body: &BGPKeepAlive{},
- }
-}
-
-type BGPRouteRefresh struct {
- AFI uint16
- Demarcation uint8
- SAFI uint8
-}
-
-func (msg *BGPRouteRefresh) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- if len(data) < 4 {
- return NewMessageError(BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR, BGP_ERROR_SUB_INVALID_MESSAGE_LENGTH, nil, "Not all RouteRefresh bytes available")
- }
- msg.AFI = binary.BigEndian.Uint16(data[0:2])
- msg.Demarcation = data[2]
- msg.SAFI = data[3]
- return nil
-}
-
-func (msg *BGPRouteRefresh) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], msg.AFI)
- buf[2] = msg.Demarcation
- buf[3] = msg.SAFI
- return buf, nil
-}
-
-func NewBGPRouteRefreshMessage(afi uint16, demarcation uint8, safi uint8) *BGPMessage {
- return &BGPMessage{
- Header: BGPHeader{Type: BGP_MSG_ROUTE_REFRESH},
- Body: &BGPRouteRefresh{afi, demarcation, safi},
- }
-}
-
-type BGPBody interface {
- DecodeFromBytes([]byte, ...*MarshallingOption) error
- Serialize(...*MarshallingOption) ([]byte, error)
-}
-
-const (
- BGP_HEADER_LENGTH = 19
- BGP_MAX_MESSAGE_LENGTH = 4096
-)
-
-type BGPHeader struct {
- Marker []byte
- Len uint16
- Type uint8
-}
-
-func (msg *BGPHeader) DecodeFromBytes(data []byte, options ...*MarshallingOption) error {
- // minimum BGP message length
- if uint16(len(data)) < BGP_HEADER_LENGTH {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "not all BGP message header")
- }
-
- msg.Len = binary.BigEndian.Uint16(data[16:18])
- if int(msg.Len) < BGP_HEADER_LENGTH {
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "unknown message type")
- }
-
- msg.Type = data[18]
- return nil
-}
-
-func (msg *BGPHeader) Serialize(options ...*MarshallingOption) ([]byte, error) {
- buf := make([]byte, 19)
- for i := range buf[:16] {
- buf[i] = 0xff
- }
- binary.BigEndian.PutUint16(buf[16:18], msg.Len)
- buf[18] = msg.Type
- return buf, nil
-}
-
-type BGPMessage struct {
- Header BGPHeader
- Body BGPBody
-}
-
-func parseBody(h *BGPHeader, data []byte, options ...*MarshallingOption) (*BGPMessage, error) {
- if len(data) < int(h.Len)-BGP_HEADER_LENGTH {
- return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "Not all BGP message bytes available")
- }
- msg := &BGPMessage{Header: *h}
-
- switch msg.Header.Type {
- case BGP_MSG_OPEN:
- msg.Body = &BGPOpen{}
- case BGP_MSG_UPDATE:
- msg.Body = &BGPUpdate{}
- case BGP_MSG_NOTIFICATION:
- msg.Body = &BGPNotification{}
- case BGP_MSG_KEEPALIVE:
- msg.Body = &BGPKeepAlive{}
- case BGP_MSG_ROUTE_REFRESH:
- msg.Body = &BGPRouteRefresh{}
- default:
- return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE, nil, "unknown message type")
- }
- err := msg.Body.DecodeFromBytes(data, options...)
- return msg, err
-}
-
-func ParseBGPMessage(data []byte, options ...*MarshallingOption) (*BGPMessage, error) {
- h := &BGPHeader{}
- err := h.DecodeFromBytes(data, options...)
- if err != nil {
- return nil, err
- }
-
- if int(h.Len) > len(data) {
- return nil, NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, nil, "unknown message type")
- }
-
- return parseBody(h, data[19:h.Len], options...)
-}
-
-func ParseBGPBody(h *BGPHeader, data []byte, options ...*MarshallingOption) (*BGPMessage, error) {
- return parseBody(h, data, options...)
-}
-
-func (msg *BGPMessage) Serialize(options ...*MarshallingOption) ([]byte, error) {
- b, err := msg.Body.Serialize(options...)
- if err != nil {
- return nil, err
- }
- if msg.Header.Len == 0 {
- if 19+len(b) > BGP_MAX_MESSAGE_LENGTH {
- return nil, NewMessageError(0, 0, nil, fmt.Sprintf("too long message length %d", 19+len(b)))
- }
- msg.Header.Len = 19 + uint16(len(b))
- }
- h, err := msg.Header.Serialize(options...)
- if err != nil {
- return nil, err
- }
- return append(h, b...), nil
-}
-
-type ErrorHandling int
-
-const (
- ERROR_HANDLING_NONE ErrorHandling = iota
- ERROR_HANDLING_ATTRIBUTE_DISCARD
- ERROR_HANDLING_TREAT_AS_WITHDRAW
- ERROR_HANDLING_AFISAFI_DISABLE
- ERROR_HANDLING_SESSION_RESET
-)
-
-func getErrorHandlingFromPathAttribute(t BGPAttrType) ErrorHandling {
- switch t {
- case BGP_ATTR_TYPE_ORIGIN:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_AS_PATH:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_AS4_PATH:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_NEXT_HOP:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_MULTI_EXIT_DISC:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_LOCAL_PREF:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_ATOMIC_AGGREGATE:
- return ERROR_HANDLING_ATTRIBUTE_DISCARD
- case BGP_ATTR_TYPE_AGGREGATOR:
- return ERROR_HANDLING_ATTRIBUTE_DISCARD
- case BGP_ATTR_TYPE_AS4_AGGREGATOR:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_COMMUNITIES:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_ORIGINATOR_ID:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_CLUSTER_LIST:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_MP_REACH_NLRI:
- return ERROR_HANDLING_AFISAFI_DISABLE
- case BGP_ATTR_TYPE_MP_UNREACH_NLRI:
- return ERROR_HANDLING_AFISAFI_DISABLE
- case BGP_ATTR_TYPE_EXTENDED_COMMUNITIES:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_IP6_EXTENDED_COMMUNITIES:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_PMSI_TUNNEL:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_LARGE_COMMUNITY:
- return ERROR_HANDLING_TREAT_AS_WITHDRAW
- case BGP_ATTR_TYPE_TUNNEL_ENCAP:
- return ERROR_HANDLING_ATTRIBUTE_DISCARD
- case BGP_ATTR_TYPE_AIGP:
- return ERROR_HANDLING_ATTRIBUTE_DISCARD
- default:
- return ERROR_HANDLING_ATTRIBUTE_DISCARD
- }
-}
-
-type MessageError struct {
- TypeCode uint8
- SubTypeCode uint8
- Data []byte
- Message string
- ErrorHandling ErrorHandling
- ErrorAttribute *PathAttributeInterface
-}
-
-func NewMessageError(typeCode, subTypeCode uint8, data []byte, msg string) error {
- return &MessageError{
- TypeCode: typeCode,
- SubTypeCode: subTypeCode,
- Data: data,
- ErrorHandling: ERROR_HANDLING_SESSION_RESET,
- ErrorAttribute: nil,
- Message: msg,
- }
-}
-
-func NewMessageErrorWithErrorHandling(typeCode, subTypeCode uint8, data []byte, errorHandling ErrorHandling, errorAttribute *PathAttributeInterface, msg string) error {
- return &MessageError{
- TypeCode: typeCode,
- SubTypeCode: subTypeCode,
- Data: data,
- ErrorHandling: errorHandling,
- ErrorAttribute: errorAttribute,
- Message: msg,
- }
-}
-
-func (e *MessageError) Error() string {
- return e.Message
-}
-
-func (e *MessageError) Stronger(err error) bool {
- if err == nil {
- return true
- }
- if msgErr, ok := err.(*MessageError); ok {
- return e.ErrorHandling > msgErr.ErrorHandling
- }
- return false
-}
-
-func (e *TwoOctetAsSpecificExtended) Flat() map[string]string {
- if e.SubType == EC_SUBTYPE_ROUTE_TARGET {
- return map[string]string{"routeTarget": e.String()}
- }
- return map[string]string{}
-}
-
-func (e *ColorExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *EncapExtended) Flat() map[string]string {
- return map[string]string{"encaspulation": e.TunnelType.String()}
-}
-
-func (e *DefaultGatewayExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *ValidationExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *OpaqueExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *IPv4AddressSpecificExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *IPv6AddressSpecificExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *FourOctetAsSpecificExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *ESILabelExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *ESImportRouteTarget) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *MacMobilityExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *RouterMacExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *TrafficRateExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *TrafficRemarkExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *RedirectIPv4AddressSpecificExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *RedirectIPv6AddressSpecificExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *RedirectFourOctetAsSpecificExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *UnknownExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (e *TrafficActionExtended) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (p *PathAttributeExtendedCommunities) Flat() map[string]string {
- flat := map[string]string{}
- for _, ec := range p.Value {
- FlatUpdate(flat, ec.Flat())
- }
- return flat
-}
-
-func (p *PathAttribute) Flat() map[string]string {
- return map[string]string{}
-}
-
-func (l *LabeledVPNIPAddrPrefix) Flat() map[string]string {
- prefixLen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len()))
- return map[string]string{
- "Prefix": l.IPAddrPrefixDefault.Prefix.String(),
- "PrefixLen": fmt.Sprintf("%d", prefixLen),
- "NLRI": l.String(),
- "Label": l.Labels.String(),
- }
-}
-
-func (p *IPAddrPrefixDefault) Flat() map[string]string {
- l := strings.Split(p.String(), "/")
- if len(l) == 2 {
- return map[string]string{
- "Prefix": l[0],
- "PrefixLen": l[1],
- }
- }
- return map[string]string{}
-}
-
-func (l *EVPNNLRI) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *RouteTargetMembershipNLRI) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *FlowSpecIPv4Unicast) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *FlowSpecIPv4VPN) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *FlowSpecIPv6Unicast) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *FlowSpecIPv6VPN) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *FlowSpecL2VPN) Flat() map[string]string {
- return map[string]string{}
-}
-func (l *OpaqueNLRI) Flat() map[string]string {
- return map[string]string{}
-}
-
-// Update a Flat representation by adding elements of the second
-// one. If two elements use same keys, values are separated with
-// ';'. In this case, it returns an error but the update has been
-// realized.
-func FlatUpdate(f1, f2 map[string]string) error {
- conflict := false
- for k2, v2 := range f2 {
- if v1, ok := f1[k2]; ok {
- f1[k2] = v1 + ";" + v2
- conflict = true
- } else {
- f1[k2] = v2
- }
- }
- if conflict {
- return fmt.Errorf("Keys conflict")
- } else {
- return nil
- }
-}
diff --git a/packet/bgp/bgp_race_test.go b/packet/bgp/bgp_race_test.go
deleted file mode 100644
index 08038200..00000000
--- a/packet/bgp/bgp_race_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (C) 2018 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// +build race
-
-package bgp
-
-import (
- "testing"
- "time"
-)
-
-// Test_RaceCondition detects data races when serialization.
-// Currently tests only attributes contained in UPDATE message.
-func Test_RaceCondition(t *testing.T) {
- m := NewTestBGPUpdateMessage()
- updateBody := m.Body.(*BGPUpdate)
-
- go func(body *BGPUpdate) {
- for _, v := range body.WithdrawnRoutes {
- v.Serialize()
- }
- for _, v := range body.PathAttributes {
- v.Serialize()
- }
- for _, v := range body.NLRI {
- v.Serialize()
- }
- }(updateBody)
-
- time.Sleep(time.Second)
-
- updateBody.Serialize()
-}
diff --git a/packet/bgp/bgp_test.go b/packet/bgp/bgp_test.go
deleted file mode 100644
index a4801f27..00000000
--- a/packet/bgp/bgp_test.go
+++ /dev/null
@@ -1,1194 +0,0 @@
-// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bgp
-
-import (
- "bytes"
- "encoding/binary"
- "net"
- "reflect"
- "strconv"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func keepalive() *BGPMessage {
- return NewBGPKeepAliveMessage()
-}
-
-func notification() *BGPMessage {
- return NewBGPNotificationMessage(1, 2, nil)
-}
-
-func refresh() *BGPMessage {
- return NewBGPRouteRefreshMessage(1, 2, 10)
-}
-
-var result []string
-
-func BenchmarkNormalizeFlowSpecOpValues(b *testing.B) {
- var r []string
- for n := 0; n < b.N; n++ {
- r = normalizeFlowSpecOpValues([]string{"&<=80"})
- }
- result = r
-}
-
-func Test_Message(t *testing.T) {
- l := []*BGPMessage{keepalive(), notification(), refresh(), NewTestBGPOpenMessage(), NewTestBGPUpdateMessage()}
-
- for _, m1 := range l {
- buf1, err := m1.Serialize()
- assert.NoError(t, err)
-
- t.Log("LEN =", len(buf1))
- m2, err := ParseBGPMessage(buf1)
- assert.NoError(t, err)
-
- // FIXME: shouldn't but workaround for some structs.
- _, err = m2.Serialize()
- assert.NoError(t, err)
-
- assert.True(t, reflect.DeepEqual(m1, m2))
- }
-}
-
-func Test_IPAddrPrefixString(t *testing.T) {
- ipv4 := NewIPAddrPrefix(24, "129.6.10.0")
- assert.Equal(t, "129.6.10.0/24", ipv4.String())
- ipv4 = NewIPAddrPrefix(24, "129.6.10.1")
- assert.Equal(t, "129.6.10.0/24", ipv4.String())
- ipv4 = NewIPAddrPrefix(22, "129.6.129.0")
- assert.Equal(t, "129.6.128.0/22", ipv4.String())
-
- ipv6 := NewIPv6AddrPrefix(64, "3343:faba:3903::0")
- assert.Equal(t, "3343:faba:3903::/64", ipv6.String())
- ipv6 = NewIPv6AddrPrefix(64, "3343:faba:3903::1")
- assert.Equal(t, "3343:faba:3903::/64", ipv6.String())
- ipv6 = NewIPv6AddrPrefix(63, "3343:faba:3903:129::0")
- assert.Equal(t, "3343:faba:3903:128::/63", ipv6.String())
-}
-
-func Test_RouteTargetMembershipNLRIString(t *testing.T) {
- assert := assert.New(t)
-
- // TwoOctetAsSpecificExtended
- buf := make([]byte, 13)
- buf[0] = 96 // in bit length
- binary.BigEndian.PutUint32(buf[1:5], 65546)
- buf[5] = byte(EC_TYPE_TRANSITIVE_TWO_OCTET_AS_SPECIFIC) // typehigh
- binary.BigEndian.PutUint16(buf[7:9], 65000)
- binary.BigEndian.PutUint32(buf[9:], 65546)
- r := &RouteTargetMembershipNLRI{}
- err := r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:65000:65546", r.String())
- buf, err = r.Serialize()
- assert.Equal(nil, err)
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:65000:65546", r.String())
-
- // IPv4AddressSpecificExtended
- buf = make([]byte, 13)
- buf[0] = 96 // in bit length
- binary.BigEndian.PutUint32(buf[1:5], 65546)
- buf[5] = byte(EC_TYPE_TRANSITIVE_IP4_SPECIFIC) // typehigh
- ip := net.ParseIP("10.0.0.1").To4()
- copy(buf[7:11], []byte(ip))
- binary.BigEndian.PutUint16(buf[11:], 65000)
- r = &RouteTargetMembershipNLRI{}
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:10.0.0.1:65000", r.String())
- buf, err = r.Serialize()
- assert.Equal(nil, err)
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:10.0.0.1:65000", r.String())
-
- // FourOctetAsSpecificExtended
- buf = make([]byte, 13)
- buf[0] = 96 // in bit length
- binary.BigEndian.PutUint32(buf[1:5], 65546)
- buf[5] = byte(EC_TYPE_TRANSITIVE_FOUR_OCTET_AS_SPECIFIC) // typehigh
- buf[6] = byte(EC_SUBTYPE_ROUTE_TARGET) // subtype
- binary.BigEndian.PutUint32(buf[7:], 65546)
- binary.BigEndian.PutUint16(buf[11:], 65000)
- r = &RouteTargetMembershipNLRI{}
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:1.10:65000", r.String())
- buf, err = r.Serialize()
- assert.Equal(nil, err)
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:1.10:65000", r.String())
-
- // OpaqueExtended
- buf = make([]byte, 13)
- buf[0] = 96 // in bit length
- binary.BigEndian.PutUint32(buf[1:5], 65546)
- buf[5] = byte(EC_TYPE_TRANSITIVE_OPAQUE) // typehigh
- binary.BigEndian.PutUint32(buf[9:], 1000000)
- r = &RouteTargetMembershipNLRI{}
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:1000000", r.String())
- buf, err = r.Serialize()
- assert.Equal(nil, err)
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:1000000", r.String())
-
- // Unknown
- buf = make([]byte, 13)
- buf[0] = 96 // in bit length
- binary.BigEndian.PutUint32(buf[1:5], 65546)
- buf[5] = 0x04 // typehigh
- binary.BigEndian.PutUint32(buf[9:], 1000000)
- r = &RouteTargetMembershipNLRI{}
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:1000000", r.String())
- buf, err = r.Serialize()
- assert.Equal(nil, err)
- err = r.DecodeFromBytes(buf)
- assert.Equal(nil, err)
- assert.Equal("65546:1000000", r.String())
-
-}
-
-func Test_MalformedUpdateMsg(t *testing.T) {
- assert := assert.New(t)
-
- // Invalid AGGREGATOR
- bufin := []byte{
- 0x00, 0x00, // Withdraws(0)
- 0x00, 0x16, // Attrs Len(22)
- 0xc0, 0x07, 0x05, // Flag, Type(7), Length(5)
- 0x00, 0x00, 0x00, 0x64, // aggregator - invalid length
- 0x00,
- 0x40, 0x01, 0x01, 0x00, // Attr(ORIGIN)
- 0x40, 0x03, 0x04, 0xc0, // Attr(NEXT_HOP)
- 0xa8, 0x01, 0x64,
- 0x40, 0x02, 0x00, // Attr(AS_PATH)
- }
-
- u := &BGPUpdate{}
- err := u.DecodeFromBytes(bufin)
- assert.Error(err)
- assert.Equal(ERROR_HANDLING_ATTRIBUTE_DISCARD, err.(*MessageError).ErrorHandling)
-
- // Invalid MP_REACH_NLRI
- bufin = []byte{
- 0x00, 0x00, // Withdraws(0)
- 0x00, 0x27, // Attrs Len(39)
- 0x80, 0x0e, 0x1d, // Flag, Type(14), Length(29)
- 0x00, 0x02, 0x01, // afi(2), safi(1)
- 0x0f, 0x00, 0x00, 0x00, // nexthop - invalid nexthop length
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0xff,
- 0xff, 0x0a, 0x00, 0x00,
- 0x00, // SNPA(0)
- 0x40, 0x20, 0x01, 0x0d, // NLRI
- 0xb8, 0x00, 0x01, 0x00,
- 0x00,
- 0x40, 0x01, 0x01, 0x00, // Attr(ORIGIN)
- 0x40, 0x02, 0x00, // Attr(AS_PATH)
- }
-
- err = u.DecodeFromBytes(bufin)
- assert.Error(err)
- assert.Equal(ERROR_HANDLING_AFISAFI_DISABLE, err.(*MessageError).ErrorHandling)
-
- // Invalid flag
- bufin = []byte{
- 0x00, 0x00, // Withdraws(0)
- 0x00, 0x0e, // Attrs Len(14)
- 0xc0, 0x01, 0x01, 0x00, // Attr(ORIGIN) - invalid flag
- 0x40, 0x03, 0x04, 0xc0, // Attr(NEXT_HOP)
- 0xa8, 0x01, 0x64,
- 0x40, 0x02, 0x00, // Attr(AS_PATH)
- }
-
- err = u.DecodeFromBytes(bufin)
- assert.Error(err)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, err.(*MessageError).ErrorHandling)
-
- // Invalid AGGREGATOR and MULTI_EXIT_DESC
- bufin = []byte{
- 0x00, 0x00, // Withdraws(0)
- 0x00, 0x1e, // Attrs Len(30)
- 0xc0, 0x07, 0x05, 0x00, // Attr(AGGREGATOR) - invalid length
- 0x00, 0x00, 0x64, 0x00,
- 0x80, 0x04, 0x05, 0x00, // Attr(MULTI_EXIT_DESC) - invalid length
- 0x00, 0x00, 0x00, 0x64,
- 0x40, 0x01, 0x01, 0x00, // Attr(ORIGIN)
- 0x40, 0x02, 0x00, // Attr(AS_PATH)
- 0x40, 0x03, 0x04, 0xc0, // Attr(NEXT_HOP)
- 0xa8, 0x01, 0x64,
- 0x20, 0xc8, 0xc8, 0xc8, // NLRI
- 0xc8,
- }
-
- err = u.DecodeFromBytes(bufin)
- assert.Error(err)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, err.(*MessageError).ErrorHandling)
-}
-
-func Test_RFC5512(t *testing.T) {
- assert := assert.New(t)
-
- buf := make([]byte, 8)
- buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
- buf[1] = byte(EC_SUBTYPE_COLOR)
- binary.BigEndian.PutUint32(buf[4:], 1000000)
- ec, err := ParseExtended(buf)
- assert.Equal(nil, err)
- assert.Equal("1000000", ec.String())
- buf, err = ec.Serialize()
- assert.Equal(nil, err)
- assert.Equal([]byte{0x3, 0xb, 0x0, 0x0, 0x0, 0xf, 0x42, 0x40}, buf)
-
- buf = make([]byte, 8)
- buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
- buf[1] = byte(EC_SUBTYPE_ENCAPSULATION)
- binary.BigEndian.PutUint16(buf[6:], uint16(TUNNEL_TYPE_VXLAN))
- ec, err = ParseExtended(buf)
- assert.Equal(nil, err)
- assert.Equal("VXLAN", ec.String())
- buf, err = ec.Serialize()
- assert.Equal(nil, err)
- assert.Equal([]byte{0x3, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8}, buf)
-
- tlv := NewTunnelEncapTLV(TUNNEL_TYPE_VXLAN, []TunnelEncapSubTLVInterface{NewTunnelEncapSubTLVColor(10)})
- attr := NewPathAttributeTunnelEncap([]*TunnelEncapTLV{tlv})
-
- buf1, err := attr.Serialize()
- assert.Equal(nil, err)
-
- p, err := GetPathAttribute(buf1)
- assert.Equal(nil, err)
-
- err = p.DecodeFromBytes(buf1)
- assert.Equal(nil, err)
-
- buf2, err := p.Serialize()
- assert.Equal(nil, err)
- assert.Equal(buf1, buf2)
-
- n1 := NewEncapNLRI("10.0.0.1")
- buf1, err = n1.Serialize()
- assert.Equal(nil, err)
-
- n2 := NewEncapNLRI("")
- err = n2.DecodeFromBytes(buf1)
- assert.Equal(nil, err)
- assert.Equal("10.0.0.1", n2.String())
-
- n3 := NewEncapv6NLRI("2001::1")
- buf1, err = n3.Serialize()
- assert.Equal(nil, err)
-
- n4 := NewEncapv6NLRI("")
- err = n4.DecodeFromBytes(buf1)
- assert.Equal(nil, err)
- assert.Equal("2001::1", n4.String())
-}
-
-func Test_ASLen(t *testing.T) {
- assert := assert.New(t)
-
- aspath := AsPathParam{
- Num: 2,
- AS: []uint16{65000, 65001},
- }
- aspath.Type = BGP_ASPATH_ATTR_TYPE_SEQ
- assert.Equal(2, aspath.ASLen())
-
- aspath.Type = BGP_ASPATH_ATTR_TYPE_SET
- assert.Equal(1, aspath.ASLen())
-
- aspath.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SEQ
- assert.Equal(0, aspath.ASLen())
-
- aspath.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SET
- assert.Equal(0, aspath.ASLen())
-
- as4path := As4PathParam{
- Num: 2,
- AS: []uint32{65000, 65001},
- }
- as4path.Type = BGP_ASPATH_ATTR_TYPE_SEQ
- assert.Equal(2, as4path.ASLen())
-
- as4path.Type = BGP_ASPATH_ATTR_TYPE_SET
- assert.Equal(1, as4path.ASLen())
-
- as4path.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SEQ
- assert.Equal(0, as4path.ASLen())
-
- as4path.Type = BGP_ASPATH_ATTR_TYPE_CONFED_SET
- assert.Equal(0, as4path.ASLen())
-
-}
-
-func Test_MPLSLabelStack(t *testing.T) {
- assert := assert.New(t)
- mpls := NewMPLSLabelStack()
- buf, err := mpls.Serialize()
- assert.Nil(err)
- assert.Equal(true, bytes.Equal(buf, []byte{0, 0, 1}))
-
- mpls = &MPLSLabelStack{}
- assert.Nil(mpls.DecodeFromBytes(buf))
- assert.Equal(1, len(mpls.Labels))
- assert.Equal(uint32(0), mpls.Labels[0])
-
- mpls = NewMPLSLabelStack(WITHDRAW_LABEL)
- buf, err = mpls.Serialize()
- assert.Nil(err)
- assert.Equal(true, bytes.Equal(buf, []byte{128, 0, 0}))
-
- mpls = &MPLSLabelStack{}
- assert.Nil(mpls.DecodeFromBytes(buf))
- assert.Equal(1, len(mpls.Labels))
- assert.Equal(WITHDRAW_LABEL, mpls.Labels[0])
-}
-
-func Test_FlowSpecNlri(t *testing.T) {
- assert := assert.New(t)
- cmp := make([]FlowSpecComponentInterface, 0)
- cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, TCP)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1}))
- item2 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 20)
- item3 := NewFlowSpecComponentItem(DEC_NUM_OP_AND|DEC_NUM_OP_LT_EQ, 30)
- item4 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 10)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PKT_LEN, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DSCP, []*FlowSpecComponentItem{item2, item3, item4}))
- isFragment := uint64(0x02)
- lastFragment := uint64(0x08)
- item5 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_MATCH, isFragment)
- item6 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND, lastFragment)
-
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5, item6}))
- item7 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK)
- item8 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND|BITMASK_FLAG_OP_NOT, TCP_FLAG_URGENT)
-
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item7, item8}))
- n1 := NewFlowSpecIPv4Unicast(cmp)
-
- buf1, err := n1.Serialize()
- assert.Nil(err)
-
- n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv4_UC))
- assert.Nil(err)
-
- err = n2.DecodeFromBytes(buf1)
- assert.Nil(err)
- // should be equal
- assert.Equal(n1, n2)
-}
-
-func Test_FlowSpecExtended(t *testing.T) {
- assert := assert.New(t)
- exts := make([]ExtendedCommunityInterface, 0)
- exts = append(exts, NewTrafficRateExtended(100, 9600.0))
- exts = append(exts, NewTrafficActionExtended(true, false))
- exts = append(exts, NewRedirectTwoOctetAsSpecificExtended(1000, 1000))
- exts = append(exts, NewRedirectIPv4AddressSpecificExtended("10.0.0.1", 1000))
- exts = append(exts, NewRedirectFourOctetAsSpecificExtended(10000000, 1000))
- exts = append(exts, NewTrafficRemarkExtended(10))
- m1 := NewPathAttributeExtendedCommunities(exts)
- buf1, err := m1.Serialize()
- require.NoError(t, err)
-
- m2 := NewPathAttributeExtendedCommunities(nil)
- err = m2.DecodeFromBytes(buf1)
- require.NoError(t, err)
-
- _, err = m2.Serialize()
- require.NoError(t, err)
-
- assert.Equal(m1, m2)
-}
-
-func Test_IP6FlowSpecExtended(t *testing.T) {
- exts := make([]ExtendedCommunityInterface, 0)
- exts = append(exts, NewRedirectIPv6AddressSpecificExtended("2001:db8::68", 1000))
- m1 := NewPathAttributeIP6ExtendedCommunities(exts)
- buf1, err := m1.Serialize()
- require.NoError(t, err)
-
- m2 := NewPathAttributeIP6ExtendedCommunities(nil)
- err = m2.DecodeFromBytes(buf1)
- require.NoError(t, err)
-
- _, err = m2.Serialize()
- require.NoError(t, err)
-
- assert.Equal(t, m1, m2)
-}
-
-func Test_FlowSpecNlriv6(t *testing.T) {
- cmp := make([]FlowSpecComponentInterface, 0)
- cmp = append(cmp, NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(64, "2001::"), 12))
- cmp = append(cmp, NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(64, "2001::"), 12))
- item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, TCP)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1}))
- item2 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 20)
- item3 := NewFlowSpecComponentItem(DEC_NUM_OP_AND|DEC_NUM_OP_LT_EQ, 30)
- item4 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, 10)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PKT_LEN, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DSCP, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_LABEL, []*FlowSpecComponentItem{item2, item3, item4}))
- isFragment := uint64(0x02)
- item5 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_MATCH, isFragment)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item5}))
- item6 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK)
- item7 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND|BITMASK_FLAG_OP_NOT, TCP_FLAG_URGENT)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item6, item7}))
- n1 := NewFlowSpecIPv6Unicast(cmp)
- buf1, err := n1.Serialize()
- require.NoError(t, err)
-
- n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv6_UC))
- require.NoError(t, err)
-
- err = n2.DecodeFromBytes(buf1)
- require.NoError(t, err)
-
- _, err = n2.Serialize()
- require.NoError(t, err)
-
- assert.Equal(t, n1, n2)
-}
-
-func Test_Aigp(t *testing.T) {
- assert := assert.New(t)
- m := NewAigpTLVIgpMetric(1000)
- a1 := NewPathAttributeAigp([]AigpTLVInterface{m})
- buf1, err := a1.Serialize()
- require.NoError(t, err)
-
- a2 := NewPathAttributeAigp(nil)
- err = a2.DecodeFromBytes(buf1)
- require.NoError(t, err)
-
- assert.Equal(a1, a2)
-}
-
-func Test_FlowSpecNlriL2(t *testing.T) {
- assert := assert.New(t)
- mac, _ := net.ParseMAC("01:23:45:67:89:ab")
- cmp := make([]FlowSpecComponentInterface, 0)
- cmp = append(cmp, NewFlowSpecDestinationMac(mac))
- cmp = append(cmp, NewFlowSpecSourceMac(mac))
- item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, uint64(IPv4))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ETHERNET_TYPE, []*FlowSpecComponentItem{item1}))
- rd, _ := ParseRouteDistinguisher("100:100")
- n1 := NewFlowSpecL2VPN(rd, cmp)
- buf1, err := n1.Serialize()
- assert.Nil(err)
- n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_L2_VPN))
- assert.Nil(err)
- err = n2.DecodeFromBytes(buf1)
- assert.Nil(err)
-
- assert.Equal(n1, n2)
-}
-
-func Test_NotificationErrorCode(t *testing.T) {
- // boundary check
- t.Log(NewNotificationErrorCode(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE).String())
- t.Log(NewNotificationErrorCode(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_TYPE+1).String())
- t.Log(NewNotificationErrorCode(BGP_ERROR_MESSAGE_HEADER_ERROR, 0).String())
- t.Log(NewNotificationErrorCode(0, BGP_ERROR_SUB_BAD_MESSAGE_TYPE).String())
- t.Log(NewNotificationErrorCode(BGP_ERROR_ROUTE_REFRESH_MESSAGE_ERROR+1, 0).String())
-}
-
-func Test_FlowSpecNlriVPN(t *testing.T) {
- assert := assert.New(t)
- cmp := make([]FlowSpecComponentInterface, 0)
- cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- rd, _ := ParseRouteDistinguisher("100:100")
- n1 := NewFlowSpecIPv4VPN(rd, cmp)
- buf1, err := n1.Serialize()
- assert.Nil(err)
- n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_FS_IPv4_VPN))
- assert.Nil(err)
- err = n2.DecodeFromBytes(buf1)
- require.NoError(t, err)
-
- assert.Equal(n1, n2)
-}
-
-func Test_EVPNIPPrefixRoute(t *testing.T) {
- assert := assert.New(t)
- rd, _ := ParseRouteDistinguisher("100:100")
- r := &EVPNIPPrefixRoute{
- RD: rd,
- ESI: EthernetSegmentIdentifier{
- Type: ESI_ARBITRARY,
- Value: make([]byte, 9),
- },
- ETag: 10,
- IPPrefixLength: 24,
- IPPrefix: net.IP{10, 10, 10, 0},
- GWIPAddress: net.IP{10, 10, 10, 10},
- Label: 1000,
- }
- n1 := NewEVPNNLRI(EVPN_IP_PREFIX, r)
- buf1, err := n1.Serialize()
- assert.Nil(err)
- n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_EVPN))
- assert.Nil(err)
- err = n2.DecodeFromBytes(buf1)
- assert.Nil(err)
-
- assert.Equal(n1, n2)
-}
-
-func Test_CapExtendedNexthop(t *testing.T) {
- assert := assert.New(t)
- tuple := NewCapExtendedNexthopTuple(RF_IPv4_UC, AFI_IP6)
- n1 := NewCapExtendedNexthop([]*CapExtendedNexthopTuple{tuple})
- buf1, err := n1.Serialize()
- assert.Nil(err)
- n2, err := DecodeCapability(buf1)
- assert.Nil(err)
-
- assert.Equal(n1, n2)
-}
-
-func Test_AddPath(t *testing.T) {
- assert := assert.New(t)
- opt := &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}}
- {
- n1 := NewIPAddrPrefix(24, "10.10.10.0")
- assert.Equal(n1.PathIdentifier(), uint32(0))
- n1.SetPathLocalIdentifier(10)
- assert.Equal(n1.PathLocalIdentifier(), uint32(10))
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := &IPAddrPrefix{}
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(10))
- }
- {
- n1 := NewIPv6AddrPrefix(64, "2001::")
- n1.SetPathIdentifier(10)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewIPv6AddrPrefix(0, "")
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(0))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH, RF_IPv6_UC: BGP_ADD_PATH_BOTH}}
- {
- n1 := NewIPv6AddrPrefix(64, "2001::")
- n1.SetPathLocalIdentifier(10)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewIPv6AddrPrefix(0, "")
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(10))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_VPN: BGP_ADD_PATH_BOTH, RF_IPv6_VPN: BGP_ADD_PATH_BOTH}}
- {
- rd, _ := ParseRouteDistinguisher("100:100")
- labels := NewMPLSLabelStack(100, 200)
- n1 := NewLabeledVPNIPAddrPrefix(24, "10.10.10.0", *labels, rd)
- n1.SetPathLocalIdentifier(20)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewLabeledVPNIPAddrPrefix(0, "", MPLSLabelStack{}, nil)
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(20))
- }
- {
- rd, _ := ParseRouteDistinguisher("100:100")
- labels := NewMPLSLabelStack(100, 200)
- n1 := NewLabeledVPNIPv6AddrPrefix(64, "2001::", *labels, rd)
- n1.SetPathLocalIdentifier(20)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewLabeledVPNIPAddrPrefix(0, "", MPLSLabelStack{}, nil)
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(20))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_MPLS: BGP_ADD_PATH_BOTH, RF_IPv6_MPLS: BGP_ADD_PATH_BOTH}}
- {
- labels := NewMPLSLabelStack(100, 200)
- n1 := NewLabeledIPAddrPrefix(24, "10.10.10.0", *labels)
- n1.SetPathLocalIdentifier(20)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewLabeledIPAddrPrefix(0, "", MPLSLabelStack{})
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(20))
- }
- {
- labels := NewMPLSLabelStack(100, 200)
- n1 := NewLabeledIPv6AddrPrefix(64, "2001::", *labels)
- n1.SetPathLocalIdentifier(20)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewLabeledIPAddrPrefix(0, "", MPLSLabelStack{})
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(20))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_RTC_UC: BGP_ADD_PATH_BOTH}}
- {
- rt, _ := ParseRouteTarget("100:100")
- n1 := NewRouteTargetMembershipNLRI(65000, rt)
- n1.SetPathLocalIdentifier(30)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewRouteTargetMembershipNLRI(0, nil)
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(30))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_EVPN: BGP_ADD_PATH_BOTH}}
- {
- n1 := NewEVPNNLRI(EVPN_ROUTE_TYPE_ETHERNET_AUTO_DISCOVERY,
- &EVPNEthernetAutoDiscoveryRoute{NewRouteDistinguisherFourOctetAS(5, 6),
- EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2})
- n1.SetPathLocalIdentifier(40)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewEVPNNLRI(0, nil)
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(40))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_IPv4_ENCAP: BGP_ADD_PATH_BOTH}}
- {
- n1 := NewEncapNLRI("10.10.10.0")
- n1.SetPathLocalIdentifier(50)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewEncapNLRI("")
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(50))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_BOTH}}
- {
- n1 := NewFlowSpecIPv4Unicast([]FlowSpecComponentInterface{NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0"))})
- n1.SetPathLocalIdentifier(60)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := NewFlowSpecIPv4Unicast(nil)
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(60))
- }
- opt = &MarshallingOption{AddPath: map[RouteFamily]BGPAddPathMode{RF_OPAQUE: BGP_ADD_PATH_BOTH}}
- {
- n1 := NewOpaqueNLRI([]byte("key"), []byte("value"))
- n1.SetPathLocalIdentifier(70)
- bits, err := n1.Serialize(opt)
- assert.Nil(err)
- n2 := &OpaqueNLRI{}
- err = n2.DecodeFromBytes(bits, opt)
- assert.Nil(err)
- assert.Equal(n2.PathIdentifier(), uint32(70))
- }
-
-}
-
-func Test_CompareFlowSpecNLRI(t *testing.T) {
- assert := assert.New(t)
- cmp, err := ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 10.0.0.2/32 source 10.0.0.1/32 destination-port ==3128 protocol tcp")
- assert.Nil(err)
- // Note: Use NewFlowSpecIPv4Unicast() for the consistent ordered rules.
- n1 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI
- cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.0/24 destination-port ==3128 protocol tcp")
- assert.Nil(err)
- n2 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI
- r, err := CompareFlowSpecNLRI(&n1, &n2)
- assert.Nil(err)
- assert.True(r > 0)
- cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "source 10.0.0.9/32 port ==80 ==8080 destination-port >8080&<8080 ==3128 source-port >1024 protocol ==udp ==tcp")
- n3 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI
- assert.Nil(err)
- cmp, err = ParseFlowSpecComponents(RF_FS_IPv4_UC, "destination 192.168.0.2/32")
- n4 := NewFlowSpecIPv4Unicast(cmp).FlowSpecNLRI
- assert.Nil(err)
- r, err = CompareFlowSpecNLRI(&n3, &n4)
- assert.Nil(err)
- assert.True(r < 0)
-}
-
-func Test_MpReachNLRIWithIPv4MappedIPv6Prefix(t *testing.T) {
- assert := assert.New(t)
- n1 := NewIPv6AddrPrefix(120, "::ffff:10.0.0.0")
- buf1, err := n1.Serialize()
- assert.Nil(err)
- n2, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_IPv6_UC))
- assert.Nil(err)
- err = n2.DecodeFromBytes(buf1)
- assert.Nil(err)
-
- assert.Equal(n1, n2)
-
- label := NewMPLSLabelStack(2)
-
- n3 := NewLabeledIPv6AddrPrefix(120, "::ffff:10.0.0.0", *label)
- buf1, err = n3.Serialize()
- assert.Nil(err)
- n4, err := NewPrefixFromRouteFamily(RouteFamilyToAfiSafi(RF_IPv6_MPLS))
- assert.Nil(err)
- err = n4.DecodeFromBytes(buf1)
- assert.Nil(err)
-
- assert.Equal(n3, n4)
-}
-
-func Test_MpReachNLRIWithIPv6PrefixWithIPv4Peering(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x80, 0x0e, 0x1e, // flags(1), type(1), length(1)
- 0x00, 0x02, 0x01, 0x10, // afi(2), safi(1), nexthoplen(1)
- 0x00, 0x00, 0x00, 0x00, // nexthop(16)
- 0x00, 0x00, 0x00, 0x00, // = "::ffff:172.20.0.1"
- 0x00, 0x00, 0xff, 0xff,
- 0xac, 0x14, 0x00, 0x01,
- 0x00, // reserved(1)
- 0x40, 0x20, 0x01, 0x0d, // nlri(9)
- 0xb8, 0x00, 0x01, 0x00, // = "2001:db8:1:1::/64"
- 0x01,
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpReachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x80), p.Flags)
- assert.Equal(BGPAttrType(0xe), p.Type)
- assert.Equal(uint16(0x1e), p.Length)
- assert.Equal(uint16(AFI_IP6), p.AFI)
- assert.Equal(uint8(SAFI_UNICAST), p.SAFI)
- assert.Equal(net.ParseIP("::ffff:172.20.0.1"), p.Nexthop)
- assert.Equal(net.ParseIP(""), p.LinkLocalNexthop)
- value := []AddrPrefixInterface{
- NewIPv6AddrPrefix(64, "2001:db8:1:1::"),
- }
- assert.Equal(value, p.Value)
- // Set NextHop as IPv4 address (because IPv4 peering)
- p.Nexthop = net.ParseIP("172.20.0.1")
- // Test Serialize()
- bufout, err := p.Serialize()
- assert.Nil(err)
- // Test serialised value
- assert.Equal(bufin, bufout)
-}
-
-func Test_MpReachNLRIWithIPv6(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x90, 0x0e, 0x00, 0x1e, // flags(1), type(1), length(2),
- 0x00, 0x02, 0x01, 0x10, // afi(2), safi(1), nexthoplen(1)
- 0x20, 0x01, 0x0d, 0xb8, // nexthop(16)
- 0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1"
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, // reserved(1)
- 0x40, 0x20, 0x01, 0x0d, // nlri(9)
- 0xb8, 0x00, 0x53, 0x00, // = "2001:db8:53::/64"
- 0x00,
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpReachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x90), p.Flags)
- assert.Equal(BGPAttrType(0xe), p.Type)
- assert.Equal(uint16(0x1e), p.Length)
- assert.Equal(uint16(AFI_IP6), p.AFI)
- assert.Equal(uint8(SAFI_UNICAST), p.SAFI)
- assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop)
- value := []AddrPrefixInterface{
- NewIPv6AddrPrefix(64, "2001:db8:53::"),
- }
- assert.Equal(value, p.Value)
-}
-
-func Test_MpUnreachNLRIWithIPv6(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x90, 0x0f, 0x00, 0x0c, // flags(1), type(1), length(2),
- 0x00, 0x02, 0x01, // afi(2), safi(1),
- 0x40, 0x20, 0x01, 0x0d, // nlri(9)
- 0xb8, 0x00, 0x53, 0x00, // = "2001:db8:53::/64"
- 0x00,
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpUnreachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x90), p.Flags)
- assert.Equal(BGPAttrType(0xf), p.Type)
- assert.Equal(uint16(0x0c), p.Length)
- assert.Equal(uint16(AFI_IP6), p.AFI)
- assert.Equal(uint8(SAFI_UNICAST), p.SAFI)
- value := []AddrPrefixInterface{
- NewIPv6AddrPrefix(64, "2001:db8:53::"),
- }
- assert.Equal(value, p.Value)
-}
-
-func Test_MpReachNLRIWithIPv6PrefixWithLinkLocalNexthop(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x80, 0x0e, 0x2c, // flags(1), type(1), length(1)
- 0x00, 0x02, 0x01, 0x20, // afi(2), safi(1), nexthoplen(1)
- 0x20, 0x01, 0x0d, 0xb8, // nexthop(32)
- 0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1"
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0xfe, 0x80, 0x00, 0x00, // + "fe80::1" (link local)
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, // reserved(1)
- 0x30, 0x20, 0x10, 0x0a, // nlri(7)
- 0xb8, 0x00, 0x01, // = "2010:ab8:1::/48"
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpReachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x80), p.Flags)
- assert.Equal(BGPAttrType(0xe), p.Type)
- assert.Equal(uint16(0x2c), p.Length)
- assert.Equal(uint16(AFI_IP6), p.AFI)
- assert.Equal(uint8(SAFI_UNICAST), p.SAFI)
- assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop)
- assert.Equal(net.ParseIP("fe80::1"), p.LinkLocalNexthop)
- value := []AddrPrefixInterface{
- NewIPv6AddrPrefix(48, "2010:ab8:1::"),
- }
- assert.Equal(value, p.Value)
- // Test Serialize()
- bufout, err := p.Serialize()
- assert.Nil(err)
- // Test serialised value
- assert.Equal(bufin, bufout)
-}
-
-func Test_MpReachNLRIWithVPNv4Prefix(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x80, 0x0e, 0x20, // flags(1), type(1), length(1)
- 0x00, 0x01, 0x80, 0x0c, // afi(2), safi(1), nexthoplen(1)
- 0x00, 0x00, 0x00, 0x00, // nexthop(12)
- 0x00, 0x00, 0x00, 0x00, // = (rd:"0:0",) "172.20.0.1"
- 0xac, 0x14, 0x00, 0x01,
- 0x00, // reserved(1)
- 0x70, 0x00, 0x01, 0x01, // nlri(15)
- 0x00, 0x00, 0xfd, 0xe8, // = label:16, rd:"65000:100", prefix:"10.1.1.0/24"
- 0x00, 0x00, 0x00, 0x64,
- 0x0a, 0x01, 0x01,
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpReachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x80), p.Flags)
- assert.Equal(BGPAttrType(0xe), p.Type)
- assert.Equal(uint16(0x20), p.Length)
- assert.Equal(uint16(AFI_IP), p.AFI)
- assert.Equal(uint8(SAFI_MPLS_VPN), p.SAFI)
- assert.Equal(net.ParseIP("172.20.0.1").To4(), p.Nexthop)
- assert.Equal(net.ParseIP(""), p.LinkLocalNexthop)
- value := []AddrPrefixInterface{
- NewLabeledVPNIPAddrPrefix(24, "10.1.1.0", *NewMPLSLabelStack(16),
- NewRouteDistinguisherTwoOctetAS(65000, 100)),
- }
- assert.Equal(value, p.Value)
- // Test Serialize()
- bufout, err := p.Serialize()
- assert.Nil(err)
- // Test serialised value
- assert.Equal(bufin, bufout)
-}
-
-func Test_MpReachNLRIWithVPNv6Prefix(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x80, 0x0e, 0x39, // flags(1), type(1), length(1)
- 0x00, 0x02, 0x80, 0x18, // afi(2), safi(1), nexthoplen(1)
- 0x00, 0x00, 0x00, 0x00, // nexthop(24)
- 0x00, 0x00, 0x00, 0x00, // = (rd:"0:0",) "2001:db8:1::1"
- 0x20, 0x01, 0x0d, 0xb8,
- 0x00, 0x01, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, // reserved(1)
- 0xd4, 0x00, 0x01, 0x01, // nlri(28)
- 0x00, 0x00, 0xfd, 0xe8, // = label:16, rd:"65000:100", prefix:"2001:1::/124"
- 0x00, 0x00, 0x00, 0x64,
- 0x20, 0x01, 0x00, 0x01,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpReachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x80), p.Flags)
- assert.Equal(BGPAttrType(0xe), p.Type)
- assert.Equal(uint16(0x39), p.Length)
- assert.Equal(uint16(AFI_IP6), p.AFI)
- assert.Equal(uint8(SAFI_MPLS_VPN), p.SAFI)
- assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop)
- assert.Equal(net.ParseIP(""), p.LinkLocalNexthop)
- value := []AddrPrefixInterface{
- NewLabeledVPNIPv6AddrPrefix(124, "2001:1::", *NewMPLSLabelStack(16),
- NewRouteDistinguisherTwoOctetAS(65000, 100)),
- }
- assert.Equal(value, p.Value)
- // Test Serialize()
- bufout, err := p.Serialize()
- assert.Nil(err)
- // Test serialised value
- assert.Equal(bufin, bufout)
-}
-
-func Test_MpReachNLRIWithIPv4PrefixWithIPv6Nexthop(t *testing.T) {
- assert := assert.New(t)
- bufin := []byte{
- 0x80, 0x0e, 0x19, // flags(1), type(1), length(1)
- 0x00, 0x01, 0x01, 0x10, // afi(1), safi(1), nexthoplen(1)
- 0x20, 0x01, 0x0d, 0xb8, // nexthop(32)
- 0x00, 0x01, 0x00, 0x00, // = "2001:db8:1::1"
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x01,
- 0x00, // reserved(1)
- 0x18, 0xc0, 0xa8, 0x0a, // nlri(7)
- }
- // Test DecodeFromBytes()
- p := &PathAttributeMpReachNLRI{}
- err := p.DecodeFromBytes(bufin)
- assert.Nil(err)
- // Test decoded values
- assert.Equal(BGPAttrFlag(0x80), p.Flags)
- assert.Equal(BGPAttrType(0xe), p.Type)
- assert.Equal(uint16(0x19), p.Length)
- assert.Equal(uint16(AFI_IP), p.AFI)
- assert.Equal(uint8(SAFI_UNICAST), p.SAFI)
- assert.Equal(net.ParseIP("2001:db8:1::1"), p.Nexthop)
- value := []AddrPrefixInterface{
- NewIPAddrPrefix(24, "192.168.10.0"),
- }
- assert.Equal(value, p.Value)
- // Test Serialize()
- bufout, err := p.Serialize()
- assert.Nil(err)
- // Test serialised value
- assert.Equal(bufin, bufout)
-}
-
-func Test_ParseRouteDistinguisher(t *testing.T) {
- assert := assert.New(t)
-
- rd, _ := ParseRouteDistinguisher("100:1000")
- rdType0, ok := rd.(*RouteDistinguisherTwoOctetAS)
- if !ok {
- t.Fatal("Type of RD interface is not RouteDistinguisherTwoOctetAS")
- }
-
- assert.Equal(uint16(100), rdType0.Admin)
- assert.Equal(uint32(1000), rdType0.Assigned)
-
- rd, _ = ParseRouteDistinguisher("10.0.0.0:100")
- rdType1, ok := rd.(*RouteDistinguisherIPAddressAS)
- if !ok {
- t.Fatal("Type of RD interface is not RouteDistinguisherIPAddressAS")
- }
-
- assert.Equal("10.0.0.0", rdType1.Admin.String())
- assert.Equal(uint16(100), rdType1.Assigned)
-
- rd, _ = ParseRouteDistinguisher("100.1000:10000")
- rdType2, ok := rd.(*RouteDistinguisherFourOctetAS)
- if !ok {
- t.Fatal("Type of RD interface is not RouteDistinguisherFourOctetAS")
- }
-
- assert.Equal(uint32((100<<16)|1000), rdType2.Admin)
- assert.Equal(uint16(10000), rdType2.Assigned)
-}
-
-func Test_ParseEthernetSegmentIdentifier(t *testing.T) {
- assert := assert.New(t)
-
- // "single-homed"
- esiZero := EthernetSegmentIdentifier{}
- args := make([]string, 0)
- esi, err := ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(esiZero, esi)
- args = []string{"single-homed"}
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(esiZero, esi)
-
- // ESI_ARBITRARY
- args = []string{"ARBITRARY", "11:22:33:44:55:66:77:88:99"} // omit "ESI_"
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESI_ARBITRARY,
- Value: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99},
- }, esi)
-
- // ESI_LACP
- args = []string{"lacp", "aa:bb:cc:dd:ee:ff", strconv.FormatInt(0x1122, 10)} // lower case
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESI_LACP,
- Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x00},
- }, esi)
-
- // ESI_MSTP
- args = []string{"esi_mstp", "aa:bb:cc:dd:ee:ff", strconv.FormatInt(0x1122, 10)} // omit "ESI_" + lower case
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESI_MSTP,
- Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x00},
- }, esi)
-
- // ESI_MAC
- args = []string{"ESI_MAC", "aa:bb:cc:dd:ee:ff", strconv.FormatInt(0x112233, 10)}
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESI_MAC,
- Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33},
- }, esi)
-
- // ESI_ROUTERID
- args = []string{"ESI_ROUTERID", "1.1.1.1", strconv.FormatInt(0x11223344, 10)}
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESI_ROUTERID,
- Value: []byte{0x01, 0x01, 0x01, 0x01, 0x11, 0x22, 0x33, 0x44, 0x00},
- }, esi)
-
- // ESI_AS
- args = []string{"ESI_AS", strconv.FormatInt(0xaabbccdd, 10), strconv.FormatInt(0x11223344, 10)}
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESI_AS,
- Value: []byte{0xaa, 0xbb, 0xcc, 0xdd, 0x11, 0x22, 0x33, 0x44, 0x00},
- }, esi)
-
- // Other
- args = []string{"99", "11:22:33:44:55:66:77:88:99"}
- esi, err = ParseEthernetSegmentIdentifier(args)
- assert.Nil(err)
- assert.Equal(EthernetSegmentIdentifier{
- Type: ESIType(99),
- Value: []byte{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99},
- }, esi)
-}
-
-func TestParseBogusShortData(t *testing.T) {
- var bodies = []BGPBody{
- &BGPOpen{},
- &BGPUpdate{},
- &BGPNotification{},
- &BGPKeepAlive{},
- &BGPRouteRefresh{},
- }
-
- for _, b := range bodies {
- b.DecodeFromBytes([]byte{0})
- }
-}
-
-func TestFuzzCrashers(t *testing.T) {
- var crashers = []string{
- "000000000000000000\x01",
- }
-
- for _, f := range crashers {
- ParseBGPMessage([]byte(f))
- }
-}
-
-func TestNormalizeFlowSpecOpValues(t *testing.T) {
- tests := []struct {
- msg string
- args []string
- want []string
- }{
- {
- msg: "valid match",
- args: []string{" & <=80", " tcp != udp ", " =! SA & =U! F", " = is-fragment+last-fragment"},
- want: []string{"<=80", "tcp", "!=udp", "=!SA", "&=U", "!F", "=is-fragment+last-fragment"},
- },
- {
- msg: "RFC5575 trims & prefix",
- args: []string{"&<=80"},
- want: []string{"<=80"},
- },
- }
-
- for _, tt := range tests {
- t.Run(tt.msg, func(t *testing.T) {
- got := normalizeFlowSpecOpValues(tt.args)
- assert.Equal(t, tt.want, got)
- })
- }
-}
diff --git a/packet/bgp/bgpattrtype_string.go b/packet/bgp/bgpattrtype_string.go
deleted file mode 100644
index 1a2cf1d0..00000000
--- a/packet/bgp/bgpattrtype_string.go
+++ /dev/null
@@ -1,28 +0,0 @@
-// generated by stringer -type BGPAttrType bgp.go; DO NOT EDIT
-
-package bgp
-
-import "fmt"
-
-const (
- _BGPAttrType_name_0 = "BGP_ATTR_TYPE_ORIGINBGP_ATTR_TYPE_AS_PATHBGP_ATTR_TYPE_NEXT_HOPBGP_ATTR_TYPE_MULTI_EXIT_DISCBGP_ATTR_TYPE_LOCAL_PREFBGP_ATTR_TYPE_ATOMIC_AGGREGATEBGP_ATTR_TYPE_AGGREGATORBGP_ATTR_TYPE_COMMUNITIESBGP_ATTR_TYPE_ORIGINATOR_IDBGP_ATTR_TYPE_CLUSTER_LIST"
- _BGPAttrType_name_1 = "BGP_ATTR_TYPE_MP_REACH_NLRIBGP_ATTR_TYPE_MP_UNREACH_NLRIBGP_ATTR_TYPE_EXTENDED_COMMUNITIESBGP_ATTR_TYPE_AS4_PATHBGP_ATTR_TYPE_AS4_AGGREGATOR"
-)
-
-var (
- _BGPAttrType_index_0 = [...]uint8{0, 20, 41, 63, 92, 116, 146, 170, 195, 222, 248}
- _BGPAttrType_index_1 = [...]uint8{0, 27, 56, 90, 112, 140}
-)
-
-func (i BGPAttrType) String() string {
- switch {
- case 1 <= i && i <= 10:
- i -= 1
- return _BGPAttrType_name_0[_BGPAttrType_index_0[i]:_BGPAttrType_index_0[i+1]]
- case 14 <= i && i <= 18:
- i -= 14
- return _BGPAttrType_name_1[_BGPAttrType_index_1[i]:_BGPAttrType_index_1[i+1]]
- default:
- return fmt.Sprintf("BGPAttrType(%d)", i)
- }
-}
diff --git a/packet/bgp/constant.go b/packet/bgp/constant.go
deleted file mode 100644
index 5ea7b414..00000000
--- a/packet/bgp/constant.go
+++ /dev/null
@@ -1,327 +0,0 @@
-// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bgp
-
-import (
- "fmt"
- "strings"
-)
-
-const AS_TRANS = 23456
-
-const BGP_PORT = 179
-
-type FSMState int
-
-const (
- BGP_FSM_IDLE FSMState = iota
- BGP_FSM_CONNECT
- BGP_FSM_ACTIVE
- BGP_FSM_OPENSENT
- BGP_FSM_OPENCONFIRM
- BGP_FSM_ESTABLISHED
-)
-
-// partially taken from http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
-type Protocol int
-
-const (
- Unknown Protocol = iota
- ICMP = 0x01
- IGMP = 0x02
- TCP = 0x06
- EGP = 0x08
- IGP = 0x09
- UDP = 0x11
- RSVP = 0x2e
- GRE = 0x2f
- OSPF = 0x59
- IPIP = 0x5e
- PIM = 0x67
- SCTP = 0x84
-)
-
-var ProtocolNameMap = map[Protocol]string{
- Unknown: "unknown",
- ICMP: "icmp",
- IGMP: "igmp",
- TCP: "tcp",
- EGP: "egp",
- IGP: "igp",
- UDP: "udp",
- RSVP: "rsvp",
- GRE: "gre",
- OSPF: "ospf",
- IPIP: "ipip",
- PIM: "pim",
- SCTP: "sctp",
-}
-
-func (p Protocol) String() string {
- name, ok := ProtocolNameMap[p]
- if !ok {
- return fmt.Sprintf("%d", p)
- }
- return name
-}
-
-type TCPFlag int
-
-const (
- _ TCPFlag = iota
- TCP_FLAG_FIN = 0x01
- TCP_FLAG_SYN = 0x02
- TCP_FLAG_RST = 0x04
- TCP_FLAG_PUSH = 0x08
- TCP_FLAG_ACK = 0x10
- TCP_FLAG_URGENT = 0x20
- TCP_FLAG_ECE = 0x40
- TCP_FLAG_CWR = 0x80
-)
-
-var TCPFlagNameMap = map[TCPFlag]string{
- TCP_FLAG_FIN: "F",
- TCP_FLAG_SYN: "S",
- TCP_FLAG_RST: "R",
- TCP_FLAG_PUSH: "P",
- TCP_FLAG_ACK: "A",
- TCP_FLAG_URGENT: "U",
- TCP_FLAG_CWR: "C",
- TCP_FLAG_ECE: "E",
-}
-
-// Prepares a sorted list of flags because map iterations does not happen
-// in a consistent order in Golang.
-var TCPSortedFlags = []TCPFlag{
- TCP_FLAG_FIN,
- TCP_FLAG_SYN,
- TCP_FLAG_RST,
- TCP_FLAG_PUSH,
- TCP_FLAG_ACK,
- TCP_FLAG_URGENT,
- TCP_FLAG_ECE,
- TCP_FLAG_CWR,
-}
-
-func (f TCPFlag) String() string {
- flags := make([]string, 0, len(TCPSortedFlags))
- for _, v := range TCPSortedFlags {
- if f&v > 0 {
- flags = append(flags, TCPFlagNameMap[v])
- }
- }
- return strings.Join(flags, "")
-}
-
-type BitmaskFlagOp uint8
-
-const (
- BITMASK_FLAG_OP_OR BitmaskFlagOp = iota
- BITMASK_FLAG_OP_MATCH = 0x01
- BITMASK_FLAG_OP_NOT = 0x02
- BITMASK_FLAG_OP_NOT_MATCH = 0x03
- BITMASK_FLAG_OP_AND = 0x40
- BITMASK_FLAG_OP_END = 0x80
-)
-
-var BitmaskFlagOpNameMap = map[BitmaskFlagOp]string{
- BITMASK_FLAG_OP_OR: " ",
- BITMASK_FLAG_OP_AND: "&",
- BITMASK_FLAG_OP_END: "E",
- BITMASK_FLAG_OP_NOT: "!",
- BITMASK_FLAG_OP_MATCH: "=",
-}
-
-// Note: Meaning of "" is different from that of the numeric operator because
-// RFC5575 says if the Match bit in the bitmask operand is set, it should be
-// "strictly" matching against the given value.
-var BitmaskFlagOpValueMap = map[string]BitmaskFlagOp{
- " ": BITMASK_FLAG_OP_OR,
- "": BITMASK_FLAG_OP_OR,
- "==": BITMASK_FLAG_OP_MATCH,
- "=": BITMASK_FLAG_OP_MATCH,
- "!": BITMASK_FLAG_OP_NOT,
- "!=": BITMASK_FLAG_OP_NOT_MATCH,
- "=!": BITMASK_FLAG_OP_NOT_MATCH, // For the backward compatibility
- "&": BITMASK_FLAG_OP_AND,
- "E": BITMASK_FLAG_OP_END,
-}
-
-func (f BitmaskFlagOp) String() string {
- ops := make([]string, 0)
- if f&BITMASK_FLAG_OP_AND > 0 {
- ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_AND])
- } else {
- ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_OR])
- }
- if f&BITMASK_FLAG_OP_NOT > 0 {
- ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_NOT])
- }
- if f&BITMASK_FLAG_OP_MATCH > 0 {
- ops = append(ops, BitmaskFlagOpNameMap[BITMASK_FLAG_OP_MATCH])
- }
- return strings.Join(ops, "")
-}
-
-type FragmentFlag int
-
-const (
- FRAG_FLAG_NOT FragmentFlag = iota
- FRAG_FLAG_DONT = 0x01
- FRAG_FLAG_IS = 0x02
- FRAG_FLAG_FIRST = 0x04
- FRAG_FLAG_LAST = 0x08
-)
-
-var FragmentFlagNameMap = map[FragmentFlag]string{
- FRAG_FLAG_NOT: "not-a-fragment",
- FRAG_FLAG_DONT: "dont-fragment",
- FRAG_FLAG_IS: "is-fragment",
- FRAG_FLAG_FIRST: "first-fragment",
- FRAG_FLAG_LAST: "last-fragment",
-}
-
-// Prepares a sorted list of flags because map iterations does not happen
-// in a consistent order in Golang.
-var FragmentSortedFlags = []FragmentFlag{
- FRAG_FLAG_NOT,
- FRAG_FLAG_DONT,
- FRAG_FLAG_IS,
- FRAG_FLAG_FIRST,
- FRAG_FLAG_LAST,
-}
-
-func (f FragmentFlag) String() string {
- flags := make([]string, 0, len(FragmentSortedFlags))
- for _, v := range FragmentSortedFlags {
- if f&v > 0 {
- flags = append(flags, FragmentFlagNameMap[v])
- }
- }
- // Note: If multiple bits are set, joins them with "+".
- return strings.Join(flags, "+")
-}
-
-type DECNumOp uint8
-
-const (
- DEC_NUM_OP_TRUE DECNumOp = iota // true always with END bit set
- DEC_NUM_OP_EQ = 0x01
- DEC_NUM_OP_GT = 0x02
- DEC_NUM_OP_GT_EQ = 0x03
- DEC_NUM_OP_LT = 0x04
- DEC_NUM_OP_LT_EQ = 0x05
- DEC_NUM_OP_NOT_EQ = 0x06
- DEC_NUM_OP_FALSE = 0x07 // false always with END bit set
- DEC_NUM_OP_OR = 0x00
- DEC_NUM_OP_AND = 0x40
- DEC_NUM_OP_END = 0x80
-)
-
-var DECNumOpNameMap = map[DECNumOp]string{
- DEC_NUM_OP_TRUE: "true",
- DEC_NUM_OP_EQ: "==",
- DEC_NUM_OP_GT: ">",
- DEC_NUM_OP_GT_EQ: ">=",
- DEC_NUM_OP_LT: "<",
- DEC_NUM_OP_LT_EQ: "<=",
- DEC_NUM_OP_NOT_EQ: "!=",
- DEC_NUM_OP_FALSE: "false",
- //DEC_NUM_OP_OR: " ", // duplicate with DEC_NUM_OP_TRUE
- DEC_NUM_OP_AND: "&",
- DEC_NUM_OP_END: "E",
-}
-
-var DECNumOpValueMap = map[string]DECNumOp{
- "true": DEC_NUM_OP_TRUE,
- "": DEC_NUM_OP_EQ,
- "==": DEC_NUM_OP_EQ,
- "=": DEC_NUM_OP_EQ,
- ">": DEC_NUM_OP_GT,
- ">=": DEC_NUM_OP_GT_EQ,
- "<": DEC_NUM_OP_LT,
- "<=": DEC_NUM_OP_LT_EQ,
- "!=": DEC_NUM_OP_NOT_EQ,
- "=!": DEC_NUM_OP_NOT_EQ,
- "!": DEC_NUM_OP_NOT_EQ,
- "false": DEC_NUM_OP_FALSE,
- " ": DEC_NUM_OP_OR,
- "&": DEC_NUM_OP_AND,
- "E": DEC_NUM_OP_END,
-}
-
-func (f DECNumOp) String() string {
- ops := make([]string, 0)
- logicFlag := DECNumOp(f & 0xc0) // higher 2 bits
- if logicFlag&DEC_NUM_OP_AND > 0 {
- ops = append(ops, DECNumOpNameMap[DEC_NUM_OP_AND])
- } else {
- ops = append(ops, " ") // DEC_NUM_OP_OR
- }
- // Omits DEC_NUM_OP_END
- cmpFlag := DECNumOp(f & 0x7) // lower 3 bits
- for v, s := range DECNumOpNameMap {
- if cmpFlag == v {
- ops = append(ops, s)
- break
- }
- }
- return strings.Join(ops, "")
-}
-
-// Potentially taken from https://www.iana.org/assignments/ieee-802-numbers/ieee-802-numbers.xhtml
-type EthernetType int
-
-const (
- IPv4 EthernetType = 0x0800
- ARP EthernetType = 0x0806
- RARP EthernetType = 0x8035
- VMTP EthernetType = 0x805B
- APPLE_TALK EthernetType = 0x809B
- AARP EthernetType = 0x80F3
- IPX EthernetType = 0x8137
- SNMP EthernetType = 0x814C
- NET_BIOS EthernetType = 0x8191
- XTP EthernetType = 0x817D
- IPv6 EthernetType = 0x86DD
- PPPoE_DISCOVERY EthernetType = 0x8863
- PPPoE_SESSION EthernetType = 0x8864
- LOOPBACK EthernetType = 0x9000
-)
-
-var EthernetTypeNameMap = map[EthernetType]string{
- IPv4: "ipv4",
- ARP: "arp",
- RARP: "rarp",
- VMTP: "vmtp",
- APPLE_TALK: "apple-talk",
- AARP: "aarp",
- IPX: "ipx",
- SNMP: "snmp",
- NET_BIOS: "net-bios",
- XTP: "xtp",
- IPv6: "ipv6",
- PPPoE_DISCOVERY: "pppoe-discovery",
- PPPoE_SESSION: "pppoe-session",
- LOOPBACK: "loopback",
-}
-
-func (t EthernetType) String() string {
- if name, ok := EthernetTypeNameMap[t]; ok {
- return name
- }
- return fmt.Sprintf("%d", t)
-}
diff --git a/packet/bgp/esitype_string.go b/packet/bgp/esitype_string.go
deleted file mode 100644
index 5651bda8..00000000
--- a/packet/bgp/esitype_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// generated by stringer -type=ESIType bgp.go validate.go; DO NOT EDIT
-
-package bgp
-
-import "fmt"
-
-const _ESIType_name = "ESI_ARBITRARYESI_LACPESI_MSTPESI_MACESI_ROUTERIDESI_AS"
-
-var _ESIType_index = [...]uint8{0, 13, 21, 29, 36, 48, 54}
-
-func (i ESIType) String() string {
- if i+1 >= ESIType(len(_ESIType_index)) {
- return fmt.Sprintf("ESIType(%d)", i)
- }
- return _ESIType_name[_ESIType_index[i]:_ESIType_index[i+1]]
-}
diff --git a/packet/bgp/fsmstate_string.go b/packet/bgp/fsmstate_string.go
deleted file mode 100644
index 4416afc1..00000000
--- a/packet/bgp/fsmstate_string.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// generated by stringer -type=FSMState -output=fsmstate_string.go bgp.go validate.go mrt.go rtr.go constant.go bmp.go esitype_string.go bgpattrtype_string.go; DO NOT EDIT
-
-package bgp
-
-import "fmt"
-
-const _FSMState_name = "BGP_FSM_IDLEBGP_FSM_CONNECTBGP_FSM_ACTIVEBGP_FSM_OPENSENTBGP_FSM_OPENCONFIRMBGP_FSM_ESTABLISHED"
-
-var _FSMState_index = [...]uint8{0, 12, 27, 41, 57, 76, 95}
-
-func (i FSMState) String() string {
- if i < 0 || i >= FSMState(len(_FSMState_index)-1) {
- return fmt.Sprintf("FSMState(%d)", i)
- }
- return _FSMState_name[_FSMState_index[i]:_FSMState_index[i+1]]
-}
diff --git a/packet/bgp/helper.go b/packet/bgp/helper.go
deleted file mode 100644
index 34648b2d..00000000
--- a/packet/bgp/helper.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bgp
-
-func NewTestBGPOpenMessage() *BGPMessage {
- p1 := NewOptionParameterCapability(
- []ParameterCapabilityInterface{NewCapRouteRefresh()})
- p2 := NewOptionParameterCapability(
- []ParameterCapabilityInterface{NewCapMultiProtocol(RF_IPv4_UC)})
- g := &CapGracefulRestartTuple{4, 2, 3}
- p3 := NewOptionParameterCapability(
- []ParameterCapabilityInterface{NewCapGracefulRestart(false, true, 100,
- []*CapGracefulRestartTuple{g})})
- p4 := NewOptionParameterCapability(
- []ParameterCapabilityInterface{NewCapFourOctetASNumber(100000)})
- p5 := NewOptionParameterCapability(
- []ParameterCapabilityInterface{NewCapAddPath([]*CapAddPathTuple{NewCapAddPathTuple(RF_IPv4_UC, BGP_ADD_PATH_BOTH)})})
- return NewBGPOpenMessage(11033, 303, "100.4.10.3",
- []OptionParameterInterface{p1, p2, p3, p4, p5})
-}
-
-func NewTestBGPUpdateMessage() *BGPMessage {
- w1 := NewIPAddrPrefix(23, "121.1.3.2")
- w2 := NewIPAddrPrefix(17, "100.33.3.0")
- w := []*IPAddrPrefix{w1, w2}
-
- aspath1 := []AsPathParamInterface{
- NewAsPathParam(2, []uint16{1000}),
- NewAsPathParam(1, []uint16{1001, 1002}),
- NewAsPathParam(2, []uint16{1003, 1004}),
- }
-
- aspath2 := []AsPathParamInterface{
- NewAs4PathParam(2, []uint32{1000000}),
- NewAs4PathParam(1, []uint32{1000001, 1002}),
- NewAs4PathParam(2, []uint32{1003, 100004}),
- }
-
- aspath3 := []*As4PathParam{
- NewAs4PathParam(2, []uint32{1000000}),
- NewAs4PathParam(1, []uint32{1000001, 1002}),
- NewAs4PathParam(2, []uint32{1003, 100004}),
- }
-
- isTransitive := true
-
- ecommunities := []ExtendedCommunityInterface{
- NewTwoOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 10003, 3<<20, isTransitive),
- NewFourOctetAsSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, 1<<20, 300, isTransitive),
- NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, "192.2.1.2", 3000, isTransitive),
- NewOpaqueExtended(false, []byte{1, 2, 3, 4, 5, 6, 7}),
- NewValidationExtended(VALIDATION_STATE_INVALID),
- NewUnknownExtended(99, []byte{0, 1, 2, 3, 4, 5, 6, 7}),
- NewESILabelExtended(1000, true),
- NewESImportRouteTarget("11:22:33:44:55:66"),
- NewMacMobilityExtended(123, false),
- }
-
- prefixes1 := []AddrPrefixInterface{
- NewLabeledVPNIPAddrPrefix(24, "192.0.9.0", *NewMPLSLabelStack(1, 2, 3),
- NewRouteDistinguisherTwoOctetAS(256, 10000)),
- NewLabeledVPNIPAddrPrefix(24, "192.10.8.0", *NewMPLSLabelStack(5, 6, 7, 8),
- NewRouteDistinguisherIPAddressAS("10.0.1.1", 10001)),
- }
-
- prefixes2 := []AddrPrefixInterface{NewIPv6AddrPrefix(128,
- "fe80:1234:1234:5667:8967:af12:8912:1023")}
-
- prefixes3 := []AddrPrefixInterface{NewLabeledVPNIPv6AddrPrefix(128,
- "fe80:1234:1234:5667:8967:af12:1203:33a1", *NewMPLSLabelStack(5, 6),
- NewRouteDistinguisherFourOctetAS(5, 6))}
-
- prefixes4 := []AddrPrefixInterface{NewLabeledIPAddrPrefix(25, "192.168.0.0",
- *NewMPLSLabelStack(5, 6, 7))}
-
- prefixes5 := []AddrPrefixInterface{
- NewEVPNEthernetAutoDiscoveryRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 2, 2),
- NewEVPNMacIPAdvertisementRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 3, "01:23:45:67:89:ab", "192.2.1.2", []uint32{3, 4}),
- NewEVPNMulticastEthernetTagRoute(NewRouteDistinguisherFourOctetAS(5, 6), 3, "192.2.1.2"),
- NewEVPNEthernetSegmentRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, "192.2.1.1"),
- NewEVPNIPPrefixRoute(NewRouteDistinguisherFourOctetAS(5, 6), EthernetSegmentIdentifier{ESI_ARBITRARY, make([]byte, 9)}, 5, 24, "192.2.1.0", "192.3.1.1", 5),
- }
-
- p := []PathAttributeInterface{
- NewPathAttributeOrigin(3),
- NewPathAttributeAsPath(aspath1),
- NewPathAttributeAsPath(aspath2),
- NewPathAttributeNextHop("129.1.1.2"),
- NewPathAttributeMultiExitDisc(1 << 20),
- NewPathAttributeLocalPref(1 << 22),
- NewPathAttributeAtomicAggregate(),
- NewPathAttributeAggregator(uint16(30002), "129.0.2.99"),
- NewPathAttributeAggregator(uint32(30002), "129.0.2.99"),
- NewPathAttributeAggregator(uint32(300020), "129.0.2.99"),
- NewPathAttributeCommunities([]uint32{1, 3}),
- NewPathAttributeOriginatorId("10.10.0.1"),
- NewPathAttributeClusterList([]string{"10.10.0.2", "10.10.0.3"}),
- NewPathAttributeExtendedCommunities(ecommunities),
- NewPathAttributeAs4Path(aspath3),
- NewPathAttributeAs4Aggregator(10000, "112.22.2.1"),
- NewPathAttributeMpReachNLRI("112.22.2.0", prefixes1),
- NewPathAttributeMpReachNLRI("1023::", prefixes2),
- NewPathAttributeMpReachNLRI("fe80::", prefixes3),
- NewPathAttributeMpReachNLRI("129.1.1.1", prefixes4),
- NewPathAttributeMpReachNLRI("129.1.1.1", prefixes5),
- NewPathAttributeMpUnreachNLRI(prefixes1),
- //NewPathAttributeMpReachNLRI("112.22.2.0", []AddrPrefixInterface{}),
- //NewPathAttributeMpUnreachNLRI([]AddrPrefixInterface{}),
- NewPathAttributeUnknown(BGP_ATTR_FLAG_TRANSITIVE, 100, []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}),
- }
- n := []*IPAddrPrefix{NewIPAddrPrefix(24, "13.2.3.1")}
- return NewBGPUpdateMessage(w, p, n)
-}
diff --git a/packet/bgp/validate.go b/packet/bgp/validate.go
deleted file mode 100644
index 60cf26e4..00000000
--- a/packet/bgp/validate.go
+++ /dev/null
@@ -1,337 +0,0 @@
-package bgp
-
-import (
- "encoding/binary"
- "fmt"
- "math"
- "net"
- "strconv"
-)
-
-// Validator for BGPUpdate
-func ValidateUpdateMsg(m *BGPUpdate, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) {
- var strongestError error
-
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCodeAttrList := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- eSubCodeMissing := uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE)
-
- if len(m.NLRI) > 0 || len(m.WithdrawnRoutes) > 0 {
- if _, ok := rfs[RF_IPv4_UC]; !ok {
- return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", RF_IPv4_UC))
- }
- }
-
- seen := make(map[BGPAttrType]PathAttributeInterface)
- newAttrs := make([]PathAttributeInterface, 0, len(seen))
- // check path attribute
- for _, a := range m.PathAttributes {
- // check duplication
- if _, ok := seen[a.GetType()]; !ok {
- seen[a.GetType()] = a
- newAttrs = append(newAttrs, a)
- //check specific path attribute
- ok, err := ValidateAttribute(a, rfs, isEBGP, isConfed)
- if !ok {
- if err.(*MessageError).ErrorHandling == ERROR_HANDLING_SESSION_RESET {
- return false, err
- } else if err.(*MessageError).Stronger(strongestError) {
- strongestError = err
- }
- }
- } else if a.GetType() == BGP_ATTR_TYPE_MP_REACH_NLRI || a.GetType() == BGP_ATTR_TYPE_MP_UNREACH_NLRI {
- eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType()))
- return false, NewMessageError(eCode, eSubCodeAttrList, nil, eMsg)
- } else {
- eMsg := "the path attribute apears twice. Type : " + strconv.Itoa(int(a.GetType()))
- e := NewMessageErrorWithErrorHandling(eCode, eSubCodeAttrList, nil, ERROR_HANDLING_ATTRIBUTE_DISCARD, nil, eMsg)
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- }
- }
- m.PathAttributes = newAttrs
-
- if _, ok := seen[BGP_ATTR_TYPE_MP_REACH_NLRI]; ok || len(m.NLRI) > 0 {
- // check the existence of well-known mandatory attributes
- exist := func(attrs []BGPAttrType) (bool, BGPAttrType) {
- for _, attr := range attrs {
- _, ok := seen[attr]
- if !ok {
- return false, attr
- }
- }
- return true, 0
- }
- mandatory := []BGPAttrType{BGP_ATTR_TYPE_ORIGIN, BGP_ATTR_TYPE_AS_PATH}
- if len(m.NLRI) > 0 {
- mandatory = append(mandatory, BGP_ATTR_TYPE_NEXT_HOP)
- }
- if ok, t := exist(mandatory); !ok {
- eMsg := "well-known mandatory attributes are not present. type : " + strconv.Itoa(int(t))
- data := []byte{byte(t)}
- e := NewMessageErrorWithErrorHandling(eCode, eSubCodeMissing, data, ERROR_HANDLING_TREAT_AS_WITHDRAW, nil, eMsg)
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- }
- }
-
- return strongestError == nil, strongestError
-}
-
-func ValidateAttribute(a PathAttributeInterface, rfs map[RouteFamily]BGPAddPathMode, isEBGP bool, isConfed bool) (bool, error) {
- var strongestError error
-
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCodeBadOrigin := uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE)
- eSubCodeBadNextHop := uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE)
- eSubCodeUnknown := uint8(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE)
- eSubCodeMalformedAspath := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH)
-
- checkPrefix := func(l []AddrPrefixInterface) error {
- for _, prefix := range l {
- rf := AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI())
- if _, ok := rfs[rf]; !ok {
- return NewMessageError(0, 0, nil, fmt.Sprintf("Address-family %s not available for this session", rf))
- }
- switch rf {
- case RF_FS_IPv4_UC, RF_FS_IPv6_UC, RF_FS_IPv4_VPN, RF_FS_IPv6_VPN, RF_FS_L2_VPN:
- t := BGPFlowSpecType(0)
- value := make([]FlowSpecComponentInterface, 0)
- switch rf {
- case RF_FS_IPv4_UC:
- value = prefix.(*FlowSpecIPv4Unicast).Value
- case RF_FS_IPv6_UC:
- value = prefix.(*FlowSpecIPv6Unicast).Value
- case RF_FS_IPv4_VPN:
- value = prefix.(*FlowSpecIPv4VPN).Value
- case RF_FS_IPv6_VPN:
- value = prefix.(*FlowSpecIPv6VPN).Value
- case RF_FS_L2_VPN:
- value = prefix.(*FlowSpecL2VPN).Value
- }
- for _, v := range value {
- if v.Type() <= t {
- return NewMessageError(0, 0, nil, fmt.Sprintf("%s nlri violate strict type ordering", rf))
- }
- t = v.Type()
- }
- }
- }
- return nil
- }
-
- switch p := a.(type) {
- case *PathAttributeMpUnreachNLRI:
- rf := AfiSafiToRouteFamily(p.AFI, p.SAFI)
- if _, ok := rfs[rf]; !ok {
- return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf))
- }
- if err := checkPrefix(p.Value); err != nil {
- return false, err
- }
- case *PathAttributeMpReachNLRI:
- rf := AfiSafiToRouteFamily(p.AFI, p.SAFI)
- if _, ok := rfs[rf]; !ok {
- return false, NewMessageError(0, 0, nil, fmt.Sprintf("Address-family rf %d not available for session", rf))
- }
- if err := checkPrefix(p.Value); err != nil {
- return false, err
- }
- case *PathAttributeOrigin:
- v := uint8(p.Value)
- if v != BGP_ORIGIN_ATTR_TYPE_IGP &&
- v != BGP_ORIGIN_ATTR_TYPE_EGP &&
- v != BGP_ORIGIN_ATTR_TYPE_INCOMPLETE {
- data, _ := a.Serialize()
- eMsg := "invalid origin attribute. value : " + strconv.Itoa(int(v))
- e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadOrigin, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg)
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- }
- case *PathAttributeNextHop:
-
- isZero := func(ip net.IP) bool {
- res := ip[0] & 0xff
- return res == 0x00
- }
-
- isClassDorE := func(ip net.IP) bool {
- res := ip[0] & 0xe0
- return res == 0xe0
- }
-
- //check IP address represents host address
- if p.Value.IsLoopback() || isZero(p.Value) || isClassDorE(p.Value) {
- eMsg := "invalid nexthop address"
- data, _ := a.Serialize()
- e := NewMessageErrorWithErrorHandling(eCode, eSubCodeBadNextHop, data, getErrorHandlingFromPathAttribute(p.GetType()), nil, eMsg)
- if e.(*MessageError).Stronger(strongestError) {
- strongestError = e
- }
- }
- case *PathAttributeAsPath:
- if isEBGP {
- if isConfed {
- if segType := p.Value[0].GetType(); segType != BGP_ASPATH_ATTR_TYPE_CONFED_SEQ {
- return false, NewMessageError(eCode, eSubCodeMalformedAspath, nil, fmt.Sprintf("segment type is not confederation seq (%d)", segType))
- }
- } else {
- for _, param := range p.Value {
- segType := param.GetType()
- switch segType {
- case BGP_ASPATH_ATTR_TYPE_CONFED_SET, BGP_ASPATH_ATTR_TYPE_CONFED_SEQ:
- err := NewMessageErrorWithErrorHandling(
- eCode, eSubCodeMalformedAspath, nil, getErrorHandlingFromPathAttribute(p.GetType()), nil, fmt.Sprintf("segment type confederation(%d) found", segType))
- if err.(*MessageError).Stronger(strongestError) {
- strongestError = err
- }
- }
- }
- }
- }
- case *PathAttributeLargeCommunities:
- uniq := make([]*LargeCommunity, 0, len(p.Values))
- for _, x := range p.Values {
- found := false
- for _, y := range uniq {
- if x.String() == y.String() {
- found = true
- break
- }
- }
- if !found {
- uniq = append(uniq, x)
- }
- }
- p.Values = uniq
-
- case *PathAttributeUnknown:
- if p.GetFlags()&BGP_ATTR_FLAG_OPTIONAL == 0 {
- eMsg := fmt.Sprintf("unrecognized well-known attribute %s", p.GetType())
- data, _ := a.Serialize()
- return false, NewMessageError(eCode, eSubCodeUnknown, data, eMsg)
- }
- }
-
- return strongestError == nil, strongestError
-}
-
-// validator for PathAttribute
-func validatePathAttributeFlags(t BGPAttrType, flags BGPAttrFlag) string {
-
- /*
- * RFC 4271 P.17 For well-known attributes, the Transitive bit MUST be set to 1.
- */
- if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 {
- eMsg := fmt.Sprintf("well-known attribute %s must have transitive flag 1", t)
- return eMsg
- }
- /*
- * RFC 4271 P.17 For well-known attributes and for optional non-transitive attributes,
- * the Partial bit MUST be set to 0.
- */
- if flags&BGP_ATTR_FLAG_OPTIONAL == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 {
- eMsg := fmt.Sprintf("well-known attribute %s must have partial bit 0", t)
- return eMsg
- }
- if flags&BGP_ATTR_FLAG_OPTIONAL != 0 && flags&BGP_ATTR_FLAG_TRANSITIVE == 0 && flags&BGP_ATTR_FLAG_PARTIAL != 0 {
- eMsg := fmt.Sprintf("optional non-transitive attribute %s must have partial bit 0", t)
- return eMsg
- }
-
- // check flags are correct
- if f, ok := PathAttrFlags[t]; ok {
- if f != flags & ^BGP_ATTR_FLAG_EXTENDED_LENGTH & ^BGP_ATTR_FLAG_PARTIAL {
- eMsg := fmt.Sprintf("flags are invalid. attribute type: %s, expect: %s, actual: %s", t, f, flags)
- return eMsg
- }
- }
- return ""
-}
-
-func validateAsPathValueBytes(data []byte) (bool, error) {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH)
- if len(data)%2 != 0 {
- return false, NewMessageError(eCode, eSubCode, nil, "AS PATH length is not odd")
- }
-
- tryParse := func(data []byte, use4byte bool) (bool, error) {
- for len(data) > 0 {
- if len(data) < 2 {
- return false, NewMessageError(eCode, eSubCode, nil, "AS PATH header is short")
- }
- segType := data[0]
- if segType == 0 || segType > 4 {
- return false, NewMessageError(eCode, eSubCode, nil, "unknown AS_PATH seg type")
- }
- asNum := data[1]
- data = data[2:]
- if asNum == 0 || int(asNum) > math.MaxUint8 {
- return false, NewMessageError(eCode, eSubCode, nil, "AS PATH the number of AS is incorrect")
- }
- segLength := int(asNum)
- if use4byte {
- segLength *= 4
- } else {
- segLength *= 2
- }
- if int(segLength) > len(data) {
- return false, NewMessageError(eCode, eSubCode, nil, "seg length is short")
- }
- data = data[segLength:]
- }
- return true, nil
- }
- _, err := tryParse(data, true)
- if err == nil {
- return true, nil
- }
-
- _, err = tryParse(data, false)
- if err == nil {
- return false, nil
- }
- return false, NewMessageError(eCode, eSubCode, nil, "can't parse AS_PATH")
-}
-
-func ValidateBGPMessage(m *BGPMessage) error {
- if m.Header.Len > BGP_MAX_MESSAGE_LENGTH {
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, m.Header.Len)
- return NewMessageError(BGP_ERROR_MESSAGE_HEADER_ERROR, BGP_ERROR_SUB_BAD_MESSAGE_LENGTH, buf, "too long length")
- }
-
- return nil
-}
-
-func ValidateOpenMsg(m *BGPOpen, expectedAS uint32) (uint32, error) {
- if m.Version != 4 {
- return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNSUPPORTED_VERSION_NUMBER, nil, fmt.Sprintf("unsupported version %d", m.Version))
- }
-
- as := uint32(m.MyAS)
- for _, p := range m.OptParams {
- paramCap, y := p.(*OptionParameterCapability)
- if !y {
- continue
- }
- for _, c := range paramCap.Capability {
- if c.Code() == BGP_CAP_FOUR_OCTET_AS_NUMBER {
- cap := c.(*CapFourOctetASNumber)
- as = cap.CapValue
- }
- }
- }
- if expectedAS != 0 && as != expectedAS {
- return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_BAD_PEER_AS, nil, fmt.Sprintf("as number mismatch expected %d, received %d", expectedAS, as))
- }
-
- if m.HoldTime < 3 && m.HoldTime != 0 {
- return 0, NewMessageError(BGP_ERROR_OPEN_MESSAGE_ERROR, BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME, nil, fmt.Sprintf("unacceptable hold time %d", m.HoldTime))
- }
- return as, nil
-}
diff --git a/packet/bgp/validate_test.go b/packet/bgp/validate_test.go
deleted file mode 100644
index 8bdec550..00000000
--- a/packet/bgp/validate_test.go
+++ /dev/null
@@ -1,423 +0,0 @@
-package bgp
-
-import (
- "encoding/binary"
- "net"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func bgpupdate() *BGPMessage {
- aspath := []AsPathParamInterface{
- NewAsPathParam(2, []uint16{65001}),
- }
-
- p := []PathAttributeInterface{
- NewPathAttributeOrigin(1),
- NewPathAttributeAsPath(aspath),
- NewPathAttributeNextHop("192.168.1.1"),
- }
-
- n := []*IPAddrPrefix{NewIPAddrPrefix(24, "10.10.10.0")}
- return NewBGPUpdateMessage(nil, p, n)
-}
-
-func bgpupdateV6() *BGPMessage {
- aspath := []AsPathParamInterface{
- NewAsPathParam(2, []uint16{65001}),
- }
-
- prefixes := []AddrPrefixInterface{NewIPv6AddrPrefix(100,
- "fe80:1234:1234:5667:8967:af12:8912:1023")}
-
- p := []PathAttributeInterface{
- NewPathAttributeOrigin(1),
- NewPathAttributeAsPath(aspath),
- NewPathAttributeMpReachNLRI("1023::", prefixes),
- }
- return NewBGPUpdateMessage(nil, p, nil)
-}
-
-func Test_Validate_CapV4(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
-
- res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- require.NoError(t, err)
- assert.Equal(true, res)
-}
-
-func Test_Validate_CapV6(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdateV6().Body.(*BGPUpdate)
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv6_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.NoError(err)
- assert.True(res)
-
- res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Error(err)
- assert.False(res)
-}
-
-func Test_Validate_OK(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(true, res)
- assert.NoError(err)
-
-}
-
-// func Test_Validate_wellknown_but_nontransitive(t *testing.T) {
-// assert := assert.New(t)
-// message := bgpupdate().Body.(*BGPUpdate)
-
-// originBytes := []byte{0, 1, 1, 1} // 0 means Flags
-// origin := &PathAttributeOrigin{}
-// origin.DecodeFromBytes(originBytes)
-// message.PathAttributes[0] = origin
-
-// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,})
-// assert.Equal(false, res)
-// assert.Error(err)
-// e := err.(*MessageError)
-// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode)
-// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode)
-// assert.Equal(originBytes, e.Data)
-// }
-
-// func Test_Validate_wellknown_but_partial(t *testing.T) {
-// assert := assert.New(t)
-// message := bgpupdate().Body.(*BGPUpdate)
-
-// originBytes := []byte{BGP_ATTR_FLAG_PARTIAL, 1, 1, 1}
-// origin := &PathAttributeOrigin{}
-// origin.DecodeFromBytes(originBytes)
-// message.PathAttributes[0] = origin
-
-// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,})
-// assert.Equal(false, res)
-// assert.Error(err)
-// e := err.(*MessageError)
-// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode)
-// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode)
-// assert.Equal(originBytes, e.Data)
-// }
-
-// func Test_Validate_optional_nontransitive_but_partial(t *testing.T) {
-// assert := assert.New(t)
-// message := bgpupdate().Body.(*BGPUpdate)
-// f := BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_PARTIAL
-// originBytes := []byte{byte(f), 1, 1, 1}
-// origin := &PathAttributeOrigin{}
-// origin.DecodeFromBytes(originBytes)
-// message.PathAttributes[0] = origin
-
-// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,})
-// assert.Equal(false, res)
-// assert.Error(err)
-// e := err.(*MessageError)
-// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode)
-// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode)
-// assert.Equal(originBytes, e.Data)
-// }
-
-// func Test_Validate_flag_mismatch(t *testing.T) {
-// assert := assert.New(t)
-// message := bgpupdate().Body.(*BGPUpdate)
-// f := BGP_ATTR_FLAG_OPTIONAL
-// // origin needs to be well-known
-// originBytes := []byte{byte(f), 1, 1, 1}
-// origin := &PathAttributeOrigin{}
-// origin.DecodeFromBytes(originBytes)
-// message.PathAttributes[0] = origin
-
-// res, err := ValidateUpdateMsg(message, []RouteFamily{RF_IPv4_UC,})
-// assert.Equal(false, res)
-// assert.Error(err)
-// e := err.(*MessageError)
-// assert.Equal(BGP_ERROR_UPDATE_MESSAGE_ERROR, e.TypeCode)
-// assert.Equal(BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, e.SubTypeCode)
-// assert.Equal(originBytes, e.Data)
-// }
-
-func Test_Validate_duplicate_attribute(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- // duplicate origin path attribute
- originBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_ORIGIN]), 1, 1, 1}
- origin := &PathAttributeOrigin{}
- origin.DecodeFromBytes(originBytes)
- message.PathAttributes = append(message.PathAttributes, origin)
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_ATTRIBUTE_DISCARD, e.ErrorHandling)
- assert.Nil(e.Data)
-}
-
-func Test_Validate_mandatory_missing(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- message.PathAttributes = message.PathAttributes[1:]
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_MISSING_WELL_KNOWN_ATTRIBUTE), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- missing, _ := binary.Uvarint(e.Data)
- assert.Equal(uint64(1), missing)
-}
-
-func Test_Validate_mandatory_missing_nocheck(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- message.PathAttributes = message.PathAttributes[1:]
- message.NLRI = nil
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(true, res)
- assert.NoError(err)
-}
-
-func Test_Validate_invalid_origin(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- // origin needs to be well-known
- originBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_ORIGIN]), 1, 1, 5}
- origin := &PathAttributeOrigin{}
- origin.DecodeFromBytes(originBytes)
- message.PathAttributes[0] = origin
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_INVALID_ORIGIN_ATTRIBUTE), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- assert.Equal(originBytes, e.Data)
-}
-
-func Test_Validate_invalid_nexthop_zero(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
-
- // invalid nexthop
- addr := net.ParseIP("0.0.0.1").To4()
- nexthopBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP]), 3, 4}
- nexthopBytes = append(nexthopBytes, addr...)
- nexthop := &PathAttributeNextHop{}
- nexthop.DecodeFromBytes(nexthopBytes)
- message.PathAttributes[2] = nexthop
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- assert.Equal(nexthopBytes, e.Data)
-}
-
-func Test_Validate_invalid_nexthop_lo(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
-
- // invalid nexthop
- addr := net.ParseIP("127.0.0.1").To4()
- nexthopBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP]), 3, 4}
- nexthopBytes = append(nexthopBytes, addr...)
- nexthop := &PathAttributeNextHop{}
- nexthop.DecodeFromBytes(nexthopBytes)
- message.PathAttributes[2] = nexthop
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- assert.Equal(nexthopBytes, e.Data)
-}
-
-func Test_Validate_invalid_nexthop_de(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
-
- // invalid nexthop
- addr := net.ParseIP("224.0.0.1").To4()
- nexthopBytes := []byte{byte(PathAttrFlags[BGP_ATTR_TYPE_NEXT_HOP]), 3, 4}
- nexthopBytes = append(nexthopBytes, addr...)
- nexthop := &PathAttributeNextHop{}
- nexthop.DecodeFromBytes(nexthopBytes)
- message.PathAttributes[2] = nexthop
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_INVALID_NEXT_HOP_ATTRIBUTE), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- assert.Equal(nexthopBytes, e.Data)
-
-}
-
-func Test_Validate_unrecognized_well_known(t *testing.T) {
-
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
- f := BGP_ATTR_FLAG_TRANSITIVE
- unknownBytes := []byte{byte(f), 30, 1, 1}
- unknown := &PathAttributeUnknown{}
- unknown.DecodeFromBytes(unknownBytes)
- message.PathAttributes = append(message.PathAttributes, unknown)
-
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, false, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_UNRECOGNIZED_WELL_KNOWN_ATTRIBUTE), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_SESSION_RESET, e.ErrorHandling)
- assert.Equal(unknownBytes, e.Data)
-}
-
-func Test_Validate_aspath(t *testing.T) {
- assert := assert.New(t)
- message := bgpupdate().Body.(*BGPUpdate)
-
- // VALID AS_PATH
- res, err := ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, false)
- require.NoError(t, err)
- assert.Equal(true, res)
-
- // CONFED_SET
- newAttrs := make([]PathAttributeInterface, 0)
- attrs := message.PathAttributes
- for _, attr := range attrs {
- if _, y := attr.(*PathAttributeAsPath); y {
- aspath := []AsPathParamInterface{
- NewAsPathParam(BGP_ASPATH_ATTR_TYPE_CONFED_SET, []uint16{65001}),
- }
- newAttrs = append(newAttrs, NewPathAttributeAsPath(aspath))
- } else {
- newAttrs = append(newAttrs, attr)
- }
- }
-
- message.PathAttributes = newAttrs
- res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, false)
- assert.Equal(false, res)
- assert.Error(err)
- e := err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- assert.Nil(e.Data)
-
- res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, true)
- assert.Equal(false, res)
- assert.Error(err)
- e = err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH), e.SubTypeCode)
- assert.Nil(e.Data)
-
- // CONFED_SEQ
- newAttrs = make([]PathAttributeInterface, 0)
- attrs = message.PathAttributes
- for _, attr := range attrs {
- if _, y := attr.(*PathAttributeAsPath); y {
- aspath := []AsPathParamInterface{
- NewAsPathParam(BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint16{65001}),
- }
- newAttrs = append(newAttrs, NewPathAttributeAsPath(aspath))
- } else {
- newAttrs = append(newAttrs, attr)
- }
- }
-
- message.PathAttributes = newAttrs
- res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, false)
- assert.Equal(false, res)
- assert.Error(err)
- e = err.(*MessageError)
- assert.Equal(uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR), e.TypeCode)
- assert.Equal(uint8(BGP_ERROR_SUB_MALFORMED_AS_PATH), e.SubTypeCode)
- assert.Equal(ERROR_HANDLING_TREAT_AS_WITHDRAW, e.ErrorHandling)
- assert.Nil(e.Data)
-
- res, err = ValidateUpdateMsg(message, map[RouteFamily]BGPAddPathMode{RF_IPv4_UC: BGP_ADD_PATH_BOTH}, true, true)
- require.NoError(t, err)
- assert.Equal(true, res)
-}
-
-func Test_Validate_flowspec(t *testing.T) {
- assert := assert.New(t)
- cmp := make([]FlowSpecComponentInterface, 0)
- cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- item1 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, TCP)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, []*FlowSpecComponentItem{item1}))
- item2 := NewFlowSpecComponentItem(DEC_NUM_OP_GT_EQ, 20)
- item3 := NewFlowSpecComponentItem(DEC_NUM_OP_AND|DEC_NUM_OP_LT_EQ, 30)
- item4 := NewFlowSpecComponentItem(DEC_NUM_OP_EQ, 10)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DST_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_SRC_PORT, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_TYPE, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_ICMP_CODE, []*FlowSpecComponentItem{item2, item3, item4}))
- item5 := NewFlowSpecComponentItem(0, TCP_FLAG_ACK)
- item6 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_AND|BITMASK_FLAG_OP_NOT, TCP_FLAG_URGENT)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, []*FlowSpecComponentItem{item5, item6}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_PKT_LEN, []*FlowSpecComponentItem{item2, item3, item4}))
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_DSCP, []*FlowSpecComponentItem{item2, item3, item4}))
- isFragment := uint64(0x02)
- item7 := NewFlowSpecComponentItem(BITMASK_FLAG_OP_MATCH, isFragment)
- cmp = append(cmp, NewFlowSpecComponent(FLOW_SPEC_TYPE_FRAGMENT, []*FlowSpecComponentItem{item7}))
- n1 := NewFlowSpecIPv4Unicast(cmp)
- a := NewPathAttributeMpReachNLRI("", []AddrPrefixInterface{n1})
- m := map[RouteFamily]BGPAddPathMode{RF_FS_IPv4_UC: BGP_ADD_PATH_NONE}
- _, err := ValidateAttribute(a, m, false, false)
- assert.Nil(err)
-
- cmp = make([]FlowSpecComponentInterface, 0)
- cmp = append(cmp, NewFlowSpecSourcePrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- cmp = append(cmp, NewFlowSpecDestinationPrefix(NewIPAddrPrefix(24, "10.0.0.0")))
- n1 = NewFlowSpecIPv4Unicast(cmp)
- a = NewPathAttributeMpReachNLRI("", []AddrPrefixInterface{n1})
- // Swaps components order to reproduce the rules order violation.
- n1.Value[0], n1.Value[1] = n1.Value[1], n1.Value[0]
- _, err = ValidateAttribute(a, m, false, false)
- assert.NotNil(err)
-}
-
-func TestValidateLargeCommunities(t *testing.T) {
- assert := assert.New(t)
- c1, err := ParseLargeCommunity("10:10:10")
- assert.Nil(err)
- c2, err := ParseLargeCommunity("10:10:10")
- assert.Nil(err)
- c3, err := ParseLargeCommunity("10:10:20")
- assert.Nil(err)
- a := NewPathAttributeLargeCommunities([]*LargeCommunity{c1, c2, c3})
- assert.True(len(a.Values) == 3)
- _, err = ValidateAttribute(a, nil, false, false)
- assert.Nil(err)
- assert.True(len(a.Values) == 2)
-}
diff --git a/packet/bmp/bmp.go b/packet/bmp/bmp.go
deleted file mode 100644
index eb2ce185..00000000
--- a/packet/bmp/bmp.go
+++ /dev/null
@@ -1,1071 +0,0 @@
-// Copyright (C) 2014,2015 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bmp
-
-import (
- "encoding/binary"
- "fmt"
- "github.com/osrg/gobgp/packet/bgp"
- "math"
- "net"
-)
-
-type BMPHeader struct {
- Version uint8
- Length uint32
- Type uint8
-}
-
-const (
- BMP_VERSION = 3
- BMP_HEADER_SIZE = 6
- BMP_PEER_HEADER_SIZE = 42
-)
-
-const (
- BMP_DEFAULT_PORT = 11019
-)
-
-const (
- BMP_PEER_TYPE_GLOBAL uint8 = iota
- BMP_PEER_TYPE_L3VPN
- BMP_PEER_TYPE_LOCAL
- BMP_PEER_TYPE_LOCAL_RIB
-)
-
-const (
- BMP_PEER_FLAG_IPV6 = 1 << 7
- BMP_PEER_FLAG_POST_POLICY = 1 << 6
- BMP_PEER_FLAG_TWO_AS = 1 << 5
- BMP_PEER_FLAG_FILTERED = 1 << 6
-)
-
-func (h *BMPHeader) DecodeFromBytes(data []byte) error {
- h.Version = data[0]
- if data[0] != BMP_VERSION {
- return fmt.Errorf("error version")
- }
- h.Length = binary.BigEndian.Uint32(data[1:5])
- h.Type = data[5]
- return nil
-}
-
-func (h *BMPHeader) Serialize() ([]byte, error) {
- buf := make([]byte, BMP_HEADER_SIZE)
- buf[0] = h.Version
- binary.BigEndian.PutUint32(buf[1:], h.Length)
- buf[5] = h.Type
- return buf, nil
-}
-
-type BMPPeerHeader struct {
- PeerType uint8
- Flags uint8
- PeerDistinguisher uint64
- PeerAddress net.IP
- PeerAS uint32
- PeerBGPID net.IP
- Timestamp float64
-}
-
-func NewBMPPeerHeader(t uint8, flags uint8, dist uint64, address string, as uint32, id string, stamp float64) *BMPPeerHeader {
- h := &BMPPeerHeader{
- PeerType: t,
- Flags: flags,
- PeerDistinguisher: dist,
- PeerAS: as,
- PeerBGPID: net.ParseIP(id).To4(),
- Timestamp: stamp,
- }
- if net.ParseIP(address).To4() != nil {
- h.PeerAddress = net.ParseIP(address).To4()
- } else {
- h.PeerAddress = net.ParseIP(address).To16()
- h.Flags |= BMP_PEER_FLAG_IPV6
- }
- return h
-}
-
-func (h *BMPPeerHeader) IsPostPolicy() bool {
- if h.Flags&BMP_PEER_FLAG_POST_POLICY != 0 {
- return true
- } else {
- return false
- }
-}
-
-func (h *BMPPeerHeader) DecodeFromBytes(data []byte) error {
- h.PeerType = data[0]
- h.Flags = data[1]
- h.PeerDistinguisher = binary.BigEndian.Uint64(data[2:10])
- if h.Flags&BMP_PEER_FLAG_IPV6 != 0 {
- h.PeerAddress = net.IP(data[10:26]).To16()
- } else {
- h.PeerAddress = net.IP(data[22:26]).To4()
- }
- h.PeerAS = binary.BigEndian.Uint32(data[26:30])
- h.PeerBGPID = data[30:34]
-
- timestamp1 := binary.BigEndian.Uint32(data[34:38])
- timestamp2 := binary.BigEndian.Uint32(data[38:42])
- h.Timestamp = float64(timestamp1) + float64(timestamp2)*math.Pow10(-6)
- return nil
-}
-
-func (h *BMPPeerHeader) Serialize() ([]byte, error) {
- buf := make([]byte, BMP_PEER_HEADER_SIZE)
- buf[0] = h.PeerType
- buf[1] = h.Flags
- binary.BigEndian.PutUint64(buf[2:10], h.PeerDistinguisher)
- if h.Flags&BMP_PEER_FLAG_IPV6 != 0 {
- copy(buf[10:26], h.PeerAddress)
- } else {
- copy(buf[22:26], h.PeerAddress.To4())
- }
- binary.BigEndian.PutUint32(buf[26:30], h.PeerAS)
- copy(buf[30:34], h.PeerBGPID)
- t1, t2 := math.Modf(h.Timestamp)
- t2 = math.Ceil(t2 * math.Pow10(6))
- binary.BigEndian.PutUint32(buf[34:38], uint32(t1))
- binary.BigEndian.PutUint32(buf[38:42], uint32(t2))
- return buf, nil
-}
-
-type BMPRouteMonitoring struct {
- BGPUpdate *bgp.BGPMessage
- BGPUpdatePayload []byte
-}
-
-func NewBMPRouteMonitoring(p BMPPeerHeader, update *bgp.BGPMessage) *BMPMessage {
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_ROUTE_MONITORING,
- },
- PeerHeader: p,
- Body: &BMPRouteMonitoring{
- BGPUpdate: update,
- },
- }
-}
-
-func (body *BMPRouteMonitoring) ParseBody(msg *BMPMessage, data []byte) error {
- update, err := bgp.ParseBGPMessage(data)
- if err != nil {
- return err
- }
- body.BGPUpdate = update
- return nil
-}
-
-func (body *BMPRouteMonitoring) Serialize() ([]byte, error) {
- if body.BGPUpdatePayload != nil {
- return body.BGPUpdatePayload, nil
- }
- return body.BGPUpdate.Serialize()
-}
-
-const (
- BMP_STAT_TYPE_REJECTED = iota
- BMP_STAT_TYPE_DUPLICATE_PREFIX
- BMP_STAT_TYPE_DUPLICATE_WITHDRAW
- BMP_STAT_TYPE_INV_UPDATE_DUE_TO_CLUSTER_LIST_LOOP
- BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_PATH_LOOP
- BMP_STAT_TYPE_INV_UPDATE_DUE_TO_ORIGINATOR_ID
- BMP_STAT_TYPE_INV_UPDATE_DUE_TO_AS_CONFED_LOOP
- BMP_STAT_TYPE_ADJ_RIB_IN
- BMP_STAT_TYPE_LOC_RIB
- BMP_STAT_TYPE_PER_AFI_SAFI_ADJ_RIB_IN
- BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB
- BMP_STAT_TYPE_WITHDRAW_UPDATE
- BMP_STAT_TYPE_WITHDRAW_PREFIX
- BMP_STAT_TYPE_DUPLICATE_UPDATE
-)
-
-type BMPStatsTLVInterface interface {
- ParseValue([]byte) error
- Serialize() ([]byte, error)
-}
-
-type BMPStatsTLV struct {
- Type uint16
- Length uint16
-}
-
-type BMPStatsTLV32 struct {
- BMPStatsTLV
- Value uint32
-}
-
-func NewBMPStatsTLV32(t uint16, v uint32) *BMPStatsTLV32 {
- return &BMPStatsTLV32{
- BMPStatsTLV: BMPStatsTLV{
- Type: t,
- Length: 4,
- },
- Value: v,
- }
-}
-
-func (s *BMPStatsTLV32) ParseValue(data []byte) error {
- if s.Length != 4 {
- return fmt.Errorf("invalid length: %d bytes (%d bytes expected)", s.Length, 4)
- }
- s.Value = binary.BigEndian.Uint32(data[:8])
- return nil
-}
-
-func (s *BMPStatsTLV32) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], 4)
- binary.BigEndian.PutUint32(buf[4:8], s.Value)
- return buf, nil
-}
-
-type BMPStatsTLV64 struct {
- BMPStatsTLV
- Value uint64
-}
-
-func NewBMPStatsTLV64(t uint16, v uint64) *BMPStatsTLV64 {
- return &BMPStatsTLV64{
- BMPStatsTLV: BMPStatsTLV{
- Type: t,
- Length: 8,
- },
- Value: v,
- }
-}
-
-func (s *BMPStatsTLV64) ParseValue(data []byte) error {
- if s.Length != 8 {
- return fmt.Errorf("invalid length: %d bytes (%d bytes expected)", s.Length, 8)
- }
- s.Value = binary.BigEndian.Uint64(data[:8])
- return nil
-}
-
-func (s *BMPStatsTLV64) Serialize() ([]byte, error) {
- buf := make([]byte, 12)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], 8)
- binary.BigEndian.PutUint64(buf[4:12], s.Value)
- return buf, nil
-}
-
-type BMPStatsTLVPerAfiSafi64 struct {
- BMPStatsTLV
- AFI uint16
- SAFI uint8
- Value uint64
-}
-
-func NewBMPStatsTLVPerAfiSafi64(t uint16, afi uint16, safi uint8, v uint64) *BMPStatsTLVPerAfiSafi64 {
- return &BMPStatsTLVPerAfiSafi64{
- BMPStatsTLV: BMPStatsTLV{
- Type: t,
- Length: 11,
- },
- AFI: afi,
- SAFI: safi,
- Value: v,
- }
-}
-
-func (s *BMPStatsTLVPerAfiSafi64) ParseValue(data []byte) error {
- if s.Length != 11 {
- return fmt.Errorf("invalid length: %d bytes (%d bytes expected)", s.Length, 11)
- }
- s.AFI = binary.BigEndian.Uint16(data[0:2])
- s.SAFI = data[2]
- s.Value = binary.BigEndian.Uint64(data[3:11])
- return nil
-}
-
-func (s *BMPStatsTLVPerAfiSafi64) Serialize() ([]byte, error) {
- buf := make([]byte, 15)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], 11)
- binary.BigEndian.PutUint16(buf[4:6], s.AFI)
- buf[6] = s.SAFI
- binary.BigEndian.PutUint64(buf[7:15], s.Value)
- return buf, nil
-}
-
-type BMPStatisticsReport struct {
- Count uint32
- Stats []BMPStatsTLVInterface
-}
-
-func NewBMPStatisticsReport(p BMPPeerHeader, stats []BMPStatsTLVInterface) *BMPMessage {
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_STATISTICS_REPORT,
- },
- PeerHeader: p,
- Body: &BMPStatisticsReport{
- Count: uint32(len(stats)),
- Stats: stats,
- },
- }
-}
-
-func (body *BMPStatisticsReport) ParseBody(msg *BMPMessage, data []byte) error {
- body.Count = binary.BigEndian.Uint32(data[0:4])
- data = data[4:]
- for len(data) >= 4 {
- tl := BMPStatsTLV{
- Type: binary.BigEndian.Uint16(data[0:2]),
- Length: binary.BigEndian.Uint16(data[2:4]),
- }
- data = data[4:]
- if len(data) < int(tl.Length) {
- return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length)
- }
- var s BMPStatsTLVInterface
- switch tl.Type {
- case BMP_STAT_TYPE_ADJ_RIB_IN, BMP_STAT_TYPE_LOC_RIB:
- s = &BMPStatsTLV64{BMPStatsTLV: tl}
- case BMP_STAT_TYPE_PER_AFI_SAFI_ADJ_RIB_IN, BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB:
- s = &BMPStatsTLVPerAfiSafi64{BMPStatsTLV: tl}
- default:
- s = &BMPStatsTLV32{BMPStatsTLV: tl}
- }
- if err := s.ParseValue(data); err != nil {
- return err
- }
- body.Stats = append(body.Stats, s)
- data = data[tl.Length:]
- }
- return nil
-}
-
-func (body *BMPStatisticsReport) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- body.Count = uint32(len(body.Stats))
- binary.BigEndian.PutUint32(buf[0:4], body.Count)
- for _, tlv := range body.Stats {
- tlvBuf, err := tlv.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, tlvBuf...)
- }
- return buf, nil
-}
-
-const (
- BMP_PEER_DOWN_REASON_UNKNOWN = iota
- BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION
- BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION
- BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION
- BMP_PEER_DOWN_REASON_REMOTE_NO_NOTIFICATION
- BMP_PEER_DOWN_REASON_PEER_DE_CONFIGURED
-)
-
-type BMPPeerDownNotification struct {
- Reason uint8
- BGPNotification *bgp.BGPMessage
- Data []byte
-}
-
-func NewBMPPeerDownNotification(p BMPPeerHeader, reason uint8, notification *bgp.BGPMessage, data []byte) *BMPMessage {
- b := &BMPPeerDownNotification{
- Reason: reason,
- }
- switch reason {
- case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION:
- b.BGPNotification = notification
- case BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION:
- b.Data = data
- default:
- }
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_PEER_DOWN_NOTIFICATION,
- },
- PeerHeader: p,
- Body: b,
- }
-}
-
-func (body *BMPPeerDownNotification) ParseBody(msg *BMPMessage, data []byte) error {
- body.Reason = data[0]
- data = data[1:]
- if body.Reason == BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION || body.Reason == BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION {
- notification, err := bgp.ParseBGPMessage(data)
- if err != nil {
- return err
- }
- body.BGPNotification = notification
- } else {
- body.Data = data
- }
- return nil
-}
-
-func (body *BMPPeerDownNotification) Serialize() ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = body.Reason
- switch body.Reason {
- case BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION, BMP_PEER_DOWN_REASON_REMOTE_BGP_NOTIFICATION:
- if body.BGPNotification != nil {
- b, err := body.BGPNotification.Serialize()
- if err != nil {
- return nil, err
- } else {
- buf = append(buf, b...)
- }
- }
- default:
- if body.Data != nil {
- buf = append(buf, body.Data...)
- }
- }
- return buf, nil
-}
-
-type BMPPeerUpNotification struct {
- LocalAddress net.IP
- LocalPort uint16
- RemotePort uint16
- SentOpenMsg *bgp.BGPMessage
- ReceivedOpenMsg *bgp.BGPMessage
-}
-
-func NewBMPPeerUpNotification(p BMPPeerHeader, lAddr string, lPort, rPort uint16, sent, recv *bgp.BGPMessage) *BMPMessage {
- b := &BMPPeerUpNotification{
- LocalPort: lPort,
- RemotePort: rPort,
- SentOpenMsg: sent,
- ReceivedOpenMsg: recv,
- }
- addr := net.ParseIP(lAddr)
- if addr.To4() != nil {
- b.LocalAddress = addr.To4()
- } else {
- b.LocalAddress = addr.To16()
- }
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_PEER_UP_NOTIFICATION,
- },
- PeerHeader: p,
- Body: b,
- }
-}
-
-func (body *BMPPeerUpNotification) ParseBody(msg *BMPMessage, data []byte) error {
- if msg.PeerHeader.Flags&BMP_PEER_FLAG_IPV6 != 0 {
- body.LocalAddress = net.IP(data[:16]).To16()
- } else {
- body.LocalAddress = net.IP(data[12:16]).To4()
- }
-
- body.LocalPort = binary.BigEndian.Uint16(data[16:18])
- body.RemotePort = binary.BigEndian.Uint16(data[18:20])
-
- data = data[20:]
- sentopen, err := bgp.ParseBGPMessage(data)
- if err != nil {
- return err
- }
- body.SentOpenMsg = sentopen
- data = data[body.SentOpenMsg.Header.Len:]
- body.ReceivedOpenMsg, err = bgp.ParseBGPMessage(data)
- if err != nil {
- return err
- }
- return nil
-}
-
-func (body *BMPPeerUpNotification) Serialize() ([]byte, error) {
- buf := make([]byte, 20)
- if body.LocalAddress.To4() != nil {
- copy(buf[12:16], body.LocalAddress.To4())
- } else {
- copy(buf[:16], body.LocalAddress.To16())
- }
-
- binary.BigEndian.PutUint16(buf[16:18], body.LocalPort)
- binary.BigEndian.PutUint16(buf[18:20], body.RemotePort)
-
- m, _ := body.SentOpenMsg.Serialize()
- buf = append(buf, m...)
- m, _ = body.ReceivedOpenMsg.Serialize()
- buf = append(buf, m...)
- return buf, nil
-}
-
-const (
- BMP_INIT_TLV_TYPE_STRING = iota
- BMP_INIT_TLV_TYPE_SYS_DESCR
- BMP_INIT_TLV_TYPE_SYS_NAME
-)
-
-type BMPInfoTLVInterface interface {
- ParseValue([]byte) error
- Serialize() ([]byte, error)
-}
-
-type BMPInfoTLV struct {
- Type uint16
- Length uint16
-}
-
-type BMPInfoTLVString struct {
- BMPInfoTLV
- Value string
-}
-
-func NewBMPInfoTLVString(t uint16, v string) *BMPInfoTLVString {
- return &BMPInfoTLVString{
- BMPInfoTLV: BMPInfoTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPInfoTLVString) ParseValue(data []byte) error {
- s.Value = string(data[:s.Length])
- return nil
-}
-
-func (s *BMPInfoTLVString) Serialize() ([]byte, error) {
- s.Length = uint16(len([]byte(s.Value)))
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- buf = append(buf, []byte(s.Value)...)
- return buf, nil
-}
-
-type BMPInfoTLVUnknown struct {
- BMPInfoTLV
- Value []byte
-}
-
-func NewBMPInfoTLVUnknown(t uint16, v []byte) *BMPInfoTLVUnknown {
- return &BMPInfoTLVUnknown{
- BMPInfoTLV: BMPInfoTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPInfoTLVUnknown) ParseValue(data []byte) error {
- s.Value = data[:s.Length]
- return nil
-}
-
-func (s *BMPInfoTLVUnknown) Serialize() ([]byte, error) {
- s.Length = uint16(len([]byte(s.Value)))
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- buf = append(buf, s.Value...)
- return buf, nil
-}
-
-type BMPInitiation struct {
- Info []BMPInfoTLVInterface
-}
-
-func NewBMPInitiation(info []BMPInfoTLVInterface) *BMPMessage {
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_INITIATION,
- },
- Body: &BMPInitiation{
- Info: info,
- },
- }
-}
-
-func (body *BMPInitiation) ParseBody(msg *BMPMessage, data []byte) error {
- for len(data) >= 4 {
- tl := BMPInfoTLV{
- Type: binary.BigEndian.Uint16(data[0:2]),
- Length: binary.BigEndian.Uint16(data[2:4]),
- }
- data = data[4:]
- if len(data) < int(tl.Length) {
- return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length)
- }
- var tlv BMPInfoTLVInterface
- switch tl.Type {
- case BMP_INIT_TLV_TYPE_STRING, BMP_INIT_TLV_TYPE_SYS_DESCR, BMP_INIT_TLV_TYPE_SYS_NAME:
- tlv = &BMPInfoTLVString{BMPInfoTLV: tl}
- default:
- tlv = &BMPInfoTLVUnknown{BMPInfoTLV: tl}
- }
- if err := tlv.ParseValue(data); err != nil {
- return err
- }
- body.Info = append(body.Info, tlv)
- data = data[tl.Length:]
- }
- return nil
-}
-
-func (body *BMPInitiation) Serialize() ([]byte, error) {
- buf := make([]byte, 0)
- for _, tlv := range body.Info {
- b, err := tlv.Serialize()
- if err != nil {
- return buf, err
- }
- buf = append(buf, b...)
- }
- return buf, nil
-}
-
-const (
- BMP_TERM_TLV_TYPE_STRING = iota
- BMP_TERM_TLV_TYPE_REASON
-)
-
-const (
- BMP_TERM_REASON_ADMIN = iota
- BMP_TERM_REASON_UNSPEC
- BMP_TERM_REASON_OUT_OF_RESOURCES
- BMP_TERM_REASON_REDUNDANT_CONNECTION
- BMP_TERM_REASON_PERMANENTLY_ADMIN
-)
-
-type BMPTermTLVInterface interface {
- ParseValue([]byte) error
- Serialize() ([]byte, error)
-}
-
-type BMPTermTLV struct {
- Type uint16
- Length uint16
-}
-
-type BMPTermTLVString struct {
- BMPTermTLV
- Value string
-}
-
-func NewBMPTermTLVString(t uint16, v string) *BMPTermTLVString {
- return &BMPTermTLVString{
- BMPTermTLV: BMPTermTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPTermTLVString) ParseValue(data []byte) error {
- s.Value = string(data[:s.Length])
- return nil
-}
-
-func (s *BMPTermTLVString) Serialize() ([]byte, error) {
- s.Length = uint16(len([]byte(s.Value)))
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- buf = append(buf, []byte(s.Value)...)
- return buf, nil
-}
-
-type BMPTermTLV16 struct {
- BMPTermTLV
- Value uint16
-}
-
-func NewBMPTermTLV16(t uint16, v uint16) *BMPTermTLV16 {
- return &BMPTermTLV16{
- BMPTermTLV: BMPTermTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPTermTLV16) ParseValue(data []byte) error {
- s.Value = binary.BigEndian.Uint16(data[:2])
- return nil
-}
-
-func (s *BMPTermTLV16) Serialize() ([]byte, error) {
- s.Length = 2
- buf := make([]byte, 6)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- binary.BigEndian.PutUint16(buf[4:6], s.Value)
- return buf, nil
-}
-
-type BMPTermTLVUnknown struct {
- BMPTermTLV
- Value []byte
-}
-
-func NewBMPTermTLVUnknown(t uint16, v []byte) *BMPTermTLVUnknown {
- return &BMPTermTLVUnknown{
- BMPTermTLV: BMPTermTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPTermTLVUnknown) ParseValue(data []byte) error {
- s.Value = data[:s.Length]
- return nil
-}
-
-func (s *BMPTermTLVUnknown) Serialize() ([]byte, error) {
- s.Length = uint16(len([]byte(s.Value)))
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- buf = append(buf, s.Value...)
- return buf, nil
-}
-
-type BMPTermination struct {
- Info []BMPTermTLVInterface
-}
-
-func NewBMPTermination(info []BMPTermTLVInterface) *BMPMessage {
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_TERMINATION,
- },
- Body: &BMPTermination{
- Info: info,
- },
- }
-}
-
-func (body *BMPTermination) ParseBody(msg *BMPMessage, data []byte) error {
- for len(data) >= 4 {
- tl := BMPTermTLV{
- Type: binary.BigEndian.Uint16(data[0:2]),
- Length: binary.BigEndian.Uint16(data[2:4]),
- }
- data = data[4:]
- if len(data) < int(tl.Length) {
- return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length)
- }
- var tlv BMPTermTLVInterface
- switch tl.Type {
- case BMP_TERM_TLV_TYPE_STRING:
- tlv = &BMPTermTLVString{BMPTermTLV: tl}
- case BMP_TERM_TLV_TYPE_REASON:
- tlv = &BMPTermTLV16{BMPTermTLV: tl}
- default:
- tlv = &BMPTermTLVUnknown{BMPTermTLV: tl}
- }
- if err := tlv.ParseValue(data); err != nil {
- return err
- }
- body.Info = append(body.Info, tlv)
- data = data[tl.Length:]
- }
- return nil
-}
-
-func (body *BMPTermination) Serialize() ([]byte, error) {
- buf := make([]byte, 0)
- for _, tlv := range body.Info {
- b, err := tlv.Serialize()
- if err != nil {
- return buf, err
- }
- buf = append(buf, b...)
- }
- return buf, nil
-}
-
-const (
- BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG = iota
- BMP_ROUTE_MIRRORING_TLV_TYPE_INFO
-)
-
-const (
- BMP_ROUTE_MIRRORING_INFO_ERR_PDU = iota
- BMP_ROUTE_MIRRORING_INFO_MSG_LOST
-)
-
-type BMPRouteMirrTLVInterface interface {
- ParseValue([]byte) error
- Serialize() ([]byte, error)
-}
-
-type BMPRouteMirrTLV struct {
- Type uint16
- Length uint16
-}
-
-type BMPRouteMirrTLVBGPMsg struct {
- BMPRouteMirrTLV
- Value *bgp.BGPMessage
-}
-
-func NewBMPRouteMirrTLVBGPMsg(t uint16, v *bgp.BGPMessage) *BMPRouteMirrTLVBGPMsg {
- return &BMPRouteMirrTLVBGPMsg{
- BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPRouteMirrTLVBGPMsg) ParseValue(data []byte) error {
- v, err := bgp.ParseBGPMessage(data)
- if err != nil {
- return err
- }
- s.Value = v
- return nil
-}
-
-func (s *BMPRouteMirrTLVBGPMsg) Serialize() ([]byte, error) {
- m, err := s.Value.Serialize()
- if err != nil {
- return nil, err
- }
- s.Length = uint16(len(m))
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- buf = append(buf, m...)
- return buf, nil
-}
-
-type BMPRouteMirrTLV16 struct {
- BMPRouteMirrTLV
- Value uint16
-}
-
-func NewBMPRouteMirrTLV16(t uint16, v uint16) *BMPRouteMirrTLV16 {
- return &BMPRouteMirrTLV16{
- BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPRouteMirrTLV16) ParseValue(data []byte) error {
- s.Value = binary.BigEndian.Uint16(data[:2])
- return nil
-}
-
-func (s *BMPRouteMirrTLV16) Serialize() ([]byte, error) {
- s.Length = 2
- buf := make([]byte, 6)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- binary.BigEndian.PutUint16(buf[4:6], s.Value)
- return buf, nil
-}
-
-type BMPRouteMirrTLVUnknown struct {
- BMPRouteMirrTLV
- Value []byte
-}
-
-func NewBMPRouteMirrTLVUnknown(t uint16, v []byte) *BMPRouteMirrTLVUnknown {
- return &BMPRouteMirrTLVUnknown{
- BMPRouteMirrTLV: BMPRouteMirrTLV{Type: t},
- Value: v,
- }
-}
-
-func (s *BMPRouteMirrTLVUnknown) ParseValue(data []byte) error {
- s.Value = data[:s.Length]
- return nil
-}
-
-func (s *BMPRouteMirrTLVUnknown) Serialize() ([]byte, error) {
- s.Length = uint16(len([]byte(s.Value)))
- buf := make([]byte, 4)
- binary.BigEndian.PutUint16(buf[0:2], s.Type)
- binary.BigEndian.PutUint16(buf[2:4], s.Length)
- buf = append(buf, s.Value...)
- return buf, nil
-}
-
-type BMPRouteMirroring struct {
- Info []BMPRouteMirrTLVInterface
-}
-
-func NewBMPRouteMirroring(p BMPPeerHeader, info []BMPRouteMirrTLVInterface) *BMPMessage {
- return &BMPMessage{
- Header: BMPHeader{
- Version: BMP_VERSION,
- Type: BMP_MSG_ROUTE_MIRRORING,
- },
- PeerHeader: p,
- Body: &BMPRouteMirroring{
- Info: info,
- },
- }
-}
-
-func (body *BMPRouteMirroring) ParseBody(msg *BMPMessage, data []byte) error {
- for len(data) >= 4 {
- tl := BMPRouteMirrTLV{
- Type: binary.BigEndian.Uint16(data[0:2]),
- Length: binary.BigEndian.Uint16(data[2:4]),
- }
- data = data[4:]
- if len(data) < int(tl.Length) {
- return fmt.Errorf("value length is not enough: %d bytes (%d bytes expected)", len(data), tl.Length)
- }
- var tlv BMPRouteMirrTLVInterface
- switch tl.Type {
- case BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG:
- tlv = &BMPRouteMirrTLVBGPMsg{BMPRouteMirrTLV: tl}
- case BMP_ROUTE_MIRRORING_TLV_TYPE_INFO:
- tlv = &BMPRouteMirrTLV16{BMPRouteMirrTLV: tl}
- default:
- tlv = &BMPRouteMirrTLVUnknown{BMPRouteMirrTLV: tl}
- }
- if err := tlv.ParseValue(data); err != nil {
- return err
- }
- body.Info = append(body.Info, tlv)
- data = data[tl.Length:]
- }
- return nil
-}
-
-func (body *BMPRouteMirroring) Serialize() ([]byte, error) {
- buf := make([]byte, 0)
- for _, tlv := range body.Info {
- b, err := tlv.Serialize()
- if err != nil {
- return buf, err
- }
- buf = append(buf, b...)
- }
- return buf, nil
-}
-
-type BMPBody interface {
- // Sigh, some body messages need a BMPHeader to parse the body
- // data so we need to pass BMPHeader (avoid DecodeFromBytes
- // function name).
- ParseBody(*BMPMessage, []byte) error
- Serialize() ([]byte, error)
-}
-
-type BMPMessage struct {
- Header BMPHeader
- PeerHeader BMPPeerHeader
- Body BMPBody
-}
-
-func (msg *BMPMessage) Serialize() ([]byte, error) {
- buf := make([]byte, 0)
- if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION {
- p, err := msg.PeerHeader.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, p...)
- }
-
- b, err := msg.Body.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, b...)
-
- if msg.Header.Length == 0 {
- msg.Header.Length = uint32(BMP_HEADER_SIZE + len(buf))
- }
-
- h, err := msg.Header.Serialize()
- if err != nil {
- return nil, err
- }
- return append(h, buf...), nil
-}
-
-func (msg *BMPMessage) Len() int {
- return int(msg.Header.Length)
-}
-
-const (
- BMP_MSG_ROUTE_MONITORING = iota
- BMP_MSG_STATISTICS_REPORT
- BMP_MSG_PEER_DOWN_NOTIFICATION
- BMP_MSG_PEER_UP_NOTIFICATION
- BMP_MSG_INITIATION
- BMP_MSG_TERMINATION
- BMP_MSG_ROUTE_MIRRORING
-)
-
-func ParseBMPMessage(data []byte) (msg *BMPMessage, err error) {
- defer func() {
- if r := recover(); r != nil {
- err = fmt.Errorf("not all data bytes are available")
- }
- }()
-
- msg = &BMPMessage{}
- err = msg.Header.DecodeFromBytes(data)
- if err != nil {
- return nil, err
- }
- data = data[BMP_HEADER_SIZE:msg.Header.Length]
-
- switch msg.Header.Type {
- case BMP_MSG_ROUTE_MONITORING:
- msg.Body = &BMPRouteMonitoring{}
- case BMP_MSG_STATISTICS_REPORT:
- msg.Body = &BMPStatisticsReport{}
- case BMP_MSG_PEER_DOWN_NOTIFICATION:
- msg.Body = &BMPPeerDownNotification{}
- case BMP_MSG_PEER_UP_NOTIFICATION:
- msg.Body = &BMPPeerUpNotification{}
- case BMP_MSG_INITIATION:
- msg.Body = &BMPInitiation{}
- case BMP_MSG_TERMINATION:
- msg.Body = &BMPTermination{}
- case BMP_MSG_ROUTE_MIRRORING:
- msg.Body = &BMPRouteMirroring{}
- default:
- return nil, fmt.Errorf("unsupported BMP message type: %d", msg.Header.Type)
- }
-
- if msg.Header.Type != BMP_MSG_INITIATION && msg.Header.Type != BMP_MSG_TERMINATION {
- msg.PeerHeader.DecodeFromBytes(data)
- data = data[BMP_PEER_HEADER_SIZE:]
- }
-
- err = msg.Body.ParseBody(msg, data)
- if err != nil {
- return nil, err
- }
- return msg, nil
-}
-
-func SplitBMP(data []byte, atEOF bool) (advance int, token []byte, err error) {
- if atEOF && len(data) == 0 || len(data) < BMP_HEADER_SIZE {
- return 0, nil, nil
- }
-
- msg := &BMPMessage{}
- msg.Header.DecodeFromBytes(data)
- if uint32(len(data)) < msg.Header.Length {
- return 0, nil, nil
- }
-
- return int(msg.Header.Length), data[0:msg.Header.Length], nil
-}
diff --git a/packet/bmp/bmp_test.go b/packet/bmp/bmp_test.go
deleted file mode 100644
index fde4cd0f..00000000
--- a/packet/bmp/bmp_test.go
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package bmp
-
-import (
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/osrg/gobgp/packet/bgp"
-
- "github.com/stretchr/testify/assert"
-)
-
-func verify(t *testing.T, m1 *BMPMessage) {
- buf1, _ := m1.Serialize()
- m2, err := ParseBMPMessage(buf1)
- require.NoError(t, err)
-
- assert.Equal(t, m1, m2)
-}
-
-func Test_Initiation(t *testing.T) {
- verify(t, NewBMPInitiation(nil))
- m := NewBMPInitiation([]BMPInfoTLVInterface{
- NewBMPInfoTLVString(BMP_INIT_TLV_TYPE_STRING, "free-form UTF-8 string"),
- NewBMPInfoTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}),
- })
- verify(t, m)
-}
-
-func Test_Termination(t *testing.T) {
- verify(t, NewBMPTermination(nil))
- m := NewBMPTermination([]BMPTermTLVInterface{
- NewBMPTermTLVString(BMP_TERM_TLV_TYPE_STRING, "free-form UTF-8 string"),
- NewBMPTermTLV16(BMP_TERM_TLV_TYPE_REASON, BMP_TERM_REASON_ADMIN),
- NewBMPTermTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}),
- })
- verify(t, m)
-}
-
-func Test_PeerUpNotification(t *testing.T) {
- m := bgp.NewTestBGPOpenMessage()
- p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1)
- verify(t, NewBMPPeerUpNotification(*p0, "10.0.0.3", 10, 100, m, m))
- p1 := NewBMPPeerHeader(0, 0, 1000, "fe80::6e40:8ff:feab:2c2a", 70000, "10.0.0.2", 1)
- verify(t, NewBMPPeerUpNotification(*p1, "fe80::6e40:8ff:feab:2c2a", 10, 100, m, m))
-}
-
-func Test_PeerDownNotification(t *testing.T) {
- p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1)
- verify(t, NewBMPPeerDownNotification(*p0, BMP_PEER_DOWN_REASON_LOCAL_NO_NOTIFICATION, nil, []byte{0x3, 0xb}))
- m := bgp.NewBGPNotificationMessage(1, 2, nil)
- verify(t, NewBMPPeerDownNotification(*p0, BMP_PEER_DOWN_REASON_LOCAL_BGP_NOTIFICATION, m, nil))
-}
-
-func Test_RouteMonitoring(t *testing.T) {
- m := bgp.NewTestBGPUpdateMessage()
- p0 := NewBMPPeerHeader(0, 0, 1000, "fe80::6e40:8ff:feab:2c2a", 70000, "10.0.0.2", 1)
- verify(t, NewBMPRouteMonitoring(*p0, m))
-}
-
-func Test_StatisticsReport(t *testing.T) {
- p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1)
- s0 := NewBMPStatisticsReport(
- *p0,
- []BMPStatsTLVInterface{
- NewBMPStatsTLV32(BMP_STAT_TYPE_REJECTED, 100),
- NewBMPStatsTLV64(BMP_STAT_TYPE_ADJ_RIB_IN, 200),
- NewBMPStatsTLVPerAfiSafi64(BMP_STAT_TYPE_PER_AFI_SAFI_LOC_RIB, bgp.AFI_IP, bgp.SAFI_UNICAST, 300),
- },
- )
- verify(t, s0)
-}
-
-func Test_RouteMirroring(t *testing.T) {
- p0 := NewBMPPeerHeader(0, 0, 1000, "10.0.0.1", 70000, "10.0.0.2", 1)
- s0 := NewBMPRouteMirroring(
- *p0,
- []BMPRouteMirrTLVInterface{
- NewBMPRouteMirrTLV16(BMP_ROUTE_MIRRORING_TLV_TYPE_INFO, BMP_ROUTE_MIRRORING_INFO_MSG_LOST),
- NewBMPRouteMirrTLVUnknown(0xff, []byte{0x01, 0x02, 0x03, 0x04}),
- // RFC7854: BGP Message TLV MUST occur last in the list of TLVs
- NewBMPRouteMirrTLVBGPMsg(BMP_ROUTE_MIRRORING_TLV_TYPE_BGP_MSG, bgp.NewTestBGPOpenMessage()),
- },
- )
- verify(t, s0)
-}
-
-func Test_BogusHeader(t *testing.T) {
- h, err := ParseBMPMessage(make([]byte, 10))
- assert.Nil(t, h)
- assert.NotNil(t, err)
-}
diff --git a/packet/mrt/mrt.go b/packet/mrt/mrt.go
deleted file mode 100644
index 9c6fef6d..00000000
--- a/packet/mrt/mrt.go
+++ /dev/null
@@ -1,1006 +0,0 @@
-// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package mrt
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "math"
- "net"
- "time"
-
- "github.com/osrg/gobgp/packet/bgp"
-)
-
-const (
- MRT_COMMON_HEADER_LEN = 12
-)
-
-type MRTType uint16
-
-const (
- NULL MRTType = 0 // deprecated
- START MRTType = 1 // deprecated
- DIE MRTType = 2 // deprecated
- I_AM_DEAD MRTType = 3 // deprecated
- PEER_DOWN MRTType = 4 // deprecated
- BGP MRTType = 5 // deprecated
- RIP MRTType = 6 // deprecated
- IDRP MRTType = 7 // deprecated
- RIPNG MRTType = 8 // deprecated
- BGP4PLUS MRTType = 9 // deprecated
- BGP4PLUS01 MRTType = 10 // deprecated
- OSPFv2 MRTType = 11
- TABLE_DUMP MRTType = 12
- TABLE_DUMPv2 MRTType = 13
- BGP4MP MRTType = 16
- BGP4MP_ET MRTType = 17
- ISIS MRTType = 32
- ISIS_ET MRTType = 33
- OSPFv3 MRTType = 48
- OSPFv3_ET MRTType = 49
-)
-
-type MRTSubTyper interface {
- ToUint16() uint16
-}
-
-type MRTSubTypeTableDumpv2 uint16
-
-const (
- PEER_INDEX_TABLE MRTSubTypeTableDumpv2 = 1
- RIB_IPV4_UNICAST MRTSubTypeTableDumpv2 = 2
- RIB_IPV4_MULTICAST MRTSubTypeTableDumpv2 = 3
- RIB_IPV6_UNICAST MRTSubTypeTableDumpv2 = 4
- RIB_IPV6_MULTICAST MRTSubTypeTableDumpv2 = 5
- RIB_GENERIC MRTSubTypeTableDumpv2 = 6
- GEO_PEER_TABLE MRTSubTypeTableDumpv2 = 7 // RFC6397
- RIB_IPV4_UNICAST_ADDPATH MRTSubTypeTableDumpv2 = 8 // RFC8050
- RIB_IPV4_MULTICAST_ADDPATH MRTSubTypeTableDumpv2 = 9 // RFC8050
- RIB_IPV6_UNICAST_ADDPATH MRTSubTypeTableDumpv2 = 10 // RFC8050
- RIB_IPV6_MULTICAST_ADDPATH MRTSubTypeTableDumpv2 = 11 // RFC8050
- RIB_GENERIC_ADDPATH MRTSubTypeTableDumpv2 = 12 // RFC8050
-)
-
-func (t MRTSubTypeTableDumpv2) ToUint16() uint16 {
- return uint16(t)
-}
-
-type MRTSubTypeBGP4MP uint16
-
-const (
- STATE_CHANGE MRTSubTypeBGP4MP = 0
- MESSAGE MRTSubTypeBGP4MP = 1
- MESSAGE_AS4 MRTSubTypeBGP4MP = 4
- STATE_CHANGE_AS4 MRTSubTypeBGP4MP = 5
- MESSAGE_LOCAL MRTSubTypeBGP4MP = 6
- MESSAGE_AS4_LOCAL MRTSubTypeBGP4MP = 7
- MESSAGE_ADDPATH MRTSubTypeBGP4MP = 8 // RFC8050
- MESSAGE_AS4_ADDPATH MRTSubTypeBGP4MP = 9 // RFC8050
- MESSAGE_LOCAL_ADDPATH MRTSubTypeBGP4MP = 10 // RFC8050
- MESSAGE_AS4_LOCAL_ADDPATH MRTSubTypeBGP4MP = 11 // RFC8050
-)
-
-func (t MRTSubTypeBGP4MP) ToUint16() uint16 {
- return uint16(t)
-}
-
-type BGPState uint16
-
-const (
- IDLE BGPState = 1
- CONNECT BGPState = 2
- ACTIVE BGPState = 3
- OPENSENT BGPState = 4
- OPENCONFIRM BGPState = 5
- ESTABLISHED BGPState = 6
-)
-
-func packValues(values []interface{}) ([]byte, error) {
- b := new(bytes.Buffer)
- for _, v := range values {
- err := binary.Write(b, binary.BigEndian, v)
- if err != nil {
- return nil, err
- }
- }
- return b.Bytes(), nil
-}
-
-type MRTHeader struct {
- Timestamp uint32
- Type MRTType
- SubType uint16
- Len uint32
-}
-
-func (h *MRTHeader) DecodeFromBytes(data []byte) error {
- if len(data) < MRT_COMMON_HEADER_LEN {
- return fmt.Errorf("not all MRTHeader bytes are available. expected: %d, actual: %d", MRT_COMMON_HEADER_LEN, len(data))
- }
- h.Timestamp = binary.BigEndian.Uint32(data[:4])
- h.Type = MRTType(binary.BigEndian.Uint16(data[4:6]))
- h.SubType = binary.BigEndian.Uint16(data[6:8])
- h.Len = binary.BigEndian.Uint32(data[8:12])
- return nil
-}
-
-func (h *MRTHeader) Serialize() ([]byte, error) {
- return packValues([]interface{}{h.Timestamp, h.Type, h.SubType, h.Len})
-}
-
-func NewMRTHeader(timestamp uint32, t MRTType, subtype MRTSubTyper, l uint32) (*MRTHeader, error) {
- return &MRTHeader{
- Timestamp: timestamp,
- Type: t,
- SubType: subtype.ToUint16(),
- Len: l,
- }, nil
-}
-
-func (h *MRTHeader) GetTime() time.Time {
- t := int64(h.Timestamp)
- return time.Unix(t, 0)
-}
-
-type MRTMessage struct {
- Header MRTHeader
- Body Body
-}
-
-func (m *MRTMessage) Serialize() ([]byte, error) {
- buf, err := m.Body.Serialize()
- if err != nil {
- return nil, err
- }
- m.Header.Len = uint32(len(buf))
- bbuf, err := m.Header.Serialize()
- if err != nil {
- return nil, err
- }
- return append(bbuf, buf...), nil
-}
-
-func NewMRTMessage(timestamp uint32, t MRTType, subtype MRTSubTyper, body Body) (*MRTMessage, error) {
- header, err := NewMRTHeader(timestamp, t, subtype, 0)
- if err != nil {
- return nil, err
- }
- return &MRTMessage{
- Header: *header,
- Body: body,
- }, nil
-}
-
-type Body interface {
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
-}
-
-type Peer struct {
- Type uint8
- BgpId net.IP
- IpAddress net.IP
- AS uint32
-}
-
-func (p *Peer) DecodeFromBytes(data []byte) ([]byte, error) {
- notAllBytesAvail := fmt.Errorf("not all Peer bytes are available")
- if len(data) < 5 {
- return nil, notAllBytesAvail
- }
- p.Type = uint8(data[0])
- p.BgpId = net.IP(data[1:5])
- data = data[5:]
-
- if p.Type&1 > 0 {
- if len(data) < 16 {
- return nil, notAllBytesAvail
- }
- p.IpAddress = net.IP(data[:16])
- data = data[16:]
- } else {
- if len(data) < 4 {
- return nil, notAllBytesAvail
- }
- p.IpAddress = net.IP(data[:4])
- data = data[4:]
- }
-
- if p.Type&(1<<1) > 0 {
- if len(data) < 4 {
- return nil, notAllBytesAvail
- }
- p.AS = binary.BigEndian.Uint32(data[:4])
- data = data[4:]
- } else {
- if len(data) < 2 {
- return nil, notAllBytesAvail
- }
- p.AS = uint32(binary.BigEndian.Uint16(data[:2]))
- data = data[2:]
- }
-
- return data, nil
-}
-
-func (p *Peer) Serialize() ([]byte, error) {
- var err error
- var bbuf []byte
- buf := make([]byte, 5)
- buf[0] = uint8(p.Type)
- copy(buf[1:], p.BgpId.To4())
- if p.Type&1 > 0 {
- buf = append(buf, p.IpAddress.To16()...)
- } else {
- buf = append(buf, p.IpAddress.To4()...)
- }
- if p.Type&(1<<1) > 0 {
- bbuf, err = packValues([]interface{}{p.AS})
- } else {
- if p.AS > uint32(math.MaxUint16) {
- return nil, fmt.Errorf("AS number is beyond 2 octet. %d > %d", p.AS, math.MaxUint16)
- }
- bbuf, err = packValues([]interface{}{uint16(p.AS)})
- }
- if err != nil {
- return nil, err
- }
- return append(buf, bbuf...), nil
-}
-
-func NewPeer(bgpid string, ipaddr string, asn uint32, isAS4 bool) *Peer {
- t := 0
- addr := net.ParseIP(ipaddr).To4()
- if addr == nil {
- t |= 1
- addr = net.ParseIP(ipaddr).To16()
- }
- if isAS4 {
- t |= (1 << 1)
- }
- return &Peer{
- Type: uint8(t),
- BgpId: net.ParseIP(bgpid).To4(),
- IpAddress: addr,
- AS: asn,
- }
-}
-
-func (p *Peer) String() string {
- return fmt.Sprintf("PEER ENTRY: ID [%s] Addr [%s] AS [%d]", p.BgpId, p.IpAddress, p.AS)
-}
-
-type PeerIndexTable struct {
- CollectorBgpId net.IP
- ViewName string
- Peers []*Peer
-}
-
-func (t *PeerIndexTable) DecodeFromBytes(data []byte) error {
- notAllBytesAvail := fmt.Errorf("not all PeerIndexTable bytes are available")
- if len(data) < 6 {
- return notAllBytesAvail
- }
- t.CollectorBgpId = net.IP(data[:4])
- viewLen := binary.BigEndian.Uint16(data[4:6])
- if len(data) < 6+int(viewLen) {
- return notAllBytesAvail
- }
- t.ViewName = string(data[6 : 6+viewLen])
-
- data = data[6+viewLen:]
-
- if len(data) < 2 {
- return notAllBytesAvail
- }
- peerNum := binary.BigEndian.Uint16(data[:2])
- data = data[2:]
- t.Peers = make([]*Peer, 0, peerNum)
- var err error
- for i := 0; i < int(peerNum); i++ {
- p := &Peer{}
- data, err = p.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- t.Peers = append(t.Peers, p)
- }
-
- return nil
-}
-
-func (t *PeerIndexTable) Serialize() ([]byte, error) {
- buf := make([]byte, 8+len(t.ViewName))
- copy(buf, t.CollectorBgpId.To4())
- binary.BigEndian.PutUint16(buf[4:], uint16(len(t.ViewName)))
- copy(buf[6:], t.ViewName)
- binary.BigEndian.PutUint16(buf[6+len(t.ViewName):], uint16(len(t.Peers)))
- for _, peer := range t.Peers {
- bbuf, err := peer.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return buf, nil
-}
-
-func NewPeerIndexTable(bgpid string, viewname string, peers []*Peer) *PeerIndexTable {
- return &PeerIndexTable{
- CollectorBgpId: net.ParseIP(bgpid).To4(),
- ViewName: viewname,
- Peers: peers,
- }
-}
-
-func (t *PeerIndexTable) String() string {
- return fmt.Sprintf("PEER_INDEX_TABLE: CollectorBgpId [%s] ViewName [%s] Peers [%s]", t.CollectorBgpId, t.ViewName, t.Peers)
-}
-
-type RibEntry struct {
- PeerIndex uint16
- OriginatedTime uint32
- PathIdentifier uint32
- PathAttributes []bgp.PathAttributeInterface
- isAddPath bool
-}
-
-func (e *RibEntry) DecodeFromBytes(data []byte) ([]byte, error) {
- notAllBytesAvail := fmt.Errorf("not all RibEntry bytes are available")
- if len(data) < 8 {
- return nil, notAllBytesAvail
- }
- e.PeerIndex = binary.BigEndian.Uint16(data[:2])
- e.OriginatedTime = binary.BigEndian.Uint32(data[2:6])
- if e.isAddPath {
- e.PathIdentifier = binary.BigEndian.Uint32(data[6:10])
- data = data[10:]
- } else {
- data = data[6:]
- }
- totalLen := binary.BigEndian.Uint16(data[:2])
- data = data[2:]
- for attrLen := totalLen; attrLen > 0; {
- p, err := bgp.GetPathAttribute(data)
- if err != nil {
- return nil, err
- }
- err = p.DecodeFromBytes(data)
- if err != nil {
- return nil, err
- }
- attrLen -= uint16(p.Len())
- if len(data) < p.Len() {
- return nil, notAllBytesAvail
- }
- data = data[p.Len():]
- e.PathAttributes = append(e.PathAttributes, p)
- }
- return data, nil
-}
-
-func (e *RibEntry) Serialize() ([]byte, error) {
- pbuf := make([]byte, 0)
- totalLen := 0
- for _, pattr := range e.PathAttributes {
- // TODO special modification is needed for MP_REACH_NLRI
- // but also Quagga doesn't implement this.
- //
- // RFC 6396 4.3.4
- // There is one exception to the encoding of BGP attributes for the BGP
- // MP_REACH_NLRI attribute (BGP Type Code 14).
- // Since the AFI, SAFI, and NLRI information is already encoded
- // in the RIB Entry Header or RIB_GENERIC Entry Header,
- // only the Next Hop Address Length and Next Hop Address fields are included.
-
- pb, err := pattr.Serialize()
- if err != nil {
- return nil, err
- }
- pbuf = append(pbuf, pb...)
- totalLen += len(pb)
- }
- var buf []byte
- if e.isAddPath {
- buf = make([]byte, 12)
- binary.BigEndian.PutUint16(buf, e.PeerIndex)
- binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime)
- binary.BigEndian.PutUint32(buf[6:], e.PathIdentifier)
- binary.BigEndian.PutUint16(buf[10:], uint16(totalLen))
- } else {
- buf = make([]byte, 8)
- binary.BigEndian.PutUint16(buf, e.PeerIndex)
- binary.BigEndian.PutUint32(buf[2:], e.OriginatedTime)
- binary.BigEndian.PutUint16(buf[6:], uint16(totalLen))
- }
- buf = append(buf, pbuf...)
- return buf, nil
-}
-
-func NewRibEntry(index uint16, time uint32, pathId uint32, pathAttrs []bgp.PathAttributeInterface, isAddPath bool) *RibEntry {
- return &RibEntry{
- PeerIndex: index,
- OriginatedTime: time,
- PathIdentifier: pathId,
- PathAttributes: pathAttrs,
- isAddPath: isAddPath,
- }
-}
-
-func (e *RibEntry) String() string {
- if e.isAddPath {
- return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathIdentifier[%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathIdentifier, e.PathAttributes)
- } else {
- return fmt.Sprintf("RIB_ENTRY: PeerIndex [%d] OriginatedTime [%d] PathAttributes [%v]", e.PeerIndex, e.OriginatedTime, e.PathAttributes)
- }
-
-}
-
-type Rib struct {
- SequenceNumber uint32
- Prefix bgp.AddrPrefixInterface
- Entries []*RibEntry
- RouteFamily bgp.RouteFamily
- isAddPath bool
-}
-
-func (u *Rib) DecodeFromBytes(data []byte) error {
- if len(data) < 4 {
- return fmt.Errorf("Not all RibIpv4Unicast message bytes available")
- }
- u.SequenceNumber = binary.BigEndian.Uint32(data[:4])
- data = data[4:]
- afi, safi := bgp.RouteFamilyToAfiSafi(u.RouteFamily)
- if afi == 0 && safi == 0 {
- afi = binary.BigEndian.Uint16(data[:2])
- safi = data[2]
- data = data[3:]
- }
- prefix, err := bgp.NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return err
- }
- err = prefix.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- u.Prefix = prefix
- data = data[prefix.Len():]
- entryNum := binary.BigEndian.Uint16(data[:2])
- data = data[2:]
- u.Entries = make([]*RibEntry, 0, entryNum)
- for i := 0; i < int(entryNum); i++ {
- e := &RibEntry{
- isAddPath: u.isAddPath,
- }
- data, err = e.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- u.Entries = append(u.Entries, e)
- }
- return nil
-}
-
-func (u *Rib) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, u.SequenceNumber)
- rf := bgp.AfiSafiToRouteFamily(u.Prefix.AFI(), u.Prefix.SAFI())
- switch rf {
- case bgp.RF_IPv4_UC, bgp.RF_IPv4_MC, bgp.RF_IPv6_UC, bgp.RF_IPv6_MC:
- default:
- bbuf := make([]byte, 2)
- binary.BigEndian.PutUint16(bbuf, u.Prefix.AFI())
- buf = append(buf, bbuf...)
- buf = append(buf, u.Prefix.SAFI())
- }
- bbuf, err := u.Prefix.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- bbuf, err = packValues([]interface{}{uint16(len(u.Entries))})
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- for _, entry := range u.Entries {
- bbuf, err = entry.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return buf, nil
-}
-
-func NewRib(seq uint32, prefix bgp.AddrPrefixInterface, entries []*RibEntry) *Rib {
- rf := bgp.AfiSafiToRouteFamily(prefix.AFI(), prefix.SAFI())
- return &Rib{
- SequenceNumber: seq,
- Prefix: prefix,
- Entries: entries,
- RouteFamily: rf,
- isAddPath: entries[0].isAddPath,
- }
-}
-
-func (u *Rib) String() string {
- return fmt.Sprintf("RIB: Seq [%d] Prefix [%s] Entries [%s]", u.SequenceNumber, u.Prefix, u.Entries)
-}
-
-type GeoPeer struct {
- Type uint8
- BgpId net.IP
- Latitude float32
- Longitude float32
-}
-
-func (p *GeoPeer) DecodeFromBytes(data []byte) ([]byte, error) {
- if len(data) < 13 {
- return nil, fmt.Errorf("not all GeoPeer bytes are available")
- }
- // Peer IP Address and Peer AS should not be included
- p.Type = uint8(data[0])
- if p.Type != uint8(0) {
- return nil, fmt.Errorf("unsupported peer type for GeoPeer: %d", p.Type)
- }
- p.BgpId = net.IP(data[1:5])
- p.Latitude = math.Float32frombits(binary.BigEndian.Uint32(data[5:9]))
- p.Longitude = math.Float32frombits(binary.BigEndian.Uint32(data[9:13]))
- return data[13:], nil
-}
-
-func (p *GeoPeer) Serialize() ([]byte, error) {
- buf := make([]byte, 13)
- buf[0] = uint8(0) // Peer IP Address and Peer AS should not be included
- bgpId := p.BgpId.To4()
- if bgpId == nil {
- return nil, fmt.Errorf("invalid BgpId: %s", p.BgpId)
- }
- copy(buf[1:5], bgpId)
- binary.BigEndian.PutUint32(buf[5:9], math.Float32bits(p.Latitude))
- binary.BigEndian.PutUint32(buf[9:13], math.Float32bits(p.Longitude))
- return buf, nil
-}
-
-func NewGeoPeer(bgpid string, latitude float32, longitude float32) *GeoPeer {
- return &GeoPeer{
- Type: 0, // Peer IP Address and Peer AS should not be included
- BgpId: net.ParseIP(bgpid).To4(),
- Latitude: latitude,
- Longitude: longitude,
- }
-}
-
-func (p *GeoPeer) String() string {
- return fmt.Sprintf("PEER ENTRY: ID [%s] Latitude [%f] Longitude [%f]", p.BgpId, p.Latitude, p.Longitude)
-}
-
-type GeoPeerTable struct {
- CollectorBgpId net.IP
- CollectorLatitude float32
- CollectorLongitude float32
- Peers []*GeoPeer
-}
-
-func (t *GeoPeerTable) DecodeFromBytes(data []byte) error {
- if len(data) < 14 {
- return fmt.Errorf("not all GeoPeerTable bytes are available")
- }
- t.CollectorBgpId = net.IP(data[0:4])
- t.CollectorLatitude = math.Float32frombits(binary.BigEndian.Uint32(data[4:8]))
- t.CollectorLongitude = math.Float32frombits(binary.BigEndian.Uint32(data[8:12]))
- peerCount := binary.BigEndian.Uint16(data[12:14])
- data = data[14:]
- t.Peers = make([]*GeoPeer, 0, peerCount)
- var err error
- for i := 0; i < int(peerCount); i++ {
- p := &GeoPeer{}
- if data, err = p.DecodeFromBytes(data); err != nil {
- return err
- }
- t.Peers = append(t.Peers, p)
- }
- return nil
-}
-
-func (t *GeoPeerTable) Serialize() ([]byte, error) {
- buf := make([]byte, 14)
- collectorBgpId := t.CollectorBgpId.To4()
- if collectorBgpId == nil {
- return nil, fmt.Errorf("invalid CollectorBgpId: %s", t.CollectorBgpId)
- }
- copy(buf[0:4], collectorBgpId)
- binary.BigEndian.PutUint32(buf[4:8], math.Float32bits(t.CollectorLatitude))
- binary.BigEndian.PutUint32(buf[8:12], math.Float32bits(t.CollectorLongitude))
- binary.BigEndian.PutUint16(buf[12:14], uint16(len(t.Peers)))
- for _, peer := range t.Peers {
- pbuf, err := peer.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- }
- return buf, nil
-}
-
-func NewGeoPeerTable(bgpid string, latitude float32, longitude float32, peers []*GeoPeer) *GeoPeerTable {
- return &GeoPeerTable{
- CollectorBgpId: net.ParseIP(bgpid).To4(),
- CollectorLatitude: latitude,
- CollectorLongitude: longitude,
- Peers: peers,
- }
-}
-
-func (t *GeoPeerTable) String() string {
- return fmt.Sprintf("GEO_PEER_TABLE: CollectorBgpId [%s] CollectorLatitude [%f] CollectorLongitude [%f] Peers [%s]", t.CollectorBgpId, t.CollectorLatitude, t.CollectorLongitude, t.Peers)
-}
-
-type BGP4MPHeader struct {
- PeerAS uint32
- LocalAS uint32
- InterfaceIndex uint16
- AddressFamily uint16
- PeerIpAddress net.IP
- LocalIpAddress net.IP
- isAS4 bool
-}
-
-func (m *BGP4MPHeader) decodeFromBytes(data []byte) ([]byte, error) {
- if m.isAS4 && len(data) < 8 {
- return nil, fmt.Errorf("Not all BGP4MPMessageAS4 bytes available")
- } else if !m.isAS4 && len(data) < 4 {
- return nil, fmt.Errorf("Not all BGP4MPMessageAS bytes available")
- }
-
- if m.isAS4 {
- m.PeerAS = binary.BigEndian.Uint32(data[:4])
- m.LocalAS = binary.BigEndian.Uint32(data[4:8])
- data = data[8:]
- } else {
- m.PeerAS = uint32(binary.BigEndian.Uint16(data[:2]))
- m.LocalAS = uint32(binary.BigEndian.Uint16(data[2:4]))
- data = data[4:]
- }
- m.InterfaceIndex = binary.BigEndian.Uint16(data[:2])
- m.AddressFamily = binary.BigEndian.Uint16(data[2:4])
- switch m.AddressFamily {
- case bgp.AFI_IP:
- m.PeerIpAddress = net.IP(data[4:8]).To4()
- m.LocalIpAddress = net.IP(data[8:12]).To4()
- data = data[12:]
- case bgp.AFI_IP6:
- m.PeerIpAddress = net.IP(data[4:20])
- m.LocalIpAddress = net.IP(data[20:36])
- data = data[36:]
- default:
- return nil, fmt.Errorf("unsupported address family: %d", m.AddressFamily)
- }
- return data, nil
-}
-
-func (m *BGP4MPHeader) serialize() ([]byte, error) {
- var values []interface{}
- if m.isAS4 {
- values = []interface{}{m.PeerAS, m.LocalAS, m.InterfaceIndex, m.AddressFamily}
- } else {
- values = []interface{}{uint16(m.PeerAS), uint16(m.LocalAS), m.InterfaceIndex, m.AddressFamily}
- }
- buf, err := packValues(values)
- if err != nil {
- return nil, err
- }
- var bbuf []byte
- switch m.AddressFamily {
- case bgp.AFI_IP:
- bbuf = make([]byte, 8)
- copy(bbuf, m.PeerIpAddress.To4())
- copy(bbuf[4:], m.LocalIpAddress.To4())
- case bgp.AFI_IP6:
- bbuf = make([]byte, 32)
- copy(bbuf, m.PeerIpAddress)
- copy(bbuf[16:], m.LocalIpAddress)
- default:
- return nil, fmt.Errorf("unsupported address family: %d", m.AddressFamily)
- }
- return append(buf, bbuf...), nil
-}
-
-func newBGP4MPHeader(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool) (*BGP4MPHeader, error) {
- var af uint16
- paddr := net.ParseIP(peerip).To4()
- laddr := net.ParseIP(localip).To4()
- if paddr != nil && laddr != nil {
- af = bgp.AFI_IP
- } else {
- paddr = net.ParseIP(peerip).To16()
- laddr = net.ParseIP(localip).To16()
- if paddr != nil && laddr != nil {
- af = bgp.AFI_IP6
- } else {
- return nil, fmt.Errorf("Peer IP Address and Local IP Address must have the same address family")
- }
- }
- return &BGP4MPHeader{
- PeerAS: peeras,
- LocalAS: localas,
- InterfaceIndex: intfindex,
- AddressFamily: af,
- PeerIpAddress: paddr,
- LocalIpAddress: laddr,
- isAS4: isAS4,
- }, nil
-}
-
-type BGP4MPStateChange struct {
- *BGP4MPHeader
- OldState BGPState
- NewState BGPState
-}
-
-func (m *BGP4MPStateChange) DecodeFromBytes(data []byte) error {
- rest, err := m.decodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(rest) < 4 {
- return fmt.Errorf("Not all BGP4MPStateChange bytes available")
- }
- m.OldState = BGPState(binary.BigEndian.Uint16(rest[:2]))
- m.NewState = BGPState(binary.BigEndian.Uint16(rest[2:4]))
- return nil
-}
-
-func (m *BGP4MPStateChange) Serialize() ([]byte, error) {
- buf, err := m.serialize()
- if err != nil {
- return nil, err
- }
- bbuf, err := packValues([]interface{}{m.OldState, m.NewState})
- if err != nil {
- return nil, err
- }
- return append(buf, bbuf...), nil
-}
-
-func NewBGP4MPStateChange(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, oldstate, newstate BGPState) *BGP4MPStateChange {
- header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
- return &BGP4MPStateChange{
- BGP4MPHeader: header,
- OldState: oldstate,
- NewState: newstate,
- }
-}
-
-type BGP4MPMessage struct {
- *BGP4MPHeader
- BGPMessage *bgp.BGPMessage
- BGPMessagePayload []byte
- isLocal bool
- isAddPath bool
-}
-
-func (m *BGP4MPMessage) DecodeFromBytes(data []byte) error {
- rest, err := m.decodeFromBytes(data)
- if err != nil {
- return err
- }
-
- if len(rest) < bgp.BGP_HEADER_LENGTH {
- return fmt.Errorf("Not all BGP4MPMessageAS4 bytes available")
- }
-
- msg, err := bgp.ParseBGPMessage(rest)
- if err != nil {
- return err
- }
- m.BGPMessage = msg
- return nil
-}
-
-func (m *BGP4MPMessage) Serialize() ([]byte, error) {
- buf, err := m.serialize()
- if err != nil {
- return nil, err
- }
- if m.BGPMessagePayload != nil {
- return append(buf, m.BGPMessagePayload...), nil
- }
- bbuf, err := m.BGPMessage.Serialize()
- if err != nil {
- return nil, err
- }
- return append(buf, bbuf...), nil
-}
-
-func NewBGP4MPMessage(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage {
- header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
- return &BGP4MPMessage{
- BGP4MPHeader: header,
- BGPMessage: msg,
- }
-}
-
-func NewBGP4MPMessageLocal(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage {
- header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
- return &BGP4MPMessage{
- BGP4MPHeader: header,
- BGPMessage: msg,
- isLocal: true,
- }
-}
-
-func NewBGP4MPMessageAddPath(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage {
- header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
- return &BGP4MPMessage{
- BGP4MPHeader: header,
- BGPMessage: msg,
- isAddPath: true,
- }
-}
-
-func NewBGP4MPMessageLocalAddPath(peeras, localas uint32, intfindex uint16, peerip, localip string, isAS4 bool, msg *bgp.BGPMessage) *BGP4MPMessage {
- header, _ := newBGP4MPHeader(peeras, localas, intfindex, peerip, localip, isAS4)
- return &BGP4MPMessage{
- BGP4MPHeader: header,
- BGPMessage: msg,
- isLocal: true,
- isAddPath: true,
- }
-}
-
-func (m *BGP4MPMessage) String() string {
- title := "BGP4MP_MSG"
- if m.isAS4 {
- title += "_AS4"
- }
- if m.isLocal {
- title += "_LOCAL"
- }
- if m.isAddPath {
- title += "_ADDPATH"
- }
- return fmt.Sprintf("%s: PeerAS [%d] LocalAS [%d] InterfaceIndex [%d] PeerIP [%s] LocalIP [%s] BGPMessage [%v]", title, m.PeerAS, m.LocalAS, m.InterfaceIndex, m.PeerIpAddress, m.LocalIpAddress, m.BGPMessage)
-}
-
-//This function can be passed into a bufio.Scanner.Split() to read buffered mrt msgs
-func SplitMrt(data []byte, atEOF bool) (advance int, token []byte, err error) {
- if atEOF && len(data) == 0 {
- return 0, nil, nil
- }
- if cap(data) < MRT_COMMON_HEADER_LEN { // read more
- return 0, nil, nil
- }
- //this reads the data
- hdr := &MRTHeader{}
- errh := hdr.DecodeFromBytes(data[:MRT_COMMON_HEADER_LEN])
- if errh != nil {
- return 0, nil, errh
- }
- totlen := int(hdr.Len + MRT_COMMON_HEADER_LEN)
- if len(data) < totlen { //need to read more
- return 0, nil, nil
- }
- return totlen, data[0:totlen], nil
-}
-
-func ParseMRTBody(h *MRTHeader, data []byte) (*MRTMessage, error) {
- if len(data) < int(h.Len) {
- return nil, fmt.Errorf("Not all MRT message bytes available. expected: %d, actual: %d", int(h.Len), len(data))
- }
- msg := &MRTMessage{Header: *h}
- switch h.Type {
- case TABLE_DUMPv2:
- subType := MRTSubTypeTableDumpv2(h.SubType)
- rf := bgp.RouteFamily(0)
- isAddPath := false
- switch subType {
- case PEER_INDEX_TABLE:
- msg.Body = &PeerIndexTable{}
- case RIB_IPV4_UNICAST:
- rf = bgp.RF_IPv4_UC
- case RIB_IPV4_MULTICAST:
- rf = bgp.RF_IPv4_MC
- case RIB_IPV6_UNICAST:
- rf = bgp.RF_IPv6_UC
- case RIB_IPV6_MULTICAST:
- rf = bgp.RF_IPv6_MC
- case RIB_GENERIC:
- case GEO_PEER_TABLE:
- msg.Body = &GeoPeerTable{}
- case RIB_IPV4_UNICAST_ADDPATH:
- rf = bgp.RF_IPv4_UC
- isAddPath = true
- case RIB_IPV4_MULTICAST_ADDPATH:
- rf = bgp.RF_IPv4_MC
- isAddPath = true
- case RIB_IPV6_UNICAST_ADDPATH:
- rf = bgp.RF_IPv6_UC
- isAddPath = true
- case RIB_IPV6_MULTICAST_ADDPATH:
- rf = bgp.RF_IPv6_MC
- isAddPath = true
- case RIB_GENERIC_ADDPATH:
- isAddPath = true
- default:
- return nil, fmt.Errorf("unsupported table dumpv2 subtype: %v\n", subType)
- }
-
- if msg.Body == nil {
- msg.Body = &Rib{
- RouteFamily: rf,
- isAddPath: isAddPath,
- }
- }
- case BGP4MP:
- subType := MRTSubTypeBGP4MP(h.SubType)
- isAS4 := true
- switch subType {
- case STATE_CHANGE:
- isAS4 = false
- fallthrough
- case STATE_CHANGE_AS4:
- msg.Body = &BGP4MPStateChange{
- BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
- }
- case MESSAGE:
- isAS4 = false
- fallthrough
- case MESSAGE_AS4:
- msg.Body = &BGP4MPMessage{
- BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
- }
- case MESSAGE_LOCAL:
- isAS4 = false
- fallthrough
- case MESSAGE_AS4_LOCAL:
- msg.Body = &BGP4MPMessage{
- BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
- isLocal: true,
- }
- case MESSAGE_ADDPATH:
- isAS4 = false
- fallthrough
- case MESSAGE_AS4_ADDPATH:
- msg.Body = &BGP4MPMessage{
- BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
- isAddPath: true,
- }
- case MESSAGE_LOCAL_ADDPATH:
- isAS4 = false
- fallthrough
- case MESSAGE_AS4_LOCAL_ADDPATH:
- msg.Body = &BGP4MPMessage{
- BGP4MPHeader: &BGP4MPHeader{isAS4: isAS4},
- isLocal: true,
- isAddPath: true,
- }
- default:
- return nil, fmt.Errorf("unsupported bgp4mp subtype: %v\n", subType)
- }
- default:
- return nil, fmt.Errorf("unsupported type: %v\n", h.Type)
- }
- err := msg.Body.DecodeFromBytes(data)
- if err != nil {
- return nil, err
- }
- return msg, nil
-}
diff --git a/packet/mrt/mrt_test.go b/packet/mrt/mrt_test.go
deleted file mode 100644
index 30edd496..00000000
--- a/packet/mrt/mrt_test.go
+++ /dev/null
@@ -1,301 +0,0 @@
-// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package mrt
-
-import (
- "bufio"
- "bytes"
- "github.com/osrg/gobgp/packet/bgp"
- "github.com/stretchr/testify/assert"
- "reflect"
- "testing"
- "time"
-)
-
-func TestMrtHdr(t *testing.T) {
- h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
- if err != nil {
- t.Fatal(err)
- }
- b1, err := h1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- h2 := &MRTHeader{}
- err = h2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(h1, h2), true)
-}
-
-func TestMrtHdrTime(t *testing.T) {
- h1, err := NewMRTHeader(10, TABLE_DUMPv2, RIB_IPV4_MULTICAST, 20)
- if err != nil {
- t.Fatal(err)
- }
- ttime := time.Unix(10, 0)
- htime := h1.GetTime()
- t.Logf("this timestamp should be 10s after epoch:%v", htime)
- assert.Equal(t, h1.GetTime(), ttime)
-}
-
-func testPeer(t *testing.T, p1 *Peer) {
- b1, err := p1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- p2 := &Peer{}
- rest, err := p2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, len(rest), 0)
- assert.Equal(t, reflect.DeepEqual(p1, p2), true)
-}
-
-func TestMrtPeer(t *testing.T) {
- p := NewPeer("192.168.0.1", "10.0.0.1", 65000, false)
- testPeer(t, p)
-}
-
-func TestMrtPeerv6(t *testing.T) {
- p := NewPeer("192.168.0.1", "2001::1", 65000, false)
- testPeer(t, p)
-}
-
-func TestMrtPeerAS4(t *testing.T) {
- p := NewPeer("192.168.0.1", "2001::1", 135500, true)
- testPeer(t, p)
-}
-
-func TestMrtPeerIndexTable(t *testing.T) {
- p1 := NewPeer("192.168.0.1", "10.0.0.1", 65000, false)
- p2 := NewPeer("192.168.0.1", "2001::1", 65000, false)
- p3 := NewPeer("192.168.0.1", "2001::1", 135500, true)
- pt1 := NewPeerIndexTable("192.168.0.1", "test", []*Peer{p1, p2, p3})
- b1, err := pt1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- pt2 := &PeerIndexTable{}
- err = pt2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(pt1, pt2), true)
-}
-
-func TestMrtRibEntry(t *testing.T) {
- aspath1 := []bgp.AsPathParamInterface{
- bgp.NewAsPathParam(2, []uint16{1000}),
- bgp.NewAsPathParam(1, []uint16{1001, 1002}),
- bgp.NewAsPathParam(2, []uint16{1003, 1004}),
- }
-
- p := []bgp.PathAttributeInterface{
- bgp.NewPathAttributeOrigin(3),
- bgp.NewPathAttributeAsPath(aspath1),
- bgp.NewPathAttributeNextHop("129.1.1.2"),
- bgp.NewPathAttributeMultiExitDisc(1 << 20),
- bgp.NewPathAttributeLocalPref(1 << 22),
- }
-
- e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false)
- b1, err := e1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
-
- e2 := &RibEntry{}
- rest, err := e2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, len(rest), 0)
- assert.Equal(t, reflect.DeepEqual(e1, e2), true)
-}
-
-func TestMrtRibEntryWithAddPath(t *testing.T) {
- aspath1 := []bgp.AsPathParamInterface{
- bgp.NewAsPathParam(2, []uint16{1000}),
- bgp.NewAsPathParam(1, []uint16{1001, 1002}),
- bgp.NewAsPathParam(2, []uint16{1003, 1004}),
- }
-
- p := []bgp.PathAttributeInterface{
- bgp.NewPathAttributeOrigin(3),
- bgp.NewPathAttributeAsPath(aspath1),
- bgp.NewPathAttributeNextHop("129.1.1.2"),
- bgp.NewPathAttributeMultiExitDisc(1 << 20),
- bgp.NewPathAttributeLocalPref(1 << 22),
- }
- e1 := NewRibEntry(1, uint32(time.Now().Unix()), 200, p, true)
- b1, err := e1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
-
- e2 := &RibEntry{isAddPath: true}
- rest, err := e2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, len(rest), 0)
- assert.Equal(t, reflect.DeepEqual(e1, e2), true)
-}
-
-func TestMrtRib(t *testing.T) {
- aspath1 := []bgp.AsPathParamInterface{
- bgp.NewAsPathParam(2, []uint16{1000}),
- bgp.NewAsPathParam(1, []uint16{1001, 1002}),
- bgp.NewAsPathParam(2, []uint16{1003, 1004}),
- }
-
- p := []bgp.PathAttributeInterface{
- bgp.NewPathAttributeOrigin(3),
- bgp.NewPathAttributeAsPath(aspath1),
- bgp.NewPathAttributeNextHop("129.1.1.2"),
- bgp.NewPathAttributeMultiExitDisc(1 << 20),
- bgp.NewPathAttributeLocalPref(1 << 22),
- }
-
- e1 := NewRibEntry(1, uint32(time.Now().Unix()), 0, p, false)
- e2 := NewRibEntry(2, uint32(time.Now().Unix()), 0, p, false)
- e3 := NewRibEntry(3, uint32(time.Now().Unix()), 0, p, false)
-
- r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3})
- b1, err := r1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- r2 := &Rib{
- RouteFamily: bgp.RF_IPv4_UC,
- }
- err = r2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(r1, r2), true)
-}
-
-func TestMrtRibWithAddPath(t *testing.T) {
- aspath1 := []bgp.AsPathParamInterface{
- bgp.NewAsPathParam(2, []uint16{1000}),
- bgp.NewAsPathParam(1, []uint16{1001, 1002}),
- bgp.NewAsPathParam(2, []uint16{1003, 1004}),
- }
-
- p := []bgp.PathAttributeInterface{
- bgp.NewPathAttributeOrigin(3),
- bgp.NewPathAttributeAsPath(aspath1),
- bgp.NewPathAttributeNextHop("129.1.1.2"),
- bgp.NewPathAttributeMultiExitDisc(1 << 20),
- bgp.NewPathAttributeLocalPref(1 << 22),
- }
-
- e1 := NewRibEntry(1, uint32(time.Now().Unix()), 100, p, true)
- e2 := NewRibEntry(2, uint32(time.Now().Unix()), 200, p, true)
- e3 := NewRibEntry(3, uint32(time.Now().Unix()), 300, p, true)
-
- r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3})
- b1, err := r1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- r2 := &Rib{
- RouteFamily: bgp.RF_IPv4_UC,
- isAddPath: true,
- }
- err = r2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(r1, r2), true)
-}
-
-func TestMrtGeoPeerTable(t *testing.T) {
- p1 := NewGeoPeer("192.168.0.1", 28.031157, 86.899684)
- p2 := NewGeoPeer("192.168.0.1", 35.360556, 138.727778)
- pt1 := NewGeoPeerTable("192.168.0.1", 12.345678, 98.765432, []*GeoPeer{p1, p2})
- b1, err := pt1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- pt2 := &GeoPeerTable{}
- err = pt2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(pt1, pt2), true)
-}
-
-func TestMrtBgp4mpStateChange(t *testing.T) {
- c1 := NewBGP4MPStateChange(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, ACTIVE, ESTABLISHED)
- b1, err := c1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- c2 := &BGP4MPStateChange{BGP4MPHeader: &BGP4MPHeader{}}
- err = c2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- _, err = c2.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(c1, c2), true)
-}
-
-func TestMrtBgp4mpMessage(t *testing.T) {
- msg := bgp.NewBGPKeepAliveMessage()
- m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg)
- b1, err := m1.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- m2 := &BGP4MPMessage{BGP4MPHeader: &BGP4MPHeader{}}
- err = m2.DecodeFromBytes(b1)
- if err != nil {
- t.Fatal(err)
- }
- assert.Equal(t, reflect.DeepEqual(m1, m2), true)
-}
-
-func TestMrtSplit(t *testing.T) {
- var b bytes.Buffer
- numwrite, numread := 10, 0
- for i := 0; i < numwrite; i++ {
- msg := bgp.NewBGPKeepAliveMessage()
- m1 := NewBGP4MPMessage(65000, 65001, 1, "192.168.0.1", "192.168.0.2", false, msg)
- mm, _ := NewMRTMessage(1234, BGP4MP, MESSAGE, m1)
- b1, err := mm.Serialize()
- if err != nil {
- t.Fatal(err)
- }
- b.Write(b1)
- }
- t.Logf("wrote %d serialized MRT keepalives in the buffer", numwrite)
- r := bytes.NewReader(b.Bytes())
- scanner := bufio.NewScanner(r)
- scanner.Split(SplitMrt)
- for scanner.Scan() {
- numread += 1
- }
- t.Logf("scanner scanned %d serialized keepalives from the buffer", numread)
- assert.Equal(t, numwrite, numread)
-}
diff --git a/packet/rtr/rtr.go b/packet/rtr/rtr.go
deleted file mode 100644
index 902f1e62..00000000
--- a/packet/rtr/rtr.go
+++ /dev/null
@@ -1,392 +0,0 @@
-// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package rtr
-
-import (
- "encoding/binary"
- "fmt"
- "net"
-)
-
-const (
- RPKI_DEFAULT_PORT = 323
-)
-
-const (
- RTR_SERIAL_NOTIFY = iota
- RTR_SERIAL_QUERY
- RTR_RESET_QUERY
- RTR_CACHE_RESPONSE
- RTR_IPV4_PREFIX
- _
- RTR_IPV6_PREFIX
- RTR_END_OF_DATA
- RTR_CACHE_RESET
- _
- RTR_ERROR_REPORT
-)
-
-const (
- RTR_SERIAL_NOTIFY_LEN = 12
- RTR_SERIAL_QUERY_LEN = 12
- RTR_RESET_QUERY_LEN = 8
- RTR_CACHE_RESPONSE_LEN = 8
- RTR_IPV4_PREFIX_LEN = 20
- RTR_IPV6_PREFIX_LEN = 32
- RTR_END_OF_DATA_LEN = 12
- RTR_CACHE_RESET_LEN = 8
- RTR_MIN_LEN = 8
- RTR_ERROR_REPORT_ERR_PDU_LEN = 4
- RTR_ERROR_REPORT_ERR_TEXT_LEN = 4
-)
-
-const (
- WITHDRAWAL uint8 = iota
- ANNOUNCEMENT
-)
-
-const (
- CORRUPT_DATA uint16 = iota
- INTERNAL_ERROR
- NO_DATA_AVAILABLE
- INVALID_REQUEST
- UNSUPPORTED_PROTOCOL_VERSION
- UNSUPPORTED_PDU_TYPE
- WITHDRAWAL_OF_UNKNOWN_RECORD
- DUPLICATE_ANNOUNCEMENT_RECORD
-)
-
-type RTRMessage interface {
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
-}
-
-type RTRCommon struct {
- Version uint8
- Type uint8
- SessionID uint16
- Len uint32
- SerialNumber uint32
-}
-
-func (m *RTRCommon) DecodeFromBytes(data []byte) error {
- m.Version = data[0]
- m.Type = data[1]
- m.SessionID = binary.BigEndian.Uint16(data[2:4])
- m.Len = binary.BigEndian.Uint32(data[4:8])
- m.SerialNumber = binary.BigEndian.Uint32(data[8:12])
- return nil
-}
-
-func (m *RTRCommon) Serialize() ([]byte, error) {
- data := make([]byte, m.Len)
- data[0] = m.Version
- data[1] = m.Type
- binary.BigEndian.PutUint16(data[2:4], m.SessionID)
- binary.BigEndian.PutUint32(data[4:8], m.Len)
- binary.BigEndian.PutUint32(data[8:12], m.SerialNumber)
- return data, nil
-}
-
-type RTRSerialNotify struct {
- RTRCommon
-}
-
-func NewRTRSerialNotify(id uint16, sn uint32) *RTRSerialNotify {
- return &RTRSerialNotify{
- RTRCommon{
- Type: RTR_SERIAL_NOTIFY,
- SessionID: id,
- Len: RTR_SERIAL_NOTIFY_LEN,
- SerialNumber: sn,
- },
- }
-}
-
-type RTRSerialQuery struct {
- RTRCommon
-}
-
-func NewRTRSerialQuery(id uint16, sn uint32) *RTRSerialQuery {
- return &RTRSerialQuery{
- RTRCommon{
- Type: RTR_SERIAL_QUERY,
- SessionID: id,
- Len: RTR_SERIAL_QUERY_LEN,
- SerialNumber: sn,
- },
- }
-}
-
-type RTRReset struct {
- Version uint8
- Type uint8
- Len uint32
-}
-
-func (m *RTRReset) DecodeFromBytes(data []byte) error {
- m.Version = data[0]
- m.Type = data[1]
- m.Len = binary.BigEndian.Uint32(data[4:8])
- return nil
-}
-
-func (m *RTRReset) Serialize() ([]byte, error) {
- data := make([]byte, m.Len)
- data[0] = m.Version
- data[1] = m.Type
- binary.BigEndian.PutUint32(data[4:8], m.Len)
- return data, nil
-}
-
-type RTRResetQuery struct {
- RTRReset
-}
-
-func NewRTRResetQuery() *RTRResetQuery {
- return &RTRResetQuery{
- RTRReset{
- Type: RTR_RESET_QUERY,
- Len: RTR_RESET_QUERY_LEN,
- },
- }
-}
-
-type RTRCacheResponse struct {
- Version uint8
- Type uint8
- SessionID uint16
- Len uint32
-}
-
-func (m *RTRCacheResponse) DecodeFromBytes(data []byte) error {
- m.Version = data[0]
- m.Type = data[1]
- m.SessionID = binary.BigEndian.Uint16(data[2:4])
- m.Len = binary.BigEndian.Uint32(data[4:8])
- return nil
-}
-
-func (m *RTRCacheResponse) Serialize() ([]byte, error) {
- data := make([]byte, m.Len)
- data[0] = m.Version
- data[1] = m.Type
- binary.BigEndian.PutUint16(data[2:4], m.SessionID)
- binary.BigEndian.PutUint32(data[4:8], m.Len)
- return data, nil
-}
-
-func NewRTRCacheResponse(id uint16) *RTRCacheResponse {
- return &RTRCacheResponse{
- Type: RTR_CACHE_RESPONSE,
- SessionID: id,
- Len: RTR_CACHE_RESPONSE_LEN,
- }
-}
-
-type RTRIPPrefix struct {
- Version uint8
- Type uint8
- Len uint32
- Flags uint8
- PrefixLen uint8
- MaxLen uint8
- Prefix net.IP
- AS uint32
-}
-
-func (m *RTRIPPrefix) DecodeFromBytes(data []byte) error {
- m.Version = data[0]
- m.Type = data[1]
- m.Len = binary.BigEndian.Uint32(data[4:8])
- m.Flags = data[8]
- m.PrefixLen = data[9]
- m.MaxLen = data[10]
- if m.Type == RTR_IPV4_PREFIX {
- m.Prefix = net.IP(data[12:16]).To4()
- m.AS = binary.BigEndian.Uint32(data[16:20])
- } else {
- m.Prefix = net.IP(data[12:28]).To16()
- m.AS = binary.BigEndian.Uint32(data[28:32])
- }
- return nil
-}
-
-func (m *RTRIPPrefix) Serialize() ([]byte, error) {
- data := make([]byte, m.Len)
- data[0] = m.Version
- data[1] = m.Type
- binary.BigEndian.PutUint32(data[4:8], m.Len)
- data[8] = m.Flags
- data[9] = m.PrefixLen
- data[10] = m.MaxLen
- if m.Type == RTR_IPV4_PREFIX {
- copy(data[12:16], m.Prefix.To4())
- binary.BigEndian.PutUint32(data[16:20], m.AS)
- } else {
- copy(data[12:28], m.Prefix.To16())
- binary.BigEndian.PutUint32(data[28:32], m.AS)
- }
- return data, nil
-}
-
-func NewRTRIPPrefix(prefix net.IP, prefixLen, maxLen uint8, as uint32, flags uint8) *RTRIPPrefix {
- var pduType uint8
- var pduLen uint32
- if prefix.To4() != nil && prefixLen <= 32 {
- pduType = RTR_IPV4_PREFIX
- pduLen = RTR_IPV4_PREFIX_LEN
- } else {
- pduType = RTR_IPV6_PREFIX
- pduLen = RTR_IPV6_PREFIX_LEN
- }
-
- return &RTRIPPrefix{
- Type: pduType,
- Len: pduLen,
- Flags: flags,
- PrefixLen: prefixLen,
- MaxLen: maxLen,
- Prefix: prefix,
- AS: as,
- }
-}
-
-type RTREndOfData struct {
- RTRCommon
-}
-
-func NewRTREndOfData(id uint16, sn uint32) *RTREndOfData {
- return &RTREndOfData{
- RTRCommon{
- Type: RTR_END_OF_DATA,
- SessionID: id,
- Len: RTR_END_OF_DATA_LEN,
- SerialNumber: sn,
- },
- }
-}
-
-type RTRCacheReset struct {
- RTRReset
-}
-
-func NewRTRCacheReset() *RTRCacheReset {
- return &RTRCacheReset{
- RTRReset{
- Type: RTR_CACHE_RESET,
- Len: RTR_CACHE_RESET_LEN,
- },
- }
-}
-
-type RTRErrorReport struct {
- Version uint8
- Type uint8
- ErrorCode uint16
- Len uint32
- PDULen uint32
- PDU []byte
- TextLen uint32
- Text []byte
-}
-
-func (m *RTRErrorReport) DecodeFromBytes(data []byte) error {
- m.Version = data[0]
- m.Type = data[1]
- m.ErrorCode = binary.BigEndian.Uint16(data[2:4])
- m.Len = binary.BigEndian.Uint32(data[4:8])
- m.PDULen = binary.BigEndian.Uint32(data[8:12])
- m.PDU = make([]byte, m.PDULen)
- copy(m.PDU, data[12:12+m.PDULen])
- m.TextLen = binary.BigEndian.Uint32(data[12+m.PDULen : 16+m.PDULen])
- m.Text = make([]byte, m.TextLen)
- copy(m.Text, data[16+m.PDULen:])
- return nil
-}
-
-func (m *RTRErrorReport) Serialize() ([]byte, error) {
- data := make([]byte, m.Len)
- data[0] = m.Version
- data[1] = m.Type
- binary.BigEndian.PutUint16(data[2:4], m.ErrorCode)
- binary.BigEndian.PutUint32(data[4:8], m.Len)
- binary.BigEndian.PutUint32(data[8:12], m.PDULen)
- copy(data[12:], m.PDU)
- binary.BigEndian.PutUint32(data[12+m.PDULen:16+m.PDULen], m.TextLen)
- copy(data[16+m.PDULen:], m.Text)
- return data, nil
-}
-
-func NewRTRErrorReport(errCode uint16, errPDU []byte, errMsg []byte) *RTRErrorReport {
- pdu := &RTRErrorReport{Type: RTR_ERROR_REPORT, ErrorCode: errCode}
- if errPDU != nil {
- if errPDU[1] == RTR_ERROR_REPORT {
- return nil
- }
- pdu.PDULen = uint32(len(errPDU))
- pdu.PDU = errPDU
- }
- if errMsg != nil {
- pdu.Text = errMsg
- pdu.TextLen = uint32(len(errMsg))
- }
- pdu.Len = uint32(RTR_MIN_LEN) + uint32(RTR_ERROR_REPORT_ERR_PDU_LEN) + pdu.PDULen + uint32(RTR_ERROR_REPORT_ERR_TEXT_LEN) + pdu.TextLen
- return pdu
-}
-
-func SplitRTR(data []byte, atEOF bool) (advance int, token []byte, err error) {
- if atEOF && len(data) == 0 || len(data) < RTR_MIN_LEN {
- return 0, nil, nil
- }
-
- totalLen := binary.BigEndian.Uint32(data[4:8])
- if totalLen < RTR_MIN_LEN {
- return 0, nil, fmt.Errorf("Invalid length: %d", totalLen)
- }
- if uint32(len(data)) < totalLen {
- return 0, nil, nil
- }
- return int(totalLen), data[0:totalLen], nil
-}
-
-func ParseRTR(data []byte) (RTRMessage, error) {
- var msg RTRMessage
- switch data[1] {
- case RTR_SERIAL_NOTIFY:
- msg = &RTRSerialNotify{}
- case RTR_SERIAL_QUERY:
- msg = &RTRSerialQuery{}
- case RTR_RESET_QUERY:
- msg = &RTRResetQuery{}
- case RTR_CACHE_RESPONSE:
- msg = &RTRCacheResponse{}
- case RTR_IPV4_PREFIX:
- msg = &RTRIPPrefix{}
- case RTR_IPV6_PREFIX:
- msg = &RTRIPPrefix{}
- case RTR_END_OF_DATA:
- msg = &RTREndOfData{}
- case RTR_CACHE_RESET:
- msg = &RTRCacheReset{}
- case RTR_ERROR_REPORT:
- msg = &RTRErrorReport{}
- default:
- return nil, fmt.Errorf("unknown RTR message type %d:", data[1])
- }
- err := msg.DecodeFromBytes(data)
- return msg, err
-}
diff --git a/packet/rtr/rtr_test.go b/packet/rtr/rtr_test.go
deleted file mode 100644
index 08f930b2..00000000
--- a/packet/rtr/rtr_test.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-// implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package rtr
-
-import (
- "encoding/hex"
- "math/rand"
- "net"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func verifyRTRMessage(t *testing.T, m1 RTRMessage) {
- buf1, _ := m1.Serialize()
- m2, err := ParseRTR(buf1)
- require.NoError(t, err)
-
- buf2, err := m2.Serialize()
- require.NoError(t, err)
-
- assert.Equal(t, buf1, buf2, "buf1: %v buf2: %v", hex.EncodeToString(buf1), hex.EncodeToString(buf2))
-}
-
-func randUint32() uint32 {
- rand.Seed(time.Now().UnixNano())
- return rand.Uint32()
-}
-
-func Test_RTRSerialNotify(t *testing.T) {
- id := uint16(time.Now().Unix())
- sn := randUint32()
- verifyRTRMessage(t, NewRTRSerialNotify(id, sn))
-}
-
-func Test_RTRSerialQuery(t *testing.T) {
- id := uint16(time.Now().Unix())
- sn := randUint32()
- verifyRTRMessage(t, NewRTRSerialQuery(id, sn))
-}
-
-func Test_RTRResetQuery(t *testing.T) {
- verifyRTRMessage(t, NewRTRResetQuery())
-}
-
-func Test_RTRCacheResponse(t *testing.T) {
- id := uint16(time.Now().Unix())
- verifyRTRMessage(t, NewRTRCacheResponse(id))
-}
-
-type rtrIPPrefixTestCase struct {
- pString string
- pLen uint8
- mLen uint8
- asn uint32
- flags uint8
-}
-
-var rtrIPPrefixTestCases = []rtrIPPrefixTestCase{
- {"192.168.0.0", 16, 32, 65001, ANNOUNCEMENT},
- {"192.168.0.0", 16, 32, 65001, WITHDRAWAL},
- {"2001:db8::", 32, 128, 65001, ANNOUNCEMENT},
- {"2001:db8::", 32, 128, 65001, WITHDRAWAL},
- {"::ffff:0.0.0.0", 96, 128, 65001, ANNOUNCEMENT},
- {"::ffff:0.0.0.0", 96, 128, 65001, WITHDRAWAL},
-}
-
-func Test_RTRIPPrefix(t *testing.T) {
- for i := range rtrIPPrefixTestCases {
- test := &rtrIPPrefixTestCases[i]
- addr := net.ParseIP(test.pString)
- verifyRTRMessage(t, NewRTRIPPrefix(addr, test.pLen, test.mLen, test.asn, test.flags))
- }
-}
-
-func Test_RTREndOfData(t *testing.T) {
- id := uint16(time.Now().Unix())
- sn := randUint32()
- verifyRTRMessage(t, NewRTREndOfData(id, sn))
-}
-
-func Test_RTRCacheReset(t *testing.T) {
- verifyRTRMessage(t, NewRTRCacheReset())
-}
-
-func Test_RTRErrorReport(t *testing.T) {
- errPDU, _ := NewRTRResetQuery().Serialize()
- errText1 := []byte("Couldn't send CacheResponce PDU")
- errText2 := []byte("Wrong Length of PDU: 10 bytes")
-
- // See 5.10 ErrorReport in RFC6810
- // when it doesn't have both "erroneous PDU" and "Arbitrary Text"
- verifyRTRMessage(t, NewRTRErrorReport(NO_DATA_AVAILABLE, nil, nil))
-
- // when it has "erroneous PDU"
- verifyRTRMessage(t, NewRTRErrorReport(UNSUPPORTED_PROTOCOL_VERSION, errPDU, nil))
-
- // when it has "ArbitaryText"
- verifyRTRMessage(t, NewRTRErrorReport(INTERNAL_ERROR, nil, errText1))
-
- // when it has both "erroneous PDU" and "Arbitrary Text"
- verifyRTRMessage(t, NewRTRErrorReport(CORRUPT_DATA, errPDU, errText2))
-}