pyof.v0x01.common.flow_match.Match.__setattr__()   B
last analyzed

Complexity

Conditions 7

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 7

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 18
ccs 12
cts 12
cp 1
rs 8
c 0
b 0
f 0
cc 7
nop 3
crap 7
1
"""Defines flow statistics structures and related items."""
2
3
# System imports
4
5
# Third-party imports
6
7
# Local source tree imports
8 1
from pyof.foundation.base import GenericBitMask, GenericStruct
9 1
from pyof.foundation.basic_types import (
10
    HWAddress, IPAddress, Pad, UBInt8, UBInt16, UBInt32)
11
12 1
__all__ = ('Match', 'FlowWildCards')
13
14
15 1
class FlowWildCards(GenericBitMask):
16
    """Wildcards used to identify flows.
17
18
    ``OFPFW_NW_SRC_*``: IP source address wildcard bit count. 0 is exact match,
19
    1 ignores the LSB, 2 ignores the 2 least-significant bits, ..., 32 and
20
    higher wildcard the entire field.  This is the *opposite* of the usual
21
    convention where e.g. /24 indicates that 8 bits (not 24 bits) are
22
    wildcarded.
23
24
    ``OFPFW_NW_DST_*``: IP destination address wildcard bit count. Same format
25
    as source.
26
    """
27
28
    #: Switch input port.
29 1
    OFPFW_IN_PORT = 1 << 0
30
    #: VLAN id.
31 1
    OFPFW_DL_VLAN = 1 << 1
32
    #: Ethernet source address.
33 1
    OFPFW_DL_SRC = 1 << 2
34
    #: Ethernet destination address.
35 1
    OFPFW_DL_DST = 1 << 3
36
    #: Ethernet frame type.
37 1
    OFPFW_DL_TYPE = 1 << 4
38
    #: IP protocol.
39 1
    OFPFW_NW_PROTO = 1 << 5
40
    #: TCP/UDP source port.
41 1
    OFPFW_TP_SRC = 1 << 6
42
    #: TCP/UDP destination port.
43 1
    OFPFW_TP_DST = 1 << 7
44
45
    # See class docstring
46 1
    OFPFW_NW_SRC_SHIFT = 8
47 1
    OFPFW_NW_SRC_BITS = 6
48 1
    OFPFW_NW_SRC_MASK = ((1 << OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT
49 1
    OFPFW_NW_SRC_ALL = 32 << OFPFW_NW_SRC_SHIFT
50
51
    # See class docstring
52 1
    OFPFW_NW_DST_SHIFT = 14
53 1
    OFPFW_NW_DST_BITS = 6
54 1
    OFPFW_NW_DST_MASK = ((1 << OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT
55 1
    OFPFW_NW_DST_ALL = 32 << OFPFW_NW_DST_SHIFT
56 1
    OFPFW_DL_VLAN_PCP = 1 << 20
57 1
    OFPFW_NW_TOS = 1 << 21
58
59
    #: Wildcard all fields.
60 1
    OFPFW_ALL = ((1 << 22) - 1)
61
62
63
# Classes
64
65
66 1
class Match(GenericStruct):
67
    """Describes a flow entry. Fields to match against flows."""
68
69
    #: Wildcards fields.
70 1
    wildcards = UBInt32(value=FlowWildCards.OFPFW_ALL, enum_ref=FlowWildCards)
71
    #: Input switch port.
72 1
    in_port = UBInt16(0)
73
    #: Ethernet source address. (default: '00:00:00:00:00:00')
74 1
    dl_src = HWAddress()
75
    #: Ethernet destination address. (default: '00:00:00:00:00:00')
76 1
    dl_dst = HWAddress()
77
    #: Input VLAN id. (default: 0)
78 1
    dl_vlan = UBInt16(0)
79
    #: Input VLAN priority. (default: 0)
80 1
    dl_vlan_pcp = UBInt8(0)
81
    #: Align to 64-bits.
82 1
    pad1 = Pad(1)
83
    #: Ethernet frame type. (default: 0)
84 1
    dl_type = UBInt16(0)
85
    #: IP ToS (actually DSCP field, 6 bits). (default: 0)
86 1
    nw_tos = UBInt8(0)
87
    #: IP protocol or lower 8 bits of ARP opcode. (default: 0)
88 1
    nw_proto = UBInt8(0)
89
    #: Align to 64-bits.
90 1
    pad2 = Pad(2)
91
    #: IP source address. (default: '0.0.0.0/0')
92 1
    nw_src = IPAddress('0.0.0.0/0')
93
    #: IP destination address. (default: '0.0.0.0/0')
94 1
    nw_dst = IPAddress('0.0.0.0/0')
95
    #: TCP/UDP source port. (default: 0)
96 1
    tp_src = UBInt16(0)
97
    #: TCP/UDP destination port. (default: 0)
98 1
    tp_dst = UBInt16(0)
99
100 1
    def __init__(self, **kwargs):
101
        """All the constructor parameters below are optional.
102
103
        Args:
104
            wildcards (FlowWildCards): Wildcards fields. (Default: OFPFW_ALL)
105
            in_port (int): Input switch port. (default: 0)
106
            dl_src (HWAddress): Ethernet source address.
107
                (default: '00:00:00:00:00:00')
108
            dl_dst (HWAddress): Ethernet destination address.
109
                (default: '00:00:00:00:00:00')
110
            dl_vlan (int): Input VLAN id. (default: 0)
111
            dl_vlan_pcp (int): Input VLAN priority. (default: 0)
112
            dl_type (int): Ethernet frame type. (default: 0)
113
            nw_tos (int): IP ToS (actually DSCP field, 6 bits). (default: 0)
114
            nw_proto (int): IP protocol or lower 8 bits of ARP opcode.
115
                (default: 0)
116
            nw_src (IPAddress): IP source address. (default: '0.0.0.0/0')
117
            nw_dst (IPAddress): IP destination address. (default: '0.0.0.0/0')
118
            tp_src (int): TCP/UDP source port. (default: 0)
119
            tp_dst (int): TCP/UDP destination port. (default: 0)
120
        """
121 1
        super().__init__()
122 1
        for field, value in kwargs.items():
123 1
            setattr(self, field, value)
124
125 1
    def __setattr__(self, name, value):
126
127
        # converts string ip_address to IPAddress
128 1
        if isinstance(getattr(Match, name), IPAddress) and \
129
                not isinstance(value, IPAddress):
130 1
            if isinstance(value, list):
131 1
                value = ".".join(str(x) for x in value)
132 1
            value = IPAddress(value)  # noqa
133
        # convertstring or list of hwaddress to HWAddress
134 1
        elif isinstance(getattr(Match, name), HWAddress) and \
135
                not isinstance(value, HWAddress):
136 1
            if isinstance(value, list):
137 1
                values = ["{0:0{1}x}".format(x, 2) for x in value]
138 1
                value = ":".join(values)
139 1
            value = HWAddress(value)
140
141 1
        super().__setattr__(name, value)
142 1
        self.fill_wildcards(name, value)
143
144 1
    def unpack(self, buff, offset=0):
145
        """Unpack *buff* into this object.
146
147
        Do nothing, since the _length is already defined and it is just a Pad.
148
        Keep buff and offset just for compability with other unpack methods.
149
150
        Args:
151
            buff (bytes): Binary buffer.
152
            offset (int): Where to begin unpacking.
153
154
        Raises:
155
            :exc:`~.exceptions.UnpackException`: If unpack fails.
156
157
        """
158 1
        super().unpack(buff, offset)
159 1
        self.wildcards = UBInt32(value=FlowWildCards.OFPFW_ALL,
160
                                 enum_ref=FlowWildCards)
161 1
        self.wildcards.unpack(buff, offset)
162
163 1
    def fill_wildcards(self, field=None, value=0):
164
        """Update wildcards attribute.
165
166
        This method update a wildcards considering the attributes of the
167
        current instance.
168
169
        Args:
170
            field (str): Name of the updated field.
171
            value (GenericType): New value used in the field.
172
        """
173 1
        if field in [None, 'wildcards'] or isinstance(value, Pad):
174 1
            return
175
176 1
        default_value = getattr(Match, field)
177 1
        if isinstance(default_value, IPAddress):
178 1
            if field == 'nw_dst':
179 1
                shift = FlowWildCards.OFPFW_NW_DST_SHIFT
180 1
                base_mask = FlowWildCards.OFPFW_NW_DST_MASK
181
            else:
182 1
                shift = FlowWildCards.OFPFW_NW_SRC_SHIFT
183 1
                base_mask = FlowWildCards.OFPFW_NW_SRC_MASK
184
185
            # First we clear the nw_dst/nw_src mask related bits on the current
186
            # wildcard by setting 0 on all of them while we keep all other bits
187
            # as they are.
188 1
            self.wildcards &= FlowWildCards.OFPFW_ALL ^ base_mask
189
190
            # nw_dst and nw_src wildcard fields have 6 bits each.
191
            # "base_mask" is the 'all ones' for those 6 bits.
192
            # Once we know the netmask, we can calculate the these 6 bits
193
            # wildcard value and reverse them in order to insert them at the
194
            # correct position in self.wildcards
195 1
            wildcard = (value.max_prefix - value.netmask) << shift
196 1
            self.wildcards |= wildcard
197
        else:
198 1
            wildcard_field = "OFPFW_{}".format(field.upper())
199 1
            wildcard = getattr(FlowWildCards, wildcard_field)
200
201 1
            if value == default_value and not (self.wildcards & wildcard) or \
202
               value != default_value and (self.wildcards & wildcard):
203
                self.wildcards ^= wildcard
204