xref: /openbsd-src/usr.sbin/tcpdump/print-ofp.c (revision 5e3c7963eb248119b7dfd4b0defad58a7d9cd306)
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 }
1254