Using eBPF in dpdk - dpdk

Sorry for some basic question. I understand eBPF in kernel context and use of bpf() system call or helper libraries. How are hooks created in dpdk ? How do we load eBPF code into an already running dpdk application ? I want to have dpdk process expose hooks at multiple places and want to load bpf to dump packets or print stats. I couldn't find all answers or examples of such real world scenarios.
I have gone through the dpdk examples and code implementation but couldn't get the details to actually write an app

The DPDK API for its eBPF module offers the following generic functions:
struct rte_bpf *rte_bpf_load(const struct rte_bpf_prm *prm);
struct rte_bpf *rte_bpf_elf_load(const struct rte_bpf_prm *prm, const char *fname, const char *sname);
void rte_bpf_destroy(struct rte_bpf *bpf);
uint64_t rte_bpf_exec(const struct rte_bpf *bpf, void *ctx);
uint32_t rte_bpf_exec_burst(const struct rte_bpf *bpf, void *ctx[], uint64_t rc[], uint32_t num);
They allow you to load and execute BPF programs in your DPDK code.
In addition to those, the DPDK library offers 4 functions to attach BPF programs to specific ports & queues. They will then execute when packets are received and sent on those queues.
void rte_bpf_eth_rx_unload(uint16_t port, uint16_t queue);
void rte_bpf_eth_tx_unload(uint16_t port, uint16_t queue);
int rte_bpf_eth_rx_elf_load(uint16_t port, uint16_t queue, const struct rte_bpf_prm *prm, const char *fname, const char *sname, uint32_t flags);
int rte_bpf_eth_tx_elf_load(uint16_t port, uint16_t queue, const struct rte_bpf_prm *prm, const char *fname, const char *sname, uint32_t flags);
You can find more information in this presentation.

Related

How to format data to be in type const uint16_t for use in an spi library

so I have been writing some code and finished it, all I had left to do was send it over SPI. However, I didn't realise that the SPI library I am using only accepts const uint_16t data. I tried setting up a temp variable of the correct data type and using a reference to send over SPI, which works, but because it is a const variable it cant change, which is something I need it to be able to do.
Below is my code, any help with this would be great, for reference this is done in C++ and uses SPI library is part of the Raspberry Pi Pico SDK (the code is cut down as is long so only needed parts included). I did try to use pointers to change the const variable which I think you can do in C but I couldn't get it to work in C++.
Any help with this would be greatly appreciated as I am very stuck as with how to go about fixing this.
Thanks,
Dean
class Frequency_Values{
Public:
static uint16_t position;
//constructors and special member functions here
private:
uint16_t MSB_LUT[401];
uint16_t LSB_LUT[401];
};
//----------static variable definition---------------------
unsigned short Frequency_Values::position = 0;
//---------------------------------------------------------
//-------------------get function definitions--------------
uint16_t Frequency_Values::get_MSB_LUT_Value()
{
return (Frequency_Values::MSB_LUT[position]);
}
uint16_t Frequency_Values::get_LSB_LUT_Value()
{
return (Frequency_Values::LSB_LUT[position]);
}
//-----------------------------------------------------------
Frequency_Values MSB, LSB;
int main(){
while(1){ // to show code runs multiple times
//--------------------------------------------------
const uint16_t LSB_Holder = LSB.get_LSB_LUT_Value(); // this is what I tried to get it in the correct data type
//which worked but as const the value wont change
const uint16_t MSB_Holder = MSB.get_MSB_LUT_Value();
//--------------------------------------------------
}
spi_write16_blocking(SPI_PORT, &LSB_Holder, 1);
spi_write16_blocking(SPI_PORT, &MSB_Holder, 1);
}
This was eventually fixed by just removing the const specifier inside of the pico sdk, spi library.

How to send a structure as data on UDP using SendBuffer?

