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

build.match.format_request()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 4.048

Importance

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