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).
This commit is contained in:
kardel 2020-01-16 12:56:39 +00:00
parent 71d284c021
commit 3408b8e06e
3 changed files with 68 additions and 8 deletions

View File

@ -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

View File

@ -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 <sys/cdefs.h>
__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 <net/pfil.h>
#include <net/if_types.h>
#include <net/if_ether.h>
#include <net/if_media.h>
#include <net/route.h>
#include <net/netisr.h>
#include <net/net_stats.h>
@ -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;
}
/*

View File

@ -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
*/