]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/openvswitch/datapath.c
Merge remote-tracking branch 'trivial/for-next'
[karo-tx-linux.git] / net / openvswitch / datapath.c
index 01d69680ba5d0f478a6d0aeea9489d859b43ca2e..91a8b004dc510272e6ab09c22ccea821cb62ac49 100644 (file)
@@ -91,8 +91,7 @@ static bool ovs_must_notify(struct genl_family *family, struct genl_info *info,
 static void ovs_notify(struct genl_family *family,
                       struct sk_buff *skb, struct genl_info *info)
 {
-       genl_notify(family, skb, genl_info_net(info), info->snd_portid,
-                   0, info->nlhdr, GFP_KERNEL);
+       genl_notify(family, skb, info, 0, GFP_KERNEL);
 }
 
 /**
@@ -176,7 +175,7 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
 const char *ovs_dp_name(const struct datapath *dp)
 {
        struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL);
-       return vport->ops->get_name(vport);
+       return ovs_vport_name(vport);
 }
 
 static int get_dpifindex(const struct datapath *dp)
@@ -188,7 +187,7 @@ static int get_dpifindex(const struct datapath *dp)
 
        local = ovs_vport_rcu(dp, OVSP_LOCAL);
        if (local)
-               ifindex = netdev_vport_priv(local)->dev->ifindex;
+               ifindex = local->dev->ifindex;
        else
                ifindex = 0;
 
@@ -275,6 +274,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
                memset(&upcall, 0, sizeof(upcall));
                upcall.cmd = OVS_PACKET_CMD_MISS;
                upcall.portid = ovs_vport_find_upcall_portid(p, skb);
+               upcall.mru = OVS_CB(skb)->mru;
                error = ovs_dp_upcall(dp, skb, key, &upcall);
                if (unlikely(error))
                        kfree_skb(skb);
@@ -400,9 +400,23 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info,
        if (upcall_info->actions_len)
                size += nla_total_size(upcall_info->actions_len);
 
+       /* OVS_PACKET_ATTR_MRU */
+       if (upcall_info->mru)
+               size += nla_total_size(sizeof(upcall_info->mru));
+
        return size;
 }
 
+static void pad_packet(struct datapath *dp, struct sk_buff *skb)
+{
+       if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
+               size_t plen = NLA_ALIGN(skb->len) - skb->len;
+
+               if (plen > 0)
+                       memset(skb_put(skb, plen), 0, plen);
+       }
+}
+
 static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                                  const struct sw_flow_key *key,
                                  const struct dp_upcall_info *upcall_info)
@@ -475,8 +489,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 
        if (upcall_info->egress_tun_info) {
                nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY);
-               err = ovs_nla_put_egress_tunnel_key(user_skb,
-                                                   upcall_info->egress_tun_info);
+               err = ovs_nla_put_tunnel_info(user_skb,
+                                             upcall_info->egress_tun_info);
                BUG_ON(err);
                nla_nest_end(user_skb, nla);
        }
@@ -492,6 +506,16 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                        nla_nest_cancel(user_skb, nla);
        }
 
+       /* Add OVS_PACKET_ATTR_MRU */
+       if (upcall_info->mru) {
+               if (nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU,
+                               upcall_info->mru)) {
+                       err = -ENOBUFS;
+                       goto out;
+               }
+               pad_packet(dp, user_skb);
+       }
+
        /* Only reserve room for attribute header, packet data is added
         * in skb_zerocopy() */
        if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) {
@@ -505,12 +529,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
                goto out;
 
        /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */
-       if (!(dp->user_features & OVS_DP_F_UNALIGNED)) {
-               size_t plen = NLA_ALIGN(user_skb->len) - user_skb->len;
-
-               if (plen > 0)
-                       memset(skb_put(user_skb, plen), 0, plen);
-       }
+       pad_packet(dp, user_skb);
 
        ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len;
 
@@ -527,6 +546,7 @@ out:
 static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 {
        struct ovs_header *ovs_header = info->userhdr;
+       struct net *net = sock_net(skb->sk);
        struct nlattr **a = info->attrs;
        struct sw_flow_actions *acts;
        struct sk_buff *packet;
@@ -535,6 +555,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        struct datapath *dp;
        struct ethhdr *eth;
        struct vport *input_vport;
+       u16 mru = 0;
        int len;
        int err;
        bool log = !a[OVS_PACKET_ATTR_PROBE];
@@ -564,29 +585,35 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        else
                packet->protocol = htons(ETH_P_802_2);
 
+       /* Set packet's mru */
+       if (a[OVS_PACKET_ATTR_MRU]) {
+               mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]);
+               packet->ignore_df = 1;
+       }
+       OVS_CB(packet)->mru = mru;
+
        /* Build an sw_flow for sending this packet. */
        flow = ovs_flow_alloc();
        err = PTR_ERR(flow);
        if (IS_ERR(flow))
                goto err_kfree_skb;
 
