diff --git a/WHATSNEW b/WHATSNEW index 68c0405dbb7..ca1d684808f 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -402,6 +402,12 @@ Notable backward incompatible changes are the following: A TCP algorithm implemented outside INET needs a simple module type that extends TcpAlgorithm, and Define_Module() in place of Register_Class(); without the type, the connection stops with an error. Its initialize() is now initializeAlgorithm(), and the cancelEvent() helper of TcpAlgorithmBase is now cancelTimer(). See the migration guide. +50. A packet drop reason for datagrams that are too big + + PacketDropReason gains PACKET_TOO_BIG, for a datagram that is larger than the MTU of the next link and may not be fragmented, with the result filter packetDropReasonIsPacketTooBig. Ipv4 reports it for a datagram with the Don't Fragment flag set, and Mpls for a labeled datagram with that flag; both reported OTHER_PACKET_DROP before. Ipv4 records the new statistic packetDropPacketTooBig. + + Ipv4's packetDropUndefined no longer counts these drops, so its results change in simulations where routers drop such datagrams, for example examples/inet/tcp_pmtud and examples/quic/dplpmtud. A PacketDropVisualizer label that shows the reason now shows 16 or PACKET_TOO_BIG instead of -1 or OTHER_PACKET_DROP. + Notable backward compatible changes are the following: 1. IEEE 802.11 per-station rate statistics diff --git a/src/inet/common/ResultFilters.cc b/src/inet/common/ResultFilters.cc index 507b2cb4c85..93bbfb9637f 100644 --- a/src/inet/common/ResultFilters.cc +++ b/src/inet/common/ResultFilters.cc @@ -1128,6 +1128,7 @@ Register_PacketDropReason_ResultFilter("packetDropReasonIsCongestion", Congestio Register_PacketDropReason_ResultFilter("packetDropReasonIsNoProtocolFound", NoProtocolFoundPacketDropReasonFilter, NO_PROTOCOL_FOUND); Register_PacketDropReason_ResultFilter("packetDropReasonIsNoPortFound", NoPortFoundPacketDropReasonFilter, NO_PORT_FOUND); Register_PacketDropReason_ResultFilter("packetDropReasonIsDuplicateDetected", DuplicateDetectedPacketDropReasonFilter, DUPLICATE_DETECTED); +Register_PacketDropReason_ResultFilter("packetDropReasonIsPacketTooBig", PacketTooBigPacketDropReasonFilter, PACKET_TOO_BIG); Register_PacketDropReason_ResultFilter("packetDropReasonIsOther", OtherPacketDropReasonFilter, OTHER_PACKET_DROP); Register_ResultFilter("minimumSnir", MinimumSnirFromSnirIndFilter); diff --git a/src/inet/common/Simsignals.msg b/src/inet/common/Simsignals.msg index 77cfebc8069..8c3a427baf6 100644 --- a/src/inet/common/Simsignals.msg +++ b/src/inet/common/Simsignals.msg @@ -26,6 +26,7 @@ enum PacketDropReason NO_PROTOCOL_FOUND = 13; NO_PORT_FOUND = 14; DUPLICATE_DETECTED = 15; + PACKET_TOO_BIG = 16; OTHER_PACKET_DROP = -1; } diff --git a/src/inet/networklayer/ipv4/Ipv4.cc b/src/inet/networklayer/ipv4/Ipv4.cc index b7f7fde3e2e..c59584a57db 100644 --- a/src/inet/networklayer/ipv4/Ipv4.cc +++ b/src/inet/networklayer/ipv4/Ipv4.cc @@ -980,6 +980,7 @@ void Ipv4::fragmentAndSend(Packet *packet) // if "don't fragment" bit is set, throw datagram away and send ICMP error message if (ipv4Header->getDontFragment()) { PacketDropDetails details; + details.setReason(PACKET_TOO_BIG); emit(packetDroppedSignal, packet, &details); EV_WARN << "datagram larger than MTU and don't fragment bit set, sending ICMP_DESTINATION_UNREACHABLE\n"; icmp->sendPtbMessage(packet, mtu); diff --git a/src/inet/networklayer/ipv4/Ipv4.ned b/src/inet/networklayer/ipv4/Ipv4.ned index 349a1644a6f..b4815802f64 100644 --- a/src/inet/networklayer/ipv4/Ipv4.ned +++ b/src/inet/networklayer/ipv4/Ipv4.ned @@ -120,6 +120,7 @@ simple Ipv4 extends SimpleModule like IIpv4 @statistic[packetDropLifetimeExpired](title="packet drop: lifetime expired"; source=packetDropReasonIsLifetimeExpired(packetDropped); record=count,sum(packetBytes),vector(packetBytes); interpolationmode=none); @statistic[packetDropNoInterfaceFound](title="packet drop: no interface found"; source=packetDropReasonIsNoInterfaceFound(packetDropped); record=count,sum(packetBytes),vector(packetBytes); interpolationmode=none); @statistic[packetDropNoRouteFound](title="packet drop: no route found"; source=packetDropReasonIsNoRouteFound(packetDropped); record=count,sum(packetBytes),vector(packetBytes); interpolationmode=none); + @statistic[packetDropPacketTooBig](title="packet drop: packet too big"; source=packetDropReasonIsPacketTooBig(packetDropped); record=count,sum(packetBytes),vector(packetBytes); interpolationmode=none); @statistic[packetDropUndefined](title="packet drop: undefined"; source=packetDropReasonIsUndefined(packetDropped); record=count,sum(packetBytes),vector(packetBytes); interpolationmode=none); gates: input transportIn @labels(Ipv4ControlInfo/down,TcpHeader,UdpHeader,SctpHeader); diff --git a/src/inet/networklayer/mpls/Mpls.cc b/src/inet/networklayer/mpls/Mpls.cc index c840625dde2..dd08c7d45a6 100644 --- a/src/inet/networklayer/mpls/Mpls.cc +++ b/src/inet/networklayer/mpls/Mpls.cc @@ -409,7 +409,7 @@ void Mpls::processTooBigDatagram(Packet *packet, const NetworkInterface *network // Destination Unreachable message whose Next-Hop MTU leaves room for the label stack EV_WARN << "discarding a too-big datagram with the DF bit, sending ICMP_DESTINATION_UNREACHABLE" << endl; PacketDropDetails details; - details.setReason(OTHER_PACKET_DROP); + details.setReason(PACKET_TOO_BIG); emit(packetDroppedSignal, packet, &details); if (icmp != nullptr) icmp->sendPtbMessage(packet, maxDatagramLength); diff --git a/tests/module/IPv4_dont_fragment_drop_reason.test b/tests/module/IPv4_dont_fragment_drop_reason.test new file mode 100644 index 00000000000..8ce69bfdeb8 --- /dev/null +++ b/tests/module/IPv4_dont_fragment_drop_reason.test @@ -0,0 +1,66 @@ +%description: +Tests that IPv4 reports a datagram that is larger than the MTU of the next link +and has the Don't Fragment (DF) flag set with the packet drop reason +PACKET_TOO_BIG, so that the packetDropPacketTooBig statistic of Ipv4 counts it +and packetDropUndefined does not. + +hostA sends three UDP datagrams with a 1000-byte payload and DF set to hostB. The router's +link toward hostB has an MTU of 576 bytes, so the router drops all three and +sends ICMP Destination Unreachable (Fragmentation Needed) to hostA. + +%#-------------------------------------------------------------------------------------------------------------- +%file: test.ned +import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator; +import inet.node.inet.Router; +import inet.node.inet.StandardHost; +import ned.DatarateChannel; + +network DontFragmentNetwork +{ + types: + channel ethline extends DatarateChannel + { + delay = 0.1us; + datarate = 100Mbps; + } + submodules: + configurator: Ipv4NetworkConfigurator; + hostA: StandardHost; + router: Router; + hostB: StandardHost; + connections: + hostA.ethg++ <--> ethline <--> router.ethg++; + router.ethg++ <--> ethline <--> hostB.ethg++; +} +%#-------------------------------------------------------------------------------------------------------------- +%inifile: omnetpp.ini +[General] +ned-path = ../../../../src +network = DontFragmentNetwork +sim-time-limit = 5s +record-vector-results = false +cmdenv-express-mode = true + +**.router.eth[1].mac.mtu = 576B + +**.hostA.numApps = 1 +**.hostA.app[0].typename = "UdpBasicApp" +**.hostA.app[0].destAddresses = "hostB" +**.hostA.app[0].destPort = 1000 +**.hostA.app[0].messageLength = 1000B +**.hostA.app[0].dontFragment = true +**.hostA.app[0].startTime = 1s +**.hostA.app[0].sendInterval = 1s +**.hostA.app[0].stopTime = 3.5s +%#-------------------------------------------------------------------------------------------------------------- +%postrun-command: gawk '$1 == "scalar" && $2 == "DontFragmentNetwork.router.ipv4.ip" && ($3 == "packetDropPacketTooBig:count" || $3 == "packetDropUndefined:count") { print $3, $4 }' results/*.sca > drops.out +%contains: drops.out +packetDropPacketTooBig:count 3 +%#-------------------------------------------------------------------------------------------------------------- +%contains: drops.out +packetDropUndefined:count 0 +%#-------------------------------------------------------------------------------------------------------------- +%postrun-command: grep "undisposed object:" test.out > test_undisposed.out || true +%not-contains: test_undisposed.out +undisposed object: ( +%#--------------------------------------------------------------------------------------------------------------