1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-25 15:45:23 +00:00

IPv6 Support: Create ipv6 network support added. Some small fixes

This commit is contained in:
catborise 2019-11-08 18:26:47 +03:00
parent 0974193e68
commit 930cef24be
6 changed files with 108 additions and 46 deletions

View file

@ -6,10 +6,13 @@ from django.utils.translation import ugettext_lazy as _
class AddNetPool(forms.Form): class AddNetPool(forms.Form):
name = forms.CharField(error_messages={'required': _('No pool name has been entered')}, name = forms.CharField(error_messages={'required': _('No pool name has been entered')},
max_length=20) max_length=20)
subnet = forms.CharField(error_messages={'required': _('No subnet has been entered')}, subnet = forms.CharField(error_messages={'required': _('No IPv4 subnet has been entered')},
max_length=20, required=False) max_length=20, required=False)
subnet6 = forms.CharField(error_messages={'required': _('No IPv6 subnet has been entered')},
max_length=42, required=False)
forward = forms.CharField(max_length=100) forward = forms.CharField(max_length=100)
dhcp4 = forms.BooleanField(required=False) dhcp4 = forms.BooleanField(required=False)
dhcp6 = forms.BooleanField(required=False)
fixed = forms.BooleanField(required=False) fixed = forms.BooleanField(required=False)
bridge_name = forms.CharField(max_length=20, required=False) bridge_name = forms.CharField(max_length=20, required=False)
openvswitch = forms.BooleanField(required=False) openvswitch = forms.BooleanField(required=False)
@ -32,6 +35,15 @@ class AddNetPool(forms.Form):
raise forms.ValidationError(_('The pool subnet must not exceed 20 characters')) raise forms.ValidationError(_('The pool subnet must not exceed 20 characters'))
return subnet return subnet
def clean_subnet6(self):
subnet = self.cleaned_data['subnet6']
have_symbol = re.match('^[0-9a-fA-F:/]+$', subnet if subnet else ":")
if not have_symbol:
raise forms.ValidationError(_('The pool subnet must not contain any special characters'))
elif len(subnet) > 42:
raise forms.ValidationError(_('The pool subnet must not exceed 42 characters'))
return subnet
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'] == 'bridge':

View file

@ -20,10 +20,21 @@
<input type="text" class="form-control" name="name" placeholder="default" required pattern="[a-zA-Z0-9_]+"> <input type="text" class="form-control" name="name" placeholder="default" required pattern="[a-zA-Z0-9_]+">
</div> </div>
</div> </div>
<div class="form-group bridge_name_form_group_dhcp"> <div class="form-group">
<label class="col-sm-4 control-label">{% trans "Subnet pool" %}</label> <label class="col-sm-4 control-label">{% trans "Type forwarding" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="subnet" value="192.168.100.0/24" required pattern="[0-9\/\.]+"> <select id="forward_select" class="form-control" name="forward">
<option value="nat">{% trans "NAT" %}</option>
<option value="route">{% trans "ROUTE" %}</option>
<option value="none">{% trans "ISOLATE" %}</option>
<option value="bridge">{% trans "BRIDGE" %}</option>
</select>
</div>
</div>
<div class="form-group bridge_name_form_group_dhcp">
<label class="col-sm-4 control-label">{% trans "IPv4 Subnet pool" %}</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="subnet" value="" placeholder="192.168.100.0/24" required pattern="[0-9\/\.]+">
</div> </div>
</div> </div>
<div class="form-group bridge_name_form_group_dhcp"> <div class="form-group bridge_name_form_group_dhcp">
@ -38,15 +49,22 @@
<input type="checkbox" name="fixed" value="true"> <input type="checkbox" name="fixed" value="true">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group bridge_name_form_group_dhcp">
<label class="col-sm-4 control-label">{% trans "Type forwarding" %}</label> <label class="col-sm-4 control-label">{% trans "Enable IPv6" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<select id="forward_select" class="form-control" name="forward"> <input type="checkbox" id="enable_ipv6" name="enable_ipv6" value="false">
<option value="nat">{% trans "NAT" %}</option> </div>
<option value="route">{% trans "ROUTE" %}</option> </div>
<option value="none">{% trans "ISOLATE" %}</option> <div class="form-group bridge_name_form_group_dhcp ipv6_group">
<option value="bridge">{% trans "BRIDGE" %}</option> <label class="col-sm-4 control-label">{% trans "IPv6 Subnet pool" %}</label>
</select> <div class="col-sm-6">
<input type="text" class="form-control" name="subnet6" value="" placeholder="fd00:dead:baba:1::/64" required pattern="[0-9\/\.]+">
</div>
</div>
<div class="form-group bridge_name_form_group_dhcp ipv6_group">
<label class="col-sm-4 control-label">{% trans "DHCPv6" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="dhcp6" value="true">
</div> </div>
</div> </div>
<div class="form-group bridge_name_form_group"> <div class="form-group bridge_name_form_group">

View file

@ -24,7 +24,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">{% trans "ID" %}</label> <label class="col-sm-4 control-label">{% trans "ID" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="id" required pattern="[0-9a-dA-D\/\:]+"> <input type="text" class="form-control" name="id" required pattern="[0-9a-fA-F\/\:]+">
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
@ -36,7 +36,7 @@
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">{% trans "Address" %}</label> <label class="col-sm-4 control-label">{% trans "Address" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="text" class="form-control" name="address" required pattern="[a-dA-D0-9\/\:]+"> <input type="text" class="form-control" name="address" required pattern="[a-fA-F0-9\/\:]+">
</div> </div>
</div> </div>
</div> </div>

View file

@ -41,7 +41,7 @@
<div class="col-lg-12"> <div class="col-lg-12">
<div class="alert alert-warning alert-dismissable"> <div class="alert alert-warning alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
<i class="fa fa-exclamation-triangle"></i><strong>{% trans "Warning:" %}</strong> {% trans "Hypervisor doesn't have any Networks" %} <i class="fa fa-exclamation-triangle"></i><strong>{% trans "Warning" %}:</strong> {% trans "Hypervisor doesn't have any network" %}
</div> </div>
</div> </div>
{% else %} {% else %}
@ -54,8 +54,8 @@
<div class="panel-body"> <div class="panel-body">
<div class="row"> <div class="row">
<div class="col-xs-4 col-sm-4"> <div class="col-xs-4 col-sm-4">
<p><strong>{% trans "Device:" %}</strong></p> <p><strong>{% trans "Device" %}:</strong></p>
<p><strong>{% trans "Forward:" %}</strong></p> <p><strong>{% trans "Forward" %}:</strong></p>
</div> </div>
<div class="col-xs-6 col-sm-7"> <div class="col-xs-6 col-sm-7">
<p>{{ pool.device }}</p> <p>{{ pool.device }}</p>
@ -81,6 +81,14 @@
$('.bridge_name_form_group_dhcp').show(); $('.bridge_name_form_group_dhcp').show();
} }
}).change(); }).change();
$('#enable_ipv6').change(function (eventObject) {
if ($(this).is(':checked')) {
$('.ipv6_group').show();
} else {
$('.ipv6_group').hide();
}
}).change();
}); });
</script> </script>
{% endblock %} {% endblock %}

