OVS_CHECK_NDEBUG
OVS_CHECK_NETLINK
OVS_CHECK_OPENSSL
-OVS_CHECK_SNAT
OVS_CHECK_LOGDIR
OVS_CHECK_CURSES
OVS_CHECK_LINUX_VT_H
dp_dev.c \
dp_notify.c \
flow.c \
- snat.c \
table.c
openvswitch_headers = \
compat.h \
datapath.h \
dp_dev.h \
- flow.h \
- snat.h
+ flow.h
dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
#include "dp_dev.h"
#include "actions.h"
#include "openvswitch/datapath-protocol.h"
-#include "snat.h"
struct sk_buff *
make_writable(struct sk_buff *skb, gfp_t gfp)
return length;
}
-#ifdef SUPPORT_SNAT
-static int
-dp_xmit_skb_finish(struct sk_buff *skb)
-{
- /* Copy back the Ethernet header that was stowed earlier. */
- if (skb->protocol == htons(ETH_P_IP) && snat_copy_header(skb)) {
- kfree_skb(skb);
- return -EINVAL;
- }
- skb_reset_mac_header(skb);
-
- if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb)) {
- printk("dropped over-mtu packet: %d > %d\n",
- packet_length(skb), skb->dev->mtu);
- kfree_skb(skb);
- return -E2BIG;
- }
-
- skb_push(skb, ETH_HLEN);
- dev_queue_xmit(skb);
-
- return 0;
-}
-
-int dp_xmit_skb(struct sk_buff *skb)
-{
- int len = skb->len;
- int err;
-
- skb_pull(skb, ETH_HLEN);
-
- /* The ip_fragment function does not copy the Ethernet header into
- * the newly generated frames, so stow the original. */
- if (skb->protocol == htons(ETH_P_IP))
- snat_save_header(skb);
-
- if (skb->protocol == htons(ETH_P_IP) &&
- skb->len > skb->dev->mtu &&
- !skb_is_gso(skb)) {
- err = ip_fragment(skb, dp_xmit_skb_finish);
- } else {
- err = dp_xmit_skb_finish(skb);
- }
- if (err)
- return err;
-
- return len;
-}
-#else
int dp_xmit_skb(struct sk_buff *skb)
{
struct datapath *dp = skb->dev->br_port->dp;
return len;
}
-#endif
static void
do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
case ODPAT_SET_TP_DST:
skb = set_tp_port(skb, key, &a->tp_port, gfp);
break;
-
-#ifdef SUPPORT_SNAT
- case ODPAT_SNAT:
- snat_skb(dp, skb, a->snat.port, gfp);
- break;
-#endif
}
if (!skb)
return -ENOMEM;
#include "openvswitch/datapath-protocol.h"
#include "datapath.h"
-#include "snat.h"
#include "actions.h"
#include "dp_dev.h"
#include "flow.h"
/* Number of milliseconds between runs of the maintenance thread. */
#define MAINT_SLEEP_MSECS 1000
-#ifdef SUPPORT_SNAT
-static int dp_maint_func(void *data);
-#endif
static int new_nbp(struct datapath *, struct net_device *, int port_no);
/* Must be called with rcu_read_lock or dp_mutex. */
if (!dp->stats_percpu)
goto err_destroy_local_port;
-#ifdef SUPPORT_SNAT
- dp->dp_task = kthread_run(dp_maint_func, dp, "dp%d", dp_idx);
- if (IS_ERR(dp->dp_task))
- goto err_destroy_stats_percpu;
-#endif
-
rcu_assign_pointer(dps[dp_idx], dp);
mutex_unlock(&dp_mutex);
rtnl_unlock();
return 0;
-#ifdef SUPPORT_SNAT
-err_destroy_stats_percpu:
- free_percpu(dp->stats_percpu);
-#endif
err_destroy_local_port:
dp_del_port(dp->ports[ODPP_LOCAL], NULL);
err_destroy_table:
struct net_bridge_port *p, *n;
int i;
-#ifdef SUPPORT_SNAT
- send_sig(SIGKILL, dp->dp_task, 0);
- kthread_stop(dp->dp_task);
-#endif
-
if (dp_del_dp_hook)
dp_del_dp_hook(dp);
dev_set_promiscuity(dev, 1);
dev_hold(dev);
p->port_no = port_no;
-#ifdef SUPPORT_SNAT
- spin_lock_init(&p->lock);
-#endif
p->dp = dp;
p->dev = dev;
if (!is_dp_dev(dev))
return err;
}
-/* Free any SNAT configuration on the port. */
-static void free_snat(struct net_bridge_port *p)
-{
-#ifdef SUPPORT_SNAT
- unsigned long int flags;
- spin_lock_irqsave(&p->lock, flags);
- snat_free_conf(p);
- spin_unlock_irqrestore(&p->lock, flags);
-#endif /* !SUPPORT_SNAT */
-}
-
int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
{
ASSERT_RTNL();
/* Then wait until no one is still using it, and destroy it. */
synchronize_rcu();
- free_snat(p);
if (is_dp_dev(p->dev)) {
dp_dev_destroy(p->dev);
return err;
}
-#ifdef SUPPORT_SNAT
-static int dp_maint_func(void *data)
-{
- struct datapath *dp = (struct datapath *) data;
-
- allow_signal(SIGKILL);
- while (!signal_pending(current)) {
- struct net_bridge_port *p;
-
- /* Expire old SNAT entries */
- rcu_read_lock();
- list_for_each_entry_rcu (p, &dp->port_list, node)
- snat_maint(p);
- rcu_read_unlock();
- msleep_interruptible(MAINT_SLEEP_MSECS);
- }
- while (!kthread_should_stop()) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
- }
- return 0;
-}
-#endif
-
/* Must be called with rcu_read_lock. */
static void
do_port_input(struct net_bridge_port *p, struct sk_buff *skb)
if (!skb)
return;
-#ifdef SUPPORT_SNAT
- /* Check if this packet needs early SNAT processing. */
- if (snat_pre_route(skb))
- return;
-#endif
-
/* Push the Ethernet header back on. */
skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
for (i = 0; i < actions->n_actions; i++) {
const union odp_action *a = &actions->actions[i];
switch (a->type) {
- case ODPAT_SNAT:
- if (a->snat.port >= DP_MAX_PORTS)
- return -EINVAL;
-#ifndef SUPPORT_SNAT
- if (net_ratelimit())
- printk(KERN_ERR "SNAT not supported\n");
- return -EOPNOTSUPP;
-#endif
-
case ODPAT_OUTPUT:
if (a->output.port >= DP_MAX_PORTS)
return -EINVAL;
int dp_idx = iminor(f->f_dentry->d_inode);
struct datapath *dp;
int drop_frags, listeners, port_no;
-#ifdef SUPPORT_SNAT
- struct odp_snat_config osc;
-#endif
int err;
/* Handle commands with special locking requirements up front. */
err = do_execute(dp, (struct odp_execute __user *)argp);
break;
-#ifdef SUPPORT_SNAT
- case ODP_SNAT_ADD_PORT:
- err = -EFAULT;
- if (copy_from_user(&osc, (struct odp_snat_config __user *)argp,
- sizeof osc))
- break;
- err = snat_add_port(dp, &osc);
- break;
-
- case ODP_SNAT_DEL_PORT:
- err = get_user(port_no, (int __user *)argp);
- if (err)
- break;
- err = snat_del_port(dp, port_no);
- break;
-#endif
-
default:
err = -ENOIOCTLCMD;
break;
struct mutex mutex;
int dp_idx;
-#ifdef SUPPORT_SNAT
- struct task_struct *dp_task; /* Kernel thread for maintenance. */
-#endif
-
#ifdef SUPPORT_SYSFS
struct kobject ifobj;
#endif
struct net_device *dev;
#ifdef SUPPORT_SYSFS
struct kobject kobj;
-#endif
-#ifdef SUPPORT_SNAT
- spinlock_t lock;
- struct snat_conf *snat;
#endif
struct list_head node; /* Element in datapath.ports. */
};
#include "datapath.h"
#include "dp_dev.h"
-#include "snat.h"
struct datapath *dp_dev_get_dp(struct net_device *netdev)
{
{
struct dp_dev *dp_dev = dp_dev_priv(netdev);
int len;
-#ifdef SUPPORT_SNAT
- snat_internal_in(skb);
-#endif
len = skb->len;
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, netdev);
/linux-2.6
/modules.order
/random32.c
-/snat.c
/table.c
/tmp
/veth.c
EXTRA_CFLAGS += -I$(srcdir)/..
EXTRA_CFLAGS += -I$(builddir)/..
EXTRA_CFLAGS += -I$(top_srcdir)/include
-EXTRA_CFLAGS += @SUPPORT_SNAT@
ifeq '$(BUILDNR)' '0'
EXTRA_CFLAGS += -DBUILDNR=\"\"
else
+++ /dev/null
-#ifdef SUPPORT_SNAT
-/*
- * Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2008, 2009 Nicira Networks
- */
-
-#include <linux/etherdevice.h>
-#include <linux/netdevice.h>
-#include <linux/netfilter.h>
-#include <linux/netfilter_bridge.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/in.h>
-#include <net/ip.h>
-#include <linux/icmp.h>
-#include <linux/if_ether.h>
-#include <net/arp.h>
-#include <net/route.h>
-
-#include "actions.h"
-#include "snat.h"
-
-/* Cache of IP->MAC mappings on the side hidden by the SNAT */
-struct snat_mapping {
- struct list_head node;
- u32 ip_addr; /* Stored in network-order */
- u8 hw_addr[ETH_ALEN];
- unsigned long used; /* Last used time (in jiffies). */
-
- struct rcu_head rcu;
-};
-
-struct snat_conf {
- u32 ip_addr_start; /* Stored in host-order */
- u32 ip_addr_end; /* Stored in host-order */
- u16 mac_timeout;
-
- u8 mac_addr[ETH_ALEN];
-
- struct list_head mappings; /* List of snat_mapping entries */
-};
-
-#define MAC_TIMEOUT_DEFAULT 120
-
-/* We need these fake structures to make netfilter happy --
- * lots of places assume that skb->dst != NULL, which isn't
- * all that unreasonable.
- *
- * Currently, we fill in the PMTU entry because netfilter
- * refragmentation needs it, and the rt_flags entry because
- * ipt_REJECT needs it. Future netfilter modules might
- * require us to fill additional fields. */
-static struct net_device __fake_net_device = {
- .hard_header_len = ETH_HLEN
-};
-
-static struct rtable __fake_rtable = {
- .u = {
- .dst = {
- .__refcnt = ATOMIC_INIT(1),
- .dev = &__fake_net_device,
- .path = &__fake_rtable.u.dst,
- .metrics = {[RTAX_MTU - 1] = 1500},
- .flags = DST_NOXFRM,
- }
- },
- .rt_flags = 0,
-};
-
-/* Define ARP for IP since the Linux headers don't do it cleanly. */
-struct ip_arphdr {
- u16 ar_hrd;
- u16 ar_pro;
- u8 ar_hln;
- u8 ar_pln;
- u16 ar_op;
- u8 ar_sha[ETH_ALEN];
- u32 ar_sip;
- u8 ar_tha[ETH_ALEN];
- u32 ar_tip;
-} __attribute__((packed));
-
-static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
-{
- skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC);
- if (likely(skb->nf_bridge))
- atomic_set(&(skb->nf_bridge->use), 1);
-
- return skb->nf_bridge;
-}
-
-/* Save a copy of the original Ethernet header. */
-void snat_save_header(struct sk_buff *skb)
-{
- int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
-
- if (!skb->nf_bridge)
- return;
-
- skb_copy_from_linear_data_offset(skb, -header_size,
- skb->nf_bridge->data, header_size);
-}
-
-/* Restore a saved Ethernet header. */
-int snat_copy_header(struct sk_buff *skb)
-{
- int err;
- int header_size = ETH_HLEN + nf_bridge_encap_header_len(skb);
-
- if (!skb->nf_bridge)
- return 0;
-
- err = skb_cow_head(skb, header_size);
- if (err)
- return err;
-
- skb_copy_to_linear_data_offset(skb, -header_size,
- skb->nf_bridge->data, header_size);
- __skb_push(skb, nf_bridge_encap_header_len(skb));
- return 0;
-}
-
-/* Push the Ethernet header back on and tranmit the packet. */
-static int
-dp_xmit_skb_push(struct sk_buff *skb)
-{
- skb_push(skb, ETH_HLEN);
- return dp_xmit_skb(skb);
-}
-
-/* Perform maintainence related to a SNAT'd interface. Currently, this only
- * checks whether MAC->IP bindings have expired.
- *
- * Called with the RCU read lock */
-void
-snat_maint(struct net_bridge_port *p)
-{
- struct snat_conf *sc;
- struct snat_mapping *m, *n;
- unsigned long flags;
- unsigned long timeout;
-
- spin_lock_irqsave(&p->lock, flags);
- sc = p->snat;
- if (!sc)
- goto done;
-
- timeout = sc->mac_timeout * HZ;
-
- list_for_each_entry_safe (m, n, &sc->mappings, node) {
- if (time_after(jiffies, m->used + timeout)) {
- list_del(&m->node);
- kfree(m);
- }
- }
-
-done:
- spin_unlock_irqrestore(&p->lock, flags);
-}
-
-/* When the packet is bound for an internal interface, strip off the fake
- * routing table.
- */
-void snat_internal_in(struct sk_buff *skb)
-{
- if (skb->dst == (struct dst_entry *)&__fake_rtable) {
- dst_release(skb->dst);
- skb->dst = NULL;
- }
-}
-
-/* Check whether destination IP's address is in the IP->MAC mappings.
- * If it is, then overwrite the destination MAC with the value from the
- * cache.
- *
- * Returns -1 if there is a problem, otherwise 0. */
-static int
-dnat_mac(struct net_bridge_port *p, struct sk_buff *skb)
-{
- struct snat_conf *sc = p->snat;
- struct iphdr *iph = ip_hdr(skb);
- struct ethhdr *eh = eth_hdr(skb);
- struct snat_mapping *m;
-
- if (skb->protocol != htons(ETH_P_IP))
- return 0;
-
- list_for_each_entry (m, &sc->mappings, node) {
- if (m->ip_addr == iph->daddr){
- /* Found it! */
- skb = make_writable(skb, GFP_ATOMIC);
- if (!skb)
- return -1;
- m->used = jiffies;
- memcpy(eh->h_dest, m->hw_addr, ETH_ALEN);
- break;
- }
- }
-
- return 0;
-}
-
-static int
-__snat_this_address(struct snat_conf *sc, u32 ip_addr)
-{
- if (sc) {
- u32 h_ip_addr = ntohl(ip_addr);
- return (h_ip_addr >= sc->ip_addr_start &&
- h_ip_addr <= sc->ip_addr_end);
- }
- return 0;
-}
-
-static int
-snat_this_address(struct net_bridge_port *p, u32 ip_addr)
-{
- unsigned long int flags;
- int retval;
-
- spin_lock_irqsave(&p->lock, flags);
- retval = __snat_this_address(p->snat, ip_addr);
- spin_unlock_irqrestore(&p->lock, flags);
-
- return retval;
-}
-
-/* Must hold RCU lock. */
-static struct net_bridge_port *
-get_nbp_by_ip_addr(struct datapath *dp, u32 ip_addr)
-{
- struct net_bridge_port *p;
-
- list_for_each_entry_rcu (p, &dp->port_list, node)
- if (snat_this_address(p, ip_addr))
- return p;
-
- return NULL;
-}
-
-static int
-snat_pre_route_finish(struct sk_buff *skb)
-{
- struct net_bridge_port *p = skb->dev->br_port;
- struct snat_conf *sc;
- struct iphdr *iph = ip_hdr(skb);
- unsigned long flags;
-
- skb->dst = (struct dst_entry *)&__fake_rtable;
- dst_hold(skb->dst);
-
- /* Don't process packets that were not translated due to NAT */
- spin_lock_irqsave(&p->lock, flags);
- sc = p->snat;
- if (!__snat_this_address(sc, iph->daddr)) {
- /* If SNAT is configured for this input device, check the
- * IP->MAC mappings to see if we should update the destination
- * MAC. */
- if (sc)
- dnat_mac(skb->dev->br_port, skb);
-
- }
- spin_unlock_irqrestore(&p->lock, flags);
-
- /* Pass the translated packet as input to the openvswitch stack, which
- * consumes it. */
- skb_push(skb, ETH_HLEN);
- skb_reset_mac_header(skb);
- dp_process_received_packet(skb, p);
-
- return 0;
-}
-
-/* Checks whether 'skb' is an ARP request for an SNAT'd interface. If
- * so, it will generate a response.
- *
- * Returns 0 if the packet was not handled. Otherwise, -1 is returned
- * and the caller is responsible for freeing 'skb'. */
-static int
-handle_arp_snat(struct sk_buff *skb)
-{
- struct net_bridge_port *s_nbp = skb->dev->br_port;
- struct net_bridge_port *nat_nbp;
- struct ip_arphdr *ah;
- u8 mac_addr[ETH_ALEN];
-
- if (!pskb_may_pull(skb, sizeof *ah))
- return 0;
-
- ah = (struct ip_arphdr *)arp_hdr(skb);
- if ((ah->ar_op != htons(ARPOP_REQUEST))
- || ah->ar_hln != ETH_ALEN
- || ah->ar_pro != htons(ETH_P_IP)
- || ah->ar_pln != 4)
- return 0;
-
- rcu_read_lock();
- nat_nbp = get_nbp_by_ip_addr(s_nbp->dp, ah->ar_tip);
- if (!nat_nbp) {
- rcu_read_unlock();
- return 0;
- }
- if (s_nbp == nat_nbp)
- memcpy(mac_addr, s_nbp->dp->ports[ODPP_LOCAL]->dev->dev_addr, sizeof(mac_addr));
- else if (!is_zero_ether_addr(nat_nbp->snat->mac_addr))
- memcpy(mac_addr, nat_nbp->snat->mac_addr, sizeof(mac_addr));
- else {
- rcu_read_unlock();
- return 0;
- }
- rcu_read_unlock();
-
- arp_send(ARPOP_REPLY, ETH_P_ARP, ah->ar_sip, skb->dev, ah->ar_tip,
- ah->ar_sha, mac_addr, ah->ar_sha);
-
- return -1;
-}
-
-/* Checks whether 'skb' is a ping request for an SNAT'd interface. If
- * so, it will generate a response.
- *
- * Returns 0 if the packet was not handled. Otherwise, -1 is returned
- * and the caller is responsible for freeing 'skb'. */
-static int
-handle_icmp_snat(struct sk_buff *skb)
-{
- struct net_bridge_port *p = skb->dev->br_port;
- struct ethhdr *eh;
- struct iphdr *iph;
- struct icmphdr *icmph;
- u8 tmp_eth[ETH_ALEN];
- u32 tmp_ip;
- struct sk_buff *nskb;
-
- /* We're only interested in addresses we rewrite. */
- iph = ip_hdr(skb);
- if (!snat_this_address(p, iph->daddr)) {
- return 0;
- }
-
- /* Drop fragments and packets not long enough to hold the ICMP
- * header. */
- if ((ntohs(iph->frag_off) & IP_OFFSET) != 0 ||
- !pskb_may_pull(skb, skb_transport_offset(skb) + 4))
- return 0;
-
- /* We only respond to echo requests to our address. Continue
- * processing replies and other ICMP messages since they may be
- * intended for NAT'd hosts. */
- icmph = icmp_hdr(skb);
- if (icmph->type != ICMP_ECHO)
- return 0;
-
- /* Send an echo reply in response */
- nskb = skb_copy(skb, GFP_ATOMIC);
- if (!nskb)
- return -1;
-
- /* Update Ethernet header. */
- eh = eth_hdr(nskb);
- memcpy(tmp_eth, eh->h_dest, ETH_ALEN);
- memcpy(eh->h_dest, eh->h_source, ETH_ALEN);
- memcpy(eh->h_source, tmp_eth, ETH_ALEN);
-
- /* Update IP header.
- * This is kind of busted, at least in that it doesn't check that the
- * echoed IP options make sense. */
- iph = ip_hdr(nskb);
- iph->id = 0;
- iph->frag_off = 0;
- iph->ttl = IPDEFTTL;
- iph->check = 0;
- tmp_ip = iph->daddr;
- iph->daddr = iph->saddr;
- iph->saddr = tmp_ip;
- iph->check = ip_fast_csum((void *)iph, iph->ihl);
-
- /* Update ICMP header. */
- icmph = icmp_hdr(nskb);
- icmph->type = ICMP_ECHOREPLY;
- icmph->checksum = 0;
- icmph->checksum = ip_compute_csum((void *)icmph,
- nskb->tail - skb_transport_header(nskb));
-
- dp_xmit_skb_push(nskb);
-
- return -1;
-}
-
-/* Check if any SNAT maintenance needs to be done on 'skb' before it's
- * checked against the datapath's tables. This includes DNAT
- * modification based on prior SNAT action and responding to ARP and
- * echo requests for the SNAT interface.
- *
- * Returns -1 if the packet was handled and consumed, 0 if the caller
- * should continue to process 'skb'.
- */
-int
-snat_pre_route(struct sk_buff *skb)
-{
- struct iphdr *iph;
- int len;
-
- WARN_ON_ONCE(skb_network_offset(skb));
- if (skb->protocol == htons(ETH_P_ARP)) {
- if (handle_arp_snat(skb))
- goto consume;
- return 0;
- }
- else if (skb->protocol != htons(ETH_P_IP))
- return 0;
-
- if (!pskb_may_pull(skb, sizeof *iph))
- goto consume;
-
- iph = ip_hdr(skb);
- if (iph->ihl < 5 || iph->version != 4)
- goto consume;
-
- if (!pskb_may_pull(skb, ip_hdrlen(skb)))
- goto consume;
- skb_set_transport_header(skb, ip_hdrlen(skb));
-
- /* Check if we need to echo reply for this address */
- iph = ip_hdr(skb);
- if ((iph->protocol == IPPROTO_ICMP) && (handle_icmp_snat(skb)))
- goto consume;
-
- iph = ip_hdr(skb);
- if (unlikely(ip_fast_csum((void *)iph, iph->ihl)))
- goto consume;
-
- len = ntohs(iph->tot_len);
- if ((skb->len < len) || len < (iph->ihl*4))
- goto consume;
-
- if (pskb_trim_rcsum(skb, len))
- goto consume;
-
- nf_bridge_put(skb->nf_bridge);
- if (!nf_bridge_alloc(skb))
- return 0;
-
- NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, skb->dev, NULL,
- snat_pre_route_finish);
- return -1;
-
-consume:
- kfree_skb(skb);
- return -1;
-}
-
-
-static int
-snat_skb_finish(struct sk_buff *skb)
-{
- NF_HOOK(PF_INET, NF_INET_POST_ROUTING, skb, NULL, skb->dev,
- dp_xmit_skb_push);
-
- return 0;
-}
-
-/* Update the MAC->IP mappings for the private side of the SNAT'd
- * interface. */
-static void
-update_mapping(struct net_bridge_port *p, const struct sk_buff *skb)
-{
- unsigned long flags;
- struct snat_conf *sc;
- const struct iphdr *iph = ip_hdr(skb);
- const struct ethhdr *eh = eth_hdr(skb);
- struct snat_mapping *m;
-
- spin_lock_irqsave(&p->lock, flags);
- sc = p->snat;
- if (!sc)
- goto done;
-
- list_for_each_entry (m, &sc->mappings, node) {
- if (m->ip_addr == iph->saddr){
- memcpy(m->hw_addr, eh->h_source, ETH_ALEN);
- m->used = jiffies;
- goto done;
- }
- }
-
- m = kmalloc(sizeof *m, GFP_ATOMIC);
- if (!m)
- goto done;
- m->ip_addr = iph->saddr;
- memcpy(m->hw_addr, eh->h_source, ETH_ALEN);
- m->used = jiffies;
-
- list_add(&m->node, &sc->mappings);
-
-done:
- spin_unlock_irqrestore(&p->lock, flags);
-}
-
-/* Perform SNAT modification on 'skb' and send out 'out_port'. If the
- * port was not configured for SNAT, it will be sent through the interface
- * unmodified. 'skb' is not consumed, so caller will need to free it.
- */
-void
-snat_skb(struct datapath *dp, const struct sk_buff *skb, int out_port,
- gfp_t gfp)
-{
- struct net_bridge_port *p = dp->ports[out_port];
- struct sk_buff *nskb;
-
- if (!p)
- return;
-
- /* FIXME: Expensive. Just need to skb_clone() here?
- * (However, the skb_copy() does linearize and ensure that the headers
- * are accessible.) */
- nskb = skb_copy(skb, gfp);
- if (!nskb)
- return;
-
- nskb->dev = p->dev;
-
- /* We only SNAT IP, so just send it on its way if not */
- if (skb->protocol != htons(ETH_P_IP)) {
- dp_xmit_skb(nskb);
- return;
- }
-
- /* Set the source MAC to the OF interface */
- memcpy(eth_hdr(nskb)->h_source, dp->ports[ODPP_LOCAL]->dev->dev_addr, ETH_ALEN);
-
- update_mapping(p, skb);
-
- /* Take the Ethernet header back off for netfilter hooks. */
- skb_pull(nskb, ETH_HLEN);
-
- NF_HOOK(PF_INET, NF_INET_FORWARD, nskb, skb->dev, nskb->dev,
- snat_skb_finish);
-}
-
-/* Remove SNAT configuration on port 'p'.
- *
- * NB: The caller must hold the port's spinlock. */
-int
-snat_free_conf(struct net_bridge_port *p)
-{
- struct snat_conf *sc = p->snat;
-
- if (!sc)
- return -EINVAL;
-
- /* Free existing mapping entries */
- while (!list_empty(&sc->mappings)) {
- struct snat_mapping *m = list_entry(sc->mappings.next,
- struct snat_mapping, node);
- list_del(&m->node);
- kfree(m);
- }
-
- kfree(p->snat);
- p->snat = NULL;
-
- return 0;
-}
-
-/* Remove SNAT configuration from an interface. */
-int snat_del_port(struct datapath *dp, int port)
-{
- unsigned long flags;
- struct net_bridge_port *p;
- int error;
-
- if (port < 0 || port >= DP_MAX_PORTS)
- return -EINVAL;
-
- p = dp->ports[port];
- if (!p)
- return -ENOENT;
-
- spin_lock_irqsave(&p->lock, flags);
- error = snat_free_conf(p);
- spin_unlock_irqrestore(&p->lock, flags);
-
- return error;
-}
-
-/* Add SNAT configuration to an interface. */
-int snat_add_port(struct datapath *dp, const struct odp_snat_config *osc)
-{
- unsigned long flags;
- struct net_bridge_port *p;
- struct snat_conf *sc;
- int mac_timeout;
-
- if (osc->port < 0 || osc->port >= DP_MAX_PORTS)
- return -EINVAL;
-
- p = dp->ports[osc->port];
- if (!p)
- return -ENOENT;
-
- mac_timeout = osc->mac_timeout;
- if (!mac_timeout)
- mac_timeout = MAC_TIMEOUT_DEFAULT;
-
- sc = kzalloc(sizeof *sc, GFP_KERNEL);
- if (!sc)
- return -ENOMEM;
-
- /* If SNAT is already configured on the port, check whether the same
- * IP addresses are used. If so, just update the mac timeout
- * configuration. Otherwise, drop all SNAT configuration and
- * reconfigure it. */
- spin_lock_irqsave(&p->lock, flags);
- if (p->snat) {
- if (p->snat->ip_addr_start == ntohl(osc->ip_start) &&
- p->snat->ip_addr_end == ntohl(osc->ip_end)) {
- p->snat->mac_timeout = mac_timeout;
- spin_unlock_irqrestore(&p->lock, flags);
- kfree(sc);
- return 0;
- }
-
- /* Free the existing configuration and mappings. */
- snat_free_conf(p);
- }
-
- sc->ip_addr_start = ntohl(osc->ip_start);
- sc->ip_addr_end = ntohl(osc->ip_end);
- sc->mac_timeout = mac_timeout;
- memcpy(sc->mac_addr, osc->mac_addr, ETH_ALEN);
- INIT_LIST_HEAD(&sc->mappings);
-
- p->snat = sc;
- spin_unlock_irqrestore(&p->lock, flags);
-
- return 0;
-}
-#endif
+++ /dev/null
-#ifdef SUPPORT_SNAT
-#ifndef ACT_SNAT_H
-#define ACT_SNAT_H
-
-#include <linux/list.h>
-#include <linux/skbuff.h>
-#include <linux/rcupdate.h>
-
-#include "datapath.h"
-
-void snat_internal_in(struct sk_buff *skb);
-int snat_pre_route(struct sk_buff *skb);
-void snat_skb(struct datapath *dp, const struct sk_buff *skb, int out_port,
- gfp_t gfp);
-void snat_save_header(struct sk_buff *skb);
-int snat_copy_header(struct sk_buff *skb);
-void snat_maint(struct net_bridge_port *p);
-int snat_add_port(struct datapath *, const struct odp_snat_config *);
-int snat_del_port(struct datapath *, int port);
-int snat_free_conf(struct net_bridge_port *p);
-
-#endif
-#endif
# load default rules
-include $(MA_DIR)/include/common-rules.make
-DATAPATH_CONFIGURE_OPTS = --enable-snat
+DATAPATH_CONFIGURE_OPTS =
# Official build number. Leave set to 0 if not an official build.
BUILD_NUMBER = 0
OFP_ASSERT(sizeof(struct nicira_header) == sizeof(struct ofp_vendor_header) + 4);
-enum nx_snat_command {
- NXSC_ADD,
- NXSC_DELETE
-};
-
-/* Configuration for source-NATing */
-struct nx_snat_config {
- uint8_t command; /* One of NXSC_*. */
- uint8_t pad[3];
- uint16_t port; /* Physical switch port. */
- uint16_t mac_timeout; /* Time to cache MAC addresses of SNAT'd hosts
- in seconds. 0 uses the default value. */
-
- /* Range of IP addresses to impersonate. Set both values to the
- * same to support a single address. */
- uint32_t ip_addr_start;
- uint32_t ip_addr_end;
-
- /* Range of transport ports that should be used as new source port. A
- * value of zero, let's the switch choose.*/
- uint16_t tcp_start;
- uint16_t tcp_end;
- uint16_t udp_start;
- uint16_t udp_end;
-
- /* MAC address to use for ARP requests for a SNAT IP address that
- * comes in on a different interface than 'port'. A value of all
- * zeros silently drops those ARP requests. Requests that arrive
- * on 'port' get a response with the mac address of the datapath
- * device. */
- uint8_t mac_addr[OFP_ETH_ALEN];
- uint8_t pad2[2];
-};
-OFP_ASSERT(sizeof(struct nx_snat_config) == 32);
-
-/* Action configuration. Not all actions require separate configuration. */
-struct nx_act_config {
- struct nicira_header header;
- uint16_t type; /* One of OFPAT_* */
- uint8_t pad[2];
- union {
- struct nx_snat_config snat[0];
- }; /* Array of action configurations. The number
- is inferred from the length field in the
- header. */
-};
-OFP_ASSERT(sizeof(struct nx_act_config) == 20);
-
-
enum nx_action_subtype {
- NXAST_SNAT, /* Source-NAT */
+ NXAST_SNAT__OBSOLETE, /* No longer used. */
NXAST_RESUBMIT /* Throw against flow table again. */
};
-/* Action structure for NXAST_SNAT. */
-struct nx_action_snat {
- uint16_t type; /* OFPAT_VENDOR. */
- uint16_t len; /* Length is 8. */
- uint32_t vendor; /* NX_VENDOR_ID. */
- uint16_t subtype; /* NXAST_SNAT. */
- uint16_t port; /* Output port--it must be previously
- configured. */
- uint8_t pad[4];
-};
-OFP_ASSERT(sizeof(struct nx_action_snat) == 16);
-
/* Action structure for NXAST_RESUBMIT. */
struct nx_action_resubmit {
uint16_t type; /* OFPAT_VENDOR. */
#define ODP_EXECUTE _IOR('O', 19, struct odp_execute)
-#define ODP_SNAT_ADD_PORT _IOR('O', 20, struct odp_snat_config)
-#define ODP_SNAT_DEL_PORT _IOR('O', 21, int)
-
struct odp_stats {
/* Flows. */
__u32 n_flows; /* Number of flows in flow table. */
#define ODPAT_SET_NW_DST 9 /* IP destination address. */
#define ODPAT_SET_TP_SRC 10 /* TCP/UDP source port. */
#define ODPAT_SET_TP_DST 11 /* TCP/UDP destination port. */
-#define ODPAT_SNAT 12 /* Source NAT. */
-#define ODPAT_N_ACTIONS 13
+#define ODPAT_N_ACTIONS 12
struct odp_action_output {
__u16 type; /* ODPAT_OUTPUT. */
__u16 reserved2;
};
-struct odp_action_snat {
- __u16 type; /* ODPAT_SNAT. */
- __u16 port; /* Output port. */
- __u16 reserved1;
- __u16 reserved2;
-};
-
union odp_action {
__u16 type;
struct odp_action_output output;
struct odp_action_dl_addr dl_addr;
struct odp_action_nw_addr nw_addr;
struct odp_action_tp_port tp_port;
- struct odp_action_snat snat;
};
struct odp_execute {
*/
#define ODP_VLAN_NONE 0xffff
-/* Configuration for source-NATing */
-struct odp_snat_config {
- __u16 port;
-
- /* Time to cache MAC addresses of SNAT'd hosts in seconds (0=default). */
- __u16 mac_timeout;
-
- /* Range of IP addresses to impersonate. Set both values to the same to
- * support a single address. */
- __be32 ip_start, ip_end;
-
- /* Range of transport ports that should be used as new source port. A
- * value of zero lets the kernel choose. */
- __be16 tcp_start, tcp_end;
- __be16 udp_start, udp_end;
-
- /* MAC address to use for ARP requests for a SNAT IP address that comes in
- * on a different interface than 'port'. A value of all zeros silently
- * drops those ARP requests. Requests that arrive on 'port' get a response
- * with the mac address of the datapath device. */
- __u8 mac_addr[ETH_ALEN];
- __u16 reserved;
-};
-
#endif /* openvswitch/datapath-protocol.h */
return error;
}
-int
-dpif_snat_add_port(struct dpif *dpif, const struct odp_snat_config *osc)
-{
- COVERAGE_INC(dpif_snat_add_port);
- return do_ioctl(dpif, ODP_SNAT_ADD_PORT, "ODP_SNAT_ADD_PORT", osc);
-}
-
-int
-dpif_snat_del_port(struct dpif *dpif, uint16_t port)
-{
- int tmp = port;
- COVERAGE_INC(dpif_snat_del_port);
- return do_ioctl(dpif, ODP_SNAT_DEL_PORT, "ODP_SNAT_DEL_PORT", &tmp);
-}
-
int
dpif_recv(struct dpif *dpif, struct ofpbuf **bufp)
{
const union odp_action[], size_t n_actions,
const struct ofpbuf *);
-int dpif_snat_add_port(struct dpif *, const struct odp_snat_config *);
-int dpif_snat_del_port(struct dpif *, uint16_t port);
-
int dpif_recv(struct dpif *, struct ofpbuf **);
void dpif_recv_wait(struct dpif *);
case ODPAT_SET_TP_DST:
ds_put_format(ds, "set_tp_dst(%"PRIu16")", ntohs(a->tp_port.tp_port));
break;
- case ODPAT_SNAT:
- ds_put_format(ds, "snat(%"PRIu16")", a->snat.port);
- break;
default:
ds_put_format(ds, "***bad action %"PRIu16"***", a->type);
break;
ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
{
switch (ntohs(nah->subtype)) {
- case NXAST_SNAT: {
- const struct nx_action_snat *nas = (struct nx_action_snat *)nah;
- uint16_t port = ntohs(nas->port);
-
- if (port < OFPP_MAX) {
- ds_put_format(string, "nat:%"PRIu16, port);
- } else {
- ds_put_format(string, "nat:%"PRIu16" (invalid port)", port);
- }
- break;
- }
-
case NXAST_RESUBMIT: {
const struct nx_action_resubmit *nar = (struct nx_action_resubmit *)nah;
ds_put_format(string, "resubmit:");
check_nicira_action(const union ofp_action *a, unsigned int len)
{
const struct nx_action_header *nah;
- int error;
if (len < 16) {
VLOG_DBG_RL(&bad_ofmsg_rl,
nah = (const struct nx_action_header *) a;
switch (ntohs(nah->subtype)) {
- case NXAST_SNAT:
- error = check_action_exact_len(a, len, 16);
- if (error) {
- return error;
- }
- return check_action_port(ntohs(((struct nx_action_snat *) nah)->port));
case NXAST_RESUBMIT:
return check_action_exact_len(a, len, 16);
default:
VLOG_MODULE(process)
VLOG_MODULE(secchan)
VLOG_MODULE(rconn)
-VLOG_MODULE(snat)
VLOG_MODULE(stp)
VLOG_MODULE(stp_secchan)
VLOG_MODULE(stats)
AC_DEFINE([HAVE_OPENSSL], [1], [Define to 1 if OpenSSL is installed.])
fi])
-dnl Checks for --enable-snat and defines SUPPORT_SNAT if it is specified.
-AC_DEFUN([OVS_CHECK_SNAT],
- [AC_ARG_ENABLE(
- [snat],
- [AC_HELP_STRING([--enable-snat],
- [Enable support for source-NAT action])],
- [case "${enableval}" in
- (yes) snat=true ;;
- (no) snat=false ;;
- (*) AC_MSG_ERROR([bad value ${enableval} for --enable-snat]) ;;
- esac],
- [snat=false])
- AM_CONDITIONAL([SUPPORT_SNAT], [test x$snat = xtrue])
- if test x$snat = xtrue; then
- AC_DEFINE([SUPPORT_SNAT], [1], [Define to 1 if SNAT is desired.])
- SUPPORT_SNAT=-DSUPPORT_SNAT
- AC_SUBST([SUPPORT_SNAT])
- fi])
-
dnl Checks for libraries needed by lib/fault.c.
AC_DEFUN([OVS_CHECK_FAULT_LIBS],
[AC_CHECK_LIB([dl], [dladdr], [FAULT_LIBS=-ldl])
xlate_nicira_action(struct action_xlate_ctx *ctx,
const struct nx_action_header *nah)
{
- const struct nx_action_snat *nas;
const struct nx_action_resubmit *nar;
int subtype = ntohs(nah->subtype);
- union odp_action *oa;
assert(nah->vendor == htonl(NX_VENDOR_ID));
switch (subtype) {
- case NXAST_SNAT:
- nas = (const struct nx_action_snat *) nah;
- oa = odp_actions_add(ctx->out, ODPAT_SNAT);
- oa->snat.port = ntohs(nas->port);
- break;
-
case NXAST_RESUBMIT:
nar = (const struct nx_action_resubmit *) nah;
xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port)));
" dump-flows SWITCH FLOW print matching FLOWs\n"
" dump-aggregate SWITCH print aggregate flow statistics\n"
" dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
-#ifdef SUPPORT_SNAT
- " add-snat SWITCH IFACE IP add SNAT config to IFACE\n"
- " del-snat SWITCH IFACE delete SNAT config on IFACE\n"
-#endif
" add-flow SWITCH FLOW add flow described by FLOW\n"
" add-flows SWITCH FILE add flows from FILE\n"
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
ovs_fatal(0, "Drop actions must not be preceded by other "
"actions");
}
-#ifdef SUPPORT_SNAT
- } else if (!strcasecmp(act, "nat")) {
- struct nx_action_snat *sa;
-
- if (str_to_u32(arg) > OFPP_MAX) {
- ovs_fatal(0, "Invalid nat port: %s\n", arg);
- }
-
- sa = put_action(b, sizeof *sa, OFPAT_VENDOR);
- sa->vendor = htonl(NX_VENDOR_ID);
- sa->subtype = htons(NXAST_SNAT);
- sa->port = htons(str_to_u32(arg));
-#endif
} else if (!strcasecmp(act, "CONTROLLER")) {
struct ofp_action_output *oao;
oao = put_output_action(b, OFPP_CONTROLLER);
dump_stats_transaction(argv[1], request);
}
-#ifdef SUPPORT_SNAT
-static void
-do_add_snat(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
- struct ofpbuf *buffer;
- struct nx_act_config *nac;
- size_t size;
-
- /* Parse and send. */
- size = sizeof *nac + sizeof nac->snat[0];
- nac = make_openflow(size, OFPT_VENDOR, &buffer);
-
- nac->header.vendor = htonl(NX_VENDOR_ID);
- nac->header.subtype = htonl(NXT_ACT_SET_CONFIG);
-
- nac->type = htons(NXAST_SNAT);
- nac->snat[0].command = NXSC_ADD;
- nac->snat[0].port = htons(str_to_u32(argv[2]));
- nac->snat[0].mac_timeout = htons(0);
- str_to_ip(argv[3], &nac->snat[0].ip_addr_start);
- str_to_ip(argv[3], &nac->snat[0].ip_addr_end);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-
-static void
-do_del_snat(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
-{
- struct vconn *vconn;
- struct ofpbuf *buffer;
- struct nx_act_config *nac;
- size_t size;
-
- /* Parse and send. */
- size = sizeof *nac + sizeof nac->snat[0];
- nac = make_openflow(size, OFPT_VENDOR, &buffer);
-
- nac->header.vendor = htonl(NX_VENDOR_ID);
- nac->header.subtype = htonl(NXT_ACT_SET_CONFIG);
-
- nac->type = htons(NXAST_SNAT);
- nac->snat[0].command = NXSC_DELETE;
- nac->snat[0].port = htons(str_to_u32(argv[2]));
- nac->snat[0].mac_timeout = htons(0);
-
- open_vconn(argv[1], &vconn);
- send_openflow_buffer(vconn, buffer);
- vconn_close(vconn);
-}
-#endif /* SUPPORT_SNAT */
-
static void
do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
{
{ "dump-tables", 1, 1, do_dump_tables },
{ "dump-flows", 1, 2, do_dump_flows },
{ "dump-aggregate", 1, 2, do_dump_aggregate },
-#ifdef SUPPORT_SNAT
- { "add-snat", 3, 3, do_add_snat },
- { "del-snat", 2, 2, do_del_snat },
-#endif
{ "add-flow", 2, 2, do_add_flow },
{ "add-flows", 2, 2, do_add_flows },
{ "mod-flows", 2, 2, do_mod_flows },