diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h --- a/lib/libifconfig/libifconfig.h +++ b/lib/libifconfig/libifconfig.h @@ -289,8 +289,12 @@ uint8_t carpr_key[CARP_KEY_LEN]; }; +int ifconfig_carp_get_vhid(ifconfig_handle_t *h, const char *name, + struct ifconfig_carp *carpr, uint32_t vhid); int ifconfig_carp_get_info(ifconfig_handle_t *h, const char *name, struct ifconfig_carp *carpr, size_t ncarp); +int ifconfig_carp_set_info(ifconfig_handle_t *h, const char *name, + const struct ifconfig_carp *carpr); /** Retrieve additional information about an inet address * @param h An open ifconfig state object diff --git a/lib/libifconfig/libifconfig_carp.c b/lib/libifconfig/libifconfig_carp.c --- a/lib/libifconfig/libifconfig_carp.c +++ b/lib/libifconfig/libifconfig_carp.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -121,41 +122,57 @@ SNL_DECLARE_PARSER(carp_get_parser, struct genlmsghdr, fp_carp_get, ap_carp_get); -int -ifconfig_carp_get_info(ifconfig_handle_t *h, const char *name, - struct ifconfig_carp *carp, size_t ncarp) +static int +_ifconfig_carp_get(ifconfig_handle_t *h, const char *name, + struct ifconfig_carp *carp, size_t ncarp, uint32_t vhid) { struct snl_state ss = {}; + struct snl_writer nw; + struct carp_get_msg *cg; + struct nlmsghdr *hdr; size_t i = 0; int family_id; ifconfig_error_clear(h); - snl_init(&ss, NETLINK_GENERIC); + if (! snl_init(&ss, NETLINK_GENERIC)) { + ifconfig_error(h, NETLINK, ENOTSUP); + return (-1); + } + + snl_init_writer(&ss, &nw); family_id = snl_get_genl_family(h, &ss, CARP_NL_FAMILY_NAME); if (family_id == 0) - return (h->error.errcode); + goto out; - struct { - struct nlmsghdr hdr; - struct genlmsghdr ghdr; - char ifname[IFNAMSIZ]; - } nlh = { - .hdr.nlmsg_len = sizeof(nlh), - .hdr.nlmsg_type = family_id, - .hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, - .hdr.nlmsg_seq = snl_get_seq(&ss), - .ghdr.cmd = CARP_NL_CMD_GET, - }; - memcpy(nlh.ifname, name, IFNAMSIZ); - snl_send(&ss, &nlh, NLMSG_ALIGN(nlh.hdr.nlmsg_len)); + hdr = snl_create_msg_request(&nw, family_id); + hdr->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; + + cg = snl_reserve_msg_object(&nw, struct carp_get_msg); + cg->genlmsghdr.cmd = CARP_NL_CMD_GET; + memcpy(cg->ifname, name, IFNAMSIZ); + + if (vhid != 0) { + if (! snl_add_msg_attr_u32(&nw, CARP_GET_VHID, vhid)) { + ifconfig_error(h, NETLINK, ENOMEM); + goto out; + } + } + hdr = snl_finalize_msg(&nw); + if (hdr == NULL) { + ifconfig_error(h, NETLINK, ENOMEM); + goto out; + } + if (! snl_send(&ss, hdr, NLMSG_ALIGN(hdr->nlmsg_len))) { + ifconfig_error(h, NETLINK, EIO); + goto out; + } while (true) { - struct nlmsghdr *hdr = snl_read_message(&ss); + hdr = snl_read_message(&ss); if (hdr->nlmsg_type == NLMSG_DONE) { - printf("KP: %s() done!\n", __func__); break; } @@ -176,9 +193,90 @@ i++; carp[0].carpr_count = i; + + if (i > ncarp) { + ifconfig_error(h, NETLINK, E2BIG); + break; + } } +out: snl_free(&ss); - return (h->error.errcode); + return (h->error.errcode ? -1 : 0); +} + +int +ifconfig_carp_set_info(ifconfig_handle_t *h, const char *name, + const struct ifconfig_carp *carpr) +{ + struct snl_state ss = {}; + struct snl_writer nw; + struct carp_set_msg *cs; + struct nlmsghdr *hdr; + int family_id; + + ifconfig_error_clear(h); + + if (! snl_init(&ss, NETLINK_GENERIC)) { + ifconfig_error(h, NETLINK, ENOTSUP); + return (-1); + } + + snl_init_writer(&ss, &nw); + + family_id = snl_get_genl_family(h, &ss, CARP_NL_FAMILY_NAME); + if (family_id == 0) + return (-1); + + hdr = snl_create_msg_request(&nw, family_id); + hdr->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK; + + cs = snl_reserve_msg_object(&nw, struct carp_set_msg); + cs->genlmsghdr.cmd = CARP_NL_CMD_SET; + + cs->vhid = carpr->carpr_vhid; + cs->state = carpr->carpr_state; + cs->advbase = carpr->carpr_advbase; + cs->advskew = carpr->carpr_advskew; + memcpy(cs->ifname, name, IFNAMSIZ); + memcpy(cs->key, carpr->carpr_key, CARP_KEY_LEN); + + hdr = snl_finalize_msg(&nw); + if (hdr == NULL) { + ifconfig_error(h, NETLINK, ENOMEM); + goto out; + } + + if (! snl_send(&ss, hdr, NLMSG_ALIGN(hdr->nlmsg_len))) { + ifconfig_error(h, NETLINK, EIO); + goto out; + } + + hdr = snl_read_message(&ss); + if (hdr->nlmsg_type == NLMSG_DONE) + goto out; + if (hdr->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *nlerr = (struct nlmsgerr *)(hdr + 1); + ifconfig_error(h, NETLINK, nlerr->error); + } + +out: + snl_free(&ss); + + return (h->error.errcode ? -1 : 0); +} + +int +ifconfig_carp_get_vhid(ifconfig_handle_t *h, const char *name, + struct ifconfig_carp *carp, uint32_t vhid) +{ + return (_ifconfig_carp_get(h, name, carp, 1, vhid)); +} + +int +ifconfig_carp_get_info(ifconfig_handle_t *h, const char *name, + struct ifconfig_carp *carp, size_t ncarp) +{ + return (_ifconfig_carp_get(h, name, carp, ncarp, 0)); } diff --git a/sbin/ifconfig/carp.c b/sbin/ifconfig/carp.c --- a/sbin/ifconfig/carp.c +++ b/sbin/ifconfig/carp.c @@ -129,16 +129,14 @@ static void setcarp_callback(int s, void *arg __unused) { - struct carpreq carpr; + struct ifconfig_carp carpr = { }; - bzero(&carpr, sizeof(struct carpreq)); - carpr.carpr_vhid = carpr_vhid; - carpr.carpr_count = 1; - ifr.ifr_data = (caddr_t)&carpr; - - if (ioctl(s, SIOCGVH, (caddr_t)&ifr) == -1 && errno != ENOENT) - err(1, "SIOCGVH"); + if (ifconfig_carp_get_vhid(lifh, name, &carpr, carpr_vhid) == -1) { + if (ifconfig_err_errno(lifh) != ENOENT) + return; + } + carpr.carpr_vhid = carpr_vhid; if (carpr_key != NULL) /* XXX Should hash the password into the key here? */ strlcpy(carpr.carpr_key, carpr_key, CARP_KEY_LEN); @@ -149,7 +147,7 @@ if (carpr_state > -1) carpr.carpr_state = carpr_state; - if (ioctl(s, SIOCSVH, (caddr_t)&ifr) == -1) + if (ifconfig_carp_set_info(lifh, name, &carpr)) err(1, "SIOCSVH"); } diff --git a/sys/netinet/ip_carp.h b/sys/netinet/ip_carp.h --- a/sys/netinet/ip_carp.h +++ b/sys/netinet/ip_carp.h @@ -119,28 +119,6 @@ uint64_t carps_preempt; /* if enabled, preemptions */ }; -/* - * Netlink interface to carp(4). - */ -#define CARP_NL_FAMILY_NAME "carp" - -/* commands */ -enum { - CARP_NL_CMD_UNSPEC = 0, - CARP_NL_CMD_GET = 1, - __CARP_NL_CMD_MAX, -}; -#define CARP_NL_CMD_MAX (__CARP_NL_CMD_MAX - 1) - -enum carp_get_type_t { - CARP_GET_UNSPEC, - CARP_GET_VHID = 1, /* u32 */ - CARP_GET_STATE = 2, /* u32 */ - CARP_GET_ADVBASE = 3, /* s32 */ - CARP_GET_ADVSKEW = 4, /* s32 */ - CARP_GET_KEY = 5, /* byte array */ -}; - /* * Configuration structure for SIOCSVH SIOCGVH */ diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c --- a/sys/netinet/ip_carp.c +++ b/sys/netinet/ip_carp.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include #endif @@ -1714,9 +1715,10 @@ free(cif, M_CARP); } -static void -carp_carprcp(struct carpreq *carpr, struct carp_softc *sc, int priv) +static bool +carp_carprcp(void *arg, struct carp_softc *sc, int priv) { + struct carpreq *carpr = arg; CARP_LOCK(sc); carpr->carpr_state = sc->sc_state; @@ -1728,6 +1730,126 @@ else bzero(carpr->carpr_key, sizeof(carpr->carpr_key)); CARP_UNLOCK(sc); + + return (true); +} + +static int +carp_ioctl_set(if_t ifp, struct ucred *cred, struct carpreq *carpr) +{ + struct carp_softc *sc = NULL; + int error = 0; + + if ((error = priv_check_cred(cred, PRIV_NETINET_CARP))) + return (error); + + if (carpr->carpr_vhid <= 0 || carpr->carpr_vhid > CARP_MAXVHID || + carpr->carpr_advbase < 0 || carpr->carpr_advskew < 0) { + return (EINVAL); + } + + if (ifp->if_carp) { + IFNET_FOREACH_CARP(ifp, sc) + 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); + if (carpr->carpr_advbase > 0) { + if (carpr->carpr_advbase > 255 || + carpr->carpr_advbase < CARP_DFLTINTV) { + error = EINVAL; + goto out; + } + sc->sc_advbase = carpr->carpr_advbase; + } + if (carpr->carpr_advskew >= 255) { + error = EINVAL; + goto out; + } + sc->sc_advskew = carpr->carpr_advskew; + if (carpr->carpr_key[0] != '\0') { + bcopy(carpr->carpr_key, sc->sc_key, sizeof(sc->sc_key)); + carp_hmac_prepare(sc); + } + if (sc->sc_state != INIT && + carpr->carpr_state != sc->sc_state) { + switch (carpr->carpr_state) { + case BACKUP: + callout_stop(&sc->sc_ad_tmo); + carp_set_state(sc, BACKUP, + "user requested via ifconfig"); + carp_setrun(sc, 0); + carp_delroute(sc); + break; + case MASTER: + carp_master_down_locked(sc, + "user requested via ifconfig"); + break; + default: + break; + } + } + +out: + CARP_UNLOCK(sc); + + return (error); +} + +static int +carp_ioctl_get(if_t ifp, struct ucred *cred, struct carpreq *carpr, + bool (*outfn)(void *, struct carp_softc *, int), void *arg) +{ + int priveleged; + struct carp_softc *sc; + + if (carpr->carpr_vhid < 0 || carpr->carpr_vhid > CARP_MAXVHID) + return (EINVAL); + if (carpr->carpr_count < 1) + return (EMSGSIZE); + if (ifp->if_carp == NULL) + return (ENOENT); + + priveleged = (priv_check_cred(cred, PRIV_NETINET_CARP) == 0); + if (carpr->carpr_vhid != 0) { + IFNET_FOREACH_CARP(ifp, sc) + if (sc->sc_vhid == carpr->carpr_vhid) + break; + if (sc == NULL) + return (ENOENT); + + if (! outfn(arg, sc, priveleged)) + return (ENOMEM); + carpr->carpr_count = 1; + } else { + int count; + + count = 0; + IFNET_FOREACH_CARP(ifp, sc) + count++; + + if (count > carpr->carpr_count) + return (EMSGSIZE); + + IFNET_FOREACH_CARP(ifp, sc) { + if (! outfn(arg, sc, priveleged)) + return (ENOMEM); + carpr->carpr_count = count; + } + } + + return (0); } int @@ -1735,8 +1857,7 @@ { struct carpreq carpr; struct ifnet *ifp; - struct carp_softc *sc = NULL; - int error = 0, locked = 0; + int error = 0; if ((error = copyin(ifr_data_get_ptr(ifr), &carpr, sizeof carpr))) return (error); @@ -1763,135 +1884,24 @@ sx_xlock(&carp_sx); switch (cmd) { case SIOCSVH: - if ((error = priv_check(td, PRIV_NETINET_CARP))) - break; - if (carpr.carpr_vhid <= 0 || carpr.carpr_vhid > CARP_MAXVHID || - carpr.carpr_advbase < 0 || carpr.carpr_advskew < 0) { - error = EINVAL; - break; - } - - if (ifp->if_carp) { - IFNET_FOREACH_CARP(ifp, sc) - 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); - locked = 1; - if (carpr.carpr_advbase > 0) { - if (carpr.carpr_advbase > 255 || - carpr.carpr_advbase < CARP_DFLTINTV) { - error = EINVAL; - break; - } - sc->sc_advbase = carpr.carpr_advbase; - } - if (carpr.carpr_advskew >= 255) { - error = EINVAL; - break; - } - sc->sc_advskew = carpr.carpr_advskew; - if (carpr.carpr_key[0] != '\0') { - bcopy(carpr.carpr_key, sc->sc_key, sizeof(sc->sc_key)); - carp_hmac_prepare(sc); - } - if (sc->sc_state != INIT && - carpr.carpr_state != sc->sc_state) { - switch (carpr.carpr_state) { - case BACKUP: - callout_stop(&sc->sc_ad_tmo); - carp_set_state(sc, BACKUP, - "user requested via ifconfig"); - carp_setrun(sc, 0); - carp_delroute(sc); - break; - case MASTER: - carp_master_down_locked(sc, - "user requested via ifconfig"); - break; - default: - break; - } - } + error = carp_ioctl_set(ifp, td->td_ucred, &carpr); break; case SIOCGVH: - { - int priveleged; - - if (carpr.carpr_vhid < 0 || carpr.carpr_vhid > CARP_MAXVHID) { - error = EINVAL; - break; - } - if (carpr.carpr_count < 1) { - error = EMSGSIZE; - break; - } - if (ifp->if_carp == NULL) { - error = ENOENT; - break; - } - - priveleged = (priv_check(td, PRIV_NETINET_CARP) == 0); - if (carpr.carpr_vhid != 0) { - IFNET_FOREACH_CARP(ifp, sc) - if (sc->sc_vhid == carpr.carpr_vhid) - break; - if (sc == NULL) { - error = ENOENT; - break; - } - carp_carprcp(&carpr, sc, priveleged); - error = copyout(&carpr, ifr_data_get_ptr(ifr), - sizeof(carpr)); - } else { - int i, count; - - count = 0; - IFNET_FOREACH_CARP(ifp, sc) - count++; - - if (count > carpr.carpr_count) { - CIF_UNLOCK(ifp->if_carp); - error = EMSGSIZE; - break; - } - - i = 0; - IFNET_FOREACH_CARP(ifp, sc) { - carp_carprcp(&carpr, sc, priveleged); - carpr.carpr_count = count; - error = copyout(&carpr, - (char *)ifr_data_get_ptr(ifr) + - (i * sizeof(carpr)), sizeof(carpr)); - if (error) { - CIF_UNLOCK(ifp->if_carp); - break; - } - i++; - } + error = carp_ioctl_get(ifp, td->td_ucred, &carpr, + carp_carprcp, &carpr); + if (error == 0) { + error = copyout(&carpr, + (char *)ifr_data_get_ptr(ifr), + carpr.carpr_count * sizeof(carpr)); } break; - } default: error = EINVAL; } sx_xunlock(&carp_sx); out: - if (locked) - CARP_UNLOCK(sc); if_rele(ifp); return (error); @@ -2183,26 +2193,43 @@ return (0); } +static int +nlf_get_carp_key(void *src, struct nl_pstate *npt, void *target) +{ + /* XXX How can we be sure about available data size here? */ + memcpy(target, src, CARP_KEY_LEN); + return (0); +} + struct nl_carp_parsed_get { char ifname[IFNAMSIZ]; uint32_t vhid; }; -#define _IN(_field) offsetof(struct genlmsghdr, _field) +#define _IN(_field) offsetof(struct carp_get_msg, _field) #define _OUT(_field) offsetof(struct nl_carp_parsed_get, _field) static const struct nlattr_parser nla_p_get[] = { { .type = CARP_GET_VHID, .off = _OUT(vhid), .cb = nlattr_get_uint32 }, }; static const struct nlfield_parser nlf_p_get[] = { - { .off_in = sizeof(struct genlmsghdr), .off_out = 0, .cb = nlf_get_ifnam }, /* XXX TODO: define a struct for the fields in this request? */ + { .off_in = _IN(ifname), .off_out = 0, .cb = nlf_get_ifnam }, +}; +NL_DECLARE_PARSER(carp_get_parser, struct carp_get_msg, nlf_p_get, nla_p_get); +#undef _IN +#undef _OUT + +struct carp_nl_send_args { + struct nlmsghdr *hdr; + struct nl_pstate *npt; }; -NL_DECLARE_PARSER(carp_get_parser, struct genlmsghdr, nlf_p_get, nla_p_get); static bool -carp_nl_send(struct nlmsghdr *hdr, struct nl_pstate *npt, - struct carp_softc *sc, int priveleged) +carp_nl_send(void *arg, struct carp_softc *sc, int priv) { + struct carp_nl_send_args *nlsa = arg; + struct nlmsghdr *hdr = nlsa->hdr; + struct nl_pstate *npt = nlsa->npt; struct nl_writer *nw = npt->nw; struct genlmsghdr *ghdr_new; @@ -2228,7 +2255,7 @@ nlattr_add_s32(nw, CARP_GET_ADVBASE, sc->sc_advbase); nlattr_add_s32(nw, CARP_GET_ADVSKEW, sc->sc_advskew); - if (priveleged) + if (priv) nlattr_add(nw, CARP_GET_KEY, sizeof(sc->sc_key), sc->sc_key); CARP_UNLOCK(sc); @@ -2245,7 +2272,8 @@ carp_nl_get(struct nlmsghdr *hdr, struct nl_pstate *npt) { struct nl_carp_parsed_get attrs = { }; - struct carp_softc *sc; + struct carp_nl_send_args args; + struct carpreq carpr = { }; if_t ifp; int error; @@ -2253,7 +2281,84 @@ if (error != 0) return (error); - if (attrs.vhid < 0 || attrs.vhid > CARP_MAXVHID) + ifp = ifunit_ref(attrs.ifname); + if (ifp == NULL) + return (ENXIO); + + switch (ifp->if_type) { + case IFT_ETHER: + case IFT_L2VLAN: + case IFT_BRIDGE: + break; + default: + error = EOPNOTSUPP; + goto out; + } + + args.hdr = hdr; + args.npt = npt; + + carpr.carpr_vhid = attrs.vhid; + carpr.carpr_count = CARP_MAXVHID; + + sx_xlock(&carp_sx); + error = carp_ioctl_get(ifp, npt->nlp->nl_cred, &carpr, carp_nl_send, + &args); + sx_xunlock(&carp_sx); + +out: + if_rele(ifp); + + return (error); +} + +struct nl_carp_parsed_set { + char ifname[IFNAMSIZ]; + uint32_t state; + uint32_t vhid; + int32_t advbase; + int32_t advskew; + char key[CARP_KEY_LEN]; +}; + +#define _IN(_field) offsetof(struct carp_set_msg, _field) +#define _OUT(_field) offsetof(struct nl_carp_parsed_set, _field) + +static const struct nlattr_parser nla_p_set[] = { +}; +static const struct nlfield_parser nlf_p_set[] = { + { .off_in = _IN(ifname), .off_out = _OUT(ifname), .cb = nlf_get_ifnam }, + { .off_in = _IN(state), .off_out = _OUT(state), .cb = nlf_get_u32 }, + { .off_in = _IN(vhid), .off_out = _OUT(vhid), .cb = nlf_get_u32 }, + { .off_in = _IN(advbase), .off_out = _OUT(advbase), .cb = nlf_get_u32 }, + { .off_in = _IN(advskew), .off_out = _OUT(advskew), .cb = nlf_get_u32 }, + { .off_in = _IN(key), .off_out = _OUT(key), .cb = nlf_get_carp_key }, +}; +NL_DECLARE_PARSER(carp_set_parser, struct carp_set_msg, nlf_p_set, nla_p_set); +#undef _IN +#undef _OUT + +static int +carp_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt) +{ + struct nl_carp_parsed_set attrs = { }; + struct carpreq carpr; + if_t ifp; + int error; + + error = nl_parse_nlmsg(hdr, &carp_set_parser, npt, &attrs); + if (error != 0) + return (error); + + if (attrs.vhid <= 0 || attrs.vhid > CARP_MAXVHID) + 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); ifp = ifunit_ref(attrs.ifname); @@ -2270,52 +2375,32 @@ goto out; } - /* XXX May want to allow this anyway in unicast mode? */ if ((ifp->if_flags & IFF_MULTICAST) == 0) { error = EADDRNOTAVAIL; goto out; } - sx_xlock(&carp_sx); - - if (ifp->if_carp == NULL) { - error = ENOENT; - goto out_unlock; - } - - int priveleged = (priv_check_cred(npt->nlp->nl_cred, - PRIV_NETINET_CARP) == 0); - if (attrs.vhid != 0) { - IFNET_FOREACH_CARP(ifp, sc) - if (sc->sc_vhid == attrs.vhid) - break; - if (sc == NULL) { - error = ENOENT; - goto out_unlock; - } + carpr.carpr_count = 1; + carpr.carpr_vhid = attrs.vhid; + carpr.carpr_state = attrs.state; + carpr.carpr_advbase = attrs.advbase; + carpr.carpr_advskew = attrs.advskew; + memcpy(&carpr.carpr_key, &attrs.key, sizeof(attrs.key)); - if (! carp_nl_send(hdr, npt, sc, priveleged)) { - error = ENOMEM; - goto out_unlock; - } - } else { - IFNET_FOREACH_CARP(ifp, sc) { - if (! carp_nl_send(hdr, npt, sc, priveleged)) { - error = ENOMEM; - goto out_unlock; - } - } - } - -out_unlock: + sx_xlock(&carp_sx); + error = carp_ioctl_set(ifp, npt->nlp->nl_cred, &carpr); sx_xunlock(&carp_sx); + out: if_rele(ifp); return (error); } -static const struct nlhdr_parser *all_parsers[] = { &carp_get_parser }; +static const struct nlhdr_parser *all_parsers[] = { + &carp_get_parser, + &carp_set_parser +}; static const struct genl_cmd carp_cmds[] = { { @@ -2325,6 +2410,12 @@ .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, }, + { + .cmd_num = CARP_NL_CMD_SET, + .cmd_name = "SIOCSVH", + .cmd_cb = carp_nl_set, + .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_HASPOL, + }, }; static void diff --git a/sys/netinet/ip_carp_nl.h b/sys/netinet/ip_carp_nl.h new file mode 100644 --- /dev/null +++ b/sys/netinet/ip_carp_nl.h @@ -0,0 +1,48 @@ +#ifndef _IP_CARP_NL_H +#define _IP_CARP_NL_H + +#include + +#include +#include + +/* + * Netlink interface to carp(4). + */ + +#define CARP_NL_FAMILY_NAME "carp" + +/* commands */ +enum { + CARP_NL_CMD_UNSPEC = 0, + CARP_NL_CMD_GET = 1, + CARP_NL_CMD_SET = 2, + __CARP_NL_CMD_MAX, +}; +#define CARP_NL_CMD_MAX (__CARP_NL_CMD_MAX - 1) + +enum carp_get_type_t { + CARP_GET_UNSPEC, + CARP_GET_VHID = 1, /* u32 */ + CARP_GET_STATE = 2, /* u32 */ + CARP_GET_ADVBASE = 3, /* s32 */ + CARP_GET_ADVSKEW = 4, /* s32 */ + CARP_GET_KEY = 5, /* byte array */ +}; + +struct carp_get_msg { + struct genlmsghdr genlmsghdr; + char ifname[IFNAMSIZ]; +}; + +struct carp_set_msg { + struct genlmsghdr genlmsghdr; + char ifname[IFNAMSIZ]; + uint32_t vhid; + uint32_t state; + int32_t advbase; + int32_t advskew; + char key[CARP_KEY_LEN]; +}; + +#endif