// NOTE currently this is specific to the version of NetFPGA SUME we're using. override public ForwardingDecision process_packet(int in_port, ref Packet packet) { // Set metadata. NetFPGA_Data dataplane = instance.Get_Data(); NetFPGA.Set_Input_Port(ref dataplane, (ulong)in_port); Debug.Assert(in_port == (int)NetFPGA.Read_Input_Port(dataplane)); byte[] bs = packet.Bytes; NetFPGA.Set_Frame(bs, ref dataplane); instance.Set_Data(dataplane); // Run the logic! instance.SwitchLogic(); dataplane = instance.Get_Data(); // Retrieve frame. bs = new byte[NetFPGA_Data.BUF_SIZE * sizeof(ulong)]; NetFPGA.Get_Frame(dataplane, ref bs); // NOTE assuming Ethernet link layer. packet = Packet.ParsePacket(LinkLayers.Ethernet, bs); // Retrieve forwarding decision. int[] outs = new int[NetFPGA_Data.NET_PORTS]; int outputs = NetFPGA.Get_Output_Ports(ref dataplane, ref outs, max_ports: PaxConfig_Lite.no_interfaces); ForwardingDecision fwd = null; // Trim away unused array space. Array.Resize <int>(ref outs, outputs); fwd = new ForwardingDecision.MultiPortForward(outs); return(fwd); }
/*FIXME would like to do this to push the compiler to inline as much as it can, * but this annotation seems to require .NET 4.5: * [MethodImpl(MethodImplOptions.AggressiveInlining)]*/ override public void Apply(ref NetFPGA_Data dataplane) { bool dstmac_lut_hit = false; bool srcmac_lut_exist = false; ulong lut_element_op = 0; // Output port // Get the destination MAC from the buffer. ulong dst_mac = dataplane.tdata.Destination_MAC(); //We structure "srcmac_port" as follows: src_mac_hi | src_mac_low | src_port; ulong srcmac_port = (dataplane.tdata.Source_MAC() << 16) | ((dataplane.tuser_low[0] >> 16) & 0xff); Kiwi.Pause(); // Once we have the destination MAC, check if it exists in the LUT. // We will later set the appropriate metadata into the tuser field accordingly. // We also check if the source MAC is in our LUT. If it isn't then we will // later add it, to map to the source port number. // FIXME how to make an API that can be backed by a CAM rather than this loop for look-up? foreach (ulong lut_element in LUT) { // Get the mac address from LUT ulong lut_element_mac = lut_element.Extract_Bytes(length: 6); // Get the output port from LUT lut_element_op = lut_element.Extract_Bytes(from_byte: 6, length: 2); Kiwi.Pause(); if (!dstmac_lut_hit && lut_element_mac == dst_mac) { dstmac_lut_hit = true; } if (!srcmac_lut_exist && srcmac_port == lut_element) { srcmac_lut_exist = true; } } Kiwi.Pause(); // If the frame does not contain an IPv4 packet then we do not set its // output port; this implicitly drops the frame. if (dataplane.tdata.EtherType_Is(Ethernet.EtherTypes.IPv4)) { // Configure the metadata such that if we have a hit then set the appropriate output // port in the metadata, otherwise broadcast. if (dstmac_lut_hit) { NetFPGA.Set_Output_Port(ref dataplane, lut_element_op); } else { NetFPGA.Broadcast(ref dataplane); } } Kiwi.Pause(); // Add source MAC to our LUT if it's not already there, thus the switch "learns". if (!srcmac_lut_exist) { LUT[free] = srcmac_port; free = (free > (LUT_SIZE - 1)) ? 0 : free++; } }
/*FIXME would like to do this to push the compiler to inline as much as it can, * but this annotation seems to require .NET 4.5: * [MethodImpl(MethodImplOptions.AggressiveInlining)]*/ override public void Apply(ref NetFPGA_Data dataplane) { bool lut_hit = false; ulong lut_element_op = 0; // Output port ulong tmp = 0; // Get the destination MAC from the buffer. ulong dst_mac = dataplane.tdata.Destination_MAC(); // Once we have the destination MAC, check if it exists in the LUT. // We will later set the appropriate metadata into the tuser field accordingly. foreach (ulong lut_element in LUT) { // Get the mac address from LUT ulong lut_element_mac = lut_element.Extract_Bytes(length: 6); /*LUT[i] & (ulong)0xffffffffffff0000;*/ // Get the output port from LUT lut_element_op = lut_element.Extract_Bytes(from_byte: 6, length: 2); /*LUT[i] & (ulong)0x000000000000ffff*/ Kiwi.Pause(); if (lut_element_mac == dst_mac) { lut_hit = true; break; } } Kiwi.Pause(); // If the frame does not contain an IPv4 packet then we do not set its // output port; this implicitly drops the frame. if (dataplane.tdata.EtherType_Is(Ethernet.EtherTypes.IPv4)) { // Configure the metadata such that if we have a hit then set the appropriate output // port in the metadata, otherwise broadcast. if (lut_hit) { NetFPGA.Set_Output_Port(ref dataplane, lut_element_op); } else { NetFPGA.Broadcast(ref dataplane); } } Kiwi.Pause(); // Check if the source MAC is in our LUT. If it isn't then add it, // to map to the source port number. //We structure "tmp" as follows: src_mac_hi | src_mac_low | src_port; tmp = (dataplane.tdata.Source_MAC() << 16) | ((dataplane.tuser_low[0] >> 16) & 0xff); Kiwi.Pause(); // Check if we need to store a new entry into the LUT if (!lut_hit) { #if Kiwi_Extension // NOTE the Kiwi interpretation of IndexOf might need to insert hard pauses. bool exist = Array.IndexOf(LUT, tmp) > -1 ? true : false; #else bool exist = false; foreach (ulong element in LUT) { Kiwi.Pause(); // Get rid off the oq, keep only the mac if (tmp == element) { exist = true; break; } } #endif if (!exist) { LUT[free] = tmp; free = (free > (LUT_SIZE - 1)) ? 0 : free++; } } }