GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tcpdump/print-ofp.c Lines: 0 569 0.0 %
Date: 2017-11-13 Branches: 0 284 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: print-ofp.c,v 1.11 2016/11/28 17:47:15 jca Exp $	*/
2
3
/*
4
 * Copyright (c) 2016 Rafael Zalamena <rzalamena@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <net/ofp.h>
20
21
#include <endian.h>
22
#include <stddef.h>
23
#include <stdio.h>
24
#include <string.h>
25
#include <pcap.h>
26
27
#include "addrtoname.h"
28
#include "extract.h"
29
#include "interface.h"
30
#include "ofp_map.h"
31
32
/* Size of action header without the padding. */
33
#define AH_UNPADDED	(offsetof(struct ofp_action_header, ah_pad))
34
35
const char *
36
	 print_map(unsigned int, struct constmap *);
37
38
void	 ofp_print_hello(const u_char *, u_int, u_int);
39
void	 ofp_print_featuresreply(const u_char *, u_int);
40
void	 ofp_print_setconfig(const u_char *, u_int);
41
void	 ofp_print_packetin(const u_char *, u_int);
42
void	 ofp_print_packetout(const u_char *, u_int);
43
void	 ofp_print_flowremoved(const u_char *, u_int);
44
void	 ofp_print_flowmod(const u_char *, u_int);
45
46
void	 oxm_print_halfword(const u_char *, u_int, int, int);
47
void	 oxm_print_word(const u_char *, u_int, int, int);
48
void	 oxm_print_quad(const u_char *, u_int, int, int);
49
void	 oxm_print_ether(const u_char *, u_int, int);
50
void	 ofp_print_oxm(struct ofp_ox_match *, const u_char *, u_int);
51
52
void	 action_print_output(const u_char *, u_int);
53
void	 action_print_group(const u_char *, u_int);
54
void	 action_print_setqueue(const u_char *, u_int);
55
void	 action_print_setmplsttl(const u_char *, u_int);
56
void	 action_print_setnwttl(const u_char *, u_int);
57
void	 action_print_push(const u_char *, u_int);
58
void	 action_print_popmpls(const u_char *, u_int);
59
void	 action_print_setfield(const u_char *, u_int);
60
void	 ofp_print_action(struct ofp_action_header *, const u_char *,
61
	    u_int);
