Passed
Pull Request — master (#92)
by Antonio
02:18
created

build.v0x04.utils   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Test Coverage

Coverage 82.67%

Importance

Changes 0
Metric Value
wmc 16
eloc 91
dl 0
loc 173
rs 10
c 0
b 0
f 0
ccs 62
cts 75
cp 0.8267

11 Functions

Rating   Name   Duplication   Size   Complexity  
A send_echo() 0 7 1
A say_hello() 0 4 1
A send_set_config() 0 6 1
A send_port_request() 0 5 1
A update_flow_list() 0 18 1
A bytes_to_mask() 0 11 3
A handle_port_desc() 0 28 3
A request_port_stats() 0 18 1
A mask_to_bytes() 0 7 2
A handle_features_reply() 0 21 1
A send_desc_request() 0 12 1
1
"""Utilities module for of_core OpenFlow v0x04 operations."""
2 1
from pyof.v0x04.common.action import ControllerMaxLen
3 1
from pyof.v0x04.controller2switch.common import ConfigFlag, MultipartType
4 1
from pyof.v0x04.controller2switch.multipart_request import (FlowStatsRequest,
5
                                                            MultipartRequest,
6
                                                            PortStatsRequest)
7 1
from pyof.v0x04.controller2switch.set_config import SetConfig
8 1
from pyof.v0x04.symmetric.echo_request import EchoRequest
9 1
from pyof.v0x04.symmetric.hello import Hello
10
11 1
from kytos.core.events import KytosEvent
12 1
from kytos.core.interface import Interface
13 1
from napps.kytos.of_core.utils import emit_message_out
14
15
16 1
def update_flow_list(controller, switch):
17
    """Request flow stats from switches.
18
19
    Args:
20
        controller(:class:`~kytos.core.controller.Controller`):
21
            the controller being used.
22
        switch(:class:`~kytos.core.switch.Switch`):
23
            target to send a stats request.
24
25
    Returns:
26
        int: multipart request xid
27
28
    """
29 1
    multipart_request = MultipartRequest()
30 1
    multipart_request.multipart_type = MultipartType.OFPMP_FLOW
31 1
    multipart_request.body = FlowStatsRequest()
32 1
    emit_message_out(controller, switch.connection, multipart_request)
33 1
    return multipart_request.header.xid
34
35
36 1
def request_port_stats(controller, switch):
37
    """Request port stats from switches.
38
39
    Args:
40
        controller(:class:`~kytos.core.controller.Controller`):
41
            the controller being used.
42
        switch(:class:`~kytos.core.switch.Switch`):
43
            target to send a stats request.
44
45
    Returns:
46
        int: multipart request xid
47
48
    """
49 1
    multipart_request = MultipartRequest()
50 1
    multipart_request.multipart_type = MultipartType.OFPMP_PORT_STATS
51 1
    multipart_request.body = PortStatsRequest()
52 1
    emit_message_out(controller, switch.connection, multipart_request)
53 1
    return multipart_request.header.xid
54
55
56 1
def send_desc_request(controller, switch):
57
    """Request vendor-specific switch description.
58
59
    Args:
60
        controller(:class:`~kytos.core.controller.Controller`):
61
            the controller being used.
62
        switch(:class:`~kytos.core.switch.Switch`):
63
            target to send a stats request.
64
    """
65 1
    multipart_request = MultipartRequest()
66 1
    multipart_request.multipart_type = MultipartType.OFPMP_DESC
67 1
    emit_message_out(controller, switch.connection, multipart_request)
68
69
70 1
def send_port_request(controller, connection):
71
    """Send a Port Description Request after the Features Reply."""
72 1
    port_request = MultipartRequest()
73 1
    port_request.multipart_type = MultipartType.OFPMP_PORT_DESC
74 1
    emit_message_out(controller, connection, port_request)
75
76
77 1
def handle_features_reply(controller, event):
78
    """Handle OF v0x04 features_reply message events.
79
80
    This is the end of the Handshake workflow of the OpenFlow Protocol.
81
82
    Parameters:
83
        controller (Controller): Controller being used.
84
        event (KytosEvent): Event with features reply message.
85
86
    """
87 1
    connection = event.source
88 1
    features_reply = event.content['message']
89 1
    dpid = features_reply.datapath_id.value
90
91 1
    switch = controller.get_switch_or_create(dpid=dpid,
92
                                             connection=connection)
93 1
    send_port_request(controller, connection)
94
95 1
    switch.update_features(features_reply)
96
97 1
    return switch
98
99
100 1
def handle_port_desc(controller, switch, port_list):
101
    """Update interfaces on switch based on port_list information."""
102 1
    for port in port_list:
103 1
        interface = switch.get_interface_by_port_no(port.port_no.value)
104 1
        if interface:
105 1
            interface.name = port.name.value
106 1
            interface.address = port.hw_addr.value
107 1
            interface.state = port.state.value
108 1
            interface.features = port.curr
109
        else:
110 1
            interface = Interface(name=port.name.value,
111
                                  address=port.hw_addr.value,
112
                                  port_number=port.port_no.value,
113
                                  switch=switch,
114
                                  state=port.state.value,
115
                                  features=port.curr)
116 1
        switch.update_interface(interface)
117 1
        port_event = KytosEvent(name='kytos/of_core.switch.port.created',
118
                                content={
119
                                    'switch': switch.id,
120
                                    'port': port.port_no.value,
121
                                    'port_description': {
122
                                        'alias': port.name.value,
123
                                        'mac': port.hw_addr.value,
124
                                        'state': port.state.value
125
                                        }
126
                                    })
127 1
        controller.buffers.app.put(port_event)
128
129
130 1
def send_echo(controller, switch):
131
    """Send echo request to a datapath.
132
133
    Keep the connection alive through symmetric echoes.
134
    """
135 1
    echo = EchoRequest(data=b'kytosd_13')
136 1
    emit_message_out(controller, switch.connection, echo)
137
138
139 1
def send_set_config(controller, switch):
140
    """Send a SetConfig message after the OpenFlow handshake."""
141 1
    set_config = SetConfig()
142 1
    set_config.flags = ConfigFlag.OFPC_FRAG_NORMAL
143 1
    set_config.miss_send_len = ControllerMaxLen.OFPCML_NO_BUFFER
144 1
    emit_message_out(controller, switch.connection, set_config)
145
146
147 1
def say_hello(controller, connection):
148
    """Send back a Hello packet with the same version as the switch."""
149 1
    hello = Hello()
150 1
    emit_message_out(controller, connection, hello)
151
152
153 1
def mask_to_bytes(mask, size):
154
    """Return the mask in bytes."""
155
    bits = 0
156
    for i in range(size-mask, size):
157
        bits |= (1 << i)
158
    tobytes = bits.to_bytes(size//8, 'big')
159
    return tobytes
160
161
162 1
def bytes_to_mask(tobytes, size):
163
    """Return the mask in string."""
164
    int_mask = int.from_bytes(tobytes, 'big')
165
    strbits = format(int_mask, 'b')
166
    netmask = 0
167
    for i in range(size):
168
        if strbits[i] == '1':
169
            netmask += 1
170
        else:
171
            break
172
    return netmask
173