1 package ethernet
2
3 import (
4 "bytes"
5 "io"
6 "net"
7 "reflect"
8 "testing"
9 )
10
11 func TestFrameMarshalBinary(t *testing.T) {
12 tests := []struct {
13 desc string
14 f *Frame
15 b []byte
16 err error
17 }{
18 {
19 desc: "S-VLAN, no C-VLAN",
20 f: &Frame{
21
22 ServiceVLAN: &VLAN{},
23 },
24 err: ErrInvalidVLAN,
25 },
26 {
27 desc: "IPv4, no VLANs",
28 f: &Frame{
29 Destination: net.HardwareAddr{0, 1, 0, 1, 0, 1},
30 Source: net.HardwareAddr{1, 0, 1, 0, 1, 0},
31 EtherType: EtherTypeIPv4,
32 Payload: bytes.Repeat([]byte{0}, 50),
33 },
34 b: append([]byte{
35 0, 1, 0, 1, 0, 1,
36 1, 0, 1, 0, 1, 0,
37 0x08, 0x00,
38 }, bytes.Repeat([]byte{0}, 50)...),
39 },
40 {
41 desc: "IPv6, C-VLAN: (PRI 1, ID 101)",
42 f: &Frame{
43 Destination: net.HardwareAddr{1, 0, 1, 0, 1, 0},
44 Source: net.HardwareAddr{0, 1, 0, 1, 0, 1},
45 VLAN: &VLAN{
46 Priority: 1,
47 ID: 101,
48 },
49 EtherType: EtherTypeIPv6,
50 Payload: bytes.Repeat([]byte{0}, 50),
51 },
52 b: append([]byte{
53 1, 0, 1, 0, 1, 0,
54 0, 1, 0, 1, 0, 1,
55 0x81, 0x00,
56 0x20, 0x65,
57 0x86, 0xDD,
58 }, bytes.Repeat([]byte{0}, 50)...),
59 },
60 {
61 desc: "ARP, S-VLAN: (PRI 0, DROP, ID 100), C-VLAN: (PRI 1, ID 101)",
62 f: &Frame{
63 Destination: Broadcast,
64 Source: net.HardwareAddr{0, 1, 0, 1, 0, 1},
65 ServiceVLAN: &VLAN{
66 DropEligible: true,
67 ID: 100,
68 },
69 VLAN: &VLAN{
70 Priority: 1,
71 ID: 101,
72 },
73 EtherType: EtherTypeARP,
74 Payload: bytes.Repeat([]byte{0}, 50),
75 },
76 b: append([]byte{
77 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
78 0, 1, 0, 1, 0, 1,
79 0x88, 0xa8,
80 0x10, 0x64,
81 0x81, 0x00,
82 0x20, 0x65,
83 0x08, 0x06,
84 }, bytes.Repeat([]byte{0}, 50)...),
85 },
86 }
87
88 for _, tt := range tests {
89 t.Run(tt.desc, func(t *testing.T) {
90 b, err := tt.f.MarshalBinary()
91 if err != nil {
92 if want, got := tt.err, err; want != got {
93 t.Fatalf("unexpected error: %v != %v", want, got)
94 }
95
96 return
97 }
98
99 if want, got := tt.b, b; !bytes.Equal(want, got) {
100 t.Fatalf("unexpected Frame bytes:\n- want: %v\n- got: %v", want, got)
101 }
102 })
103 }
104 }
105
106 func TestFrameMarshalFCS(t *testing.T) {
107 tests := []struct {
108 desc string
109 f *Frame
110 b []byte
111 err error
112 }{
113 {
114 desc: "IPv4, no VLANs",
115 f: &Frame{
116 Destination: net.HardwareAddr{0, 1, 0, 1, 0, 1},
117 Source: net.HardwareAddr{1, 0, 1, 0, 1, 0},
118 EtherType: EtherTypeIPv4,
119 Payload: bytes.Repeat([]byte{0}, 50),
120 },
121 b: append(
122 append(
123 []byte{
124 0, 1, 0, 1, 0, 1,
125 1, 0, 1, 0, 1, 0,
126 0x08, 0x00,
127 },
128 bytes.Repeat([]byte{0}, 50)...,
129 ),
130 []byte{159, 205, 24, 60}...,
131 ),
132 },
133 }
134
135 for _, tt := range tests {
136 t.Run(tt.desc, func(t *testing.T) {
137 b, err := tt.f.MarshalFCS()
138 if err != nil {
139 if want, got := tt.err, err; want != got {
140 t.Fatalf("unexpected error: %v != %v", want, got)
141 }
142
143 return
144 }
145
146 if want, got := tt.b, b; !bytes.Equal(want, got) {
147 t.Fatalf("unexpected Frame bytes:\n- want: %v\n- got: %v", want, got)
148 }
149 })
150 }
151 }
152
153 func TestFrameUnmarshalBinary(t *testing.T) {
154 tests := []struct {
155 desc string
156 b []byte
157 f *Frame
158 err error
159 }{
160 {
161 desc: "nil buffer",
162 err: io.ErrUnexpectedEOF,
163 },
164 {
165 desc: "short buffer",
166 b: bytes.Repeat([]byte{0}, 13),
167 err: io.ErrUnexpectedEOF,
168 },
169 {
170 desc: "1 short S-VLAN",
171 b: []byte{
172 0, 0, 0, 0, 0, 0,
173 0, 0, 0, 0, 0, 0,
174 0x88, 0xa8,
175 0x00,
176 },
177 err: io.ErrUnexpectedEOF,
178 },
179 {
180 desc: "1 short C-VLAN",
181 b: []byte{
182 0, 0, 0, 0, 0, 0,
183 0, 0, 0, 0, 0, 0,
184 0x81, 0x00,
185 0x00,
186 },
187 err: io.ErrUnexpectedEOF,
188 },
189 {
190 desc: "VLAN ID too large",
191 b: []byte{
192 0, 0, 0, 0, 0, 0,
193 0, 0, 0, 0, 0, 0,
194 0x81, 0x00,
195 0xff, 0xff,
196 0x00, 0x00,
197 },
198 err: ErrInvalidVLAN,
199 },
200 {
201 desc: "no C-VLAN after S-VLAN",
202 b: []byte{
203 0, 0, 0, 0, 0, 0,
204 0, 0, 0, 0, 0, 0,
205 0x88, 0xa8,
206 0x20, 0x65,
207 0x08, 0x06,
208 0x00, 0x00, 0x00, 0x00,
209 },
210 err: ErrInvalidVLAN,
211 },
212 {
213 desc: "short C-VLAN after S-VLAN",
214 b: []byte{
215 0, 0, 0, 0, 0, 0,
216 0, 0, 0, 0, 0, 0,
217 0x88, 0xa8,
218 0x20, 0x65,
219 0x81, 0x00,
220 0x00, 0x00,
221 },
222 err: io.ErrUnexpectedEOF,
223 },
224 {
225 desc: "go-fuzz crasher: VLAN tag without enough bytes for trailing EtherType",
226 b: []byte("190734863281\x81\x0032"),
227 err: io.ErrUnexpectedEOF,
228 },
229 {
230 desc: "0 VLANs detected, but 1 may have been present",
231 b: bytes.Repeat([]byte{0}, 56),
232 f: &Frame{
233 Destination: net.HardwareAddr{0, 0, 0, 0, 0, 0},
234 Source: net.HardwareAddr{0, 0, 0, 0, 0, 0},
235 Payload: bytes.Repeat([]byte{0}, 42),
236 },
237 },
238 {
239 desc: "IPv4, no VLANs",
240 b: append([]byte{
241 0, 1, 0, 1, 0, 1,
242 1, 0, 1, 0, 1, 0,
243 0x08, 0x00,
244 }, bytes.Repeat([]byte{0}, 50)...),
245 f: &Frame{
246 Destination: net.HardwareAddr{0, 1, 0, 1, 0, 1},
247 Source: net.HardwareAddr{1, 0, 1, 0, 1, 0},
248 EtherType: EtherTypeIPv4,
249 Payload: bytes.Repeat([]byte{0}, 50),
250 },
251 },
252 {
253 desc: "IPv6, C-VLAN: (PRI 1, ID 101)",
254 b: append([]byte{
255 1, 0, 1, 0, 1, 0,
256 0, 1, 0, 1, 0, 1,
257 0x81, 0x00,
258 0x20, 0x65,
259 0x86, 0xDD,
260 }, bytes.Repeat([]byte{0}, 50)...),
261 f: &Frame{
262 Destination: net.HardwareAddr{1, 0, 1, 0, 1, 0},
263 Source: net.HardwareAddr{0, 1, 0, 1, 0, 1},
264 VLAN: &VLAN{
265 Priority: 1,
266 ID: 101,
267 },
268 EtherType: EtherTypeIPv6,
269 Payload: bytes.Repeat([]byte{0}, 50),
270 },
271 },
272 {
273 desc: "ARP, S-VLAN: (PRI 0, DROP, ID 100), C-VLAN: (PRI 1, ID 101)",
274 b: append([]byte{
275 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
276 0, 1, 0, 1, 0, 1,
277 0x88, 0xa8,
278 0x10, 0x64,
279 0x81, 0x00,
280 0x20, 0x65,
281 0x08, 0x06,
282 }, bytes.Repeat([]byte{0}, 50)...),
283 f: &Frame{
284 Destination: Broadcast,
285 Source: net.HardwareAddr{0, 1, 0, 1, 0, 1},
286 ServiceVLAN: &VLAN{
287 DropEligible: true,
288 ID: 100,
289 },
290 VLAN: &VLAN{
291 Priority: 1,
292 ID: 101,
293 },
294 EtherType: EtherTypeARP,
295 Payload: bytes.Repeat([]byte{0}, 50),
296 },
297 },
298 }
299
300 for _, tt := range tests {
301 t.Run(tt.desc, func(t *testing.T) {
302 f := new(Frame)
303 if err := f.UnmarshalBinary(tt.b); err != nil {
304 if want, got := tt.err, err; want != got {
305 t.Fatalf("unexpected error: %v != %v", want, got)
306 }
307
308 return
309 }
310
311 if want, got := tt.f, f; !reflect.DeepEqual(want, got) {
312 t.Fatalf("unexpected Frame:\n- want: %v\n- got: %v", want, got)
313 }
314 })
315 }
316 }
317
318 func TestFrameUnmarshalFCS(t *testing.T) {
319 tests := []struct {
320 desc string
321 b []byte
322 f *Frame
323 err error
324 }{
325 {
326 desc: "too short for FCS",
327 b: []byte{1, 2, 3},
328 err: io.ErrUnexpectedEOF,
329 },
330 {
331 desc: "invalid FCS",
332 b: []byte{1, 2, 3, 4},
333 err: ErrInvalidFCS,
334 },
335 {
336 desc: "IPv4, no VLANs",
337 b: append(
338 append(
339 []byte{
340 0, 1, 0, 1, 0, 1,
341 1, 0, 1, 0, 1, 0,
342 0x08, 0x00,
343 },
344 bytes.Repeat([]byte{0}, 50)...,
345 ),
346 []byte{159, 205, 24, 60}...,
347 ),
348 f: &Frame{
349 Destination: net.HardwareAddr{0, 1, 0, 1, 0, 1},
350 Source: net.HardwareAddr{1, 0, 1, 0, 1, 0},
351 EtherType: EtherTypeIPv4,
352 Payload: bytes.Repeat([]byte{0}, 50),
353 },
354 },
355 }
356
357 for _, tt := range tests {
358 t.Run(tt.desc, func(t *testing.T) {
359 f := new(Frame)
360 if err := f.UnmarshalFCS(tt.b); err != nil {
361 if want, got := tt.err, err; want != got {
362 t.Fatalf("unexpected error: %v != %v", want, got)
363 }
364
365 return
366 }
367
368 if want, got := tt.f, f; !reflect.DeepEqual(want, got) {
369 t.Fatalf("unexpected Frame:\n- want: %v\n- got: %v", want, got)
370 }
371 })
372 }
373 }
374
375
376
377 func BenchmarkFrameMarshalBinary(b *testing.B) {
378 f := &Frame{
379 Payload: []byte{0, 1, 2, 3, 4},
380 }
381
382 benchmarkFrameMarshalBinary(b, f)
383 }
384
385 func BenchmarkFrameMarshalBinaryCVLAN(b *testing.B) {
386 f := &Frame{
387 VLAN: &VLAN{
388 Priority: PriorityBackground,
389 ID: 10,
390 },
391 Payload: []byte{0, 1, 2, 3, 4},
392 }
393
394 benchmarkFrameMarshalBinary(b, f)
395 }
396
397 func BenchmarkFrameMarshalBinarySVLANCVLAN(b *testing.B) {
398 f := &Frame{
399 ServiceVLAN: &VLAN{
400 Priority: PriorityBackground,
401 ID: 10,
402 },
403 VLAN: &VLAN{
404 Priority: PriorityBestEffort,
405 ID: 20,
406 },
407 Payload: []byte{0, 1, 2, 3, 4},
408 }
409
410 benchmarkFrameMarshalBinary(b, f)
411 }
412
413 func BenchmarkFrameMarshalBinaryJumboPayload(b *testing.B) {
414 f := &Frame{
415 Payload: make([]byte, 8192),
416 }
417
418 benchmarkFrameMarshalBinary(b, f)
419 }
420
421 func benchmarkFrameMarshalBinary(b *testing.B, f *Frame) {
422 f.Destination = net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad}
423 f.Source = net.HardwareAddr{0xad, 0xbe, 0xef, 0xde, 0xad, 0xde}
424
425 b.ResetTimer()
426 b.ReportAllocs()
427 for i := 0; i < b.N; i++ {
428 if _, err := f.MarshalBinary(); err != nil {
429 b.Fatal(err)
430 }
431 }
432 }
433
434
435
436 func BenchmarkFrameMarshalFCS(b *testing.B) {
437 f := &Frame{
438 Payload: []byte{0, 1, 2, 3, 4},
439 }
440
441 benchmarkFrameMarshalFCS(b, f)
442 }
443
444 func benchmarkFrameMarshalFCS(b *testing.B, f *Frame) {
445 f.Destination = net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad}
446 f.Source = net.HardwareAddr{0xad, 0xbe, 0xef, 0xde, 0xad, 0xde}
447
448 b.ResetTimer()
449 b.ReportAllocs()
450 for i := 0; i < b.N; i++ {
451 if _, err := f.MarshalFCS(); err != nil {
452 b.Fatal(err)
453 }
454 }
455 }
456
457
458
459 func BenchmarkFrameUnmarshalBinary(b *testing.B) {
460 f := &Frame{
461 Payload: []byte{0, 1, 2, 3, 4},
462 }
463
464 benchmarkFrameUnmarshalBinary(b, f)
465 }
466
467 func BenchmarkFrameUnmarshalBinaryCVLAN(b *testing.B) {
468 f := &Frame{
469 VLAN: &VLAN{
470 Priority: PriorityBackground,
471 ID: 10,
472 },
473
474 Payload: []byte{0, 1, 2, 3, 4},
475 }
476
477 benchmarkFrameUnmarshalBinary(b, f)
478 }
479
480 func BenchmarkFrameUnmarshalBinarySVLANCVLAN(b *testing.B) {
481 f := &Frame{
482 ServiceVLAN: &VLAN{
483 Priority: PriorityBackground,
484 ID: 10,
485 },
486 VLAN: &VLAN{
487 Priority: PriorityBestEffort,
488 ID: 20,
489 },
490 Payload: []byte{0, 1, 2, 3, 4},
491 }
492
493 benchmarkFrameUnmarshalBinary(b, f)
494 }
495
496 func BenchmarkFrameUnmarshalBinaryJumboPayload(b *testing.B) {
497 f := &Frame{
498 Payload: make([]byte, 8192),
499 }
500
501 benchmarkFrameUnmarshalBinary(b, f)
502 }
503
504 func benchmarkFrameUnmarshalBinary(b *testing.B, f *Frame) {
505 f.Destination = net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad}
506 f.Source = net.HardwareAddr{0xad, 0xbe, 0xef, 0xde, 0xad, 0xde}
507
508 fb, err := f.MarshalBinary()
509 if err != nil {
510 b.Fatal(err)
511 }
512
513 b.ResetTimer()
514 b.ReportAllocs()
515 for i := 0; i < b.N; i++ {
516 if err := f.UnmarshalBinary(fb); err != nil {
517 b.Fatal(err)
518 }
519 }
520 }
521
522
523
524 func BenchmarkFrameUnmarshalFCS(b *testing.B) {
525 f := &Frame{
526 Payload: []byte{0, 1, 2, 3, 4},
527 }
528
529 benchmarkFrameUnmarshalFCS(b, f)
530 }
531
532 func benchmarkFrameUnmarshalFCS(b *testing.B, f *Frame) {
533 f.Destination = net.HardwareAddr{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad}
534 f.Source = net.HardwareAddr{0xad, 0xbe, 0xef, 0xde, 0xad, 0xde}
535
536 fb, err := f.MarshalFCS()
537 if err != nil {
538 b.Fatal(err)
539 }
540
541 b.ResetTimer()
542 b.ReportAllocs()
543 for i := 0; i < b.N; i++ {
544 if err := f.UnmarshalFCS(fb); err != nil {
545 b.Fatal(err)
546 }
547 }
548 }
549
View as plain text