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 * 71 print_map(unsigned int type, struct constmap *map) 72 { 73 unsigned int i; 74 #define CYCLE_BUFFERS 8 75 static char buf[CYCLE_BUFFERS][32]; 76 static int idx = 0; 77 const char *name = NULL; 78 79 if (idx >= CYCLE_BUFFERS) 80 idx = 0; 81 memset(buf[idx], 0, sizeof(buf[idx])); 82 83 for (i = 0; map[i].cm_name != NULL; i++) { 84 if (map[i].cm_type == type) { 85 name = map[i].cm_name; 86 break; 87 } 88 } 89 90 if (name == NULL) 91 snprintf(buf[idx], sizeof(buf[idx]), "%u", type); 92 else if (vflag > 1) 93 snprintf(buf[idx], sizeof(buf[idx]), "%s[%u]", name, type); 94 else 95 strlcpy(buf[idx], name, sizeof(buf[idx])); 96 97 return (buf[idx++]); 98 } 99 100 void 101 ofp_print_hello(const u_char *bp, u_int length, u_int ohlen) 102 { 103 struct ofp_hello_element_header *he; 104 int hetype, helen, ver, i; 105 int vmajor, vminor; 106 uint32_t bmp; 107 108 /* Skip the OFP header. */ 109 bp += sizeof(struct ofp_header); 110 length -= sizeof(struct ofp_header); 111 112 /* Check for header truncation. */ 113 if (ohlen > sizeof(struct ofp_header) && 114 length < sizeof(*he)) { 115 printf(" [|OpenFlow]"); 116 return; 117 } 118 119 next_header: 120 /* Check for hello element headers. */ 121 if (length < sizeof(*he)) 122 return; 123 124 he = (struct ofp_hello_element_header *)bp; 125 hetype = ntohs(he->he_type); 126 helen = ntohs(he->he_length); 127 128 bp += sizeof(*he); 129 length -= sizeof(*he); 130 helen -= sizeof(*he); 131 132 switch (hetype) { 133 case OFP_HELLO_T_VERSION_BITMAP: 134 printf(" version bitmap <"); 135 if (helen < sizeof(bmp)) { 136 printf("invalid header>"); 137 break; 138 } 139 140 next_bitmap: 141 if (length < sizeof(bmp)) { 142 printf("[|OpenFlow]>"); 143 break; 144 } 145 146 bmp = ntohl(*(uint32_t *)bp); 147 for (i = 0, ver = 9; i < 32; i++, ver++) { 148 if ((bmp & (1 << i)) == 0) 149 continue; 150 151 vmajor = (ver / 10); 152 vminor = ver % 10; 153 printf("v%d.%d ", vmajor, vminor); 154 } 155 helen -= min(sizeof(bmp), helen); 156 length -= sizeof(bmp); 157 bp += sizeof(bmp); 158 if (helen) 159 goto next_bitmap; 160 161 printf("\b>"); 162 break; 163 164 default: 165 printf(" element header[type %d length %d]", hetype, helen); 166 break; 167 } 168 169 length -= min(helen, length); 170 bp += helen; 171 if (length) 172 goto next_header; 173 } 174 175 void 176 ofp_print_error(const u_char *bp, u_int length) 177 { 178 struct ofp_error *err; 179 180 if (length < sizeof(*err)) { 181 printf(" [|OpenFlow]"); 182 return; 183 } 184 185 err = (struct ofp_error *)bp; 186 printf(" <type %s code %d>", 187 print_map(ntohs(err->err_type), ofp_errtype_map), 188 ntohs(err->err_code)); 189 190 length -= min(sizeof(*err), length); 191 bp += sizeof(*err); 192 /* If there are still bytes left, print the optional error data. */ 193 if (length) { 194 printf(" error data"); 195 ofp_print(bp, length); 196 } 197 } 198 199 void 200 ofp_print_featuresreply(const u_char *bp, u_int length) 201 { 202 struct ofp_switch_features *swf; 203 204 if (length < sizeof(*swf)) { 205 printf(" [trucanted]"); 206 return; 207 } 208 209 swf = (struct ofp_switch_features *)bp; 210 printf(" <datapath_id %#016llx nbuffers %u ntables %d aux_id %d " 211 "capabilities %#08x>", 212 be64toh(swf->swf_datapath_id), ntohl(swf->swf_nbuffers), 213 swf->swf_ntables, swf->swf_aux_id, 214 ntohl(swf->swf_capabilities)); 215 } 216 217 void 218 ofp_print_setconfig(const u_char *bp, u_int length) 219 { 220 struct ofp_switch_config *cfg; 221 222 if (length < sizeof(*cfg)) { 223 printf(" [|OpenFlow]"); 224 return; 225 } 226 227 cfg = (struct ofp_switch_config *)bp; 228 printf(" <flags %#04x miss_send_len %s>", 229 ntohs(cfg->cfg_flags), 230 print_map(ntohs(cfg->cfg_miss_send_len), 231 ofp_controller_maxlen_map)); 232 } 233 234 void 235 ofp_print_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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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