typedef struct
{
char cStartByte; // Set Cmd 0xB1
int iTotalBytes;
char cSeqNum; // 0 to 99 repeating
char cCommand; //
char cPrintCmd; //
float fData[8]
} CMD,*psCmdOut;
In the code tried many options with no success what to put in ??? to sedn the above structure?
UDPClient1->SendBuffer(EHost->Text,12000, ????);
You can't send your structure as-is using a socket : you need to serialize it. You need to create a common format for data exchange, usually an array of char like this one.
Code :
unsigned char* ToCharArray(psCmdOut s)
{
unsigned char serial[12]; //32-bit arch
serial[0] = s.cStartByte;
/*etc.*/
return serial;
}
You can cast your structure in a (char*) back and forth , but I would advise strongly against it : the implicit conversion hides subtleties like endianness, internal memory padding and alignment, which can blow your system in a unpredictable way.
The answer depends on your version of Indy.
In Indy 8 and 9, SendBuffer() has the following signture:
void __fastcall SendBuffer(String AHost, const int APort, void* ABuffer, const int AByteCount);
So you can do this:
CMD cmd;
// fill cmd as needed...
UDPClient1->SendBuffer(EHost->Text, 12000, &cmd, sizeof(cmd));
In Indy 10, SendBuffer() was changed to take a TIdBytes (dynamic array of bytes) instead:
void __fastcall SendBuffer(const String AHost, const TIdPort APort, const TIdBytes ABuffer);
So you cannot pass the struct pointer directly anymore. However, Indy 10 has a RawToBytes() function to create a TIdBytes from a memory block, so you can do this instead:
CMD cmd;
// fill cmd as needed...
UDPClient1->SendBuffer(EHost->Text, 12000, RawToBytes(&cmd, sizeof(cmd)));
As the #Sam suggested:
UDPClient1->SendBuffer(EHost->Text,12000,reinterpret_cast(&cmd_command));
But the length of the structure is also required. So it will be:
UDPClient1->SendBuffer(EHost->Text,12000,reinterpret_cast<char*>(&cmd_command), sizeof(cmd_command));
And also I think it will be better if you do packing of the structure by adding
#pragma pack(1)
This will give you the actual size of the structure. With this you will be able to send the complete structure. And while receiving on the other side, typecast it back to the same structure.

How can I port DeviceIOControl to ioctl?

In my understanding, DeviceIOControl and ioctl are the same functions. They both send control codes to the hardware and return the responses. In an effort to reuse code, I am trying to create a function which will work in a cross-platform manner. Therefore, I've decided to use the DeviceIOControl api since it is fixed and specific. The problem is: how do I map ioctl to that?
I currently have:
int DeviceIoControl_issueCommand(DeviceHandle handle, int command, void *input, ssize_t sizeof_input, void *output, ssize_t sizeof_output, uint32_t *bytes_written){
#if SYSTEMINFORMATION_ISWINDOWS
int result = DeviceIoControl(handle,command,input,sizeof_input,output,sizeof_output,bytes_written,0);
if (result == 0){
result = -1; //-1 is the new error return
}
return result;
#else
int result = ioctl(handle, command, input); //this doesnt work!
return result;
#endif
}
Any help is greatly appreciated!
What you are asking is not possible without a lot of internal translation in DeviceIoControl_issueCommand. The function calls are completely different and expect different parameters and data. You can work around this by declaring an IOControl class and adding member functions for each type of IO functionality you want to support.
class IOControl
{
public:
void DoIoControlX();
void DoIoControlY(int param1, int param2);
};
Then provide an impelementation for each platform you need to support. One for Windows DeviceIOControl calls and one for systems that support ioctl
I actually found that there is an IOCTL which does pass raw data to and from the driver (at least for the hard drive): HDIO_DRIVE_TASKFILE (http://www.mjmwired.net/kernel/Documentation/ioctl/hdio.txt)

Cooperation between boost::asio and standard C socket interface

I'm currently working on a small project: there's a protocol for sending some strings via UDP implemented with standard C interface.
Although it works pretty fine, I'd like to rewrite it with some more sophisticated C++ (consider it exercise).
Currently it's something like that: A client wants that string so it sends the following struct:
struct request {
uint8_t msg_type;// == 1
uint64_t key; // generated randomly to identify each request
}
In new implementation, I want to use boost::asio so in server I have a following piece of code:
boost::asio::io_service io_service;
boost::asio::ip::udp::endpoint client_endpoint;
boost::asio::ip::udp::socket socket(io_service,
boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(),
m_serverPort));
boost::asio::streambuf sb;
boost::asio::streambuf::mutable_buffers_type mutableBuf =
sb.prepare(sizeof(request));
size_t received_bytes = socket.receive_from(mutableBuf, client_endpoint);
sb.commit(received_bytes);
request r;
std::istream is(&sb);
is >> msg_type;
is >> key;
key = __bswap64(key); // I'm using network byteorder for numbers sent with this protocol
// and there's no ntohll function on Snow Leopard (at least I can't
// find one)
sb.consume(received_bytes);
And here's my problem: the "key" value which I try to receive this way is wrong - I mean I get something that I did not send.
Here are my suspicions:
__bswap64 does not convert network to host (little-endian) byteorder
I misunderstood how to use boost::asio::streambuf with streams
There's some incompatibility between old C interface and boost (but I don't think so
cause I've found out that boost functions are just wrappers for it)
EDIT:
hmm they say "don't praise a ford till you get over". Now I have a very similar issue in another place of my code. I have a following struct which is sent as a reply for request metioned above:
struct __attribute__ ((packed)) CITE_MSG_T
{
uint8_t msg_id;
uint64_t key; // must be the same as in request
uint16_t index; // part number
uint16_t parts; // number of all parts
CITE_PART_T text; // message being sent
};
//where CITE_PART_T is:
struct __attribute__ ((packed)) CITE_PART_T
{
uint16_t data_length;
char* data;
};
and following piece of code: http://pastebin.com/eTzq6AWQ.
Unfortunately there's another bug in it and again I read something I haven't sent - replyMsg.parts and replyMsg.index is always 0 although old implementation says they're for example 3 and 10. What's wrong this time? As you can see I take care of padding and I use read instead of operator>>. If you wonder why I read that struct field by field here's an answer: A server sends two different structures, both beginning with msg_id, one if it succeceeds and another if it fails. Right now, I simply have no idea how to do it other way.
You're using formatted input, as though the data being sent were textual -- you need unformatted input. Read about the std::istream::read member function, as it's what you should be using rather than operator>>.
Note that this would have been immediately obvious if you had been checking the stream state after each extraction, as one always should in non-throw-away code.
You forgot about padding. Your request structure probably has at least three bytes inserted by the compiler between the first and the second member, as in:
struct request {
uint8_t msg_type;
char __pad__[3]; // or 7 on 64-bit machine.
uint64_t key;
};
You can fix that, say in GCC, with attributes (see the GCC manual):
struct __attribute__ ((__packed__)) request { ...
And yes, I did miss the fact that you are trying to read text instead of binary. Fix that first, get bitten by alignment/padding later :)

