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

     1  package netlink
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"net"
     7  	"testing"
     8  
     9  	"github.com/vishvananda/netlink/nl"
    10  	"golang.org/x/sys/unix"
    11  )
    12  
    13  func TestParseIpsetProtocolResult(t *testing.T) {
    14  	msgBytes, err := ioutil.ReadFile("testdata/ipset_protocol_result")
    15  	if err != nil {
    16  		t.Fatalf("reading test fixture failed: %v", err)
    17  	}
    18  
    19  	msg := ipsetUnserialize([][]byte{msgBytes})
    20  	if msg.Protocol != 6 {
    21  		t.Errorf("expected msg.Protocol to equal 6, got %d", msg.Protocol)
    22  	}
    23  }
    24  
    25  func TestParseIpsetListResult(t *testing.T) {
    26  	msgBytes, err := ioutil.ReadFile("testdata/ipset_list_result")
    27  	if err != nil {
    28  		t.Fatalf("reading test fixture failed: %v", err)
    29  	}
    30  
    31  	msg := ipsetUnserialize([][]byte{msgBytes})
    32  	if msg.SetName != "clients" {
    33  		t.Errorf(`expected SetName to equal "clients", got %q`, msg.SetName)
    34  	}
    35  	if msg.TypeName != "hash:mac" {
    36  		t.Errorf(`expected TypeName to equal "hash:mac", got %q`, msg.TypeName)
    37  	}
    38  	if msg.Protocol != 6 {
    39  		t.Errorf("expected Protocol to equal 6, got %d", msg.Protocol)
    40  	}
    41  	if msg.References != 0 {
    42  		t.Errorf("expected References to equal 0, got %d", msg.References)
    43  	}
    44  	if msg.NumEntries != 2 {
    45  		t.Errorf("expected NumEntries to equal 2, got %d", msg.NumEntries)
    46  	}
    47  	if msg.HashSize != 1024 {
    48  		t.Errorf("expected HashSize to equal 1024, got %d", msg.HashSize)
    49  	}
    50  	if *msg.Timeout != 3600 {
    51  		t.Errorf("expected Timeout to equal 3600, got %d", *msg.Timeout)
    52  	}
    53  	if msg.MaxElements != 65536 {
    54  		t.Errorf("expected MaxElements to equal 65536, got %d", msg.MaxElements)
    55  	}
    56  	if msg.CadtFlags != nl.IPSET_FLAG_WITH_COMMENT|nl.IPSET_FLAG_WITH_COUNTERS {
    57  		t.Error("expected CadtFlags to be IPSET_FLAG_WITH_COMMENT and IPSET_FLAG_WITH_COUNTERS")
    58  	}
    59  	if len(msg.Entries) != 2 {
    60  		t.Fatalf("expected 2 Entries, got %d", len(msg.Entries))
    61  	}
    62  
    63  	// first entry
    64  	ent := msg.Entries[0]
    65  	if int(*ent.Timeout) != 3577 {
    66  		t.Errorf("expected Timeout for first entry to equal 3577, got %d", *ent.Timeout)
    67  	}
    68  	if int(*ent.Bytes) != 4121 {
    69  		t.Errorf("expected Bytes for first entry to equal 4121, got %d", *ent.Bytes)
    70  	}
    71  	if int(*ent.Packets) != 42 {
    72  		t.Errorf("expected Packets for first entry to equal 42, got %d", *ent.Packets)
    73  	}
    74  	if ent.Comment != "foo bar" {
    75  		t.Errorf("unexpected Comment for first entry: %q", ent.Comment)
    76  	}
    77  	expectedMAC := net.HardwareAddr{0xde, 0xad, 0x0, 0x0, 0xbe, 0xef}
    78  	if !bytes.Equal(ent.MAC, expectedMAC) {
    79  		t.Errorf("expected MAC for first entry to be %s, got %s", expectedMAC.String(), ent.MAC.String())
    80  	}
    81  
    82  	// second entry
    83  	ent = msg.Entries[1]
    84  	expectedMAC = net.HardwareAddr{0x1, 0x2, 0x3, 0x0, 0x1, 0x2}
    85  	if !bytes.Equal(ent.MAC, expectedMAC) {
    86  		t.Errorf("expected MAC for second entry to be %s, got %s", expectedMAC.String(), ent.MAC.String())
    87  	}
    88  }
    89  
    90  func TestIpsetCreateListAddDelDestroy(t *testing.T) {
    91  	tearDown := setUpNetlinkTest(t)
    92  	defer tearDown()
    93  	timeout := uint32(3)
    94  	err := IpsetCreate("my-test-ipset-1", "hash:ip", IpsetCreateOptions{
    95  		Replace:  true,
    96  		Timeout:  &timeout,
    97  		Counters: true,
    98  		Comments: true,
    99  		Skbinfo:  false,
   100  	})
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  
   105  	err = IpsetCreate("my-test-ipset-2", "hash:net", IpsetCreateOptions{
   106  		Replace:  true,
   107  		Timeout:  &timeout,
   108  		Counters: false,
   109  		Comments: true,
   110  		Skbinfo:  true,
   111  	})
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  
   116  	results, err := IpsetListAll()
   117  
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  
   122  	if len(results) != 2 {
   123  		t.Fatalf("expected 2 IPSets to be created, got %d", len(results))
   124  	}
   125  
   126  	if results[0].SetName != "my-test-ipset-1" {
   127  		t.Errorf("expected name to be 'my-test-ipset-1', but got '%s'", results[0].SetName)
   128  	}
   129  
   130  	if results[1].SetName != "my-test-ipset-2" {
   131  		t.Errorf("expected name to be 'my-test-ipset-2', but got '%s'", results[1].SetName)
   132  	}
   133  
   134  	if results[0].TypeName != "hash:ip" {
   135  		t.Errorf("expected type to be 'hash:ip', but got '%s'", results[0].TypeName)
   136  	}
   137  
   138  	if results[1].TypeName != "hash:net" {
   139  		t.Errorf("expected type to be 'hash:net', but got '%s'", results[1].TypeName)
   140  	}
   141  
   142  	if *results[0].Timeout != 3 {
   143  		t.Errorf("expected timeout to be 3, but got '%d'", *results[0].Timeout)
   144  	}
   145  
   146  	ip := net.ParseIP("10.99.99.99")
   147  	exist, err := IpsetTest("my-test-ipset-1", &IPSetEntry{
   148  		IP: ip,
   149  	})
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	if exist {
   154  		t.Errorf("entry should not exist before being added: %s", ip.String())
   155  	}
   156  
   157  	err = IpsetAdd("my-test-ipset-1", &IPSetEntry{
   158  		Comment: "test comment",
   159  		IP:      ip,
   160  		Replace: false,
   161  	})
   162  
   163  	if err != nil {
   164  		t.Fatal(err)
   165  	}
   166  
   167  	exist, err = IpsetTest("my-test-ipset-1", &IPSetEntry{
   168  		IP: ip,
   169  	})
   170  	if err != nil {
   171  		t.Fatal(err)
   172  	}
   173  	if !exist {
   174  		t.Errorf("entry should exist after being added: %s", ip.String())
   175  	}
   176  
   177  	result, err := IpsetList("my-test-ipset-1")
   178  
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	if len(result.Entries) != 1 {
   184  		t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries))
   185  	}
   186  	if result.Entries[0].IP.String() != "10.99.99.99" {
   187  		t.Fatalf("expected entry to be '10.99.99.99', got '%s'", result.Entries[0].IP.String())
   188  	}
   189  
   190  	if result.Entries[0].Comment != "test comment" {
   191  		// This is only supported in the kernel module from revision 2 or 4, so comments may be ignored.
   192  		t.Logf("expected comment to be 'test comment', got '%s'", result.Entries[0].Comment)
   193  	}
   194  
   195  	err = IpsetDel("my-test-ipset-1", &IPSetEntry{
   196  		Comment: "test comment",
   197  		IP:      net.ParseIP("10.99.99.99"),
   198  	})
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  
   203  	result, err = IpsetList("my-test-ipset-1")
   204  	if err != nil {
   205  		t.Fatal(err)
   206  	}
   207  
   208  	if len(result.Entries) != 0 {
   209  		t.Fatalf("expected 0 entries to exist, got %d", len(result.Entries))
   210  	}
   211  
   212  	err = IpsetDestroy("my-test-ipset-1")
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	err = IpsetDestroy("my-test-ipset-2")
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  }
   222  
   223  func TestIpsetCreateListAddDelDestroyWithTestCases(t *testing.T) {
   224  	timeout := uint32(3)
   225  	protocalTCP := uint8(unix.IPPROTO_TCP)
   226  	port := uint16(80)
   227  
   228  	testCases := []struct {
   229  		desc     string
   230  		setname  string
   231  		typename string
   232  		options  IpsetCreateOptions
   233  		entry    *IPSetEntry
   234  	}{
   235  		{
   236  			desc:     "Type-hash:ip",
   237  			setname:  "my-test-ipset-1",
   238  			typename: "hash:ip",
   239  			options: IpsetCreateOptions{
   240  				Replace:  true,
   241  				Timeout:  &timeout,
   242  				Counters: true,
   243  				Comments: true,
   244  				Skbinfo:  false,
   245  			},
   246  			entry: &IPSetEntry{
   247  				Comment: "test comment",
   248  				IP:      net.ParseIP("10.99.99.99"),
   249  				Replace: false,
   250  			},
   251  		},
   252  		{
   253  			desc:     "Type-hash:net",
   254  			setname:  "my-test-ipset-2",
   255  			typename: "hash:net",
   256  			options: IpsetCreateOptions{
   257  				Replace:  true,
   258  				Timeout:  &timeout,
   259  				Counters: false,
   260  				Comments: true,
   261  				Skbinfo:  true,
   262  			},
   263  			entry: &IPSetEntry{
   264  				Comment: "test comment",
   265  				IP:      net.ParseIP("10.99.99.0"),
   266  				CIDR:    24,
   267  				Replace: false,
   268  			},
   269  		},
   270  		{
   271  			desc:     "Type-hash:net,net",
   272  			setname:  "my-test-ipset-4",
   273  			typename: "hash:net,net",
   274  			options: IpsetCreateOptions{
   275  				Replace:  true,
   276  				Timeout:  &timeout,
   277  				Counters: false,
   278  				Comments: true,
   279  				Skbinfo:  true,
   280  			},
   281  			entry: &IPSetEntry{
   282  				Comment: "test comment",
   283  				IP:      net.ParseIP("10.99.99.0"),
   284  				CIDR:    24,
   285  				IP2:     net.ParseIP("10.99.0.0"),
   286  				CIDR2:   24,
   287  				Replace: false,
   288  			},
   289  		},
   290  		{
   291  			desc:     "Type-hash:ip,ip",
   292  			setname:  "my-test-ipset-5",
   293  			typename: "hash:net,net",
   294  			options: IpsetCreateOptions{
   295  				Replace:  true,
   296  				Timeout:  &timeout,
   297  				Counters: false,
   298  				Comments: true,
   299  				Skbinfo:  true,
   300  			},
   301  			entry: &IPSetEntry{
   302  				Comment: "test comment",
   303  				IP:      net.ParseIP("10.99.99.0"),
   304  				IP2:     net.ParseIP("10.99.0.0"),
   305  				Replace: false,
   306  			},
   307  		},
   308  		{
   309  			desc:     "Type-hash:ip,port",
   310  			setname:  "my-test-ipset-6",
   311  			typename: "hash:ip,port",
   312  			options: IpsetCreateOptions{
   313  				Replace:  true,
   314  				Timeout:  &timeout,
   315  				Counters: false,
   316  				Comments: true,
   317  				Skbinfo:  true,
   318  			},
   319  			entry: &IPSetEntry{
   320  				Comment:  "test comment",
   321  				IP:       net.ParseIP("10.99.99.1"),
   322  				Protocol: &protocalTCP,
   323  				Port:     &port,
   324  				Replace:  false,
   325  			},
   326  		},
   327  		{
   328  			desc:     "Type-hash:net,port,net",
   329  			setname:  "my-test-ipset-7",
   330  			typename: "hash:net,port,net",
   331  			options: IpsetCreateOptions{
   332  				Replace:  true,
   333  				Timeout:  &timeout,
   334  				Counters: false,
   335  				Comments: true,
   336  				Skbinfo:  true,
   337  			},
   338  			entry: &IPSetEntry{
   339  				Comment:  "test comment",
   340  				IP:       net.ParseIP("10.99.99.0"),
   341  				CIDR:     24,
   342  				IP2:      net.ParseIP("10.99.0.0"),
   343  				CIDR2:    24,
   344  				Protocol: &protocalTCP,
   345  				Port:     &port,
   346  				Replace:  false,
   347  			},
   348  		},
   349  		{
   350  			desc:     "Type-hash:mac",
   351  			setname:  "my-test-ipset-8",
   352  			typename: "hash:mac",
   353  			options: IpsetCreateOptions{
   354  				Replace:  true,
   355  				Timeout:  &timeout,
   356  				Counters: true,
   357  				Comments: true,
   358  				Skbinfo:  false,
   359  			},
   360  			entry: &IPSetEntry{
   361  				Comment: "test comment",
   362  				MAC:     net.HardwareAddr{0x26, 0x6f, 0x0d, 0x5b, 0xc1, 0x9d},
   363  				Replace: false,
   364  			},
   365  		},
   366  		{
   367  			desc:     "Type-hash:net,iface",
   368  			setname:  "my-test-ipset-9",
   369  			typename: "hash:net,iface",
   370  			options: IpsetCreateOptions{
   371  				Replace:  true,
   372  				Timeout:  &timeout,
   373  				Counters: true,
   374  				Comments: true,
   375  				Skbinfo:  false,
   376  			},
   377  			entry: &IPSetEntry{
   378  				Comment: "test comment",
   379  				IP:      net.ParseIP("10.99.99.0"),
   380  				CIDR:    24,
   381  				IFace:   "eth0",
   382  				Replace: false,
   383  			},
   384  		},
   385  		{
   386  			desc:     "Type-hash:ip,mark",
   387  			setname:  "my-test-ipset-10",
   388  			typename: "hash:ip,mark",
   389  			options: IpsetCreateOptions{
   390  				Replace:  true,
   391  				Timeout:  &timeout,
   392  				Counters: true,
   393  				Comments: true,
   394  				Skbinfo:  false,
   395  			},
   396  			entry: &IPSetEntry{
   397  				Comment: "test comment",
   398  				IP:      net.ParseIP("10.99.99.0"),
   399  				Mark:    &timeout,
   400  				Replace: false,
   401  			},
   402  		},
   403  		{
   404  			desc:     "Type-hash:net6",
   405  			setname:  "my-test-ipset-11",
   406  			typename: "hash:net",
   407  			options: IpsetCreateOptions{
   408  				Replace:  true,
   409  				Timeout:  &timeout,
   410  				Counters: false,
   411  				Comments: true,
   412  				Skbinfo:  true,
   413  				Family:   unix.AF_INET6,
   414  			},
   415  			entry: &IPSetEntry{
   416  				Comment: "test comment",
   417  				IP:      net.ParseIP("::1"),
   418  				CIDR:    128,
   419  				Replace: false,
   420  			},
   421  		},
   422  		{
   423  			desc:     "Type-hash:net6:net6",
   424  			setname:  "my-test-ipset-11",
   425  			typename: "hash:net,net",
   426  			options: IpsetCreateOptions{
   427  				Replace:  true,
   428  				Timeout:  &timeout,
   429  				Counters: false,
   430  				Comments: true,
   431  				Skbinfo:  true,
   432  				Family:   unix.AF_INET6,
   433  			},
   434  			entry: &IPSetEntry{
   435  				Comment: "test comment",
   436  				IP:      net.ParseIP("::1"),
   437  				CIDR:    128,
   438  				IP2:     net.ParseIP("::2"),
   439  				CIDR2:   128,
   440  				Replace: false,
   441  			},
   442  		},
   443  	}
   444  
   445  	for _, tC := range testCases {
   446  		t.Run(tC.desc, func(t *testing.T) {
   447  			tearDown := setUpNetlinkTest(t)
   448  			defer tearDown()
   449  
   450  			err := IpsetCreate(tC.setname, tC.typename, tC.options)
   451  			if err != nil {
   452  				t.Fatal(err)
   453  			}
   454  
   455  			result, err := IpsetList(tC.setname)
   456  			if err != nil {
   457  				t.Fatal(err)
   458  			}
   459  
   460  			if result.SetName != tC.setname {
   461  				t.Errorf("expected name to be '%s', but got '%s'", tC.setname, result.SetName)
   462  			}
   463  
   464  			if result.TypeName != tC.typename {
   465  				t.Errorf("expected type to be '%s', but got '%s'", tC.typename, result.TypeName)
   466  			}
   467  
   468  			if *result.Timeout != timeout {
   469  				t.Errorf("expected timeout to be %d, but got '%d'", timeout, *result.Timeout)
   470  			}
   471  
   472  			err = IpsetAdd(tC.setname, tC.entry)
   473  
   474  			if err != nil {
   475  				t.Error(result.Protocol, result.Family)
   476  				t.Fatal(err)
   477  			}
   478  
   479  			exist, err := IpsetTest(tC.setname, tC.entry)
   480  			if err != nil {
   481  				t.Fatal(err)
   482  			}
   483  			if !exist {
   484  				t.Errorf("entry should exist, but 'test' got false, case: %s", tC.desc)
   485  			}
   486  
   487  			result, err = IpsetList(tC.setname)
   488  
   489  			if err != nil {
   490  				t.Fatal(err)
   491  			}
   492  
   493  			if len(result.Entries) != 1 {
   494  				t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries))
   495  			}
   496  
   497  			if tC.entry.IP != nil {
   498  				if !tC.entry.IP.Equal(result.Entries[0].IP) {
   499  					t.Fatalf("expected entry to be '%v', got '%v'", tC.entry.IP, result.Entries[0].IP)
   500  				}
   501  			}
   502  
   503  			if tC.entry.CIDR > 0 {
   504  				if result.Entries[0].CIDR != tC.entry.CIDR {
   505  					t.Fatalf("expected cidr to be '%d', got '%d'", tC.entry.CIDR, result.Entries[0].CIDR)
   506  				}
   507  			}
   508  
   509  			if tC.entry.IP2 != nil {
   510  				if !tC.entry.IP2.Equal(result.Entries[0].IP2) {
   511  					t.Fatalf("expected entry.ip2 to be '%v', got '%v'", tC.entry.IP2, result.Entries[0].IP2)
   512  				}
   513  			}
   514  
   515  			if tC.entry.CIDR2 > 0 {
   516  				if result.Entries[0].CIDR2 != tC.entry.CIDR2 {
   517  					t.Fatalf("expected cidr2 to be '%d', got '%d'", tC.entry.CIDR2, result.Entries[0].CIDR2)
   518  				}
   519  			}
   520  
   521  			if tC.entry.Port != nil {
   522  				if *result.Entries[0].Protocol != *tC.entry.Protocol {
   523  					t.Fatalf("expected protocol to be '%d', got '%d'", *tC.entry.Protocol, *result.Entries[0].Protocol)
   524  				}
   525  				if *result.Entries[0].Port != *tC.entry.Port {
   526  					t.Fatalf("expected port to be '%d', got '%d'", *tC.entry.Port, *result.Entries[0].Port)
   527  				}
   528  			}
   529  
   530  			if tC.entry.MAC != nil {
   531  				if result.Entries[0].MAC.String() != tC.entry.MAC.String() {
   532  					t.Fatalf("expected mac to be '%v', got '%v'", tC.entry.MAC, result.Entries[0].MAC)
   533  				}
   534  			}
   535  
   536  			if tC.entry.IFace != "" {
   537  				if result.Entries[0].IFace != tC.entry.IFace {
   538  					t.Fatalf("expected iface to be '%v', got '%v'", tC.entry.IFace, result.Entries[0].IFace)
   539  				}
   540  			}
   541  
   542  			if tC.entry.Mark != nil {
   543  				if *result.Entries[0].Mark != *tC.entry.Mark {
   544  					t.Fatalf("expected mark to be '%v', got '%v'", *tC.entry.Mark, *result.Entries[0].Mark)
   545  				}
   546  			}
   547  
   548  			if result.Entries[0].Comment != tC.entry.Comment {
   549  				// This is only supported in the kernel module from revision 2 or 4, so comments may be ignored.
   550  				t.Logf("expected comment to be '%s', got '%s'", tC.entry.Comment, result.Entries[0].Comment)
   551  			}
   552  
   553  			err = IpsetDel(tC.setname, tC.entry)
   554  			if err != nil {
   555  				t.Fatal(err)
   556  			}
   557  
   558  			exist, err = IpsetTest(tC.setname, tC.entry)
   559  			if err != nil {
   560  				t.Fatal(err)
   561  			}
   562  			if exist {
   563  				t.Errorf("entry should be deleted, but 'test' got true, case: %s", tC.desc)
   564  			}
   565  
   566  			result, err = IpsetList(tC.setname)
   567  			if err != nil {
   568  				t.Fatal(err)
   569  			}
   570  
   571  			if len(result.Entries) != 0 {
   572  				t.Fatalf("expected 0 entries to exist, got %d", len(result.Entries))
   573  			}
   574  
   575  			err = IpsetDestroy(tC.setname)
   576  			if err != nil {
   577  				t.Fatal(err)
   578  			}
   579  		})
   580  	}
   581  }
   582  
   583  func TestIpsetBitmapCreateListWithTestCases(t *testing.T) {
   584  	timeout := uint32(3)
   585  
   586  	testCases := []struct {
   587  		desc     string
   588  		setname  string
   589  		typename string
   590  		options  IpsetCreateOptions
   591  		entry    *IPSetEntry
   592  	}{
   593  		{
   594  			desc:     "Type-bitmap:port",
   595  			setname:  "my-test-ipset-11",
   596  			typename: "bitmap:port",
   597  			options: IpsetCreateOptions{
   598  				Replace:  true,
   599  				Timeout:  &timeout,
   600  				Counters: true,
   601  				Comments: false,
   602  				Skbinfo:  false,
   603  				PortFrom: 100,
   604  				PortTo:   600,
   605  			},
   606  			entry: &IPSetEntry{
   607  				Comment: "test comment",
   608  				IP:      net.ParseIP("10.99.99.0"),
   609  				CIDR:    26,
   610  				Mark:    &timeout,
   611  				Replace: false,
   612  			},
   613  		},
   614  	}
   615  
   616  	for _, tC := range testCases {
   617  		t.Run(tC.desc, func(t *testing.T) {
   618  			tearDown := setUpNetlinkTest(t)
   619  			defer tearDown()
   620  
   621  			err := IpsetCreate(tC.setname, tC.typename, tC.options)
   622  			if err != nil {
   623  				t.Fatal(err)
   624  			}
   625  
   626  			result, err := IpsetList(tC.setname)
   627  			if err != nil {
   628  				t.Fatal(err)
   629  			}
   630  
   631  			if tC.typename == "bitmap:port" {
   632  				if result.PortFrom != tC.options.PortFrom || result.PortTo != tC.options.PortTo {
   633  					t.Fatalf("expected port range %d-%d, got %d-%d", tC.options.PortFrom, tC.options.PortTo, result.PortFrom, result.PortTo)
   634  				}
   635  			} else if tC.typename == "bitmap:ip" {
   636  				if result.IPFrom == nil || result.IPTo == nil || result.IPFrom.Equal(tC.options.IPFrom) || result.IPTo.Equal(tC.options.IPTo) {
   637  					t.Fatalf("expected ip range %v-%v, got %v-%v", tC.options.IPFrom, tC.options.IPTo, result.IPFrom, result.IPTo)
   638  				}
   639  			}
   640  
   641  		})
   642  	}
   643  }
   644  
   645  func TestIpsetSwap(t *testing.T) {
   646  	tearDown := setUpNetlinkTest(t)
   647  	defer tearDown()
   648  
   649  	ipset1 := "my-test-ipset-swap-1"
   650  	ipset2 := "my-test-ipset-swap-2"
   651  
   652  	err := IpsetCreate(ipset1, "hash:ip", IpsetCreateOptions{
   653  		Replace: true,
   654  	})
   655  	if err != nil {
   656  		t.Fatal(err)
   657  	}
   658  	defer func() {
   659  		_ = IpsetDestroy(ipset1)
   660  	}()
   661  
   662  	err = IpsetCreate(ipset2, "hash:ip", IpsetCreateOptions{
   663  		Replace: true,
   664  	})
   665  	if err != nil {
   666  		t.Fatal(err)
   667  	}
   668  	defer func() {
   669  		_ = IpsetDestroy(ipset2)
   670  	}()
   671  
   672  	err = IpsetAdd(ipset1, &IPSetEntry{
   673  		IP: net.ParseIP("10.99.99.99"),
   674  	})
   675  	if err != nil {
   676  		t.Fatal(err)
   677  	}
   678  
   679  	assertHasOneEntry := func(name string) {
   680  		result, err := IpsetList(name)
   681  		if err != nil {
   682  			t.Fatal(err)
   683  		}
   684  		if len(result.Entries) != 1 {
   685  			t.Fatalf("expected 1 entry be created, got '%d'", len(result.Entries))
   686  		}
   687  		if result.Entries[0].IP.String() != "10.99.99.99" {
   688  			t.Fatalf("expected entry to be '10.99.99.99', got '%s'", result.Entries[0].IP.String())
   689  		}
   690  	}
   691  
   692  	assertIsEmpty := func(name string) {
   693  		result, err := IpsetList(name)
   694  		if err != nil {
   695  			t.Fatal(err)
   696  		}
   697  		if len(result.Entries) != 0 {
   698  			t.Fatalf("expected 0 entry be created, got '%d'", len(result.Entries))
   699  		}
   700  	}
   701  
   702  	assertHasOneEntry(ipset1)
   703  	assertIsEmpty(ipset2)
   704  
   705  	err = IpsetSwap(ipset1, ipset2)
   706  	if err != nil {
   707  		t.Fatal(err)
   708  	}
   709  
   710  	assertIsEmpty(ipset1)
   711  	assertHasOneEntry(ipset2)
   712  }
   713  
   714  func nextIP(ip net.IP) {
   715  	for j := len(ip) - 1; j >= 0; j-- {
   716  		ip[j]++
   717  		if ip[j] > 0 {
   718  			break
   719  		}
   720  	}
   721  }
   722  
   723  // TestIpsetMaxElements tests that we can create an ipset containing
   724  // 128k elements, which is double the default size (64k elements).
   725  func TestIpsetMaxElements(t *testing.T) {
   726  	tearDown := setUpNetlinkTest(t)
   727  	defer tearDown()
   728  
   729  	ipsetName := "my-test-ipset-max"
   730  	maxElements := uint32(128 << 10)
   731  
   732  	err := IpsetCreate(ipsetName, "hash:ip", IpsetCreateOptions{
   733  		Replace:     true,
   734  		MaxElements: maxElements,
   735  	})
   736  	if err != nil {
   737  		t.Fatal(err)
   738  	}
   739  	defer func() {
   740  		_ = IpsetDestroy(ipsetName)
   741  	}()
   742  
   743  	ip := net.ParseIP("10.0.0.0")
   744  	for i := uint32(0); i < maxElements; i++ {
   745  		err = IpsetAdd(ipsetName, &IPSetEntry{
   746  			IP: ip,
   747  		})
   748  		if err != nil {
   749  			t.Fatal(err)
   750  		}
   751  		nextIP(ip)
   752  	}
   753  
   754  	result, err := IpsetList(ipsetName)
   755  	if err != nil {
   756  		t.Fatal(err)
   757  	}
   758  	if len(result.Entries) != int(maxElements) {
   759  		t.Fatalf("expected '%d' entry be created, got '%d'", maxElements, len(result.Entries))
   760  	}
   761  }