mirror of
https://github.com/OpenNebula/one.git
synced 2026-10-23 19:57:32 +09:00
This PR adds Group VLAN authorization rules for Virtual Network self-provisioning
through VN Template instantiation and VNET updates derived from a VN Template.
The feature lets administrators define VLAN usage policies at group level. These policies are
evaluated when users instantiate VN Templates or update VNETs that were instantiated from a VN
Template. Direct VNET allocation is not treated as the tenant self-provisioning path; the intended
multi-tenant model is to expose network creation through reservations and VN Template
instantiation, while direct VNET allocation remains an admin-controlled operation.
Group VLAN rules are stored under `VLAN_RULES` as `RULE` vector attributes.
Rule format:
```txt
RULE = [
ID = "5,6,100-200",
SCOPE = "CVLAN",
VNTEMPLATE = "10,20-30"
]
Fields:
- ID: VLAN values allowed by the rule. Supports single values and ranges, comma-separated.
- Examples: "5", "5,6,100-200"
- SCOPE: VLAN attribute scope controlled by the rule.
- Supported scopes: VLAN_ID, OUTER_VLAN_ID, CVLAN, VLAN_TAGGED_ID, ANY
- VNTEMPLATE: optional VN Template IDs where the rule applies.
- Supports single values and ranges, comma-separated.
- -1 or missing value means the rule applies to any VN Template.
Examples:
RULE = [
ID = "100-200",
SCOPE = "VLAN_ID",
VNTEMPLATE = "10"
]
Allows VLAN_ID values from 100 to 200 when instantiating or updating VNETs derived from VN Template
10.
RULE = [
ID = "300,400-450",
SCOPE = "ANY",
VNTEMPLATE = "-1"
]
Allows the listed VLAN IDs/ranges for any supported VLAN scope and any VN Template.
Rules are parsed into an internal structured representation when group VLAN data is loaded or
updated. Each rule is normalized into:
- scope
- VLAN ID ranges
- VN Template ID ranges
This avoids reparsing raw template attributes during authorization checks.
Validation is applied to these input scopes:
- VLAN_ID
- OUTER_VLAN_ID
- CVLAN
- VLAN_TAGGED_ID
VLAN_ID and OUTER_VLAN_ID are validated as single integer values. CVLAN and VLAN_TAGGED_ID accept
range expressions such as 5,6-10.
For each requested VLAN value or range:
1. The input is parsed into one or more test ranges.
2. Rules are scanned for matching scope, including ANY.
3. Rules are filtered by VN Template ID:
- empty/-1 VNTEMPLATE matches all templates
- explicit ranges match only included template IDs
4. A requested range is accepted only if it is fully covered by a single rule range.
5. The check passes when all requested ranges are covered.
Automatic VLAN selection is rejected when the user belongs to a group with VLAN rules matching the
target VN Template, including global rules. This avoids bypassing explicit group VLAN policy
through automatic allocation.
VNETs instantiated from VN Templates now preserve the source VN Template ID as a first-class VNET
attribute:
<VNET>
...
<TEMPLATE_ID>...</TEMPLATE_ID>
...
</VNET>
TEMPLATE_ID = -1 means the VNET was created directly and was not instantiated from a VN Template.
This ID is immutable from user template updates:
- it is removed from the VNET template body on insert/update
- it is serialized as a top-level VNET attribute
- update operations use the stored value to validate VLAN authorization
A database migrator moves legacy TEMPLATE/TEMPLATE_ID values to top-level VNET/TEMPLATE_ID.
The tenant self-provisioning model for VNETs is based on controlled entry points:
- VNET reservations
- VN Template instantiation
Group VLAN authorization is enforced on VN Template instantiation and on updates to VNETs that were
instantiated from a VN Template.
Direct VNET allocation is not considered the tenant-facing self-provisioning path. It should remain
admin-controlled, as unrestricted VNET creation can expose other sensitive network attributes such
as PHYDEV, BRIDGE, and driver-specific configuration in addition to VLAN IDs.
Existing VNETs created from VN Templates may have the source template ID stored inside TEMPLATE/
TEMPLATE_ID. The migration step moves that value to top-level VNET/TEMPLATE_ID and removes it from
the template body.
This PR also updates the AR operations (add/del/update) so tenants can easily managed the VNET instantiations.
Existing directly-created VNETs will have no source VN Template and are treated as TEMPLATE_ID =
-1.
Existing group objects without VLAN rules are initialized with an empty VLAN_RULES section,
preserving current behavior until rules are explicitly configured.
Configuration compatibility:
- VLAN_ID, CVLANS, and AR/VLAN_ID are no longer expected to be handled through generic VNET
restricted attributes for the VN Template instantiation flow.
- OneCfg migration/update handling for configuration files will be addressed separately before
release.
co-authored-by: Pavel Czerny <pczerny@opennebula.io>
co-authored-by: Miguel E. Ruiz <mruiz@opennebula.io>
co-authored-by: dcarracedo <dcarracedo@opennebula.io>
458 lines
16 KiB
C++
458 lines
16 KiB
C++
/* -------------------------------------------------------------------------- */
|
|
/* Copyright 2002-2026, OpenNebula Project, OpenNebula Systems */
|
|
/* */
|
|
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
|
|
/* not use this file except in compliance with the License. You may obtain */
|
|
/* a copy of the License at */
|
|
/* */
|
|
/* http://www.apache.org/licenses/LICENSE-2.0 */
|
|
/* */
|
|
/* Unless required by applicable law or agreed to in writing, software */
|
|
/* distributed under the License is distributed on an "AS IS" BASIS, */
|
|
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
|
|
/* See the License for the specific language governing permissions and */
|
|
/* limitations under the License. */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
#ifndef VIRTUAL_NETWORK_POOL_H_
|
|
#define VIRTUAL_NETWORK_POOL_H_
|
|
|
|
#include "PoolSQL.h"
|
|
#include "VirtualNetwork.h"
|
|
#include "BitMap.h"
|
|
#include "OneDB.h"
|
|
|
|
class AuthRequest;
|
|
class VirtualMachineNic;
|
|
class VirtualMachine;
|
|
|
|
/**
|
|
* The Virtual Network Pool class. ...
|
|
*/
|
|
class VirtualNetworkPool : public PoolSQL
|
|
{
|
|
public:
|
|
|
|
VirtualNetworkPool(SqlDB * db,
|
|
const std::string& str_mac_prefix,
|
|
bool mac_global_space,
|
|
unsigned long int default_size,
|
|
std::vector<const SingleAttribute *>& restricted_attrs,
|
|
std::vector<const SingleAttribute *>& encrypted_attrs,
|
|
const std::vector<const SingleAttribute *>& _inherit_attrs,
|
|
const VectorAttribute * vlan_conf,
|
|
const VectorAttribute * vxlan_conf);
|
|
|
|
~VirtualNetworkPool() {};
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Virtual Network DB access functions
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* Function to allocate a new VNET object
|
|
* @param uid user identifier
|
|
* @param gid the id of the group this object is assigned to
|
|
* @param uname user name
|
|
* @param gname group name
|
|
* @param umask permissions umask
|
|
* @param parent_vid parent network id, -1 if this is not a reservation
|
|
* @param template_id VN Template id, -1 if directly created
|
|
* @param vn_template a VirtualNetworkTemplate describing the VNET
|
|
* @param oid the id assigned to the VM (output)
|
|
* @param cluster_ids the ids of the clusters this VNET will belong to
|
|
* @param error_str Returns the error reason, if any
|
|
* @return oid on success, -1 error
|
|
*/
|
|
int allocate (
|
|
int uid,
|
|
int gid,
|
|
const std::string& uname,
|
|
const std::string& gname,
|
|
int umask,
|
|
int parent_vid,
|
|
int template_id,
|
|
std::unique_ptr<VirtualNetworkTemplate> vn_template,
|
|
int * oid,
|
|
const std::set<int> &cluster_ids,
|
|
std::string& error_str);
|
|
|
|
/**
|
|
* Updates a Virtual Network in the data base. It also updates the previous state
|
|
* after executing the hooks.
|
|
* @param objsql a pointer to the Host
|
|
*
|
|
* @return 0 on success.
|
|
*/
|
|
int update(PoolObjectSQL * objsql) override;
|
|
|
|
/**
|
|
* Drops a Virtual Network and the associated VLAN_ID if needed
|
|
*/
|
|
int drop(PoolObjectSQL * vn, std::string& error_msg) override
|
|
{
|
|
auto vnet = static_cast<VirtualNetwork *>(vn);
|
|
|
|
release_vlan_id(vnet);
|
|
vnet->release_mac_ids();
|
|
|
|
return PoolSQL::drop(vn, error_msg);
|
|
};
|
|
|
|
/**
|
|
* Gets an object from the pool (if needed the object is loaded from the
|
|
* database). The object is locked, other threads can't access the same
|
|
* object. The lock is released by destructor.
|
|
* @param oid the VN unique identifier
|
|
* @return a pointer to the VN, nullptr in case of failure
|
|
*/
|
|
std::unique_ptr<VirtualNetwork> get(int oid)
|
|
{
|
|
return PoolSQL::get<VirtualNetwork>(oid);
|
|
}
|
|
|
|
/**
|
|
* Gets a read only object from the pool (if needed the object is loaded from the
|
|
* database). No object lock, other threads may work with the same object.
|
|
* @param oid the VN unique identifier
|
|
* @return a pointer to the VN, nullptr in case of failure
|
|
*/
|
|
std::unique_ptr<VirtualNetwork> get_ro(int oid)
|
|
{
|
|
return PoolSQL::get_ro<VirtualNetwork>(oid);
|
|
}
|
|
|
|
/**
|
|
* Gets an object from the pool (if needed the object is loaded from the
|
|
* database). The object is locked, other threads can't access the same
|
|
* object. The lock is released by destructor.
|
|
* @param name of the object
|
|
* @param uid id of owner
|
|
*
|
|
* @return a pointer to the object, 0 in case of failure
|
|
*/
|
|
std::unique_ptr<VirtualNetwork> get(const std::string& name, int uid)
|
|
{
|
|
return PoolSQL::get<VirtualNetwork>(name, uid);
|
|
}
|
|
|
|
/**
|
|
* Gets a read only object from the pool (if needed the object is loaded from the
|
|
* database). No object lock, other threads may work with the same object.
|
|
* @param name of the object
|
|
* @param uid id of owner
|
|
*
|
|
* @return a pointer to the object, 0 in case of failure
|
|
*/
|
|
std::unique_ptr<VirtualNetwork> get_ro(const std::string& name, int uid)
|
|
{
|
|
return PoolSQL::get_ro<VirtualNetwork>(name, uid);
|
|
}
|
|
|
|
/**
|
|
* Bootstraps the database table(s) associated to the VirtualNetwork pool
|
|
* @return 0 on success
|
|
*/
|
|
static int bootstrap(SqlDB * _db)
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
int rc;
|
|
|
|
rc = VirtualNetwork::bootstrap(_db);
|
|
rc += _db->exec_local_wr(BitMap<0>::bootstrap(vlan_table, oss));
|
|
|
|
return rc;
|
|
};
|
|
|
|
/**
|
|
* Dumps the Virtual Network pool in XML format. A filter can be also added
|
|
* to the query
|
|
* @param oss the output stream to dump the pool contents
|
|
* @param where filter for the objects, defaults to all
|
|
* @param sid first element used for pagination
|
|
* @param eid last element used for pagination, -1 to disable
|
|
* @param desc descending order of pool elements
|
|
*
|
|
* @return 0 on success
|
|
*/
|
|
int dump(std::string& oss, const std::string& where, int sid, int eid,
|
|
bool desc) override
|
|
{
|
|
return PoolSQL::dump(oss, "VNET_POOL", "body", one_db::vn_table,
|
|
where, sid, eid, desc);
|
|
}
|
|
|
|
/**
|
|
* Get the mac prefix
|
|
* @return the mac prefix
|
|
*/
|
|
static const unsigned int& mac_prefix()
|
|
{
|
|
return _mac_prefix;
|
|
};
|
|
|
|
/**
|
|
* Returns true if global MAC address space generation is enabled
|
|
*/
|
|
static bool mac_global_space()
|
|
{
|
|
return _mac_global_space;
|
|
};
|
|
|
|
/**
|
|
* Get the default network size
|
|
* @return the size
|
|
*/
|
|
static const unsigned long int& default_size()
|
|
{
|
|
return _default_size;
|
|
};
|
|
|
|
/**
|
|
* Gets the IDs of VNETs matching the given SQL where string.
|
|
* @param oids a vector that contains the IDs
|
|
* @param where SQL clause
|
|
* @return 0 on success
|
|
*/
|
|
int search(std::vector<int>& oids, const std::string& where)
|
|
{
|
|
return PoolSQL::search(oids, one_db::vn_table, where);
|
|
};
|
|
|
|
const std::set<std::string>& get_inherited_attrs() const
|
|
{
|
|
return inherit_attrs;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// NIC Attribute build functions
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* Generates a NIC attribute for VM templates using the VirtualNetwork
|
|
* metadata
|
|
* @param nic the nic attribute to be generated
|
|
* @param nic_id the id for this NIC
|
|
* @param uid of the VM owner
|
|
* @param vid of the VM requesting the lease
|
|
* @param error_str string describing the error
|
|
* @return 0 on success,
|
|
* -1 error,
|
|
* -2 not using the pool
|
|
*/
|
|
int nic_attribute(
|
|
PoolObjectSQL::ObjectType ot,
|
|
VirtualMachineNic * nic,
|
|
int nic_id,
|
|
int uid,
|
|
int vid,
|
|
std::string& error_str);
|
|
|
|
/**
|
|
* Generates an Authorization token for a NIC attribute
|
|
* @param nic the nic to be authorized
|
|
* @param ar the AuthRequest
|
|
* @param check_lock for check if the resource is lock or not
|
|
* @param uid of user making the request
|
|
* @param sgs to check the security groups
|
|
*/
|
|
void authorize_nic(
|
|
PoolObjectSQL::ObjectType ot,
|
|
VirtualMachineNic * nic,
|
|
int uid,
|
|
AuthRequest * ar,
|
|
std::set<int> & sgs,
|
|
bool check_lock);
|
|
|
|
//--------------------------------------------------------------------------
|
|
// VNET Reservation interface
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* Reserve an address range
|
|
* @param pid the parent VNET ID to get the leases from
|
|
* @param rid the reservation VNET ID to store the reserved AR
|
|
* @param rsize number of addresses to reserve
|
|
* @param err error message
|
|
* @return 0 on success
|
|
*/
|
|
int reserve_addr(int pid, int rid, unsigned int rsize, std::string& err);
|
|
|
|
/**
|
|
* Reserve an address range
|
|
* @param pid the parent VNET ID to get the leases from
|
|
* @param rid the reservation VNET ID to store the reserved AR
|
|
* @param rsize number of addresses to reserve
|
|
* @param ar_id AR to make the reservation from
|
|
* @param err error message
|
|
* @return 0 on success
|
|
*/
|
|
int reserve_addr(int pid, int rid, unsigned int rsize, unsigned int ar_id,
|
|
std::string& err);
|
|
|
|
/**
|
|
* Reserve an address range
|
|
* @param pid the parent VNET ID to get the leases from
|
|
* @param rid the reservation VNET ID to store the reserved AR
|
|
* @param rsize number of addresses to reserve
|
|
* @param ar_id AR to make the reservation from
|
|
* @param ip/mac the first ip/mac in the reservations
|
|
* @param err error message
|
|
* @return 0 on success
|
|
*/
|
|
int reserve_addr_by_ip(int pid, int rid, unsigned int rsize,
|
|
unsigned int ar_id, const std::string& ip, std::string& err);
|
|
|
|
int reserve_addr_by_ip6(int pid, int rid, unsigned int rsize,
|
|
unsigned int ar_id, const std::string& ip, std::string& err);
|
|
|
|
int reserve_addr_by_mac(int pid, int rid, unsigned int rsize,
|
|
unsigned int ar_id, const std::string& mac, std::string& err);
|
|
|
|
void delete_success(std::unique_ptr<VirtualNetwork> vn);
|
|
|
|
private:
|
|
/**
|
|
* Holds the system-wide MAC prefix
|
|
*/
|
|
static unsigned int _mac_prefix;
|
|
|
|
/**
|
|
* Enables global MAC address space generation
|
|
*/
|
|
static bool _mac_global_space;
|
|
|
|
/**
|
|
* Default size for Virtual Networks
|
|
*/
|
|
static unsigned long int _default_size;
|
|
|
|
/**
|
|
* VNet attributes to be injected into the VM nic
|
|
*/
|
|
std::set<std::string> inherit_attrs;
|
|
|
|
/**
|
|
* Configuration attributes for the vlan_id pool
|
|
*/
|
|
const VectorAttribute vlan_conf;
|
|
|
|
/**
|
|
* ID for the VLAN_BITMAP, to store it in the DB
|
|
*/
|
|
static constexpr int VLAN_BITMAP_ID = 0;
|
|
|
|
/**
|
|
* ID for the MAC_BITMAP, to store it in the DB
|
|
*/
|
|
static constexpr int MAC_BITMAP_ID = 1;
|
|
|
|
/**
|
|
* Configuration attributes for the vxlan_id pool
|
|
*/
|
|
const VectorAttribute vxlan_conf;
|
|
|
|
/**
|
|
* Virtual Network bitmap pool for VLANs table
|
|
*/
|
|
static constexpr const char * vlan_table = "network_vlan_bitmap";
|
|
|
|
//--------------------------------------------------------------------------
|
|
// NIC Attribute build functions
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* Function to get a VirtualNetwork by its name, as provided by a VM
|
|
* template
|
|
*/
|
|
std::unique_ptr<VirtualNetwork> get_nic_by_name(VirtualMachineNic * nic,
|
|
const std::string& name,
|
|
int _uidi,
|
|
bool ro,
|
|
std::string& error);
|
|
/**
|
|
* Function to get a VirtualNetwork by its id, as provided by a VM template
|
|
*/
|
|
std::unique_ptr<VirtualNetwork> get_nic_by_id(const std::string& id_s,
|
|
bool ro,
|
|
std::string& error);
|
|
|
|
public:
|
|
//--------------------------------------------------------------------------
|
|
// VLAN ID management functions
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* Gets a free VLAN_ID, if not set by the user, and for VXLAN, VLAN and
|
|
* OVSWITCH networks.
|
|
* @param vn pointer to the network
|
|
* @return 0 on success
|
|
*/
|
|
int set_vlan_id(VirtualNetwork * vn);
|
|
|
|
/**
|
|
* Gets a free Global MAC ID, if not set by the user.
|
|
* @param preferred_id hint for the MAC ID
|
|
* @param allocated_id the allocated MAC ID
|
|
* @return 0 on success
|
|
*/
|
|
static int allocate_mac_id(unsigned int preferred_id, unsigned int& allocated_id);
|
|
|
|
/**
|
|
* Free a previously allocated Global MAC ID
|
|
* @param id the MAC ID to free
|
|
*/
|
|
static void release_mac_id(int id);
|
|
|
|
/**
|
|
* Reserves a specific Global MAC ID
|
|
* @param id the MAC ID to reserve
|
|
* @return 0 on success
|
|
*/
|
|
static int reserve_mac_id(unsigned int id);
|
|
|
|
/**
|
|
* Helper functions to compute the next vlan_id for 802.1Q and VXLAN.
|
|
* @param vnid network id
|
|
* @param vlan_var, attribute to store the vlan_id
|
|
* @param auto_var, attribute to flag this vlan_id as auto generated
|
|
*/
|
|
int set_8021Q_id(int vnid, std::string& vlan_var, bool& auto_var);
|
|
|
|
int set_vxlan_id(int vnid, std::string& vlan_var, bool& auto_var);
|
|
|
|
/**
|
|
* Free a previously allocated VLAN ID if needed
|
|
* @param vn pointer to the network
|
|
*/
|
|
void release_vlan_id(VirtualNetwork *vn);
|
|
|
|
//--------------------------------------------------------------------------
|
|
// VNET Reservation Functions
|
|
//--------------------------------------------------------------------------
|
|
/**
|
|
* Allocate a new AR from the given VNET
|
|
* @param rid VNET ID
|
|
* @param err string if any
|
|
* @return pointer to the allocated AR
|
|
*/
|
|
AddressRange * allocate_ar(int rid, std::string &err);
|
|
|
|
/**
|
|
* Adds a new AR to a VNET
|
|
* @param rid VNET ID
|
|
* @param ar pointer to the AR
|
|
* @param err string if any
|
|
* @return 0 on success
|
|
*/
|
|
int add_ar(int rid, AddressRange *rar, std::string &err);
|
|
|
|
/**
|
|
* Factory method to produce VN objects
|
|
* @return a pointer to the new VN
|
|
*/
|
|
PoolObjectSQL * create() override
|
|
{
|
|
std::set <int> empty;
|
|
return new VirtualNetwork(-1, -1, "", "", 0, -1, -1, empty, 0);
|
|
};
|
|
};
|
|
|
|
#endif /*VIRTUAL_NETWORK_POOL_H_*/
|