# Path: lab/network/dhcp.py
# class DHCP4(object):
#     def __init__(self, iface):
#         self.iface = iface
#         self.sock = DHCP4Socket(iface.ifname)
# 
#         self._yiaddr = None
#         self._subnet_mask = None
#         self._ready_event = threading.Event()
#         self._stop_event = threading.Event()
#         self._thread = threading.Thread(target=self._lease)
#         self._thread.daemon = True
#         self._thread.start()
#         if not self._ready_event.wait(10.0):
#             raise RuntimeError('Failed to get DHCP lease')
# 
#         logger.info('Setting {} on {}...'.format(self.yiaddr,
#                                                  self.iface.ifname))
#         self.iface.add_ip(self.yiaddr.compressed,
#                           mask=self.subnet_mask.compressed)
#         self.iface.commit()
# 
#     def _discover(self, src=None):
#         logger.info('Sending DHCP4 discover on {}...'.format(self.iface.ifname))
#         chaddr = src or self.sock.src
#         options = build_options(DHCPMessage.Discover, chaddr)
#         packet = DHCPPacket(DHCPOpCode.Request, chaddr=chaddr, options=options)
#         return self.sock.send(packet, src=src, expect=DHCPMessage.Offer)
# 
#     def _request(self, yiaddr, src=None):
#         logger.info('Sending DHCP4 request on {}...'.format(self.iface.ifname))
#         chaddr = src or self.sock.src
#         options = build_options(DHCPMessage.Request, chaddr, requested_ip=yiaddr)
#         packet = DHCPPacket(DHCPOpCode.Request, chaddr=chaddr, options=options)
#         return self.sock.send(packet, src=src, expect=DHCPMessage.ACK)
# 
#     def _release(self, yiaddr, src=None):
#         logger.info('Sending DHCP4 release on {}...'.format(self.iface.ifname))
#         chaddr = src or self.sock.src
#         options = build_options(DHCPMessage.Release, chaddr, requested_ip=yiaddr)
#         packet = DHCPPacket(DHCPOpCode.Request, chaddr=chaddr, options=options)
#         self.sock.send(packet, src=src)
# 
#     def _lease(self):
#         offer = self._discover()
#         self._yiaddr = offer.yiaddr
# 
#         while True:
#             reply = self._request(self._yiaddr)
#             options = dict(reply.options)
# 
#             self._yiaddr = reply.yiaddr
#             self._subnet_mask = options[DHCPOption.SubnetMask].tobytes()
#             self._ready_event.set()
# 
#             # TODO: fix
#             lease_time = reply.secs
# 
#             # If there's either no leasetime, or the stop event has
#             # been set before our renew timeout, renew our lease
#             if not lease_time:
#                 logger.debug('No lease time on DHCP lease!')
#                 return
#             elif self._stop_event.wait(lease_time // 2):
#                 logger.debug('Leaving DHCP renewal loop!')
#                 return
# 
#     def close(self):
#         self._stop_event.set()
#         self._release(self._yiaddr)
# 
#     @property
#     def yiaddr(self):
#         return ipaddress.IPv4Address(self._yiaddr)
# 
#     @property
#     def subnet_mask(self):
#         return ipaddress.IPv4Address(self._subnet_mask)


