1# Copyright (C) 2011-2015 Nippon Telegraph and Telephone Corporation. 2# Copyright (C) 2011, 2012 Isaku Yamahata <yamahata at valinux co jp> 3# Copyright (C) 2012 Simon Horman <horms ad verge net au> 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 14# implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17 18import struct 19 20from ryu import exception 21from ryu.lib import mac 22from ryu.lib.pack_utils import msg_pack_into 23from ryu.ofproto import ether 24from ryu.ofproto import ofproto_parser 25from ryu.ofproto import ofproto_v1_0 26from ryu.ofproto import inet 27 28 29import logging 30LOG = logging.getLogger('ryu.ofproto.nx_match') 31 32 33UINT64_MAX = (1 << 64) - 1 34UINT32_MAX = (1 << 32) - 1 35UINT16_MAX = (1 << 16) - 1 36 37FWW_IN_PORT = 1 << 0 38FWW_DL_TYPE = 1 << 4 39FWW_NW_PROTO = 1 << 5 40# No corresponding OFPFW_* bits 41FWW_NW_DSCP = 1 << 1 42FWW_NW_ECN = 1 << 2 43FWW_ARP_SHA = 1 << 3 44FWW_ARP_THA = 1 << 6 45FWW_IPV6_LABEL = 1 << 7 46FWW_NW_TTL = 1 << 8 47FWW_ALL = (1 << 13) - 1 48 49FLOW_NW_FRAG_ANY = 1 << 0 50FLOW_NW_FRAG_LATER = 1 << 1 51FLOW_NW_FRAG_MASK = FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER 52 53IP_ECN_MASK = 0x03 54IP_DSCP_MASK = 0xfc 55 56MF_PACK_STRING_BE64 = '!Q' 57MF_PACK_STRING_BE32 = '!I' 58MF_PACK_STRING_BE16 = '!H' 59MF_PACK_STRING_8 = '!B' 60MF_PACK_STRING_MAC = '!6s' 61MF_PACK_STRING_IPV6 = '!8H' 62 63_MF_FIELDS = {} 64 65FLOW_N_REGS = 8 # ovs 1.5 66 67 68class Flow(ofproto_parser.StringifyMixin): 69 def __init__(self): 70 self.in_port = 0 71 self.dl_vlan = 0 72 self.dl_vlan_pcp = 0 73 self.dl_src = mac.DONTCARE 74 self.dl_dst = mac.DONTCARE 75 self.dl_type = 0 76 self.tp_dst = 0 77 self.tp_src = 0 78 self.nw_tos = 0 79 self.vlan_tci = 0 80 self.nw_ttl = 0 81 self.nw_proto = 0 82 self.arp_sha = 0 83 self.arp_tha = 0 84 self.nw_src = 0 85 self.nw_dst = 0 86 self.tun_id = 0 87 self.arp_spa = 0 88 self.arp_tpa = 0 89 self.ipv6_src = [] 90 self.ipv6_dst = [] 91 self.nd_target = [] 92 self.nw_frag = 0 93 self.regs = [0] * FLOW_N_REGS 94 self.ipv6_label = 0 95 self.pkt_mark = 0 96 self.tcp_flags = 0 97 98 99class FlowWildcards(ofproto_parser.StringifyMixin): 100 def __init__(self): 101 self.dl_src_mask = 0 102 self.dl_dst_mask = 0 103 self.tp_src_mask = 0 104 self.tp_dst_mask = 0 105 self.nw_src_mask = 0 106 self.nw_dst_mask = 0 107 self.tun_id_mask = 0 108 self.arp_spa_mask = 0 109 self.arp_tpa_mask = 0 110 self.vlan_tci_mask = 0 111 self.ipv6_src_mask = [] 112 self.ipv6_dst_mask = [] 113 self.nd_target_mask = [] 114 self.nw_frag_mask = 0 115 self.regs_bits = 0 116 self.regs_mask = [0] * FLOW_N_REGS 117 self.wildcards = ofproto_v1_0.OFPFW_ALL 118 self.pkt_mark_mask = 0 119 self.tcp_flags_mask = 0 120 121 122class ClsRule(ofproto_parser.StringifyMixin): 123 """describe a matching rule for OF 1.0 OFPMatch (and NX). 124 """ 125 126 def __init__(self, **kwargs): 127 self.wc = FlowWildcards() 128 self.flow = Flow() 129 130 for key, value in kwargs.items(): 131 if key[:3] == 'reg': 132 register = int(key[3:] or -1) 133 self.set_reg(register, value) 134 continue 135 136 setter = getattr(self, 'set_' + key, None) 137 if not setter: 138 LOG.error('Invalid kwarg specified to ClsRule (%s)', key) 139 continue 140 141 if not isinstance(value, (tuple, list)): 142 value = (value, ) 143 144 setter(*value) 145 146 def set_in_port(self, port): 147 self.wc.wildcards &= ~FWW_IN_PORT 148 self.flow.in_port = port 149 150 def set_dl_vlan(self, dl_vlan): 151 self.wc.wildcards &= ~ofproto_v1_0.OFPFW_DL_VLAN 152 self.flow.dl_vlan = dl_vlan 153 154 def set_dl_vlan_pcp(self, dl_vlan_pcp): 155 self.wc.wildcards &= ~ofproto_v1_0.OFPFW_DL_VLAN_PCP 156 self.flow.dl_vlan_pcp = dl_vlan_pcp 157 158 def set_dl_dst(self, dl_dst): 159 self.flow.dl_dst = dl_dst 160 161 def set_dl_dst_masked(self, dl_dst, mask): 162 self.wc.dl_dst_mask = mask 163 # bit-wise and of the corresponding elements of dl_dst and mask 164 self.flow.dl_dst = mac.haddr_bitand(dl_dst, mask) 165 166 def set_dl_src(self, dl_src): 167 self.flow.dl_src = dl_src 168 169 def set_dl_src_masked(self, dl_src, mask): 170 self.wc.dl_src_mask = mask 171 self.flow.dl_src = mac.haddr_bitand(dl_src, mask) 172 173 def set_dl_type(self, dl_type): 174 self.wc.wildcards &= ~FWW_DL_TYPE 175 self.flow.dl_type = dl_type 176 177 def set_dl_tci(self, tci): 178 self.set_dl_tci_masked(tci, UINT16_MAX) 179 180 def set_dl_tci_masked(self, tci, mask): 181 self.wc.vlan_tci_mask = mask 182 self.flow.vlan_tci = tci 183 184 def set_tp_src(self, tp_src): 185 self.set_tp_src_masked(tp_src, UINT16_MAX) 186 187 def set_tp_src_masked(self, tp_src, mask): 188 self.wc.tp_src_mask = mask 189 self.flow.tp_src = tp_src & mask 190 191 def set_tp_dst(self, tp_dst): 192 self.set_tp_dst_masked(tp_dst, UINT16_MAX) 193 194 def set_tp_dst_masked(self, tp_dst, mask): 195 self.wc.tp_dst_mask = mask 196 self.flow.tp_dst = tp_dst & mask 197 198 def set_nw_proto(self, nw_proto): 199 self.wc.wildcards &= ~FWW_NW_PROTO 200 self.flow.nw_proto = nw_proto 201 202 def set_nw_src(self, nw_src): 203 self.set_nw_src_masked(nw_src, UINT32_MAX) 204 205 def set_nw_src_masked(self, nw_src, mask): 206 self.flow.nw_src = nw_src 207 self.wc.nw_src_mask = mask 208 209 def set_nw_dst(self, nw_dst): 210 self.set_nw_dst_masked(nw_dst, UINT32_MAX) 211 212 def set_nw_dst_masked(self, nw_dst, mask): 213 self.flow.nw_dst = nw_dst 214 self.wc.nw_dst_mask = mask 215 216 def set_nw_dscp(self, nw_dscp): 217 self.wc.wildcards &= ~FWW_NW_DSCP 218 self.flow.nw_tos &= ~IP_DSCP_MASK 219 self.flow.nw_tos |= nw_dscp & IP_DSCP_MASK 220 221 def set_icmp_type(self, icmp_type): 222 self.set_tp_src(icmp_type) 223 224 def set_icmp_code(self, icmp_code): 225 self.set_tp_dst(icmp_code) 226 227 def set_tun_id(self, tun_id): 228 self.set_tun_id_masked(tun_id, UINT64_MAX) 229 230 def set_tun_id_masked(self, tun_id, mask): 231 self.wc.tun_id_mask = mask 232 self.flow.tun_id = tun_id & mask 233 234 def set_nw_ecn(self, nw_ecn): 235 self.wc.wildcards &= ~FWW_NW_ECN 236 self.flow.nw_tos &= ~IP_ECN_MASK 237 self.flow.nw_tos |= nw_ecn & IP_ECN_MASK 238 239 def set_nw_ttl(self, nw_ttl): 240 self.wc.wildcards &= ~FWW_NW_TTL 241 self.flow.nw_ttl = nw_ttl 242 243 def set_nw_frag(self, nw_frag): 244 self.wc.nw_frag_mask |= FLOW_NW_FRAG_MASK 245 self.flow.nw_frag = nw_frag 246 247 def set_nw_frag_masked(self, nw_frag, mask): 248 self.wc.nw_frag_mask = mask 249 self.flow.nw_frag = nw_frag & mask 250 251 def set_arp_spa(self, spa): 252 self.set_arp_spa_masked(spa, UINT32_MAX) 253 254 def set_arp_spa_masked(self, spa, mask): 255 self.flow.arp_spa = spa 256 self.wc.arp_spa_mask = mask 257 258 def set_arp_tpa(self, tpa): 259 self.set_arp_tpa_masked(tpa, UINT32_MAX) 260 261 def set_arp_tpa_masked(self, tpa, mask): 262 self.flow.arp_tpa = tpa 263 self.wc.arp_tpa_mask = mask 264 265 def set_arp_sha(self, sha): 266 self.wc.wildcards &= ~FWW_ARP_SHA 267 self.flow.arp_sha = sha 268 269 def set_arp_tha(self, tha): 270 self.wc.wildcards &= ~FWW_ARP_THA 271 self.flow.arp_tha = tha 272 273 def set_icmpv6_type(self, icmp_type): 274 self.set_tp_src(icmp_type) 275 276 def set_icmpv6_code(self, icmp_code): 277 self.set_tp_dst(icmp_code) 278 279 def set_ipv6_label(self, label): 280 self.wc.wildcards &= ~FWW_IPV6_LABEL 281 self.flow.ipv6_label = label 282 283 def set_ipv6_src_masked(self, src, mask): 284 self.wc.ipv6_src_mask = mask 285 self.flow.ipv6_src = [x & y for (x, y) in zip(src, mask)] 286 287 def set_ipv6_src(self, src): 288 self.flow.ipv6_src = src 289 290 def set_ipv6_dst_masked(self, dst, mask): 291 self.wc.ipv6_dst_mask = mask 292 self.flow.ipv6_dst = [x & y for (x, y) in zip(dst, mask)] 293 294 def set_ipv6_dst(self, dst): 295 self.flow.ipv6_dst = dst 296 297 def set_nd_target_masked(self, target, mask): 298 self.wc.nd_target_mask = mask 299 self.flow.nd_target = [x & y for (x, y) in 300 zip(target, mask)] 301 302 def set_nd_target(self, target): 303 self.flow.nd_target = target 304 305 def set_reg(self, reg_idx, value): 306 self.set_reg_masked(reg_idx, value, 0) 307 308 def set_reg_masked(self, reg_idx, value, mask): 309 self.wc.regs_mask[reg_idx] = mask 310 self.flow.regs[reg_idx] = value 311 self.wc.regs_bits |= (1 << reg_idx) 312 313 def set_pkt_mark_masked(self, pkt_mark, mask): 314 self.flow.pkt_mark = pkt_mark 315 self.wc.pkt_mark_mask = mask 316 317 def set_tcp_flags(self, tcp_flags, mask): 318 self.flow.tcp_flags = tcp_flags 319 self.wc.tcp_flags_mask = mask 320 321 def flow_format(self): 322 # Tunnel ID is only supported by NXM 323 if self.wc.tun_id_mask != 0: 324 return ofproto_v1_0.NXFF_NXM 325 326 # Masking DL_DST is only supported by NXM 327 if self.wc.dl_dst_mask: 328 return ofproto_v1_0.NXFF_NXM 329 330 # Masking DL_SRC is only supported by NXM 331 if self.wc.dl_src_mask: 332 return ofproto_v1_0.NXFF_NXM 333 334 # ECN is only supported by NXM 335 if not self.wc.wildcards & FWW_NW_ECN: 336 return ofproto_v1_0.NXFF_NXM 337 338 if self.wc.regs_bits > 0: 339 return ofproto_v1_0.NXFF_NXM 340 341 if self.flow.tcp_flags > 0: 342 return ofproto_v1_0.NXFF_NXM 343 344 return ofproto_v1_0.NXFF_OPENFLOW10 345 346 def match_tuple(self): 347 """return a tuple which can be used as *args for 348 ofproto_v1_0_parser.OFPMatch.__init__(). 349 see Datapath.send_flow_mod. 350 """ 351 assert self.flow_format() == ofproto_v1_0.NXFF_OPENFLOW10 352 wildcards = ofproto_v1_0.OFPFW_ALL 353 354 if not self.wc.wildcards & FWW_IN_PORT: 355 wildcards &= ~ofproto_v1_0.OFPFW_IN_PORT 356 357 if self.flow.dl_src != mac.DONTCARE: 358 wildcards &= ~ofproto_v1_0.OFPFW_DL_SRC 359 360 if self.flow.dl_dst != mac.DONTCARE: 361 wildcards &= ~ofproto_v1_0.OFPFW_DL_DST 362 363 if not self.wc.wildcards & FWW_DL_TYPE: 364 wildcards &= ~ofproto_v1_0.OFPFW_DL_TYPE 365 366 if self.flow.dl_vlan != 0: 367 wildcards &= ~ofproto_v1_0.OFPFW_DL_VLAN 368 369 if self.flow.dl_vlan_pcp != 0: 370 wildcards &= ~ofproto_v1_0.OFPFW_DL_VLAN_PCP 371 372 if self.flow.nw_tos != 0: 373 wildcards &= ~ofproto_v1_0.OFPFW_NW_TOS 374 375 if self.flow.nw_proto != 0: 376 wildcards &= ~ofproto_v1_0.OFPFW_NW_PROTO 377 378 if self.wc.nw_src_mask != 0 and "01" not in bin(self.wc.nw_src_mask): 379 wildcards &= ~ofproto_v1_0.OFPFW_NW_SRC_MASK 380 maskbits = (bin(self.wc.nw_src_mask).count("0") - 1) 381 wildcards |= (maskbits << ofproto_v1_0.OFPFW_NW_SRC_SHIFT) 382 383 if self.wc.nw_dst_mask != 0 and "01" not in bin(self.wc.nw_dst_mask): 384 wildcards &= ~ofproto_v1_0.OFPFW_NW_DST_MASK 385 maskbits = (bin(self.wc.nw_dst_mask).count("0") - 1) 386 wildcards |= (maskbits << ofproto_v1_0.OFPFW_NW_DST_SHIFT) 387 388 if self.flow.tp_src != 0: 389 wildcards &= ~ofproto_v1_0.OFPFW_TP_SRC 390 391 if self.flow.tp_dst != 0: 392 wildcards &= ~ofproto_v1_0.OFPFW_TP_DST 393 394 return (wildcards, self.flow.in_port, self.flow.dl_src, 395 self.flow.dl_dst, self.flow.dl_vlan, self.flow.dl_vlan_pcp, 396 self.flow.dl_type, self.flow.nw_tos & IP_DSCP_MASK, 397 self.flow.nw_proto, self.flow.nw_src, self.flow.nw_dst, 398 self.flow.tp_src, self.flow.tp_dst) 399 400 401def _set_nxm_headers(nxm_headers): 402 '''Annotate corresponding NXM header''' 403 404 def _set_nxm_headers_dec(self): 405 self.nxm_headers = nxm_headers 406 return self 407 return _set_nxm_headers_dec 408 409 410def _register_make(cls): 411 '''class decorator to Register mf make''' 412 assert cls.nxm_headers is not None 413 assert cls.nxm_headers is not [] 414 for nxm_header in cls.nxm_headers: 415 assert nxm_header not in _MF_FIELDS 416 _MF_FIELDS[nxm_header] = cls.make 417 return cls 418 419 420def mf_from_nxm_header(nxm_header): 421 if nxm_header not in _MF_FIELDS: 422 return None 423 make = _MF_FIELDS.get(nxm_header) 424 assert make is not None 425 return make(nxm_header) 426 427 428class MFField(object): 429 _FIELDS_HEADERS = {} 430 431 @staticmethod 432 def register_field_header(headers): 433 def _register_field_header(cls): 434 for header in headers: 435 MFField._FIELDS_HEADERS[header] = cls 436 return cls 437 return _register_field_header 438 439 def __init__(self, nxm_header, pack_str): 440 self.nxm_header = nxm_header 441 self.pack_str = pack_str 442 self.n_bytes = struct.calcsize(pack_str) 443 self.n_bits = self.n_bytes * 8 444 445 @classmethod 446 def parser(cls, buf, offset): 447 (header,) = struct.unpack_from('!I', buf, offset) 448 449 cls_ = MFField._FIELDS_HEADERS.get(header) 450 451 if cls_: 452 field = cls_.field_parser(header, buf, offset) 453 else: 454 # print 'unknown field type' 455 raise 456 field.length = (header & 0xff) + 4 457 458 return field 459 460 @classmethod 461 def field_parser(cls, header, buf, offset): 462 hasmask = (header >> 8) & 1 463 mask = None 464 if hasmask: 465 pack_str = '!' + cls.pack_str[1:] * 2 466 (value, mask) = struct.unpack_from(pack_str, buf, 467 offset + 4) 468 else: 469 (value,) = struct.unpack_from(cls.pack_str, buf, 470 offset + 4) 471 return cls(header, value, mask) 472 473 def _put(self, buf, offset, value): 474 msg_pack_into(self.pack_str, buf, offset, value) 475 return self.n_bytes 476 477 def putw(self, buf, offset, value, mask): 478 len_ = self._put(buf, offset, value) 479 return len_ + self._put(buf, offset + len_, mask) 480 481 def _is_all_ones(self, value): 482 return value == (1 << self.n_bits) - 1 483 484 def putm(self, buf, offset, value, mask): 485 if mask == 0: 486 return 0 487 elif self._is_all_ones(mask): 488 return self._put(buf, offset, value) 489 else: 490 return self.putw(buf, offset, value, mask) 491 492 def _putv6(self, buf, offset, value): 493 msg_pack_into(self.pack_str, buf, offset, *value) 494 return self.n_bytes 495 496 def putv6(self, buf, offset, value, mask): 497 len_ = self._putv6(buf, offset, value) 498 if len(mask): 499 return len_ + self._putv6(buf, offset + len_, mask) 500 return len_ 501 502 503@_register_make 504@_set_nxm_headers([ofproto_v1_0.NXM_OF_IN_PORT]) 505@MFField.register_field_header([ofproto_v1_0.NXM_OF_IN_PORT]) 506class MFInPort(MFField): 507 pack_str = MF_PACK_STRING_BE16 508 509 def __init__(self, header, value, mask=None): 510 super(MFInPort, self).__init__(header, MFInPort.pack_str) 511 self.value = value 512 513 @classmethod 514 def make(cls, header): 515 return cls(header, MFInPort.pack_str) 516 517 def put(self, buf, offset, rule): 518 return self._put(buf, offset, rule.flow.in_port) 519 520 521@_register_make 522@_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_DST, ofproto_v1_0.NXM_OF_ETH_DST_W]) 523@MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_DST, 524 ofproto_v1_0.NXM_OF_ETH_DST_W]) 525class MFEthDst(MFField): 526 pack_str = MF_PACK_STRING_MAC 527 528 def __init__(self, header, value, mask=None): 529 super(MFEthDst, self).__init__(header, MFEthDst.pack_str) 530 self.value = value 531 532 @classmethod 533 def make(cls, header): 534 return cls(header, MFEthDst.pack_str) 535 536 def put(self, buf, offset, rule): 537 if rule.wc.dl_dst_mask: 538 return self.putw(buf, offset, rule.flow.dl_dst, 539 rule.wc.dl_dst_mask) 540 else: 541 return self._put(buf, offset, rule.flow.dl_dst) 542 543 544@_register_make 545@_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_SRC, ofproto_v1_0.NXM_OF_ETH_SRC_W]) 546@MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_SRC, 547 ofproto_v1_0.NXM_OF_ETH_SRC_W]) 548class MFEthSrc(MFField): 549 pack_str = MF_PACK_STRING_MAC 550 551 def __init__(self, header, value, mask=None): 552 super(MFEthSrc, self).__init__(header, MFEthSrc.pack_str) 553 self.value = value 554 555 @classmethod 556 def make(cls, header): 557 return cls(header, MFEthSrc.pack_str) 558 559 def put(self, buf, offset, rule): 560 if rule.wc.dl_src_mask: 561 return self.putw(buf, offset, rule.flow.dl_src, 562 rule.wc.dl_src_mask) 563 else: 564 return self._put(buf, offset, rule.flow.dl_src) 565 566 567@_register_make 568@_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_TYPE]) 569@MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_TYPE]) 570class MFEthType(MFField): 571 pack_str = MF_PACK_STRING_BE16 572 573 def __init__(self, header, value, mask=None): 574 super(MFEthType, self).__init__(header, MFEthType.pack_str) 575 self.value = value 576 577 @classmethod 578 def make(cls, header): 579 return cls(header, MFEthType.pack_str) 580 581 def put(self, buf, offset, rule): 582 return self._put(buf, offset, rule.flow.dl_type) 583 584 585@_register_make 586@_set_nxm_headers([ofproto_v1_0.NXM_OF_VLAN_TCI, 587 ofproto_v1_0.NXM_OF_VLAN_TCI_W]) 588@MFField.register_field_header([ofproto_v1_0.NXM_OF_VLAN_TCI, 589 ofproto_v1_0.NXM_OF_VLAN_TCI_W]) 590class MFVlan(MFField): 591 pack_str = MF_PACK_STRING_BE16 592 593 def __init__(self, header, value, mask=None): 594 super(MFVlan, self).__init__(header, MFVlan.pack_str) 595 self.value = value 596 597 @classmethod 598 def make(cls, header): 599 return cls(header, MFVlan.pack_str) 600 601 def put(self, buf, offset, rule): 602 return self.putm(buf, offset, rule.flow.vlan_tci, 603 rule.wc.vlan_tci_mask) 604 605 606@_register_make 607@_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_TOS]) 608@MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_TOS]) 609class MFIPDSCP(MFField): 610 pack_str = MF_PACK_STRING_8 611 612 def __init__(self, header, value, mask=None): 613 super(MFIPDSCP, self).__init__(header, MFIPDSCP.pack_str) 614 self.value = value 615 616 @classmethod 617 def make(cls, header): 618 return cls(header, MFIPDSCP.pack_str) 619 620 def put(self, buf, offset, rule): 621 return self._put(buf, offset, 622 rule.flow.nw_tos & IP_DSCP_MASK) 623 624 625@_register_make 626@_set_nxm_headers([ofproto_v1_0.NXM_NX_TUN_ID, 627 ofproto_v1_0.NXM_NX_TUN_ID_W]) 628@MFField.register_field_header([ofproto_v1_0.NXM_NX_TUN_ID, 629 ofproto_v1_0.NXM_NX_TUN_ID_W]) 630class MFTunId(MFField): 631 pack_str = MF_PACK_STRING_BE64 632 633 def __init__(self, header, value, mask=None): 634 super(MFTunId, self).__init__(header, MFTunId.pack_str) 635 self.value = value 636 637 @classmethod 638 def make(cls, header): 639 return cls(header, MFTunId.pack_str) 640 641 def put(self, buf, offset, rule): 642 return self.putm(buf, offset, rule.flow.tun_id, rule.wc.tun_id_mask) 643 644 645@_register_make 646@_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_SRC, ofproto_v1_0.NXM_OF_IP_SRC_W]) 647@MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_SRC, 648 ofproto_v1_0.NXM_OF_IP_SRC_W]) 649class MFIPSrc(MFField): 650 pack_str = MF_PACK_STRING_BE32 651 652 def __init__(self, header, value, mask=None): 653 super(MFIPSrc, self).__init__(header, MFIPSrc.pack_str) 654 self.value = value 655 self.mask = mask 656 657 @classmethod 658 def make(cls, header): 659 return cls(header, MFIPSrc.pack_str) 660 661 def put(self, buf, offset, rule): 662 return self.putm(buf, offset, rule.flow.nw_src, rule.wc.nw_src_mask) 663 664 665@_register_make 666@_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_DST, ofproto_v1_0.NXM_OF_IP_DST_W]) 667@MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_DST, 668 ofproto_v1_0.NXM_OF_IP_DST_W]) 669class MFIPDst(MFField): 670 pack_str = MF_PACK_STRING_BE32 671 672 def __init__(self, header, value, mask=None): 673 super(MFIPDst, self).__init__(header, MFIPDst.pack_str) 674 self.value = value 675 self.mask = mask 676 677 @classmethod 678 def make(cls, header): 679 return cls(header, MFIPDst.pack_str) 680 681 def put(self, buf, offset, rule): 682 return self.putm(buf, offset, rule.flow.nw_dst, rule.wc.nw_dst_mask) 683 684 685@_register_make 686@_set_nxm_headers([ofproto_v1_0.NXM_NX_IP_ECN]) 687class MFIPECN(MFField): 688 @classmethod 689 def make(cls, header): 690 return cls(header, MF_PACK_STRING_8) 691 692 def put(self, buf, offset, rule): 693 return self._put(buf, offset, 694 rule.flow.nw_tos & IP_ECN_MASK) 695 696 697@_register_make 698@_set_nxm_headers([ofproto_v1_0.NXM_NX_IP_TTL]) 699class MFIPTTL(MFField): 700 @classmethod 701 def make(cls, header): 702 return cls(header, MF_PACK_STRING_8) 703 704 def put(self, buf, offset, rule): 705 return self._put(buf, offset, rule.flow.nw_ttl) 706 707 708@_register_make 709@_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_PROTO]) 710class MFIPProto(MFField): 711 @classmethod 712 def make(cls, header): 713 return cls(header, MF_PACK_STRING_8) 714 715 def put(self, buf, offset, rule): 716 return self._put(buf, offset, rule.flow.nw_proto) 717 718 719@_register_make 720@_set_nxm_headers([ofproto_v1_0.NXM_OF_TCP_SRC, ofproto_v1_0.NXM_OF_TCP_SRC_W, 721 ofproto_v1_0.NXM_OF_UDP_SRC, ofproto_v1_0.NXM_OF_UDP_SRC_W]) 722class MFTPSRC(MFField): 723 @classmethod 724 def make(cls, header): 725 return cls(header, MF_PACK_STRING_BE16) 726 727 def put(self, buf, offset, rule): 728 return self.putm(buf, offset, rule.flow.tp_src, rule.wc.tp_src_mask) 729 730 731@_register_make 732@_set_nxm_headers([ofproto_v1_0.NXM_OF_TCP_DST, ofproto_v1_0.NXM_OF_TCP_DST_W, 733 ofproto_v1_0.NXM_OF_UDP_DST, ofproto_v1_0.NXM_OF_UDP_DST_W]) 734class MFTPDST(MFField): 735 @classmethod 736 def make(cls, header): 737 return cls(header, MF_PACK_STRING_BE16) 738 739 def put(self, buf, offset, rule): 740 return self.putm(buf, offset, rule.flow.tp_dst, rule.wc.tp_dst_mask) 741 742 743@_register_make 744@_set_nxm_headers([ofproto_v1_0.NXM_OF_ARP_SPA, ofproto_v1_0.NXM_OF_ARP_SPA_W]) 745class MFArpSpa(MFField): 746 @classmethod 747 def make(cls, header): 748 return cls(header, MF_PACK_STRING_BE32) 749 750 def put(self, buf, offset, rule): 751 return self.putm(buf, offset, rule.flow.arp_spa, rule.wc.arp_spa_mask) 752 753 754@_register_make 755@_set_nxm_headers([ofproto_v1_0.NXM_OF_ARP_TPA, ofproto_v1_0.NXM_OF_ARP_TPA_W]) 756class MFArpTpa(MFField): 757 @classmethod 758 def make(cls, header): 759 return cls(header, MF_PACK_STRING_BE32) 760 761 def put(self, buf, offset, rule): 762 return self.putm(buf, offset, rule.flow.arp_tpa, rule.wc.arp_tpa_mask) 763 764 765@_register_make 766@_set_nxm_headers([ofproto_v1_0.NXM_NX_ARP_SHA]) 767class MFArpSha(MFField): 768 @classmethod 769 def make(cls, header): 770 return cls(header, MF_PACK_STRING_MAC) 771 772 def put(self, buf, offset, rule): 773 return self._put(buf, offset, rule.flow.arp_sha) 774 775 776class MFIPV6(object): 777 pack_str = MF_PACK_STRING_IPV6 778 779 @classmethod 780 def field_parser(cls, header, buf, offset): 781 hasmask = (header >> 8) & 1 782 if hasmask: 783 pack_string = '!' + cls.pack_str[1:] * 2 784 value = struct.unpack_from(pack_string, buf, offset + 4) 785 return cls(header, list(value[:8]), list(value[8:])) 786 else: 787 value = struct.unpack_from(cls.pack_str, buf, offset + 4) 788 return cls(header, list(value)) 789 790 791@_register_make 792@_set_nxm_headers([ofproto_v1_0.NXM_NX_IPV6_SRC, 793 ofproto_v1_0.NXM_NX_IPV6_SRC_W]) 794@MFField.register_field_header([ofproto_v1_0.NXM_NX_IPV6_SRC, 795 ofproto_v1_0.NXM_NX_IPV6_SRC_W]) 796class MFIPV6Src(MFIPV6, MFField): 797 def __init__(self, header, value, mask=None): 798 super(MFIPV6Src, self).__init__(header, MFIPV6Src.pack_str) 799 self.value = value 800 self.mask = mask 801 802 @classmethod 803 def make(cls, header): 804 return cls(header, cls.pack_str) 805 806 def put(self, buf, offset, rule): 807 return self.putv6(buf, offset, 808 rule.flow.ipv6_src, 809 rule.wc.ipv6_src_mask) 810 811 812@_register_make 813@_set_nxm_headers([ofproto_v1_0.NXM_NX_IPV6_DST, 814 ofproto_v1_0.NXM_NX_IPV6_DST_W]) 815@MFField.register_field_header([ofproto_v1_0.NXM_NX_IPV6_DST, 816 ofproto_v1_0.NXM_NX_IPV6_DST_W]) 817class MFIPV6Dst(MFIPV6, MFField): 818 def __init__(self, header, value, mask=None): 819 super(MFIPV6Dst, self).__init__(header, MFIPV6Dst.pack_str) 820 self.value = value 821 self.mask = mask 822 823 @classmethod 824 def make(cls, header): 825 return cls(header, cls.pack_str) 826 827 def put(self, buf, offset, rule): 828 return self.putv6(buf, offset, 829 rule.flow.ipv6_dst, 830 rule.wc.ipv6_dst_mask) 831 832 833@_register_make 834@_set_nxm_headers([ofproto_v1_0.NXM_NX_ND_TARGET, 835 ofproto_v1_0.NXM_NX_ND_TARGET_W]) 836class MFNdTarget(MFField): 837 @classmethod 838 def make(cls, header): 839 return cls(header, '!4I') 840 841 def put(self, buf, offset, rule): 842 return self.putv6(buf, offset, 843 rule.flow.nd_target, 844 rule.wc.nd_target_mask) 845 846 847@_register_make 848@_set_nxm_headers([ofproto_v1_0.NXM_NX_IP_FRAG, 849 ofproto_v1_0.NXM_NX_IP_FRAG_W]) 850class MFIpFrag(MFField): 851 @classmethod 852 def make(cls, header): 853 return cls(header, '!B') 854 855 def put(self, buf, offset, rule): 856 if rule.wc.nw_frag_mask == FLOW_NW_FRAG_MASK: 857 return self._put(buf, offset, rule.flow.nw_frag) 858 else: 859 return self.putw(buf, offset, rule.flow.nw_frag, 860 rule.wc.nw_frag_mask & FLOW_NW_FRAG_MASK) 861 862 863@_register_make 864@_set_nxm_headers([ofproto_v1_0.NXM_NX_ARP_THA]) 865class MFArpTha(MFField): 866 @classmethod 867 def make(cls, header): 868 return cls(header, MF_PACK_STRING_MAC) 869 870 def put(self, buf, offset, rule): 871 return self._put(buf, offset, rule.flow.arp_tha) 872 873 874@_register_make 875@_set_nxm_headers([ofproto_v1_0.NXM_OF_ICMP_TYPE]) 876class MFICMPType(MFField): 877 @classmethod 878 def make(cls, header): 879 return cls(header, MF_PACK_STRING_8) 880 881 def put(self, buf, offset, rule): 882 return self._put(buf, offset, rule.flow.tp_src) 883 884 885@_register_make 886@_set_nxm_headers([ofproto_v1_0.NXM_OF_ICMP_CODE]) 887class MFICMPCode(MFField): 888 @classmethod 889 def make(cls, header): 890 return cls(header, MF_PACK_STRING_8) 891 892 def put(self, buf, offset, rule): 893 return self._put(buf, offset, rule.flow.tp_dst) 894 895 896@_register_make 897@_set_nxm_headers([ofproto_v1_0.NXM_NX_ICMPV6_TYPE]) 898class MFICMPV6Type(MFField): 899 @classmethod 900 def make(cls, header): 901 return cls(header, MF_PACK_STRING_8) 902 903 def put(self, buf, offset, rule): 904 return self._put(buf, offset, rule.flow.tp_src) 905 906 907@_register_make 908@_set_nxm_headers([ofproto_v1_0.NXM_NX_ICMPV6_CODE]) 909class MFICMPV6Code(MFField): 910 @classmethod 911 def make(cls, header): 912 return cls(header, MF_PACK_STRING_8) 913 914 def put(self, buf, offset, rule): 915 return self._put(buf, offset, rule.flow.tp_dst) 916 917 918@_register_make 919@_set_nxm_headers([ofproto_v1_0.NXM_NX_IPV6_LABEL]) 920class MFICMPV6Label(MFField): 921 @classmethod 922 def make(cls, header): 923 return cls(header, MF_PACK_STRING_BE32) 924 925 def put(self, buf, offset, rule): 926 return self._put(buf, offset, rule.flow.ipv6_label) 927 928 929@_register_make 930@_set_nxm_headers([ofproto_v1_0.nxm_nx_reg(i) for i in range(FLOW_N_REGS)] 931 + [ofproto_v1_0.nxm_nx_reg_w(i) for i in range(FLOW_N_REGS)]) 932class MFRegister(MFField): 933 @classmethod 934 def make(cls, header): 935 return cls(header, MF_PACK_STRING_BE32) 936 937 def put(self, buf, offset, rule): 938 for i in range(FLOW_N_REGS): 939 if (ofproto_v1_0.nxm_nx_reg(i) == self.nxm_header or 940 ofproto_v1_0.nxm_nx_reg_w(i) == self.nxm_header): 941 if rule.wc.regs_mask[i]: 942 return self.putm(buf, offset, rule.flow.regs[i], 943 rule.wc.regs_mask[i]) 944 else: 945 return self._put(buf, offset, rule.flow.regs[i]) 946 947 948@_register_make 949@_set_nxm_headers([ofproto_v1_0.NXM_NX_PKT_MARK, 950 ofproto_v1_0.NXM_NX_PKT_MARK_W]) 951class MFPktMark(MFField): 952 @classmethod 953 def make(cls, header): 954 return cls(header, MF_PACK_STRING_BE32) 955 956 def put(self, buf, offset, rule): 957 return self.putm(buf, offset, rule.flow.pkt_mark, 958 rule.wc.pkt_mark_mask) 959 960 961@_register_make 962@_set_nxm_headers([ofproto_v1_0.NXM_NX_TCP_FLAGS, 963 ofproto_v1_0.NXM_NX_TCP_FLAGS_W]) 964class MFTcpFlags(MFField): 965 @classmethod 966 def make(cls, header): 967 return cls(header, MF_PACK_STRING_BE16) 968 969 def put(self, buf, offset, rule): 970 return self.putm(buf, offset, rule.flow.tcp_flags, 971 rule.wc.tcp_flags_mask) 972 973 974def serialize_nxm_match(rule, buf, offset): 975 old_offset = offset 976 977 if not rule.wc.wildcards & FWW_IN_PORT: 978 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_IN_PORT, rule) 979 980 # Ethernet. 981 if rule.flow.dl_dst != mac.DONTCARE: 982 if rule.wc.dl_dst_mask: 983 header = ofproto_v1_0.NXM_OF_ETH_DST_W 984 else: 985 header = ofproto_v1_0.NXM_OF_ETH_DST 986 offset += nxm_put(buf, offset, header, rule) 987 988 if rule.flow.dl_src != mac.DONTCARE: 989 if rule.wc.dl_src_mask: 990 header = ofproto_v1_0.NXM_OF_ETH_SRC_W 991 else: 992 header = ofproto_v1_0.NXM_OF_ETH_SRC 993 offset += nxm_put(buf, offset, header, rule) 994 995 if not rule.wc.wildcards & FWW_DL_TYPE: 996 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_ETH_TYPE, rule) 997 998 # 802.1Q 999 if rule.wc.vlan_tci_mask != 0: 1000 if rule.wc.vlan_tci_mask == UINT16_MAX: 1001 header = ofproto_v1_0.NXM_OF_VLAN_TCI 1002 else: 1003 header = ofproto_v1_0.NXM_OF_VLAN_TCI_W 1004 offset += nxm_put(buf, offset, header, rule) 1005 1006 # L3 1007 if not rule.wc.wildcards & FWW_NW_DSCP: 1008 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_IP_TOS, rule) 1009 if not rule.wc.wildcards & FWW_NW_ECN: 1010 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_IP_ECN, rule) 1011 if not rule.wc.wildcards & FWW_NW_TTL: 1012 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_IP_TTL, rule) 1013 if not rule.wc.wildcards & FWW_NW_PROTO: 1014 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_IP_PROTO, rule) 1015 1016 if not rule.wc.wildcards & FWW_NW_PROTO and (rule.flow.nw_proto 1017 == inet.IPPROTO_ICMP): 1018 if rule.wc.tp_src_mask != 0: 1019 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_ICMP_TYPE, rule) 1020 if rule.wc.tp_dst_mask != 0: 1021 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_ICMP_CODE, rule) 1022 1023 if rule.flow.tp_src != 0: 1024 if rule.flow.nw_proto == 6: 1025 if rule.wc.tp_src_mask == UINT16_MAX: 1026 header = ofproto_v1_0.NXM_OF_TCP_SRC 1027 else: 1028 header = ofproto_v1_0.NXM_OF_TCP_SRC_W 1029 elif rule.flow.nw_proto == 17: 1030 if rule.wc.tp_src_mask == UINT16_MAX: 1031 header = ofproto_v1_0.NXM_OF_UDP_SRC 1032 else: 1033 header = ofproto_v1_0.NXM_OF_UDP_SRC_W 1034 else: 1035 header = 0 1036 if header != 0: 1037 offset += nxm_put(buf, offset, header, rule) 1038 1039 if rule.flow.tp_dst != 0: 1040 if rule.flow.nw_proto == 6: 1041 if rule.wc.tp_dst_mask == UINT16_MAX: 1042 header = ofproto_v1_0.NXM_OF_TCP_DST 1043 else: 1044 header = ofproto_v1_0.NXM_OF_TCP_DST_W 1045 elif rule.flow.nw_proto == 17: 1046 if rule.wc.tp_dst_mask == UINT16_MAX: 1047 header = ofproto_v1_0.NXM_OF_UDP_DST 1048 else: 1049 header = ofproto_v1_0.NXM_OF_UDP_DST_W 1050 else: 1051 header = 0 1052 if header != 0: 1053 offset += nxm_put(buf, offset, header, rule) 1054 1055 if rule.flow.tcp_flags != 0: 1056 # TCP Flags can only be used if the ethernet type is IPv4 or IPv6 1057 if rule.flow.dl_type in (ether.ETH_TYPE_IP, ether.ETH_TYPE_IPV6): 1058 # TCP Flags can only be used if the ip protocol is TCP 1059 if rule.flow.nw_proto == inet.IPPROTO_TCP: 1060 if rule.wc.tcp_flags_mask == UINT16_MAX: 1061 header = ofproto_v1_0.NXM_NX_TCP_FLAGS 1062 else: 1063 header = ofproto_v1_0.NXM_NX_TCP_FLAGS_W 1064 else: 1065 header = 0 1066 else: 1067 header = 0 1068 if header != 0: 1069 offset += nxm_put(buf, offset, header, rule) 1070 1071 # IP Source and Destination 1072 if rule.flow.nw_src != 0: 1073 if rule.wc.nw_src_mask == UINT32_MAX: 1074 header = ofproto_v1_0.NXM_OF_IP_SRC 1075 else: 1076 header = ofproto_v1_0.NXM_OF_IP_SRC_W 1077 offset += nxm_put(buf, offset, header, rule) 1078 1079 if rule.flow.nw_dst != 0: 1080 if rule.wc.nw_dst_mask == UINT32_MAX: 1081 header = ofproto_v1_0.NXM_OF_IP_DST 1082 else: 1083 header = ofproto_v1_0.NXM_OF_IP_DST_W 1084 offset += nxm_put(buf, offset, header, rule) 1085 1086 # IPv6 1087 if not rule.wc.wildcards & FWW_NW_PROTO and (rule.flow.nw_proto 1088 == inet.IPPROTO_ICMPV6): 1089 if rule.wc.tp_src_mask != 0: 1090 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_ICMPV6_TYPE, 1091 rule) 1092 if rule.wc.tp_dst_mask != 0: 1093 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_ICMPV6_CODE, 1094 rule) 1095 1096 if not rule.wc.wildcards & FWW_IPV6_LABEL: 1097 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_IPV6_LABEL, rule) 1098 1099 if len(rule.flow.ipv6_src): 1100 if len(rule.wc.ipv6_src_mask): 1101 header = ofproto_v1_0.NXM_NX_IPV6_SRC_W 1102 else: 1103 header = ofproto_v1_0.NXM_NX_IPV6_SRC 1104 offset += nxm_put(buf, offset, header, rule) 1105 1106 if len(rule.flow.ipv6_dst): 1107 if len(rule.wc.ipv6_dst_mask): 1108 header = ofproto_v1_0.NXM_NX_IPV6_DST_W 1109 else: 1110 header = ofproto_v1_0.NXM_NX_IPV6_DST 1111 offset += nxm_put(buf, offset, header, rule) 1112 1113 if len(rule.flow.nd_target): 1114 if len(rule.wc.nd_target_mask): 1115 header = ofproto_v1_0.NXM_NX_ND_TARGET_W 1116 else: 1117 header = ofproto_v1_0.NXM_NX_ND_TARGET 1118 offset += nxm_put(buf, offset, header, rule) 1119 1120 # ARP 1121 if rule.flow.arp_spa != 0: 1122 if rule.wc.arp_spa_mask == UINT32_MAX: 1123 header = ofproto_v1_0.NXM_OF_ARP_SPA 1124 else: 1125 header = ofproto_v1_0.NXM_OF_ARP_SPA_W 1126 offset += nxm_put(buf, offset, header, rule) 1127 1128 if rule.flow.arp_tpa != 0: 1129 if rule.wc.arp_tpa_mask == UINT32_MAX: 1130 header = ofproto_v1_0.NXM_OF_ARP_TPA 1131 else: 1132 header = ofproto_v1_0.NXM_OF_ARP_TPA_W 1133 offset += nxm_put(buf, offset, header, rule) 1134 1135 if not rule.wc.wildcards & FWW_ARP_SHA: 1136 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_ARP_SHA, rule) 1137 if not rule.wc.wildcards & FWW_ARP_THA: 1138 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_ARP_THA, rule) 1139 1140 if rule.flow.nw_frag: 1141 if rule.wc.nw_frag_mask == FLOW_NW_FRAG_MASK: 1142 header = ofproto_v1_0.NXM_NX_IP_FRAG 1143 else: 1144 header = ofproto_v1_0.NXM_NX_IP_FRAG_W 1145 offset += nxm_put(buf, offset, header, rule) 1146 1147 if rule.flow.pkt_mark != 0: 1148 if rule.wc.pkt_mark_mask == UINT32_MAX: 1149 header = ofproto_v1_0.NXM_NX_PKT_MARK 1150 else: 1151 header = ofproto_v1_0.NXM_NX_PKT_MARK_W 1152 offset += nxm_put(buf, offset, header, rule) 1153 1154 # Tunnel Id 1155 if rule.wc.tun_id_mask != 0: 1156 if rule.wc.tun_id_mask == UINT64_MAX: 1157 header = ofproto_v1_0.NXM_NX_TUN_ID 1158 else: 1159 header = ofproto_v1_0.NXM_NX_TUN_ID_W 1160 offset += nxm_put(buf, offset, header, rule) 1161 1162 # XXX: Cookie 1163 1164 for i in range(FLOW_N_REGS): 1165 if rule.wc.regs_bits & (1 << i): 1166 if rule.wc.regs_mask[i]: 1167 header = ofproto_v1_0.nxm_nx_reg_w(i) 1168 else: 1169 header = ofproto_v1_0.nxm_nx_reg(i) 1170 offset += nxm_put(buf, offset, header, rule) 1171 1172 # Pad 1173 pad_len = round_up(offset) - offset 1174 msg_pack_into("%dx" % pad_len, buf, offset) 1175 1176 # The returned length, the match_len, does not include the pad 1177 return offset - old_offset 1178 1179 1180def nxm_put(buf, offset, header, rule): 1181 nxm = NXMatch(header) 1182 len_ = nxm.put_header(buf, offset) 1183 mf = mf_from_nxm_header(nxm.header) 1184 return len_ + mf.put(buf, offset + len_, rule) 1185 1186 1187def round_up(length): 1188 return (length + 7) // 8 * 8 # Round up to a multiple of 8 1189 1190 1191class NXMatch(object): 1192 def __init__(self, header): 1193 self.header = header 1194 1195 @classmethod 1196 def parser(cls, buf, offset, match_len): 1197 if match_len < 4: 1198 raise exception.OFPMalformedMessage 1199 (header,) = struct.unpack_from(ofproto_v1_0.NXM_HEADER_PACK_STRING, 1200 buf, offset) 1201 instance = cls(header) 1202 payload_len = instance.length() 1203 if payload_len == 0 or match_len < payload_len + 4: 1204 raise exception.OFPMalformedMessage 1205 return instance 1206 1207 def vendor(self): 1208 return self.header >> 16 1209 1210 def field(self): 1211 return (self.header >> 9) % 0x7f 1212 1213 def type(self): 1214 return (self.header >> 9) % 0x7fffff 1215 1216 def hasmask(self): 1217 return (self.header >> 8) & 1 1218 1219 def length(self): 1220 return self.header & 0xff 1221 1222 def show(self): 1223 return ('%08x (vendor=%x, field=%x, hasmask=%x len=%x)' % 1224 (self.header, self.vendor(), self.field(), 1225 self.hasmask(), self.length())) 1226 1227 def put_header(self, buf, offset): 1228 msg_pack_into(ofproto_v1_0.NXM_HEADER_PACK_STRING, 1229 buf, offset, self.header) 1230 return struct.calcsize(ofproto_v1_0.NXM_HEADER_PACK_STRING) 1231