-       err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet,
-                                            &flow->key, log);
+       err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY],
+                                            packet, &flow->key, log);
        if (err)
                goto err_flow_free;
 
-       err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS],
+       err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS],
                                   &flow->key, &acts, log);
        if (err)
                goto err_flow_free;
 
        rcu_assign_pointer(flow->sf_acts, acts);
-       OVS_CB(packet)->egress_tun_info = NULL;
        packet->priority = flow->key.phy.priority;
        packet->mark = flow->key.phy.skb_mark;
 
        rcu_read_lock();
-       dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex);
+       dp = get_dp_rcu(net, ovs_header->dp_ifindex);
        err = -ENODEV;
        if (!dp)
                goto err_unlock;
@@ -598,6 +625,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        if (!input_vport)
                goto err_unlock;
 
+       packet->dev = input_vport->dev;
        OVS_CB(packet)->input_vport = input_vport;
        sf_acts = rcu_dereference(flow->sf_acts);
 
@@ -624,6 +652,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
        [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG },
+       [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 },
 };
 
 static const struct genl_ops dp_packet_genl_ops[] = {
@@ -713,7 +742,7 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts,
 
        /* OVS_FLOW_ATTR_ACTIONS */
        if (should_fill_actions(ufid_flags))
-               len += nla_total_size(acts->actions_len);
+               len += nla_total_size(acts->orig_len);
 
        return len
                + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
@@ -880,6 +909,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow,
 
 static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
 {
+       struct net *net = sock_net(skb->sk);
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
        struct sw_flow *flow = NULL, *new_flow;
@@ -915,12 +945,12 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
        /* Extract key. */
        ovs_match_init(&match, &key, &mask);
-       error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
+       error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
                                  a[OVS_FLOW_ATTR_MASK], log);
        if (error)
                goto err_kfree_flow;
 
-       ovs_flow_mask_key(&new_flow->key, &key, &mask);
+       ovs_flow_mask_key(&new_flow->key, &key, true, &mask);
 
        /* Extract flow identifier. */
        error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
@@ -929,8 +959,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_kfree_flow;
 
        /* Validate actions. */
-       error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key,
-                                    &acts, log);
+       error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
+                                    &new_flow->key, &acts, log);
        if (error) {
                OVS_NLERR(log, "Flow actions may not be safe on all matching packets.");
                goto err_kfree_flow;
@@ -944,7 +974,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        }
 
        ovs_lock();
-       dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
+       dp = get_dp(net, ovs_header->dp_ifindex);
        if (unlikely(!dp)) {
                error = -ENODEV;
                goto err_unlock_ovs;
@@ -1018,7 +1048,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
                }
                ovs_unlock();
 
-               ovs_nla_free_flow_actions(old_acts);
+               ovs_nla_free_flow_actions_rcu(old_acts);
                ovs_flow_free(new_flow, false);
        }
 
@@ -1030,7 +1060,7 @@ err_unlock_ovs:
        ovs_unlock();
        kfree_skb(reply);
 err_kfree_acts:
-       kfree(acts);
+       ovs_nla_free_flow_actions(acts);
 err_kfree_flow:
        ovs_flow_free(new_flow, false);
 error:
@@ -1038,7 +1068,8 @@ error:
 }
 
 /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */
-static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
+static struct sw_flow_actions *get_flow_actions(struct net *net,
+                                               const struct nlattr *a,
                                                const struct sw_flow_key *key,
                                                const struct sw_flow_mask *mask,
                                                bool log)
@@ -1047,8 +1078,8 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
        struct sw_flow_key masked_key;
        int error;
 
