Ejemplo n.º 1
0
def create_bridge(br_name, phy_ip):
    """
    Create a bridge for connecting the container clients to the network.

    :param br_name: Name of the bridge to create.
    :param phy_ip: IP of the physical interface to include in the bridge.
    :return: True if success, False if failure
    """

    log.info("Creating bridge %s." % br_name)

    assert (phy_ip.startswith('10.') or phy_ip.startswith('192.'))

    ipdb = IPDB()

    if br_name in ipdb.interfaces.keys():
        log.fatal("A bridge/interface with the name %s already exists!" %
                  br_name)
        return False

    phy_eth = None

    for eth in ipdb.interfaces.keys():
        if type(eth) is int: continue
        for ip, netmask in ipdb.interfaces[eth]['ipaddr']:
            log.debug("%s: %s" % (eth, ip))
            if ip == phy_ip:
                phy_eth = (eth, ip, netmask)
                break

    if phy_eth is None:
        log.fatal("Could not find an interface with IP '%s'!" % phy_ip)
        return False

    log.info("Using interface %s for the bridge." % str(phy_eth))

    log.debug("Creating bridge with ifname %s." % br_name)

    with ipdb.create(kind='bridge', ifname=br_name) as br:
        br.add_port(ipdb.interfaces[phy_eth[0]])
        br.up()
        br.add_ip('%s/%s' % (phy_eth[1], phy_eth[2]))

    log.debug("Removing IP %s from interface %s." % (phy_eth[1], phy_eth))

    with ipdb.interfaces[phy_eth[0]] as i:
        i.del_ip('%s/%s' % (phy_eth[1], phy_eth[2]))

    ipdb.commit()
    ipdb.release()

    return True
Ejemplo n.º 2
0
    def test_vrouter(self):
        require_user('root')
        nsid = str(uuid.uuid4())
        ns = NetNS(nsid)
        ipdb = IPDB()
        ipns = IPDB(nl=ns)
        try:
            ipdb.create(ifname='ve0p0', peer='ve0p1', kind='veth').commit()
            ipdb.interfaces.ve0p1.net_ns_fd = nsid
            ipdb.commit()

            with ipns.interfaces.ve0p1 as i:
                i.set_ifname('eth0')
                i.up()

        except:
            raise
        finally:
            ipdb.interfaces.ve0p0.remove()
            ipdb.commit()
            ipdb.release()
            ipns.release()
            ns.remove()
Ejemplo n.º 3
0
    def test_vrouter(self):
        require_user('root')
        nsid = str(uuid.uuid4())
        ns = NetNS(nsid)
        ipdb = IPDB()
        ipns = IPDB(nl=ns)
        try:
            ipdb.create(ifname='ve0p0', peer='ve0p1', kind='veth').commit()
            ipdb.interfaces.ve0p1.net_ns_fd = nsid
            ipdb.commit()

            with ipns.interfaces.ve0p1 as i:
                i.set_ifname('eth0')
                i.up()

        except:
            raise
        finally:
            ipdb.interfaces.ve0p0.remove()
            ipdb.commit()
            ipdb.release()
            ipns.release()
            ns.remove()
def delete_tunnel(args):
    """
    """
    ipdb = IPDB()
    try:
        ipdb.interfaces[args.physical_interface]
    except KeyError:
        logger.error(f"{args.physical_interface} interface does not exist")
        sys.exit()
    try:
        ipdb.interfaces[f"vxlan{args.vni}"]
    except KeyError:
        logger.error(f"vxlan{args.vni} interface does not exist")
        sys.exit()
    try:
        ipdb.interfaces[f"br{args.vni}"]
    except KeyError:
        logger.error(f"br{args.vni} interface does not exist")
        sys.exit()
    ipdb.interfaces[f"vxlan{args.vni}"].remove()
    logger.info(f"vxlan{args.vni} deleted")
    ipdb.interfaces[f"br{args.vni}"].remove()
    logger.info(f"br{args.vni} deleted")
    ipdb.commit()
Ejemplo n.º 5
0
def create_ns(br_name, ns_name, ns_ip, ns_netmask, if_description, add_if):
    """
    :param br_name:
    :param ns_name:
    :param ns_ip:
    :param ns_netmask:
    :param if_description:
    :param add_if:
    :return:
    """

    # start the main network settings database:
    ipdb = IPDB()

    # Check if the bridge exists
    if br_name not in ipdb.interfaces.keys():
        log.fatal("Could not find bridge %s!" % br_name)
        sys.exit(-1)

    # veth naming
    ifname = "%s_%s_p%%d" % (ns_name, if_description)

    if (ifname % 0) in ipdb.interfaces.keys():
        log.fatal("%s already exists as interface!" % (ifname % 0))
        return False

    log.debug("Creating veth pair %s - %s for namespace %s." %
              (ifname % 0, ifname % 1, ns_name))

    if ns_name in netns.listnetns() and not add_if:
        log.warning("Namespace %s already exists!" % ns_name)

    # Create/configure a network namespace
    ipdb_ns = IPDB(nl=NetNS(ns_name))

    # Make sure lo is up in the namespace
    ipdb_ns.interfaces["lo"].up().commit()

    # Create veth pair
    ipdb.create(kind='veth', ifname=(ifname % 0), peer=(ifname % 1)).commit()

    # Move peer veth into the netns
    with ipdb.interfaces[(ifname % 1)] as veth:
        veth.net_ns_fd = ns_name

    with ipdb.interfaces[(ifname % 0)] as veth:
        veth.up()

    # wait for iface to be moved to ns
    time.sleep(0.1)

    ns_ip = '%s/%s' % (ns_ip, ns_netmask)

    log.debug("Assigning IP %s to %s." % (ns_ip, (ifname % 1)))

    with ipdb_ns.interfaces[(ifname % 1)] as veth:
        veth.add_ip(ns_ip)
        veth.up()

    log.debug("Adding port %s to bridge %s." % ((ifname % 0), br_name))

    ipdb.interfaces[br_name].add_port((ifname % 0))

    ipdb.commit()

    return True