View file

@ -31,7 +31,9 @@ def networks(request, compute_id):
compute.password, compute.password,
compute.type) compute.type)
networks = conn.get_networks_info() networks = conn.get_networks_info()
dhcp4 = netmask = gateway = '' dhcp4 = netmask4 = gateway4 = ''
dhcp6 = prefix6 = gateway6 = ''
ipv4 = ipv6 = False
if request.method == 'POST': if request.method == 'POST':
if 'create' in request.POST: if 'create' in request.POST:
@ -39,15 +41,24 @@ def networks(request, compute_id):
if form.is_valid(): if form.is_valid():
data = form.cleaned_data data = form.cleaned_data
if data['name'] in networks: if data['name'] in networks:
msg = _("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'] == 'bridge' and data['bridge_name'] == '':
error_messages.append('Please enter bridge name') error_messages.append('Please enter bridge name')
if data['subnet']: if data['subnet']:
gateway, netmask, dhcp4 = network_size(data['subnet'], data['dhcp4']) ipv4 = True
gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4'])
if data['subnet6']:
ipv6 = True
gateway6, prefix6, dhcp6 = network_size(data['subnet6'], data['dhcp6'])
if prefix6 != '64':
error_messages.append('For libvirt, the IPv6 network prefix must be /64')
if not error_messages: if not error_messages:
conn.create_network(data['name'], data['forward'], gateway, netmask, conn.create_network(data['name'],
dhcp4, data['bridge_name'], data['openvswitch'], data['fixed']) data['forward'],
ipv4, gateway4, netmask4, dhcp4,
ipv6, gateway6, prefix6, dhcp6,
data['bridge_name'], data['openvswitch'], data['fixed'])
return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']])) return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']]))
else: else:
for msg_err in form.errors.values(): for msg_err in form.errors.values():
@ -151,7 +162,7 @@ def network(request, compute_id, pool):
try: try:
ret_val = conn.modify_fixed_address(name, address, mac_duid, family) ret_val = conn.modify_fixed_address(name, address, mac_duid, family)
messages.success(request, "{} Fixed Address Operation Completed.".format(family)) messages.success(request, "{} Fixed Address Operation Completed.".format(family.upper()))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err.message) error_messages.append(lib_err.message)
@ -161,7 +172,7 @@ def network(request, compute_id, pool):
ip = request.POST.get('address', '') ip = request.POST.get('address', '')
family = request.POST.get('family', 'ipv4') family = request.POST.get('family', 'ipv4')
conn.delete_fixed_address(ip, family) conn.delete_fixed_address(ip, family)
messages.success(request, "{} Fixed Address is Deleted.".format(family)) messages.success(request, "{} Fixed Address is Deleted.".format(family.upper()))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
if 'modify_dhcp_range' in request.POST: if 'modify_dhcp_range' in request.POST:
range_start = request.POST.get('range_start', '') range_start = request.POST.get('range_start', '')
@ -169,7 +180,7 @@ def network(request, compute_id, pool):
family = request.POST.get('family', 'ipv4') family = request.POST.get('family', 'ipv4')
try: try:
conn.modify_dhcp_range(range_start, range_end, family) conn.modify_dhcp_range(range_start, range_end, family)
messages.success(request, "{} DHCP Range is Changed.".format(family)) messages.success(request, "{} DHCP Range is Changed.".format(family.upper()))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err.message) error_messages.append(lib_err.message)

