+++ /dev/null
-# 01
-
-```shell
-
--------------------------
-| |
-| |
-| host network |
-| veth01 |
-| | |
-| | |
-------------|-------------
- |
- |
-------------|---------------
-| | |
-| | |
-| veth02 |
-| namespaced network |
-| |
-| |
----------------------------
-
-
-```
-
-# 02
-
-
-```shell
-
-[Apr 6 05:18] entered xmit
-[ +0.000010] entered hw tx
-[ +0.000003] kxfrm: ipproto ESP
-[ +0.000002] kxfrm: spi: 01000000
-[ +0.000005] kxfrm: got xfrm state
-[ +0.000001] kxfrm: totlen: 154: esplen: 96: payloadlen: 80
-[ +0.000004] esp: spi: 01000000
-[ +0.000003] esp: seq: 00000010
-[ +0.000002] aalgname: hmac(sha256)
-[ +0.000003] aalg key start: AABBCCDD
-[ +0.000003] ealgname: cbc(aes)
-[ +0.000002] ealg key start: AABBCCDD
-[ +0.000002] kxfrm: got nonce
-[ +0.000002] kxfrm: nonce: A6A34725
-[ +0.000035] hmac: 582E5B00
-[ +0.000002] calc hmac: 582E5B00
-[ +0.000003] kxfrm: hmac verification success
-[ +0.000010] kxfrm: decrypt success
-[ +0.000002] decap ip src: 0aa84201
-[ +0.000002] decap ip dst: 0aa84202
-[ +0.000002] decap ip data len: 66
-[ +0.000002] decap pad exists:
-[ +0.000001] ==========PAD START==========
-[ +0.000002] 1
-[ +0.000002] 2
-[ +0.000002] 3
-[ +0.000001] 4
-[ +0.000002] 5
-[ +0.000002] 6
-[ +0.000001] 7
-[ +0.000002] 8
-[ +0.000001] 9
-[ +0.000002] 10
-[ +0.000002] 11
-[ +0.000001] 12
-[ +0.000002] ==========PAD END==========
-[ +0.000002] total padlen: 12
-[ +0.000002] next header: 4
-[ +0.000002] decap ip padded data len: 80
-[ +0.000001] dec ip proto tcp: dst port: 09999
-[ +0.000003] 9999: data: \x01\x01\x08
- \x9a\x8c?t\x0e\x05/\xc2helloxfrm!!!!
- \x01\x02\x03\x04\x05\x06\x07\x08
-
-
-
- \x04
-[ +0.000002] kxfrm: reencrpyted
-[ +0.000002] kxfrm: reencrypted result match
-[ +0.000007] kxfrm: hmac recalculated
-[ +0.000002] kxfrm: copied generated values
-[ +0.000001] kxfrm: old ipcsum: EDA0
-[ +0.000002] kxfrm: new ipcsum: EDA0
-[ +0.000002] kxfrm: success
-
-```
-
-# 03
-
-
-```shell
-
-# the moment you insert the kernel module
-# using `insmod deth.ko`
-
-# this function will initiate
-# two ethernet interfaces
-# and invokes...
-deth_init_module
- |
- | # ...this function
- | # which sets up
- | # data structures and
- | # operations for each interface
- | # and registers..
- --------> deth_setup
- |
- | #... this function
- | # which sets MAC address and
- | # enable NAPI for RX
- --------> deth_open
- |
- | #... and this function
- | # which is used
- | # to send packet to the other end
- --------> deth_xmit
- # ... and few others
-
-
-```
-
-# 04
-
-
-```
-
----------------------------
-| |
-| |
-| host network |
-| deth1 |
-| (192.168.10.1/24) |
-| | |
-| | |
-------------|--------------
- |
- |
-------------|--------------
-| | |
-| | |
-| (192.168.10.2/24) |
-| deth2 |
-| vnet network |
-| |
-| |
----------------------------
-
-
-
-
-```
-
-# 05
-
-
-```shell
-
-# the moment you connect (or send)
-# from your client on host to the server
-# on the vnet namespace,
-# this function triggers...
-deth_xmit
- |
- | # ...this function
- | # which prints eth src,dst
- | # checks protocol,
- | # prints ip src, dst
- | # get the device pointer of the other end
- | # and invokes...
- ---------> deth_hw_tx
- |
- | # ... this function
- | # to get the tx slot of sender interface
- ----> deth_tx_cons_buffer
- | # ... this function
- | # to set the rx slot of receiver interface
- ----> deth_rx_prod_buffer
- | # ... this function
- | # to trigger the receiver interface
- | # to start napi polling (receiving)
- ----> deth_interrupt(deth_napi_interrupt)
-
-# and here, this is what happens
-# when deth_napi_interrupt is triggered
-# this function, if real network interface card was used,
-# will be triggerd as actual hardware irq is fired
-# after registering using request_irq function.
-# however, since there is no real nic involved in this scenario
-# this function is manually triggered by calling deth_interrupt
-# within hw_tx
-# this function invokes...
-deth_napi_interrupt
- |
- | # ...this function if statusword is RX_INTR
- ----> napi_schedule
-
-# and here, this is what happens
-# when napi_schedule is triggered
-# this function start...
-napi_schedule
- |
- | # ...this function
- | # which is registered using netif_napi_add_weight
- | # within deth_setup
- | # this is the receiving logic
- | # this invokes....
- ----> deth_poll
- |
- | # ... this function
- | # which gets the packet set within hw_tx
- ----> deth_rx_cons_buf
- |
- | # ... and this function
- | # which frees up the space for another
- | # transmission by the sending side
- ----> deth_tx_release_buffer
-
-
-
-```
\ No newline at end of file
+++ /dev/null
-obj-m += deth.o
-
-all:
- make -C /lib/modules/`uname -r`/build M=`pwd` modules
-
-clean:
- make -C /lib/modules/`uname -r`/build M=`pwd` clean
\ No newline at end of file
+++ /dev/null
-
-#include "deth.h"
-
-
-
-struct net_device *deth_devs[DRV_COUNT];
-struct deth_priv *deth_privs[DRV_COUNT];
-int setup_ptr= 0;
-
-
-int lockup = 0;
-int timeout = DETH_TIMEOUT;
-int pool_size = 8;
-
-
-void (*deth_interrupt)(int, void *, struct pt_regs *);
-
-
-void deth_setup_pool(struct net_device *dev){
-
- struct deth_priv *priv = netdev_priv(dev);
- int i;
- struct deth_packet *pkt;
-
- priv->ppool = NULL;
- for (i = 0; i < pool_size; i++) {
- pkt = kmalloc (sizeof (struct deth_packet), GFP_KERNEL);
- if (pkt == NULL) {
- printk (KERN_INFO "out of memory allocating packet pool\n");
- return;
- }
- pkt->dev = dev;
- pkt->next = priv->ppool;
- priv->ppool = pkt;
- }
-
-
-}
-
-
-void deth_teardown_pool(struct net_device *dev){
-
- struct deth_priv *priv = netdev_priv(dev);
- struct deth_packet *pkt;
-
- while ((pkt = priv->ppool)) {
- priv->ppool = pkt->next;
- kfree (pkt);
- }
-}
-
-
-struct deth_packet *deth_tx_cons_buffer(struct net_device *dev){
-
- struct deth_priv *priv = netdev_priv(dev);
- unsigned long flags;
- struct deth_packet *pkt;
-
- spin_lock_irqsave(&priv->lock, flags);
- pkt = priv->ppool;
- if(!pkt) {
- printk (KERN_INFO "out of pool\n");
- return pkt;
- }
- priv->ppool = pkt->next;
- if (priv->ppool == NULL) {
- printk (KERN_INFO "pool empty\n");
- netif_stop_queue(dev);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- return pkt;
-
-
-}
-
-void deth_tx_release_buffer(struct deth_packet *pkt){
-
- unsigned long flags;
- struct deth_priv *priv = netdev_priv(pkt->dev);
-
- spin_lock_irqsave(&priv->lock, flags);
- pkt->next = priv->ppool;
- priv->ppool = pkt;
- spin_unlock_irqrestore(&priv->lock, flags);
- if (netif_queue_stopped(pkt->dev) && pkt->next == NULL){
-
- netif_wake_queue(pkt->dev);
- }
-
-
-}
-
-void deth_rx_prod_buf(struct net_device *dev, struct deth_packet *pkt){
-
- unsigned long flags;
- struct deth_priv *priv = netdev_priv(dev);
-
- spin_lock_irqsave(&priv->lock, flags);
- pkt->next = priv->rx_queue;
- priv->rx_queue = pkt;
- spin_unlock_irqrestore(&priv->lock, flags);
-
-
-}
-
-
-
-struct deth_packet *deth_rx_cons_buf(struct net_device *dev){
-
- struct deth_priv *priv = netdev_priv(dev);
- struct deth_packet *pkt;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- pkt = priv->rx_queue;
- if (pkt != NULL){
- priv->rx_queue = pkt->next;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- return pkt;
-
-}
-
-void deth_rx_ints(struct net_device *dev, int enable){
-
- struct deth_priv *priv = netdev_priv(dev);
- priv->rx_int_enabled = enable;
-}
-
-
-
-
-void deth_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs){
-
- printk(KERN_INFO "napi interrupt\n");
-
- int statusword;
- struct deth_priv *priv;
-
-
- struct net_device *dev = (struct net_device *)dev_id;
-
- if (!dev){
- printk(KERN_INFO "invalid dev\n");
- return;
- }
-
- priv = netdev_priv(dev);
- spin_lock(&priv->lock);
-
-
- statusword = priv->status;
- priv->status = 0;
- if (statusword & DETH_RX_INTR) {
- printk(KERN_INFO "napi receive\n");
- napi_schedule(&priv->napi);
- }
- if (statusword & DETH_TX_INTR) {
- printk(KERN_INFO "napi transmit\n");
- priv->stats.tx_packets++;
- priv->stats.tx_bytes += priv->tx_packetlen;
- if(priv->skb) {
- dev_kfree_skb(priv->skb);
- priv->skb = 0;
- }
- }
-
- printk(KERN_INFO "napi interrupt end\n");
-
- spin_unlock(&priv->lock);
- return;
-}
-
-
-int deth_poll(struct napi_struct *napi, int budget){
-
-
- int npackets = 0;
- struct sk_buff *skb;
- struct deth_priv *priv = container_of(napi, struct deth_priv, napi);
- struct net_device *dev = priv->dev;
- struct deth_packet *pkt;
-
- printk(KERN_INFO "polling\n");
-
- while (npackets < budget && priv->rx_queue) {
- pkt = deth_rx_cons_buf(dev);
- skb = dev_alloc_skb(NET_IP_ALIGN + pkt->datalen);
- if (! skb) {
- if (printk_ratelimit()){
- printk(KERN_INFO "deth: packet dropped\n");
- }
- priv->stats.rx_dropped++;
- npackets++;
- deth_tx_release_buffer(pkt);
- continue;
- }
- skb_reserve(skb, NET_IP_ALIGN);
- memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- netif_receive_skb(skb);
-
- npackets++;
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += pkt->datalen;
- deth_tx_release_buffer(pkt);
- }
-
- printk(KERN_INFO "polling done\n");
-
- if (npackets < budget) {
- printk(KERN_INFO "npackets smaller than budget\n");
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- if (napi_complete_done(napi, npackets)){
- printk(KERN_INFO "napi complete\n");
- //deth_rx_ints(dev, 1);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- }
-
- printk(KERN_INFO "polling end\n");
-
- return npackets;
-
-}
-
-
-
-netdev_tx_t deth_xmit(struct sk_buff *skb, struct net_device *dev){
-
- printk("entered xmit\n");
-
- int len;
- char *data, shortpkt[ETH_ZLEN];
- struct deth_priv *priv = netdev_priv(dev);
-
- data = skb->data;
- len = skb->len;
- if (len < ETH_ZLEN) {
- memset(shortpkt, 0, ETH_ZLEN);
- memcpy(shortpkt, skb->data, skb->len);
- len = ETH_ZLEN;
- data = shortpkt;
- }
- netif_trans_update(dev);
-
- priv->skb = skb;
-
- deth_hw_tx(data, len, dev);
-
- printk("exiting xmit\n");
-
- return 0;
-
-
-}
-
-
-void deth_hw_tx(char *buf, int len, struct net_device *dev){
-
-
- printk(KERN_INFO "entered hw tx\n");
-
- struct ethhdr *eh;
- struct iphdr *ih;
- struct udphdr *uh;
- struct tcphdr *th;
-
- struct net_device *dest;
- struct deth_priv *priv;
- u16 sport;
- u16 dport;
- struct deth_packet *tx_buffer;
-
- if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
- printk("deth: packet too short (%i octets)\n",
- len);
- return;
- }
-
-
- eh = (struct ethhdr*)buf;
-
- ih = (struct iphdr*)(buf + sizeof(struct ethhdr));
-
-
- printk("eth src: %02X:%02X:%02X:%02X:%02X:%02X\n",
- eh->h_source[0],
- eh->h_source[1],
- eh->h_source[2],
- eh->h_source[3],
- eh->h_source[4],
- eh->h_source[5]);
- printk("eth dst: %02X:%02X:%02X:%02X:%02X:%02X\n",
- eh->h_dest[0],
- eh->h_dest[1],
- eh->h_dest[2],
- eh->h_dest[3],
- eh->h_dest[4],
- eh->h_dest[5]);
-
-
- if(ih->protocol == IPPROTO_UDP){
-
- uh = (struct udphdr*)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
-
- sport = ntohs(uh->source);
- dport = ntohs(uh->dest);
-
- } else if (ih->protocol == IPPROTO_TCP){
-
- th = (struct tcphdr*)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
-
- sport = ntohs(th->source);
- dport = ntohs(th->dest);
-
- }
-
- printk("src: %08x:%05i\n",
- ntohl(ih->daddr), sport);
-
- printk("dst: %08x:%05i\n",
- ntohl(ih->daddr), dport);
-
- dest = deth_devs[dev == deth_devs[0] ? 1 : 0];
- priv = netdev_priv(dest);
-
- tx_buffer = deth_tx_cons_buffer(dev);
-
- if(!tx_buffer) {
- printk(KERN_INFO "out of tx buffer, len is %i\n",len);
- return;
- }
-
- tx_buffer->datalen = len;
- memcpy(tx_buffer->data, buf, len);
- deth_rx_prod_buf(dest, tx_buffer);
- if (priv->rx_int_enabled) {
-
- priv->status |= DETH_RX_INTR;
- deth_interrupt(0, dest, NULL);
- }
-
- priv = netdev_priv(dev);
- priv->tx_packetlen = len;
- priv->tx_packetdata = buf;
- priv->status |= DETH_TX_INTR;
- if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) {
-
- netif_stop_queue(dev);
- printk(KERN_INFO "simulate lockup at %ld, txp %ld\n", jiffies, (unsigned long) priv->stats.tx_packets);
-
- } else{
-
- deth_interrupt(0, dev, NULL);
- }
-
-
-}
-
-
-
-
-int deth_open(struct net_device *dev){
-
- if (dev == deth_devs[1]){
-
- memcpy((void*)dev->dev_addr, "DETH01", ETH_ALEN);
-
-
- } else {
-
- memcpy((void*)dev->dev_addr, "DETH00", ETH_ALEN);
- }
-
- struct deth_priv *priv = netdev_priv(dev);
- napi_enable(&priv->napi);
-
- netif_start_queue(dev);
-
- printk(KERN_INFO "started deth\n");
-
- return 0;
-}
-
-int deth_stop(struct net_device *dev){
-
- netif_stop_queue(dev);
-
- struct deth_priv *priv = netdev_priv(dev);
- napi_disable(&priv->napi);
-
- return 0;
-
- printk(KERN_INFO "stopped deth\n");
-}
-
-
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
-
-void deth_tx_timeout(struct net_device *dev)
-
-#else
-
-void deth_tx_timeout(struct net_device *dev, unsigned int txqueue)
-
-#endif
-
-{
- struct deth_priv *priv = netdev_priv(dev);
- struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
-
- printk(KERN_INFO "transmit timeout at %ld, latency %ld\n", jiffies,
- jiffies - txq->trans_start);
-
- priv->status |= DETH_TX_INTR;
- deth_interrupt(0, dev, NULL);
- priv->stats.tx_errors++;
-
- spin_lock(&priv->lock);
- deth_teardown_pool(dev);
- deth_setup_pool(dev);
- spin_unlock(&priv->lock);
-
- netif_wake_queue(dev);
- return;
-}
-
-
-
-const struct net_device_ops deth_netdev_ops = {
- .ndo_open = deth_open,
- .ndo_stop = deth_stop,
- .ndo_start_xmit = deth_xmit,
- .ndo_tx_timeout = deth_tx_timeout,
-};
-
-
-
-
-void deth_setup(struct net_device *dev){
-
- ether_setup(dev);
- dev->watchdog_timeo = timeout;
- dev->netdev_ops = &deth_netdev_ops;
- dev->features |= NETIF_F_HW_CSUM;
-
- deth_privs[setup_ptr] = netdev_priv(dev);
-
- memset(deth_privs[setup_ptr], 0, sizeof(struct deth_priv));
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
- netif_napi_add(dev, &(deth_privs[setup_ptr])->napi, deth_poll,2);
-#else
- netif_napi_add_weight(dev, &(deth_privs[setup_ptr])->napi, deth_poll,2);
-#endif
-
- spin_lock_init(&(deth_privs[setup_ptr])->lock);
- deth_privs[setup_ptr]->dev = dev;
-
- deth_rx_ints(dev, 1);
- deth_setup_pool(dev);
-
- setup_ptr += 1;
-
- printk(KERN_INFO "deth: setup success: %d\n", setup_ptr);
-}
-
-
-static int __init deth_init_module(void){
-
- int err;
-
- deth_interrupt = deth_napi_interrupt;
-
- deth_devs[0] = alloc_netdev(sizeof(struct deth_priv), "deth%d", NET_NAME_UNKNOWN, deth_setup);
- if (!deth_devs[0]){
- return -ENOMEM;
- }
-
- deth_devs[1] = alloc_netdev(sizeof(struct deth_priv), "deth%d", NET_NAME_UNKNOWN, deth_setup);
-
- if (!deth_devs[1]){
- return -ENOMEM;
- }
-
- err = register_netdevice(deth_devs[0]);
- if (err < 0) {
- goto err1;
- }
-
- err = register_netdevice(deth_devs[1]);
-
- if(err < 0) {
-
- goto err2;
- }
-
-
- return 0;
-
-err1:
-
- free_netdev(deth_devs[0]);
- return err;
-
-err2:
- free_netdev(deth_devs[0]);
- free_netdev(deth_devs[1]);
- return err;
-
-}
-
-
-
-static void __exit deth_cleanup_module(void)
-{
- int i;
-
- for (i = 0; i < DRV_COUNT; i++) {
- if (deth_devs[i]) {
- unregister_netdev(deth_devs[i]);
- deth_teardown_pool(deth_devs[i]);
- free_netdev(deth_devs[i]);
- }
- }
- return;
-}
-
-
-
-
-module_init(deth_init_module);
-module_exit(deth_cleanup_module);
-MODULE_LICENSE("GPL");
\ No newline at end of file
+++ /dev/null
-#ifndef _DETH_X_H_
-#define _DETH_X_H_
-
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/moduleparam.h>
-
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-
-#include <linux/skbuff.h>
-#include <linux/version.h>
-
-#include <linux/in6.h>
-#include <asm/checksum.h>
-
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <linux/udp.h>
-
-
-#define DRV_NAME "deth"
-#define DRV_COUNT 2
-
-
-#define DETH_RX_INTR 0x0001
-#define DETH_TX_INTR 0x0002
-
-
-#define DETH_TIMEOUT 5
-
-
-
-struct deth_packet {
- struct deth_packet *next;
- struct net_device *dev;
- int datalen;
- u8 data[ETH_DATA_LEN];
-};
-
-struct deth_priv {
- struct net_device_stats stats;
- int status;
- struct deth_packet *ppool;
- struct deth_packet *rx_queue;
- int rx_int_enabled;
- int tx_packetlen;
- u8 *tx_packetdata;
- struct sk_buff *skb;
- spinlock_t lock;
- struct net_device *dev;
- struct napi_struct napi;
-};
-
-
-extern struct net_device *deth_devs[DRV_COUNT];
-extern struct deth_priv *deth_privs[DRV_COUNT];
-extern int setup_ptr;
-
-extern const struct net_device_ops deth_netdev_ops;
-
-extern const struct header_ops deth_header_ops;
-
-extern int lockup;
-
-extern int timeout;
-
-extern int pool_size;
-
-extern void (*deth_interrupt)(int, void *, struct pt_regs *);
-
-
-
-void deth_setup_pool(struct net_device *dev);
-
-void deth_teardown_pool(struct net_device *dev);
-
-struct deth_packet *deth_tx_cons_buffer(struct net_device *dev);
-
-void deth_tx_release_buffer(struct deth_packet *pkt);
-
-void deth_rx_prod_buf(struct net_device *dev, struct deth_packet *pkt);
-
-struct deth_packet *deth_rx_cons_buf(struct net_device *dev);
-
-
-
-void deth_rx_ints(struct net_device *dev, int enable);
-
-void deth_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-int deth_poll(struct napi_struct *napi, int budget);
-
-
-
-netdev_tx_t deth_xmit(struct sk_buff *skb, struct net_device *dev);
-
-void deth_hw_tx(char *buf, int len, struct net_device *dev);
-
-
-int deth_open(struct net_device *dev);
-
-int deth_stop(struct net_device *dev);
-
-
-
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
-
-void deth_tx_timeout(struct net_device *dev);
-
-#else
-
-void deth_tx_timeout(struct net_device *dev, unsigned int txqueue);
-
-#endif
-
-
-/* module entry */
-
-void deth_setup(struct net_device *dev);
-
-#endif
\ No newline at end of file
+++ /dev/null
-#!/bin/bash
-
-sudo ip netns add vnet
-
-sudo ip link set deth1 netns vnet
-
-sudo ip addr add 192.168.10.1/24 dev deth0
-
-sudo ip link set dev deth0 up
-
-sudo ip netns exec vnet ip addr add 192.168.10.2/24 dev deth1
-
-sudo ip netns exec vnet ip link set dev deth1 up
-
+++ /dev/null
-#!/bin/bash
-
-
-sudo ip link set dev deth0 down
-
-sudo ip netns exec vnet ip link set dev deth1 down
-
-sudo ip addr del 192.168.10.1/24 dev deth0
-
-sudo ip netns exec vnet ip addr del 192.168.10.2/24 dev deth1
-
-sudo ip netns del vnet
-
-
-
-
--- /dev/null
+# 01
+
+```shell
+
+-------------------------
+| |
+| |
+| host network |
+| veth01 |
+| | |
+| | |
+------------|-------------
+ |
+ |
+------------|---------------
+| | |
+| | |
+| veth02 |
+| namespaced network |
+| |
+| |
+---------------------------
+
+
+```
+
+# 02
+
+
+```shell
+
+[Apr 6 05:18] entered xmit
+[ +0.000010] entered hw tx
+[ +0.000003] kxfrm: ipproto ESP
+[ +0.000002] kxfrm: spi: 01000000
+[ +0.000005] kxfrm: got xfrm state
+[ +0.000001] kxfrm: totlen: 154: esplen: 96: payloadlen: 80
+[ +0.000004] esp: spi: 01000000
+[ +0.000003] esp: seq: 00000010
+[ +0.000002] aalgname: hmac(sha256)
+[ +0.000003] aalg key start: AABBCCDD
+[ +0.000003] ealgname: cbc(aes)
+[ +0.000002] ealg key start: AABBCCDD
+[ +0.000002] kxfrm: got nonce
+[ +0.000002] kxfrm: nonce: A6A34725
+[ +0.000035] hmac: 582E5B00
+[ +0.000002] calc hmac: 582E5B00
+[ +0.000003] kxfrm: hmac verification success
+[ +0.000010] kxfrm: decrypt success
+[ +0.000002] decap ip src: 0aa84201
+[ +0.000002] decap ip dst: 0aa84202
+[ +0.000002] decap ip data len: 66
+[ +0.000002] decap pad exists:
+[ +0.000001] ==========PAD START==========
+[ +0.000002] 1
+[ +0.000002] 2
+[ +0.000002] 3
+[ +0.000001] 4
+[ +0.000002] 5
+[ +0.000002] 6
+[ +0.000001] 7
+[ +0.000002] 8
+[ +0.000001] 9
+[ +0.000002] 10
+[ +0.000002] 11
+[ +0.000001] 12
+[ +0.000002] ==========PAD END==========
+[ +0.000002] total padlen: 12
+[ +0.000002] next header: 4
+[ +0.000002] decap ip padded data len: 80
+[ +0.000001] dec ip proto tcp: dst port: 09999
+[ +0.000003] 9999: data: \x01\x01\x08
+ \x9a\x8c?t\x0e\x05/\xc2helloxfrm!!!!
+ \x01\x02\x03\x04\x05\x06\x07\x08
+
+
+
+ \x04
+[ +0.000002] kxfrm: reencrpyted
+[ +0.000002] kxfrm: reencrypted result match
+[ +0.000007] kxfrm: hmac recalculated
+[ +0.000002] kxfrm: copied generated values
+[ +0.000001] kxfrm: old ipcsum: EDA0
+[ +0.000002] kxfrm: new ipcsum: EDA0
+[ +0.000002] kxfrm: success
+
+```
+
+# 03
+
+
+```shell
+
+# the moment you insert the kernel module
+# using `insmod deth.ko`
+
+# this function will initiate
+# two ethernet interfaces
+# and invokes...
+deth_init_module
+ |
+ | # ...this function
+ | # which sets up
+ | # data structures and
+ | # operations for each interface
+ | # and registers..
+ --------> deth_setup
+ |
+ | #... this function
+ | # which sets MAC address and
+ | # enable NAPI for RX
+ --------> deth_open
+ |
+ | #... and this function
+ | # which is used
+ | # to send packet to the other end
+ --------> deth_xmit
+ # ... and few others
+
+
+```
+
+# 04
+
+
+```
+
+---------------------------
+| |
+| |
+| host network |
+| deth1 |
+| (192.168.10.1/24) |
+| | |
+| | |
+------------|--------------
+ |
+ |
+------------|--------------
+| | |
+| | |
+| (192.168.10.2/24) |
+| deth2 |
+| vnet network |
+| |
+| |
+---------------------------
+
+
+
+
+```
+
+# 05
+
+
+```shell
+
+# the moment you connect (or send)
+# from your client on host to the server
+# on the vnet namespace,
+# this function triggers...
+deth_xmit
+ |
+ | # ...this function
+ | # which prints eth src,dst
+ | # checks protocol,
+ | # prints ip src, dst
+ | # get the device pointer of the other end
+ | # and invokes...
+ ---------> deth_hw_tx
+ |
+ | # ... this function
+ | # to get the tx slot of sender interface
+ ----> deth_tx_cons_buffer
+ | # ... this function
+ | # to set the rx slot of receiver interface
+ ----> deth_rx_prod_buffer
+ | # ... this function
+ | # to trigger the receiver interface
+ | # to start napi polling (receiving)
+ ----> deth_interrupt(deth_napi_interrupt)
+
+# and here, this is what happens
+# when deth_napi_interrupt is triggered
+# this function, if real network interface card was used,
+# will be triggerd as actual hardware irq is fired
+# after registering using request_irq function.
+# however, since there is no real nic involved in this scenario
+# this function is manually triggered by calling deth_interrupt
+# within hw_tx
+# this function invokes...
+deth_napi_interrupt
+ |
+ | # ...this function if statusword is RX_INTR
+ ----> napi_schedule
+
+# and here, this is what happens
+# when napi_schedule is triggered
+# this function start...
+napi_schedule
+ |
+ | # ...this function
+ | # which is registered using netif_napi_add_weight
+ | # within deth_setup
+ | # this is the receiving logic
+ | # this invokes....
+ ----> deth_poll
+ |
+ | # ... this function
+ | # which gets the packet set within hw_tx
+ ----> deth_rx_cons_buf
+ |
+ | # ... and this function
+ | # which frees up the space for another
+ | # transmission by the sending side
+ ----> deth_tx_release_buffer
+
+
+
+```
\ No newline at end of file
--- /dev/null
+obj-m += deth.o
+
+all:
+ make -C /lib/modules/`uname -r`/build M=`pwd` modules
+
+clean:
+ make -C /lib/modules/`uname -r`/build M=`pwd` clean
\ No newline at end of file
--- /dev/null
+
+#include "deth.h"
+
+
+
+struct net_device *deth_devs[DRV_COUNT];
+struct deth_priv *deth_privs[DRV_COUNT];
+int setup_ptr= 0;
+
+
+int lockup = 0;
+int timeout = DETH_TIMEOUT;
+int pool_size = 8;
+
+
+void (*deth_interrupt)(int, void *, struct pt_regs *);
+
+
+void deth_setup_pool(struct net_device *dev){
+
+ struct deth_priv *priv = netdev_priv(dev);
+ int i;
+ struct deth_packet *pkt;
+
+ priv->ppool = NULL;
+ for (i = 0; i < pool_size; i++) {
+ pkt = kmalloc (sizeof (struct deth_packet), GFP_KERNEL);
+ if (pkt == NULL) {
+ printk (KERN_INFO "out of memory allocating packet pool\n");
+ return;
+ }
+ pkt->dev = dev;
+ pkt->next = priv->ppool;
+ priv->ppool = pkt;
+ }
+
+
+}
+
+
+void deth_teardown_pool(struct net_device *dev){
+
+ struct deth_priv *priv = netdev_priv(dev);
+ struct deth_packet *pkt;
+
+ while ((pkt = priv->ppool)) {
+ priv->ppool = pkt->next;
+ kfree (pkt);
+ }
+}
+
+
+struct deth_packet *deth_tx_reserve_buffer(struct net_device *dev){
+
+ struct deth_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+ struct deth_packet *pkt;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pkt = priv->ppool;
+ if(!pkt) {
+ printk (KERN_INFO "out of pool\n");
+ return pkt;
+ }
+ priv->ppool = pkt->next;
+ if (priv->ppool == NULL) {
+ printk (KERN_INFO "pool empty\n");
+ netif_stop_queue(dev);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return pkt;
+
+
+}
+
+void deth_tx_release_buffer(struct deth_packet *pkt){
+
+ unsigned long flags;
+ struct deth_priv *priv = netdev_priv(pkt->dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pkt->next = priv->ppool;
+ priv->ppool = pkt;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (netif_queue_stopped(pkt->dev) && pkt->next == NULL){
+
+ netif_wake_queue(pkt->dev);
+ }
+
+
+}
+
+void deth_rx_prod_buf(struct net_device *dev, struct deth_packet *pkt){
+
+ unsigned long flags;
+ struct deth_priv *priv = netdev_priv(dev);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pkt->next = priv->rx_queue;
+ priv->rx_queue = pkt;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+
+}
+
+
+
+struct deth_packet *deth_rx_cons_buf(struct net_device *dev){
+
+ struct deth_priv *priv = netdev_priv(dev);
+ struct deth_packet *pkt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ pkt = priv->rx_queue;
+ if (pkt != NULL){
+ priv->rx_queue = pkt->next;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return pkt;
+
+}
+
+void deth_rx_ints(struct net_device *dev, int enable){
+
+ struct deth_priv *priv = netdev_priv(dev);
+ priv->rx_int_enabled = enable;
+}
+
+
+
+
+void deth_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs){
+
+ printk(KERN_INFO "napi interrupt\n");
+
+ int statusword;
+ struct deth_priv *priv;
+
+
+ struct net_device *dev = (struct net_device *)dev_id;
+
+ if (!dev){
+ printk(KERN_INFO "invalid dev\n");
+ return;
+ }
+
+ priv = netdev_priv(dev);
+ spin_lock(&priv->lock);
+
+
+ statusword = priv->status;
+ priv->status = 0;
+ if (statusword & DETH_RX_INTR) {
+ printk(KERN_INFO "napi receive\n");
+ napi_schedule(&priv->napi);
+ }
+ if (statusword & DETH_TX_INTR) {
+ printk(KERN_INFO "napi transmit\n");
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += priv->tx_packetlen;
+ if(priv->skb) {
+ dev_kfree_skb(priv->skb);
+ priv->skb = 0;
+ }
+ }
+
+ printk(KERN_INFO "napi interrupt end\n");
+
+ spin_unlock(&priv->lock);
+ return;
+}
+
+
+int deth_poll(struct napi_struct *napi, int budget){
+
+
+ int npackets = 0;
+ struct sk_buff *skb;
+ struct deth_priv *priv = container_of(napi, struct deth_priv, napi);
+ struct net_device *dev = priv->dev;
+ struct deth_packet *pkt;
+
+ printk(KERN_INFO "polling\n");
+
+ while (npackets < budget && priv->rx_queue) {
+ pkt = deth_rx_cons_buf(dev);
+ skb = dev_alloc_skb(NET_IP_ALIGN + pkt->datalen);
+ if (! skb) {
+ if (printk_ratelimit()){
+ printk(KERN_INFO "deth: packet dropped\n");
+ }
+ priv->stats.rx_dropped++;
+ npackets++;
+ deth_tx_release_buffer(pkt);
+ continue;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_receive_skb(skb);
+
+ npackets++;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += pkt->datalen;
+ deth_tx_release_buffer(pkt);
+ }
+
+ printk(KERN_INFO "polling done\n");
+
+ if (npackets < budget) {
+ printk(KERN_INFO "npackets smaller than budget\n");
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
+ if (napi_complete_done(napi, npackets)){
+ printk(KERN_INFO "napi complete\n");
+ //deth_rx_ints(dev, 1);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ printk(KERN_INFO "polling end\n");
+
+ return npackets;
+
+}
+
+
+
+netdev_tx_t deth_xmit(struct sk_buff *skb, struct net_device *dev){
+
+ printk("entered xmit\n");
+
+ int len;
+ char *data, shortpkt[ETH_ZLEN];
+ struct deth_priv *priv = netdev_priv(dev);
+
+ data = skb->data;
+ len = skb->len;
+ if (len < ETH_ZLEN) {
+ memset(shortpkt, 0, ETH_ZLEN);
+ memcpy(shortpkt, skb->data, skb->len);
+ len = ETH_ZLEN;
+ data = shortpkt;
+ }
+ netif_trans_update(dev);
+
+ priv->skb = skb;
+
+ deth_hw_tx(data, len, dev);
+
+ printk("exiting xmit\n");
+
+ return 0;
+
+
+}
+
+
+void deth_hw_tx(char *buf, int len, struct net_device *dev){
+
+
+ printk(KERN_INFO "entered hw tx\n");
+
+ struct ethhdr *eh;
+ struct iphdr *ih;
+ struct udphdr *uh;
+ struct tcphdr *th;
+
+ struct net_device *dest;
+ struct deth_priv *priv;
+ u16 sport;
+ u16 dport;
+ struct deth_packet *tx_buffer;
+
+ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
+ printk("deth: packet too short (%i octets)\n",
+ len);
+ return;
+ }
+
+
+ eh = (struct ethhdr*)buf;
+
+ ih = (struct iphdr*)(buf + sizeof(struct ethhdr));
+
+
+ printk("eth src: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ eh->h_source[0],
+ eh->h_source[1],
+ eh->h_source[2],
+ eh->h_source[3],
+ eh->h_source[4],
+ eh->h_source[5]);
+ printk("eth dst: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ eh->h_dest[0],
+ eh->h_dest[1],
+ eh->h_dest[2],
+ eh->h_dest[3],
+ eh->h_dest[4],
+ eh->h_dest[5]);
+
+
+ if(ih->protocol == IPPROTO_UDP){
+
+ uh = (struct udphdr*)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
+
+ sport = ntohs(uh->source);
+ dport = ntohs(uh->dest);
+
+ } else if (ih->protocol == IPPROTO_TCP){
+
+ th = (struct tcphdr*)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
+
+ sport = ntohs(th->source);
+ dport = ntohs(th->dest);
+
+ }
+
+ printk("src: %08x:%05i\n",
+ ntohl(ih->daddr), sport);
+
+ printk("dst: %08x:%05i\n",
+ ntohl(ih->daddr), dport);
+
+ dest = deth_devs[dev == deth_devs[0] ? 1 : 0];
+ priv = netdev_priv(dest);
+
+ tx_buffer = deth_tx_reserve_buffer(dev);
+
+ if(!tx_buffer) {
+ printk(KERN_INFO "out of tx buffer, len is %i\n",len);
+ return;
+ }
+
+ tx_buffer->datalen = len;
+ memcpy(tx_buffer->data, buf, len);
+ deth_rx_prod_buf(dest, tx_buffer);
+ if (priv->rx_int_enabled) {
+
+ priv->status |= DETH_RX_INTR;
+ deth_interrupt(0, dest, NULL);
+ }
+
+ priv = netdev_priv(dev);
+ priv->tx_packetlen = len;
+ priv->tx_packetdata = buf;
+ priv->status |= DETH_TX_INTR;
+ if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) {
+
+ netif_stop_queue(dev);
+ printk(KERN_INFO "simulate lockup at %ld, txp %ld\n", jiffies, (unsigned long) priv->stats.tx_packets);
+
+ } else{
+
+ deth_interrupt(0, dev, NULL);
+ }
+
+
+}
+
+
+
+
+int deth_open(struct net_device *dev){
+
+ if (dev == deth_devs[1]){
+
+ memcpy((void*)dev->dev_addr, "DETH01", ETH_ALEN);
+
+
+ } else {
+
+ memcpy((void*)dev->dev_addr, "DETH00", ETH_ALEN);
+ }
+
+ struct deth_priv *priv = netdev_priv(dev);
+ napi_enable(&priv->napi);
+
+ netif_start_queue(dev);
+
+ printk(KERN_INFO "started deth\n");
+
+ return 0;
+}
+
+int deth_stop(struct net_device *dev){
+
+ netif_stop_queue(dev);
+
+ struct deth_priv *priv = netdev_priv(dev);
+ napi_disable(&priv->napi);
+
+ return 0;
+
+ printk(KERN_INFO "stopped deth\n");
+}
+
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+
+void deth_tx_timeout(struct net_device *dev)
+
+#else
+
+void deth_tx_timeout(struct net_device *dev, unsigned int txqueue)
+
+#endif
+
+{
+ struct deth_priv *priv = netdev_priv(dev);
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+
+ printk(KERN_INFO "transmit timeout at %ld, latency %ld\n", jiffies,
+ jiffies - txq->trans_start);
+
+ priv->status |= DETH_TX_INTR;
+ deth_interrupt(0, dev, NULL);
+ priv->stats.tx_errors++;
+
+ spin_lock(&priv->lock);
+ deth_teardown_pool(dev);
+ deth_setup_pool(dev);
+ spin_unlock(&priv->lock);
+
+ netif_wake_queue(dev);
+ return;
+}
+
+
+
+const struct net_device_ops deth_netdev_ops = {
+ .ndo_open = deth_open,
+ .ndo_stop = deth_stop,
+ .ndo_start_xmit = deth_xmit,
+ .ndo_tx_timeout = deth_tx_timeout,
+};
+
+
+
+
+void deth_setup(struct net_device *dev){
+
+ ether_setup(dev);
+ dev->watchdog_timeo = timeout;
+ dev->netdev_ops = &deth_netdev_ops;
+ dev->features |= NETIF_F_HW_CSUM;
+
+ deth_privs[setup_ptr] = netdev_priv(dev);
+
+ memset(deth_privs[setup_ptr], 0, sizeof(struct deth_priv));
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+ netif_napi_add(dev, &(deth_privs[setup_ptr])->napi, deth_poll,2);
+#else
+ netif_napi_add_weight(dev, &(deth_privs[setup_ptr])->napi, deth_poll,2);
+#endif
+
+ spin_lock_init(&(deth_privs[setup_ptr])->lock);
+ deth_privs[setup_ptr]->dev = dev;
+
+ deth_rx_ints(dev, 1);
+ deth_setup_pool(dev);
+
+ setup_ptr += 1;
+
+ printk(KERN_INFO "deth: setup success: %d\n", setup_ptr);
+}
+
+
+static int __init deth_init_module(void){
+
+ int err;
+
+ deth_interrupt = deth_napi_interrupt;
+
+ deth_devs[0] = alloc_netdev(sizeof(struct deth_priv), "deth%d", NET_NAME_UNKNOWN, deth_setup);
+ if (!deth_devs[0]){
+ return -ENOMEM;
+ }
+
+ deth_devs[1] = alloc_netdev(sizeof(struct deth_priv), "deth%d", NET_NAME_UNKNOWN, deth_setup);
+
+ if (!deth_devs[1]){
+ return -ENOMEM;
+ }
+
+ err = register_netdevice(deth_devs[0]);
+ if (err < 0) {
+ goto err1;
+ }
+
+ err = register_netdevice(deth_devs[1]);
+
+ if(err < 0) {
+
+ goto err2;
+ }
+
+
+ return 0;
+
+err1:
+
+ free_netdev(deth_devs[0]);
+ return err;
+
+err2:
+ free_netdev(deth_devs[0]);
+ free_netdev(deth_devs[1]);
+ return err;
+
+}
+
+
+
+static void __exit deth_cleanup_module(void)
+{
+ int i;
+
+ for (i = 0; i < DRV_COUNT; i++) {
+ if (deth_devs[i]) {
+ unregister_netdev(deth_devs[i]);
+ deth_teardown_pool(deth_devs[i]);
+ free_netdev(deth_devs[i]);
+ }
+ }
+ return;
+}
+
+
+
+
+module_init(deth_init_module);
+module_exit(deth_cleanup_module);
+MODULE_LICENSE("GPL");
\ No newline at end of file
--- /dev/null
+#ifndef _DETH_X_H_
+#define _DETH_X_H_
+
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <linux/skbuff.h>
+#include <linux/version.h>
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+
+
+#define DRV_NAME "deth"
+#define DRV_COUNT 2
+
+
+#define DETH_RX_INTR 0x0001
+#define DETH_TX_INTR 0x0002
+
+
+#define DETH_TIMEOUT 5
+
+
+
+struct deth_packet {
+ struct deth_packet *next;
+ struct net_device *dev;
+ int datalen;
+ u8 data[ETH_DATA_LEN];
+};
+
+struct deth_priv {
+ struct net_device_stats stats;
+ int status;
+ struct deth_packet *ppool;
+ struct deth_packet *rx_queue;
+ int rx_int_enabled;
+ int tx_packetlen;
+ u8 *tx_packetdata;
+ struct sk_buff *skb;
+ spinlock_t lock;
+ struct net_device *dev;
+ struct napi_struct napi;
+};
+
+
+extern struct net_device *deth_devs[DRV_COUNT];
+extern struct deth_priv *deth_privs[DRV_COUNT];
+extern int setup_ptr;
+
+extern const struct net_device_ops deth_netdev_ops;
+
+extern const struct header_ops deth_header_ops;
+
+extern int lockup;
+
+extern int timeout;
+
+extern int pool_size;
+
+extern void (*deth_interrupt)(int, void *, struct pt_regs *);
+
+
+
+void deth_setup_pool(struct net_device *dev);
+
+void deth_teardown_pool(struct net_device *dev);
+
+struct deth_packet *deth_tx_reserve_buffer(struct net_device *dev);
+
+void deth_tx_release_buffer(struct deth_packet *pkt);
+
+void deth_rx_prod_buf(struct net_device *dev, struct deth_packet *pkt);
+
+struct deth_packet *deth_rx_cons_buf(struct net_device *dev);
+
+
+
+void deth_rx_ints(struct net_device *dev, int enable);
+
+void deth_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+int deth_poll(struct napi_struct *napi, int budget);
+
+
+
+netdev_tx_t deth_xmit(struct sk_buff *skb, struct net_device *dev);
+
+void deth_hw_tx(char *buf, int len, struct net_device *dev);
+
+
+int deth_open(struct net_device *dev);
+
+int deth_stop(struct net_device *dev);
+
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+
+void deth_tx_timeout(struct net_device *dev);
+
+#else
+
+void deth_tx_timeout(struct net_device *dev, unsigned int txqueue);
+
+#endif
+
+
+/* module entry */
+
+void deth_setup(struct net_device *dev);
+
+#endif
\ No newline at end of file
--- /dev/null
+#!/bin/bash
+
+sudo ip netns add vnet
+
+sudo ip link set deth1 netns vnet
+
+sudo ip addr add 192.168.10.1/24 dev deth0
+
+sudo ip link set dev deth0 up
+
+sudo ip netns exec vnet ip addr add 192.168.10.2/24 dev deth1
+
+sudo ip netns exec vnet ip link set dev deth1 up
+
--- /dev/null
+#!/bin/bash
+
+
+sudo ip link set dev deth0 down
+
+sudo ip netns exec vnet ip link set dev deth1 down
+
+sudo ip addr del 192.168.10.1/24 dev deth0
+
+sudo ip netns exec vnet ip addr del 192.168.10.2/24 dev deth1
+
+sudo ip netns del vnet
+
+
+
+
--- /dev/null
+#
+
+```shell
+seantywork@raspberrypi2:~/hack/linux/linuxyz/kgpio-irqsock $ cat ins.conf
+#CTLOUT=GPIO17
+#DATAOUT=GPIO23
+CTLIN=GPIO24
+DATAIN=GPIO27
+CTLOUT=0
+DATAOUT=0
+```
+
+#
+
+```shell
+seantywork@raspberrypi2:~/hack/linux/linuxyz/kgpio-irqsock $ sudo ./ins.sh
+CTL OUT: 0 = 0
+DATA OUT: 0 = 0
+CTL IN : GPIO24 = 536
+DATA IN : GPIO27 = 539
+```
+
+```shell
+[Jun17 10:53] gpio irqsk: gpio_ctl_i to IRQ 55
+[ +0.000012] gpio irqsk: gpio_data_i to IRQ 54
+[ +0.000002] gpio irqsk: module is initialized into the kernel
+[ +0.000002] gpio irqsk: ctl_o: 0 ctl_i: 536
+[ +0.000002] gpio irqsk: data_o: 0 data_i: 539
+[ +1.788774] hwmon hwmon1: Undervoltage detected!
+[ +4.032053] hwmon hwmon1: Voltage normalised
+[ +22.627644] value: c906ea54...b98f7b6f
+[ +1.268015] value: c906ea54...b98f7b6f
+[ +1.267979] value: c906ea54...b98f7b6f
+[ +1.267823] value: c906ea54...b98f7b6f
+[ +1.268179] value: c906ea54...b98f7b6f
+[ +1.267929] value: c906ea54...b98f7b6f
+[ +1.267974] value: c906ea54...b98f7b6f
+[ +1.268064] value: c906ea54...b98f7b6f
+[ +1.268899] value: c906ea54...b98f7b6f
+[ +1.267049] value: c906ea54...b98f7b6f
+
+```
+
+
+#
+
+```shell
+seantywork@raspberrypi:~/hack/linux/linuxyz/kgpio-irqsock $ cat ins.conf
+CTLOUT=GPIO24
+DATAOUT=GPIO27
+CTLIN=0
+DATAIN=0
+#CTLIN=GPIO17
+#DATAIN=GPIO23
+```
+
+#
+```shell
+
+seantywork@raspberrypi:~/hack/linux/linuxyz/kgpio-irqsock $ sudo ./ins.sh
+CTL OUT: GPIO24 = 536
+DATA OUT: GPIO27 = 539
+CTL IN : 0 = 0
+DATA IN : 0 = 0
+
+```
+
+```shell
+[Jun17 10:53] gpio irqsk: module is initialized into the kernel
+[ +0.000015] gpio irqsk: ctl_o: 536 ctl_i: 0
+[ +0.000005] gpio irqsk: data_o: 539 data_i: 0
+[ +0.000004] gpio irqsk: test mode
+[ +0.000020] value: c906ea54...b98f7b6f
+[ +0.000038] waitqueue handler: job_handler
+[ +0.000004] waitqueue handler waiting...
+[ +0.104805] sending ctl start preamble
+[ +1.172572] waitqueue handler: job_handler
+[ +0.000013] waitqueue handler waiting...
+[ +0.107381] sending ctl start preamble
+[ +1.160622] waitqueue handler: job_handler
+[ +0.000013] waitqueue handler waiting...
+[ +0.107374] sending ctl start preamble
+[ +1.160590] waitqueue handler: job_handler
+[ +0.000012] waitqueue handler waiting...
+[ +0.107411] sending ctl start preamble
+[ +1.160399] waitqueue handler: job_handler
+[ +0.000012] waitqueue handler waiting...
+[ +0.107614] sending ctl start preamble
+[ +1.160547] waitqueue handler: job_handler
+[ +0.000013] waitqueue handler waiting...
+[ +0.107441] sending ctl start preamble
+[ +1.160471] waitqueue handler: job_handler
+[ +0.000012] waitqueue handler waiting...
+[ +0.107531] sending ctl start preamble
+[ +1.160428] waitqueue handler: job_handler
+[ +0.000011] waitqueue handler waiting...
+[ +0.107573] sending ctl start preamble
+[ +1.160478] waitqueue handler: job_handler
+[ +0.000013] waitqueue handler waiting...
+[ +0.107522] sending ctl start preamble
+[ +1.161356] waitqueue handler: job_handler
+[ +0.000011] waitqueue handler waiting...
+[ +0.106649] sending ctl start preamble
+[ +1.160377] job done
+
+```
+
+++ /dev/null
-#
\ No newline at end of file
#include "kgpio_irqsk.h"
+struct net_device *geth_devs;
+struct geth_priv *geth_privs;
+
+
+int lockup = 0;
+int timeout = GETH_TIMEOUT;
+int pool_size = 8;
+
+
+void (*geth_interrupt)(int, void *, struct pt_regs *);
+
int gpio_ctl_o;
int gpio_ctl_i;
int gpio_data_o;
u8 i_value[MAX_PKTLEN] = {0};
+
+
+
+void geth_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs){
+
+ printk(KERN_INFO "napi interrupt\n");
+
+ struct geth_priv *priv;
+
+
+ struct net_device *dev = (struct net_device *)dev_id;
+
+ if (!dev){
+ printk(KERN_INFO "invalid dev\n");
+ return;
+ }
+
+ priv = netdev_priv(dev);
+ spin_lock(&priv->lock);
+
+ printk(KERN_INFO "napi receive\n");
+ napi_schedule(&priv->napi);
+
+ printk(KERN_INFO "napi interrupt end\n");
+
+ spin_unlock(&priv->lock);
+ return;
+}
+
+
+int geth_poll(struct napi_struct *napi, int budget){
+
+
+ int npackets = 0;
+ struct sk_buff *skb;
+ struct geth_priv *priv = container_of(napi, struct geth_priv, napi);
+ struct net_device *dev = priv->dev;
+ struct geth_packet *pkt;
+
+ printk(KERN_INFO "polling\n");
+
+ while (npackets < budget) {
+
+ // copy value to pkt
+ // pkt =
+ skb = dev_alloc_skb(NET_IP_ALIGN + pkt->datalen);
+ if (! skb) {
+ if (printk_ratelimit()){
+ printk(KERN_INFO "geth: packet dropped\n");
+ }
+ priv->stats.rx_dropped++;
+ npackets++;
+ continue;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ memcpy(skb_put(skb, pkt->datalen), pkt->data, pkt->datalen);
+ skb->dev = dev;
+ skb->protocol = eth_type_trans(skb, dev);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ netif_receive_skb(skb);
+
+ npackets++;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += pkt->datalen;
+ }
+
+ printk(KERN_INFO "polling done\n");
+
+ if (npackets < budget) {
+ printk(KERN_INFO "npackets smaller than budget\n");
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
+ if (napi_complete_done(napi, npackets)){
+ printk(KERN_INFO "napi complete\n");
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+
+ printk(KERN_INFO "polling end\n");
+
+ return npackets;
+
+}
+
+
+
+netdev_tx_t geth_xmit(struct sk_buff *skb, struct net_device *dev){
+
+ printk("entered xmit\n");
+
+ int len;
+ char *data, shortpkt[ETH_ZLEN];
+ struct geth_priv *priv = netdev_priv(dev);
+
+ data = skb->data;
+ len = skb->len;
+ if (len < ETH_ZLEN) {
+ memset(shortpkt, 0, ETH_ZLEN);
+ memcpy(shortpkt, skb->data, skb->len);
+ len = ETH_ZLEN;
+ data = shortpkt;
+ }
+ netif_trans_update(dev);
+
+ priv->skb = skb;
+
+ geth_hw_tx(data, len, dev);
+
+ printk("exiting xmit\n");
+
+ return 0;
+
+
+}
+
+
+void geth_hw_tx(char *buf, int len, struct net_device *dev){
+
+
+ printk(KERN_INFO "entered hw tx\n");
+
+ struct ethhdr *eh;
+ struct iphdr *ih;
+ struct udphdr *uh;
+ struct tcphdr *th;
+
+ struct geth_priv *priv;
+ u16 sport;
+ u16 dport;
+
+
+ if (len < sizeof(struct ethhdr) + sizeof(struct iphdr)) {
+ printk("geth: packet too short (%i octets)\n",
+ len);
+ return;
+ }
+
+
+ eh = (struct ethhdr*)buf;
+
+ ih = (struct iphdr*)(buf + sizeof(struct ethhdr));
+
+
+ printk("eth src: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ eh->h_source[0],
+ eh->h_source[1],
+ eh->h_source[2],
+ eh->h_source[3],
+ eh->h_source[4],
+ eh->h_source[5]);
+ printk("eth dst: %02X:%02X:%02X:%02X:%02X:%02X\n",
+ eh->h_dest[0],
+ eh->h_dest[1],
+ eh->h_dest[2],
+ eh->h_dest[3],
+ eh->h_dest[4],
+ eh->h_dest[5]);
+
+
+ if(ih->protocol == IPPROTO_UDP){
+
+ uh = (struct udphdr*)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
+
+ sport = ntohs(uh->source);
+ dport = ntohs(uh->dest);
+
+ } else if (ih->protocol == IPPROTO_TCP){
+
+ th = (struct tcphdr*)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
+
+ sport = ntohs(th->source);
+ dport = ntohs(th->dest);
+
+ }
+
+ printk("src: %08x:%05i\n",
+ ntohl(ih->daddr), sport);
+
+ printk("dst: %08x:%05i\n",
+ ntohl(ih->daddr), dport);
+
+
+
+ // gpio tx
+
+ priv = netdev_priv(dev);
+
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += len;
+ if(priv->skb) {
+ dev_kfree_skb(priv->skb);
+ priv->skb = 0;
+ }
+ if (lockup && ((priv->stats.tx_packets + 1) % lockup) == 0) {
+
+ netif_stop_queue(dev);
+ printk(KERN_INFO "simulate lockup at %ld, txp %ld\n", jiffies, (unsigned long) priv->stats.tx_packets);
+
+ }
+
+}
+
+
+
+
+int geth_open(struct net_device *dev){
+
+ memcpy((void*)dev->dev_addr, "GETH01", ETH_ALEN);
+
+ struct geth_priv *priv = netdev_priv(dev);
+ napi_enable(&priv->napi);
+
+ netif_start_queue(dev);
+
+ printk(KERN_INFO "started geth\n");
+
+ return 0;
+}
+
+int geth_stop(struct net_device *dev){
+
+ netif_stop_queue(dev);
+
+ struct geth_priv *priv = netdev_priv(dev);
+ napi_disable(&priv->napi);
+
+ return 0;
+
+ printk(KERN_INFO "stopped geth\n");
+}
+
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+
+void geth_tx_timeout(struct net_device *dev)
+
+#else
+
+void geth_tx_timeout(struct net_device *dev, unsigned int txqueue)
+
+#endif
+
+{
+ struct geth_priv *priv = netdev_priv(dev);
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+
+ printk(KERN_INFO "transmit timeout at %ld, latency %ld\n", jiffies,
+ jiffies - txq->trans_start);
+
+ geth_interrupt(0, dev, NULL);
+ priv->stats.tx_errors++;
+
+ spin_lock(&priv->lock);
+ spin_unlock(&priv->lock);
+
+ netif_wake_queue(dev);
+ return;
+}
+
+
+
+const struct net_device_ops geth_netdev_ops = {
+ .ndo_open = geth_open,
+ .ndo_stop = geth_stop,
+ .ndo_start_xmit = geth_xmit,
+ .ndo_tx_timeout = geth_tx_timeout,
+};
+
+
+
+
+void geth_setup(struct net_device *dev){
+
+ ether_setup(dev);
+ dev->watchdog_timeo = timeout;
+ dev->netdev_ops = &geth_netdev_ops;
+ dev->features |= NETIF_F_HW_CSUM;
+
+ geth_privs = netdev_priv(dev);
+
+ memset(geth_privs, 0, sizeof(struct geth_priv));
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+ netif_napi_add(dev, &geth_privs->napi, geth_poll,2);
+#else
+ netif_napi_add_weight(dev, &geth_privs->napi, geth_poll,2);
+#endif
+
+ spin_lock_init(&geth_privs->lock);
+ geth_privs->dev = dev;
+
+ printk(KERN_INFO "geth: setup success\n");
+}
+
+
+
+
void gpio_ctl_on(void){
gpio_set_value(gpio_ctl_o, IRQF_TRIGGER_RISING);
- udelay(64);
+ udelay(SYNC_UDELAY);
gpio_set_value(gpio_ctl_o, IRQF_TRIGGER_NONE);
}
gpio_set_value(gpio_data_o, IRQF_TRIGGER_RISING);
- udelay(64);
+ udelay(SYNC_UDELAY);
gpio_set_value(gpio_data_o, IRQF_TRIGGER_NONE);
if(data_bits_count == 0){
return IRQ_HANDLED;
} else {
- // skb
- printk("value: %02x%02x%02x%02x...%02x%02x%02x%02x\n",
- i_value[0],
- i_value[1],
- i_value[2],
- i_value[3],
- i_value[MAX_PKTLEN-4],
- i_value[MAX_PKTLEN-3],
- i_value[MAX_PKTLEN-2],
- i_value[MAX_PKTLEN-1]
- );
+ if(gpio_ctl_i != 0 && gpio_ctl_o != 0){
+ // geth interrupt
+ }else {
+ printk("value: %02x%02x%02x%02x...%02x%02x%02x%02x\n",
+ i_value[0],
+ i_value[1],
+ i_value[2],
+ i_value[3],
+ i_value[MAX_PKTLEN-4],
+ i_value[MAX_PKTLEN-3],
+ i_value[MAX_PKTLEN-2],
+ i_value[MAX_PKTLEN-1]
+ );
+ }
data_bits_count = 0;
return IRQ_HANDLED;
}
static int __init ksock_gpio_init(void) {
+ int err;
+
if(gpio_ctl_o == 0 && gpio_ctl_i == 0){
printk("gpio irqsk: at least one ctl should be set\n");
printk(KERN_INFO "job done\n");
}
+ if(gpio_ctl_o != 0 && gpio_ctl_i != 0){
+
+ printk("gpio irqsk: prod mode\n");
+
+ geth_interrupt = geth_napi_interrupt;
+
+ geth_devs = alloc_netdev(sizeof(struct geth_priv), "geth%d", NET_NAME_UNKNOWN, geth_setup);
+ if (!geth_devs){
+ printk("gpio irqsk: can't alloc netdev\n");
+ gpio_free(gpio_ctl_o);
+ gpio_free(gpio_data_o);
+ gpio_free(gpio_ctl_i);
+ gpio_free(gpio_data_i);
+ free_irq(gpio_ctl_i_irq, NULL);
+ free_irq(gpio_data_i_irq, NULL);
+ return -ENOMEM;
+ }
+
+ err = register_netdevice(geth_devs);
+ if (err < 0) {
+ printk("gpio irqsk: can't register netdev\n");
+ gpio_free(gpio_ctl_o);
+ gpio_free(gpio_data_o);
+ gpio_free(gpio_ctl_i);
+ gpio_free(gpio_data_i);
+ free_irq(gpio_ctl_i_irq, NULL);
+ free_irq(gpio_data_i_irq, NULL);
+ free_netdev(geth_devs);
+ return -1;
+ }
+
+ }
return 0;
static void __exit ksock_gpio_exit(void) {
+ unregister_netdev(geth_devs);
+ free_netdev(geth_devs);
+
if(gpio_ctl_o != 0){
gpio_free(gpio_ctl_o);
#include <linux/udp.h>
#include <linux/string.h>
#include <linux/version.h>
+#include <linux/skbuff.h>
#include <linux/in6.h>
#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/checksum.h>
+#define DRV_NAME "geth"
+
+#define GETH_TIMEOUT 5
#define CHECK_BIT(var,pos) ((var) & (1<<(pos)))
#define MAX_PKTLEN 1500
+#define SYNC_UDELAY 64
+
+
+
+struct geth_packet {
+ struct geth_packet *next;
+ struct net_device *dev;
+ int datalen;
+ u8 data[ETH_DATA_LEN];
+};
+
+struct geth_priv {
+ struct net_device_stats stats;
+ int status;
+ struct geth_packet *ppool;
+ struct geth_packet *rx_queue;
+ int rx_int_enabled;
+ int tx_packetlen;
+ u8 *tx_packetdata;
+ struct sk_buff *skb;
+ spinlock_t lock;
+ struct net_device *dev;
+ struct napi_struct napi;
+};
+
+
+extern struct net_device *geth_devs;
+extern struct geth_priv *geth_privs;
+
+
+extern const struct net_device_ops geth_netdev_ops;
+
+extern const struct header_ops geth_header_ops;
+
+extern int lockup;
+
+extern int timeout;
+
+extern int pool_size;
+
+extern void (*geth_interrupt)(int, void *, struct pt_regs *);
+
+
extern int gpio_ctl_o;
extern int gpio_ctl_i;
extern u8 i_value[MAX_PKTLEN];
+
+
+
+void geth_napi_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+int geth_poll(struct napi_struct *napi, int budget);
+
+
+netdev_tx_t geth_xmit(struct sk_buff *skb, struct net_device *dev);
+
+void geth_hw_tx(char *buf, int len, struct net_device *dev);
+
+
+int geth_open(struct net_device *dev);
+
+int geth_stop(struct net_device *dev);
+
+
+
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,6,0)
+
+void geth_tx_timeout(struct net_device *dev);
+
+#else
+
+void geth_tx_timeout(struct net_device *dev, unsigned int txqueue);
+
+#endif
+
+
+/* module entry */
+
+void geth_setup(struct net_device *dev);
+
+
void gpio_ctl_on(void);
void gpio_data_on(void);
}
-struct kxfrm_packet *kxfrm_tx_cons_buffer(struct net_device *dev){
+struct kxfrm_packet *kxfrm_tx_reserve_buffer(struct net_device *dev){
struct kxfrm_priv *priv = netdev_priv(dev);
unsigned long flags;
priv = netdev_priv(dest);
- tx_buffer = kxfrm_tx_cons_buffer(dev);
+ tx_buffer = kxfrm_tx_reserve_buffer(dev);
if(!tx_buffer) {
printk(KERN_INFO "out of tx buffer, len is %i\n",len);
void kxfrm_teardown_pool(struct net_device *dev);
-struct kxfrm_packet *kxfrm_tx_cons_buffer(struct net_device *dev);
+struct kxfrm_packet *kxfrm_tx_reserve_buffer(struct net_device *dev);
void kxfrm_tx_release_buffer(struct kxfrm_packet *pkt);
}
-struct kxfrm_packet *kxfrm_tx_cons_buffer(struct net_device *dev){
+struct kxfrm_packet *kxfrm_tx_reserve_buffer(struct net_device *dev){
struct kxfrm_priv *priv = netdev_priv(dev);
unsigned long flags;
priv = netdev_priv(dest);
- tx_buffer = kxfrm_tx_cons_buffer(dev);
+ tx_buffer = kxfrm_tx_reserve_buffer(dev);
if(!tx_buffer) {
printk(KERN_INFO "out of tx buffer, len is %i\n",len);
void kxfrm_teardown_pool(struct net_device *dev);
-struct kxfrm_packet *kxfrm_tx_cons_buffer(struct net_device *dev);
+struct kxfrm_packet *kxfrm_tx_reserve_buffer(struct net_device *dev);
void kxfrm_tx_release_buffer(struct kxfrm_packet *pkt);