Ejemplo n.º 6
0
class TestExplicit(object):
    ip = None
    mode = "explicit"

    def setup(self):
        self.ifaces = []
        self.ifd = self.get_ifname()
        create_link(self.ifd, kind="dummy")
        self.ip = IPDB(mode=self.mode)

    def get_ifname(self):
        ifname = uifname()
        self.ifaces.append(ifname)
        return ifname

    def teardown(self):
        for name in self.ifaces:
            try:
                # just a hardcore removal
                self.ip.nl.link_remove(self.ip.interfaces[name].index)
            except Exception:
                pass
        self.ip.release()
        self.ifaces = []

    def test_simple(self):
        assert len(list(self.ip.interfaces.keys())) > 0

    def test_empty_transaction(self):
        assert "lo" in self.ip.interfaces
        with self.ip.interfaces.lo as i:
            assert isinstance(i.mtu, int)

    def test_idx_len(self):
        assert len(self.ip.by_name.keys()) == len(self.ip.by_index.keys())

    def test_idx_set(self):
        assert set(self.ip.by_name.values()) == set(self.ip.by_index.values())

    def test_idx_types(self):
        assert all(isinstance(i, int) for i in self.ip.by_index.keys())
        assert all(isinstance(i, basestring) for i in self.ip.by_name.keys())

    def test_addr_attributes(self):
        require_user("root")

        if1 = self.get_ifname()
        if2 = self.get_ifname()

        with self.ip.create(ifname=if1, kind="dummy") as i:
            # +scope host (=> broadcast == None)
            i.add_ip("172.16.102.1/24", scope=254)

        with self.ip.create(ifname=if2, kind="dummy") as i:
            # +broadcast (default scope == 0)
            i.add_ip("172.16.103.1/24", broadcast="172.16.103.128")

        index = self.ip.interfaces[if1]["index"]
        addr = self.ip.nl.get_addr(index=index)[0]
        assert addr["scope"] == 254
        assert addr.get_attr("IFA_BROADCAST") is None

        index = self.ip.interfaces[if2]["index"]
        addr = self.ip.nl.get_addr(index=index)[0]
        assert addr["scope"] == 0
        assert addr.get_attr("IFA_BROADCAST") == "172.16.103.128"

    def test_addr_loaded(self):
        for name in self.ip.by_name:
            assert len(self.ip.interfaces[name]["ipaddr"]) == len(get_ip_addr(name))

    def test_reprs(self):
        assert isinstance(repr(self.ip.interfaces.lo.ipaddr), basestring)
        assert isinstance(repr(self.ip.interfaces.lo), basestring)

    def test_dotkeys(self):
        # self.ip.lo hint for ipython
        assert "lo" in dir(self.ip.interfaces)
        assert "lo" in self.ip.interfaces
        assert self.ip.interfaces.lo == self.ip.interfaces["lo"]
        # create attribute
        self.ip.interfaces["newitem"] = True
        self.ip.interfaces.newattr = True
        self.ip.interfaces.newitem = None
        assert self.ip.interfaces.newitem == self.ip.interfaces["newitem"]
        assert self.ip.interfaces.newitem is None
        # delete attribute
        del self.ip.interfaces.newitem
        del self.ip.interfaces.newattr
        assert "newattr" not in dir(self.ip.interfaces)
        # test hasattr protocol
        assert hasattr(self.ip.interfaces, "nonexistinginterface") is False

    @skip_if_not_supported
    def test_vlan_slave_bridge(self):
        # https://github.com/svinota/pyroute2/issues/58
        # based on the code by Petr Horáček
        dXname = self.get_ifname()
        vXname = self.get_ifname()
        vYname = self.get_ifname()
        brname = self.get_ifname()

        require_user("root")
        dX = self.ip.create(ifname=dXname, kind="dummy").commit()
        vX = self.ip.create(ifname=vXname, kind="vlan", link=dX, vlan_id=101).commit()
        vY = self.ip.create(ifname=vYname, kind="vlan", link=dX, vlan_id=102).commit()
        with self.ip.create(ifname=brname, kind="bridge") as i:
            i.add_port(vX)
            i.add_port(vY["index"])

        assert vX["index"] in self.ip.interfaces[brname]["ports"]
        assert vY["index"] in self.ip.interfaces[brname].ports
        assert vX["link"] == dX["index"]
        assert vY["link"] == dX["index"]
        assert vX["master"] == self.ip.interfaces[brname]["index"]
        assert vY["master"] == self.ip.interfaces[brname].index

    def _test_commit_hook_positive(self):
        require_user("root")

        # test callback, that adds an address by itself --
        # just to check the possibility
        def cb(interface, snapshot, transaction):
            self.ip.nl.addr("add", self.ip.interfaces[self.ifd].index, address="172.16.22.1", mask=24)

        # register callback and check CB chain length
        self.ip.interfaces[self.ifd].register_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 1

        # create a transaction and commit it
        if self.ip.interfaces[self.ifd]._mode == "explicit":
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].add_ip("172.16.21.1/24")
        self.ip.interfaces[self.ifd].commit()

        # added address should be there
        assert ("172.16.21.1", 24) in self.ip.interfaces[self.ifd].ipaddr
        # and the one, added by the callback, too
        assert ("172.16.22.1", 24) in self.ip.interfaces[self.ifd].ipaddr

        # unregister callback
        self.ip.interfaces[self.ifd].unregister_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 0

    def _test_commit_hook_negative(self):
        require_user("root")

        # test exception to differentiate
        class CBException(Exception):
            pass

        # test callback, that always fail
        def cb(interface, snapshot, transaction):
            raise CBException()

        # register callback and check CB chain length
        self.ip.interfaces[self.ifd].register_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 1

        # create a transaction and commit it; should fail
        # 'cause of the callback
        if self.ip.interfaces[self.ifd]._mode == "explicit":
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].add_ip("172.16.21.1/24")
        try:
            self.ip.interfaces[self.ifd].commit()
        except CBException:
            pass

        # added address should be removed
        assert ("172.16.21.1", 24) not in self.ip.interfaces[self.ifd].ipaddr

        # unregister callback
        self.ip.interfaces[self.ifd].unregister_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 0

    def test_review(self):
        assert len(self.ip.interfaces.lo._tids) == 0
        if self.ip.interfaces.lo._mode == "explicit":
            self.ip.interfaces.lo.begin()
        self.ip.interfaces.lo.add_ip("172.16.21.1/24")
        r = self.ip.interfaces.lo.review()
        assert len(r["+ipaddr"]) == 1
        assert len(r["-ipaddr"]) == 0
        assert len(r["+ports"]) == 0
        assert len(r["-ports"]) == 0
        # +/-ipaddr, +/-ports
        assert len([i for i in r if r[i] is not None]) == 4
        self.ip.interfaces.lo.drop()

    def test_rename(self):
        require_user("root")

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        self.ip.create(ifname=ifA, kind="dummy").commit()

        if self.ip.interfaces[ifA]._mode == "explicit":
            self.ip.interfaces[ifA].begin()
        self.ip.interfaces[ifA].ifname = ifB
        self.ip.interfaces[ifA].commit()

        assert ifB in self.ip.interfaces
        assert ifA not in self.ip.interfaces

        if self.ip.interfaces[ifB]._mode == "explicit":
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifB].ifname = ifA
        self.ip.interfaces[ifB].commit()

        assert ifB not in self.ip.interfaces
        assert ifA in self.ip.interfaces

    def test_routes_keys(self):
        assert "172.16.0.0/24" not in self.ip.routes
        # create but not commit
        self.ip.routes.add(dst="172.16.0.0/24", gateway="127.0.0.1")
        # checks
        assert "172.16.0.0/24" in self.ip.routes
        assert "172.16.0.0/24" in list(self.ip.routes.keys())

    def test_routes(self):
        require_user("root")
        assert "172.16.0.0/24" not in self.ip.routes

        # create a route
        with self.ip.routes.add({"dst": "172.16.0.0/24", "gateway": "127.0.0.1"}) as r:
            pass
        assert "172.16.0.0/24" in self.ip.routes.keys()
        assert grep("ip ro", pattern="172.16.0.0/24.*127.0.0.1")

        # change the route
        with self.ip.routes["172.16.0.0/24"] as r:
            r.gateway = "127.0.0.2"
        assert self.ip.routes["172.16.0.0/24"].gateway == "127.0.0.2"
        assert grep("ip ro", pattern="172.16.0.0/24.*127.0.0.2")

        # delete the route
        with self.ip.routes["172.16.0.0/24"] as r:
            r.remove()
        assert "172.16.0.0/24" not in self.ip.routes.keys()
        assert not grep("ip ro", pattern="172.16.0.0/24")

    def test_routes_multipath_gateway(self):
        require_user("root")
        ifR = self.get_ifname()

        with self.ip.create(ifname=ifR, kind="dummy") as i:
            i.add_ip("172.16.231.1/24")
            i.up()

        r = self.ip.routes.add(
            {
                "dst": "172.16.232.0/24",
                "multipath": [
                    {"gateway": "172.16.231.2", "hops": 20},
                    {"gateway": "172.16.231.3", "hops": 30},
                    {"gateway": "172.16.231.4"},
                ],
            }
        )
        r.commit()
        assert grep("ip ro", pattern="172.16.232.0/24")
        assert grep("ip ro", pattern="nexthop.*172.16.231.2.*weight.*21")
        assert grep("ip ro", pattern="nexthop.*172.16.231.3.*weight.*31")
        assert grep("ip ro", pattern="nexthop.*172.16.231.4.*weight.*1")

        with self.ip.routes["172.16.232.0/24"] as r:
            r.add_nh({"gateway": "172.16.231.5", "hops": 50})
            r.del_nh({"gateway": "172.16.231.2"})
        assert grep("ip ro", pattern="172.16.232.0/24")
        assert grep("ip ro", pattern="nexthop.*172.16.231.5.*weight.*51")
        assert grep("ip ro", pattern="nexthop.*172.16.231.3.*weight.*31")
        assert grep("ip ro", pattern="nexthop.*172.16.231.4.*weight.*1")

    def test_routes_metrics(self):
        require_user("root")
        assert "172.16.0.0/24" not in self.ip.routes.keys()

        # create a route
        self.ip.routes.add({"dst": "172.16.0.0/24", "gateway": "127.0.0.1", "metrics": {"mtu": 1360}}).commit()
        assert grep("ip ro", pattern="172.16.0.0/24.*mtu 1360")

        # change metrics
        with self.ip.routes["172.16.0.0/24"] as r:
            r.metrics.mtu = 1400
        assert self.ip.routes["172.16.0.0/24"]["metrics"]["mtu"] == 1400
        assert grep("ip ro", pattern="172.16.0.0/24.*mtu 1400")

        # delete the route
        with self.ip.routes["172.16.0.0/24"] as r:
            r.remove()

        assert "172.16.0.0/24" not in self.ip.routes.keys()
        assert not grep("ip ro", pattern="172.16.0.0/24")

    def test_wait_ip_exact(self):
        ts = time.time()
        ret = self.ip.interfaces.lo.wait_ip("127.0.0.1", timeout=2)
        assert (time.time() - ts) < 2
        assert ret

    def test_wait_ip_net(self):
        ts = time.time()
        ret = self.ip.interfaces.lo.ipaddr.wait_ip("127.0.0.0", 8, timeout=2)
        assert (time.time() - ts) < 2
        assert ret

    def test_wait_ip_exact_fail(self):
        ts = time.time()
        ret = self.ip.interfaces.lo.wait_ip("1.1.1.1", timeout=2)
        assert (time.time() - ts) >= 2
        assert not ret

    def test_wait_ip_net_fail(self):
        ts = time.time()
        ret = self.ip.interfaces.lo.ipaddr.wait_ip("172.6.0.0", 24, timeout=2)
        assert (time.time() - ts) >= 2
        assert not ret

    @skip_if_not_supported
    def _test_shadow(self, kind):
        ifA = self.get_ifname()

        a = self.ip.create(ifname=ifA, kind=kind).commit()
        if a._mode == "explicit":
            a.begin()
        a.shadow().commit()
        assert ifA in self.ip.interfaces
        assert not grep("ip link", pattern=ifA)
        time.sleep(0.5)
        b = self.ip.create(ifname=ifA, kind=kind).commit()
        assert a == b
        assert grep("ip link", pattern=ifA)

    def test_shadow_bond(self):
        require_user("root")
        self._test_shadow("bond")

    def test_shadow_bridge(self):
        require_user("root")
        self._test_shadow("bridge")

    def test_shadow_dummy(self):
        require_user("root")
        self._test_shadow("dummy")

    def test_updown(self):
        require_user("root")

        if self.ip.interfaces[self.ifd]._mode == "explicit":
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].up()
        self.ip.interfaces[self.ifd].commit()
        assert self.ip.interfaces[self.ifd].flags & 1

        if self.ip.interfaces[self.ifd]._mode == "explicit":
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].down()
        self.ip.interfaces[self.ifd].commit()
        assert not (self.ip.interfaces[self.ifd].flags & 1)

    def test_slave_data(self):
        require_user("root")

        ifBR = self.get_ifname()
        ifP = self.get_ifname()
        self.ip.debug = True

        bridge = self.ip.create(ifname=ifBR, kind="bridge").commit()
        port = self.ip.create(ifname=ifP, kind="dummy").commit()

        if self.ip.mode == "explicit":
            bridge.begin()
        bridge.add_port(port)
        bridge.up()
        bridge.commit()

        li = port.nlmsg.get_attr("IFLA_LINKINFO")
        skind = li.get_attr("IFLA_INFO_SLAVE_KIND")
        sdata = li.get_attr("IFLA_INFO_SLAVE_DATA")
        self.ip.debug = False
        if skind is None or sdata is None:
            raise SkipTest("slave data not provided")

        assert sdata.get_attr("IFLA_BRPORT_STATE") is not None
        assert sdata.get_attr("IFLA_BRPORT_MODE") is not None

    def test_fail_ipaddr(self):
        require_user("root")

        ifA = self.get_ifname()

        i = self.ip.create(ifname=ifA, kind="dummy").commit()
        assert not len(i.ipaddr)
        if i._mode == "explicit":
            i.begin()
        i.add_ip("123.456.789.1024/153")
        try:
            i.commit()
        except socket.error as e:
            if not e.args[0].startswith("illegal IP"):
                raise
        assert not len(i.ipaddr)
        if i._mode == "explicit":
            i.begin()
        i.remove().commit()
        assert ifA not in self.ip.interfaces

    def test_multiple_ips_one_transaction(self):
        require_user("root")

        ifA = self.get_ifname()
        with self.ip.create(kind="dummy", ifname=ifA) as i:
            for x in range(1, 255):
                i.add_ip("172.16.0.%i/24" % x)
            i.up()

        idx = self.ip.interfaces[ifA].index
        assert len(self.ip.nl.get_addr(index=idx, family=2)) == 254

    def test_json_dump(self):
        require_user("root")

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        # set up the interface
        with self.ip.create(kind="dummy", ifname=ifA) as i:
            i.add_ip("172.16.0.1/24")
            i.up()

        # imitate some runtime
        time.sleep(2)

        # make a backup
        backup = self.ip.interfaces[ifA].dump()
        assert isinstance(backup, dict)

        # remove index and protinfo -- make it portable
        del backup["index"]
        if "protinfo" in backup:
            del backup["protinfo"]

        # serialize
        backup = json.dumps(backup)

        # remove the interface
        with self.ip.interfaces[ifA] as i:
            i.remove()

        # create again, but with different name
        self.ip.create(kind="dummy", ifname=ifB).commit()

        # load the backup
        # 1. prepare to the restore: bring it down
        with self.ip.interfaces[ifB] as i:
            i.down()
        # 2. please notice, the interface will be renamed after the backup
        with self.ip.interfaces[ifB] as i:
            i.load(json.loads(backup))

        # check :)
        assert ifA in self.ip.interfaces
        assert ifB not in self.ip.interfaces
        for ipaddr in json.loads(backup)["ipaddr"]:
            assert tuple(ipaddr) in self.ip.interfaces[ifA].ipaddr
        assert self.ip.interfaces[ifA].flags & 1

    def test_freeze_del(self):
        require_user("root")

        interface = self.ip.interfaces[self.ifd]

        # set up the interface
        with interface as i:
            i.add_ip("172.16.0.1/24")
            i.add_ip("172.16.1.1/24")
            i.up()

        # check
        assert ("172.16.0.1", 24) in interface.ipaddr
        assert ("172.16.1.1", 24) in interface.ipaddr
        assert interface.flags & 1

        interface.freeze()

        # delete interface with an external routine
        remove_link(interface.ifname)

        # wait for a second
        time.sleep(1)

        # check if it is back
        ipdb = IPDB()
        try:
            ifc = ipdb.interfaces[self.ifd]
            assert ("172.16.0.1", 24) in ifc.ipaddr
            assert ("172.16.1.1", 24) in ifc.ipaddr
            assert ifc.flags & 1
        except:
            raise
        finally:
            interface.unfreeze()
            ipdb.release()

    def test_freeze(self):
        require_user("root")

        interface = self.ip.interfaces[self.ifd]

        # set up the interface
        with interface as i:
            i.add_ip("172.16.0.1/24")
            i.add_ip("172.16.1.1/24")
            i.up()

        # check
        assert ("172.16.0.1", 24) in interface.ipaddr
        assert ("172.16.1.1", 24) in interface.ipaddr
        assert interface.flags & 1

        # assert routine
        def probe():
            # The freeze results are dynamic: it is not a real freeze,
            # it is a restore routine. So it takes time for results
            # to stabilize
            err = None
            for _ in range(3):
                err = None
                interface.ipaddr.set_target((("172.16.0.1", 24), ("172.16.1.1", 24)))
                interface.ipaddr.target.wait()
                try:
                    assert ("172.16.0.1", 24) in interface.ipaddr
                    assert ("172.16.1.1", 24) in interface.ipaddr
                    assert interface.flags & 1
                    break
                except AssertionError as e:
                    err = e
                    continue
                except Exception as e:
                    err = e
                    break
            if err is not None:
                interface.unfreeze()
                i2.close()
                raise err

        # freeze
        interface.freeze()

        # change the interface somehow
        i2 = IPRoute()
        i2.addr("delete", interface.index, "172.16.0.1", 24)
        i2.addr("delete", interface.index, "172.16.1.1", 24)
        probe()

        # unfreeze
        self.ip.interfaces[self.ifd].unfreeze()

        try:
            i2.addr("delete", interface.index, "172.16.0.1", 24)
            i2.addr("delete", interface.index, "172.16.1.1", 24)
        except:
            pass
        finally:
            i2.close()

        # should be up, but w/o addresses
        interface.ipaddr.set_target(set())
        interface.ipaddr.target.wait(3)
        assert ("172.16.0.1", 24) not in self.ip.interfaces[self.ifd].ipaddr
        assert ("172.16.1.1", 24) not in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

    def test_snapshots(self):
        require_user("root")

        ifB = self.get_ifname()

        # set up the interface
        with self.ip.interfaces[self.ifd] as i:
            i.add_ip("172.16.0.1/24")
            i.up()

        # check it
        assert ("172.16.0.1", 24) in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

        # make a snapshot
        s = self.ip.interfaces[self.ifd].snapshot()
        i = self.ip.interfaces[self.ifd]

        # check it
        assert i.last_snapshot_id() == s

        # unset the interface
        with self.ip.interfaces[self.ifd] as i:
            i.del_ip("172.16.0.1/24")
            i.down()

        # we can not rename the interface while it is up,
        # so do it in two turns
        with self.ip.interfaces[self.ifd] as i:
            i.ifname = ifB

        # check it
        assert ifB in self.ip.interfaces
        assert self.ifd not in self.ip.interfaces
        y = self.ip.interfaces[ifB]
        assert i == y
        assert ("172.16.0.1", 24) not in y.ipaddr
        assert not (y.flags & 1)

        # revert snapshot
        y.revert(s).commit()

        # check it
        assert ifB not in self.ip.interfaces
        assert self.ifd in self.ip.interfaces
        assert ("172.16.0.1", 24) in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

    @skip_if_not_supported
    def _test_ipv(self, ipv, kind):
        require_user("root")

        ifA = self.get_ifname()

        i = self.ip.create(kind=kind, ifname=ifA).commit()
        if self.ip.interfaces[ifA]._mode == "explicit":
            self.ip.interfaces[ifA].begin()

        if ipv == 4:
            addr = "172.16.0.1/24"
        elif ipv == 6:
            addr = "fdb3:84e5:4ff4:55e4::1/64"
        else:
            raise Exception("bad IP version")

        i.add_ip(addr).commit()
        pre_target = addr.split("/")
        target = (pre_target[0], int(pre_target[1]))
        assert target in i["ipaddr"]

    def test_ipv4_dummy(self):
        self._test_ipv(4, "dummy")

    def test_ipv4_bond(self):
        self._test_ipv(4, "bond")

    def test_ipv4_bridge(self):
        self._test_ipv(4, "bridge")

    def test_ipv6_dummy(self):
        self._test_ipv(6, "dummy")

    def test_ipv6_bond(self):
        self._test_ipv(6, "bond")

    def test_ipv6_bridge(self):
        self._test_ipv(6, "bridge")

    @skip_if_not_supported
    def test_create_tuntap_fail(self):
        try:
            self.ip.create(ifname="fAiL", kind="tuntap", mode="fail").commit()
        except:
            assert not grep("ip link", pattern="fAiL")
            return
        raise Exception("tuntap create succeded")

    @skip_if_not_supported
    def test_create_tuntap(self):
        require_user("root")

        ifA = self.get_ifname()
        self.ip.create(ifname=ifA, kind="tuntap", mode="tap", uid=1, gid=1).commit()

        assert ifA in self.ip.interfaces
        assert grep("ip link", pattern=ifA)

    def test_global_create(self):
        require_user("root")

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, kind="dummy")
        self.ip.create(ifname=ifB, kind="dummy")
        self.ip.commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert grep("ip link", pattern=ifA)
        assert grep("ip link", pattern=ifB)

    def test_global_priorities(self):
        require_user("root")
        ifA = self.get_ifname()
        ifB = self.get_ifname()
        ifC = self.get_ifname()
        a = self.ip.create(ifname=ifA, kind="dummy").commit()
        #
        if a._mode == "explicit":
            a.begin()

        # prepare transaction: two interface creations
        # and one failure on an existing interface
        a.set_address("11:22:33:44:55:66")
        b = self.ip.create(ifname=ifB, kind="dummy")
        c = self.ip.create(ifname=ifC, kind="dummy")
        # now assign priorities
        b.ipdb_priority = 15  # will be execute first
        a.ipdb_priority = 10  # second -- and fail
        c.ipdb_priority = 5  # should not be executed
        # prepare watchdogs
        wdb = self.ip.watchdog(ifname=ifB)
        wdc = self.ip.watchdog(ifname=ifC)
        # run the transaction
        try:
            self.ip.commit()
        except NetlinkError:
            pass
        # control system state
        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert ifC in self.ip.interfaces
        assert a.ipdb_scope == "system"
        assert b.ipdb_scope == "create"
        assert c.ipdb_scope == "create"
        assert a.address != "11:22:33:44:55:66"
        assert grep("ip link", pattern=ifA)
        assert not grep("ip link", pattern=ifB)
        assert not grep("ip link", pattern=ifC)
        wdb.wait(1)
        wdc.wait(1)
        assert wdb.is_set
        assert not wdc.is_set

    def test_global_rollback(self):
        require_user("root")

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        a = self.ip.create(ifname=ifA, kind="dummy").commit()
        #
        if a._mode == "explicit":
            a.begin()
        a.remove()
        b = self.ip.create(ifname=ifB, kind="dummy")
        b.set_mtu(1500).set_address("11:22:33:44:55:66")
        try:
            self.ip.commit()
        except NetlinkError:
            pass

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert b.ipdb_scope == "create"
        assert grep("ip link", pattern=ifA)
        assert not grep("ip link", pattern=ifB)

    def test_global_netns(self):
        require_user("root")

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        ns = str(uuid.uuid4())

        with IPDB(nl=NetNS(ns)) as nsdb:
            v1 = self.ip.create(ifname="x" + ifA, kind="veth", peer=ifA)
            v2 = self.ip.create(ifname="x" + ifB, kind="veth", peer=ifB)
            if v1._mode == "explicit":
                v1.begin()
                v2.begin()
            v1.net_ns_fd = ns
            v2.net_ns_fd = ns
            self.ip.commit()
            nsdb.interfaces["x" + ifA].ifname = "eth0"
            nsdb.interfaces["x" + ifB].ifname = "eth1"
            nsdb.commit()
            if self.ip.interfaces[ifA]._mode == "explicit":
                self.ip.interfaces[ifA].begin()
                self.ip.interfaces[ifB].begin()
            self.ip.interfaces[ifA].up()
            self.ip.interfaces[ifB].up()
            self.ip.commit()

        assert "x" + ifA not in self.ip.interfaces
        assert "x" + ifB not in self.ip.interfaces
        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert self.ip.interfaces[ifA].flags & 1
        assert self.ip.interfaces[ifB].flags & 1

        if self.ip.interfaces[ifA]._mode == "explicit":
            self.ip.interfaces[ifA].begin()
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifA].remove()
        self.ip.interfaces[ifB].remove()
        self.ip.commit()
        netns.remove(ns)

    @skip_if_not_supported
    def test_create_veth(self):
        require_user("root")

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        self.ip.create(ifname=ifA, kind="veth", peer=ifB).commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces

    def test_create_fail(self):
        require_user("root")

        ifA = self.get_ifname()

        # create with mac 11:22:33:44:55:66 should fail
        i = self.ip.create(kind="dummy", ifname=ifA, address="11:22:33:44:55:66")
        try:
            i.commit()
        except NetlinkError:
            pass

        assert i._mode == "invalid"
        assert ifA not in self.ip.interfaces

    def test_create_dqn(self):
        require_user("root")
        ifA = self.get_ifname()

        i = self.ip.create(kind="dummy", ifname=ifA)
        i.add_ip("172.16.0.1/255.255.255.0")
        i.commit()
        assert ("172.16.0.1", 24) in self.ip.interfaces[ifA].ipaddr
        assert "172.16.0.1/24" in get_ip_addr(interface=ifA)

    def test_create_double_reuse(self):
        require_user("root")

        ifA = self.get_ifname()
        # create an interface
        i1 = self.ip.create(kind="dummy", ifname=ifA).commit()
        try:
            # this call should fail on the very first step:
            # `bala` interface already exists
            self.ip.create(kind="dummy", ifname=ifA)
        except CreateException:
            pass
        # add `reuse` keyword -- now should pass
        i2 = self.ip.create(kind="dummy", ifname=ifA, reuse=True).commit()
        # assert that we have got references to the same interface
        assert i1 == i2

    @skip_if_not_supported
    def _create_double(self, kind):
        require_user("root")
        ifA = self.get_ifname()

        self.ip.create(kind=kind, ifname=ifA).commit()
        try:
            self.ip.create(kind=kind, ifname=ifA).commit()
        except CreateException:
            pass

    def test_create_double_dummy(self):
        self._create_double("dummy")

    def test_create_double_bridge(self):
        self._create_double("bridge")

    def test_create_double_bond(self):
        self._create_double("bond")

    def test_create_plain(self):
        require_user("root")
        ifA = self.get_ifname()

        i = self.ip.create(kind="dummy", ifname=ifA)
        i.add_ip("172.16.0.1/24")
        i.commit()
        assert ("172.16.0.1", 24) in self.ip.interfaces[ifA].ipaddr
        assert "172.16.0.1/24" in get_ip_addr(interface=ifA)

    def test_create_and_remove(self):
        require_user("root")

        ifA = self.get_ifname()

        with self.ip.create(kind="dummy", ifname=ifA) as i:
            i.add_ip("172.16.0.1/24")
        assert ("172.16.0.1", 24) in self.ip.interfaces[ifA].ipaddr
        assert "172.16.0.1/24" in get_ip_addr(interface=ifA)

        with self.ip.interfaces[ifA] as i:
            i.remove()
        assert ifA not in self.ip.interfaces

    def test_dqn_mask(self):
        require_user("root")

        iface = self.ip.interfaces[self.ifd]
        with iface as i:
            i.add_ip("172.16.0.1/24")
            i.add_ip("172.16.0.2", mask=24)
            i.add_ip("172.16.0.3/255.255.255.0")
            i.add_ip("172.16.0.4", mask="255.255.255.0")

        assert ("172.16.0.1", 24) in iface.ipaddr
        assert ("172.16.0.2", 24) in iface.ipaddr
        assert ("172.16.0.3", 24) in iface.ipaddr
        assert ("172.16.0.4", 24) in iface.ipaddr

    @skip_if_not_supported
    def test_master_cleanup_del_port(self):
        require_user("root")

        ifMname = self.get_ifname()
        ifPname = self.get_ifname()

        ifM = self.ip.create(ifname=ifMname, kind="bridge").commit()
        ifP = self.ip.create(ifname=ifPname, kind="dummy").commit()

        if self.ip.mode == "explicit":
            ifM.begin()
        ifM.add_port(ifP).commit()

        assert ifP.index in ifM.ports
        assert ifP.master == ifM.index

        if self.ip.mode == "explicit":
            ifM.begin()
        ifM.del_port(ifP).commit()

        assert ifPname in self.ip.interfaces
        assert ifP.index not in ifM.ports
        assert ifP.master is None

    @skip_if_not_supported
    def _create_master(self, kind, **kwarg):

        ifM = self.get_ifname()
        ifP1 = self.get_ifname()
        ifP2 = self.get_ifname()

        self.ip.create(kind="dummy", ifname=ifP1).commit()
        self.ip.create(kind="dummy", ifname=ifP2).commit()

        with self.ip.create(kind=kind, ifname=ifM, **kwarg) as i:
            i.add_port(self.ip.interfaces[ifP1])
            i.add_ip("172.16.0.1/24")

        with self.ip.interfaces[ifM] as i:
            i.add_port(self.ip.interfaces[ifP2])
            i.add_ip("172.16.0.2/24")

        assert ("172.16.0.1", 24) in self.ip.interfaces[ifM].ipaddr
        assert ("172.16.0.2", 24) in self.ip.interfaces[ifM].ipaddr
        assert "172.16.0.1/24" in get_ip_addr(interface=ifM)
        assert "172.16.0.2/24" in get_ip_addr(interface=ifM)
        assert self.ip.interfaces[ifP1].if_master == self.ip.interfaces[ifM].index
        assert self.ip.interfaces[ifP2].if_master == self.ip.interfaces[ifM].index

        with self.ip.interfaces[ifM] as i:
            i.del_port(self.ip.interfaces[ifP1])
            i.del_port(self.ip.interfaces[ifP2])
            i.del_ip("172.16.0.1/24")
            i.del_ip("172.16.0.2/24")

        assert ("172.16.0.1", 24) not in self.ip.interfaces[ifM].ipaddr
        assert ("172.16.0.2", 24) not in self.ip.interfaces[ifM].ipaddr
        assert "172.16.0.1/24" not in get_ip_addr(interface=ifM)
        assert "172.16.0.2/24" not in get_ip_addr(interface=ifM)
        assert self.ip.interfaces[ifP1].if_master is None
        assert self.ip.interfaces[ifP2].if_master is None

    def test_create_bridge(self):
        require_user("root")
        self._create_master("bridge")

    def test_create_bond(self):
        require_user("root")
        self._create_master("bond")

    def test_create_team(self):
        require_user("root")
        self._create_master("team")

    def test_create_bond2(self):
        require_user("root")
        self._create_master("bond", bond_mode=2)

    @skip_if_not_supported
    def _create_macvx_mode(self, kind, mode):
        require_user("root")
        ifL = self.get_ifname()
        ifV = self.get_ifname()
        ifdb = self.ip.interfaces

        self.ip.create(kind="dummy", ifname=ifL).commit()
        self.ip.create(**{"kind": kind, "link": ifdb[ifL], "ifname": ifV, "%s_mode" % kind: mode}).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].link == ifdb[ifL].index
            assert ifdb[ifV]["%s_mode" % kind] == mode
        except Exception:
            raise
        finally:
            ip2.release()

    def test_create_macvtap_vepa(self):
        return self._create_macvx_mode("macvtap", "vepa")

    def test_create_macvtap_bridge(self):
        return self._create_macvx_mode("macvtap", "bridge")

    def test_create_macvlan_vepa(self):
        return self._create_macvx_mode("macvlan", "vepa")

    def test_create_macvlan_bridge(self):
        return self._create_macvx_mode("macvlan", "bridge")

    def test_create_utf_name(self):
        require_user("root")
        ifO = "ༀ"
        self.ip.create(kind="dummy", ifname=ifO).commit()
        assert ifO in self.ip.interfaces
        assert self.ip.nl.link_lookup(ifname=ifO)
        if self.ip.interfaces[ifO]._mode == "explicit":
            self.ip.interfaces[ifO].begin()
        self.ip.interfaces[ifO].remove().commit()

    @skip_if_not_supported
    def test_create_gre(self):
        require_user("root")

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        with self.ip.create(kind="dummy", ifname=ifL) as i:
            i.add_ip("172.16.0.1/24")
            i.up()

        self.ip.create(kind="gre", ifname=ifV, gre_local="172.16.0.1", gre_remote="172.16.0.2", gre_ttl=16).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].gre_local == "172.16.0.1"
            assert ifdb[ifV].gre_remote == "172.16.0.2"
            assert ifdb[ifV].gre_ttl == 16
        except Exception:
            raise
        finally:
            ip2.release()

    @skip_if_not_supported
    def test_create_gretap(self):
        require_user("root")

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        with self.ip.create(kind="dummy", ifname=ifL) as i:
            i.add_ip("172.16.0.1/24")
            i.up()

        self.ip.create(
            kind="gretap",
            ifname=ifV,
            gre_local="172.16.0.1",
            gre_ikey=1,
            gre_okey=2,
            gre_iflags=0x0020,
            gre_oflags=0x0020,
            gre_collect_metadata=True,
            gre_ttl=16,
        ).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].gre_local == "172.16.0.1"
            assert ifdb[ifV].gre_ikey == 1
            assert ifdb[ifV].gre_okey == 2
            assert ifdb[ifV].gre_iflags == 0x0020
            assert ifdb[ifV].gre_oflags == 0x0020
            if kernel_version_ge(4, 3):
                assert ifdb[ifV].gre_collect_metadata
            assert ifdb[ifV].gre_ttl == 16
        except Exception:
            raise
        finally:
            ip2.release()

    @skip_if_not_supported
    def test_create_vxlan(self):
        require_user("root")

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        ifdb = self.ip.interfaces

        self.ip.create(kind="dummy", ifname=ifL).commit()
        self.ip.create(kind="vxlan", ifname=ifV, vxlan_link=ifdb[ifL], vxlan_id=101, vxlan_group="239.1.1.1").commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces

        try:
            assert ifdb[ifV].vxlan_link == ifdb[ifL].index
            assert ifdb[ifV].vxlan_group == "239.1.1.1"
            assert ifdb[ifV].vxlan_id == 101
        except Exception:
            raise
        finally:
            ip2.release()

    def test_create_vlan_by_interface(self):
        require_user("root")
        require_8021q()
        ifL = self.get_ifname()
        ifV = self.get_ifname()

        self.ip.create(kind="dummy", ifname=ifL).commit()
        self.ip.create(kind="vlan", ifname=ifV, link=self.ip.interfaces[ifL], vlan_id=101).commit()

        assert self.ip.interfaces[ifV].link == self.ip.interfaces[ifL].index

    def test_create_vlan_by_index(self):
        require_user("root")
        require_8021q()
        ifL = self.get_ifname()
        ifV = self.get_ifname()

        self.ip.create(kind="dummy", ifname=ifL).commit()
        self.ip.create(kind="vlan", ifname=ifV, link=self.ip.interfaces[ifL].index, vlan_id=101).commit()

        assert self.ip.interfaces[ifV].link == self.ip.interfaces[ifL].index

    def test_remove_secondaries(self):
        require_user("root")

        ifA = self.get_ifname()

        with self.ip.create(kind="dummy", ifname=ifA) as i:
            i.add_ip("172.16.0.1", 24)
            i.add_ip("172.16.0.2", 24)

        assert ifA in self.ip.interfaces
        assert ("172.16.0.1", 24) in self.ip.interfaces[ifA].ipaddr
        assert ("172.16.0.2", 24) in self.ip.interfaces[ifA].ipaddr
        assert "172.16.0.1/24" in get_ip_addr(interface=ifA)
        assert "172.16.0.2/24" in get_ip_addr(interface=ifA)

        if i._mode == "explicit":
            i.begin()

        i.del_ip("172.16.0.1", 24)
        i.del_ip("172.16.0.2", 24)
        i.commit()

        assert ("172.16.0.1", 24) not in self.ip.interfaces[ifA].ipaddr
        assert ("172.16.0.2", 24) not in self.ip.interfaces[ifA].ipaddr
        assert "172.16.0.1/24" not in get_ip_addr(interface=ifA)
        assert "172.16.0.2/24" not in get_ip_addr(interface=ifA)
