These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / net / netfilter / nfnetlink_log.c
index 4ef1fae..740cce4 100644 (file)
@@ -27,6 +27,7 @@
 #include <net/netlink.h>
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_log.h>
+#include <linux/netfilter/nf_conntrack_common.h>
 #include <linux/spinlock.h>
 #include <linux/sysctl.h>
 #include <linux/proc_fs.h>
@@ -401,7 +402,9 @@ __build_packet_message(struct nfnl_log_net *log,
                        unsigned int hooknum,
                        const struct net_device *indev,
                        const struct net_device *outdev,
-                       const char *prefix, unsigned int plen)
+                       const char *prefix, unsigned int plen,
+                       const struct nfnl_ct_hook *nfnl_ct,
+                       struct nf_conn *ct, enum ip_conntrack_info ctinfo)
 {
        struct nfulnl_msg_packet_hdr pmsg;
        struct nlmsghdr *nlh;
@@ -538,9 +541,9 @@ __build_packet_message(struct nfnl_log_net *log,
 
        if (skb->tstamp.tv64) {
                struct nfulnl_msg_packet_timestamp ts;
-               struct timeval tv = ktime_to_timeval(skb->tstamp);
-               ts.sec = cpu_to_be64(tv.tv_sec);
-               ts.usec = cpu_to_be64(tv.tv_usec);
+               struct timespec64 kts = ktime_to_timespec64(skb->tstamp);
+               ts.sec = cpu_to_be64(kts.tv_sec);
+               ts.usec = cpu_to_be64(kts.tv_nsec / NSEC_PER_USEC);
 
                if (nla_put(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts))
                        goto nla_put_failure;
@@ -575,6 +578,10 @@ __build_packet_message(struct nfnl_log_net *log,
                         htonl(atomic_inc_return(&log->global_seq))))
                goto nla_put_failure;
 
+       if (ct && nfnl_ct->build(inst->skb, ct, ctinfo,
+                                NFULA_CT, NFULA_CT_INFO) < 0)
+               goto nla_put_failure;
+
        if (data_len) {
                struct nlattr *nla;
                int size = nla_attr_size(data_len);
@@ -598,8 +605,6 @@ nla_put_failure:
        return -1;
 }
 
-#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
-
 static struct nf_loginfo default_loginfo = {
        .type =         NF_LOG_TYPE_ULOG,
        .u = {
@@ -622,12 +627,16 @@ nfulnl_log_packet(struct net *net,
                  const struct nf_loginfo *li_user,
                  const char *prefix)
 {
-       unsigned int size, data_len;
+       size_t size;
+       unsigned int data_len;
        struct nfulnl_instance *inst;
        const struct nf_loginfo *li;
        unsigned int qthreshold;
        unsigned int plen;
        struct nfnl_log_net *log = nfnl_log_pernet(net);
+       const struct nfnl_ct_hook *nfnl_ct = NULL;
+       struct nf_conn *ct = NULL;
+       enum ip_conntrack_info uninitialized_var(ctinfo);
 
        if (li_user && li_user->type == NF_LOG_TYPE_ULOG)
                li = li_user;
@@ -673,6 +682,14 @@ nfulnl_log_packet(struct net *net,
                size += nla_total_size(sizeof(u_int32_t));
        if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL)
                size += nla_total_size(sizeof(u_int32_t));
+       if (inst->flags & NFULNL_CFG_F_CONNTRACK) {
+               nfnl_ct = rcu_dereference(nfnl_ct_hook);
+               if (nfnl_ct != NULL) {
+                       ct = nfnl_ct->get_ct(skb, &ctinfo);
+                       if (ct != NULL)
+                               size += nfnl_ct->build_size(ct);
+               }
+       }
 
        qthreshold = inst->qthreshold;
        /* per-rule qthreshold overrides per-instance */
@@ -717,7 +734,8 @@ nfulnl_log_packet(struct net *net,
        inst->qlen++;
 
        __build_packet_message(log, inst, skb, data_len, pf,
-                               hooknum, in, out, prefix, plen);
+                               hooknum, in, out, prefix, plen,
+                               nfnl_ct, ct, ctinfo);
 
        if (inst->qlen >= qthreshold)
                __nfulnl_flush(inst);
@@ -807,6 +825,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
        struct net *net = sock_net(ctnl);
        struct nfnl_log_net *log = nfnl_log_pernet(net);
        int ret = 0;
+       u16 flags = 0;
 
        if (nfula[NFULA_CFG_CMD]) {
                u_int8_t pf = nfmsg->nfgen_family;
@@ -828,6 +847,28 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
                goto out_put;
        }
 
+       /* Check if we support these flags in first place, dependencies should
+        * be there too not to break atomicity.
+        */
+       if (nfula[NFULA_CFG_FLAGS]) {
+               flags = ntohs(nla_get_be16(nfula[NFULA_CFG_FLAGS]));
+
+               if ((flags & NFULNL_CFG_F_CONNTRACK) &&
+                   !rcu_access_pointer(nfnl_ct_hook)) {
+#ifdef CONFIG_MODULES
+                       nfnl_unlock(NFNL_SUBSYS_ULOG);
+                       request_module("ip_conntrack_netlink");
+                       nfnl_lock(NFNL_SUBSYS_ULOG);
+                       if (rcu_access_pointer(nfnl_ct_hook)) {
+                               ret = -EAGAIN;
+                               goto out_put;
+                       }
+#endif
+                       ret = -EOPNOTSUPP;
+                       goto out_put;
+               }
+       }
+
        if (cmd != NULL) {
                switch (cmd->command) {
                case NFULNL_CFG_CMD_BIND:
@@ -856,16 +897,15 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
                        ret = -ENOTSUPP;
                        break;
                }
+       } else if (!inst) {
+               ret = -ENODEV;
+               goto out;
        }
 
        if (nfula[NFULA_CFG_MODE]) {
-               struct nfulnl_msg_config_mode *params;
-               params = nla_data(nfula[NFULA_CFG_MODE]);
+               struct nfulnl_msg_config_mode *params =
+                       nla_data(nfula[NFULA_CFG_MODE]);
 
-               if (!inst) {
-                       ret = -ENODEV;
-                       goto out;
-               }
                nfulnl_set_mode(inst, params->copy_mode,
                                ntohl(params->copy_range));
        }
@@ -873,42 +913,23 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
        if (nfula[NFULA_CFG_TIMEOUT]) {
                __be32 timeout = nla_get_be32(nfula[NFULA_CFG_TIMEOUT]);
 
-               if (!inst) {
-                       ret = -ENODEV;
-                       goto out;
-               }
                nfulnl_set_timeout(inst, ntohl(timeout));
        }
 
        if (nfula[NFULA_CFG_NLBUFSIZ]) {
                __be32 nlbufsiz = nla_get_be32(nfula[NFULA_CFG_NLBUFSIZ]);
 
-               if (!inst) {
-                       ret = -ENODEV;
-                       goto out;
-               }
                nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz));
        }
 
        if (nfula[NFULA_CFG_QTHRESH]) {
                __be32 qthresh = nla_get_be32(nfula[NFULA_CFG_QTHRESH]);
 
-               if (!inst) {
-                       ret = -ENODEV;
-                       goto out;
-               }
                nfulnl_set_qthresh(inst, ntohl(qthresh));
        }
 
-       if (nfula[NFULA_CFG_FLAGS]) {
-               __be16 flags = nla_get_be16(nfula[NFULA_CFG_FLAGS]);
-
-               if (!inst) {
-                       ret = -ENODEV;
-                       goto out;
-               }
-               nfulnl_set_flags(inst, ntohs(flags));
-       }
+       if (nfula[NFULA_CFG_FLAGS])
+               nfulnl_set_flags(inst, flags);
 
 out_put:
        instance_put(inst);