Adding create network operation
diff --git a/acceptance/openstack/networking/v2/network_test.go b/acceptance/openstack/networking/v2/network_test.go
index 209a68c..4fe7775 100644
--- a/acceptance/openstack/networking/v2/network_test.go
+++ b/acceptance/openstack/networking/v2/network_test.go
@@ -4,6 +4,7 @@
 
 import (
 	"os"
+	"reflect"
 	"testing"
 
 	"github.com/rackspace/gophercloud"
@@ -12,7 +13,9 @@
 	"github.com/rackspace/gophercloud/openstack/utils"
 )
 
-var Client *gophercloud.ServiceClient
+var (
+	Client *gophercloud.ServiceClient
+)
 
 func NewClient() (*gophercloud.ServiceClient, error) {
 	opts, err := utils.AuthOptions()
@@ -50,6 +53,12 @@
 	}
 }
 
+func DeepEquals(t *testing.T, actual, expected interface{}) {
+	if !reflect.DeepEqual(actual, expected) {
+		t.Fatalf("Expected %#v but got %#v", expected, actual)
+	}
+}
+
 func TestListAPIVersions(t *testing.T) {
 	Setup(t)
 	defer Teardown()
@@ -116,22 +125,50 @@
 	//networks.List()
 }
 
-func TestGetNetwork(t *testing.T) {
-	//networks.Get()
-}
+func TestNetworkCRUDOperations(t *testing.T) {
+	Setup(t)
+	defer Teardown()
 
-func TestCreateNetwork(t *testing.T) {
-	//networks.Create()
+	// Create a network
+	res, err := networks.Create(Client, networks.NetworkOpts{Name: "sample_network", AdminStateUp: true})
+	if err != nil {
+		t.Fatalf("Unexpected error when creating network: %#v", err)
+	}
+
+	Equals(t, res.Name, "sample_network")
+	Equals(t, res.AdminStateUp, true)
+
+	networkID := res.ID
+
+	// Get a network
+	if networkID == "" {
+		t.Fatalf("In order to retrieve a network, the NetworkID must be set")
+	}
+
+	Setup(t)
+	defer Teardown()
+
+	n, err := networks.Get(Client, networkID)
+	if err != nil {
+		t.Fatalf("Unexpected error: %#v", err)
+	}
+
+	Equals(t, n.Status, "ACTIVE")
+	DeepEquals(t, n.Subnets, []string{})
+	Equals(t, n.Name, "sample_network")
+	Equals(t, n.ProviderPhysicalNetwork, "")
+	Equals(t, n.ProviderNetworkType, "local")
+	Equals(t, n.ProviderSegmentationID, "")
+	Equals(t, n.AdminStateUp, true)
+	Equals(t, n.RouterExternal, false)
+	Equals(t, n.Shared, false)
+	Equals(t, n.ID, networkID)
+
+	// Update network
+
+	// Delete network
 }
 
 func TestCreateMultipleNetworks(t *testing.T) {
 	//networks.CreateMany()
 }
-
-func TestUpdateNetwork(t *testing.T) {
-	//networks.Update()
-}
-
-func TestDeleteNetwork(t *testing.T) {
-	//networks.Delete()
-}
diff --git a/openstack/networking/v2/networks/errors.go b/openstack/networking/v2/networks/errors.go
index 83c4a6a..7397213 100644
--- a/openstack/networking/v2/networks/errors.go
+++ b/openstack/networking/v2/networks/errors.go
@@ -1 +1,11 @@
 package networks
+
+import "fmt"
+
+func requiredAttr(attr string) error {
+	return fmt.Errorf("You must specify %s for this resource", attr)
+}
+
+var (
+	ErrNameRequired = requiredAttr("name")
+)
diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go
index e27445d..7b647fe 100644
--- a/openstack/networking/v2/networks/requests.go
+++ b/openstack/networking/v2/networks/requests.go
@@ -1,26 +1,13 @@
 package networks
 
 import (
+	"encoding/json"
+	"fmt"
+
 	"github.com/racker/perigee"
 	"github.com/rackspace/gophercloud"
 )
 
-// User-defined options sent to the API when creating or updating a network.
-type NetworkOpts struct {
-	// The administrative state of the network, which is up (true) or down (false).
-	AdminStateUp bool `json:"admin_state_up"`
-	// The network name (optional)
-	Name string `json:"name"`
-	// Indicates whether this network is shared across all tenants. By default,
-	// only administrative users can change this value.
-	Shared bool `json:"shared"`
-	// Admin-only. The UUID of the tenant that will own the network. This tenant
-	// can be different from the tenant that makes the create network request.
-	// However, only administrative users can specify a tenant ID other than their
-	// own. You cannot change this value through authorization policies.
-	TenantID string `json:"tenant_id"`
-}
-
 func APIVersions(c *gophercloud.ServiceClient) (*APIVersionsList, error) {
 	var resp APIVersionsList
 	_, err := perigee.Request("GET", APIVersionsURL(c), perigee.Options{
@@ -79,3 +66,77 @@
 	}
 	return &n, nil
 }
+
+type NetworkOpts struct {
+	AdminStateUp bool
+	Name         string
+	Shared       *bool
+	TenantID     string
+}
+
+type NetworkProvider struct {
+	ProviderSegmentationID  int    `json:"provider:segmentation_id"`
+	ProviderPhysicalNetwork string `json:"provider:physical_network"`
+	ProviderNetworkType     string `json:"provider:network_type"`
+}
+
+type NetworkResult struct {
+	Status              string            `json:"status"`
+	Subnets             []interface{}     `json:"subnets"`
+	Name                string            `json:"name"`
+	AdminStateUp        bool              `json:"admin_state_up"`
+	TenantID            string            `json:"tenant_id"`
+	Segments            []NetworkProvider `json:"segments"`
+	Shared              bool              `json:"shared"`
+	PortSecurityEnabled bool              `json:"port_security_enabled"`
+	ID                  string            `json:"id"`
+}
+
+func Create(c *gophercloud.ServiceClient, opts NetworkOpts) (*NetworkResult, error) {
+	// Define structures
+	type network struct {
+		AdminStateUp bool    `json:"admin_state_up"`
+		Name         string  `json:"name"`
+		Shared       *bool   `json:"shared,omitempty"`
+		TenantID     *string `json:"tenant_id,omitempty"`
+	}
+	type request struct {
+		Network network `json:"network"`
+	}
+	type response struct {
+		Network *NetworkResult `json:"network"`
+	}
+
+	// Validate
+	if opts.Name == "" {
+		return nil, ErrNameRequired
+	}
+
+	// Populate request body
+	reqBody := request{Network: network{
+		AdminStateUp: opts.AdminStateUp,
+		Name:         opts.Name,
+		Shared:       opts.Shared,
+	}}
+
+	if opts.TenantID != "" {
+		reqBody.Network.TenantID = &opts.TenantID
+	}
+
+	j, _ := json.Marshal(reqBody)
+	fmt.Println(string(j))
+
+	// Send request to API
+	var res response
+	_, err := perigee.Request("POST", CreateURL(c), perigee.Options{
+		MoreHeaders: c.Provider.AuthenticatedHeaders(),
+		ReqBody:     &reqBody,
+		Results:     &res,
+		OkCodes:     []int{201},
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return res.Network, nil
+}
diff --git a/openstack/networking/v2/networks/requests_test.go b/openstack/networking/v2/networks/requests_test.go
index 5682c33..61d9268 100644
--- a/openstack/networking/v2/networks/requests_test.go
+++ b/openstack/networking/v2/networks/requests_test.go
@@ -262,3 +262,105 @@
 	Equals(t, n.Shared, true)
 	Equals(t, n.ID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
 }
+
+func TestCreateNetwork(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/v2.0/networks", 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, `
+{
+    "network": {
+        "name": "sample_network",
+        "admin_state_up": true
+    }
+}
+			`)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusCreated)
+
+		fmt.Fprintf(w, `
+{
+    "network": {
+        "status": "ACTIVE",
+        "subnets": [],
+        "name": "net1",
+        "admin_state_up": true,
+        "tenant_id": "9bacb3c5d39d41a79512987f338cf177",
+        "segments": [
+            {
+                "provider:segmentation_id": 2,
+                "provider:physical_network": "8bab8453-1bc9-45af-8c70-f83aa9b50453",
+                "provider:network_type": "vlan"
+            },
+            {
+                "provider:segmentation_id": null,
+                "provider:physical_network": "8bab8453-1bc9-45af-8c70-f83aa9b50453",
+                "provider:network_type": "stt"
+            }
+        ],
+        "shared": false,
+        "port_security_enabled": true,
+        "id": "4e8e5957-649f-477b-9e5b-f1f75b21c03c"
+    }
+}
+		`)
+	})
+
+	options := NetworkOpts{Name: "sample_network", AdminStateUp: true}
+
+	n, err := Create(ServiceClient(), options)
+	if err != nil {
+		t.Fatalf("Unexpected error: %#v", err)
+	}
+
+	Equals(t, n.Status, "ACTIVE")
+	DeepEquals(t, n.Subnets, []interface{}{})
+	Equals(t, n.Name, "net1")
+	Equals(t, n.AdminStateUp, true)
+	Equals(t, n.TenantID, "9bacb3c5d39d41a79512987f338cf177")
+	DeepEquals(t, n.Segments, []NetworkProvider{
+		{ProviderSegmentationID: 2, ProviderPhysicalNetwork: "8bab8453-1bc9-45af-8c70-f83aa9b50453", ProviderNetworkType: "vlan"},
+		{ProviderSegmentationID: 0, ProviderPhysicalNetwork: "8bab8453-1bc9-45af-8c70-f83aa9b50453", ProviderNetworkType: "stt"},
+	})
+	Equals(t, n.Shared, false)
+	Equals(t, n.PortSecurityEnabled, true)
+	Equals(t, n.ID, "4e8e5957-649f-477b-9e5b-f1f75b21c03c")
+}
+
+func TestCreateNetworkWithOptionalFields(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/v2.0/networks", 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, `
+{
+	"network": {
+			"name": "sample_network",
+			"admin_state_up": true,
+			"shared": true,
+			"tenant_id": "12345"
+	}
+}
+		`)
+
+		w.WriteHeader(http.StatusCreated)
+	})
+
+	shared := true
+	options := NetworkOpts{Name: "sample_network", AdminStateUp: true, Shared: &shared, TenantID: "12345"}
+
+	_, err := Create(ServiceClient(), options)
+	if err != nil {
+		t.Fatalf("Unexpected error: %#v", err)
+	}
+}
diff --git a/openstack/networking/v2/networks/urls.go b/openstack/networking/v2/networks/urls.go
index 70cc6e1..0b0b70e 100644
--- a/openstack/networking/v2/networks/urls.go
+++ b/openstack/networking/v2/networks/urls.go
@@ -23,3 +23,7 @@
 func NetworkURL(c *gophercloud.ServiceClient, id string) string {
 	return c.ServiceURL(Version, "networks", id)
 }
+
+func CreateURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL(Version, "networks")
+}
diff --git a/openstack/networking/v2/networks/urls_test.go b/openstack/networking/v2/networks/urls_test.go
index df8bd02..b38a417 100644
--- a/openstack/networking/v2/networks/urls_test.go
+++ b/openstack/networking/v2/networks/urls_test.go
@@ -43,3 +43,11 @@
 		t.Fatalf("[%s] does not match expected [%s]", actual, expected)
 	}
 }
+
+func TestCreateURL(t *testing.T) {
+	actual := CreateURL(EndpointClient())
+	expected := Endpoint + "v2.0/networks"
+	if expected != actual {
+		t.Fatalf("[%s] does not match expected [%s]", actual, expected)
+	}
+}