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