def _onlySAPsRequest(): nffg = NFFG(id="BME-req-001") sap1 = nffg.add_sap(name="SAP1", id="sap1") sap2 = nffg.add_sap(name="SAP2", id="sap2") nffg.add_sglink(sap1.add_port(0), sap2.add_port(0)) # nffg.add_sglink(sap1.add_port(1), sap2.add_port(1)) nffg.add_req(sap1.ports[0], sap2.ports[0], bandwidth=1000, delay=24) nffg.add_req(sap1.ports[0], sap2.ports[0], bandwidth=1000, delay=24) return nffg
def _example_request_for_fallback(): nffg = NFFG(id="FALLBACK-REQ", name="fallback-req") sap1 = nffg.add_sap(name="SAP1", id="sap1") sap2 = nffg.add_sap(name="SAP2", id="sap2") # add NF requirements. nf0 = nffg.add_nf(id="NF0", name="NetFunc0", func_type='B', cpu=2, mem=2, storage=2, bandwidth=100) nf1 = nffg.add_nf(id="NF1", name="NetFunc1", func_type='A', cpu=1.5, mem=1.5, storage=1.5, delay=50) nf2 = nffg.add_nf(id="NF2", name="NetFunc2", func_type='C', cpu=3, mem=3, storage=3, bandwidth=500) nf3 = nffg.add_nf(id="NF3", name="NetFunc3", func_type='A', cpu=2, mem=2, storage=2, bandwidth=100, delay=50) # add SG hops nffg.add_sglink(sap1.add_port(0), nf0.add_port(0), id="s1n0") nffg.add_sglink(nf0.add_port(1), nf1.add_port(0), id="n0n1") nffg.add_sglink(nf1.add_port(1), nf2.add_port(0), id="n1n2") nffg.add_sglink(nf1.add_port(2), nf3.add_port(0), id="n1n3") nffg.add_sglink(nf2.add_port(1), sap2.add_port(0), id="n2s2") nffg.add_sglink(nf3.add_port(1), sap2.add_port(1), id="n3s2") # add EdgeReqs # port number on SAP2 doesn`t count nffg.add_req(sap1.ports[0], sap2.ports[1], bandwidth=1000, delay=24) nffg.add_req(nf0.ports[1], nf1.ports[0], bandwidth=200) nffg.add_req(nf0.ports[1], nf1.ports[0], delay=3) # set placement criteria. Should be used to enforce the placement decision of # the upper orchestration layer. Placement criteria can contain multiple # InfraNode id-s, if the BiS-BiS is decomposed to multiple InfraNodes in this # layer. # setattr(nf1, 'placement_criteria', ['nc2']) return nffg
def _testRequestForBacktrack(): nffg = NFFG(id="backtracktest-req", name="btreq") sap1 = nffg.add_sap(name="SAP1", id="sap1req") sap2 = nffg.add_sap(name="SAP2", id="sap2req") a = nffg.add_nf(id="a", name="NetFunc0", func_type='A', cpu=3, mem=3, storage=3) b = nffg.add_nf(id="b", name="NetFunc1", func_type='A', cpu=3, mem=3, storage=3) c = nffg.add_nf(id="c", name="NetFunc2", func_type='A', cpu=3, mem=3, storage=3) nffg.add_sglink(sap1.add_port(0), a.add_port(0), id="sa") nffg.add_sglink(a.add_port(1), b.add_port(0), id="ab") nffg.add_sglink(b.add_port(1), c.add_port(0), id="bc") nffg.add_sglink(c.add_port(1), sap2.add_port(0), id="cs") nffg.add_req(a.ports[0], b.ports[1], delay=1.0, sg_path=["ab"]) nffg.add_req(b.ports[0], c.ports[1], delay=1.0, sg_path=["bc"]) nffg.add_req(c.ports[0], sap2.ports[0], delay=1.0, sg_path=["cs"]) nffg.add_req(sap1.ports[0], sap2.ports[0], delay=50, bandwidth=10, sg_path=["sa", "ab", "bc", "cs"]) return nffg
def generateRequestForCarrierTopo(all_saps_ending, all_saps_beginning, avg_shp_len, nf_types, max_e2e_lat_multiplier=20, min_e2e_lat_multiplier=1.1, loops=False, use_saps_once=True, vnf_sharing_probabilty=0.0, multiSC=False, max_sc_count=2, chain_maxlen=8, max_cpu=4, max_mem=1600, max_storage=3, max_bw=7): """ By default generates VNF-disjoint SC-s starting/ending only once in each SAP. With the 'loops' option, only loop SC-s are generated. 'vnf_sharing_probabilty' determines the ratio of #(VNF-s used by at least two SC-s)/#(not shared VNF-s). """ sc_count = 1 gen = NameGenerator() # maximal possible bandwidth for chains if multiSC: sc_count = rnd.randint(2, max_sc_count) while len(all_saps_ending) > sc_count and len( all_saps_beginning) > sc_count: nffg = NFFG(id="E2e_req_test_nffg") nffg.mode = NFFG.MODE_ADD # newly added NF-s of one request current_nfs = [] for scid in xrange(0, sc_count): # find two SAP-s for chain ends. nfs_this_sc = [] sapid = all_saps_beginning.pop() if use_saps_once else \ rnd.choice(all_saps_beginning) if sapid not in nffg: sap1 = nffg.add_sap(id=sapid) else: sap1 = nffg.network.node[sapid] sap2 = None if loops: sap2 = sap1 else: tmpid = all_saps_ending.pop() if use_saps_once else \ rnd.choice(all_saps_ending) while True: if tmpid != sap1.id: if tmpid not in nffg: sap2 = nffg.add_sap(id=tmpid) else: sap2 = nffg.network.node[tmpid] break else: tmpid = all_saps_ending.pop() if use_saps_once else \ rnd.choice(all_saps_ending) sg_path = [] if len(sap1.ports) > 0: for sap1port in sap1.ports: break else: sap1port = sap1.add_port(id=gen.get_name("port")) last_req_port = sap1port # generate some VNF-s connecting the two SAP-s vnf_cnt = next(gen_seq()) % chain_maxlen + 1 for vnf in xrange(0, vnf_cnt): # in the first case p is used to determine which previous chain should # be used to share the VNF, in the latter case it is used to determine # whether we should share now. p = rnd.random() if multiSC and \ p < vnf_sharing_probabilty and len(current_nfs) > 0: # this influences the the given VNF sharing probability... if reduce(lambda a, b: a and b, [v in nfs_this_sc for v in current_nfs]): log.warn( "All shareable VNF-s are already added to this chain! " "Skipping VNF sharing...") continue else: nf = rnd.choice(current_nfs) while nf in nfs_this_sc: nf = rnd.choice(current_nfs) # the VNF is already in the subchain, we just need to add the # links # vnf_added = True else: nf = nffg.add_nf(id="-".join( ("SC", str(scid), "VNF", str(vnf))), func_type=rnd.choice(nf_types), cpu=rnd.random() * max_cpu, mem=rnd.random() * max_mem, storage=rnd.random() * max_storage) nfs_this_sc.append(nf) newport = nf.add_port(id=gen.get_name("port")) sglink = nffg.add_sglink(last_req_port, newport, id=gen.get_name("link")) sg_path.append(sglink.id) last_req_port = nf.add_port(id=gen.get_name("port")) if len(sap2.ports) > 0: for sap2port in sap2.ports: break else: sap2port = sap2.add_port(id=gen.get_name("port")) sglink = nffg.add_sglink(last_req_port, sap2port, id=gen.get_name("link")) sg_path.append(sglink.id) # WARNING: this is completly a wild guess! Failing due to this doesn't # necessarily mean algorithm failure # Bandwidth maximal random value should be min(SAP1acces_bw, # SAP2access_bw) # MAYBE: each SAP can only be once in the reqgraph? - this is the case # now. minlat = avg_shp_len * min_e2e_lat_multiplier maxlat = avg_shp_len * max_e2e_lat_multiplier nffg.add_req(sap1port, sap2port, delay=rnd.uniform(minlat, maxlat), bandwidth=rnd.random() * max_bw, sg_path=sg_path, id=gen.get_name("req")) # log.debug( # "Service Chain on NF-s added: %s" % [nf.id for nf in nfs_this_sc]) # this prevents loops in the chains and makes new and old NF-s equally # preferable in total for NF sharing new_nfs = [vnf for vnf in nfs_this_sc if vnf not in current_nfs] for tmp in xrange(0, scid + 1): current_nfs.extend(new_nfs) if not multiSC: return nffg if multiSC: return nffg return None
def generateRequestForCarrierTopo(test_lvl, all_saps_beginning, all_saps_ending, running_nfs, loops=False, use_saps_once=True, vnf_sharing_probabilty=0.0, vnf_sharing_same_sg=0.0, shareable_sg_count=9999999999999999, multiSC=False, max_sc_count=2): """ By default generates VNF-disjoint SC-s starting/ending only once in each SAP. With the 'loops' option, only loop SC-s are generated. 'vnf_sharing_probabilty' determines the ratio of #(VNF-s used by at least two SC-s)/#(not shared VNF-s). NOTE: some kind of periodicity is included to make the effect of batching visible. But it is (and must be) independent of the batch_length. WARNING!! batch_length meaining is changed if --poisson is set! Generate exponential arrival time for VNF-s to make Batching more reasonable. inter arrival time is Exp(1) so if we are batching for 4 time units, the expected SG count is 4, because the sum of 4 Exp(1) is Exp(4). BUT we wait for 1 SG at least, but if by that time 4 units has already passed, map the SG alone (unbatched). """ chain_maxlen = 8 sc_count = 1 # maximal possible bandwidth for chains max_bw = 7.0 if multiSC: sc_count = random.randint(2, max_sc_count) while len(all_saps_ending) > sc_count and len( all_saps_beginning) > sc_count: nffg = NFFG(id="Benchmark-Req-" + str(test_lvl) + "-Piece") # newly added NF-s of one request current_nfs = [] for scid in xrange(0, sc_count): # find two SAP-s for chain ends. nfs_this_sc = [] sap1 = nffg.add_sap(id = all_saps_beginning.pop() if use_saps_once else \ random.choice(all_saps_beginning)) sap2 = None if loops: sap2 = sap1 else: tmpid = all_saps_ending.pop() if use_saps_once else \ random.choice(all_saps_ending) while True: if tmpid != sap1.id: sap2 = nffg.add_sap(id=tmpid) break else: tmpid = all_saps_ending.pop() if use_saps_once else \ random.choice(all_saps_ending) sg_path = [] sap1port = sap1.add_port() last_req_port = sap1port # generate some VNF-s connecting the two SAP-s vnf_cnt = next(gen_seq()) % chain_maxlen + 1 for vnf in xrange(0, vnf_cnt): # in the first case p is used to determine which previous chain should # be used to share the VNF, in the latter case it is used to determine # whether we should share now. vnf_added = False p = random.random() if random.random() < vnf_sharing_probabilty and len(running_nfs) > 0 \ and not multiSC: vnf_added, nf = _shareVNFFromEarlierSG( nffg, running_nfs, nfs_this_sc, p) elif multiSC and \ p < vnf_sharing_probabilty and len(current_nfs) > 0 \ and len(running_nfs) > 0: # this influences the the given VNF sharing probability... if reduce(lambda a, b: a and b, [v in nfs_this_sc for v in current_nfs]): log.warn( "All shareable VNF-s are already added to this chain! " "Skipping VNF sharing...") elif random.random() < vnf_sharing_same_sg: nf = random.choice(current_nfs) while nf in nfs_this_sc: nf = random.choice(current_nfs) # the VNF is already in the subchain, we just need to add the links # vnf_added = True else: # this happens when VNF sharing is needed but not with the actual SG vnf_added, nf = _shareVNFFromEarlierSG( nffg, running_nfs, nfs_this_sc, p) else: nf = nffg.add_nf(id="-".join(("Test",str(test_lvl),"SC",str(scid), "VNF",str(vnf))), func_type=random.choice(['A','B','C']), cpu=random.randint(1 + (2 if test_lvl%4 == 3 else 0), 4 + (6 if test_lvl%4 == 3 else 0)), mem=random.random()*1000 + \ (1000 if test_lvl%4 > 1 else 0), storage=random.random()*3 + \ (6 if test_lvl%4 > 1 else 0), delay=1 + random.random()*10, bandwidth=random.random()) vnf_added = True if vnf_added: # add olny the newly added VNF-s, not the shared ones. nfs_this_sc.append(nf) newport = nf.add_port() sglink = nffg.add_sglink(last_req_port, newport) sg_path.append(sglink.id) last_req_port = nf.add_port() sap2port = sap2.add_port() sglink = nffg.add_sglink(last_req_port, sap2port) sg_path.append(sglink.id) # WARNING: this is completly a wild guess! Failing due to this doesn't # necessarily mean algorithm failure # Bandwidth maximal random value should be min(SAP1acces_bw, SAP2access_bw) # MAYBE: each SAP can only be once in the reqgraph? - this is the case now. if multiSC: minlat = 5.0 * (len(nfs_this_sc) + 2) maxlat = 13.0 * (len(nfs_this_sc) + 2) else: # nfcnt = len([i for i in nffg.nfs]) minlat = 45.0 - 10.0 * (test_lvl % 4) maxlat = 60.0 - 12.25 * (test_lvl % 4) nffg.add_req(sap1port, sap2port, delay=random.uniform(minlat, maxlat), bandwidth=random.random() * (max_bw + test_lvl % 4), sg_path=sg_path) log.info("Service Chain on NF-s added: %s" % [nf.id for nf in nfs_this_sc]) # this prevents loops in the chains and makes new and old NF-s equally # preferable in total for NF sharing new_nfs = [vnf for vnf in nfs_this_sc if vnf not in current_nfs] for tmp in xrange(0, scid + 1): current_nfs.extend(new_nfs) if not multiSC: return nffg, all_saps_beginning, all_saps_ending if multiSC: return nffg, all_saps_beginning, all_saps_ending return None, all_saps_beginning, all_saps_ending
def _constructExampleRequest(): nffg = NFFG(id="BME-req-001") sap0 = nffg.add_sap(name="SAP0", id="sap0") sap1 = nffg.add_sap(name="SAP1", id="sap1") # add NF requirements. # Note: storage is used now for the first time, it comes in with the # NodeResource class # Note: internal latency is only forwarded to lower layer # Note: internal bw is untested yet, even before the NFFG support nf0 = nffg.add_nf(id="NF0", name="NetFunc0", func_type='A', cpu=2, mem=2, storage=2, bandwidth=100) nf1 = nffg.add_nf(id="NF1", name="NetFunc1", func_type='B', cpu=1.5, mem=1.5, storage=1.5, delay=50) nf2 = nffg.add_nf(id="NF2", name="NetFunc2", func_type='C', cpu=3, mem=3, storage=3, bandwidth=500) nf3 = nffg.add_nf(id="NF3", name="NetFunc3", func_type='A', cpu=2, mem=2, storage=2, bandwidth=100, delay=50) nf4 = nffg.add_nf(id="NF4", name="NetFunc4", func_type='C', cpu=0, mem=0, storage=0, bandwidth=500) # directed SG links # flowclass default: None, meaning: match all traffic # some agreement on flowclass format is required. nffg.add_sglink(sap0.add_port(0), nf0.add_port(0)) nffg.add_sglink(nf0.add_port(1), nf1.add_port(0), flowclass="HTTP") nffg.add_sglink(nf1.add_port(1), nf2.add_port(0), flowclass="HTTP") nffg.add_sglink(nf2.add_port(1), sap1.add_port(1)) nffg.add_sglink(nf0.add_port(2), nf3.add_port(0), flowclass="non-HTTP") nffg.add_sglink(nf3.add_port(1), nf2.add_port(2), flowclass="non-HTTP") nffg.add_sglink(nf1.add_port(2), nf4.add_port(0), flowclass="index.com") nffg.add_sglink(nf4.add_port(1), nf2.add_port(3), flowclass="index.com") # add EdgeReqs nffg.add_req(sap0.ports[0], sap1.ports[1], delay=40, bandwidth=1500) nffg.add_req(nf1.ports[1], nf2.ports[0], delay=3.5) nffg.add_req(nf3.ports[1], nf2.ports[2], bandwidth=500) nffg.add_req(sap0.ports[0], nf0.ports[0], delay=3.0) # force collocation of NF0 and NF3 # nffg.add_req(nf0.ports[2], nf3.ports[0], delay=1.0) # not SAP-to-SAP requests are not taken into account yet, these are ignored nffg.add_req(nf0.ports[1], nf2.ports[0], delay=1.0) # test Infra node removal from the request NFFG infra1 = nffg.add_infra(id="BiS-BiS1") infra2 = nffg.add_infra(id="BiS-BiS2") nffg.add_undirected_link(infra1.add_port(0), nf0.add_port(3), dynamic=True) nffg.add_undirected_link(infra1.add_port(1), nf0.add_port(4), dynamic=True) nffg.add_undirected_link(infra1.add_port(2), nf1.add_port(3), dynamic=True) nffg.add_undirected_link(infra2.add_port(0), nf2.add_port(4), dynamic=True) nffg.add_undirected_link(infra2.add_port(1), nf3.add_port(2), dynamic=True) nffg.add_undirected_link(infra1.add_port(3), infra2.add_port(2), bandwidth=31241242) return nffg