Skip to content

Commit

Permalink
Attractor ipv4/ipv6-prefix also accept IP range
Browse files Browse the repository at this point in the history
Allows limiting the pool of IP addresses to allocate IPs from.
-Enables coordination of multiple Attractors when they share
 the same external network.
-Can be also used to exclude reserved IPs of Gateway Routers.

Example:
    ipv4-prefix: 169.254.100.0-169.254.100.100/24
    ipv6-prefix: 100:100::0-100:100::100/64;100:100::2000-100:100::ffff/64
  • Loading branch information
zolug committed Jan 6, 2023
1 parent 3805116 commit 4205264
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 10 deletions.
10 changes: 8 additions & 2 deletions api/v1/attractor_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,18 @@ type InterfaceSpec struct {
// +kubebuilder:validation:Pattern=`^[^:\//\s]{1,13}$`
Name string `json:"name"`

// (immutable) IPv4 prefix of the interface, which is used for frontend to set up communication with the ipv4 gateways.
// (immutable) IPv4 prefix or range of the interface, which is used for frontend to set up communication with the ipv4 gateways.
// If the type is "nsm-vlan", this information must be specified.
// For example, '192.168.100.0/24', '192.168.100.1-192.168.100.100/24'.
// Multiple IP ranges can be combined using semicolon delimiter, but they must belong to the same network.
// For example, '192.168.100.3-192.168.100.100/24;192.168.100.200-192.168.100.250/24'.
PrefixIPv4 string `json:"ipv4-prefix,omitempty"`

// (immutable) IPv6 prefix of the interface, which is used for frontend to set up communication with the ipv6 gateways.
// (immutable) IPv6 prefix or range of the interface, which is used for frontend to set up communication with the ipv6 gateways.
// If the type is "nsm-vlan", this information must be specified.
// For example, '100:100::/64', '100:100::bbbb-100:100::cccc/64'.
// Multiple IP ranges can be combined using semicolon delimiter, but they must belong to the same network.
// For example, '100:100::2-100:100::ffff/64;100:100::a:2-100:100::a:f/64;100:100::e:2-100:100::e:f/64'.
PrefixIPv6 string `json:"ipv6-prefix,omitempty"`

// Interface choice.
Expand Down
4 changes: 2 additions & 2 deletions api/v1/attractor_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,12 @@ func (r *Attractor) validateAttractor() error {
}
switch r.Spec.Interface.Type {
case NSMVlan:
_, err := validatePrefix(r.Spec.Interface.PrefixIPv4)
err := validatePrefixAndRange(r.Spec.Interface.PrefixIPv4)
if err != nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("ipv4-prefix"), r.Spec.Interface.PrefixIPv4, err.Error()))
}

_, err = validatePrefix(r.Spec.Interface.PrefixIPv6)
err = validatePrefixAndRange(r.Spec.Interface.PrefixIPv6)
if err != nil {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("ipv6-prefix"), r.Spec.Interface.PrefixIPv6, err.Error()))
}
Expand Down
41 changes: 41 additions & 0 deletions api/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,47 @@ func validatePrefix(p string) (*net.IPNet, error) {
return n, nil
}

func validatePrefixAndRange(p string) error {
var err error
var network *net.IPNet
composite := strings.Split(p, ";")
for _, c := range composite {
if r := strings.SplitN(c, "-", 2); len(r) == 2 {
// validate IP range
firstip := net.ParseIP(r[0])
if firstip == nil {
return fmt.Errorf("'%s' is not a valid IP range start", r[0])
}
_, ipNet, err := net.ParseCIDR(r[1])
if err != nil {
return fmt.Errorf("'%s' is not a valid CIDR: %s", r[1], err)
}
if !ipNet.Contains(firstip) {
return fmt.Errorf("'%s' is not a valid IP range start for CIDR %s", ipNet.String(), firstip)
}
if network == nil {
network = ipNet
} else {
if !network.IP.Equal(ipNet.IP) {
return fmt.Errorf("network mismatch: '%s' != '%s'", network, ipNet)
}
netOnes, netBits := network.Mask.Size()
ones, bits := ipNet.Mask.Size()
if netOnes != ones || netBits != bits {
return fmt.Errorf("network mask mismatch: %v != %v", network.Mask, ipNet.Mask)
}
}
} else {
// validate prefix
if len(composite) > 1 {
return fmt.Errorf("%s composite subnet config is invalid", composite)
}
_, err = validatePrefix(c)
}
}
return err
}

type InterfaceType string

const (
Expand Down
18 changes: 12 additions & 6 deletions config/crd/bases/meridio.nordix.org_attractors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,20 @@ spec:
description: defines the interface information that attractor use
properties:
ipv4-prefix:
description: (immutable) IPv4 prefix of the interface, which is
used for frontend to set up communication with the ipv4 gateways.
If the type is "nsm-vlan", this information must be specified.
description: (immutable) IPv4 prefix or range of the interface,
which is used for frontend to set up communication with the
ipv4 gateways. If the type is "nsm-vlan", this information must
be specified. For example, '192.168.100.0/24', '192.168.100.1-192.168.100.100/24'.
Multiple IP ranges can be combined using semicolon delimiter,
but they must belong to the same network. For example, '192.168.100.3-192.168.100.100/24;192.168.100.200-192.168.100.250/24'.
type: string
ipv6-prefix:
description: (immutable) IPv6 prefix of the interface, which is
used for frontend to set up communication with the ipv6 gateways.
If the type is "nsm-vlan", this information must be specified.
description: (immutable) IPv6 prefix or range of the interface,
which is used for frontend to set up communication with the
ipv6 gateways. If the type is "nsm-vlan", this information must
be specified. For example, '100:100::/64', '100:100::bbbb-100:100::cccc/64'.
Multiple IP ranges can be combined using semicolon delimiter,
but they must belong to the same network. For example, '100:100::2-100:100::ffff/64;100:100::a:2-100:100::a:f/64;100:100::e:2-100:100::e:f/64'.
type: string
name:
description: Name of the interface. Must be a valid Linux kernel
Expand Down

0 comments on commit 4205264

Please sign in to comment.