Thanks!
All the switches use the same P4 program as follows:
/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
const bit<16> TYPE_IPV4 = 0x800;
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
typedef bit<9> egressSpec_t;
typedef bit<48> macAddr_t;
typedef bit<32> ip4Addr_t;
header ethernet_t {
macAddr_t dstAddr;
macAddr_t srcAddr;
bit<16> etherType;
}
header ipv4_t {
bit<4> version;
bit<4> ihl;
bit<6> dscp;
bit<2> ecn;
bit<16> totalLen;
bit<16> identification;
bit<3> flags;
bit<13> fragOffset;
bit<8> ttl;
bit<8> protocol;
bit<16> hdrChecksum;
ip4Addr_t srcAddr;
ip4Addr_t dstAddr;
}
struct metadata {
/* empty */
}
struct headers {
ethernet_t ethernet;
ipv4_t ipv4;
}
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
packet.extract(hdr.ethernet);
transition select(hdr.ethernet.etherType){
TYPE_IPV4: ipv4;
default: accept;
}
}
state ipv4 {
packet.extract(hdr.ipv4);
transition accept;
}
}
/*************************************************************************
************ C H E C K S U M V E R I F I C A T I O N *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) {
//set the src mac address as the previous dst
hdr.ethernet.srcAddr = hdr.ethernet.dstAddr;
//set the destination mac address that we got from the match in the table
hdr.ethernet.dstAddr = dstAddr;
//set the output port that we also get from the table
standard_metadata.egress_spec = port;
//decrease ttl by 1
hdr.ipv4.ttl = hdr.ipv4.ttl -1;
}
table ipv4_lpm {
key = {
hdr.ipv4.dstAddr: lpm;
}
actions = {
ipv4_forward;
drop;
NoAction;
}
size = 1024;
default_action = NoAction();
}
apply {
//only if IPV4 the rule is applied. Therefore other packets will not be forwarded.
if (hdr.ipv4.isValid()){
ipv4_lpm.apply();
}
}
}
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
apply { }
}
/*************************************************************************
************* C H E C K S U M C O M P U T A T I O N **************
*************************************************************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
update_checksum(
hdr.ipv4.isValid(),
{ hdr.ipv4.version,
hdr.ipv4.ihl,
hdr.ipv4.dscp,
hdr.ipv4.ecn,
hdr.ipv4.totalLen,
hdr.ipv4.identification,
hdr.ipv4.flags,
hdr.ipv4.fragOffset,
hdr.ipv4.ttl,
hdr.ipv4.protocol,
hdr.ipv4.srcAddr,
hdr.ipv4.dstAddr },
hdr.ipv4.hdrChecksum,
HashAlgorithm.csum16);
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
//parsed headers have to be added again into the packet.
packet.emit(hdr.ethernet);
packet.emit(hdr.ipv4);
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
//switch architecture
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main;
I have configure all the 20 switches table files, c1-c4, a1-a8, e1-e8. But for the convenience of reading, I only wrote e1, e2, and a1. Below, I will write the complete topology, switch flow table files and network.py.
network.py:
from p4utils.mininetlib.network_API import NetworkAPI
def create_fat_tree_topology(k):
if k % 2 != 0:
raise ValueError("The order k of Fat-Tree must be even!")
net = NetworkAPI()
# Network general options
net.setLogLevel('info')
net.enableCli()
# Network definition
# Number of Core layer switches = (k/2) ^ 2
# Number of Agg Layer and Edge Layer Switches = k * k/2
core_switch_count = (k // 2) ** 2
agg_switch_count = k * (k // 2)
edge_switch_count = agg_switch_count
core_switches = [f'c{i+1}' for i in range(core_switch_count)]
aggregation_switches = [f'a{i+1}' for i in range(agg_switch_count)]
edge_switches = [f'e{i+1}' for i in range(edge_switch_count)]
# Add Core switch
for core_switch in core_switches:
net.addP4Switch(core_switch, cli_input=f'switch/core/{core_switch.lower()}-commands.txt')
# Add Agg switch
for agg_switch in aggregation_switches:
net.addP4Switch(agg_switch, cli_input=f'switch/agg/{agg_switch.lower()}-commands.txt')
# Add Edge switch
for edge_switch in edge_switches:
net.addP4Switch(edge_switch, cli_input=f'switch/edge/{edge_switch.lower()}-commands.txt')
net.setP4SourceAll('p4src/forwarding.p4')
# Number of servers = k ^ 3/4
host_count = (k ** 3) // 4
hosts = {} #
#hosts = [f'h{i+1}' for i in range(host_count)]
# Add Host
# Dynamically add hosts with IP and MAC
host_index = 1
for pod in range(k):
for edge in range(k // 2):
# Global Edge
global_edge_index = pod * (k // 2) + edge + 1
for host in range(k // 2):
host_name = f'h{host_index}'
ip = f'10.{pod}.{global_edge_index}.{host + 1}/24'
#ip = f'10.{pod}.{global_edge_index}.{host + 1}'
mac = f'00:00:{pod:02x}:{global_edge_index:02x}:00:{host + 1:02x}'
net.addHost(host_name)
# hosts
if global_edge_index not in hosts:
hosts[global_edge_index] = []
hosts[global_edge_index].append((host_name, ip, mac))
host_index += 1
# Links
# 1. Core - Agg Links
for i, core_switch in enumerate(core_switches):
for pod in range(k): # Traverse all Pods
# Calculate the convergence switch index connected by the core switch
agg_index = pod * (k // 2) + (i // (k // 2))
net.addLink(core_switch, aggregation_switches[agg_index])
mac_Core_Agg = f'00:01:{i + 1:02x}:00:00:{agg_index + 1:02x}'
mac_Agg_Core = f'00:02:{i + 1:02x}:00:00:{agg_index + 1:02x}'
net.setIntfMac(core_switch, aggregation_switches[agg_index], mac_Core_Agg)
net.setIntfMac(aggregation_switches[agg_index], core_switch, mac_Agg_Core)
# 2. Agg - Edge Links
for pod in range(k):
for agg in range(k // 2):
for edge in range(k // 2):
agg_index = pod * (k // 2) + agg
edge_index = pod * (k // 2) + edge
net.addLink(aggregation_switches[agg_index], edge_switches[edge_index])
mac_Agg_Edge = f'00:02:{agg_index + 1:02x}:00:{edge_index + 1:02x}:00'
mac_Edge_Agg = f'00:03:{agg_index + 1:02x}:00:{edge_index + 1:02x}:00'
net.setIntfMac(aggregation_switches[agg_index], edge_switches[edge_index], mac_Agg_Edge)
net.setIntfMac(edge_switches[edge_index], aggregation_switches[agg_index], mac_Edge_Agg)
# 3. Edge - Host Links
for access_id, host_info in hosts.items():
edge_host = 1
for host_name, ip, mac in host_info:
net.addLink(edge_switches[access_id - 1], host_name) # access_id - 1
net.setIntfIp(host_name, edge_switches[access_id - 1], ip)
#net.setIntfIp(host_name, edge_switches[access_id - 1], f'{ip}/32')
net.setIntfMac(host_name, edge_switches[access_id - 1], mac)
mac_Edge_Host = f'00:03:{access_id:02x}:00:00:{edge_host:02x}'
net.setIntfMac(edge_switches[access_id - 1], host_name, mac_Edge_Host)
edge_host = edge_host + 1
# Nodes general options
net.enablePcapDumpAll()
net.enableLogAll()
# Start network
net.startNetwork()
if __name__ == '__main__':
# Fat-Tree
k = 4 # Fat-Tree
create_fat_tree_topology(k)
The topology photo:
c1-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.0.0/16 => 00:02:01:00:00:01 1
table_add ipv4_lpm ipv4_forward 10.1.0.0/16 => 00:02:01:00:00:03 2
table_add ipv4_lpm ipv4_forward 10.2.0.0/16 => 00:02:01:00:00:05 3
table_add ipv4_lpm ipv4_forward 10.3.0.0/16 => 00:02:01:00:00:07 4
c2-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.0.0/16 => 00:02:02:00:00:01 1
table_add ipv4_lpm ipv4_forward 10.1.0.0/16 => 00:02:02:00:00:03 2
table_add ipv4_lpm ipv4_forward 10.2.0.0/16 => 00:02:02:00:00:05 3
table_add ipv4_lpm ipv4_forward 10.3.0.0/16 => 00:02:02:00:00:07 4
c3-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.0.0/16 => 00:02:03:00:00:02 1
table_add ipv4_lpm ipv4_forward 10.1.0.0/16 => 00:02:03:00:00:04 2
table_add ipv4_lpm ipv4_forward 10.2.0.0/16 => 00:02:03:00:00:06 3
table_add ipv4_lpm ipv4_forward 10.3.0.0/16 => 00:02:03:00:00:08 4
c4-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.0.0/16 => 00:02:04:00:00:02 1
table_add ipv4_lpm ipv4_forward 10.1.0.0/16 => 00:02:04:00:00:04 2
table_add ipv4_lpm ipv4_forward 10.2.0.0/16 => 00:02:04:00:00:06 3
table_add ipv4_lpm ipv4_forward 10.3.0.0/16 => 00:02:04:00:00:08 4
a1-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:03:01:00:01:00 1
table_add ipv4_lpm ipv4_forward 10.0.2.0/24 => 00:03:01:00:02:00 2
table_add ipv4_lpm ipv4_forward 10.1.0.0/16 => 00:01:01:00:00:01 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:02:00:00:01 4
a2-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:03:02:00:01:00 1
table_add ipv4_lpm ipv4_forward 10.0.2.0/24 => 00:03:02:00:02:00 2
table_add ipv4_lpm ipv4_forward 10.1.0.0/16 => 00:01:03:00:00:02 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:04:00:00:02 4
a3-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.1.3.0/24 => 00:03:03:00:03:00 1
table_add ipv4_lpm ipv4_forward 10.1.4.0/24 => 00:03:03:00:04:00 2
table_add ipv4_lpm ipv4_forward 10.0.0.0/16 => 00:01:01:00:00:03 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:02:00:00:03 4
a4-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.1.3.0/24 => 00:03:04:00:03:00 1
table_add ipv4_lpm ipv4_forward 10.1.4.0/24 => 00:03:04:00:04:00 2
table_add ipv4_lpm ipv4_forward 10.0.0.0/16 => 00:01:03:00:00:04 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:04:00:00:04 4
a5-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.2.5.0/24 => 00:03:05:00:05:00 1
table_add ipv4_lpm ipv4_forward 10.2.6.0/24 => 00:03:05:00:06:00 2
table_add ipv4_lpm ipv4_forward 10.3.0.0/16 => 00:01:01:00:00:05 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:02:00:00:05 4
a6-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.2.5.0/24 => 00:03:06:00:05:00 1
table_add ipv4_lpm ipv4_forward 10.2.6.0/24 => 00:03:06:00:06:00 2
table_add ipv4_lpm ipv4_forward 10.3.0.0/16 => 00:01:03:00:00:06 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:04:00:00:06 4
a7-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.3.7.0/24 => 00:03:07:00:07:00 1
table_add ipv4_lpm ipv4_forward 10.3.8.0/24 => 00:03:07:00:08:00 2
table_add ipv4_lpm ipv4_forward 10.2.0.0/16 => 00:01:01:00:00:07 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:02:00:00:07 4
a8-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.3.7.0/24 => 00:03:08:00:07:00 1
table_add ipv4_lpm ipv4_forward 10.3.8.0/24 => 00:03:08:00:08:00 2
table_add ipv4_lpm ipv4_forward 10.2.0.0/16 => 00:01:03:00:00:08 3
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:01:04:00:00:08 4
e1-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.1.1/32 => 00:00:00:01:00:01 3
table_add ipv4_lpm ipv4_forward 10.0.1.2/32 => 00:00:00:01:00:02 4
table_add ipv4_lpm ipv4_forward 10.0.2.0/24 => 00:02:01:00:01:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:02:00:01:00 2
e2-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.0.2.1/32 => 00:00:00:02:00:01 3
table_add ipv4_lpm ipv4_forward 10.0.2.2/32 => 00:00:00:02:00:02 4
table_add ipv4_lpm ipv4_forward 10.0.1.0/24 => 00:02:01:00:02:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:02:00:02:00 2
e3-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.1.3.1/32 => 00:00:01:03:00:01 3
table_add ipv4_lpm ipv4_forward 10.1.3.2/32 => 00:00:01:03:00:02 4
table_add ipv4_lpm ipv4_forward 10.1.4.0/24 => 00:02:03:00:03:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:04:00:03:00 2
e4-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.1.4.1/32 => 00:00:01:04:00:01 3
table_add ipv4_lpm ipv4_forward 10.1.4.2/32 => 00:00:01:04:00:02 4
table_add ipv4_lpm ipv4_forward 10.1.3.0/24 => 00:02:03:00:04:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:04:00:04:00 2
e5-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.2.5.1/32 => 00:00:02:05:00:01 3
table_add ipv4_lpm ipv4_forward 10.2.5.2/32 => 00:00:02:05:00:02 4
table_add ipv4_lpm ipv4_forward 10.2.6.0/24 => 00:02:05:00:05:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:06:00:05:00 2
e6-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.2.6.1/32 => 00:00:02:06:00:01 3
table_add ipv4_lpm ipv4_forward 10.2.6.2/32 => 00:00:02:06:00:02 4
table_add ipv4_lpm ipv4_forward 10.2.5.0/24 => 00:02:05:00:06:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:06:00:06:00 2
e7-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.3.7.1/32 => 00:00:03:07:00:01 3
table_add ipv4_lpm ipv4_forward 10.3.7.2/32 => 00:00:03:07:00:02 4
table_add ipv4_lpm ipv4_forward 10.3.8.0/24 => 00:02:07:00:07:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:08:00:07:00 2
e8-switch:
table_set_default ipv4_lpm drop
table_add ipv4_lpm ipv4_forward 10.3.8.1/32 => 00:00:03:08:00:01 3
table_add ipv4_lpm ipv4_forward 10.3.8.2/32 => 00:00:03:08:00:02 4
table_add ipv4_lpm ipv4_forward 10.3.7.0/24 => 00:02:07:00:08:00 1
table_add ipv4_lpm ipv4_forward 10.0.0.0/8 => 00:02:08:00:08:00 2