% % Service Function Chain % % Contact: t.liu@unibo.it % Ref % Liu, Tong, et al. "Constraint programming for flexible Service Function Chaining deployment." arXiv preprint arXiv:1812.05534 (2018). int: VNF_DOMAIN_KEY = 8; int: VNF_STATE_KEY = 7; int: VNF_TYPE = 2; int: VNF_TERMINATING = 3; int: VNF_MIRRORED = 5; int: ENDPOINT = 10; int: GATEWAY = 9; % services int: n_services = 5; int: WANA = 2; int: DPI = 1; int: SHAPER = 3; int: VPN = 4; int: NAT = 5; %%%%%%%%%%%%%%%%%%%%%%%%%%%% % Functional Parameters %%%%%%%%%%%%%%%%%%%%%%%%%%%% int: n_nodes; % number of nodes in the matrix int: start_domain; % start node int: target_domain; % end node int: M; % edge cost's upper bound int: n_domains; % num of domains int: num_node_links; % num of vnf links int: n_domain_constraints; array[1..n_domain_constraints,1..4] of int: domain_constraints; array[1..n_nodes, 1..8] of int: nodes; % vnf attributes array[1..num_node_links, 1..2] of 1..n_nodes: node_links; % vnf links array[1..n_domains, 1..n_domains] of 0..M: domain_link_weights; % distance matrix array[1..vnflist_size] of 0..1: proximity_to_source; % VNF service in end domain array[1..vnflist_size] of 0..1: proximity_to_destination; % VNF service in end domain int: vnflist_size; int: n_vnf_arcs = vnflist_size - 1; array[1..vnflist_size] of 1..10: vnflist; % 10 is the number of types array[1..n_vnf_arcs, 1..2] of 0..vnflist_size: vnf_arcs; % arcs extracted from vnflist considering dupList array[1..vnflist_size] of var 1..n_nodes: vnf_match; % ground nodes for vnflist array[1..n_domains,1..n_domains] of var 0..1: domain_path; % domain_path[i,j]=1 means domain i is reachable from j (exists a path from j to i) array[1..n_domains] of var 0..1: selected_domain; % domains traversed by SFC array[1..n_nodes] of var 0..1: selected_nodes; % all nodes belong to SFC array[1..num_node_links] of var 0..1: link_selection; % resulting SFC var int: n_fun_nodes; % number of functional nodes in SFC (excepting GATEWAY nodes) var int: objective; % objective function % -- constraint objective = sum(i in 1..num_node_links where nodes[node_links[i,1], VNF_TYPE] = GATEWAY /\ nodes[node_links[i,2], VNF_TYPE] = GATEWAY ) (domain_link_weights[nodes[node_links[i,1], VNF_DOMAIN_KEY], nodes[node_links[i,2],VNF_DOMAIN_KEY] ]*link_selection[i] ); % % ------------------------------------------------- % % SFC Model % % ------------------------------------------------- % % % domain constraints: % % % ------------------------------------------------- % % % % optimized predicate ensure_domain_vnf(var int: domain_id,var int: type_id,var int: min,var int: max) = let { var 0..vnflist_size: acc = sum(i in 1..vnflist_size where nodes[vnf_match[i],VNF_DOMAIN_KEY] = domain_id /\ nodes[vnf_match[i],VNF_TYPE] = type_id )( 1 ) } in ( acc >= min /\ acc <= max ) ; % optimized constraint forall(i in 1..n_domain_constraints)( selected_domain[domain_constraints[i,1]] = 1 -> ensure_domain_vnf(domain_constraints[i,1], domain_constraints[i,2], domain_constraints[i,3], domain_constraints[i,4]) ); % % domain path constraints: % % ------------------------------------------------- % % domain has a path to itself constraint forall(i,j in 1..n_domains where i == j)( domain_path[i,j] = 1 ); % propagate domain path constraint forall(i,j in 1..n_domains where i exists(j in 1..n_nodes where nodes[j,VNF_DOMAIN_KEY] = target_domain)( selected_nodes[j] = 1 /\ vnf_match[i] = j ) ); constraint forall(i in 1..vnflist_size)( proximity_to_source[i] = 1 -> exists(j in 1..n_nodes where nodes[j,VNF_DOMAIN_KEY] = start_domain)( selected_nodes[j] = 1 /\ vnf_match[i] = j ) ); % % % channel constraints: % % % ------------------------------------------------- % % % node with incoming arc means node domain is selected constraint forall(i in 1..num_node_links)( link_selection[i] = 1 -> selected_domain[nodes[node_links[i,1], VNF_DOMAIN_KEY] ] == 1 /\ selected_domain[nodes[node_links[i,2], VNF_DOMAIN_KEY] ] == 1 /\ selected_nodes[node_links[i,1]] == 1 /\ selected_nodes[node_links[i,2]] == 1 ) ;% includes both start and target D because ENDPOINT connects to gateway% % constraint approach 1 % % % get number of fun nodes by filtering selected_nodes constraint n_fun_nodes = sum(i in 1..n_nodes where nodes[i,VNF_TYPE] != GATEWAY)( selected_nodes[i] ); % tightly bound the number of selected fun node to vnflist, constraint n_fun_nodes = vnflist_size; % % % ENDPOINT constraint: % % % ------------------------------------------------- % % % ENDPOINT arcs must be selected in start and target domains constraint forall(i in 1..num_node_links where (nodes[node_links[i,2], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,1], VNF_TYPE] == ENDPOINT /\ nodes[node_links[i,1], VNF_DOMAIN_KEY] == start_domain) \/ (nodes[node_links[i,1], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,2], VNF_TYPE] == ENDPOINT /\ nodes[node_links[i,2], VNF_DOMAIN_KEY] == target_domain) )( link_selection[i] = 1 ); % % no arcs to ENDPOINT if they are not start target domains constraint forall(i in 1..num_node_links where (nodes[node_links[i,1], VNF_TYPE] == ENDPOINT /\ nodes[node_links[i,1], VNF_DOMAIN_KEY] != start_domain) \/ (nodes[node_links[i,2], VNF_TYPE] == ENDPOINT /\ nodes[node_links[i,2], VNF_DOMAIN_KEY] != target_domain) )( link_selection[i] = 0 ); % ENDPOINT in start and target domains are selected, others no constraint forall(i in 1..n_nodes where nodes[i,VNF_TYPE] == ENDPOINT)( if nodes[i,VNF_DOMAIN_KEY] = start_domain \/ nodes[i,VNF_DOMAIN_KEY] = target_domain then selected_nodes[i] == 1 else selected_nodes[i] == 0 endif ); % ------------------------------------------------- % Core Graph % ------------------------------------------------- % ??? todo % no loop between neighbor domains constraint forall(i,j in 1..num_node_links where i < j /\ nodes[node_links[i,1], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,2], VNF_TYPE] == GATEWAY /\ node_links[i,1] == node_links[j,2] /\ node_links[i,2] == node_links[j,1] ) ( not (link_selection[i] = 1 /\ link_selection[j] = 1) % link_selection[i] = 1 -> link_selection[j] = 1 ); % start domain has no incoming arc from other domain constraint forall(i in 1..num_node_links where nodes[node_links[i,2], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,1], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,2], VNF_DOMAIN_KEY] = start_domain ) ( link_selection[i] = 0 ); % no domains allow 2 incoming arcs from different domains % todo: can be improved based on domains ? constraint not exists(i,j in 1..num_node_links where i < j /\ nodes[node_links[i,2], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,1], VNF_TYPE] == GATEWAY /\ nodes[node_links[j,2], VNF_TYPE] == GATEWAY /\ nodes[node_links[j,1], VNF_TYPE] == GATEWAY /\ nodes[node_links[i,2], VNF_DOMAIN_KEY] == nodes[node_links[j,2], VNF_DOMAIN_KEY] /\ nodes[node_links[i,1], VNF_DOMAIN_KEY] != nodes[node_links[j,1], VNF_DOMAIN_KEY] ) ( link_selection[i] = 1 /\ link_selection[j] = 1 ); % each selected domain must have an incoming arc from other domain constraint forall(i in 1..n_domains where i != start_domain) ( selected_domain[i] == 1 -> exists (j in 1..num_node_links)( link_selection[j] = 1 /\ nodes[node_links[j,2], VNF_DOMAIN_KEY] == i /\ nodes[node_links[j,1], VNF_DOMAIN_KEY] != i /\ nodes[node_links[j,2], VNF_TYPE] == GATEWAY /\ nodes[node_links[j,1], VNF_TYPE] == GATEWAY )); % no outgoing arcs from unselected domains constraint forall(i in 1..num_node_links) ( selected_domain[nodes[node_links[i,1],VNF_DOMAIN_KEY]] = 0 -> link_selection[i] = 0 ); % solve satisfy; solve :: seq_search([ int_search(selected_domain, input_order, indomain_min), int_search(selected_nodes, input_order, indomain_min), int_search(link_selection, input_order, indomain_min), int_search(domain_path, input_order, indomain_min)]) minimize objective; % outputs % -------------------------- output [ "vnf_match = array1d(1..\(vnflist_size), \(vnf_match));\n", "domain_path = array2d(1..\(n_domains), 1..\(n_domains), \(domain_path));\n", "selected_domain = array1d(1..\(n_domains), \(selected_domain));\n", "selected_nodes = array1d(1..\(n_nodes), \(selected_nodes));\n", "link_selection = array1d(1..\(num_node_links), \(link_selection));\n", "n_fun_nodes = \(n_fun_nodes);\n", "objective = \(objective);\n" ]; % output[show(link_selection),show(selected_domain)]; % output[ % "total_cost = ", show(objective), "\n" % ]; % output[show(domain_path)]; % output[show(vnf_match)]; % output[show(n_fun_nodes)]; % output[show(selected_nodes)];