aboutsummaryrefslogtreecommitdiffstats
path: root/tools/vnet/vnet-module/vnet_forward.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/vnet/vnet-module/vnet_forward.c')
-rw-r--r--tools/vnet/vnet-module/vnet_forward.c389
1 files changed, 0 insertions, 389 deletions
diff --git a/tools/vnet/vnet-module/vnet_forward.c b/tools/vnet/vnet-module/vnet_forward.c
deleted file mode 100644
index 74a55c4582..0000000000
--- a/tools/vnet/vnet-module/vnet_forward.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2005, 2006 Mike Wray <mike.wray@hp.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free software Foundation, Inc.,
- * 59 Temple Place, suite 330, Boston, MA 02111-1307 USA
- *
- */
-#ifdef __KERNEL__
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <linux/version.h>
-#include <linux/spinlock.h>
-
-#include <linux/skbuff.h>
-#include <linux/net.h>
-#include <linux/netdevice.h>
-#include <linux/in.h>
-#include <linux/inet.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/udp.h>
-
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/route.h>
-#include <net/checksum.h>
-
-#else
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "sys_kernel.h"
-#include "spinlock.h"
-#include "skbuff.h"
-#include <linux/ip.h>
-#include <linux/udp.h>
-
-#endif
-
-#include <varp.h>
-#include <if_varp.h>
-#include <varp.h>
-#include <skb_util.h>
-#include <skb_context.h>
-
-#include "allocate.h"
-#include "iostream.h"
-#include "hash_table.h"
-#include "vnet_forward.h"
-
-#define MODULE_NAME "VNET"
-#define DEBUG 1
-#undef DEBUG
-#include "debug.h"
-
-extern int _skb_xmit(struct sk_buff *skb, uint32_t saddr);
-
-typedef struct VnetPeer {
- struct VarpAddr addr;
- uint16_t port;
- atomic_t refcount;
- int tx_packets;
- int rx_packets;
-} VnetPeer;
-
-static HashTable *vnet_peer_table = NULL;
-static rwlock_t vnet_peer_table_lock = RW_LOCK_UNLOCKED;
-
-#define vnet_peer_read_lock(flags) read_lock_irqsave(&vnet_peer_table_lock, (flags))
-#define vnet_peer_read_unlock(flags) read_unlock_irqrestore(&vnet_peer_table_lock, (flags))
-#define vnet_peer_write_lock(flags) write_lock_irqsave(&vnet_peer_table_lock, (flags))
-#define vnet_peer_write_unlock(flags) write_unlock_irqrestore(&vnet_peer_table_lock, (flags))
-
-static void VnetPeer_decref(VnetPeer *peer){
- if(!peer) return;
- if(atomic_dec_and_test(&peer->refcount)){
- kfree(peer);
- }
-}
-
-static void VnetPeer_incref(VnetPeer *peer){
- if(!peer) return;
- atomic_inc(&peer->refcount);
-}
-
-static void VnetPeer_print(VnetPeer *peer, IOStream *io){
- char addrbuf[VARP_ADDR_BUF];
-
- IOStream_print(io, "(vnet_peer\n");
- IOStream_print(io, " (addr %s)\n", VarpAddr_ntoa(&peer->addr, addrbuf));
- IOStream_print(io, " (port %d)\n", htons(peer->port));
- IOStream_print(io, " (tx_packets %d)\n", peer->tx_packets);
- IOStream_print(io, " (rx_packets %d)\n", peer->tx_packets);
- IOStream_print(io, ")\n");
-}
-
-static int VnetPeer_forward(VnetPeer *peer, struct sk_buff *fwdskb){
- int err = 0;
- const int ip_n = sizeof(struct iphdr);
- const int udp_n = sizeof(struct udphdr);
- const int vnet_n = sizeof(struct VnetMsgHdr);
- int head_n = 16 + ip_n + udp_n + vnet_n;
- int push_n = 0;
- struct sk_buff *skb = NULL;
- struct VnetMsgHdr *vhdr;
- uint32_t saddr = 0;
- uint16_t sport = varp_port;
- uint32_t daddr = peer->addr.u.ip4.s_addr;
- uint16_t dport = varp_port;
-
- if(!fwdskb) goto exit;
- if(daddr == fwdskb->nh.iph->saddr){
- // Don't forward if the skb src addr is the peer addr.
- dprintf("> Forward loop on " IPFMT "\n", NIPQUAD(daddr));
- goto exit;
- }
- // On entry fwdskb->data should be at fwdskb->nh.raw (adjust if not).
- // Also fwdskb->h.raw and fwdskb->nh.raw are set.
- if(fwdskb->data > fwdskb->nh.raw){
- push_n = fwdskb->data - fwdskb->nh.raw;
- head_n += push_n;
- }
- // If has headroom, copies header (which incs ref on dst),
- // otherwise only clones header, which does not inc ref on dst.
- skb = skb_realloc_headroom(fwdskb, head_n);
- //skb = skb_copy_expand(fwdskb, head_n, 0, GFP_ATOMIC);
- if(!skb){
- err = -ENOMEM;
- goto exit;
- }
-
- if(push_n){
- skb_push(skb, push_n);
- }
-
-#ifdef DEBUG
- printk("\nOriginal packet:\n");
- print_iphdr(__FUNCTION__, skb);
- skb_print_bits(__FUNCTION__, skb, 0, skb->len);
-#endif
-
- skb->mac.raw = NULL;
- vhdr = (void*)skb_push(skb, vnet_n);
- vhdr->id = htons(VFWD_ID);
- vhdr->opcode = 0;
-
- // Setup the UDP header.
- skb->h.raw = skb_push(skb, udp_n);
- skb->h.uh->source = sport; // Source port.
- skb->h.uh->dest = dport; // Destination port.
- skb->h.uh->len = htons(skb->len); // Total packet length (bytes).
- skb->h.uh->check = 0;
-
- // Setup the IP header.
- skb->nh.raw = skb_push(skb, ip_n);
- skb->nh.iph->version = 4; // Standard version.
- skb->nh.iph->ihl = ip_n / 4; // IP header length (32-bit words).
- skb->nh.iph->tos = 0; // No special type-of-service.
- skb->nh.iph->tot_len = htons(skb->len); // Total packet length (bytes).
- skb->nh.iph->id = 0; // No flow id.
- skb->nh.iph->protocol = IPPROTO_UDP; // IP protocol number.
- skb->nh.iph->frag_off = 0;
- skb->nh.iph->ttl = 64; // Linux default time-to-live.
- skb->nh.iph->saddr = saddr; // Source address.
- skb->nh.iph->daddr = daddr; // Destination address.
- skb->nh.iph->check = 0;
-
-#ifdef DEBUG
- printk("\nWrapped packet:\n");
- print_iphdr(__FUNCTION__, skb);
- print_udphdr(__FUNCTION__, skb);
- skb_print_bits(__FUNCTION__, skb, 0, skb->len);
-#endif
-
- err = _skb_xmit(skb, saddr);
- peer->tx_packets++;
-
- exit:
- if(err < 0) kfree_skb(skb);
- return err;
-}
-
-int vnet_peer_get(VarpAddr *addr, VnetPeer **peer){
- unsigned long flags;
-
- vnet_peer_read_lock(flags);
- *peer = HashTable_get(vnet_peer_table, addr);
- VnetPeer_incref(*peer);
- vnet_peer_read_unlock(flags);
- return (*peer ? 0 : -ENOENT);
-}
-
-int vnet_peer_add(VarpAddr *addr, uint16_t port){
- int err = 0;
- unsigned long flags;
- VnetPeer *peer;
-
- vnet_peer_write_lock(flags);
- peer = HashTable_get(vnet_peer_table, addr);
- if(peer){
- VnetPeer_incref(peer);
- goto exit;
- }
- peer = ALLOCATE(VnetPeer);
- if(!peer){
- err = -ENOMEM;
- goto exit;
- }
- peer->addr = *addr;
- peer->port = port;
- VnetPeer_incref(peer);
- if(!HashTable_add(vnet_peer_table, &peer->addr, peer)){
- VnetPeer_decref(peer);
- err = -ENOMEM;
- }
- exit:
- vnet_peer_write_unlock(flags);
- return err;
-}
-
-int vnet_peer_del(VarpAddr *addr){
- int ret = 0;
- unsigned long flags;
-
- vnet_peer_write_lock(flags);
- ret = HashTable_remove(vnet_peer_table, addr);
- vnet_peer_write_unlock(flags);
- return ret;
-}
-
-void vnet_peer_print(IOStream *io){
- HashTable_for_decl(entry);
- unsigned long flags;
-
- if(!vnet_peer_table) return;
- vnet_peer_read_lock(flags);
- HashTable_for_each(entry, vnet_peer_table){
- VnetPeer *peer = entry->value;
- VnetPeer_print(peer, io);
- }
- vnet_peer_read_unlock(flags);
-}
-
-int vnet_forward_send(struct sk_buff *skb){
- int err = 0;
- unsigned long flags;
- HashTable_for_decl(entry);
- int count = 0;
-
- if(!vnet_peer_table){
- goto exit;
- }
- vnet_peer_read_lock(flags);
- HashTable_for_each(entry, vnet_peer_table){
- VnetPeer *peer = entry->value;
- VnetPeer_forward(peer, skb);
- count++;
- }
- vnet_peer_read_unlock(flags);
- exit:
- return err;
-}
-
-int vnet_forward_recv(struct sk_buff *skb){
- int err = 0;
- VarpAddr addr = { .family = AF_INET };
- VnetPeer *peer = NULL;
- unsigned char eth[ETH_HLEN] = {};
- struct sk_buff *recvskb;
-
- if(!vnet_peer_table){
- dprintf("> no table\n");
- return -ENOSYS;
- }
- // On entry mac.raw, h.raw, nh.raw are set.
- // skb->data points after the fwd vnet header, at the complete
- // forwarded packet (which has IP hdr, no eth hdr).
-
- // Save the eth hdr and source addr (peer).
- memcpy(eth, skb->mac.raw, ETH_HLEN);
- addr.u.ip4.s_addr = skb->nh.iph->saddr;
- err = vnet_peer_get(&addr, &peer);
- if(err){
- wprintf("> no peer for " IPFMT "\n", NIPQUAD(skb->nh.iph->saddr));
- goto exit;
- }
- peer->rx_packets++;
- skb->mac.raw = NULL;
- skb->nh.raw = skb->data;
- skb->h.raw = skb->data + sizeof(struct iphdr);
- if(!skb->nh.iph->saddr){
- skb->nh.iph->saddr = addr.u.ip4.s_addr;
- }
-#ifdef __KERNEL__
- // Fix IP options, checksum, skb dst, netfilter state.
- memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
- skb->dev = NULL;
- dst_release(skb->dst);
- skb->dst = NULL;
- nf_reset(skb);
-#endif // __KERNEL__
-
- skb->mac.raw = skb->nh.raw - ETH_HLEN;
- memcpy(skb->mac.raw, eth, ETH_HLEN);
-
- // Map destination mcast addresses to our mcast address.
- if(MULTICAST(skb->nh.iph->daddr)){
- skb->nh.iph->daddr = varp_mcast_addr;
- //xmit does this: ip_eth_mc_map(varp_mcast_addr, eth_hdr(skb)->h_dest);
- }
-
- // Handle (a copy of) it ourselves, because
- // if it is looped-back by xmit it will be ignored.
- recvskb = alloc_skb(skb->len, GFP_ATOMIC);
- if(recvskb){
- recvskb->protocol = htons(ETH_P_IP);
-
- recvskb->nh.raw = skb_put(recvskb, skb->len);
- recvskb->h.raw = recvskb->data + sizeof(struct iphdr);
- skb_copy_bits(skb, 0, recvskb->data, skb->len);
-
- // Data points at the unwrapped iphdr, but varp_handle_message()
- // expects it to point at the udphdr, so pull.
- skb_pull_vn(recvskb, sizeof(struct iphdr));
- if(varp_handle_message(recvskb) <= 0){
- kfree_skb(recvskb);
- }
- }
- err = _skb_xmit(skb, skb->nh.iph->saddr);
- if(err >= 0) err = 1;
- exit:
- return err;
-}
-
-/** Hash function for keys in the peer table.
- */
-static Hashcode peer_key_hash_fn(void *k){
- return hash_hvoid(0, k, sizeof(struct VarpAddr));
-}
-
-/** Equality function for keys in the peer table.
- */
-static int peer_key_equal_fn(void *k1, void *k2){
- return memcmp(k1, k2, sizeof(struct VarpAddr)) == 0;
-}
-
-static void peer_entry_free_fn(HashTable *table, HTEntry *entry){
- if(!entry) return;
- VnetPeer_decref((VnetPeer*)entry->value);
- HTEntry_free(entry);
-}
-
-int vnet_forward_init(void){
- int err = 0;
- if(vnet_peer_table) goto exit;
- vnet_peer_table = HashTable_new(0);
- if(!vnet_peer_table){
- err = -ENOMEM;
- goto exit;
- }
- vnet_peer_table->key_size = sizeof(struct VarpAddr);
- vnet_peer_table->key_equal_fn = peer_key_equal_fn;
- vnet_peer_table->key_hash_fn = peer_key_hash_fn;
- vnet_peer_table->entry_free_fn = peer_entry_free_fn;
- exit:
- return err;
-}
-
-void vnet_forward_exit(void){
- HashTable_free(vnet_peer_table);
- vnet_peer_table = NULL;
-}