Passed
Pull Request — master (#128)
by Carlos
03:05
created

build.v0x01.utils   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Test Coverage

Coverage 85.25%

Importance

Changes 0
Metric Value
wmc 14
eloc 80
dl 0
loc 151
ccs 52
cts 61
cp 0.8525
rs 10
c 0
b 0
f 0

7 Functions

Rating   Name   Duplication   Size   Complexity  
A handle_features_reply() 0 45 3
A update_flow_list() 0 15 1
A say_hello() 0 4 1
A send_set_config() 0 6 1
A send_echo() 0 7 1
A request_port_stats() 0 15 1
A send_desc_request() 0 11 1

1 Method

Rating   Name   Duplication   Size   Complexity  
A Of10Encoder.default() 0 11 5
1
"""Utilities module for of_core OpenFlow v0x01 operations."""
2 1
import json
3
4 1
from pyof.foundation.basic_types import UBInt8, UBInt16, UBInt32, UBInt64
5 1
from pyof.v0x01.controller2switch.common import (ConfigFlag, FlowStatsRequest,
6
                                                 PortStatsRequest)
7 1
from pyof.v0x01.controller2switch.set_config import SetConfig
8 1
from pyof.v0x01.controller2switch.stats_request import StatsRequest, StatsType
9 1
from pyof.v0x01.symmetric.echo_request import EchoRequest
10 1
from pyof.v0x01.symmetric.hello import Hello
11
12 1
from kytos.core import KytosEvent
13 1
from kytos.core.interface import Interface
14 1
from napps.kytos.of_core.utils import emit_message_out
15
16
17 1
class Of10Encoder(json.JSONEncoder):
18
    """Custom JSON encoder for OF 1.0 stream representation.
19
20
    Make casting from UBInt8, UBInt16, UBInt32, UBInt64 to int.
21
    """
22
23 1
    def default(self, obj):  # pylint: disable=E0202,W0221
24
        """Make casting from UBInt8, UBInt16, UBInt32, UBInt64 to int."""
25
        if isinstance(obj, UBInt8):
26
            return int(obj)
27
        if isinstance(obj, UBInt16):
28
            return int(obj)
29
        if isinstance(obj, UBInt32):
30
            return int(obj)
31
        if isinstance(obj, UBInt64):
32
            return int(obj)
33
        return json.JSONEncoder.default(self, obj)
34
35
36 1
def update_flow_list(controller, switch):
37
    """Request flow 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 1
    body = FlowStatsRequest()
46 1
    stats_request = StatsRequest(
47
        body_type=StatsType.OFPST_FLOW,
48
        body=body)
49
    # req.pack()
50 1
    emit_message_out(controller, switch.connection, stats_request)
51
52
53 1
def request_port_stats(controller, switch):
54
    """Request port stats from switches.
55
56
    Args:
57
        controller(:class:`~kytos.core.controller.Controller`):
58
            the controller being used.
59
        switch(:class:`~kytos.core.switch.Switch`):
60
            target to send a stats request.
61
    """
62 1
    body = PortStatsRequest()
63 1
    stats_request = StatsRequest(
64
        body_type=StatsType.OFPST_PORT,
65
        body=body)
66
    # req.pack()
67 1
    emit_message_out(controller, switch.connection, stats_request)
68
69
70 1
def send_desc_request(controller, switch):
71
    """Send a description request to the switch.
72
73
    Args:
74
        controller(:class:`~kytos.core.controller.Controller`):
75
            the controller being used.
76
        switch(:class:`~kytos.core.switch.Switch`):
77
            target to send a stats request.
78
    """
79 1
    stats_request = StatsRequest(body_type=StatsType.OFPST_DESC)
80 1
    emit_message_out(controller, switch.connection, stats_request)
81
82
83 1
def handle_features_reply(controller, event):
84
    """Handle OF v0x01 features_reply message events.
85
86
    This is the end of the Handshake workflow of the OpenFlow Protocol.
87
    Parameters:
88
        controller (Controller): Controller being used.
89
        event (KytosEvent): Event with features reply message.
90
91
    """
92 1
    connection = event.source
93 1
    features_reply = event.content['message']
94 1
    dpid = features_reply.datapath_id.value
95
96 1
    switch = controller.get_switch_or_create(dpid=dpid,
97
                                             connection=connection)
98
99 1
    for port in features_reply.ports:
100 1
        interface = switch.get_interface_by_port_no(port.port_no.value)
101 1
        if interface:
102 1
            interface.name = port.name.value
103 1
            interface.address = port.hw_addr.value
104 1
            interface.state = port.state.value
105 1
            interface.features = port.curr
106
        else:
107 1
            interface = Interface(name=port.name.value,
108
                                  address=port.hw_addr.value,
109
                                  port_number=port.port_no.value,
110
                                  switch=switch,
111
                                  state=port.state.value,
112
                                  features=port.curr)
113 1
        switch.update_interface(interface)
114 1
        port_event = KytosEvent(name='kytos/of_core.switch.port.created',
115
                                content={
116
                                    'switch': switch.id,
117
                                    'port': port.port_no.value,
118
                                    'port_description': {
119
                                        'alias': port.name.value,
120
                                        'mac': port.hw_addr.value,
121
                                        'state': port.state.value
122
                                        }
123
                                    })
124 1
        controller.buffers.app.put(port_event)
125
126 1
    switch.update_features(features_reply)
127 1
    return switch
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_10')
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 = 0xffff       # Send the whole packet
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
    emit_message_out(controller, connection, hello)
151