void ether_bridge(struct nm_if *nmif, int ring, char *inbuf, int len) { char *buf; struct netmap_if *ifp; struct netmap_ring *nring; struct nm_if *parentif; parentif = NETMAP_PARENTIF(nmif); ifp = parentif->nm_if_ifp; if (NETMAP_HOST_RING(parentif, ring)) nring = netmap_hw_tx_ring(ifp); else nring = NETMAP_TXRING(ifp, ifp->ni_tx_rings); buf = NETMAP_GET_BUF(nring); if (buf == NULL) { DPRINTF("%s: no available buffer for tx (%s).\n", __func__, nmif->nm_if_name); parentif->nm_if_txsync = 1; pktcnt.tx_drop++; return; } /* Copy the payload. */ memcpy(buf, inbuf, len); NETMAP_UPDATE_LEN(nring, len); /* Update the current ring slot. */ NETMAP_RING_NEXT(nring); pktcnt.tx_pkts++; parentif->nm_if_txsync = 1; }
static void netmap_read(evutil_socket_t fd, short event, void *data) { char *buf; int err, i, pkts, rx_rings; struct netmap_if *ifp; struct netmap_ring *nring; struct nm_if *nmif; nmif = (struct nm_if *)data; ifp = nmif->nm_if_ifp; rx_rings = ifp->ni_rx_rings; if (!nohostring && !nmif->nm_if_vale) rx_rings++; pkts = 0; for (i = 0; i < rx_rings; i++) { nring = NETMAP_RXRING(ifp, i); while (!nm_ring_empty(nring)) { buf = NETMAP_GET_BUF(nring); err = ether_input(nmif, i, buf, NETMAP_SLOT_LEN(nring)); /* Send the packet to hw <-> host bridge. */ if (!nohostring && err == 1) err = ether_bridge(nmif, i, buf, NETMAP_SLOT_LEN(nring)); NETMAP_RING_NEXT(nring); if (err < 0 || ++pkts == burst) goto done; } } done: if_netmap_txsync(); }
int ether_output(struct nm_if *nmif, struct in_addr *dst, struct ether_addr *lladdr, unsigned short ether_type, char *inbuf, int inlen) { char *buf; int err, len; struct arp *arp; struct ether_header *eh; struct ether_vlan_header *evl; struct netmap_ring *ring; struct nm_if *parentif; if (lladdr == NULL) { err = arp_search_if(nmif, dst, &arp); if (err != 0) return (err); } parentif = NETMAP_PARENTIF(nmif); ring = netmap_hw_tx_ring(parentif->nm_if_ifp); if (ring == NULL) { DPRINTF("%s: no available ring for tx (%s).\n", __func__, parentif->nm_if_name); parentif->nm_if_txsync = 1; pktcnt.tx_drop++; return (-1); } if (inlen + ETHER_HDR_LEN > ring->nr_buf_size) { DPRINTF("%s: buffer too big, cannot tx.\n", __func__); pktcnt.tx_drop++; return (-1); } buf = NETMAP_GET_BUF(ring); if (buf == NULL) { DPRINTF("%s: no available buffer for tx (%s).\n", __func__, parentif->nm_if_name); parentif->nm_if_txsync = 1; pktcnt.tx_drop++; return (-1); } if (NETMAP_VLANIF(nmif)) { /* Copy the ethernet vlan header. */ evl = (struct ether_vlan_header *)buf; evl->evl_encap_proto = htons(ETHERTYPE_VLAN); evl->evl_tag = htons(nmif->nm_if_vtag); evl->evl_proto = htons(ether_type); if (lladdr != NULL) memcpy(evl->evl_dhost, lladdr, sizeof(evl->evl_dhost)); else memcpy(evl->evl_dhost, &arp->lladdr, sizeof(evl->evl_dhost)); memcpy(evl->evl_shost, LLADDR(&nmif->nm_if_dl), sizeof(evl->evl_shost)); len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; } else { /* Copy the ethernet header. */ eh = (struct ether_header *)buf; eh->ether_type = htons(ether_type); if (lladdr != NULL) memcpy(eh->ether_dhost, lladdr, sizeof(eh->ether_dhost)); else memcpy(eh->ether_dhost, &arp->lladdr, sizeof(eh->ether_dhost)); memcpy(eh->ether_shost, LLADDR(&nmif->nm_if_dl), sizeof(eh->ether_shost)); len = ETHER_HDR_LEN; } /* Copy the payload. */ memcpy(buf + len, inbuf, inlen); len += inlen; NETMAP_UPDATE_LEN(ring, len); //DPRINTF("%s: len: %d\n", __func__, len); //if (verbose) hexdump(buf, len, NULL, 0); /* Update the current ring slot. */ NETMAP_RING_NEXT(ring); pktcnt.tx_pkts++; parentif->nm_if_txsync = 1; return (0); }