Author: bz
Date: Tue Nov 14 16:47:05 2017
New Revision: 325813
URL: https://svnweb.freebsd.org/changeset/base/325813

Log:
  Unbreak IPv6.
  
  No longer return ENXIO when trying to send an IPv6 packet in
  nicvf_sq_add_hdr_subdesc().
  Restructure the code so that the upper layer protocol parts are
  agnostic of the L3 protocol (and no longer specific to IPv4).
  With this basic IPv6 packets go through.  We are still seeing
  weird behaviour which needs further diagnosis.
  
  PR:                   223669
  In collaboration with:        emaste
  MFC after:            3 days

Modified:
  head/sys/dev/vnic/nicvf_queues.c

Modified: head/sys/dev/vnic/nicvf_queues.c
==============================================================================
--- head/sys/dev/vnic/nicvf_queues.c    Tue Nov 14 16:32:40 2017        
(r325812)
+++ head/sys/dev/vnic/nicvf_queues.c    Tue Nov 14 16:47:05 2017        
(r325813)
@@ -78,6 +78,8 @@ __FBSDID("$FreeBSD$");
 #include <netinet/tcp_lro.h>
 #include <netinet/udp.h>
 
+#include <netinet6/ip6_var.h>
+
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 
@@ -1752,7 +1754,7 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qen
        struct tcphdr *th;
 #endif
        uint16_t etype;
-       int ehdrlen, iphlen, poff;
+       int ehdrlen, iphlen, poff, proto;
 
        nic = sq->nic;
 
@@ -1776,13 +1778,21 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qen
                etype = ntohs(eh->evl_encap_proto);
        }
 
+       poff = proto = -1;
        switch (etype) {
 #ifdef INET6
        case ETHERTYPE_IPV6:
-               /* ARM64TODO: Add support for IPv6 */
-               hdr->csum_l3 = 0;
-               sq->snd_buff[qentry].mbuf = NULL;
-               return (ENXIO);
+               if (mbuf->m_len < ehdrlen + sizeof(struct ip6_hdr)) {
+                       mbuf = m_pullup(mbuf, ehdrlen +sizeof(struct ip6_hdr));
+                       sq->snd_buff[qentry].mbuf = NULL;
+                       if (mbuf == NULL)
+                               return (ENOBUFS);
+               }
+               poff = ip6_lasthdr(mbuf, ehdrlen, IPPROTO_IPV6, &proto);
+               if (poff < 0)
+                       return (ENOBUFS);
+               poff += ehdrlen;
+               break;
 #endif
 #ifdef INET
        case ETHERTYPE_IP:
@@ -1796,71 +1806,70 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qen
                ip = (struct ip *)(mbuf->m_data + ehdrlen);
                iphlen = ip->ip_hl << 2;
                poff = ehdrlen + iphlen;
+               proto = ip->ip_p;
+               break;
+#endif
+       default:
+               hdr->csum_l3 = 0;
+       }
 
-               if (mbuf->m_pkthdr.csum_flags != 0) {
-                       hdr->csum_l3 = 1; /* Enable IP csum calculation */
-                       switch (ip->ip_p) {
-                       case IPPROTO_TCP:
-                               if ((mbuf->m_pkthdr.csum_flags & CSUM_TCP) == 0)
-                                       break;
-
-                               if (mbuf->m_len < (poff + sizeof(struct 
tcphdr))) {
-                                       mbuf = m_pullup(mbuf, poff + 
sizeof(struct tcphdr));
-                                       sq->snd_buff[qentry].mbuf = mbuf;
-                                       if (mbuf == NULL)
-                                               return (ENOBUFS);
-                               }
-                               hdr->csum_l4 = SEND_L4_CSUM_TCP;
+#if defined(INET6) || defined(INET)
+       if (poff > 0 && mbuf->m_pkthdr.csum_flags != 0) {
+               hdr->csum_l3 = 1; /* Enable IP csum calculation */
+               switch (proto) {
+               case IPPROTO_TCP:
+                       if ((mbuf->m_pkthdr.csum_flags & CSUM_TCP) == 0)
                                break;
-                       case IPPROTO_UDP:
-                               if ((mbuf->m_pkthdr.csum_flags & CSUM_UDP) == 0)
-                                       break;
 
-                               if (mbuf->m_len < (poff + sizeof(struct 
udphdr))) {
-                                       mbuf = m_pullup(mbuf, poff + 
sizeof(struct udphdr));
-                                       sq->snd_buff[qentry].mbuf = mbuf;
-                                       if (mbuf == NULL)
-                                               return (ENOBUFS);
-                               }
-                               hdr->csum_l4 = SEND_L4_CSUM_UDP;
+                       if (mbuf->m_len < (poff + sizeof(struct tcphdr))) {
+                               mbuf = m_pullup(mbuf, poff + sizeof(struct 
tcphdr));
+                               sq->snd_buff[qentry].mbuf = mbuf;
+                               if (mbuf == NULL)
+                                       return (ENOBUFS);
+                       }
+                       hdr->csum_l4 = SEND_L4_CSUM_TCP;
+                       break;
+               case IPPROTO_UDP:
+                       if ((mbuf->m_pkthdr.csum_flags & CSUM_UDP) == 0)
                                break;
-                       case IPPROTO_SCTP:
-                               if ((mbuf->m_pkthdr.csum_flags & CSUM_SCTP) == 
0)
-                                       break;
 
-                               if (mbuf->m_len < (poff + sizeof(struct 
sctphdr))) {
-                                       mbuf = m_pullup(mbuf, poff + 
sizeof(struct sctphdr));
-                                       sq->snd_buff[qentry].mbuf = mbuf;
-                                       if (mbuf == NULL)
-                                               return (ENOBUFS);
-                               }
-                               hdr->csum_l4 = SEND_L4_CSUM_SCTP;
+                       if (mbuf->m_len < (poff + sizeof(struct udphdr))) {
+                               mbuf = m_pullup(mbuf, poff + sizeof(struct 
udphdr));
+                               sq->snd_buff[qentry].mbuf = mbuf;
+                               if (mbuf == NULL)
+                                       return (ENOBUFS);
+                       }
+                       hdr->csum_l4 = SEND_L4_CSUM_UDP;
+                       break;
+               case IPPROTO_SCTP:
+                       if ((mbuf->m_pkthdr.csum_flags & CSUM_SCTP) == 0)
                                break;
-                       default:
-                               break;
+
+                       if (mbuf->m_len < (poff + sizeof(struct sctphdr))) {
+                               mbuf = m_pullup(mbuf, poff + sizeof(struct 
sctphdr));
+                               sq->snd_buff[qentry].mbuf = mbuf;
+                               if (mbuf == NULL)
+                                       return (ENOBUFS);
                        }
-                       hdr->l3_offset = ehdrlen;
-                       hdr->l4_offset = ehdrlen + iphlen;
+                       hdr->csum_l4 = SEND_L4_CSUM_SCTP;
+                       break;
+               default:
+                       break;
                }
+               hdr->l3_offset = ehdrlen;
+               hdr->l4_offset = poff;
+       }
 
-               if ((mbuf->m_pkthdr.tso_segsz != 0) && nic->hw_tso) {
-                       /*
-                        * Extract ip again as m_data could have been modified.
-                        */
-                       ip = (struct ip *)(mbuf->m_data + ehdrlen);
-                       th = (struct tcphdr *)((caddr_t)ip + iphlen);
+       if ((mbuf->m_pkthdr.tso_segsz != 0) && nic->hw_tso) {
+               th = (struct tcphdr *)((caddr_t)(mbuf->m_data + poff));
 
-                       hdr->tso = 1;
-                       hdr->tso_start = ehdrlen + iphlen + (th->th_off * 4);
-                       hdr->tso_max_paysize = mbuf->m_pkthdr.tso_segsz;
-                       hdr->inner_l3_offset = ehdrlen - 2;
-                       nic->drv_stats.tx_tso++;
-               }
-               break;
-#endif
-       default:
-               hdr->csum_l3 = 0;
+               hdr->tso = 1;
+               hdr->tso_start = poff + (th->th_off * 4);
+               hdr->tso_max_paysize = mbuf->m_pkthdr.tso_segsz;
+               hdr->inner_l3_offset = ehdrlen - 2;
+               nic->drv_stats.tx_tso++;
        }
+#endif
 
        return (0);
 }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to