Passed
Push — master ( 667973...d237fc )
by Beraldo
01:46
created

build.v0x04.match_fields   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 315
Duplicated Lines 0 %

Test Coverage

Coverage 56.46%

Importance

Changes 0
Metric Value
eloc 167
dl 0
loc 315
ccs 83
cts 147
cp 0.5646
rs 9.52
c 0
b 0
f 0
wmc 36

32 Methods

Rating   Name   Duplication   Size   Complexity  
A MatchFieldFactory._index_classes() 0 5 2
A MatchField.oxm_field() 0 9 1
A MatchField.__init__() 0 3 1
A MatchTCPDst.as_of_tlv() 0 4 1
A MatchField.from_of_tlv() 0 5 1
A MatchTCPSrc.from_of_tlv() 0 5 1
A MatchFieldFactory.from_name() 0 6 2
A MatchField.__eq__() 0 7 1
A MatchInPort.from_of_tlv() 0 5 1
A MatchTCPSrc.as_of_tlv() 0 4 1
A MatchField.as_of_tlv() 0 4 1
A MatchNwDst.from_of_tlv() 0 7 1
A MatchFieldFactory.from_of_tlv() 0 6 2
A MatchDLVLAN.from_of_tlv() 0 5 1
A MatchDLSrc.from_of_tlv() 0 7 1
A MatchDLDst.as_of_tlv() 0 4 1
A MatchDLDst.from_of_tlv() 0 7 1
A MatchNwDst.as_of_tlv() 0 4 1
A MatchDLVLAN.as_of_tlv() 0 5 1
A MatchNwProto.as_of_tlv() 0 4 1
A MatchDLVLANPCP.from_of_tlv() 0 5 1
A MatchTCPDst.from_of_tlv() 0 5 1
A MatchNwSrc.from_of_tlv() 0 7 1
A MatchDLType.from_of_tlv() 0 5 1
A MatchInPort.as_of_tlv() 0 4 1
A MatchField.name() 0 9 1
A MatchDLVLANPCP.as_of_tlv() 0 4 1
A MatchFieldFactory._get_class() 0 6 2
A MatchNwProto.from_of_tlv() 0 5 1
A MatchDLType.as_of_tlv() 0 4 1
A MatchNwSrc.as_of_tlv() 0 4 1
A MatchDLSrc.as_of_tlv() 0 4 1
1
"""OpenFlow 1.3 OXM match fields.
2
3
Flow's match is very different from OF 1.0. Instead of always having all
4
fields, there's a variable list of match fields and each one is an Openflow
5
eXtended Match Type-Length-Value (OXM TLV) element.
6
7
This module provides high-level Python classes for OXM TLV fields in order to
8
make the OF 1.3 match fields easy to use and to be coded.
9
"""
10 1
from abc import ABC, abstractmethod
11
12 1
from pyof.foundation.basic_types import HWAddress, IPAddress
13 1
from pyof.v0x04.common.flow_match import OxmOfbMatchField, OxmTLV, VlanId
14
15
16 1
class MatchField(ABC):
17
    """Base class for match fields. Abstract OXM TLVs of python-openflow.
18
19
    Just extend this class and you will be forced to define the required
20
    low-level attributes and methods below:
21
22
    * "name" attribute (field name to be displayed in JSON);
23
    * "oxm_field" attribute (``OxmOfbMatchField`` enum);
24
    * Method to return a pyof OxmTLV;
25
    * Method to create an instance from an OxmTLV.
26
    """
27
28 1
    def __init__(self, value):
29
        """Define match field value."""
30 1
        self.value = value
31
32 1
    @property
33 1
    @classmethod
34 1
    @abstractmethod
35
    def name(cls):
36
        """Define a name to be displayed in JSON.
37
38
        It can be overriden just by a class attibute.
39
        """
40
        pass
41
42 1
    @property
43 1
    @classmethod
44 1
    @abstractmethod
45
    def oxm_field(cls):
46
        """Define this subclass ``OxmOfbMatchField`` value.
47
48
        It can be overriden just by as a class attibute.
49
        """
50
        pass
51
52 1
    @abstractmethod
53
    def as_of_tlv(self):
54
        """Return a pyof OXM TLV instance."""
55
        pass
56
57 1
    @classmethod
58 1
    @abstractmethod
59
    def from_of_tlv(cls, tlv):