62
63
void	 instruction_print_gototable(const char *, u_int);
64
void	 instruction_print_meta(const char *, u_int);
65
void	 instruction_print_actions(const char *, u_int);
66
void	 instruction_print_meter(const char *, u_int);
67
void	 instruction_print_experimenter(const char *, u_int);
68
void	 ofp_print_instruction(struct ofp_instruction *, const char *, u_int);
69
70
const char *
71
print_map(unsigned int type, struct constmap *map)
72
{
73
	unsigned int		 i;
74
#define CYCLE_BUFFERS		 8
75
	static char		 buf[CYCLE_BUFFERS][32];
76
	static int		 idx = 0;
77
	const char		*name = NULL;
78
79
	if (idx >= CYCLE_BUFFERS)
80
		idx = 0;
81
	memset(buf[idx], 0, sizeof(buf[idx]));
82
83
	for (i = 0; map[i].cm_name != NULL; i++) {
84
		if (map[i].cm_type == type) {
85
			name = map[i].cm_name;
86
			break;
87
		}
88
	}
89
90
	if (name == NULL)
91
		snprintf(buf[idx], sizeof(buf[idx]), "%u", type);
92
	else if (vflag > 1)
93
		snprintf(buf[idx], sizeof(buf[idx]), "%s[%u]", name, type);
94
	else
95
		strlcpy(buf[idx], name, sizeof(buf[idx]));
96
97
	return (buf[idx++]);
98
}
99
100
void
101
ofp_print_hello(const u_char *bp, u_int length, u_int ohlen)
102
{
103
	struct ofp_hello_element_header		*he;
104
	int					 hetype, helen, ver, i;
105
	int					 vmajor, vminor;
106
	uint32_t				 bmp;
107
108
	/* Skip the OFP header. */
109
	bp += sizeof(struct ofp_header);
110
	length -= sizeof(struct ofp_header);
111
112
	/* Check for header truncation. */
113
	if (ohlen > sizeof(struct ofp_header) &&
114
	    length < sizeof(*he)) {
115
		printf(" [|OpenFlow]");
116
		return;
117
	}
118
119
 next_header:
120
	/* Check for hello element headers. */
121
	if (length < sizeof(*he))
122
		return;
123
124
	he = (struct ofp_hello_element_header *)bp;
125
	hetype = ntohs(he->he_type);
126
	helen = ntohs(he->he_length);
127
128
	bp += sizeof(*he);
129
	length -= sizeof(*he);
130
	helen -= sizeof(*he);
131
132
	switch (hetype) {
133
	case OFP_HELLO_T_VERSION_BITMAP:
134
		printf(" version bitmap <");
135
		if (helen < sizeof(bmp)) {
136
			printf("invalid header>");
137
			break;
138
		}
139
140
 next_bitmap:
141
		if (length < sizeof(bmp)) {
142
			printf("[|OpenFlow]>");
143
			break;
144
		}
145
146
		bmp = ntohl(*(uint32_t *)bp);
147
		for (i = 0, ver = 9; i < 32; i++, ver++) {
148
			if ((bmp & (1 << i)) == 0)
149
				continue;
150
151
			vmajor = (ver / 10);
152
			vminor = ver % 10;
153
			printf("v%d.%d ", vmajor, vminor);
154
		}
155
		helen -= min(sizeof(bmp), helen);
156
		length -= sizeof(bmp);
157
		bp += sizeof(bmp);
158
		if (helen)
159
			goto next_bitmap;
160
161
		printf("\b>");
162
		break;
163
164
	default:
165
		printf(" element header[type %d length %d]", hetype, helen);
166
		break;
167
	}
168
169
	length -= min(helen, length);
170
	bp += helen;
171
	if (length)
172
		goto next_header;
173
}
174
175
void
176
ofp_print_error(const u_char *bp, u_int length)
177
{
178
	struct ofp_error			*err;
179
180
	if (length < sizeof(*err)) {
181
		printf(" [|OpenFlow]");
182
		return;
183
	}
184
185
	err = (struct ofp_error *)bp;
186
	printf(" <type %s code %d>",
187
	    print_map(ntohs(err->err_type), ofp_errtype_map),
188
	    ntohs(err->err_code));
189
190
	length -= min(sizeof(*err), length);
191
	bp += sizeof(*err);
192
	/* If there are still bytes left, print the optional error data. */
193
	if (length) {
194
		printf(" error data");
195
		ofp_print(bp, length);
196
	}
197
}
198
199
void
200
ofp_print_featuresreply(const u_char *bp, u_int length)
201
{
202
	struct ofp_switch_features		*swf;
203
204
	if (length < sizeof(*swf)) {
205
		printf(" [trucanted]");
206
		return;
207
	}
208
209
	swf = (struct ofp_switch_features *)bp;
210
	printf(" <datapath_id %#016llx nbuffers %u ntables %d aux_id %d "
211
	    "capabilities %#08x>",
212
	    be64toh(swf->swf_datapath_id), ntohl(swf->swf_nbuffers),
213
	    swf->swf_ntables, swf->swf_aux_id,
214
	    ntohl(swf->swf_capabilities));
215
}
216
217
void
218
ofp_print_setconfig(const u_char *bp, u_int length)
219
{
220
	struct ofp_switch_config		*cfg;
221
222
	if (length < sizeof(*cfg)) {
223
		printf(" [|OpenFlow]");
224
		return;
225
	}
226
227
	cfg = (struct ofp_switch_config *)bp;
228
	printf(" <flags %#04x miss_send_len %s>",
229
	    ntohs(cfg->cfg_flags),
230
	    print_map(ntohs(cfg->cfg_miss_send_len),
231
	    ofp_controller_maxlen_map));
232
}
233
234
void
235
ofp_print_packetin(const u_char *bp, u_int length)
236
{
237
	struct ofp_packet_in		*pin;
238
	struct ofp_ox_match		*oxm;
239
	int				 omtype, omlen;
240
	int				 haspacket = 0;
241
	const u_char			*pktptr;
242
243
	if (length < sizeof(*pin)) {
244
		printf(" [|OpenFlow]");
245
		return;
246
	}
247
248
	pin = (struct ofp_packet_in *)bp;
249
	omtype = ntohs(pin->pin_match.om_type);
250
	omlen = ntohs(pin->pin_match.om_length);
251
	printf(" <buffer_id %s total_len %d reason %s table_id %s "
252
	    "cookie %#016llx match type %s length %d>",
253
	    print_map(ntohl(pin->pin_buffer_id), ofp_pktout_map),
254
	    ntohs(pin->pin_total_len),
255
	    print_map(pin->pin_reason, ofp_pktin_reason_map),
256
	    print_map(pin->pin_table_id, ofp_table_id_map),
257
	    be64toh(pin->pin_cookie),
258
	    print_map(omtype, ofp_match_map), omlen);
259
260
	if (pin->pin_buffer_id == OFP_PKTOUT_NO_BUFFER)
261
		haspacket = 1;
262
263
	/* We only support OXM. */
264
	if (omtype != OFP_MATCH_OXM)
265
		return;
266
267
	bp += sizeof(*pin);
268
	length -= sizeof(*pin);
269
270
	/* Get packet start address. */
271
	pktptr = (bp - sizeof(pin->pin_match)) +
272
	    OFP_ALIGN(omlen) + ETHER_ALIGN;
273
274
	/* Don't count the header for the OXM fields. */
275
	omlen -= min(sizeof(pin->pin_match), omlen);
276
	if (omlen == 0)
277
		goto print_packet;
278
279
 parse_next_oxm:
280
	if (length < sizeof(*oxm)) {
281
		printf(" [|OpenFlow]");
282
		return;
283
	}
284
285
	oxm = (struct ofp_ox_match *)bp;
286
	bp += sizeof(*oxm);
287
	length -= sizeof(*oxm);
288
	if (length < oxm->oxm_length) {
289
		printf(" [|OpenFlow]");
290
		return;
291
	}
292
293
	ofp_print_oxm(oxm, bp, length);
294
295
	bp += oxm->oxm_length;
296
	length -= oxm->oxm_length;
297
	omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen);
298
	if (omlen)
299
		goto parse_next_oxm;
300
301
 print_packet:
302
	if (haspacket == 0)
303
		return;
304
305
	/*
306
	 * Recalculate length:
307
	 * pktptr skipped the omlen + padding and the ETHER_ALIGN, so
308
	 * instead of keeping track of that we just recalculate length
309
	 * using the encapsulated packet begin and snapend.
310
	 */
311
	length = max(snapend - pktptr, 0);
