how to capture packets sent by XDP user space program - bpf

Say I have XDP kernel and user programs. Kernel code examines ingress packets and "forwards" them to XDP user space program. XDP user space program then does some processing and sends packets out (could be same NIC or other one).
For controlling reasons we want to examine the outgoing packets sent by XDP user space code. Our first idea was using tc and insert BPF code to egress part, clearly didn't work.
Any idea?
EDIT1: egress program:
SEC("tx")
int track_tx(struct __sk_buff *skb)
{
__u64 t2 = bpf_ktime_get_ns();
void *data_end = (void *)(long)skb->data_end;
void *data = (void *)(long)skb->data;
bpf_custom_printk("\n__________send length %d\n", data_end-data);
return TC_ACT_OK;
}
run:
sudo tc filter add dev ens13 egress bpf da obj layercoop.o sec tx
EDIT2: Code
USer: https://github.com/torvalds/linux/blob/master/samples/bpf/xdpsock_user.c
Kernel (not interesting): https://github.com/torvalds/linux/blob/master/samples/bpf/xdpsock_kern.c
I want to forward incoming packets, so run it with make -j 4; sudo ./xdpsock -i ens13 -l

Related

What will the network interrupt handler do when NIC recieve data?

As far as I know, when a packet arrives at the NIC, the DMAC will copy the packet to the kernel space. When the DMAC completes its work, it notifies the CPU, and then the CPU copies the data to the user space. Doing so will cause the memory to be read once and to be written twice. I wrote a simple program to simulate this process. This is the code:
# server.py
import socket
import sys
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "70.202.0.116"
port = 12306
server.bind((host, port))
server.listen(5)
while True:
conn,addr = server.accept()
print(conn,addr)
while True:
data = conn.recv(4096)
if not data:
print("client has lost")
conn.close()
break
server.close()
# client.py
import socket
import sys
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "70.202.0.116"
port = 12306
client.connect((host, port))
data = ''
for i in range(4096):
data += 'a'
while True:
client.send(data.encode())
client.close()
My machine has two numa nodes. At the first time, I disabled NIC Multi-Queue by ethtool -L eno1 combined 1, thus there is only one network interrupt left, and set the affanity by ehco 22 > /proc/irq/137/smp_affinity_list. Core 22 is on numa 1. Then I ran server.py. I use pcm-memory to moniter system memory bandwidth, and I got the expected output, the read-write ratio is close to 1:2.
But when I changed the affanity to core 0 which is on numa 0, I got totally different result. The read-write ratio is close to 1:1.
I want to know what does the interrput handler do during this process, why did I get different result?
increase read latency could be because device belongs to different numa_node. Check device where server and client is running belongs to which numa node
# cat /sys/bus/pci/devices/<PCI device>/numa_node

Why might `i2c_smbus_write_byte_data` be returning "Operation not permitted" on uClinux 2.4?

