Page MenuHomeFreeBSD

D39048.id118727.diff
No OneTemporary

D39048.id118727.diff

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 <net/if.h>
#include <netinet/ip_carp.h>
+#include <netinet/ip_carp_nl.h>
#include <netlink/netlink.h>
#include <netlink/netlink_generic.h>
@@ -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 <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/ip_carp.h>
+#include <netinet/ip_carp_nl.h>
#include <netinet/ip.h>
#include <machine/in_cksum.h>
#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 <net/if.h>
+
+#include <netinet/ip_carp.h>
+#include <netlink/netlink_generic.h>
+
+/*
+ * 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

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 22, 11:17 AM (20 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31973185
Default Alt Text
D39048.id118727.diff (20 KB)

Event Timeline