// 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
	EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2      ExtendedCommunityAttrType = 0x81 // RFC7674
	EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3      ExtendedCommunityAttrType = 0x82 // RFC7674
)

// 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]
		if rest < paramlen+2 {
			return fmt.Errorf("Malformed BGP Open message")
		}
		rest -= paramlen + 2

		if paramtype == BGP_OPT_CAPABILITY {
			p := &OptionParameterCapability{}
			p.ParamType = paramtype
			p.ParamLen = paramlen
			p.DecodeFromBytes(data[2 : 2+paramlen])
			msg.OptParams = append(msg.OptParams, p)
		} else {
			p := &OptionParameterUnknown{}
			p.ParamType = paramtype
			p.ParamLen = paramlen
			p.Value = data[2 : 2+paramlen]
			msg.OptParams = append(msg.OptParams, p)
		}
		data = data[2+paramlen:]
	}
	return nil
}

func (msg *BGPOpen) Serialize() ([]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
	addrlen uint8
}

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]
	if n.addrlen == 0 {
		n.addrlen = 4
	}
	return n.decodePrefix(data[1:], n.Length, n.addrlen)
}

func (n *EncapNLRI) Serialize() ([]byte, error) {
	buf := make([]byte, 1)
	buf[0] = n.Length
	pbuf, err := n.serializePrefix(n.Length)
	if err != nil {
		return nil, err
	}
	return append(buf, pbuf...), nil
}

func (n *EncapNLRI) String() string {
	return n.Prefix.String()
}

func (n *EncapNLRI) AFI() uint16 {
	return AFI_IP
}

func (n *EncapNLRI) SAFI() uint8 {
	return SAFI_ENCAPSULATION
}

func NewEncapNLRI(endpoint string) *EncapNLRI {
	return &EncapNLRI{
		IPAddrPrefixDefault{32, net.ParseIP(endpoint).To4()},
		4,
	}
}

type Encapv6NLRI struct {
	EncapNLRI
}

func (n *Encapv6NLRI) AFI() uint16 {
	return AFI_IP6
}

func NewEncapv6NLRI(endpoint string) *Encapv6NLRI {
	return &Encapv6NLRI{
		EncapNLRI{
			IPAddrPrefixDefault{128, net.ParseIP(endpoint)},
			16,
		},
	}
}

type BGPFlowSpecType uint8

const (
	FLOW_SPEC_TYPE_UNKNOWN BGPFlowSpecType = iota
	FLOW_SPEC_TYPE_DST_PREFIX
	FLOW_SPEC_TYPE_SRC_PREFIX
	FLOW_SPEC_TYPE_IP_PROTO
	FLOW_SPEC_TYPE_PORT
	FLOW_SPEC_TYPE_DST_PORT
	FLOW_SPEC_TYPE_SRC_PORT
	FLOW_SPEC_TYPE_ICMP_TYPE
	FLOW_SPEC_TYPE_ICMP_CODE
	FLOW_SPEC_TYPE_TCP_FLAG
	FLOW_SPEC_TYPE_PKT_LEN
	FLOW_SPEC_TYPE_DSCP
	FLOW_SPEC_TYPE_FRAGMENT
	FLOW_SPEC_TYPE_LABEL
	FLOW_SPEC_TYPE_ETHERNET_TYPE // 14
	FLOW_SPEC_TYPE_SRC_MAC
	FLOW_SPEC_TYPE_DST_MAC
	FLOW_SPEC_TYPE_LLC_DSAP
	FLOW_SPEC_TYPE_LLC_SSAP
	FLOW_SPEC_TYPE_LLC_CONTROL
	FLOW_SPEC_TYPE_SNAP
	FLOW_SPEC_TYPE_VID
	FLOW_SPEC_TYPE_COS
	FLOW_SPEC_TYPE_INNER_VID
	FLOW_SPEC_TYPE_INNER_COS
)

var FlowSpecNameMap = map[BGPFlowSpecType]string{
	FLOW_SPEC_TYPE_UNKNOWN:       "unknown",
	FLOW_SPEC_TYPE_DST_PREFIX:    "destination",
	FLOW_SPEC_TYPE_SRC_PREFIX:    "source",
	FLOW_SPEC_TYPE_IP_PROTO:      "protocol",
	FLOW_SPEC_TYPE_PORT:          "port",
	FLOW_SPEC_TYPE_DST_PORT:      "destination-port",
	FLOW_SPEC_TYPE_SRC_PORT:      "source-port",
	FLOW_SPEC_TYPE_ICMP_TYPE:     "icmp-type",
	FLOW_SPEC_TYPE_ICMP_CODE:     "icmp-code",
	FLOW_SPEC_TYPE_TCP_FLAG:      "tcp-flags",
	FLOW_SPEC_TYPE_PKT_LEN:       "packet-length",
	FLOW_SPEC_TYPE_DSCP:          "dscp",
	FLOW_SPEC_TYPE_FRAGMENT:      "fragment",
	FLOW_SPEC_TYPE_LABEL:         "label",
	FLOW_SPEC_TYPE_ETHERNET_TYPE: "ether-type",
	FLOW_SPEC_TYPE_SRC_MAC:       "source-mac",
	FLOW_SPEC_TYPE_DST_MAC:       "destination-mac",
	FLOW_SPEC_TYPE_LLC_DSAP:      "llc-dsap",
	FLOW_SPEC_TYPE_LLC_SSAP:      "llc-ssap",
	FLOW_SPEC_TYPE_LLC_CONTROL:   "llc-control",
	FLOW_SPEC_TYPE_SNAP:          "snap",
	FLOW_SPEC_TYPE_VID:           "vid",
	FLOW_SPEC_TYPE_COS:           "cos",
	FLOW_SPEC_TYPE_INNER_VID:     "inner-vid",
	FLOW_SPEC_TYPE_INNER_COS:     "inner-cos",
}