Ejemplo n.º 7
0
def clean(graph, dry_run=False, instance_id=None, strays=False):
    """
    Remove namespaces listed in :data:`graph` and stop scripts

    :param networkx.Graph graph: The graph for which we want to clean up
    :param bool dry_run: If set makes Meshinery not touch any namespaces
    :param str instance_id: If set changes the middle section of each
    namespace's name; current PID by default

    :return networkx.Graph: The same graph after cleanup
    """
    if instance_id is None:
        instance_id = os.getpid()

    # Remove namespaces and kill running commands if applicable
    for node_name in graph:
        node = graph.node[node_name]
        netns_name = 'meshinery-{}-{}'.format(instance_id, node_name)
        try:
            if not dry_run:
                netns.remove(netns_name)
                logging.info('Removed namespace {}'.format(netns_name))

        # The namespace does not exist
        except FileNotFoundError as e:
            logging.debug('Namespace {} doesn\'t exist - not removing'.format(
                netns_name))

        # Grab the per-node command and see if it's still running
        cmd_handle = node.get('command_handle')
        if cmd_handle is not None:
            if cmd_handle.poll() is not None:
                logging.warn('{}: "{}" was not running at cleanup time'.format(
                    node_name, node['command']))

            # Play nice - send initial SIGTERM
            cmd_handle.terminate()
            logging.debug('{}: Sent SIGTERM to PID {} ("{}")'.format(
                node['netns'], cmd_handle.pid, node['command']))

            # Wait the specified/default time before nuclear option
            command_exit_delay = node.get('command_exit_delay',
                                          DEFAULT_COMMAND_EXIT_TIMEOUT)
            time.sleep(command_exit_delay)

            # Send the SIGKILL if applicable
            if cmd_handle.poll() is None:
                cmd_handle.kill()
                logging.debug(
                    '{nn}: "{cmd}" was SIGKILLed (was PID {pid})'.format(
                        nn=node_name, cmd=node['command'], pid=cmd_handle.pid))
            else:
                logging.debug(
                    '{nn}: "{cmd}" quit gracefully. (was PID {pid})'.format(
                        nn=node_name, cmd=node['command'], pid=cmd_handle.pid))

            stdout, stderr = cmd_handle.communicate()
            logging.debug('{nn}: "{cmd}" stdout:\n{out}'.format(
                nn=node_name, cmd=node['command'], out=str(stdout, 'utf-8')))
            logging.debug('{nn}: "{cmd}" stderr:\n{err}'.format(
                nn=node_name, cmd=node['command'], err=str(stderr, 'utf-8')))
        else:
            logging.debug('{}: No command to stop.'.format(node_name))

    # Remove stray interfaces
    if strays:
        ipdb = IPDB()
        for node_name_a, node_name_b in graph.edges:
            if_name = '{}-{}'.format(node_name_a, node_name_b)
            try:
                ipdb.interfaces[if_name].remove()
                logging.info('Removed stray interface {}'.format(if_name))
            except KeyError as e:
                logging.debug(
                    'Stray interface {} doesn\'t exist -- not removing'.format(
                        if_name))
        ipdb.commit()
        ipdb.release()
