Aaron U'Ren a610596277 fact(GetMTUFromNodeIP): move up a layer of abstraction
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.
2021-05-17 16:33:15 -05:00

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)
}