1
0
mirror of https://github.com/OpenNebula/one.git synced 2024-12-23 17:33:56 +03:00

F #1498: Open vSwitch VXLAN driver

This commit is contained in:
Vlastimil Holer 2018-02-28 17:31:38 +01:00 committed by Ruben S. Montero
parent fa2b83545f
commit fdb22a0376
23 changed files with 713 additions and 131 deletions

View File

@ -52,28 +52,30 @@ public:
*/
enum VirtualNetworkDriver
{
NONE = 0,
DUMMY = 1,
VLAN = 2,
EBTABLES = 3,
FW = 4,
OVSWITCH = 5,
VXLAN = 6,
VCENTER = 7
NONE = 0,
DUMMY = 1,
VLAN = 2,
EBTABLES = 3,
FW = 4,
OVSWITCH = 5,
VXLAN = 6,
VCENTER = 7,
OVSWITCH_VXLAN = 8
};
static string driver_to_str(VirtualNetworkDriver ob)
{
switch (ob)
{
case NONE: return "";
case DUMMY: return "dummy";
case VLAN: return "802.1Q";
case EBTABLES: return "ebtables";
case FW: return "fw";
case OVSWITCH: return "ovswitch";
case VXLAN: return "vxlan";
case VCENTER: return "vcenter";
case NONE: return "";
case DUMMY: return "dummy";
case VLAN: return "802.1Q";
case EBTABLES: return "ebtables";
case FW: return "fw";
case OVSWITCH: return "ovswitch";
case VXLAN: return "vxlan";
case VCENTER: return "vcenter";
case OVSWITCH_VXLAN: return "ovswitch_vxlan";
}
};
@ -107,6 +109,10 @@ public:
{
return VCENTER;
}
else if ( ob == "ovswitch_vxlan" )
{
return OVSWITCH_VXLAN;
}
else
{
return NONE;
@ -473,6 +479,15 @@ public:
new_vn->replace("VLAN_ID", vlan_id);
}
if ( outer_vlan_id.empty() )
{
new_vn->replace("AUTOMATIC_OUTER_VLAN_ID", "NO");
}
else
{
new_vn->replace("OUTER_VLAN_ID", outer_vlan_id);
}
return new_vn;
};
@ -507,15 +522,27 @@ private:
string phydev;
/**
* VLAN ID of the NIC
* VLAN ID of the NIC. When more than VLAN ID is used this refers to the
* link layer or outer/service VLAN_ID
*/
string vlan_id;
/**
* Used for double tagging of VM traffic. This id refers to the transport
* layer or outer/service VLAN_ID
*/
string outer_vlan_id;
/**
* If the VLAN has been set automatically
*/
bool vlan_id_automatic;
/**
* If the outer VLAN has been set automatically
*/
bool outer_vlan_id_automatic;
/**
* Parent VNET ID if any
*/
@ -536,6 +563,22 @@ private:
*/
ObjectCollection vrouters;
// *************************************************************************
// VLAN ID functions
// *************************************************************************
/**
* This function parses the VLAN attribute and clears the associated
* automatic flag if set.
* @param id_name of the VLAN attribute VLAN_ID or OUTER_VLAN_ID
* @param auto_name of automatic flag AUTOMATIC_VLAN_ID or
* AUTOMATIC_OUTER_VLAN_ID
* @param id the associated vlan variable
* @param auto the associated automatic variable
*/
void parse_vlan_id(const char * id_name, const char * auto_name,
string& id, bool& auto_id);
// *************************************************************************
// Address allocation funtions
// *************************************************************************

View File

