8 "github.com/docker/libnetwork/driverapi"
9 "github.com/docker/libnetwork/types"
12 // EndpointInfo provides an interface to retrieve network resources bound to the endpoint.
13 type EndpointInfo interface {
14 // Iface returns InterfaceInfo, go interface that can be used
15 // to get more information on the interface which was assigned to
16 // the endpoint by the driver. This can be used after the
17 // endpoint has been created.
20 // Gateway returns the IPv4 gateway assigned by the driver.
21 // This will only return a valid value if a container has joined the endpoint.
24 // GatewayIPv6 returns the IPv6 gateway assigned by the driver.
25 // This will only return a valid value if a container has joined the endpoint.
28 // StaticRoutes returns the list of static routes configured by the network
29 // driver when the container joins a network
30 StaticRoutes() []*types.StaticRoute
32 // Sandbox returns the attached sandbox if there, nil otherwise.
36 // InterfaceInfo provides an interface to retrieve interface addresses bound to the endpoint.
37 type InterfaceInfo interface {
38 // MacAddress returns the MAC address assigned to the endpoint.
39 MacAddress() net.HardwareAddr
41 // Address returns the IPv4 address assigned to the endpoint.
44 // AddressIPv6 returns the IPv6 address assigned to the endpoint.
45 AddressIPv6() *net.IPNet
47 // LinkLocalAddresses returns the list of link-local (IPv4/IPv6) addresses assigned to the endpoint.
48 LinkLocalAddresses() []*net.IPNet
51 type endpointInterface struct {
63 func (epi *endpointInterface) MarshalJSON() ([]byte, error) {
64 epMap := make(map[string]interface{})
66 epMap["mac"] = epi.mac.String()
69 epMap["addr"] = epi.addr.String()
71 if epi.addrv6 != nil {
72 epMap["addrv6"] = epi.addrv6.String()
74 if len(epi.llAddrs) != 0 {
75 list := make([]string, 0, len(epi.llAddrs))
76 for _, ll := range epi.llAddrs {
77 list = append(list, ll.String())
79 epMap["llAddrs"] = list
81 epMap["srcName"] = epi.srcName
82 epMap["dstPrefix"] = epi.dstPrefix
84 for _, route := range epi.routes {
85 routes = append(routes, route.String())
87 epMap["routes"] = routes
88 epMap["v4PoolID"] = epi.v4PoolID
89 epMap["v6PoolID"] = epi.v6PoolID
90 return json.Marshal(epMap)
93 func (epi *endpointInterface) UnmarshalJSON(b []byte) error {
96 epMap map[string]interface{}
98 if err = json.Unmarshal(b, &epMap); err != nil {
101 if v, ok := epMap["mac"]; ok {
102 if epi.mac, err = net.ParseMAC(v.(string)); err != nil {
103 return types.InternalErrorf("failed to decode endpoint interface mac address after json unmarshal: %s", v.(string))
106 if v, ok := epMap["addr"]; ok {
107 if epi.addr, err = types.ParseCIDR(v.(string)); err != nil {
108 return types.InternalErrorf("failed to decode endpoint interface ipv4 address after json unmarshal: %v", err)
111 if v, ok := epMap["addrv6"]; ok {
112 if epi.addrv6, err = types.ParseCIDR(v.(string)); err != nil {
113 return types.InternalErrorf("failed to decode endpoint interface ipv6 address after json unmarshal: %v", err)
116 if v, ok := epMap["llAddrs"]; ok {
117 list := v.([]interface{})
118 epi.llAddrs = make([]*net.IPNet, 0, len(list))
119 for _, llS := range list {
120 ll, err := types.ParseCIDR(llS.(string))
122 return types.InternalErrorf("failed to decode endpoint interface link-local address (%v) after json unmarshal: %v", llS, err)
124 epi.llAddrs = append(epi.llAddrs, ll)
127 epi.srcName = epMap["srcName"].(string)
128 epi.dstPrefix = epMap["dstPrefix"].(string)
130 rb, _ := json.Marshal(epMap["routes"])
132 json.Unmarshal(rb, &routes)
133 epi.routes = make([]*net.IPNet, 0)
134 for _, route := range routes {
135 ip, ipr, err := net.ParseCIDR(route)
138 epi.routes = append(epi.routes, ipr)
141 epi.v4PoolID = epMap["v4PoolID"].(string)
142 epi.v6PoolID = epMap["v6PoolID"].(string)
147 func (epi *endpointInterface) CopyTo(dstEpi *endpointInterface) error {
148 dstEpi.mac = types.GetMacCopy(epi.mac)
149 dstEpi.addr = types.GetIPNetCopy(epi.addr)
150 dstEpi.addrv6 = types.GetIPNetCopy(epi.addrv6)
151 dstEpi.srcName = epi.srcName
152 dstEpi.dstPrefix = epi.dstPrefix
153 dstEpi.v4PoolID = epi.v4PoolID
154 dstEpi.v6PoolID = epi.v6PoolID
155 if len(epi.llAddrs) != 0 {
156 dstEpi.llAddrs = make([]*net.IPNet, 0, len(epi.llAddrs))
157 for _, ll := range epi.llAddrs {
158 dstEpi.llAddrs = append(dstEpi.llAddrs, ll)
162 for _, route := range epi.routes {
163 dstEpi.routes = append(dstEpi.routes, types.GetIPNetCopy(route))
169 type endpointJoinInfo struct {
172 StaticRoutes []*types.StaticRoute
173 driverTableEntries []*tableEntry
174 disableGatewayService bool
177 type tableEntry struct {
183 func (ep *endpoint) Info() EndpointInfo {
184 if ep.sandboxID != "" {
187 n, err := ep.getNetworkFromStore()
192 ep, err = n.getEndpointFromStore(ep.ID())
197 sb, ok := ep.getSandbox()
199 // endpoint hasn't joined any sandbox.
200 // Just return the endpoint
204 if epi := sb.getEndpoint(ep.ID()); epi != nil {
211 func (ep *endpoint) Iface() InterfaceInfo {
222 func (ep *endpoint) Interface() driverapi.InterfaceInfo {
233 func (epi *endpointInterface) SetMacAddress(mac net.HardwareAddr) error {
235 return types.ForbiddenErrorf("endpoint interface MAC address present (%s). Cannot be modified with %s.", epi.mac, mac)
238 return types.BadRequestErrorf("tried to set nil MAC address to endpoint interface")
240 epi.mac = types.GetMacCopy(mac)
244 func (epi *endpointInterface) SetIPAddress(address *net.IPNet) error {
245 if address.IP == nil {
246 return types.BadRequestErrorf("tried to set nil IP address to endpoint interface")
248 if address.IP.To4() == nil {
249 return setAddress(&epi.addrv6, address)
251 return setAddress(&epi.addr, address)
254 func setAddress(ifaceAddr **net.IPNet, address *net.IPNet) error {
255 if *ifaceAddr != nil {
256 return types.ForbiddenErrorf("endpoint interface IP present (%s). Cannot be modified with (%s).", *ifaceAddr, address)
258 *ifaceAddr = types.GetIPNetCopy(address)
262 func (epi *endpointInterface) MacAddress() net.HardwareAddr {
263 return types.GetMacCopy(epi.mac)
266 func (epi *endpointInterface) Address() *net.IPNet {
267 return types.GetIPNetCopy(epi.addr)
270 func (epi *endpointInterface) AddressIPv6() *net.IPNet {
271 return types.GetIPNetCopy(epi.addrv6)
274 func (epi *endpointInterface) LinkLocalAddresses() []*net.IPNet {
278 func (epi *endpointInterface) SetNames(srcName string, dstPrefix string) error {
279 epi.srcName = srcName
280 epi.dstPrefix = dstPrefix
284 func (ep *endpoint) InterfaceName() driverapi.InterfaceNameInfo {
295 func (ep *endpoint) AddStaticRoute(destination *net.IPNet, routeType int, nextHop net.IP) error {
299 r := types.StaticRoute{Destination: destination, RouteType: routeType, NextHop: nextHop}
301 if routeType == types.NEXTHOP {
302 // If the route specifies a next-hop, then it's loosely routed (i.e. not bound to a particular interface).
303 ep.joinInfo.StaticRoutes = append(ep.joinInfo.StaticRoutes, &r)
305 // If the route doesn't specify a next-hop, it must be a connected route, bound to an interface.
306 ep.iface.routes = append(ep.iface.routes, r.Destination)
311 func (ep *endpoint) AddTableEntry(tableName, key string, value []byte) error {
315 ep.joinInfo.driverTableEntries = append(ep.joinInfo.driverTableEntries, &tableEntry{
316 tableName: tableName,
324 func (ep *endpoint) Sandbox() Sandbox {
325 cnt, ok := ep.getSandbox()
332 func (ep *endpoint) StaticRoutes() []*types.StaticRoute {
336 if ep.joinInfo == nil {
340 return ep.joinInfo.StaticRoutes
343 func (ep *endpoint) Gateway() net.IP {
347 if ep.joinInfo == nil {
351 return types.GetIPCopy(ep.joinInfo.gw)
354 func (ep *endpoint) GatewayIPv6() net.IP {
358 if ep.joinInfo == nil {
362 return types.GetIPCopy(ep.joinInfo.gw6)
365 func (ep *endpoint) SetGateway(gw net.IP) error {
369 ep.joinInfo.gw = types.GetIPCopy(gw)
373 func (ep *endpoint) SetGatewayIPv6(gw6 net.IP) error {
377 ep.joinInfo.gw6 = types.GetIPCopy(gw6)
381 func (ep *endpoint) retrieveFromStore() (*endpoint, error) {
382 n, err := ep.getNetworkFromStore()
384 return nil, fmt.Errorf("could not find network in store to get latest endpoint %s: %v", ep.Name(), err)
386 return n.getEndpointFromStore(ep.ID())
389 func (ep *endpoint) DisableGatewayService() {
393 ep.joinInfo.disableGatewayService = true
396 func (epj *endpointJoinInfo) MarshalJSON() ([]byte, error) {
397 epMap := make(map[string]interface{})
399 epMap["gw"] = epj.gw.String()
402 epMap["gw6"] = epj.gw6.String()
404 epMap["disableGatewayService"] = epj.disableGatewayService
405 epMap["StaticRoutes"] = epj.StaticRoutes
406 return json.Marshal(epMap)
409 func (epj *endpointJoinInfo) UnmarshalJSON(b []byte) error {
412 epMap map[string]interface{}
414 if err = json.Unmarshal(b, &epMap); err != nil {
417 if v, ok := epMap["gw"]; ok {
418 epj.gw6 = net.ParseIP(v.(string))
420 if v, ok := epMap["gw6"]; ok {
421 epj.gw6 = net.ParseIP(v.(string))
423 epj.disableGatewayService = epMap["disableGatewayService"].(bool)
425 var tStaticRoute []types.StaticRoute
426 if v, ok := epMap["StaticRoutes"]; ok {
427 tb, _ := json.Marshal(v)
428 var tStaticRoute []types.StaticRoute
429 json.Unmarshal(tb, &tStaticRoute)
431 var StaticRoutes []*types.StaticRoute
432 for _, r := range tStaticRoute {
433 StaticRoutes = append(StaticRoutes, &r)
435 epj.StaticRoutes = StaticRoutes
440 func (epj *endpointJoinInfo) CopyTo(dstEpj *endpointJoinInfo) error {
441 dstEpj.disableGatewayService = epj.disableGatewayService
442 dstEpj.StaticRoutes = make([]*types.StaticRoute, len(epj.StaticRoutes))
443 copy(dstEpj.StaticRoutes, epj.StaticRoutes)
444 dstEpj.driverTableEntries = make([]*tableEntry, len(epj.driverTableEntries))
445 copy(dstEpj.driverTableEntries, epj.driverTableEntries)
446 dstEpj.gw = types.GetIPCopy(epj.gw)
447 dstEpj.gw = types.GetIPCopy(epj.gw6)