I am writing a C program with the aim of configuring a peripheral device (the CS5368 ADC) via the I2C interface of a Dante Brooklyn II, a board based on a Microblaze soft-core processor running uClinux 2.4.
I have implemented the configuration following the Dante OEM docs for guidance, however when running my program I am encountering an "Operation not permitted" (EPERM) error when attempting to write data to I2C using i2c_smbus_write_byte_data.
Here is the section of code containing the culprit call to i2c_smbus_write_byte_data:
// Set ADC I2S to "Slave mode all speeds".
printf("Set the CS5368 I2S mode to slave\n");
unsigned char adc_dif = 0x01; // I2S mode
unsigned char adc_mode = 0x03; // Slave mode all speeds
unsigned char data = 0x90 | (adc_dif << 2) | adc_mode;
result = i2c_smbus_write_byte_data(i2c_fd, CS5368_GCTL_MDE, data);
if (result < 0) {
perror("Failed to write to the 'Global Mode Control' register");
return -1;
}
Here is the code within context of the full source of the small program. The program begins by resetting the CS5368 via a GPIO pin before doing the configuration via I2C.
EPERM is returned whether or not I have the CS5368 wired up. I've been able to successfully configure the CS5368 using the I2C interface of an Arduino Uno, so the issue does not appear to be related to the CS5368.
To run the program I login to the board via telnet as root, so I doubt the error has anything to do with user permissions.
The OEM docs state:
The Brooklyn II module can operate as an I2C controller running at
100Khz and using 7 bit addressing mode. It supports multi-master
operation. I2C devices can be accessed from user application running
on the Brooklyn II module. The interface supports the SMBus (System
Management Bus) protocol, which is a subset from the I2C protocol.
It goes on to list the supported i2c_smbus_* functions including i2c_smbus_write_byte_data, so the issue does not appear to be related to lack of support for SMBus or I2C.
I came across a related issue where a user was getting an EPERM error code when attempting to use the I2C write API, however the solution appears to have been to use the i2c_smbus_* API instead which I am already doing.
Any advice on what could be causing this error code to be returned or how to debug the issue further would be greatly appreciated!
Edit: In case it helps, here is the full output, starting from logging onto the board via telnet after having moved the exe to /tmp via ftp:
$ telnet 169.254.72.245
Trying 169.254.72.245...
Connected to 169.254.72.245.
Escape character is '^]'.
login: root
Password:
BusyBox v1.23.2 (2018-05-31 11:33:18 AEST) hush - the humble shell
/ # cd /tmp
/var/tmp # ./cs5368-i2c-config
Open GPIO device
Set GPIO tristate outputs
Set GPIO pins low
Sleep for 10 secs
Set GPIO pins high
Close GPIO file descriptor
Searching for I2C device
Opening /dev/i2c-0
Setting I2C_SLAVE 4c...
I2C Interface found: /dev/i2c-0
Set the CS5368 as the slave
Set the CS5368 I2S mode to slave
Failed to write to the 'Global Mode Control' register: Operation not permitted

IP_ADD_MEMBERSHIP fails when set both on interface and its subinterface; is that expected?

I'm debugging a 3rd-party network application and trying to figure out why it reports errors when calling setsockopt with IP_ADD_MEMBERSHIP to set up a multicast group. The application is in C++, but I've written an MWE in python that replicates the same syscalls:
import socket
import struct
ETH0_IP = "192.168.88.85"
ETH0_1_IP = "192.168.88.254"
MULTICAST_IP = "224.0.0.7"
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
ip = socket.inet_aton(ETH0_IP)
s.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, ip)
group = struct.pack("4s4s", socket.inet_aton(MULTICAST_IP), ip)
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group)
# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
ip2 = socket.inet_aton(ETH0_1_IP)
s2.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_IF, ip2)
group2 = struct.pack("4s4s", socket.inet_aton(MULTICAST_IP), ip2)
# the second group is added to the first socket so that we can only bind to one socket and read data from it
s.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, group2)
At the second IP_ADD_MEMBERSHIP call I get error OSError: [Errno 98] Address already in use.
I found out this only happens when ETH0_1_IP is a subinterface of ETH_0_IP. And I'm not sure if this is expected. If it is, is there a way to actually detect this situation and discard subinterfaces of already bound interfaces? Further, would my multicast socket receive data sent to the subinterface if registration for it fails with the above error?
For the sake of completeness:
$ cat /etc/network/interfaces
auto lo
iface lo inet loopback
iface lo inet6 loopback
auto eth0:1
iface eth0:1 inet static
address 192.168.88.254
netmask 255.255.240.0
Linux is tracking your alias interface as the same interface and so rejecting the attempt to re-use the interface.
In a bit more detail, I have run your code successfully on CentOS 7 using two separate physical interfaces with no changes. If I then change the code to use an alias on the same physical address, it fails with the same error that you see.
Digging a little further, I see that if I dump the interface indeces (using SIOCGIFINDEX) for the physical adaptor and the alias, they do indeed have the same index.
If you want to use Python to check this for yourself, have a quick look at https://gist.github.com/firaxis/0e538c8e5f81eaa55748acc5e679a36e for some code (missing imports of ctypes and socket) and then try something like this:
print(Interface(name="eth0").index)
print(Interface(name="eth0:1").index)

