<commit_before>---------------------------------
--- @file packet.lua
--- @brief Utility functions for packets (rte_mbuf).
--- Includes:
--- - General functions (timestamping, rate control, ...)
--- - Offloading
--- - Create packet types
---------------------------------

local ffi = require "ffi"

require "utils"
require "headers"
local dpdkc = require "dpdkc"
local dpdk = require "dpdk"
local log = require "log"
local colors = require "colors"

local bor, band, bnot, rshift, lshift= bit.bor, bit.band, bit.bnot, bit.rshift, bit.lshift
local istype = ffi.istype
local write = io.write


-------------------------------------------------------------------------------------------
---- General functions
-------------------------------------------------------------------------------------------

--- Module for packets (rte_mbuf)
local pkt = {}
pkt.__index = pkt


--- Get a void* pointer to the packet data.
function pkt:getData()
	return ffi.cast("void*", ffi.cast("uint8_t*", self.buf_addr) + self.data_off)
end

function pkt:getBytes()
	return ffi.cast("uint8_t*", self.buf_addr) + self.data_off
end

function pkt:getTimesync()
	return self.timesync
end

--- Retrieve the time stamp information.
--- @return The timestamp or nil if the packet was not time stamped.
function pkt:getTimestamp()
	if bit.bor(self.ol_flags, dpdk.PKT_RX_IEEE1588_TMST) ~= 0 then
		-- TODO: support timestamps that are stored in registers instead of the rx buffer
		local data = ffi.cast("uint32_t* ", self:getData())
		-- TODO: this is only tested with the Intel 82580 NIC at the moment
		-- the datasheet claims that low and high are swapped, but this doesn't seem to be the case
		-- TODO: check other NICs
		local low = data[2]
		local high = data[3]
		return high * 2^32 + low
	end
end

--- Check if the PKT_RX_IEEE1588_TMST flag is set.
--- Turns out that this flag is pretty pointless, it does not indicate
--- if the packet was actually timestamped, just that it came from a
--- queue/filter with timestamping enabled.
--- You probably want to use device:hasTimestamp() and check the sequence number.
function pkt:hasTimestamp()
	return bit.bor(self.ol_flags, dpdk.PKT_RX_IEEE1588_TMST) ~= 0
end

function pkt:getSecFlags()
	local secp = bit.rshift(bit.band(self.ol_flags, dpdk.PKT_RX_IPSEC_SECP), 11)
	local secerr = bit.rshift(bit.band(self.ol_flags, bit.bor(dpdk.PKT_RX_SECERR_MSB, dpdk.PKT_RX_SECERR_LSB)), 12)
	return secp, secerr
end

--- Offload VLAN tagging to the NIC for this packet.
function pkt:setVlan(vlan, pcp, cfi)
	local tci = vlan + bit.lshift(pcp or 0, 13) + bit.lshift(cfi or 0, 12)
	self.vlan_tci = tci
	self.ol_flags = bit.bor(self.ol_flags, dpdk.PKT_TX_VLAN_PKT)
end

local VLAN_VALID_MASK = bit.bor(dpdk.PKT_RX_VLAN_PKT, dpdk.PKT_TX_VLAN_PKT)

--- Get the VLAN associated with a received packet.
function pkt:getVlan()
	if bit.bor(self.ol_flags, VLAN_VALID_MASK) == 0 then
		return nil
	end
	local tci = self.vlan_tci
	return bit.band(tci, 0xFFF), bit.rshift(tci, 13), bit.band(bit.rshift(tci, 12), 1)
end

function pkt:getSoftwareRxTimestamp(offs)
	log:fatal("requires DPDK 2.x, use old API for now")
end

--- Set the time to wait before the packet is sent for software rate-controlled send methods.
--- @param delay The time to wait before this packet \(in bytes, i.e. 1 == 0.8 nanoseconds on 10 GbE\)
function pkt:setDelay(delay)
	self.hash.rss = delay
end

--- @todo TODO docu
function pkt:setRate(rate)
	self.hash.rss = 10^10 / 8 / (rate * 10^6) - self.pkt_len - 24
end

--- @todo TODO does
function pkt:setSize(size)
	self.pkt_len = size
	self.data_len = size
end

function pkt:getSize()
	return self.pkt_len
end

--- Returns the packet data cast to the best fitting packet struct. 
--- Starting with ethernet header.
--- @return packet data as cdata of best fitting packet
function pkt:get()<commit_msg>remove moongen-specific methods<commit_after>---------------------------------
--- @file packet.lua
--- @brief Utility functions for packets (rte_mbuf).
--- Includes:
--- - General functions (timestamping, rate control, ...)
--- - Offloading
--- - Create packet types
---------------------------------

local ffi = require "ffi"

require "utils"
require "headers"
local dpdkc = require "dpdkc"
local dpdk = require "dpdk"
local log = require "log"
local colors = require "colors"

local bor, band, bnot, rshift, lshift= bit.bor, bit.band, bit.bnot, bit.rshift, bit.lshift
local istype = ffi.istype
local write = io.write


-------------------------------------------------------------------------------------------
---- General functions
-------------------------------------------------------------------------------------------

--- Module for packets (rte_mbuf)
local pkt = {}
pkt.__index = pkt


--- Get a void* pointer to the packet data.
function pkt:getData()
	return ffi.cast("void*", ffi.cast("uint8_t*", self.buf_addr) + self.data_off)
end

function pkt:getBytes()
	return ffi.cast("uint8_t*", self.buf_addr) + self.data_off
end

function pkt:getTimesync()
	return self.timesync
end

--- Retrieve the time stamp information.
--- @return The timestamp or nil if the packet was not time stamped.
function pkt:getTimestamp()
	if bit.bor(self.ol_flags, dpdk.PKT_RX_IEEE1588_TMST) ~= 0 then
		-- TODO: support timestamps that are stored in registers instead of the rx buffer
		local data = ffi.cast("uint32_t* ", self:getData())
		-- TODO: this is only tested with the Intel 82580 NIC at the moment
		-- the datasheet claims that low and high are swapped, but this doesn't seem to be the case
		-- TODO: check other NICs
		local low = data[2]
		local high = data[3]
		return high * 2^32 + low
	end
end

--- Check if the PKT_RX_IEEE1588_TMST flag is set.
--- Turns out that this flag is pretty pointless, it does not indicate
--- if the packet was actually timestamped, just that it came from a
--- queue/filter with timestamping enabled.
--- You probably want to use device:hasTimestamp() and check the sequence number.
function pkt:hasTimestamp()
	return bit.bor(self.ol_flags, dpdk.PKT_RX_IEEE1588_TMST) ~= 0
end

function pkt:getSecFlags()
	local secp = bit.rshift(bit.band(self.ol_flags, dpdk.PKT_RX_IPSEC_SECP), 11)
	local secerr = bit.rshift(bit.band(self.ol_flags, bit.bor(dpdk.PKT_RX_SECERR_MSB, dpdk.PKT_RX_SECERR_LSB)), 12)
	return secp, secerr
end

--- Offload VLAN tagging to the NIC for this packet.
function pkt:setVlan(vlan, pcp, cfi)
	local tci = vlan + bit.lshift(pcp or 0, 13) + bit.lshift(cfi or 0, 12)
	self.vlan_tci = tci
	self.ol_flags = bit.bor(self.ol_flags, dpdk.PKT_TX_VLAN_PKT)
end

local VLAN_VALID_MASK = bit.bor(dpdk.PKT_RX_VLAN_PKT, dpdk.PKT_TX_VLAN_PKT)

--- Get the VLAN associated with a received packet.
function pkt:getVlan()
	if bit.bor(self.ol_flags, VLAN_VALID_MASK) == 0 then
		return nil
	end
	local tci = self.vlan_tci
	return bit.band(tci, 0xFFF), bit.rshift(tci, 13), bit.band(bit.rshift(tci, 12), 1)
end


--- @todo TODO does
function pkt:setSize(size)
	self.pkt_len = size
	self.data_len = size
end

function pkt:getSize()
	return self.pkt_len
end

--- Returns the packet data cast to the best fitting packet struct. 
--- Starting with ethernet header.
--- @return packet data as cdata of best fitting packet
function pkt:get()
{'fraction_non_alphanumeric': 0.1740216486261449, 'fraction_numerical': 0.014709963918956424, 'mean_word_length': 2.8705692803437164, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '2431380', 'n_tokens_mistral': 2505, 'n_tokens_neox': 2404, 'n_words': 783}