1 ## This file is part of Scapy 2 ## See http://www.secdev.org/projects/scapy for more information 3 ## Copyright (C) Philippe Biondi <phil (at] secdev.org> 4 ## This program is published under a GPLv2 license 5 6 ## Copyright (C) 2014 Maxence Tury <maxence.tury (at] ssi.gouv.fr> 7 ## OpenFlow is an open standard used in SDN deployments. 8 ## Based on OpenFlow v1.0.1 9 ## Specifications can be retrieved from https://www.opennetworking.org/ 10 11 # scapy.contrib.description = Openflow v1.0 12 # scapy.contrib.status = loads 13 14 from __future__ import absolute_import 15 import struct 16 from scapy.fields import * 17 from scapy.layers.l2 import * 18 from scapy.layers.inet import * 19 from scapy.compat import orb 20 21 ### If prereq_autocomplete is True then match prerequisites will be 22 ### automatically handled. See OFPMatch class. 23 prereq_autocomplete = False 24 25 ##################################################### 26 ################# Predefined values ################# 27 ##################################################### 28 29 ofp_port_no = { 0xfff8: "IN_PORT", 30 0xfff9: "TABLE", 31 0xfffa: "NORMAL", 32 0xfffb: "FLOOD", 33 0xfffc: "ALL", 34 0xfffd: "CONTROLLER", 35 0xfffe: "LOCAL", 36 0xffff: "NONE" } 37 38 ofp_table = { 0xff: "ALL" } 39 40 ofp_queue = { 0xffffffff: "ALL" } 41 42 ofp_buffer = { 0xffffffff: "NO_BUFFER" } 43 44 ofp_max_len = { 0xffff: "NO_BUFFER" } 45 46 ##################################################### 47 ################# Common structures ################# 48 ##################################################### 49 50 ### The following structures will be used in different types 51 ### of OpenFlow messages: ports, matches, actions, queues. 52 53 54 ##################### Ports ##################### 55 56 ofp_port_config = [ "PORT_DOWN", 57 "NO_STP", 58 "NO_RECV", 59 "NO_RECV_STP", 60 "NO_FLOOD", 61 "NO_FWD", 62 "NO_PACKET_IN" ] 63 64 ofp_port_state = [ "LINK_DOWN" ] 65 66 ofp_port_state_stp = { 0: "OFPPS_STP_LISTEN", 67 1: "OFPPS_STP_LEARN", 68 2: "OFPPS_STP_FORWARD", 69 3: "OFPPS_STP_BLOCK" } 70 71 ofp_port_features = [ "10MB_HD", 72 "10MB_FD", 73 "100MB_HD", 74 "100MB_FD", 75 "1GB_HD", 76 "1GB_FD", 77 "10GB_FD", 78 "COPPER", 79 "FIBER", 80 "AUTONEG", 81 "PAUSE", 82 "PAUSE_ASYM" ] 83 84 class OFPPhyPort(Packet): 85 name = "OFP_PHY_PORT" 86 fields_desc = [ ShortEnumField("port_no", 0, ofp_port_no), 87 MACField("hw_addr", "0"), 88 StrFixedLenField("port_name", "", 16), 89 FlagsField("config", 0, 32, ofp_port_config), 90 BitEnumField("stp_state", 0, 24, ofp_port_state), 91 FlagsField("state", 0, 8, ofp_port_state), 92 FlagsField("curr", 0, 32, ofp_port_features), 93 FlagsField("advertised", 0, 32, ofp_port_features), 94 FlagsField("supported", 0, 32, ofp_port_features), 95 FlagsField("peer", 0, 32, ofp_port_features) ] 96 97 def extract_padding(self, s): 98 return "", s 99 100 class OFPMatch(Packet): 101 name = "OFP_MATCH" 102 fields_desc= [ FlagsField("wildcards1", None, 12, [ "DL_VLAN_PCP", 103 "NW_TOS" ]), 104 BitField("nw_dst_mask", None, 6), 105 BitField("nw_src_mask", None, 6), 106 FlagsField("wildcards2", None, 8, [ "IN_PORT", 107 "DL_VLAN", 108 "DL_SRC", 109 "DL_DST", 110 "DL_TYPE", 111 "NW_PROTO", 112 "TP_SRC", 113 "TP_DST" ]), 114 ShortEnumField("in_port", None, ofp_port_no), 115 MACField("dl_src", None), 116 MACField("dl_dst", None), 117 ShortField("dl_vlan", None), 118 ByteField("dl_vlan_pcp", None), 119 XByteField("pad1", None), 120 ShortField("dl_type", None), 121 ByteField("nw_tos", None), 122 ByteField("nw_proto", None), 123 XShortField("pad2", None), 124 IPField("nw_src", "0"), 125 IPField("nw_dst", "0"), 126 ShortField("tp_src", None), 127 ShortField("tp_dst", None) ] 128 129 def extract_padding(self, s): 130 return "", s 131 132 ### with post_build we create the wildcards field bit by bit 133 def post_build(self, p, pay): 134 # first 10 bits of an ofp_match are always set to 0 135 l = "0"*10 136 137 # when one field has not been declared, it is assumed to be wildcarded 138 if self.wildcards1 is None: 139 if self.nw_tos is None: l+="1" 140 else: l+="0" 141 if self.dl_vlan_pcp is None: l+="1" 142 else: l+="0" 143 else: 144 w1 = binrepr(self.wildcards1) 145 l+="0"*(2-len(w1)) 146 l+=w1 147 148 # ip masks use 6 bits each 149 if self.nw_dst_mask is None: 150 if self.nw_dst is "0": l+="111111" 151 # 0x100000 would be ok too (32-bit IP mask) 152 else: l+="0"*6 153 else: 154 m1 = binrepr(self.nw_dst_mask) 155 l+="0"*(6-len(m1)) 156 l+=m1 157 if self.nw_src_mask is None: 158 if self.nw_src is "0": l+="111111" 159 else: l+="0"*6 160 else: 161 m2 = binrepr(self.nw_src_mask) 162 l+="0"*(6-len(m2)) 163 l+=m2 164 165 # wildcards2 works the same way as wildcards1 166 if self.wildcards2 is None: 167 if self.tp_dst is None: l+="1" 168 else: l+="0" 169 if self.tp_src is None: l+="1" 170 else: l+="0" 171 if self.nw_proto is None: l+="1" 172 else: l+="0" 173 if self.dl_type is None: l+="1" 174 else: l+="0" 175 if self.dl_dst is None: l+="1" 176 else: l+="0" 177 if self.dl_src is None: l+="1" 178 else: l+="0" 179 if self.dl_vlan is None: l+="1" 180 else: l+="0" 181 if self.in_port is None: l+="1" 182 else: l+="0" 183 else: 184 w2 = binrepr(self.wildcards2) 185 l+="0"*(8-len(w2)) 186 l+=w2 187 188 ### In order to write OFPMatch compliant with the specifications, 189 ### if prereq_autocomplete has been set to True 190 ### we assume ethertype=IP or nwproto=TCP when appropriate subfields are provided. 191 if prereq_autocomplete: 192 if self.dl_type is None: 193 if self.nw_src is not "0" or self.nw_dst is not "0" or self.nw_proto is not None or self.nw_tos is not None: 194 p = p[:22] + struct.pack("!H", 0x0800) + p[24:] 195 l = l[:-5] + "0" + l[-4:] 196 if self.nw_proto is None: 197 if self.tp_src is not None or self.tp_dst is not None: 198 p = p[:22] + struct.pack("!H", 0x0800) + p[24:] 199 l = l[:-5] + "0" + l[-4:] 200 p = p[:25] + struct.pack("!B", 0x06) + p[26:] 201 l = l[:-6] + "0" + l[-5:] 202 203 ins = b"".join(chb(int("".join(x),2)) for x in zip(*[iter(l)]*8)) 204 p = ins + p[4:] 205 return p + pay 206 207 208 ###################### Actions ###################### 209 210 class _ofp_action_header(Packet): 211 name = "Dummy OpenFlow Action Header" 212 213 def post_build(self, p, pay): 214 if self.len is None: 215 l = len(p)+len(pay) 216 p = p[:2] + struct.pack("!H", l) + p[4:] 217 return p + pay 218 219 ofp_action_types = { 0: "OFPAT_OUTPUT", 220 1: "OFPAT_SET_VLAN_VID", 221 2: "OFPAT_SET_VLAN_PCP", 222 3: "OFPAT_STRIP_VLAN", 223 4: "OFPAT_SET_DL_SRC", 224 5: "OFPAT_SET_DL_DST", 225 6: "OFPAT_SET_NW_SRC", 226 7: "OFPAT_SET_NW_DST", 227 8: "OFPAT_SET_NW_TOS", 228 9: "OFPAT_SET_TP_SRC", 229 10: "OFPAT_SET_TP_DST", 230 11: "OFPAT_ENQUEUE", 231 65535: "OFPAT_VENDOR" } 232 233 class OFPATOutput(_ofp_action_header): 234 name = "OFPAT_OUTPUT" 235 fields_desc = [ ShortEnumField("type", 0, ofp_action_types), 236 ShortField("len", 8), 237 ShortEnumField("port", 0, ofp_port_no), 238 ShortEnumField("max_len", "NO_BUFFER", ofp_max_len) ] 239 240 class OFPATSetVLANVID(_ofp_action_header): 241 name = "OFPAT_SET_VLAN_VID" 242 fields_desc = [ ShortEnumField("type", 1, ofp_action_types), 243 ShortField("len", 8), 244 ShortField("vlan_vid", 0), 245 XShortField("pad", 0) ] 246 247 class OFPATSetVLANPCP(_ofp_action_header): 248 name = "OFPAT_SET_VLAN_PCP" 249 fields_desc = [ ShortEnumField("type", 2, ofp_action_types), 250 ShortField("len", 8), 251 ByteField("vlan_pcp", 0), 252 X3BytesField("pad", 0) ] 253 254 class OFPATStripVLAN(_ofp_action_header): 255 name = "OFPAT_STRIP_VLAN" 256 fields_desc = [ ShortEnumField("type", 3, ofp_action_types), 257 ShortField("len", 8), 258 XIntField("pad", 0) ] 259 260 class OFPATSetDlSrc(_ofp_action_header): 261 name = "OFPAT_SET_DL_SRC" 262 fields_desc = [ ShortEnumField("type", 4, ofp_action_types), 263 ShortField("len", 16), 264 MACField("dl_addr", "0"), 265 XBitField("pad", 0, 48) ] 266 267 class OFPATSetDlDst(_ofp_action_header): 268 name = "OFPAT_SET_DL_DST" 269 fields_desc = [ ShortEnumField("type", 5, ofp_action_types), 270 ShortField("len", 16), 271 MACField("dl_addr", "0"), 272 XBitField("pad", 0, 48) ] 273 274 class OFPATSetNwSrc(_ofp_action_header): 275 name = "OFPAT_SET_NW_SRC" 276 fields_desc = [ ShortEnumField("type", 6, ofp_action_types), 277 ShortField("len", 8), 278 IPField("nw_addr", "0") ] 279 280 class OFPATSetNwDst(_ofp_action_header): 281 name = "OFPAT_SET_NW_DST" 282 fields_desc = [ ShortEnumField("type", 7, ofp_action_types), 283 ShortField("len", 8), 284 IPField("nw_addr", "0") ] 285 286 class OFPATSetNwToS(_ofp_action_header): 287 name = "OFPAT_SET_TP_TOS" 288 fields_desc = [ ShortEnumField("type", 8, ofp_action_types), 289 ShortField("len", 8), 290 ByteField("nw_tos", 0), 291 X3BytesField("pad", 0) ] 292 293 class OFPATSetTpSrc(_ofp_action_header): 294 name = "OFPAT_SET_TP_SRC" 295 fields_desc = [ ShortEnumField("type", 9, ofp_action_types), 296 ShortField("len", 8), 297 ShortField("tp_port", 0), 298 XShortField("pad", 0) ] 299 300 class OFPATSetTpDst(_ofp_action_header): 301 name = "OFPAT_SET_TP_DST" 302 fields_desc = [ ShortEnumField("type", 10, ofp_action_types), 303 ShortField("len", 8), 304 ShortField("tp_port", 0), 305 XShortField("pad", 0) ] 306 307 class OFPATEnqueue(_ofp_action_header): 308 name = "OFPAT_ENQUEUE" 309 fields_desc = [ ShortEnumField("type", 11, ofp_action_types), 310 ShortField("len", 16), 311 ShortEnumField("port", 0, ofp_port_no), 312 XBitField("pad", 0, 48), 313 IntField("queue_id", 0) ] 314 315 class OFPATVendor(_ofp_action_header): 316 name = "OFPAT_VENDOR" 317 fields_desc = [ ShortEnumField("type", 65535, ofp_action_types), 318 ShortField("len", 8), 319 IntField("vendor", 0) ] 320 321 ofp_action_cls = { 0: OFPATOutput, 322 1: OFPATSetVLANVID, 323 2: OFPATSetVLANPCP, 324 3: OFPATStripVLAN, 325 4: OFPATSetDlSrc, 326 5: OFPATSetDlDst, 327 6: OFPATSetNwSrc, 328 7: OFPATSetNwDst, 329 8: OFPATSetNwToS, 330 9: OFPATSetTpSrc, 331 10: OFPATSetTpDst, 332 11: OFPATEnqueue, 333 65535: OFPATVendor } 334 335 class ActionPacketListField(PacketListField): 336 def m2i(self, pkt, s): 337 t = struct.unpack("!H", s[:2])[0] 338 return ofp_action_cls.get(t, Raw)(s) 339 340 @staticmethod 341 def _get_action_length(s): 342 return struct.unpack("!H", s[2:4])[0] 343 344 def getfield(self, pkt, s): 345 lst = [] 346 remain = s 347 348 while remain: 349 l = ActionPacketListField._get_action_length(remain) 350 current = remain[:l] 351 remain = remain[l:] 352 p = self.m2i(pkt, current) 353 lst.append(p) 354 355 return remain, lst 356 357 358 ####################### Queues ###################### 359 360 class _ofp_queue_property_header(Packet): 361 name = "Dummy OpenFlow Queue Property Header" 362 363 def post_build(self, p, pay): 364 if self.len is None: 365 l = len(p)+len(pay) 366 p = p[:2] + struct.pack("!H", l) + p[4:] 367 return p + pay 368 369 ofp_queue_property_types = { 0: "OFPQT_NONE", 370 1: "OFPQT_MIN_RATE" } 371 372 class OFPQTNone(_ofp_queue_property_header): 373 name = "OFPQT_NONE" 374 fields_desc = [ ShortEnumField("type", 0, ofp_queue_property_types), 375 ShortField("len", 8), 376 XIntField("pad", 0) ] 377 378 class OFPQTMinRate(_ofp_queue_property_header): 379 name = "OFPQT_MIN_RATE" 380 fields_desc = [ ShortEnumField("type", 1, ofp_queue_property_types), 381 ShortField("len", 16), 382 XIntField("pad", 0), 383 ShortField("rate", 0), 384 XBitField("pad2", 0, 48) ] 385 386 ofp_queue_property_cls = { 0: OFPQTNone, 387 1: OFPQTMinRate } 388 389 class QueuePropertyPacketListField(PacketListField): 390 def m2i(self, pkt, s): 391 t = struct.unpack("!H", s[:2])[0] 392 return ofp_queue_property_cls.get(t, Raw)(s) 393 394 @staticmethod 395 def _get_queue_property_length(s): 396 return struct.unpack("!H", s[2:4])[0] 397 398 def getfield(self, pkt, s): 399 lst = [] 400 l = 0 401 ret = "" 402 remain = s 403 404 while remain: 405 l = QueuePropertyPacketListField._get_queue_property_length(remain) 406 current = remain[:l] 407 remain = remain[l:] 408 p = self.m2i(pkt, current) 409 lst.append(p) 410 411 return remain + ret, lst 412 413 class OFPPacketQueue(Packet): 414 415 def extract_padding(self, s): 416 return "", s 417 418 def post_build(self, p, pay): 419 if self.properties == []: 420 p += str(OFPQTNone()) 421 if self.len is None: 422 l = len(p)+len(pay) 423 p = p[:4] + struct.pack("!H", l) + p[6:] 424 return p + pay 425 426 name = "OFP_PACKET_QUEUE" 427 fields_desc = [ IntField("queue_id", 0), 428 ShortField("len", None), 429 XShortField("pad", 0), 430 QueuePropertyPacketListField("properties", [], Packet, 431 length_from=lambda pkt:pkt.len-8) ] 432 433 class QueuePacketListField(PacketListField): 434 435 @staticmethod 436 def _get_queue_length(s): 437 return struct.unpack("!H", s[4:6])[0] 438 439 def getfield(self, pkt, s): 440 lst = [] 441 l = 0 442 ret = "" 443 remain = s 444 445 while remain: 446 l = QueuePacketListField._get_queue_length(remain) 447 current = remain[:l] 448 remain = remain[l:] 449 p = OFPPacketQueue(current) 450 lst.append(p) 451 452 return remain + ret, lst 453 454 455 ##################################################### 456 ############## OpenFlow 1.0 Messages ################ 457 ##################################################### 458 459 class _ofp_header(Packet): 460 name = "Dummy OpenFlow Header" 461 462 def post_build(self, p, pay): 463 if self.len is None: 464 l = len(p)+len(pay) 465 p = p[:2] + struct.pack("!H", l) + p[4:] 466 return p + pay 467 468 ofp_version = { 0x01: "OpenFlow 1.0", 469 0x02: "OpenFlow 1.1", 470 0x03: "OpenFlow 1.2", 471 0x04: "OpenFlow 1.3", 472 0x05: "OpenFlow 1.4" } 473 474 ofp_type = { 0: "OFPT_HELLO", 475 1: "OFPT_ERROR", 476 2: "OFPT_ECHO_REQUEST", 477 3: "OFPT_ECHO_REPLY", 478 4: "OFPT_VENDOR", 479 5: "OFPT_FEATURES_REQUEST", 480 6: "OFPT_FEATURES_REPLY", 481 7: "OFPT_GET_CONFIG_REQUEST", 482 8: "OFPT_GET_CONFIG_REPLY", 483 9: "OFPT_SET_CONFIG", 484 10: "OFPT_PACKET_IN", 485 11: "OFPT_FLOW_REMOVED", 486 12: "OFPT_PORT_STATUS", 487 13: "OFPT_PACKET_OUT", 488 14: "OFPT_FLOW_MOD", 489 15: "OFPT_PORT_MOD", 490 16: "OFPT_STATS_REQUEST", 491 17: "OFPT_STATS_REPLY", 492 18: "OFPT_BARRIER_REQUEST", 493 19: "OFPT_BARRIER_REPLY", 494 20: "OFPT_QUEUE_GET_CONFIG_REQUEST", 495 21: "OFPT_QUEUE_GET_CONFIG_REPLY" } 496 497 class OFPTHello(_ofp_header): 498 name = "OFPT_HELLO" 499 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 500 ByteEnumField("type", 0, ofp_type), 501 ShortField("len", None), 502 IntField("xid", 0) ] 503 overload_fields = {TCP: {"sport": 6653}} 504 505 ##################################################### 506 #################### OFPT_ERROR ##################### 507 ##################################################### 508 509 ### this class will be used to display some messages 510 ### sent back by the switch after an error 511 class OFPacketField(PacketField): 512 def getfield(self, pkt, s): 513 try: 514 l = s[2:4] 515 l = struct.unpack("!H", l)[0] 516 ofload = s[:l] 517 remain = s[l:] 518 return remain, OpenFlow(None, ofload)(ofload) 519 except: 520 return "", Raw(s) 521 522 ofp_error_type = { 0: "OFPET_HELLO_FAILED", 523 1: "OFPET_BAD_REQUEST", 524 2: "OFPET_BAD_ACTION", 525 3: "OFPET_FLOW_MOD_FAILED", 526 4: "OFPET_PORT_MOD_FAILED", 527 5: "OFPET_QUEUE_OP_FAILED" } 528 529 class OFPETHelloFailed(_ofp_header): 530 name = "OFPET_HELLO_FAILED" 531 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 532 ByteEnumField("type", 1, ofp_type), 533 ShortField("len", None), 534 IntField("xid", 0), 535 ShortEnumField("errtype", 0, ofp_error_type), 536 ShortEnumField("errcode", 0, { 0: "OFPHFC_INCOMPATIBLE", 537 1: "OFPHFC_EPERM" }), 538 OFPacketField("data", "", Raw) ] 539 overload_fields = {TCP: {"dport": 6653}} 540 541 class OFPETBadRequest(_ofp_header): 542 name = "OFPET_BAD_REQUEST" 543 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 544 ByteEnumField("type", 1, ofp_type), 545 ShortField("len", None), 546 IntField("xid", 0), 547 ShortEnumField("errtype", 1, ofp_error_type), 548 ShortEnumField("errcode", 0, { 0: "OFPBRC_BAD_VERSION", 549 1: "OFPBRC_BAD_TYPE", 550 2: "OFPBRC_BAD_STAT", 551 3: "OFPBRC_BAD_VENDOR", 552 4: "OFPBRC_BAD_SUBTYPE", 553 5: "OFPBRC_EPERM", 554 6: "OFPBRC_BAD_LEN", 555 7: "OFPBRC_BUFFER_EMPTY", 556 8: "OFPBRC_BUFFER_UNKNOWN" }), 557 OFPacketField("data", "", Raw) ] 558 overload_fields = {TCP: {"dport": 6653}} 559 560 class OFPETBadAction(_ofp_header): 561 name = "OFPET_BAD_ACTION" 562 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 563 ByteEnumField("type", 1, ofp_type), 564 ShortField("len", None), 565 IntField("xid", 0), 566 ShortEnumField("errtype", 2, ofp_error_type), 567 ShortEnumField("errcode", 0, { 0: "OFPBAC_BAD_TYPE", 568 1: "OFPBAC_BAD_LEN", 569 2: "OFPBAC_BAD_VENDOR", 570 3: "OFPBAC_BAD_VENDOR_TYPE", 571 4: "OFPBAC_BAD_OUT_PORT", 572 5: "OFPBAC_BAD_ARGUMENT", 573 6: "OFPBAC_EPERM", 574 7: "OFPBAC_TOO_MANY", 575 8: "OFPBAC_BAD_QUEUE" }), 576 OFPacketField("data", "", Raw) ] 577 overload_fields = {TCP: {"dport": 6653}} 578 579 class OFPETFlowModFailed(_ofp_header): 580 name = "OFPET_FLOW_MOD_FAILED" 581 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 582 ByteEnumField("type", 1, ofp_type), 583 ShortField("len", None), 584 IntField("xid", 0), 585 ShortEnumField("errtype", 3, ofp_error_type), 586 ShortEnumField("errcode", 0, { 0: "OFPFMFC_ALL_TABLES_FULL", 587 1: "OFPFMFC_OVERLAP", 588 2: "OFPFMFC_EPERM", 589 3: "OFPFMFC_BAD_EMERG_TIMEOUT", 590 4: "OFPFMFC_BAD_COMMAND", 591 5: "OFPFMFC_UNSUPPORTED" }), 592 OFPacketField("data", "", Raw) ] 593 overload_fields = {TCP: {"dport": 6653}} 594 595 class OFPETPortModFailed(_ofp_header): 596 name = "OFPET_PORT_MOD_FAILED" 597 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 598 ByteEnumField("type", 1, ofp_type), 599 ShortField("len", None), 600 IntField("xid", 0), 601 ShortEnumField("errtype", 4, ofp_error_type), 602 ShortEnumField("errcode", 0, { 0: "OFPPMFC_BAD_PORT", 603 1: "OFPPMFC_BAD_HW_ADDR" }), 604 OFPacketField("data", "", Raw) ] 605 overload_fields = {TCP: {"dport": 6653}} 606 607 class OFPETQueueOpFailed(_ofp_header): 608 name = "OFPET_QUEUE_OP_FAILED" 609 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 610 ByteEnumField("type", 1, ofp_type), 611 ShortField("len", None), 612 IntField("xid", 0), 613 ShortEnumField("errtype", 5, ofp_error_type), 614 ShortEnumField("errcode", 0, { 0: "OFPQOFC_BAD_PORT", 615 1: "OFPQOFC_BAD_QUEUE", 616 2: "OFPQOFC_EPERM" }), 617 OFPacketField("data", "", Raw) ] 618 overload_fields = {TCP: {"dport": 6653}} 619 620 # ofp_error_cls allows generic method OpenFlow() to choose the right class for dissection 621 ofp_error_cls = { 0: OFPETHelloFailed, 622 1: OFPETBadRequest, 623 2: OFPETBadAction, 624 3: OFPETFlowModFailed, 625 4: OFPETPortModFailed, 626 5: OFPETQueueOpFailed } 627 628 ################ end of OFPT_ERRORS ################# 629 630 class OFPTEchoRequest(_ofp_header): 631 name = "OFPT_ECHO_REQUEST" 632 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 633 ByteEnumField("type", 2, ofp_type), 634 ShortField("len", None), 635 IntField("xid", 0) ] 636 overload_fields = {TCP: {"sport": 6653}} 637 638 class OFPTEchoReply(_ofp_header): 639 name = "OFPT_ECHO_REPLY" 640 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 641 ByteEnumField("type", 3, ofp_type), 642 ShortField("len", None), 643 IntField("xid", 0) ] 644 overload_fields = {TCP: {"sport": 6653}} 645 646 class OFPTVendor(_ofp_header): 647 name = "OFPT_VENDOR" 648 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 649 ByteEnumField("type", 4, ofp_type), 650 ShortField("len", None), 651 IntField("xid", 0), 652 IntField("vendor", 0) ] 653 overload_fields = {TCP: {"sport": 6653}} 654 655 class OFPTFeaturesRequest(_ofp_header): 656 name = "OFPT_FEATURES_REQUEST" 657 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 658 ByteEnumField("type", 5, ofp_type), 659 ShortField("len", None), 660 IntField("xid", 0) ] 661 overload_fields = {TCP: {"sport": 6653}} 662 663 ofp_action_types_flags = list(ofp_action_types.values())[:-1] # no ofpat_vendor flag 664 665 class OFPTFeaturesReply(_ofp_header): 666 name = "OFPT_FEATURES_REPLY" 667 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 668 ByteEnumField("type", 6, ofp_type), 669 ShortField("len", None), 670 IntField("xid", 0), 671 LongField("datapath_id", 0), 672 IntField("n_buffers", 0), 673 ByteField("n_tables", 1), 674 X3BytesField("pad", 0), 675 FlagsField("capabilities", 0, 32, [ "FLOW_STATS", 676 "TABLE_STATS", 677 "PORT_STATS", 678 "STP", 679 "RESERVED", 680 "IP_REASM", 681 "QUEUE_STATS", 682 "ARP_MATCH_IP" ]), 683 FlagsField("actions", 0, 32, ofp_action_types_flags), 684 PacketListField("ports", None, OFPPhyPort, 685 length_from=lambda pkt:pkt.len-32) ] 686 overload_fields = {TCP: {"dport": 6653}} 687 688 class OFPTGetConfigRequest(_ofp_header): 689 name = "OFPT_GET_CONFIG_REQUEST" 690 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 691 ByteEnumField("type", 7, ofp_type), 692 ShortField("len", None), 693 IntField("xid", 0) ] 694 overload_fields = {TCP: {"sport": 6653}} 695 696 class OFPTGetConfigReply(_ofp_header): 697 name = "OFPT_GET_CONFIG_REPLY" 698 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 699 ByteEnumField("type", 8, ofp_type), 700 ShortField("len", None), 701 IntField("xid", 0), 702 ShortEnumField("flags", 0, { 0: "FRAG_NORMAL", 703 1: "FRAG_DROP", 704 2: "FRAG_REASM", 705 3: "FRAG_MASK" }), 706 ShortField("miss_send_len", 0) ] 707 overload_fields = {TCP: {"dport": 6653}} 708 709 class OFPTSetConfig(_ofp_header): 710 name = "OFPT_SET_CONFIG" 711 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 712 ByteEnumField("type", 9, ofp_type), 713 ShortField("len", None), 714 IntField("xid", 0), 715 ShortEnumField("flags", 0, { 0: "FRAG_NORMAL", 716 1: "FRAG_DROP", 717 2: "FRAG_REASM", 718 3: "FRAG_MASK" }), 719 ShortField("miss_send_len", 128) ] 720 overload_fields = {TCP: {"sport": 6653}} 721 722 class OFPTPacketIn(_ofp_header): 723 name = "OFPT_PACKET_IN" 724 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 725 ByteEnumField("type", 10, ofp_type), 726 ShortField("len", None), 727 IntField("xid", 0), 728 IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer), 729 ShortField("total_len", 0), 730 ShortEnumField("in_port", 0, ofp_port_no), 731 ByteEnumField("reason", 0, { 0: "OFPR_NO_MATCH", 732 1: "OFPR_ACTION" }), 733 XByteField("pad", 0), 734 PacketField("data", None, Ether) ] 735 overload_fields = {TCP: {"dport": 6653}} 736 737 class OFPTFlowRemoved(_ofp_header): 738 name = "OFPT_FLOW_REMOVED" 739 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 740 ByteEnumField("type", 11, ofp_type), 741 ShortField("len", None), 742 IntField("xid", 0), 743 PacketField("match", OFPMatch(), OFPMatch), 744 LongField("cookie", 0), 745 ShortField("priority", 0), 746 ByteEnumField("reason", 0, { 0: "OFPRR_IDLE_TIMEOUT", 747 1: "OFPRR_HARD_TIMEOUT", 748 2: "OFPRR_DELETE" }), 749 XByteField("pad1", 0), 750 IntField("duration_sec", 0), 751 IntField("duration_nsec", 0), 752 ShortField("idle_timeout", 0), 753 XShortField("pad2", 0), 754 LongField("packet_count", 0), 755 LongField("byte_count", 0) ] 756 overload_fields = {TCP: {"dport": 6653}} 757 758 class OFPTPortStatus(_ofp_header): 759 name = "OFPT_PORT_STATUS" 760 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 761 ByteEnumField("type", 12, ofp_type), 762 ShortField("len", None), 763 IntField("xid", 0), 764 ByteEnumField("reason", 0, { 0: "OFPPR_ADD", 765 1: "OFPPR_DELETE", 766 2: "OFPPR_MODIFY" }), 767 XBitField("pad", 0, 56), 768 PacketField("desc", OFPPhyPort(), OFPPhyPort) ] 769 overload_fields = {TCP: {"dport": 6653}} 770 771 class OFPTPacketOut(_ofp_header): 772 name = "OFPT_PACKET_OUT" 773 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 774 ByteEnumField("type", 13, ofp_type), 775 ShortField("len", None), 776 IntField("xid", 0), 777 IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer), 778 ShortEnumField("in_port", "NONE", ofp_port_no), 779 FieldLenField("actions_len", None, fmt="H", length_of="actions"), 780 ActionPacketListField("actions", [], Packet, 781 length_from=lambda pkt:pkt.actions_len), 782 PacketField("data", None, Ether) ] 783 overload_fields = {TCP: {"sport": 6653}} 784 785 class OFPTFlowMod(_ofp_header): 786 name = "OFPT_FLOW_MOD" 787 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 788 ByteEnumField("type", 14, ofp_type), 789 ShortField("len", None), 790 IntField("xid", 0), 791 PacketField("match", OFPMatch(), OFPMatch), 792 LongField("cookie", 0), 793 ShortEnumField("cmd", 0, { 0: "OFPFC_ADD", 794 1: "OFPFC_MODIFY", 795 2: "OFPFC_MODIFY_STRICT", 796 3: "OFPFC_DELETE", 797 4: "OFPFC_DELETE_STRICT" }), 798 ShortField("idle_timeout", 0), 799 ShortField("hard_timeout", 0), 800 ShortField("priority", 0), 801 IntEnumField("buffer_id", "NO_BUFFER", ofp_buffer), 802 ShortEnumField("out_port", "NONE", ofp_port_no), 803 FlagsField("flags", 0, 16, [ "SEND_FLOW_REM", 804 "CHECK_OVERLAP", 805 "EMERG" ]), 806 ActionPacketListField("actions", [], Packet, 807 length_from=lambda pkt:pkt.len-72) ] 808 overload_fields = {TCP: {"sport": 6653}} 809 810 class OFPTPortMod(_ofp_header): 811 name = "OFPT_PORT_MOD" 812 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 813 ByteEnumField("type", 15, ofp_type), 814 ShortField("len", None), 815 IntField("xid", 0), 816 ShortEnumField("port_no", 0, ofp_port_no), 817 MACField("hw_addr", "0"), 818 FlagsField("config", 0, 32, ofp_port_config), 819 FlagsField("mask", 0, 32, ofp_port_config), 820 FlagsField("advertise", 0, 32, ofp_port_features), 821 IntField("pad", 0) ] 822 overload_fields = {TCP: {"sport": 6653}} 823 824 ##################################################### 825 ##################### OFPT_STATS #################### 826 ##################################################### 827 828 ofp_stats_types = { 0: "OFPST_DESC", 829 1: "OFPST_FLOW", 830 2: "OFPST_AGGREGATE", 831 3: "OFPST_TABLE", 832 4: "OFPST_PORT", 833 5: "OFPST_QUEUE", 834 65535: "OFPST_VENDOR" } 835 836 class OFPTStatsRequestDesc(_ofp_header): 837 name = "OFPST_STATS_REQUEST_DESC" 838 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 839 ByteEnumField("type", 16, ofp_type), 840 ShortField("len", None), 841 IntField("xid", 0), 842 ShortEnumField("stats_type", 0, ofp_stats_types), 843 FlagsField("flags", 0, 16, []) ] 844 overload_fields = {TCP: {"sport": 6653}} 845 846 class OFPTStatsReplyDesc(_ofp_header): 847 name = "OFPST_STATS_REPLY_DESC" 848 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 849 ByteEnumField("type", 17, ofp_type), 850 ShortField("len", None), 851 IntField("xid", 0), 852 ShortEnumField("stats_type", 0, ofp_stats_types), 853 FlagsField("flags", 0, 16, []), 854 StrFixedLenField("mfr_desc", "", 256), 855 StrFixedLenField("hw_desc", "", 256), 856 StrFixedLenField("sw_desc", "", 256), 857 StrFixedLenField("serial_num", "", 32), 858 StrFixedLenField("dp_desc", "", 256) ] 859 overload_fields = {TCP: {"dport": 6653}} 860 861 class OFPTStatsRequestFlow(_ofp_header): 862 name = "OFPST_STATS_REQUEST_FLOW" 863 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 864 ByteEnumField("type", 16, ofp_type), 865 ShortField("len", None), 866 IntField("xid", 0), 867 ShortEnumField("stats_type", 1, ofp_stats_types), 868 FlagsField("flags", 0, 16, []), 869 PacketField("match", OFPMatch(), OFPMatch), 870 ByteEnumField("table_id", "ALL", ofp_table), 871 ByteField("pad", 0), 872 ShortEnumField("out_port", "NONE", ofp_port_no) ] 873 overload_fields = {TCP: {"sport": 6653}} 874 875 class OFPFlowStats(Packet): 876 877 def post_build(self, p, pay): 878 if self.length is None: 879 l = len(p)+len(pay) 880 p = struct.pack("!H", l) + p[2:] 881 return p + pay 882 883 name = "OFP_FLOW_STATS" 884 fields_desc = [ ShortField("length", None), 885 ByteField("table_id", 0), 886 XByteField("pad1", 0), 887 PacketField("match", OFPMatch(), OFPMatch), 888 IntField("duration_sec", 0), 889 IntField("duration_nsec", 0), 890 ShortField("priority", 0), 891 ShortField("idle_timeout", 0), 892 ShortField("hard_timeout", 0), 893 XBitField("pad2", 0, 48), 894 LongField("cookie", 0), 895 LongField("packet_count", 0), 896 LongField("byte_count", 0), 897 ActionPacketListField("actions", [], Packet, 898 length_from=lambda pkt:pkt.length-88) ] 899 900 class FlowStatsPacketListField(PacketListField): 901 902 @staticmethod 903 def _get_flow_stats_length(s): 904 return struct.unpack("!H", s[:2])[0] 905 906 def getfield(self, pkt, s): 907 lst = [] 908 remain = s 909 910 while remain: 911 l = FlowStatsPacketListField._get_flow_stats_length(remain) 912 current = remain[:l] 913 remain = remain[l:] 914 p = OFPFlowStats(current) 915 lst.append(p) 916 917 return remain, lst 918 919 class OFPTStatsReplyFlow(_ofp_header): 920 name = "OFPST_STATS_REPLY_FLOW" 921 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 922 ByteEnumField("type", 17, ofp_type), 923 ShortField("len", None), 924 IntField("xid", 0), 925 ShortEnumField("stats_type", 1, ofp_stats_types), 926 FlagsField("flags", 0, 16, []), 927 FlowStatsPacketListField("flow_stats", [], Packet, 928 length_from=lambda pkt:pkt.len-12) ] 929 overload_fields = {TCP: {"dport": 6653}} 930 931 class OFPTStatsRequestAggregate(_ofp_header): 932 name = "OFPST_STATS_REQUEST_AGGREGATE" 933 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 934 ByteEnumField("type", 16, ofp_type), 935 ShortField("len", None), 936 IntField("xid", 0), 937 ShortEnumField("stats_type", 2, ofp_stats_types), 938 FlagsField("flags", 0, 16, []), 939 PacketField("match", OFPMatch(), OFPMatch), 940 ByteEnumField("table_id", "ALL", ofp_table), 941 ByteField("pad", 0), 942 ShortEnumField("out_port", "NONE", ofp_port_no) ] 943 overload_fields = {TCP: {"sport": 6653}} 944 945 class OFPTStatsReplyAggregate(_ofp_header): 946 name = "OFPST_STATS_REPLY_AGGREGATE" 947 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 948 ByteEnumField("type", 17, ofp_type), 949 ShortField("len", None), 950 IntField("xid", 0), 951 ShortEnumField("stats_type", 2, ofp_stats_types), 952 FlagsField("flags", 0, 16, []), 953 LongField("packet_count", 0), 954 LongField("byte_count", 0), 955 IntField("flow_count", 0), 956 XIntField("pad", 0) ] 957 overload_fields = {TCP: {"dport": 6653}} 958 959 class OFPTStatsRequestTable(_ofp_header): 960 name = "OFPST_STATS_REQUEST_TABLE" 961 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 962 ByteEnumField("type", 16, ofp_type), 963 ShortField("len", None), 964 IntField("xid", 0), 965 ShortEnumField("stats_type", 3, ofp_stats_types), 966 FlagsField("flags", 0, 16, []) ] 967 overload_fields = {TCP: {"sport": 6653}} 968 969 class OFPTableStats(Packet): 970 971 def extract_padding(self, s): 972 return "", s 973 974 name = "OFP_TABLE_STATS" 975 fields_desc = [ ByteField("table_id", 0), 976 X3BytesField("pad", 0), 977 StrFixedLenField("name", "", 32), 978 FlagsField("wildcards1", 0x003, 12, [ "DL_VLAN_PCP", 979 "NW_TOS" ]), 980 BitField("nw_dst_mask", 63, 6), # 32 would be enough 981 BitField("nw_src_mask", 63, 6), 982 FlagsField("wildcards2", 0xff, 8, [ "IN_PORT", 983 "DL_VLAN", 984 "DL_SRC", 985 "DL_DST", 986 "DL_TYPE", 987 "NW_PROTO", 988 "TP_SRC", 989 "TP_DST" ]), 990 IntField("max_entries", 0), 991 IntField("active_count", 0), 992 LongField("lookup_count", 0), 993 LongField("matched_count", 0) ] 994 995 class OFPTStatsReplyTable(_ofp_header): 996 name = "OFPST_STATS_REPLY_TABLE" 997 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 998 ByteEnumField("type", 17, ofp_type), 999 ShortField("len", None), 1000 IntField("xid", 0), 1001 ShortEnumField("stats_type", 3, ofp_stats_types), 1002 FlagsField("flags", 0, 16, []), 1003 PacketListField("table_stats", None, OFPTableStats, 1004 length_from=lambda pkt:pkt.len-12) ] 1005 overload_fields = {TCP: {"dport": 6653}} 1006 1007 class OFPTStatsRequestPort(_ofp_header): 1008 name = "OFPST_STATS_REQUEST_PORT" 1009 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1010 ByteEnumField("type", 16, ofp_type), 1011 ShortField("len", None), 1012 IntField("xid", 0), 1013 ShortEnumField("stats_type", 4, ofp_stats_types), 1014 FlagsField("flags", 0, 16, []), 1015 ShortEnumField("port_no", "NONE", ofp_port_no), 1016 XBitField("pad", 0, 48) ] 1017 overload_fields = {TCP: {"sport": 6653}} 1018 1019 class OFPPortStats(Packet): 1020 1021 def extract_padding(self, s): 1022 return "", s 1023 1024 name = "OFP_PORT_STATS" 1025 fields_desc = [ ShortEnumField("port_no", 0, ofp_port_no), 1026 XBitField("pad", 0, 48), 1027 LongField("rx_packets", 0), 1028 LongField("tx_packets", 0), 1029 LongField("rx_bytes", 0), 1030 LongField("tx_bytes", 0), 1031 LongField("rx_dropped", 0), 1032 LongField("tx_dropped", 0), 1033 LongField("rx_errors", 0), 1034 LongField("tx_errors", 0), 1035 LongField("rx_frame_err", 0), 1036 LongField("rx_over_err", 0), 1037 LongField("rx_crc_err", 0), 1038 LongField("collisions", 0) ] 1039 1040 class OFPTStatsReplyPort(_ofp_header): 1041 name = "OFPST_STATS_REPLY_TABLE" 1042 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1043 ByteEnumField("type", 17, ofp_type), 1044 ShortField("len", None), 1045 IntField("xid", 0), 1046 ShortEnumField("stats_type", 4, ofp_stats_types), 1047 FlagsField("flags", 0, 16, []), 1048 PacketListField("port_stats", None, OFPPortStats, 1049 length_from=lambda pkt:pkt.len-12) ] 1050 overload_fields = {TCP: {"dport": 6653}} 1051 1052 class OFPTStatsRequestQueue(_ofp_header): 1053 name = "OFPST_STATS_REQUEST_QUEUE" 1054 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1055 ByteEnumField("type", 16, ofp_type), 1056 ShortField("len", None), 1057 IntField("xid", 0), 1058 ShortEnumField("stats_type", 5, ofp_stats_types), 1059 FlagsField("flags", 0, 16, []), 1060 ShortEnumField("port_no", "NONE", ofp_port_no), 1061 XShortField("pad", 0), 1062 IntEnumField("queue_id", "ALL", ofp_queue) ] 1063 overload_fields = {TCP: {"sport": 6653}} 1064 1065 class OFPTStatsReplyQueue(_ofp_header): 1066 name = "OFPST_STATS_REPLY_QUEUE" 1067 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1068 ByteEnumField("type", 17, ofp_type), 1069 ShortField("len", None), 1070 IntField("xid", 0), 1071 ShortEnumField("stats_type", 5, ofp_stats_types), 1072 FlagsField("flags", 0, 16, []), 1073 ShortEnumField("port_no", "NONE", ofp_port_no), 1074 XShortField("pad", 0), 1075 IntEnumField("queue_id", "ALL", ofp_queue), 1076 LongField("tx_bytes", 0), 1077 LongField("tx_packets", 0), 1078 LongField("tx_errors", 0) ] 1079 overload_fields = {TCP: {"dport": 6653}} 1080 1081 class OFPTStatsRequestVendor(_ofp_header): 1082 name = "OFPST_STATS_REQUEST_VENDOR" 1083 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1084 ByteEnumField("type", 16, ofp_type), 1085 ShortField("len", None), 1086 IntField("xid", 0), 1087 ShortEnumField("stats_type", 6, ofp_stats_types), 1088 FlagsField("flags", 0, 16, []), 1089 IntField("vendor", 0) ] 1090 overload_fields = {TCP: {"sport": 6653}} 1091 1092 class OFPTStatsReplyVendor(_ofp_header): 1093 name = "OFPST_STATS_REPLY_VENDOR" 1094 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1095 ByteEnumField("type", 17, ofp_type), 1096 ShortField("len", None), 1097 IntField("xid", 0), 1098 ShortEnumField("stats_type", 6, ofp_stats_types), 1099 FlagsField("flags", 0, 16, []), 1100 IntField("vendor", 0) ] 1101 overload_fields = {TCP: {"dport": 6653}} 1102 1103 # ofp_stats_request/reply_cls allows generic method OpenFlow() (end of script) 1104 # to choose the right class for dissection 1105 ofp_stats_request_cls = { 0: OFPTStatsRequestDesc, 1106 1: OFPTStatsRequestFlow, 1107 2: OFPTStatsRequestAggregate, 1108 3: OFPTStatsRequestTable, 1109 4: OFPTStatsRequestPort, 1110 5: OFPTStatsRequestQueue, 1111 65535: OFPTStatsRequestVendor } 1112 1113 ofp_stats_reply_cls = { 0: OFPTStatsReplyDesc, 1114 1: OFPTStatsReplyFlow, 1115 2: OFPTStatsReplyAggregate, 1116 3: OFPTStatsReplyTable, 1117 4: OFPTStatsReplyPort, 1118 5: OFPTStatsReplyQueue, 1119 65535: OFPTStatsReplyVendor } 1120 1121 ################ end of OFPT_STATS ################## 1122 1123 class OFPTBarrierRequest(_ofp_header): 1124 name = "OFPT_BARRIER_REQUEST" 1125 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1126 ByteEnumField("type", 18, ofp_type), 1127 ShortField("len", None), 1128 IntField("xid", 0) ] 1129 overload_fields = {TCP: {"sport": 6653}} 1130 1131 class OFPTBarrierReply(_ofp_header): 1132 name = "OFPT_BARRIER_REPLY" 1133 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1134 ByteEnumField("type", 19, ofp_type), 1135 ShortField("len", None), 1136 IntField("xid", 0) ] 1137 overload_fields = {TCP: {"dport": 6653}} 1138 1139 class OFPTQueueGetConfigRequest(_ofp_header): 1140 name = "OFPT_QUEUE_GET_CONFIG_REQUEST" 1141 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1142 ByteEnumField("type", 20, ofp_type), 1143 ShortField("len", None), 1144 IntField("xid", 0), 1145 ShortEnumField("port", 0, ofp_port_no), 1146 XShortField("pad", 0) ] 1147 overload_fields = {TCP: {"sport": 6653}} 1148 1149 class OFPTQueueGetConfigReply(_ofp_header): 1150 name = "OFPT_QUEUE_GET_CONFIG_REPLY" 1151 fields_desc = [ ByteEnumField("version", 0x01, ofp_version), 1152 ByteEnumField("type", 21, ofp_type), 1153 ShortField("len", None), 1154 IntField("xid", 0), 1155 ShortEnumField("port", 0, ofp_port_no), 1156 XBitField("pad", 0, 48), 1157 QueuePacketListField("queues", [], Packet, 1158 length_from=lambda pkt:pkt.len-16) ] 1159 overload_fields = {TCP: {"dport": 6653}} 1160 1161 # ofpt_cls allows generic method OpenFlow() to choose the right class for dissection 1162 ofpt_cls = { 0: OFPTHello, 1163 #1: OFPTError, 1164 2: OFPTEchoRequest, 1165 3: OFPTEchoReply, 1166 4: OFPTVendor, 1167 5: OFPTFeaturesRequest, 1168 6: OFPTFeaturesReply, 1169 7: OFPTGetConfigRequest, 1170 8: OFPTGetConfigReply, 1171 9: OFPTSetConfig, 1172 10: OFPTPacketIn, 1173 11: OFPTFlowRemoved, 1174 12: OFPTPortStatus, 1175 13: OFPTPacketOut, 1176 14: OFPTFlowMod, 1177 15: OFPTPortMod, 1178 #16: OFPTStatsRequest, 1179 #17: OFPTStatsReply, 1180 18: OFPTBarrierRequest, 1181 19: OFPTBarrierReply, 1182 20: OFPTQueueGetConfigRequest, 1183 21: OFPTQueueGetConfigReply } 1184 1185 TCP_guess_payload_class_copy = TCP.guess_payload_class 1186 1187 def OpenFlow(self, payload): 1188 if self is None or self.dport == 6653 or self.dport == 6633 or self.sport == 6653 or self.sport == 6633: 1189 # port 6653 has been allocated by IANA, port 6633 should no longer be used 1190 # OpenFlow function may be called with None self in OFPPacketField 1191 of_type = orb(payload[1]) 1192 if of_type == 1: 1193 err_type = orb(payload[9]) 1194 # err_type is a short int, but last byte is enough 1195 if err_type == 255: err_type = 65535 1196 return ofp_error_cls[err_type] 1197 elif of_type == 16: 1198 mp_type = orb(payload[9]) 1199 if mp_type == 255: mp_type = 65535 1200 return ofp_stats_request_cls[mp_type] 1201 elif of_type == 17: 1202 mp_type = orb(payload[9]) 1203 if mp_type == 255: mp_type = 65535 1204 return ofp_stats_reply_cls[mp_type] 1205 else: 1206 return ofpt_cls[of_type] 1207 else: 1208 return TCP_guess_payload_class_copy(self, payload) 1209 1210 TCP.guess_payload_class = OpenFlow 1211