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
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 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()
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
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)
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()
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()
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)
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)
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()