I want to print IP addresses of packets parsed by an XDP program I am testing with. I using bpf_trace_printk() to print details about packets parsed by my program.
How can I print IP addresses with bpf_trace_print()?
I tried using this suggestion to print the IP, but I get this error when trying to use bpf_trace_printk()
/virtual/main.c:99:52: warning: cannot use more than 3 conversion specifiers
bpf_trace_printk("\n- src_ip: %d.%d.%d.%d\n", src_ipaddr[3],src_ipaddr[2],src_ipaddr[1],src_ipaddr[0]);
^
6 warnings generated.
error: /virtual/main.c:111:59: in function filter i32 (%struct.xdp_md*): too many args to 0x5b6de28: i64 = Constant<6>
Its not clear to my why I am getting this error.
bpf_trace_printk is meant for debugging only. It will print a large warning in your system logs when you use it. If you're at the stage where you want to pretty-print IP addresses, then you're probably not debugging anymore.
The proper alternative is to use the bpf_perf_event_output BPF helper. See https://github.com/iovisor/bcc/blob/master/docs/tutorial_bcc_python_developer.md#lesson-7-hello_perf_outputpy for an example with bcc. That will allow you to send arbitrary data to userspace, where you can pretty-print the IP addresses with Python.
Linux kernel provides BPF helper, bpf_trace_printk(), with the following definition:
long bpf_trace_printk(const char *fmt, __u32 fmt_size, ...);
So you need to define size of format string before your arguments.
A hard limitation is that bpf_trace_printk() can accept only up to 5 input arguments in total. You must define fmt and fmt_size, which means you limit to use just 3 other arguments. So 4 specifiers is not allowed in format string. This is quite often pretty limiting and you might need to use multiple bpf_trace_printk() invocations to log all the data.
for(int i=0; i<4; i++)
bpf_trace_printk("IP section %d [%d]", strlen("IP section %d [%d]"),i,src_ipaddr[i]);
or use #craig-estey method
bpf_trace_printk("\n- src_ip:");
for (int idx = 3; idx >= 0; --idx)
bpf_trace_printk("%c%d",(idx == 0) ? ' ' : '.',src_ipaddr[idx]);
bpf_trace_printk("\n");
I'm not sure but you may use sprintf
char part1Ip[32] = {0};
char part2Ip[32] = {0};
char wholeIp[32] = {0};
sprintf(part1Ip, "%d.%d", src_ipaddr[3],src_ipaddr[2]);
sprintf(part2Ip, "%d.%d", src_ipaddr[1],src_ipaddr[0]);
sprintf(wholeIp, "%s.%s", part1Ip,part2Ip);
bpf_trace_printk("\n- src_ip: %s\n", wholeIp);
For more information see BPF tips & tricks.
Related
I've been trying to read the Unique Identifier (UID) from a Atmel SAM3U MCU, but it's proven more difficult than it needs to be to make it happen. Does anyone have any examples or can suggest how to read it properly? Whenever I do, I wait in a do while loop (like the documentation states) for the EEFC (Flash ROM) status register to change states, but it never does so the MCU is then stuck in a loop.
Here is the code I'm using
// must run this from SRAM
__attribute__((section(".ARM.__at_0x20080000"))) void Get_Unique_ID(unsigned int *pdwUniqueID)
{
Efc *p_efc;
unsigned int status;
// clear the array
pdwUniqueID[0] = 0;
pdwUniqueID[1] = 0;
pdwUniqueID[2] = 0;
pdwUniqueID[3] = 0;
// send the Start Read Unique Identifier command (STUI) by writing the Flash Command Register with the STUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
// wait for the Flash Programming Status Register (EEFC_FSR) to fall
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);
// the Unique Identifier is located in the first 128 bits of the Flash memory mapping
pdwUniqueID[0] = *(unsigned int *)IFLASH0_ADDR;
pdwUniqueID[1] = *(unsigned int *)(IFLASH0_ADDR + 4);
pdwUniqueID[2] = *(unsigned int *)(IFLASH0_ADDR + 8);
pdwUniqueID[3] = *(unsigned int *)(IFLASH0_ADDR + 12);
// to stop the Unique Identifier mode, the user needs to send the Stop Read unique Identifier
// command (SPUI) by writing the Flash Command Register with the SPUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_SPUI;
// when the Stop Read Unique Unique Identifier command (SPUI) has been performed
// the FRDY bit in the Flash Programming Status Register (EEFC_FSR) rises
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
}
Note that __attribute__((section(".ARM.__at_0x20080000"))) isn't the best method to dynamically assign this function to SRAM via the linker and any suggestions on how to make it more dynamic would be appreciated.
SOLVED The problem was the chips I had were fake so SAM-BA was returning whatever was at the SRAM buffer address it specified. It's a bug in SAM-BA since if it received 0x00000000, it should give an error or warning message and then stop reading. Do not buy fake chips from China!
Thanks.
I don't believe p_efc is correctly initialized.
You create a pointer to a Efc datastructure which thus points to something.
You then write something to somewhere and are expect it to work.
Efc *p_efc;
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
My guess would be that you need to intialize it to the correct EEFC base address. The datasheet has the following to say:
The SAM3U4 (256 Kbytes internal Flash
version) embeds two EEFC (EEFC0 for Flash0 and EEFC1 for Flash1)
whereas the SAM3U2/1 embeds one EEFC.
So depending on your MCU version you need to address EEFC0 or EEFC1. I'm assuming that you use libopencm3 but this will work for any other library. Look for the EEFC location define. Following the defines/files/links we get to this page, it tells us to point our Efc pointer to EEFC0_BASE or EEFC1_BASE. I would advise you to use the EEFC0 and EEFC1 defines though as it makes your code portabler.
So your code should work if your Efc is located in EEFC0 if you do:
Efc *p_efc = EEFC0;
In an answer on a sister site, I'm trying to dump information from the Linux kernel array unix_socket_table#net/unix/af_unix.c which is defined as:
struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
For the moment, I'm hard-coding the size of the array in my stp script:
for (i = 0; i < 512; i++)
How could I avoid that? That information (the size of the array) is stored in the debug information. gdb can tell me it:
$ gdb --batch --ex 'whatis unix_socket_table' "/usr/lib/debug/boot/vmlinux-$(uname -r)"
type = struct hlist_head [512]
$ gdb --batch --ex 'p sizeof(unix_socket_table)/sizeof(*unix_socket_table)' "/usr/lib/debug/boot/vmlinux-$(uname -r)"
$1 = 512
But how would I do it in systemtap? AFAICT, systemtap has no sizeof() operator.
If it were a type, the #cast operator could be used:
size=&#cast(0,"$TYPENAME")[1]
but alas, unix_socket_table isn't a type. So, plan B, use symdata on the variable (in scope of any old kernel function in the vicinity).
probe begin /* kernel.function("*#net/unix/af_unix.c") */ {
println(symdata(& #var("unix_socket_table")))
exit()
}
results here:
unix_socket_table+0x0/0x1000 [kernel]
The second hex number is the symbol size, as computed from the ELF symbol tables at script processing time, equivalent to the 4096 figure here:
% readelf -s /usr/lib/debug/lib/modules/`uname -r`/vmlinux | grep unix_socket_table
71901: ffffffff82023dc0 4096 OBJECT GLOBAL DEFAULT 28 unix_socket_table
You can get the number with for instance:
probe begin {
tokenize(symdata(#var("unix_socket_table#net/unix/af_unix.c")),"/");
printf("%d\n", strtol(tokenize("",""), 16));
exit()
}
Many thanks to #fche for pointing me in the right direction. As he says, systemtap's symdata() function can be used to retrieve symbol information at a given address including the size. So we can write our own sizeof() function that parses it to extract the size as:
function sizeof(address:long) {
tokenize(symdata(address), "/");
return strtol(tokenize("",""),16);
}
If we look at the definition of that symdata() function, we see that it is itself a systemtap function that makes use of the _stp_snprint_addr() C function, itself calling _stp_kallsyms_lookup() to retrieve data. That means we can also define our own sizeof() using stp_kallsyms_lookup() directly:
function sizeof:long (addr:long) %{ /* pure */ /* pragma:symbols */
STAP_RETVALUE = -1;
_stp_kallsyms_lookup(STAP_ARG_addr, (unsigned long*)&(STAP_RETVALUE), NULL, NULL, NULL);
%}
(note that we need -g (guru) here as we're using embedded C).
Now, to get the array size, we need the size of the elements of the arrays. One approach can be to use the address offset between 2 elements of the array. So we could define our array_size() function as:
function array_size(first:long, second:long) {
return sizeof(first) / (second - first);
}
(where sizeof() is one or the other of the functions defined above).
And call it as:
probe begin {
printf("%d\n", array_size(
&#var("unix_socket_table#net/unix/af_unix.c")[0],
&#var("unix_socket_table#net/unix/af_unix.c")[1]));
exit();
}
Which gives us 512 as expected.
For sizeof(), another approach could be to use the C sizeof() operator:
$ sudo stap -ge '
%{ #include <net/af_unix.h> %}
probe begin {
printf("%d\n", %{ sizeof(unix_socket_table)/sizeof(unix_socket_table[0]) %} );
exit();
}'
512
(also needs -g) but then the information is retrieved from the kernel source code (header files), not debug information, so while that would work for kernel arrays that are defined in header files, that approach won't necessary work for all arrays.
I've got some code that is using the functions ieee80211_radiotap_iterator_init() and ieee80211_radiotap_iterator_next() from radiotap-parser.c,
I'm not sure what I'm doing incorrectly, perhaps someone can educate me? I'm using the sample code from the documentation more or less without modification, it fits very well to what I was trying to achieve:
/* where packet is `const u_char *packet' */
struct ieee80211_radiotap_iterator rti;
struct ieee80211_radiotap_header *rth = ( struct ieee80211_radiotap_header * ) packet;
/* 802.11 frame starts here */
struct wi_frame *fr= ( struct wi_frame * ) ( packet + rth->it_len );
/* Set up the iteration */
int ret = ieee80211_radiotap_iterator_init(&rti, rth, rth->it_len);
/* Loop until we've consumed all the fields */
while(!ret) {
printf("Itteration: %d\n", count++);
ret = ieee80211_radiotap_iterator_next(&rti);
if(ret) {
/*
* The problem is here, I'm dropping into this clause with
* a value of `1` consistently, that doesn't match my platform's
* definition of EINVAL or ENOENT.
*/
continue;
}
switch(rti.this_arg_index) {
default:
printf("Constant: %d\n", *rti.this_arg);
break;
}
}
There's limited scope for having screwed something up in that code, I think, I'm confused by the 1 being returned from ieee80211_radiotap_iterator_next() which according to the implenentation doesn't seem like an error condition in the implementation.
I'm filtering for packets of type "(type mgt) and (not type mgt subtype beacon)", and I'm not even certain if libpcap will include these attributes when the data link is set to DLT_IEEE802_11_RADIO?
First:
I'm filtering for packets of type "(type mgt) and (not type mgt subtype beacon)", and I'm not even certain if libpcap will include these attributes when the data link is set to DLT_IEEE802_11_RADIO?
It will. The filter code generated for DLT_IEEE802_11_RADIO fetches the radiotap header length and skips the radiotap header, so it'll just skip the radiotap header and check the 802.11 header following it.
Second:
the implementation
You linked to two different implementations of ieee80211_radiotap_iterator_next() - the one at radiotap-parser.c, in which ieee80211_radiotap_iterator_next() returns the "next present arg index" on success, and the one from the Linux kernel, in which ieee80211_radiotap_iterator_next() returns 0 on success. If the radiotap iterator code you're using is the one at radiotap-parser.c, pay no attention whatsoever to the one from the Linux kernel, as it doesn't behave the way the one you're using behaves.
I am trying to make a simple kernel using C. Everything loads and works fine, and I can access the video memory and display characters, but when i try to implement a simple puts function for some reason it doesn't work. I've tried my own code and other's. Also, when I try to use a variable which is declared outside a function it doesn't seem to work. This is my own code:
#define PUTCH(C, X) pos = putc(C, X, pos)
#define PUTSTR(C, X) pos = puts(C, X, pos)
int putc(char c, char color, int spos) {
volatile char *vidmem = (volatile char*)(0xB8000);
if (c == '\n') {
spos += (160-(spos % 160));
} else {
vidmem[spos] = c;
vidmem[spos+1] = color;
spos += 2;
}
return spos;
}
int puts(char* str, char color, int spos) {
while (*str != '\0') {
spos = putc(*str, color, spos);
str++;
}
return spos;
}
int kmain(void) {
int pos = 0;
PUTSTR("Hello, world!", 6);
return 0;
}
The spos (starting position) stuff is because I can't make a global position variable. putc works fine, but puts doesn't. I also tried this:
unsigned int k_printf(char *message, unsigned int line) // the message and then the line #
{
char *vidmem = (char *) 0xb8000;
unsigned int i=0;
i=(line*80*2);
while(*message!=0)
{
if(*message=='\n') // check for a new line
{
line++;
i=(line*80*2);
*message++;
} else {
vidmem[i]=*message;
*message++;
i++;
vidmem[i]=7;
i++;
};
};
return(1);
};
int kmain(void) {
k_printf("Hello, world!", 0);
return 0;
}
Why doesn't this work? I tried using my puts implementation with my native GCC (without the color and spos data and using printf("%c")) and it worked fine.
Since you're having an issue with global variables in general, the problem most likely has to-do with where the linker is placing your "Hello World" string literal in memory. This is due to the fact that string literals are typically stored in a read-only portion of global memory by the linker ... You have not detailed exactly how you are compiling and linking your kernel, so I would attempt something like the following and see if that works:
int kmain(void)
{
char array[] = "Hello World\n";
int pos = 0;
puts(array, 0, pos);
return 0;
}
This will allocate the character array on the stack rather than global memory, and avoid any issues with where the linker decides to place global variables.
In general, when creating a simple kernel, you want to compile and link it as a flat binary with no dependencies on external OS libraries. If you're working with a multiboot compliant boot-loader like GRUB, you may want to look at the bare-bones sample code from the multiboot specification pages.
Since this got references outside of SO, I'll add a universal answer
There are several kernel examples around the internet, and many are in various states of degradation - the Multiboot sample code for instance lacks compilation instructions. If you're looking for a working start, a known good example can be found at http://wiki.osdev.org/Bare_Bones
In the end there are three things that should be properly dealt with:
The bootloader will need to properly load the kernel, and as such they must agree on a certain format. GRUB defines the fairly common standard that is Multiboot, but you can roll your own. It boils down that you need to choose a file format and locations where all the parts of your kernel and related metadata end up in memory before the kernel code will ever get executed. One would typically use the ELF format with multiboot which contains that information in its headers
The compiler must be able to create binary code that is relevant to the platform. A typical PC boots in 16-bit mode after which the BIOS or bootloader might often decide to change it. Typically, if you use GRUB legacy, the Multiboot standard puts you in 32-bit mode by its contract. If you used the default compiler settings on a 64-bit linux, you end up with code for the wrong architecture (which happens to be sufficiently similar that you might get something that looks like the result you want). Compilers also like to rename sections or include platform-specific mechanisms and security features such as stack probing or canaries. Especially compilers on windows tend to inject host-specific code that of course breaks when run without the presence of Windows. The example provided deliberately uses a separate compiler to prevent all sorts of problems in this category.these
The linker must be able to combine the code in ways needed to create output that adheres to the bootloader's contract. A linker has a default way of generating a binary, and typically it's not at all what you want. In pretty much all cases, choosing gnu ld for this task means that you're required to write a linker script that puts all the sections in the places where you want. Omitted sections will result in data going missing, sections at the wrong location might make an image unbootable. Assuming you have gnu ld, you can also use the bundled nm and objdump tools besides your hex editor of choice to tell you where things have appeared in your output binary, and with it, check if you've been following the contract that has been set for you.
Problems of this fundamental type are eventually tracked back to not following one or more of the steps above. Use the reference at the top of this answer and go find the differences.
Is there a way to get the C/C++ preprocessor or a template or such to mangle/hash the __FILE__ and __LINE__ and perhaps some other external input like a build-number into a single short number that can be quoted in logs or error messages?
(The intention would be to be able to reverse it (to a list of candidates if its lossy) when needed when a customer quotes it in a bug report.)
You will have to use a function to perform the hashing and create a code from __LINE__ and __FILE__ as the C preprocessor is not able to do such complex tasks.
Anyway, you can take inspiration by this article to see if a different solution can be better suited to your situation.
Well... you could use something like:
((*(int*)__FILE__ && 0xFFFF0000) | version << 8 | __LINE__ )
It wouldn't be perfectly unique, but it might work for what you want. Could change those ORs to +, which might work better for some things.
Naturally, if you can actually create a hashcode, you'll probably want to do that.
I needed serial valuse in a project of mine and got them by making a template that specialized on __LINE__ and __FILE__ and resulted in an int as well as generating (as compile time output to stdout) a template specialization for it's inputs that resulted in the line number of that template. These were collected the first time through the compiler and then dumped into a code file and the program was compiled again. That time each location that the template was used got a different number.
(done in D so it might not be possible in C++)
template Serial(char[] file, int line)
{
prgams(msg,
"template Serial(char[] file : \"~file~"\", int line : "~line.stringof~")"
"{const int Serial = __LINE__;");
const int Serial = -1;
}
A simpler solution would be to keep a global static "error location" variable.
#ifdef DEBUG
#define trace_here(version) printf("[%d]%s:%d {%d}\n", version, __FILE__, __LINE__, errloc++);
#else
#define trace_here(version) printf("{%lu}\n", version<<16|errloc++);
#endif
Or without the printf.. Just increment the errloc everytime you cross a tracepoint. Then you can correlate the value to the line/number/version spit out by your debug builds pretty easily.
You'd need to include version or build number, because those error locations could change with any build.
Doesn't work well if you can't reproduce the code paths.
__FILE__ is a pointer into the constants segment of your program. If you output the difference between that and some other constant you should get a result that's independent of any relocation, etc:
extern const char g_DebugAnchor;
#define FILE_STR_OFFSET (__FILE__ - &g_DebugAnchor)
You can then report that, or combine it in some way with the line number, etc. The middle bits of FILE_STR_OFFSET are likely the most interesting.
Well, if you're displaying the message to the user yourself (as opposed to having a crash address or function be displayed by the system), there's nothing to keep you from displaying exactly what you want.
For example:
typedef union ErrorCode {
struct {
unsigned int file: 15;
unsigned int line: 12; /* Better than 5 bits, still not great
Thanks commenters!! */
unsigned int build: 5;
} bits;
unsigned int code;
} ErrorCode;
unsigned int buildErrorCodes(const char *file, int line, int build)
{
ErrorCode code;
code.bits.line=line & ((1<<12) - 1);
code.bits.build=build & ((1<< 5) - 1);
code.bits.file=some_hash_function(file) & ((1<<15) - 1);
return code.code;
}
You'd use that as
buildErrorCodes(__FILE__, __LINE__, BUILD_CODE)
and output it in hex. It wouldn't be very hard to decode...
(Edited -- the commenters are correct, I must have been nuts to specify 5 bits for the line number. Modulo 4096, however, lines with error messages aren't likely to collide. 5 bits for build is still fine - modulo 32 means that only 32 builds can be outstanding AND have the error still happen at the same line.)