* [PATCH 4/4] usbnet: smsc95xx: fix rx packet alignment
From: Ben Dooks @ 2018-10-02 9:26 UTC (permalink / raw)
To: netdev; +Cc: oneukum, davem, linux-usb, linux-kernel, linux-kernel, Ben Dooks
In-Reply-To: <20181002092645.1115-1-ben.dooks@codethink.co.uk>
The smsc95xx driver already takes into account the NET_IP_ALIGN
parameter when setting up the receive packet data, which means
we do not need to worry about aligning the packets in the usbnet
driver.
Adding the EVENT_NO_IP_ALIGN means that the IPv4 header is now
passed to the ip_rcv() routine with the start on an aligned address.
Tested on Raspberry Pi B3.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/net/usb/smsc95xx.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 46385a4b8b98..2b867523cd53 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1296,6 +1296,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->features |= NETIF_F_RXCSUM;
dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+ set_bit(EVENT_NO_IP_ALIGN, &dev->flags);
smsc95xx_init_mac_address(dev);
--
2.19.0
^ permalink raw reply related
* [PATCH 3/4] usbnet: smsc95xx: check for csum being in last four bytes
From: Ben Dooks @ 2018-10-02 9:26 UTC (permalink / raw)
To: netdev; +Cc: oneukum, davem, linux-usb, linux-kernel, linux-kernel, Ben Dooks
In-Reply-To: <20181002092645.1115-1-ben.dooks@codethink.co.uk>
The manual states that the checksum cannot lie in the last DWORD of the
transmission, so add a basic check for this and fall back to software
checksumming the packet.
This only seems to trigger for ACK packets with no options or data to
return to the other end, and the use of the tx-alignment option makes
it more likely to happen.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/net/usb/smsc95xx.c | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index d244357bf1ad..46385a4b8b98 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -2003,6 +2003,20 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
return (high_16 << 16) | low_16;
}
+/* The CSUM won't work if the checksum lies in the last 4 bytes of the
+ * transmission. This is fairly unlikely, only seems to trigger with some
+ * short TCP ACK packets sent.
+ *
+ * Note, this calculation should probably check for the alignment of the
+ * data as well, but a straight chec for csum being in the last four bytes
+ * of the packet should be ok for now.
+*/
+static bool smsc95xx_can_checksum(struct sk_buff *skb)
+{
+ unsigned int len = skb->len - skb_checksum_start_offset(skb);
+ return skb->csum_offset < (len - (4 + 1));
+}
+
static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags)
{
@@ -2031,7 +2045,8 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
}
if (csum) {
- if (skb->len <= 45) {
+ /* note, csum does not work if csum in last DWORD of packet */
+ if (skb->len <= 45 || !smsc95xx_can_checksum(skb)) {
/* workaround - hardware tx checksum does not work
* properly with extremely small packets */
long csstart = skb_checksum_start_offset(skb);
--
2.19.0
^ permalink raw reply related
* [PATCH 2/4] usbnet: smsc95xx: align tx-buffer to word
From: Ben Dooks @ 2018-10-02 9:26 UTC (permalink / raw)
To: netdev; +Cc: oneukum, davem, linux-usb, linux-kernel, linux-kernel, Ben Dooks
In-Reply-To: <20181002092645.1115-1-ben.dooks@codethink.co.uk>
The tegra driver requires alignment of the buffer, so try and
make this better by pushing the buffer start back to an word
aligned address. At the worst this makes memcpy() easier as
it is word aligned, at best it makes sure the usb can directly
map the buffer.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
[todo - make this configurable]
---
drivers/net/usb/Kconfig | 12 ++++++++++++
drivers/net/usb/smsc95xx.c | 22 ++++++++++++++++++++--
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index a32f1a446ce9..35bad8bd2e2a 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -360,6 +360,18 @@ config USB_NET_SMSC95XX_TURBO
driver's receive path. These can also be altered by the
turbo_mode module parameter.
+config USB_NET_SMSC95XX_TXALIGN
+ bool "Add bytes to align transmit buffers"
+ depends on USB_NET_SMSC95XX
+ default n
+ help
+ This option makes the tx buffers 32 bit aligned which might
+ help with systems that want tx data aligned to a 32 bit
+ boundary.
+
+ Using this option will mean there may be up to 3 bytes of
+ data per packet sent.
+
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index fe13bef9579e..d244357bf1ad 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -78,6 +78,10 @@ struct smsc95xx_priv {
struct usbnet *dev;
};
+static bool align_tx = IS_ENABLED(CONFIG_USB_NET_SMSC95XX_TXALIGN);
+module_param(align_tx, bool, 0644);
+MODULE_PARM_DESC(align_tx, "Align TX buffers to word boundaries");
+
static bool turbo_mode = IS_ENABLED(CONFIG_USB_NET_SMSC95XX_TURBO);
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
@@ -2005,10 +2009,18 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
bool csum = skb->ip_summed == CHECKSUM_PARTIAL;
int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
u32 tx_cmd_a, tx_cmd_b;
+ u32 data_len;
+ uintptr_t align = 0;
/* We do not advertise SG, so skbs should be already linearized */
BUG_ON(skb_shinfo(skb)->nr_frags);
+ if (IS_ENABLED(CONFIG_USB_NET_SMSC95XX_TXALIGN) && align_tx) {
+ align = (uintptr_t)skb->data & 3;
+ if (align)
+ overhead += 4 - align;
+ }
+
/* Make writable and expand header space by overhead if required */
if (skb_cow_head(skb, overhead)) {
/* Must deallocate here as returning NULL to indicate error
@@ -2037,16 +2049,22 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
}
}
+ data_len = skb->len;
+ if (align)
+ skb_push(skb, 4 - align);
+
skb_push(skb, 4);
- tx_cmd_b = (u32)(skb->len - 4);
+ tx_cmd_b = (u32)(data_len);
if (csum)
tx_cmd_b |= TX_CMD_B_CSUM_ENABLE;
cpu_to_le32s(&tx_cmd_b);
memcpy(skb->data, &tx_cmd_b, 4);
skb_push(skb, 4);
- tx_cmd_a = (u32)(skb->len - 8) | TX_CMD_A_FIRST_SEG_ |
+ tx_cmd_a = (u32)(data_len) | TX_CMD_A_FIRST_SEG_ |
TX_CMD_A_LAST_SEG_;
+ if (align)
+ tx_cmd_a |= (4 - align) << 16;
cpu_to_le32s(&tx_cmd_a);
memcpy(skb->data, &tx_cmd_a, 4);
--
2.19.0
^ permalink raw reply related
* [PATCH 1/4] usbnet: smsc95xx: add kconfig for turbo mode
From: Ben Dooks @ 2018-10-02 9:26 UTC (permalink / raw)
To: netdev; +Cc: oneukum, davem, linux-usb, linux-kernel, linux-kernel, Ben Dooks
In-Reply-To: <20181002092645.1115-1-ben.dooks@codethink.co.uk>
Add a configuration option for the default state of turbo mode
on the smsc95xx networking driver. Some systems it is better
to default this to off as it causes significant increases in
soft-irq load.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/net/usb/Kconfig | 9 +++++++++
drivers/net/usb/smsc95xx.c | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 418b0904cecb..a32f1a446ce9 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -351,6 +351,15 @@ config USB_NET_SMSC95XX
This option adds support for SMSC LAN95XX based USB 2.0
10/100 Ethernet adapters.
+config USB_NET_SMSC95XX_TURBO
+ bool "Use turbo receive mode by default"
+ depends on USB_NET_SMSC95XX
+ default y
+ help
+ This options sets the default turbo mode settings for the
+ driver's receive path. These can also be altered by the
+ turbo_mode module parameter.
+
config USB_NET_GL620A
tristate "GeneSys GL620USB-A based cables"
depends on USB_USBNET
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 06b4d290784d..fe13bef9579e 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -78,7 +78,7 @@ struct smsc95xx_priv {
struct usbnet *dev;
};
-static bool turbo_mode = true;
+static bool turbo_mode = IS_ENABLED(CONFIG_USB_NET_SMSC95XX_TURBO);
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
--
2.19.0
^ permalink raw reply related
* SMSC95XX driver updates
From: Ben Dooks @ 2018-10-02 9:26 UTC (permalink / raw)
To: netdev; +Cc: oneukum, davem, linux-usb, linux-kernel, linux-kernel
I have been doing some work with tegra3 systems which have a smsc9512
USB network device on them. A couple of issues we found with alignment
of the data (both receive and transmit) and an issue where the automatic
transmit checksum failed.
^ permalink raw reply
* Re: [PATCH net] inet: frags: rework rhashtable dismantle
From: Eric Dumazet @ 2018-10-02 1:54 UTC (permalink / raw)
To: Herbert Xu; +Cc: David Miller, netdev, Eric Dumazet, Thomas Graf
In-Reply-To: <20181002005841.pgusxxfk6hsl5bg4@gondor.apana.org.au>
On Mon, Oct 1, 2018 at 5:58 PM Herbert Xu <herbert@gondor.apana.org.au> wrote:
> The walk interface was designed to handle read-only iteration
> through the hash table. While this probably works since the
> actual freeing is delayed by RCU, it seems to be rather fragile.
>
> How about using the dead flag but instead of putting it in the
> rhashtable put it in netns_frags and have the timers check on that
> before calling rhashtable_remove?
Sure, I will send a new version, thanks.
^ permalink raw reply
* Re: [PATCH net-next] rtnetlink: fix rtnl_fdb_dump() for shorter family headers
From: Mauricio Faria de Oliveira @ 2018-10-02 1:50 UTC (permalink / raw)
To: David Ahern; +Cc: netdev, davem
In-Reply-To: <CAO9xwp1fJzU6ima5KG6crSd6U9QSsJQCOx98iVqiD5Nq5ms7Fw@mail.gmail.com>
On Mon, Oct 1, 2018 at 12:38 PM Mauricio Faria de Oliveira
<mfo@canonical.com> wrote:
> Ok, thanks for your suggestions.
> I'll do some research/learning on them, and give it a try for a v2.
FYI, that is "[PATCH v2 net-next] rtnetlink: fix rtnl_fdb_dump() for
ndmsg header".
BTW, could please advise whether this should be net or net-next? It's a bug fix,
but it's late in the cycle, and this is not urgent (the problem has been around
since v4.12), so not sure it's really needed for v4.19.
Thanks,
--
Mauricio Faria de Oliveira
^ permalink raw reply
* [PATCH v2 net-next] rtnetlink: fix rtnl_fdb_dump() for ndmsg header
From: Mauricio Faria de Oliveira @ 2018-10-02 1:46 UTC (permalink / raw)
To: netdev; +Cc: davem, dsahern
Currently, rtnl_fdb_dump() assumes the family header is 'struct ifinfomsg',
which is not always true -- 'struct ndmsg' is used by iproute2 ('ip neigh').
The problem is, the function bails out early if nlmsg_parse() fails, which
does occur for iproute2 usage of 'struct ndmsg' because the payload length
is shorter than the family header alone (as 'struct ifinfomsg' is assumed).
This breaks backward compatibility with userspace -- nothing is sent back.
Some examples with iproute2 and netlink library for go [1]:
1) $ bridge fdb show
33:33:00:00:00:01 dev ens3 self permanent
01:00:5e:00:00:01 dev ens3 self permanent
33:33:ff:15:98:30 dev ens3 self permanent
This one works, as it uses 'struct ifinfomsg'.
fdb_show() @ iproute2/bridge/fdb.c
"""
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
...
if (rtnl_dump_request(&rth, RTM_GETNEIGH, [...]
"""
2) $ ip --family bridge neigh
RTNETLINK answers: Invalid argument
Dump terminated
This one fails, as it uses 'struct ndmsg'.
do_show_or_flush() @ iproute2/ip/ipneigh.c
"""
.n.nlmsg_type = RTM_GETNEIGH,
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
"""
3) $ ./neighlist
< no output >
This one fails, as it uses 'struct ndmsg'-based.
neighList() @ netlink/neigh_linux.go
"""
req := h.newNetlinkRequest(unix.RTM_GETNEIGH, [...]
msg := Ndmsg{
"""
The actual breakage was introduced by commit 0ff50e83b512 ("net: rtnetlink:
bail out from rtnl_fdb_dump() on parse error"), because nlmsg_parse() fails
if the payload length (with the _actual_ family header) is less than the
family header length alone (which is assumed, in parameter 'hdrlen').
This is true in the examples above with struct ndmsg, with size and payload
length shorter than struct ifinfomsg.
However, that commit just intends to fix something under the assumption the
family header is indeed an 'struct ifinfomsg' - by preventing access to the
payload as such (via 'ifm' pointer) if the payload length is not sufficient
to actually contain it.
The assumption was introduced by commit 5e6d24358799 ("bridge: netlink dump
interface at par with brctl"), to support iproute2's 'bridge fdb' command
(not 'ip neigh') which indeed uses 'struct ifinfomsg', thus is not broken.
So, in order to unbreak the 'struct ndmsg' family headers and still allow
'struct ifinfomsg' to continue to work, check for the known message sizes
used with 'struct ndmsg' in iproute2 (with zero or one attribute which is
not used in this function anyway) then do not parse the data as ifinfomsg.
Same examples with this patch applied (or revert/before the original fix):
$ bridge fdb show
33:33:00:00:00:01 dev ens3 self permanent
01:00:5e:00:00:01 dev ens3 self permanent
33:33:ff:15:98:30 dev ens3 self permanent
$ ip --family bridge neigh
dev ens3 lladdr 33:33:00:00:00:01 PERMANENT
dev ens3 lladdr 01:00:5e:00:00:01 PERMANENT
dev ens3 lladdr 33:33:ff:15:98:30 PERMANENT
$ ./neighlist
netlink.Neigh{LinkIndex:2, Family:7, State:128, Type:0, Flags:2, IP:net.IP(nil), HardwareAddr:net.HardwareAddr{0x33, 0x33, 0x0, 0x0, 0x0, 0x1}, LLIPAddr:net.IP(nil), Vlan:0, VNI:0}
netlink.Neigh{LinkIndex:2, Family:7, State:128, Type:0, Flags:2, IP:net.IP(nil), HardwareAddr:net.HardwareAddr{0x1, 0x0, 0x5e, 0x0, 0x0, 0x1}, LLIPAddr:net.IP(nil), Vlan:0, VNI:0}
netlink.Neigh{LinkIndex:2, Family:7, State:128, Type:0, Flags:2, IP:net.IP(nil), HardwareAddr:net.HardwareAddr{0x33, 0x33, 0xff, 0x15, 0x98, 0x30}, LLIPAddr:net.IP(nil), Vlan:0, VNI:0}
Tested on mainline (v4.19-rc6) and net-next (3bd09b05b068).
References:
[1] netlink library for go (test-case)
https://github.com/vishvananda/netlink
$ cat ~/go/src/neighlist/main.go
package main
import ("fmt"; "syscall"; "github.com/vishvananda/netlink")
func main() {
neighs, _ := netlink.NeighList(0, syscall.AF_BRIDGE)
for _, neigh := range neighs { fmt.Printf("%#v\n", neigh) }
}
$ export GOPATH=~/go
$ go get github.com/vishvananda/netlink
$ go build neighlist
$ ~/go/src/neighlist/neighlist
Thanks to David Ahern for suggestions to improve this patch.
Fixes: 0ff50e83b512 ("net: rtnetlink: bail out from rtnl_fdb_dump() on parse error")
Fixes: 5e6d24358799 ("bridge: netlink dump interface at par with brctl")
Reported-by: Aidan Obley <aobley@pivotal.io>
Signed-off-by: Mauricio Faria de Oliveira <mfo@canonical.com>
---
v2: Change logic to check msg size for ndmsg with optional attribute.
Thanks: David Ahern <dsahern@gmail.com>
net/core/rtnetlink.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 60c928894a78..6633f245fce5 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3744,16 +3744,27 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
int err = 0;
int fidx = 0;
- err = nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb,
- IFLA_MAX, ifla_policy, NULL);
- if (err < 0) {
- return -EINVAL;
- } else if (err == 0) {
- if (tb[IFLA_MASTER])
- br_idx = nla_get_u32(tb[IFLA_MASTER]);
- }
+ /* A hack to preserve kernel<->userspace interface.
+ * Before Linux v4.12 this code accepted ndmsg since iproute2 v3.3.0.
+ * However, ndmsg is shorter than ifinfomsg thus nlmsg_parse() bails.
+ * So, check for ndmsg with an optional u32 attribute (not used here).
+ * Fortunately these sizes don't conflict with the size of ifinfomsg
+ * with an optional attribute.
+ */
+ if (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) &&
+ (nlmsg_len(cb->nlh) != sizeof(struct ndmsg) +
+ nla_attr_size(sizeof(u32)))) {
+ err = nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb,
+ IFLA_MAX, ifla_policy, NULL);
+ if (err < 0) {
+ return -EINVAL;
+ } else if (err == 0) {
+ if (tb[IFLA_MASTER])
+ br_idx = nla_get_u32(tb[IFLA_MASTER]);
+ }
- brport_idx = ifm->ifi_index;
+ brport_idx = ifm->ifi_index;
+ }
if (br_idx) {
br_dev = __dev_get_by_index(net, br_idx);
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next 3/3] nfp: bpf: allow control message sizing for map ops
From: Jakub Kicinski @ 2018-10-02 1:30 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: netdev, oss-drivers, Jakub Kicinski
In-Reply-To: <20181002013034.8144-1-jakub.kicinski@netronome.com>
In current ABI the size of the messages carrying map elements was
statically defined to at most 16 words of key and 16 words of value
(NFP word is 4 bytes). We should not make this assumption and use
the max key and value sizes from the BPF capability instead.
To make sure old kernels don't get surprised with larger (or smaller)
messages bump the FW ABI version to 3 when key/value size is different
than 16 words.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/bpf/cmsg.c | 71 ++++++++++++++++---
drivers/net/ethernet/netronome/nfp/bpf/fw.h | 10 +--
drivers/net/ethernet/netronome/nfp/bpf/main.c | 11 ++-
drivers/net/ethernet/netronome/nfp/bpf/main.h | 7 ++
.../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 1 -
5 files changed, 83 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
index 2572a4b91c7c..fdcd2bc98916 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/cmsg.c
@@ -89,15 +89,32 @@ nfp_bpf_cmsg_alloc(struct nfp_app_bpf *bpf, unsigned int size)
return skb;
}
+static unsigned int
+nfp_bpf_cmsg_map_req_size(struct nfp_app_bpf *bpf, unsigned int n)
+{
+ unsigned int size;
+
+ size = sizeof(struct cmsg_req_map_op);
+ size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n;
+
+ return size;
+}
+
static struct sk_buff *
nfp_bpf_cmsg_map_req_alloc(struct nfp_app_bpf *bpf, unsigned int n)
+{
+ return nfp_bpf_cmsg_alloc(bpf, nfp_bpf_cmsg_map_req_size(bpf, n));
+}
+
+static unsigned int
+nfp_bpf_cmsg_map_reply_size(struct nfp_app_bpf *bpf, unsigned int n)
{
unsigned int size;
- size = sizeof(struct cmsg_req_map_op);
- size += sizeof(struct cmsg_key_value_pair) * n;
+ size = sizeof(struct cmsg_reply_map_op);
+ size += (bpf->cmsg_key_sz + bpf->cmsg_val_sz) * n;
- return nfp_bpf_cmsg_alloc(bpf, size);
+ return size;
}
static u8 nfp_bpf_cmsg_get_type(struct sk_buff *skb)
@@ -338,6 +355,34 @@ void nfp_bpf_ctrl_free_map(struct nfp_app_bpf *bpf, struct nfp_bpf_map *nfp_map)
dev_consume_skb_any(skb);
}
+static void *
+nfp_bpf_ctrl_req_key(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req,
+ unsigned int n)
+{
+ return &req->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n];
+}
+
+static void *
+nfp_bpf_ctrl_req_val(struct nfp_app_bpf *bpf, struct cmsg_req_map_op *req,
+ unsigned int n)
+{
+ return &req->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n];
+}
+
+static void *
+nfp_bpf_ctrl_reply_key(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply,
+ unsigned int n)
+{
+ return &reply->data[bpf->cmsg_key_sz * n + bpf->cmsg_val_sz * n];
+}
+
+static void *
+nfp_bpf_ctrl_reply_val(struct nfp_app_bpf *bpf, struct cmsg_reply_map_op *reply,
+ unsigned int n)
+{
+ return &reply->data[bpf->cmsg_key_sz * (n + 1) + bpf->cmsg_val_sz * n];
+}
+
static int
nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap,
enum nfp_bpf_cmsg_type op,
@@ -366,12 +411,13 @@ nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap,
/* Copy inputs */
if (key)
- memcpy(&req->elem[0].key, key, map->key_size);
+ memcpy(nfp_bpf_ctrl_req_key(bpf, req, 0), key, map->key_size);
if (value)
- memcpy(&req->elem[0].value, value, map->value_size);
+ memcpy(nfp_bpf_ctrl_req_val(bpf, req, 0), value,
+ map->value_size);
skb = nfp_bpf_cmsg_communicate(bpf, skb, op,
- sizeof(*reply) + sizeof(*reply->elem));
+ nfp_bpf_cmsg_map_reply_size(bpf, 1));
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -382,9 +428,11 @@ nfp_bpf_ctrl_entry_op(struct bpf_offloaded_map *offmap,
/* Copy outputs */
if (out_key)
- memcpy(out_key, &reply->elem[0].key, map->key_size);
+ memcpy(out_key, nfp_bpf_ctrl_reply_key(bpf, reply, 0),
+ map->key_size);
if (out_value)
- memcpy(out_value, &reply->elem[0].value, map->value_size);
+ memcpy(out_value, nfp_bpf_ctrl_reply_val(bpf, reply, 0),
+ map->value_size);
dev_consume_skb_any(skb);
@@ -428,6 +476,13 @@ int nfp_bpf_ctrl_getnext_entry(struct bpf_offloaded_map *offmap,
key, NULL, 0, next_key, NULL);
}
+unsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf)
+{
+ return max3((unsigned int)NFP_NET_DEFAULT_MTU,
+ nfp_bpf_cmsg_map_req_size(bpf, 1),
+ nfp_bpf_cmsg_map_reply_size(bpf, 1));
+}
+
void nfp_bpf_ctrl_msg_rx(struct nfp_app *app, struct sk_buff *skb)
{
struct nfp_app_bpf *bpf = app->priv;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
index 58bad868bb6f..813644e90b27 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
@@ -99,6 +99,7 @@ enum nfp_bpf_cmsg_type {
#define CMSG_TYPE_MAP_REPLY_BIT 7
#define __CMSG_REPLY(req) (BIT(CMSG_TYPE_MAP_REPLY_BIT) | (req))
+/* BPF ABIv2 fixed-length control message fields */
#define CMSG_MAP_KEY_LW 16
#define CMSG_MAP_VALUE_LW 16
@@ -148,24 +149,19 @@ struct cmsg_reply_map_free_tbl {
__be32 count;
};
-struct cmsg_key_value_pair {
- __be32 key[CMSG_MAP_KEY_LW];
- __be32 value[CMSG_MAP_VALUE_LW];
-};
-
struct cmsg_req_map_op {
struct cmsg_hdr hdr;
__be32 tid;
__be32 count;
__be32 flags;
- struct cmsg_key_value_pair elem[0];
+ u8 data[0];
};
struct cmsg_reply_map_op {
struct cmsg_reply_map_simple reply_hdr;
__be32 count;
__be32 resv;
- struct cmsg_key_value_pair elem[0];
+ u8 data[0];
};
struct cmsg_bpf_event {
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 1f79246765d1..d9d37aa860e0 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -356,7 +356,7 @@ nfp_bpf_parse_cap_abi_version(struct nfp_app_bpf *bpf, void __iomem *value,
}
bpf->abi_version = readl(value);
- if (bpf->abi_version != 2) {
+ if (bpf->abi_version < 2 || bpf->abi_version > 3) {
nfp_warn(bpf->app->cpp, "unsupported BPF ABI version: %d\n",
bpf->abi_version);
bpf->abi_version = 0;
@@ -486,6 +486,15 @@ static int nfp_bpf_init(struct nfp_app *app)
if (err)
goto err_free_neutral_maps;
+ if (bpf->abi_version < 3) {
+ bpf->cmsg_key_sz = CMSG_MAP_KEY_LW * 4;
+ bpf->cmsg_val_sz = CMSG_MAP_VALUE_LW * 4;
+ } else {
+ bpf->cmsg_key_sz = bpf->maps.max_key_sz;
+ bpf->cmsg_val_sz = bpf->maps.max_val_sz;
+ app->ctrl_mtu = nfp_bpf_ctrl_cmsg_mtu(bpf);
+ }
+
bpf->bpf_dev = bpf_offload_dev_create();
err = PTR_ERR_OR_ZERO(bpf->bpf_dev);
if (err)
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index 62cdb183efdb..792ebc4081a3 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -121,6 +121,9 @@ enum pkt_vec {
* @cmsg_replies: received cmsg replies waiting to be consumed
* @cmsg_wq: work queue for waiting for cmsg replies
*
+ * @cmsg_key_sz: size of key in cmsg element array
+ * @cmsg_val_sz: size of value in cmsg element array
+ *
* @map_list: list of offloaded maps
* @maps_in_use: number of currently offloaded maps
* @map_elems_in_use: number of elements allocated to offloaded maps
@@ -166,6 +169,9 @@ struct nfp_app_bpf {
struct sk_buff_head cmsg_replies;
struct wait_queue_head cmsg_wq;
+ unsigned int cmsg_key_sz;
+ unsigned int cmsg_val_sz;
+
struct list_head map_list;
unsigned int maps_in_use;
unsigned int map_elems_in_use;
@@ -496,6 +502,7 @@ nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv);
+unsigned int nfp_bpf_ctrl_cmsg_mtu(struct nfp_app_bpf *bpf);
long long int
nfp_bpf_ctrl_alloc_map(struct nfp_app_bpf *bpf, struct bpf_map *map);
void
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
index a51490747689..863ca04fffbf 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h
@@ -264,7 +264,6 @@
* %NFP_NET_CFG_BPF_ADDR: DMA address of the buffer with JITed BPF code
*/
#define NFP_NET_CFG_BPF_ABI 0x0080
-#define NFP_NET_BPF_ABI 2
#define NFP_NET_CFG_BPF_CAP 0x0081
#define NFP_NET_BPF_CAP_RELO (1 << 0) /* seamless reload */
#define NFP_NET_CFG_BPF_MAX_LEN 0x0082
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next 2/3] nfp: allow apps to request larger MTU on control vNIC
From: Jakub Kicinski @ 2018-10-02 1:30 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: netdev, oss-drivers, Jakub Kicinski
In-Reply-To: <20181002013034.8144-1-jakub.kicinski@netronome.com>
Some apps may want to have higher MTU on the control vNIC/queue.
Allow them to set the requested MTU at init time.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/nfp_app.h | 4 ++++
.../net/ethernet/netronome/nfp/nfp_net_common.c | 14 ++++++++++++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h
index 4e1eb3395648..c896eb8f87a1 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h
@@ -40,6 +40,8 @@
#include "nfp_net_repr.h"
+#define NFP_APP_CTRL_MTU_MAX U32_MAX
+
struct bpf_prog;
struct net_device;
struct netdev_bpf;
@@ -178,6 +180,7 @@ struct nfp_app_type {
* @ctrl: pointer to ctrl vNIC struct
* @reprs: array of pointers to representors
* @type: pointer to const application ops and info
+ * @ctrl_mtu: MTU to set on the control vNIC (set in .init())
* @priv: app-specific priv data
*/
struct nfp_app {
@@ -189,6 +192,7 @@ struct nfp_app {
struct nfp_reprs __rcu *reprs[NFP_REPR_TYPE_MAX + 1];
const struct nfp_app_type *type;
+ unsigned int ctrl_mtu;
void *priv;
};
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index d05e37fcc1b2..8e8dc0db2493 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -3877,10 +3877,20 @@ int nfp_net_init(struct nfp_net *nn)
return err;
/* Set default MTU and Freelist buffer size */
- if (nn->max_mtu < NFP_NET_DEFAULT_MTU)
+ if (!nfp_net_is_data_vnic(nn) && nn->app->ctrl_mtu) {
+ if (nn->app->ctrl_mtu <= nn->max_mtu) {
+ nn->dp.mtu = nn->app->ctrl_mtu;
+ } else {
+ if (nn->app->ctrl_mtu != NFP_APP_CTRL_MTU_MAX)
+ nn_warn(nn, "app requested MTU above max supported %u > %u\n",
+ nn->app->ctrl_mtu, nn->max_mtu);
+ nn->dp.mtu = nn->max_mtu;
+ }
+ } else if (nn->max_mtu < NFP_NET_DEFAULT_MTU) {
nn->dp.mtu = nn->max_mtu;
- else
+ } else {
nn->dp.mtu = NFP_NET_DEFAULT_MTU;
+ }
nn->dp.fl_bufsz = nfp_net_calc_fl_bufsz(&nn->dp);
if (nfp_app_ctrl_uses_data_vnics(nn->app))
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next 1/3] nfp: bpf: parse global BPF ABI version capability
From: Jakub Kicinski @ 2018-10-02 1:30 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: netdev, oss-drivers, Jakub Kicinski
In-Reply-To: <20181002013034.8144-1-jakub.kicinski@netronome.com>
Up until now we only had per-vNIC BPF ABI version capabilities,
which are slightly awkward to use because bulk of the resources
and configuration does not relate to any particular vNIC. Add
a new capability for global ABI version and check the per-vNIC
version are equal to it. Assume the ABI version 2 if no explicit
version capability is present.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
drivers/net/ethernet/netronome/nfp/bpf/fw.h | 1 +
drivers/net/ethernet/netronome/nfp/bpf/main.c | 43 +++++++++++++++++--
drivers/net/ethernet/netronome/nfp/bpf/main.h | 4 ++
3 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/fw.h b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
index e4f9b7ec8528..58bad868bb6f 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/fw.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/fw.h
@@ -52,6 +52,7 @@ enum bpf_cap_tlv_type {
NFP_BPF_CAP_TYPE_RANDOM = 4,
NFP_BPF_CAP_TYPE_QUEUE_SELECT = 5,
NFP_BPF_CAP_TYPE_ADJUST_TAIL = 6,
+ NFP_BPF_CAP_TYPE_ABI_VERSION = 7,
};
struct nfp_bpf_cap_tlv_func {
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
index 970af07f4656..1f79246765d1 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -54,11 +54,14 @@ const struct rhashtable_params nfp_bpf_maps_neutral_params = {
static bool nfp_net_ebpf_capable(struct nfp_net *nn)
{
#ifdef __LITTLE_ENDIAN
- if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
- nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
- return true;
-#endif
+ struct nfp_app_bpf *bpf = nn->app->priv;
+
+ return nn->cap & NFP_NET_CFG_CTRL_BPF &&
+ bpf->abi_version &&
+ nn_readb(nn, NFP_NET_CFG_BPF_ABI) == bpf->abi_version;
+#else
return false;
+#endif
}
static int
@@ -342,6 +345,26 @@ nfp_bpf_parse_cap_adjust_tail(struct nfp_app_bpf *bpf, void __iomem *value,
return 0;
}
+static int
+nfp_bpf_parse_cap_abi_version(struct nfp_app_bpf *bpf, void __iomem *value,
+ u32 length)
+{
+ if (length < 4) {
+ nfp_err(bpf->app->cpp, "truncated ABI version TLV: %d\n",
+ length);
+ return -EINVAL;
+ }
+
+ bpf->abi_version = readl(value);
+ if (bpf->abi_version != 2) {
+ nfp_warn(bpf->app->cpp, "unsupported BPF ABI version: %d\n",
+ bpf->abi_version);
+ bpf->abi_version = 0;
+ }
+
+ return 0;
+}
+
static int nfp_bpf_parse_capabilities(struct nfp_app *app)
{
struct nfp_cpp *cpp = app->pf->cpp;
@@ -393,6 +416,11 @@ static int nfp_bpf_parse_capabilities(struct nfp_app *app)
length))
goto err_release_free;
break;
+ case NFP_BPF_CAP_TYPE_ABI_VERSION:
+ if (nfp_bpf_parse_cap_abi_version(app->priv, value,
+ length))
+ goto err_release_free;
+ break;
default:
nfp_dbg(cpp, "unknown BPF capability: %d\n", type);
break;
@@ -414,6 +442,11 @@ static int nfp_bpf_parse_capabilities(struct nfp_app *app)
return -EINVAL;
}
+static void nfp_bpf_init_capabilities(struct nfp_app_bpf *bpf)
+{
+ bpf->abi_version = 2; /* Original BPF ABI version */
+}
+
static int nfp_bpf_ndo_init(struct nfp_app *app, struct net_device *netdev)
{
struct nfp_app_bpf *bpf = app->priv;
@@ -447,6 +480,8 @@ static int nfp_bpf_init(struct nfp_app *app)
if (err)
goto err_free_bpf;
+ nfp_bpf_init_capabilities(bpf);
+
err = nfp_bpf_parse_capabilities(app);
if (err)
goto err_free_neutral_maps;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index dbd00982fd2b..62cdb183efdb 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -127,6 +127,8 @@ enum pkt_vec {
*
* @maps_neutral: hash table of offload-neutral maps (on pointer)
*
+ * @abi_version: global BPF ABI version
+ *
* @adjust_head: adjust head capability
* @adjust_head.flags: extra flags for adjust head
* @adjust_head.off_min: minimal packet offset within buffer required
@@ -170,6 +172,8 @@ struct nfp_app_bpf {
struct rhashtable maps_neutral;
+ u32 abi_version;
+
struct nfp_bpf_cap_adjust_head {
u32 flags;
int off_min;
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next 0/3] nfp: bpf: support big map entries
From: Jakub Kicinski @ 2018-10-02 1:30 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: netdev, oss-drivers, Jakub Kicinski
Hi!
This series makes the control message parsing for interacting
with BPF maps more flexible. Up until now we had a hard limit
in the ABI for key and value size to be 64B at most. Using
TLV capability allows us to support large map entries.
Jakub Kicinski (3):
nfp: bpf: parse global BPF ABI version capability
nfp: allow apps to request larger MTU on control vNIC
nfp: bpf: allow control message sizing for map ops
drivers/net/ethernet/netronome/nfp/bpf/cmsg.c | 70 ++++++++++++++++---
drivers/net/ethernet/netronome/nfp/bpf/fw.h | 11 ++-
drivers/net/ethernet/netronome/nfp/bpf/main.c | 52 ++++++++++++--
drivers/net/ethernet/netronome/nfp/bpf/main.h | 11 +++
drivers/net/ethernet/netronome/nfp/nfp_app.h | 4 ++
.../ethernet/netronome/nfp/nfp_net_common.c | 14 +++-
.../net/ethernet/netronome/nfp/nfp_net_ctrl.h | 2 +-
7 files changed, 142 insertions(+), 22 deletions(-)
--
2.17.1
^ permalink raw reply
* Re: [PATCH v2] net/ncsi: Add NCSI OEM command support
From: Samuel Mendoza-Jonas @ 2018-10-02 1:20 UTC (permalink / raw)
To: Vijay Khemka, Justin . Lee1 @ Dell . com, joel @ jms . id . au,
linux-aspeed @ lists . ozlabs . org,
openbmc @ lists . ozlabs . org, Sai Dasari,
netdev @ vger . kernel . org, christian @ cmd . nu
In-Reply-To: <20180929010602.1025909-1-vijaykhemka@fb.com>
On Fri, 2018-09-28 at 18:06 -0700, Vijay Khemka wrote:
> This patch adds OEM commands and response handling. It also defines OEM
> command and response structure as per NCSI specification along with its
> handlers.
>
> ncsi_cmd_handler_oem: This is a generic command request handler for OEM
> commands
> ncsi_rsp_handler_oem: This is a generic response handler for OEM commands
>
> Signed-off-by: Vijay Khemka <vijaykhemka@fb.com>
Hi Vijay - looks good to me, and should be a good common base for your
and Justin's changes.
Reviewed-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
> ---
> net/ncsi/internal.h | 4 ++++
> net/ncsi/ncsi-cmd.c | 31 ++++++++++++++++++++++++++++---
> net/ncsi/ncsi-pkt.h | 16 ++++++++++++++++
> net/ncsi/ncsi-rsp.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
> 4 files changed, 91 insertions(+), 4 deletions(-)
>
> diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
> index 8055e3965cef..c16cb7223064 100644
> --- a/net/ncsi/internal.h
> +++ b/net/ncsi/internal.h
> @@ -68,6 +68,10 @@ enum {
> NCSI_MODE_MAX
> };
>
> +/* OEM Vendor Manufacture ID */
> +#define NCSI_OEM_MFR_MLX_ID 0x8119
> +#define NCSI_OEM_MFR_BCM_ID 0x113d
> +
> struct ncsi_channel_version {
> u32 version; /* Supported BCD encoded NCSI version */
> u32 alpha2; /* Supported BCD encoded NCSI version */
> diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
> index 7567ca63aae2..2f98533eba46 100644
> --- a/net/ncsi/ncsi-cmd.c
> +++ b/net/ncsi/ncsi-cmd.c
> @@ -211,6 +211,26 @@ static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
> return 0;
> }
>
> +static int ncsi_cmd_handler_oem(struct sk_buff *skb,
> + struct ncsi_cmd_arg *nca)
> +{
> + struct ncsi_cmd_oem_pkt *cmd;
> + unsigned int len;
> +
> + len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
> + if (nca->payload < 26)
> + len += 26;
> + else
> + len += nca->payload;
> +
> + cmd = skb_put_zero(skb, len);
> + cmd->mfr_id = nca->dwords[0];
> + memcpy(cmd->data, &nca->dwords[1], nca->payload - 4);
> + ncsi_cmd_build_header(&cmd->cmd.common, nca);
> +
> + return 0;
> +}
> +
> static struct ncsi_cmd_handler {
> unsigned char type;
> int payload;
> @@ -244,7 +264,7 @@ static struct ncsi_cmd_handler {
> { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
> { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
> { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
> - { NCSI_PKT_CMD_OEM, 0, NULL },
> + { NCSI_PKT_CMD_OEM, -1, ncsi_cmd_handler_oem },
> { NCSI_PKT_CMD_PLDM, 0, NULL },
> { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
> };
> @@ -316,8 +336,13 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
> return -ENOENT;
> }
>
> - /* Get packet payload length and allocate the request */
> - nca->payload = nch->payload;
> + /* Get packet payload length and allocate the request
> + * It is expected that if length set as negative in
> + * handler structure means caller is initializing it
> + * and setting length in nca before calling xmit function
> + */
> + if (nch->payload >= 0)
> + nca->payload = nch->payload;
> nr = ncsi_alloc_command(nca);
> if (!nr)
> return -ENOMEM;
> diff --git a/net/ncsi/ncsi-pkt.h b/net/ncsi/ncsi-pkt.h
> index 91b4b66438df..1f338386810d 100644
> --- a/net/ncsi/ncsi-pkt.h
> +++ b/net/ncsi/ncsi-pkt.h
> @@ -151,6 +151,22 @@ struct ncsi_cmd_snfc_pkt {
> unsigned char pad[22];
> };
>
> +/* OEM Request Command as per NCSI Specification */
> +struct ncsi_cmd_oem_pkt {
> + struct ncsi_cmd_pkt_hdr cmd; /* Command header */
> + __be32 mfr_id; /* Manufacture ID */
> + unsigned char data[64]; /* OEM Payload Data */
> + __be32 checksum; /* Checksum */
> +};
> +
> +/* OEM Response Packet as per NCSI Specification */
> +struct ncsi_rsp_oem_pkt {
> + struct ncsi_rsp_pkt_hdr rsp; /* Command header */
> + __be32 mfr_id; /* Manufacture ID */
> + unsigned char data[64]; /* Payload data */
> + __be32 checksum; /* Checksum */
> +};
> +
> /* Get Link Status */
> struct ncsi_rsp_gls_pkt {
> struct ncsi_rsp_pkt_hdr rsp; /* Response header */
> diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
> index 930c1d3796f0..22664ebdc93a 100644
> --- a/net/ncsi/ncsi-rsp.c
> +++ b/net/ncsi/ncsi-rsp.c
> @@ -596,6 +596,48 @@ static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
> return 0;
> }
>
> +static struct ncsi_rsp_oem_handler {
> + unsigned int mfr_id;
> + int (*handler)(struct ncsi_request *nr);
> +} ncsi_rsp_oem_handlers[] = {
> + { NCSI_OEM_MFR_MLX_ID, NULL },
> + { NCSI_OEM_MFR_BCM_ID, NULL }
> +};
> +
> +
> +/* Response handler for OEM command */
> +static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
> +{
> + struct ncsi_rsp_oem_pkt *rsp;
> + struct ncsi_rsp_oem_handler *nrh = NULL;
> + unsigned int mfr_id, i;
> +
> + /* Get the response header */
> + rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
> + mfr_id = ntohl(rsp->mfr_id);
> +
> + /* Check for manufacturer id and Find the handler */
> + for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
> + if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
> + if (ncsi_rsp_oem_handlers[i].handler)
> + nrh = &ncsi_rsp_oem_handlers[i];
> + else
> + nrh = NULL;
> +
> + break;
> + }
> + }
> +
> + if (!nrh) {
> + netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
> + mfr_id);
> + return -ENOENT;
> + }
> +
> + /* Process the packet */
> + return nrh->handler(nr);
> +}
> +
> static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
> {
> struct ncsi_rsp_gvi_pkt *rsp;
> @@ -932,7 +974,7 @@ static struct ncsi_rsp_handler {
> { NCSI_PKT_RSP_GNS, 172, ncsi_rsp_handler_gns },
> { NCSI_PKT_RSP_GNPTS, 172, ncsi_rsp_handler_gnpts },
> { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
> - { NCSI_PKT_RSP_OEM, 0, NULL },
> + { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
> { NCSI_PKT_RSP_PLDM, 0, NULL },
> { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid }
> };
^ permalink raw reply
* [PATCH net-next] netfilter: xt_quota: fix the behavior of xt_quota module
From: Chenbo Feng @ 2018-10-02 1:23 UTC (permalink / raw)
To: netdev, netfilter-devel, pablo
Cc: kernel-team, Lorenzo Colitti, maze, Chenbo Feng
In-Reply-To: <1538443388-6881-1-git-send-email-chenbofeng.kernel@gmail.com>
From: Chenbo Feng <fengc@google.com>
A major flaw of the current xt_quota module is that quota in a specific
rule gets reset every time there is a rule change in the same table. It
makes the xt_quota module not very useful in a table in which iptables
rules are changed at run time. This fix introduces a new counter that is
visible to userspace as the remaining quota of the current rule. When
userspace restores the rules in a table, it can restore the counter to
the remaining quota instead of resetting it to the full quota.
Signed-off-by: Chenbo Feng <fengc@google.com>
Suggested-by: Maciej Żenczykowski <maze@google.com>
Reviewed-by: Maciej Żenczykowski <maze@google.com>
---
include/uapi/linux/netfilter/xt_quota.h | 8 +++--
net/netfilter/xt_quota.c | 55 +++++++++++++--------------------
2 files changed, 27 insertions(+), 36 deletions(-)
diff --git a/include/uapi/linux/netfilter/xt_quota.h b/include/uapi/linux/netfilter/xt_quota.h
index f3ba5d9..d72fd52 100644
--- a/include/uapi/linux/netfilter/xt_quota.h
+++ b/include/uapi/linux/netfilter/xt_quota.h
@@ -15,9 +15,11 @@ struct xt_quota_info {
__u32 flags;
__u32 pad;
__aligned_u64 quota;
-
- /* Used internally by the kernel */
- struct xt_quota_priv *master;
+#ifdef __KERNEL__
+ atomic64_t counter;
+#else
+ __aligned_u64 remain;
+#endif
};
#endif /* _XT_QUOTA_H */
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index 10d61a6..6afa7f4 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -11,11 +11,6 @@
#include <linux/netfilter/xt_quota.h>
#include <linux/module.h>
-struct xt_quota_priv {
- spinlock_t lock;
- uint64_t quota;
-};
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
MODULE_DESCRIPTION("Xtables: countdown quota match");
@@ -26,54 +21,48 @@ static bool
quota_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
struct xt_quota_info *q = (void *)par->matchinfo;
- struct xt_quota_priv *priv = q->master;
+ u64 current_count = atomic64_read(&q->counter);
bool ret = q->flags & XT_QUOTA_INVERT;
-
- spin_lock_bh(&priv->lock);
- if (priv->quota >= skb->len) {
- priv->quota -= skb->len;
- ret = !ret;
- } else {
- /* we do not allow even small packets from now on */
- priv->quota = 0;
- }
- spin_unlock_bh(&priv->lock);
-
- return ret;
+ u64 old_count, new_count;
+
+ do {
+ if (current_count == 1)
+ return ret;
+ if (current_count <= skb->len) {
+ atomic64_set(&q->counter, 1);
+ return ret;
+ }
+ old_count = current_count;
+ new_count = current_count - skb->len;
+ current_count = atomic64_cmpxchg(&q->counter, old_count,
+ new_count);
+ } while (current_count != old_count);
+ return !ret;
}
static int quota_mt_check(const struct xt_mtchk_param *par)
{
struct xt_quota_info *q = par->matchinfo;
+ BUILD_BUG_ON(sizeof(atomic64_t) != sizeof(__aligned_u64));
+
if (q->flags & ~XT_QUOTA_MASK)
return -EINVAL;
+ if (atomic64_read(&q->counter) > q->quota + 1)
+ return -ERANGE;
- q->master = kmalloc(sizeof(*q->master), GFP_KERNEL);
- if (q->master == NULL)
- return -ENOMEM;
-
- spin_lock_init(&q->master->lock);
- q->master->quota = q->quota;
+ if (atomic64_read(&q->counter) == 0)
+ atomic64_set(&q->counter, q->quota + 1);
return 0;
}
-static void quota_mt_destroy(const struct xt_mtdtor_param *par)
-{
- const struct xt_quota_info *q = par->matchinfo;
-
- kfree(q->master);
-}
-
static struct xt_match quota_mt_reg __read_mostly = {
.name = "quota",
.revision = 0,
.family = NFPROTO_UNSPEC,
.match = quota_mt,
.checkentry = quota_mt_check,
- .destroy = quota_mt_destroy,
.matchsize = sizeof(struct xt_quota_info),
- .usersize = offsetof(struct xt_quota_info, master),
.me = THIS_MODULE,
};
--
2.7.4
^ permalink raw reply related
* [PATCH iptables] extensions: libxt_quota: Allow setting the remaining quota
From: Chenbo Feng @ 2018-10-02 1:23 UTC (permalink / raw)
To: netdev, netfilter-devel, pablo
Cc: kernel-team, Lorenzo Colitti, maze, Chenbo Feng
In-Reply-To: <1538443388-6881-1-git-send-email-chenbofeng.kernel@gmail.com>
From: Chenbo Feng <fengc@google.com>
The current xt_quota module cannot track the current remaining quota
of a specific rule. Everytime an unrelated rule is updated in the same
iptables table, the quota will be reset. This is not a very useful
function for iptables that get changed at run time. This patch fixes the
above problem by adding a new field in the struct that records the
current remaining quota.
Fixed a print out bug in verbose print out wrt. inversion.
Signed-off-by: Chenbo Feng <fengc@google.com>
Suggested-by: Maciej Żenczykowski <maze@google.com>
Reviewed-by: Maciej Żenczykowski <maze@google.com>
---
extensions/libxt_quota.c | 25 +++++++++++++++++++++++--
include/linux/netfilter/xt_quota.h | 8 +++++---
2 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/extensions/libxt_quota.c b/extensions/libxt_quota.c
index bad77d2..6371aa0 100644
--- a/extensions/libxt_quota.c
+++ b/extensions/libxt_quota.c
@@ -9,26 +9,36 @@
enum {
O_QUOTA = 0,
+ O_REMAIN = 1,
};
static const struct xt_option_entry quota_opts[] = {
{.name = "quota", .id = O_QUOTA, .type = XTTYPE_UINT64,
.flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT,
XTOPT_POINTER(struct xt_quota_info, quota)},
+ {.name = "remain", .id = O_REMAIN, .type = XTTYPE_UINT64,
+ .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_quota_info, remain)},
XTOPT_TABLEEND,
};
static void quota_help(void)
{
printf("quota match options:\n"
- "[!] --quota quota quota (bytes)\n");
+ "[!] --quota quota quota (bytes)\n"
+ " --remain remain remain (bytes)\n");
}
static void
quota_print(const void *ip, const struct xt_entry_match *match, int numeric)
{
const struct xt_quota_info *q = (const void *)match->data;
+ if (q->flags & XT_QUOTA_INVERT)
+ printf(" !");
printf(" quota: %llu bytes", (unsigned long long)q->quota);
+ if (q->remain) {
+ printf(" remain: %llu bytes",
+ (unsigned long long)q->remain - 1);
+ }
}
static void
@@ -39,6 +49,10 @@ quota_save(const void *ip, const struct xt_entry_match *match)
if (q->flags & XT_QUOTA_INVERT)
printf(" !");
printf(" --quota %llu", (unsigned long long) q->quota);
+ if (q->remain) {
+ printf(" --remain %llu",
+ (unsigned long long) q->remain - 1);
+ }
}
static void quota_parse(struct xt_option_call *cb)
@@ -48,6 +62,8 @@ static void quota_parse(struct xt_option_call *cb)
xtables_option_parse(cb);
if (cb->invert)
info->flags |= XT_QUOTA_INVERT;
+ if (cb->entry->id == O_REMAIN)
+ info->remain++;
}
static int quota_xlate(struct xt_xlate *xl,
@@ -66,7 +82,12 @@ static struct xtables_match quota_match = {
.name = "quota",
.version = XTABLES_VERSION,
.size = XT_ALIGN(sizeof (struct xt_quota_info)),
- .userspacesize = offsetof(struct xt_quota_info, master),
+ /*
+ * This size is only used for rule matching purpose when deleting
+ * rules. The real size copied out from new kernel xt_quota module
+ * is the whole struct xt_quota_info.
+ */
+ .userspacesize = offsetof(struct xt_quota_info, remain),
.help = quota_help,
.print = quota_print,
.save = quota_save,
diff --git a/include/linux/netfilter/xt_quota.h b/include/linux/netfilter/xt_quota.h
index 9314723..d817aab 100644
--- a/include/linux/netfilter/xt_quota.h
+++ b/include/linux/netfilter/xt_quota.h
@@ -14,9 +14,11 @@ struct xt_quota_info {
__u32 flags;
__u32 pad;
__aligned_u64 quota;
-
- /* Used internally by the kernel */
- struct xt_quota_priv *master;
+#ifdef __KERNEL__
+ atomic64_t counter;
+#else
+ __aligned_u64 remain;
+#endif
};
#endif /* _XT_QUOTA_H */
--
2.7.4
^ permalink raw reply related
* [PATCH net-next iptables] Rework the xt_quota module
From: Chenbo Feng @ 2018-10-02 1:23 UTC (permalink / raw)
To: netdev, netfilter-devel, pablo
Cc: kernel-team, Lorenzo Colitti, maze, Chenbo Feng
From: Chenbo Feng <fengc@google.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The current xt_quota module uses an additional kernel struct to store
the remaining quota of an iptables match and does not expose it to
userspace. The major flaw of the current implementation is the quota
will be reset whenever an unrelated rule gets updated in the same table
as an xt_quota rule exists. Such behavior makes xt_quota rules not very
useful in a dynamically changing iptables setup.
To fix the problem above, a new remain field is introduced to replace
the kernel struct pointer. It is used in the kernel as an atomic64_t and
treated as an __aligned_u64 when it is copied to userspace. Since the
struct xt_quota_info uses __aligned_u64 to record the quota, it is
guaranteed the padding space at the end of the current struct is 64bit
wide even on a 32bit machine. So we can safely pass the current quota
from kernel to userspace without adding an extra revision to the
xt_quota module. Userspace can set the remaining quota with new
"--remain x" option when restoring a rule that is previously saved.
For general quota rule insertion/deletion, the user can choose whether
to specify the remaining quota or not. If a quota rule is inserted
without specifying the remaining quota, it will be set to the original
quota. As for rule deletion, the remaining part is not matched since it
is a dynamically changing field when there is live networking traffic
and makes no sense to specify the exact value of current remaining
quota.
For an old kernel with new iptables with this fix, the remain field will
not get copied into kernel memory because of the usersize definition in
kernel xt_quota module. So it will still act the same as old xt_quota
module. When dumping or saving the iptables rule, the kernel pointer
will not get copied to userspace and iptables will ignore the remaining
field if it is just zero initilized memory.
For a kernel with fix running against old iptables, insertion or
deletion of an unrelated rule no longer resets the quota since the
remain field will be copied out of kernel and updated back during the
rule insertion/deletion process.
kernel changes:
Chenbo Feng (1):
netfilter: xt_quota: fix the behavior of xt_quota module
include/uapi/linux/netfilter/xt_quota.h | 8 +++--
net/netfilter/xt_quota.c | 55 +++++++++++++--------------------
2 files changed, 27 insertions(+), 36 deletions(-)
iptables changes:
Chenbo Feng (1):
extensions: libxt_quota: Allow setting the remaining quota
extensions/libxt_quota.c | 23 +++++++++++++++++++++--
include/linux/netfilter/xt_quota.h | 8 +++++---
2 files changed, 26 insertions(+), 5 deletions(-)
--
2.7.4
^ permalink raw reply
* Re: Query in Crypto framework
From: gregkh @ 2018-10-01 21:18 UTC (permalink / raw)
To: Kalyani Akula
Cc: Herbert Xu, davem@davemloft.net, kstewart@linuxfoundation.org,
tglx@linutronix.de, pombredanne@nexb.com,
linux-crypto@vger.kernel.org, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org
In-Reply-To: <BN7PR02MB51249DB95E4CCBC5257C1F45AFEF0@BN7PR02MB5124.namprd02.prod.outlook.com>
On Mon, Oct 01, 2018 at 09:30:35AM +0000, Kalyani Akula wrote:
> This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.
Footers like this ensure that your email will not get answered, as it's
not compatible with kernel development :(
^ permalink raw reply
* Re: [PATCH net] inet: frags: rework rhashtable dismantle
From: Herbert Xu @ 2018-10-02 0:58 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David S . Miller, netdev, Eric Dumazet, Thomas Graf
In-Reply-To: <20181001175821.118684-1-edumazet@google.com>
On Mon, Oct 01, 2018 at 10:58:21AM -0700, Eric Dumazet wrote:
>
> void inet_frags_exit_net(struct netns_frags *nf)
> {
> + struct rhashtable_iter hti;
> + struct inet_frag_queue *fq;
> +
> + /* Since we want to cleanup the hashtable, make sure that
> + * we wont trigger an automatic shrinking while in our
> + * rhashtable_walk_next() loop.
> + * Also make sure that no resize is in progress.
> + */
> nf->high_thresh = 0; /* prevent creation of new frags */
> + nf->rhashtable.p.automatic_shrinking = false;
> + cancel_work_sync(&nf->rhashtable.run_work);
>
> - rhashtable_free_and_destroy(&nf->rhashtable, inet_frags_free_cb, NULL);
> + rhashtable_walk_enter(&nf->rhashtable, &hti);
> + rhashtable_walk_start(&hti);
> + while ((fq = rhashtable_walk_next(&hti)) != NULL) {
> + if (IS_ERR(fq)) /* should not happen */
> + break;
> + if (!del_timer_sync(&fq->timer))
> + continue;
> +
> + spin_lock_bh(&fq->lock);
> + inet_frag_kill(fq);
> + spin_unlock_bh(&fq->lock);
> +
> + inet_frag_put(fq);
> + if (need_resched()) {
> + rhashtable_walk_stop(&hti);
> + cond_resched();
> + rhashtable_walk_start(&hti);
> + }
> + }
The walk interface was designed to handle read-only iteration
through the hash table. While this probably works since the
actual freeing is delayed by RCU, it seems to be rather fragile.
How about using the dead flag but instead of putting it in the
rhashtable put it in netns_frags and have the timers check on that
before calling rhashtable_remove?
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH iproute2 net-next] ipneigh: update man page and help for router
From: David Ahern @ 2018-10-02 0:38 UTC (permalink / raw)
To: Roopa Prabhu; +Cc: netdev
In-Reply-To: <1538275691-41500-1-git-send-email-roopa@cumulusnetworks.com>
On 9/29/18 8:48 PM, Roopa Prabhu wrote:
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
>
> While at it also add missing text for proxy in the man page.
>
> Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com>
> ---
> ip/ipneigh.c | 1 +
> man/man8/ip-neighbour.8 | 11 ++++++++++-
> 2 files changed, 11 insertions(+), 1 deletion(-)
>
applied to iproute2-next. Thanks
^ permalink raw reply
* Re: [PATCH net-next] ipv6: add vrf table handling code for ipv6 mcast
From: David Ahern @ 2018-10-02 0:34 UTC (permalink / raw)
To: Mike Manning, netdev; +Cc: Patrick Ruddy
In-Reply-To: <20181001084127.32370-1-mmanning@vyatta.att-mail.com>
On 10/1/18 2:41 AM, Mike Manning wrote:
> From: Patrick Ruddy <pruddy@vyatta.att-mail.com>
>
> The code to obtain the correct table for the incoming interface was
> missing for IPv6. This has been added along with the table creation
> notification to fib rules for the RTNL_FAMILY_IP6MR address family.
>
> Signed-off-by: Patrick Ruddy <pruddy@vyatta.att-mail.com>
> Signed-off-by: Mike Manning <mmanning@vyatta.att-mail.com>
> ---
> drivers/net/vrf.c | 11 +++++++++++
> net/ipv6/ip6mr.c | 48 ++++++++++++++++++++++++++++++++++++------------
> 2 files changed, 47 insertions(+), 12 deletions(-)
>
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH net-next] ipv4: Allow sending multicast packets on specific i/f using VRF socket
From: David Ahern @ 2018-10-02 0:30 UTC (permalink / raw)
To: Mike Manning, netdev; +Cc: Robert Shearman
In-Reply-To: <20181001084023.32310-1-mmanning@vyatta.att-mail.com>
On 10/1/18 2:40 AM, Mike Manning wrote:
> From: Robert Shearman <rshearma@vyatta.att-mail.com>
>
> It is useful to be able to use the same socket for listening in a
> specific VRF, as for sending multicast packets out of a specific
> interface. However, the bound device on the socket currently takes
> precedence and results in the packets not being sent.
>
> Relax the condition on overriding the output interface to use for
> sending packets out of UDP, raw and ping sockets to allow multicast
> packets to be sent using the specified multicast interface.
>
> Signed-off-by: Robert Shearman <rshearma@vyatta.att-mail.com>
> Signed-off-by: Mike Manning <mmanning@vyatta.att-mail.com>
> ---
> net/ipv4/datagram.c | 2 +-
> net/ipv4/ping.c | 2 +-
> net/ipv4/raw.c | 2 +-
> net/ipv4/udp.c | 2 +-
> 4 files changed, 4 insertions(+), 4 deletions(-)
>
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* [PATCH RFC v2 net-next 22/25] net/ipv6: Plumb support for filtering route dumps
From: David Ahern @ 2018-10-02 0:28 UTC (permalink / raw)
To: netdev, davem; +Cc: christian, jbenc, stephen, David Ahern
In-Reply-To: <20181002002851.5002-1-dsahern@kernel.org>
From: David Ahern <dsahern@gmail.com>
Implement kernel side filtering of routes by table id, egress device index,
protocol, and route type. Move the existing route flags check
for prefix only routes to the new filter.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/ipv6/ip6_fib.c | 13 +++++++++++++
net/ipv6/route.c | 36 +++++++++++++++++++++++++++---------
2 files changed, 40 insertions(+), 9 deletions(-)
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index e0362a21737f..15b9806270c1 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -613,12 +613,25 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
w->args = &arg;
rcu_read_lock();
+
+ if (arg.filter.ifindex) {
+ arg.filter.dev = dev_get_by_index_rcu(net, arg.filter.ifindex);
+ if (!arg.filter.dev) {
+ res = -ENODEV;
+ goto out;
+ }
+ }
+
for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) {
e = 0;
head = &net->ipv6.fib_table_hash[h];
hlist_for_each_entry_rcu(tb, head, tb6_hlist) {
if (e < s_e)
goto next;
+ if (arg.filter.table_id &&
+ arg.filter.table_id != tb->tb6_id)
+ goto next;
+
res = fib6_dump_table(tb, skb, cb);
if (res != 0)
goto out;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d28f83e01593..99ba2313c380 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -4792,24 +4792,42 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
return -EMSGSIZE;
}
+static bool fib6_info_uses_dev(const struct fib6_info *f6i,
+ const struct net_device *dev)
+{
+ if (f6i->fib6_nh.nh_dev == dev)
+ return true;
+
+ if (f6i->fib6_nsiblings) {
+ struct fib6_info *sibling, *next_sibling;
+
+ list_for_each_entry_safe(sibling, next_sibling,
+ &f6i->fib6_siblings, fib6_siblings) {
+ if (sibling->fib6_nh.nh_dev == dev)
+ return true;
+ }
+ }
+ return false;
+}
+
int rt6_dump_route(struct fib6_info *rt, void *p_arg)
{
struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
+ struct fib_dump_filter *filter = &arg->filter;
struct net *net = arg->net;
if (rt == net->ipv6.fib6_null_entry)
return 0;
- if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) {
- struct rtmsg *rtm = nlmsg_data(arg->cb->nlh);
-
- /* user wants prefix routes only */
- if (rtm->rtm_flags & RTM_F_PREFIX &&
- !(rt->fib6_flags & RTF_PREFIX_RT)) {
- /* success since this is not a prefix route */
- return 1;
- }
+ if ((filter->flags & RTM_F_PREFIX) &&
+ !(rt->fib6_flags & RTF_PREFIX_RT)) {
+ /* success since this is not a prefix route */
+ return 1;
}
+ if ((filter->protocol && rt->fib6_protocol != filter->protocol) ||
+ (filter->rt_type && rt->fib6_type != filter->rt_type) ||
+ (filter->dev && !fib6_info_uses_dev(rt, filter->dev)))
+ return 1;
return rt6_fill_node(net, arg->skb, rt, NULL, NULL, NULL, 0,
RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).portid,
--
2.11.0
^ permalink raw reply related
* [PATCH RFC v2 net-next 24/25] net: Plumb support for filtering ipv4 and ipv6 multicast route dumps
From: David Ahern @ 2018-10-02 0:28 UTC (permalink / raw)
To: netdev, davem; +Cc: christian, jbenc, stephen, David Ahern
In-Reply-To: <20181002002851.5002-1-dsahern@kernel.org>
From: David Ahern <dsahern@gmail.com>
Implement kernel side filtering of routes by egress device index and
table id.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
include/linux/mroute_base.h | 5 +++--
net/ipv4/ipmr.c | 2 +-
net/ipv4/ipmr_base.c | 42 +++++++++++++++++++++++++++++++++++++++++-
net/ipv6/ip6mr.c | 2 +-
4 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/include/linux/mroute_base.h b/include/linux/mroute_base.h
index 6675b9f81979..8fc516c47a64 100644
--- a/include/linux/mroute_base.h
+++ b/include/linux/mroute_base.h
@@ -7,6 +7,7 @@
#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/fib_notifier.h>
+#include <net/ip_fib.h>
/**
* struct vif_device - interface representor for multicast routing
@@ -290,7 +291,7 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
struct sk_buff *skb,
u32 portid, u32 seq, struct mr_mfc *c,
int cmd, int flags),
- spinlock_t *lock);
+ spinlock_t *lock, struct fib_dump_filter *filter);
int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
int (*rules_dump)(struct net *net,
@@ -340,7 +341,7 @@ mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
struct sk_buff *skb,
u32 portid, u32 seq, struct mr_mfc *c,
int cmd, int flags),
- spinlock_t *lock)
+ spinlock_t *lock, struct fib_dump_filter *filter)
{
return -EINVAL;
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 9e9ad60dff6b..2fe24009439a 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -2538,7 +2538,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
}
return mr_rtm_dumproute(skb, cb, ipmr_mr_table_iter,
- _ipmr_fill_mroute, &mfc_unres_lock);
+ _ipmr_fill_mroute, &mfc_unres_lock, &filter);
}
static const struct nla_policy rtm_ipmr_policy[RTA_MAX + 1] = {
diff --git a/net/ipv4/ipmr_base.c b/net/ipv4/ipmr_base.c
index 1ad9aa62a97b..a4f83cbf033d 100644
--- a/net/ipv4/ipmr_base.c
+++ b/net/ipv4/ipmr_base.c
@@ -268,6 +268,24 @@ int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
}
EXPORT_SYMBOL(mr_fill_mroute);
+static bool mr_mfc_uses_dev(const struct mr_table *mrt,
+ const struct mr_mfc *c,
+ const struct net_device *dev)
+{
+ int ct;
+
+ for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
+ if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
+ const struct vif_device *vif;
+
+ vif = &mrt->vif_table[ct];
+ if (vif->dev == dev)
+ return true;
+ }
+ }
+ return false;
+}
+
int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
struct mr_table *(*iter)(struct net *net,
struct mr_table *mrt),
@@ -275,17 +293,35 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
struct sk_buff *skb,
u32 portid, u32 seq, struct mr_mfc *c,
int cmd, int flags),
- spinlock_t *lock)
+ spinlock_t *lock, struct fib_dump_filter *filter)
{
unsigned int t = 0, e = 0, s_t = cb->args[0], s_e = cb->args[1];
struct net *net = sock_net(skb->sk);
struct mr_table *mrt;
struct mr_mfc *mfc;
+ /* multicast does not use tos or scope, track protocol or have
+ * route type other than RTN_MULTICAST
+ */
+ if (filter->tos || filter->protocol || filter->scope || filter->flags ||
+ (filter->rt_type && filter->rt_type != RTN_MULTICAST))
+ return 0;
+
rcu_read_lock();
+
+ if (filter->ifindex) {
+ filter->dev = dev_get_by_index_rcu(net, filter->ifindex);
+ if (!filter->dev) {
+ rcu_read_unlock();
+ return -ENODEV;
+ }
+ }
+
for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
if (t < s_t)
goto next_table;
+ if (filter->table_id && filter->table_id != mrt->id)
+ goto next_table;
list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
if (e < s_e)
goto next_entry;
@@ -303,6 +339,10 @@ int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
if (e < s_e)
goto next_entry2;
+ if (filter->dev &&
+ !mr_mfc_uses_dev(mrt, mfc, filter->dev))
+ goto next_entry2;
+
if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, mfc,
RTM_NEWROUTE, NLM_F_MULTI) < 0) {
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index b3084b2c8f88..08e2443ca0cc 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -2444,5 +2444,5 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
}
return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
- _ip6mr_fill_mroute, &mfc_unres_lock);
+ _ip6mr_fill_mroute, &mfc_unres_lock, &filter);
}
--
2.11.0
^ permalink raw reply related
* [PATCH RFC v2 net-next 25/25] net: Enable kernel side filtering of route dumps
From: David Ahern @ 2018-10-02 0:28 UTC (permalink / raw)
To: netdev, davem; +Cc: christian, jbenc, stephen, David Ahern
In-Reply-To: <20181002002851.5002-1-dsahern@kernel.org>
From: David Ahern <dsahern@gmail.com>
Update parsing of route dump request to enable kernel side of filtering.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/ipv4/fib_frontend.c | 42 ++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index a3f4073e509a..d1ef1cb98139 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -806,7 +806,9 @@ int ip_valid_fib_dump_req(const struct nlmsghdr *nlh,
struct fib_dump_filter *filter,
struct netlink_ext_ack *extack)
{
+ struct nlattr *tb[RTA_MAX + 1];
struct rtmsg *rtm;
+ int err, i;
if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
NL_SET_ERR_MSG(extack, "Invalid header");
@@ -814,21 +816,37 @@ int ip_valid_fib_dump_req(const struct nlmsghdr *nlh,
}
rtm = nlmsg_data(nlh);
- if (rtm->rtm_dst_len || rtm->rtm_src_len || rtm->rtm_tos ||
- rtm->rtm_table || rtm->rtm_protocol || rtm->rtm_scope ||
- rtm->rtm_type) {
- NL_SET_ERR_MSG(extack,
- "Invalid values in header for dump request");
+ if (rtm->rtm_dst_len || rtm->rtm_src_len) {
+ NL_SET_ERR_MSG(extack, "Invalid values in header for dump request");
return -EINVAL;
}
- if (rtm->rtm_flags & ~(RTM_F_CLONED | RTM_F_PREFIX)) {
- NL_SET_ERR_MSG(extack, "Invalid flags for dump request");
- return -EINVAL;
- }
- if (nlh->nlmsg_len != nlmsg_msg_size(sizeof(*rtm))) {
- NL_SET_ERR_MSG(extack, "Invalid data after header");
- return -EINVAL;
+ filter->flags = rtm->rtm_flags;
+ filter->tos = rtm->rtm_tos;
+ filter->protocol = rtm->rtm_protocol;
+ filter->scope = rtm->rtm_scope;
+ filter->rt_type = rtm->rtm_type;
+ filter->table_id = rtm->rtm_table;
+
+ err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX,
+ rtm_ipv4_policy, extack);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i <= RTA_MAX; ++i) {
+ if (!tb[i])
+ continue;
+ switch (i) {
+ case RTA_TABLE:
+ filter->table_id = nla_get_u32(tb[i]);
+ break;
+ case RTA_OIF:
+ filter->ifindex = nla_get_u32(tb[i]);
+ break;
+ default:
+ NL_SET_ERR_MSG(extack, "Unsupported attribute in dump request");
+ return -EINVAL;
+ }
}
return 0;
--
2.11.0
^ permalink raw reply related
* [PATCH RFC v2 net-next 23/25] net/mpls: Plumb support for filtering route dumps
From: David Ahern @ 2018-10-02 0:28 UTC (permalink / raw)
To: netdev, davem; +Cc: christian, jbenc, stephen, David Ahern
In-Reply-To: <20181002002851.5002-1-dsahern@kernel.org>
From: David Ahern <dsahern@gmail.com>
Implement kernel side filtering of routes by egress device index and
protocol. MPLS uses only a single table and route type.
Signed-off-by: David Ahern <dsahern@gmail.com>
---
net/mpls/af_mpls.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index f94d1db63eb5..4dd8a2a026e7 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -2031,6 +2031,28 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
return -EMSGSIZE;
}
+static bool mpls_rt_uses_dev(struct mpls_route *rt,
+ const struct net_device *dev)
+{
+ struct net_device *nh_dev;
+
+ if (rt->rt_nhn == 1) {
+ struct mpls_nh *nh = rt->rt_nh;
+
+ nh_dev = rtnl_dereference(nh->nh_dev);
+ if (dev == nh_dev)
+ return true;
+ } else {
+ for_nexthops(rt) {
+ nh_dev = rtnl_dereference(nh->nh_dev);
+ if (nh_dev == dev)
+ return true;
+ } endfor_nexthops(rt);
+ }
+
+ return false;
+}
+
static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
{
const struct nlmsghdr *nlh = cb->nlh;
@@ -2039,6 +2061,7 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
struct fib_dump_filter filter = {};
size_t platform_labels;
unsigned int index;
+ int err;
ASSERT_RTNL();
@@ -2047,6 +2070,15 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
if (err)
return err;
+
+ /* for MPLS, there is only 1 table with fixed type, scope
+ * tos and flags. If any of these are set in the filter then
+ * return nothing
+ */
+ if ((filter.table_id && filter.table_id != RT_TABLE_MAIN) ||
+ (filter.rt_type && filter.rt_type != RTN_UNICAST) ||
+ filter.scope || filter.tos || filter.flags)
+ return 0;
}
index = cb->args[0];
@@ -2055,20 +2087,41 @@ static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
platform_label = rtnl_dereference(net->mpls.platform_label);
platform_labels = net->mpls.platform_labels;
+
+ rcu_read_lock();
+
+ if (filter.ifindex) {
+ filter.dev = dev_get_by_index_rcu(net, filter.ifindex);
+ if (!filter.dev) {
+ err = -ENODEV;
+ goto out_err;
+ }
+ }
+
for (; index < platform_labels; index++) {
struct mpls_route *rt;
+
rt = rtnl_dereference(platform_label[index]);
if (!rt)
continue;
+ if (filter.protocol && rt->rt_protocol != filter.protocol)
+ continue;
+
+ if (filter.dev && !mpls_rt_uses_dev(rt, filter.dev))
+ continue;
+
if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, RTM_NEWROUTE,
index, rt, NLM_F_MULTI) < 0)
break;
}
cb->args[0] = index;
+ err = skb->len;
- return skb->len;
+out_err:
+ rcu_read_unlock();
+ return err;
}
static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
--
2.11.0
^ 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