having issues on the traceroute

4 views
Skip to first unread message

Md Rackybul Hashan

unread,
Apr 2, 2025, 8:06:18 AMApr 2
to ofswitch13-users
#include "ns3/core-module.h"
#include "ns3/network-module.h"
#include "ns3/internet-module.h"
#include "ns3/ofswitch13-module.h"
#include "ns3/csma-module.h"
#include "ns3/applications-module.h"

using namespace ns3;


static inline struct ofl_match_tlv*
oxm_match_lookup(uint32_t oxm, struct ofl_match *match) {
    struct ofl_match_tlv *tlv;
    HMAP_FOR_EACH (tlv, struct ofl_match_tlv, hmap_node, &match->match_fields) {
        if (ntohl(tlv->header) >> 16 == oxm) {
            return tlv;
        }
    }
    return NULL;
}
class TTLController : public OFSwitch13Controller
{
public:
    static TypeId GetTypeId(void)
    {
        static TypeId tid = TypeId("TTLController")
            .SetParent<OFSwitch13Controller>()
            .AddConstructor<TTLController>();
        return tid;
    }
void InstallFlowRule(Ptr<OFSwitch13Device> swtch)
    {
        std::ostringstream cmd;
        // <<< Fix spot: Correct syntax to "output:controller"
        cmd << "flow-mod cmd=add,table=0 eth_type=0x0800 output:controller";
        DpctlExecute(swtch->GetDatapathId(), cmd.str());
        std::cout << "Installed flow rule: IPv4 packets to controller" << std::endl;
    }
protected:
     void SendIcmpTimeExceeded(Ptr<const RemoteSwitch> swtch, Ptr<Packet> packet, uint32_t inPort) {
        Ipv4Header ipHeader;
        packet->PeekHeader(ipHeader);
        Ipv4Address srcAddr = ipHeader.GetSource();

        Ptr<OFSwitch13Device> switchDev = OFSwitch13Device::GetDevice(swtch->GetDpId());
        Ptr<Node> switchNode = switchDev->GetObject<Node>();
        Ptr<Ipv4> ipv4 = switchNode->GetObject<Ipv4>();
       
        // FIX: Use interface index 0 instead of 1
        Ipv4Address switchIp = ipv4->GetAddress(0, 0).GetLocal(); // <<< Critical fix here

        Icmpv4TimeExceeded icmp;
        icmp.SetData(packet);
        Ptr<Packet> icmpPkt = Create<Packet>();
        icmpPkt->AddHeader(icmp);

        Ipv4Header icmpIpHeader;
        icmpIpHeader.SetSource(switchIp);
        icmpIpHeader.SetDestination(srcAddr);
        icmpIpHeader.SetProtocol(1);
        icmpIpHeader.SetTtl(64);
        icmpIpHeader.SetPayloadSize(icmpPkt->GetSize());
        icmpPkt->AddHeader(icmpIpHeader);

        struct ofl_msg_packet_out outMsg;
        memset(&outMsg, 0, sizeof(outMsg));
        outMsg.header.type = OFPT_PACKET_OUT;
        outMsg.buffer_id = OFP_NO_BUFFER;
        outMsg.in_port = inPort;

        struct ofl_action_output* action = (struct ofl_action_output*)xmalloc(sizeof(struct ofl_action_output));
        action->header.type = OFPAT_OUTPUT;
        action->port = OFPP_CONTROLLER;
        action->max_len = 0;

        outMsg.actions_num = 1;
        outMsg.actions = (struct ofl_action_header**)&action;

        uint8_t* icmpBuffer = new uint8_t[icmpPkt->GetSize()];
        icmpPkt->CopyData(icmpBuffer, icmpPkt->GetSize());
        outMsg.data = icmpBuffer;
        outMsg.data_length = icmpPkt->GetSize();

        SendToSwitch(swtch, (struct ofl_msg_header*)&outMsg, 0);
        delete[] icmpBuffer;
        free(action);
    }

