summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdladm
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2013-08-20 12:46:33 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2013-08-20 12:46:33 +0000
commit8302f394821111c3580a65235587303036ff42d9 (patch)
treeacbe4e08936204a9766a9b212deb27330ce9b10e /usr/src/lib/libdladm
parent1fbda5aea84129b7604f310ec37f429deda7f045 (diff)
downloadillumos-joyent-8302f394821111c3580a65235587303036ff42d9.tar.gz
OS-1535 allowed-ips should let you specify prefixes
Diffstat (limited to 'usr/src/lib/libdladm')
-rw-r--r--usr/src/lib/libdladm/common/linkprop.c70
1 files changed, 69 insertions, 1 deletions
diff --git a/usr/src/lib/libdladm/common/linkprop.c b/usr/src/lib/libdladm/common/linkprop.c
index d46054e686..8c0a5daf9f 100644
--- a/usr/src/lib/libdladm/common/linkprop.c
+++ b/usr/src/lib/libdladm/common/linkprop.c
@@ -20,7 +20,7 @@
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, Joyent, Inc. All rights reserved.
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
#include <stdlib.h>
@@ -2333,6 +2333,33 @@ get_protection(dladm_handle_t handle, prop_desc_t *pdp,
return (DLADM_STATUS_OK);
}
+static uint32_t
+nbits_to_mask(int nbits)
+{
+ int i;
+ uint_t mask = 0;
+
+ for (i = 0; i < nbits; i++) {
+ mask >>= 1;
+ mask |= 0x80000000;
+ }
+
+ return (mask);
+}
+
+static uint32_t
+mask_to_nbits(uint32_t mask)
+{
+ uint_t nbits = 0;
+
+ while (mask != 0) {
+ nbits++;
+ mask <<= 1;
+ }
+
+ return (nbits);
+}
+
/* ARGSUSED */
static dladm_status_t
get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
@@ -2360,9 +2387,16 @@ get_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
for (i = 0; i < p->mp_ipaddrcnt; i++) {
if (p->mp_ipaddrs[i].ip_version == IPV4_VERSION) {
ipaddr_t v4addr;
+ uint32_t mask;
v4addr = V4_PART_OF_V6(p->mp_ipaddrs[i].ip_addr);
+ mask = p->mp_ipaddrs[i].ip_v4netmask;
(void) dladm_ipv4addr2str(&v4addr, prop_val[i]);
+ if (mask != 0) {
+ int len = strlen(prop_val[i]);
+ (void)sprintf(prop_val[i] + len, "/%d",
+ mask_to_nbits(mask));
+ }
} else {
(void) dladm_ipv6addr2str(&p->mp_ipaddrs[i].ip_addr,
prop_val[i]);
@@ -2414,6 +2448,28 @@ check_single_ip(char *buf, mac_ipaddr_t *addr)
ipaddr_t v4addr;
in6_addr_t v6addr;
boolean_t isv4 = B_TRUE;
+ char *p;
+ uint32_t mask;
+
+ /*
+ * If the IP address is in CIDR format, parse the bits component
+ * seperately. An address in this style will be used to indicate an
+ * entire subnet, so it must be a network number with no host address.
+ */
+ if ((p = strchr(buf, '/')) != NULL) {
+ char *end = NULL;
+ long msk;
+
+ *p++ = '\0';
+ if (!isdigit(*p))
+ return (DLADM_STATUS_INVALID_IP);
+ msk = strtol(p, &end, 10);
+ if (end != NULL && *end != '\0')
+ return (DLADM_STATUS_INVALID_IP);
+ if (msk > 32 || msk < 1)
+ return (DLADM_STATUS_INVALID_IP);
+ mask = nbits_to_mask((int)msk);
+ }
status = dladm_str2ipv4addr(buf, &v4addr);
if (status == DLADM_STATUS_INVALID_IP) {
@@ -2430,10 +2486,22 @@ check_single_ip(char *buf, mac_ipaddr_t *addr)
IN6_IPADDR_TO_V4MAPPED(v4addr, &addr->ip_addr);
addr->ip_version = IPV4_VERSION;
+ if (p != NULL) {
+ /*
+ * We have a CIDR style address, confirm that only the
+ * network number is set.
+ */
+ if (htonl(v4addr) & ~mask)
+ return (DLADM_STATUS_INVALID_IP);
+ addr->ip_v4netmask = mask;
+ }
} else {
if (IN6_IS_ADDR_UNSPECIFIED(&v6addr))
return (DLADM_STATUS_INVALID_IP);
+ if (p != NULL)
+ return (DLADM_STATUS_INVALID_IP);
+
addr->ip_addr = v6addr;
addr->ip_version = IPV6_VERSION;
}