summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2012-06-12 10:44:09 +0000
committerrrs <rrs@FreeBSD.org>2012-06-12 10:44:09 +0000
commit813f2809c580633e12abec8bd0f7599ee0865661 (patch)
tree89792661fcd3d6ed05be74a652d968d2fb8a3615 /sys/net
parentbcf3f4263d67f83311b4d5db42c220f7fa151990 (diff)
downloadFreeBSD-src-813f2809c580633e12abec8bd0f7599ee0865661.zip
FreeBSD-src-813f2809c580633e12abec8bd0f7599ee0865661.tar.gz
Allow a gif tunnel to be used with ALTq.
Reviewed by: gnn
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if_gif.c148
1 files changed, 102 insertions, 46 deletions
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 350611d..56796d7 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -342,26 +342,98 @@ gif_encapcheck(m, off, proto, arg)
return 0;
}
}
+#ifdef INET
+#define GIF_HDR_LEN (ETHER_HDR_LEN + sizeof (struct ip))
+#endif
+#ifdef INET6
+#define GIF_HDR_LEN6 (ETHER_HDR_LEN + sizeof (struct ip6_hdr))
+#endif
static void
gif_start(struct ifnet *ifp)
{
struct gif_softc *sc;
struct mbuf *m;
+ uint32_t af;
+ int error = 0;
sc = ifp->if_softc;
-
+ GIF_LOCK(sc);
+ if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
+ /* Already active */
+ ifp->if_drv_flags |= IFF_GIF_WANTED;
+ GIF_UNLOCK(sc);
+ return;
+ }
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- for (;;) {
- IFQ_DEQUEUE(&ifp->if_snd, m);
+ GIF_UNLOCK(sc);
+keep_going:
+ while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) {
+
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
if (m == 0)
break;
- gif_output(ifp, m, sc->gif_pdst, NULL);
+#ifdef ALTQ
+ /* Take out those altq bytes we add in gif_output */
+#ifdef INET
+ if (sc->gif_psrc->sa_family == AF_INET)
+ m->m_pkthdr.len -= GIF_HDR_LEN;
+#endif
+#ifdef INET6
+ if (sc->gif_psrc->sa_family == AF_INET6)
+ m->m_pkthdr.len -= GIF_HDR_LEN6;
+#endif
+#endif
+ /* Now pull back the af in packet that
+ * was saved in the address location.
+ */
+ bcopy(m->m_pkthdr.src_mac_addr, &af, sizeof(af));
+ if (ifp->if_bridge)
+ af = AF_LINK;
+
+ BPF_MTAP2(ifp, &af, sizeof(af), m);
+ ifp->if_opackets++;
+
+/* Done by IFQ_HANDOFF */
+/* ifp->if_obytes += m->m_pkthdr.len;*/
+ /* override to IPPROTO_ETHERIP for bridged traffic */
+
+ M_SETFIB(m, sc->gif_fibnum);
+ /* inner AF-specific encapsulation */
+ /* XXX should we check if our outer source is legal? */
+ /* dispatch to output logic based on outer AF */
+ switch (sc->gif_psrc->sa_family) {
+#ifdef INET
+ case AF_INET:
+ error = in_gif_output(ifp, af, m);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ error = in6_gif_output(ifp, af, m);
+ break;
+#endif
+ default:
+ m_freem(m);
+ error = ENETDOWN;
+ }
+ if (error)
+ ifp->if_oerrors++;
}
+ GIF_LOCK(sc);
+ if (ifp->if_drv_flags & IFF_GIF_WANTED) {
+ /* Someone did a start while
+ * we were unlocked and processing
+ * lets clear the flag and try again.
+ */
+ ifp->if_drv_flags &= ~IFF_GIF_WANTED;
+ GIF_UNLOCK(sc);
+ goto keep_going;
+ }
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
-
+ GIF_UNLOCK(sc);
return;
}
@@ -376,8 +448,7 @@ gif_output(ifp, m, dst, ro)
struct m_tag *mtag;
int error = 0;
int gif_called;
- u_int32_t af;
-
+ uint32_t af;
#ifdef MAC
error = mac_ifnet_check_transmit(ifp, m);
if (error) {
@@ -426,55 +497,40 @@ gif_output(ifp, m, dst, ro)
m_tag_prepend(m, mtag);
m->m_flags &= ~(M_BCAST|M_MCAST);
-
- GIF_LOCK(sc);
-
- if (!(ifp->if_flags & IFF_UP) ||
- sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
- GIF_UNLOCK(sc);
- m_freem(m);
- error = ENETDOWN;
- goto end;
- }
-
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC) {
bcopy(dst->sa_data, &af, sizeof(af));
dst->sa_family = af;
}
-
af = dst->sa_family;
- BPF_MTAP2(ifp, &af, sizeof(af), m);
- ifp->if_opackets++;
- ifp->if_obytes += m->m_pkthdr.len;
-
- /* override to IPPROTO_ETHERIP for bridged traffic */
- if (ifp->if_bridge)
- af = AF_LINK;
-
- M_SETFIB(m, sc->gif_fibnum);
- /* inner AF-specific encapsulation */
-
- /* XXX should we check if our outer source is legal? */
-
- /* dispatch to output logic based on outer AF */
- switch (sc->gif_psrc->sa_family) {
+ /* Now save the af in the inbound pkt mac
+ * address location.
+ */
+ bcopy(&af, m->m_pkthdr.src_mac_addr, sizeof(af));
+ if (!(ifp->if_flags & IFF_UP) ||
+ sc->gif_psrc == NULL || sc->gif_pdst == NULL) {
+ m_freem(m);
+ error = ENETDOWN;
+ goto end;
+ }
+#ifdef ALTQ
+ /* Make altq aware of the bytes we will add
+ * when we actually send it.
+ */
#ifdef INET
- case AF_INET:
- error = in_gif_output(ifp, af, m);
- break;
+ if (sc->gif_psrc->sa_family == AF_INET)
+ m->m_pkthdr.len += GIF_HDR_LEN;
#endif
#ifdef INET6
- case AF_INET6:
- error = in6_gif_output(ifp, af, m);
- break;
+ if (sc->gif_psrc->sa_family == AF_INET6)
+ m->m_pkthdr.len += GIF_HDR_LEN6;
#endif
- default:
- m_freem(m);
- error = ENETDOWN;
- }
-
- GIF_UNLOCK(sc);
+#endif
+ /*
+ * Queue message on interface, update output statistics if
+ * successful, and start output if interface not yet active.
+ */
+ IFQ_HANDOFF(ifp, m, error);
end:
if (error)
ifp->if_oerrors++;
OpenPOWER on IntegriCloud