From nobody Wed May 08 11:19:58 2024 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VZCNb0CfQz5Kt56; Wed, 08 May 2024 11:19:59 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4VZCNZ631Fz49XJ; Wed, 8 May 2024 11:19:58 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1715167198; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=u3P+hrdm1zIYB5zDpxszVsLWXq/SskAa7bj21WeYTgY=; b=fnfrZVSCTxbdQjA146aMZqNbqLUCpmCtJvnJtqZAHkddwqbtYPOgwrwslUZBm+JpIKrtXP 2dEjRU/L692th7M648cj0YnmE9bhsuBVANrfRGE/f5TuZTVJjKwUPS71DsA+01naHeie01 8u0e8E4GWUHtFItnJBwjefcE7p2ulbURNj+Umd0QNSz/9GsTBH1ZBpAbCGhdArFLHHzoSO c/N9Dugjn//Z7jhYCOC5XhJOpgghlsbjg+KpOSQr2NczpjdilQwM/gO5s/7TuNg2Ux+qct pFeGYkHAF+wFsul4IXVWrwcgoEP7rvQ8SQCMZg6UkqacdxPIVLl7KtKvKWb3Gg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1715167198; a=rsa-sha256; cv=none; b=Wm1qwmzqSMOswwfkEJUa9A2YD7Ac0f5IB1xbP3pozQes8vq1phQqCfOXNBuzD6hR9sL1sU JZEWBp/wtQj7v8y/jg130Pdmhs4GRA5UVTBuBV+3ACbx38R/Vc+cF760LBGsPY/eTLz2/n RiFiVKd1AVteQEy07KWM72I/Pj7lGpQy/fjeP+I74Ls3C1tZXLKpMm92E2+oI9xLwmFYyn kSssSRTLIsfQHwev5mqaOilAobwD/lbZn6fpN5l1KuJ30cd2EOGakhxRQdsWTyOOQuE1YI 0+aZpYhnZCKh2V9CcD+7F41cPBbYAdMvq3O3Mf6P++oH2K09WNdvPX2CRataLA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1715167198; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=u3P+hrdm1zIYB5zDpxszVsLWXq/SskAa7bj21WeYTgY=; b=ycnrih+aJhb466IfbI4tw3+D3ljyGdtil6WYcA4g1GCXCn7Waz9M0WXxAV/01W6+IJl9RJ Qe2XvRIjlIbk+LAAgYUeHzKsV8rvuXaiuCSHHSky0yft19pdKGLJrhT7j4b/Y8iaOe8L3L K2j3aR+4H+63n87v81FYU21j/GgPR1fYtGPldZVDoIfaLYehE1iZ4COeYz2qduWmAYan/8 YpSp6sit9kx7F1mR7rHDn6nUZcQNuTd0XBn9zyJZlQ/lOWpj8kDZYFvFa1IjRhZS1KRfzx NIxHk9gkmXE5b3RdLVwk7NRHmZJcpngb3DKTKyUyL7xZrLbu8HWpjitNX+LmlQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4VZCNZ5dyyzN39; Wed, 8 May 2024 11:19:58 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 448BJw6B094707; Wed, 8 May 2024 11:19:58 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 448BJwFM094704; Wed, 8 May 2024 11:19:58 GMT (envelope-from git) Date: Wed, 8 May 2024 11:19:58 GMT Message-Id: <202405081119.448BJwFM094704@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kristof Provost Subject: git: a254d6870e88 - main - carp: isolate VRRP from CARP List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kp X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: a254d6870e88d4194390d822ab6a2dff59a83892 Auto-Submitted: auto-generated The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=a254d6870e88d4194390d822ab6a2dff59a83892 commit a254d6870e88d4194390d822ab6a2dff59a83892 Author: Gleb Smirnoff AuthorDate: 2024-04-30 02:58:25 +0000 Commit: Kristof Provost CommitDate: 2024-05-08 11:19:04 +0000 carp: isolate VRRP from CARP There is only one functional change here - we don't allow SIOCSVH (or netlink request) to change sc->sc_version. I'm convinced that allowing such a change doesn't brings any practical value, but creates enless minefields in front of both developers and end users (sysadmins). If you want to switch from VRRP to CARP or vice versa, you'd need to recreate the VHID. Oh, one tiny funtional change: carp_ioctl_set() won't modify any fields if it returns EINVAL. Previously you could provide valid advbase with invalid advskew - that used to modify advbase and return EINVAL. All other changes is a sweep around not ever using CARP fields when we are in VRRP mode and vice versa. Also adding assertions on sc_version where necessary. Do not send VRRP vars in CARP mode via NetLink and vice versa. However in compat ioctl SIOCGVH for VRRP mode the CARP fields would be zeroes. This allows to declare softc as union and thus prevent any future logic deterioration wrt to mixing VRRP and CARP. Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D45039 --- sys/netinet/ip_carp.c | 358 ++++++++++++++++++++++++++++---------------------- 1 file changed, 199 insertions(+), 159 deletions(-) diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c index d7dd6ced2e44..9f163c1097ba 100644 --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -97,7 +97,7 @@ struct carp_softc { struct ifnet *sc_carpdev; /* Pointer to parent ifnet. */ struct ifaddr **sc_ifas; /* Our ifaddrs. */ carp_version_t sc_version; /* carp or VRRPv3 */ - struct sockaddr_dl sc_addr; /* Our link level address. */ + uint8_t sc_addr[ETHER_ADDR_LEN]; /* Our link level address. */ struct callout sc_ad_tmo; /* Advertising timeout. */ #ifdef INET struct callout sc_md_tmo; /* Master down timeout. */ @@ -108,18 +108,25 @@ struct carp_softc { struct mtx sc_mtx; int sc_vhid; - struct { /* CARP specific context */ - int sc_advskew; - int sc_advbase; - struct in_addr sc_carpaddr; - struct in6_addr sc_carpaddr6; - }; - struct { /* VRRPv3 specific context */ - uint8_t sc_vrrp_prio; - uint16_t sc_vrrp_adv_inter; - uint16_t sc_vrrp_master_inter; + union { + struct { /* sc_version == CARP_VERSION_CARP */ + int sc_advskew; + int sc_advbase; + struct in_addr sc_carpaddr; + struct in6_addr sc_carpaddr6; + uint64_t sc_counter; + bool sc_init_counter; +#define CARP_HMAC_PAD 64 + unsigned char sc_key[CARP_KEY_LEN]; + unsigned char sc_pad[CARP_HMAC_PAD]; + SHA1_CTX sc_sha1; + }; + struct { /* sc_version == CARP_VERSION_VRRPv3 */ + uint8_t sc_vrrp_prio; + uint16_t sc_vrrp_adv_inter; + uint16_t sc_vrrp_master_inter; + }; }; - int sc_naddrs; int sc_naddrs6; int sc_ifasiz; @@ -130,15 +137,6 @@ struct carp_softc { int sc_sendad_success; #define CARP_SENDAD_MIN_SUCCESS 3 - int sc_init_counter; - uint64_t sc_counter; - - /* authentication */ -#define CARP_HMAC_PAD 64 - unsigned char sc_key[CARP_KEY_LEN]; - unsigned char sc_pad[CARP_HMAC_PAD]; - SHA1_CTX sc_sha1; - TAILQ_ENTRY(carp_softc) sc_list; /* On the carp_if list. */ LIST_ENTRY(carp_softc) sc_next; /* On the global list. */ }; @@ -339,7 +337,7 @@ SYSCTL_VNET_PCPUSTAT(_net_inet_carp, OID_AUTO, stats, struct carpstats, static void carp_input_c(struct mbuf *, struct carp_header *, sa_family_t, int); static void vrrp_input_c(struct mbuf *, int, sa_family_t, int, int, uint16_t); static struct carp_softc - *carp_alloc(struct ifnet *); + *carp_alloc(struct ifnet *, carp_version_t, int); static void carp_destroy(struct carp_softc *); static struct carp_if *carp_alloc_if(struct ifnet *); @@ -398,6 +396,7 @@ carp_hmac_prepare(struct carp_softc *sc) #endif CARP_LOCK_ASSERT(sc); + MPASS(sc->sc_version == CARP_VERSION_CARP); /* Compute ipad from key. */ bzero(sc->sc_pad, sizeof(sc->sc_pad)); @@ -522,7 +521,6 @@ carp_input(struct mbuf **mp, int *offp, int proto) int iplen; int minlen; int totlen; - uint16_t phdrcksum = 0; iplen = *offp; *mp = NULL; @@ -593,10 +591,10 @@ carp_input(struct mbuf **mp, int *offp, int proto) vh = (struct vrrpv3_header *)((char *)ip + iplen); } - phdrcksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, - htonl((u_short)(totlen - iplen) + ip->ip_p)); + switch (vh->vrrp_version) { + case CARP_VERSION_CARP: { + struct carp_header *ch; - if (vh->vrrp_version == CARP_VERSION_CARP) { /* verify the CARP checksum */ m->m_data += iplen; if (in_cksum(m, totlen - iplen)) { @@ -604,20 +602,22 @@ carp_input(struct mbuf **mp, int *offp, int proto) CARP_DEBUG("%s: checksum failed on %s\n", __func__, if_name(m->m_pkthdr.rcvif)); m_freem(m); - return (IPPROTO_DONE); + break; } m->m_data -= iplen; - } - - switch (vh->vrrp_version) { - case CARP_VERSION_CARP: { - struct carp_header *ch = (struct carp_header *)((char *)ip + iplen); + ch = (struct carp_header *)((char *)ip + iplen); carp_input_c(m, ch, AF_INET, ip->ip_ttl); break; } - case CARP_VERSION_VRRPv3: - vrrp_input_c(m, iplen, AF_INET, ip->ip_ttl, totlen - iplen, phdrcksum); + case CARP_VERSION_VRRPv3: { + uint16_t phdrcksum; + + phdrcksum = in_pseudo(ip->ip_src.s_addr, ip->ip_dst.s_addr, + htonl((u_short)(totlen - iplen) + ip->ip_p)); + vrrp_input_c(m, iplen, AF_INET, ip->ip_ttl, totlen - iplen, + phdrcksum); break; + } default: KASSERT(false, ("Unsupported version %d", vh->vrrp_version)); } @@ -634,7 +634,6 @@ carp6_input(struct mbuf **mp, int *offp, int proto) struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); struct vrrpv3_header *vh; u_int len, minlen; - uint16_t phdrcksum = 0; CARPSTATS_INC(carps_ipackets6); @@ -700,31 +699,33 @@ carp6_input(struct mbuf **mp, int *offp, int proto) vh = (struct vrrpv3_header *)mtodo(m, sizeof(*ip6)); } - phdrcksum = in6_cksum_pseudo(ip6, ntohs(ip6->ip6_plen), ip6->ip6_nxt, 0); + switch (vh->vrrp_version) { + case CARP_VERSION_CARP: { + struct carp_header *ch; - /* verify the CARP checksum */ - if (vh->vrrp_version == CARP_VERSION_CARP) { + /* verify the CARP checksum */ m->m_data += *offp; if (in_cksum(m, sizeof(struct carp_header))) { CARPSTATS_INC(carps_badsum); CARP_DEBUG("%s: checksum failed, on %s\n", __func__, if_name(m->m_pkthdr.rcvif)); m_freem(m); - return (IPPROTO_DONE); + break; } m->m_data -= *offp; - } - - switch (vh->vrrp_version) { - case CARP_VERSION_CARP: { - struct carp_header *ch = (struct carp_header *)((char *)ip6 + sizeof(*ip6)); + ch = (struct carp_header *)((char *)ip6 + sizeof(*ip6)); carp_input_c(m, ch, AF_INET6, ip6->ip6_hlim); break; } - case CARP_VERSION_VRRPv3: - vrrp_input_c(m, sizeof(*ip6), AF_INET6, ip6->ip6_hlim, ntohs(ip6->ip6_plen), - phdrcksum); + case CARP_VERSION_VRRPv3: { + uint16_t phdrcksum; + + phdrcksum = in6_cksum_pseudo(ip6, ntohs(ip6->ip6_plen), + ip6->ip6_nxt, 0); + vrrp_input_c(m, sizeof(*ip6), AF_INET6, ip6->ip6_hlim, + ntohs(ip6->ip6_plen), phdrcksum); break; + } default: KASSERT(false, ("Unsupported version %d", vh->vrrp_version)); } @@ -886,7 +887,7 @@ carp_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af, int ttl) /* XXX Replay protection goes here */ - sc->sc_init_counter = 0; + sc->sc_init_counter = false; sc->sc_counter = tmp_counter; sc_tv.tv_sec = sc->sc_advbase; @@ -1624,7 +1625,7 @@ carp_send_arp(struct carp_softc *sc) if (ifa->ifa_addr->sa_family != AF_INET) continue; addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; - arp_announce_ifaddr(sc->sc_carpdev, addr, LLADDR(&sc->sc_addr)); + arp_announce_ifaddr(sc->sc_carpdev, addr, sc->sc_addr); } } @@ -1634,7 +1635,7 @@ carp_iamatch(struct ifaddr *ifa, uint8_t **enaddr) struct carp_softc *sc = ifa->ifa_carp; if (sc->sc_state == MASTER) { - *enaddr = LLADDR(&sc->sc_addr); + *enaddr = sc->sc_addr; return (1); } @@ -1705,12 +1706,12 @@ carp_macmatch6(struct ifnet *ifp, struct mbuf *m, const struct in6_addr *taddr) sizeof(struct carp_softc *), M_NOWAIT); if (mtag == NULL) /* Better a bit than nothing. */ - return (LLADDR(&sc->sc_addr)); + return (sc->sc_addr); bcopy(&sc, mtag + 1, sizeof(sc)); m_tag_prepend(m, mtag); - return (LLADDR(&sc->sc_addr)); + return (sc->sc_addr); } return (NULL); @@ -1732,7 +1733,7 @@ carp_forus(struct ifnet *ifp, u_char *dhost) * CARP_LOCK() is not here, since would protect nothing, but * cause deadlock with if_bridge, calling this under its lock. */ - if (sc->sc_state == MASTER && !bcmp(dhost, LLADDR(&sc->sc_addr), + if (sc->sc_state == MASTER && !bcmp(dhost, sc->sc_addr, ETHER_ADDR_LEN)) { CIF_UNLOCK(ifp->if_carp); return (1); @@ -1821,18 +1822,21 @@ carp_setrun(struct carp_softc *sc, sa_family_t af) case BACKUP: callout_stop(&sc->sc_ad_tmo); - if (sc->sc_version == CARP_VERSION_CARP) { + switch (sc->sc_version) { + case CARP_VERSION_CARP: tv.tv_sec = 3 * sc->sc_advbase; tv.tv_usec = sc->sc_advskew * 1000000 / 256; timeout = tvtohz(&tv); - } else { + break; + case CARP_VERSION_VRRPv3: /* skew time */ - timeout = (256 - sc->sc_vrrp_prio) * sc->sc_vrrp_master_inter / 256; + timeout = (256 - sc->sc_vrrp_prio) * + sc->sc_vrrp_master_inter / 256; timeout += (3 * sc->sc_vrrp_master_inter); timeout *= hz; - timeout /= 100; /* master interval is in centiseconds. */ + timeout /= 100; /* master interval is in centiseconds */ + break; } - switch (af) { #ifdef INET case AF_INET: @@ -1861,15 +1865,18 @@ carp_setrun(struct carp_softc *sc, sa_family_t af) } break; case MASTER: - if (sc->sc_version == CARP_VERSION_CARP) { + switch (sc->sc_version) { + case CARP_VERSION_CARP: tv.tv_sec = sc->sc_advbase; tv.tv_usec = sc->sc_advskew * 1000000 / 256; callout_reset(&sc->sc_ad_tmo, tvtohz(&tv), carp_callout, sc); - } else { + break; + case CARP_VERSION_VRRPv3: callout_reset(&sc->sc_ad_tmo, sc->sc_vrrp_adv_inter * hz / 100, carp_callout, sc); + break; } break; } @@ -2073,7 +2080,7 @@ carp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *sa) } static struct carp_softc* -carp_alloc(struct ifnet *ifp) +carp_alloc(struct ifnet *ifp, carp_version_t version, int vhid) { struct carp_softc *sc; struct carp_if *cif; @@ -2083,25 +2090,31 @@ carp_alloc(struct ifnet *ifp) if ((cif = ifp->if_carp) == NULL) cif = carp_alloc_if(ifp); - sc = malloc(sizeof(*sc), M_CARP, M_WAITOK|M_ZERO); - - sc->sc_version = CARP_VERSION_CARP; - sc->sc_advbase = CARP_DFLTINTV; - sc->sc_vhid = -1; /* required setting */ - sc->sc_init_counter = 1; - sc->sc_state = INIT; - - sc->sc_ifasiz = sizeof(struct ifaddr *); + sc = malloc(sizeof(*sc), M_CARP, M_WAITOK); + *sc = (struct carp_softc ){ + .sc_vhid = vhid, + .sc_version = version, + .sc_state = INIT, + .sc_carpdev = ifp, + .sc_ifasiz = sizeof(struct ifaddr *), + .sc_addr = { 0, 0, 0x5e, 0, 1, vhid }, + }; sc->sc_ifas = malloc(sc->sc_ifasiz, M_CARP, M_WAITOK|M_ZERO); - sc->sc_carpdev = ifp; - sc->sc_carpaddr.s_addr = htonl(INADDR_CARP_GROUP); - sc->sc_carpaddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; - sc->sc_carpaddr6.s6_addr8[15] = 0x12; - - sc->sc_vrrp_adv_inter = 100; - sc->sc_vrrp_master_inter = sc->sc_vrrp_adv_inter; - sc->sc_vrrp_prio = 100; + switch (version) { + case CARP_VERSION_CARP: + sc->sc_advbase = CARP_DFLTINTV; + sc->sc_init_counter = true; + sc->sc_carpaddr.s_addr = htonl(INADDR_CARP_GROUP); + sc->sc_carpaddr6.s6_addr16[0] = IPV6_ADDR_INT16_MLL; + sc->sc_carpaddr6.s6_addr8[15] = 0x12; + break; + case CARP_VERSION_VRRPv3: + sc->sc_vrrp_adv_inter = 100; + sc->sc_vrrp_master_inter = sc->sc_vrrp_adv_inter; + sc->sc_vrrp_prio = 100; + break; + } CARP_LOCK_INIT(sc); #ifdef INET @@ -2226,12 +2239,19 @@ carp_carprcp(void *arg, struct carp_softc *sc, int priv) CARP_LOCK(sc); carpr->carpr_state = sc->sc_state; carpr->carpr_vhid = sc->sc_vhid; - carpr->carpr_advbase = sc->sc_advbase; - carpr->carpr_advskew = sc->sc_advskew; - if (priv) - bcopy(sc->sc_key, carpr->carpr_key, sizeof(carpr->carpr_key)); - else - bzero(carpr->carpr_key, sizeof(carpr->carpr_key)); + switch (sc->sc_version) { + case CARP_VERSION_CARP: + carpr->carpr_advbase = sc->sc_advbase; + carpr->carpr_advskew = sc->sc_advskew; + if (priv) + bcopy(sc->sc_key, carpr->carpr_key, + sizeof(carpr->carpr_key)); + else + bzero(carpr->carpr_key, sizeof(carpr->carpr_key)); + break; + case CARP_VERSION_VRRPv3: + break; + } CARP_UNLOCK(sc); return (true); @@ -2244,10 +2264,21 @@ carp_ioctl_set(if_t ifp, struct carpkreq *carpr) struct carp_softc *sc = NULL; int error = 0; - if (carpr->carpr_vhid <= 0 || carpr->carpr_vhid > CARP_MAXVHID || - carpr->carpr_advbase < 0 || carpr->carpr_advskew < 0 || - (carpr->carpr_version != CARP_VERSION_CARP && - carpr->carpr_version != CARP_VERSION_VRRPv3)) { + if (carpr->carpr_vhid <= 0 || carpr->carpr_vhid > CARP_MAXVHID) + return (EINVAL); + + switch (carpr->carpr_version) { + case CARP_VERSION_CARP: + if (carpr->carpr_advbase != 0 && (carpr->carpr_advbase > 255 || + carpr->carpr_advbase < CARP_DFLTINTV)) + return (EINVAL); + if (carpr->carpr_advskew < 0 || carpr->carpr_advskew >= 255) + return (EINVAL); + break; + case CARP_VERSION_VRRPv3: + /* XXXGL: shouldn't we check anything? */ + break; + default: return (EINVAL); } @@ -2256,46 +2287,36 @@ carp_ioctl_set(if_t ifp, struct carpkreq *carpr) if (sc->sc_vhid == carpr->carpr_vhid) break; } - if (sc == NULL) { - sc = carp_alloc(ifp); - CARP_LOCK(sc); - sc->sc_vhid = carpr->carpr_vhid; - LLADDR(&sc->sc_addr)[0] = 0; - LLADDR(&sc->sc_addr)[1] = 0; - LLADDR(&sc->sc_addr)[2] = 0x5e; - LLADDR(&sc->sc_addr)[3] = 0; - LLADDR(&sc->sc_addr)[4] = 1; - LLADDR(&sc->sc_addr)[5] = sc->sc_vhid; - } else - CARP_LOCK(sc); - sc->sc_version = carpr->carpr_version; - if (carpr->carpr_advbase > 0) { - if (carpr->carpr_advbase > 255 || - carpr->carpr_advbase < CARP_DFLTINTV) { - error = EINVAL; - goto out; + + if (sc == NULL) + sc = carp_alloc(ifp, carpr->carpr_version, carpr->carpr_vhid); + else if (sc->sc_version != carpr->carpr_version) + return (EINVAL); + + CARP_LOCK(sc); + switch (sc->sc_version) { + case CARP_VERSION_CARP: + if (carpr->carpr_advbase != 0) + sc->sc_advbase = carpr->carpr_advbase; + sc->sc_advskew = carpr->carpr_advskew; + if (carpr->carpr_addr.s_addr != INADDR_ANY) + sc->sc_carpaddr = carpr->carpr_addr; + if (!IN6_IS_ADDR_UNSPECIFIED(&carpr->carpr_addr6)) { + memcpy(&sc->sc_carpaddr6, &carpr->carpr_addr6, + sizeof(sc->sc_carpaddr6)); } - sc->sc_advbase = carpr->carpr_advbase; - } - if (carpr->carpr_advskew >= 255) { - error = EINVAL; - goto out; - } - sc->sc_advskew = carpr->carpr_advskew; - if (carpr->carpr_addr.s_addr != INADDR_ANY) - sc->sc_carpaddr = carpr->carpr_addr; - if (! IN6_IS_ADDR_UNSPECIFIED(&carpr->carpr_addr6)) { - memcpy(&sc->sc_carpaddr6, &carpr->carpr_addr6, - sizeof(sc->sc_carpaddr6)); - } - if (carpr->carpr_key[0] != '\0') { - bcopy(carpr->carpr_key, sc->sc_key, sizeof(sc->sc_key)); - carp_hmac_prepare(sc); + if (carpr->carpr_key[0] != '\0') { + bcopy(carpr->carpr_key, sc->sc_key, sizeof(sc->sc_key)); + carp_hmac_prepare(sc); + } + break; + case CARP_VERSION_VRRPv3: + if (carpr->carpr_vrrp_priority != 0) + sc->sc_vrrp_prio = carpr->carpr_vrrp_priority; + if (carpr->carpr_vrrp_adv_inter) + sc->sc_vrrp_adv_inter = carpr->carpr_vrrp_adv_inter; + break; } - if (carpr->carpr_vrrp_priority != 0) - sc->sc_vrrp_prio = carpr->carpr_vrrp_priority; - if (carpr->carpr_vrrp_adv_inter) - sc->sc_vrrp_adv_inter = carpr->carpr_vrrp_adv_inter; if (sc->sc_state != INIT && carpr->carpr_state != sc->sc_state) { @@ -2317,8 +2338,6 @@ carp_ioctl_set(if_t ifp, struct carpkreq *carpr) break; } } - -out: CARP_UNLOCK(sc); return (error); @@ -2373,7 +2392,9 @@ int carp_ioctl(struct ifreq *ifr, u_long cmd, struct thread *td) { struct carpreq carpr; - struct carpkreq carprk = { }; + struct carpkreq carprk = { + .carpr_version = CARP_VERSION_CARP, + }; struct ifnet *ifp; int error = 0; @@ -2497,7 +2518,8 @@ carp_attach(struct ifaddr *ifa, int vhid) CARP_LOCK(sc); sc->sc_ifas[index - 1] = ifa; ifa->ifa_carp = sc; - carp_hmac_prepare(sc); + if (sc->sc_version == CARP_VERSION_CARP) + carp_hmac_prepare(sc); carp_sc_state(sc); CARP_UNLOCK(sc); @@ -2550,7 +2572,8 @@ carp_detach(struct ifaddr *ifa, bool keep_cif) ifa->ifa_carp = NULL; ifa_free(ifa); - carp_hmac_prepare(sc); + if (sc->sc_version == CARP_VERSION_CARP) + carp_hmac_prepare(sc); carp_sc_state(sc); if (!keep_cif && sc->sc_naddrs == 0 && sc->sc_naddrs6 == 0) @@ -2742,16 +2765,23 @@ carp_nl_send(void *arg, struct carp_softc *sc, int priv) nlattr_add_u32(nw, CARP_NL_VHID, sc->sc_vhid); nlattr_add_u32(nw, CARP_NL_STATE, sc->sc_state); - nlattr_add_s32(nw, CARP_NL_ADVBASE, sc->sc_advbase); - nlattr_add_s32(nw, CARP_NL_ADVSKEW, sc->sc_advskew); - nlattr_add_in_addr(nw, CARP_NL_ADDR, &sc->sc_carpaddr); - nlattr_add_in6_addr(nw, CARP_NL_ADDR6, &sc->sc_carpaddr6); nlattr_add_u8(nw, CARP_NL_VERSION, sc->sc_version); - nlattr_add_u8(nw, CARP_NL_VRRP_PRIORITY, sc->sc_vrrp_prio); - nlattr_add_u16(nw, CARP_NL_VRRP_ADV_INTER, sc->sc_vrrp_adv_inter); - - if (priv) - nlattr_add(nw, CARP_NL_KEY, sizeof(sc->sc_key), sc->sc_key); + switch (sc->sc_version) { + case CARP_VERSION_CARP: + nlattr_add_s32(nw, CARP_NL_ADVBASE, sc->sc_advbase); + nlattr_add_s32(nw, CARP_NL_ADVSKEW, sc->sc_advskew); + nlattr_add_in_addr(nw, CARP_NL_ADDR, &sc->sc_carpaddr); + nlattr_add_in6_addr(nw, CARP_NL_ADDR6, &sc->sc_carpaddr6); + if (priv) + nlattr_add(nw, CARP_NL_KEY, sizeof(sc->sc_key), + sc->sc_key); + break; + case CARP_VERSION_VRRPv3: + nlattr_add_u8(nw, CARP_NL_VRRP_PRIORITY, sc->sc_vrrp_prio); + nlattr_add_u16(nw, CARP_NL_VRRP_ADV_INTER, + sc->sc_vrrp_adv_inter); + break; + } CARP_UNLOCK(sc); @@ -2865,19 +2895,24 @@ carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt) return (EINVAL); if (attrs.state > CARP_MAXSTATE) return (EINVAL); - if (attrs.advbase < 0 || attrs.advskew < 0) - return (EINVAL); - if (attrs.advbase > 255) - return (EINVAL); - if (attrs.advskew >= 255) - return (EINVAL); - if (attrs.version == 0) + if (attrs.version == 0) /* compat with pre-VRRPv3 */ attrs.version = CARP_VERSION_CARP; - if (attrs.version != CARP_VERSION_CARP && - attrs.version != CARP_VERSION_VRRPv3) - return (EINVAL); - if (attrs.vrrp_adv_inter > VRRP_MAX_INTERVAL) + switch (attrs.version) { + case CARP_VERSION_CARP: + if (attrs.advbase < 0 || attrs.advskew < 0) + return (EINVAL); + if (attrs.advbase > 255) + return (EINVAL); + if (attrs.advskew >= 255) + return (EINVAL); + break; + case CARP_VERSION_VRRPv3: + if (attrs.vrrp_adv_inter > VRRP_MAX_INTERVAL) + return (EINVAL); + break; + default: return (EINVAL); + } NET_EPOCH_ENTER(et); if (attrs.ifname != NULL) @@ -2897,15 +2932,20 @@ carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt) carpr.carpr_count = 1; carpr.carpr_vhid = attrs.vhid; carpr.carpr_state = attrs.state; - carpr.carpr_advbase = attrs.advbase; - carpr.carpr_advskew = attrs.advskew; - carpr.carpr_addr = attrs.addr; - carpr.carpr_addr6 = attrs.addr6; carpr.carpr_version = attrs.version; - carpr.carpr_vrrp_priority = attrs.vrrp_prio; - carpr.carpr_vrrp_adv_inter = attrs.vrrp_adv_inter; - - memcpy(&carpr.carpr_key, &attrs.key, sizeof(attrs.key)); + switch (attrs.version) { + case CARP_VERSION_CARP: + carpr.carpr_advbase = attrs.advbase; + carpr.carpr_advskew = attrs.advskew; + carpr.carpr_addr = attrs.addr; + carpr.carpr_addr6 = attrs.addr6; + memcpy(&carpr.carpr_key, &attrs.key, sizeof(attrs.key)); + break; + case CARP_VERSION_VRRPv3: + carpr.carpr_vrrp_priority = attrs.vrrp_prio; + carpr.carpr_vrrp_adv_inter = attrs.vrrp_adv_inter; + break; + } sx_xlock(&carp_sx); error = carp_ioctl_set(ifp, &carpr);