Passed
Pull Request — master (#117)
by Carlos
02:49
created

build.match.match13_no_strict()   C

Complexity

Conditions 11

Size

Total Lines 31
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 11.5605

Importance

Changes 0
Metric Value
cc 11
eloc 25
nop 2
dl 0
loc 31
ccs 20
cts 24
cp 0.8333
crap 11.5605
rs 5.4
c 0
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like build.match.match13_no_strict() 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
8 1
def match_flow(flow_to_install, version, stored_flow_dict):
9
    """Check that the flow fields match.
10
11
    It has support for (OF 1.0) and (OF 1.3) flows.
12
    If fields match, return the flow, otherwise return False.
13
    Does not require that all fields match.
14
    """
15 1
    if version == 0x01:
16 1
        return match10(flow_to_install, stored_flow_dict)
17 1
    elif version == 0x04:
18 1
        return match13_no_strict(flow_to_install, stored_flow_dict)
19
    raise NotImplementedError(f'Unsupported OpenFlow version {version}')
20
21
22 1
def _get_match_fields(flow_dict):
23
    """Generate match fields."""
24 1
    match_fields = {}
25 1
    if 'match' in flow_dict:
26 1
        for key, value in flow_dict['match'].items():
27 1
            match_fields[key] = value
28 1
    return match_fields
29
30
31
# pylint: disable=too-many-return-statements, too-many-statements, R0912
32 1
def _match_ipv4_10(match_fields, args, wildcards):
33
    """Match IPV4 fields against packet with Flow (OF1.0)."""
34 1
    flow_ip_int = int(ipaddress.IPv4Address(match_fields.get('nw_src', 0)))
35 1
    if flow_ip_int != 0:
36
        mask = (wildcards
37
                & FlowWildCards.OFPFW_NW_SRC_MASK) >> \
38
                FlowWildCards.OFPFW_NW_SRC_SHIFT
39
        if mask > 32:
40
            mask = 32
41
        if mask != 32 and 'nw_src' not in args:
42
            return False
43
        mask = (0xffffffff << mask) & 0xffffffff
44
        ip_int = int(ipaddress.IPv4Address(args.get('nw_src')))
45
        if ip_int & mask != flow_ip_int & mask:
46
            return False
47 1
    flow_ip_int = int(ipaddress.IPv4Address(match_fields.get('nw_dst', 0)))
48 1
    if flow_ip_int != 0:
49
        mask = (wildcards
50
                & FlowWildCards.OFPFW_NW_DST_MASK) >> \
51
                FlowWildCards.OFPFW_NW_DST_SHIFT
52
        if mask > 32:
53
            mask = 32
54
        if mask != 32 and 'nw_dst' not in args:
55
            return False
56
        mask = (0xffffffff << mask) & 0xffffffff
57
        ip_int = int(ipaddress.IPv4Address(args.get('nw_dst')))
58
        if ip_int & mask != flow_ip_int & mask:
59
            return False
60 1
    if not wildcards & FlowWildCards.OFPFW_NW_TOS:
61 1
        if ('nw_tos', 'nw_proto', 'tp_src', 'tp_dst') not in args:
62 1
            return True
63
        if match_fields.get('nw_tos') != int(args.get('nw_tos')):
64
            return False
65
    if not wildcards & FlowWildCards.OFPFW_NW_PROTO:
66
        if match_fields.get('nw_proto') != int(args.get('nw_proto')):
67
            return False
68
    if not wildcards & FlowWildCards.OFPFW_TP_SRC:
69
        if match_fields.get('tp_src') != int(args.get('tp_src')):
70
            return False
71
    if not wildcards & FlowWildCards.OFPFW_TP_DST:
72
        if match_fields.get('tp_dst') != int(args.get('tp_dst')):
73
            return False
74
    return True
75
76
77
# pylint: disable=too-many-return-statements, too-many-statements, R0912
78 1
def match10(flow_dict, args):
79
    """Match a packet against this flow (OF1.0)."""
80 1
    args = _get_match_fields(args)
81 1
    match_fields = _get_match_fields(flow_dict)
82 1
    wildcards = match_fields.get('wildcards', 0)
83 1
    if not wildcards & FlowWildCards.OFPFW_IN_PORT:
84
        if match_fields.get('in_port') != args.get('in_port'):
85
            return False
86 1
    if not wildcards & FlowWildCards.OFPFW_DL_VLAN_PCP:
87
        if match_fields.get('dl_vlan_pcp') != args.get('dl_vlan_pcp'):
88
            return False
89 1
    if not wildcards & FlowWildCards.OFPFW_DL_VLAN:
90
        if match_fields.get('dl_vlan') != args.get('dl_vlan'):
91
            return False
92 1
    if not wildcards & FlowWildCards.OFPFW_DL_SRC:
93
        if match_fields.get('dl_src') != args.get('dl_src'):
94
            return False
95 1
    if not wildcards & FlowWildCards.OFPFW_DL_DST:
96 1
        if match_fields.get('dl_dst') != args.get('dl_dst'):
97 1
            return False
98 1
    if not wildcards & FlowWildCards.OFPFW_DL_TYPE:
99 1
        if match_fields.get('dl_type') != args.get('dl_type'):
100
            return False
101 1
    if not _match_ipv4_10(match_fields, args, wildcards):
102
        return False
103 1
    return flow_dict
104
105
106 1
def match13_no_strict(flow_to_install, stored_flow_dict):
107
    """Match a packet againts the stored flow (OF 1.3).
108
109
    Return the flow if any fields match, otherwise, return False.
110
    """
111 1
    if flow_to_install.get('cookie_mask') and 'cookie' in stored_flow_dict:
112 1
        cookie = flow_to_install['cookie'] & flow_to_install['cookie_mask']
113 1
        stored_cookie = (stored_flow_dict['cookie'] &
114
                         flow_to_install['cookie_mask'])
115 1
        if cookie == stored_cookie:
116 1
            return stored_flow_dict
117 1
        return False
118 1
    if 'match' not in flow_to_install:
119
        return False
120
121 1
    for key, value in flow_to_install.get('match').items():
122 1
        if 'match' not in stored_flow_dict:
123
            return False
124 1
        if key not in ('ipv4_src', 'ipv4_dst', 'ipv6_src', 'ipv6_dst'):
125
            if value == stored_flow_dict['match'].get(key):
126
                return stored_flow_dict
127
        else:
128 1
            field = stored_flow_dict['match'].get(key)
129 1
            if not field:
130 1
                return False
131 1
            masked_ip_addr = ipaddress.ip_network(value, False)
132 1
            field_mask = field + "/" + str(masked_ip_addr.netmask)
133 1
            masked_stored_ip = ipaddress.ip_network(field_mask, False)
134 1
            if masked_ip_addr == masked_stored_ip:
135 1
                return stored_flow_dict
136
    return False
137