Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153492602
D39048.id118727.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
D39048.id118727.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D39048: carp: add netlink interface
Attached
Detach File
Event Timeline
Log In to Comment