Skip site navigation (1)Skip section navigation (2)
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>