var FlowSpecValueMap = map[string]BGPFlowSpecType{
	FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]:    FLOW_SPEC_TYPE_DST_PREFIX,
	FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]:    FLOW_SPEC_TYPE_SRC_PREFIX,
	FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO]:      FLOW_SPEC_TYPE_IP_PROTO,
	FlowSpecNameMap[FLOW_SPEC_TYPE_PORT]:          FLOW_SPEC_TYPE_PORT,
	FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PORT]:      FLOW_SPEC_TYPE_DST_PORT,
	FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PORT]:      FLOW_SPEC_TYPE_SRC_PORT,
	FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_TYPE]:     FLOW_SPEC_TYPE_ICMP_TYPE,
	FlowSpecNameMap[FLOW_SPEC_TYPE_ICMP_CODE]:     FLOW_SPEC_TYPE_ICMP_CODE,
	FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG]:      FLOW_SPEC_TYPE_TCP_FLAG,
	FlowSpecNameMap[FLOW_SPEC_TYPE_PKT_LEN]:       FLOW_SPEC_TYPE_PKT_LEN,
	FlowSpecNameMap[FLOW_SPEC_TYPE_DSCP]:          FLOW_SPEC_TYPE_DSCP,
	FlowSpecNameMap[FLOW_SPEC_TYPE_FRAGMENT]:      FLOW_SPEC_TYPE_FRAGMENT,
	FlowSpecNameMap[FLOW_SPEC_TYPE_LABEL]:         FLOW_SPEC_TYPE_LABEL,
	FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE]: FLOW_SPEC_TYPE_ETHERNET_TYPE,
	FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]:       FLOW_SPEC_TYPE_SRC_MAC,
	FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]:       FLOW_SPEC_TYPE_DST_MAC,
	FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_DSAP]:      FLOW_SPEC_TYPE_LLC_DSAP,
	FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_SSAP]:      FLOW_SPEC_TYPE_LLC_SSAP,
	FlowSpecNameMap[FLOW_SPEC_TYPE_LLC_CONTROL]:   FLOW_SPEC_TYPE_LLC_CONTROL,
	FlowSpecNameMap[FLOW_SPEC_TYPE_SNAP]:          FLOW_SPEC_TYPE_SNAP,
	FlowSpecNameMap[FLOW_SPEC_TYPE_VID]:           FLOW_SPEC_TYPE_VID,
	FlowSpecNameMap[FLOW_SPEC_TYPE_COS]:           FLOW_SPEC_TYPE_COS,
	FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_VID]:     FLOW_SPEC_TYPE_INNER_VID,
	FlowSpecNameMap[FLOW_SPEC_TYPE_INNER_COS]:     FLOW_SPEC_TYPE_INNER_COS,
}

func flowSpecPrefixParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	if len(args) < 2 {
		return nil, fmt.Errorf("invalid flowspec dst/src prefix")
	}
	typ := args[0]
	ip, net, err := net.ParseCIDR(args[1])
	if err != nil {
		return nil, fmt.Errorf("invalid ip prefix")
	}
	afi, _ := RouteFamilyToAfiSafi(rf)
	if afi == AFI_IP && ip.To4() == nil {
		return nil, fmt.Errorf("invalid ipv4 prefix")
	} else if afi == AFI_IP6 && !strings.Contains(ip.String(), ":") {
		return nil, fmt.Errorf("invalid ipv6 prefix")
	}
	ones, _ := net.Mask.Size()
	var offset uint8
	if len(args) > 2 {
		o, err := strconv.Atoi(args[2])
		offset = uint8(o)
		if err != nil {
			return nil, err
		}
	}

	switch typ {
	case FlowSpecNameMap[FLOW_SPEC_TYPE_DST_PREFIX]:
		switch rf {
		case RF_FS_IPv4_UC:
			return NewFlowSpecDestinationPrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
		case RF_FS_IPv6_UC:
			return NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(uint8(ones), ip.String()), offset), nil
		default:
			return nil, fmt.Errorf("invalid type. only RF_FS_IPv4_UC or RF_FS_IPv6_UC is allowed")
		}
	case FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_PREFIX]:
		switch rf {
		case RF_FS_IPv4_UC:
			return NewFlowSpecSourcePrefix(NewIPAddrPrefix(uint8(ones), ip.String())), nil
		case RF_FS_IPv6_UC:
			return NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(uint8(ones), ip.String()), offset), nil
		default:
			return nil, fmt.Errorf("invalid type. only RF_FS_IPv4_UC or RF_FS_IPv6_UC is allowed")
		}
	}
	return nil, fmt.Errorf("invalid type. only destination or source is allowed")
}

func flowSpecIpProtoParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	ss := make([]string, 0, len(ProtocolNameMap))
	for _, v := range ProtocolNameMap {
		ss = append(ss, v)
	}
	protos := strings.Join(ss, "|")
	exp := regexp.MustCompile(fmt.Sprintf("^%s (((%s) )*)(%s)$", FlowSpecNameMap[FLOW_SPEC_TYPE_IP_PROTO], protos, protos))
	elems := exp.FindStringSubmatch(strings.Join(args, " "))
	items := make([]*FlowSpecComponentItem, 0)
	eq := 0x1
	if elems[1] != "" {
		for _, v := range strings.Split(elems[1], " ") {
			p, ok := ProtocolValueMap[v]
			if !ok {
				continue
			}
			items = append(items, NewFlowSpecComponentItem(eq, int(p)))
		}
	}
	items = append(items, NewFlowSpecComponentItem(eq, int(ProtocolValueMap[elems[4]])))
	return NewFlowSpecComponent(FLOW_SPEC_TYPE_IP_PROTO, items), nil
}

func flowSpecTcpFlagParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	ss := make([]string, 0, len(TCPFlagNameMap))
	for _, v := range TCPFlagNameMap {
		ss = append(ss, v)
	}
	protos := strings.Join(ss, "|")
	exp := regexp.MustCompile(fmt.Sprintf("^%s (not )?(match )?((((%s)\\&)*(%s) )*(((%s)\\&)*(%s)))$", FlowSpecNameMap[FLOW_SPEC_TYPE_TCP_FLAG], protos, protos, protos, protos))
	elems := exp.FindStringSubmatch(strings.Join(args, " "))
	if len(elems) < 1 {
		return nil, fmt.Errorf("invalid flag format")
	}
	items := make([]*FlowSpecComponentItem, 0)
	op := 0
	if elems[2] != "" {
		op |= 0x1
	}
	if elems[1] != "" {
		op |= 0x2
	}
	for _, v := range strings.Split(elems[3], " ") {
		flag := 0
		for _, e := range strings.Split(v, "&") {
			flag |= int(TCPFlagValueMap[e])
		}
		items = append(items, NewFlowSpecComponentItem(op, flag))
	}
	return NewFlowSpecComponent(FLOW_SPEC_TYPE_TCP_FLAG, items), nil
}

func flowSpecEtherTypeParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	ss := make([]string, 0, len(EthernetTypeNameMap))
	for _, v := range EthernetTypeNameMap {
		ss = append(ss, v)
	}
	protos := strings.Join(ss, "|")
	exp := regexp.MustCompile(fmt.Sprintf("^%s (((%s) )*)(%s)$", FlowSpecNameMap[FLOW_SPEC_TYPE_ETHERNET_TYPE], protos, protos))
	elems := exp.FindStringSubmatch(strings.Join(args, " "))
	items := make([]*FlowSpecComponentItem, 0)
	eq := 0x1
	if elems[1] != "" {
		for _, v := range strings.Split(elems[1], " ") {
			p, ok := EthernetTypeValueMap[v]
			if !ok {
				continue
			}
			items = append(items, NewFlowSpecComponentItem(eq, int(p)))
		}
	}
	items = append(items, NewFlowSpecComponentItem(eq, int(EthernetTypeValueMap[elems[4]])))
	return NewFlowSpecComponent(FLOW_SPEC_TYPE_ETHERNET_TYPE, items), nil
}

