Announcing ethernet link state changes via route socket
Hasso Tepper
hasso at estpak.ee
Fri Mar 16 01:13:04 PDT 2007
Announcing link state changes to the userspace via route socket is critical
to get routing related applications to work correctly - routing protocols
are most important, but other applications might benefit from it as well.
This code is adapted from OpenBSD and is only the first basic step in path
to get correct support. Only em(4) is tested because I don't have hardware
to test others, although bge(4) might get my attention as well in the
future.
There is one fundamental problem I'd like to get feedback about from
developers - how to make various kernel stuff react on link state changes?
For example various interfaces which are somehow attached to the interface
(bridges, carp, vlans etc) should react. Ideally routing table should react
as well (yes, no BSD or Linux kernel does that yet, but they should).
Personally I like the idea of the hooks OpenBSD uses, but as I'm not very
familiar of DragonFlyBSD, my personal opinion might be very far from good
solution ;).
regards,
--
Hasso Tepper
diff -r 9d42302b182d sys/dev/netif/em/if_em.c
--- a/sys/dev/netif/em/if_em.c Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/dev/netif/em/if_em.c Thu Mar 15 20:05:40 2007 +0200
@@ -1788,6 +1788,9 @@ static void
static void
em_update_link_status(struct adapter *adapter)
{
+ struct ifnet *ifp;
+ ifp = &adapter->interface_data.ac_if;
+
if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
if (adapter->link_active == 0) {
em_get_speed_and_duplex(&adapter->hw,
@@ -1812,16 +1815,13 @@ em_update_link_status(struct adapter *ad
}
adapter->link_active = 1;
adapter->smartspeed = 0;
-#ifdef notyet
ifp->if_baudrate = adapter->link_speed * 1000000;
- if_link_state_change(ifp, LINK_STATE_UP);
-#endif
+ ifp->if_link_state = LINK_STATE_UP;
+ if_link_state_change(ifp);
}
} else {
if (adapter->link_active == 1) {
-#ifdef notyet
ifp->if_baudrate = 0;
-#endif
adapter->link_speed = 0;
adapter->link_duplex = 0;
if (bootverbose) {
@@ -1829,9 +1829,8 @@ em_update_link_status(struct adapter *ad
"Link is Down\n");
}
adapter->link_active = 0;
-#ifdef notyet
- if_link_state_change(ifp, LINK_STATE_DOWN);
-#endif
+ ifp->if_link_state = LINK_STATE_DOWN;
+ if_link_state_change(ifp);
}
}
}
diff -r 9d42302b182d sys/dev/netif/mii_layer/mii_physubr.c
--- a/sys/dev/netif/mii_layer/mii_physubr.c Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/dev/netif/mii_layer/mii_physubr.c Thu Mar 15 20:10:03 2007 +0200
@@ -500,42 +500,61 @@ mii_phy_tick(struct mii_softc *sc)
return (0);
}
-#ifdef notyet
-static void
+static int
mii_phy_statusmsg(struct mii_softc *sc)
{
struct mii_data *mii = sc->mii_pdata;
struct ifnet *ifp = mii->mii_ifp;
- int s;
-
- crit_enter();
+ int baudrate, link_state, announce = 0;
+
if (mii->mii_media_status & IFM_AVALID) {
if (mii->mii_media_status & IFM_ACTIVE)
- if_link_state_change(ifp, LINK_STATE_UP);
+ link_state = LINK_STATE_UP;
else
- if_link_state_change(ifp, LINK_STATE_DOWN);
+ link_state = LINK_STATE_DOWN;
} else
- if_link_state_change(ifp, LINK_STATE_UNKNOWN);
- crit_exit();
-
- ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active);
-}
-#endif
+ link_state = LINK_STATE_UNKNOWN;
+
+ baudrate = ifmedia_baudrate(mii->mii_media_active);
+
+ if (link_state != ifp->if_link_state) {
+ ifp->if_link_state = link_state;
+ /*
+ * XXX Right here we'd like to notify protocols
+ * XXX that the link status has changed, so that
+ * XXX e.g. Duplicate Address Detection can restart.
+ */
+ announce = 1;
+ }
+
+ if (baudrate != ifp->if_baudrate) {
+ ifp->if_baudrate = baudrate;
+ announce = 1;
+ }
+
+ return (announce);
+}
void
mii_phy_update(struct mii_softc *sc, int cmd)
{
struct mii_data *mii = sc->mii_pdata;
+ struct ifnet *ifp = mii->mii_ifp;
+ int announce;
if (sc->mii_media_active != mii->mii_media_active ||
sc->mii_media_status != mii->mii_media_status ||
cmd == MII_MEDIACHG) {
-#ifdef notyet
- mii_phy_statusmsg(sc);
-#endif
+ announce = mii_phy_statusmsg(sc);
MIIBUS_STATCHG(sc->mii_dev);
sc->mii_media_active = mii->mii_media_active;
sc->mii_media_status = mii->mii_media_status;
+
+ if (announce) {
+ crit_enter();
+ if_link_state_change(ifp);
+ crit_exit();
+ }
}
}
diff -r 9d42302b182d sys/net/if.c
--- a/sys/net/if.c Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if.c Fri Mar 16 06:58:52 2007 +0200
@@ -975,6 +975,16 @@ if_up(struct ifnet *ifp)
{
if_route(ifp, IFF_UP, AF_UNSPEC);
+}
+
+/*
+ * Process a link state change.
+ * NOTE: must be called at splsoftnet or equivalent.
+ */
+void
+if_link_state_change(struct ifnet *ifp)
+{
+ rt_ifmsg(ifp);
}
/*
diff -r 9d42302b182d sys/net/if.h
--- a/sys/net/if.h Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if.h Thu Mar 15 20:08:58 2007 +0200
@@ -56,6 +56,13 @@
#endif
+/*
+ * Values for if_link_state.
+ */
+#define LINK_STATE_UNKNOWN 0 /* link invalid/unknown */
+#define LINK_STATE_DOWN 1 /* link is down */
+#define LINK_STATE_UP 2 /* link is up */
+
struct ifnet;
/*
@@ -111,6 +118,7 @@ struct if_data {
u_char ifi_xmitquota; /* polling quota for xmit intrs */
u_long ifi_mtu; /* maximum transmission unit */
u_long ifi_metric; /* routing metric (external only) */
+ u_long ifi_link_state; /* current link state */
u_long ifi_baudrate; /* linespeed */
/* volatile statistics */
u_long ifi_ipackets; /* packets received on interface */
diff -r 9d42302b182d sys/net/if_media.c
--- a/sys/net/if_media.c Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if_media.c Thu Mar 15 13:57:11 2007 +0200
@@ -360,6 +360,24 @@ ifmedia_match(struct ifmedia *ifm, int t
return match;
}
+struct ifmedia_baudrate ifmedia_baudrate_descriptions[] =
+ IFM_BAUDRATE_DESCRIPTIONS;
+
+int
+ifmedia_baudrate(int mword)
+{
+ int i;
+
+ for (i = 0; ifmedia_baudrate_descriptions[i].ifmb_word != 0; i++) {
+ if ((mword & (IFM_NMASK|IFM_TMASK)) ==
+ ifmedia_baudrate_descriptions[i].ifmb_word)
+ return (ifmedia_baudrate_descriptions[i].ifmb_baudrate);
+ }
+
+ /* Not known. */
+ return (0);
+}
+
#ifdef IFMEDIA_DEBUG
struct ifmedia_description ifm_type_descriptions[] =
IFM_TYPE_DESCRIPTIONS;
diff -r 9d42302b182d sys/net/if_media.h
--- a/sys/net/if_media.h Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if_media.h Fri Mar 16 06:56:20 2007 +0200
@@ -115,6 +115,8 @@ int ifmedia_ioctl(struct ifnet *ifp, str
int ifmedia_ioctl(struct ifnet *ifp, struct ifreq *ifr,
struct ifmedia *ifm, u_long cmd);
+/* Compute baudrate for a given media. */
+int ifmedia_baudrate(int);
#endif /*_KERNEL */
/*
@@ -541,4 +543,57 @@ struct ifmedia_description {
{ 0, NULL }, \
}
+/*
+ * Baudrate descriptions for the various media types.
+ */
+struct ifmedia_baudrate {
+ int ifmb_word; /* media word */
+ int ifmb_baudrate; /* corresponding baudrate */
+};
+
+#define IFM_BAUDRATE_DESCRIPTIONS { \
+ { IFM_ETHER|IFM_10_T, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_10_2, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_10_5, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_100_TX, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_FX, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_T4, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_VG, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_100_T2, IF_Mbps(100) }, \
+ { IFM_ETHER|IFM_1000_SX, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_10_STP, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_10_FL, IF_Mbps(10) }, \
+ { IFM_ETHER|IFM_1000_LX, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_1000_CX, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_1000_T, IF_Mbps(1000) }, \
+ { IFM_ETHER|IFM_HPNA_1, IF_Mbps(1) }, \
+ \
+ { IFM_TOKEN|IFM_TOK_STP4, IF_Mbps(4) }, \
+ { IFM_TOKEN|IFM_TOK_STP16, IF_Mbps(16) }, \
+ { IFM_TOKEN|IFM_TOK_UTP4, IF_Mbps(4) }, \
+ { IFM_TOKEN|IFM_TOK_UTP16, IF_Mbps(16) }, \
+ \
+ { IFM_FDDI|IFM_FDDI_SMF, IF_Mbps(100) }, \
+ { IFM_FDDI|IFM_FDDI_MMF, IF_Mbps(100) }, \
+ { IFM_FDDI|IFM_FDDI_UTP, IF_Mbps(100) }, \
+ \
+ { IFM_IEEE80211|IFM_IEEE80211_FH1, IF_Mbps(1) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_FH2, IF_Mbps(2) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS1, IF_Mbps(1) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS2, IF_Mbps(2) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS5, IF_Mbps(5) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS11, IF_Mbps(11) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_DS22, IF_Mbps(22) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM6, IF_Mbps(6) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM9, IF_Mbps(9) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM12, IF_Mbps(12) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM18, IF_Mbps(18) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM24, IF_Mbps(24) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM36, IF_Mbps(36) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM48, IF_Mbps(48) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM54, IF_Mbps(54) }, \
+ { IFM_IEEE80211|IFM_IEEE80211_OFDM72, IF_Mbps(72) }, \
+ \
+ { 0, 0 }, \
+}
#endif /* _NET_IF_MEDIA_H_ */
diff -r 9d42302b182d sys/net/if_var.h
--- a/sys/net/if_var.h Thu Mar 15 21:41:11 2007 +0000
+++ b/sys/net/if_var.h Thu Mar 15 14:18:56 2007 +0200
@@ -228,6 +228,7 @@ typedef void if_init_f_t (void *);
#define if_addrlen if_data.ifi_addrlen
#define if_hdrlen if_data.ifi_hdrlen
#define if_metric if_data.ifi_metric
+#define if_link_state if_data.ifi_link_state
#define if_baudrate if_data.ifi_baudrate
#define if_hwassist if_data.ifi_hwassist
#define if_ipackets if_data.ifi_ipackets
@@ -462,6 +463,7 @@ int if_delmulti(struct ifnet *, struct s
int if_delmulti(struct ifnet *, struct sockaddr *);
void if_detach(struct ifnet *);
void if_down(struct ifnet *);
+void if_link_state_change(struct ifnet *);
void if_initname(struct ifnet *, const char *, int);
int if_printf(struct ifnet *, const char *, ...) __printflike(2, 3);
void if_route(struct ifnet *, int flag, int fam);
More information about the Submit
mailing list