Repository: scionproto/scion
Pull request #3685 (2020-03-10 12:54:31)

colibri: add ctrl structs for requests
Adding the corresponding `lib/ctrl/colibri_mgmt` structs for (de)serialization of the capnp messages.
Added only those types needed for `colibri_mgmt.Request`. The `Response` type is still pending.
Added UT to check correct (de)serialization.

After this, still pending before the colibri store:
- Finish the `Response` type.
- Application level types, that include fields from capnp messages and colibri HbH extension.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/scionproto/scion/3685)
<!-- Reviewable:end -->



Patch:
diff --git a/go/lib/ctrl/colibri_mgmt/BUILD.bazel b/go/lib/ctrl/colibri_mgmt/BUILD.bazel
new file mode 100644
index 000000000..b6007534e
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/BUILD.bazel
@@ -0,0 +1,31 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
+
+go_library(
+    name = "go_default_library",
+    srcs = [
+        "colibri_mgmt.go",
+        "e2e_cleanup.go",
+        "e2e_setup.go",
+        "request.go",
+        "reservation_ids.go",
+        "segment_cleanup.go",
+        "segment_index_confirmation.go",
+        "segment_setup.go",
+        "segment_teardown.go",
+        "segment_teles_setup.go",
+    ],
+    importpath = "github.com/scionproto/scion/go/lib/ctrl/colibri_mgmt",
+    visibility = ["//visibility:public"],
+    deps = ["//go/proto:go_default_library"],
+)
+
+go_test(
+    name = "go_default_test",
+    srcs = ["colibri_mgmt_test.go"],
+    embed = [":go_default_library"],
+    deps = [
+        "//go/lib/xtest:go_default_library",
+        "//go/proto:go_default_library",
+        "@com_github_stretchr_testify//require:go_default_library",
+    ],
+)
diff --git a/go/lib/ctrl/colibri_mgmt/colibri_mgmt.go b/go/lib/ctrl/colibri_mgmt/colibri_mgmt.go
new file mode 100644
index 000000000..2253f6212
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/colibri_mgmt.go
@@ -0,0 +1,64 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"strings"
+
+	"github.com/scionproto/scion/go/proto"
+)
+
+type Response struct {
+	// TODO(juagargi)
+}
+
+type ColibriRequestPayload struct {
+	Which    proto.ColibriRequestPayload_Which
+	Request  *Request
+	Response *Response
+}
+
+var _ proto.Cerealizable = (*ColibriRequestPayload)(nil)
+
+func (p *ColibriRequestPayload) ProtoId() proto.ProtoIdType {
+	return proto.ColibriRequestPayload_TypeID
+}
+
+func (p *ColibriRequestPayload) String() string {
+	strs := make([]string, 1, 2)
+	strs[0] = "ColibriRequestPayload:"
+	switch p.Which {
+	case proto.ColibriRequestPayload_Which_request:
+		strs = append(strs, "Request")
+	case proto.ColibriRequestPayload_Which_response:
+		strs = append(strs, "Response")
+	default:
+		strs = append(strs, "Unknown subtype")
+	}
+	return strings.Join(strs, " ")
+}
+
+func (p *ColibriRequestPayload) PackRoot() ([]byte, error) {
+	return proto.PackRoot(p)
+}
+
+func NewFromRaw(b []byte) (*ColibriRequestPayload, error) {
+	pld := &ColibriRequestPayload{}
+	err := proto.ParseFromRaw(pld, b)
+	if err != nil {
+		return nil, err
+	}
+	return pld, nil
+}
diff --git a/go/lib/ctrl/colibri_mgmt/request.go b/go/lib/ctrl/colibri_mgmt/request.go
new file mode 100644
index 000000000..dc44fefe5
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/request.go
@@ -0,0 +1,37 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type Request struct {
+	Which                    proto.Request_Which
+	SegmentSetup             *SegmentSetup
+	SegmentRenewal           *SegmentSetup
+	SegmentTelesSetup        *SegmentTelesSetup
+	SegmentTelesRenewal      *SegmentTelesSetup
+	SegmentTeardown          *SegmentTeardownReq
+	SegmentIndexConfirmation *SegmentIndexConfirmation
+	SegmentCleanup           *SegmentCleanup
+	E2ESetup                 *E2ESetup   `capnp:"e2eSetup"`
+	E2ERenewal               *E2ESetup   `capnp:"e2eRenewal"`
+	E2ECleanup               *E2ECleanup `capnp:"e2eCleanup"`
+}
+
+func (r *Request) ProtoId() proto.ProtoIdType {
+	return proto.Request_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/reservation_ids.go b/go/lib/ctrl/colibri_mgmt/reservation_ids.go
new file mode 100644
index 000000000..28ab49e43
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/reservation_ids.go
@@ -0,0 +1,37 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type SegmentReservationID struct {
+	ASID   []byte `capnp:"asid"`
+	Suffix []byte // 4 bytes long
+}
+
+func (id *SegmentReservationID) ProtoId() proto.ProtoIdType {
+	return proto.SegmentReservationID_TypeID
+}
+
+type E2EReservationID struct {
+	ASID   []byte `capnp:"asid"`
+	Suffix []byte // 16 bytes long
+}
+
+func (id *E2EReservationID) ProtoId() proto.ProtoIdType {
+	return proto.E2EReservationID_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/segment_cleanup.go b/go/lib/ctrl/colibri_mgmt/segment_cleanup.go
new file mode 100644
index 000000000..74707a462
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/segment_cleanup.go
@@ -0,0 +1,28 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type SegmentCleanup struct {
+	ID    *SegmentReservationID `capnp:"id"`
+	Index uint8
+}
+
+func (s *SegmentCleanup) ProtoId() proto.ProtoIdType {
+	return proto.SegmentCleanupData_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/segment_index_confirmation.go b/go/lib/ctrl/colibri_mgmt/segment_index_confirmation.go
new file mode 100644
index 000000000..18e9031dc
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/segment_index_confirmation.go
@@ -0,0 +1,28 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type SegmentIndexConfirmation struct {
+	Index uint8
+	State proto.ReservationIndexState
+}
+
+func (s *SegmentIndexConfirmation) ProtoId() proto.ProtoIdType {
+	return proto.SegmentIndexConfirmationData_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/segment_setup.go b/go/lib/ctrl/colibri_mgmt/segment_setup.go
new file mode 100644
index 000000000..4fb18fe5e
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/segment_setup.go
@@ -0,0 +1,50 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type SegmentSetup struct {
+	MinBW           uint8
+	MaxBW           uint8
+	SplitCls        uint8
+	StartProps      PathEndProps
+	EndProps        PathEndProps
+	AllocationTrail []*AllocationBeads
+}
+
+func (s *SegmentSetup) ProtoId() proto.ProtoIdType {
+	return proto.SegmentSetupReqData_TypeID
+}
+
+type PathEndProps struct {
+	Local    bool
+	Transfer bool
+}
+
+func (pep *PathEndProps) ProtoId() proto.ProtoIdType {
+	return proto.PathEndProps_TypeID
+}
+
+type AllocationBeads struct {
+	AllocBW uint8
+	MaxBW   uint8
+}
+
+func (ab *AllocationBeads) ProtoId() proto.ProtoIdType {
+	return proto.AllocationBeads_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/segment_teardown.go b/go/lib/ctrl/colibri_mgmt/segment_teardown.go
new file mode 100644
index 000000000..3ed714bf8
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/segment_teardown.go
@@ -0,0 +1,25 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type SegmentTeardownReq struct{}
+
+func (s *SegmentTeardownReq) ProtoId() proto.ProtoIdType {
+	return proto.SegmentTeardownReqData_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/segment_teles_setup.go b/go/lib/ctrl/colibri_mgmt/segment_teles_setup.go
new file mode 100644
index 000000000..125c9edb2
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/segment_teles_setup.go
@@ -0,0 +1,28 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type SegmentTelesSetup struct {
+	Setup  *SegmentSetup
+	BaseID *SegmentReservationID
+}
+
+func (sts *SegmentTelesSetup) ProtoId() proto.ProtoIdType {
+	return proto.SegmentTelesSetupData_TypeID
+}
diff --git a/go/proto/colibri.capnp.go b/go/proto/colibri.capnp.go
index ce14ef77f..50f85995c 100644
--- a/go/proto/colibri.capnp.go
+++ b/go/proto/colibri.capnp.go
@@ -530,17 +530,20 @@ type SegmentSetupResData struct{ capnp.Struct }
 type SegmentSetupResData_Which uint16
 
 const (
-	SegmentSetupResData_Which_failure SegmentSetupResData_Which = 0
-	SegmentSetupResData_Which_token   SegmentSetupResData_Which = 1
+	SegmentSetupResData_Which_unset   SegmentSetupResData_Which = 0
+	SegmentSetupResData_Which_failure SegmentSetupResData_Which = 1
+	SegmentSetupResData_Which_token   SegmentSetupResData_Which = 2
 )
 
 func (w SegmentSetupResData_Which) String() string {
-	const s = "failuretoken"
+	const s = "unsetfailuretoken"
 	switch w {
+	case SegmentSetupResData_Which_unset:
+		return s[0:5]
 	case SegmentSetupResData_Which_failure:
-		return s[0:7]
+		return s[5:12]
 	case SegmentSetupResData_Which_token:
-		return s[7:12]
+		return s[12:17]
 
 	}
 	return "SegmentSetupResData_Which(" + strconv.FormatUint(uint64(w), 10) + ")"
@@ -572,8 +575,13 @@ func (s SegmentSetupResData) String() string {
 func (s SegmentSetupResData) Which() SegmentSetupResData_Which {
 	return SegmentSetupResData_Which(s.Struct.Uint16(0))
 }
+func (s SegmentSetupResData) SetUnset() {
+	s.Struct.SetUint16(0, 0)
+
+}
+
 func (s SegmentSetupResData) Failure() (SegmentSetupReqData, error) {
-	if s.Struct.Uint16(0) != 0 {
+	if s.Struct.Uint16(0) != 1 {
 		panic("Which() != failure")
 	}
 	p, err := s.Struct.Ptr(0)
@@ -581,7 +589,7 @@ func (s SegmentSetupResData) Failure() (SegmentSetupReqData, error) {
 }
 
 func (s SegmentSetupResData) HasFailure() bool {
-	if s.Struct.Uint16(0) != 0 {
+	if s.Struct.Uint16(0) != 1 {
 		return false
 	}
 	p, err := s.Struct.Ptr(0)
@@ -589,14 +597,14 @@ func (s SegmentSetupResData) HasFailure() bool {
 }
 
 func (s SegmentSetupResData) SetFailure(v SegmentSetupReqData) error {
-	s.Struct.SetUint16(0, 0)
+	s.Struct.SetUint16(0, 1)
 	return s.Struct.SetPtr(0, v.Struct.ToPtr())
 }
 
 // NewFailure sets the failure field to a newly
 // allocated SegmentSetupReqData struct, preferring placement in s's segment.
 func (s SegmentSetupResData) NewFailure() (SegmentSetupReqData, error) {
-	s.Struct.SetUint16(0, 0)
+	s.Struct.SetUint16(0, 1)
 	ss, err := NewSegmentSetupReqData(s.Struct.Segment())
 	if err != nil {
 		return SegmentSetupReqData{}, err
@@ -606,7 +614,7 @@ func (s SegmentSetupResData) NewFailure() (SegmentSetupReqData, error) {
 }
 
 func (s SegmentSetupResData) Token() ([]byte, error) {
-	if s.Struct.Uint16(0) != 1 {
+	if s.Struct.Uint16(0) != 2 {
 		panic("Which() != token")
 	}
 	p, err := s.Struct.Ptr(0)
@@ -614,7 +622,7 @@ func (s SegmentSetupResData) Token() ([]byte, error) {
 }
 
 func (s SegmentSetupResData) HasToken() bool {
-	if s.Struct.Uint16(0) != 1 {
+	if s.Struct.Uint16(0) != 2 {
 		return false
 	}
 	p, err := s.Struct.Ptr(0)
@@ -622,7 +630,7 @@ func (s SegmentSetupResData) HasToken() bool {
 }
 
 func (s SegmentSetupResData) SetToken(v []byte) error {
-	s.Struct.SetUint16(0, 1)
+	s.Struct.SetUint16(0, 2)
 	return s.Struct.SetData(0, v)
 }
 
@@ -1060,17 +1068,20 @@ type E2ESetupData_failure E2ESetupData
 type E2ESetupData_Which uint16
 
 const (
-	E2ESetupData_Which_success E2ESetupData_Which = 0
-	E2ESetupData_Which_failure E2ESetupData_Which = 1
+	E2ESetupData_Which_unset   E2ESetupData_Which = 0
+	E2ESetupData_Which_success E2ESetupData_Which = 1
+	E2ESetupData_Which_failure E2ESetupData_Which = 2
 )
 
 func (w E2ESetupData_Which) String() string {
-	const s = "successfailure"
+	const s = "unsetsuccessfailure"
 	switch w {
+	case E2ESetupData_Which_unset:
+		return s[0:5]
 	case E2ESetupData_Which_success:
-		return s[0:7]
+		return s[5:12]
 	case E2ESetupData_Which_failure:
-		return s[7:14]
+		return s[12:19]
 
 	}
 	return "E2ESetupData_Which(" + strconv.FormatUint(uint64(w), 10) + ")"
@@ -1102,10 +1113,15 @@ func (s E2ESetupData) String() string {
 func (s E2ESetupData) Which() E2ESetupData_Which {
 	return E2ESetupData_Which(s.Struct.Uint16(0))
 }
+func (s E2ESetupData) SetUnset() {
+	s.Struct.SetUint16(0, 0)
+
+}
+
 func (s E2ESetupData) Success() E2ESetupData_success { return E2ESetupData_success(s) }
 
 func (s E2ESetupData) SetSuccess() {
-	s.Struct.SetUint16(0, 0)
+	s.Struct.SetUint16(0, 1)
 }
 
 func (s E2ESetupData_success) ReservationID() (E2EReservationID, error) {
@@ -1150,7 +1166,7 @@ func (s E2ESetupData_success) SetToken(v []byte) error {
 func (s E2ESetupData) Failure() E2ESetupData_failure { return E2ESetupData_failure(s) }
 
 func (s E2ESetupData) SetFailure() {
-	s.Struct.SetUint16(0, 1)
+	s.Struct.SetUint16(0, 2)
 }
 
 func (s E2ESetupData_failure) ErrorCode() uint8 {
@@ -2464,124 +2480,126 @@ func (p ColibriRequestPayload_Promise) Response() Response_Promise {
 	return Response_Promise{Pipeline: p.Pipeline.GetPipeline(0)}
 }
 
-const schema_a3bf9fed859570f0 = "x\xda\xd4X}\x8cTW\x15?\xe7\xde\xd9\xf9\x80\x9d" +
-	"\x9d\x19\xde4\x05L\x1d!\xd2,\x84\xf2\xb1\x83\x1f " +
-	"ft?\x14\x90\xea\xbc\x9d5 B\xe4u\xe6.<" +
-	"\x9dyo\xf6\xbd\xb7]0\xc5-\xc8&6\x18\xd1\xa6" +
-	"\x9a\xfa\x87\x0a\x95\xc6\xa2k\xfa\x91\x92\x94\x06\xd4\x9a\x12" +
-	"\xb0\xa9\x1ac\xb5Z%\xb6\x89\xa4\x89\x88\x81&\xa5n" +
-	"qy\xe6\xdc\x99yo>\xb3\xfb\x87\xff\xf8\x1f{\x7f" +
-	"\xbf\xb9\xf7\xdc\xf3\xfb\x9ds\xeec\xdd\xf5\xc0\xc7\xd8\xfa" +
-	"\xae\xe3A\x00u{W\xd0\xbdzf\xcd\xf2\xf3\x1b_" +
-	"?\x0c\xea{\x10\xdd\xdf:{\xd2_\xdd\x9d\xbb\x0aw" +
-	"\xb0\x10\x02\xa4\xef\xe1K\x11P\xf9\x00\x7f\x12\xd0=:" +
-	"\xb3}\xf7O~\xf9\xc7c\xa0\xf6 \xba\xd7\xcb\xdf\x9e" +
-	"\xba\xf6\x83\x9f\xff\x10\x02!\x80\xf4\x15\xbe\x0a\x95\xb7y" +
-	"\x08@\xb9\xc13\x80\xee\x99\xdbo\xfe\xe9\xadK\xff\xfa" +
-	"\x06$z\xea\xb8]\x8c\xc8w\x04\x96\xa2\xb2\x82~\xa7" +
-	",\x0bL\x00\xba\xaf\x8e\x9e\xff\xb4\xb5\xf7\x9f\xdfi\"" +
-	"#1\x0e\x05\xfe\xa1<$\xb9S\x01\xda\xf8+\xbdW" +
-	"O\xfd\xcc)=\xd6\x14E\x17\x9d\x9d>\x1dX\x84\xca" +
-	"Y\x19\xd1\x99\xc0\x0e\x04t\xf7_X\xf8\xf9k\x9f\xfa" +
-	"\xc8\xe3\x8d[K\xc6\xb2\xe0*T\xd6\x07C\xc0\xdd\xe7" +
-	"{\xff~\xec\xa3O\xe6N\xb7\x8b6\x1a\\\x8e\xca]" +
-	"A\x8a`I\x90\xa2}|\xed\x9a\x8b#\xea\x86\x1f7" +
-	"E0\x84!\x06\x90\x1e\x0f.BeJ\xd2\x0fK\xfa" +
-	"o\xc6\xf2\x7f\xb99\xb5\xef\x99\xf6\x19\xbe\x1c\x94\x19\xbe" +
-	"\"\xa9w_\xdes|\x91;}\xaeM\x86\x95\xa1\xd0" +
-	"k\x8a\x1a\xa2\x7f\xdd\x1b\"\xee\xf4L\xef;\xbb?s" +
-	"\xf7\x8b\xed\xd4\xf8ih\x17*/H\xf2y\"\xcf\xc6" +
-	"\x1e\xfe\xd1'_\x1e\xbb\xd0\x120G\x96^\x12^\x8e" +
-	"\xca\xca0\x91W\x84\xdf\x04tO\xce\x8c\\?~\xe7" +
-	"7/B\xa2\x87\xf9l\xc04F\x96\xa3\x92\x88\x103" +
-	"\x1a\xf9\x10\xa0\xbb\xf9\xa5\x8d\xef\xcd\x94\xae\xfc\xbeY\x0b" +
-	"\x12.\x9d\x88,@e\x99d\xdf\x15\x99\x00\xbc\xd5\x7f" +
-	"\xa3\xef\x83\xb7\x8e\xfd\xa1\xcd\xdd\x0eF\xdeR\xa6$\xf3" +
-	"01\xddC;\xaf\xfdy\xed\xda\x8b\xaf\xb7fx!" +
-	"\x80r9\xf2\xbcr\x85\xd8\xe97\"\x7fc\x80\xee\xa0" +
-	"u\xe9\xaf\xd3_(\xbd\xd1\x9e\x9e\x88>\xa3,\x89J" +
-	"\xdfEM\xa2{\x124\xd1\x19\xe9\xa7\\\x88\xbd\xa6\xfc" +
-	".F\xb1\xfc:F\xb1\x1c]|\xe7\xf7\x8f\xbc\xba\xec" +
-	"f\x1bk(7b\xef*\xb3\x92;#\xb9y\xb3\xa8" +
-	"\xdfg\xe9kx^+\x1b\xe5MC}C9\xe1\x8c" +
-	"\x97\x075G[3\xaa\xe9\xc5qn\x09\xb5\x9b\x07\xe2" +
-	",\x89\x0c 14\x0c\xa0\x0erT\xb3\x0c\x11\x93\xc8" +
-	"\x01\x12\xf7\xd2\xdav\x8e\xeaN\x86\x09\x86I\x0c\x00$" +
-	">\xbb\x09@\xcdrT\x8b\x0c]aY\xa65`\x16" +
-	"\x00\x05\x06\x81a\x10\xd0\xd5\x8dQ\xf3\x13\xba(\x02\x16" +
-	"0\x0a\x0c\xa3\x80\x99\x92v\xa0\x7f\x87\x8d=\x80Y\x8e" +
-	"\x92\xd9\xd3\x1acN\xec+\x09\xc3\x19\x11\x9aU0'" +
-	"\x8caa\xc7(\xdc,\xa2\x1a\xe0\x01\x80\x00\x02$\xa2" +
-	"\x14S7Guq\x87\xe3\xdbo:,la\xdd\xaf" +
-	"9\xbai\xf0\xad\x83\xb4e\xd8\xdbr\xe5*\x00\xf5\xfd" +
-	"\x1c\xd5u\x0c\x13twZ\xbc\x87\xae\xd9\xcbQ\xdd\xc0" +
-	"0\xa6\xd9\xba\x7f\x17{|tT?P\xfb\xd3;\x8f" +
-	"y\x89\x1e(\x0a\xcd\x18/\xb7\x0b\xde\xaa\x0b\xde\xaa\x86" +
-	"\x04)\xdd4\xb6\x0eb\xdc\xd7\x17\x10\xe3\x1d\xaf\"u" +
-	"\x1c\x16c\x83\x9a\x83r\xff\xc5\xde\xfe\xdf\xed\x03P\x1f" +
-	"\xe1\xa8\x9e\xa8\xbb\xc9\xf7h\xf1Q\x8e\xea)R\xb1*" +
-	"\xf7\xc9m\x00\xea\x09\x8e\xea4C\xe4\x15\xb9O\xef\x02" +
-	"P\x9f\xe0\xa8>\xcb0\x11\xa8\xca\xfd4\x11\x9f\xe2\xa8" +
-	"\x9ec\x98\xe8bI\xec\x02H\x9c=\x02\xa0>\xc7Q" +
-	"}\x85a\xaa\xa4\x1b\xfd;j\xe9OI\xa5=1\xec" +
-	"rQw\x06\x8a6\x00\xf8k\x8ef9Y\xcb\x04^" +
-	"\xb61\xee7\x9a\xea\xa5\x85Q\xc8ZfY\xfe\xa4\x15" +
-	"\xd5\x8aE3\xaf9:\x9a\xc6\x88\xa5\xe9E\xa8y*" +
-	"^\xabi\xc0yyk\xac&OGfQ\xd8\x95\x92" +
-	"\x09Uu\xacsL\xdf\x1c\x8eI\xd9\xf4K\x8c\xfb#" +
-	"\xa2\x12\x7f\xe6>\xcd\x16Rko(\xcdGk\xdb\xd3" +
-	":\xcc\x03\xdd\xae[\x09\xa2\xdf\x0f\"\x8a\xb7\xddj\x14" +
-	"}~\x14\x93\xb2\xd0-\xd1\x1aG\xca1\xbf$\x8c\x16" +
-	"\x0f\xb7k\x16\xf6x>/\xb8m\xd7_\xdf\xf2\xcf\xf0" +
-	"\xae\xbf\x9e\x0e^\xcdQ\xfd\xf0|\xbc\xdd!\x80j\x11" +
-	"e5g\xff\x90\xf4\x01/\xdb\xf3I\xfd6\xff\xec\x14" +
-	"\x19\xa4\x88\x08\x0ci\xe8:\x96f\xd8\xa3\xc2\";\xd5" +
-	"\xd6j\xa7\x05\x1ar\xbd\xd5(\x88\x03\x03\xa61\xaa[" +
-	"%\xd9(\x065>?\xe1\xebR\x9e\xd2i\x17\xaf\x1a" +
-	"lGs\x04\xc6\xfc9\x06\x88\xb1\xd6\x84\x0fT\xfe\x1c" +
-	"\x16c\xe3\xc2v\xb2\xda\xc1b\xc8\xd4\x0att\xdc;" +
-	"Z\xa3\xc6\xb7\xb7\xd2w\xa3\xe8V\xe5\xd6\xe9\xec\x02G" +
-	"\xb5\xcc0\xca\xc8\x04T\xdd%\xb2\xc6~\x8e\xaa\xc30" +
-	"\xcag\xddJ}\x8fQ\x96\xca\x1c\xd5\x07\x18\xba\x8e^" +
-	"\x12\xb6\xa3\x95\x00\xcb\x18\x06\x86a\xc0\xd4\xb8a\x0b\x07" +
-	"\x82\x93V%\x0e\x8c\xfb\xe3\xac\xeaRK\xd8e\xd3\xb0" +
-	"E\xa58\xbd\xd9\xd8\xde\xc3u=W\xe66\xe7\x844" +
-	"G\xc8\x84\xca(\x13\xfd\xf4\xc3Dd\x13\xc0dY\x18" +
-	"\x05\xdd\xd8\x97\xd1\xf2\x8e~\xbf\xe8P\x0d\xd5\xc6J\xb6" +
-	"\x04h\x12f\xa9/L;]\xb8^h-\xbaF\xb1" +
-	"\x9aM\xf8\xf1j\xab1\x8dT\xbf\xd0\x0a\xcd>\xec\x9f" +
-	"\xc3\x09\x93\xb2Uu\xec\x8c\xb5\xc3\xb0\x96\xabL%\xb3" +
-	"t\xca\x06\xaf\xc8\x95=\xd8\x07\x90\xdb\x89\x1cs\x05\xac" +
-	"\xabsE\xc3/\x02\xe4\xf6\x12P$\x80\xcdV\xb4W" +
-	"t\xfc2@n?\x01\x0e\x01\xfc?\x15\xf9\x951|" +
-	"\x18 \xe7\x10\xf0 \x01\x81[\xael\xf1\xca!|\x0c" +
-	" \xf7 \x01_'\xa0\xeb]W\xb6y\xe5!<\x02" +
-	"\x90\xfb\x1a\x01\x8f\x10\x10\x9cq\x93\x18\x04P\xbe\x85/" +
-	"\x01\xe4\x1e%\xe0\x14\x01\xa1\x7f\xbbI\xf9B>)\x0f" +
-	"?A\xc04\x01\xe1w\xdc$\x86\x01\x94\xd3\xb8\x0d " +
-	"\xf7\x04\x01\xcf\x12\x10\xb9\xe9&1\x02\xa0<\x8d\xbb\x00" +
-	"rO\x11p\x8e\x80\x05o\xbbI\\\x00\xa0\x9c\x95\xc0" +
-	"s\x04\xbc\x88\x0c\x13\x0b\xe3I\xa47\xd4\x0br\xa7_" +
-	"\xd0\xfa\xcb\xb4\xde\xcd\x93\xd8\x0d\xa0\xfc\x0a\x87\x01r\x97" +
-	"h\xfd\x15d\x9e\x99]\xbb\xdaI!Vm\xc9\xde\x9b" +
-	"\xb9\xea\xda*a\x182\xc2\x10\x13Z\xb13e\x04k" +
-	"C\x01\xcbs\xb1\x86\x85!Bs\xedV\x19FTJ" +
-	"\xde\x07M#g+knJ\xb2\xf0\xbc\x07w#{" +
-	"\x002\x95\x0a\xc1\xb8\xff\x1e\xae\x8d\xd5>!{z\xa5" +
-	"r\xbdw\xa7\x8fR\xc0\x13\xc0e\xc4m`Y{\xc0" +
-	"\xe5\xde\xde7Rm(\xe7\xf3\xa2\xec\x88B}\x8f\xa5" +
-	"\xd1#\x0a[L\xea/\x1d=\x9f\xaa\xf4;Du\xb5" +
-	"o\xf9\x15\xd2\xf2\xef#!W7X~\xa5\xb4|/" +
-	"\x01\x1b\x1a,\xbf^\xban\x1d\x01\x9b\x1b,\xbfQZ" +
-	"~3\x01[\x1a,?$-\xbf\x85\x80\x91\x06\xcb\xab" +
-	"\xd2\xf2Y\x02v7X\xfes\xd2\xf2~\xbdy\x96o" +
-	"\xae7\xcf\xf2c\xd2\xa8e\x02\x1eh\xb0\xfcA\xe9\xec" +
-	"\x03\x04\x1cm\xb0\xfca\x09x\x85\xd8\xd9\xc2M\xd3\xbc" +
-	"\x9d\x85;P\x9a,\xec}l\xcea\xe1\xce<\xdf\xc2" +
-	"\xde\xe7\xed\xff\xa3\x85[_\xf1\xd5\x17\x90\xff\x04\xe8v" +
-	"]\xac\xfb\x84\xa6\x09\xc0\xc8\x9c\x88\xfe\xff\\\xd0Lc" +
-	"\x93\xf2\xc9d\xdb\xb5\xe7W\x9b\xcd\xab\xa31#g\xe3" +
-	"\xff\xf2s\xe4\xbf\x01\x00\x00\xff\xffT\xab\xae\x85"
+const schema_a3bf9fed859570f0 = "x\xda\xd4X}\x8cTW\x15?\xe7\xdd\xf9\xd8Yv" +
+	"vgxc\x8a\x18\x1d\xd9h\xb3\x10>w\xa9\x0aR" +
+	"\xa7\xee\x87\xb2\xc8\xea\xdc\x9d%|\x08)\x8f\x9d\xbb\xe5" +
+	"\xe9\xcc{\xb3\xef\xbd\xe9R\xd3JA\x9aHP\xd1\xa6" +
+	"\xd5\xf6\x0f\x15*\xc4\xa2\x9b\xb45%i\x1bPkJ" +
+	"\xc0\xda\xc4\x18[\xab\x8d\x8d5j\x9a\x8a\x98\xdaD\xea" +
+	"\x16\xe1\x99s\xe7\xcd{\xf3\xc9\xf2\x87\xff\xf4?\xb8\xbf" +
+	"\xdf\xdc\xfb;\xe7\xfc\xce\xb9\xf7\xed\xea\xee\xf0m\xca\x9a" +
+	"\xf0\xd1\x08\x00\xdf\x1c\x8e\xb8\x17O\xaf\xec=\xbb\xee\xb5" +
+	"\x03\xc0\xdf\x87\xe8\xfe\xda\xd95\xf0\x95\x9d\xb9\x8b\xf0\x1e" +
+	"%\x8a\x00\x03+\xd8b\x04Toa3\x80\xee\xa1\xb9" +
+	"\xcd;\x7f\xfc\x8b\xdf\x1d\x01\xde\x8d\xe8\xbeYz\xf0\xbe" +
+	"K\xdf\xff\xd9\x0f \x14\x05\x18x\x90-C\xf5$\x8b" +
+	"\x02\xa8\xc7Y\x06\xd0=}\xed\xf5\xdf\xbfu\xe1\x9f\xdf" +
+	"\x80dw\x0d7\xac\x10\xf9\x1c[\x8c\xeaK\x92\xfc\x1b" +
+	"\xb9\xf3\xcbSg?k\xed\xfe\xc7\xb7\x1b\xc8H\x8c\x15" +
+	"\xa1\xbf\xab\xeb\xe8\x0c\xf5\x96\x10m|{\xef\x9e\xbf|" +
+	"\xe2W\x97\xbf\xd3Z\xf0\xf6\x90\x14\xac\x85\x1e\x03t\xbf" +
+	"\xdcw\xf1\xc4O\x9d\xe2#\x0d\x82\xc3t\xf2@2\xbc" +
+	"\x10\xd5%a\xfa\xe7\xfb\xc3[\x11\xd0\xdd{n\xc1\xe7" +
+	"/}\xe6\xe3'\xebU\xc8\xf0\x0eG\x96\xa1\xfap$" +
+	"\x0a\xcc}\xa6\xef\xafGn},w\xaaU`\xe5H" +
+	"/\xaa\xf7EH\xec\x81\x08\x05vr\xd5\xca\xf3\x13|" +
+	"\xed\x8f\x1a\x14\x8c`\x94\x01\x0c\xbc\x1aY\x88\xea%I" +
+	"\x7f#B\x82o~u\xd7\xd1\x85\xee\xec\x99\x16\x19V" +
+	"\x0fD_Q\xbf\x1e\xa5\x7f\x1d\x8e\xd2\xd6\xb3s}o" +
+	"\xef\xfc\xdc\xcd\xcf\xb5\xaa\xc6\x1b\xd1\x1d\xa8^\x95\xe49" +
+	"\"_\xed\xb9\xff\x87\x9f~a\xfa\\\xb3\x0aT\x06\xb6" +
+	"t\xf4\xa2*:\x88\xacu\xbc\x0e\xe8\x1e\x9f\x9bx\xf3" +
+	"\xe8M\xdf<\x0f\xc9n%`\x03\x0e\xdc\x1a\xebEu" +
+	",F\xcc\xd1\xd8G\x01\xdd\x0d\xcf\xaf\xfb@\xa6\xf8\xb7" +
+	"\xdf6&\x98\x0a70\x16\xebDu\x97do\x8f\xcd" +
+	"\x00^\x19\xfcW\xffG\xae\x1cy\xa9El\xa7co" +
+	"\xa9\xcfJ\xe6Yb\xba\xf7l\xbb\xf4\x87U\xab\xce\xbf" +
+	"\xd6\x9c\xb6\x05\x00\xea{;\x9fQ\x97t\xca\xc2u\xfe" +
+	"I\x01t\x87\xad\x0b\x7f\x9c\xbd\xbd\xf8\xe7\xd6\xf4\xb1\xf8" +
+	"O\xd4-q\xa2\xf3\xb8It\xdf3\x0dt\x85\x8a\xa2" +
+	"b\xe2\x155\x9e -\xb1\x04\xd5\xe4\xd0\xa2\x9b\xbew" +
+	"\xf0\xe5%\x97[\xd4[\xd5\x13\xef\xa8e\xc9\x9dN\x90" +
+	"\xeeI\xb3\xa0\xef\xb1\xf4\x95lR+\x19\xa5\xf5#\xfd" +
+	"#9\xe1\x94K\xc3\x9a\xa3\xad\xb4\xcb\x93\x93\x82\xd96" +
+	"\xef`!\x80\x14\"@r\xa9\x05\xc0\xfb\x18\xf2\xb5\x0a" +
+	"&\x11S\xa8\x00$\xd7\xf4\x03\xf0\xe5\x0c\xf9\xc7\x14t" +
+	"-a\x0b\xebN\xcd\x81\xb4n\x1a\xa3\xc3\x98\x08\xf4\x00" +
+	"b\x020\xed\x98_\x14\x06\xc6A\xc1x\xb3\x82\x9c\xb8" +
+	"\xa3(\x0cgBhV\xde\x9c1\xc6\x85\xddCb\xb2" +
+	"\x88<D2B\xa4\">\x0e\xc0\xbb\x18\xf2E\x0a\xba" +
+	"\xc2\xb2Lk\xc8\xcc\x03\x0a\x8c\x80\x82\x91\xb6\x9b\x8e{" +
+	"\xd2t\xd3`\xa3\xc3\xb4e\x87\xbf\xe5\xd2e\x00\xfcC" +
+	"\x0c\xf9j/0Z\\\xb1>\x88\xb6G\xb3\xf5|U" +
+	"u\xc6.OM\xe9\xfb\x9a\x82P\xfc4\x0e\x15\x84f" +
+	"\x94K\xad\xc4[5\xe2\xe7\xcd\xd6u+4\xa5\xe9\x85" +
+	"2\xb3\x04\xefb\xa1\x84\x92B\x06\x90\x1c\xa1\xdc\x0c3" +
+	"\xe4Y\x05)\x8e\x10@r\x8c\xd663\xe4\xdb\x14L" +
+	"*\x98\xc20@r\x0b\x05\x97e\xc8\x0bm\x92\xa8\x1b" +
+	"S\xe6\xa7tQ\x00\x0c\xe2.j\xfb\x06\xb7\xda\xd8\x0d" +
+	"\x98e(\x99\xddm\xd3-u\x8e\x8b\xe9a\xcdA\x99" +
+	"\x83E~\x0e\x1e&\xc7<\xc0\x90\x1f\xab\xc9\xf6wi" +
+	"\xf1!\x86\xfc\x04\xa9T*\xde:\xbe\x09\x80\x1fc\xc8" +
+	"g\x15DV\x09\xf1\xd4\x0e\x00\xfe(C\xfe\xa4\x82\xc9" +
+	"\x90\x17\xe3\x13D|\x9c!?\xa3`2\xacTb|" +
+	"\xfa \x00\x7f\x8a!\x7fQ\xc1tQ7\x06\xb7V\xa3" +
+	"K\xcbH\xfcX\xedRAw\x86\x0a6\x00\x04k\x8e" +
+	"f9Y\xcb\x04V\xb21\x11\x8c:\xaf0\xc2\xc8g" +
+	"-\xb3$\x7f\xd2\x8cj\x85\x829\xa99:\x9a\xc6\x84" +
+	"\xa5\xe9\x05\xa8\xe6,Q\x9d*\x80\xd7\xc9]\xe0\xff\xe9" +
+	"\xaa\x85\xda2\x0b\xc2\xaeX\"\xeay\xad\xc6\xd5\xfd\xf3" +
+	"\xb8:m\xd3/1\x11\xdc<\x15\xfd\x99=\x9a-\xa4" +
+	"\x1f\xfdk\xb1\xb5\x1f\xebkm\xfb\xb5\xeeb\xa1.\xd7" +
+	"\x95\"FH\xc4m\x0c\xf9f\x05\xe3x\xcd\xad\xa8\x18" +
+	"\x1d\x0c|\x1aW\xae\xba\x95r\x8f\x11w#C>\xa1" +
+	"`\xbal\xd8\xc2\x81\xc8~isK4\xabl3J" +
+	"\xbc.\xccj\xce\xde\x11Y$V\xb2o$/\x9b\x82" +
+	"1\x96\xa6\xea\x15\x10AA\xbah\x1dK3\xec)a" +
+	"Q\xad\xabk\xd5\xd3Bu\x89\x185\xf2b\xdf\x90i" +
+	"L\xe9VQN\x9aa\x8d\xddXU\xfak\xaa\xa2\xd3" +
+	".\xbeUmGs\x04\xf6\x04\xd7\x1c \xf64\x97b" +
+	"\xa8\xf2\xdfq1]\x16\xb6\x93\xd5\xee*DM-O" +
+	"G'\xfc\xa35\x9a\x04\xbb+M\x1fG\xd7\xab\x85N" +
+	"g\xe7\x19\xf2\x12\xd5\xe2\x9aW\x8b\"Uh/C\xee" +
+	"(\x18gT!j\xbei\xcaR\x89!\xbf[A\xd7" +
+	"\xd1\x8b\xc2v\xb4\"`\x09;@\xc1\x0e\x08\xaafU" +
+	"t`\"\xb8\xed<\x0bY\xc2.\x99\x86-*\x9d\xe3" +
+	"_\x9d\xad\x0dV3\xb4ensNTs\x84L\xa8" +
+	"T\x99\x1c\xa4\x1f&c\xeb\x01\xf6\x97\x84\x91\xd7\x8d;" +
+	"2\xda\xa4\xa3\xdf)\xdaX\xd5\x9b\xcc\xd4U\x00\x0d\x85" +
+	"Y\x1c\x14\xa6U]\x98\x9eo\xee\x88\xfab5\x9a\xf0" +
+	"\x93\xde\x1c0\x8d\xf4\xa0\xd0\xf2\x8d>\x1c\x9c\xc7\x09\xfb" +
+	"\xe5\x1ci;\xb6\xaa\x87a5W\x99Jf\xe9\x94\xb5" +
+	"~\x07\xaa\xbb\xb0\x1f \xb7\x0d\x19\xe6\xf2X\xd3\x84\xaa" +
+	"\x86_\x00\xc8\xed&\xa0\x805}\xa8\xea\xf8%\x80\xdc" +
+	"^\x02\x1c\x02\xd8\x7f+\xe5W\xa7\xf1~\x80\x9cC\xc0" +
+	"\xbd\x04\x84\xae\xb8r\xfe\xaa\xf7\xe0#\x00\xb9{\x09\xf8" +
+	"\x1a\x01\xe1w\\9\x83\xd5\xc3x\x10 \xf7U\x02\x1e" +
+	"  2\xe7\xa60\x02\xa0~\x0b\x9f\x07\xc8=D\xc0" +
+	"\x09\x02\xa2\xffqS\xf2\x01}\\\x1e~\x8c\x80Y\x02" +
+	":\xdevS\xd8\x01\xa0\x9e\xc2M\x00\xb9G\x09x\x92" +
+	"\x80\xd8e7\x851\x00\xf5\x09\xdc\x01\x90{\x9c\x803" +
+	"\x04t\xfe\xdbMa'\x80\xfa\xb4\x04\x9e\"\xe09T" +
+	"0\xb9 \x91Bzb=+w\xfa9\xad\xbf@\xeb" +
+	"],\x85]\x00\xea/q\x1c w\x81\xd6_\xc4`" +
+	"\x04\xb9\xb67\xe6\xa0\xc7\x9b\x97\xfe;\xd9s\xadG\x18" +
+	"\x87\x8c0\xc4\x8cVhO\x99\xc0\xea\xc4\xc6\xd2|\xac" +
+	"qa\x88\xe8|\xbbUn\x0aj%\xff{\xa7\x9e3" +
+	"\xaa4\x0e%\xd9x\xfe{\xbc\x9e=\x04\x99J\x87`" +
+	"\"x.W\xef\xbc~!'}\xa5s\xfdgi\x80" +
+	"\x92\xe0\x19`Rq\x0bX\xf6\x1e0\xb9\xb7\xff\x09U" +
+	"\xbd1''E\xc9\x11\xf9\xda\x19K\x93_\xe47\x9a" +
+	"4_\xdaz>]\x99w\x88|y`\xf9\x0fK\xcb" +
+	"\x7f\x90\x0a\xb9\xbc\xce\xf2K\xa5\xe5\xfb\x08X[g\xf9" +
+	"5\xd2u\xab\x09\xd8Pg\xf9u\xd2\xf2\x1b\x08\xd8X" +
+	"g\xf9\x11i\xf9\x8d\x04L\xd4Y\x9eK\xcbg\x09\xd8" +
+	"Yg\xf9\xed\xd2\xf2A\xbf\xf9\x96o\xec7\xdf\xf2\xd3" +
+	"\xd2\xa8%\x02\xee\xae\xb3\xfc]\xd2\xd9\xfb\x088Tg" +
+	"\xf9\x03\x12\xf0\x1b\xb1\xbd\x85\x1b.\xd3V\x16nCi" +
+	"\xb0\xb0\xff\x819\x8f\x85\xdb\xf3\x02\x0b\xfb\x9f\xb4\xefF" +
+	"\x0b7\x7f\x06xou\xef\x09p\x9dG\x11b\xf0\x87" +
+	"\x0dz\x1b)dL\xac\xf9\xe3Ar\xcd (\xfe\xe5" +
+	"*\xbf\xcdl\xbb\xfa4jq\xb2wof\xe4\xc5\xf9" +
+	"\xff\xfc\xd8\xf9_\x00\x00\x00\xff\xff\x8a0\xb9~"
 
 func init() {
 	schemas.Register(schema_a3bf9fed859570f0,
@@ -2589,11 +2607,11 @@ func init() {
 		0x8bd6c2ab5c4cf984,
 		0x8eeec8f2d8e7feb5,
 		0x96ec60724ebd66d7,
+		0x97f6cb3ee362225f,
 		0xa26d74bea4eb287e,
 		0xa53b4bed5b0bc568,
 		0xa953af3d8be428ba,
 		0xaa345154c72e2fa5,
-		0xb26785f6db6371ce,
 		0xbcacff128f5ddd26,
 		0xc4264f5cf728f9ac,
 		0xc571cc47a792000f,
diff --git a/go/proto/structs.gen.go b/go/proto/structs.gen.go
index dbcaa9a10..b5207e8e5 100644
--- a/go/proto/structs.gen.go
+++ b/go/proto/structs.gen.go
@@ -68,6 +68,12 @@ func NewRootStruct(id ProtoIdType, seg *capnp.Segment) (capnp.Struct, error) {
 			return blank, common.NewBasicError("Error creating new SVCResolutionReply capnp struct", err)
 		}
 		return v.Struct, nil
+	case ColibriRequestPayload_TypeID:
+		v, err := NewRootColibriRequestPayload(seg)
+		if err != nil {
+			return blank, common.NewBasicError("Error creating new ColibriRequestPayload capnp struct", err)
+		}
+		return v.Struct, nil
 	}
 	return blank, common.NewBasicError(
 		"Unsupported capnp struct type (i.e. not listed in go/proto/structs_gen_go.sh:ROOTTYPES)",
@@ -103,3 +109,6 @@ func (s SignedCtrlPld) GetStruct() capnp.Struct {
 func (s SVCResolutionReply) GetStruct() capnp.Struct {
 	return s.Struct
 }
+func (s ColibriRequestPayload) GetStruct() capnp.Struct {
+	return s.Struct
+}
diff --git a/go/proto/structs_gen_go.sh b/go/proto/structs_gen_go.sh
index 4bde56257..aea4d79a6 100755
--- a/go/proto/structs_gen_go.sh
+++ b/go/proto/structs_gen_go.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-ROOTTYPES="ASEntry CtrlPld PathSegment PathSegmentSignedData RevInfo SCIONDMsg SignedBlob SignedCtrlPld SVCResolutionReply"
+ROOTTYPES="ASEntry CtrlPld PathSegment PathSegmentSignedData RevInfo SCIONDMsg SignedBlob SignedCtrlPld SVCResolutionReply ColibriRequestPayload"
 
 cat <<EOF
 // Code generated by go/proto/structs_gen_go.sh; DO NOT EDIT.
diff --git a/proto/colibri.capnp b/proto/colibri.capnp
index a55e83997..0aaca2fee 100644
--- a/proto/colibri.capnp
+++ b/proto/colibri.capnp
@@ -44,8 +44,9 @@ struct SegmentSetupReqData {
 # They travel inside a hop by hop colibri extension.
 struct SegmentSetupResData {
     union{
-        failure @0 :SegmentSetupReqData; # sent along the path in the opposite direction in case of failure
-        token   @1 :Data;                # if successful
+        unset @0 :Void;
+        failure @1 :SegmentSetupReqData; # sent along the path in the opposite direction in case of failure
+        token   @2 :Data;                # if successful
     }
 }
 
@@ -81,14 +82,15 @@ struct SegmentCleanupData {
 # Setup an E2E reservation. Sent in a hop by hop colibri extension through a stitched segment reservation.
 struct E2ESetupData {
     union {
+        unset @0 :Void;
         success :group {
-            reservationID @0 :E2EReservationID;     # 16 byte e2e reservation ID
-            token @1 :Data;
+            reservationID @1 :E2EReservationID;     # 16 byte e2e reservation ID
+            token @2 :Data;
         }
         failure :group {
-            errorCode @2 :UInt8;
-            infoField @3 :Data;
-            maxBWs @4 :List(UInt8);     # max bandwidths granted by the ASes along the path, until failure
+            errorCode @3 :UInt8;
+            infoField @4 :Data;
+            maxBWs @5 :List(UInt8);     # max bandwidths granted by the ASes along the path, until failure
         }
     }
 }


Test patch:
diff --git a/go/lib/ctrl/colibri_mgmt/colibri_mgmt_test.go b/go/lib/ctrl/colibri_mgmt/colibri_mgmt_test.go
new file mode 100644
index 000000000..9759a8edc
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/colibri_mgmt_test.go
@@ -0,0 +1,204 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+
+	"github.com/scionproto/scion/go/lib/ctrl/colibri_mgmt"
+	"github.com/scionproto/scion/go/lib/xtest"
+	"github.com/scionproto/scion/go/proto"
+)
+
+func TestSerializeRoot(t *testing.T) {
+	root := &colibri_mgmt.ColibriRequestPayload{
+		Which: proto.ColibriRequestPayload_Which_unset,
+	}
+	buffer, err := root.PackRoot()
+	require.NoError(t, err)
+	require.Len(t, buffer, 7)
+	otherRoot, err := colibri_mgmt.NewFromRaw(buffer)
+	require.NoError(t, err)
+	require.Equal(t, root.Which, otherRoot.Which)
+	otherBuffer, err := otherRoot.PackRoot()
+	require.NoError(t, err)
+	require.Equal(t, buffer, otherBuffer)
+}
+
+// tests serialization for all types of requests
+func TestSerializeRequest(t *testing.T) {
+	newSegmentSetup := func() *colibri_mgmt.SegmentSetup {
+		return &colibri_mgmt.SegmentSetup{
+			MinBW:    1,
+			MaxBW:    2,
+			SplitCls: 3,
+			StartProps: colibri_mgmt.PathEndProps{
+				Local:    true,
+				Transfer: false,
+			},
+			EndProps: colibri_mgmt.PathEndProps{
+				Local:    false,
+				Transfer: true,
+			},
+			AllocationTrail: []*colibri_mgmt.AllocationBeads{
+				{
+					AllocBW: 5,
+					MaxBW:   6,
+				},
+			},
+		}
+	}
+
+	testCases := map[string]struct {
+		Request *colibri_mgmt.Request
+	}{
+		"setup": {
+			Request: &colibri_mgmt.Request{
+				Which:        proto.Request_Which_segmentSetup,
+				SegmentSetup: newSegmentSetup(),
+			},
+		},
+		"renewal": {
+			Request: &colibri_mgmt.Request{
+				Which:          proto.Request_Which_segmentRenewal,
+				SegmentRenewal: newSegmentSetup(),
+			},
+		},
+		"teles_setup": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_segmentTelesSetup,
+				SegmentTelesSetup: &colibri_mgmt.SegmentTelesSetup{
+					Setup: newSegmentSetup(),
+					BaseID: &colibri_mgmt.SegmentReservationID{
+						ASID:   xtest.MustParseHexString("ff00cafe0001"),
+						Suffix: xtest.MustParseHexString("deadbeef"),
+					},
+				},
+			},
+		},
+		"teles_renewal": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_segmentTelesRenewal,
+				SegmentTelesRenewal: &colibri_mgmt.SegmentTelesSetup{
+					Setup: newSegmentSetup(),
+					BaseID: &colibri_mgmt.SegmentReservationID{
+						ASID:   xtest.MustParseHexString("ff00cafe0001"),
+						Suffix: xtest.MustParseHexString("deadbeef"),
+					},
+				},
+			},
+		},
+		"teardown": {
+			Request: &colibri_mgmt.Request{
+				Which:           proto.Request_Which_segmentTeardown,
+				SegmentTeardown: &colibri_mgmt.SegmentTeardownReq{},
+			},
+		},
+		"index_confirmation": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_segmentIndexConfirmation,
+				SegmentIndexConfirmation: &colibri_mgmt.SegmentIndexConfirmation{
+					Index: 111,
+					State: proto.ReservationIndexState_active,
+				},
+			},
+		},
+		"cleanup": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_segmentCleanup,
+				SegmentCleanup: &colibri_mgmt.SegmentCleanup{
+					ID: &colibri_mgmt.SegmentReservationID{
+						ASID:   xtest.MustParseHexString("ff00cafe0001"),
+						Suffix: xtest.MustParseHexString("deadbeef"),
+					},
+					Index: 17,
+				},
+			},
+		},
+		"e2esetup": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_e2eSetup,
+				E2ESetup: &colibri_mgmt.E2ESetup{
+					Which: proto.E2ESetupData_Which_success,
+					Success: &colibri_mgmt.E2ESetupSuccess{
+						ReservationID: &colibri_mgmt.E2EReservationID{
+							ASID:   xtest.MustParseHexString("ff00cafe0001"),
+							Suffix: xtest.MustParseHexString("0123456789abcdef0123456789abcdef"),
+						},
+						Token: xtest.MustParseHexString("0000"),
+					},
+				},
+			},
+		},
+		"e2esetup_failure": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_e2eSetup,
+				E2ESetup: &colibri_mgmt.E2ESetup{
+					Which: proto.E2ESetupData_Which_failure,
+					Failure: &colibri_mgmt.E2ESetupFailure{
+						ErrorCode: 1,
+						InfoField: xtest.MustParseHexString("fedcba9876543210"),
+						MaxBWs:    []uint8{1, 1, 2, 2},
+					},
+				},
+			},
+		},
+		"e2erenewal": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_e2eRenewal,
+				E2ERenewal: &colibri_mgmt.E2ESetup{
+					Which: proto.E2ESetupData_Which_failure,
+					Failure: &colibri_mgmt.E2ESetupFailure{
+						ErrorCode: 1,
+						InfoField: xtest.MustParseHexString("fedcba9876543210"),
+						MaxBWs:    []uint8{1, 1, 2, 2},
+					},
+				},
+			},
+		},
+		"e2ecleanup": {
+			Request: &colibri_mgmt.Request{
+				Which: proto.Request_Which_e2eCleanup,
+				E2ECleanup: &colibri_mgmt.E2ECleanup{
+					ReservationID: &colibri_mgmt.E2EReservationID{
+						ASID:   xtest.MustParseHexString("ff00cafe0001"),
+						Suffix: xtest.MustParseHexString("0123456789abcdef0123456789abcdef"),
+					},
+				},
+			},
+		},
+	}
+
+	for name, tc := range testCases {
+		name, tc := name, tc
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			root := &colibri_mgmt.ColibriRequestPayload{
+				Which:   proto.ColibriRequestPayload_Which_request,
+				Request: tc.Request,
+			}
+			buffer, err := root.PackRoot()
+			require.NoError(t, err)
+			otherRoot, err := colibri_mgmt.NewFromRaw(buffer)
+			require.NoError(t, err)
+			otherBuffer, err := otherRoot.PackRoot()
+			require.NoError(t, err)
+			require.NoError(t, err)
+			require.Equal(t, buffer, otherBuffer)
+		})
+	}
+}
diff --git a/go/lib/ctrl/colibri_mgmt/e2e_cleanup.go b/go/lib/ctrl/colibri_mgmt/e2e_cleanup.go
new file mode 100644
index 000000000..ee8a7fa51
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/e2e_cleanup.go
@@ -0,0 +1,27 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type E2ECleanup struct {
+	ReservationID *E2EReservationID
+}
+
+func (r *E2ECleanup) ProtoId() proto.ProtoIdType {
+	return proto.E2ECleanupData_TypeID
+}
diff --git a/go/lib/ctrl/colibri_mgmt/e2e_setup.go b/go/lib/ctrl/colibri_mgmt/e2e_setup.go
new file mode 100644
index 000000000..a8d433d39
--- /dev/null
+++ b/go/lib/ctrl/colibri_mgmt/e2e_setup.go
@@ -0,0 +1,40 @@
+// Copyright 2020 ETH Zurich, Anapaya Systems
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package colibri_mgmt
+
+import (
+	"github.com/scionproto/scion/go/proto"
+)
+
+type E2ESetup struct {
+	Which   proto.E2ESetupData_Which
+	Success *E2ESetupSuccess
+	Failure *E2ESetupFailure
+}
+
+func (s *E2ESetup) ProtoId() proto.ProtoIdType {
+	return proto.E2ESetupData_TypeID
+}
+
+type E2ESetupSuccess struct {
+	ReservationID *E2EReservationID
+	Token         []byte
+}
+
+type E2ESetupFailure struct {
+	ErrorCode uint8
+	InfoField []byte
+	MaxBWs    []uint8
+}