NS4: A P4-drien Network Simulator (NS3)
Please follow the instructions in https://github.com/kphf1995cm/ns4-install and https://github.com/p4db/NS4-DEV to install NS4.
[Topology]
N0(10.1.1.1, 00:00:00:00:00:01)---------(port 0)P4switch(port 1)-----N1(10.1.1.2, 00:00:00:00:00:03)
We will implement the MAC layer Forwarding in P4switch. It means that the packets with MAC addr=00:00:00:00:00:01 will be forwarded to port 0 and the packets with MAC addr=00:00:00:00:00:03 will be forwarded to port 1.
l2_switch.p4
header_type ethernet_t { fields { dstAddr : 48; srcAddr : 48; etherType : 16; } }
header ethernet_t ethernet;
parser start { return parse_ethernet; }
parser parse_ethernet { extract(ethernet); return ingress; }
action _drop() { drop(); }
action forward(port) { modify_field(standard_metadata.egress_spec, port); }
table dmac { reads { ethernet.dstAddr : exact; } actions { forward; _drop; } size : 512; }
control ingress { apply(dmac); }
control egress { } |
commands.txt
table_set_default dmac _drop table_add dmac forward 0x000000000001 => 0 table_add dmac forward 0x000000000003 => 1 |
mtype.txt
dmac exact |
readme.txt
|
Put these files under ns-allinone-2.27/ns-2.27/src/ns4/test/l2_switch
Compile the l2_switch.p4 to get l2_switch.json
Modify global.cc and global.h under model folder
global.cc
# include "ns3/log.h" # include "ns3/global.h" namespace ns3 { NS_LOG_COMPONENT_DEFINE("P4GlobalVar"); NS_OBJECT_ENSURE_REGISTERED(P4GlobalVar); // init default static global variable unsigned int P4GlobalVar::g_networkFunc=ROUTER; std::string P4GlobalVar::g_flowTablePath=""; std::string P4GlobalVar::g_p4MatchTypePath=""; unsigned int P4GlobalVar::g_populateFlowTableWay=LOCAL_CALL; std::string P4GlobalVar::g_p4JsonPath="";
std::string
P4GlobalVar::g_homePath="/home/user/ns4-install/"; std::string
P4GlobalVar::g_ns3RootName="ns-allinone-3.27/"; std::string
P4GlobalVar::g_ns3SrcName="ns-3.27/"; std::string P4GlobalVar::g_nfDir=P4GlobalVar::g_homePath+P4GlobalVar::g_ns3RootName+P4GlobalVar::g_ns3SrcName+"src/ns4/test/"; std::string P4GlobalVar::g_topoDir=P4GlobalVar::g_homePath+P4GlobalVar::g_ns3RootName+P4GlobalVar::g_ns3SrcName+"src/ns4/topo/"; std::string P4GlobalVar::g_flowTableDir=P4GlobalVar::g_homePath+P4GlobalVar::g_ns3RootName+P4GlobalVar::g_ns3SrcName+"src/ns4/flowtable/"; unsigned int P4GlobalVar::g_nsType=NS4; unsigned int P4GlobalVar::g_runtimeCliTime=10; std::map<std::string,unsigned int> P4GlobalVar::g_nfStrUintMap; unsigned long getTickCount(void) { unsigned long currentTime=0; #ifdef WIN32 currentTime = GetTickCount(); #endif struct timeval current; gettimeofday(¤t, NULL); currentTime = current.tv_sec * 1000 + current.tv_usec / 1000; #ifdef OS_VXWORKS ULONGA timeSecond = tickGet() / sysClkRateGet(); ULONGA timeMilsec = tickGet() % sysClkRateGet() * 1000 / sysClkRateGet(); currentTime = timeSecond * 1000 + timeMilsec; #endif return currentTime; } void P4GlobalVar::SetP4MatchTypeJsonPath() { if(P4GlobalVar::g_networkFunc==FIREWALL) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"firewall/firewall.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "firewall/mtype.txt"; } if(P4GlobalVar::g_networkFunc==SILKROAD) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"silkroad/silkroad.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "silkroad/mtype.txt"; } if(P4GlobalVar::g_networkFunc==ROUTER) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"router/router.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "router/mtype.txt"; } if(P4GlobalVar::g_networkFunc==SIMPLE_ROUTER) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"simple_router/simple_router.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "simple_router/mtype.txt"; } if(P4GlobalVar::g_networkFunc==COUNTER) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"counter/counter.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "counter/mtype.txt"; } if(P4GlobalVar::g_networkFunc==METER) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"meter/meter.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "meter/mtype.txt"; } if(P4GlobalVar::g_networkFunc==REGISTER) { P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"register/register.json"; P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir + "register/mtype.txt"; } if(P4GlobalVar::g_networkFunc==L2_SWITCH) {
P4GlobalVar::g_p4JsonPath=P4GlobalVar::g_nfDir+"l2_switch/l2_switch.json";
P4GlobalVar::g_p4MatchTypePath=P4GlobalVar::g_nfDir +
"l2_switch/mtype.txt"; } } void P4GlobalVar::InitNfStrUintMap() { P4GlobalVar::g_nfStrUintMap["ROUTER"]=ROUTER; P4GlobalVar::g_nfStrUintMap["SIMPLE_ROUTER"]=SIMPLE_ROUTER; P4GlobalVar::g_nfStrUintMap["FIREWALL"]=FIREWALL; P4GlobalVar::g_nfStrUintMap["SILKROAD"]=SILKROAD; P4GlobalVar::g_nfStrUintMap["COUNTER"]=COUNTER; P4GlobalVar::g_nfStrUintMap["METER"]=METER; P4GlobalVar::g_nfStrUintMap["REGISTER"]=REGISTER; P4GlobalVar::g_nfStrUintMap["l2_SWITCH"]=L2_SWITCH; } TypeId P4GlobalVar::GetTypeId(void) { static TypeId tid = TypeId("ns3::P4GlobalVar") .SetParent<Object>() .SetGroupName("P4GlobalVar") ; return tid; } P4GlobalVar::P4GlobalVar() { NS_LOG_FUNCTION(this); } P4GlobalVar::~P4GlobalVar() { NS_LOG_FUNCTION(this); } } |
global.h
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) YEAR COPYRIGHTHOLDER * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: PengKuang <kphf1995cm@outlook.com> */ #ifndef GLOBAL_H #define GLOBAL_H #include <cstring> #include <map> #include "ns3/object.h" #include <sys/time.h> namespace ns3 { #define LOCAL_CALL 0 #define RUNTIME_CLI 1 #define NS3 1 #define NS4 0 // nf info unsigned const int ROUTER = 0; unsigned const int FIREWALL = 1; unsigned const int SILKROAD = 2; unsigned const int SIMPLE_ROUTER = 3; unsigned const int COUNTER = 4; unsigned const int METER = 5; unsigned const int REGISTER = 6; unsigned const int
L2_SWITCH = 7; // match type unsigned const int EXACT = 0; unsigned const int LPM = 1; unsigned const int TERNARY = 2; unsigned const int VALID = 3; unsigned const int RANGE = 4; //get current time (ms) unsigned long getTickCount(void); class P4GlobalVar : public Object { public: static TypeId GetTypeId(void); // siwtch info static unsigned int g_networkFunc; static std::string g_p4MatchTypePath; static std::string g_flowTablePath; static std::string g_p4JsonPath; static unsigned int g_populateFlowTableWay; // path info static std::string g_homePath; static std::string g_ns3RootName; static std::string g_ns3SrcName; static unsigned int g_nsType; static std::string g_nfDir; static std::string g_topoDir; static std::string g_flowTableDir; // runtime CLI wait time static unsigned int g_runtimeCliTime;//s static std::map<std::string,unsigned int> g_nfStrUintMap; //set g_p4MatchTypePath,g_p4JsonPath according to g_networkFunc static void SetP4MatchTypeJsonPath(); static void InitNfStrUintMap(); private: P4GlobalVar(); ~P4GlobalVar(); P4GlobalVar(const P4GlobalVar&); P4GlobalVar& operator= (const P4GlobalVar&); }; } #endif /*GLOBAL_H*/ |
test-p4.cc (put this file under scratch)
#include <iostream> #include <fstream> #include <string> #include <cassert> #include <unistd.h> #include <sys/time.h> #include <netinet/in.h> #include <unordered_map> #include "ns3/core-module.h" #include "ns3/network-module.h" #include "ns3/applications-module.h" #include "ns3/csma-module.h" #include "ns3/internet-module.h" #include "ns3/p4-helper.h" #include "ns3/v4ping-helper.h" #include "ns3/global.h" #include <bm/SimpleSwitch.h> #include <bm/bm_runtime/bm_runtime.h> #include <bm/bm_sim/target_parser.h> using namespace ns3; NS_LOG_COMPONENT_DEFINE ("P4Test"); int main (int argc, char *argv[]) { LogComponentEnable ("P4Test", LOG_LEVEL_LOGIC); LogComponentEnable ("P4Helper", LOG_LEVEL_LOGIC); LogComponentEnable ("P4NetDevice", LOG_LEVEL_LOGIC); // Initialize global variable // P4GlobalVar::g_homePath
= "/home/user/ns4-install/"; P4GlobalVar::g_ns3RootName
= "ns-allinone-3.27/"; P4GlobalVar::g_ns3SrcName
= "ns-3.27/"; P4GlobalVar::g_nfDir =
P4GlobalVar::g_homePath + P4GlobalVar::g_ns3RootName +
P4GlobalVar::g_ns3SrcName + "src/ns4/test/"; P4GlobalVar::g_nsType=NS4;
P4GlobalVar::g_runtimeCliTime = 100; CommandLine cmd; cmd.Parse (argc, argv); NS_LOG_INFO ("Create nodes."); NodeContainer nodes; nodes.Create(2); NodeContainer csmaSwitch; csmaSwitch.Create(1); NS_LOG_INFO ("Build Topology"); CsmaHelper csma; csma.SetChannelAttribute ("DataRate", DataRateValue (5000000)); csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2))); NetDeviceContainer terminalDevices; NetDeviceContainer switchDevices; for (int i = 0; i < 2; i ++) { NetDeviceContainer link = csma.Install(NodeContainer(nodes.Get(i), csmaSwitch.Get(0))); terminalDevices.Add(link.Get(0)); switchDevices.Add(link.Get(1)); } Ptr<Node> switchNode = csmaSwitch.Get(0); if (P4GlobalVar::g_nsType==NS4) //ns4 mode { P4GlobalVar::g_populateFlowTableWay=LOCAL_CALL;//LOCAL_CALL
RUNTIME_CLI
P4GlobalVar::g_networkFunc=L2_SWITCH;
P4GlobalVar::SetP4MatchTypeJsonPath();
P4GlobalVar::g_flowTablePath=P4GlobalVar::g_nfDir+"l2_switch/commands.txt"; P4Helper bridge; NS_LOG_INFO("P4 bridge established"); bridge.Install (switchNode, switchDevices); } else { //ns3 mode BridgeHelper bridge; bridge.Install (switchNode, switchDevices); } InternetStackHelper internet; internet.Install (nodes); Ipv4AddressHelper ipv4; ipv4.SetBase ("10.1.1.0", "255.255.255.0"); Ipv4InterfaceContainer addresses = ipv4.Assign(terminalDevices); //we use static arp. No ARP packets will be sent. Ptr<ArpCache> arp =
CreateObject<ArpCache>();
arp->SetAliveTimeout(Seconds(3600 * 24 * 365)); ArpCache::Entry * entry =
arp->Add(Ipv4Address ("10.1.1.1"));
entry->SetMacAddress(Mac48Address("00:00:00:00:00:01")); entry->MarkPermanent();
std::pair<Ptr<Ipv4>, uint32_t> returnValue =
addresses.Get(1); Ptr<Ipv4> myipv4 =
returnValue.first; uint32_t index =
returnValue.second; Ptr<Ipv4Interface>
iface =
myipv4->GetObject<Ipv4L3Protocol> ()->GetInterface
(index);
iface->SetAttribute("ArpCache", PointerValue(arp)); arp =
CreateObject<ArpCache>(); arp->SetAliveTimeout(Seconds(3600
* 24 * 365)); entry =
arp->Add(Ipv4Address ("10.1.1.2"));
entry->SetMacAddress(Mac48Address("00:00:00:00:00:03")); entry->MarkPermanent(); returnValue =
addresses.Get(0); myipv4 =
returnValue.first; index = returnValue.second; iface =
myipv4->GetObject<Ipv4L3Protocol> ()->GetInterface
(index);
iface->SetAttribute("ArpCache", PointerValue(arp)); // Create Applications NS_LOG_INFO ("Create Applications."); V4PingHelper pingHelper = V4PingHelper (addresses.GetAddress(1)); pingHelper.SetAttribute ("Verbose", BooleanValue (true)); ApplicationContainer pingApps = pingHelper.Install (nodes.Get(0)); pingApps.Start (Seconds (1)); Packet::EnablePrinting (); Simulator::Stop (Seconds (3)); Simulator::Run (); Simulator::Destroy (); return 0; } |
Execution
Last
Modified: 2022/2/28 done
[Author]
Dr. Chih-Heng Ke
Department of Computer
Science and Information Engineering, National Quemoy University, Kinmen,
Taiwan
Email: smallko@gmail.com