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

build.match._get_match_fields()   A

Complexity

Conditions 3

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 8.2077

Importance

Changes 0
Metric Value
cc 3
eloc 6
nop 1
dl 0
loc 7
ccs 1
cts 6
cp 0.1666
crap 8.2077
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
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