func doFlowSpecNumericParser(rf RouteFamily, args []string, validationFunc func(int) error) (FlowSpecComponentInterface, error) {
	if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP && FlowSpecValueMap[args[0]] == FLOW_SPEC_TYPE_LABEL {
		return nil, fmt.Errorf("flow label spec is only allowed for ipv6")
	}
	exp := regexp.MustCompile("^((<=|>=|[<>=])(\\d+)&)?(<=|>=|[<>=])?(\\d+)$")
	items := make([]*FlowSpecComponentItem, 0)

	f := func(and bool, o, v string) (*FlowSpecComponentItem, error) {
		op := 0
		if and {
			op |= 0x40
		}
		if len(o) == 0 {
			op |= 0x1
		}
		for _, oo := range o {
			switch oo {
			case '>':
				op |= 0x2
			case '<':
				op |= 0x4
			case '=':
				op |= 0x1
			}
		}
		value, err := strconv.Atoi(v)
		if err != nil {
			return nil, err
		}
		err = validationFunc(value)
		if err != nil {
			return nil, err
		}
		return NewFlowSpecComponentItem(op, value), nil
	}

	for _, arg := range args[1:] {
		var and bool
		elems := exp.FindStringSubmatch(arg)
		if len(elems) == 0 {
			return nil, fmt.Errorf("invalid flowspec numeric item")
		}
		if elems[1] != "" {
			and = true
			item, err := f(false, elems[2], elems[3])
			if err != nil {
				return nil, err
			}
			items = append(items, item)
		}
		item, err := f(and, elems[4], elems[5])
		if err != nil {
			return nil, err
		}
		items = append(items, item)
	}

	return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
}

func flowSpecNumericParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	f := func(i int) error {
		return nil
	}
	return doFlowSpecNumericParser(rf, args, f)
}

func flowSpecPortParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	f := func(i int) error {
		if 0 < i && i < 65536 {
			return nil
		}
		return fmt.Errorf("port range exceeded")
	}
	return doFlowSpecNumericParser(rf, args, f)
}

func flowSpecDscpParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	f := func(i int) error {
		if 0 < i && i < 64 {
			return nil
		}
		return fmt.Errorf("dscp value range exceeded")
	}
	return doFlowSpecNumericParser(rf, args, f)
}

func flowSpecFragmentParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	if len(args) < 2 {
		return nil, fmt.Errorf("invalid flowspec fragment specifier")
	}
	items := make([]*FlowSpecComponentItem, 0)
	for _, a := range args[1:] {
		value := 0
		switch a {
		case "dont-fragment":
			if afi, _ := RouteFamilyToAfiSafi(rf); afi == AFI_IP6 {
				return nil, fmt.Errorf("can't specify dont-fragment for ipv6")
			}
			value = 0x1
		case "is-fragment":
			value = 0x2
		case "first-fragment":
			value = 0x4
		case "last-fragment":
			value = 0x8
		case "not-a-fragment":
			value = 0x0
		default:
			return nil, fmt.Errorf("invalid flowspec fragment specifier")
		}
		items = append(items, NewFlowSpecComponentItem(0, value))
	}
	return NewFlowSpecComponent(FlowSpecValueMap[args[0]], items), nil
}

func flowSpecMacParser(rf RouteFamily, args []string) (FlowSpecComponentInterface, error) {
	if len(args) < 2 {
		return nil, fmt.Errorf("invalid flowspec dst/src mac")
	}
	if rf != RF_FS_L2_VPN {
		return nil, fmt.Errorf("invalid family")
	}
	typ := args[0]
	mac, err := net.ParseMAC(args[1])
	if err != nil {
		return nil, fmt.Errorf("invalid mac")
	}
	switch typ {
	case FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC]:
		return NewFlowSpecDestinationMac(mac), nil
	case FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC]:
		return NewFlowSpecSourceMac(mac), nil
	}
	return nil, fmt.Errorf("invalid type. only %s or %s allowed", FlowSpecNameMap[FLOW_SPEC_TYPE_DST_MAC], FlowSpecNameMap[FLOW_SPEC_TYPE_SRC_MAC])
}

var flowSpecParserMap = map[BGPFlowSpecType]func(RouteFamily, []string) (FlowSpecComponentInterface, error){
	FLOW_SPEC_TYPE_DST_PREFIX:    flowSpecPrefixParser,
	FLOW_SPEC_TYPE_SRC_PREFIX:    flowSpecPrefixParser,
	FLOW_SPEC_TYPE_IP_PROTO:      flowSpecIpProtoParser,
	FLOW_SPEC_TYPE_PORT:          flowSpecPortParser,
	FLOW_SPEC_TYPE_DST_PORT:      flowSpecPortParser,
	FLOW_SPEC_TYPE_SRC_PORT:      flowSpecPortParser,
	FLOW_SPEC_TYPE_ICMP_TYPE:     flowSpecNumericParser,
	FLOW_SPEC_TYPE_ICMP_CODE:     flowSpecNumericParser,
	FLOW_SPEC_TYPE_TCP_FLAG:      flowSpecTcpFlagParser,
	FLOW_SPEC_TYPE_PKT_LEN:       flowSpecNumericParser,
	FLOW_SPEC_TYPE_DSCP:          flowSpecDscpParser,
	FLOW_SPEC_TYPE_FRAGMENT:      flowSpecFragmentParser,
	FLOW_SPEC_TYPE_LABEL:         flowSpecNumericParser,
	FLOW_SPEC_TYPE_ETHERNET_TYPE: flowSpecEtherTypeParser,
	FLOW_SPEC_TYPE_DST_MAC:       flowSpecMacParser,
	FLOW_SPEC_TYPE_SRC_MAC:       flowSpecMacParser,
	FLOW_SPEC_TYPE_LLC_DSAP:      flowSpecNumericParser,
	FLOW_SPEC_TYPE_LLC_SSAP:      flowSpecNumericParser,
	FLOW_SPEC_TYPE_LLC_CONTROL:   flowSpecNumericParser,
	FLOW_SPEC_TYPE_SNAP:          flowSpecNumericParser,
	FLOW_SPEC_TYPE_VID:           flowSpecNumericParser,
	FLOW_SPEC_TYPE_COS:           flowSpecNumericParser,
	FLOW_SPEC_TYPE_INNER_VID:     flowSpecNumericParser,
	FLOW_SPEC_TYPE_INNER_COS:     flowSpecNumericParser,
}

func ParseFlowSpecComponents(rf RouteFamily, input string) ([]FlowSpecComponentInterface, error) {
	idxs := make([]struct {
		t BGPFlowSpecType
		i int
	}, 0, 8)
	args := strings.Split(input, " ")
	for idx, v := range args {
		if t, ok := FlowSpecValueMap[v]; ok {
			idxs = append(idxs, struct {
				t BGPFlowSpecType
				i int
			}{t, idx})
		}
	}
	if len(idxs) == 0 {
		return nil, fmt.Errorf("failed to parse: %s", input)
	}
	cmps := make([]FlowSpecComponentInterface, 0, len(idxs))
	for i, idx := range idxs {
		var a []string
		f := flowSpecParserMap[idx.t]
		if i < len(idxs)-1 {
			a = args[idx.i:idxs[i+1].i]
		} else {
			a = args[idx.i:]
		}
		cmp, err := f(rf, a)
		if err != nil {
			return nil, err
		}
		cmps = append(cmps, cmp)
	}
	return cmps, nil
}