60
        """Return an instance from a pyof OXM TLV."""
61
        pass
62
63 1
    def __eq__(self, other):
64
        """Two objects are equal if their values are the same.
65
66
        The oxm_field equality is checked indirectly when comparing whether
67
        the objects are instances of the same class.
68
        """
69 1
        return isinstance(other, self.__class__) and other.value == self.value
70
71
72 1
class MatchDLVLAN(MatchField):
73
    """Match for datalink VLAN ID."""
74
75 1
    name = 'dl_vlan'
76 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_VLAN_VID
77
78 1
    def as_of_tlv(self):
79
        """Return a pyof OXM TLV instance."""
80 1
        value = self.value | VlanId.OFPVID_PRESENT
81 1
        value_bytes = value.to_bytes(2, 'big')
82 1
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
83
84 1
    @classmethod
85
    def from_of_tlv(cls, tlv):
86
        """Return an instance from a pyof OXM TLV."""
87 1
        vlan_id = int.from_bytes(tlv.oxm_value, 'big') & 4095
88 1
        return cls(vlan_id)
89
90
91 1
class MatchDLVLANPCP(MatchField):
92
    """Match for VLAN Priority Code Point."""
93
94 1
    name = 'dl_vlan_pcp'
95 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_VLAN_PCP
96
97 1
    def as_of_tlv(self):
98
        """Return a pyof OXM TLV instance."""
99
        value_bytes = self.value.to_bytes(1, 'big')
100
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
101
102 1
    @classmethod
103
    def from_of_tlv(cls, tlv):
104
        """Return an instance from a pyof OXM TLV."""
105
        priority = int.from_bytes(tlv.oxm_value, 'big')
106
        return cls(priority)
107
108
109 1
class MatchDLSrc(MatchField):
110
    """Match for datalink source."""
111
112 1
    name = 'dl_src'
113 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_SRC
114
115 1
    def as_of_tlv(self):
116
        """Return a pyof OXM TLV instance."""
117
        value_bytes = HWAddress(self.value).pack()
118
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
119
120 1
    @classmethod
121
    def from_of_tlv(cls, tlv):
122
        """Return an instance from a pyof OXM TLV."""
123
        hw_address = HWAddress()
124
        hw_address.unpack(tlv.oxm_value)
125
        addr_str = str(hw_address)
126
        return cls(addr_str)
127
128
129 1
class MatchDLDst(MatchField):
130
    """Match for dataling destination."""
131
132 1
    name = 'dl_dst'
133 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_DST
134
135 1
    def as_of_tlv(self):
136
        """Return a pyof OXM TLV instance."""
137
        value_bytes = HWAddress(self.value).pack()
138
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
139
140 1
    @classmethod
141
    def from_of_tlv(cls, tlv):
142
        """Return an instance from a pyof OXM TLV."""
143
        hw_address = HWAddress()
144
        hw_address.unpack(tlv.oxm_value)
145
        addr_str = str(hw_address)
146
        return cls(addr_str)
147
148
149 1
class MatchDLType(MatchField):
150
    """Match for datalink type."""
151
152 1
    name = 'dl_type'
153 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_ETH_TYPE
154
155 1
    def as_of_tlv(self):
156
        """Return a pyof OXM TLV instance."""
157
        value_bytes = self.value.to_bytes(2, 'big')
158
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
159
160 1
    @classmethod
161
    def from_of_tlv(cls, tlv):
162
        """Return an instance from a pyof OXM TLV."""
163
        port = int.from_bytes(tlv.oxm_value, 'big')
164
        return cls(port)
165
166
167 1
class MatchNwSrc(MatchField):
168
    """Match for IPV4 source."""
169
170 1
    name = 'nw_src'
171 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_IPV4_SRC
172
173 1
    def as_of_tlv(self):
174
        """Return a pyof OXM TLV instance."""
175
        value_bytes = IPAddress(self.value).pack()
176
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
177
178 1
    @classmethod
179
    def from_of_tlv(cls, tlv):
180
        """Return an instance from a pyof OXM TLV."""
181
        ip_address = IPAddress()
182
        ip_address.unpack(tlv.oxm_value)
183
        ip_str = str(ip_address)
184
        return cls(ip_str)
185
186
187 1
class MatchNwDst(MatchField):
188
    """Match for IPV4 destination."""
189
190 1
    name = 'nw_dst'
