Adding create vip operation
diff --git a/openstack/networking/v2/extensions/lbaas/vips/requests.go b/openstack/networking/v2/extensions/lbaas/vips/requests.go
index bcc0b58..f325bce 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/requests.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/requests.go
@@ -1,13 +1,20 @@
 package vips
 
 import (
+	"fmt"
 	"strconv"
 
+	"github.com/racker/perigee"
 	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/openstack/utils"
 	"github.com/rackspace/gophercloud/pagination"
 )
 
+const (
+	Up   = true
+	Down = false
+)
+
 // ListOpts allows the filtering and sorting of paginated collections through
 // the API. Filtering is achieved by passing in struct field values that map to
 // the floating IP attributes you want to see returned. SortKey allows you to
@@ -91,3 +98,131 @@
 		return VIPPage{pagination.LinkedPageBase{LastHTTPResponse: r}}
 	})
 }
+
+// CreateOpts contains all the values needed to create a new virtual IP.
+type CreateOpts struct {
+	// Required. Human-readable name for the VIP. Does not have to be unique.
+	Name string
+
+	// Required. The network on which to allocate the VIP's address. A tenant can
+	// only create VIPs on networks authorized by policy (e.g. networks that
+	// belong to them or networks that are shared).
+	SubnetID string
+
+	// Required. The protocol - can either be TCP, HTTP or HTTPS.
+	Protocol string
+
+	// Required. The port on which to listen for client traffic.
+	ProtocolPort int
+
+	// Required. The ID of the pool with which the VIP is associated.
+	PoolID string
+
+	// Required for admins. Indicates the owner of the VIP.
+	TenantID string
+
+	// Optional. The IP address of the VIP.
+	Address string
+
+	// Optional. Human-readable description for the VIP.
+	Description string
+
+	// Optional. Omit this field to prevent session persistence.
+	Persistence *SessionPersistence
+
+	// Optional. The maximum number of connections allowed for the VIP.
+	ConnLimit *int
+
+	// Optional. The administrative state of the VIP. A valid value is true (UP)
+	// or false (DOWN).
+	AdminStateUp *bool
+}
+
+var (
+	errNameRequired         = fmt.Errorf("Name is required")
+	errSubnetIDRequried     = fmt.Errorf("SubnetID is required")
+	errProtocolRequired     = fmt.Errorf("Protocol is required")
+	errProtocolPortRequired = fmt.Errorf("Protocol port is required")
+	errPoolIDRequired       = fmt.Errorf("PoolID is required")
+)
+
+// Create is an operation which provisions a new virtual IP based on the
+// configuration defined in the CreateOpts struct. Once the request is
+// validated and progress has started on the provisioning process, a
+// CreateResult will be returned.
+//
+// Please note that the PoolID should refer to a pool that is not already
+// associated with another vip. If the pool is already used by another vip,
+// then the operation will fail with a 409 Conflict error will be returned.
+//
+// Users with an admin role can create VIPs on behalf of other tenants by
+// specifying a TenantID attribute different than their own.
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
+	var res CreateResult
+
+	// Validate required opts
+	if opts.Name == "" {
+		res.Err = errNameRequired
+		return res
+	}
+	if opts.SubnetID == "" {
+		res.Err = errSubnetIDRequried
+		return res
+	}
+	if opts.Protocol == "" {
+		res.Err = errProtocolRequired
+		return res
+	}
+	if opts.ProtocolPort == 0 {
+		res.Err = errProtocolPortRequired
+		return res
+	}
+	if opts.PoolID == "" {
+		res.Err = errPoolIDRequired
+		return res
+	}
+
+	type vip struct {
+		Name         string              `json:"name"`
+		SubnetID     string              `json:"subnet_id"`
+		Protocol     string              `json:"protocol"`
+		ProtocolPort int                 `json:"protocol_port"`
+		PoolID       string              `json:"pool_id"`
+		Description  *string             `json:"description,omitempty"`
+		TenantID     *string             `json:"tenant_id,omitempty"`
+		Address      *string             `json:"address,omitempty"`
+		Persistence  *SessionPersistence `json:"session_persistence,omitempty"`
+		ConnLimit    *int                `json:"connection_limit,omitempty"`
+		AdminStateUp *bool               `json:"admin_state_up,omitempty"`
+	}
+
+	type request struct {
+		VirtualIP vip `json:"vip"`
+	}
+
+	reqBody := request{VirtualIP: vip{
+		Name:         opts.Name,
+		SubnetID:     opts.SubnetID,
+		Protocol:     opts.Protocol,
+		ProtocolPort: opts.ProtocolPort,
+		PoolID:       opts.PoolID,
+		Description:  gophercloud.MaybeString(opts.Description),
+		TenantID:     gophercloud.MaybeString(opts.TenantID),
+		Address:      gophercloud.MaybeString(opts.Address),
+		ConnLimit:    opts.ConnLimit,
+		AdminStateUp: opts.AdminStateUp,
+	}}
+
+	if opts.Persistence != nil {
+		reqBody.VirtualIP.Persistence = opts.Persistence
+	}
+
+	_, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
+		MoreHeaders: c.Provider.AuthenticatedHeaders(),
+		ReqBody:     &reqBody,
+		Results:     &res.Resp,
+		OkCodes:     []int{201},
+	})
+
+	return res
+}
diff --git a/openstack/networking/v2/extensions/lbaas/vips/requests_test.go b/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
index ccb3d02..15e380f 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/requests_test.go
@@ -98,7 +98,7 @@
 				Protocol:     "HTTP",
 				ProtocolPort: 80,
 				PoolID:       "cfc6589d-f949-4c66-99d2-c2da56ef3764",
