github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/filter_test.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package netlink
     5  
     6  import (
     7  	"net"
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/sagernet/netlink/nl"
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func TestFilterAddDel(t *testing.T) {
    16  	tearDown := setUpNetlinkTest(t)
    17  	defer tearDown()
    18  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
    19  		t.Fatal(err)
    20  	}
    21  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
    22  		t.Fatal(err)
    23  	}
    24  	link, err := LinkByName("foo")
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	if err := LinkSetUp(link); err != nil {
    29  		t.Fatal(err)
    30  	}
    31  	redir, err := LinkByName("bar")
    32  	if err != nil {
    33  		t.Fatal(err)
    34  	}
    35  	if err := LinkSetUp(redir); err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	qdisc := &Ingress{
    39  		QdiscAttrs: QdiscAttrs{
    40  			LinkIndex: link.Attrs().Index,
    41  			Handle:    MakeHandle(0xffff, 0),
    42  			Parent:    HANDLE_INGRESS,
    43  		},
    44  	}
    45  	if err := QdiscAdd(qdisc); err != nil {
    46  		t.Fatal(err)
    47  	}
    48  	qdiscs, err := SafeQdiscList(link)
    49  	if err != nil {
    50  		t.Fatal(err)
    51  	}
    52  	if len(qdiscs) != 1 {
    53  		t.Fatal("Failed to add qdisc")
    54  	}
    55  	_, ok := qdiscs[0].(*Ingress)
    56  	if !ok {
    57  		t.Fatal("Qdisc is the wrong type")
    58  	}
    59  	classId := MakeHandle(1, 1)
    60  	filter := &U32{
    61  		FilterAttrs: FilterAttrs{
    62  			LinkIndex: link.Attrs().Index,
    63  			Parent:    MakeHandle(0xffff, 0),
    64  			Priority:  1,
    65  			Protocol:  unix.ETH_P_IP,
    66  		},
    67  		RedirIndex: redir.Attrs().Index,
    68  		ClassId:    classId,
    69  	}
    70  	if err := FilterAdd(filter); err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
    74  	if err != nil {
    75  		t.Fatal(err)
    76  	}
    77  	if len(filters) != 1 {
    78  		t.Fatal("Failed to add filter")
    79  	}
    80  	u32, ok := filters[0].(*U32)
    81  	if !ok {
    82  		t.Fatal("Filter is the wrong type")
    83  	}
    84  	if u32.ClassId != classId {
    85  		t.Fatalf("ClassId of the filter is the wrong value")
    86  	}
    87  	if err := FilterDel(filter); err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
    91  	if err != nil {
    92  		t.Fatal(err)
    93  	}
    94  	if len(filters) != 0 {
    95  		t.Fatal("Failed to remove filter")
    96  	}
    97  	if err := QdiscDel(qdisc); err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	qdiscs, err = SafeQdiscList(link)
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  	if len(qdiscs) != 0 {
   105  		t.Fatal("Failed to remove qdisc")
   106  	}
   107  }
   108  
   109  func TestFilterReplace(t *testing.T) {
   110  	tearDown := setUpNetlinkTest(t)
   111  	defer tearDown()
   112  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   113  		t.Fatal(err)
   114  	}
   115  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	link, err := LinkByName("foo")
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	if err := LinkSetUp(link); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	redir, err := LinkByName("bar")
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  	if err := LinkSetUp(redir); err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	qdisc := &Ingress{
   133  		QdiscAttrs: QdiscAttrs{
   134  			LinkIndex: link.Attrs().Index,
   135  			Handle:    MakeHandle(0xffff, 0),
   136  			Parent:    HANDLE_INGRESS,
   137  		},
   138  	}
   139  	if err := QdiscAdd(qdisc); err != nil {
   140  		t.Fatal(err)
   141  	}
   142  
   143  	filter := &U32{
   144  		FilterAttrs: FilterAttrs{
   145  			LinkIndex: link.Attrs().Index,
   146  			Parent:    MakeHandle(0xffff, 0),
   147  			Priority:  1,
   148  			Protocol:  unix.ETH_P_IP,
   149  		},
   150  		RedirIndex: redir.Attrs().Index,
   151  		ClassId:    MakeHandle(1, 1),
   152  	}
   153  
   154  	if err := FilterReplace(filter); err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	if len(filters) != 1 {
   162  		t.Fatal("Failed replace filter")
   163  	}
   164  
   165  	if err := FilterReplace(filter); err != nil {
   166  		t.Fatal(err)
   167  	}
   168  }
   169  
   170  func TestAdvancedFilterAddDel(t *testing.T) {
   171  	tearDown := setUpNetlinkTest(t)
   172  	defer tearDown()
   173  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "baz"}}); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	link, err := LinkByName("baz")
   177  	if err != nil {
   178  		t.Fatal(err)
   179  	}
   180  	if err := LinkSetUp(link); err != nil {
   181  		t.Fatal(err)
   182  	}
   183  	index := link.Attrs().Index
   184  
   185  	qdiscHandle := MakeHandle(0x1, 0x0)
   186  	qdiscAttrs := QdiscAttrs{
   187  		LinkIndex: index,
   188  		Handle:    qdiscHandle,
   189  		Parent:    HANDLE_ROOT,
   190  	}
   191  
   192  	qdisc := NewHtb(qdiscAttrs)
   193  	if err := QdiscAdd(qdisc); err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	qdiscs, err := SafeQdiscList(link)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  	if len(qdiscs) != 1 {
   201  		t.Fatal("Failed to add qdisc")
   202  	}
   203  	_, ok := qdiscs[0].(*Htb)
   204  	if !ok {
   205  		t.Fatal("Qdisc is the wrong type")
   206  	}
   207  
   208  	classId := MakeHandle(0x1, 0x46cb)
   209  	classAttrs := ClassAttrs{
   210  		LinkIndex: index,
   211  		Parent:    qdiscHandle,
   212  		Handle:    classId,
   213  	}
   214  	htbClassAttrs := HtbClassAttrs{
   215  		Rate:   512 * 1024,
   216  		Buffer: 32 * 1024,
   217  	}
   218  	htbClass := NewHtbClass(classAttrs, htbClassAttrs)
   219  	if err = ClassReplace(htbClass); err != nil {
   220  		t.Fatalf("Failed to add a HTB class: %v", err)
   221  	}
   222  	classes, err := SafeClassList(link, qdiscHandle)
   223  	if err != nil {
   224  		t.Fatal(err)
   225  	}
   226  	if len(classes) != 1 {
   227  		t.Fatal("Failed to add class")
   228  	}
   229  	_, ok = classes[0].(*HtbClass)
   230  	if !ok {
   231  		t.Fatal("Class is the wrong type")
   232  	}
   233  
   234  	htid := MakeHandle(0x0010, 0000)
   235  	divisor := uint32(1)
   236  	hashTable := &U32{
   237  		FilterAttrs: FilterAttrs{
   238  			LinkIndex: index,
   239  			Handle:    htid,
   240  			Parent:    qdiscHandle,
   241  			Priority:  1,
   242  			Protocol:  unix.ETH_P_ALL,
   243  		},
   244  		Divisor: divisor,
   245  	}
   246  	cHashTable := *hashTable
   247  	if err := FilterAdd(hashTable); err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	// Check if the hash table is identical before and after FilterAdd.
   251  	if !reflect.DeepEqual(cHashTable, *hashTable) {
   252  		t.Fatalf("Hash table %v and %v are not equal", cHashTable, *hashTable)
   253  	}
   254  
   255  	u32SelKeys := []TcU32Key{
   256  		{
   257  			Mask:    0xff,
   258  			Val:     80,
   259  			Off:     20,
   260  			OffMask: 0,
   261  		},
   262  		{
   263  			Mask:    0xffff,
   264  			Val:     0x146ca,
   265  			Off:     32,
   266  			OffMask: 0,
   267  		},
   268  	}
   269  
   270  	handle := MakeHandle(0x0000, 0001)
   271  	filter := &U32{
   272  		FilterAttrs: FilterAttrs{
   273  			LinkIndex: index,
   274  			Handle:    handle,
   275  			Parent:    qdiscHandle,
   276  			Priority:  1,
   277  			Protocol:  unix.ETH_P_ALL,
   278  		},
   279  		Sel: &TcU32Sel{
   280  			Keys:  u32SelKeys,
   281  			Flags: TC_U32_TERMINAL,
   282  		},
   283  		ClassId: classId,
   284  		Hash:    htid,
   285  		Actions: []Action{},
   286  	}
   287  	// Copy filter.
   288  	cFilter := *filter
   289  	if err := FilterAdd(filter); err != nil {
   290  		t.Fatal(err)
   291  	}
   292  	// Check if the filter is identical before and after FilterAdd.
   293  	if !reflect.DeepEqual(cFilter, *filter) {
   294  		t.Fatalf("U32 %v and %v are not equal", cFilter, *filter)
   295  	}
   296  
   297  	filters, err := FilterList(link, qdiscHandle)
   298  	if err != nil {
   299  		t.Fatal(err)
   300  	}
   301  	if len(filters) != 1 {
   302  		t.Fatal("Failed to add filter")
   303  	}
   304  
   305  	u32, ok := filters[0].(*U32)
   306  	if !ok {
   307  		t.Fatal("Filter is the wrong type")
   308  	}
   309  	// Endianness checks
   310  	if u32.Sel.Offmask != filter.Sel.Offmask {
   311  		t.Fatal("The endianness of TcU32Key.Sel.Offmask is wrong")
   312  	}
   313  	if u32.Sel.Hmask != filter.Sel.Hmask {
   314  		t.Fatal("The endianness of TcU32Key.Sel.Hmask is wrong")
   315  	}
   316  	for i, key := range u32.Sel.Keys {
   317  		if key.Mask != filter.Sel.Keys[i].Mask {
   318  			t.Fatal("The endianness of TcU32Key.Mask is wrong")
   319  		}
   320  		if key.Val != filter.Sel.Keys[i].Val {
   321  			t.Fatal("The endianness of TcU32Key.Val is wrong")
   322  		}
   323  	}
   324  	if u32.Handle != (handle | htid) {
   325  		t.Fatalf("The handle is wrong. expected %v but actually %v",
   326  			(handle | htid), u32.Handle)
   327  	}
   328  	if u32.Hash != htid {
   329  		t.Fatal("The hash table ID is wrong")
   330  	}
   331  
   332  	if err := FilterDel(u32); err != nil {
   333  		t.Fatal(err)
   334  	}
   335  	filters, err = FilterList(link, qdiscHandle)
   336  	if err != nil {
   337  		t.Fatal(err)
   338  	}
   339  	if len(filters) != 0 {
   340  		t.Fatal("Failed to remove filter")
   341  	}
   342  
   343  	if err = ClassDel(htbClass); err != nil {
   344  		t.Fatalf("Failed to delete a HTP class: %v", err)
   345  	}
   346  	classes, err = SafeClassList(link, qdiscHandle)
   347  	if err != nil {
   348  		t.Fatal(err)
   349  	}
   350  	if len(classes) != 0 {
   351  		t.Fatal("Failed to remove class")
   352  	}
   353  
   354  	if err := QdiscDel(qdisc); err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	qdiscs, err = SafeQdiscList(link)
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  	if len(qdiscs) != 0 {
   362  		t.Fatal("Failed to remove qdisc")
   363  	}
   364  }
   365  
   366  func TestFilterFwAddDel(t *testing.T) {
   367  	tearDown := setUpNetlinkTest(t)
   368  	defer tearDown()
   369  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   370  		t.Fatal(err)
   371  	}
   372  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   373  		t.Fatal(err)
   374  	}
   375  	link, err := LinkByName("foo")
   376  	if err != nil {
   377  		t.Fatal(err)
   378  	}
   379  	if err := LinkSetUp(link); err != nil {
   380  		t.Fatal(err)
   381  	}
   382  	redir, err := LinkByName("bar")
   383  	if err != nil {
   384  		t.Fatal(err)
   385  	}
   386  	if err := LinkSetUp(redir); err != nil {
   387  		t.Fatal(err)
   388  	}
   389  	attrs := QdiscAttrs{
   390  		LinkIndex: link.Attrs().Index,
   391  		Handle:    MakeHandle(0xffff, 0),
   392  		Parent:    HANDLE_ROOT,
   393  	}
   394  	qdisc := NewHtb(attrs)
   395  	if err := QdiscAdd(qdisc); err != nil {
   396  		t.Fatal(err)
   397  	}
   398  	qdiscs, err := SafeQdiscList(link)
   399  	if err != nil {
   400  		t.Fatal(err)
   401  	}
   402  	if len(qdiscs) != 1 {
   403  		t.Fatal("Failed to add qdisc")
   404  	}
   405  	_, ok := qdiscs[0].(*Htb)
   406  	if !ok {
   407  		t.Fatal("Qdisc is the wrong type")
   408  	}
   409  
   410  	classattrs := ClassAttrs{
   411  		LinkIndex: link.Attrs().Index,
   412  		Parent:    MakeHandle(0xffff, 0),
   413  		Handle:    MakeHandle(0xffff, 2),
   414  	}
   415  
   416  	htbclassattrs := HtbClassAttrs{
   417  		Rate:    1234000,
   418  		Cbuffer: 1690,
   419  	}
   420  	class := NewHtbClass(classattrs, htbclassattrs)
   421  	if err := ClassAdd(class); err != nil {
   422  		t.Fatal(err)
   423  	}
   424  	classes, err := SafeClassList(link, MakeHandle(0xffff, 2))
   425  	if err != nil {
   426  		t.Fatal(err)
   427  	}
   428  	if len(classes) != 1 {
   429  		t.Fatal("Failed to add class")
   430  	}
   431  
   432  	police := NewPoliceAction()
   433  	police.Burst = 12345
   434  	police.Rate = 1234
   435  	police.PeakRate = 2345
   436  	police.Action = TcAct(TC_POLICE_SHOT)
   437  
   438  	filterattrs := FilterAttrs{
   439  		LinkIndex: link.Attrs().Index,
   440  		Parent:    MakeHandle(0xffff, 0),
   441  		Handle:    MakeHandle(0, 0x6),
   442  		Priority:  1,
   443  		Protocol:  unix.ETH_P_IP,
   444  	}
   445  
   446  	filter := FwFilter{
   447  		FilterAttrs: filterattrs,
   448  		ClassId:     MakeHandle(0xffff, 2),
   449  		Police:      police,
   450  	}
   451  
   452  	if err := FilterAdd(&filter); err != nil {
   453  		t.Fatal(err)
   454  	}
   455  
   456  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   457  	if err != nil {
   458  		t.Fatal(err)
   459  	}
   460  	if len(filters) != 1 {
   461  		t.Fatal("Failed to add filter")
   462  	}
   463  	fw, ok := filters[0].(*FwFilter)
   464  	if !ok {
   465  		t.Fatal("Filter is the wrong type")
   466  	}
   467  	if fw.Police.Rate != filter.Police.Rate {
   468  		t.Fatal("Police Rate doesn't match")
   469  	}
   470  	if fw.ClassId != filter.ClassId {
   471  		t.Fatal("ClassId doesn't match")
   472  	}
   473  	if fw.InDev != filter.InDev {
   474  		t.Fatal("InDev doesn't match")
   475  	}
   476  	if fw.Police.AvRate != filter.Police.AvRate {
   477  		t.Fatal("AvRate doesn't match")
   478  	}
   479  
   480  	if err := FilterDel(&filter); err != nil {
   481  		t.Fatal(err)
   482  	}
   483  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   484  	if err != nil {
   485  		t.Fatal(err)
   486  	}
   487  	if len(filters) != 0 {
   488  		t.Fatal("Failed to remove filter")
   489  	}
   490  	if err := ClassDel(class); err != nil {
   491  		t.Fatal(err)
   492  	}
   493  	classes, err = SafeClassList(link, MakeHandle(0xffff, 0))
   494  	if err != nil {
   495  		t.Fatal(err)
   496  	}
   497  	if len(classes) != 0 {
   498  		t.Fatal("Failed to remove class")
   499  	}
   500  
   501  	if err := QdiscDel(qdisc); err != nil {
   502  		t.Fatal(err)
   503  	}
   504  	qdiscs, err = SafeQdiscList(link)
   505  	if err != nil {
   506  		t.Fatal(err)
   507  	}
   508  	if len(qdiscs) != 0 {
   509  		t.Fatal("Failed to remove qdisc")
   510  	}
   511  }
   512  
   513  func TestFilterU32BpfAddDel(t *testing.T) {
   514  	t.Skipf("Fd does not match in ci")
   515  	tearDown := setUpNetlinkTest(t)
   516  	defer tearDown()
   517  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   518  		t.Fatal(err)
   519  	}
   520  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   521  		t.Fatal(err)
   522  	}
   523  	link, err := LinkByName("foo")
   524  	if err != nil {
   525  		t.Fatal(err)
   526  	}
   527  	if err := LinkSetUp(link); err != nil {
   528  		t.Fatal(err)
   529  	}
   530  	redir, err := LinkByName("bar")
   531  	if err != nil {
   532  		t.Fatal(err)
   533  	}
   534  	if err := LinkSetUp(redir); err != nil {
   535  		t.Fatal(err)
   536  	}
   537  	qdisc := &Ingress{
   538  		QdiscAttrs: QdiscAttrs{
   539  			LinkIndex: link.Attrs().Index,
   540  			Handle:    MakeHandle(0xffff, 0),
   541  			Parent:    HANDLE_INGRESS,
   542  		},
   543  	}
   544  	if err := QdiscAdd(qdisc); err != nil {
   545  		t.Fatal(err)
   546  	}
   547  	qdiscs, err := SafeQdiscList(link)
   548  	if err != nil {
   549  		t.Fatal(err)
   550  	}
   551  	if len(qdiscs) != 1 {
   552  		t.Fatal("Failed to add qdisc")
   553  	}
   554  	_, ok := qdiscs[0].(*Ingress)
   555  	if !ok {
   556  		t.Fatal("Qdisc is the wrong type")
   557  	}
   558  
   559  	fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT, 1)
   560  	if err != nil {
   561  		t.Skipf("Loading bpf program failed: %s", err)
   562  	}
   563  	classId := MakeHandle(1, 1)
   564  	filter := &U32{
   565  		FilterAttrs: FilterAttrs{
   566  			LinkIndex: link.Attrs().Index,
   567  			Parent:    MakeHandle(0xffff, 0),
   568  			Priority:  1,
   569  			Protocol:  unix.ETH_P_ALL,
   570  		},
   571  		ClassId: classId,
   572  		Actions: []Action{
   573  			&BpfAction{Fd: fd, Name: "simple"},
   574  			&MirredAction{
   575  				ActionAttrs: ActionAttrs{
   576  					Action: TC_ACT_STOLEN,
   577  				},
   578  				MirredAction: TCA_EGRESS_REDIR,
   579  				Ifindex:      redir.Attrs().Index,
   580  			},
   581  		},
   582  	}
   583  
   584  	if err := FilterAdd(filter); err != nil {
   585  		t.Fatal(err)
   586  	}
   587  
   588  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   589  	if err != nil {
   590  		t.Fatal(err)
   591  	}
   592  	if len(filters) != 1 {
   593  		t.Fatal("Failed to add filter")
   594  	}
   595  	u32, ok := filters[0].(*U32)
   596  	if !ok {
   597  		t.Fatal("Filter is the wrong type")
   598  	}
   599  
   600  	if len(u32.Actions) != 2 {
   601  		t.Fatalf("Too few Actions in filter")
   602  	}
   603  	if u32.ClassId != classId {
   604  		t.Fatalf("ClassId of the filter is the wrong value")
   605  	}
   606  
   607  	// actions can be returned in reverse order
   608  	bpfAction, ok := u32.Actions[0].(*BpfAction)
   609  	if !ok {
   610  		bpfAction, ok = u32.Actions[1].(*BpfAction)
   611  		if !ok {
   612  			t.Fatal("Action is the wrong type")
   613  		}
   614  	}
   615  	if bpfAction.Fd != fd {
   616  		t.Fatalf("Action Fd does not match %d != %d", bpfAction.Fd, fd)
   617  	}
   618  	if _, ok := u32.Actions[0].(*MirredAction); !ok {
   619  		if _, ok := u32.Actions[1].(*MirredAction); !ok {
   620  			t.Fatal("Action is the wrong type")
   621  		}
   622  	}
   623  
   624  	if err := FilterDel(filter); err != nil {
   625  		t.Fatal(err)
   626  	}
   627  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   628  	if err != nil {
   629  		t.Fatal(err)
   630  	}
   631  	if len(filters) != 0 {
   632  		t.Fatal("Failed to remove filter")
   633  	}
   634  
   635  	if err := QdiscDel(qdisc); err != nil {
   636  		t.Fatal(err)
   637  	}
   638  	qdiscs, err = SafeQdiscList(link)
   639  	if err != nil {
   640  		t.Fatal(err)
   641  	}
   642  	if len(qdiscs) != 0 {
   643  		t.Fatal("Failed to remove qdisc")
   644  	}
   645  }
   646  
   647  func TestFilterU32ConnmarkAddDel(t *testing.T) {
   648  	tearDown := setUpNetlinkTest(t)
   649  	defer tearDown()
   650  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   651  		t.Fatal(err)
   652  	}
   653  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   654  		t.Fatal(err)
   655  	}
   656  	link, err := LinkByName("foo")
   657  	if err != nil {
   658  		t.Fatal(err)
   659  	}
   660  	if err := LinkSetUp(link); err != nil {
   661  		t.Fatal(err)
   662  	}
   663  	redir, err := LinkByName("bar")
   664  	if err != nil {
   665  		t.Fatal(err)
   666  	}
   667  	if err := LinkSetUp(redir); err != nil {
   668  		t.Fatal(err)
   669  	}
   670  	qdisc := &Ingress{
   671  		QdiscAttrs: QdiscAttrs{
   672  			LinkIndex: link.Attrs().Index,
   673  			Handle:    MakeHandle(0xffff, 0),
   674  			Parent:    HANDLE_INGRESS,
   675  		},
   676  	}
   677  	if err := QdiscAdd(qdisc); err != nil {
   678  		t.Fatal(err)
   679  	}
   680  	qdiscs, err := SafeQdiscList(link)
   681  	if err != nil {
   682  		t.Fatal(err)
   683  	}
   684  	if len(qdiscs) != 1 {
   685  		t.Fatal("Failed to add qdisc")
   686  	}
   687  	_, ok := qdiscs[0].(*Ingress)
   688  	if !ok {
   689  		t.Fatal("Qdisc is the wrong type")
   690  	}
   691  
   692  	classId := MakeHandle(1, 1)
   693  	filter := &U32{
   694  		FilterAttrs: FilterAttrs{
   695  			LinkIndex: link.Attrs().Index,
   696  			Parent:    MakeHandle(0xffff, 0),
   697  			Priority:  1,
   698  			Protocol:  unix.ETH_P_ALL,
   699  		},
   700  		ClassId: classId,
   701  		Actions: []Action{
   702  			&ConnmarkAction{
   703  				ActionAttrs: ActionAttrs{
   704  					Action: TC_ACT_PIPE,
   705  				},
   706  			},
   707  			&MirredAction{
   708  				ActionAttrs: ActionAttrs{
   709  					Action: TC_ACT_STOLEN,
   710  				},
   711  				MirredAction: TCA_EGRESS_REDIR,
   712  				Ifindex:      redir.Attrs().Index,
   713  			},
   714  		},
   715  	}
   716  
   717  	if err := FilterAdd(filter); err != nil {
   718  		t.Fatal(err)
   719  	}
   720  
   721  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   722  	if err != nil {
   723  		t.Fatal(err)
   724  	}
   725  	if len(filters) != 1 {
   726  		t.Fatal("Failed to add filter")
   727  	}
   728  	u32, ok := filters[0].(*U32)
   729  	if !ok {
   730  		t.Fatal("Filter is the wrong type")
   731  	}
   732  
   733  	if len(u32.Actions) != 2 {
   734  		t.Fatalf("Too few Actions in filter")
   735  	}
   736  	if u32.ClassId != classId {
   737  		t.Fatalf("ClassId of the filter is the wrong value")
   738  	}
   739  
   740  	// actions can be returned in reverse order
   741  	cma, ok := u32.Actions[0].(*ConnmarkAction)
   742  	if !ok {
   743  		cma, ok = u32.Actions[1].(*ConnmarkAction)
   744  		if !ok {
   745  			t.Fatal("Unable to find connmark action")
   746  		}
   747  	}
   748  
   749  	if cma.Attrs().Action != TC_ACT_PIPE {
   750  		t.Fatal("Connmark action isn't TC_ACT_PIPE")
   751  	}
   752  
   753  	mia, ok := u32.Actions[0].(*MirredAction)
   754  	if !ok {
   755  		mia, ok = u32.Actions[1].(*MirredAction)
   756  		if !ok {
   757  			t.Fatal("Unable to find mirred action")
   758  		}
   759  	}
   760  
   761  	if mia.Attrs().Action != TC_ACT_STOLEN {
   762  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
   763  	}
   764  
   765  	if err := FilterDel(filter); err != nil {
   766  		t.Fatal(err)
   767  	}
   768  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   769  	if err != nil {
   770  		t.Fatal(err)
   771  	}
   772  	if len(filters) != 0 {
   773  		t.Fatal("Failed to remove filter")
   774  	}
   775  
   776  	if err := QdiscDel(qdisc); err != nil {
   777  		t.Fatal(err)
   778  	}
   779  	qdiscs, err = SafeQdiscList(link)
   780  	if err != nil {
   781  		t.Fatal(err)
   782  	}
   783  	if len(qdiscs) != 0 {
   784  		t.Fatal("Failed to remove qdisc")
   785  	}
   786  }
   787  
   788  func TestFilterU32CsumAddDel(t *testing.T) {
   789  	tearDown := setUpNetlinkTest(t)
   790  	defer tearDown()
   791  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   792  		t.Fatalf("add link foo error: %v", err)
   793  	}
   794  	link, err := LinkByName("foo")
   795  	if err != nil {
   796  		t.Fatalf("add link foo error: %v", err)
   797  	}
   798  	if err := LinkSetUp(link); err != nil {
   799  		t.Fatalf("set foo link up error: %v", err)
   800  	}
   801  
   802  	qdisc := &Ingress{
   803  		QdiscAttrs: QdiscAttrs{
   804  			LinkIndex: link.Attrs().Index,
   805  			Handle:    MakeHandle(0xffff, 0),
   806  			Parent:    HANDLE_INGRESS,
   807  		},
   808  	}
   809  	if err := QdiscAdd(qdisc); err != nil {
   810  		t.Fatal(err)
   811  	}
   812  	qdiscs, err := SafeQdiscList(link)
   813  	if err != nil {
   814  		t.Fatalf("get qdisc error: %v", err)
   815  	}
   816  
   817  	found := false
   818  	for _, v := range qdiscs {
   819  		if _, ok := v.(*Ingress); ok {
   820  			found = true
   821  			break
   822  		}
   823  	}
   824  	if !found {
   825  		t.Fatal("Qdisc is the wrong type")
   826  	}
   827  
   828  	classId := MakeHandle(1, 1)
   829  	filter := &U32{
   830  		FilterAttrs: FilterAttrs{
   831  			LinkIndex: link.Attrs().Index,
   832  			Parent:    MakeHandle(0xffff, 0),
   833  			Priority:  1,
   834  			Protocol:  unix.ETH_P_ALL,
   835  		},
   836  		ClassId: classId,
   837  		Actions: []Action{
   838  			&CsumAction{
   839  				ActionAttrs: ActionAttrs{
   840  					Action: TC_ACT_PIPE,
   841  				},
   842  				UpdateFlags: TCA_CSUM_UPDATE_FLAG_TCP,
   843  			},
   844  		},
   845  	}
   846  
   847  	if err := FilterAdd(filter); err != nil {
   848  		t.Fatal(err)
   849  	}
   850  
   851  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   852  	if err != nil {
   853  		t.Fatalf("get filter error: %v", err)
   854  	}
   855  
   856  	if len(filters) != 1 {
   857  		t.Fatalf("the count filters error, expect: 1, acutal: %d", len(filters))
   858  	}
   859  
   860  	ft, ok := filters[0].(*U32)
   861  	if !ok {
   862  		t.Fatal("Filter is the wrong type")
   863  	}
   864  
   865  	if ft.LinkIndex != link.Attrs().Index {
   866  		t.Fatal("link index error")
   867  	}
   868  
   869  	if len(ft.Actions) != 1 {
   870  		t.Fatalf("filter has wrong number of actions, expect: 1, acutal: %d", len(filters))
   871  	}
   872  
   873  	csum, ok := ft.Actions[0].(*CsumAction)
   874  	if !ok {
   875  		t.Fatal("action is the wrong type")
   876  	}
   877  
   878  	if csum.Attrs().Action != TC_ACT_PIPE {
   879  		t.Fatal("Csum action isn't TC_ACT_PIPE")
   880  	}
   881  
   882  	if csum.UpdateFlags != TCA_CSUM_UPDATE_FLAG_TCP {
   883  		t.Fatalf("Csum action isn't TCA_CSUM_UPDATE_FLAG_TCP, got %d", csum.UpdateFlags)
   884  	}
   885  
   886  	if err := FilterDel(ft); err != nil {
   887  		t.Fatal(err)
   888  	}
   889  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   890  	if err != nil {
   891  		t.Fatal(err)
   892  	}
   893  	if len(filters) != 0 {
   894  		t.Fatal("Failed to remove filter")
   895  	}
   896  
   897  	if err := QdiscDel(qdisc); err != nil {
   898  		t.Fatal(err)
   899  	}
   900  	qdiscs, err = SafeQdiscList(link)
   901  	if err != nil {
   902  		t.Fatal(err)
   903  	}
   904  
   905  	found = false
   906  	for _, v := range qdiscs {
   907  		if _, ok := v.(*Ingress); ok {
   908  			found = true
   909  			break
   910  		}
   911  	}
   912  	if found {
   913  		t.Fatal("Failed to remove qdisc")
   914  	}
   915  }
   916  
   917  func setupLinkForTestWithQdisc(t *testing.T, linkName string) (Qdisc, Link) {
   918  	if err := LinkAdd(&Ifb{LinkAttrs{Name: linkName}}); err != nil {
   919  		t.Fatal(err)
   920  	}
   921  	link, err := LinkByName(linkName)
   922  	if err != nil {
   923  		t.Fatal(err)
   924  	}
   925  	if err := LinkSetUp(link); err != nil {
   926  		t.Fatal(err)
   927  	}
   928  	attrs := QdiscAttrs{
   929  		LinkIndex: link.Attrs().Index,
   930  		Handle:    MakeHandle(0xffff, 0),
   931  		Parent:    HANDLE_CLSACT,
   932  	}
   933  	qdisc := &GenericQdisc{
   934  		QdiscAttrs: attrs,
   935  		QdiscType:  "clsact",
   936  	}
   937  
   938  	if err := QdiscAdd(qdisc); err != nil {
   939  		t.Fatal(err)
   940  	}
   941  	qdiscs, err := SafeQdiscList(link)
   942  	if err != nil {
   943  		t.Fatal(err)
   944  	}
   945  	if len(qdiscs) != 1 {
   946  		t.Fatal("Failed to add qdisc", len(qdiscs))
   947  	}
   948  	if q, ok := qdiscs[0].(*GenericQdisc); !ok || q.Type() != "clsact" {
   949  		t.Fatal("qdisc is the wrong type")
   950  	}
   951  	return qdiscs[0], link
   952  }
   953  
   954  func TestFilterClsActBpfAddDel(t *testing.T) {
   955  	t.Skipf("Fd does not match in ci")
   956  	// This feature was added in kernel 4.5
   957  	minKernelRequired(t, 4, 5)
   958  
   959  	tearDown := setUpNetlinkTest(t)
   960  	defer tearDown()
   961  
   962  	qdisc, link := setupLinkForTestWithQdisc(t, "foo")
   963  	filterattrs := FilterAttrs{
   964  		LinkIndex: link.Attrs().Index,
   965  		Parent:    HANDLE_MIN_EGRESS,
   966  		Handle:    MakeHandle(0, 1),
   967  		Protocol:  unix.ETH_P_ALL,
   968  		Priority:  1,
   969  	}
   970  	fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS, 1)
   971  	if err != nil {
   972  		t.Skipf("Loading bpf program failed: %s", err)
   973  	}
   974  	filter := &BpfFilter{
   975  		FilterAttrs:  filterattrs,
   976  		Fd:           fd,
   977  		Name:         "simple",
   978  		DirectAction: true,
   979  	}
   980  	if filter.Fd < 0 {
   981  		t.Skipf("Failed to load bpf program")
   982  	}
   983  
   984  	if err := FilterAdd(filter); err != nil {
   985  		t.Fatal(err)
   986  	}
   987  
   988  	filters, err := FilterList(link, HANDLE_MIN_EGRESS)
   989  	if err != nil {
   990  		t.Fatal(err)
   991  	}
   992  	if len(filters) != 1 {
   993  		t.Fatal("Failed to add filter")
   994  	}
   995  	bpf, ok := filters[0].(*BpfFilter)
   996  	if !ok {
   997  		t.Fatal("Filter is the wrong type")
   998  	}
   999  
  1000  	if bpf.Fd != filter.Fd {
  1001  		t.Fatal("Filter Fd does not match")
  1002  	}
  1003  	if bpf.DirectAction != filter.DirectAction {
  1004  		t.Fatal("Filter DirectAction does not match")
  1005  	}
  1006  
  1007  	if err := FilterDel(filter); err != nil {
  1008  		t.Fatal(err)
  1009  	}
  1010  	filters, err = FilterList(link, HANDLE_MIN_EGRESS)
  1011  	if err != nil {
  1012  		t.Fatal(err)
  1013  	}
  1014  	if len(filters) != 0 {
  1015  		t.Fatal("Failed to remove filter")
  1016  	}
  1017  
  1018  	if err := QdiscDel(qdisc); err != nil {
  1019  		t.Fatal(err)
  1020  	}
  1021  	qdiscs, err := SafeQdiscList(link)
  1022  	if err != nil {
  1023  		t.Fatal(err)
  1024  	}
  1025  	if len(qdiscs) != 0 {
  1026  		t.Fatal("Failed to remove qdisc")
  1027  	}
  1028  }
  1029  
  1030  func TestFilterMatchAllAddDel(t *testing.T) {
  1031  	// This classifier was added in kernel 4.7
  1032  	minKernelRequired(t, 4, 7)
  1033  
  1034  	tearDown := setUpNetlinkTest(t)
  1035  	defer tearDown()
  1036  	_, link := setupLinkForTestWithQdisc(t, "foo")
  1037  	_, link2 := setupLinkForTestWithQdisc(t, "bar")
  1038  	filter := &MatchAll{
  1039  		FilterAttrs: FilterAttrs{
  1040  			LinkIndex: link.Attrs().Index,
  1041  			Parent:    HANDLE_MIN_EGRESS,
  1042  			Priority:  32000,
  1043  			Protocol:  unix.ETH_P_ALL,
  1044  		},
  1045  		Actions: []Action{
  1046  			&MirredAction{
  1047  				ActionAttrs: ActionAttrs{
  1048  					Action: TC_ACT_STOLEN,
  1049  				},
  1050  				MirredAction: TCA_EGRESS_REDIR,
  1051  				Ifindex:      link2.Attrs().Index,
  1052  			},
  1053  		},
  1054  	}
  1055  	if err := FilterAdd(filter); err != nil {
  1056  		t.Fatal(err)
  1057  	}
  1058  
  1059  	filters, err := FilterList(link, HANDLE_MIN_EGRESS)
  1060  	if err != nil {
  1061  		t.Fatal(err)
  1062  	}
  1063  	if len(filters) != 1 {
  1064  		t.Fatal("Failed to add filter")
  1065  	}
  1066  	matchall, ok := filters[0].(*MatchAll)
  1067  	if !ok {
  1068  		t.Fatal("Filter is the wrong type")
  1069  	}
  1070  
  1071  	if matchall.Priority != 32000 {
  1072  		t.Fatal("Filter priority does not match")
  1073  	}
  1074  
  1075  	if len(matchall.Actions) != 1 {
  1076  		t.Fatal("Filter has no actions")
  1077  	}
  1078  
  1079  	mirredAction, ok := matchall.Actions[0].(*MirredAction)
  1080  	if !ok {
  1081  		t.Fatal("Action does not match")
  1082  	}
  1083  
  1084  	if mirredAction.Ifindex != link2.Attrs().Index {
  1085  		t.Fatal("Action ifindex does not match")
  1086  	}
  1087  
  1088  	if err := FilterDel(filter); err != nil {
  1089  		t.Fatal(err)
  1090  	}
  1091  	filters, err = FilterList(link, HANDLE_MIN_EGRESS)
  1092  	if err != nil {
  1093  		t.Fatal(err)
  1094  	}
  1095  	if len(filters) != 0 {
  1096  		t.Fatal("Failed to remove filter")
  1097  	}
  1098  
  1099  }
  1100  
  1101  func TestFilterU32TunnelKeyAddDel(t *testing.T) {
  1102  	tearDown := setUpNetlinkTest(t)
  1103  	defer tearDown()
  1104  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1105  		t.Fatal(err)
  1106  	}
  1107  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1108  		t.Fatal(err)
  1109  	}
  1110  	link, err := LinkByName("foo")
  1111  	if err != nil {
  1112  		t.Fatal(err)
  1113  	}
  1114  	if err := LinkSetUp(link); err != nil {
  1115  		t.Fatal(err)
  1116  	}
  1117  	redir, err := LinkByName("bar")
  1118  	if err != nil {
  1119  		t.Fatal(err)
  1120  	}
  1121  	if err := LinkSetUp(redir); err != nil {
  1122  		t.Fatal(err)
  1123  	}
  1124  
  1125  	qdisc := &Ingress{
  1126  		QdiscAttrs: QdiscAttrs{
  1127  			LinkIndex: link.Attrs().Index,
  1128  			Handle:    MakeHandle(0xffff, 0),
  1129  			Parent:    HANDLE_INGRESS,
  1130  		},
  1131  	}
  1132  	if err := QdiscAdd(qdisc); err != nil {
  1133  		t.Fatal(err)
  1134  	}
  1135  	qdiscs, err := SafeQdiscList(link)
  1136  	if err != nil {
  1137  		t.Fatal(err)
  1138  	}
  1139  
  1140  	found := false
  1141  	for _, v := range qdiscs {
  1142  		if _, ok := v.(*Ingress); ok {
  1143  			found = true
  1144  			break
  1145  		}
  1146  	}
  1147  	if !found {
  1148  		t.Fatal("Qdisc is the wrong type")
  1149  	}
  1150  
  1151  	tunnelAct := NewTunnelKeyAction()
  1152  	tunnelAct.SrcAddr = net.IPv4(10, 10, 10, 1)
  1153  	tunnelAct.DstAddr = net.IPv4(10, 10, 10, 2)
  1154  	tunnelAct.KeyID = 0x01
  1155  	tunnelAct.Action = TCA_TUNNEL_KEY_SET
  1156  	tunnelAct.DestPort = 8472
  1157  
  1158  	classId := MakeHandle(1, 1)
  1159  	filter := &U32{
  1160  		FilterAttrs: FilterAttrs{
  1161  			LinkIndex: link.Attrs().Index,
  1162  			Parent:    MakeHandle(0xffff, 0),
  1163  			Priority:  1,
  1164  			Protocol:  unix.ETH_P_ALL,
  1165  		},
  1166  		ClassId: classId,
  1167  		Actions: []Action{
  1168  			tunnelAct,
  1169  			&MirredAction{
  1170  				ActionAttrs: ActionAttrs{
  1171  					Action: TC_ACT_STOLEN,
  1172  				},
  1173  				MirredAction: TCA_EGRESS_REDIR,
  1174  				Ifindex:      redir.Attrs().Index,
  1175  			},
  1176  		},
  1177  	}
  1178  
  1179  	if err := FilterAdd(filter); err != nil {
  1180  		t.Fatal(err)
  1181  	}
  1182  
  1183  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1184  	if err != nil {
  1185  		t.Fatal(err)
  1186  	}
  1187  	if len(filters) != 1 {
  1188  		t.Fatal("Failed to add filter")
  1189  	}
  1190  	u32, ok := filters[0].(*U32)
  1191  	if !ok {
  1192  		t.Fatal("Filter is the wrong type")
  1193  	}
  1194  
  1195  	if len(u32.Actions) != 2 {
  1196  		t.Fatalf("Too few Actions in filter")
  1197  	}
  1198  	if u32.ClassId != classId {
  1199  		t.Fatalf("ClassId of the filter is the wrong value")
  1200  	}
  1201  
  1202  	// actions can be returned in reverse order
  1203  	tun, ok := u32.Actions[0].(*TunnelKeyAction)
  1204  	if !ok {
  1205  		tun, ok = u32.Actions[1].(*TunnelKeyAction)
  1206  		if !ok {
  1207  			t.Fatal("Unable to find tunnel action")
  1208  		}
  1209  	}
  1210  
  1211  	if tun.Attrs().Action != TC_ACT_PIPE {
  1212  		t.Fatal("TunnelKey action isn't TC_ACT_PIPE")
  1213  	}
  1214  	if !tun.SrcAddr.Equal(tunnelAct.SrcAddr) {
  1215  		t.Fatal("Action SrcAddr doesn't match")
  1216  	}
  1217  	if !tun.DstAddr.Equal(tunnelAct.DstAddr) {
  1218  		t.Fatal("Action DstAddr doesn't match")
  1219  	}
  1220  	if tun.KeyID != tunnelAct.KeyID {
  1221  		t.Fatal("Action KeyID doesn't match")
  1222  	}
  1223  	if tun.DestPort != tunnelAct.DestPort {
  1224  		t.Fatal("Action DestPort doesn't match")
  1225  	}
  1226  	if tun.Action != tunnelAct.Action {
  1227  		t.Fatal("Action doesn't match")
  1228  	}
  1229  
  1230  	mia, ok := u32.Actions[0].(*MirredAction)
  1231  	if !ok {
  1232  		mia, ok = u32.Actions[1].(*MirredAction)
  1233  		if !ok {
  1234  			t.Fatal("Unable to find mirred action")
  1235  		}
  1236  	}
  1237  
  1238  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1239  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1240  	}
  1241  
  1242  	if err := FilterDel(filter); err != nil {
  1243  		t.Fatal(err)
  1244  	}
  1245  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1246  	if err != nil {
  1247  		t.Fatal(err)
  1248  	}
  1249  	if len(filters) != 0 {
  1250  		t.Fatal("Failed to remove filter")
  1251  	}
  1252  
  1253  	if err := QdiscDel(qdisc); err != nil {
  1254  		t.Fatal(err)
  1255  	}
  1256  	qdiscs, err = SafeQdiscList(link)
  1257  	if err != nil {
  1258  		t.Fatal(err)
  1259  	}
  1260  
  1261  	found = false
  1262  	for _, v := range qdiscs {
  1263  		if _, ok := v.(*Ingress); ok {
  1264  			found = true
  1265  			break
  1266  		}
  1267  	}
  1268  	if found {
  1269  		t.Fatal("Failed to remove qdisc")
  1270  	}
  1271  }
  1272  
  1273  func TestFilterU32SkbEditAddDel(t *testing.T) {
  1274  	tearDown := setUpNetlinkTest(t)
  1275  	defer tearDown()
  1276  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1277  		t.Fatal(err)
  1278  	}
  1279  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1280  		t.Fatal(err)
  1281  	}
  1282  	link, err := LinkByName("foo")
  1283  	if err != nil {
  1284  		t.Fatal(err)
  1285  	}
  1286  	if err := LinkSetUp(link); err != nil {
  1287  		t.Fatal(err)
  1288  	}
  1289  	redir, err := LinkByName("bar")
  1290  	if err != nil {
  1291  		t.Fatal(err)
  1292  	}
  1293  	if err := LinkSetUp(redir); err != nil {
  1294  		t.Fatal(err)
  1295  	}
  1296  
  1297  	qdisc := &Ingress{
  1298  		QdiscAttrs: QdiscAttrs{
  1299  			LinkIndex: link.Attrs().Index,
  1300  			Handle:    MakeHandle(0xffff, 0),
  1301  			Parent:    HANDLE_INGRESS,
  1302  		},
  1303  	}
  1304  	if err := QdiscAdd(qdisc); err != nil {
  1305  		t.Fatal(err)
  1306  	}
  1307  	qdiscs, err := SafeQdiscList(link)
  1308  	if err != nil {
  1309  		t.Fatal(err)
  1310  	}
  1311  
  1312  	found := false
  1313  	for _, v := range qdiscs {
  1314  		if _, ok := v.(*Ingress); ok {
  1315  			found = true
  1316  			break
  1317  		}
  1318  	}
  1319  	if !found {
  1320  		t.Fatal("Qdisc is the wrong type")
  1321  	}
  1322  
  1323  	skbedit := NewSkbEditAction()
  1324  	ptype := uint16(unix.PACKET_HOST)
  1325  	skbedit.PType = &ptype
  1326  	priority := uint32(0xff)
  1327  	skbedit.Priority = &priority
  1328  	mark := uint32(0xfe)
  1329  	skbedit.Mark = &mark
  1330  	mapping := uint16(0xf)
  1331  	skbedit.QueueMapping = &mapping
  1332  
  1333  	classId := MakeHandle(1, 1)
  1334  	filter := &U32{
  1335  		FilterAttrs: FilterAttrs{
  1336  			LinkIndex: link.Attrs().Index,
  1337  			Parent:    MakeHandle(0xffff, 0),
  1338  			Priority:  1,
  1339  			Protocol:  unix.ETH_P_ALL,
  1340  		},
  1341  		ClassId: classId,
  1342  		Actions: []Action{
  1343  			skbedit,
  1344  			&MirredAction{
  1345  				ActionAttrs: ActionAttrs{
  1346  					Action: TC_ACT_STOLEN,
  1347  				},
  1348  				MirredAction: TCA_EGRESS_REDIR,
  1349  				Ifindex:      redir.Attrs().Index,
  1350  			},
  1351  		},
  1352  	}
  1353  
  1354  	if err := FilterAdd(filter); err != nil {
  1355  		t.Fatal(err)
  1356  	}
  1357  
  1358  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1359  	if err != nil {
  1360  		t.Fatal(err)
  1361  	}
  1362  	if len(filters) != 1 {
  1363  		t.Fatal("Failed to add filter")
  1364  	}
  1365  	u32, ok := filters[0].(*U32)
  1366  	if !ok {
  1367  		t.Fatal("Filter is the wrong type")
  1368  	}
  1369  
  1370  	if len(u32.Actions) != 2 {
  1371  		t.Fatalf("Too few Actions in filter")
  1372  	}
  1373  	if u32.ClassId != classId {
  1374  		t.Fatalf("ClassId of the filter is the wrong value")
  1375  	}
  1376  
  1377  	// actions can be returned in reverse order
  1378  	edit, ok := u32.Actions[0].(*SkbEditAction)
  1379  	if !ok {
  1380  		edit, ok = u32.Actions[1].(*SkbEditAction)
  1381  		if !ok {
  1382  			t.Fatal("Unable to find tunnel action")
  1383  		}
  1384  	}
  1385  
  1386  	if edit.Attrs().Action != TC_ACT_PIPE {
  1387  		t.Fatal("SkbEdit action isn't TC_ACT_PIPE")
  1388  	}
  1389  	if edit.PType == nil || *edit.PType != *skbedit.PType {
  1390  		t.Fatal("Action PType doesn't match")
  1391  	}
  1392  	if edit.QueueMapping == nil || *edit.QueueMapping != *skbedit.QueueMapping {
  1393  		t.Fatal("Action QueueMapping doesn't match")
  1394  	}
  1395  	if edit.Mark == nil || *edit.Mark != *skbedit.Mark {
  1396  		t.Fatal("Action Mark doesn't match")
  1397  	}
  1398  	if edit.Priority == nil || *edit.Priority != *skbedit.Priority {
  1399  		t.Fatal("Action Priority doesn't match")
  1400  	}
  1401  
  1402  	mia, ok := u32.Actions[0].(*MirredAction)
  1403  	if !ok {
  1404  		mia, ok = u32.Actions[1].(*MirredAction)
  1405  		if !ok {
  1406  			t.Fatal("Unable to find mirred action")
  1407  		}
  1408  	}
  1409  
  1410  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1411  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1412  	}
  1413  
  1414  	if err := FilterDel(filter); err != nil {
  1415  		t.Fatal(err)
  1416  	}
  1417  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1418  	if err != nil {
  1419  		t.Fatal(err)
  1420  	}
  1421  	if len(filters) != 0 {
  1422  		t.Fatal("Failed to remove filter")
  1423  	}
  1424  
  1425  	if err := QdiscDel(qdisc); err != nil {
  1426  		t.Fatal(err)
  1427  	}
  1428  	qdiscs, err = SafeQdiscList(link)
  1429  	if err != nil {
  1430  		t.Fatal(err)
  1431  	}
  1432  
  1433  	found = false
  1434  	for _, v := range qdiscs {
  1435  		if _, ok := v.(*Ingress); ok {
  1436  			found = true
  1437  			break
  1438  		}
  1439  	}
  1440  	if found {
  1441  		t.Fatal("Failed to remove qdisc")
  1442  	}
  1443  }
  1444  
  1445  func TestFilterU32LinkOption(t *testing.T) {
  1446  	tearDown := setUpNetlinkTest(t)
  1447  	defer tearDown()
  1448  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1449  		t.Fatalf("add link foo error: %v", err)
  1450  	}
  1451  	link, err := LinkByName("foo")
  1452  	if err != nil {
  1453  		t.Fatalf("add link foo error: %v", err)
  1454  	}
  1455  	if err := LinkSetUp(link); err != nil {
  1456  		t.Fatalf("set foo link up error: %v", err)
  1457  	}
  1458  
  1459  	qdisc := &Ingress{
  1460  		QdiscAttrs: QdiscAttrs{
  1461  			LinkIndex: link.Attrs().Index,
  1462  			Handle:    MakeHandle(0xffff, 0),
  1463  			Parent:    HANDLE_INGRESS,
  1464  		},
  1465  	}
  1466  	if err := QdiscAdd(qdisc); err != nil {
  1467  		t.Fatal(err)
  1468  	}
  1469  	qdiscs, err := SafeQdiscList(link)
  1470  	if err != nil {
  1471  		t.Fatalf("get qdisc error: %v", err)
  1472  	}
  1473  
  1474  	found := false
  1475  	for _, v := range qdiscs {
  1476  		if _, ok := v.(*Ingress); ok {
  1477  			found = true
  1478  			break
  1479  		}
  1480  	}
  1481  	if !found {
  1482  		t.Fatal("Qdisc is the wrong type")
  1483  	}
  1484  
  1485  	htid := uint32(10)
  1486  	size := uint32(8)
  1487  	priority := uint16(200)
  1488  	u32Table := &U32{
  1489  		FilterAttrs: FilterAttrs{
  1490  			LinkIndex: link.Attrs().Index,
  1491  			Handle:    htid << 20,
  1492  			Parent:    MakeHandle(0xffff, 0),
  1493  			Priority:  priority,
  1494  			Protocol:  unix.ETH_P_ALL,
  1495  		},
  1496  		Divisor: size,
  1497  	}
  1498  	if err := FilterAdd(u32Table); err != nil {
  1499  		t.Fatal(err)
  1500  	}
  1501  
  1502  	u32 := &U32{
  1503  		FilterAttrs: FilterAttrs{
  1504  			LinkIndex: link.Attrs().Index,
  1505  			Parent:    MakeHandle(0xffff, 0),
  1506  			Handle:    1,
  1507  			Priority:  priority,
  1508  			Protocol:  unix.ETH_P_ALL,
  1509  		},
  1510  		Link: uint32(htid << 20),
  1511  		Sel: &TcU32Sel{
  1512  			Nkeys:    1,
  1513  			Flags:    TC_U32_TERMINAL | TC_U32_VAROFFSET,
  1514  			Hmask:    0x0000ff00,
  1515  			Hoff:     0,
  1516  			Offshift: 8,
  1517  			Keys: []TcU32Key{
  1518  				{
  1519  					Mask: 0,
  1520  					Val:  0,
  1521  					Off:  0,
  1522  				},
  1523  			},
  1524  		},
  1525  	}
  1526  	if err := FilterAdd(u32); err != nil {
  1527  		t.Fatal(err)
  1528  	}
  1529  
  1530  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1531  	if err != nil {
  1532  		t.Fatalf("get filter error: %v", err)
  1533  	}
  1534  
  1535  	if len(filters) != 1 {
  1536  		t.Fatalf("the count filters error, expect: 1, acutal: %d", len(filters))
  1537  	}
  1538  
  1539  	ft, ok := filters[0].(*U32)
  1540  	if !ok {
  1541  		t.Fatal("Filter is the wrong type")
  1542  	}
  1543  
  1544  	if ft.LinkIndex != link.Attrs().Index {
  1545  		t.Fatal("link index error")
  1546  	}
  1547  
  1548  	if ft.Link != htid<<20 {
  1549  		t.Fatal("hash table id error")
  1550  	}
  1551  
  1552  	if ft.Priority != priority {
  1553  		t.Fatal("priority error")
  1554  	}
  1555  
  1556  	if err := FilterDel(ft); err != nil {
  1557  		t.Fatal(err)
  1558  	}
  1559  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1560  	if err != nil {
  1561  		t.Fatal(err)
  1562  	}
  1563  	if len(filters) != 0 {
  1564  		t.Fatal("Failed to remove filter")
  1565  	}
  1566  
  1567  	if err := QdiscDel(qdisc); err != nil {
  1568  		t.Fatal(err)
  1569  	}
  1570  	qdiscs, err = SafeQdiscList(link)
  1571  	if err != nil {
  1572  		t.Fatal(err)
  1573  	}
  1574  
  1575  	found = false
  1576  	for _, v := range qdiscs {
  1577  		if _, ok := v.(*Ingress); ok {
  1578  			found = true
  1579  			break
  1580  		}
  1581  	}
  1582  	if found {
  1583  		t.Fatal("Failed to remove qdisc")
  1584  	}
  1585  }
  1586  
  1587  func TestFilterFlowerAddDel(t *testing.T) {
  1588  	tearDown := setUpNetlinkTest(t)
  1589  	defer tearDown()
  1590  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1591  		t.Fatal(err)
  1592  	}
  1593  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1594  		t.Fatal(err)
  1595  	}
  1596  	link, err := LinkByName("foo")
  1597  	if err != nil {
  1598  		t.Fatal(err)
  1599  	}
  1600  	if err := LinkSetUp(link); err != nil {
  1601  		t.Fatal(err)
  1602  	}
  1603  	redir, err := LinkByName("bar")
  1604  	if err != nil {
  1605  		t.Fatal(err)
  1606  	}
  1607  	if err := LinkSetUp(redir); err != nil {
  1608  		t.Fatal(err)
  1609  	}
  1610  
  1611  	qdisc := &Ingress{
  1612  		QdiscAttrs: QdiscAttrs{
  1613  			LinkIndex: link.Attrs().Index,
  1614  			Handle:    MakeHandle(0xffff, 0),
  1615  			Parent:    HANDLE_INGRESS,
  1616  		},
  1617  	}
  1618  	if err := QdiscAdd(qdisc); err != nil {
  1619  		t.Fatal(err)
  1620  	}
  1621  	qdiscs, err := SafeQdiscList(link)
  1622  	if err != nil {
  1623  		t.Fatal(err)
  1624  	}
  1625  
  1626  	found := false
  1627  	for _, v := range qdiscs {
  1628  		if _, ok := v.(*Ingress); ok {
  1629  			found = true
  1630  			break
  1631  		}
  1632  	}
  1633  	if !found {
  1634  		t.Fatal("Qdisc is the wrong type")
  1635  	}
  1636  
  1637  	testMask := net.CIDRMask(24, 32)
  1638  
  1639  	filter := &Flower{
  1640  		FilterAttrs: FilterAttrs{
  1641  			LinkIndex: link.Attrs().Index,
  1642  			Parent:    MakeHandle(0xffff, 0),
  1643  			Priority:  1,
  1644  			Protocol:  unix.ETH_P_ALL,
  1645  		},
  1646  		DestIP:        net.ParseIP("1.0.0.1"),
  1647  		DestIPMask:    testMask,
  1648  		SrcIP:         net.ParseIP("2.0.0.1"),
  1649  		SrcIPMask:     testMask,
  1650  		EthType:       unix.ETH_P_IP,
  1651  		EncDestIP:     net.ParseIP("3.0.0.1"),
  1652  		EncDestIPMask: testMask,
  1653  		EncSrcIP:      net.ParseIP("4.0.0.1"),
  1654  		EncSrcIPMask:  testMask,
  1655  		EncDestPort:   8472,
  1656  		EncKeyId:      1234,
  1657  		Actions: []Action{
  1658  			&MirredAction{
  1659  				ActionAttrs: ActionAttrs{
  1660  					Action: TC_ACT_STOLEN,
  1661  				},
  1662  				MirredAction: TCA_EGRESS_REDIR,
  1663  				Ifindex:      redir.Attrs().Index,
  1664  			},
  1665  		},
  1666  	}
  1667  
  1668  	if err := FilterAdd(filter); err != nil {
  1669  		t.Fatal(err)
  1670  	}
  1671  
  1672  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1673  	if err != nil {
  1674  		t.Fatal(err)
  1675  	}
  1676  	if len(filters) != 1 {
  1677  		t.Fatal("Failed to add filter")
  1678  	}
  1679  	flower, ok := filters[0].(*Flower)
  1680  	if !ok {
  1681  		t.Fatal("Filter is the wrong type")
  1682  	}
  1683  
  1684  	if filter.EthType != flower.EthType {
  1685  		t.Fatalf("Flower EthType doesn't match")
  1686  	}
  1687  	if !filter.DestIP.Equal(flower.DestIP) {
  1688  		t.Fatalf("Flower DestIP doesn't match")
  1689  	}
  1690  	if !filter.SrcIP.Equal(flower.SrcIP) {
  1691  		t.Fatalf("Flower SrcIP doesn't match")
  1692  	}
  1693  
  1694  	if !reflect.DeepEqual(filter.DestIPMask, testMask) {
  1695  		t.Fatalf("Flower DestIPMask doesn't match")
  1696  	}
  1697  	if !reflect.DeepEqual(filter.SrcIPMask, testMask) {
  1698  		t.Fatalf("Flower SrcIPMask doesn't match")
  1699  	}
  1700  
  1701  	if !filter.EncDestIP.Equal(flower.EncDestIP) {
  1702  		t.Fatalf("Flower EncDestIP doesn't match")
  1703  	}
  1704  	if !filter.EncSrcIP.Equal(flower.EncSrcIP) {
  1705  		t.Fatalf("Flower EncSrcIP doesn't match")
  1706  	}
  1707  	if !reflect.DeepEqual(filter.EncDestIPMask, testMask) {
  1708  		t.Fatalf("Flower EncDestIPMask doesn't match")
  1709  	}
  1710  	if !reflect.DeepEqual(filter.EncSrcIPMask, testMask) {
  1711  		t.Fatalf("Flower EncSrcIPMask doesn't match")
  1712  	}
  1713  	if filter.EncKeyId != flower.EncKeyId {
  1714  		t.Fatalf("Flower EncKeyId doesn't match")
  1715  	}
  1716  	if filter.EncDestPort != flower.EncDestPort {
  1717  		t.Fatalf("Flower EncDestPort doesn't match")
  1718  	}
  1719  
  1720  	mia, ok := flower.Actions[0].(*MirredAction)
  1721  	if !ok {
  1722  		t.Fatal("Unable to find mirred action")
  1723  	}
  1724  
  1725  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1726  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1727  	}
  1728  
  1729  	if err := FilterDel(filter); err != nil {
  1730  		t.Fatal(err)
  1731  	}
  1732  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1733  	if err != nil {
  1734  		t.Fatal(err)
  1735  	}
  1736  	if len(filters) != 0 {
  1737  		t.Fatal("Failed to remove filter")
  1738  	}
  1739  
  1740  	if err := QdiscDel(qdisc); err != nil {
  1741  		t.Fatal(err)
  1742  	}
  1743  	qdiscs, err = SafeQdiscList(link)
  1744  	if err != nil {
  1745  		t.Fatal(err)
  1746  	}
  1747  
  1748  	found = false
  1749  	for _, v := range qdiscs {
  1750  		if _, ok := v.(*Ingress); ok {
  1751  			found = true
  1752  			break
  1753  		}
  1754  	}
  1755  	if found {
  1756  		t.Fatal("Failed to remove qdisc")
  1757  	}
  1758  }
  1759  
  1760  func TestFilterU32PoliceAddDel(t *testing.T) {
  1761  	tearDown := setUpNetlinkTest(t)
  1762  	defer tearDown()
  1763  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1764  		t.Fatal(err)
  1765  	}
  1766  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1767  		t.Fatal(err)
  1768  	}
  1769  	link, err := LinkByName("foo")
  1770  	if err != nil {
  1771  		t.Fatal(err)
  1772  	}
  1773  	if err := LinkSetUp(link); err != nil {
  1774  		t.Fatal(err)
  1775  	}
  1776  	redir, err := LinkByName("bar")
  1777  	if err != nil {
  1778  		t.Fatal(err)
  1779  	}
  1780  	if err := LinkSetUp(redir); err != nil {
  1781  		t.Fatal(err)
  1782  	}
  1783  
  1784  	qdisc := &Ingress{
  1785  		QdiscAttrs: QdiscAttrs{
  1786  			LinkIndex: link.Attrs().Index,
  1787  			Handle:    MakeHandle(0xffff, 0),
  1788  			Parent:    HANDLE_INGRESS,
  1789  		},
  1790  	}
  1791  	if err := QdiscAdd(qdisc); err != nil {
  1792  		t.Fatal(err)
  1793  	}
  1794  	qdiscs, err := SafeQdiscList(link)
  1795  	if err != nil {
  1796  		t.Fatal(err)
  1797  	}
  1798  
  1799  	found := false
  1800  	for _, v := range qdiscs {
  1801  		if _, ok := v.(*Ingress); ok {
  1802  			found = true
  1803  			break
  1804  		}
  1805  	}
  1806  	if !found {
  1807  		t.Fatal("Qdisc is the wrong type")
  1808  	}
  1809  
  1810  	const (
  1811  		policeRate     = 0x40000000 // 1 Gbps
  1812  		policeBurst    = 0x19000    // 100 KB
  1813  		policePeakRate = 0x4000     // 16 Kbps
  1814  	)
  1815  
  1816  	police := NewPoliceAction()
  1817  	police.Rate = policeRate
  1818  	police.PeakRate = policePeakRate
  1819  	police.Burst = policeBurst
  1820  	police.ExceedAction = TC_POLICE_SHOT
  1821  	police.NotExceedAction = TC_POLICE_UNSPEC
  1822  
  1823  	classId := MakeHandle(1, 1)
  1824  	filter := &U32{
  1825  		FilterAttrs: FilterAttrs{
  1826  			LinkIndex: link.Attrs().Index,
  1827  			Parent:    MakeHandle(0xffff, 0),
  1828  			Priority:  1,
  1829  			Protocol:  unix.ETH_P_ALL,
  1830  		},
  1831  		ClassId: classId,
  1832  		Actions: []Action{
  1833  			police,
  1834  			&MirredAction{
  1835  				ActionAttrs: ActionAttrs{
  1836  					Action: TC_ACT_STOLEN,
  1837  				},
  1838  				MirredAction: TCA_EGRESS_REDIR,
  1839  				Ifindex:      redir.Attrs().Index,
  1840  			},
  1841  		},
  1842  	}
  1843  
  1844  	if err := FilterAdd(filter); err != nil {
  1845  		t.Fatal(err)
  1846  	}
  1847  
  1848  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1849  	if err != nil {
  1850  		t.Fatal(err)
  1851  	}
  1852  	if len(filters) != 1 {
  1853  		t.Fatal("Failed to add filter")
  1854  	}
  1855  	u32, ok := filters[0].(*U32)
  1856  	if !ok {
  1857  		t.Fatal("Filter is the wrong type")
  1858  	}
  1859  
  1860  	if len(u32.Actions) != 2 {
  1861  		t.Fatalf("Too few Actions in filter")
  1862  	}
  1863  	if u32.ClassId != classId {
  1864  		t.Fatalf("ClassId of the filter is the wrong value")
  1865  	}
  1866  
  1867  	// actions can be returned in reverse order
  1868  	p, ok := u32.Actions[0].(*PoliceAction)
  1869  	if !ok {
  1870  		p, ok = u32.Actions[1].(*PoliceAction)
  1871  		if !ok {
  1872  			t.Fatal("Unable to find police action")
  1873  		}
  1874  	}
  1875  
  1876  	if p.ExceedAction != TC_POLICE_SHOT {
  1877  		t.Fatal("Police ExceedAction isn't TC_POLICE_SHOT")
  1878  	}
  1879  
  1880  	if p.NotExceedAction != TC_POLICE_UNSPEC {
  1881  		t.Fatal("Police NotExceedAction isn't TC_POLICE_UNSPEC")
  1882  	}
  1883  
  1884  	if p.Rate != policeRate {
  1885  		t.Fatal("Action Rate doesn't match")
  1886  	}
  1887  
  1888  	if p.PeakRate != policePeakRate {
  1889  		t.Fatal("Action PeakRate doesn't match")
  1890  	}
  1891  
  1892  	if p.LinkLayer != nl.LINKLAYER_ETHERNET {
  1893  		t.Fatal("Action LinkLayer doesn't match")
  1894  	}
  1895  
  1896  	mia, ok := u32.Actions[0].(*MirredAction)
  1897  	if !ok {
  1898  		mia, ok = u32.Actions[1].(*MirredAction)
  1899  		if !ok {
  1900  			t.Fatal("Unable to find mirred action")
  1901  		}
  1902  	}
  1903  
  1904  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1905  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1906  	}
  1907  
  1908  	if err := FilterDel(filter); err != nil {
  1909  		t.Fatal(err)
  1910  	}
  1911  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1912  	if err != nil {
  1913  		t.Fatal(err)
  1914  	}
  1915  	if len(filters) != 0 {
  1916  		t.Fatal("Failed to remove filter")
  1917  	}
  1918  
  1919  	if err := QdiscDel(qdisc); err != nil {
  1920  		t.Fatal(err)
  1921  	}
  1922  	qdiscs, err = SafeQdiscList(link)
  1923  	if err != nil {
  1924  		t.Fatal(err)
  1925  	}
  1926  
  1927  	found = false
  1928  	for _, v := range qdiscs {
  1929  		if _, ok := v.(*Ingress); ok {
  1930  			found = true
  1931  			break
  1932  		}
  1933  	}
  1934  	if found {
  1935  		t.Fatal("Failed to remove qdisc")
  1936  	}
  1937  }