1
2
3 package hcn
4
5 import (
6 "encoding/json"
7 "errors"
8
9 "github.com/Microsoft/go-winio/pkg/guid"
10 "github.com/Microsoft/hcsshim/internal/interop"
11 "github.com/sirupsen/logrus"
12 )
13
14
15 type HostComputeRoute struct {
16 ID string `json:"ID,omitempty"`
17 HostComputeEndpoints []string `json:",omitempty"`
18 Setting []SDNRoutePolicySetting `json:",omitempty"`
19 SchemaVersion SchemaVersion `json:",omitempty"`
20 }
21
22
23 func ListRoutes() ([]HostComputeRoute, error) {
24 hcnQuery := defaultQuery()
25 routes, err := ListRoutesQuery(hcnQuery)
26 if err != nil {
27 return nil, err
28 }
29 return routes, nil
30 }
31
32
33 func ListRoutesQuery(query HostComputeQuery) ([]HostComputeRoute, error) {
34 queryJSON, err := json.Marshal(query)
35 if err != nil {
36 return nil, err
37 }
38
39 routes, err := enumerateRoutes(string(queryJSON))
40 if err != nil {
41 return nil, err
42 }
43 return routes, nil
44 }
45
46
47 func GetRouteByID(routeID string) (*HostComputeRoute, error) {
48 hcnQuery := defaultQuery()
49 mapA := map[string]string{"ID": routeID}
50 filter, err := json.Marshal(mapA)
51 if err != nil {
52 return nil, err
53 }
54 hcnQuery.Filter = string(filter)
55
56 routes, err := ListRoutesQuery(hcnQuery)
57 if err != nil {
58 return nil, err
59 }
60 if len(routes) == 0 {
61 return nil, RouteNotFoundError{RouteId: routeID}
62 }
63 return &routes[0], err
64 }
65
66
67 func (route *HostComputeRoute) Create() (*HostComputeRoute, error) {
68 logrus.Debugf("hcn::HostComputeRoute::Create id=%s", route.ID)
69
70 jsonString, err := json.Marshal(route)
71 if err != nil {
72 return nil, err
73 }
74
75 logrus.Debugf("hcn::HostComputeRoute::Create JSON: %s", jsonString)
76 route, hcnErr := createRoute(string(jsonString))
77 if hcnErr != nil {
78 return nil, hcnErr
79 }
80 return route, nil
81 }
82
83
84 func (route *HostComputeRoute) Delete() error {
85 logrus.Debugf("hcn::HostComputeRoute::Delete id=%s", route.ID)
86
87 existingRoute, _ := GetRouteByID(route.ID)
88
89 if existingRoute != nil {
90 if err := deleteRoute(route.ID); err != nil {
91 return err
92 }
93 }
94
95 return nil
96 }
97
98
99
100 func (route *HostComputeRoute) AddEndpoint(endpoint *HostComputeEndpoint) (*HostComputeRoute, error) {
101 logrus.Debugf("hcn::HostComputeRoute::AddEndpoint route=%s endpoint=%s", route.ID, endpoint.Id)
102
103 err := route.Delete()
104 if err != nil {
105 return nil, err
106 }
107
108
109 route.HostComputeEndpoints = append(route.HostComputeEndpoints, endpoint.Id)
110
111 return route.Create()
112 }
113
114
115
116 func (route *HostComputeRoute) RemoveEndpoint(endpoint *HostComputeEndpoint) (*HostComputeRoute, error) {
117 logrus.Debugf("hcn::HostComputeRoute::RemoveEndpoint route=%s endpoint=%s", route.ID, endpoint.Id)
118
119 err := route.Delete()
120 if err != nil {
121 return nil, err
122 }
123
124
125 i := 0
126 for index, endpointReference := range route.HostComputeEndpoints {
127 if endpointReference == endpoint.Id {
128 i = index
129 break
130 }
131 }
132
133 route.HostComputeEndpoints = append(route.HostComputeEndpoints[0:i], route.HostComputeEndpoints[i+1:]...)
134 return route.Create()
135 }
136
137
138 func AddRoute(endpoints []HostComputeEndpoint, destinationPrefix string, nextHop string, needEncapsulation bool) (*HostComputeRoute, error) {
139 logrus.Debugf("hcn::HostComputeRoute::AddRoute endpointId=%v, destinationPrefix=%v, nextHop=%v, needEncapsulation=%v", endpoints, destinationPrefix, nextHop, needEncapsulation)
140
141 if len(endpoints) <= 0 {
142 return nil, errors.New("missing endpoints")
143 }
144
145 route := &HostComputeRoute{
146 SchemaVersion: V2SchemaVersion(),
147 Setting: []SDNRoutePolicySetting{
148 {
149 DestinationPrefix: destinationPrefix,
150 NextHop: nextHop,
151 NeedEncap: needEncapsulation,
152 },
153 },
154 }
155
156 for _, endpoint := range endpoints {
157 route.HostComputeEndpoints = append(route.HostComputeEndpoints, endpoint.Id)
158 }
159
160 return route.Create()
161 }
162
163 func enumerateRoutes(query string) ([]HostComputeRoute, error) {
164
165 var (
166 resultBuffer *uint16
167 routeBuffer *uint16
168 )
169 hr := hcnEnumerateRoutes(query, &routeBuffer, &resultBuffer)
170 if err := checkForErrors("hcnEnumerateRoutes", hr, resultBuffer); err != nil {
171 return nil, err
172 }
173
174 routes := interop.ConvertAndFreeCoTaskMemString(routeBuffer)
175 var routeIds []guid.GUID
176 if err := json.Unmarshal([]byte(routes), &routeIds); err != nil {
177 return nil, err
178 }
179
180 var outputRoutes []HostComputeRoute
181 for _, routeGUID := range routeIds {
182 route, err := getRoute(routeGUID, query)
183 if err != nil {
184 return nil, err
185 }
186 outputRoutes = append(outputRoutes, *route)
187 }
188 return outputRoutes, nil
189 }
190
191 func getRoute(routeGUID guid.GUID, query string) (*HostComputeRoute, error) {
192
193 var (
194 routeHandle hcnRoute
195 resultBuffer *uint16
196 propertiesBuffer *uint16
197 )
198 hr := hcnOpenRoute(&routeGUID, &routeHandle, &resultBuffer)
199 if err := checkForErrors("hcnOpenRoute", hr, resultBuffer); err != nil {
200 return nil, err
201 }
202
203 hr = hcnQueryRouteProperties(routeHandle, query, &propertiesBuffer, &resultBuffer)
204 if err := checkForErrors("hcnQueryRouteProperties", hr, resultBuffer); err != nil {
205 return nil, err
206 }
207 properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
208
209 hr = hcnCloseRoute(routeHandle)
210 if err := checkForErrors("hcnCloseRoute", hr, nil); err != nil {
211 return nil, err
212 }
213
214 var outputRoute HostComputeRoute
215 if err := json.Unmarshal([]byte(properties), &outputRoute); err != nil {
216 return nil, err
217 }
218 return &outputRoute, nil
219 }
220
221 func createRoute(settings string) (*HostComputeRoute, error) {
222
223 var (
224 routeHandle hcnRoute
225 resultBuffer *uint16
226 propertiesBuffer *uint16
227 )
228 routeGUID := guid.GUID{}
229 hr := hcnCreateRoute(&routeGUID, settings, &routeHandle, &resultBuffer)
230 if err := checkForErrors("hcnCreateRoute", hr, resultBuffer); err != nil {
231 return nil, err
232 }
233
234 hcnQuery := defaultQuery()
235 query, err := json.Marshal(hcnQuery)
236 if err != nil {
237 return nil, err
238 }
239 hr = hcnQueryRouteProperties(routeHandle, string(query), &propertiesBuffer, &resultBuffer)
240 if err := checkForErrors("hcnQueryRouteProperties", hr, resultBuffer); err != nil {
241 return nil, err
242 }
243 properties := interop.ConvertAndFreeCoTaskMemString(propertiesBuffer)
244
245 hr = hcnCloseRoute(routeHandle)
246 if err := checkForErrors("hcnCloseRoute", hr, nil); err != nil {
247 return nil, err
248 }
249
250 var outputRoute HostComputeRoute
251 if err := json.Unmarshal([]byte(properties), &outputRoute); err != nil {
252 return nil, err
253 }
254 return &outputRoute, nil
255 }
256
257 func deleteRoute(routeID string) error {
258 routeGUID, err := guid.FromString(routeID)
259 if err != nil {
260 return errInvalidRouteID
261 }
262 var resultBuffer *uint16
263 hr := hcnDeleteRoute(&routeGUID, &resultBuffer)
264 if err := checkForErrors("hcnDeleteRoute", hr, resultBuffer); err != nil {
265 return err
266 }
267 return nil
268 }
269
View as plain text