xref: /openbsd/usr.sbin/tcpdump/print-ofp.c (revision c74ea871)
1 /*	$OpenBSD: print-ofp.c,v 1.12 2019/11/27 17:37:32 akoshibe 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 *
print_map(unsigned int type,struct constmap * map)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
ofp_print_hello(const u_char * bp,u_int length,u_int ohlen)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
ofp_print_error(const u_char * bp,u_int length)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
ofp_print_featuresreply(const u_char * bp,u_int length)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
ofp_print_setconfig(const u_char * bp,u_int length)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
ofp_print_oxm_field(const u_char * bp,u_int length,int omlen,int once)235 ofp_print_oxm_field(const u_char *bp, u_int length, int omlen, int once)
236 {
237 	struct ofp_ox_match		*oxm;
238 
239 	do {
240 		if (length < sizeof(*oxm)) {
241 			printf(" [|OpenFlow]");
242 			return;
243 		}
244 
245 		oxm = (struct ofp_ox_match *)bp;
246 		bp += sizeof(*oxm);
247 		length -= sizeof(*oxm);
248 		if (length < oxm->oxm_length) {
249 			printf(" [|OpenFlow]");
250 			return;
251 		}
252 
253 		ofp_print_oxm(oxm, bp, length);
254 		bp += oxm->oxm_length;
255 		length -= oxm->oxm_length;
256 
257 		if (once)
258 			return;
259 
260 		omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen);
261 	} while (omlen > 0);
262 }
263 
264 void
ofp_print_packetin(const u_char * bp,u_int length)265 ofp_print_packetin(const u_char *bp, u_int length)
266 {
267 	struct ofp_packet_in		*pin;
268 	int				 omtype, omlen;
269 	int				 haspacket = 0;
270 	const u_char			*pktptr;
271 
272 	if (length < sizeof(*pin)) {
273 		printf(" [|OpenFlow]");
274 		return;
275 	}
276 
277 	pin = (struct ofp_packet_in *)bp;
278 	omtype = ntohs(pin->pin_match.om_type);
279 	omlen = ntohs(pin->pin_match.om_length);
280 	printf(" <buffer_id %s total_len %d reason %s table_id %s "
281 	    "cookie %#016llx match type %s length %d>",
282 	    print_map(ntohl(pin->pin_buffer_id), ofp_pktout_map),
283 	    ntohs(pin->pin_total_len),
284 	    print_map(pin->pin_reason, ofp_pktin_reason_map),
285 	    print_map(pin->pin_table_id, ofp_table_id_map),
286 	    be64toh(pin->pin_cookie),
287 	    print_map(omtype, ofp_match_map), omlen);
288 
289 	if (pin->pin_buffer_id == OFP_PKTOUT_NO_BUFFER)
290 		haspacket = 1;
291 
292 	/* We only support OXM. */
293 	if (omtype != OFP_MATCH_OXM)
294 		return;
295 
296 	bp += sizeof(*pin);
297 	length -= sizeof(*pin);
298 
299 	/* Get packet start address. */
300 	pktptr = (bp - sizeof(pin->pin_match)) +
301 	    OFP_ALIGN(omlen) + ETHER_ALIGN;
302 
303 	/* Don't count the header for the OXM fields. */
304 	omlen -= min(sizeof(pin->pin_match), omlen);
305 	if (omlen == 0)
306 		goto print_packet;
307 
308 	ofp_print_oxm_field(bp, length, omlen, 0);
309 
310  print_packet:
311 	if (haspacket == 0)
312 		return;
313 
314 	/*
315 	 * Recalculate length:
316 	 * pktptr skipped the omlen + padding and the ETHER_ALIGN, so
317 	 * instead of keeping track of that we just recalculate length
318 	 * using the encapsulated packet begin and snapend.
319 	 */
320 	length = max(snapend - pktptr, 0);
321 	if (length < ETHER_ADDR_LEN) {
322 		printf(" [|ether]");
323 		return;
324 	}
325 
326 	printf(" ");
327 	ether_tryprint(pktptr, length, 0);
328 }
329 
330 void
ofp_print_flowremoved(const u_char * bp,u_int length)331 ofp_print_flowremoved(const u_char *bp, u_int length)
332 {
333 	struct ofp_flow_removed			*fr;
334 	int					 omtype, omlen;
335 
336 	if (length < sizeof(*fr)) {
337 		printf(" [|OpenFlow]");
338 		return;
339 	}
340 
341 	fr = (struct ofp_flow_removed *)bp;
342 	omtype = ntohs(fr->fr_match.om_type);
343 	omlen = ntohs(fr->fr_match.om_length);
344 	printf(" <cookie %#016llx priority %d reason %s table_id %s "
345 	    "duration sec %u nsec %u timeout idle %d hard %d "
346 	    "packet count %llu byte count %llu match type %s length %d>",
347 	    be64toh(fr->fr_cookie), ntohs(fr->fr_priority),
348 	    print_map(fr->fr_reason, ofp_flowrem_reason_map),
349 	    print_map(fr->fr_table_id, ofp_table_id_map),
350 	    ntohl(fr->fr_duration_sec), ntohl(fr->fr_duration_nsec),
351 	    ntohs(fr->fr_idle_timeout), ntohs(fr->fr_hard_timeout),
352 	    be64toh(fr->fr_packet_count), be64toh(fr->fr_byte_count),
353 	    print_map(omtype, ofp_match_map), omlen);
354 
355 	/* We only support OXM. */
356 	if (omtype != OFP_MATCH_OXM)
357 		return;
358 
359 	omlen -= min(sizeof(fr->fr_match), omlen);
360 	if (omlen == 0)
361 		return;
362 
363 	bp += sizeof(*fr);
364 	length -= sizeof(*fr);
365 
366 	ofp_print_oxm_field(bp, length, omlen, 0);
367 }
368 
369 void
ofp_print_packetout(const u_char * bp,u_int length)370 ofp_print_packetout(const u_char *bp, u_int length)
371 {
372 	struct ofp_packet_out			*pout;
373 	struct ofp_action_header		*ah;
374 	const u_char				*pktptr;
375 	int					 actionslen, haspacket = 0;
376 	int					 ahlen;
377 
378 	if (length < sizeof(*pout)) {
379 		printf(" [|OpenFlow]");
380 		return;
381 	}
382 
383 	pout = (struct ofp_packet_out *)bp;
384 	actionslen = ntohs(pout->pout_actions_len);
385 	printf(" <buffer_id %s in_port %s actions_len %d>",
386 	    print_map(ntohl(pout->pout_buffer_id), ofp_pktout_map),
387 	    print_map(ntohl(pout->pout_in_port), ofp_port_map),
388 	    actionslen);
389 
390 	if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER)
391 		haspacket = 1;
392 
393 	bp += sizeof(*pout);
394 	length -= sizeof(*pout);
395 	pktptr = bp + actionslen;
396 
397 	/* No actions or unpadded header. */
398 	if (actionslen < sizeof(*ah))
399 		goto print_packet;
400 
401  parse_next_action:
402 	if (length < sizeof(*ah)) {
403 		printf(" [|OpenFlow]");
404 		return;
405 	}
406 
407 	ah = (struct ofp_action_header *)bp;
408 	bp += AH_UNPADDED;
409 	length -= AH_UNPADDED;
410 	actionslen -= AH_UNPADDED;
411 	ahlen = ntohs(ah->ah_len) - AH_UNPADDED;
412 	if (length < ahlen) {
413 		printf(" [|OpenFlow]");
414 		return;
415 	}
416 
417 	ofp_print_action(ah, bp, length);
418 
419 	bp += ahlen;
420 	length -= ahlen;
421 	actionslen -= min(ahlen, actionslen);
422 	if (actionslen)
423 		goto parse_next_action;
424 
425  print_packet:
426 	if (haspacket == 0)
427 		return;
428 
429 	/* Recalculate length using packet boundaries. */
430 	length = max(snapend - pktptr, 0);
431 	if (length < ETHER_ADDR_LEN) {
432 		printf(" [|ether]");
433 		return;
434 	}
435 
436 	printf(" ");
437 	ether_tryprint(pktptr, length, 0);
438 }
439 
440 void
ofp_print_flowmod(const u_char * bp,u_int length)441 ofp_print_flowmod(const u_char *bp, u_int length)
442 {
443 	struct ofp_flow_mod			*fm;
444 	struct ofp_instruction			*i;
445 	int					 omtype, omlen, ilen;
446 	int					 instructionslen, padsize;
447 
448 	if (length < sizeof(*fm)) {
449 		printf(" [|OpenFlow]");
450 		return;
451 	}
452 
453 	fm = (struct ofp_flow_mod *)bp;
454 	omtype = ntohs(fm->fm_match.om_type);
455 	omlen = ntohs(fm->fm_match.om_length);
456 	printf(" <cookie %llu cookie_mask %#016llx table_id %s command %s "
457 	    "timeout idle %d hard %d priority %d buffer_id %s out_port %s "
458 	    "out_group %s flags %#04x match type %s length %d>",
459 	    be64toh(fm->fm_cookie), be64toh(fm->fm_cookie_mask),
460 	    print_map(fm->fm_table_id, ofp_table_id_map),
461 	    print_map(fm->fm_command, ofp_flowcmd_map),
462 	    ntohs(fm->fm_idle_timeout), ntohs(fm->fm_hard_timeout),
463 	    fm->fm_priority,
464 	    print_map(ntohl(fm->fm_buffer_id), ofp_pktout_map),
465 	    print_map(ntohl(fm->fm_out_port), ofp_port_map),
466 	    print_map(ntohl(fm->fm_out_group), ofp_group_id_map),
467 	    ntohs(fm->fm_flags),
468 	    print_map(omtype, ofp_match_map), omlen);
469 
470 	bp += sizeof(*fm);
471 	length -= sizeof(*fm);
472 
473 	padsize = OFP_ALIGN(omlen) - omlen;
474 	omlen -= min(sizeof(fm->fm_match), omlen);
475 	instructionslen = length - (omlen + padsize);
476 	if (omtype != OFP_MATCH_OXM || omlen == 0) {
477 		if (instructionslen <= 0)
478 			return;
479 
480 		/* Skip padding if any. */
481 		if (padsize) {
482 			bp += padsize;
483 			length -= padsize;
484 		}
485 		goto parse_next_instruction;
486 	}
487 
488 	ofp_print_oxm_field(bp, length, omlen, 0);
489 
490 	bp += omlen;
491 	length -= omlen;
492 
493 	/* Skip padding if any. */
494 	if (padsize) {
495 		bp += padsize;
496 		length -= padsize;
497 	}
498 
499 parse_next_instruction:
500 	if (length < sizeof(*i)) {
501 		printf(" [|OpenFlow]");
502 		return;
503 	}
504 
505 	i = (struct ofp_instruction *)bp;
506 	bp += sizeof(*i);
507 	length -= sizeof(*i);
508 	instructionslen -= sizeof(*i);
509 	ilen = ntohs(i->i_len) - sizeof(*i);
510 	if (length < ilen) {
511 		printf(" [|OpenFlow]");
512 		return;
513 	}
514 
515 	ofp_print_instruction(i, bp, length);
516 
517 	bp += ilen;
518 	length -= ilen;
519 	instructionslen -= ilen;
520 	if (instructionslen > 0)
521 		goto parse_next_instruction;
522 }
523 
524 void
ofp_if_print(u_char * user,const struct pcap_pkthdr * h,const u_char * p)525 ofp_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
526 {
527 	struct dlt_openflow_hdr	 of;
528 	unsigned int		 length;
529 
530 	ts_print(&h->ts);
531 
532 	packetp = p;
533 	snapend = p + h->caplen;
534 	length = snapend - p;
535 
536 	TCHECK2(*p, sizeof(of));
537 	memcpy(&of, p, sizeof(of));
538 
539 	if (ntohl(of.of_direction) == DLT_OPENFLOW_TO_SWITCH)
540 		printf("controller -> %s", device);
541 	else
542 		printf("%s -> controller", device);
543 	if (eflag)
544 		printf(", datapath %#016llx", be64toh(of.of_datapath_id));
545 
546 	ofp_print(p + sizeof(of), length - sizeof(of));
547 	goto out;
548 
549  trunc:
550 	printf("[|OpenFlow]");
551 
552  out:
553 	if (xflag)
554 		default_print(p, (u_int)h->len);
555 	putchar('\n');
556 }
557 
558 void
ofp_print(const u_char * bp,u_int length)559 ofp_print(const u_char *bp, u_int length)
560 {
561 	struct ofp_header	*oh;
562 	unsigned int		 ohlen, snaplen;
563 
564 	/* The captured data might be smaller than indicated */
565 	snaplen = snapend - bp;
566 	length = min(snaplen, length);
567 	if (length < sizeof(*oh)) {
568 		printf("[|OpenFlow]");
569 		return;
570 	}
571 
572 	oh = (struct ofp_header *)bp;
573 	ohlen = ntohs(oh->oh_length);
574 
575 	printf(": OpenFlow %s type %u length %u xid %u",
576 	    print_map(oh->oh_version, ofp_v_map),
577 	    oh->oh_type, ntohs(oh->oh_length), ntohl(oh->oh_xid));
578 
579 	switch (oh->oh_version) {
580 	case OFP_V_1_3:
581 		break;
582 
583 	default:
584 		return;
585 	}
586 
587 	printf(": %s", print_map(oh->oh_type, ofp_t_map));
588 
589 	switch (oh->oh_type) {
590 	case OFP_T_HELLO:
591 		ofp_print_hello(bp, length, ohlen);
592 		break;
593 	case OFP_T_ERROR:
594 		ofp_print_error(bp, length);
595 		break;
596 	case OFP_T_ECHO_REQUEST:
597 	case OFP_T_ECHO_REPLY:
598 		break;
599 	case OFP_T_FEATURES_REQUEST:
600 		break;
601 	case OFP_T_FEATURES_REPLY:
602 		ofp_print_featuresreply(bp, length);
603 		break;
604 	case OFP_T_SET_CONFIG:
605 		ofp_print_setconfig(bp, length);
606 		break;
607 	case OFP_T_PACKET_IN:
608 		ofp_print_packetin(bp, length);
609 		break;
610 	case OFP_T_FLOW_REMOVED:
611 		ofp_print_flowremoved(bp, length);
612 		break;
613 	case OFP_T_PACKET_OUT:
614 		ofp_print_packetout(bp, length);
615 		break;
616 	case OFP_T_FLOW_MOD:
617 		ofp_print_flowmod(bp, length);
618 		break;
619 	}
620 }
621 
622 void
oxm_print_byte(const u_char * bp,u_int length,int hasmask,int hex)623 oxm_print_byte(const u_char *bp, u_int length, int hasmask, int hex)
624 {
625 	uint8_t		*b;
626 
627 	if (length < sizeof(*b)) {
628 		printf("[|OpenFlow]");
629 		return;
630 	}
631 
632 	b = (uint8_t *)bp;
633 	if (hex)
634 		printf("%#02x", ntohs(*b));
635 	else
636 		printf("%u", ntohs(*b));
637 
638 	if (hasmask) {
639 		bp += sizeof(*b);
640 		length -= sizeof(*b);
641 		printf(" mask ");
642 		oxm_print_byte(bp, length, 0, 1);
643 	}
644 }
645 
646 void
oxm_print_halfword(const u_char * bp,u_int length,int hasmask,int hex)647 oxm_print_halfword(const u_char *bp, u_int length, int hasmask, int hex)
648 {
649 	uint16_t	*h;
650 
651 	if (length < sizeof(*h)) {
652 		printf("[|OpenFlow]");
653 		return;
654 	}
655 
656 	h = (uint16_t *)bp;
657 	if (hex)
658 		printf("%#04x", ntohs(*h));
659 	else
660 		printf("%u", ntohs(*h));
661 
662 	if (hasmask) {
663 		bp += sizeof(*h);
664 		length -= sizeof(*h);
665 		printf(" mask ");
666 		oxm_print_halfword(bp, length, 0, 1);
667 	}
668 }
669 
670 void
oxm_print_word(const u_char * bp,u_int length,int hasmask,int hex)671 oxm_print_word(const u_char *bp, u_int length, int hasmask, int hex)
672 {
673 	uint32_t	*w;
674 
675 	if (length < sizeof(*w)) {
676 		printf("[|OpenFlow]");
677 		return;
678 	}
679 
680 	w = (uint32_t *)bp;
681 	if (hex)
682 		printf("%#08x", ntohl(*w));
683 	else
684 		printf("%u", ntohl(*w));
685 
686 	if (hasmask) {
687 		bp += sizeof(*w);
688 		length -= sizeof(*w);
689 		printf(" mask ");
690 		oxm_print_word(bp, length, 0, 1);
691 	}
692 }
693 
694 void
oxm_print_quad(const u_char * bp,u_int length,int hasmask,int hex)695 oxm_print_quad(const u_char *bp, u_int length, int hasmask, int hex)
696 {
697 	uint64_t	*q;
698 
699 	if (length < sizeof(*q)) {
700 		printf("[|OpenFlow]");
701 		return;
702 	}
703 
704 	q = (uint64_t *)bp;
705 	if (hex)
706 		printf("%#016llx", be64toh(*q));
707 	else
708 		printf("%llu", be64toh(*q));
709 
710 	if (hasmask) {
711 		bp += sizeof(*q);
712 		length -= sizeof(*q);
713 		printf(" mask ");
714 		oxm_print_quad(bp, length, 0, 1);
715 	}
716 }
717 
718 void
oxm_print_ether(const u_char * bp,u_int length,int hasmask)719 oxm_print_ether(const u_char *bp, u_int length, int hasmask)
720 {
721 	if (length < ETHER_HDR_LEN) {
722 		printf("[|OpenFlow]");
723 		return;
724 	}
725 
726 	printf("%s", etheraddr_string(bp));
727 
728 	if (hasmask) {
729 		bp += ETHER_ADDR_LEN;
730 		length -= ETHER_ADDR_LEN;
731 		printf(" mask ");
732 		oxm_print_ether(bp, length, 0);
733 	}
734 }
735 
736 void
oxm_print_data(const u_char * bp,u_int length,int hasmask,size_t datalen)737 oxm_print_data(const u_char *bp, u_int length, int hasmask, size_t datalen)
738 {
739 	uint8_t		*ptr;
740 	int		 i;
741 	char		 hex[8];
742 
743 	if (length < datalen) {
744 		printf("[|OpenFlow]");
745 		return;
746 	}
747 
748 	ptr = (uint8_t *)bp;
749 	for (i = 0; i < datalen; i++) {
750 		snprintf(hex, sizeof(hex), "%02x", ptr[i]);
751 		printf("%s", hex);
752 	}
753 
754 	if (hasmask) {
755 		bp += datalen;
756 		length -= datalen;
757 		printf(" mask ");
758 		oxm_print_data(bp, length, 0, datalen);
759 	}
760 }
761 
762 void
ofp_print_oxm(struct ofp_ox_match * oxm,const u_char * bp,u_int length)763 ofp_print_oxm(struct ofp_ox_match *oxm, const u_char *bp, u_int length)
764 {
765 	int				 class, field, mask, len;
766 	uint16_t			*vlan;
767 
768 	class = ntohs(oxm->oxm_class);
769 	field = OFP_OXM_GET_FIELD(oxm);
770 	mask = OFP_OXM_GET_HASMASK(oxm);
771 	len = oxm->oxm_length;
772 	printf(" oxm <class %s field %s hasmask %d length %d",
773 	    print_map(class, ofp_oxm_c_map),
774 	    print_map(field, ofp_xm_t_map), mask, len);
775 
776 	switch (class) {
777 	case OFP_OXM_C_OPENFLOW_BASIC:
778 		break;
779 
780 	case OFP_OXM_C_NXM_0:
781 	case OFP_OXM_C_NXM_1:
782 	case OFP_OXM_C_OPENFLOW_EXPERIMENTER:
783 	default:
784 		printf(">");
785 		return;
786 	}
787 
788 	printf(" value ");
789 
790 	switch (field) {
791 	case OFP_XM_T_IN_PORT:
792 	case OFP_XM_T_IN_PHY_PORT:
793 	case OFP_XM_T_MPLS_LABEL:
794 		oxm_print_word(bp, length, mask, 0);
795 		break;
796 
797 	case OFP_XM_T_META:
798 	case OFP_XM_T_TUNNEL_ID:
799 		oxm_print_quad(bp, length, mask, 1);
800 		break;
801 
802 	case OFP_XM_T_ETH_DST:
803 	case OFP_XM_T_ETH_SRC:
804 	case OFP_XM_T_ARP_SHA:
805 	case OFP_XM_T_ARP_THA:
806 	case OFP_XM_T_IPV6_ND_SLL:
807 	case OFP_XM_T_IPV6_ND_TLL:
808 		oxm_print_ether(bp, length, mask);
809 		break;
810 
811 	case OFP_XM_T_ETH_TYPE:
812 		oxm_print_halfword(bp, length, mask, 1);
813 		break;
814 
815 	case OFP_XM_T_VLAN_VID:
816 		/*
817 		 * VLAN has an exception: it uses the higher bits to signal
818 		 * the presence of the VLAN.
819 		 */
820 		if (length < sizeof(*vlan)) {
821 			printf("[|OpenFlow]");
822 			break;
823 		}
824 
825 		vlan = (uint16_t *)bp;
826 		if (ntohs(*vlan) & OFP_XM_VID_PRESENT)
827 			printf("(VLAN %d) ",
828 			    ntohs(*vlan) & (~OFP_XM_VID_PRESENT));
829 		else
830 			printf("(no VLAN) ");
831 		/* FALLTHROUGH */
832 	case OFP_XM_T_TCP_SRC:
833 	case OFP_XM_T_TCP_DST:
834 	case OFP_XM_T_UDP_SRC:
835 	case OFP_XM_T_UDP_DST:
836 	case OFP_XM_T_SCTP_SRC:
837 	case OFP_XM_T_SCTP_DST:
838 	case OFP_XM_T_ARP_OP:
839 	case OFP_XM_T_IPV6_EXTHDR:
840 		oxm_print_halfword(bp, length, mask, 0);
841 		break;
842 
843 	case OFP_XM_T_VLAN_PCP:
844 	case OFP_XM_T_IP_DSCP:
845 	case OFP_XM_T_IP_ECN:
846 	case OFP_XM_T_MPLS_TC:
847 	case OFP_XM_T_MPLS_BOS:
848 		oxm_print_byte(bp, length, mask, 1);
849 		break;
850 
851 	case OFP_XM_T_IPV4_SRC:
852 	case OFP_XM_T_IPV4_DST:
853 	case OFP_XM_T_ARP_SPA:
854 	case OFP_XM_T_ARP_TPA:
855 	case OFP_XM_T_IPV6_FLABEL:
856 		oxm_print_word(bp, length, mask, 1);
857 		break;
858 
859 	case OFP_XM_T_IP_PROTO:
860 	case OFP_XM_T_ICMPV4_TYPE:
861 	case OFP_XM_T_ICMPV4_CODE:
862 	case OFP_XM_T_ICMPV6_TYPE:
863 	case OFP_XM_T_ICMPV6_CODE:
864 		oxm_print_byte(bp, length, mask, 0);
865 		break;
866 
867 	case OFP_XM_T_IPV6_SRC:
868 	case OFP_XM_T_IPV6_DST:
869 	case OFP_XM_T_IPV6_ND_TARGET:
870 		oxm_print_data(bp, length, mask, sizeof(struct in6_addr));
871 		break;
872 
873 	case OFP_XM_T_PBB_ISID:
874 		oxm_print_data(bp, length, mask, 3);
875 		break;
876 
877 	default:
878 		printf("unknown");
879 		break;
880 	}
881 
882 	printf(">");
883 }
884 
885 void
action_print_output(const u_char * bp,u_int length)886 action_print_output(const u_char *bp, u_int length)
887 {
888 	struct ofp_action_output		*ao;
889 
890 	if (length < (sizeof(*ao) - AH_UNPADDED)) {
891 		printf(" [|OpenFlow]");
892 		return;
893 	}
894 
895 	ao = (struct ofp_action_output *)(bp - AH_UNPADDED);
896 	printf(" port %s max_len %s",
897 	    print_map(ntohl(ao->ao_port), ofp_port_map),
898 	    print_map(ntohs(ao->ao_max_len), ofp_controller_maxlen_map));
899 }
900 
901 void
action_print_group(const u_char * bp,u_int length)902 action_print_group(const u_char *bp, u_int length)
903 {
904 	struct ofp_action_group		*ag;
905 
906 	if (length < (sizeof(*ag) - AH_UNPADDED)) {
907 		printf(" [|OpenFlow]");
908 		return;
909 	}
910 
911 	ag = (struct ofp_action_group *)(bp - AH_UNPADDED);
912 	printf(" group_id %s",
913 	    print_map(ntohl(ag->ag_group_id), ofp_group_id_map));
914 }
915 
916 void
action_print_setqueue(const u_char * bp,u_int length)917 action_print_setqueue(const u_char *bp, u_int length)
918 {
919 	struct ofp_action_set_queue	*asq;
920 
921 	if (length < (sizeof(*asq) - AH_UNPADDED)) {
922 		printf(" [|OpenFlow]");
923 		return;
924 	}
925 
926 	asq = (struct ofp_action_set_queue *)(bp - AH_UNPADDED);
927 	printf(" queue_id %u", ntohl(asq->asq_queue_id));
928 }
929 
930 void
action_print_setmplsttl(const u_char * bp,u_int length)931 action_print_setmplsttl(const u_char *bp, u_int length)
932 {
933 	struct ofp_action_mpls_ttl	*amt;
934 
935 	if (length < (sizeof(*amt) - AH_UNPADDED)) {
936 		printf(" [|OpenFlow]");
937 		return;
938 	}
939 
940 	amt = (struct ofp_action_mpls_ttl *)(bp - AH_UNPADDED);
941 	printf(" ttl %d", amt->amt_ttl);
942 }
943 
944 void
action_print_setnwttl(const u_char * bp,u_int length)945 action_print_setnwttl(const u_char *bp, u_int length)
946 {
947 	struct ofp_action_nw_ttl	*ant;
948 
949 	if (length < (sizeof(*ant) - AH_UNPADDED)) {
950 		printf(" [|OpenFlow]");
951 		return;
952 	}
953 
954 	ant = (struct ofp_action_nw_ttl *)(bp - AH_UNPADDED);
955 	printf(" ttl %d", ant->ant_ttl);
956 }
957 
958 void
action_print_push(const u_char * bp,u_int length)959 action_print_push(const u_char *bp, u_int length)
960 {
961 	struct ofp_action_push		*ap;
962 
963 	if (length < (sizeof(*ap) - AH_UNPADDED)) {
964 		printf(" [|OpenFlow]");
965 		return;
966 	}
967 
968 	ap = (struct ofp_action_push *)(bp - AH_UNPADDED);
969 	printf(" ethertype %#04x", ntohs(ap->ap_ethertype));
970 }
971 
972 void
action_print_popmpls(const u_char * bp,u_int length)973 action_print_popmpls(const u_char *bp, u_int length)
974 {
975 	struct ofp_action_pop_mpls	*apm;
976 
977 	if (length < (sizeof(*apm) - AH_UNPADDED)) {
978 		printf(" [|OpenFlow]");
979 		return;
980 	}
981 
982 	apm = (struct ofp_action_pop_mpls *)(bp - AH_UNPADDED);
983 	printf(" ethertype %#04x", ntohs(apm->apm_ethertype));
984 }
985 
986 void
action_print_setfield(const u_char * bp,u_int length)987 action_print_setfield(const u_char *bp, u_int length)
988 {
989 	struct ofp_action_set_field	*asf;
990 	int				 omlen;
991 
992 	if (length < (sizeof(*asf) - AH_UNPADDED)) {
993 		printf(" [|OpenFlow]");
994 		return;
995 	}
996 
997 	asf = (struct ofp_action_set_field *)(bp - AH_UNPADDED);
998 	omlen = ntohs(asf->asf_len) - AH_UNPADDED;
999 	if (omlen == 0)
1000 		return;
1001 
1002 	ofp_print_oxm_field(bp, length, omlen, 1);
1003 }
1004 
1005 void
ofp_print_action(struct ofp_action_header * ah,const u_char * bp,u_int length)1006 ofp_print_action(struct ofp_action_header *ah, const u_char *bp, u_int length)
1007 {
1008 	int			ahtype;
1009 
1010 	ahtype = ntohs(ah->ah_type);
1011 	printf(" action <type %s length %d",
1012 	    print_map(ahtype, ofp_action_map), ntohs(ah->ah_len));
1013 
1014 	switch (ahtype) {
1015 	case OFP_ACTION_OUTPUT:
1016 		action_print_output(bp, length);
1017 		break;
1018 
1019 	case OFP_ACTION_GROUP:
1020 		action_print_group(bp, length);
1021 		break;
1022 
1023 	case OFP_ACTION_SET_QUEUE:
1024 		action_print_setqueue(bp, length);
1025 		break;
1026 
1027 	case OFP_ACTION_SET_MPLS_TTL:
1028 		action_print_setmplsttl(bp, length);
1029 		break;
1030 
1031 	case OFP_ACTION_SET_NW_TTL:
1032 		action_print_setnwttl(bp, length);
1033 		break;
1034 
1035 	case OFP_ACTION_PUSH_VLAN:
1036 	case OFP_ACTION_PUSH_MPLS:
1037 	case OFP_ACTION_PUSH_PBB:
1038 		action_print_push(bp, length);
1039 		break;
1040 
1041 	case OFP_ACTION_POP_MPLS:
1042 		action_print_popmpls(bp, length);
1043 		break;
1044 
1045 	case OFP_ACTION_SET_FIELD:
1046 		action_print_setfield(bp, length);
1047 		break;
1048 
1049 	case OFP_ACTION_COPY_TTL_OUT:
1050 	case OFP_ACTION_COPY_TTL_IN:
1051 	case OFP_ACTION_DEC_NW_TTL:
1052 	case OFP_ACTION_DEC_MPLS_TTL:
1053 	case OFP_ACTION_POP_VLAN:
1054 	case OFP_ACTION_POP_PBB:
1055 	case OFP_ACTION_EXPERIMENTER:
1056 	default:
1057 		/* Generic header, nothing to show here. */
1058 		break;
1059 	}
1060 
1061 	printf(">");
1062 }
1063 
1064 void
instruction_print_gototable(const char * bp,u_int length)1065 instruction_print_gototable(const char *bp, u_int length)
1066 {
1067 	struct ofp_instruction_goto_table	*igt;
1068 
1069 	if (length < (sizeof(*igt) - sizeof(struct ofp_instruction))) {
1070 		printf(" [|OpenFlow]");
1071 		return;
1072 	}
1073 
1074 	igt = (struct ofp_instruction_goto_table *)
1075 	    (bp - sizeof(struct ofp_instruction));
1076 	printf(" table_id %d", igt->igt_table_id);
1077 }
1078 
1079 void
instruction_print_meta(const char * bp,u_int length)1080 instruction_print_meta(const char *bp, u_int length)
1081 {
1082 	struct ofp_instruction_write_metadata	*iwm;
1083 
1084 	if (length < (sizeof(*iwm) - sizeof(struct ofp_instruction))) {
1085 		printf(" [|OpenFlow]");
1086 		return;
1087 	}
1088 
1089 	iwm = (struct ofp_instruction_write_metadata *)
1090 	    (bp - sizeof(struct ofp_instruction));
1091 	printf(" metadata %llu metadata_mask %llu",
1092 	    be64toh(iwm->iwm_metadata), be64toh(iwm->iwm_metadata_mask));
1093 }
1094 
1095 void
instruction_print_actions(const char * bp,u_int length)1096 instruction_print_actions(const char *bp, u_int length)
1097 {
1098 	struct ofp_instruction_actions		*ia;
1099 	struct ofp_action_header		*ah;
1100 	int					 actionslen;
1101 	unsigned int				 ahlen;
1102 
1103 	if (length < (sizeof(*ia) - sizeof(struct ofp_instruction))) {
1104 		printf(" [|OpenFlow]");
1105 		return;
1106 	}
1107 
1108 	ia = (struct ofp_instruction_actions *)
1109 	    (bp - sizeof(struct ofp_instruction));
1110 
1111 	actionslen = ntohs(ia->ia_len) - sizeof(*ia);
1112 	if (actionslen <= 0)
1113 		return;
1114 
1115 	bp += sizeof(*ia) - sizeof(struct ofp_instruction);
1116 	length -= sizeof(*ia) - sizeof(struct ofp_instruction);
1117 
1118 parse_next_action:
1119 	if (length < sizeof(*ah)) {
1120 		printf(" [|OpenFlow]");
1121 		return;
1122 	}
1123 
1124 	ah = (struct ofp_action_header *)bp;
1125 	bp += AH_UNPADDED;
1126 	length -= AH_UNPADDED;
1127 	actionslen -= AH_UNPADDED;
1128 	ahlen = ntohs(ah->ah_len) - AH_UNPADDED;
1129 	if (length < ahlen) {
1130 		printf(" [|OpenFlow]");
1131 		return;
1132 	}
1133 
1134 	ofp_print_action(ah, bp, length);
1135 
1136 	bp += ahlen;
1137 	length -= ahlen;
1138 	actionslen -= min(ahlen, actionslen);
1139 	if (actionslen)
1140 		goto parse_next_action;
1141 }
1142 
1143 void
instruction_print_meter(const char * bp,u_int length)1144 instruction_print_meter(const char *bp, u_int length)
1145 {
1146 	struct ofp_instruction_meter		*im;
1147 
1148 	if (length < (sizeof(*im) - sizeof(struct ofp_instruction))) {
1149 		printf(" [|OpenFlow]");
1150 		return;
1151 	}
1152 
1153 	im = (struct ofp_instruction_meter *)
1154 	    (bp - sizeof(struct ofp_instruction));
1155 	printf(" meter_id %u", ntohl(im->im_meter_id));
1156 }
1157 
1158 void
instruction_print_experimenter(const char * bp,u_int length)1159 instruction_print_experimenter(const char *bp, u_int length)
1160 {
1161 	struct ofp_instruction_experimenter		*ie;
1162 
1163 	if (length < (sizeof(*ie) - sizeof(struct ofp_instruction))) {
1164 		printf(" [|OpenFlow]");
1165 		return;
1166 	}
1167 
1168 	ie = (struct ofp_instruction_experimenter *)
1169 	    (bp - sizeof(struct ofp_instruction));
1170 	printf(" experimenter %u", ntohl(ie->ie_experimenter));
1171 }
1172 
1173 void
ofp_print_instruction(struct ofp_instruction * i,const char * bp,u_int length)1174 ofp_print_instruction(struct ofp_instruction *i, const char *bp, u_int length)
1175 {
1176 	int			itype;
1177 
1178 	itype = ntohs(i->i_type);
1179 	printf(" instruction <type %s length %d",
1180 	    print_map(itype, ofp_instruction_t_map), ntohs(i->i_len));
1181 
1182 	switch (itype) {
1183 	case OFP_INSTRUCTION_T_GOTO_TABLE:
1184 		instruction_print_gototable(bp, length);
1185 		break;
1186 	case OFP_INSTRUCTION_T_WRITE_META:
1187 		instruction_print_meta(bp, length);
1188 		break;
1189 	case OFP_INSTRUCTION_T_WRITE_ACTIONS:
1190 	case OFP_INSTRUCTION_T_APPLY_ACTIONS:
1191 	case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
1192 		instruction_print_actions(bp, length);
1193 		break;
1194 	case OFP_INSTRUCTION_T_METER:
1195 		instruction_print_meter(bp, length);
1196 		break;
1197 	case OFP_INSTRUCTION_T_EXPERIMENTER:
1198 		instruction_print_meter(bp, length);
1199 		break;
1200 	}
1201 
1202 	printf(">");
1203 }
1204