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);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to