Netdev List
 help / color / mirror / Atom feed
* Re: [PATCH v3 net-next 2/2] net: deprecate eth_change_mtu, remove usage
From: Jakub Kicinski @ 2016-10-17 17:04 UTC (permalink / raw)
  To: David Miller; +Cc: jarod, linux-kernel, netdev
In-Reply-To: <20161017180027.4936fa15@jkicinski-Precision-T1700>

On Mon, 17 Oct 2016 18:00:27 +0100, Jakub Kicinski wrote:
> On Mon, 17 Oct 2016 12:49:54 -0400 (EDT), David Miller wrote:
> > From: Jakub Kicinski <kubakici@wp.pl>
> > Date: Mon, 17 Oct 2016 17:20:06 +0100
> >   
> > > Please correct me if I'm wrong but it seems like we are now limiting
> > > _all_ ethernet drivers to ETH_DATA_LEN in net-next.    
> > 
> > No, because the driver can increase the netdev->max_mtu value as needed.  
> 
> But since almost no driver is doing that, yet, right now in net-next
> jumbo frames are not possible, no?  I thought the idea was the leave
> the value at 0 so drivers can opt-in as needed but since setup_ether()
> is initializing to 1500 now all ethernet driver get a default of
> limiting to 1500.
> 
> IOW this patch made checks which were done only in eth_change_mtu()
> mandatory for all drivers.

all ethernet drivers to be clear

^ permalink raw reply

* Re: [PATCH 2/9] ipv6: sr: add code base for control plane support of SR-IPv6
From: Tom Herbert @ 2016-10-17 17:07 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1476715350-18983-3-git-send-email-david.lebrun@uclouvain.be>

On Mon, Oct 17, 2016 at 7:42 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> This patch adds the necessary hooks and structures to provide support
> for SR-IPv6 control plane, essentially the Generic Netlink commands
> that will be used for userspace control over the Segment Routing
> kernel structures.
>
> The genetlink commands provide control over two different structures:
> tunnel source and HMAC data. The tunnel source is the source address
> that will be used by default when encapsulating packets into an
> outer IPv6 header + SRH. If the tunnel source is set to :: then an
> address of the outgoing interface will be selected as the source.
>
> The HMAC commands currently just return ENOTSUPP and will be implemented
> in a future patch.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/seg6_genl.h      |   6 ++
>  include/net/netns/ipv6.h       |   3 +
>  include/net/seg6.h             |  41 ++++++++
>  include/uapi/linux/seg6_genl.h |  33 +++++++
>  net/ipv6/Makefile              |   1 +
>  net/ipv6/seg6.c                | 212 +++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 296 insertions(+)
>  create mode 100644 include/linux/seg6_genl.h
>  create mode 100644 include/net/seg6.h
>  create mode 100644 include/uapi/linux/seg6_genl.h
>  create mode 100644 net/ipv6/seg6.c
>
> diff --git a/include/linux/seg6_genl.h b/include/linux/seg6_genl.h
> new file mode 100644
> index 0000000..d6c3fb4f
> --- /dev/null
> +++ b/include/linux/seg6_genl.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_GENL_H
> +#define _LINUX_SEG6_GENL_H
> +
> +#include <uapi/linux/seg6_genl.h>
> +
> +#endif
> diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
> index 10d0848..67825bb 100644
> --- a/include/net/netns/ipv6.h
> +++ b/include/net/netns/ipv6.h
> @@ -85,6 +85,9 @@ struct netns_ipv6 {
>  #endif
>         atomic_t                dev_addr_genid;
>         atomic_t                fib6_sernum;
> +#ifdef CONFIG_IPV6_SEG6
> +       struct seg6_pernet_data *seg6_data;
> +#endif
>  };
>
>  #if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
> diff --git a/include/net/seg6.h b/include/net/seg6.h
> new file mode 100644
> index 0000000..89b819e
> --- /dev/null
> +++ b/include/net/seg6.h
> @@ -0,0 +1,41 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *      modify it under the terms of the GNU General Public License
> + *      as published by the Free Software Foundation; either version
> + *      2 of the License, or (at your option) any later version.
> + */
> +
> +#ifndef _NET_SEG6_H
> +#define _NET_SEG6_H
> +
> +#include <linux/net.h>
> +#include <linux/ipv6.h>
> +
> +struct seg6_pernet_data {
> +       struct mutex lock;
> +       struct in6_addr __rcu *tun_src;
> +};
> +
> +static inline struct seg6_pernet_data *seg6_pernet(struct net *net)
> +{
> +       return net->ipv6.seg6_data;
> +}
> +
> +static inline void seg6_pernet_lock(struct net *net)
> +{
> +       mutex_lock(&seg6_pernet(net)->lock);
> +}
> +
> +static inline void seg6_pernet_unlock(struct net *net)
> +{
> +       mutex_unlock(&seg6_pernet(net)->lock);
> +}
> +
IMO it's better not to hide mutex_lock/unlock in a static inline
function. Pairing mutex_lock with mutex_lock is critical and should be
each to see in code.

> +#endif
> +
> diff --git a/include/uapi/linux/seg6_genl.h b/include/uapi/linux/seg6_genl.h
> new file mode 100644
> index 0000000..4db988b
> --- /dev/null
> +++ b/include/uapi/linux/seg6_genl.h
> @@ -0,0 +1,33 @@
> +#ifndef _UAPI_LINUX_SEG6_GENL_H
> +#define _UAPI_LINUX_SEG6_GENL_H
> +
> +#define SEG6_GENL_NAME         "SEG6"
> +#define SEG6_GENL_VERSION      0x1
> +
> +enum {
> +       SEG6_ATTR_UNSPEC,
> +       SEG6_ATTR_DST,
> +       SEG6_ATTR_DSTLEN,
> +       SEG6_ATTR_HMACKEYID,
> +       SEG6_ATTR_SECRET,
> +       SEG6_ATTR_SECRETLEN,
> +       SEG6_ATTR_ALGID,
> +       SEG6_ATTR_HMACINFO,
> +       __SEG6_ATTR_MAX,
> +};
> +
> +#define SEG6_ATTR_MAX (__SEG6_ATTR_MAX - 1)
> +
> +enum {
> +       SEG6_CMD_UNSPEC,
> +       SEG6_CMD_SETHMAC,
> +       SEG6_CMD_DUMPHMAC,
> +       SEG6_CMD_SET_TUNSRC,
> +       SEG6_CMD_GET_TUNSRC,
> +       __SEG6_CMD_MAX,
> +};
> +
> +#define SEG6_CMD_MAX (__SEG6_CMD_MAX - 1)
> +
> +#endif
> +
> diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
> index c174ccb..5069257 100644
> --- a/net/ipv6/Makefile
> +++ b/net/ipv6/Makefile
> @@ -44,6 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
>  obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
>  obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
>  obj-$(CONFIG_IPV6_FOU) += fou6.o
> +obj-$(CONFIG_IPV6_SEG6) += seg6.o
>
>  obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
>  obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
> diff --git a/net/ipv6/seg6.c b/net/ipv6/seg6.c
> new file mode 100644
> index 0000000..8dafe7b
> --- /dev/null
> +++ b/net/ipv6/seg6.c
> @@ -0,0 +1,212 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *       modify it under the terms of the GNU General Public License
> + *       as published by the Free Software Foundation; either version
> + *       2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/socket.h>
> +#include <linux/net.h>
> +#include <linux/in6.h>
> +#include <linux/slab.h>
> +
> +#include <net/ipv6.h>
> +#include <net/protocol.h>
> +
> +#include <net/seg6.h>
> +#include <net/genetlink.h>
> +#include <linux/seg6.h>
> +#include <linux/seg6_genl.h>
> +
> +static const struct nla_policy seg6_genl_policy[SEG6_ATTR_MAX + 1] = {
> +       [SEG6_ATTR_DST]                         = { .type = NLA_BINARY,
> +               .len = sizeof(struct in6_addr) },
> +       [SEG6_ATTR_DSTLEN]                      = { .type = NLA_S32, },
> +       [SEG6_ATTR_HMACKEYID]           = { .type = NLA_U32, },
> +       [SEG6_ATTR_SECRET]                      = { .type = NLA_BINARY, },
> +       [SEG6_ATTR_SECRETLEN]           = { .type = NLA_U8, },
> +       [SEG6_ATTR_ALGID]                       = { .type = NLA_U8, },
> +       [SEG6_ATTR_HMACINFO]            = { .type = NLA_NESTED, },
> +};
> +
> +static struct genl_family seg6_genl_family = {
> +       .id = GENL_ID_GENERATE,
> +       .hdrsize = 0,
> +       .name = SEG6_GENL_NAME,
> +       .version = SEG6_GENL_VERSION,
> +       .maxattr = SEG6_ATTR_MAX,
> +       .netnsok = true,
> +};
> +
> +static int seg6_genl_sethmac(struct sk_buff *skb, struct genl_info *info)
> +{
> +       return -ENOTSUPP;

Is the intent to implement this later?

> +}
> +
> +static int seg6_genl_set_tunsrc(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct net *net = genl_info_net(info);
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct in6_addr *val, *t_old, *t_new;
> +
> +       if (!info->attrs[SEG6_ATTR_DST])
> +               return -EINVAL;
> +
> +       val = (struct in6_addr *)nla_data(info->attrs[SEG6_ATTR_DST]);
> +       t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
> +
> +       seg6_pernet_lock(net);
> +
> +       t_old = sdata->tun_src;
> +       rcu_assign_pointer(sdata->tun_src, t_new);
> +
> +       seg6_pernet_unlock(net);
> +
> +       synchronize_net();
> +       kfree(t_old);
> +
> +       return 0;
> +}
> +
> +static int seg6_genl_get_tunsrc(struct sk_buff *skb, struct genl_info *info)
> +{
> +       struct net *net = genl_info_net(info);
> +       struct sk_buff *msg;
> +       void *hdr;
> +       struct in6_addr *tun_src;
> +
> +       msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
> +       if (!msg)
> +               return -ENOMEM;
> +
> +       hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
> +                         &seg6_genl_family, 0, SEG6_CMD_GET_TUNSRC);
> +       if (!hdr)
> +               goto free_msg;
> +
> +       rcu_read_lock();
> +       tun_src = rcu_dereference(seg6_pernet(net)->tun_src);
> +
> +       if (nla_put(msg, SEG6_ATTR_DST, sizeof(struct in6_addr), tun_src))
> +               goto nla_put_failure;
> +
> +       rcu_read_unlock();
> +
> +       genlmsg_end(msg, hdr);
> +       genlmsg_reply(msg, info);
> +
> +       return 0;
> +
> +nla_put_failure:
> +       rcu_read_unlock();
> +       genlmsg_cancel(msg, hdr);
> +free_msg:
> +       nlmsg_free(msg);
> +       return -ENOMEM;
> +}
> +
> +static int seg6_genl_dumphmac(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +       return -ENOTSUPP;
> +}
> +
> +static const struct genl_ops seg6_genl_ops[] = {
> +       {
> +               .cmd    = SEG6_CMD_SETHMAC,
> +               .doit   = seg6_genl_sethmac,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +       {
> +               .cmd    = SEG6_CMD_DUMPHMAC,
> +               .dumpit = seg6_genl_dumphmac,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +       {
> +               .cmd    = SEG6_CMD_SET_TUNSRC,
> +               .doit   = seg6_genl_set_tunsrc,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +       {
> +               .cmd    = SEG6_CMD_GET_TUNSRC,
> +               .doit   = seg6_genl_get_tunsrc,
> +               .policy = seg6_genl_policy,
> +               .flags  = GENL_ADMIN_PERM,
> +       },
> +};
> +
> +static int __net_init seg6_net_init(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata;
> +
> +       sdata = kzalloc(sizeof(*sdata), GFP_KERNEL);
> +       if (!sdata)
> +               return -ENOMEM;
> +
> +       mutex_init(&sdata->lock);
> +
> +       sdata->tun_src = kzalloc(sizeof(*sdata->tun_src), GFP_KERNEL);
> +       if (!sdata->tun_src) {
> +               kfree(sdata);
> +               return -ENOMEM;
> +       }
> +
> +       net->ipv6.seg6_data = sdata;
> +
> +       return 0;
> +}
> +
> +static void __net_exit seg6_net_exit(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +
> +       kfree(sdata->tun_src);
> +       kfree(sdata);
> +}
> +
> +static struct pernet_operations ip6_segments_ops = {
> +       .init = seg6_net_init,
> +       .exit = seg6_net_exit,
> +};
> +
> +static int __init seg6_init(void)
> +{
> +       int err = -ENOMEM;
> +
> +       err = genl_register_family_with_ops(&seg6_genl_family, seg6_genl_ops);
> +       if (err)
> +               goto out;
> +
> +       err = register_pernet_subsys(&ip6_segments_ops);
> +       if (err)
> +               goto out_unregister_genl;
> +
> +       pr_info("Segment Routing with IPv6\n");
> +
> +out:
> +       return err;
> +out_unregister_genl:
> +       genl_unregister_family(&seg6_genl_family);
> +       goto out;
> +}
> +module_init(seg6_init);
> +
> +static void __exit seg6_exit(void)
> +{
> +       unregister_pernet_subsys(&ip6_segments_ops);
> +       genl_unregister_family(&seg6_genl_family);
> +}
> +module_exit(seg6_exit);
> +
> +MODULE_DESCRIPTION("Segment Routing with IPv6 core");
> +MODULE_LICENSE("GPL v2");
> --
> 2.7.3
>

^ permalink raw reply

* Re: [PATCH] fjes: fix format string for trace output
From: David Miller @ 2016-10-17 17:08 UTC (permalink / raw)
  To: arnd; +Cc: izumi.taku, netdev, linux-kernel
In-Reply-To: <20161017143314.515133-1-arnd@arndb.de>

From: Arnd Bergmann <arnd@arndb.de>
Date: Mon, 17 Oct 2016 16:30:57 +0200

> phys_addr_t may be wider than a pointer and has to be printed
> using the special %pap format string, as pointed out by
> this new warning.
> 
> arch/x86/include/../../../drivers/net/fjes/fjes_trace.h: In function ‘trace_raw_output_fjes_hw_start_debug_req’:
> arch/x86/include/../../../drivers/net/fjes/fjes_trace.h:212:563: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast]
> 
> Note that this has to pass the address by reference instead of
> casting it to a different type.
> 
> Fixes: b6ba737d0b29 ("fjes: ethtool -w and -W support for fjes driver")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>

When a patch is targetting 'net-next' please indicate this in the
subject line by saying "[PATCH net-next]" etc.  And likewise for
'net'.

Applied, thanks.

^ permalink raw reply

* Re: [PATCH] crypto: ccm - avoid scatterlist for MAC encryption
From: Andy Lutomirski @ 2016-10-17 17:08 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: Johannes Berg, Sergey Senozhatsky, <netdev@vger.kernel.org>,
	Herbert Xu, David S. Miller,
	<linux-wireless@vger.kernel.org>,
	linux-kernel@vger.kernel.org, Jouni Malinen
In-Reply-To: <CAKv+Gu_P-6sHW3t7tp1N+3v9ZGqWcQrzMZkASY5g=QR76KN4wg@mail.gmail.com>

On Mon, Oct 17, 2016 at 12:37 AM, Ard Biesheuvel
<ard.biesheuvel@linaro.org> wrote:
> On 17 October 2016 at 08:28, Johannes Berg <johannes@sipsolutions.net> wrote:
>> On Sat, 2016-10-15 at 18:16 +0100, Ard Biesheuvel wrote:
>>> The CCM code goes out of its way to perform the CTR encryption of the
>>> MAC using the subordinate CTR driver. To this end, it tweaks the
>>> input and output scatterlists so the aead_req 'odata' and/or
>>> 'auth_tag' fields [which may live on the stack] are prepended to the
>>> CTR payload. This involves calling sg_set_buf() on addresses which
>>> are not direct mapped, which is not supported.
>>
>>> Since the calculation of the MAC keystream involves a single call
>>> into the cipher, to which we have a handle already given that the
>>> CBC-MAC calculation uses it as well, just calculate the MAC keystream
>>> directly, and record it in the aead_req private context so we can
>>> apply it to the MAC in cypto_ccm_auth_mac(). This greatly simplifies
>>> the scatterlist manipulation, and no longer requires scatterlists to
>>> refer to buffers that may live on the stack.
>>
>> No objection from me, Herbert?
>>
>> I'm getting a bit nervous though - I'd rather have any fix first so
>> people get things working again - so maybe I'll apply your other patch
>> and mine first, and then we can replace yours by this later.
>>
>
> Could we get a statement first whether it is supported to allocate
> aead_req (and other crypto req structures) on the stack? If not, then
> we have our work cut out for us. But if it is, I'd rather we didn't
> apply the kzalloc/kfree patch, since it is just a workaround for the
> broken generic CCM driver, for which a fix is already available.

I'm not a crypto person, but I don't see why not.  There's even a
helper called SKCIPHER_REQUEST_ON_STACK. :)  The only problem I know
of is pointing a scatterlist at the stack, which is bad for much the
same reason as doing real DMA from the stack.

^ permalink raw reply

* Re: [PATCH -next] net: wan: slic_ds26522: Use module_spi_driver to simplify the code
From: David Miller @ 2016-10-17 17:09 UTC (permalink / raw)
  To: weiyj.lk; +Cc: javier, qiang.zhao, weiyongjun1, netdev
In-Reply-To: <1476715845-27691-1-git-send-email-weiyj.lk@gmail.com>

From: Wei Yongjun <weiyj.lk@gmail.com>
Date: Mon, 17 Oct 2016 14:50:45 +0000

> From: Wei Yongjun <weiyongjun1@huawei.com>
> 
> module_spi_driver() makes the code simpler by eliminating
> boilerplate code.
> 
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>

These two patches do not apply cleanly to net-next, please respin.

^ permalink raw reply

* Re: UDP wierdness around skb_copy_and_csum_datagram_msg()
From: Jay Smith @ 2016-10-17 17:10 UTC (permalink / raw)
  To: Christian Lamparter
  Cc: Jay Smith, Alan Curry, Eric Dumazet, netdev, Al Viro,
	davem@davemloft.net
In-Reply-To: <2193954.GuvoBo3fQP@debian64>


Trying to revive this thread.

To review:  skb_copy_and_csum_datagram_msg() pretty clearly doesn't do
the right thing since it started using an iov_iter to copy into the
user's iovec.  In particular, if it encounters a datagram that fails the
checksum, the iov_iter continues to point to the end of the failed
datagram's data, and that data makes it out to user-space.

I'd previously sent a test program that consistenly reproduced the UDP(v4)
symptoms of this problem [0].  I've now also taken Christian's netem
suggestion and written a quick program that sends known data over
loopback TCP from one thread and reads it from another.  It optionally
sets up a netem qdisc that corrupts 1% of packets.  As expected, even
with corruption, tcp delivers correct data to the user on pre-3.19
kernels; on 3.19 and later, long transfers usually see corruptions.
(Source for the TCP test program below.)

I've also tried both test programs with the following patch:

diff --git a/net/core/datagram.c b/net/core/datagram.c
index b7de71f..61da091 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -730,6 +730,7 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
 {
        __wsum csum;
        int chunk = skb->len - hlen;
+       struct iov_iter saved_iter;
 
        if (!chunk)
                return 0;
@@ -741,11 +742,16 @@ int skb_copy_and_csum_datagram_msg(struct sk_buff *skb,
                        goto fault;
        } else {
                csum = csum_partial(skb->data, hlen, skb->csum);
+
+               /* save msg_iter state, so we can revert if csum fails. */
+               saved_iter = msg->msg_iter;
                if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter,
                                               chunk, &csum))
                        goto fault;
-               if (csum_fold(csum))
+               if (csum_fold(csum)) {
+                       msg->msg_iter = saved_iter;
                        goto csum_error;
+               }
                if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
                        netdev_rx_csum_fault(skb->dev);
        }


