aboutsummaryrefslogtreecommitdiff
path: root/03-switch3.rb
diff options
context:
space:
mode:
authorNat Lasseter <user@4574.co.uk>2024-05-08 14:23:26 +0100
committerNat Lasseter <user@4574.co.uk>2024-05-08 14:23:26 +0100
commit9a947b32a74e5f2866f12d9552e1265c3e3650a6 (patch)
tree4795d3923d9908e489e1355bd37ecdaf8bdb8602 /03-switch3.rb
parente796ea2d6d3aabe84ff165d8be110506482f895d (diff)
Demo ends. For now...
Diffstat (limited to '03-switch3.rb')
-rw-r--r--03-switch3.rb61
1 files changed, 61 insertions, 0 deletions
diff --git a/03-switch3.rb b/03-switch3.rb
new file mode 100644
index 0000000..7cbdc2f
--- /dev/null
+++ b/03-switch3.rb
@@ -0,0 +1,61 @@
+require './level'
+require './frame2'
+
+$levels << Level.new do
+ @interfaces = %w(1 2 3)
+ @description = <<~EOD
+ You are now a three-port switch.
+ When a frame comes in on a port, you should keep track of the source address,
+ and any frames destined for that address in future clicks should only be
+ forwarded to that port. All other frames should be broadcast as before.
+ EOD
+ @clicks = 8
+
+ @fib = @interfaces.product([nil]).to_h
+ @next_fib = @fib.dup
+
+ def target(frame)
+ ifib = @fib.invert
+ if ifib.keys.include?(frame.dst_addr)
+ [frame.to(ifib[frame.dst_addr])]
+ else
+ case frame.iface
+ when ?1
+ [frame.to(?2), frame.to(?3)]
+ when ?2
+ [frame.to(?1), frame.to(?3)]
+ when ?3
+ [frame.to(?1), frame.to(?2)]
+ else
+ []
+ end
+ end
+ end
+
+ def generate
+ frames = {}
+ @interfaces.each do |iface|
+ next if rand < 0.3
+
+ if rand < 0.4 || @fib[iface].nil?
+ src = Frame2.gen_addr
+ @next_fib[iface] = src
+ else
+ src = @fib[iface]
+ end
+
+ dst = nil
+ dst = (@fib.values.compact - [src]).sample if rand < 0.5
+ dst = Frame2.gen_addr if dst.nil?
+
+ frames[@count.to_s] = Frame2.new(iface, src, dst)
+ @count += 1
+ end
+ frames
+ end
+
+ def click
+ @fib = @next_fib
+ @next_fib = @fib.dup
+ end
+end