Ejemplo n.º 8
0
def prepare_namespaces(graph, dry_run=False, instance_id=None):
    """
    Create a veth-connected mesh from :data:`graph`

    :param networkx.Graph graph: The graph defining the test mesh
    :param bool dry_run: If set makes Meshinery not touch any namespaces
    :param str instance_id: If set changes the middle section of each
    namespace's name; current PID by default
    :return networkx.Graph: The same graph containing runtime attributes
    """
    if instance_id is None:
        instance_id = os.getpid()
    # Create namespaces
    for node_name in graph.nodes:
        ns_name = 'meshinery-{}-{}'.format(instance_id, node_name)
        logging.info('Adding namespace "{}"'.format(ns_name))
        if not dry_run:
            # Establish the namespace
            ns = NetNS(ns_name)
            ipdb = IPDB(nl=ns)
            ipdb.interfaces['lo'].up().commit()
            ipdb.commit()
            ipdb.release()

            # Enable forwarding
            sysctl_cmd = shlex.split(
                'sysctl -w net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1'
            )
            subprocess.run(sysctl_cmd,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE).check_returncode()

            graph.node[node_name]['netns'] = ns_name
            graph.node[node_name]['interfaces'] = [
            ]  # Needed so that we can safely append later

    # Create veth bridges
    for node_name, neigh_name in graph.edges:
        neighbors = graph[node_name]

        node = graph.node[node_name]
        neigh = graph.node[neigh_name]

        # If an edge hasn't been created yet
        node_iface = '{}-{}'.format(node_name, neigh_name)
        neigh_iface = '{}-{}'.format(neigh_name, node_name)

        if not dry_run:
            node_ns_handle = NetNS(node['netns'])
            neigh_ns_handle = NetNS(neigh['netns'])

            ipdb = IPDB()

            # Create namespace-aware IPDB handles
            node_ipdb = IPDB(nl=node_ns_handle)
            neigh_ipdb = IPDB(nl=neigh_ns_handle)

            # Create a veth pair
            ipdb.create(ifname=node_iface, kind='veth',
                        peer=neigh_iface).commit()

            # Assign node IP
            ipdb.interfaces[node_iface]['net_ns_fd'] = node['netns']
            ipdb.commit()
            node_ipdb.interfaces[node_iface].add_ip(node['ip'])
            node_ipdb.interfaces[node_iface].up().commit()

            # Assign neighbor IP
            ipdb.interfaces[neigh_iface].add_ip(neigh['ip'])
            ipdb.interfaces[neigh_iface]['net_ns_fd'] = neigh['netns']
            ipdb.commit()
            neigh_ipdb.interfaces[neigh_iface].add_ip(neigh['ip'])
            neigh_ipdb.interfaces[neigh_iface].up().commit()

            ipdb.release()

            node_ipdb.release()
            neigh_ipdb.release()

            node['interfaces'].append(node_iface)
            neigh['interfaces'].append(neigh_iface)

        logging.debug('Created %s and %s interfaces' %
                      (node_iface, neigh_iface))

    ipdb.release()
