1# Copyright (C) 2006, 2013-2014 Red Hat, Inc.
2# Copyright (C) 2006 Daniel P. Berrange <berrange@redhat.com>
3#
4# This work is licensed under the GNU GPLv2 or later.
5# See the COPYING file in the top-level directory.
6
7import ipaddress
8
9from virtinst import log
10from virtinst import Network
11
12from .libvirtobject import vmmLibvirtObject
13from ..lib import testmock
14
15
16def _make_addr_str(addrStr, prefix, netmaskStr):
17    if prefix:
18        return str(
19            ipaddress.ip_network(
20                str("{}/{}").format(addrStr, prefix), strict=False
21            )
22        )
23    elif netmaskStr:
24        netmask = ipaddress.ip_address(str((netmaskStr)))
25        network = ipaddress.ip_address(str((addrStr)))
26        return str(
27            ipaddress.ip_network(
28                str("{}/{}").format(network, netmask), strict=False
29            )
30        )
31    else:
32        return str(ipaddress.ip_network(str(addrStr), strict=False))
33
34
35class vmmNetwork(vmmLibvirtObject):
36    def __init__(self, conn, backend, key):
37        vmmLibvirtObject.__init__(self, conn, backend, key, Network)
38
39        self._leases = None
40
41
42    ##########################
43    # Required class methods #
44    ##########################
45
46    def _conn_tick_poll_param(self):
47        return "pollnet"
48    def class_name(self):
49        return "network"
50
51    def _XMLDesc(self, flags):
52        return self._backend.XMLDesc(flags)
53    def _define(self, xml):
54        return self.conn.define_network(xml)
55    def _using_events(self):
56        return self.conn.using_network_events
57    def _get_backend_status(self):
58        return (bool(self._backend.isActive()) and
59                self._STATUS_ACTIVE or
60                self._STATUS_INACTIVE)
61
62
63    ###########
64    # Actions #
65    ###########
66
67    @vmmLibvirtObject.lifecycle_action
68    def start(self):
69        self._backend.create()
70
71    @vmmLibvirtObject.lifecycle_action
72    def stop(self):
73        self._backend.destroy()
74
75    @vmmLibvirtObject.lifecycle_action
76    def delete(self, force=True):
77        ignore = force
78        self._backend.undefine()
79        self._backend = None
80
81
82    ###############################
83    # XML/config handling parsing #
84    ###############################
85
86    def get_autostart(self):
87        return self._backend.autostart()
88    def set_autostart(self, value):
89        self._backend.setAutostart(value)
90
91    def _refresh_dhcp_leases(self):
92        ret = []
93        try:
94            ret = self._backend.DHCPLeases()
95        except Exception as e:
96            log.debug("Error getting %s DHCP leases: %s", self, str(e))
97            if self.conn.is_test():
98                ret = testmock.fake_dhcp_leases()
99        self._leases = ret
100
101    def get_dhcp_leases(self, refresh=False):
102        if self._leases is None or refresh:
103            self._refresh_dhcp_leases()
104        return self._leases
105
106    def get_bridge_device(self):
107        return self.get_xmlobj().bridge
108    def get_name_domain(self):
109        return self.get_xmlobj().domain_name
110    def get_ipv6_enabled(self):
111        return self.get_xmlobj().ipv6
112    def get_ipv4_forward_mode(self):
113        return self.get_xmlobj().forward.mode
114
115    def _get_network(self, family):
116        dhcpstart = None
117        dhcpend = None
118
119        xmlobj = self.get_xmlobj()
120        ip = None
121        for i in xmlobj.ips:
122            if (i.family == family or
123                (family == "ipv4" and not i.family)):
124                if i.ranges:
125                    ip = i
126                    dhcpstart = i.ranges[0].start
127                    dhcpend = i.ranges[0].end
128                    break
129
130        if not ip:
131            for i in xmlobj.ips:
132                if (i.family == family or
133                    (family == "ipv4" and not i.family)):
134                    ip = i
135                    break
136
137        ret = None
138        if ip:
139            ret = _make_addr_str(ip.address, ip.prefix, ip.netmask)
140
141        dhcp = [None, None]
142        if dhcpstart and dhcpend:
143            dhcp = [str(ipaddress.ip_address(str(dhcpstart))),
144                    str(ipaddress.ip_address(str(dhcpend)))]
145        return [ret, dhcp]
146
147    def get_ipv4_network(self):
148        return self._get_network("ipv4")
149    def get_ipv6_network(self):
150        return self._get_network("ipv6")
151
152    def pretty_forward_mode(self):
153        mode = self.xmlobj.forward.mode
154        dev = self.xmlobj.forward.dev
155
156        if not mode:
157            return _("Isolated network")
158
159        if mode == "nat":
160            if dev:
161                desc = _("NAT to %s") % dev
162            else:
163                desc = _("NAT")
164        elif mode == "route":
165            if dev:
166                desc = _("Route to %s") % dev
167            else:
168                desc = _("Routed network")
169        else:
170            modestr = mode.capitalize()
171            desc = _("%s network") % modestr
172
173        return desc
174