QNX Networking (io-pkt & QNET)
About 1284 wordsAbout 4 min
2026-03-25
Networking Architecture
QNX networking is implemented entirely in user space by the io-pkt (I/O Packet) stack — a user-space TCP/IP implementation derived from NetBSD's networking code. This gives it:
- Full BSD socket API compatibility
- User-space fault isolation (io-pkt crashes don't take down the kernel)
- Dynamically loadable protocol and driver modules
- True POSIX sockets
Application
│ socket() / connect() / send() / recv()
▼
C Library (POSIX socket API)
│ MsgSend → io-pkt resource manager
▼
io-pkt-v6-hc Process
│ [TCP/IP stack: BSD-derived — IPv4, IPv6, TCP, UDP, SCTP, ICMP]
│ [Protocol modules: dll/devnp-*.so]
▼
NIC Driver Module (devn-*.so or devnp-*.so)
│ hardware DMA
▼
Network Hardware (GbE, Wi-Fi, etc.)Starting io-pkt
# Start the network stack (IPv4 + IPv6, high-capacity variant)
io-pkt-v6-hc &
# Start with a specific NIC driver
io-pkt-v6-hc -d /lib/dll/devnp-speedo.so &
# For embedded boards with onboard GbE (e.g., NXP i.MX8):
io-pkt-v6-hc -d fec address=0x30BE0000,irq=118 &
# Multiple NICs on one io-pkt instance
io-pkt-v6-hc \
-d /lib/dll/devnp-speedo.so \
-d /lib/dll/devnp-e1000.so &io-pkt Variants
| Binary | Description |
|---|---|
io-pkt-v6-hc | IPv4 + IPv6 + high capacity (default for SDP 7.x+) |
io-pkt-v4-hc | IPv4 only + high capacity |
io-pkt-v6 | IPv4 + IPv6 (standard capacity) |
Network Configuration
Static IP Configuration
# Configure network interface en0 with static IP
ifconfig en0 192.168.1.100 netmask 255.255.255.0 up
# Add default gateway
route add default 192.168.1.1
# Add DNS (edit /etc/resolv.conf or set via DHCP)
echo "nameserver 8.8.8.8" >> /etc/resolv.confDHCP Client
# Start DHCP client on en0
dhclient en0
# Or use the built-in QNX DHCP client
dhcpcd en0
# Auto-configure (common in BSP startup scripts)
if_up en0
dhcp_start en0Showing Interface Status
ifconfig -a # show all interfaces
ifconfig en0 # show en0 details
netstat -rn # routing table
netstat -an # all sockets
netstat -s # protocol statisticsExample ifconfig en0 output:
en0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
address: 00:11:22:33:44:55
media: Ethernet autoselect (1000baseT full-duplex)
inet 192.168.1.100 netmask 0xffffff00 broadcast 192.168.1.255
inet6 fe80::211:22ff:fe33:4455%en0 prefixlen 64 scopeid 0x1POSIX Socket Programming
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
/* ── TCP Server ─────────────────────────────────────────────────── */
int server_fd = socket(AF_INET, SOCK_STREAM, 0);
int opt = 1;
setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
.sin_port = htons(8080),
};
bind(server_fd, (struct sockaddr *)&addr, sizeof(addr));
listen(server_fd, 5);
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
char buf[1024];
recv(client_fd, buf, sizeof(buf), 0);
send(client_fd, "OK\n", 3, 0);
close(client_fd);
close(server_fd);
/* ── UDP Client ─────────────────────────────────────────────────── */
int sock = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in dest = {
.sin_family = AF_INET,
.sin_port = htons(9000),
};
inet_pton(AF_INET, "192.168.1.200", &dest.sin_addr);
sendto(sock, "ping", 4, 0, (struct sockaddr *)&dest, sizeof(dest));
close(sock);
/* ── IPv6 TCP Client ─────────────────────────────────────────────── */
int fd = socket(AF_INET6, SOCK_STREAM, 0);
struct sockaddr_in6 addr6 = {
.sin6_family = AF_INET6,
.sin6_port = htons(443),
};
inet_pton(AF_INET6, "2001:db8::1", &addr6.sin6_addr);
connect(fd, (struct sockaddr *)&addr6, sizeof(addr6));Non-Blocking I/O and select()/poll()
#include <sys/select.h>
#include <poll.h>
#include <fcntl.h>
/* Set socket non-blocking */
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
/* poll(): wait on multiple fds */
struct pollfd fds[2];
fds[0].fd = server_fd;
fds[0].events = POLLIN;
fds[1].fd = pipe_read_end;
fds[1].events = POLLIN;
int ret = poll(fds, 2, 5000); /* 5 second timeout */
if (ret > 0) {
if (fds[0].revents & POLLIN) accept_connection();
if (fds[1].revents & POLLIN) read_pipe_data();
}
/* select() */
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(server_fd, &readfds);
struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
select(server_fd + 1, &readfds, NULL, NULL, &tv);Unix Domain Sockets
#include <sys/un.h>
/* Server */
int srv = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un su;
memset(&su, 0, sizeof(su));
su.sun_family = AF_UNIX;
strncpy(su.sun_path, "/tmp/myapp.sock", sizeof(su.sun_path) - 1);
unlink(su.sun_path);
bind(srv, (struct sockaddr *)&su, SUN_LEN(&su));
listen(srv, 5);
/* Client */
int cli = socket(AF_UNIX, SOCK_STREAM, 0);
connect(cli, (struct sockaddr *)&su, SUN_LEN(&su));
send(cli, "hello", 5, 0);NIC Driver Modules (devnp-*.so)
QNX uses loadable NIC driver modules rather than compiled-in drivers:
| Driver Module | Hardware |
|---|---|
devnp-speedo.so | Intel Pro/100 (Speedo) |
devnp-e1000.so | Intel Pro/1000 (GbE) |
devnp-bcm*.so | Broadcom GbE |
devnp-fec.so | NXP FEC (Freescale Fast Ethernet) |
devnp-dwcgmac.so | Synopsys DesignWare GbE |
devnp-mxgebc.so | Myricom 10 GbE |
devnp-ath.so | Atheros Wi-Fi |
io-pkt Driver Options
# Load with driver-specific options
io-pkt-v6-hc -d /lib/dll/devnp-e1000.so \
"ioaddr=0xe0000000,irq=11,speed=1000,duplex=full" &
# Specify multiple driver instances (multiple NICs)
io-pkt-v6-hc \
-d "/lib/dll/devnp-fec.so address=0x30BE0000,irq=118,phy=0" \
-d "/lib/dll/devnp-fec.so address=0x30BF0000,irq=119,phy=1" &
# After startup, configure each interface
ifconfig fec0 192.168.1.100/24 up
ifconfig fec1 10.0.0.1/8 upQNX Native Networking: QNET
QNET (QNX Transparent Distributed Processing) is QNX's native network protocol that makes remote processes appear local. It extends the QNX IPC model across a network:
Node A Node B
─────────── ───────────
My program Remote server
│ │
│ ConnectAttach( │
│ remote_nd, ← node descriptor │
│ server_pid, │
│ server_chid) │
│ │
│ MsgSend(coid, ...) ══════════════► MsgReceive()
◄══════════════════════════════════ MsgReply()# Load QNET support
npm-qnet &
# Show connected QNET nodes
ls /net/
# Output: node1, 192.168.1.101, myserver
# Connect to a remote node
cd /net/192.168.1.101/
# Open a remote file
cat /net/192.168.1.101/tmp/logfile.txt
# Run a program on remote node using on utility
on /net/192.168.1.101 ls -la /
# In C: get node descriptor for remote node
uint32_t nd = netmgr_remote_nd(NETMGR_ND_LOCAL_NODE, "192.168.1.101");
int coid = ConnectAttach(nd, remote_pid, remote_chid,
_NTO_SIDE_CHANNEL, 0);
MsgSend(coid, &msg, sizeof(msg), &reply, sizeof(reply));Firewall / Packet Filtering
QNX uses a BSD-derived packet filter (pf) or ipf for firewalling:
# Enable IP forwarding (for NAT/router use)
sysctl -w net.inet.ip.forwarding=1
# IPFilter rules (similar to Linux iptables)
# Edit /etc/ipf.conf
# Block all incoming except SSH:
# block in all
# pass in proto tcp from any to any port = 22 keep state
# Load rules
ipf -f /etc/ipf.conf
# NAT configuration (/etc/ipnat.conf)
# map en0 192.168.2.0/24 -> 0/32
# Apply NAT
ipnat -f /etc/ipnat.confNetwork Namespaces (SDP 8.0)
QNX SDP 8.0 supports separate network namespace instances for container-like isolation:
# Create a second isolated network stack instance
io-pkt-v6-hc -p /dev/io-net2 -d devnp-e1000.so &
# Configure the second instance
nicinfo -p /dev/io-net2 en0
ifconfig -p /dev/io-net2 en0 10.1.0.1/24 upNetwork Diagnostics Tools
# Ping
ping 192.168.1.1
ping6 fe80::1%en0
# Trace route
traceroute 8.8.8.8
# DNS lookup
nslookup google.com
host google.com
# Netstat
netstat -rn # routing table
netstat -an # all connections + listening sockets
netstat -s # per-protocol statistics
netstat -i # interface statistics
# Interface statistics
nicinfo # QNX NIC statistics tool
nicinfo en0 # specific interface
# Bandwidth test (requires netserver on target)
iperf3 -s & # server mode
iperf3 -c 192.168.1.1 # client, TCP throughput test
iperf3 -c 192.168.1.1 -u # UDP test
# Packet capture
tcpdump -i en0 -n port 8080
tcpdump -i en0 -w /tmp/capture.pcap
# Socket statistics
fstat # open files + sockets per processSCTP Support
QNX io-pkt supports SCTP (Stream Control Transmission Protocol) for multi-homed, multi-stream reliable transport:
#include <sys/socket.h>
#include <netinet/sctp.h>
int fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
struct sctp_initmsg init = {
.sinit_num_ostreams = 5,
.sinit_max_instreams = 5,
.sinit_max_attempts = 3,
};
setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(init));
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons(9900),
.sin_addr.s_addr = INADDR_ANY,
};
bind(fd, (struct sockaddr *)&addr, sizeof(addr));
listen(fd, 5);Summary: io-pkt vs QNET
| Feature | io-pkt (TCP/IP) | QNET |
|---|---|---|
| Protocol | TCP/IP, UDP, IPv4/IPv6 | QNX native protocol |
| API | POSIX sockets | QNX IPC (ConnectAttach) |
| Transparency | No (need to know IP:port) | Yes (same as local IPC) |
| Transport | Ethernet, Wi-Fi, serial | Any io-pkt-enabled link |
| Firewall | pf/ipf | None (OS-level only) |
| Use case | Internet/LAN communication | QNX-to-QNX node IPC |
| Priority-aware | No | Yes (IPC priorities preserved) |