mirror of
https://github.com/cloudnativelabs/kube-router.git
synced 2025-09-27 19:11:05 +02:00
This function is useful for more than just the NRC, move it up a layer into the global utils so it can be used from multiple controllers.
152 lines
3.8 KiB
Go
152 lines
3.8 KiB
Go
package routing
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/osrg/gobgp/pkg/packet/bgp"
|
|
|
|
"github.com/vishvananda/netlink"
|
|
)
|
|
|
|
// Used for processing Annotations that may contain multiple items
|
|
// Pass this the string and the delimiter
|
|
func stringToSlice(s, d string) []string {
|
|
ss := make([]string, 0)
|
|
if strings.Contains(s, d) {
|
|
ss = strings.Split(s, d)
|
|
} else {
|
|
ss = append(ss, s)
|
|
}
|
|
return ss
|
|
}
|
|
|
|
func stringSliceToIPs(s []string) ([]net.IP, error) {
|
|
ips := make([]net.IP, 0)
|
|
for _, ipString := range s {
|
|
ip := net.ParseIP(ipString)
|
|
if ip == nil {
|
|
return nil, fmt.Errorf("could not parse \"%s\" as an IP", ipString)
|
|
}
|
|
ips = append(ips, ip)
|
|
}
|
|
return ips, nil
|
|
}
|
|
|
|
func stringSliceToUInt32(s []string) ([]uint32, error) {
|
|
ints := make([]uint32, 0)
|
|
for _, intString := range s {
|
|
newInt, err := strconv.ParseUint(intString, 0, 32)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not parse \"%s\" as an integer", intString)
|
|
}
|
|
ints = append(ints, uint32(newInt))
|
|
}
|
|
return ints, nil
|
|
}
|
|
|
|
func stringSliceB64Decode(s []string) ([]string, error) {
|
|
ss := make([]string, 0)
|
|
for _, b64String := range s {
|
|
decoded, err := base64.StdEncoding.DecodeString(b64String)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not parse \"%s\" as a base64 encoded string",
|
|
b64String)
|
|
}
|
|
ss = append(ss, string(decoded))
|
|
}
|
|
return ss, nil
|
|
}
|
|
|
|
func ipv4IsEnabled() bool {
|
|
l, err := net.Listen("tcp4", "")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
_ = l.Close()
|
|
|
|
return true
|
|
}
|
|
|
|
func ipv6IsEnabled() bool {
|
|
// If ipv6 is disabled with;
|
|
//
|
|
// sysctl -w net.ipv6.conf.all.disable_ipv6=1
|
|
//
|
|
// It is still possible to listen on the any-address "::". So this
|
|
// function tries the loopback address "::1" which must be present
|
|
// if ipv6 is enabled.
|
|
l, err := net.Listen("tcp6", "[::1]:0")
|
|
if err != nil {
|
|
return false
|
|
}
|
|
_ = l.Close()
|
|
|
|
return true
|
|
}
|
|
|
|
func getNodeSubnet(nodeIP net.IP) (net.IPNet, string, error) {
|
|
links, err := netlink.LinkList()
|
|
if err != nil {
|
|
return net.IPNet{}, "", errors.New("failed to get list of links")
|
|
}
|
|
for _, link := range links {
|
|
addresses, err := netlink.AddrList(link, netlink.FAMILY_ALL)
|
|
if err != nil {
|
|
return net.IPNet{}, "", errors.New("failed to get list of addr")
|
|
}
|
|
for _, addr := range addresses {
|
|
if addr.IPNet.IP.Equal(nodeIP) {
|
|
return *addr.IPNet, link.Attrs().Name, nil
|
|
}
|
|
}
|
|
}
|
|
return net.IPNet{}, "", errors.New("failed to find interface with specified node ip")
|
|
}
|
|
|
|
// generateTunnelName will generate a name for a tunnel interface given a node IP
|
|
// for example, if the node IP is 10.0.0.1 the tunnel interface will be named tun-10001
|
|
// Since linux restricts interface names to 15 characters, if length of a node IP
|
|
// is greater than 12 (after removing "."), then the interface name is tunXYZ
|
|
// as opposed to tun-XYZ
|
|
func generateTunnelName(nodeIP string) string {
|
|
hash := strings.Replace(nodeIP, ".", "", -1)
|
|
|
|
if len(hash) < 12 {
|
|
return "tun-" + hash
|
|
}
|
|
|
|
return "tun" + hash
|
|
}
|
|
|
|
// validateCommunity takes in a string and attempts to parse a BGP community out of it in a way that is similar to
|
|
// gobgp (internal/pkg/table/policy.go:ParseCommunity()). If it is not able to parse the community information it
|
|
// returns an error.
|
|
func validateCommunity(arg string) error {
|
|
_, err := strconv.ParseUint(arg, 10, 32)
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
_regexpCommunity := regexp.MustCompile(`(\d+):(\d+)`)
|
|
elems := _regexpCommunity.FindStringSubmatch(arg)
|
|
if len(elems) == 3 {
|
|
if _, err := strconv.ParseUint(elems[1], 10, 16); err == nil {
|
|
if _, err = strconv.ParseUint(elems[2], 10, 16); err == nil {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
for _, v := range bgp.WellKnownCommunityNameMap {
|
|
if arg == v {
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("failed to parse %s as community", arg)
|
|
}
|