Re: Generating 'Fragment Needed but DF was Set' ICMP & Dummynet

From: Andre Oppermann (andre_at_freebsd.org)
Date: 02/23/04

  • Next message: Max Laier: "Re: Generating 'Fragment Needed but DF was Set' ICMP & Dummynet"
    Date: Mon, 23 Feb 2004 18:02:52 +0100
    To: Alexander Motin <mav@alkar.net>
    
    

    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"
    _______________________________________________
    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"
    

  • Next message: Max Laier: "Re: Generating 'Fragment Needed but DF was Set' ICMP & Dummynet"