Provide fake link status information in an attempt to let ng_eiface(4)
virtual ifnets more realistically mimic physical ethernet interfaces. The main motivation behind this change is to allow for ng_eiface(4) interfaces to participate in STP if_bridge(4) configurations. When announcing link status changes, switch to the vnet to which the ifnet belongs, since it is possible for ng_eiface ifnets to be assigned to a vnet different from the one in which its netgraph node resides. MFC after: 3 days
This commit is contained in:
parent
47ad691f87
commit
7d5ddd30cd
@ -41,6 +41,7 @@
|
||||
#include <sys/syslog.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/netisr.h>
|
||||
#include <net/route.h>
|
||||
@ -76,6 +77,8 @@ static const struct ng_cmdlist ng_eiface_cmdlist[] = {
|
||||
/* Node private data */
|
||||
struct ng_eiface_private {
|
||||
struct ifnet *ifp; /* per-interface network data */
|
||||
struct ifmedia media; /* (fake) media information */
|
||||
int link_status; /* fake */
|
||||
int unit; /* Interface unit number */
|
||||
node_p node; /* Our netgraph node */
|
||||
hook_p ether; /* Hook for ethernet stream */
|
||||
@ -127,6 +130,7 @@ static VNET_DEFINE(struct unrhdr *, ng_eiface_unit);
|
||||
static int
|
||||
ng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
{
|
||||
const priv_p priv = (priv_p)ifp->if_softc;
|
||||
struct ifreq *const ifr = (struct ifreq *)data;
|
||||
int s, error = 0;
|
||||
|
||||
@ -170,6 +174,12 @@ ng_eiface_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
|
||||
ifp->if_mtu = ifr->ifr_mtu;
|
||||
break;
|
||||
|
||||
/* (Fake) media type manipulation */
|
||||
case SIOCSIFMEDIA:
|
||||
case SIOCGIFMEDIA:
|
||||
error = ifmedia_ioctl(ifp, ifr, &priv->media, command);
|
||||
break;
|
||||
|
||||
/* Stuff that's not supported */
|
||||
case SIOCADDMULTI:
|
||||
case SIOCDELMULTI:
|
||||
@ -280,7 +290,6 @@ ng_eiface_start2(node_p node, hook_p hook, void *arg1, int arg2)
|
||||
static void
|
||||
ng_eiface_start(struct ifnet *ifp)
|
||||
{
|
||||
|
||||
const priv_p priv = (priv_p)ifp->if_softc;
|
||||
|
||||
/* Don't do anything if output is active */
|
||||
@ -328,6 +337,41 @@ ng_eiface_print_ioctl(struct ifnet *ifp, int command, caddr_t data)
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
* ifmedia stuff
|
||||
*/
|
||||
static int
|
||||
ng_eiface_mediachange(struct ifnet *ifp)
|
||||
{
|
||||
const priv_p priv = (priv_p)ifp->if_softc;
|
||||
struct ifmedia *ifm = &priv->media;
|
||||
|
||||
if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
|
||||
return (EINVAL);
|
||||
if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
|
||||
ifp->if_baudrate = ifmedia_baudrate(IFM_ETHER | IFM_1000_T);
|
||||
else
|
||||
ifp->if_baudrate = ifmedia_baudrate(ifm->ifm_media);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ng_eiface_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
|
||||
{
|
||||
const priv_p priv = (priv_p)ifp->if_softc;
|
||||
struct ifmedia *ifm = &priv->media;
|
||||
|
||||
if (ifm->ifm_cur->ifm_media == (IFM_ETHER | IFM_AUTO) &&
|
||||
(priv->link_status & IFM_ACTIVE))
|
||||
ifmr->ifm_active = IFM_ETHER | IFM_1000_T | IFM_FDX;
|
||||
else
|
||||
ifmr->ifm_active = ifm->ifm_cur->ifm_media;
|
||||
ifmr->ifm_status = priv->link_status;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
NETGRAPH NODE STUFF
|
||||
************************************************************************/
|
||||
@ -371,6 +415,18 @@ ng_eiface_constructor(node_p node)
|
||||
ifp->if_flags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST);
|
||||
ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
|
||||
ifp->if_capenable = IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
|
||||
ifmedia_init(&priv->media, 0, ng_eiface_mediachange,
|
||||
ng_eiface_mediastatus);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_10_T, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_100_TX, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_1000_T, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_10G_T | IFM_FDX, 0, NULL);
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
|
||||
ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
|
||||
priv->link_status = IFM_AVALID;
|
||||
|
||||
/* Give this node the same name as the interface (if possible) */
|
||||
if (ng_name_node(node, ifp->if_xname) != 0)
|
||||
@ -379,6 +435,7 @@ ng_eiface_constructor(node_p node)
|
||||
|
||||
/* Attach the interface */
|
||||
ether_ifattach(ifp, eaddr);
|
||||
ifp->if_baudrate = ifmedia_baudrate(IFM_ETHER | IFM_1000_T);
|
||||
|
||||
/* Done */
|
||||
return (0);
|
||||
@ -401,7 +458,10 @@ ng_eiface_newhook(node_p node, hook_p hook, const char *name)
|
||||
NG_HOOK_SET_PRIVATE(hook, &priv->ether);
|
||||
NG_HOOK_SET_TO_INBOUND(hook);
|
||||
|
||||
priv->link_status |= IFM_ACTIVE;
|
||||
CURVNET_SET_QUIET(ifp->if_vnet);
|
||||
if_link_state_change(ifp, LINK_STATE_UP);
|
||||
CURVNET_RESTORE();
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -486,16 +546,20 @@ ng_eiface_rcvmsg(node_p node, item_p item, hook_p lasthook)
|
||||
} /* end of inner switch() */
|
||||
break;
|
||||
case NGM_FLOW_COOKIE:
|
||||
CURVNET_SET_QUIET(ifp->if_vnet);
|
||||
switch (msg->header.cmd) {
|
||||
case NGM_LINK_IS_UP:
|
||||
priv->link_status |= IFM_ACTIVE;
|
||||
if_link_state_change(ifp, LINK_STATE_UP);
|
||||
break;
|
||||
case NGM_LINK_IS_DOWN:
|
||||
priv->link_status &= ~IFM_ACTIVE;
|
||||
if_link_state_change(ifp, LINK_STATE_DOWN);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
CURVNET_RESTORE();
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
@ -557,6 +621,7 @@ ng_eiface_rmnode(node_p node)
|
||||
* hence we have to change the current vnet context here.
|
||||
*/
|
||||
CURVNET_SET_QUIET(ifp->if_vnet);
|
||||
ifmedia_removeall(&priv->media);
|
||||
ether_ifdetach(ifp);
|
||||
if_free(ifp);
|
||||
CURVNET_RESTORE();
|
||||
@ -576,6 +641,10 @@ ng_eiface_disconnect(hook_p hook)
|
||||
const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
|
||||
|
||||
priv->ether = NULL;
|
||||
priv->link_status &= ~IFM_ACTIVE;
|
||||
CURVNET_SET_QUIET(priv->ifp->if_vnet);
|
||||
if_link_state_change(priv->ifp, LINK_STATE_DOWN);
|
||||
CURVNET_RESTORE();
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user