mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
Add peer groups support for network routes (#1150)
This commit enhances the functionality of the network routes endpoint by introducing a new parameter called `peers_group`. This addition allows users to associate network routes with specific peer groups, simplifying the management and distribution of routes within a network.
This commit is contained in:
@@ -39,30 +39,82 @@ func (am *DefaultAccountManager) GetRoute(accountID, routeID, userID string) (*r
|
||||
return nil, status.Errorf(status.NotFound, "route with ID %s not found", routeID)
|
||||
}
|
||||
|
||||
// checkPrefixPeerExists checks the combination of prefix and peer id, if it exists returns an error, otherwise returns nil
|
||||
func (am *DefaultAccountManager) checkPrefixPeerExists(accountID, peerID string, prefix netip.Prefix) error {
|
||||
|
||||
if peerID == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
account, err := am.Store.GetAccount(accountID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// checkRoutePrefixExistsForPeers checks if a route with a given prefix exists for a single peer or multiple peer groups.
|
||||
func (am *DefaultAccountManager) checkRoutePrefixExistsForPeers(account *Account, peerID, routeID string, peerGroupIDs []string, prefix netip.Prefix) error {
|
||||
// routes can have both peer and peer_groups
|
||||
routesWithPrefix := account.GetRoutesByPrefix(prefix)
|
||||
|
||||
// lets remember all the peers and the peer groups from routesWithPrefix
|
||||
seenPeers := make(map[string]bool)
|
||||
seenPeerGroups := make(map[string]bool)
|
||||
|
||||
for _, prefixRoute := range routesWithPrefix {
|
||||
if prefixRoute.Peer == peerID {
|
||||
return status.Errorf(status.AlreadyExists, "failed to add route with prefix %s - peer already has this route", prefix.String())
|
||||
// we skip route(s) with the same network ID as we want to allow updating of the existing route
|
||||
// when create a new route routeID is newly generated so nothing will be skipped
|
||||
if routeID == prefixRoute.ID {
|
||||
continue
|
||||
}
|
||||
|
||||
if prefixRoute.Peer != "" {
|
||||
seenPeers[prefixRoute.ID] = true
|
||||
}
|
||||
for _, groupID := range prefixRoute.PeerGroups {
|
||||
seenPeerGroups[groupID] = true
|
||||
|
||||
group := account.GetGroup(groupID)
|
||||
if group == nil {
|
||||
return status.Errorf(
|
||||
status.InvalidArgument, "failed to add route with prefix %s - peer group %s doesn't exist",
|
||||
prefix.String(), groupID)
|
||||
}
|
||||
|
||||
for _, pID := range group.Peers {
|
||||
seenPeers[pID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if peerID != "" {
|
||||
// check that peerID exists and is not in any route as single peer or part of the group
|
||||
peer := account.GetPeer(peerID)
|
||||
if peer == nil {
|
||||
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
||||
}
|
||||
if _, ok := seenPeers[peerID]; ok {
|
||||
return status.Errorf(status.AlreadyExists,
|
||||
"failed to add route with prefix %s - peer %s already has this route", prefix.String(), peerID)
|
||||
}
|
||||
}
|
||||
|
||||
// check that peerGroupIDs are not in any route peerGroups list
|
||||
for _, groupID := range peerGroupIDs {
|
||||
group := account.GetGroup(groupID) // we validated the group existent before entering this function, o need to check again.
|
||||
|
||||
if _, ok := seenPeerGroups[groupID]; ok {
|
||||
return status.Errorf(
|
||||
status.AlreadyExists, "failed to add route with prefix %s - peer group %s already has this route",
|
||||
prefix.String(), group.Name)
|
||||
}
|
||||
|
||||
// check that the peers from peerGroupIDs groups are not the same peers we saw in routesWithPrefix
|
||||
for _, id := range group.Peers {
|
||||
if _, ok := seenPeers[id]; ok {
|
||||
peer := account.GetPeer(peerID)
|
||||
if peer == nil {
|
||||
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
||||
}
|
||||
return status.Errorf(status.AlreadyExists,
|
||||
"failed to add route with prefix %s - peer %s from the group %s already has this route",
|
||||
prefix.String(), peer.Name, group.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateRoute creates and saves a new route
|
||||
func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
|
||||
func (am *DefaultAccountManager) CreateRoute(accountID, network, peerID string, peerGroupIDs []string, description, netID string, masquerade bool, metric int, groups []string, enabled bool, userID string) (*route.Route, error) {
|
||||
unlock := am.Store.AcquireAccountLock(accountID)
|
||||
defer unlock()
|
||||
|
||||
@@ -71,19 +123,29 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if peerID != "" {
|
||||
peer := account.GetPeer(peerID)
|
||||
if peer == nil {
|
||||
return nil, status.Errorf(status.InvalidArgument, "peer with ID %s not found", peerID)
|
||||
}
|
||||
if peerID != "" && len(peerGroupIDs) != 0 {
|
||||
return nil, status.Errorf(
|
||||
status.InvalidArgument,
|
||||
"peer with ID %s and peers group %s should not be provided at the same time",
|
||||
peerID, peerGroupIDs)
|
||||
}
|
||||
|
||||
var newRoute route.Route
|
||||
newRoute.ID = xid.New().String()
|
||||
|
||||
prefixType, newPrefix, err := route.ParseNetwork(network)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(status.InvalidArgument, "failed to parse IP %s", network)
|
||||
}
|
||||
err = am.checkPrefixPeerExists(accountID, peerID, newPrefix)
|
||||
|
||||
if len(peerGroupIDs) > 0 {
|
||||
err = validateGroups(peerGroupIDs, account.Groups)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = am.checkRoutePrefixExistsForPeers(account, peerID, newRoute.ID, peerGroupIDs, newPrefix)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -102,7 +164,7 @@ func (am *DefaultAccountManager) CreateRoute(accountID string, network, peerID,
|
||||
}
|
||||
|
||||
newRoute.Peer = peerID
|
||||
newRoute.ID = xid.New().String()
|
||||
newRoute.PeerGroups = peerGroupIDs
|
||||
newRoute.Network = newPrefix
|
||||
newRoute.NetworkType = prefixType
|
||||
newRoute.Description = description
|
||||
@@ -160,13 +222,22 @@ func (am *DefaultAccountManager) SaveRoute(accountID, userID string, routeToSave
|
||||
return err
|
||||
}
|
||||
|
||||
if routeToSave.Peer != "" {
|
||||
peer := account.GetPeer(routeToSave.Peer)
|
||||
if peer == nil {
|
||||
return status.Errorf(status.InvalidArgument, "peer with ID %s not found", routeToSave.Peer)
|
||||
if routeToSave.Peer != "" && len(routeToSave.PeerGroups) != 0 {
|
||||
return status.Errorf(status.InvalidArgument, "peer with ID and peer groups should not be provided at the same time")
|
||||
}
|
||||
|
||||
if len(routeToSave.PeerGroups) > 0 {
|
||||
err = validateGroups(routeToSave.PeerGroups, account.Groups)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = am.checkRoutePrefixExistsForPeers(account, routeToSave.Peer, routeToSave.ID, routeToSave.Copy().PeerGroups, routeToSave.Network)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = validateGroups(routeToSave.Groups, account.Groups)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user