Bug #26 ยป vlan1.diff
| sys/net/vlan/if_vlan.c 30 Dec 2005 00:24:00 -0000 | ||
|---|---|---|
|
altq_etherclassify(&p->if_snd, m, &pktattr);
|
||
|
/*
|
||
|
* If the LINK0 flag is set, it means the underlying interface
|
||
|
* can do VLAN tag insertion itself and doesn't require us to
|
||
|
* create a special header for it. In this case, we just pass
|
||
|
* the packet along. However, we need some way to tell the
|
||
|
* interface where the packet came from so that it knows how
|
||
|
* to find the VLAN tag to use, so we set the rcvif in the
|
||
|
* mbuf header to our ifnet.
|
||
|
* If underlying interface can do VLAN tag insertion itself,
|
||
|
* just pass the packet along. However, we need some way to
|
||
|
* tell the interface where the packet came from so that it
|
||
|
* knows how to find the VLAN tag to use, so we set the rcvif
|
||
|
* in the mbuf header to our ifnet.
|
||
|
*
|
||
|
* Note: we also set the M_PROTO1 flag in the mbuf to let
|
||
|
* the parent driver know that the rcvif pointer is really
|
||
| ... | ... | |
|
* following potentially bogus rcvif pointers off into
|
||
|
* never-never land.
|
||
|
*/
|
||
|
if (ifp->if_flags & IFF_LINK0) {
|
||
|
if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
|
||
|
m->m_pkthdr.rcvif = ifp;
|
||
|
m->m_flags |= M_PROTO1;
|
||
|
} else {
|
||
| ... | ... | |
|
{
|
||
|
struct bpf_if *bif;
|
||
|
struct ifvlan *ifv;
|
||
|
struct ether_header *eh = mtod(m, struct ether_header *);
|
||
|
struct ifnet *rcvif;
|
||
|
m_adj(m, ETHER_HDR_LEN);
|
||
|
rcvif = m->m_pkthdr.rcvif;
|
||
|
ASSERT_SERIALIZED(rcvif->if_serializer);
|
||
| ... | ... | |
|
* bpf tap if active.
|
||
|
*/
|
||
|
if ((bif = rcvif->if_bpf) != NULL) {
|
||
|
struct ether_header *eh;
|
||
|
struct ether_vlan_header evh;
|
||
|
eh = mtod(m, struct ether_header *);
|
||
|
m_adj(m, ETHER_HDR_LEN);
|
||
|
bcopy(eh, &evh, 2*ETHER_ADDR_LEN);
|
||
|
evh.evl_encap_proto = htons(ETHERTYPE_VLAN);
|
||
|
evh.evl_tag = htons(t);
|
||
|
evh.evl_proto = eh->ether_type;
|
||
|
bpf_ptap(bif, m, &evh, ETHER_HDR_LEN + EVL_ENCAPLEN);
|
||
|
/* XXX assumes data was left intact */
|
||
|
M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT);
|
||
|
}
|
||
|
for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
|
||
| ... | ... | |
|
ifv->ifv_if.if_ipackets++;
|
||
|
lwkt_serialize_exit(rcvif->if_serializer);
|
||
|
lwkt_serialize_enter(ifv->ifv_if.if_serializer);
|
||
|
ether_input(&ifv->ifv_if, eh, m);
|
||
|
ether_input(&ifv->ifv_if, NULL, m);
|
||
|
lwkt_serialize_exit(ifv->ifv_if.if_serializer);
|
||
|
lwkt_serialize_enter(rcvif->if_serializer);
|
||
|
return 0;
|
||
| ... | ... | |
|
{
|
||
|
struct ifvlan *ifv;
|
||
|
struct ifnet *rcvif;
|
||
|
struct ether_header eh_copy;
|
||
|
rcvif = m->m_pkthdr.rcvif;
|
||
|
ASSERT_SERIALIZED(rcvif->if_serializer);
|
||
| ... | ... | |
|
/*
|
||
|
* Having found a valid vlan interface corresponding to
|
||
|
* the given source interface and vlan tag, remove the
|
||
|
* encapsulation, and run the real packet through
|
||
|
* ether_input() a second time (it had better be
|
||
|
* remaining encapsulation (ether_vlan_header minus the ether_header
|
||
|
* that had already been removed) and run the real packet
|
||
|
* through ether_input() a second time (it had better be
|
||
|
* reentrant!).
|
||
|
*/
|
||
|
eh_copy = *eh;
|
||
|
eh_copy.ether_type = mtod(m, u_int16_t *)[1]; /* evl_proto */
|
||
|
m->m_pkthdr.rcvif = &ifv->ifv_if;
|
||
|
eh->ether_type = mtod(m, u_int16_t *)[1];
|
||
|
m->m_data += EVL_ENCAPLEN;
|
||
|
m->m_len -= EVL_ENCAPLEN;
|
||
|
m->m_pkthdr.len -= EVL_ENCAPLEN;
|
||
|
m_adj(m, EVL_ENCAPLEN);
|
||
|
M_PREPEND(m, ETHER_HDR_LEN, MB_WAIT);
|
||
|
*(struct ether_header *)mtod(m, void *) = eh_copy;
|
||
|
ifv->ifv_if.if_ipackets++;
|
||
|
lwkt_serialize_exit(rcvif->if_serializer);
|
||
|
lwkt_serialize_enter(ifv->ifv_if.if_serializer);
|
||
|
ether_input(&ifv->ifv_if, eh, m);
|
||
|
ether_input(&ifv->ifv_if, NULL, m);
|
||
|
lwkt_serialize_exit(ifv->ifv_if.if_serializer);
|
||
|
lwkt_serialize_enter(rcvif->if_serializer);
|
||
|
return 0;
|
||
| ... | ... | |
|
if (ifv->ifv_p)
|
||
|
return EBUSY;
|
||
|
ifv->ifv_p = p;
|
||
|
if (p->if_data.ifi_hdrlen == sizeof(struct ether_vlan_header))
|
||
|
if (p->if_capenable & IFCAP_VLAN_MTU)
|
||
|
ifv->ifv_if.if_mtu = p->if_mtu;
|
||
|
else
|
||
|
ifv->ifv_if.if_mtu = p->if_data.ifi_mtu - EVL_ENCAPLEN;
|
||
| share/man/man4/vlan.4 30 Dec 2005 00:00:41 -0000 | ||
|---|---|---|
|
.Pp
|
||
|
The
|
||
|
.Nm
|
||
|
driver supports physical devices that do
|
||
|
the VLAN demultiplexing in firmware.
|
||
|
The
|
||
|
.Cm link0
|
||
|
flag should be set on a
|
||
|
.Nm
|
||
|
interface
|
||
|
.Pq Em not on its parent
|
||
|
using
|
||
|
.Xr ifconfig 8
|
||
|
in that case to indicate that hardware support for
|
||
|
the 802.1Q VLANs is present in its parent.
|
||
|
driver supports efficient operation over parent interfaces that can provide
|
||
|
help in processing VLANs.
|
||
|
Such interfaces are automatically recognized by their capabilities.
|
||
|
Depending on the level of sophistication found in a physical
|
||
|
interface, it may do full VLAN processing or just be able to
|
||
|
receive and transmit frames exceeding the maximum Ethernet frame size
|
||
|
by the length of a 802.1Q header.
|
||
|
The capabilities may be user-controlled by the respective parameters to
|
||
|
.Xr ifconfig 8 ,
|
||
|
.Cm vlanhwtag
|
||
|
and
|
||
|
.Cm vlanmtu .
|
||
|
However, a physical interface is not obliged to react to them:
|
||
|
It may have either capability enabled permanently without
|
||
|
a way to turn it off.
|
||
|
The whole issue is very specific to a particular device and its driver.
|
||
|
.\"
|
||
|
.Ss "Selecting the Right Network Interface Card to Run VLANs Through"
|
||
|
By now, the only NICs that have both hardware support and proper
|
||
| ... | ... | |
|
.Xr em 4 ,
|
||
|
.Xr gx 4 ,
|
||
|
.Xr nge 4 ,
|
||
|
.Xr re 4 ,
|
||
|
.Xr ti 4 ,
|
||
|
and
|
||
|
.Xr txp 4 .
|
||