Allow a gif tunnel to be used with ALTq.

Reviewed by:	gnn
This commit is contained in:
Randall Stewart 2012-06-12 10:44:09 +00:00
parent faf0db351d
commit 776b728856
1 changed files with 102 additions and 46 deletions

View File

@ -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) {
#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:
/* 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;
}
GIF_UNLOCK(sc);
#ifdef ALTQ
/* Make altq aware of the bytes we will add
* when we actually send it.
*/
#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
/*
* 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++;