from builtins import range
from builtins import object
from .dhcp import DHCP4
import time
import logging
import socket
import ipaddress
import pyroute2

    A context manager is provided for convenience and is the recommended
    way to use this library::

        with MacVLan('eno1', name='test-network', mac='00:19:d1:29:d2:58') as vlan:
            ...

    Will create a new mavlan called ``test-network`` bound to ``eno1`` using
    the provided mac. It will also try and aquire an IP over DHCP.::

        31: test-network@eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
            link/ether 9e:dc:e3:d6:1e:ad brd ff:ff:ff:ff:ff:ff
            inet6 fe80::9cdc:e3ff:fed6:1ead/64 scope link tentative dadfailed
               valid_lft forever preferred_lft forever
    """
    def __init__(self, interface, name='macvlan', dhcp=True):
        self.name = _generate_device_name(name)
        self.dhcp = None

        self.ipdb = pyroute2.IPDB()
        vlan = self.ipdb.create(kind='macvlan',
                                link=self.ipdb.interfaces[interface],
                                ifname=self.name,
                                mode='bridge')
        vlan.up()
        vlan.commit()

        # Start dhcp process if necessary
        if dhcp:
            try:

# Path: lab/network/dhcp.py
# class DHCP4(object):
#     def __init__(self, iface):
#         self.iface = iface
#         self.sock = DHCP4Socket(iface.ifname)
# 
#         self._yiaddr = None
#         self._subnet_mask = None
#         self._ready_event = threading.Event()
#         self._stop_event = threading.Event()
#         self._thread = threading.Thread(target=self._lease)
#         self._thread.daemon = True
#         self._thread.start()
#         if not self._ready_event.wait(10.0):
#             raise RuntimeError('Failed to get DHCP lease')
# 
#         logger.info('Setting {} on {}...'.format(self.yiaddr,
#                                                  self.iface.ifname))
#         self.iface.add_ip(self.yiaddr.compressed,
#                           mask=self.subnet_mask.compressed)
#         self.iface.commit()
# 
#     def _discover(self, src=None):
#         logger.info('Sending DHCP4 discover on {}...'.format(self.iface.ifname))
#         chaddr = src or self.sock.src
#         options = build_options(DHCPMessage.Discover, chaddr)
#         packet = DHCPPacket(DHCPOpCode.Request, chaddr=chaddr, options=options)
#         return self.sock.send(packet, src=src, expect=DHCPMessage.Offer)
# 
#     def _request(self, yiaddr, src=None):
#         logger.info('Sending DHCP4 request on {}...'.format(self.iface.ifname))
#         chaddr = src or self.sock.src
#         options = build_options(DHCPMessage.Request, chaddr, requested_ip=yiaddr)
#         packet = DHCPPacket(DHCPOpCode.Request, chaddr=chaddr, options=options)
#         return self.sock.send(packet, src=src, expect=DHCPMessage.ACK)
# 
#     def _release(self, yiaddr, src=None):
#         logger.info('Sending DHCP4 release on {}...'.format(self.iface.ifname))
#         chaddr = src or self.sock.src
#         options = build_options(DHCPMessage.Release, chaddr, requested_ip=yiaddr)
#         packet = DHCPPacket(DHCPOpCode.Request, chaddr=chaddr, options=options)
#         self.sock.send(packet, src=src)
# 
#     def _lease(self):
#         offer = self._discover()
#         self._yiaddr = offer.yiaddr
# 
#         while True:
#             reply = self._request(self._yiaddr)
#             options = dict(reply.options)
# 
#             self._yiaddr = reply.yiaddr
#             self._subnet_mask = options[DHCPOption.SubnetMask].tobytes()
#             self._ready_event.set()
# 
#             # TODO: fix
#             lease_time = reply.secs
# 
#             # If there's either no leasetime, or the stop event has
#             # been set before our renew timeout, renew our lease
#             if not lease_time:
#                 logger.debug('No lease time on DHCP lease!')
#                 return
#             elif self._stop_event.wait(lease_time // 2):
#                 logger.debug('Leaving DHCP renewal loop!')
#                 return
# 
#     def close(self):
#         self._stop_event.set()
#         self._release(self._yiaddr)
# 
#     @property
#     def yiaddr(self):
#         return ipaddress.IPv4Address(self._yiaddr)
# 
#     @property
#     def subnet_mask(self):
#         return ipaddress.IPv4Address(self._subnet_mask)


# Path: lab/network/macvlan.py
from builtins import range
from builtins import object
from .dhcp import DHCP4
import time
import logging
import socket
import ipaddress
import pyroute2


    A context manager is provided for convenience and is the recommended
    way to use this library::

        with MacVLan('eno1', name='test-network', mac='00:19:d1:29:d2:58') as vlan:
            ...

    Will create a new mavlan called ``test-network`` bound to ``eno1`` using
    the provided mac. It will also try and aquire an IP over DHCP.::

        31: test-network@eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
            link/ether 9e:dc:e3:d6:1e:ad brd ff:ff:ff:ff:ff:ff
            inet6 fe80::9cdc:e3ff:fed6:1ead/64 scope link tentative dadfailed
               valid_lft forever preferred_lft forever
    """
    def __init__(self, interface, name='macvlan', dhcp=True):
        self.name = _generate_device_name(name)
        self.dhcp = None

        self.ipdb = pyroute2.IPDB()
        vlan = self.ipdb.create(kind='macvlan',
                                link=self.ipdb.interfaces[interface],
                                ifname=self.name,
                                mode='bridge')
        vlan.up()
        vlan.commit()

        # Start dhcp process if necessary
        if dhcp:
            try:

                self.dhcp = DHCP4(vlan)