312
	if (length < ETHER_ADDR_LEN) {
313
		printf(" [|ether]");
314
		return;
315
	}
316
317
	printf(" ");
318
	ether_tryprint(pktptr, length, 0);
319
}
320
321
void
322
ofp_print_flowremoved(const u_char *bp, u_int length)
323
{
324
	struct ofp_flow_removed			*fr;
325
	struct ofp_ox_match			*oxm;
326
	int					 omtype, omlen;
327
328
	if (length < sizeof(*fr)) {
329
		printf(" [|OpenFlow]");
330
		return;
331
	}
332
333
	fr = (struct ofp_flow_removed *)bp;
334
	omtype = ntohs(fr->fr_match.om_type);
335
	omlen = ntohs(fr->fr_match.om_length);
336
	printf(" <cookie %#016llx priority %d reason %s table_id %s "
337
	    "duration sec %u nsec %u timeout idle %d hard %d "
338
	    "packet count %llu byte count %llu match type %s length %d>",
339
	    be64toh(fr->fr_cookie), ntohs(fr->fr_priority),
340
	    print_map(fr->fr_reason, ofp_flowrem_reason_map),
341
	    print_map(fr->fr_table_id, ofp_table_id_map),
342
	    ntohl(fr->fr_duration_sec), ntohl(fr->fr_duration_nsec),
343
	    ntohs(fr->fr_idle_timeout), ntohs(fr->fr_hard_timeout),
344
	    be64toh(fr->fr_packet_count), be64toh(fr->fr_byte_count),
345
	    print_map(omtype, ofp_match_map), omlen);
346
347
	/* We only support OXM. */
348
	if (omtype != OFP_MATCH_OXM)
349
		return;
350
351
	omlen -= min(sizeof(fr->fr_match), omlen);
352
	if (omlen == 0)
353
		return;
354
355
	bp += sizeof(*fr);
356
	length -= sizeof(*fr);
357
358
 parse_next_oxm:
359
	if (length < sizeof(*oxm)) {
360
		printf(" [|OpenFlow]");
361
		return;
362
	}
363
364
	oxm = (struct ofp_ox_match *)bp;
365
	bp += sizeof(*oxm);
366
	length -= sizeof(*oxm);
367
	if (length < oxm->oxm_length) {
368
		printf(" [|OpenFlow]");
369
		return;
370
	}
371
372
	ofp_print_oxm(oxm, bp, length);
373
374
	bp += oxm->oxm_length;
375
	length -= oxm->oxm_length;
376
	omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen);
377
	if (omlen)
378
		goto parse_next_oxm;
379
}
380
381
void
382
ofp_print_packetout(const u_char *bp, u_int length)
383
{
384
	struct ofp_packet_out			*pout;
385
	struct ofp_action_header		*ah;
386
	const u_char				*pktptr;
387
	int					 actionslen, haspacket = 0;
388
	int					 ahlen;
389
390
	if (length < sizeof(*pout)) {
391
		printf(" [|OpenFlow]");
392
		return;
393
	}
394
395
	pout = (struct ofp_packet_out *)bp;
396
	actionslen = ntohs(pout->pout_actions_len);
397
	printf(" <buffer_id %s in_port %s actions_len %d>",
398
	    print_map(ntohl(pout->pout_buffer_id), ofp_pktout_map),
399
	    print_map(ntohl(pout->pout_in_port), ofp_port_map),
400
	    actionslen);
401
402
	if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER)
403
		haspacket = 1;
404
405
	bp += sizeof(*pout);
406
	length -= sizeof(*pout);
407
	pktptr = bp + actionslen;
408
409
	/* No actions or unpadded header. */
410
	if (actionslen < sizeof(*ah))
411
		goto print_packet;
412
413
 parse_next_action:
414
	if (length < sizeof(*ah)) {
415
		printf(" [|OpenFlow]");
416
		return;
417
	}
418
419
	ah = (struct ofp_action_header *)bp;
420
	bp += AH_UNPADDED;
421
	length -= AH_UNPADDED;
422
	actionslen -= AH_UNPADDED;
423
	ahlen = ntohs(ah->ah_len) - AH_UNPADDED;
424
	if (length < ahlen) {
425
		printf(" [|OpenFlow]");
426
		return;
427
	}
428
429
	ofp_print_action(ah, bp, length);
430
431
	bp += ahlen;
432
	length -= ahlen;
433
	actionslen -= min(ahlen, actionslen);
434
	if (actionslen)
435
		goto parse_next_action;
436
437
 print_packet:
438
	if (haspacket == 0)
439
		return;
440
441
	/* Recalculate length using packet boundaries. */
442
	length = max(snapend - pktptr, 0);
443
	if (length < ETHER_ADDR_LEN) {
444
		printf(" [|ether]");
445
		return;
446
	}
447
448
	printf(" ");
449
	ether_tryprint(pktptr, length, 0);