191 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_IPV4_DST
192
193 1
    def as_of_tlv(self):
194
        """Return a pyof OXM TLV instance."""
195
        value_bytes = IPAddress(self.value).pack()
196
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
197
198 1
    @classmethod
199
    def from_of_tlv(cls, tlv):
200
        """Return an instance from a pyof OXM TLV."""
201
        ip_address = IPAddress()
202
        ip_address.unpack(tlv.oxm_value)
203
        ip_str = str(ip_address)
204
        return cls(ip_str)
205
206
207 1
class MatchNwProto(MatchField):
208
    """Match for IP protocol."""
209
210 1
    name = 'nw_proto'
211 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_IP_PROTO
212
213 1
    def as_of_tlv(self):
214
        """Return a pyof OXM TLV instance."""
215
        value_bytes = self.value.to_bytes(1, 'big')
216
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
217
218 1
    @classmethod
219
    def from_of_tlv(cls, tlv):
220
        """Return an instance from a pyof OXM TLV."""
221
        priority = int.from_bytes(tlv.oxm_value, 'big')
222
        return cls(priority)
223
224
225 1
class MatchInPort(MatchField):
226
    """Match for input port."""
227
228 1
    name = 'in_port'
229 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_IN_PORT
230
231 1
    def as_of_tlv(self):
232
        """Return a pyof OXM TLV instance."""
233
        value_bytes = self.value.to_bytes(4, 'big')
234
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
235
236 1
    @classmethod
237
    def from_of_tlv(cls, tlv):
238
        """Return an instance from a pyof OXM TLV."""
239
        port = int.from_bytes(tlv.oxm_value, 'big')
240
        return cls(port)
241
242
243 1
class MatchTCPSrc(MatchField):
244
    """Match for TCP source."""
245
246 1
    name = 'tp_src'
247 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_TCP_SRC
248
249 1
    def as_of_tlv(self):
250
        """Return a pyof OXM TLV instance."""
251
        value_bytes = self.value.to_bytes(2, 'big')
252
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
253
254 1
    @classmethod
255
    def from_of_tlv(cls, tlv):
256
        """Return an instance from a pyof OXM TLV."""
257
        port = int.from_bytes(tlv.oxm_value, 'big')
258
        return cls(port)
259
260
261 1
class MatchTCPDst(MatchField):
262
    """Match for TCP destination."""
263
264 1
    name = 'tp_dst'
265 1
    oxm_field = OxmOfbMatchField.OFPXMT_OFB_TCP_DST
266
267 1
    def as_of_tlv(self):
268
        """Return a pyof OXM TLV instance."""
269
        value_bytes = self.value.to_bytes(2, 'big')
270
        return OxmTLV(oxm_field=self.oxm_field, oxm_value=value_bytes)
271
272 1
    @classmethod
273
    def from_of_tlv(cls, tlv):
274
        """Return an instance from a pyof OXM TLV."""
275
        port = int.from_bytes(tlv.oxm_value, 'big')
276
        return cls(port)
277
278
279 1
class MatchFieldFactory(ABC):
280
    """Create the correct MatchField subclass instance.
281
282
    As OF 1.3 has many match fields and there are many ways to (un)pack their
283
    OxmTLV.oxm_value, this class does all the work of finding the correct
284
    MatchField class and instantiating the corresponding object.
285
    """
286
287 1
    __classes = {}
288
289 1
    @classmethod
290
    def from_name(cls, name, value):
291
        """Return the proper object from name and value."""
292
        field_class = cls._get_class(name)
293
        if field_class:
294
            return field_class(value)
295
296 1
    @classmethod
297
    def from_of_tlv(cls, tlv):
298
        """Return the proper object from a pyof OXM TLV."""
299
        field_class = cls._get_class(tlv.oxm_field)
300
        if field_class:
301
            return field_class.from_of_tlv(tlv)
302
303 1
    @classmethod
304
    def _get_class(cls, name_or_field):
305
        """Return the proper object from field name or OxmTLV.oxm_field."""
306
        if not cls.__classes:
307
            cls._index_classes()
308
        return cls.__classes.get(name_or_field)
309
310 1
    @classmethod
311
    def _index_classes(cls):
312
        for subclass in MatchField.__subclasses__():
313
            cls.__classes[subclass.name] = subclass
314
            cls.__classes[subclass.oxm_field] = subclass
315