• No results found

Modelling packets

In document OMNet 4.0 Manual (Page 106-109)

RxGate100 Mbps

5.1 Messages and packets

5.1.3 Modelling packets

Arrival gate and time

The following methods can tell where the message came from and where it arrived (or will arrive if it is currently scheduled or under way.)

int getSenderModuleId();

int getSenderGateId();

int getArrivalModuleId();

int getArrivalGateId();

The following methods are just convenience functions which build on the ones above.

cModule *getSenderModule();

cGate *getSenderGate();

cGate *getArrivalGate();

And there are further convenience functions to tell whether the message arrived on a specific gate given with id or name+index.

bool arrivedOn(int id);

bool arrivedOn(const char *gname, int gindex=0);

The following methods return message creation time and the last sending and arrival times.

simtime_t getCreationTime();

simtime_t getSendingTime();

simtime_t getArrivalTime();

Control info

One of the main application areas of OMNeT++ is the simulation of telecommunication net-works. Here, protocol layers are usually implemented as modules which exchange packets.

Packets themselves are represented by messages subclassed from cMessage.

However, communication between protocol layers requires sending additional information to be attached to packets. For example, a TCP implementation sending down a TCP packet to IP will want to specify the destination IP address and possibly other parameters. When IP passes up a packet to TCP after decapsulation from the IP header, it’ll want to let TCP know at least the source IP address.

This additional information is represented by control info objects in OMNeT++. Control info ob-jects have to be subclassed from cObject (a small footprint base class with no data members), and attached to the messages representing packets. cMessage has the following methods for this purpose:

void setControlInfo(cObject *controlInfo);

cObject *getControlInfo();

cObject *removeControlInfo();

When a "command" is associated with the message sending (such as TCP OPEN, SEND, CLOSE, etc), the message kind field (getKind(), setKind() methods of cMessage) should carry the command code. When the command doesn’t involve a data packet (e.g. TCP CLOSE command), a dummy packet (empty cMessage) can be sent.

Identifying the protocol

In OMNeT++ protocol models, the protocol type is usually represented in the message sub-class. For example, instances of class IPv6Datagram represent IPv6 datagrams and Ether-netFrame represents Ethernet frames) and/or in the message kind value. The PDU type is usually represented as a field inside the message class.

The C++ dynamic_cast operator can be used to determine if a message object is of a specific protocol.

cMessage *msg = receive();

if (dynamic_cast<IPv6Datagram *>(msg) != NULL) {

IPv6Datagram *datagram = (IPv6Datagram *)msg;

...

}

5.1.4 Encapsulation

Encapsulating packets

It is often necessary to encapsulate a message into another when you’re modeling layered protocols of computer networks. Although you can encapsulate messages by adding them to the parameter list, there’s a better way.

The encapsulate() function encapsulates a message into another one. The length of the message will grow by the length of the encapsulated message. An exception: when the encap-sulating (outer) message has zero length, OMNeT++ assumes it is not a real packet but some out-of-band signal, so its length is left at zero.

cMessage *userdata = new cMessage("userdata");

userdata->setByteLength(2048); // 2K cMessage *tcpseg = new cMessage("tcp");

tcpseg->setByteLength(24);

tcpseg->encapsulate(userdata);

ev << tcpseg->getByteLength() << endl; // --> 2048+24 = 2072

A message can only hold one encapsulated message at a time. The second encapsulate() call will result in an error. It is also an error if the message to be encapsulated isn’t owned by the module.

You can get back the encapsulated message by decapsulate():

cMessage *userdata = tcpseg->decapsulate();

OMNeT++ Manual – Messages

decapsulate()will decrease the length of the message accordingly, except if it was zero. If the length would become negative, an error occurs.

The getEncapsulatedMsg() function returns a pointer to the encapsulated message, or NULL if no message was encapsulated.

Reference counting

Since the 3.2 release, OMNeT++ implements reference counting of encapsulated messages, meaning that if you dup() a message that contains an encapsulated message, then the en-capsulated message will not be duplicated, only a reference count incremented. Duplication of the encapsulated message is deferred until decapsulate() actually gets called. If the outer message gets deleted without its decapsulate() method ever being called, then the reference count of the encapsulated message simply gets decremented. The encapsulated message is deleted when its reference count reaches zero.

Reference counting can significantly improve performance, especially in LAN and wireless scenarios. For example, in the simulation of a broadcast LAN or WLAN, the IP, TCP and higher layer packets won’t get duplicated (and then discarded without being used) if the MAC address doesn’t match in the first place.

The reference counting mechanism works transparently. However, there is one implication:

one must not change anything in a message that is encapsulated into another! That is, getEncapsulatedMsg() should be viewed as if it returned a pointer to a read-only object (it returns a const pointer indeed), for quite obvious reasons: the encapsulated message may be shared between several messages, and any change would affect those other messages as well.

Encapsulating several messages

The cMessage class doesn’t directly support adding more than one messages to a message object, but you can subclass cMessage and add the necessary functionality. (It is recom-mended that you use the message definition syntax 5.2 and customized messages 5.2.6 to be described later on in this chapter – it can spare you some work.)

You can store the messages in a fixed-size or a dynamically allocated array, or you can use STL classes like std::vector or std::list. There is one additional “trick” that you might not expect: your message class has to take ownership of the inserted messages, and release them when they are removed from the message. These are done via the take() and drop() methods. Let us see an example which assumes you have added to the class an std::list member called messages that stores message pointers:

void MessageBundleMessage::insertMessage(cMessage *msg) {

take(msg); // take ownership

messages.push_back(msg); // store pointer }

void MessageBundleMessage::removeMessage(cMessage *msg) {

messages.remove(msg); // remove pointer drop(msg); // release ownership

}

You will also have to provide an operator=() method to make sure your message objects can be copied and duplicated properly – this is something often needed in simulations (think of broadcasts and retransmissions!). Section 6.10 contains more info about the things you need to take care of when deriving new classes.

In document OMNet 4.0 Manual (Page 106-109)