Passed
Pull Request — master (#91)
by Gleyberson
03:12
created

build.v0x04.utils   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 156
Duplicated Lines 0 %

Test Coverage

Coverage 79.17%

Importance

Changes 0
Metric Value
wmc 15
eloc 88
dl 0
loc 156
ccs 57
cts 72
cp 0.7917
rs 10
c 0
b 0
f 0

10 Functions

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