OS detection using nmap for a particular IP address

I am trying to determine the OS of a particular IP address using nmap. Here is my code so far:
import java.io.*;
public class NmapFlags {
public static void main(String[] args) throws Exception {
try {
String[] cmdarray = { "nmap", "-O", "66.110.59.130" };//
// example trying to find the OS or device detials of this Ip address//
Process process = Runtime.getRuntime().exec(cmdarray);
BufferedReader r = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String s;
while ((s = r.readLine()) != null) {
System.out.println(s);
}
r.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
After running this code output I got is:
All 1000 scanned ports on 66.110.59.130 are filtered
All 1000 scanned ports on 66.110.59.130 are filtered
Too many fingerprints match this host to give specific OS details
Too many fingerprints match this host to give specific OS details
OS detection performed. Please report any incorrect results at http://nmap.org/submit/ .
OS detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 246.06 seconds
Nmap done: 1 IP address (1 host up) scanned in 246.06 seconds**
Are there any other nmap flags I can use to detect the device type? I tried -A option. I need to find the device details at each hop of trace route.
Nmap performs “active fingerprinting” (it sends packets then analyse the response) to guess what the remote Operating System is. These probes are quite intrusive and I‘d recommend reading more about it (http://nmap.org/book/osdetect-fingerprint-format.html).
"Too many fingerprints match this host to give specific OS details" means that the probes are contradictory or too broad.
For example in a NAT scenario, some port scans return the router information (e.q. Cisco iOS), some other probes return the real host specifications (e.q. Windows).
The best way to understand how the network is designed is to rely on your own judgment based on different probes and output.
IP ID sequence, fingerprint analysis and service detection (-sV) can help:
e.q. If 3389 is open, then the OS running is a Windows.
e.q. if IP ID sequence varies then the target might be multiple (Load balanced).
Your analysis of the network traffic will always be more accurate than what nmap attempt to guess in an automated way.

Lua Socket cannot be properly stopped by Ctrl+C

I have a standalone lua script that uses lua sockets to connect to a server via TCP IP. It uses receive call to receive data from that server. It works, however, when I try to stop it with Ctrl+C, one of the two scenarios is happening:
-If there is currently no traffic and receive is waiting, Ctrl+C will have no effect. The program will continue to run, and will have to be terminated by kill.
-If there is traffic, the program will exit with the below printout and with the socket still open and with the server not accepting another connection:
lua: luaSocketTest.lua:15: interrupted!
stack traceback:
[C]: in function 'receive'
luaSocketTest.lua:15: in function 'doWork'
luaSocketTest.lua:22: in main chunk
[C]: ?
I tried using pcall to solve the second scenario, without success. pcall doesn't return, the process still throws the error.
Sample of my program is below:
local socket = require ("socket")
local ip = "localhost"
local port = 5003
function doWork ()
print ("Starting socket: "..ip..":"..port)
client = assert(socket.connect(ip, port))
print ("Socket Accepted")
client:send("TEST TEST")
while 1 do
local byte, err = client:receive (1)
if not err then
print (byte)
end
end
end
while 1 do
local status = pcall(doWork())
print ("EXITED PCALL WITH STATUS: "..tostring(status))
if not status then client:close() end
end
This would be quite a change, but you could employ lua-ev. It allows to add Signal handlers, which is exactly what is required to react to ctrl-c.
local socket = require'socket'
-- make connect and send in blocking mode
local client = socket.connect(ip,port)
client:send('TEST TEST')
-- make client non-blocking
client:settimeout(0)
ev.IO.new(function()
repeat
local data,err,part = client:receive(10000)
print('received',data or part)
until err
end,client:getfd(),ev.READ):start(ev.Loop.default)
local ev = require'ev'
local SIGINT = 2
ev.Signal.new(function()
print('SIGINT received')
end,SIGINT):start(ev.Loop.default)
ev.Loop.default:loop()