    ofl_err HandlePacketIn(
        struct ofl_msg_packet_in *msg,
        Ptr<const RemoteSwitch> swtch,
        uint32_t xid) override
    {
        Ptr<Packet> packet = Create<Packet>(msg->data, msg->data_length);
        Ipv4Header ipHeader;

        // Extract input port from match fields
        uint32_t inPort = 0;
        struct ofl_match* match = (struct ofl_match*)msg->match;
        struct ofl_match_tlv* tlv = oxm_match_lookup(OFPXMT_OFB_IN_PORT, match);
        if (tlv) {
            inPort = ntohl(*((uint32_t*)tlv->value));
        }

        if (packet->RemoveHeader(ipHeader))
        {
            uint8_t ttl = ipHeader.GetTtl();
            if (ttl <= 1)
            {
                SendIcmpTimeExceeded(swtch, packet, inPort);
                return 0;
            }

            // Decrement TTL and forward
            ipHeader.SetTtl(ttl - 1);
            packet->AddHeader(ipHeader);

            // Simple forwarding logic
            uint32_t outPort = (ipHeader.GetDestination() == Ipv4Address("10.1.1.2")) ? 2 : 1;

            struct ofl_msg_packet_out outMsg;
            memset(&outMsg, 0, sizeof(outMsg));
            outMsg.header.type = OFPT_PACKET_OUT;
            outMsg.buffer_id = OFP_NO_BUFFER;
            outMsg.in_port = inPort;

            struct ofl_action_output* action = (struct ofl_action_output*)xmalloc(sizeof(struct ofl_action_output));
            action->header.type = OFPAT_OUTPUT;
            action->port = outPort;
            action->max_len = 0;

            outMsg.actions_num = 1;
            outMsg.actions = (struct ofl_action_header**)&action;

            uint8_t* buffer = new uint8_t[packet->GetSize()];
            packet->CopyData(buffer, packet->GetSize());
            outMsg.data = buffer;
            outMsg.data_length = packet->GetSize();

            SendToSwitch(swtch, (struct ofl_msg_header*)&outMsg, xid);
            delete[] buffer;
            free(action);
        }
        return 0;
    }
};

class CustomTraceroute : public Application
{
public:
    static TypeId GetTypeId(void)
    {
        static TypeId tid = TypeId("CustomTraceroute")
            .SetParent<Application>()
            .AddConstructor<CustomTraceroute>()
            .AddAttribute("Remote",
                          "Destination address",
                          Ipv4AddressValue(),
                          MakeIpv4AddressAccessor(&CustomTraceroute::m_remote),
                          MakeIpv4AddressChecker())
            .AddAttribute("MaxTtl",
                          "Maximum TTL",
                          UintegerValue(5),
                          MakeUintegerAccessor(&CustomTraceroute::m_maxTtl),
                          MakeUintegerChecker<uint32_t>())
            .AddAttribute("Interval",
                          "Probing interval",
                          TimeValue(Seconds(1)),
                          MakeTimeAccessor(&CustomTraceroute::m_interval),
                          MakeTimeChecker());
        return tid;
    }

    CustomTraceroute() : m_socket(0), m_seq(0) {}
    virtual ~CustomTraceroute() {}

protected:
    virtual void DoDispose(void)
    {
        if (m_socket) m_socket->Close();
        Application::DoDispose();
    }

    virtual void StartApplication(void)
    {
        m_socket = Socket::CreateSocket(GetNode(), TypeId::LookupByName("ns3::Ipv4RawSocketFactory"));
        m_socket->SetAttribute("Protocol", UintegerValue(1)); // ICMP
        m_socket->SetRecvCallback(MakeCallback(&CustomTraceroute::HandleRead, this));
        Simulator::Schedule(Seconds(0), &CustomTraceroute::SendProbe, this, 1);
    }

    virtual void StopApplication(void)
    {
        if (m_socket) m_socket->Close();
    }

private:
    void SendProbe(uint8_t ttl)
    {
        if (ttl > m_maxTtl)
        {
            std::cout << "Traceroute complete" << std::endl;
            return;
        }

        Ptr<Packet> p = Create<Packet>();
        Icmpv4Echo echo;
        echo.SetSequenceNumber(m_seq++);
        echo.SetIdentifier(0);
        p->AddHeader(echo);

        Icmpv4Header icmp;
        icmp.SetType(Icmpv4Header::ICMPV4_ECHO);
        icmp.SetCode(0);
        p->AddHeader(icmp);

        m_socket->SetIpTtl(ttl);
        m_socket->SendTo(p, 0, InetSocketAddress(m_remote, 0));

        std::cout << "Sent probe with TTL=" << (int)ttl << std::endl;
        Simulator::Schedule(m_interval, &CustomTraceroute::SendProbe, this, ttl + 1);
    }

