When a host want to send packets to a destination whose Ethernet address
that has not been resolved yet, it puts such packet on a mbuf queue.

Right now this queue, linked to the corresponding ARP data structure, is
hand rolled.  I wrote the diff below during s2k15 to make use of the
mq_enqueue(9) API instead.

I verified that the queue is correctly dropped when an infinite recursion
in in_arpinput() is triggered.

Comments, Ok?

Index: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.148
diff -u -p -r1.148 if_ether.c
--- netinet/if_ether.c  14 Mar 2015 17:13:44 -0000      1.148
+++ netinet/if_ether.c  19 Mar 2015 13:04:28 -0000
@@ -69,7 +69,6 @@
 #endif
 
 #define SDL(s) ((struct sockaddr_dl *)s)
-#define SRP(s) ((struct sockaddr_inarp *)s)
 
 /*
  * ARP trailer negotiation.  Trailer protocol is not IP specific,
@@ -77,6 +76,15 @@
  */
 #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
 
+struct llinfo_arp {
+       LIST_ENTRY(llinfo_arp)   la_list;
+       struct rtentry          *la_rt;         /* backpointer to rtentry */
+       long                     la_asked;      /* last time we QUERIED */
+       struct mbuf_queue        la_mq;         /* packet hold queue */
+};
+#define LA_HOLD_QUEUE 10
+#define LA_HOLD_TOTAL 100
+
 /* timer values */
 int    arpt_prune = (5*60*1);  /* walk list every 5 minutes */
 int    arpt_keep = (20*60);    /* once resolved, good for 20 more minutes */
@@ -220,6 +228,7 @@ arp_rtrequest(int req, struct rtentry *r
                 * add with a LL address.
                 */
                la = pool_get(&arp_pool, PR_NOWAIT | PR_ZERO);
+               mq_init(&la->la_mq, LA_HOLD_QUEUE, IPL_NONE);
                rt->rt_llinfo = (caddr_t)la;
                if (la == NULL) {
                        log(LOG_DEBUG, "%s: malloc failed\n", __func__);
@@ -282,8 +291,7 @@ arp_rtrequest(int req, struct rtentry *r
                LIST_REMOVE(la, la_list);
                rt->rt_llinfo = 0;
                rt->rt_flags &= ~RTF_LLINFO;
-               while ((m = la->la_hold_head) != NULL) {
-                       la->la_hold_head = la->la_hold_head->m_nextpkt;
+               while ((m = mq_dequeue(&la->la_mq)) != NULL) {
                        la_hold_total--;
                        m_freem(m);
                }
@@ -425,32 +433,14 @@ arpresolve(struct arpcom *ac, struct rte
         * response yet. Insert mbuf in hold queue if below limit
         * if above the limit free the queue without queuing the new packet.
         */
-       if (la_hold_total < MAX_HOLD_TOTAL && la_hold_total < nmbclust / 64) {
-               if (la->la_hold_count >= MAX_HOLD_QUEUE) {
-                       mh = la->la_hold_head;
-                       la->la_hold_head = la->la_hold_head->m_nextpkt;
-                       if (mh == la->la_hold_tail)
-                               la->la_hold_tail = NULL;
-                       la->la_hold_count--;
-                       la_hold_total--;
-                       m_freem(mh);
-               }
-               if (la->la_hold_tail == NULL)
-                       la->la_hold_head = m;
-               else
-                       la->la_hold_tail->m_nextpkt = m;
-               la->la_hold_tail = m;
-               la->la_hold_count++;
-               la_hold_total++;
+       if (la_hold_total < LA_HOLD_TOTAL && la_hold_total < nmbclust / 64) {
+               if (mq_enqueue(&la->la_mq, m) == 0)
+                       la_hold_total++;
        } else {
-               while ((mh = la->la_hold_head) != NULL) {
-                       la->la_hold_head =
-                           la->la_hold_head->m_nextpkt;
+               while ((mh = mq_dequeue(&la->la_mq)) != NULL) {
                        la_hold_total--;
                        m_freem(mh);
                }
-               la->la_hold_tail = NULL;
-               la->la_hold_count = 0;
                m_freem(m);
        }
 
@@ -483,14 +473,10 @@ arpresolve(struct arpcom *ac, struct rte
                                rt->rt_flags |= RTF_REJECT;
                                rt->rt_expire += arpt_down;
                                la->la_asked = 0;
-                               while ((mh = la->la_hold_head) != NULL) {
-                                       la->la_hold_head =
-                                           la->la_hold_head->m_nextpkt;
+                               while ((mh = mq_dequeue(&la->la_mq)) != NULL) {
                                        la_hold_total--;
                                        m_freem(mh);
                                }
-                               la->la_hold_tail = NULL;
-                               la->la_hold_count = 0;
                        }
                }
        }
@@ -570,13 +556,14 @@ in_arpinput(struct mbuf *m)
        struct sockaddr_dl *sdl;
        struct sockaddr sa;
        struct in_addr isaddr, itaddr, myaddr;
-       struct mbuf *mh, *mt;
+       struct mbuf *mh;
        u_int8_t *enaddr = NULL;
 #if NCARP > 0
        u_int8_t *ether_shost = NULL;
 #endif
        char addr[INET_ADDRSTRLEN];
        int op, changed = 0;
+       unsigned int len;
 
        ea = mtod(m, struct ether_arp *);
        op = ntohs(ea->arp_op);
@@ -732,25 +719,19 @@ in_arpinput(struct mbuf *m)
                if (la->la_asked || changed)
                        rt_sendmsg(rt, RTM_RESOLVE, rt->rt_ifp->if_rdomain);
                la->la_asked = 0;
-               while ((mh = la->la_hold_head) != NULL) {
-                       if ((la->la_hold_head = mh->m_nextpkt) == NULL)
-                               la->la_hold_tail = NULL;
-                       la->la_hold_count--;
+               while ((len = mq_len(&la->la_mq)) != 0) {
+                       mh = mq_dequeue(&la->la_mq);
                        la_hold_total--;
-                       mt = la->la_hold_tail;
 
                        (*ac->ac_if.if_output)(&ac->ac_if, mh, rt_key(rt), rt);
 
-                       if (la->la_hold_tail == mh) {
+                       if (mq_len(&la->la_mq) == len) {
                                /* mbuf is back in queue. Discard. */
-                               la->la_hold_tail = mt;
-                               if (la->la_hold_tail)
-                                       la->la_hold_tail->m_nextpkt = NULL;
-                               else
-                                       la->la_hold_head = NULL;
-                               la->la_hold_count--;
-                               la_hold_total--;
-                               m_freem(mh);
+                               while ((mh = mq_dequeue(&la->la_mq)) != NULL) {
+                                       la_hold_total--;
+                                       m_freem(mh);
+                               }
+                               break;
                        }
                }
        }
@@ -1114,8 +1095,7 @@ db_print_llinfo(caddr_t li)
        if (li == 0)
                return;
        la = (struct llinfo_arp *)li;
-       db_printf("  la_rt=%p la_hold_head=%p, la_asked=0x%lx\n",
-           la->la_rt, la->la_hold_head, la->la_asked);
+       db_printf("  la_rt=%p la_asked=0x%lx\n", la->la_rt, la->la_asked);
 }
 
 /*

Reply via email to