build.match._match_ipv4_10()   F
last analyzed

Complexity

Conditions 21

Size

Total Lines 45
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 189.0554

Importance

Changes 0
Metric Value
cc 21
eloc 44
nop 3
dl 0
loc 45
rs 0
c 0
b 0
f 0
ccs 11
cts 40
cp 0.275
crap 189.0554

How to fix   Complexity   

Complexity

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