-				Persistence:  SessionPersistence{},
+				//Persistence:  SessionPersistence{},
 				ConnLimit:    0,
 				AdminStateUp: true,
 				Status:       "ACTIVE",
@@ -114,7 +114,7 @@
 				Protocol:     "TCP",
 				ProtocolPort: 3306,
 				PoolID:       "41efe233-7591-43c5-9cf7-923964759f9e",
-				Persistence:  SessionPersistence{Type: "SOURCE_IP"},
+				//Persistence:  SessionPersistence{Type: "SOURCE_IP"},
 				ConnLimit:    2000,
 				AdminStateUp: true,
 				Status:       "INACTIVE",
@@ -130,3 +130,77 @@
 		t.Errorf("Expected 1 page, got %d", count)
 	}
 }
+
+func TestCreate(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/v2.0/lb/vips", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "POST")
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
+		th.TestHeader(t, r, "Content-Type", "application/json")
+		th.TestHeader(t, r, "Accept", "application/json")
+		th.TestJSONRequest(t, r, `
+{
+    "vip": {
+        "protocol": "HTTP",
+        "name": "NewVip",
+        "admin_state_up": true,
+        "subnet_id": "8032909d-47a1-4715-90af-5153ffe39861",
+        "pool_id": "61b1f87a-7a21-4ad3-9dda-7f81d249944f",
+        "protocol_port": 80
+    }
+}
+			`)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusCreated)
+
+		fmt.Fprintf(w, `
+{
+    "vip": {
+        "status": "PENDING_CREATE",
+        "protocol": "HTTP",
+        "description": "",
+        "admin_state_up": true,
+        "subnet_id": "8032909d-47a1-4715-90af-5153ffe39861",
+        "tenant_id": "83657cfcdfe44cd5920adaf26c48ceea",
+        "connection_limit": -1,
+        "pool_id": "61b1f87a-7a21-4ad3-9dda-7f81d249944f",
+        "address": "10.0.0.11",
+        "protocol_port": 80,
+        "port_id": "f7e6fe6a-b8b5-43a8-8215-73456b32e0f5",
+        "id": "c987d2be-9a3c-4ac9-a046-e8716b1350e2",
+        "name": "NewVip"
+    }
+}
+		`)
+	})
+
+	iTrue := true
+	opts := CreateOpts{
+		Protocol:     "HTTP",
+		Name:         "NewVip",
+		AdminStateUp: &iTrue,
+		SubnetID:     "8032909d-47a1-4715-90af-5153ffe39861",
+		PoolID:       "61b1f87a-7a21-4ad3-9dda-7f81d249944f",
+		ProtocolPort: 80,
+	}
+
+	r, err := Create(serviceClient(), opts).Extract()
+	th.AssertNoErr(t, err)
+
+	th.AssertEquals(t, "PENDING_CREATE", r.Status)
+	th.AssertEquals(t, "HTTP", r.Protocol)
+	th.AssertEquals(t, "", r.Description)
+	th.AssertEquals(t, true, r.AdminStateUp)
+	th.AssertEquals(t, "8032909d-47a1-4715-90af-5153ffe39861", r.SubnetID)
+	th.AssertEquals(t, "83657cfcdfe44cd5920adaf26c48ceea", r.TenantID)
+	th.AssertEquals(t, -1, r.ConnLimit)
+	th.AssertEquals(t, "61b1f87a-7a21-4ad3-9dda-7f81d249944f", r.PoolID)
+	th.AssertEquals(t, "10.0.0.11", r.Address)
+	th.AssertEquals(t, 80, r.ProtocolPort)
+	th.AssertEquals(t, "f7e6fe6a-b8b5-43a8-8215-73456b32e0f5", r.PortID)
+	th.AssertEquals(t, "c987d2be-9a3c-4ac9-a046-e8716b1350e2", r.ID)
+	th.AssertEquals(t, "NewVip", r.Name)
+}
diff --git a/openstack/networking/v2/extensions/lbaas/vips/results.go b/openstack/networking/v2/extensions/lbaas/vips/results.go
index 35a7bc1..5b2718d 100644
--- a/openstack/networking/v2/extensions/lbaas/vips/results.go
+++ b/openstack/networking/v2/extensions/lbaas/vips/results.go
@@ -1,7 +1,10 @@
 package vips
 
 import (
+	"fmt"
+
 	"github.com/mitchellh/mapstructure"
+	"github.com/rackspace/gophercloud"
 	"github.com/rackspace/gophercloud/pagination"
 )
 
