package nl import ( "bytes" "encoding/binary" "fmt" "net" "unsafe" "golang.org/x/sys/unix" ) // LinkLayer const ( LINKLAYER_UNSPEC = iota LINKLAYER_ETHERNET LINKLAYER_ATM ) // ATM const ( ATM_CELL_PAYLOAD = 48 ATM_CELL_SIZE = 53 ) const TC_LINKLAYER_MASK = 0x0F // Police const ( TCA_POLICE_UNSPEC = iota TCA_POLICE_TBF TCA_POLICE_RATE TCA_POLICE_PEAKRATE TCA_POLICE_AVRATE TCA_POLICE_RESULT TCA_POLICE_MAX = TCA_POLICE_RESULT ) // Message types const ( TCA_UNSPEC = iota TCA_KIND TCA_OPTIONS TCA_STATS TCA_XSTATS TCA_RATE TCA_FCNT TCA_STATS2 TCA_STAB TCA_PAD TCA_DUMP_INVISIBLE TCA_CHAIN TCA_HW_OFFLOAD TCA_INGRESS_BLOCK TCA_EGRESS_BLOCK TCA_DUMP_FLAGS TCA_MAX = TCA_DUMP_FLAGS ) const ( TCA_ACT_TAB = 1 TCAA_MAX = 1 ) const ( TCA_ACT_UNSPEC = iota TCA_ACT_KIND TCA_ACT_OPTIONS TCA_ACT_INDEX TCA_ACT_STATS TCA_ACT_PAD TCA_ACT_COOKIE TCA_ACT_FLAGS TCA_ACT_HW_STATS TCA_ACT_USED_HW_STATS TCA_ACT_IN_HW_COUNT TCA_ACT_MAX ) const ( TCA_PRIO_UNSPEC = iota TCA_PRIO_MQ TCA_PRIO_MAX = TCA_PRIO_MQ ) const ( TCA_STATS_UNSPEC = iota TCA_STATS_BASIC TCA_STATS_RATE_EST TCA_STATS_QUEUE TCA_STATS_APP TCA_STATS_RATE_EST64 TCA_STATS_PAD TCA_STATS_BASIC_HW TCA_STATS_PKT64 TCA_STATS_MAX = TCA_STATS_PKT64 ) const ( SizeofTcMsg = 0x14 SizeofTcActionMsg = 0x04 SizeofTcPrioMap = 0x14 SizeofTcRateSpec = 0x0c SizeofTcNetemQopt = 0x18 SizeofTcNetemCorr = 0x0c SizeofTcNetemReorder = 0x08 SizeofTcNetemCorrupt = 0x08 SizeOfTcNetemRate = 0x10 SizeofTcTbfQopt = 2*SizeofTcRateSpec + 0x0c SizeofTcHtbCopt = 2*SizeofTcRateSpec + 0x14 SizeofTcHtbGlob = 0x14 SizeofTcU32Key = 0x10 SizeofTcU32Sel = 0x10 // without keys SizeofTcGen = 0x16 SizeofTcConnmark = SizeofTcGen + 0x04 SizeofTcCsum = SizeofTcGen + 0x04 SizeofTcMirred = SizeofTcGen + 0x08 SizeofTcTunnelKey = SizeofTcGen + 0x04 SizeofTcSkbEdit = SizeofTcGen SizeofTcPolice = 2*SizeofTcRateSpec + 0x20 SizeofTcSfqQopt = 0x0b SizeofTcSfqRedStats = 0x18 SizeofTcSfqQoptV1 = SizeofTcSfqQopt + SizeofTcSfqRedStats + 0x1c SizeofUint32Bitfield = 0x8 ) // struct tcmsg { // unsigned char tcm_family; // unsigned char tcm__pad1; // unsigned short tcm__pad2; // int tcm_ifindex; // __u32 tcm_handle; // __u32 tcm_parent; // __u32 tcm_info; // }; type TcMsg struct { Family uint8 Pad [3]byte Ifindex int32 Handle uint32 Parent uint32 Info uint32 } func (msg *TcMsg) Len() int { return SizeofTcMsg } func DeserializeTcMsg(b []byte) *TcMsg { return (*TcMsg)(unsafe.Pointer(&b[0:SizeofTcMsg][0])) } func (x *TcMsg) Serialize() []byte { return (*(*[SizeofTcMsg]byte)(unsafe.Pointer(x)))[:] } type Tcf struct { Install uint64 LastUse uint64 Expires uint64 FirstUse uint64 } func DeserializeTcf(b []byte) *Tcf { const size = int(unsafe.Sizeof(Tcf{})) return (*Tcf)(unsafe.Pointer(&b[0:size][0])) } // struct tcamsg { // unsigned char tca_family; // unsigned char tca__pad1; // unsigned short tca__pad2; // }; type TcActionMsg struct { Family uint8 Pad [3]byte } func (msg *TcActionMsg) Len() int { return SizeofTcActionMsg } func DeserializeTcActionMsg(b []byte) *TcActionMsg { return (*TcActionMsg)(unsafe.Pointer(&b[0:SizeofTcActionMsg][0])) } func (x *TcActionMsg) Serialize() []byte { return (*(*[SizeofTcActionMsg]byte)(unsafe.Pointer(x)))[:] } const ( TC_PRIO_MAX = 15 ) // struct tc_prio_qopt { // int bands; /* Number of bands */ // __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ // }; type TcPrioMap struct { Bands int32 Priomap [TC_PRIO_MAX + 1]uint8 } func (msg *TcPrioMap) Len() int { return SizeofTcPrioMap } func DeserializeTcPrioMap(b []byte) *TcPrioMap { return (*TcPrioMap)(unsafe.Pointer(&b[0:SizeofTcPrioMap][0])) } func (x *TcPrioMap) Serialize() []byte { return (*(*[SizeofTcPrioMap]byte)(unsafe.Pointer(x)))[:] } const ( TCA_TBF_UNSPEC = iota TCA_TBF_PARMS TCA_TBF_RTAB TCA_TBF_PTAB TCA_TBF_RATE64 TCA_TBF_PRATE64 TCA_TBF_BURST TCA_TBF_PBURST TCA_TBF_MAX = TCA_TBF_PBURST ) // struct tc_ratespec { // unsigned char cell_log; // __u8 linklayer; /* lower 4 bits */ // unsigned short overhead; // short cell_align; // unsigned short mpu; // __u32 rate; // }; type TcRateSpec struct { CellLog uint8 Linklayer uint8 Overhead uint16 CellAlign int16 Mpu uint16 Rate uint32 } func (msg *TcRateSpec) Len() int { return SizeofTcRateSpec } func DeserializeTcRateSpec(b []byte) *TcRateSpec { return (*TcRateSpec)(unsafe.Pointer(&b[0:SizeofTcRateSpec][0])) } func (x *TcRateSpec) Serialize() []byte { return (*(*[SizeofTcRateSpec]byte)(unsafe.Pointer(x)))[:] } /** * NETEM */ const ( TCA_NETEM_UNSPEC = iota TCA_NETEM_CORR TCA_NETEM_DELAY_DIST TCA_NETEM_REORDER TCA_NETEM_CORRUPT TCA_NETEM_LOSS TCA_NETEM_RATE TCA_NETEM_ECN TCA_NETEM_RATE64 TCA_NETEM_MAX = TCA_NETEM_RATE64 ) // struct tc_netem_qopt { // __u32 latency; /* added delay (us) */ // __u32 limit; /* fifo limit (packets) */ // __u32 loss; /* random packet loss (0=none ~0=100%) */ // __u32 gap; /* re-ordering gap (0 for none) */ // __u32 duplicate; /* random packet dup (0=none ~0=100%) */ // __u32 jitter; /* random jitter in latency (us) */ // }; type TcNetemQopt struct { Latency uint32 Limit uint32 Loss uint32 Gap uint32 Duplicate uint32 Jitter uint32 } func (msg *TcNetemQopt) Len() int { return SizeofTcNetemQopt } func DeserializeTcNetemQopt(b []byte) *TcNetemQopt { return (*TcNetemQopt)(unsafe.Pointer(&b[0:SizeofTcNetemQopt][0])) } func (x *TcNetemQopt) Serialize() []byte { return (*(*[SizeofTcNetemQopt]byte)(unsafe.Pointer(x)))[:] } // struct tc_netem_corr { // __u32 delay_corr; /* delay correlation */ // __u32 loss_corr; /* packet loss correlation */ // __u32 dup_corr; /* duplicate correlation */ // }; type TcNetemCorr struct { DelayCorr uint32 LossCorr uint32 DupCorr uint32 } func (msg *TcNetemCorr) Len() int { return SizeofTcNetemCorr } func DeserializeTcNetemCorr(b []byte) *TcNetemCorr { return (*TcNetemCorr)(unsafe.Pointer(&b[0:SizeofTcNetemCorr][0])) } func (x *TcNetemCorr) Serialize() []byte { return (*(*[SizeofTcNetemCorr]byte)(unsafe.Pointer(x)))[:] } // struct tc_netem_reorder { // __u32 probability; // __u32 correlation; // }; type TcNetemReorder struct { Probability uint32 Correlation uint32 } func (msg *TcNetemReorder) Len() int { return SizeofTcNetemReorder } func DeserializeTcNetemReorder(b []byte) *TcNetemReorder { return (*TcNetemReorder)(unsafe.Pointer(&b[0:SizeofTcNetemReorder][0])) } func (x *TcNetemReorder) Serialize() []byte { return (*(*[SizeofTcNetemReorder]byte)(unsafe.Pointer(x)))[:] } // struct tc_netem_corrupt { // __u32 probability; // __u32 correlation; // }; type TcNetemCorrupt struct { Probability uint32 Correlation uint32 } func (msg *TcNetemCorrupt) Len() int { return SizeofTcNetemCorrupt } func DeserializeTcNetemCorrupt(b []byte) *TcNetemCorrupt { return (*TcNetemCorrupt)(unsafe.Pointer(&b[0:SizeofTcNetemCorrupt][0])) } func (x *TcNetemCorrupt) Serialize() []byte { return (*(*[SizeofTcNetemCorrupt]byte)(unsafe.Pointer(x)))[:] } // TcNetemRate is a struct that represents the rate of a netem qdisc type TcNetemRate struct { Rate uint32 PacketOverhead int32 CellSize uint32 CellOverhead int32 } func (msg *TcNetemRate) Len() int { return SizeofTcRateSpec } func DeserializeTcNetemRate(b []byte) *TcNetemRate { return (*TcNetemRate)(unsafe.Pointer(&b[0:SizeofTcRateSpec][0])) } func (msg *TcNetemRate) Serialize() []byte { return (*(*[SizeOfTcNetemRate]byte)(unsafe.Pointer(msg)))[:] } // struct tc_tbf_qopt { // struct tc_ratespec rate; // struct tc_ratespec peakrate; // __u32 limit; // __u32 buffer; // __u32 mtu; // }; type TcTbfQopt struct { Rate TcRateSpec Peakrate TcRateSpec Limit uint32 Buffer uint32 Mtu uint32 } func (msg *TcTbfQopt) Len() int { return SizeofTcTbfQopt } func DeserializeTcTbfQopt(b []byte) *TcTbfQopt { return (*TcTbfQopt)(unsafe.Pointer(&b[0:SizeofTcTbfQopt][0])) } func (x *TcTbfQopt) Serialize() []byte { return (*(*[SizeofTcTbfQopt]byte)(unsafe.Pointer(x)))[:] } const ( TCA_HTB_UNSPEC = iota TCA_HTB_PARMS TCA_HTB_INIT TCA_HTB_CTAB TCA_HTB_RTAB TCA_HTB_DIRECT_QLEN TCA_HTB_RATE64 TCA_HTB_CEIL64 TCA_HTB_MAX = TCA_HTB_CEIL64 ) //struct tc_htb_opt { // struct tc_ratespec rate; // struct tc_ratespec ceil; // __u32 buffer; // __u32 cbuffer; // __u32 quantum; // __u32 level; /* out only */ // __u32 prio; //}; type TcHtbCopt struct { Rate TcRateSpec Ceil TcRateSpec Buffer uint32 Cbuffer uint32 Quantum uint32 Level uint32 Prio uint32 } func (msg *TcHtbCopt) Len() int { return SizeofTcHtbCopt } func DeserializeTcHtbCopt(b []byte) *TcHtbCopt { return (*TcHtbCopt)(unsafe.Pointer(&b[0:SizeofTcHtbCopt][0])) } func (x *TcHtbCopt) Serialize() []byte { return (*(*[SizeofTcHtbCopt]byte)(unsafe.Pointer(x)))[:] } type TcHtbGlob struct { Version uint32 Rate2Quantum uint32 Defcls uint32 Debug uint32 DirectPkts uint32 } func (msg *TcHtbGlob) Len() int { return SizeofTcHtbGlob } func DeserializeTcHtbGlob(b []byte) *TcHtbGlob { return (*TcHtbGlob)(unsafe.Pointer(&b[0:SizeofTcHtbGlob][0])) } func (x *TcHtbGlob) Serialize() []byte { return (*(*[SizeofTcHtbGlob]byte)(unsafe.Pointer(x)))[:] } // HFSC type Curve struct { m1 uint32 d uint32 m2 uint32 } type HfscCopt struct { Rsc Curve Fsc Curve Usc Curve } func (c *Curve) Attrs() (uint32, uint32, uint32) { return c.m1, c.d, c.m2 } func (c *Curve) Set(m1 uint32, d uint32, m2 uint32) { c.m1 = m1 c.d = d c.m2 = m2 } func DeserializeHfscCurve(b []byte) *Curve { return &Curve{ m1: binary.LittleEndian.Uint32(b[0:4]), d: binary.LittleEndian.Uint32(b[4:8]), m2: binary.LittleEndian.Uint32(b[8:12]), } } func SerializeHfscCurve(c *Curve) (b []byte) { t := make([]byte, binary.MaxVarintLen32) binary.LittleEndian.PutUint32(t, c.m1) b = append(b, t[:4]...) binary.LittleEndian.PutUint32(t, c.d) b = append(b, t[:4]...) binary.LittleEndian.PutUint32(t, c.m2) b = append(b, t[:4]...) return b } type TcHfscOpt struct { Defcls uint16 } func (x *TcHfscOpt) Serialize() []byte { return (*(*[2]byte)(unsafe.Pointer(x)))[:] } const ( TCA_U32_UNSPEC = iota TCA_U32_CLASSID TCA_U32_HASH TCA_U32_LINK TCA_U32_DIVISOR TCA_U32_SEL TCA_U32_POLICE TCA_U32_ACT TCA_U32_INDEV TCA_U32_PCNT TCA_U32_MARK TCA_U32_MAX = TCA_U32_MARK ) // struct tc_u32_key { // __be32 mask; // __be32 val; // int off; // int offmask; // }; type TcU32Key struct { Mask uint32 // big endian Val uint32 // big endian Off int32 OffMask int32 } func (msg *TcU32Key) Len() int { return SizeofTcU32Key } func DeserializeTcU32Key(b []byte) *TcU32Key { return (*TcU32Key)(unsafe.Pointer(&b[0:SizeofTcU32Key][0])) } func (x *TcU32Key) Serialize() []byte { return (*(*[SizeofTcU32Key]byte)(unsafe.Pointer(x)))[:] } // struct tc_u32_sel { // unsigned char flags; // unsigned char offshift; // unsigned char nkeys; // // __be16 offmask; // __u16 off; // short offoff; // // short hoff; // __be32 hmask; // struct tc_u32_key keys[0]; // }; const ( TC_U32_TERMINAL = 1 << iota TC_U32_OFFSET = 1 << iota TC_U32_VAROFFSET = 1 << iota TC_U32_EAT = 1 << iota ) type TcU32Sel struct { Flags uint8 Offshift uint8 Nkeys uint8 Pad uint8 Offmask uint16 // big endian Off uint16 Offoff int16 Hoff int16 Hmask uint32 // big endian Keys []TcU32Key } func (msg *TcU32Sel) Len() int { return SizeofTcU32Sel + int(msg.Nkeys)*SizeofTcU32Key } func DeserializeTcU32Sel(b []byte) *TcU32Sel { x := &TcU32Sel{} copy((*(*[SizeofTcU32Sel]byte)(unsafe.Pointer(x)))[:], b) next := SizeofTcU32Sel var i uint8 for i = 0; i < x.Nkeys; i++ { x.Keys = append(x.Keys, *DeserializeTcU32Key(b[next:])) next += SizeofTcU32Key } return x } func (x *TcU32Sel) Serialize() []byte { // This can't just unsafe.cast because it must iterate through keys. buf := make([]byte, x.Len()) copy(buf, (*(*[SizeofTcU32Sel]byte)(unsafe.Pointer(x)))[:]) next := SizeofTcU32Sel for _, key := range x.Keys { keyBuf := key.Serialize() copy(buf[next:], keyBuf) next += SizeofTcU32Key } return buf } type TcGen struct { Index uint32 Capab uint32 Action int32 Refcnt int32 Bindcnt int32 } func (msg *TcGen) Len() int { return SizeofTcGen } func DeserializeTcGen(b []byte) *TcGen { return (*TcGen)(unsafe.Pointer(&b[0:SizeofTcGen][0])) } func (x *TcGen) Serialize() []byte { return (*(*[SizeofTcGen]byte)(unsafe.Pointer(x)))[:] } // #define tc_gen \ // __u32 index; \ // __u32 capab; \ // int action; \ // int refcnt; \ // int bindcnt const ( TCA_ACT_GACT = 5 ) const ( TCA_GACT_UNSPEC = iota TCA_GACT_TM TCA_GACT_PARMS TCA_GACT_PROB TCA_GACT_MAX = TCA_GACT_PROB ) type TcGact TcGen const ( TCA_ACT_BPF = 13 ) const ( TCA_ACT_BPF_UNSPEC = iota TCA_ACT_BPF_TM TCA_ACT_BPF_PARMS TCA_ACT_BPF_OPS_LEN TCA_ACT_BPF_OPS TCA_ACT_BPF_FD TCA_ACT_BPF_NAME TCA_ACT_BPF_MAX = TCA_ACT_BPF_NAME ) const ( TCA_BPF_FLAG_ACT_DIRECT uint32 = 1 << iota ) const ( TCA_BPF_UNSPEC = iota TCA_BPF_ACT TCA_BPF_POLICE TCA_BPF_CLASSID TCA_BPF_OPS_LEN TCA_BPF_OPS TCA_BPF_FD TCA_BPF_NAME TCA_BPF_FLAGS TCA_BPF_FLAGS_GEN TCA_BPF_TAG TCA_BPF_ID TCA_BPF_MAX = TCA_BPF_ID ) type TcBpf TcGen const ( TCA_ACT_CONNMARK = 14 ) const ( TCA_CONNMARK_UNSPEC = iota TCA_CONNMARK_PARMS TCA_CONNMARK_TM TCA_CONNMARK_MAX = TCA_CONNMARK_TM ) // struct tc_connmark { // tc_gen; // __u16 zone; // }; type TcConnmark struct { TcGen Zone uint16 } func (msg *TcConnmark) Len() int { return SizeofTcConnmark } func DeserializeTcConnmark(b []byte) *TcConnmark { return (*TcConnmark)(unsafe.Pointer(&b[0:SizeofTcConnmark][0])) } func (x *TcConnmark) Serialize() []byte { return (*(*[SizeofTcConnmark]byte)(unsafe.Pointer(x)))[:] } const ( TCA_CSUM_UNSPEC = iota TCA_CSUM_PARMS TCA_CSUM_TM TCA_CSUM_PAD TCA_CSUM_MAX = TCA_CSUM_PAD ) // struct tc_csum { // tc_gen; // __u32 update_flags; // } type TcCsum struct { TcGen UpdateFlags uint32 } func (msg *TcCsum) Len() int { return SizeofTcCsum } func DeserializeTcCsum(b []byte) *TcCsum { return (*TcCsum)(unsafe.Pointer(&b[0:SizeofTcCsum][0])) } func (x *TcCsum) Serialize() []byte { return (*(*[SizeofTcCsum]byte)(unsafe.Pointer(x)))[:] } const ( TCA_ACT_MIRRED = 8 ) const ( TCA_MIRRED_UNSPEC = iota TCA_MIRRED_TM TCA_MIRRED_PARMS TCA_MIRRED_MAX = TCA_MIRRED_PARMS ) // struct tc_mirred { // tc_gen; // int eaction; /* one of IN/EGRESS_MIRROR/REDIR */ // __u32 ifindex; /* ifindex of egress port */ // }; type TcMirred struct { TcGen Eaction int32 Ifindex uint32 } func (msg *TcMirred) Len() int { return SizeofTcMirred } func DeserializeTcMirred(b []byte) *TcMirred { return (*TcMirred)(unsafe.Pointer(&b[0:SizeofTcMirred][0])) } func (x *TcMirred) Serialize() []byte { return (*(*[SizeofTcMirred]byte)(unsafe.Pointer(x)))[:] } const ( TCA_TUNNEL_KEY_UNSPEC = iota TCA_TUNNEL_KEY_TM TCA_TUNNEL_KEY_PARMS TCA_TUNNEL_KEY_ENC_IPV4_SRC TCA_TUNNEL_KEY_ENC_IPV4_DST TCA_TUNNEL_KEY_ENC_IPV6_SRC TCA_TUNNEL_KEY_ENC_IPV6_DST TCA_TUNNEL_KEY_ENC_KEY_ID TCA_TUNNEL_KEY_PAD TCA_TUNNEL_KEY_ENC_DST_PORT TCA_TUNNEL_KEY_NO_CSUM TCA_TUNNEL_KEY_ENC_OPTS TCA_TUNNEL_KEY_ENC_TOS TCA_TUNNEL_KEY_ENC_TTL TCA_TUNNEL_KEY_MAX ) type TcTunnelKey struct { TcGen Action int32 } func (x *TcTunnelKey) Len() int { return SizeofTcTunnelKey } func DeserializeTunnelKey(b []byte) *TcTunnelKey { return (*TcTunnelKey)(unsafe.Pointer(&b[0:SizeofTcTunnelKey][0])) } func (x *TcTunnelKey) Serialize() []byte { return (*(*[SizeofTcTunnelKey]byte)(unsafe.Pointer(x)))[:] } const ( TCA_SKBEDIT_UNSPEC = iota TCA_SKBEDIT_TM TCA_SKBEDIT_PARMS TCA_SKBEDIT_PRIORITY TCA_SKBEDIT_QUEUE_MAPPING TCA_SKBEDIT_MARK TCA_SKBEDIT_PAD TCA_SKBEDIT_PTYPE TCA_SKBEDIT_MASK TCA_SKBEDIT_MAX ) type TcSkbEdit struct { TcGen } func (x *TcSkbEdit) Len() int { return SizeofTcSkbEdit } func DeserializeSkbEdit(b []byte) *TcSkbEdit { return (*TcSkbEdit)(unsafe.Pointer(&b[0:SizeofTcSkbEdit][0])) } func (x *TcSkbEdit) Serialize() []byte { return (*(*[SizeofTcSkbEdit]byte)(unsafe.Pointer(x)))[:] } // struct tc_police { // __u32 index; // int action; // __u32 limit; // __u32 burst; // __u32 mtu; // struct tc_ratespec rate; // struct tc_ratespec peakrate; // int refcnt; // int bindcnt; // __u32 capab; // }; type TcPolice struct { Index uint32 Action int32 Limit uint32 Burst uint32 Mtu uint32 Rate TcRateSpec PeakRate TcRateSpec Refcnt int32 Bindcnt int32 Capab uint32 } func (msg *TcPolice) Len() int { return SizeofTcPolice } func DeserializeTcPolice(b []byte) *TcPolice { return (*TcPolice)(unsafe.Pointer(&b[0:SizeofTcPolice][0])) } func (x *TcPolice) Serialize() []byte { return (*(*[SizeofTcPolice]byte)(unsafe.Pointer(x)))[:] } const ( TCA_FW_UNSPEC = iota TCA_FW_CLASSID TCA_FW_POLICE TCA_FW_INDEV TCA_FW_ACT TCA_FW_MASK TCA_FW_MAX = TCA_FW_MASK ) const ( TCA_MATCHALL_UNSPEC = iota TCA_MATCHALL_CLASSID TCA_MATCHALL_ACT TCA_MATCHALL_FLAGS ) const ( TCA_FQ_UNSPEC = iota TCA_FQ_PLIMIT // limit of total number of packets in queue TCA_FQ_FLOW_PLIMIT // limit of packets per flow TCA_FQ_QUANTUM // RR quantum TCA_FQ_INITIAL_QUANTUM // RR quantum for new flow TCA_FQ_RATE_ENABLE // enable/disable rate limiting TCA_FQ_FLOW_DEFAULT_RATE // obsolete do not use TCA_FQ_FLOW_MAX_RATE // per flow max rate TCA_FQ_BUCKETS_LOG // log2(number of buckets) TCA_FQ_FLOW_REFILL_DELAY // flow credit refill delay in usec TCA_FQ_ORPHAN_MASK // mask applied to orphaned skb hashes TCA_FQ_LOW_RATE_THRESHOLD // per packet delay under this rate TCA_FQ_CE_THRESHOLD // DCTCP-like CE-marking threshold TCA_FQ_TIMER_SLACK // timer slack TCA_FQ_HORIZON // time horizon in us TCA_FQ_HORIZON_DROP // drop packets beyond horizon, or cap their EDT ) const ( TCA_FQ_CODEL_UNSPEC = iota TCA_FQ_CODEL_TARGET TCA_FQ_CODEL_LIMIT TCA_FQ_CODEL_INTERVAL TCA_FQ_CODEL_ECN TCA_FQ_CODEL_FLOWS TCA_FQ_CODEL_QUANTUM TCA_FQ_CODEL_CE_THRESHOLD TCA_FQ_CODEL_DROP_BATCH_SIZE TCA_FQ_CODEL_MEMORY_LIMIT ) const ( TCA_HFSC_UNSPEC = iota TCA_HFSC_RSC TCA_HFSC_FSC TCA_HFSC_USC ) const ( TCA_FLOWER_UNSPEC = iota TCA_FLOWER_CLASSID TCA_FLOWER_INDEV TCA_FLOWER_ACT TCA_FLOWER_KEY_ETH_DST /* ETH_ALEN */ TCA_FLOWER_KEY_ETH_DST_MASK /* ETH_ALEN */ TCA_FLOWER_KEY_ETH_SRC /* ETH_ALEN */ TCA_FLOWER_KEY_ETH_SRC_MASK /* ETH_ALEN */ TCA_FLOWER_KEY_ETH_TYPE /* be16 */ TCA_FLOWER_KEY_IP_PROTO /* u8 */ TCA_FLOWER_KEY_IPV4_SRC /* be32 */ TCA_FLOWER_KEY_IPV4_SRC_MASK /* be32 */ TCA_FLOWER_KEY_IPV4_DST /* be32 */ TCA_FLOWER_KEY_IPV4_DST_MASK /* be32 */ TCA_FLOWER_KEY_IPV6_SRC /* struct in6_addr */ TCA_FLOWER_KEY_IPV6_SRC_MASK /* struct in6_addr */ TCA_FLOWER_KEY_IPV6_DST /* struct in6_addr */ TCA_FLOWER_KEY_IPV6_DST_MASK /* struct in6_addr */ TCA_FLOWER_KEY_TCP_SRC /* be16 */ TCA_FLOWER_KEY_TCP_DST /* be16 */ TCA_FLOWER_KEY_UDP_SRC /* be16 */ TCA_FLOWER_KEY_UDP_DST /* be16 */ TCA_FLOWER_FLAGS TCA_FLOWER_KEY_VLAN_ID /* be16 */ TCA_FLOWER_KEY_VLAN_PRIO /* u8 */ TCA_FLOWER_KEY_VLAN_ETH_TYPE /* be16 */ TCA_FLOWER_KEY_ENC_KEY_ID /* be32 */ TCA_FLOWER_KEY_ENC_IPV4_SRC /* be32 */ TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK /* be32 */ TCA_FLOWER_KEY_ENC_IPV4_DST /* be32 */ TCA_FLOWER_KEY_ENC_IPV4_DST_MASK /* be32 */ TCA_FLOWER_KEY_ENC_IPV6_SRC /* struct in6_addr */ TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK /* struct in6_addr */ TCA_FLOWER_KEY_ENC_IPV6_DST /* struct in6_addr */ TCA_FLOWER_KEY_ENC_IPV6_DST_MASK /* struct in6_addr */ TCA_FLOWER_KEY_TCP_SRC_MASK /* be16 */ TCA_FLOWER_KEY_TCP_DST_MASK /* be16 */ TCA_FLOWER_KEY_UDP_SRC_MASK /* be16 */ TCA_FLOWER_KEY_UDP_DST_MASK /* be16 */ TCA_FLOWER_KEY_SCTP_SRC_MASK /* be16 */ TCA_FLOWER_KEY_SCTP_DST_MASK /* be16 */ TCA_FLOWER_KEY_SCTP_SRC /* be16 */ TCA_FLOWER_KEY_SCTP_DST /* be16 */ TCA_FLOWER_KEY_ENC_UDP_SRC_PORT /* be16 */ TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK /* be16 */ TCA_FLOWER_KEY_ENC_UDP_DST_PORT /* be16 */ TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK /* be16 */ TCA_FLOWER_KEY_FLAGS /* be32 */ TCA_FLOWER_KEY_FLAGS_MASK /* be32 */ TCA_FLOWER_KEY_ICMPV4_CODE /* u8 */ TCA_FLOWER_KEY_ICMPV4_CODE_MASK /* u8 */ TCA_FLOWER_KEY_ICMPV4_TYPE /* u8 */ TCA_FLOWER_KEY_ICMPV4_TYPE_MASK /* u8 */ TCA_FLOWER_KEY_ICMPV6_CODE /* u8 */ TCA_FLOWER_KEY_ICMPV6_CODE_MASK /* u8 */ TCA_FLOWER_KEY_ICMPV6_TYPE /* u8 */ TCA_FLOWER_KEY_ICMPV6_TYPE_MASK /* u8 */ TCA_FLOWER_KEY_ARP_SIP /* be32 */ TCA_FLOWER_KEY_ARP_SIP_MASK /* be32 */ TCA_FLOWER_KEY_ARP_TIP /* be32 */ TCA_FLOWER_KEY_ARP_TIP_MASK /* be32 */ TCA_FLOWER_KEY_ARP_OP /* u8 */ TCA_FLOWER_KEY_ARP_OP_MASK /* u8 */ TCA_FLOWER_KEY_ARP_SHA /* ETH_ALEN */ TCA_FLOWER_KEY_ARP_SHA_MASK /* ETH_ALEN */ TCA_FLOWER_KEY_ARP_THA /* ETH_ALEN */ TCA_FLOWER_KEY_ARP_THA_MASK /* ETH_ALEN */ TCA_FLOWER_KEY_MPLS_TTL /* u8 - 8 bits */ TCA_FLOWER_KEY_MPLS_BOS /* u8 - 1 bit */ TCA_FLOWER_KEY_MPLS_TC /* u8 - 3 bits */ TCA_FLOWER_KEY_MPLS_LABEL /* be32 - 20 bits */ TCA_FLOWER_KEY_TCP_FLAGS /* be16 */ TCA_FLOWER_KEY_TCP_FLAGS_MASK /* be16 */ TCA_FLOWER_KEY_IP_TOS /* u8 */ TCA_FLOWER_KEY_IP_TOS_MASK /* u8 */ TCA_FLOWER_KEY_IP_TTL /* u8 */ TCA_FLOWER_KEY_IP_TTL_MASK /* u8 */ TCA_FLOWER_KEY_CVLAN_ID /* be16 */ TCA_FLOWER_KEY_CVLAN_PRIO /* u8 */ TCA_FLOWER_KEY_CVLAN_ETH_TYPE /* be16 */ TCA_FLOWER_KEY_ENC_IP_TOS /* u8 */ TCA_FLOWER_KEY_ENC_IP_TOS_MASK /* u8 */ TCA_FLOWER_KEY_ENC_IP_TTL /* u8 */ TCA_FLOWER_KEY_ENC_IP_TTL_MASK /* u8 */ TCA_FLOWER_KEY_ENC_OPTS TCA_FLOWER_KEY_ENC_OPTS_MASK __TCA_FLOWER_MAX ) const TCA_CLS_FLAGS_SKIP_HW = 1 << 0 /* don't offload filter to HW */ const TCA_CLS_FLAGS_SKIP_SW = 1 << 1 /* don't use filter in SW */ // struct tc_sfq_qopt { // unsigned quantum; /* Bytes per round allocated to flow */ // int perturb_period; /* Period of hash perturbation */ // __u32 limit; /* Maximal packets in queue */ // unsigned divisor; /* Hash divisor */ // unsigned flows; /* Maximal number of flows */ // }; type TcSfqQopt struct { Quantum uint8 Perturb int32 Limit uint32 Divisor uint8 Flows uint8 } func (x *TcSfqQopt) Len() int { return SizeofTcSfqQopt } func DeserializeTcSfqQopt(b []byte) *TcSfqQopt { return (*TcSfqQopt)(unsafe.Pointer(&b[0:SizeofTcSfqQopt][0])) } func (x *TcSfqQopt) Serialize() []byte { return (*(*[SizeofTcSfqQopt]byte)(unsafe.Pointer(x)))[:] } // struct tc_sfqred_stats { // __u32 prob_drop; /* Early drops, below max threshold */ // __u32 forced_drop; /* Early drops, after max threshold */ // __u32 prob_mark; /* Marked packets, below max threshold */ // __u32 forced_mark; /* Marked packets, after max threshold */ // __u32 prob_mark_head; /* Marked packets, below max threshold */ // __u32 forced_mark_head;/* Marked packets, after max threshold */ // }; type TcSfqRedStats struct { ProbDrop uint32 ForcedDrop uint32 ProbMark uint32 ForcedMark uint32 ProbMarkHead uint32 ForcedMarkHead uint32 } func (x *TcSfqRedStats) Len() int { return SizeofTcSfqRedStats } func DeserializeTcSfqRedStats(b []byte) *TcSfqRedStats { return (*TcSfqRedStats)(unsafe.Pointer(&b[0:SizeofTcSfqRedStats][0])) } func (x *TcSfqRedStats) Serialize() []byte { return (*(*[SizeofTcSfqRedStats]byte)(unsafe.Pointer(x)))[:] } // struct tc_sfq_qopt_v1 { // struct tc_sfq_qopt v0; // unsigned int depth; /* max number of packets per flow */ // unsigned int headdrop; // // /* SFQRED parameters */ // // __u32 limit; /* HARD maximal flow queue length (bytes) */ // __u32 qth_min; /* Min average length threshold (bytes) */ // __u32 qth_max; /* Max average length threshold (bytes) */ // unsigned char Wlog; /* log(W) */ // unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ // unsigned char Scell_log; /* cell size for idle damping */ // unsigned char flags; // __u32 max_P; /* probability, high resolution */ // // /* SFQRED stats */ // // struct tc_sfqred_stats stats; // }; type TcSfqQoptV1 struct { TcSfqQopt Depth uint32 HeadDrop uint32 Limit uint32 QthMin uint32 QthMax uint32 Wlog byte Plog byte ScellLog byte Flags byte MaxP uint32 TcSfqRedStats } func (x *TcSfqQoptV1) Len() int { return SizeofTcSfqQoptV1 } func DeserializeTcSfqQoptV1(b []byte) *TcSfqQoptV1 { return (*TcSfqQoptV1)(unsafe.Pointer(&b[0:SizeofTcSfqQoptV1][0])) } func (x *TcSfqQoptV1) Serialize() []byte { return (*(*[SizeofTcSfqQoptV1]byte)(unsafe.Pointer(x)))[:] } // IPProto represents Flower ip_proto attribute type IPProto uint8 const ( IPPROTO_TCP IPProto = unix.IPPROTO_TCP IPPROTO_UDP IPProto = unix.IPPROTO_UDP IPPROTO_SCTP IPProto = unix.IPPROTO_SCTP IPPROTO_ICMP IPProto = unix.IPPROTO_ICMP IPPROTO_ICMPV6 IPProto = unix.IPPROTO_ICMPV6 ) func (i IPProto) Serialize() []byte { arr := make([]byte, 1) arr[0] = byte(i) return arr } func (i IPProto) String() string { switch i { case IPPROTO_TCP: return "tcp" case IPPROTO_UDP: return "udp" case IPPROTO_SCTP: return "sctp" case IPPROTO_ICMP: return "icmp" case IPPROTO_ICMPV6: return "icmpv6" } return fmt.Sprintf("%d", i) } const ( MaxOffs = 128 SizeOfPeditSel = 24 SizeOfPeditKey = 24 TCA_PEDIT_KEY_EX_HTYPE = 1 TCA_PEDIT_KEY_EX_CMD = 2 ) const ( TCA_PEDIT_UNSPEC = iota TCA_PEDIT_TM TCA_PEDIT_PARMS TCA_PEDIT_PAD TCA_PEDIT_PARMS_EX TCA_PEDIT_KEYS_EX TCA_PEDIT_KEY_EX ) // /* TCA_PEDIT_KEY_EX_HDR_TYPE_NETWROK is a special case for legacy users. It // * means no specific header type - offset is relative to the network layer // */ type PeditHeaderType uint16 const ( TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK = iota TCA_PEDIT_KEY_EX_HDR_TYPE_ETH TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 TCA_PEDIT_KEY_EX_HDR_TYPE_TCP TCA_PEDIT_KEY_EX_HDR_TYPE_UDP __PEDIT_HDR_TYPE_MAX ) type PeditCmd uint16 const ( TCA_PEDIT_KEY_EX_CMD_SET = 0 TCA_PEDIT_KEY_EX_CMD_ADD = 1 ) type TcPeditSel struct { TcGen NKeys uint8 Flags uint8 } func DeserializeTcPeditKey(b []byte) *TcPeditKey { return (*TcPeditKey)(unsafe.Pointer(&b[0:SizeOfPeditKey][0])) } func DeserializeTcPedit(b []byte) (*TcPeditSel, []TcPeditKey) { x := &TcPeditSel{} copy((*(*[SizeOfPeditSel]byte)(unsafe.Pointer(x)))[:SizeOfPeditSel], b) var keys []TcPeditKey next := SizeOfPeditKey var i uint8 for i = 0; i < x.NKeys; i++ { keys = append(keys, *DeserializeTcPeditKey(b[next:])) next += SizeOfPeditKey } return x, keys } type TcPeditKey struct { Mask uint32 Val uint32 Off uint32 At uint32 OffMask uint32 Shift uint32 } type TcPeditKeyEx struct { HeaderType PeditHeaderType Cmd PeditCmd } type TcPedit struct { Sel TcPeditSel Keys []TcPeditKey KeysEx []TcPeditKeyEx Extend uint8 } func (p *TcPedit) Encode(parent *RtAttr) { parent.AddRtAttr(TCA_ACT_KIND, ZeroTerminated("pedit")) actOpts := parent.AddRtAttr(TCA_ACT_OPTIONS, nil) bbuf := bytes.NewBuffer(make([]byte, 0, int(unsafe.Sizeof(p.Sel)+unsafe.Sizeof(p.Keys)))) bbuf.Write((*(*[SizeOfPeditSel]byte)(unsafe.Pointer(&p.Sel)))[:]) for i := uint8(0); i < p.Sel.NKeys; i++ { bbuf.Write((*(*[SizeOfPeditKey]byte)(unsafe.Pointer(&p.Keys[i])))[:]) } actOpts.AddRtAttr(TCA_PEDIT_PARMS_EX, bbuf.Bytes()) exAttrs := actOpts.AddRtAttr(int(TCA_PEDIT_KEYS_EX|NLA_F_NESTED), nil) for i := uint8(0); i < p.Sel.NKeys; i++ { keyAttr := exAttrs.AddRtAttr(int(TCA_PEDIT_KEY_EX|NLA_F_NESTED), nil) htypeBuf := make([]byte, 2) cmdBuf := make([]byte, 2) NativeEndian().PutUint16(htypeBuf, uint16(p.KeysEx[i].HeaderType)) NativeEndian().PutUint16(cmdBuf, uint16(p.KeysEx[i].Cmd)) keyAttr.AddRtAttr(TCA_PEDIT_KEY_EX_HTYPE, htypeBuf) keyAttr.AddRtAttr(TCA_PEDIT_KEY_EX_CMD, cmdBuf) } } func (p *TcPedit) SetEthDst(mac net.HardwareAddr) { u32 := NativeEndian().Uint32(mac) u16 := NativeEndian().Uint16(mac[4:]) tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} tKey.Val = u32 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_ETH tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = uint32(u16) tKey.Mask = 0xffff0000 tKey.Off = 4 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_ETH tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } func (p *TcPedit) SetEthSrc(mac net.HardwareAddr) { u16 := NativeEndian().Uint16(mac) u32 := NativeEndian().Uint32(mac[2:]) tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} tKey.Val = uint32(u16) << 16 tKey.Mask = 0x0000ffff tKey.Off = 4 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_ETH tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Mask = 0 tKey.Off = 8 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_ETH tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } func (p *TcPedit) SetIPv6Src(ip6 net.IP) { u32 := NativeEndian().Uint32(ip6[:4]) tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 8 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ u32 = NativeEndian().Uint32(ip6[4:8]) tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 12 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ u32 = NativeEndian().Uint32(ip6[8:12]) tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 16 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ u32 = NativeEndian().Uint32(ip6[12:16]) tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 20 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } func (p *TcPedit) SetDstIP(ip net.IP) { if ip.To4() != nil { p.SetIPv4Dst(ip) } else { p.SetIPv6Dst(ip) } } func (p *TcPedit) SetSrcIP(ip net.IP) { if ip.To4() != nil { p.SetIPv4Src(ip) } else { p.SetIPv6Src(ip) } } func (p *TcPedit) SetIPv6Dst(ip6 net.IP) { u32 := NativeEndian().Uint32(ip6[:4]) tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 24 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ u32 = NativeEndian().Uint32(ip6[4:8]) tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 28 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ u32 = NativeEndian().Uint32(ip6[8:12]) tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 32 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ u32 = NativeEndian().Uint32(ip6[12:16]) tKey = TcPeditKey{} tKeyEx = TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 36 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP6 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } func (p *TcPedit) SetIPv4Src(ip net.IP) { u32 := NativeEndian().Uint32(ip[:4]) tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 12 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } func (p *TcPedit) SetIPv4Dst(ip net.IP) { u32 := NativeEndian().Uint32(ip[:4]) tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} tKey.Val = u32 tKey.Off = 16 tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } // SetDstPort only tcp and udp are supported to set port func (p *TcPedit) SetDstPort(dstPort uint16, protocol uint8) { tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} switch protocol { case unix.IPPROTO_TCP: tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP case unix.IPPROTO_UDP: tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_UDP default: return } tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET tKey.Val = uint32(Swap16(dstPort)) << 16 tKey.Mask = 0x0000ffff p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ } // SetSrcPort only tcp and udp are supported to set port func (p *TcPedit) SetSrcPort(srcPort uint16, protocol uint8) { tKey := TcPeditKey{} tKeyEx := TcPeditKeyEx{} switch protocol { case unix.IPPROTO_TCP: tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP case unix.IPPROTO_UDP: tKeyEx.HeaderType = TCA_PEDIT_KEY_EX_HDR_TYPE_UDP default: return } tKeyEx.Cmd = TCA_PEDIT_KEY_EX_CMD_SET tKey.Val = uint32(Swap16(srcPort)) tKey.Mask = 0xffff0000 p.Keys = append(p.Keys, tKey) p.KeysEx = append(p.KeysEx, tKeyEx) p.Sel.NKeys++ }