Created
November 21, 2014 19:45
-
-
Save sora/c33d0f726e301f94aa48 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: | |
gcc -g -Wall -O -o pktgen pktgen_stdout.c | |
gcc -g -Wall -O -o ring ring.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <sys/types.h> | |
#include <arpa/inet.h> | |
#include <net/ethernet.h> | |
#include <netinet/in.h> | |
#include <netinet/ip.h> | |
#define __FAVOR_BSD | |
#include <netinet/udp.h> | |
#define PKTGEN_MAGIC 0xbe9be955 | |
#define ETH_DST_MAC 0x020000000002 | |
#define ETH_SRC_MAC 0x020000000001 | |
#define IP4_SRC_IP "10.0.0.1" | |
#define IP4_DST_IP "10.0.0.2" | |
#define IP4_TTL 0x20 | |
#define IP4_PROTO_UDP 0x11 | |
#define UDP_SRC_PORT 0x09 | |
#define UDP_DST_PORT 0x09 | |
#define PKTDEV_HDR_LEN 12 | |
#define ETH_HDR_LEN 14 | |
#define IP4_HDR_LEN 20 | |
#define PKTDEV_MAGIC 0x3776 | |
/* from netmap pkt-gen.c */ | |
static uint16_t checksum(const void * data, uint16_t len, uint32_t sum) | |
{ | |
const uint8_t *addr = data; | |
uint32_t i; | |
/* Checksum all the pairs of bytes first... */ | |
for (i = 0; i < (len & ~1U); i += 2) { | |
sum += (u_int16_t)ntohs(*((u_int16_t *)(addr + i))); | |
if (sum > 0xFFFF) | |
sum -= 0xFFFF; | |
} | |
/* | |
* If there's a single byte left over, checksum it, too. | |
* Network byte order is big-endian, so the remaining byte is | |
* the high byte. | |
*/ | |
if (i < len) { | |
sum += addr[i] << 8; | |
if (sum > 0xFFFF) | |
sum -= 0xFFFF; | |
} | |
return sum; | |
} | |
static u_int16_t wrapsum(u_int32_t sum) | |
{ | |
sum = ~sum & 0xFFFF; | |
return (htons(sum)); | |
} | |
/* pktdev header */ | |
struct pd_hdr { | |
u_int16_t pd_magic; /* le */ | |
u_int16_t pd_frame_len; /* le */ | |
struct pd_timestamp { | |
uint32_t val_low; | |
uint16_t val_high; | |
uint8_t resv2; | |
uint8_t resv:4; | |
uint8_t reg:3; | |
bool reset:1; | |
} __attribute__((packed)) pd_time; /* le */ | |
} __attribute__((packed)); /* le */ | |
/* pktgen header */ | |
struct pg_hdr { | |
u_int32_t pg_magic; | |
u_int32_t pg_id; | |
u_int64_t pg_time; | |
} __attribute__((packed)); | |
/* packet */ | |
struct pktgen_pkt { | |
struct pd_hdr pd; | |
struct ether_header eth; | |
struct ip ip; | |
struct udphdr udp; | |
struct pg_hdr pg; | |
} __attribute__((packed)); | |
void set_pdhdr(struct pktgen_pkt *pkt, u_int16_t frame_len) | |
{ | |
struct pd_hdr *pd; | |
pd = &pkt->pd; | |
pd->pd_magic = PKTDEV_MAGIC; | |
pd->pd_frame_len = frame_len; | |
pd->pd_time.reset = 1; | |
pd->pd_time.reg = 1; | |
pd->pd_time.resv = 0; | |
pd->pd_time.resv2 = 0; | |
pd->pd_time.val_high = 0; | |
pd->pd_time.val_low = 0; | |
return; | |
} | |
void set_ethhdr(struct pktgen_pkt *pkt) | |
{ | |
struct ether_header *eth; | |
eth = &pkt->eth; | |
eth->ether_dhost[5] = (ETH_DST_MAC ) & 0xFF; | |
eth->ether_dhost[4] = (ETH_DST_MAC >> 8) & 0xFF; | |
eth->ether_dhost[3] = (ETH_DST_MAC >> 16) & 0xFF; | |
eth->ether_dhost[2] = (ETH_DST_MAC >> 24) & 0xFF; | |
eth->ether_dhost[1] = (ETH_DST_MAC >> 32) & 0xFF; | |
eth->ether_dhost[0] = (ETH_DST_MAC >> 40) & 0xFF; | |
eth->ether_shost[5] = (ETH_SRC_MAC ) & 0xFF; | |
eth->ether_shost[4] = (ETH_SRC_MAC >> 8) & 0xFF; | |
eth->ether_shost[3] = (ETH_SRC_MAC >> 16) & 0xFF; | |
eth->ether_shost[2] = (ETH_SRC_MAC >> 24) & 0xFF; | |
eth->ether_shost[1] = (ETH_SRC_MAC >> 32) & 0xFF; | |
eth->ether_shost[0] = (ETH_SRC_MAC >> 40) & 0xFF; | |
eth->ether_type = htons(ETHERTYPE_IP); | |
return; | |
} | |
void set_ip4hdr(struct pktgen_pkt *pkt, u_int16_t frame_len) | |
{ | |
struct ip *ip; | |
ip = &pkt->ip; | |
ip->ip_v = IPVERSION; | |
ip->ip_hl = 5; | |
ip->ip_tos = 0; | |
ip->ip_len = htons(frame_len - ETH_HDR_LEN); | |
ip->ip_id = 0; | |
ip->ip_off = htons (IP_DF); | |
ip->ip_ttl = 0x20; | |
ip->ip_p = IPPROTO_UDP; | |
inet_pton(AF_INET, IP4_SRC_IP, &ip->ip_src); | |
inet_pton(AF_INET, IP4_DST_IP, &ip->ip_dst); | |
ip->ip_sum = 0; | |
return; | |
} | |
void set_udphdr(struct pktgen_pkt *pkt, u_int16_t frame_len) | |
{ | |
struct udphdr *udp; | |
udp = &pkt->udp; | |
udp->uh_sport = htons(UDP_SRC_PORT); | |
udp->uh_dport = htons(UDP_DST_PORT); | |
udp->uh_ulen = htons(frame_len - ETH_HDR_LEN - IP4_HDR_LEN); | |
udp->uh_sum = 0; | |
return; | |
} | |
void set_pghdr(struct pktgen_pkt *pkt) | |
{ | |
struct pg_hdr *pg; | |
pg = &pkt->pg; | |
pg->pg_magic = htonl(PKTGEN_MAGIC); | |
pg->pg_id = 0; | |
pg->pg_time = 0; | |
return; | |
}; | |
//#define step 0xEE6B280 | |
unsigned short id = 0; | |
unsigned long long ts = 0; | |
static inline void build_pack(char *pack, struct pktgen_pkt *pkt, | |
unsigned int npkt, int pktlen, unsigned int step) | |
{ | |
struct ip *ip; | |
int i, offset; | |
ip = (struct ip *)&pkt->ip; | |
offset = 0; | |
for (i = 0; i < npkt; i++) { | |
ip->ip_id = htons(id); | |
pkt->pd.pd_time.val_low = ts & 0xFFFFFFFF; | |
pkt->pd.pd_time.val_high = (ts >> 32) & 0xFFFF; | |
pkt->pg.pg_id = htonl((u_int32_t)id++); | |
ip->ip_sum = wrapsum(checksum(ip, sizeof(*ip), 0)); | |
//pkt->ip.ip_sum = 0; | |
memcpy(pack + offset, pkt, sizeof(struct pktgen_pkt)); | |
pkt->pd.pd_time.reset = 0; | |
offset += pktlen; | |
ts += step; | |
} | |
} | |
//#define mbps 1000 | |
//#define step (int)(84 * (1000 / (float)mbps)) | |
// ./pktgen_stdout -s <frame_len> -n <npkt> -m <nloop> | |
// ex(595 * 25010 = 14.88Mpps): ./pktgen_stdout -s 60 -n 595 -m 25010 | |
int main(int argc, char **argv) | |
{ | |
char *pack = NULL; | |
const char *ptr = NULL; | |
struct pktgen_pkt *pkt = NULL; | |
int ret = 0, i, pktlen, packlen, cnt, nleft; | |
unsigned int step = 84; | |
unsigned short frame_len = 60; | |
unsigned int npkt = 5; | |
unsigned int nloop = 10; | |
unsigned int mbps = 1000; | |
for (i = 1; i < argc; ++i) { | |
if (0 == strcmp(argv[i], "-s")) { | |
if (++i == argc) perror("-s"); | |
frame_len = atoi(argv[i]); | |
} else if (0 == strcmp(argv[i], "-n")) { | |
if (++i == argc) perror("-n"); | |
npkt = atoi(argv[i]); | |
} else if (0 == strcmp(argv[i], "-m")) { | |
if (++i == argc) perror("-m"); | |
nloop = atoi(argv[i]); | |
} else if (0 == strcmp(argv[i], "-t")) { | |
if (++i == argc) perror("-t"); | |
mbps = atoi(argv[i]); | |
} | |
} | |
step = (unsigned int)(84 * (1000 / (float)mbps)); | |
fprintf(stderr, "step=%d\n", step); | |
if (frame_len < 60 || frame_len > 9014) { | |
fprintf(stderr, "frame size error: %d\n", frame_len); | |
ret = -1; | |
goto out; | |
} | |
if (npkt < 1) { | |
fprintf(stderr, "npkt error: %d\n", (int)npkt); | |
ret = -1; | |
goto out; | |
} | |
if (nloop < 1) { | |
fprintf(stderr, "nloop error: %d\n", nloop); | |
ret = -1; | |
goto out; | |
} | |
pkt = malloc(sizeof(struct pktgen_pkt)); | |
set_pdhdr(pkt, frame_len); | |
set_ethhdr(pkt); | |
set_ip4hdr(pkt, frame_len); | |
set_udphdr(pkt, frame_len); | |
set_pghdr(pkt); | |
pktlen = PKTDEV_HDR_LEN + frame_len; | |
pack = calloc((size_t)(pktlen * npkt), sizeof(char)); | |
// nloop | |
packlen = pktlen * npkt; | |
for (i = 0; i < nloop; i++) { | |
nleft = packlen; | |
ptr = (char *)pack; | |
build_pack(pack, pkt, npkt, pktlen, step); | |
while (nleft > 0) { | |
if ((cnt = write(1, ptr, nleft)) <= 0) { | |
// :todo (check errno) | |
; | |
} | |
nleft -= cnt; | |
ptr += cnt; | |
} | |
} | |
out: | |
if (pack) | |
free(pack); | |
if (pkt) | |
free(pkt); | |
return ret; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <unistd.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <libkern/OSByteOrder.h> | |
#define EP_XMIT_OK 0x10 | |
#define EP_XMIT_BUSY 0x11 | |
#define EP_XMIT_ERR 0x12 | |
#define cpu_to_be16(x) OSSwapHostToBigInt16(x) | |
#define cpu_to_be64(x) OSSwapHostToBigInt64(x) | |
#define EP_MAGIC 0x3776 | |
#define EP_HDR_SIZE 12 // magic:2 + frame_len:2 + ts:8 | |
#define EP_HWHDR_SIZE 14 // frame_len:2 + hash:4 + ts:8 | |
#define MAX_PKT_SIZE 9014 | |
#define MIN_PKT_SIZE 40 | |
#define RING_ALMOST_FULL (MAX_PKT_SIZE*2) | |
#define XMIT_BUDGET 0x3F | |
#define pr_info printf | |
#define func_enter() pr_info("entering %s\n", __func__); | |
#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) | |
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) | |
struct ep_ring { | |
uint32_t size; /* malloc size of ring */ | |
uint8_t *start; /* start address */ | |
uint8_t *end; /* end address */ | |
uint32_t mask; /* (size - 1) of ring */ | |
volatile uint8_t *read; /* next position to be read */ | |
volatile uint8_t *write; /* next position to be written */ | |
}; | |
struct ep_hw_pkt { | |
uint16_t len; /* frame length */ | |
uint64_t ts; /* timestamp */ | |
uint32_t hash; /* unused. reserved */ | |
uint8_t body[1]; /* ethnet frame data */ | |
} __attribute__((__packed__)); | |
struct mmio { | |
uint8_t *virt; | |
uint64_t start; | |
uint64_t end; | |
uint64_t flags; | |
uint64_t len; | |
}; | |
struct ecp3versa { | |
struct pci_dev *pcidev; | |
struct mmio mmio0; | |
struct mmio mmio1; | |
struct tx { | |
volatile uint32_t *write; | |
volatile uint32_t *read; | |
uint32_t *start; | |
uint32_t *end; | |
uint32_t size; | |
uint32_t mask; | |
} tx; | |
}; | |
struct ep_dev { | |
struct ep_ring txq; | |
struct ep_ring wrq; | |
struct ecp3versa nic; | |
struct ep_hw_pkt *hw_pkt; | |
uint32_t tx_counter; | |
uint32_t txq_size; | |
uint32_t wrq_size; | |
}; | |
struct ep_dev *pdev; | |
uint32_t txwr = 0; | |
uint32_t txrd = 0; | |
static inline bool ring_empty(const struct ep_ring *r) | |
{ | |
return !!(r->read == r->write); | |
} | |
static inline uint32_t ring_free_count(const struct ep_ring *r) | |
{ | |
return ((r->read - r->write - 1) & r->mask); | |
} | |
static inline bool ring_almost_full(const struct ep_ring *r) | |
{ | |
return !!(ring_free_count(r) < RING_ALMOST_FULL); | |
} | |
static inline void ring_read_next_aligned(struct ep_ring *r, uint32_t size) | |
{ | |
r->read += ALIGN(size, 4); | |
if (r->read > r->end) { | |
r->read = r->start; | |
} | |
} | |
static inline uint16_t ring_next_magic(struct ep_ring *r) | |
{ | |
return *(uint16_t *)&r->read[0]; | |
} | |
static inline uint16_t ring_next_frame_len(struct ep_ring *r) | |
{ | |
return *(uint16_t *)&r->read[2]; | |
} | |
static inline uint64_t ring_next_timestamp(struct ep_ring *r) | |
{ | |
return *(uint64_t *)&r->read[4]; | |
} | |
static inline uint32_t read_nic_txptr(uint32_t *p) | |
{ | |
return *p << 1; | |
} | |
static inline void set_nic_txptr(uint32_t *p, uint32_t addr) | |
{ | |
*p = addr >> 1; | |
} | |
static inline uint32_t hwtx_xmit_next(uint32_t hw_write, uint32_t size) | |
{ | |
struct ecp3versa *nic = &pdev->nic; | |
hw_write += ALIGN(EP_HWHDR_SIZE + size, 2); | |
hw_write &= nic->tx.mask; | |
return hw_write; | |
} | |
static inline void ring_write_next(struct ep_ring *r, uint32_t size) | |
{ | |
r->write += size; | |
if (r->write > r->end) { | |
r->write = r->start; | |
} | |
} | |
static inline void ring_read_next(struct ep_ring *r, uint32_t size) | |
{ | |
r->read += size; | |
if (r->read > r->end) { | |
r->read = r->start; | |
} | |
} | |
static inline void ring_write_next_aligned(struct ep_ring *r, uint32_t size) | |
{ | |
r->write += ALIGN(size, 4); | |
if (r->write > r->end) { | |
r->write = r->start; | |
} | |
} | |
/* | |
* build_ep_pkt | |
*/ | |
static inline int build_ep_pkt(struct ep_hw_pkt *pkt) | |
{ | |
uint16_t magic, frame_len; | |
struct ep_ring *txq = &pdev->txq; | |
// check magic code | |
magic = ring_next_magic(txq); | |
if (magic != EP_MAGIC) { | |
pr_info("packet format error: magic=%X\n", (int)magic); | |
return 0; | |
} | |
// check frame length | |
frame_len = ring_next_frame_len(txq); | |
if ((frame_len > MAX_PKT_SIZE) || (frame_len < MIN_PKT_SIZE)) { | |
pr_info("packet format error: frame_len=%X\n", (int)frame_len); | |
return 0; | |
} | |
pkt->len = cpu_to_be16(frame_len); | |
pkt->hash = 0; | |
pkt->ts = cpu_to_be64(ring_next_timestamp(txq)); | |
//pkt->ts = ring_next_timestamp(txq); | |
memcpy(&pkt->body, (uint8_t *)(txq->read + EP_HDR_SIZE), frame_len); | |
return frame_len; | |
} | |
/* | |
* hxtx_alomost_full | |
*/ | |
static inline bool hwtx_almost_full(uint32_t wr, uint32_t rd) | |
{ | |
return !!((rd - wr - 1) < 9000); | |
} | |
/* | |
* xmit | |
*/ | |
static inline void xmit(uint32_t wr, struct ep_hw_pkt *pkt, int len) | |
{ | |
uint8_t *nic_virt = pdev->nic.mmio1.virt; | |
uint32_t tmp; | |
len += EP_HWHDR_SIZE; | |
if ((wr + len) < pdev->nic.tx.size) { | |
memcpy(nic_virt + wr, pkt, len); | |
} else { | |
tmp = pdev->nic.tx.size - wr; | |
//pr_info("overwriting: wr=%d, tmp=%d\n", wr, tmp); | |
memcpy(nic_virt + wr, pkt, tmp); | |
memcpy(nic_virt, ((uint8_t *)pkt + tmp), (len - tmp)); | |
//dump_nic_info((struct ep_hw_pkt *)((uint8_t *)pkt + tmp)); | |
} | |
} | |
/* | |
* ethpipe_xmit | |
*/ | |
static inline int ethpipe_xmit(uint32_t hw_write, | |
uint32_t hw_read, int len) | |
{ | |
struct ep_ring *txq = &pdev->txq; | |
int ret = EP_XMIT_OK; | |
func_enter(); | |
if (!hwtx_almost_full(hw_write, hw_read)) { | |
xmit(hw_write, pdev->hw_pkt, len); | |
ring_read_next_aligned(txq, EP_HDR_SIZE + len); | |
ret = EP_XMIT_OK; | |
} else { | |
ret = EP_XMIT_BUSY; | |
pr_info("hwring is full\n"); | |
} | |
return ret; | |
} | |
/* | |
* ethpipe_send | |
*/ | |
static inline void ethpipe_send(void) | |
{ | |
int limit, ret, len; | |
uint32_t hw_write, hw_read; | |
struct ep_ring *txq = &pdev->txq; | |
func_enter(); | |
// read hwtx read and write address via pcie pio read | |
hw_write = read_nic_txptr((uint32_t *)pdev->nic.tx.write); | |
hw_read = read_nic_txptr((uint32_t *)pdev->nic.tx.read); | |
// reset xmit budget | |
limit = XMIT_BUDGET; | |
// sending | |
while(!ring_empty(txq) && (--limit > 0)) { | |
len = build_ep_pkt(pdev->hw_pkt); | |
if (len < 1) { | |
pr_info("err: build_ep_pkt() len=%d\n", len); | |
goto error; | |
} | |
ret = ethpipe_xmit(hw_write, hw_read, len); | |
if (ret == EP_XMIT_OK) { | |
hw_write = hwtx_xmit_next(hw_write, len); | |
++pdev->tx_counter; // incr tx_counter | |
} else if (ret == EP_XMIT_BUSY) { | |
goto out; | |
} else { | |
pr_info("err: unknown ret of ethpipe_xmit()\n"); | |
goto error; | |
} | |
} | |
// commit to NIC via pcie pio write | |
set_nic_txptr((uint32_t *)pdev->nic.tx.write, hw_write); | |
// debug | |
//dump_nic_info(); | |
out: | |
return; | |
error: | |
pr_info("kthread: tx_err\n"); | |
// todo: need lock | |
txq->read = txq->start; | |
txq->write = txq->start; | |
return; | |
} | |
void release(void) | |
{ | |
pr_info("%s\n", __func__); | |
if(pdev->txq.start != NULL) | |
free(pdev->txq.start); | |
if(pdev->wrq.start != NULL) | |
free(pdev->wrq.start); | |
if(pdev->hw_pkt != NULL) | |
free(pdev->hw_pkt); | |
if(pdev->nic.mmio0.virt != NULL) | |
free(pdev->nic.mmio0.virt); | |
if(pdev->nic.mmio1.virt != NULL) | |
free(pdev->nic.mmio1.virt); | |
if(pdev != NULL) | |
free(pdev); | |
} | |
void init(void) | |
{ | |
struct mmio *mmio0 = NULL; | |
struct mmio *mmio1 = NULL; | |
struct ecp3versa *nic = NULL; | |
pr_info("%s\n", __func__); | |
pdev = malloc(sizeof(struct ep_dev)); | |
pdev->tx_counter = 0; | |
pdev->txq_size = 32 * 1024 * 1024; | |
pdev->wrq_size = 32 * 1024 * 1024; | |
pr_info("pdev->txq_size: %d\n", pdev->txq_size); | |
pr_info("pdev->wrq_size: %d\n", pdev->wrq_size); | |
/* temporary buffer for build paket */ | |
pdev->hw_pkt = (struct ep_hw_pkt *)malloc( | |
sizeof(struct ep_hw_pkt) - sizeof(uint8_t) + (sizeof(uint8_t) * MAX_PKT_SIZE)); | |
if (pdev->hw_pkt == 0) { | |
pr_info("fail to kmalloc: *pdev->hw_pkt\n"); | |
goto err; | |
} | |
/* setup transmit buffer */ | |
if ((pdev->txq.start = | |
malloc(pdev->txq_size + EP_HDR_SIZE + MAX_PKT_SIZE)) == 0) { | |
pr_info("fail to vmalloc: txq\n"); | |
goto err; | |
} | |
pdev->txq.size = pdev->txq_size; | |
pdev->txq.mask = pdev->txq_size - 1; | |
pdev->txq.end = pdev->txq.start + pdev->txq_size - 1; | |
pdev->txq.write = pdev->txq.start; | |
pdev->txq.read = pdev->txq.start; | |
/* setup */ | |
if ((pdev->wrq.start = | |
malloc(pdev->wrq_size + EP_HDR_SIZE + MAX_PKT_SIZE)) == 0) { | |
pr_info("fail to vmalloc: wrq\n"); | |
goto err; | |
} | |
pdev->wrq.size = pdev->wrq_size; | |
pdev->wrq.mask = pdev->wrq_size - 1; | |
pdev->wrq.end = pdev->wrq.start + pdev->wrq_size - 1; | |
pdev->wrq.write = pdev->wrq.start; | |
pdev->wrq.read = pdev->wrq.start; | |
/* setup */ | |
if ((pdev->nic.mmio0.virt = (uint8_t *)malloc(32 * 1024)) == 0) { | |
pr_info("fail to vmalloc: mmio0\n"); | |
goto err; | |
} | |
mmio0 = &pdev->nic.mmio0; | |
pr_info("mmio0->virt: %p\n", mmio0->virt); | |
if ((pdev->nic.mmio1.virt = (uint8_t *)malloc(32 * 1024)) == 0) { | |
pr_info("fail to vmalloc: mmio0\n"); | |
goto err; | |
} | |
mmio1 = &pdev->nic.mmio1; | |
pr_info("mmio1->virt: %p\n", mmio1->virt); | |
mmio1->len = 0x10000; | |
nic = &pdev->nic; | |
/* pointer of NIC registers */ | |
nic->tx.write = &txwr; | |
nic->tx.read = &txrd; | |
nic->tx.mask = nic->tx.size - 1; | |
nic->tx.size = mmio1->len >> 1; | |
pr_info("nic->tx.write: %p, %X\n", nic->tx.write, *nic->tx.write); | |
pr_info("nic->tx.read: %p, %X\n", nic->tx.read, *nic->tx.read); | |
pr_info("nic->tx.end: %p\n", nic->tx.end); | |
pr_info("nic->tx.size: %X\n", (unsigned int)nic->tx.size); | |
return; | |
err: | |
release(); | |
exit(1); | |
} | |
void dump(void) | |
{ | |
struct ep_ring *t = &pdev->txq; | |
printf("----------DUMP\n"); | |
printf("%02X %02X %02X %02X ", t->read[ 0], t->read[ 1], t->read[ 2], t->read[ 3]); | |
printf("%02X %02X %02X %02X\n", t->read[ 4], t->read[ 5], t->read[ 6], t->read[ 7]); | |
printf("%02X %02X %02X %02X ", t->read[ 8], t->read[ 9], t->read[10], t->read[11]); | |
printf("%02X %02X %02X %02X\n", t->read[12], t->read[13], t->read[14], t->read[15]); | |
printf("----------DUMP\n"); | |
} | |
void work(void) | |
{ | |
struct ep_ring *wrq = &pdev->wrq; | |
struct ep_ring *txq = &pdev->txq; | |
int magic, frame_len, len; | |
wrq->write = (volatile uint8_t *)wrq->start; | |
wrq->read = (volatile uint8_t *)wrq->start; | |
while(1){ | |
if (read(0, (uint8_t *)wrq->write, EP_HDR_SIZE) <= 0) { | |
printf("No input data\n"); | |
dump(); | |
goto err; | |
} | |
ring_write_next(wrq, EP_HDR_SIZE); | |
// check magic code | |
magic = ring_next_magic(wrq); | |
if (magic != EP_MAGIC) { | |
pr_info("packet format error: magic=%X\n", (int)magic); | |
goto err; | |
} | |
// check frame length | |
frame_len = ring_next_frame_len(wrq); | |
if ((frame_len > MAX_PKT_SIZE) || (frame_len < MIN_PKT_SIZE)) { | |
pr_info("packet format error: frame_len=%X\n", (int)frame_len); | |
goto err; | |
} else { | |
pr_info("frame_len=%X\n", (int)frame_len); | |
} | |
read(0, (uint8_t *)wrq->write, frame_len); | |
ring_write_next(wrq, frame_len); | |
len = EP_HDR_SIZE + frame_len; | |
if (!ring_almost_full(txq)) { | |
memcpy((uint8_t *)txq->write, (uint8_t *)wrq->read, len); | |
ring_read_next(wrq, len); | |
ring_write_next_aligned(txq, len); | |
} else { | |
// return when a ring buffer reached the max size | |
pr_info("txq is full.\n"); | |
sleep(1); | |
break; | |
} | |
} | |
err: | |
return; | |
} | |
int main(void) | |
{ | |
init(); | |
work(); | |
ethpipe_send(); | |
release(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment