summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/io/vnic/vnic_dev.c
diff options
context:
space:
mode:
authorRobert Mustacchi <rm@joyent.com>2014-05-24 03:25:32 +0000
committerRobert Mustacchi <rm@joyent.com>2014-05-29 02:00:30 +0000
commite91da55ff5412995f14d956fc173096f48a0dbe7 (patch)
treec99a6090f55600f4d2fc49ace8cdcf35e3da7f45 /usr/src/uts/common/io/vnic/vnic_dev.c
parent88d1ad82179b795c150d676c55cbde142aa68441 (diff)
downloadillumos-joyent-20140529.tar.gz
OS-3053 VNICs should support a variable MTU20140529release-20140529
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Rob Gulewich <robert.gulewich@joyent.com>
Diffstat (limited to 'usr/src/uts/common/io/vnic/vnic_dev.c')
-rw-r--r--usr/src/uts/common/io/vnic/vnic_dev.c100
1 files changed, 85 insertions, 15 deletions
diff --git a/usr/src/uts/common/io/vnic/vnic_dev.c b/usr/src/uts/common/io/vnic/vnic_dev.c
index e7ad2608dc..64ce41a001 100644
--- a/usr/src/uts/common/io/vnic/vnic_dev.c
+++ b/usr/src/uts/common/io/vnic/vnic_dev.c
@@ -500,10 +500,21 @@ vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
mac_sdu_get(vnic->vn_lower_mh, &mac->m_min_sdu,
&mac->m_max_sdu);
+ err = mac_mtu_add(vnic->vn_lower_mh, &mac->m_max_sdu, B_FALSE);
+ if (err != 0) {
+ VERIFY(mac_margin_remove(vnic->vn_lower_mh,
+ vnic->vn_margin) == 0);
+ mac_free(mac);
+ if (diag != NULL)
+ *diag = VNIC_IOC_DIAG_MACMTU_INVALID;
+ goto bail;
+ }
+ vnic->vn_mtu = mac->m_max_sdu;
} else {
vnic->vn_margin = VLAN_TAGSZ;
mac->m_min_sdu = 1;
mac->m_max_sdu = ANCHOR_VNIC_MAX_MTU;
+ vnic->vn_mtu = ANCHOR_VNIC_MAX_MTU;
}
mac->m_margin = vnic->vn_margin;
@@ -511,8 +522,12 @@ vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
err = mac_register(mac, &vnic->vn_mh);
mac_free(mac);
if (err != 0) {
- VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
- vnic->vn_margin) == 0);
+ if (!is_anchor) {
+ VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
+ vnic->vn_mtu) == 0);
+ VERIFY(mac_margin_remove(vnic->vn_lower_mh,
+ vnic->vn_margin) == 0);
+ }
goto bail;
}
@@ -527,6 +542,10 @@ vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
}
err = mac_client_set_resources(vnic->vn_mch, mrp);
if (err != 0) {
+ VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
+ vnic->vn_mtu) == 0);
+ VERIFY(mac_margin_remove(vnic->vn_lower_mh,
+ vnic->vn_margin) == 0);
(void) mac_unregister(vnic->vn_mh);
goto bail;
}
@@ -537,6 +556,12 @@ vnic_dev_create(datalink_id_t vnic_id, datalink_id_t linkid,
if (err != 0) {
VERIFY(is_anchor || mac_margin_remove(vnic->vn_lower_mh,
vnic->vn_margin) == 0);
+ if (!is_anchor) {
+ VERIFY(mac_mtu_remove(vnic->vn_lower_mh,
+ vnic->vn_mtu) == 0);
+ VERIFY(mac_margin_remove(vnic->vn_lower_mh,
+ vnic->vn_margin) == 0);
+ }
(void) mac_unregister(vnic->vn_mh);
goto bail;
}
@@ -655,6 +680,7 @@ vnic_dev_delete(datalink_id_t vnic_id, uint32_t flags, cred_t *credp)
vnic->vn_slot_id);
}
(void) mac_margin_remove(vnic->vn_lower_mh, vnic->vn_margin);
+ (void) mac_mtu_remove(vnic->vn_lower_mh, vnic->vn_mtu);
(void) mac_notify_remove(vnic->vn_mnh, B_TRUE);
(void) mac_unicast_remove(vnic->vn_mch, vnic->vn_muh);
mac_client_close(vnic->vn_mch, MAC_CLOSE_FLAGS_IS_VNIC);
@@ -1004,20 +1030,35 @@ vnic_m_setprop(void *m_driver, const char *pr_name, mac_prop_id_t pr_num,
uint32_t mtu;
/* allow setting MTU only on an etherstub */
- if (vn->vn_link_id != DATALINK_INVALID_LINKID) {
- err = ENOTSUP;
- break;
- }
if (pr_valsize < sizeof (mtu)) {
err = EINVAL;
break;
}
bcopy(pr_val, &mtu, sizeof (mtu));
- if (mtu < ANCHOR_VNIC_MIN_MTU || mtu > ANCHOR_VNIC_MAX_MTU) {
- err = EINVAL;
- break;
+
+ if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
+ if (mtu < ANCHOR_VNIC_MIN_MTU ||
+ mtu > ANCHOR_VNIC_MAX_MTU) {
+ err = EINVAL;
+ break;
+ }
+ } else {
+ err = mac_mtu_add(vn->vn_lower_mh, &mtu, B_FALSE);
+ /*
+ * If it's not supported to set a value here, translate
+ * that to EINVAL, so user land gets a better idea of
+ * what went wrong. This realistically means that they
+ * violated the output of prop info.
+ */
+ if (err == ENOTSUP)
+ err = EINVAL;
+ if (err != 0)
+ break;
+ VERIFY(mac_mtu_remove(vn->vn_lower_mh,
+ vn->vn_mtu) == 0);
}
+ vn->vn_mtu = mtu;
err = mac_maxsdu_update(vn->vn_mh, mtu);
break;
}
@@ -1078,14 +1119,43 @@ static void vnic_m_propinfo(void *m_driver, const char *pr_name,
{
vnic_t *vn = m_driver;
- /* MTU setting allowed only on an etherstub */
- if (vn->vn_link_id != DATALINK_INVALID_LINKID)
- return;
-
switch (pr_num) {
case MAC_PROP_MTU:
- mac_prop_info_set_range_uint32(prh,
- ANCHOR_VNIC_MIN_MTU, ANCHOR_VNIC_MAX_MTU);
+ if (vn->vn_link_id == DATALINK_INVALID_LINKID) {
+ mac_prop_info_set_range_uint32(prh,
+ ANCHOR_VNIC_MIN_MTU, ANCHOR_VNIC_MAX_MTU);
+ } else {
+ uint32_t max;
+ mac_perim_handle_t mph;
+ mac_propval_range_t range;
+
+ /*
+ * The valid range for a VNIC's MTU is the minimum that
+ * the device supports and the current value of the
+ * device. A VNIC cannot increase the current MTU of the
+ * device. Therefore we need to get the range from the
+ * propinfo endpoint and current mtu from the
+ * traditional property endpoint.
+ */
+ mac_perim_enter_by_mh(vn->vn_lower_mh, &mph);
+ if (mac_get_prop(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
+ &max, sizeof (uint32_t)) != 0) {
+ mac_perim_exit(mph);
+ return;
+ }
+
+ range.mpr_count = 1;
+ if (mac_prop_info(vn->vn_lower_mh, MAC_PROP_MTU, "mtu",
+ NULL, 0, &range, NULL) != 0) {
+ mac_perim_exit(mph);
+ return;
+ }
+
+ mac_prop_info_set_default_uint32(prh, max);
+ mac_prop_info_set_range_uint32(prh,
+ range.mpr_range_uint32[0].mpur_min, max);
+ mac_perim_exit(mph);
+ }
break;
}
}