* [PATCH net-next v5 2/2] bonding: Simplify the xmit function for modes that use xmit_hash
From: Mahesh Bandewar @ 2014-09-30 6:27 UTC (permalink / raw)
To: Jay Vosburgh, Veaceslav Falico, Andy Gospodarek, David Miller
Cc: netdev, Mahesh Bandewar, Eric Dumazet, Maciej Zenczykowski
Earlier change to use usable slave array for TLB mode had an additional
performance advantage. So extending the same logic to all other modes
that use xmit-hash for slave selection (viz 802.3AD, and XOR modes).
Also consolidating this with the earlier TLB change.
The main idea is to build the usable slaves array in the control path
and use that array for slave selection during xmit operation.
Measured performance in a setup with a bond of 4x1G NICs with 200
instances of netperf for the modes involved (3ad, xor, tlb)
cmd: netperf -t TCP_RR -H <TargetHost> -l 60 -s 5
Mode TPS-Before TPS-After
802.3ad : 468,694 493,101
TLB (lb=0): 392,583 392,965
XOR : 475,696 484,517
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
---
v1:
(a) If bond_update_slave_arr() fails to allocate memory, it will overwrite
the slave that need to be removed.
(b) Freeing of array will assign NULL (to handle bond->down to bond->up
transition gracefully.
(c) Change from pr_debug() to pr_err() if bond_update_slave_arr() returns
failure.
(d) XOR: bond_update_slave_arr() will consider mii-mon, arp-mon cases and
will populate the array even if these parameters are not used.
(e) 3AD: Should handle the ad_agg_selection_logic correctly.
v2:
(a) Removed rcu_read_{un}lock() calls from array manipulation code.
(b) Slave link-events now refresh array for all these modes.
(c) Moved free-array call from bond_close() to bond_uninit().
v3:
(a) Fixed null pointer dereference.
(b) Removed bond->lock lockdep dependency.
v4:
(a) Made to changes to comply with Nikolay's locking changes
(b) Added a work-queue to refresh slave-array when RTNL is not held
(c) Array refresh happens ONLY with RTNL now.
(d) alloc changed from GFP_ATOMIC to GFP_KERNEL
v5:
(a) Consolidated all delayed slave-array updates at one place in
3ad_state_machine_handler()
drivers/net/bonding/bond_3ad.c | 140 ++++++++++++------------------
drivers/net/bonding/bond_alb.c | 51 ++---------
drivers/net/bonding/bond_alb.h | 8 --
drivers/net/bonding/bond_main.c | 185 +++++++++++++++++++++++++++++++++++++---
drivers/net/bonding/bonding.h | 10 +++
5 files changed, 242 insertions(+), 152 deletions(-)
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 7e9e522fd476..2110215f3528 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -102,17 +102,20 @@ static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
/* ================= main 802.3ad protocol functions ================== */
static int ad_lacpdu_send(struct port *port);
static int ad_marker_send(struct port *port, struct bond_marker *marker);
-static void ad_mux_machine(struct port *port);
+static void ad_mux_machine(struct port *port, bool *update_slave_arr);
static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
static void ad_tx_machine(struct port *port);
static void ad_periodic_machine(struct port *port);
-static void ad_port_selection_logic(struct port *port);
-static void ad_agg_selection_logic(struct aggregator *aggregator);
+static void ad_port_selection_logic(struct port *port, bool *update_slave_arr);
+static void ad_agg_selection_logic(struct aggregator *aggregator,
+ bool *update_slave_arr);
static void ad_clear_agg(struct aggregator *aggregator);
static void ad_initialize_agg(struct aggregator *aggregator);
static void ad_initialize_port(struct port *port, int lacp_fast);
-static void ad_enable_collecting_distributing(struct port *port);
-static void ad_disable_collecting_distributing(struct port *port);
+static void ad_enable_collecting_distributing(struct port *port,
+ bool *update_slave_arr);
+static void ad_disable_collecting_distributing(struct port *port,
+ bool *update_slave_arr);
static void ad_marker_info_received(struct bond_marker *marker_info,
struct port *port);
static void ad_marker_response_received(struct bond_marker *marker,
@@ -796,8 +799,9 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker)
/**
* ad_mux_machine - handle a port's mux state machine
* @port: the port we're looking at
+ * @update_slave_arr: Does slave array need update?
*/
-static void ad_mux_machine(struct port *port)
+static void ad_mux_machine(struct port *port, bool *update_slave_arr)
{
mux_states_t last_state;
@@ -901,7 +905,8 @@ static void ad_mux_machine(struct port *port)
switch (port->sm_mux_state) {
case AD_MUX_DETACHED:
port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
- ad_disable_collecting_distributing(port);
+ ad_disable_collecting_distributing(port,
+ update_slave_arr);
port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
port->ntt = true;
@@ -913,13 +918,15 @@ static void ad_mux_machine(struct port *port)
port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION;
port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
- ad_disable_collecting_distributing(port);
+ ad_disable_collecting_distributing(port,
+ update_slave_arr);
port->ntt = true;
break;
case AD_MUX_COLLECTING_DISTRIBUTING:
port->actor_oper_port_state |= AD_STATE_COLLECTING;
port->actor_oper_port_state |= AD_STATE_DISTRIBUTING;
- ad_enable_collecting_distributing(port);
+ ad_enable_collecting_distributing(port,
+ update_slave_arr);
port->ntt = true;
break;
default:
@@ -1187,12 +1194,13 @@ static void ad_periodic_machine(struct port *port)
/**
* ad_port_selection_logic - select aggregation groups
* @port: the port we're looking at
+ * @update_slave_arr: Does slave array need update?
*
* Select aggregation groups, and assign each port for it's aggregetor. The
* selection logic is called in the inititalization (after all the handshkes),
* and after every lacpdu receive (if selected is off).
*/
-static void ad_port_selection_logic(struct port *port)
+static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
{
struct aggregator *aggregator, *free_aggregator = NULL, *temp_aggregator;
struct port *last_port = NULL, *curr_port;
@@ -1347,7 +1355,7 @@ static void ad_port_selection_logic(struct port *port)
__agg_ports_are_ready(port->aggregator));
aggregator = __get_first_agg(port);
- ad_agg_selection_logic(aggregator);
+ ad_agg_selection_logic(aggregator, update_slave_arr);
}
/* Decide if "agg" is a better choice for the new active aggregator that
@@ -1435,6 +1443,7 @@ static int agg_device_up(const struct aggregator *agg)
/**
* ad_agg_selection_logic - select an aggregation group for a team
* @aggregator: the aggregator we're looking at
+ * @update_slave_arr: Does slave array need update?
*
* It is assumed that only one aggregator may be selected for a team.
*
@@ -1457,7 +1466,8 @@ static int agg_device_up(const struct aggregator *agg)
* __get_active_agg() won't work correctly. This function should be better
* called with the bond itself, and retrieve the first agg from it.
*/
-static void ad_agg_selection_logic(struct aggregator *agg)
+static void ad_agg_selection_logic(struct aggregator *agg,
+ bool *update_slave_arr)
{
struct aggregator *best, *active, *origin;
struct bonding *bond = agg->slave->bond;
@@ -1550,6 +1560,8 @@ static void ad_agg_selection_logic(struct aggregator *agg)
__disable_port(port);
}
}
+ /* Slave array needs update. */
+ *update_slave_arr = true;
}
/* if the selected aggregator is of join individuals
@@ -1678,24 +1690,30 @@ static void ad_initialize_port(struct port *port, int lacp_fast)
/**
* ad_enable_collecting_distributing - enable a port's transmit/receive
* @port: the port we're looking at
+ * @update_slave_arr: Does slave array need update?
*
* Enable @port if it's in an active aggregator
*/
-static void ad_enable_collecting_distributing(struct port *port)
+static void ad_enable_collecting_distributing(struct port *port,
+ bool *update_slave_arr)
{
if (port->aggregator->is_active) {
pr_debug("Enabling port %d(LAG %d)\n",
port->actor_port_number,
port->aggregator->aggregator_identifier);
__enable_port(port);
+ /* Slave array needs update */
+ *update_slave_arr = true;
}
}
/**
* ad_disable_collecting_distributing - disable a port's transmit/receive
* @port: the port we're looking at
+ * @update_slave_arr: Does slave array need update?
*/
-static void ad_disable_collecting_distributing(struct port *port)
+static void ad_disable_collecting_distributing(struct port *port,
+ bool *update_slave_arr)
{
if (port->aggregator &&
!MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system),
@@ -1704,6 +1722,8 @@ static void ad_disable_collecting_distributing(struct port *port)
port->actor_port_number,
port->aggregator->aggregator_identifier);
__disable_port(port);
+ /* Slave array needs an update */
+ *update_slave_arr = true;
}
}
@@ -1868,6 +1888,7 @@ void bond_3ad_unbind_slave(struct slave *slave)
struct bonding *bond = slave->bond;
struct slave *slave_iter;
struct list_head *iter;
+ bool dummy_slave_update; /* Ignore this value as caller updates array */
/* Sync against bond_3ad_state_machine_handler() */
spin_lock_bh(&bond->mode_lock);
@@ -1951,7 +1972,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
ad_clear_agg(aggregator);
if (select_new_active_agg)
- ad_agg_selection_logic(__get_first_agg(port));
+ ad_agg_selection_logic(__get_first_agg(port),
+ &dummy_slave_update);
} else {
netdev_warn(bond->dev, "unbinding aggregator, and could not find a new aggregator for its ports\n");
}
@@ -1966,7 +1988,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
/* select new active aggregator */
temp_aggregator = __get_first_agg(port);
if (temp_aggregator)
- ad_agg_selection_logic(temp_aggregator);
+ ad_agg_selection_logic(temp_aggregator,
+ &dummy_slave_update);
}
}
}
@@ -1996,7 +2019,8 @@ void bond_3ad_unbind_slave(struct slave *slave)
if (select_new_active_agg) {
netdev_info(bond->dev, "Removing an active aggregator\n");
/* select new active aggregator */
- ad_agg_selection_logic(__get_first_agg(port));
+ ad_agg_selection_logic(__get_first_agg(port),
+ &dummy_slave_update);
}
}
break;
@@ -2031,6 +2055,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
struct slave *slave;
struct port *port;
bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER;
+ bool update_slave_arr = false;
/* Lock to protect data accessed by all (e.g., port->sm_vars) and
* against running with bond_3ad_unbind_slave. ad_rx_machine may run
@@ -2058,7 +2083,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
}
aggregator = __get_first_agg(port);
- ad_agg_selection_logic(aggregator);
+ ad_agg_selection_logic(aggregator, &update_slave_arr);
}
bond_3ad_set_carrier(bond);
}
@@ -2074,8 +2099,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work)
ad_rx_machine(NULL, port);
ad_periodic_machine(port);
- ad_port_selection_logic(port);
- ad_mux_machine(port);
+ ad_port_selection_logic(port, &update_slave_arr);
+ ad_mux_machine(port, &update_slave_arr);
ad_tx_machine(port);
/* turn off the BEGIN bit, since we already handled it */
@@ -2093,6 +2118,9 @@ re_arm:
rcu_read_unlock();
spin_unlock_bh(&bond->mode_lock);
+ if (update_slave_arr)
+ bond_slave_arr_work_rearm(bond, 0);
+
if (should_notify_rtnl && rtnl_trylock()) {
bond_slave_state_notify(bond);
rtnl_unlock();
@@ -2283,6 +2311,11 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
port->sm_vars |= AD_PORT_BEGIN;
spin_unlock_bh(&slave->bond->mode_lock);
+
+ /* RTNL is held and mode_lock is released so it's safe
+ * to update slave_array here.
+ */
+ bond_update_slave_arr(slave->bond, NULL);
}
/**
@@ -2377,73 +2410,6 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info)
return ret;
}
-int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
-{
- struct bonding *bond = netdev_priv(dev);
- struct slave *slave, *first_ok_slave;
- struct aggregator *agg;
- struct ad_info ad_info;
- struct list_head *iter;
- int slaves_in_agg;
- int slave_agg_no;
- int agg_id;
-
- if (__bond_3ad_get_active_agg_info(bond, &ad_info)) {
- netdev_dbg(dev, "__bond_3ad_get_active_agg_info failed\n");
- goto err_free;
- }
-
- slaves_in_agg = ad_info.ports;
- agg_id = ad_info.aggregator_id;
-
- if (slaves_in_agg == 0) {
- netdev_dbg(dev, "active aggregator is empty\n");
- goto err_free;
- }
-
- slave_agg_no = bond_xmit_hash(bond, skb) % slaves_in_agg;
- first_ok_slave = NULL;
-
- bond_for_each_slave_rcu(bond, slave, iter) {
- agg = SLAVE_AD_INFO(slave)->port.aggregator;
- if (!agg || agg->aggregator_identifier != agg_id)
- continue;
-
- if (slave_agg_no >= 0) {
- if (!first_ok_slave && bond_slave_can_tx(slave))
- first_ok_slave = slave;
- slave_agg_no--;
- continue;
- }
-
- if (bond_slave_can_tx(slave)) {
- bond_dev_queue_xmit(bond, skb, slave->dev);
- goto out;
- }
- }
-
- if (slave_agg_no >= 0) {
- netdev_err(dev, "Couldn't find a slave to tx on for aggregator ID %d\n",
- agg_id);
- goto err_free;
- }
-
- /* we couldn't find any suitable slave after the agg_no, so use the
- * first suitable found, if found.
- */
- if (first_ok_slave)
- bond_dev_queue_xmit(bond, skb, first_ok_slave->dev);
- else
- goto err_free;
-
-out:
- return NETDEV_TX_OK;
-err_free:
- /* no suitable interface, frame not sent */
- dev_kfree_skb_any(skb);
- goto out;
-}
-
int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond,
struct slave *slave)
{
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 615f3bebd019..d2eadab787c5 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -177,7 +177,6 @@ static int tlb_initialize(struct bonding *bond)
static void tlb_deinitialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- struct tlb_up_slave *arr;
spin_lock_bh(&bond->mode_lock);
@@ -185,10 +184,6 @@ static void tlb_deinitialize(struct bonding *bond)
bond_info->tx_hashtbl = NULL;
spin_unlock_bh(&bond->mode_lock);
-
- arr = rtnl_dereference(bond_info->slave_arr);
- if (arr)
- kfree_rcu(arr, rcu);
}
static long long compute_gap(struct slave *slave)
@@ -1336,39 +1331,9 @@ out:
return NETDEV_TX_OK;
}
-static int bond_tlb_update_slave_arr(struct bonding *bond,
- struct slave *skipslave)
-{
- struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- struct slave *tx_slave;
- struct list_head *iter;
- struct tlb_up_slave *new_arr, *old_arr;
-
- new_arr = kzalloc(offsetof(struct tlb_up_slave, arr[bond->slave_cnt]),
- GFP_ATOMIC);
- if (!new_arr)
- return -ENOMEM;
-
- bond_for_each_slave(bond, tx_slave, iter) {
- if (!bond_slave_can_tx(tx_slave))
- continue;
- if (skipslave == tx_slave)
- continue;
- new_arr->arr[new_arr->count++] = tx_slave;
- }
-
- old_arr = rtnl_dereference(bond_info->slave_arr);
- rcu_assign_pointer(bond_info->slave_arr, new_arr);
- if (old_arr)
- kfree_rcu(old_arr, rcu);
-
- return 0;
-}
-
int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct ethhdr *eth_data;
struct slave *tx_slave = NULL;
u32 hash_index;
@@ -1389,12 +1354,14 @@ int bond_tlb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
hash_index & 0xFF,
skb->len);
} else {
- struct tlb_up_slave *slaves;
+ struct bond_up_slave *slaves;
+ unsigned int count;
- slaves = rcu_dereference(bond_info->slave_arr);
- if (slaves && slaves->count)
+ slaves = rcu_dereference(bond->slave_arr);
+ count = slaves ? ACCESS_ONCE(slaves->count) : 0;
+ if (likely(count))
tx_slave = slaves->arr[hash_index %
- slaves->count];
+ count];
}
break;
}
@@ -1641,10 +1608,6 @@ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave)
rlb_clear_slave(bond, slave);
}
- if (bond_is_nondyn_tlb(bond))
- if (bond_tlb_update_slave_arr(bond, slave))
- pr_err("Failed to build slave-array for TLB mode.\n");
-
}
void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link)
@@ -1669,7 +1632,7 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char
}
if (bond_is_nondyn_tlb(bond)) {
- if (bond_tlb_update_slave_arr(bond, NULL))
+ if (bond_update_slave_arr(bond, NULL))
pr_err("Failed to build slave-array for TLB mode.\n");
}
}
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 3c6a7ff974d7..1ad473b4ade5 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -139,19 +139,11 @@ struct tlb_slave_info {
*/
};
-struct tlb_up_slave {
- unsigned int count;
- struct rcu_head rcu;
- struct slave *arr[0];
-};
-
struct alb_bond_info {
struct tlb_client_info *tx_hashtbl; /* Dynamically allocated */
u32 unbalanced_load;
int tx_rebalance_counter;
int lp_counter;
- /* -------- non-dynamic tlb mode only ---------*/
- struct tlb_up_slave __rcu *slave_arr; /* Up slaves */
/* -------- rlb parameters -------- */
int rlb_enabled;
struct rlb_client_info *rx_hashtbl; /* Receive hash table */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index c2adc2755ff6..fd4766861d6e 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -210,6 +210,7 @@ static int bond_init(struct net_device *bond_dev);
static void bond_uninit(struct net_device *bond_dev);
static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
struct rtnl_link_stats64 *stats);
+static void bond_slave_arr_handler(struct work_struct *work);
/*---------------------------- General routines -----------------------------*/
@@ -1551,6 +1552,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
unblock_netpoll_tx();
}
+ if (bond_mode_uses_xmit_hash(bond))
+ bond_update_slave_arr(bond, NULL);
+
netdev_info(bond_dev, "Enslaving %s as %s interface with %s link\n",
slave_dev->name,
bond_is_active_slave(new_slave) ? "an active" : "a backup",
@@ -1668,6 +1672,9 @@ static int __bond_release_one(struct net_device *bond_dev,
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_unbind_slave(slave);
+ if (bond_mode_uses_xmit_hash(bond))
+ bond_update_slave_arr(bond, slave);
+
netdev_info(bond_dev, "Releasing %s interface %s\n",
bond_is_active_slave(slave) ? "active" : "backup",
slave_dev->name);
@@ -1970,6 +1977,9 @@ static void bond_miimon_commit(struct bonding *bond)
bond_alb_handle_link_change(bond, slave,
BOND_LINK_UP);
+ if (BOND_MODE(bond) == BOND_MODE_XOR)
+ bond_update_slave_arr(bond, NULL);
+
if (!bond->curr_active_slave || slave == primary)
goto do_failover;
@@ -1997,6 +2007,9 @@ static void bond_miimon_commit(struct bonding *bond)
bond_alb_handle_link_change(bond, slave,
BOND_LINK_DOWN);
+ if (BOND_MODE(bond) == BOND_MODE_XOR)
+ bond_update_slave_arr(bond, NULL);
+
if (slave == rcu_access_pointer(bond->curr_active_slave))
goto do_failover;
@@ -2453,6 +2466,8 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
if (slave_state_changed) {
bond_slave_state_change(bond);
+ if (BOND_MODE(bond) == BOND_MODE_XOR)
+ bond_update_slave_arr(bond, NULL);
} else if (do_failover) {
block_netpoll_tx();
bond_select_active_slave(bond);
@@ -2829,8 +2844,20 @@ static int bond_slave_netdev_event(unsigned long event,
if (old_duplex != slave->duplex)
bond_3ad_adapter_duplex_changed(slave);
}
+ /* Refresh slave-array if applicable!
+ * If the setup does not use miimon or arpmon (mode-specific!),
+ * then these events will not cause the slave-array to be
+ * refreshed. This will cause xmit to use a slave that is not
+ * usable. Avoid such situation by refeshing the array at these
+ * events. If these (miimon/arpmon) parameters are configured
+ * then array gets refreshed twice and that should be fine!
+ */
+ if (bond_mode_uses_xmit_hash(bond))
+ bond_update_slave_arr(bond, NULL);
break;
case NETDEV_DOWN:
+ if (bond_mode_uses_xmit_hash(bond))
+ bond_update_slave_arr(bond, NULL);
break;
case NETDEV_CHANGEMTU:
/* TODO: Should slaves be allowed to
@@ -3010,6 +3037,7 @@ static void bond_work_init_all(struct bonding *bond)
else
INIT_DELAYED_WORK(&bond->arp_work, bond_loadbalance_arp_mon);
INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
+ INIT_DELAYED_WORK(&bond->slave_arr_work, bond_slave_arr_handler);
}
static void bond_work_cancel_all(struct bonding *bond)
@@ -3019,6 +3047,7 @@ static void bond_work_cancel_all(struct bonding *bond)
cancel_delayed_work_sync(&bond->alb_work);
cancel_delayed_work_sync(&bond->ad_work);
cancel_delayed_work_sync(&bond->mcast_work);
+ cancel_delayed_work_sync(&bond->slave_arr_work);
}
static int bond_open(struct net_device *bond_dev)
@@ -3068,6 +3097,9 @@ static int bond_open(struct net_device *bond_dev)
bond_3ad_initiate_agg_selection(bond, 1);
}
+ if (bond_mode_uses_xmit_hash(bond))
+ bond_update_slave_arr(bond, NULL);
+
return 0;
}
@@ -3573,20 +3605,141 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
return NETDEV_TX_OK;
}
-/* In bond_xmit_xor() , we determine the output device by using a pre-
- * determined xmit_hash_policy(), If the selected device is not enabled,
- * find the next active slave.
+/* Use this to update slave_array when (a) it's not appropriate to update
+ * slave_array right away (note that update_slave_array() may sleep)
+ * and / or (b) RTNL is not held.
*/
-static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
+void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay)
{
- struct bonding *bond = netdev_priv(bond_dev);
- int slave_cnt = ACCESS_ONCE(bond->slave_cnt);
+ queue_delayed_work(bond->wq, &bond->slave_arr_work, delay);
+}
- if (likely(slave_cnt))
- bond_xmit_slave_id(bond, skb,
- bond_xmit_hash(bond, skb) % slave_cnt);
- else
+/* Slave array work handler. Holds only RTNL */
+static void bond_slave_arr_handler(struct work_struct *work)
+{
+ struct bonding *bond = container_of(work, struct bonding,
+ slave_arr_work.work);
+ int ret;
+
+ if (!rtnl_trylock())
+ goto err;
+
+ ret = bond_update_slave_arr(bond, NULL);
+ rtnl_unlock();
+ if (ret) {
+ pr_warn_ratelimited("Failed to update slave array from WT\n");
+ goto err;
+ }
+ return;
+
+err:
+ bond_slave_arr_work_rearm(bond, 1);
+}
+
+/* Build the usable slaves array in control path for modes that use xmit-hash
+ * to determine the slave interface -
+ * (a) BOND_MODE_8023AD
+ * (b) BOND_MODE_XOR
+ * (c) BOND_MODE_TLB && tlb_dynamic_lb == 0
+ *
+ * The caller is expected to hold RTNL only and NO other lock!
+ */
+int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave)
+{
+ struct slave *slave;
+ struct list_head *iter;
+ struct bond_up_slave *new_arr, *old_arr;
+ int slaves_in_agg;
+ int agg_id = 0;
+ int ret = 0;
+
+#ifdef CONFIG_LOCKDEP
+ WARN_ON(lockdep_is_held(&bond->mode_lock));
+#endif
+
+ new_arr = kzalloc(offsetof(struct bond_up_slave, arr[bond->slave_cnt]),
+ GFP_KERNEL);
+ if (!new_arr) {
+ ret = -ENOMEM;
+ pr_err("Failed to build slave-array.\n");
+ goto out;
+ }
+ if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ struct ad_info ad_info;
+
+ if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
+ pr_debug("bond_3ad_get_active_agg_info failed\n");
+ kfree_rcu(new_arr, rcu);
+ ret = -EINVAL;
+ goto out;
+ }
+ slaves_in_agg = ad_info.ports;
+ agg_id = ad_info.aggregator_id;
+ }
+ bond_for_each_slave(bond, slave, iter) {
+ if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ struct aggregator *agg;
+
+ agg = SLAVE_AD_INFO(slave)->port.aggregator;
+ if (!agg || agg->aggregator_identifier != agg_id)
+ continue;
+ }
+ if (!bond_slave_can_tx(slave))
+ continue;
+ if (skipslave == slave)
+ continue;
+ new_arr->arr[new_arr->count++] = slave;
+ }
+
+ old_arr = rtnl_dereference(bond->slave_arr);
+ rcu_assign_pointer(bond->slave_arr, new_arr);
+ if (old_arr)
+ kfree_rcu(old_arr, rcu);
+out:
+ if (ret != 0 && skipslave) {
+ int idx;
+
+ /* Rare situation where caller has asked to skip a specific
+ * slave but allocation failed (most likely!). BTW this is
+ * only possible when the call is initiated from
+ * __bond_release_one(). In this situation; overwrite the
+ * skipslave entry in the array with the last entry from the
+ * array to avoid a situation where the xmit path may choose
+ * this to-be-skipped slave to send a packet out.
+ */
+ old_arr = rtnl_dereference(bond->slave_arr);
+ for (idx = 0; idx < old_arr->count; idx++) {
+ if (skipslave == old_arr->arr[idx]) {
+ old_arr->arr[idx] =
+ old_arr->arr[old_arr->count-1];
+ old_arr->count--;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+/* Use this Xmit function for 3AD as well as XOR modes. The current
+ * usable slave array is formed in the control path. The xmit function
+ * just calculates hash and sends the packet out.
+ */
+int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct bonding *bond = netdev_priv(dev);
+ struct slave *slave;
+ struct bond_up_slave *slaves;
+ unsigned int count;
+
+ slaves = rcu_dereference(bond->slave_arr);
+ count = slaves ? ACCESS_ONCE(slaves->count) : 0;
+ if (likely(count)) {
+ slave = slaves->arr[bond_xmit_hash(bond, skb) % count];
+ bond_dev_queue_xmit(bond, skb, slave->dev);
+ } else {
dev_kfree_skb_any(skb);
+ atomic_long_inc(&dev->tx_dropped);
+ }
return NETDEV_TX_OK;
}
@@ -3682,12 +3835,11 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev
return bond_xmit_roundrobin(skb, dev);
case BOND_MODE_ACTIVEBACKUP:
return bond_xmit_activebackup(skb, dev);
+ case BOND_MODE_8023AD:
case BOND_MODE_XOR:
- return bond_xmit_xor(skb, dev);
+ return bond_3ad_xor_xmit(skb, dev);
case BOND_MODE_BROADCAST:
return bond_xmit_broadcast(skb, dev);
- case BOND_MODE_8023AD:
- return bond_3ad_xmit_xor(skb, dev);
case BOND_MODE_ALB:
return bond_alb_xmit(skb, dev);
case BOND_MODE_TLB:
@@ -3861,6 +4013,7 @@ static void bond_uninit(struct net_device *bond_dev)
struct bonding *bond = netdev_priv(bond_dev);
struct list_head *iter;
struct slave *slave;
+ struct bond_up_slave *arr;
bond_netpoll_cleanup(bond_dev);
@@ -3869,6 +4022,12 @@ static void bond_uninit(struct net_device *bond_dev)
__bond_release_one(bond_dev, slave->dev, true);
netdev_info(bond_dev, "Released all slaves\n");
+ arr = rtnl_dereference(bond->slave_arr);
+ if (arr) {
+ kfree_rcu(arr, rcu);
+ RCU_INIT_POINTER(bond->slave_arr, NULL);
+ }
+
list_del(&bond->bond_list);
bond_debug_unregister(bond);
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 5b022da9cad2..10920f0686e2 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -179,6 +179,12 @@ struct slave {
struct rtnl_link_stats64 slave_stats;
};
+struct bond_up_slave {
+ unsigned int count;
+ struct rcu_head rcu;
+ struct slave *arr[0];
+};
+
/*
* Link pseudo-state only used internally by monitors
*/
@@ -193,6 +199,7 @@ struct bonding {
struct slave __rcu *curr_active_slave;
struct slave __rcu *current_arp_slave;
struct slave __rcu *primary_slave;
+ struct bond_up_slave __rcu *slave_arr; /* Array of usable slaves */
bool force_primary;
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
int (*recv_probe)(const struct sk_buff *, struct bonding *,
@@ -222,6 +229,7 @@ struct bonding {
struct delayed_work alb_work;
struct delayed_work ad_work;
struct delayed_work mcast_work;
+ struct delayed_work slave_arr_work;
#ifdef CONFIG_DEBUG_FS
/* debugging support via debugfs */
struct dentry *debug_dir;
@@ -534,6 +542,8 @@ const char *bond_slave_link_status(s8 link);
struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
int level);
+int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave);
+void bond_slave_arr_work_rearm(struct bonding *bond, unsigned long delay);
#ifdef CONFIG_PROC_FS
void bond_create_proc_entry(struct bonding *bond);
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH net-next v5 1/2] bonding: display xmit_hash_policy for non-dynamic-tlb mode
From: Mahesh Bandewar @ 2014-09-30 6:26 UTC (permalink / raw)
To: Jay Vosburgh, Veaceslav Falico, Andy Gospodarek, David Miller
Cc: netdev, Mahesh Bandewar, Eric Dumazet, Maciej Zenczykowski
It's a trivial fix to display xmit_hash_policy for this new TLB mode
since it uses transmit-hash-poilicy as part of bonding-master info
(/proc/net/bonding/<bonding-interface).
Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Reviewed-by: Nikolay Aleksandrov <nikolay@redhat.com>
---
v1
Rebase
v2
Added bond_mode_uses_xmit_hash() inline function
v3
Rebase
v4
Rebase
v5
Rebase
drivers/net/bonding/bond_procfs.c | 3 +--
drivers/net/bonding/bonding.h | 7 +++++++
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index bb09d0442aa8..a3948f8d1e53 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -73,8 +73,7 @@ static void bond_info_show_master(struct seq_file *seq)
seq_printf(seq, "\n");
- if (BOND_MODE(bond) == BOND_MODE_XOR ||
- BOND_MODE(bond) == BOND_MODE_8023AD) {
+ if (bond_mode_uses_xmit_hash(bond)) {
optval = bond_opt_get_val(BOND_OPT_XMIT_HASH,
bond->params.xmit_policy);
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 57917e63b4e6..5b022da9cad2 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -274,6 +274,13 @@ static inline bool bond_is_nondyn_tlb(const struct bonding *bond)
(bond->params.tlb_dynamic_lb == 0);
}
+static inline bool bond_mode_uses_xmit_hash(const struct bonding *bond)
+{
+ return (BOND_MODE(bond) == BOND_MODE_8023AD ||
+ BOND_MODE(bond) == BOND_MODE_XOR ||
+ bond_is_nondyn_tlb(bond));
+}
+
static inline bool bond_mode_uses_arp(int mode)
{
return mode != BOND_MODE_8023AD && mode != BOND_MODE_TLB &&
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH iproute2] tests: Check existing of /proc/config.gz before use it
From: Vadim Kochan @ 2014-09-30 6:15 UTC (permalink / raw)
To: netdev; +Cc: Vadim Kochan
Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
---
testsuite/Makefile | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/testsuite/Makefile b/testsuite/Makefile
index b4ab15e..d1bf359 100644
--- a/testsuite/Makefile
+++ b/testsuite/Makefile
@@ -6,7 +6,10 @@ RESULTS_DIR := results
TESTS := $(patsubst tests/%,%,$(wildcard tests/*.t))
IPVERS := $(filter-out iproute2/Makefile,$(wildcard iproute2/*))
-KENV := $(shell cat /proc/config.gz | gunzip | grep ^CONFIG)
+
+ifneq (,$(wildcard /proc/config.gz))
+ KENV := $(shell cat /proc/config.gz | gunzip | grep ^CONFIG)
+endif
.PHONY: compile listtests alltests configure $(TESTS)
--
2.1.0
^ permalink raw reply related
* [PATCH] net: ethernet : stmicro: fixed power suspend and resume failure in stmmac driver
From: hliang1025 @ 2014-09-30 5:55 UTC (permalink / raw)
To: peppe.cavallaro; +Cc: netdev, linux-kernel, adi-linux-docs, Hao Liang
From: Hao Liang <hliang1025@gmail.com>
This is the fix for a power management issue caused by suspend and resume function in stmmac_main.c.
After enable CONFIG_DEBUG_ATOMIC_SLEEP which enable sleep-inside atomic section checking, power
managemet can not work normally. Board couldn't wakeup successfully after suspend. Command
"echo mem > /sys/power/state" suspend the board.
In suspend and resume function of stmmac driver, there are some sleep-inside function in atomic section
created by spin lock. These functions will causes system warnings and wakeup issue when enable
CONFIG_DEBUG_ATOMIC_SLEEP.
This bug was fixed by:
* replace some sleep function with non-sleep function
clk_disable_unprepare -> clk_disable ...
* decrease the atomic area created by spin lock function. The original atomic area in resume function is
too large.
Signed-off-by: Hao Liang <hliang1025@gmail.com>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 6e6ee22..2effbfe 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -2924,9 +2924,8 @@ int stmmac_suspend(struct net_device *ndev)
if (priv->phydev)
phy_stop(priv->phydev);
- spin_lock_irqsave(&priv->lock, flags);
-
netif_device_detach(ndev);
+
netif_stop_queue(ndev);
napi_disable(&priv->napi);
@@ -2935,6 +2934,8 @@ int stmmac_suspend(struct net_device *ndev)
priv->hw->dma->stop_tx(priv->ioaddr);
priv->hw->dma->stop_rx(priv->ioaddr);
+ spin_lock_irqsave(&priv->lock, flags);
+
stmmac_clear_descriptors(priv);
/* Enable Power down mode by programming the PMT regs */
@@ -2945,7 +2946,7 @@ int stmmac_suspend(struct net_device *ndev)
stmmac_set_mac(priv->ioaddr, false);
pinctrl_pm_select_sleep_state(priv->device);
/* Disable clock in case of PWM is off */
- clk_disable_unprepare(priv->stmmac_clk);
+ clk_disable(priv->stmmac_clk);
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -2977,12 +2978,14 @@ int stmmac_resume(struct net_device *ndev)
} else {
pinctrl_pm_select_default_state(priv->device);
/* enable the clk prevously disabled */
- clk_prepare_enable(priv->stmmac_clk);
+ clk_enable(priv->stmmac_clk);
/* reset the phy so that it's ready */
if (priv->mii)
stmmac_mdio_reset(priv->mii);
}
+ spin_unlock_irqrestore(&priv->lock, flags);
+
netif_device_attach(ndev);
stmmac_hw_setup(ndev);
@@ -2991,8 +2994,6 @@ int stmmac_resume(struct net_device *ndev)
netif_start_queue(ndev);
- spin_unlock_irqrestore(&priv->lock, flags);
-
if (priv->phydev)
phy_start(priv->phydev);
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH RESEND v6 0/7] net: cpsw: Support for am335x chip MACIDs
From: David Miller @ 2014-09-30 5:31 UTC (permalink / raw)
To: mpa
Cc: bcousson, tony, wsa, rostedt, mugunthanvnm, linux-omap,
devicetree, linux-arm-kernel, netdev, kernel
In-Reply-To: <1411973599-18908-1-git-send-email-mpa@pengutronix.de>
From: Markus Pargmann <mpa@pengutronix.de>
Date: Mon, 29 Sep 2014 08:53:12 +0200
> Another resend of this series to add the netdev list.
>
> This series adds support to the cpsw driver to read the MACIDs of the am335x
> chip and use them as fallback. These addresses are only used if there are no
> mac addresses in the devicetree, for example set by a bootloader.
Series applied to net-next, thanks.
^ permalink raw reply
* Re: [PATCH iproute2] ip link: Shortify printing the usage of link type
From: Vadim Kochan @ 2014-09-30 5:27 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev@vger.kernel.org
In-Reply-To: <20140929085038.7d2b5de3@urahara>
Fixed conflicts in the v2.
On Mon, Sep 29, 2014 at 6:50 PM, Stephen Hemminger
<stephen@networkplumber.org> wrote:
> On Sat, 20 Sep 2014 01:43:47 +0300
> Vadim Kochan <vadim4j@gmail.com> wrote:
>
>> Allow to print particular link type usage by:
>>
>> ip link help [TYPE]
>>
>> Currently to print usage for some link type it is needed
>> to use the following way:
>>
>> ip link { add | del | set } type TYPE help
>>
>> Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
>
> I like this, but does not apply to current iproute2 tree.
> Probably because I took in some other patches.
^ permalink raw reply
* [PATCH iproute2 v2] ip link: Shortify printing the usage of link type
From: Vadim Kochan @ 2014-09-30 5:17 UTC (permalink / raw)
To: netdev; +Cc: Vadim Kochan
Allow to print particular link type usage by:
ip link help [TYPE]
Currently to print usage for some link type it is needed
to use the following way:
ip link { add | del | set } type TYPE help
Signed-off-by: Vadim Kochan <vadim4j@gmail.com>
---
ip/ip_common.h | 2 ++
ip/iplink.c | 24 ++++++++++++++++++++++--
ip/iplink_bond.c | 16 ++++++++++++++--
ip/iplink_can.c | 16 ++++++++++++++--
ip/iplink_hsr.c | 16 ++++++++++++++--
ip/iplink_ipoib.c | 15 +++++++++++++--
ip/iplink_macvlan.c | 16 ++++++++++++++--
ip/iplink_macvtap.c | 14 +++++++++++++-
ip/iplink_vlan.c | 16 ++++++++++++++--
ip/iplink_vxlan.c | 34 +++++++++++++++++++++++-----------
ip/link_gre.c | 33 +++++++++++++++++++++++----------
ip/link_gre6.c | 45 +++++++++++++++++++++++++++++----------------
ip/link_ip6tnl.c | 42 +++++++++++++++++++++++++++---------------
ip/link_iptnl.c | 39 ++++++++++++++++++++++++++-------------
ip/link_veth.c | 14 +++++++++++++-
ip/link_vti.c | 28 ++++++++++++++++++++--------
16 files changed, 281 insertions(+), 89 deletions(-)
diff --git a/ip/ip_common.h b/ip/ip_common.h
index e56d1ac..8351463 100644
--- a/ip/ip_common.h
+++ b/ip/ip_common.h
@@ -76,6 +76,8 @@ struct link_util
struct rtattr *[]);
void (*print_xstats)(struct link_util *, FILE *,
struct rtattr *);
+ void (*print_help)(struct link_util *, int, char **,
+ FILE *);
bool slave;
};
diff --git a/ip/iplink.c b/ip/iplink.c
index cb9c870..2736e63 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -85,6 +85,7 @@ void iplink_usage(void)
fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up]\n");
if (iplink_have_newlink()) {
+ fprintf(stderr, " ip link help [ TYPE ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n");
fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n");
@@ -1134,6 +1135,23 @@ static int do_set(int argc, char **argv)
}
#endif /* IPLINK_IOCTL_COMPAT */
+static void do_help(int argc, char **argv)
+{
+ struct link_util *lu = NULL;
+
+ if (argc <= 0) {
+ usage();
+ return ;
+ }
+
+ lu = get_link_kind(*argv);
+
+ if (lu && lu->print_help)
+ lu->print_help(lu, argc-1, argv+1, stdout);
+ else
+ usage();
+}
+
int do_iplink(int argc, char **argv)
{
if (argc > 0) {
@@ -1163,8 +1181,10 @@ int do_iplink(int argc, char **argv)
matches(*argv, "lst") == 0 ||
matches(*argv, "list") == 0)
return ipaddr_list_link(argc-1, argv+1);
- if (matches(*argv, "help") == 0)
- usage();
+ if (matches(*argv, "help") == 0) {
+ do_help(argc-1, argv+1);
+ return 0;
+ }
} else
return ipaddr_list_link(0, NULL);
diff --git a/ip/iplink_bond.c b/ip/iplink_bond.c
index 0a1ed03..3009ec9 100644
--- a/ip/iplink_bond.c
+++ b/ip/iplink_bond.c
@@ -112,9 +112,9 @@ static int get_index(const char **tbl, char *name)
return -1;
}
-static void explain(void)
+static void print_explain(FILE *f)
{
- fprintf(stderr,
+ fprintf(f,
"Usage: ... bond [ mode BONDMODE ] [ active_slave SLAVE_DEV ]\n"
" [ clear_active_slave ] [ miimon MIIMON ]\n"
" [ updelay UPDELAY ] [ downdelay DOWNDELAY ]\n"
@@ -147,6 +147,11 @@ static void explain(void)
);
}
+static void explain(void)
+{
+ print_explain(stderr);
+}
+
static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
@@ -530,9 +535,16 @@ static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
}
}
+static void bond_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_explain(f);
+}
+
struct link_util bond_link_util = {
.id = "bond",
.maxattr = IFLA_BOND_MAX,
.parse_opt = bond_parse_opt,
.print_opt = bond_print_opt,
+ .print_help = bond_print_help,
};
diff --git a/ip/iplink_can.c b/ip/iplink_can.c
index 3bef82a..5b92426 100644
--- a/ip/iplink_can.c
+++ b/ip/iplink_can.c
@@ -19,9 +19,9 @@
#include "utils.h"
#include "ip_common.h"
-static void usage(void)
+static void print_usage(FILE *f)
{
- fprintf(stderr,
+ fprintf(f,
"Usage: ip link set DEVICE type can\n"
"\t[ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | \n"
"\t[ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n "
@@ -52,6 +52,11 @@ static void usage(void)
);
}
+static void usage(void)
+{
+ print_usage(stderr);
+}
+
static int get_float(float *val, const char *arg)
{
float res;
@@ -344,10 +349,17 @@ static void can_print_xstats(struct link_util *lu,
}
}
+static void can_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util can_link_util = {
.id = "can",
.maxattr = IFLA_CAN_MAX,
.parse_opt = can_parse_opt,
.print_opt = can_print_opt,
.print_xstats = can_print_xstats,
+ .print_help = can_print_help,
};
diff --git a/ip/iplink_hsr.c b/ip/iplink_hsr.c
index 136da35..65fbec8 100644
--- a/ip/iplink_hsr.c
+++ b/ip/iplink_hsr.c
@@ -21,9 +21,9 @@
#include "utils.h"
#include "ip_common.h"
-static void usage(void)
+static void print_usage(FILE *f)
{
- fprintf(stderr,
+ fprintf(f,
"Usage:\tip link add name NAME type hsr slave1 SLAVE1-IF slave2 SLAVE2-IF\n"
"\t[ supervision ADDR-BYTE ]\n"
"\n"
@@ -36,6 +36,11 @@ static void usage(void)
" frames (default = 0)\n");
}
+static void usage(void)
+{
+ print_usage(stderr);
+}
+
static int hsr_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *n)
{
@@ -121,9 +126,16 @@ static void hsr_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
b1, sizeof(b1)));
}
+static void hsr_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util hsr_link_util = {
.id = "hsr",
.maxattr = IFLA_VLAN_MAX,
.parse_opt = hsr_parse_opt,
.print_opt = hsr_print_opt,
+ .print_help = hsr_print_help,
};
diff --git a/ip/iplink_ipoib.c b/ip/iplink_ipoib.c
index 5c1c68c..6087cbe 100644
--- a/ip/iplink_ipoib.c
+++ b/ip/iplink_ipoib.c
@@ -19,9 +19,9 @@
#include "utils.h"
#include "ip_common.h"
-static void explain(void)
+static void print_explain(FILE *f)
{
- fprintf(stderr,
+ fprintf(f,
"Usage: ... ipoib [pkey PKEY] [mode {datagram | connected}]"
"[umcast {0|1}]\n"
"\n"
@@ -29,6 +29,10 @@ static void explain(void)
);
}
+static void explain(void)
+{
+ print_explain(stderr);
+}
static int mode_arg(void)
{
@@ -106,9 +110,16 @@ static void ipoib_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fprintf(f, "umcast %.4x ", rta_getattr_u16(tb[IFLA_IPOIB_UMCAST]));
}
+static void ipoib_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_explain(f);
+}
+
struct link_util ipoib_link_util = {
.id = "ipoib",
.maxattr = IFLA_IPOIB_MAX,
.parse_opt = ipoib_parse_opt,
.print_opt = ipoib_print_opt,
+ .print_help = ipoib_print_help,
};
diff --git a/ip/iplink_macvlan.c b/ip/iplink_macvlan.c
index ec51106..826b659 100644
--- a/ip/iplink_macvlan.c
+++ b/ip/iplink_macvlan.c
@@ -20,13 +20,18 @@
#include "utils.h"
#include "ip_common.h"
-static void explain(void)
+static void print_explain(FILE *f)
{
- fprintf(stderr,
+ fprintf(f,
"Usage: ... macvlan mode { private | vepa | bridge | passthru }\n"
);
}
+static void explain(void)
+{
+ print_explain(stderr);
+}
+
static int mode_arg(void)
{
fprintf(stderr, "Error: argument of \"mode\" must be \"private\", "
@@ -88,9 +93,16 @@ static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
: "unknown");
}
+static void macvlan_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_explain(f);
+}
+
struct link_util macvlan_link_util = {
.id = "macvlan",
.maxattr = IFLA_MACVLAN_MAX,
.parse_opt = macvlan_parse_opt,
.print_opt = macvlan_print_opt,
+ .print_help = macvlan_print_help,
};
diff --git a/ip/iplink_macvtap.c b/ip/iplink_macvtap.c
index bea9f0c..9c2cd74 100644
--- a/ip/iplink_macvtap.c
+++ b/ip/iplink_macvtap.c
@@ -17,13 +17,18 @@
#include "utils.h"
#include "ip_common.h"
-static void explain(void)
+static void print_explain(FILE *f)
{
fprintf(stderr,
"Usage: ... macvtap mode { private | vepa | bridge | passthru }\n"
);
}
+static void explain(void)
+{
+ print_explain(stderr);
+}
+
static int mode_arg(const char *arg)
{
fprintf(stderr, "Error: argument of \"mode\" must be \"private\", "
@@ -85,9 +90,16 @@ static void macvtap_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]
: "unknown");
}
+static void macvtap_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_explain(f);
+}
+
struct link_util macvtap_link_util = {
.id = "macvtap",
.maxattr = IFLA_MACVLAN_MAX,
.parse_opt = macvtap_parse_opt,
.print_opt = macvtap_print_opt,
+ .print_help = macvtap_print_help,
};
diff --git a/ip/iplink_vlan.c b/ip/iplink_vlan.c
index 94b52ae..5bd766f 100644
--- a/ip/iplink_vlan.c
+++ b/ip/iplink_vlan.c
@@ -18,9 +18,9 @@
#include "utils.h"
#include "ip_common.h"
-static void explain(void)
+static void print_explain(FILE *f)
{
- fprintf(stderr,
+ fprintf(f,
"Usage: ... vlan [ protocol VLANPROTO ] id VLANID"
" [ FLAG-LIST ]\n"
" [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
@@ -35,6 +35,11 @@ static void explain(void)
);
}
+static void explain(void)
+{
+ print_explain(stderr);
+}
+
static int on_off(const char *msg, const char *arg)
{
fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", msg, arg);
@@ -226,9 +231,16 @@ static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
}
+static void vlan_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_explain(f);
+}
+
struct link_util vlan_link_util = {
.id = "vlan",
.maxattr = IFLA_VLAN_MAX,
.parse_opt = vlan_parse_opt,
.print_opt = vlan_print_opt,
+ .print_help = vlan_print_help,
};
diff --git a/ip/iplink_vxlan.c b/ip/iplink_vxlan.c
index d92cfe8..f410423 100644
--- a/ip/iplink_vxlan.c
+++ b/ip/iplink_vxlan.c
@@ -21,19 +21,24 @@
#include "utils.h"
#include "ip_common.h"
+static void print_explain(FILE *f)
+{
+ fprintf(f, "Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ]\n");
+ fprintf(f, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
+ fprintf(f, " [ dstport PORT ] [ srcport MIN MAX ]\n");
+ fprintf(f, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
+ fprintf(f, " [ [no]l2miss ] [ [no]l3miss ]\n");
+ fprintf(f, " [ ageing SECONDS ] [ maxaddress NUMBER ]\n");
+ fprintf(f, "\n");
+ fprintf(f, "Where: VNI := 0-16777215\n");
+ fprintf(f, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(f, " TOS := { NUMBER | inherit }\n");
+ fprintf(f, " TTL := { 1..255 | inherit }\n");
+}
+
static void explain(void)
{
- fprintf(stderr, "Usage: ... vxlan id VNI [ { group | remote } ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ dev PHYS_DEV ]\n");
- fprintf(stderr, " [ dstport PORT ] [ srcport MIN MAX ]\n");
- fprintf(stderr, " [ [no]learning ] [ [no]proxy ] [ [no]rsc ]\n");
- fprintf(stderr, " [ [no]l2miss ] [ [no]l3miss ]\n");
- fprintf(stderr, " [ ageing SECONDS ] [ maxaddress NUMBER ]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: VNI := 0-16777215\n");
- fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
- fprintf(stderr, " TOS := { NUMBER | inherit }\n");
- fprintf(stderr, " TTL := { 1..255 | inherit }\n");
+ print_explain(stderr);
}
static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
@@ -365,9 +370,16 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fprintf(f, "maxaddr %u ", maxaddr);
}
+static void vxlan_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_explain(f);
+}
+
struct link_util vxlan_link_util = {
.id = "vxlan",
.maxattr = IFLA_VXLAN_MAX,
.parse_opt = vxlan_parse_opt,
.print_opt = vxlan_print_opt,
+ .print_help = vxlan_print_help,
};
diff --git a/ip/link_gre.c b/ip/link_gre.c
index fda84d8..83653d0 100644
--- a/ip/link_gre.c
+++ b/ip/link_gre.c
@@ -23,19 +23,24 @@
#include "ip_common.h"
#include "tunnel.h"
+static void print_usage(FILE *f)
+{
+ fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(f, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(f, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(f, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(f, "\n");
+ fprintf(f, "Where: NAME := STRING\n");
+ fprintf(f, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(f, " TOS := { NUMBER | inherit }\n");
+ fprintf(f, " TTL := { 1..255 | inherit }\n");
+ fprintf(f, " KEY := { DOTTED_QUAD | NUMBER }\n");
+}
+
static void usage(void) __attribute__((noreturn));
static void usage(void)
{
- fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
- fprintf(stderr, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
- fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: NAME := STRING\n");
- fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
- fprintf(stderr, " TOS := { NUMBER | inherit }\n");
- fprintf(stderr, " TTL := { 1..255 | inherit }\n");
- fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ print_usage(stderr);
exit(-1);
}
@@ -354,11 +359,18 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fputs("ocsum ", f);
}
+static void gre_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util gre_link_util = {
.id = "gre",
.maxattr = IFLA_GRE_MAX,
.parse_opt = gre_parse_opt,
.print_opt = gre_print_opt,
+ .print_help = gre_print_help,
};
struct link_util gretap_link_util = {
@@ -366,4 +378,5 @@ struct link_util gretap_link_util = {
.maxattr = IFLA_GRE_MAX,
.parse_opt = gre_parse_opt,
.print_opt = gre_print_opt,
+ .print_help = gre_print_help,
};
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
index c7183e2..f18919c 100644
--- a/ip/link_gre6.c
+++ b/ip/link_gre6.c
@@ -30,25 +30,30 @@
#define DEFAULT_TNL_HOP_LIMIT (64)
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
+static void print_usage(FILE *f)
{
- fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
- fprintf(stderr, " type { ip6gre | ip6gretap } [ remote ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
- fprintf(stderr, " [ hoplimit TTL ] [ encaplimit ELIM ]\n");
- fprintf(stderr, " [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
- fprintf(stderr, " [ dscp inherit ] [ dev PHYS_DEV ]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: NAME := STRING\n");
- fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
- fprintf(stderr, " TTL := { 0..255 } (default=%d)\n",
+ fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(f, " type { ip6gre | ip6gretap } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(f, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
+ fprintf(f, " [ hoplimit TTL ] [ encaplimit ELIM ]\n");
+ fprintf(f, " [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+ fprintf(f, " [ dscp inherit ] [ dev PHYS_DEV ]\n");
+ fprintf(f, "\n");
+ fprintf(f, "Where: NAME := STRING\n");
+ fprintf(f, " ADDR := IPV6_ADDRESS\n");
+ fprintf(f, " TTL := { 0..255 } (default=%d)\n",
DEFAULT_TNL_HOP_LIMIT);
- fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
- fprintf(stderr, " ELIM := { none | 0..255 }(default=%d)\n",
+ fprintf(f, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ fprintf(f, " ELIM := { none | 0..255 }(default=%d)\n",
IPV6_DEFAULT_TNL_ENCAP_LIMIT);
- fprintf(stderr, " TCLASS := { 0x0..0xff | inherit }\n");
- fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+ fprintf(f, " TCLASS := { 0x0..0xff | inherit }\n");
+ fprintf(f, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+}
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ print_usage(stderr);
exit(-1);
}
@@ -386,11 +391,18 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fputs("ocsum ", f);
}
+static void gre_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util ip6gre_link_util = {
.id = "ip6gre",
.maxattr = IFLA_GRE_MAX,
.parse_opt = gre_parse_opt,
.print_opt = gre_print_opt,
+ .print_help = gre_print_help,
};
struct link_util ip6gretap_link_util = {
@@ -398,4 +410,5 @@ struct link_util ip6gretap_link_util = {
.maxattr = IFLA_GRE_MAX,
.parse_opt = gre_parse_opt,
.print_opt = gre_print_opt,
+ .print_help = gre_print_help,
};
diff --git a/ip/link_ip6tnl.c b/ip/link_ip6tnl.c
index 1c7f56c..5ed3d5a 100644
--- a/ip/link_ip6tnl.c
+++ b/ip/link_ip6tnl.c
@@ -29,24 +29,29 @@
#define DEFAULT_TNL_HOP_LIMIT (64)
-static void usage(void) __attribute__((noreturn));
-static void usage(void)
+static void print_usage(FILE *f)
{
- fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
- fprintf(stderr, " [ mode { ip6ip6 | ipip6 | any } ]\n");
- fprintf(stderr, " type ip6tnl [ remote ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ dev PHYS_DEV ] [ encaplimit ELIM ]\n");
- fprintf(stderr ," [ hoplimit HLIM ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
- fprintf(stderr, " [ dscp inherit ] [ fwmark inherit ]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: NAME := STRING\n");
- fprintf(stderr, " ADDR := IPV6_ADDRESS\n");
- fprintf(stderr, " ELIM := { none | 0..255 }(default=%d)\n",
+ fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(f, " [ mode { ip6ip6 | ipip6 | any } ]\n");
+ fprintf(f, " type ip6tnl [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(f, " [ dev PHYS_DEV ] [ encaplimit ELIM ]\n");
+ fprintf(f ," [ hoplimit HLIM ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]\n");
+ fprintf(f, " [ dscp inherit ] [ fwmark inherit ]\n");
+ fprintf(f, "\n");
+ fprintf(f, "Where: NAME := STRING\n");
+ fprintf(f, " ADDR := IPV6_ADDRESS\n");
+ fprintf(f, " ELIM := { none | 0..255 }(default=%d)\n",
IPV6_DEFAULT_TNL_ENCAP_LIMIT);
- fprintf(stderr, " HLIM := 0..255 (default=%d)\n",
+ fprintf(f, " HLIM := 0..255 (default=%d)\n",
DEFAULT_TNL_HOP_LIMIT);
- fprintf(stderr, " TCLASS := { 0x0..0xff | inherit }\n");
- fprintf(stderr, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+ fprintf(f, " TCLASS := { 0x0..0xff | inherit }\n");
+ fprintf(f, " FLOWLABEL := { 0x0..0xfffff | inherit }\n");
+}
+
+static void usage(void) __attribute__((noreturn));
+static void usage(void)
+{
+ print_usage(stderr);
exit(-1);
}
@@ -335,9 +340,16 @@ static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb
fprintf(f, "fwmark inherit ");
}
+static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util ip6tnl_link_util = {
.id = "ip6tnl",
.maxattr = IFLA_IPTUN_MAX,
.parse_opt = ip6tunnel_parse_opt,
.print_opt = ip6tunnel_print_opt,
+ .print_help = ip6tunnel_print_help,
};
diff --git a/ip/link_iptnl.c b/ip/link_iptnl.c
index d5324f8..ea13ce9 100644
--- a/ip/link_iptnl.c
+++ b/ip/link_iptnl.c
@@ -23,22 +23,27 @@
#include "ip_common.h"
#include "tunnel.h"
-static void usage(int sit) __attribute__((noreturn));
-static void usage(int sit)
+static void print_usage(FILE *f, int sit)
{
- fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
- fprintf(stderr, " type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
- fprintf(stderr, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
+ fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(f, " type { ipip | sit } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(f, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
+ fprintf(f, " [ 6rd-prefix ADDR ] [ 6rd-relay_prefix ADDR ] [ 6rd-reset ]\n");
if (sit) {
- fprintf(stderr, " [ mode { ip6ip | ipip | any } ]\n");
- fprintf(stderr, " [ isatap ]\n");
+ fprintf(f, " [ mode { ip6ip | ipip | any } ]\n");
+ fprintf(f, " [ isatap ]\n");
}
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: NAME := STRING\n");
- fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
- fprintf(stderr, " TOS := { NUMBER | inherit }\n");
- fprintf(stderr, " TTL := { 1..255 | inherit }\n");
+ fprintf(f, "\n");
+ fprintf(f, "Where: NAME := STRING\n");
+ fprintf(f, " ADDR := { IP_ADDRESS | any }\n");
+ fprintf(f, " TOS := { NUMBER | inherit }\n");
+ fprintf(f, " TTL := { 1..255 | inherit }\n");
+}
+
+static void usage(int sit) __attribute__((noreturn));
+static void usage(int sit)
+{
+ print_usage(stderr, sit);
exit(-1);
}
@@ -347,11 +352,18 @@ static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[
}
}
+static void iptunnel_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f, strcmp(lu->id, "sit") == 0);
+}
+
struct link_util ipip_link_util = {
.id = "ipip",
.maxattr = IFLA_IPTUN_MAX,
.parse_opt = iptunnel_parse_opt,
.print_opt = iptunnel_print_opt,
+ .print_help = iptunnel_print_help,
};
struct link_util sit_link_util = {
@@ -359,4 +371,5 @@ struct link_util sit_link_util = {
.maxattr = IFLA_IPTUN_MAX,
.parse_opt = iptunnel_parse_opt,
.print_opt = iptunnel_print_opt,
+ .print_help = iptunnel_print_help,
};
diff --git a/ip/link_veth.c b/ip/link_veth.c
index 1196a1b..314216c 100644
--- a/ip/link_veth.c
+++ b/ip/link_veth.c
@@ -17,12 +17,17 @@
#include "utils.h"
#include "ip_common.h"
-static void usage(void)
+static void print_usage(FILE *f)
{
printf("Usage: ip link <options> type veth [peer <options>]\n"
"To get <options> type 'ip link add help'\n");
}
+static void usage(void)
+{
+ print_usage(stderr);
+}
+
static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
struct nlmsghdr *hdr)
{
@@ -79,7 +84,14 @@ static int veth_parse_opt(struct link_util *lu, int argc, char **argv,
return argc - 1 - err;
}
+static void veth_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util veth_link_util = {
.id = "veth",
.parse_opt = veth_parse_opt,
+ .print_help = veth_print_help,
};
diff --git a/ip/link_vti.c b/ip/link_vti.c
index 6274c83..59ac4c4 100644
--- a/ip/link_vti.c
+++ b/ip/link_vti.c
@@ -24,17 +24,22 @@
#include "tunnel.h"
+static void print_usage(FILE *f)
+{
+ fprintf(f, "Usage: ip link { add | set | change | replace | del } NAME\n");
+ fprintf(f, " type { vti } [ remote ADDR ] [ local ADDR ]\n");
+ fprintf(f, " [ [i|o]key KEY ]\n");
+ fprintf(f, " [ dev PHYS_DEV ]\n");
+ fprintf(f, "\n");
+ fprintf(f, "Where: NAME := STRING\n");
+ fprintf(f, " ADDR := { IP_ADDRESS }\n");
+ fprintf(f, " KEY := { DOTTED_QUAD | NUMBER }\n");
+}
+
static void usage(void) __attribute__((noreturn));
static void usage(void)
{
- fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
- fprintf(stderr, " type { vti } [ remote ADDR ] [ local ADDR ]\n");
- fprintf(stderr, " [ [i|o]key KEY ]\n");
- fprintf(stderr, " [ dev PHYS_DEV ]\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "Where: NAME := STRING\n");
- fprintf(stderr, " ADDR := { IP_ADDRESS }\n");
- fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
+ print_usage(stderr);
exit(-1);
}
@@ -240,9 +245,16 @@ static void vti_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
}
}
+static void vti_print_help(struct link_util *lu, int argc, char **argv,
+ FILE *f)
+{
+ print_usage(f);
+}
+
struct link_util vti_link_util = {
.id = "vti",
.maxattr = IFLA_VTI_MAX,
.parse_opt = vti_parse_opt,
.print_opt = vti_print_opt,
+ .print_help = vti_print_help,
};
--
2.1.0
^ permalink raw reply related
* RE: bna alloc_pages() order 2 failure in bnad.c bnad_rxq_refill_page()
From: Shahed Shaikh @ 2014-09-30 5:23 UTC (permalink / raw)
To: Stephen Hemminger, Eric Wheeler; +Cc: netdev, rmody@brocade.com, Rasesh Mody
In-Reply-To: <20140929092833.6c2cb7e9@urahara>
+Rasesh, Maintainer of bna driver.
> -----Original Message-----
> From: netdev-owner@vger.kernel.org [mailto:netdev-
> owner@vger.kernel.org] On Behalf Of Stephen Hemminger
> Sent: Monday, September 29, 2014 9:59 PM
> To: Eric Wheeler
> Cc: netdev; rmody@brocade.com
> Subject: Re: bna alloc_pages() order 2 failure in bnad.c
> bnad_rxq_refill_page()
>
> On Sat, 27 Sep 2014 16:44:22 -0700 (PDT) Eric Wheeler
> <nevdev@lists.ewheeler.net> wrote:
>
> > Hello all,
> >
> > We're using the 10gbe bna card and sometimes we get pages and pages of
> > alloc_pages() failure backtraces like below. (The maintainer
> > rmody@brocade.com does not appear to have an active email at brocade,
> > but cc'ing again just in case.)
> >
> > It looks like bnad_rxq_refill_page() in bnad.c is allocating for the
> > receive queue but fails. We've already tried bumping
> > vm.min_free_kbytes and vm.zone_reclaim_mode but it doesn't appear to
> help.
> >
> > Suggestions?
> >
> > Would it be appropriate to convert alloc_pages() to a mempool
> > implementation?
> >
> > -Eric
>
> Brocade sold the NIC hardware business off to Qlogic.
> I told them to update MAINTAINERS but they haven't submitted a patch yet.
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in the body
> of a message to majordomo@vger.kernel.org More majordomo info at
> http://vger.kernel.org/majordomo-info.html
________________________________
This message and any attached documents contain information from QLogic Corporation or its wholly-owned subsidiaries that may be confidential. If you are not the intended recipient, you may not read, copy, distribute, or use this information. If you have received this transmission in error, please notify the sender immediately by reply e-mail and then delete this message.
^ permalink raw reply
* Re: [PATCH net 1/1 V2] hyperv: Fix a bug in netvsc_start_xmit()
From: David Miller @ 2014-09-30 5:21 UTC (permalink / raw)
To: kys; +Cc: olaf, netdev, jasowang, linux-kernel, apw, devel
In-Reply-To: <1411967803-29233-1-git-send-email-kys@microsoft.com>
From: "K. Y. Srinivasan" <kys@microsoft.com>
Date: Sun, 28 Sep 2014 22:16:43 -0700
> After the packet is successfully sent, we should not touch the skb
> as it may have been freed. This patch is based on the work done by
> Long Li <longli@microsoft.com>.
>
> In this version of the patch I have fixed issues pointed out by David.
> David, please queue this up for stable.
>
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Tested-by: Long Li <longli@microsoft.com>
Applied and queued up for -stable.
^ permalink raw reply
* Re: [net-next PATCH v3 4/4] net: sched: enable per cpu qstats
From: David Miller @ 2014-09-30 5:03 UTC (permalink / raw)
To: john.fastabend; +Cc: xiyou.wangcong, jhs, eric.dumazet, netdev
In-Reply-To: <20140928185423.1976.31409.stgit@nitbit.x32>
From: John Fastabend <john.fastabend@gmail.com>
Date: Sun, 28 Sep 2014 11:54:24 -0700
> After previous patches to simplify qstats the qstats can be
> made per cpu with a packed union in Qdisc struct.
>
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Applied.
^ permalink raw reply
* Re: [net-next PATCH v3 3/4] net: sched: restrict use of qstats qlen
From: David Miller @ 2014-09-30 5:03 UTC (permalink / raw)
To: john.fastabend; +Cc: xiyou.wangcong, jhs, eric.dumazet, netdev
In-Reply-To: <20140928185356.1976.19980.stgit@nitbit.x32>
From: John Fastabend <john.fastabend@gmail.com>
Date: Sun, 28 Sep 2014 11:53:57 -0700
> This removes the use of qstats->qlen variable from the classifiers
> and makes it an explicit argument to gnet_stats_copy_queue().
>
> The qlen represents the qdisc queue length and is packed into
> the qstats at the last moment before passnig to user space. By
> handling it explicitely we avoid, in the percpu stats case, having
> to figure out which per_cpu variable to put it in.
>
> It would probably be best to remove it from qstats completely
> but qstats is a user space ABI and can't be broken. A future
> patch could make an internal only qstats structure that would
> avoid having to allocate an additional u32 variable on the
> Qdisc struct. This would make the qstats struct 128bits instead
> of 128+32.
>
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Applied.
^ permalink raw reply
* Re: [net-next PATCH v3 2/4] net: sched: implement qstat helper routines
From: David Miller @ 2014-09-30 5:02 UTC (permalink / raw)
To: john.fastabend; +Cc: xiyou.wangcong, jhs, eric.dumazet, netdev
In-Reply-To: <20140928185327.1976.62322.stgit@nitbit.x32>
From: John Fastabend <john.fastabend@gmail.com>
Date: Sun, 28 Sep 2014 11:53:29 -0700
> This adds helpers to manipulate qstats logic and replaces locations
> that touch the counters directly. This simplifies future patches
> to push qstats onto per cpu counters.
>
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Applied.
^ permalink raw reply
* Re: [net-next PATCH v3 1/4] net: sched: make bstats per cpu and estimator RCU safe
From: David Miller @ 2014-09-30 5:02 UTC (permalink / raw)
To: john.fastabend; +Cc: xiyou.wangcong, jhs, eric.dumazet, netdev
In-Reply-To: <20140928185255.1976.56179.stgit@nitbit.x32>
From: John Fastabend <john.fastabend@gmail.com>
Date: Sun, 28 Sep 2014 11:52:56 -0700
> From: John Fastabend <john.fastabend@gmail.com>
>
> In order to run qdisc's without locking statistics and estimators
> need to be handled correctly.
>
> To resolve bstats make the statistics per cpu. And because this is
> only needed for qdiscs that are running without locks which is not
> the case for most qdiscs in the near future only create percpu
> stats when qdiscs set the TCQ_F_CPUSTATS flag.
>
> Next because estimators use the bstats to calculate packets per
> second and bytes per second the estimator code paths are updated
> to use the per cpu statistics.
>
> Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 4/5] gre: Set inner protocol in v4 and v6 GRE transmit
From: Simon Horman @ 2014-09-30 5:02 UTC (permalink / raw)
To: Tom Herbert; +Cc: davem, netdev
In-Reply-To: <1411748554-7346-5-git-send-email-therbert@google.com>
On Fri, Sep 26, 2014 at 09:22:33AM -0700, Tom Herbert wrote:
> Call skb_set_inner_protocol to set inner Ethernet protocol to
> protocol being encapsulation by GRE before tunnel_xmit. This is
> needed for GSO if UDP encapsulation (fou) is being done.
>
> Signed-off-by: Tom Herbert <therbert@google.com>
Reviewed-by: Simon Horman <horms@verge.net.au>
> ---
> net/ipv4/ip_gre.c | 2 ++
> net/ipv6/ip6_gre.c | 8 ++++++--
> 2 files changed, 8 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
> index 829aff8b..0485ef1 100644
> --- a/net/ipv4/ip_gre.c
> +++ b/net/ipv4/ip_gre.c
> @@ -241,6 +241,8 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
> /* Push GRE header. */
> gre_build_header(skb, &tpi, tunnel->tun_hlen);
>
> + skb_set_inner_protocol(skb, tpi.proto);
> +
> ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
> }
>
> diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
> index 5f19dfb..9a0a1aa 100644
> --- a/net/ipv6/ip6_gre.c
> +++ b/net/ipv6/ip6_gre.c
> @@ -616,6 +616,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
> int err = -1;
> u8 proto;
> struct sk_buff *new_skb;
> + __be16 protocol;
>
> if (dev->type == ARPHRD_ETHER)
> IPCB(skb)->flags = 0;
> @@ -732,8 +733,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
> ipv6h->daddr = fl6->daddr;
>
> ((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
> - ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ?
> - htons(ETH_P_TEB) : skb->protocol;
> + protocol = (dev->type == ARPHRD_ETHER) ?
> + htons(ETH_P_TEB) : skb->protocol;
> + ((__be16 *)(ipv6h + 1))[1] = protocol;
>
> if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
> __be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4);
> @@ -754,6 +756,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
> }
> }
>
> + skb_set_inner_protocol(skb, protocol);
> +
> ip6tunnel_xmit(skb, dev);
> if (ndst)
> ip6_tnl_dst_store(tunnel, ndst);
> --
> 2.1.0.rc2.206.gedb03e5
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH] bridge: Fix redefined references
From: David Miller @ 2014-09-30 5:01 UTC (permalink / raw)
To: therbert; +Cc: pablo, netdev
In-Reply-To: <1412043404-27494-1-git-send-email-therbert@google.com>
From: Tom Herbert <therbert@google.com>
Date: Mon, 29 Sep 2014 19:16:44 -0700
> Commit 34666d467cbf1e2e3 ("netfilter: bridge: move br_netfilter out of
> the core") cause compiler errors when CONFIG_BRIDGE_NETFILTER is not
> defined.
>
> net/bridge/br_nf_core.c:77:1: error: expected identifier or '(' before '{' token
> net/bridge/br_nf_core.c:88:115: error: redefinition of 'br_nf_core_init'
> In file included from net/bridge/br_nf_core.c:23:0:
> net/bridge/br_private.h:762:59: note: previous definition of 'br_nf_core_init' was here
> net/bridge/br_nf_core.c:93:6: error: redefinition of 'br_nf_core_fini'
> In file included from net/bridge/br_nf_core.c:23:0:
> net/bridge/br_private.h:763:60: note: previous definition of 'br_nf_core_fini' was here
>
> Add #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) around definitions of
> the redefined functions.
>
> Signed-off-by: Tom Herbert <therbert@google.com>
Pablo please either ACK this or provide an alternative fix ASAP.
This bridging build breakage is impacting a lot of people.
^ permalink raw reply
* Re: [PATCH] Fix getsockopt(SO_PEERNAME) buffer size against potential future buffer overflow
From: David Miller @ 2014-09-30 4:59 UTC (permalink / raw)
To: samuel.thibault; +Cc: linux-kernel, netdev, akpm
In-Reply-To: <20140928135545.GA23220@type.youpi.perso.aquilenet.fr>
From: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date: Sun, 28 Sep 2014 15:55:45 +0200
> In net/core/sock.c's sock_getsockopt, the address buffer size is
> hardcoded to 128. It happens that sizeof(struct sockaddr_storage) is
> indeed 128, but that is just luck and would probably not get updated
> whenever sockaddr_storage would grow. This patch makes it simply use
> sockaddr_storage instead.
>
> Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
sockaddr_storage's size is a user exported API and therefore can
never, ever, change.
If you want to change 128 to _K_SS_MAXSIZE or similar, fine.
^ permalink raw reply
* [PATCH v2 net-next 5/5] vxlan: Set inner protocol before transmit
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
In-Reply-To: <1412047353-28502-1-git-send-email-therbert@google.com>
Call skb_set_inner_protocol to set inner Ethernet protocol to
ETH_P_TEB before transmit. This is needed for GSO with UDP tunnels.
Signed-off-by: Tom Herbert <therbert@google.com>
---
drivers/net/vxlan.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 34e102e..2af795d 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1610,6 +1610,8 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
vxh->vx_flags = htonl(VXLAN_FLAGS);
vxh->vx_vni = vni;
+ skb_set_inner_protocol(skb, htons(ETH_P_TEB));
+
udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
ttl, src_port, dst_port);
return 0;
@@ -1652,6 +1654,8 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
vxh->vx_flags = htonl(VXLAN_FLAGS);
vxh->vx_vni = vni;
+ skb_set_inner_protocol(skb, htons(ETH_P_TEB));
+
return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos,
ttl, df, src_port, dst_port, xnet);
}
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH v2 net-next 4/5] gre: Set inner protocol in v4 and v6 GRE transmit
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
In-Reply-To: <1412047353-28502-1-git-send-email-therbert@google.com>
Call skb_set_inner_protocol to set inner Ethernet protocol to
protocol being encapsulation by GRE before tunnel_xmit. This is
needed for GSO if UDP encapsulation (fou) is being done.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/ip_gre.c | 2 ++
net/ipv6/ip6_gre.c | 8 ++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 829aff8b..0485ef1 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -241,6 +241,8 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
/* Push GRE header. */
gre_build_header(skb, &tpi, tunnel->tun_hlen);
+ skb_set_inner_protocol(skb, tpi.proto);
+
ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
}
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 5f19dfb..9a0a1aa 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -616,6 +616,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
int err = -1;
u8 proto;
struct sk_buff *new_skb;
+ __be16 protocol;
if (dev->type == ARPHRD_ETHER)
IPCB(skb)->flags = 0;
@@ -732,8 +733,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
ipv6h->daddr = fl6->daddr;
((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
- ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ?
- htons(ETH_P_TEB) : skb->protocol;
+ protocol = (dev->type == ARPHRD_ETHER) ?
+ htons(ETH_P_TEB) : skb->protocol;
+ ((__be16 *)(ipv6h + 1))[1] = protocol;
if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
__be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4);
@@ -754,6 +756,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
}
}
+ skb_set_inner_protocol(skb, protocol);
+
ip6tunnel_xmit(skb, dev);
if (ndst)
ip6_tnl_dst_store(tunnel, ndst);
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH v2 net-next 3/5] ipip: Set inner IP protocol in ipip
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
In-Reply-To: <1412047353-28502-1-git-send-email-therbert@google.com>
Call skb_set_inner_ipproto to set inner IP protocol to IPPROTO_IPV4
before tunnel_xmit. This is needed if UDP encapsulation (fou) is
being done.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/ipip.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index bfec31d..ea88ab3 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -224,6 +224,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (IS_ERR(skb))
goto out;
+ skb_set_inner_ipproto(skb, IPPROTO_IPIP);
+
ip_tunnel_xmit(skb, dev, tiph, tiph->protocol);
return NETDEV_TX_OK;
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH v2 net-next 2/5] sit: Set inner IP protocol in sit
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
In-Reply-To: <1412047353-28502-1-git-send-email-therbert@google.com>
Call skb_set_inner_ipproto to set inner IP protocol to IPPROTO_IPV6
before tunnel_xmit. This is needed if UDP encapsulation (fou) is
being done.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv6/sit.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index db75809..0d4e274 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -982,6 +982,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error;
}
+ skb_set_inner_ipproto(skb, IPPROTO_IPV6);
+
err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr,
protocol, tos, ttl, df,
!net_eq(tunnel->net, dev_net(dev)));
@@ -1006,6 +1008,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (IS_ERR(skb))
goto out;
+ skb_set_inner_ipproto(skb, IPPROTO_IPIP);
+
ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP);
return NETDEV_TX_OK;
out:
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH v2 net-next 1/5] udp: Generalize skb_udp_segment
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
In-Reply-To: <1412047353-28502-1-git-send-email-therbert@google.com>
skb_udp_segment is the function called from udp4_ufo_fragment to
segment a UDP tunnel packet. This function currently assumes
segmentation is transparent Ethernet bridging (i.e. VXLAN
encapsulation). This patch generalizes the function to
operate on either Ethertype or IP protocol.
The inner_protocol field must be set to the protocol of the inner
header. This can now be either an Ethertype or an IP protocol
(in a union). A new flag in the skbuff indicates which type is
effective. skb_set_inner_protocol and skb_set_inner_ipproto
helper functions were added to set the inner_protocol. These
functions are called from the point where the tunnel encapsulation
is occuring.
When skb_udp_tunnel_segment is called, the function to segment the
inner packet is selected based on the inner IP or Ethertype. In the
case of an IP protocol encapsulation, the function is derived from
inet[6]_offloads. In the case of Ethertype, skb->protocol is
set to the inner_protocol and skb_mac_gso_segment is called. (GRE
currently does this, but it might be possible to lookup the protocol
in offload_base and call the appropriate segmenation function
directly).
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/linux/skbuff.h | 26 +++++++++++++++++++++++--
include/net/udp.h | 3 ++-
net/ipv4/udp_offload.c | 51 +++++++++++++++++++++++++++++++++++++++++++++-----
net/ipv6/udp_offload.c | 2 +-
4 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 262efdb..49bc464 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -596,7 +596,8 @@ struct sk_buff {
__u8 ndisc_nodetype:2;
#endif
__u8 ipvs_property:1;
- /* 5 or 7 bit hole */
+ __u8 inner_protocol_type:1;
+ /* 4 or 6 bit hole */
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
@@ -632,7 +633,11 @@ struct sk_buff {
__u32 reserved_tailroom;
};
- __be16 inner_protocol;
+ union {
+ __be16 inner_protocol;
+ __u8 inner_ipproto;
+ };
+
__u16 inner_transport_header;
__u16 inner_network_header;
__u16 inner_mac_header;
@@ -1737,6 +1742,23 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
skb->tail += len;
}
+#define ENCAP_TYPE_ETHER 0
+#define ENCAP_TYPE_IPPROTO 1
+
+static inline void skb_set_inner_protocol(struct sk_buff *skb,
+ __be16 protocol)
+{
+ skb->inner_protocol = protocol;
+ skb->inner_protocol_type = ENCAP_TYPE_ETHER;
+}
+
+static inline void skb_set_inner_ipproto(struct sk_buff *skb,
+ __u8 ipproto)
+{
+ skb->inner_ipproto = ipproto;
+ skb->inner_protocol_type = ENCAP_TYPE_IPPROTO;
+}
+
static inline void skb_reset_inner_headers(struct sk_buff *skb)
{
skb->inner_mac_header = skb->mac_header;
diff --git a/include/net/udp.h b/include/net/udp.h
index 16f4e80..07f9b70 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -239,7 +239,8 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
int udp_disconnect(struct sock *sk, int flags);
unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait);
struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
- netdev_features_t features);
+ netdev_features_t features,
+ bool is_ipv6);
int udp_lib_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 19ebe6a..8c35f2c 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -25,8 +25,11 @@ struct udp_offload_priv {
struct udp_offload_priv __rcu *next;
};
-struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
- netdev_features_t features)
+static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ netdev_features_t features,
+ struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb,
+ netdev_features_t features),
+ __be16 new_protocol)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
u16 mac_offset = skb->mac_header;
@@ -48,7 +51,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb_inner_network_offset(skb));
skb->mac_len = skb_inner_network_offset(skb);
- skb->protocol = htons(ETH_P_TEB);
+ skb->protocol = new_protocol;
need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
if (need_csum)
@@ -56,7 +59,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
/* segment inner packet. */
enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
- segs = skb_mac_gso_segment(skb, enc_features);
+ segs = gso_inner_segment(skb, enc_features);
if (IS_ERR_OR_NULL(segs)) {
skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
mac_len);
@@ -101,6 +104,44 @@ out:
return segs;
}
+struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
+ netdev_features_t features,
+ bool is_ipv6)
+{
+ __be16 protocol = skb->protocol;
+ const struct net_offload **offloads;
+ const struct net_offload *ops;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb,
+ netdev_features_t features);
+
+ rcu_read_lock();
+
+ switch (skb->inner_protocol_type) {
+ case ENCAP_TYPE_ETHER:
+ protocol = skb->inner_protocol;
+ gso_inner_segment = skb_mac_gso_segment;
+ break;
+ case ENCAP_TYPE_IPPROTO:
+ offloads = is_ipv6 ? inet6_offloads : inet_offloads;
+ ops = rcu_dereference(offloads[skb->inner_ipproto]);
+ if (!ops || !ops->callbacks.gso_segment)
+ goto out_unlock;
+ gso_inner_segment = ops->callbacks.gso_segment;
+ break;
+ default:
+ goto out_unlock;
+ }
+
+ segs = __skb_udp_tunnel_segment(skb, features, gso_inner_segment,
+ protocol);
+
+out_unlock:
+ rcu_read_unlock();
+
+ return segs;
+}
+
static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -113,7 +154,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
if (skb->encapsulation &&
(skb_shinfo(skb)->gso_type &
(SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) {
- segs = skb_udp_tunnel_segment(skb, features);
+ segs = skb_udp_tunnel_segment(skb, features, false);
goto out;
}
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 212ebfc..8f96988 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -58,7 +58,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
if (skb->encapsulation && skb_shinfo(skb)->gso_type &
(SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))
- segs = skb_udp_tunnel_segment(skb, features);
+ segs = skb_udp_tunnel_segment(skb, features, true);
else {
const struct ipv6hdr *ipv6h;
struct udphdr *uh;
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
This patch set generalizes the UDP tunnel segmentation functions so
that they can work with various protocol encapsulations. The primary
change is to set the inner_protocol field in the skbuff when creating
the encapsulated packet, and then in skb_udp_tunnel_segment this data
is used to determine the function for segmenting the encapsulated
packet. The inner_protocol field is overloaded to take either an
Ethertype or IP protocol.
The inner_protocol is set on transmit using skb_set_inner_ipproto or
skb_set_inner_protocol functions. VXLAN and IP tunnels (for fou GSO)
were modified to call these.
Notes:
- GSO for GRE/UDP where GRE checksum is enabled does not work.
Handling this will require some special case code.
- Software GSO now supports many varieties of encapsulation with
SKB_GSO_UDP_TUNNEL{_CSUM}. We still need a mechanism to query
for device support of particular combinations (I intend to
add ndo_gso_check for that).
- MPLS seems to be the only previous user of inner_protocol. I don't
believe these patches can affect that. For supporting GSO with
MPLS over UDP, the inner_protocol should be set using the
helper functions in this patch.
- GSO for L2TP/UDP should also be straightforward now.
v2:
- Respin for Eric's restructuring of skbuff.
Tested GRE, IPIP, and SIT over fou as well as VLXAN. This was
done using 200 TCP_STREAMs in netperf.
GRE
IPv4, FOU, UDP checksum enabled
TCP_STREAM TSO enabled on tun interface
14.04% TX CPU utilization
13.17% RX CPU utilization
9211 Mbps
TCP_STREAM TSO disabled on tun interface
27.82% TX CPU utilization
25.41% RX CPU utilization
9336 Mbps
IPv4, FOU, UDP checksum disabled
TCP_STREAM TSO enabled on tun interface
13.14% TX CPU utilization
23.18% RX CPU utilization
9277 Mbps
TCP_STREAM TSO disabled on tun interface
30.00% TX CPU utilization
31.28% RX CPU utilization
9327 Mbps
IPIP
FOU, UDP checksum enabled
TCP_STREAM TSO enabled on tun interface
15.28% TX CPU utilization
13.92% RX CPU utilization
9342 Mbps
TCP_STREAM TSO disabled on tun interface
27.82% TX CPU utilization
25.41% RX CPU utilization
9336 Mbps
FOU, UDP checksum disabled
TCP_STREAM TSO enabled on tun interface
15.08% TX CPU utilization
24.64% RX CPU utilization
9226 Mbps
TCP_STREAM TSO disabled on tun interface
30.00% TX CPU utilization
31.28% RX CPU utilization
9327 Mbps
SIT
FOU, UDP checksum enabled
TCP_STREAM TSO enabled on tun interface
14.47% TX CPU utilization
14.58% RX CPU utilization
9106 Mbps
TCP_STREAM TSO disabled on tun interface
31.82% TX CPU utilization
30.82% RX CPU utilization
9204 Mbps
FOU, UDP checksum disabled
TCP_STREAM TSO enabled on tun interface
15.70% TX CPU utilization
27.93% RX CPU utilization
9097 Mbps
TCP_STREAM TSO disabled on tun interface
33.48% TX CPU utilization
37.36% RX CPU utilization
9197 Mbps
VXLAN
TCP_STREAM TSO enabled on tun interface
16.42% TX CPU utilization
23.66% RX CPU utilization
9081 Mbps
TCP_STREAM TSO disabled on tun interface
30.32% TX CPU utilization
30.55% RX CPU utilization
9185 Mbps
Baseline (no encp, TSO and LRO enabled)
TCP_STREAM
11.85% TX CPU utilization
15.13% RX CPU utilization
9452 Mbps
Tom Herbert (5):
udp: Generalize skb_udp_segment
sit: Set inner IP protocol in sit
ipip: Set inner IP protocol in ipip
gre: Set inner protocol in v4 and v6 GRE transmit
vxlan: Set inner protocol before transmit
drivers/net/vxlan.c | 4 ++++
include/linux/skbuff.h | 26 +++++++++++++++++++++++--
include/net/udp.h | 3 ++-
net/ipv4/ip_gre.c | 2 ++
net/ipv4/ipip.c | 2 ++
net/ipv4/udp_offload.c | 51 +++++++++++++++++++++++++++++++++++++++++++++-----
net/ipv6/ip6_gre.c | 8 ++++++--
net/ipv6/sit.c | 4 ++++
net/ipv6/udp_offload.c | 2 +-
9 files changed, 91 insertions(+), 11 deletions(-)
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply
* Re: linux-next: build failure after merge of the net-next tree
From: Stephen Rothwell @ 2014-09-30 3:22 UTC (permalink / raw)
To: David Miller, netdev; +Cc: linux-next, linux-kernel, Pablo Neira Ayuso
In-Reply-To: <20140930131354.792033e7@canb.auug.org.au>
[-- Attachment #1: Type: text/plain, Size: 2689 bytes --]
Hi all,
On Tue, 30 Sep 2014 13:13:54 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> Hi all,
>
> After merging the net-next tree, today's linux-next build (powerpc
> ppc64_defconfig) failed like this:
>
> net/bridge/br_nf_core.c:77:1: error: expected identifier or '(' before '{' token
> {
> ^
> net/bridge/br_nf_core.c:88:12: error: redefinition of 'br_nf_core_init'
> int __init br_nf_core_init(void)
> ^
> In file included from net/bridge/br_nf_core.c:23:0:
> net/bridge/br_private.h:762:19: note: previous definition of 'br_nf_core_init' was here
> static inline int br_nf_core_init(void) { return 0; }
> ^
> net/bridge/br_nf_core.c:93:6: error: redefinition of 'br_nf_core_fini'
> void br_nf_core_fini(void)
> ^
> In file included from net/bridge/br_nf_core.c:23:0:
> net/bridge/br_private.h:763:20: note: previous definition of 'br_nf_core_fini' was here
> static inline void br_nf_core_fini(void) {}
> ^
>
> Caused by commit 34666d467cbf ("netfilter: bridge: move br_netfilter
> out of the core"). This build has CONFIG_BRIDGE_NETFILTER not set ...
>
> I have applied the following patch for today:
>
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Tue, 30 Sep 2014 13:09:09 +1000
> Subject: [PATCH] netfilter: bridge: don't build br_nf_core unless necessary
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> net/bridge/Makefile | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/net/bridge/Makefile b/net/bridge/Makefile
> index 5e3eac5dc8b9..eb653a225397 100644
> --- a/net/bridge/Makefile
> +++ b/net/bridge/Makefile
> @@ -6,12 +6,11 @@ obj-$(CONFIG_BRIDGE) += bridge.o
>
> bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
> br_ioctl.o br_stp.o br_stp_bpdu.o \
> - br_stp_if.o br_stp_timer.o br_netlink.o \
> - br_nf_core.o
> + br_stp_if.o br_stp_timer.o br_netlink.o
>
> bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
>
> -obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
> +obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o br_nf_core.o
>
> bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
>
> --
> 2.1.1
After whish I get this from an x86_64 allmodconfig build:
ERROR: "br_nf_core_fini" [net/bridge/bridge.ko] undefined!
ERROR: "br_netfilter_rtable_init" [net/bridge/bridge.ko] undefined!
ERROR: "br_nf_core_init" [net/bridge/bridge.ko] undefined!
So I gave up :-(
I have used the net-next tree from next-20140926 for today.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* linux-next: build failure after merge of the net-next tree
From: Stephen Rothwell @ 2014-09-30 3:13 UTC (permalink / raw)
To: David Miller, netdev; +Cc: linux-next, linux-kernel, Pablo Neira Ayuso
[-- Attachment #1: Type: text/plain, Size: 2143 bytes --]
Hi all,
After merging the net-next tree, today's linux-next build (powerpc
ppc64_defconfig) failed like this:
net/bridge/br_nf_core.c:77:1: error: expected identifier or '(' before '{' token
{
^
net/bridge/br_nf_core.c:88:12: error: redefinition of 'br_nf_core_init'
int __init br_nf_core_init(void)
^
In file included from net/bridge/br_nf_core.c:23:0:
net/bridge/br_private.h:762:19: note: previous definition of 'br_nf_core_init' was here
static inline int br_nf_core_init(void) { return 0; }
^
net/bridge/br_nf_core.c:93:6: error: redefinition of 'br_nf_core_fini'
void br_nf_core_fini(void)
^
In file included from net/bridge/br_nf_core.c:23:0:
net/bridge/br_private.h:763:20: note: previous definition of 'br_nf_core_fini' was here
static inline void br_nf_core_fini(void) {}
^
Caused by commit 34666d467cbf ("netfilter: bridge: move br_netfilter
out of the core"). This build has CONFIG_BRIDGE_NETFILTER not set ...
I have applied the following patch for today:
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 30 Sep 2014 13:09:09 +1000
Subject: [PATCH] netfilter: bridge: don't build br_nf_core unless necessary
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
net/bridge/Makefile | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/bridge/Makefile b/net/bridge/Makefile
index 5e3eac5dc8b9..eb653a225397 100644
--- a/net/bridge/Makefile
+++ b/net/bridge/Makefile
@@ -6,12 +6,11 @@ obj-$(CONFIG_BRIDGE) += bridge.o
bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
br_ioctl.o br_stp.o br_stp_bpdu.o \
- br_stp_if.o br_stp_timer.o br_netlink.o \
- br_nf_core.o
+ br_stp_if.o br_stp_timer.o br_netlink.o
bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
-obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
+obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o br_nf_core.o
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o
--
2.1.1
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply related
* linux-next: manual merge of the net-next tree with the net tree
From: Stephen Rothwell @ 2014-09-30 2:54 UTC (permalink / raw)
To: David Miller, netdev; +Cc: linux-next, linux-kernel, Pablo Neira Ayuso
[-- Attachment #1: Type: text/plain, Size: 1181 bytes --]
Hi all,
Today's linux-next merge of the net-next tree got a conflict in
net/netfilter/nfnetlink.c between commit cbb8125eb40b ("netfilter:
nfnetlink: deliver netlink errors on batch completion") from the net
tree and commit fc04733a1a71 ("netfilter: nfnetlink: use original
skbuff when committing/aborting") from the net-next tree.
I fixed it up (see below) and can carry the fix as necessary (no action
is required).
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
diff --cc net/netfilter/nfnetlink.c
index f37f0716a9fc,f77d3f7f22b5..000000000000
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@@ -380,8 -333,7 +380,8 @@@ replay
* original skb.
*/
if (err == -EAGAIN) {
+ nfnl_err_reset(&err_list);
- ss->abort(skb);
+ ss->abort(oskb);
nfnl_unlock(subsys_id);
kfree_skb(nskb);
goto replay;
@@@ -418,11 -357,10 +418,11 @@@ ack
}
done:
if (success && done)
- ss->commit(skb);
+ ss->commit(oskb);
else
- ss->abort(skb);
+ ss->abort(oskb);
+ nfnl_err_deliver(&err_list, oskb);
nfnl_unlock(subsys_id);
kfree_skb(nskb);
}
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox