diff --git a/datapath/Modules.mk b/datapath/Modules.mk index a02f0d7..4db64d9 100644 --- a/datapath/Modules.mk +++ b/datapath/Modules.mk @@ -19,7 +19,6 @@ ofdatapath_sources = \ flow.c \ forward.c \ nx_act.c \ - nx_act_snat.c \ nx_msg.c \ table-hash.c \ table-linear.c @@ -34,7 +33,6 @@ ofdatapath_headers = \ forward.h \ dp_act.h \ nx_act.h \ - nx_act_snat.h \ nx_msg.h \ table.h diff --git a/datapath/datapath.c b/datapath/datapath.c index 7dc55b7..a27b88d 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -38,7 +38,6 @@ #include "openflow/nicira-ext.h" #include "openflow/openflow-netlink.h" #include "datapath.h" -#include "nx_act_snat.h" #include "table.h" #include "chain.h" #include "dp_dev.h" @@ -443,9 +442,6 @@ int add_switch_port(struct datapath *dp, struct net_device *dev) * Called with RTNL lock and dp_mutex. */ int dp_del_switch_port(struct net_bridge_port *p) { -#ifdef SUPPORT_SNAT - unsigned long flags; -#endif #if CONFIG_SYSFS if ((p->port_no != OFPP_LOCAL) && dp_del_if_hook) @@ -462,13 +458,6 @@ int dp_del_switch_port(struct net_bridge_port *p) /* Then wait until no one is still using it, and destroy it. */ synchronize_rcu(); -#ifdef SUPPORT_SNAT - /* Free any SNAT configuration on the port. */ - spin_lock_irqsave(&p->lock, flags); - snat_free_conf(p); - spin_unlock_irqrestore(&p->lock, flags); -#endif - /* Notify the ctlpath that this port no longer exists */ dp_send_port_status(p, OFPPR_DELETE); @@ -520,16 +509,6 @@ static int dp_maint_func(void *data) allow_signal(SIGKILL); while (!signal_pending(current)) { -#ifdef SUPPORT_SNAT - 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(); -#endif - /* Timeout old entries */ chain_timeout(dp->chain); msleep_interruptible(MAINT_SLEEP_MSECS); @@ -552,12 +531,6 @@ 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); @@ -653,56 +626,6 @@ void dp_set_origin(struct datapath *dp, uint16_t in_port, skb->dev = NULL; } -#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) { @@ -720,7 +643,6 @@ dp_xmit_skb(struct sk_buff *skb) return len; } -#endif /* Takes ownership of 'skb' and transmits it to 'out_port' on 'dp'. */ @@ -761,9 +683,6 @@ int dp_output_port(struct datapath *dp, struct sk_buff *skb, int out_port, case OFPP_LOCAL: { struct net_device *dev = dp->netdev; -#ifdef SUPPORT_SNAT - snat_local_in(skb); -#endif return dev ? dp_dev_recv(dev, skb) : -ESRCH; } diff --git a/datapath/datapath.h b/datapath/datapath.h index babf10e..f241509 100644 --- a/datapath/datapath.h +++ b/datapath/datapath.h @@ -78,7 +78,6 @@ struct net_bridge_port { struct datapath *dp; struct net_device *dev; struct kobject kobj; - struct snat_conf *snat; /* Only set if SNAT is configured for this port. */ struct list_head node; /* Element in datapath.ports. */ }; diff --git a/datapath/linux-2.6/Kbuild.in b/datapath/linux-2.6/Kbuild.in index 25f9e78..8260562 100644 --- a/datapath/linux-2.6/Kbuild.in +++ b/datapath/linux-2.6/Kbuild.in @@ -13,7 +13,6 @@ EXTRA_CFLAGS := -DVERSION=\"$(VERSION)\" 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 diff --git a/datapath/nx_act.c b/datapath/nx_act.c index d96c48f..3ad3b98 100644 --- a/datapath/nx_act.c +++ b/datapath/nx_act.c @@ -7,7 +7,6 @@ #include "openflow/nicira-ext.h" #include "dp_act.h" #include "nx_act.h" -#include "nx_act_snat.h" uint16_t nx_validate_act(struct datapath *dp, const struct sw_flow_key *key, @@ -16,17 +15,6 @@ nx_validate_act(struct datapath *dp, const struct sw_flow_key *key, if (len < sizeof *nah) return OFPBAC_BAD_LEN; -#ifdef SUPPORT_SNAT - if (nah->subtype == ntohs(NXAST_SNAT)) { - struct nx_action_snat *nas = (struct nx_action_snat *)nah; - if (len != sizeof(*nas)) - return OFPBAC_BAD_LEN; - else if (ntohs(nas->port) >= OFPP_MAX) - return OFPBAC_BAD_ARGUMENT; - - return ACT_VALIDATION_OK; - } -#endif return OFPBAC_BAD_VENDOR_TYPE; } @@ -34,13 +22,6 @@ struct sk_buff * nx_execute_act(struct sk_buff *skb, const struct sw_flow_key *key, const struct nx_action_header *nah) { -#ifdef SUPPORT_SNAT - if (nah->subtype == ntohs(NXAST_SNAT)) { - struct nx_action_snat *nas = (struct nx_action_snat *)nah; - snat_skb(skb->dev->br_port->dp, skb, ntohs(nas->port)); - } -#endif - return skb; } diff --git a/datapath/nx_act_snat.c b/datapath/nx_act_snat.c deleted file mode 100644 index c7705d4..0000000 --- a/datapath/nx_act_snat.c +++ /dev/null @@ -1,656 +0,0 @@ -#ifdef SUPPORT_SNAT -/* - * Distributed under the terms of the GNU GPL version 2. - * Copyright (c) 2008, 2009 Nicira Networks - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "forward.h" -#include "dp_act.h" -#include "nx_act_snat.h" - - -/* 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 { - uint16_t ar_hrd; - uint16_t ar_pro; - uint8_t ar_hln; - uint8_t ar_pln; - uint16_t ar_op; - uint8_t ar_sha[ETH_ALEN]; - uint32_t ar_sip; - uint8_t ar_tha[ETH_ALEN]; - uint32_t ar_tip; -} __attribute__((packed)); -OFP_ASSERT(sizeof(struct ip_arphdr) == 28); - -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 a local interface, strip off the fake - * routing table. - */ -void snat_local_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! */ - if (!make_writable(&skb)) - return -EINVAL; - 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 OpenFlow stack, which - * consumes it. */ - skb_push(skb, ETH_HLEN); - skb_reset_mac_header(skb); - fwd_port_input(p->dp->chain, 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; - uint8_t 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->netdev->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; - uint8_t tmp_eth[ETH_ALEN]; - uint32_t 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) -{ - 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_ATOMIC); - 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->netdev->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. */ -static int -snat_del_port(struct datapath *dp, const struct nx_snat_config *nsc) -{ - unsigned long flags; - uint16_t port = ntohs(nsc->port); - struct net_bridge_port *p = dp->ports[port]; - - if (!p) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: attempt to remove snat on " - "non-existent port: %d\n", - dp->netdev->name, port); - return -EINVAL; - } - - spin_lock_irqsave(&p->lock, flags); - if (snat_free_conf(p)) { - /* SNAT not configured on this port */ - spin_unlock_irqrestore(&p->lock, flags); - if (net_ratelimit()) - printk(KERN_NOTICE "%s: attempt to remove snat on " - "non-snat port: %d\n", dp->netdev->name, port); - return -EINVAL; - } - - spin_unlock_irqrestore(&p->lock, flags); - - return 0; -} - -/* Add SNAT configuration to an interface. */ -static int -snat_add_port(struct datapath *dp, const struct nx_snat_config *nsc) -{ - unsigned long flags; - uint16_t port = ntohs(nsc->port); - struct net_bridge_port *p = dp->ports[port]; - uint16_t mac_timeout = ntohs(nsc->mac_timeout); - struct snat_conf *sc; - - if (mac_timeout == 0) - mac_timeout = MAC_TIMEOUT_DEFAULT; - - if (!p) { - if (net_ratelimit()) - printk(KERN_NOTICE "%s: attempt to add snat on " - "non-existent port: %d\n", - dp->netdev->name, port); - return -EINVAL; - } - - /* 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(nsc->ip_addr_start)) - && (p->snat->ip_addr_end == ntohl(nsc->ip_addr_end))) { - p->snat->mac_timeout = mac_timeout; - spin_unlock_irqrestore(&p->lock, flags); - return 0; - } - - /* Free the existing configuration and mappings. */ - snat_free_conf(p); - } - - sc = kzalloc(sizeof *sc, GFP_ATOMIC); - if (!sc) { - spin_unlock_irqrestore(&p->lock, flags); - return -ENOMEM; - } - - sc->ip_addr_start = ntohl(nsc->ip_addr_start); - sc->ip_addr_end = ntohl(nsc->ip_addr_end); - sc->mac_timeout = mac_timeout; - memcpy(sc->mac_addr, nsc->mac_addr, sizeof(sc->mac_addr)); - INIT_LIST_HEAD(&sc->mappings); - - p->snat = sc; - spin_unlock_irqrestore(&p->lock, flags); - - return 0; -} - -/* Handle a SNAT configuration message. - * - * Returns 0 if no problems are found. Otherwise, a negative errno. */ -int -snat_mod_config(struct datapath *dp, const struct nx_act_config *nac) -{ - int n_entries = (ntohs(nac->header.header.length) - sizeof *nac) - / sizeof (struct nx_snat_config); - int ret = 0; - int i; - - for (i=0; isnat[i]; - int r = 0; - - if (nsc->command == NXSC_ADD) - r = snat_add_port(dp, nsc); - else - r = snat_del_port(dp, nsc); - - if (r) - ret = r; - } - - return ret; -} -#endif diff --git a/datapath/nx_act_snat.h b/datapath/nx_act_snat.h deleted file mode 100644 index fc86d38..0000000 --- a/datapath/nx_act_snat.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifdef SUPPORT_SNAT -#ifndef ACT_SNAT_H -#define ACT_SNAT_H - -#include -#include -#include - -#include "openflow/nicira-ext.h" -#include "datapath.h" - -/* Cache of IP->MAC mappings on the side hidden by the SNAT */ -struct snat_mapping { - struct list_head node; - uint32_t ip_addr; /* Stored in network-order */ - uint8_t hw_addr[ETH_ALEN]; - unsigned long used; /* Last used time (in jiffies). */ - - struct rcu_head rcu; -}; - -struct snat_conf { - uint32_t ip_addr_start; /* Stored in host-order */ - uint32_t ip_addr_end; /* Stored in host-order */ - uint16_t mac_timeout; - - uint8_t mac_addr[ETH_ALEN]; - - struct list_head mappings; /* List of snat_mapping entries */ -}; - -#define MAC_TIMEOUT_DEFAULT 120 - -void snat_local_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); -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_mod_config(struct datapath *, const struct nx_act_config *); -int snat_free_conf(struct net_bridge_port *p); - -#endif -#endif diff --git a/datapath/nx_msg.c b/datapath/nx_msg.c index 839fac8..80772ff 100644 --- a/datapath/nx_msg.c +++ b/datapath/nx_msg.c @@ -6,7 +6,6 @@ #include "chain.h" #include "datapath.h" #include "openflow/nicira-ext.h" -#include "nx_act_snat.h" #include "nx_msg.h" @@ -24,20 +23,6 @@ nx_recv_msg(struct sw_chain *chain, const struct sender *sender, return 0; } -#ifdef SUPPORT_SNAT - case NXT_ACT_SET_CONFIG: { - const struct nx_act_config *nac = msg; - if (ntohs(nh->header.length) < sizeof(*nac)) - return -EINVAL; - - if (nac->type == htons(NXAST_SNAT)) - return snat_mod_config(chain->dp, nac); - else - return -EINVAL; - break; - } -#endif - default: dp_send_error_msg(chain->dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE, msg, ntohs(nh->header.length)); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 1be73d0..2bb1dc6 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -214,20 +214,8 @@ static void ofp_print_port_name(struct ds *string, uint16_t port) static void ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah) { - - if (nah->subtype == htonl(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); - } - } else { - ds_put_format(string, "***unknown Nicira action:%d***\n", - ntohl(nah->subtype)); - } + ds_put_format(string, "***unknown Nicira action:%d***\n", + ntohl(nah->subtype)); } static int diff --git a/lib/vlog-modules.def b/lib/vlog-modules.def index 4f21366..eb7872c 100644 --- a/lib/vlog-modules.def +++ b/lib/vlog-modules.def @@ -33,7 +33,6 @@ VLOG_MODULE(process) VLOG_MODULE(protocol_stat) VLOG_MODULE(secchan) VLOG_MODULE(rconn) -VLOG_MODULE(snat) VLOG_MODULE(stp) VLOG_MODULE(stp_secchan) VLOG_MODULE(stats) diff --git a/m4/libopenflow.m4 b/m4/libopenflow.m4 index 294932b..58014ed 100644 --- a/m4/libopenflow.m4 +++ b/m4/libopenflow.m4 @@ -91,25 +91,6 @@ AC_DEFUN([OFP_CHECK_OPENSSL], 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([OFP_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([OFP_CHECK_FAULT_LIBS], [AC_CHECK_LIB([dl], [dladdr], [FAULT_LIBS=-ldl]) @@ -177,7 +158,6 @@ AC_DEFUN([OFP_CHECK_LIBOPENFLOW], AC_REQUIRE([OFP_CHECK_NDEBUG]) AC_REQUIRE([OFP_CHECK_NETLINK]) AC_REQUIRE([OFP_CHECK_OPENSSL]) - AC_REQUIRE([OFP_CHECK_SNAT]) AC_REQUIRE([OFP_CHECK_FAULT_LIBS]) AC_REQUIRE([OFP_CHECK_SOCKET_LIBS]) AC_REQUIRE([OFP_CHECK_PKIDIR]) diff --git a/secchan/automake.mk b/secchan/automake.mk index 661f749..1924cc2 100644 --- a/secchan/automake.mk +++ b/secchan/automake.mk @@ -27,11 +27,6 @@ secchan_ofprotocol_SOURCES = \ secchan/status.h \ secchan/stp-secchan.c \ secchan/stp-secchan.h -if SUPPORT_SNAT -secchan_ofprotocol_SOURCES += \ - secchan/snat.c \ - secchan/snat.h -endif secchan_ofprotocol_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS) EXTRA_DIST += secchan/ofprotocol.8.in diff --git a/secchan/secchan.c b/secchan/secchan.c index 3300dff..61a8516 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -61,9 +61,6 @@ #include "poll-loop.h" #include "ratelimit.h" #include "rconn.h" -#ifdef SUPPORT_SNAT -#include "snat.h" -#endif #include "flow-end.h" #include "stp-secchan.h" #include "status.h" @@ -213,9 +210,6 @@ main(int argc, char *argv[]) /* Set up hooks. */ port_watcher_start(&secchan, local_rconn, remote_rconn, &pw); discovery = s.discovery ? discovery_init(&s, pw, switch_status) : NULL; -#ifdef SUPPORT_SNAT - snat_start(&secchan, pw); -#endif flow_end_start(&secchan, s.netflow_dst, local_rconn, remote_rconn); if (s.enable_stp) { stp_start(&secchan, pw, local_rconn, remote_rconn); diff --git a/secchan/snat.c b/secchan/snat.c deleted file mode 100644 index b27372c..0000000 --- a/secchan/snat.c +++ /dev/null @@ -1,293 +0,0 @@ -/* Copyright (c) 2008, 2009 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include "snat.h" -#include -#include -#include -#include "openflow/nicira-ext.h" -#include "ofpbuf.h" -#include "openflow/openflow.h" -#include "port-watcher.h" - -#define THIS_MODULE VLM_snat -#include "vlog.h" - -struct snat_port_conf { - struct list node; - struct nx_snat_config config; -}; - -struct snat_data { - struct port_watcher *pw; - struct list port_list; -}; - - -/* Source-NAT configuration monitor. */ -#define SNAT_CMD_LEN 1024 - -/* Commands to configure iptables. There is no programmatic interface - * to iptables from the kernel, so we're stuck making command-line calls - * in user-space. */ -#define SNAT_FLUSH_ALL_CMD "/sbin/iptables -t nat -F" -#define SNAT_FLUSH_CHAIN_CMD "/sbin/iptables -t nat -F of-snat-%s" - -#define SNAT_ADD_CHAIN_CMD "/sbin/iptables -t nat -N of-snat-%s" -#define SNAT_CONF_CHAIN_CMD "/sbin/iptables -t nat -A POSTROUTING -o %s -j of-snat-%s" - -#define SNAT_ADD_IP_CMD "/sbin/iptables -t nat -A of-snat-%s -j SNAT --to %s-%s" -#define SNAT_ADD_TCP_CMD "/sbin/iptables -t nat -A of-snat-%s -j SNAT -p TCP --to %s-%s:%d-%d" -#define SNAT_ADD_UDP_CMD "/sbin/iptables -t nat -A of-snat-%s -j SNAT -p UDP --to %s-%s:%d-%d" - -#define SNAT_UNSET_CHAIN_CMD "/sbin/iptables -t nat -D POSTROUTING -o %s -j of-snat-%s" -#define SNAT_DEL_CHAIN_CMD "/sbin/iptables -t nat -X of-snat-%s" - -static void -snat_add_rules(const struct nx_snat_config *sc, const uint8_t *dev_name) -{ - char command[SNAT_CMD_LEN]; - char ip_str_start[16]; - char ip_str_end[16]; - - - snprintf(ip_str_start, sizeof ip_str_start, IP_FMT, - IP_ARGS(&sc->ip_addr_start)); - snprintf(ip_str_end, sizeof ip_str_end, IP_FMT, - IP_ARGS(&sc->ip_addr_end)); - - /* We always attempt to remove existing entries, so that we know - * there's a pristine state for SNAT on the interface. We just ignore - * the results of these calls, since iptables will complain about - * any non-existent entries. */ - - /* Flush the chain that does the SNAT. */ - snprintf(command, sizeof(command), SNAT_FLUSH_CHAIN_CMD, dev_name); - system(command); - - /* We always try to create the a new chain. */ - snprintf(command, sizeof(command), SNAT_ADD_CHAIN_CMD, dev_name); - system(command); - - /* Disassociate any old SNAT chain from the POSTROUTING chain. */ - snprintf(command, sizeof(command), SNAT_UNSET_CHAIN_CMD, dev_name, - dev_name); - system(command); - - /* Associate the new chain with the POSTROUTING hook. */ - snprintf(command, sizeof(command), SNAT_CONF_CHAIN_CMD, dev_name, - dev_name); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem flushing chain for add"); - return; - } - - /* If configured, restrict TCP source port ranges. */ - if ((sc->tcp_start != 0) && (sc->tcp_end != 0)) { - snprintf(command, sizeof(command), SNAT_ADD_TCP_CMD, - dev_name, ip_str_start, ip_str_end, - ntohs(sc->tcp_start), ntohs(sc->tcp_end)); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem adding TCP rule"); - return; - } - } - - /* If configured, restrict UDP source port ranges. */ - if ((sc->udp_start != 0) && (sc->udp_end != 0)) { - snprintf(command, sizeof(command), SNAT_ADD_UDP_CMD, - dev_name, ip_str_start, ip_str_end, - ntohs(sc->udp_start), ntohs(sc->udp_end)); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem adding UDP rule"); - return; - } - } - - /* Add a rule that covers all IP traffic that would not be covered - * by the prior TCP or UDP ranges. */ - snprintf(command, sizeof(command), SNAT_ADD_IP_CMD, - dev_name, ip_str_start, ip_str_end); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem adding base rule"); - return; - } -} - -static void -snat_del_rules(const uint8_t *dev_name) -{ - char command[SNAT_CMD_LEN]; - - /* Flush the chain that does the SNAT. */ - snprintf(command, sizeof(command), SNAT_FLUSH_CHAIN_CMD, dev_name); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem flushing chain for deletion"); - return; - } - - /* Disassociate the SNAT chain from the POSTROUTING chain. */ - snprintf(command, sizeof(command), SNAT_UNSET_CHAIN_CMD, dev_name, - dev_name); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem unsetting chain"); - return; - } - - /* Now we can finally delete our SNAT chain. */ - snprintf(command, sizeof(command), SNAT_DEL_CHAIN_CMD, dev_name); - if (system(command) != 0) { - VLOG_ERR("SNAT: problem deleting chain"); - return; - } -} - -static void -snat_config(const struct nx_snat_config *sc, struct snat_data *snat) -{ - struct snat_port_conf *c, *spc=NULL; - const uint8_t *netdev_name; - - netdev_name = (const uint8_t *) port_watcher_get_name(snat->pw, - ntohs(sc->port)); - if (!netdev_name) { - return; - } - - LIST_FOR_EACH(c, struct snat_port_conf, node, &snat->port_list) { - if (c->config.port == sc->port) { - spc = c; - break; - } - } - - if (sc->command == NXSC_ADD) { - if (!spc) { - spc = xmalloc(sizeof(*c)); - if (!spc) { - VLOG_ERR("SNAT: no memory for new entry"); - return; - } - list_push_back(&snat->port_list, &spc->node); - } - memcpy(&spc->config, sc, sizeof(spc->config)); - snat_add_rules(sc, netdev_name); - } else if (spc) { - snat_del_rules(netdev_name); - list_remove(&spc->node); - } -} - -static bool -snat_remote_packet_cb(struct relay *r, void *snat_) -{ - struct snat_data *snat = snat_; - struct ofpbuf *msg = r->halves[HALF_REMOTE].rxbuf; - struct nicira_header *request = msg->data; - struct nx_act_config *nac = msg->data; - int n_configs, i; - - - if (msg->size < sizeof(struct nx_act_config)) { - return false; - } - request = msg->data; - if (request->header.type != OFPT_VENDOR - || request->vendor != htonl(NX_VENDOR_ID) - || request->subtype != htonl(NXT_ACT_SET_CONFIG)) { - return false; - } - - /* We're only interested in attempts to configure SNAT */ - if (nac->type != htons(NXAST_SNAT)) { - return false; - } - - n_configs = (msg->size - sizeof *nac) / sizeof *nac->snat; - for (i=0; isnat[i], snat); - } - - return false; -} - -static void -snat_port_changed_cb(uint16_t port_no UNUSED, - const struct ofp_phy_port *old, - const struct ofp_phy_port *new, - void *snat_) -{ - struct snat_data *snat = snat_; - struct snat_port_conf *c; - - /* We're only interested in ports that went away */ - if (old && !new) { - return; - } - - LIST_FOR_EACH(c, struct snat_port_conf, node, &snat->port_list) { - if (c->config.port == old->port_no) { - snat_del_rules(old->name); - list_remove(&c->node); - return; - } - } -} - -static struct hook_class snat_hook_class = { - NULL, /* local_packet_cb */ - snat_remote_packet_cb, /* remote_packet_cb */ - NULL, /* periodic_cb */ - NULL, /* wait_cb */ - NULL, /* closing_cb */ -}; - -void -snat_start(struct secchan *secchan, struct port_watcher *pw) -{ - int ret; - struct snat_data *snat; - - ret = system(SNAT_FLUSH_ALL_CMD); - if (ret != 0) { - VLOG_ERR("SNAT: problem flushing tables"); - } - - snat = xcalloc(1, sizeof *snat); - snat->pw = pw; - list_init(&snat->port_list); - - port_watcher_register_callback(pw, snat_port_changed_cb, snat); - add_hook(secchan, &snat_hook_class, snat); -} diff --git a/secchan/snat.h b/secchan/snat.h deleted file mode 100644 index 8f71b15..0000000 --- a/secchan/snat.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#ifndef SNAT_H -#define SNAT_H 1 - -#include "secchan.h" - -struct port_watcher; -struct secchan; - -void snat_start(struct secchan *, struct port_watcher *); - -#endif /* snat.h */ diff --git a/utilities/dpctl.c b/utilities/dpctl.c index a81ef1c..17ee3ca 100644 --- a/utilities/dpctl.c +++ b/utilities/dpctl.c @@ -235,10 +235,6 @@ usage(void) " 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" @@ -830,19 +826,6 @@ str_to_action(char *str, struct ofpbuf *b) ah->type = htons(OFPAT_STRIP_VLAN); } else if (!strcasecmp(act, "output")) { put_output_action(b, str_to_u32(arg)); -#ifdef SUPPORT_SNAT - } else if (!strcasecmp(act, "nat")) { - struct nx_action_snat *sa; - - if (str_to_u32(arg) > OFPP_MAX) { - ofp_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, "TABLE")) { put_output_action(b, OFPP_TABLE); } else if (!strcasecmp(act, "NORMAL")) { @@ -1067,60 +1050,6 @@ do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[]) 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[]) { @@ -1567,10 +1496,6 @@ static struct command all_commands[] = { { "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 },