* [PATCH net-next 4/4 RESEND] net: phy: bcm7xxx: add BCM7250 and BCM7364 PHY entries
From: Florian Fainelli @ 2014-08-26 20:10 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1409083851-29690-1-git-send-email-f.fainelli@gmail.com>
Add two new entries to the Broadcom BCM7xxx internal PHY driver for
BCM7250 and BCM7364 chips. Those chips share the usual 28nm process
Gigabit PHY sequence and require the same workarounds so far.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/phy/bcm7xxx.c | 4 ++++
include/linux/brcmphy.h | 2 ++
2 files changed, 6 insertions(+)
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 948c7086679a..09dd6e1dc6e1 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -335,6 +335,8 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
}
static struct phy_driver bcm7xxx_driver[] = {
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
@@ -367,6 +369,8 @@ static struct phy_driver bcm7xxx_driver[] = {
} };
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+ { PHY_ID_BCM7250, 0xfffffff0, },
+ { PHY_ID_BCM7364, 0xfffffff0, },
{ PHY_ID_BCM7366, 0xfffffff0, },
{ PHY_ID_BCM7439, 0xfffffff0, },
{ PHY_ID_BCM7445, 0xfffffff0, },
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index cbcfad36d4c0..5bd35cc0d471 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -13,6 +13,8 @@
#define PHY_ID_BCM5461 0x002060c0
#define PHY_ID_BCM57780 0x03625d90
+#define PHY_ID_BCM7250 0xae025280
+#define PHY_ID_BCM7364 0xae025260
#define PHY_ID_BCM7366 0x600d8490
#define PHY_ID_BCM7439 0x600d8480
#define PHY_ID_BCM7445 0x600d8510
--
1.9.1
^ permalink raw reply related
* Re: [patch net-next RFC 10/12] openvswitch: add support for datapath hardware offload
From: Alexei Starovoitov @ 2014-08-26 20:13 UTC (permalink / raw)
To: Thomas Graf
Cc: ryazanov.s.a-Re5JQEeQqe8AvxtiuMwx3w, ronye-VPRAkNaXOzVWk0Htik3J/w,
jasowang-H+wXaHxf7aLQT0dZR+AlfA,
john.r.fastabend-ral2JQCrhuEAvxtiuMwx3w,
Neil.Jerram-QnUH15yq9NYqDJ6do+/SaQ, Eric Dumazet, Andy Gospodarek,
dev-yBygre7rU0TnMu66kgdUjQ@public.gmane.org,
nbd-p3rKhJxN3npAfugRpC6u6w, Florian Fainelli, Andy Gospodarek,
Shrijeet Mukherjee, John Fastabend,
jeffrey.t.kirsher-ral2JQCrhuEAvxtiuMwx3w, ogerlitz,
ben-/+tVBieCtBitmTQ+vhA3Yw, buytenh-OLH4Qvv75CYX/NnBR394Jw,
Jiri Pirko, Roopa Prabhu, Jamal Hadi Salim,
aviadr-VPRAkNaXOzVWk0Htik3J/w, Nicolas Dichtel,
vyasevic-H+wXaHxf7aLQT0dZR+AlfA, Neil Horman, netdev,
Stephen Hemminger, dborkman
In-Reply-To: <20140826161956.GA15316-FZi0V3Vbi30CUdFEqe4BF2D2FQJk+8+b@public.gmane.org>
On Tue, Aug 26, 2014 at 9:19 AM, Thomas Graf <tgraf-G/eBtMaohhA@public.gmane.org> wrote:
>
> Wait... I don't want to use OpenFlow to configure my laptop ;-)
+1
> We should leave the controller out of this discussion though. A
> controller is not required to run OVS at all. OpenStack Neutron
> is a very good example for that. There are even applications which
> use the OVS kernel datapath but not the OVS user space portion.
> We have a wide set of APIs serving different purposes and need to
> account for all of them. I'm as much interested in an offloaded
> nftables and tc command as you.
I think it's important distinction. In-kernel OVS is not OF.
It's a networking function that has hard-coded packet parser,
N-tuple match and programmable actions.
There were times when HW vendors were using OF check-box
to sell more chips, but at the end there is not a single HW
that is fully OF compliant. OF brand is still around, but
OF 2.0 is not tcam+action anymore.
Imo trying to standardize HW offload interface based on OF 1.x
principles is strange. Does anyone has performance data
that shows that hard-parser+N-tuple-match offload actually speeds
up real life applications ?
Why are we designing kernel offload based on 'rocker' emulator?
Enterprise silicon I've seen doesn't look like it...
I'm not saying that kernel should not have a driver for rocker.
It should, but it shouldn't be a golden model for HW offload.
"straw-man proposal for OF 2.0" paper have very
interesting ideas:
http://arxiv.org/pdf/1312.1719.pdf
sooner or later off the shelf NICs will have similar functionality.
In Linux we already have bridge that is perfect abstraction of
L2 network functions. OF 1.x has to use 'tcam' to do bridge and
in-kernel OVS has to fall back to 'mega-flows', but HW has proper
exact match tables and HW mac learning,
so OF 1.x principles just don't fit to L2 offloading.
^ permalink raw reply
* [PATCH net-next v2 0/4] Broadcom BCM7xxx PHY updates for new entries
From: Florian Fainelli @ 2014-08-26 20:15 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
Hi David,
Another week, another set of updates for the Broadcom BCM7xxx PHY driver. This
patch set cleanups the existing definitions, adds a macro to ease the addition
of future chips, and finally add two new SoCs to the list of supported chips.
Resending since the first patch did not make it to the list, sorry about that.
Changes in v2:
- rephrased commit message for patch 1 to make it pass majordomo
capital triple X was rejected
Thanks!
Florian Fainelli (4):
net: phy: bcm7xxx: introduce helper macro
net: phy: broadcom: fix PHY_BCM_OUI_4
net: phy: broadcom: add new Broadcom OUI
net: phy: bcm7xxx: add BCM7250 and BCM7364 PHY entries
drivers/net/phy/bcm7xxx.c | 58 ++++++++++++++++++-----------------------------
include/linux/brcmphy.h | 6 +++--
2 files changed, 26 insertions(+), 38 deletions(-)
--
1.9.1
^ permalink raw reply
* [PATCH net-next v2 1/4] net: phy: bcm7xxx: introduce helper macro
From: Florian Fainelli @ 2014-08-26 20:15 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1409084127-30387-1-git-send-email-f.fainelli@gmail.com>
All 28nm Gigabit PHYs supported by the driver have the same
callbacks, the only differences being the 32-bits OUI and the name. Use
a macro to factor this, making it easier in the future to add new
entries.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/phy/bcm7xxx.c | 54 ++++++++++++++++-------------------------------
1 file changed, 18 insertions(+), 36 deletions(-)
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index e98c510b75c5..948c7086679a 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -319,44 +319,26 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
return 0;
}
+#define BCM7XXX_28NM_GPHY(_oui, _name) \
+{ \
+ .phy_id = (_oui), \
+ .phy_id_mask = 0xfffffff0, \
+ .name = _name, \
+ .features = PHY_GBIT_FEATURES | \
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause, \
+ .flags = PHY_IS_INTERNAL, \
+ .config_init = bcm7xxx_28nm_afe_config_init, \
+ .config_aneg = genphy_config_aneg, \
+ .read_status = genphy_read_status, \
+ .resume = bcm7xxx_28nm_resume, \
+ .driver = { .owner = THIS_MODULE }, \
+}
+
static struct phy_driver bcm7xxx_driver[] = {
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
{
- .phy_id = PHY_ID_BCM7366,
- .phy_id_mask = 0xfffffff0,
- .name = "Broadcom BCM7366",
- .features = PHY_GBIT_FEATURES |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_28nm_afe_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .resume = bcm7xxx_28nm_resume,
- .driver = { .owner = THIS_MODULE },
-}, {
- .phy_id = PHY_ID_BCM7439,
- .phy_id_mask = 0xfffffff0,
- .name = "Broadcom BCM7439",
- .features = PHY_GBIT_FEATURES |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_28nm_afe_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .resume = bcm7xxx_28nm_resume,
- .driver = { .owner = THIS_MODULE },
-}, {
- .phy_id = PHY_ID_BCM7445,
- .phy_id_mask = 0xfffffff0,
- .name = "Broadcom BCM7445",
- .features = PHY_GBIT_FEATURES |
- SUPPORTED_Pause | SUPPORTED_Asym_Pause,
- .flags = PHY_IS_INTERNAL,
- .config_init = bcm7xxx_28nm_config_init,
- .config_aneg = genphy_config_aneg,
- .read_status = genphy_read_status,
- .resume = bcm7xxx_28nm_afe_config_init,
- .driver = { .owner = THIS_MODULE },
-}, {
.phy_id = PHY_BCM_OUI_4,
.phy_id_mask = 0xffff0000,
.name = "Broadcom BCM7XXX 40nm",
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v2 2/4] net: phy: broadcom: fix PHY_BCM_OUI_4
From: Florian Fainelli @ 2014-08-26 20:15 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1409084127-30387-1-git-send-email-f.fainelli@gmail.com>
PHY_BCM_OUI_4 is missing two significant digits that actually make it an
OUI, add those missing bits so it becomes usable again for matching.
Fixes: b560a58c45c6 ("net: phy: add Broadcom BCM7xxx internal PHY driver")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/linux/brcmphy.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index ee1431d976fa..921f17ca4c26 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -21,7 +21,7 @@
#define PHY_BCM_OUI_1 0x00206000
#define PHY_BCM_OUI_2 0x0143bc00
#define PHY_BCM_OUI_3 0x03625c00
-#define PHY_BCM_OUI_4 0x600d0000
+#define PHY_BCM_OUI_4 0x600d8400
#define PHY_BCM_OUI_5 0x03625e00
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v2 3/4] net: phy: broadcom: add new Broadcom OUI
From: Florian Fainelli @ 2014-08-26 20:15 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1409084127-30387-1-git-send-email-f.fainelli@gmail.com>
Broadcom started to use a new OUI for its 2013 and newer products:
D4-01-29 which translates into 0xae025000 for a 32-bits OUI, add its
definition.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
include/linux/brcmphy.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index 921f17ca4c26..cbcfad36d4c0 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -23,7 +23,7 @@
#define PHY_BCM_OUI_3 0x03625c00
#define PHY_BCM_OUI_4 0x600d8400
#define PHY_BCM_OUI_5 0x03625e00
-
+#define PHY_BCM_OUI_6 0xae025000
#define PHY_BCM_FLAGS_MODE_COPPER 0x00000001
#define PHY_BCM_FLAGS_MODE_1000BX 0x00000002
--
1.9.1
^ permalink raw reply related
* [PATCH net-next v2 4/4] net: phy: bcm7xxx: add BCM7250 and BCM7364 PHY entries
From: Florian Fainelli @ 2014-08-26 20:15 UTC (permalink / raw)
To: netdev; +Cc: davem, Florian Fainelli
In-Reply-To: <1409084127-30387-1-git-send-email-f.fainelli@gmail.com>
Add two new entries to the Broadcom BCM7xxx internal PHY driver for
BCM7250 and BCM7364 chips. Those chips share the usual 28nm process
Gigabit PHY sequence and require the same workarounds so far.
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
drivers/net/phy/bcm7xxx.c | 4 ++++
include/linux/brcmphy.h | 2 ++
2 files changed, 6 insertions(+)
diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c
index 948c7086679a..09dd6e1dc6e1 100644
--- a/drivers/net/phy/bcm7xxx.c
+++ b/drivers/net/phy/bcm7xxx.c
@@ -335,6 +335,8 @@ static int bcm7xxx_dummy_config_init(struct phy_device *phydev)
}
static struct phy_driver bcm7xxx_driver[] = {
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
BCM7XXX_28NM_GPHY(PHY_ID_BCM7445, "Broadcom BCM7445"),
@@ -367,6 +369,8 @@ static struct phy_driver bcm7xxx_driver[] = {
} };
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
+ { PHY_ID_BCM7250, 0xfffffff0, },
+ { PHY_ID_BCM7364, 0xfffffff0, },
{ PHY_ID_BCM7366, 0xfffffff0, },
{ PHY_ID_BCM7439, 0xfffffff0, },
{ PHY_ID_BCM7445, 0xfffffff0, },
diff --git a/include/linux/brcmphy.h b/include/linux/brcmphy.h
index cbcfad36d4c0..5bd35cc0d471 100644
--- a/include/linux/brcmphy.h
+++ b/include/linux/brcmphy.h
@@ -13,6 +13,8 @@
#define PHY_ID_BCM5461 0x002060c0
#define PHY_ID_BCM57780 0x03625d90
+#define PHY_ID_BCM7250 0xae025280
+#define PHY_ID_BCM7364 0xae025260
#define PHY_ID_BCM7366 0x600d8490
#define PHY_ID_BCM7439 0x600d8480
#define PHY_ID_BCM7445 0x600d8510
--
1.9.1
^ permalink raw reply related
* [PATCH net-next 1/1] r8169: add missing MODULE_FIRMWARE.
From: Francois Romieu @ 2014-08-26 20:40 UTC (permalink / raw)
To: netdev; +Cc: davem, Chun-Hao Lin
From: Francois Romieu <romieu@fr.zoreil.com>
Leftover from 6e1d0b8988188956dac091441c1492a79a342666 ("r8169:add
support for RTL8168H and RTL8107E").
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Cc: Chun-Hao Lin <hau@realtek.com>
---
drivers/net/ethernet/realtek/r8169.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index c8375f6..02dd92a 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -852,6 +852,8 @@ MODULE_FIRMWARE(FIRMWARE_8168G_2);
MODULE_FIRMWARE(FIRMWARE_8168G_3);
MODULE_FIRMWARE(FIRMWARE_8168H_1);
MODULE_FIRMWARE(FIRMWARE_8168H_2);
+MODULE_FIRMWARE(FIRMWARE_8107E_1);
+MODULE_FIRMWARE(FIRMWARE_8107E_2);
static void rtl_lock_work(struct rtl8169_private *tp)
{
--
1.9.3
^ permalink raw reply related
* Re: [patch net-next RFC 10/12] openvswitch: add support for datapath hardware offload
From: Thomas Graf @ 2014-08-26 20:54 UTC (permalink / raw)
To: Alexei Starovoitov
Cc: Andy Gospodarek, Jiri Pirko, Jamal Hadi Salim, Roopa Prabhu,
John Fastabend, Scott Feldman, netdev, David Miller, Neil Horman,
Andy Gospodarek, dborkman, ogerlitz, Jesse Gross, Pravin Shelar,
Andy Zhou, ben, Stephen Hemminger, jeffrey.t.kirsher, vyasevic,
Cong Wang, john.r.fastabend, Eric Dumazet, Florian Fainelli,
John Linville, "dev@openvswitch.org" <
In-Reply-To: <CAADnVQLeNTQO9rekWRAb_2MWgiZqEiZ4p6GAsypdkhgg3xQffw@mail.gmail.com>
On 08/26/14 at 01:13pm, Alexei Starovoitov wrote:
> I think it's important distinction. In-kernel OVS is not OF.
> It's a networking function that has hard-coded packet parser,
> N-tuple match and programmable actions.
> There were times when HW vendors were using OF check-box
> to sell more chips, but at the end there is not a single HW
> that is fully OF compliant. OF brand is still around, but
> OF 2.0 is not tcam+action anymore.
> Imo trying to standardize HW offload interface based on OF 1.x
> principles is strange. Does anyone has performance data
> that shows that hard-parser+N-tuple-match offload actually speeds
> up real life applications ?
That really depends on your definition of application. A pure
switch application will obviously benefit. The host case is more
complicated, offloading packet switching doesn't buy you anything
obviously but it does allow to use SR-IOV in a broader context. If
I have to chose between a DPDK host stack bypass and a well
abstracted and flexible SR-IOV bypass I would favour the VF approach.
Especially once things like P4 make its way into hardware and
the flexibility of hardware becomes less of an issue. My interest
is mainly driven from this perspective.
> Why are we designing kernel offload based on 'rocker' emulator?
> Enterprise silicon I've seen doesn't look like it...
> I'm not saying that kernel should not have a driver for rocker.
> It should, but it shouldn't be a golden model for HW offload.
I agree that it shouldn't be the golden model. Is that even
happening? Given the earlier discussions, the only reason rocker
seems to exist is because of lack of public hardware specs. I doubt
that Jiri and Scott are doing this excercise if they wouldn't have
to.
> "straw-man proposal for OF 2.0" paper have very
> interesting ideas:
> http://arxiv.org/pdf/1312.1719.pdf
> sooner or later off the shelf NICs will have similar functionality.
>
> In Linux we already have bridge that is perfect abstraction of
> L2 network functions. OF 1.x has to use 'tcam' to do bridge and
> in-kernel OVS has to fall back to 'mega-flows', but HW has proper
> exact match tables and HW mac learning,
> so OF 1.x principles just don't fit to L2 offloading.
Agreed but I don't think we should restrict this to L2. As you say,
that problem is solved and we have fdb_add() to take care of the
offload.
What we're facing as minimal requirements are L2-L3 forwarding needs
combined with encap and encryption. Does it have to be implemented
with OF1.x flows? No. In fact I would love to use eBPF in the
software path and will support you all the way ;-) P4 hardware will
make that even sweeter. But using a flow model does seem kind of
straight forward to allow for offload with today's available HW n-tuple
filters.
^ permalink raw reply
* [PATCH net-next] net: add skb_get_tx_queue() helper
From: Daniel Borkmann @ 2014-08-26 21:06 UTC (permalink / raw)
To: davem; +Cc: netdev
Replace occurences of skb_get_queue_mapping() and follow-up
netdev_get_tx_queue() with an actual helper function.
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
---
include/linux/netdevice.h | 8 ++++++++
net/core/netpoll.c | 2 +-
net/core/pktgen.c | 4 +---
net/packet/af_packet.c | 4 +---
net/sched/sch_generic.c | 6 ++++--
5 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 039b237..200ee4f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1747,6 +1747,14 @@ struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
return &dev->_tx[index];
}
+static inline struct netdev_queue *skb_get_tx_queue(const struct net_device *dev,
+ const struct sk_buff *skb)
+{
+ u16 index = skb_get_queue_mapping(skb);
+
+ return netdev_get_tx_queue(dev, index);
+}
+
static inline void netdev_for_each_tx_queue(struct net_device *dev,
void (*f)(struct net_device *,
struct netdev_queue *,
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index a5ad068..12b1df9 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -115,7 +115,7 @@ static void queue_process(struct work_struct *work)
continue;
}
- txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+ txq = skb_get_tx_queue(dev, skb);
local_irq_save(flags);
HARD_TX_LOCK(dev, txq, smp_processor_id());
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 83e2b4b..d81b540 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -3286,7 +3286,6 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
{
struct net_device *odev = pkt_dev->odev;
struct netdev_queue *txq;
- u16 queue_map;
int ret;
/* If device is offline, then don't send */
@@ -3324,8 +3323,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
if (pkt_dev->delay && pkt_dev->last_ok)
spin(pkt_dev, pkt_dev->next_tx);
- queue_map = skb_get_queue_mapping(pkt_dev->skb);
- txq = netdev_get_tx_queue(odev, queue_map);
+ txq = skb_get_tx_queue(odev, pkt_dev->skb);
local_bh_disable();
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 0dfa990..b7a7f5a 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -243,7 +243,6 @@ static int packet_direct_xmit(struct sk_buff *skb)
netdev_features_t features;
struct netdev_queue *txq;
int ret = NETDEV_TX_BUSY;
- u16 queue_map;
if (unlikely(!netif_running(dev) ||
!netif_carrier_ok(dev)))
@@ -254,8 +253,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
__skb_linearize(skb))
goto drop;
- queue_map = skb_get_queue_mapping(skb);
- txq = netdev_get_tx_queue(dev, queue_map);
+ txq = skb_get_tx_queue(dev, skb);
local_bh_disable();
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index fc04fe9..05b3f5d 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -63,7 +63,7 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
if (unlikely(skb)) {
/* check the reason of requeuing without tx lock first */
- txq = netdev_get_tx_queue(txq->dev, skb_get_queue_mapping(skb));
+ txq = skb_get_tx_queue(txq->dev, skb);
if (!netif_xmit_frozen_or_stopped(txq)) {
q->gso_skb = NULL;
q->q.qlen--;
@@ -183,10 +183,12 @@ static inline int qdisc_restart(struct Qdisc *q)
skb = dequeue_skb(q);
if (unlikely(!skb))
return 0;
+
WARN_ON_ONCE(skb_dst_is_noref(skb));
+
root_lock = qdisc_lock(q);
dev = qdisc_dev(q);
- txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
+ txq = skb_get_tx_queue(dev, skb);
return sch_direct_xmit(skb, q, dev, txq, root_lock);
}
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH net-next v3 2/3] ethtool: Add generic options for tunables
From: Govindarajulu Varadarajan @ 2014-08-26 21:33 UTC (permalink / raw)
To: Ben Hutchings
Cc: Govindarajulu Varadarajan, davem, netdev, stephen, ssujith, benve
In-Reply-To: <1408749965.4672.29.camel@deadeye.wl.decadent.org.uk>
On Fri, 22 Aug 2014, Ben Hutchings wrote:
> On Thu, 2014-08-14 at 14:59 +0530, Govindarajulu Varadarajan wrote:
>> @@ -257,6 +262,7 @@ struct ethtool_ops {
>> struct ethtool_eeprom *, u8 *);
>> int (*get_eee)(struct net_device *, struct ethtool_eee *);
>> int (*set_eee)(struct net_device *, struct ethtool_eee *);
>> + struct ethtool_tunable_ops tunable_ops[ETHTOOL_TUNABLE_MAX];
>
> This is OK but if we add a lot of tunables then it bloats up each driver
> with a (probably quite sparse) array of function pointers.
>
Will fix with David's suggestion.
>> +struct ethtool_tunable {
>> + u32 cmd;
>> + u32 tcmd;
>> + u32 len;
>> + union {
>> + u32 rx_copybreak;
>> + u32 data[48];
>> + } data;
> [...]
>
> This is not at all generic. If tunables don't all have the same type,
> then the type - not just the length - should be explicit.
>
> I also think that if the length of a value can vary then we should not
> declare a data member at all. So we would have something like:
>
> struct ethtool_tunable {
> __u32 cmd;
> __u32 id;
> __u32 type_id;
> __u32 len;
> __u8 data[0];
> };
>
> Then the value buffer would be passed to the driver functions separately
> (as for other variable-length command structures).
>
OK. id show be the tunable command type right? Like RX_COPYBREAK, TX_COPYBREAK
etc. What is the type_id?
> By the way, you must use double-underscore prefixes on fixed-width
> integer type names in UAPI headers.
>
will fix it.
Thanks
^ permalink raw reply
* Re: BCM4313 & brcmsmac & 3.12: only semi-working?
From: Arend van Spriel @ 2014-08-26 21:37 UTC (permalink / raw)
To: Michael Tokarev; +Cc: brcm80211-dev-list, linux-wireless, netdev
In-Reply-To: <53FCB2A3.1050605@msgid.tls.msk.ru>
On 08/26/14 18:15, Michael Tokarev wrote:
> 26.08.2014 18:56, Arend van Spriel wrote:
>> On 08/26/14 07:13, Michael Tokarev wrote:
> []
>>> So, I'm curious -- why this driver is found in regular section of kernel?
>>> It looks like it should be in staging at least, or better yet, in a new section
>>> titled "toy drivers" or something like this. Does it work for any device at
>>> all?
>>
>> Hi Michael,
>>
>> Thanks for your encouraging suggestions.
>
> You might be a good politician :) These are blames, quite strong...
>
> Seriously. As you revisited this thread, I had quite some issues and
> money loss after all this, -- after initially especially choosing a
> model with a supported wifi card which turned out to be non-working,
> which I tried to fix by buying a new wifi NIC (which didn't work
> thanks to Lenovo), and which I finally broke due to usb wifi dongle
> I used.
>
> But that's all "poetry", the main source of my blames is you reaction -
> your first reply was really ecoraging, I hoped we can have some solution
> together (I have strong programming background, just not as good with
> kernel and drivers as you). But after your single reply, you never
> spoke again until now. That's 8 months. _That_ is where my frustration
> comes from.
Well, sorry about that. I did see the other messages fly by and noticed
you were using the wl driver so assumed you were fine with that.
Admittedly the brcmsmac got very little attention as all our resources
were put on brcmfmac.
> And the actual facts are true - by now I have had 2 entirely different
> devices (my original laptop which is now thrown away and another, given
> by me by a friend because I needed something) - I dunno if that's
> exactly the same wifi card or not (lspci output looks similar, and
> this one is also bt/wifi combo), but they both doesn't work in a
> quite similar way. So, the driver doesn't work with 2 out of 2 devices
> which I've seen. Not a good statistics generally, but that's 100%
> "hit" ratio for me. So I really am curious if this driver works at
> all.
>
>> I revisited the threads you referred to. In the boardflags it shows you
>> have a bt+wifi card. It could be that is an issue. The brcmsmac supports other
>> devices, ie. bcm43224/5 and the bcm4313 comes in a number of varieties.
>> From what you tell here it seems you have trouble in rx path so I will look
>> into that area if there is any specifically done for your variant of the bcm4313.
>
> I tested this "new" laptop with 3.16 kernel just briefly. I may try more
> complete analysis. I can participate with the debugging/dumping (I already
> mentioned my strong programming background - but I'm really not into drivers
> and hardware internals). So, basically, I'm all yours ;) Not that I really
> need this driver anymore (since I will avoid these cards like a plague, for
> obvious reasons :), but I want to have some good outcome out of all this
> story :)
Ok. Let's put frustration aside and make an effort. So could you make a
trace using trace-cmd utility. The log can get quite big. The brcmsmac
driver needs to be built with CONFIG_BRCM_TRACING enabled. Please
execute the following commands (assuming you use ubuntu with
network-manager):
$ sudo stop network-manager
$ sudo insmod brcmfmac.ko
$ sudo trace-cmd record -e brcmsmac:*
In another terminal:
$ sudo start network-manager
The trace-cmd must be stopped using ctrl-c.
Regards,
Arend
^ permalink raw reply
* Re: IPv6 Policy based routing not working.
From: Hannes Frederic Sowa @ 2014-08-26 22:01 UTC (permalink / raw)
To: Tushar Shinde; +Cc: netdev
In-Reply-To: <CABQpAL7X9_=RTS2cd_m3jkCzWOM8hjcu22yQdnRD6S4fs5AF2Q@mail.gmail.com>
Hi,
On Di, 2014-08-26 at 21:32 +0530, Tushar Shinde wrote:
> Hello NetDev,
>
> I am facing problem where if ipv6 route (outside to current subnet) is
> reachable only if route is present in main table. Policy based routes
> are not working.
>
> Following is my setup,
>
> eth0 inet6 2001:1::10/120 scope global
> eth1 inet6 2001:1::11/120 scope global
> 2001:1::1 is gateway
> 2.6.32-431.11.2.el6.x86_64 kernel (I tried on 3.x also)
>
> [root@ipv6node1 ~]# ip -6 route show tab 1
> 2001:1::/120 dev eth0 metric 1024 mtu 1500 advmss 1440 hoplimit 4294967295
> default via 2001:1::1 dev eth0 metric 1024 mtu 1500 advmss 1440
> hoplimit 4294967295
> [root@ipv6node1 ~]#
> [root@ipv6node1 ~]# ip -6 route show tab 2
> 2001:1::/120 dev eth1 metric 1024 mtu 1500 advmss 1440 hoplimit 4294967295
> default via 2001:1::1 dev eth1 metric 1024 mtu 1500 advmss 1440
> hoplimit 4294967295
> [root@ipv6node1 ~]#
> [root@ipv6node1 ~]# ip -6 rule show
> 0: from all lookup local
> 16383: from 2001:1::10 lookup 1
> 16383: from 2001:1::11 lookup 2
> 32766: from all lookup main
> [root@ipv6node1 ~]#
>
> If I add default vai eth0 only ip of eth0 is reachable from outside or
> eth1 dont work. In above setup default route is not present.
>
> But default entry in "table" is never getting used to resolve route
>
> [root@ipv6node1 ~]# ping6 -I eth0 2001:2::20
> connect: Network is unreachable
> [root@ipv6node1 ~]#
> [root@ipv6node1 ~]# ping6 -I eth1 2001:2::20
> connect: Network is unreachable
> [root@ipv6node1 ~]#
ping6 selects the ipv6 address based on netlink route lookup given the
specified interface but without setting the source address. That said,
it is probable that the rule lookup happens with a completely different
ipv6 address. Please verify this. ping6 -I also accepts a source ipv6
address, can you try this?
Otherwise please specify with which 3.x kernel you tested this.
Thanks,
Hannes
^ permalink raw reply
* Re: [PATCH net-next v4 12/13] Documentation: devicetree: update dsa binding with optional properties
From: Sergei Shtylyov @ 2014-08-26 22:40 UTC (permalink / raw)
To: Florian Fainelli, netdev; +Cc: davem, linville, jhs, alexander.duyck
In-Reply-To: <1409028581-17399-13-git-send-email-f.fainelli@gmail.com>
Hello.
On 08/26/2014 08:49 AM, Florian Fainelli wrote:
> Add documentation for a bunch of new optional properties described in
> ethernet.txt and fixed-link.txt, this includes: 'phy-handle', 'phy-mode'
> and the 'fixed-link' subnode.
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
> ---
> Documentation/devicetree/bindings/net/dsa/dsa.txt | 17 +++++++++++++++++
> 1 file changed, 17 insertions(+)
> diff --git a/Documentation/devicetree/bindings/net/dsa/dsa.txt b/Documentation/devicetree/bindings/net/dsa/dsa.txt
> index 49f4f7ae3f51..6192f9a7aa89 100644
> --- a/Documentation/devicetree/bindings/net/dsa/dsa.txt
> +++ b/Documentation/devicetree/bindings/net/dsa/dsa.txt
> @@ -39,6 +39,22 @@ Optionnal property:
> This property is only used when switches are being
> chained/cascaded together.
>
> +- phy-handle : Phandle to a PHY on an external MDIO bus, not the
> + switch internal one. See
> + Documentation/devicetree/bindings/net/ethernet.txt
> + for details.
> +
> +- phy-mode : String representing the connection to the designeted
Designated?
> + PHY node specified by the 'phy-handle' property. See
> + Documentation/devicetree/bindings/net/ethernet.txt
> + for details.
> +
> +Optionnal subnodes:
One 'n' is enough (although DaveM may disagree ;-).
WBR, Sergei
^ permalink raw reply
* Re: [PATCH net-next] net: add skb_get_tx_queue() helper
From: Tom Herbert @ 2014-08-26 23:51 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: David Miller, Linux Netdev List
In-Reply-To: <1409087208-25809-1-git-send-email-dborkman@redhat.com>
On Tue, Aug 26, 2014 at 2:06 PM, Daniel Borkmann <dborkman@redhat.com> wrote:
> Replace occurences of skb_get_queue_mapping() and follow-up
> netdev_get_tx_queue() with an actual helper function.
>
> Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
> ---
> include/linux/netdevice.h | 8 ++++++++
> net/core/netpoll.c | 2 +-
> net/core/pktgen.c | 4 +---
> net/packet/af_packet.c | 4 +---
> net/sched/sch_generic.c | 6 ++++--
> 5 files changed, 15 insertions(+), 9 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 039b237..200ee4f 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1747,6 +1747,14 @@ struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev,
> return &dev->_tx[index];
> }
>
> +static inline struct netdev_queue *skb_get_tx_queue(const struct net_device *dev,
> + const struct sk_buff *skb)
> +{
> + u16 index = skb_get_queue_mapping(skb);
> +
> + return netdev_get_tx_queue(dev, index);
> +}
> +
return netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
if you want to be a little more concise.
> static inline void netdev_for_each_tx_queue(struct net_device *dev,
> void (*f)(struct net_device *,
> struct netdev_queue *,
> diff --git a/net/core/netpoll.c b/net/core/netpoll.c
> index a5ad068..12b1df9 100644
> --- a/net/core/netpoll.c
> +++ b/net/core/netpoll.c
> @@ -115,7 +115,7 @@ static void queue_process(struct work_struct *work)
> continue;
> }
>
> - txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
> + txq = skb_get_tx_queue(dev, skb);
>
> local_irq_save(flags);
> HARD_TX_LOCK(dev, txq, smp_processor_id());
> diff --git a/net/core/pktgen.c b/net/core/pktgen.c
> index 83e2b4b..d81b540 100644
> --- a/net/core/pktgen.c
> +++ b/net/core/pktgen.c
> @@ -3286,7 +3286,6 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
> {
> struct net_device *odev = pkt_dev->odev;
> struct netdev_queue *txq;
> - u16 queue_map;
> int ret;
>
> /* If device is offline, then don't send */
> @@ -3324,8 +3323,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
> if (pkt_dev->delay && pkt_dev->last_ok)
> spin(pkt_dev, pkt_dev->next_tx);
>
> - queue_map = skb_get_queue_mapping(pkt_dev->skb);
> - txq = netdev_get_tx_queue(odev, queue_map);
> + txq = skb_get_tx_queue(odev, pkt_dev->skb);
>
> local_bh_disable();
>
> diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
> index 0dfa990..b7a7f5a 100644
> --- a/net/packet/af_packet.c
> +++ b/net/packet/af_packet.c
> @@ -243,7 +243,6 @@ static int packet_direct_xmit(struct sk_buff *skb)
> netdev_features_t features;
> struct netdev_queue *txq;
> int ret = NETDEV_TX_BUSY;
> - u16 queue_map;
>
> if (unlikely(!netif_running(dev) ||
> !netif_carrier_ok(dev)))
> @@ -254,8 +253,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
> __skb_linearize(skb))
> goto drop;
>
> - queue_map = skb_get_queue_mapping(skb);
> - txq = netdev_get_tx_queue(dev, queue_map);
> + txq = skb_get_tx_queue(dev, skb);
>
> local_bh_disable();
>
> diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
> index fc04fe9..05b3f5d 100644
> --- a/net/sched/sch_generic.c
> +++ b/net/sched/sch_generic.c
> @@ -63,7 +63,7 @@ static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
>
> if (unlikely(skb)) {
> /* check the reason of requeuing without tx lock first */
> - txq = netdev_get_tx_queue(txq->dev, skb_get_queue_mapping(skb));
> + txq = skb_get_tx_queue(txq->dev, skb);
> if (!netif_xmit_frozen_or_stopped(txq)) {
> q->gso_skb = NULL;
> q->q.qlen--;
> @@ -183,10 +183,12 @@ static inline int qdisc_restart(struct Qdisc *q)
> skb = dequeue_skb(q);
> if (unlikely(!skb))
> return 0;
> +
> WARN_ON_ONCE(skb_dst_is_noref(skb));
> +
> root_lock = qdisc_lock(q);
> dev = qdisc_dev(q);
> - txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
> + txq = skb_get_tx_queue(dev, skb);
>
> return sch_direct_xmit(skb, q, dev, txq, root_lock);
> }
> --
> 1.7.11.7
>
> --
> 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 (net-next) v2] net: stmmac: fix warning from Sparse for socfpga
From: Ley Foon Tan @ 2014-08-27 1:24 UTC (permalink / raw)
To: Giuseppe CAVALLARO
Cc: netdev, linux-kernel@vger.kernel.org, David S. Miller,
Vince Bridgers
In-Reply-To: <53FC5DCF.4060202@st.com>
On Tue, Aug 26, 2014 at 6:13 PM, Giuseppe CAVALLARO
<peppe.cavallaro@st.com> wrote:
> On 8/26/2014 11:47 AM, Ley Foon Tan wrote:
>>
>> Warning:
>> drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:122:41:
>> sparse: cast removes address space of expression
>> drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c:122:38:
>> sparse: incorrect type in assignment (different address spaces)
>>
>> Signed-off-by: Ley Foon Tan <lftan@altera.com>
>> ---
>> drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
>> b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
>> index cd613d7..ff54a1f 100644
>> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
>> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
>> @@ -119,7 +119,7 @@ static int socfpga_dwmac_parse_data(struct
>> socfpga_dwmac *dwmac, struct device *
>> return -EINVAL;
>> }
>>
>> - dwmac->splitter_base = (void *)devm_ioremap_resource(dev,
>> + dwmac->splitter_base = devm_ioremap_resource(dev,
>> &res_splitter);
>
>
> can the ioremap call stay in a single line ? or pls review indent looks
> NOK
It will has "line over 80 characters" if it is one line code.
BTW, this patch passed "checkpatch.pl" script.
Let me know if think indent is not okay.
Thanks.
^ permalink raw reply
* Re: [PATCH] net: stmmac: add dcrs parameter
From: Ley Foon Tan @ 2014-08-27 1:27 UTC (permalink / raw)
To: Giuseppe CAVALLARO
Cc: Vince Bridgers, Chen-Yu Tsai, netdev, linux-kernel,
David S. Miller, Vince Bridgers
In-Reply-To: <53FC89A0.8040905@st.com>
On Tue, Aug 26, 2014 at 9:20 PM, Giuseppe CAVALLARO
<peppe.cavallaro@st.com> wrote:
>>>
>>>
>>>
>>> Indeed this is what I had done in the patch.
>>>
>>>
>>> http://git.stlinux.com/?p=stm/linux-sh4-2.6.32.y.git;a=commit;h=b0b863bf65c36dc593f6b7b4b418394fd880dae2
>>>
>>> Also in case of carrier sense the frame will be dropped in any case
>>> later.
>>>
>>> Let me know if you Acked this patch so I will rebase it on
>>> net.git and I send it soon
>>>
>>> peppe
>>>
>>
>> Yes, this looks good to me. I don't expect anyone is using 10Base2 or
>> 10Base5 anymore, so it's ok to disable DCRS by default.
>>
>> ack
>>
>> All the best,
>
>
> thx so much, I will send this patch (with your Acked-by) and ported on
> net.git soon.
>
> Chen-Yu, Ley Foon, pls let me know if it is ok for you as well
I'm fine with your patch.
Thanks.
Regards
Ley Foon
^ permalink raw reply
* [PATCH 1/1] add selftest for virtio-net
From: Hengjinxiao @ 2014-08-27 1:45 UTC (permalink / raw)
To: virtualization-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
Cc: mst-H+wXaHxf7aLQT0dZR+AlfA, rusty-8n+1lVoiYb80n/F98K4Iww,
famz-H+wXaHxf7aLQT0dZR+AlfA, jasowang-H+wXaHxf7aLQT0dZR+AlfA
Selftest is an important part of network driver, this patch adds selftest for
virtio-net, including loopback test, negotiate test and reset test. Loopback
test checks whether virtio-net can send and receive packets normally. Negotiate test
executes feature negotiation between virtio-net driver in Guest OS and virtio-net
device in Host OS. Reset test resets virtio-net.
Signed-off-by: Hengjinxiao <hjxiaohust-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
drivers/net/virtio_net.c | 233 +++++++++++++++++++++++++++++++++++++++-
include/uapi/linux/virtio_net.h | 9 ++
2 files changed, 241 insertions(+), 1 deletion(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 59caa06..f83f6e4 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -28,6 +28,7 @@
#include <linux/cpu.h>
#include <linux/average.h>
#include <net/busy_poll.h>
+#include <linux/pci.h>
static int napi_weight = NAPI_POLL_WEIGHT;
module_param(napi_weight, int, 0444);
@@ -51,6 +52,23 @@ module_param(gso, bool, 0444);
#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256)
#define VIRTNET_DRIVER_VERSION "1.0.0"
+#define __VIRTNET_TESTING 0
+
+enum {
+ VIRTNET_LOOPBACK_TEST,
+ VIRTNET_FEATURE_NEG_TEST,
+ VIRTNET_RESET_TEST,
+};
+
+static const struct {
+ const char string[ETH_GSTRING_LEN];
+} virtnet_gstrings_test[] = {
+ [VIRTNET_LOOPBACK_TEST] = { "loopback test (offline)" },
+ [VIRTNET_FEATURE_NEG_TEST] = { "negotiate test (offline)" },
+ [VIRTNET_RESET_TEST] = { "reset test (offline)" },
+};
+
+#define VIRTNET_NUM_TEST ARRAY_SIZE(virtnet_gstrings_test)
struct virtnet_stats {
struct u64_stats_sync tx_syncp;
@@ -104,6 +122,8 @@ struct virtnet_info {
struct send_queue *sq;
struct receive_queue *rq;
unsigned int status;
+ unsigned long flags;
+ atomic_t lb_count;
/* Max # of queue pairs supported by the device */
u16 max_queue_pairs;
@@ -436,6 +456,19 @@ err_buf:
return NULL;
}
+void virtnet_check_lb_frame(struct virtnet_info *vi,
+ struct sk_buff *skb)
+{
+ unsigned int frame_size = skb->len;
+
+ if (*(skb->data + 3) == 0xFF) {
+ if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+ (*(skb->data + frame_size / 2 + 12) == 0xAF)) {
+ atomic_dec(&vi->lb_count);
+ }
+ }
+}
+
static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
{
struct virtnet_info *vi = rq->vq->vdev->priv;
@@ -485,7 +518,12 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
} else if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
-
+ /* loopback self test for ethtool */
+ if (test_bit(__VIRTNET_TESTING, &vi->flags)) {
+ virtnet_check_lb_frame(vi, skb);
+ dev_kfree_skb_any(skb);
+ return;
+ }
skb->protocol = eth_type_trans(skb, dev);
pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
ntohs(skb->protocol), skb->len, skb->pkt_type);
@@ -813,6 +851,9 @@ static int virtnet_open(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
int i;
+ /* disallow open during test */
+ if (test_bit(__VIRTNET_TESTING, &vi->flags))
+ return -EBUSY;
for (i = 0; i < vi->max_queue_pairs; i++) {
if (i < vi->curr_queue_pairs)
@@ -1363,12 +1404,158 @@ static void virtnet_get_channels(struct net_device *dev,
channels->other_count = 0;
}
+static int virtnet_reset(struct virtnet_info *vi);
+
+static void virtnet_create_lb_frame(struct sk_buff *skb,
+ unsigned int frame_size)
+{
+ memset(skb->data, 0xFF, frame_size);
+ frame_size &= ~1;
+ memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+ memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+ memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int virtnet_start_loopback(struct virtnet_info *vi)
+{
+ if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_LOOPBACK,
+ VIRTIO_NET_CTRL_LOOPBACK_SET, NULL, NULL)) {
+ dev_warn(&vi->dev->dev, "Failed to set loopback.\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int virtnet_run_loopback_test(struct virtnet_info *vi)
+{
+ int i;
+ netdev_tx_t rc;
+ struct sk_buff *skb;
+ unsigned int size = GOOD_COPY_LEN;
+
+ for (i = 0; i < 100; i++) {
+ skb = netdev_alloc_skb(vi->dev, size);
+ if (!skb)
+ return -ENOMEM;
+
+ skb->queue_mapping = 0;
+ skb_put(skb, size);
+ virtnet_create_lb_frame(skb, size);
+ rc = start_xmit(skb, vi->dev);
+ if (rc != NETDEV_TX_OK)
+ return -EPIPE;
+ atomic_inc(&vi->lb_count);
+ }
+ /* Give queue time to settle before testing results. */
+ msleep(20);
+ return atomic_read(&vi->lb_count) ? -EIO : 0;
+}
+
+static int virtnet_stop_loopback(struct virtnet_info *vi)
+{
+ if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_LOOPBACK,
+ VIRTIO_NET_CTRL_LOOPBACK_UNSET, NULL, NULL)) {
+ dev_warn(&vi->dev->dev, "Failed to unset loopback.\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int virtnet_loopback_test(struct virtnet_info *vi, u64 *data)
+{
+ *data = virtnet_start_loopback(vi);
+ if (*data)
+ goto out;
+ *data = virtnet_run_loopback_test(vi);
+ if (*data)
+ goto out;
+ *data = virtnet_stop_loopback(vi);
+out:
+ return *data;
+}
+
+static void virtnet_feature_neg_test(struct virtnet_info *vi)
+{
+ struct virtio_device *dev = vi->vdev;
+ struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int i;
+ u32 device_features;
+
+ /* Figure out what features the device supports. */
+ device_features = dev->config->get_features(dev);
+
+ /* Features supported by both device and driver into dev->features. */
+ memset(dev->features, 0, sizeof(dev->features));
+ for (i = 0; i < drv->feature_table_size; i++) {
+ unsigned int f = drv->feature_table[i];
+
+ BUG_ON(f >= 32);
+ if (device_features & (1 << f))
+ set_bit(f, dev->features);
+ }
+
+ /* Transport features always preserved to pass to finalize_features. */
+ for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
+ if (device_features & (1 << i))
+ set_bit(i, dev->features);
+
+ dev->config->finalize_features(dev);
+}
+
+static int virtnet_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_TEST:
+ return VIRTNET_NUM_TEST;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void virtnet_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+ switch (stringset) {
+ case ETH_SS_TEST:
+ memcpy(buf, &virtnet_gstrings_test,
+ sizeof(virtnet_gstrings_test));
+ break;
+ default:
+ break;
+ }
+}
+
+static void virtnet_self_test(struct net_device *netdev,
+ struct ethtool_test *eth_test, u64 *data)
+{
+ struct virtnet_info *vi = netdev_priv(netdev);
+ bool if_running = netif_running(netdev);
+
+ set_bit(__VIRTNET_TESTING, &vi->flags);
+ memset(data, 0, sizeof(u64) * VIRTNET_NUM_TEST);
+
+ if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+ if (!if_running) {
+ dev_warn(&vi->dev->dev, "Failed to execute self test.\n");
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ return;
+ }
+ if (virtnet_loopback_test(vi, &data[VIRTNET_LOOPBACK_TEST]))
+ eth_test->flags |= ETH_TEST_FL_FAILED;
+ virtnet_feature_neg_test(vi);
+ virtnet_reset(vi);
+ }
+ clear_bit(__VIRTNET_TESTING, &vi->flags);
+}
+
static const struct ethtool_ops virtnet_ethtool_ops = {
.get_drvinfo = virtnet_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ringparam = virtnet_get_ringparam,
.set_channels = virtnet_set_channels,
.get_channels = virtnet_get_channels,
+ .self_test = virtnet_self_test,
+ .get_strings = virtnet_get_strings,
+ .get_sset_count = virtnet_get_sset_count,
};
#define MIN_MTU 68
@@ -1957,6 +2144,50 @@ static int virtnet_restore(struct virtio_device *vdev)
}
#endif
+static int virtnet_reset(struct virtnet_info *vi)
+{
+ struct virtio_device *vdev = vi->vdev;
+ int err, i;
+ u8 status;
+
+ mutex_lock(&vi->config_lock);
+ vi->config_enable = false;
+ mutex_unlock(&vi->config_lock);
+
+ cancel_delayed_work_sync(&vi->refill);
+
+ if (netif_running(vi->dev))
+ for (i = 0; i < vi->max_queue_pairs; i++) {
+ napi_disable(&vi->rq[i].napi);
+ netif_napi_del(&vi->rq[i].napi);
+ }
+
+ remove_vq_common(vi);
+ flush_work(&vi->config_work);
+
+ virtnet_feature_neg_test(vi);
+ err = init_vqs(vi);
+ if (err)
+ return err;
+ if (netif_running(vi->dev)) {
+ for (i = 0; i < vi->curr_queue_pairs; i++)
+ if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+ schedule_delayed_work(&vi->refill, 0);
+
+ for (i = 0; i < vi->max_queue_pairs; i++)
+ virtnet_napi_enable(&vi->rq[i]);
+ }
+
+ mutex_lock(&vi->config_lock);
+ vi->config_enable = true;
+ mutex_unlock(&vi->config_lock);
+
+ virtnet_set_queues(vi, vi->curr_queue_pairs);
+ status = vdev->config->get_status(vdev);
+ vdev->config->set_status(vdev, status | VIRTIO_CONFIG_S_DRIVER_OK);
+ return 0;
+}
+
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
{ 0 },
diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h
index 172a7f0..1f31f90 100644
--- a/include/uapi/linux/virtio_net.h
+++ b/include/uapi/linux/virtio_net.h
@@ -201,4 +201,13 @@ struct virtio_net_ctrl_mq {
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1
#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000
+ /*
+ * Control Loopback(5 is used by VIRTIO_NET_CTRL_GUEST_OFFLOADS in latest qemu)
+ *
+ * The command VIRTIO_NET_CTRL_LOOPBACK_SET is used to require the device come
+ * into loopback state.
+ */
+#define VIRTIO_NET_CTRL_LOOPBACK 6
+ #define VIRTIO_NET_CTRL_LOOPBACK_SET 0
+ #define VIRTIO_NET_CTRL_LOOPBACK_UNSET 1
#endif /* _LINUX_VIRTIO_NET_H */
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH 00/14] arm64: eBPF JIT compiler
From: Z Lim @ 2014-08-27 2:02 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, Alexei Starovoitov, Jiang Liu, AKASHI Takahiro,
David S. Miller, Daniel Borkmann, Chema Gonzalez,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org
In-Reply-To: <20140826095804.GB23445@arm.com>
Hi Will,
On Tue, Aug 26, 2014 at 2:58 AM, Will Deacon <will.deacon@arm.com> wrote:
> Hi Z Lim,
>
> On Thu, Jul 24, 2014 at 05:55:36AM +0100, Z Lim wrote:
>> On Wed, Jul 23, 2014 at 3:32 AM, Catalin Marinas
>> <catalin.marinas@arm.com> wrote:
>> > On Mon, Jul 21, 2014 at 04:49:29PM +0100, Alexei Starovoitov wrote:
>> >> On Mon, Jul 21, 2014 at 2:16 AM, Will Deacon <will.deacon@arm.com> wrote:
>> >> > On Fri, Jul 18, 2014 at 07:28:06PM +0100, Zi Shen Lim wrote:
>> [...]
>> >> >> This series applies against net-next and is tested working
>> >> >> with lib/test_bpf on ARMv8 Foundation Model.
>> >> >
>> >> > Looks like it works on my Juno board too, so:
>> >> >
>> >> > Acked-by: Will Deacon <will.deacon@arm.com>
>> >> >
>> >> > for the series.
>> >> >
>> >> > It's a bit late for 3.17 now, so I guess we'll queue this for 3.18 (which
>> >> > also means the dependency on -next isn't an issue). Perhaps you could repost
>> >> > around -rc3?
>> >>
>> >> Thanks for testing! Nice to see it working on real hw.
>> >> I'm not sure why you're proposing a 4+ week delay. The patches
>> >> will rot instead of getting used and tested. Imo it makes sense to
>> >> get them into net-next now for 3.17.
>> >> JIT is disabled by sysctl by default anyway.
>> >
>> > We normally like some patches (especially new functionality) to sit in
>> > linux-next for a while before the mering window (ideally starting with
>> > -rc4 or -rc5). We are at -rc6 already, so getting close to the 3.17
>> > merging window.
>> >
>> > Another aspect is that the arm64/bpf branch depends on the net tree, so
>> > it can't easily go in via the arm64 tree for 3.17 (3.18 would not be a
>> > problem).
>>
>> Hi Catalin, I take it you prefer this series going through arm64 tree,
>> targeting 3.18, is that right?
>>
>> I understand your preference to have it sitting in linux-next for a
>> longer period for arm64 material, I'll repost this again after 3.17 so
>> it gets more exposure in linux-next.
>
> Any chance you could post a new version of this, based on a 3.17 -rc,
> please? Whilst your current patches apply, I get a bunch of errors if I try
> to build them.
Sure. I just rebased onto -rc2 and fixed up as necessary due to
changes introduced in net.
I'll post a v2 shortly.
Thanks for the reminder :)
z
>
> Cheers,
>
> Will
^ permalink raw reply
* [PATCH RFC v7 net-next 00/28] BPF syscall
From: Alexei Starovoitov @ 2014-08-27 2:29 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Brendan Gregg, Namhyung Kim, H. Peter Anvin, Andrew Morton,
Kees Cook, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
Hi Ingo, David,
posting whole thing again as RFC to get feedback on syscall only.
If syscall bpf(int cmd, union bpf_attr *attr, unsigned int size) is ok,
I'll split them into small chunks as requested and will repost without RFC.
Right now please only review syscall API
patch 0003 introduces sys_bpf and first BPF_MAP_CREATE command
patch 0005 adds four more commands to the same syscall
patch 0007 adds BPF_PROG_LOAD command
patch 0010 extends BPF_PROG_LOAD command with 3 more attributes
patch 0021 adds user space wrapper for BPF syscall
patch 0023 uses these wrappers in verifier testsuite
Note that additions of commands and attributes kept this syscall
backwards compatible from one patch to another.
I've decided not to bother with forward compatiblity for now.
We can address it later the way perf_event_open did.
Please ignore other patches, since I cannot easily remove them
without breaking compilation
btw, tested on x64/i386 and comiled tested on arm with NET-less config.
V6->V7:
- only BPF syscall interface changed from long+nlattr+a_lot_of_type_casts to
single 'union bpf_attr'.
It pretty much removed all type casts in kernel and in user space that
were there because of 'long' and because of 'nlattr'
Thanks for feedback. I think this version is definitely cleaner.
As a side note I've addressed Cong's comment regarding commit log.
Now it documents syscall itself instead of wrappers of syscall.
If anyone prefers to see patches in the browser, they are here:
https://git.kernel.org/cgit/linux/kernel/git/ast/bpf.git/log/?h=v7
Thanks!
Alexei Starovoitov (28):
net: filter: add "load 64-bit immediate" eBPF instruction
net: filter: split filter.h and expose eBPF to user space
bpf: introduce syscall(BPF, ...) and BPF maps
bpf: enable bpf syscall on x64 and i386
bpf: add lookup/update/delete/iterate methods to BPF maps
bpf: add hashtable type of BPF maps
bpf: expand BPF syscall with program load/unload
bpf: handle pseudo BPF_CALL insn
bpf: verifier (add docs)
bpf: verifier (add ability to receive verification log)
bpf: handle pseudo BPF_LD_IMM64 insn
bpf: verifier (add branch/goto checks)
bpf: verifier (add verifier core)
bpf: verifier (add state prunning optimization)
bpf: allow eBPF programs to use maps
bpf: split eBPF out of NET
tracing: allow eBPF programs to be attached to events
tracing: allow eBPF programs call printk()
tracing: allow eBPF programs to be attached to kprobe/kretprobe
tracing: allow eBPF programs to call ktime_get_ns() and get_current()
samples: bpf: add mini eBPF library to manipulate maps and programs
samples: bpf: example of tracing filters with eBPF
bpf: verifier test
bpf: llvm backend
samples: bpf: elf file loader
samples: bpf: eBPF example in C
samples: bpf: counting eBPF example in C
samples: bpf: IO latency analysis (iosnoop/heatmap)
Documentation/networking/filter.txt | 313 +++-
arch/Kconfig | 3 +
arch/x86/net/bpf_jit_comp.c | 17 +
arch/x86/syscalls/syscall_32.tbl | 1 +
arch/x86/syscalls/syscall_64.tbl | 1 +
fs/btrfs/super.c | 3 +
include/linux/bpf.h | 139 ++
include/linux/filter.h | 303 +---
include/linux/ftrace_event.h | 5 +
include/linux/syscalls.h | 3 +-
include/trace/bpf_trace.h | 23 +
include/trace/ftrace.h | 25 +
include/uapi/asm-generic/unistd.h | 4 +-
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/bpf.h | 439 +++++
kernel/Makefile | 2 +-
kernel/bpf/Makefile | 2 +-
kernel/bpf/core.c | 17 +
kernel/bpf/hashtab.c | 365 ++++
kernel/bpf/syscall.c | 645 +++++++
kernel/bpf/verifier.c | 1910 ++++++++++++++++++++
kernel/sys_ni.c | 3 +
kernel/trace/Kconfig | 1 +
kernel/trace/Makefile | 1 +
kernel/trace/bpf_trace.c | 264 +++
kernel/trace/trace.h | 3 +
kernel/trace/trace_events.c | 41 +-
kernel/trace/trace_events_filter.c | 72 +-
kernel/trace/trace_kprobe.c | 28 +
kernel/trace/trace_syscalls.c | 32 +
lib/test_bpf.c | 21 +
net/Kconfig | 1 +
net/core/filter.c | 2 +
samples/bpf/Makefile | 28 +
samples/bpf/bpf_helpers.h | 27 +
samples/bpf/bpf_load.c | 234 +++
samples/bpf/bpf_load.h | 26 +
samples/bpf/dropmon.c | 122 ++
samples/bpf/ex1_kern.c | 27 +
samples/bpf/ex1_user.c | 24 +
samples/bpf/ex2_kern.c | 73 +
samples/bpf/ex2_user.c | 94 +
samples/bpf/ex3_kern.c | 104 ++
samples/bpf/ex3_user.c | 149 ++
samples/bpf/libbpf.c | 89 +
samples/bpf/libbpf.h | 21 +
samples/bpf/test_verifier.c | 599 ++++++
tools/bpf/llvm/.gitignore | 54 +
tools/bpf/llvm/LICENSE.TXT | 70 +
tools/bpf/llvm/Makefile.rules | 641 +++++++
tools/bpf/llvm/README.txt | 23 +
tools/bpf/llvm/bld/Makefile | 27 +
tools/bpf/llvm/bld/Makefile.common | 14 +
tools/bpf/llvm/bld/Makefile.config | 124 ++
.../llvm/bld/include/llvm/Config/AsmParsers.def | 8 +
.../llvm/bld/include/llvm/Config/AsmPrinters.def | 9 +
.../llvm/bld/include/llvm/Config/Disassemblers.def | 8 +
tools/bpf/llvm/bld/include/llvm/Config/Targets.def | 9 +
.../bpf/llvm/bld/include/llvm/Support/DataTypes.h | 96 +
tools/bpf/llvm/bld/lib/Makefile | 11 +
.../llvm/bld/lib/Target/BPF/InstPrinter/Makefile | 10 +
.../llvm/bld/lib/Target/BPF/MCTargetDesc/Makefile | 11 +
tools/bpf/llvm/bld/lib/Target/BPF/Makefile | 17 +
.../llvm/bld/lib/Target/BPF/TargetInfo/Makefile | 10 +
tools/bpf/llvm/bld/lib/Target/Makefile | 11 +
tools/bpf/llvm/bld/tools/Makefile | 12 +
tools/bpf/llvm/bld/tools/llc/Makefile | 15 +
tools/bpf/llvm/lib/Target/BPF/BPF.h | 28 +
tools/bpf/llvm/lib/Target/BPF/BPF.td | 29 +
tools/bpf/llvm/lib/Target/BPF/BPFAsmPrinter.cpp | 100 +
tools/bpf/llvm/lib/Target/BPF/BPFCallingConv.td | 24 +
tools/bpf/llvm/lib/Target/BPF/BPFFrameLowering.cpp | 36 +
tools/bpf/llvm/lib/Target/BPF/BPFFrameLowering.h | 35 +
tools/bpf/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp | 182 ++
tools/bpf/llvm/lib/Target/BPF/BPFISelLowering.cpp | 683 +++++++
tools/bpf/llvm/lib/Target/BPF/BPFISelLowering.h | 105 ++
tools/bpf/llvm/lib/Target/BPF/BPFInstrFormats.td | 29 +
tools/bpf/llvm/lib/Target/BPF/BPFInstrInfo.cpp | 162 ++
tools/bpf/llvm/lib/Target/BPF/BPFInstrInfo.h | 53 +
tools/bpf/llvm/lib/Target/BPF/BPFInstrInfo.td | 498 +++++
tools/bpf/llvm/lib/Target/BPF/BPFMCInstLower.cpp | 77 +
tools/bpf/llvm/lib/Target/BPF/BPFMCInstLower.h | 40 +
tools/bpf/llvm/lib/Target/BPF/BPFRegisterInfo.cpp | 122 ++
tools/bpf/llvm/lib/Target/BPF/BPFRegisterInfo.h | 65 +
tools/bpf/llvm/lib/Target/BPF/BPFRegisterInfo.td | 39 +
tools/bpf/llvm/lib/Target/BPF/BPFSubtarget.cpp | 23 +
tools/bpf/llvm/lib/Target/BPF/BPFSubtarget.h | 33 +
tools/bpf/llvm/lib/Target/BPF/BPFTargetMachine.cpp | 66 +
tools/bpf/llvm/lib/Target/BPF/BPFTargetMachine.h | 69 +
.../lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp | 81 +
.../lib/Target/BPF/InstPrinter/BPFInstPrinter.h | 34 +
.../lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp | 89 +
.../llvm/lib/Target/BPF/MCTargetDesc/BPFBaseInfo.h | 33 +
.../Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp | 56 +
.../lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h | 34 +
.../Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp | 167 ++
.../Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp | 115 ++
.../lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h | 56 +
.../lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp | 13 +
tools/bpf/llvm/tools/llc/llc.cpp | 381 ++++
100 files changed, 10742 insertions(+), 302 deletions(-)
create mode 100644 include/linux/bpf.h
create mode 100644 include/trace/bpf_trace.h
create mode 100644 include/uapi/linux/bpf.h
create mode 100644 kernel/bpf/hashtab.c
create mode 100644 kernel/bpf/syscall.c
create mode 100644 kernel/bpf/verifier.c
create mode 100644 kernel/trace/bpf_trace.c
create mode 100644 samples/bpf/Makefile
create mode 100644 samples/bpf/bpf_helpers.h
create mode 100644 samples/bpf/bpf_load.c
create mode 100644 samples/bpf/bpf_load.h
create mode 100644 samples/bpf/dropmon.c
create mode 100644 samples/bpf/ex1_kern.c
create mode 100644 samples/bpf/ex1_user.c
create mode 100644 samples/bpf/ex2_kern.c
create mode 100644 samples/bpf/ex2_user.c
create mode 100644 samples/bpf/ex3_kern.c
create mode 100644 samples/bpf/ex3_user.c
create mode 100644 samples/bpf/libbpf.c
create mode 100644 samples/bpf/libbpf.h
create mode 100644 samples/bpf/test_verifier.c
create mode 100644 tools/bpf/llvm/.gitignore
create mode 100644 tools/bpf/llvm/LICENSE.TXT
create mode 100644 tools/bpf/llvm/Makefile.rules
create mode 100644 tools/bpf/llvm/README.txt
create mode 100644 tools/bpf/llvm/bld/Makefile
create mode 100644 tools/bpf/llvm/bld/Makefile.common
create mode 100644 tools/bpf/llvm/bld/Makefile.config
create mode 100644 tools/bpf/llvm/bld/include/llvm/Config/AsmParsers.def
create mode 100644 tools/bpf/llvm/bld/include/llvm/Config/AsmPrinters.def
create mode 100644 tools/bpf/llvm/bld/include/llvm/Config/Disassemblers.def
create mode 100644 tools/bpf/llvm/bld/include/llvm/Config/Targets.def
create mode 100644 tools/bpf/llvm/bld/include/llvm/Support/DataTypes.h
create mode 100644 tools/bpf/llvm/bld/lib/Makefile
create mode 100644 tools/bpf/llvm/bld/lib/Target/BPF/InstPrinter/Makefile
create mode 100644 tools/bpf/llvm/bld/lib/Target/BPF/MCTargetDesc/Makefile
create mode 100644 tools/bpf/llvm/bld/lib/Target/BPF/Makefile
create mode 100644 tools/bpf/llvm/bld/lib/Target/BPF/TargetInfo/Makefile
create mode 100644 tools/bpf/llvm/bld/lib/Target/Makefile
create mode 100644 tools/bpf/llvm/bld/tools/Makefile
create mode 100644 tools/bpf/llvm/bld/tools/llc/Makefile
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPF.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPF.td
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFCallingConv.td
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFFrameLowering.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFFrameLowering.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFISelDAGToDAG.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFISelLowering.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFISelLowering.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFInstrFormats.td
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFInstrInfo.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFInstrInfo.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFInstrInfo.td
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFMCInstLower.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFMCInstLower.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFRegisterInfo.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFRegisterInfo.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFRegisterInfo.td
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFSubtarget.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFSubtarget.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFTargetMachine.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/BPFTargetMachine.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/InstPrinter/BPFInstPrinter.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFBaseInfo.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFELFObjectWriter.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFMCAsmInfo.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFMCCodeEmitter.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.cpp
create mode 100644 tools/bpf/llvm/lib/Target/BPF/MCTargetDesc/BPFMCTargetDesc.h
create mode 100644 tools/bpf/llvm/lib/Target/BPF/TargetInfo/BPFTargetInfo.cpp
create mode 100644 tools/bpf/llvm/tools/llc/llc.cpp
--
1.7.9.5
^ permalink raw reply
* [PATCH RFC v7 net-next 01/28] net: filter: add "load 64-bit immediate" eBPF instruction
From: Alexei Starovoitov @ 2014-08-27 2:29 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Brendan Gregg, Namhyung Kim, H. Peter Anvin, Andrew Morton,
Kees Cook, linux-api, netdev, linux-kernel
In-Reply-To: <1409106582-10095-1-git-send-email-ast@plumgrid.com>
add BPF_LD_IMM64 instruction to load 64-bit immediate value into a register.
All previous instructions were 8-byte. This is first 16-byte instruction.
Two consecutive 'struct bpf_insn' blocks are interpreted as single instruction:
insn[0].code = BPF_LD | BPF_DW | BPF_IMM
insn[0].dst_reg = destination register
insn[0].imm = lower 32-bit
insn[1].code = 0
insn[1].imm = upper 32-bit
All unused fields must be zero.
Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM
which loads 32-bit immediate value into a register.
x64 JITs it as single 'movabsq %rax, imm64'
arm64 may JIT as sequence of four 'movk x0, #imm16, lsl #shift' insn
Note that old eBPF programs are binary compatible with new interpreter.
In the following patches this instruction is used to store eBPF map pointers:
BPF_LD_IMM64(R1, const_imm_map_ptr)
BPF_CALL(BPF_FUNC_map_lookup_elem)
and verifier is introduced to check validity of the programs.
Later LLVM compiler is using this insn as generic load of 64-bit immediate
constant and as a load of map pointer with relocation.
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
Documentation/networking/filter.txt | 8 +++++++-
arch/x86/net/bpf_jit_comp.c | 17 +++++++++++++++++
include/linux/filter.h | 18 ++++++++++++++++++
kernel/bpf/core.c | 5 +++++
lib/test_bpf.c | 21 +++++++++++++++++++++
5 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index c48a9704bda8..81916ab5d96f 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -951,7 +951,7 @@ Size modifier is one of ...
Mode modifier is one of:
- BPF_IMM 0x00 /* classic BPF only, reserved in eBPF */
+ BPF_IMM 0x00 /* used for 32-bit mov in classic BPF and 64-bit in eBPF */
BPF_ABS 0x20
BPF_IND 0x40
BPF_MEM 0x60
@@ -995,6 +995,12 @@ BPF_XADD | BPF_DW | BPF_STX: lock xadd *(u64 *)(dst_reg + off16) += src_reg
Where size is one of: BPF_B or BPF_H or BPF_W or BPF_DW. Note that 1 and
2 byte atomic increments are not supported.
+eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM which consists
+of two consecutive 'struct bpf_insn' 8-byte blocks and interpreted as single
+instruction that loads 64-bit immediate value into a dst_reg.
+Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM which loads
+32-bit immediate value into a register.
+
Testing
-------
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index b08a98c59530..98837147ee57 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -393,6 +393,23 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image,
EMIT1_off32(add_1reg(0xB8, dst_reg), imm32);
break;
+ case BPF_LD | BPF_IMM | BPF_DW:
+ if (insn[1].code != 0 || insn[1].src_reg != 0 ||
+ insn[1].dst_reg != 0 || insn[1].off != 0) {
+ /* verifier must catch invalid insns */
+ pr_err("invalid BPF_LD_IMM64 insn\n");
+ return -EINVAL;
+ }
+
+ /* movabsq %rax, imm64 */
+ EMIT2(add_1mod(0x48, dst_reg), add_1reg(0xB8, dst_reg));
+ EMIT(insn[0].imm, 4);
+ EMIT(insn[1].imm, 4);
+
+ insn++;
+ i++;
+ break;
+
/* dst %= src, dst /= src, dst %= imm32, dst /= imm32 */
case BPF_ALU | BPF_MOD | BPF_X:
case BPF_ALU | BPF_DIV | BPF_X:
diff --git a/include/linux/filter.h b/include/linux/filter.h
index a5227ab8ccb1..f3262b598262 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -161,6 +161,24 @@ enum {
.off = 0, \
.imm = IMM })
+/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
+#define BPF_LD_IMM64(DST, IMM) \
+ BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_DW | BPF_IMM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = (__u32) (IMM) }), \
+ ((struct bpf_insn) { \
+ .code = 0, /* zero is reserved opcode */ \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((__u64) (IMM)) >> 32 })
+
/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 7f0dbcbb34af..0434c2170f2b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -180,6 +180,7 @@ static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn)
[BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W,
[BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H,
[BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B,
+ [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW,
};
void *ptr;
int off;
@@ -239,6 +240,10 @@ select_insn:
ALU64_MOV_K:
DST = IMM;
CONT;
+ LD_IMM_DW:
+ DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32;
+ insn++;
+ CONT;
ALU64_ARSH_X:
(*(s64 *) &DST) >>= SRC;
CONT;
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index 8c66c6aace04..46ab1a7ef135 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -1735,6 +1735,27 @@ static struct bpf_test tests[] = {
{ },
{ { 1, 0 } },
},
+ {
+ "load 64-bit immediate",
+ .u.insns_int = {
+ BPF_LD_IMM64(R1, 0x567800001234L),
+ BPF_MOV64_REG(R2, R1),
+ BPF_MOV64_REG(R3, R2),
+ BPF_ALU64_IMM(BPF_RSH, R2, 32),
+ BPF_ALU64_IMM(BPF_LSH, R3, 32),
+ BPF_ALU64_IMM(BPF_RSH, R3, 32),
+ BPF_ALU64_IMM(BPF_MOV, R0, 0),
+ BPF_JMP_IMM(BPF_JEQ, R2, 0x5678, 1),
+ BPF_EXIT_INSN(),
+ BPF_JMP_IMM(BPF_JEQ, R3, 0x1234, 1),
+ BPF_EXIT_INSN(),
+ BPF_ALU64_IMM(BPF_MOV, R0, 1),
+ BPF_EXIT_INSN(),
+ },
+ INTERNAL,
+ { },
+ { { 0, 1 } }
+ },
};
static struct net_device dev;
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v7 net-next 02/28] net: filter: split filter.h and expose eBPF to user space
From: Alexei Starovoitov @ 2014-08-27 2:29 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Brendan Gregg, Namhyung Kim, H. Peter Anvin, Andrew Morton,
Kees Cook, linux-api, netdev, linux-kernel
In-Reply-To: <1409106582-10095-1-git-send-email-ast@plumgrid.com>
eBPF can be used from user space.
uapi/linux/bpf.h: eBPF instruction set definition
linux/filter.h: the rest
This patch only moves macro definitions, but practically it freezes existing
eBPF instruction set, though new instructions can still be added in the future.
These eBPF definitions cannot go into uapi/linux/filter.h, since the names
may conflict with existing applications.
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
include/linux/filter.h | 312 +------------------------------------------
include/uapi/linux/Kbuild | 1 +
include/uapi/linux/bpf.h | 321 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 323 insertions(+), 311 deletions(-)
create mode 100644 include/uapi/linux/bpf.h
diff --git a/include/linux/filter.h b/include/linux/filter.h
index f3262b598262..f04793474d16 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -9,322 +9,12 @@
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <uapi/linux/filter.h>
-
-/* Internally used and optimized filter representation with extended
- * instruction set based on top of classic BPF.
- */
-
-/* instruction classes */
-#define BPF_ALU64 0x07 /* alu mode in double word width */
-
-/* ld/ldx fields */
-#define BPF_DW 0x18 /* double word */
-#define BPF_XADD 0xc0 /* exclusive add */
-
-/* alu/jmp fields */
-#define BPF_MOV 0xb0 /* mov reg to reg */
-#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */
-
-/* change endianness of a register */
-#define BPF_END 0xd0 /* flags for endianness conversion: */
-#define BPF_TO_LE 0x00 /* convert to little-endian */
-#define BPF_TO_BE 0x08 /* convert to big-endian */
-#define BPF_FROM_LE BPF_TO_LE
-#define BPF_FROM_BE BPF_TO_BE
-
-#define BPF_JNE 0x50 /* jump != */
-#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */
-#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
-#define BPF_CALL 0x80 /* function call */
-#define BPF_EXIT 0x90 /* function return */
-
-/* Register numbers */
-enum {
- BPF_REG_0 = 0,
- BPF_REG_1,
- BPF_REG_2,
- BPF_REG_3,
- BPF_REG_4,
- BPF_REG_5,
- BPF_REG_6,
- BPF_REG_7,
- BPF_REG_8,
- BPF_REG_9,
- BPF_REG_10,
- __MAX_BPF_REG,
-};
-
-/* BPF has 10 general purpose 64-bit registers and stack frame. */
-#define MAX_BPF_REG __MAX_BPF_REG
-
-/* ArgX, context and stack frame pointer register positions. Note,
- * Arg1, Arg2, Arg3, etc are used as argument mappings of function
- * calls in BPF_CALL instruction.
- */
-#define BPF_REG_ARG1 BPF_REG_1
-#define BPF_REG_ARG2 BPF_REG_2
-#define BPF_REG_ARG3 BPF_REG_3
-#define BPF_REG_ARG4 BPF_REG_4
-#define BPF_REG_ARG5 BPF_REG_5
-#define BPF_REG_CTX BPF_REG_6
-#define BPF_REG_FP BPF_REG_10
-
-/* Additional register mappings for converted user programs. */
-#define BPF_REG_A BPF_REG_0
-#define BPF_REG_X BPF_REG_7
-#define BPF_REG_TMP BPF_REG_8
-
-/* BPF program can access up to 512 bytes of stack space. */
-#define MAX_BPF_STACK 512
-
-/* Helper macros for filter block array initializers. */
-
-/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
-
-#define BPF_ALU64_REG(OP, DST, SRC) \
- ((struct bpf_insn) { \
- .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = 0 })
-
-#define BPF_ALU32_REG(OP, DST, SRC) \
- ((struct bpf_insn) { \
- .code = BPF_ALU | BPF_OP(OP) | BPF_X, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = 0 })
-
-/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
-
-#define BPF_ALU64_IMM(OP, DST, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = 0, \
- .imm = IMM })
-
-#define BPF_ALU32_IMM(OP, DST, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ALU | BPF_OP(OP) | BPF_K, \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = 0, \
- .imm = IMM })
-
-/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
-
-#define BPF_ENDIAN(TYPE, DST, LEN) \
- ((struct bpf_insn) { \
- .code = BPF_ALU | BPF_END | BPF_SRC(TYPE), \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = 0, \
- .imm = LEN })
-
-/* Short form of mov, dst_reg = src_reg */
-
-#define BPF_MOV64_REG(DST, SRC) \
- ((struct bpf_insn) { \
- .code = BPF_ALU64 | BPF_MOV | BPF_X, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = 0 })
-
-#define BPF_MOV32_REG(DST, SRC) \
- ((struct bpf_insn) { \
- .code = BPF_ALU | BPF_MOV | BPF_X, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = 0 })
-
-/* Short form of mov, dst_reg = imm32 */
-
-#define BPF_MOV64_IMM(DST, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ALU64 | BPF_MOV | BPF_K, \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = 0, \
- .imm = IMM })
-
-#define BPF_MOV32_IMM(DST, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ALU | BPF_MOV | BPF_K, \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = 0, \
- .imm = IMM })
-
-/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
-#define BPF_LD_IMM64(DST, IMM) \
- BPF_LD_IMM64_RAW(DST, 0, IMM)
-
-#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_LD | BPF_DW | BPF_IMM, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = (__u32) (IMM) }), \
- ((struct bpf_insn) { \
- .code = 0, /* zero is reserved opcode */ \
- .dst_reg = 0, \
- .src_reg = 0, \
- .off = 0, \
- .imm = ((__u64) (IMM)) >> 32 })
-
-/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
-
-#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE), \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = IMM })
-
-#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ALU | BPF_MOV | BPF_SRC(TYPE), \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = IMM })
-
-/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
-
-#define BPF_LD_ABS(SIZE, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \
- .dst_reg = 0, \
- .src_reg = 0, \
- .off = 0, \
- .imm = IMM })
-
-/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */
-
-#define BPF_LD_IND(SIZE, SRC, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_LD | BPF_SIZE(SIZE) | BPF_IND, \
- .dst_reg = 0, \
- .src_reg = SRC, \
- .off = 0, \
- .imm = IMM })
-
-/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
-
-#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
- ((struct bpf_insn) { \
- .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = OFF, \
- .imm = 0 })
-
-/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
-
-#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
- ((struct bpf_insn) { \
- .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = OFF, \
- .imm = 0 })
-
-/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
-
-#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
- ((struct bpf_insn) { \
- .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = OFF, \
- .imm = IMM })
-
-/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
-
-#define BPF_JMP_REG(OP, DST, SRC, OFF) \
- ((struct bpf_insn) { \
- .code = BPF_JMP | BPF_OP(OP) | BPF_X, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = OFF, \
- .imm = 0 })
-
-/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
-
-#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
- ((struct bpf_insn) { \
- .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
- .dst_reg = DST, \
- .src_reg = 0, \
- .off = OFF, \
- .imm = IMM })
-
-/* Function call */
-
-#define BPF_EMIT_CALL(FUNC) \
- ((struct bpf_insn) { \
- .code = BPF_JMP | BPF_CALL, \
- .dst_reg = 0, \
- .src_reg = 0, \
- .off = 0, \
- .imm = ((FUNC) - __bpf_call_base) })
-
-/* Raw code statement block */
-
-#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
- ((struct bpf_insn) { \
- .code = CODE, \
- .dst_reg = DST, \
- .src_reg = SRC, \
- .off = OFF, \
- .imm = IMM })
-
-/* Program exit */
-
-#define BPF_EXIT_INSN() \
- ((struct bpf_insn) { \
- .code = BPF_JMP | BPF_EXIT, \
- .dst_reg = 0, \
- .src_reg = 0, \
- .off = 0, \
- .imm = 0 })
-
-#define bytes_to_bpf_size(bytes) \
-({ \
- int bpf_size = -EINVAL; \
- \
- if (bytes == sizeof(u8)) \
- bpf_size = BPF_B; \
- else if (bytes == sizeof(u16)) \
- bpf_size = BPF_H; \
- else if (bytes == sizeof(u32)) \
- bpf_size = BPF_W; \
- else if (bytes == sizeof(u64)) \
- bpf_size = BPF_DW; \
- \
- bpf_size; \
-})
+#include <uapi/linux/bpf.h>
/* Macro to invoke filter function. */
#define SK_RUN_FILTER(filter, ctx) \
(*filter->prog->bpf_func)(ctx, filter->prog->insnsi)
-struct bpf_insn {
- __u8 code; /* opcode */
- __u8 dst_reg:4; /* dest register */
- __u8 src_reg:4; /* source register */
- __s16 off; /* signed offset */
- __s32 imm; /* signed immediate constant */
-};
-
#ifdef CONFIG_COMPAT
/* A struct sock_filter is architecture independent. */
struct compat_sock_fprog {
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 24e9033f8b3f..fb3f7b675229 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -67,6 +67,7 @@ header-y += bfs_fs.h
header-y += binfmts.h
header-y += blkpg.h
header-y += blktrace_api.h
+header-y += bpf.h
header-y += bpqether.h
header-y += bsg.h
header-y += btrfs.h
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
new file mode 100644
index 000000000000..45a09b46c578
--- /dev/null
+++ b/include/uapi/linux/bpf.h
@@ -0,0 +1,321 @@
+/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#ifndef _UAPI__LINUX_BPF_H__
+#define _UAPI__LINUX_BPF_H__
+
+#include <linux/types.h>
+
+/* Extended instruction set based on top of classic BPF */
+
+/* instruction classes */
+#define BPF_ALU64 0x07 /* alu mode in double word width */
+
+/* ld/ldx fields */
+#define BPF_DW 0x18 /* double word */
+#define BPF_XADD 0xc0 /* exclusive add */
+
+/* alu/jmp fields */
+#define BPF_MOV 0xb0 /* mov reg to reg */
+#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */
+
+/* change endianness of a register */
+#define BPF_END 0xd0 /* flags for endianness conversion: */
+#define BPF_TO_LE 0x00 /* convert to little-endian */
+#define BPF_TO_BE 0x08 /* convert to big-endian */
+#define BPF_FROM_LE BPF_TO_LE
+#define BPF_FROM_BE BPF_TO_BE
+
+#define BPF_JNE 0x50 /* jump != */
+#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */
+#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
+#define BPF_CALL 0x80 /* function call */
+#define BPF_EXIT 0x90 /* function return */
+
+/* Register numbers */
+enum {
+ BPF_REG_0 = 0,
+ BPF_REG_1,
+ BPF_REG_2,
+ BPF_REG_3,
+ BPF_REG_4,
+ BPF_REG_5,
+ BPF_REG_6,
+ BPF_REG_7,
+ BPF_REG_8,
+ BPF_REG_9,
+ BPF_REG_10,
+ __MAX_BPF_REG,
+};
+
+/* BPF has 10 general purpose 64-bit registers and stack frame. */
+#define MAX_BPF_REG __MAX_BPF_REG
+
+/* ArgX, context and stack frame pointer register positions. Note,
+ * Arg1, Arg2, Arg3, etc are used as argument mappings of function
+ * calls in BPF_CALL instruction.
+ */
+#define BPF_REG_ARG1 BPF_REG_1
+#define BPF_REG_ARG2 BPF_REG_2
+#define BPF_REG_ARG3 BPF_REG_3
+#define BPF_REG_ARG4 BPF_REG_4
+#define BPF_REG_ARG5 BPF_REG_5
+#define BPF_REG_CTX BPF_REG_6
+#define BPF_REG_FP BPF_REG_10
+
+/* Additional register mappings for converted user programs. */
+#define BPF_REG_A BPF_REG_0
+#define BPF_REG_X BPF_REG_7
+#define BPF_REG_TMP BPF_REG_8
+
+/* BPF program can access up to 512 bytes of stack space. */
+#define MAX_BPF_STACK 512
+
+/* Helper macros for filter block array initializers. */
+
+/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
+
+#define BPF_ALU64_REG(OP, DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_ALU32_REG(OP, DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
+
+#define BPF_ALU64_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_ALU32_IMM(OP, DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
+
+#define BPF_ENDIAN(TYPE, DST, LEN) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_END | BPF_SRC(TYPE), \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = LEN })
+
+/* Short form of mov, dst_reg = src_reg */
+
+#define BPF_MOV64_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+#define BPF_MOV32_REG(DST, SRC) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = 0 })
+
+/* Short form of mov, dst_reg = imm32 */
+
+#define BPF_MOV64_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_MOV32_IMM(DST, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */
+#define BPF_LD_IMM64(DST, IMM) \
+ BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_DW | BPF_IMM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = (__u32) (IMM) }), \
+ ((struct bpf_insn) { \
+ .code = 0, /* zero is reserved opcode */ \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((__u64) (IMM)) >> 32 })
+
+/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */
+
+#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE), \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = IMM })
+
+#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ALU | BPF_MOV | BPF_SRC(TYPE), \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = IMM })
+
+/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
+
+#define BPF_LD_ABS(SIZE, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = IMM })
+
+/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */
+
+#define BPF_LD_IND(SIZE, SRC, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_LD | BPF_SIZE(SIZE) | BPF_IND, \
+ .dst_reg = 0, \
+ .src_reg = SRC, \
+ .off = 0, \
+ .imm = IMM })
+
+/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
+
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
+
+#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \
+ ((struct bpf_insn) { \
+ .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */
+
+#define BPF_JMP_REG(OP, DST, SRC, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_OP(OP) | BPF_X, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = 0 })
+
+/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_OP(OP) | BPF_K, \
+ .dst_reg = DST, \
+ .src_reg = 0, \
+ .off = OFF, \
+ .imm = IMM })
+
+/* Function call */
+
+#define BPF_EMIT_CALL(FUNC) \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_CALL, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = ((FUNC) - __bpf_call_base) })
+
+/* Raw code statement block */
+
+#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \
+ ((struct bpf_insn) { \
+ .code = CODE, \
+ .dst_reg = DST, \
+ .src_reg = SRC, \
+ .off = OFF, \
+ .imm = IMM })
+
+/* Program exit */
+
+#define BPF_EXIT_INSN() \
+ ((struct bpf_insn) { \
+ .code = BPF_JMP | BPF_EXIT, \
+ .dst_reg = 0, \
+ .src_reg = 0, \
+ .off = 0, \
+ .imm = 0 })
+
+#define bytes_to_bpf_size(bytes) \
+({ \
+ int bpf_size = -EINVAL; \
+ \
+ if (bytes == sizeof(u8)) \
+ bpf_size = BPF_B; \
+ else if (bytes == sizeof(u16)) \
+ bpf_size = BPF_H; \
+ else if (bytes == sizeof(u32)) \
+ bpf_size = BPF_W; \
+ else if (bytes == sizeof(u64)) \
+ bpf_size = BPF_DW; \
+ \
+ bpf_size; \
+})
+
+struct bpf_insn {
+ __u8 code; /* opcode */
+ __u8 dst_reg:4; /* dest register */
+ __u8 src_reg:4; /* source register */
+ __s16 off; /* signed offset */
+ __s32 imm; /* signed immediate constant */
+};
+
+#endif /* _UAPI__LINUX_BPF_H__ */
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v7 net-next 03/28] bpf: introduce syscall(BPF, ...) and BPF maps
From: Alexei Starovoitov @ 2014-08-27 2:29 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Brendan Gregg, Namhyung Kim, H. Peter Anvin, Andrew Morton,
Kees Cook, linux-api, netdev, linux-kernel
In-Reply-To: <1409106582-10095-1-git-send-email-ast@plumgrid.com>
BPF syscall is a demux for different BPF releated commands.
'maps' is a generic storage of different types for sharing data between kernel
and userspace.
The maps can be created from user space via BPF syscall:
- create a map with given type and attributes
fd = bpf(BPF_MAP_CREATE, union bpf_attr *attr, u32 size)
returns fd or negative error
- close(fd) deletes the map
Next patch allows userspace programs to populate/read maps that eBPF programs
are concurrently updating.
maps can have different types: hash, bloom filter, radix-tree, etc.
The map is defined by:
. type
. max number of elements
. key size in bytes
. value size in bytes
This patch establishes core infrastructure for BPF maps.
Next patches implement lookup/update and hashtable type.
More map types can be added in the future.
syscall is using 'union bpf_attr' to be backwards compatible with future
extensions. Different syscall commands will use different attributes.
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
Documentation/networking/filter.txt | 75 +++++++++++++++++
include/linux/bpf.h | 41 ++++++++++
include/uapi/linux/bpf.h | 24 ++++++
kernel/bpf/Makefile | 2 +-
kernel/bpf/syscall.c | 151 +++++++++++++++++++++++++++++++++++
5 files changed, 292 insertions(+), 1 deletion(-)
create mode 100644 include/linux/bpf.h
create mode 100644 kernel/bpf/syscall.c
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index 81916ab5d96f..30c142b58936 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -1001,6 +1001,81 @@ instruction that loads 64-bit immediate value into a dst_reg.
Classic BPF has similar instruction: BPF_LD | BPF_W | BPF_IMM which loads
32-bit immediate value into a register.
+eBPF maps
+---------
+'maps' is a generic storage of different types for sharing data between kernel
+and userspace.
+
+The maps are accessed from user space via BPF syscall, which has commands:
+- create a map with given type and attributes
+ map_fd = bpf(BPF_MAP_CREATE, union bpf_attr *attr, u32 size)
+ using attr->map_type, attr->key_size, attr->value_size, attr->max_entries
+ returns process-local file descriptor or negative error
+
+- lookup key in a given map
+ err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)
+ using attr->map_fd, attr->key, attr->value
+ returns zero and stores found elem into value or negative error
+
+- create or update key/value pair in a given map
+ err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)
+ using attr->map_fd, attr->key, attr->value
+ returns zero or negative error
+
+- find and delete element by key in a given map
+ err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)
+ using attr->map_fd, attr->key
+
+- to delete map: close(fd)
+ Exiting process will delete maps automatically
+
+userspace programs uses this API to create/populate/read maps that eBPF programs
+are concurrently updating.
+
+maps can have different types: hash, array, bloom filter, radix-tree, etc.
+
+The map is defined by:
+ . type
+ . max number of elements
+ . key size in bytes
+ . value size in bytes
+
+The maps are accesible from eBPF program with API:
+ void * bpf_map_lookup_elem(map_fd, void *key);
+ int bpf_map_update_elem(map_fd, void *key, void *value);
+ int bpf_map_delete_elem(map_fd, void *key);
+
+The kernel replaces process-local map_fd with kernel internal map pointer,
+while loading eBPF program.
+
+If eBPF verifier is configured to recognize extra calls in the program
+bpf_map_lookup_elem() and bpf_map_update_elem() then access to maps looks like:
+ ...
+ ptr_to_value = bpf_map_lookup_elem(map_fd, key)
+ access memory range [ptr_to_value, ptr_to_value + value_size_in_bytes)
+ ...
+ prepare key2 and value2 on stack of key_size and value_size
+ err = bpf_map_update_elem(map_fd, key2, value2)
+ ...
+
+eBPF program cannot create or delete maps
+(such calls will be unknown to verifier)
+
+During program loading the refcnt of used maps is incremented, so they don't get
+deleted while program is running
+
+bpf_map_update_elem() can fail if maximum number of elements reached.
+if key2 already exists, bpf_map_update_elem() replaces it with value2 atomically
+
+bpf_map_lookup_elem() returns NULL or ptr_to_value, so program must do
+if (ptr_to_value != NULL) check before accessing it.
+NULL means that element with given 'key' was not found.
+
+The verifier will check that the program accesses map elements within specified
+size. It will not let programs pass junk values to bpf_map_*_elem() functions,
+so these functions (implemented in C inside kernel) can safely access
+the pointers in all cases.
+
Testing
-------
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
new file mode 100644
index 000000000000..48014a71f0fe
--- /dev/null
+++ b/include/linux/bpf.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#ifndef _LINUX_BPF_H
+#define _LINUX_BPF_H 1
+
+#include <uapi/linux/bpf.h>
+#include <linux/workqueue.h>
+
+struct bpf_map;
+
+/* map is generic key/value storage optionally accesible by eBPF programs */
+struct bpf_map_ops {
+ /* funcs callable from userspace (via syscall) */
+ struct bpf_map *(*map_alloc)(union bpf_attr *attr);
+ void (*map_free)(struct bpf_map *);
+};
+
+struct bpf_map {
+ atomic_t refcnt;
+ enum bpf_map_type map_type;
+ u32 key_size;
+ u32 value_size;
+ u32 max_entries;
+ struct bpf_map_ops *ops;
+ struct work_struct work;
+};
+
+struct bpf_map_type_list {
+ struct list_head list_node;
+ struct bpf_map_ops *ops;
+ enum bpf_map_type type;
+};
+
+void bpf_register_map_type(struct bpf_map_type_list *tl);
+void bpf_map_put(struct bpf_map *map);
+
+#endif /* _LINUX_BPF_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 45a09b46c578..51dc51c898c6 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -318,4 +318,28 @@ struct bpf_insn {
__s32 imm; /* signed immediate constant */
};
+/* BPF syscall commands */
+enum bpf_cmd {
+ /* create a map with given type and attributes
+ * fd = bpf(BPF_MAP_CREATE, union bpf_attr *, u32 size)
+ * returns fd or negative error
+ * map is deleted when fd is closed
+ */
+ BPF_MAP_CREATE,
+};
+
+enum bpf_map_type {
+ BPF_MAP_TYPE_UNSPEC,
+};
+
+union bpf_attr {
+ struct { /* anonymous struct used by BPF_MAP_CREATE command */
+ enum bpf_map_type map_type;
+ __u32 key_size; /* size of key in bytes */
+ __u32 value_size; /* size of value in bytes */
+ __u32 max_entries; /* max number of entries in a map */
+#define BPF_MAP_CREATE_LAST_FIELD max_entries
+ };
+};
+
#endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/Makefile b/kernel/bpf/Makefile
index 6a71145e2769..e9f7334ed07a 100644
--- a/kernel/bpf/Makefile
+++ b/kernel/bpf/Makefile
@@ -1 +1 @@
-obj-y := core.o
+obj-y := core.o syscall.o
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
new file mode 100644
index 000000000000..989c17c35a62
--- /dev/null
+++ b/kernel/bpf/syscall.c
@@ -0,0 +1,151 @@
+/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <linux/bpf.h>
+#include <linux/syscalls.h>
+#include <linux/slab.h>
+#include <linux/anon_inodes.h>
+
+static LIST_HEAD(bpf_map_types);
+
+static struct bpf_map *find_and_alloc_map(union bpf_attr *attr)
+{
+ struct bpf_map_type_list *tl;
+ struct bpf_map *map;
+
+ list_for_each_entry(tl, &bpf_map_types, list_node) {
+ if (tl->type == attr->map_type) {
+ map = tl->ops->map_alloc(attr);
+ if (IS_ERR(map))
+ return map;
+ map->ops = tl->ops;
+ map->map_type = attr->map_type;
+ return map;
+ }
+ }
+ return ERR_PTR(-EINVAL);
+}
+
+/* boot time registration of different map implementations */
+void bpf_register_map_type(struct bpf_map_type_list *tl)
+{
+ list_add(&tl->list_node, &bpf_map_types);
+}
+
+/* called from workqueue */
+static void bpf_map_free_deferred(struct work_struct *work)
+{
+ struct bpf_map *map = container_of(work, struct bpf_map, work);
+
+ /* implementation dependent freeing */
+ map->ops->map_free(map);
+}
+
+/* decrement map refcnt and schedule it for freeing via workqueue
+ * (unrelying map implementation ops->map_free() might sleep)
+ */
+void bpf_map_put(struct bpf_map *map)
+{
+ if (atomic_dec_and_test(&map->refcnt)) {
+ INIT_WORK(&map->work, bpf_map_free_deferred);
+ schedule_work(&map->work);
+ }
+}
+
+static int bpf_map_release(struct inode *inode, struct file *filp)
+{
+ struct bpf_map *map = filp->private_data;
+
+ bpf_map_put(map);
+ return 0;
+}
+
+static const struct file_operations bpf_map_fops = {
+ .release = bpf_map_release,
+};
+
+#define CHECK_ATTR(CMD) \
+ memchr_inv((void *) &attr->CMD##_LAST_FIELD + \
+ sizeof(attr->CMD##_LAST_FIELD), 0, \
+ sizeof(*attr) - \
+ offsetof(union bpf_attr, CMD##_LAST_FIELD)) != NULL
+
+/* called via syscall */
+static int map_create(union bpf_attr *attr)
+{
+ struct bpf_map *map;
+ int err;
+
+ /* check that all unused fields are zero */
+ err = CHECK_ATTR(BPF_MAP_CREATE);
+ if (err)
+ return -EINVAL;
+
+ /* find map type and init map: hashtable vs rbtree vs bloom vs ... */
+ map = find_and_alloc_map(attr);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ atomic_set(&map->refcnt, 1);
+
+ err = anon_inode_getfd("bpf-map", &bpf_map_fops, map, O_RDWR | O_CLOEXEC);
+
+ if (err < 0)
+ /* failed to allocate fd */
+ goto free_map;
+
+ return err;
+
+free_map:
+ map->ops->map_free(map);
+ return err;
+}
+
+SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
+{
+ union bpf_attr *attr;
+ int err;
+
+ /* eBPF syscall is limited to root temporarily. This restriction will
+ * be lifted when verifier has enough mileage and security audit is
+ * clean. Note that tracing/networking analytics use cases will be
+ * turning off 'secure' mode of verifier, since they need to pass
+ * kernel data back to user space
+ */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ /* newer userspace cannot run with older kernel */
+ if (size > sizeof(*attr))
+ return -EINVAL;
+
+ attr = kzalloc(sizeof(*attr), GFP_USER);
+ if (!attr)
+ return -ENOMEM;
+
+ /* copy attributes from user space, may be less than sizeof(bpf_attr) */
+ err = -EFAULT;
+ if (copy_from_user(attr, uattr, size) != 0)
+ goto free_attr;
+
+ switch (cmd) {
+ case BPF_MAP_CREATE:
+ err = map_create(attr);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+free_attr:
+ kfree(attr);
+ return err;
+}
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v7 net-next 04/28] bpf: enable bpf syscall on x64 and i386
From: Alexei Starovoitov @ 2014-08-27 2:29 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Brendan Gregg, Namhyung Kim, H. Peter Anvin, Andrew Morton,
Kees Cook, linux-api, netdev, linux-kernel
In-Reply-To: <1409106582-10095-1-git-send-email-ast@plumgrid.com>
done as separate commit to ease conflict resolution
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
arch/x86/syscalls/syscall_32.tbl | 1 +
arch/x86/syscalls/syscall_64.tbl | 1 +
include/linux/syscalls.h | 3 ++-
include/uapi/asm-generic/unistd.h | 4 +++-
kernel/sys_ni.c | 3 +++
5 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl
index 028b78168d85..9fe1b5d002f0 100644
--- a/arch/x86/syscalls/syscall_32.tbl
+++ b/arch/x86/syscalls/syscall_32.tbl
@@ -363,3 +363,4 @@
354 i386 seccomp sys_seccomp
355 i386 getrandom sys_getrandom
356 i386 memfd_create sys_memfd_create
+357 i386 bpf sys_bpf
diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl
index 35dd922727b9..281150b539a2 100644
--- a/arch/x86/syscalls/syscall_64.tbl
+++ b/arch/x86/syscalls/syscall_64.tbl
@@ -327,6 +327,7 @@
318 common getrandom sys_getrandom
319 common memfd_create sys_memfd_create
320 common kexec_file_load sys_kexec_file_load
+321 common bpf sys_bpf
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 0f86d85a9ce4..bda9b81357cc 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -65,6 +65,7 @@ struct old_linux_dirent;
struct perf_event_attr;
struct file_handle;
struct sigaltstack;
+union bpf_attr;
#include <linux/types.h>
#include <linux/aio_abi.h>
@@ -875,5 +876,5 @@ asmlinkage long sys_seccomp(unsigned int op, unsigned int flags,
const char __user *uargs);
asmlinkage long sys_getrandom(char __user *buf, size_t count,
unsigned int flags);
-
+asmlinkage long sys_bpf(int cmd, union bpf_attr *attr, unsigned int size);
#endif
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 11d11bc5c78f..22749c134117 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -705,9 +705,11 @@ __SYSCALL(__NR_seccomp, sys_seccomp)
__SYSCALL(__NR_getrandom, sys_getrandom)
#define __NR_memfd_create 279
__SYSCALL(__NR_memfd_create, sys_memfd_create)
+#define __NR_bpf 280
+__SYSCALL(__NR_bpf, sys_bpf)
#undef __NR_syscalls
-#define __NR_syscalls 280
+#define __NR_syscalls 281
/*
* All syscalls below here should go away really,
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 391d4ddb6f4b..b4b5083f5f5e 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -218,3 +218,6 @@ cond_syscall(sys_kcmp);
/* operate on Secure Computing state */
cond_syscall(sys_seccomp);
+
+/* access BPF programs and maps */
+cond_syscall(sys_bpf);
--
1.7.9.5
^ permalink raw reply related
* [PATCH RFC v7 net-next 05/28] bpf: add lookup/update/delete/iterate methods to BPF maps
From: Alexei Starovoitov @ 2014-08-27 2:29 UTC (permalink / raw)
To: David S. Miller
Cc: Ingo Molnar, Linus Torvalds, Andy Lutomirski, Steven Rostedt,
Daniel Borkmann, Chema Gonzalez, Eric Dumazet, Peter Zijlstra,
Brendan Gregg, Namhyung Kim, H. Peter Anvin, Andrew Morton,
Kees Cook, linux-api, netdev, linux-kernel
In-Reply-To: <1409106582-10095-1-git-send-email-ast@plumgrid.com>
'maps' is a generic storage of different types for sharing data between kernel
and userspace.
The maps are accessed from user space via BPF syscall, which has commands:
- create a map with given type and attributes
fd = bpf(BPF_MAP_CREATE, union bpf_attr *attr, u32 size)
returns fd or negative error
- lookup key in a given map referenced by fd
err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)
using attr->map_fd, attr->key, attr->value
returns zero and stores found elem into value or negative error
- create or update key/value pair in a given map
err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)
using attr->map_fd, attr->key, attr->value
returns zero or negative error
- find and delete element by key in a given map
err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)
using attr->map_fd, attr->key
- iterate map elements (based on input key return next_key)
err = bpf(BPF_MAP_GET_NEXT_KEY, union bpf_attr *attr, u32 size)
using attr->map_fd, attr->key, attr->next_key
- close(fd) deletes the map
Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
---
include/linux/bpf.h | 8 ++
include/uapi/linux/bpf.h | 42 +++++++++
kernel/bpf/syscall.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 269 insertions(+)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 48014a71f0fe..2887f3f9da59 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -9,6 +9,7 @@
#include <uapi/linux/bpf.h>
#include <linux/workqueue.h>
+#include <linux/file.h>
struct bpf_map;
@@ -17,6 +18,12 @@ struct bpf_map_ops {
/* funcs callable from userspace (via syscall) */
struct bpf_map *(*map_alloc)(union bpf_attr *attr);
void (*map_free)(struct bpf_map *);
+ int (*map_get_next_key)(struct bpf_map *map, void *key, void *next_key);
+
+ /* funcs callable from userspace and from eBPF programs */
+ void *(*map_lookup_elem)(struct bpf_map *map, void *key);
+ int (*map_update_elem)(struct bpf_map *map, void *key, void *value);
+ int (*map_delete_elem)(struct bpf_map *map, void *key);
};
struct bpf_map {
@@ -37,5 +44,6 @@ struct bpf_map_type_list {
void bpf_register_map_type(struct bpf_map_type_list *tl);
void bpf_map_put(struct bpf_map *map);
+struct bpf_map *bpf_map_get(struct fd f);
#endif /* _LINUX_BPF_H */
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 51dc51c898c6..1602de6423b5 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -326,6 +326,35 @@ enum bpf_cmd {
* map is deleted when fd is closed
*/
BPF_MAP_CREATE,
+
+ /* lookup key in a given map
+ * err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)
+ * Using attr->map_fd, attr->key, attr->value
+ * returns zero and stores found elem into value
+ * or negative error
+ */
+ BPF_MAP_LOOKUP_ELEM,
+
+ /* create or update key/value pair in a given map
+ * err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)
+ * Using attr->map_fd, attr->key, attr->value
+ * returns zero or negative error
+ */
+ BPF_MAP_UPDATE_ELEM,
+
+ /* find and delete elem by key in a given map
+ * err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)
+ * Using attr->map_fd, attr->key
+ * returns zero or negative error
+ */
+ BPF_MAP_DELETE_ELEM,
+
+ /* lookup key in a given map and return next key
+ * err = bpf(BPF_MAP_GET_NEXT_KEY, union bpf_attr *attr, u32 size)
+ * Using attr->map_fd, attr->key, attr->next_key
+ * returns zero and stores next key or negative error
+ */
+ BPF_MAP_GET_NEXT_KEY,
};
enum bpf_map_type {
@@ -340,6 +369,19 @@ union bpf_attr {
__u32 max_entries; /* max number of entries in a map */
#define BPF_MAP_CREATE_LAST_FIELD max_entries
};
+
+ struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
+ int map_fd;
+ void __user *key;
+ union {
+ void __user *value;
+ void __user *next_key;
+ };
+#define BPF_MAP_LOOKUP_ELEM_LAST_FIELD value
+#define BPF_MAP_UPDATE_ELEM_LAST_FIELD value
+#define BPF_MAP_DELETE_ELEM_LAST_FIELD key
+#define BPF_MAP_GET_NEXT_KEY_LAST_FIELD next_key
+ };
};
#endif /* _UAPI__LINUX_BPF_H__ */
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 989c17c35a62..b863976741d4 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -13,6 +13,7 @@
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/anon_inodes.h>
+#include <linux/file.h>
static LIST_HEAD(bpf_map_types);
@@ -109,6 +110,212 @@ free_map:
return err;
}
+/* if error is returned, fd is released.
+ * On success caller should complete fd access with matching fdput()
+ */
+struct bpf_map *bpf_map_get(struct fd f)
+{
+ struct bpf_map *map;
+
+ if (!f.file)
+ return ERR_PTR(-EBADF);
+
+ if (f.file->f_op != &bpf_map_fops) {
+ fdput(f);
+ return ERR_PTR(-EINVAL);
+ }
+
+ map = f.file->private_data;
+
+ return map;
+}
+
+static int map_lookup_elem(union bpf_attr *attr)
+{
+ void __user *ukey = attr->key;
+ void __user *uvalue = attr->value;
+ int ufd = attr->map_fd;
+ struct fd f = fdget(ufd);
+ struct bpf_map *map;
+ void *key, *value;
+ int err;
+
+ if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM))
+ return -EINVAL;
+
+ map = bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ err = -ENOMEM;
+ key = kmalloc(map->key_size, GFP_USER);
+ if (!key)
+ goto err_put;
+
+ err = -EFAULT;
+ if (copy_from_user(key, ukey, map->key_size) != 0)
+ goto free_key;
+
+ err = -ESRCH;
+ rcu_read_lock();
+ value = map->ops->map_lookup_elem(map, key);
+ if (!value)
+ goto err_unlock;
+
+ err = -EFAULT;
+ if (copy_to_user(uvalue, value, map->value_size) != 0)
+ goto err_unlock;
+
+ err = 0;
+
+err_unlock:
+ rcu_read_unlock();
+free_key:
+ kfree(key);
+err_put:
+ fdput(f);
+ return err;
+}
+
+static int map_update_elem(union bpf_attr *attr)
+{
+ void __user *ukey = attr->key;
+ void __user *uvalue = attr->value;
+ int ufd = attr->map_fd;
+ struct fd f = fdget(ufd);
+ struct bpf_map *map;
+ void *key, *value;
+ int err;
+
+ if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM))
+ return -EINVAL;
+
+ map = bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ err = -ENOMEM;
+ key = kmalloc(map->key_size, GFP_USER);
+ if (!key)
+ goto err_put;
+
+ err = -EFAULT;
+ if (copy_from_user(key, ukey, map->key_size) != 0)
+ goto free_key;
+
+ err = -ENOMEM;
+ value = kmalloc(map->value_size, GFP_USER);
+ if (!value)
+ goto free_key;
+
+ err = -EFAULT;
+ if (copy_from_user(value, uvalue, map->value_size) != 0)
+ goto free_value;
+
+ /* eBPF program that use maps are running under rcu_read_lock(),
+ * therefore all map accessors rely on this fact, so do the same here
+ */
+ rcu_read_lock();
+ err = map->ops->map_update_elem(map, key, value);
+ rcu_read_unlock();
+
+free_value:
+ kfree(value);
+free_key:
+ kfree(key);
+err_put:
+ fdput(f);
+ return err;
+}
+
+static int map_delete_elem(union bpf_attr *attr)
+{
+ void __user *ukey = attr->key;
+ int ufd = attr->map_fd;
+ struct fd f = fdget(ufd);
+ struct bpf_map *map;
+ void *key;
+ int err;
+
+ if (CHECK_ATTR(BPF_MAP_DELETE_ELEM))
+ return -EINVAL;
+
+ map = bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ err = -ENOMEM;
+ key = kmalloc(map->key_size, GFP_USER);
+ if (!key)
+ goto err_put;
+
+ err = -EFAULT;
+ if (copy_from_user(key, ukey, map->key_size) != 0)
+ goto free_key;
+
+ rcu_read_lock();
+ err = map->ops->map_delete_elem(map, key);
+ rcu_read_unlock();
+
+free_key:
+ kfree(key);
+err_put:
+ fdput(f);
+ return err;
+}
+
+static int map_get_next_key(union bpf_attr *attr)
+{
+ void __user *ukey = attr->key;
+ void __user *unext_key = attr->next_key;
+ int ufd = attr->map_fd;
+ struct fd f = fdget(ufd);
+ struct bpf_map *map;
+ void *key, *next_key;
+ int err;
+
+ if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY))
+ return -EINVAL;
+
+ map = bpf_map_get(f);
+ if (IS_ERR(map))
+ return PTR_ERR(map);
+
+ err = -ENOMEM;
+ key = kmalloc(map->key_size, GFP_USER);
+ if (!key)
+ goto err_put;
+
+ err = -EFAULT;
+ if (copy_from_user(key, ukey, map->key_size) != 0)
+ goto free_key;
+
+ err = -ENOMEM;
+ next_key = kmalloc(map->key_size, GFP_USER);
+ if (!next_key)
+ goto free_key;
+
+ rcu_read_lock();
+ err = map->ops->map_get_next_key(map, key, next_key);
+ rcu_read_unlock();
+ if (err)
+ goto free_next_key;
+
+ err = -EFAULT;
+ if (copy_to_user(unext_key, next_key, map->key_size) != 0)
+ goto free_next_key;
+
+ err = 0;
+
+free_next_key:
+ kfree(next_key);
+free_key:
+ kfree(key);
+err_put:
+ fdput(f);
+ return err;
+}
+
SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size)
{
union bpf_attr *attr;
@@ -140,6 +347,18 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
case BPF_MAP_CREATE:
err = map_create(attr);
break;
+ case BPF_MAP_LOOKUP_ELEM:
+ err = map_lookup_elem(attr);
+ break;
+ case BPF_MAP_UPDATE_ELEM:
+ err = map_update_elem(attr);
+ break;
+ case BPF_MAP_DELETE_ELEM:
+ err = map_delete_elem(attr);
+ break;
+ case BPF_MAP_GET_NEXT_KEY:
+ err = map_get_next_key(attr);
+ break;
default:
err = -EINVAL;
break;
--
1.7.9.5
^ permalink raw reply related
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