(This is essentially the same fix Alan previously sent [1], except that
it uses struct assignment rather than memcpy'ing the struct iov_iter.)
As expected, both UDP and TCP tests succeed under this fix.

So I've missed whatever conversations happened off-list after Alan's
original report.  But it appears to me that this patch completely
resolves the csum/iov_iter problem for both TCP and UDP; I'm not sure I
see what further problem we'd want to hold the fix off for?

[0] https://www.spinics.net/lists/netdev/msg398026.html
[1] https://patchwork.kernel.org/patch/9260733/


New TCP test program:

#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>

#include <netlink/route/tc.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc/netem.h>

int bytes = 0;
struct sockaddr_in addr;
socklen_t addrLen = sizeof(addr);  


void *sender(void *ignore)
{
  int send = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (send < 0)
  {
    fprintf(stderr, "failed to create sending socket (err=%d: %s)\n", errno, strerror(errno));
    exit(1);
  }

  int ret = connect(send, (struct sockaddr *) &addr, addrLen);
  if (ret != 0)
  {
    fprintf(stderr, "failed to connect sending socket (err=%d: %s)\n", errno, strerror(errno));
    exit(1);
  }

  int i = 0;
  while (i < bytes)
  {
#define OUT_MESSAGE  "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    int w = write(send, OUT_MESSAGE, strlen(OUT_MESSAGE));
    if (w < 0)
    {
      fprintf(stdout, "failed to write byte %d\n", i);
      exit(1);
    }
    i += w;
  }

  close(send);
}

/* set a qdisc on lo with corruption_probability 1% (or remove if if on==0) */
void setCorrupt(int on)
{
  struct nl_sock *sock;
  struct nl_cache *cache;
  struct rtnl_qdisc *q;
  struct rtnl_link *link;
  int if_index;

  sock = nl_socket_alloc();
  nl_connect(sock, NETLINK_ROUTE);

  rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
  link = rtnl_link_get_by_name(cache, "lo");
  if_index = rtnl_link_get_ifindex(link);

  q = rtnl_qdisc_alloc();
  rtnl_tc_set_ifindex(TC_CAST(q), if_index);
  rtnl_tc_set_parent(TC_CAST(q), TC_H_ROOT);
  rtnl_tc_set_handle(TC_CAST(q), TC_HANDLE(1, 0));
  rtnl_tc_set_kind(TC_CAST(q), "netem");
  rtnl_netem_set_corruption_probability(q, 0xffffffff / 100);
  if (on)
  {
    int ret = rtnl_qdisc_add(sock, q, NLM_F_CREATE);
    if (ret < 0)
      {
	fprintf(stderr, "rtnl_qdisc_add error: %s\n", nl_geterror(ret));
	exit(1);
      }
  }
  else
  {
    int ret = rtnl_qdisc_delete(sock, q);
    if (ret < 0)
      {
	fprintf(stderr, "rtnl_qdisc_del error: %s\n", nl_geterror(ret));
	exit(1);
      }
  }

  rtnl_qdisc_put(q);
  nl_socket_free(sock);
  rtnl_link_put(link);
  nl_cache_put(cache);
}


int main(int argc, char **argv)
{
  if (argc < 2)
  {
    fprintf(stderr, "Usage: tcpcsum <number-of-bytes> [corruption-rate]");
    exit(1);
  }

  bytes = atoi(argv[1]);
  int corrupt = argc > 2;

  if (corrupt)
  {
    setCorrupt(1);
  }

  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = inet_addr("127.0.0.1");
  addr.sin_port = htons(0);

  int l = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (l < 0)
  {
    fprintf(stderr, "failed to create listening socket (err=%d: %s)\n", errno, strerror(errno));
    goto exit;
  }

  int ret = bind(l, (struct sockaddr *) &addr, addrLen);
  if (ret != 0)
  {
    fprintf(stderr, "failed to bind listening socket socket (err=%d: %s)\n", errno, strerror(errno));
    goto exit;
  }

  ret = listen(l, 5);
  if (ret != 0)
  {
    fprintf(stderr, "listen failed (err=%d: %s)\n", errno, strerror(errno));
    goto exit;
  }

  ret = getsockname(l, (struct sockaddr *) &addr, &addrLen);
  if (ret != 0)
  {
    fprintf(stderr, "getsockname failed for listening socket socket (err=%d: %s)\n", errno, strerror(errno));
    goto exit;
  }
  else
  {
    printf("listening on port %d\n", ntohs(addr.sin_port));
  }
  
  // Launch writer thread
  pthread_t t;
  ret = pthread_create(&t, NULL, &sender, NULL);
  if (ret != 0)
  {
    fprintf(stderr, "pthread_create failed: (err=%d: %s)\n", errno, strerror(errno));
    goto exit;
  }

  int recv = accept(l, NULL, NULL);
  if (recv < 0)
  {
    fprintf(stderr, "accept failed: (err=%d: %s)\n", errno, strerror(errno));
    goto exit;
  }
   
#define BUFLEN  16384
  char buf[BUFLEN];
  int total = 0;
  int r = 0;
  while((r = read(recv, buf, BUFLEN)))
  {
    if(r < 0)
    {
      perror("read from socket");
      return 1;
    }

    if (r == 0)
    {
      break;
    }
    
    int i;
    for(i= 0; i < r; i++, total++)
    {
      if (buf[i] != 'a')
      {
	fprintf(stdout, "data corruption found at byte %d: %c\n", total, buf[i]);
	goto exit;
      }
    }
  }

  fprintf(stdout, "read %d bytes without data corruption\n", total);

exit:
  if (corrupt)
  {
    setCorrupt(0);
  }
  exit(0);
}

^ permalink raw reply related

* Re: [PATCH -next] net: ethernet: nb8800: fix error return code in nb8800_open()
From: David Miller @ 2016-10-17 17:12 UTC (permalink / raw)
  To: weiyj.lk
  Cc: jarod, sf84, peter.chen, mans, tremyfr, arnd, f.fainelli,
	weiyongjun1, netdev
In-Reply-To: <1476718318-28428-1-git-send-email-weiyj.lk@gmail.com>

From: Wei Yongjun <weiyj.lk@gmail.com>
Date: Mon, 17 Oct 2016 15:31:58 +0000

> From: Wei Yongjun <weiyongjun1@huawei.com>
> 
> Fix to return error code -ENODEV from the of_phy_connect() error
> handling case instead of 0, as done elsewhere in this function.
> 
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>

Applied.

^ permalink raw reply

* Re: [PATCH v3 net-next 2/2] net: deprecate eth_change_mtu, remove usage
From: David Miller @ 2016-10-17 17:15 UTC (permalink / raw)
  To: kubakici; +Cc: jarod, linux-kernel, netdev
In-Reply-To: <20161017180027.4936fa15@jkicinski-Precision-T1700>

From: Jakub Kicinski <kubakici@wp.pl>
Date: Mon, 17 Oct 2016 18:00:27 +0100

> On Mon, 17 Oct 2016 12:49:54 -0400 (EDT), David Miller wrote:
>> From: Jakub Kicinski <kubakici@wp.pl>
>> Date: Mon, 17 Oct 2016 17:20:06 +0100
>> 
>> > Please correct me if I'm wrong but it seems like we are now limiting
>> > _all_ ethernet drivers to ETH_DATA_LEN in net-next.  
>> 
>> No, because the driver can increase the netdev->max_mtu value as needed.
> 
> But since almost no driver is doing that, yet, right now in net-next
> jumbo frames are not possible, no?  I thought the idea was the leave
> the value at 0 so drivers can opt-in as needed but since setup_ether()
> is initializing to 1500 now all ethernet driver get a default of
> limiting to 1500.
> 
> IOW this patch made checks which were done only in eth_change_mtu()
> mandatory for all drivers.

The conversions he made were in cases where the driver's method was doing
exactly the same thing eth_change_mtu() does not.

He strictly worked to keep the behavior identical compared to before his
changes, please read his patches carefully.

^ permalink raw reply

* Re: [PATCH net-next] net: report right mtu value in error message
From: David Miller @ 2016-10-17 17:15 UTC (permalink / raw)
  To: jakub.kicinski; +Cc: netdev, jarod
In-Reply-To: <1476723742-7557-1-git-send-email-jakub.kicinski@netronome.com>

From: Jakub Kicinski <jakub.kicinski@netronome.com>
Date: Mon, 17 Oct 2016 18:02:22 +0100

> Check is for max_mtu but message reports min_mtu.
> 
> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>

Good catch, applied, thanks.

^ permalink raw reply

* Re: [PATCH -next] fsl/fman: fix error return code in mac_probe()
From: David Miller @ 2016-10-17 17:17 UTC (permalink / raw)
  To: weiyj.lk; +Cc: madalin.bucur, weiyongjun1, netdev
In-Reply-To: <1476717596-19526-1-git-send-email-weiyj.lk@gmail.com>

From: Wei Yongjun <weiyj.lk@gmail.com>
Date: Mon, 17 Oct 2016 15:19:56 +0000

> From: Wei Yongjun <weiyongjun1@huawei.com>
> 
> Fix to return a negative error code from the error handling
> case instead of 0, as done elsewhere in this function.
> 
> Fixes: 3933961682a3 ("fsl/fman: Add FMan MAC driver")
> Signed-off-by: Wei Yongjun <weiyongjun1@huawei.com>

Applied, thanks.

^ permalink raw reply

* Re: [PATCH 3/9] ipv6: sr: add support for SRH encapsulation and injection with lwtunnels
From: Tom Herbert @ 2016-10-17 17:17 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1476715350-18983-4-git-send-email-david.lebrun@uclouvain.be>

On Mon, Oct 17, 2016 at 7:42 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> This patch creates a new type of interfaceless lightweight tunnel (SEG6),
> enabling the encapsulation and injection of SRH within locally emitted
> packets and forwarded packets.
>
> From a configuration viewpoint, a seg6 tunnel would be configured as follows:
>
>   ip -6 ro ad fc00::1/128 via <gw> encap seg6 mode encap segs fc42::1,fc42::2,fc42::3
>
> Any packet whose destination address is fc00::1 would thus be encapsulated
> within an outer IPv6 header containing the SRH with three segments, and would
> actually be routed to the first segment of the list. If `mode inline' was
> specified instead of `mode encap', then the SRH would be directly inserted
> after the IPv6 header without outer encapsulation.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/seg6_iptunnel.h      |   6 +
>  include/net/seg6.h                 |   7 +
>  include/uapi/linux/lwtunnel.h      |   1 +
>  include/uapi/linux/seg6_iptunnel.h |  33 ++++
>  net/core/lwtunnel.c                |   2 +
>  net/ipv6/Makefile                  |   2 +-
>  net/ipv6/seg6_iptunnel.c           | 315 +++++++++++++++++++++++++++++++++++++
>  7 files changed, 365 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/seg6_iptunnel.h
>  create mode 100644 include/uapi/linux/seg6_iptunnel.h
>  create mode 100644 net/ipv6/seg6_iptunnel.c
>
> diff --git a/include/linux/seg6_iptunnel.h b/include/linux/seg6_iptunnel.h
> new file mode 100644
> index 0000000..5377cf6
> --- /dev/null
> +++ b/include/linux/seg6_iptunnel.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_IPTUNNEL_H
> +#define _LINUX_SEG6_IPTUNNEL_H
> +
> +#include <uapi/linux/seg6_iptunnel.h>
> +
> +#endif
> diff --git a/include/net/seg6.h b/include/net/seg6.h
> index 89b819e..228f90f 100644
> --- a/include/net/seg6.h
> +++ b/include/net/seg6.h
> @@ -16,6 +16,7 @@
>
>  #include <linux/net.h>
>  #include <linux/ipv6.h>
> +#include <net/lwtunnel.h>
>
>  struct seg6_pernet_data {
>         struct mutex lock;
> @@ -37,5 +38,11 @@ static inline void seg6_pernet_unlock(struct net *net)
>         mutex_unlock(&seg6_pernet(net)->lock);
>  }
>
> +static inline struct seg6_iptunnel_encap *
> +seg6_lwtunnel_encap(struct lwtunnel_state *lwtstate)
> +{
> +       return (struct seg6_iptunnel_encap *)lwtstate->data;
> +}
> +
>  #endif
>
> diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h
> index a478fe8..453cc62 100644
> --- a/include/uapi/linux/lwtunnel.h
> +++ b/include/uapi/linux/lwtunnel.h
> @@ -9,6 +9,7 @@ enum lwtunnel_encap_types {
>         LWTUNNEL_ENCAP_IP,
>         LWTUNNEL_ENCAP_ILA,
>         LWTUNNEL_ENCAP_IP6,
> +       LWTUNNEL_ENCAP_SEG6,
>         __LWTUNNEL_ENCAP_MAX,
>  };
>
> diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
> new file mode 100644
> index 0000000..2794a5f
> --- /dev/null
> +++ b/include/uapi/linux/seg6_iptunnel.h
> @@ -0,0 +1,33 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *      modify it under the terms of the GNU General Public License
> + *      as published by the Free Software Foundation; either version
> + *      2 of the License, or (at your option) any later version.
> + */
> +
> +#ifndef _UAPI_LINUX_SEG6_IPTUNNEL_H
> +#define _UAPI_LINUX_SEG6_IPTUNNEL_H
> +
> +enum {
> +       SEG6_IPTUNNEL_UNSPEC,
> +       SEG6_IPTUNNEL_SRH,
> +       __SEG6_IPTUNNEL_MAX,
> +};
> +#define SEG6_IPTUNNEL_MAX (__SEG6_IPTUNNEL_MAX - 1)
> +
> +struct seg6_iptunnel_encap {
> +       int flags;
> +       struct ipv6_sr_hdr srh[0];
> +};
> +
> +#define SEG6_IPTUN_ENCAP_SIZE(x) (sizeof(*(x)) + (((x)->srh->hdrlen + 1) << 3))
> +
> +#define SEG6_IPTUN_FLAG_ENCAP   0x1
> +
> +#endif
> diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
> index 88fd642..03976e9 100644
> --- a/net/core/lwtunnel.c
> +++ b/net/core/lwtunnel.c
> @@ -39,6 +39,8 @@ static const char *lwtunnel_encap_str(enum lwtunnel_encap_types encap_type)
>                 return "MPLS";
>         case LWTUNNEL_ENCAP_ILA:
>                 return "ILA";
> +       case LWTUNNEL_ENCAP_SEG6:
> +               return "SEG6";
>         case LWTUNNEL_ENCAP_IP6:
>         case LWTUNNEL_ENCAP_IP:
>         case LWTUNNEL_ENCAP_NONE:
> diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
> index 5069257..2fe7b54 100644
> --- a/net/ipv6/Makefile
> +++ b/net/ipv6/Makefile
> @@ -44,7 +44,7 @@ obj-$(CONFIG_IPV6_SIT) += sit.o
>  obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
>  obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
>  obj-$(CONFIG_IPV6_FOU) += fou6.o
> -obj-$(CONFIG_IPV6_SEG6) += seg6.o
> +obj-$(CONFIG_IPV6_SEG6) += seg6.o seg6_iptunnel.o
>
>  obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o
>  obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload)
> diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
> new file mode 100644
> index 0000000..461375c
> --- /dev/null
> +++ b/net/ipv6/seg6_iptunnel.c
> @@ -0,0 +1,315 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *        modify it under the terms of the GNU General Public License
> + *        as published by the Free Software Foundation; either version
> + *        2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/types.h>
> +#include <linux/skbuff.h>
> +#include <linux/net.h>
> +#include <linux/module.h>
> +#include <net/ip.h>
> +#include <net/lwtunnel.h>
> +#include <net/netevent.h>
> +#include <net/netns/generic.h>
> +#include <net/ip6_fib.h>
> +#include <net/route.h>
> +#include <net/seg6.h>
> +#include <linux/seg6.h>
> +#include <linux/seg6_iptunnel.h>
> +#include <net/addrconf.h>
> +#include <net/ip6_route.h>
> +
> +static const struct nla_policy seg6_iptunnel_policy[SEG6_IPTUNNEL_MAX + 1] = {
> +       [SEG6_IPTUNNEL_SRH]     = { .type = NLA_BINARY },
> +};
> +
> +int nla_put_srh(struct sk_buff *skb, int attrtype,
> +               struct seg6_iptunnel_encap *tuninfo)
> +{
> +       struct nlattr *nla;
> +       struct seg6_iptunnel_encap *data;
> +       int len;
> +
> +       len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
> +
> +       nla = nla_reserve(skb, attrtype, len);
> +       if (!nla)
> +               return -EMSGSIZE;
> +
> +       data = nla_data(nla);
> +       memcpy(data, tuninfo, len);
> +
> +       return 0;
> +}
> +
> +static void set_tun_src(struct net *net, struct net_device *dev,
> +                       struct in6_addr *daddr, struct in6_addr *saddr)
> +{
> +       struct in6_addr *tun_src;
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +
> +       rcu_read_lock();
> +
> +       tun_src = rcu_dereference(sdata->tun_src);
> +
> +       if (!ipv6_addr_any(tun_src)) {
> +               memcpy(saddr, tun_src, sizeof(struct in6_addr));
> +       } else {
> +               ipv6_dev_get_saddr(net, dev, daddr, IPV6_PREFER_SRC_PUBLIC,
> +                                  saddr);
> +       }
> +
> +       rcu_read_unlock();
> +}
> +
> +/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
> +static int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
> +{
> +       struct ipv6hdr *hdr, *inner_hdr;
> +       struct ipv6_sr_hdr *isrh;
> +       struct net *net = dev_net(skb_dst(skb)->dev);
> +       int hdrlen, tot_len, err;
> +
> +       hdrlen = (osrh->hdrlen + 1) << 3;
> +       tot_len = hdrlen + sizeof(*hdr);
> +
> +       err = pskb_expand_head(skb, tot_len, 0, GFP_ATOMIC);
> +       if (unlikely(err))
> +               return err;
> +
> +       inner_hdr = ipv6_hdr(skb);
> +
> +       skb_push(skb, tot_len);
> +       skb_reset_network_header(skb);
> +       skb_mac_header_rebuild(skb);
> +       hdr = ipv6_hdr(skb);
> +
> +       /* inherit tc, flowlabel and hlim
> +        * hlim will be decremented in ip6_forward() afterwards and
> +        * decapsulation will overwrite inner hlim with outer hlim
> +        */
> +       ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
> +                    ip6_flowlabel(inner_hdr));
> +       hdr->hop_limit = inner_hdr->hop_limit;
> +       hdr->nexthdr = NEXTHDR_ROUTING;
> +
> +       isrh = (void *)hdr + sizeof(*hdr);
> +       memcpy(isrh, osrh, hdrlen);
> +
> +       isrh->nexthdr = NEXTHDR_IPV6;
> +
> +       hdr->daddr = isrh->segments[isrh->first_segment];
> +       set_tun_src(net, skb->dev, &hdr->daddr, &hdr->saddr);
> +
> +       return 0;
> +}
> +
> +/* insert an SRH within an IPv6 packet, just after the IPv6 header */
> +static int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
> +{
> +       struct ipv6hdr *hdr, *oldhdr;
> +       struct ipv6_sr_hdr *isrh;
> +       int hdrlen, err;
> +
> +       hdrlen = (osrh->hdrlen + 1) << 3;
> +
> +       err = pskb_expand_head(skb, hdrlen, 0, GFP_ATOMIC);
> +       if (unlikely(err))
> +               return err;
> +
> +       oldhdr = ipv6_hdr(skb);
> +
> +       skb_push(skb, hdrlen);
> +       skb_reset_network_header(skb);
> +       skb_mac_header_rebuild(skb);
> +
> +       hdr = ipv6_hdr(skb);
> +
> +       memmove(hdr, oldhdr, sizeof(*hdr));
> +
> +       isrh = (void *)hdr + sizeof(*hdr);
> +       memcpy(isrh, osrh, hdrlen);
> +
> +       isrh->nexthdr = hdr->nexthdr;
> +       hdr->nexthdr = NEXTHDR_ROUTING;
> +
> +       isrh->segments[0] = hdr->daddr;
> +       hdr->daddr = isrh->segments[isrh->first_segment];
> +
> +       return 0;
> +}
> +
> +static int seg6_do_srh(struct sk_buff *skb)
> +{
> +       struct dst_entry *dst = skb_dst(skb);
> +       struct seg6_iptunnel_encap *tinfo = seg6_lwtunnel_encap(dst->lwtstate);
> +       int err = 0;
> +
> +       if (likely(!skb->encapsulation)) {
> +               skb_reset_inner_headers(skb);
> +               skb->encapsulation = 1;
> +       }
> +
> +       if (tinfo->flags & SEG6_IPTUN_FLAG_ENCAP) {
> +               err = seg6_do_srh_encap(skb, tinfo->srh);
> +       } else {
> +               err = seg6_do_srh_inline(skb, tinfo->srh);
> +               skb_reset_inner_headers(skb);
> +       }
> +
> +       if (err)
> +               return err;
> +
> +       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
> +       skb_set_transport_header(skb, sizeof(struct ipv6hdr));
> +
> +       skb_set_inner_protocol(skb, skb->protocol);
> +
> +       return 0;
> +}
> +
> +int seg6_input(struct sk_buff *skb)
> +{
> +       int err;
> +
> +       err = seg6_do_srh(skb);
> +       if (unlikely(err))
> +               return err;
> +
> +       skb_dst_drop(skb);
> +       ip6_route_input(skb);
> +
> +       return dst_input(skb);
> +}
> +
> +int seg6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
> +{
> +       int err;
> +       struct dst_entry *dst;
> +       struct ipv6hdr *hdr;
> +       struct flowi6 fl6;
> +
> +       err = seg6_do_srh(skb);
> +       if (unlikely(err))
> +               return err;
> +
> +       hdr = ipv6_hdr(skb);
> +       fl6.daddr = hdr->daddr;
> +       fl6.saddr = hdr->saddr;
> +       fl6.flowlabel = ip6_flowinfo(hdr);
> +       fl6.flowi6_mark = skb->mark;
> +       fl6.flowi6_proto = hdr->nexthdr;
> +
> +       skb_dst_drop(skb);
> +
> +       err = ip6_dst_lookup(net, sk, &dst, &fl6);

Please look at the use of dst_cache that I added in ila_lwt.c, I think
the SR has similar properties and might be able to use dst_cache which
is a significant performance improvement when source packets from a
connected socket. The dst_cache will work in LWT as long as the new
destination address is the same and other input to routing (saddr,
flow label, mark, etc.) are either always the same or assumed to be
immaterial to lookup of the second route.

> +       if (unlikely(err))
> +               return err;
> +
> +       skb_dst_set(skb, dst);
> +
> +       return dst_output(net, sk, skb);
> +}
> +
> +static int seg6_build_state(struct net_device *dev, struct nlattr *nla,
> +                           unsigned int family, const void *cfg,
> +                           struct lwtunnel_state **ts)
> +{
> +       struct seg6_iptunnel_encap *tuninfo, *tuninfo_new;
> +       struct nlattr *tb[SEG6_IPTUNNEL_MAX + 1];
> +       struct lwtunnel_state *newts;
> +       int tuninfo_len;
> +       int err;
> +
> +       err = nla_parse_nested(tb, SEG6_IPTUNNEL_MAX, nla,
> +                              seg6_iptunnel_policy);
> +
> +       if (err < 0)
> +               return err;
> +
> +       if (!tb[SEG6_IPTUNNEL_SRH])
> +               return -EINVAL;
> +
> +       tuninfo = nla_data(tb[SEG6_IPTUNNEL_SRH]);
> +       tuninfo_len = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
> +
> +       newts = lwtunnel_state_alloc(tuninfo_len);
> +       if (!newts)
> +               return -ENOMEM;
> +
> +       newts->len = tuninfo_len;
> +       tuninfo_new = seg6_lwtunnel_encap(newts);
> +       memcpy(tuninfo_new, tuninfo, tuninfo_len);
> +
> +       newts->type = LWTUNNEL_ENCAP_SEG6;
> +       newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
> +                       LWTUNNEL_STATE_INPUT_REDIRECT;
> +       newts->headroom = SEG6_IPTUN_ENCAP_SIZE(tuninfo);
> +
> +       *ts = newts;
> +
> +       return 0;
> +}
> +
> +static int seg6_fill_encap_info(struct sk_buff *skb,
> +                               struct lwtunnel_state *lwtstate)
> +{
> +       struct seg6_iptunnel_encap *tuninfo = seg6_lwtunnel_encap(lwtstate);
> +
> +       if (nla_put_srh(skb, SEG6_IPTUNNEL_SRH, tuninfo))
> +               return -EMSGSIZE;
> +
> +       return 0;
> +}
> +
> +static int seg6_encap_nlsize(struct lwtunnel_state *lwtstate)
> +{
> +       struct seg6_iptunnel_encap *tuninfo = seg6_lwtunnel_encap(lwtstate);
> +
> +       return nla_total_size(SEG6_IPTUN_ENCAP_SIZE(tuninfo));
> +}
> +
> +static int seg6_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
> +{
> +       struct seg6_iptunnel_encap *a_hdr = seg6_lwtunnel_encap(a);
> +       struct seg6_iptunnel_encap *b_hdr = seg6_lwtunnel_encap(b);
> +       int len = SEG6_IPTUN_ENCAP_SIZE(a_hdr);
> +
> +       if (len != SEG6_IPTUN_ENCAP_SIZE(b_hdr))
> +               return 1;
> +
> +       return memcmp(a_hdr, b_hdr, len);
> +}
> +
> +static const struct lwtunnel_encap_ops seg6_iptun_ops = {
> +       .build_state = seg6_build_state,
> +       .output = seg6_output,
> +       .input = seg6_input,
> +       .fill_encap = seg6_fill_encap_info,
> +       .get_encap_size = seg6_encap_nlsize,
> +       .cmp_encap = seg6_encap_cmp,
> +};
> +
> +static int __init seg6_iptunnel_init(void)
> +{
> +       return lwtunnel_encap_add_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
> +}
> +module_init(seg6_iptunnel_init);
> +
> +static void __exit seg6_iptunnel_exit(void)
> +{
> +       lwtunnel_encap_del_ops(&seg6_iptun_ops, LWTUNNEL_ENCAP_SEG6);
> +}
> +module_exit(seg6_iptunnel_exit);
> +
> +MODULE_DESCRIPTION("Segment Routing with IPv6 IP Tunnels");
> +MODULE_LICENSE("GPL v2");
> +
> --
> 2.7.3
>

