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