Add support for floating IPs using nova API.

When using vanilla OpenStack with neutron, instances are commonly
accessible from the outside world only by using floating IPs.

This patch adds support for:
  - listing floating IPs
  - allocating a floating IP from a given pool
  - attaching a floating IP to an instance
  - de-allocating an IP and returning it to its pool.
diff --git a/floating_ips.go b/floating_ips.go
new file mode 100644
index 0000000..4c27347
--- /dev/null
+++ b/floating_ips.go
@@ -0,0 +1,83 @@
+package gophercloud
+
+import (
+	"fmt"
+	"github.com/racker/perigee"
+)
+
+func (gsp *genericServersProvider) ListFloatingIps() ([]FloatingIp, error) {
+	var fips []FloatingIp
+
+	err := gsp.context.WithReauth(gsp.access, func() error {
+		url := gsp.endpoint + "/os-floating-ips"
+		return perigee.Get(url, perigee.Options{
+			CustomClient: gsp.context.httpClient,
+			Results: &struct {
+				FloatingIps *[]FloatingIp `json:"floating_ips"`
+			}{&fips},
+			MoreHeaders: map[string]string{
+				"X-Auth-Token": gsp.access.AuthToken(),
+			},
+		})
+	})
+	return fips, err
+}
+
+func (gsp *genericServersProvider) CreateFloatingIp(pool string) (FloatingIp, error) {
+	var fip *FloatingIp
+
+	err := gsp.context.WithReauth(gsp.access, func() error {
+		url := gsp.endpoint + "/os-floating-ips"
+		return perigee.Post(url, perigee.Options{
+			CustomClient: gsp.context.httpClient,
+			ReqBody: map[string]string{
+				"pool": pool,
+			},
+			Results: &struct {
+				FloatingIp **FloatingIp `json:"floating_ip"`
+			}{&fip},
+			MoreHeaders: map[string]string{
+				"X-Auth-Token": gsp.access.AuthToken(),
+			},
+		})
+	})
+
+	return *fip, err
+}
+
+func (gsp *genericServersProvider) AssociateFloatingIp(serverId string, ip FloatingIp) error {
+	return gsp.context.WithReauth(gsp.access, func() error {
+		ep := fmt.Sprintf("%s/servers/%s/action", gsp.endpoint, serverId)
+		return perigee.Post(ep, perigee.Options{
+			CustomClient: gsp.context.httpClient,
+			ReqBody: map[string](map[string]string){
+				"addFloatingIp": map[string]string{"address": ip.Ip},
+			},
+			MoreHeaders: map[string]string{
+				"X-Auth-Token": gsp.access.AuthToken(),
+			},
+			OkCodes: []int{202},
+		})
+	})
+}
+
+func (gsp *genericServersProvider) DeleteFloatingIp(ip FloatingIp) error {
+	return gsp.context.WithReauth(gsp.access, func() error {
+		ep := fmt.Sprintf("%s/os-floating-ips/%s", gsp.endpoint, ip.Id)
+		return perigee.Delete(ep, perigee.Options{
+			CustomClient: gsp.context.httpClient,
+			MoreHeaders: map[string]string{
+				"X-Auth-Token": gsp.access.AuthToken(),
+			},
+			OkCodes: []int{202},
+		})
+	})
+}
+
+type FloatingIp struct {
+	Id         string `json:"id"`
+	Pool       string `json:"pool"`
+	Ip         string `json:"ip"`
+	FixedIp    string `json:"fixed_ip"`
+	InstanceId string `json:"instance_id"`
+}
diff --git a/interfaces.go b/interfaces.go
index 7a9c7eb..6340c1c 100644
--- a/interfaces.go
+++ b/interfaces.go
@@ -150,6 +150,18 @@
 	// Example: ListAddressesByNetwork("234-4353-4jfrj-43j2s", "private")
 	ListAddressesByNetwork(id, networkLabel string) (NetworkAddress, error)
 
+	// ListFloatingIps yields the list of all floating IP addresses allocated to the current project.
+	ListFloatingIps() ([]FloatingIp, error)
+
+	// CreateFloatingIp allocates a new IP from the named pool to the current project.
+	CreateFloatingIp(pool string) (FloatingIp, error)
+
+	// DeleteFloatingIp returns the specified IP from the current project to the pool.
+	DeleteFloatingIp(ip FloatingIp) error
+
+	// AssociateFloatingIp associates the given floating IP to the given server id.
+	AssociateFloatingIp(serverId string, ip FloatingIp) error
+
 	// Images
 
 	// ListImages yields the list of available operating system images.  This function