github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/drivers/remote/driver.go (about) 1 package remote 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 8 "github.com/containerd/log" 9 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/discoverapi" 10 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/driverapi" 11 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/drivers/remote/api" 12 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/scope" 13 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/types" 14 "github.com/Prakhar-Agarwal-byte/moby/pkg/plugingetter" 15 "github.com/Prakhar-Agarwal-byte/moby/pkg/plugins" 16 "github.com/pkg/errors" 17 ) 18 19 // remote driver must implement the discover-API. 20 var _ discoverapi.Discover = (*driver)(nil) 21 22 type driver struct { 23 endpoint *plugins.Client 24 networkType string 25 } 26 27 type maybeError interface { 28 GetError() string 29 } 30 31 func newDriver(name string, client *plugins.Client) *driver { 32 return &driver{networkType: name, endpoint: client} 33 } 34 35 // Register makes sure a remote driver is registered with r when a network 36 // driver plugin is activated. 37 func Register(r driverapi.Registerer, pg plugingetter.PluginGetter) error { 38 newPluginHandler := func(name string, client *plugins.Client) { 39 // negotiate driver capability with client 40 d := newDriver(name, client) 41 c, err := d.getCapabilities() 42 if err != nil { 43 log.G(context.TODO()).Errorf("error getting capability for %s due to %v", name, err) 44 return 45 } 46 if err = r.RegisterDriver(name, d, *c); err != nil { 47 log.G(context.TODO()).Errorf("error registering driver for %s due to %v", name, err) 48 } 49 } 50 51 // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins. 52 handleFunc := plugins.Handle 53 if pg != nil { 54 handleFunc = pg.Handle 55 activePlugins := pg.GetAllManagedPluginsByCap(driverapi.NetworkPluginEndpointType) 56 for _, ap := range activePlugins { 57 client, err := getPluginClient(ap) 58 if err != nil { 59 return err 60 } 61 newPluginHandler(ap.Name(), client) 62 } 63 } 64 handleFunc(driverapi.NetworkPluginEndpointType, newPluginHandler) 65 66 return nil 67 } 68 69 func getPluginClient(p plugingetter.CompatPlugin) (*plugins.Client, error) { 70 if v1, ok := p.(plugingetter.PluginWithV1Client); ok { 71 return v1.Client(), nil 72 } 73 74 pa, ok := p.(plugingetter.PluginAddr) 75 if !ok { 76 return nil, errors.Errorf("unknown plugin type %T", p) 77 } 78 79 if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 { 80 return nil, errors.Errorf("unsupported plugin protocol %s", pa.Protocol()) 81 } 82 83 addr := pa.Addr() 84 client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout()) 85 if err != nil { 86 return nil, errors.Wrap(err, "error creating plugin client") 87 } 88 return client, nil 89 } 90 91 // Get capability from client 92 func (d *driver) getCapabilities() (*driverapi.Capability, error) { 93 var capResp api.GetCapabilityResponse 94 if err := d.call("GetCapabilities", nil, &capResp); err != nil { 95 return nil, err 96 } 97 98 c := &driverapi.Capability{} 99 switch capResp.Scope { 100 case scope.Global, scope.Local: 101 c.DataScope = capResp.Scope 102 default: 103 return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope) 104 } 105 106 switch capResp.ConnectivityScope { 107 case scope.Global, scope.Local: 108 c.ConnectivityScope = capResp.ConnectivityScope 109 case "": 110 c.ConnectivityScope = c.DataScope 111 default: 112 return nil, fmt.Errorf("invalid capability: expecting 'local' or 'global', got %s", capResp.Scope) 113 } 114 115 return c, nil 116 } 117 118 // Config is not implemented for remote drivers, since it is assumed 119 // to be supplied to the remote process out-of-band (e.g., as command 120 // line arguments). 121 func (d *driver) Config(option map[string]interface{}) error { 122 return &driverapi.ErrNotImplemented{} 123 } 124 125 func (d *driver) call(methodName string, arg interface{}, retVal maybeError) error { 126 method := driverapi.NetworkPluginEndpointType + "." + methodName 127 err := d.endpoint.Call(method, arg, retVal) 128 if err != nil { 129 return err 130 } 131 if e := retVal.GetError(); e != "" { 132 return fmt.Errorf("remote: %s", e) 133 } 134 return nil 135 } 136 137 func (d *driver) NetworkAllocate(id string, options map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { 138 create := &api.AllocateNetworkRequest{ 139 NetworkID: id, 140 Options: options, 141 IPv4Data: ipV4Data, 142 IPv6Data: ipV6Data, 143 } 144 retVal := api.AllocateNetworkResponse{} 145 err := d.call("AllocateNetwork", create, &retVal) 146 return retVal.Options, err 147 } 148 149 func (d *driver) NetworkFree(id string) error { 150 fr := &api.FreeNetworkRequest{NetworkID: id} 151 return d.call("FreeNetwork", fr, &api.FreeNetworkResponse{}) 152 } 153 154 func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { 155 } 156 157 func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) { 158 return "", nil 159 } 160 161 func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { 162 create := &api.CreateNetworkRequest{ 163 NetworkID: id, 164 Options: options, 165 IPv4Data: ipV4Data, 166 IPv6Data: ipV6Data, 167 } 168 return d.call("CreateNetwork", create, &api.CreateNetworkResponse{}) 169 } 170 171 func (d *driver) DeleteNetwork(nid string) error { 172 return d.call("DeleteNetwork", &api.DeleteNetworkRequest{NetworkID: nid}, &api.DeleteNetworkResponse{}) 173 } 174 175 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { 176 if ifInfo == nil { 177 return errors.New("must not be called with nil InterfaceInfo") 178 } 179 180 reqIface := &api.EndpointInterface{} 181 if ifInfo.Address() != nil { 182 reqIface.Address = ifInfo.Address().String() 183 } 184 if ifInfo.AddressIPv6() != nil { 185 reqIface.AddressIPv6 = ifInfo.AddressIPv6().String() 186 } 187 if ifInfo.MacAddress() != nil { 188 reqIface.MacAddress = ifInfo.MacAddress().String() 189 } 190 191 create := &api.CreateEndpointRequest{ 192 NetworkID: nid, 193 EndpointID: eid, 194 Interface: reqIface, 195 Options: epOptions, 196 } 197 var res api.CreateEndpointResponse 198 if err := d.call("CreateEndpoint", create, &res); err != nil { 199 return err 200 } 201 202 inIface, err := parseInterface(res) 203 if err != nil { 204 return err 205 } 206 if inIface == nil { 207 // Remote driver did not set any field 208 return nil 209 } 210 211 if inIface.MacAddress != nil { 212 if err := ifInfo.SetMacAddress(inIface.MacAddress); err != nil { 213 return errorWithRollback(fmt.Sprintf("driver modified interface MAC address: %v", err), d.DeleteEndpoint(nid, eid)) 214 } 215 } 216 if inIface.Address != nil { 217 if err := ifInfo.SetIPAddress(inIface.Address); err != nil { 218 return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid)) 219 } 220 } 221 if inIface.AddressIPv6 != nil { 222 if err := ifInfo.SetIPAddress(inIface.AddressIPv6); err != nil { 223 return errorWithRollback(fmt.Sprintf("driver modified interface address: %v", err), d.DeleteEndpoint(nid, eid)) 224 } 225 } 226 227 return nil 228 } 229 230 func errorWithRollback(msg string, err error) error { 231 rollback := "rolled back" 232 if err != nil { 233 rollback = "failed to roll back: " + err.Error() 234 } 235 return fmt.Errorf("%s; %s", msg, rollback) 236 } 237 238 func (d *driver) DeleteEndpoint(nid, eid string) error { 239 deleteRequest := &api.DeleteEndpointRequest{ 240 NetworkID: nid, 241 EndpointID: eid, 242 } 243 return d.call("DeleteEndpoint", deleteRequest, &api.DeleteEndpointResponse{}) 244 } 245 246 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 247 info := &api.EndpointInfoRequest{ 248 NetworkID: nid, 249 EndpointID: eid, 250 } 251 var res api.EndpointInfoResponse 252 if err := d.call("EndpointOperInfo", info, &res); err != nil { 253 return nil, err 254 } 255 return res.Value, nil 256 } 257 258 // Join method is invoked when a Sandbox is attached to an endpoint. 259 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 260 join := &api.JoinRequest{ 261 NetworkID: nid, 262 EndpointID: eid, 263 SandboxKey: sboxKey, 264 Options: options, 265 } 266 var ( 267 res api.JoinResponse 268 err error 269 ) 270 if err = d.call("Join", join, &res); err != nil { 271 return err 272 } 273 274 ifaceName := res.InterfaceName 275 if iface := jinfo.InterfaceName(); iface != nil && ifaceName != nil { 276 if err := iface.SetNames(ifaceName.SrcName, ifaceName.DstPrefix); err != nil { 277 return errorWithRollback(fmt.Sprintf("failed to set interface name: %s", err), d.Leave(nid, eid)) 278 } 279 } 280 281 var addr net.IP 282 if res.Gateway != "" { 283 if addr = net.ParseIP(res.Gateway); addr == nil { 284 return fmt.Errorf(`unable to parse Gateway "%s"`, res.Gateway) 285 } 286 if jinfo.SetGateway(addr) != nil { 287 return errorWithRollback(fmt.Sprintf("failed to set gateway: %v", addr), d.Leave(nid, eid)) 288 } 289 } 290 if res.GatewayIPv6 != "" { 291 if addr = net.ParseIP(res.GatewayIPv6); addr == nil { 292 return fmt.Errorf(`unable to parse GatewayIPv6 "%s"`, res.GatewayIPv6) 293 } 294 if jinfo.SetGatewayIPv6(addr) != nil { 295 return errorWithRollback(fmt.Sprintf("failed to set gateway IPv6: %v", addr), d.Leave(nid, eid)) 296 } 297 } 298 if len(res.StaticRoutes) > 0 { 299 routes, err := parseStaticRoutes(res) 300 if err != nil { 301 return err 302 } 303 for _, route := range routes { 304 if jinfo.AddStaticRoute(route.Destination, route.RouteType, route.NextHop) != nil { 305 return errorWithRollback(fmt.Sprintf("failed to set static route: %v", route), d.Leave(nid, eid)) 306 } 307 } 308 } 309 if res.DisableGatewayService { 310 jinfo.DisableGatewayService() 311 } 312 return nil 313 } 314 315 // Leave method is invoked when a Sandbox detaches from an endpoint. 316 func (d *driver) Leave(nid, eid string) error { 317 leave := &api.LeaveRequest{ 318 NetworkID: nid, 319 EndpointID: eid, 320 } 321 return d.call("Leave", leave, &api.LeaveResponse{}) 322 } 323 324 // ProgramExternalConnectivity is invoked to program the rules to allow external connectivity for the endpoint. 325 func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { 326 data := &api.ProgramExternalConnectivityRequest{ 327 NetworkID: nid, 328 EndpointID: eid, 329 Options: options, 330 } 331 err := d.call("ProgramExternalConnectivity", data, &api.ProgramExternalConnectivityResponse{}) 332 if err != nil && plugins.IsNotFound(err) { 333 // It is not mandatory yet to support this method 334 return nil 335 } 336 return err 337 } 338 339 // RevokeExternalConnectivity method is invoked to remove any external connectivity programming related to the endpoint. 340 func (d *driver) RevokeExternalConnectivity(nid, eid string) error { 341 data := &api.RevokeExternalConnectivityRequest{ 342 NetworkID: nid, 343 EndpointID: eid, 344 } 345 err := d.call("RevokeExternalConnectivity", data, &api.RevokeExternalConnectivityResponse{}) 346 if err != nil && plugins.IsNotFound(err) { 347 // It is not mandatory yet to support this method 348 return nil 349 } 350 return err 351 } 352 353 func (d *driver) Type() string { 354 return d.networkType 355 } 356 357 func (d *driver) IsBuiltIn() bool { 358 return false 359 } 360 361 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster 362 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { 363 if dType != discoverapi.NodeDiscovery { 364 return nil 365 } 366 notif := &api.DiscoveryNotification{ 367 DiscoveryType: dType, 368 DiscoveryData: data, 369 } 370 return d.call("DiscoverNew", notif, &api.DiscoveryResponse{}) 371 } 372 373 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster 374 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { 375 if dType != discoverapi.NodeDiscovery { 376 return nil 377 } 378 notif := &api.DiscoveryNotification{ 379 DiscoveryType: dType, 380 DiscoveryData: data, 381 } 382 return d.call("DiscoverDelete", notif, &api.DiscoveryResponse{}) 383 } 384 385 func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) { 386 routes := make([]*types.StaticRoute, len(r.StaticRoutes)) 387 for i, inRoute := range r.StaticRoutes { 388 var err error 389 outRoute := &types.StaticRoute{RouteType: inRoute.RouteType} 390 391 if inRoute.Destination != "" { 392 if outRoute.Destination, err = types.ParseCIDR(inRoute.Destination); err != nil { 393 return nil, err 394 } 395 } 396 397 if inRoute.NextHop != "" { 398 outRoute.NextHop = net.ParseIP(inRoute.NextHop) 399 if outRoute.NextHop == nil { 400 return nil, fmt.Errorf("failed to parse nexthop IP %s", inRoute.NextHop) 401 } 402 } 403 404 routes[i] = outRoute 405 } 406 return routes, nil 407 } 408 409 // parseInterfaces validates all the parameters of an Interface and returns them. 410 func parseInterface(r api.CreateEndpointResponse) (*api.Interface, error) { 411 var outIf *api.Interface 412 413 inIf := r.Interface 414 if inIf != nil { 415 var err error 416 outIf = &api.Interface{} 417 if inIf.Address != "" { 418 if outIf.Address, err = types.ParseCIDR(inIf.Address); err != nil { 419 return nil, err 420 } 421 } 422 if inIf.AddressIPv6 != "" { 423 if outIf.AddressIPv6, err = types.ParseCIDR(inIf.AddressIPv6); err != nil { 424 return nil, err 425 } 426 } 427 if inIf.MacAddress != "" { 428 if outIf.MacAddress, err = net.ParseMAC(inIf.MacAddress); err != nil { 429 return nil, err 430 } 431 } 432 } 433 434 return outIf, nil 435 }