eBPF BPF_ARRAY lookup - c

I am trying to build a packet counter with eBPF and XDP. I need a way to keep track of the total number of packets received. Since I'm using XDP I use a BPF_ARRAY and increment it every time a packet is received. The problem is I can't seem to access the stored value using the provided lookup() function.
Here is how I create the BPF_ARRAY.
BPF_ARRAY(counter, u64, 1);
Here is how I try to access and use the stored value. The type of output.avg is u64.
int cindex = 0;
counter.increment(&cindex);
long current_count = counter.lookup(&cindex);
output.avg = current_count;
BPF gives me this warning and fails to compile.
warning: incompatible pointer to integer conversion initializing 'long' with
an expression of type 'u64 *' (aka 'unsigned long long *') [-Wint-conversion]
long current_count = counter.lookup(&cindex);

I figured out how to fix my errors. I'm new to C so the pointers confused me a little bit.
int cindex = 0;
counter.increment(cindex);
unsigned long long *current_count = counter.lookup(&cindex);
if(current_count != NULL){
output.avg = *current_count;
}

Related

assignment to 'char' from 'const char *' makes integer from pointer without a cast

I am very new to C and am encountering an issue while trying to store my next_frame in a variable. Any help would be great as I think this is probably something simple I'm just missing.
If I just change the following it works fine, only when I try to store the next_frame in a variable does it not compile.
// Doesn't compile
oled_write_raw_P(next_frame, FRAME_SIZE);
// Compiles
oled_write_raw_P(frames[abs((FRAME_COUNT - 1) - current_frame)];, FRAME_SIZE);
Full Code
#define FRAME_COUNT 5 // Animation Frames
#define FRAME_SIZE 256
#define FRAME_DURATION 200 // MS duration of each frame
// Variables
uint32_t timer = 0;
uint8_t current_frame = 0;
char next_frame;
static void render_animation(void) {
static const char PROGMEM frames[FRAME_COUNT][FRAME_SIZE] = {
// Images here, removed for example
};
// If timer is more than 200ms, animate
if (timer_elapsed32(timer) > FRAME_DURATION) {
timer = timer_read32();
current_frame = (current_frame + 1) % FRAME_COUNT;
next_frame = frames[abs((FRAME_COUNT - 1) - current_frame)];
// Set cursor position
oled_set_cursor(128, 0);
// Write next frame
oled_write_raw_P(next_frame, FRAME_SIZE);
}
}
These are the errors:
error: assignment to 'char' from 'const char *' makes integer from pointer without a cast [-Werror=int-conversion]
next_frame = frames[abs((FRAME_COUNT - 1) - current_frame)];
error: passing argument 1 of 'oled_write_raw_P' makes pointer from integer without a cast [-Werror=int-conversion]
oled_write_raw_P(next_frame, FRAME_SIZE);
The line
next_frame = frames[abs((FRAME_COUNT - 1) - current_frame)]
does not make sense.
The variable next_frame, to which you are assigning a value, has the type char. However, you are assigning it the expression
frames[abs((FRAME_COUNT - 1) - current_frame)]
which decays to a pointer to the first element of the sub-array, so the expression evaluates to a value of type const char *.
I'm not exactly sure what you want to accomplish, but I guess the solution to your problem is to change the type of next_frame to const char *, so that the types match. In order to do this, you can change the line
char next_frame;
to:
const char *next_frame;

Is it possible to reset user defined data type by accessing the address typecasted content, in C?