func (t BGPFlowSpecType) String() string {
	name, ok := FlowSpecNameMap[t]
	if !ok {
		return fmt.Sprintf("%s(%d)", FlowSpecNameMap[FLOW_SPEC_TYPE_UNKNOWN], t)
	}
	return name
}

type FlowSpecComponentInterface interface {
	DecodeFromBytes([]byte) error
	Serialize() ([]byte, error)
	Len() int
	Type() BGPFlowSpecType
	String() string
}

type flowSpecPrefix struct {
	Prefix AddrPrefixInterface
	type_  BGPFlowSpecType
}

func (p *flowSpecPrefix) DecodeFromBytes(data []byte) error {
	p.type_ = BGPFlowSpecType(data[0])
	return p.Prefix.DecodeFromBytes(data[1:])
}

func (p *flowSpecPrefix) Serialize() ([]byte, error) {
	buf := []byte{byte(p.Type())}
	bbuf, err := p.Prefix.Serialize()
	if err != nil {
		return nil, err
	}
	return append(buf, bbuf...), nil
}

func (p *flowSpecPrefix) Len() int {
	buf, _ := p.Serialize()
	return len(buf)
}

func (p *flowSpecPrefix) Type() BGPFlowSpecType {
	return p.type_
}

func (p *flowSpecPrefix) String() string {
	return fmt.Sprintf("[%s:%s]", p.Type(), p.Prefix.String())
}

func (p *flowSpecPrefix) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Type  BGPFlowSpecType     `json:"type"`
		Value AddrPrefixInterface `json:"value"`
	}{
		Type:  p.Type(),
		Value: p.Prefix,
	})
}

type flowSpecPrefix6 struct {
	Prefix AddrPrefixInterface
	Offset uint8
	type_  BGPFlowSpecType
}

// draft-ietf-idr-flow-spec-v6-06
// <type (1 octet), prefix length (1 octet), prefix offset(1 octet), prefix>
func (p *flowSpecPrefix6) DecodeFromBytes(data []byte) error {
	p.type_ = BGPFlowSpecType(data[0])
	p.Offset = data[2]
	prefix := append([]byte{data[1]}, data[3:]...)
	return p.Prefix.DecodeFromBytes(prefix)
}

func (p *flowSpecPrefix6) Serialize() ([]byte, error) {
	buf := []byte{byte(p.Type())}
	bbuf, err := p.Prefix.Serialize()
	if err != nil {
		return nil, err
	}
	buf = append(buf, bbuf[0])
	buf = append(buf, p.Offset)
	return append(buf, bbuf[1:]...), nil
}

func (p *flowSpecPrefix6) Len() int {
	buf, _ := p.Serialize()
	return len(buf)
}

func (p *flowSpecPrefix6) Type() BGPFlowSpecType {
	return p.type_
}

func (p *flowSpecPrefix6) String() string {
	return fmt.Sprintf("[%s:%s/%d]", p.Type(), p.Prefix.String(), p.Offset)
}

func (p *flowSpecPrefix6) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Type   BGPFlowSpecType     `json:"type"`
		Value  AddrPrefixInterface `json:"value"`
		Offset uint8               `json:"offset"`
	}{
		Type:   p.Type(),
		Value:  p.Prefix,
		Offset: p.Offset,
	})
}

type FlowSpecDestinationPrefix struct {
	flowSpecPrefix
}

func NewFlowSpecDestinationPrefix(prefix AddrPrefixInterface) *FlowSpecDestinationPrefix {
	return &FlowSpecDestinationPrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_DST_PREFIX}}
}

type FlowSpecSourcePrefix struct {
	flowSpecPrefix
}

func NewFlowSpecSourcePrefix(prefix AddrPrefixInterface) *FlowSpecSourcePrefix {
	return &FlowSpecSourcePrefix{flowSpecPrefix{prefix, FLOW_SPEC_TYPE_SRC_PREFIX}}
}

type FlowSpecDestinationPrefix6 struct {
	flowSpecPrefix6
}

func NewFlowSpecDestinationPrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecDestinationPrefix6 {
	return &FlowSpecDestinationPrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_DST_PREFIX}}
}

type FlowSpecSourcePrefix6 struct {
	flowSpecPrefix6
}

func NewFlowSpecSourcePrefix6(prefix AddrPrefixInterface, offset uint8) *FlowSpecSourcePrefix6 {
	return &FlowSpecSourcePrefix6{flowSpecPrefix6{prefix, offset, FLOW_SPEC_TYPE_SRC_PREFIX}}
}

type flowSpecMac struct {
	Mac   net.HardwareAddr
	type_ BGPFlowSpecType
}

func (p *flowSpecMac) DecodeFromBytes(data []byte) error {
	if len(data) < 2 || len(data) < 2+int(data[1]) {
		return fmt.Errorf("not all mac bits available")
	}
	p.type_ = BGPFlowSpecType(data[0])
	p.Mac = net.HardwareAddr(data[2 : 2+int(data[1])])
	return nil
}

func (p *flowSpecMac) Serialize() ([]byte, error) {
	if len(p.Mac) == 0 {
		return nil, fmt.Errorf("mac unset")
	}
	buf := []byte{byte(p.Type()), byte(len(p.Mac))}
	return append(buf, []byte(p.Mac)...), nil
}

func (p *flowSpecMac) Len() int {
	return 2 + len(p.Mac)
}

func (p *flowSpecMac) Type() BGPFlowSpecType {
	return p.type_
}

func (p *flowSpecMac) String() string {
	return fmt.Sprintf("[%s:%s]", p.Type(), p.Mac.String())
}

func (p *flowSpecMac) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Type  BGPFlowSpecType `json:"type"`
		Value string          `json:"value"`
	}{
		Type:  p.Type(),
		Value: p.Mac.String(),
	})
}

type FlowSpecSourceMac struct {
	flowSpecMac
}

func NewFlowSpecSourceMac(mac net.HardwareAddr) *FlowSpecSourceMac {
	return &FlowSpecSourceMac{flowSpecMac{Mac: mac, type_: FLOW_SPEC_TYPE_SRC_MAC}}
}

type FlowSpecDestinationMac struct {
	flowSpecMac
}

func NewFlowSpecDestinationMac(mac net.HardwareAddr) *FlowSpecDestinationMac {
	return &FlowSpecDestinationMac{flowSpecMac{Mac: mac, type_: FLOW_SPEC_TYPE_DST_MAC}}
}

type FlowSpecComponentItem struct {
	Op    int `json:"op"`
	Value int `json:"value"`
}

func (v *FlowSpecComponentItem) Len() int {
	return 1 << ((uint32(v.Op) >> 4) & 0x3)
}

