Modifying opts and model structs with stricter types
diff --git a/openstack/networking/v2/networks/requests.go b/openstack/networking/v2/networks/requests.go
index 73b8a1f..4f1037e 100644
--- a/openstack/networking/v2/networks/requests.go
+++ b/openstack/networking/v2/networks/requests.go
@@ -23,7 +23,7 @@
 	SortDir      string
 }
 
-type NetworkOpts struct {
+type networkOpts struct {
 	AdminStateUp bool
 	Name         string
 	Shared       *bool
@@ -98,7 +98,9 @@
 	return &n, nil
 }
 
-func Create(c *gophercloud.ServiceClient, opts NetworkOpts) (*NetworkCreateResult, error) {
+type CreateOpts networkOpts
+
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*NetworkCreateResult, error) {
 	// Define structures
 	type network struct {
 		AdminStateUp bool    `json:"admin_state_up"`
@@ -144,13 +146,14 @@
 	return res.Network, nil
 }
 
-func Update(c *gophercloud.ServiceClient, networkID string, opts NetworkOpts) (*Network, error) {
+type UpdateOpts networkOpts
+
+func Update(c *gophercloud.ServiceClient, networkID string, opts UpdateOpts) (*Network, 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"`
+		AdminStateUp bool   `json:"admin_state_up"`
+		Name         string `json:"name"`
+		Shared       *bool  `json:"shared,omitempty"`
 	}
 
 	type request struct {
@@ -167,10 +170,6 @@
 		Shared:       opts.Shared,
 	}}
 
-	if opts.TenantID != "" {
-		reqBody.Network.TenantID = &opts.TenantID
-	}
-
 	// Send request to API
 	var res response
 	_, err := perigee.Request("PUT", GetURL(c, networkID), perigee.Options{
diff --git a/openstack/networking/v2/networks/requests_test.go b/openstack/networking/v2/networks/requests_test.go
index b4332b0..b637b50 100644
--- a/openstack/networking/v2/networks/requests_test.go
+++ b/openstack/networking/v2/networks/requests_test.go
@@ -84,7 +84,7 @@
 		expected := []Network{
 			Network{
 				Status:  "ACTIVE",
-				Subnets: []interface{}{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"},
+				Subnets: []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"},
 				Name:    "private-network",
 				ProviderPhysicalNetwork: "",
 				AdminStateUp:            true,
@@ -97,7 +97,7 @@
 			},
 			Network{
 				Status:  "ACTIVE",
-				Subnets: []interface{}{"08eae331-0402-425a-923c-34f7cfe39c1b"},
+				Subnets: []string{"08eae331-0402-425a-923c-34f7cfe39c1b"},
 				Name:    "private",
 				ProviderPhysicalNetwork: "",
 				AdminStateUp:            true,
@@ -156,7 +156,7 @@
 	th.AssertNoErr(t, err)
 
 	th.AssertEquals(t, n.Status, "ACTIVE")
-	th.AssertDeepEquals(t, n.Subnets, []interface{}{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"})
+	th.AssertDeepEquals(t, n.Subnets, []string{"54d6f61d-db07-451c-9ab3-b9609b6b6f0b"})
 	th.AssertEquals(t, n.Name, "private-network")
 	th.AssertEquals(t, n.ProviderPhysicalNetwork, "")
 	th.AssertEquals(t, n.ProviderNetworkType, "local")
@@ -217,12 +217,12 @@
 		`)
 	})
 
-	options := NetworkOpts{Name: "sample_network", AdminStateUp: true}
+	options := CreateOpts{Name: "sample_network", AdminStateUp: true}
 	n, err := Create(ServiceClient(), options)
 	th.AssertNoErr(t, err)
 
 	th.AssertEquals(t, n.Status, "ACTIVE")
-	th.AssertDeepEquals(t, n.Subnets, []interface{}{})
+	th.AssertDeepEquals(t, n.Subnets, []string{})
 	th.AssertEquals(t, n.Name, "net1")
 	th.AssertEquals(t, n.AdminStateUp, true)
 	th.AssertEquals(t, n.TenantID, "9bacb3c5d39d41a79512987f338cf177")
@@ -259,7 +259,7 @@
 	})
 
 	shared := true
-	options := NetworkOpts{Name: "sample_network", AdminStateUp: true, Shared: &shared, TenantID: "12345"}
+	options := CreateOpts{Name: "sample_network", AdminStateUp: true, Shared: &shared, TenantID: "12345"}
 	_, err := Create(ServiceClient(), options)
 	th.AssertNoErr(t, err)
 }
@@ -306,7 +306,7 @@
 	})
 
 	shared := true
-	options := NetworkOpts{Name: "new_network_name", AdminStateUp: false, Shared: &shared}
+	options := UpdateOpts{Name: "new_network_name", AdminStateUp: false, Shared: &shared}
 	n, err := Update(ServiceClient(), "4e8e5957-649f-477b-9e5b-f1f75b21c03c", options)
 	th.AssertNoErr(t, err)
 
diff --git a/openstack/networking/v2/networks/results.go b/openstack/networking/v2/networks/results.go
index 1f4b809..78bdff5 100644
--- a/openstack/networking/v2/networks/results.go
+++ b/openstack/networking/v2/networks/results.go
@@ -12,17 +12,26 @@
 }
 
 type Network struct {
-	Status                  string        `mapstructure:"status" json:"status"`
-	Subnets                 []interface{} `mapstructure:"subnets" json:"subnets"`
-	Name                    string        `mapstructure:"name" json:"name"`
-	AdminStateUp            bool          `mapstructure:"admin_state_up" json:"admin_state_up"`
-	TenantID                string        `mapstructure:"tenant_id" json:"tenant_id"`
-	Shared                  bool          `mapstructure:"shared" json:"shared"`
-	ID                      string        `mapstructure:"id" json:"id"`
-	ProviderSegmentationID  int           `mapstructure:"provider:segmentation_id" json:"provider:segmentation_id"`
-	ProviderPhysicalNetwork string        `mapstructure:"provider:physical_network" json:"provider:physical_network"`
-	ProviderNetworkType     string        `mapstructure:"provider:network_type" json:"provider:network_type"`
-	RouterExternal          bool          `mapstructure:"router:external" json:"router:external"`
+	// UUID for the network
+	ID string `mapstructure:"id" json:"id"`
+	// Human-readable name for the network. Might not be unique.
+	Name string `mapstructure:"name" json:"name"`
+	// The administrative state of network. If false (down), the network does not forward packets.
+	AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+	// Indicates whether network is currently operational. Possible values include
+	// `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
+	Status string `mapstructure:"status" json:"status"`
+	// Subnets associated with this network.
+	Subnets []string `mapstructure:"subnets" json:"subnets"`
+	// Owner of network. Only admin users can specify a tenant_id other than its own.
+	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+	// Specifies whether the network resource can be accessed by any tenant or not.
+	Shared bool `mapstructure:"shared" json:"shared"`
+
+	ProviderSegmentationID  int    `mapstructure:"provider:segmentation_id" json:"provider:segmentation_id"`
+	ProviderPhysicalNetwork string `mapstructure:"provider:physical_network" json:"provider:physical_network"`
+	ProviderNetworkType     string `mapstructure:"provider:network_type" json:"provider:network_type"`
+	RouterExternal          bool   `mapstructure:"router:external" json:"router:external"`
 }
 
 type NetworkCreateResult struct {
diff --git a/openstack/networking/v2/ports/requests.go b/openstack/networking/v2/ports/requests.go
index 6543313..cc0949f 100644
--- a/openstack/networking/v2/ports/requests.go
+++ b/openstack/networking/v2/ports/requests.go
@@ -91,7 +91,7 @@
 		q["sort_dir"] = opts.SortDir
 	}
 
-	u := ListURL(c) + utils.BuildQuery(q)
+	u := listURL(c) + utils.BuildQuery(q)
 	return pagination.NewPager(c, u, func(r pagination.LastHTTPResponse) pagination.Page {
 		return PortPage{pagination.LinkedPageBase(r)}
 	})
@@ -99,7 +99,7 @@
 
 func Get(c *gophercloud.ServiceClient, id string) (*Port, error) {
 	var p Port
-	_, err := perigee.Request("GET", GetURL(c, id), perigee.Options{
+	_, err := perigee.Request("GET", getURL(c, id), perigee.Options{
 		MoreHeaders: c.Provider.AuthenticatedHeaders(),
 		Results: &struct {
 			Port *Port `json:"port"`
@@ -112,17 +112,6 @@
 	return &p, nil
 }
 
-type PortOpts struct {
-	NetworkID      string
-	Status         string
-	Name           string
-	AdminStateUp   *bool
-	TenantID       string
-	MACAddress     string
-	FixedIPs       interface{}
-	SecurityGroups []string
-}
-
 func maybeString(original string) *string {
 	if original != "" {
 		return &original
@@ -130,15 +119,28 @@
 	return nil
 }
 
-func Create(c *gophercloud.ServiceClient, opts PortOpts) (*Port, error) {
+type CreateOpts struct {
+	NetworkID      string
+	Name           string
+	AdminStateUp   *bool
+	MACAddress     string
+	FixedIPs       interface{}
+	DeviceID       string
+	DeviceOwner    string
+	TenantID       string
+	SecurityGroups []string
+}
+
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*Port, error) {
 	type port struct {
 		NetworkID      string      `json:"network_id,omitempty"`
-		Status         *string     `json:"status,omitempty"`
 		Name           *string     `json:"name,omitempty"`
 		AdminStateUp   *bool       `json:"admin_state_up,omitempty"`
-		TenantID       *string     `json:"tenant_id,omitempty"`
 		MACAddress     *string     `json:"mac_address,omitempty"`
 		FixedIPs       interface{} `json:"fixed_ips,omitempty"`
+		DeviceID       *string     `json:"device_id,omitempty"`
+		DeviceOwner    *string     `json:"device_owner,omitempty"`
+		TenantID       *string     `json:"tenant_id,omitempty"`
 		SecurityGroups []string    `json:"security_groups,omitempty"`
 	}
 	type request struct {
@@ -153,11 +155,12 @@
 	// Populate request body
 	reqBody := request{Port: port{
 		NetworkID:    opts.NetworkID,
-		Status:       maybeString(opts.Status),
 		Name:         maybeString(opts.Name),
 		AdminStateUp: opts.AdminStateUp,
 		TenantID:     maybeString(opts.TenantID),
 		MACAddress:   maybeString(opts.MACAddress),
+		DeviceID:     maybeString(opts.DeviceID),
+		DeviceOwner:  maybeString(opts.DeviceOwner),
 	}}
 
 	if opts.FixedIPs != nil {
@@ -173,7 +176,7 @@
 		Port *Port `json:"port"`
 	}
 	var res response
-	_, err := perigee.Request("POST", CreateURL(c), perigee.Options{
+	_, err := perigee.Request("POST", createURL(c), perigee.Options{
 		MoreHeaders: c.Provider.AuthenticatedHeaders(),
 		ReqBody:     &reqBody,
 		Results:     &res,
@@ -187,34 +190,34 @@
 	return res.Port, nil
 }
 
-func Update(c *gophercloud.ServiceClient, id string, opts PortOpts) (*Port, error) {
+type UpdateOpts struct {
+	Name           string
+	AdminStateUp   *bool
+	FixedIPs       interface{}
+	DeviceID       string
+	DeviceOwner    string
+	SecurityGroups []string
+}
+
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (*Port, error) {
 	type port struct {
-		NetworkID      string      `json:"network_id,omitempty"`
-		Status         *string     `json:"status,omitempty"`
 		Name           *string     `json:"name,omitempty"`
 		AdminStateUp   *bool       `json:"admin_state_up,omitempty"`
-		TenantID       *string     `json:"tenant_id,omitempty"`
-		MACAddress     *string     `json:"mac_address,omitempty"`
 		FixedIPs       interface{} `json:"fixed_ips,omitempty"`
+		DeviceID       *string     `json:"device_id,omitempty"`
+		DeviceOwner    *string     `json:"device_owner,omitempty"`
 		SecurityGroups []string    `json:"security_groups,omitempty"`
 	}
 	type request struct {
 		Port port `json:"port"`
 	}
 
-	// Validate
-	if opts.NetworkID == "" {
-		return nil, ErrNetworkIDRequired
-	}
-
 	// Populate request body
 	reqBody := request{Port: port{
-		NetworkID:    opts.NetworkID,
-		Status:       maybeString(opts.Status),
 		Name:         maybeString(opts.Name),
 		AdminStateUp: opts.AdminStateUp,
-		TenantID:     maybeString(opts.TenantID),
-		MACAddress:   maybeString(opts.MACAddress),
+		DeviceID:     maybeString(opts.DeviceID),
+		DeviceOwner:  maybeString(opts.DeviceOwner),
 	}}
 
 	if opts.FixedIPs != nil {
@@ -230,7 +233,7 @@
 		Port *Port `json:"port"`
 	}
 	var res response
-	_, err := perigee.Request("PUT", UpdateURL(c, id), perigee.Options{
+	_, err := perigee.Request("PUT", updateURL(c, id), perigee.Options{
 		MoreHeaders: c.Provider.AuthenticatedHeaders(),
 		ReqBody:     &reqBody,
 		Results:     &res,
@@ -244,7 +247,7 @@
 }
 
 func Delete(c *gophercloud.ServiceClient, id string) error {
-	_, err := perigee.Request("DELETE", DeleteURL(c, id), perigee.Options{
+	_, err := perigee.Request("DELETE", deleteURL(c, id), perigee.Options{
 		MoreHeaders: c.Provider.AuthenticatedHeaders(),
 		OkCodes:     []int{204},
 	})
diff --git a/openstack/networking/v2/ports/requests_test.go b/openstack/networking/v2/ports/requests_test.go
index cb4cc2c..83b0153 100644
--- a/openstack/networking/v2/ports/requests_test.go
+++ b/openstack/networking/v2/ports/requests_test.go
@@ -10,13 +10,11 @@
 	th "github.com/rackspace/gophercloud/testhelper"
 )
 
-const TokenID = "123"
+const tokenID = "123"
 
 func ServiceClient() *gophercloud.ServiceClient {
 	return &gophercloud.ServiceClient{
-		Provider: &gophercloud.ProviderClient{
-			TokenID: TokenID,
-		},
+		Provider: &gophercloud.ProviderClient{TokenID: tokenID},
 		Endpoint: th.Endpoint(),
 	}
 }
@@ -27,7 +25,7 @@
 
 	th.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "GET")
-		th.TestHeader(t, r, "X-Auth-Token", TokenID)
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
 
 		w.Header().Add("Content-Type", "application/json")
 		w.WriteHeader(http.StatusOK)
@@ -122,7 +120,7 @@
 
 	th.Mux.HandleFunc("/v2.0/ports/46d4bfb9-b26e-41f3-bd2e-e6dcc1ccedb2", func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "GET")
-		th.TestHeader(t, r, "X-Auth-Token", TokenID)
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
 
 		w.Header().Add("Content-Type", "application/json")
 		w.WriteHeader(http.StatusOK)
@@ -192,7 +190,7 @@
 
 	th.Mux.HandleFunc("/v2.0/ports", func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "POST")
-		th.TestHeader(t, r, "X-Auth-Token", TokenID)
+		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, `
@@ -241,7 +239,7 @@
 	})
 
 	asu := true
-	options := PortOpts{Name: "private-port", AdminStateUp: &asu, NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7"}
+	options := CreateOpts{Name: "private-port", AdminStateUp: &asu, NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7"}
 	n, err := Create(ServiceClient(), options)
 	th.AssertNoErr(t, err)
 
@@ -272,13 +270,12 @@
 
 	th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "PUT")
-		th.TestHeader(t, r, "X-Auth-Token", TokenID)
+		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, `
 {
 		"port": {
-				"network_id": "a87cc70a-3e15-4acf-8205-9b711a3531b7",
 				"name": "new_port_name",
 				"fixed_ips": [
             {
@@ -328,9 +325,8 @@
 		`)
 	})
 
-	options := PortOpts{
-		NetworkID: "a87cc70a-3e15-4acf-8205-9b711a3531b7",
-		Name:      "new_port_name",
+	options := UpdateOpts{
+		Name: "new_port_name",
 		FixedIPs: []IP{
 			IP{SubnetID: "a0304c3a-4f08-4c43-88af-d796509c97d2", IPAddress: "10.0.0.3"},
 		},
@@ -353,7 +349,7 @@
 
 	th.Mux.HandleFunc("/v2.0/ports/65c0ee9f-d634-4522-8954-51021b570b0d", func(w http.ResponseWriter, r *http.Request) {
 		th.TestMethod(t, r, "DELETE")
-		th.TestHeader(t, r, "X-Auth-Token", TokenID)
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
 		w.WriteHeader(http.StatusNoContent)
 	})
 
diff --git a/openstack/networking/v2/ports/results.go b/openstack/networking/v2/ports/results.go
index f7f947d..7e90d8d 100644
--- a/openstack/networking/v2/ports/results.go
+++ b/openstack/networking/v2/ports/results.go
@@ -11,19 +11,33 @@
 }
 
 type Port struct {
-	Status              string        `mapstructure:"status" json:"status"`
-	Name                string        `mapstructure:"name" json:"name"`
+	// UUID for the port.
+	ID string `mapstructure:"id" json:"id"`
+	// Network that this port is associated with.
+	NetworkID string `mapstructure:"network_id" json:"network_id"`
+	// Human-readable name for the port. Might not be unique.
+	Name string `mapstructure:"name" json:"name"`
+	// Administrative state of port. If false (down), port does not forward packets.
+	AdminStateUp bool `mapstructure:"admin_state_up" json:"admin_state_up"`
+	// Indicates whether network is currently operational. Possible values include
+	// `ACTIVE', `DOWN', `BUILD', or `ERROR'. Plug-ins might define additional values.
+	Status string `mapstructure:"status" json:"status"`
+	// Mac address to use on this port.
+	MACAddress string `mapstructure:"mac_address" json:"mac_address"`
+	// Specifies IP addresses for the port thus associating the port itself with
+	// the subnets where the IP addresses are picked from
+	FixedIPs []IP `mapstructure:"fixed_ips" json:"fixed_ips"`
+	// Owner of network. Only admin users can specify a tenant_id other than its own.
+	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
+	// Identifies the entity (e.g.: dhcp agent) using this port.
+	DeviceOwner string `mapstructure:"device_owner" json:"device_owner"`
+	// Specifies the IDs of any security groups associated with a port.
+	SecurityGroups []string `mapstructure:"security_groups" json:"security_groups"`
+	// Identifies the device (e.g., virtual server) using this port.
+	DeviceID string `mapstructure:"device_id" json:"device_id"`
+
 	AllowedAddressPairs []interface{} `mapstructure:"allowed" json:"allowed"`
-	AdminStateUp        bool          `mapstructure:"admin_state_up" json:"admin_state_up"`
-	NetworkID           string        `mapstructure:"network_id" json:"network_id"`
-	TenantID            string        `mapstructure:"tenant_id" json:"tenant_id"`
 	ExtraDHCPOpts       interface{}   `mapstructure:"extra_dhcp_opts" json:"extra_dhcp_opts"`
-	DeviceOwner         string        `mapstructure:"device_owner" json:"device_owner"`
-	MACAddress          string        `mapstructure:"mac_address" json:"mac_address"`
-	FixedIPs            []IP          `mapstructure:"fixed_ips" json:"fixed_ips"`
-	ID                  string        `mapstructure:"id" json:"id"`
-	SecurityGroups      []string      `mapstructure:"security_groups" json:"security_groups"`
-	DeviceID            string        `mapstructure:"device_id" json:"device_id"`
 	BindingHostID       string        `mapstructure:"binding:host_id" json:"binding:host_id"`
 	BindingVIFDetails   interface{}   `mapstructure:"binding:vif_details" json:"binding:vif_details"`
 	BindingVIFType      string        `mapstructure:"binding:vif_type" json:"binding:vif_type"`
diff --git a/openstack/networking/v2/ports/urls.go b/openstack/networking/v2/ports/urls.go
index 5dc4696..558b399 100644
--- a/openstack/networking/v2/ports/urls.go
+++ b/openstack/networking/v2/ports/urls.go
@@ -2,32 +2,32 @@
 
 import "github.com/rackspace/gophercloud"
 
-const Version = "v2.0"
+const version = "v2.0"
 
-func ResourceURL(c *gophercloud.ServiceClient, id string) string {
-	return c.ServiceURL(Version, "ports", id)
+func resourceURL(c *gophercloud.ServiceClient, id string) string {
+	return c.ServiceURL(version, "ports", id)
 }
 
-func RootURL(c *gophercloud.ServiceClient) string {
-	return c.ServiceURL(Version, "ports")
+func rootURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL(version, "ports")
 }
 
-func ListURL(c *gophercloud.ServiceClient) string {
-	return RootURL(c)
+func listURL(c *gophercloud.ServiceClient) string {
+	return rootURL(c)
 }
 
-func GetURL(c *gophercloud.ServiceClient, id string) string {
-	return ResourceURL(c, id)
+func getURL(c *gophercloud.ServiceClient, id string) string {
+	return resourceURL(c, id)
 }
 
-func CreateURL(c *gophercloud.ServiceClient) string {
-	return RootURL(c)
+func createURL(c *gophercloud.ServiceClient) string {
+	return rootURL(c)
 }
 
-func UpdateURL(c *gophercloud.ServiceClient, id string) string {
-	return ResourceURL(c, id)
+func updateURL(c *gophercloud.ServiceClient, id string) string {
+	return resourceURL(c, id)
 }
 
-func DeleteURL(c *gophercloud.ServiceClient, id string) string {
-	return ResourceURL(c, id)
+func deleteURL(c *gophercloud.ServiceClient, id string) string {
+	return resourceURL(c, id)
 }
diff --git a/openstack/networking/v2/ports/urls_tests.go b/openstack/networking/v2/ports/urls_tests.go
index 089725d..6fb20aa 100644
--- a/openstack/networking/v2/ports/urls_tests.go
+++ b/openstack/networking/v2/ports/urls_tests.go
@@ -7,38 +7,38 @@
 	th "github.com/rackspace/gophercloud/testhelper"
 )
 
-const Endpoint = "http://localhost:57909/"
+const endpoint = "http://localhost:57909/"
 
-func EndpointClient() *gophercloud.ServiceClient {
-	return &gophercloud.ServiceClient{Endpoint: Endpoint}
+func endpointClient() *gophercloud.ServiceClient {
+	return &gophercloud.ServiceClient{Endpoint: endpoint}
 }
 
 func TestListURL(t *testing.T) {
-	actual := ListURL(EndpointClient())
-	expected := Endpoint + "v2.0/ports"
+	actual := listURL(endpointClient())
+	expected := endpoint + "v2.0/ports"
 	th.AssertEquals(t, expected, actual)
 }
 
 func TestGetURL(t *testing.T) {
-	actual := GetURL(EndpointClient(), "foo")
-	expected := Endpoint + "v2.0/ports/foo"
+	actual := getURL(endpointClient(), "foo")
+	expected := endpoint + "v2.0/ports/foo"
 	th.AssertEquals(t, expected, actual)
 }
 
 func TestCreateURL(t *testing.T) {
-	actual := CreateURL(EndpointClient())
-	expected := Endpoint + "v2.0/ports"
+	actual := createURL(endpointClient())
+	expected := endpoint + "v2.0/ports"
 	th.AssertEquals(t, expected, actual)
 }
 
 func TestUpdateURL(t *testing.T) {
-	actual := UpdateURL(EndpointClient(), "foo")
-	expected := Endpoint + "v2.0/ports/foo"
+	actual := updateURL(endpointClient(), "foo")
+	expected := endpoint + "v2.0/ports/foo"
 	th.AssertEquals(t, expected, actual)
 }
 
 func TestDeleteURL(t *testing.T) {
-	actual := DeleteURL(EndpointClient(), "foo")
-	expected := Endpoint + "v2.0/ports/foo"
+	actual := deleteURL(endpointClient(), "foo")
+	expected := endpoint + "v2.0/ports/foo"
 	th.AssertEquals(t, expected, actual)
 }
diff --git a/openstack/networking/v2/subnets/requests.go b/openstack/networking/v2/subnets/requests.go
index f592739..ff36765 100644
--- a/openstack/networking/v2/subnets/requests.go
+++ b/openstack/networking/v2/subnets/requests.go
@@ -89,12 +89,20 @@
 	return &s, nil
 }
 
+// maybeString returns nil for empty strings and nil for empty.
+func maybeString(original string) *string {
+	if original != "" {
+		return &original
+	}
+	return nil
+}
+
 const (
 	IPv4 = 4
 	IPv6 = 6
 )
 
-type SubnetOpts struct {
+type CreateOpts struct {
 	// Required
 	NetworkID string
 	CIDR      string
@@ -104,19 +112,12 @@
 	AllocationPools []AllocationPool
 	GatewayIP       string
 	IPVersion       int
-	ID              string
 	EnableDHCP      *bool
+	DNSNameservers  []string
+	HostRoutes      []interface{}
 }
 
-// maybeString returns nil for empty strings and nil for empty.
-func maybeString(original string) *string {
-	if original != "" {
-		return &original
-	}
-	return nil
-}
-
-func Create(c *gophercloud.ServiceClient, opts SubnetOpts) (*Subnet, error) {
+func Create(c *gophercloud.ServiceClient, opts CreateOpts) (*Subnet, error) {
 	// Validate required options
 	if opts.NetworkID == "" {
 		return nil, ErrNetworkIDRequired
@@ -136,8 +137,9 @@
 		AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
 		GatewayIP       *string          `json:"gateway_ip,omitempty"`
 		IPVersion       int              `json:"ip_version,omitempty"`
-		ID              *string          `json:"id,omitempty"`
 		EnableDHCP      *bool            `json:"enable_dhcp,omitempty"`
+		DNSNameservers  []string         `json:"dns_nameservers,omitempty"`
+		HostRoutes      []interface{}    `json:"host_routes,omitempty"`
 	}
 	type request struct {
 		Subnet subnet `json:"subnet"`
@@ -149,17 +151,21 @@
 		Name:       maybeString(opts.Name),
 		TenantID:   maybeString(opts.TenantID),
 		GatewayIP:  maybeString(opts.GatewayIP),
-		ID:         maybeString(opts.ID),
 		EnableDHCP: opts.EnableDHCP,
 	}}
 
 	if opts.IPVersion != 0 {
 		reqBody.Subnet.IPVersion = opts.IPVersion
 	}
-
 	if len(opts.AllocationPools) != 0 {
 		reqBody.Subnet.AllocationPools = opts.AllocationPools
 	}
+	if len(opts.DNSNameservers) != 0 {
+		reqBody.Subnet.DNSNameservers = opts.DNSNameservers
+	}
+	if len(opts.HostRoutes) != 0 {
+		reqBody.Subnet.HostRoutes = opts.HostRoutes
+	}
 
 	type response struct {
 		Subnet *Subnet `json:"subnet"`
@@ -179,38 +185,38 @@
 	return res.Subnet, nil
 }
 
-func Update(c *gophercloud.ServiceClient, id string, opts SubnetOpts) (*Subnet, error) {
-	if opts.CIDR != "" {
-		return nil, ErrCIDRNotUpdatable
-	}
-	if opts.IPVersion != 0 {
-		return nil, ErrIPVersionNotUpdatable
-	}
+type UpdateOpts struct {
+	Name           string
+	GatewayIP      string
+	DNSNameservers []string
+	HostRoutes     []interface{}
+	EnableDHCP     *bool
+}
 
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) (*Subnet, error) {
 	type subnet struct {
-		NetworkID       string           `json:"network_id,omitempty"`
-		Name            *string          `json:"name,omitempty"`
-		TenantID        *string          `json:"tenant_id,omitempty"`
-		AllocationPools []AllocationPool `json:"allocation_pools,omitempty"`
-		GatewayIP       *string          `json:"gateway_ip,omitempty"`
-		ID              *string          `json:"id,omitempty"`
-		EnableDHCP      *bool            `json:"enable_dhcp,omitempty"`
+		Name           *string       `json:"name,omitempty"`
+		GatewayIP      *string       `json:"gateway_ip,omitempty"`
+		DNSNameservers []string      `json:"dns_nameservers,omitempty"`
+		HostRoutes     []interface{} `json:"host_routes,omitempty"`
+		EnableDHCP     *bool         `json:"enable_dhcp,omitempty"`
 	}
 	type request struct {
 		Subnet subnet `json:"subnet"`
 	}
 
 	reqBody := request{Subnet: subnet{
-		NetworkID:  opts.NetworkID,
 		Name:       maybeString(opts.Name),
-		TenantID:   maybeString(opts.TenantID),
 		GatewayIP:  maybeString(opts.GatewayIP),
-		ID:         maybeString(opts.ID),
 		EnableDHCP: opts.EnableDHCP,
 	}}
 
-	if len(opts.AllocationPools) != 0 {
-		reqBody.Subnet.AllocationPools = opts.AllocationPools
+	if len(opts.DNSNameservers) != 0 {
+		reqBody.Subnet.DNSNameservers = opts.DNSNameservers
+	}
+
+	if len(opts.HostRoutes) != 0 {
+		reqBody.Subnet.HostRoutes = opts.HostRoutes
 	}
 
 	type response struct {
diff --git a/openstack/networking/v2/subnets/requests_test.go b/openstack/networking/v2/subnets/requests_test.go
index edf59e7..63e9cc2 100644
--- a/openstack/networking/v2/subnets/requests_test.go
+++ b/openstack/networking/v2/subnets/requests_test.go
@@ -92,7 +92,7 @@
 				EnableDHCP:     true,
 				NetworkID:      "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
 				TenantID:       "26a7980765d0414dbc1fc1f88cdb7e6e",
-				DNSNameservers: []interface{}{},
+				DNSNameservers: []string{},
 				AllocationPools: []AllocationPool{
 					AllocationPool{
 						Start: "10.0.0.2",
@@ -110,7 +110,7 @@
 				EnableDHCP:     true,
 				NetworkID:      "d32019d3-bc6e-4319-9c1d-6722fc136a22",
 				TenantID:       "4fd44f30292945e481c7b8a0c8908869",
-				DNSNameservers: []interface{}{},
+				DNSNameservers: []string{},
 				AllocationPools: []AllocationPool{
 					AllocationPool{
 						Start: "192.0.0.2",
@@ -177,7 +177,7 @@
 	th.AssertEquals(t, s.EnableDHCP, true)
 	th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
 	th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869")
-	th.AssertDeepEquals(t, s.DNSNameservers, []interface{}{})
+	th.AssertDeepEquals(t, s.DNSNameservers, []string{})
 	th.AssertDeepEquals(t, s.AllocationPools, []AllocationPool{
 		AllocationPool{
 			Start: "192.0.0.2",
@@ -237,7 +237,7 @@
 		`)
 	})
 
-	opts := SubnetOpts{NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22", IPVersion: 4, CIDR: "192.168.199.0/24"}
+	opts := CreateOpts{NetworkID: "d32019d3-bc6e-4319-9c1d-6722fc136a22", IPVersion: 4, CIDR: "192.168.199.0/24"}
 	s, err := Create(ServiceClient(), opts)
 	th.AssertNoErr(t, err)
 
@@ -245,7 +245,7 @@
 	th.AssertEquals(t, s.EnableDHCP, true)
 	th.AssertEquals(t, s.NetworkID, "d32019d3-bc6e-4319-9c1d-6722fc136a22")
 	th.AssertEquals(t, s.TenantID, "4fd44f30292945e481c7b8a0c8908869")
-	th.AssertDeepEquals(t, s.DNSNameservers, []interface{}{})
+	th.AssertDeepEquals(t, s.DNSNameservers, []string{})
 	th.AssertDeepEquals(t, s.AllocationPools, []AllocationPool{
 		AllocationPool{
 			Start: "192.168.199.2",
@@ -303,7 +303,7 @@
 	`)
 	})
 
-	opts := SubnetOpts{Name: "my_new_subnet"}
+	opts := UpdateOpts{Name: "my_new_subnet"}
 	s, err := Update(ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b", opts)
 	th.AssertNoErr(t, err)
 
@@ -311,15 +311,6 @@
 	th.AssertEquals(t, s.ID, "08eae331-0402-425a-923c-34f7cfe39c1b")
 }
 
-func TestCertainAttrsCannotBeUpdated(t *testing.T) {
-	opts := SubnetOpts{IPVersion: 6, CIDR: "192.0.0.1/24"}
-	_, err := Update(ServiceClient(), "08eae331-0402-425a-923c-34f7cfe39c1b", opts)
-
-	if err == nil {
-		t.Errorf("An error was expected when updating IPVersion and CIDR, none was raised")
-	}
-}
-
 func TestDelete(t *testing.T) {
 	th.SetupHTTP()
 	defer th.TeardownHTTP()
diff --git a/openstack/networking/v2/subnets/results.go b/openstack/networking/v2/subnets/results.go
index 3de2668..d916a1c 100644
--- a/openstack/networking/v2/subnets/results.go
+++ b/openstack/networking/v2/subnets/results.go
@@ -11,17 +11,28 @@
 }
 
 type Subnet struct {
-	Name            string           `mapstructure:"name" json:"name"`
-	EnableDHCP      bool             `mapstructure:"enable_dhcp" json:"enable_dhcp"`
-	NetworkID       string           `mapstructure:"network_id" json:"network_id"`
-	TenantID        string           `mapstructure:"tenant_id" json:"tenant_id"`
-	DNSNameservers  []interface{}    `mapstructure:"dns_nameservers" json:"dns_nameservers"`
+	// UUID representing the subnet
+	ID string `mapstructure:"id" json:"id"`
+	// UUID of the parent network
+	NetworkID string `mapstructure:"network_id" json:"network_id"`
+	// Human-readable name for the subnet. Might not be unique.
+	Name string `mapstructure:"name" json:"name"`
+	// IP version, either `4' or `6'
+	IPVersion int `mapstructure:"ip_version" json:"ip_version"`
+	// CIDR representing IP range for this subnet, based on IP version
+	CIDR string `mapstructure:"cidr" json:"cidr"`
+	// Default gateway used by devices in this subnet
+	GatewayIP string `mapstructure:"gateway_ip" json:"gateway_ip"`
+	// DNS name servers used by hosts in this subnet.
+	DNSNameservers []string `mapstructure:"dns_nameservers" json:"dns_nameservers"`
+	// Sub-ranges of CIDR available for dynamic allocation to ports. See AllocationPool.
 	AllocationPools []AllocationPool `mapstructure:"allocation_pools" json:"allocation_pools"`
-	HostRoutes      []interface{}    `mapstructure:"host_routes" json:"host_routes"`
-	IPVersion       int              `mapstructure:"ip_version" json:"ip_version"`
-	GatewayIP       string           `mapstructure:"gateway_ip" json:"gateway_ip"`
-	CIDR            string           `mapstructure:"cidr" json:"cidr"`
-	ID              string           `mapstructure:"id" json:"id"`
+	// Routes that should be used by devices with IPs from this subnet (not including local subnet route).
+	HostRoutes []interface{} `mapstructure:"host_routes" json:"host_routes"`
+	// Specifies whether DHCP is enabled for this subnet or not.
+	EnableDHCP bool `mapstructure:"enable_dhcp" json:"enable_dhcp"`
+	// Owner of network. Only admin users can specify a tenant_id other than its own.
+	TenantID string `mapstructure:"tenant_id" json:"tenant_id"`
 }
 
 type SubnetPage struct {