^ permalink raw reply

* Re: [PATCH v3 net-next 2/2] net: deprecate eth_change_mtu, remove usage
From: Jakub Kicinski @ 2016-10-17 17:20 UTC (permalink / raw)
  To: David Miller; +Cc: jarod, linux-kernel, netdev
In-Reply-To: <20161017.131513.135103913948374087.davem@davemloft.net>

On Mon, 17 Oct 2016 13:15:13 -0400 (EDT), David Miller wrote:
> From: Jakub Kicinski <kubakici@wp.pl>
> Date: Mon, 17 Oct 2016 18:00:27 +0100
> 
> > On Mon, 17 Oct 2016 12:49:54 -0400 (EDT), David Miller wrote:  
> >> From: Jakub Kicinski <kubakici@wp.pl>
> >> Date: Mon, 17 Oct 2016 17:20:06 +0100
> >>   
> >> > Please correct me if I'm wrong but it seems like we are now limiting
> >> > _all_ ethernet drivers to ETH_DATA_LEN in net-next.    
> >> 
> >> No, because the driver can increase the netdev->max_mtu value as needed.  
> > 
> > But since almost no driver is doing that, yet, right now in net-next
> > jumbo frames are not possible, no?  I thought the idea was the leave
> > the value at 0 so drivers can opt-in as needed but since setup_ether()
> > is initializing to 1500 now all ethernet driver get a default of
> > limiting to 1500.
> > 
> > IOW this patch made checks which were done only in eth_change_mtu()
> > mandatory for all drivers.  
> 
> The conversions he made were in cases where the driver's method was doing
> exactly the same thing eth_change_mtu() does not.
> 
> He strictly worked to keep the behavior identical compared to before his
> changes, please read his patches carefully.