450
}
451
452
void
453
ofp_print_flowmod(const u_char *bp, u_int length)
454
{
455
	struct ofp_flow_mod			*fm;
456
	struct ofp_ox_match			*oxm;
457
	struct ofp_instruction			*i;
458
	int					 omtype, omlen, ilen;
459
	int					 instructionslen, padsize;
460
461
	if (length < sizeof(*fm)) {
462
		printf(" [|OpenFlow]");
463
		return;
464
	}
465
466
	fm = (struct ofp_flow_mod *)bp;
467
	omtype = ntohs(fm->fm_match.om_type);
468
	omlen = ntohs(fm->fm_match.om_length);
469
	printf(" <cookie %llu cookie_mask %#016llx table_id %s command %s "
470
	    "timeout idle %d hard %d priority %d buffer_id %s out_port %s "
471
	    "out_group %s flags %#04x match type %s length %d>",
472
	    be64toh(fm->fm_cookie), be64toh(fm->fm_cookie_mask),
473
	    print_map(fm->fm_table_id, ofp_table_id_map),
474
	    print_map(fm->fm_command, ofp_flowcmd_map),
475
	    ntohs(fm->fm_idle_timeout), ntohs(fm->fm_hard_timeout),
476
	    fm->fm_priority,
477
	    print_map(ntohl(fm->fm_buffer_id), ofp_pktout_map),
478
	    print_map(ntohl(fm->fm_out_port), ofp_port_map),
479
	    print_map(ntohl(fm->fm_out_group), ofp_group_id_map),
480
	    ntohs(fm->fm_flags),
481
	    print_map(omtype, ofp_match_map), omlen);
482
483
	bp += sizeof(*fm);
484
	length -= sizeof(*fm);
485
486
	padsize = OFP_ALIGN(omlen) - omlen;
487
	omlen -= min(sizeof(fm->fm_match), omlen);
488
	instructionslen = length - (omlen + padsize);
489
	if (omtype != OFP_MATCH_OXM || omlen == 0) {
490
		if (instructionslen <= 0)
491
			return;
492
493
		/* Skip padding if any. */
494
		if (padsize) {
495
			bp += padsize;
496
			length -= padsize;
497
		}
498
		goto parse_next_instruction;
499
	}
500
501
 parse_next_oxm:
502
	if (length < sizeof(*oxm)) {
503
		printf(" [|OpenFlow]");
504
		return;
505
	}
506
507
	oxm = (struct ofp_ox_match *)bp;
508
	bp += sizeof(*oxm);
509
	length -= sizeof(*oxm);
510
	if (length < oxm->oxm_length) {
511
		printf(" [|OpenFlow]");
512
		return;
513
	}
514
515
	ofp_print_oxm(oxm, bp, length);
516
517
	bp += oxm->oxm_length;
518
	length -= oxm->oxm_length;
519
	omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen);
520
	if (omlen)
521
		goto parse_next_oxm;
522
523
	/* Skip padding if any. */
524
	if (padsize) {
525
		bp += padsize;
526
		length -= padsize;
527
	}
528
529
parse_next_instruction:
530
	if (length < sizeof(*i)) {
531
		printf(" [|OpenFlow]");
532
		return;
533
	}
534
535
	i = (struct ofp_instruction *)bp;
536
	bp += sizeof(*i);
537
	length -= sizeof(*i);
538
	instructionslen -= sizeof(*i);
539
	ilen = ntohs(i->i_len) - sizeof(*i);
540
	if (length < ilen) {
541
		printf(" [|OpenFlow]");
542
		return;
543
	}
544
545
	ofp_print_instruction(i, bp, length);
546
547
	bp += ilen;
548
	length -= ilen;
549
	instructionslen -= ilen;
550
	if (instructionslen > 0)
551
		goto parse_next_instruction;
