@@ -7,7 +7,7 @@ import { Position } from "../common";
77import { IpAddress , IPv4Packet } from "../../packets/ip" ;
88import { DeviceId , NetworkInterfaceData } from "../graphs/datagraph" ;
99import { Texture , Ticker } from "pixi.js" ;
10- import { EthernetFrame } from "../../packets/ethernet" ;
10+ import { EthernetFrame , MacAddress } from "../../packets/ethernet" ;
1111import { GlobalContext } from "../../context" ;
1212import { DataRouter } from "../data-devices" ;
1313import { dropPacket , sendViewPacket } from "../packet" ;
@@ -171,17 +171,18 @@ export class ViewRouter extends ViewNetworkDevice {
171171 this . handleDatagram ( datagram , iface ) ;
172172 return ;
173173 }
174- this . addPacketToQueue ( datagram ) ;
174+ this . addPacketToQueue ( datagram , iface ) ;
175175 }
176176
177- addPacketToQueue ( datagram : IPv4Packet ) {
177+ addPacketToQueue ( datagram : IPv4Packet , iface : number ) {
178178 const wasEmpty = this . packetQueue . isEmpty ( ) ;
179179 datagram . timeToLive -= 1 ;
180180 if ( datagram . timeToLive <= 0 ) {
181181 console . debug ( `Device ${ this . id } dropped packet with TTL 0` ) ;
182182 this . dropPacket ( datagram ) ;
183+ return ;
183184 }
184- if ( ! this . packetQueue . enqueue ( datagram ) ) {
185+ if ( ! this . packetQueue . enqueue ( datagram , iface ) ) {
185186 console . debug ( "Packet queue full, dropping packet" ) ;
186187 this . showDeviceIconFor ( "queueFull" , "❗" , "Queue full" ) ;
187188 this . dropPacket ( datagram ) ;
@@ -201,10 +202,11 @@ export class ViewRouter extends ViewNetworkDevice {
201202
202203 processPacket ( ticker : Ticker ) {
203204 const elapsedTime = ticker . deltaMS * this . viewgraph . getSpeed ( ) ;
204- const datagram = this . getPacketsToProcess ( elapsedTime ) ;
205- if ( ! datagram ) {
205+ const packetWithIface = this . getPacketsToProcess ( elapsedTime ) ;
206+ if ( ! packetWithIface ) {
206207 return ;
207208 }
209+ const datagram = packetWithIface . packet ;
208210
209211 const iface = this . routePacket ( datagram ) ;
210212
@@ -215,18 +217,67 @@ export class ViewRouter extends ViewNetworkDevice {
215217 dstDevice ?. id ,
216218 this . viewgraph ,
217219 ) ;
218- if ( forwardingData && forwardingData . sendingIface === iface ) {
220+ if ( forwardingData ) {
219221 const { src, nextHop } = forwardingData ;
220-
221- const newFrame = new EthernetFrame ( src . mac , nextHop . mac , datagram ) ;
222+ let nextHopMac : MacAddress ;
223+ if ( forwardingData . sendingIface === iface ) {
224+ nextHopMac = nextHop . mac ;
225+ } else {
226+ // Try to deduce next hop from the routing table
227+ // If the interface connects to a router, just send it
228+ nextHopMac = this . deduceNextHopMac ( datagram , iface ) ;
229+ if ( ! nextHopMac ) {
230+ return ;
231+ }
232+ }
233+ const newFrame = new EthernetFrame ( src . mac , nextHopMac , datagram ) ;
222234 sendViewPacket ( this . viewgraph , this . id , newFrame , iface ) ;
223- } else console . debug ( `Router ${ this . id } could not forward packet.` ) ;
235+ } else {
236+ console . debug ( `Router ${ this . id } could not forward packet.` ) ;
237+ }
224238
225239 if ( this . packetQueue . isEmpty ( ) ) {
226240 this . stopPacketProcessor ( ) ;
227241 }
228242 }
229243
244+ private deduceNextHopMac ( datagram : IPv4Packet , iface : number ) : MacAddress {
245+ const connections = this . viewgraph
246+ . getDataGraph ( )
247+ . getConnectionsInInterface ( this . id , iface ) ;
248+ if ( connections . length === 0 ) {
249+ console . warn (
250+ `Device ${ this . id } has no connections in interface ${ iface } , dropping packet` ,
251+ ) ;
252+ this . dropPacket ( datagram ) ;
253+ return ;
254+ }
255+ const nextHopId = connections [ 0 ] ;
256+ const edge = this . viewgraph . getEdge ( this . id , nextHopId ) ;
257+ if ( ! edge ) {
258+ console . error ( `Edge ${ this . id } has no edge to next hop ${ nextHopId } ` ) ;
259+ return ;
260+ }
261+ const nextHopIface = edge . getDeviceInterface ( nextHopId ) ;
262+ if ( nextHopIface === undefined ) {
263+ console . error (
264+ `Edge ${ this . id } has no interface for next hop ${ nextHopId } ` ,
265+ ) ;
266+ return ;
267+ }
268+ const nextHop = this . viewgraph . getDevice ( nextHopId ) ;
269+ if ( ! nextHop ) {
270+ console . error ( `Next hop ${ nextHopId } not found` ) ;
271+ return ;
272+ }
273+ if ( ! ( nextHop instanceof ViewNetworkDevice ) ) {
274+ console . error ( `Next hop ${ nextHopId } is not a network device` ) ;
275+ this . dropPacket ( datagram ) ;
276+ return ;
277+ }
278+ return nextHop . interfaces [ nextHopIface ] . mac ;
279+ }
280+
230281 startPacketProcessor ( ) {
231282 this . processingProgress = 0 ;
232283 Ticker . shared . add ( this . processPacket , this ) ;
@@ -237,9 +288,9 @@ export class ViewRouter extends ViewNetworkDevice {
237288 Ticker . shared . remove ( this . processPacket , this ) ;
238289 }
239290
240- getPacketsToProcess ( timeMs : number ) : IPv4Packet | null {
291+ getPacketsToProcess ( timeMs : number ) : PacketWithIface | null {
241292 this . processingProgress += ( this . bytesPerSecond * timeMs ) / 1000 ;
242- const packetLength = this . packetQueue . getHead ( ) ?. totalLength ;
293+ const packetLength = this . packetQueue . getHead ( ) ?. packet ?. totalLength ;
243294 if ( this . processingProgress < packetLength ) {
244295 return null ;
245296 }
@@ -271,8 +322,19 @@ export class ViewRouter extends ViewNetworkDevice {
271322 }
272323}
273324
325+ /**
326+ * A packet with the interface it was received on.
327+ * This is used to keep track of which interface the packet was received on
328+ * when it is enqueued in the packet queue.
329+ */
330+ interface PacketWithIface {
331+ packet : IPv4Packet ;
332+ iface : number ;
333+ }
334+
274335class PacketQueue {
275- private queue : IPv4Packet [ ] = [ ] ;
336+ // Queue of packets with the interface they were received on
337+ private queue : PacketWithIface [ ] = [ ] ;
276338 private queueSizeBytes = 0 ;
277339 private maxQueueSizeBytes : number ;
278340
@@ -308,27 +370,27 @@ class PacketQueue {
308370 }
309371 }
310372
311- enqueue ( packet : IPv4Packet ) {
373+ enqueue ( packet : IPv4Packet , iface : number ) {
312374 if ( this . queueSizeBytes + packet . totalLength > this . maxQueueSizeBytes ) {
313375 return false ;
314376 }
315- this . queue . push ( packet ) ;
377+ this . queue . push ( { packet, iface } ) ;
316378 this . queueSizeBytes += packet . totalLength ;
317379 this . notifyObservers ( ) ;
318380 return true ;
319381 }
320382
321- dequeue ( ) : IPv4Packet | undefined {
383+ dequeue ( ) : PacketWithIface | undefined {
322384 if ( this . queue . length === 0 ) {
323385 return ;
324386 }
325- const packet = this . queue . shift ( ) ;
387+ const { packet, iface } = this . queue . shift ( ) ;
326388 this . queueSizeBytes -= packet . totalLength ;
327389 this . notifyObservers ( ) ;
328- return packet ;
390+ return { packet, iface } ;
329391 }
330392
331- getHead ( ) : IPv4Packet | undefined {
393+ getHead ( ) : PacketWithIface | undefined {
332394 return this . queue [ 0 ] ;
333395 }
334396
0 commit comments