xref: /openbsd-src/usr.sbin/tcpdump/print-ofp.c (revision c74ea871291a33bdfae991403f4d9469cc040c7f)
1*c74ea871Sakoshibe /*	$OpenBSD: print-ofp.c,v 1.12 2019/11/27 17:37:32 akoshibe Exp $	*/
228aafed6Srzalamena 
328aafed6Srzalamena /*
428aafed6Srzalamena  * Copyright (c) 2016 Rafael Zalamena <rzalamena@openbsd.org>
528aafed6Srzalamena  *
628aafed6Srzalamena  * Permission to use, copy, modify, and distribute this software for any
728aafed6Srzalamena  * purpose with or without fee is hereby granted, provided that the above
828aafed6Srzalamena  * copyright notice and this permission notice appear in all copies.
928aafed6Srzalamena  *
1028aafed6Srzalamena  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1128aafed6Srzalamena  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1228aafed6Srzalamena  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1328aafed6Srzalamena  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1428aafed6Srzalamena  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1528aafed6Srzalamena  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1628aafed6Srzalamena  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1728aafed6Srzalamena  */
1828aafed6Srzalamena 
1928aafed6Srzalamena #include <net/ofp.h>
2028aafed6Srzalamena 
2128aafed6Srzalamena #include <endian.h>
2228aafed6Srzalamena #include <stddef.h>
2328aafed6Srzalamena #include <stdio.h>
24814a7e6dSreyk #include <string.h>
257a61d4b0Sreyk #include <pcap.h>
2628aafed6Srzalamena 
27980a59dcSjca #include "addrtoname.h"
287a61d4b0Sreyk #include "extract.h"
2928aafed6Srzalamena #include "interface.h"
30814a7e6dSreyk #include "ofp_map.h"
3128aafed6Srzalamena 
3228aafed6Srzalamena /* Size of action header without the padding. */
3328aafed6Srzalamena #define AH_UNPADDED	(offsetof(struct ofp_action_header, ah_pad))
3428aafed6Srzalamena 
35814a7e6dSreyk const char *
36814a7e6dSreyk 	 print_map(unsigned int, struct constmap *);
37814a7e6dSreyk 
3828aafed6Srzalamena void	 ofp_print_hello(const u_char *, u_int, u_int);
3928aafed6Srzalamena void	 ofp_print_featuresreply(const u_char *, u_int);
4028aafed6Srzalamena void	 ofp_print_setconfig(const u_char *, u_int);
4128aafed6Srzalamena void	 ofp_print_packetin(const u_char *, u_int);
4228aafed6Srzalamena void	 ofp_print_packetout(const u_char *, u_int);
4328aafed6Srzalamena void	 ofp_print_flowremoved(const u_char *, u_int);
4428aafed6Srzalamena void	 ofp_print_flowmod(const u_char *, u_int);
4528aafed6Srzalamena 
4628aafed6Srzalamena void	 oxm_print_halfword(const u_char *, u_int, int, int);
4728aafed6Srzalamena void	 oxm_print_word(const u_char *, u_int, int, int);
4828aafed6Srzalamena void	 oxm_print_quad(const u_char *, u_int, int, int);
4928aafed6Srzalamena void	 oxm_print_ether(const u_char *, u_int, int);
5028aafed6Srzalamena void	 ofp_print_oxm(struct ofp_ox_match *, const u_char *, u_int);
5128aafed6Srzalamena 
5228aafed6Srzalamena void	 action_print_output(const u_char *, u_int);
5328aafed6Srzalamena void	 action_print_group(const u_char *, u_int);
5427ad49faSrzalamena void	 action_print_setqueue(const u_char *, u_int);
5528aafed6Srzalamena void	 action_print_setmplsttl(const u_char *, u_int);
5628aafed6Srzalamena void	 action_print_setnwttl(const u_char *, u_int);
5728aafed6Srzalamena void	 action_print_push(const u_char *, u_int);
5828aafed6Srzalamena void	 action_print_popmpls(const u_char *, u_int);
5928aafed6Srzalamena void	 action_print_setfield(const u_char *, u_int);
6028aafed6Srzalamena void	 ofp_print_action(struct ofp_action_header *, const u_char *,
6128aafed6Srzalamena 	    u_int);
6228aafed6Srzalamena 
6328aafed6Srzalamena void	 instruction_print_gototable(const char *, u_int);
6428aafed6Srzalamena void	 instruction_print_meta(const char *, u_int);
6528aafed6Srzalamena void	 instruction_print_actions(const char *, u_int);
6628aafed6Srzalamena void	 instruction_print_meter(const char *, u_int);
6728aafed6Srzalamena void	 instruction_print_experimenter(const char *, u_int);
6828aafed6Srzalamena void	 ofp_print_instruction(struct ofp_instruction *, const char *, u_int);
6928aafed6Srzalamena 
70814a7e6dSreyk const char *
print_map(unsigned int type,struct constmap * map)71814a7e6dSreyk print_map(unsigned int type, struct constmap *map)
72814a7e6dSreyk {
73814a7e6dSreyk 	unsigned int		 i;
74814a7e6dSreyk #define CYCLE_BUFFERS		 8
75814a7e6dSreyk 	static char		 buf[CYCLE_BUFFERS][32];
76814a7e6dSreyk 	static int		 idx = 0;
77814a7e6dSreyk 	const char		*name = NULL;
78814a7e6dSreyk 
79814a7e6dSreyk 	if (idx >= CYCLE_BUFFERS)
80814a7e6dSreyk 		idx = 0;
81814a7e6dSreyk 	memset(buf[idx], 0, sizeof(buf[idx]));
82814a7e6dSreyk 
83814a7e6dSreyk 	for (i = 0; map[i].cm_name != NULL; i++) {
84814a7e6dSreyk 		if (map[i].cm_type == type) {
85814a7e6dSreyk 			name = map[i].cm_name;
86814a7e6dSreyk 			break;
87814a7e6dSreyk 		}
88814a7e6dSreyk 	}
89814a7e6dSreyk 
90814a7e6dSreyk 	if (name == NULL)
91814a7e6dSreyk 		snprintf(buf[idx], sizeof(buf[idx]), "%u", type);
92814a7e6dSreyk 	else if (vflag > 1)
93814a7e6dSreyk 		snprintf(buf[idx], sizeof(buf[idx]), "%s[%u]", name, type);
94814a7e6dSreyk 	else
95814a7e6dSreyk 		strlcpy(buf[idx], name, sizeof(buf[idx]));
96814a7e6dSreyk 
97814a7e6dSreyk 	return (buf[idx++]);
98814a7e6dSreyk }
99814a7e6dSreyk 
10028aafed6Srzalamena void
ofp_print_hello(const u_char * bp,u_int length,u_int ohlen)10128aafed6Srzalamena ofp_print_hello(const u_char *bp, u_int length, u_int ohlen)
10228aafed6Srzalamena {
10328aafed6Srzalamena 	struct ofp_hello_element_header		*he;
10428aafed6Srzalamena 	int					 hetype, helen, ver, i;
10528aafed6Srzalamena 	int					 vmajor, vminor;
10628aafed6Srzalamena 	uint32_t				 bmp;
10728aafed6Srzalamena 
10828aafed6Srzalamena 	/* Skip the OFP header. */
10928aafed6Srzalamena 	bp += sizeof(struct ofp_header);
11028aafed6Srzalamena 	length -= sizeof(struct ofp_header);
11128aafed6Srzalamena 
11228aafed6Srzalamena 	/* Check for header truncation. */
11328aafed6Srzalamena 	if (ohlen > sizeof(struct ofp_header) &&
11428aafed6Srzalamena 	    length < sizeof(*he)) {
115814a7e6dSreyk 		printf(" [|OpenFlow]");
11628aafed6Srzalamena 		return;
11728aafed6Srzalamena 	}
11828aafed6Srzalamena 
11928aafed6Srzalamena  next_header:
12028aafed6Srzalamena 	/* Check for hello element headers. */
12128aafed6Srzalamena 	if (length < sizeof(*he))
12228aafed6Srzalamena 		return;
12328aafed6Srzalamena 
12428aafed6Srzalamena 	he = (struct ofp_hello_element_header *)bp;
12528aafed6Srzalamena 	hetype = ntohs(he->he_type);
12628aafed6Srzalamena 	helen = ntohs(he->he_length);
12728aafed6Srzalamena 
12828aafed6Srzalamena 	bp += sizeof(*he);
12928aafed6Srzalamena 	length -= sizeof(*he);
13028aafed6Srzalamena 	helen -= sizeof(*he);
13128aafed6Srzalamena 
13228aafed6Srzalamena 	switch (hetype) {
1335cec6c3dSrzalamena 	case OFP_HELLO_T_VERSION_BITMAP:
13428aafed6Srzalamena 		printf(" version bitmap <");
13528aafed6Srzalamena 		if (helen < sizeof(bmp)) {
13628aafed6Srzalamena 			printf("invalid header>");
13728aafed6Srzalamena 			break;
13828aafed6Srzalamena 		}
13928aafed6Srzalamena 
14028aafed6Srzalamena  next_bitmap:
14128aafed6Srzalamena 		if (length < sizeof(bmp)) {
1425cec6c3dSrzalamena 			printf("[|OpenFlow]>");
14328aafed6Srzalamena 			break;
14428aafed6Srzalamena 		}
14528aafed6Srzalamena 
14628aafed6Srzalamena 		bmp = ntohl(*(uint32_t *)bp);
14728aafed6Srzalamena 		for (i = 0, ver = 9; i < 32; i++, ver++) {
14828aafed6Srzalamena 			if ((bmp & (1 << i)) == 0)
14928aafed6Srzalamena 				continue;
15028aafed6Srzalamena 
15128aafed6Srzalamena 			vmajor = (ver / 10);
15228aafed6Srzalamena 			vminor = ver % 10;
15328aafed6Srzalamena 			printf("v%d.%d ", vmajor, vminor);
15428aafed6Srzalamena 		}
15528aafed6Srzalamena 		helen -= min(sizeof(bmp), helen);
15628aafed6Srzalamena 		length -= sizeof(bmp);
15728aafed6Srzalamena 		bp += sizeof(bmp);
15828aafed6Srzalamena 		if (helen)
15928aafed6Srzalamena 			goto next_bitmap;
16028aafed6Srzalamena 
16128aafed6Srzalamena 		printf("\b>");
16228aafed6Srzalamena 		break;
16328aafed6Srzalamena 
16428aafed6Srzalamena 	default:
16528aafed6Srzalamena 		printf(" element header[type %d length %d]", hetype, helen);
16628aafed6Srzalamena 		break;
16728aafed6Srzalamena 	}
16828aafed6Srzalamena 
16928aafed6Srzalamena 	length -= min(helen, length);
17028aafed6Srzalamena 	bp += helen;
17128aafed6Srzalamena 	if (length)
17228aafed6Srzalamena 		goto next_header;
17328aafed6Srzalamena }
17428aafed6Srzalamena 
17528aafed6Srzalamena void
ofp_print_error(const u_char * bp,u_int length)17628aafed6Srzalamena ofp_print_error(const u_char *bp, u_int length)
17728aafed6Srzalamena {
17828aafed6Srzalamena 	struct ofp_error			*err;
17928aafed6Srzalamena 
18028aafed6Srzalamena 	if (length < sizeof(*err)) {
181814a7e6dSreyk 		printf(" [|OpenFlow]");
18228aafed6Srzalamena 		return;
18328aafed6Srzalamena 	}
18428aafed6Srzalamena 
18528aafed6Srzalamena 	err = (struct ofp_error *)bp;
186814a7e6dSreyk 	printf(" <type %s code %d>",
187814a7e6dSreyk 	    print_map(ntohs(err->err_type), ofp_errtype_map),
18828aafed6Srzalamena 	    ntohs(err->err_code));
18928aafed6Srzalamena 
19028aafed6Srzalamena 	length -= min(sizeof(*err), length);
19128aafed6Srzalamena 	bp += sizeof(*err);
19228aafed6Srzalamena 	/* If there are still bytes left, print the optional error data. */
19328aafed6Srzalamena 	if (length) {
194814a7e6dSreyk 		printf(" error data");
1957a61d4b0Sreyk 		ofp_print(bp, length);
19628aafed6Srzalamena 	}
19728aafed6Srzalamena }
19828aafed6Srzalamena 
19928aafed6Srzalamena void
ofp_print_featuresreply(const u_char * bp,u_int length)20028aafed6Srzalamena ofp_print_featuresreply(const u_char *bp, u_int length)
20128aafed6Srzalamena {
20228aafed6Srzalamena 	struct ofp_switch_features		*swf;
20328aafed6Srzalamena 
20428aafed6Srzalamena 	if (length < sizeof(*swf)) {
20528aafed6Srzalamena 		printf(" [trucanted]");
20628aafed6Srzalamena 		return;
20728aafed6Srzalamena 	}
20828aafed6Srzalamena 
20928aafed6Srzalamena 	swf = (struct ofp_switch_features *)bp;
21028aafed6Srzalamena 	printf(" <datapath_id %#016llx nbuffers %u ntables %d aux_id %d "
211677ebbdaSrzalamena 	    "capabilities %#08x>",
21228aafed6Srzalamena 	    be64toh(swf->swf_datapath_id), ntohl(swf->swf_nbuffers),
21328aafed6Srzalamena 	    swf->swf_ntables, swf->swf_aux_id,
214677ebbdaSrzalamena 	    ntohl(swf->swf_capabilities));
21528aafed6Srzalamena }
21628aafed6Srzalamena 
21728aafed6Srzalamena void
ofp_print_setconfig(const u_char * bp,u_int length)21828aafed6Srzalamena ofp_print_setconfig(const u_char *bp, u_int length)
21928aafed6Srzalamena {
22028aafed6Srzalamena 	struct ofp_switch_config		*cfg;
22128aafed6Srzalamena 
22228aafed6Srzalamena 	if (length < sizeof(*cfg)) {
223814a7e6dSreyk 		printf(" [|OpenFlow]");
22428aafed6Srzalamena 		return;
22528aafed6Srzalamena 	}
22628aafed6Srzalamena 
22728aafed6Srzalamena 	cfg = (struct ofp_switch_config *)bp;
2282757b9e2Sreyk 	printf(" <flags %#04x miss_send_len %s>",
2292757b9e2Sreyk 	    ntohs(cfg->cfg_flags),
2302757b9e2Sreyk 	    print_map(ntohs(cfg->cfg_miss_send_len),
2312757b9e2Sreyk 	    ofp_controller_maxlen_map));
23228aafed6Srzalamena }
23328aafed6Srzalamena 
23428aafed6Srzalamena void
ofp_print_oxm_field(const u_char * bp,u_int length,int omlen,int once)235*c74ea871Sakoshibe ofp_print_oxm_field(const u_char *bp, u_int length, int omlen, int once)
236*c74ea871Sakoshibe {
237*c74ea871Sakoshibe 	struct ofp_ox_match		*oxm;
238*c74ea871Sakoshibe 
239*c74ea871Sakoshibe 	do {
240*c74ea871Sakoshibe 		if (length < sizeof(*oxm)) {
241*c74ea871Sakoshibe 			printf(" [|OpenFlow]");
242*c74ea871Sakoshibe 			return;
243*c74ea871Sakoshibe 		}
244*c74ea871Sakoshibe 
245*c74ea871Sakoshibe 		oxm = (struct ofp_ox_match *)bp;
246*c74ea871Sakoshibe 		bp += sizeof(*oxm);
247*c74ea871Sakoshibe 		length -= sizeof(*oxm);
248*c74ea871Sakoshibe 		if (length < oxm->oxm_length) {
249*c74ea871Sakoshibe 			printf(" [|OpenFlow]");
250*c74ea871Sakoshibe 			return;
251*c74ea871Sakoshibe 		}
252*c74ea871Sakoshibe 
253*c74ea871Sakoshibe 		ofp_print_oxm(oxm, bp, length);
254*c74ea871Sakoshibe 		bp += oxm->oxm_length;
255*c74ea871Sakoshibe 		length -= oxm->oxm_length;
256*c74ea871Sakoshibe 
257*c74ea871Sakoshibe 		if (once)
258*c74ea871Sakoshibe 			return;
259*c74ea871Sakoshibe 
260*c74ea871Sakoshibe 		omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen);
261*c74ea871Sakoshibe 	} while (omlen > 0);
262*c74ea871Sakoshibe }
263*c74ea871Sakoshibe 
264*c74ea871Sakoshibe void
ofp_print_packetin(const u_char * bp,u_int length)26528aafed6Srzalamena ofp_print_packetin(const u_char *bp, u_int length)
26628aafed6Srzalamena {
26728aafed6Srzalamena 	struct ofp_packet_in		*pin;
26828aafed6Srzalamena 	int				 omtype, omlen;
26928aafed6Srzalamena 	int				 haspacket = 0;
27028aafed6Srzalamena 	const u_char			*pktptr;
27128aafed6Srzalamena 
27228aafed6Srzalamena 	if (length < sizeof(*pin)) {
273814a7e6dSreyk 		printf(" [|OpenFlow]");
27428aafed6Srzalamena 		return;
27528aafed6Srzalamena 	}
27628aafed6Srzalamena 
27728aafed6Srzalamena 	pin = (struct ofp_packet_in *)bp;
27828aafed6Srzalamena 	omtype = ntohs(pin->pin_match.om_type);
27928aafed6Srzalamena 	omlen = ntohs(pin->pin_match.om_length);
280814a7e6dSreyk 	printf(" <buffer_id %s total_len %d reason %s table_id %s "
281814a7e6dSreyk 	    "cookie %#016llx match type %s length %d>",
282814a7e6dSreyk 	    print_map(ntohl(pin->pin_buffer_id), ofp_pktout_map),
283814a7e6dSreyk 	    ntohs(pin->pin_total_len),
284814a7e6dSreyk 	    print_map(pin->pin_reason, ofp_pktin_reason_map),
285814a7e6dSreyk 	    print_map(pin->pin_table_id, ofp_table_id_map),
286814a7e6dSreyk 	    be64toh(pin->pin_cookie),
287814a7e6dSreyk 	    print_map(omtype, ofp_match_map), omlen);
28828aafed6Srzalamena 
28928aafed6Srzalamena 	if (pin->pin_buffer_id == OFP_PKTOUT_NO_BUFFER)
29028aafed6Srzalamena 		haspacket = 1;
29128aafed6Srzalamena 
29228aafed6Srzalamena 	/* We only support OXM. */
29328aafed6Srzalamena 	if (omtype != OFP_MATCH_OXM)
29428aafed6Srzalamena 		return;
29528aafed6Srzalamena 
29628aafed6Srzalamena 	bp += sizeof(*pin);
29728aafed6Srzalamena 	length -= sizeof(*pin);
29828aafed6Srzalamena 
29928aafed6Srzalamena 	/* Get packet start address. */
30028aafed6Srzalamena 	pktptr = (bp - sizeof(pin->pin_match)) +
30128aafed6Srzalamena 	    OFP_ALIGN(omlen) + ETHER_ALIGN;
30228aafed6Srzalamena 
30328aafed6Srzalamena 	/* Don't count the header for the OXM fields. */
30428aafed6Srzalamena 	omlen -= min(sizeof(pin->pin_match), omlen);
30528aafed6Srzalamena 	if (omlen == 0)
30628aafed6Srzalamena 		goto print_packet;
30728aafed6Srzalamena 
308*c74ea871Sakoshibe 	ofp_print_oxm_field(bp, length, omlen, 0);
30928aafed6Srzalamena 
31028aafed6Srzalamena  print_packet:
31128aafed6Srzalamena 	if (haspacket == 0)
31228aafed6Srzalamena 		return;
31328aafed6Srzalamena 
31428aafed6Srzalamena 	/*
31528aafed6Srzalamena 	 * Recalculate length:
31628aafed6Srzalamena 	 * pktptr skipped the omlen + padding and the ETHER_ALIGN, so
31728aafed6Srzalamena 	 * instead of keeping track of that we just recalculate length
31828aafed6Srzalamena 	 * using the encapsulated packet begin and snapend.
31928aafed6Srzalamena 	 */
32028aafed6Srzalamena 	length = max(snapend - pktptr, 0);
32128aafed6Srzalamena 	if (length < ETHER_ADDR_LEN) {
32228aafed6Srzalamena 		printf(" [|ether]");
32328aafed6Srzalamena 		return;
32428aafed6Srzalamena 	}
32528aafed6Srzalamena 
32628aafed6Srzalamena 	printf(" ");
32728aafed6Srzalamena 	ether_tryprint(pktptr, length, 0);
32828aafed6Srzalamena }
32928aafed6Srzalamena 
33028aafed6Srzalamena void
ofp_print_flowremoved(const u_char * bp,u_int length)33128aafed6Srzalamena ofp_print_flowremoved(const u_char *bp, u_int length)
33228aafed6Srzalamena {
33328aafed6Srzalamena 	struct ofp_flow_removed			*fr;
33428aafed6Srzalamena 	int					 omtype, omlen;
33528aafed6Srzalamena 
33628aafed6Srzalamena 	if (length < sizeof(*fr)) {
337814a7e6dSreyk 		printf(" [|OpenFlow]");
33828aafed6Srzalamena 		return;
33928aafed6Srzalamena 	}
34028aafed6Srzalamena 
34128aafed6Srzalamena 	fr = (struct ofp_flow_removed *)bp;
34228aafed6Srzalamena 	omtype = ntohs(fr->fr_match.om_type);
34328aafed6Srzalamena 	omlen = ntohs(fr->fr_match.om_length);
344814a7e6dSreyk 	printf(" <cookie %#016llx priority %d reason %s table_id %s "
34528aafed6Srzalamena 	    "duration sec %u nsec %u timeout idle %d hard %d "
346814a7e6dSreyk 	    "packet count %llu byte count %llu match type %s length %d>",
347814a7e6dSreyk 	    be64toh(fr->fr_cookie), ntohs(fr->fr_priority),
348814a7e6dSreyk 	    print_map(fr->fr_reason, ofp_flowrem_reason_map),
349814a7e6dSreyk 	    print_map(fr->fr_table_id, ofp_table_id_map),
350814a7e6dSreyk 	    ntohl(fr->fr_duration_sec), ntohl(fr->fr_duration_nsec),
351814a7e6dSreyk 	    ntohs(fr->fr_idle_timeout), ntohs(fr->fr_hard_timeout),
352814a7e6dSreyk 	    be64toh(fr->fr_packet_count), be64toh(fr->fr_byte_count),
353814a7e6dSreyk 	    print_map(omtype, ofp_match_map), omlen);
35428aafed6Srzalamena 
35528aafed6Srzalamena 	/* We only support OXM. */
35628aafed6Srzalamena 	if (omtype != OFP_MATCH_OXM)
35728aafed6Srzalamena 		return;
35828aafed6Srzalamena 
35928aafed6Srzalamena 	omlen -= min(sizeof(fr->fr_match), omlen);
36028aafed6Srzalamena 	if (omlen == 0)
36128aafed6Srzalamena 		return;
36228aafed6Srzalamena 
36328aafed6Srzalamena 	bp += sizeof(*fr);
36428aafed6Srzalamena 	length -= sizeof(*fr);
36528aafed6Srzalamena 
366*c74ea871Sakoshibe 	ofp_print_oxm_field(bp, length, omlen, 0);
36728aafed6Srzalamena }
36828aafed6Srzalamena 
36928aafed6Srzalamena void
ofp_print_packetout(const u_char * bp,u_int length)37028aafed6Srzalamena ofp_print_packetout(const u_char *bp, u_int length)
37128aafed6Srzalamena {
37228aafed6Srzalamena 	struct ofp_packet_out			*pout;
37328aafed6Srzalamena 	struct ofp_action_header		*ah;
37428aafed6Srzalamena 	const u_char				*pktptr;
37528aafed6Srzalamena 	int					 actionslen, haspacket = 0;
37628aafed6Srzalamena 	int					 ahlen;
37728aafed6Srzalamena 
37828aafed6Srzalamena 	if (length < sizeof(*pout)) {
379814a7e6dSreyk 		printf(" [|OpenFlow]");
38028aafed6Srzalamena 		return;
38128aafed6Srzalamena 	}
38228aafed6Srzalamena 
38328aafed6Srzalamena 	pout = (struct ofp_packet_out *)bp;
38428aafed6Srzalamena 	actionslen = ntohs(pout->pout_actions_len);
385814a7e6dSreyk 	printf(" <buffer_id %s in_port %s actions_len %d>",
386814a7e6dSreyk 	    print_map(ntohl(pout->pout_buffer_id), ofp_pktout_map),
387814a7e6dSreyk 	    print_map(ntohl(pout->pout_in_port), ofp_port_map),
38828aafed6Srzalamena 	    actionslen);
38928aafed6Srzalamena 
39028aafed6Srzalamena 	if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER)
39128aafed6Srzalamena 		haspacket = 1;
39228aafed6Srzalamena 
39328aafed6Srzalamena 	bp += sizeof(*pout);
39428aafed6Srzalamena 	length -= sizeof(*pout);
39528aafed6Srzalamena 	pktptr = bp + actionslen;
39628aafed6Srzalamena 
39728aafed6Srzalamena 	/* No actions or unpadded header. */
39828aafed6Srzalamena 	if (actionslen < sizeof(*ah))
39928aafed6Srzalamena 		goto print_packet;
40028aafed6Srzalamena 
40128aafed6Srzalamena  parse_next_action:
40228aafed6Srzalamena 	if (length < sizeof(*ah)) {
403814a7e6dSreyk 		printf(" [|OpenFlow]");
40428aafed6Srzalamena 		return;
40528aafed6Srzalamena 	}
40628aafed6Srzalamena 
40728aafed6Srzalamena 	ah = (struct ofp_action_header *)bp;
40828aafed6Srzalamena 	bp += AH_UNPADDED;
40928aafed6Srzalamena 	length -= AH_UNPADDED;
41028aafed6Srzalamena 	actionslen -= AH_UNPADDED;
41128aafed6Srzalamena 	ahlen = ntohs(ah->ah_len) - AH_UNPADDED;
41228aafed6Srzalamena 	if (length < ahlen) {
413814a7e6dSreyk 		printf(" [|OpenFlow]");
41428aafed6Srzalamena 		return;
41528aafed6Srzalamena 	}
41628aafed6Srzalamena 
41728aafed6Srzalamena 	ofp_print_action(ah, bp, length);
41828aafed6Srzalamena 
41928aafed6Srzalamena 	bp += ahlen;
42028aafed6Srzalamena 	length -= ahlen;
42128aafed6Srzalamena 	actionslen -= min(ahlen, actionslen);
42228aafed6Srzalamena 	if (actionslen)
42328aafed6Srzalamena 		goto parse_next_action;
42428aafed6Srzalamena 
42528aafed6Srzalamena  print_packet:
42628aafed6Srzalamena 	if (haspacket == 0)
42728aafed6Srzalamena 		return;
42828aafed6Srzalamena 
42928aafed6Srzalamena 	/* Recalculate length using packet boundaries. */
43028aafed6Srzalamena 	length = max(snapend - pktptr, 0);
43128aafed6Srzalamena 	if (length < ETHER_ADDR_LEN) {
43228aafed6Srzalamena 		printf(" [|ether]");
43328aafed6Srzalamena 		return;
43428aafed6Srzalamena 	}
43528aafed6Srzalamena 
43628aafed6Srzalamena 	printf(" ");
43728aafed6Srzalamena 	ether_tryprint(pktptr, length, 0);
43828aafed6Srzalamena }
43928aafed6Srzalamena 
44028aafed6Srzalamena void
ofp_print_flowmod(const u_char * bp,u_int length)44128aafed6Srzalamena ofp_print_flowmod(const u_char *bp, u_int length)
44228aafed6Srzalamena {
44328aafed6Srzalamena 	struct ofp_flow_mod			*fm;
44428aafed6Srzalamena 	struct ofp_instruction			*i;
44528aafed6Srzalamena 	int					 omtype, omlen, ilen;
44628aafed6Srzalamena 	int					 instructionslen, padsize;
44728aafed6Srzalamena 
44828aafed6Srzalamena 	if (length < sizeof(*fm)) {
449814a7e6dSreyk 		printf(" [|OpenFlow]");
45028aafed6Srzalamena 		return;
45128aafed6Srzalamena 	}
45228aafed6Srzalamena 
45328aafed6Srzalamena 	fm = (struct ofp_flow_mod *)bp;
45428aafed6Srzalamena 	omtype = ntohs(fm->fm_match.om_type);
45528aafed6Srzalamena 	omlen = ntohs(fm->fm_match.om_length);
456814a7e6dSreyk 	printf(" <cookie %llu cookie_mask %#016llx table_id %s command %s "
457814a7e6dSreyk 	    "timeout idle %d hard %d priority %d buffer_id %s out_port %s "
458814a7e6dSreyk 	    "out_group %s flags %#04x match type %s length %d>",
45928aafed6Srzalamena 	    be64toh(fm->fm_cookie), be64toh(fm->fm_cookie_mask),
460814a7e6dSreyk 	    print_map(fm->fm_table_id, ofp_table_id_map),
461814a7e6dSreyk 	    print_map(fm->fm_command, ofp_flowcmd_map),
462814a7e6dSreyk 	    ntohs(fm->fm_idle_timeout), ntohs(fm->fm_hard_timeout),
463814a7e6dSreyk 	    fm->fm_priority,
464814a7e6dSreyk 	    print_map(ntohl(fm->fm_buffer_id), ofp_pktout_map),
465814a7e6dSreyk 	    print_map(ntohl(fm->fm_out_port), ofp_port_map),
466814a7e6dSreyk 	    print_map(ntohl(fm->fm_out_group), ofp_group_id_map),
467814a7e6dSreyk 	    ntohs(fm->fm_flags),
468814a7e6dSreyk 	    print_map(omtype, ofp_match_map), omlen);
46928aafed6Srzalamena 
47028aafed6Srzalamena 	bp += sizeof(*fm);
47128aafed6Srzalamena 	length -= sizeof(*fm);
47228aafed6Srzalamena 
47328aafed6Srzalamena 	padsize = OFP_ALIGN(omlen) - omlen;
47428aafed6Srzalamena 	omlen -= min(sizeof(fm->fm_match), omlen);
47528aafed6Srzalamena 	instructionslen = length - (omlen + padsize);
47628aafed6Srzalamena 	if (omtype != OFP_MATCH_OXM || omlen == 0) {
47728aafed6Srzalamena 		if (instructionslen <= 0)
47828aafed6Srzalamena 			return;
47928aafed6Srzalamena 
48028aafed6Srzalamena 		/* Skip padding if any. */
48128aafed6Srzalamena 		if (padsize) {
48228aafed6Srzalamena 			bp += padsize;
48328aafed6Srzalamena 			length -= padsize;
48428aafed6Srzalamena 		}
48528aafed6Srzalamena 		goto parse_next_instruction;
48628aafed6Srzalamena 	}
48728aafed6Srzalamena 
488*c74ea871Sakoshibe 	ofp_print_oxm_field(bp, length, omlen, 0);
48928aafed6Srzalamena 
490*c74ea871Sakoshibe 	bp += omlen;
491*c74ea871Sakoshibe 	length -= omlen;
49228aafed6Srzalamena 
49328aafed6Srzalamena 	/* Skip padding if any. */
49428aafed6Srzalamena 	if (padsize) {
49528aafed6Srzalamena 		bp += padsize;
49628aafed6Srzalamena 		length -= padsize;
49728aafed6Srzalamena 	}
49828aafed6Srzalamena 
49928aafed6Srzalamena parse_next_instruction:
50028aafed6Srzalamena 	if (length < sizeof(*i)) {
501814a7e6dSreyk 		printf(" [|OpenFlow]");
50228aafed6Srzalamena 		return;
50328aafed6Srzalamena 	}
50428aafed6Srzalamena 
50528aafed6Srzalamena 	i = (struct ofp_instruction *)bp;
50628aafed6Srzalamena 	bp += sizeof(*i);
50728aafed6Srzalamena 	length -= sizeof(*i);
50828aafed6Srzalamena 	instructionslen -= sizeof(*i);
50928aafed6Srzalamena 	ilen = ntohs(i->i_len) - sizeof(*i);
51028aafed6Srzalamena 	if (length < ilen) {
511814a7e6dSreyk 		printf(" [|OpenFlow]");
51228aafed6Srzalamena 		return;
51328aafed6Srzalamena 	}
51428aafed6Srzalamena 
51528aafed6Srzalamena 	ofp_print_instruction(i, bp, length);
51628aafed6Srzalamena 
51728aafed6Srzalamena 	bp += ilen;
51828aafed6Srzalamena 	length -= ilen;
51928aafed6Srzalamena 	instructionslen -= ilen;
52028aafed6Srzalamena 	if (instructionslen > 0)
52128aafed6Srzalamena 		goto parse_next_instruction;
52228aafed6Srzalamena }
52328aafed6Srzalamena 
52428aafed6Srzalamena void
ofp_if_print(u_char * user,const struct pcap_pkthdr * h,const u_char * p)5257a61d4b0Sreyk ofp_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
5267a61d4b0Sreyk {
5278167ef46Sreyk 	struct dlt_openflow_hdr	 of;
5287a61d4b0Sreyk 	unsigned int		 length;
5297a61d4b0Sreyk 
5307a61d4b0Sreyk 	ts_print(&h->ts);
5317a61d4b0Sreyk 
5327a61d4b0Sreyk 	packetp = p;
5337a61d4b0Sreyk 	snapend = p + h->caplen;
5347a61d4b0Sreyk 	length = snapend - p;
5357a61d4b0Sreyk 
5368167ef46Sreyk 	TCHECK2(*p, sizeof(of));
5378167ef46Sreyk 	memcpy(&of, p, sizeof(of));
5387a61d4b0Sreyk 
5398167ef46Sreyk 	if (ntohl(of.of_direction) == DLT_OPENFLOW_TO_SWITCH)
5407a61d4b0Sreyk 		printf("controller -> %s", device);
5417a61d4b0Sreyk 	else
5427a61d4b0Sreyk 		printf("%s -> controller", device);
5438167ef46Sreyk 	if (eflag)
5448167ef46Sreyk 		printf(", datapath %#016llx", be64toh(of.of_datapath_id));
5457a61d4b0Sreyk 
5468167ef46Sreyk 	ofp_print(p + sizeof(of), length - sizeof(of));
5477a61d4b0Sreyk 	goto out;
5487a61d4b0Sreyk 
5497a61d4b0Sreyk  trunc:
5507a61d4b0Sreyk 	printf("[|OpenFlow]");
5517a61d4b0Sreyk 
5527a61d4b0Sreyk  out:
5537a61d4b0Sreyk 	if (xflag)
5547a61d4b0Sreyk 		default_print(p, (u_int)h->len);
5557a61d4b0Sreyk 	putchar('\n');
5567a61d4b0Sreyk }
5577a61d4b0Sreyk 
5587a61d4b0Sreyk void
ofp_print(const u_char * bp,u_int length)5597a61d4b0Sreyk ofp_print(const u_char *bp, u_int length)
56028aafed6Srzalamena {
56128aafed6Srzalamena 	struct ofp_header	*oh;
5627a61d4b0Sreyk 	unsigned int		 ohlen, snaplen;
56328aafed6Srzalamena 
5647a61d4b0Sreyk 	/* The captured data might be smaller than indicated */
5657a61d4b0Sreyk 	snaplen = snapend - bp;
5667a61d4b0Sreyk 	length = min(snaplen, length);
56728aafed6Srzalamena 	if (length < sizeof(*oh)) {
5687a61d4b0Sreyk 		printf("[|OpenFlow]");
56928aafed6Srzalamena 		return;
57028aafed6Srzalamena 	}
57128aafed6Srzalamena 
57228aafed6Srzalamena 	oh = (struct ofp_header *)bp;
57328aafed6Srzalamena 	ohlen = ntohs(oh->oh_length);
574814a7e6dSreyk 
575814a7e6dSreyk 	printf(": OpenFlow %s type %u length %u xid %u",
576814a7e6dSreyk 	    print_map(oh->oh_version, ofp_v_map),
577814a7e6dSreyk 	    oh->oh_type, ntohs(oh->oh_length), ntohl(oh->oh_xid));
57828aafed6Srzalamena 
57928aafed6Srzalamena 	switch (oh->oh_version) {
58028aafed6Srzalamena 	case OFP_V_1_3:
58128aafed6Srzalamena 		break;
58228aafed6Srzalamena 
58328aafed6Srzalamena 	default:
58428aafed6Srzalamena 		return;
58528aafed6Srzalamena 	}
58628aafed6Srzalamena 
587814a7e6dSreyk 	printf(": %s", print_map(oh->oh_type, ofp_t_map));
588814a7e6dSreyk 
58928aafed6Srzalamena 	switch (oh->oh_type) {
59028aafed6Srzalamena 	case OFP_T_HELLO:
59128aafed6Srzalamena 		ofp_print_hello(bp, length, ohlen);
59228aafed6Srzalamena 		break;
59328aafed6Srzalamena 	case OFP_T_ERROR:
59428aafed6Srzalamena 		ofp_print_error(bp, length);
59528aafed6Srzalamena 		break;
59628aafed6Srzalamena 	case OFP_T_ECHO_REQUEST:
59728aafed6Srzalamena 	case OFP_T_ECHO_REPLY:
59828aafed6Srzalamena 		break;
59928aafed6Srzalamena 	case OFP_T_FEATURES_REQUEST:
60028aafed6Srzalamena 		break;
60128aafed6Srzalamena 	case OFP_T_FEATURES_REPLY:
60228aafed6Srzalamena 		ofp_print_featuresreply(bp, length);
60328aafed6Srzalamena 		break;
60428aafed6Srzalamena 	case OFP_T_SET_CONFIG:
60528aafed6Srzalamena 		ofp_print_setconfig(bp, length);
60628aafed6Srzalamena 		break;
60728aafed6Srzalamena 	case OFP_T_PACKET_IN:
60828aafed6Srzalamena 		ofp_print_packetin(bp, length);
60928aafed6Srzalamena 		break;
61028aafed6Srzalamena 	case OFP_T_FLOW_REMOVED:
61128aafed6Srzalamena 		ofp_print_flowremoved(bp, length);
61228aafed6Srzalamena 		break;
61328aafed6Srzalamena 	case OFP_T_PACKET_OUT:
61428aafed6Srzalamena 		ofp_print_packetout(bp, length);
61528aafed6Srzalamena 		break;
61628aafed6Srzalamena 	case OFP_T_FLOW_MOD:
61728aafed6Srzalamena 		ofp_print_flowmod(bp, length);
61828aafed6Srzalamena 		break;
61928aafed6Srzalamena 	}
62028aafed6Srzalamena }
62128aafed6Srzalamena 
62228aafed6Srzalamena void
oxm_print_byte(const u_char * bp,u_int length,int hasmask,int hex)62328aafed6Srzalamena oxm_print_byte(const u_char *bp, u_int length, int hasmask, int hex)
62428aafed6Srzalamena {
62528aafed6Srzalamena 	uint8_t		*b;
62628aafed6Srzalamena 
62728aafed6Srzalamena 	if (length < sizeof(*b)) {
628814a7e6dSreyk 		printf("[|OpenFlow]");
62928aafed6Srzalamena 		return;
63028aafed6Srzalamena 	}
63128aafed6Srzalamena 
63228aafed6Srzalamena 	b = (uint8_t *)bp;
63328aafed6Srzalamena 	if (hex)
63428aafed6Srzalamena 		printf("%#02x", ntohs(*b));
63528aafed6Srzalamena 	else
63628aafed6Srzalamena 		printf("%u", ntohs(*b));
63728aafed6Srzalamena 
63828aafed6Srzalamena 	if (hasmask) {
63928aafed6Srzalamena 		bp += sizeof(*b);
64028aafed6Srzalamena 		length -= sizeof(*b);
64128aafed6Srzalamena 		printf(" mask ");
6423dc0e679Srzalamena 		oxm_print_byte(bp, length, 0, 1);
64328aafed6Srzalamena 	}
64428aafed6Srzalamena }
64528aafed6Srzalamena 
64628aafed6Srzalamena void
oxm_print_halfword(const u_char * bp,u_int length,int hasmask,int hex)64728aafed6Srzalamena oxm_print_halfword(const u_char *bp, u_int length, int hasmask, int hex)
64828aafed6Srzalamena {
64928aafed6Srzalamena 	uint16_t	*h;
65028aafed6Srzalamena 
65128aafed6Srzalamena 	if (length < sizeof(*h)) {
652814a7e6dSreyk 		printf("[|OpenFlow]");
65328aafed6Srzalamena 		return;
65428aafed6Srzalamena 	}
65528aafed6Srzalamena 
65628aafed6Srzalamena 	h = (uint16_t *)bp;
65728aafed6Srzalamena 	if (hex)
65828aafed6Srzalamena 		printf("%#04x", ntohs(*h));
65928aafed6Srzalamena 	else
66028aafed6Srzalamena 		printf("%u", ntohs(*h));
66128aafed6Srzalamena 
66228aafed6Srzalamena 	if (hasmask) {
66328aafed6Srzalamena 		bp += sizeof(*h);
66428aafed6Srzalamena 		length -= sizeof(*h);
66528aafed6Srzalamena 		printf(" mask ");
6663dc0e679Srzalamena 		oxm_print_halfword(bp, length, 0, 1);
66728aafed6Srzalamena 	}
66828aafed6Srzalamena }
66928aafed6Srzalamena 
67028aafed6Srzalamena void
oxm_print_word(const u_char * bp,u_int length,int hasmask,int hex)67128aafed6Srzalamena oxm_print_word(const u_char *bp, u_int length, int hasmask, int hex)
67228aafed6Srzalamena {
67328aafed6Srzalamena 	uint32_t	*w;
67428aafed6Srzalamena 
67528aafed6Srzalamena 	if (length < sizeof(*w)) {
676814a7e6dSreyk 		printf("[|OpenFlow]");
67728aafed6Srzalamena 		return;
67828aafed6Srzalamena 	}
67928aafed6Srzalamena 
68028aafed6Srzalamena 	w = (uint32_t *)bp;
68128aafed6Srzalamena 	if (hex)
68228aafed6Srzalamena 		printf("%#08x", ntohl(*w));
68328aafed6Srzalamena 	else
68428aafed6Srzalamena 		printf("%u", ntohl(*w));
68528aafed6Srzalamena 
68628aafed6Srzalamena 	if (hasmask) {
68728aafed6Srzalamena 		bp += sizeof(*w);
68828aafed6Srzalamena 		length -= sizeof(*w);
68928aafed6Srzalamena 		printf(" mask ");
69028aafed6Srzalamena 		oxm_print_word(bp, length, 0, 1);
69128aafed6Srzalamena 	}
69228aafed6Srzalamena }
69328aafed6Srzalamena 
69428aafed6Srzalamena void
oxm_print_quad(const u_char * bp,u_int length,int hasmask,int hex)69528aafed6Srzalamena oxm_print_quad(const u_char *bp, u_int length, int hasmask, int hex)
69628aafed6Srzalamena {
69728aafed6Srzalamena 	uint64_t	*q;
69828aafed6Srzalamena 
69928aafed6Srzalamena 	if (length < sizeof(*q)) {
700814a7e6dSreyk 		printf("[|OpenFlow]");
70128aafed6Srzalamena 		return;
70228aafed6Srzalamena 	}
70328aafed6Srzalamena 
70428aafed6Srzalamena 	q = (uint64_t *)bp;
70528aafed6Srzalamena 	if (hex)
70628aafed6Srzalamena 		printf("%#016llx", be64toh(*q));
70728aafed6Srzalamena 	else
70828aafed6Srzalamena 		printf("%llu", be64toh(*q));
70928aafed6Srzalamena 
71028aafed6Srzalamena 	if (hasmask) {
71128aafed6Srzalamena 		bp += sizeof(*q);
71228aafed6Srzalamena 		length -= sizeof(*q);
71328aafed6Srzalamena 		printf(" mask ");
71428aafed6Srzalamena 		oxm_print_quad(bp, length, 0, 1);
71528aafed6Srzalamena 	}
71628aafed6Srzalamena }
71728aafed6Srzalamena 
71828aafed6Srzalamena void
oxm_print_ether(const u_char * bp,u_int length,int hasmask)71928aafed6Srzalamena oxm_print_ether(const u_char *bp, u_int length, int hasmask)
72028aafed6Srzalamena {
72128aafed6Srzalamena 	if (length < ETHER_HDR_LEN) {
722814a7e6dSreyk 		printf("[|OpenFlow]");
72328aafed6Srzalamena 		return;
72428aafed6Srzalamena 	}
72528aafed6Srzalamena 
726980a59dcSjca 	printf("%s", etheraddr_string(bp));
72728aafed6Srzalamena 
72828aafed6Srzalamena 	if (hasmask) {
72928aafed6Srzalamena 		bp += ETHER_ADDR_LEN;
73028aafed6Srzalamena 		length -= ETHER_ADDR_LEN;
73128aafed6Srzalamena 		printf(" mask ");
73228aafed6Srzalamena 		oxm_print_ether(bp, length, 0);
73328aafed6Srzalamena 	}
73428aafed6Srzalamena }
73528aafed6Srzalamena 
73628aafed6Srzalamena void
oxm_print_data(const u_char * bp,u_int length,int hasmask,size_t datalen)73728aafed6Srzalamena oxm_print_data(const u_char *bp, u_int length, int hasmask, size_t datalen)
73828aafed6Srzalamena {
73928aafed6Srzalamena 	uint8_t		*ptr;
74028aafed6Srzalamena 	int		 i;
74128aafed6Srzalamena 	char		 hex[8];
74228aafed6Srzalamena 
74328aafed6Srzalamena 	if (length < datalen) {
744814a7e6dSreyk 		printf("[|OpenFlow]");
74528aafed6Srzalamena 		return;
74628aafed6Srzalamena 	}
74728aafed6Srzalamena 
74828aafed6Srzalamena 	ptr = (uint8_t *)bp;
74928aafed6Srzalamena 	for (i = 0; i < datalen; i++) {
75028aafed6Srzalamena 		snprintf(hex, sizeof(hex), "%02x", ptr[i]);
75128aafed6Srzalamena 		printf("%s", hex);
75228aafed6Srzalamena 	}
75328aafed6Srzalamena 
75428aafed6Srzalamena 	if (hasmask) {
75528aafed6Srzalamena 		bp += datalen;
75628aafed6Srzalamena 		length -= datalen;
75728aafed6Srzalamena 		printf(" mask ");
75828aafed6Srzalamena 		oxm_print_data(bp, length, 0, datalen);
75928aafed6Srzalamena 	}
76028aafed6Srzalamena }
76128aafed6Srzalamena 
76228aafed6Srzalamena void
ofp_print_oxm(struct ofp_ox_match * oxm,const u_char * bp,u_int length)76328aafed6Srzalamena ofp_print_oxm(struct ofp_ox_match *oxm, const u_char *bp, u_int length)
76428aafed6Srzalamena {
76528aafed6Srzalamena 	int				 class, field, mask, len;
76628aafed6Srzalamena 	uint16_t			*vlan;
76728aafed6Srzalamena 
76828aafed6Srzalamena 	class = ntohs(oxm->oxm_class);
76928aafed6Srzalamena 	field = OFP_OXM_GET_FIELD(oxm);
77028aafed6Srzalamena 	mask = OFP_OXM_GET_HASMASK(oxm);
77128aafed6Srzalamena 	len = oxm->oxm_length;
772814a7e6dSreyk 	printf(" oxm <class %s field %s hasmask %d length %d",
773814a7e6dSreyk 	    print_map(class, ofp_oxm_c_map),
774814a7e6dSreyk 	    print_map(field, ofp_xm_t_map), mask, len);
77528aafed6Srzalamena 
77628aafed6Srzalamena 	switch (class) {
77728aafed6Srzalamena 	case OFP_OXM_C_OPENFLOW_BASIC:
77828aafed6Srzalamena 		break;
77928aafed6Srzalamena 
78028aafed6Srzalamena 	case OFP_OXM_C_NXM_0:
78128aafed6Srzalamena 	case OFP_OXM_C_NXM_1:
78228aafed6Srzalamena 	case OFP_OXM_C_OPENFLOW_EXPERIMENTER:
78328aafed6Srzalamena 	default:
78428aafed6Srzalamena 		printf(">");
78528aafed6Srzalamena 		return;
78628aafed6Srzalamena 	}
78728aafed6Srzalamena 
78828aafed6Srzalamena 	printf(" value ");
78928aafed6Srzalamena 
79028aafed6Srzalamena 	switch (field) {
79128aafed6Srzalamena 	case OFP_XM_T_IN_PORT:
79228aafed6Srzalamena 	case OFP_XM_T_IN_PHY_PORT:
79328aafed6Srzalamena 	case OFP_XM_T_MPLS_LABEL:
79428aafed6Srzalamena 		oxm_print_word(bp, length, mask, 0);
79528aafed6Srzalamena 		break;
79628aafed6Srzalamena 
79728aafed6Srzalamena 	case OFP_XM_T_META:
79828aafed6Srzalamena 	case OFP_XM_T_TUNNEL_ID:
79928aafed6Srzalamena 		oxm_print_quad(bp, length, mask, 1);
80028aafed6Srzalamena 		break;
80128aafed6Srzalamena 
80228aafed6Srzalamena 	case OFP_XM_T_ETH_DST:
80328aafed6Srzalamena 	case OFP_XM_T_ETH_SRC:
80428aafed6Srzalamena 	case OFP_XM_T_ARP_SHA:
80528aafed6Srzalamena 	case OFP_XM_T_ARP_THA:
80628aafed6Srzalamena 	case OFP_XM_T_IPV6_ND_SLL:
80728aafed6Srzalamena 	case OFP_XM_T_IPV6_ND_TLL:
80828aafed6Srzalamena 		oxm_print_ether(bp, length, mask);
80928aafed6Srzalamena 		break;
81028aafed6Srzalamena 
81128aafed6Srzalamena 	case OFP_XM_T_ETH_TYPE:
81228aafed6Srzalamena 		oxm_print_halfword(bp, length, mask, 1);
81328aafed6Srzalamena 		break;
81428aafed6Srzalamena 
81528aafed6Srzalamena 	case OFP_XM_T_VLAN_VID:
81628aafed6Srzalamena 		/*
81728aafed6Srzalamena 		 * VLAN has an exception: it uses the higher bits to signal
81828aafed6Srzalamena 		 * the presence of the VLAN.
81928aafed6Srzalamena 		 */
82028aafed6Srzalamena 		if (length < sizeof(*vlan)) {
821814a7e6dSreyk 			printf("[|OpenFlow]");
82228aafed6Srzalamena 			break;
82328aafed6Srzalamena 		}
82428aafed6Srzalamena 
82528aafed6Srzalamena 		vlan = (uint16_t *)bp;
82628aafed6Srzalamena 		if (ntohs(*vlan) & OFP_XM_VID_PRESENT)
82728aafed6Srzalamena 			printf("(VLAN %d) ",
82828aafed6Srzalamena 			    ntohs(*vlan) & (~OFP_XM_VID_PRESENT));
82928aafed6Srzalamena 		else
83028aafed6Srzalamena 			printf("(no VLAN) ");
83128aafed6Srzalamena 		/* FALLTHROUGH */
83228aafed6Srzalamena 	case OFP_XM_T_TCP_SRC:
83328aafed6Srzalamena 	case OFP_XM_T_TCP_DST:
83428aafed6Srzalamena 	case OFP_XM_T_UDP_SRC:
83528aafed6Srzalamena 	case OFP_XM_T_UDP_DST:
83628aafed6Srzalamena 	case OFP_XM_T_SCTP_SRC:
83728aafed6Srzalamena 	case OFP_XM_T_SCTP_DST:
83828aafed6Srzalamena 	case OFP_XM_T_ARP_OP:
83928aafed6Srzalamena 	case OFP_XM_T_IPV6_EXTHDR:
84028aafed6Srzalamena 		oxm_print_halfword(bp, length, mask, 0);
84128aafed6Srzalamena 		break;
84228aafed6Srzalamena 
84328aafed6Srzalamena 	case OFP_XM_T_VLAN_PCP:
84428aafed6Srzalamena 	case OFP_XM_T_IP_DSCP:
84528aafed6Srzalamena 	case OFP_XM_T_IP_ECN:
84628aafed6Srzalamena 	case OFP_XM_T_MPLS_TC:
84728aafed6Srzalamena 	case OFP_XM_T_MPLS_BOS:
84828aafed6Srzalamena 		oxm_print_byte(bp, length, mask, 1);
84928aafed6Srzalamena 		break;
85028aafed6Srzalamena 
85128aafed6Srzalamena 	case OFP_XM_T_IPV4_SRC:
85228aafed6Srzalamena 	case OFP_XM_T_IPV4_DST:
85328aafed6Srzalamena 	case OFP_XM_T_ARP_SPA:
85428aafed6Srzalamena 	case OFP_XM_T_ARP_TPA:
85528aafed6Srzalamena 	case OFP_XM_T_IPV6_FLABEL:
85628aafed6Srzalamena 		oxm_print_word(bp, length, mask, 1);
85728aafed6Srzalamena 		break;
85828aafed6Srzalamena 
85928aafed6Srzalamena 	case OFP_XM_T_IP_PROTO:
86028aafed6Srzalamena 	case OFP_XM_T_ICMPV4_TYPE:
86128aafed6Srzalamena 	case OFP_XM_T_ICMPV4_CODE:
86228aafed6Srzalamena 	case OFP_XM_T_ICMPV6_TYPE:
86328aafed6Srzalamena 	case OFP_XM_T_ICMPV6_CODE:
86428aafed6Srzalamena 		oxm_print_byte(bp, length, mask, 0);
86528aafed6Srzalamena 		break;
86628aafed6Srzalamena 
86728aafed6Srzalamena 	case OFP_XM_T_IPV6_SRC:
86828aafed6Srzalamena 	case OFP_XM_T_IPV6_DST:
86928aafed6Srzalamena 	case OFP_XM_T_IPV6_ND_TARGET:
87028aafed6Srzalamena 		oxm_print_data(bp, length, mask, sizeof(struct in6_addr));
87128aafed6Srzalamena 		break;
87228aafed6Srzalamena 
87328aafed6Srzalamena 	case OFP_XM_T_PBB_ISID:
87428aafed6Srzalamena 		oxm_print_data(bp, length, mask, 3);
87528aafed6Srzalamena 		break;
87628aafed6Srzalamena 
87728aafed6Srzalamena 	default:
87828aafed6Srzalamena 		printf("unknown");
87928aafed6Srzalamena 		break;
88028aafed6Srzalamena 	}
88128aafed6Srzalamena 
88228aafed6Srzalamena 	printf(">");
88328aafed6Srzalamena }
88428aafed6Srzalamena 
88528aafed6Srzalamena void
action_print_output(const u_char * bp,u_int length)88628aafed6Srzalamena action_print_output(const u_char *bp, u_int length)
88728aafed6Srzalamena {
88828aafed6Srzalamena 	struct ofp_action_output		*ao;
88928aafed6Srzalamena 
89028aafed6Srzalamena 	if (length < (sizeof(*ao) - AH_UNPADDED)) {
891814a7e6dSreyk 		printf(" [|OpenFlow]");
89228aafed6Srzalamena 		return;
89328aafed6Srzalamena 	}
89428aafed6Srzalamena 
89528aafed6Srzalamena 	ao = (struct ofp_action_output *)(bp - AH_UNPADDED);
896814a7e6dSreyk 	printf(" port %s max_len %s",
897814a7e6dSreyk 	    print_map(ntohl(ao->ao_port), ofp_port_map),
898814a7e6dSreyk 	    print_map(ntohs(ao->ao_max_len), ofp_controller_maxlen_map));
89928aafed6Srzalamena }
90028aafed6Srzalamena 
90128aafed6Srzalamena void
action_print_group(const u_char * bp,u_int length)90228aafed6Srzalamena action_print_group(const u_char *bp, u_int length)
90328aafed6Srzalamena {
90428aafed6Srzalamena 	struct ofp_action_group		*ag;
90528aafed6Srzalamena 
90628aafed6Srzalamena 	if (length < (sizeof(*ag) - AH_UNPADDED)) {
907814a7e6dSreyk 		printf(" [|OpenFlow]");
90828aafed6Srzalamena 		return;
90928aafed6Srzalamena 	}
91028aafed6Srzalamena 
91128aafed6Srzalamena 	ag = (struct ofp_action_group *)(bp - AH_UNPADDED);
912814a7e6dSreyk 	printf(" group_id %s",
913814a7e6dSreyk 	    print_map(ntohl(ag->ag_group_id), ofp_group_id_map));
91428aafed6Srzalamena }
91528aafed6Srzalamena 
91628aafed6Srzalamena void
action_print_setqueue(const u_char * bp,u_int length)91727ad49faSrzalamena action_print_setqueue(const u_char *bp, u_int length)
91827ad49faSrzalamena {
91927ad49faSrzalamena 	struct ofp_action_set_queue	*asq;
92027ad49faSrzalamena 
92127ad49faSrzalamena 	if (length < (sizeof(*asq) - AH_UNPADDED)) {
92227ad49faSrzalamena 		printf(" [|OpenFlow]");
92327ad49faSrzalamena 		return;
92427ad49faSrzalamena 	}
92527ad49faSrzalamena 
92627ad49faSrzalamena 	asq = (struct ofp_action_set_queue *)(bp - AH_UNPADDED);
92727ad49faSrzalamena 	printf(" queue_id %u", ntohl(asq->asq_queue_id));
92827ad49faSrzalamena }
92927ad49faSrzalamena 
93027ad49faSrzalamena void
action_print_setmplsttl(const u_char * bp,u_int length)93128aafed6Srzalamena action_print_setmplsttl(const u_char *bp, u_int length)
93228aafed6Srzalamena {
93328aafed6Srzalamena 	struct ofp_action_mpls_ttl	*amt;
93428aafed6Srzalamena 
93528aafed6Srzalamena 	if (length < (sizeof(*amt) - AH_UNPADDED)) {
936814a7e6dSreyk 		printf(" [|OpenFlow]");
93728aafed6Srzalamena 		return;
93828aafed6Srzalamena 	}
93928aafed6Srzalamena 
94028aafed6Srzalamena 	amt = (struct ofp_action_mpls_ttl *)(bp - AH_UNPADDED);
94128aafed6Srzalamena 	printf(" ttl %d", amt->amt_ttl);
94228aafed6Srzalamena }
94328aafed6Srzalamena 
94428aafed6Srzalamena void
action_print_setnwttl(const u_char * bp,u_int length)94528aafed6Srzalamena action_print_setnwttl(const u_char *bp, u_int length)
94628aafed6Srzalamena {
94728aafed6Srzalamena 	struct ofp_action_nw_ttl	*ant;
94828aafed6Srzalamena 
94928aafed6Srzalamena 	if (length < (sizeof(*ant) - AH_UNPADDED)) {
950814a7e6dSreyk 		printf(" [|OpenFlow]");
95128aafed6Srzalamena 		return;
95228aafed6Srzalamena 	}
95328aafed6Srzalamena 
95428aafed6Srzalamena 	ant = (struct ofp_action_nw_ttl *)(bp - AH_UNPADDED);
95528aafed6Srzalamena 	printf(" ttl %d", ant->ant_ttl);
95628aafed6Srzalamena }
95728aafed6Srzalamena 
95828aafed6Srzalamena void
action_print_push(const u_char * bp,u_int length)95928aafed6Srzalamena action_print_push(const u_char *bp, u_int length)
96028aafed6Srzalamena {
96128aafed6Srzalamena 	struct ofp_action_push		*ap;
96228aafed6Srzalamena 
96328aafed6Srzalamena 	if (length < (sizeof(*ap) - AH_UNPADDED)) {
964814a7e6dSreyk 		printf(" [|OpenFlow]");
96528aafed6Srzalamena 		return;
96628aafed6Srzalamena 	}
96728aafed6Srzalamena 
96828aafed6Srzalamena 	ap = (struct ofp_action_push *)(bp - AH_UNPADDED);
96928aafed6Srzalamena 	printf(" ethertype %#04x", ntohs(ap->ap_ethertype));
97028aafed6Srzalamena }
97128aafed6Srzalamena 
97228aafed6Srzalamena void
action_print_popmpls(const u_char * bp,u_int length)97328aafed6Srzalamena action_print_popmpls(const u_char *bp, u_int length)
97428aafed6Srzalamena {
97528aafed6Srzalamena 	struct ofp_action_pop_mpls	*apm;
97628aafed6Srzalamena 
97728aafed6Srzalamena 	if (length < (sizeof(*apm) - AH_UNPADDED)) {
978814a7e6dSreyk 		printf(" [|OpenFlow]");
97928aafed6Srzalamena 		return;
98028aafed6Srzalamena 	}
98128aafed6Srzalamena 
98228aafed6Srzalamena 	apm = (struct ofp_action_pop_mpls *)(bp - AH_UNPADDED);
98328aafed6Srzalamena 	printf(" ethertype %#04x", ntohs(apm->apm_ethertype));
98428aafed6Srzalamena }
98528aafed6Srzalamena 
98628aafed6Srzalamena void
action_print_setfield(const u_char * bp,u_int length)98728aafed6Srzalamena action_print_setfield(const u_char *bp, u_int length)
98828aafed6Srzalamena {
98928aafed6Srzalamena 	struct ofp_action_set_field	*asf;
99028aafed6Srzalamena 	int				 omlen;
99128aafed6Srzalamena 
99228aafed6Srzalamena 	if (length < (sizeof(*asf) - AH_UNPADDED)) {
993814a7e6dSreyk 		printf(" [|OpenFlow]");
99428aafed6Srzalamena 		return;
99528aafed6Srzalamena 	}
99628aafed6Srzalamena 
99728aafed6Srzalamena 	asf = (struct ofp_action_set_field *)(bp - AH_UNPADDED);
99828aafed6Srzalamena 	omlen = ntohs(asf->asf_len) - AH_UNPADDED;
99928aafed6Srzalamena 	if (omlen == 0)
100028aafed6Srzalamena 		return;
100128aafed6Srzalamena 
1002*c74ea871Sakoshibe 	ofp_print_oxm_field(bp, length, omlen, 1);
100328aafed6Srzalamena }
100428aafed6Srzalamena 
100528aafed6Srzalamena void
ofp_print_action(struct ofp_action_header * ah,const u_char * bp,u_int length)100628aafed6Srzalamena ofp_print_action(struct ofp_action_header *ah, const u_char *bp, u_int length)
100728aafed6Srzalamena {
100828aafed6Srzalamena 	int			ahtype;
100928aafed6Srzalamena 
101028aafed6Srzalamena 	ahtype = ntohs(ah->ah_type);
1011814a7e6dSreyk 	printf(" action <type %s length %d",
1012814a7e6dSreyk 	    print_map(ahtype, ofp_action_map), ntohs(ah->ah_len));
101328aafed6Srzalamena 
101428aafed6Srzalamena 	switch (ahtype) {
101528aafed6Srzalamena 	case OFP_ACTION_OUTPUT:
101628aafed6Srzalamena 		action_print_output(bp, length);
101728aafed6Srzalamena 		break;
101828aafed6Srzalamena 
101928aafed6Srzalamena 	case OFP_ACTION_GROUP:
102028aafed6Srzalamena 		action_print_group(bp, length);
102128aafed6Srzalamena 		break;
102228aafed6Srzalamena 
102328aafed6Srzalamena 	case OFP_ACTION_SET_QUEUE:
102427ad49faSrzalamena 		action_print_setqueue(bp, length);
102528aafed6Srzalamena 		break;
102628aafed6Srzalamena 
102728aafed6Srzalamena 	case OFP_ACTION_SET_MPLS_TTL:
102828aafed6Srzalamena 		action_print_setmplsttl(bp, length);
102928aafed6Srzalamena 		break;
103028aafed6Srzalamena 
103128aafed6Srzalamena 	case OFP_ACTION_SET_NW_TTL:
103228aafed6Srzalamena 		action_print_setnwttl(bp, length);
103328aafed6Srzalamena 		break;
103428aafed6Srzalamena 
103528aafed6Srzalamena 	case OFP_ACTION_PUSH_VLAN:
103628aafed6Srzalamena 	case OFP_ACTION_PUSH_MPLS:
103728aafed6Srzalamena 	case OFP_ACTION_PUSH_PBB:
103828aafed6Srzalamena 		action_print_push(bp, length);
103928aafed6Srzalamena 		break;
104028aafed6Srzalamena 
104128aafed6Srzalamena 	case OFP_ACTION_POP_MPLS:
104228aafed6Srzalamena 		action_print_popmpls(bp, length);
104328aafed6Srzalamena 		break;
104428aafed6Srzalamena 
104528aafed6Srzalamena 	case OFP_ACTION_SET_FIELD:
1046*c74ea871Sakoshibe 		action_print_setfield(bp, length);
104728aafed6Srzalamena 		break;
104828aafed6Srzalamena 
104928aafed6Srzalamena 	case OFP_ACTION_COPY_TTL_OUT:
105028aafed6Srzalamena 	case OFP_ACTION_COPY_TTL_IN:
105128aafed6Srzalamena 	case OFP_ACTION_DEC_NW_TTL:
105228aafed6Srzalamena 	case OFP_ACTION_DEC_MPLS_TTL:
105328aafed6Srzalamena 	case OFP_ACTION_POP_VLAN:
105428aafed6Srzalamena 	case OFP_ACTION_POP_PBB:
105528aafed6Srzalamena 	case OFP_ACTION_EXPERIMENTER:
105628aafed6Srzalamena 	default:
105728aafed6Srzalamena 		/* Generic header, nothing to show here. */
105828aafed6Srzalamena 		break;
105928aafed6Srzalamena 	}
106028aafed6Srzalamena 
106128aafed6Srzalamena 	printf(">");
106228aafed6Srzalamena }
106328aafed6Srzalamena 
106428aafed6Srzalamena void
instruction_print_gototable(const char * bp,u_int length)106528aafed6Srzalamena instruction_print_gototable(const char *bp, u_int length)
106628aafed6Srzalamena {
106728aafed6Srzalamena 	struct ofp_instruction_goto_table	*igt;
106828aafed6Srzalamena 
106928aafed6Srzalamena 	if (length < (sizeof(*igt) - sizeof(struct ofp_instruction))) {
1070814a7e6dSreyk 		printf(" [|OpenFlow]");
107128aafed6Srzalamena 		return;
107228aafed6Srzalamena 	}
107328aafed6Srzalamena 
107428aafed6Srzalamena 	igt = (struct ofp_instruction_goto_table *)
107528aafed6Srzalamena 	    (bp - sizeof(struct ofp_instruction));
107628aafed6Srzalamena 	printf(" table_id %d", igt->igt_table_id);
107728aafed6Srzalamena }
107828aafed6Srzalamena 
107928aafed6Srzalamena void
instruction_print_meta(const char * bp,u_int length)108028aafed6Srzalamena instruction_print_meta(const char *bp, u_int length)
108128aafed6Srzalamena {
108228aafed6Srzalamena 	struct ofp_instruction_write_metadata	*iwm;
108328aafed6Srzalamena 
108428aafed6Srzalamena 	if (length < (sizeof(*iwm) - sizeof(struct ofp_instruction))) {
1085814a7e6dSreyk 		printf(" [|OpenFlow]");
108628aafed6Srzalamena 		return;
108728aafed6Srzalamena 	}
108828aafed6Srzalamena 
108928aafed6Srzalamena 	iwm = (struct ofp_instruction_write_metadata *)
109028aafed6Srzalamena 	    (bp - sizeof(struct ofp_instruction));
109128aafed6Srzalamena 	printf(" metadata %llu metadata_mask %llu",
109228aafed6Srzalamena 	    be64toh(iwm->iwm_metadata), be64toh(iwm->iwm_metadata_mask));
109328aafed6Srzalamena }
109428aafed6Srzalamena 
109528aafed6Srzalamena void
instruction_print_actions(const char * bp,u_int length)109628aafed6Srzalamena instruction_print_actions(const char *bp, u_int length)
109728aafed6Srzalamena {
109828aafed6Srzalamena 	struct ofp_instruction_actions		*ia;
109928aafed6Srzalamena 	struct ofp_action_header		*ah;
110028aafed6Srzalamena 	int					 actionslen;
110128aafed6Srzalamena 	unsigned int				 ahlen;
110228aafed6Srzalamena 
110328aafed6Srzalamena 	if (length < (sizeof(*ia) - sizeof(struct ofp_instruction))) {
1104814a7e6dSreyk 		printf(" [|OpenFlow]");
110528aafed6Srzalamena 		return;
110628aafed6Srzalamena 	}
110728aafed6Srzalamena 
110828aafed6Srzalamena 	ia = (struct ofp_instruction_actions *)
110928aafed6Srzalamena 	    (bp - sizeof(struct ofp_instruction));
111028aafed6Srzalamena 
111128aafed6Srzalamena 	actionslen = ntohs(ia->ia_len) - sizeof(*ia);
111228aafed6Srzalamena 	if (actionslen <= 0)
111328aafed6Srzalamena 		return;
111428aafed6Srzalamena 
111528aafed6Srzalamena 	bp += sizeof(*ia) - sizeof(struct ofp_instruction);
111628aafed6Srzalamena 	length -= sizeof(*ia) - sizeof(struct ofp_instruction);
111728aafed6Srzalamena 
111828aafed6Srzalamena parse_next_action:
111928aafed6Srzalamena 	if (length < sizeof(*ah)) {
1120814a7e6dSreyk 		printf(" [|OpenFlow]");
112128aafed6Srzalamena 		return;
112228aafed6Srzalamena 	}
112328aafed6Srzalamena 
112428aafed6Srzalamena 	ah = (struct ofp_action_header *)bp;
112528aafed6Srzalamena 	bp += AH_UNPADDED;
112628aafed6Srzalamena 	length -= AH_UNPADDED;
112728aafed6Srzalamena 	actionslen -= AH_UNPADDED;
112828aafed6Srzalamena 	ahlen = ntohs(ah->ah_len) - AH_UNPADDED;
112928aafed6Srzalamena 	if (length < ahlen) {
1130814a7e6dSreyk 		printf(" [|OpenFlow]");
113128aafed6Srzalamena 		return;
113228aafed6Srzalamena 	}
113328aafed6Srzalamena 
113428aafed6Srzalamena 	ofp_print_action(ah, bp, length);
113528aafed6Srzalamena 
113628aafed6Srzalamena 	bp += ahlen;
113728aafed6Srzalamena 	length -= ahlen;
113828aafed6Srzalamena 	actionslen -= min(ahlen, actionslen);
113928aafed6Srzalamena 	if (actionslen)
114028aafed6Srzalamena 		goto parse_next_action;
114128aafed6Srzalamena }
114228aafed6Srzalamena 
114328aafed6Srzalamena void
instruction_print_meter(const char * bp,u_int length)114428aafed6Srzalamena instruction_print_meter(const char *bp, u_int length)
114528aafed6Srzalamena {
114628aafed6Srzalamena 	struct ofp_instruction_meter		*im;
114728aafed6Srzalamena 
114828aafed6Srzalamena 	if (length < (sizeof(*im) - sizeof(struct ofp_instruction))) {
1149814a7e6dSreyk 		printf(" [|OpenFlow]");
115028aafed6Srzalamena 		return;
115128aafed6Srzalamena 	}
115228aafed6Srzalamena 
115328aafed6Srzalamena 	im = (struct ofp_instruction_meter *)
115428aafed6Srzalamena 	    (bp - sizeof(struct ofp_instruction));
115528aafed6Srzalamena 	printf(" meter_id %u", ntohl(im->im_meter_id));
115628aafed6Srzalamena }
115728aafed6Srzalamena 
115828aafed6Srzalamena void
instruction_print_experimenter(const char * bp,u_int length)115928aafed6Srzalamena instruction_print_experimenter(const char *bp, u_int length)
116028aafed6Srzalamena {
116128aafed6Srzalamena 	struct ofp_instruction_experimenter		*ie;
116228aafed6Srzalamena 
116328aafed6Srzalamena 	if (length < (sizeof(*ie) - sizeof(struct ofp_instruction))) {
1164814a7e6dSreyk 		printf(" [|OpenFlow]");
116528aafed6Srzalamena 		return;
116628aafed6Srzalamena 	}
116728aafed6Srzalamena 
116828aafed6Srzalamena 	ie = (struct ofp_instruction_experimenter *)
116928aafed6Srzalamena 	    (bp - sizeof(struct ofp_instruction));
117028aafed6Srzalamena 	printf(" experimenter %u", ntohl(ie->ie_experimenter));
117128aafed6Srzalamena }
117228aafed6Srzalamena 
117328aafed6Srzalamena void
ofp_print_instruction(struct ofp_instruction * i,const char * bp,u_int length)117428aafed6Srzalamena ofp_print_instruction(struct ofp_instruction *i, const char *bp, u_int length)
117528aafed6Srzalamena {
117628aafed6Srzalamena 	int			itype;
117728aafed6Srzalamena 
117828aafed6Srzalamena 	itype = ntohs(i->i_type);
1179814a7e6dSreyk 	printf(" instruction <type %s length %d",
1180814a7e6dSreyk 	    print_map(itype, ofp_instruction_t_map), ntohs(i->i_len));
118128aafed6Srzalamena 
118228aafed6Srzalamena 	switch (itype) {
118328aafed6Srzalamena 	case OFP_INSTRUCTION_T_GOTO_TABLE:
118428aafed6Srzalamena 		instruction_print_gototable(bp, length);
118528aafed6Srzalamena 		break;
118628aafed6Srzalamena 	case OFP_INSTRUCTION_T_WRITE_META:
118728aafed6Srzalamena 		instruction_print_meta(bp, length);
118828aafed6Srzalamena 		break;
118928aafed6Srzalamena 	case OFP_INSTRUCTION_T_WRITE_ACTIONS:
119028aafed6Srzalamena 	case OFP_INSTRUCTION_T_APPLY_ACTIONS:
119128aafed6Srzalamena 	case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
119228aafed6Srzalamena 		instruction_print_actions(bp, length);
119328aafed6Srzalamena 		break;
119428aafed6Srzalamena 	case OFP_INSTRUCTION_T_METER:
119528aafed6Srzalamena 		instruction_print_meter(bp, length);
119628aafed6Srzalamena 		break;
119728aafed6Srzalamena 	case OFP_INSTRUCTION_T_EXPERIMENTER:
119828aafed6Srzalamena 		instruction_print_meter(bp, length);
119928aafed6Srzalamena 		break;
120028aafed6Srzalamena 	}
120128aafed6Srzalamena 
120228aafed6Srzalamena 	printf(">");
120328aafed6Srzalamena }
1204