1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-11-01 03:54:15 +00:00

add macvtap support : create macvtap virtual net, add/edit instance network for macvtap

This commit is contained in:
catborise 2020-07-21 14:56:00 +03:00
parent 46884304b0
commit 015719b952
9 changed files with 90 additions and 67 deletions

View file

@ -353,6 +353,7 @@
<input name="set_link_state" value="{{ network.state }}" hidden/> <input name="set_link_state" value="{{ network.state }}" hidden/>
<input type="checkbox" {% if network.state == 'up' %} checked{% endif %} onclick='submit();' /> <input type="checkbox" {% if network.state == 'up' %} checked{% endif %} onclick='submit();' />
<strong>{% trans 'active' %}</strong> <strong>{% trans 'active' %}</strong>
<small>{{ network.type }}</small>
</form> </form>
</td> </td>
<th class="d-none d-table-cell d-sm-table-cell">{% trans 'MAC' %}</th> <th class="d-none d-table-cell d-sm-table-cell">{% trans 'MAC' %}</th>
@ -390,10 +391,10 @@
<input class="form-control" type="text" value="{{ network.nic }}" readonly/> <input class="form-control" type="text" value="{{ network.nic }}" readonly/>
<select class="form-control" name="net-source-{{ forloop.counter0 }}"> <select class="form-control" name="net-source-{{ forloop.counter0 }}">
{% for c_net in networks_host %} {% for c_net in networks_host %}
<option value="net:{{ c_net }}" {% if c_net == network.nic %} selected {% endif %}>{% trans 'Network' %} {{ c_net }}</option> <option value="net:{{ c_net }}" {% if c_net == network.nic %} selected {% endif %}>{% trans 'Network' %} {{ c_net }}</option>
{% endfor %} {% endfor %}
{% for c_iface in interfaces_host %} {% for c_iface in interfaces_host %}
<option value="iface:{{ c_iface }}" {% if c_iface == network.nic %} selected {% endif %}>{% trans 'Interface' %} {{ c_iface }}</option> <option value="iface:{{ c_iface }}" {% if c_iface == network.nic %} selected {% endif %}>{% trans 'Interface' %} {{ c_iface }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -405,7 +406,7 @@
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}"> <select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
<option value="">{% trans "None" %}</option> <option value="">{% trans "None" %}</option>
{% for c_filters in nwfilters_host %} {% for c_filters in nwfilters_host %}
<option value="{{ c_filters }}" {% if c_filters == network.filterref %} selected {% endif %}>{{ c_filters }}</option> <option value="{{ c_filters }}" {% if c_filters == network.filterref %} selected {% endif %}>{{ c_filters }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -462,7 +463,11 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td class="bg-primary" colspan="9"></td> <td class="py-1 bg-primary text-white" colspan="9">
{% if network.type == 'direct' %}
<small>{% trans 'In most configurations, macvtap does not work for host to guest network communication' %}</small>
{% endif %}
</td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>

View file

@ -965,8 +965,8 @@ def set_qos(request, pk):
else: else:
messages.success( messages.success(
request, request,
_(f"{qos_dir.capitalize()} QoS is set. Network XML is changed.") + _(f"{qos_dir.capitalize()} QoS is set. Network XML is changed. \
_("Stop and start network to activate new config"), Stop and start network to activate new config.")
) )
return redirect(request.META.get('HTTP_REFERER') + '#network') return redirect(request.META.get('HTTP_REFERER') + '#network')
@ -984,8 +984,8 @@ def unset_qos(request, pk):
else: else:
messages.success( messages.success(
request, request,
_(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. ") + _(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. \
_("Stop and start network to activate new config."), Stop and start network to activate new config.")
) )
return redirect(request.META.get('HTTP_REFERER') + '#network') return redirect(request.META.get('HTTP_REFERER') + '#network')

View file

@ -46,7 +46,7 @@ class AddNetPool(forms.Form):
def clean_bridge_name(self): def clean_bridge_name(self):
bridge_name = self.cleaned_data['bridge_name'] bridge_name = self.cleaned_data['bridge_name']
if self.cleaned_data['forward'] == 'bridge': if self.cleaned_data['forward'] in ['bridge', 'macvtap']:
have_symbol = re.match('^[a-zA-Z0-9\.\_\:\-]+$', bridge_name) have_symbol = re.match('^[a-zA-Z0-9\.\_\:\-]+$', bridge_name)
if not have_symbol: if not have_symbol:
raise forms.ValidationError(_('The pool bridge name must not contain any special characters')) raise forms.ValidationError(_('The pool bridge name must not contain any special characters'))

View file

@ -28,6 +28,7 @@
<option value="route">{% trans "ROUTE" %}</option> <option value="route">{% trans "ROUTE" %}</option>
<option value="none">{% trans "ISOLATE" %}</option> <option value="none">{% trans "ISOLATE" %}</option>
<option value="bridge">{% trans "BRIDGE" %}</option> <option value="bridge">{% trans "BRIDGE" %}</option>
<option value="macvtap">{% trans "MACVTAP" %}</option>
</select> </select>
</div> </div>
</div> </div>
@ -55,25 +56,25 @@
<input type="checkbox" id="enable_ipv6" name="enable_ipv6" value="false"> <input type="checkbox" id="enable_ipv6" name="enable_ipv6" value="false">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group_dhcp ipv6_group"> <div class="form-group row ipv6_group">
<label class="col-sm-4 col-form-label">{% trans "IPv6 Subnet pool" %}</label> <label class="col-sm-4 col-form-label">{% trans "IPv6 Subnet pool" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="subnet6" value="" placeholder="fd00:dead:baba:1::/64" required pattern="[0-9\/\.]+"> <input type="text" class="form-control" name="subnet6" value="" placeholder="fd00:dead:baba:1::/64" required pattern="[0-9\/\.]+">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group_dhcp ipv6_group"> <div class="form-group row ipv6_group">
<label class="col-sm-4 col-form-label">{% trans "DHCPv6" %}</label> <label class="col-sm-4 col-form-label">{% trans "DHCPv6" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="checkbox" name="dhcp6" value="true"> <input type="checkbox" name="dhcp6" value="true">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group"> <div class="form-group row bridge_name_form_group">
<label class="col-sm-4 col-form-label">{% trans "Bridge Name" %}</label> <label class="col-sm-4 col-form-label" id="bridge_label">{% trans "Bridge Name" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="bridge_name" placeholder="br0" pattern="[a-z0-9\-_:]+"> <input type="text" class="form-control" name="bridge_name" id="bridge_name" placeholder="br0" pattern="[a-z0-9\-_:]+">
</div> </div>
</div> </div>
<div class="form-group row bridge_name_form_group"> <div class="form-group row bridge_name_form_group openvswitch">
<label class="col-sm-4 col-form-label">{% trans "Open vSwitch" %}</label> <label class="col-sm-4 col-form-label">{% trans "Open vSwitch" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="checkbox" name="openvswitch" value="true"> <input type="checkbox" name="openvswitch" value="true">
@ -89,3 +90,4 @@
</div> <!-- /.modal-dialog --> </div> <!-- /.modal-dialog -->
</div> <!-- /.modal --> </div> <!-- /.modal -->
{% endif %} {% endif %}

View file

@ -37,7 +37,6 @@
<!-- /.row --> <!-- /.row -->
{% include 'errors_block.html' %} {% include 'errors_block.html' %}
{% include 'messages_block.html' %}
<div class="row"> <div class="row">
<dl class="ml-3 row"> <dl class="ml-3 row">

View file

@ -79,6 +79,12 @@
if ($(this).val() == 'bridge') { if ($(this).val() == 'bridge') {
$('.bridge_name_form_group').show(); $('.bridge_name_form_group').show();
$('.bridge_name_form_group_dhcp').hide(); $('.bridge_name_form_group_dhcp').hide();
} else if ($(this).val() == 'macvtap') {
$('#bridge_label').text("Dev Name");
$('#bridge_name').attr("placeholder", "eth0");
$('.bridge_name_form_group').show();
$('.bridge_name_form_group_dhcp').hide();
$('.openvswitch').hide();
} else { } else {
$('.bridge_name_form_group').hide(); $('.bridge_name_form_group').hide();
$('.bridge_name_form_group_dhcp').show(); $('.bridge_name_form_group_dhcp').show();

View file

@ -42,8 +42,8 @@ def networks(request, compute_id):
if data['name'] in networks: if data['name'] in networks:
msg = _("Network pool name already in use") msg = _("Network pool name already in use")
error_messages.append(msg) error_messages.append(msg)
if data['forward'] == 'bridge' and data['bridge_name'] == '': if data['forward'] in ['bridge', 'macvtap'] and data['bridge_name'] == '':
error_messages.append(_('Please enter bridge name')) error_messages.append(_('Please enter bridge/dev name'))
if data['subnet']: if data['subnet']:
ipv4 = True ipv4 = True
gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4']) gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4'])

View file

@ -345,6 +345,7 @@ class wvmInstance(wvmConnect):
result = [] result = []
inbound = outbound = [] inbound = outbound = []
for net in ctx.xpath('/domain/devices/interface'): for net in ctx.xpath('/domain/devices/interface'):
interface_type = net.xpath('@type')[0]
mac_inst = net.xpath('mac/@address')[0] mac_inst = net.xpath('mac/@address')[0]
nic_inst = net.xpath('source/@network|source/@bridge|source/@dev')[0] nic_inst = net.xpath('source/@network|source/@bridge|source/@dev')[0]
target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0] target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0]
@ -369,6 +370,7 @@ class wvmInstance(wvmConnect):
except libvirtError: except libvirtError:
ipv4, ipv6 = None, None ipv4, ipv6 = None, None
result.append({ result.append({
'type': interface_type,
'mac': mac_inst, 'mac': mac_inst,
'nic': nic_inst, 'nic': nic_inst,
'target': target_inst, 'target': target_inst,
@ -1289,24 +1291,39 @@ class wvmInstance(wvmConnect):
bridge_name = iface.name() bridge_name = iface.name()
else: else:
net = self.get_network(source) net = self.get_network(source)
bridge_name = net.bridgeName() try:
bridge_name = net.bridgeName()
except libvirtError:
bridge_name = None
return bridge_name return bridge_name
def add_network(self, mac_address, source, source_type='net', model='virtio', nwfilter=None): def add_network(self, mac_address, source, source_type='net', model='virtio', nwfilter=None):
bridge_name = self.get_bridge_name(source, source_type) forward_mode = ''
if source_type != 'iface':
forward_mode = self.get_network_forward(source)
forward_mode = self.get_network_forward(source)
if forward_mode in ['nat', 'isolated', 'routed']: if forward_mode in ['nat', 'isolated', 'routed']:
interface_type = 'network' interface_type = 'network'
elif forward_mode == '':
interface_type = 'direct'
else: else:
interface_type = 'bridge' if self.get_bridge_name(source, source_type) is None:
interface_type = 'network'
else:
interface_type = 'bridge'
xml_iface = f""" xml_iface = f"""
<interface type='{interface_type}'> <interface type='{interface_type}'>
<mac address='{mac_address}'/>""" <mac address='{mac_address}'/>"""
if interface_type == 'network': if interface_type == 'network':
xml_iface += f"""<source network='{source}'/>""" xml_iface += f"""<source network='{source}'/>"""
elif interface_type == 'direct':
if source_type == 'net':
xml_iface += f"""<source network='{source}' mode='bridge'/>"""
else:
xml_iface += f"""<source dev='{source}' mode='bridge'/>"""
else: else:
bridge_name = self.get_bridge_name(source, source_type)
xml_iface += f"""<source bridge='{bridge_name}'/>""" xml_iface += f"""<source bridge='{bridge_name}'/>"""
xml_iface += f"""<model type='{model}'/>""" xml_iface += f"""<model type='{model}'/>"""
if nwfilter: if nwfilter:
@ -1342,49 +1359,38 @@ class wvmInstance(wvmConnect):
net_source_type = network_data.get('net-source-' + str(num) + '-type') net_source_type = network_data.get('net-source-' + str(num) + '-type')
net_filter = network_data.get('net-nwfilter-' + str(num)) net_filter = network_data.get('net-nwfilter-' + str(num))
net_model = network_data.get('net-model-' + str(num)) net_model = network_data.get('net-model-' + str(num))
source = interface.find('source')
if interface.get('type') == 'bridge': if interface.get('type') == 'bridge':
bridge_name = self.get_bridge_name(net_source, net_source_type) bridge_name = self.get_bridge_name(net_source, net_source_type)
source = interface.find('mac')
source.set('address', net_mac)
source = interface.find('source')
source.set('bridge', bridge_name) source.set('bridge', bridge_name)
elif interface.get('type') in ['network', 'direct']:
source = interface.find('model') if net_source_type == 'net':
if net_model != 'default': source.set('network', net_source)
source.attrib['type'] = net_model elif net_source_type == 'iface':
source.set('dev', net_source)
else: else:
interface.remove(source) raise libvirtError(f"Unknown network type: {net_source_type}")
else:
raise libvirtError(f"Unknown network type: {interface.get('type')}")
source = interface.find('filterref') source = interface.find('model')
if net_filter: if net_model != 'default':
if source is not None: source.set('filter', net_filter) source.attrib['type'] = net_model
else: else:
element = ElementTree.Element("filterref") interface.remove(source)
element.attrib['filter'] = net_filter
interface.append(element)
else:
if source is not None: interface.remove(source)
elif interface.get('type') == 'network':
source = interface.find('mac')
source.set('address', net_mac)
source = interface.find('source')
source.set('network', net_source)
source = interface.find('model') source = interface.find('mac')
if net_model != 'default': source.set('address', net_mac)
source.attrib['type'] = net_model source = interface.find('filterref')
if net_filter:
if source is not None: source.set('filter', net_filter)
else: else:
interface.remove(source) element = ElementTree.Element("filterref")
element.attrib['filter'] = net_filter
source = interface.find('filterref') interface.append(element)
if net_filter: else:
if source is not None: source.set('filter', net_filter) if source is not None: interface.remove(source)
else:
element = ElementTree.Element("filterref")
element.attrib['filter'] = net_filter
interface.append(element)
else:
if source is not None: interface.remove(source)
new_xml = ElementTree.tostring(tree).decode() new_xml = ElementTree.tostring(tree).decode()
self._defineXML(new_xml) self._defineXML(new_xml)

View file

@ -55,15 +55,20 @@ class wvmNetworks(wvmConnect):
<name>{name}</name>""" <name>{name}</name>"""
if forward in ['nat', 'route', 'bridge']: if forward in ['nat', 'route', 'bridge']:
xml += f"""<forward mode='{forward}'/>""" xml += f"""<forward mode='{forward}'/>"""
xml += """<bridge """ if forward == 'macvtap':
if forward in ['nat', 'route', 'none']: xml += f"""<forward mode='bridge'>
xml += """stp='on' delay='0'""" <interface dev='{bridge}'/>
if forward == 'bridge': </forward>"""
xml += f"""name='{bridge}'""" else:
xml += """/>""" xml += """<bridge """
if openvswitch is True: if forward in ['nat', 'route', 'none']:
xml += """<virtualport type='openvswitch'/>""" xml += """stp='on' delay='0'"""
if forward != 'bridge': if forward == 'bridge':
xml += f"""name='{bridge}'"""
xml += """/>"""
if openvswitch is True:
xml += """<virtualport type='openvswitch'/>"""
if forward not in ['bridge', 'macvtap']:
if ipv4: if ipv4:
xml += f"""<ip address='{gateway}' netmask='{mask}'>""" xml += f"""<ip address='{gateway}' netmask='{mask}'>"""
if dhcp4: if dhcp4: