]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/core/dev.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / core / dev.c
index 416137c64bf809328898f42fff41cd27ccf036d6..88927f1a3e4f838bea54d1dc8cf6ee06f79477c8 100644 (file)
 #include <net/dst.h>
 #include <net/dst_metadata.h>
 #include <net/pkt_sched.h>
+#include <net/pkt_cls.h>
 #include <net/checksum.h>
 #include <net/xfrm.h>
 #include <linux/highmem.h>
 #include <linux/hrtimer.h>
 #include <linux/netfilter_ingress.h>
 #include <linux/crash_dump.h>
+#include <linux/sctp.h>
 
 #include "net-sysfs.h"
 
@@ -161,6 +163,7 @@ static int netif_rx_internal(struct sk_buff *skb);
 static int call_netdevice_notifiers_info(unsigned long val,
                                         struct net_device *dev,
                                         struct netdev_notifier_info *info);
+static struct napi_struct *napi_by_id(unsigned int napi_id);
 
 /*
  * The @dev_base_head list is protected by @dev_base_lock and the rtnl
@@ -864,6 +867,31 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
 }
 EXPORT_SYMBOL(dev_get_by_index);
 
+/**
+ *     dev_get_by_napi_id - find a device by napi_id
+ *     @napi_id: ID of the NAPI struct
+ *
+ *     Search for an interface by NAPI ID. Returns %NULL if the device
+ *     is not found or a pointer to the device. The device has not had
+ *     its reference counter increased so the caller must be careful
+ *     about locking. The caller must hold RCU lock.
+ */
+
+struct net_device *dev_get_by_napi_id(unsigned int napi_id)
+{
+       struct napi_struct *napi;
+
+       WARN_ON_ONCE(!rcu_read_lock_held());
+
+       if (napi_id < MIN_NAPI_ID)
+               return NULL;
+
+       napi = napi_by_id(napi_id);
+
+       return napi ? napi->dev : NULL;
+}
+EXPORT_SYMBOL(dev_get_by_napi_id);
+
 /**
  *     netdev_get_name - get a netdevice name, knowing its ifindex.
  *     @net: network namespace
@@ -2612,6 +2640,47 @@ out:
 }
 EXPORT_SYMBOL(skb_checksum_help);
 
+int skb_crc32c_csum_help(struct sk_buff *skb)
+{
+       __le32 crc32c_csum;
+       int ret = 0, offset, start;
+
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               goto out;
+
+       if (unlikely(skb_is_gso(skb)))
+               goto out;
+
+       /* Before computing a checksum, we should make sure no frag could
+        * be modified by an external entity : checksum could be wrong.
+        */
+       if (unlikely(skb_has_shared_frag(skb))) {
+               ret = __skb_linearize(skb);
+               if (ret)
+                       goto out;
+       }
+       start = skb_checksum_start_offset(skb);
+       offset = start + offsetof(struct sctphdr, checksum);
+       if (WARN_ON_ONCE(offset >= skb_headlen(skb))) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (skb_cloned(skb) &&
+           !skb_clone_writable(skb, offset + sizeof(__le32))) {
+               ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+               if (ret)
+                       goto out;
+       }
+       crc32c_csum = cpu_to_le32(~__skb_checksum(skb, start,
+                                                 skb->len - start, ~(__u32)0,
+                                                 crc32c_csum_stub));
+       *(__le32 *)(skb->data + offset) = crc32c_csum;
+       skb->ip_summed = CHECKSUM_NONE;
+       skb->csum_not_inet = 0;
+out:
+       return ret;
+}
+
 __be16 skb_network_protocol(struct sk_buff *skb, int *depth)
 {
        __be16 type = skb->protocol;
@@ -2954,6 +3023,17 @@ static struct sk_buff *validate_xmit_vlan(struct sk_buff *skb,
        return skb;
 }
 
+int skb_csum_hwoffload_help(struct sk_buff *skb,
+                           const netdev_features_t features)
+{
+       if (unlikely(skb->csum_not_inet))
+               return !!(features & NETIF_F_SCTP_CRC) ? 0 :
+                       skb_crc32c_csum_help(skb);
+
+       return !!(features & NETIF_F_CSUM_MASK) ? 0 : skb_checksum_help(skb);
+}
+EXPORT_SYMBOL(skb_csum_hwoffload_help);
+
 static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev)
 {
        netdev_features_t features;
@@ -2992,8 +3072,7 @@ static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device
                        else
                                skb_set_transport_header(skb,
                                                         skb_checksum_start_offset(skb));
-                       if (!(features & NETIF_F_CSUM_MASK) &&
-                           skb_checksum_help(skb))
+                       if (skb_csum_hwoffload_help(skb, features))
                                goto out_kfree_skb;
                }
        }
@@ -3179,7 +3258,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
        /* qdisc_skb_cb(skb)->pkt_len was already set by the caller. */
        qdisc_bstats_cpu_update(cl->q, skb);
 
-       switch (tc_classify(skb, cl, &cl_res, false)) {
+       switch (tcf_classify(skb, cl, &cl_res, false)) {
        case TC_ACT_OK:
        case TC_ACT_RECLASSIFY:
                skb->tc_index = TC_H_MIN(cl_res.classid);
@@ -3191,6 +3270,7 @@ sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev)
                return NULL;
        case TC_ACT_STOLEN:
        case TC_ACT_QUEUED:
+       case TC_ACT_TRAP:
                *ret = NET_XMIT_SUCCESS;
                consume_skb(skb);
                return NULL;
@@ -3949,7 +4029,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
        skb->tc_at_ingress = 1;
        qdisc_bstats_cpu_update(cl->q, skb);
 
-       switch (tc_classify(skb, cl, &cl_res, false)) {
+       switch (tcf_classify(skb, cl, &cl_res, false)) {
        case TC_ACT_OK:
        case TC_ACT_RECLASSIFY:
                skb->tc_index = TC_H_MIN(cl_res.classid);
@@ -3960,6 +4040,7 @@ sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret,
                return NULL;
        case TC_ACT_STOLEN:
        case TC_ACT_QUEUED:
+       case TC_ACT_TRAP:
                consume_skb(skb);
                return NULL;
        case TC_ACT_REDIRECT:
@@ -4261,13 +4342,12 @@ static struct static_key generic_xdp_needed __read_mostly;
 
 static int generic_xdp_install(struct net_device *dev, struct netdev_xdp *xdp)
 {
+       struct bpf_prog *old = rtnl_dereference(dev->xdp_prog);
        struct bpf_prog *new = xdp->prog;
        int ret = 0;
 
        switch (xdp->command) {
-       case XDP_SETUP_PROG: {
-               struct bpf_prog *old = rtnl_dereference(dev->xdp_prog);
-
+       case XDP_SETUP_PROG:
                rcu_assign_pointer(dev->xdp_prog, new);
                if (old)
                        bpf_prog_put(old);
@@ -4279,10 +4359,10 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_xdp *xdp)
                        dev_disable_lro(dev);
                }
                break;
-       }
 
        case XDP_QUERY_PROG:
-               xdp->prog_attached = !!rcu_access_pointer(dev->xdp_prog);
+               xdp->prog_attached = !!old;
+               xdp->prog_id = old ? old->aux->id : 0;
                break;
 
        default:
@@ -4637,9 +4717,6 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
        if (netif_elide_gro(skb->dev))
                goto normal;
 
-       if (skb->csum_bad)
-               goto normal;
-
        gro_list_prepare(napi, skb);
 
        rcu_read_lock();
@@ -6867,7 +6944,7 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
 }
 EXPORT_SYMBOL(dev_change_proto_down);
 
-bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op)
+u8 __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op, u32 *prog_id)
 {
        struct netdev_xdp xdp;
 
@@ -6876,18 +6953,25 @@ bool __dev_xdp_attached(struct net_device *dev, xdp_op_t xdp_op)
 
        /* Query must always succeed. */
        WARN_ON(xdp_op(dev, &xdp) < 0);
+       if (prog_id)
+               *prog_id = xdp.prog_id;
+
        return xdp.prog_attached;
 }
 
 static int dev_xdp_install(struct net_device *dev, xdp_op_t xdp_op,
-                          struct netlink_ext_ack *extack,
+                          struct netlink_ext_ack *extack, u32 flags,
                           struct bpf_prog *prog)
 {
        struct netdev_xdp xdp;
 
        memset(&xdp, 0, sizeof(xdp));
-       xdp.command = XDP_SETUP_PROG;
+       if (flags & XDP_FLAGS_HW_MODE)
+               xdp.command = XDP_SETUP_PROG_HW;
+       else
+               xdp.command = XDP_SETUP_PROG;
        xdp.extack = extack;
+       xdp.flags = flags;
        xdp.prog = prog;
 
        return xdp_op(dev, &xdp);
@@ -6913,7 +6997,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
        ASSERT_RTNL();
 
        xdp_op = xdp_chk = ops->ndo_xdp;
-       if (!xdp_op && (flags & XDP_FLAGS_DRV_MODE))
+       if (!xdp_op && (flags & (XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE)))
                return -EOPNOTSUPP;
        if (!xdp_op || (flags & XDP_FLAGS_SKB_MODE))
                xdp_op = generic_xdp_install;
@@ -6921,10 +7005,10 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
                xdp_chk = generic_xdp_install;
 
        if (fd >= 0) {
-               if (xdp_chk && __dev_xdp_attached(dev, xdp_chk))
+               if (xdp_chk && __dev_xdp_attached(dev, xdp_chk, NULL))
                        return -EEXIST;
                if ((flags & XDP_FLAGS_UPDATE_IF_NOEXIST) &&
-                   __dev_xdp_attached(dev, xdp_op))
+                   __dev_xdp_attached(dev, xdp_op, NULL))
                        return -EBUSY;
 
                prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP);
@@ -6932,7 +7016,7 @@ int dev_change_xdp_fd(struct net_device *dev, struct netlink_ext_ack *extack,
                        return PTR_ERR(prog);
        }
 
-       err = dev_xdp_install(dev, xdp_op, extack, prog);
+       err = dev_xdp_install(dev, xdp_op, extack, flags, prog);
        if (err < 0 && prog)
                bpf_prog_put(prog);
 
@@ -7023,7 +7107,7 @@ static void rollback_registered_many(struct list_head *head)
 
                if (!dev->rtnl_link_ops ||
                    dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
-                       skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U,
+                       skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, 0,
                                                     GFP_KERNEL);
 
                /*
@@ -8608,7 +8692,6 @@ static int __init net_dev_init(void)
        rc = cpuhp_setup_state_nocalls(CPUHP_NET_DEV_DEAD, "net/dev:dead",
                                       NULL, dev_cpu_dead);
        WARN_ON(rc < 0);
-       dst_subsys_init();
        rc = 0;
 out:
        return rc;