Passed
Push — master ( e385f0...0b1ef2 )
by Vinicius
02:02 queued 14s
created

build.tracing.trace_pkt   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 225
Duplicated Lines 0 %

Test Coverage

Coverage 87.84%

Importance

Changes 0
Metric Value
eloc 78
dl 0
loc 225
ccs 65
cts 74
cp 0.8784
rs 10
c 0
b 0
f 0
wmc 19

9 Functions

Rating   Name   Duplication   Size   Complexity  
A prepare_next_packet() 0 30 2
A generate_trace_pkt() 0 48 4
A process_packet() 0 37 4
A _get_node_color_from_dpid() 0 13 3
A _create_ethernet_frame() 0 21 2
A _create_udp_packet() 0 9 1
A _create_tcp_packet() 0 9 1
A _create_ip_packet() 0 14 1
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
    if trace_entries.dl_vlan:
154 1
        vlan = VLAN(vid=trace_entries.dl_vlan,
155
                    pcp=trace_entries.dl_vlan_pcp)
156 1
        ethernet.vlans.append(vlan)
157 1
    return ethernet
158
159
160 1
def _create_ip_packet(trace_entries):
161
    """ Create an IP packet using TraceEntries
162
163
    Args:
164
        trace_entries: TraceEntries provided by user or collected from PacketIn
165
    Returns:
166
        ip packet
167
    """
168 1
    ip_pkt = IPv4()
169 1
    ip_pkt.destination = trace_entries.nw_dst
170 1
    ip_pkt.source = trace_entries.nw_src
171 1
    ip_pkt.dscp = trace_entries.nw_tos
172 1
    ip_pkt.protocol = trace_entries.nw_proto
173 1
    return ip_pkt
174
175
176 1
def _create_tcp_packet(trace_entries):
177
    """ Create a TCP packet using TraceEntries (FUTURE)
178
179
    Args:
180
        trace_entries: TraceEntries provided by user or collected from PacketIn
181
    Returns:
182
        tcp packet
183
    """
184
    return trace_entries
185
186
187 1
def _create_udp_packet(trace_entries):
188
    """ Create an UDP datagram using TraceEntries (FUTURE)
189
190
    Args:
191
        trace_entries: TraceEntries provided by user or collected from PacketIn
192
    Returns:
193
        tcp message
194
    """
195
    return trace_entries
196
197
198 1
def _get_node_color_from_dpid(dpid):
199
    """ Get node color from Coloring Napp
200
201
    Args:
202
        dpid: switch DPID
203
    Returns:
204
        switch and color
205
        0 for not Found
206
    """
207 1
    for switch in Switches().get_switches():
208 1
        if dpid == switch.dpid:
209 1
            return switch, Colors().get_switch_color(switch.dpid)
210 1
    return 0, 0
211
212
213 1
def _get_vlan_from_pkt(data):
214
    """ Get VLAN ID from frame. Used for VLAN Translation
215
216
    Args:
217
        data: Ethernet Frame
218
    Returns:
219
        VLAN VID
220
    """
221 1
    ethernet = Ethernet()
222 1
    ethernet.unpack(data)
223 1
    vlan = ethernet.vlans[0]
224
    return vlan.vid
225