I want to write a bpf program which return [1,n] in round-robin pattern. e.g if n=4 then it should return 1,2,3,4,1,2,3,4,1,2..
Algorithm for above idea is:
- A = read M[0]
- A = A % n-1
- A = A+1
- store M[0] = A
- return A
Apart from first step, everything is correct in my case. I am not able to load value from memory into accumulator.
BPF code
// CBPF code for REUSEPORT using plain round robin algorithm
struct sock_filter code[] = {
{BPF_LD | BPF_MEM, 0, 0, 0}, // A = M[0]
{BPF_ALU | BPF_MOD | BPF_K, 0, 0, groupSize - 1}, // A = A % group_size-1
{BPF_ALU | BPF_ADD | BPF_K, 0, 0, 1}, // A = A+1
{BPF_ST, 0, 0, 0}, // M[0] = A
{BPF_RET | BPF_A, 0, 0, 0} // return A
};
There is problem in using BPF_LD | BPF_MEM to load value from memory into accumulator. What is correct way to do this.
Here is my complete code, you can take and run:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/filter.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#define BUFFER_SIZE 2048
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0
char ip[] = "0.0.0.0";
int port = 7155;
unsigned int groupSize = 3;
int sockFD;
void print_error(char* main_message)
{
printf("%s.\nErrNo: %d. ErrMessage: %s\n",main_message, errno, strerror(errno));
}
int udp_balancer()
{
struct sockaddr_in6 serverAddress;
// initialise socket
sockFD = socket(AF_INET6, SOCK_DGRAM, 0);
if (sockFD < 0)
{
print_error("Socket initialisation failed");
return EXIT_FAILURE;
}
// Enable SO_REUSEPORT option
const int enable = 1;
if (setsockopt(sockFD, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(int)) < 0)
{
print_error("setsockopt(SO_REUSEPORT) failed");
return EXIT_FAILURE;
}
// CBPF code for REUSEPORT dispatch based on CPU() % group_size
// struct sock_filter code[] = {
// {BPF_LD | BPF_W | BPF_ABS, 0, 0, SKF_AD_CPU}, // A = #cpu
// {BPF_ALU | BPF_MOD | BPF_K, 0, 0, groupSize - 1}, // A = A % group_size-1
// {BPF_ALU | BPF_ADD | BPF_K, 0, 0, 1}, // A = A+1
// {BPF_RET | BPF_A, 0, 0, 0} // return A
// };
// CBPF code for REUSEPORT using plain round robin algorithm
struct sock_filter code[] = {
{BPF_LD | BPF_MEM, 0, 0, 0}, // A = M[0]
{BPF_ALU | BPF_MOD | BPF_K, 0, 0, groupSize - 1}, // A = A % group_size-1
{BPF_ALU | BPF_ADD | BPF_K, 0, 0, 1}, // A = A+1
{BPF_ST, 0, 0, 0}, // M[0] = A
{BPF_RET | BPF_A, 0, 0, 0} // return A
};
struct sock_fprog bpf = {
.len = sizeof(code) / sizeof(code[0]),
.filter = code,
};
// Attach bpf program
socklen_t sizeOfBPF = (socklen_t)sizeof(bpf);
if (setsockopt(sockFD, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &bpf, sizeOfBPF) < 0)
{
print_error("Bpf attach is failed");
return EXIT_FAILURE;
}
// Configure serverAddress object
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin6_family = AF_INET6; // address is of type ip6
// serverAddress.sin6_addr = in6addr_any;
inet_pton(AF_INET6, ip, &(serverAddress.sin6_addr));
serverAddress.sin6_port = htons(port);
// Bind socket to specific ip and port
if (bind(sockFD, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0)
{
print_error("Address binding is failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void displayConfig()
{
pid_t pid = getpid();
printf("FD %d PID %d\n",sockFD,pid);
struct sockaddr_in addr;
socklen_t addrLen = sizeof(addr);
// Assuming sockfd is your bound UDP socket
if (getsockname(sockFD, (struct sockaddr *)&addr, &addrLen) == -1)
{
print_error("getsockname failed");
exit(EXIT_FAILURE);
}
char ipStr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(addr.sin_addr), ipStr, INET_ADDRSTRLEN);
printf("Listening on IP: %s::%d\n" , ipStr ,ntohs(addr.sin_port));
}
void capture()
{
int packetCount = 0;
struct sockaddr_in6 clientAddress;
char buffer[BUFFER_SIZE];
socklen_t clientAddressLength = sizeof(clientAddress);
displayConfig();
while (1)
{
// clear the buffer
memset(buffer, 0, BUFFER_SIZE);
// Receive packet
ssize_t bytesRead = recvfrom(sockFD, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&clientAddress, &clientAddressLength);
if (bytesRead < 0)
{
print_error("recvfrom failed");
break;
}
packetCount++;
printf("Total packet count %d\n", packetCount);
}
}
int main()
{
int status = udp_balancer();
if(status == EXIT_FAILURE){
printf("Balancer failed to run\n");
}
else
capture();
return 0;
}
I tried running with above bpf program but it is throwing error that not able to attch bpf.