github.com/vishvananda/netlink@v1.3.1/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  	"time"
    11  
    12  	"github.com/vishvananda/netlink/nl"
    13  	"golang.org/x/sys/unix"
    14  )
    15  
    16  func TestFilterAddDel(t *testing.T) {
    17  	tearDown := setUpNetlinkTest(t)
    18  	defer tearDown()
    19  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
    20  		t.Fatal(err)
    21  	}
    22  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
    23  		t.Fatal(err)
    24  	}
    25  	link, err := LinkByName("foo")
    26  	if err != nil {
    27  		t.Fatal(err)
    28  	}
    29  	if err := LinkSetUp(link); err != nil {
    30  		t.Fatal(err)
    31  	}
    32  	redir, err := LinkByName("bar")
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	if err := LinkSetUp(redir); err != nil {
    37  		t.Fatal(err)
    38  	}
    39  	qdisc := &Ingress{
    40  		QdiscAttrs: QdiscAttrs{
    41  			LinkIndex: link.Attrs().Index,
    42  			Handle:    MakeHandle(0xffff, 0),
    43  			Parent:    HANDLE_INGRESS,
    44  		},
    45  	}
    46  	if err := QdiscAdd(qdisc); err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	qdiscs, err := SafeQdiscList(link)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	if len(qdiscs) != 1 {
    54  		t.Fatal("Failed to add qdisc")
    55  	}
    56  	_, ok := qdiscs[0].(*Ingress)
    57  	if !ok {
    58  		t.Fatal("Qdisc is the wrong type")
    59  	}
    60  	classId := MakeHandle(1, 1)
    61  	filter := &U32{
    62  		FilterAttrs: FilterAttrs{
    63  			LinkIndex: link.Attrs().Index,
    64  			Parent:    MakeHandle(0xffff, 0),
    65  			Priority:  1,
    66  			Protocol:  unix.ETH_P_IP,
    67  		},
    68  		RedirIndex: redir.Attrs().Index,
    69  		ClassId:    classId,
    70  	}
    71  	if err := FilterAdd(filter); err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
    75  	if err != nil {
    76  		t.Fatal(err)
    77  	}
    78  	if len(filters) != 1 {
    79  		t.Fatal("Failed to add filter")
    80  	}
    81  	u32, ok := filters[0].(*U32)
    82  	if !ok {
    83  		t.Fatal("Filter is the wrong type")
    84  	}
    85  	if u32.ClassId != classId {
    86  		t.Fatalf("ClassId of the filter is the wrong value")
    87  	}
    88  	if err := FilterDel(filter); err != nil {
    89  		t.Fatal(err)
    90  	}
    91  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
    92  	if err != nil {
    93  		t.Fatal(err)
    94  	}
    95  	if len(filters) != 0 {
    96  		t.Fatal("Failed to remove filter")
    97  	}
    98  	if err := QdiscDel(qdisc); err != nil {
    99  		t.Fatal(err)
   100  	}
   101  	qdiscs, err = SafeQdiscList(link)
   102  	if err != nil {
   103  		t.Fatal(err)
   104  	}
   105  	if len(qdiscs) != 0 {
   106  		t.Fatal("Failed to remove qdisc")
   107  	}
   108  }
   109  
   110  func TestFilterReplace(t *testing.T) {
   111  	tearDown := setUpNetlinkTest(t)
   112  	defer tearDown()
   113  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   117  		t.Fatal(err)
   118  	}
   119  	link, err := LinkByName("foo")
   120  	if err != nil {
   121  		t.Fatal(err)
   122  	}
   123  	if err := LinkSetUp(link); err != nil {
   124  		t.Fatal(err)
   125  	}
   126  	redir, err := LinkByName("bar")
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	if err := LinkSetUp(redir); err != nil {
   131  		t.Fatal(err)
   132  	}
   133  	qdisc := &Ingress{
   134  		QdiscAttrs: QdiscAttrs{
   135  			LinkIndex: link.Attrs().Index,
   136  			Handle:    MakeHandle(0xffff, 0),
   137  			Parent:    HANDLE_INGRESS,
   138  		},
   139  	}
   140  	if err := QdiscAdd(qdisc); err != nil {
   141  		t.Fatal(err)
   142  	}
   143  
   144  	filter := &U32{
   145  		FilterAttrs: FilterAttrs{
   146  			LinkIndex: link.Attrs().Index,
   147  			Parent:    MakeHandle(0xffff, 0),
   148  			Priority:  1,
   149  			Protocol:  unix.ETH_P_IP,
   150  		},
   151  		RedirIndex: redir.Attrs().Index,
   152  		ClassId:    MakeHandle(1, 1),
   153  	}
   154  
   155  	if err := FilterReplace(filter); err != nil {
   156  		t.Fatal(err)
   157  	}
   158  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	if len(filters) != 1 {
   163  		t.Fatal("Failed replace filter")
   164  	}
   165  
   166  	if err := FilterReplace(filter); err != nil {
   167  		t.Fatal(err)
   168  	}
   169  }
   170  
   171  func TestAdvancedFilterAddDel(t *testing.T) {
   172  	tearDown := setUpNetlinkTest(t)
   173  	defer tearDown()
   174  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "baz"}}); err != nil {
   175  		t.Fatal(err)
   176  	}
   177  	link, err := LinkByName("baz")
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	if err := LinkSetUp(link); err != nil {
   182  		t.Fatal(err)
   183  	}
   184  	index := link.Attrs().Index
   185  
   186  	qdiscHandle := MakeHandle(0x1, 0x0)
   187  	qdiscAttrs := QdiscAttrs{
   188  		LinkIndex: index,
   189  		Handle:    qdiscHandle,
   190  		Parent:    HANDLE_ROOT,
   191  	}
   192  
   193  	qdisc := NewHtb(qdiscAttrs)
   194  	if err := QdiscAdd(qdisc); err != nil {
   195  		t.Fatal(err)
   196  	}
   197  	qdiscs, err := SafeQdiscList(link)
   198  	if err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	if len(qdiscs) != 1 {
   202  		t.Fatal("Failed to add qdisc")
   203  	}
   204  	_, ok := qdiscs[0].(*Htb)
   205  	if !ok {
   206  		t.Fatal("Qdisc is the wrong type")
   207  	}
   208  
   209  	classId := MakeHandle(0x1, 0x46cb)
   210  	classAttrs := ClassAttrs{
   211  		LinkIndex: index,
   212  		Parent:    qdiscHandle,
   213  		Handle:    classId,
   214  	}
   215  	htbClassAttrs := HtbClassAttrs{
   216  		Rate:   512 * 1024,
   217  		Buffer: 32 * 1024,
   218  	}
   219  	htbClass := NewHtbClass(classAttrs, htbClassAttrs)
   220  	if err = ClassReplace(htbClass); err != nil {
   221  		t.Fatalf("Failed to add a HTB class: %v", err)
   222  	}
   223  	classes, err := SafeClassList(link, qdiscHandle)
   224  	if err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	if len(classes) != 1 {
   228  		t.Fatal("Failed to add class")
   229  	}
   230  	_, ok = classes[0].(*HtbClass)
   231  	if !ok {
   232  		t.Fatal("Class is the wrong type")
   233  	}
   234  
   235  	htid := MakeHandle(0x0010, 0000)
   236  	divisor := uint32(1)
   237  	hashTable := &U32{
   238  		FilterAttrs: FilterAttrs{
   239  			LinkIndex: index,
   240  			Handle:    htid,
   241  			Parent:    qdiscHandle,
   242  			Priority:  1,
   243  			Protocol:  unix.ETH_P_ALL,
   244  		},
   245  		Divisor: divisor,
   246  	}
   247  	cHashTable := *hashTable
   248  	if err := FilterAdd(hashTable); err != nil {
   249  		t.Fatal(err)
   250  	}
   251  	// Check if the hash table is identical before and after FilterAdd.
   252  	if !reflect.DeepEqual(cHashTable, *hashTable) {
   253  		t.Fatalf("Hash table %v and %v are not equal", cHashTable, *hashTable)
   254  	}
   255  
   256  	u32SelKeys := []TcU32Key{
   257  		{
   258  			Mask:    0xff,
   259  			Val:     80,
   260  			Off:     20,
   261  			OffMask: 0,
   262  		},
   263  		{
   264  			Mask:    0xffff,
   265  			Val:     0x146ca,
   266  			Off:     32,
   267  			OffMask: 0,
   268  		},
   269  	}
   270  
   271  	handle := MakeHandle(0x0000, 0001)
   272  	filter := &U32{
   273  		FilterAttrs: FilterAttrs{
   274  			LinkIndex: index,
   275  			Handle:    handle,
   276  			Parent:    qdiscHandle,
   277  			Priority:  1,
   278  			Protocol:  unix.ETH_P_ALL,
   279  		},
   280  		Sel: &TcU32Sel{
   281  			Keys:  u32SelKeys,
   282  			Flags: TC_U32_TERMINAL,
   283  		},
   284  		ClassId: classId,
   285  		Hash:    htid,
   286  		Actions: []Action{},
   287  	}
   288  	// Copy filter.
   289  	cFilter := *filter
   290  	if err := FilterAdd(filter); err != nil {
   291  		t.Fatal(err)
   292  	}
   293  	// Check if the filter is identical before and after FilterAdd.
   294  	if !reflect.DeepEqual(cFilter, *filter) {
   295  		t.Fatalf("U32 %v and %v are not equal", cFilter, *filter)
   296  	}
   297  
   298  	filters, err := FilterList(link, qdiscHandle)
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  	if len(filters) != 1 {
   303  		t.Fatal("Failed to add filter")
   304  	}
   305  
   306  	u32, ok := filters[0].(*U32)
   307  	if !ok {
   308  		t.Fatal("Filter is the wrong type")
   309  	}
   310  	// Endianness checks
   311  	if u32.Sel.Offmask != filter.Sel.Offmask {
   312  		t.Fatal("The endianness of TcU32Key.Sel.Offmask is wrong")
   313  	}
   314  	if u32.Sel.Hmask != filter.Sel.Hmask {
   315  		t.Fatal("The endianness of TcU32Key.Sel.Hmask is wrong")
   316  	}
   317  	for i, key := range u32.Sel.Keys {
   318  		if key.Mask != filter.Sel.Keys[i].Mask {
   319  			t.Fatal("The endianness of TcU32Key.Mask is wrong")
   320  		}
   321  		if key.Val != filter.Sel.Keys[i].Val {
   322  			t.Fatal("The endianness of TcU32Key.Val is wrong")
   323  		}
   324  	}
   325  	if u32.Handle != (handle | htid) {
   326  		t.Fatalf("The handle is wrong. expected %v but actually %v",
   327  			(handle | htid), u32.Handle)
   328  	}
   329  	if u32.Hash != htid {
   330  		t.Fatal("The hash table ID is wrong")
   331  	}
   332  
   333  	if err := FilterDel(u32); err != nil {
   334  		t.Fatal(err)
   335  	}
   336  	filters, err = FilterList(link, qdiscHandle)
   337  	if err != nil {
   338  		t.Fatal(err)
   339  	}
   340  	if len(filters) != 0 {
   341  		t.Fatal("Failed to remove filter")
   342  	}
   343  
   344  	if err = ClassDel(htbClass); err != nil {
   345  		t.Fatalf("Failed to delete a HTP class: %v", err)
   346  	}
   347  	classes, err = SafeClassList(link, qdiscHandle)
   348  	if err != nil {
   349  		t.Fatal(err)
   350  	}
   351  	if len(classes) != 0 {
   352  		t.Fatal("Failed to remove class")
   353  	}
   354  
   355  	if err := QdiscDel(qdisc); err != nil {
   356  		t.Fatal(err)
   357  	}
   358  	qdiscs, err = SafeQdiscList(link)
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  	if len(qdiscs) != 0 {
   363  		t.Fatal("Failed to remove qdisc")
   364  	}
   365  }
   366  
   367  func TestFilterFwAddDel(t *testing.T) {
   368  	tearDown := setUpNetlinkTest(t)
   369  	defer tearDown()
   370  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   371  		t.Fatal(err)
   372  	}
   373  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   374  		t.Fatal(err)
   375  	}
   376  	link, err := LinkByName("foo")
   377  	if err != nil {
   378  		t.Fatal(err)
   379  	}
   380  	if err := LinkSetUp(link); err != nil {
   381  		t.Fatal(err)
   382  	}
   383  	redir, err := LinkByName("bar")
   384  	if err != nil {
   385  		t.Fatal(err)
   386  	}
   387  	if err := LinkSetUp(redir); err != nil {
   388  		t.Fatal(err)
   389  	}
   390  	attrs := QdiscAttrs{
   391  		LinkIndex: link.Attrs().Index,
   392  		Handle:    MakeHandle(0xffff, 0),
   393  		Parent:    HANDLE_ROOT,
   394  	}
   395  	qdisc := NewHtb(attrs)
   396  	if err := QdiscAdd(qdisc); err != nil {
   397  		t.Fatal(err)
   398  	}
   399  	qdiscs, err := SafeQdiscList(link)
   400  	if err != nil {
   401  		t.Fatal(err)
   402  	}
   403  	if len(qdiscs) != 1 {
   404  		t.Fatal("Failed to add qdisc")
   405  	}
   406  	_, ok := qdiscs[0].(*Htb)
   407  	if !ok {
   408  		t.Fatal("Qdisc is the wrong type")
   409  	}
   410  
   411  	classattrs := ClassAttrs{
   412  		LinkIndex: link.Attrs().Index,
   413  		Parent:    MakeHandle(0xffff, 0),
   414  		Handle:    MakeHandle(0xffff, 2),
   415  	}
   416  
   417  	htbclassattrs := HtbClassAttrs{
   418  		Rate:    1234000,
   419  		Cbuffer: 1690,
   420  	}
   421  	class := NewHtbClass(classattrs, htbclassattrs)
   422  	if err := ClassAdd(class); err != nil {
   423  		t.Fatal(err)
   424  	}
   425  	classes, err := SafeClassList(link, MakeHandle(0xffff, 2))
   426  	if err != nil {
   427  		t.Fatal(err)
   428  	}
   429  	if len(classes) != 1 {
   430  		t.Fatal("Failed to add class")
   431  	}
   432  
   433  	police := NewPoliceAction()
   434  	police.Burst = 12345
   435  	police.Rate = 1234
   436  	police.PeakRate = 2345
   437  	police.Action = TcAct(TC_POLICE_SHOT)
   438  
   439  	filterattrs := FilterAttrs{
   440  		LinkIndex: link.Attrs().Index,
   441  		Parent:    MakeHandle(0xffff, 0),
   442  		Handle:    MakeHandle(0, 0x6),
   443  		Priority:  1,
   444  		Protocol:  unix.ETH_P_IP,
   445  	}
   446  
   447  	filter := FwFilter{
   448  		FilterAttrs: filterattrs,
   449  		ClassId:     MakeHandle(0xffff, 2),
   450  		Police:      police,
   451  	}
   452  
   453  	if err := FilterAdd(&filter); err != nil {
   454  		t.Fatal(err)
   455  	}
   456  
   457  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   458  	if err != nil {
   459  		t.Fatal(err)
   460  	}
   461  	if len(filters) != 1 {
   462  		t.Fatal("Failed to add filter")
   463  	}
   464  	fw, ok := filters[0].(*FwFilter)
   465  	if !ok {
   466  		t.Fatal("Filter is the wrong type")
   467  	}
   468  	if fw.Police.Rate != filter.Police.Rate {
   469  		t.Fatal("Police Rate doesn't match")
   470  	}
   471  	if fw.ClassId != filter.ClassId {
   472  		t.Fatal("ClassId doesn't match")
   473  	}
   474  	if fw.InDev != filter.InDev {
   475  		t.Fatal("InDev doesn't match")
   476  	}
   477  	if fw.Police.AvRate != filter.Police.AvRate {
   478  		t.Fatal("AvRate doesn't match")
   479  	}
   480  
   481  	if err := FilterDel(&filter); err != nil {
   482  		t.Fatal(err)
   483  	}
   484  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   485  	if err != nil {
   486  		t.Fatal(err)
   487  	}
   488  	if len(filters) != 0 {
   489  		t.Fatal("Failed to remove filter")
   490  	}
   491  	if err := ClassDel(class); err != nil {
   492  		t.Fatal(err)
   493  	}
   494  	classes, err = SafeClassList(link, MakeHandle(0xffff, 0))
   495  	if err != nil {
   496  		t.Fatal(err)
   497  	}
   498  	if len(classes) != 0 {
   499  		t.Fatal("Failed to remove class")
   500  	}
   501  
   502  	if err := QdiscDel(qdisc); err != nil {
   503  		t.Fatal(err)
   504  	}
   505  	qdiscs, err = SafeQdiscList(link)
   506  	if err != nil {
   507  		t.Fatal(err)
   508  	}
   509  	if len(qdiscs) != 0 {
   510  		t.Fatal("Failed to remove qdisc")
   511  	}
   512  }
   513  
   514  func TestFilterFwActAddDel(t *testing.T) {
   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  	classId := MakeHandle(1, 1)
   560  	filter := &FwFilter{
   561  		FilterAttrs: FilterAttrs{
   562  			LinkIndex: link.Attrs().Index,
   563  			Parent:    MakeHandle(0xffff, 0),
   564  			Priority:  1,
   565  			Protocol:  unix.ETH_P_ALL,
   566  			Handle:    MakeHandle(0, 0x6),
   567  		},
   568  		ClassId: classId,
   569  		Actions: []Action{
   570  			&MirredAction{
   571  				ActionAttrs: ActionAttrs{
   572  					Action: TC_ACT_STOLEN,
   573  				},
   574  				MirredAction: TCA_EGRESS_REDIR,
   575  				Ifindex:      redir.Attrs().Index,
   576  			},
   577  		},
   578  	}
   579  
   580  	if err := FilterAdd(filter); err != nil {
   581  		t.Fatal(err)
   582  	}
   583  
   584  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   585  	if err != nil {
   586  		t.Fatal(err)
   587  	}
   588  	if len(filters) != 1 {
   589  		t.Fatal("Failed to add filter")
   590  	}
   591  	fw, ok := filters[0].(*FwFilter)
   592  	if !ok {
   593  		t.Fatal("Filter is the wrong type")
   594  	}
   595  
   596  	if len(fw.Actions) != 1 {
   597  		t.Fatalf("Too few Actions in filter")
   598  	}
   599  	if fw.ClassId != classId {
   600  		t.Fatalf("ClassId of the filter is the wrong value")
   601  	}
   602  
   603  	mia, ok := fw.Actions[0].(*MirredAction)
   604  	if !ok {
   605  		t.Fatal("Unable to find mirred action")
   606  	}
   607  
   608  	if mia.Attrs().Action != TC_ACT_STOLEN {
   609  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
   610  	}
   611  
   612  	if mia.MirredAction != TCA_EGRESS_REDIR {
   613  		t.Fatal("MirredAction isn't TCA_EGRESS_REDIR")
   614  	}
   615  
   616  	if mia.Ifindex != redir.Attrs().Index {
   617  		t.Fatal("Unmatched redirect index")
   618  	}
   619  
   620  	if err := FilterDel(filter); err != nil {
   621  		t.Fatal(err)
   622  	}
   623  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   624  	if err != nil {
   625  		t.Fatal(err)
   626  	}
   627  	if len(filters) != 0 {
   628  		t.Fatal("Failed to remove filter")
   629  	}
   630  
   631  	if err := QdiscDel(qdisc); err != nil {
   632  		t.Fatal(err)
   633  	}
   634  	qdiscs, err = SafeQdiscList(link)
   635  	if err != nil {
   636  		t.Fatal(err)
   637  	}
   638  	if len(qdiscs) != 0 {
   639  		t.Fatal("Failed to remove qdisc")
   640  	}
   641  }
   642  
   643  func TestFilterU32BpfAddDel(t *testing.T) {
   644  	t.Skipf("Fd does not match in ci")
   645  	tearDown := setUpNetlinkTest(t)
   646  	defer tearDown()
   647  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   648  		t.Fatal(err)
   649  	}
   650  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   651  		t.Fatal(err)
   652  	}
   653  	link, err := LinkByName("foo")
   654  	if err != nil {
   655  		t.Fatal(err)
   656  	}
   657  	if err := LinkSetUp(link); err != nil {
   658  		t.Fatal(err)
   659  	}
   660  	redir, err := LinkByName("bar")
   661  	if err != nil {
   662  		t.Fatal(err)
   663  	}
   664  	if err := LinkSetUp(redir); err != nil {
   665  		t.Fatal(err)
   666  	}
   667  	qdisc := &Ingress{
   668  		QdiscAttrs: QdiscAttrs{
   669  			LinkIndex: link.Attrs().Index,
   670  			Handle:    MakeHandle(0xffff, 0),
   671  			Parent:    HANDLE_INGRESS,
   672  		},
   673  	}
   674  	if err := QdiscAdd(qdisc); err != nil {
   675  		t.Fatal(err)
   676  	}
   677  	qdiscs, err := SafeQdiscList(link)
   678  	if err != nil {
   679  		t.Fatal(err)
   680  	}
   681  	if len(qdiscs) != 1 {
   682  		t.Fatal("Failed to add qdisc")
   683  	}
   684  	_, ok := qdiscs[0].(*Ingress)
   685  	if !ok {
   686  		t.Fatal("Qdisc is the wrong type")
   687  	}
   688  
   689  	fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_ACT, 1)
   690  	if err != nil {
   691  		t.Skipf("Loading bpf program failed: %s", err)
   692  	}
   693  	classId := MakeHandle(1, 1)
   694  	filter := &U32{
   695  		FilterAttrs: FilterAttrs{
   696  			LinkIndex: link.Attrs().Index,
   697  			Parent:    MakeHandle(0xffff, 0),
   698  			Priority:  1,
   699  			Protocol:  unix.ETH_P_ALL,
   700  		},
   701  		ClassId: classId,
   702  		Actions: []Action{
   703  			&BpfAction{Fd: fd, Name: "simple"},
   704  			&MirredAction{
   705  				ActionAttrs: ActionAttrs{
   706  					Action: TC_ACT_STOLEN,
   707  				},
   708  				MirredAction: TCA_EGRESS_REDIR,
   709  				Ifindex:      redir.Attrs().Index,
   710  			},
   711  		},
   712  	}
   713  
   714  	if err := FilterAdd(filter); err != nil {
   715  		t.Fatal(err)
   716  	}
   717  
   718  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   719  	if err != nil {
   720  		t.Fatal(err)
   721  	}
   722  	if len(filters) != 1 {
   723  		t.Fatal("Failed to add filter")
   724  	}
   725  	u32, ok := filters[0].(*U32)
   726  	if !ok {
   727  		t.Fatal("Filter is the wrong type")
   728  	}
   729  
   730  	if len(u32.Actions) != 2 {
   731  		t.Fatalf("Too few Actions in filter")
   732  	}
   733  	if u32.ClassId != classId {
   734  		t.Fatalf("ClassId of the filter is the wrong value")
   735  	}
   736  
   737  	// actions can be returned in reverse order
   738  	bpfAction, ok := u32.Actions[0].(*BpfAction)
   739  	if !ok {
   740  		bpfAction, ok = u32.Actions[1].(*BpfAction)
   741  		if !ok {
   742  			t.Fatal("Action is the wrong type")
   743  		}
   744  	}
   745  	if bpfAction.Fd != fd {
   746  		t.Fatalf("Action Fd does not match %d != %d", bpfAction.Fd, fd)
   747  	}
   748  	if _, ok := u32.Actions[0].(*MirredAction); !ok {
   749  		if _, ok := u32.Actions[1].(*MirredAction); !ok {
   750  			t.Fatal("Action is the wrong type")
   751  		}
   752  	}
   753  
   754  	if err := FilterDel(filter); err != nil {
   755  		t.Fatal(err)
   756  	}
   757  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   758  	if err != nil {
   759  		t.Fatal(err)
   760  	}
   761  	if len(filters) != 0 {
   762  		t.Fatal("Failed to remove filter")
   763  	}
   764  
   765  	if err := QdiscDel(qdisc); err != nil {
   766  		t.Fatal(err)
   767  	}
   768  	qdiscs, err = SafeQdiscList(link)
   769  	if err != nil {
   770  		t.Fatal(err)
   771  	}
   772  	if len(qdiscs) != 0 {
   773  		t.Fatal("Failed to remove qdisc")
   774  	}
   775  }
   776  
   777  func TestFilterU32ConnmarkAddDel(t *testing.T) {
   778  	tearDown := setUpNetlinkTest(t)
   779  	defer tearDown()
   780  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   781  		t.Fatal(err)
   782  	}
   783  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
   784  		t.Fatal(err)
   785  	}
   786  	link, err := LinkByName("foo")
   787  	if err != nil {
   788  		t.Fatal(err)
   789  	}
   790  	if err := LinkSetUp(link); err != nil {
   791  		t.Fatal(err)
   792  	}
   793  	redir, err := LinkByName("bar")
   794  	if err != nil {
   795  		t.Fatal(err)
   796  	}
   797  	if err := LinkSetUp(redir); err != nil {
   798  		t.Fatal(err)
   799  	}
   800  	qdisc := &Ingress{
   801  		QdiscAttrs: QdiscAttrs{
   802  			LinkIndex: link.Attrs().Index,
   803  			Handle:    MakeHandle(0xffff, 0),
   804  			Parent:    HANDLE_INGRESS,
   805  		},
   806  	}
   807  	if err := QdiscAdd(qdisc); err != nil {
   808  		t.Fatal(err)
   809  	}
   810  	qdiscs, err := SafeQdiscList(link)
   811  	if err != nil {
   812  		t.Fatal(err)
   813  	}
   814  	if len(qdiscs) != 1 {
   815  		t.Fatal("Failed to add qdisc")
   816  	}
   817  	_, ok := qdiscs[0].(*Ingress)
   818  	if !ok {
   819  		t.Fatal("Qdisc is the wrong type")
   820  	}
   821  
   822  	classId := MakeHandle(1, 1)
   823  	filter := &U32{
   824  		FilterAttrs: FilterAttrs{
   825  			LinkIndex: link.Attrs().Index,
   826  			Parent:    MakeHandle(0xffff, 0),
   827  			Priority:  1,
   828  			Protocol:  unix.ETH_P_ALL,
   829  		},
   830  		ClassId: classId,
   831  		Actions: []Action{
   832  			&ConnmarkAction{
   833  				ActionAttrs: ActionAttrs{
   834  					Action: TC_ACT_PIPE,
   835  				},
   836  			},
   837  			&MirredAction{
   838  				ActionAttrs: ActionAttrs{
   839  					Action: TC_ACT_STOLEN,
   840  				},
   841  				MirredAction: TCA_EGRESS_REDIR,
   842  				Ifindex:      redir.Attrs().Index,
   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.Fatal(err)
   854  	}
   855  	if len(filters) != 1 {
   856  		t.Fatal("Failed to add filter")
   857  	}
   858  	u32, ok := filters[0].(*U32)
   859  	if !ok {
   860  		t.Fatal("Filter is the wrong type")
   861  	}
   862  
   863  	if len(u32.Actions) != 2 {
   864  		t.Fatalf("Too few Actions in filter")
   865  	}
   866  	if u32.ClassId != classId {
   867  		t.Fatalf("ClassId of the filter is the wrong value")
   868  	}
   869  
   870  	// actions can be returned in reverse order
   871  	cma, ok := u32.Actions[0].(*ConnmarkAction)
   872  	if !ok {
   873  		cma, ok = u32.Actions[1].(*ConnmarkAction)
   874  		if !ok {
   875  			t.Fatal("Unable to find connmark action")
   876  		}
   877  	}
   878  
   879  	if cma.Attrs().Action != TC_ACT_PIPE {
   880  		t.Fatal("Connmark action isn't TC_ACT_PIPE")
   881  	}
   882  
   883  	mia, ok := u32.Actions[0].(*MirredAction)
   884  	if !ok {
   885  		mia, ok = u32.Actions[1].(*MirredAction)
   886  		if !ok {
   887  			t.Fatal("Unable to find mirred action")
   888  		}
   889  	}
   890  
   891  	if mia.Attrs().Action != TC_ACT_STOLEN {
   892  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
   893  	}
   894  
   895  	if err := FilterDel(filter); err != nil {
   896  		t.Fatal(err)
   897  	}
   898  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
   899  	if err != nil {
   900  		t.Fatal(err)
   901  	}
   902  	if len(filters) != 0 {
   903  		t.Fatal("Failed to remove filter")
   904  	}
   905  
   906  	if err := QdiscDel(qdisc); err != nil {
   907  		t.Fatal(err)
   908  	}
   909  	qdiscs, err = SafeQdiscList(link)
   910  	if err != nil {
   911  		t.Fatal(err)
   912  	}
   913  	if len(qdiscs) != 0 {
   914  		t.Fatal("Failed to remove qdisc")
   915  	}
   916  }
   917  
   918  func TestFilterU32CsumAddDel(t *testing.T) {
   919  	tearDown := setUpNetlinkTest(t)
   920  	defer tearDown()
   921  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
   922  		t.Fatalf("add link foo error: %v", err)
   923  	}
   924  	link, err := LinkByName("foo")
   925  	if err != nil {
   926  		t.Fatalf("add link foo error: %v", err)
   927  	}
   928  	if err := LinkSetUp(link); err != nil {
   929  		t.Fatalf("set foo link up error: %v", err)
   930  	}
   931  
   932  	qdisc := &Ingress{
   933  		QdiscAttrs: QdiscAttrs{
   934  			LinkIndex: link.Attrs().Index,
   935  			Handle:    MakeHandle(0xffff, 0),
   936  			Parent:    HANDLE_INGRESS,
   937  		},
   938  	}
   939  	if err := QdiscAdd(qdisc); err != nil {
   940  		t.Fatal(err)
   941  	}
   942  	qdiscs, err := SafeQdiscList(link)
   943  	if err != nil {
   944  		t.Fatalf("get qdisc error: %v", err)
   945  	}
   946  
   947  	found := false
   948  	for _, v := range qdiscs {
   949  		if _, ok := v.(*Ingress); ok {
   950  			found = true
   951  			break
   952  		}
   953  	}
   954  	if !found {
   955  		t.Fatal("Qdisc is the wrong type")
   956  	}
   957  
   958  	classId := MakeHandle(1, 1)
   959  	filter := &U32{
   960  		FilterAttrs: FilterAttrs{
   961  			LinkIndex: link.Attrs().Index,
   962  			Parent:    MakeHandle(0xffff, 0),
   963  			Priority:  1,
   964  			Protocol:  unix.ETH_P_ALL,
   965  		},
   966  		ClassId: classId,
   967  		Actions: []Action{
   968  			&CsumAction{
   969  				ActionAttrs: ActionAttrs{
   970  					Action: TC_ACT_PIPE,
   971  				},
   972  				UpdateFlags: TCA_CSUM_UPDATE_FLAG_TCP,
   973  			},
   974  		},
   975  	}
   976  
   977  	if err := FilterAdd(filter); err != nil {
   978  		t.Fatal(err)
   979  	}
   980  
   981  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
   982  	if err != nil {
   983  		t.Fatalf("get filter error: %v", err)
   984  	}
   985  
   986  	if len(filters) != 1 {
   987  		t.Fatalf("the count filters error, expect: 1, acutal: %d", len(filters))
   988  	}
   989  
   990  	ft, ok := filters[0].(*U32)
   991  	if !ok {
   992  		t.Fatal("Filter is the wrong type")
   993  	}
   994  
   995  	if ft.LinkIndex != link.Attrs().Index {
   996  		t.Fatal("link index error")
   997  	}
   998  
   999  	if len(ft.Actions) != 1 {
  1000  		t.Fatalf("filter has wrong number of actions, expect: 1, acutal: %d", len(filters))
  1001  	}
  1002  
  1003  	csum, ok := ft.Actions[0].(*CsumAction)
  1004  	if !ok {
  1005  		t.Fatal("action is the wrong type")
  1006  	}
  1007  
  1008  	if csum.Attrs().Action != TC_ACT_PIPE {
  1009  		t.Fatal("Csum action isn't TC_ACT_PIPE")
  1010  	}
  1011  
  1012  	if csum.UpdateFlags != TCA_CSUM_UPDATE_FLAG_TCP {
  1013  		t.Fatalf("Csum action isn't TCA_CSUM_UPDATE_FLAG_TCP, got %d", csum.UpdateFlags)
  1014  	}
  1015  
  1016  	if err := FilterDel(ft); err != nil {
  1017  		t.Fatal(err)
  1018  	}
  1019  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1020  	if err != nil {
  1021  		t.Fatal(err)
  1022  	}
  1023  	if len(filters) != 0 {
  1024  		t.Fatal("Failed to remove filter")
  1025  	}
  1026  
  1027  	if err := QdiscDel(qdisc); err != nil {
  1028  		t.Fatal(err)
  1029  	}
  1030  	qdiscs, err = SafeQdiscList(link)
  1031  	if err != nil {
  1032  		t.Fatal(err)
  1033  	}
  1034  
  1035  	found = false
  1036  	for _, v := range qdiscs {
  1037  		if _, ok := v.(*Ingress); ok {
  1038  			found = true
  1039  			break
  1040  		}
  1041  	}
  1042  	if found {
  1043  		t.Fatal("Failed to remove qdisc")
  1044  	}
  1045  }
  1046  
  1047  func setupLinkForTestWithQdisc(t *testing.T, linkName string) (Qdisc, Link) {
  1048  	if err := LinkAdd(&Ifb{LinkAttrs{Name: linkName}}); err != nil {
  1049  		t.Fatal(err)
  1050  	}
  1051  	link, err := LinkByName(linkName)
  1052  	if err != nil {
  1053  		t.Fatal(err)
  1054  	}
  1055  	if err := LinkSetUp(link); err != nil {
  1056  		t.Fatal(err)
  1057  	}
  1058  	qdisc := &Clsact{
  1059  		QdiscAttrs: QdiscAttrs{
  1060  			LinkIndex: link.Attrs().Index,
  1061  			Handle:    MakeHandle(0xffff, 0),
  1062  			Parent:    HANDLE_CLSACT,
  1063  		},
  1064  	}
  1065  
  1066  	if err := QdiscAdd(qdisc); err != nil {
  1067  		t.Fatal(err)
  1068  	}
  1069  	qdiscs, err := SafeQdiscList(link)
  1070  	if err != nil {
  1071  		t.Fatal(err)
  1072  	}
  1073  	if len(qdiscs) != 1 {
  1074  		t.Fatal("Failed to add qdisc", len(qdiscs))
  1075  	}
  1076  	if q, ok := qdiscs[0].(*Clsact); !ok || q.Type() != "clsact" {
  1077  		t.Fatal("qdisc is the wrong type")
  1078  	}
  1079  	return qdiscs[0], link
  1080  }
  1081  
  1082  func TestFilterClsActBpfAddDel(t *testing.T) {
  1083  	t.Skipf("Fd does not match in ci")
  1084  	// This feature was added in kernel 4.5
  1085  	minKernelRequired(t, 4, 5)
  1086  
  1087  	tearDown := setUpNetlinkTest(t)
  1088  	defer tearDown()
  1089  
  1090  	qdisc, link := setupLinkForTestWithQdisc(t, "foo")
  1091  	filterattrs := FilterAttrs{
  1092  		LinkIndex: link.Attrs().Index,
  1093  		Parent:    HANDLE_MIN_EGRESS,
  1094  		Handle:    MakeHandle(0, 1),
  1095  		Protocol:  unix.ETH_P_ALL,
  1096  		Priority:  1,
  1097  	}
  1098  	fd, err := loadSimpleBpf(BPF_PROG_TYPE_SCHED_CLS, 1)
  1099  	if err != nil {
  1100  		t.Skipf("Loading bpf program failed: %s", err)
  1101  	}
  1102  	filter := &BpfFilter{
  1103  		FilterAttrs:  filterattrs,
  1104  		Fd:           fd,
  1105  		Name:         "simple",
  1106  		DirectAction: true,
  1107  	}
  1108  	if filter.Fd < 0 {
  1109  		t.Skipf("Failed to load bpf program")
  1110  	}
  1111  
  1112  	if err := FilterAdd(filter); err != nil {
  1113  		t.Fatal(err)
  1114  	}
  1115  
  1116  	filters, err := FilterList(link, HANDLE_MIN_EGRESS)
  1117  	if err != nil {
  1118  		t.Fatal(err)
  1119  	}
  1120  	if len(filters) != 1 {
  1121  		t.Fatal("Failed to add filter")
  1122  	}
  1123  	bpf, ok := filters[0].(*BpfFilter)
  1124  	if !ok {
  1125  		t.Fatal("Filter is the wrong type")
  1126  	}
  1127  
  1128  	if bpf.Fd != filter.Fd {
  1129  		t.Fatal("Filter Fd does not match")
  1130  	}
  1131  	if bpf.DirectAction != filter.DirectAction {
  1132  		t.Fatal("Filter DirectAction does not match")
  1133  	}
  1134  
  1135  	if err := FilterDel(filter); err != nil {
  1136  		t.Fatal(err)
  1137  	}
  1138  	filters, err = FilterList(link, HANDLE_MIN_EGRESS)
  1139  	if err != nil {
  1140  		t.Fatal(err)
  1141  	}
  1142  	if len(filters) != 0 {
  1143  		t.Fatal("Failed to remove filter")
  1144  	}
  1145  
  1146  	if err := QdiscDel(qdisc); err != nil {
  1147  		t.Fatal(err)
  1148  	}
  1149  	qdiscs, err := SafeQdiscList(link)
  1150  	if err != nil {
  1151  		t.Fatal(err)
  1152  	}
  1153  	if len(qdiscs) != 0 {
  1154  		t.Fatal("Failed to remove qdisc")
  1155  	}
  1156  }
  1157  
  1158  func TestFilterMatchAllAddDel(t *testing.T) {
  1159  	// This classifier was added in kernel 4.7
  1160  	minKernelRequired(t, 4, 7)
  1161  
  1162  	tearDown := setUpNetlinkTest(t)
  1163  	defer tearDown()
  1164  	_, link := setupLinkForTestWithQdisc(t, "foo")
  1165  	_, link2 := setupLinkForTestWithQdisc(t, "bar")
  1166  	filter := &MatchAll{
  1167  		FilterAttrs: FilterAttrs{
  1168  			LinkIndex: link.Attrs().Index,
  1169  			Parent:    HANDLE_MIN_EGRESS,
  1170  			Priority:  32000,
  1171  			Protocol:  unix.ETH_P_ALL,
  1172  		},
  1173  		Actions: []Action{
  1174  			&MirredAction{
  1175  				ActionAttrs: ActionAttrs{
  1176  					Action: TC_ACT_STOLEN,
  1177  				},
  1178  				MirredAction: TCA_EGRESS_REDIR,
  1179  				Ifindex:      link2.Attrs().Index,
  1180  			},
  1181  		},
  1182  	}
  1183  	if err := FilterAdd(filter); err != nil {
  1184  		t.Fatal(err)
  1185  	}
  1186  
  1187  	filters, err := FilterList(link, HANDLE_MIN_EGRESS)
  1188  	if err != nil {
  1189  		t.Fatal(err)
  1190  	}
  1191  	if len(filters) != 1 {
  1192  		t.Fatal("Failed to add filter")
  1193  	}
  1194  	matchall, ok := filters[0].(*MatchAll)
  1195  	if !ok {
  1196  		t.Fatal("Filter is the wrong type")
  1197  	}
  1198  
  1199  	if matchall.Priority != 32000 {
  1200  		t.Fatal("Filter priority does not match")
  1201  	}
  1202  
  1203  	if len(matchall.Actions) != 1 {
  1204  		t.Fatal("Filter has no actions")
  1205  	}
  1206  
  1207  	mirredAction, ok := matchall.Actions[0].(*MirredAction)
  1208  	if !ok {
  1209  		t.Fatal("Action does not match")
  1210  	}
  1211  
  1212  	if mirredAction.Ifindex != link2.Attrs().Index {
  1213  		t.Fatal("Action ifindex does not match")
  1214  	}
  1215  
  1216  	if err := FilterDel(filter); err != nil {
  1217  		t.Fatal(err)
  1218  	}
  1219  	filters, err = FilterList(link, HANDLE_MIN_EGRESS)
  1220  	if err != nil {
  1221  		t.Fatal(err)
  1222  	}
  1223  	if len(filters) != 0 {
  1224  		t.Fatal("Failed to remove filter")
  1225  	}
  1226  
  1227  }
  1228  
  1229  func TestFilterU32TunnelKeyAddDel(t *testing.T) {
  1230  	tearDown := setUpNetlinkTest(t)
  1231  	defer tearDown()
  1232  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1233  		t.Fatal(err)
  1234  	}
  1235  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1236  		t.Fatal(err)
  1237  	}
  1238  	link, err := LinkByName("foo")
  1239  	if err != nil {
  1240  		t.Fatal(err)
  1241  	}
  1242  	if err := LinkSetUp(link); err != nil {
  1243  		t.Fatal(err)
  1244  	}
  1245  	redir, err := LinkByName("bar")
  1246  	if err != nil {
  1247  		t.Fatal(err)
  1248  	}
  1249  	if err := LinkSetUp(redir); err != nil {
  1250  		t.Fatal(err)
  1251  	}
  1252  
  1253  	qdisc := &Ingress{
  1254  		QdiscAttrs: QdiscAttrs{
  1255  			LinkIndex: link.Attrs().Index,
  1256  			Handle:    MakeHandle(0xffff, 0),
  1257  			Parent:    HANDLE_INGRESS,
  1258  		},
  1259  	}
  1260  	if err := QdiscAdd(qdisc); err != nil {
  1261  		t.Fatal(err)
  1262  	}
  1263  	qdiscs, err := SafeQdiscList(link)
  1264  	if err != nil {
  1265  		t.Fatal(err)
  1266  	}
  1267  
  1268  	found := false
  1269  	for _, v := range qdiscs {
  1270  		if _, ok := v.(*Ingress); ok {
  1271  			found = true
  1272  			break
  1273  		}
  1274  	}
  1275  	if !found {
  1276  		t.Fatal("Qdisc is the wrong type")
  1277  	}
  1278  
  1279  	tunnelAct := NewTunnelKeyAction()
  1280  	tunnelAct.SrcAddr = net.IPv4(10, 10, 10, 1)
  1281  	tunnelAct.DstAddr = net.IPv4(10, 10, 10, 2)
  1282  	tunnelAct.KeyID = 0x01
  1283  	tunnelAct.Action = TCA_TUNNEL_KEY_SET
  1284  	tunnelAct.DestPort = 8472
  1285  
  1286  	classId := MakeHandle(1, 1)
  1287  	filter := &U32{
  1288  		FilterAttrs: FilterAttrs{
  1289  			LinkIndex: link.Attrs().Index,
  1290  			Parent:    MakeHandle(0xffff, 0),
  1291  			Priority:  1,
  1292  			Protocol:  unix.ETH_P_ALL,
  1293  		},
  1294  		ClassId: classId,
  1295  		Actions: []Action{
  1296  			tunnelAct,
  1297  			&MirredAction{
  1298  				ActionAttrs: ActionAttrs{
  1299  					Action: TC_ACT_STOLEN,
  1300  				},
  1301  				MirredAction: TCA_EGRESS_REDIR,
  1302  				Ifindex:      redir.Attrs().Index,
  1303  			},
  1304  		},
  1305  	}
  1306  
  1307  	if err := FilterAdd(filter); err != nil {
  1308  		t.Fatal(err)
  1309  	}
  1310  
  1311  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1312  	if err != nil {
  1313  		t.Fatal(err)
  1314  	}
  1315  	if len(filters) != 1 {
  1316  		t.Fatal("Failed to add filter")
  1317  	}
  1318  	u32, ok := filters[0].(*U32)
  1319  	if !ok {
  1320  		t.Fatal("Filter is the wrong type")
  1321  	}
  1322  
  1323  	if len(u32.Actions) != 2 {
  1324  		t.Fatalf("Too few Actions in filter")
  1325  	}
  1326  	if u32.ClassId != classId {
  1327  		t.Fatalf("ClassId of the filter is the wrong value")
  1328  	}
  1329  
  1330  	// actions can be returned in reverse order
  1331  	tun, ok := u32.Actions[0].(*TunnelKeyAction)
  1332  	if !ok {
  1333  		tun, ok = u32.Actions[1].(*TunnelKeyAction)
  1334  		if !ok {
  1335  			t.Fatal("Unable to find tunnel action")
  1336  		}
  1337  	}
  1338  
  1339  	if tun.Attrs().Action != TC_ACT_PIPE {
  1340  		t.Fatal("TunnelKey action isn't TC_ACT_PIPE")
  1341  	}
  1342  	if !tun.SrcAddr.Equal(tunnelAct.SrcAddr) {
  1343  		t.Fatal("Action SrcAddr doesn't match")
  1344  	}
  1345  	if !tun.DstAddr.Equal(tunnelAct.DstAddr) {
  1346  		t.Fatal("Action DstAddr doesn't match")
  1347  	}
  1348  	if tun.KeyID != tunnelAct.KeyID {
  1349  		t.Fatal("Action KeyID doesn't match")
  1350  	}
  1351  	if tun.DestPort != tunnelAct.DestPort {
  1352  		t.Fatal("Action DestPort doesn't match")
  1353  	}
  1354  	if tun.Action != tunnelAct.Action {
  1355  		t.Fatal("Action doesn't match")
  1356  	}
  1357  
  1358  	mia, ok := u32.Actions[0].(*MirredAction)
  1359  	if !ok {
  1360  		mia, ok = u32.Actions[1].(*MirredAction)
  1361  		if !ok {
  1362  			t.Fatal("Unable to find mirred action")
  1363  		}
  1364  	}
  1365  
  1366  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1367  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1368  	}
  1369  
  1370  	if err := FilterDel(filter); err != nil {
  1371  		t.Fatal(err)
  1372  	}
  1373  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1374  	if err != nil {
  1375  		t.Fatal(err)
  1376  	}
  1377  	if len(filters) != 0 {
  1378  		t.Fatal("Failed to remove filter")
  1379  	}
  1380  
  1381  	if err := QdiscDel(qdisc); err != nil {
  1382  		t.Fatal(err)
  1383  	}
  1384  	qdiscs, err = SafeQdiscList(link)
  1385  	if err != nil {
  1386  		t.Fatal(err)
  1387  	}
  1388  
  1389  	found = false
  1390  	for _, v := range qdiscs {
  1391  		if _, ok := v.(*Ingress); ok {
  1392  			found = true
  1393  			break
  1394  		}
  1395  	}
  1396  	if found {
  1397  		t.Fatal("Failed to remove qdisc")
  1398  	}
  1399  }
  1400  
  1401  func TestFilterU32SkbEditAddDel(t *testing.T) {
  1402  	tearDown := setUpNetlinkTest(t)
  1403  	defer tearDown()
  1404  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1405  		t.Fatal(err)
  1406  	}
  1407  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1408  		t.Fatal(err)
  1409  	}
  1410  	link, err := LinkByName("foo")
  1411  	if err != nil {
  1412  		t.Fatal(err)
  1413  	}
  1414  	if err := LinkSetUp(link); err != nil {
  1415  		t.Fatal(err)
  1416  	}
  1417  	redir, err := LinkByName("bar")
  1418  	if err != nil {
  1419  		t.Fatal(err)
  1420  	}
  1421  	if err := LinkSetUp(redir); err != nil {
  1422  		t.Fatal(err)
  1423  	}
  1424  
  1425  	qdisc := &Ingress{
  1426  		QdiscAttrs: QdiscAttrs{
  1427  			LinkIndex: link.Attrs().Index,
  1428  			Handle:    MakeHandle(0xffff, 0),
  1429  			Parent:    HANDLE_INGRESS,
  1430  		},
  1431  	}
  1432  	if err := QdiscAdd(qdisc); err != nil {
  1433  		t.Fatal(err)
  1434  	}
  1435  	qdiscs, err := SafeQdiscList(link)
  1436  	if err != nil {
  1437  		t.Fatal(err)
  1438  	}
  1439  
  1440  	found := false
  1441  	for _, v := range qdiscs {
  1442  		if _, ok := v.(*Ingress); ok {
  1443  			found = true
  1444  			break
  1445  		}
  1446  	}
  1447  	if !found {
  1448  		t.Fatal("Qdisc is the wrong type")
  1449  	}
  1450  
  1451  	skbedit := NewSkbEditAction()
  1452  	ptype := uint16(unix.PACKET_HOST)
  1453  	skbedit.PType = &ptype
  1454  	priority := uint32(0xff)
  1455  	skbedit.Priority = &priority
  1456  	mark := uint32(0xfe)
  1457  	skbedit.Mark = &mark
  1458  	mask := uint32(0xff)
  1459  	skbedit.Mask = &mask
  1460  	mapping := uint16(0xf)
  1461  	skbedit.QueueMapping = &mapping
  1462  
  1463  	classId := MakeHandle(1, 1)
  1464  	filter := &U32{
  1465  		FilterAttrs: FilterAttrs{
  1466  			LinkIndex: link.Attrs().Index,
  1467  			Parent:    MakeHandle(0xffff, 0),
  1468  			Priority:  1,
  1469  			Protocol:  unix.ETH_P_ALL,
  1470  		},
  1471  		ClassId: classId,
  1472  		Actions: []Action{
  1473  			skbedit,
  1474  			&MirredAction{
  1475  				ActionAttrs: ActionAttrs{
  1476  					Action: TC_ACT_STOLEN,
  1477  				},
  1478  				MirredAction: TCA_EGRESS_REDIR,
  1479  				Ifindex:      redir.Attrs().Index,
  1480  			},
  1481  		},
  1482  	}
  1483  
  1484  	if err := FilterAdd(filter); err != nil {
  1485  		t.Fatal(err)
  1486  	}
  1487  
  1488  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1489  	if err != nil {
  1490  		t.Fatal(err)
  1491  	}
  1492  	if len(filters) != 1 {
  1493  		t.Fatal("Failed to add filter")
  1494  	}
  1495  	u32, ok := filters[0].(*U32)
  1496  	if !ok {
  1497  		t.Fatal("Filter is the wrong type")
  1498  	}
  1499  
  1500  	if len(u32.Actions) != 2 {
  1501  		t.Fatalf("Too few Actions in filter")
  1502  	}
  1503  	if u32.ClassId != classId {
  1504  		t.Fatalf("ClassId of the filter is the wrong value")
  1505  	}
  1506  
  1507  	// actions can be returned in reverse order
  1508  	edit, ok := u32.Actions[0].(*SkbEditAction)
  1509  	if !ok {
  1510  		edit, ok = u32.Actions[1].(*SkbEditAction)
  1511  		if !ok {
  1512  			t.Fatal("Unable to find tunnel action")
  1513  		}
  1514  	}
  1515  
  1516  	if edit.Attrs().Action != TC_ACT_PIPE {
  1517  		t.Fatal("SkbEdit action isn't TC_ACT_PIPE")
  1518  	}
  1519  	if edit.PType == nil || *edit.PType != *skbedit.PType {
  1520  		t.Fatal("Action PType doesn't match")
  1521  	}
  1522  	if edit.QueueMapping == nil || *edit.QueueMapping != *skbedit.QueueMapping {
  1523  		t.Fatal("Action QueueMapping doesn't match")
  1524  	}
  1525  	if edit.Mark == nil || *edit.Mark != *skbedit.Mark {
  1526  		t.Fatal("Action Mark doesn't match")
  1527  	}
  1528  	if edit.Mask == nil || *edit.Mask != *skbedit.Mask {
  1529  		t.Fatal("Action Mask doesn't match")
  1530  	}
  1531  	if edit.Priority == nil || *edit.Priority != *skbedit.Priority {
  1532  		t.Fatal("Action Priority doesn't match")
  1533  	}
  1534  
  1535  	mia, ok := u32.Actions[0].(*MirredAction)
  1536  	if !ok {
  1537  		mia, ok = u32.Actions[1].(*MirredAction)
  1538  		if !ok {
  1539  			t.Fatal("Unable to find mirred action")
  1540  		}
  1541  	}
  1542  
  1543  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1544  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1545  	}
  1546  
  1547  	if err := FilterDel(filter); err != nil {
  1548  		t.Fatal(err)
  1549  	}
  1550  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1551  	if err != nil {
  1552  		t.Fatal(err)
  1553  	}
  1554  	if len(filters) != 0 {
  1555  		t.Fatal("Failed to remove filter")
  1556  	}
  1557  
  1558  	if err := QdiscDel(qdisc); err != nil {
  1559  		t.Fatal(err)
  1560  	}
  1561  	qdiscs, err = SafeQdiscList(link)
  1562  	if err != nil {
  1563  		t.Fatal(err)
  1564  	}
  1565  
  1566  	found = false
  1567  	for _, v := range qdiscs {
  1568  		if _, ok := v.(*Ingress); ok {
  1569  			found = true
  1570  			break
  1571  		}
  1572  	}
  1573  	if found {
  1574  		t.Fatal("Failed to remove qdisc")
  1575  	}
  1576  }
  1577  
  1578  func TestFilterU32LinkOption(t *testing.T) {
  1579  	tearDown := setUpNetlinkTest(t)
  1580  	defer tearDown()
  1581  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1582  		t.Fatalf("add link foo error: %v", err)
  1583  	}
  1584  	link, err := LinkByName("foo")
  1585  	if err != nil {
  1586  		t.Fatalf("add link foo error: %v", err)
  1587  	}
  1588  	if err := LinkSetUp(link); err != nil {
  1589  		t.Fatalf("set foo link up error: %v", err)
  1590  	}
  1591  
  1592  	qdisc := &Ingress{
  1593  		QdiscAttrs: QdiscAttrs{
  1594  			LinkIndex: link.Attrs().Index,
  1595  			Handle:    MakeHandle(0xffff, 0),
  1596  			Parent:    HANDLE_INGRESS,
  1597  		},
  1598  	}
  1599  	if err := QdiscAdd(qdisc); err != nil {
  1600  		t.Fatal(err)
  1601  	}
  1602  	qdiscs, err := SafeQdiscList(link)
  1603  	if err != nil {
  1604  		t.Fatalf("get qdisc error: %v", err)
  1605  	}
  1606  
  1607  	found := false
  1608  	for _, v := range qdiscs {
  1609  		if _, ok := v.(*Ingress); ok {
  1610  			found = true
  1611  			break
  1612  		}
  1613  	}
  1614  	if !found {
  1615  		t.Fatal("Qdisc is the wrong type")
  1616  	}
  1617  
  1618  	htid := uint32(10)
  1619  	size := uint32(8)
  1620  	priority := uint16(200)
  1621  	u32Table := &U32{
  1622  		FilterAttrs: FilterAttrs{
  1623  			LinkIndex: link.Attrs().Index,
  1624  			Handle:    htid << 20,
  1625  			Parent:    MakeHandle(0xffff, 0),
  1626  			Priority:  priority,
  1627  			Protocol:  unix.ETH_P_ALL,
  1628  		},
  1629  		Divisor: size,
  1630  	}
  1631  	if err := FilterAdd(u32Table); err != nil {
  1632  		t.Fatal(err)
  1633  	}
  1634  
  1635  	u32 := &U32{
  1636  		FilterAttrs: FilterAttrs{
  1637  			LinkIndex: link.Attrs().Index,
  1638  			Parent:    MakeHandle(0xffff, 0),
  1639  			Handle:    1,
  1640  			Priority:  priority,
  1641  			Protocol:  unix.ETH_P_ALL,
  1642  		},
  1643  		Link: uint32(htid << 20),
  1644  		Sel: &TcU32Sel{
  1645  			Nkeys:    1,
  1646  			Flags:    TC_U32_TERMINAL | TC_U32_VAROFFSET,
  1647  			Hmask:    0x0000ff00,
  1648  			Hoff:     0,
  1649  			Offshift: 8,
  1650  			Keys: []TcU32Key{
  1651  				{
  1652  					Mask: 0,
  1653  					Val:  0,
  1654  					Off:  0,
  1655  				},
  1656  			},
  1657  		},
  1658  	}
  1659  	if err := FilterAdd(u32); err != nil {
  1660  		t.Fatal(err)
  1661  	}
  1662  
  1663  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1664  	if err != nil {
  1665  		t.Fatalf("get filter error: %v", err)
  1666  	}
  1667  
  1668  	if len(filters) != 1 {
  1669  		t.Fatalf("the count filters error, expect: 1, acutal: %d", len(filters))
  1670  	}
  1671  
  1672  	ft, ok := filters[0].(*U32)
  1673  	if !ok {
  1674  		t.Fatal("Filter is the wrong type")
  1675  	}
  1676  
  1677  	if ft.LinkIndex != link.Attrs().Index {
  1678  		t.Fatal("link index error")
  1679  	}
  1680  
  1681  	if ft.Link != htid<<20 {
  1682  		t.Fatal("hash table id error")
  1683  	}
  1684  
  1685  	if ft.Priority != priority {
  1686  		t.Fatal("priority error")
  1687  	}
  1688  
  1689  	if err := FilterDel(ft); err != nil {
  1690  		t.Fatal(err)
  1691  	}
  1692  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1693  	if err != nil {
  1694  		t.Fatal(err)
  1695  	}
  1696  	if len(filters) != 0 {
  1697  		t.Fatal("Failed to remove filter")
  1698  	}
  1699  
  1700  	if err := QdiscDel(qdisc); err != nil {
  1701  		t.Fatal(err)
  1702  	}
  1703  	qdiscs, err = SafeQdiscList(link)
  1704  	if err != nil {
  1705  		t.Fatal(err)
  1706  	}
  1707  
  1708  	found = false
  1709  	for _, v := range qdiscs {
  1710  		if _, ok := v.(*Ingress); ok {
  1711  			found = true
  1712  			break
  1713  		}
  1714  	}
  1715  	if found {
  1716  		t.Fatal("Failed to remove qdisc")
  1717  	}
  1718  }
  1719  
  1720  func TestFilterFlowerAddDel(t *testing.T) {
  1721  	tearDown := setUpNetlinkTest(t)
  1722  	defer tearDown()
  1723  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  1724  		t.Fatal(err)
  1725  	}
  1726  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  1727  		t.Fatal(err)
  1728  	}
  1729  	link, err := LinkByName("foo")
  1730  	if err != nil {
  1731  		t.Fatal(err)
  1732  	}
  1733  	if err := LinkSetUp(link); err != nil {
  1734  		t.Fatal(err)
  1735  	}
  1736  	redir, err := LinkByName("bar")
  1737  	if err != nil {
  1738  		t.Fatal(err)
  1739  	}
  1740  	if err := LinkSetUp(redir); err != nil {
  1741  		t.Fatal(err)
  1742  	}
  1743  
  1744  	qdisc := &Ingress{
  1745  		QdiscAttrs: QdiscAttrs{
  1746  			LinkIndex: link.Attrs().Index,
  1747  			Handle:    MakeHandle(0xffff, 0),
  1748  			Parent:    HANDLE_INGRESS,
  1749  		},
  1750  	}
  1751  	if err := QdiscAdd(qdisc); err != nil {
  1752  		t.Fatal(err)
  1753  	}
  1754  	qdiscs, err := SafeQdiscList(link)
  1755  	if err != nil {
  1756  		t.Fatal(err)
  1757  	}
  1758  
  1759  	found := false
  1760  	for _, v := range qdiscs {
  1761  		if _, ok := v.(*Ingress); ok {
  1762  			found = true
  1763  			break
  1764  		}
  1765  	}
  1766  	if !found {
  1767  		t.Fatal("Qdisc is the wrong type")
  1768  	}
  1769  
  1770  	testMask := net.CIDRMask(24, 32)
  1771  	srcMac, err := net.ParseMAC("2C:54:91:88:C9:E3")
  1772  	if err != nil {
  1773  		t.Fatal(err)
  1774  	}
  1775  	destMac, err := net.ParseMAC("2C:54:91:88:C9:E5")
  1776  	if err != nil {
  1777  		t.Fatal(err)
  1778  	}
  1779  
  1780  	ipproto := new(nl.IPProto)
  1781  	*ipproto = nl.IPPROTO_TCP
  1782  
  1783  	filter := &Flower{
  1784  		FilterAttrs: FilterAttrs{
  1785  			LinkIndex: link.Attrs().Index,
  1786  			Parent:    MakeHandle(0xffff, 0),
  1787  			Priority:  1,
  1788  			Protocol:  unix.ETH_P_ALL,
  1789  		},
  1790  		DestIP:        net.ParseIP("1.0.0.1"),
  1791  		DestIPMask:    testMask,
  1792  		SrcIP:         net.ParseIP("2.0.0.1"),
  1793  		SrcIPMask:     testMask,
  1794  		EthType:       unix.ETH_P_IP,
  1795  		EncDestIP:     net.ParseIP("3.0.0.1"),
  1796  		EncDestIPMask: testMask,
  1797  		EncSrcIP:      net.ParseIP("4.0.0.1"),
  1798  		EncSrcIPMask:  testMask,
  1799  		EncDestPort:   8472,
  1800  		EncKeyId:      1234,
  1801  		SrcMac:        srcMac,
  1802  		DestMac:       destMac,
  1803  		IPProto:       ipproto,
  1804  		DestPort:      1111,
  1805  		SrcPort:       1111,
  1806  		Actions: []Action{
  1807  			&VlanAction{
  1808  				ActionAttrs: ActionAttrs{
  1809  					Action: TC_ACT_PIPE,
  1810  				},
  1811  				Action: TCA_VLAN_ACT_PUSH,
  1812  				VlanID: 1234,
  1813  			},
  1814  			&MirredAction{
  1815  				ActionAttrs: ActionAttrs{
  1816  					Action: TC_ACT_STOLEN,
  1817  				},
  1818  				MirredAction: TCA_EGRESS_REDIR,
  1819  				Ifindex:      redir.Attrs().Index,
  1820  			},
  1821  			&GenericAction{
  1822  				ActionAttrs: ActionAttrs{
  1823  					Action: getTcActGotoChain(),
  1824  				},
  1825  				Chain: 20,
  1826  			},
  1827  		},
  1828  	}
  1829  
  1830  	if err := FilterAdd(filter); err != nil {
  1831  		t.Fatal(err)
  1832  	}
  1833  
  1834  	time.Sleep(time.Second)
  1835  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  1836  	if err != nil {
  1837  		t.Fatal(err)
  1838  	}
  1839  	if len(filters) != 1 {
  1840  		t.Fatal("Failed to add filter")
  1841  	}
  1842  	flower, ok := filters[0].(*Flower)
  1843  	if !ok {
  1844  		t.Fatal("Filter is the wrong type")
  1845  	}
  1846  
  1847  	if filter.EthType != flower.EthType {
  1848  		t.Fatalf("Flower EthType doesn't match")
  1849  	}
  1850  	if !filter.DestIP.Equal(flower.DestIP) {
  1851  		t.Fatalf("Flower DestIP doesn't match")
  1852  	}
  1853  	if !filter.SrcIP.Equal(flower.SrcIP) {
  1854  		t.Fatalf("Flower SrcIP doesn't match")
  1855  	}
  1856  
  1857  	if !reflect.DeepEqual(filter.DestIPMask, testMask) {
  1858  		t.Fatalf("Flower DestIPMask doesn't match")
  1859  	}
  1860  	if !reflect.DeepEqual(filter.SrcIPMask, testMask) {
  1861  		t.Fatalf("Flower SrcIPMask doesn't match")
  1862  	}
  1863  
  1864  	if !filter.EncDestIP.Equal(flower.EncDestIP) {
  1865  		t.Fatalf("Flower EncDestIP doesn't match")
  1866  	}
  1867  	if !filter.EncSrcIP.Equal(flower.EncSrcIP) {
  1868  		t.Fatalf("Flower EncSrcIP doesn't match")
  1869  	}
  1870  	if !reflect.DeepEqual(filter.EncDestIPMask, testMask) {
  1871  		t.Fatalf("Flower EncDestIPMask doesn't match")
  1872  	}
  1873  	if !reflect.DeepEqual(filter.EncSrcIPMask, testMask) {
  1874  		t.Fatalf("Flower EncSrcIPMask doesn't match")
  1875  	}
  1876  	if filter.EncKeyId != flower.EncKeyId {
  1877  		t.Fatalf("Flower EncKeyId doesn't match")
  1878  	}
  1879  	if filter.EncDestPort != flower.EncDestPort {
  1880  		t.Fatalf("Flower EncDestPort doesn't match")
  1881  	}
  1882  	if flower.IPProto == nil || *filter.IPProto != *flower.IPProto {
  1883  		t.Fatalf("Flower IPProto doesn't match")
  1884  	}
  1885  	if filter.DestPort != flower.DestPort {
  1886  		t.Fatalf("Flower DestPort doesn't match")
  1887  	}
  1888  	if filter.SrcPort != flower.SrcPort {
  1889  		t.Fatalf("Flower SrcPort doesn't match")
  1890  	}
  1891  	if !(filter.SrcMac.String() == flower.SrcMac.String()) {
  1892  		t.Fatalf("Flower SrcMac doesn't match")
  1893  	}
  1894  	if !(filter.DestMac.String() == flower.DestMac.String()) {
  1895  		t.Fatalf("Flower DestMac doesn't match")
  1896  	}
  1897  
  1898  	vla, ok := flower.Actions[0].(*VlanAction)
  1899  	if !ok {
  1900  		t.Fatal("Unable to find vlan action")
  1901  	}
  1902  
  1903  	if vla.Attrs().Action != TC_ACT_PIPE {
  1904  		t.Fatal("Vlan action isn't TC_ACT_PIPE")
  1905  	}
  1906  
  1907  	if vla.Action != TCA_VLAN_ACT_PUSH {
  1908  		t.Fatal("Second Vlan action isn't push")
  1909  	}
  1910  
  1911  	if vla.VlanID != 1234 {
  1912  		t.Fatal("Second Vlan action vlanId isn't correct")
  1913  	}
  1914  
  1915  	mia, ok := flower.Actions[1].(*MirredAction)
  1916  	if !ok {
  1917  		t.Fatal("Unable to find mirred action")
  1918  	}
  1919  
  1920  	if mia.Attrs().Action != TC_ACT_STOLEN {
  1921  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  1922  	}
  1923  
  1924  	if mia.Timestamp == nil || mia.Timestamp.Installed == 0 {
  1925  		t.Fatal("Incorrect mirred action timestamp")
  1926  	}
  1927  
  1928  	if mia.Statistics == nil {
  1929  		t.Fatal("Incorrect mirred action stats")
  1930  	}
  1931  
  1932  	ga, ok := flower.Actions[2].(*GenericAction)
  1933  	if !ok {
  1934  		t.Fatal("Unable to find generic action")
  1935  	}
  1936  
  1937  	if ga.Attrs().Action != getTcActGotoChain() {
  1938  		t.Fatal("Generic action isn't TC_ACT_GOTO_CHAIN")
  1939  	}
  1940  
  1941  	if ga.Timestamp == nil || ga.Timestamp.Installed == 0 {
  1942  		t.Fatal("Incorrect generic action timestamp")
  1943  	}
  1944  
  1945  	if ga.Statistics == nil {
  1946  		t.Fatal("Incorrect generic action stats")
  1947  	}
  1948  
  1949  	if err := FilterDel(filter); err != nil {
  1950  		t.Fatal(err)
  1951  	}
  1952  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1953  	if err != nil {
  1954  		t.Fatal(err)
  1955  	}
  1956  	if len(filters) != 0 {
  1957  		t.Fatal("Failed to remove filter")
  1958  	}
  1959  
  1960  	filter = &Flower{
  1961  		FilterAttrs: FilterAttrs{
  1962  			LinkIndex: link.Attrs().Index,
  1963  			Parent:    MakeHandle(0xffff, 0),
  1964  			Priority:  1,
  1965  			Protocol:  unix.ETH_P_8021Q,
  1966  		},
  1967  		EthType: unix.ETH_P_8021Q,
  1968  		VlanId:  2046,
  1969  		Actions: []Action{
  1970  			&VlanAction{
  1971  				ActionAttrs: ActionAttrs{
  1972  					Action: TC_ACT_PIPE,
  1973  				},
  1974  				Action: TCA_VLAN_ACT_POP,
  1975  			},
  1976  			&MirredAction{
  1977  				ActionAttrs: ActionAttrs{
  1978  					Action: TC_ACT_STOLEN,
  1979  				},
  1980  				MirredAction: TCA_EGRESS_REDIR,
  1981  				Ifindex:      redir.Attrs().Index,
  1982  			},
  1983  		},
  1984  	}
  1985  
  1986  	if err := FilterAdd(filter); err != nil {
  1987  		t.Fatal(err)
  1988  	}
  1989  
  1990  	time.Sleep(time.Second)
  1991  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  1992  	if err != nil {
  1993  		t.Fatal(err)
  1994  	}
  1995  	if len(filters) != 1 {
  1996  		t.Fatal("Failed to add filter")
  1997  	}
  1998  	flower, ok = filters[0].(*Flower)
  1999  	if !ok {
  2000  		t.Fatal("Filter is the wrong type")
  2001  	}
  2002  
  2003  	if filter.VlanId != flower.VlanId {
  2004  		t.Fatalf("Flower VlanId doesn't match")
  2005  	}
  2006  
  2007  	vla, ok = flower.Actions[0].(*VlanAction)
  2008  	if !ok {
  2009  		t.Fatal("Unable to find vlan action")
  2010  	}
  2011  
  2012  	if vla.Attrs().Action != TC_ACT_PIPE {
  2013  		t.Fatal("Vlan action isn't TC_ACT_PIPE")
  2014  	}
  2015  
  2016  	if vla.Action != TCA_VLAN_ACT_POP {
  2017  		t.Fatal("First Vlan action isn't pop")
  2018  	}
  2019  
  2020  	mia, ok = flower.Actions[1].(*MirredAction)
  2021  	if !ok {
  2022  		t.Fatal("Unable to find mirred action")
  2023  	}
  2024  
  2025  	if mia.Attrs().Action != TC_ACT_STOLEN {
  2026  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  2027  	}
  2028  
  2029  	if mia.Timestamp == nil || mia.Timestamp.Installed == 0 {
  2030  		t.Fatal("Incorrect mirred action timestamp")
  2031  	}
  2032  
  2033  	if mia.Statistics == nil {
  2034  		t.Fatal("Incorrect mirred action stats")
  2035  	}
  2036  
  2037  	if err := FilterDel(filter); err != nil {
  2038  		t.Fatal(err)
  2039  	}
  2040  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2041  	if err != nil {
  2042  		t.Fatal(err)
  2043  	}
  2044  	if len(filters) != 0 {
  2045  		t.Fatal("Failed to remove filter")
  2046  	}
  2047  
  2048  	classId := MakeHandle(1, 101)
  2049  
  2050  	filter = &Flower{
  2051  		FilterAttrs: FilterAttrs{
  2052  			LinkIndex: link.Attrs().Index,
  2053  			Parent:    MakeHandle(0xffff, 0),
  2054  			Priority:  1,
  2055  			Protocol:  unix.ETH_P_ALL,
  2056  		},
  2057  
  2058  		EthType:         unix.ETH_P_IP,
  2059  		IPProto:         ipproto,
  2060  		ClassId:         classId,
  2061  		SrcPortRangeMin: 1000,
  2062  		SrcPortRangeMax: 2000,
  2063  	}
  2064  	if err := FilterAdd(filter); err != nil {
  2065  		t.Fatal(err)
  2066  	}
  2067  
  2068  	time.Sleep(time.Second)
  2069  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2070  	if err != nil {
  2071  		t.Fatal(err)
  2072  	}
  2073  	if len(filters) != 1 {
  2074  		t.Fatal("Failed to add filter")
  2075  	}
  2076  	flower, ok = filters[0].(*Flower)
  2077  	if !ok {
  2078  		t.Fatal("Filter is the wrong type")
  2079  	}
  2080  	if filter.ClassId != flower.ClassId {
  2081  		t.Fatalf("Flower ClassId doesn't match")
  2082  	}
  2083  	if filter.SrcPortRangeMin != flower.SrcPortRangeMin {
  2084  		t.Fatalf("Flower SrcPortRangeMin doesn't match")
  2085  	}
  2086  	if filter.SrcPortRangeMax != flower.SrcPortRangeMax {
  2087  		t.Fatalf("Flower SrcPortRangeMax doesn't match")
  2088  	}
  2089  	if err := FilterDel(filter); err != nil {
  2090  		t.Fatal(err)
  2091  	}
  2092  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2093  	if err != nil {
  2094  		t.Fatal(err)
  2095  	}
  2096  	if len(filters) != 0 {
  2097  		t.Fatal("Failed to remove filter")
  2098  	}
  2099  
  2100  	if err := QdiscDel(qdisc); err != nil {
  2101  		t.Fatal(err)
  2102  	}
  2103  	qdiscs, err = SafeQdiscList(link)
  2104  	if err != nil {
  2105  		t.Fatal(err)
  2106  	}
  2107  
  2108  	found = false
  2109  	for _, v := range qdiscs {
  2110  		if _, ok := v.(*Ingress); ok {
  2111  			found = true
  2112  			break
  2113  		}
  2114  	}
  2115  	if found {
  2116  		t.Fatal("Failed to remove qdisc")
  2117  	}
  2118  }
  2119  
  2120  func TestFilterIPv6FlowerPedit(t *testing.T) {
  2121  	tearDown := setUpNetlinkTest(t)
  2122  	defer tearDown()
  2123  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  2124  		t.Fatal(err)
  2125  	}
  2126  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  2127  		t.Fatal(err)
  2128  	}
  2129  	link, err := LinkByName("foo")
  2130  	if err != nil {
  2131  		t.Fatal(err)
  2132  	}
  2133  	if err := LinkSetUp(link); err != nil {
  2134  		t.Fatal(err)
  2135  	}
  2136  	redir, err := LinkByName("bar")
  2137  	if err != nil {
  2138  		t.Fatal(err)
  2139  	}
  2140  	if err := LinkSetUp(redir); err != nil {
  2141  		t.Fatal(err)
  2142  	}
  2143  
  2144  	qdisc := &Ingress{
  2145  		QdiscAttrs: QdiscAttrs{
  2146  			LinkIndex: link.Attrs().Index,
  2147  			Handle:    MakeHandle(0xffff, 0),
  2148  			Parent:    HANDLE_INGRESS,
  2149  		},
  2150  	}
  2151  	if err := QdiscAdd(qdisc); err != nil {
  2152  		t.Fatal(err)
  2153  	}
  2154  	qdiscs, err := SafeQdiscList(link)
  2155  	if err != nil {
  2156  		t.Fatal(err)
  2157  	}
  2158  
  2159  	found := false
  2160  	for _, v := range qdiscs {
  2161  		if _, ok := v.(*Ingress); ok {
  2162  			found = true
  2163  			break
  2164  		}
  2165  	}
  2166  	if !found {
  2167  		t.Fatal("Qdisc is the wrong type")
  2168  	}
  2169  
  2170  	testMask := net.CIDRMask(64, 128)
  2171  
  2172  	ipproto := new(nl.IPProto)
  2173  	*ipproto = nl.IPPROTO_TCP
  2174  
  2175  	filter := &Flower{
  2176  		FilterAttrs: FilterAttrs{
  2177  			LinkIndex: link.Attrs().Index,
  2178  			Parent:    MakeHandle(0xffff, 0),
  2179  			Priority:  1,
  2180  			Protocol:  unix.ETH_P_ALL,
  2181  		},
  2182  		DestIP:     net.ParseIP("ffff::fff1"),
  2183  		DestIPMask: testMask,
  2184  		EthType:    unix.ETH_P_IPV6,
  2185  		IPProto:    ipproto,
  2186  		DestPort:   6666,
  2187  		Actions:    []Action{},
  2188  	}
  2189  
  2190  	peditAction := NewPeditAction()
  2191  	peditAction.Proto = uint8(nl.IPPROTO_TCP)
  2192  	peditAction.SrcPort = 7777
  2193  	peditAction.SrcIP = net.ParseIP("ffff::fff2")
  2194  	filter.Actions = append(filter.Actions, peditAction)
  2195  
  2196  	miaAction := &MirredAction{
  2197  		ActionAttrs: ActionAttrs{
  2198  			Action: TC_ACT_REDIRECT,
  2199  		},
  2200  		MirredAction: TCA_EGRESS_REDIR,
  2201  		Ifindex:      redir.Attrs().Index,
  2202  	}
  2203  	filter.Actions = append(filter.Actions, miaAction)
  2204  
  2205  	if err := FilterAdd(filter); err != nil {
  2206  		t.Fatal(err)
  2207  	}
  2208  
  2209  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  2210  	if err != nil {
  2211  		t.Fatal(err)
  2212  	}
  2213  	if len(filters) != 1 {
  2214  		t.Fatal("Failed to add filter")
  2215  	}
  2216  	flower, ok := filters[0].(*Flower)
  2217  	if !ok {
  2218  		t.Fatal("Filter is the wrong type")
  2219  	}
  2220  
  2221  	if filter.EthType != flower.EthType {
  2222  		t.Fatalf("Flower EthType doesn't match")
  2223  	}
  2224  	if !filter.DestIP.Equal(flower.DestIP) {
  2225  		t.Fatalf("Flower DestIP doesn't match")
  2226  	}
  2227  
  2228  	if !reflect.DeepEqual(filter.DestIPMask, testMask) {
  2229  		t.Fatalf("Flower DestIPMask doesn't match")
  2230  	}
  2231  
  2232  	if flower.IPProto == nil || *filter.IPProto != *flower.IPProto {
  2233  		t.Fatalf("Flower IPProto doesn't match")
  2234  	}
  2235  	if filter.DestPort != flower.DestPort {
  2236  		t.Fatalf("Flower DestPort doesn't match")
  2237  	}
  2238  
  2239  	_, ok = flower.Actions[0].(*PeditAction)
  2240  	if !ok {
  2241  		t.Fatal("Unable to find pedit action")
  2242  	}
  2243  
  2244  	_, ok = flower.Actions[1].(*MirredAction)
  2245  	if !ok {
  2246  		t.Fatal("Unable to find mirred action")
  2247  	}
  2248  
  2249  	if err := FilterDel(filter); err != nil {
  2250  		t.Fatal(err)
  2251  	}
  2252  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2253  	if err != nil {
  2254  		t.Fatal(err)
  2255  	}
  2256  	if len(filters) != 0 {
  2257  		t.Fatal("Failed to remove filter")
  2258  	}
  2259  
  2260  	if err := QdiscDel(qdisc); err != nil {
  2261  		t.Fatal(err)
  2262  	}
  2263  	qdiscs, err = SafeQdiscList(link)
  2264  	if err != nil {
  2265  		t.Fatal(err)
  2266  	}
  2267  
  2268  	found = false
  2269  	for _, v := range qdiscs {
  2270  		if _, ok := v.(*Ingress); ok {
  2271  			found = true
  2272  			break
  2273  		}
  2274  	}
  2275  	if found {
  2276  		t.Fatal("Failed to remove qdisc")
  2277  	}
  2278  }
  2279  
  2280  func TestFilterU32PoliceAddDel(t *testing.T) {
  2281  	tearDown := setUpNetlinkTest(t)
  2282  	defer tearDown()
  2283  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  2284  		t.Fatal(err)
  2285  	}
  2286  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  2287  		t.Fatal(err)
  2288  	}
  2289  	link, err := LinkByName("foo")
  2290  	if err != nil {
  2291  		t.Fatal(err)
  2292  	}
  2293  	if err := LinkSetUp(link); err != nil {
  2294  		t.Fatal(err)
  2295  	}
  2296  	redir, err := LinkByName("bar")
  2297  	if err != nil {
  2298  		t.Fatal(err)
  2299  	}
  2300  	if err := LinkSetUp(redir); err != nil {
  2301  		t.Fatal(err)
  2302  	}
  2303  
  2304  	qdisc := &Ingress{
  2305  		QdiscAttrs: QdiscAttrs{
  2306  			LinkIndex: link.Attrs().Index,
  2307  			Handle:    MakeHandle(0xffff, 0),
  2308  			Parent:    HANDLE_INGRESS,
  2309  		},
  2310  	}
  2311  	if err := QdiscAdd(qdisc); err != nil {
  2312  		t.Fatal(err)
  2313  	}
  2314  	qdiscs, err := SafeQdiscList(link)
  2315  	if err != nil {
  2316  		t.Fatal(err)
  2317  	}
  2318  
  2319  	found := false
  2320  	for _, v := range qdiscs {
  2321  		if _, ok := v.(*Ingress); ok {
  2322  			found = true
  2323  			break
  2324  		}
  2325  	}
  2326  	if !found {
  2327  		t.Fatal("Qdisc is the wrong type")
  2328  	}
  2329  
  2330  	const (
  2331  		policeRate     = 0x40000000 // 1 Gbps
  2332  		policeBurst    = 0x19000    // 100 KB
  2333  		policePeakRate = 0x4000     // 16 Kbps
  2334  	)
  2335  
  2336  	police := NewPoliceAction()
  2337  	police.Rate = policeRate
  2338  	police.PeakRate = policePeakRate
  2339  	police.Burst = policeBurst
  2340  	police.ExceedAction = TC_POLICE_SHOT
  2341  	police.NotExceedAction = TC_POLICE_UNSPEC
  2342  
  2343  	classId := MakeHandle(1, 1)
  2344  	filter := &U32{
  2345  		FilterAttrs: FilterAttrs{
  2346  			LinkIndex: link.Attrs().Index,
  2347  			Parent:    MakeHandle(0xffff, 0),
  2348  			Priority:  1,
  2349  			Protocol:  unix.ETH_P_ALL,
  2350  		},
  2351  		ClassId: classId,
  2352  		Actions: []Action{
  2353  			police,
  2354  			&MirredAction{
  2355  				ActionAttrs: ActionAttrs{
  2356  					Action: TC_ACT_STOLEN,
  2357  				},
  2358  				MirredAction: TCA_EGRESS_REDIR,
  2359  				Ifindex:      redir.Attrs().Index,
  2360  			},
  2361  		},
  2362  	}
  2363  
  2364  	if err := FilterAdd(filter); err != nil {
  2365  		t.Fatal(err)
  2366  	}
  2367  
  2368  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  2369  	if err != nil {
  2370  		t.Fatal(err)
  2371  	}
  2372  	if len(filters) != 1 {
  2373  		t.Fatal("Failed to add filter")
  2374  	}
  2375  	u32, ok := filters[0].(*U32)
  2376  	if !ok {
  2377  		t.Fatal("Filter is the wrong type")
  2378  	}
  2379  
  2380  	if len(u32.Actions) != 2 {
  2381  		t.Fatalf("Too few Actions in filter")
  2382  	}
  2383  	if u32.ClassId != classId {
  2384  		t.Fatalf("ClassId of the filter is the wrong value")
  2385  	}
  2386  
  2387  	// actions can be returned in reverse order
  2388  	p, ok := u32.Actions[0].(*PoliceAction)
  2389  	if !ok {
  2390  		p, ok = u32.Actions[1].(*PoliceAction)
  2391  		if !ok {
  2392  			t.Fatal("Unable to find police action")
  2393  		}
  2394  	}
  2395  
  2396  	if p.ExceedAction != TC_POLICE_SHOT {
  2397  		t.Fatal("Police ExceedAction isn't TC_POLICE_SHOT")
  2398  	}
  2399  
  2400  	if p.NotExceedAction != TC_POLICE_UNSPEC {
  2401  		t.Fatal("Police NotExceedAction isn't TC_POLICE_UNSPEC")
  2402  	}
  2403  
  2404  	if p.Rate != policeRate {
  2405  		t.Fatal("Action Rate doesn't match")
  2406  	}
  2407  
  2408  	if p.PeakRate != policePeakRate {
  2409  		t.Fatal("Action PeakRate doesn't match")
  2410  	}
  2411  
  2412  	if p.LinkLayer != nl.LINKLAYER_ETHERNET {
  2413  		t.Fatal("Action LinkLayer doesn't match")
  2414  	}
  2415  
  2416  	mia, ok := u32.Actions[0].(*MirredAction)
  2417  	if !ok {
  2418  		mia, ok = u32.Actions[1].(*MirredAction)
  2419  		if !ok {
  2420  			t.Fatal("Unable to find mirred action")
  2421  		}
  2422  	}
  2423  
  2424  	if mia.Attrs().Action != TC_ACT_STOLEN {
  2425  		t.Fatal("Mirred action isn't TC_ACT_STOLEN")
  2426  	}
  2427  
  2428  	if err := FilterDel(filter); err != nil {
  2429  		t.Fatal(err)
  2430  	}
  2431  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2432  	if err != nil {
  2433  		t.Fatal(err)
  2434  	}
  2435  	if len(filters) != 0 {
  2436  		t.Fatal("Failed to remove filter")
  2437  	}
  2438  
  2439  	if err := QdiscDel(qdisc); err != nil {
  2440  		t.Fatal(err)
  2441  	}
  2442  	qdiscs, err = SafeQdiscList(link)
  2443  	if err != nil {
  2444  		t.Fatal(err)
  2445  	}
  2446  
  2447  	found = false
  2448  	for _, v := range qdiscs {
  2449  		if _, ok := v.(*Ingress); ok {
  2450  			found = true
  2451  			break
  2452  		}
  2453  	}
  2454  	if found {
  2455  		t.Fatal("Failed to remove qdisc")
  2456  	}
  2457  }
  2458  
  2459  func TestFilterU32DirectPoliceAddDel(t *testing.T) {
  2460  	tearDown := setUpNetlinkTest(t)
  2461  	defer tearDown()
  2462  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  2463  		t.Fatal(err)
  2464  	}
  2465  	link, err := LinkByName("foo")
  2466  	if err != nil {
  2467  		t.Fatal(err)
  2468  	}
  2469  	if err := LinkSetUp(link); err != nil {
  2470  		t.Fatal(err)
  2471  	}
  2472  
  2473  	qdisc := &Ingress{
  2474  		QdiscAttrs: QdiscAttrs{
  2475  			LinkIndex: link.Attrs().Index,
  2476  			Handle:    MakeHandle(0xffff, 0),
  2477  			Parent:    HANDLE_INGRESS,
  2478  		},
  2479  	}
  2480  	if err := QdiscAdd(qdisc); err != nil {
  2481  		t.Fatal(err)
  2482  	}
  2483  
  2484  	const (
  2485  		policeRate     = 0x40000000 // 1 Gbps
  2486  		policeBurst    = 0x19000    // 100 KB
  2487  		policePeakRate = 0x4000     // 16 Kbps
  2488  	)
  2489  
  2490  	police := NewPoliceAction()
  2491  	police.Rate = policeRate
  2492  	police.PeakRate = policePeakRate
  2493  	police.Burst = policeBurst
  2494  	police.ExceedAction = TC_POLICE_SHOT
  2495  	police.NotExceedAction = TC_POLICE_UNSPEC
  2496  
  2497  	classId := MakeHandle(1, 1)
  2498  	filter := &U32{
  2499  		FilterAttrs: FilterAttrs{
  2500  			LinkIndex: link.Attrs().Index,
  2501  			Parent:    MakeHandle(0xffff, 0),
  2502  			Priority:  1,
  2503  			Protocol:  unix.ETH_P_ALL,
  2504  		},
  2505  		ClassId: classId,
  2506  		Police:  police,
  2507  	}
  2508  
  2509  	if err := FilterAdd(filter); err != nil {
  2510  		t.Fatal(err)
  2511  	}
  2512  
  2513  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  2514  	if err != nil {
  2515  		t.Fatal(err)
  2516  	}
  2517  	if len(filters) != 1 {
  2518  		t.Fatal("Failed to add filter")
  2519  	}
  2520  	u32, ok := filters[0].(*U32)
  2521  	if !ok {
  2522  		t.Fatal("Filter is the wrong type")
  2523  	}
  2524  
  2525  	if u32.Police == nil {
  2526  		t.Fatalf("No police in filter")
  2527  	}
  2528  
  2529  	if u32.Police.Rate != policeRate {
  2530  		t.Fatal("Filter Rate doesn't match")
  2531  	}
  2532  
  2533  	if u32.Police.PeakRate != policePeakRate {
  2534  		t.Fatal("Filter PeakRate doesn't match")
  2535  	}
  2536  
  2537  	if u32.Police.LinkLayer != nl.LINKLAYER_ETHERNET {
  2538  		t.Fatal("Filter LinkLayer doesn't match")
  2539  	}
  2540  
  2541  	if err := QdiscDel(qdisc); err != nil {
  2542  		t.Fatal(err)
  2543  	}
  2544  	qdiscs, err := SafeQdiscList(link)
  2545  	if err != nil {
  2546  		t.Fatal(err)
  2547  	}
  2548  
  2549  	found := false
  2550  	for _, v := range qdiscs {
  2551  		if _, ok := v.(*Ingress); ok {
  2552  			found = true
  2553  			break
  2554  		}
  2555  	}
  2556  	if found {
  2557  		t.Fatal("Failed to remove qdisc")
  2558  	}
  2559  }
  2560  
  2561  func TestFilterChainAddDel(t *testing.T) {
  2562  	tearDown := setUpNetlinkTest(t)
  2563  	defer tearDown()
  2564  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  2565  		t.Fatal(err)
  2566  	}
  2567  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "bar"}}); err != nil {
  2568  		t.Fatal(err)
  2569  	}
  2570  	link, err := LinkByName("foo")
  2571  	if err != nil {
  2572  		t.Fatal(err)
  2573  	}
  2574  	if err := LinkSetUp(link); err != nil {
  2575  		t.Fatal(err)
  2576  	}
  2577  	redir, err := LinkByName("bar")
  2578  	if err != nil {
  2579  		t.Fatal(err)
  2580  	}
  2581  	if err := LinkSetUp(redir); err != nil {
  2582  		t.Fatal(err)
  2583  	}
  2584  	qdisc := &Ingress{
  2585  		QdiscAttrs: QdiscAttrs{
  2586  			LinkIndex: link.Attrs().Index,
  2587  			Handle:    MakeHandle(0xffff, 0),
  2588  			Parent:    HANDLE_INGRESS,
  2589  		},
  2590  	}
  2591  	if err := QdiscAdd(qdisc); err != nil {
  2592  		t.Fatal(err)
  2593  	}
  2594  	qdiscs, err := SafeQdiscList(link)
  2595  	if err != nil {
  2596  		t.Fatal(err)
  2597  	}
  2598  	if len(qdiscs) != 1 {
  2599  		t.Fatal("Failed to add qdisc")
  2600  	}
  2601  	_, ok := qdiscs[0].(*Ingress)
  2602  	if !ok {
  2603  		t.Fatal("Qdisc is the wrong type")
  2604  	}
  2605  	classId := MakeHandle(1, 1)
  2606  	chainVal := new(uint32)
  2607  	*chainVal = 20
  2608  	filter := &U32{
  2609  		FilterAttrs: FilterAttrs{
  2610  			LinkIndex: link.Attrs().Index,
  2611  			Parent:    MakeHandle(0xffff, 0),
  2612  			Priority:  1,
  2613  			Protocol:  unix.ETH_P_IP,
  2614  			Chain:     chainVal,
  2615  		},
  2616  		RedirIndex: redir.Attrs().Index,
  2617  		ClassId:    classId,
  2618  	}
  2619  	if err := FilterAdd(filter); err != nil {
  2620  		t.Fatal(err)
  2621  	}
  2622  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  2623  	if err != nil {
  2624  		t.Fatal(err)
  2625  	}
  2626  	if len(filters) != 1 {
  2627  		t.Fatal("Failed to add filter")
  2628  	}
  2629  	filterChain := filters[0].Attrs().Chain
  2630  	if filterChain != nil && *filterChain != *chainVal {
  2631  		t.Fatalf("Chain of the filter is the wrong value")
  2632  	}
  2633  	if err := FilterDel(filter); err != nil {
  2634  		t.Fatal(err)
  2635  	}
  2636  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2637  	if err != nil {
  2638  		t.Fatal(err)
  2639  	}
  2640  	if len(filters) != 0 {
  2641  		t.Fatal("Failed to remove filter")
  2642  	}
  2643  	if err := QdiscDel(qdisc); err != nil {
  2644  		t.Fatal(err)
  2645  	}
  2646  	qdiscs, err = SafeQdiscList(link)
  2647  	if err != nil {
  2648  		t.Fatal(err)
  2649  	}
  2650  	if len(qdiscs) != 0 {
  2651  		t.Fatal("Failed to remove qdisc")
  2652  	}
  2653  }
  2654  
  2655  func TestFilterSampleAddDel(t *testing.T) {
  2656  	minKernelRequired(t, 4, 11)
  2657  	if _, err := GenlFamilyGet("psample"); err != nil {
  2658  		t.Skip("psample genetlink family unavailable - is CONFIG_PSAMPLE enabled?")
  2659  	}
  2660  
  2661  	tearDown := setUpNetlinkTest(t)
  2662  	defer tearDown()
  2663  	if err := LinkAdd(&Ifb{LinkAttrs{Name: "foo"}}); err != nil {
  2664  		t.Fatal(err)
  2665  	}
  2666  	link, err := LinkByName("foo")
  2667  	if err != nil {
  2668  		t.Fatal(err)
  2669  	}
  2670  	if err := LinkSetUp(link); err != nil {
  2671  		t.Fatal(err)
  2672  	}
  2673  
  2674  	qdisc := &Ingress{
  2675  		QdiscAttrs: QdiscAttrs{
  2676  			LinkIndex: link.Attrs().Index,
  2677  			Handle:    MakeHandle(0xffff, 0),
  2678  			Parent:    HANDLE_INGRESS,
  2679  		},
  2680  	}
  2681  	if err := QdiscAdd(qdisc); err != nil {
  2682  		t.Fatal(err)
  2683  	}
  2684  	qdiscs, err := SafeQdiscList(link)
  2685  	if err != nil {
  2686  		t.Fatal(err)
  2687  	}
  2688  
  2689  	found := false
  2690  	for _, v := range qdiscs {
  2691  		if _, ok := v.(*Ingress); ok {
  2692  			found = true
  2693  			break
  2694  		}
  2695  	}
  2696  	if !found {
  2697  		t.Fatal("Qdisc is the wrong type")
  2698  	}
  2699  
  2700  	sample := NewSampleAction()
  2701  	sample.Group = 7
  2702  	sample.Rate = 12
  2703  	sample.TruncSize = 200
  2704  
  2705  	classId := MakeHandle(1, 1)
  2706  	filter := &MatchAll{
  2707  		FilterAttrs: FilterAttrs{
  2708  			LinkIndex: link.Attrs().Index,
  2709  			Parent:    MakeHandle(0xffff, 0),
  2710  			Priority:  1,
  2711  			Protocol:  unix.ETH_P_ALL,
  2712  		},
  2713  		ClassId: classId,
  2714  		Actions: []Action{
  2715  			sample,
  2716  		},
  2717  	}
  2718  
  2719  	if err := FilterAdd(filter); err != nil {
  2720  		t.Fatal(err)
  2721  	}
  2722  
  2723  	filters, err := FilterList(link, MakeHandle(0xffff, 0))
  2724  	if err != nil {
  2725  		t.Fatal(err)
  2726  	}
  2727  	if len(filters) != 1 {
  2728  		t.Fatal("Failed to add filter")
  2729  	}
  2730  	mf, ok := filters[0].(*MatchAll)
  2731  	if !ok {
  2732  		t.Fatal("Filter is the wrong type")
  2733  	}
  2734  
  2735  	if len(mf.Actions) < 1 {
  2736  		t.Fatalf("Too few Actions in filter")
  2737  	}
  2738  	if mf.ClassId != classId {
  2739  		t.Fatalf("ClassId of the filter is the wrong value")
  2740  	}
  2741  
  2742  	lsample, ok := mf.Actions[0].(*SampleAction)
  2743  	if !ok {
  2744  		t.Fatal("Unable to find sample action")
  2745  	}
  2746  	if lsample.Group != sample.Group {
  2747  		t.Fatalf("Inconsistent sample action group")
  2748  	}
  2749  	if lsample.Rate != sample.Rate {
  2750  		t.Fatalf("Inconsistent sample action rate")
  2751  	}
  2752  	if lsample.TruncSize != sample.TruncSize {
  2753  		t.Fatalf("Inconsistent sample truncation size")
  2754  	}
  2755  
  2756  	if err := FilterDel(filter); err != nil {
  2757  		t.Fatal(err)
  2758  	}
  2759  	filters, err = FilterList(link, MakeHandle(0xffff, 0))
  2760  	if err != nil {
  2761  		t.Fatal(err)
  2762  	}
  2763  	if len(filters) != 0 {
  2764  		t.Fatal("Failed to remove filter")
  2765  	}
  2766  
  2767  	if err := QdiscDel(qdisc); err != nil {
  2768  		t.Fatal(err)
  2769  	}
  2770  	qdiscs, err = SafeQdiscList(link)
  2771  	if err != nil {
  2772  		t.Fatal(err)
  2773  	}
  2774  
  2775  	found = false
  2776  	for _, v := range qdiscs {
  2777  		if _, ok := v.(*Ingress); ok {
  2778  			found = true
  2779  			break
  2780  		}
  2781  	}
  2782  	if found {
  2783  		t.Fatal("Failed to remove qdisc")
  2784  	}
  2785  }