-       ovs_flow_mask_key(&masked_key, key, mask);
-       error = ovs_nla_copy_actions(a, &masked_key, &acts, log);
+       ovs_flow_mask_key(&masked_key, key, true, mask);
+       error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log);
        if (error) {
                OVS_NLERR(log,
                          "Actions may not be safe on all matching packets");
@@ -1060,6 +1091,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a,
 
 static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
 {
+       struct net *net = sock_net(skb->sk);
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
        struct sw_flow_key key;
@@ -1084,15 +1116,15 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
 
        ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log);
        ovs_match_init(&match, &key, &mask);
-       error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY],
+       error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
                                  a[OVS_FLOW_ATTR_MASK], log);
        if (error)
                goto error;
 
        /* Validate actions. */
        if (a[OVS_FLOW_ATTR_ACTIONS]) {
-               acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask,
-                                       log);
+               acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key,
+                                       &mask, log);
                if (IS_ERR(acts)) {
                        error = PTR_ERR(acts);
                        goto error;
@@ -1108,7 +1140,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
        }
 
        ovs_lock();
-       dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
+       dp = get_dp(net, ovs_header->dp_ifindex);
        if (unlikely(!dp)) {
                error = -ENODEV;
                goto err_unlock_ovs;
@@ -1157,7 +1189,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info)
        if (reply)
                ovs_notify(&dp_flow_genl_family, reply, info);
        if (old_acts)
-               ovs_nla_free_flow_actions(old_acts);
+               ovs_nla_free_flow_actions_rcu(old_acts);
 
        return 0;
 
@@ -1165,7 +1197,7 @@ err_unlock_ovs:
        ovs_unlock();
        kfree_skb(reply);
 err_kfree_acts:
-       kfree(acts);
+       ovs_nla_free_flow_actions(acts);
 error:
        return error;
 }
@@ -1174,6 +1206,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
+       struct net *net = sock_net(skb->sk);
        struct sw_flow_key key;
        struct sk_buff *reply;
        struct sw_flow *flow;
@@ -1188,7 +1221,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
        ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
        if (a[OVS_FLOW_ATTR_KEY]) {
                ovs_match_init(&match, &key, NULL);
-               err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL,
+               err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL,
                                        log);
        } else if (!ufid_present) {
                OVS_NLERR(log,
@@ -1232,6 +1265,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 {
        struct nlattr **a = info->attrs;
        struct ovs_header *ovs_header = info->userhdr;
+       struct net *net = sock_net(skb->sk);
        struct sw_flow_key key;
        struct sk_buff *reply;
        struct sw_flow *flow = NULL;
@@ -1246,8 +1280,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
        ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log);
        if (a[OVS_FLOW_ATTR_KEY]) {
                ovs_match_init(&match, &key, NULL);
-               err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL,
-                                       log);
+               err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
+                                       NULL, log);
                if (unlikely(err))
                        return err;
        }
@@ -1800,7 +1834,7 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,
        if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) ||
            nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) ||
            nla_put_string(skb, OVS_VPORT_ATTR_NAME,
-                          vport->ops->get_name(vport)))
+                          ovs_vport_name(vport)))
                goto nla_put_failure;
 
        ovs_vport_get_stats(vport, &vport_stats);
@@ -2203,6 +2237,7 @@ static int __net_init ovs_init_net(struct net *net)
 
        INIT_LIST_HEAD(&ovs_net->dps);
        INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq);
+       ovs_ct_init(net);
        return 0;
 }
 
@@ -2219,13 +2254,10 @@ static void __net_exit list_vports_from_net(struct net *net, struct net *dnet,
                        struct vport *vport;
 
                        hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) {
-                               struct netdev_vport *netdev_vport;
-
                                if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL)
                                        continue;
 
-                               netdev_vport = netdev_vport_priv(vport);
-                               if (dev_net(netdev_vport->dev) == dnet)
+                               if (dev_net(vport->dev) == dnet)
                                        list_add(&vport->detach_list, head);
                        }
                }
@@ -2240,6 +2272,7 @@ static void __net_exit ovs_exit_net(struct net *dnet)
        struct net *net;
        LIST_HEAD(head);
 
+       ovs_ct_exit(dnet);
        ovs_lock();
        list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node)
                __dp_destroy(dp);