Adding list operation for L3-routing
diff --git a/openstack/networking/v2/extensions/layer3/doc.go b/openstack/networking/v2/extensions/layer3/doc.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/doc.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/layer3/errors.go b/openstack/networking/v2/extensions/layer3/errors.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/errors.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/layer3/requests.go b/openstack/networking/v2/extensions/layer3/requests.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/requests.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/layer3/requests_test.go b/openstack/networking/v2/extensions/layer3/requests_test.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/requests_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/layer3/results.go b/openstack/networking/v2/extensions/layer3/results.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/results.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/layer3/routers/doc.go b/openstack/networking/v2/extensions/layer3/routers/doc.go
new file mode 100755
index 0000000..159906f
--- /dev/null
+++ b/openstack/networking/v2/extensions/layer3/routers/doc.go
@@ -0,0 +1 @@
+package routers
diff --git a/openstack/networking/v2/extensions/layer3/routers/requests.go b/openstack/networking/v2/extensions/layer3/routers/requests.go
new file mode 100755
index 0000000..38ab4f4
--- /dev/null
+++ b/openstack/networking/v2/extensions/layer3/routers/requests.go
@@ -0,0 +1,70 @@
+package routers
+
+import (
+	"strconv"
+
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/openstack/utils"
+	"github.com/rackspace/gophercloud/pagination"
+)
+
+const (
+	version      = "v2.0"
+	resourcePath = "routers"
+)
+
+func rootURL(c *gophercloud.ServiceClient) string {
+	return c.ServiceURL(version, resourcePath)
+}
+
+func resourceURL(c *gophercloud.ServiceClient, id string) string {
+	return c.ServiceURL(version, resourcePath, id)
+}
+
+type ListOpts struct {
+	ID           string
+	Name         string
+	AdminStateUp *bool
+	Status       string
+	TenantID     string
+	Limit        int
+	Marker       string
+	SortKey      string
+	SortDir      string
+}
+
+func List(c *gophercloud.ServiceClient, opts ListOpts) pagination.Pager {
+	q := make(map[string]string)
+	if opts.ID != "" {
+		q["id"] = opts.ID
+	}
+	if opts.Name != "" {
+		q["name"] = opts.Name
+	}
+	if opts.AdminStateUp != nil {
+		q["admin_state_up"] = strconv.FormatBool(*opts.AdminStateUp)
+	}
+	if opts.Status != "" {
+		q["status"] = opts.Status
+	}
+	if opts.TenantID != "" {
+		q["tenant_id"] = opts.TenantID
+	}
+	if opts.Marker != "" {
+		q["marker"] = opts.Marker
+	}
+	if opts.Limit != 0 {
+		q["limit"] = strconv.Itoa(opts.Limit)
+	}
+	if opts.SortKey != "" {
+		q["sort_key"] = opts.SortKey
+	}
+	if opts.SortDir != "" {
+		q["sort_dir"] = opts.SortDir
+	}
+
+	u := rootURL(c) + utils.BuildQuery(q)
+	return pagination.NewPager(c, u, func(r pagination.LastHTTPResponse) pagination.Page {
+		return RouterPage{pagination.LinkedPageBase(r)}
+	})
+}
diff --git a/openstack/networking/v2/extensions/layer3/routers/requests_test.go b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
new file mode 100755
index 0000000..0078fc5
--- /dev/null
+++ b/openstack/networking/v2/extensions/layer3/routers/requests_test.go
@@ -0,0 +1,119 @@
+package routers
+
+import (
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/rackspace/gophercloud"
+	"github.com/rackspace/gophercloud/pagination"
+	th "github.com/rackspace/gophercloud/testhelper"
+)
+
+const tokenID = "123"
+
+func serviceClient() *gophercloud.ServiceClient {
+	return &gophercloud.ServiceClient{
+		Provider: &gophercloud.ProviderClient{TokenID: tokenID},
+		Endpoint: th.Endpoint(),
+	}
+}
+
+func TestURLs(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.AssertEquals(t, th.Endpoint()+"v2.0/routers", rootURL(serviceClient()))
+}
+
+func TestList(t *testing.T) {
+	th.SetupHTTP()
+	defer th.TeardownHTTP()
+
+	th.Mux.HandleFunc("/v2.0/routers", func(w http.ResponseWriter, r *http.Request) {
+		th.TestMethod(t, r, "GET")
+		th.TestHeader(t, r, "X-Auth-Token", tokenID)
+
+		w.Header().Add("Content-Type", "application/json")
+		w.WriteHeader(http.StatusOK)
+
+		fmt.Fprintf(w, `
+{
+    "routers": [
+        {
+            "status": "ACTIVE",
+            "external_gateway_info": null,
+            "name": "second_routers",
+            "admin_state_up": true,
+            "tenant_id": "6b96ff0cb17a4b859e1e575d221683d3",
+            "id": "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b"
+        },
+        {
+            "status": "ACTIVE",
+            "external_gateway_info": {
+                "network_id": "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"
+            },
+            "name": "router1",
+            "admin_state_up": true,
+            "tenant_id": "33a40233088643acb66ff6eb0ebea679",
+            "id": "a9254bdb-2613-4a13-ac4c-adc581fba50d"
+        }
+    ]
+}
+			`)
+	})
+
+	count := 0
+
+	List(serviceClient(), ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
+		count++
+		actual, err := ExtractRouters(page)
+		if err != nil {
+			t.Errorf("Failed to extract routers: %v", err)
+			return false, err
+		}
+
+		expected := []Router{
+			Router{
+				Status:         "ACTIVE",
+				ExtGatewayInfo: GatewayInfo{NetworkID: ""},
+				AdminStateUp:   true,
+				Name:           "second_routers",
+				ID:             "7177abc4-5ae9-4bb7-b0d4-89e94a4abf3b",
+				TenantID:       "6b96ff0cb17a4b859e1e575d221683d3",
+			},
+			Router{
+				Status:         "ACTIVE",
+				ExtGatewayInfo: GatewayInfo{NetworkID: "3c5bcddd-6af9-4e6b-9c3e-c153e521cab8"},
+				AdminStateUp:   true,
+				Name:           "router1",
+				ID:             "a9254bdb-2613-4a13-ac4c-adc581fba50d",
+				TenantID:       "33a40233088643acb66ff6eb0ebea679",
+			},
+		}
+
+		th.CheckDeepEquals(t, expected, actual)
+
+		return true, nil
+	})
+
+	if count != 1 {
+		t.Errorf("Expected 1 page, got %d", count)
+	}
+}
+
+func TestCreate(t *testing.T) {
+
+}
+
+func TestGet(t *testing.T) {
+
+}
+
+func TestUpdate(t *testing.T) {
+
+}
+
+func TestDelete(t *testing.T) {
+
+}
diff --git a/openstack/networking/v2/extensions/layer3/routers/results.go b/openstack/networking/v2/extensions/layer3/routers/results.go
new file mode 100755
index 0000000..cdacb5b
--- /dev/null
+++ b/openstack/networking/v2/extensions/layer3/routers/results.go
@@ -0,0 +1,72 @@
+package routers
+
+import (
+	"github.com/mitchellh/mapstructure"
+	"github.com/rackspace/gophercloud/pagination"
+)
+
+type GatewayInfo struct {
+	NetworkID string `json:"network_id" mapstructure:"network_id"`
+}
+
+type Router struct {
+	Status         string      `json:"status" mapstructure:"status"`
+	ExtGatewayInfo GatewayInfo `json:"external_gateway_info" mapstructure:"external_gateway_info"`
+	AdminStateUp   bool        `json:"admin_state_up" mapstructure:"admin_state_up"`
+	Name           string      `json:"name" mapstructure:"name"`
+	ID             string      `json:"id" mapstructure:"id"`
+	TenantID       string      `json:"tenant_id" mapstructure:"tenant_id"`
+}
+
+type RouterPage struct {
+	pagination.LinkedPageBase
+}
+
+func (p RouterPage) NextPageURL() (string, error) {
+	type link struct {
+		Href string `mapstructure:"href"`
+		Rel  string `mapstructure:"rel"`
+	}
+	type resp struct {
+		Links []link `mapstructure:"routers_links"`
+	}
+
+	var r resp
+	err := mapstructure.Decode(p.Body, &r)
+	if err != nil {
+		return "", err
+	}
+
+	var url string
+	for _, l := range r.Links {
+		if l.Rel == "next" {
+			url = l.Href
+		}
+	}
+	if url == "" {
+		return "", nil
+	}
+
+	return url, nil
+}
+
+func (p RouterPage) IsEmpty() (bool, error) {
+	is, err := ExtractRouters(p)
+	if err != nil {
+		return true, nil
+	}
+	return len(is) == 0, nil
+}
+
+func ExtractRouters(page pagination.Page) ([]Router, error) {
+	var resp struct {
+		Routers []Router `mapstructure:"routers" json:"routers"`
+	}
+
+	err := mapstructure.Decode(page.(RouterPage).Body, &resp)
+	if err != nil {
+		return nil, err
+	}
+
+	return resp.Routers, nil
+}
diff --git a/openstack/networking/v2/extensions/layer3/urls.go b/openstack/networking/v2/extensions/layer3/urls.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/urls.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/layer3/urls_tests.go b/openstack/networking/v2/extensions/layer3/urls_tests.go
deleted file mode 100755
index 1040241..0000000
--- a/openstack/networking/v2/extensions/layer3/urls_tests.go
+++ /dev/null
@@ -1 +0,0 @@
-package layer3
diff --git a/openstack/networking/v2/extensions/meteringlabels/doc.go b/openstack/networking/v2/extensions/meteringlabels/doc.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/doc.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/meteringlabels/errors.go b/openstack/networking/v2/extensions/meteringlabels/errors.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/errors.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/meteringlabels/requests.go b/openstack/networking/v2/extensions/meteringlabels/requests.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/requests.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/meteringlabels/requests_test.go b/openstack/networking/v2/extensions/meteringlabels/requests_test.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/requests_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/meteringlabels/results.go b/openstack/networking/v2/extensions/meteringlabels/results.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/results.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/meteringlabels/urls.go b/openstack/networking/v2/extensions/meteringlabels/urls.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/urls.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/meteringlabels/urls_tests.go b/openstack/networking/v2/extensions/meteringlabels/urls_tests.go
deleted file mode 100755
index d8c10b8..0000000
--- a/openstack/networking/v2/extensions/meteringlabels/urls_tests.go
+++ /dev/null
@@ -1 +0,0 @@
-package meteringlabels
diff --git a/openstack/networking/v2/extensions/multiple/doc.go b/openstack/networking/v2/extensions/multiple/doc.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/doc.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/multiple/errors.go b/openstack/networking/v2/extensions/multiple/errors.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/errors.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/multiple/requests.go b/openstack/networking/v2/extensions/multiple/requests.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/requests.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/multiple/requests_test.go b/openstack/networking/v2/extensions/multiple/requests_test.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/requests_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/multiple/results.go b/openstack/networking/v2/extensions/multiple/results.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/results.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/multiple/urls.go b/openstack/networking/v2/extensions/multiple/urls.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/urls.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/multiple/urls_tests.go b/openstack/networking/v2/extensions/multiple/urls_tests.go
deleted file mode 100755
index 5d32c92..0000000
--- a/openstack/networking/v2/extensions/multiple/urls_tests.go
+++ /dev/null
@@ -1 +0,0 @@
-package multiple
diff --git a/openstack/networking/v2/extensions/portattrs/doc.go b/openstack/networking/v2/extensions/portattrs/doc.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/doc.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/portattrs/errors.go b/openstack/networking/v2/extensions/portattrs/errors.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/errors.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/portattrs/requests.go b/openstack/networking/v2/extensions/portattrs/requests.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/requests.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/portattrs/requests_test.go b/openstack/networking/v2/extensions/portattrs/requests_test.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/requests_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/portattrs/results.go b/openstack/networking/v2/extensions/portattrs/results.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/results.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/portattrs/urls.go b/openstack/networking/v2/extensions/portattrs/urls.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/urls.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/portattrs/urls_tests.go b/openstack/networking/v2/extensions/portattrs/urls_tests.go
deleted file mode 100755
index 5fa2499..0000000
--- a/openstack/networking/v2/extensions/portattrs/urls_tests.go
+++ /dev/null
@@ -1 +0,0 @@
-package portattrs
diff --git a/openstack/networking/v2/extensions/securitygroups/doc.go b/openstack/networking/v2/extensions/securitygroups/doc.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/doc.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups
diff --git a/openstack/networking/v2/extensions/securitygroups/errors.go b/openstack/networking/v2/extensions/securitygroups/errors.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/errors.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups
diff --git a/openstack/networking/v2/extensions/securitygroups/requests.go b/openstack/networking/v2/extensions/securitygroups/requests.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/requests.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups
diff --git a/openstack/networking/v2/extensions/securitygroups/requests_test.go b/openstack/networking/v2/extensions/securitygroups/requests_test.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/requests_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups
diff --git a/openstack/networking/v2/extensions/securitygroups/results.go b/openstack/networking/v2/extensions/securitygroups/results.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/results.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups
diff --git a/openstack/networking/v2/extensions/securitygroups/urls.go b/openstack/networking/v2/extensions/securitygroups/urls.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/urls.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups
diff --git a/openstack/networking/v2/extensions/securitygroups/urls_tests.go b/openstack/networking/v2/extensions/securitygroups/urls_tests.go
deleted file mode 100755
index 8c2b45b..0000000
--- a/openstack/networking/v2/extensions/securitygroups/urls_tests.go
+++ /dev/null
@@ -1 +0,0 @@
-package securitygroups