Files
moby/daemon/libnetwork/driverapi/ipamdata.go
Cory Snider a90adb6dc1 api/types/network: use netip types as appropriate
And generate the ServiceInfo struct from the Swagger spec.

Signed-off-by: Cory Snider <csnider@mirantis.com>
2025-10-03 21:39:14 +02:00

125 lines
3.4 KiB
Go

package driverapi
import (
"encoding/json"
"fmt"
"maps"
"net"
"net/netip"
"github.com/moby/moby/api/types/network"
"github.com/moby/moby/v2/daemon/internal/netiputil"
"github.com/moby/moby/v2/daemon/libnetwork/types"
"github.com/moby/moby/v2/internal/iterutil"
)
// MarshalJSON encodes IPAMData into json message
func (i *IPAMData) MarshalJSON() ([]byte, error) {
m := map[string]any{}
m["AddressSpace"] = i.AddressSpace
if i.Pool != nil {
m["Pool"] = i.Pool.String()
}
if i.Gateway != nil {
m["Gateway"] = i.Gateway.String()
}
if i.AuxAddresses != nil {
am := make(map[string]string, len(i.AuxAddresses))
for k, v := range i.AuxAddresses {
am[k] = v.String()
}
m["AuxAddresses"] = am
}
return json.Marshal(m)
}
// UnmarshalJSON decodes a json message into IPAMData
func (i *IPAMData) UnmarshalJSON(data []byte) error {
var (
m map[string]any
err error
)
if err := json.Unmarshal(data, &m); err != nil {
return err
}
i.AddressSpace = m["AddressSpace"].(string)
if v, ok := m["Pool"]; ok {
if i.Pool, err = types.ParseCIDR(v.(string)); err != nil {
return err
}
}
if v, ok := m["Gateway"]; ok {
if i.Gateway, err = types.ParseCIDR(v.(string)); err != nil {
return err
}
}
if v, ok := m["AuxAddresses"]; ok {
b, _ := json.Marshal(v) //nolint:errchkjson // FIXME: Error return value of unsafe type `interface{}` is unchecked (errchkjson)
var am map[string]string
if err = json.Unmarshal(b, &am); err != nil {
return err
}
i.AuxAddresses = make(map[string]*net.IPNet, len(am))
for k, v := range am {
if i.AuxAddresses[k], err = types.ParseCIDR(v); err != nil {
return err
}
}
}
return nil
}
// Validate checks whether the IPAMData structure contains congruent data
func (i *IPAMData) Validate() error {
var isV6 bool
if i.Pool == nil {
return types.InvalidParameterErrorf("invalid pool")
}
if i.Gateway == nil {
return types.InvalidParameterErrorf("invalid gateway address")
}
isV6 = i.IsV6()
if isV6 && i.Gateway.IP.To4() != nil || !isV6 && i.Gateway.IP.To4() == nil {
return types.InvalidParameterErrorf("incongruent ip versions for pool and gateway")
}
for k, sip := range i.AuxAddresses {
if isV6 && sip.IP.To4() != nil || !isV6 && sip.IP.To4() == nil {
return types.InvalidParameterErrorf("incongruent ip versions for pool and secondary ip address %s", k)
}
}
if !i.Pool.Contains(i.Gateway.IP) {
return types.InvalidParameterErrorf("invalid gateway address (%s) does not belong to the pool (%s)", i.Gateway, i.Pool)
}
for k, sip := range i.AuxAddresses {
if !i.Pool.Contains(sip.IP) {
return types.InvalidParameterErrorf("invalid secondary address %s (%s) does not belong to the pool (%s)", k, i.Gateway, i.Pool)
}
}
return nil
}
// IsV6 returns whether this is an IPv6 IPAMData structure
func (i *IPAMData) IsV6() bool {
return i.Pool.IP.To4() == nil
}
func (i *IPAMData) String() string {
return fmt.Sprintf("AddressSpace: %s\nPool: %v\nGateway: %v\nAddresses: %v", i.AddressSpace, i.Pool, i.Gateway, i.AuxAddresses)
}
func (i *IPAMData) IPAMConfig() network.IPAMConfig {
var c network.IPAMConfig
c.Subnet, _ = netiputil.ToPrefix(i.Pool)
if i.Gateway != nil {
gw, _ := netip.AddrFromSlice(i.Gateway.IP)
c.Gateway = gw.Unmap()
}
if i.AuxAddresses != nil {
c.AuxAddress = maps.Collect(iterutil.Map2(maps.All(i.AuxAddresses), func(k string, v *net.IPNet) (string, netip.Addr) {
a, _ := netip.AddrFromSlice(v.IP)
return k, a.Unmap()
}))
}
return c
}