View file

@ -7,14 +7,18 @@ from libvirt import VIR_NETWORK_UPDATE_COMMAND_ADD_LAST, VIR_NETWORK_UPDATE_COMM
from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG from libvirt import VIR_NETWORK_UPDATE_AFFECT_LIVE, VIR_NETWORK_UPDATE_AFFECT_CONFIG
def network_size(net, dhcp=None): def network_size(subnet, dhcp=None):
""" """
Func return gateway, mask and dhcp pool. Func return gateway, mask and dhcp pool.
""" """
mask = IP(net).strNetmask() mask = IP(subnet).strNetmask()
addr = IP(net) addr = IP(subnet)
gateway = addr[1].strNormal() gateway = addr[1].strCompressed()
dhcp_pool = [addr[2].strNormal(), addr[addr.len() - 2].strNormal()] if addr.version() == 4:
dhcp_pool = [addr[2].strCompressed(), addr[addr.len() - 2].strCompressed()]
if addr.version() == 6:
mask = mask.lstrip('/') if '/' in mask else mask
dhcp_pool = [IP(addr[0].strCompressed() + hex(256)), IP(addr[0].strCompressed() + hex(512 - 1))]
if dhcp: if dhcp:
return gateway, mask, dhcp_pool return gateway, mask, dhcp_pool
else: else:
@ -30,15 +34,18 @@ class wvmNetworks(wvmConnect):
net = self.get_network(network) net = self.get_network(network)
net_status = net.isActive() net_status = net.isActive()
net_bridge = net.bridgeName() net_bridge = net.bridgeName()
net_forwd = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode") net_forward = util.get_xml_path(net.XMLDesc(0), "/network/forward/@mode")
networks.append({'name': network, 'status': net_status, networks.append({'name': network, 'status': net_status,
'device': net_bridge, 'forward': net_forwd}) 'device': net_bridge, 'forward': net_forward})
return networks return networks
def define_network(self, xml): def define_network(self, xml):
self.wvm.networkDefineXML(xml) self.wvm.networkDefineXML(xml)
def create_network(self, name, forward, gateway, mask, dhcp4, bridge, openvswitch, fixed=False): def create_network(self, name, forward,
ipv4, gateway, mask, dhcp4,
ipv6, gateway6, prefix6, dhcp6,
bridge, openvswitch, fixed=False):
xml = """ xml = """
<network> <network>
<name>%s</name>""" % name <name>%s</name>""" % name
@ -53,8 +60,8 @@ class wvmNetworks(wvmConnect):
if openvswitch is True: if openvswitch is True:
xml += """<virtualport type='openvswitch'/>""" xml += """<virtualport type='openvswitch'/>"""
if forward != 'bridge': if forward != 'bridge':
xml += """ if ipv4:
<ip address='%s' netmask='%s'>""" % (gateway, mask) xml += """<ip address='%s' netmask='%s'>""" % (gateway, mask)
if dhcp4: if dhcp4:
xml += """<dhcp> xml += """<dhcp>
<range start='%s' end='%s' />""" % (dhcp4[0], dhcp4[1]) <range start='%s' end='%s' />""" % (dhcp4[0], dhcp4[1])
@ -64,7 +71,13 @@ class wvmNetworks(wvmConnect):
for ip in range(fist_oct, last_oct + 1): for ip in range(fist_oct, last_oct + 1):
xml += """<host mac='%s' ip='%s.%s' />""" % (util.randomMAC(), gateway[:-2], ip) xml += """<host mac='%s' ip='%s.%s' />""" % (util.randomMAC(), gateway[:-2], ip)
xml += """</dhcp>""" xml += """</dhcp>"""
xml += """</ip>"""
if ipv6:
xml += """<ip family='ipv6' address='%s' prefix='%s'>""" % (gateway6, prefix6)
if dhcp6:
xml += """<dhcp>
<range start='%s' end='%s' />""" % (dhcp6[0], dhcp6[1])
xml += """</dhcp>"""
xml += """</ip>""" xml += """</ip>"""
xml += """</network>""" xml += """</network>"""
self.define_network(xml) self.define_network(xml)