/// <summary> /// Transforms a raw frame (i.e., byte sequence) into the abstraction we use for NetFPGA's data+metadata, and sets in the input port metadata to a specific port number. /// </summary> /// <param name="tdata_e">The raw frame data</param> /// <param name="intfNumber">The 0-based port number the frame is arriving on</param> /// <remarks> /// Note that this involves copying the data (into a ulong array). /// </remarks> public static NetFPGA_Data CreateData(IEnumerable <byte> tdata_e, int intfNumber) { var d = new NetFPGA_Data(); var tdata_b = tdata_e.ToArray(); var length = (int)Math.Ceiling(tdata_b.Length / 8.0); Buffer.BlockCopy(tdata_b, 0, d.tdata, 0, tdata_b.Length); var tkeep = Enumerable.Repeat((byte)0xff, length - 1).Append((byte)~(~0 << tdata_b.Length % 8)).ToArray(); Array.Copy(tkeep, d.tkeep, tkeep.Length); var tlast = Enumerable.Repeat(false, length - 1).Append(true).ToArray(); Array.Copy(tlast, d.tlast, tlast.Length); var tuser_hi = Enumerable.Repeat(0uL, length).ToArray(); Array.Copy(tuser_hi, d.tuser_hi, tuser_hi.Length); var tuser_low = Enumerable.Repeat(((1uL << (intfNumber * 2)) << 16) | (byte)tdata_b.Length, length).ToArray(); Array.Copy(tuser_low, d.tuser_low, tuser_low.Length); return(d); }
/// <summary> /// Update the metadata to broadcast the frame (to all ports except the /// one that the frame was received on). /// </summary> public static void Broadcast(ref NetFPGA_Data dataplane) { ulong broadcast_ports = ((dataplane.tuser_low[0] ^ NetFPGA_Data.default_oqs) >> 8) << 16 | dataplane.tuser_low[0]; dataplane.tuser_low[0] = (ulong)(broadcast_ports | dataplane.tuser_low[0]); return; }
/// <summary> /// Set the output port to a specific value. /// (i.e., the port to which we are forwarding the frame.) /// </summary> public static void Set_Output_Port(ref NetFPGA_Data dataplane, ulong value) { // FIXME we currently don't one-hot encode "value" value = value << NetFPGA_Data.tuser_low_destination_port; dataplane.tuser_low[0] = (ulong)(value | dataplane.tuser_low[0]); return; }
// Extract the frame from NetFPGA_Data into a byte array. public static void Get_Frame(NetFPGA_Data src, ref byte[] dst) { // FIXME we don't check the bounds of dst. // FIXME we don't null unused locations in dst. int offset = 0; for (int i = 0; i < src.tdata.Length; i++) { byte[] bs = BitConverter.GetBytes(src.tdata[i]); for (int j = 0; j < bs.Length; j++) { if (src.tlast[i] && NetFPGA.to_keep(src, i) > j) { break; } dst[offset] = bs[j]; offset++; } if (src.tlast[i]) { break; } } }
/// <summary> /// Read the output ports that are currently set in the metadata. /// (i.e., the port(s) to which we are forwarding the frame.) /// </summary> public static byte Get_Output_Ports(ref NetFPGA_Data dataplane, ref int[] output_ports, int?max_ports = null) { ulong value = dataplane.tuser_low[0]; value = (value >> NetFPGA_Data.tuser_low_destination_port); bool nf0 = (value & 0x01L) > 0; bool nf1 = (value & 0x04L) > 0; bool nf2 = (value & 0x10L) > 0; bool nf3 = (value & 0x40L) > 0; // FIXME code in this function is a bit dirty -- can be tidied up? byte dim = 0; if (nf0) { dim++; } if (nf1 && max_ports.HasValue && max_ports.Value > 1) { dim++; } if (nf2 && max_ports.HasValue && max_ports.Value > 2) { dim++; } if (nf3 && max_ports.HasValue && max_ports.Value > 3) { dim++; } Debug.Assert(dim == output_ports.Length); int i = 0; if (nf0) { output_ports[i] = 0; i++; } if (nf1) { output_ports[i] = 1; i++; } if (nf2) { output_ports[i] = 2; i++; } if (nf3) { output_ports[i] = 3; i++; } return(dim); }
// This method describes the operations required to rx a frame over the AXI4-Stream. // and extract basic information such as dst_MAC, src_MAC, dst_port, src_port protected static uint ReceiveFrame() { var frame = FrameController.ReceiveFrame(); dataplane = frame.Data; uint size = (uint)Math.Min(dataplane.tdata.Length, dataplane.tlast.TakeWhile(x => !x).Count() + 1); // Length of frame in ulongs return(size); }
public static NetFPGA_Data DeepClone(this NetFPGA_Data src) { var r = new NetFPGA_Data(); Array.Copy(src.tdata, r.tdata, src.tdata.Length); Array.Copy(src.tkeep, r.tkeep, src.tkeep.Length); Array.Copy(src.tlast, r.tlast, src.tlast.Length); Array.Copy(src.tuser_hi, r.tuser_hi, src.tuser_hi.Length); Array.Copy(src.tuser_low, r.tuser_low, src.tuser_low.Length); return(r); }
/// <summary> /// Send a frame. Uses the network interface specified by the supplied metadata. /// </summary> /// <param name="data">The data of the frame to send.</param> public void SendFrame(NetFPGA_Data data) { // Use the current timestamp for this frame var frame = new FrameInfo(data, sw.Elapsed); // Notify listeners of frame being sent OnSendFrame?.Invoke(this, new FrameEventArgs(frame, sw.Elapsed)); // Log that the frame was sent _SentFrames.Add(frame); }
/// <summary> /// Converts the data (<see cref="NetFPGA_Data.tdata"/>) into a binary string, with a title, /// and each ulong on a new line. /// </summary> public static string ToBinaryString(this NetFPGA_Data d) { StringBuilder sb = new StringBuilder(); sb.AppendLine("tdata:"); for (int i = 0; i < d.tdata.Length && !d.tlast[i]; i++) { sb.Append(" "); sb.AppendLine(d.tdata[i].ToBinaryString()); } return(sb.ToString()); }
/// <summary> /// Converts the data (<see cref="NetFPGA_Data.tdata"/>) into a hex string, with a title, /// and each ulong on a new line. /// </summary> public static string ToHexString(this NetFPGA_Data d) { StringBuilder sb = new StringBuilder(); sb.AppendLine("tdata:"); for (int i = 0; i < d.tdata.Length; i++) { sb.Append(" "); sb.AppendLine(d.tdata[i].ToString("X16")); if (d.tlast[i]) { break; } } return(sb.ToString()); }
public static void Write48(this NetFPGA_Data dataplane, ulong v, int offset) { int index64 = offset / 8; int offset1 = offset % 8 * 8; ulong data1 = v << offset1; ulong mask1 = ~(0x0000FFFFFFFFFFFFuL << offset1); dataplane.tdata[index64] = (dataplane.tdata[index64] & mask1) | data1; index64++; offset1 = 64 - offset1; ulong data2 = offset1 >= 64 ? 0 : v >> offset1; ulong mask2 = offset1 >= 64 ? ~0uL : ~(0x0000FFFFFFFFFFFFuL >> offset1); dataplane.tdata[index64] = (dataplane.tdata[index64] & mask2) | data2; }
// Move the contents of a byte array into the frame field in NetFPGA_Data. public static void Set_Frame(byte[] src, ref NetFPGA_Data dst) { // If not ulong (8-byte) aligned then we indicate this using // NetFPGA_Data.tkeep. We indicate the end of the frame by setting // NetFPGA_Data.tlast. int i = 0; int max = dst.tdata.Length / sizeof(ulong); byte[] buf = new byte[sizeof(long)]; for (i = 0; i < max; i++) { for (int j = 0; j < sizeof(long); j++) { buf[j] = src[i + j]; } dst.tdata[i * sizeof(long)] = BitConverter.ToUInt32(buf, 0); dst.tlast[i] = false; } // Now we handle the last word. dst.tlast[i] = true; byte to_keep = (byte)(dst.tdata.Length % sizeof(ulong)); dst.tkeep[i] = one_hot_encode(to_keep); // Copy remaining bytes. int k = 0; for (k = 0; k < to_keep; k++) { buf[k] = src[i + k]; } // Zero-out the bytes until the word boundary. for (; k < sizeof(ulong); k++) { buf[k] = 0; } dst.tdata[i * sizeof(long)] = BitConverter.ToUInt32(buf, 0); }
/// <summary> /// Read the input port (i.e., port on which we received the frame). /// </summary> public static uint Read_Input_Port(NetFPGA_Data dataplane) { uint encoded_in_port = (uint)(dataplane.tuser_low[0] >> NetFPGA_Data.tuser_low_source_port); encoded_in_port &= 0x00FF; // Zero out the destination port. uint in_port = 0; while ((encoded_in_port & 1) == 0) { in_port++; encoded_in_port = encoded_in_port >> 2; } // "in_port" indicates network port index, starting with 0. Debug.Assert(in_port < NetFPGA_Data.NET_PORTS); return(in_port); }
// Extract how many bytes we are keeping from a given (8 byte) segment as // identified by an offset. // This involves looking up the tkeep[offset] value and carrying out // the one-hot decoding. // NOTE we expect that the bits indicating which bits to keep are // contiguous. We currently don't check this. public static int to_keep(NetFPGA_Data src, int offset) { byte tkeep = src.tkeep[offset]; int keeping = 0; const int bits_in_a_byte = 8; for (int i = 0; i < bits_in_a_byte; i++) { tkeep = (byte)(tkeep >> i); if ((tkeep & 0x1) == 1) { keeping++; } else { break; } } return(keeping); }
/// <summary> /// Set the input port (i.e., port on which we received the frame). /// </summary> public static void Set_Input_Port(ref NetFPGA_Data dataplane, ulong value) { // "value" indicates network port index, starting with 0. Debug.Assert(value < NetFPGA_Data.NET_PORTS); // Map value into a bit-based encoding as described for source/destination // ports in NetFPGA_Data. ulong encoded_in_port = 1; for (int i = (int)value; i > 0; i--) { encoded_in_port = encoded_in_port << 2; } // Move into position, in preparation for OR-ing. encoded_in_port = encoded_in_port << NetFPGA_Data.tuser_low_source_port; // Erase any existing input port. dataplane.tuser_low[0] = (ulong)(0xFF00FFFF & dataplane.tuser_low[0]); // Write the new input port. dataplane.tuser_low[0] = (ulong)(encoded_in_port | dataplane.tuser_low[0]); }
public FrameInfo(NetFPGA_Data data, TimeSpan time) { Data = data; Time = time; }
abstract public void Set_Data(NetFPGA_Data data);