func (v *FlowSpecComponentItem) Serialize() ([]byte, error) {
	if v.Value < 0 {
		return nil, fmt.Errorf("invalid value size(too small): %d", v.Value)
	}
	if v.Op < 0 || v.Op > math.MaxUint8 {
		return nil, fmt.Errorf("invalid op size: %d", v.Op)

	}
	order := uint32(math.Log2(float64(v.Len())))
	buf := make([]byte, 1+(1<<order))
	buf[0] = byte(uint32(v.Op) | order<<4)
	switch order {
	case 0:
		buf[1] = byte(v.Value)
	case 1:
		binary.BigEndian.PutUint16(buf[1:], uint16(v.Value))
	case 2:
		binary.BigEndian.PutUint32(buf[1:], uint32(v.Value))
	case 3:
		binary.BigEndian.PutUint64(buf[1:], uint64(v.Value))
	default:
		return nil, fmt.Errorf("invalid value size(too big): %d", v.Value)
	}
	return buf, nil
}

func NewFlowSpecComponentItem(op int, value int) *FlowSpecComponentItem {
	v := &FlowSpecComponentItem{op, value}
	order := uint32(math.Log2(float64(v.Len())))
	// we don't know if not initialized properly or initialized to
	// zero...
	if order == 0 {
		order = func() uint32 {
			for i := 0; i < 3; i++ {
				if v.Value < (1 << ((1 << uint(i)) * 8)) {
					return uint32(i)
				}
			}
			// return invalid order
			return 4
		}()
	}
	if order > 3 {
		return nil
	}
	v.Op = int(uint32(v.Op) | order<<4)
	return v
}

type FlowSpecComponent struct {
	Items []*FlowSpecComponentItem
	type_ BGPFlowSpecType
}

func (p *FlowSpecComponent) DecodeFromBytes(data []byte) error {
	p.type_ = BGPFlowSpecType(data[0])
	data = data[1:]
	p.Items = make([]*FlowSpecComponentItem, 0)
	for {
		if len(data) < 2 {
			return fmt.Errorf("not all flowspec component bytes available")
		}
		op := data[0]
		end := op & 0x80
		l := 1 << ((op >> 4) & 0x3) // (min, max) = (1, 8)
		v := make([]byte, 8)
		copy(v[8-l:], data[1:1+l])
		i := int(binary.BigEndian.Uint64(v))
		item := &FlowSpecComponentItem{int(op), i}
		p.Items = append(p.Items, item)
		if end > 0 {
			break
		}
		data = data[1+l:]
	}
	return nil
}

func (p *FlowSpecComponent) Serialize() ([]byte, error) {
	buf := []byte{byte(p.Type())}
	for i, v := range p.Items {
		//set end-of-list bit
		if i == (len(p.Items) - 1) {
			v.Op |= 0x80
		} else {
			v.Op &^= 0x80
		}
		bbuf, err := v.Serialize()
		if err != nil {
			return nil, err
		}
		buf = append(buf, bbuf...)
	}
	return buf, nil
}

func (p *FlowSpecComponent) Len() int {
	l := 1
	for _, item := range p.Items {
		l += (item.Len() + 1)
	}
	return l
}

func (p *FlowSpecComponent) Type() BGPFlowSpecType {
	return p.type_
}

func formatRaw(op int, value int) string {
	return fmt.Sprintf("op: %b, value: %d", op, value)
}

func formatNumericOp(op int) string {
	var opstr string
	if op&0x40 > 0 {
		opstr = "&"
	} else {
		opstr = " "
	}
	if op&0x2 > 0 {
		opstr += ">"
	}
	if op&0x4 > 0 {
		opstr += "<"
	}
	if op&0x1 > 0 {
		opstr += "="
	}
	return opstr
}

func formatNumeric(op int, value int) string {
	return fmt.Sprintf("%s%d", formatNumericOp(op), value)
}

func formatProto(op int, value int) string {
	return fmt.Sprintf(" %s", Protocol(value).String())
}

func formatFlag(op int, value int) string {
	and := " "
	ss := make([]string, 0, 2)
	if op&0x40 > 0 {
		and = "&"
	}
	if op&0x1 > 0 {
		ss = append(ss, "match")
	}
	if op&0x2 > 0 {
		ss = append(ss, "not")
	}
	if len(ss) > 0 {
		return fmt.Sprintf("%s(%s)%s", and, strings.Join(ss, "|"), TCPFlag(value).String())
	}
	return fmt.Sprintf("%s%s", and, TCPFlag(value).String())
}

func formatFragment(op int, value int) string {
	ss := make([]string, 0)
	if value == 0 {
		ss = append(ss, "not-a-fragment")
	}
	if value&0x1 > 0 {
		ss = append(ss, "dont-fragment")
	}
	if value&0x2 > 0 {
		ss = append(ss, "is-fragment")
	}
	if value&0x4 > 0 {
		ss = append(ss, "first-fragment")
	}
	if value&0x8 > 0 {
		ss = append(ss, "last-fragment")
	}
	if len(ss) > 1 {
		return fmt.Sprintf("%s(%s)", formatNumericOp(op), strings.Join(ss, "|"))
	}
	return fmt.Sprintf("%s%s", formatNumericOp(op), ss[0])
}

func formatEtherType(op int, value int) string {
	return fmt.Sprintf(" %s", EthernetType(value).String())
}

var flowSpecFormatMap = map[BGPFlowSpecType]func(op int, value int) string{
	FLOW_SPEC_TYPE_UNKNOWN:       formatRaw,
	FLOW_SPEC_TYPE_IP_PROTO:      formatProto,
	FLOW_SPEC_TYPE_PORT:          formatNumeric,
	FLOW_SPEC_TYPE_DST_PORT:      formatNumeric,
	FLOW_SPEC_TYPE_SRC_PORT:      formatNumeric,
	FLOW_SPEC_TYPE_ICMP_TYPE:     formatNumeric,
	FLOW_SPEC_TYPE_ICMP_CODE:     formatNumeric,
	FLOW_SPEC_TYPE_TCP_FLAG:      formatFlag,
	FLOW_SPEC_TYPE_PKT_LEN:       formatNumeric,
	FLOW_SPEC_TYPE_DSCP:          formatNumeric,
	FLOW_SPEC_TYPE_FRAGMENT:      formatFragment,
	FLOW_SPEC_TYPE_LABEL:         formatNumeric,
	FLOW_SPEC_TYPE_ETHERNET_TYPE: formatEtherType,
	FLOW_SPEC_TYPE_LLC_DSAP:      formatNumeric,
	FLOW_SPEC_TYPE_LLC_SSAP:      formatNumeric,
	FLOW_SPEC_TYPE_LLC_CONTROL:   formatNumeric,
	FLOW_SPEC_TYPE_SNAP:          formatNumeric,
	FLOW_SPEC_TYPE_VID:           formatNumeric,
	FLOW_SPEC_TYPE_COS:           formatNumeric,
	FLOW_SPEC_TYPE_INNER_VID:     formatNumeric,
	FLOW_SPEC_TYPE_INNER_COS:     formatNumeric,
}

func (p *FlowSpecComponent) String() string {
	f := flowSpecFormatMap[FLOW_SPEC_TYPE_UNKNOWN]
	if _, ok := flowSpecFormatMap[p.Type()]; ok {
		f = flowSpecFormatMap[p.Type()]
	}
	buf := bytes.NewBuffer(make([]byte, 0, 32))
	for _, i := range p.Items {
		buf.WriteString(f(i.Op, i.Value))
	}
	return fmt.Sprintf("[%s:%s]", p.type_, buf.String())
}

