PSARC/2009/436 Anti-spoofing Link Protection
PSARC/2009/488 flowadm(1m) remote_port flow attribute
6884729 Integrate Link Protection Phase I
6882391 Offer flowadm -a remote_port
--- a/usr/src/cmd/dladm/dladm.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/cmd/dladm/dladm.c Wed Oct 07 14:39:04 2009 -0700
@@ -891,7 +891,7 @@
{ "PERM", 5, LINKPROP_PERM, print_linkprop_cb},
{ "VALUE", 15, LINKPROP_VALUE, print_linkprop_cb},
{ "DEFAULT", 15, LINKPROP_DEFAULT, print_linkprop_cb},
-{ "POSSIBLE", 21, LINKPROP_POSSIBLE, print_linkprop_cb},
+{ "POSSIBLE", 20, LINKPROP_POSSIBLE, print_linkprop_cb},
{ NULL, 0, 0, NULL}}
;
@@ -6286,6 +6286,7 @@
statep->ls_status = DLADM_STATUS_OK;
+ buf[0] = '\0';
ptr = buf;
lim = buf + DLADM_STRSIZE;
for (i = 0; i < valcnt; i++) {
@@ -6493,6 +6494,9 @@
if (state.ls_parsable)
ofmtflags |= OFMT_PARSABLE;
+ else
+ ofmtflags |= OFMT_WRAP;
+
oferr = ofmt_open(fields_str, linkprop_fields, ofmtflags, 0, &ofmt);
dladm_ofmt_check(oferr, state.ls_parsable, ofmt);
state.ls_ofmt = ofmt;
--- a/usr/src/cmd/flowadm/flowadm.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/cmd/flowadm/flowadm.c Wed Oct 07 14:39:04 2009 -0700
@@ -163,7 +163,8 @@
char flow_link[MAXLINKNAMELEN];
char flow_ipaddr[INET6_ADDRSTRLEN+4];
char flow_proto[PROTO_MAXSTR_LEN];
- char flow_port[PORT_MAXSTR_LEN];
+ char flow_lport[PORT_MAXSTR_LEN];
+ char flow_rport[PORT_MAXSTR_LEN];
char flow_dsfield[DSFIELD_MAXSTR_LEN];
} flow_fields_buf_t;
@@ -173,12 +174,14 @@
offsetof(flow_fields_buf_t, flow_name), print_default_cb},
{ "LINK", 12,
offsetof(flow_fields_buf_t, flow_link), print_default_cb},
-{ "IPADDR", 31,
+{ "IPADDR", 25,
offsetof(flow_fields_buf_t, flow_ipaddr), print_default_cb},
{ "PROTO", 7,
offsetof(flow_fields_buf_t, flow_proto), print_default_cb},
-{ "PORT", 8,
- offsetof(flow_fields_buf_t, flow_port), print_default_cb},
+{ "LPORT", 8,
+ offsetof(flow_fields_buf_t, flow_lport), print_default_cb},
+{ "RPORT", 8,
+ offsetof(flow_fields_buf_t, flow_rport), print_default_cb},
{ "DSFLD", 10,
offsetof(flow_fields_buf_t, flow_dsfield), print_default_cb},
NULL_OFMT}
@@ -344,7 +347,8 @@
static dladm_handle_t handle = NULL;
static const char *attr_table[] =
- {"local_ip", "remote_ip", "transport", "local_port", "dsfield"};
+ {"local_ip", "remote_ip", "transport", "local_port", "remote_port",
+ "dsfield"};
#define NATTR (sizeof (attr_table)/sizeof (char *))
@@ -909,8 +913,14 @@
sizeof (fbuf->flow_ipaddr));
(void) dladm_flow_attr_proto2str(attr, fbuf->flow_proto,
sizeof (fbuf->flow_proto));
- (void) dladm_flow_attr_port2str(attr, fbuf->flow_port,
- sizeof (fbuf->flow_port));
+ if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_LOCAL) != 0) {
+ (void) dladm_flow_attr_port2str(attr, fbuf->flow_lport,
+ sizeof (fbuf->flow_lport));
+ }
+ if ((attr->fa_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE) != 0) {
+ (void) dladm_flow_attr_port2str(attr, fbuf->flow_rport,
+ sizeof (fbuf->flow_rport));
+ }
(void) dladm_flow_attr_dsfield2str(attr, fbuf->flow_dsfield,
sizeof (fbuf->flow_dsfield));
--- a/usr/src/cmd/flowadm/flowadm.xcl Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/cmd/flowadm/flowadm.xcl Wed Oct 07 14:39:04 2009 -0700
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
@@ -92,6 +92,7 @@
msgid "property"
msgid "psSi:l:o:"
msgid "remote_ip"
+msgid "remote_port"
msgid "remove-flow"
msgid "reset"
msgid "reset-flowprop"
--- a/usr/src/lib/libdladm/common/flowattr.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/flowattr.c Wed Oct 07 14:39:04 2009 -0700
@@ -50,15 +50,17 @@
static fad_checkf_t do_check_remote_ip;
static fad_checkf_t do_check_protocol;
static fad_checkf_t do_check_local_port;
+static fad_checkf_t do_check_remote_port;
static dladm_status_t do_check_port(char *, boolean_t, flow_desc_t *);
static fattr_desc_t attr_table[] = {
- { "local_ip", do_check_local_ip },
- { "remote_ip", do_check_remote_ip },
- { "transport", do_check_protocol },
- { "local_port", do_check_local_port },
- { "dsfield", do_check_dsfield },
+ { "local_ip", do_check_local_ip },
+ { "remote_ip", do_check_remote_ip },
+ { "transport", do_check_protocol },
+ { "local_port", do_check_local_port },
+ { "remote_port", do_check_remote_port },
+ { "dsfield", do_check_dsfield },
};
#define DLADM_MAX_FLOWATTRS (sizeof (attr_table) / sizeof (fattr_desc_t))
@@ -162,19 +164,26 @@
}
dladm_status_t
+do_check_remote_port(char *attr_val, flow_desc_t *fdesc)
+{
+ return (do_check_port(attr_val, B_FALSE, fdesc));
+}
+
+dladm_status_t
do_check_port(char *attr_val, boolean_t local, flow_desc_t *fdesc)
{
char *endp = NULL;
long val;
+ val = strtol(attr_val, &endp, 10);
+ if (val < 1 || val > MAX_PORT || *endp != '\0')
+ return (DLADM_STATUS_INVALID_PORT);
if (local) {
fdesc->fd_mask |= FLOW_ULP_PORT_LOCAL;
- val = strtol(attr_val, &endp, 10);
- if (val < 1 || val > MAX_PORT)
- return (DLADM_STATUS_INVALID_PORT);
fdesc->fd_local_port = htons((uint16_t)val);
} else {
- return (DLADM_STATUS_BADVAL);
+ fdesc->fd_mask |= FLOW_ULP_PORT_REMOTE;
+ fdesc->fd_remote_port = htons((uint16_t)val);
}
return (DLADM_STATUS_OK);
@@ -391,6 +400,9 @@
if (fdesc.fd_mask & FLOW_ULP_PORT_LOCAL) {
(void) snprintf(buf, buf_len, "%d",
ntohs(fdesc.fd_local_port));
+ } else if (fdesc.fd_mask & FLOW_ULP_PORT_REMOTE) {
+ (void) snprintf(buf, buf_len, "%d",
+ ntohs(fdesc.fd_remote_port));
} else {
buf[0] = '\0';
}
--- a/usr/src/lib/libdladm/common/flowprop.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/flowprop.c Wed Oct 07 14:39:04 2009 -0700
@@ -493,7 +493,7 @@
*/
static dladm_status_t
i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist,
- const char *name, void *val)
+ const char *name, void *arg)
{
dladm_status_t status;
dladm_arg_info_t *aip = NULL;
@@ -543,8 +543,8 @@
/* Extract kernel structure */
if (rpp->rp_extract != NULL) {
- status = rpp->rp_extract(vdp, val,
- aip->ai_count);
+ status = rpp->rp_extract(vdp,
+ aip->ai_count, arg);
} else {
status = DLADM_STATUS_BADARG;
}
--- a/usr/src/lib/libdladm/common/libdladm.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdladm.c Wed Oct 07 14:39:04 2009 -0700
@@ -30,6 +30,8 @@
#include <strings.h>
#include <dirent.h>
#include <stdlib.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/dld.h>
@@ -80,6 +82,18 @@
};
#define MEDIATYPECOUNT (sizeof (media_type_table) / sizeof (media_type_t))
+typedef struct {
+ uint32_t lp_type;
+ char *lp_name;
+} link_protect_t;
+
+static link_protect_t link_protect_types[] = {
+ { MPT_MACNOSPOOF, "mac-nospoof" },
+ { MPT_IPNOSPOOF, "ip-nospoof" },
+ { MPT_RESTRICTED, "restricted" }
+};
+#define LPTYPES (sizeof (link_protect_types) / sizeof (link_protect_t))
+
dladm_status_t
dladm_open(dladm_handle_t *handle)
{
@@ -836,6 +850,82 @@
return (buf);
}
+/*
+ * Convert protect string to a value.
+ */
+dladm_status_t
+dladm_str2protect(char *token, uint32_t *ptype)
+{
+ link_protect_t *lp;
+ int i;
+
+ for (i = 0; i < LPTYPES; i++) {
+ lp = &link_protect_types[i];
+ if (strcmp(token, lp->lp_name) == 0) {
+ *ptype = lp->lp_type;
+ return (DLADM_STATUS_OK);
+ }
+ }
+ return (DLADM_STATUS_BADVAL);
+}
+
+/*
+ * Convert protect value to a string.
+ */
+const char *
+dladm_protect2str(uint32_t ptype, char *buf)
+{
+ const char *s = "--";
+ link_protect_t *lp;
+ int i;
+
+ for (i = 0; i < LPTYPES; i++) {
+ lp = &link_protect_types[i];
+ if (lp->lp_type == ptype) {
+ s = lp->lp_name;
+ break;
+ }
+ }
+ (void) snprintf(buf, DLADM_STRSIZE, "%s", dgettext(TEXT_DOMAIN, s));
+ return (buf);
+}
+
+/*
+ * Convert an IPv4 address to/from a string.
+ */
+const char *
+dladm_ipv4addr2str(void *addr, char *buf)
+{
+ if (inet_ntop(AF_INET, addr, buf, INET_ADDRSTRLEN) == NULL)
+ buf[0] = 0;
+
+ return (buf);
+}
+
+dladm_status_t
+dladm_str2ipv4addr(char *token, void *addr)
+{
+ return (inet_pton(AF_INET, token, addr) == 1 ?
+ DLADM_STATUS_OK : DLADM_STATUS_INVALID_IP);
+}
+
+/*
+ * Find the set bits in a mask.
+ * This is used for expanding a bitmask into individual sub-masks
+ * which can be used for further processing.
+ */
+void
+dladm_find_setbits32(uint32_t mask, uint32_t *list, uint32_t *cnt)
+{
+ int i, c = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (((1 << i) & mask) != 0)
+ list[c++] = 1 << i;
+ }
+ *cnt = c;
+}
+
void
dladm_free_args(dladm_arg_list_t *list)
{
--- a/usr/src/lib/libdladm/common/libdladm.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdladm.h Wed Oct 07 14:39:04 2009 -0700
@@ -27,6 +27,7 @@
#define _LIBDLADM_H
#include <sys/dls_mgmt.h>
+#include <sys/dld.h>
#include <sys/dlpi.h>
/*
@@ -224,6 +225,12 @@
extern boolean_t dladm_str2interval(char *, uint32_t *);
extern dladm_status_t dladm_str2bw(char *, uint64_t *);
extern const char *dladm_bw2str(int64_t, char *);
+extern dladm_status_t dladm_str2pri(char *, mac_priority_level_t *);
+extern const char *dladm_pri2str(mac_priority_level_t, char *);
+extern dladm_status_t dladm_str2protect(char *, uint32_t *);
+extern const char *dladm_protect2str(uint32_t, char *);
+extern dladm_status_t dladm_str2ipv4addr(char *, void *);
+extern const char *dladm_ipv4addr2str(void *, char *);
extern dladm_status_t dladm_parse_flow_props(char *, dladm_arg_list_t **,
boolean_t);
--- a/usr/src/lib/libdladm/common/libdladm_impl.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdladm_impl.h Wed Oct 07 14:39:04 2009 -0700
@@ -59,9 +59,7 @@
FILE *), void *, boolean_t);
extern dladm_status_t i_dladm_get_state(dladm_handle_t, datalink_id_t,
link_state_t *);
-
-extern const char *dladm_pri2str(mac_priority_level_t, char *);
-extern dladm_status_t dladm_str2pri(char *, mac_priority_level_t *);
+extern void dladm_find_setbits32(uint32_t, uint32_t *, uint32_t *);
extern dladm_status_t dladm_parse_args(char *, dladm_arg_list_t **,
boolean_t);
extern void dladm_free_args(dladm_arg_list_t *);
@@ -140,10 +138,10 @@
* rp_extract extracts the kernel structure from the val_desc_t created
* by the pd_check function.
*/
-typedef dladm_status_t rp_extractf_t(val_desc_t *propval, void *arg,
- uint_t cnt);
+typedef dladm_status_t rp_extractf_t(val_desc_t *, uint_t, void *);
extern rp_extractf_t do_extract_maxbw, do_extract_priority,
- do_extract_cpus;
+ do_extract_cpus, do_extract_protection,
+ do_extract_allowedips;
typedef struct resource_prop_s {
/*
--- a/usr/src/lib/libdladm/common/libdlflow.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/libdlflow.c Wed Oct 07 14:39:04 2009 -0700
@@ -72,6 +72,7 @@
static const char *REMOTE_IP_ADDR = "remote_ip";
static const char *TRANSPORT = "transport";
static const char *LOCAL_PORT = "local_port";
+static const char *REMOTE_PORT = "remote_port";
static const char *DSFIELD = "dsfield";
/*
@@ -131,7 +132,6 @@
{
char *token;
char *value, *name = NULL;
- char *endp = NULL;
char *lasts = NULL;
dladm_status_t status = DLADM_STATUS_FLOW_DB_PARSE_ERR;
@@ -156,7 +156,7 @@
if (strcmp(name, "linkid") == 0) {
if ((attr->fi_linkid =
- (uint32_t)strtol(value, &endp, 10)) ==
+ (uint32_t)strtol(value, NULL, 10)) ==
DATALINK_INVALID_LINKID)
goto done;
@@ -164,7 +164,7 @@
attr->fi_resource_props.mrp_mask |=
MRP_MAXBW;
attr->fi_resource_props.mrp_maxbw =
- (uint64_t)strtol(value, &endp, 0);
+ (uint64_t)strtol(value, NULL, 0);
} else if (strcmp(name, PRIORITY) == 0) {
attr->fi_resource_props.mrp_mask |= MRP_PRIORITY;
@@ -194,14 +194,20 @@
} else if (strcmp(name, TRANSPORT) == 0) {
attr->fi_flow_desc.fd_mask |= FLOW_IP_PROTOCOL;
attr->fi_flow_desc.fd_protocol =
- (uint8_t)strtol(value, &endp, 0);
+ (uint8_t)strtol(value, NULL, 0);
} else if (strcmp(name, LOCAL_PORT) == 0) {
attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_LOCAL;
attr->fi_flow_desc.fd_local_port =
- (uint16_t)strtol(value, &endp, 10);
+ (uint16_t)strtol(value, NULL, 10);
attr->fi_flow_desc.fd_local_port =
htons(attr->fi_flow_desc.fd_local_port);
+ } else if (strcmp(name, REMOTE_PORT) == 0) {
+ attr->fi_flow_desc.fd_mask |= FLOW_ULP_PORT_REMOTE;
+ attr->fi_flow_desc.fd_remote_port =
+ (uint16_t)strtol(value, NULL, 10);
+ attr->fi_flow_desc.fd_remote_port =
+ htons(attr->fi_flow_desc.fd_remote_port);
}
free(name);
name = NULL;
@@ -303,6 +309,10 @@
FPRINTF_ERR(fprintf(fp, "%s=%d\t", LOCAL_PORT,
ntohs(attr->fi_flow_desc.fd_local_port)));
+ if (attr->fi_flow_desc.fd_mask & FLOW_ULP_PORT_REMOTE)
+ FPRINTF_ERR(fprintf(fp, "%s=%d\t", REMOTE_PORT,
+ ntohs(attr->fi_flow_desc.fd_remote_port)));
+
FPRINTF_ERR(fprintf(fp, "\n"));
return (0);
--- a/usr/src/lib/libdladm/common/linkprop.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/linkprop.c Wed Oct 07 14:39:04 2009 -0700
@@ -51,7 +51,6 @@
#include <sys/param.h>
#include <sys/debug.h>
#include <sys/dld.h>
-#include <sys/mac_flow.h>
#include <inttypes.h>
#include <sys/ethernet.h>
#include <inet/iptun.h>
@@ -139,17 +138,21 @@
i_dladm_cpus_get, i_dladm_priority_get,
i_dladm_tagmode_get, i_dladm_range_get,
get_stp_prop, get_bridge_forward,
- get_bridge_pvid;
+ get_bridge_pvid,
+ /* the above need to be renamed to "do_get_xxx" */
+ do_get_protection;
static pd_setf_t do_set_zone, do_set_rate_prop,
do_set_powermode_prop, do_set_radio_prop,
i_dladm_set_public_prop, do_set_res, do_set_cpus,
- set_stp_prop, set_bridge_forward, set_bridge_pvid;
+ set_stp_prop, set_bridge_forward, set_bridge_pvid,
+ do_set_protection;
static pd_checkf_t do_check_zone, do_check_autopush, do_check_rate,
do_check_hoplimit, do_check_encaplim,
i_dladm_uint32_check, do_check_maxbw, do_check_cpus,
- do_check_priority, check_stp_prop, check_bridge_pvid;
+ do_check_priority, check_stp_prop, check_bridge_pvid,
+ do_check_allowedips, do_check_prop;
static dladm_status_t i_dladm_speed_get(dladm_handle_t, prop_desc_t *,
datalink_id_t, char **, uint_t *, uint_t, uint_t *);
@@ -341,8 +344,9 @@
{ MAC_PROP_LDECAY, sizeof (uint32_t), "learn_decay"},
+ { MAC_PROP_PROTECT, sizeof (mac_resource_props_t), "protection"},
+
{ MAC_PROP_PRIVATE, 0, "driver-private"}
-
};
typedef struct bridge_public_prop_s {
@@ -389,6 +393,12 @@
{ "vlanonly", LINK_TAGMODE_VLANONLY }
};
+static val_desc_t link_protect_vals[] = {
+ { "mac-nospoof", MPT_MACNOSPOOF },
+ { "ip-nospoof", MPT_IPNOSPOOF },
+ { "restricted", MPT_RESTRICTED }
+};
+
static val_desc_t dladm_wlan_radio_vals[] = {
{ "on", DLADM_WLAN_RADIO_ON },
{ "off", DLADM_WLAN_RADIO_OFF }
@@ -622,6 +632,16 @@
set_stp_prop, NULL, get_stp_prop, check_stp_prop, PD_AFTER_PERM,
DATALINK_CLASS_PHYS|DATALINK_CLASS_AGGR|
DATALINK_CLASS_ETHERSTUB|DATALINK_CLASS_SIMNET, DL_ETHER },
+
+ { "protection", { "--", RESET_VAL },
+ link_protect_vals, VALCNT(link_protect_vals),
+ do_set_protection, NULL, do_get_protection, do_check_prop, 0,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
+
+ { "allowed-ips", { "--", 0 },
+ NULL, 0, do_set_protection, NULL,
+ do_get_protection, do_check_allowedips, 0,
+ DATALINK_CLASS_ALL, DATALINK_ANY_MEDIATYPE },
};
#define DLADM_MAX_PROPS (sizeof (prop_table) / sizeof (prop_desc_t))
@@ -629,7 +649,9 @@
static resource_prop_t rsrc_prop_table[] = {
{"maxbw", do_extract_maxbw},
{"priority", do_extract_priority},
- {"cpus", do_extract_cpus}
+ {"cpus", do_extract_cpus},
+ {"protection", do_extract_protection},
+ {"allowed-ips", do_extract_allowedips}
};
#define DLADM_MAX_RSRC_PROP (sizeof (rsrc_prop_table) / \
sizeof (resource_prop_t))
@@ -667,29 +689,26 @@
#define AP_ANCHOR "[anchor]"
#define AP_DELIMITER '.'
+/* ARGSUSED */
static dladm_status_t
-do_check_prop(prop_desc_t *pdp, char **prop_val, uint_t val_cnt,
- val_desc_t *vdp)
+do_check_prop(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
+ char **prop_val, uint_t val_cnt, val_desc_t *vdp, datalink_media_t media)
{
int i, j;
- dladm_status_t status = DLADM_STATUS_OK;
for (j = 0; j < val_cnt; j++) {
for (i = 0; i < pdp->pd_noptval; i++) {
- if (strcasecmp(*prop_val,
+ if (strcasecmp(prop_val[j],
pdp->pd_optval[i].vd_name) == 0) {
break;
}
}
- if (i == pdp->pd_noptval) {
- status = DLADM_STATUS_BADVAL;
- goto done;
- }
- (void) memcpy(vdp + j, &pdp->pd_optval[i], sizeof (val_desc_t));
+ if (i == pdp->pd_noptval)
+ return (DLADM_STATUS_BADVAL);
+
+ (void) memcpy(&vdp[j], &pdp->pd_optval[i], sizeof (val_desc_t));
}
-
-done:
- return (status);
+ return (DLADM_STATUS_OK);
}
static dladm_status_t
@@ -727,7 +746,8 @@
status = pdp->pd_check(handle, pdp, linkid, prop_val,
val_cnt, vdp, media);
} else if (pdp->pd_optval != NULL) {
- status = do_check_prop(pdp, prop_val, val_cnt, vdp);
+ status = do_check_prop(handle, pdp, linkid, prop_val,
+ val_cnt, vdp, media);
} else {
status = DLADM_STATUS_BADARG;
}
@@ -1523,9 +1543,9 @@
/* ARGSUSED */
dladm_status_t
-do_extract_maxbw(val_desc_t *vdp, void *arg, uint_t cnt)
+do_extract_maxbw(val_desc_t *vdp, uint_t cnt, void *arg)
{
- mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
+ mac_resource_props_t *mrp = arg;
bcopy((char *)vdp->vd_val, &mrp->mrp_maxbw, sizeof (uint64_t));
mrp->mrp_mask |= MRP_MAXBW;
@@ -1728,9 +1748,9 @@
/* ARGSUSED */
dladm_status_t
-do_extract_cpus(val_desc_t *vdp, void *arg, uint_t cnt)
+do_extract_cpus(val_desc_t *vdp, uint_t cnt, void *arg)
{
- mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
+ mac_resource_props_t *mrp = arg;
mac_resource_props_t *vmrp = (mac_resource_props_t *)vdp->vd_val;
int i;
@@ -1804,9 +1824,9 @@
/* ARGSUSED */
dladm_status_t
-do_extract_priority(val_desc_t *vdp, void *arg, uint_t cnt)
+do_extract_priority(val_desc_t *vdp, uint_t cnt, void *arg)
{
- mac_resource_props_t *mrp = (mac_resource_props_t *)arg;
+ mac_resource_props_t *mrp = arg;
bcopy((char *)vdp->vd_val, &mrp->mrp_priority,
sizeof (mac_priority_level_t));
@@ -1817,6 +1837,157 @@
/* ARGSUSED */
static dladm_status_t
+do_set_protection(dladm_handle_t handle, prop_desc_t *pdp,
+ datalink_id_t linkid, val_desc_t *vdp, uint_t val_cnt,
+ uint_t flags, datalink_media_t media)
+{
+ mac_resource_props_t mrp;
+ dladm_status_t status = DLADM_STATUS_OK;
+ dld_ioc_macprop_t *dip;
+
+ bzero(&mrp, sizeof (mac_resource_props_t));
+ dip = i_dladm_buf_alloc_by_name(0, linkid, "protection",
+ flags, &status);
+
+ if (dip == NULL)
+ return (status);
+
+ if (strcmp(pdp->pd_name, "protection") == 0) {
+ status = do_extract_protection(vdp, val_cnt, &mrp);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+
+ } else if (strcmp(pdp->pd_name, "allowed-ips") == 0) {
+ status = do_extract_allowedips(vdp, val_cnt, &mrp);
+ if (status != DLADM_STATUS_OK)
+ goto done;
+ } else {
+ status = DLADM_STATUS_BADARG;
+ goto done;
+ }
+
+ (void) memcpy(dip->pr_val, &mrp, dip->pr_valsize);
+ status = i_dladm_macprop(handle, dip, B_TRUE);
+
+done:
+ free(dip);
+ return (status);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_get_protection(dladm_handle_t handle, prop_desc_t *pdp,
+ datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
+ datalink_media_t media, uint_t flags, uint_t *perm_flags)
+{
+ dld_ioc_macprop_t *dip;
+ mac_resource_props_t mrp;
+ mac_protect_t *p;
+ dladm_status_t status;
+ int i;
+
+ dip = i_dladm_get_public_prop(handle, linkid, "protection", flags,
+ &status, perm_flags);
+ if (dip == NULL)
+ return (status);
+
+ bcopy(dip->pr_val, &mrp, sizeof (mac_resource_props_t));
+ free(dip);
+
+ p = &mrp.mrp_protect;
+ if ((mrp.mrp_mask & MRP_PROTECT) != 0 &&
+ strcmp(pdp->pd_name, "protection") == 0) {
+ uint32_t cnt = 0, setbits[32];
+
+ dladm_find_setbits32(p->mp_types, setbits, &cnt);
+ if (cnt > *val_cnt)
+ return (DLADM_STATUS_BADVALCNT);
+
+ for (i = 0; i < cnt; i++)
+ (void) dladm_protect2str(setbits[i], prop_val[i]);
+
+ *val_cnt = cnt;
+ return (DLADM_STATUS_OK);
+ }
+
+ if (p->mp_ipaddrcnt > 0 &&
+ strcmp(pdp->pd_name, "allowed-ips") == 0) {
+ if (p->mp_ipaddrcnt > *val_cnt)
+ return (DLADM_STATUS_BADVALCNT);
+
+ for (i = 0; i < p->mp_ipaddrcnt; i++) {
+ (void) dladm_ipv4addr2str(&p->mp_ipaddrs[i],
+ prop_val[i]);
+ }
+ *val_cnt = p->mp_ipaddrcnt;
+ return (DLADM_STATUS_OK);
+ }
+
+ *val_cnt = 0;
+ return (DLADM_STATUS_OK);
+}
+
+dladm_status_t
+do_extract_protection(val_desc_t *vdp, uint_t cnt, void *arg)
+{
+ mac_resource_props_t *mrp = arg;
+ uint32_t types = 0;
+ int i;
+
+ for (i = 0; i < cnt; i++)
+ types |= (uint32_t)vdp[i].vd_val;
+
+ mrp->mrp_protect.mp_types = types;
+ mrp->mrp_mask |= MRP_PROTECT;
+ return (DLADM_STATUS_OK);
+}
+
+dladm_status_t
+do_extract_allowedips(val_desc_t *vdp, uint_t cnt, void *arg)
+{
+ mac_resource_props_t *mrp = arg;
+ mac_protect_t *p = &mrp->mrp_protect;
+ int i;
+
+ if (vdp->vd_val == 0) {
+ cnt = (uint_t)-1;
+ } else {
+ for (i = 0; i < cnt; i++)
+ p->mp_ipaddrs[i] = (ipaddr_t)vdp[i].vd_val;
+ }
+ p->mp_ipaddrcnt = cnt;
+ mrp->mrp_mask |= MRP_PROTECT;
+ return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
+do_check_allowedips(dladm_handle_t handle, prop_desc_t *pdp,
+ datalink_id_t linkid, char **prop_val, uint_t val_cnt,
+ val_desc_t *vdp, datalink_media_t media)
+{
+ dladm_status_t status;
+ ipaddr_t addr;
+ int i;
+
+ if (val_cnt > MPT_MAXIPADDR)
+ return (DLADM_STATUS_BADVALCNT);
+
+ for (i = 0; i < val_cnt; i++) {
+ status = dladm_str2ipv4addr(prop_val[i], &addr);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+
+ if (addr == 0)
+ return (DLADM_STATUS_BADVAL);
+
+ vdp[i].vd_val = (uintptr_t)addr;
+ }
+ return (DLADM_STATUS_OK);
+}
+
+/* ARGSUSED */
+static dladm_status_t
do_get_autopush(dladm_handle_t handle, prop_desc_t *pdp, datalink_id_t linkid,
char **prop_val, uint_t *val_cnt, datalink_media_t media,
uint_t flags, uint_t *perm_flags)
@@ -3438,7 +3609,7 @@
*/
static dladm_status_t
i_dladm_link_proplist_extract_one(dladm_handle_t handle,
- dladm_arg_list_t *proplist, const char *name, void *val)
+ dladm_arg_list_t *proplist, const char *name, void *arg)
{
dladm_status_t status;
dladm_arg_info_t *aip = NULL;
@@ -3488,8 +3659,8 @@
/* Extract kernel structure */
if (rpp->rp_extract != NULL) {
- status = rpp->rp_extract(vdp, val,
- aip->ai_count);
+ status = rpp->rp_extract(vdp,
+ aip->ai_count, arg);
} else {
status = DLADM_STATUS_BADARG;
}
@@ -3511,20 +3682,15 @@
dladm_link_proplist_extract(dladm_handle_t handle, dladm_arg_list_t *proplist,
mac_resource_props_t *mrp)
{
- dladm_status_t status = DLADM_STATUS_OK;
-
- status = i_dladm_link_proplist_extract_one(handle, proplist, "maxbw",
- mrp);
- if (status != DLADM_STATUS_OK)
- return (status);
- status = i_dladm_link_proplist_extract_one(handle, proplist, "priority",
- mrp);
- if (status != DLADM_STATUS_OK)
- return (status);
- status = i_dladm_link_proplist_extract_one(handle, proplist, "cpus",
- mrp);
- if (status != DLADM_STATUS_OK)
- return (status);
+ dladm_status_t status;
+ int i;
+
+ for (i = 0; i < DLADM_MAX_RSRC_PROP; i++) {
+ status = i_dladm_link_proplist_extract_one(handle,
+ proplist, rsrc_prop_table[i].rp_name, mrp);
+ if (status != DLADM_STATUS_OK)
+ return (status);
+ }
return (status);
}
--- a/usr/src/lib/libdladm/common/mapfile-vers Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libdladm/common/mapfile-vers Wed Oct 07 14:39:04 2009 -0700
@@ -157,6 +157,10 @@
dladm_walk_hwgrp;
dladm_pri2str;
dladm_str2pri;
+ dladm_protect2str;
+ dladm_str2protect;
+ dladm_ipv4addr2str;
+ dladm_str2ipv4addr;
dladm_start_usagelog;
dladm_stop_usagelog;
dladm_walk_usage_res;
--- a/usr/src/lib/libinetutil/common/ofmt.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libinetutil/common/ofmt.c Wed Oct 07 14:39:04 2009 -0700
@@ -43,6 +43,7 @@
char *s_buf;
const char **s_fields; /* array of pointers to the fields in s_buf */
uint_t s_nfields; /* the number of fields in s_buf */
+ uint_t s_currfield; /* the current field being processed */
} split_t;
static void splitfree(split_t *);
static split_t *split_str(const char *, uint_t);
@@ -62,6 +63,7 @@
struct winsize os_winsize;
int os_nrow;
boolean_t os_parsable;
+ boolean_t os_wrap;
int os_nbad;
char **os_badfields;
} ofmt_state_t;
@@ -74,6 +76,12 @@
*/
#define OFMT_VAL_UNDEF "--"
#define OFMT_VAL_UNKNOWN "?"
+
+/*
+ * The maximum number of rows supported by the OFMT_WRAP option.
+ */
+#define OFMT_MAX_ROWS 128
+
static void ofmt_print_header(ofmt_state_t *);
static void ofmt_print_field(ofmt_state_t *, ofmt_field_t *, const char *,
boolean_t);
@@ -177,7 +185,8 @@
ofmt_state_t *os;
int nfields = 0;
ofmt_status_t err = OFMT_SUCCESS;
- boolean_t parsable = (flags & OFMT_PARSABLE);
+ boolean_t parsable = ((flags & OFMT_PARSABLE) != 0);
+ boolean_t wrap = ((flags & OFMT_WRAP) != 0);
*ofmt = NULL;
if (parsable) {
@@ -190,6 +199,8 @@
return (OFMT_EPARSENONE);
if (strcmp(str, "all") == 0)
return (OFMT_EPARSEALL);
+ if (wrap)
+ return (OFMT_EPARSEWRAP);
}
if (template == NULL)
return (OFMT_ENOTEMPLATE);
@@ -216,6 +227,8 @@
*ofmt = os;
os->os_fields = (ofmt_field_t *)&os[1];
os->os_parsable = parsable;
+ os->os_wrap = wrap;
+
of = os->os_fields;
of_index = 0;
/*
@@ -318,8 +331,6 @@
(void) putchar(':');
return;
} else {
- if (value[0] == '\0')
- value = OFMT_VAL_UNDEF;
if (os->os_lastfield) {
(void) printf("%s", value);
os->os_overflow = 0;
@@ -343,7 +354,42 @@
}
/*
- * print one row of output values for the selected columns.
+ * Print enough to fit the field width.
+ */
+static void
+ofmt_fit_width(split_t **spp, uint_t width, char *value, uint_t bufsize)
+{
+ split_t *sp = *spp;
+ char *ptr = value, *lim = ptr + bufsize;
+ int i, nextlen;
+
+ if (sp == NULL) {
+ sp = split_str(value, OFMT_MAX_ROWS);
+ if (sp == NULL)
+ return;
+
+ *spp = sp;
+ }
+ for (i = sp->s_currfield; i < sp->s_nfields; i++) {
+ ptr += snprintf(ptr, lim - ptr, "%s,", sp->s_fields[i]);
+ if (i + 1 == sp->s_nfields) {
+ nextlen = 0;
+ if (ptr > value)
+ ptr[-1] = '\0';
+ } else {
+ nextlen = strlen(sp->s_fields[i + 1]);
+ }
+
+ if (strlen(value) + nextlen > width || ptr >= lim) {
+ i++;
+ break;
+ }
+ }
+ sp->s_currfield = i;
+}
+
+/*
+ * Print one or more rows of output values for the selected columns.
*/
void
ofmt_print(ofmt_handle_t ofmt, void *arg)
@@ -352,8 +398,15 @@
int i;
char value[1024];
ofmt_field_t *of;
- boolean_t escsep;
+ boolean_t escsep, more_rows;
ofmt_arg_t ofarg;
+ split_t **sp = NULL;
+
+ if (os->os_wrap) {
+ sp = calloc(sizeof (split_t *), os->os_nfields);
+ if (sp == NULL)
+ return;
+ }
if ((os->os_nrow++ % os->os_winsize.ws_row) == 0 && !os->os_parsable) {
ofmt_print_header(os);
@@ -362,18 +415,57 @@
of = os->os_fields;
escsep = (os->os_nfields > 1);
+ more_rows = B_FALSE;
for (i = 0; i < os->os_nfields; i++) {
os->os_lastfield = (i + 1 == os->os_nfields);
value[0] = '\0';
ofarg.ofmt_id = of[i].of_id;
ofarg.ofmt_cbarg = arg;
- if ((*of[i].of_cb)(&ofarg, value, sizeof (value)))
- ofmt_print_field(os, &of[i], value, escsep);
- else
+
+ if ((*of[i].of_cb)(&ofarg, value, sizeof (value))) {
+ if (os->os_wrap) {
+ /*
+ * 'value' will be split at comma boundaries
+ * and stored into sp[i].
+ */
+ ofmt_fit_width(&sp[i], of[i].of_width, value,
+ sizeof (value));
+ if (sp[i] != NULL &&
+ sp[i]->s_currfield < sp[i]->s_nfields)
+ more_rows = B_TRUE;
+ }
+ ofmt_print_field(os, &of[i],
+ (*value == '\0' && !os->os_parsable) ?
+ OFMT_VAL_UNDEF : value, escsep);
+ } else {
ofmt_print_field(os, &of[i], OFMT_VAL_UNKNOWN, escsep);
+ }
}
(void) putchar('\n');
+
+ while (more_rows) {
+ more_rows = B_FALSE;
+ for (i = 0; i < os->os_nfields; i++) {
+ os->os_lastfield = (i + 1 == os->os_nfields);
+ value[0] = '\0';
+
+ ofmt_fit_width(&sp[i], of[i].of_width,
+ value, sizeof (value));
+ if (sp[i] != NULL &&
+ sp[i]->s_currfield < sp[i]->s_nfields)
+ more_rows = B_TRUE;
+
+ ofmt_print_field(os, &of[i], value, escsep);
+ }
+ (void) putchar('\n');
+ }
(void) fflush(stdout);
+
+ if (sp != NULL) {
+ for (i = 0; i < os->os_nfields; i++)
+ splitfree(sp[i]);
+ free(sp);
+ }
}
/*
@@ -463,6 +555,9 @@
case OFMT_EPARSENONE:
s = "output fields must be specified in parsable mode";
break;
+ case OFMT_EPARSEWRAP:
+ s = "parsable mode is incompatible with wrap mode";
+ break;
case OFMT_ENOTEMPLATE:
s = "no template provided for fields";
break;
--- a/usr/src/lib/libinetutil/common/ofmt.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/lib/libinetutil/common/ofmt.h Wed Oct 07 14:39:04 2009 -0700
@@ -134,6 +134,7 @@
OFMT_ENOFIELDS, /* no valid output fields */
OFMT_EPARSEALL, /* 'all' invalid in parsable mode */
OFMT_EPARSENONE, /* output fields missing in parsable mode */
+ OFMT_EPARSEWRAP, /* parsable mode incompatible with wrap mode */
OFMT_ENOTEMPLATE /* no template provided for fields */
} ofmt_status_t;
@@ -169,6 +170,7 @@
uint_t, ofmt_handle_t *);
#define OFMT_PARSABLE 0x00000001 /* machine parsable mode */
+#define OFMT_WRAP 0x00000002 /* wrap output if field width is exceeded */
/*
* ofmt_close() must be called to free resources associated
--- a/usr/src/uts/common/Makefile.files Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/Makefile.files Wed Oct 07 14:39:04 2009 -0700
@@ -613,7 +613,7 @@
MAC_OBJS += mac.o mac_bcast.o mac_client.o mac_datapath_setup.o mac_flow.o \
mac_hio.o mac_mod.o mac_ndd.o mac_provider.o mac_sched.o \
- mac_soft_ring.o mac_stat.o mac_util.o
+ mac_protect.o mac_soft_ring.o mac_stat.o mac_util.o
MAC_6TO4_OBJS += mac_6to4.o
--- a/usr/src/uts/common/io/dld/dld_proto.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/dld/dld_proto.c Wed Oct 07 14:39:04 2009 -0700
@@ -913,6 +913,17 @@
goto failed2;
}
+ /*
+ * If mac-nospoof is enabled and the link is owned by a
+ * non-global zone, changing the mac address is not allowed.
+ */
+ if (dsp->ds_dlp->dl_zid != GLOBAL_ZONEID &&
+ mac_protect_enabled(dsp->ds_mch, MPT_MACNOSPOOF)) {
+ dls_active_clear(dsp, B_FALSE);
+ err = EACCES;
+ goto failed2;
+ }
+
err = mac_unicast_primary_set(dsp->ds_mh,
mp->b_rptr + dlp->dl_addr_offset);
if (err != 0) {
--- a/usr/src/uts/common/io/dld/dld_str.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/dld/dld_str.c Wed Oct 07 14:39:04 2009 -0700
@@ -934,7 +934,7 @@
size += MBLKL(bp);
}
- if (dls_link_header_info(dsp->ds_dlp, mp, &mhi) != 0)
+ if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
goto discard;
mac_sdu_get(dsp->ds_mh, NULL, &max_sdu);
@@ -1450,7 +1450,7 @@
/*
* Get the packet header information.
*/
- if (dls_link_header_info(dsp->ds_dlp, mp, &mhi) != 0)
+ if (mac_vlan_header_info(dsp->ds_mh, mp, &mhi) != 0)
return (NULL);
/*
--- a/usr/src/uts/common/io/dls/dls_link.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/dls/dls_link.c Wed Oct 07 14:39:04 2009 -0700
@@ -100,17 +100,17 @@
* - Strip the padding and skip over the header. Note that because some
* DLS consumers only check the db_ref count of the first mblk, we
* pullup the message into a single mblk. Because the original message
- * is freed as the result of message pulling up, dls_link_header_info()
+ * is freed as the result of message pulling up, mac_vlan_header_info()
* is called again to update the mhi_saddr and mhi_daddr pointers in the
- * mhip. Further, the dls_link_header_info() function ensures that the
+ * mhip. Further, the mac_vlan_header_info() function ensures that the
* size of the pulled message is greater than the MAC header size,
* therefore we can directly advance b_rptr to point at the payload.
*
* We choose to use a macro for performance reasons.
*/
-#define DLS_PREPARE_PKT(dlp, mp, mhip, err) { \
+#define DLS_PREPARE_PKT(mh, mp, mhip, err) { \
mblk_t *nextp = (mp)->b_next; \
- if (((err) = dls_link_header_info((dlp), (mp), (mhip))) == 0) { \
+ if (((err) = mac_vlan_header_info((mh), (mp), (mhip))) == 0) { \
DLS_STRIP_PADDING((mhip)->mhi_pktsize, (mp)); \
if (MBLKL((mp)) < (mhip)->mhi_hdrsize) { \
mblk_t *newmp; \
@@ -120,7 +120,7 @@
(mp)->b_next = NULL; \
freemsg((mp)); \
(mp) = newmp; \
- VERIFY(dls_link_header_info((dlp), \
+ VERIFY(mac_vlan_header_info((mh), \
(mp), (mhip)) == 0); \
(mp)->b_next = nextp; \
(mp)->b_rptr += (mhip)->mhi_hdrsize; \
@@ -160,7 +160,7 @@
uint16_t cvid, cpri;
int err;
- DLS_PREPARE_PKT(dlp, mp, &cmhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &cmhi, err);
if (err != 0)
break;
@@ -361,7 +361,7 @@
*/
accepted = B_FALSE;
- DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &mhi, err);
if (err != 0) {
atomic_add_32(&(dlp->dl_unknowns), 1);
nextp = mp->b_next;
@@ -510,7 +510,7 @@
void *ds_rx_arg;
int err;
- DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &mhi, err);
if (err != 0)
goto drop;
@@ -555,7 +555,7 @@
dls_head_t *dhp;
mod_hash_key_t key;
- DLS_PREPARE_PKT(dlp, mp, &mhi, err);
+ DLS_PREPARE_PKT(dlp->dl_mh, mp, &mhi, err);
if (err != 0)
goto drop;
@@ -1035,70 +1035,3 @@
mutex_exit(&dhp->dh_lock);
}
}
-
-int
-dls_link_header_info(dls_link_t *dlp, mblk_t *mp, mac_header_info_t *mhip)
-{
- boolean_t is_ethernet = (dlp->dl_mip->mi_media == DL_ETHER);
- uint16_t pvid = mac_get_pvid(dlp->dl_mh);
- int err = 0;
-
- /*
- * Packets should always be at least 16 bit aligned.
- */
- ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
-
- if ((err = mac_header_info(dlp->dl_mh, mp, mhip)) != 0)
- return (err);
-
- /*
- * If this is a VLAN-tagged Ethernet packet, then the SAP in the
- * mac_header_info_t as returned by mac_header_info() is
- * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
- */
- mhip->mhi_ispvid = B_FALSE;
- if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
- struct ether_vlan_header *evhp;
- uint16_t sap;
- mblk_t *tmp = NULL;
- size_t size;
-
- size = sizeof (struct ether_vlan_header);
- if (MBLKL(mp) < size) {
- /*
- * Pullup the message in order to get the MAC header
- * infomation. Note that this is a read-only function,
- * we keep the input packet intact.
- */
- if ((tmp = msgpullup(mp, size)) == NULL)
- return (EINVAL);
-
- mp = tmp;
- }
- evhp = (struct ether_vlan_header *)mp->b_rptr;
- sap = ntohs(evhp->ether_type);
- (void) mac_sap_verify(dlp->dl_mh, sap, &mhip->mhi_bindsap);
- mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
- mhip->mhi_tci = ntohs(evhp->ether_tci);
- mhip->mhi_istagged = B_TRUE;
- freemsg(tmp);
-
- /*
- * If this port has a non-zero PVID, then we have to lie to the
- * caller about the VLAN ID. It's always zero on receive for
- * that VLAN.
- */
- if (pvid != VLAN_ID_NONE && VLAN_ID(mhip->mhi_tci) == pvid) {
- mhip->mhi_tci &= ~(VLAN_ID_MASK << VLAN_ID_SHIFT);
- mhip->mhi_ispvid = B_TRUE;
- }
-
- if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
- return (EINVAL);
- } else {
- mhip->mhi_istagged = B_FALSE;
- mhip->mhi_tci = 0;
- }
-
- return (0);
-}
--- a/usr/src/uts/common/io/mac/mac.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac.c Wed Oct 07 14:39:04 2009 -0700
@@ -2729,6 +2729,7 @@
switch (macprop->mp_id) {
case MAC_PROP_MAXBW:
case MAC_PROP_PRIO:
+ case MAC_PROP_PROTECT:
case MAC_PROP_BIND_CPU: {
mac_resource_props_t mrp;
@@ -2808,6 +2809,7 @@
switch (macprop->mp_id) {
case MAC_PROP_MAXBW:
case MAC_PROP_PRIO:
+ case MAC_PROP_PROTECT:
case MAC_PROP_BIND_CPU: {
mac_resource_props_t mrp;
--- a/usr/src/uts/common/io/mac/mac_client.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac_client.c Wed Oct 07 14:39:04 2009 -0700
@@ -2791,7 +2791,7 @@
mac_tx(mac_client_handle_t mch, mblk_t *mp_chain, uintptr_t hint,
uint16_t flag, mblk_t **ret_mp)
{
- mac_tx_cookie_t cookie;
+ mac_tx_cookie_t cookie = NULL;
int error;
mac_tx_percpu_t *mytx;
mac_soft_ring_set_t *srs;
@@ -2812,6 +2812,15 @@
}
}
+ /*
+ * If mac protection is enabled, only the permissible packets will be
+ * returned by mac_protect_check().
+ */
+ if ((mcip->mci_flent->
+ fe_resource_props.mrp_mask & MRP_PROTECT) != 0 &&
+ (mp_chain = mac_protect_check(mch, mp_chain)) == NULL)
+ goto done;
+
if (mcip->mci_subflow_tab != NULL &&
mcip->mci_subflow_tab->ft_flow_count > 0 &&
mac_flow_lookup(mcip->mci_subflow_tab, mp_chain,
@@ -2836,11 +2845,10 @@
* of the mac datapath is required to remove this limitation.
*/
if (srs == NULL) {
- if (!(flag & MAC_TX_NO_HOLD))
- MAC_TX_RELE(mcip, mytx);
freemsgchain(mp_chain);
- return (NULL);
+ goto done;
}
+
srs_tx = &srs->srs_tx;
if (srs_tx->st_mode == SRS_TX_DEFAULT &&
(srs->srs_state & SRS_ENQUEUED) == 0 &&
@@ -3225,15 +3233,20 @@
if ((mrp->mrp_mask & MRP_MAXBW) || (mrp->mrp_mask & MRP_PRIORITY)) {
err = mac_resource_ctl_set(mch, mrp);
- if (err != 0) {
- i_mac_perim_exit(mip);
- return (err);
- }
+ if (err != 0)
+ goto done;
}
- if (mrp->mrp_mask & MRP_CPUS)
+ if (mrp->mrp_mask & MRP_CPUS) {
err = mac_cpu_set(mch, mrp);
-
+ if (err != 0)
+ goto done;
+ }
+
+ if (mrp->mrp_mask & MRP_PROTECT)
+ err = mac_protect_set(mch, mrp);
+
+done:
i_mac_perim_exit(mip);
return (err);
}
@@ -3558,6 +3571,62 @@
mhip));
}
+int
+mac_vlan_header_info(mac_handle_t mh, mblk_t *mp, mac_header_info_t *mhip)
+{
+ mac_impl_t *mip = (mac_impl_t *)mh;
+ boolean_t is_ethernet = (mip->mi_info.mi_media == DL_ETHER);
+ int err = 0;
+
+ /*
+ * Packets should always be at least 16 bit aligned.
+ */
+ ASSERT(IS_P2ALIGNED(mp->b_rptr, sizeof (uint16_t)));
+
+ if ((err = mac_header_info(mh, mp, mhip)) != 0)
+ return (err);
+
+ /*
+ * If this is a VLAN-tagged Ethernet packet, then the SAP in the
+ * mac_header_info_t as returned by mac_header_info() is
+ * ETHERTYPE_VLAN. We need to grab the ethertype from the VLAN header.
+ */
+ if (is_ethernet && (mhip->mhi_bindsap == ETHERTYPE_VLAN)) {
+ struct ether_vlan_header *evhp;
+ uint16_t sap;
+ mblk_t *tmp = NULL;
+ size_t size;
+
+ size = sizeof (struct ether_vlan_header);
+ if (MBLKL(mp) < size) {
+ /*
+ * Pullup the message in order to get the MAC header
+ * infomation. Note that this is a read-only function,
+ * we keep the input packet intact.
+ */
+ if ((tmp = msgpullup(mp, size)) == NULL)
+ return (EINVAL);
+
+ mp = tmp;
+ }
+ evhp = (struct ether_vlan_header *)mp->b_rptr;
+ sap = ntohs(evhp->ether_type);
+ (void) mac_sap_verify(mh, sap, &mhip->mhi_bindsap);
+ mhip->mhi_hdrsize = sizeof (struct ether_vlan_header);
+ mhip->mhi_tci = ntohs(evhp->ether_tci);
+ mhip->mhi_istagged = B_TRUE;
+ freemsg(tmp);
+
+ if (VLAN_CFI(mhip->mhi_tci) != ETHER_CFI)
+ return (EINVAL);
+ } else {
+ mhip->mhi_istagged = B_FALSE;
+ mhip->mhi_tci = 0;
+ }
+
+ return (0);
+}
+
mblk_t *
mac_header_cook(mac_handle_t mh, mblk_t *mp)
{
@@ -3648,6 +3717,9 @@
}
if (nmrp->mrp_mask & MRP_CPUS)
MAC_COPY_CPUS(nmrp, cmrp);
+
+ if (nmrp->mrp_mask & MRP_PROTECT)
+ mac_protect_update(nmrp, cmrp);
}
}
@@ -4149,6 +4221,12 @@
if (fanout < 0 || fanout > MCM_CPUS)
return (EINVAL);
}
+
+ if (mrp->mrp_mask & MRP_PROTECT) {
+ int err = mac_protect_validate(mrp);
+ if (err != 0)
+ return (err);
+ }
return (0);
}
--- a/usr/src/uts/common/io/mac/mac_flow.c Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/io/mac/mac_flow.c Wed Oct 07 14:39:04 2009 -0700
@@ -2354,7 +2354,10 @@
if ((fd1->fd_mask & FLOW_ULP_PORT_LOCAL) != 0)
return (fd1->fd_local_port == fd2->fd_local_port);
- return (fd1->fd_remote_port == fd2->fd_remote_port);
+ if ((fd1->fd_mask & FLOW_ULP_PORT_REMOTE) != 0)
+ return (fd1->fd_remote_port == fd2->fd_remote_port);
+
+ return (B_TRUE);
}
static flow_ops_t flow_l2_ops = {
@@ -2398,7 +2401,8 @@
{&flow_ip_ops, FLOW_IP_VERSION | FLOW_IP_REMOTE, 2},
{&flow_ip_ops, FLOW_IP_DSFIELD, 1},
{&flow_ip_proto_ops, FLOW_IP_PROTOCOL, 256},
- {&flow_transport_ops, FLOW_IP_PROTOCOL | FLOW_ULP_PORT_LOCAL, 1024}
+ {&flow_transport_ops, FLOW_IP_PROTOCOL | FLOW_ULP_PORT_LOCAL, 1024},
+ {&flow_transport_ops, FLOW_IP_PROTOCOL | FLOW_ULP_PORT_REMOTE, 1024}
};
#define FLOW_MAX_TAB_INFO \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/mac/mac_protect.c Wed Oct 07 14:39:04 2009 -0700
@@ -0,0 +1,340 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/strsun.h>
+#include <sys/sdt.h>
+#include <sys/mac.h>
+#include <sys/mac_impl.h>
+#include <sys/mac_client_impl.h>
+#include <sys/mac_client_priv.h>
+#include <sys/ethernet.h>
+#include <sys/vlan.h>
+#include <sys/dlpi.h>
+#include <inet/ip.h>
+#include <inet/ip6.h>
+#include <inet/arp.h>
+
+/*
+ * Check if ipaddr is in the 'allowed-ips' list.
+ */
+static boolean_t
+ipnospoof_check_ips(mac_protect_t *protect, ipaddr_t ipaddr)
+{
+ uint_t i;
+
+ /*
+ * unspecified addresses are harmless and are used by ARP,DHCP..etc.
+ */
+ if (ipaddr == INADDR_ANY)
+ return (B_TRUE);
+
+ for (i = 0; i < protect->mp_ipaddrcnt; i++) {
+ if (protect->mp_ipaddrs[i] == ipaddr)
+ return (B_TRUE);
+ }
+ return (B_FALSE);
+}
+
+/*
+ * Enforce ip-nospoof protection. Only IPv4 is supported for now.
+ */
+static int
+ipnospoof_check(mac_client_impl_t *mcip, mac_protect_t *protect,
+ mblk_t *mp, mac_header_info_t *mhip)
+{
+ uint32_t sap = mhip->mhi_bindsap;
+ uchar_t *start = mp->b_rptr + mhip->mhi_hdrsize;
+ int err = EINVAL;
+
+ /*
+ * This handles the case where the mac header is not in
+ * the same mblk as the IP header.
+ */
+ if (start == mp->b_wptr) {
+ mp = mp->b_cont;
+
+ /*
+ * IP header missing. Let the packet through.
+ */
+ if (mp == NULL)
+ return (0);
+
+ start = mp->b_rptr;
+ }
+
+ switch (sap) {
+ case ETHERTYPE_IP: {
+ ipha_t *ipha = (ipha_t *)start;
+
+ if (start + sizeof (ipha_t) > mp->b_wptr || !OK_32PTR(start))
+ goto fail;
+
+ if (!ipnospoof_check_ips(protect, ipha->ipha_src))
+ goto fail;
+
+ break;
+ }
+ case ETHERTYPE_ARP: {
+ arh_t *arh = (arh_t *)start;
+ uint32_t maclen, hlen, plen, arplen;
+ ipaddr_t spaddr;
+ uchar_t *shaddr;
+
+ if (start + sizeof (arh_t) > mp->b_wptr)
+ goto fail;
+
+ maclen = mcip->mci_mip->mi_info.mi_addr_length;
+ hlen = arh->arh_hlen;
+ plen = arh->arh_plen;
+ if ((hlen != 0 && hlen != maclen) ||
+ plen != sizeof (ipaddr_t))
+ goto fail;
+
+ arplen = sizeof (arh_t) + 2 * hlen + 2 * plen;
+ if (start + arplen > mp->b_wptr)
+ goto fail;
+
+ shaddr = start + sizeof (arh_t);
+ if (hlen != 0 &&
+ bcmp(mcip->mci_unicast->ma_addr, shaddr, maclen) != 0)
+ goto fail;
+
+ bcopy(shaddr + hlen, &spaddr, sizeof (spaddr));
+ if (!ipnospoof_check_ips(protect, spaddr))
+ goto fail;
+ break;
+ }
+ default:
+ break;
+ }
+ return (0);
+
+fail:
+ /* increment ipnospoof stat here */
+ return (err);
+}
+
+/*
+ * Enforce link protection on one packet.
+ */
+static int
+mac_protect_check_one(mac_client_impl_t *mcip, mblk_t *mp)
+{
+ mac_impl_t *mip = mcip->mci_mip;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
+ mac_protect_t *protect;
+ mac_header_info_t mhi;
+ uint32_t types;
+ int err;
+
+ ASSERT(mp->b_next == NULL);
+ ASSERT(mrp != NULL);
+
+ err = mac_vlan_header_info((mac_handle_t)mip, mp, &mhi);
+ if (err != 0) {
+ DTRACE_PROBE2(invalid__header, mac_client_impl_t *, mcip,
+ mblk_t *, mp);
+ return (err);
+ }
+
+ protect = &mrp->mrp_protect;
+ types = protect->mp_types;
+
+ if ((types & MPT_MACNOSPOOF) != 0) {
+ if (mhi.mhi_saddr != NULL &&
+ bcmp(mcip->mci_unicast->ma_addr, mhi.mhi_saddr,
+ mip->mi_info.mi_addr_length) != 0) {
+ DTRACE_PROBE2(mac__nospoof__fail,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (EINVAL);
+ }
+ }
+
+ if ((types & MPT_RESTRICTED) != 0) {
+ uint32_t vid = VLAN_ID(mhi.mhi_tci);
+ uint32_t sap = mhi.mhi_bindsap;
+
+ /*
+ * ETHERTYPE_VLAN packets are allowed through, provided that
+ * the vid is not spoofed.
+ */
+ if (vid != 0 && !mac_client_check_flow_vid(mcip, vid)) {
+ DTRACE_PROBE2(restricted__vid__invalid,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (EINVAL);
+ }
+
+ if (sap != ETHERTYPE_IP && sap != ETHERTYPE_IPV6 &&
+ sap != ETHERTYPE_ARP) {
+ DTRACE_PROBE2(restricted__fail,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (EINVAL);
+ }
+ }
+
+ if ((types & MPT_IPNOSPOOF) != 0) {
+ if ((err = ipnospoof_check(mcip, protect,
+ mp, &mhi)) != 0) {
+ DTRACE_PROBE2(ip__nospoof__fail,
+ mac_client_impl_t *, mcip, mblk_t *, mp);
+ return (err);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Enforce link protection on a packet chain.
+ * Packets that pass the checks are returned back to the caller.
+ */
+mblk_t *
+mac_protect_check(mac_client_handle_t mch, mblk_t *mp)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mblk_t *ret_mp = NULL, **tailp = &ret_mp, *next;
+
+ /*
+ * Skip checks if we are part of an aggr.
+ */
+ if ((mcip->mci_state_flags & MCIS_IS_AGGR_PORT) != 0)
+ return (mp);
+
+ for (; mp != NULL; mp = next) {
+ next = mp->b_next;
+ mp->b_next = NULL;
+
+ if (mac_protect_check_one(mcip, mp) == 0) {
+ *tailp = mp;
+ tailp = &mp->b_next;
+ } else {
+ freemsg(mp);
+ }
+ }
+ return (ret_mp);
+}
+
+/*
+ * Check if a particular protection type is enabled.
+ */
+boolean_t
+mac_protect_enabled(mac_client_handle_t mch, uint32_t type)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_resource_props_t *mrp = MCIP_RESOURCE_PROPS(mcip);
+
+ ASSERT(mrp != NULL);
+ return ((mrp->mrp_protect.mp_types & type) != 0);
+}
+
+/*
+ * Sanity-checks parameters given by userland.
+ */
+int
+mac_protect_validate(mac_resource_props_t *mrp)
+{
+ mac_protect_t *p = &mrp->mrp_protect;
+
+ /* check for invalid types */
+ if (p->mp_types != MPT_RESET && (p->mp_types & ~MPT_ALL) != 0)
+ return (EINVAL);
+
+ if (p->mp_ipaddrcnt != MPT_RESET) {
+ uint_t i, j;
+
+ if (p->mp_ipaddrcnt > MPT_MAXIPADDR)
+ return (EINVAL);
+
+ for (i = 0; i < p->mp_ipaddrcnt; i++) {
+ /*
+ * The unspecified address is implicitly allowed
+ * so there's no need to add it to the list.
+ */
+ if (p->mp_ipaddrs[i] == INADDR_ANY)
+ return (EINVAL);
+
+ for (j = 0; j < p->mp_ipaddrcnt; j++) {
+ /* found a duplicate */
+ if (i != j &&
+ p->mp_ipaddrs[i] == p->mp_ipaddrs[j])
+ return (EINVAL);
+ }
+ }
+ }
+ return (0);
+}
+
+/*
+ * Enable/disable link protection.
+ */
+int
+mac_protect_set(mac_client_handle_t mch, mac_resource_props_t *mrp)
+{
+ mac_client_impl_t *mcip = (mac_client_impl_t *)mch;
+ mac_impl_t *mip = mcip->mci_mip;
+ uint_t media = mip->mi_info.mi_nativemedia;
+ int err;
+
+ ASSERT(MAC_PERIM_HELD((mac_handle_t)mip));
+
+ /* tunnels are not supported */
+ if (media == DL_IPV4 || media == DL_IPV6 || media == DL_6TO4)
+ return (ENOTSUP);
+
+ if ((err = mac_protect_validate(mrp)) != 0)
+ return (err);
+
+ mac_update_resources(mrp, MCIP_RESOURCE_PROPS(mcip), B_FALSE);
+ return (0);
+}
+
+void
+mac_protect_update(mac_resource_props_t *new, mac_resource_props_t *curr)
+{
+ mac_protect_t *np = &new->mrp_protect;
+ mac_protect_t *cp = &curr->mrp_protect;
+ uint32_t types = np->mp_types;
+
+ if (types == MPT_RESET) {
+ cp->mp_types = 0;
+ curr->mrp_mask &= ~MRP_PROTECT;
+ } else {
+ if (types != 0) {
+ cp->mp_types = types;
+ curr->mrp_mask |= MRP_PROTECT;
+ }
+ }
+
+ if (np->mp_ipaddrcnt != 0) {
+ if (np->mp_ipaddrcnt < MPT_MAXIPADDR) {
+ bcopy(np->mp_ipaddrs, cp->mp_ipaddrs,
+ sizeof (cp->mp_ipaddrs));
+ cp->mp_ipaddrcnt = np->mp_ipaddrcnt;
+ } else if (np->mp_ipaddrcnt == MPT_RESET) {
+ bzero(cp->mp_ipaddrs, sizeof (cp->mp_ipaddrs));
+ cp->mp_ipaddrcnt = 0;
+ }
+ }
+}
--- a/usr/src/uts/common/sys/dls_impl.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/dls_impl.h Wed Oct 07 14:39:04 2009 -0700
@@ -84,8 +84,6 @@
extern int dls_link_rele_by_name(const char *);
extern void dls_link_add(dls_link_t *, uint32_t, dld_str_t *);
extern void dls_link_remove(dls_link_t *, dld_str_t *);
-extern int dls_link_header_info(dls_link_t *, mblk_t *,
- mac_header_info_t *);
extern int dls_link_getzid(const char *, zoneid_t *);
extern int dls_link_setzid(const char *, zoneid_t);
extern dev_info_t *dls_link_devinfo(dev_t);
--- a/usr/src/uts/common/sys/mac.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac.h Wed Oct 07 14:39:04 2009 -0700
@@ -211,6 +211,7 @@
MAC_PROP_PVID,
MAC_PROP_LLIMIT,
MAC_PROP_LDECAY,
+ MAC_PROP_PROTECT,
MAC_PROP_PRIVATE = -1
} mac_prop_id_t;
--- a/usr/src/uts/common/sys/mac_client_priv.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac_client_priv.h Wed Oct 07 14:39:04 2009 -0700
@@ -68,6 +68,7 @@
extern mblk_t *mac_header(mac_handle_t, const uint8_t *, uint32_t, mblk_t *,
size_t);
extern int mac_header_info(mac_handle_t, mblk_t *, mac_header_info_t *);
+extern int mac_vlan_header_info(mac_handle_t, mblk_t *, mac_header_info_t *);
extern mblk_t *mac_header_cook(mac_handle_t, mblk_t *);
extern mblk_t *mac_header_uncook(mac_handle_t, mblk_t *);
--- a/usr/src/uts/common/sys/mac_flow.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac_flow.h Wed Oct 07 14:39:04 2009 -0700
@@ -113,7 +113,7 @@
* in retargetting the interrupt assignment.
*/
int32_t mc_intr_cpu;
- mac_cpu_mode_t mc_fanout_mode; /* fanout mode */
+ mac_cpu_mode_t mc_fanout_mode; /* fanout mode */
} mac_cpus_t;
/* Priority values */
@@ -124,6 +124,21 @@
MPL_RESET
} mac_priority_level_t;
+/* Protection types */
+#define MPT_MACNOSPOOF 0x00000001
+#define MPT_IPNOSPOOF 0x00000002
+#define MPT_RESTRICTED 0x00000004
+#define MPT_ALL (MPT_MACNOSPOOF|MPT_IPNOSPOOF|MPT_RESTRICTED)
+#define MPT_RESET 0xffffffff
+#define MPT_MAXIPADDR 32
+
+typedef struct mac_protect_s {
+ uint32_t mp_types;
+ uint32_t mp_ipaddrcnt;
+ ipaddr_t mp_ipaddrs[MPT_MAXIPADDR];
+} mac_protect_t;
+
+
/* The default priority for links */
#define MPL_LINK_DEFAULT MPL_HIGH
@@ -134,6 +149,7 @@
#define MRP_CPUS 0x00000002 /* CPU/fanout set */
#define MRP_CPUS_USERSPEC 0x00000004 /* CPU/fanout from user */
#define MRP_PRIORITY 0x00000008 /* Priority set */
+#define MRP_PROTECT 0x00000010 /* Protection set */
#define MRP_THROTTLE MRP_MAXBW
@@ -157,6 +173,7 @@
uint64_t mrp_maxbw; /* bandwidth limit in bps */
mac_priority_level_t mrp_priority; /* relative flow priority */
mac_cpus_t mrp_cpus;
+ mac_protect_t mrp_protect;
} mac_resource_props_t;
#define mrp_ncpus mrp_cpus.mc_ncpus
--- a/usr/src/uts/common/sys/mac_impl.h Wed Oct 07 14:30:51 2009 -0700
+++ b/usr/src/uts/common/sys/mac_impl.h Wed Oct 07 14:39:04 2009 -0700
@@ -751,6 +751,12 @@
extern void mac_poll_state_change(mac_handle_t, boolean_t);
+extern mblk_t *mac_protect_check(mac_client_handle_t, mblk_t *);
+extern int mac_protect_set(mac_client_handle_t, mac_resource_props_t *);
+extern boolean_t mac_protect_enabled(mac_client_handle_t, uint32_t);
+extern int mac_protect_validate(mac_resource_props_t *);
+extern void mac_protect_update(mac_resource_props_t *, mac_resource_props_t *);
+
/* Global callbacks into the bridging module (when loaded) */
extern mac_bridge_tx_t mac_bridge_tx_cb;
extern mac_bridge_rx_t mac_bridge_rx_cb;