lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Thu, 21 Nov 2013 16:55:36 +0200
From:	Anton Nayshtut <Anton.Nayshtut@...ocity.com>
To:	Jay Vosburgh <fubar@...ibm.com>,
	Veaceslav Falico <vfalico@...hat.com>,
	Andy Gospodarek <andy@...yhouse.net>,
	"David S. Miller" <davem@...emloft.net>,
	Cong Wang <xiyou.wangcong@...il.com>,
	Nicolas Schichan <nschichan@...ebox.fr>,
	Eric Dumazet <edumazet@...gle.com>
Cc:	linux-kernel@...r.kernel.org, netdev@...r.kernel.org,
	Anton Nayshtut <Anton.Nayshtut@...ocity.com>,
	Erez Kirshenbaum <Erez.Kirshenbaum@...ocity.com>,
	Boris Lapshin <Boris.Lapshin@...ocity.com>
Subject: [PATCH 2/4] bonding: L2DA mode intergated

L2DA bonding module integration, including module parameters, sysfs entries and
module calls.

Signed-off-by: Anton Nayshtut <Anton.Nayshtut@...ocity.com>
Signed-off-by: Erez Kirshenbaum <Erez.Kirshenbaum@...ocity.com>
Signed-off-by: Boris Lapshin <Boris.Lapshin@...ocity.com>
---
 drivers/net/bonding/bond_main.c    |  51 ++++++++-
 drivers/net/bonding/bond_options.c |  17 ++-
 drivers/net/bonding/bond_sysfs.c   | 223 ++++++++++++++++++++++++++++++++++++-
 drivers/net/bonding/bonding.h      |   5 +
 include/uapi/linux/if_bonding.h    |   1 +
 5 files changed, 290 insertions(+), 7 deletions(-)

diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 4dd5ee2..33733be 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -138,7 +138,7 @@ module_param(mode, charp, 0);
 MODULE_PARM_DESC(mode, "Mode of operation; 0 for balance-rr, "
 		       "1 for active-backup, 2 for balance-xor, "
 		       "3 for broadcast, 4 for 802.3ad, 5 for balance-tlb, "
-		       "6 for balance-alb");
+		       "6 for balance-alb, 7 for l2da");
 module_param(primary, charp, 0);
 MODULE_PARM_DESC(primary, "Primary network device to use");
 module_param(primary_reselect, charp, 0);
@@ -218,6 +218,7 @@ const struct bond_parm_tbl bond_mode_tbl[] = {
 {	"802.3ad",		BOND_MODE_8023AD},
 {	"balance-tlb",		BOND_MODE_TLB},
 {	"balance-alb",		BOND_MODE_ALB},
+{	"l2da",			BOND_MODE_L2DA },
 {	NULL,			-1},
 };
 
@@ -282,9 +283,10 @@ const char *bond_mode_name(int mode)
 		[BOND_MODE_8023AD] = "IEEE 802.3ad Dynamic link aggregation",
 		[BOND_MODE_TLB] = "transmit load balancing",
 		[BOND_MODE_ALB] = "adaptive load balancing",
+		[BOND_MODE_L2DA] = "l2 DA matrix",
 	};
 
-	if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_ALB)
+	if (mode < BOND_MODE_ROUNDROBIN || mode > BOND_MODE_L2DA)
 		return "unknown";
 
 	return names[mode];
@@ -1546,6 +1548,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 		bond_set_active_slave(new_slave);
 		bond_set_slave_inactive_flags(new_slave);
 		break;
+	case BOND_MODE_L2DA:
+		bond_set_slave_active_flags(new_slave);
+		bond_l2da_slave_init(bond, new_slave);
+		break;
 	default:
 		pr_debug("This slave is always active in trunk mode\n");
 
@@ -1760,7 +1766,8 @@ static int __bond_release_one(struct net_device *bond_dev,
 		write_unlock_bh(&bond->lock);
 		bond_alb_deinit_slave(bond, slave);
 		write_lock_bh(&bond->lock);
-	}
+	} else if (bond_is_l2da(bond))
+		bond_l2da_slave_deinit(bond, slave);
 
 	if (all) {
 		rcu_assign_pointer(bond->curr_active_slave, NULL);
@@ -2058,6 +2065,9 @@ static void bond_miimon_commit(struct bonding *bond)
 				bond_alb_handle_link_change(bond, slave,
 							    BOND_LINK_UP);
 
+			if (bond_is_l2da(bond))
+				bond_l2da_handle_link_change(bond, slave);
+
 			if (!bond->curr_active_slave ||
 			    (slave == bond->primary_slave))
 				goto do_failover;
@@ -2085,6 +2095,9 @@ static void bond_miimon_commit(struct bonding *bond)
 				bond_alb_handle_link_change(bond, slave,
 							    BOND_LINK_DOWN);
 
+			if (bond_is_l2da(bond))
+				bond_l2da_handle_link_change(bond, slave);
+
 			if (slave == bond->curr_active_slave)
 				goto do_failover;
 
@@ -3778,6 +3791,8 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
 	case BOND_MODE_ALB:
 	case BOND_MODE_TLB:
 		return bond_alb_xmit(skb, dev);
+	case BOND_MODE_L2DA:
+		return bond_l2da_xmit(skb, dev);
 	default:
 		/* Should never happen, mode already checked */
 		pr_err("%s: Error: Unknown bonding mode %d\n",
@@ -3969,6 +3984,9 @@ static void bond_uninit(struct net_device *bond_dev)
 	list_del(&bond->bond_list);
 
 	bond_debug_unregister(bond);
+
+	if (bond_is_l2da(bond))
+		bond_l2da_deinitialize(bond);
 }
 
 /*------------------------- Module initialization ---------------------------*/
@@ -4041,7 +4059,8 @@ static int bond_check_params(struct bond_params *params)
 	}
 
 	if (lacp_rate) {
-		if (bond_mode != BOND_MODE_8023AD) {
+		if (bond_mode != BOND_MODE_8023AD ||
+			bond_mode != BOND_MODE_L2DA) {
 			pr_info("lacp_rate param is irrelevant in mode %s\n",
 				bond_mode_name(bond_mode));
 		} else {
@@ -4128,6 +4147,19 @@ static int bond_check_params(struct bond_params *params)
 		all_slaves_active = 0;
 	}
 
+	if (bond_mode == BOND_MODE_L2DA) {
+		if (!all_slaves_active) {
+			pr_warning("Warning: all_slaves_active must be specified, otherwise bonding will not be able to route packets that is essential for l2da operation\n");
+			pr_warning("Forcing all_slaves_active to 1\n");
+			all_slaves_active = 1;
+		}
+		if (!miimon) {
+			pr_warning("Warning: miimon must be specified, otherwise bonding will not detect link failure and link speed which are essential for l2da operation\n");
+			pr_warning("Forcing miimon to 100msec\n");
+			miimon = 100;
+		}
+	}
+
 	if (resend_igmp < 0 || resend_igmp > 255) {
 		pr_warning("Warning: resend_igmp (%d) should be between "
 			   "0 and 255, resetting to %d\n",
@@ -4372,6 +4404,7 @@ static int bond_init(struct net_device *bond_dev)
 	struct bonding *bond = netdev_priv(bond_dev);
 	struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+	int ret;
 
 	pr_debug("Begin bond_init for %s\n", bond_dev->name);
 
@@ -4384,6 +4417,16 @@ static int bond_init(struct net_device *bond_dev)
 	spin_lock_init(&(bond_info->tx_hashtbl_lock));
 	spin_lock_init(&(bond_info->rx_hashtbl_lock));
 
+	if (bond_is_l2da(bond)) {
+		ret = bond_l2da_initialize(bond);
+		if (ret) {
+			pr_err("%s: %s mode cannot be initialized.\n",
+					bond->dev->name,
+					bond_mode_tbl[BOND_MODE_L2DA].modename);
+			return ret;
+		}
+	}
+
 	bond->wq = create_singlethread_workqueue(bond_dev->name);
 	if (!bond->wq)
 		return -ENOMEM;
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 9a5223c..b413665 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -45,12 +45,27 @@ int bond_option_mode_set(struct bonding *bond, int mode)
 		return -EPERM;
 	}
 
-	if (BOND_MODE_IS_LB(mode) && bond->params.arp_interval) {
+	if ((BOND_MODE_IS_LB(mode) || bond_is_l2da(bond)) &&
+	    bond->params.arp_interval) {
 		pr_err("%s: %s mode is incompatible with arp monitoring.\n",
 		       bond->dev->name, bond_mode_tbl[mode].modename);
 		return -EINVAL;
 	}
 
+	if (bond->params.mode == mode)
+		;
+	else if (mode == BOND_MODE_L2DA) {
+		int ret = bond_l2da_initialize(bond);
+		if (ret) {
+			pr_err("%s: %s mode cannot be initialized.\n",
+			       bond->dev->name,
+			       bond_mode_tbl[mode].modename);
+			return ret;
+		}
+	} else if (bond_is_l2da(bond))
+		bond_l2da_deinitialize(bond);
+
+
 	/* don't cache arp_validate between modes */
 	bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
 	bond->params.mode = mode;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 0ec2a7e..d4727d2 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -525,8 +525,9 @@ static ssize_t bonding_store_arp_interval(struct device *d,
 	}
 	if (bond->params.mode == BOND_MODE_ALB ||
 	    bond->params.mode == BOND_MODE_TLB ||
-	    bond->params.mode == BOND_MODE_8023AD) {
-		pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad. Only MII monitoring is supported on %s.\n",
+	    bond->params.mode == BOND_MODE_8023AD ||
+	    bond->params.mode == BOND_MODE_L2DA) {
+		pr_info("%s: ARP monitoring cannot be used with ALB/TLB/802.3ad/L2DA. Only MII monitoring is supported on %s.\n",
 			bond->dev->name, bond->dev->name);
 		ret = -EINVAL;
 		goto out;
@@ -1679,6 +1680,222 @@ static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR,
 		   bonding_show_packets_per_slave,
 		   bonding_store_packets_per_slave);
 
+static ssize_t bonding_show_l2da_default_slave(struct device *d,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct bonding *bond = to_bond(d);
+	char ifname[IFNAMSIZ + 1];
+	int ret;
+
+	read_lock(&bond->lock);
+	ret = bond_l2da_get_default_slave_name(bond, ifname, sizeof(ifname));
+	read_unlock(&bond->lock);
+
+	ifname[IFNAMSIZ] = 0;
+
+	return sprintf(buf, "%s\n", ifname);
+}
+
+static ssize_t bonding_store_l2da_default_slave(struct device *d,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+	struct slave *slave;
+	struct bonding *bond = to_bond(d);
+	char ifname[IFNAMSIZ];
+	struct list_head *iter;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	if (sscanf(buf, "%15s", ifname) != 1) {/* IFNAMSIZ */
+		pr_info("%s: no L2DA slave name specified\n",
+			netdev_name(bond->dev));
+		goto rtnl_out;
+	}
+
+	block_netpoll_tx();
+	read_lock(&bond->lock);
+
+	if (!bond_is_l2da(bond)) {
+		pr_info("%s: Unable to set default slave ; %s is in mode %d\n",
+			netdev_name(bond->dev), netdev_name(bond->dev),
+			bond->params.mode);
+		goto out;
+	}
+
+	bond_for_each_slave(bond, slave, iter) {
+		if (strncmp(netdev_name(slave->dev), ifname, IFNAMSIZ) == 0) {
+			if (slave->link == BOND_LINK_UP && IS_UP(slave->dev)) {
+				bond_l2da_set_default_slave(bond, slave);
+				ret = count;
+			} else
+				pr_warn("%s: cannot set %s as default slave\n",
+					netdev_name(bond->dev),
+					netdev_name(slave->dev));
+
+			break;
+		}
+	}
+
+	if (ret < 0)
+		pr_warn("%s: Unable to to set %.*s as default slave.\n",
+			netdev_name(bond->dev), (int)strlen(buf) - 1, buf);
+
+out:
+	read_unlock(&bond->lock);
+	unblock_netpoll_tx();
+rtnl_out:
+	rtnl_unlock();
+
+	return ret;
+}
+
+static DEVICE_ATTR(l2da_default_slave, S_IRUGO | S_IWUSR,
+		   bonding_show_l2da_default_slave,
+		   bonding_store_l2da_default_slave);
+
+struct bonding_show_l2da_table_clb_ctx {
+	char *buf;
+	int   res;
+};
+
+static int bonding_show_l2da_table_clb(const unsigned char *da,
+		struct slave *slave, void *_ctx)
+{
+	struct bonding_show_l2da_table_clb_ctx *ctx = _ctx;
+	if (ctx->res > (PAGE_SIZE - 18 - IFNAMSIZ)) {
+		/* not enough space for another da@...erface_name pair */
+		if ((PAGE_SIZE - ctx->res) > 9)
+			ctx->res = PAGE_SIZE - 9;
+		ctx->res += sprintf(ctx->buf + ctx->res, "++more++");
+		return 1;
+	}
+	ctx->res += sprintf(ctx->buf + ctx->res, "%pM@%s\n",
+		       da, netdev_name(slave->dev));
+	return 0;
+}
+
+static ssize_t bonding_show_l2da_table(struct device *d,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct bonding *bond = to_bond(d);
+	struct bonding_show_l2da_table_clb_ctx ctx = {
+		.buf = buf,
+	};
+
+	read_lock(&bond->lock);
+	bond_l2da_call_foreach(bond, bonding_show_l2da_table_clb, &ctx);
+	read_unlock(&bond->lock);
+	if (ctx.res)
+		buf[ctx.res-1] = '\n'; /* eat the leftover space */
+
+	return ctx.res;
+}
+
+static ssize_t bonding_store_l2da_table(struct device *d,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	struct slave *slave;
+	struct bonding *bond = to_bond(d);
+	int ret = -EINVAL;
+	char *delim;
+	unsigned char da[ETH_ALEN];
+	struct net_device *sdev = NULL;
+	struct list_head *iter;
+
+	if (!rtnl_trylock())
+		return restart_syscall();
+
+	/* Check command syntax and extract parameters */
+	if (buf[0] == '+') {
+		unsigned char ifname[IFNAMSIZ] = {0, };
+		/* delim will point to slave interface name if successful */
+		delim = strchr(buf, '@');
+		if (!delim) {
+			pr_err("%s: Invalid L2DA command string: %s\n",
+			    netdev_name(bond->dev), buf);
+			goto out;
+		}
+		/* Terminate string that points to device name and bump it
+		 * up one, so we can read the destination address there.
+		 */
+		*delim = '\0';
+		if (sscanf(delim + 1, "%15s", ifname) != 1) { /* IFNAMSIZ */
+			pr_err("%s: no L2DA slave name specified\n",
+			    netdev_name(bond->dev));
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/* Check valid ifname */
+		if (!dev_valid_name(ifname)) {
+			pr_err("%s: Invalid L2DA slave name: '%s'\n",
+			    netdev_name(bond->dev), ifname);
+			ret = -EINVAL;
+			goto out;
+
+		}
+
+		/* Get the pointer to that interface if it exists */
+		sdev = __dev_get_by_name(dev_net(bond->dev), ifname);
+		if (!sdev) {
+			pr_err("%s: No L2DA slave found: %s\n",
+			    netdev_name(bond->dev), ifname);
+			ret = -EINVAL;
+			goto out;
+		}
+	} else if (buf[0] != '-') {
+		pr_err("%s: Invalid L2DA command string: %s\n",
+		    netdev_name(bond->dev), buf);
+		goto out;
+	}
+
+	if (!mac_pton(buf + 1, da)) {
+		pr_err("%s: Invalid L2DA MAC address string: %s\n",
+		    netdev_name(bond->dev), buf + 1);
+		goto out;
+	}
+
+	if (!is_valid_ether_addr(da)) {
+		pr_err("%s: Invalid L2DA MAC address: %pM\n",
+		    netdev_name(bond->dev), da);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	block_netpoll_tx();
+	read_lock(&bond->lock);
+
+	if (!bond_is_l2da(bond))
+		pr_info("%s: Unable to set default slave ; %s is in mode %d\n",
+			netdev_name(bond->dev), netdev_name(bond->dev),
+			bond->params.mode);
+	else if (buf[0] == '-')
+		ret = bond_l2da_del_da(bond, da);
+	else {
+		bond_for_each_slave(bond, slave, iter) {
+			if (sdev == slave->dev) {
+				ret = bond_l2da_set_da_slave(bond, da, slave);
+				break;
+			}
+		}
+	}
+
+	read_unlock(&bond->lock);
+	unblock_netpoll_tx();
+out:
+	rtnl_unlock();
+	return ret ? ret : count;
+}
+
+static DEVICE_ATTR(l2da_table, S_IRUGO | S_IWUSR,
+		   bonding_show_l2da_table, bonding_store_l2da_table);
+
 static struct attribute *per_bond_attrs[] = {
 	&dev_attr_slaves.attr,
 	&dev_attr_mode.attr,
@@ -1711,6 +1928,8 @@ static struct attribute *per_bond_attrs[] = {
 	&dev_attr_min_links.attr,
 	&dev_attr_lp_interval.attr,
 	&dev_attr_packets_per_slave.attr,
+	&dev_attr_l2da_default_slave.attr,
+	&dev_attr_l2da_table.attr,
 	NULL,
 };
 
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 2069584..6c8c851 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -273,6 +273,11 @@ static inline bool bond_is_lb(const struct bonding *bond)
 	return BOND_MODE_IS_LB(bond->params.mode);
 }
 
+static inline bool bond_is_l2da(const struct bonding *bond)
+{
+	return bond->params.mode == BOND_MODE_L2DA;
+}
+
 static inline void bond_set_active_slave(struct slave *slave)
 {
 	slave->backup = 0;
diff --git a/include/uapi/linux/if_bonding.h b/include/uapi/linux/if_bonding.h
index 9635a62..b70ff3e 100644
--- a/include/uapi/linux/if_bonding.h
+++ b/include/uapi/linux/if_bonding.h
@@ -70,6 +70,7 @@
 #define BOND_MODE_8023AD        4
 #define BOND_MODE_TLB           5
 #define BOND_MODE_ALB		6 /* TLB + RLB (receive load balancing) */
+#define BOND_MODE_L2DA          7
 
 /* each slave's link has 4 states */
 #define BOND_LINK_UP    0           /* link is up and running */
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists