Date: Mon, 23 Feb 2004 18:02:52 +0100 From: Andre Oppermann <andre@freebsd.org> To: Alexander Motin <mav@alkar.net> Cc: freebsd-ipfw@freebsd.org Subject: Re: Generating 'Fragment Needed but DF was Set' ICMP & Dummynet Message-ID: <403A323C.A8685981@freebsd.org> References: <c0soic$1njq$2@pandora.alkar.net.lucky.freebsd.net> <c1d9id$10qf$1@pandora.alkar.net>
next in thread | previous in thread | raw e-mail | index | archive | help
Alexander Motin wrote: > > Here are my patches for this problem for FreeBSD 4.8 and 5.2. > Review them please. Doing a mcopy is pretty ugly... but ip_output() doesn't offer any way of saying "don't flush packet but leave it for icmp error messages". So the better fix would be to teach that to ip_output() and change the callers accordingly. Actually I'll have a patch to do that ready in a couple of hours. Then I'll commit your patch w/o the packet copying stuff. Good catch Alexander, send more(1)! :-) -- Andre > 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 > > -------------------------------------------------------------------------------- > --- 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 ; > > > -------------------------------------------------------------------------------- > --- 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 ; > > > -------------------------------------------------------------------------------- > _______________________________________________ > freebsd-net@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-net > To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org"
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?403A323C.A8685981>