// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"
#include <stdint.h>
__attribute__((__always_inline__))
static inline __u16 csum_fold_helper(__u64 csum) {
int i;
#pragma unroll
for (i = 0; i < 4; i++) {
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
__attribute__((__always_inline__))
static inline void ipv4_csum(void* data_start, int data_size, __u64* csum) {
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
__attribute__((__always_inline__))
static inline void ipv4_l4_csum(void* data_start, __u32 data_size,
__u64* csum, struct iphdr* iph) {
__u32 tmp = 0;
*csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
*csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
tmp = __builtin_bswap32((__u32)(iph->protocol));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
tmp = __builtin_bswap32((__u32)(data_size));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md* ctx)
{
void* data_end = (void*)(long)ctx->data_end;
void* data = (void*)(long)ctx->data;
struct ethhdr* eth = data;
if (data + sizeof(*eth) > data_end) {
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP)) {
struct iphdr* iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end) {
return XDP_PASS;
}
if (iph->protocol != IPPROTO_TCP) {
return XDP_PASS;
}
struct tcphdr* tcph = data + sizeof(*eth) + sizeof(*iph);
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end) {
return XDP_PASS;
}
__u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);
if (tcp_len > 2000) {
return XDP_DROP;
}
if (tcph->dest == htons(65535)) {
unsigned char gateway[ETH_ALEN];
gateway[0] = 0x92; gateway[1] = 0x10;
gateway[2] = 0x95; gateway[3] = 0x86;
gateway[4] = 0x26; gateway[5] = 0xbf;
__builtin_memcpy(eth->h_source, eth->h_dest, ETH_ALEN);
__builtin_memcpy(eth->h_dest, gateway, ETH_ALEN);
bpf_debug("MAC Source: %i:%i:%i", eth->h_source[0], eth->h_source[1], eth->h_source[2]);
bpf_debug("%i:%i:%i\n", eth->h_source[3], eth->h_source[4], eth->h_source[5]);
bpf_debug("MAC Destin: %i:%i:%i", eth->h_dest[0], eth->h_dest[1], eth->h_dest[2]);
bpf_debug("%i:%i:%i\n", eth->h_dest[3], eth->h_dest[4], eth->h_dest[5]);
iph->saddr = iph->daddr;
iph->daddr = htonl(4266428307);
__u64 csum = 0;
iph->check = 0;
ipv4_csum(iph, sizeof(struct iphdr), &csum);
iph->check = csum;
csum = 0;
tcph->check = 0;
ipv4_l4_csum(tcph, tcp_len, &csum, iph);
tcph->check = csum;
bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);
return XDP_TX;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
Strangely I'm not receiving TCP packets on my destination server *(147.135.76.254 | 4266428307), and also on the local server the packet doesn't appear in tcpdump -i eth0 dst port 65535
Am I doing something wrong? If yes, how can I fix the code.
The purpose is: Receive packet on server port LOCAL:65535, and redirect to DESTINATION:65535
Updates:
The program seems to work correctly, I'm getting the message "Received!" in cat /sys/kernel/debug/tracing/trace_pipe
The packet did not reach the destination server
In the destination server (Windows), i'm running Wireshark with TCP Checksum verification disabled, this means that there is no filter in the middle that prevents packets with invalid checksum, example:
On source server (linux), i send hping3 147.135.76.254 -p 65535 --
badcksum and receive all packets (with invalid checksums) in wireshark (dest server)
In source server (XDP), when i execute: tcpdump -i eth0 tcp port 65535, i'm not receiving any packets.
Note: I used ethtool -K eth0 tx off to disable offload / chksum
If i change XDP_TX to XDP_PASS i can receive this packet in tcpdump (command above):
14:38:10.964195 IP d2-2-us-east-va-1.39698 > 147.135.76.254.65535: Flags [S], seq 3962643128, win 14600, options [mss 1460,sackOK,TS val 2414158903 ecr 0,nop,wscale 9], length 0
In ethtool -S eth0 shows rx/tx correctly
If i change from "XDP_TX" to "XDP_PASS" i receive this response in tcpdump: 135.148.232.155.58062 > 147.135.76.254.65535: Flags [S], cksum 0x41c3 (correct), seq 2996104997, win 14600, options [mss 1460,sackOK,TS val 2614058020 ecr 0,nop,wscale 9], length 0, that means my TCP Checksum & IP Calculation is working correcly
I updated informing the MAC Address correctly and the problem continues.
The commands executed:
[root#d2-2-us-east-va-1 ~]# arp -a
_gateway (135.148.232.1) at 92:10:95:86:26:bf [ether] on eth0
[root#d2-2-us-east-va-1 ~]# cat /sys/class/net/eth0/address
fa:16:3e:0e:cf:a4
[root#d2-2-us-east-va-1 ~]# ifconfig
... (to confirm mac address)
You are not updating the source and destination MAC addresses of the ethernet layer. Some NICs especially virtualized ones will drop outgoing packets if the source MAC does not match the configured MAC of the NIC.
If you are reflecting the packets back to the same physical machine on your local network(local machine or router/default gateway) you can simply swap the src and dst addresses.
I updated your code to add this:
// SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
// Copyright (c) 2018 Netronome Systems, Inc.
#define BPF_NO_GLOBAL_DATA
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include <linux/bpf.h>
#include <linux/icmp.h>
#include <linux/if_ether.h>
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
#include <endian.h>
#include "bpf_endian.h"
#include "bpf_helpers.h"
#include "jhash.h"
#include "common.h"
#include "parsing_helpers.h"
#include <stdint.h>
__attribute__((__always_inline__)) static inline __u16 csum_fold_helper(__u64 csum)
{
int i;
#pragma unroll
for (i = 0; i < 4; i++)
{
if (csum >> 16)
csum = (csum & 0xffff) + (csum >> 16);
}
return ~csum;
}
__attribute__((__always_inline__)) static inline void ipv4_csum(void *data_start, int data_size, __u64 *csum)
{
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
__attribute__((__always_inline__)) static inline void ipv4_l4_csum(void *data_start, __u32 data_size,
__u64 *csum, struct iphdr *iph)
{
__u32 tmp = 0;
*csum = bpf_csum_diff(0, 0, &iph->saddr, sizeof(__be32), *csum);
*csum = bpf_csum_diff(0, 0, &iph->daddr, sizeof(__be32), *csum);
tmp = __builtin_bswap32((__u32)(iph->protocol));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
tmp = __builtin_bswap32((__u32)(data_size));
*csum = bpf_csum_diff(0, 0, &tmp, sizeof(__u32), *csum);
*csum = bpf_csum_diff(0, 0, data_start, data_size, *csum);
*csum = csum_fold_helper(*csum);
}
SEC("prog")
int xdp_drop_benchmark_traffic(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
if (data + sizeof(*eth) > data_end)
{
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP))
{
struct iphdr *iph = data + sizeof(*eth);
if (data + sizeof(*eth) + sizeof(*iph) > data_end)
{
return XDP_PASS;
}
if (iph->protocol != IPPROTO_TCP)
{
return XDP_PASS;
}
struct tcphdr *tcph = data + sizeof(*eth) + sizeof(*iph);
if (data + sizeof(*eth) + sizeof(*iph) + sizeof(*tcph) > data_end)
{
return XDP_PASS;
}
__u16 tcp_len = htons(iph->tot_len) - (iph->ihl << 2);
if (tcp_len > 2000)
{
return XDP_DROP;
}
if (tcph->dest == htons(65535))
{
bpf_debug("Checksum Old: %i | %i\n", iph->check, tcph->check);
unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);
iph->saddr = iph->daddr;
iph->daddr = htonl(4266428307);
__u64 csum = 0;
iph->check = 0;
ipv4_csum(iph, sizeof(struct iphdr), &csum);
iph->check = csum;
csum = 0;
tcph->check = 0;
ipv4_l4_csum(tcph, tcp_len, &csum, iph);
tcph->check = csum;
bpf_debug("Checksum New: %i | %i\n", iph->check, tcph->check);
return XDP_TX;
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
The changed lines being:
unsigned char tmp[ETH_ALEN];
__builtin_memcpy(tmp, eth->h_source, ETH_ALEN);
__builtin_memcpy(eth->h_source, eth->h_dest ETH_ALEN);
__builtin_memcpy(eth->h_dest, tmp);
Please note that the this does not work if you are switching the packet(sending it to a different physical device) in which case you need to use ARP to get the correct MAC or hardcode it.
Related
In my project,
I implement a new class called myApp which inherits from ApplicationBase and UdpSocket classes. When I build my project I get no error, but when I debug C/C++ application with the IDE, it displays the first error in errors section. And the command line display the second error when I run make :
Code of myApp.ned, myApp.h and myApp.cc in what follows :
I did include inet library in project references, and I tried the solution posted in The following NED types could not be fully resolved, due to a missing base type or interface.
import inet.applications.contract.IApp;
simple myApp like IApp
{
parameters:
int localPort = default(-1); // local UDP port number (-1: use ephemeral port)
int destPort; // remote UDP port number
string packetName = default("myApp");
string interfaceTableModule; // The path to the InterfaceTable module
double helloInterval #unit(s) = default(5s); // how often hello messages should be sent out
volatile double sendInterval #unit(s); // should usually be a random value, e.g. exponential(1)
double startTime #unit(s) = default(this.sendInterval); // application start time (start of the first packet)
double stopTime #unit(s) = default(-1s); // time of finishing sending, -1s means forever
double maxVariance = default(1); // This is the maximum of a random value to determine when the first hello message will be sent out
volatile double broadcastDelay #unit(s) = default(uniform(0s,0.01s));
int timeToLive = default(-1); // if not -1, set the TTL (IPv4) or Hop Limit (IPv6) field of sent packets to this value
bool dontFragment = default(false); // if true, asks IP to not fragment the message during routing
int typeOfService = default(-1); // if not -1, set the ToS (IPv4) or Traffic Class (IPv6) field of sent packets to this value
string multicastInterface = default(""); // if not empty, set the multicast output interface option on the socket (interface name expected)
bool receiveBroadcast = default(false); // if true, makes the socket receive broadcast packets
bool joinLocalMulticastGroups = default(false); // if true, makes the socket receive packets from all multicast groups set on local interfaces
#class(myApp);
gates:
input socketIn #labels(UdpControlInfo/up);
output socketOut #labels(UdpControlInfo/down);
}
#ifndef MYAPP_H_
#define MYAPP_H_
#include "inet/common/INETDefs.h"
#include "inet/applications/base/ApplicationBase.h"
#include "inet/transportlayer/contract/udp/UdpSocket.h"
#include "inet/transportlayer/contract/udp/UdpControlInfo_m.h"
#include "inet/common/ModuleAccess.h"
#include "inet/common/TimeTag_m.h"
#include "inet/common/packet/Packet.h"
#include "inet/common/lifecycle/ModuleOperations.h"
#include "inet/common/IProtocolRegistrationListener.h"
#include "inet/common/ProtocolTag_m.h"
#include "inet/linklayer/common/InterfaceTag_m.h"
#include "inet/networklayer/contract/IInterfaceTable.h"
#include "inet/networklayer/contract/ipv4/Ipv4Address.h"
#include "inet/networklayer/ipv4/IIpv4RoutingTable.h"
#include "inet/networklayer/ipv4/Ipv4Header_m.h"
#include "inet/networklayer/ipv4/Ipv4InterfaceData.h"
#include "inet/networklayer/common/FragmentationTag_m.h"
#include "inet/networklayer/common/L3AddressResolver.h"
#include "HelloMsg_m.h"
#include "XedMsg_m.h"
#include <omnetpp.h>
#include <vector>
#include <random>
#include <algorithm>
using namespace omnetpp;
using namespace inet;
using namespace std;
class myApp : public ApplicationBase, public UdpSocket::ICallback
{
protected:
//enum SelfMsgKinds { START = 1, SEND, STOP };
int localPort = -1, destPort = -1;
bool dontFragment = false;
const char *packetName = nullptr;
simtime_t startTime;
simtime_t stopTime;
// state
UdpSocket socket;
cMessage *selfMsg = nullptr;
cModule *host = nullptr;
cMessage *event = nullptr;
cPar *broadcastDelay = nullptr;
unsigned int sequencenumber = 0;
simtime_t helloInterval;
IInterfaceTable *ift = nullptr;
InterfaceEntry *interface80211ptr = nullptr;
int interfaceId = -1;
list<L3Address> neighbors;
Ipv4Address source;
/********** XED **********/
class XED
{
public:
L3Address originatorAddr, destinationAddr;
unsigned int random;
XED(const L3Address& originatorAddr, const L3Address& destinationAddr, unsigned int random)
: originatorAddr(originatorAddr), destinationAddr(destinationAddr), random(random) {};
bool operator==(const XED& other) const
{
return this->originatorAddr == other.originatorAddr && this->destinationAddr == other.destinationAddr
&& this->random == other.random;
}
};
list<XED> lr,ls;
/********** MTLSD **********/
class MTLSD
{
public:
L3Address originatorAddr, destinationAddr;
char *position;
simtime_t time;
MTLSD(const L3Address& originatorAddr, const L3Address& destinationAddr, char *position, simtime_t time)
: originatorAddr(originatorAddr), destinationAddr(destinationAddr), position(position), time(time) {};
bool operator==(const MTLSD& other) const
{
return this->originatorAddr == other.originatorAddr && this->destinationAddr == other.destinationAddr
&& this->position == other.position && this->time == time;
}
};
protected:
virtual int numInitStages() const override { return NUM_INIT_STAGES; }
virtual void initialize(int stage) override;
virtual void handleMessageWhenUp(cMessage *msg) override;
void handleSelfMessage(cMessage *msg);
/*virtual void processStart();
virtual void processSend();
virtual void processStop();*/
// lifecycle
virtual void handleStartOperation(LifecycleOperation *operation) override { start(); }
virtual void handleStopOperation(LifecycleOperation *operation) override { stop(); }
virtual void handleCrashOperation(LifecycleOperation *operation) override { stop(); }
void start();
void stop();
virtual void socketDataArrived(UdpSocket *socket, Packet *packet) override;
virtual void socketErrorArrived(UdpSocket *socket, Indication *indication) override;
virtual void socketClosed(UdpSocket *socket) override;
//virtual void generateMTLSDPacket();
//virtual Packet *generateXEDPacket();
virtual double generateRandom();
public:
myApp() {}
~myApp();
};
#endif /* MYAPP_H_ */
#include "myApp.h"
#include "inet/applications/base/ApplicationPacket_m.h"
#include "inet/applications/udpapp/UdpBasicApp.h"
#include "inet/common/TagBase_m.h"
#include "inet/networklayer/common/L3AddressTag_m.h"
#include <iterator>
using namespace std;
Define_Module(myApp);
myApp::~myApp()
{
EV << "App destructor" << endl;
cancelAndDelete(selfMsg);
}
void myApp::initialize(int stage)
{
ApplicationBase::initialize(stage);
if (stage == INITSTAGE_LOCAL)
{
sequencenumber = 0;
ift = getModuleFromPar<IInterfaceTable>(par("interfaceTableModule"), this);
event = new cMessage("event");
broadcastDelay = &par("broadcastDelay");
helloInterval = par("helloInterval");
localPort = par("localPort");
destPort = par("destPort");
packetName = par("packetName");
startTime = par("startTime");
stopTime = par("stopTime");
}
else if (stage == INITSTAGE_ROUTING_PROTOCOLS)
{
registerService(Protocol::manet, nullptr, gate("socketIn"));
registerProtocol(Protocol::manet, gate("socketOut"), nullptr);
}
}
void myApp::handleSelfMessage(cMessage *msg)
{
if (msg == event)
{
auto hello = makeShared<HelloMsg>();
Ipv4Address source = (interface80211ptr->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
hello->setChunkLength(b(128));
hello->setSrcAddress(source);
sequencenumber += 2;
hello->setSequencenumber(sequencenumber);
hello->setNextAddress(source);
hello->setHopdistance(1);
auto packet = new Packet("Hello", hello);
packet->addTagIfAbsent<L3AddressReq>()->setDestAddress(Ipv4Address(255, 255, 255, 255));
packet->addTagIfAbsent<L3AddressReq>()->setSrcAddress(source);
packet->addTagIfAbsent<InterfaceReq>()->setInterfaceId(interface80211ptr->getInterfaceId());
packet->addTagIfAbsent<PacketProtocolTag>()->setProtocol(&Protocol::manet);
packet->addTagIfAbsent<DispatchProtocolReq>()->setProtocol(&Protocol::ipv4);
send(packet, "socketOut");
packet = nullptr;
hello = nullptr;
scheduleAt(simTime()+helloInterval+broadcastDelay->doubleValue(), event);
}
}
void myApp::handleMessageWhenUp(cMessage *msg)
{
if (msg->isSelfMessage())
{
handleSelfMessage(msg);
}
else if (check_and_cast<Packet *>(msg)->getTag<PacketProtocolTag>()->getProtocol() == &Protocol::manet)
{
auto recHello = staticPtrCast<HelloMsg>(check_and_cast<Packet *>(msg)->peekData<HelloMsg>()->dupShared());
if (msg->arrivedOn("socketIn"))
{
bubble("Received hello message");
Ipv4Address source = interface80211ptr->getProtocolData<Ipv4InterfaceData>()->getIPAddress();
Ipv4Address src;
unsigned int msgsequencenumber;
int numHops;
Ipv4Address next;
src = recHello->getSrcAddress();
msgsequencenumber = recHello->getSequencenumber();
next = recHello->getNextAddress();
numHops = recHello->getHopdistance();
if (src == source)
{
EV_INFO << "Hello msg dropped. This message returned to the original creator.\n";
delete msg;
return;
}
else
{
neighbors.push_back(src);
/*list<XED>::iterator findIter = find(ls.begin()->destinationAddr, ls.end()->destinationAddr, src);
if (findIter != ls.end()->destinationAddr)
{
}*/
source = (interface80211ptr->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
//socket.bind(source, localPort);
auto xed = makeShared<XedMsg>();
xed->setChunkLength(b(128)); ///size of XED message in bits
xed->setSrcAddress(source);
xed->setDstAddress(src);
double random = generateRandom();
xed->setRandom(random);
//XED item = XED(source, src, random);
//ls.push_back(item);
auto packet = new Packet("XED", xed);
packet->addTagIfAbsent<L3AddressReq>()->setDestAddress(src);
packet->addTagIfAbsent<L3AddressReq>()->setSrcAddress(source);
packet->addTagIfAbsent<InterfaceReq>()->setInterfaceId(interfaceId);
packet->addTagIfAbsent<PacketProtocolTag>()->setProtocol(&Protocol::ipv4);
packet->addTagIfAbsent<DispatchProtocolReq>()->setProtocol(&Protocol::ipv4);
socket.setOutputGate(gate("socketOut"));
socket.setCallback(this);
socket.bind(source, localPort);
//emit(packetSentSignal, packet);
socket.sendTo(packet, src, destPort);
//send(packet, "socketOut");
packet = nullptr;
xed = nullptr;
/*Ipv4Address source = (interface80211ptr->getProtocolData<Ipv4InterfaceData>()->getIPAddress());
EV << "I am node " << source << ", my neighbors are : " << endl;
list<L3Address>::iterator it;
for (it = neighbors.begin(); it != neighbors.end(); ++it)
{
EV << it. << endl;
}
for (auto const& i : neighbors)
{
EV << i.str() << endl;
}*/
EV << "I am your neighbor " << src.str();
}
delete msg;
}
else if (check_and_cast<Packet *>(msg)->getTag<PacketProtocolTag>()->getProtocol() == &Protocol::ipv4)
{
EV << "Xed message received" << endl;
//auto recXed = staticPtrCast<XedMsg>(check_and_cast<Packet *>(msg)->peekData<XedMsg>()->dupShared());
}
else
throw cRuntimeError("Message arrived on unknown gate %s", msg->getArrivalGate()->getName());
}
}
void myApp::start()
{
/*socket.setOutputGate(gate("socketOut"));
socket.setCallback(this);*/
int num_80211 = 0;
InterfaceEntry *ie;
InterfaceEntry *i_face;
const char *name;
for (int i = 0; i < ift->getNumInterfaces(); i++)
{
ie = ift->getInterface(i);
name = ie->getInterfaceName();
if (strstr(name, "wlan") != nullptr)
{
i_face = ie;
num_80211++;
interfaceId = i;
}
}
if (num_80211 == 1)
{
interface80211ptr = i_face;
interfaceId = interface80211ptr->getInterfaceId();
}
else
throw cRuntimeError("Node has found %i 80211 interfaces", num_80211);
scheduleAt(simTime() + uniform(0.0, par("maxVariance").doubleValue()), event);
}
double myApp::generateRandom()
{
double lower_bound = 10000;
double upper_bound = 100000;
uniform_real_distribution<double> unif(lower_bound,upper_bound);
default_random_engine re;
double a_random_double = unif(re);
return a_random_double;
}
void myApp::stop()
{
cancelEvent(event);
socket.close();
delayActiveOperationFinish(par("stopOperationTimeout"));
}
void myApp::socketDataArrived(UdpSocket *socket, Packet *packet)
{
emit(packetReceivedSignal, packet);
EV_INFO << "Received packet: " << UdpSocket::getReceivedPacketInfo(packet) << endl;
}
void myApp::socketErrorArrived(UdpSocket *socket, Indication *indication)
{
EV_WARN << "Ignoring UDP error report " << indication->getName() << endl;
delete indication;
}
void myApp::socketClosed(UdpSocket *socket)
{
if (operationalState == State::STOPPING_OPERATION)
startActiveOperationExtraTimeOrFinish(par("stopOperationExtraTime"));
}
Error: NED type 'myApp' could not be fully resolved due to a missing base type or interface, at /home/bocuhra/Downloads/omnetpp-5.4.1/samples/SaaS/myApp.ned:18
myApp.cc
HelloMsg_m.cc
XedMsg_m.cc
Creating executable: out/gcc-release//SaaS
/usr/bin/ld: cannot find -lINET
collect2: error: ld returned 1 exit status
Makefile:104: recipe for target 'out/gcc-release//SaaS' failed
make: *** [out/gcc-release//SaaS] Error 1
I did solve the problem by adding all ned files in my .ini file.
ned-path = .;../inet/src/inet
I have encountered a problem of high memory usage when using ParseFromZeroCopyStream to load file in which a large buffer is written. Besides, the code snippet below uses 60Gb++ of RAM but failed as the system froze after reaching its RAM limit.
FYI, I am using protobuf as DLL.
scene.proto
syntax = "proto3";
package Recipe;
option cc_enable_arenas = true;
message Scene
{
repeated int32 image_data = 1 [packed=true];
}
source.cpp
#include <iostream>
#include <fstream>
#include <ostream>
#include <istream>
#include <string>
#include <cstdint>
#include "Scene.pb.h"
#include <google\protobuf\io\zero_copy_stream_impl.h>
#include <google\protobuf\io\gzip_stream.h>
#include <google\protobuf\arena.h>
int const _MIN = 0;
int const _MAX = 255;
unsigned int const _SIZE = 1280000000;
//unsigned int const _SIZE = 2000;
unsigned int const _COMPRESSION_LEVEL = 6;
void randWithinUnsignedCharSize(uint8_t * buffer, unsigned int size)
{
for (size_t i = 0; i < size; ++i)
{
buffer[i] = i;
}
}
using namespace google::protobuf::io;
int main()
{
GOOGLE_PROTOBUF_VERIFY_VERSION;
{
google::protobuf::Arena arena;
Recipe::Scene * scene = google::protobuf::Arena::CreateMessage<Recipe::Scene>(&arena);
uint8_t * imageData = new uint8_t[_SIZE];
randWithinUnsignedCharSize(imageData, _SIZE);
scene->mutable_image_data()->Resize(_SIZE, 0);
for (size_t i = 0; i < _SIZE; i++)
{
scene->set_image_data(i, imageData[i]);
}
std::cout << "done saving data to repeated field.\n";
{
std::fstream output("data.txt", std::ios::out | std::ios::trunc | std::ios::binary);
OstreamOutputStream outputFileStream(&output);
GzipOutputStream::Options options;
options.format = GzipOutputStream::GZIP;
options.compression_level = _COMPRESSION_LEVEL;
GzipOutputStream gzipOutputStream(&outputFileStream, options);
if (!scene->SerializeToZeroCopyStream(&gzipOutputStream)) {
std::cerr << "Failed to write scene." << std::endl;
return -1;
}
}
delete[] imageData;
}
std::cout << "Finish serializing into data.txt\n";
{
google::protobuf::Arena arena1;
Recipe::Scene * scene1 = google::protobuf::Arena::CreateMessage<Recipe::Scene>(&arena1);
{
std::fstream input("data.txt", std::ios::in | std::ios::binary);
IstreamInputStream inputFileStream(&input);
GzipInputStream gzipInputStream(&inputFileStream);
if (!scene1->ParseFromZeroCopyStream(&gzipInputStream)) {
std::cerr << "Failed to parse scene." << std::endl;
return -1;
}
}
std::cout << "scene1->imagedata_size() " << scene1->image_data_size() << std::endl;
}
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
This is client code by using libwebsocket version 1.5
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <syslog.h>
#include <sys/time.h>
#include <unistd.h>
#include <libwebsockets.h>
static volatile int force_exit = 0;
static int state, command_received = 0, forked = 0;
#define MAX_ECHO_PAYLOAD 1400
#define LOCAL_RESOURCE_PATH "./"
struct per_session_data {
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + MAX_ECHO_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING];
unsigned int len;
};
//for temporary storing data from tcpdump
struct per_session_data data1;
static int callback_echo(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len)
{
struct per_session_data *pss = (struct per_session_data *)user;
int n;
switch (reason) {
/* when the callback is used for client operations --> */
case LWS_CALLBACK_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
printf("Closed\n");
state = 0;
break;
case LWS_CALLBACK_ESTABLISHED:
case LWS_CALLBACK_CLIENT_ESTABLISHED:
printf("Client connected\n");
state = 2;
break;
/* we will receive our packet here*/
case LWS_CALLBACK_RECEIVE:
case LWS_CALLBACK_CLIENT_RECEIVE:
printf("Rx from server: %s\n", (char *)in);
if (!strcmp((char *)in, "tcpdump"))
{
command_received = 1;
}
break;
/* we will send our packet here */
case LWS_CALLBACK_CLIENT_WRITEABLE:
printf("client writing to server\n");
pss->len = sprintf((char *)&pss->buf[LWS_SEND_BUFFER_PRE_PADDING], "%s", data1.buf + LWS_SEND_BUFFER_PRE_PADDING);
n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT);
printf("Data: %s\n\n\n\n\n\n\n", &pss->buf[LWS_SEND_BUFFER_PRE_PADDING]);
//error handling for write fail and partial writes
if (n < 0) {
printf("ERROR %d writing to socket, hanging up\n", n);
return -1;
}
if (n < (int)pss->len) {
printf("Partial write\n");
return -1;
}
break;
default:
printf("default...\n");
break;
}
return 0;
}
/* List of available protocols */
static struct libwebsocket_protocols protocols[] = {
{
"default", /* name */
callback_echo, /* callback */
sizeof(struct per_session_data) /* per_session_data_size */
},
{
NULL, NULL, 0 /* End of list */
}
};
void sighandler(int sig)
{
force_exit = 1;
}
int main(int argc, char **argv)
{
//pipe stuff
int pipe_fd[2];
if (pipe(pipe_fd) < 0)
{
perror("PIPE:");
exit(-1);
}
//for libwebsocket_service
int n = 0;
//test port can be overidden
int port = 9000;
struct libwebsocket_context *context;
int opts = 0;
char interface_name[128] = "";
const char *interface = NULL;
int use_ssl = 0;
char ssl_cert[256] = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.pem";
char ssl_key[256] = LOCAL_RESOURCE_PATH"/libwebsockets-test-server.key.pem";
int listen_port = 80;
struct lws_context_creation_info info;
char passphrase[256];
char uri[256] = "/";
char address[256], ads_port[256 + 30];
//lws servicing time intervals
int rate_us = 250000;
unsigned int oldus = 0;
struct libwebsocket *wsi;
//should check this
int debug_level = 2;
memset(&info, 0, sizeof info);
lwsl_notice("Built to support client operations\n");
//re-configuring server ip and port here
if (argc == 3)
{
strncpy(address, argv[1], sizeof(address) - 1);
address[sizeof(address) - 1] = '\0';
port = atoi(argv[2]);
}
else if (argc == 1)
{
strncpy(address, "localhost", sizeof(address) - 1);
address[sizeof(address) - 1] = '\0';
port = 9000;
}
else
{
printf("Try: ./client.exec <ip> <port>\n");
exit(-1);
}
/* we will only try to log things according to our debug_level */
setlogmask(LOG_UPTO (LOG_DEBUG));
openlog("lwsts", 0, LOG_DAEMON);
/* tell the library what debug level to emit and to send it to syslog */
lws_set_log_level(debug_level, lwsl_emit_syslog);
lwsl_notice("libwebsockets echo test - "
"(C) Copyright 2010-2015 Andy Green <andy#warmcat.com> - "
"licensed under LGPL2.1\n");
lwsl_notice("Running in client mode\n");
listen_port = CONTEXT_PORT_NO_LISTEN;
lwsl_info("requiring server cert validation againts %s\n", ssl_cert);
info.ssl_ca_filepath = ssl_cert;
info.port = listen_port;
info.iface = interface;
info.protocols = protocols;
#ifndef LWS_NO_EXTENSIONS
info.extensions = libwebsocket_get_internal_extensions();
#endif
info.gid = -1;
info.uid = -1;
info.options = opts;
context = libwebsocket_create_context(&info);
if (context == NULL) {
lwsl_err("libwebsocket init failed\n");
return -1;
}
signal(SIGINT, sighandler);
n = 0;
while (n >= 0 && !force_exit)
{
//do connect only once
if (!state) {
state = 1;
printf("Client connecting to %s:%u....\n", address, port);
address[sizeof(address) - 1] = '\0';
sprintf(ads_port, "%s:%u", address, port & 65535);
wsi = libwebsocket_client_connect(context, address, port, use_ssl, uri, ads_port, ads_port, NULL, -1);
if (!wsi) {
printf("Client failed to connect to %s:%u\n", address, port);
goto bail;
}
}
if (command_received == 1 && !forked)
{
printf("Going to fork\n");
forked = 1;
pid_t child_pid = fork();
if (child_pid == -1)
{
perror("FORK:");
exit(-1);
}
else if (child_pid == 0)
{
close(pipe_fd[0]);
printf("Starting tcpdump\n");
if (dup2(pipe_fd[1], 1) < 0)
{
perror("DUP2:");
exit(-1);
}
//closing the connection to server for child
libwebsocket_context_destroy(context);
closelog();
char *cmd[] = {"tcpdump", "-i", "any", NULL};
if (execv("/usr/sbin/tcpdump", cmd) < 0)
{
perror("EXECV:");
exit(-1);
}
}
}
/* if (forked == 1)
{
close(pipe_fd[1]);
}
*/
if (command_received == 1)
{
//stay here if the pipe is empty else try to read max 1400 bytes of data
while ((data1.len = read(pipe_fd[0], data1.buf + LWS_SEND_BUFFER_PRE_PADDING, 1400)) <= 0);
//check if server wants any service
//printf("%s\n\n\n\n\n\n\n", data1.buf + LWS_SEND_BUFFER_PRE_PADDING);
libwebsocket_callback_on_writable(context, wsi);
}
//This fn times out every 10usec
n = libwebsocket_service(context, 10);
}
//bail: jump from while loop also if connect fails
bail:
libwebsocket_context_destroy(context);
printf("libwebsockets-test-echo exited cleanly\n");
closelog();
return 0;
}
This is my server code by using socket.io
var io = require('socket.io')();
var middleware = require('socketio-wildcard')();
io.use(middleware);
io.on('connection', function(socket) {
console.log('On socket connection')
socket.on('*', function(event, data){
console.log("---- Event ----- : " + JSON.stringify(event));
console.log("---- Data ----- : " + JSON.stringify(data))
});
});
io.listen(9000, 'localhost');
The client is unable to connect with server. when i tested client with strace it infinitely does receive as below
recv(8, "", 1, 0) = 0
recv(8, "", 1, 0) = 0
recv(8, "", 1, 0) = 0
.
.
.
.
Please point out my mistake. Any help is appreciated.
Thanks
Hellow I'm tring to learn writing kernel modules and device drivers. As a begginig I decided to start by making a driver for my tlc5947 led matrix. From simple kernel module with parameters I moved to char device driver but I'm having hard time with resource reference counting. Whole day I have been playing the restart game with my PI and still can't figure from where the bug is comming ...
This is the module header:
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#ifndef _TLC5947_LED_MATRIX_H
#define _TLC5947_LED_MATRIX_H
#define TLC5947_GPIOS 3
#define TLC5947_LEDS 24
#define TLC5947_MAXPWM 4096
#define GPIO_HIGH 1
#define GPIO_LOW 0
#define TLC5947_NAME "tlc5947"
#define CONST_PARAM S_IRUSR | S_IRGRP | S_IROTH
ushort tlc5947_chips = 255;
ushort tlc5947_data = 255;
ushort tlc5947_clock = 255;
ushort tlc5947_latch = 255;
static struct gpio tlc5947[TLC5947_GPIOS] = {
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 DATA"},
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 CLOCK"},
{.gpio = -1, .flags = GPIOF_OUT_INIT_HIGH, .label = "TLC5947 LATCH"},
};
static dev_t tlc5947_numbers;
static int tlc5947_major_number;
static int tlc5947_first_minor = 0;
static unsigned int tlc5947_minor_count = 1;
static struct file_operations tlc5947_file_operations;
static struct cdev* tlc5947_cdev;
static int tlc5947_file_opened = 0;
static int tlc5947_file_open(struct inode* inode, struct file* file);
static ssize_t tlc5947_file_write(struct file* file, const char __user* buffer, size_t buffer_length, loff_t* offset);
static int tlc5947_file_close(struct inode* inode, struct file* file);
static int is_tlc5947_param_set(ushort* tlc5947_param, const char* tlc5947_param_name);
static int __init tlc5947_init(void);
static void __exit tlc5947_exit(void);
#endif
The source:
#include "tlc5947_led_matrix.h"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <linux/gpio.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
module_param(tlc5947_chips, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_chips, "Number of tlc5967 chips that are chain connected.");
module_param(tlc5947_data, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_data, "Number of gpio pin on wich DATA signal is connected (BCM Enum).");
module_param(tlc5947_clock, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_clock, "Number of gpio pin on wich CLOCK signal is connected (BCM Enum).");
module_param(tlc5947_latch, ushort, CONST_PARAM);
MODULE_PARM_DESC(tlc5967_latch, "Number of gpio pin on wich LATCH signal is connected (BCM Enum).");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ivo Stratev");
MODULE_DESCRIPTION("Basic Linux Kernel module using GPIOs to drive tlc5947");
MODULE_SUPPORTED_DEVICE(TLC5947_NAME);
static int tlc5947_file_open(struct inode* inode, struct file* file) {
if(tlc5947_file_opened == 1) {
printk(KERN_ERR "Fail to open file /dev/%s\n", TLC5947_NAME);
return -EBUSY;
}
tlc5947_file_opened = 1;
return 0;
}
static ssize_t tlc5947_file_write(struct file* file, const char __user* buffer, size_t buffer_length, loff_t* offset) {
char data[10];
unsigned int i;
unsigned long copy_ret = copy_from_user(data, buffer, buffer_length);
if(copy_ret) {
printk(KERN_ERR "Error while copying data\nCalling copy_from_user reurned%ld\n", copy_ret);
return copy_ret;
}
data[0] -= '0';
i = tlc5947_chips * TLC5947_LEDS - 1;
gpio_set_value(tlc5947_latch, GPIO_LOW);
while(1) {
unsigned char bit = 11;
while(1) {
gpio_set_value(tlc5947_clock, GPIO_LOW);
gpio_set_value(tlc5947_data, (data[0] & (1 << bit)) ? GPIO_HIGH : GPIO_LOW);
gpio_set_value(tlc5947_clock, GPIO_HIGH);
if(bit == 0) {
break;
}
bit--;
}
if(i == 0) {
break;
}
i--;
}
gpio_set_value(tlc5947_clock, GPIO_LOW);
gpio_set_value(tlc5947_latch, GPIO_HIGH);
gpio_set_value(tlc5947_latch, GPIO_LOW);
return copy_ret;
}
static int tlc5947_file_close(struct inode* inode, struct file* file) {
tlc5947_file_opened = 0;
return 0;
}
static int is_tlc5947_param_set(ushort* tlc5947_param, const char* tlc5947_param_name) {
int is_255 = (*tlc5947_param) == 255;
if(is_255) {
printk(KERN_ERR "Parameter %s value not setted when loading the module\n", tlc5947_param_name);
}
return is_255;
}
static int __init tlc5947_init(void) {
int init_ret = 0;
init_ret |= is_tlc5947_param_set(&tlc5947_chips, "tlc5947_chips");
init_ret |= is_tlc5947_param_set(&tlc5947_data, "tlc5947_data");
init_ret |= is_tlc5947_param_set(&tlc5947_clock, "tlc5947_clock");
init_ret |= is_tlc5947_param_set(&tlc5947_latch, "tlc5947_latch");
if(init_ret) {
return -EINVAL;
}
tlc5947[0].gpio = tlc5947_data;
tlc5947[1].gpio = tlc5947_clock;
tlc5947[2].gpio = tlc5947_latch;
init_ret = gpio_request_array(tlc5947, TLC5947_GPIOS);
if(init_ret) {
printk(KERN_ERR "Unable to request GPIOs!\nCalling gpio_request_array returned %d\n", init_ret);
return init_ret;
}
init_ret = alloc_chrdev_region(&tlc5947_numbers, tlc5947_first_minor, tlc5947_minor_count, TLC5947_NAME);
if(init_ret) {
printk(KERN_ERR "Could not allocate device numbers\nCalling alloc_chrdev_region returned %d\n", init_ret);
return init_ret;
}
tlc5947_major_number = MAJOR(tlc5947_numbers);
printk(KERN_INFO "Device major number is %d. Use $ sudo make device\n", tlc5947_major_number);
tlc5947_cdev = cdev_alloc();
tlc5947_cdev->owner = THIS_MODULE;
tlc5947_file_operations.owner = THIS_MODULE;
tlc5947_file_operations.open = tlc5947_file_open;
tlc5947_file_operations.release = tlc5947_file_close;
tlc5947_file_operations.write = tlc5947_file_write;
tlc5947_cdev->ops = &tlc5947_file_operations;
init_ret = cdev_add(tlc5947_cdev, tlc5947_numbers, tlc5947_minor_count);
if(init_ret) {
printk(KERN_ERR "Failed to add device numbers to struct cdev\nCalling cdev_add returned %d\n", init_ret);
return init_ret;
}
return 0;
}
static void __exit tlc5947_exit(void) {
cdev_del(tlc5947_cdev);
unregister_chrdev_region(tlc5947_numbers, tlc5947_minor_count);
gpio_free_array(tlc5947, TLC5947_GPIOS);
}
module_init(tlc5947_init);
module_exit(tlc5947_exit);
And the makefile:
target = tlc5947
driver = tlc5947_led_matrix
obj-m := $(target).o
$(target)-objs := $(driver).o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
rm -f /dev/$(target)
activate:
insmod $(target).ko tlc5947_chips=8 tlc5947_data=17 tlc5947_clock=27 tlc5947_latch=22
remove:
rmmod -rf $(target)
modprobe -rf $(target)
device:
mknod /dev/$(target) c 243 0
chmod 777 /dev/$(target)
I'm testing out multicast with the two programs below. The client run well on linux and in wine on two of my machines, but it won't work properly on my windows machine (in Virtualbox).
Strangely, if I start up vlc in windows and open the udp stream, the client program receives the packets - and when I stop vlc, the client goes silent again.
What am I doing wrong?
Here is the the server program:
/*
* server.c - multicast server program.
*/
#include <sys/types.h>
#ifdef WINDOWS
#include <winsock.h>
#include <windows.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <time.h>
#include <string.h>
#include <stdio.h>
#define HELLO_PORT 5004
#define HELLO_GROUP "224.0.0.1"
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, cnt, numbytes;
struct ip_mreq mreq;
char message[100];
#ifdef WINDOWS
WSADATA wsaData; /* Windows socket DLL structure */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup() failed");
return 1;
}
#endif
/* create what looks like an ordinary UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
fprintf(stderr, "failed to create socket.\n");
return 1;
}
/* set up destination address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(HELLO_GROUP);
addr.sin_port = htons(HELLO_PORT);
/* now just sendto() our destination! */
cnt = 0;
while (1) {
numbytes = sprintf(message, "%d", cnt);
if (sendto(fd, message, numbytes, 0, (struct sockaddr*)&addr,
sizeof(addr)) < 0) {
fprintf(stderr, "sendto failed.\n");
return 1;
}
#ifdef WINDOWS
Sleep(1000);
#else
sleep(1);
#endif
cnt++;
}
return 0;
}
and here's the client program:
/*
* client.c -- client program for udp multicast data.
*/
#include <sys/types.h>
#ifdef WINDOWS
#include <winsock.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include <time.h>
#include <string.h>
#include <stdio.h>
#define HELLO_GROUP "224.0.0.1"
#define HELLO_PORT 5004
#define MSGBUFSIZE 256
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
int fd, nbytes,addrlen;
struct ip_mreq mreq;
char msgbuf[MSGBUFSIZE];
u_int yes = 1;
#ifdef WINDOWS
WSADATA wsaData; /* Windows socket DLL structure */
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) {
fprintf(stderr, "WSAStartup() failed");
return 1;
}
#endif
/* create what looks like an ordinary UDP socket */
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
fprintf(stderr, "failed to create socket.\n");
return 1;
}
/* allow multiple sockets to use the same PORT number */
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes)) != 0) {
fprintf(stderr, "failed to reuse port number.\n");
return 1;
}
/* set up destination address */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(HELLO_PORT);
/* bind to receive address */
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
fprintf(stderr, "failed to bind socket.\n");
return 1;
}
/* use setsockopt() to request that the kernel join a multicast group */
mreq.imr_multiaddr.s_addr = inet_addr(HELLO_GROUP);
mreq.imr_interface.s_addr = INADDR_ANY;
if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*)&mreq, sizeof(mreq)) != 0) {
fprintf(stderr, "failed to join the multicast group.\n");
return 1;
}
/* now just enter a read-print loop */
while (1) {
addrlen = sizeof(addr);
nbytes = recvfrom(fd, msgbuf, MSGBUFSIZE, 0,
(struct sockaddr*)&addr, &addrlen);
if (nbytes < 0) {
fprintf(stderr, "recfrom failed, %d\n", nbytes);
return 1;
}
msgbuf[nbytes] = '\0';
puts(msgbuf);
}
return 0;
}
Thanks,
Oskar
Ok, so apparently the firewall blocked the packets. Turning it off fixes the issue.