// Copyright (c) PLUMgrid, Inc. // Licensed under the Apache License, Version 2.0 (the "License") #include struct IPKey { u32 dip; u32 sip; }; struct IPLeaf { u32 xdip; u32 xsip; u64 ip_xlated_pkts; u64 arp_xlated_pkts; }; BPF_HASH(xlate, struct IPKey, struct IPLeaf, 1024); int on_packet(struct __sk_buff *skb) { u8 *cursor = 0; u32 orig_dip = 0; u32 orig_sip = 0; struct IPLeaf xleaf = {}; ethernet: { struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet)); switch (ethernet->type) { case ETH_P_IP: goto ip; case ETH_P_ARP: goto arp; case ETH_P_8021Q: goto dot1q; default: goto EOP; } } dot1q: { struct dot1q_t *dot1q = cursor_advance(cursor, sizeof(*dot1q)); switch (dot1q->type) { case ETH_P_IP: goto ip; case ETH_P_ARP: goto arp; default: goto EOP; } } arp: { struct arp_t *arp = cursor_advance(cursor, sizeof(*arp)); orig_dip = arp->tpa; orig_sip = arp->spa; struct IPKey key = {.dip=orig_dip, .sip=orig_sip}; struct IPLeaf *xleafp = xlate.lookup(&key); if (xleafp) { xleaf = *xleafp; arp->tpa = xleaf.xdip; arp->spa = xleaf.xsip; lock_xadd(&xleafp->arp_xlated_pkts, 1); } goto EOP; } ip: { struct ip_t *ip = cursor_advance(cursor, sizeof(*ip)); orig_dip = ip->dst; orig_sip = ip->src; struct IPKey key = {.dip=orig_dip, .sip=orig_sip}; struct IPLeaf *xleafp = xlate.lookup(&key); if (xleafp) { xleaf = *xleafp; ip->dst = xleaf.xdip; incr_cksum_l3(&ip->hchecksum, orig_dip, xleaf.xdip); ip->src = xleaf.xsip; incr_cksum_l3(&ip->hchecksum, orig_sip, xleaf.xsip); lock_xadd(&xleafp->ip_xlated_pkts, 1); } switch (ip->nextp) { case 6: goto tcp; case 17: goto udp; default: goto EOP; } } udp: { struct udp_t *udp = cursor_advance(cursor, sizeof(*udp)); if (xleaf.xdip) { incr_cksum_l4(&udp->crc, orig_dip, xleaf.xdip, 1); incr_cksum_l4(&udp->crc, orig_sip, xleaf.xsip, 1); } goto EOP; } tcp: { struct tcp_t *tcp = cursor_advance(cursor, sizeof(*tcp)); if (xleaf.xdip) { incr_cksum_l4(&tcp->cksum, orig_dip, xleaf.xdip, 1); incr_cksum_l4(&tcp->cksum, orig_sip, xleaf.xsip, 1); } goto EOP; } EOP: return 0; }