<commit_before>-- Copyright 2012 Snabb GmbH
--
-- Ethernet switch module.
--
-- Packets are represented as tables with the following fields:
--   inputport = port the packet was received on
--   src, dst  = string representations of the ethernet src/dst addresses
--   length    = number of bytes of data
--   data      = pointer to memory buffer containing data

module("switch",package.seeall)

require("shm")

local ffi  = require("ffi")
local fabric = ffi.load("fabric")
local c    = require("c")
local port = require("port")
local medium = require("medium")
local C    = ffi.C

local tracefile = io.open("/tmp/switch.pcap", "w+")
pcap.write_file_header(tracefile)

-- Ethernet frame format

ffi.cdef[[
      struct ethh {
	 uint8_t  dst[6];
	 uint8_t  src[6];
	 uint16_t type;   // NOTE: Network byte order!
      } __attribute__ ((__packed__));
]]

-- Counters

-- Switch ports
--local ports = { port.new(1, "/tmp/a"),
--		port.new(2, "/tmp/b") }

-- local ports = { port.new(1), port.new(2), port.new(3) }

local ports = { [0] = port.Port:new(0, medium.Null),
		[1] = port.Port:new(1, medium.Null),
		[2] = port.Port:new(2, medium.Null),
		[3] = port.Port:new(3, medium.Null) }

local allports = { 0, 1, 2, 3}

-- testing data

local pcap_file   = ffi.new("struct pcap_file")
local pcap_record = ffi.new("struct pcap_record")
local pcap_extra  = ffi.new("struct pcap_record_extra")

-- Switch logic
local fdb = {} -- { MAC -> [Port] }

function main ()
   while true do
      -- print("Main loop")
      for _,port in ipairs(ports) do
	 local frame = port:receive()
	 if packet ~= nil then
	    local packet = makepacket(port, frame.data, frame.length)
	    input(packet)
	 end
      end
      C.usleep(100000)
   end
end

function testmain ()
   local testfile = arg[1]
   for data, header, extra in pcap.records(testfile) do
      if extra.flags == 0 then
	 local frame = ffi.cast("char *", data)
	 local packet = makepacket(extra.port_id, frame, header.orig_len)
	 input(packet)
      end
   end
end

function makepacket (inputport, data, length)
   return {inputport = inputport,
	   length    = length,
	   data      = data,
	   src       = ffi.string(data, 6),
	   dst       = ffi.string(data + 6, 6)}
end

-- Input a packet into the switching logic.
function input (packet)
   pcap.write_record(tracefile, packet.data, packet.length,
		     packet.inputport, true)
   fdb:update(packet)
   output(packet)
end

-- Output `eth' to the appropriate ports.
function output (packet)
   print("Sending packet to " .. #fdb:lookup(packet))
   for _,port in ipairs(fdb:lookup(packet)) do
      if port ~= packet.inputport then
	 if (ports[port]):transmit(packet) then
	    pcap.write_record(tracefile, packet.data, packet.length,
			      port, false)
	 else
	    print "TX overflow" end
      end
   end
end

-- Forwarding database

function fdb:update (packet)
   print("inputport = " .. tostring(packet.inputport))
   self[packet.src] = packet.inputport
end

function fdb:lookup (packet)
   local out = self[packet.dst]
   if out ~= nil and out ~= packet.inputport then
      return {out}
   else
      return allports
   end
end

testmain()
<commit_msg>switch.lua: More hacking and slashing.<commit_after>-- Copyright 2012 Snabb GmbH
--
-- Ethernet switch module.
--
-- Packets are represented as tables with the following fields:
--   inputport = port the packet was received on
--   src, dst  = string representations of the ethernet src/dst addresses
--   length    = number of bytes of data
--   data      = pointer to memory buffer containing data

module("switch",package.seeall)

require("shm")

local ffi  = require("ffi")
local fabric = ffi.load("fabric")
local c    = require("c")
local port = require("port")
local medium = require("medium")
local C    = ffi.C

local tracefile

function trace (filename)
   tracefile = io.open(filename, "w+")
   pcap.write_file_header(tracefile)
end

-- Ethernet frame format

ffi.cdef[[
      struct ethh {
	 uint8_t  dst[6];
	 uint8_t  src[6];
	 uint16_t type;   // NOTE: Network byte order!
      } __attribute__ ((__packed__));
]]

-- Counters

-- Switch ports
--local ports = { port.new(1, "/tmp/a"),
--		port.new(2, "/tmp/b") }

-- local ports = { port.new(1), port.new(2), port.new(3) }

local ports = { [0] = port.Port:new(0, medium.Null),
		[1] = port.Port:new(1, medium.Null),
		[2] = port.Port:new(2, medium.Null),
		[3] = port.Port:new(3, medium.Null) }

local allports = { 0, 1, 2, 3}

function addport(id, medium, ...)
   local port = port.Port:new(id, medium, ...)
   table.insert(ports, port)
   table.insert(allports, #allports - 1)
end

function getport(id)
   return ports[id]
end

-- testing data

local pcap_file   = ffi.new("struct pcap_file")
local pcap_record = ffi.new("struct pcap_record")
local pcap_extra  = ffi.new("struct pcap_record_extra")

-- Switch logic
local fdb = {} -- { MAC -> [Port] }

function main ()
   while true do
      -- print("Main loop")
      for _,port in ipairs(ports) do
	 local frame = port:receive()
	 if packet ~= nil then
	    local packet = makepacket(port, frame.data, frame.length)
	    input(packet)
	 end
      end
      C.usleep(100000)
   end
end

function testmain ()
   local testfile = arg[1]
   for data, header, extra in pcap.records(testfile) do
      if extra.flags == 0 then
	 local frame = ffi.cast("char *", data)
	 local packet = makepacket(extra.port_id, frame, header.orig_len)
	 input(packet)
      end
   end
end

function makepacket (inputport, data, length)
   return {inputport = inputport,
	   length    = length,
	   data      = data,
	   src       = ffi.string(data, 6),
	   dst       = ffi.string(data + 6, 6)}
end

function tracepacket (packet, direction)
   if tracefile then
      pcap.write_record(tracefile, packet.data, packet.length,
			packet.inputport, direction == "input")
   end
end

-- Input a packet into the switching logic.
function input (packet)
   tracepacket(packet, "input")
   fdb:update(packet)
   output(packet)
end

-- Output `eth' to the appropriate ports.
function output (packet)
   print("Sending packet to " .. #fdb:lookup(packet))
   for _,port in ipairs(fdb:lookup(packet)) do
      if port ~= packet.inputport then
	 if (ports[port]):transmit(packet) then
	    tracepacket(packet, "output")
	 else
	    print "TX overflow" end
      end
   end
end

-- Forwarding database

function fdb:update (packet)
   print("inputport = " .. tostring(packet.inputport))
   self[packet.src] = packet.inputport
end

function fdb:lookup (packet)
   local out = self[packet.dst]
   if out ~= nil and out ~= packet.inputport then
      return {out}
   else
      return allports
   end
end

-- testmain()

{'fraction_non_alphanumeric': 0.13106140219186307, 'fraction_numerical': 0.011559825851974178, 'mean_word_length': 3.077111383108935, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2532904', 'n_tokens_mistral': 2321, 'n_tokens_neox': 2218, 'n_words': 654}