Passed
Push — master ( e932ef...36cf0a )
by Vinicius
02:30 queued 14s
created

build.tracing.trace_pkt   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 224
Duplicated Lines 0 %

Test Coverage

Coverage 87.67%

Importance

Changes 0
Metric Value
eloc 77
dl 0
loc 224
ccs 64
cts 73
cp 0.8767
rs 10
c 0
b 0
f 0
wmc 18

9 Functions

Rating   Name   Duplication   Size   Complexity  
A _create_udp_packet() 0 9 1
A _create_tcp_packet() 0 9 1
A prepare_next_packet() 0 30 2
A _get_node_color_from_dpid() 0 13 3
A _create_ethernet_frame() 0 20 1
A _create_ip_packet() 0 14 1
A generate_trace_pkt() 0 48 4
A process_packet() 0 37 4
A _get_vlan_from_pkt() 0 12 1
1
"""
2
    This module has functions used to pack and unpack the Ethernet frame
3
     used by PacketOuts and PacketIns.
4
"""
5
6
7 1
import dill
8 1
from pyof.foundation.network_types import Ethernet, IPv4, VLAN
9 1
from napps.amlight.sdntrace import constants
10 1
from napps.amlight.sdntrace.tracing.trace_msg import TraceMsg
11
# from napps.amlight.sdntrace.shared.extd_nw_types import TCP, UDP
12 1
from napps.amlight.sdntrace.shared.switches import Switches
13 1
from napps.amlight.sdntrace.shared.colors import Colors
14
15
16 1
def generate_trace_pkt(trace_entries, color, r_id):
17
    """ Receives the REST/PUT to generate a PacketOut
18
    data needs to be serialized. The goal is always to create
19
    a packet with data being the TraceMsg to differentiate different
20
    traces running in parallel. We will stack layers depending of
21
    the user request. If user submits just a VLAN ID, we will use
22
    ethertype 88b5 and add TraceMsg after it. Same for IP, however
23
    the protocol will be 65535. If user provides all the way to TCP/UDP
24
    we will add TraceMsg after it. First thing is to discover
25
    what it is that the user has provided.
26
27
    Args:
28
        trace_entries: TraceEntries provided by user or collected from PacketIn
29
        color: result from Coloring Napp for a specific DPID
30
        r_id: request ID
31
32
    Returns:
33
        in_port: in_port
34
        pkt: serialized Ethernet frame
35
    """
36
37 1
    ethernet = _create_ethernet_frame(trace_entries, color)
38
39 1
    msg = TraceMsg(r_id)
40
41 1
    if ethernet.ether_type == constants.IPV4:
42 1
        ip_pkt = _create_ip_packet(trace_entries)
43 1
        if ip_pkt.protocol == constants.TCP:
44
            # No dissector for TCP yet
45
            ip_pkt.data = dill.dumps(msg)
46
47
            # tp_pkt = _create_tcp_packet(trace_entries)
48
            # ip_pkt.data = tp_pkt.pack()
49 1
        elif ip_pkt.protocol == constants.UDP:
50
            # No dissector for UDP yet
51
            ip_pkt.data = dill.dumps(msg)
52
53
            # tp_pkt = _create_udp_packet(trace_entries)
54
            # ip_pkt.data = tp_pkt.pack()
55
        else:
56 1
            ip_pkt.data = dill.dumps(msg)
57
58 1
        ethernet.data = ip_pkt.pack()
59
    else:
60
        ethernet.data = dill.dumps(msg)
61
62 1
    pkt = ethernet.pack()
63 1
    return trace_entries.in_port, pkt
64
65
66 1
def prepare_next_packet(trace_entries, result, event):
67
    """ Used to support VLAN translation. Currently, it does not
68
    support translation of other fields, such as MAC addresses.
69
70
    Args:
71
        trace_entries: TraceEntries provided by user or collected from PacketIn
72
        result: Result of the last Trace Probe sent.
73
        event: PacketIn event
74
75
    Returns:
76
        trace_entries: TraceEntries customized with new VLAN
77
        color: result from Coloring Napp for a specific DPID
78
        switch: DPID
79
    """
80 1
    dpid = result['dpid']
81 1
    switch, color = _get_node_color_from_dpid(dpid)
82
83 1
    trace_entries.dpid = dpid
84
85 1
    if event.content['message'].header.version == 1:
86 1
        in_port = event.content['message'].in_port.value
87 1
        trace_entries.in_port = in_port
88
    else:
