1// +build linux
2
3package netlink
4
5import (
6	"net"
7	"testing"
8)
9
10type arpEntry struct {
11	ip  net.IP
12	mac net.HardwareAddr
13}
14
15type proxyEntry struct {
16	ip  net.IP
17	dev int
18}
19
20func parseMAC(s string) net.HardwareAddr {
21	m, err := net.ParseMAC(s)
22	if err != nil {
23		panic(err)
24	}
25	return m
26}
27
28func dumpContains(dump []Neigh, e arpEntry) bool {
29	for _, n := range dump {
30		if n.IP.Equal(e.ip) && (n.State&NUD_INCOMPLETE) == 0 {
31			return true
32		}
33	}
34	return false
35}
36
37func dumpContainsNeigh(dump []Neigh, ne Neigh) bool {
38	for _, n := range dump {
39		if n.IP.Equal(ne.IP) && n.LLIPAddr.Equal(ne.LLIPAddr) {
40			return true
41		}
42	}
43	return false
44}
45
46func dumpContainsProxy(dump []Neigh, p proxyEntry) bool {
47	for _, n := range dump {
48		if n.IP.Equal(p.ip) && (n.LinkIndex == p.dev) && (n.Flags&NTF_PROXY) == NTF_PROXY {
49			return true
50		}
51	}
52	return false
53}
54
55func TestNeighAddDelLLIPAddr(t *testing.T) {
56	setUpNetlinkTestWithKModule(t, "ipip")
57
58	tearDown := setUpNetlinkTest(t)
59	defer tearDown()
60
61	dummy := Iptun{
62		LinkAttrs: LinkAttrs{Name: "neigh0"},
63		PMtuDisc:  1,
64		Local:     net.IPv4(127, 0, 0, 1),
65		Remote:    net.IPv4(127, 0, 0, 1)}
66	if err := LinkAdd(&dummy); err != nil {
67		t.Errorf("Failed to create link: %v", err)
68	}
69	ensureIndex(dummy.Attrs())
70
71	entry := Neigh{
72		LinkIndex: dummy.Index,
73		State:     NUD_PERMANENT,
74		IP:        net.IPv4(198, 51, 100, 2),
75		LLIPAddr:  net.IPv4(198, 51, 100, 1),
76	}
77
78	err := NeighAdd(&entry)
79	if err != nil {
80		t.Errorf("Failed to NeighAdd: %v", err)
81	}
82
83	// Dump and see that all added entries are there
84	dump, err := NeighList(dummy.Index, 0)
85	if err != nil {
86		t.Errorf("Failed to NeighList: %v", err)
87	}
88
89	if !dumpContainsNeigh(dump, entry) {
90		t.Errorf("Dump does not contain: %v: %v", entry, dump)
91
92	}
93
94	// Delete the entry
95	err = NeighDel(&entry)
96	if err != nil {
97		t.Errorf("Failed to NeighDel: %v", err)
98	}
99
100	if err := LinkDel(&dummy); err != nil {
101		t.Fatal(err)
102	}
103}
104
105func TestNeighAddDel(t *testing.T) {
106	tearDown := setUpNetlinkTest(t)
107	defer tearDown()
108
109	dummy := Dummy{LinkAttrs{Name: "neigh0"}}
110	if err := LinkAdd(&dummy); err != nil {
111		t.Fatal(err)
112	}
113
114	ensureIndex(dummy.Attrs())
115
116	arpTable := []arpEntry{
117		{net.ParseIP("10.99.0.1"), parseMAC("aa:bb:cc:dd:00:01")},
118		{net.ParseIP("10.99.0.2"), parseMAC("aa:bb:cc:dd:00:02")},
119		{net.ParseIP("10.99.0.3"), parseMAC("aa:bb:cc:dd:00:03")},
120		{net.ParseIP("10.99.0.4"), parseMAC("aa:bb:cc:dd:00:04")},
121		{net.ParseIP("10.99.0.5"), parseMAC("aa:bb:cc:dd:00:05")},
122	}
123
124	// Add the arpTable
125	for _, entry := range arpTable {
126		err := NeighAdd(&Neigh{
127			LinkIndex:    dummy.Index,
128			State:        NUD_REACHABLE,
129			IP:           entry.ip,
130			HardwareAddr: entry.mac,
131		})
132
133		if err != nil {
134			t.Errorf("Failed to NeighAdd: %v", err)
135		}
136	}
137
138	// Dump and see that all added entries are there
139	dump, err := NeighList(dummy.Index, 0)
140	if err != nil {
141		t.Errorf("Failed to NeighList: %v", err)
142	}
143
144	for _, entry := range arpTable {
145		if !dumpContains(dump, entry) {
146			t.Errorf("Dump does not contain: %v", entry)
147		}
148	}
149
150	// Delete the arpTable
151	for _, entry := range arpTable {
152		err := NeighDel(&Neigh{
153			LinkIndex:    dummy.Index,
154			IP:           entry.ip,
155			HardwareAddr: entry.mac,
156		})
157
158		if err != nil {
159			t.Errorf("Failed to NeighDel: %v", err)
160		}
161	}
162
163	// TODO: seems not working because of cache
164	//// Dump and see that none of deleted entries are there
165	//dump, err = NeighList(dummy.Index, 0)
166	//if err != nil {
167	//t.Errorf("Failed to NeighList: %v", err)
168	//}
169
170	//for _, entry := range arpTable {
171	//if dumpContains(dump, entry) {
172	//t.Errorf("Dump contains: %v", entry)
173	//}
174	//}
175
176	if err := LinkDel(&dummy); err != nil {
177		t.Fatal(err)
178	}
179}
180
181func TestNeighAddDelProxy(t *testing.T) {
182	tearDown := setUpNetlinkTest(t)
183	defer tearDown()
184
185	dummy := Dummy{LinkAttrs{Name: "neigh0"}}
186	if err := LinkAdd(&dummy); err != nil {
187		t.Fatal(err)
188	}
189
190	ensureIndex(dummy.Attrs())
191
192	proxyTable := []proxyEntry{
193		{net.ParseIP("10.99.0.1"), dummy.Index},
194		{net.ParseIP("10.99.0.2"), dummy.Index},
195		{net.ParseIP("10.99.0.3"), dummy.Index},
196		{net.ParseIP("10.99.0.4"), dummy.Index},
197		{net.ParseIP("10.99.0.5"), dummy.Index},
198	}
199
200	// Add the proxyTable
201	for _, entry := range proxyTable {
202		err := NeighAdd(&Neigh{
203			LinkIndex: dummy.Index,
204			Flags:     NTF_PROXY,
205			IP:        entry.ip,
206		})
207
208		if err != nil {
209			t.Errorf("Failed to NeighAdd: %v", err)
210		}
211	}
212
213	// Dump and see that all added entries are there
214	dump, err := NeighProxyList(dummy.Index, 0)
215	if err != nil {
216		t.Errorf("Failed to NeighList: %v", err)
217	}
218
219	for _, entry := range proxyTable {
220		if !dumpContainsProxy(dump, entry) {
221			t.Errorf("Dump does not contain: %v", entry)
222		}
223	}
224
225	// Delete the proxyTable
226	for _, entry := range proxyTable {
227		err := NeighDel(&Neigh{
228			LinkIndex: dummy.Index,
229			Flags:     NTF_PROXY,
230			IP:        entry.ip,
231		})
232
233		if err != nil {
234			t.Errorf("Failed to NeighDel: %v", err)
235		}
236	}
237
238	// Dump and see that none of deleted entries are there
239	dump, err = NeighProxyList(dummy.Index, 0)
240	if err != nil {
241		t.Errorf("Failed to NeighList: %v", err)
242	}
243
244	for _, entry := range proxyTable {
245		if dumpContainsProxy(dump, entry) {
246			t.Errorf("Dump contains: %v", entry)
247		}
248	}
249
250	if err := LinkDel(&dummy); err != nil {
251		t.Fatal(err)
252	}
253}
254