net: Fix a bug when handling IPv6 packets
authorPin-Yen Lin <treapking@google.com>
Mon, 13 Aug 2018 06:23:24 +0000 (14:23 +0800)
committerEarl Ou <shunhsingou@google.com>
Fri, 7 Sep 2018 09:30:30 +0000 (09:30 +0000)
When gem5 runs with the networking support, it will run into an assertion
fail and aborted. This is because it tries to calculate checksum for IPv6
packet and this makes the IpPtr pointer ``ip'' become NULL. For that there
is functions and classes for IPv6 in base/inet.cc, I added IPv6 support for
i8254xGBe.cc. Because IPv6 header does not have identification number,  I
ignored some of the debug messages using ip->id().

Change-Id: Ida5e36aefd2c5c26053f8152a0aac24191e7757c
Reviewed-on: https://gem5-review.googlesource.com/12339
Reviewed-by: Earl Ou <shunhsingou@google.com>
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Gabe Black <gabeblack@google.com>

src/dev/net/i8254xGBe.cc

index 3359b0d61a286c75c3177bc28e5e010138a55877..88528c4b73cec74c08267054ad599bd573dd74e1 100644 (file)
@@ -1373,13 +1373,19 @@ IGbE::RxDescCache::pktComplete()
         status |= RXDS_EOP;
 
     IpPtr ip(pktPtr);
+    Ip6Ptr ip6(pktPtr);
 
-    if (ip) {
-        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
-        ptype |= RXDP_IPV4;
-        ip_id = ip->id();
+    if (ip || ip6) {
+        if (ip) {
+            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
+                    ip->id());
+            ptype |= RXDP_IPV4;
+            ip_id = ip->id();
+        }
+        if (ip6)
+            ptype |= RXDP_IPV6;
 
-        if (igbe->regs.rxcsum.ipofld()) {
+        if (ip && igbe->regs.rxcsum.ipofld()) {
             DPRINTF(EthernetDesc, "Checking IP checksum\n");
             status |= RXDS_IPCS;
             csum = htole(cksum(ip));
@@ -1390,7 +1396,7 @@ IGbE::RxDescCache::pktComplete()
                 DPRINTF(EthernetDesc, "Checksum is bad!!\n");
             }
         }
-        TcpPtr tcp(ip);
+        TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
         if (tcp && igbe->regs.rxcsum.tuofld()) {
             DPRINTF(EthernetDesc, "Checking TCP checksum\n");
             status |= RXDS_TCPCS;
@@ -1404,7 +1410,7 @@ IGbE::RxDescCache::pktComplete()
             }
         }
 
-        UdpPtr udp(ip);
+        UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
         if (udp && igbe->regs.rxcsum.tuofld()) {
             DPRINTF(EthernetDesc, "Checking UDP checksum\n");
             status |= RXDS_UDPCS;
@@ -1838,26 +1844,28 @@ IGbE::TxDescCache::pktComplete()
 
     if (useTso) {
         IpPtr ip(pktPtr);
+        Ip6Ptr ip6(pktPtr);
         if (ip) {
             DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
                     tsoPkts);
             ip->id(ip->id() + tsoPkts++);
             ip->len(pktPtr->length - EthPtr(pktPtr)->size());
-
-            TcpPtr tcp(ip);
-            if (tcp) {
-                DPRINTF(EthernetDesc,
-                        "TSO: Modifying TCP header. old seq %d + %d\n",
-                        tcp->seq(), tsoPrevSeq);
-                tcp->seq(tcp->seq() + tsoPrevSeq);
-                if (tsoUsedLen != tsoTotalLen)
-                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
-            }
-            UdpPtr udp(ip);
-            if (udp) {
-                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
-                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
-            }
+        }
+        if (ip6)
+            ip6->plen(pktPtr->length - EthPtr(pktPtr)->size());
+        TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
+        if (tcp) {
+            DPRINTF(EthernetDesc,
+                    "TSO: Modifying TCP header. old seq %d + %d\n",
+                    tcp->seq(), tsoPrevSeq);
+            tcp->seq(tcp->seq() + tsoPrevSeq);
+            if (tsoUsedLen != tsoTotalLen)
+                tcp->flags(tcp->flags() & ~9); // clear fin & psh
+        }
+        UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
+        if (udp) {
+            DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
+            udp->len(pktPtr->length - EthPtr(pktPtr)->size());
         }
         tsoPrevSeq = tsoUsedLen;
     }
@@ -1872,19 +1880,20 @@ IGbE::TxDescCache::pktComplete()
     }
 
     // Checksums are only ofloaded for new descriptor types
-    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
+    if (TxdOp::isData(desc) && (TxdOp::ixsm(desc) || TxdOp::txsm(desc))) {
         DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
         IpPtr ip(pktPtr);
-        assert(ip);
-        if (TxdOp::ixsm(desc)) {
+        Ip6Ptr ip6(pktPtr);
+        assert(ip || ip6);
+        if (ip && TxdOp::ixsm(desc)) {
             ip->sum(0);
             ip->sum(cksum(ip));
             igbe->txIpChecksums++;
             DPRINTF(EthernetDesc, "Calculated IP checksum\n");
         }
         if (TxdOp::txsm(desc)) {
-            TcpPtr tcp(ip);
-            UdpPtr udp(ip);
+            TcpPtr tcp = ip ? TcpPtr(ip) : TcpPtr(ip6);
+            UdpPtr udp = ip ? UdpPtr(ip) : UdpPtr(ip6);
             if (tcp) {
                 tcp->sum(0);
                 tcp->sum(cksum(tcp));