Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 24 May 2011 14:10:34 +0000 (UTC)
From:      Marko Zec <zec@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r222255 - head/sys/netgraph
Message-ID:  <201105241410.p4OEAYGH071553@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: zec
Date: Tue May 24 14:10:33 2011
New Revision: 222255
URL: http://svn.freebsd.org/changeset/base/222255

Log:
  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

Modified:
  head/sys/netgraph/ng_eiface.c

Modified: head/sys/netgraph/ng_eiface.c
==============================================================================
--- head/sys/netgraph/ng_eiface.c	Tue May 24 13:36:41 2011	(r222254)
+++ head/sys/netgraph/ng_eiface.c	Tue May 24 14:10:33 2011	(r222255)
@@ -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
 /* 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_e
 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_lon
 			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 hoo
 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,
 }
 #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 ho
 	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 ite
 		} /* 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);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201105241410.p4OEAYGH071553>