You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
6.6 KiB
C
245 lines
6.6 KiB
C
1 year ago
|
/* netmap!! */
|
||
|
#define NETMAP_WITH_LIBS
|
||
|
#include<net/netmap_user.h>
|
||
|
|
||
|
/* default, printf, etc */
|
||
|
#include<stdio.h>
|
||
|
/* uint32_t */
|
||
|
#include<stdint.h>
|
||
|
/* ioctl stuff */
|
||
|
#include <sys/ioctl.h>
|
||
|
/* string stuff(memset, strcmp, strlen, etc) */
|
||
|
#include<string.h>
|
||
|
/* ether_header */
|
||
|
#include <netinet/if_ether.h>
|
||
|
/* ether_aton */
|
||
|
#include <netinet/ether.h>
|
||
|
/* htons, htonl, etc */
|
||
|
#include<netinet/in.h>
|
||
|
/* close() */
|
||
|
#include<unistd.h>
|
||
|
|
||
|
#include "common.h"
|
||
|
#include "debug.h"
|
||
|
#include "endian.h"
|
||
|
|
||
|
#define ETHERTYPE_PTP 0x88F7
|
||
|
#define DEST_MAC "01:1b:19:00:00:00" /*defined by IEEE-1588v2*/
|
||
|
|
||
|
struct ptp_header {
|
||
|
uint8_t ptp_ts:4, /*transportSpecific*/
|
||
|
ptp_type:4; /*messageType*/
|
||
|
uint8_t ptp_v; /*versionPTP (4 bits in size)*/
|
||
|
uint16_t ptp_ml; /*messageLength*/
|
||
|
uint8_t ptp_dn; /*domainNumber*/
|
||
|
uint8_t ptp_res; /*reserved*/
|
||
|
uint16_t ptp_flags; /*flags*/
|
||
|
uint64_t ptp_cf; /*correctionField*/
|
||
|
uint32_t ptp_res2; /*reserved*/
|
||
|
uint8_t ptp_src[10]; /*sourcePortIdentity,8 byte mac,2 byte portId*/
|
||
|
uint16_t ptp_sid; /*sequenceId*/
|
||
|
uint8_t ptp_ctlf; /*controlField*/
|
||
|
uint8_t ptp_lmi; /*logMessageInterval*/
|
||
|
} __attribute__((__packed__));
|
||
|
|
||
|
struct pkt_ptp {
|
||
|
struct ether_header eh;
|
||
|
struct ptp_header ph;
|
||
|
uint64_t s:48;
|
||
|
uint32_t ns;
|
||
|
} __attribute__((__packed__));
|
||
|
|
||
|
enum ptp_msg_type
|
||
|
{
|
||
|
SYNC = 0x0,
|
||
|
DELAY_REQ = 0x1,
|
||
|
FOLLOW_UP = 0x8,
|
||
|
DELAY_RESP = 0x9,
|
||
|
};
|
||
|
|
||
|
void get_local_mac(uint8_t addr[6]) {
|
||
|
int fd;
|
||
|
struct ifreq req;
|
||
|
|
||
|
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||
|
strcpy(req.ifr_name, NETMAP_INTERFACE);
|
||
|
|
||
|
if(likely(ioctl(fd, SIOCGIFHWADDR, &req) == 0)) {
|
||
|
memcpy(addr, req.ifr_hwaddr.sa_data, 6);
|
||
|
close(fd);
|
||
|
} else {
|
||
|
ERROR(strcat("Unable to retrieve hwaddr for ", NETMAP_INTERFACE));
|
||
|
close(fd);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void netmap_close(struct nm_desc *d) {
|
||
|
if (d == NULL)
|
||
|
return;
|
||
|
if (d->done_mmap && d->mem)
|
||
|
munmap(d->mem, d->memsize);
|
||
|
if (d->fd != -1)
|
||
|
close(d->fd);
|
||
|
memset(d, 0, sizeof(*d));
|
||
|
free(d);
|
||
|
printf("netmap closed...\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
struct nm_desc * netmap_open() {
|
||
|
struct nm_desc *d;
|
||
|
uint32_t nr_flags = NR_REG_ALL_NIC;
|
||
|
|
||
|
/* allocate memory and set up the descriptor */
|
||
|
d = (struct nm_desc *)calloc(1, sizeof(*d));
|
||
|
if (unlikely(d == NULL)) {
|
||
|
ERROR("nm_desc alloc failure");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
d->self = d; /* just to indicate this is a netmap configuration */
|
||
|
|
||
|
printf("opening /dev/netmap...\n");
|
||
|
d->fd = open("/dev/netmap", O_RDWR);
|
||
|
if (unlikely(d->fd < 0)) {
|
||
|
ERROR("cannot open /dev/netmap");
|
||
|
netmap_close(d);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
|
||
|
d->req.nr_version = NETMAP_API;
|
||
|
d->req.nr_flags = nr_flags;
|
||
|
strcpy(d->req.nr_name, NETMAP_INTERFACE);
|
||
|
d->req.nr_name[strlen(d->req.nr_name)] = '\0'; /* null terminate the string */
|
||
|
|
||
|
/* configure the network interface */
|
||
|
printf("executing ioctl...\n");
|
||
|
if (unlikely(ioctl(d->fd, NIOCREGIF, &d->req))) {
|
||
|
ERROR("ioctl NIOCREGIF failed");
|
||
|
netmap_close(d);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
/* memory map netmap */
|
||
|
printf("mmaping...\n");
|
||
|
d->memsize = d->req.nr_memsize;
|
||
|
d->mem = mmap(0, d->memsize, PROT_READ | PROT_WRITE, MAP_SHARED, d->fd, 0);
|
||
|
if(unlikely(d->mem == MAP_FAILED)) {
|
||
|
ERROR("mmap failed");
|
||
|
netmap_close(d);
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
d->done_mmap = 1;
|
||
|
|
||
|
/* set up rings locations */
|
||
|
|
||
|
/* braces used for scope */
|
||
|
{
|
||
|
struct netmap_if *nifp = NETMAP_IF(d->mem, d->req.nr_offset);
|
||
|
struct netmap_ring *r = NETMAP_RXRING(nifp, );
|
||
|
|
||
|
*(struct netmap_if **)(uintptr_t)&d->nifp = nifp;
|
||
|
*(struct netmap_ring **)(uintptr_t)&d->some_ring = r;
|
||
|
*(void **)(uintptr_t)&d->buf_start = NETMAP_BUF(r, 0);
|
||
|
*(void **)(uintptr_t)&d->buf_end = (char *) d->mem + d->memsize;
|
||
|
}
|
||
|
|
||
|
d->first_tx_ring = 0;
|
||
|
d->first_rx_ring = 0;
|
||
|
|
||
|
d->last_tx_ring = d->req.nr_tx_rings - 1;
|
||
|
d->last_rx_ring = d->req.nr_rx_rings - 1;
|
||
|
|
||
|
d->cur_tx_ring = d->first_tx_ring;
|
||
|
d->cur_rx_ring = d->first_rx_ring;
|
||
|
|
||
|
return d;
|
||
|
}
|
||
|
|
||
|
static char * netmap_nextpkt(struct nm_desc *d, struct nm_pkthdr *hdr) {
|
||
|
|
||
|
int ri = d->cur_rx_ring;
|
||
|
|
||
|
do {
|
||
|
struct netmap_ring *ring = NETMAP_RXRING(d->nifp, ri);
|
||
|
if(!nm_ring_empty(ring)) {
|
||
|
u_int cur = ring->cur;
|
||
|
u_int idx = ring->slot[cur].buf_idx;
|
||
|
char *buf = (char *) NETMAP_BUF(ring, idx);
|
||
|
|
||
|
hdr->ts = ring->ts;
|
||
|
hdr->len = hdr->caplen = ring->slot[cur].len;
|
||
|
ring->cur = nm_ring_next(ring, cur);
|
||
|
ring->head = ring->cur;
|
||
|
d->cur_rx_ring = ri;
|
||
|
return buf;
|
||
|
}
|
||
|
ri++;
|
||
|
if(ri > d->last_rx_ring) {
|
||
|
ri = d->first_rx_ring;
|
||
|
}
|
||
|
} while(ri != d->cur_rx_ring);
|
||
|
return NULL; /* nothing found :( */
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Construct a new PTP Ethernet packet.
|
||
|
*/
|
||
|
struct pkt_ptp *init_ptp_packet(int ptp_mtype) {
|
||
|
int i, j = 0;
|
||
|
struct pkt_ptp *pkt = malloc(sizeof(struct pkt_ptp));
|
||
|
struct ether_header *eh = &pkt->eh;
|
||
|
struct ptp_header *ph = &pkt->ph;
|
||
|
uint8_t shost[6];
|
||
|
|
||
|
get_local_mac(shost);
|
||
|
|
||
|
eh->ether_type = htons(ETHERTYPE_PTP); /*PTP over 802.3 ethertype*/
|
||
|
memcpy(eh->ether_shost, shost, 6); /*source mac*/
|
||
|
memcpy(eh->ether_dhost, ether_aton(DEST_MAC), 6); /*destination mac*/
|
||
|
|
||
|
ph->ptp_ts = 0;
|
||
|
ph->ptp_type = ptp_mtype;
|
||
|
ph->ptp_v = 2; /*PTPv2 IEEE1588-2008*/
|
||
|
ph->ptp_ml = htons(sizeof(struct pkt_ptp) - sizeof(struct ether_header));
|
||
|
ph->ptp_dn = 0;
|
||
|
ph->ptp_flags = 0;
|
||
|
ph->ptp_cf = 0;
|
||
|
|
||
|
for(i = 0; i < 10; i++) {
|
||
|
if(i == 3)
|
||
|
ph->ptp_src[i] = 0xff;
|
||
|
else if(i == 4)
|
||
|
ph->ptp_src[i] = 0xfe;
|
||
|
else if(i == 8 || i == 9)
|
||
|
ph->ptp_src[i] = 0x00;
|
||
|
else {
|
||
|
ph->ptp_src[i] = shost[j];
|
||
|
j++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ph->ptp_sid = 0; /*TODO, add sequence number on each protocol iteration*/
|
||
|
ph->ptp_ctlf = 0; /*deprecated in PTPv2*/
|
||
|
ph->ptp_lmi = 0; /*irrelevant*/
|
||
|
|
||
|
pkt->s = 0;
|
||
|
pkt -> ns = 0;
|
||
|
return pkt;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Timestamp a PTP Ethernet packet. Optimizations needed.
|
||
|
*/
|
||
|
struct pkt_ptp *timestamp_ptp_packet(struct pkt_ptp *p) {
|
||
|
int t[2];
|
||
|
get_time(t);
|
||
|
union uint48_t n, n2;
|
||
|
n.v = t[0];
|
||
|
hton(n.c, 6, n2.c);
|
||
|
dump_payload(n2.c, 6);
|
||
|
p->s = n2.v;
|
||
|
p->ns = htonl(t[1]);
|
||
|
return p;
|
||
|
}
|