Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Feb 2004 18:25:49 +0200
From:      Alexander Motin <mav@alkar.net>
To:        freebsd-net@freebsd.org, freebsd-ipfw@freebsd.org
Subject:   Re: Generating 'Fragment Needed but DF was Set' ICMP & Dummynet
Message-ID:  <c1d9id$10qf$1@pandora.alkar.net>
In-Reply-To: <c0soic$1njq$2@pandora.alkar.net.lucky.freebsd.net>
References:  <c0soic$1njq$2@pandora.alkar.net.lucky.freebsd.net>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------080204090202030100030402
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Here are my patches for this problem for FreeBSD 4.8 and 5.2.
Review them please.

Alexander Motin wrote:
> I observe a strange thing. When I create dummynet pipe on output router 
> interface with lower MTU system stops to generate 'Fragment Needed but 
> DF was Set' ICMP in cases when it must. If I create this pipe on 
> incoming interface there is no problem.
> 
> I check this on many routers under 4.8 and 5.2 FreeBSD.
> 
> Is this a bug or feature? :) How pipes can be created leaving ICMP 
> generation working?

-- 
Alexander Motin

--------------080204090202030100030402
Content-Type: text/plain;
 name="dn_df_48.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="dn_df_48.patch"

--- ip_dummynet.c.orig	Wed May 28 01:36:02 2003
+++ ip_dummynet.c	Sat Feb 21 12:49:11 2004
@@ -81,6 +81,7 @@
 #include <netinet/ip_fw.h>
 #include <netinet/ip_dummynet.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
 
 #include <netinet/if_ether.h> /* for struct arpcom */
 #include <net/bridge.h>
@@ -407,6 +408,9 @@
 transmit_event(struct dn_pipe *pipe)
 {
     struct dn_pkt *pkt ;
+    struct mbuf *mcopy;
+    struct ip *ip;
+    int error, type, code;
 
     while ( (pkt = pipe->head) && DN_KEY_LEQ(pkt->output_time, curr_time) ) {
 	/*
@@ -426,7 +430,39 @@
 	 */
 	switch (pkt->dn_dir) {
 	case DN_TO_IP_OUT:
-	    (void)ip_output((struct mbuf *)pkt, NULL, NULL, 0, NULL, NULL);
+	    MGET(mcopy, M_DONTWAIT, pkt->dn_m->m_type);
+	    if (mcopy != NULL && !m_dup_pkthdr(mcopy, pkt->dn_m, M_DONTWAIT)) {
+		m_free(mcopy);
+		mcopy = NULL;
+	    }
+	    if (mcopy != NULL) {
+		ip = mtod(pkt->dn_m, struct ip *);
+		mcopy->m_len = imin((ip->ip_hl << 2) + 8,
+		    (int)ip->ip_len);
+		m_copydata(pkt->dn_m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
+	    }
+	    
+	    error = ip_output((struct mbuf *)pkt, NULL, NULL, 0, NULL, NULL);
+	    
+	    if (mcopy != NULL) {
+		switch (error) {
+		    case ENETUNREACH:
+		    case EHOSTUNREACH:
+		    case ENETDOWN:
+		    case EHOSTDOWN:
+			type = ICMP_UNREACH;
+		        code = ICMP_UNREACH_HOST;
+			icmp_error(mcopy, type, code, 0, pkt->ifp);
+			break;
+		    case EMSGSIZE:
+			type = ICMP_UNREACH;
+		        code = ICMP_UNREACH_NEEDFRAG;
+			icmp_error(mcopy, type, code, 0, pkt->ifp);
+			break;
+		    default:
+			m_freem(mcopy);
+		};
+	    };
 	    rt_unref (pkt->ro.ro_rt) ;
 	    break ;
 

--------------080204090202030100030402
Content-Type: text/plain;
 name="dn_df_52.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="dn_df_52.patch"

--- ip_dummynet.c.orig	Mon Dec  8 11:50:54 2003
+++ ip_dummynet.c	Sat Feb 21 12:17:44 2004
@@ -73,6 +73,7 @@
 #include <netinet/ip_fw.h>
 #include <netinet/ip_dummynet.h>
 #include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
 
 #include <netinet/if_ether.h> /* for struct arpcom */
 #include <net/bridge.h>
@@ -426,6 +427,9 @@
 transmit_event(struct dn_pipe *pipe)
 {
     struct dn_pkt *pkt ;
+    struct mbuf *mcopy;
+    struct ip *ip;
+    int error, type, code;
 
     DUMMYNET_LOCK_ASSERT();
 
@@ -449,7 +453,39 @@
 	 */
 	switch (pkt->dn_dir) {
 	case DN_TO_IP_OUT:
-	    (void)ip_output((struct mbuf *)pkt, NULL, NULL, 0, NULL, NULL);
+	    MGET(mcopy, M_DONTWAIT, pkt->dn_m->m_type);
+	    if (mcopy != NULL && !m_dup_pkthdr(mcopy, pkt->dn_m, M_DONTWAIT)) {
+		m_free(mcopy);
+		mcopy = NULL;
+	    }
+	    if (mcopy != NULL) {
+		ip = mtod(pkt->dn_m, struct ip *);
+		mcopy->m_len = imin((ip->ip_hl << 2) + 8,
+		    (int)ip->ip_len);
+		m_copydata(pkt->dn_m, 0, mcopy->m_len, mtod(mcopy, caddr_t));
+	    }
+	    
+	    error = ip_output((struct mbuf *)pkt, NULL, NULL, 0, NULL, NULL);
+	    
+	    if (mcopy != NULL) {
+		switch (error) {
+		    case ENETUNREACH:
+		    case EHOSTUNREACH:
+		    case ENETDOWN:
+		    case EHOSTDOWN:
+			type = ICMP_UNREACH;
+		        code = ICMP_UNREACH_HOST;
+			icmp_error(mcopy, type, code, 0, pkt->ifp);
+			break;
+		    case EMSGSIZE:
+			type = ICMP_UNREACH;
+		        code = ICMP_UNREACH_NEEDFRAG;
+			icmp_error(mcopy, type, code, 0, pkt->ifp);
+			break;
+		    default:
+			m_freem(mcopy);
+		};
+	    };
 	    rt_unref (pkt->ro.ro_rt, __func__) ;
 	    break ;
 

--------------080204090202030100030402--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?c1d9id$10qf$1>