552
}
553
554
void
555
ofp_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
556
{
557
	struct dlt_openflow_hdr	 of;
558
	unsigned int		 length;
559
560
	ts_print(&h->ts);
561
562
	packetp = p;
563
	snapend = p + h->caplen;
564
	length = snapend - p;
565
566
	TCHECK2(*p, sizeof(of));
567
	memcpy(&of, p, sizeof(of));
568
569
	if (ntohl(of.of_direction) == DLT_OPENFLOW_TO_SWITCH)
570
		printf("controller -> %s", device);
571
	else
572
		printf("%s -> controller", device);
573
	if (eflag)
574
		printf(", datapath %#016llx", be64toh(of.of_datapath_id));
575
576
	ofp_print(p + sizeof(of), length - sizeof(of));
577
	goto out;
578
579
 trunc:
580
	printf("[|OpenFlow]");
581
582
 out:
583
	if (xflag)
584
		default_print(p, (u_int)h->len);
585
	putchar('\n');
586
}
587
588
void
589
ofp_print(const u_char *bp, u_int length)
590
{
591
	struct ofp_header	*oh;
592
	unsigned int		 ohlen, snaplen;
593
594
	/* The captured data might be smaller than indicated */
595
	snaplen = snapend - bp;
596
	length = min(snaplen, length);
597
	if (length < sizeof(*oh)) {
598
		printf("[|OpenFlow]");
599
		return;
600
	}
601
602
	oh = (struct ofp_header *)bp;
603
	ohlen = ntohs(oh->oh_length);
604
605
	printf(": OpenFlow %s type %u length %u xid %u",
606
	    print_map(oh->oh_version, ofp_v_map),
607
	    oh->oh_type, ntohs(oh->oh_length), ntohl(oh->oh_xid));
608
609
	switch (oh->oh_version) {
610
	case OFP_V_1_3:
611
		break;
612
613
	default:
614
		return;
615
	}
616
617
	printf(": %s", print_map(oh->oh_type, ofp_t_map));
618
619
	switch (oh->oh_type) {
620
	case OFP_T_HELLO:
621
		ofp_print_hello(bp, length, ohlen);
622
		break;
623
	case OFP_T_ERROR:
624
		ofp_print_error(bp, length);
625
		break;
626
	case OFP_T_ECHO_REQUEST:
627
	case OFP_T_ECHO_REPLY:
628
		break;
629
	case OFP_T_FEATURES_REQUEST:
630
		break;
631
	case OFP_T_FEATURES_REPLY:
632
		ofp_print_featuresreply(bp, length);
633
		break;
634
	case OFP_T_SET_CONFIG:
635
		ofp_print_setconfig(bp, length);
636
		break;
637
	case OFP_T_PACKET_IN:
638
		ofp_print_packetin(bp, length);
639
		break;
640
	case OFP_T_FLOW_REMOVED:
641
		ofp_print_flowremoved(bp, length);
642
		break;
643
	case OFP_T_PACKET_OUT:
644
		ofp_print_packetout(bp, length);
645
		break;
646
	case OFP_T_FLOW_MOD:
647
		ofp_print_flowmod(bp, length);
648
		break;
649
	}
650
}
651
652
void
653
oxm_print_byte(const u_char *bp, u_int length, int hasmask, int hex)
654
{
655
	uint8_t		*b;
656
657
	if (length < sizeof(*b)) {
658
		printf("[|OpenFlow]");
659
		return;
660
	}
661
662
	b = (uint8_t *)bp;
663
	if (hex)
664
		printf("%#02x", ntohs(*b));
665
	else
666
		printf("%u", ntohs(*b));
667
668
	if (hasmask) {
669
		bp += sizeof(*b);
670
		length -= sizeof(*b);
671
		printf(" mask ");
672
		oxm_print_byte(bp, length, 0, 1);
673
	}
674
}
675
676
void
677
oxm_print_halfword(const u_char *bp, u_int length, int hasmask, int hex)
678
{
679
	uint16_t	*h;
680
681
	if (length < sizeof(*h)) {
682
		printf("[|OpenFlow]");
683
		return;
684
	}
685
686
	h = (uint16_t *)bp;
687
	if (hex)
688
		printf("%#04x", ntohs(*h));
689
	else
690
		printf("%u", ntohs(*h));
691
692
	if (hasmask) {
693
		bp += sizeof(*h);
694
		length -= sizeof(*h);
695
		printf(" mask ");
696
		oxm_print_halfword(bp, length, 0, 1);
697
	}
698
}
699
700
void
701
oxm_print_word(const u_char *bp, u_int length, int hasmask, int hex)
702
{
703
	uint32_t	*w;
704
705
	if (length < sizeof(*w)) {
706
		printf("[|OpenFlow]");
707
		return;
708
	}
709
710
	w = (uint32_t *)bp;
711
	if (hex)
712
		printf("%#08x", ntohl(*w));
713
	else
714
		printf("%u", ntohl(*w));
715
716
	if (hasmask) {
717
		bp += sizeof(*w);
718
		length -= sizeof(*w);
719
		printf(" mask ");
720
		oxm_print_word(bp, length, 0, 1);
721
	}
722
}
723
724
void
725
oxm_print_quad(const u_char *bp, u_int length, int hasmask, int hex)
726
{
727
	uint64_t	*q;
728
729
	if (length < sizeof(*q)) {
730
		printf("[|OpenFlow]");
731
		return;
732
	}
733
734
	q = (uint64_t *)bp;
735
	if (hex)
736
		printf("%#016llx", be64toh(*q));
737
	else
738
		printf("%llu", be64toh(*q));
739
740
	if (hasmask) {
741
		bp += sizeof(*q);
742
		length -= sizeof(*q);
743
		printf(" mask ");
744
		oxm_print_quad(bp, length, 0, 1);
745
	}
746
}
747
748
void
749
oxm_print_ether(const u_char *bp, u_int length, int hasmask)
750
{
751
	if (length < ETHER_HDR_LEN) {
752
		printf("[|OpenFlow]");
753
		return;
754
	}
755
756
	printf("%s", etheraddr_string(bp));
757
758
	if (hasmask) {
759
		bp += ETHER_ADDR_LEN;
760
		length -= ETHER_ADDR_LEN;
761
		printf(" mask ");
762
		oxm_print_ether(bp, length, 0);
763
	}
764
}
765
766
void
767
oxm_print_data(const u_char *bp, u_int length, int hasmask, size_t datalen)
768
{
769
	uint8_t		*ptr;
770
	int		 i;
771
	char		 hex[8];
772
773
	if (length < datalen) {
774
		printf("[|OpenFlow]");
775
		return;
776
	}
777
778
	ptr = (uint8_t *)bp;
779
	for (i = 0; i < datalen; i++) {
780
		snprintf(hex, sizeof(hex), "%02x", ptr[i]);
781
		printf("%s", hex);
782
	}
783
784
	if (hasmask) {
785
		bp += datalen;
786
		length -= datalen;
787
		printf(" mask ");
788
		oxm_print_data(bp, length, 0, datalen);
789
	}
790
}
791
792
void
793
ofp_print_oxm(struct ofp_ox_match *oxm, const u_char *bp, u_int length)
794
{
795
	int				 class, field, mask, len;
796
	uint16_t			*vlan;
797
798
	class = ntohs(oxm->oxm_class);
799
	field = OFP_OXM_GET_FIELD(oxm);
800
	mask = OFP_OXM_GET_HASMASK(oxm);
801
	len = oxm->oxm_length;
802
	printf(" oxm <class %s field %s hasmask %d length %d",
803
	    print_map(class, ofp_oxm_c_map),
804
	    print_map(field, ofp_xm_t_map), mask, len);
805
806
	switch (class) {
807
	case OFP_OXM_C_OPENFLOW_BASIC:
808
		break;
809
810
	case OFP_OXM_C_NXM_0:
811
	case OFP_OXM_C_NXM_1:
812
	case OFP_OXM_C_OPENFLOW_EXPERIMENTER:
813
	default:
814
		printf(">");
815
		return;
816
	}
817
818
	printf(" value ");
819
820
	switch (field) {
821
	case OFP_XM_T_IN_PORT:
822
	case OFP_XM_T_IN_PHY_PORT:
823
	case OFP_XM_T_MPLS_LABEL:
824
		oxm_print_word(bp, length, mask, 0);
825
		break;
826
827
	case OFP_XM_T_META:
828
	case OFP_XM_T_TUNNEL_ID:
829
		oxm_print_quad(bp, length, mask, 1);
830
		break;
831
832
	case OFP_XM_T_ETH_DST:
833
	case OFP_XM_T_ETH_SRC:
834
	case OFP_XM_T_ARP_SHA:
835
	case OFP_XM_T_ARP_THA:
836
	case OFP_XM_T_IPV6_ND_SLL:
837
	case OFP_XM_T_IPV6_ND_TLL:
838
		oxm_print_ether(bp, length, mask);
839
		break;
840
841
	case OFP_XM_T_ETH_TYPE:
842
		oxm_print_halfword(bp, length, mask, 1);
843
		break;
844
845
	case OFP_XM_T_VLAN_VID:
846
		/*
847
		 * VLAN has an exception: it uses the higher bits to signal
848
		 * the presence of the VLAN.
849
		 */
850
		if (length < sizeof(*vlan)) {
851
			printf("[|OpenFlow]");
852
			break;
853
		}
854
855
		vlan = (uint16_t *)bp;
856
		if (ntohs(*vlan) & OFP_XM_VID_PRESENT)
857
			printf("(VLAN %d) ",
858
			    ntohs(*vlan) & (~OFP_XM_VID_PRESENT));
859
		else
860
			printf("(no VLAN) ");
861
		/* FALLTHROUGH */
862
	case OFP_XM_T_TCP_SRC:
863
	case OFP_XM_T_TCP_DST:
864
	case OFP_XM_T_UDP_SRC:
865
	case OFP_XM_T_UDP_DST:
866
	case OFP_XM_T_SCTP_SRC:
867
	case OFP_XM_T_SCTP_DST:
868
	case OFP_XM_T_ARP_OP:
869
	case OFP_XM_T_IPV6_EXTHDR:
870
		oxm_print_halfword(bp, length, mask, 0);
871
		break;
872
873
	case OFP_XM_T_VLAN_PCP:
874
	case OFP_XM_T_IP_DSCP:
875
	case OFP_XM_T_IP_ECN:
876
	case OFP_XM_T_MPLS_TC:
877
	case OFP_XM_T_MPLS_BOS:
878
		oxm_print_byte(bp, length, mask, 1);
879
		break;
880
881
	case OFP_XM_T_IPV4_SRC:
882
	case OFP_XM_T_IPV4_DST:
883
	case OFP_XM_T_ARP_SPA:
884
	case OFP_XM_T_ARP_TPA:
885
	case OFP_XM_T_IPV6_FLABEL:
886
		oxm_print_word(bp, length, mask, 1);
887
		break;
888
889
	case OFP_XM_T_IP_PROTO:
890
	case OFP_XM_T_ICMPV4_TYPE:
891
	case OFP_XM_T_ICMPV4_CODE:
892
	case OFP_XM_T_ICMPV6_TYPE:
893
	case OFP_XM_T_ICMPV6_CODE:
894
		oxm_print_byte(bp, length, mask, 0);
895
		break;
896
897
	case OFP_XM_T_IPV6_SRC:
898
	case OFP_XM_T_IPV6_DST:
899
	case OFP_XM_T_IPV6_ND_TARGET:
900
		oxm_print_data(bp, length, mask, sizeof(struct in6_addr));
901
		break;
902
903
	case OFP_XM_T_PBB_ISID:
904
		oxm_print_data(bp, length, mask, 3);
905
		break;
906
907
	default:
908
		printf("unknown");
909
		break;
910
	}
911
912
	printf(">");
913
}
914
915
void
916
action_print_output(const u_char *bp, u_int length)
917
{
918
	struct ofp_action_output		*ao;
919
920
	if (length < (sizeof(*ao) - AH_UNPADDED)) {
921
		printf(" [|OpenFlow]");
922
		return;
923
	}
924
925
	ao = (struct ofp_action_output *)(bp - AH_UNPADDED);
926
	printf(" port %s max_len %s",
927
	    print_map(ntohl(ao->ao_port), ofp_port_map),
928
	    print_map(ntohs(ao->ao_max_len), ofp_controller_maxlen_map));
929
}
930
931
void
932
action_print_group(const u_char *bp, u_int length)
933
{
934
	struct ofp_action_group		*ag;
935
936
	if (length < (sizeof(*ag) - AH_UNPADDED)) {
937
		printf(" [|OpenFlow]");
938
		return;
939
	}
940
941
	ag = (struct ofp_action_group *)(bp - AH_UNPADDED);
942
	printf(" group_id %s",
943
	    print_map(ntohl(ag->ag_group_id), ofp_group_id_map));
944
}
945
946
void
947
action_print_setqueue(const u_char *bp, u_int length)
948
{
949
	struct ofp_action_set_queue	*asq;
950
951
	if (length < (sizeof(*asq) - AH_UNPADDED)) {
952
		printf(" [|OpenFlow]");
953
		return;
954
	}
955
956
	asq = (struct ofp_action_set_queue *)(bp - AH_UNPADDED);
957
	printf(" queue_id %u", ntohl(asq->asq_queue_id));
958
}
959
960
void
961
action_print_setmplsttl(const u_char *bp, u_int length)
962
{
963
	struct ofp_action_mpls_ttl	*amt;
964
965
	if (length < (sizeof(*amt) - AH_UNPADDED)) {
966
		printf(" [|OpenFlow]");
967
		return;
968
	}
969
970
	amt = (struct ofp_action_mpls_ttl *)(bp - AH_UNPADDED);
971
	printf(" ttl %d", amt->amt_ttl);
972
}
973
974
void
975
action_print_setnwttl(const u_char *bp, u_int length)
976
{
977
	struct ofp_action_nw_ttl	*ant;
978
979
	if (length < (sizeof(*ant) - AH_UNPADDED)) {
980
		printf(" [|OpenFlow]");
981
		return;
982
	}
983
984
	ant = (struct ofp_action_nw_ttl *)(bp - AH_UNPADDED);
985
	printf(" ttl %d", ant->ant_ttl);
986
}
987
988
void
989
action_print_push(const u_char *bp, u_int length)
990
{
991
	struct ofp_action_push		*ap;
992
993
	if (length < (sizeof(*ap) - AH_UNPADDED)) {
994
		printf(" [|OpenFlow]");
995
		return;
996
	}
997
998
	ap = (struct ofp_action_push *)(bp - AH_UNPADDED);
999
	printf(" ethertype %#04x", ntohs(ap->ap_ethertype));
1000
}
1001
1002
void
1003
action_print_popmpls(const u_char *bp, u_int length)
1004
{
1005
	struct ofp_action_pop_mpls	*apm;
1006
1007
	if (length < (sizeof(*apm) - AH_UNPADDED)) {
1008
		printf(" [|OpenFlow]");
1009
		return;
1010
	}
1011
1012
	apm = (struct ofp_action_pop_mpls *)(bp - AH_UNPADDED);
1013
	printf(" ethertype %#04x", ntohs(apm->apm_ethertype));
1014
}
1015
1016
void
1017
action_print_setfield(const u_char *bp, u_int length)
1018
{
1019
	struct ofp_action_set_field	*asf;
1020
	struct ofp_ox_match		*oxm;
1021
	int				 omlen;
1022
1023
	if (length < (sizeof(*asf) - AH_UNPADDED)) {
1024
		printf(" [|OpenFlow]");
1025
		return;
1026
	}
1027
1028
	asf = (struct ofp_action_set_field *)(bp - AH_UNPADDED);
1029
	omlen = ntohs(asf->asf_len) - AH_UNPADDED;
1030
	if (omlen == 0)
1031
		return;
1032
1033
 parse_next_oxm:
1034
	if (length < sizeof(*oxm)) {
1035
		printf(" [|OpenFlow]");
1036
		return;
1037
	}
1038
1039
	oxm = (struct ofp_ox_match *)bp;
1040
	bp += sizeof(*oxm);
1041
	length -= sizeof(*oxm);
1042
	if (length < oxm->oxm_length) {
1043
		printf(" [|OpenFlow]");
1044
		return;
1045
	}
1046
1047
	ofp_print_oxm(oxm, bp, length);
1048
1049
	bp += oxm->oxm_length;
1050
	length -= oxm->oxm_length;
1051
	omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen);