func (p *FlowSpecComponent) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Type  BGPFlowSpecType          `json:"type"`
		Value []*FlowSpecComponentItem `json:"value"`
	}{
		Type:  p.Type(),
		Value: p.Items,
	})
}

func NewFlowSpecComponent(type_ BGPFlowSpecType, items []*FlowSpecComponentItem) *FlowSpecComponent {
	return &FlowSpecComponent{
		Items: items,
		type_: type_,
	}
}

type FlowSpecUnknown struct {
	Value []byte
}

func (p *FlowSpecUnknown) DecodeFromBytes(data []byte) error {
	p.Value = data
	return nil
}

func (p *FlowSpecUnknown) Serialize() ([]byte, error) {
	return p.Value, nil
}

func (p *FlowSpecUnknown) Len() int {
	return len(p.Value)
}

func (p *FlowSpecUnknown) Type() BGPFlowSpecType {
	if len(p.Value) > 0 {
		return BGPFlowSpecType(p.Value[0])
	}
	return FLOW_SPEC_TYPE_UNKNOWN
}

func (p *FlowSpecUnknown) String() string {
	return fmt.Sprintf("[unknown:%v]", p.Value)
}

type FlowSpecNLRI struct {
	Value []FlowSpecComponentInterface
	rf    RouteFamily
}

func (n *FlowSpecNLRI) decodeFromBytes(rf RouteFamily, data []byte) error {
	var length int
	if (data[0]>>4) == 0xf && len(data) > 2 {
		length = int(binary.BigEndian.Uint16(data[0:2]))
		data = data[2:]
	} else if len(data) > 1 {
		length = int(data[0])
		data = data[1:]
	} else {
		return fmt.Errorf("not all flowspec component bytes available")
	}

	n.rf = rf

	for l := length; l > 0; {
		if len(data) == 0 {
			return fmt.Errorf("not all flowspec component bytes available")
		}
		t := BGPFlowSpecType(data[0])
		var i FlowSpecComponentInterface
		switch t {
		case FLOW_SPEC_TYPE_DST_PREFIX:
			switch rf {
			case RF_FS_IPv4_UC:
				i = NewFlowSpecDestinationPrefix(NewIPAddrPrefix(0, ""))
			case RF_FS_IPv4_VPN:
				i = NewFlowSpecDestinationPrefix(NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil))
			case RF_FS_IPv6_UC:
				i = NewFlowSpecDestinationPrefix6(NewIPv6AddrPrefix(0, ""), 0)
			case RF_FS_IPv6_VPN:
				i = NewFlowSpecDestinationPrefix6(NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil), 0)
			default:
				return fmt.Errorf("Invalid RF: %v", rf)
			}
		case FLOW_SPEC_TYPE_SRC_PREFIX:
			switch rf {
			case RF_FS_IPv4_UC:
				i = NewFlowSpecSourcePrefix(NewIPAddrPrefix(0, ""))
			case RF_FS_IPv4_VPN:
				i = NewFlowSpecSourcePrefix(NewLabeledVPNIPAddrPrefix(0, "", *NewMPLSLabelStack(), nil))
			case RF_FS_IPv6_UC:
				i = NewFlowSpecSourcePrefix6(NewIPv6AddrPrefix(0, ""), 0)
			case RF_FS_IPv6_VPN:
				i = NewFlowSpecSourcePrefix6(NewLabeledVPNIPv6AddrPrefix(0, "", *NewMPLSLabelStack(), nil), 0)
			default:
				return fmt.Errorf("Invalid RF: %v", rf)
			}
		case FLOW_SPEC_TYPE_SRC_MAC:
			switch rf {
			case RF_FS_L2_VPN:
				i = NewFlowSpecSourceMac(nil)
			default:
				return fmt.Errorf("invalid family: %v", rf)
			}
		case FLOW_SPEC_TYPE_DST_MAC:
			switch rf {
			case RF_FS_L2_VPN:
				i = NewFlowSpecDestinationMac(nil)
			default:
				return fmt.Errorf("invalid family: %v", rf)
			}
		case FLOW_SPEC_TYPE_IP_PROTO, FLOW_SPEC_TYPE_PORT, FLOW_SPEC_TYPE_DST_PORT, FLOW_SPEC_TYPE_SRC_PORT,
			FLOW_SPEC_TYPE_ICMP_TYPE, FLOW_SPEC_TYPE_ICMP_CODE, FLOW_SPEC_TYPE_TCP_FLAG, FLOW_SPEC_TYPE_PKT_LEN,
			FLOW_SPEC_TYPE_DSCP, FLOW_SPEC_TYPE_FRAGMENT, FLOW_SPEC_TYPE_LABEL, FLOW_SPEC_TYPE_ETHERNET_TYPE,
			FLOW_SPEC_TYPE_LLC_DSAP, FLOW_SPEC_TYPE_LLC_SSAP, FLOW_SPEC_TYPE_LLC_CONTROL, FLOW_SPEC_TYPE_SNAP,
			FLOW_SPEC_TYPE_VID, FLOW_SPEC_TYPE_COS, FLOW_SPEC_TYPE_INNER_VID, FLOW_SPEC_TYPE_INNER_COS:
			i = NewFlowSpecComponent(t, nil)
		default:
			i = &FlowSpecUnknown{}
		}

		err := i.DecodeFromBytes(data)
		if err != nil {
			i = &FlowSpecUnknown{data}
		}
		l -= i.Len()
		data = data[i.Len():]
		n.Value = append(n.Value, i)
	}

	return nil
}

func (n *FlowSpecNLRI) Serialize() ([]byte, error) {
	buf := make([]byte, 0, 32)
	for _, v := range n.Value {
		b, err := v.Serialize()
		if err != nil {
			return nil, err
		}
		buf = append(buf, b...)
	}
	length := n.Len()
	if length > 0xfff {
		return nil, fmt.Errorf("Too large: %d", length)
	} else if length < 0xf0 {
		length -= 1
		buf = append([]byte{byte(length)}, buf...)
	} else {
		length -= 2
		b := make([]byte, 2)
		binary.BigEndian.PutUint16(buf, uint16(length))
		buf = append(b, buf...)
	}

	return buf, nil
}

func (n *FlowSpecNLRI) Len() int {
	l := 0
	for _, v := range n.Value {
		l += v.Len()
	}
	if l < 0xf0 {
		return l + 1
	} else {
		return l + 2
	}
}

func (n *FlowSpecNLRI) String() string {
	buf := bytes.NewBuffer(make([]byte, 0, 32))
	for _, v := range n.Value {
		buf.WriteString(v.String())
	}
	return buf.String()
}

func (n *FlowSpecNLRI) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Value []FlowSpecComponentInterface `json:"value"`
	}{
		Value: n.Value,
	})
}

type FlowSpecIPv4Unicast struct {
	FlowSpecNLRI
}

