From 311324fab8bf7d9e39365d53f7e810af90476d85 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 31 Mar 2016 13:19:17 +0900 Subject: move packet/*.go to packet/bgp/*.go for Go's convention Later, we move non-bgp protocol stuff like mrt under their own direcotries. Signed-off-by: FUJITA Tomonori --- packet/bgp.go | 6785 --------------------------------------------------------- 1 file changed, 6785 deletions(-) delete mode 100644 packet/bgp.go (limited to 'packet/bgp.go') 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 -// -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< 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 -} -- cgit v1.2.3