summaryrefslogtreecommitdiffhomepage
path: root/packet/bgp.go
diff options
context:
space:
mode:
Diffstat (limited to 'packet/bgp.go')
-rw-r--r--packet/bgp.go6785
1 files changed, 0 insertions, 6785 deletions
diff --git a/packet/bgp.go b/packet/bgp.go
deleted file mode 100644
index 34b812a0..00000000
--- a/packet/bgp.go
+++ /dev/null
@@ -1,6785 +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"
- "strconv"
- "strings"
-)
-
-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_CONSTRTAINS = 132
- SAFI_FLOW_SPEC_UNICAST = 133
- SAFI_FLOW_SPEC_VPN = 134
- SAFI_KEY_VALUE = 241
-)
-
-const (
- BGP_ORIGIN_ATTR_TYPE_IGP = 0
- BGP_ORIGIN_ATTR_TYPE_EGP = 1
- BGP_ORIGIN_ATTR_TYPE_INCOMPLETE = 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 REGISTRACTION 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_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_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
- //draft-ietf-idr-flowspec-redirect-rt-bis-05
- EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2 ExtendedCommunityAttrType = 0x81
- EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3 ExtendedCommunityAttrType = 0x82
-)
-
-// RFC7153 5.2. Registraction for the "Sub-Type" Field
-// RANGE REGISTRACTION 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_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_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
-)
-
-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_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_ROUTE_REFRESH_CISCO BGPCapabilityCode = 128
-)
-
-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 fmt.Errorf("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 fmt.Errorf("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
-}
-
-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:]
- restart := binary.BigEndian.Uint16(data[0:2])
- c.Flags = uint8(restart >> 12)
- c.Time = restart & 0xfff
- data = data[2:]
- c.Tuples = make([]*CapGracefulRestartTuple, 0, len(data)/4)
- for len(data) >= 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 bool, time uint16, tuples []*CapGracefulRestartTuple) *CapGracefulRestart {
- flags := 0
- if restarting {
- flags = 0x08
- }
- 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 fmt.Errorf("Not all CapabilityMultiProtocol 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_RECEIVE BGPAddPathMode = 1
- BGP_ADD_PATH_SEND BGPAddPathMode = 2
- BGP_ADD_PATH_BOTH BGPAddPathMode = 3
-)
-
-func (m BGPAddPathMode) String() string {
- switch m {
- 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 CapAddPath struct {
- DefaultParameterCapability
- RouteFamily RouteFamily
- Mode BGPAddPathMode
-}
-
-func (c *CapAddPath) DecodeFromBytes(data []byte) error {
- c.DefaultParameterCapability.DecodeFromBytes(data)
- data = data[2:]
- if len(data) < 4 {
- return fmt.Errorf("Not all CapabilityAddPath bytes available")
- }
- c.RouteFamily = AfiSafiToRouteFamily(binary.BigEndian.Uint16(data[:2]), data[2])
- c.Mode = BGPAddPathMode(data[3])
- return nil
-}
-
-func (c *CapAddPath) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- afi, safi := RouteFamilyToAfiSafi(c.RouteFamily)
- binary.BigEndian.PutUint16(buf, afi)
- buf[2] = safi
- buf[3] = byte(c.Mode)
- c.DefaultParameterCapability.CapValue = buf
- return c.DefaultParameterCapability.Serialize()
-}
-
-func (c *CapAddPath) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Code BGPCapabilityCode `json:"code"`
- Value RouteFamily `json:"value"`
- Mode BGPAddPathMode `json:"mode"`
- }{
- Code: c.Code(),
- Value: c.RouteFamily,
- Mode: c.Mode,
- })
-}
-
-func NewCapAddPath(rf RouteFamily, mode BGPAddPathMode) *CapAddPath {
- return &CapAddPath{
- DefaultParameterCapability: DefaultParameterCapability{
- CapCode: BGP_CAP_ADD_PATH,
- },
- RouteFamily: rf,
- Mode: mode,
- }
-}
-
-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 CapUnknown struct {
- DefaultParameterCapability
-}
-
-func DecodeCapability(data []byte) (ParameterCapabilityInterface, error) {
- if len(data) < 2 {
- return nil, fmt.Errorf("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_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{}
- 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 fmt.Errorf("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) error {
- 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 fmt.Errorf("Not all BGP Open message bytes available")
- }
-
- msg.OptParams = []OptionParameterInterface{}
- for rest := msg.OptParamLen; rest > 0; {
- paramtype := data[0]
- paramlen := data[1]
- 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() ([]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) error
- Serialize() ([]byte, error)
- AFI() uint16
- SAFI() uint8
- Len() int
- String() string
- MarshalJSON() ([]byte, error)
-}
-
-type IPAddrPrefixDefault struct {
- 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])
- 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)
- // clear trailing bits in the last byte. rfc doesn't require
- // this though.
- if bitlen%8 != 0 {
- mask := 0xff00 >> (bitlen % 8)
- last_byte_value := buf[bytelen-1] & byte(mask)
- buf[bytelen-1] = last_byte_value
- }
- b := make([]byte, len(r.Prefix))
- copy(b, buf)
- copy(r.Prefix, b)
- return buf, nil
-}
-
-func (r *IPAddrPrefixDefault) Len() int {
- return 1 + ((int(r.Length) + 7) / 8)
-}
-
-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) error {
- if len(data) < 1 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "prefix misses length field")
- }
- r.Length = data[0]
- if r.addrlen == 0 {
- r.addrlen = 4
- }
- return r.decodePrefix(data[1:], r.Length, r.addrlen)
-}
-
-func (r *IPAddrPrefix) Serialize() ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = r.Length
- 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 NewIPAddrPrefix(length uint8, prefix string) *IPAddrPrefix {
- return &IPAddrPrefix{
- IPAddrPrefixDefault{length, net.ParseIP(prefix).To4()},
- 4,
- }
-}
-
-type IPv6AddrPrefix struct {
- IPAddrPrefix
-}
-
-func (r *IPv6AddrPrefix) AFI() uint16 {
- return AFI_IP6
-}
-
-func (r *IPv6AddrPrefix) String() string {
- isZero := func(p net.IP) bool {
- for i := 0; i < len(p); i++ {
- if p[i] != 0 {
- return false
- }
- }
- return true
- }(r.Prefix[0:10])
- if isZero && r.Prefix[10] == 0xff && r.Prefix[11] == 0xff {
- return fmt.Sprintf("::ffff:%s/%d", r.Prefix.String(), r.Length)
- }
- return fmt.Sprintf("%s/%d", r.Prefix.String(), r.Length)
-}
-
-func NewIPv6AddrPrefix(length uint8, prefix string) *IPv6AddrPrefix {
- return &IPv6AddrPrefix{
- IPAddrPrefix{
- IPAddrPrefixDefault{length, net.ParseIP(prefix)},
- 16,
- },
- }
-}
-
-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
- Value []byte
-}
-
-func (rd *DefaultRouteDistinguisher) DecodeFromBytes(data []byte) error {
- rd.Type = binary.BigEndian.Uint16(data[0:2])
- rd.Value = data[2:8]
- return nil
-}
-
-func (rd *DefaultRouteDistinguisher) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint16(buf, rd.Type)
- copy(buf[2:], rd.Value)
- return buf, nil
-}
-
-func (rd *DefaultRouteDistinguisher) String() string {
- return fmt.Sprintf("%v", rd.Value)
-}
-
-func (rd *DefaultRouteDistinguisher) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type uint16 `json:"type"`
- Value []byte `json:"value"`
- }{
- Type: rd.Type,
- Value: rd.Value,
- })
-}
-
-func (rd *DefaultRouteDistinguisher) Len() int { return 8 }
-
-type RouteDistinguisherTwoOctetAS struct {
- DefaultRouteDistinguisher
- Admin uint16
- Assigned uint32
-}
-
-func (rd *RouteDistinguisherTwoOctetAS) Serialize() ([]byte, error) {
- buf := make([]byte, 6)
- binary.BigEndian.PutUint16(buf[0:], rd.Admin)
- binary.BigEndian.PutUint32(buf[2:], rd.Assigned)
- rd.Value = buf
- return rd.DefaultRouteDistinguisher.Serialize()
-}
-
-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) Serialize() ([]byte, error) {
- buf := make([]byte, 6)
- copy(buf[0:], rd.Admin.To4())
- binary.BigEndian.PutUint16(buf[4:], rd.Assigned)
- rd.Value = buf
- return rd.DefaultRouteDistinguisher.Serialize()
-}
-
-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) Serialize() ([]byte, error) {
- buf := make([]byte, 6)
- binary.BigEndian.PutUint32(buf[0:], rd.Admin)
- binary.BigEndian.PutUint16(buf[4:], rd.Assigned)
- rd.Value = buf
- return rd.DefaultRouteDistinguisher.Serialize()
-}
-
-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
-}
-
-func GetRouteDistinguisher(data []byte) RouteDistinguisherInterface {
- rdtype := binary.BigEndian.Uint16(data[0:2])
- switch rdtype {
- 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{}
- rd.Type = rdtype
- return rd
-}
-
-func parseRdAndRt(input string) ([]string, error) {
- exp := regexp.MustCompile("^((\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)|((\\d+)\\.)?(\\d+)):(\\d+)$")
- elems := exp.FindStringSubmatch(input)
- if len(elems) != 10 {
- 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.Atoi(elems[9])
- ip := net.ParseIP(elems[1])
- switch {
- case ip.To4() != nil:
- return NewRouteDistinguisherIPAddressAS(elems[1], uint16(assigned)), nil
- case elems[6] == "" && elems[7] == "":
- asn, _ := strconv.Atoi(elems[8])
- return NewRouteDistinguisherTwoOctetAS(uint16(asn), uint32(assigned)), nil
- default:
- fst, _ := strconv.Atoi(elems[7])
- snd, _ := strconv.Atoi(elems[8])
- 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)
-
-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 {
- l.Labels = []uint32{label}
- return nil
- }
- data = data[3:]
- labels = append(labels, label>>4)
- if label&1 == 1 {
- foundBottom = true
- break
- }
- }
- if foundBottom == false {
- 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.Atoi(elem)
- if err != nil {
- goto ERR
- }
- if i < 0 || i > ((1<<20)-1) {
- goto ERR
- }
- labels = append(labels, uint32(i))
- }
- return NewMPLSLabelStack(labels...), nil
-ERR:
- return nil, fmt.Errorf("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) error {
- 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())
- l.decodePrefix(data, uint8(restbits), l.addrlen)
- return nil
-}
-
-func (l *LabeledVPNIPAddrPrefix) Serialize() ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = 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) String() string {
- masklen := l.IPAddrPrefixDefault.Length - uint8(8*(l.Labels.Len()+l.RD.Len()))
- return fmt.Sprintf("%s:%s/%d", l.RD, 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 + uint8(8*(label.Len()+rdlen)), 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 + uint8(8*(label.Len()+rdlen)), 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) DecodeFromBytes(data []byte) error {
- 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():]
- l.decodePrefix(data, uint8(restbits), l.addrlen)
- return nil
-}
-
-func (l *LabeledIPAddrPrefix) Serialize() ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = 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 {
- return fmt.Sprintf("%s/%d", l.Prefix.String(), int(l.Length)-l.Labels.Len()*8)
-}
-
-func NewLabeledIPAddrPrefix(length uint8, prefix string, label MPLSLabelStack) *LabeledIPAddrPrefix {
- return &LabeledIPAddrPrefix{
- IPAddrPrefixDefault{length + uint8(label.Len()*8), 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 + uint8(label.Len()*8), net.ParseIP(prefix)},
- label,
- 16,
- },
- }
-}
-
-type RouteTargetMembershipNLRI struct {
- Length uint8
- AS uint32
- RouteTarget ExtendedCommunityInterface
-}
-
-func (n *RouteTargetMembershipNLRI) DecodeFromBytes(data []byte) error {
- n.Length = data[0]
- data = data[1:]
- if len(data) == 0 {
- return nil
- } else if len(data) != 12 {
- return fmt.Errorf("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() ([]byte, error) {
- if n.RouteTarget == nil {
- return []byte{0}, nil
- }
- buf := make([]byte, 5)
- buf[0] = 12 * 8
- binary.BigEndian.PutUint32(buf[1:], n.AS)
- ebuf, err := n.RouteTarget.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, ebuf...)
- return buf, nil
-}
-
-func (n *RouteTargetMembershipNLRI) AFI() uint16 {
- return AFI_IP
-}
-
-func (n *RouteTargetMembershipNLRI) SAFI() uint8 {
- return SAFI_ROUTE_TARGET_CONSTRTAINS
-}
-
-func (n *RouteTargetMembershipNLRI) Len() 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 fmt.Errorf("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 {
- s := bytes.NewBuffer(make([]byte, 0, 64))
- s.WriteString(fmt.Sprintf("%s | ", esi.Type.String()))
- switch esi.Type {
- case ESI_ARBITRARY:
- if isZeroBuf(esi.Value) {
- return "single-homed"
- }
- s.WriteString(fmt.Sprintf("%s", esi.Value))
- 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:%d, ", binary.BigEndian.Uint16(esi.Value[:2]), binary.BigEndian.Uint16(esi.Value[2:4])))
- s.WriteString(fmt.Sprintf("local discriminator %d", binary.BigEndian.Uint32(esi.Value[4:8])))
- default:
- s.WriteString(fmt.Sprintf("value %s", esi.Value))
- }
- return s.String()
-}
-
-//
-// 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 {
- return uint32(data[0])<<16 | uint32(data[1])<<8 | uint32(data[2])
-}
-
-func labelSerialize(label uint32, buf []byte) {
- buf[0] = byte((label >> 16) & 0xff)
- buf[1] = byte((label >> 8) & 0xff)
- buf[2] = byte(label & 0xff)
-}
-
-type EVPNEthernetAutoDiscoveryRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- ETag uint32
- Label uint32
-}
-
-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:]
- er.Label = labelDecode(data)
- 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 = make([]byte, 3)
- labelSerialize(er.Label, tbuf)
- buf = append(buf, tbuf...)
-
- return buf, nil
-}
-
-func (er *EVPNEthernetAutoDiscoveryRoute) String() string {
- return fmt.Sprintf("[type:A-D][rd:%s][esi:%s][etag:%d][label:%d]", er.RD, er.ESI.String(), er.ETag, er.Label)
-}
-
-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
-}
-
-type EVPNMacIPAdvertisementRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- ETag uint32
- MacAddressLength uint8
- MacAddress net.HardwareAddr
- IPAddressLength uint8
- IPAddress net.IP
- Labels []uint32
-}
-
-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 fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength)
- }
- data = data[(er.IPAddressLength / 8):]
- label1 := labelDecode(data)
- er.Labels = append(er.Labels, label1)
- data = data[3:]
- if len(data) == 3 {
- label2 := labelDecode(data)
- er.Labels = append(er.Labels, label2)
-
- }
- 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...)
-
- if er.IPAddressLength == 0 {
- buf = append(buf, 0)
- } else if er.IPAddressLength == 32 || er.IPAddressLength == 128 {
- buf = append(buf, er.IPAddressLength)
- if er.IPAddressLength == 32 {
- er.IPAddress = er.IPAddress.To4()
- }
- buf = append(buf, []byte(er.IPAddress)...)
- } else {
- return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength)
- }
-
- for _, l := range er.Labels {
- tbuf = make([]byte, 3)
- labelSerialize(l, tbuf)
- buf = append(buf, tbuf...)
- }
- return buf, nil
-}
-
-func (er *EVPNMacIPAdvertisementRoute) String() string {
- return fmt.Sprintf("[type:macadv][rd:%s][esi:%s][etag:%d][mac:%s][ip:%s][labels:%v]", er.RD, er.ESI.String(), er.ETag, er.MacAddress, er.IPAddress, er.Labels)
-}
-
-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
-}
-
-type EVPNMulticastEthernetTagRoute struct {
- RD RouteDistinguisherInterface
- ETag uint32
- IPAddressLength uint8
- IPAddress net.IP
-}
-
-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 fmt.Errorf("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...)
- if er.IPAddressLength == 32 || er.IPAddressLength == 128 {
- buf = append(buf, er.IPAddressLength)
- if er.IPAddressLength == 32 {
- er.IPAddress = er.IPAddress.To4()
- }
- buf = append(buf, []byte(er.IPAddress)...)
- } else {
- 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 {
- 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
-}
-
-type EVPNEthernetSegmentRoute struct {
- RD RouteDistinguisherInterface
- ESI EthernetSegmentIdentifier
- IPAddressLength uint8
- IPAddress net.IP
-}
-
-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 fmt.Errorf("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)
- if er.IPAddressLength == 32 || er.IPAddressLength == 128 {
- if er.IPAddressLength == 32 {
- er.IPAddress = er.IPAddress.To4()
- }
- buf = append(buf, []byte(er.IPAddress)...)
- } else {
- return nil, fmt.Errorf("Invalid IP address length: %d", er.IPAddressLength)
- }
- return buf, nil
-}
-
-type EVPNRouteTypeInterface interface {
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
- String() string
- rd() RouteDistinguisherInterface
- MarshalJSON() ([]byte, error)
-}
-
-func (er *EVPNEthernetSegmentRoute) String() string {
- return fmt.Sprintf("[type:esi][rd:%s][esi:%d][ip:%s]", er.RD, er.ESI, 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 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
- }
- return nil, fmt.Errorf("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
-)
-
-type EVPNNLRI struct {
- RouteType uint8
- Length uint8
- RouteTypeData EVPNRouteTypeInterface
-}
-
-func (n *EVPNNLRI) DecodeFromBytes(data []byte) error {
- if len(data) < 2 {
- return fmt.Errorf("Not all EVPNNLRI bytes available")
- }
- n.RouteType = data[0]
- n.Length = data[1]
- data = data[2:]
- if len(data) < int(n.Length) {
- return fmt.Errorf("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() ([]byte, error) {
- buf := make([]byte, 2)
- buf[0] = n.RouteType
- tbuf, err := n.RouteTypeData.Serialize()
- n.Length = uint8(len(tbuf))
- buf[1] = n.Length
- if err != nil {
- return nil, err
- }
- buf = append(buf, tbuf...)
- return buf, nil
-}
-
-func (n *EVPNNLRI) AFI() uint16 {
- return AFI_L2VPN
-}
-
-func (n *EVPNNLRI) SAFI() uint8 {
- return SAFI_EVPN
-}
-
-func (n *EVPNNLRI) Len() 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, length uint8, routetypedata EVPNRouteTypeInterface) *EVPNNLRI {
- return &EVPNNLRI{
- routetype,
- length,
- routetypedata,
- }
-}
-
-type EncapNLRI struct {
- IPAddrPrefixDefault
-}
-
-func (n *EncapNLRI) DecodeFromBytes(data []byte) error {
- 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]
- return n.decodePrefix(data[1:], n.Length, n.Length/8)
-}
-
-func (n *EncapNLRI) Serialize() ([]byte, error) {
- buf := make([]byte, 1)
- buf[0] = net.IPv6len * 8
- if n.Prefix.To4() != nil {
- buf[0] = net.IPv4len * 8
- n.Prefix = n.Prefix.To4()
- }
- n.Length = buf[0]
- 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 {
- if n.Prefix.To4() != nil {
- return AFI_IP
- }
- return AFI_IP6
-}
-
-func (n *EncapNLRI) SAFI() uint8 {
- return SAFI_ENCAPSULATION
-}
-
-func NewEncapNLRI(endpoint string) *EncapNLRI {
- return &EncapNLRI{
- IPAddrPrefixDefault{0, net.ParseIP(endpoint)},
- }
-}
-
-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,
-}
-
-func flowSpecPrefixParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- if len(args) < 2 {
- return nil, fmt.Errorf("invalid flowspec dst/src prefix")
- }
- typ := args[0]
- ip, net, err := net.ParseCIDR(args[1])
- if err != nil {
- return nil, fmt.Errorf("invalid ip prefix")
- }
- afi, _ := RouteFamilyToAfiSafi(rf)
- if afi == AFI_IP && ip.To4() == nil {
- return nil, fmt.Errorf("invalid ipv4 prefix")
- } else if afi == AFI_IP6 && !strings.Contains(ip.String(), ":") {
- return nil, fmt.Errorf("invalid ipv6 prefix")
- }
- ones, _ := net.Mask.Size()
- var offset uint8
- if len(args) > 2 {
- o, err := strconv.Atoi(args[2])
- offset = uint8(o)
- if err != nil {
- return nil, err
- }
- }
-
- switch typ {
- case FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]:
- switch rf {
- case RF_FS_IPv4_UC:
- return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
- case RF_FS_IPv6_UC:
- return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(ones), ip.String()), offset), nil
- default:
- return nil, fmt.Errorf("invalid type. only RF_FS_IPv4_UC or RF_FS_IPv6_UC is allowed")
- }
- case FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]:
- switch rf {
- case RF_FS_IPv4_UC:
- return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
- case RF_FS_IPv6_UC:
- return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(ones), ip.String()), offset), nil
- default:
- return nil, fmt.Errorf("invalid type. only RF_FS_IPv4_UC or RF_FS_IPv6_UC is allowed")
- }
- }
- return nil, fmt.Errorf("invalid type. only destination or source is allowed")
-}
-
-func flowSpecIpProtoParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- ss := make([]string, 0, len(ProtocolNameMap))
- for _, v := range ProtocolNameMap {
- ss = append(ss, v)
- }
- protos := strings.Join(ss, "|")
- exp := regexp.MustCompile(fmt.Sprintf("^%s (((%s) )*)(%s)$", FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO], protos, protos))
- elems := exp.FindStringSubmatch(strings.Join(args, " "))
- items := make([]*FlowSpecComponentItem, 0)
- eq := 0x1
- if elems[1] != "" {
- for _, v := range strings.Split(elems[1], " ") {
- p, ok := ProtocolValueMap[v]
- if !ok {
- continue
- }
- items = append(items, NewFlowSpecComponentItem(eq, int(p)))
- }
- }
- items = append(items, NewFlowSpecComponentItem(eq, int(ProtocolValueMap[elems[4]])))
- return NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, items), nil
-}
-
-func flowSpecTcpFlagParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- ss := make([]string, 0, len(TCPFlagNameMap))
- for _, v := range TCPFlagNameMap {
- ss = append(ss, v)
- }
- protos := strings.Join(ss, "|")
- exp := regexp.MustCompile(fmt.Sprintf("^%s (not )?(match )?((((%s)\\&)*(%s) )*(((%s)\\&)*(%s)))$", FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG], protos, protos, protos, protos))
- elems := exp.FindStringSubmatch(strings.Join(args, " "))
- if len(elems) < 1 {
- return nil, fmt.Errorf("invalid flag format")
- }
- items := make([]*FlowSpecComponentItem, 0)
- op := 0
- if elems[2] != "" {
- op |= 0x1
- }
- if elems[1] != "" {
- op |= 0x2
- }
- for _, v := range strings.Split(elems[3], " ") {
- flag := 0
- for _, e := range strings.Split(v, "&") {
- flag |= int(TCPFlagValueMap[e])
- }
- items = append(items, NewFlowSpecComponentItem(op, flag))
- }
- return NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, items), nil
-}
-
-func flowSpecEtherTypeParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- ss := make([]string, 0, len(EthernetTypeNameMap))
- for _, v := range EthernetTypeNameMap {
- ss = append(ss, v)
- }
- protos := strings.Join(ss, "|")
- exp := regexp.MustCompile(fmt.Sprintf("^%s (((%s) )*)(%s)$", FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE], protos, protos))
- elems := exp.FindStringSubmatch(strings.Join(args, " "))
- items := make([]*FlowSpecComponentItem, 0)
- eq := 0x1
- if elems[1] != "" {
- for _, v := range strings.Split(elems[1], " ") {
- p, ok := EthernetTypeValueMap[v]
- if !ok {
- continue
- }
- items = append(items, NewFlowSpecComponentItem(eq, int(p)))
- }
- }
- items = append(items, NewFlowSpecComponentItem(eq, int(EthernetTypeValueMap[elems[4]])))
- return NewFlowSpecComponent(FLOW_SPEC_TYPE_ETHERNET_TYPE, items), nil
-}
-
-func doFlowSpecNumericParser(rf RouteFamily, args []string, validationFunc func(int) error) (FlowSpecComponentInterface, error) {
- if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP && FlowSpecValueMap[args[0]] == FLOW_SPEC_TYPE_LABEL {
- return nil, fmt.Errorf("flow label spec is only allowed for ipv6")
- }
- exp := regexp.MustCompile("^((<=|>=|[<>=])(\\d+)&)?(<=|>=|[<>=])?(\\d+)$")
- items := make([]*FlowSpecComponentItem, 0)
-
- f := func(and bool, o, v string) (*FlowSpecComponentItem, error) {
- op := 0
- if and {
- op |= 0x40
- }
- if len(o) == 0 {
- op |= 0x1
- }
- for _, oo := range o {
- switch oo {
- case '>':
- op |= 0x2
- case '<':
- op |= 0x4
- case '=':
- op |= 0x1
- }
- }
- value, err := strconv.Atoi(v)
- if err != nil {
- return nil, err
- }
- err = validationFunc(value)
- if err != nil {
- return nil, err
- }
- return NewFlowSpecComponentItem(op, value), nil
- }
-
- for _, arg := range args[1:] {
- var and bool
- elems := exp.FindStringSubmatch(arg)
- if len(elems) == 0 {
- return nil, fmt.Errorf("invalid flowspec numeric item")
- }
- if elems[1] != "" {
- and = true
- item, err := f(false, elems[2], elems[3])
- if err != nil {
- return nil, err
- }
- items = append(items, item)
- }
- item, err := f(and, elems[4], elems[5])
- if err != nil {
- return nil, err
- }
- items = append(items, item)
- }
-
- return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
-}
-
-func flowSpecNumericParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- f := func(i int) error {
- return nil
- }
- return doFlowSpecNumericParser(rf, args, f)
-}
-
-func flowSpecPortParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- f := func(i int) error {
- if 0 < i && i < 65536 {
- return nil
- }
- return fmt.Errorf("port range exceeded")
- }
- return doFlowSpecNumericParser(rf, args, f)
-}
-
-func flowSpecDscpParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- f := func(i int) error {
- if 0 < i && i < 64 {
- return nil
- }
- return fmt.Errorf("dscp value range exceeded")
- }
- return doFlowSpecNumericParser(rf, args, f)
-}
-
-func flowSpecFragmentParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- if len(args) < 2 {
- return nil, fmt.Errorf("invalid flowspec fragment specifier")
- }
- items := make([]*FlowSpecComponentItem, 0)
- for _, a := range args[1:] {
- value := 0
- switch a {
- case "dont-fragment":
- if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP6 {
- return nil, fmt.Errorf("can't specify dont-fragment for ipv6")
- }
- value = 0x1
- case "is-fragment":
- value = 0x2
- case "first-fragment":
- value = 0x4
- case "last-fragment":
- value = 0x8
- case "not-a-fragment":
- value = 0x0
- default:
- return nil, fmt.Errorf("invalid flowspec fragment specifier")
- }
- items = append(items, NewFlowSpecComponentItem(0, value))
- }
- return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
-}
-
-func flowSpecMacParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
- if len(args) < 2 {
- return nil, fmt.Errorf("invalid flowspec dst/src mac")
- }
- if rf != RF_FS_L2_VPN {
- return nil, fmt.Errorf("invalid family")
- }
- typ := args[0]
- mac, err := net.ParseMAC(args[1])
- if err != nil {
- return nil, fmt.Errorf("invalid mac")
- }
- switch typ {
- case FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]:
- return NewFlowSpecDestinationMac(mac), nil
- case FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]:
- return NewFlowSpecSourceMac(mac), nil
- }
- return nil, fmt.Errorf("invalid type. only %s or %s allowed", FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC], FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC])
-}
-
-var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, []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: flowSpecPortParser,
- FLOW_SPEC_TYPE_DST_PORT: flowSpecPortParser,
- FLOW_SPEC_TYPE_SRC_PORT: flowSpecPortParser,
- FLOW_SPEC_TYPE_ICMP_TYPE: flowSpecNumericParser,
- FLOW_SPEC_TYPE_ICMP_CODE: flowSpecNumericParser,
- FLOW_SPEC_TYPE_TCP_FLAG: flowSpecTcpFlagParser,
- FLOW_SPEC_TYPE_PKT_LEN: flowSpecNumericParser,
- FLOW_SPEC_TYPE_DSCP: flowSpecDscpParser,
- FLOW_SPEC_TYPE_FRAGMENT: flowSpecFragmentParser,
- FLOW_SPEC_TYPE_LABEL: flowSpecNumericParser,
- FLOW_SPEC_TYPE_ETHERNET_TYPE: flowSpecEtherTypeParser,
- FLOW_SPEC_TYPE_DST_MAC: flowSpecMacParser,
- FLOW_SPEC_TYPE_SRC_MAC: flowSpecMacParser,
- FLOW_SPEC_TYPE_LLC_DSAP: flowSpecNumericParser,
- FLOW_SPEC_TYPE_LLC_SSAP: flowSpecNumericParser,
- FLOW_SPEC_TYPE_LLC_CONTROL: flowSpecNumericParser,
- FLOW_SPEC_TYPE_SNAP: flowSpecNumericParser,
- FLOW_SPEC_TYPE_VID: flowSpecNumericParser,
- FLOW_SPEC_TYPE_COS: flowSpecNumericParser,
- FLOW_SPEC_TYPE_INNER_VID: flowSpecNumericParser,
- FLOW_SPEC_TYPE_INNER_COS: flowSpecNumericParser,
-}
-
-func ParseFlowSpecComponents(rf RouteFamily, input string) ([]FlowSpecComponentInterface, error) {
- idxs := make([]struct {
- t BGPFlowSpecType
- i int
- }, 0, 8)
- args := strings.Split(input, " ")
- for idx, v := range args {
- if t, ok := FlowSpecValueMap[v]; ok {
- idxs = append(idxs, struct {
- t BGPFlowSpecType
- i int
- }{t, idx})
- }
- }
- if len(idxs) == 0 {
- return nil, fmt.Errorf("failed to parse: %s", input)
- }
- cmps := make([]FlowSpecComponentInterface, 0, len(idxs))
- for i, idx := range idxs {
- var a []string
- f := flowSpecParserMap[idx.t]
- if i < len(idxs)-1 {
- a = args[idx.i:idxs[i+1].i]
- } else {
- a = args[idx.i:]
- }
- cmp, err := f(rf, a)
- if err != nil {
- return nil, err
- }
- cmps = append(cmps, cmp)
- }
- return cmps, 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) error
- Serialize() ([]byte, error)
- Len() int
- Type() BGPFlowSpecType
- String() string
-}
-
-type flowSpecPrefix struct {
- Prefix AddrPrefixInterface
- type_ BGPFlowSpecType
-}
-
-func (p *flowSpecPrefix) DecodeFromBytes(data []byte) error {
- p.type_ = BGPFlowSpecType(data[0])
- return p.Prefix.DecodeFromBytes(data[1:])
-}
-
-func (p *flowSpecPrefix) Serialize() ([]byte, error) {
- buf := []byte{byte(p.Type())}
- bbuf, err := p.Prefix.Serialize()
- if err != nil {
- return nil, err
- }
- return append(buf, bbuf...), nil
-}
-
-func (p *flowSpecPrefix) Len() int {
- buf, _ := p.Serialize()
- return len(buf)
-}
-
-func (p *flowSpecPrefix) Type() BGPFlowSpecType {
- return p.type_
-}
-
-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
- type_ 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) error {
- p.type_ = BGPFlowSpecType(data[0])
- p.Offset = data[2]
- prefix := append([]byte{data[1]}, data[3:]...)
- return p.Prefix.DecodeFromBytes(prefix)
-}
-
-func (p *flowSpecPrefix6) Serialize() ([]byte, error) {
- buf := []byte{byte(p.Type())}
- bbuf, err := p.Prefix.Serialize()
- 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() int {
- buf, _ := p.Serialize()
- return len(buf)
-}
-
-func (p *flowSpecPrefix6) Type() BGPFlowSpecType {
- return p.type_
-}
-
-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
- type_ BGPFlowSpecType
-}
-
-func (p *flowSpecMac) DecodeFromBytes(data []byte) error {
- if len(data) < 2 || len(data) < 2+int(data[1]) {
- return fmt.Errorf("not all mac bits available")
- }
- p.type_ = BGPFlowSpecType(data[0])
- p.Mac = net.HardwareAddr(data[2 : 2+int(data[1])])
- return nil
-}
-
-func (p *flowSpecMac) Serialize() ([]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() int {
- return 2 + len(p.Mac)
-}
-
-func (p *flowSpecMac) Type() BGPFlowSpecType {
- return p.type_
-}
-
-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, type_: FLOW_SPEC_TYPE_SRC_MAC}}
-}
-
-type FlowSpecDestinationMac struct {
- flowSpecMac
-}
-
-func NewFlowSpecDestinationMac(mac net.HardwareAddr) *FlowSpecDestinationMac {
- return &FlowSpecDestinationMac{flowSpecMac{Mac: mac, type_: FLOW_SPEC_TYPE_DST_MAC}}
-}
-
-type FlowSpecComponentItem struct {
- Op int `json:"op"`
- Value int `json:"value"`
-}
-
-func (v *FlowSpecComponentItem) Len() int {
- return 1 << ((uint32(v.Op) >> 4) & 0x3)
-}
-
-func (v *FlowSpecComponentItem) Serialize() ([]byte, error) {
- if v.Value < 0 {
- return nil, fmt.Errorf("invalid value size(too small): %d", v.Value)
- }
- if v.Op < 0 || 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 int, value int) *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 = int(uint32(v.Op) | order<<4)
- return v
-}
-
-type FlowSpecComponent struct {
- Items []*FlowSpecComponentItem
- type_ BGPFlowSpecType
-}
-
-func (p *FlowSpecComponent) DecodeFromBytes(data []byte) error {
- p.type_ = BGPFlowSpecType(data[0])
- data = data[1:]
- p.Items = make([]*FlowSpecComponentItem, 0)
- for {
- if len(data) < 2 {
- return fmt.Errorf("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 := int(binary.BigEndian.Uint64(v))
- item := &FlowSpecComponentItem{int(op), i}
- p.Items = append(p.Items, item)
- if end > 0 {
- break
- }
- data = data[1+l:]
- }
- return nil
-}
-
-func (p *FlowSpecComponent) Serialize() ([]byte, error) {
- buf := []byte{byte(p.Type())}
- for i, v := range p.Items {
- //set end-of-list bit
- if i == (len(p.Items) - 1) {
- v.Op |= 0x80
- } else {
- v.Op &^= 0x80
- }
- bbuf, err := v.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- return buf, nil
-}
-
-func (p *FlowSpecComponent) Len() int {
- l := 1
- for _, item := range p.Items {
- l += (item.Len() + 1)
- }
- return l
-}
-
-func (p *FlowSpecComponent) Type() BGPFlowSpecType {
- return p.type_
-}
-
-func formatRaw(op int, value int) string {
- return fmt.Sprintf("op: %b, value: %d", op, value)
-}
-
-func formatNumericOp(op int) string {
- var opstr string
- if op&0x40 > 0 {
- opstr = "&"
- } else {
- opstr = " "
- }
- if op&0x2 > 0 {
- opstr += ">"
- }
- if op&0x4 > 0 {
- opstr += "<"
- }
- if op&0x1 > 0 {
- opstr += "="
- }
- return opstr
-}
-
-func formatNumeric(op int, value int) string {
- return fmt.Sprintf("%s%d", formatNumericOp(op), value)
-}
-
-func formatProto(op int, value int) string {
- return fmt.Sprintf(" %s", Protocol(value).String())
-}
-
-func formatFlag(op int, value int) string {
- and := " "
- ss := make([]string, 0, 2)
- if op&0x40 > 0 {
- and = "&"
- }
- if op&0x1 > 0 {
- ss = append(ss, "match")
- }
- if op&0x2 > 0 {
- ss = append(ss, "not")
- }
- if len(ss) > 0 {
- return fmt.Sprintf("%s(%s)%s", and, strings.Join(ss, "|"), TCPFlag(value).String())
- }
- return fmt.Sprintf("%s%s", and, TCPFlag(value).String())
-}
-
-func formatFragment(op int, value int) string {
- ss := make([]string, 0)
- if value == 0 {
- ss = append(ss, "not-a-fragment")
- }
- if value&0x1 > 0 {
- ss = append(ss, "dont-fragment")
- }
- if value&0x2 > 0 {
- ss = append(ss, "is-fragment")
- }
- if value&0x4 > 0 {
- ss = append(ss, "first-fragment")
- }
- if value&0x8 > 0 {
- ss = append(ss, "last-fragment")
- }
- if len(ss) > 1 {
- return fmt.Sprintf("%s(%s)", formatNumericOp(op), strings.Join(ss, "|"))
- }
- return fmt.Sprintf("%s%s", formatNumericOp(op), ss[0])
-}
-
-func formatEtherType(op int, value int) string {
- return fmt.Sprintf(" %s", EthernetType(value).String())
-}
-
-var flowSpecFormatMap = map[BGPFlowSpecType]func(op int, value int) 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: formatFlag,
- 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.Type()]; ok {
- f = flowSpecFormatMap[p.Type()]
- }
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- for _, i := range p.Items {
- buf.WriteString(f(i.Op, i.Value))
- }
- return fmt.Sprintf("[%s:%s]", p.type_, buf.String())
-}
-
-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(type_ BGPFlowSpecType, items []*FlowSpecComponentItem) *FlowSpecComponent {
- return &FlowSpecComponent{
- Items: items,
- type_: type_,
- }
-}
-
-type FlowSpecUnknown struct {
- Value []byte
-}
-
-func (p *FlowSpecUnknown) DecodeFromBytes(data []byte) error {
- p.Value = data
- return nil
-}
-
-func (p *FlowSpecUnknown) Serialize() ([]byte, error) {
- return p.Value, nil
-}
-
-func (p *FlowSpecUnknown) Len() 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)
-}
-
-type FlowSpecNLRI struct {
- Value []FlowSpecComponentInterface
- rf RouteFamily
-}
-
-func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error {
- 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 fmt.Errorf("not all flowspec component bytes available")
- }
-
- n.rf = rf
-
- for l := length; l > 0; {
- if len(data) == 0 {
- return fmt.Errorf("not all flowspec component bytes available")
- }
- t := BGPFlowSpecType(data[0])
- var i FlowSpecComponentInterface
- switch t {
- case FLOW_SPEC_TYPE_DST_PREFIX:
- switch rf {
- case RF_FS_IPv4_UC:
- i = NewFlowSpecDestinationPrefix(NewIPAddrPrefix(0, ""))
- case RF_FS_IPv4_VPN:
- i = NewFlowSpecDestinationPrefix(NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil))
- case RF_FS_IPv6_UC:
- i = NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(0, ""), 0)
- case RF_FS_IPv6_VPN:
- i = NewFlowSpecDestinationPrefix6(NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil), 0)
- default:
- return fmt.Errorf("Invalid RF: %v", rf)
- }
- case FLOW_SPEC_TYPE_SRC_PREFIX:
- switch rf {
- case RF_FS_IPv4_UC:
- i = NewFlowSpecSourcePrefix(NewIPAddrPrefix(0, ""))
- case RF_FS_IPv4_VPN:
- i = NewFlowSpecSourcePrefix(NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil))
- case RF_FS_IPv6_UC:
- i = NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(0, ""), 0)
- case RF_FS_IPv6_VPN:
- i = NewFlowSpecSourcePrefix6(NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil), 0)
- default:
- return fmt.Errorf("Invalid RF: %v", rf)
- }
- case FLOW_SPEC_TYPE_SRC_MAC:
- switch rf {
- case RF_FS_L2_VPN:
- i = NewFlowSpecSourceMac(nil)
- default:
- return fmt.Errorf("invalid family: %v", rf)
- }
- case FLOW_SPEC_TYPE_DST_MAC:
- switch rf {
- case RF_FS_L2_VPN:
- i = NewFlowSpecDestinationMac(nil)
- default:
- return fmt.Errorf("invalid 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)
- if err != nil {
- i = &FlowSpecUnknown{data}
- }
- l -= i.Len()
- data = data[i.Len():]
- n.Value = append(n.Value, i)
- }
-
- return nil
-}
-
-func (n *FlowSpecNLRI) Serialize() ([]byte, error) {
- buf := make([]byte, 0, 32)
- for _, v := range n.Value {
- b, err := v.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, b...)
- }
- length := n.Len()
- 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...)
- }
-
- return buf, nil
-}
-
-func (n *FlowSpecNLRI) Len() int {
- l := 0
- for _, v := range n.Value {
- l += v.Len()
- }
- if l < 0xf0 {
- return l + 1
- } else {
- return l + 2
- }
-}
-
-func (n *FlowSpecNLRI) String() string {
- buf := bytes.NewBuffer(make([]byte, 0, 32))
- for _, v := range n.Value {
- buf.WriteString(v.String())
- }
- return buf.String()
-}
-
-func (n *FlowSpecNLRI) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Value []FlowSpecComponentInterface `json:"value"`
- }{
- Value: n.Value,
- })
-}
-
-type FlowSpecIPv4Unicast struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
-}
-
-func (n *FlowSpecIPv4Unicast) AFI() uint16 {
- return AFI_IP
-}
-
-func (n *FlowSpecIPv4Unicast) SAFI() uint8 {
- return SAFI_FLOW_SPEC_UNICAST
-}
-
-func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast {
- return &FlowSpecIPv4Unicast{FlowSpecNLRI{value, RF_FS_IPv4_UC}}
-}
-
-type FlowSpecIPv4VPN struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
-}
-
-func (n *FlowSpecIPv4VPN) AFI() uint16 {
- return AFI_IP
-}
-
-func (n *FlowSpecIPv4VPN) SAFI() uint8 {
- return SAFI_FLOW_SPEC_VPN
-}
-
-func NewFlowSpecIPv4VPN(value []FlowSpecComponentInterface) *FlowSpecIPv4VPN {
- return &FlowSpecIPv4VPN{FlowSpecNLRI{value, RF_FS_IPv4_VPN}}
-}
-
-type FlowSpecIPv6Unicast struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
-}
-
-func (n *FlowSpecIPv6Unicast) AFI() uint16 {
- return AFI_IP6
-}
-
-func (n *FlowSpecIPv6Unicast) SAFI() uint8 {
- return SAFI_FLOW_SPEC_UNICAST
-}
-
-func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast {
- return &FlowSpecIPv6Unicast{FlowSpecNLRI{
- Value: value,
- rf: RF_FS_IPv6_UC,
- }}
-}
-
-type FlowSpecIPv6VPN struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
-}
-
-func (n *FlowSpecIPv6VPN) AFI() uint16 {
- return AFI_IP6
-}
-
-func (n *FlowSpecIPv6VPN) SAFI() uint8 {
- return SAFI_FLOW_SPEC_VPN
-}
-
-func NewFlowSpecIPv6VPN(value []FlowSpecComponentInterface) *FlowSpecIPv6VPN {
- return &FlowSpecIPv6VPN{FlowSpecNLRI{
- Value: value,
- rf: RF_FS_IPv6_VPN,
- }}
-}
-
-type FlowSpecL2VPN struct {
- FlowSpecNLRI
-}
-
-func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte) error {
- return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
-}
-
-func (n *FlowSpecL2VPN) AFI() uint16 {
- return AFI_L2VPN
-}
-
-func (n *FlowSpecL2VPN) SAFI() uint8 {
- return SAFI_FLOW_SPEC_VPN
-}
-
-func NewFlowSpecL2VPN(value []FlowSpecComponentInterface) *FlowSpecL2VPN {
- return &FlowSpecL2VPN{FlowSpecNLRI{
- Value: value,
- rf: RF_FS_L2_VPN,
- }}
-}
-
-type OpaqueNLRI struct {
- Length uint8
- Key []byte
-}
-
-func (n *OpaqueNLRI) DecodeFromBytes(data []byte) error {
- n.Length = data[0]
- if len(data)-1 < int(n.Length) {
- return fmt.Errorf("Not all OpaqueNLRI bytes available")
- }
- n.Key = data[1 : 1+n.Length]
- return nil
-}
-
-func (n *OpaqueNLRI) Serialize() ([]byte, error) {
- if len(n.Key) > math.MaxUint8 {
- return nil, fmt.Errorf("Key length too big")
- }
- return append([]byte{byte(len(n.Key))}, n.Key...), nil
-}
-
-func (n *OpaqueNLRI) AFI() uint16 {
- return AFI_OPAQUE
-}
-
-func (n *OpaqueNLRI) SAFI() uint8 {
- return SAFI_KEY_VALUE
-}
-
-func (n *OpaqueNLRI) Len() int {
- return 1 + len(n.Key)
-}
-
-func (n *OpaqueNLRI) String() string {
- return string(n.Key)
-}
-
-func (n *OpaqueNLRI) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Key string `json:"key"`
- }{
- Key: n.String(),
- })
-}
-
-func NewOpaqueNLRI(key []byte) *OpaqueNLRI {
- return &OpaqueNLRI{
- Key: key,
- }
-}
-
-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_CONSTRTAINS
- RF_ENCAP RouteFamily = AFI_IP<<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_ENCAP: "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_ENCAP]: RF_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) (prefix AddrPrefixInterface, err error) {
- switch AfiSafiToRouteFamily(afi, safi) {
- case RF_IPv4_UC, RF_IPv4_MC:
- prefix = NewIPAddrPrefix(0, "")
- case RF_IPv6_UC, RF_IPv6_MC:
- 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, 0, nil)
- case RF_RTC_UC:
- prefix = &RouteTargetMembershipNLRI{}
- case RF_ENCAP:
- prefix = NewEncapNLRI("")
- case RF_FS_IPv4_UC:
- prefix = &FlowSpecIPv4Unicast{}
- case RF_FS_IPv4_VPN:
- prefix = &FlowSpecIPv4VPN{}
- case RF_FS_IPv6_UC:
- prefix = &FlowSpecIPv6Unicast{}
- case RF_FS_IPv6_VPN:
- prefix = &FlowSpecIPv6VPN{}
- case RF_FS_L2_VPN:
- prefix = &FlowSpecL2VPN{}
- case RF_OPAQUE:
- prefix = &OpaqueNLRI{}
- default:
- return nil, fmt.Errorf("unknown route family. AFI: %d, SAFI: %d", afi, safi)
- }
- return prefix, nil
-}
-
-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_AIGP // = 26
- BGP_ATTR_TYPE_OPAQUE_VALUE BGPAttrType = 41
-)
-
-// 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
-)
-
-// 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_AUTHENTICATION_FAILURE
- BGP_ERROR_SUB_UNACCEPTABLE_HOLD_TIME
-)
-
-// 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_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_FSM_ERROR
-)
-
-// 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_RESET
- BGP_ERROR_SUB_OTHER_CONFIGURATION_CHANGE
- BGP_ERROR_SUB_CONNECTION_COLLISION_RESOLUTION
- BGP_ERROR_SUB_OUT_OF_RESOURCES
-)
-
-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_AIGP: BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_TYPE_OPAQUE_VALUE: BGP_ATTR_FLAG_TRANSITIVE | BGP_ATTR_FLAG_OPTIONAL,
-}
-
-type PathAttributeInterface interface {
- DecodeFromBytes([]byte) error
- Serialize() ([]byte, error)
- Len() int
- getFlags() BGPAttrFlag
- GetType() BGPAttrType
- String() string
- MarshalJSON() ([]byte, error)
-}
-
-type PathAttribute struct {
- Flags BGPAttrFlag
- Type BGPAttrType
- Length uint16
- Value []byte
-}
-
-func (p *PathAttribute) Len() int {
- if p.Length == 0 {
- p.Length = uint16(len(p.Value))
- }
- l := 2 + p.Length
- if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 {
- l += 2
- } else {
- l += 1
- }
- return int(l)
-}
-
-func (p *PathAttribute) getFlags() BGPAttrFlag {
- return p.Flags
-}
-
-func (p *PathAttribute) GetType() BGPAttrType {
- return p.Type
-}
-
-func (p *PathAttribute) DecodeFromBytes(data []byte) error {
- odata := data
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- if len(data) < 2 {
- return NewMessageError(eCode, eSubCode, data, "attribute header length is short")
- }
- p.Flags = BGPAttrFlag(data[0])
- p.Type = BGPAttrType(data[1])
-
- if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 {
- if len(data) < 4 {
- return 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 NewMessageError(eCode, eSubCode, data, "attribute header length is short")
- }
- p.Length = uint16(data[2])
- data = data[3:]
- }
- if len(data) < int(p.Length) {
- return NewMessageError(eCode, eSubCode, data, "attribute value length is short")
- }
- if len(data[:p.Length]) > 0 {
- p.Value = data[:p.Length]
- }
-
- ok, eMsg := ValidateFlags(p.Type, p.Flags)
- if !ok {
- return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, odata[:p.Len()], eMsg)
- }
- return nil
-}
-
-func (p *PathAttribute) Serialize() ([]byte, error) {
- p.Length = uint16(len(p.Value))
- if p.Length > 255 {
- p.Flags |= BGP_ATTR_FLAG_EXTENDED_LENGTH
- } else {
- p.Flags &^= BGP_ATTR_FLAG_EXTENDED_LENGTH
- }
- buf := make([]byte, p.Len())
- buf[0] = uint8(p.Flags)
- buf[1] = uint8(p.Type)
- if p.Flags&BGP_ATTR_FLAG_EXTENDED_LENGTH != 0 {
- binary.BigEndian.PutUint16(buf[2:4], p.Length)
- copy(buf[4:], p.Value)
- } else {
- buf[2] = byte(p.Length)
- copy(buf[3:], p.Value)
- }
- return buf, nil
-}
-
-func (p *PathAttribute) String() string {
- return fmt.Sprintf("%s %s %s", p.Type.String(), p.Flags, []byte(p.Value))
-}
-
-func (p *PathAttribute) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value []byte `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Value,
- })
-}
-
-type PathAttributeOrigin struct {
- PathAttribute
-}
-
-func (p *PathAttributeOrigin) String() string {
- typ := "-"
- switch p.Value[0] {
- 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[0],
- })
-}
-
-func NewPathAttributeOrigin(value uint8) *PathAttributeOrigin {
- t := BGP_ATTR_TYPE_ORIGIN
- return &PathAttributeOrigin{
-
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- Value: []byte{byte(value)},
- },
- }
-}
-
-type AsPathParamFormat struct {
- start string
- end string
- separator string
-}
-
-var asPathParamFormatMap = map[uint8]*AsPathParamFormat{
- BGP_ASPATH_ATTR_TYPE_SET: &AsPathParamFormat{"{", "}", ","},
- BGP_ASPATH_ATTR_TYPE_SEQ: &AsPathParamFormat{"", "", " "},
- BGP_ASPATH_ATTR_TYPE_CONFED_SET: &AsPathParamFormat{"(", ")", " "},
- BGP_ASPATH_ATTR_TYPE_CONFED_SEQ: &AsPathParamFormat{"[", "]", ","},
-}
-
-type AsPathParamInterface interface {
- Serialize() ([]byte, error)
- DecodeFromBytes([]byte) error
- Len() int
- ASLen() int
- MarshalJSON() ([]byte, error)
- String() string
-}
-
-type AsPathParam struct {
- Type uint8
- Num uint8
- AS []uint16
-}
-
-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) 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 DefaultAsPath struct {
-}
-
-func (p *DefaultAsPath) isValidAspath(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 == true {
- 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")
-}
-
-type PathAttributeAsPath struct {
- DefaultAsPath
- PathAttribute
- Value []AsPathParamInterface
-}
-
-func (p *PathAttributeAsPath) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if p.PathAttribute.Length == 0 {
- // ibgp or something
- return nil
- }
- as4Bytes, err := p.DefaultAsPath.isValidAspath(p.PathAttribute.Value)
- if err != nil {
- err.(*MessageError).Data = data[:p.Len()]
- return err
- }
- v := p.PathAttribute.Value
- for len(v) > 0 {
- var tuple AsPathParamInterface
- if as4Bytes == true {
- tuple = &As4PathParam{}
- } else {
- tuple = &AsPathParam{}
- }
- err := tuple.DecodeFromBytes(v)
- if err != nil {
- return err
- }
- p.Value = append(p.Value, tuple)
- if tuple.Len() > len(v) {
-
- }
- v = v[tuple.Len():]
- }
- return nil
-}
-
-func (p *PathAttributeAsPath) Serialize() ([]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...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 {
- t := BGP_ATTR_TYPE_AS_PATH
- return &PathAttributeAsPath{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Value: value,
- }
-}
-
-type PathAttributeNextHop struct {
- PathAttribute
- Value net.IP
-}
-
-func (p *PathAttributeNextHop) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) != 4 && len(p.PathAttribute.Value) != 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 = p.PathAttribute.Value
- return nil
-}
-
-func (p *PathAttributeNextHop) Serialize() ([]byte, error) {
- p.PathAttribute.Value = p.Value
- return p.PathAttribute.Serialize()
-}
-
-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,
- },
- Value: net.ParseIP(value).To4(),
- }
-}
-
-type PathAttributeMultiExitDisc struct {
- PathAttribute
- Value uint32
-}
-
-func (p *PathAttributeMultiExitDisc) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) != 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(p.PathAttribute.Value)
- return nil
-}
-
-func (p *PathAttributeMultiExitDisc) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, p.Value)
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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,
- },
- Value: value,
- }
-}
-
-type PathAttributeLocalPref struct {
- PathAttribute
- Value uint32
-}
-
-func (p *PathAttributeLocalPref) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) != 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(p.PathAttribute.Value)
- return nil
-}
-
-func (p *PathAttributeLocalPref) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, p.Value)
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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,
- },
- Value: value,
- }
-}
-
-type PathAttributeAtomicAggregate struct {
- PathAttribute
-}
-
-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,
- },
- }
-}
-
-type PathAttributeAggregatorParam struct {
- AS uint32
- askind reflect.Kind
- Address net.IP
-}
-
-type PathAttributeAggregator struct {
- PathAttribute
- Value PathAttributeAggregatorParam
-}
-
-func (p *PathAttributeAggregator) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) != 6 && len(p.PathAttribute.Value) != 8 {
- 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")
- }
- if len(p.PathAttribute.Value) == 6 {
- p.Value.AS = uint32(binary.BigEndian.Uint16(p.PathAttribute.Value[0:2]))
- p.Value.Address = p.PathAttribute.Value[2:]
- p.Value.askind = reflect.Uint16
- } else {
- p.Value.AS = binary.BigEndian.Uint32(p.PathAttribute.Value[0:4])
- p.Value.Address = p.PathAttribute.Value[4:]
- p.Value.askind = reflect.Uint32
- }
- return nil
-}
-
-func (p *PathAttributeAggregator) Serialize() ([]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)
- }
-
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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)
- t := BGP_ATTR_TYPE_AGGREGATOR
- return &PathAttributeAggregator{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Value: PathAttributeAggregatorParam{
- AS: uint32(v.Uint()),
- askind: v.Kind(),
- Address: net.ParseIP(address).To4(),
- },
- }
-}
-
-type PathAttributeCommunities struct {
- PathAttribute
- Value []uint32
-}
-
-func (p *PathAttributeCommunities) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value)%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")
- }
- value := p.PathAttribute.Value
- for len(value) >= 4 {
- p.Value = append(p.Value, binary.BigEndian.Uint32(value))
- value = value[4:]
- }
- return nil
-}
-
-func (p *PathAttributeCommunities) Serialize() ([]byte, error) {
- buf := make([]byte, len(p.Value)*4)
- for i, v := range p.Value {
- binary.BigEndian.PutUint32(buf[i*4:], v)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-type WellKnownCommunity uint32
-
-const (
- COMMUNITY_INTERNET WellKnownCommunity = 0x00000000
- COMMUNITY_PLANNED_SHUT = 0xffff0000
- COMMUNITY_ACCEPT_OWN = 0xffff0001
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v4 = 0xffff0002
- COMMUNITY_ROUTE_FILTER_v4 = 0xffff0003
- COMMUNITY_ROUTE_FILTER_TRANSLATED_v6 = 0xffff0004
- COMMUNITY_ROUTE_FILTER_v6 = 0xffff0005
- COMMUNITY_LLGR_STALE = 0xffff0006
- COMMUNITY_NO_LLGR = 0xffff0007
- COMMUNITY_NO_EXPORT = 0xffffff01
- COMMUNITY_NO_ADVERTISE = 0xffffff02
- COMMUNITY_NO_EXPORT_SUBCONFED = 0xffffff03
- COMMUNITY_NO_PEER = 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_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_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 {
- t := BGP_ATTR_TYPE_COMMUNITIES
- return &PathAttributeCommunities{
- PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- Length: 0,
- Value: nil},
- value,
- }
-}
-
-type PathAttributeOriginatorId struct {
- PathAttribute
- Value net.IP
-}
-
-func (p *PathAttributeOriginatorId) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) != 4 && len(p.PathAttribute.Value) != 16 {
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
- return NewMessageError(eCode, eSubCode, nil, "originatorid length isn't correct")
- }
- p.Value = p.PathAttribute.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() ([]byte, error) {
- buf := make([]byte, 4)
- copy(buf, p.Value)
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-func NewPathAttributeOriginatorId(value string) *PathAttributeOriginatorId {
- t := BGP_ATTR_TYPE_ORIGINATOR_ID
- return &PathAttributeOriginatorId{
- PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- Length: 0,
- Value: nil},
- net.ParseIP(value).To4(),
- }
-}
-
-type PathAttributeClusterList struct {
- PathAttribute
- Value []net.IP
-}
-
-func (p *PathAttributeClusterList) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- value := p.PathAttribute.Value
- if len(p.PathAttribute.Value)%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() ([]byte, error) {
- buf := make([]byte, len(p.Value)*4)
- for i, v := range p.Value {
- copy(buf[i*4:], v)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 := make([]net.IP, len(value))
- for i, v := range value {
- l[i] = net.ParseIP(v).To4()
- }
- t := BGP_ATTR_TYPE_CLUSTER_LIST
- return &PathAttributeClusterList{
- PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- Length: 0,
- Value: nil},
- l,
- }
-}
-
-type PathAttributeMpReachNLRI struct {
- PathAttribute
- Nexthop net.IP
- LinkLocalNexthop net.IP
- AFI uint16
- SAFI uint8
- Value []AddrPrefixInterface
-}
-
-func (p *PathAttributeMpReachNLRI) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
-
- value := p.PathAttribute.Value
- if len(value) < 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_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error())
- }
- nexthopLen := value[3]
- if len(value) < 4+int(nexthopLen) {
- return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is short")
- }
- nexthopbin := value[4 : 4+nexthopLen]
- value = value[4+nexthopLen:]
- if nexthopLen > 0 {
- offset := 0
- if safi == SAFI_MPLS_VPN {
- offset = 8
- }
- addrlen := 4
- hasLinkLocal := false
-
- if afi == AFI_IP6 {
- addrlen = 16
- hasLinkLocal = len(nexthopbin) == offset+2*addrlen
- }
-
- isValid := len(nexthopbin) == offset+addrlen || hasLinkLocal
-
- if !isValid {
- return NewMessageError(eCode, eSubCode, value, "mpreach nexthop length is incorrect")
- }
- p.Nexthop = nexthopbin[offset : +offset+addrlen]
- if hasLinkLocal {
- p.LinkLocalNexthop = nexthopbin[offset+addrlen : offset+2*addrlen]
- }
- }
- // skip reserved
- if len(value) == 0 {
- return NewMessageError(eCode, eSubCode, value, "no skip byte")
- }
- value = value[1:]
- for len(value) > 0 {
- prefix, err := NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error())
- }
- err = prefix.DecodeFromBytes(value)
- if err != nil {
- return err
- }
- if prefix.Len() > len(value) {
- return NewMessageError(eCode, eSubCode, value, "prefix length is incorrect")
- }
- value = value[prefix.Len():]
- p.Value = append(p.Value, prefix)
- }
- return nil
-}
-
-func (p *PathAttributeMpReachNLRI) Serialize() ([]byte, error) {
- afi := p.AFI
- safi := p.SAFI
- nexthoplen := 4
- if afi == AFI_IP6 {
- nexthoplen = 16
- if p.LinkLocalNexthop != nil {
- nexthoplen += 16
- }
- }
- offset := 0
- switch safi {
- case SAFI_MPLS_VPN:
- offset = 8
- nexthoplen += 8
- case SAFI_FLOW_SPEC_VPN, SAFI_FLOW_SPEC_UNICAST:
- nexthoplen = 0
- }
- buf := make([]byte, 4+nexthoplen)
- binary.BigEndian.PutUint16(buf[0:], afi)
- buf[2] = safi
- buf[3] = uint8(nexthoplen)
- copy(buf[4+offset:], p.Nexthop)
- if p.LinkLocalNexthop != nil {
- copy(buf[4+offset+len(p.Nexthop):], p.LinkLocalNexthop)
- }
- buf = append(buf, make([]byte, 1)...)
- for _, prefix := range p.Value {
- pbuf, err := prefix.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 NewPathAttributeMpReachNLRI(nexthop string, nlri []AddrPrefixInterface) *PathAttributeMpReachNLRI {
- t := BGP_ATTR_TYPE_MP_REACH_NLRI
- ip := net.ParseIP(nexthop)
- if ip.To4() != nil {
- ip = ip.To4()
- }
- p := &PathAttributeMpReachNLRI{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Nexthop: ip,
- Value: nlri,
- }
- if len(nlri) > 0 {
- p.AFI = nlri[0].AFI()
- p.SAFI = nlri[0].SAFI()
- }
- return p
-}
-
-type PathAttributeMpUnreachNLRI struct {
- PathAttribute
- AFI uint16
- SAFI uint8
- Value []AddrPrefixInterface
-}
-
-func (p *PathAttributeMpUnreachNLRI) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR)
-
- value := p.PathAttribute.Value
- if len(value) < 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_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error())
- }
- value = value[3:]
- p.AFI = afi
- p.SAFI = safi
- for len(value) > 0 {
- prefix, err := NewPrefixFromRouteFamily(afi, safi)
- if err != nil {
- return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_FLAGS_ERROR, data[:p.PathAttribute.Len()], err.Error())
- }
- err = prefix.DecodeFromBytes(value)
- if err != nil {
- return err
- }
- if prefix.Len() > len(value) {
- return NewMessageError(eCode, eSubCode, data[:p.PathAttribute.Len()], "prefix length is incorrect")
- }
- value = value[prefix.Len():]
- p.Value = append(p.Value, prefix)
- }
- return nil
-}
-
-func (p *PathAttributeMpUnreachNLRI) Serialize() ([]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()
- if err != nil {
- return nil, err
- }
- buf = append(buf, pbuf...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-func NewPathAttributeMpUnreachNLRI(nlri []AddrPrefixInterface) *PathAttributeMpUnreachNLRI {
- t := BGP_ATTR_TYPE_MP_UNREACH_NLRI
- p := &PathAttributeMpUnreachNLRI{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- Length: 0,
- },
- Value: nlri,
- }
- if len(nlri) > 0 {
- p.AFI = nlri[0].AFI()
- p.SAFI = nlri[0].SAFI()
- }
- return p
-}
-
-type ExtendedCommunityInterface interface {
- Serialize() ([]byte, error)
- String() string
- GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType)
- MarshalJSON() ([]byte, error)
-}
-
-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 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 value ValidationState
- switch com {
- case VALIDATION_STATE_VALID.String():
- value = VALIDATION_STATE_VALID
- case VALIDATION_STATE_NOT_FOUND.String():
- value = VALIDATION_STATE_NOT_FOUND
- case VALIDATION_STATE_INVALID.String():
- value = VALIDATION_STATE_INVALID
- default:
- return nil, fmt.Errorf("invalid validation state")
- }
- return &OpaqueExtended{
- SubType: EC_SUBTYPE_ORIGIN_VALIDATION,
- Value: &ValidationExtended{
- Value: value,
- },
- }, nil
- }
- elems, err := parseRdAndRt(com)
- if err != nil {
- return nil, err
- }
- localAdmin, _ := strconv.Atoi(elems[9])
- ip := net.ParseIP(elems[1])
- isTransitive := true
- switch {
- case ip.To4() != nil:
- return NewIPv4AddressSpecificExtended(subtype, elems[1], uint16(localAdmin), isTransitive), nil
- case elems[6] == "" && elems[7] == "":
- asn, _ := strconv.Atoi(elems[8])
- return NewTwoOctetAsSpecificExtended(subtype, uint16(asn), uint32(localAdmin), isTransitive), nil
- default:
- fst, _ := strconv.Atoi(elems[7])
- snd, _ := strconv.Atoi(elems[8])
- 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)
-}
-
-type OpaqueExtendedValueInterface interface {
- Serialize() ([]byte, error)
- String() string
-}
-
-type DefaultOpaqueExtendedValue struct {
- Value []byte
-}
-
-func (v *DefaultOpaqueExtendedValue) Serialize() ([]byte, error) {
- v.Value = v.Value[:7]
- return v.Value[:7], nil
-}
-
-func (v *DefaultOpaqueExtendedValue) String() string {
- buf := make([]byte, 8)
- copy(buf[1:], v.Value)
- d := binary.BigEndian.Uint64(buf)
- return fmt.Sprintf("%d", d)
-}
-
-type ValidationState uint8
-
-const (
- 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 validatation state(%d)", s)
-}
-
-type ValidationExtended struct {
- Value ValidationState
-}
-
-func (e *ValidationExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 7)
- buf[0] = byte(EC_SUBTYPE_ORIGIN_VALIDATION)
- buf[6] = byte(e.Value)
- return buf, nil
-}
-
-func (e *ValidationExtended) String() string {
- return e.Value.String()
-}
-
-type ColorExtended struct {
- Value uint32
-}
-
-func (e *ColorExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 7)
- buf[0] = byte(EC_SUBTYPE_COLOR)
- binary.BigEndian.PutUint32(buf[3:], uint32(e.Value))
- return buf, nil
-}
-
-func (e *ColorExtended) String() string {
- return fmt.Sprintf("%d", e.Value)
-}
-
-type EncapExtended struct {
- TunnelType TunnelType
-}
-
-func (e *EncapExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 7)
- buf[0] = byte(EC_SUBTYPE_ENCAPSULATION)
- binary.BigEndian.PutUint16(buf[5:], 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"
- default:
- return fmt.Sprintf("tunnel: %d", e.TunnelType)
- }
-}
-
-type OpaqueExtended struct {
- IsTransitive bool
- Value OpaqueExtendedValueInterface
- SubType ExtendedCommunityAttrSubType
-}
-
-func (e *OpaqueExtended) DecodeFromBytes(data []byte) error {
- if len(data) != 7 {
- return fmt.Errorf("Invalid OpaqueExtended bytes len: %d", len(data))
- }
- e.SubType = ExtendedCommunityAttrSubType(data[0])
-
- if e.IsTransitive {
- switch e.SubType {
- case EC_SUBTYPE_COLOR:
- v := binary.BigEndian.Uint32(data[3:7])
- e.Value = &ColorExtended{
- Value: v,
- }
- case EC_SUBTYPE_ENCAPSULATION:
- t := TunnelType(binary.BigEndian.Uint16(data[5:7]))
- e.Value = &EncapExtended{
- TunnelType: t,
- }
- default:
- e.Value = &DefaultOpaqueExtendedValue{
- Value: data, //7byte
- }
- }
- } else {
- switch e.SubType {
- case EC_SUBTYPE_ORIGIN_VALIDATION:
- e.Value = &ValidationExtended{
- Value: ValidationState(data[6]),
- }
- default:
- e.Value = &DefaultOpaqueExtendedValue{
- Value: data, //7byte
- }
- }
- }
- return nil
-}
-
-func (e *OpaqueExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 1, 7)
- if e.IsTransitive {
- buf[0] = byte(EC_TYPE_TRANSITIVE_OPAQUE)
- } else {
- buf[0] = byte(EC_TYPE_NON_TRANSITIVE_OPAQUE)
- }
- bbuf, err := e.Value.Serialize()
- e.SubType = ExtendedCommunityAttrSubType(bbuf[0])
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- return buf, nil
-}
-
-func (e *OpaqueExtended) String() string {
- return e.Value.String()
-}
-
-func (e *OpaqueExtended) MarshalJSON() ([]byte, error) {
- t, s := e.GetTypes()
- return json.Marshal(struct {
- Type ExtendedCommunityAttrType `json:"type"`
- Subtype ExtendedCommunityAttrSubType `json:"subtype"`
- Value OpaqueExtendedValueInterface `json:"value"`
- }{
- Type: t,
- Subtype: s,
- Value: e.Value,
- })
-}
-
-func (e *OpaqueExtended) GetTypes() (ExtendedCommunityAttrType, ExtendedCommunityAttrSubType) {
- t := EC_TYPE_TRANSITIVE_OPAQUE
- if !e.IsTransitive {
- t = EC_TYPE_NON_TRANSITIVE_OPAQUE
- }
- return t, e.SubType
-}
-
-func NewOpaqueExtended(isTransitive bool) *OpaqueExtended {
- return &OpaqueExtended{
- IsTransitive: isTransitive,
- }
-}
-
-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,
- }
-}
-
-func parseEvpnExtended(data []byte) (ExtendedCommunityInterface, error) {
- if ExtendedCommunityAttrType(data[0]) != EC_TYPE_EVPN {
- return nil, fmt.Errorf("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
- }
- return nil, fmt.Errorf("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, 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, 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 {
- return &RedirectIPv4AddressSpecificExtended{*NewIPv4AddressSpecificExtended(EC_SUBTYPE_ROUTE_TARGET, ipv4, localAdmin, false)}
-}
-
-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}
-}
-
-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, fmt.Errorf("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:
- //draft-ietf-idr-flowspec-redirect-rt-bis-05
- 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
- }
- return &UnknownExtended{
- Type: ExtendedCommunityAttrType(data[0]),
- Value: data[1:8],
- }, nil
-}
-
-type UnknownExtended struct {
- Type ExtendedCommunityAttrType
- Value []byte
-}
-
-func (e *UnknownExtended) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- buf[0] = uint8(e.Type)
- copy(buf[1:], e.Value)
- e.Value = buf[1:]
- return buf, nil
-}
-
-func (e *UnknownExtended) String() string {
- buf := make([]byte, 8)
- copy(buf[1:], e.Value)
- v := binary.BigEndian.Uint64(buf)
- return fmt.Sprintf("%d", v)
-}
-
-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) {
- return ExtendedCommunityAttrType(0xFF), ExtendedCommunityAttrSubType(0xFF)
-}
-
-type PathAttributeExtendedCommunities struct {
- PathAttribute
- Value []ExtendedCommunityInterface
-}
-
-func ParseExtended(data []byte) (ExtendedCommunityInterface, error) {
- if len(data) < 8 {
- return nil, fmt.Errorf("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:
- e := NewOpaqueExtended(transitive)
- err := e.DecodeFromBytes(data[1:8])
- return e, err
- 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) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value)%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")
- }
- value := p.PathAttribute.Value
- 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() ([]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...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 {
- t := BGP_ATTR_TYPE_EXTENDED_COMMUNITIES
- return &PathAttributeExtendedCommunities{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Value: value,
- }
-}
-
-type PathAttributeAs4Path struct {
- PathAttribute
- Value []*As4PathParam
- DefaultAsPath
-}
-
-func (p *PathAttributeAs4Path) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- v := p.PathAttribute.Value
- as4Bytes, err := p.DefaultAsPath.isValidAspath(p.PathAttribute.Value)
- if err != nil {
- return err
- }
- if as4Bytes == false {
- return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed")
- }
- for len(v) > 0 {
- tuple := &As4PathParam{}
- tuple.DecodeFromBytes(v)
- p.Value = append(p.Value, tuple)
- if len(v) < tuple.Len() {
- return NewMessageError(eCode, eSubCode, nil, "AS4 PATH param is malformed")
- }
- v = v[tuple.Len():]
- }
- return nil
-}
-
-func (p *PathAttributeAs4Path) Serialize() ([]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...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 NewPathAttributeAs4Path(value []*As4PathParam) *PathAttributeAs4Path {
- t := BGP_ATTR_TYPE_AS4_PATH
- return &PathAttributeAs4Path{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Value: value,
- }
-}
-
-type PathAttributeAs4Aggregator struct {
- PathAttribute
- Value PathAttributeAggregatorParam
-}
-
-func (p *PathAttributeAs4Aggregator) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) != 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(p.PathAttribute.Value[0:4])
- p.Value.Address = p.PathAttribute.Value[4:]
- return nil
-}
-
-func (p *PathAttributeAs4Aggregator) Serialize() ([]byte, error) {
- buf := make([]byte, 8)
- binary.BigEndian.PutUint32(buf[0:], p.Value.AS)
- copy(buf[4:], p.Value.Address.To4())
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-func NewPathAttributeAs4Aggregator(as uint32, address string) *PathAttributeAs4Aggregator {
- t := BGP_ATTR_TYPE_AS4_AGGREGATOR
- return &PathAttributeAs4Aggregator{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Value: PathAttributeAggregatorParam{
- AS: as,
- Address: net.ParseIP(address).To4(),
- },
- }
-}
-
-type TunnelEncapSubTLVValue interface {
- Serialize() ([]byte, error)
-}
-
-type TunnelEncapSubTLVDefault struct {
- Value []byte
-}
-
-func (t *TunnelEncapSubTLVDefault) Serialize() ([]byte, error) {
- return t.Value, nil
-}
-
-type TunnelEncapSubTLVEncapuslation struct {
- Key uint32 // this represent both SessionID for L2TPv3 case and GRE-key for GRE case (RFC5512 4.)
- Cookie []byte
-}
-
-func (t *TunnelEncapSubTLVEncapuslation) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- binary.BigEndian.PutUint32(buf, t.Key)
- return append(buf, t.Cookie...), nil
-}
-
-type TunnelEncapSubTLVProtocol struct {
- Protocol uint16
-}
-
-func (t *TunnelEncapSubTLVProtocol) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- binary.BigEndian.PutUint16(buf, t.Protocol)
- return buf, nil
-}
-
-type TunnelEncapSubTLVColor struct {
- Color uint32
-}
-
-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:], t.Color)
- return buf, nil
-}
-
-type TunnelEncapSubTLV struct {
- Type EncapSubTLVType
- Len int
- Value TunnelEncapSubTLVValue
-}
-
-func (p *TunnelEncapSubTLV) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- bbuf, err := p.Value.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- buf[0] = byte(p.Type)
- p.Len = len(buf) - 2
- buf[1] = byte(p.Len)
- return buf, nil
-}
-
-func (p *TunnelEncapSubTLV) DecodeFromBytes(data []byte) error {
- switch p.Type {
- case ENCAP_SUBTLV_TYPE_ENCAPSULATION:
- if len(data) < 4 {
- return fmt.Errorf("Not all TunnelEncapSubTLV bytes available")
- }
- key := binary.BigEndian.Uint32(data[:4])
- p.Value = &TunnelEncapSubTLVEncapuslation{
- Key: key,
- Cookie: data[4:],
- }
- case ENCAP_SUBTLV_TYPE_PROTOCOL:
- if len(data) < 2 {
- return fmt.Errorf("Not all TunnelEncapSubTLV bytes available")
- }
- protocol := binary.BigEndian.Uint16(data[:2])
- p.Value = &TunnelEncapSubTLVProtocol{protocol}
- case ENCAP_SUBTLV_TYPE_COLOR:
- if len(data) < 8 {
- return fmt.Errorf("Not all TunnelEncapSubTLV bytes available")
- }
- color := binary.BigEndian.Uint32(data[4:])
- p.Value = &TunnelEncapSubTLVColor{color}
- default:
- p.Value = &TunnelEncapSubTLVDefault{data}
- }
- return nil
-}
-
-type TunnelEncapTLV struct {
- Type TunnelType
- Len int
- Value []*TunnelEncapSubTLV
-}
-
-func (t *TunnelEncapTLV) DecodeFromBytes(data []byte) error {
- curr := 0
- for {
- if len(data) < curr+2 {
- break
- }
- subType := EncapSubTLVType(data[curr])
- l := int(data[curr+1])
- if len(data) < curr+2+l {
- return fmt.Errorf("Not all TunnelEncapSubTLV bytes available")
- }
- v := data[curr+2 : curr+2+l]
- subTlv := &TunnelEncapSubTLV{
- Type: subType,
- }
- err := subTlv.DecodeFromBytes(v)
- if err != nil {
- return err
- }
- t.Value = append(t.Value, subTlv)
- curr += 2 + l
- }
- return nil
-}
-
-func (p *TunnelEncapTLV) Serialize() ([]byte, error) {
- buf := make([]byte, 4)
- for _, s := range p.Value {
- bbuf, err := s.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, bbuf...)
- }
- binary.BigEndian.PutUint16(buf, uint16(p.Type))
- p.Len = len(buf) - 4
- binary.BigEndian.PutUint16(buf[2:], uint16(p.Len))
- return buf, nil
-}
-
-type PathAttributeTunnelEncap struct {
- PathAttribute
- Value []*TunnelEncapTLV
-}
-
-func (p *PathAttributeTunnelEncap) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- curr := 0
- for {
- if len(p.PathAttribute.Value) < curr+4 {
- break
- }
- t := binary.BigEndian.Uint16(p.PathAttribute.Value[curr : curr+2])
- tunnelType := TunnelType(t)
- l := int(binary.BigEndian.Uint16(p.PathAttribute.Value[curr+2 : curr+4]))
- if len(p.PathAttribute.Value) < curr+4+l {
- return fmt.Errorf("Not all TunnelEncapTLV bytes available. %d < %d", len(p.PathAttribute.Value), curr+4+l)
- }
- v := p.PathAttribute.Value[curr+4 : curr+4+l]
- tlv := &TunnelEncapTLV{
- Type: tunnelType,
- Len: l,
- }
- err = tlv.DecodeFromBytes(v)
- if err != nil {
- return err
- }
- p.Value = append(p.Value, tlv)
- curr += 4 + l
- }
- return nil
-}
-
-func (p *PathAttributeTunnelEncap) Serialize() ([]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...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-func NewPathAttributeTunnelEncap(value []*TunnelEncapTLV) *PathAttributeTunnelEncap {
- t := BGP_ATTR_TYPE_TUNNEL_ENCAP
- return &PathAttributeTunnelEncap{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Value: value,
- }
-}
-
-type PmsiTunnelIDInterface interface {
- Serialize() ([]byte, error)
- String() string
-}
-
-type DefaultPmsiTunnelID struct {
- Value []byte
-}
-
-func (i *DefaultPmsiTunnelID) Serialize() ([]byte, error) {
- return i.Value, nil
-}
-
-func (i *DefaultPmsiTunnelID) String() string {
- return string(i.Value)
-}
-
-type IngressReplTunnelID struct {
- Value net.IP
-}
-
-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()
-}
-
-type PathAttributePmsiTunnel struct {
- PathAttribute
- IsLeafInfoRequired bool
- TunnelType PmsiTunnelType
- Label uint32
- TunnelID PmsiTunnelIDInterface
-}
-
-func (p *PathAttributePmsiTunnel) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- if len(p.PathAttribute.Value) < 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 (p.PathAttribute.Value[0] & 0x01) > 0 {
- p.IsLeafInfoRequired = true
- }
- p.TunnelType = PmsiTunnelType(p.PathAttribute.Value[1])
- p.Label = labelDecode(p.PathAttribute.Value[2:5])
-
- switch p.TunnelType {
- case PMSI_TUNNEL_TYPE_INGRESS_REPL:
- p.TunnelID = &IngressReplTunnelID{net.IP(p.PathAttribute.Value[5:])}
- default:
- p.TunnelID = &DefaultPmsiTunnelID{p.PathAttribute.Value[5:]}
- }
- return nil
-}
-
-func (p *PathAttributePmsiTunnel) Serialize() ([]byte, error) {
- buf := make([]byte, 2)
- if p.IsLeafInfoRequired {
- buf[0] = 0x01
- }
- buf[1] = byte(p.TunnelType)
- lbuf := make([]byte, 3)
- labelSerialize(p.Label, lbuf)
- buf = append(buf, lbuf...)
- ibuf, err := p.TunnelID.Serialize()
- if err != nil {
- return nil, err
- }
- buf = append(buf, ibuf...)
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 {
- t := BGP_ATTR_TYPE_PMSI_TUNNEL
- return &PathAttributePmsiTunnel{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- IsLeafInfoRequired: isLeafInfoRequired,
- TunnelType: typ,
- Label: label,
- TunnelID: id,
- }
-}
-
-type AigpTLVType uint8
-
-const (
- AIGP_TLV_UNKNOWN AigpTLVType = iota
- AIGP_TLV_IGP_METRIC
-)
-
-type AigpTLV interface {
- Serialize() ([]byte, error)
- String() string
- MarshalJSON() ([]byte, error)
- Type() AigpTLVType
-}
-
-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
-}
-
-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
-}
-
-type PathAttributeAigp struct {
- PathAttribute
- Values []AigpTLV
-}
-
-func (p *PathAttributeAigp) DecodeFromBytes(data []byte) error {
- err := p.PathAttribute.DecodeFromBytes(data)
- if err != nil {
- return err
- }
-
- rest := p.PathAttribute.Value
- values := make([]AigpTLV, 0)
-
- for {
- if len(rest) < 3 {
- break
- }
- typ := rest[0]
- length := binary.BigEndian.Uint16(rest[1:3])
- if len(rest) < int(length) {
- break
- }
- v := rest[3:length]
- switch AigpTLVType(typ) {
- case AIGP_TLV_IGP_METRIC:
- if len(v) < 8 {
- break
- }
- metric := binary.BigEndian.Uint64(v)
- values = append(values, NewAigpTLVIgpMetric(metric))
- default:
- values = append(values, &AigpTLVDefault{AigpTLVType(typ), v})
- }
- rest = rest[length:]
- if len(rest) == 0 {
- p.Values = values
- return nil
- }
- }
- eCode := uint8(BGP_ERROR_UPDATE_MESSAGE_ERROR)
- eSubCode := uint8(BGP_ERROR_SUB_MALFORMED_ATTRIBUTE_LIST)
- return NewMessageError(eCode, eSubCode, nil, "Aigp length is incorrect")
-}
-
-func (p *PathAttributeAigp) Serialize() ([]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...)
- }
- p.PathAttribute.Value = buf
- return p.PathAttribute.Serialize()
-}
-
-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 []AigpTLV `json:"value"`
- }{
- Type: p.GetType(),
- Value: p.Values,
- })
-}
-
-func NewPathAttributeAigp(values []AigpTLV) *PathAttributeAigp {
- t := BGP_ATTR_TYPE_AIGP
- return &PathAttributeAigp{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- },
- Values: values,
- }
-}
-
-type PathAttributeOpaqueValue struct {
- PathAttribute
-}
-
-func (p *PathAttributeOpaqueValue) String() string {
- return fmt.Sprintf("{Value: %s}", string(p.Value))
-}
-
-func (p *PathAttributeOpaqueValue) MarshalJSON() ([]byte, error) {
- return json.Marshal(struct {
- Type BGPAttrType `json:"type"`
- Value string `json:"value"`
- }{
- Type: p.GetType(),
- Value: string(p.Value),
- })
-}
-
-func NewPathAttributeOpaqueValue(value []byte) *PathAttributeOpaqueValue {
- t := BGP_ATTR_TYPE_OPAQUE_VALUE
- return &PathAttributeOpaqueValue{
- PathAttribute: PathAttribute{
- Flags: pathAttrFlags[t],
- Type: t,
- Value: value,
- },
- }
-}
-
-type PathAttributeUnknown struct {
- PathAttribute
-}
-
-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_AIGP:
- return &PathAttributeAigp{}, nil
- case BGP_ATTR_TYPE_OPAQUE_VALUE:
- return &PathAttributeOpaqueValue{}, nil
- }
- return &PathAttributeUnknown{}, nil
-}
-
-type BGPUpdate struct {
- WithdrawnRoutesLen uint16
- WithdrawnRoutes []*IPAddrPrefix
- TotalPathAttributeLen uint16
- PathAttributes []PathAttributeInterface
- NLRI []*IPAddrPrefix
-}
-
-func (msg *BGPUpdate) DecodeFromBytes(data []byte) 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")
- }
-
- msg.WithdrawnRoutes = make([]*IPAddrPrefix, 0, msg.WithdrawnRoutesLen)
- for routelen := msg.WithdrawnRoutesLen; routelen > 0; {
- w := &IPAddrPrefix{}
- err := w.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- routelen -= uint16(w.Len())
- if len(data) < w.Len() {
- return NewMessageError(eCode, eSubCode, nil, "Withdrawn route length is short")
- }
- data = data[w.Len():]
- 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; {
- p, err := GetPathAttribute(data)
- if err != nil {
- return err
- }
- err = p.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- pathlen -= uint16(p.Len())
- if len(data) < p.Len() {
- return NewMessageError(eCode, BGP_ERROR_SUB_ATTRIBUTE_LENGTH_ERROR, data, "attribute length is short")
- }
- data = data[p.Len():]
- msg.PathAttributes = append(msg.PathAttributes, p)
- }
-
- msg.NLRI = make([]*IPAddrPrefix, 0)
- for restlen := len(data); restlen > 0; {
- n := &IPAddrPrefix{}
- err := n.DecodeFromBytes(data)
- if err != nil {
- return err
- }
- restlen -= n.Len()
- if len(data) < n.Len() {
- return NewMessageError(eCode, BGP_ERROR_SUB_INVALID_NETWORK_FIELD, nil, "NLRI length is short")
- }
- data = data[n.Len():]
- msg.NLRI = append(msg.NLRI, n)
- }
-
- return nil
-}
-
-func (msg *BGPUpdate) Serialize() ([]byte, error) {
- wbuf := make([]byte, 2)
- for _, w := range msg.WithdrawnRoutes {
- onewbuf, err := w.Serialize()
- 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()
- 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()
- 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)
- return true, AfiSafiToRouteFamily(unreach.AFI, unreach.SAFI)
- }
- }
- return false, RouteFamily(0)
-}
-
-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)
- unreach := &PathAttributeMpUnreachNLRI{
- 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) error {
- if len(data) < 2 {
- return fmt.Errorf("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() ([]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) error {
- return nil
-}
-
-func (msg *BGPKeepAlive) Serialize() ([]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) error {
- if len(data) < 4 {
- return fmt.Errorf("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() ([]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) error
- Serialize() ([]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) error {
- // minimum BGP message length
- if uint16(len(data)) < BGP_HEADER_LENGTH {
- return fmt.Errorf("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() ([]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) (*BGPMessage, error) {
- if len(data) < int(h.Len)-BGP_HEADER_LENGTH {
- return nil, fmt.Errorf("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)
- if err != nil {
- return nil, err
- }
- return msg, nil
-}
-
-func ParseBGPMessage(data []byte) (*BGPMessage, error) {
- h := &BGPHeader{}
- err := h.DecodeFromBytes(data)
- if err != nil {
- return nil, err
- }
- return parseBody(h, data[19:h.Len])
-}
-
-func ParseBGPBody(h *BGPHeader, data []byte) (*BGPMessage, error) {
- return parseBody(h, data)
-}
-
-func (msg *BGPMessage) Serialize() ([]byte, error) {
- b, err := msg.Body.Serialize()
- 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()
- if err != nil {
- return nil, err
- }
- return append(h, b...), nil
-}