* [PATCH 1/5] Bluetooth: Remove double free of SKB pointer in L2CAP
From: Marcel Holtmann @ 2010-01-30 14:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <cover.1264859950.git.marcel@holtmann.org>
From: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Trivial fix for double free of SKB pointer with kfree_skb to
make code simplier and cleaner. Remove unused variable err.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com>
Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/l2cap.c | 11 ++++-------
1 files changed, 4 insertions(+), 7 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 1120cf1..8acc19e 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3518,7 +3518,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
struct l2cap_pinfo *pi;
u16 control, len;
u8 tx_seq;
- int err;
sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
if (!sk) {
@@ -3570,13 +3569,11 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
goto drop;
if (__is_iframe(control))
- err = l2cap_data_channel_iframe(sk, control, skb);
+ l2cap_data_channel_iframe(sk, control, skb);
else
- err = l2cap_data_channel_sframe(sk, control, skb);
+ l2cap_data_channel_sframe(sk, control, skb);
- if (!err)
- goto done;
- break;
+ goto done;
case L2CAP_MODE_STREAMING:
control = get_unaligned_le16(skb->data);
@@ -3602,7 +3599,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
else
pi->expected_tx_seq = tx_seq + 1;
- err = l2cap_sar_reassembly_sdu(sk, skb, control);
+ l2cap_sar_reassembly_sdu(sk, skb, control);
goto done;
--
1.6.6
^ permalink raw reply related
* Pull request: bluetooth-2.6 2010-01-30
From: Marcel Holtmann @ 2010-01-30 14:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Hi Dave,
this includes two L2CAP fixes. One for a memory leak and another one for
a double free.
For Bluetooth PCMCIA cards a BUG_ON caused a few issues when we have
shared interrupts. So revert this and put a clear comment in the source
that this is what we actually want.
The Bluetooth HID fix for raw reports has a big diffstat, but the logical
change is small. By accident we send the reports on the interrupt channel
and the original test device seems to cope with that. Devices that follow
the specification more closer will break. The right thing is to use the
control channel. This is similar to what is done via USB.
And by request from Luis, include the driver for Atheros Bluetooth chipset
AR3011. It is a new driver and by itself small and self contained. If you
feel that it should not be merged, then let me know and I redo this
patchset.
Regards
Marcel
Please pull from
git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6.git master
This will update the following files:
drivers/bluetooth/Kconfig | 13 +++-
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/ath3k.c | 187 +++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/bluecard_cs.c | 4 +-
drivers/bluetooth/bt3c_cs.c | 4 +-
drivers/bluetooth/btuart_cs.c | 4 +-
drivers/bluetooth/dtl1_cs.c | 4 +-
net/bluetooth/hidp/core.c | 70 ++++++++-------
net/bluetooth/l2cap.c | 14 ++--
9 files changed, 254 insertions(+), 47 deletions(-)
create mode 100644 drivers/bluetooth/ath3k.c
through these ChangeSets:
Andrei Emeltchenko (2):
Bluetooth: Remove double free of SKB pointer in L2CAP
Bluetooth: Fix memory leak in L2CAP
Bastien Nocera (1):
Bluetooth: Use the control channel for raw HID reports
Mike Frysinger (1):
Bluetooth: Redo checks in IRQ handler for shared IRQ support
Vikram Kandukuri (1):
Bluetooth: Add DFU driver for Atheros Bluetooth chipset AR3011
^ permalink raw reply
* Re: [PATCH] tcp: fix ICMP-RTO war
From: Damian Lukowski @ 2010-01-30 13:56 UTC (permalink / raw)
To: Denys Fedoryshchenko; +Cc: Ilpo Järvinen, Netdev, David Miller
In-Reply-To: <201001301535.43469.denys@visp.net.lb>
> On Friday 29 January 2010 23:45:35 Damian Lukowski wrote:
>> Denys Fedoryshchenko schrieb:
>> > On Friday 29 January 2010 14:13:18 Damian Lukowski wrote:
>> >> Denys Fedoryshchenko schrieb:
>> >>> On Wednesday 27 January 2010 14:36:18 you wrote:
>> >>>> Unless they are for a different connection? We might have to print
>> sk
>> >>>> (%p) in all those printouts to be sure which maps to which. If a
>> peer
>> >>>> becomes unreachable, it may well have multiple connections open
>> (this
>> >>>> was a proxy, iirc?).
>> >>>
>> >>> Ok i will try to do that today.
>> >>>
>> >>> Most probably different connections, on this proxy i have 10-15k
>> >>> established connections at peak time.
>> >
>> > http://www.nuclearcat.com/files/report1.txt
>> > http://www.nuclearcat.com/files/report2.txt
>> >
>> > Here with %p and sk.
>>
>> Ok, thanks for testing.
>> So it is ec0f3440 causing the trouble. Are there still objections
>> on the lower bound check in __tcp_set_rto()? Well, I will submit
>> an updated patch and you can make comments there.
> There is another sk also. I can catch for more time - there is many
> different
> pointers to sk appearing (but not in same time, it is rare case even
> with my thousands of connections).
Hmm, I shouldn't have posted so late yesterday, as I forgot to CC
you and the others when submitting the patch, amongst the grammar error. :/
Can you test the patch in
http://marc.info/?l=linux-netdev&m=126480336216898
please?
Damian
^ permalink raw reply
* Re: [PATCH] tcp: fix ICMP-RTO war
From: Denys Fedoryshchenko @ 2010-01-30 13:35 UTC (permalink / raw)
To: Damian Lukowski; +Cc: Ilpo Järvinen, Netdev, David Miller
In-Reply-To: <4B6356FF.7070504@tvk.rwth-aachen.de>
On Friday 29 January 2010 23:45:35 Damian Lukowski wrote:
> Denys Fedoryshchenko schrieb:
> > On Friday 29 January 2010 14:13:18 Damian Lukowski wrote:
> >> Denys Fedoryshchenko schrieb:
> >>> On Wednesday 27 January 2010 14:36:18 you wrote:
> >>>> Unless they are for a different connection? We might have to print sk
> >>>> (%p) in all those printouts to be sure which maps to which. If a peer
> >>>> becomes unreachable, it may well have multiple connections open (this
> >>>> was a proxy, iirc?).
> >>>
> >>> Ok i will try to do that today.
> >>>
> >>> Most probably different connections, on this proxy i have 10-15k
> >>> established connections at peak time.
> >
> > http://www.nuclearcat.com/files/report1.txt
> > http://www.nuclearcat.com/files/report2.txt
> >
> > Here with %p and sk.
>
> Ok, thanks for testing.
> So it is ec0f3440 causing the trouble. Are there still objections
> on the lower bound check in __tcp_set_rto()? Well, I will submit
> an updated patch and you can make comments there.
There is another sk also. I can catch for more time - there is many different
pointers to sk appearing (but not in same time, it is rare case even with my
thousands of connections).
^ permalink raw reply
* Re: [2.6.33-rc5] kernel BUG at include/net/netns/generic.h:41!
From: Luca Tettamanti @ 2010-01-30 13:23 UTC (permalink / raw)
To: Alexey Dobriyan; +Cc: linux-kernel, netdev, Eric Dumazet
In-Reply-To: <b6fcc0a1001290217l4edb0a0btbafa0c26b6f14ad5@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1116 bytes --]
On Fri, Jan 29, 2010 at 11:17 AM, Alexey Dobriyan <adobriyan@gmail.com> wrote:
> On Fri, Jan 29, 2010 at 11:48 AM, Luca Tettamanti <kronos.it@gmail.com> wrote:
>> with recent kernels I'm seeing this BUG - triggered by racoon - at boot:
>>
>> NET: Registered protocol family 15
>> ------------[ cut here ]------------
>> kernel BUG at /home/kronos/src/linux-2.6.git/include/net/netns/generic.h:43!
>> invalid opcode: 0000 [#1] PREEMPT SMP
>> last sysfs file: /sys/kernel/uevent_seqnum
>> CPU 1
>> Pid: 1941, comm: racoon Not tainted 2.6.33-rc5-00271-gbe8cde8-dirty #238 F3Sa /F3Sa
>> RIP: 0010:[<ffffffffa03035be>] [<ffffffffa03035be>] pfkey_create+0x36/0x18b [af_key]
>
> Does it triggers after succesfull boot if you do
>
> rmmod af_key; modprobe af_key
>
> a couple of times?
No. Neither does:
racoon stop; rmmod af_key; racoon start
It might be connected to the fact that I'm using Debian startpar to
run multiple init scripts in parallel.
I'm now testing Eric's patch and I haven't seen the BUG after a few reboots.
> Post .config, just in case.
Attached.
Luca
[-- Attachment #2: config.gz --]
[-- Type: application/x-gzip, Size: 16150 bytes --]
^ permalink raw reply
* [PATCH net-next-2.6] can: mcp251x: Move to threaded interrupts instead of workqueues.
From: Christian Pellegrin @ 2010-01-30 13:19 UTC (permalink / raw)
To: socketcan-core, netdev; +Cc: Christian Pellegrin
This patch addresses concerns about efficiency of handling incoming packets. Handling of
interrupts is done in a threaded interrupt handler which has a smaller latency than workqueues.
This change needed a rework of the locking scheme that was much simplified. Some other
(more or less longstanding) bugs are fixed: utilization of just half of the RX buffers,
useless wait for interrupt on open, more reliable reset sequence. The MERR interrupt is
not used anymore: it overloads the CPU in bus-off state without any additional information.
Signed-off-by: Christian Pellegrin <chripell@fsfe.org>
---
drivers/net/can/mcp251x.c | 353 +++++++++++++++++++++++----------------------
1 files changed, 179 insertions(+), 174 deletions(-)
diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c
index bbe186b..03a20c3 100644
--- a/drivers/net/can/mcp251x.c
+++ b/drivers/net/can/mcp251x.c
@@ -180,6 +180,14 @@
#define RXBEID0_OFF 4
#define RXBDLC_OFF 5
#define RXBDAT_OFF 6
+#define RXFSIDH(n) ((n) * 4)
+#define RXFSIDL(n) ((n) * 4 + 1)
+#define RXFEID8(n) ((n) * 4 + 2)
+#define RXFEID0(n) ((n) * 4 + 3)
+#define RXMSIDH(n) ((n) * 4 + 0x20)
+#define RXMSIDL(n) ((n) * 4 + 0x21)
+#define RXMEID8(n) ((n) * 4 + 0x22)
+#define RXMEID0(n) ((n) * 4 + 0x23)
#define GET_BYTE(val, byte) \
(((val) >> ((byte) * 8)) & 0xff)
@@ -219,7 +227,8 @@ struct mcp251x_priv {
struct net_device *net;
struct spi_device *spi;
- struct mutex spi_lock; /* SPI buffer lock */
+ struct mutex mcp_lock; /* SPI device lock */
+
u8 *spi_tx_buf;
u8 *spi_rx_buf;
dma_addr_t spi_tx_dma;
@@ -227,11 +236,11 @@ struct mcp251x_priv {
struct sk_buff *tx_skb;
int tx_len;
+
struct workqueue_struct *wq;
struct work_struct tx_work;
- struct work_struct irq_work;
- struct completion awake;
- int wake;
+ struct work_struct restart_work;
+
int force_quit;
int after_suspend;
#define AFTER_SUSPEND_UP 1
@@ -241,11 +250,17 @@ struct mcp251x_priv {
int restart_tx;
};
+/* Delayed work functions */
+static irqreturn_t mcp251x_can_ist(int irq, void *dev_id);
+static void mcp251x_restart_work_handler(struct work_struct *ws);
+static void mcp251x_tx_work_handler(struct work_struct *ws);
+
static void mcp251x_clean(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
- net->stats.tx_errors++;
+ if (priv->tx_skb || priv->tx_len)
+ net->stats.tx_errors++;
if (priv->tx_skb)
dev_kfree_skb(priv->tx_skb);
if (priv->tx_len)
@@ -300,16 +315,12 @@ static u8 mcp251x_read_reg(struct spi_device *spi, uint8_t reg)
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
u8 val = 0;
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[0] = INSTRUCTION_READ;
priv->spi_tx_buf[1] = reg;
mcp251x_spi_trans(spi, 3);
val = priv->spi_rx_buf[2];
- mutex_unlock(&priv->spi_lock);
-
return val;
}
@@ -317,15 +328,11 @@ static void mcp251x_write_reg(struct spi_device *spi, u8 reg, uint8_t val)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[0] = INSTRUCTION_WRITE;
priv->spi_tx_buf[1] = reg;
priv->spi_tx_buf[2] = val;
mcp251x_spi_trans(spi, 3);
-
- mutex_unlock(&priv->spi_lock);
}
static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
@@ -333,16 +340,12 @@ static void mcp251x_write_bits(struct spi_device *spi, u8 reg,
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[0] = INSTRUCTION_BIT_MODIFY;
priv->spi_tx_buf[1] = reg;
priv->spi_tx_buf[2] = mask;
priv->spi_tx_buf[3] = val;
mcp251x_spi_trans(spi, 4);
-
- mutex_unlock(&priv->spi_lock);
}
static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
@@ -358,10 +361,8 @@ static void mcp251x_hw_tx_frame(struct spi_device *spi, u8 *buf,
mcp251x_write_reg(spi, TXBCTRL(tx_buf_idx) + i,
buf[i]);
} else {
- mutex_lock(&priv->spi_lock);
memcpy(priv->spi_tx_buf, buf, TXBDAT_OFF + len);
mcp251x_spi_trans(spi, TXBDAT_OFF + len);
- mutex_unlock(&priv->spi_lock);
}
}
@@ -408,13 +409,9 @@ static void mcp251x_hw_rx_frame(struct spi_device *spi, u8 *buf,
for (; i < (RXBDAT_OFF + len); i++)
buf[i] = mcp251x_read_reg(spi, RXBCTRL(buf_idx) + i);
} else {
- mutex_lock(&priv->spi_lock);
-
priv->spi_tx_buf[RXBCTRL_OFF] = INSTRUCTION_READ_RXB(buf_idx);
mcp251x_spi_trans(spi, SPI_TRANSFER_BUF_LEN);
memcpy(buf, priv->spi_rx_buf, SPI_TRANSFER_BUF_LEN);
-
- mutex_unlock(&priv->spi_lock);
}
}
@@ -467,21 +464,6 @@ static void mcp251x_hw_sleep(struct spi_device *spi)
mcp251x_write_reg(spi, CANCTRL, CANCTRL_REQOP_SLEEP);
}
-static void mcp251x_hw_wakeup(struct spi_device *spi)
-{
- struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
-
- priv->wake = 1;
-
- /* Can only wake up by generating a wake-up interrupt. */
- mcp251x_write_bits(spi, CANINTE, CANINTE_WAKIE, CANINTE_WAKIE);
- mcp251x_write_bits(spi, CANINTF, CANINTF_WAKIF, CANINTF_WAKIF);
-
- /* Wait until the device is awake */
- if (!wait_for_completion_timeout(&priv->awake, HZ))
- dev_err(&spi->dev, "MCP251x didn't wake-up\n");
-}
-
static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
struct net_device *net)
{
@@ -490,7 +472,15 @@ static netdev_tx_t mcp251x_hard_start_xmit(struct sk_buff *skb,
if (priv->tx_skb || priv->tx_len) {
dev_warn(&spi->dev, "hard_xmit called while tx busy\n");
- netif_stop_queue(net);
+ /*
+ * Note: we may see this message on recovery from bus-off.
+ * This happens because can_restart calls netif_carrier_on
+ * before the restart worqueue has had a chance to run and
+ * clear the TX logic.
+ * This message is worrisome (because it points out
+ * something wrong with locking logic) if seen when
+ * there is no bus-off recovery going on.
+ */
return NETDEV_TX_BUSY;
}
@@ -516,7 +506,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
priv->restart_tx = 1;
if (priv->can.restart_ms == 0)
priv->after_suspend = AFTER_SUSPEND_RESTART;
- queue_work(priv->wq, &priv->irq_work);
+ queue_work(priv->wq, &priv->restart_work);
break;
default:
return -EOPNOTSUPP;
@@ -525,7 +515,7 @@ static int mcp251x_do_set_mode(struct net_device *net, enum can_mode mode)
return 0;
}
-static void mcp251x_set_normal_mode(struct spi_device *spi)
+static int mcp251x_set_normal_mode(struct spi_device *spi)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
unsigned long timeout;
@@ -533,8 +523,7 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
/* Enable interrupts */
mcp251x_write_reg(spi, CANINTE,
CANINTE_ERRIE | CANINTE_TX2IE | CANINTE_TX1IE |
- CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE |
- CANINTF_MERRF);
+ CANINTE_TX0IE | CANINTE_RX1IE | CANINTE_RX0IE);
if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) {
/* Put device into loopback mode */
@@ -555,11 +544,12 @@ static void mcp251x_set_normal_mode(struct spi_device *spi)
if (time_after(jiffies, timeout)) {
dev_err(&spi->dev, "MCP251x didn't"
" enter in normal mode\n");
- return;
+ return -EBUSY;
}
}
}
priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ return 0;
}
static int mcp251x_do_set_bittiming(struct net_device *net)
@@ -590,33 +580,39 @@ static int mcp251x_setup(struct net_device *net, struct mcp251x_priv *priv,
{
mcp251x_do_set_bittiming(net);
- /* Enable RX0->RX1 buffer roll over and disable filters */
- mcp251x_write_bits(spi, RXBCTRL(0),
- RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1,
- RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);
- mcp251x_write_bits(spi, RXBCTRL(1),
- RXBCTRL_RXM0 | RXBCTRL_RXM1,
- RXBCTRL_RXM0 | RXBCTRL_RXM1);
+ mcp251x_write_reg(spi, RXBCTRL(0),
+ RXBCTRL_BUKT | RXBCTRL_RXM0 | RXBCTRL_RXM1);
+ mcp251x_write_reg(spi, RXBCTRL(1),
+ RXBCTRL_RXM0 | RXBCTRL_RXM1);
return 0;
}
-static void mcp251x_hw_reset(struct spi_device *spi)
+static int mcp251x_hw_reset(struct spi_device *spi)
{
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
int ret;
-
- mutex_lock(&priv->spi_lock);
+ unsigned long timeout;
priv->spi_tx_buf[0] = INSTRUCTION_RESET;
-
ret = spi_write(spi, priv->spi_tx_buf, 1);
-
- mutex_unlock(&priv->spi_lock);
-
- if (ret)
+ if (ret) {
dev_err(&spi->dev, "reset failed: ret = %d\n", ret);
+ return -EIO;
+ }
+
/* Wait for reset to finish */
+ timeout = jiffies + HZ;
mdelay(10);
+ while ((mcp251x_read_reg(spi, CANSTAT) & CANCTRL_REQOP_MASK)
+ != CANCTRL_REQOP_CONF) {
+ schedule();
+ if (time_after(jiffies, timeout)) {
+ dev_err(&spi->dev, "MCP251x didn't"
+ " enter in conf mode after reset\n");
+ return -EBUSY;
+ }
+ }
+ return 0;
}
static int mcp251x_hw_probe(struct spi_device *spi)
@@ -640,16 +636,17 @@ static int mcp251x_hw_probe(struct spi_device *spi)
return (st1 == 0x80 && st2 == 0x07) ? 1 : 0;
}
-static irqreturn_t mcp251x_can_isr(int irq, void *dev_id)
+static void mcp251x_open_clean(struct net_device *net)
{
- struct net_device *net = (struct net_device *)dev_id;
struct mcp251x_priv *priv = netdev_priv(net);
+ struct spi_device *spi = priv->spi;
+ struct mcp251x_platform_data *pdata = spi->dev.platform_data;
- /* Schedule bottom half */
- if (!work_pending(&priv->irq_work))
- queue_work(priv->wq, &priv->irq_work);
-
- return IRQ_HANDLED;
+ free_irq(spi->irq, priv);
+ mcp251x_hw_sleep(spi);
+ if (pdata->transceiver_enable)
+ pdata->transceiver_enable(0);
+ close_candev(net);
}
static int mcp251x_open(struct net_device *net)
@@ -665,6 +662,7 @@ static int mcp251x_open(struct net_device *net)
return ret;
}
+ mutex_lock(&priv->mcp_lock);
if (pdata->transceiver_enable)
pdata->transceiver_enable(1);
@@ -672,31 +670,40 @@ static int mcp251x_open(struct net_device *net)
priv->tx_skb = NULL;
priv->tx_len = 0;
- ret = request_irq(spi->irq, mcp251x_can_isr,
- IRQF_TRIGGER_FALLING, DEVICE_NAME, net);
+ ret = request_threaded_irq(spi->irq, NULL, mcp251x_can_ist,
+ IRQF_TRIGGER_FALLING, DEVICE_NAME, priv);
if (ret) {
dev_err(&spi->dev, "failed to acquire irq %d\n", spi->irq);
if (pdata->transceiver_enable)
pdata->transceiver_enable(0);
close_candev(net);
- return ret;
+ goto open_unlock;
}
- mcp251x_hw_wakeup(spi);
- mcp251x_hw_reset(spi);
+ priv->wq = create_freezeable_workqueue("mcp251x_wq");
+ INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
+ INIT_WORK(&priv->restart_work, mcp251x_restart_work_handler);
+
+ ret = mcp251x_hw_reset(spi);
+ if (ret) {
+ mcp251x_open_clean(net);
+ goto open_unlock;
+ }
ret = mcp251x_setup(net, priv, spi);
if (ret) {
- free_irq(spi->irq, net);
- mcp251x_hw_sleep(spi);
- if (pdata->transceiver_enable)
- pdata->transceiver_enable(0);
- close_candev(net);
- return ret;
+ mcp251x_open_clean(net);
+ goto open_unlock;
+ }
+ ret = mcp251x_set_normal_mode(spi);
+ if (ret) {
+ mcp251x_open_clean(net);
+ goto open_unlock;
}
- mcp251x_set_normal_mode(spi);
netif_wake_queue(net);
- return 0;
+open_unlock:
+ mutex_unlock(&priv->mcp_lock);
+ return ret;
}
static int mcp251x_stop(struct net_device *net)
@@ -707,17 +714,19 @@ static int mcp251x_stop(struct net_device *net)
close_candev(net);
+ priv->force_quit = 1;
+ free_irq(spi->irq, priv);
+ destroy_workqueue(priv->wq);
+ priv->wq = NULL;
+
+ mutex_lock(&priv->mcp_lock);
+
/* Disable and clear pending interrupts */
mcp251x_write_reg(spi, CANINTE, 0x00);
mcp251x_write_reg(spi, CANINTF, 0x00);
- priv->force_quit = 1;
- free_irq(spi->irq, net);
- flush_workqueue(priv->wq);
-
mcp251x_write_reg(spi, TXBCTRL(0), 0);
- if (priv->tx_skb || priv->tx_len)
- mcp251x_clean(net);
+ mcp251x_clean(net);
mcp251x_hw_sleep(spi);
@@ -726,9 +735,27 @@ static int mcp251x_stop(struct net_device *net)
priv->can.state = CAN_STATE_STOPPED;
+ mutex_unlock(&priv->mcp_lock);
+
return 0;
}
+static void mcp251x_error_skb(struct net_device *net, int can_id, int data1)
+{
+ struct sk_buff *skb;
+ struct can_frame *frame;
+
+ skb = alloc_can_err_skb(net, &frame);
+ if (skb) {
+ frame->can_id = can_id;
+ frame->data[1] = data1;
+ netif_rx(skb);
+ } else {
+ dev_info(&net->dev,
+ "cannot allocate error skb\n");
+ }
+}
+
static void mcp251x_tx_work_handler(struct work_struct *ws)
{
struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
@@ -737,14 +764,16 @@ static void mcp251x_tx_work_handler(struct work_struct *ws)
struct net_device *net = priv->net;
struct can_frame *frame;
+ mutex_lock(&priv->mcp_lock);
if (priv->tx_skb) {
frame = (struct can_frame *)priv->tx_skb->data;
if (priv->can.state == CAN_STATE_BUS_OFF) {
mcp251x_clean(net);
netif_wake_queue(net);
- return;
+ goto restart_work_unlock;
}
+
if (frame->can_dlc > CAN_FRAME_MAX_DATA_LEN)
frame->can_dlc = CAN_FRAME_MAX_DATA_LEN;
mcp251x_hw_tx(spi, frame, 0);
@@ -752,18 +781,18 @@ static void mcp251x_tx_work_handler(struct work_struct *ws)
can_put_echo_skb(priv->tx_skb, net, 0);
priv->tx_skb = NULL;
}
+restart_work_unlock:
+ mutex_unlock(&priv->mcp_lock);
}
-static void mcp251x_irq_work_handler(struct work_struct *ws)
+static void mcp251x_restart_work_handler(struct work_struct *ws)
{
struct mcp251x_priv *priv = container_of(ws, struct mcp251x_priv,
- irq_work);
+ restart_work);
struct spi_device *spi = priv->spi;
struct net_device *net = priv->net;
- u8 txbnctrl;
- u8 intf;
- enum can_state new_state;
+ mutex_lock(&priv->mcp_lock);
if (priv->after_suspend) {
mdelay(10);
mcp251x_hw_reset(spi);
@@ -772,45 +801,54 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
mcp251x_set_normal_mode(spi);
} else if (priv->after_suspend & AFTER_SUSPEND_UP) {
netif_device_attach(net);
- /* Clean since we lost tx buffer */
- if (priv->tx_skb || priv->tx_len) {
- mcp251x_clean(net);
- netif_wake_queue(net);
- }
+ mcp251x_clean(net);
mcp251x_set_normal_mode(spi);
+ netif_wake_queue(net);
} else {
mcp251x_hw_sleep(spi);
}
priv->after_suspend = 0;
+ priv->force_quit = 0;
}
- if (priv->can.restart_ms == 0 && priv->can.state == CAN_STATE_BUS_OFF)
- return;
+ if (priv->restart_tx) {
+ priv->restart_tx = 0;
+ mcp251x_write_reg(spi, TXBCTRL(0), 0);
+ mcp251x_clean(net);
+ netif_wake_queue(net);
+ mcp251x_error_skb(net, CAN_ERR_RESTARTED, 0);
+ }
+ mutex_unlock(&priv->mcp_lock);
+}
- while (!priv->force_quit && !freezing(current)) {
- u8 eflag = mcp251x_read_reg(spi, EFLG);
- int can_id = 0, data1 = 0;
+static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
+{
+ struct mcp251x_priv *priv = dev_id;
+ struct spi_device *spi = priv->spi;
+ struct net_device *net = priv->net;
- mcp251x_write_reg(spi, EFLG, 0x00);
+ mutex_lock(&priv->mcp_lock);
+ while (!priv->force_quit) {
+ enum can_state new_state;
+ u8 intf = mcp251x_read_reg(spi, CANINTF);
+ u8 eflag;
+ int can_id = 0, data1 = 0;
- if (priv->restart_tx) {
- priv->restart_tx = 0;
- mcp251x_write_reg(spi, TXBCTRL(0), 0);
- if (priv->tx_skb || priv->tx_len)
- mcp251x_clean(net);
- netif_wake_queue(net);
- can_id |= CAN_ERR_RESTARTED;
+ if (intf & CANINTF_RX0IF) {
+ mcp251x_hw_rx(spi, 0);
+ /* Free one buffer ASAP */
+ mcp251x_write_bits(spi, CANINTF, intf & CANINTF_RX0IF,
+ 0x00);
}
- if (priv->wake) {
- /* Wait whilst the device wakes up */
- mdelay(10);
- priv->wake = 0;
- }
+ if (intf & CANINTF_RX1IF)
+ mcp251x_hw_rx(spi, 1);
- intf = mcp251x_read_reg(spi, CANINTF);
mcp251x_write_bits(spi, CANINTF, intf, 0x00);
+ eflag = mcp251x_read_reg(spi, EFLG);
+ mcp251x_write_reg(spi, EFLG, 0x00);
+
/* Update can state */
if (eflag & EFLG_TXBO) {
new_state = CAN_STATE_BUS_OFF;
@@ -851,59 +889,31 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
}
priv->can.state = new_state;
- if ((intf & CANINTF_ERRIF) || (can_id & CAN_ERR_RESTARTED)) {
- struct sk_buff *skb;
- struct can_frame *frame;
-
- /* Create error frame */
- skb = alloc_can_err_skb(net, &frame);
- if (skb) {
- /* Set error frame flags based on bus state */
- frame->can_id = can_id;
- frame->data[1] = data1;
-
- /* Update net stats for overflows */
- if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
- if (eflag & EFLG_RX0OVR)
- net->stats.rx_over_errors++;
- if (eflag & EFLG_RX1OVR)
- net->stats.rx_over_errors++;
- frame->can_id |= CAN_ERR_CRTL;
- frame->data[1] |=
- CAN_ERR_CRTL_RX_OVERFLOW;
- }
-
- netif_rx(skb);
- } else {
- dev_info(&spi->dev,
- "cannot allocate error skb\n");
+ if (intf & CANINTF_ERRIF) {
+ /* Handle overflow counters */
+ if (eflag & (EFLG_RX0OVR | EFLG_RX1OVR)) {
+ if (eflag & EFLG_RX0OVR)
+ net->stats.rx_over_errors++;
+ if (eflag & EFLG_RX1OVR)
+ net->stats.rx_over_errors++;
+ can_id |= CAN_ERR_CRTL;
+ data1 |= CAN_ERR_CRTL_RX_OVERFLOW;
}
+ mcp251x_error_skb(net, can_id, data1);
}
if (priv->can.state == CAN_STATE_BUS_OFF) {
if (priv->can.restart_ms == 0) {
+ priv->force_quit = 1;
can_bus_off(net);
mcp251x_hw_sleep(spi);
- return;
+ break;
}
}
if (intf == 0)
break;
- if (intf & CANINTF_WAKIF)
- complete(&priv->awake);
-
- if (intf & CANINTF_MERRF) {
- /* If there are pending Tx buffers, restart queue */
- txbnctrl = mcp251x_read_reg(spi, TXBCTRL(0));
- if (!(txbnctrl & TXBCTRL_TXREQ)) {
- if (priv->tx_skb || priv->tx_len)
- mcp251x_clean(net);
- netif_wake_queue(net);
- }
- }
-
if (intf & (CANINTF_TX2IF | CANINTF_TX1IF | CANINTF_TX0IF)) {
net->stats.tx_packets++;
net->stats.tx_bytes += priv->tx_len - 1;
@@ -914,12 +924,9 @@ static void mcp251x_irq_work_handler(struct work_struct *ws)
netif_wake_queue(net);
}
- if (intf & CANINTF_RX0IF)
- mcp251x_hw_rx(spi, 0);
-
- if (intf & CANINTF_RX1IF)
- mcp251x_hw_rx(spi, 1);
}
+ mutex_unlock(&priv->mcp_lock);
+ return IRQ_HANDLED;
}
static const struct net_device_ops mcp251x_netdev_ops = {
@@ -961,7 +968,7 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
dev_set_drvdata(&spi->dev, priv);
priv->spi = spi;
- mutex_init(&priv->spi_lock);
+ mutex_init(&priv->mcp_lock);
/* If requested, allocate DMA buffers */
if (mcp251x_enable_dma) {
@@ -1010,18 +1017,12 @@ static int __devinit mcp251x_can_probe(struct spi_device *spi)
SET_NETDEV_DEV(net, &spi->dev);
- priv->wq = create_freezeable_workqueue("mcp251x_wq");
-
- INIT_WORK(&priv->tx_work, mcp251x_tx_work_handler);
- INIT_WORK(&priv->irq_work, mcp251x_irq_work_handler);
-
- init_completion(&priv->awake);
-
/* Configure the SPI bus */
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
spi_setup(spi);
+ /* Here is OK to not lock the MCP, no one knows about it yet */
if (!mcp251x_hw_probe(spi)) {
dev_info(&spi->dev, "Probe failed\n");
goto error_probe;
@@ -1064,10 +1065,6 @@ static int __devexit mcp251x_can_remove(struct spi_device *spi)
unregister_candev(net);
free_candev(net);
- priv->force_quit = 1;
- flush_workqueue(priv->wq);
- destroy_workqueue(priv->wq);
-
if (mcp251x_enable_dma) {
dma_free_coherent(&spi->dev, PAGE_SIZE,
priv->spi_tx_buf, priv->spi_tx_dma);
@@ -1089,6 +1086,12 @@ static int mcp251x_can_suspend(struct spi_device *spi, pm_message_t state)
struct mcp251x_priv *priv = dev_get_drvdata(&spi->dev);
struct net_device *net = priv->net;
+ priv->force_quit = 1;
+ disable_irq(spi->irq);
+ /*
+ * Note: at this point neither IST nor workqueues are running.
+ * open/stop cannot be called anyway so locking is not needed
+ */
if (netif_running(net)) {
netif_device_detach(net);
@@ -1115,16 +1118,18 @@ static int mcp251x_can_resume(struct spi_device *spi)
if (priv->after_suspend & AFTER_SUSPEND_POWER) {
pdata->power_enable(1);
- queue_work(priv->wq, &priv->irq_work);
+ queue_work(priv->wq, &priv->restart_work);
} else {
if (priv->after_suspend & AFTER_SUSPEND_UP) {
if (pdata->transceiver_enable)
pdata->transceiver_enable(1);
- queue_work(priv->wq, &priv->irq_work);
+ queue_work(priv->wq, &priv->restart_work);
} else {
priv->after_suspend = 0;
}
}
+ priv->force_quit = 0;
+ enable_irq(spi->irq);
return 0;
}
#else
--
1.5.6.5
^ permalink raw reply related
* [PATCH] af_key: fix netns ops ordering on module load/unload
From: Alexey Dobriyan @ 2010-01-30 12:53 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Luca Tettamanti, linux-kernel, netdev, David Miller
In-Reply-To: <1264782806.3184.42.camel@edumazet-laptop>
On Fri, Jan 29, 2010 at 05:33:26PM +0100, Eric Dumazet wrote:
> @@ -3807,21 +3807,24 @@ static int __init ipsec_pfkey_init(void)
> if (err != 0)
> goto out;
>
> - err = sock_register(&pfkey_family_ops);
> - if (err != 0)
> - goto out_unregister_key_proto;
> err = xfrm_register_km(&pfkeyv2_mgr);
> if (err != 0)
> - goto out_sock_unregister;
> + goto out_unregister_key_proto;
> +
> err = register_pernet_subsys(&pfkey_net_ops);
> if (err != 0)
> goto out_xfrm_unregister_km;
> +
> + err = sock_register(&pfkey_family_ops);
> + if (err != 0)
> + goto out_unregister_pernet;
> out:
> return err;
> +
> +out_unregister_pernet:
> + unregister_pernet_subsys(&pfkey_net_ops);
> out_xfrm_unregister_km:
> xfrm_unregister_km(&pfkeyv2_mgr);
> -out_sock_unregister:
> - sock_unregister(PF_KEY);
> out_unregister_key_proto:
> proto_unregister(&key_proto);
> goto out;
ACK analysis, except this is not enough.
Here is patch which survived netns start/stop/modprobe/rmmod cycles.
Alexey, who still doesn't get why bug reproduces so easily for bug reporter.
Luca, please confirm.
Audit for the rest of the modules pending.
[PATCH] af_key: fix netns ops ordering on module load/unload
1. After sock_register() returns, it's possible to create sockets,
even if module still not initialized fully (blame generic module code
for that!)
2. Consequently, pfkey_create() can be called with pfkey_net_id still not
initialized which will BUG_ON in net_generic():
kernel BUG at include/net/netns/generic.h:43!
3. During netns shutdown, netns ops should be unregistered after
key manager unregistered because key manager calls can be triggered
from xfrm_user module:
general protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC
pfkey_broadcast+0x111/0x210 [af_key]
pfkey_send_notify+0x16a/0x300 [af_key]
km_state_notify+0x41/0x70
xfrm_flush_sa+0x75/0x90 [xfrm_user]
4. Unregister netns ops after socket ops just in case and for symmetry.
Reported by Luca Tettamanti.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---
net/key/af_key.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3794,9 +3794,9 @@ static struct pernet_operations pfkey_net_ops = {
static void __exit ipsec_pfkey_exit(void)
{
- unregister_pernet_subsys(&pfkey_net_ops);
xfrm_unregister_km(&pfkeyv2_mgr);
sock_unregister(PF_KEY);
+ unregister_pernet_subsys(&pfkey_net_ops);
proto_unregister(&key_proto);
}
@@ -3807,21 +3807,22 @@ static int __init ipsec_pfkey_init(void)
if (err != 0)
goto out;
- err = sock_register(&pfkey_family_ops);
+ err = register_pernet_subsys(&pfkey_net_ops);
if (err != 0)
goto out_unregister_key_proto;
+ err = sock_register(&pfkey_family_ops);
+ if (err != 0)
+ goto out_unregister_pernet;
err = xfrm_register_km(&pfkeyv2_mgr);
if (err != 0)
goto out_sock_unregister;
- err = register_pernet_subsys(&pfkey_net_ops);
- if (err != 0)
- goto out_xfrm_unregister_km;
out:
return err;
-out_xfrm_unregister_km:
- xfrm_unregister_km(&pfkeyv2_mgr);
+
out_sock_unregister:
sock_unregister(PF_KEY);
+out_unregister_pernet:
+ unregister_pernet_subsys(&pfkey_net_ops);
out_unregister_key_proto:
proto_unregister(&key_proto);
goto out;
^ permalink raw reply
* [iproute2 PATCH 4/4] ip: Update man page to indicate current options.
From: Jeff Kirsher @ 2010-01-30 10:43 UTC (permalink / raw)
To: davem, shemminger; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130104226.26719.21774.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
man/man8/ip.8 | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/man/man8/ip.8 b/man/man8/ip.8
index 273be92..dd323a4 100644
--- a/man/man8/ip.8
+++ b/man/man8/ip.8
@@ -53,7 +53,21 @@ ip \- show / manipulate routing, devices, policy routing and tunnels
.IR MTU " |"
.br
.B netns
-.IR PID " }"
+.IR PID " |"
+.br
+.B alias
+.IR NAME " |"
+.br
+.B vf
+.IR NUM " ["
+.B mac
+.IR LLADDR " ] ["
+.B vlan
+.IR VLANID " ] ["
+.B rate
+.IR TXRATE " ]"
+.BR " }"
+
.ti -8
.B ip link show
@@ -826,7 +840,9 @@ display and change the state of devices.
.TP
.BI dev " NAME " (default)
.I NAME
-specifies network device to operate on.
+specifies network device to operate on. When configuring SR-IOV Virtual Fuction
+(VF) devices, this keyword should specify the associated Physical Function (PF)
+device.
.TP
.BR up " and " down
@@ -888,7 +904,42 @@ the interface is
.TP
.BI netns " PID"
move the device to the network namespace associated with the process
-.IR "PID" .
+.IR "PID".
+
+.TP
+.BI alias " NAME"
+give the device a symbolic name for easy reference.
+
+.TP
+.BI vf " NUM"
+specify a Virtual Function device to be configured. The associated PF device
+must be specified using the
+.B dev
+parameter.
+
+.in +8
+.BI mac " LLADDRESS"
+- change the station address for the specified VF. The
+.B vf
+parameter must be specified.
+
+.sp
+.BI vlan " VLANID"
+- change the assigned VLAN for the specified VF. When specified, all traffic
+sent from the VF will be tagged with the specified VLAN ID. Incoming traffic
+will be filtered for the specified VLAN ID, and will have all VLAN tags
+stripped before being passed to the VF. Setting this parameter to 0 disables
+VLAN tagging and filtering. The
+.B vf
+parameter must be specified.
+
+.sp
+.BI rate " TXRATE"
+- change the allowed transmit bandwidth, in Mbps, for the specified VF.
+Setting this parameter to 0 disables rate limiting. The
+.B vf
+parameter must be specified.
+.in -8
.PP
.B Warning:
^ permalink raw reply related
* [iproute2 PATCH 3/4] ip: Add support for SR-IOV function link parameters
From: Jeff Kirsher @ 2010-01-30 10:43 UTC (permalink / raw)
To: davem, shemminger; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130104226.26719.21774.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Add support to 'ip' for setting and showing SR-IOV virtual function link
parameters.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
ip/ipaddress.c | 23 +++++++++++++++++++++++
ip/iplink.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 91c7b1b..d39a675 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -331,6 +331,29 @@ int print_linkinfo(const struct sockaddr_nl *who,
);
}
}
+ if (do_link && tb[IFLA_VFINFO] && tb[IFLA_NUM_VF]) {
+ SPRINT_BUF(b1);
+ struct rtattr *rta = tb[IFLA_VFINFO];
+ struct ifla_vf_info *ivi;
+ int i;
+ for (i = 0; i < *(int *)RTA_DATA(tb[IFLA_NUM_VF]); i++) {
+ if (rta->rta_type != IFLA_VFINFO) {
+ fprintf(stderr, "BUG: rta type is %d\n", rta->rta_type);
+ break;
+ }
+ ivi = RTA_DATA(rta);
+ fprintf(fp, "\n vf %d: MAC %s",
+ ivi->vf,
+ ll_addr_n2a((unsigned char *)&ivi->mac,
+ ETH_ALEN, 0, b1, sizeof(b1)));
+ if (ivi->vlan)
+ fprintf(fp, ", vlan %d", ivi->vlan);
+ if (ivi->tx_rate)
+ fprintf(fp, ", tx rate %d (Mbps_",
+ ivi->tx_rate);
+ rta = (struct rtattr *)((char *)rta + RTA_ALIGN(rta->rta_len));
+ }
+ }
fprintf(fp, "\n");
fflush(fp);
return 0;
diff --git a/ip/iplink.c b/ip/iplink.c
index 32cce24..88a5606 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -68,6 +68,9 @@ void iplink_usage(void)
fprintf(stderr, " [ mtu MTU ]\n");
fprintf(stderr, " [ netns PID ]\n");
fprintf(stderr, " [ alias NAME ]\n");
+ fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
+ fprintf(stderr, " [ vlan VLANID ] ] \n");
+ fprintf(stderr, " [ rate TXRATE ] ] \n");
fprintf(stderr, " ip link show [ DEVICE ]\n");
if (iplink_have_newlink()) {
@@ -181,6 +184,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
int qlen = -1;
int mtu = -1;
int netns = -1;
+ int vf = -1;
ret = argc;
@@ -278,6 +282,41 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
req->i.ifi_flags |= IFF_NOARP;
} else
return on_off("noarp");
+ } else if (strcmp(*argv, "vf") == 0) {
+ NEXT_ARG();
+ if (get_integer(&vf, *argv, 0)) {
+ invarg("Invalid \"vf\" value\n", *argv);
+ }
+ } else if (matches(*argv, "mac") == 0) {
+ struct ifla_vf_mac ivm;
+ NEXT_ARG();
+ if (vf < 0)
+ missarg("vf");
+ ivm.vf = vf;
+ len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
+ if (len < 0)
+ return -1;
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
+ } else if (matches(*argv, "vlan") == 0) {
+ struct ifla_vf_vlan ivv;
+ NEXT_ARG();
+ if (vf < 0)
+ missarg("vf");
+ if (get_integer(&ivv.vlan, *argv, 0)) {
+ invarg("Invalid \"vlan\" value\n", *argv);
+ }
+ ivv.vf = vf;
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
+ } else if (matches(*argv, "rate") == 0) {
+ struct ifla_vf_tx_rate ivt;
+ NEXT_ARG();
+ if (vf < 0)
+ missarg("vf");
+ if (get_unsigned(&ivt.rate, *argv, 0)) {
+ invarg("Invalid \"rate\" value\n", *argv);
+ }
+ ivt.vf = vf;
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
#ifdef IFF_DYNAMIC
} else if (matches(*argv, "dynamic") == 0) {
NEXT_ARG();
^ permalink raw reply related
* [iproute2 PATCH 2/4] libnetlink: Modify parser to track the first duplicated attributes
From: Jeff Kirsher @ 2010-01-30 10:42 UTC (permalink / raw)
To: davem, shemminger; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130104226.26719.21774.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Modify the parser to keep track of the first of any duplicated attributes,
instead of the last. This is required for VF configuration reporting, where
multiple attributes of the same type are added sequentially.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
lib/libnetlink.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 4ba6019..cfeb894 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -644,7 +644,7 @@ int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
{
memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
while (RTA_OK(rta, len)) {
- if (rta->rta_type <= max)
+ if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
tb[rta->rta_type] = rta;
rta = RTA_NEXT(rta,len);
}
^ permalink raw reply related
* [iproute2 PATCH 1/4] if_link: Sync header with kernel to get new VF configuration defines.
From: Jeff Kirsher @ 2010-01-30 10:42 UTC (permalink / raw)
To: davem, shemminger; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
From: Williams, Mitch A <mitch.a.williams@intel.com>
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/linux/if_link.h | 32 ++++++++++++++++++++++++++++++++
1 files changed, 32 insertions(+), 0 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index cbefb3b..65e9a17 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -78,6 +78,11 @@ enum {
#define IFLA_LINKINFO IFLA_LINKINFO
IFLA_NET_NS_PID,
IFLA_IFALIAS,
+ IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */
+ IFLA_VF_MAC, /* Hardware queue specific attributes */
+ IFLA_VF_VLAN,
+ IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */
+ IFLA_VFINFO,
__IFLA_MAX
};
@@ -194,4 +199,31 @@ enum macvlan_mode {
MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
};
+/* subqueue managment section */
+
+struct ifla_vf_mac
+{
+ __u32 vf;
+ __u8 mac[32]; /* MAX_ADDR_LEN */
+};
+
+struct ifla_vf_vlan
+{
+ __u32 vf;
+ __s32 vlan; /* 0 - 4095, -1 disables VLAN filter */
+};
+
+struct ifla_vf_tx_rate
+{
+ __u32 vf;
+ __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+};
+
+struct ifla_vf_info
+{
+ __u32 vf;
+ __u8 mac[32];
+ __s32 vlan;
+ __u32 tx_rate;
+};
#endif /* _LINUX_IF_LINK_H */
^ permalink raw reply related
* [net-next-2.6 PATCH 5/5] igb: support for VF configuration tools
From: Jeff Kirsher @ 2010-01-30 10:40 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130103842.26633.73429.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Add support to the igb driver for VF configuration mechanisms through the
PF interface.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/igb/e1000_82575.h | 3 +
drivers/net/igb/e1000_regs.h | 1
drivers/net/igb/igb.h | 2 +
drivers/net/igb/igb_main.c | 122 ++++++++++++++++++++++++++++++++++++++---
4 files changed, 119 insertions(+), 9 deletions(-)
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h
index d51c992..bb53083 100644
--- a/drivers/net/igb/e1000_82575.h
+++ b/drivers/net/igb/e1000_82575.h
@@ -219,6 +219,9 @@ struct e1000_adv_tx_context_desc {
#define E1000_VLVF_LVLAN 0x00100000
#define E1000_VLVF_VLANID_ENABLE 0x80000000
+#define E1000_VMVIR_VLANA_DEFAULT 0x40000000 /* Always use default VLAN */
+#define E1000_VMVIR_VLANA_NEVER 0x80000000 /* Never insert VLAN tag */
+
#define E1000_IOVCTL 0x05BBC
#define E1000_IOVCTL_REUSE_VFQ 0x00000001
diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h
index dd4e6ff..abb7333 100644
--- a/drivers/net/igb/e1000_regs.h
+++ b/drivers/net/igb/e1000_regs.h
@@ -310,6 +310,7 @@
#define E1000_VMOLR(_n) (0x05AD0 + (4 * (_n)))
#define E1000_VLVF(_n) (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
* Filter - RW */
+#define E1000_VMVIR(_n) (0x03700 + (4 * (_n)))
#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
#define rd32(reg) (readl(hw->hw_addr + reg))
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index b1c1eb8..92ca69c 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -75,11 +75,13 @@ struct vf_data_storage {
u16 vlans_enabled;
u32 flags;
unsigned long last_nack;
+ u16 pf_vlan; /* When set, guest VLAN config not allowed. */
};
#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */
#define IGB_VF_FLAG_UNI_PROMISC 0x00000002 /* VF has unicast promisc */
#define IGB_VF_FLAG_MULTI_PROMISC 0x00000004 /* VF has multicast promisc */
+#define IGB_VF_FLAG_PF_SET_MAC 0x00000008 /* PF has set MAC address */
/* RX descriptor control thresholds.
* PTHRESH - MAC will consider prefetch if it has fewer than this number of
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 0a064ce..09309aa 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -133,6 +133,11 @@ static void igb_msg_task(struct igb_adapter *);
static void igb_vmm_control(struct igb_adapter *);
static int igb_set_vf_mac(struct igb_adapter *, int, unsigned char *);
static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
+static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac);
+static int igb_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan);
+static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate);
+static int igb_ndo_get_vf_config(struct net_device *netdev, int vf,
+ struct ifla_vf_info *ivi);
#ifdef CONFIG_PM
static int igb_suspend(struct pci_dev *, pm_message_t);
@@ -1362,6 +1367,10 @@ static const struct net_device_ops igb_netdev_ops = {
.ndo_vlan_rx_register = igb_vlan_rx_register,
.ndo_vlan_rx_add_vid = igb_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = igb_vlan_rx_kill_vid,
+ .ndo_set_vf_mac = igb_ndo_set_vf_mac,
+ .ndo_set_vf_vlan = igb_ndo_set_vf_vlan,
+ .ndo_set_vf_tx_rate = igb_ndo_set_vf_bw,
+ .ndo_get_vf_config = igb_ndo_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = igb_netpoll,
#endif
@@ -2489,7 +2498,8 @@ static void igb_rlpml_set(struct igb_adapter *adapter)
wr32(E1000_RLPML, max_frame_size);
}
-static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn)
+static inline void igb_set_vmolr(struct igb_adapter *adapter,
+ int vfn, bool aupe)
{
struct e1000_hw *hw = &adapter->hw;
u32 vmolr;
@@ -2502,8 +2512,11 @@ static inline void igb_set_vmolr(struct igb_adapter *adapter, int vfn)
return;
vmolr = rd32(E1000_VMOLR(vfn));
- vmolr |= E1000_VMOLR_AUPE | /* Accept untagged packets */
- E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+ vmolr |= E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+ if (aupe)
+ vmolr |= E1000_VMOLR_AUPE; /* Accept untagged packets */
+ else
+ vmolr &= ~(E1000_VMOLR_AUPE); /* Tagged packets ONLY */
/* clear all bits that might not be set */
vmolr &= ~(E1000_VMOLR_BAM | E1000_VMOLR_RSSE);
@@ -2574,7 +2587,7 @@ void igb_configure_rx_ring(struct igb_adapter *adapter,
wr32(E1000_SRRCTL(reg_idx), srrctl);
/* set filtering for VMDQ pools */
- igb_set_vmolr(adapter, reg_idx & 0x7);
+ igb_set_vmolr(adapter, reg_idx & 0x7, true);
/* enable receive descriptor fetching */
rxdctl = rd32(E1000_RXDCTL(reg_idx));
@@ -4506,6 +4519,54 @@ static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
return -1;
}
+static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (vid)
+ wr32(E1000_VMVIR(vf), (vid | E1000_VMVIR_VLANA_DEFAULT));
+ else
+ wr32(E1000_VMVIR(vf), 0);
+}
+
+static int igb_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan)
+{
+ int err = 0;
+ struct igb_adapter *adapter = netdev_priv(netdev);
+
+ if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095))
+ return -EINVAL;
+
+ if (vlan) {
+ err = igb_vlvf_set(adapter, vlan, true, vf);
+ if (err)
+ goto out;
+ igb_set_vmvir(adapter, vlan, vf);
+ igb_set_vmolr(adapter, vf, false);
+ adapter->vf_data[vf].pf_vlan = vlan;
+ dev_info(&adapter->pdev->dev,
+ "Setting VLAN %d on VF %d\n", vlan, vf);
+ if (test_bit(__IGB_DOWN, &adapter->state)) {
+ dev_warn(&adapter->pdev->dev,
+ "The VF VLAN has been set,"
+ " but the PF device is not up.\n");
+ dev_warn(&adapter->pdev->dev,
+ "Bring the PF device up before"
+ " attempting to use the VF device.\n");
+ }
+ } else if (adapter->vf_data[vf].pf_vlan) {
+ err = igb_vlvf_set(adapter, adapter->vf_data[vf].pf_vlan,
+ false, vf);
+ if (err)
+ goto out;
+ igb_set_vmvir(adapter, vlan, vf);
+ igb_set_vmolr(adapter, vf, true);
+ adapter->vf_data[vf].pf_vlan = 0;
+ }
+out:
+ return err;
+}
+
static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
{
int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
@@ -4516,15 +4577,20 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
{
- /* clear all flags */
- adapter->vf_data[vf].flags = 0;
+ /* clear flags */
+ adapter->vf_data[vf].flags &= ~(IGB_VF_FLAG_PF_SET_MAC);
adapter->vf_data[vf].last_nack = jiffies;
/* reset offloads to defaults */
- igb_set_vmolr(adapter, vf);
+ igb_set_vmolr(adapter, vf, true);
/* reset vlans for device */
igb_clear_vf_vfta(adapter, vf);
+ if (adapter->vf_data[vf].pf_vlan)
+ igb_ndo_set_vf_vlan(adapter->netdev,
+ adapter->vf_data[vf].pf_vlan, vf);
+ else
+ igb_clear_vf_vfta(adapter, vf);
/* reset multicast table array for vf */
adapter->vf_data[vf].num_vf_mc_hashes = 0;
@@ -4538,7 +4604,8 @@ static void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
/* generate a new mac address as we were hotplug removed/added */
- random_ether_addr(vf_mac);
+ if (!(adapter->vf_data[vf].flags & IGB_VF_FLAG_PF_SET_MAC))
+ random_ether_addr(vf_mac);
/* process remaining reset events */
igb_vf_reset(adapter, vf);
@@ -4651,7 +4718,10 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
break;
case E1000_VF_SET_VLAN:
- retval = igb_set_vf_vlan(adapter, msgbuf, vf);
+ if (adapter->vf_data[vf].pf_vlan)
+ retval = -1;
+ else
+ retval = igb_set_vf_vlan(adapter, msgbuf, vf);
break;
default:
dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
@@ -6013,6 +6083,40 @@ static int igb_set_vf_mac(struct igb_adapter *adapter,
return 0;
}
+static int igb_ndo_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ if (!is_valid_ether_addr(mac) || (vf >= adapter->vfs_allocated_count))
+ return -EINVAL;
+ adapter->vf_data[vf].flags |= IGB_VF_FLAG_PF_SET_MAC;
+ dev_info(&adapter->pdev->dev, "setting MAC %pM on VF %d\n", mac, vf);
+ if (test_bit(__IGB_DOWN, &adapter->state)) {
+ dev_warn(&adapter->pdev->dev, "The VF MAC address has been set,"
+ " but the PF device is not up.\n");
+ dev_warn(&adapter->pdev->dev, "Bring the PF device up before"
+ " attempting to use the VF device.\n");
+ }
+ return igb_set_vf_mac(adapter, vf, mac);
+}
+
+static int igb_ndo_set_vf_bw(struct net_device *netdev, int vf, int tx_rate)
+{
+ return -EOPNOTSUPP;
+}
+
+static int igb_ndo_get_vf_config(struct net_device *netdev,
+ int vf, struct ifla_vf_info *ivi)
+{
+ struct igb_adapter *adapter = netdev_priv(netdev);
+ if (vf >= adapter->vfs_allocated_count)
+ return -EINVAL;
+ ivi->vf = vf;
+ memcpy(&ivi->mac, adapter->vf_data[vf].vf_mac_addresses, ETH_ALEN);
+ ivi->tx_rate = 0;
+ ivi->vlan = adapter->vf_data[vf].pf_vlan;
+ return 0;
+}
+
static void igb_vmm_control(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
^ permalink raw reply related
* [net-next-2.6 PATCH 4/5] rtnetlink: Add VF config code to rtnetlink
From: Jeff Kirsher @ 2010-01-30 10:40 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130103842.26633.73429.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Add code to allow rtnetlink clients to query and set VF information through
the PF driver.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
net/core/rtnetlink.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 62f3878..10c0d87 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -35,6 +35,7 @@
#include <linux/security.h>
#include <linux/mutex.h>
#include <linux/if_addr.h>
+#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -580,6 +581,15 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->tx_compressed = b->tx_compressed;
};
+static inline int rtnl_vfinfo_size(const struct net_device *dev)
+{
+ if (dev->dev.parent && dev_is_pci(dev->dev.parent))
+ return dev_num_vf(dev->dev.parent) *
+ sizeof(struct ifla_vf_info);
+ else
+ return 0;
+}
+
static inline size_t if_nlmsg_size(const struct net_device *dev)
{
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
@@ -597,6 +607,8 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)
+ nla_total_size(4) /* IFLA_MASTER */
+ nla_total_size(1) /* IFLA_OPERSTATE */
+ nla_total_size(1) /* IFLA_LINKMODE */
+ + nla_total_size(4) /* IFLA_NUM_VF */
+ + nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */
+ rtnl_link_get_size(dev); /* IFLA_LINKINFO */
}
@@ -665,6 +677,17 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
stats = dev_get_stats(dev);
copy_rtnl_link_stats(nla_data(attr), stats);
+ if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {
+ int i;
+ struct ifla_vf_info ivi;
+
+ NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
+ for (i = 0; i < dev_num_vf(dev->dev.parent); i++) {
+ if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))
+ break;
+ NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi);
+ }
+ }
if (dev->rtnl_link_ops) {
if (rtnl_link_fill(skb, dev) < 0)
goto nla_put_failure;
@@ -725,6 +748,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
[IFLA_LINKINFO] = { .type = NLA_NESTED },
[IFLA_NET_NS_PID] = { .type = NLA_U32 },
[IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 },
+ [IFLA_VF_MAC] = { .type = NLA_BINARY,
+ .len = sizeof(struct ifla_vf_mac) },
+ [IFLA_VF_VLAN] = { .type = NLA_BINARY,
+ .len = sizeof(struct ifla_vf_vlan) },
+ [IFLA_VF_TX_RATE] = { .type = NLA_BINARY,
+ .len = sizeof(struct ifla_vf_tx_rate) },
};
EXPORT_SYMBOL(ifla_policy);
@@ -898,6 +927,42 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
write_unlock_bh(&dev_base_lock);
}
+ if (tb[IFLA_VF_MAC]) {
+ struct ifla_vf_mac *ivm;
+ ivm = nla_data(tb[IFLA_VF_MAC]);
+ write_lock_bh(&dev_base_lock);
+ if (ops->ndo_set_vf_mac)
+ err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac);
+ write_unlock_bh(&dev_base_lock);
+ if (err < 0)
+ goto errout;
+ modified = 1;
+ }
+
+ if (tb[IFLA_VF_VLAN]) {
+ struct ifla_vf_vlan *ivv;
+ ivv = nla_data(tb[IFLA_VF_VLAN]);
+ write_lock_bh(&dev_base_lock);
+ if (ops->ndo_set_vf_vlan)
+ err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan);
+ write_unlock_bh(&dev_base_lock);
+ if (err < 0)
+ goto errout;
+ modified = 1;
+ }
+ err = 0;
+
+ if (tb[IFLA_VF_TX_RATE]) {
+ struct ifla_vf_tx_rate *ivt;
+ ivt = nla_data(tb[IFLA_VF_TX_RATE]);
+ write_lock_bh(&dev_base_lock);
+ if (ops->ndo_set_vf_tx_rate)
+ err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate);
+ write_unlock_bh(&dev_base_lock);
+ if (err < 0)
+ goto errout;
+ modified = 1;
+ }
err = 0;
errout:
^ permalink raw reply related
* [net-next-2.6 PATCH 3/5] net: Add netdev ops for SR-IOV configuration
From: Jeff Kirsher @ 2010-01-30 10:40 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130103842.26633.73429.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Add netdev ops for configuring SR-IOV VF devices through the PF driver.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/linux/netdevice.h | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 93a32a5..3e14066 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -28,6 +28,7 @@
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
+#include <linux/if_link.h>
#ifdef __KERNEL__
#include <linux/timer.h>
@@ -615,6 +616,13 @@ struct netdev_queue {
* this function is called when a VLAN id is unregistered.
*
* void (*ndo_poll_controller)(struct net_device *dev);
+ *
+ * SR-IOV management functions.
+ * int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac);
+ * int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan);
+ * int (*ndo_set_vf_tx_rate)(struct net_device *dev, int vf, int rate);
+ * int (*ndo_get_vf_config)(struct net_device *dev,
+ * int vf, struct ifla_vf_info *ivf);
*/
#define HAVE_NET_DEVICE_OPS
struct net_device_ops {
@@ -654,6 +662,15 @@ struct net_device_ops {
#ifdef CONFIG_NET_POLL_CONTROLLER
void (*ndo_poll_controller)(struct net_device *dev);
#endif
+ int (*ndo_set_vf_mac)(struct net_device *dev,
+ int queue, u8 *mac);
+ int (*ndo_set_vf_vlan)(struct net_device *dev,
+ int queue, u16 vlan);
+ int (*ndo_set_vf_tx_rate)(struct net_device *dev,
+ int vf, int rate);
+ int (*ndo_get_vf_config)(struct net_device *dev,
+ int vf,
+ struct ifla_vf_info *ivf);
#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)
int (*ndo_fcoe_enable)(struct net_device *dev);
int (*ndo_fcoe_disable)(struct net_device *dev);
^ permalink raw reply related
* [net-next-2.6 PATCH 2/5] if_link: Add SR-IOV configuration methods
From: Jeff Kirsher @ 2010-01-30 10:39 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
In-Reply-To: <20100130103842.26633.73429.stgit@localhost.localdomain>
From: Williams, Mitch A <mitch.a.williams@intel.com>
Add SR-IOV VF management methods to IFLA_LINKINFO. This allows userspace to
use rtnetlink to configure VF network devices.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
include/linux/if_link.h | 28 ++++++++++++++++++++++++++++
1 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index 6674791..7d0c687 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -78,6 +78,11 @@ enum {
#define IFLA_LINKINFO IFLA_LINKINFO
IFLA_NET_NS_PID,
IFLA_IFALIAS,
+ IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */
+ IFLA_VF_MAC, /* Hardware queue specific attributes */
+ IFLA_VF_VLAN,
+ IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */
+ IFLA_VFINFO,
__IFLA_MAX
};
@@ -196,4 +201,27 @@ enum macvlan_mode {
MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
};
+/* SR-IOV virtual function managment section */
+
+struct ifla_vf_mac {
+ __u32 vf;
+ __u8 mac[32]; /* MAX_ADDR_LEN */
+};
+
+struct ifla_vf_vlan {
+ __u32 vf;
+ __s32 vlan; /* 0 - 4095, -1 disables VLAN filter */
+};
+
+struct ifla_vf_tx_rate {
+ __u32 vf;
+ __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
+};
+
+struct ifla_vf_info {
+ __u32 vf;
+ __u8 mac[32];
+ __s32 vlan;
+ __u32 tx_rate;
+};
#endif /* _LINUX_IF_LINK_H */
^ permalink raw reply related
* [net-next-2.6 PATCH 1/5] pci: Add SR-IOV convenience functions and macros
From: Jeff Kirsher @ 2010-01-30 10:39 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, Mitch Williams, Jeff Kirsher
From: Williams, Mitch A <mitch.a.williams@intel.com>
Add and export pci_num_vf to allow other subsystems to determine how many
virtual function devices are associated with an SR-IOV physical function
device.
Add macros dev_is_pci, dev_is_ps, and dev_num_vf to make it easier for
non-PCI specific code to determine SR-IOV capabilities.
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/pci/iov.c | 15 +++++++++++++++
include/linux/pci.h | 8 ++++++++
2 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index b2a448e..3e5ab2b 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -706,6 +706,21 @@ irqreturn_t pci_sriov_migration(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_sriov_migration);
+/**
+ * pci_num_vf - return number of VFs associated with a PF device_release_driver
+ * @dev: the PCI device
+ *
+ * Returns number of VFs, or 0 if SR-IOV is not enabled.
+ */
+int pci_num_vf(struct pci_dev *dev)
+{
+ if (!dev || !dev->is_physfn)
+ return 0;
+ else
+ return dev->sriov->nr_virtfn;
+}
+EXPORT_SYMBOL_GPL(pci_num_vf);
+
static int ats_alloc_one(struct pci_dev *dev, int ps)
{
int pos;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 174e539..db7706d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -310,6 +310,9 @@ extern struct pci_dev *alloc_pci_dev(void);
#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list)
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
+#define dev_is_pci(d) ((d)->bus == &pci_bus_type)
+#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false))
+#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0))
static inline int pci_channel_offline(struct pci_dev *pdev)
{
@@ -1286,6 +1289,7 @@ void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar);
extern int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn);
extern void pci_disable_sriov(struct pci_dev *dev);
extern irqreturn_t pci_sriov_migration(struct pci_dev *dev);
+extern int pci_num_vf(struct pci_dev *dev);
#else
static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
{
@@ -1298,6 +1302,10 @@ static inline irqreturn_t pci_sriov_migration(struct pci_dev *dev)
{
return IRQ_NONE;
}
+static inline int pci_num_vf(struct pci_dev *dev)
+{
+ return 0;
+}
#endif
#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE)
^ permalink raw reply related
* Re: debug: nt_conntrack and KVM crash
From: Jon Masters @ 2010-01-30 10:03 UTC (permalink / raw)
To: Eric Dumazet; +Cc: linux-kernel, netdev, netfilter-devel, Patrick McHardy
In-Reply-To: <1264840415.2919.19.camel@edumazet-laptop>
On Sat, 2010-01-30 at 09:33 +0100, Eric Dumazet wrote:
> Le samedi 30 janvier 2010 à 02:36 -0500, Jon Masters a écrit :
>
> > I'll play later. Right now, I'm looking over every iptables/ip call
> > libvirt makes - it explicitly plays with the netns for the loopback,
> > which looks interesting. Supposing it does cause the hashtables to get
> > unintentionally zereod or the sizing to get wiped out, we should also
> > nonetheless catch the case that the hash function generates a whacko
> > number or that the hash size is set to zero when we want to use it.
> I asked you if you had multiple namespaces, because I was not sure
> conntracking hash was global (shared by all namespaces), or local.
Well, I didn't think I had multiple namespaces, and in fact I don't see
more than one in gdb when I poke at the net struct. What I see libvirt
doing (very oddly indeed - looking at the source now) is calling ip and
asking for the lo device to be moved into the netns for pid "-1", which
isn't valid AFAIK (should be a valid pid, unless "-1" is supposed to be
"this process" or something, haven't played with multiple namespaces).
I'll do some more digging (network stuff isn't my area) now and come
back. It only reproduces if multiple VMs start at once (hence a race,
perhaps as you describe) whereas if I disable autostart and let them
come up one at a time, the box doesn't roll over.
Jon.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" 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
* NF_STOLEN and reinsert in to IP stack
From: Susant Sahani @ 2010-01-30 8:57 UTC (permalink / raw)
To: netfilter-devel, netfilter, netdev
Hi,
I have yet to find any resource that answers this question. If I have
a kernel module that registers a callback with netfilter and steals a
packet during the NF_IP_PRE_ROUTING stage, How can I re-insert this
packet on the network stack, (before the ip routing stage) so it is
forwarded back out on the correct device?
susant
Charles de Gaulle - "The better I get to know men, the more I find
myself loving dogs." -
http://www.brainyquote.com/quotes/authors/c/charles_de_gaulle.html
^ permalink raw reply
* NF_STOLEN and re-insert in to IP stack
From: Susant Sahani @ 2010-01-30 8:58 UTC (permalink / raw)
To: netfilter-devel, netfilter, netdev
Hi,
I have yet to find any resource that answers this question. If I
have a kernel module that registers a callback with netfilter and
steals a packet during the NF_IP_PRE_ROUTING stage, How can I
re-insert this packet on the network stack, (before the ip routing
stage) .
susant
^ permalink raw reply
* Re: debug: nt_conntrack and KVM crash
From: Eric Dumazet @ 2010-01-30 8:33 UTC (permalink / raw)
To: Jon Masters; +Cc: linux-kernel, netdev, netfilter-devel, Patrick McHardy
In-Reply-To: <1264836971.7499.4.camel@tonnant>
Le samedi 30 janvier 2010 à 02:36 -0500, Jon Masters a écrit :
> I'll play later. Right now, I'm looking over every iptables/ip call
> libvirt makes - it explicitly plays with the netns for the loopback,
> which looks interesting. Supposing it does cause the hashtables to get
> unintentionally zereod or the sizing to get wiped out, we should also
> nonetheless catch the case that the hash function generates a whacko
> number or that the hash size is set to zero when we want to use it.
>
I asked you if you had multiple namespaces, because I was not sure
conntracking hash was global (shared by all namespaces), or local.
If it is local, then we have a bug, because nf_conntrack_cachep
is still shared.
Because of SLAB_DESTROY_BY_RCU constraint, we must use a distinct
cachep, or an object can be freed from a namespace and immediatly reused
into another namespace, without lookups being able to notice.
^ permalink raw reply
* Re: debug: nt_conntrack and KVM crash
From: Jon Masters @ 2010-01-30 7:40 UTC (permalink / raw)
To: Eric Dumazet; +Cc: linux-kernel, netdev, netfilter-devel, Patrick McHardy
In-Reply-To: <1264836971.7499.4.camel@tonnant>
On Sat, 2010-01-30 at 02:36 -0500, Jon Masters wrote:
> On Sat, 2010-01-30 at 07:58 +0100, Eric Dumazet wrote:
> > Le vendredi 29 janvier 2010 à 20:59 -0500, Jon Masters a écrit :
> > > On Fri, 2010-01-29 at 20:57 -0500, Jon Masters wrote:
> > >
> > > > Ah so I should have realized before but I wasn't looking at valid values
> > > > for the range of the hashtable yet, nf_conntrack_htable_size is getting
> > > > wildly out of whack. It goes from:
> > > >
> > > > (gdb) print nf_conntrack_hash_rnd
> > > > $1 = 2688505299
> > > > (gdb) print nf_conntrack_htable_size
> > > > $2 = 16384
> > > >
> > > > nf_conntrack_events: 1
> > > > nf_conntrack_max: 65536
> > > >
> > > > Shortly after booting, before being NULLed shortly after starting some
> > > > virtual machines (the hash isn't reset, whereas it is recomputed if the
> > > > hashtable is re-initialized after an intentional resizing operation):
> > >
> > > I mean the *seed* isn't changed, so I don't think it was resized
> > > intentionally. I wonder where else htable_size is fiddled with.
>
> > This rings a bell here, since another crash analysis on another problem
> > suggested to me a potential problem with read_mostly and modules, but I
> > had no time to confirm the thing yet.
> >
> > Could you try changing
> >
> >
> > net/netfilter/nf_conntrack_core.c:57:unsigned int nf_conntrack_htable_size __read_mostly;
> > to
> > net/netfilter/nf_conntrack_core.c:57:unsigned int nf_conntrack_htable_size ;
>
> I'll play later. Right now, I'm looking over every iptables/ip call
> libvirt makes - it explicitly plays with the netns for the loopback,
> which looks interesting. Supposing it does cause the hashtables to get
> unintentionally zereod or the sizing to get wiped out, we should also
> nonetheless catch the case that the hash function generates a whacko
> number or that the hash size is set to zero when we want to use it.
Oh, btw, it's definitely a localized corruption, I did memory dumps of
the offending page before and after - it's only the two hashing sizes
that get screwed around with, so it's "intentional".
Jon.
^ permalink raw reply
* Re: debug: nt_conntrack and KVM crash
From: Jon Masters @ 2010-01-30 7:36 UTC (permalink / raw)
To: Eric Dumazet; +Cc: linux-kernel, netdev, netfilter-devel, Patrick McHardy
In-Reply-To: <1264834704.2919.3.camel@edumazet-laptop>
On Sat, 2010-01-30 at 07:58 +0100, Eric Dumazet wrote:
> Le vendredi 29 janvier 2010 à 20:59 -0500, Jon Masters a écrit :
> > On Fri, 2010-01-29 at 20:57 -0500, Jon Masters wrote:
> >
> > > Ah so I should have realized before but I wasn't looking at valid values
> > > for the range of the hashtable yet, nf_conntrack_htable_size is getting
> > > wildly out of whack. It goes from:
> > >
> > > (gdb) print nf_conntrack_hash_rnd
> > > $1 = 2688505299
> > > (gdb) print nf_conntrack_htable_size
> > > $2 = 16384
> > >
> > > nf_conntrack_events: 1
> > > nf_conntrack_max: 65536
> > >
> > > Shortly after booting, before being NULLed shortly after starting some
> > > virtual machines (the hash isn't reset, whereas it is recomputed if the
> > > hashtable is re-initialized after an intentional resizing operation):
> >
> > I mean the *seed* isn't changed, so I don't think it was resized
> > intentionally. I wonder where else htable_size is fiddled with.
> This rings a bell here, since another crash analysis on another problem
> suggested to me a potential problem with read_mostly and modules, but I
> had no time to confirm the thing yet.
>
> Could you try changing
>
>
> net/netfilter/nf_conntrack_core.c:57:unsigned int nf_conntrack_htable_size __read_mostly;
> to
> net/netfilter/nf_conntrack_core.c:57:unsigned int nf_conntrack_htable_size ;
I'll play later. Right now, I'm looking over every iptables/ip call
libvirt makes - it explicitly plays with the netns for the loopback,
which looks interesting. Supposing it does cause the hashtables to get
unintentionally zereod or the sizing to get wiped out, we should also
nonetheless catch the case that the hash function generates a whacko
number or that the hash size is set to zero when we want to use it.
Amazing more people aren't talking about this, happens on several Fedora
boxes that I know of, and I'm sure many more too using KVM+nf.
Jon.
^ permalink raw reply
* nf_reinject crashes after NF_STOLEN
From: Susant Sahani @ 2010-01-30 7:09 UTC (permalink / raw)
To: netfilter, netdev
Hi,
If NF_STOLEN is done then how to reinsert the packet after sometime.
Here is the scenario.
packet1 comes in store return NF_STOLEN
packet2 comes in store return NF_STOLEN
packet3 comes in store return NF_STOLEN
packet4 comes in reinsert All the packets (packet1, packet2, packet3,
packet4) to IP stack so that it can continue the journey.
But if I do nf_reinject it crashes.
Please let me know how to do it.
susant
^ permalink raw reply
* Re: [PATCH v2] skbuff: align sk_buff::cb to 64 bit
From: Eric Dumazet @ 2010-01-30 7:07 UTC (permalink / raw)
To: Felix Fietkau; +Cc: netdev, Lennert Buytenhek, David Daney
In-Reply-To: <4B637F85.8080809@openwrt.org>
Le samedi 30 janvier 2010 à 01:38 +0100, Felix Fietkau a écrit :
> The alignment requirement for 64-bit load/store instructions on ARM is
> implementation defined. Some CPUs (such as Marvell Feroceon) do not
> generate an exception, if such an instruction is executed with an
> address that is not 64 bit aligned. In such a case, the Feroceon
> corrupts adjacent memory, which showed up
> in my tests as a crash in the rx path of ath9k that only occured with
> CONFIG_XFRM set. This crash happened, because the first field of the
> mac80211 rx status info in the cb is an u64, and changing it corrupted
> the skb->sp field.
>
> Signed-off-by: Felix Fietkau <nbd@openwrt.org>
> Cc: stable@kernel.org
> ---
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -329,7 +329,7 @@ struct sk_buff {
> * want to keep them across layers you have to do a skb_clone()
> * first. This is owned by whoever has the skb queued ATM.
> */
> - char cb[48];
> + char cb[48] __aligned(8);
> unsigned int len,
> data_len;
>
> --
Without a detailed analysis of holes added on x86_32 and/or x86_64, I
guess this patch is not acceptable as is.
You certainly can find a better way to do this, without adding holes in
sk_buff structure. Size matters a lot :)
Thanks
^ permalink raw reply
* Re: debug: nt_conntrack and KVM crash
From: Eric Dumazet @ 2010-01-30 6:58 UTC (permalink / raw)
To: Jon Masters; +Cc: linux-kernel, netdev, netfilter-devel, Patrick McHardy
In-Reply-To: <1264816777.2793.510.camel@tonnant>
Le vendredi 29 janvier 2010 à 20:59 -0500, Jon Masters a écrit :
> On Fri, 2010-01-29 at 20:57 -0500, Jon Masters wrote:
>
> > Ah so I should have realized before but I wasn't looking at valid values
> > for the range of the hashtable yet, nf_conntrack_htable_size is getting
> > wildly out of whack. It goes from:
> >
> > (gdb) print nf_conntrack_hash_rnd
> > $1 = 2688505299
> > (gdb) print nf_conntrack_htable_size
> > $2 = 16384
> >
> > nf_conntrack_events: 1
> > nf_conntrack_max: 65536
> >
> > Shortly after booting, before being NULLed shortly after starting some
> > virtual machines (the hash isn't reset, whereas it is recomputed if the
> > hashtable is re-initialized after an intentional resizing operation):
>
> I mean the *seed* isn't changed, so I don't think it was resized
> intentionally. I wonder where else htable_size is fiddled with.
>
> Jon.
>
>
This rings a bell here, since another crash analysis on another problem
suggested to me a potential problem with read_mostly and modules, but I
had no time to confirm the thing yet.
Could you try changing
net/netfilter/nf_conntrack_core.c:57:unsigned int nf_conntrack_htable_size __read_mostly;
to
net/netfilter/nf_conntrack_core.c:57:unsigned int nf_conntrack_htable_size ;
^ 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