From 3408b8e06e1ee37e7abda2e3a29e508a84d63287 Mon Sep 17 00:00:00 2001 From: kardel Date: Thu, 16 Jan 2020 12:56:39 +0000 Subject: [PATCH] Provide SIOCGIFMEDIA ioctl to deliver link status. Add link0 (IFF_LINK0) flag to map INIT state to LINK_STATE_DOWN instead of LINK_STATE_UNKNOWN. This allows routing software to suppress routes to the interface of the carp interface when in init state (e. g. link down in the parent interface). --- share/man/man4/carp.4 | 18 +++++++++++++-- sys/netinet/ip_carp.c | 53 +++++++++++++++++++++++++++++++++++++++---- sys/netinet/ip_carp.h | 5 +++- 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/share/man/man4/carp.4 b/share/man/man4/carp.4 index bfe1c7a889b7..4627a93ad150 100644 --- a/share/man/man4/carp.4 +++ b/share/man/man4/carp.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: carp.4,v 1.6 2019/04/10 00:18:39 sevan Exp $ +.\" $NetBSD: carp.4,v 1.7 2020/01/16 12:56:39 kardel Exp $ .\" $OpenBSD: carp.4,v 1.19 2005/08/09 09:52:12 jmc Exp $ .\" .\" Copyright (c) 2003, Ryan McBride. All rights reserved. @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 10, 2019 +.Dd January 16, 2020 .Dt CARP 4 .Os .Sh NAME @@ -76,6 +76,20 @@ or through the .Dv SIOCSVH ioctl. .Pp +Setting the +.Cm link0 +parameter will cause the carp interface to report +.Dv LINK_STATE_DOWN +in non +.Dv MASTER/BACKUP +mode instead of +.Dv LINK_STATE_UNKNOWN +as link status. +This prevents routing software to announce routes for the carp +interface when in +.Dv INIT +mode. +.Pp Additionally, there are a number of global parameters which can be set using .Xr sysctl 8 : .Bl -tag -width xxxxxxxxxxxxxxxxxxxxxxxxxx diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index 0bccf7ad3f19..aba393f9632d 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip_carp.c,v 1.104 2019/11/10 21:16:38 chs Exp $ */ +/* $NetBSD: ip_carp.c,v 1.105 2020/01/16 12:56:40 kardel Exp $ */ /* $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $ */ /* @@ -33,7 +33,7 @@ #endif #include -__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.104 2019/11/10 21:16:38 chs Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.105 2020/01/16 12:56:40 kardel Exp $"); /* * TODO: @@ -67,6 +67,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.104 2019/11/10 21:16:38 chs Exp $"); #include #include #include +#include #include #include #include @@ -122,6 +123,7 @@ struct carp_softc { #define sc_carpdev sc_ac.ec_if.if_carpdev int ah_cookie; int lh_cookie; + struct ifmedia sc_im; /* ifmedia for link status */ struct ip_moptions sc_imo; #ifdef INET6 struct ip6_moptions sc_im6o; @@ -233,6 +235,9 @@ static int carp_clone_destroy(struct ifnet *); static int carp_ether_addmulti(struct carp_softc *, struct ifreq *); static int carp_ether_delmulti(struct carp_softc *, struct ifreq *); static void carp_ether_purgemulti(struct carp_softc *); +static int carp_mediachange(struct ifnet *ifp); +static void carp_mediastatus(struct ifnet *ifp, struct ifmediareq *imr); +static void carp_update_link_state(struct carp_softc *sc); static void sysctl_net_inet_carp_setup(struct sysctllog **); @@ -893,6 +898,8 @@ carp_clone_create(struct if_clone *ifc, int unit) return rv; } + ifmedia_init(&sc->sc_im, 0, carp_mediachange, carp_mediastatus); + sc->sc_im.ifm_media = IFM_CARP; ether_ifattach(ifp, NULL); carp_set_enaddr(sc); /* Overwrite ethernet defaults */ @@ -908,6 +915,7 @@ carp_clone_destroy(struct ifnet *ifp) { struct carp_softc *sc = ifp->if_softc; + ifmedia_delete_instance(&sc->sc_im, IFM_INST_ANY); carpdetach(ifp->if_softc); ether_ifdetach(ifp); if_detach(ifp); @@ -2069,6 +2077,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, void *data) sc->sc_if.if_flags |= IFF_UP; carp_setrun(sc, 0); } + carp_update_link_state(sc); break; case SIOCSVH: @@ -2174,6 +2183,10 @@ carp_ioctl(struct ifnet *ifp, u_long cmd, void *data) error = 0; break; + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd); + break; + default: error = ether_ioctl(ifp, cmd, data); } @@ -2209,11 +2222,32 @@ carp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa, } } +static int +carp_mediachange(struct ifnet *ifp) +{ + return (0); +} + +static void +carp_mediastatus(struct ifnet *ifp, struct ifmediareq *imr) +{ + switch (ifp->if_link_state) { + case LINK_STATE_UP: + imr->ifm_status = IFM_AVALID | IFM_ACTIVE; + break; + case LINK_STATE_DOWN: + imr->ifm_status = IFM_AVALID; + break; + default: + imr->ifm_status = 0; + break; + } +} + static void carp_set_state(struct carp_softc *sc, int state) { static const char *carp_states[] = { CARP_STATES }; - int link_state; if (sc->sc_state == state) return; @@ -2221,7 +2255,15 @@ carp_set_state(struct carp_softc *sc, int state) CARP_LOG(sc, ("state transition from: %s -> to: %s", carp_states[sc->sc_state], carp_states[state])); sc->sc_state = state; - switch (state) { + carp_update_link_state(sc); +} + +static void +carp_update_link_state(struct carp_softc *sc) +{ + int link_state; + + switch (sc->sc_state) { case BACKUP: link_state = LINK_STATE_DOWN; break; @@ -2229,7 +2271,8 @@ carp_set_state(struct carp_softc *sc, int state) link_state = LINK_STATE_UP; break; default: - link_state = LINK_STATE_UNKNOWN; + link_state = ((sc->sc_if.if_flags & IFF_ONLY_MASTER_UP) != 0) + ? LINK_STATE_DOWN : LINK_STATE_UNKNOWN; break; } /* diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h index 218c3ec64791..af7560affeec 100644 --- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip_carp.h,v 1.10 2018/09/14 05:09:51 maxv Exp $ */ +/* $NetBSD: ip_carp.h,v 1.11 2020/01/16 12:56:40 kardel Exp $ */ /* $OpenBSD: ip_carp.h,v 1.18 2005/04/20 23:00:41 mpf Exp $ */ /* @@ -133,6 +133,9 @@ struct carpreq { unsigned char carpr_key[CARP_KEY_LEN]; }; +/* enable link status up only for MASTER state */ +#define IFF_ONLY_MASTER_UP IFF_LINK0 + /* * Names for CARP sysctl objects */