I'm trying to reset the values to 0 in the arrays made by user a defined data type and standard data type as in the code displayed below.
(Case 1)
uint8_t source[2] = {1,1};
uint8_t data[2];
typedef struct
{
uint32_t event3;
float32_t event4;
float32_t event5;
} test_Data_ts;
test_Data_ts test_Data_s[32];
void main()
{
test_Data_ts test_Data_s2 = {0};
//This Works
(*(uint32_t*)(data)) = 0;
(*(uint16_t*)(&data[0])) = (*(uint16_t*)(&source[0]));
//This Works
(*(test_Data_ts*)(&test_Data_s[0])) = test_Data_s2;
}
The following lines of code results in error
(Case 2)
(*(test_Data_ts*)(&test_Data_s[0])) = *(test_Data_ts*)0x00; //do not execute
(*(test_Data_ts*)(&test_Data_s[0])) = (test_Data_ts)0; //**Error -> conversion to non-scalar type requested
(*(test_Data_ts*)(&test_Data_s[0])) = 0;//**Error -> incompatible types when assigning to type 'test_Data_ts' from type 'int
Why is the second 3 cases are incorrect? Can somebody give explanations of the Errors as well?
*(test_Data_ts*)(&test_Data_s[0])
is the first element of table test_Data_s and is of type test_Data_ts
In the first allocation, types are corrects.
(*(test_Data_ts*)(&test_Data_s[0])) = *(test_Data_ts*)0x00; //do not execute
but you are trying to dereference a null pointer.
(*(test_Data_ts*)(&test_Data_s[0])) = (test_Data_ts)0; //**Error -> conversion to non-scalar type requested
It does not work, because you are asking the compiler to convert a scalar type (0 is int), to a struct.
(*(test_Data_ts*)(&test_Data_s[0])) = 0;//**Error -> incompatible types when assigning
//to type 'test_Data_ts' from type 'int
You do not ask for a conversion, as in the previous line, but the compiler tells you that types on both sides of the assignment are not compatible. One is an int (0) and the other a struct.
I think that's what you are looking for
memset(&test_Data_s, 0, sizeof test_Data_s);

Casting Pointers to int in c