89
        in_port = event.message.in_port
90
        trace_entries.in_port = in_port
91
92 1
    trace_entries.dl_vlan = _get_vlan_from_pkt(
93
        event.content['message'].data.value)
94
95 1
    return trace_entries, color, switch
96
97
98 1
def process_packet(ethernet):
99
    """Navigates through the Ethernet payload looking for the
100
    TraceMsg(). TraceMsg is the payload after all protocols of
101
    the TCP/IP stack.
102
103
    Args:
104
        ethernet: ethernet frame
105
106
    Returns:
107
        TraceMsg in the binary format
108
    """
109 1
    offset = 0
110
111 1
    trace_msg = ethernet.data.value
112
113 1
    if ethernet.ether_type == constants.IPV4:
114 1
        ip_pkt = IPv4()
115 1
        ip_pkt.unpack(ethernet.data.value, offset)
116 1
        offset += ip_pkt.length
117 1
        trace_msg = ip_pkt.data
118
119 1
        if ip_pkt.protocol == constants.TCP:
120
            # TCP and UDP are not yet supported
121
            # transport = TCP()
122
            # transport.parse(ethernet.data.value, offset)
123
            # offset += transport.length
124
            # trace_msg = transport.data
125
            trace_msg = ip_pkt.data
126
127 1
        if ip_pkt.protocol == constants.UDP:
128
            # transport = UDP()
129
            # transport.parse(ethernet.data.value, offset)
130
            # offset += transport.length
131
            # trace_msg = transport.data
132
            trace_msg = ip_pkt.data
133
134 1
    return trace_msg
135
136
137 1
def _create_ethernet_frame(trace_entries, color):
138
    """ Create an Ethernet frame using TraceEntries
139
    and color (dl_src)
140
141
    Args:
142
        trace_entries: TraceEntries provided by user or collected from PacketIn
143
        color: field and value that indicate the color
144
    Returns:
145
        ethernet frame
146
    """
147 1
    ethernet = Ethernet()
148 1
    ethernet.ether_type = trace_entries.dl_type
149
150 1
    ethernet.source = color['color_value']
151 1
    ethernet.destination = trace_entries.dl_dst
152
153 1
    vlan = VLAN(vid=trace_entries.dl_vlan,
154
                pcp=trace_entries.dl_vlan_pcp)
155 1
    ethernet.vlans.append(vlan)
156 1
    return ethernet
157
158
159 1
def _create_ip_packet(trace_entries):
160
    """ Create an IP packet using TraceEntries
161
162
    Args:
163
        trace_entries: TraceEntries provided by user or collected from PacketIn
164
    Returns:
165
        ip packet
166
    """
167 1
    ip_pkt = IPv4()
168 1
    ip_pkt.destination = trace_entries.nw_dst
169 1
    ip_pkt.source = trace_entries.nw_src
170 1
    ip_pkt.dscp = trace_entries.nw_tos
171 1
    ip_pkt.protocol = trace_entries.nw_proto
172 1
    return ip_pkt
173
174
175 1
def _create_tcp_packet(trace_entries):
176
    """ Create a TCP packet using TraceEntries (FUTURE)
177
178
    Args:
179
        trace_entries: TraceEntries provided by user or collected from PacketIn
180
    Returns:
181
        tcp packet
182
    """
183
    return trace_entries
184
185
186 1
def _create_udp_packet(trace_entries):
187
    """ Create an UDP datagram using TraceEntries (FUTURE)
188
189
    Args:
190
        trace_entries: TraceEntries provided by user or collected from PacketIn
191
    Returns:
192
        tcp message
193
    """
194
    return trace_entries
195
196
197 1
def _get_node_color_from_dpid(dpid):
198
    """ Get node color from Coloring Napp
199
200
    Args:
201
        dpid: switch DPID
202
    Returns:
203
        switch and color
204
        0 for not Found
205
    """
206 1
    for switch in Switches().get_switches():
207 1
        if dpid == switch.dpid:
208 1
            return switch, Colors().get_switch_color(switch.dpid)
209 1
    return 0, 0
210
211
212 1
def _get_vlan_from_pkt(data):
213
    """ Get VLAN ID from frame. Used for VLAN Translation
214
215
    Args:
216
        data: Ethernet Frame
217
    Returns:
218
        VLAN VID
219
    """
220 1
    ethernet = Ethernet()
221 1
    ethernet.unpack(data)
222 1
    vlan = ethernet.vlans[0]
223
    return vlan.vid
224