func (n *FlowSpecIPv4Unicast) DecodeFromBytes(data []byte) error {
	return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
}

func (n *FlowSpecIPv4Unicast) AFI() uint16 {
	return AFI_IP
}

func (n *FlowSpecIPv4Unicast) SAFI() uint8 {
	return SAFI_FLOW_SPEC_UNICAST
}

func NewFlowSpecIPv4Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv4Unicast {
	return &FlowSpecIPv4Unicast{FlowSpecNLRI{value, RF_FS_IPv4_UC}}
}

type FlowSpecIPv4VPN struct {
	FlowSpecNLRI
}

func (n *FlowSpecIPv4VPN) DecodeFromBytes(data []byte) error {
	return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
}

func (n *FlowSpecIPv4VPN) AFI() uint16 {
	return AFI_IP
}

func (n *FlowSpecIPv4VPN) SAFI() uint8 {
	return SAFI_FLOW_SPEC_VPN
}

func NewFlowSpecIPv4VPN(value []FlowSpecComponentInterface) *FlowSpecIPv4VPN {
	return &FlowSpecIPv4VPN{FlowSpecNLRI{value, RF_FS_IPv4_VPN}}
}

type FlowSpecIPv6Unicast struct {
	FlowSpecNLRI
}

func (n *FlowSpecIPv6Unicast) DecodeFromBytes(data []byte) error {
	return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
}

func (n *FlowSpecIPv6Unicast) AFI() uint16 {
	return AFI_IP6
}

func (n *FlowSpecIPv6Unicast) SAFI() uint8 {
	return SAFI_FLOW_SPEC_UNICAST
}

func NewFlowSpecIPv6Unicast(value []FlowSpecComponentInterface) *FlowSpecIPv6Unicast {
	return &FlowSpecIPv6Unicast{FlowSpecNLRI{
		Value: value,
		rf:    RF_FS_IPv6_UC,
	}}
}

type FlowSpecIPv6VPN struct {
	FlowSpecNLRI
}

func (n *FlowSpecIPv6VPN) DecodeFromBytes(data []byte) error {
	return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
}

func (n *FlowSpecIPv6VPN) AFI() uint16 {
	return AFI_IP6
}

func (n *FlowSpecIPv6VPN) SAFI() uint8 {
	return SAFI_FLOW_SPEC_VPN
}

func NewFlowSpecIPv6VPN(value []FlowSpecComponentInterface) *FlowSpecIPv6VPN {
	return &FlowSpecIPv6VPN{FlowSpecNLRI{
		Value: value,
		rf:    RF_FS_IPv6_VPN,
	}}
}

type FlowSpecL2VPN struct {
	FlowSpecNLRI
}

func (n *FlowSpecL2VPN) DecodeFromBytes(data []byte) error {
	return n.decodeFromBytes(AfiSafiToRouteFamily(n.AFI(), n.SAFI()), data)
}

func (n *FlowSpecL2VPN) AFI() uint16 {
	return AFI_L2VPN
}

func (n *FlowSpecL2VPN) SAFI() uint8 {
	return SAFI_FLOW_SPEC_VPN
}

func NewFlowSpecL2VPN(value []FlowSpecComponentInterface) *FlowSpecL2VPN {
	return &FlowSpecL2VPN{FlowSpecNLRI{
		Value: value,
		rf:    RF_FS_L2_VPN,
	}}
}

type OpaqueNLRI struct {
	Length uint8
	Key    []byte
}

func (n *OpaqueNLRI) DecodeFromBytes(data []byte) error {
	n.Length = data[0]
	if len(data)-1 < int(n.Length) {
		return fmt.Errorf("Not all OpaqueNLRI bytes available")
	}
	n.Key = data[1 : 1+n.Length]
	return nil
}

func (n *OpaqueNLRI) Serialize() ([]byte, error) {
	if len(n.Key) > math.MaxUint8 {
		return nil, fmt.Errorf("Key length too big")
	}
	return append([]byte{byte(len(n.Key))}, n.Key...), nil
}

func (n *OpaqueNLRI) AFI() uint16 {
	return AFI_OPAQUE
}

func (n *OpaqueNLRI) SAFI() uint8 {
	return SAFI_KEY_VALUE
}

func (n *OpaqueNLRI) Len() int {
	return 1 + len(n.Key)
}

func (n *OpaqueNLRI) String() string {
	return string(n.Key)
}

func (n *OpaqueNLRI) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Key string `json:"key"`
	}{
		Key: n.String(),
	})
}

func NewOpaqueNLRI(key []byte) *OpaqueNLRI {
	return &OpaqueNLRI{
		Key: key,
	}
}

func AfiSafiToRouteFamily(afi uint16, safi uint8) RouteFamily {
	return RouteFamily(int(afi)<<16 | int(safi))
}

func RouteFamilyToAfiSafi(rf RouteFamily) (uint16, uint8) {
	return uint16(int(rf) >> 16), uint8(int(rf) & 0xff)
}

type RouteFamily int

func (f RouteFamily) String() string {
	if n, y := AddressFamilyNameMap[f]; y {
		return n
	}
	return fmt.Sprintf("UnknownFamily(%d)", f)
}

const (
	RF_IPv4_UC     RouteFamily = AFI_IP<<16 | SAFI_UNICAST
	RF_IPv6_UC     RouteFamily = AFI_IP6<<16 | SAFI_UNICAST
	RF_IPv4_MC     RouteFamily = AFI_IP<<16 | SAFI_MULTICAST
	RF_IPv6_MC     RouteFamily = AFI_IP6<<16 | SAFI_MULTICAST
	RF_IPv4_VPN    RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN
	RF_IPv6_VPN    RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN
	RF_IPv4_VPN_MC RouteFamily = AFI_IP<<16 | SAFI_MPLS_VPN_MULTICAST
	RF_IPv6_VPN_MC RouteFamily = AFI_IP6<<16 | SAFI_MPLS_VPN_MULTICAST
	RF_IPv4_MPLS   RouteFamily = AFI_IP<<16 | SAFI_MPLS_LABEL
	RF_IPv6_MPLS   RouteFamily = AFI_IP6<<16 | SAFI_MPLS_LABEL
	RF_VPLS        RouteFamily = AFI_L2VPN<<16 | SAFI_VPLS
	RF_EVPN        RouteFamily = AFI_L2VPN<<16 | SAFI_EVPN
	RF_RTC_UC      RouteFamily = AFI_IP<<16 | SAFI_ROUTE_TARGET_CONSTRTAINS
	RF_IPv4_ENCAP  RouteFamily = AFI_IP<<16 | SAFI_ENCAPSULATION
	RF_IPv6_ENCAP  RouteFamily = AFI_IP6<<16 | SAFI_ENCAPSULATION
	RF_FS_IPv4_UC  RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_UNICAST
	RF_FS_IPv4_VPN RouteFamily = AFI_IP<<16 | SAFI_FLOW_SPEC_VPN
	RF_FS_IPv6_UC  RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_UNICAST
	RF_FS_IPv6_VPN RouteFamily = AFI_IP6<<16 | SAFI_FLOW_SPEC_VPN
	RF_FS_L2_VPN   RouteFamily = AFI_L2VPN<<16 | SAFI_FLOW_SPEC_VPN
	RF_OPAQUE      RouteFamily = AFI_OPAQUE<<16 | SAFI_KEY_VALUE
)

