From 5d50cf2cc49611daf986afc0e2833607cc6ab411 Mon Sep 17 00:00:00 2001 From: Alina Quereilhac Date: Mon, 3 Oct 2011 22:51:51 +0200 Subject: [PATCH] multicast_overlay experoment --- examples/multicast_overlay.py | 344 +++++++++++++++++++++++++++------- src/nepi/core/design.py | 2 +- 2 files changed, 280 insertions(+), 66 deletions(-) diff --git a/examples/multicast_overlay.py b/examples/multicast_overlay.py index 7372f92a..4eb7ea2a 100644 --- a/examples/multicast_overlay.py +++ b/examples/multicast_overlay.py @@ -19,17 +19,18 @@ import operator import ipaddr import gzip import random +import math class PlanetLabMulticastOverlay: testbed_id = "planetlab" - slicename = "inria_nepi" + slicename = "inria_nepi12" plchost = "www.planet-lab.eu" plkey = os.environ.get( "PL_SSH_KEY", "%s/.ssh/id_rsa_planetlab" % (os.environ['HOME'],) ) pluser = os.environ.get("PL_USER") plpass = os.environ.get("PL_PASS") - vnet = "192.168.3.0" + vnet = "192.168.2.0" port_base = 2000 + (os.getpid() % 1000) * 13 @@ -68,17 +69,16 @@ class PlanetLabMulticastOverlay: pl_desc.set_attribute_value("plLogLevel", "INFO") netns_provider = FactoriesProvider("netns") - netns_desc = exp_desc.add_testbed_description(netns_provider) - netns_desc.set_attribute_value("homeDirectory", self.root_dir) - netns_desc.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON) + netns = exp_desc.add_testbed_description(netns_provider) + netns.set_attribute_value("homeDirectory", self.root_dir) + netns.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON) netns_root_dir = os.path.join(self.root_dir, "netns") os.mkdir(netns_root_dir) - netns_desc.set_attribute_value(DC.ROOT_DIRECTORY, netns_root_dir) - netns_desc.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL) - netns_desc.set_attribute_value(DC.USE_SUDO, True) + netns.set_attribute_value(DC.ROOT_DIRECTORY, netns_root_dir) + netns.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL) + netns.set_attribute_value(DC.USE_SUDO, True) - return pl_desc, netns_desc, exp_desc - + return pl_desc, netns, exp_desc def make_pl_tapnode(self, pl, ip, inet = None, label = None, hostname = None, routes = None, mcast = False, mcastrouter = False): if not isinstance(ip, list): @@ -102,11 +102,8 @@ class PlanetLabMulticastOverlay: if label: _tap1.set_attribute_value("label", label+"tap"+(str(i+1) if i else "")) - _tap1ip = _tap1.add_address() - _tap1ip.set_attribute_value("Address", ip) - _tap1ip.set_attribute_value("NetPrefix", 32) - _tap1ip.set_attribute_value("Broadcast", False) - + _tap1ip = self.add_ip_address(_tap1, ip, 32) + node1.connector("devs").connect(_tap1.connector("node")) tap1.append(_tap1) @@ -117,10 +114,7 @@ class PlanetLabMulticastOverlay: iface1.connector("inet").connect(inet.connector("devs")) for destip, destprefix, nexthop in routes: - r1 = node1.add_route() - r1.set_attribute_value("Destination", destip) - r1.set_attribute_value("NetPrefix", destprefix) - r1.set_attribute_value("NextHop", nexthop) + r1 = self.add_route(node1, destip, destprefix, nexthop) if mcast: fwd = pl.create("MulticastForwarder") @@ -132,7 +126,21 @@ class PlanetLabMulticastOverlay: mrt.enable_trace("stderr") return node1, iface1, tap1, tap1ip, inet - + + def add_ip_address(self, iface, address, netprefix, broadcast = False): + ip = iface.add_address() + ip.set_attribute_value("Address", address) + ip.set_attribute_value("NetPrefix", netprefix) + ip.set_attribute_value("Broadcast", broadcast) + return ip + + def add_route(self, node, destination, netprefix, nexthop): + route = node.add_route() + route.set_attribute_value("Destination", destination) + route.set_attribute_value("NetPrefix", netprefix) + route.set_attribute_value("NextHop", nexthop) + return route + def add_vlc_base(self, pl, node): app = pl.create("Application") app.set_attribute_value("rpmFusion", True) @@ -164,8 +172,8 @@ class PlanetLabMulticastOverlay: return app def add_vlc_source(self, netns, node, iflabel): - app = netns_desc.create("Application") - app.set_attribute_value("user", os.getlogin()) + app = netns.create("Application") + app.set_attribute_value("user", self.user) app.set_attribute_value("label","vlc_source_%d" % (node.guid,)) app.set_attribute_value("command", "vlc -vvv -I dummy " @@ -195,68 +203,258 @@ class PlanetLabMulticastOverlay: # Create NS3 testbed running in node1 ns3_provider = FactoriesProvider(ns3_testbed_id) - ns3_desc = exp.add_testbed_description(ns3_provider) - ns3_desc.set_attribute_value("rootDirectory", root) - ns3_desc.set_attribute_value("SimulatorImplementationType", "ns3::RealtimeSimulatorImpl") - ns3_desc.set_attribute_value("ChecksumEnabled", True) - ns3_desc.set_attribute_value(DC.DEPLOYMENT_HOST, "{#[%s].addr[0].[Address]#}" % ( + ns = exp.add_testbed_description(ns3_provider) + ns.set_attribute_value("rootDirectory", root) + ns.set_attribute_value("SimulatorImplementationType", "ns3::RealtimeSimulatorImpl") + ns.set_attribute_value("ChecksumEnabled", True) + ns.set_attribute_value(DC.DEPLOYMENT_HOST, "{#[%s].addr[0].[Address]#}" % ( iface1.get_attribute_value("label"),)) - ns3_desc.set_attribute_value(DC.DEPLOYMENT_USER, + ns.set_attribute_value(DC.DEPLOYMENT_USER, pl.get_attribute_value("slice")) - ns3_desc.set_attribute_value(DC.DEPLOYMENT_KEY, + ns.set_attribute_value(DC.DEPLOYMENT_KEY, pl.get_attribute_value("sliceSSHKey")) - ns3_desc.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON) - ns3_desc.set_attribute_value(DC.DEPLOYMENT_COMMUNICATION, DC.ACCESS_SSH) - ns3_desc.set_attribute_value(DC.DEPLOYMENT_ENVIRONMENT_SETUP, + ns.set_attribute_value(DC.DEPLOYMENT_MODE, DC.MODE_DAEMON) + ns.set_attribute_value(DC.DEPLOYMENT_COMMUNICATION, DC.ACCESS_SSH) + ns.set_attribute_value(DC.DEPLOYMENT_ENVIRONMENT_SETUP, "{#[%s].[%s]#}" % ( node1.get_attribute_value("label"), ATTR_NEPI_TESTBED_ENVIRONMENT_SETUP,)) - ns3_desc.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL) + ns.set_attribute_value(DC.LOG_LEVEL, DC.DEBUG_LEVEL) - return ns3_desc - - def make_netns_node(self, netns_desc): - node = netns_desc.create("Node") + return ns + + def add_pl_ns_node(self, pl_desc, inet, label_prefix): + node = pl_desc.create("Node") + node.set_attribute_value("label", label_prefix) + iface = pl_desc.create("NodeInterface") + iface.set_attribute_value("label", label_prefix+"iface") + iface.connector("inet").connect(inet.connector("devs")) + node.connector("devs").connect(iface.connector("node")) + forwarder = pl_desc.create("MulticastForwarder") + forwarder.enable_trace("stderr") + node.connector("apps").connect(forwarder.connector("node")) + return node, iface + + def add_pl_ns_connection(self, pl_desc, pl_node, pl_addr, + ns, ns_node, ns_addr): + pl_tap = pl_desc.create("TapInterface") + pl_tap.set_attribute_value("tun_cipher", "PLAIN") + self.add_ip_address(pl_tap, pl_addr, 31) + pl_node.connector("devs").connect(pl_tap.connector("node")) + ns_fdnd = ns.create("ns3::FdNetDevice") + ns_node.connector("devs").connect(ns_fdnd.connector("node")) + self.add_ip_address(ns_fdnd, ns_addr, 31) + pl_tap.connector("fd->").connect(ns_fdnd.connector("->fd")) + + def add_pl_ns_tunchan_connection(self, pl_desc, pl_node, pl_addr, + ns, ns_node, ns_addr): + pl_tap = pl_desc.create("TunInterface") + self.add_ip_address(pl_tap, pl_addr, 31) + pl_node.connector("devs").connect(pl_tap.connector("node")) + ns_fdnd = ns.create("ns3::FdNetDevice") + ns_fdnd.enable_trace("FdPcapTrace") + self.add_ip_address(ns_fdnd, ns_addr, 31) + ns_node.connector("devs").connect(ns_fdnd.connector("node")) + ns_tc = ns.create("ns3::Nepi::TunChannel") + ns_tc.connector("fd->").connect(ns_fdnd.connector("->fd")) + pl_tap.connector("tcp").connect(ns_tc.connector("tcp")) + + def make_netns_node(self, netns): + node = netns.create("Node") node.set_attribute_value("forward_X11", True) + command = "xterm" + app = netns.create("Application") + app.set_attribute_value("command", command) + app.set_attribute_value("user", self.user) + app.connector("node").connect(node.connector("apps")) return node - def make_pl_netns_connection(self, pl_desc, pl_node, netns_desc, - netns_node, netns_iface_label, vnet): - base = struct.unpack('!L',socket.inet_aton(vnet))[0] + def make_pl_netns_connection(self, pl_desc, pl_node, netns, + netns_node, netns_iface_label): + base=struct.unpack('!L',socket.inet_aton(self.vnet))[0] netns_addr = socket.inet_ntoa(struct.pack('!L',(base | 1))) pl_addr = socket.inet_ntoa(struct.pack('!L',(base | 2))) - pl_tap = pl_desc.create("TunInterface") pl_tap.set_attribute_value("multicast", True) #pl_tap.set_attribute_value("tun_cipher", "PLAIN") #pl_tap.enable_trace("pcap") #pl_tap.enable_trace("packets") - addr = pl_tap.add_address() - adrr.set_attribute_value("Address", pl_addr) - addr.set_attribute_value("NetPrefix", 32) - addr.set_attribute_value("Broadcast", False) + self.add_ip_address(pl_tap, pl_addr, 31) pl_node.connector("devs").connect(pl_tap.connector("node")) - netns_tap = netns_desc.create("TunNodeInterface") + netns_tap = netns.create("TunNodeInterface") netns_tap.set_attribute_value("label", netns_iface_label) netns_tap.set_attribute_value("up", True) netns_tap.set_attribute_value("mtu", 1448) - addr = netns_tap.add_address() - adrr.set_attribute_value("Address", netns_addr) - addr.set_attribute_value("NetPrefix", 32) - addr.set_attribute_value("Broadcast", False) - route = netns_node.add_route() - route.set_attribute_value("Destination", vnet) - r1.set_attribute_value("NetPrefix", 24) - r1.set_attribute_value("NextHop", pl_addr) + self.add_ip_address(netns_tap, netns_addr, 31) + self.add_route(netns_node, self.vnet, 24, pl_addr) netns_node.connector("devs").connect(netns_tap.connector("node")) - netns_tunchannel = netns_desc.create("TunChannel") + netns_tunchannel = netns.create("TunChannel") #netns_tunchannel.set_attribute_value("tun_cipher", "PLAIN") netns_tunchannel.connector("->fd").connect(netns_tap.connector("fd->")) pl_tap.connector("tcp").connect(netns_tunchannel.connector("tcp")) - def make_pl_overlay(self, numnodes, num_wifi): + def add_ns_fdnd(self, ns, node): + fdnd = ns.create("ns3::FdNetDevice") + node.connector("devs").connect(fdnd.connector("node")) + #fdnd.enable_trace("FdPcapTrace") + return fdnd + + def add_ns_node(self, ns): + node = ns.create("ns3::Node") + ipv4 = ns.create("ns3::Ipv4L3Protocol") + arp = ns.create("ns3::ArpL3Protocol") + icmp = ns.create("ns3::Icmpv4L4Protocol") + udp = ns.create("ns3::UdpL4Protocol") + node.connector("protos").connect(ipv4.connector("node")) + node.connector("protos").connect(arp.connector("node")) + node.connector("protos").connect(icmp.connector("node")) + node.connector("protos").connect(udp.connector("node")) + return node + + def add_ns_wifi_dev(self, ns, node, access_point = False): + wifi = ns.create("ns3::WifiNetDevice") + node.connector("devs").connect(wifi.connector("node")) + + phy = ns.create("ns3::YansWifiPhy") + error = ns.create("ns3::NistErrorRateModel") + manager = ns.create("ns3::ArfWifiManager") + if access_point: + mac = ns.create("ns3::ApWifiMac") + else: + mac = ns.create("ns3::StaWifiMac") + + phy.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a") + mac.set_attribute_value("Standard", "WIFI_PHY_STANDARD_80211a") + phy.connector("err").connect(error.connector("phy")) + wifi.connector("phy").connect(phy.connector("dev")) + wifi.connector("mac").connect(mac.connector("dev")) + wifi.connector("manager").connect(manager.connector("dev")) + + #phy.enable_trace("YansWifiPhyPcapTrace") + return wifi, phy + + def add_ns_constant_mobility(self, ns, node, x, y, z): + mobility = ns.create("ns3::ConstantPositionMobilityModel") + position = "%d:%d:%d" % (x, y, z) + mobility.set_attribute_value("Position", position) + node.connector("mobility").connect(mobility.connector("node")) + return mobility + + def add_ns_wifi_channel(self, ns): + channel = ns.create("ns3::YansWifiChannel") + delay = ns.create("ns3::ConstantSpeedPropagationDelayModel") + loss = ns.create("ns3::LogDistancePropagationLossModel") + channel.connector("delay").connect(delay.connector("chan")) + channel.connector("loss").connect(loss.connector("prev")) + return channel + + def make_ns_wifi(self, ns, pl, pl_ns_root, inet, numwifinodes, nextip): + base=struct.unpack('!L',socket.inet_aton(self.vnet))[0] + error = False + for i in xrange(2, 6): + nr = int(math.pow(2, i)) + if nr <= (numwifinodes + 2): + break + else: + error = True + + # how many IPs will we need? + # 1 for the AP, 2 for each station and one for each extra PL node + # BUT we need to also reserve IPs to sum up to a posible subnetwork + # number of nodes: 2, 4, 8, 16, etc ... + # And finally, we need 2 extra IPs for the PL-AP iface + + nrips = (1 + 2*numwifinodes + nr + 2) + if nrips + nextip[0] > 255: + error = True + if error: + raise RuntimeError("There are not enough IP addresses for the wireless network", ) + + netprefix = 32 - i + _nextwifiip = [254] + def nextwifiip(): + ip = socket.inet_ntoa(struct.pack('!L',(base | _nextwifiip[0]))) + _nextwifiip[0] -= 1 + return ip + + _nextnstapip = [(254 - nr -1)] + def nextnstapip(): + ip = socket.inet_ntoa(struct.pack('!L',(base | _nextnstapip[0]))) + _nextnstapip[0] -= 1 + return ip + + _nexttapip = [(254 - nr - 1 - numwifinodes)] + def nexttapip(): + ip = socket.inet_ntoa(struct.pack('!L',(base | _nexttapip[0]))) + _nexttapip[0] -= 1 + return ip + + # WIFI network + wifi_chan = self.add_ns_wifi_channel(ns) + + # AP node + ap_node = self.add_ns_node(ns) + self.add_ns_constant_mobility(ns, ap_node, 0, 0, 0) + ap_wifi, ap_phy = self.add_ns_wifi_dev(ns, ap_node, access_point = True) + ap_phy.connector("chan").connect(wifi_chan.connector("phys")) + + # connect AP to PL + _nextplip = (254 - nrips) + pl_ip = socket.inet_ntoa(struct.pack('!L',(base | _nextplip))) + print "PL IP %s" % pl_ip + _nextplip -= 1 + ns_ip = socket.inet_ntoa(struct.pack('!L',(base | _nextplip))) + print "NS IP %s" % ns_ip + self.add_pl_ns_connection(pl, pl_ns_root, pl_ip, ns, ap_node, ns_ip) + + # routes in and out ns + self.add_route(ap_node, self.vnet, 24, pl_ip) + net = 256 - nr + ip = socket.inet_ntoa(struct.pack('!L',(base | net))) + self.add_route(pl_ns_root, ip, netprefix, ns_ip) + + ap_ip = nextwifiip() + print "AP IP %s" % ap_ip + self.add_ip_address(ap_wifi, ap_ip, netprefix) + + r = 50 + # STA nodes + for i in xrange(0, numwifinodes): + stai = self.add_ns_node(ns) + angi = (360/numwifinodes)*i + xi = r*math.cos(angi) + yi = r*math.sin(angi) + self.add_ns_constant_mobility(ns, stai, xi, yi, 0) + wifi, phy = self.add_ns_wifi_dev(ns, stai, access_point = False) + phy.connector("chan").connect(wifi_chan.connector("phys")) + + wifi_ip = nextwifiip() + print "WIFI IP %s" % wifi_ip + self.add_ip_address(wifi, wifi_ip, netprefix) + self.add_route(stai, self.vnet, 24, ap_ip) + + """ + pl_nodei, pl_ifacei = self.add_pl_ns_node(pl, inet, + "node2%d_pl"%i) + + pl_addr = (self.base_addr%(net+1)) + ns3_addr = (self.base_addr%(net+2)) + self.add_pl_ns_tunchan_connection(pl_desc, pl_nodei, pl_addr, + ns, stai, ns3_addr) + self.add_route(pl_nodei, (self.base_addr%32), 27, ns3_addr) + self.add_route(pl_nodei, (self.base_addr%0), 30, ns3_addr) + self.add_route(pl_nodei, (self.base_addr%4), 30, ns3_addr) + + network = (self.base_addr%net) + self.add_route(netns_node, network, 30, (self.base_addr%2)) + self.add_route(pl_node1, network, 30, (self.base_addr%6)) + self.add_route(ap_node, network, 30, wifi_addr) + """ + + def make_pl_overlay(self, numnodes, numwifinodes): + print "make_pl_overlay ..." ns3_testbed_id = "ns3" pl, netns, exp = self.make_experiment_desc() @@ -299,6 +497,7 @@ class PlanetLabMulticastOverlay: if parent: parent.childips.update(node.childips) + print "traverse..." traverse(traverse, root) def printtree(printtree, node, indent=''): @@ -311,9 +510,11 @@ class PlanetLabMulticastOverlay: print indent, '|- R', cnet, '->', cip printtree(printtree, child, indent+' | ') printtree(printtree, root) - - inet = pl.create("Internet") + inet = pl.create("Internet") + + ns_chosen = [] + def maketree(maketree, node, parent=None, parentIp=None): routes = [] ctaps = [] @@ -325,6 +526,7 @@ class PlanetLabMulticastOverlay: for cnet in childnets: routes.append((cnet.ip.exploded, cnet.prefixlen, cip.exploded)) ctaps.append( maketree(maketree, child, node, pip) ) + if parentIp: routes.append((self.vnet,24,parentIp)) @@ -332,6 +534,9 @@ class PlanetLabMulticastOverlay: label = "root" else: label = None + if not ns_chosen and node.children: + ns_chosen.append(True) + label = "ns_root" ips = [ ipaddr.IPAddress(node.vif_addr+i) for i in xrange(1+len(node.children)) ] node1, iface1, tap1, tap1ip, _ = self.make_pl_tapnode(pl, ips, inet, hostname = node.hostname, @@ -342,23 +547,31 @@ class PlanetLabMulticastOverlay: for tap, ctap in zip(tap1[1:], ctaps): tap.connector("udp").connect(ctap.connector("udp")) - + self.add_net_monitor(pl, node1) self.add_vlc_restreamer(pl, node1) if random.random() < 0.1 and parent: self.add_vlc_dumper(pl, node1) return tap1[0] + + print "maketree..." maketree(maketree, root) # create a netns node and connect it to the root pl node - pl_root = exp_desc.get_element_by_label("root") + pl_root = exp.get_element_by_label("root") netns_source = self.make_netns_node(netns) iflabel = "source-iface" - self.make_pl_netns_connection(pl_desc, pl_root, netns_desc, - netns_source, iflabel, self.vnet) - self.add_vlc_source(netns, netns_n, iflabel) + self.make_pl_netns_connection(pl, pl_root, netns, + netns_source, iflabel) + self.add_vlc_source(netns, netns_source, iflabel) + # add ns wireless network + pl_ns_root = exp.get_element_by_label("ns_root") + pl_ns_root_iface = exp.get_element_by_label("ns_rootiface") + ns = self.make_ns_in_pl(pl, exp, pl_ns_root, pl_ns_root_iface, "ns3") + self.make_ns_wifi(ns, pl, pl_ns_root, inet, numwifinodes, nextip) + xml = exp.to_xml() test_dir = "./results" @@ -425,7 +638,7 @@ class PlanetLabMulticastOverlay: if __name__ == '__main__': usage = "usage: %prog -n number_sta -m movie -u user" parser = OptionParser(usage=usage) - parser.add_option("-u", "--user", dest="user", help="Valid linux system user (not root).", type="str") + parser.add_option("-u", "--user", dest="user", help="Valid linux system user (not root).", type="str", default=os.getlogin()) parser.add_option("-m", "--movie", dest="movie", help="Path to movie file to play", type="str") parser.add_option("-n", "--nsta", dest="nsta", help="Number of wifi stations", type="int") parser.add_option("-N", "--nodes", dest="nsta", help="Number of overlay nodes", type="int") @@ -441,9 +654,10 @@ if __name__ == '__main__': exp = PlanetLabMulticastOverlay() exp.movie_source = options.movie + exp.user = options.user try: exp.setUp() - exp.make_pl_overlay(50, 8) + exp.make_pl_overlay(5, 2) finally: exp.tearDown() diff --git a/src/nepi/core/design.py b/src/nepi/core/design.py index f40b54b8..11b9d7b3 100644 --- a/src/nepi/core/design.py +++ b/src/nepi/core/design.py @@ -371,7 +371,7 @@ class ExperimentDescription(object): for box in tbd_desc.boxes: l = box.get_attribute_value("label") if label == l: - return tbd_desc + return box return None def add_testbed_description(self, provider, guid = None): -- 2.43.0