Generating 'Fragment Needed but DF was Set' ICMP & Dummynet
Andre Oppermann
andre at freebsd.org
Mon Feb 23 09:02:59 PST 2004
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 at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-net
> To unsubscribe, send any mail to "freebsd-net-unsubscribe at freebsd.org"
More information about the freebsd-net
mailing list