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>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
20 from ryu import exception
21 from ryu.lib import mac
22 from ryu.lib.pack_utils import msg_pack_into
23 from ryu.ofproto import ether
24 from ryu.ofproto import ofproto_parser
25 from ryu.ofproto import ofproto_v1_0
26 from ryu.ofproto import inet
30 LOG = logging.getLogger('ryu.ofproto.nx_match')
33 UINT64_MAX = (1 << 64) - 1
34 UINT32_MAX = (1 << 32) - 1
35 UINT16_MAX = (1 << 16) - 1
40 # No corresponding OFPFW_* bits
45 FWW_IPV6_LABEL = 1 << 7
47 FWW_ALL = (1 << 13) - 1
49 FLOW_NW_FRAG_ANY = 1 << 0
50 FLOW_NW_FRAG_LATER = 1 << 1
51 FLOW_NW_FRAG_MASK = FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER
56 MF_PACK_STRING_BE64 = '!Q'
57 MF_PACK_STRING_BE32 = '!I'
58 MF_PACK_STRING_BE16 = '!H'
59 MF_PACK_STRING_8 = '!B'
60 MF_PACK_STRING_MAC = '!6s'
61 MF_PACK_STRING_IPV6 = '!8H'
65 FLOW_N_REGS = 8 # ovs 1.5
68 class Flow(ofproto_parser.StringifyMixin):
73 self.dl_src = mac.DONTCARE
74 self.dl_dst = mac.DONTCARE
93 self.regs = [0] * FLOW_N_REGS
99 class FlowWildcards(ofproto_parser.StringifyMixin):
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
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
122 class ClsRule(ofproto_parser.StringifyMixin):
123 """describe a matching rule for OF 1.0 OFPMatch (and NX).
126 def __init__(self, **kwargs):
127 self.wc = FlowWildcards()
130 for key, value in kwargs.items():
132 register = int(key[3:] or -1)
133 self.set_reg(register, value)
136 setter = getattr(self, 'set_' + key, None)
138 LOG.error('Invalid kwarg specified to ClsRule (%s)', key)
141 if not isinstance(value, (tuple, list)):
146 def set_in_port(self, port):
147 self.wc.wildcards &= ~FWW_IN_PORT
148 self.flow.in_port = port
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
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
158 def set_dl_dst(self, dl_dst):
159 self.flow.dl_dst = dl_dst
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)
166 def set_dl_src(self, dl_src):
167 self.flow.dl_src = dl_src
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)
173 def set_dl_type(self, dl_type):
174 self.wc.wildcards &= ~FWW_DL_TYPE
175 self.flow.dl_type = dl_type
177 def set_dl_tci(self, tci):
178 self.set_dl_tci_masked(tci, UINT16_MAX)
180 def set_dl_tci_masked(self, tci, mask):
181 self.wc.vlan_tci_mask = mask
182 self.flow.vlan_tci = tci
184 def set_tp_src(self, tp_src):
185 self.set_tp_src_masked(tp_src, UINT16_MAX)
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
191 def set_tp_dst(self, tp_dst):
192 self.set_tp_dst_masked(tp_dst, UINT16_MAX)
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
198 def set_nw_proto(self, nw_proto):
199 self.wc.wildcards &= ~FWW_NW_PROTO
200 self.flow.nw_proto = nw_proto
202 def set_nw_src(self, nw_src):
203 self.set_nw_src_masked(nw_src, UINT32_MAX)
205 def set_nw_src_masked(self, nw_src, mask):
206 self.flow.nw_src = nw_src
207 self.wc.nw_src_mask = mask
209 def set_nw_dst(self, nw_dst):
210 self.set_nw_dst_masked(nw_dst, UINT32_MAX)
212 def set_nw_dst_masked(self, nw_dst, mask):
213 self.flow.nw_dst = nw_dst
214 self.wc.nw_dst_mask = mask
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
221 def set_icmp_type(self, icmp_type):
222 self.set_tp_src(icmp_type)
224 def set_icmp_code(self, icmp_code):
225 self.set_tp_dst(icmp_code)
227 def set_tun_id(self, tun_id):
228 self.set_tun_id_masked(tun_id, UINT64_MAX)
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
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
239 def set_nw_ttl(self, nw_ttl):
240 self.wc.wildcards &= ~FWW_NW_TTL
241 self.flow.nw_ttl = nw_ttl
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
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
251 def set_arp_spa(self, spa):
252 self.set_arp_spa_masked(spa, UINT32_MAX)
254 def set_arp_spa_masked(self, spa, mask):
255 self.flow.arp_spa = spa
256 self.wc.arp_spa_mask = mask
258 def set_arp_tpa(self, tpa):
259 self.set_arp_tpa_masked(tpa, UINT32_MAX)
261 def set_arp_tpa_masked(self, tpa, mask):
262 self.flow.arp_tpa = tpa
263 self.wc.arp_tpa_mask = mask
265 def set_arp_sha(self, sha):
266 self.wc.wildcards &= ~FWW_ARP_SHA
267 self.flow.arp_sha = sha
269 def set_arp_tha(self, tha):
270 self.wc.wildcards &= ~FWW_ARP_THA
271 self.flow.arp_tha = tha
273 def set_icmpv6_type(self, icmp_type):
274 self.set_tp_src(icmp_type)
276 def set_icmpv6_code(self, icmp_code):
277 self.set_tp_dst(icmp_code)
279 def set_ipv6_label(self, label):
280 self.wc.wildcards &= ~FWW_IPV6_LABEL
281 self.flow.ipv6_label = label
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)]
287 def set_ipv6_src(self, src):
288 self.flow.ipv6_src = src
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)]
294 def set_ipv6_dst(self, dst):
295 self.flow.ipv6_dst = dst
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
302 def set_nd_target(self, target):
303 self.flow.nd_target = target
305 def set_reg(self, reg_idx, value):
306 self.set_reg_masked(reg_idx, value, 0)
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)
313 def set_pkt_mark_masked(self, pkt_mark, mask):
314 self.flow.pkt_mark = pkt_mark
315 self.wc.pkt_mark_mask = mask
317 def set_tcp_flags(self, tcp_flags, mask):
318 self.flow.tcp_flags = tcp_flags
319 self.wc.tcp_flags_mask = mask
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
326 # Masking DL_DST is only supported by NXM
327 if self.wc.dl_dst_mask:
328 return ofproto_v1_0.NXFF_NXM
330 # Masking DL_SRC is only supported by NXM
331 if self.wc.dl_src_mask:
332 return ofproto_v1_0.NXFF_NXM
334 # ECN is only supported by NXM
335 if not self.wc.wildcards & FWW_NW_ECN:
336 return ofproto_v1_0.NXFF_NXM
338 if self.wc.regs_bits > 0:
339 return ofproto_v1_0.NXFF_NXM
341 if self.flow.tcp_flags > 0:
342 return ofproto_v1_0.NXFF_NXM
344 return ofproto_v1_0.NXFF_OPENFLOW10
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.
351 assert self.flow_format() == ofproto_v1_0.NXFF_OPENFLOW10
352 wildcards = ofproto_v1_0.OFPFW_ALL
354 if not self.wc.wildcards & FWW_IN_PORT:
355 wildcards &= ~ofproto_v1_0.OFPFW_IN_PORT
357 if self.flow.dl_src != mac.DONTCARE:
358 wildcards &= ~ofproto_v1_0.OFPFW_DL_SRC
360 if self.flow.dl_dst != mac.DONTCARE:
361 wildcards &= ~ofproto_v1_0.OFPFW_DL_DST
363 if not self.wc.wildcards & FWW_DL_TYPE:
364 wildcards &= ~ofproto_v1_0.OFPFW_DL_TYPE
366 if self.flow.dl_vlan != 0:
367 wildcards &= ~ofproto_v1_0.OFPFW_DL_VLAN
369 if self.flow.dl_vlan_pcp != 0:
370 wildcards &= ~ofproto_v1_0.OFPFW_DL_VLAN_PCP
372 if self.flow.nw_tos != 0:
373 wildcards &= ~ofproto_v1_0.OFPFW_NW_TOS
375 if self.flow.nw_proto != 0:
376 wildcards &= ~ofproto_v1_0.OFPFW_NW_PROTO
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)
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)
388 if self.flow.tp_src != 0:
389 wildcards &= ~ofproto_v1_0.OFPFW_TP_SRC
391 if self.flow.tp_dst != 0:
392 wildcards &= ~ofproto_v1_0.OFPFW_TP_DST
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)
401 def _set_nxm_headers(nxm_headers):
402 '''Annotate corresponding NXM header'''
404 def _set_nxm_headers_dec(self):
405 self.nxm_headers = nxm_headers
407 return _set_nxm_headers_dec
410 def _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
420 def mf_from_nxm_header(nxm_header):
421 if nxm_header not in _MF_FIELDS:
423 make = _MF_FIELDS.get(nxm_header)
424 assert make is not None
425 return make(nxm_header)
428 class MFField(object):
432 def register_field_header(headers):
433 def _register_field_header(cls):
434 for header in headers:
435 MFField._FIELDS_HEADERS[header] = cls
437 return _register_field_header
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
446 def parser(cls, buf, offset):
447 (header,) = struct.unpack_from('!I', buf, offset)
449 cls_ = MFField._FIELDS_HEADERS.get(header)
452 field = cls_.field_parser(header, buf, offset)
454 # print 'unknown field type'
456 field.length = (header & 0xff) + 4
461 def field_parser(cls, header, buf, offset):
462 hasmask = (header >> 8) & 1
465 pack_str = '!' + cls.pack_str[1:] * 2
466 (value, mask) = struct.unpack_from(pack_str, buf,
469 (value,) = struct.unpack_from(cls.pack_str, buf,
471 return cls(header, value, mask)
473 def _put(self, buf, offset, value):
474 msg_pack_into(self.pack_str, buf, offset, value)
477 def putw(self, buf, offset, value, mask):
478 len_ = self._put(buf, offset, value)
479 return len_ + self._put(buf, offset + len_, mask)
481 def _is_all_ones(self, value):
482 return value == (1 << self.n_bits) - 1
484 def putm(self, buf, offset, value, mask):
487 elif self._is_all_ones(mask):
488 return self._put(buf, offset, value)
490 return self.putw(buf, offset, value, mask)
492 def _putv6(self, buf, offset, value):
493 msg_pack_into(self.pack_str, buf, offset, *value)
496 def putv6(self, buf, offset, value, mask):
497 len_ = self._putv6(buf, offset, value)
499 return len_ + self._putv6(buf, offset + len_, mask)
504 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IN_PORT])
505 @MFField.register_field_header([ofproto_v1_0.NXM_OF_IN_PORT])
506 class MFInPort(MFField):
507 pack_str = MF_PACK_STRING_BE16
509 def __init__(self, header, value, mask=None):
510 super(MFInPort, self).__init__(header, MFInPort.pack_str)
514 def make(cls, header):
515 return cls(header, MFInPort.pack_str)
517 def put(self, buf, offset, rule):
518 return self._put(buf, offset, rule.flow.in_port)
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])
525 class MFEthDst(MFField):
526 pack_str = MF_PACK_STRING_MAC
528 def __init__(self, header, value, mask=None):
529 super(MFEthDst, self).__init__(header, MFEthDst.pack_str)
533 def make(cls, header):
534 return cls(header, MFEthDst.pack_str)
536 def put(self, buf, offset, rule):
537 if rule.wc.dl_dst_mask:
538 return self.putw(buf, offset, rule.flow.dl_dst,
541 return self._put(buf, offset, rule.flow.dl_dst)
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])
548 class MFEthSrc(MFField):
549 pack_str = MF_PACK_STRING_MAC
551 def __init__(self, header, value, mask=None):
552 super(MFEthSrc, self).__init__(header, MFEthSrc.pack_str)
556 def make(cls, header):
557 return cls(header, MFEthSrc.pack_str)
559 def put(self, buf, offset, rule):
560 if rule.wc.dl_src_mask:
561 return self.putw(buf, offset, rule.flow.dl_src,
564 return self._put(buf, offset, rule.flow.dl_src)
568 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ETH_TYPE])
569 @MFField.register_field_header([ofproto_v1_0.NXM_OF_ETH_TYPE])
570 class MFEthType(MFField):
571 pack_str = MF_PACK_STRING_BE16
573 def __init__(self, header, value, mask=None):
574 super(MFEthType, self).__init__(header, MFEthType.pack_str)
578 def make(cls, header):
579 return cls(header, MFEthType.pack_str)
581 def put(self, buf, offset, rule):
582 return self._put(buf, offset, rule.flow.dl_type)
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])
590 class MFVlan(MFField):
591 pack_str = MF_PACK_STRING_BE16
593 def __init__(self, header, value, mask=None):
594 super(MFVlan, self).__init__(header, MFVlan.pack_str)
598 def make(cls, header):
599 return cls(header, MFVlan.pack_str)
601 def put(self, buf, offset, rule):
602 return self.putm(buf, offset, rule.flow.vlan_tci,
603 rule.wc.vlan_tci_mask)
607 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_TOS])
608 @MFField.register_field_header([ofproto_v1_0.NXM_OF_IP_TOS])
609 class MFIPDSCP(MFField):
610 pack_str = MF_PACK_STRING_8
612 def __init__(self, header, value, mask=None):
613 super(MFIPDSCP, self).__init__(header, MFIPDSCP.pack_str)
617 def make(cls, header):
618 return cls(header, MFIPDSCP.pack_str)
620 def put(self, buf, offset, rule):
621 return self._put(buf, offset,
622 rule.flow.nw_tos & IP_DSCP_MASK)
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])
630 class MFTunId(MFField):
631 pack_str = MF_PACK_STRING_BE64
633 def __init__(self, header, value, mask=None):
634 super(MFTunId, self).__init__(header, MFTunId.pack_str)
638 def make(cls, header):
639 return cls(header, MFTunId.pack_str)
641 def put(self, buf, offset, rule):
642 return self.putm(buf, offset, rule.flow.tun_id, rule.wc.tun_id_mask)
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])
649 class MFIPSrc(MFField):
650 pack_str = MF_PACK_STRING_BE32
652 def __init__(self, header, value, mask=None):
653 super(MFIPSrc, self).__init__(header, MFIPSrc.pack_str)
658 def make(cls, header):
659 return cls(header, MFIPSrc.pack_str)
661 def put(self, buf, offset, rule):
662 return self.putm(buf, offset, rule.flow.nw_src, rule.wc.nw_src_mask)
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])
669 class MFIPDst(MFField):
670 pack_str = MF_PACK_STRING_BE32
672 def __init__(self, header, value, mask=None):
673 super(MFIPDst, self).__init__(header, MFIPDst.pack_str)
678 def make(cls, header):
679 return cls(header, MFIPDst.pack_str)
681 def put(self, buf, offset, rule):
682 return self.putm(buf, offset, rule.flow.nw_dst, rule.wc.nw_dst_mask)
686 @_set_nxm_headers([ofproto_v1_0.NXM_NX_IP_ECN])
687 class MFIPECN(MFField):
689 def make(cls, header):
690 return cls(header, MF_PACK_STRING_8)
692 def put(self, buf, offset, rule):
693 return self._put(buf, offset,
694 rule.flow.nw_tos & IP_ECN_MASK)
698 @_set_nxm_headers([ofproto_v1_0.NXM_NX_IP_TTL])
699 class MFIPTTL(MFField):
701 def make(cls, header):
702 return cls(header, MF_PACK_STRING_8)
704 def put(self, buf, offset, rule):
705 return self._put(buf, offset, rule.flow.nw_ttl)
709 @_set_nxm_headers([ofproto_v1_0.NXM_OF_IP_PROTO])
710 class MFIPProto(MFField):
712 def make(cls, header):
713 return cls(header, MF_PACK_STRING_8)
715 def put(self, buf, offset, rule):
716 return self._put(buf, offset, rule.flow.nw_proto)
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])
722 class MFTPSRC(MFField):
724 def make(cls, header):
725 return cls(header, MF_PACK_STRING_BE16)
727 def put(self, buf, offset, rule):
728 return self.putm(buf, offset, rule.flow.tp_src, rule.wc.tp_src_mask)
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])
734 class MFTPDST(MFField):
736 def make(cls, header):
737 return cls(header, MF_PACK_STRING_BE16)
739 def put(self, buf, offset, rule):
740 return self.putm(buf, offset, rule.flow.tp_dst, rule.wc.tp_dst_mask)
744 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ARP_SPA, ofproto_v1_0.NXM_OF_ARP_SPA_W])
745 class MFArpSpa(MFField):
747 def make(cls, header):
748 return cls(header, MF_PACK_STRING_BE32)
750 def put(self, buf, offset, rule):
751 return self.putm(buf, offset, rule.flow.arp_spa, rule.wc.arp_spa_mask)
755 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ARP_TPA, ofproto_v1_0.NXM_OF_ARP_TPA_W])
756 class MFArpTpa(MFField):
758 def make(cls, header):
759 return cls(header, MF_PACK_STRING_BE32)
761 def put(self, buf, offset, rule):
762 return self.putm(buf, offset, rule.flow.arp_tpa, rule.wc.arp_tpa_mask)
766 @_set_nxm_headers([ofproto_v1_0.NXM_NX_ARP_SHA])
767 class MFArpSha(MFField):
769 def make(cls, header):
770 return cls(header, MF_PACK_STRING_MAC)
772 def put(self, buf, offset, rule):
773 return self._put(buf, offset, rule.flow.arp_sha)
776 class MFIPV6(object):
777 pack_str = MF_PACK_STRING_IPV6
780 def field_parser(cls, header, buf, offset):
781 hasmask = (header >> 8) & 1
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:]))
787 value = struct.unpack_from(cls.pack_str, buf, offset + 4)
788 return cls(header, list(value))
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])
796 class MFIPV6Src(MFIPV6, MFField):
797 def __init__(self, header, value, mask=None):
798 super(MFIPV6Src, self).__init__(header, MFIPV6Src.pack_str)
803 def make(cls, header):
804 return cls(header, cls.pack_str)
806 def put(self, buf, offset, rule):
807 return self.putv6(buf, offset,
809 rule.wc.ipv6_src_mask)
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])
817 class MFIPV6Dst(MFIPV6, MFField):
818 def __init__(self, header, value, mask=None):
819 super(MFIPV6Dst, self).__init__(header, MFIPV6Dst.pack_str)
824 def make(cls, header):
825 return cls(header, cls.pack_str)
827 def put(self, buf, offset, rule):
828 return self.putv6(buf, offset,
830 rule.wc.ipv6_dst_mask)
834 @_set_nxm_headers([ofproto_v1_0.NXM_NX_ND_TARGET,
835 ofproto_v1_0.NXM_NX_ND_TARGET_W])
836 class MFNdTarget(MFField):
838 def make(cls, header):
839 return cls(header, '!4I')
841 def put(self, buf, offset, rule):
842 return self.putv6(buf, offset,
844 rule.wc.nd_target_mask)
848 @_set_nxm_headers([ofproto_v1_0.NXM_NX_IP_FRAG,
849 ofproto_v1_0.NXM_NX_IP_FRAG_W])
850 class MFIpFrag(MFField):
852 def make(cls, header):
853 return cls(header, '!B')
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)
859 return self.putw(buf, offset, rule.flow.nw_frag,
860 rule.wc.nw_frag_mask & FLOW_NW_FRAG_MASK)
864 @_set_nxm_headers([ofproto_v1_0.NXM_NX_ARP_THA])
865 class MFArpTha(MFField):
867 def make(cls, header):
868 return cls(header, MF_PACK_STRING_MAC)
870 def put(self, buf, offset, rule):
871 return self._put(buf, offset, rule.flow.arp_tha)
875 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ICMP_TYPE])
876 class MFICMPType(MFField):
878 def make(cls, header):
879 return cls(header, MF_PACK_STRING_8)
881 def put(self, buf, offset, rule):
882 return self._put(buf, offset, rule.flow.tp_src)
886 @_set_nxm_headers([ofproto_v1_0.NXM_OF_ICMP_CODE])
887 class MFICMPCode(MFField):
889 def make(cls, header):
890 return cls(header, MF_PACK_STRING_8)
892 def put(self, buf, offset, rule):
893 return self._put(buf, offset, rule.flow.tp_dst)
897 @_set_nxm_headers([ofproto_v1_0.NXM_NX_ICMPV6_TYPE])
898 class MFICMPV6Type(MFField):
900 def make(cls, header):
901 return cls(header, MF_PACK_STRING_8)
903 def put(self, buf, offset, rule):
904 return self._put(buf, offset, rule.flow.tp_src)
908 @_set_nxm_headers([ofproto_v1_0.NXM_NX_ICMPV6_CODE])
909 class MFICMPV6Code(MFField):
911 def make(cls, header):
912 return cls(header, MF_PACK_STRING_8)
914 def put(self, buf, offset, rule):
915 return self._put(buf, offset, rule.flow.tp_dst)
919 @_set_nxm_headers([ofproto_v1_0.NXM_NX_IPV6_LABEL])
920 class MFICMPV6Label(MFField):
922 def make(cls, header):
923 return cls(header, MF_PACK_STRING_BE32)
925 def put(self, buf, offset, rule):
926 return self._put(buf, offset, rule.flow.ipv6_label)
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)])
932 class MFRegister(MFField):
934 def make(cls, header):
935 return cls(header, MF_PACK_STRING_BE32)
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])
945 return self._put(buf, offset, rule.flow.regs[i])
949 @_set_nxm_headers([ofproto_v1_0.NXM_NX_PKT_MARK,
950 ofproto_v1_0.NXM_NX_PKT_MARK_W])
951 class MFPktMark(MFField):
953 def make(cls, header):
954 return cls(header, MF_PACK_STRING_BE32)
956 def put(self, buf, offset, rule):
957 return self.putm(buf, offset, rule.flow.pkt_mark,
958 rule.wc.pkt_mark_mask)
962 @_set_nxm_headers([ofproto_v1_0.NXM_NX_TCP_FLAGS,
963 ofproto_v1_0.NXM_NX_TCP_FLAGS_W])
964 class MFTcpFlags(MFField):
966 def make(cls, header):
967 return cls(header, MF_PACK_STRING_BE16)
969 def put(self, buf, offset, rule):
970 return self.putm(buf, offset, rule.flow.tcp_flags,
971 rule.wc.tcp_flags_mask)
974 def serialize_nxm_match(rule, buf, offset):
977 if not rule.wc.wildcards & FWW_IN_PORT:
978 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_IN_PORT, rule)
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
985 header = ofproto_v1_0.NXM_OF_ETH_DST
986 offset += nxm_put(buf, offset, header, rule)
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
992 header = ofproto_v1_0.NXM_OF_ETH_SRC
993 offset += nxm_put(buf, offset, header, rule)
995 if not rule.wc.wildcards & FWW_DL_TYPE:
996 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_OF_ETH_TYPE, rule)
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
1003 header = ofproto_v1_0.NXM_OF_VLAN_TCI_W
1004 offset += nxm_put(buf, offset, header, rule)
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)
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)
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
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
1033 header = ofproto_v1_0.NXM_OF_UDP_SRC_W
1037 offset += nxm_put(buf, offset, header, rule)
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
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
1049 header = ofproto_v1_0.NXM_OF_UDP_DST_W
1053 offset += nxm_put(buf, offset, header, rule)
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
1063 header = ofproto_v1_0.NXM_NX_TCP_FLAGS_W
1069 offset += nxm_put(buf, offset, header, rule)
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
1076 header = ofproto_v1_0.NXM_OF_IP_SRC_W
1077 offset += nxm_put(buf, offset, header, rule)
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
1083 header = ofproto_v1_0.NXM_OF_IP_DST_W
1084 offset += nxm_put(buf, offset, header, rule)
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,
1092 if rule.wc.tp_dst_mask != 0:
1093 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_ICMPV6_CODE,
1096 if not rule.wc.wildcards & FWW_IPV6_LABEL:
1097 offset += nxm_put(buf, offset, ofproto_v1_0.NXM_NX_IPV6_LABEL, rule)
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
1103 header = ofproto_v1_0.NXM_NX_IPV6_SRC
1104 offset += nxm_put(buf, offset, header, rule)
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
1110 header = ofproto_v1_0.NXM_NX_IPV6_DST
1111 offset += nxm_put(buf, offset, header, rule)
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
1117 header = ofproto_v1_0.NXM_NX_ND_TARGET
1118 offset += nxm_put(buf, offset, header, rule)
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
1125 header = ofproto_v1_0.NXM_OF_ARP_SPA_W
1126 offset += nxm_put(buf, offset, header, rule)
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
1132 header = ofproto_v1_0.NXM_OF_ARP_TPA_W
1133 offset += nxm_put(buf, offset, header, rule)
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)
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
1144 header = ofproto_v1_0.NXM_NX_IP_FRAG_W
1145 offset += nxm_put(buf, offset, header, rule)
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
1151 header = ofproto_v1_0.NXM_NX_PKT_MARK_W
1152 offset += nxm_put(buf, offset, header, rule)
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
1159 header = ofproto_v1_0.NXM_NX_TUN_ID_W
1160 offset += nxm_put(buf, offset, header, rule)
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)
1169 header = ofproto_v1_0.nxm_nx_reg(i)
1170 offset += nxm_put(buf, offset, header, rule)
1173 pad_len = round_up(offset) - offset
1174 msg_pack_into("%dx" % pad_len, buf, offset)
1176 # The returned length, the match_len, does not include the pad
1177 return offset - old_offset
1180 def 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)
1187 def round_up(length):
1188 return (length + 7) // 8 * 8 # Round up to a multiple of 8
1191 class NXMatch(object):
1192 def __init__(self, header):
1193 self.header = header
1196 def parser(cls, buf, offset, match_len):
1198 raise exception.OFPMalformedMessage
1199 (header,) = struct.unpack_from(ofproto_v1_0.NXM_HEADER_PACK_STRING,
1201 instance = cls(header)
1202 payload_len = instance.length()
1203 if payload_len == 0 or match_len < payload_len + 4:
1204 raise exception.OFPMalformedMessage
1208 return self.header >> 16
1211 return (self.header >> 9) % 0x7f
1214 return (self.header >> 9) % 0x7fffff
1217 return (self.header >> 8) & 1
1220 return self.header & 0xff
1223 return ('%08x (vendor=%x, field=%x, hasmask=%x len=%x)' %
1224 (self.header, self.vendor(), self.field(),
1225 self.hasmask(), self.length()))
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)