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_input(struct nm_if *nmif, int ring, char *buf, int len) { int err; struct ether_header *eh; struct ether_vlan_header *evl; struct nm_if_vlan *vlan; if (len < ETHER_HDR_LEN) { DPRINTF("%s: discarding packet, too short.\n", __func__); pktcnt.rx_drop++; return (-1); } err = 0; eh = (struct ether_header *)buf; switch (ntohs(eh->ether_type)) { case ETHERTYPE_ARP: pktcnt.rx_arp++; err = arp_input(nmif, ring, buf + ETHER_HDR_LEN, len - ETHER_HDR_LEN); break; case ETHERTYPE_IP: pktcnt.rx_ip++; err = ip_input(nmif, ring, buf + ETHER_HDR_LEN, len - ETHER_HDR_LEN); break; case ETHERTYPE_VLAN: //pktcnt.rx_vlan++; if (len < ETHER_VLAN_ENCAP_LEN) { DPRINTF("%s: discarding vlan packet, too short.\n", __func__); pktcnt.rx_drop++; return (-1); } evl = (struct ether_vlan_header *)buf; vlan = if_find_vlan(nmif, ntohs(evl->evl_tag)); if (vlan == NULL) { pktcnt.rx_drop++; DPRINTF("%s: unknown vlan tag %d, discanding packet.\n", __func__, ntohs(evl->evl_tag)); return (-1); } memmove(buf + ETHER_VLAN_ENCAP_LEN, buf, ETHER_ADDR_LEN * 2); err = ether_input(vlan->nmif, ring, buf + ETHER_VLAN_ENCAP_LEN, len - ETHER_VLAN_ENCAP_LEN); if (!nohostring && err == 1) { memmove(buf, buf + ETHER_VLAN_ENCAP_LEN, ETHER_ADDR_LEN * 2); evl = (struct ether_vlan_header *)buf; evl->evl_encap_proto = htons(ETHERTYPE_VLAN); evl->evl_tag = htons(vlan->nmif->nm_if_vtag); ether_bridge(vlan->nmif, ring, buf, len); return (0); } break; default: pktcnt.rx_drop++; DPRINTF("%s: protocol %#04x not supported, discanding packet.\n", __func__, ntohs(eh->ether_type)); err = -1; } return (err); }