|
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
|
|
|
|