@@ -64,7 +67,7 @@
 
 	// Indicates whether connections in the same session will be processed by the
 	// same pool member or not.
-	Persistence SessionPersistence `mapstructure:"session_persistence" json:"session_persistence"`
+	//Persistence SessionPersistence `mapstructure:"session_persistence" json:"session_persistence"`
 
 	// The maximum number of connections allowed for the VIP. Default is -1,
 	// meaning no limit.
@@ -138,3 +141,43 @@
 
 	return resp.VIPs, nil
 }
+
+type commonResult struct {
+	gophercloud.CommonResult
+}
+
+// Extract is a function that accepts a result and extracts a router.
+func (r commonResult) Extract() (*VirtualIP, error) {
+	if r.Err != nil {
+		return nil, r.Err
+	}
+
+	var res struct {
+		VirtualIP *VirtualIP `mapstructure:"vip" json:"vip"`
+	}
+
+	err := mapstructure.Decode(r.Resp, &res)
+	if err != nil {
+		return nil, fmt.Errorf("Error decoding Neutron Virtual IP: %v", err)
+	}
+
+	return res.VirtualIP, nil
+}
+
+// CreateResult represents the result of a create operation.
+type CreateResult struct {
+	commonResult
+}
+
+// GetResult represents the result of a get operation.
+type GetResult struct {
+	commonResult
+}
+
+// UpdateResult represents the result of an update operation.
+type UpdateResult struct {
+	commonResult
+}
+
+// DeleteResult represents the result of a delete operation.
+type DeleteResult commonResult