Hm.  I must be missing something really obvious.  I just booted
net-next an hour ago and couldn't set MTU to anything larger than 1500
on either nfp or igb.  As far as I can read the code it will set the
max_mtu to 1500 in setup_ether() but none of the jumbo-capable drivers
had been touched by Jarod so far...

^ permalink raw reply

* Re: [PATCH] crypto: ccm - avoid scatterlist for MAC encryption
From: Ard Biesheuvel @ 2016-10-17 17:21 UTC (permalink / raw)
  To: Andy Lutomirski
  Cc: Johannes Berg, Sergey Senozhatsky, <netdev@vger.kernel.org>,
	Herbert Xu, David S. Miller,
	<linux-wireless@vger.kernel.org>,
	linux-kernel@vger.kernel.org, Jouni Malinen
In-Reply-To: <CALCETrUWW2A1XK7BzcajTcBzg58SDUCTE35Hj1vmbywTLCe2vQ@mail.gmail.com>

On 17 October 2016 at 18:08, Andy Lutomirski <luto@amacapital.net> wrote:
> On Mon, Oct 17, 2016 at 12:37 AM, Ard Biesheuvel
> <ard.biesheuvel@linaro.org> wrote:
>> On 17 October 2016 at 08:28, Johannes Berg <johannes@sipsolutions.net> wrote:
>>> On Sat, 2016-10-15 at 18:16 +0100, Ard Biesheuvel wrote:
>>>> The CCM code goes out of its way to perform the CTR encryption of the
>>>> MAC using the subordinate CTR driver. To this end, it tweaks the
>>>> input and output scatterlists so the aead_req 'odata' and/or
>>>> 'auth_tag' fields [which may live on the stack] are prepended to the
>>>> CTR payload. This involves calling sg_set_buf() on addresses which
>>>> are not direct mapped, which is not supported.
>>>
>>>> Since the calculation of the MAC keystream involves a single call
>>>> into the cipher, to which we have a handle already given that the
>>>> CBC-MAC calculation uses it as well, just calculate the MAC keystream
>>>> directly, and record it in the aead_req private context so we can
>>>> apply it to the MAC in cypto_ccm_auth_mac(). This greatly simplifies
>>>> the scatterlist manipulation, and no longer requires scatterlists to
>>>> refer to buffers that may live on the stack.
>>>
>>> No objection from me, Herbert?
>>>
>>> I'm getting a bit nervous though - I'd rather have any fix first so
>>> people get things working again - so maybe I'll apply your other patch
>>> and mine first, and then we can replace yours by this later.
>>>
>>
>> Could we get a statement first whether it is supported to allocate
>> aead_req (and other crypto req structures) on the stack? If not, then
>> we have our work cut out for us. But if it is, I'd rather we didn't
>> apply the kzalloc/kfree patch, since it is just a workaround for the
>> broken generic CCM driver, for which a fix is already available.
>
> I'm not a crypto person, but I don't see why not.  There's even a
> helper called SKCIPHER_REQUEST_ON_STACK. :)  The only problem I know
> of is pointing a scatterlist at the stack, which is bad for much the
> same reason as doing real DMA from the stack.

Excellent point!

So the CCM code was an easy fix, although the RFC4309 part is still broken:

It does

"""
scatterwalk_map_and_copy(iv + 16, req->src, 0, req->assoclen - 8, 0);
...
sg_set_buf(rctx->src, iv + 16, req->assoclen - 8);
sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
"""

which essentially just hides the last 8 bytes of associated data from
the inner CCM transform. So we'd need to rewrite this part to create a
new scatterlist that omits those 8 bytes instead of just replacing the
first sg entry and point it to another buffer entirely (and copy the
data into it)

The GCM code is much more complicated, and does not easily allow the
offending sg_set_buf() calls to be turned into something that only
involves direct mapped memory references. I haven't looked at anything
else.

Annoyingly, all this complication with scatterlists etc is for doing
asynchronous crypto via DMA capable crypto accelerators, and the
networking code (ipsec as well as mac80211, afaik) only allow
synchronous in the first place, given that they execute in softirq
context.

^ permalink raw reply

* Re: [PATCH net] bnx2: fix locking when netconsole is used
From: David Miller @ 2016-10-17 17:21 UTC (permalink / raw)
  To: ivecera; +Cc: netdev, sony.chacko, Dept-HSGLinuxNICDev
In-Reply-To: <1476721231-31624-1-git-send-email-ivecera@redhat.com>

From: Ivan Vecera <ivecera@redhat.com>
Date: Mon, 17 Oct 2016 18:20:31 +0200

> diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
> index 27f11a5..9c408413 100644
> --- a/drivers/net/ethernet/broadcom/bnx2.c
> +++ b/drivers/net/ethernet/broadcom/bnx2.c
> @@ -272,21 +272,24 @@ static u32
>  bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
>  {
>  	u32 val;
> +	unsigned long flags;
>  

Please order local variable declarations from longest to shortest
line.

Thank you.

^ permalink raw reply

* Re: [PATCH 4/9] ipv6: sr: add core files for SR HMAC support
From: Tom Herbert @ 2016-10-17 17:24 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1476715350-18983-5-git-send-email-david.lebrun@uclouvain.be>

On Mon, Oct 17, 2016 at 7:42 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> This patch adds the necessary functions to compute and check the HMAC signature
> of an SR-enabled packet. Two HMAC algorithms are supported: hmac(sha1) and
> hmac(sha256).
>
> In order to avoid dynamic memory allocation for each HMAC computation,
> a per-cpu ring buffer is allocated for this purpose.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/seg6_hmac.h      |   6 +
>  include/net/seg6_hmac.h        |  61 ++++++
>  include/uapi/linux/seg6_hmac.h |  20 ++
>  net/ipv6/seg6_hmac.c           | 432 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 519 insertions(+)
>  create mode 100644 include/linux/seg6_hmac.h
>  create mode 100644 include/net/seg6_hmac.h
>  create mode 100644 include/uapi/linux/seg6_hmac.h
>  create mode 100644 net/ipv6/seg6_hmac.c
>
> diff --git a/include/linux/seg6_hmac.h b/include/linux/seg6_hmac.h
> new file mode 100644
> index 0000000..da437eb
> --- /dev/null
> +++ b/include/linux/seg6_hmac.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_HMAC_H
> +#define _LINUX_SEG6_HMAC_H
> +
> +#include <uapi/linux/seg6_hmac.h>
> +
> +#endif
> diff --git a/include/net/seg6_hmac.h b/include/net/seg6_hmac.h
> new file mode 100644
> index 0000000..6e5ee6a
> --- /dev/null
> +++ b/include/net/seg6_hmac.h
> @@ -0,0 +1,61 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *      modify it under the terms of the GNU General Public License
> + *      as published by the Free Software Foundation; either version
> + *      2 of the License, or (at your option) any later version.
> + */
> +
> +#ifndef _NET_SEG6_HMAC_H
> +#define _NET_SEG6_HMAC_H
> +
> +#include <net/flow.h>
> +#include <net/ip6_fib.h>
> +#include <net/sock.h>
> +#include <linux/ip.h>
> +#include <linux/ipv6.h>
> +#include <linux/route.h>
> +#include <net/seg6.h>
> +#include <linux/seg6_hmac.h>
> +
> +#define SEG6_HMAC_MAX_DIGESTSIZE       160
> +#define SEG6_HMAC_RING_SIZE            256
> +
> +struct seg6_hmac_info {
> +       struct list_head list;
> +
> +       u32 hmackeyid;
> +       char secret[SEG6_HMAC_SECRET_LEN];
> +       u8 slen;
> +       u8 alg_id;
> +};
> +
> +struct seg6_hmac_algo {
> +       u8 alg_id;
> +       char name[64];
> +       struct crypto_shash * __percpu *tfms;
> +       struct shash_desc * __percpu *shashs;
> +};

A lot of this looks generic and potentially useful in other cases
where we we want to do HMAC over some headers (I'm thinking GUE can
probably use some of this for header authentication). Might be nice to
split out the generic pieces at some point.

> +
> +extern int seg6_hmac_compute(struct seg6_hmac_info *hinfo,
> +                            struct ipv6_sr_hdr *hdr, struct in6_addr *saddr,
> +                            u8 *output);
> +extern struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key);
> +extern int seg6_hmac_info_add(struct net *net, u32 key,
> +                             struct seg6_hmac_info *hinfo);
> +extern int seg6_hmac_info_del(struct net *net, u32 key,
> +                             struct seg6_hmac_info *hinfo);
> +extern int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
> +                         struct ipv6_sr_hdr *srh);
> +extern bool seg6_hmac_validate_skb(struct sk_buff *skb);
> +extern int seg6_hmac_init(void);
> +extern void seg6_hmac_exit(void);
> +extern int seg6_hmac_net_init(struct net *net);
> +extern void seg6_hmac_net_exit(struct net *net);
> +
> +#endif
> diff --git a/include/uapi/linux/seg6_hmac.h b/include/uapi/linux/seg6_hmac.h
> new file mode 100644
> index 0000000..0b5eda7
> --- /dev/null
> +++ b/include/uapi/linux/seg6_hmac.h
> @@ -0,0 +1,20 @@
> +#ifndef _UAPI_LINUX_SEG6_HMAC_H
> +#define _UAPI_LINUX_SEG6_HMAC_H
> +
> +#define SEG6_HMAC_SECRET_LEN   64
> +#define SEG6_HMAC_FIELD_LEN    32
> +
> +struct sr6_tlv_hmac {
> +       __u8 type;
> +       __u8 len;
> +       __u16 reserved;
> +       __be32 hmackeyid;
> +       __u8 hmac[SEG6_HMAC_FIELD_LEN];
> +} __attribute__((packed));
> +
> +enum {
> +       SEG6_HMAC_ALGO_SHA1 = 1,
> +       SEG6_HMAC_ALGO_SHA256 = 2,
> +};
> +
> +#endif
> diff --git a/net/ipv6/seg6_hmac.c b/net/ipv6/seg6_hmac.c
> new file mode 100644
> index 0000000..91bd59a
> --- /dev/null
> +++ b/net/ipv6/seg6_hmac.c
> @@ -0,0 +1,432 @@
> +/*
> + *  SR-IPv6 implementation -- HMAC functions
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *      modify it under the terms of the GNU General Public License
> + *      as published by the Free Software Foundation; either version
> + *      2 of the License, or (at your option) any later version.
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/socket.h>
> +#include <linux/sockios.h>
> +#include <linux/net.h>
> +#include <linux/netdevice.h>
> +#include <linux/in6.h>
> +#include <linux/icmpv6.h>
> +#include <linux/mroute6.h>
> +#include <linux/slab.h>
> +
> +#include <linux/netfilter.h>
> +#include <linux/netfilter_ipv6.h>
> +
> +#include <net/sock.h>
> +#include <net/snmp.h>
> +
> +#include <net/ipv6.h>
> +#include <net/protocol.h>
> +#include <net/transp_v6.h>
> +#include <net/rawv6.h>
> +#include <net/ndisc.h>
> +#include <net/ip6_route.h>
> +#include <net/addrconf.h>
> +#include <net/xfrm.h>
> +
> +#include <linux/cryptohash.h>
> +#include <crypto/hash.h>
> +#include <crypto/sha.h>
> +#include <net/seg6.h>
> +#include <net/genetlink.h>
> +#include <net/seg6_hmac.h>
> +#include <linux/random.h>
> +
> +static char * __percpu *hmac_ring;
> +
> +static struct seg6_hmac_algo hmac_algos[] = {
> +       {
> +               .alg_id = SEG6_HMAC_ALGO_SHA1,
> +               .name = "hmac(sha1)",
> +       },
> +       {
> +               .alg_id = SEG6_HMAC_ALGO_SHA256,
> +               .name = "hmac(sha256)",
> +       },
> +};
> +
> +static struct seg6_hmac_algo *__hmac_get_algo(u8 alg_id)
> +{
> +       int i, alg_count;
> +       struct seg6_hmac_algo *algo;
> +
> +       alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
> +       for (i = 0; i < alg_count; i++) {
> +               algo = &hmac_algos[i];
> +               if (algo->alg_id == alg_id)
> +                       return algo;
> +       }
> +
> +       return NULL;
> +}
> +
> +static int __do_hmac(struct seg6_hmac_info *hinfo, const char *text, u8 psize,
> +                    u8 *output, int outlen)
> +{
> +       struct crypto_shash *tfm;
> +       struct shash_desc *shash;
> +       struct seg6_hmac_algo *algo;
> +       int ret, dgsize;
> +
> +       algo = __hmac_get_algo(hinfo->alg_id);
> +       if (!algo)
> +               return -ENOENT;
> +
> +       tfm = *this_cpu_ptr(algo->tfms);
> +
> +       dgsize = crypto_shash_digestsize(tfm);
> +       if (dgsize > outlen) {
> +               pr_debug("sr-ipv6: __do_hmac: digest size too big (%d / %d)\n",
> +                        dgsize, outlen);
> +               return -ENOMEM;
> +       }
> +
> +       ret = crypto_shash_setkey(tfm, hinfo->secret, hinfo->slen);
> +       if (ret < 0) {
> +               pr_debug("sr-ipv6: crypto_shash_setkey failed: err %d\n", ret);
> +               goto failed;
> +       }
> +
> +       shash = *this_cpu_ptr(algo->shashs);
> +       shash->tfm = tfm;
> +
> +       ret = crypto_shash_digest(shash, text, psize, output);
> +       if (ret < 0) {
> +               pr_debug("sr-ipv6: crypto_shash_digest failed: err %d\n", ret);
> +               goto failed;
> +       }
> +
> +       return dgsize;
> +
> +failed:
> +       return ret;
> +}
> +
> +int seg6_hmac_compute(struct seg6_hmac_info *hinfo, struct ipv6_sr_hdr *hdr,
> +                     struct in6_addr *saddr, u8 *output)
> +{
> +       int plen, i, dgsize, wrsize;
> +       char *ring, *off;
> +       u8 tmp_out[SEG6_HMAC_MAX_DIGESTSIZE];
> +       __be32 hmackeyid = cpu_to_be32(hinfo->hmackeyid);
> +
> +       /* a 160-byte buffer for digest output allows to store highest known
> +        * hash function (RadioGatun) with up to 1216 bits
> +        */
> +
> +       /* saddr(16) + first_seg(1) + cleanup(1) + keyid(4) + seglist(16n) */
> +       plen = 16 + 1 + 1 + 4 + (hdr->first_segment + 1) * 16;
> +
> +       /* this limit allows for 14 segments */
> +       if (plen >= SEG6_HMAC_RING_SIZE)
> +               return -EMSGSIZE;
> +
> +       local_bh_disable();
> +       ring = *this_cpu_ptr(hmac_ring);
> +       off = ring;
> +       memcpy(off, saddr, 16);
> +       off += 16;
> +       *off++ = hdr->first_segment;
> +       *off++ = !!(sr_get_flags(hdr) & SR6_FLAG_CLEANUP) << 7;
> +       memcpy(off, &hmackeyid, 4);
> +       off += 4;
> +
> +       for (i = 0; i < hdr->first_segment + 1; i++) {
> +               memcpy(off, hdr->segments + i, 16);
> +               off += 16;
> +       }
> +
> +       dgsize = __do_hmac(hinfo, ring, plen, tmp_out,
> +                          SEG6_HMAC_MAX_DIGESTSIZE);
> +       local_bh_enable();
> +
> +       if (dgsize < 0)
> +               return dgsize;
> +
> +       wrsize = SEG6_HMAC_FIELD_LEN;
> +       if (wrsize > dgsize)
> +               wrsize = dgsize;
> +
> +       memset(output, 0, SEG6_HMAC_FIELD_LEN);
> +       memcpy(output, tmp_out, wrsize);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(seg6_hmac_compute);
> +
> +/* checks if an incoming SR-enabled packet's HMAC status matches
> + * the incoming policy.
> + *
> + * called with rcu_read_lock()
> + */
> +bool seg6_hmac_validate_skb(struct sk_buff *skb)
> +{
> +       struct inet6_dev *idev;
> +       struct ipv6_sr_hdr *srh;
> +       struct sr6_tlv_hmac *tlv;
> +       struct seg6_hmac_info *hinfo;
> +       struct net *net = dev_net(skb->dev);
> +       u8 hmac_output[SEG6_HMAC_FIELD_LEN];
> +
> +       idev = __in6_dev_get(skb->dev);
> +
> +       srh = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +       tlv = seg6_get_tlv_hmac(srh);
> +
> +       /* mandatory check but no tlv */
> +       if (idev->cnf.seg6_require_hmac > 0 && !tlv)
> +               return false;
> +
> +       /* no check */
> +       if (idev->cnf.seg6_require_hmac < 0)
> +               return true;
> +
> +       /* check only if present */
> +       if (idev->cnf.seg6_require_hmac == 0 && !tlv)
> +               return true;
> +
> +       /* now, seg6_require_hmac >= 0 && tlv */
> +
> +       hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid));
> +       if (!hinfo)
> +               return false;
> +
> +       if (seg6_hmac_compute(hinfo, srh, &ipv6_hdr(skb)->saddr, hmac_output))
> +               return false;
> +
> +       if (memcmp(hmac_output, tlv->hmac, SEG6_HMAC_FIELD_LEN) != 0)
> +               return false;
> +
> +       return true;
> +}
> +
> +/* called with rcu_read_lock() */
> +struct seg6_hmac_info *seg6_hmac_info_lookup(struct net *net, u32 key)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct seg6_hmac_info *hinfo;
> +
> +       list_for_each_entry_rcu(hinfo, &sdata->hmac_infos, list) {
> +               if (hinfo->hmackeyid == key)
> +                       return hinfo;
> +       }
> +
> +       return NULL;
> +}
> +EXPORT_SYMBOL(seg6_hmac_info_lookup);
> +
> +int seg6_hmac_info_add(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct seg6_hmac_info *old_hinfo;
> +
> +       old_hinfo = seg6_hmac_info_lookup(net, key);
> +       if (old_hinfo)
> +               return -EEXIST;
> +
> +       list_add_rcu(&hinfo->list, &sdata->hmac_infos);
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(seg6_hmac_info_add);
> +
> +int seg6_hmac_info_del(struct net *net, u32 key, struct seg6_hmac_info *hinfo)
> +{
> +       struct seg6_hmac_info *tmp;
> +
> +       tmp = seg6_hmac_info_lookup(net, key);
> +       if (!tmp)
> +               return -ENOENT;
> +
> +       /* entry was replaced, ignore deletion */
> +       if (tmp != hinfo)
> +               return -ENOENT;
> +
> +       list_del_rcu(&hinfo->list);
> +       synchronize_net();
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(seg6_hmac_info_del);
> +
> +static void seg6_hmac_info_flush(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +       struct seg6_hmac_info *hinfo;
> +
> +       seg6_pernet_lock(net);
> +       while ((hinfo = list_first_or_null_rcu(&sdata->hmac_infos,
> +                                              struct seg6_hmac_info,
> +                                              list)) != NULL) {
> +               list_del_rcu(&hinfo->list);
> +               seg6_pernet_unlock(net);
> +               synchronize_net();
> +               kfree(hinfo);
> +               seg6_pernet_lock(net);
> +       }
> +
> +       seg6_pernet_unlock(net);
> +}
> +
> +int seg6_push_hmac(struct net *net, struct in6_addr *saddr,
> +                  struct ipv6_sr_hdr *srh)
> +{
> +       struct seg6_hmac_info *hinfo;
> +       int err = -ENOENT;
> +       struct sr6_tlv_hmac *tlv;
> +
> +       tlv = seg6_get_tlv(srh, SR6_TLV_HMAC);
> +       if (!tlv)
> +               return -EINVAL;
> +
> +       rcu_read_lock();
> +
> +       hinfo = seg6_hmac_info_lookup(net, be32_to_cpu(tlv->hmackeyid));
> +       if (!hinfo)
> +               goto out;
> +
> +       memset(tlv->hmac, 0, SEG6_HMAC_FIELD_LEN);
> +       err = seg6_hmac_compute(hinfo, srh, saddr, tlv->hmac);
> +
> +out:
> +       rcu_read_unlock();
> +       return err;
> +}
> +EXPORT_SYMBOL(seg6_push_hmac);
> +
> +static int seg6_hmac_init_ring(void)
> +{
> +       int i;
> +
> +       hmac_ring = alloc_percpu(char *);
> +
> +       if (!hmac_ring)
> +               return -ENOMEM;
> +
> +       for_each_possible_cpu(i) {
> +               char *ring = kzalloc(SEG6_HMAC_RING_SIZE, GFP_KERNEL);
> +
> +               if (!ring)
> +                       return -ENOMEM;
> +
> +               *per_cpu_ptr(hmac_ring, i) = ring;
> +       }
> +
> +       return 0;
> +}
> +
> +static int seg6_hmac_init_algo(void)
> +{
> +       int i, alg_count, cpu;
> +       struct seg6_hmac_algo *algo;
> +       struct crypto_shash *tfm;
> +       struct shash_desc *shash;
> +
> +       alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
> +
> +       for (i = 0; i < alg_count; i++) {
> +               int shsize;
> +               struct crypto_shash **p_tfm;
> +
> +               algo = &hmac_algos[i];
> +               algo->tfms = alloc_percpu(struct crypto_shash *);
> +               if (!algo->tfms)
> +                       return -ENOMEM;
> +
> +               for_each_possible_cpu(cpu) {
> +                       tfm = crypto_alloc_shash(algo->name, 0, GFP_KERNEL);
> +                       if (IS_ERR(tfm))
> +                               return PTR_ERR(tfm);
> +                       p_tfm = per_cpu_ptr(algo->tfms, cpu);
> +                       *p_tfm = tfm;
> +               }
> +
> +               p_tfm = this_cpu_ptr(algo->tfms);
> +               tfm = *p_tfm;
> +
> +               shsize = sizeof(*shash) + crypto_shash_descsize(tfm);
> +
> +               algo->shashs = alloc_percpu(struct shash_desc *);
> +               if (!algo->shashs)
> +                       return -ENOMEM;
> +
> +               for_each_possible_cpu(cpu) {
> +                       shash = kzalloc(shsize, GFP_KERNEL);
> +                       if (!shash)
> +                               return -ENOMEM;
> +                       *per_cpu_ptr(algo->shashs, cpu) = shash;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +int __init seg6_hmac_init(void)
> +{
> +       int ret;
> +
> +       ret = seg6_hmac_init_ring();
> +       if (ret < 0)
> +               goto out;
> +
> +       ret = seg6_hmac_init_algo();
> +
> +out:
> +       return ret;
> +}
> +
> +int __net_init seg6_hmac_net_init(struct net *net)
> +{
> +       struct seg6_pernet_data *sdata = seg6_pernet(net);
> +
> +       INIT_LIST_HEAD(&sdata->hmac_infos);
> +       return 0;
> +}
> +
> +void __exit seg6_hmac_exit(void)
> +{
> +       int i, alg_count, cpu;
> +       struct seg6_hmac_algo *algo = NULL;
> +
> +       for_each_possible_cpu(i) {
> +               char *ring = *per_cpu_ptr(hmac_ring, i);
> +
> +               kfree(ring);
> +       }
> +       free_percpu(hmac_ring);
> +
> +       alg_count = sizeof(hmac_algos) / sizeof(struct seg6_hmac_algo);
> +       for (i = 0; i < alg_count; i++) {
> +               algo = &hmac_algos[i];
> +               for_each_possible_cpu(cpu) {
> +                       struct crypto_shash *tfm;
> +                       struct shash_desc *shash;
> +
> +                       shash = *per_cpu_ptr(algo->shashs, cpu);
> +                       kfree(shash);
> +                       tfm = *per_cpu_ptr(algo->tfms, cpu);
> +                       crypto_free_shash(tfm);
> +               }
> +               free_percpu(algo->tfms);
> +               free_percpu(algo->shashs);
> +       }
> +}
> +
> +void __net_exit seg6_hmac_net_exit(struct net *net)
> +{
> +       seg6_hmac_info_flush(net);
> +}
> --
> 2.7.3
>

^ permalink raw reply

* [PATCH V2 RFC 1/2] ixgbe: ixgbe_atr() should access udp_hdr(skb) only for UDP packets
From: Sowmini Varadhan @ 2016-10-17 17:25 UTC (permalink / raw)
  To: sowmini.varadhan, alexander.h.duyck; +Cc: netdev, intel-wired-lan
In-Reply-To: <cover.1476724638.git.sowmini.varadhan@oracle.com>

Commit 9f12df906cd8 ("ixgbe: Store VXLAN port number in network order")
incorrectly checks for hdr.ipv4->protocol != IPPROTO_UDP
in ixgbe_atr(). This check should be for "==" instead.

Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index a244d9a..eceb47b 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7653,7 +7653,7 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
 	hdr.network = skb_network_header(skb);
 	if (skb->encapsulation &&
 	    first->protocol == htons(ETH_P_IP) &&
-	    hdr.ipv4->protocol != IPPROTO_UDP) {
+	    hdr.ipv4->protocol == IPPROTO_UDP) {
 		struct ixgbe_adapter *adapter = q_vector->adapter;
 
 		/* verify the port is recognized as VXLAN */
-- 
1.7.1

^ permalink raw reply related

* [PATCH V2 RFC 0/2] ixgbe: ixgbe_atr() bug fixes
From: Sowmini Varadhan @ 2016-10-17 17:25 UTC (permalink / raw)
  To: sowmini.varadhan, alexander.h.duyck; +Cc: netdev, intel-wired-lan

Two bug fixes:
- ixgbe_atr() should check for protocol == udp in the
  skb->encapsulation case (instead of !=)
- ixgbe_atr() should make sure the non-paged data has the
  needed network/transport header for computing l4_proto.

Sowmini Varadhan (2):
  ixgbe: ixgbe_atr() should access udp_hdr(skb) only for UDP packets
  ixgbe: ixgbe_atr() compute l4_proto only if non-paged data has
    network/transport headers

 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   20 +++++++++++++++++++-
 1 files changed, 19 insertions(+), 1 deletions(-)

^ permalink raw reply

* [PATCH V2 RFC 2/2] ixgbe: ixgbe_atr() compute l4_proto only if non-paged data has network/transport headers
From: Sowmini Varadhan @ 2016-10-17 17:25 UTC (permalink / raw)
  To: sowmini.varadhan, alexander.h.duyck; +Cc: netdev, intel-wired-lan
In-Reply-To: <cover.1476724638.git.sowmini.varadhan@oracle.com>

For some Tx paths (e.g., tpacket_snd()), ixgbe_atr may be
passed down an sk_buff that has the network and transport
header in the paged data, so it needs to make sure these
headers are available in the headlen bytes to calculate the
l4_proto.

This patch expect that network and transport headers are
already available in the non-paged header dat.  The assumption
is that the caller has set this up if l4_proto based Tx
steering is desired.

Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
---
 drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index eceb47b..2cc1dae 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -54,6 +54,7 @@
 #include <net/pkt_cls.h>
 #include <net/tc_act/tc_gact.h>
 #include <net/tc_act/tc_mirred.h>
+#include <net/vxlan.h>
 
 #include "ixgbe.h"
 #include "ixgbe_common.h"
@@ -7651,11 +7652,16 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
 	/* snag network header to get L4 type and address */
 	skb = first->skb;
 	hdr.network = skb_network_header(skb);
+	if (hdr.network <= skb->data || hdr.network >= skb_tail_pointer(skb))
+		return;
 	if (skb->encapsulation &&
 	    first->protocol == htons(ETH_P_IP) &&
 	    hdr.ipv4->protocol == IPPROTO_UDP) {
 		struct ixgbe_adapter *adapter = q_vector->adapter;
 
+		if (skb_tail_pointer(skb) < hdr.network + VXLAN_HEADROOM)
+			return;
+
 		/* verify the port is recognized as VXLAN */
 		if (adapter->vxlan_port &&
 		    udp_hdr(skb)->dest == adapter->vxlan_port)
@@ -7666,15 +7672,27 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
 			hdr.network = skb_inner_network_header(skb);
 	}
 
+	/* Make sure we have at least [minimum IPv4 header + TCP]
+	 * or [IPv6 header] bytes
+	 */
+	if (skb_tail_pointer(skb) < hdr.network + 40)
+		return;
+
 	/* Currently only IPv4/IPv6 with TCP is supported */
 	switch (hdr.ipv4->version) {
 	case IPVERSION:
 		/* access ihl as u8 to avoid unaligned access on ia64 */
 		hlen = (hdr.network[0] & 0x0F) << 2;
+		if (skb_tail_pointer(skb) < hdr.network + hlen +
+					    sizeof(struct tcphdr))
+			return;
 		l4_proto = hdr.ipv4->protocol;
 		break;
 	case 6:
 		hlen = hdr.network - skb->data;
+		if (skb_tail_pointer(skb) < hdr.network + hlen +
+					    sizeof(struct tcphdr))
+			return;
 		l4_proto = ipv6_find_hdr(skb, &hlen, IPPROTO_TCP, NULL, NULL);
 		hlen -= hdr.network - skb->data;
 		break;
-- 
1.7.1

^ permalink raw reply related

* Re: [PATCH v3 net-next 2/2] net: deprecate eth_change_mtu, remove usage
From: David Miller @ 2016-10-17 17:25 UTC (permalink / raw)
  To: kubakici; +Cc: jarod, linux-kernel, netdev
In-Reply-To: <20161017182049.4be802d1@jkicinski-Precision-T1700>

From: Jakub Kicinski <kubakici@wp.pl>
Date: Mon, 17 Oct 2016 18:20:49 +0100

> Hm.  I must be missing something really obvious.  I just booted
> net-next an hour ago and couldn't set MTU to anything larger than 1500
> on either nfp or igb.  As far as I can read the code it will set the
> max_mtu to 1500 in setup_ether() but none of the jumbo-capable drivers
> had been touched by Jarod so far...

Indeed.

Jarod, this doesn't work.

I guess the idea was that if the driver overrides ndo_change_mtu and
enforeced it's limits there, the driver would still work after your
changes.

But that isn't what is happening, look at the IGB example.

It uses ether_setup(), which sets those new defaults, but now when
the MTU is changed you enforce those default min/max before the
driver's ->ndo_change_mtu() has a change to step in front and make
the decision on it's own.

This means your changes pretty much did indeed break a lot of
drivers's ability to set larger than a 1500 byte MTU.

^ permalink raw reply

* Re: [PATCH 1/9] ipv6: implement dataplane support for rthdr type 4 (Segment Routing Header)
From: Tom Herbert @ 2016-10-17 17:31 UTC (permalink / raw)
  To: David Lebrun; +Cc: Linux Kernel Network Developers
In-Reply-To: <1476715350-18983-2-git-send-email-david.lebrun@uclouvain.be>

On Mon, Oct 17, 2016 at 7:42 AM, David Lebrun <david.lebrun@uclouvain.be> wrote:
> Implement minimal support for processing of SR-enabled packets
> as described in
> https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-02.
>
> This patch implements the following operations:
> - Intermediate segment endpoint: incrementation of active segment and rerouting.
> - Egress for SR-encapsulated packets: decapsulation of outer IPv6 header + SRH
>   and routing of inner packet.
> - Cleanup flag support for SR-inlined packets: removal of SRH if we are the
>   penultimate segment endpoint.
>
> A per-interface sysctl seg6_enabled is provided, to accept/deny SR-enabled
> packets. Default is deny.
>
> This patch does not provide support for HMAC-signed packets.
>
> Signed-off-by: David Lebrun <david.lebrun@uclouvain.be>
> ---
>  include/linux/ipv6.h      |   3 +
>  include/linux/seg6.h      |   6 ++
>  include/uapi/linux/ipv6.h |   2 +
>  include/uapi/linux/seg6.h |  46 +++++++++++++++
>  net/ipv6/Kconfig          |  13 +++++
>  net/ipv6/addrconf.c       |  18 ++++++
>  net/ipv6/exthdrs.c        | 140 ++++++++++++++++++++++++++++++++++++++++++++++
>  7 files changed, 228 insertions(+)
>  create mode 100644 include/linux/seg6.h
>  create mode 100644 include/uapi/linux/seg6.h
>
> diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
> index 7e9a789..75395ad 100644
> --- a/include/linux/ipv6.h
> +++ b/include/linux/ipv6.h
> @@ -64,6 +64,9 @@ struct ipv6_devconf {
>         } stable_secret;
>         __s32           use_oif_addrs_only;
>         __s32           keep_addr_on_down;
> +#ifdef CONFIG_IPV6_SEG6
> +       __s32           seg6_enabled;
> +#endif
>
>         struct ctl_table_header *sysctl_header;
>  };
> diff --git a/include/linux/seg6.h b/include/linux/seg6.h
> new file mode 100644
> index 0000000..7a66d2b
> --- /dev/null
> +++ b/include/linux/seg6.h
> @@ -0,0 +1,6 @@
> +#ifndef _LINUX_SEG6_H
> +#define _LINUX_SEG6_H
> +
> +#include <uapi/linux/seg6.h>
> +
> +#endif
> diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h
> index 8c27723..7ff1d65 100644
> --- a/include/uapi/linux/ipv6.h
> +++ b/include/uapi/linux/ipv6.h
> @@ -39,6 +39,7 @@ struct in6_ifreq {
>  #define IPV6_SRCRT_STRICT      0x01    /* Deprecated; will be removed */
>  #define IPV6_SRCRT_TYPE_0      0       /* Deprecated; will be removed */
>  #define IPV6_SRCRT_TYPE_2      2       /* IPv6 type 2 Routing Header   */
> +#define IPV6_SRCRT_TYPE_4      4       /* Segment Routing with IPv6 */
>
>  /*
>   *     routing header
> @@ -178,6 +179,7 @@ enum {
>         DEVCONF_DROP_UNSOLICITED_NA,
>         DEVCONF_KEEP_ADDR_ON_DOWN,
>         DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
> +       DEVCONF_SEG6_ENABLED,
>         DEVCONF_MAX
>  };
>
> diff --git a/include/uapi/linux/seg6.h b/include/uapi/linux/seg6.h
> new file mode 100644
> index 0000000..9f9e157
> --- /dev/null
> +++ b/include/uapi/linux/seg6.h
> @@ -0,0 +1,46 @@
> +/*
> + *  SR-IPv6 implementation
> + *
> + *  Author:
> + *  David Lebrun <david.lebrun@uclouvain.be>
> + *
> + *
> + *  This program is free software; you can redistribute it and/or
> + *      modify it under the terms of the GNU General Public License
> + *      as published by the Free Software Foundation; either version
> + *      2 of the License, or (at your option) any later version.
> + */
> +
> +#ifndef _UAPI_LINUX_SEG6_H
> +#define _UAPI_LINUX_SEG6_H
> +
> +/*
> + * SRH
> + */
> +struct ipv6_sr_hdr {
> +       __u8    nexthdr;
> +       __u8    hdrlen;
> +       __u8    type;
> +       __u8    segments_left;
> +       __u8    first_segment;
> +       __be16  flags;
> +       __u8    reserved;
> +
> +       struct in6_addr segments[0];
> +} __attribute__((packed));
> +
> +#define SR6_FLAG_CLEANUP       (1 << 15)
> +#define SR6_FLAG_PROTECTED     (1 << 14)
> +#define SR6_FLAG_OAM           (1 << 13)
> +#define SR6_FLAG_ALERT         (1 << 12)
> +#define SR6_FLAG_HMAC          (1 << 11)
> +
> +#define SR6_TLV_INGRESS                1
> +#define SR6_TLV_EGRESS         2
> +#define SR6_TLV_OPAQUE         3
> +#define SR6_TLV_PADDING                4
> +#define SR6_TLV_HMAC           5
> +
> +#define sr_get_flags(srh) (be16_to_cpu((srh)->flags))
> +
> +#endif
> diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
> index 2343e4f..691c318 100644
> --- a/net/ipv6/Kconfig
> +++ b/net/ipv6/Kconfig
> @@ -289,4 +289,17 @@ config IPV6_PIMSM_V2
>           Support for IPv6 PIM multicast routing protocol PIM-SMv2.
>           If unsure, say N.
>
> +config IPV6_SEG6
> +       bool "IPv6: Segment Routing support"
> +       depends on IPV6
> +       select CRYPTO_HMAC
> +       select CRYPTO_SHA1
> +       select CRYPTO_SHA256
> +       ---help---
> +         Experimental support for IPv6 Segment Routing dataplane as defined
> +         in IETF draft-ietf-6man-segment-routing-header-02. This option
> +         enables the processing of SR-enabled packets allowing the kernel
> +         to act as a segment endpoint (intermediate or egress). It also
> +         enables an API for the kernel to act as an ingress SR router.
> +

I suggest that you eliminate IPV6_SEG6 as config, always include SR
with IPv6. But then maybe SR security should be a CONFIG variable
since this would pull in a lot of crypto. I imagine in a closed
environment (e.g. within a datacenter) security might not normally be
enabled.

>  endif # IPV6
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index d8983e1..42c0ffb 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -239,6 +239,9 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
>         .use_oif_addrs_only     = 0,
>         .ignore_routes_with_linkdown = 0,
>         .keep_addr_on_down      = 0,
> +#ifdef CONFIG_IPV6_SEG6
> +       .seg6_enabled           = 0,
> +#endif
>  };
>
>  static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
> @@ -285,6 +288,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
>         .use_oif_addrs_only     = 0,
>         .ignore_routes_with_linkdown = 0,
>         .keep_addr_on_down      = 0,
> +#ifdef CONFIG_IPV6_SEG6
> +       .seg6_enabled           = 0,
> +#endif
>  };
>
>  /* Check if a valid qdisc is available */
> @@ -4965,6 +4971,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
>         array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast;
>         array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na;
>         array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down;
> +#ifdef CONFIG_IPV6_SEG6
> +       array[DEVCONF_SEG6_ENABLED] = cnf->seg6_enabled;
> +#endif
>  }
>
>  static inline size_t inet6_ifla6_size(void)
> @@ -6056,6 +6065,15 @@ static const struct ctl_table addrconf_sysctl[] = {
>                 .proc_handler   = proc_dointvec,
>
>         },
> +#ifdef CONFIG_IPV6_SEG6
> +       {
> +               .procname       = "seg6_enabled",
> +               .data           = &ipv6_devconf.seg6_enabled,
> +               .maxlen         = sizeof(int),
> +               .mode           = 0644,
> +               .proc_handler   = proc_dointvec,
> +       },
> +#endif
>         {
>                 /* sentinel */
>         }
> diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
> index 139ceb6..b31f811 100644
> --- a/net/ipv6/exthdrs.c
> +++ b/net/ipv6/exthdrs.c
> @@ -47,6 +47,9 @@
>  #if IS_ENABLED(CONFIG_IPV6_MIP6)
>  #include <net/xfrm.h>
>  #endif
> +#ifdef CONFIG_IPV6_SEG6
> +#include <linux/seg6.h>
> +#endif
>
>  #include <linux/uaccess.h>
>
> @@ -286,6 +289,137 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
>         return -1;
>  }
>
> +#ifdef CONFIG_IPV6_SEG6
> +static int ipv6_srh_rcv(struct sk_buff *skb)
> +{
> +       struct in6_addr *addr = NULL, *last_addr = NULL, *active_addr = NULL;
> +       struct inet6_skb_parm *opt = IP6CB(skb);
> +       struct net *net = dev_net(skb->dev);
> +       struct ipv6_sr_hdr *hdr;
> +       struct inet6_dev *idev;
> +       int cleanup = 0;
> +       int accept_seg6;
> +
> +       hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +       idev = __in6_dev_get(skb->dev);
> +
> +       accept_seg6 = net->ipv6.devconf_all->seg6_enabled;
> +       if (accept_seg6 > idev->cnf.seg6_enabled)
> +               accept_seg6 = idev->cnf.seg6_enabled;
> +
> +       if (!accept_seg6) {
> +               kfree_skb(skb);
> +               return -1;
> +       }
> +
> +looped_back:
> +       last_addr = hdr->segments;
> +
> +       if (hdr->segments_left > 0) {
> +               if (hdr->nexthdr != NEXTHDR_IPV6 && hdr->segments_left == 1 &&
> +                   sr_get_flags(hdr) & SR6_FLAG_CLEANUP)
> +                       cleanup = 1;
> +       } else {
> +               if (hdr->nexthdr == NEXTHDR_IPV6) {
> +                       int offset = (hdr->hdrlen + 1) << 3;
> +
> +                       if (!pskb_pull(skb, offset)) {
> +                               kfree_skb(skb);
> +                               return -1;
> +                       }
> +                       skb_postpull_rcsum(skb, skb_transport_header(skb),
> +                                          offset);
> +
> +                       skb_reset_network_header(skb);
> +                       skb_reset_transport_header(skb);
> +                       skb->encapsulation = 0;
> +
> +                       __skb_tunnel_rx(skb, skb->dev, net);
> +
> +                       netif_rx(skb);
> +                       return -1;
> +               }
> +
> +               opt->srcrt = skb_network_header_len(skb);
> +               opt->lastopt = opt->srcrt;
> +               skb->transport_header += (hdr->hdrlen + 1) << 3;
> +               opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb);
> +
> +               return 1;
> +       }
> +
> +       if (skb_cloned(skb)) {
> +               if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
> +                       __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
> +                                       IPSTATS_MIB_OUTDISCARDS);
> +                       kfree_skb(skb);
> +                       return -1;
> +               }
> +       }
> +
> +       if (skb->ip_summed == CHECKSUM_COMPLETE)
> +               skb->ip_summed = CHECKSUM_NONE;
> +
> +       hdr = (struct ipv6_sr_hdr *)skb_transport_header(skb);
> +
> +       active_addr = hdr->segments + hdr->segments_left;
> +       hdr->segments_left--;
> +       addr = hdr->segments + hdr->segments_left;
> +
> +       ipv6_hdr(skb)->daddr = *addr;
> +
> +       skb_push(skb, sizeof(struct ipv6hdr));
> +
> +       if (cleanup) {
> +               int srhlen = (hdr->hdrlen + 1) << 3;
> +               int nh = hdr->nexthdr;
> +
> +               memmove(skb_network_header(skb) + srhlen,
> +                       skb_network_header(skb),
> +                       (unsigned char *)hdr - skb_network_header(skb));
> +               skb_pull(skb, srhlen);
> +               skb->network_header += srhlen;
> +               ipv6_hdr(skb)->nexthdr = nh;
> +               ipv6_hdr(skb)->payload_len = htons(skb->len -
> +                                                  sizeof(struct ipv6hdr));
> +       }
> +
> +       skb_dst_drop(skb);
> +
> +       ip6_route_input(skb);
> +
> +       if (skb_dst(skb)->error) {
> +               dst_input(skb);
> +               return -1;
> +       }
> +
> +       if (skb_dst(skb)->dev->flags & IFF_LOOPBACK) {
> +               if (ipv6_hdr(skb)->hop_limit <= 1) {
> +                       __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
> +                                       IPSTATS_MIB_INHDRERRORS);
> +                       icmpv6_send(skb, ICMPV6_TIME_EXCEED,
> +                                   ICMPV6_EXC_HOPLIMIT, 0);
> +                       kfree_skb(skb);
> +                       return -1;
> +               }
> +               ipv6_hdr(skb)->hop_limit--;
> +
> +               /* be sure that srh is still present before reinjecting */
> +               if (!cleanup) {
> +                       skb_pull(skb, sizeof(struct ipv6hdr));
> +                       goto looped_back;
> +               }
> +               skb_set_transport_header(skb, sizeof(struct ipv6hdr));
> +               IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
> +       }
> +
> +       dst_input(skb);
> +
> +       return -1;
> +}
> +#endif
> +
>  /********************************
>    Routing header.
>   ********************************/
> @@ -326,6 +460,12 @@ static int ipv6_rthdr_rcv(struct sk_buff *skb)
>                 return -1;
>         }
>
> +#ifdef CONFIG_IPV6_SEG6
> +       /* segment routing */
> +       if (hdr->type == IPV6_SRCRT_TYPE_4)
> +               return ipv6_srh_rcv(skb);
> +#endif
> +
>  looped_back:
>         if (hdr->segments_left == 0) {
>                 switch (hdr->type) {
> --
> 2.7.3
>

^ permalink raw reply

* RE: [ANNOUNCE] bridge-utils 1.6 release
From: Rosen, Rami @ 2016-10-17 18:03 UTC (permalink / raw)
  To: Alexander Alemayhu, Stephen Hemminger
  Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20161017165902.GA18441@gmail.com>

Hi, Alexander, 

>This link seems to be broken.

Seems that it should be:
https://www.kernel.org/pub/linux/utils/net/bridge-utils/bridge-utils-1.6.tar.gz
Instead of:
>   http://www.kernel.org/pub/linux/utils/net/bridge-utils/bridge-utils.1.6.tar.gz

Regards,
Rami Rosen
Intel Corporation

^ permalink raw reply

* Re: [PATCH] mac80211_hwsim: suggest nl80211 instead of wext driver in documentation
From: Linus Lüssing @ 2016-10-17 18:14 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-wireless, Jouni Malinen, David S . Miller, Jonathan Corbet,
	netdev, linux-kernel, linux-doc
In-Reply-To: <1476697144.19992.16.camel@sipsolutions.net>

On Mon, Oct 17, 2016 at 11:39:04AM +0200, Johannes Berg wrote:
> On Mon, 2016-10-17 at 00:39 +0200, Linus Lüssing wrote:
> > For mac80211_hwsim interfaces, suggest to use wpa_supplicant with the
> > more modern, netlink based driver instead of wext.
> 
> Makes sense, applied.
> 
> > Actually, I wasn't even able to make a connection with the
> > configuration
> > files and information provided in
> > Documentation/networking/mac80211_hwsim/{README,hostapd.conf/wpa_supp
> > licant.conf}
> > 
> This less so, we even have a few test cases we run regularly, but I
> don't know. Maybe there's something special in those configuration
> files that we don't test for otherwise.

I investigated a little further and the problem is probably that
I'm running a minimal Linux kernel which was compiled without
CONFIG_CFG80211_WEXT :-).

Anyways, thanks for applying the patch!

Regards, Linus

^ permalink raw reply

* Re: [Intel-wired-lan] [PATCH V2 RFC 2/2] ixgbe: ixgbe_atr() compute l4_proto only if non-paged data has network/transport headers
From: Alexander Duyck @ 2016-10-17 18:15 UTC (permalink / raw)
  To: Sowmini Varadhan; +Cc: Duyck, Alexander H, Netdev, intel-wired-lan
In-Reply-To: <ff985fc71358a90f7a97ca176abb96845852269e.1476724638.git.sowmini.varadhan@oracle.com>

On Mon, Oct 17, 2016 at 10:25 AM, Sowmini Varadhan
<sowmini.varadhan@oracle.com> wrote:
> For some Tx paths (e.g., tpacket_snd()), ixgbe_atr may be
> passed down an sk_buff that has the network and transport
> header in the paged data, so it needs to make sure these
> headers are available in the headlen bytes to calculate the
> l4_proto.
>
> This patch expect that network and transport headers are
> already available in the non-paged header dat.  The assumption
> is that the caller has set this up if l4_proto based Tx
> steering is desired.
>
> Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com>
> ---
>  drivers/net/ethernet/intel/ixgbe/ixgbe_main.c |   18 ++++++++++++++++++
>  1 files changed, 18 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> index eceb47b..2cc1dae 100644
> --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
> @@ -54,6 +54,7 @@
>  #include <net/pkt_cls.h>
>  #include <net/tc_act/tc_gact.h>
>  #include <net/tc_act/tc_mirred.h>
> +#include <net/vxlan.h>
>
>  #include "ixgbe.h"
>  #include "ixgbe_common.h"
> @@ -7651,11 +7652,16 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
>         /* snag network header to get L4 type and address */
>         skb = first->skb;
>         hdr.network = skb_network_header(skb);
> +       if (hdr.network <= skb->data || hdr.network >= skb_tail_pointer(skb))
> +               return;

I would say you probably only need the first check here for skb->data
and could probably skip the second part.  You will be testing for
skb_tail_pointer in all the other tests you added so this check is
redundant anyway.

Also you might want to go through and wrap these with unlikely() since
most of these are exception cases.

>         if (skb->encapsulation &&
>             first->protocol == htons(ETH_P_IP) &&
>             hdr.ipv4->protocol == IPPROTO_UDP) {
>                 struct ixgbe_adapter *adapter = q_vector->adapter;
>
> +               if (skb_tail_pointer(skb) < hdr.network + VXLAN_HEADROOM)
> +                       return;
> +
>                 /* verify the port is recognized as VXLAN */
>                 if (adapter->vxlan_port &&
>                     udp_hdr(skb)->dest == adapter->vxlan_port)
> @@ -7666,15 +7672,27 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
>                         hdr.network = skb_inner_network_header(skb);
>         }
>
> +       /* Make sure we have at least [minimum IPv4 header + TCP]
> +        * or [IPv6 header] bytes
> +        */
> +       if (skb_tail_pointer(skb) < hdr.network + 40)
> +               return;
> +
>         /* Currently only IPv4/IPv6 with TCP is supported */
>         switch (hdr.ipv4->version) {
>         case IPVERSION:
>                 /* access ihl as u8 to avoid unaligned access on ia64 */
>                 hlen = (hdr.network[0] & 0x0F) << 2;
> +               if (skb_tail_pointer(skb) < hdr.network + hlen +
> +                                           sizeof(struct tcphdr))
> +                       return;
>                 l4_proto = hdr.ipv4->protocol;
>                 break;
>         case 6:
>                 hlen = hdr.network - skb->data;
> +               if (skb_tail_pointer(skb) < hdr.network + hlen +
> +                                           sizeof(struct tcphdr))
> +                       return;
>                 l4_proto = ipv6_find_hdr(skb, &hlen, IPPROTO_TCP, NULL, NULL);
>                 hlen -= hdr.network - skb->data;
>                 break;

I believe one more check is needed after this block to verify the TCP
header fields are present.

So you probably need to add a check for "skb_tail_pointer(skb) <
(hdr.network + hlen + 20)".

Thanks.

- Alex

^ permalink raw reply

* Re: Kernel 4.6.7-rt13: Intel Ethernet driver igb causes huge latencies in cyclictest
From: Julia Cartwright @ 2016-10-17 18:32 UTC (permalink / raw)
  To: Alexander Duyck
  Cc: Koehrer Mathias (ETAS/ESW5), Bjorn Helgaas,
	linux-rt-users@vger.kernel.org, Sebastian Andrzej Siewior,
	netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,
	Matthew Garrett, Bjorn Helgaas, Greg, linux-pci
In-Reply-To: <CAKgT0Uf-F9V+AeP0+92Gf=40Tye-687_GFbhp4Sex=Hat+Ha+w@mail.gmail.com>

+linux-pci

On Mon, Oct 17, 2016 at 08:39:40AM -0700, Alexander Duyck wrote:
> On Mon, Oct 17, 2016 at 8:00 AM, Koehrer Mathias (ETAS/ESW5)
> <mathias.koehrer@etas.com> wrote:
> > Hi Julia!
> >> > > Have you tested on a vanilla (non-RT) kernel?  I doubt there is
> >> > > anything RT specific about what you are seeing, but it might be nice
> >> > > to get confirmation.  Also, bisection would probably be easier if you confirm on a
> >> vanilla kernel.
> >> > >
> >> > > I find it unlikely that it's a kernel config option that changed
> >> > > which regressed you, but instead was a code change to a driver.
> >> > > Which driver is now the question, and the surface area is still big
> >> > > (processor mapping attributes for this region, PCI root complex configuration,
> >> PCI brige configuration, igb driver itself, etc.).
> >> > >
> >> > > Big enough that I'd recommend a bisection.  It looks like a
> >> > > bisection between 3.18 and 4.8 would take you about 18 tries to narrow down,
> >> assuming all goes well.
> >> > >
> >> >
> >> > I have now repeated my tests using the vanilla kernel.
> >> > There I got the very same issue.
> >> > Using kernel 4.0 is fine, however starting with kernel 4.1, the issue appears.
> >>
> >> Great, thanks for confirming!  That helps narrow things down quite a bit.
> >>
> >> > Here is my exact (reproducible) test description:
> >> > I applied the following patch to the kernel to get the igb trace.
> >> > This patch instruments the igb_rd32() function to measure the call to
> >> > readl() which is used to access registers of the igb NIC.
> >>
> >> I took your test setup and ran it between 4.0 and 4.1 on the hardware on my desk,
> >> which is an Atom-based board with dual I210s, however I didn't see much
> >> difference.
> >>
> >> However, it's a fairly simple board, with a much simpler PCI topology than your
> >> workstation.  I'll see if I can find some other hardware to test on.
> >>
> >> [..]
> >> > This means, that I think that some other stuff in kernel 4.1 has
> >> > changed, which has impact on the igb accesses.
> >> >
> >> > Any idea what component could cause this kind of issue?
> >>
> >> Can you continue your bisection using 'git bisect'?  You've already narrowed it down
> >> between 4.0 and 4.1, so you're well on your way.
> >>
> >
> > OK - done.
> > And finally I was successful!
> > The following git commit is the one that is causing the trouble!
> > (The full commit is in the attachment).
> > +++++++++++++++++++++ BEGIN +++++++++++++++++++++++++++
> > commit 387d37577fdd05e9472c20885464c2a53b3c945f
> > Author: Matthew Garrett <mjg59@coreos.com>
> > Date:   Tue Apr 7 11:07:00 2015 -0700
> >
> >     PCI: Don't clear ASPM bits when the FADT declares it's unsupported
> >
> >     Communications with a hardware vendor confirm that the expected behaviour
> >     on systems that set the FADT ASPM disable bit but which still grant full
> >     PCIe control is for the OS to leave any BIOS configuration intact and
> >     refuse to touch the ASPM bits.  This mimics the behaviour of Windows.
> >
> >     Signed-off-by: Matthew Garrett <mjg59@coreos.com>
> >     Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
> > +++++++++++++++++++++ HEADER +++++++++++++++++++++++++++
> >
> > The only files that are modified by this commit are
> > drivers/acpi/pci_root.c
> > drivers/pci/pcie/aspm.c
> > include/linux/pci-aspm.h
> >
> > This is all generic PCIe stuff - however I do not really understand what
> > the changes of the commit are...
> >
> > In my setup I am using a dual port igb Ethernet adapter.
> > This has an onboard PCIe switch and it might be that the configuration of this
> > PCIe switch on the Intel board is causing the trouble.
> >
> > Please see also the output of "lspci -v" in the attachment.
> > The relevant PCI address of the NIC is 04:00.0 / 04:00.1
> >
> > Any feedback on this is welcome!
> >
> > Thanks
> >
> > Mathias
>
> Hi Mathias,
>
> If you could set the output of lspci -vvv it might be more useful as
> most of the configuration data isn't present in the lspci dump you had
> attached.  Specifically if you could do this for the working case and
> the non-working case we could verify if this issue is actually due to
> the ASPM configuration on the device.
>
> Also one thing you might try is booting your kernel with the kernel
> parameter "pcie_aspm=off".  It sounds like the extra latency is likely
> due to your platform enabling ASPM on the device and this in turn will
> add latency if the PCIe link is disabled when you attempt to perform a
> read as it takes some time to bring the PCIe link up when in L1 state.

So if we assume it's this commit causing the regression, then it's safe
to assume that this system's BIOS is claiming to not support ASPM in the
FADT, but the BIOS is leaving ASPM configured in some way on the
relevant devices.

Also, unfortunately, taking a look at the code which handles
"pcie_aspm=off", it won't be sufficient to disable ASPM on these
this system, as disabling these states is skipped when the FADT doesn't
advertise ASPM support.

What would be needed is an option like "force", but which force
_disables_ ASPM.  "force-disable", maybe.

   Julia

^ permalink raw reply

* Re: Kernel 4.6.7-rt13: Intel Ethernet driver igb causes huge latencies in cyclictest
From: Julia Cartwright @ 2016-10-17 18:36 UTC (permalink / raw)
  To: Richard Cochran
  Cc: Koehrer Mathias (ETAS/ESW5), Williams, Mitch A,
	Kirsher, Jeffrey T, linux-rt-users@vger.kernel.org,
	Sebastian Andrzej Siewior, netdev@vger.kernel.org,
	intel-wired-lan@lists.osuosl.org, Greg
In-Reply-To: <20161014220633.GA1811@netboy>

On Sat, Oct 15, 2016 at 12:06:33AM +0200, Richard Cochran wrote:
> On Fri, Oct 14, 2016 at 08:58:22AM +0000, Koehrer Mathias (ETAS/ESW5) wrote:
> > @@ -753,7 +756,9 @@ u32 igb_rd32(struct e1000_hw *hw, u32 re
> >  	if (E1000_REMOVED(hw_addr))
> >  		return ~value;
> >  
> > +        trace_igb(801);
> >  	value = readl(&hw_addr[reg]);
> > +        trace_igb(802);
> 
> Nothing prevents this code from being preempted between the two trace
> points, and so you can't be sure whether the time delta in the trace
> is caused by the PCIe read stalling or not.

While that is certainly the case, and would explain the most egregious
of measured latency spikes, it doesn't invalidate the test if you
consider the valuable data point(s) to be the minimum and/or median
latencies.

   Julia

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox