Seán C McCord 5d4d179cd8 feat: support ipv6 routes
While IPv6 were mostly supported already, there was a single segment in
the interface setup which forced everything into an IPv4 route.
This limitation has been removed.

In so doing, route metrics have been cleaned up a small amount.
This change allows the specification of the route metric from the
config.

Fixes #2772

Signed-off-by: Seán C McCord <ulexus@gmail.com>
2020-11-17 13:11:26 -08:00

145 lines
2.9 KiB
Go

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package address
import (
"context"
"net"
"time"
"golang.org/x/sys/unix"
"github.com/talos-systems/talos/pkg/machinery/config"
)
const staticRouteDefaultMetric uint32 = 10
// Static implements the Addressing interface.
type Static struct {
CIDR string
Mtu int
FQDN string
RouteList []config.Route
NetIf *net.Interface
NameServers []net.IP
}
// Discover doesnt do anything in the static configuration since all
// the necessary configuration data is supplied via config.
func (s *Static) Discover(ctx context.Context, link *net.Interface) error {
s.NetIf = link
return nil
}
// Name returns back the name of the address method.
func (s *Static) Name() string {
return "static"
}
// Address returns the IP address.
func (s *Static) Address() *net.IPNet {
var ip net.IP
var ipn *net.IPNet
if s.CIDR != "" {
// nolint: errcheck
ip, ipn, _ = net.ParseCIDR(s.CIDR)
ipn.IP = ip
}
return ipn
}
// Mask returns the netmask.
func (s *Static) Mask() net.IPMask {
// nolint: errcheck
_, ipnet, _ := net.ParseCIDR(s.CIDR)
return ipnet.Mask
}
// MTU returns the specified MTU.
func (s *Static) MTU() uint32 {
mtu := uint32(s.Mtu)
if mtu == 0 {
mtu = uint32(s.NetIf.MTU)
}
return mtu
}
// TTL returns the address lifetime. Since this is static, there is
// no TTL (0).
func (s *Static) TTL() time.Duration {
return 0
}
// Family qualifies the address as ipv4 or ipv6.
func (s *Static) Family() int {
if s.Address() == nil {
panic("unable to determine address family as address is nil")
}
if s.Address().IP.To4() != nil {
return unix.AF_INET
}
return unix.AF_INET6
}
// Scope sets the address scope.
func (s *Static) Scope() uint8 {
return unix.RT_SCOPE_UNIVERSE
}
// Routes aggregates the specified routes for a given device configuration
// TODO: do we need to be explicit on route vs gateway?
func (s *Static) Routes() (routes []*Route) {
for _, route := range s.RouteList {
_, ipnet, err := net.ParseCIDR(route.Network())
if err != nil {
// TODO: we should at least log the error
continue
}
metric := staticRouteDefaultMetric
if route.Metric() != 0 {
metric = route.Metric()
}
routes = append(routes, &Route{
Destination: ipnet,
Gateway: net.ParseIP(route.Gateway()),
Metric: metric,
})
}
return routes
}
// Resolvers returns the DNS resolvers.
func (s *Static) Resolvers() []net.IP {
return s.NameServers
}
// Hostname returns the hostname.
func (s *Static) Hostname() string {
return s.FQDN
}
// Link returns the underlying net.Interface that this address
// method is configured for.
func (s Static) Link() *net.Interface {
return s.NetIf
}
// Valid denotes if this address method should be used.
func (s *Static) Valid() bool {
return true
}