.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (c) 2015 Nicira, Inc. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or |
---|
5 | | - * modify it under the terms of version 2 of the GNU General Public |
---|
6 | | - * License as published by the Free Software Foundation. |
---|
7 | | - * |
---|
8 | | - * This program is distributed in the hope that it will be useful, but |
---|
9 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
11 | | - * General Public License for more details. |
---|
12 | 4 | */ |
---|
13 | 5 | |
---|
14 | 6 | #include <linux/module.h> |
---|
.. | .. |
---|
24 | 16 | #include <net/netfilter/nf_conntrack_helper.h> |
---|
25 | 17 | #include <net/netfilter/nf_conntrack_labels.h> |
---|
26 | 18 | #include <net/netfilter/nf_conntrack_seqadj.h> |
---|
| 19 | +#include <net/netfilter/nf_conntrack_timeout.h> |
---|
27 | 20 | #include <net/netfilter/nf_conntrack_zones.h> |
---|
28 | 21 | #include <net/netfilter/ipv6/nf_defrag_ipv6.h> |
---|
29 | 22 | #include <net/ipv6_frag.h> |
---|
30 | 23 | |
---|
31 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
32 | | -#include <linux/netfilter/nf_nat.h> |
---|
33 | | -#include <net/netfilter/nf_nat_core.h> |
---|
34 | | -#include <net/netfilter/nf_nat_l3proto.h> |
---|
| 24 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
| 25 | +#include <net/netfilter/nf_nat.h> |
---|
35 | 26 | #endif |
---|
36 | 27 | |
---|
37 | 28 | #include "datapath.h" |
---|
.. | .. |
---|
75 | 66 | u32 eventmask; /* Mask of 1 << IPCT_*. */ |
---|
76 | 67 | struct md_mark mark; |
---|
77 | 68 | struct md_labels labels; |
---|
78 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
| 69 | + char timeout[CTNL_TIMEOUT_NAME_MAX]; |
---|
| 70 | + struct nf_ct_timeout *nf_ct_timeout; |
---|
| 71 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
79 | 72 | struct nf_nat_range2 range; /* Only present for SRC NAT and DST NAT. */ |
---|
80 | 73 | #endif |
---|
81 | 74 | }; |
---|
.. | .. |
---|
157 | 150 | static u32 ovs_ct_get_mark(const struct nf_conn *ct) |
---|
158 | 151 | { |
---|
159 | 152 | #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) |
---|
160 | | - return ct ? ct->mark : 0; |
---|
| 153 | + return ct ? READ_ONCE(ct->mark) : 0; |
---|
161 | 154 | #else |
---|
162 | 155 | return 0; |
---|
163 | 156 | #endif |
---|
.. | .. |
---|
343 | 336 | #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) |
---|
344 | 337 | u32 new_mark; |
---|
345 | 338 | |
---|
346 | | - new_mark = ct_mark | (ct->mark & ~(mask)); |
---|
347 | | - if (ct->mark != new_mark) { |
---|
348 | | - ct->mark = new_mark; |
---|
| 339 | + new_mark = ct_mark | (READ_ONCE(ct->mark) & ~(mask)); |
---|
| 340 | + if (READ_ONCE(ct->mark) != new_mark) { |
---|
| 341 | + WRITE_ONCE(ct->mark, new_mark); |
---|
349 | 342 | if (nf_ct_is_confirmed(ct)) |
---|
350 | 343 | nf_conntrack_event_cache(IPCT_MARK, ct); |
---|
351 | 344 | key->ct.mark = new_mark; |
---|
.. | .. |
---|
534 | 527 | return -EPFNOSUPPORT; |
---|
535 | 528 | } |
---|
536 | 529 | |
---|
| 530 | + /* The key extracted from the fragment that completed this datagram |
---|
| 531 | + * likely didn't have an L4 header, so regenerate it. |
---|
| 532 | + */ |
---|
| 533 | + ovs_flow_key_update_l3l4(skb, key); |
---|
| 534 | + |
---|
537 | 535 | key->ip.frag = OVS_FRAG_TYPE_NONE; |
---|
538 | 536 | skb_clear_hash(skb); |
---|
539 | 537 | skb->ignore_df = 1; |
---|
.. | .. |
---|
624 | 622 | if (natted) { |
---|
625 | 623 | struct nf_conntrack_tuple inverse; |
---|
626 | 624 | |
---|
627 | | - if (!nf_ct_invert_tuplepr(&inverse, &tuple)) { |
---|
| 625 | + if (!nf_ct_invert_tuple(&inverse, &tuple)) { |
---|
628 | 626 | pr_debug("ovs_ct_find_existing: Inversion failed!\n"); |
---|
629 | 627 | return NULL; |
---|
630 | 628 | } |
---|
.. | .. |
---|
707 | 705 | if (help && rcu_access_pointer(help->helper) != info->helper) |
---|
708 | 706 | return false; |
---|
709 | 707 | } |
---|
| 708 | + if (info->nf_ct_timeout) { |
---|
| 709 | + struct nf_conn_timeout *timeout_ext; |
---|
| 710 | + |
---|
| 711 | + timeout_ext = nf_ct_timeout_find(ct); |
---|
| 712 | + if (!timeout_ext || info->nf_ct_timeout != |
---|
| 713 | + rcu_dereference(timeout_ext->timeout)) |
---|
| 714 | + return false; |
---|
| 715 | + } |
---|
710 | 716 | /* Force conntrack entry direction to the current packet? */ |
---|
711 | 717 | if (info->force && CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL) { |
---|
712 | 718 | /* Delete the conntrack entry if confirmed, else just release |
---|
.. | .. |
---|
723 | 729 | return ct_executed; |
---|
724 | 730 | } |
---|
725 | 731 | |
---|
726 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
727 | | -/* Modelled after nf_nat_ipv[46]_fn(). |
---|
728 | | - * range is only used for new, uninitialized NAT state. |
---|
729 | | - * Returns either NF_ACCEPT or NF_DROP. |
---|
730 | | - */ |
---|
731 | | -static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, |
---|
732 | | - enum ip_conntrack_info ctinfo, |
---|
733 | | - const struct nf_nat_range2 *range, |
---|
734 | | - enum nf_nat_manip_type maniptype) |
---|
735 | | -{ |
---|
736 | | - int hooknum, nh_off, err = NF_ACCEPT; |
---|
737 | | - |
---|
738 | | - nh_off = skb_network_offset(skb); |
---|
739 | | - skb_pull_rcsum(skb, nh_off); |
---|
740 | | - |
---|
741 | | - /* See HOOK2MANIP(). */ |
---|
742 | | - if (maniptype == NF_NAT_MANIP_SRC) |
---|
743 | | - hooknum = NF_INET_LOCAL_IN; /* Source NAT */ |
---|
744 | | - else |
---|
745 | | - hooknum = NF_INET_LOCAL_OUT; /* Destination NAT */ |
---|
746 | | - |
---|
747 | | - switch (ctinfo) { |
---|
748 | | - case IP_CT_RELATED: |
---|
749 | | - case IP_CT_RELATED_REPLY: |
---|
750 | | - if (IS_ENABLED(CONFIG_NF_NAT_IPV4) && |
---|
751 | | - skb->protocol == htons(ETH_P_IP) && |
---|
752 | | - ip_hdr(skb)->protocol == IPPROTO_ICMP) { |
---|
753 | | - if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, |
---|
754 | | - hooknum)) |
---|
755 | | - err = NF_DROP; |
---|
756 | | - goto push; |
---|
757 | | - } else if (IS_ENABLED(CONFIG_NF_NAT_IPV6) && |
---|
758 | | - skb->protocol == htons(ETH_P_IPV6)) { |
---|
759 | | - __be16 frag_off; |
---|
760 | | - u8 nexthdr = ipv6_hdr(skb)->nexthdr; |
---|
761 | | - int hdrlen = ipv6_skip_exthdr(skb, |
---|
762 | | - sizeof(struct ipv6hdr), |
---|
763 | | - &nexthdr, &frag_off); |
---|
764 | | - |
---|
765 | | - if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { |
---|
766 | | - if (!nf_nat_icmpv6_reply_translation(skb, ct, |
---|
767 | | - ctinfo, |
---|
768 | | - hooknum, |
---|
769 | | - hdrlen)) |
---|
770 | | - err = NF_DROP; |
---|
771 | | - goto push; |
---|
772 | | - } |
---|
773 | | - } |
---|
774 | | - /* Non-ICMP, fall thru to initialize if needed. */ |
---|
775 | | - /* fall through */ |
---|
776 | | - case IP_CT_NEW: |
---|
777 | | - /* Seen it before? This can happen for loopback, retrans, |
---|
778 | | - * or local packets. |
---|
779 | | - */ |
---|
780 | | - if (!nf_nat_initialized(ct, maniptype)) { |
---|
781 | | - /* Initialize according to the NAT action. */ |
---|
782 | | - err = (range && range->flags & NF_NAT_RANGE_MAP_IPS) |
---|
783 | | - /* Action is set up to establish a new |
---|
784 | | - * mapping. |
---|
785 | | - */ |
---|
786 | | - ? nf_nat_setup_info(ct, range, maniptype) |
---|
787 | | - : nf_nat_alloc_null_binding(ct, hooknum); |
---|
788 | | - if (err != NF_ACCEPT) |
---|
789 | | - goto push; |
---|
790 | | - } |
---|
791 | | - break; |
---|
792 | | - |
---|
793 | | - case IP_CT_ESTABLISHED: |
---|
794 | | - case IP_CT_ESTABLISHED_REPLY: |
---|
795 | | - break; |
---|
796 | | - |
---|
797 | | - default: |
---|
798 | | - err = NF_DROP; |
---|
799 | | - goto push; |
---|
800 | | - } |
---|
801 | | - |
---|
802 | | - err = nf_nat_packet(ct, ctinfo, hooknum, skb); |
---|
803 | | -push: |
---|
804 | | - skb_push(skb, nh_off); |
---|
805 | | - skb_postpush_rcsum(skb, skb->data, nh_off); |
---|
806 | | - |
---|
807 | | - return err; |
---|
808 | | -} |
---|
809 | | - |
---|
| 732 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
810 | 733 | static void ovs_nat_update_key(struct sw_flow_key *key, |
---|
811 | 734 | const struct sk_buff *skb, |
---|
812 | 735 | enum nf_nat_manip_type maniptype) |
---|
.. | .. |
---|
858 | 781 | } |
---|
859 | 782 | } |
---|
860 | 783 | |
---|
| 784 | +/* Modelled after nf_nat_ipv[46]_fn(). |
---|
| 785 | + * range is only used for new, uninitialized NAT state. |
---|
| 786 | + * Returns either NF_ACCEPT or NF_DROP. |
---|
| 787 | + */ |
---|
| 788 | +static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct, |
---|
| 789 | + enum ip_conntrack_info ctinfo, |
---|
| 790 | + const struct nf_nat_range2 *range, |
---|
| 791 | + enum nf_nat_manip_type maniptype, struct sw_flow_key *key) |
---|
| 792 | +{ |
---|
| 793 | + int hooknum, nh_off, err = NF_ACCEPT; |
---|
| 794 | + |
---|
| 795 | + nh_off = skb_network_offset(skb); |
---|
| 796 | + skb_pull_rcsum(skb, nh_off); |
---|
| 797 | + |
---|
| 798 | + /* See HOOK2MANIP(). */ |
---|
| 799 | + if (maniptype == NF_NAT_MANIP_SRC) |
---|
| 800 | + hooknum = NF_INET_LOCAL_IN; /* Source NAT */ |
---|
| 801 | + else |
---|
| 802 | + hooknum = NF_INET_LOCAL_OUT; /* Destination NAT */ |
---|
| 803 | + |
---|
| 804 | + switch (ctinfo) { |
---|
| 805 | + case IP_CT_RELATED: |
---|
| 806 | + case IP_CT_RELATED_REPLY: |
---|
| 807 | + if (IS_ENABLED(CONFIG_NF_NAT) && |
---|
| 808 | + skb->protocol == htons(ETH_P_IP) && |
---|
| 809 | + ip_hdr(skb)->protocol == IPPROTO_ICMP) { |
---|
| 810 | + if (!nf_nat_icmp_reply_translation(skb, ct, ctinfo, |
---|
| 811 | + hooknum)) |
---|
| 812 | + err = NF_DROP; |
---|
| 813 | + goto push; |
---|
| 814 | + } else if (IS_ENABLED(CONFIG_IPV6) && |
---|
| 815 | + skb->protocol == htons(ETH_P_IPV6)) { |
---|
| 816 | + __be16 frag_off; |
---|
| 817 | + u8 nexthdr = ipv6_hdr(skb)->nexthdr; |
---|
| 818 | + int hdrlen = ipv6_skip_exthdr(skb, |
---|
| 819 | + sizeof(struct ipv6hdr), |
---|
| 820 | + &nexthdr, &frag_off); |
---|
| 821 | + |
---|
| 822 | + if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) { |
---|
| 823 | + if (!nf_nat_icmpv6_reply_translation(skb, ct, |
---|
| 824 | + ctinfo, |
---|
| 825 | + hooknum, |
---|
| 826 | + hdrlen)) |
---|
| 827 | + err = NF_DROP; |
---|
| 828 | + goto push; |
---|
| 829 | + } |
---|
| 830 | + } |
---|
| 831 | + /* Non-ICMP, fall thru to initialize if needed. */ |
---|
| 832 | + fallthrough; |
---|
| 833 | + case IP_CT_NEW: |
---|
| 834 | + /* Seen it before? This can happen for loopback, retrans, |
---|
| 835 | + * or local packets. |
---|
| 836 | + */ |
---|
| 837 | + if (!nf_nat_initialized(ct, maniptype)) { |
---|
| 838 | + /* Initialize according to the NAT action. */ |
---|
| 839 | + err = (range && range->flags & NF_NAT_RANGE_MAP_IPS) |
---|
| 840 | + /* Action is set up to establish a new |
---|
| 841 | + * mapping. |
---|
| 842 | + */ |
---|
| 843 | + ? nf_nat_setup_info(ct, range, maniptype) |
---|
| 844 | + : nf_nat_alloc_null_binding(ct, hooknum); |
---|
| 845 | + if (err != NF_ACCEPT) |
---|
| 846 | + goto push; |
---|
| 847 | + } |
---|
| 848 | + break; |
---|
| 849 | + |
---|
| 850 | + case IP_CT_ESTABLISHED: |
---|
| 851 | + case IP_CT_ESTABLISHED_REPLY: |
---|
| 852 | + break; |
---|
| 853 | + |
---|
| 854 | + default: |
---|
| 855 | + err = NF_DROP; |
---|
| 856 | + goto push; |
---|
| 857 | + } |
---|
| 858 | + |
---|
| 859 | + err = nf_nat_packet(ct, ctinfo, hooknum, skb); |
---|
| 860 | +push: |
---|
| 861 | + skb_push(skb, nh_off); |
---|
| 862 | + skb_postpush_rcsum(skb, skb->data, nh_off); |
---|
| 863 | + |
---|
| 864 | + /* Update the flow key if NAT successful. */ |
---|
| 865 | + if (err == NF_ACCEPT) |
---|
| 866 | + ovs_nat_update_key(key, skb, maniptype); |
---|
| 867 | + |
---|
| 868 | + return err; |
---|
| 869 | +} |
---|
| 870 | + |
---|
861 | 871 | /* Returns NF_DROP if the packet should be dropped, NF_ACCEPT otherwise. */ |
---|
862 | 872 | static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, |
---|
863 | 873 | const struct ovs_conntrack_info *info, |
---|
.. | .. |
---|
897 | 907 | } else { |
---|
898 | 908 | return NF_ACCEPT; /* Connection is not NATed. */ |
---|
899 | 909 | } |
---|
900 | | - err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype); |
---|
| 910 | + err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, maniptype, key); |
---|
901 | 911 | |
---|
902 | 912 | if (err == NF_ACCEPT && ct->status & IPS_DST_NAT) { |
---|
903 | 913 | if (ct->status & IPS_SRC_NAT) { |
---|
.. | .. |
---|
907 | 917 | maniptype = NF_NAT_MANIP_SRC; |
---|
908 | 918 | |
---|
909 | 919 | err = ovs_ct_nat_execute(skb, ct, ctinfo, &info->range, |
---|
910 | | - maniptype); |
---|
| 920 | + maniptype, key); |
---|
911 | 921 | } else if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) { |
---|
912 | 922 | err = ovs_ct_nat_execute(skb, ct, ctinfo, NULL, |
---|
913 | | - NF_NAT_MANIP_SRC); |
---|
| 923 | + NF_NAT_MANIP_SRC, key); |
---|
914 | 924 | } |
---|
915 | 925 | } |
---|
916 | 926 | |
---|
917 | | - /* Mark NAT done if successful and update the flow key. */ |
---|
918 | | - if (err == NF_ACCEPT) |
---|
919 | | - ovs_nat_update_key(key, skb, maniptype); |
---|
920 | | - |
---|
921 | 927 | return err; |
---|
922 | 928 | } |
---|
923 | | -#else /* !CONFIG_NF_NAT_NEEDED */ |
---|
| 929 | +#else /* !CONFIG_NF_NAT */ |
---|
924 | 930 | static int ovs_ct_nat(struct net *net, struct sw_flow_key *key, |
---|
925 | 931 | const struct ovs_conntrack_info *info, |
---|
926 | 932 | struct sk_buff *skb, struct nf_conn *ct, |
---|
.. | .. |
---|
950 | 956 | struct nf_conn *ct; |
---|
951 | 957 | |
---|
952 | 958 | if (!cached) { |
---|
| 959 | + struct nf_hook_state state = { |
---|
| 960 | + .hook = NF_INET_PRE_ROUTING, |
---|
| 961 | + .pf = info->family, |
---|
| 962 | + .net = net, |
---|
| 963 | + }; |
---|
953 | 964 | struct nf_conn *tmpl = info->ct; |
---|
954 | 965 | int err; |
---|
955 | 966 | |
---|
.. | .. |
---|
961 | 972 | nf_ct_set(skb, tmpl, IP_CT_NEW); |
---|
962 | 973 | } |
---|
963 | 974 | |
---|
964 | | - err = nf_conntrack_in(net, info->family, |
---|
965 | | - NF_INET_PRE_ROUTING, skb); |
---|
| 975 | + err = nf_conntrack_in(skb, &state); |
---|
966 | 976 | if (err != NF_ACCEPT) |
---|
967 | 977 | return -ENOENT; |
---|
968 | 978 | |
---|
.. | .. |
---|
978 | 988 | |
---|
979 | 989 | ct = nf_ct_get(skb, &ctinfo); |
---|
980 | 990 | if (ct) { |
---|
| 991 | + bool add_helper = false; |
---|
| 992 | + |
---|
981 | 993 | /* Packets starting a new connection must be NATted before the |
---|
982 | 994 | * helper, so that the helper knows about the NAT. We enforce |
---|
983 | 995 | * this by delaying both NAT and helper calls for unconfirmed |
---|
.. | .. |
---|
995 | 1007 | } |
---|
996 | 1008 | |
---|
997 | 1009 | /* Userspace may decide to perform a ct lookup without a helper |
---|
998 | | - * specified followed by a (recirculate and) commit with one. |
---|
999 | | - * Therefore, for unconfirmed connections which we will commit, |
---|
1000 | | - * we need to attach the helper here. |
---|
| 1010 | + * specified followed by a (recirculate and) commit with one, |
---|
| 1011 | + * or attach a helper in a later commit. Therefore, for |
---|
| 1012 | + * connections which we will commit, we may need to attach |
---|
| 1013 | + * the helper here. |
---|
1001 | 1014 | */ |
---|
1002 | | - if (!nf_ct_is_confirmed(ct) && info->commit && |
---|
1003 | | - info->helper && !nfct_help(ct)) { |
---|
| 1015 | + if (info->commit && info->helper && !nfct_help(ct)) { |
---|
1004 | 1016 | int err = __nf_ct_try_assign_helper(ct, info->ct, |
---|
1005 | 1017 | GFP_ATOMIC); |
---|
1006 | 1018 | if (err) |
---|
1007 | 1019 | return err; |
---|
| 1020 | + add_helper = true; |
---|
| 1021 | + |
---|
| 1022 | + /* helper installed, add seqadj if NAT is required */ |
---|
| 1023 | + if (info->nat && !nfct_seqadj(ct)) { |
---|
| 1024 | + if (!nfct_seqadj_ext_add(ct)) |
---|
| 1025 | + return -EINVAL; |
---|
| 1026 | + } |
---|
1008 | 1027 | } |
---|
1009 | 1028 | |
---|
1010 | 1029 | /* Call the helper only if: |
---|
1011 | | - * - nf_conntrack_in() was executed above ("!cached") for a |
---|
1012 | | - * confirmed connection, or |
---|
| 1030 | + * - nf_conntrack_in() was executed above ("!cached") or a |
---|
| 1031 | + * helper was just attached ("add_helper") for a confirmed |
---|
| 1032 | + * connection, or |
---|
1013 | 1033 | * - When committing an unconfirmed connection. |
---|
1014 | 1034 | */ |
---|
1015 | | - if ((nf_ct_is_confirmed(ct) ? !cached : info->commit) && |
---|
| 1035 | + if ((nf_ct_is_confirmed(ct) ? !cached || add_helper : |
---|
| 1036 | + info->commit) && |
---|
1016 | 1037 | ovs_ct_helper(skb, info->family) != NF_ACCEPT) { |
---|
1017 | 1038 | return -EINVAL; |
---|
1018 | 1039 | } |
---|
.. | .. |
---|
1179 | 1200 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
---|
1180 | 1201 | if (err) { |
---|
1181 | 1202 | net_warn_ratelimited("openvswitch: zone: %u " |
---|
1182 | | - "execeeds conntrack limit\n", |
---|
| 1203 | + "exceeds conntrack limit\n", |
---|
1183 | 1204 | info->zone.id); |
---|
1184 | 1205 | return err; |
---|
1185 | 1206 | } |
---|
.. | .. |
---|
1303 | 1324 | if (skb_nfct(skb)) { |
---|
1304 | 1325 | nf_conntrack_put(skb_nfct(skb)); |
---|
1305 | 1326 | nf_ct_set(skb, NULL, IP_CT_UNTRACKED); |
---|
1306 | | - ovs_ct_fill_key(skb, key); |
---|
| 1327 | + if (key) |
---|
| 1328 | + ovs_ct_fill_key(skb, key); |
---|
1307 | 1329 | } |
---|
1308 | 1330 | |
---|
1309 | 1331 | return 0; |
---|
.. | .. |
---|
1314 | 1336 | { |
---|
1315 | 1337 | struct nf_conntrack_helper *helper; |
---|
1316 | 1338 | struct nf_conn_help *help; |
---|
| 1339 | + int ret = 0; |
---|
1317 | 1340 | |
---|
1318 | 1341 | helper = nf_conntrack_helper_try_module_get(name, info->family, |
---|
1319 | 1342 | key->ip.proto); |
---|
.. | .. |
---|
1328 | 1351 | return -ENOMEM; |
---|
1329 | 1352 | } |
---|
1330 | 1353 | |
---|
| 1354 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
| 1355 | + if (info->nat) { |
---|
| 1356 | + ret = nf_nat_helper_try_module_get(name, info->family, |
---|
| 1357 | + key->ip.proto); |
---|
| 1358 | + if (ret) { |
---|
| 1359 | + nf_conntrack_helper_put(helper); |
---|
| 1360 | + OVS_NLERR(log, "Failed to load \"%s\" NAT helper, error: %d", |
---|
| 1361 | + name, ret); |
---|
| 1362 | + return ret; |
---|
| 1363 | + } |
---|
| 1364 | + } |
---|
| 1365 | +#endif |
---|
1331 | 1366 | rcu_assign_pointer(help->helper, helper); |
---|
1332 | 1367 | info->helper = helper; |
---|
1333 | | - |
---|
1334 | | - if (info->nat) |
---|
1335 | | - request_module("ip_nat_%s", name); |
---|
1336 | | - |
---|
1337 | | - return 0; |
---|
| 1368 | + return ret; |
---|
1338 | 1369 | } |
---|
1339 | 1370 | |
---|
1340 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
| 1371 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
1341 | 1372 | static int parse_nat(const struct nlattr *attr, |
---|
1342 | 1373 | struct ovs_conntrack_info *info, bool log) |
---|
1343 | 1374 | { |
---|
.. | .. |
---|
1474 | 1505 | .maxlen = sizeof(struct md_labels) }, |
---|
1475 | 1506 | [OVS_CT_ATTR_HELPER] = { .minlen = 1, |
---|
1476 | 1507 | .maxlen = NF_CT_HELPER_NAME_LEN }, |
---|
1477 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
| 1508 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
1478 | 1509 | /* NAT length is checked when parsing the nested attributes. */ |
---|
1479 | 1510 | [OVS_CT_ATTR_NAT] = { .minlen = 0, .maxlen = INT_MAX }, |
---|
1480 | 1511 | #endif |
---|
1481 | 1512 | [OVS_CT_ATTR_EVENTMASK] = { .minlen = sizeof(u32), |
---|
1482 | 1513 | .maxlen = sizeof(u32) }, |
---|
| 1514 | + [OVS_CT_ATTR_TIMEOUT] = { .minlen = 1, |
---|
| 1515 | + .maxlen = CTNL_TIMEOUT_NAME_MAX }, |
---|
1483 | 1516 | }; |
---|
1484 | 1517 | |
---|
1485 | 1518 | static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, |
---|
.. | .. |
---|
1512 | 1545 | switch (type) { |
---|
1513 | 1546 | case OVS_CT_ATTR_FORCE_COMMIT: |
---|
1514 | 1547 | info->force = true; |
---|
1515 | | - /* fall through. */ |
---|
| 1548 | + fallthrough; |
---|
1516 | 1549 | case OVS_CT_ATTR_COMMIT: |
---|
1517 | 1550 | info->commit = true; |
---|
1518 | 1551 | break; |
---|
.. | .. |
---|
1552 | 1585 | return -EINVAL; |
---|
1553 | 1586 | } |
---|
1554 | 1587 | break; |
---|
1555 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
| 1588 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
1556 | 1589 | case OVS_CT_ATTR_NAT: { |
---|
1557 | 1590 | int err = parse_nat(a, info, log); |
---|
1558 | 1591 | |
---|
.. | .. |
---|
1565 | 1598 | info->have_eventmask = true; |
---|
1566 | 1599 | info->eventmask = nla_get_u32(a); |
---|
1567 | 1600 | break; |
---|
| 1601 | +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT |
---|
| 1602 | + case OVS_CT_ATTR_TIMEOUT: |
---|
| 1603 | + memcpy(info->timeout, nla_data(a), nla_len(a)); |
---|
| 1604 | + if (!memchr(info->timeout, '\0', nla_len(a))) { |
---|
| 1605 | + OVS_NLERR(log, "Invalid conntrack timeout"); |
---|
| 1606 | + return -EINVAL; |
---|
| 1607 | + } |
---|
| 1608 | + break; |
---|
| 1609 | +#endif |
---|
1568 | 1610 | |
---|
1569 | 1611 | default: |
---|
1570 | 1612 | OVS_NLERR(log, "Unknown conntrack attr (%d)", |
---|
.. | .. |
---|
1646 | 1688 | OVS_NLERR(log, "Failed to allocate conntrack template"); |
---|
1647 | 1689 | return -ENOMEM; |
---|
1648 | 1690 | } |
---|
| 1691 | + |
---|
| 1692 | + if (ct_info.timeout[0]) { |
---|
| 1693 | + if (nf_ct_set_timeout(net, ct_info.ct, family, key->ip.proto, |
---|
| 1694 | + ct_info.timeout)) |
---|
| 1695 | + pr_info_ratelimited("Failed to associated timeout " |
---|
| 1696 | + "policy `%s'\n", ct_info.timeout); |
---|
| 1697 | + else |
---|
| 1698 | + ct_info.nf_ct_timeout = rcu_dereference( |
---|
| 1699 | + nf_ct_timeout_find(ct_info.ct)->timeout); |
---|
| 1700 | + |
---|
| 1701 | + } |
---|
| 1702 | + |
---|
1649 | 1703 | if (helper) { |
---|
1650 | 1704 | err = ovs_ct_add_helper(&ct_info, helper, key, log); |
---|
1651 | 1705 | if (err) |
---|
.. | .. |
---|
1665 | 1719 | return err; |
---|
1666 | 1720 | } |
---|
1667 | 1721 | |
---|
1668 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
| 1722 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
1669 | 1723 | static bool ovs_ct_nat_to_attr(const struct ovs_conntrack_info *info, |
---|
1670 | 1724 | struct sk_buff *skb) |
---|
1671 | 1725 | { |
---|
1672 | 1726 | struct nlattr *start; |
---|
1673 | 1727 | |
---|
1674 | | - start = nla_nest_start(skb, OVS_CT_ATTR_NAT); |
---|
| 1728 | + start = nla_nest_start_noflag(skb, OVS_CT_ATTR_NAT); |
---|
1675 | 1729 | if (!start) |
---|
1676 | 1730 | return false; |
---|
1677 | 1731 | |
---|
.. | .. |
---|
1686 | 1740 | } |
---|
1687 | 1741 | |
---|
1688 | 1742 | if (info->range.flags & NF_NAT_RANGE_MAP_IPS) { |
---|
1689 | | - if (IS_ENABLED(CONFIG_NF_NAT_IPV4) && |
---|
| 1743 | + if (IS_ENABLED(CONFIG_NF_NAT) && |
---|
1690 | 1744 | info->family == NFPROTO_IPV4) { |
---|
1691 | 1745 | if (nla_put_in_addr(skb, OVS_NAT_ATTR_IP_MIN, |
---|
1692 | 1746 | info->range.min_addr.ip) || |
---|
.. | .. |
---|
1695 | 1749 | (nla_put_in_addr(skb, OVS_NAT_ATTR_IP_MAX, |
---|
1696 | 1750 | info->range.max_addr.ip)))) |
---|
1697 | 1751 | return false; |
---|
1698 | | - } else if (IS_ENABLED(CONFIG_NF_NAT_IPV6) && |
---|
| 1752 | + } else if (IS_ENABLED(CONFIG_IPV6) && |
---|
1699 | 1753 | info->family == NFPROTO_IPV6) { |
---|
1700 | 1754 | if (nla_put_in6_addr(skb, OVS_NAT_ATTR_IP_MIN, |
---|
1701 | 1755 | &info->range.min_addr.in6) || |
---|
.. | .. |
---|
1738 | 1792 | { |
---|
1739 | 1793 | struct nlattr *start; |
---|
1740 | 1794 | |
---|
1741 | | - start = nla_nest_start(skb, OVS_ACTION_ATTR_CT); |
---|
| 1795 | + start = nla_nest_start_noflag(skb, OVS_ACTION_ATTR_CT); |
---|
1742 | 1796 | if (!start) |
---|
1743 | 1797 | return -EMSGSIZE; |
---|
1744 | 1798 | |
---|
.. | .. |
---|
1766 | 1820 | if (ct_info->have_eventmask && |
---|
1767 | 1821 | nla_put_u32(skb, OVS_CT_ATTR_EVENTMASK, ct_info->eventmask)) |
---|
1768 | 1822 | return -EMSGSIZE; |
---|
| 1823 | + if (ct_info->timeout[0]) { |
---|
| 1824 | + if (nla_put_string(skb, OVS_CT_ATTR_TIMEOUT, ct_info->timeout)) |
---|
| 1825 | + return -EMSGSIZE; |
---|
| 1826 | + } |
---|
1769 | 1827 | |
---|
1770 | | -#ifdef CONFIG_NF_NAT_NEEDED |
---|
| 1828 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
1771 | 1829 | if (ct_info->nat && !ovs_ct_nat_to_attr(ct_info, skb)) |
---|
1772 | 1830 | return -EMSGSIZE; |
---|
1773 | 1831 | #endif |
---|
.. | .. |
---|
1785 | 1843 | |
---|
1786 | 1844 | static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info) |
---|
1787 | 1845 | { |
---|
1788 | | - if (ct_info->helper) |
---|
| 1846 | + if (ct_info->helper) { |
---|
| 1847 | +#if IS_ENABLED(CONFIG_NF_NAT) |
---|
| 1848 | + if (ct_info->nat) |
---|
| 1849 | + nf_nat_helper_put(ct_info->helper); |
---|
| 1850 | +#endif |
---|
1789 | 1851 | nf_conntrack_helper_put(ct_info->helper); |
---|
1790 | | - if (ct_info->ct) |
---|
| 1852 | + } |
---|
| 1853 | + if (ct_info->ct) { |
---|
| 1854 | + if (ct_info->timeout[0]) |
---|
| 1855 | + nf_ct_destroy_timeout(ct_info->ct); |
---|
1791 | 1856 | nf_ct_tmpl_free(ct_info->ct); |
---|
| 1857 | + } |
---|
1792 | 1858 | } |
---|
1793 | 1859 | |
---|
1794 | 1860 | #if IS_ENABLED(CONFIG_NETFILTER_CONNCOUNT) |
---|
.. | .. |
---|
1836 | 1902 | struct hlist_head *head = &info->limits[i]; |
---|
1837 | 1903 | struct ovs_ct_limit *ct_limit; |
---|
1838 | 1904 | |
---|
1839 | | - hlist_for_each_entry_rcu(ct_limit, head, hlist_node) |
---|
| 1905 | + hlist_for_each_entry_rcu(ct_limit, head, hlist_node, |
---|
| 1906 | + lockdep_ovsl_is_held()) |
---|
1840 | 1907 | kfree_rcu(ct_limit, rcu); |
---|
1841 | 1908 | } |
---|
1842 | | - kfree(ovs_net->ct_limit_info->limits); |
---|
1843 | | - kfree(ovs_net->ct_limit_info); |
---|
| 1909 | + kfree(info->limits); |
---|
| 1910 | + kfree(info); |
---|
1844 | 1911 | } |
---|
1845 | 1912 | |
---|
1846 | 1913 | static struct sk_buff * |
---|
.. | .. |
---|
1958 | 2025 | static int ovs_ct_limit_get_default_limit(struct ovs_ct_limit_info *info, |
---|
1959 | 2026 | struct sk_buff *reply) |
---|
1960 | 2027 | { |
---|
1961 | | - struct ovs_zone_limit zone_limit; |
---|
1962 | | - int err; |
---|
| 2028 | + struct ovs_zone_limit zone_limit = { |
---|
| 2029 | + .zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE, |
---|
| 2030 | + .limit = info->default_limit, |
---|
| 2031 | + }; |
---|
1963 | 2032 | |
---|
1964 | | - zone_limit.zone_id = OVS_ZONE_LIMIT_DEFAULT_ZONE; |
---|
1965 | | - zone_limit.limit = info->default_limit; |
---|
1966 | | - err = nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); |
---|
1967 | | - if (err) |
---|
1968 | | - return err; |
---|
1969 | | - |
---|
1970 | | - return 0; |
---|
| 2033 | + return nla_put_nohdr(reply, sizeof(zone_limit), &zone_limit); |
---|
1971 | 2034 | } |
---|
1972 | 2035 | |
---|
1973 | 2036 | static int __ovs_ct_limit_get_zone_limit(struct net *net, |
---|
.. | .. |
---|
2141 | 2204 | if (IS_ERR(reply)) |
---|
2142 | 2205 | return PTR_ERR(reply); |
---|
2143 | 2206 | |
---|
2144 | | - nla_reply = nla_nest_start(reply, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); |
---|
| 2207 | + nla_reply = nla_nest_start_noflag(reply, OVS_CT_LIMIT_ATTR_ZONE_LIMIT); |
---|
| 2208 | + if (!nla_reply) { |
---|
| 2209 | + err = -EMSGSIZE; |
---|
| 2210 | + goto exit_err; |
---|
| 2211 | + } |
---|
2145 | 2212 | |
---|
2146 | 2213 | if (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT]) { |
---|
2147 | 2214 | err = ovs_ct_limit_get_zone_limit( |
---|
.. | .. |
---|
2165 | 2232 | return err; |
---|
2166 | 2233 | } |
---|
2167 | 2234 | |
---|
2168 | | -static struct genl_ops ct_limit_genl_ops[] = { |
---|
| 2235 | +static const struct genl_small_ops ct_limit_genl_ops[] = { |
---|
2169 | 2236 | { .cmd = OVS_CT_LIMIT_CMD_SET, |
---|
| 2237 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
---|
2170 | 2238 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN |
---|
2171 | 2239 | * privilege. */ |
---|
2172 | | - .policy = ct_limit_policy, |
---|
2173 | 2240 | .doit = ovs_ct_limit_cmd_set, |
---|
2174 | 2241 | }, |
---|
2175 | 2242 | { .cmd = OVS_CT_LIMIT_CMD_DEL, |
---|
| 2243 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
---|
2176 | 2244 | .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN |
---|
2177 | 2245 | * privilege. */ |
---|
2178 | | - .policy = ct_limit_policy, |
---|
2179 | 2246 | .doit = ovs_ct_limit_cmd_del, |
---|
2180 | 2247 | }, |
---|
2181 | 2248 | { .cmd = OVS_CT_LIMIT_CMD_GET, |
---|
| 2249 | + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, |
---|
2182 | 2250 | .flags = 0, /* OK for unprivileged users. */ |
---|
2183 | | - .policy = ct_limit_policy, |
---|
2184 | 2251 | .doit = ovs_ct_limit_cmd_get, |
---|
2185 | 2252 | }, |
---|
2186 | 2253 | }; |
---|
.. | .. |
---|
2194 | 2261 | .name = OVS_CT_LIMIT_FAMILY, |
---|
2195 | 2262 | .version = OVS_CT_LIMIT_VERSION, |
---|
2196 | 2263 | .maxattr = OVS_CT_LIMIT_ATTR_MAX, |
---|
| 2264 | + .policy = ct_limit_policy, |
---|
2197 | 2265 | .netnsok = true, |
---|
2198 | 2266 | .parallel_ops = true, |
---|
2199 | | - .ops = ct_limit_genl_ops, |
---|
2200 | | - .n_ops = ARRAY_SIZE(ct_limit_genl_ops), |
---|
| 2267 | + .small_ops = ct_limit_genl_ops, |
---|
| 2268 | + .n_small_ops = ARRAY_SIZE(ct_limit_genl_ops), |
---|
2201 | 2269 | .mcgrps = &ovs_ct_limit_multicast_group, |
---|
2202 | 2270 | .n_mcgrps = 1, |
---|
2203 | 2271 | .module = THIS_MODULE, |
---|