LinkedList Queue implementation
Packet

private static int packetCount; // Determined at the time of the objects creation [incremental]


I would remove this field. Personally I feel it's odd for a Packet to need to know the number of packets. Apart from that you would need to synchronize access to this field, should your class ever be used in a multi-threading environment.

Node


make data final. A node should never change it's data once created. Remove the setter as well.
Remove the default constructor public Node(). It is unused and does not initialize the (now final) field data.
rename the field data to packet. A clear naming will help other developers and your future self remember what is stored here.


Router

size should be private too

public void enqueue(Packet packet) {
    Node node = new Node(packet);

    if (head == null) {
        head = node;
        tail = node;
    }
    tail.setNext(node);
    node.setPrev(tail);
    tail = node;

    size++;
}


if head == nullyou set head = tail = node. You now have three references to the same Packet object. After that you set next and prev on this object to itself. 

public Packet dequeue() {
    Node ptr = head;
    head = ptr.getNext();

    if (head == null) {
        tail = null;
    }

    size--;

    return ptr.getData();
}


If now dequeue is called, head is assigned to ptr (which is the Packet pointing forward and backward to itself. head is assigned ptr.next which means, it is still the same object. head == null will never be true. For every subsequent call to dequeue you will get that Packet.

If another Packet ist enqueued the next call to dequeue will return the first Packet once more and then return the new Packet, removing it from your list.

To fix that, change enqueue to 

public void enqueue(Packet packet) {
    Node node = new Node(packet);

    if (head == null) {
        head = node;
        tail = node;
    } else {
        tail.setNext(node);
        node.setPrev(tail);
        tail = node;
    }

    size++;
}


Are you sure, that the output created by recToString is what you want/need?

Calling

router.enqueue(new Packet(11, 11, 11, 11));
router.enqueue(new Packet(22, 22, 22, 22));
router.enqueue(new Packet(33, 33, 33, 33));
System.out.println(router.toString());


yields the output:

Packet #33 =&gt; arrive at simulation unit: 33 =&gt; packet size: 33
Packet #22 =&gt; arrive at simulation unit: 22 =&gt; packet size: 22
Packet #11 =&gt; arrive at simulation unit: 11 =&gt; packet size: 11Packet #22 =&gt; arrive at simulation unit: 22 =&gt; packet size: 22Packet #33 =&gt; arrive at simulation unit: 33 =&gt; packet size: 33


Since you implement FIFO I think, the first (head) element should be printed first.

Remove recToString and replace toString:

@Override
public String toString() {
    StringBuilder result = new StringBuilder();

    Node current = head;
    while (current != null) {
        result.append(current.getData().toString()).append("\n");

        current = current.getNext();
    }

    return result.toString();
}


It now starts at head and walks forward through the list till it hits the end.

With recToString removed the only call to Node#getPrev() got removed, too. A FIFO-structure does not need to be double linked. Let's remove it.

Node:

public class Node {
    private Packet data;
    private Node next;

    public Node(Packet data) {
        this.data = data;
        next = null;
    }

    public Packet getData() {
        return data;
    }

    public Node getNext() {
        return next;
    }

    public void setNext(Node next) {
        this.next = next;
    }
}


Router#enqueue()

public void enqueue(Packet packet) {
    Node node = new Node(packet);

    if (head == null) {
        head = node;
        tail = node;
    } else {
        tail.setNext(node);
        tail = node;
    }

    size++;
}


Edit:
Forgot my own comment.

Exception handling

Create your own Exception:

public class QueueEmptyException extends RuntimeException {
    public QueueEmptyException() {
    }

    public QueueEmptyException(final String message) {
        super(message);
    }

    public QueueEmptyException(final String message, final Throwable cause) {
        super(message, cause);
    }

    public QueueEmptyException(final Throwable cause) {
        super(cause);
    }

    public QueueEmptyException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}


Create a method that throws the Exception, if the queue is empty:

private void assertNotEmpty() {
    if (isEmpty()) {
        throw new QueueEmptyException("Queue is emtpy");
    }
}


Change peek

public Packet peek() {
    assertNotEmpty();

    return head.getData();
}


and dequeue

public Packet dequeue() {
    assertNotEmpty();

    [...]
}