Update, if_vether(4) refactored and to if_bridge(4) dedicated extensions
reimplemented.

Now, if_vether(4) denotes own interface type constant. Further,
net/if_ethersubr.c was extended by

	void	(*vether_pppoe_proxy_change_p)(struct ifnet *,
		struct ether_header *, struct pppoe_hdr *);

and

	struct mbuf *	(*vether_pppoe_proxy_p)(struct ifnet *,
		struct mbuf *);

whose maps to subr performing rfc-2516 proxyfieing tasks in net/if_vether.c,
if IPv[46] SDU are throught by if_bridge(4) IAP diverted from rfc-2516
downstream. Vether_pppoe_proxy_change() maps rfc-2516 session identifier
to instnace of if_vether(4) if any is if_bridge(4) member and proxyfieing
is enabled. Any instance of if_vether(4) maps to OID subtree of

	net.link.ether

during interface lifetime. Suppose vether0

	# sysctl net.link.ether.vether0.pppoe_proxy=1

enables this feature. If there were was IPv[46] PDU diverted by if_bridge(4)
dedicated IAP from rfc-2516 downstream, if_vether(4) is capable to reinject
them by vether_pppoe_proxy(). Running instance inherites lla (FEC) of remote
site where BRAS remains.

ATTENTION - DUE TO THIS COMMIT, THIS FEATURUE IS STILL UNTESTED. BUT,
I'M TESTING THIS STUFF AT THIS MOMENT. PURPOSE OF THIS COMMIT IS TO
SHOW UP PROGRESS DUE TO ONGOING IMPLEMENTAION ISSUES AND MAY UNDERSTAND
AS DVELOPEMENT STATUS REPORT!

	Any interface maps to an instance of if_brigde(4) passes incomming frames
to if_bridge(4) to distinguish if either frame destined member interface for
local processing or for forwarding by if_bridge(4). Instances of if_vether(4)
operates as communication endpoints, this implies that no running instance of
if_bridge(4) is allowed forward any received frame. I've itroduced IFT_VETHER
as constant (see net/if_types.h) to identify instances of if_vether(4), if
they are if_bridge(4) member, e. g.

	if (ifp->if_type == IFT_VETHER)
		return (m);

in bridge_input(). This step, was neccessary to avoid broadcast storm, if an
instance of if_vether(4) receives frames with multi- / broadcast destination
address.
	It is obvious that frame IO by if_vether(4) depends on if_bridge(4),
further, sending of frames depends on bridge_output() and is implemented as
follos:

	if (m->m_pkthdr.rcvif == NULL) {
	/*
	 * Inject frames into if_bridge(4), if they
	 * are in ETHERTYPE_PPPOE[DISC] and injected
	 * by ng_ether(4) on downstream hook.
	 *
	 * Any frame which are not injected by netgraph(4)
	 * is transmitted by bridge_output() in ether_output().
	 */
			switch (ether_type) {
			case ETHERTYPE_PPPOEDISC:
			case ETHERTYPE_PPPOE:	/* FALLTHROUGH */
				m->m_pkthdr.rcvif = ifp;
				BRIDGE_OUTPUT(ifp, m, error);
				break;
			default:
				m_freem(m);
				continue;
			}
		} else if (m->m_pkthdr.rcvif != ifp) {
			m->m_pkthdr.rcvif = ifp;
			(*ifp->if_input)(ifp, m);
		} else {
			m_freem(m);
			continue;
		}

in vether_start_locked().
	Further, due to introduced constant, minor changes took place in
ng_ether(4):

static void
ng_ether_ifnet_arrival_event(void *arg __unused, struct ifnet *ifp)
{
	char name[IFNAMSIZ];
	node_p node;

	/* Only ethernet interfaces are of interest. */
	if (ifp->if_type != IFT_ETHER
		&& ifp->if_type != IFT_VETHER /* XXX: applied constant */
	    && ifp->if_type != IFT_L2VLAN)
		return;

	/*
	 * Just return if it's a new interface without an ng_ether companion.
	 */
	node = IFP2NG(ifp);
	if (node == NULL)
		return;

	/* Try to give the node the same name as the new interface name */
	ng_ether_sanitize_ifname(ifp->if_xname, name);
	if (ng_name_node(node, name) != 0)
		log(LOG_WARNING, "%s: can't re-name node %s\n", __func__, name);
}

and

static void
vnet_ng_ether_init(const void *unused)
{
	struct ifnet *ifp;

	/* If module load was rejected, don't attach to vnets. */
	if (ng_ether_attach_p != ng_ether_attach)
		return;

	/* Create nodes for any already-existing Ethernet interfaces. */
	IFNET_RLOCK();
	TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
		if (ifp->if_type == IFT_ETHER
		    || ifp->if_type == IFT_VETHER /* XXX: applied constant */
		    || ifp->if_type == IFT_L2VLAN)
			ng_ether_attach(ifp);
	}
	IFNET_RUNLOCK();
}

which make ng_ether(4) make capable to register targeted instance of
if_vether(4) as Ethernet interface. Further, similar changes in if_bridge(4)
took place:

static void
bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
    int gone)
{
	struct ifnet *ifs = bif->bif_ifp;
	struct ifnet *fif = NULL;

	BRIDGE_LOCK_ASSERT(sc);

	if (bif->bif_flags & IFBIF_STP)
		bstp_disable(&bif->bif_stp);

	ifs->if_bridge = NULL;
	BRIDGE_XLOCK(sc);
	LIST_REMOVE(bif, bif_next);
	BRIDGE_XDROP(sc);

	/*
	 * If removing the interface that gave the bridge its mac address, set
	 * the mac address of the bridge to the address of the next member, or
	 * to its default address if no members are left.
	 */
	if (bridge_inherit_mac && sc->sc_ifaddr == ifs) {
		if (LIST_EMPTY(&sc->sc_iflist)) {
			bcopy(sc->sc_defaddr,
			    IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
			sc->sc_ifaddr = NULL;
		} else {
			fif = LIST_FIRST(&sc->sc_iflist)->bif_ifp;
			bcopy(IF_LLADDR(fif),
			    IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
			sc->sc_ifaddr = fif;
		}
		EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
	}

	bridge_linkcheck(sc);
	bridge_mutecaps(sc);	/* recalcuate now this interface is removed */
	bridge_rtdelete(sc, ifs, IFBF_FLUSHALL);
	KASSERT(bif->bif_addrcnt == 0,
	    ("%s: %d bridge routes referenced", __func__, bif->bif_addrcnt));

	BRIDGE_UNLOCK(sc);
	if (!gone) {
		switch (ifs->if_type) {
		case IFT_ETHER:
		case IFT_VETHER: /* XXX: applied constant */
		case IFT_L2VLAN:
			/*
			 * Take the interface out of promiscuous mode.
			 */
			(void) ifpromisc(ifs, 0);
			break;

		case IFT_GIF:
			break;
		case IFT_MPLS:
			if (MPLS_IFINFO_RT(ifs) != NULL) {
				GET_MPLS_IFINFO_RT(ifs)->mrt_flags &= ~MRT_PW2;
				GET_MPLS_IFINFO_RT(ifs)->mrt_nh_smpls.smpls_vprd = 0;
			}
			break;
		default:
			panic("bridge_delete_member: impossible");
			break;
		}
		/* reneable any interface capabilities */
		bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
	}
	bstp_destroy(&bif->bif_stp);	/* prepare to free */
	BRIDGE_LOCK(sc);
	free(bif, M_DEVBUF);
}

and

static int
bridge_ioctl_add(struct bridge_softc *sc, void *arg)
{
	struct ifbreq *req = arg;
	struct bridge_iflist *bif = NULL;
	struct ifnet *ifs;
	int error = 0;

	ifs = ifunit(req->ifbr_ifsname);
	if (ifs == NULL)
		return (ENOENT);
	if (ifs->if_ioctl == NULL)	/* must be supported */
		return (EINVAL);

	/* If it's in the span list, it can't be a member. */
	LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
		if (ifs == bif->bif_ifp)
			return (EBUSY);

	if (ifs->if_bridge == sc)
		return (EEXIST);

	if (ifs->if_bridge != NULL)
		return (EBUSY);

	switch (ifs->if_type) {
	case IFT_ETHER:
	case IFT_VETHER: /* XXX: applied constant */
	case IFT_L2VLAN:
	case IFT_GIF:
		/* permitted interface types */
		break;
	case IFT_MPLS:
		if (MPLS_IFINFO_RT(ifs) != NULL) {
			GET_MPLS_IFINFO_RT(ifs)->mrt_flags |= MRT_PW2;
			GET_MPLS_IFINFO_RT(ifs)->mrt_nh_smpls.smpls_vprd =
				MPLS_LABEL_SET(MPLS_RD_ETHDEMUX);
		}
		break;
	default:
		return (EINVAL);
	}

	/*
	 * Two valid inet6 addresses with link-local scope must not be
	 * on the parent interface and the member interfaces at the
	 * same time.  This restriction is needed to prevent violation
	 * of link-local scope zone.  Attempts to add a member
	 * interface which has inet6 addresses when the parent has
	 * inet6 triggers removal of all inet6 addresses on the member
	 * interface.
	 */

	/* Check if the parent interface has a link-local scope addr. */
	if (V_allow_llz_overlap == 0 &&
	    in6ifa_llaonifp(sc->sc_ifp) != NULL) {
		/*
		 * If any, remove all inet6 addresses from the member
		 * interfaces.
		 */
		BRIDGE_XLOCK(sc);
		LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
 			if (in6ifa_llaonifp(bif->bif_ifp)) {
				BRIDGE_UNLOCK(sc);
				in6_ifdetach(bif->bif_ifp);
				BRIDGE_LOCK(sc);
				if_printf(sc->sc_ifp,
				    "IPv6 addresses on %s have been removed "
				    "before adding it as a member to prevent "
				    "IPv6 address scope violation.\n",
				    bif->bif_ifp->if_xname);
			}
		}
		BRIDGE_XDROP(sc);
		if (in6ifa_llaonifp(ifs)) {
			BRIDGE_UNLOCK(sc);
			in6_ifdetach(ifs);
			BRIDGE_LOCK(sc);
			if_printf(sc->sc_ifp,
			    "IPv6 addresses on %s have been removed "
			    "before adding it as a member to prevent "
			    "IPv6 address scope violation.\n",
			    ifs->if_xname);
		}
	}
	/* Allow the first Ethernet member to define the MTU */
	if (LIST_EMPTY(&sc->sc_iflist))
		sc->sc_ifp->if_mtu = ifs->if_mtu;
	else if (sc->sc_ifp->if_mtu != ifs->if_mtu) {
		if_printf(sc->sc_ifp, "invalid MTU: %lu(%s) != %lu\n",
		    ifs->if_mtu, ifs->if_xname, sc->sc_ifp->if_mtu);
		return (EINVAL);
	}

	bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
	if (bif == NULL)
		return (ENOMEM);

	bif->bif_ifp = ifs;
	bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
	bif->bif_savedcaps = ifs->if_capenable;

	/*
	 * Assign the interface's MAC address to the bridge if it's the first
	 * member and the MAC address of the bridge has not been changed from
	 * the default randomly generated one.
	 */
	if (bridge_inherit_mac && LIST_EMPTY(&sc->sc_iflist) &&
	    !memcmp(IF_LLADDR(sc->sc_ifp), sc->sc_defaddr, ETHER_ADDR_LEN)) {
		bcopy(IF_LLADDR(ifs), IF_LLADDR(sc->sc_ifp), ETHER_ADDR_LEN);
		sc->sc_ifaddr = ifs;
		EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp);
	}

	ifs->if_bridge = sc;
	bstp_create(&sc->sc_stp, &bif->bif_stp, bif->bif_ifp);
	/*
	 * XXX: XLOCK HERE!?!
	 *
	 * NOTE: insert_***HEAD*** should be safe for the traversals.
	 */
	LIST_INSERT_HEAD(&sc->sc_iflist, bif, bif_next);

	/* Set interface capabilities to the intersection set of all members */
	bridge_mutecaps(sc);
	bridge_linkcheck(sc);

	/* Place the interface into promiscuous mode */
	switch (ifs->if_type) {
		case IFT_ETHER:
		case IFT_VETHER: /* XXX: applied constant */
		case IFT_L2VLAN:
			BRIDGE_UNLOCK(sc);
			error = ifpromisc(ifs, 1);
			BRIDGE_LOCK(sc);
			break;
	}

	if (error) {
		bridge_delete_member(sc, bif, 0);
		free(bif, M_DEVBUF);
	}
	return (error);
}

Now, I'm starting testing rfc-2516 proxyfieing. Possible changes on
implementation maybe commited soon.