netbird/route/route.go
Yury Gargay 32880c56a4
Implement SQLite Store using gorm and relational approach (#1065)
Restructure data handling for improved performance and flexibility. 
Introduce 'G'-prefixed fields to represent Gorm relations, simplifying resource management. 
Eliminate complexity in lookup tables for enhanced query and write speed. 
Enable independent operations on data structures, requiring adjustments in the Store interface and Account Manager.
2023-10-12 15:42:36 +02:00

167 lines
4.2 KiB
Go

package route
import (
"net/netip"
"github.com/netbirdio/netbird/management/server/status"
)
// Windows has some limitation regarding metric size that differ from Unix-like systems.
// Because of that we are limiting the min and max metric size based on Windows limits:
// see based on info from https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/route_ws2008
const (
// MinMetric max metric input
MinMetric = 1
// MaxMetric max metric input
MaxMetric = 9999
// MaxNetIDChar Max Network Identifier
MaxNetIDChar = 40
)
const (
// InvalidNetworkString invalid network type string
InvalidNetworkString = "Invalid"
// IPv4NetworkString IPv4 network type string
IPv4NetworkString = "IPv4"
// IPv6NetworkString IPv6 network type string
IPv6NetworkString = "IPv6"
)
const (
// InvalidNetwork invalid network type
InvalidNetwork NetworkType = iota
// IPv4Network IPv4 network type
IPv4Network
// IPv6Network IPv6 network type
IPv6Network
)
// NetworkType route network type
type NetworkType int
// String returns prefix type string
func (p NetworkType) String() string {
switch p {
case IPv4Network:
return IPv4NetworkString
case IPv6Network:
return IPv6NetworkString
default:
return InvalidNetworkString
}
}
// ToPrefixType returns a prefix type
func ToPrefixType(prefix string) NetworkType {
switch prefix {
case IPv4NetworkString:
return IPv4Network
case IPv6NetworkString:
return IPv6Network
default:
return InvalidNetwork
}
}
// Route represents a route
type Route struct {
ID string `gorm:"primaryKey"`
// AccountID is a reference to Account that this object belongs
AccountID string `gorm:"index"`
Network netip.Prefix `gorm:"serializer:gob"`
NetID string
Description string
Peer string
PeerGroups []string `gorm:"serializer:gob"`
NetworkType NetworkType
Masquerade bool
Metric int
Enabled bool
Groups []string `gorm:"serializer:json"`
}
// EventMeta returns activity event meta related to the route
func (r *Route) EventMeta() map[string]any {
return map[string]any{"name": r.NetID, "network_range": r.Network.String(), "peer_id": r.Peer, "peer_groups": r.PeerGroups}
}
// Copy copies a route object
func (r *Route) Copy() *Route {
route := &Route{
ID: r.ID,
Description: r.Description,
NetID: r.NetID,
Network: r.Network,
NetworkType: r.NetworkType,
Peer: r.Peer,
PeerGroups: make([]string, len(r.PeerGroups)),
Metric: r.Metric,
Masquerade: r.Masquerade,
Enabled: r.Enabled,
Groups: make([]string, len(r.Groups)),
}
copy(route.Groups, r.Groups)
copy(route.PeerGroups, r.PeerGroups)
return route
}
// IsEqual compares one route with the other
func (r *Route) IsEqual(other *Route) bool {
return other.ID == r.ID &&
other.Description == r.Description &&
other.NetID == r.NetID &&
other.Network == r.Network &&
other.NetworkType == r.NetworkType &&
other.Peer == r.Peer &&
other.Metric == r.Metric &&
other.Masquerade == r.Masquerade &&
other.Enabled == r.Enabled &&
compareList(r.Groups, other.Groups) &&
compareList(r.PeerGroups, other.PeerGroups)
}
// ParseNetwork Parses a network prefix string and returns a netip.Prefix object and if is invalid, IPv4 or IPv6
func ParseNetwork(networkString string) (NetworkType, netip.Prefix, error) {
prefix, err := netip.ParsePrefix(networkString)
if err != nil {
return InvalidNetwork, netip.Prefix{}, status.Errorf(status.InvalidArgument, "invalid network %s", networkString)
}
masked := prefix.Masked()
if !masked.IsValid() {
return InvalidNetwork, netip.Prefix{}, status.Errorf(status.InvalidArgument, "invalid range %s", networkString)
}
if masked.Addr().Is6() {
return IPv6Network, masked, nil
}
return IPv4Network, masked, nil
}
func compareList(list, other []string) bool {
if len(list) != len(other) {
return false
}
for _, id := range list {
match := false
for _, otherID := range other {
if id == otherID {
match = true
break
}
}
if !match {
return false
}
}
return true
}
// GetHAUniqueID returns a highly available route ID by combining Network ID and Network range address
func GetHAUniqueID(input *Route) string {
return input.NetID + "-" + input.Network.String()
}