# HG changeset patch # User Eric Cheng # Date 1254951544 25200 # Node ID 0622a203d0396b265e5b9d35f551346874034c55 # Parent b95259752377c7607f0f1db8d72a2bc05207c81f 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 diff -r b95259752377 -r 0622a203d039 usr/src/cmd/dladm/dladm.c --- 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; diff -r b95259752377 -r 0622a203d039 usr/src/cmd/flowadm/flowadm.c --- 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)); diff -r b95259752377 -r 0622a203d039 usr/src/cmd/flowadm/flowadm.xcl --- 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" diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/flowattr.c --- 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'; } diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/flowprop.c --- 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; } diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/libdladm.c --- 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 #include #include +#include +#include #include #include #include @@ -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) { diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/libdladm.h --- 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 +#include #include /* @@ -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); diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/libdladm_impl.h --- 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 { /* diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/libdlflow.c --- 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); diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/linkprop.c --- 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 #include #include -#include #include #include #include @@ -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); } diff -r b95259752377 -r 0622a203d039 usr/src/lib/libdladm/common/mapfile-vers --- 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; diff -r b95259752377 -r 0622a203d039 usr/src/lib/libinetutil/common/ofmt.c --- 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; diff -r b95259752377 -r 0622a203d039 usr/src/lib/libinetutil/common/ofmt.h --- 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 diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/Makefile.files --- 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 diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/dld/dld_proto.c --- 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) { diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/dld/dld_str.c --- 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); /* diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/dls/dls_link.c --- 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); -} diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/mac/mac.c --- 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; diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/mac/mac_client.c --- 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); } diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/mac/mac_flow.c --- 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 \ diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/io/mac/mac_protect.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * 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; + } + } +} diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/sys/dls_impl.h --- 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); diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/sys/mac.h --- 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; diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/sys/mac_client_priv.h --- 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 *); diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/sys/mac_flow.h --- 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 diff -r b95259752377 -r 0622a203d039 usr/src/uts/common/sys/mac_impl.h --- 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;