All Classes Namespaces Files Functions Pages
networking.tcl
1 ##
2 # @brief Basic namespace for all Excentis Tcl extensions
3 #
4 namespace eval excentis {
5 
6 ##
7 # @brief This namespace holds all ByteBlower-related Tcl extensions, including the ByteBlower higher-layer Tcl API.
8 #
9 # These procedures are developed for higher-level usage of the ByteBlower API.
10 # They are mainly used to simplify running specific Test Scenarios similar to
11 # scenarios you know from the ByteBlower GUI.
12 #
13 namespace eval ByteBlower {
14 
15 # This files includes helper functions to perform networking-related tasks.
16 
17 package require excentis_basic
18 
19 ##
20 # Update the Layer2 and/or Layer 2.5 Header of the Frame
21 #
22 # The Layer2 Header of the frame will be set to match the Port's Layer2 configuration and Layer2.5 extensions.
23 #
24 # The Source MAC Address will be filled in as the Port's Mac address.
25 #
26 # If the L2 Type is IPv4 or IPv6, the destination IPv4 / IPv6 address
27 # will be resolved (if it is a non-broadcast / non-multicast address)
28 # and the resulting destination MAC address will be filled in.
29 #
30 # Layer2.5 extension Headers will be added to the frame.
31 #
32 # @param frameContent
33 # Frame content to adjust to the source ByteBlower port configuration.
34 #
35 # @param bbPort
36 # Source ByteBlower Port from which the given @p frameContent will be sent.
37 #
38 # @return
39 # New frame content string
40 #
41 # @note
42 # This function only supports Ethernet II frames with DIX encoding for now.
43 #
44 proc LinkLayer.AutoComplete { frameContent bbPort } {
45 
46  set l3HeaderOffset 14
47  set l2TypeOffset 12
48 
49  x.Print.Debug "LinkLayer.AutoComplete: OLD Frame Content: {${frameContent}}"
50 
52 
53  set frameContentString [ ::excentis::basic::Hex.To.String ${frameContent} ]
54  #set frameSize [ expr [ string length $frameContentString ] / 2 ]
55  set frameSize [ llength $frameContent ]
56 
57  if { $frameSize < $l3HeaderOffset} {
58  error "LinkLayer.AutoComplete: Frame too small"
59  }
60 
61  # --- Initialize the l2UlProtocol to the UlProtocol typ in the packet
62  # --- Byte 12,13
63  set l2UlProtocol "0x[ string range $frameContentString [ expr 2 * $l2TypeOffset ] [ expr 2 * ( $l2TypeOffset + 2 ) - 1 ] ]"
64 
65  set payloadLength 0
66 
67  set resolveAddress ""
68  # --- Byte 14-end
69  set l3Data [ string range $frameContentString [ expr 2 * $l3HeaderOffset ] end ]
70 
71  # --- Check the Layer3
72  switch -- [ string tolower $l2UlProtocol ] {
73  0x0800 {
74  # --- IPv4
75  if { $frameSize < $l3HeaderOffset + 20 } {
76  # --- Incomplete IPv4 Header
77  x.Print.Debug stderr "Incomplete IPv4 Header."
78  } else {
79  # --- Byte 3,2
80  set l3Length "0x[ string range $l3Data 4 7 ]"
81  incr payloadLength $l3Length
82  unset l3Length
83 
84  # --- Byte 16-19
85  set dstIpStr [ string range $l3Data 32 39 ]
86  set dstIpHex [ ::excentis::basic::String.To.Hex $dstIpStr ]
87  set dstIp [ ::excentis::basic::Hex.To.IP $dstIpHex ]
88  x.Print.Debug "Destination IPv4 address: ${dstIp}."
89 
90  set l3 [ $bbPort Layer3.IPv4.Get ]
91  x.Print.Debug "Processing L3 Protocol is ${l3} ([ if { [ llength $l3 ] } { lindex [ $l3 Info -implements ] 0 } else { lindex "n/a" 0 } ])."
92 
93  if { [ ::excentis::basic::IPv4.IsThisNetwork ${dstIp} ] || \
94  [ ::excentis::basic::IPv4.IsMulticast ${dstIp} ] || \
96  # --- Unable to resolve these kinds of IP addresses
97  x.Print.Debug stderr "IpAddress is ThisNetwork / Multicast / Broadcast."
98  } elseif { [ llength $l3 ] < 1 } {
99  # --- Port is not Layer3 IPv4 configured
100  x.Print.Debug stderr "Port is not Layer3 configured."
101  } elseif { ![ ::excentis::basic::IPv4.IsBroadcast [ $l3 Netmask.Get ] ] && \
102  [ ::excentis::basic::IPv4.IsBroadcast ${dstIp} [ $l3 Netmask.Get ] ] } {
103  x.Print.Debug stderr "Netmask is not 'host' netmask and IpAddress is broadcast for netmask."
104  } else {
105  set resolveAddress $dstIp
106  set l3 [ $bbPort Layer3.IPv4.Get ]
107  }
108 
109  # --- Cleanup
110  unset dstIp
111  unset dstIpHex
112  unset dstIpStr
113  }
114  }
115  0x86dd {
116  # --- IPv6
117  if { $frameSize < $l3HeaderOffset + 20 } {
118  # --- Incomplete IPv6 Header
119  } else {
120  set ipv6PayloadLength "0x[ string range $l3Data 8 11 ]"
121  incr payloadLength [ expr 40 + $ipv6PayloadLength ]
122  unset ipv6PayloadLength
123  # --- Byte 24-39
124  set dstIpStr [ string range $l3Data 48 79 ]
125  set dstIpHex [ ::excentis::basic::String.To.Hex $dstIpStr ]
126  set dstIp [ ::excentis::basic::Hex.To.IPv6 $dstIpHex ]
127  if { ![ ::excentis::basic::IPv6.IsMulticast $dstIp ] } {
128  set resolveAddress $dstIp
129  set l3 [ $bbPort Layer3.IPv6.Get ]
130  }
131 
132  # --- Cleanup
133  unset dstIp
134  unset dstIpHex
135  unset dstIpStr
136  }
137  }
138  0x8100 {
139  # --- VLAN TAG
140  error "LinkLayer.AutoComplete: Auto-completion of VLAN 802.1Q Frame is not supported."
141  }
142  0x8863 -
143  0x8864 {
144  # --- PPPoE Discovery/Session TAG
145  error "LinkLayer.AutoComplete: Auto-completion of PPPoE Frame is not supported."
146  }
147  0x88a8 -
148  0x9100 {
149  # --- VLAN TAG
150  error "LinkLayer.AutoComplete: Auto-completion of VLAN QinQ Frame is not supported."
151  }
152  default {
153  # --- Skipping Mac address resolution
154  # If we have e.g. a VLAN tag in the packet already
155  # do we have to resolve including the VLAN tag also?
156  # FIXME: We should fix this to the correct size, using the VLAN's upper layer payload size
157  #incr payloadLength [ expr $frameSize - $l3HeaderOffset ]
158  error "LinkLayer.AutoComplete: Auto-completion of Ethernet Frame (EtherType ${l2UlProtocol}) is not supported."
159  }
160  }
161  unset l3Data
162 
163  # --- Check existence of Layer 2.5 Protocols
164  set extraHeader ""
165  set extraHeaderSize 0
166 
167  # --- Prepending the Layer 2.5 to the previous layer 2.5 extensions
168  #
169  # `Layer2_5.Get` is deprecated => Process all types separately.
170  #
171  # Since VLAN cannot be added above PPPoE, we will first add all VLANs
172  # headers above the Ethernet header and add the PPPoE client(s) "on top" of them.
173  #
174  #
175  # --- Check if we have a PPPoE Protocol
176  set pppoeClients [ $bbPort Layer2_5.PPPoE.Get ]
177  for { set i [ expr [ llength $pppoeClients ] - 1 ]} { $i >= 0} { incr i -1} {
178  set pppoeClient [ lindex $pppoeClients $i ]
179  x.Print.Debug "Processing PPPoE Protocol ${pppoeClient} ([ lindex [ $pppoeClient Info -implements ] 0 ])."
180 
181  # --- Prepending the Layer 2.5 PPPoE headers to the previous layer 2.5 extensions
182  # Adding the PPPoE Header + PPP Header to the frame (8 Bytes)
183 
185  [ $pppoeClient SessionId.Get ] \
186  $payloadLength \
187  $l2UlProtocol ]
188 
189  set extraHeader "[ ::excentis::basic::Hex.To.String ${pppoeSessionHeader} ]${extraHeader}"
190 
191  # --- PPPoE Session Protocol
192  set l2UlProtocol 0x8864
193 
194  # --- The lower layer's payload will be 8 bytes longer
195  incr extraHeaderSize 8
196  incr payloadLength 8
197 
198  # --- Cleanup
199  unset pppoeSessionHeader
200  }
201 
202  # --- Check if we have VLAN Protocols
203  set vlans [ $bbPort Layer2_5.Vlan.Get ]
204  for { set i [ expr [ llength $vlans ] - 1 ]} { $i >= 0} { incr i -1} {
205  set vlanProtocol [ lindex $vlans $i ]
206  x.Print.Debug "Processing VLAN Protocol ${vlanProtocol} ([ lindex [ $vlanProtocol Info -implements ] 0 ])."
207 
208  # --- Prepending the Layer 2.5 VLAN header to the previous layer 2.5 extensions
209  # Adding VLAN tag to the frame (4 Bytes)
211  [ $vlanProtocol ID.Get ] \
212  [ $vlanProtocol Priority.Get ] \
213  [ $vlanProtocol DropEligible.Get ] \
214  [ $vlanProtocol Protocol.ID.Get ] ]
215 
216  set vlanExtraHeader [ ::excentis::basic::Hex.To.String [ lrange ${vlanTag} 2 end ] ]
217 
218  # --- Fill in the PPP header
219  #append vlanExtraHeader [ format "%04x" $l2UlProtocol ]
220  # Use extra sanity checks:
221  append vlanExtraHeader [ ::excentis::basic::Hex.To.String [ ::excentis::basic::Short.To.Hex $l2UlProtocol ] ]
222 
223  set extraHeader "${vlanExtraHeader}${extraHeader}"
224 
225  # --- VLAN Protocol ( C-TAG 0x8100 or S-TAG 0x88A8 )
226  #set l2UlProtocol [ ::excentis::basic::Hex.To.Short [ lrange ${vlanTag} 0 1 ] ]
227  set l2UlProtocol [ $vlanProtocol Protocol.ID.Get ]
228 
229  # --- Cleanup
230  unset vlanExtraHeader
231  unset vlanTag
232  }
233  # --- Cleanup
234  unset vlans
235 
236  # --- Create new data
237  if { ![ string equal $extraHeader "" ]} {
238  # --- Adding Layer 2.5 extension headers
239  set newFrameContentString [ string range $frameContentString 0 [ expr ( 2 * $l2TypeOffset ) - 1 ] ]
240  #append newFrameContentString [ format "%04x" $l2UlProtocol ]
241  # Use extra sanity checks:
242  append newFrameContentString [ ::excentis::basic::Hex.To.String [ ::excentis::basic::Short.To.Hex $l2UlProtocol ] ]
243  append newFrameContentString $extraHeader
244  append newFrameContentString [ string range $frameContentString [ expr ( 2 * $l3HeaderOffset ) ] end ]
245  incr frameSize $extraHeaderSize
246  } else {
247  # --- No Layer 2.5 extensions
248  set newFrameContentString $frameContentString
249  }
250 
251  # --- Cleanup
252  unset extraHeaderSize
253  unset extraHeader
254 
255  x.Print.Debug "LinkLayer.AutoComplete: NEW L2 (including L2.5) header data: {[ ::excentis::basic::String.To.Hex ${newFrameContentString} ]}"
256 
257  if { ![ string equal $resolveAddress "" ]} {
258  # --- Resolve the Ip address and overwrite the destination Mac address
259  x.Print.Debug "Resolving IP address '${resolveAddress}'."
260  set destinationMac [ $l3 Resolve $resolveAddress ]
261 # TODO: DEBUG
262 # set destinationMac [ $l3 Resolve.Async $resolveAddress ]
263 # puts "ASYNC MAC: '${destinationMac}'"
264 # set destinationMac [ $l3 Resolve $resolveAddress ]
265 # puts "SYNC MAC: '${destinationMac}'"
266 # set destinationMac [ $l3 Protocol.Arp.Async $resolveAddress ]
267 # puts "ASYNC ARP MAC: '${destinationMac}'"
268 # set destinationMac [ $l3 Protocol.Arp $resolveAddress ]
269 # puts "SYNC ARP MAC: '${destinationMac}'"
270 # TODO: END DEBUG
271 
272  # --- Cleanup
273  unset resolveAddress
274 
275  # --- Rewriting Destination Mac bytes
276  set newFrameContentString [ string replace $newFrameContentString 0 11 [ ::excentis::basic::Hex.To.String [ ::excentis::basic::Mac.To.Hex $destinationMac ] ] ]
277  }
278  catch { unset l3 }
279 
280  # --- Rewrite Source Mac Address
281  set l2 [ $bbPort Layer2.EthII.Get ]
282 
283  set sourceMac [ $l2 Mac.Get ]
284  set sourceMac [ ::excentis::basic::Mac.To.Hex $sourceMac ]
285 
286  set newFrameContentString [ string replace $newFrameContentString 12 23 [ ::excentis::basic::Hex.To.String [ ::excentis::basic::Mac.To.Hex $sourceMac ] ] ]
287 
288  x.Print.Debug "LinkLayer.AutoComplete: NEW Frame Content: {[ ::excentis::basic::String.To.Hex ${newFrameContentString} ]}"
289 
290  return ${newFrameContentString}
291 }
292 
293 
294 }
295 
296 }