Ejemplo n.º 9
0
class TestExplicit(object):
    ip = None
    mode = 'explicit'

    def setup(self):
        self.ifaces = []
        self.ifd = self.get_ifname()
        create_link(self.ifd, kind='dummy')
        self.ip = IPDB(mode=self.mode)

    def get_ifname(self):
        ifname = uifname()
        self.ifaces.append(ifname)
        return ifname

    def teardown(self):
        for name in self.ifaces:
            try:
                # just a hardcore removal
                self.ip.nl.link_remove(self.ip.interfaces[name].index)
            except Exception:
                pass
        self.ip.release()
        self.ifaces = []

    def test_simple(self):
        assert len(list(self.ip.interfaces.keys())) > 0

    def test_empty_transaction(self):
        assert 'lo' in self.ip.interfaces
        with self.ip.interfaces.lo as i:
            assert isinstance(i.mtu, int)

    def test_idx_len(self):
        assert len(self.ip.by_name.keys()) == len(self.ip.by_index.keys())

    def test_idx_set(self):
        assert set(self.ip.by_name.values()) == set(self.ip.by_index.values())

    def test_idx_types(self):
        assert all(isinstance(i, int) for i in self.ip.by_index.keys())
        assert all(isinstance(i, basestring) for i in self.ip.by_name.keys())

    def test_addr_attributes(self):
        require_user('root')

        if1 = self.get_ifname()
        if2 = self.get_ifname()

        with self.ip.create(ifname=if1, kind='dummy') as i:
            # +scope host (=> broadcast == None)
            i.add_ip('172.16.102.1/24', scope=254)

        with self.ip.create(ifname=if2, kind='dummy') as i:
            # +broadcast (default scope == 0)
            i.add_ip('172.16.103.1/24', broadcast='172.16.103.128')

        index = self.ip.interfaces[if1]['index']
        addr = self.ip.nl.get_addr(index=index)[0]
        assert addr['scope'] == 254
        assert addr.get_attr('IFA_BROADCAST') is None

        index = self.ip.interfaces[if2]['index']
        addr = self.ip.nl.get_addr(index=index)[0]
        assert addr['scope'] == 0
        assert addr.get_attr('IFA_BROADCAST') == '172.16.103.128'

    def test_addr_loaded(self):
        for name in self.ip.by_name:
            assert len(self.ip.interfaces[name]['ipaddr']) == \
                len(get_ip_addr(name))

    def test_reprs(self):
        assert isinstance(repr(self.ip.interfaces.lo.ipaddr), basestring)
        assert isinstance(repr(self.ip.interfaces.lo), basestring)

    def test_dotkeys(self):
        # self.ip.lo hint for ipython
        assert 'lo' in dir(self.ip.interfaces)
        assert 'lo' in self.ip.interfaces
        assert self.ip.interfaces.lo == self.ip.interfaces['lo']
        # create attribute
        self.ip.interfaces['newitem'] = True
        self.ip.interfaces.newattr = True
        self.ip.interfaces.newitem = None
        assert self.ip.interfaces.newitem == self.ip.interfaces['newitem']
        assert self.ip.interfaces.newitem is None
        # delete attribute
        del self.ip.interfaces.newitem
        del self.ip.interfaces.newattr
        assert 'newattr' not in dir(self.ip.interfaces)

    @skip_if_not_supported
    def test_vlan_slave_bridge(self):
        # https://github.com/svinota/pyroute2/issues/58
        # based on the code by Petr Horáček
        dXname = self.get_ifname()
        vXname = self.get_ifname()
        vYname = self.get_ifname()
        brname = self.get_ifname()

        require_user('root')
        dX = self.ip.create(ifname=dXname, kind='dummy').commit()
        vX = self.ip.create(ifname=vXname, kind='vlan', link=dX,
                            vlan_id=101).commit()
        vY = self.ip.create(ifname=vYname, kind='vlan', link=dX,
                            vlan_id=102).commit()
        with self.ip.create(ifname=brname, kind='bridge') as i:
            i.add_port(vX)
            i.add_port(vY['index'])

        assert vX['index'] in self.ip.interfaces[brname]['ports']
        assert vY['index'] in self.ip.interfaces[brname].ports
        assert vX['link'] == dX['index']
        assert vY['link'] == dX['index']
        assert vX['master'] == self.ip.interfaces[brname]['index']
        assert vY['master'] == self.ip.interfaces[brname].index

    def _test_commit_hook_positive(self):
        require_user('root')

        # test callback, that adds an address by itself --
        # just to check the possibility
        def cb(interface, snapshot, transaction):
            self.ip.nl.addr('add',
                            self.ip.interfaces[self.ifd].index,
                            address='172.16.22.1',
                            mask=24)

        # register callback and check CB chain length
        self.ip.interfaces[self.ifd].register_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 1

        # create a transaction and commit it
        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].add_ip('172.16.21.1/24')
        self.ip.interfaces[self.ifd].commit()

        # added address should be there
        assert ('172.16.21.1', 24) in \
            self.ip.interfaces[self.ifd].ipaddr
        # and the one, added by the callback, too
        assert ('172.16.22.1', 24) in \
            self.ip.interfaces[self.ifd].ipaddr

        # unregister callback
        self.ip.interfaces[self.ifd].unregister_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 0

    def _test_commit_hook_negative(self):
        require_user('root')

        # test exception to differentiate
        class CBException(Exception):
            pass

        # test callback, that always fail
        def cb(interface, snapshot, transaction):
            raise CBException()

        # register callback and check CB chain length
        self.ip.interfaces[self.ifd].register_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 1

        # create a transaction and commit it; should fail
        # 'cause of the callback
        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].add_ip('172.16.21.1/24')
        try:
            self.ip.interfaces[self.ifd].commit()
        except CBException:
            pass

        # added address should be removed
        assert ('172.16.21.1', 24) not in \
            self.ip.interfaces[self.ifd].ipaddr

        # unregister callback
        self.ip.interfaces[self.ifd].unregister_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 0

    def test_review(self):
        assert len(self.ip.interfaces.lo._tids) == 0
        if self.ip.interfaces.lo._mode == 'explicit':
            self.ip.interfaces.lo.begin()
        self.ip.interfaces.lo.add_ip('172.16.21.1/24')
        r = self.ip.interfaces.lo.review()
        assert len(r['+ipaddr']) == 1
        assert len(r['-ipaddr']) == 0
        assert len(r['+ports']) == 0
        assert len(r['-ports']) == 0
        # +/-ipaddr, +/-ports
        assert len([i for i in r if r[i] is not None]) == 4
        self.ip.interfaces.lo.drop()

    def test_rename(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        self.ip.create(ifname=ifA, kind='dummy').commit()

        if self.ip.interfaces[ifA]._mode == 'explicit':
            self.ip.interfaces[ifA].begin()
        self.ip.interfaces[ifA].ifname = ifB
        self.ip.interfaces[ifA].commit()

        assert ifB in self.ip.interfaces
        assert ifA not in self.ip.interfaces

        if self.ip.interfaces[ifB]._mode == 'explicit':
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifB].ifname = ifA
        self.ip.interfaces[ifB].commit()

        assert ifB not in self.ip.interfaces
        assert ifA in self.ip.interfaces

    def test_routes_keys(self):
        assert '172.16.0.0/24' not in self.ip.routes
        # create but not commit
        self.ip.routes.add(dst='172.16.0.0/24', gateway='127.0.0.1')
        # checks
        assert '172.16.0.0/24' in self.ip.routes
        assert '172.16.0.0/24' in list(self.ip.routes.keys())

    def test_routes(self):
        require_user('root')
        assert '172.16.0.0/24' not in self.ip.routes

        # create a route
        with self.ip.routes.add({
                'dst': '172.16.0.0/24',
                'gateway': '127.0.0.1'
        }) as r:
            pass
        assert '172.16.0.0/24' in self.ip.routes.keys()
        assert grep('ip ro', pattern='172.16.0.0/24.*127.0.0.1')

        # change the route
        with self.ip.routes['172.16.0.0/24'] as r:
            r.gateway = '127.0.0.2'
        assert self.ip.routes['172.16.0.0/24'].gateway == '127.0.0.2'
        assert grep('ip ro', pattern='172.16.0.0/24.*127.0.0.2')

        # delete the route
        with self.ip.routes['172.16.0.0/24'] as r:
            r.remove()
        assert '172.16.0.0/24' not in self.ip.routes.keys()
        assert not grep('ip ro', pattern='172.16.0.0/24')

    def test_routes_multipath_gateway(self):
        require_user('root')
        ifR = self.get_ifname()

        with self.ip.create(ifname=ifR, kind='dummy') as i:
            i.add_ip('172.16.231.1/24')
            i.up()

        r = self.ip.routes.add({
            'dst':
            '172.16.232.0/24',
            'multipath': [{
                'gateway': '172.16.231.2',
                'hops': 20
            }, {
                'gateway': '172.16.231.3',
                'hops': 30
            }, {
                'gateway': '172.16.231.4'
            }]
        })
        r.commit()
        assert grep('ip ro', pattern='172.16.232.0/24')
        assert grep('ip ro', pattern='nexthop.*172.16.231.2.*weight.*21')
        assert grep('ip ro', pattern='nexthop.*172.16.231.3.*weight.*31')
        assert grep('ip ro', pattern='nexthop.*172.16.231.4.*weight.*1')

        with self.ip.routes['172.16.232.0/24'] as r:
            r.add_nh({'gateway': '172.16.231.5', 'hops': 50})
            r.del_nh({'gateway': '172.16.231.2'})
        assert grep('ip ro', pattern='172.16.232.0/24')
        assert grep('ip ro', pattern='nexthop.*172.16.231.5.*weight.*51')
        assert grep('ip ro', pattern='nexthop.*172.16.231.3.*weight.*31')
        assert grep('ip ro', pattern='nexthop.*172.16.231.4.*weight.*1')

    def test_routes_metrics(self):
        require_user('root')
        assert '172.16.0.0/24' not in self.ip.routes.keys()

        # create a route
        self.ip.routes.add({
            'dst': '172.16.0.0/24',
            'gateway': '127.0.0.1',
            'metrics': {
                'mtu': 1360
            }
        }).commit()
        assert grep('ip ro', pattern='172.16.0.0/24.*mtu 1360')

        # change metrics
        with self.ip.routes['172.16.0.0/24'] as r:
            r.metrics.mtu = 1400
        assert self.ip.routes['172.16.0.0/24']['metrics']['mtu'] == 1400
        assert grep('ip ro', pattern='172.16.0.0/24.*mtu 1400')

        # delete the route
        with self.ip.routes['172.16.0.0/24'] as r:
            r.remove()

        assert '172.16.0.0/24' not in self.ip.routes.keys()
        assert not grep('ip ro', pattern='172.16.0.0/24')

    @skip_if_not_supported
    def _test_shadow(self, kind):
        ifA = self.get_ifname()

        a = self.ip.create(ifname=ifA, kind=kind).commit()
        if a._mode == 'explicit':
            a.begin()
        a.shadow().commit()
        assert ifA in self.ip.interfaces
        assert not grep('ip link', pattern=ifA)
        time.sleep(0.5)
        b = self.ip.create(ifname=ifA, kind=kind).commit()
        assert a == b
        assert grep('ip link', pattern=ifA)

    def test_shadow_bond(self):
        require_user('root')
        self._test_shadow('bond')

    def test_shadow_bridge(self):
        require_user('root')
        self._test_shadow('bridge')

    def test_shadow_dummy(self):
        require_user('root')
        self._test_shadow('dummy')

    def test_updown(self):
        require_user('root')

        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].up()
        self.ip.interfaces[self.ifd].commit()
        assert self.ip.interfaces[self.ifd].flags & 1

        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].down()
        self.ip.interfaces[self.ifd].commit()
        assert not (self.ip.interfaces[self.ifd].flags & 1)

    def test_slave_data(self):
        require_user('root')

        ifBR = self.get_ifname()
        ifP = self.get_ifname()
        self.ip.debug = True

        bridge = self.ip.create(ifname=ifBR, kind='bridge').commit()
        port = self.ip.create(ifname=ifP, kind='dummy').commit()

        if self.ip.mode == 'explicit':
            bridge.begin()
        bridge.add_port(port)
        bridge.up()
        bridge.commit()

        li = port.nlmsg.get_attr('IFLA_LINKINFO')
        skind = li.get_attr('IFLA_INFO_SLAVE_KIND')
        sdata = li.get_attr('IFLA_INFO_SLAVE_DATA')
        self.ip.debug = False
        if skind is None or sdata is None:
            raise SkipTest('slave data not provided')

        assert sdata.get_attr('IFLA_BRPORT_STATE') is not None
        assert sdata.get_attr('IFLA_BRPORT_MODE') is not None

    def test_fail_ipaddr(self):
        require_user('root')

        ifA = self.get_ifname()

        i = self.ip.create(ifname=ifA, kind='dummy').commit()
        assert not len(i.ipaddr)
        if i._mode == 'explicit':
            i.begin()
        i.add_ip('123.456.789.1024/153')
        try:
            i.commit()
        except socket.error as e:
            if not e.args[0].startswith('illegal IP'):
                raise
        assert not len(i.ipaddr)
        if i._mode == 'explicit':
            i.begin()
        i.remove().commit()
        assert ifA not in self.ip.interfaces

    def test_json_dump(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        # set up the interface
        with self.ip.create(kind='dummy', ifname=ifA) as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.0.2/24')
            i.up()

        # make a backup
        backup = self.ip.interfaces[ifA].dump()
        assert isinstance(backup, dict)

        # remove index and protinfo -- make it portable
        del backup['index']
        if 'protinfo' in backup:
            del backup['protinfo']

        # serialize
        backup = json.dumps(backup)

        # remove the interface
        with self.ip.interfaces[ifA] as i:
            i.remove()

        # create again, but with different name
        self.ip.create(kind='dummy', ifname=ifB).commit()

        # load the backup
        # 1. prepare to the restore: bring it down
        with self.ip.interfaces[ifB] as i:
            i.down()
        # 2. please notice, the interface will be renamed after the backup
        with self.ip.interfaces[ifB] as i:
            i.load(json.loads(backup))

        # check :)
        assert ifA in self.ip.interfaces
        assert ifB not in self.ip.interfaces
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert ('172.16.0.2', 24) in self.ip.interfaces[ifA].ipaddr
        assert self.ip.interfaces[ifA].flags & 1

    def test_freeze_del(self):
        require_user('root')

        interface = self.ip.interfaces[self.ifd]

        # set up the interface
        with interface as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.1.1/24')
            i.up()

        # check
        assert ('172.16.0.1', 24) in interface.ipaddr
        assert ('172.16.1.1', 24) in interface.ipaddr
        assert interface.flags & 1

        interface.freeze()

        # delete interface with an external routine
        remove_link(interface.ifname)

        # wait for a second
        time.sleep(1)

        # check if it is back
        ipdb = IPDB()
        try:
            ifc = ipdb.interfaces[self.ifd]
            assert ('172.16.0.1', 24) in ifc.ipaddr
            assert ('172.16.1.1', 24) in ifc.ipaddr
            assert ifc.flags & 1
        except:
            raise
        finally:
            interface.unfreeze()
            ipdb.release()

    def test_freeze(self):
        require_user('root')

        interface = self.ip.interfaces[self.ifd]

        # set up the interface
        with interface as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.1.1/24')
            i.up()

        # check
        assert ('172.16.0.1', 24) in interface.ipaddr
        assert ('172.16.1.1', 24) in interface.ipaddr
        assert interface.flags & 1

        # assert routine
        def probe():
            # The freeze results are dynamic: it is not a real freeze,
            # it is a restore routine. So it takes time for results
            # to stabilize
            err = None
            for _ in range(3):
                err = None
                interface.ipaddr.set_target(
                    (('172.16.0.1', 24), ('172.16.1.1', 24)))
                interface.ipaddr.target.wait()
                try:
                    assert ('172.16.0.1', 24) in interface.ipaddr
                    assert ('172.16.1.1', 24) in interface.ipaddr
                    assert interface.flags & 1
                    break
                except AssertionError as e:
                    err = e
                    continue
                except Exception as e:
                    err = e
                    break
            if err is not None:
                interface.unfreeze()
                i2.close()
                raise err

        # freeze
        interface.freeze()

        # change the interface somehow
        i2 = IPRoute()
        i2.addr('delete', interface.index, '172.16.0.1', 24)
        i2.addr('delete', interface.index, '172.16.1.1', 24)
        probe()

        # unfreeze
        self.ip.interfaces[self.ifd].unfreeze()

        try:
            i2.addr('delete', interface.index, '172.16.0.1', 24)
            i2.addr('delete', interface.index, '172.16.1.1', 24)
        except:
            pass
        finally:
            i2.close()

        # should be up, but w/o addresses
        interface.ipaddr.set_target(set())
        interface.ipaddr.target.wait(3)
        assert ('172.16.0.1', 24) not in self.ip.interfaces[self.ifd].ipaddr
        assert ('172.16.1.1', 24) not in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

    def test_snapshots(self):
        require_user('root')

        ifB = self.get_ifname()

        # set up the interface
        with self.ip.interfaces[self.ifd] as i:
            i.add_ip('172.16.0.1/24')
            i.up()

        # check it
        assert ('172.16.0.1', 24) in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

        # make a snapshot
        s = self.ip.interfaces[self.ifd].snapshot()
        i = self.ip.interfaces[self.ifd]

        # check it
        assert i.last_snapshot_id() == s

        # unset the interface
        with self.ip.interfaces[self.ifd] as i:
            i.del_ip('172.16.0.1/24')
            i.down()

        # we can not rename the interface while it is up,
        # so do it in two turns
        with self.ip.interfaces[self.ifd] as i:
            i.ifname = ifB

        # check it
        assert ifB in self.ip.interfaces
        assert self.ifd not in self.ip.interfaces
        y = self.ip.interfaces[ifB]
        assert i == y
        assert ('172.16.0.1', 24) not in y.ipaddr
        assert not (y.flags & 1)

        # revert snapshot
        y.revert(s).commit()

        # check it
        assert ifB not in self.ip.interfaces
        assert self.ifd in self.ip.interfaces
        assert ('172.16.0.1', 24) in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

    @skip_if_not_supported
    def _test_ipv(self, ipv, kind):
        require_user('root')

        ifA = self.get_ifname()

        i = self.ip.create(kind=kind, ifname=ifA).commit()
        if self.ip.interfaces[ifA]._mode == 'explicit':
            self.ip.interfaces[ifA].begin()

        if ipv == 4:
            addr = '172.16.0.1/24'
        elif ipv == 6:
            addr = 'fdb3:84e5:4ff4:55e4::1/64'
        else:
            raise Exception('bad IP version')

        i.add_ip(addr).commit()
        pre_target = addr.split('/')
        target = (pre_target[0], int(pre_target[1]))
        assert target in i['ipaddr']

    def test_ipv4_dummy(self):
        self._test_ipv(4, 'dummy')

    def test_ipv4_bond(self):
        self._test_ipv(4, 'bond')

    def test_ipv4_bridge(self):
        self._test_ipv(4, 'bridge')

    def test_ipv6_dummy(self):
        self._test_ipv(6, 'dummy')

    def test_ipv6_bond(self):
        self._test_ipv(6, 'bond')

    def test_ipv6_bridge(self):
        self._test_ipv(6, 'bridge')

    @skip_if_not_supported
    def test_create_tuntap_fail(self):
        try:
            self.ip.create(ifname='fAiL', kind='tuntap', mode='fail').commit()
        except:
            assert not grep('ip link', pattern='fAiL')
            return
        raise Exception('tuntap create succeded')

    @skip_if_not_supported
    def test_create_tuntap(self):
        require_user('root')

        ifA = self.get_ifname()
        self.ip.create(ifname=ifA, kind='tuntap', mode='tap', uid=1,
                       gid=1).commit()

        assert ifA in self.ip.interfaces
        assert grep('ip link', pattern=ifA)

    @skip_if_not_supported
    def test_ovs_kind_aliases(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, kind='ovs-bridge').commit()
        self.ip.create(ifname=ifB, kind='openvswitch').commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert grep('ip link', pattern=ifA)
        assert grep('ip link', pattern=ifB)

    @skip_if_not_supported
    def test_ovs_add_remove_port(self):
        require_user('root')

        ifOVS = self.get_ifname()
        self.ip.create(ifname=ifOVS, kind='ovs-bridge').commit()
        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, kind='dummy')
        self.ip.create(ifname=ifB, peer='x' + ifB, kind='veth')
        self.ip.commit()

        # add ports
        if self.ip.mode == 'explicit':
            self.ip.interfaces[ifOVS].begin()
        self.ip.interfaces[ifOVS].\
            add_port(self.ip.interfaces[ifA]).\
            add_port(self.ip.interfaces[ifB]).\
            commit()

        #
        assert self.ip.interfaces[ifA].master == \
            self.ip.interfaces[ifOVS].index
        assert self.ip.interfaces[ifB].master == \
            self.ip.interfaces[ifOVS].index
        assert self.ip.interfaces[ifA].index in \
            self.ip.interfaces[ifOVS].ports
        assert self.ip.interfaces[ifB].index in \
            self.ip.interfaces[ifOVS].ports

        # remove ports
        if self.ip.mode == 'explicit':
            self.ip.interfaces[ifOVS].begin()
        self.ip.interfaces[ifOVS].\
            del_port(self.ip.interfaces[ifA]).\
            del_port(self.ip.interfaces[ifB]).\
            commit()

        #
        assert self.ip.interfaces[ifA].get('master') is None
        assert self.ip.interfaces[ifB].get('master') is None
        assert not self.ip.interfaces[ifOVS].ports

    def test_global_create(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, kind='dummy')
        self.ip.create(ifname=ifB, kind='dummy')
        self.ip.commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert grep('ip link', pattern=ifA)
        assert grep('ip link', pattern=ifB)

    def test_global_priorities(self):
        require_user('root')
        ifA = self.get_ifname()
        ifB = self.get_ifname()
        ifC = self.get_ifname()
        a = self.ip.create(ifname=ifA, kind='dummy').commit()
        #
        if a._mode == 'explicit':
            a.begin()

        # prepare transaction: two interface creations
        # and one failure on an existing interface
        a.set_address('11:22:33:44:55:66')
        b = self.ip.create(ifname=ifB, kind='dummy')
        c = self.ip.create(ifname=ifC, kind='dummy')
        # now assign priorities
        b.ipdb_priority = 15  # will be execute first
        a.ipdb_priority = 10  # second -- and fail
        c.ipdb_priority = 5  # should not be executed
        # prepare watchdogs
        wdb = self.ip.watchdog(ifname=ifB)
        wdc = self.ip.watchdog(ifname=ifC)
        # run the transaction
        try:
            self.ip.commit()
        except NetlinkError:
            pass
        # control system state
        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert ifC in self.ip.interfaces
        assert a.ipdb_scope == 'system'
        assert b.ipdb_scope == 'create'
        assert c.ipdb_scope == 'create'
        assert a.address != '11:22:33:44:55:66'
        assert grep('ip link', pattern=ifA)
        assert not grep('ip link', pattern=ifB)
        assert not grep('ip link', pattern=ifC)
        wdb.wait(1)
        wdc.wait(1)
        assert wdb.is_set
        assert not wdc.is_set

    def test_global_veth(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, peer=ifB, kind='veth')
        self.ip.commit()

        assert self.ip.interfaces[ifA]['ipdb_scope'] == 'system'
        assert self.ip.interfaces[ifB]['ipdb_scope'] == 'system'

        if self.ip.mode == 'explicit':
            self.ip.interfaces[ifA].begin()
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifA].remove()
        self.ip.interfaces[ifB].remove()
        self.ip.commit()

        assert ifA not in self.ip.interfaces
        assert ifB not in self.ip.interfaces

    def test_global_rollback(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        a = self.ip.create(ifname=ifA, kind='dummy').commit()
        #
        if a._mode == 'explicit':
            a.begin()
        a.remove()
        b = self.ip.create(ifname=ifB, kind='dummy')
        b.set_mtu(1500).set_address('11:22:33:44:55:66')
        try:
            self.ip.commit()
        except NetlinkError:
            pass

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert b.ipdb_scope == 'create'
        assert grep('ip link', pattern=ifA)
        assert not grep('ip link', pattern=ifB)

    def test_global_netns(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        ns = str(uuid.uuid4())

        with IPDB(nl=NetNS(ns)) as nsdb:
            v1 = self.ip.create(ifname='x' + ifA, kind='veth', peer=ifA)
            v2 = self.ip.create(ifname='x' + ifB, kind='veth', peer=ifB)
            if v1._mode == 'explicit':
                v1.begin()
                v2.begin()
            v1.net_ns_fd = ns
            v2.net_ns_fd = ns
            self.ip.commit()
            nsdb.interfaces['x' + ifA].ifname = 'eth0'
            nsdb.interfaces['x' + ifB].ifname = 'eth1'
            nsdb.commit()
            if self.ip.interfaces[ifA]._mode == 'explicit':
                self.ip.interfaces[ifA].begin()
                self.ip.interfaces[ifB].begin()
            self.ip.interfaces[ifA].up()
            self.ip.interfaces[ifB].up()
            self.ip.commit()

        assert 'x' + ifA not in self.ip.interfaces
        assert 'x' + ifB not in self.ip.interfaces
        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert self.ip.interfaces[ifA].flags & 1
        assert self.ip.interfaces[ifB].flags & 1

        if self.ip.interfaces[ifA]._mode == 'explicit':
            self.ip.interfaces[ifA].begin()
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifA].remove()
        self.ip.interfaces[ifB].remove()
        self.ip.commit()
        netns.remove(ns)

    @skip_if_not_supported
    def test_create_veth(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        self.ip.create(ifname=ifA, kind='veth', peer=ifB).commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces

    def test_create_fail(self):
        require_user('root')

        ifA = self.get_ifname()

        # create with mac 11:22:33:44:55:66 should fail
        i = self.ip.create(kind='dummy',
                           ifname=ifA,
                           address='11:22:33:44:55:66')
        try:
            i.commit()
        except NetlinkError:
            pass

        assert i._mode == 'invalid'
        assert ifA not in self.ip.interfaces

    def test_create_dqn(self):
        require_user('root')
        ifA = self.get_ifname()

        i = self.ip.create(kind='dummy', ifname=ifA)
        i.add_ip('172.16.0.1/255.255.255.0')
        i.commit()
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)

    def test_create_double_reuse(self):
        require_user('root')

        ifA = self.get_ifname()
        # create an interface
        i1 = self.ip.create(kind='dummy', ifname=ifA).commit()
        try:
            # this call should fail on the very first step:
            # `bala` interface already exists
            self.ip.create(kind='dummy', ifname=ifA)
        except CreateException:
            pass
        # add `reuse` keyword -- now should pass
        i2 = self.ip.create(kind='dummy', ifname=ifA, reuse=True).commit()
        # assert that we have got references to the same interface
        assert i1 == i2

    @skip_if_not_supported
    def _create_double(self, kind):
        require_user('root')
        ifA = self.get_ifname()

        self.ip.create(kind=kind, ifname=ifA).commit()
        try:
            self.ip.create(kind=kind, ifname=ifA).commit()
        except CreateException:
            pass

    def test_create_double_dummy(self):
        self._create_double('dummy')

    def test_create_double_bridge(self):
        self._create_double('bridge')

    def test_create_double_bond(self):
        self._create_double('bond')

    def test_create_plain(self):
        require_user('root')
        ifA = self.get_ifname()

        i = self.ip.create(kind='dummy', ifname=ifA)
        i.add_ip('172.16.0.1/24')
        i.commit()
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)

    def test_create_and_remove(self):
        require_user('root')

        ifA = self.get_ifname()

        with self.ip.create(kind='dummy', ifname=ifA) as i:
            i.add_ip('172.16.0.1/24')
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)

        with self.ip.interfaces[ifA] as i:
            i.remove()
        assert ifA not in self.ip.interfaces

    def test_dqn_mask(self):
        require_user('root')

        iface = self.ip.interfaces[self.ifd]
        with iface as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.0.2', mask=24)
            i.add_ip('172.16.0.3/255.255.255.0')
            i.add_ip('172.16.0.4', mask='255.255.255.0')

        assert ('172.16.0.1', 24) in iface.ipaddr
        assert ('172.16.0.2', 24) in iface.ipaddr
        assert ('172.16.0.3', 24) in iface.ipaddr
        assert ('172.16.0.4', 24) in iface.ipaddr

    @skip_if_not_supported
    def _create_master(self, kind, **kwarg):

        ifM = self.get_ifname()
        ifP1 = self.get_ifname()
        ifP2 = self.get_ifname()

        self.ip.create(kind='dummy', ifname=ifP1).commit()
        self.ip.create(kind='dummy', ifname=ifP2).commit()

        with self.ip.create(kind=kind, ifname=ifM, **kwarg) as i:
            i.add_port(self.ip.interfaces[ifP1])
            i.add_ip('172.16.0.1/24')

        with self.ip.interfaces[ifM] as i:
            i.add_port(self.ip.interfaces[ifP2])
            i.add_ip('172.16.0.2/24')

        assert ('172.16.0.1', 24) in self.ip.interfaces[ifM].ipaddr
        assert ('172.16.0.2', 24) in self.ip.interfaces[ifM].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifM)
        assert '172.16.0.2/24' in get_ip_addr(interface=ifM)
        assert self.ip.interfaces[ifP1].if_master == \
            self.ip.interfaces[ifM].index
        assert self.ip.interfaces[ifP2].if_master == \
            self.ip.interfaces[ifM].index

        with self.ip.interfaces[ifM] as i:
            i.del_port(self.ip.interfaces[ifP1])
            i.del_port(self.ip.interfaces[ifP2])
            i.del_ip('172.16.0.1/24')
            i.del_ip('172.16.0.2/24')

        assert ('172.16.0.1', 24) not in self.ip.interfaces[ifM].ipaddr
        assert ('172.16.0.2', 24) not in self.ip.interfaces[ifM].ipaddr
        assert '172.16.0.1/24' not in get_ip_addr(interface=ifM)
        assert '172.16.0.2/24' not in get_ip_addr(interface=ifM)
        assert self.ip.interfaces[ifP1].if_master is None
        assert self.ip.interfaces[ifP2].if_master is None

    def test_create_bridge(self):
        require_user('root')
        self._create_master('bridge')

    def test_create_bond(self):
        require_user('root')
        self._create_master('bond')

    def test_create_team(self):
        require_user('root')
        self._create_master('team')

    def test_create_ovs(self):
        require_user('root')
        self._create_master('openvswitch')

    def test_create_bond2(self):
        require_user('root')
        self._create_master('bond', bond_mode=2)

    @skip_if_not_supported
    def _create_macvx_mode(self, kind, mode):
        require_user('root')
        ifL = self.get_ifname()
        ifV = self.get_ifname()
        ifdb = self.ip.interfaces

        self.ip.create(kind='dummy', ifname=ifL).commit()
        self.ip.create(**{
            'kind': kind,
            'link': ifdb[ifL],
            'ifname': ifV,
            '%s_mode' % kind: mode
        }).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].link == ifdb[ifL].index
            assert ifdb[ifV]['%s_mode' % kind] == mode
        except Exception:
            raise
        finally:
            ip2.release()

    def test_create_macvtap_vepa(self):
        return self._create_macvx_mode('macvtap', 'vepa')

    def test_create_macvtap_bridge(self):
        return self._create_macvx_mode('macvtap', 'bridge')

    def test_create_macvlan_vepa(self):
        return self._create_macvx_mode('macvlan', 'vepa')

    def test_create_macvlan_bridge(self):
        return self._create_macvx_mode('macvlan', 'bridge')

    def test_create_utf_name(self):
        require_user('root')
        ifO = 'ༀ'
        self.ip.create(kind='dummy', ifname=ifO).commit()
        assert ifO in self.ip.interfaces
        assert self.ip.nl.link_lookup(ifname=ifO)
        if self.ip.interfaces[ifO]._mode == 'explicit':
            self.ip.interfaces[ifO].begin()
        self.ip.interfaces[ifO].remove().commit()

    @skip_if_not_supported
    def test_create_gre(self):
        require_user('root')

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        with self.ip.create(kind='dummy', ifname=ifL) as i:
            i.add_ip('172.16.0.1/24')
            i.up()

        self.ip.create(kind='gre',
                       ifname=ifV,
                       gre_local='172.16.0.1',
                       gre_remote='172.16.0.2',
                       gre_ttl=16).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].gre_local == '172.16.0.1'
            assert ifdb[ifV].gre_remote == '172.16.0.2'
            assert ifdb[ifV].gre_ttl == 16
        except Exception:
            raise
        finally:
            ip2.release()

    @skip_if_not_supported
    def test_create_vxlan(self):
        require_user('root')

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        ifdb = self.ip.interfaces

        self.ip.create(kind='dummy', ifname=ifL).commit()
        self.ip.create(kind='vxlan',
                       ifname=ifV,
                       vxlan_link=ifdb[ifL],
                       vxlan_id=101,
                       vxlan_group='239.1.1.1').commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces

        try:
            assert ifdb[ifV].vxlan_link == ifdb[ifL].index
            assert ifdb[ifV].vxlan_group == '239.1.1.1'
            assert ifdb[ifV].vxlan_id == 101
        except Exception:
            raise
        finally:
            ip2.release()

    def test_create_vlan_by_interface(self):
        require_user('root')
        require_8021q()
        ifL = self.get_ifname()
        ifV = self.get_ifname()

        self.ip.create(kind='dummy', ifname=ifL).commit()
        self.ip.create(kind='vlan',
                       ifname=ifV,
                       link=self.ip.interfaces[ifL],
                       vlan_id=101).commit()

        assert self.ip.interfaces[ifV].link == \
            self.ip.interfaces[ifL].index

    def test_create_vlan_by_index(self):
        require_user('root')
        require_8021q()
        ifL = self.get_ifname()
        ifV = self.get_ifname()

        self.ip.create(kind='dummy', ifname=ifL).commit()
        self.ip.create(kind='vlan',
                       ifname=ifV,
                       link=self.ip.interfaces[ifL].index,
                       vlan_id=101).commit()

        assert self.ip.interfaces[ifV].link == \
            self.ip.interfaces[ifL].index

    def test_remove_secondaries(self):
        require_user('root')

        ifA = self.get_ifname()

        with self.ip.create(kind='dummy', ifname=ifA) as i:
            i.add_ip('172.16.0.1', 24)
            i.add_ip('172.16.0.2', 24)

        assert ifA in self.ip.interfaces
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert ('172.16.0.2', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)
        assert '172.16.0.2/24' in get_ip_addr(interface=ifA)

        if i._mode == 'explicit':
            i.begin()

        i.del_ip('172.16.0.1', 24)
        i.del_ip('172.16.0.2', 24)
        i.commit()

        assert ('172.16.0.1', 24) not in self.ip.interfaces[ifA].ipaddr
        assert ('172.16.0.2', 24) not in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' not in get_ip_addr(interface=ifA)
        assert '172.16.0.2/24' not in get_ip_addr(interface=ifA)