I have to learn it for my study. Is their any way to cast a pointer to integer. I have to give myEulerForward1 a pointer as a paramter and i always get this error message :
eulerZahl.c: In function ‘main’:
eulerZahl.c:38:35: warning: passing argument 1 of ‘myEulerForward1’ makes pointer from integer without a cast [-Wint-conversion]
double forward = myEulerForward1(k);
^
eulerZahl.c:16:8: note: expected ‘int *’ but argument is of type ‘int’
double myEulerForward1(int *n1){
^~~~~~~~~~~~~~~
Can someone help me with it?
#include <stdio.h>
#include <stdint.h>
double kFactorial(int k){
if(k <= 1){
return 1;
}
return k * kFactorial(k - 1);
}
double myEulerForward1(int *n1){
double n = 1;
double euler, nFact = 1;
for(int i = sizeof(&n1); i >= 0; i--){
nFact*= i;
euler = euler + (1.0/nFact);
}
return euler;
}
int main(){
int k = 4;
double factorial = kFactorial(k);
printf("The factorial of %d is: %lf ", k, factorial);
double forward = myEulerForward1(k);
printf("The Eulers Number: %lf", forward);
}
First i can see an error at sizeof(&n1);
Of course n1 is a pointeur. His Value is a RAM address. But for see his Deferenced value, you must use * before n1. & is used for get the adress of something. * is used for get the inside of a pointer.
Use : sizeof(*n1);
In Second, i see that you get a pointer in the prototype of myEulerForward1
double myEulerForward1(int *n1)
It's your compile error. He said that your function need a pointer (an adress) and that you put everything except that.
So when you call this function, you must put a pointer (a RAM adress).
And for do that, in the calling of the function, you must use & of course for get the adress of n1 and not his number value.
Use : double forward = myEulerForward1(&k);
Well, yes, it is possible to convert a pointer to an int, and vice versa.
However, you are making a serious mistake in asking that question. There are circumstances where converting an int to a pointer, or vice versa, makes sense. But, in your code, you would be using it as a blunt instrument to force the compiler to accept bad code.
Your compiler is complaining because you have passed an int to a function that expects an int *.
Forcing the issue, by converting that int to a pointer, will stop the compiler complaining, but then you'll (possibly) get some form of runtime error, since the function will receive an invalid pointer.
Your choices are
remove the * from double myEulerForward1(int *n1). This will mean, the function expects an int, so your code that passes an int will be correct.
Call the function as myEulerForward1(&k) which passes an address of k (which is not k converted to a pointer) as a pointer.
Looking at the body of myEulerForward1() there are other problems as well. You need to read up and better understand what sizeof does. Whether your function accepts an int or a pointer (int *) the logic of your function is faulty.

v8 node buffer of unsigned chars

My knowledge / experience of C is quite limited but I'm trying to create a node addon that uses a node buffer with a C call which expects the buffer to be of type 'unsigned char*' but from what I can see the node buffer Data method provides a 'char*' so the types are incompatible. E.g.
This is how it would be called using c:
int length = 100;
unsigned char buf[length];
int ret = ftdi_read_data(&ftdic, buf, length);
And from what I have read, to use a node buffer you do the following instead:
int length = 100;
node::Buffer *slowBuffer = node::Buffer::New(length);
int ret = ftdi_read_data(&ftdic, node::Buffer::Data(slowBuffer), length);
However this returns the following error when building:
error: invalid conversion from ‘char*’ to ‘unsigned char*’ [-fpermissive]
int ret = ftdi_read_data(&ftdic, node::Buffer::Data(slowBuffer), length);
Is it possible to create a node buffer of type unsigned chars, or achieve this in some other way?
Thanks
In your addon C code use a cast like this: (unsigned char*)node::Buffer::Data(slowBuffer). This is the usual fix for the specific error shown.

passing non-global array variable in C

C is a reasonably new language to me, most of my programming knowledge is based around Java, or web-based languages - so please be gentle if I come across as a complete noob with this question!
I have an array of type unsigned long, with size 100000, declared in main(). When a certain condition of user input is met, a record() function call is made which initiates some hardware to begin audio recording (not really important to the scope of the question).
At the record() function call, as long as a 'ready' flag in a register is initialised, the contents of the register is copied to an array cell - this process iterates until all 100000 cells of the array have been recorded to.
The array from the record() function now needs be returned to a variable in main(). I have tried this by simply returning a variable of type unsigned long from the method call - but I can't seem to make this work. I have also tried this using pointers - but my inexperience with C is showing when I try this.
My code for using pointers is:
int main(void){
...
unsigned long recordingOne[100000];
unsigned long *ptrOne;
ptrOne = &recordingOne;
...
initiateRecording(ptrOne);
}
void initiateRecording(unsigned long *ptr){
unsigned long returnOne[100000];
for(i = 0; i<100001; i++){
returnOne[i] = AD0DR1 //AD0DR1 corresponds to hardware register
}
*ptr = returnOne;
}
For this I get two warnings:
(in function main) warning: assignment from incompatible pointer type [enabled by default]
(in function initiateRecording) warning: assignment makes integer from pointer without a cast [enabled by default]
When I tried this previously without pointers, I tried passing an array as a parameter, and then returning an array. That looked something like this:
int main(void){
...
unsigned long recordingOne[100000];
...
recordingOne = initiateRecording();
}
unsigned long[] initiateRecording(){
unsigned long toReturnOne[100000];
for(i = 0; i<100001; i++){
toReturnOne[i] = AD0DR1 //AD0DR1 corresponds to hardware register
}
return toReturnOne;
}
The compiler wasn't a fan of this either - I'm struggling to declare a return object of type unsigned long that is also an array.
As always, your help is very much appreciated!
Here is the best method:
int main(void)
{
...
unsigned long recordingOne[100000];
unsigned long *ptrOne; // <<<--- Don't need this
ptrOne = &recordingOne; // <<<--- Don't need this
...
initiateRecording(recordingOne); <<<--- Pass address of array directly
}
void initiateRecording(unsigned long *ptr)
{
for(i = 0; i<100000; i++) <<<---- If i == 100000 undefined behavior, such as a segmentation fault, may occur; change 100001 to 100000
ptr[i] = AD0DR1 // <<<--- write directly to array
}
The accessible elements in recordingOne are from [0] to [99999]
The source of both compiler warnings is the following: when you initialize a C array like int array[100];, the symbol array is a pointer to the first element of the array. So when you write something like int *p = &array, the result is that p points not to the beginning of array, but to the location in memory that holds the pointer to the beginning of array. What you want is int *p = &array[0].
Edit: or int *p = array works just fine too, as pointed out in a comment in another answer.

Resources