    void HandleRead(Ptr<Socket> socket)
    {
        Ptr<Packet> packet = socket->Recv();
        Ipv4Header ipHeader;
        Icmpv4Header icmpHeader;
        packet->RemoveHeader(ipHeader);
        packet->PeekHeader(icmpHeader);

        if (icmpHeader.GetType() == Icmpv4Header::ICMPV4_TIME_EXCEEDED)
        {
            Icmpv4TimeExceeded timeExceeded;
            packet->RemoveHeader(timeExceeded);
           
            // Extract original IP header from payload
            Ipv4Header originalIpHeader;
            if (packet->PeekHeader(originalIpHeader))
            {
                std::cout << "Hop " << (int)originalIpHeader.GetTtl()
                          << ": " << ipHeader.GetSource()
                          << " (ICMP Time Exceeded)" << std::endl;
            }
        }
        else if (icmpHeader.GetType() == Icmpv4Header::ICMPV4_ECHO_REPLY)
        {
            std::cout << "Destination reached: " << ipHeader.GetSource() << std::endl;
        }
    }

    Ptr<Socket> m_socket;
    Ipv4Address m_remote;
    uint32_t m_maxTtl;
    Time m_interval;
    uint16_t m_seq;
};

int main(int argc, char* argv[])
{
    uint16_t simTime = 10;
    bool verbose = false;
    bool trace = false;

    CommandLine cmd;
    cmd.AddValue("simTime", "Simulation time", simTime);
    cmd.AddValue("verbose", "Enable verbose", verbose);
    cmd.AddValue("trace", "Enable tracing", trace);
    cmd.Parse(argc, argv);

    if (verbose)
    {
        OFSwitch13Helper::EnableDatapathLogs();
        LogComponentEnable("CustomTraceroute", LOG_LEVEL_ALL);
    }

    // Create nodes
    NodeContainer hosts;
    hosts.Create(2);
    Ptr<Node> switchNode = CreateObject<Node>();
    Ptr<Node> controllerNode = CreateObject<Node>();

    // Create CSMA links
    CsmaHelper csmaHelper;
    csmaHelper.SetChannelAttribute("DataRate", StringValue("100Mbps"));
    csmaHelper.SetChannelAttribute("Delay", StringValue("2ms"));

    NetDeviceContainer hostDevices, switchPorts;
    for (uint32_t i = 0; i < hosts.GetN(); i++) {
        NetDeviceContainer link = csmaHelper.Install(NodeContainer(hosts.Get(i), switchNode));
        hostDevices.Add(link.Get(0));
        switchPorts.Add(link.Get(1));
    }

    // Install OpenFlow
   Ptr<OFSwitch13InternalHelper> of13Helper = CreateObject<OFSwitch13InternalHelper>();
    Ptr<TTLController> controller = CreateObject<TTLController>();
    of13Helper->InstallController(controllerNode, controller);
    // <<< Fix spot: Declare switchDevice and assign it
    Ptr<OFSwitch13Device> switchDevice = of13Helper->InstallSwitch(switchNode, switchPorts);
    controller->InstallFlowRule(switchDevice); // Use the declared switchDevice
    of13Helper->CreateOpenFlowChannels();

    // Install internet stack
    InternetStackHelper internet;
    internet.Install(hosts);
    internet.Install(switchNode); // Critical for ICMP generation

    // Assign IP addresses
    Ipv4AddressHelper address;
    address.SetBase("10.1.1.0", "255.255.255.0");
    Ipv4InterfaceContainer hostIfaces = address.Assign(hostDevices);
    Ipv4InterfaceContainer switchIfaces = address.Assign(switchPorts); // Critical for switch IP

    // Install traceroute on host 0
    Ptr<CustomTraceroute> traceroute = CreateObject<CustomTraceroute>();
    traceroute->SetAttribute("Remote", Ipv4AddressValue(hostIfaces.GetAddress(1)));
    hosts.Get(0)->AddApplication(traceroute);
    traceroute->SetStartTime(Seconds(1));
    traceroute->SetStopTime(Seconds(simTime));

    // Enable tracing
    if (trace)
    {
        csmaHelper.EnablePcap("host", hostDevices);
        csmaHelper.EnablePcap("switch", switchPorts);
    }

    Simulator::Stop(Seconds(simTime));
    Simulator::Run();
    Simulator::Destroy();
    return 0;
} hi im new user of the ns3 and sdn i needs to traceroute to intermediate routing nodes between the host but im getting this error  0$  ./ns3 run scratch/t1
[0/2] Re-checking globbed directories...
[2/2] Linking CXX executable ../build/scratch/ns3.40-t1-default
Installed flow rule: IPv4 packets to controller
Error parsing instruction: output:controller.
Command 'build/scratch/ns3.40-t1-default' returned non-zero exit status 1.
Reply all
Reply to author
Forward
0 new messages