1 /* $OpenBSD: print-ofp.c,v 1.11 2016/11/28 17:47:15 jca Exp $ */ 2 3 /* 4 * Copyright (c) 2016 Rafael Zalamena <rzalamena@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <net/ofp.h> 20 21 #include <endian.h> 22 #include <stddef.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <pcap.h> 26 27 #include "addrtoname.h" 28 #include "extract.h" 29 #include "interface.h" 30 #include "ofp_map.h" 31 32 /* Size of action header without the padding. */ 33 #define AH_UNPADDED (offsetof(struct ofp_action_header, ah_pad)) 34 35 const char * 36 print_map(unsigned int, struct constmap *); 37 38 void ofp_print_hello(const u_char *, u_int, u_int); 39 void ofp_print_featuresreply(const u_char *, u_int); 40 void ofp_print_setconfig(const u_char *, u_int); 41 void ofp_print_packetin(const u_char *, u_int); 42 void ofp_print_packetout(const u_char *, u_int); 43 void ofp_print_flowremoved(const u_char *, u_int); 44 void ofp_print_flowmod(const u_char *, u_int); 45 46 void oxm_print_halfword(const u_char *, u_int, int, int); 47 void oxm_print_word(const u_char *, u_int, int, int); 48 void oxm_print_quad(const u_char *, u_int, int, int); 49 void oxm_print_ether(const u_char *, u_int, int); 50 void ofp_print_oxm(struct ofp_ox_match *, const u_char *, u_int); 51 52 void action_print_output(const u_char *, u_int); 53 void action_print_group(const u_char *, u_int); 54 void action_print_setqueue(const u_char *, u_int); 55 void action_print_setmplsttl(const u_char *, u_int); 56 void action_print_setnwttl(const u_char *, u_int); 57 void action_print_push(const u_char *, u_int); 58 void action_print_popmpls(const u_char *, u_int); 59 void action_print_setfield(const u_char *, u_int); 60 void ofp_print_action(struct ofp_action_header *, const u_char *, 61 u_int); 62 63 void instruction_print_gototable(const char *, u_int); 64 void instruction_print_meta(const char *, u_int); 65 void instruction_print_actions(const char *, u_int); 66 void instruction_print_meter(const char *, u_int); 67 void instruction_print_experimenter(const char *, u_int); 68 void ofp_print_instruction(struct ofp_instruction *, const char *, u_int); 69 70 const char * 71 print_map(unsigned int type, struct constmap *map) 72 { 73 unsigned int i; 74 #define CYCLE_BUFFERS 8 75 static char buf[CYCLE_BUFFERS][32]; 76 static int idx = 0; 77 const char *name = NULL; 78 79 if (idx >= CYCLE_BUFFERS) 80 idx = 0; 81 memset(buf[idx], 0, sizeof(buf[idx])); 82 83 for (i = 0; map[i].cm_name != NULL; i++) { 84 if (map[i].cm_type == type) { 85 name = map[i].cm_name; 86 break; 87 } 88 } 89 90 if (name == NULL) 91 snprintf(buf[idx], sizeof(buf[idx]), "%u", type); 92 else if (vflag > 1) 93 snprintf(buf[idx], sizeof(buf[idx]), "%s[%u]", name, type); 94 else 95 strlcpy(buf[idx], name, sizeof(buf[idx])); 96 97 return (buf[idx++]); 98 } 99 100 void 101 ofp_print_hello(const u_char *bp, u_int length, u_int ohlen) 102 { 103 struct ofp_hello_element_header *he; 104 int hetype, helen, ver, i; 105 int vmajor, vminor; 106 uint32_t bmp; 107 108 /* Skip the OFP header. */ 109 bp += sizeof(struct ofp_header); 110 length -= sizeof(struct ofp_header); 111 112 /* Check for header truncation. */ 113 if (ohlen > sizeof(struct ofp_header) && 114 length < sizeof(*he)) { 115 printf(" [|OpenFlow]"); 116 return; 117 } 118 119 next_header: 120 /* Check for hello element headers. */ 121 if (length < sizeof(*he)) 122 return; 123 124 he = (struct ofp_hello_element_header *)bp; 125 hetype = ntohs(he->he_type); 126 helen = ntohs(he->he_length); 127 128 bp += sizeof(*he); 129 length -= sizeof(*he); 130 helen -= sizeof(*he); 131 132 switch (hetype) { 133 case OFP_HELLO_T_VERSION_BITMAP: 134 printf(" version bitmap <"); 135 if (helen < sizeof(bmp)) { 136 printf("invalid header>"); 137 break; 138 } 139 140 next_bitmap: 141 if (length < sizeof(bmp)) { 142 printf("[|OpenFlow]>"); 143 break; 144 } 145 146 bmp = ntohl(*(uint32_t *)bp); 147 for (i = 0, ver = 9; i < 32; i++, ver++) { 148 if ((bmp & (1 << i)) == 0) 149 continue; 150 151 vmajor = (ver / 10); 152 vminor = ver % 10; 153 printf("v%d.%d ", vmajor, vminor); 154 } 155 helen -= min(sizeof(bmp), helen); 156 length -= sizeof(bmp); 157 bp += sizeof(bmp); 158 if (helen) 159 goto next_bitmap; 160 161 printf("\b>"); 162 break; 163 164 default: 165 printf(" element header[type %d length %d]", hetype, helen); 166 break; 167 } 168 169 length -= min(helen, length); 170 bp += helen; 171 if (length) 172 goto next_header; 173 } 174 175 void 176 ofp_print_error(const u_char *bp, u_int length) 177 { 178 struct ofp_error *err; 179 180 if (length < sizeof(*err)) { 181 printf(" [|OpenFlow]"); 182 return; 183 } 184 185 err = (struct ofp_error *)bp; 186 printf(" <type %s code %d>", 187 print_map(ntohs(err->err_type), ofp_errtype_map), 188 ntohs(err->err_code)); 189 190 length -= min(sizeof(*err), length); 191 bp += sizeof(*err); 192 /* If there are still bytes left, print the optional error data. */ 193 if (length) { 194 printf(" error data"); 195 ofp_print(bp, length); 196 } 197 } 198 199 void 200 ofp_print_featuresreply(const u_char *bp, u_int length) 201 { 202 struct ofp_switch_features *swf; 203 204 if (length < sizeof(*swf)) { 205 printf(" [trucanted]"); 206 return; 207 } 208 209 swf = (struct ofp_switch_features *)bp; 210 printf(" <datapath_id %#016llx nbuffers %u ntables %d aux_id %d " 211 "capabilities %#08x>", 212 be64toh(swf->swf_datapath_id), ntohl(swf->swf_nbuffers), 213 swf->swf_ntables, swf->swf_aux_id, 214 ntohl(swf->swf_capabilities)); 215 } 216 217 void 218 ofp_print_setconfig(const u_char *bp, u_int length) 219 { 220 struct ofp_switch_config *cfg; 221 222 if (length < sizeof(*cfg)) { 223 printf(" [|OpenFlow]"); 224 return; 225 } 226 227 cfg = (struct ofp_switch_config *)bp; 228 printf(" <flags %#04x miss_send_len %s>", 229 ntohs(cfg->cfg_flags), 230 print_map(ntohs(cfg->cfg_miss_send_len), 231 ofp_controller_maxlen_map)); 232 } 233 234 void 235 ofp_print_packetin(const u_char *bp, u_int length) 236 { 237 struct ofp_packet_in *pin; 238 struct ofp_ox_match *oxm; 239 int omtype, omlen; 240 int haspacket = 0; 241 const u_char *pktptr; 242 243 if (length < sizeof(*pin)) { 244 printf(" [|OpenFlow]"); 245 return; 246 } 247 248 pin = (struct ofp_packet_in *)bp; 249 omtype = ntohs(pin->pin_match.om_type); 250 omlen = ntohs(pin->pin_match.om_length); 251 printf(" <buffer_id %s total_len %d reason %s table_id %s " 252 "cookie %#016llx match type %s length %d>", 253 print_map(ntohl(pin->pin_buffer_id), ofp_pktout_map), 254 ntohs(pin->pin_total_len), 255 print_map(pin->pin_reason, ofp_pktin_reason_map), 256 print_map(pin->pin_table_id, ofp_table_id_map), 257 be64toh(pin->pin_cookie), 258 print_map(omtype, ofp_match_map), omlen); 259 260 if (pin->pin_buffer_id == OFP_PKTOUT_NO_BUFFER) 261 haspacket = 1; 262 263 /* We only support OXM. */ 264 if (omtype != OFP_MATCH_OXM) 265 return; 266 267 bp += sizeof(*pin); 268 length -= sizeof(*pin); 269 270 /* Get packet start address. */ 271 pktptr = (bp - sizeof(pin->pin_match)) + 272 OFP_ALIGN(omlen) + ETHER_ALIGN; 273 274 /* Don't count the header for the OXM fields. */ 275 omlen -= min(sizeof(pin->pin_match), omlen); 276 if (omlen == 0) 277 goto print_packet; 278 279 parse_next_oxm: 280 if (length < sizeof(*oxm)) { 281 printf(" [|OpenFlow]"); 282 return; 283 } 284 285 oxm = (struct ofp_ox_match *)bp; 286 bp += sizeof(*oxm); 287 length -= sizeof(*oxm); 288 if (length < oxm->oxm_length) { 289 printf(" [|OpenFlow]"); 290 return; 291 } 292 293 ofp_print_oxm(oxm, bp, length); 294 295 bp += oxm->oxm_length; 296 length -= oxm->oxm_length; 297 omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen); 298 if (omlen) 299 goto parse_next_oxm; 300 301 print_packet: 302 if (haspacket == 0) 303 return; 304 305 /* 306 * Recalculate length: 307 * pktptr skipped the omlen + padding and the ETHER_ALIGN, so 308 * instead of keeping track of that we just recalculate length 309 * using the encapsulated packet begin and snapend. 310 */ 311 length = max(snapend - pktptr, 0); 312 if (length < ETHER_ADDR_LEN) { 313 printf(" [|ether]"); 314 return; 315 } 316 317 printf(" "); 318 ether_tryprint(pktptr, length, 0); 319 } 320 321 void 322 ofp_print_flowremoved(const u_char *bp, u_int length) 323 { 324 struct ofp_flow_removed *fr; 325 struct ofp_ox_match *oxm; 326 int omtype, omlen; 327 328 if (length < sizeof(*fr)) { 329 printf(" [|OpenFlow]"); 330 return; 331 } 332 333 fr = (struct ofp_flow_removed *)bp; 334 omtype = ntohs(fr->fr_match.om_type); 335 omlen = ntohs(fr->fr_match.om_length); 336 printf(" <cookie %#016llx priority %d reason %s table_id %s " 337 "duration sec %u nsec %u timeout idle %d hard %d " 338 "packet count %llu byte count %llu match type %s length %d>", 339 be64toh(fr->fr_cookie), ntohs(fr->fr_priority), 340 print_map(fr->fr_reason, ofp_flowrem_reason_map), 341 print_map(fr->fr_table_id, ofp_table_id_map), 342 ntohl(fr->fr_duration_sec), ntohl(fr->fr_duration_nsec), 343 ntohs(fr->fr_idle_timeout), ntohs(fr->fr_hard_timeout), 344 be64toh(fr->fr_packet_count), be64toh(fr->fr_byte_count), 345 print_map(omtype, ofp_match_map), omlen); 346 347 /* We only support OXM. */ 348 if (omtype != OFP_MATCH_OXM) 349 return; 350 351 omlen -= min(sizeof(fr->fr_match), omlen); 352 if (omlen == 0) 353 return; 354 355 bp += sizeof(*fr); 356 length -= sizeof(*fr); 357 358 parse_next_oxm: 359 if (length < sizeof(*oxm)) { 360 printf(" [|OpenFlow]"); 361 return; 362 } 363 364 oxm = (struct ofp_ox_match *)bp; 365 bp += sizeof(*oxm); 366 length -= sizeof(*oxm); 367 if (length < oxm->oxm_length) { 368 printf(" [|OpenFlow]"); 369 return; 370 } 371 372 ofp_print_oxm(oxm, bp, length); 373 374 bp += oxm->oxm_length; 375 length -= oxm->oxm_length; 376 omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen); 377 if (omlen) 378 goto parse_next_oxm; 379 } 380 381 void 382 ofp_print_packetout(const u_char *bp, u_int length) 383 { 384 struct ofp_packet_out *pout; 385 struct ofp_action_header *ah; 386 const u_char *pktptr; 387 int actionslen, haspacket = 0; 388 int ahlen; 389 390 if (length < sizeof(*pout)) { 391 printf(" [|OpenFlow]"); 392 return; 393 } 394 395 pout = (struct ofp_packet_out *)bp; 396 actionslen = ntohs(pout->pout_actions_len); 397 printf(" <buffer_id %s in_port %s actions_len %d>", 398 print_map(ntohl(pout->pout_buffer_id), ofp_pktout_map), 399 print_map(ntohl(pout->pout_in_port), ofp_port_map), 400 actionslen); 401 402 if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER) 403 haspacket = 1; 404 405 bp += sizeof(*pout); 406 length -= sizeof(*pout); 407 pktptr = bp + actionslen; 408 409 /* No actions or unpadded header. */ 410 if (actionslen < sizeof(*ah)) 411 goto print_packet; 412 413 parse_next_action: 414 if (length < sizeof(*ah)) { 415 printf(" [|OpenFlow]"); 416 return; 417 } 418 419 ah = (struct ofp_action_header *)bp; 420 bp += AH_UNPADDED; 421 length -= AH_UNPADDED; 422 actionslen -= AH_UNPADDED; 423 ahlen = ntohs(ah->ah_len) - AH_UNPADDED; 424 if (length < ahlen) { 425 printf(" [|OpenFlow]"); 426 return; 427 } 428 429 ofp_print_action(ah, bp, length); 430 431 bp += ahlen; 432 length -= ahlen; 433 actionslen -= min(ahlen, actionslen); 434 if (actionslen) 435 goto parse_next_action; 436 437 print_packet: 438 if (haspacket == 0) 439 return; 440 441 /* Recalculate length using packet boundaries. */ 442 length = max(snapend - pktptr, 0); 443 if (length < ETHER_ADDR_LEN) { 444 printf(" [|ether]"); 445 return; 446 } 447 448 printf(" "); 449 ether_tryprint(pktptr, length, 0); 450 } 451 452 void 453 ofp_print_flowmod(const u_char *bp, u_int length) 454 { 455 struct ofp_flow_mod *fm; 456 struct ofp_ox_match *oxm; 457 struct ofp_instruction *i; 458 int omtype, omlen, ilen; 459 int instructionslen, padsize; 460 461 if (length < sizeof(*fm)) { 462 printf(" [|OpenFlow]"); 463 return; 464 } 465 466 fm = (struct ofp_flow_mod *)bp; 467 omtype = ntohs(fm->fm_match.om_type); 468 omlen = ntohs(fm->fm_match.om_length); 469 printf(" <cookie %llu cookie_mask %#016llx table_id %s command %s " 470 "timeout idle %d hard %d priority %d buffer_id %s out_port %s " 471 "out_group %s flags %#04x match type %s length %d>", 472 be64toh(fm->fm_cookie), be64toh(fm->fm_cookie_mask), 473 print_map(fm->fm_table_id, ofp_table_id_map), 474 print_map(fm->fm_command, ofp_flowcmd_map), 475 ntohs(fm->fm_idle_timeout), ntohs(fm->fm_hard_timeout), 476 fm->fm_priority, 477 print_map(ntohl(fm->fm_buffer_id), ofp_pktout_map), 478 print_map(ntohl(fm->fm_out_port), ofp_port_map), 479 print_map(ntohl(fm->fm_out_group), ofp_group_id_map), 480 ntohs(fm->fm_flags), 481 print_map(omtype, ofp_match_map), omlen); 482 483 bp += sizeof(*fm); 484 length -= sizeof(*fm); 485 486 padsize = OFP_ALIGN(omlen) - omlen; 487 omlen -= min(sizeof(fm->fm_match), omlen); 488 instructionslen = length - (omlen + padsize); 489 if (omtype != OFP_MATCH_OXM || omlen == 0) { 490 if (instructionslen <= 0) 491 return; 492 493 /* Skip padding if any. */ 494 if (padsize) { 495 bp += padsize; 496 length -= padsize; 497 } 498 goto parse_next_instruction; 499 } 500 501 parse_next_oxm: 502 if (length < sizeof(*oxm)) { 503 printf(" [|OpenFlow]"); 504 return; 505 } 506 507 oxm = (struct ofp_ox_match *)bp; 508 bp += sizeof(*oxm); 509 length -= sizeof(*oxm); 510 if (length < oxm->oxm_length) { 511 printf(" [|OpenFlow]"); 512 return; 513 } 514 515 ofp_print_oxm(oxm, bp, length); 516 517 bp += oxm->oxm_length; 518 length -= oxm->oxm_length; 519 omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen); 520 if (omlen) 521 goto parse_next_oxm; 522 523 /* Skip padding if any. */ 524 if (padsize) { 525 bp += padsize; 526 length -= padsize; 527 } 528 529 parse_next_instruction: 530 if (length < sizeof(*i)) { 531 printf(" [|OpenFlow]"); 532 return; 533 } 534 535 i = (struct ofp_instruction *)bp; 536 bp += sizeof(*i); 537 length -= sizeof(*i); 538 instructionslen -= sizeof(*i); 539 ilen = ntohs(i->i_len) - sizeof(*i); 540 if (length < ilen) { 541 printf(" [|OpenFlow]"); 542 return; 543 } 544 545 ofp_print_instruction(i, bp, length); 546 547 bp += ilen; 548 length -= ilen; 549 instructionslen -= ilen; 550 if (instructionslen > 0) 551 goto parse_next_instruction; 552 } 553 554 void 555 ofp_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p) 556 { 557 struct dlt_openflow_hdr of; 558 unsigned int length; 559 560 ts_print(&h->ts); 561 562 packetp = p; 563 snapend = p + h->caplen; 564 length = snapend - p; 565 566 TCHECK2(*p, sizeof(of)); 567 memcpy(&of, p, sizeof(of)); 568 569 if (ntohl(of.of_direction) == DLT_OPENFLOW_TO_SWITCH) 570 printf("controller -> %s", device); 571 else 572 printf("%s -> controller", device); 573 if (eflag) 574 printf(", datapath %#016llx", be64toh(of.of_datapath_id)); 575 576 ofp_print(p + sizeof(of), length - sizeof(of)); 577 goto out; 578 579 trunc: 580 printf("[|OpenFlow]"); 581 582 out: 583 if (xflag) 584 default_print(p, (u_int)h->len); 585 putchar('\n'); 586 } 587 588 void 589 ofp_print(const u_char *bp, u_int length) 590 { 591 struct ofp_header *oh; 592 unsigned int ohlen, snaplen; 593 594 /* The captured data might be smaller than indicated */ 595 snaplen = snapend - bp; 596 length = min(snaplen, length); 597 if (length < sizeof(*oh)) { 598 printf("[|OpenFlow]"); 599 return; 600 } 601 602 oh = (struct ofp_header *)bp; 603 ohlen = ntohs(oh->oh_length); 604 605 printf(": OpenFlow %s type %u length %u xid %u", 606 print_map(oh->oh_version, ofp_v_map), 607 oh->oh_type, ntohs(oh->oh_length), ntohl(oh->oh_xid)); 608 609 switch (oh->oh_version) { 610 case OFP_V_1_3: 611 break; 612 613 default: 614 return; 615 } 616 617 printf(": %s", print_map(oh->oh_type, ofp_t_map)); 618 619 switch (oh->oh_type) { 620 case OFP_T_HELLO: 621 ofp_print_hello(bp, length, ohlen); 622 break; 623 case OFP_T_ERROR: 624 ofp_print_error(bp, length); 625 break; 626 case OFP_T_ECHO_REQUEST: 627 case OFP_T_ECHO_REPLY: 628 break; 629 case OFP_T_FEATURES_REQUEST: 630 break; 631 case OFP_T_FEATURES_REPLY: 632 ofp_print_featuresreply(bp, length); 633 break; 634 case OFP_T_SET_CONFIG: 635 ofp_print_setconfig(bp, length); 636 break; 637 case OFP_T_PACKET_IN: 638 ofp_print_packetin(bp, length); 639 break; 640 case OFP_T_FLOW_REMOVED: 641 ofp_print_flowremoved(bp, length); 642 break; 643 case OFP_T_PACKET_OUT: 644 ofp_print_packetout(bp, length); 645 break; 646 case OFP_T_FLOW_MOD: 647 ofp_print_flowmod(bp, length); 648 break; 649 } 650 } 651 652 void 653 oxm_print_byte(const u_char *bp, u_int length, int hasmask, int hex) 654 { 655 uint8_t *b; 656 657 if (length < sizeof(*b)) { 658 printf("[|OpenFlow]"); 659 return; 660 } 661 662 b = (uint8_t *)bp; 663 if (hex) 664 printf("%#02x", ntohs(*b)); 665 else 666 printf("%u", ntohs(*b)); 667 668 if (hasmask) { 669 bp += sizeof(*b); 670 length -= sizeof(*b); 671 printf(" mask "); 672 oxm_print_byte(bp, length, 0, 1); 673 } 674 } 675 676 void 677 oxm_print_halfword(const u_char *bp, u_int length, int hasmask, int hex) 678 { 679 uint16_t *h; 680 681 if (length < sizeof(*h)) { 682 printf("[|OpenFlow]"); 683 return; 684 } 685 686 h = (uint16_t *)bp; 687 if (hex) 688 printf("%#04x", ntohs(*h)); 689 else 690 printf("%u", ntohs(*h)); 691 692 if (hasmask) { 693 bp += sizeof(*h); 694 length -= sizeof(*h); 695 printf(" mask "); 696 oxm_print_halfword(bp, length, 0, 1); 697 } 698 } 699 700 void 701 oxm_print_word(const u_char *bp, u_int length, int hasmask, int hex) 702 { 703 uint32_t *w; 704 705 if (length < sizeof(*w)) { 706 printf("[|OpenFlow]"); 707 return; 708 } 709 710 w = (uint32_t *)bp; 711 if (hex) 712 printf("%#08x", ntohl(*w)); 713 else 714 printf("%u", ntohl(*w)); 715 716 if (hasmask) { 717 bp += sizeof(*w); 718 length -= sizeof(*w); 719 printf(" mask "); 720 oxm_print_word(bp, length, 0, 1); 721 } 722 } 723 724 void 725 oxm_print_quad(const u_char *bp, u_int length, int hasmask, int hex) 726 { 727 uint64_t *q; 728 729 if (length < sizeof(*q)) { 730 printf("[|OpenFlow]"); 731 return; 732 } 733 734 q = (uint64_t *)bp; 735 if (hex) 736 printf("%#016llx", be64toh(*q)); 737 else 738 printf("%llu", be64toh(*q)); 739 740 if (hasmask) { 741 bp += sizeof(*q); 742 length -= sizeof(*q); 743 printf(" mask "); 744 oxm_print_quad(bp, length, 0, 1); 745 } 746 } 747 748 void 749 oxm_print_ether(const u_char *bp, u_int length, int hasmask) 750 { 751 if (length < ETHER_HDR_LEN) { 752 printf("[|OpenFlow]"); 753 return; 754 } 755 756 printf("%s", etheraddr_string(bp)); 757 758 if (hasmask) { 759 bp += ETHER_ADDR_LEN; 760 length -= ETHER_ADDR_LEN; 761 printf(" mask "); 762 oxm_print_ether(bp, length, 0); 763 } 764 } 765 766 void 767 oxm_print_data(const u_char *bp, u_int length, int hasmask, size_t datalen) 768 { 769 uint8_t *ptr; 770 int i; 771 char hex[8]; 772 773 if (length < datalen) { 774 printf("[|OpenFlow]"); 775 return; 776 } 777 778 ptr = (uint8_t *)bp; 779 for (i = 0; i < datalen; i++) { 780 snprintf(hex, sizeof(hex), "%02x", ptr[i]); 781 printf("%s", hex); 782 } 783 784 if (hasmask) { 785 bp += datalen; 786 length -= datalen; 787 printf(" mask "); 788 oxm_print_data(bp, length, 0, datalen); 789 } 790 } 791 792 void 793 ofp_print_oxm(struct ofp_ox_match *oxm, const u_char *bp, u_int length) 794 { 795 int class, field, mask, len; 796 uint16_t *vlan; 797 798 class = ntohs(oxm->oxm_class); 799 field = OFP_OXM_GET_FIELD(oxm); 800 mask = OFP_OXM_GET_HASMASK(oxm); 801 len = oxm->oxm_length; 802 printf(" oxm <class %s field %s hasmask %d length %d", 803 print_map(class, ofp_oxm_c_map), 804 print_map(field, ofp_xm_t_map), mask, len); 805 806 switch (class) { 807 case OFP_OXM_C_OPENFLOW_BASIC: 808 break; 809 810 case OFP_OXM_C_NXM_0: 811 case OFP_OXM_C_NXM_1: 812 case OFP_OXM_C_OPENFLOW_EXPERIMENTER: 813 default: 814 printf(">"); 815 return; 816 } 817 818 printf(" value "); 819 820 switch (field) { 821 case OFP_XM_T_IN_PORT: 822 case OFP_XM_T_IN_PHY_PORT: 823 case OFP_XM_T_MPLS_LABEL: 824 oxm_print_word(bp, length, mask, 0); 825 break; 826 827 case OFP_XM_T_META: 828 case OFP_XM_T_TUNNEL_ID: 829 oxm_print_quad(bp, length, mask, 1); 830 break; 831 832 case OFP_XM_T_ETH_DST: 833 case OFP_XM_T_ETH_SRC: 834 case OFP_XM_T_ARP_SHA: 835 case OFP_XM_T_ARP_THA: 836 case OFP_XM_T_IPV6_ND_SLL: 837 case OFP_XM_T_IPV6_ND_TLL: 838 oxm_print_ether(bp, length, mask); 839 break; 840 841 case OFP_XM_T_ETH_TYPE: 842 oxm_print_halfword(bp, length, mask, 1); 843 break; 844 845 case OFP_XM_T_VLAN_VID: 846 /* 847 * VLAN has an exception: it uses the higher bits to signal 848 * the presence of the VLAN. 849 */ 850 if (length < sizeof(*vlan)) { 851 printf("[|OpenFlow]"); 852 break; 853 } 854 855 vlan = (uint16_t *)bp; 856 if (ntohs(*vlan) & OFP_XM_VID_PRESENT) 857 printf("(VLAN %d) ", 858 ntohs(*vlan) & (~OFP_XM_VID_PRESENT)); 859 else 860 printf("(no VLAN) "); 861 /* FALLTHROUGH */ 862 case OFP_XM_T_TCP_SRC: 863 case OFP_XM_T_TCP_DST: 864 case OFP_XM_T_UDP_SRC: 865 case OFP_XM_T_UDP_DST: 866 case OFP_XM_T_SCTP_SRC: 867 case OFP_XM_T_SCTP_DST: 868 case OFP_XM_T_ARP_OP: 869 case OFP_XM_T_IPV6_EXTHDR: 870 oxm_print_halfword(bp, length, mask, 0); 871 break; 872 873 case OFP_XM_T_VLAN_PCP: 874 case OFP_XM_T_IP_DSCP: 875 case OFP_XM_T_IP_ECN: 876 case OFP_XM_T_MPLS_TC: 877 case OFP_XM_T_MPLS_BOS: 878 oxm_print_byte(bp, length, mask, 1); 879 break; 880 881 case OFP_XM_T_IPV4_SRC: 882 case OFP_XM_T_IPV4_DST: 883 case OFP_XM_T_ARP_SPA: 884 case OFP_XM_T_ARP_TPA: 885 case OFP_XM_T_IPV6_FLABEL: 886 oxm_print_word(bp, length, mask, 1); 887 break; 888 889 case OFP_XM_T_IP_PROTO: 890 case OFP_XM_T_ICMPV4_TYPE: 891 case OFP_XM_T_ICMPV4_CODE: 892 case OFP_XM_T_ICMPV6_TYPE: 893 case OFP_XM_T_ICMPV6_CODE: 894 oxm_print_byte(bp, length, mask, 0); 895 break; 896 897 case OFP_XM_T_IPV6_SRC: 898 case OFP_XM_T_IPV6_DST: 899 case OFP_XM_T_IPV6_ND_TARGET: 900 oxm_print_data(bp, length, mask, sizeof(struct in6_addr)); 901 break; 902 903 case OFP_XM_T_PBB_ISID: 904 oxm_print_data(bp, length, mask, 3); 905 break; 906 907 default: 908 printf("unknown"); 909 break; 910 } 911 912 printf(">"); 913 } 914 915 void 916 action_print_output(const u_char *bp, u_int length) 917 { 918 struct ofp_action_output *ao; 919 920 if (length < (sizeof(*ao) - AH_UNPADDED)) { 921 printf(" [|OpenFlow]"); 922 return; 923 } 924 925 ao = (struct ofp_action_output *)(bp - AH_UNPADDED); 926 printf(" port %s max_len %s", 927 print_map(ntohl(ao->ao_port), ofp_port_map), 928 print_map(ntohs(ao->ao_max_len), ofp_controller_maxlen_map)); 929 } 930 931 void 932 action_print_group(const u_char *bp, u_int length) 933 { 934 struct ofp_action_group *ag; 935 936 if (length < (sizeof(*ag) - AH_UNPADDED)) { 937 printf(" [|OpenFlow]"); 938 return; 939 } 940 941 ag = (struct ofp_action_group *)(bp - AH_UNPADDED); 942 printf(" group_id %s", 943 print_map(ntohl(ag->ag_group_id), ofp_group_id_map)); 944 } 945 946 void 947 action_print_setqueue(const u_char *bp, u_int length) 948 { 949 struct ofp_action_set_queue *asq; 950 951 if (length < (sizeof(*asq) - AH_UNPADDED)) { 952 printf(" [|OpenFlow]"); 953 return; 954 } 955 956 asq = (struct ofp_action_set_queue *)(bp - AH_UNPADDED); 957 printf(" queue_id %u", ntohl(asq->asq_queue_id)); 958 } 959 960 void 961 action_print_setmplsttl(const u_char *bp, u_int length) 962 { 963 struct ofp_action_mpls_ttl *amt; 964 965 if (length < (sizeof(*amt) - AH_UNPADDED)) { 966 printf(" [|OpenFlow]"); 967 return; 968 } 969 970 amt = (struct ofp_action_mpls_ttl *)(bp - AH_UNPADDED); 971 printf(" ttl %d", amt->amt_ttl); 972 } 973 974 void 975 action_print_setnwttl(const u_char *bp, u_int length) 976 { 977 struct ofp_action_nw_ttl *ant; 978 979 if (length < (sizeof(*ant) - AH_UNPADDED)) { 980 printf(" [|OpenFlow]"); 981 return; 982 } 983 984 ant = (struct ofp_action_nw_ttl *)(bp - AH_UNPADDED); 985 printf(" ttl %d", ant->ant_ttl); 986 } 987 988 void 989 action_print_push(const u_char *bp, u_int length) 990 { 991 struct ofp_action_push *ap; 992 993 if (length < (sizeof(*ap) - AH_UNPADDED)) { 994 printf(" [|OpenFlow]"); 995 return; 996 } 997 998 ap = (struct ofp_action_push *)(bp - AH_UNPADDED); 999 printf(" ethertype %#04x", ntohs(ap->ap_ethertype)); 1000 } 1001 1002 void 1003 action_print_popmpls(const u_char *bp, u_int length) 1004 { 1005 struct ofp_action_pop_mpls *apm; 1006 1007 if (length < (sizeof(*apm) - AH_UNPADDED)) { 1008 printf(" [|OpenFlow]"); 1009 return; 1010 } 1011 1012 apm = (struct ofp_action_pop_mpls *)(bp - AH_UNPADDED); 1013 printf(" ethertype %#04x", ntohs(apm->apm_ethertype)); 1014 } 1015 1016 void 1017 action_print_setfield(const u_char *bp, u_int length) 1018 { 1019 struct ofp_action_set_field *asf; 1020 struct ofp_ox_match *oxm; 1021 int omlen; 1022 1023 if (length < (sizeof(*asf) - AH_UNPADDED)) { 1024 printf(" [|OpenFlow]"); 1025 return; 1026 } 1027 1028 asf = (struct ofp_action_set_field *)(bp - AH_UNPADDED); 1029 omlen = ntohs(asf->asf_len) - AH_UNPADDED; 1030 if (omlen == 0) 1031 return; 1032 1033 parse_next_oxm: 1034 if (length < sizeof(*oxm)) { 1035 printf(" [|OpenFlow]"); 1036 return; 1037 } 1038 1039 oxm = (struct ofp_ox_match *)bp; 1040 bp += sizeof(*oxm); 1041 length -= sizeof(*oxm); 1042 if (length < oxm->oxm_length) { 1043 printf(" [|OpenFlow]"); 1044 return; 1045 } 1046 1047 ofp_print_oxm(oxm, bp, length); 1048 1049 bp += oxm->oxm_length; 1050 length -= oxm->oxm_length; 1051 omlen -= min(sizeof(*oxm) + oxm->oxm_length, omlen); 1052 if (omlen) 1053 goto parse_next_oxm; 1054 } 1055 1056 void 1057 ofp_print_action(struct ofp_action_header *ah, const u_char *bp, u_int length) 1058 { 1059 int ahtype; 1060 1061 ahtype = ntohs(ah->ah_type); 1062 printf(" action <type %s length %d", 1063 print_map(ahtype, ofp_action_map), ntohs(ah->ah_len)); 1064 1065 switch (ahtype) { 1066 case OFP_ACTION_OUTPUT: 1067 action_print_output(bp, length); 1068 break; 1069 1070 case OFP_ACTION_GROUP: 1071 action_print_group(bp, length); 1072 break; 1073 1074 case OFP_ACTION_SET_QUEUE: 1075 action_print_setqueue(bp, length); 1076 break; 1077 1078 case OFP_ACTION_SET_MPLS_TTL: 1079 action_print_setmplsttl(bp, length); 1080 break; 1081 1082 case OFP_ACTION_SET_NW_TTL: 1083 action_print_setnwttl(bp, length); 1084 break; 1085 1086 case OFP_ACTION_PUSH_VLAN: 1087 case OFP_ACTION_PUSH_MPLS: 1088 case OFP_ACTION_PUSH_PBB: 1089 action_print_push(bp, length); 1090 break; 1091 1092 case OFP_ACTION_POP_MPLS: 1093 action_print_popmpls(bp, length); 1094 break; 1095 1096 case OFP_ACTION_SET_FIELD: 1097 break; 1098 1099 case OFP_ACTION_COPY_TTL_OUT: 1100 case OFP_ACTION_COPY_TTL_IN: 1101 case OFP_ACTION_DEC_NW_TTL: 1102 case OFP_ACTION_DEC_MPLS_TTL: 1103 case OFP_ACTION_POP_VLAN: 1104 case OFP_ACTION_POP_PBB: 1105 case OFP_ACTION_EXPERIMENTER: 1106 default: 1107 /* Generic header, nothing to show here. */ 1108 break; 1109 } 1110 1111 printf(">"); 1112 } 1113 1114 void 1115 instruction_print_gototable(const char *bp, u_int length) 1116 { 1117 struct ofp_instruction_goto_table *igt; 1118 1119 if (length < (sizeof(*igt) - sizeof(struct ofp_instruction))) { 1120 printf(" [|OpenFlow]"); 1121 return; 1122 } 1123 1124 igt = (struct ofp_instruction_goto_table *) 1125 (bp - sizeof(struct ofp_instruction)); 1126 printf(" table_id %d", igt->igt_table_id); 1127 } 1128 1129 void 1130 instruction_print_meta(const char *bp, u_int length) 1131 { 1132 struct ofp_instruction_write_metadata *iwm; 1133 1134 if (length < (sizeof(*iwm) - sizeof(struct ofp_instruction))) { 1135 printf(" [|OpenFlow]"); 1136 return; 1137 } 1138 1139 iwm = (struct ofp_instruction_write_metadata *) 1140 (bp - sizeof(struct ofp_instruction)); 1141 printf(" metadata %llu metadata_mask %llu", 1142 be64toh(iwm->iwm_metadata), be64toh(iwm->iwm_metadata_mask)); 1143 } 1144 1145 void 1146 instruction_print_actions(const char *bp, u_int length) 1147 { 1148 struct ofp_instruction_actions *ia; 1149 struct ofp_action_header *ah; 1150 int actionslen; 1151 unsigned int ahlen; 1152 1153 if (length < (sizeof(*ia) - sizeof(struct ofp_instruction))) { 1154 printf(" [|OpenFlow]"); 1155 return; 1156 } 1157 1158 ia = (struct ofp_instruction_actions *) 1159 (bp - sizeof(struct ofp_instruction)); 1160 1161 actionslen = ntohs(ia->ia_len) - sizeof(*ia); 1162 if (actionslen <= 0) 1163 return; 1164 1165 bp += sizeof(*ia) - sizeof(struct ofp_instruction); 1166 length -= sizeof(*ia) - sizeof(struct ofp_instruction); 1167 1168 parse_next_action: 1169 if (length < sizeof(*ah)) { 1170 printf(" [|OpenFlow]"); 1171 return; 1172 } 1173 1174 ah = (struct ofp_action_header *)bp; 1175 bp += AH_UNPADDED; 1176 length -= AH_UNPADDED; 1177 actionslen -= AH_UNPADDED; 1178 ahlen = ntohs(ah->ah_len) - AH_UNPADDED; 1179 if (length < ahlen) { 1180 printf(" [|OpenFlow]"); 1181 return; 1182 } 1183 1184 ofp_print_action(ah, bp, length); 1185 1186 bp += ahlen; 1187 length -= ahlen; 1188 actionslen -= min(ahlen, actionslen); 1189 if (actionslen) 1190 goto parse_next_action; 1191 } 1192 1193 void 1194 instruction_print_meter(const char *bp, u_int length) 1195 { 1196 struct ofp_instruction_meter *im; 1197 1198 if (length < (sizeof(*im) - sizeof(struct ofp_instruction))) { 1199 printf(" [|OpenFlow]"); 1200 return; 1201 } 1202 1203 im = (struct ofp_instruction_meter *) 1204 (bp - sizeof(struct ofp_instruction)); 1205 printf(" meter_id %u", ntohl(im->im_meter_id)); 1206 } 1207 1208 void 1209 instruction_print_experimenter(const char *bp, u_int length) 1210 { 1211 struct ofp_instruction_experimenter *ie; 1212 1213 if (length < (sizeof(*ie) - sizeof(struct ofp_instruction))) { 1214 printf(" [|OpenFlow]"); 1215 return; 1216 } 1217 1218 ie = (struct ofp_instruction_experimenter *) 1219 (bp - sizeof(struct ofp_instruction)); 1220 printf(" experimenter %u", ntohl(ie->ie_experimenter)); 1221 } 1222 1223 void 1224 ofp_print_instruction(struct ofp_instruction *i, const char *bp, u_int length) 1225 { 1226 int itype; 1227 1228 itype = ntohs(i->i_type); 1229 printf(" instruction <type %s length %d", 1230 print_map(itype, ofp_instruction_t_map), ntohs(i->i_len)); 1231 1232 switch (itype) { 1233 case OFP_INSTRUCTION_T_GOTO_TABLE: 1234 instruction_print_gototable(bp, length); 1235 break; 1236 case OFP_INSTRUCTION_T_WRITE_META: 1237 instruction_print_meta(bp, length); 1238 break; 1239 case OFP_INSTRUCTION_T_WRITE_ACTIONS: 1240 case OFP_INSTRUCTION_T_APPLY_ACTIONS: 1241 case OFP_INSTRUCTION_T_CLEAR_ACTIONS: 1242 instruction_print_actions(bp, length); 1243 break; 1244 case OFP_INSTRUCTION_T_METER: 1245 instruction_print_meter(bp, length); 1246 break; 1247 case OFP_INSTRUCTION_T_EXPERIMENTER: 1248 instruction_print_meter(bp, length); 1249 break; 1250 } 1251 1252 printf(">"); 1253 } 1254