1052
	if (omlen)
1053
		goto parse_next_oxm;
1054
}
1055
1056
void
1057
ofp_print_action(struct ofp_action_header *ah, const u_char *bp, u_int length)
1058
{
1059
	int			ahtype;
1060
1061
	ahtype = ntohs(ah->ah_type);
1062
	printf(" action <type %s length %d",
1063
	    print_map(ahtype, ofp_action_map), ntohs(ah->ah_len));
1064
1065
	switch (ahtype) {
1066
	case OFP_ACTION_OUTPUT:
1067
		action_print_output(bp, length);
1068
		break;
1069
1070
	case OFP_ACTION_GROUP:
1071
		action_print_group(bp, length);
1072
		break;
1073
1074
	case OFP_ACTION_SET_QUEUE:
1075
		action_print_setqueue(bp, length);
1076
		break;
1077
1078
	case OFP_ACTION_SET_MPLS_TTL:
1079
		action_print_setmplsttl(bp, length);
1080
		break;
1081
1082
	case OFP_ACTION_SET_NW_TTL:
1083
		action_print_setnwttl(bp, length);
1084
		break;
1085
1086
	case OFP_ACTION_PUSH_VLAN:
1087
	case OFP_ACTION_PUSH_MPLS:
1088
	case OFP_ACTION_PUSH_PBB:
1089
		action_print_push(bp, length);
1090
		break;
1091
1092
	case OFP_ACTION_POP_MPLS:
1093
		action_print_popmpls(bp, length);
1094
		break;
1095
1096
	case OFP_ACTION_SET_FIELD:
1097
		break;
1098
1099
	case OFP_ACTION_COPY_TTL_OUT:
1100
	case OFP_ACTION_COPY_TTL_IN:
1101
	case OFP_ACTION_DEC_NW_TTL:
1102
	case OFP_ACTION_DEC_MPLS_TTL:
1103
	case OFP_ACTION_POP_VLAN:
1104
	case OFP_ACTION_POP_PBB:
1105
	case OFP_ACTION_EXPERIMENTER:
1106
	default:
1107
		/* Generic header, nothing to show here. */
1108
		break;
1109
	}
1110
1111
	printf(">");
1112
}
1113
1114
void
1115
instruction_print_gototable(const char *bp, u_int length)
1116
{
1117
	struct ofp_instruction_goto_table	*igt;
1118
1119
	if (length < (sizeof(*igt) - sizeof(struct ofp_instruction))) {
1120
		printf(" [|OpenFlow]");
1121
		return;
1122
	}
1123
1124
	igt = (struct ofp_instruction_goto_table *)
1125
	    (bp - sizeof(struct ofp_instruction));
1126
	printf(" table_id %d", igt->igt_table_id);
1127
}
1128
1129
void
1130
instruction_print_meta(const char *bp, u_int length)
1131
{
1132
	struct ofp_instruction_write_metadata	*iwm;
1133
1134
	if (length < (sizeof(*iwm) - sizeof(struct ofp_instruction))) {
1135
		printf(" [|OpenFlow]");
1136
		return;
1137
	}
1138
1139
	iwm = (struct ofp_instruction_write_metadata *)
1140
	    (bp - sizeof(struct ofp_instruction));
1141
	printf(" metadata %llu metadata_mask %llu",
1142
	    be64toh(iwm->iwm_metadata), be64toh(iwm->iwm_metadata_mask));
1143
}
1144
1145
void
1146
instruction_print_actions(const char *bp, u_int length)
1147
{
1148
	struct ofp_instruction_actions		*ia;
1149
	struct ofp_action_header		*ah;
1150
	int					 actionslen;
1151
	unsigned int				 ahlen;
1152
1153
	if (length < (sizeof(*ia) - sizeof(struct ofp_instruction))) {
1154
		printf(" [|OpenFlow]");
1155
		return;
1156
	}
1157
1158
	ia = (struct ofp_instruction_actions *)
1159
	    (bp - sizeof(struct ofp_instruction));
1160
1161
	actionslen = ntohs(ia->ia_len) - sizeof(*ia);
1162
	if (actionslen <= 0)
1163
		return;
1164
1165
	bp += sizeof(*ia) - sizeof(struct ofp_instruction);
1166
	length -= sizeof(*ia) - sizeof(struct ofp_instruction);
1167
1168
parse_next_action:
1169
	if (length < sizeof(*ah)) {
1170
		printf(" [|OpenFlow]");
1171
		return;
1172
	}
1173
1174
	ah = (struct ofp_action_header *)bp;
1175
	bp += AH_UNPADDED;
1176
	length -= AH_UNPADDED;
1177
	actionslen -= AH_UNPADDED;
1178
	ahlen = ntohs(ah->ah_len) - AH_UNPADDED;
1179
	if (length < ahlen) {
1180
		printf(" [|OpenFlow]");
1181
		return;
1182
	}
1183
1184
	ofp_print_action(ah, bp, length);
1185
1186
	bp += ahlen;
1187
	length -= ahlen;
1188
	actionslen -= min(ahlen, actionslen);
1189
	if (actionslen)
1190
		goto parse_next_action;
1191
}
1192
1193
void
1194
instruction_print_meter(const char *bp, u_int length)
1195
{
1196
	struct ofp_instruction_meter		*im;
1197
1198
	if (length < (sizeof(*im) - sizeof(struct ofp_instruction))) {
1199
		printf(" [|OpenFlow]");
1200
		return;
1201
	}
1202
1203
	im = (struct ofp_instruction_meter *)
1204
	    (bp - sizeof(struct ofp_instruction));
1205
	printf(" meter_id %u", ntohl(im->im_meter_id));
1206
}
1207
1208
void
1209
instruction_print_experimenter(const char *bp, u_int length)
1210
{
1211
	struct ofp_instruction_experimenter		*ie;
1212
1213
	if (length < (sizeof(*ie) - sizeof(struct ofp_instruction))) {
1214
		printf(" [|OpenFlow]");
1215
		return;
1216
	}
1217
1218
	ie = (struct ofp_instruction_experimenter *)
1219
	    (bp - sizeof(struct ofp_instruction));
1220
	printf(" experimenter %u", ntohl(ie->ie_experimenter));
1221
}
1222
1223
void
1224
ofp_print_instruction(struct ofp_instruction *i, const char *bp, u_int length)
1225
{
1226
	int			itype;
1227
1228
	itype = ntohs(i->i_type);
1229
	printf(" instruction <type %s length %d",
1230
	    print_map(itype, ofp_instruction_t_map), ntohs(i->i_len));
1231
1232
	switch (itype) {
1233
	case OFP_INSTRUCTION_T_GOTO_TABLE:
1234
		instruction_print_gototable(bp, length);
1235
		break;
1236
	case OFP_INSTRUCTION_T_WRITE_META:
1237
		instruction_print_meta(bp, length);
1238
		break;
1239
	case OFP_INSTRUCTION_T_WRITE_ACTIONS:
1240
	case OFP_INSTRUCTION_T_APPLY_ACTIONS:
1241
	case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
1242
		instruction_print_actions(bp, length);
1243
		break;
1244
	case OFP_INSTRUCTION_T_METER:
1245
		instruction_print_meter(bp, length);
1246
		break;
1247
	case OFP_INSTRUCTION_T_EXPERIMENTER:
1248
		instruction_print_meter(bp, length);
1249
		break;
1250
	}
1251
1252
	printf(">");
1253
}