var AddressFamilyNameMap = map[RouteFamily]string{
	RF_IPv4_UC:     "ipv4-unicast",
	RF_IPv6_UC:     "ipv6-unicast",
	RF_IPv4_MC:     "ipv4-multicast",
	RF_IPv6_MC:     "ipv6-multicast",
	RF_IPv4_MPLS:   "ipv4-labelled-unicast",
	RF_IPv6_MPLS:   "ipv6-labelled-unicast",
	RF_IPv4_VPN:    "l3vpn-ipv4-unicast",
	RF_IPv6_VPN:    "l3vpn-ipv6-unicast",
	RF_IPv4_VPN_MC: "l3vpn-ipv4-multicast",
	RF_IPv6_VPN_MC: "l3vpn-ipv6-multicast",
	RF_VPLS:        "l2vpn-vpls",
	RF_EVPN:        "l2vpn-evpn",
	RF_RTC_UC:      "rtc",
	RF_IPv4_ENCAP:  "ipv4-encap",
	RF_IPv6_ENCAP:  "ipv6-encap",
	RF_FS_IPv4_UC:  "ipv4-flowspec",
	RF_FS_IPv4_VPN: "l3vpn-ipv4-flowspec",
	RF_FS_IPv6_UC:  "ipv6-flowspec",
	RF_FS_IPv6_VPN: "l3vpn-ipv6-flowspec",
	RF_FS_L2_VPN:   "l2vpn-flowspec",
	RF_OPAQUE:      "opaque",
}

var AddressFamilyValueMap = map[string]RouteFamily{
	AddressFamilyNameMap[RF_IPv4_UC]:     RF_IPv4_UC,
	AddressFamilyNameMap[RF_IPv6_UC]:     RF_IPv6_UC,
	AddressFamilyNameMap[RF_IPv4_MC]:     RF_IPv4_MC,
	AddressFamilyNameMap[RF_IPv6_MC]:     RF_IPv6_MC,
	AddressFamilyNameMap[RF_IPv4_MPLS]:   RF_IPv4_MPLS,
	AddressFamilyNameMap[RF_IPv6_MPLS]:   RF_IPv6_MPLS,
	AddressFamilyNameMap[RF_IPv4_VPN]:    RF_IPv4_VPN,
	AddressFamilyNameMap[RF_IPv6_VPN]:    RF_IPv6_VPN,
	AddressFamilyNameMap[RF_IPv4_VPN_MC]: RF_IPv4_VPN_MC,
	AddressFamilyNameMap[RF_IPv6_VPN_MC]: RF_IPv6_VPN_MC,
	AddressFamilyNameMap[RF_VPLS]:        RF_VPLS,
	AddressFamilyNameMap[RF_EVPN]:        RF_EVPN,
	AddressFamilyNameMap[RF_RTC_UC]:      RF_RTC_UC,
	AddressFamilyNameMap[RF_IPv4_ENCAP]:  RF_IPv4_ENCAP,
	AddressFamilyNameMap[RF_IPv6_ENCAP]:  RF_IPv6_ENCAP,
	AddressFamilyNameMap[RF_FS_IPv4_UC]:  RF_FS_IPv4_UC,
	AddressFamilyNameMap[RF_FS_IPv4_VPN]: RF_FS_IPv4_VPN,
	AddressFamilyNameMap[RF_FS_IPv6_UC]:  RF_FS_IPv6_UC,
	AddressFamilyNameMap[RF_FS_IPv6_VPN]: RF_FS_IPv6_VPN,
	AddressFamilyNameMap[RF_FS_L2_VPN]:   RF_FS_L2_VPN,
	AddressFamilyNameMap[RF_OPAQUE]:      RF_OPAQUE,
}

func GetRouteFamily(name string) (RouteFamily, error) {
	if v, ok := AddressFamilyValueMap[name]; ok {
		return v, nil
	}
	return RouteFamily(0), fmt.Errorf("%s isn't a valid route family name", name)
}

func NewPrefixFromRouteFamily(afi uint16, safi uint8) (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_IPv4_ENCAP:
		prefix = NewEncapNLRI("")
	case RF_IPv6_ENCAP:
		prefix = NewEncapv6NLRI("")
	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 (p *PathAttributeMpReachNLRI) String() string {
	return fmt.Sprintf("{MpReach(%s): {Nexthop: %s, NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Nexthop, p.Value)
}

func NewPathAttributeMpReachNLRI(nexthop string, nlri []AddrPrefixInterface) *PathAttributeMpReachNLRI {
	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 (p *PathAttributeMpUnreachNLRI) String() string {
	if len(p.Value) > 0 {
		return fmt.Sprintf("{MpUnreach(%s): {NLRIs: %s}}", AfiSafiToRouteFamily(p.AFI, p.SAFI), p.Value)
	}
	return fmt.Sprintf("{MpUnreach(%s): End-of-Rib}", AfiSafiToRouteFamily(p.AFI, p.SAFI))
}

func NewPathAttributeMpUnreachNLRI(nlri []AddrPrefixInterface) *PathAttributeMpUnreachNLRI {
	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:
		// RFC7674
		switch typ {
		case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL:
			as := binary.BigEndian.Uint16(data[2:4])
			localAdmin := binary.BigEndian.Uint32(data[4:8])
			return NewRedirectTwoOctetAsSpecificExtended(as, localAdmin), nil
		case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL2:
			ipv4 := net.IP(data[2:6]).String()
			localAdmin := binary.BigEndian.Uint16(data[6:8])
			return NewRedirectIPv4AddressSpecificExtended(ipv4, localAdmin), nil
		case EC_TYPE_GENERIC_TRANSITIVE_EXPERIMENTAL3:
			as := binary.BigEndian.Uint32(data[2:6])
			localAdmin := binary.BigEndian.Uint16(data[6:8])
			return NewRedirectFourOctetAsSpecificExtended(as, localAdmin), nil
		}
	case EC_SUBTYPE_FLOWSPEC_TRAFFIC_REMARK:
		dscp := data[7]
		return NewTrafficRemarkExtended(dscp), nil
	}
	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)
		t := BGP_ATTR_TYPE_MP_UNREACH_NLRI
		unreach := &PathAttributeMpUnreachNLRI{
			PathAttribute: PathAttribute{
				Flags:  pathAttrFlags[t],
				Type:   t,
				Length: 0,
			},
			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
}

type MessageError struct {
	TypeCode    uint8
	SubTypeCode uint8
	Data        []byte
	Message     string
}

func NewMessageError(typeCode, subTypeCode uint8, data []byte, msg string) error {
	return &MessageError{
		TypeCode:    typeCode,
		SubTypeCode: subTypeCode,
		Data:        data,
		Message:     msg,
	}
}

func (e *MessageError) Error() string {
	return e.Message
}