Passed
Pull Request — master (#117)
by Carlos
03:33
created

build.match.match10()   F

Complexity

Conditions 42

Size

Total Lines 83
Code Lines 81

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1738.0944

Importance

Changes 0
Metric Value
cc 42
eloc 81
nop 2
dl 0
loc 83
ccs 1
cts 77
cp 0.013
crap 1738.0944
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like build.match.match10() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""Switch match."""
2
3 1
import ipaddress
4
5 1
from pyof.v0x01.common.flow_match import FlowWildCards
6
7 1
from kytos.core import log
8
9 1
from .settings import IPV4
10
11
12 1
def format_request(request):
13
    """Format user request to match function format."""
14
    args = {}
15
    for key, value in request.items():
16
        args[key] = value
17
    return args
18
19
20 1
def do_match(flow_to_install, version, stored_flow_dict):
21
    """Match a packet against this flow."""
22
    if version == 0x01:
23
        return match10(stored_flow_dict, flow_to_install)
24
    elif version == 0x04:
25
        return match13_no_strict(flow_to_install, stored_flow_dict)
26
    return None
27
28
29 1
def _get_match_fields(flow_dict):
30
    """Generate match fields."""
31
    match_fields = {}
32
    if 'match' in flow_dict:
33
        for key, value in flow_dict['match'].items():
34
            match_fields[key] = value
35
    return match_fields
36
37
38
# pylint: disable=too-many-return-statements, too-many-statements, R0912
39 1
def match10(flow_dict, args):
40
    """Match a packet against this flow (OF1.0)."""
41
    log.debug('Matching packet')
42
    match_fields = _get_match_fields(flow_dict)
43
    if not match_fields.get('wildcards') & FlowWildCards.OFPFW_IN_PORT:
44
        if 'in_port' not in args:
45
            return False
46
        if match_fields.get('in_port') != int(args.get('in_port')):
47
            return False
48
    if not match_fields.get('wildcards') & FlowWildCards.OFPFW_DL_VLAN_PCP:
49
        if 'vlan_pcp' not in args:
50
            return False
51
        if match_fields.get('vlan_pcp') != int(args.get('vlan_pcp')):
52
            return False
53
    if not match_fields.get('wildcards') & FlowWildCards.OFPFW_DL_VLAN:
54
        if 'vlan_vid' not in args:
55
            return False
56
        if match_fields.get('vlan_vid') != args.get('vlan_vid')[-1]:
57
            return False
58
    if not match_fields.get('wildcards') & FlowWildCards.OFPFW_DL_SRC:
59
        if 'eth_src' not in args:
60
            return False
61
        if match_fields.get('eth_src') != args.get('eth_src'):
62
            return False
63
    if not match_fields.get('wildcards') & FlowWildCards.OFPFW_DL_DST:
64
        if 'eth_dst' not in args:
65
            return False
66
        if match_fields.get('eth_dst') != args.get('eth_dst'):
67
            return False
68
    if not match_fields.get('wildcards') & FlowWildCards.OFPFW_DL_TYPE:
69
        if 'eth_type' not in args:
70
            return False
71
        if match_fields.get('eth_type') != int(args.get('eth_type')):
72
            return False
73
    if match_fields['eth_type'] == IPV4:
74
        flow_ip_int = int(ipaddress.IPv4Address(match_fields.get('ipv4_src')))
75
        if flow_ip_int != 0:
76
            mask = (match_fields.get('wildcards')
77
                    & FlowWildCards.OFPFW_NW_SRC_MASK) >> \
78
                    FlowWildCards.OFPFW_NW_SRC_SHIFT
79
            if mask > 32:
80
                mask = 32
81
            if mask != 32 and 'ipv4_src' not in args:
82
                return False
83
            mask = (0xffffffff << mask) & 0xffffffff
84
            ip_int = int(ipaddress.IPv4Address(args.get('ipv4_src')))
85
            if ip_int & mask != flow_ip_int & mask:
86
                return False
87
88
        flow_ip_int = int(ipaddress.IPv4Address(match_fields['ipv4_dst']))
89
        if flow_ip_int != 0:
90
            mask = (match_fields.get('wildcards')
91
                    & FlowWildCards.OFPFW_NW_DST_MASK) >> \
92
                    FlowWildCards.OFPFW_NW_DST_SHIFT
93
            if mask > 32:
94
                mask = 32
95
            if mask != 32 and 'ipv4_dst' not in args:
96
                return False
97
            mask = (0xffffffff << mask) & 0xffffffff
98
            ip_int = int(ipaddress.IPv4Address(args.get('ipv4_dst')))
99
            if ip_int & mask != flow_ip_int & mask:
100
                return False
101
        if not match_fields.get('wildcards') & FlowWildCards.OFPFW_NW_TOS:
102
            if 'ip_tos' not in args:
103
                return False
104
            if match_fields.get('ip_tos') != int(args.get('ip_tos')):
105
                return False
106
        if not match_fields.get('wildcards') & FlowWildCards.OFPFW_NW_PROTO:
107
            if 'ip_proto' not in args:
108
                return False
109
            if match_fields.get('ip_proto') != int(args.get('ip_proto')):
110
                return False
111
        if not match_fields.get('wildcards') & FlowWildCards.OFPFW_TP_SRC:
112
            if 'tp_src' not in args:
113
                return False
114
            if match_fields.get('tcp_src') != int(args.get('tp_src')):
115
                return False
116
        if not match_fields.get('wildcards') & FlowWildCards.OFPFW_TP_DST:
117
            if 'tp_dst' not in args:
118
                return False
119
            if match_fields.get('tcp_dst') != int(args.get('tp_dst')):
120
                return False
121
    return flow_dict
122
123
    # def match13(self, args):
124
    #     """Match a packet against this flow (OF1.3)."""
125
    #     for name in self.match:
126
    #         if name not in args:
127
    #             return False
128
    #         if name == 'vlan_vid':
129
    #             field = args[name][-1]
130
    #         else:
131
    #             field = args[name]
132
    #         if name not in ('ipv4_src', 'ipv4_dst', 'ipv6_src', 'ipv6_dst'):
133
    #             if self.match[name].value != field:
134
    #                 return False
135
    #         else:
136
    #             packet_ip = int(ipaddress.ip_address(field))
137
    #             ip_addr = self.match[name].value
138
    #             if packet_ip & ip_addr.netmask != ip_addr.address:
139
    #                 return False
140
    #     return self
141
142
143 1
def match13_no_strict(flow_to_install, stored_flow_dict):
144
    """Match a packet againts the stored flow (OF 1.3).
145
146
    Return the flow if any fields match, otherwise, return False.
147
    """
148
    if flow_to_install.get('cookie_mask') and 'cookie' in stored_flow_dict:
149
        cookie = flow_to_install['cookie_mask'] & flow_to_install['cookie']
150
        if cookie == stored_flow_dict['cookie']:
151
            return stored_flow_dict
152
        return False
153
154
    if 'match' not in flow_to_install:
155
        return False
156
157
    for key, value in flow_to_install.get('match').items():
158
        if 'match' in stored_flow_dict:
159
            if value == stored_flow_dict['match'].get(key):
160
                return stored_flow_dict
161
    return None
162
163
164 1
def match_flows(flow_to_install, version, stored_flow_dict):
165
    # pylint: disable=bad-staticmethod-argument
166
    """
167
    Match the packet in request against the flows installed in the switch.
168
169
    Try the match with each flow, in other. If many is True, tries the
170
    match with all flows, if False, tries until the first match.
171
    :param args: packet data
172
    :param many: Boolean, indicating whether to continue after matching the
173
            first flow or not
174
    :return: If many, the list of matched flows, or the matched flow
175
    """
176
    match = do_match(flow_to_install, version, stored_flow_dict)
177
    return match
178