@ -270,6 +270,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \
$VAR_LOCATION/remotes/vnm/ebtables \
$VAR_LOCATION/remotes/vnm/fw \
$VAR_LOCATION/remotes/vnm/ovswitch \
$VAR_LOCATION/remotes/vnm/ovswitch_vxlan \
$VAR_LOCATION/remotes/vnm/vcenter \
$VAR_LOCATION/remotes/tm/ \
$VAR_LOCATION/remotes/tm/dummy \
@ -435,6 +436,7 @@ INSTALL_FILES=(
NETWORK_EBTABLES_FILES:$VAR_LOCATION/remotes/vnm/ebtables
NETWORK_FW_FILES:$VAR_LOCATION/remotes/vnm/fw
NETWORK_OVSWITCH_FILES:$VAR_LOCATION/remotes/vnm/ovswitch
NETWORK_OVSWITCH_VXLAN_FILES:$VAR_LOCATION/remotes/vnm/ovswitch_vxlan
NETWORK_VCENTER_FILES:$VAR_LOCATION/remotes/vnm/vcenter
EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples
WEBSOCKIFY_SHARE_FILES:$SHARE_LOCATION/websockify
@ -896,6 +898,7 @@ NETWORK_VXLAN_FILES="src/vnm_mad/remotes/vxlan/clean \
src/vnm_mad/remotes/vxlan/post \
src/vnm_mad/remotes/vxlan/pre \
src/vnm_mad/remotes/vxlan/update_sg \
src/vnm_mad/remotes/vxlan/vxlan.rb \
src/vnm_mad/remotes/vxlan/vxlan_driver.rb"
@ -921,6 +924,12 @@ NETWORK_OVSWITCH_FILES="src/vnm_mad/remotes/ovswitch/clean \
src/vnm_mad/remotes/ovswitch/update_sg \
src/vnm_mad/remotes/ovswitch/OpenvSwitch.rb"
NETWORK_OVSWITCH_VXLAN_FILES="src/vnm_mad/remotes/ovswitch_vxlan/clean \
src/vnm_mad/remotes/ovswitch_vxlan/post \
src/vnm_mad/remotes/ovswitch_vxlan/pre \
src/vnm_mad/remotes/ovswitch_vxlan/update_sg \
src/vnm_mad/remotes/ovswitch_vxlan/OpenvSwitchVXLAN.rb"
NETWORK_VCENTER_FILES="src/vnm_mad/remotes/vcenter/pre \
src/vnm_mad/remotes/vcenter/post \
src/vnm_mad/remotes/vcenter/clean"

View File

@ -984,6 +984,7 @@ VNET_RESTRICTED_ATTR = "VLAN_ID"
VNET_RESTRICTED_ATTR = "BRIDGE"
VNET_RESTRICTED_ATTR = "CONF"
VNET_RESTRICTED_ATTR = "BRIDGE_CONF"
VNET_RESTRICTED_ATTR = "OVS_BRIDGE_CONF"
VNET_RESTRICTED_ATTR = "IP_LINK_CONF"
VNET_RESTRICTED_ATTR = "AR/VN_MAD"
@ -1057,6 +1058,7 @@ INHERIT_VNET_ATTR = "OUTBOUND_PEAK_BW"
INHERIT_VNET_ATTR = "OUTBOUND_PEAK_KB"
INHERIT_VNET_ATTR = "CONF"
INHERIT_VNET_ATTR = "BRIDGE_CONF"
INHERIT_VNET_ATTR = "OVS_BRIDGE_CONF"
INHERIT_VNET_ATTR = "IP_LINK_CONF"
INHERIT_VNET_ATTR = "VCENTER_NET_REF"

View File

@ -214,7 +214,7 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
CLIHelper.print_header(str_h1 %
["VIRTUAL NETWORK #{vn.id.to_s} INFORMATION"])
str="%-15s: %-20s"
str="%-25s: %-20s"
puts str % ["ID", vn.id.to_s]
puts str % ["NAME", vn['NAME']]
puts str % ["USER", vn['UNAME']]
@ -226,6 +226,9 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper
puts str % ["VN_MAD", vn['VN_MAD']] if !vn['VN_MAD'].empty?
puts str % ["PHYSICAL DEVICE", vn["PHYDEV"]] if !vn["PHYDEV"].empty?
puts str % ["VLAN ID", vn["VLAN_ID"]] if !vn["VLAN_ID"].empty?
puts str % ["AUTOMATIC VLAN ID", vn["VLAN_ID_AUTOMATIC"]=="1" ? "YES" : "NO"]
puts str % ["OUTER VLAN ID", vn["OUTER_VLAN_ID"]] if !vn["OUTER_VLAN_ID"].empty?
puts str % ["AUTOMATIC OUTER VLAN ID", vn["OUTER_VLAN_ID_AUTOMATIC"]=="1" ? "YES" : "NO"]
puts str % ["USED LEASES", vn['USED_LEASES']]
puts

View File

@ -171,6 +171,13 @@ define(function(require) {
$("#vnetCreateSecurityTab-label").hide();
$("div.mode_param.ovswitch [wizard_field]", context).prop("wizard_field_disabled", false);
$("input#bridge", context).attr("required", "");
break;
case "ovswitch_vxlan":
$("div.mode_param.ovswitch_vxlan", context).show();
$("#vnetCreateSecurityTab-label").hide();
$("div.mode_param.ovswitch_vxlan [wizard_field]", context).prop("wizard_field_disabled", false);
$("input#bridge", context).attr("required", "");
break;
case "vcenter":
@ -219,9 +226,18 @@ define(function(require) {
}
});
$("select[wizard_field=AUTOMATIC_OUTER_VLAN_ID]", context).change(function(){
if($(this).val() != "") {
$("input[wizard_field=\"OUTER_VLAN_ID\"]", context).hide().prop("wizard_field_disabled", true);
} else {
$("input[wizard_field=\"OUTER_VLAN_ID\"]", context).show().prop("wizard_field_disabled", false);
}
});
//Initialize shown options
$("#network_mode", context).trigger("change");
$("select[wizard_field=AUTOMATIC_VLAN_ID]", context).trigger("change");
$("select[wizard_field=AUTOMATIC_OUTER_VLAN_ID]", context).trigger("change");
this.securityGroupsTable.initialize();
@ -243,6 +259,7 @@ define(function(require) {
$("#network_mode option[value=\"802.1Q\"]", context).hide();
$("#network_mode option[value=\"vxlan\"]", context).hide();
$("#network_mode option[value=\"ovswitch\"]", context).hide();
$("#network_mode option[value=\"ovswitch_vxlan\"]", context).hide();
}
return false;
}
@ -393,6 +410,14 @@ define(function(require) {
attr("disabled", "disabled").trigger("change");
}
if (element.OUTER_VLAN_ID_AUTOMATIC== 1){
$("select[wizard_field=AUTOMATIC_OUTER_VLAN_ID]", context).val("YES").
attr("disabled", "disabled").trigger("change");
} else {
$("select[wizard_field=AUTOMATIC_OUTER_VLAN_ID]", context).val("").
attr("disabled", "disabled").trigger("change");
}
WizardFields.fill($("#vnetCreateGeneralTab", context), element.TEMPLATE);
WizardFields.fill($("#vnetCreateBridgeTab", context), element.TEMPLATE);
WizardFields.fill($("#vnetCreateQoSTab", context), element.TEMPLATE);

View File

@ -87,6 +87,7 @@
<option value="802.1Q">{{tr "802.1Q"}}</option>
<option value="vxlan">{{tr "VXLAN"}}</option>
<option value="ovswitch">{{tr "Open vSwitch"}}</option>
<option value="ovswitch_vxlan">{{tr "Open vSwitch - VXLAN"}}</option>
<option value="vcenter">{{tr "vCenter"}}</option>
<option value="custom">{{tr "Custom"}}</option>
</select>
@ -116,6 +117,9 @@
<div class="network_mode_description" value="ovswitch">
{{tr "Open vSwitch, restrict network access with Open vSwitch Virtual Switch. Security Groups are not applied."}}
</div>
<div class="network_mode_description" value="ovswitch_vxlan">
{{tr "Open vSwitch on VXLAN L2 network overlay. Security Groups are not applied."}}
</div>
<div class="network_mode_description" value="vcenter">
{{tr "vSphere standard switches or distributed switches with port groups. Security Groups are not applied."}}
</div>
@ -126,7 +130,7 @@
</div>
<br>
<div class="row">
<div class="large-6 columns mode_param ebtables 8021Q vxlan fw ovswitch custom">
<div class="large-6 columns mode_param ebtables 8021Q vxlan fw ovswitch ovswitch_vxlan custom">
<label for="mac_spoofing">
<input type="checkbox" wizard_field="FILTER_MAC_SPOOFING" value="YES" name="mac_spoofing" id="mac_spoofing" />
{{tr "MAC spoofing filter"}}
@ -134,7 +138,7 @@
</div>
</div>
<div class="row">
<div class="large-6 columns mode_param ebtables 8021Q vxlan fw ovswitch custom">
<div class="large-6 columns mode_param ebtables 8021Q vxlan fw ovswitch ovswitch_vxlan custom">
<label for="ip_spoofing">
<input type="checkbox" wizard_field="FILTER_IP_SPOOFING" value="YES" name="ip_spoofing" id="ip_spoofing" />
{{tr "IP spoofing filter"}}
@ -143,7 +147,7 @@
</div>
</div>
<div class="row">
<div class="medium-3 columns left mode_param 8021Q vxlan ovswitch vcenter custom">
<div class="medium-3 columns left mode_param 8021Q vxlan ovswitch ovswitch_vxlan vcenter custom">
<label>
{{tr "VLAN ID"}}
<select wizard_field="AUTOMATIC_VLAN_ID">
@ -154,7 +158,7 @@
<input type="number" wizard_field="VLAN_ID"/>
</label>
</div>
<div class="medium-3 columns left mode_param 8021Q vxlan custom">
<div class="medium-3 columns left mode_param 8021Q vxlan ovswitch_vxlan custom">
<label for="phydev">
{{tr "Physical device"}}
<span class="tip">
@ -172,12 +176,25 @@
</label>
<input type="text" wizard_field="PHYDEV" name="phydev" id="phydev" />
</div>
<div class="medium-3 columns left mode_param 8021Q vxlan vcenter custom">
<div class="medium-3 columns left mode_param 8021Q vxlan ovswitch_vxlan vcenter custom">
<label for="mtu">
{{tr "MTU of the interface"}}
</label>
<input type="text" wizard_field="MTU" name="mtu" id="mtu" />
</div>
<div class="medium-3 columns left mode_param ovswitch_vxlan">
<label>
{{tr "Outer VLAN ID"}}
<span class="tip">
{{tr "First level (outer, service) VLAN ID"}}
</span>
<select wizard_field="AUTOMATIC_OUTER_VLAN_ID">
<option value="YES">{{tr "Automatic Outer VLAN ID"}}</option>
<option value="">{{tr "Manual Outer VLAN ID"}}</option>
</select>
<input type="text" wizard_field="OUTER_VLAN_ID" name="outer_vlan_id" id="outer_vlan_id" />
</label>
</div>
</div>
<div class="row">
<div class="medium-3 columns left mode_param vcenter">

View File

@ -117,6 +117,16 @@ define(function(require) {
$(".reserve-sunstone-info").removeAttr("title");
}
//====
var auto_vlan_id = Locale.tr("NO");
var auto_outer_vlan_id = Locale.tr("NO");
if (this.element.VLAN_ID_AUTOMATIC == "1") {
auto_vlan_id = Locale.tr("YES");
}
if (this.element.OUTER_VLAN_ID_AUTOMATIC == "1") {
auto_outer_vlan_id = Locale.tr("YES");
}
return TemplateInfo({
'element': this.element,
@ -124,7 +134,9 @@ define(function(require) {
'reservationTrHTML': reservationTrHTML,
'permissionsTableHTML': permissionsTableHTML,
'templateTableHTML': templateTableHTML,
'templateTableVcenterHTML': templateTableVcenterHTML
'templateTableVcenterHTML': templateTableVcenterHTML,
'autoVlanID': auto_vlan_id,
'autoOuterVlanID': auto_outer_vlan_id,
});
}

View File

@ -35,6 +35,21 @@
<td class="value_td">{{valOrDefault element.VLAN_ID "--"}}</td>
<td></td>
</tr>
<tr>
<td class="key_td">{{tr "AUTO VLAN ID"}}</td>
<td class="value_td">{{autoVlanID}}</td>
<td></td>
</tr>
<tr>
<td class="key_td">{{tr "OUTER VLAN ID"}}</td>
<td class="value_td">{{valOrDefault element.OUTER_VLAN_ID "--"}}</td>
<td></td>
</tr>
<tr>
<td class="key_td">{{tr "AUTO OUTER VLAN ID"}}</td>
<td class="value_td">{{autoOuterVlanID}}</td>
<td></td>
</tr>
<tbody>
</table>
</div>

View File

@ -929,8 +929,8 @@ int LibVirtDriver::deployment_description_kvm(
{
file << "\t\t<interface type='bridge'>" << endl;
if (VirtualNetwork::str_to_driver(vn_mad) == VirtualNetwork::OVSWITCH)
if (VirtualNetwork::str_to_driver(vn_mad) == VirtualNetwork::OVSWITCH ||
VirtualNetwork::str_to_driver(vn_mad) == VirtualNetwork::OVSWITCH_VXLAN)
{
file << "\t\t\t<virtualport type='openvswitch'/>" << endl;
}

View File

@ -34,7 +34,9 @@ if [ -z "${BRIDGE}" ]; then
DEVICE+="<interface type='ethernet'>"
else
DEVICE+="<interface type='bridge'>"
[ "${VN_MAD}" = 'ovswitch' ] && DEVICE+=" <virtualport type='openvswitch'/>"
if [ "${VN_MAD}" = 'ovswitch' ] || [ "${VN_MAD}" = 'ovswitch_vxlan' ]; then
DEVICE+=" <virtualport type='openvswitch'/>"
fi
DEVICE+=" <source bridge='$(xml_esc "${BRIDGE}")'/>"
fi

View File

@ -46,6 +46,7 @@ VirtualNetwork::VirtualNetwork(int _uid,
Clusterable(_cluster_ids),
bridge(""),
vlan_id_automatic(false),
outer_vlan_id_automatic(false),
parent_vid(_pvid),
vrouters("VROUTERS")
{
@ -98,6 +99,30 @@ const char * VirtualNetwork::db_bootstrap = "CREATE TABLE IF NOT EXISTS"
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
void VirtualNetwork::parse_vlan_id(const char * id_name, const char * auto_name,
string& id, bool& auto_id)
{
string vis;
if ( PoolObjectSQL::get_template_attribute(id_name, vis) && !vis.empty() )
{
erase_template_attribute(id_name, id);
add_template_attribute(id_name, id);
remove_template_attribute(auto_name);
auto_id = false;
}
else
{
erase_template_attribute(auto_name, auto_id);
}
}
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetwork::insert(SqlDB * db, string& error_str)
{
vector<VectorAttribute *> ars;
@ -137,22 +162,12 @@ int VirtualNetwork::insert(SqlDB * db, string& error_str)
add_template_attribute("PHYDEV", phydev);
// ---- VLAN_ID if not set allocated in VirtualNetworkPool, if needed -----
// ---- VLAN_IDs if not set will be allocated in VirtualNetworkPool -----
if (PoolObjectSQL::get_template_attribute("VLAN_ID", vis) && !vis.empty())
{
erase_template_attribute("VLAN_ID", vlan_id);
parse_vlan_id("VLAN_ID", "AUTOMATIC_VLAN_ID", vlan_id, vlan_id_automatic);
add_template_attribute("VLAN_ID", vlan_id);
remove_template_attribute("AUTOMATIC_VLAN_ID");
vlan_id_automatic = false;
}
else
{
erase_template_attribute("AUTOMATIC_VLAN_ID", vlan_id_automatic);
}
parse_vlan_id("OUTER_VLAN_ID", "AUTOMATIC_OUTER_VLAN_ID", outer_vlan_id,
outer_vlan_id_automatic);
// ------------ BRIDGE --------------------
@ -284,6 +299,8 @@ int VirtualNetwork::post_update_template(string& error)
remove_template_attribute("AUTOMATIC_VLAN_ID");
remove_template_attribute("AUTOMATIC_OUTER_VLAN_ID");
if (!vlan_id_automatic)
{
erase_template_attribute("VLAN_ID", vlan_id);
@ -294,6 +311,16 @@ int VirtualNetwork::post_update_template(string& error)
remove_template_attribute("VLAN_ID");
}
if (!outer_vlan_id_automatic)
{
erase_template_attribute("OUTER_VLAN_ID", outer_vlan_id);
add_template_attribute("OUTER_VLAN_ID", outer_vlan_id);
}
else
{
remove_template_attribute("OUTER_VLAN_ID");
}
erase_template_attribute("BRIDGE",new_bridge);
if (!new_bridge.empty())
@ -431,6 +458,7 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended,
string lock_str;
int int_vlan_id_automatic = vlan_id_automatic ? 1 : 0;
int int_outer_vlan_id_automatic = outer_vlan_id_automatic ? 1 : 0;
os <<
"<VNET>" <<
@ -481,8 +509,21 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended,
os << "<VLAN_ID/>";
}
if (!outer_vlan_id.empty())
{
os << "<OUTER_VLAN_ID>" << one_util::escape_xml(outer_vlan_id)
<< "</OUTER_VLAN_ID>";
}
else
{
os << "<OUTER_VLAN_ID/>";
}
os << "<VLAN_ID_AUTOMATIC>" << int_vlan_id_automatic <<"</VLAN_ID_AUTOMATIC>";
os << "<OUTER_VLAN_ID_AUTOMATIC>" << int_outer_vlan_id_automatic
<< "</OUTER_VLAN_ID_AUTOMATIC>";
os << "<USED_LEASES>"<< ar_pool.get_used_addr() << "</USED_LEASES>";
os << vrouters.to_xml(vrouters_xml);
@ -506,7 +547,9 @@ int VirtualNetwork::from_xml(const string &xml_str)
vector<xmlNodePtr> content;
int rc = 0;
int int_vlan_id_automatic;
int int_outer_vlan_id_automatic;
// Initialize the internal XML object
update_from_str(xml_str);
@ -527,11 +570,17 @@ int VirtualNetwork::from_xml(const string &xml_str)
xpath(vn_mad, "/VNET/VN_MAD", "");
xpath(phydev, "/VNET/PHYDEV", "");
xpath(vlan_id,"/VNET/VLAN_ID","");
xpath(vlan_id, "/VNET/VLAN_ID", "");
xpath(outer_vlan_id, "/VNET/OUTER_VLAN_ID", "");
xpath(int_vlan_id_automatic, "/VNET/VLAN_ID_AUTOMATIC", 0);
xpath(int_outer_vlan_id_automatic, "/VNET/OUTER_VLAN_ID_AUTOMATIC", 0);
xpath(parent_vid,"/VNET/PARENT_NETWORK_ID",-1);
xpath(int_vlan_id_automatic,"/VNET/VLAN_ID_AUTOMATIC",0);
vlan_id_automatic = int_vlan_id_automatic;
outer_vlan_id_automatic = int_outer_vlan_id_automatic;
// Set of cluster IDs
rc += Clusterable::from_xml(this, "/VNET/");
@ -621,6 +670,11 @@ int VirtualNetwork::nic_attribute(
nic->replace("VLAN_ID", vlan_id);
}
if (!outer_vlan_id.empty())
{
nic->replace("OUTER_VLAN_ID", outer_vlan_id);
}
if (parent_vid != -1)
{
nic->replace("PARENT_NETWORK_ID", parent_vid);

View File

@ -342,67 +342,124 @@ void VirtualNetworkPool::authorize_nic(
/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */
int VirtualNetworkPool::set_vlan_id(VirtualNetwork * vn)
static int set_8021Q_id(int vnid, string& vlan_var, bool& auto_var,
BitMap<4096>& bitmap)
{
string vn_mad;
unsigned int start_vlan, hint_vlan;
unsigned int vlan_id;
ostringstream oss;
if ( !vn->vlan_id.empty() || !vn->vlan_id_automatic )
if ( !vlan_var.empty() || !auto_var )
{
return 0;
}
unsigned int vlan_id;
ostringstream oss;
unsigned int start_vlan = bitmap.get_start_bit();
unsigned int hint_vlan = start_vlan + (vnid % (4095 - start_vlan));
if ( bitmap.get(hint_vlan, vlan_id) != 0 )
{
return -1;
}
oss << vlan_id;
vlan_var = oss.str();
auto_var = true;
return vlan_id;
}
static int set_vxlan_id(int vnid, string& vlan_var, bool& auto_var,
unsigned int start_vlan)
{
if ( !vlan_var.empty() || !auto_var )
{
return 0;
}
ostringstream oss;
unsigned int vlan_id = start_vlan + vnid;
oss << vlan_id;
vlan_var = oss.str();
auto_var = true;
return vlan_id;
}
int VirtualNetworkPool::set_vlan_id(VirtualNetwork * vn)
{
unsigned int start_vlan;
int rc, rcx;
if ( vn->vn_mad.empty() )
{
return 0;
}
if (vxlan_conf.vector_value("START", start_vlan) != 0)
{
start_vlan = 2; //default in oned.conf
}
switch (VirtualNetwork::str_to_driver(vn->vn_mad))
{
case VirtualNetwork::VXLAN:
if (vxlan_conf.vector_value("START", start_vlan) != 0)
case VirtualNetwork::OVSWITCH_VXLAN:
rc = set_8021Q_id(vn->get_oid(), vn->vlan_id, vn->vlan_id_automatic,
vlan_id_bitmap);
if ( rc == -1 )
{
start_vlan = 2; //default in oned.conf
return -1;
}
else if ( rc != 0 )
{
vlan_id_bitmap.update(db);
}
vlan_id = start_vlan + vn->get_oid();
oss << vlan_id;
rcx = set_vxlan_id(vn->get_oid(), vn->outer_vlan_id,
vn->outer_vlan_id_automatic, start_vlan);
vn->vlan_id = oss.str();
if ( rc != 0 || rcx != 0 )
{
update(vn);
}
break;
vn->vlan_id_automatic = true;
update(vn);
case VirtualNetwork::VXLAN:
rcx = set_vxlan_id(vn->get_oid(), vn->vlan_id, vn->vlan_id_automatic,
start_vlan);
if ( rcx != 0 )
{
update(vn);
}
break;
case VirtualNetwork::VLAN:
case VirtualNetwork::VCENTER:
case VirtualNetwork::OVSWITCH:
start_vlan = vlan_id_bitmap.get_start_bit();
hint_vlan = start_vlan + (vn->get_oid() % (4095 - start_vlan ));
rc = set_8021Q_id(vn->get_oid(), vn->vlan_id, vn->vlan_id_automatic,
vlan_id_bitmap);
if ( vlan_id_bitmap.get(hint_vlan, vlan_id) != 0 )
if ( rc == -1 )
{
return -1;
}
oss << vlan_id;
vn->vlan_id = oss.str();
vn->vlan_id_automatic = true;
vlan_id_bitmap.update(db);
update(vn);
else if ( rc != 0 )
{
vlan_id_bitmap.update(db);
update(vn);
}
break;
default:
case VirtualNetwork::NONE:
case VirtualNetwork::DUMMY:
case VirtualNetwork::EBTABLES:
case VirtualNetwork::FW:
break;
}
@ -439,7 +496,9 @@ void VirtualNetworkPool::release_vlan_id(VirtualNetwork *vn)
switch (VirtualNetwork::str_to_driver(vn->vn_mad))
{
case VirtualNetwork::VLAN:
case VirtualNetwork::VCENTER:
case VirtualNetwork::OVSWITCH:
case VirtualNetwork::OVSWITCH_VXLAN:
vlan_id_bitmap.reset(vlan_id);
vlan_id_bitmap.update(db);
break;

View File

@ -23,6 +23,7 @@
#
# CONF="vxlan_mc=239.0.100.0,test=false,validate_vlan_id=true"
# BRIDGE_CONF="sethello=6"
# OVS_BRIDGE_CONF="stp_enable=true"
# IP_LINK_CONF="tos=10,udpcsum=,udp6zerocsumrx=__delete__"
#
# Options can have empty value when they don't need a parameter. Also the
@ -77,6 +78,15 @@
# :stp: on
# These options are set on the OvS bridge. For example,
# this command will be trigged for the following option:
#
# ovs-vsctl set-bridge <bridge name> stp_enable=true
#
# :ovs_bridge_conf:
# :stp_enable: true
# These options will be added to the ip link add command. For example:
#
# sudo ip link add lxcbr0.260 type vxlan id 260 group 239.0.101.4 \

View File

@ -73,6 +73,7 @@ module VNMMAD
blk = lambda do |nic|
add_nic_conf(nic)
add_bridge_conf(nic)
add_ovs_bridge_conf(nic)
add_ip_link_conf(nic)
block.call(nic)
@ -106,6 +107,10 @@ module VNMMAD
add_command_conf(nic, :bridge_conf)
end
def add_ovs_bridge_conf(nic)
add_command_conf(nic, :ovs_bridge_conf)
end
def add_ip_link_conf(nic)
add_command_conf(nic, :ip_link_conf)
end

View File

@ -34,16 +34,44 @@ class OpenvSwitchVLAN < VNMMAD::VNMDriver
end
end
def activate
def activate(pre_action=false)
lock
@bridges = get_bridges
process do |nic|
@nic = nic
# Get the name of the link vlan device.
get_vlan_dev_name
# Create the bridge.
create_bridge
# Check that no other vlans are connected to this bridge
validate_vlan_id if @nic[:conf][:validate_vlan_id]
if @nic[:vlan_dev]
unless @bridges[@nic[:bridge]].include? @nic[:vlan_dev]
create_vlan_dev
add_bridge_port(@nic[:vlan_dev])
end
elsif @nic[:phydev]
add_bridge_port(@nic[:phydev])
end
if @nic[:tap].nil?
STDERR.puts "No tap device found for nic #{@nic[:nic_id]}"
unlock
exit 1
# In net/pre action, we just need to ensure the bridge is
# created so the libvirt/QEMU can add VM interfaces into that.
# Any other driver actions are done in net/post action.
if pre_action
next
else
STDERR.puts "No tap device found for nic #{@nic[:nic_id]}"
unlock
exit 1
end
end
# Apply VLAN
@ -96,6 +124,8 @@ class OpenvSwitchVLAN < VNMMAD::VNMDriver
def deactivate
lock
@bridges = get_bridges
attach_nic_id = @vm['TEMPLATE/NIC[ATTACH="YES"]/NIC_ID']
process do |nic|
@ -107,6 +137,27 @@ class OpenvSwitchVLAN < VNMMAD::VNMDriver
# Remove flows
del_flows
next if @nic[:phydev].nil?
next if @bridges[@nic[:bridge]].nil?
# Get the name of the vlan device.
get_vlan_dev_name
# Return if the bridge doesn't exist because it was already deleted (handles last vm with multiple nics on the same vlan)
next if !@bridges.include? @nic[:bridge]
# Return if the vlan device is not the only left device in the bridge.
next if @bridges[@nic[:bridge]].length > 1 or
(@nic[:vlan_dev] and
!@bridges[@nic[:bridge]].include? @nic[:vlan_dev])
if @nic[:vlan_dev]
delete_vlan_dev
@bridges[@nic[:bridge]].delete(@nic[:vlan_dev])
end
delete_bridge
end
unlock
@ -287,4 +338,84 @@ class OpenvSwitchVLAN < VNMMAD::VNMDriver
def range?(range)
!range.to_s.match(/^\d+(,\d+)*$/).nil?
end
private
# Generate the name of the vlan device which will be added to the bridge.
def get_vlan_dev_name
nil
end
# Create a VLAN device.
# NEEDS to be implemented by the subclass.
def create_vlan_dev
nil
end
# Delete a VLAN device
# NEEDS to be implemented by the subclass.
def delete_vlan_dev
nil
end
# Creates an OvS bridge if it does not exists, and brings it up.
# This function IS FINAL, exits if action cannot be completed
def create_bridge
return if @bridges.keys.include? @nic[:bridge]
OpenNebula.exec_and_log("#{command(:ovs_vsctl)} add-br #{@nic[:bridge]}")
set_bridge_options
@bridges[@nic[:bridge]] = Array.new
OpenNebula.exec_and_log("#{command(:ip)} link set #{@nic[:bridge]} up")
end
# Delete OvS bridge
def delete_bridge
OpenNebula.exec_and_log("#{command(:ovs_vsctl)} del-br #{@nic[:bridge]}")
@bridges.delete(@nic[:bridge])
end
# Add port into OvS bridge
def add_bridge_port(port)
return if @bridges[@nic[:bridge]].include? port
OpenNebula.exec_and_log("#{command(:ovs_vsctl)} add-port #{@nic[:bridge]} #{port}")
@bridges[@nic[:bridge]] << port
end
# Calls ovs-vsctl set bridge to set options stored in ovs_bridge_conf
def set_bridge_options
@nic[:ovs_bridge_conf].each do |option, value|
cmd = "#{command(:ovs_vsctl)} set bridge " <<
"#{@nic[:bridge]} #{option}=#{value}"
OpenNebula.exec_and_log(cmd)
end
end
# Get hypervisor bridges
# @return [Hash<String>] with the bridge names
def get_bridges
bridges = Hash.new
list_br =`#{command(:ovs_vsctl)} list-br`
list_br.split.each do |bridge|
bridge = bridge.strip
if bridge
list_ports =`#{command(:ovs_vsctl)} list-ports #{bridge}`
bridges[bridge] = list_ports.split("\n")
end
end
bridges
end
def validate_vlan_id
OpenNebula.log_error("VLAN ID validation not supported with Open vSwitch, skipped.")
end
end

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, OpenNebula Project, OpenNebula Systems #
@ -16,4 +16,15 @@
# limitations under the License. #
#--------------------------------------------------------------------------- #
exit 0
$: << File.dirname(__FILE__)
$: << File.join(File.dirname(__FILE__), "..")
require 'OpenvSwitch'
template64 = ARGV[0]
deploy_id = ARGV[1]
xpath_filter = OpenvSwitchVLAN::XPATH_FILTER
ovs = OpenvSwitchVLAN.from_base64(template64, xpath_filter, deploy_id)
ovs.activate(pre_action=true)

View File

@ -0,0 +1,44 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, 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. #
#--------------------------------------------------------------------------- #
require 'vnmmad'
require 'ovswitch/OpenvSwitch'
require 'vxlan/vxlan'
class OpenvSwitchVXLAN < OpenvSwitchVLAN
include VXLAN
# VXLAN orrides
ATTR_VLAN_ID = :outer_vlan_id
# DRIVER name and XPATH for relevant NICs
DRIVER = "ovswitch_vxlan"
XPATH_FILTER = "TEMPLATE/NIC[VN_MAD='ovswitch_vxlan']"
def initialize(vm, xpath_filter = nil, deploy_id = nil)
@attr_vlan_id = ATTR_VLAN_ID
@attr_vlan_dev = ATTR_VLAN_DEV
xpath_filter ||= XPATH_FILTER
super(vm, xpath_filter, deploy_id)
end
private
# Generate the name of the vlan device which will be added to the bridge.
def get_vlan_dev_name
@nic[:vlan_dev] = "#{@nic[:phydev]}.#{@nic[@attr_vlan_id]}"
end
end

View File

@ -0,0 +1,29 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, 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. #
#--------------------------------------------------------------------------- #
$: << File.dirname(__FILE__)
$: << File.join(File.dirname(__FILE__), "..")
require 'OpenvSwitchVXLAN'
template64 = ARGV[0]
deploy_id = nil
xpath_filter = OpenvSwitchVXLAN::XPATH_FILTER
ovs = OpenvSwitchVXLAN.from_base64(template64, xpath_filter, deploy_id)
ovs.deactivate

View File

@ -0,0 +1,30 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, 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. #
#--------------------------------------------------------------------------- #
$: << File.dirname(__FILE__)
$: << File.join(File.dirname(__FILE__), "..")
require 'OpenvSwitchVXLAN'
template64 = ARGV[0]
deploy_id = ARGV[1]
xpath_filter = OpenvSwitchVXLAN::XPATH_FILTER
ovs = OpenvSwitchVXLAN.from_base64(template64, xpath_filter, deploy_id)
ovs.activate

View File

@ -0,0 +1,30 @@
#!/usr/bin/env ruby
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, 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. #
#--------------------------------------------------------------------------- #
$: << File.dirname(__FILE__)
$: << File.join(File.dirname(__FILE__), "..")
require 'OpenvSwitchVXLAN'
template64 = ARGV[0]
deploy_id = ARGV[1]
xpath_filter = OpenvSwitchVXLAN::XPATH_FILTER
ovs = OpenvSwitchVXLAN.from_base64(template64, xpath_filter, deploy_id)
ovs.activate(pre_action=true)

View File

@ -0,0 +1,21 @@
#!/bin/bash
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, 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. #
#--------------------------------------------------------------------------- #
source $(dirname $0)/../../scripts_common.sh
log_error "Security groups not supported for ovswitch"
exit 1

View File

@ -0,0 +1,75 @@
# -------------------------------------------------------------------------- #
# Copyright 2002-2018, 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. #
#--------------------------------------------------------------------------- #
require 'ipaddr'
module VXLAN
ATTR_VLAN_ID = :vlan_id
ATTR_VLAN_DEV = :vlan_dev
############################################################################
# This function creates and activate a VLAN device
############################################################################
def create_vlan_dev
begin
ipaddr = IPAddr.new @nic[:conf][:vxlan_mc]
rescue
ipaddr = IPAddr.new "239.0.0.0"
end
mc = ipaddr.to_i + @nic[@attr_vlan_id].to_i
mcs = IPAddr.new(mc, Socket::AF_INET).to_s
mtu = @nic[:mtu] ? "mtu #{@nic[:mtu]}" : "mtu #{@nic[:conf][:vxlan_mtu]}"
ttl = @nic[:conf][:vxlan_ttl] ? "ttl #{@nic[:conf][:vxlan_ttl]}" : ""
ip_link_conf = ""
@nic[:ip_link_conf].each do |option, value|
case value
when true
value = "on"
when false
value = "off"
end
ip_link_conf << "#{option} #{value} "
end
OpenNebula.exec_and_log("#{command(:ip)} link add #{@nic[@attr_vlan_dev]}"\
" #{mtu} type vxlan id #{@nic[@attr_vlan_id]} group #{mcs} #{ttl}"\
" dev #{@nic[:phydev]} #{ip_link_conf}")
OpenNebula.exec_and_log("#{command(:ip)} link set #{@nic[@attr_vlan_dev]} up")
end
def delete_vlan_dev
OpenNebula.exec_and_log("#{command(:ip)} link delete #{@nic[@attr_vlan_dev]}")
end
def get_interface_vlan(name)
text = %x(#{command(:ip)} -d link show #{name})
return nil if $?.exitstatus != 0
text.each_line do |line|
m = line.match(/^\s*vxlan id (\d+)/)
return m[1] if m
end
nil
end
end

View File

@ -15,7 +15,7 @@
#--------------------------------------------------------------------------- #
require 'vnmmad'
require 'ipaddr'
require 'vxlan'
################################################################################
# This driver tag VM traffic with a VLAN_ID using VXLAN protocol. Features:
@ -25,6 +25,7 @@ require 'ipaddr'
# Once activated the VM will be attached to this bridge
################################################################################
class VXLANDriver < VNMMAD::VLANDriver
include VXLAN
# DRIVER name and XPATH for relevant NICs
DRIVER = "vxlan"
@ -36,56 +37,10 @@ class VXLANDriver < VNMMAD::VLANDriver
def initialize(vm, xpath_filter = nil, deploy_id = nil)
@locking = true
@attr_vlan_id = ATTR_VLAN_ID
@attr_vlan_dev = ATTR_VLAN_DEV
xpath_filter ||= XPATH_FILTER
super(vm, xpath_filter, deploy_id)
end
############################################################################
# This function creates and activate a VLAN device
############################################################################
def create_vlan_dev
begin
ipaddr = IPAddr.new @nic[:conf][:vxlan_mc]
rescue
ipaddr = IPAddr.new "239.0.0.0"
end
mc = ipaddr.to_i + @nic[:vlan_id].to_i
mcs = IPAddr.new(mc, Socket::AF_INET).to_s
mtu = @nic[:mtu] ? "mtu #{@nic[:mtu]}" : "mtu #{@nic[:conf][:vxlan_mtu]}"
ttl = @nic[:conf][:vxlan_ttl] ? "ttl #{@nic[:conf][:vxlan_ttl]}" : ""
ip_link_conf = ""
@nic[:ip_link_conf].each do |option, value|
case value
when true
value = "on"
when false
value = "off"
end
ip_link_conf << "#{option} #{value} "
end
OpenNebula.exec_and_log("#{command(:ip)} link add #{@nic[:vlan_dev]}"\
" #{mtu} type vxlan id #{@nic[:vlan_id]} group #{mcs} #{ttl}"\
" dev #{@nic[:phydev]} #{ip_link_conf}")
OpenNebula.exec_and_log("#{command(:ip)} link set #{@nic[:vlan_dev]} up")
end
def get_interface_vlan(name)
text = %x(#{command(:ip)} -d link show #{name})
return nil if $?.exitstatus != 0
text.each_line do |line|
m = line.match(/^\s*vxlan id (\d+)/)
return m[1] if m
end
nil
end
end