github.com/vishvananda/netlink@v1.3.0/filter_linux.go (about)

     1  package netlink
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"encoding/hex"
     7  	"errors"
     8  	"fmt"
     9  	"net"
    10  	"syscall"
    11  
    12  	"github.com/vishvananda/netlink/nl"
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  // Constants used in TcU32Sel.Flags.
    17  const (
    18  	TC_U32_TERMINAL  = nl.TC_U32_TERMINAL
    19  	TC_U32_OFFSET    = nl.TC_U32_OFFSET
    20  	TC_U32_VAROFFSET = nl.TC_U32_VAROFFSET
    21  	TC_U32_EAT       = nl.TC_U32_EAT
    22  )
    23  
    24  // Sel of the U32 filters that contains multiple TcU32Key. This is the type
    25  // alias and the frontend representation of nl.TcU32Sel. It is serialized into
    26  // canonical nl.TcU32Sel with the appropriate endianness.
    27  type TcU32Sel = nl.TcU32Sel
    28  
    29  // TcU32Key contained of Sel in the U32 filters. This is the type alias and the
    30  // frontend representation of nl.TcU32Key. It is serialized into chanonical
    31  // nl.TcU32Sel with the appropriate endianness.
    32  type TcU32Key = nl.TcU32Key
    33  
    34  // U32 filters on many packet related properties
    35  type U32 struct {
    36  	FilterAttrs
    37  	ClassId    uint32
    38  	Divisor    uint32 // Divisor MUST be power of 2.
    39  	Hash       uint32
    40  	Link       uint32
    41  	RedirIndex int
    42  	Sel        *TcU32Sel
    43  	Actions    []Action
    44  	Police     *PoliceAction
    45  }
    46  
    47  func (filter *U32) Attrs() *FilterAttrs {
    48  	return &filter.FilterAttrs
    49  }
    50  
    51  func (filter *U32) Type() string {
    52  	return "u32"
    53  }
    54  
    55  type Flower struct {
    56  	FilterAttrs
    57  	DestIP        net.IP
    58  	DestIPMask    net.IPMask
    59  	SrcIP         net.IP
    60  	SrcIPMask     net.IPMask
    61  	EthType       uint16
    62  	EncDestIP     net.IP
    63  	EncDestIPMask net.IPMask
    64  	EncSrcIP      net.IP
    65  	EncSrcIPMask  net.IPMask
    66  	EncDestPort   uint16
    67  	EncKeyId      uint32
    68  	SkipHw        bool
    69  	SkipSw        bool
    70  	IPProto       *nl.IPProto
    71  	DestPort      uint16
    72  	SrcPort       uint16
    73  
    74  	Actions []Action
    75  }
    76  
    77  func (filter *Flower) Attrs() *FilterAttrs {
    78  	return &filter.FilterAttrs
    79  }
    80  
    81  func (filter *Flower) Type() string {
    82  	return "flower"
    83  }
    84  
    85  func (filter *Flower) encodeIP(parent *nl.RtAttr, ip net.IP, mask net.IPMask, v4Type, v6Type int, v4MaskType, v6MaskType int) {
    86  	ipType := v4Type
    87  	maskType := v4MaskType
    88  
    89  	encodeMask := mask
    90  	if mask == nil {
    91  		encodeMask = net.CIDRMask(32, 32)
    92  	}
    93  	v4IP := ip.To4()
    94  	if v4IP == nil {
    95  		ipType = v6Type
    96  		maskType = v6MaskType
    97  		if mask == nil {
    98  			encodeMask = net.CIDRMask(128, 128)
    99  		}
   100  	} else {
   101  		ip = v4IP
   102  	}
   103  
   104  	parent.AddRtAttr(ipType, ip)
   105  	parent.AddRtAttr(maskType, encodeMask)
   106  }
   107  
   108  func (filter *Flower) encode(parent *nl.RtAttr) error {
   109  	if filter.EthType != 0 {
   110  		parent.AddRtAttr(nl.TCA_FLOWER_KEY_ETH_TYPE, htons(filter.EthType))
   111  	}
   112  	if filter.SrcIP != nil {
   113  		filter.encodeIP(parent, filter.SrcIP, filter.SrcIPMask,
   114  			nl.TCA_FLOWER_KEY_IPV4_SRC, nl.TCA_FLOWER_KEY_IPV6_SRC,
   115  			nl.TCA_FLOWER_KEY_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_IPV6_SRC_MASK)
   116  	}
   117  	if filter.DestIP != nil {
   118  		filter.encodeIP(parent, filter.DestIP, filter.DestIPMask,
   119  			nl.TCA_FLOWER_KEY_IPV4_DST, nl.TCA_FLOWER_KEY_IPV6_DST,
   120  			nl.TCA_FLOWER_KEY_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_IPV6_DST_MASK)
   121  	}
   122  	if filter.EncSrcIP != nil {
   123  		filter.encodeIP(parent, filter.EncSrcIP, filter.EncSrcIPMask,
   124  			nl.TCA_FLOWER_KEY_ENC_IPV4_SRC, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC,
   125  			nl.TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK)
   126  	}
   127  	if filter.EncDestIP != nil {
   128  		filter.encodeIP(parent, filter.EncDestIP, filter.EncSrcIPMask,
   129  			nl.TCA_FLOWER_KEY_ENC_IPV4_DST, nl.TCA_FLOWER_KEY_ENC_IPV6_DST,
   130  			nl.TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_DST_MASK)
   131  	}
   132  	if filter.EncDestPort != 0 {
   133  		parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_UDP_DST_PORT, htons(filter.EncDestPort))
   134  	}
   135  	if filter.EncKeyId != 0 {
   136  		parent.AddRtAttr(nl.TCA_FLOWER_KEY_ENC_KEY_ID, htonl(filter.EncKeyId))
   137  	}
   138  	if filter.IPProto != nil {
   139  		ipproto := *filter.IPProto
   140  		parent.AddRtAttr(nl.TCA_FLOWER_KEY_IP_PROTO, ipproto.Serialize())
   141  		if filter.SrcPort != 0 {
   142  			switch ipproto {
   143  			case nl.IPPROTO_TCP:
   144  				parent.AddRtAttr(nl.TCA_FLOWER_KEY_TCP_SRC, htons(filter.SrcPort))
   145  			case nl.IPPROTO_UDP:
   146  				parent.AddRtAttr(nl.TCA_FLOWER_KEY_UDP_SRC, htons(filter.SrcPort))
   147  			case nl.IPPROTO_SCTP:
   148  				parent.AddRtAttr(nl.TCA_FLOWER_KEY_SCTP_SRC, htons(filter.SrcPort))
   149  			}
   150  		}
   151  		if filter.DestPort != 0 {
   152  			switch ipproto {
   153  			case nl.IPPROTO_TCP:
   154  				parent.AddRtAttr(nl.TCA_FLOWER_KEY_TCP_DST, htons(filter.DestPort))
   155  			case nl.IPPROTO_UDP:
   156  				parent.AddRtAttr(nl.TCA_FLOWER_KEY_UDP_DST, htons(filter.DestPort))
   157  			case nl.IPPROTO_SCTP:
   158  				parent.AddRtAttr(nl.TCA_FLOWER_KEY_SCTP_DST, htons(filter.DestPort))
   159  			}
   160  		}
   161  	}
   162  
   163  	var flags uint32 = 0
   164  	if filter.SkipHw {
   165  		flags |= nl.TCA_CLS_FLAGS_SKIP_HW
   166  	}
   167  	if filter.SkipSw {
   168  		flags |= nl.TCA_CLS_FLAGS_SKIP_SW
   169  	}
   170  	parent.AddRtAttr(nl.TCA_FLOWER_FLAGS, htonl(flags))
   171  
   172  	actionsAttr := parent.AddRtAttr(nl.TCA_FLOWER_ACT, nil)
   173  	if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
   174  		return err
   175  	}
   176  	return nil
   177  }
   178  
   179  func (filter *Flower) decode(data []syscall.NetlinkRouteAttr) error {
   180  	for _, datum := range data {
   181  		switch datum.Attr.Type {
   182  		case nl.TCA_FLOWER_KEY_ETH_TYPE:
   183  			filter.EthType = ntohs(datum.Value)
   184  		case nl.TCA_FLOWER_KEY_IPV4_SRC, nl.TCA_FLOWER_KEY_IPV6_SRC:
   185  			filter.SrcIP = datum.Value
   186  		case nl.TCA_FLOWER_KEY_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_IPV6_SRC_MASK:
   187  			filter.SrcIPMask = datum.Value
   188  		case nl.TCA_FLOWER_KEY_IPV4_DST, nl.TCA_FLOWER_KEY_IPV6_DST:
   189  			filter.DestIP = datum.Value
   190  		case nl.TCA_FLOWER_KEY_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_IPV6_DST_MASK:
   191  			filter.DestIPMask = datum.Value
   192  		case nl.TCA_FLOWER_KEY_ENC_IPV4_SRC, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC:
   193  			filter.EncSrcIP = datum.Value
   194  		case nl.TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK:
   195  			filter.EncSrcIPMask = datum.Value
   196  		case nl.TCA_FLOWER_KEY_ENC_IPV4_DST, nl.TCA_FLOWER_KEY_ENC_IPV6_DST:
   197  			filter.EncDestIP = datum.Value
   198  		case nl.TCA_FLOWER_KEY_ENC_IPV4_DST_MASK, nl.TCA_FLOWER_KEY_ENC_IPV6_DST_MASK:
   199  			filter.EncDestIPMask = datum.Value
   200  		case nl.TCA_FLOWER_KEY_ENC_UDP_DST_PORT:
   201  			filter.EncDestPort = ntohs(datum.Value)
   202  		case nl.TCA_FLOWER_KEY_ENC_KEY_ID:
   203  			filter.EncKeyId = ntohl(datum.Value)
   204  		case nl.TCA_FLOWER_KEY_IP_PROTO:
   205  			val := new(nl.IPProto)
   206  			*val = nl.IPProto(datum.Value[0])
   207  			filter.IPProto = val
   208  		case nl.TCA_FLOWER_KEY_TCP_SRC, nl.TCA_FLOWER_KEY_UDP_SRC, nl.TCA_FLOWER_KEY_SCTP_SRC:
   209  			filter.SrcPort = ntohs(datum.Value)
   210  		case nl.TCA_FLOWER_KEY_TCP_DST, nl.TCA_FLOWER_KEY_UDP_DST, nl.TCA_FLOWER_KEY_SCTP_DST:
   211  			filter.DestPort = ntohs(datum.Value)
   212  		case nl.TCA_FLOWER_ACT:
   213  			tables, err := nl.ParseRouteAttr(datum.Value)
   214  			if err != nil {
   215  				return err
   216  			}
   217  			filter.Actions, err = parseActions(tables)
   218  			if err != nil {
   219  				return err
   220  			}
   221  		case nl.TCA_FLOWER_FLAGS:
   222  			attr := nl.DeserializeUint32Bitfield(datum.Value)
   223  			skipSw := attr.Value & nl.TCA_CLS_FLAGS_SKIP_HW
   224  			skipHw := attr.Value & nl.TCA_CLS_FLAGS_SKIP_SW
   225  			if skipSw != 0 {
   226  				filter.SkipSw = true
   227  			}
   228  			if skipHw != 0 {
   229  				filter.SkipHw = true
   230  			}
   231  		}
   232  	}
   233  	return nil
   234  }
   235  
   236  // FilterDel will delete a filter from the system.
   237  // Equivalent to: `tc filter del $filter`
   238  func FilterDel(filter Filter) error {
   239  	return pkgHandle.FilterDel(filter)
   240  }
   241  
   242  // FilterDel will delete a filter from the system.
   243  // Equivalent to: `tc filter del $filter`
   244  func (h *Handle) FilterDel(filter Filter) error {
   245  	return h.filterModify(filter, unix.RTM_DELTFILTER, 0)
   246  }
   247  
   248  // FilterAdd will add a filter to the system.
   249  // Equivalent to: `tc filter add $filter`
   250  func FilterAdd(filter Filter) error {
   251  	return pkgHandle.FilterAdd(filter)
   252  }
   253  
   254  // FilterAdd will add a filter to the system.
   255  // Equivalent to: `tc filter add $filter`
   256  func (h *Handle) FilterAdd(filter Filter) error {
   257  	return h.filterModify(filter, unix.RTM_NEWTFILTER, unix.NLM_F_CREATE|unix.NLM_F_EXCL)
   258  }
   259  
   260  // FilterReplace will replace a filter.
   261  // Equivalent to: `tc filter replace $filter`
   262  func FilterReplace(filter Filter) error {
   263  	return pkgHandle.FilterReplace(filter)
   264  }
   265  
   266  // FilterReplace will replace a filter.
   267  // Equivalent to: `tc filter replace $filter`
   268  func (h *Handle) FilterReplace(filter Filter) error {
   269  	return h.filterModify(filter, unix.RTM_NEWTFILTER, unix.NLM_F_CREATE)
   270  }
   271  
   272  func (h *Handle) filterModify(filter Filter, proto, flags int) error {
   273  	req := h.newNetlinkRequest(proto, flags|unix.NLM_F_ACK)
   274  	base := filter.Attrs()
   275  	msg := &nl.TcMsg{
   276  		Family:  nl.FAMILY_ALL,
   277  		Ifindex: int32(base.LinkIndex),
   278  		Handle:  base.Handle,
   279  		Parent:  base.Parent,
   280  		Info:    MakeHandle(base.Priority, nl.Swap16(base.Protocol)),
   281  	}
   282  	req.AddData(msg)
   283  	if filter.Attrs().Chain != nil {
   284  		req.AddData(nl.NewRtAttr(nl.TCA_CHAIN, nl.Uint32Attr(*filter.Attrs().Chain)))
   285  	}
   286  	req.AddData(nl.NewRtAttr(nl.TCA_KIND, nl.ZeroTerminated(filter.Type())))
   287  
   288  	options := nl.NewRtAttr(nl.TCA_OPTIONS, nil)
   289  
   290  	switch filter := filter.(type) {
   291  	case *U32:
   292  		sel := filter.Sel
   293  		if sel == nil {
   294  			// match all
   295  			sel = &nl.TcU32Sel{
   296  				Nkeys: 1,
   297  				Flags: nl.TC_U32_TERMINAL,
   298  			}
   299  			sel.Keys = append(sel.Keys, nl.TcU32Key{})
   300  		}
   301  
   302  		if native != networkOrder {
   303  			// Copy TcU32Sel.
   304  			cSel := *sel
   305  			keys := make([]nl.TcU32Key, cap(sel.Keys))
   306  			copy(keys, sel.Keys)
   307  			cSel.Keys = keys
   308  			sel = &cSel
   309  
   310  			// Handle the endianness of attributes
   311  			sel.Offmask = native.Uint16(htons(sel.Offmask))
   312  			sel.Hmask = native.Uint32(htonl(sel.Hmask))
   313  			for i, key := range sel.Keys {
   314  				sel.Keys[i].Mask = native.Uint32(htonl(key.Mask))
   315  				sel.Keys[i].Val = native.Uint32(htonl(key.Val))
   316  			}
   317  		}
   318  		sel.Nkeys = uint8(len(sel.Keys))
   319  		options.AddRtAttr(nl.TCA_U32_SEL, sel.Serialize())
   320  		if filter.ClassId != 0 {
   321  			options.AddRtAttr(nl.TCA_U32_CLASSID, nl.Uint32Attr(filter.ClassId))
   322  		}
   323  		if filter.Divisor != 0 {
   324  			if (filter.Divisor-1)&filter.Divisor != 0 {
   325  				return fmt.Errorf("illegal divisor %d. Must be a power of 2", filter.Divisor)
   326  			}
   327  			options.AddRtAttr(nl.TCA_U32_DIVISOR, nl.Uint32Attr(filter.Divisor))
   328  		}
   329  		if filter.Hash != 0 {
   330  			options.AddRtAttr(nl.TCA_U32_HASH, nl.Uint32Attr(filter.Hash))
   331  		}
   332  		if filter.Link != 0 {
   333  			options.AddRtAttr(nl.TCA_U32_LINK, nl.Uint32Attr(filter.Link))
   334  		}
   335  		if filter.Police != nil {
   336  			police := options.AddRtAttr(nl.TCA_U32_POLICE, nil)
   337  			if err := encodePolice(police, filter.Police); err != nil {
   338  				return err
   339  			}
   340  		}
   341  		actionsAttr := options.AddRtAttr(nl.TCA_U32_ACT, nil)
   342  		// backwards compatibility
   343  		if filter.RedirIndex != 0 {
   344  			filter.Actions = append([]Action{NewMirredAction(filter.RedirIndex)}, filter.Actions...)
   345  		}
   346  		if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
   347  			return err
   348  		}
   349  	case *FwFilter:
   350  		if filter.Mask != 0 {
   351  			b := make([]byte, 4)
   352  			native.PutUint32(b, filter.Mask)
   353  			options.AddRtAttr(nl.TCA_FW_MASK, b)
   354  		}
   355  		if filter.InDev != "" {
   356  			options.AddRtAttr(nl.TCA_FW_INDEV, nl.ZeroTerminated(filter.InDev))
   357  		}
   358  		if filter.Police != nil {
   359  			police := options.AddRtAttr(nl.TCA_FW_POLICE, nil)
   360  			if err := encodePolice(police, filter.Police); err != nil {
   361  				return err
   362  			}
   363  		}
   364  		if filter.ClassId != 0 {
   365  			b := make([]byte, 4)
   366  			native.PutUint32(b, filter.ClassId)
   367  			options.AddRtAttr(nl.TCA_FW_CLASSID, b)
   368  		}
   369  		actionsAttr := options.AddRtAttr(nl.TCA_FW_ACT, nil)
   370  		if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
   371  			return err
   372  		}
   373  	case *BpfFilter:
   374  		var bpfFlags uint32
   375  		if filter.ClassId != 0 {
   376  			options.AddRtAttr(nl.TCA_BPF_CLASSID, nl.Uint32Attr(filter.ClassId))
   377  		}
   378  		if filter.Fd >= 0 {
   379  			options.AddRtAttr(nl.TCA_BPF_FD, nl.Uint32Attr((uint32(filter.Fd))))
   380  		}
   381  		if filter.Name != "" {
   382  			options.AddRtAttr(nl.TCA_BPF_NAME, nl.ZeroTerminated(filter.Name))
   383  		}
   384  		if filter.DirectAction {
   385  			bpfFlags |= nl.TCA_BPF_FLAG_ACT_DIRECT
   386  		}
   387  		options.AddRtAttr(nl.TCA_BPF_FLAGS, nl.Uint32Attr(bpfFlags))
   388  	case *MatchAll:
   389  		actionsAttr := options.AddRtAttr(nl.TCA_MATCHALL_ACT, nil)
   390  		if err := EncodeActions(actionsAttr, filter.Actions); err != nil {
   391  			return err
   392  		}
   393  		if filter.ClassId != 0 {
   394  			options.AddRtAttr(nl.TCA_MATCHALL_CLASSID, nl.Uint32Attr(filter.ClassId))
   395  		}
   396  	case *Flower:
   397  		if err := filter.encode(options); err != nil {
   398  			return err
   399  		}
   400  	}
   401  	req.AddData(options)
   402  	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
   403  	return err
   404  }
   405  
   406  // FilterList gets a list of filters in the system.
   407  // Equivalent to: `tc filter show`.
   408  // Generally returns nothing if link and parent are not specified.
   409  func FilterList(link Link, parent uint32) ([]Filter, error) {
   410  	return pkgHandle.FilterList(link, parent)
   411  }
   412  
   413  // FilterList gets a list of filters in the system.
   414  // Equivalent to: `tc filter show`.
   415  // Generally returns nothing if link and parent are not specified.
   416  func (h *Handle) FilterList(link Link, parent uint32) ([]Filter, error) {
   417  	req := h.newNetlinkRequest(unix.RTM_GETTFILTER, unix.NLM_F_DUMP)
   418  	msg := &nl.TcMsg{
   419  		Family: nl.FAMILY_ALL,
   420  		Parent: parent,
   421  	}
   422  	if link != nil {
   423  		base := link.Attrs()
   424  		h.ensureIndex(base)
   425  		msg.Ifindex = int32(base.Index)
   426  	}
   427  	req.AddData(msg)
   428  
   429  	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWTFILTER)
   430  	if err != nil {
   431  		return nil, err
   432  	}
   433  
   434  	var res []Filter
   435  	for _, m := range msgs {
   436  		msg := nl.DeserializeTcMsg(m)
   437  
   438  		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
   439  		if err != nil {
   440  			return nil, err
   441  		}
   442  
   443  		base := FilterAttrs{
   444  			LinkIndex: int(msg.Ifindex),
   445  			Handle:    msg.Handle,
   446  			Parent:    msg.Parent,
   447  		}
   448  		base.Priority, base.Protocol = MajorMinor(msg.Info)
   449  		base.Protocol = nl.Swap16(base.Protocol)
   450  
   451  		var filter Filter
   452  		filterType := ""
   453  		detailed := false
   454  		for _, attr := range attrs {
   455  			switch attr.Attr.Type {
   456  			case nl.TCA_KIND:
   457  				filterType = string(attr.Value[:len(attr.Value)-1])
   458  				switch filterType {
   459  				case "u32":
   460  					filter = &U32{}
   461  				case "fw":
   462  					filter = &FwFilter{}
   463  				case "bpf":
   464  					filter = &BpfFilter{}
   465  				case "matchall":
   466  					filter = &MatchAll{}
   467  				case "flower":
   468  					filter = &Flower{}
   469  				default:
   470  					filter = &GenericFilter{FilterType: filterType}
   471  				}
   472  			case nl.TCA_OPTIONS:
   473  				data, err := nl.ParseRouteAttr(attr.Value)
   474  				if err != nil {
   475  					return nil, err
   476  				}
   477  				switch filterType {
   478  				case "u32":
   479  					detailed, err = parseU32Data(filter, data)
   480  					if err != nil {
   481  						return nil, err
   482  					}
   483  				case "fw":
   484  					detailed, err = parseFwData(filter, data)
   485  					if err != nil {
   486  						return nil, err
   487  					}
   488  				case "bpf":
   489  					detailed, err = parseBpfData(filter, data)
   490  					if err != nil {
   491  						return nil, err
   492  					}
   493  				case "matchall":
   494  					detailed, err = parseMatchAllData(filter, data)
   495  					if err != nil {
   496  						return nil, err
   497  					}
   498  				case "flower":
   499  					detailed, err = parseFlowerData(filter, data)
   500  					if err != nil {
   501  						return nil, err
   502  					}
   503  				default:
   504  					detailed = true
   505  				}
   506  			case nl.TCA_CHAIN:
   507  				val := new(uint32)
   508  				*val = native.Uint32(attr.Value)
   509  				base.Chain = val
   510  			}
   511  		}
   512  		// only return the detailed version of the filter
   513  		if detailed {
   514  			*filter.Attrs() = base
   515  			res = append(res, filter)
   516  		}
   517  	}
   518  
   519  	return res, nil
   520  }
   521  
   522  func toTcGen(attrs *ActionAttrs, tcgen *nl.TcGen) {
   523  	tcgen.Index = uint32(attrs.Index)
   524  	tcgen.Capab = uint32(attrs.Capab)
   525  	tcgen.Action = int32(attrs.Action)
   526  	tcgen.Refcnt = int32(attrs.Refcnt)
   527  	tcgen.Bindcnt = int32(attrs.Bindcnt)
   528  }
   529  
   530  func toAttrs(tcgen *nl.TcGen, attrs *ActionAttrs) {
   531  	attrs.Index = int(tcgen.Index)
   532  	attrs.Capab = int(tcgen.Capab)
   533  	attrs.Action = TcAct(tcgen.Action)
   534  	attrs.Refcnt = int(tcgen.Refcnt)
   535  	attrs.Bindcnt = int(tcgen.Bindcnt)
   536  }
   537  
   538  func toTimeStamp(tcf *nl.Tcf) *ActionTimestamp {
   539  	return &ActionTimestamp{
   540  		Installed: tcf.Install,
   541  		LastUsed:  tcf.LastUse,
   542  		Expires:   tcf.Expires,
   543  		FirstUsed: tcf.FirstUse}
   544  }
   545  
   546  func encodePolice(attr *nl.RtAttr, action *PoliceAction) error {
   547  	var rtab [256]uint32
   548  	var ptab [256]uint32
   549  	police := nl.TcPolice{}
   550  	police.Index = uint32(action.Attrs().Index)
   551  	police.Bindcnt = int32(action.Attrs().Bindcnt)
   552  	police.Capab = uint32(action.Attrs().Capab)
   553  	police.Refcnt = int32(action.Attrs().Refcnt)
   554  	police.Rate.Rate = action.Rate
   555  	police.PeakRate.Rate = action.PeakRate
   556  	police.Action = int32(action.ExceedAction)
   557  
   558  	if police.Rate.Rate != 0 {
   559  		police.Rate.Mpu = action.Mpu
   560  		police.Rate.Overhead = action.Overhead
   561  		if CalcRtable(&police.Rate, rtab[:], action.RCellLog, action.Mtu, action.LinkLayer) < 0 {
   562  			return errors.New("TBF: failed to calculate rate table")
   563  		}
   564  		police.Burst = Xmittime(uint64(police.Rate.Rate), action.Burst)
   565  	}
   566  
   567  	police.Mtu = action.Mtu
   568  	if police.PeakRate.Rate != 0 {
   569  		police.PeakRate.Mpu = action.Mpu
   570  		police.PeakRate.Overhead = action.Overhead
   571  		if CalcRtable(&police.PeakRate, ptab[:], action.PCellLog, action.Mtu, action.LinkLayer) < 0 {
   572  			return errors.New("POLICE: failed to calculate peak rate table")
   573  		}
   574  	}
   575  
   576  	attr.AddRtAttr(nl.TCA_POLICE_TBF, police.Serialize())
   577  	if police.Rate.Rate != 0 {
   578  		attr.AddRtAttr(nl.TCA_POLICE_RATE, SerializeRtab(rtab))
   579  	}
   580  	if police.PeakRate.Rate != 0 {
   581  		attr.AddRtAttr(nl.TCA_POLICE_PEAKRATE, SerializeRtab(ptab))
   582  	}
   583  	if action.AvRate != 0 {
   584  		attr.AddRtAttr(nl.TCA_POLICE_AVRATE, nl.Uint32Attr(action.AvRate))
   585  	}
   586  	if action.NotExceedAction != 0 {
   587  		attr.AddRtAttr(nl.TCA_POLICE_RESULT, nl.Uint32Attr(uint32(action.NotExceedAction)))
   588  	}
   589  
   590  	return nil
   591  }
   592  
   593  func EncodeActions(attr *nl.RtAttr, actions []Action) error {
   594  	tabIndex := int(nl.TCA_ACT_TAB)
   595  
   596  	for _, action := range actions {
   597  		switch action := action.(type) {
   598  		default:
   599  			return fmt.Errorf("unknown action type %s", action.Type())
   600  		case *PoliceAction:
   601  			table := attr.AddRtAttr(tabIndex, nil)
   602  			tabIndex++
   603  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("police"))
   604  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   605  			if err := encodePolice(aopts, action); err != nil {
   606  				return err
   607  			}
   608  		case *MirredAction:
   609  			table := attr.AddRtAttr(tabIndex, nil)
   610  			tabIndex++
   611  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("mirred"))
   612  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   613  			mirred := nl.TcMirred{
   614  				Eaction: int32(action.MirredAction),
   615  				Ifindex: uint32(action.Ifindex),
   616  			}
   617  			toTcGen(action.Attrs(), &mirred.TcGen)
   618  			aopts.AddRtAttr(nl.TCA_MIRRED_PARMS, mirred.Serialize())
   619  		case *TunnelKeyAction:
   620  			table := attr.AddRtAttr(tabIndex, nil)
   621  			tabIndex++
   622  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("tunnel_key"))
   623  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   624  			tun := nl.TcTunnelKey{
   625  				Action: int32(action.Action),
   626  			}
   627  			toTcGen(action.Attrs(), &tun.TcGen)
   628  			aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_PARMS, tun.Serialize())
   629  			if action.Action == TCA_TUNNEL_KEY_SET {
   630  				aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_KEY_ID, htonl(action.KeyID))
   631  				if v4 := action.SrcAddr.To4(); v4 != nil {
   632  					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC, v4[:])
   633  				} else if v6 := action.SrcAddr.To16(); v6 != nil {
   634  					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, v6[:])
   635  				} else {
   636  					return fmt.Errorf("invalid src addr %s for tunnel_key action", action.SrcAddr)
   637  				}
   638  				if v4 := action.DstAddr.To4(); v4 != nil {
   639  					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV4_DST, v4[:])
   640  				} else if v6 := action.DstAddr.To16(); v6 != nil {
   641  					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, v6[:])
   642  				} else {
   643  					return fmt.Errorf("invalid dst addr %s for tunnel_key action", action.DstAddr)
   644  				}
   645  				if action.DestPort != 0 {
   646  					aopts.AddRtAttr(nl.TCA_TUNNEL_KEY_ENC_DST_PORT, htons(action.DestPort))
   647  				}
   648  			}
   649  		case *SkbEditAction:
   650  			table := attr.AddRtAttr(tabIndex, nil)
   651  			tabIndex++
   652  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("skbedit"))
   653  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   654  			skbedit := nl.TcSkbEdit{}
   655  			toTcGen(action.Attrs(), &skbedit.TcGen)
   656  			aopts.AddRtAttr(nl.TCA_SKBEDIT_PARMS, skbedit.Serialize())
   657  			if action.QueueMapping != nil {
   658  				aopts.AddRtAttr(nl.TCA_SKBEDIT_QUEUE_MAPPING, nl.Uint16Attr(*action.QueueMapping))
   659  			}
   660  			if action.Priority != nil {
   661  				aopts.AddRtAttr(nl.TCA_SKBEDIT_PRIORITY, nl.Uint32Attr(*action.Priority))
   662  			}
   663  			if action.PType != nil {
   664  				aopts.AddRtAttr(nl.TCA_SKBEDIT_PTYPE, nl.Uint16Attr(*action.PType))
   665  			}
   666  			if action.Mark != nil {
   667  				aopts.AddRtAttr(nl.TCA_SKBEDIT_MARK, nl.Uint32Attr(*action.Mark))
   668  			}
   669  			if action.Mask != nil {
   670  				aopts.AddRtAttr(nl.TCA_SKBEDIT_MASK, nl.Uint32Attr(*action.Mask))
   671  			}
   672  		case *ConnmarkAction:
   673  			table := attr.AddRtAttr(tabIndex, nil)
   674  			tabIndex++
   675  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("connmark"))
   676  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   677  			connmark := nl.TcConnmark{
   678  				Zone: action.Zone,
   679  			}
   680  			toTcGen(action.Attrs(), &connmark.TcGen)
   681  			aopts.AddRtAttr(nl.TCA_CONNMARK_PARMS, connmark.Serialize())
   682  		case *CsumAction:
   683  			table := attr.AddRtAttr(tabIndex, nil)
   684  			tabIndex++
   685  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("csum"))
   686  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   687  			csum := nl.TcCsum{
   688  				UpdateFlags: uint32(action.UpdateFlags),
   689  			}
   690  			toTcGen(action.Attrs(), &csum.TcGen)
   691  			aopts.AddRtAttr(nl.TCA_CSUM_PARMS, csum.Serialize())
   692  		case *BpfAction:
   693  			table := attr.AddRtAttr(tabIndex, nil)
   694  			tabIndex++
   695  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("bpf"))
   696  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   697  			gen := nl.TcGen{}
   698  			toTcGen(action.Attrs(), &gen)
   699  			aopts.AddRtAttr(nl.TCA_ACT_BPF_PARMS, gen.Serialize())
   700  			aopts.AddRtAttr(nl.TCA_ACT_BPF_FD, nl.Uint32Attr(uint32(action.Fd)))
   701  			aopts.AddRtAttr(nl.TCA_ACT_BPF_NAME, nl.ZeroTerminated(action.Name))
   702  		case *GenericAction:
   703  			table := attr.AddRtAttr(tabIndex, nil)
   704  			tabIndex++
   705  			table.AddRtAttr(nl.TCA_ACT_KIND, nl.ZeroTerminated("gact"))
   706  			aopts := table.AddRtAttr(nl.TCA_ACT_OPTIONS, nil)
   707  			gen := nl.TcGen{}
   708  			toTcGen(action.Attrs(), &gen)
   709  			aopts.AddRtAttr(nl.TCA_GACT_PARMS, gen.Serialize())
   710  		case *PeditAction:
   711  			table := attr.AddRtAttr(tabIndex, nil)
   712  			tabIndex++
   713  			pedit := nl.TcPedit{}
   714  			if action.SrcMacAddr != nil {
   715  				pedit.SetEthSrc(action.SrcMacAddr)
   716  			}
   717  			if action.DstMacAddr != nil {
   718  				pedit.SetEthDst(action.DstMacAddr)
   719  			}
   720  			if action.SrcIP != nil {
   721  				pedit.SetSrcIP(action.SrcIP)
   722  			}
   723  			if action.DstIP != nil {
   724  				pedit.SetDstIP(action.DstIP)
   725  			}
   726  			if action.SrcPort != 0 {
   727  				pedit.SetSrcPort(action.SrcPort, action.Proto)
   728  			}
   729  			if action.DstPort != 0 {
   730  				pedit.SetDstPort(action.DstPort, action.Proto)
   731  			}
   732  			pedit.Encode(table)
   733  		}
   734  	}
   735  	return nil
   736  }
   737  
   738  func parsePolice(data syscall.NetlinkRouteAttr, police *PoliceAction) {
   739  	switch data.Attr.Type {
   740  	case nl.TCA_POLICE_RESULT:
   741  		police.NotExceedAction = TcPolAct(native.Uint32(data.Value[0:4]))
   742  	case nl.TCA_POLICE_AVRATE:
   743  		police.AvRate = native.Uint32(data.Value[0:4])
   744  	case nl.TCA_POLICE_TBF:
   745  		p := *nl.DeserializeTcPolice(data.Value)
   746  		police.ActionAttrs = ActionAttrs{}
   747  		police.Attrs().Index = int(p.Index)
   748  		police.Attrs().Bindcnt = int(p.Bindcnt)
   749  		police.Attrs().Capab = int(p.Capab)
   750  		police.Attrs().Refcnt = int(p.Refcnt)
   751  		police.ExceedAction = TcPolAct(p.Action)
   752  		police.Rate = p.Rate.Rate
   753  		police.PeakRate = p.PeakRate.Rate
   754  		police.Burst = Xmitsize(uint64(p.Rate.Rate), p.Burst)
   755  		police.Mtu = p.Mtu
   756  		police.LinkLayer = int(p.Rate.Linklayer) & nl.TC_LINKLAYER_MASK
   757  		police.Overhead = p.Rate.Overhead
   758  	}
   759  }
   760  
   761  func parseActions(tables []syscall.NetlinkRouteAttr) ([]Action, error) {
   762  	var actions []Action
   763  	for _, table := range tables {
   764  		var action Action
   765  		var actionType string
   766  		var actionnStatistic *ActionStatistic
   767  		var actionTimestamp *ActionTimestamp
   768  		aattrs, err := nl.ParseRouteAttr(table.Value)
   769  		if err != nil {
   770  			return nil, err
   771  		}
   772  	nextattr:
   773  		for _, aattr := range aattrs {
   774  			switch aattr.Attr.Type {
   775  			case nl.TCA_KIND:
   776  				actionType = string(aattr.Value[:len(aattr.Value)-1])
   777  				// only parse if the action is mirred or bpf
   778  				switch actionType {
   779  				case "mirred":
   780  					action = &MirredAction{}
   781  				case "bpf":
   782  					action = &BpfAction{}
   783  				case "connmark":
   784  					action = &ConnmarkAction{}
   785  				case "csum":
   786  					action = &CsumAction{}
   787  				case "gact":
   788  					action = &GenericAction{}
   789  				case "tunnel_key":
   790  					action = &TunnelKeyAction{}
   791  				case "skbedit":
   792  					action = &SkbEditAction{}
   793  				case "police":
   794  					action = &PoliceAction{}
   795  				case "pedit":
   796  					action = &PeditAction{}
   797  				default:
   798  					break nextattr
   799  				}
   800  			case nl.TCA_OPTIONS:
   801  				adata, err := nl.ParseRouteAttr(aattr.Value)
   802  				if err != nil {
   803  					return nil, err
   804  				}
   805  				for _, adatum := range adata {
   806  					switch actionType {
   807  					case "mirred":
   808  						switch adatum.Attr.Type {
   809  						case nl.TCA_MIRRED_PARMS:
   810  							mirred := *nl.DeserializeTcMirred(adatum.Value)
   811  							action.(*MirredAction).ActionAttrs = ActionAttrs{}
   812  							toAttrs(&mirred.TcGen, action.Attrs())
   813  							action.(*MirredAction).Ifindex = int(mirred.Ifindex)
   814  							action.(*MirredAction).MirredAction = MirredAct(mirred.Eaction)
   815  						case nl.TCA_MIRRED_TM:
   816  							tcTs := nl.DeserializeTcf(adatum.Value)
   817  							actionTimestamp = toTimeStamp(tcTs)
   818  						}
   819  
   820  					case "tunnel_key":
   821  						switch adatum.Attr.Type {
   822  						case nl.TCA_TUNNEL_KEY_PARMS:
   823  							tun := *nl.DeserializeTunnelKey(adatum.Value)
   824  							action.(*TunnelKeyAction).ActionAttrs = ActionAttrs{}
   825  							toAttrs(&tun.TcGen, action.Attrs())
   826  							action.(*TunnelKeyAction).Action = TunnelKeyAct(tun.Action)
   827  						case nl.TCA_TUNNEL_KEY_ENC_KEY_ID:
   828  							action.(*TunnelKeyAction).KeyID = networkOrder.Uint32(adatum.Value[0:4])
   829  						case nl.TCA_TUNNEL_KEY_ENC_IPV6_SRC, nl.TCA_TUNNEL_KEY_ENC_IPV4_SRC:
   830  							action.(*TunnelKeyAction).SrcAddr = adatum.Value[:]
   831  						case nl.TCA_TUNNEL_KEY_ENC_IPV6_DST, nl.TCA_TUNNEL_KEY_ENC_IPV4_DST:
   832  							action.(*TunnelKeyAction).DstAddr = adatum.Value[:]
   833  						case nl.TCA_TUNNEL_KEY_ENC_DST_PORT:
   834  							action.(*TunnelKeyAction).DestPort = ntohs(adatum.Value)
   835  						case nl.TCA_TUNNEL_KEY_TM:
   836  							tcTs := nl.DeserializeTcf(adatum.Value)
   837  							actionTimestamp = toTimeStamp(tcTs)
   838  						}
   839  					case "skbedit":
   840  						switch adatum.Attr.Type {
   841  						case nl.TCA_SKBEDIT_PARMS:
   842  							skbedit := *nl.DeserializeSkbEdit(adatum.Value)
   843  							action.(*SkbEditAction).ActionAttrs = ActionAttrs{}
   844  							toAttrs(&skbedit.TcGen, action.Attrs())
   845  						case nl.TCA_SKBEDIT_MARK:
   846  							mark := native.Uint32(adatum.Value[0:4])
   847  							action.(*SkbEditAction).Mark = &mark
   848  						case nl.TCA_SKBEDIT_MASK:
   849  							mask := native.Uint32(adatum.Value[0:4])
   850  							action.(*SkbEditAction).Mask = &mask
   851  						case nl.TCA_SKBEDIT_PRIORITY:
   852  							priority := native.Uint32(adatum.Value[0:4])
   853  							action.(*SkbEditAction).Priority = &priority
   854  						case nl.TCA_SKBEDIT_PTYPE:
   855  							ptype := native.Uint16(adatum.Value[0:2])
   856  							action.(*SkbEditAction).PType = &ptype
   857  						case nl.TCA_SKBEDIT_QUEUE_MAPPING:
   858  							mapping := native.Uint16(adatum.Value[0:2])
   859  							action.(*SkbEditAction).QueueMapping = &mapping
   860  						case nl.TCA_SKBEDIT_TM:
   861  							tcTs := nl.DeserializeTcf(adatum.Value)
   862  							actionTimestamp = toTimeStamp(tcTs)
   863  						}
   864  					case "bpf":
   865  						switch adatum.Attr.Type {
   866  						case nl.TCA_ACT_BPF_PARMS:
   867  							gen := *nl.DeserializeTcGen(adatum.Value)
   868  							toAttrs(&gen, action.Attrs())
   869  						case nl.TCA_ACT_BPF_FD:
   870  							action.(*BpfAction).Fd = int(native.Uint32(adatum.Value[0:4]))
   871  						case nl.TCA_ACT_BPF_NAME:
   872  							action.(*BpfAction).Name = string(adatum.Value[:len(adatum.Value)-1])
   873  						case nl.TCA_ACT_BPF_TM:
   874  							tcTs := nl.DeserializeTcf(adatum.Value)
   875  							actionTimestamp = toTimeStamp(tcTs)
   876  						}
   877  					case "connmark":
   878  						switch adatum.Attr.Type {
   879  						case nl.TCA_CONNMARK_PARMS:
   880  							connmark := *nl.DeserializeTcConnmark(adatum.Value)
   881  							action.(*ConnmarkAction).ActionAttrs = ActionAttrs{}
   882  							toAttrs(&connmark.TcGen, action.Attrs())
   883  							action.(*ConnmarkAction).Zone = connmark.Zone
   884  						case nl.TCA_CONNMARK_TM:
   885  							tcTs := nl.DeserializeTcf(adatum.Value)
   886  							actionTimestamp = toTimeStamp(tcTs)
   887  						}
   888  					case "csum":
   889  						switch adatum.Attr.Type {
   890  						case nl.TCA_CSUM_PARMS:
   891  							csum := *nl.DeserializeTcCsum(adatum.Value)
   892  							action.(*CsumAction).ActionAttrs = ActionAttrs{}
   893  							toAttrs(&csum.TcGen, action.Attrs())
   894  							action.(*CsumAction).UpdateFlags = CsumUpdateFlags(csum.UpdateFlags)
   895  						case nl.TCA_CSUM_TM:
   896  							tcTs := nl.DeserializeTcf(adatum.Value)
   897  							actionTimestamp = toTimeStamp(tcTs)
   898  						}
   899  					case "gact":
   900  						switch adatum.Attr.Type {
   901  						case nl.TCA_GACT_PARMS:
   902  							gen := *nl.DeserializeTcGen(adatum.Value)
   903  							toAttrs(&gen, action.Attrs())
   904  							if action.Attrs().Action.String() == "goto" {
   905  								action.(*GenericAction).Chain = TC_ACT_EXT_VAL_MASK & gen.Action
   906  							}
   907  						case nl.TCA_GACT_TM:
   908  							tcTs := nl.DeserializeTcf(adatum.Value)
   909  							actionTimestamp = toTimeStamp(tcTs)
   910  						}
   911  					case "police":
   912  						parsePolice(adatum, action.(*PoliceAction))
   913  					}
   914  				}
   915  			case nl.TCA_ACT_STATS:
   916  				s, err := parseTcStats2(aattr.Value)
   917  				if err != nil {
   918  					return nil, err
   919  				}
   920  				actionnStatistic = (*ActionStatistic)(s)
   921  			}
   922  		}
   923  		action.Attrs().Statistics = actionnStatistic
   924  		action.Attrs().Timestamp = actionTimestamp
   925  		actions = append(actions, action)
   926  	}
   927  	return actions, nil
   928  }
   929  
   930  func parseU32Data(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
   931  	u32 := filter.(*U32)
   932  	detailed := false
   933  	for _, datum := range data {
   934  		switch datum.Attr.Type {
   935  		case nl.TCA_U32_SEL:
   936  			detailed = true
   937  			sel := nl.DeserializeTcU32Sel(datum.Value)
   938  			u32.Sel = sel
   939  			if native != networkOrder {
   940  				// Handle the endianness of attributes
   941  				u32.Sel.Offmask = native.Uint16(htons(sel.Offmask))
   942  				u32.Sel.Hmask = native.Uint32(htonl(sel.Hmask))
   943  				for i, key := range u32.Sel.Keys {
   944  					u32.Sel.Keys[i].Mask = native.Uint32(htonl(key.Mask))
   945  					u32.Sel.Keys[i].Val = native.Uint32(htonl(key.Val))
   946  				}
   947  			}
   948  		case nl.TCA_U32_ACT:
   949  			tables, err := nl.ParseRouteAttr(datum.Value)
   950  			if err != nil {
   951  				return detailed, err
   952  			}
   953  			u32.Actions, err = parseActions(tables)
   954  			if err != nil {
   955  				return detailed, err
   956  			}
   957  			for _, action := range u32.Actions {
   958  				if action, ok := action.(*MirredAction); ok {
   959  					u32.RedirIndex = int(action.Ifindex)
   960  				}
   961  			}
   962  		case nl.TCA_U32_POLICE:
   963  			var police PoliceAction
   964  			adata, _ := nl.ParseRouteAttr(datum.Value)
   965  			for _, aattr := range adata {
   966  				parsePolice(aattr, &police)
   967  			}
   968  			u32.Police = &police
   969  		case nl.TCA_U32_CLASSID:
   970  			u32.ClassId = native.Uint32(datum.Value)
   971  		case nl.TCA_U32_DIVISOR:
   972  			u32.Divisor = native.Uint32(datum.Value)
   973  		case nl.TCA_U32_HASH:
   974  			u32.Hash = native.Uint32(datum.Value)
   975  		case nl.TCA_U32_LINK:
   976  			u32.Link = native.Uint32(datum.Value)
   977  		}
   978  	}
   979  	return detailed, nil
   980  }
   981  
   982  func parseFwData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
   983  	fw := filter.(*FwFilter)
   984  	detailed := true
   985  	for _, datum := range data {
   986  		switch datum.Attr.Type {
   987  		case nl.TCA_FW_MASK:
   988  			fw.Mask = native.Uint32(datum.Value[0:4])
   989  		case nl.TCA_FW_CLASSID:
   990  			fw.ClassId = native.Uint32(datum.Value[0:4])
   991  		case nl.TCA_FW_INDEV:
   992  			fw.InDev = string(datum.Value[:len(datum.Value)-1])
   993  		case nl.TCA_FW_POLICE:
   994  			var police PoliceAction
   995  			adata, _ := nl.ParseRouteAttr(datum.Value)
   996  			for _, aattr := range adata {
   997  				parsePolice(aattr, &police)
   998  			}
   999  			fw.Police = &police
  1000  		case nl.TCA_FW_ACT:
  1001  			tables, err := nl.ParseRouteAttr(datum.Value)
  1002  			if err != nil {
  1003  				return detailed, err
  1004  			}
  1005  			fw.Actions, err = parseActions(tables)
  1006  			if err != nil {
  1007  				return detailed, err
  1008  			}
  1009  		}
  1010  	}
  1011  	return detailed, nil
  1012  }
  1013  
  1014  func parseBpfData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
  1015  	bpf := filter.(*BpfFilter)
  1016  	detailed := true
  1017  	for _, datum := range data {
  1018  		switch datum.Attr.Type {
  1019  		case nl.TCA_BPF_FD:
  1020  			bpf.Fd = int(native.Uint32(datum.Value[0:4]))
  1021  		case nl.TCA_BPF_NAME:
  1022  			bpf.Name = string(datum.Value[:len(datum.Value)-1])
  1023  		case nl.TCA_BPF_CLASSID:
  1024  			bpf.ClassId = native.Uint32(datum.Value[0:4])
  1025  		case nl.TCA_BPF_FLAGS:
  1026  			flags := native.Uint32(datum.Value[0:4])
  1027  			if (flags & nl.TCA_BPF_FLAG_ACT_DIRECT) != 0 {
  1028  				bpf.DirectAction = true
  1029  			}
  1030  		case nl.TCA_BPF_ID:
  1031  			bpf.Id = int(native.Uint32(datum.Value[0:4]))
  1032  		case nl.TCA_BPF_TAG:
  1033  			bpf.Tag = hex.EncodeToString(datum.Value)
  1034  		}
  1035  	}
  1036  	return detailed, nil
  1037  }
  1038  
  1039  func parseMatchAllData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
  1040  	matchall := filter.(*MatchAll)
  1041  	detailed := true
  1042  	for _, datum := range data {
  1043  		switch datum.Attr.Type {
  1044  		case nl.TCA_MATCHALL_CLASSID:
  1045  			matchall.ClassId = native.Uint32(datum.Value[0:4])
  1046  		case nl.TCA_MATCHALL_ACT:
  1047  			tables, err := nl.ParseRouteAttr(datum.Value)
  1048  			if err != nil {
  1049  				return detailed, err
  1050  			}
  1051  			matchall.Actions, err = parseActions(tables)
  1052  			if err != nil {
  1053  				return detailed, err
  1054  			}
  1055  		}
  1056  	}
  1057  	return detailed, nil
  1058  }
  1059  
  1060  func parseFlowerData(filter Filter, data []syscall.NetlinkRouteAttr) (bool, error) {
  1061  	return true, filter.(*Flower).decode(data)
  1062  }
  1063  
  1064  func AlignToAtm(size uint) uint {
  1065  	var linksize, cells int
  1066  	cells = int(size / nl.ATM_CELL_PAYLOAD)
  1067  	if (size % nl.ATM_CELL_PAYLOAD) > 0 {
  1068  		cells++
  1069  	}
  1070  	linksize = cells * nl.ATM_CELL_SIZE
  1071  	return uint(linksize)
  1072  }
  1073  
  1074  func AdjustSize(sz uint, mpu uint, linklayer int) uint {
  1075  	if sz < mpu {
  1076  		sz = mpu
  1077  	}
  1078  	switch linklayer {
  1079  	case nl.LINKLAYER_ATM:
  1080  		return AlignToAtm(sz)
  1081  	default:
  1082  		return sz
  1083  	}
  1084  }
  1085  
  1086  func CalcRtable(rate *nl.TcRateSpec, rtab []uint32, cellLog int, mtu uint32, linklayer int) int {
  1087  	bps := rate.Rate
  1088  	mpu := rate.Mpu
  1089  	var sz uint
  1090  	if mtu == 0 {
  1091  		mtu = 2047
  1092  	}
  1093  	if cellLog < 0 {
  1094  		cellLog = 0
  1095  		for (mtu >> uint(cellLog)) > 255 {
  1096  			cellLog++
  1097  		}
  1098  	}
  1099  	for i := 0; i < 256; i++ {
  1100  		sz = AdjustSize(uint((i+1)<<uint32(cellLog)), uint(mpu), linklayer)
  1101  		rtab[i] = Xmittime(uint64(bps), uint32(sz))
  1102  	}
  1103  	rate.CellAlign = -1
  1104  	rate.CellLog = uint8(cellLog)
  1105  	rate.Linklayer = uint8(linklayer & nl.TC_LINKLAYER_MASK)
  1106  	return cellLog
  1107  }
  1108  
  1109  func DeserializeRtab(b []byte) [256]uint32 {
  1110  	var rtab [256]uint32
  1111  	r := bytes.NewReader(b)
  1112  	_ = binary.Read(r, native, &rtab)
  1113  	return rtab
  1114  }
  1115  
  1116  func SerializeRtab(rtab [256]uint32) []byte {
  1117  	var w bytes.Buffer
  1118  	_ = binary.Write(&w, native, rtab)
  1119  	return w.Bytes()
  1120  }