Ejemplo n.º 10
0
class TestExplicit(object):
    ip = None
    mode = 'explicit'

    def setup(self):
        self.ifaces = []
        self.ifd = self.get_ifname()
        create_link(self.ifd, kind='dummy')
        self.ip = IPDB(mode=self.mode)

    def get_ifname(self):
        ifname = uifname()
        self.ifaces.append(ifname)
        return ifname

    def teardown(self):
        for name in self.ifaces:
            try:
                # just a hardcore removal
                self.ip.nl.link_remove(self.ip.interfaces[name].index)
            except Exception:
                pass
        self.ip.release()
        self.ifaces = []

    def test_simple(self):
        assert len(list(self.ip.interfaces.keys())) > 0

    def test_empty_transaction(self):
        assert 'lo' in self.ip.interfaces
        with self.ip.interfaces.lo as i:
            assert isinstance(i.mtu, int)

    def test_idx_len(self):
        assert len(self.ip.by_name.keys()) == len(self.ip.by_index.keys())

    def test_idx_set(self):
        assert set(self.ip.by_name.values()) == set(self.ip.by_index.values())

    def test_idx_types(self):
        assert all(isinstance(i, int) for i in self.ip.by_index.keys())
        assert all(isinstance(i, basestring) for i in self.ip.by_name.keys())

    def test_addr_attributes(self):
        require_user('root')

        if1 = self.get_ifname()
        if2 = self.get_ifname()

        with self.ip.create(ifname=if1, kind='dummy') as i:
            # +scope host (=> broadcast == None)
            i.add_ip('172.16.102.1/24', scope=254)

        with self.ip.create(ifname=if2, kind='dummy') as i:
            # +broadcast (default scope == 0)
            i.add_ip('172.16.103.1/24', broadcast='172.16.103.128')

        index = self.ip.interfaces[if1]['index']
        addr = self.ip.nl.get_addr(index=index)[0]
        assert addr['scope'] == 254
        assert addr.get_attr('IFA_BROADCAST') is None

        index = self.ip.interfaces[if2]['index']
        addr = self.ip.nl.get_addr(index=index)[0]
        assert addr['scope'] == 0
        assert addr.get_attr('IFA_BROADCAST') == '172.16.103.128'

    def test_addr_loaded(self):
        for name in self.ip.by_name:
            assert len(self.ip.interfaces[name]['ipaddr']) == \
                len(get_ip_addr(name))

    def test_reprs(self):
        assert isinstance(repr(self.ip.interfaces.lo.ipaddr), basestring)
        assert isinstance(repr(self.ip.interfaces.lo), basestring)

    def test_dotkeys(self):
        # self.ip.lo hint for ipython
        assert 'lo' in dir(self.ip.interfaces)
        assert 'lo' in self.ip.interfaces
        assert self.ip.interfaces.lo == self.ip.interfaces['lo']
        # create attribute
        self.ip.interfaces['newitem'] = True
        self.ip.interfaces.newattr = True
        self.ip.interfaces.newitem = None
        assert self.ip.interfaces.newitem == self.ip.interfaces['newitem']
        assert self.ip.interfaces.newitem is None
        # delete attribute
        del self.ip.interfaces.newitem
        del self.ip.interfaces.newattr
        assert 'newattr' not in dir(self.ip.interfaces)

    @skip_if_not_supported
    def test_vlan_slave_bridge(self):
        # https://github.com/svinota/pyroute2/issues/58
        # based on the code by Petr Horáček
        dXname = self.get_ifname()
        vXname = self.get_ifname()
        vYname = self.get_ifname()
        brname = self.get_ifname()

        require_user('root')
        dX = self.ip.create(ifname=dXname, kind='dummy').commit()
        vX = self.ip.create(ifname=vXname, kind='vlan',
                            link=dX, vlan_id=101).commit()
        vY = self.ip.create(ifname=vYname, kind='vlan',
                            link=dX, vlan_id=102).commit()
        with self.ip.create(ifname=brname, kind='bridge') as i:
            i.add_port(vX)
            i.add_port(vY['index'])

        assert vX['index'] in self.ip.interfaces[brname]['ports']
        assert vY['index'] in self.ip.interfaces[brname].ports
        assert vX['link'] == dX['index']
        assert vY['link'] == dX['index']
        assert vX['master'] == self.ip.interfaces[brname]['index']
        assert vY['master'] == self.ip.interfaces[brname].index

    def _test_commit_hook_positive(self):
        require_user('root')

        # test callback, that adds an address by itself --
        # just to check the possibility
        def cb(interface, snapshot, transaction):
            self.ip.nl.addr('add',
                            self.ip.interfaces[self.ifd].index,
                            address='172.16.22.1',
                            mask=24)

        # register callback and check CB chain length
        self.ip.interfaces[self.ifd].register_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 1

        # create a transaction and commit it
        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].add_ip('172.16.21.1/24')
        self.ip.interfaces[self.ifd].commit()

        # added address should be there
        assert ('172.16.21.1', 24) in \
            self.ip.interfaces[self.ifd].ipaddr
        # and the one, added by the callback, too
        assert ('172.16.22.1', 24) in \
            self.ip.interfaces[self.ifd].ipaddr

        # unregister callback
        self.ip.interfaces[self.ifd].unregister_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 0

    def _test_commit_hook_negative(self):
        require_user('root')

        # test exception to differentiate
        class CBException(Exception):
            pass

        # test callback, that always fail
        def cb(interface, snapshot, transaction):
            raise CBException()

        # register callback and check CB chain length
        self.ip.interfaces[self.ifd].register_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 1

        # create a transaction and commit it; should fail
        # 'cause of the callback
        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].add_ip('172.16.21.1/24')
        try:
            self.ip.interfaces[self.ifd].commit()
        except CBException:
            pass

        # added address should be removed
        assert ('172.16.21.1', 24) not in \
            self.ip.interfaces[self.ifd].ipaddr

        # unregister callback
        self.ip.interfaces[self.ifd].unregister_commit_hook(cb)
        assert len(self.ip.interfaces[self.ifd]._commit_hooks) == 0

    def test_review(self):
        assert len(self.ip.interfaces.lo._tids) == 0
        if self.ip.interfaces.lo._mode == 'explicit':
            self.ip.interfaces.lo.begin()
        self.ip.interfaces.lo.add_ip('172.16.21.1/24')
        r = self.ip.interfaces.lo.review()
        assert len(r['+ipaddr']) == 1
        assert len(r['-ipaddr']) == 0
        assert len(r['+ports']) == 0
        assert len(r['-ports']) == 0
        # +/-ipaddr, +/-ports
        assert len([i for i in r if r[i] is not None]) == 4
        self.ip.interfaces.lo.drop()

    def test_rename(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        self.ip.create(ifname=ifA, kind='dummy').commit()

        if self.ip.interfaces[ifA]._mode == 'explicit':
            self.ip.interfaces[ifA].begin()
        self.ip.interfaces[ifA].ifname = ifB
        self.ip.interfaces[ifA].commit()

        assert ifB in self.ip.interfaces
        assert ifA not in self.ip.interfaces

        if self.ip.interfaces[ifB]._mode == 'explicit':
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifB].ifname = ifA
        self.ip.interfaces[ifB].commit()

        assert ifB not in self.ip.interfaces
        assert ifA in self.ip.interfaces

    def test_routes_keys(self):
        assert '172.16.0.0/24' not in self.ip.routes
        # create but not commit
        self.ip.routes.add(dst='172.16.0.0/24', gateway='127.0.0.1')
        # checks
        assert '172.16.0.0/24' in self.ip.routes
        assert '172.16.0.0/24' in list(self.ip.routes.keys())

    def test_routes(self):
        require_user('root')
        assert '172.16.0.0/24' not in self.ip.routes

        # create a route
        with self.ip.routes.add({'dst': '172.16.0.0/24',
                                 'gateway': '127.0.0.1'}) as r:
            pass
        assert '172.16.0.0/24' in self.ip.routes.keys()
        assert grep('ip ro', pattern='172.16.0.0/24.*127.0.0.1')

        # change the route
        with self.ip.routes['172.16.0.0/24'] as r:
            r.gateway = '127.0.0.2'
        assert self.ip.routes['172.16.0.0/24'].gateway == '127.0.0.2'
        assert grep('ip ro', pattern='172.16.0.0/24.*127.0.0.2')

        # delete the route
        with self.ip.routes['172.16.0.0/24'] as r:
            r.remove()
        assert '172.16.0.0/24' not in self.ip.routes.keys()
        assert not grep('ip ro', pattern='172.16.0.0/24')

    def test_routes_multipath_gateway(self):
        require_user('root')
        ifR = self.get_ifname()

        with self.ip.create(ifname=ifR, kind='dummy') as i:
            i.add_ip('172.16.231.1/24')
            i.up()

        r = self.ip.routes.add({'dst': '172.16.232.0/24',
                                'multipath': [{'gateway': '172.16.231.2',
                                               'hops': 20},
                                              {'gateway': '172.16.231.3',
                                               'hops': 30},
                                              {'gateway': '172.16.231.4'}]})
        r.commit()
        assert grep('ip ro', pattern='172.16.232.0/24')
        assert grep('ip ro', pattern='nexthop.*172.16.231.2.*weight.*21')
        assert grep('ip ro', pattern='nexthop.*172.16.231.3.*weight.*31')
        assert grep('ip ro', pattern='nexthop.*172.16.231.4.*weight.*1')

        with self.ip.routes['172.16.232.0/24'] as r:
            r.add_nh({'gateway': '172.16.231.5', 'hops': 50})
            r.del_nh({'gateway': '172.16.231.2'})
        assert grep('ip ro', pattern='172.16.232.0/24')
        assert grep('ip ro', pattern='nexthop.*172.16.231.5.*weight.*51')
        assert grep('ip ro', pattern='nexthop.*172.16.231.3.*weight.*31')
        assert grep('ip ro', pattern='nexthop.*172.16.231.4.*weight.*1')

    def test_routes_metrics(self):
        require_user('root')
        assert '172.16.0.0/24' not in self.ip.routes.keys()

        # create a route
        self.ip.routes.add({'dst': '172.16.0.0/24',
                            'gateway': '127.0.0.1',
                            'metrics': {'mtu': 1360}}).commit()
        assert grep('ip ro', pattern='172.16.0.0/24.*mtu 1360')

        # change metrics
        with self.ip.routes['172.16.0.0/24'] as r:
            r.metrics.mtu = 1400
        assert self.ip.routes['172.16.0.0/24']['metrics']['mtu'] == 1400
        assert grep('ip ro', pattern='172.16.0.0/24.*mtu 1400')

        # delete the route
        with self.ip.routes['172.16.0.0/24'] as r:
            r.remove()

        assert '172.16.0.0/24' not in self.ip.routes.keys()
        assert not grep('ip ro', pattern='172.16.0.0/24')

    @skip_if_not_supported
    def _test_shadow(self, kind):
        ifA = self.get_ifname()

        a = self.ip.create(ifname=ifA, kind=kind).commit()
        if a._mode == 'explicit':
            a.begin()
        a.shadow().commit()
        assert ifA in self.ip.interfaces
        assert not grep('ip link', pattern=ifA)
        time.sleep(0.5)
        b = self.ip.create(ifname=ifA, kind=kind).commit()
        assert a == b
        assert grep('ip link', pattern=ifA)

    def test_shadow_bond(self):
        require_user('root')
        self._test_shadow('bond')

    def test_shadow_bridge(self):
        require_user('root')
        self._test_shadow('bridge')

    def test_shadow_dummy(self):
        require_user('root')
        self._test_shadow('dummy')

    def test_updown(self):
        require_user('root')

        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].up()
        self.ip.interfaces[self.ifd].commit()
        assert self.ip.interfaces[self.ifd].flags & 1

        if self.ip.interfaces[self.ifd]._mode == 'explicit':
            self.ip.interfaces[self.ifd].begin()
        self.ip.interfaces[self.ifd].down()
        self.ip.interfaces[self.ifd].commit()
        assert not (self.ip.interfaces[self.ifd].flags & 1)

    def test_slave_data(self):
        require_user('root')

        ifBR = self.get_ifname()
        ifP = self.get_ifname()
        self.ip.debug = True

        bridge = self.ip.create(ifname=ifBR, kind='bridge').commit()
        port = self.ip.create(ifname=ifP, kind='dummy').commit()

        if self.ip.mode == 'explicit':
            bridge.begin()
        bridge.add_port(port)
        bridge.up()
        bridge.commit()

        li = port.nlmsg.get_attr('IFLA_LINKINFO')
        skind = li.get_attr('IFLA_INFO_SLAVE_KIND')
        sdata = li.get_attr('IFLA_INFO_SLAVE_DATA')
        self.ip.debug = False
        if skind is None or sdata is None:
            raise SkipTest('slave data not provided')

        assert sdata.get_attr('IFLA_BRPORT_STATE') is not None
        assert sdata.get_attr('IFLA_BRPORT_MODE') is not None

    def test_fail_ipaddr(self):
        require_user('root')

        ifA = self.get_ifname()

        i = self.ip.create(ifname=ifA, kind='dummy').commit()
        assert not len(i.ipaddr)
        if i._mode == 'explicit':
            i.begin()
        i.add_ip('123.456.789.1024/153')
        try:
            i.commit()
        except socket.error as e:
            if not e.args[0].startswith('illegal IP'):
                raise
        assert not len(i.ipaddr)
        if i._mode == 'explicit':
            i.begin()
        i.remove().commit()
        assert ifA not in self.ip.interfaces

    def test_json_dump(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        # set up the interface
        with self.ip.create(kind='dummy', ifname=ifA) as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.0.2/24')
            i.up()

        # make a backup
        backup = self.ip.interfaces[ifA].dump()
        assert isinstance(backup, dict)

        # remove index and protinfo -- make it portable
        del backup['index']
        if 'protinfo' in backup:
            del backup['protinfo']

        # serialize
        backup = json.dumps(backup)

        # remove the interface
        with self.ip.interfaces[ifA] as i:
            i.remove()

        # create again, but with different name
        self.ip.create(kind='dummy', ifname=ifB).commit()

        # load the backup
        # 1. prepare to the restore: bring it down
        with self.ip.interfaces[ifB] as i:
            i.down()
        # 2. please notice, the interface will be renamed after the backup
        with self.ip.interfaces[ifB] as i:
            i.load(json.loads(backup))

        # check :)
        assert ifA in self.ip.interfaces
        assert ifB not in self.ip.interfaces
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert ('172.16.0.2', 24) in self.ip.interfaces[ifA].ipaddr
        assert self.ip.interfaces[ifA].flags & 1

    def test_freeze_del(self):
        require_user('root')

        interface = self.ip.interfaces[self.ifd]

        # set up the interface
        with interface as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.1.1/24')
            i.up()

        # check
        assert ('172.16.0.1', 24) in interface.ipaddr
        assert ('172.16.1.1', 24) in interface.ipaddr
        assert interface.flags & 1

        interface.freeze()

        # delete interface with an external routine
        remove_link(interface.ifname)

        # wait for a second
        time.sleep(1)

        # check if it is back
        ipdb = IPDB()
        try:
            ifc = ipdb.interfaces[self.ifd]
            assert ('172.16.0.1', 24) in ifc.ipaddr
            assert ('172.16.1.1', 24) in ifc.ipaddr
            assert ifc.flags & 1
        except:
            raise
        finally:
            interface.unfreeze()
            ipdb.release()

    def test_freeze(self):
        require_user('root')

        interface = self.ip.interfaces[self.ifd]

        # set up the interface
        with interface as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.1.1/24')
            i.up()

        # check
        assert ('172.16.0.1', 24) in interface.ipaddr
        assert ('172.16.1.1', 24) in interface.ipaddr
        assert interface.flags & 1

        # assert routine
        def probe():
            # The freeze results are dynamic: it is not a real freeze,
            # it is a restore routine. So it takes time for results
            # to stabilize
            err = None
            for _ in range(3):
                err = None
                interface.ipaddr.set_target((('172.16.0.1', 24),
                                             ('172.16.1.1', 24)))
                interface.ipaddr.target.wait()
                try:
                    assert ('172.16.0.1', 24) in interface.ipaddr
                    assert ('172.16.1.1', 24) in interface.ipaddr
                    assert interface.flags & 1
                    break
                except AssertionError as e:
                    err = e
                    continue
                except Exception as e:
                    err = e
                    break
            if err is not None:
                interface.unfreeze()
                i2.close()
                raise err

        # freeze
        interface.freeze()

        # change the interface somehow
        i2 = IPRoute()
        i2.addr('delete', interface.index, '172.16.0.1', 24)
        i2.addr('delete', interface.index, '172.16.1.1', 24)
        probe()

        # unfreeze
        self.ip.interfaces[self.ifd].unfreeze()

        try:
            i2.addr('delete', interface.index, '172.16.0.1', 24)
            i2.addr('delete', interface.index, '172.16.1.1', 24)
        except:
            pass
        finally:
            i2.close()

        # should be up, but w/o addresses
        interface.ipaddr.set_target(set())
        interface.ipaddr.target.wait(3)
        assert ('172.16.0.1', 24) not in self.ip.interfaces[self.ifd].ipaddr
        assert ('172.16.1.1', 24) not in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

    def test_snapshots(self):
        require_user('root')

        ifB = self.get_ifname()

        # set up the interface
        with self.ip.interfaces[self.ifd] as i:
            i.add_ip('172.16.0.1/24')
            i.up()

        # check it
        assert ('172.16.0.1', 24) in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

        # make a snapshot
        s = self.ip.interfaces[self.ifd].snapshot()
        i = self.ip.interfaces[self.ifd]

        # check it
        assert i.last_snapshot_id() == s

        # unset the interface
        with self.ip.interfaces[self.ifd] as i:
            i.del_ip('172.16.0.1/24')
            i.down()

        # we can not rename the interface while it is up,
        # so do it in two turns
        with self.ip.interfaces[self.ifd] as i:
            i.ifname = ifB

        # check it
        assert ifB in self.ip.interfaces
        assert self.ifd not in self.ip.interfaces
        y = self.ip.interfaces[ifB]
        assert i == y
        assert ('172.16.0.1', 24) not in y.ipaddr
        assert not (y.flags & 1)

        # revert snapshot
        y.revert(s).commit()

        # check it
        assert ifB not in self.ip.interfaces
        assert self.ifd in self.ip.interfaces
        assert ('172.16.0.1', 24) in self.ip.interfaces[self.ifd].ipaddr
        assert self.ip.interfaces[self.ifd].flags & 1

    @skip_if_not_supported
    def _test_ipv(self, ipv, kind):
        require_user('root')

        ifA = self.get_ifname()

        i = self.ip.create(kind=kind, ifname=ifA).commit()
        if self.ip.interfaces[ifA]._mode == 'explicit':
            self.ip.interfaces[ifA].begin()

        if ipv == 4:
            addr = '172.16.0.1/24'
        elif ipv == 6:
            addr = 'fdb3:84e5:4ff4:55e4::1/64'
        else:
            raise Exception('bad IP version')

        i.add_ip(addr).commit()
        pre_target = addr.split('/')
        target = (pre_target[0], int(pre_target[1]))
        assert target in i['ipaddr']

    def test_ipv4_dummy(self):
        self._test_ipv(4, 'dummy')

    def test_ipv4_bond(self):
        self._test_ipv(4, 'bond')

    def test_ipv4_bridge(self):
        self._test_ipv(4, 'bridge')

    def test_ipv6_dummy(self):
        self._test_ipv(6, 'dummy')

    def test_ipv6_bond(self):
        self._test_ipv(6, 'bond')

    def test_ipv6_bridge(self):
        self._test_ipv(6, 'bridge')

    @skip_if_not_supported
    def test_create_tuntap_fail(self):
        try:
            self.ip.create(ifname='fAiL',
                           kind='tuntap',
                           mode='fail').commit()
        except:
            assert not grep('ip link', pattern='fAiL')
            return
        raise Exception('tuntap create succeded')

    @skip_if_not_supported
    def test_create_tuntap(self):
        require_user('root')

        ifA = self.get_ifname()
        self.ip.create(ifname=ifA,
                       kind='tuntap',
                       mode='tap',
                       uid=1,
                       gid=1).commit()

        assert ifA in self.ip.interfaces
        assert grep('ip link', pattern=ifA)

    @skip_if_not_supported
    def test_ovs_kind_aliases(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA,
                       kind='ovs-bridge').commit()
        self.ip.create(ifname=ifB,
                       kind='openvswitch').commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert grep('ip link', pattern=ifA)
        assert grep('ip link', pattern=ifB)

    @skip_if_not_supported
    def test_ovs_add_remove_port(self):
        require_user('root')

        ifOVS = self.get_ifname()
        self.ip.create(ifname=ifOVS,
                       kind='ovs-bridge').commit()
        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, kind='dummy')
        self.ip.create(ifname=ifB, peer='x' + ifB, kind='veth')
        self.ip.commit()

        # add ports
        if self.ip.mode == 'explicit':
            self.ip.interfaces[ifOVS].begin()
        self.ip.interfaces[ifOVS].\
            add_port(self.ip.interfaces[ifA]).\
            add_port(self.ip.interfaces[ifB]).\
            commit()

        #
        assert self.ip.interfaces[ifA].master == \
            self.ip.interfaces[ifOVS].index
        assert self.ip.interfaces[ifB].master == \
            self.ip.interfaces[ifOVS].index
        assert self.ip.interfaces[ifA].index in \
            self.ip.interfaces[ifOVS].ports
        assert self.ip.interfaces[ifB].index in \
            self.ip.interfaces[ifOVS].ports

        # remove ports
        if self.ip.mode == 'explicit':
            self.ip.interfaces[ifOVS].begin()
        self.ip.interfaces[ifOVS].\
            del_port(self.ip.interfaces[ifA]).\
            del_port(self.ip.interfaces[ifB]).\
            commit()

        #
        assert self.ip.interfaces[ifA].get('master') is None
        assert self.ip.interfaces[ifB].get('master') is None
        assert not self.ip.interfaces[ifOVS].ports

    def test_global_create(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, kind='dummy')
        self.ip.create(ifname=ifB, kind='dummy')
        self.ip.commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert grep('ip link', pattern=ifA)
        assert grep('ip link', pattern=ifB)

    def test_global_priorities(self):
        require_user('root')
        ifA = self.get_ifname()
        ifB = self.get_ifname()
        ifC = self.get_ifname()
        a = self.ip.create(ifname=ifA, kind='dummy').commit()
        #
        if a._mode == 'explicit':
            a.begin()

        # prepare transaction: two interface creations
        # and one failure on an existing interface
        a.set_address('11:22:33:44:55:66')
        b = self.ip.create(ifname=ifB, kind='dummy')
        c = self.ip.create(ifname=ifC, kind='dummy')
        # now assign priorities
        b.ipdb_priority = 15  # will be execute first
        a.ipdb_priority = 10  # second -- and fail
        c.ipdb_priority = 5   # should not be executed
        # prepare watchdogs
        wdb = self.ip.watchdog(ifname=ifB)
        wdc = self.ip.watchdog(ifname=ifC)
        # run the transaction
        try:
            self.ip.commit()
        except NetlinkError:
            pass
        # control system state
        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert ifC in self.ip.interfaces
        assert a.ipdb_scope == 'system'
        assert b.ipdb_scope == 'create'
        assert c.ipdb_scope == 'create'
        assert a.address != '11:22:33:44:55:66'
        assert grep('ip link', pattern=ifA)
        assert not grep('ip link', pattern=ifB)
        assert not grep('ip link', pattern=ifC)
        wdb.wait(1)
        wdc.wait(1)
        assert wdb.is_set
        assert not wdc.is_set

    def test_global_veth(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        self.ip.create(ifname=ifA, peer=ifB, kind='veth')
        self.ip.commit()

        assert self.ip.interfaces[ifA]['ipdb_scope'] == 'system'
        assert self.ip.interfaces[ifB]['ipdb_scope'] == 'system'

        if self.ip.mode == 'explicit':
            self.ip.interfaces[ifA].begin()
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifA].remove()
        self.ip.interfaces[ifB].remove()
        self.ip.commit()

        assert ifA not in self.ip.interfaces
        assert ifB not in self.ip.interfaces

    def test_global_rollback(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        a = self.ip.create(ifname=ifA, kind='dummy').commit()
        #
        if a._mode == 'explicit':
            a.begin()
        a.remove()
        b = self.ip.create(ifname=ifB, kind='dummy')
        b.set_mtu(1500).set_address('11:22:33:44:55:66')
        try:
            self.ip.commit()
        except NetlinkError:
            pass

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert b.ipdb_scope == 'create'
        assert grep('ip link', pattern=ifA)
        assert not grep('ip link', pattern=ifB)

    def test_global_netns(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()
        ns = str(uuid.uuid4())

        with IPDB(nl=NetNS(ns)) as nsdb:
            v1 = self.ip.create(ifname='x' + ifA, kind='veth', peer=ifA)
            v2 = self.ip.create(ifname='x' + ifB, kind='veth', peer=ifB)
            if v1._mode == 'explicit':
                v1.begin()
                v2.begin()
            v1.net_ns_fd = ns
            v2.net_ns_fd = ns
            self.ip.commit()
            nsdb.interfaces['x' + ifA].ifname = 'eth0'
            nsdb.interfaces['x' + ifB].ifname = 'eth1'
            nsdb.commit()
            if self.ip.interfaces[ifA]._mode == 'explicit':
                self.ip.interfaces[ifA].begin()
                self.ip.interfaces[ifB].begin()
            self.ip.interfaces[ifA].up()
            self.ip.interfaces[ifB].up()
            self.ip.commit()

        assert 'x' + ifA not in self.ip.interfaces
        assert 'x' + ifB not in self.ip.interfaces
        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces
        assert self.ip.interfaces[ifA].flags & 1
        assert self.ip.interfaces[ifB].flags & 1

        if self.ip.interfaces[ifA]._mode == 'explicit':
            self.ip.interfaces[ifA].begin()
            self.ip.interfaces[ifB].begin()
        self.ip.interfaces[ifA].remove()
        self.ip.interfaces[ifB].remove()
        self.ip.commit()
        netns.remove(ns)

    @skip_if_not_supported
    def test_create_veth(self):
        require_user('root')

        ifA = self.get_ifname()
        ifB = self.get_ifname()

        self.ip.create(ifname=ifA, kind='veth', peer=ifB).commit()

        assert ifA in self.ip.interfaces
        assert ifB in self.ip.interfaces

    def test_create_fail(self):
        require_user('root')

        ifA = self.get_ifname()

        # create with mac 11:22:33:44:55:66 should fail
        i = self.ip.create(kind='dummy',
                           ifname=ifA,
                           address='11:22:33:44:55:66')
        try:
            i.commit()
        except NetlinkError:
            pass

        assert i._mode == 'invalid'
        assert ifA not in self.ip.interfaces

    def test_create_dqn(self):
        require_user('root')
        ifA = self.get_ifname()

        i = self.ip.create(kind='dummy', ifname=ifA)
        i.add_ip('172.16.0.1/255.255.255.0')
        i.commit()
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)

    def test_create_double_reuse(self):
        require_user('root')

        ifA = self.get_ifname()
        # create an interface
        i1 = self.ip.create(kind='dummy', ifname=ifA).commit()
        try:
            # this call should fail on the very first step:
            # `bala` interface already exists
            self.ip.create(kind='dummy', ifname=ifA)
        except CreateException:
            pass
        # add `reuse` keyword -- now should pass
        i2 = self.ip.create(kind='dummy',
                            ifname=ifA,
                            reuse=True).commit()
        # assert that we have got references to the same interface
        assert i1 == i2

    @skip_if_not_supported
    def _create_double(self, kind):
        require_user('root')
        ifA = self.get_ifname()

        self.ip.create(kind=kind, ifname=ifA).commit()
        try:
            self.ip.create(kind=kind, ifname=ifA).commit()
        except CreateException:
            pass

    def test_create_double_dummy(self):
        self._create_double('dummy')

    def test_create_double_bridge(self):
        self._create_double('bridge')

    def test_create_double_bond(self):
        self._create_double('bond')

    def test_create_plain(self):
        require_user('root')
        ifA = self.get_ifname()

        i = self.ip.create(kind='dummy', ifname=ifA)
        i.add_ip('172.16.0.1/24')
        i.commit()
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)

    def test_create_and_remove(self):
        require_user('root')

        ifA = self.get_ifname()

        with self.ip.create(kind='dummy', ifname=ifA) as i:
            i.add_ip('172.16.0.1/24')
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)

        with self.ip.interfaces[ifA] as i:
            i.remove()
        assert ifA not in self.ip.interfaces

    def test_dqn_mask(self):
        require_user('root')

        iface = self.ip.interfaces[self.ifd]
        with iface as i:
            i.add_ip('172.16.0.1/24')
            i.add_ip('172.16.0.2', mask=24)
            i.add_ip('172.16.0.3/255.255.255.0')
            i.add_ip('172.16.0.4', mask='255.255.255.0')

        assert ('172.16.0.1', 24) in iface.ipaddr
        assert ('172.16.0.2', 24) in iface.ipaddr
        assert ('172.16.0.3', 24) in iface.ipaddr
        assert ('172.16.0.4', 24) in iface.ipaddr

    @skip_if_not_supported
    def _create_master(self, kind, **kwarg):

        ifM = self.get_ifname()
        ifP1 = self.get_ifname()
        ifP2 = self.get_ifname()

        self.ip.create(kind='dummy', ifname=ifP1).commit()
        self.ip.create(kind='dummy', ifname=ifP2).commit()

        with self.ip.create(kind=kind, ifname=ifM, **kwarg) as i:
            i.add_port(self.ip.interfaces[ifP1])
            i.add_ip('172.16.0.1/24')

        with self.ip.interfaces[ifM] as i:
            i.add_port(self.ip.interfaces[ifP2])
            i.add_ip('172.16.0.2/24')

        assert ('172.16.0.1', 24) in self.ip.interfaces[ifM].ipaddr
        assert ('172.16.0.2', 24) in self.ip.interfaces[ifM].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifM)
        assert '172.16.0.2/24' in get_ip_addr(interface=ifM)
        assert self.ip.interfaces[ifP1].if_master == \
            self.ip.interfaces[ifM].index
        assert self.ip.interfaces[ifP2].if_master == \
            self.ip.interfaces[ifM].index

        with self.ip.interfaces[ifM] as i:
            i.del_port(self.ip.interfaces[ifP1])
            i.del_port(self.ip.interfaces[ifP2])
            i.del_ip('172.16.0.1/24')
            i.del_ip('172.16.0.2/24')

        assert ('172.16.0.1', 24) not in self.ip.interfaces[ifM].ipaddr
        assert ('172.16.0.2', 24) not in self.ip.interfaces[ifM].ipaddr
        assert '172.16.0.1/24' not in get_ip_addr(interface=ifM)
        assert '172.16.0.2/24' not in get_ip_addr(interface=ifM)
        assert self.ip.interfaces[ifP1].if_master is None
        assert self.ip.interfaces[ifP2].if_master is None

    def test_create_bridge(self):
        require_user('root')
        self._create_master('bridge')

    def test_create_bond(self):
        require_user('root')
        self._create_master('bond')

    def test_create_team(self):
        require_user('root')
        self._create_master('team')

    def test_create_ovs(self):
        require_user('root')
        self._create_master('openvswitch')

    def test_create_bond2(self):
        require_user('root')
        self._create_master('bond', bond_mode=2)

    @skip_if_not_supported
    def _create_macvx_mode(self, kind, mode):
        require_user('root')
        ifL = self.get_ifname()
        ifV = self.get_ifname()
        ifdb = self.ip.interfaces

        self.ip.create(kind='dummy',
                       ifname=ifL).commit()
        self.ip.create(**{'kind': kind,
                          'link': ifdb[ifL],
                          'ifname': ifV,
                          '%s_mode' % kind: mode}).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].link == ifdb[ifL].index
            assert ifdb[ifV]['%s_mode' % kind] == mode
        except Exception:
            raise
        finally:
            ip2.release()

    def test_create_macvtap_vepa(self):
        return self._create_macvx_mode('macvtap', 'vepa')

    def test_create_macvtap_bridge(self):
        return self._create_macvx_mode('macvtap', 'bridge')

    def test_create_macvlan_vepa(self):
        return self._create_macvx_mode('macvlan', 'vepa')

    def test_create_macvlan_bridge(self):
        return self._create_macvx_mode('macvlan', 'bridge')

    def test_create_utf_name(self):
        require_user('root')
        ifO = 'ༀ'
        self.ip.create(kind='dummy', ifname=ifO).commit()
        assert ifO in self.ip.interfaces
        assert self.ip.nl.link_lookup(ifname=ifO)
        if self.ip.interfaces[ifO]._mode == 'explicit':
            self.ip.interfaces[ifO].begin()
        self.ip.interfaces[ifO].remove().commit()

    @skip_if_not_supported
    def test_create_gre(self):
        require_user('root')

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        with self.ip.create(kind='dummy', ifname=ifL) as i:
            i.add_ip('172.16.0.1/24')
            i.up()

        self.ip.create(kind='gre',
                       ifname=ifV,
                       gre_local='172.16.0.1',
                       gre_remote='172.16.0.2',
                       gre_ttl=16).commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces
        try:
            assert ifdb[ifV].gre_local == '172.16.0.1'
            assert ifdb[ifV].gre_remote == '172.16.0.2'
            assert ifdb[ifV].gre_ttl == 16
        except Exception:
            raise
        finally:
            ip2.release()

    @skip_if_not_supported
    def test_create_vxlan(self):
        require_user('root')

        ifL = self.get_ifname()
        ifV = self.get_ifname()
        ifdb = self.ip.interfaces

        self.ip.create(kind='dummy',
                       ifname=ifL).commit()
        self.ip.create(kind='vxlan',
                       ifname=ifV,
                       vxlan_link=ifdb[ifL],
                       vxlan_id=101,
                       vxlan_group='239.1.1.1').commit()

        ip2 = IPDB()
        ifdb = ip2.interfaces

        try:
            assert ifdb[ifV].vxlan_link == ifdb[ifL].index
            assert ifdb[ifV].vxlan_group == '239.1.1.1'
            assert ifdb[ifV].vxlan_id == 101
        except Exception:
            raise
        finally:
            ip2.release()

    def test_create_vlan_by_interface(self):
        require_user('root')
        require_8021q()
        ifL = self.get_ifname()
        ifV = self.get_ifname()

        self.ip.create(kind='dummy',
                       ifname=ifL).commit()
        self.ip.create(kind='vlan',
                       ifname=ifV,
                       link=self.ip.interfaces[ifL],
                       vlan_id=101).commit()

        assert self.ip.interfaces[ifV].link == \
            self.ip.interfaces[ifL].index

    def test_create_vlan_by_index(self):
        require_user('root')
        require_8021q()
        ifL = self.get_ifname()
        ifV = self.get_ifname()

        self.ip.create(kind='dummy',
                       ifname=ifL).commit()
        self.ip.create(kind='vlan',
                       ifname=ifV,
                       link=self.ip.interfaces[ifL].index,
                       vlan_id=101).commit()

        assert self.ip.interfaces[ifV].link == \
            self.ip.interfaces[ifL].index

    def test_remove_secondaries(self):
        require_user('root')

        ifA = self.get_ifname()

        with self.ip.create(kind='dummy', ifname=ifA) as i:
            i.add_ip('172.16.0.1', 24)
            i.add_ip('172.16.0.2', 24)

        assert ifA in self.ip.interfaces
        assert ('172.16.0.1', 24) in self.ip.interfaces[ifA].ipaddr
        assert ('172.16.0.2', 24) in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' in get_ip_addr(interface=ifA)
        assert '172.16.0.2/24' in get_ip_addr(interface=ifA)

        if i._mode == 'explicit':
            i.begin()

        i.del_ip('172.16.0.1', 24)
        i.del_ip('172.16.0.2', 24)
        i.commit()

        assert ('172.16.0.1', 24) not in self.ip.interfaces[ifA].ipaddr
        assert ('172.16.0.2', 24) not in self.ip.interfaces[ifA].ipaddr
        assert '172.16.0.1/24' not in get_ip_addr(interface=ifA)
        assert '172.16.0.2/24' not in get_ip_addr(interface=ifA)
Ejemplo n.º 11
0
import sys
from socket import AF_INET
from pyroute2 import IPRoute
from pprint import pprint
from pyroute2 import IPDB
from tabulate import tabulate
from yaml import load, dump
from time import sleep

#from pyface import Iface, Vlan

ip = IPDB()
parent = ip.interfaces['eth1']
i = ip.interfaces['lltest']
i.remove()
ip.commit()

i = ip.create(kind='vlan',
              ifname='lltest',
              link=parent,
              vlan_id=1234,
              reuse=True)
i.up()
ip.commit()

print("Waiting for fe80 address")
i.wait_ip('fe80::', mask=64)
pprint(i)

i.add_ip('fc00::1:1:1:1/64')
ip.commit()