package netlink import ( "errors" "fmt" "github.com/vishvananda/netlink/nl" ) type Filter interface { Attrs() *FilterAttrs Type() string } // FilterAttrs represents a netlink filter. A filter is associated with a link, // has a handle and a parent. The root filter of a device should have a // parent == HANDLE_ROOT. type FilterAttrs struct { LinkIndex int Handle uint32 Parent uint32 Priority uint16 // lower is higher priority Protocol uint16 // syscall.ETH_P_* } func (q FilterAttrs) String() string { return fmt.Sprintf("{LinkIndex: %d, Handle: %s, Parent: %s, Priority: %d, Protocol: %d}", q.LinkIndex, HandleStr(q.Handle), HandleStr(q.Parent), q.Priority, q.Protocol) } type TcAct int32 const ( TC_ACT_UNSPEC TcAct = -1 TC_ACT_OK TcAct = 0 TC_ACT_RECLASSIFY TcAct = 1 TC_ACT_SHOT TcAct = 2 TC_ACT_PIPE TcAct = 3 TC_ACT_STOLEN TcAct = 4 TC_ACT_QUEUED TcAct = 5 TC_ACT_REPEAT TcAct = 6 TC_ACT_REDIRECT TcAct = 7 TC_ACT_JUMP TcAct = 0x10000000 ) func (a TcAct) String() string { switch a { case TC_ACT_UNSPEC: return "unspec" case TC_ACT_OK: return "ok" case TC_ACT_RECLASSIFY: return "reclassify" case TC_ACT_SHOT: return "shot" case TC_ACT_PIPE: return "pipe" case TC_ACT_STOLEN: return "stolen" case TC_ACT_QUEUED: return "queued" case TC_ACT_REPEAT: return "repeat" case TC_ACT_REDIRECT: return "redirect" case TC_ACT_JUMP: return "jump" } return fmt.Sprintf("0x%x", a) } type TcPolAct int32 const ( TC_POLICE_UNSPEC TcPolAct = TcPolAct(TC_ACT_UNSPEC) TC_POLICE_OK TcPolAct = TcPolAct(TC_ACT_OK) TC_POLICE_RECLASSIFY TcPolAct = TcPolAct(TC_ACT_RECLASSIFY) TC_POLICE_SHOT TcPolAct = TcPolAct(TC_ACT_SHOT) TC_POLICE_PIPE TcPolAct = TcPolAct(TC_ACT_PIPE) ) func (a TcPolAct) String() string { switch a { case TC_POLICE_UNSPEC: return "unspec" case TC_POLICE_OK: return "ok" case TC_POLICE_RECLASSIFY: return "reclassify" case TC_POLICE_SHOT: return "shot" case TC_POLICE_PIPE: return "pipe" } return fmt.Sprintf("0x%x", a) } type ActionAttrs struct { Index int Capab int Action TcAct Refcnt int Bindcnt int } func (q ActionAttrs) String() string { return fmt.Sprintf("{Index: %d, Capab: %x, Action: %s, Refcnt: %d, Bindcnt: %d}", q.Index, q.Capab, q.Action.String(), q.Refcnt, q.Bindcnt) } // Action represents an action in any supported filter. type Action interface { Attrs() *ActionAttrs Type() string } type GenericAction struct { ActionAttrs } func (action *GenericAction) Type() string { return "generic" } func (action *GenericAction) Attrs() *ActionAttrs { return &action.ActionAttrs } type BpfAction struct { ActionAttrs Fd int Name string } func (action *BpfAction) Type() string { return "bpf" } func (action *BpfAction) Attrs() *ActionAttrs { return &action.ActionAttrs } type MirredAct uint8 func (a MirredAct) String() string { switch a { case TCA_EGRESS_REDIR: return "egress redir" case TCA_EGRESS_MIRROR: return "egress mirror" case TCA_INGRESS_REDIR: return "ingress redir" case TCA_INGRESS_MIRROR: return "ingress mirror" } return "unknown" } const ( TCA_EGRESS_REDIR MirredAct = 1 /* packet redirect to EGRESS*/ TCA_EGRESS_MIRROR MirredAct = 2 /* mirror packet to EGRESS */ TCA_INGRESS_REDIR MirredAct = 3 /* packet redirect to INGRESS*/ TCA_INGRESS_MIRROR MirredAct = 4 /* mirror packet to INGRESS */ ) type MirredAction struct { ActionAttrs MirredAction MirredAct Ifindex int } func (action *MirredAction) Type() string { return "mirred" } func (action *MirredAction) Attrs() *ActionAttrs { return &action.ActionAttrs } func NewMirredAction(redirIndex int) *MirredAction { return &MirredAction{ ActionAttrs: ActionAttrs{ Action: TC_ACT_STOLEN, }, MirredAction: TCA_EGRESS_REDIR, Ifindex: redirIndex, } } // U32 filters on many packet related properties type U32 struct { FilterAttrs ClassId uint32 RedirIndex int Actions []Action } func (filter *U32) Attrs() *FilterAttrs { return &filter.FilterAttrs } func (filter *U32) Type() string { return "u32" } type FilterFwAttrs struct { ClassId uint32 InDev string Mask uint32 Index uint32 Buffer uint32 Mtu uint32 Mpu uint16 Rate uint32 AvRate uint32 PeakRate uint32 Action TcPolAct Overhead uint16 LinkLayer int } // Fw filter filters on firewall marks type Fw struct { FilterAttrs ClassId uint32 // TODO remove nl type from interface Police nl.TcPolice InDev string // TODO Action Mask uint32 AvRate uint32 Rtab [256]uint32 Ptab [256]uint32 } func NewFw(attrs FilterAttrs, fattrs FilterFwAttrs) (*Fw, error) { var rtab [256]uint32 var ptab [256]uint32 rcellLog := -1 pcellLog := -1 avrate := fattrs.AvRate / 8 police := nl.TcPolice{} police.Rate.Rate = fattrs.Rate / 8 police.PeakRate.Rate = fattrs.PeakRate / 8 buffer := fattrs.Buffer linklayer := nl.LINKLAYER_ETHERNET if fattrs.LinkLayer != nl.LINKLAYER_UNSPEC { linklayer = fattrs.LinkLayer } police.Action = int32(fattrs.Action) if police.Rate.Rate != 0 { police.Rate.Mpu = fattrs.Mpu police.Rate.Overhead = fattrs.Overhead if CalcRtable(&police.Rate, rtab, rcellLog, fattrs.Mtu, linklayer) < 0 { return nil, errors.New("TBF: failed to calculate rate table") } police.Burst = uint32(Xmittime(uint64(police.Rate.Rate), uint32(buffer))) } police.Mtu = fattrs.Mtu if police.PeakRate.Rate != 0 { police.PeakRate.Mpu = fattrs.Mpu police.PeakRate.Overhead = fattrs.Overhead if CalcRtable(&police.PeakRate, ptab, pcellLog, fattrs.Mtu, linklayer) < 0 { return nil, errors.New("POLICE: failed to calculate peak rate table") } } return &Fw{ FilterAttrs: attrs, ClassId: fattrs.ClassId, InDev: fattrs.InDev, Mask: fattrs.Mask, Police: police, AvRate: avrate, Rtab: rtab, Ptab: ptab, }, nil } func (filter *Fw) Attrs() *FilterAttrs { return &filter.FilterAttrs } func (filter *Fw) Type() string { return "fw" } type BpfFilter struct { FilterAttrs ClassId uint32 Fd int Name string DirectAction bool } func (filter *BpfFilter) Type() string { return "bpf" } func (filter *BpfFilter) Attrs() *FilterAttrs { return &filter.FilterAttrs } // GenericFilter filters represent types that are not currently understood // by this netlink library. type GenericFilter struct { FilterAttrs FilterType string } func (filter *GenericFilter) Attrs() *FilterAttrs { return &filter.FilterAttrs } func (filter *GenericFilter) Type() string { return filter.FilterType }