How to use Boost.Asio c++?

I would try to use the library to use socket Boost.Asio c++ on multiple platforms.
I downloaded the latest version here:
http://sourceforge.net/projects/boost/files/boost/1.46.1/
but now what do I use in my code?
I have compile it? include just enough?
Can you tell me the steps?
How you use it depends on what you want to do, ;-).
The documentation is found here:
http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio.html
You will find lots of examples that should suite your needs.
For building, you should note that the library dependancies depend upon whether you are running on windows or linux. See here
http://www.boost.org/doc/libs/1_46_1/doc/html/boost_asio/using.html
In particular:
With MSVC or Borland C++ you may want
to add -DBOOST_DATE_TIME_NO_LIB and
-DBOOST_REGEX_NO_LIB to your project settings to disable autolinking of the
Boost.Date_Time and Boost.Regex
libraries respectively. Alternatively,
you may choose to build these
libraries and link to them
If you don't want the dependancies to the other boost libraries then you can use the non-boost (i think otherwise identical asio) library from here: http://think-async.com/
For sources of other documentation see this question on SO: Best documentation for Boost:asio?
As an example, to open a serial port you might write something like this:
/** Manage serial connections.*/
class serial_manager
{
boost::asio::io_service m_io_service;
std::string m_name;
const unsigned int m_baud_rate;
const enum flow_control::type m_flow_control;
const enum parity::type m_parity;
const enum stop_bits::type m_stop_bits;
const unsigned int m_char_size;
boost::asio::serial_port m_SerialPort;
boost::system::error_code m_error;
public:
/** A constructor.
* #param name The dvice name, for example "COM1" (windows, or "/dev/ttyS0" (linux).
* #param baud_rate The baud rate.
* #param flow_control The flow control. Acceptable values are flow_control::none, flow_control::software, flow_control::hardware.
* #param parity The parity of the connection. Acceptable values are parity::none, parity::even, parity::odd.
* #param stop_bits The number of stop bits. Acceptable values are stop_bits::one, stop_bits::one_point_five, stop::bits::two
* #param char_size The number of characters in connection.
*/
serial_manager(const std::string& name,
const unsigned int& baud_rate = 19200,
const enum flow_control::type& flow_control = flow_control::none,
const enum parity::type& parity = parity::none,
const enum stop_bits::type& stop_bits = stop_bits::one,
const unsigned int& char_size = 8
)
;
void open();
};
void
serial_manager::open() {
if (!m_SerialPort.is_open())
{
m_SerialPort.open(m_name, m_error);
if (m_error == boost::system::errc::no_such_file_or_directory )
{ //for example you tried to open "COM1" on a linux machine.
//... handle the error somehow
}
m_SerialPort.set_option(boost::asio::serial_port::baud_rate(m_baud_rate));
m_SerialPort.set_option(boost::asio::serial_port::flow_control(m_flow_control));
m_SerialPort.set_option(boost::asio::serial_port::parity(m_parity));
m_SerialPort.set_option(boost::asio::serial_port::stop_bits(m_stop_bits));
m_SerialPort.set_option(boost::asio::serial_port::character_size(m_char_size));
}
}
Read through some of the previous Boost.Asio questions on SO. You will get a good idea about some of the techniques used when using this library.