diff options
72 files changed, 1595 insertions, 512 deletions
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h index 96afc29184be..f1606fa6132d 100644 --- a/include/linux/netfilter/ipset/ip_set.h +++ b/include/linux/netfilter/ipset/ip_set.h | |||
@@ -57,6 +57,8 @@ enum ip_set_extension { | |||
57 | IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), | 57 | IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER), |
58 | IPSET_EXT_BIT_COMMENT = 2, | 58 | IPSET_EXT_BIT_COMMENT = 2, |
59 | IPSET_EXT_COMMENT = (1 << IPSET_EXT_BIT_COMMENT), | 59 | IPSET_EXT_COMMENT = (1 << IPSET_EXT_BIT_COMMENT), |
60 | IPSET_EXT_BIT_SKBINFO = 3, | ||
61 | IPSET_EXT_SKBINFO = (1 << IPSET_EXT_BIT_SKBINFO), | ||
60 | /* Mark set with an extension which needs to call destroy */ | 62 | /* Mark set with an extension which needs to call destroy */ |
61 | IPSET_EXT_BIT_DESTROY = 7, | 63 | IPSET_EXT_BIT_DESTROY = 7, |
62 | IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY), | 64 | IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY), |
@@ -65,12 +67,14 @@ enum ip_set_extension { | |||
65 | #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) | 67 | #define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT) |
66 | #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) | 68 | #define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER) |
67 | #define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT) | 69 | #define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT) |
70 | #define SET_WITH_SKBINFO(s) ((s)->extensions & IPSET_EXT_SKBINFO) | ||
68 | #define SET_WITH_FORCEADD(s) ((s)->flags & IPSET_CREATE_FLAG_FORCEADD) | 71 | #define SET_WITH_FORCEADD(s) ((s)->flags & IPSET_CREATE_FLAG_FORCEADD) |
69 | 72 | ||
70 | /* Extension id, in size order */ | 73 | /* Extension id, in size order */ |
71 | enum ip_set_ext_id { | 74 | enum ip_set_ext_id { |
72 | IPSET_EXT_ID_COUNTER = 0, | 75 | IPSET_EXT_ID_COUNTER = 0, |
73 | IPSET_EXT_ID_TIMEOUT, | 76 | IPSET_EXT_ID_TIMEOUT, |
77 | IPSET_EXT_ID_SKBINFO, | ||
74 | IPSET_EXT_ID_COMMENT, | 78 | IPSET_EXT_ID_COMMENT, |
75 | IPSET_EXT_ID_MAX, | 79 | IPSET_EXT_ID_MAX, |
76 | }; | 80 | }; |
@@ -92,6 +96,10 @@ struct ip_set_ext { | |||
92 | u64 packets; | 96 | u64 packets; |
93 | u64 bytes; | 97 | u64 bytes; |
94 | u32 timeout; | 98 | u32 timeout; |
99 | u32 skbmark; | ||
100 | u32 skbmarkmask; | ||
101 | u32 skbprio; | ||
102 | u16 skbqueue; | ||
95 | char *comment; | 103 | char *comment; |
96 | }; | 104 | }; |
97 | 105 | ||
@@ -104,6 +112,13 @@ struct ip_set_comment { | |||
104 | char *str; | 112 | char *str; |
105 | }; | 113 | }; |
106 | 114 | ||
115 | struct ip_set_skbinfo { | ||
116 | u32 skbmark; | ||
117 | u32 skbmarkmask; | ||
118 | u32 skbprio; | ||
119 | u16 skbqueue; | ||
120 | }; | ||
121 | |||
107 | struct ip_set; | 122 | struct ip_set; |
108 | 123 | ||
109 | #define ext_timeout(e, s) \ | 124 | #define ext_timeout(e, s) \ |
@@ -112,7 +127,8 @@ struct ip_set; | |||
112 | (struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER]) | 127 | (struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER]) |
113 | #define ext_comment(e, s) \ | 128 | #define ext_comment(e, s) \ |
114 | (struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT]) | 129 | (struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT]) |
115 | 130 | #define ext_skbinfo(e, s) \ | |
131 | (struct ip_set_skbinfo *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_SKBINFO]) | ||
116 | 132 | ||
117 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, | 133 | typedef int (*ipset_adtfn)(struct ip_set *set, void *value, |
118 | const struct ip_set_ext *ext, | 134 | const struct ip_set_ext *ext, |
@@ -256,6 +272,8 @@ ip_set_put_flags(struct sk_buff *skb, struct ip_set *set) | |||
256 | cadt_flags |= IPSET_FLAG_WITH_COUNTERS; | 272 | cadt_flags |= IPSET_FLAG_WITH_COUNTERS; |
257 | if (SET_WITH_COMMENT(set)) | 273 | if (SET_WITH_COMMENT(set)) |
258 | cadt_flags |= IPSET_FLAG_WITH_COMMENT; | 274 | cadt_flags |= IPSET_FLAG_WITH_COMMENT; |
275 | if (SET_WITH_SKBINFO(set)) | ||
276 | cadt_flags |= IPSET_FLAG_WITH_SKBINFO; | ||
259 | if (SET_WITH_FORCEADD(set)) | 277 | if (SET_WITH_FORCEADD(set)) |
260 | cadt_flags |= IPSET_FLAG_WITH_FORCEADD; | 278 | cadt_flags |= IPSET_FLAG_WITH_FORCEADD; |
261 | 279 | ||
@@ -304,6 +322,43 @@ ip_set_update_counter(struct ip_set_counter *counter, | |||
304 | } | 322 | } |
305 | } | 323 | } |
306 | 324 | ||
325 | static inline void | ||
326 | ip_set_get_skbinfo(struct ip_set_skbinfo *skbinfo, | ||
327 | const struct ip_set_ext *ext, | ||
328 | struct ip_set_ext *mext, u32 flags) | ||
329 | { | ||
330 | mext->skbmark = skbinfo->skbmark; | ||
331 | mext->skbmarkmask = skbinfo->skbmarkmask; | ||
332 | mext->skbprio = skbinfo->skbprio; | ||
333 | mext->skbqueue = skbinfo->skbqueue; | ||
334 | } | ||
335 | static inline bool | ||
336 | ip_set_put_skbinfo(struct sk_buff *skb, struct ip_set_skbinfo *skbinfo) | ||
337 | { | ||
338 | /* Send nonzero parameters only */ | ||
339 | return ((skbinfo->skbmark || skbinfo->skbmarkmask) && | ||
340 | nla_put_net64(skb, IPSET_ATTR_SKBMARK, | ||
341 | cpu_to_be64((u64)skbinfo->skbmark << 32 | | ||
342 | skbinfo->skbmarkmask))) || | ||
343 | (skbinfo->skbprio && | ||
344 | nla_put_net32(skb, IPSET_ATTR_SKBPRIO, | ||
345 | cpu_to_be32(skbinfo->skbprio))) || | ||
346 | (skbinfo->skbqueue && | ||
347 | nla_put_net16(skb, IPSET_ATTR_SKBQUEUE, | ||
348 | cpu_to_be16(skbinfo->skbqueue))); | ||
349 | |||
350 | } | ||
351 | |||
352 | static inline void | ||
353 | ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo, | ||
354 | const struct ip_set_ext *ext) | ||
355 | { | ||
356 | skbinfo->skbmark = ext->skbmark; | ||
357 | skbinfo->skbmarkmask = ext->skbmarkmask; | ||
358 | skbinfo->skbprio = ext->skbprio; | ||
359 | skbinfo->skbqueue = ext->skbqueue; | ||
360 | } | ||
361 | |||
307 | static inline bool | 362 | static inline bool |
308 | ip_set_put_counter(struct sk_buff *skb, struct ip_set_counter *counter) | 363 | ip_set_put_counter(struct sk_buff *skb, struct ip_set_counter *counter) |
309 | { | 364 | { |
@@ -497,6 +552,9 @@ ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set, | |||
497 | if (SET_WITH_COMMENT(set) && | 552 | if (SET_WITH_COMMENT(set) && |
498 | ip_set_put_comment(skb, ext_comment(e, set))) | 553 | ip_set_put_comment(skb, ext_comment(e, set))) |
499 | return -EMSGSIZE; | 554 | return -EMSGSIZE; |
555 | if (SET_WITH_SKBINFO(set) && | ||
556 | ip_set_put_skbinfo(skb, ext_skbinfo(e, set))) | ||
557 | return -EMSGSIZE; | ||
500 | return 0; | 558 | return 0; |
501 | } | 559 | } |
502 | 560 | ||
diff --git a/include/linux/netfilter_bridge.h b/include/linux/netfilter_bridge.h index 8ab1c278b66d..c755e4971fa3 100644 --- a/include/linux/netfilter_bridge.h +++ b/include/linux/netfilter_bridge.h | |||
@@ -15,7 +15,7 @@ enum nf_br_hook_priorities { | |||
15 | NF_BR_PRI_LAST = INT_MAX, | 15 | NF_BR_PRI_LAST = INT_MAX, |
16 | }; | 16 | }; |
17 | 17 | ||
18 | #ifdef CONFIG_BRIDGE_NETFILTER | 18 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
19 | 19 | ||
20 | #define BRNF_PKT_TYPE 0x01 | 20 | #define BRNF_PKT_TYPE 0x01 |
21 | #define BRNF_BRIDGED_DNAT 0x02 | 21 | #define BRNF_BRIDGED_DNAT 0x02 |
@@ -24,16 +24,6 @@ enum nf_br_hook_priorities { | |||
24 | #define BRNF_8021Q 0x10 | 24 | #define BRNF_8021Q 0x10 |
25 | #define BRNF_PPPoE 0x20 | 25 | #define BRNF_PPPoE 0x20 |
26 | 26 | ||
27 | /* Only used in br_forward.c */ | ||
28 | int nf_bridge_copy_header(struct sk_buff *skb); | ||
29 | static inline int nf_bridge_maybe_copy_header(struct sk_buff *skb) | ||
30 | { | ||
31 | if (skb->nf_bridge && | ||
32 | skb->nf_bridge->mask & (BRNF_BRIDGED | BRNF_BRIDGED_DNAT)) | ||
33 | return nf_bridge_copy_header(skb); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) | 27 | static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) |
38 | { | 28 | { |
39 | switch (skb->protocol) { | 29 | switch (skb->protocol) { |
@@ -46,6 +36,44 @@ static inline unsigned int nf_bridge_encap_header_len(const struct sk_buff *skb) | |||
46 | } | 36 | } |
47 | } | 37 | } |
48 | 38 | ||
39 | static inline void nf_bridge_update_protocol(struct sk_buff *skb) | ||
40 | { | ||
41 | if (skb->nf_bridge->mask & BRNF_8021Q) | ||
42 | skb->protocol = htons(ETH_P_8021Q); | ||
43 | else if (skb->nf_bridge->mask & BRNF_PPPoE) | ||
44 | skb->protocol = htons(ETH_P_PPP_SES); | ||
45 | } | ||
46 | |||
47 | /* Fill in the header for fragmented IP packets handled by | ||
48 | * the IPv4 connection tracking code. | ||
49 | * | ||
50 | * Only used in br_forward.c | ||
51 | */ | ||
52 | static inline int nf_bridge_copy_header(struct sk_buff *skb) | ||
53 | { | ||
54 | int err; | ||
55 | unsigned int header_size; | ||
56 | |||
57 | nf_bridge_update_protocol(skb); | ||
58 | header_size = ETH_HLEN + nf_bridge_encap_header_len(skb); | ||
59 | err = skb_cow_head(skb, header_size); | ||
60 | if (err) | ||
61 | return err; | ||
62 | |||
63 | skb_copy_to_linear_data_offset(skb, -header_size, | ||
64 | skb->nf_bridge->data, header_size); | ||
65 | __skb_push(skb, nf_bridge_encap_header_len(skb)); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline int nf_bridge_maybe_copy_header(struct sk_buff *skb) | ||
70 | { | ||
71 | if (skb->nf_bridge && | ||
72 | skb->nf_bridge->mask & (BRNF_BRIDGED | BRNF_BRIDGED_DNAT)) | ||
73 | return nf_bridge_copy_header(skb); | ||
74 | return 0; | ||
75 | } | ||
76 | |||
49 | static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb) | 77 | static inline unsigned int nf_bridge_mtu_reduction(const struct sk_buff *skb) |
50 | { | 78 | { |
51 | if (unlikely(skb->nf_bridge->mask & BRNF_PPPoE)) | 79 | if (unlikely(skb->nf_bridge->mask & BRNF_PPPoE)) |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b6cced304b26..262efdbc346b 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -156,7 +156,7 @@ struct nf_conntrack { | |||
156 | }; | 156 | }; |
157 | #endif | 157 | #endif |
158 | 158 | ||
159 | #ifdef CONFIG_BRIDGE_NETFILTER | 159 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
160 | struct nf_bridge_info { | 160 | struct nf_bridge_info { |
161 | atomic_t use; | 161 | atomic_t use; |
162 | unsigned int mask; | 162 | unsigned int mask; |
@@ -534,7 +534,7 @@ struct sk_buff { | |||
534 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 534 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
535 | struct nf_conntrack *nfct; | 535 | struct nf_conntrack *nfct; |
536 | #endif | 536 | #endif |
537 | #ifdef CONFIG_BRIDGE_NETFILTER | 537 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
538 | struct nf_bridge_info *nf_bridge; | 538 | struct nf_bridge_info *nf_bridge; |
539 | #endif | 539 | #endif |
540 | unsigned int len, | 540 | unsigned int len, |
@@ -556,8 +556,6 @@ struct sk_buff { | |||
556 | /* one bit hole */ | 556 | /* one bit hole */ |
557 | kmemcheck_bitfield_end(flags1); | 557 | kmemcheck_bitfield_end(flags1); |
558 | 558 | ||
559 | |||
560 | |||
561 | /* fields enclosed in headers_start/headers_end are copied | 559 | /* fields enclosed in headers_start/headers_end are copied |
562 | * using a single memcpy() in __copy_skb_header() | 560 | * using a single memcpy() in __copy_skb_header() |
563 | */ | 561 | */ |
@@ -3016,7 +3014,7 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct) | |||
3016 | atomic_inc(&nfct->use); | 3014 | atomic_inc(&nfct->use); |
3017 | } | 3015 | } |
3018 | #endif | 3016 | #endif |
3019 | #ifdef CONFIG_BRIDGE_NETFILTER | 3017 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
3020 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) | 3018 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) |
3021 | { | 3019 | { |
3022 | if (nf_bridge && atomic_dec_and_test(&nf_bridge->use)) | 3020 | if (nf_bridge && atomic_dec_and_test(&nf_bridge->use)) |
@@ -3034,7 +3032,7 @@ static inline void nf_reset(struct sk_buff *skb) | |||
3034 | nf_conntrack_put(skb->nfct); | 3032 | nf_conntrack_put(skb->nfct); |
3035 | skb->nfct = NULL; | 3033 | skb->nfct = NULL; |
3036 | #endif | 3034 | #endif |
3037 | #ifdef CONFIG_BRIDGE_NETFILTER | 3035 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
3038 | nf_bridge_put(skb->nf_bridge); | 3036 | nf_bridge_put(skb->nf_bridge); |
3039 | skb->nf_bridge = NULL; | 3037 | skb->nf_bridge = NULL; |
3040 | #endif | 3038 | #endif |
@@ -3057,7 +3055,7 @@ static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src, | |||
3057 | if (copy) | 3055 | if (copy) |
3058 | dst->nfctinfo = src->nfctinfo; | 3056 | dst->nfctinfo = src->nfctinfo; |
3059 | #endif | 3057 | #endif |
3060 | #ifdef CONFIG_BRIDGE_NETFILTER | 3058 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
3061 | dst->nf_bridge = src->nf_bridge; | 3059 | dst->nf_bridge = src->nf_bridge; |
3062 | nf_bridge_get(src->nf_bridge); | 3060 | nf_bridge_get(src->nf_bridge); |
3063 | #endif | 3061 | #endif |
@@ -3072,7 +3070,7 @@ static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src) | |||
3072 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) | 3070 | #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) |
3073 | nf_conntrack_put(dst->nfct); | 3071 | nf_conntrack_put(dst->nfct); |
3074 | #endif | 3072 | #endif |
3075 | #ifdef CONFIG_BRIDGE_NETFILTER | 3073 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
3076 | nf_bridge_put(dst->nf_bridge); | 3074 | nf_bridge_put(dst->nf_bridge); |
3077 | #endif | 3075 | #endif |
3078 | __nf_copy(dst, src, true); | 3076 | __nf_copy(dst, src, true); |
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 624a8a54806d..576d7f0bed5d 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h | |||
@@ -535,6 +535,7 @@ struct ip_vs_conn { | |||
535 | union nf_inet_addr daddr; /* destination address */ | 535 | union nf_inet_addr daddr; /* destination address */ |
536 | volatile __u32 flags; /* status flags */ | 536 | volatile __u32 flags; /* status flags */ |
537 | __u16 protocol; /* Which protocol (TCP/UDP) */ | 537 | __u16 protocol; /* Which protocol (TCP/UDP) */ |
538 | __u16 daf; /* Address family of the dest */ | ||
538 | #ifdef CONFIG_NET_NS | 539 | #ifdef CONFIG_NET_NS |
539 | struct net *net; /* Name space */ | 540 | struct net *net; /* Name space */ |
540 | #endif | 541 | #endif |
@@ -648,6 +649,9 @@ struct ip_vs_dest_user_kern { | |||
648 | /* thresholds for active connections */ | 649 | /* thresholds for active connections */ |
649 | u32 u_threshold; /* upper threshold */ | 650 | u32 u_threshold; /* upper threshold */ |
650 | u32 l_threshold; /* lower threshold */ | 651 | u32 l_threshold; /* lower threshold */ |
652 | |||
653 | /* Address family of addr */ | ||
654 | u16 af; | ||
651 | }; | 655 | }; |
652 | 656 | ||
653 | 657 | ||
@@ -986,6 +990,10 @@ struct netns_ipvs { | |||
986 | char backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; | 990 | char backup_mcast_ifn[IP_VS_IFNAME_MAXLEN]; |
987 | /* net name space ptr */ | 991 | /* net name space ptr */ |
988 | struct net *net; /* Needed by timer routines */ | 992 | struct net *net; /* Needed by timer routines */ |
993 | /* Number of heterogeneous destinations, needed because | ||
994 | * heterogeneous are not supported when synchronization is | ||
995 | * enabled */ | ||
996 | unsigned int mixed_address_family_dests; | ||
989 | }; | 997 | }; |
990 | 998 | ||
991 | #define DEFAULT_SYNC_THRESHOLD 3 | 999 | #define DEFAULT_SYNC_THRESHOLD 3 |
@@ -1210,7 +1218,7 @@ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp) | |||
1210 | void ip_vs_conn_put(struct ip_vs_conn *cp); | 1218 | void ip_vs_conn_put(struct ip_vs_conn *cp); |
1211 | void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport); | 1219 | void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport); |
1212 | 1220 | ||
1213 | struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p, | 1221 | struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af, |
1214 | const union nf_inet_addr *daddr, | 1222 | const union nf_inet_addr *daddr, |
1215 | __be16 dport, unsigned int flags, | 1223 | __be16 dport, unsigned int flags, |
1216 | struct ip_vs_dest *dest, __u32 fwmark); | 1224 | struct ip_vs_dest *dest, __u32 fwmark); |
@@ -1396,8 +1404,9 @@ void ip_vs_unregister_nl_ioctl(void); | |||
1396 | int ip_vs_control_init(void); | 1404 | int ip_vs_control_init(void); |
1397 | void ip_vs_control_cleanup(void); | 1405 | void ip_vs_control_cleanup(void); |
1398 | struct ip_vs_dest * | 1406 | struct ip_vs_dest * |
1399 | ip_vs_find_dest(struct net *net, int af, const union nf_inet_addr *daddr, | 1407 | ip_vs_find_dest(struct net *net, int svc_af, int dest_af, |
1400 | __be16 dport, const union nf_inet_addr *vaddr, __be16 vport, | 1408 | const union nf_inet_addr *daddr, __be16 dport, |
1409 | const union nf_inet_addr *vaddr, __be16 vport, | ||
1401 | __u16 protocol, __u32 fwmark, __u32 flags); | 1410 | __u16 protocol, __u32 fwmark, __u32 flags); |
1402 | void ip_vs_try_bind_dest(struct ip_vs_conn *cp); | 1411 | void ip_vs_try_bind_dest(struct ip_vs_conn *cp); |
1403 | 1412 | ||
diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 47f425464f84..f60558d0254c 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h | |||
@@ -373,7 +373,7 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | |||
373 | return 0; | 373 | return 0; |
374 | } | 374 | } |
375 | 375 | ||
376 | #ifdef CONFIG_BRIDGE_NETFILTER | 376 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
377 | static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) | 377 | static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) |
378 | { | 378 | { |
379 | unsigned int seq, hh_alen; | 379 | unsigned int seq, hh_alen; |
diff --git a/include/net/netfilter/ipv4/nf_reject.h b/include/net/netfilter/ipv4/nf_reject.h index 931fbf812171..f713b5a31d62 100644 --- a/include/net/netfilter/ipv4/nf_reject.h +++ b/include/net/netfilter/ipv4/nf_reject.h | |||
@@ -98,7 +98,7 @@ static void nf_send_reset(struct sk_buff *oldskb, int hook) | |||
98 | 98 | ||
99 | nf_ct_attach(nskb, oldskb); | 99 | nf_ct_attach(nskb, oldskb); |
100 | 100 | ||
101 | #ifdef CONFIG_BRIDGE_NETFILTER | 101 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
102 | /* If we use ip_local_out for bridged traffic, the MAC source on | 102 | /* If we use ip_local_out for bridged traffic, the MAC source on |
103 | * the RST will be ours, instead of the destination's. This confuses | 103 | * the RST will be ours, instead of the destination's. This confuses |
104 | * some routers/firewalls, and they drop the packet. So we need to | 104 | * some routers/firewalls, and they drop the packet. So we need to |
diff --git a/include/net/netfilter/ipv6/nf_reject.h b/include/net/netfilter/ipv6/nf_reject.h index 710d17ed70b4..7a10cfcd8e33 100644 --- a/include/net/netfilter/ipv6/nf_reject.h +++ b/include/net/netfilter/ipv6/nf_reject.h | |||
@@ -147,7 +147,7 @@ static void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) | |||
147 | 147 | ||
148 | nf_ct_attach(nskb, oldskb); | 148 | nf_ct_attach(nskb, oldskb); |
149 | 149 | ||
150 | #ifdef CONFIG_BRIDGE_NETFILTER | 150 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
151 | /* If we use ip6_local_out for bridged traffic, the MAC source on | 151 | /* If we use ip6_local_out for bridged traffic, the MAC source on |
152 | * the RST will be ours, instead of the destination's. This confuses | 152 | * the RST will be ours, instead of the destination's. This confuses |
153 | * some routers/firewalls, and they drop the packet. So we need to | 153 | * some routers/firewalls, and they drop the packet. So we need to |
diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index a71dd333ac68..344b1ab19220 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h | |||
@@ -32,10 +32,8 @@ struct nf_conn_nat { | |||
32 | struct hlist_node bysource; | 32 | struct hlist_node bysource; |
33 | struct nf_conn *ct; | 33 | struct nf_conn *ct; |
34 | union nf_conntrack_nat_help help; | 34 | union nf_conntrack_nat_help help; |
35 | #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | 35 | #if IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV4) || \ |
36 | defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) || \ | 36 | IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV6) |
37 | defined(CONFIG_IP6_NF_TARGET_MASQUERADE) || \ | ||
38 | defined(CONFIG_IP6_NF_TARGET_MASQUERADE_MODULE) | ||
39 | int masq_index; | 37 | int masq_index; |
40 | #endif | 38 | #endif |
41 | }; | 39 | }; |
@@ -68,8 +66,8 @@ static inline bool nf_nat_oif_changed(unsigned int hooknum, | |||
68 | struct nf_conn_nat *nat, | 66 | struct nf_conn_nat *nat, |
69 | const struct net_device *out) | 67 | const struct net_device *out) |
70 | { | 68 | { |
71 | #if IS_ENABLED(CONFIG_IP_NF_TARGET_MASQUERADE) || \ | 69 | #if IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV4) || \ |
72 | IS_ENABLED(CONFIG_IP6_NF_TARGET_MASQUERADE) | 70 | IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV6) |
73 | return nat->masq_index && hooknum == NF_INET_POST_ROUTING && | 71 | return nat->masq_index && hooknum == NF_INET_POST_ROUTING && |
74 | CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && | 72 | CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && |
75 | nat->masq_index != out->ifindex; | 73 | nat->masq_index != out->ifindex; |
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index c4d86198d3d6..3d7292392fac 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
@@ -241,6 +241,7 @@ void nft_unregister_set(struct nft_set_ops *ops); | |||
241 | * @dtype: data type (verdict or numeric type defined by userspace) | 241 | * @dtype: data type (verdict or numeric type defined by userspace) |
242 | * @size: maximum set size | 242 | * @size: maximum set size |
243 | * @nelems: number of elements | 243 | * @nelems: number of elements |
244 | * @policy: set parameterization (see enum nft_set_policies) | ||
244 | * @ops: set ops | 245 | * @ops: set ops |
245 | * @flags: set flags | 246 | * @flags: set flags |
246 | * @klen: key length | 247 | * @klen: key length |
@@ -255,6 +256,7 @@ struct nft_set { | |||
255 | u32 dtype; | 256 | u32 dtype; |
256 | u32 size; | 257 | u32 size; |
257 | u32 nelems; | 258 | u32 nelems; |
259 | u16 policy; | ||
258 | /* runtime data below here */ | 260 | /* runtime data below here */ |
259 | const struct nft_set_ops *ops ____cacheline_aligned; | 261 | const struct nft_set_ops *ops ____cacheline_aligned; |
260 | u16 flags; | 262 | u16 flags; |
diff --git a/include/uapi/linux/ip_vs.h b/include/uapi/linux/ip_vs.h index fbcffe8041f7..cabe95d5b461 100644 --- a/include/uapi/linux/ip_vs.h +++ b/include/uapi/linux/ip_vs.h | |||
@@ -384,6 +384,9 @@ enum { | |||
384 | IPVS_DEST_ATTR_PERSIST_CONNS, /* persistent connections */ | 384 | IPVS_DEST_ATTR_PERSIST_CONNS, /* persistent connections */ |
385 | 385 | ||
386 | IPVS_DEST_ATTR_STATS, /* nested attribute for dest stats */ | 386 | IPVS_DEST_ATTR_STATS, /* nested attribute for dest stats */ |
387 | |||
388 | IPVS_DEST_ATTR_ADDR_FAMILY, /* Address family of address */ | ||
389 | |||
387 | __IPVS_DEST_ATTR_MAX, | 390 | __IPVS_DEST_ATTR_MAX, |
388 | }; | 391 | }; |
389 | 392 | ||
diff --git a/include/uapi/linux/netfilter/ipset/ip_set.h b/include/uapi/linux/netfilter/ipset/ip_set.h index 78c2f2e79920..ca03119111a2 100644 --- a/include/uapi/linux/netfilter/ipset/ip_set.h +++ b/include/uapi/linux/netfilter/ipset/ip_set.h | |||
@@ -115,6 +115,9 @@ enum { | |||
115 | IPSET_ATTR_BYTES, | 115 | IPSET_ATTR_BYTES, |
116 | IPSET_ATTR_PACKETS, | 116 | IPSET_ATTR_PACKETS, |
117 | IPSET_ATTR_COMMENT, | 117 | IPSET_ATTR_COMMENT, |
118 | IPSET_ATTR_SKBMARK, | ||
119 | IPSET_ATTR_SKBPRIO, | ||
120 | IPSET_ATTR_SKBQUEUE, | ||
118 | __IPSET_ATTR_ADT_MAX, | 121 | __IPSET_ATTR_ADT_MAX, |
119 | }; | 122 | }; |
120 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) | 123 | #define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1) |
@@ -147,6 +150,7 @@ enum ipset_errno { | |||
147 | IPSET_ERR_COUNTER, | 150 | IPSET_ERR_COUNTER, |
148 | IPSET_ERR_COMMENT, | 151 | IPSET_ERR_COMMENT, |
149 | IPSET_ERR_INVALID_MARKMASK, | 152 | IPSET_ERR_INVALID_MARKMASK, |
153 | IPSET_ERR_SKBINFO, | ||
150 | 154 | ||
151 | /* Type specific error codes */ | 155 | /* Type specific error codes */ |
152 | IPSET_ERR_TYPE_SPECIFIC = 4352, | 156 | IPSET_ERR_TYPE_SPECIFIC = 4352, |
@@ -170,6 +174,12 @@ enum ipset_cmd_flags { | |||
170 | IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS), | 174 | IPSET_FLAG_MATCH_COUNTERS = (1 << IPSET_FLAG_BIT_MATCH_COUNTERS), |
171 | IPSET_FLAG_BIT_RETURN_NOMATCH = 7, | 175 | IPSET_FLAG_BIT_RETURN_NOMATCH = 7, |
172 | IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH), | 176 | IPSET_FLAG_RETURN_NOMATCH = (1 << IPSET_FLAG_BIT_RETURN_NOMATCH), |
177 | IPSET_FLAG_BIT_MAP_SKBMARK = 8, | ||
178 | IPSET_FLAG_MAP_SKBMARK = (1 << IPSET_FLAG_BIT_MAP_SKBMARK), | ||
179 | IPSET_FLAG_BIT_MAP_SKBPRIO = 9, | ||
180 | IPSET_FLAG_MAP_SKBPRIO = (1 << IPSET_FLAG_BIT_MAP_SKBPRIO), | ||
181 | IPSET_FLAG_BIT_MAP_SKBQUEUE = 10, | ||
182 | IPSET_FLAG_MAP_SKBQUEUE = (1 << IPSET_FLAG_BIT_MAP_SKBQUEUE), | ||
173 | IPSET_FLAG_CMD_MAX = 15, | 183 | IPSET_FLAG_CMD_MAX = 15, |
174 | }; | 184 | }; |
175 | 185 | ||
@@ -187,6 +197,8 @@ enum ipset_cadt_flags { | |||
187 | IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT), | 197 | IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT), |
188 | IPSET_FLAG_BIT_WITH_FORCEADD = 5, | 198 | IPSET_FLAG_BIT_WITH_FORCEADD = 5, |
189 | IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD), | 199 | IPSET_FLAG_WITH_FORCEADD = (1 << IPSET_FLAG_BIT_WITH_FORCEADD), |
200 | IPSET_FLAG_BIT_WITH_SKBINFO = 6, | ||
201 | IPSET_FLAG_WITH_SKBINFO = (1 << IPSET_FLAG_BIT_WITH_SKBINFO), | ||
190 | IPSET_FLAG_CADT_MAX = 15, | 202 | IPSET_FLAG_CADT_MAX = 15, |
191 | }; | 203 | }; |
192 | 204 | ||
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index eeec0ae845ef..b72ccfeaf865 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h | |||
@@ -51,6 +51,8 @@ enum nft_verdicts { | |||
51 | * @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes) | 51 | * @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes) |
52 | * @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes) | 52 | * @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes) |
53 | * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes) | 53 | * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes) |
54 | * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes) | ||
55 | * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes) | ||
54 | */ | 56 | */ |
55 | enum nf_tables_msg_types { | 57 | enum nf_tables_msg_types { |
56 | NFT_MSG_NEWTABLE, | 58 | NFT_MSG_NEWTABLE, |
@@ -68,6 +70,8 @@ enum nf_tables_msg_types { | |||
68 | NFT_MSG_NEWSETELEM, | 70 | NFT_MSG_NEWSETELEM, |
69 | NFT_MSG_GETSETELEM, | 71 | NFT_MSG_GETSETELEM, |
70 | NFT_MSG_DELSETELEM, | 72 | NFT_MSG_DELSETELEM, |
73 | NFT_MSG_NEWGEN, | ||
74 | NFT_MSG_GETGEN, | ||
71 | NFT_MSG_MAX, | 75 | NFT_MSG_MAX, |
72 | }; | 76 | }; |
73 | 77 | ||
@@ -806,9 +810,22 @@ enum nft_nat_attributes { | |||
806 | * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) | 810 | * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) |
807 | */ | 811 | */ |
808 | enum nft_masq_attributes { | 812 | enum nft_masq_attributes { |
813 | NFTA_MASQ_UNSPEC, | ||
809 | NFTA_MASQ_FLAGS, | 814 | NFTA_MASQ_FLAGS, |
810 | __NFTA_MASQ_MAX | 815 | __NFTA_MASQ_MAX |
811 | }; | 816 | }; |
812 | #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) | 817 | #define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) |
813 | 818 | ||
819 | /** | ||
820 | * enum nft_gen_attributes - nf_tables ruleset generation attributes | ||
821 | * | ||
822 | * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32) | ||
823 | */ | ||
824 | enum nft_gen_attributes { | ||
825 | NFTA_GEN_UNSPEC, | ||
826 | NFTA_GEN_ID, | ||
827 | __NFTA_GEN_MAX | ||
828 | }; | ||
829 | #define NFTA_GEN_MAX (__NFTA_GEN_MAX - 1) | ||
830 | |||
814 | #endif /* _LINUX_NF_TABLES_H */ | 831 | #endif /* _LINUX_NF_TABLES_H */ |
diff --git a/include/uapi/linux/netfilter/xt_set.h b/include/uapi/linux/netfilter/xt_set.h index 964d3d42f874..d6a1df1f2947 100644 --- a/include/uapi/linux/netfilter/xt_set.h +++ b/include/uapi/linux/netfilter/xt_set.h | |||
@@ -71,4 +71,14 @@ struct xt_set_info_match_v3 { | |||
71 | __u32 flags; | 71 | __u32 flags; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* Revision 3 target */ | ||
75 | |||
76 | struct xt_set_info_target_v3 { | ||
77 | struct xt_set_info add_set; | ||
78 | struct xt_set_info del_set; | ||
79 | struct xt_set_info map_set; | ||
80 | __u32 flags; | ||
81 | __u32 timeout; | ||
82 | }; | ||
83 | |||
74 | #endif /*_XT_SET_H*/ | 84 | #endif /*_XT_SET_H*/ |
diff --git a/net/Kconfig b/net/Kconfig index 4051fdfa4367..dc5d700d05e7 100644 --- a/net/Kconfig +++ b/net/Kconfig | |||
@@ -176,10 +176,11 @@ config NETFILTER_ADVANCED | |||
176 | If unsure, say Y. | 176 | If unsure, say Y. |
177 | 177 | ||
178 | config BRIDGE_NETFILTER | 178 | config BRIDGE_NETFILTER |
179 | bool "Bridged IP/ARP packets filtering" | 179 | tristate "Bridged IP/ARP packets filtering" |
180 | depends on BRIDGE && NETFILTER && INET | 180 | depends on (BRIDGE || BRIDGE=n) |
181 | depends on NETFILTER && INET | ||
181 | depends on NETFILTER_ADVANCED | 182 | depends on NETFILTER_ADVANCED |
182 | default y | 183 | default m |
183 | ---help--- | 184 | ---help--- |
184 | Enabling this option will let arptables resp. iptables see bridged | 185 | Enabling this option will let arptables resp. iptables see bridged |
185 | ARP resp. IP traffic. If you want a bridging firewall, you probably | 186 | ARP resp. IP traffic. If you want a bridging firewall, you probably |
diff --git a/net/bridge/Makefile b/net/bridge/Makefile index 8590b942bffa..5e3eac5dc8b9 100644 --- a/net/bridge/Makefile +++ b/net/bridge/Makefile | |||
@@ -6,11 +6,12 @@ obj-$(CONFIG_BRIDGE) += bridge.o | |||
6 | 6 | ||
7 | bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ | 7 | bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \ |
8 | br_ioctl.o br_stp.o br_stp_bpdu.o \ | 8 | br_ioctl.o br_stp.o br_stp_bpdu.o \ |
9 | br_stp_if.o br_stp_timer.o br_netlink.o | 9 | br_stp_if.o br_stp_timer.o br_netlink.o \ |
10 | br_nf_core.o | ||
10 | 11 | ||
11 | bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o | 12 | bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o |
12 | 13 | ||
13 | bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o | 14 | obj-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o |
14 | 15 | ||
15 | bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o | 16 | bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o br_mdb.o |
16 | 17 | ||
diff --git a/net/bridge/br.c b/net/bridge/br.c index 1a755a1e5410..44425aff7cba 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c | |||
@@ -161,7 +161,7 @@ static int __init br_init(void) | |||
161 | if (err) | 161 | if (err) |
162 | goto err_out1; | 162 | goto err_out1; |
163 | 163 | ||
164 | err = br_netfilter_init(); | 164 | err = br_nf_core_init(); |
165 | if (err) | 165 | if (err) |
166 | goto err_out2; | 166 | goto err_out2; |
167 | 167 | ||
@@ -179,11 +179,16 @@ static int __init br_init(void) | |||
179 | br_fdb_test_addr_hook = br_fdb_test_addr; | 179 | br_fdb_test_addr_hook = br_fdb_test_addr; |
180 | #endif | 180 | #endif |
181 | 181 | ||
182 | pr_info("bridge: automatic filtering via arp/ip/ip6tables has been " | ||
183 | "deprecated. Update your scripts to load br_netfilter if you " | ||
184 | "need this.\n"); | ||
185 | |||
182 | return 0; | 186 | return 0; |
187 | |||
183 | err_out4: | 188 | err_out4: |
184 | unregister_netdevice_notifier(&br_device_notifier); | 189 | unregister_netdevice_notifier(&br_device_notifier); |
185 | err_out3: | 190 | err_out3: |
186 | br_netfilter_fini(); | 191 | br_nf_core_fini(); |
187 | err_out2: | 192 | err_out2: |
188 | unregister_pernet_subsys(&br_net_ops); | 193 | unregister_pernet_subsys(&br_net_ops); |
189 | err_out1: | 194 | err_out1: |
@@ -196,20 +201,17 @@ err_out: | |||
196 | static void __exit br_deinit(void) | 201 | static void __exit br_deinit(void) |
197 | { | 202 | { |
198 | stp_proto_unregister(&br_stp_proto); | 203 | stp_proto_unregister(&br_stp_proto); |
199 | |||
200 | br_netlink_fini(); | 204 | br_netlink_fini(); |
201 | unregister_netdevice_notifier(&br_device_notifier); | 205 | unregister_netdevice_notifier(&br_device_notifier); |
202 | brioctl_set(NULL); | 206 | brioctl_set(NULL); |
203 | |||
204 | unregister_pernet_subsys(&br_net_ops); | 207 | unregister_pernet_subsys(&br_net_ops); |
205 | 208 | ||
206 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 209 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
207 | 210 | ||
208 | br_netfilter_fini(); | 211 | br_nf_core_fini(); |
209 | #if IS_ENABLED(CONFIG_ATM_LANE) | 212 | #if IS_ENABLED(CONFIG_ATM_LANE) |
210 | br_fdb_test_addr_hook = NULL; | 213 | br_fdb_test_addr_hook = NULL; |
211 | #endif | 214 | #endif |
212 | |||
213 | br_fdb_fini(); | 215 | br_fdb_fini(); |
214 | } | 216 | } |
215 | 217 | ||
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 568cccd39a3d..659cac15c0df 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c | |||
@@ -36,7 +36,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) | |||
36 | u16 vid = 0; | 36 | u16 vid = 0; |
37 | 37 | ||
38 | rcu_read_lock(); | 38 | rcu_read_lock(); |
39 | #ifdef CONFIG_BRIDGE_NETFILTER | 39 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
40 | if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) { | 40 | if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) { |
41 | br_nf_pre_routing_finish_bridge_slow(skb); | 41 | br_nf_pre_routing_finish_bridge_slow(skb); |
42 | rcu_read_unlock(); | 42 | rcu_read_unlock(); |
@@ -167,7 +167,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu) | |||
167 | 167 | ||
168 | dev->mtu = new_mtu; | 168 | dev->mtu = new_mtu; |
169 | 169 | ||
170 | #ifdef CONFIG_BRIDGE_NETFILTER | 170 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
171 | /* remember the MTU in the rtable for PMTU */ | 171 | /* remember the MTU in the rtable for PMTU */ |
172 | dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); | 172 | dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu); |
173 | #endif | 173 | #endif |
diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 056b67b0e277..992ec49a96aa 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c | |||
@@ -49,6 +49,7 @@ int br_dev_queue_push_xmit(struct sk_buff *skb) | |||
49 | 49 | ||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | EXPORT_SYMBOL_GPL(br_dev_queue_push_xmit); | ||
52 | 53 | ||
53 | int br_forward_finish(struct sk_buff *skb) | 54 | int br_forward_finish(struct sk_buff *skb) |
54 | { | 55 | { |
@@ -56,6 +57,7 @@ int br_forward_finish(struct sk_buff *skb) | |||
56 | br_dev_queue_push_xmit); | 57 | br_dev_queue_push_xmit); |
57 | 58 | ||
58 | } | 59 | } |
60 | EXPORT_SYMBOL_GPL(br_forward_finish); | ||
59 | 61 | ||
60 | static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) | 62 | static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb) |
61 | { | 63 | { |
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 366c43649079..6fd5522df696 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c | |||
@@ -140,6 +140,7 @@ drop: | |||
140 | kfree_skb(skb); | 140 | kfree_skb(skb); |
141 | goto out; | 141 | goto out; |
142 | } | 142 | } |
143 | EXPORT_SYMBOL_GPL(br_handle_frame_finish); | ||
143 | 144 | ||
144 | /* note: already called with rcu_read_lock */ | 145 | /* note: already called with rcu_read_lock */ |
145 | static int br_handle_local_finish(struct sk_buff *skb) | 146 | static int br_handle_local_finish(struct sk_buff *skb) |
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index a615264cf01a..97e43937aaca 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c | |||
@@ -111,66 +111,6 @@ static inline __be16 pppoe_proto(const struct sk_buff *skb) | |||
111 | pppoe_proto(skb) == htons(PPP_IPV6) && \ | 111 | pppoe_proto(skb) == htons(PPP_IPV6) && \ |
112 | brnf_filter_pppoe_tagged) | 112 | brnf_filter_pppoe_tagged) |
113 | 113 | ||
114 | static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk, | ||
115 | struct sk_buff *skb, u32 mtu) | ||
116 | { | ||
117 | } | ||
118 | |||
119 | static void fake_redirect(struct dst_entry *dst, struct sock *sk, | ||
120 | struct sk_buff *skb) | ||
121 | { | ||
122 | } | ||
123 | |||
124 | static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old) | ||
125 | { | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst, | ||
130 | struct sk_buff *skb, | ||
131 | const void *daddr) | ||
132 | { | ||
133 | return NULL; | ||
134 | } | ||
135 | |||
136 | static unsigned int fake_mtu(const struct dst_entry *dst) | ||
137 | { | ||
138 | return dst->dev->mtu; | ||
139 | } | ||
140 | |||
141 | static struct dst_ops fake_dst_ops = { | ||
142 | .family = AF_INET, | ||
143 | .protocol = cpu_to_be16(ETH_P_IP), | ||
144 | .update_pmtu = fake_update_pmtu, | ||
145 | .redirect = fake_redirect, | ||
146 | .cow_metrics = fake_cow_metrics, | ||
147 | .neigh_lookup = fake_neigh_lookup, | ||
148 | .mtu = fake_mtu, | ||
149 | }; | ||
150 | |||
151 | /* | ||
152 | * Initialize bogus route table used to keep netfilter happy. | ||
153 | * Currently, we fill in the PMTU entry because netfilter | ||
154 | * refragmentation needs it, and the rt_flags entry because | ||
155 | * ipt_REJECT needs it. Future netfilter modules might | ||
156 | * require us to fill additional fields. | ||
157 | */ | ||
158 | static const u32 br_dst_default_metrics[RTAX_MAX] = { | ||
159 | [RTAX_MTU - 1] = 1500, | ||
160 | }; | ||
161 | |||
162 | void br_netfilter_rtable_init(struct net_bridge *br) | ||
163 | { | ||
164 | struct rtable *rt = &br->fake_rtable; | ||
165 | |||
166 | atomic_set(&rt->dst.__refcnt, 1); | ||
167 | rt->dst.dev = br->dev; | ||
168 | rt->dst.path = &rt->dst; | ||
169 | dst_init_metrics(&rt->dst, br_dst_default_metrics, true); | ||
170 | rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE; | ||
171 | rt->dst.ops = &fake_dst_ops; | ||
172 | } | ||
173 | |||
174 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) | 114 | static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) |
175 | { | 115 | { |
176 | struct net_bridge_port *port; | 116 | struct net_bridge_port *port; |
@@ -245,14 +185,6 @@ static inline void nf_bridge_save_header(struct sk_buff *skb) | |||
245 | skb->nf_bridge->data, header_size); | 185 | skb->nf_bridge->data, header_size); |
246 | } | 186 | } |
247 | 187 | ||
248 | static inline void nf_bridge_update_protocol(struct sk_buff *skb) | ||
249 | { | ||
250 | if (skb->nf_bridge->mask & BRNF_8021Q) | ||
251 | skb->protocol = htons(ETH_P_8021Q); | ||
252 | else if (skb->nf_bridge->mask & BRNF_PPPoE) | ||
253 | skb->protocol = htons(ETH_P_PPP_SES); | ||
254 | } | ||
255 | |||
256 | /* When handing a packet over to the IP layer | 188 | /* When handing a packet over to the IP layer |
257 | * check whether we have a skb that is in the | 189 | * check whether we have a skb that is in the |
258 | * expected format | 190 | * expected format |
@@ -320,26 +252,6 @@ drop: | |||
320 | return -1; | 252 | return -1; |
321 | } | 253 | } |
322 | 254 | ||
323 | /* Fill in the header for fragmented IP packets handled by | ||
324 | * the IPv4 connection tracking code. | ||
325 | */ | ||
326 | int nf_bridge_copy_header(struct sk_buff *skb) | ||
327 | { | ||
328 | int err; | ||
329 | unsigned int header_size; | ||
330 | |||
331 | nf_bridge_update_protocol(skb); | ||
332 | header_size = ETH_HLEN + nf_bridge_encap_header_len(skb); | ||
333 | err = skb_cow_head(skb, header_size); | ||
334 | if (err) | ||
335 | return err; | ||
336 | |||
337 | skb_copy_to_linear_data_offset(skb, -header_size, | ||
338 | skb->nf_bridge->data, header_size); | ||
339 | __skb_push(skb, nf_bridge_encap_header_len(skb)); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ | 255 | /* PF_BRIDGE/PRE_ROUTING *********************************************/ |
344 | /* Undo the changes made for ip6tables PREROUTING and continue the | 256 | /* Undo the changes made for ip6tables PREROUTING and continue the |
345 | * bridge PRE_ROUTING hook. */ | 257 | * bridge PRE_ROUTING hook. */ |
@@ -1059,38 +971,42 @@ static struct ctl_table brnf_table[] = { | |||
1059 | }; | 971 | }; |
1060 | #endif | 972 | #endif |
1061 | 973 | ||
1062 | int __init br_netfilter_init(void) | 974 | static int __init br_netfilter_init(void) |
1063 | { | 975 | { |
1064 | int ret; | 976 | int ret; |
1065 | 977 | ||
1066 | ret = dst_entries_init(&fake_dst_ops); | 978 | ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); |
1067 | if (ret < 0) | 979 | if (ret < 0) |
1068 | return ret; | 980 | return ret; |
1069 | 981 | ||
1070 | ret = nf_register_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); | ||
1071 | if (ret < 0) { | ||
1072 | dst_entries_destroy(&fake_dst_ops); | ||
1073 | return ret; | ||
1074 | } | ||
1075 | #ifdef CONFIG_SYSCTL | 982 | #ifdef CONFIG_SYSCTL |
1076 | brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table); | 983 | brnf_sysctl_header = register_net_sysctl(&init_net, "net/bridge", brnf_table); |
1077 | if (brnf_sysctl_header == NULL) { | 984 | if (brnf_sysctl_header == NULL) { |
1078 | printk(KERN_WARNING | 985 | printk(KERN_WARNING |
1079 | "br_netfilter: can't register to sysctl.\n"); | 986 | "br_netfilter: can't register to sysctl.\n"); |
1080 | nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); | 987 | ret = -ENOMEM; |
1081 | dst_entries_destroy(&fake_dst_ops); | 988 | goto err1; |
1082 | return -ENOMEM; | ||
1083 | } | 989 | } |
1084 | #endif | 990 | #endif |
1085 | printk(KERN_NOTICE "Bridge firewalling registered\n"); | 991 | printk(KERN_NOTICE "Bridge firewalling registered\n"); |
1086 | return 0; | 992 | return 0; |
993 | err1: | ||
994 | nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); | ||
995 | return ret; | ||
1087 | } | 996 | } |
1088 | 997 | ||
1089 | void br_netfilter_fini(void) | 998 | static void __exit br_netfilter_fini(void) |
1090 | { | 999 | { |
1091 | nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); | 1000 | nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); |
1092 | #ifdef CONFIG_SYSCTL | 1001 | #ifdef CONFIG_SYSCTL |
1093 | unregister_net_sysctl_table(brnf_sysctl_header); | 1002 | unregister_net_sysctl_table(brnf_sysctl_header); |
1094 | #endif | 1003 | #endif |
1095 | dst_entries_destroy(&fake_dst_ops); | ||
1096 | } | 1004 | } |
1005 | |||
1006 | module_init(br_netfilter_init); | ||
1007 | module_exit(br_netfilter_fini); | ||
1008 | |||
1009 | MODULE_LICENSE("GPL"); | ||
1010 | MODULE_AUTHOR("Lennert Buytenhek <buytenh@gnu.org>"); | ||
1011 | MODULE_AUTHOR("Bart De Schuymer <bdschuym@pandora.be>"); | ||
1012 | MODULE_DESCRIPTION("Linux ethernet netfilter firewall bridge"); | ||
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 90a91e137acc..0fa66b83685f 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -602,7 +602,7 @@ out_af: | |||
602 | return err; | 602 | return err; |
603 | } | 603 | } |
604 | 604 | ||
605 | void __exit br_netlink_fini(void) | 605 | void br_netlink_fini(void) |
606 | { | 606 | { |
607 | br_mdb_uninit(); | 607 | br_mdb_uninit(); |
608 | rtnl_af_unregister(&br_af_ops); | 608 | rtnl_af_unregister(&br_af_ops); |
diff --git a/net/bridge/br_nf_core.c b/net/bridge/br_nf_core.c new file mode 100644 index 000000000000..387cb3bd017c --- /dev/null +++ b/net/bridge/br_nf_core.c | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Handle firewalling core | ||
3 | * Linux ethernet bridge | ||
4 | * | ||
5 | * Authors: | ||
6 | * Lennert Buytenhek <buytenh@gnu.org> | ||
7 | * Bart De Schuymer <bdschuym@pandora.be> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | * | ||
14 | * Lennert dedicates this file to Kerstin Wurdinger. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/in_route.h> | ||
20 | #include <linux/inetdevice.h> | ||
21 | #include <net/route.h> | ||
22 | |||
23 | #include "br_private.h" | ||
24 | #ifdef CONFIG_SYSCTL | ||
25 | #include <linux/sysctl.h> | ||
26 | #endif | ||
27 | |||
28 | static void fake_update_pmtu(struct dst_entry *dst, struct sock *sk, | ||
29 | struct sk_buff *skb, u32 mtu) | ||
30 | { | ||
31 | } | ||
32 | |||
33 | static void fake_redirect(struct dst_entry *dst, struct sock *sk, | ||
34 | struct sk_buff *skb) | ||
35 | { | ||
36 | } | ||
37 | |||
38 | static u32 *fake_cow_metrics(struct dst_entry *dst, unsigned long old) | ||
39 | { | ||
40 | return NULL; | ||
41 | } | ||
42 | |||
43 | static struct neighbour *fake_neigh_lookup(const struct dst_entry *dst, | ||
44 | struct sk_buff *skb, | ||
45 | const void *daddr) | ||
46 | { | ||
47 | return NULL; | ||
48 | } | ||
49 | |||
50 | static unsigned int fake_mtu(const struct dst_entry *dst) | ||
51 | { | ||
52 | return dst->dev->mtu; | ||
53 | } | ||
54 | |||
55 | static struct dst_ops fake_dst_ops = { | ||
56 | .family = AF_INET, | ||
57 | .protocol = cpu_to_be16(ETH_P_IP), | ||
58 | .update_pmtu = fake_update_pmtu, | ||
59 | .redirect = fake_redirect, | ||
60 | .cow_metrics = fake_cow_metrics, | ||
61 | .neigh_lookup = fake_neigh_lookup, | ||
62 | .mtu = fake_mtu, | ||
63 | }; | ||
64 | |||
65 | /* | ||
66 | * Initialize bogus route table used to keep netfilter happy. | ||
67 | * Currently, we fill in the PMTU entry because netfilter | ||
68 | * refragmentation needs it, and the rt_flags entry because | ||
69 | * ipt_REJECT needs it. Future netfilter modules might | ||
70 | * require us to fill additional fields. | ||
71 | */ | ||
72 | static const u32 br_dst_default_metrics[RTAX_MAX] = { | ||
73 | [RTAX_MTU - 1] = 1500, | ||
74 | }; | ||
75 | |||
76 | void br_netfilter_rtable_init(struct net_bridge *br) | ||
77 | { | ||
78 | struct rtable *rt = &br->fake_rtable; | ||
79 | |||
80 | atomic_set(&rt->dst.__refcnt, 1); | ||
81 | rt->dst.dev = br->dev; | ||
82 | rt->dst.path = &rt->dst; | ||
83 | dst_init_metrics(&rt->dst, br_dst_default_metrics, true); | ||
84 | rt->dst.flags = DST_NOXFRM | DST_FAKE_RTABLE; | ||
85 | rt->dst.ops = &fake_dst_ops; | ||
86 | } | ||
87 | |||
88 | int __init br_nf_core_init(void) | ||
89 | { | ||
90 | return dst_entries_init(&fake_dst_ops); | ||
91 | } | ||
92 | |||
93 | void br_nf_core_fini(void) | ||
94 | { | ||
95 | dst_entries_destroy(&fake_dst_ops); | ||
96 | } | ||
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index b6c04cbcfdc5..f53592fc3ef9 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -221,7 +221,7 @@ struct net_bridge | |||
221 | struct pcpu_sw_netstats __percpu *stats; | 221 | struct pcpu_sw_netstats __percpu *stats; |
222 | spinlock_t hash_lock; | 222 | spinlock_t hash_lock; |
223 | struct hlist_head hash[BR_HASH_SIZE]; | 223 | struct hlist_head hash[BR_HASH_SIZE]; |
224 | #ifdef CONFIG_BRIDGE_NETFILTER | 224 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
225 | struct rtable fake_rtable; | 225 | struct rtable fake_rtable; |
226 | bool nf_call_iptables; | 226 | bool nf_call_iptables; |
227 | bool nf_call_ip6tables; | 227 | bool nf_call_ip6tables; |
@@ -754,13 +754,13 @@ static inline int br_vlan_enabled(struct net_bridge *br) | |||
754 | #endif | 754 | #endif |
755 | 755 | ||
756 | /* br_netfilter.c */ | 756 | /* br_netfilter.c */ |
757 | #ifdef CONFIG_BRIDGE_NETFILTER | 757 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
758 | int br_netfilter_init(void); | 758 | int br_nf_core_init(void); |
759 | void br_netfilter_fini(void); | 759 | void br_nf_core_fini(void); |
760 | void br_netfilter_rtable_init(struct net_bridge *); | 760 | void br_netfilter_rtable_init(struct net_bridge *); |
761 | #else | 761 | #else |
762 | #define br_netfilter_init() (0) | 762 | static inline int br_nf_core_init(void) { return 0; } |
763 | #define br_netfilter_fini() do { } while (0) | 763 | static inline void br_nf_core_fini(void) {} |
764 | #define br_netfilter_rtable_init(x) | 764 | #define br_netfilter_rtable_init(x) |
765 | #endif | 765 | #endif |
766 | 766 | ||
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c9e2572b15f4..cb431c6016ee 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c | |||
@@ -629,7 +629,7 @@ static ssize_t multicast_startup_query_interval_store( | |||
629 | } | 629 | } |
630 | static DEVICE_ATTR_RW(multicast_startup_query_interval); | 630 | static DEVICE_ATTR_RW(multicast_startup_query_interval); |
631 | #endif | 631 | #endif |
632 | #ifdef CONFIG_BRIDGE_NETFILTER | 632 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
633 | static ssize_t nf_call_iptables_show( | 633 | static ssize_t nf_call_iptables_show( |
634 | struct device *d, struct device_attribute *attr, char *buf) | 634 | struct device *d, struct device_attribute *attr, char *buf) |
635 | { | 635 | { |
@@ -763,7 +763,7 @@ static struct attribute *bridge_attrs[] = { | |||
763 | &dev_attr_multicast_query_response_interval.attr, | 763 | &dev_attr_multicast_query_response_interval.attr, |
764 | &dev_attr_multicast_startup_query_interval.attr, | 764 | &dev_attr_multicast_startup_query_interval.attr, |
765 | #endif | 765 | #endif |
766 | #ifdef CONFIG_BRIDGE_NETFILTER | 766 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
767 | &dev_attr_nf_call_iptables.attr, | 767 | &dev_attr_nf_call_iptables.attr, |
768 | &dev_attr_nf_call_ip6tables.attr, | 768 | &dev_attr_nf_call_ip6tables.attr, |
769 | &dev_attr_nf_call_arptables.attr, | 769 | &dev_attr_nf_call_arptables.attr, |
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index d189c5262bdb..345242a79db6 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -61,16 +61,6 @@ config NFT_CHAIN_ROUTE_IPV4 | |||
61 | fields such as the source, destination, type of service and | 61 | fields such as the source, destination, type of service and |
62 | the packet mark. | 62 | the packet mark. |
63 | 63 | ||
64 | config NFT_CHAIN_NAT_IPV4 | ||
65 | depends on NF_TABLES_IPV4 | ||
66 | depends on NF_NAT_IPV4 && NFT_NAT | ||
67 | tristate "IPv4 nf_tables nat chain support" | ||
68 | help | ||
69 | This option enables the "nat" chain for IPv4 in nf_tables. This | ||
70 | chain type is used to perform Network Address Translation (NAT) | ||
71 | packet transformations such as the source, destination address and | ||
72 | source and destination ports. | ||
73 | |||
74 | config NFT_REJECT_IPV4 | 64 | config NFT_REJECT_IPV4 |
75 | depends on NF_TABLES_IPV4 | 65 | depends on NF_TABLES_IPV4 |
76 | default NFT_REJECT | 66 | default NFT_REJECT |
@@ -94,6 +84,30 @@ config NF_NAT_IPV4 | |||
94 | 84 | ||
95 | if NF_NAT_IPV4 | 85 | if NF_NAT_IPV4 |
96 | 86 | ||
87 | config NFT_CHAIN_NAT_IPV4 | ||
88 | depends on NF_TABLES_IPV4 | ||
89 | tristate "IPv4 nf_tables nat chain support" | ||
90 | help | ||
91 | This option enables the "nat" chain for IPv4 in nf_tables. This | ||
92 | chain type is used to perform Network Address Translation (NAT) | ||
93 | packet transformations such as the source, destination address and | ||
94 | source and destination ports. | ||
95 | |||
96 | config NF_NAT_MASQUERADE_IPV4 | ||
97 | tristate "IPv4 masquerade support" | ||
98 | help | ||
99 | This is the kernel functionality to provide NAT in the masquerade | ||
100 | flavour (automatic source address selection). | ||
101 | |||
102 | config NFT_MASQ_IPV4 | ||
103 | tristate "IPv4 masquerading support for nf_tables" | ||
104 | depends on NF_TABLES_IPV4 | ||
105 | depends on NFT_MASQ | ||
106 | select NF_NAT_MASQUERADE_IPV4 | ||
107 | help | ||
108 | This is the expression that provides IPv4 masquerading support for | ||
109 | nf_tables. | ||
110 | |||
97 | config NF_NAT_SNMP_BASIC | 111 | config NF_NAT_SNMP_BASIC |
98 | tristate "Basic SNMP-ALG support" | 112 | tristate "Basic SNMP-ALG support" |
99 | depends on NF_CONNTRACK_SNMP | 113 | depends on NF_CONNTRACK_SNMP |
@@ -232,18 +246,6 @@ config IP_NF_NAT | |||
232 | 246 | ||
233 | if IP_NF_NAT | 247 | if IP_NF_NAT |
234 | 248 | ||
235 | config NF_NAT_MASQUERADE_IPV4 | ||
236 | tristate "IPv4 masquerade support" | ||
237 | help | ||
238 | This is the kernel functionality to provide NAT in the masquerade | ||
239 | flavour (automatic source address selection). | ||
240 | |||
241 | config NFT_MASQ_IPV4 | ||
242 | tristate "IPv4 masquerading support for nf_tables" | ||
243 | depends on NF_TABLES_IPV4 | ||
244 | depends on NFT_MASQ | ||
245 | select NF_NAT_MASQUERADE_IPV4 | ||
246 | |||
247 | config IP_NF_TARGET_MASQUERADE | 249 | config IP_NF_TARGET_MASQUERADE |
248 | tristate "MASQUERADE target support" | 250 | tristate "MASQUERADE target support" |
249 | select NF_NAT_MASQUERADE_IPV4 | 251 | select NF_NAT_MASQUERADE_IPV4 |
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig index a8f25306a46a..bb1a40db7be1 100644 --- a/net/ipv6/netfilter/Kconfig +++ b/net/ipv6/netfilter/Kconfig | |||
@@ -40,16 +40,6 @@ config NFT_CHAIN_ROUTE_IPV6 | |||
40 | fields such as the source, destination, flowlabel, hop-limit and | 40 | fields such as the source, destination, flowlabel, hop-limit and |
41 | the packet mark. | 41 | the packet mark. |
42 | 42 | ||
43 | config NFT_CHAIN_NAT_IPV6 | ||
44 | depends on NF_TABLES_IPV6 | ||
45 | depends on NF_NAT_IPV6 && NFT_NAT | ||
46 | tristate "IPv6 nf_tables nat chain support" | ||
47 | help | ||
48 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
49 | chain type is used to perform Network Address Translation (NAT) | ||
50 | packet transformations such as the source, destination address and | ||
51 | source and destination ports. | ||
52 | |||
53 | config NFT_REJECT_IPV6 | 43 | config NFT_REJECT_IPV6 |
54 | depends on NF_TABLES_IPV6 | 44 | depends on NF_TABLES_IPV6 |
55 | default NFT_REJECT | 45 | default NFT_REJECT |
@@ -70,6 +60,34 @@ config NF_NAT_IPV6 | |||
70 | forms of full Network Address Port Translation. This can be | 60 | forms of full Network Address Port Translation. This can be |
71 | controlled by iptables or nft. | 61 | controlled by iptables or nft. |
72 | 62 | ||
63 | if NF_NAT_IPV6 | ||
64 | |||
65 | config NFT_CHAIN_NAT_IPV6 | ||
66 | depends on NF_TABLES_IPV6 | ||
67 | tristate "IPv6 nf_tables nat chain support" | ||
68 | help | ||
69 | This option enables the "nat" chain for IPv6 in nf_tables. This | ||
70 | chain type is used to perform Network Address Translation (NAT) | ||
71 | packet transformations such as the source, destination address and | ||
72 | source and destination ports. | ||
73 | |||
74 | config NF_NAT_MASQUERADE_IPV6 | ||
75 | tristate "IPv6 masquerade support" | ||
76 | help | ||
77 | This is the kernel functionality to provide NAT in the masquerade | ||
78 | flavour (automatic source address selection) for IPv6. | ||
79 | |||
80 | config NFT_MASQ_IPV6 | ||
81 | tristate "IPv6 masquerade support for nf_tables" | ||
82 | depends on NF_TABLES_IPV6 | ||
83 | depends on NFT_MASQ | ||
84 | select NF_NAT_MASQUERADE_IPV6 | ||
85 | help | ||
86 | This is the expression that provides IPv4 masquerading support for | ||
87 | nf_tables. | ||
88 | |||
89 | endif # NF_NAT_IPV6 | ||
90 | |||
73 | config IP6_NF_IPTABLES | 91 | config IP6_NF_IPTABLES |
74 | tristate "IP6 tables support (required for filtering)" | 92 | tristate "IP6 tables support (required for filtering)" |
75 | depends on INET && IPV6 | 93 | depends on INET && IPV6 |
@@ -258,18 +276,6 @@ config IP6_NF_NAT | |||
258 | 276 | ||
259 | if IP6_NF_NAT | 277 | if IP6_NF_NAT |
260 | 278 | ||
261 | config NF_NAT_MASQUERADE_IPV6 | ||
262 | tristate "IPv6 masquerade support" | ||
263 | help | ||
264 | This is the kernel functionality to provide NAT in the masquerade | ||
265 | flavour (automatic source address selection) for IPv6. | ||
266 | |||
267 | config NFT_MASQ_IPV6 | ||
268 | tristate "IPv6 masquerade support for nf_tables" | ||
269 | depends on NF_TABLES_IPV6 | ||
270 | depends on NFT_MASQ | ||
271 | select NF_NAT_MASQUERADE_IPV6 | ||
272 | |||
273 | config IP6_NF_TARGET_MASQUERADE | 279 | config IP6_NF_TARGET_MASQUERADE |
274 | tristate "MASQUERADE target support" | 280 | tristate "MASQUERADE target support" |
275 | select NF_NAT_MASQUERADE_IPV6 | 281 | select NF_NAT_MASQUERADE_IPV6 |
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index 2f7f5c32c6f9..234a8ec82076 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig | |||
@@ -99,6 +99,15 @@ config IP_SET_HASH_IPPORTNET | |||
99 | 99 | ||
100 | To compile it as a module, choose M here. If unsure, say N. | 100 | To compile it as a module, choose M here. If unsure, say N. |
101 | 101 | ||
102 | config IP_SET_HASH_MAC | ||
103 | tristate "hash:mac set support" | ||
104 | depends on IP_SET | ||
105 | help | ||
106 | This option adds the hash:mac set type support, by which | ||
107 | one can store MAC (ethernet address) elements in a set. | ||
108 | |||
109 | To compile it as a module, choose M here. If unsure, say N. | ||
110 | |||
102 | config IP_SET_HASH_NETPORTNET | 111 | config IP_SET_HASH_NETPORTNET |
103 | tristate "hash:net,port,net set support" | 112 | tristate "hash:net,port,net set support" |
104 | depends on IP_SET | 113 | depends on IP_SET |
diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile index 231f10196cb9..3dbd5e958489 100644 --- a/net/netfilter/ipset/Makefile +++ b/net/netfilter/ipset/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_IP_SET_HASH_IPMARK) += ip_set_hash_ipmark.o | |||
18 | obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o | 18 | obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o |
19 | obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o | 19 | obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o |
20 | obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o | 20 | obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o |
21 | obj-$(CONFIG_IP_SET_HASH_MAC) += ip_set_hash_mac.o | ||
21 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o | 22 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o |
22 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o | 23 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o |
23 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o | 24 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o |
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h index f2c7d83dc23f..6f024a8a1534 100644 --- a/net/netfilter/ipset/ip_set_bitmap_gen.h +++ b/net/netfilter/ipset/ip_set_bitmap_gen.h | |||
@@ -128,6 +128,8 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
128 | return 0; | 128 | return 0; |
129 | if (SET_WITH_COUNTER(set)) | 129 | if (SET_WITH_COUNTER(set)) |
130 | ip_set_update_counter(ext_counter(x, set), ext, mext, flags); | 130 | ip_set_update_counter(ext_counter(x, set), ext, mext, flags); |
131 | if (SET_WITH_SKBINFO(set)) | ||
132 | ip_set_get_skbinfo(ext_skbinfo(x, set), ext, mext, flags); | ||
131 | return 1; | 133 | return 1; |
132 | } | 134 | } |
133 | 135 | ||
@@ -161,6 +163,8 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
161 | ip_set_init_counter(ext_counter(x, set), ext); | 163 | ip_set_init_counter(ext_counter(x, set), ext); |
162 | if (SET_WITH_COMMENT(set)) | 164 | if (SET_WITH_COMMENT(set)) |
163 | ip_set_init_comment(ext_comment(x, set), ext); | 165 | ip_set_init_comment(ext_comment(x, set), ext); |
166 | if (SET_WITH_SKBINFO(set)) | ||
167 | ip_set_init_skbinfo(ext_skbinfo(x, set), ext); | ||
164 | return 0; | 168 | return 0; |
165 | } | 169 | } |
166 | 170 | ||
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c index dafdb39ef042..55b083ec587a 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ip.c +++ b/net/netfilter/ipset/ip_set_bitmap_ip.c | |||
@@ -27,7 +27,8 @@ | |||
27 | 27 | ||
28 | #define IPSET_TYPE_REV_MIN 0 | 28 | #define IPSET_TYPE_REV_MIN 0 |
29 | /* 1 Counter support added */ | 29 | /* 1 Counter support added */ |
30 | #define IPSET_TYPE_REV_MAX 2 /* Comment support added */ | 30 | /* 2 Comment support added */ |
31 | #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */ | ||
31 | 32 | ||
32 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -139,7 +140,10 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], | |||
139 | if (unlikely(!tb[IPSET_ATTR_IP] || | 140 | if (unlikely(!tb[IPSET_ATTR_IP] || |
140 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 141 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
141 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 142 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
142 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 143 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
144 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
145 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
146 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
143 | return -IPSET_ERR_PROTOCOL; | 147 | return -IPSET_ERR_PROTOCOL; |
144 | 148 | ||
145 | if (tb[IPSET_ATTR_LINENO]) | 149 | if (tb[IPSET_ATTR_LINENO]) |
@@ -357,6 +361,9 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { | |||
357 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 361 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
358 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 362 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
359 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 363 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
364 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
365 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
366 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
360 | }, | 367 | }, |
361 | .me = THIS_MODULE, | 368 | .me = THIS_MODULE, |
362 | }; | 369 | }; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c index dbad505e79e3..86104744b00f 100644 --- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c +++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c | |||
@@ -27,7 +27,8 @@ | |||
27 | 27 | ||
28 | #define IPSET_TYPE_REV_MIN 0 | 28 | #define IPSET_TYPE_REV_MIN 0 |
29 | /* 1 Counter support added */ | 29 | /* 1 Counter support added */ |
30 | #define IPSET_TYPE_REV_MAX 2 /* Comment support added */ | 30 | /* 2 Comment support added */ |
31 | #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */ | ||
31 | 32 | ||
32 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -240,7 +241,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], | |||
240 | if (unlikely(!tb[IPSET_ATTR_IP] || | 241 | if (unlikely(!tb[IPSET_ATTR_IP] || |
241 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 242 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
242 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 243 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
243 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 244 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
245 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
246 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
247 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
244 | return -IPSET_ERR_PROTOCOL; | 248 | return -IPSET_ERR_PROTOCOL; |
245 | 249 | ||
246 | if (tb[IPSET_ATTR_LINENO]) | 250 | if (tb[IPSET_ATTR_LINENO]) |
@@ -394,6 +398,9 @@ static struct ip_set_type bitmap_ipmac_type = { | |||
394 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 398 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
395 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 399 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
396 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 400 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
401 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
402 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
403 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
397 | }, | 404 | }, |
398 | .me = THIS_MODULE, | 405 | .me = THIS_MODULE, |
399 | }; | 406 | }; |
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c index a4b65ae1986c..005dd36444c3 100644 --- a/net/netfilter/ipset/ip_set_bitmap_port.c +++ b/net/netfilter/ipset/ip_set_bitmap_port.c | |||
@@ -22,7 +22,8 @@ | |||
22 | 22 | ||
23 | #define IPSET_TYPE_REV_MIN 0 | 23 | #define IPSET_TYPE_REV_MIN 0 |
24 | /* 1 Counter support added */ | 24 | /* 1 Counter support added */ |
25 | #define IPSET_TYPE_REV_MAX 2 /* Comment support added */ | 25 | /* 2 Comment support added */ |
26 | #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */ | ||
26 | 27 | ||
27 | MODULE_LICENSE("GPL"); | 28 | MODULE_LICENSE("GPL"); |
28 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 29 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -139,7 +140,10 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], | |||
139 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 140 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
140 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 141 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
141 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 142 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
142 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 143 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
144 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
145 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
146 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
143 | return -IPSET_ERR_PROTOCOL; | 147 | return -IPSET_ERR_PROTOCOL; |
144 | 148 | ||
145 | if (tb[IPSET_ATTR_LINENO]) | 149 | if (tb[IPSET_ATTR_LINENO]) |
@@ -291,6 +295,9 @@ static struct ip_set_type bitmap_port_type = { | |||
291 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 295 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
292 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 296 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
293 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 297 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
298 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
299 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
300 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
294 | }, | 301 | }, |
295 | .me = THIS_MODULE, | 302 | .me = THIS_MODULE, |
296 | }; | 303 | }; |
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index 5593e97426c4..26c795e6b57f 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c | |||
@@ -337,6 +337,12 @@ const struct ip_set_ext_type ip_set_extensions[] = { | |||
337 | .len = sizeof(unsigned long), | 337 | .len = sizeof(unsigned long), |
338 | .align = __alignof__(unsigned long), | 338 | .align = __alignof__(unsigned long), |
339 | }, | 339 | }, |
340 | [IPSET_EXT_ID_SKBINFO] = { | ||
341 | .type = IPSET_EXT_SKBINFO, | ||
342 | .flag = IPSET_FLAG_WITH_SKBINFO, | ||
343 | .len = sizeof(struct ip_set_skbinfo), | ||
344 | .align = __alignof__(struct ip_set_skbinfo), | ||
345 | }, | ||
340 | [IPSET_EXT_ID_COMMENT] = { | 346 | [IPSET_EXT_ID_COMMENT] = { |
341 | .type = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY, | 347 | .type = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY, |
342 | .flag = IPSET_FLAG_WITH_COMMENT, | 348 | .flag = IPSET_FLAG_WITH_COMMENT, |
@@ -382,6 +388,7 @@ int | |||
382 | ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], | 388 | ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], |
383 | struct ip_set_ext *ext) | 389 | struct ip_set_ext *ext) |
384 | { | 390 | { |
391 | u64 fullmark; | ||
385 | if (tb[IPSET_ATTR_TIMEOUT]) { | 392 | if (tb[IPSET_ATTR_TIMEOUT]) { |
386 | if (!(set->extensions & IPSET_EXT_TIMEOUT)) | 393 | if (!(set->extensions & IPSET_EXT_TIMEOUT)) |
387 | return -IPSET_ERR_TIMEOUT; | 394 | return -IPSET_ERR_TIMEOUT; |
@@ -402,7 +409,25 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[], | |||
402 | return -IPSET_ERR_COMMENT; | 409 | return -IPSET_ERR_COMMENT; |
403 | ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]); | 410 | ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]); |
404 | } | 411 | } |
405 | 412 | if (tb[IPSET_ATTR_SKBMARK]) { | |
413 | if (!(set->extensions & IPSET_EXT_SKBINFO)) | ||
414 | return -IPSET_ERR_SKBINFO; | ||
415 | fullmark = be64_to_cpu(nla_get_be64(tb[IPSET_ATTR_SKBMARK])); | ||
416 | ext->skbmark = fullmark >> 32; | ||
417 | ext->skbmarkmask = fullmark & 0xffffffff; | ||
418 | } | ||
419 | if (tb[IPSET_ATTR_SKBPRIO]) { | ||
420 | if (!(set->extensions & IPSET_EXT_SKBINFO)) | ||
421 | return -IPSET_ERR_SKBINFO; | ||
422 | ext->skbprio = be32_to_cpu(nla_get_be32( | ||
423 | tb[IPSET_ATTR_SKBPRIO])); | ||
424 | } | ||
425 | if (tb[IPSET_ATTR_SKBQUEUE]) { | ||
426 | if (!(set->extensions & IPSET_EXT_SKBINFO)) | ||
427 | return -IPSET_ERR_SKBINFO; | ||
428 | ext->skbqueue = be16_to_cpu(nla_get_be16( | ||
429 | tb[IPSET_ATTR_SKBQUEUE])); | ||
430 | } | ||
406 | return 0; | 431 | return 0; |
407 | } | 432 | } |
408 | EXPORT_SYMBOL_GPL(ip_set_get_extensions); | 433 | EXPORT_SYMBOL_GPL(ip_set_get_extensions); |
@@ -1397,7 +1422,8 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set, | |||
1397 | struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); | 1422 | struct nlmsghdr *rep, *nlh = nlmsg_hdr(skb); |
1398 | struct sk_buff *skb2; | 1423 | struct sk_buff *skb2; |
1399 | struct nlmsgerr *errmsg; | 1424 | struct nlmsgerr *errmsg; |
1400 | size_t payload = sizeof(*errmsg) + nlmsg_len(nlh); | 1425 | size_t payload = min(SIZE_MAX, |
1426 | sizeof(*errmsg) + nlmsg_len(nlh)); | ||
1401 | int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); | 1427 | int min_len = nlmsg_total_size(sizeof(struct nfgenmsg)); |
1402 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; | 1428 | struct nlattr *cda[IPSET_ATTR_CMD_MAX+1]; |
1403 | struct nlattr *cmdattr; | 1429 | struct nlattr *cmdattr; |
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index 8a38890cbe5e..fee7c64e4dd1 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h | |||
@@ -720,6 +720,8 @@ reuse_slot: | |||
720 | ip_set_init_counter(ext_counter(data, set), ext); | 720 | ip_set_init_counter(ext_counter(data, set), ext); |
721 | if (SET_WITH_COMMENT(set)) | 721 | if (SET_WITH_COMMENT(set)) |
722 | ip_set_init_comment(ext_comment(data, set), ext); | 722 | ip_set_init_comment(ext_comment(data, set), ext); |
723 | if (SET_WITH_SKBINFO(set)) | ||
724 | ip_set_init_skbinfo(ext_skbinfo(data, set), ext); | ||
723 | 725 | ||
724 | out: | 726 | out: |
725 | rcu_read_unlock_bh(); | 727 | rcu_read_unlock_bh(); |
@@ -797,6 +799,9 @@ mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext, | |||
797 | if (SET_WITH_COUNTER(set)) | 799 | if (SET_WITH_COUNTER(set)) |
798 | ip_set_update_counter(ext_counter(data, set), | 800 | ip_set_update_counter(ext_counter(data, set), |
799 | ext, mext, flags); | 801 | ext, mext, flags); |
802 | if (SET_WITH_SKBINFO(set)) | ||
803 | ip_set_get_skbinfo(ext_skbinfo(data, set), | ||
804 | ext, mext, flags); | ||
800 | return mtype_do_data_match(data); | 805 | return mtype_do_data_match(data); |
801 | } | 806 | } |
802 | 807 | ||
@@ -1049,8 +1054,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, | |||
1049 | struct HTYPE *h; | 1054 | struct HTYPE *h; |
1050 | struct htable *t; | 1055 | struct htable *t; |
1051 | 1056 | ||
1057 | #ifndef IP_SET_PROTO_UNDEF | ||
1052 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) | 1058 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
1053 | return -IPSET_ERR_INVALID_FAMILY; | 1059 | return -IPSET_ERR_INVALID_FAMILY; |
1060 | #endif | ||
1054 | 1061 | ||
1055 | #ifdef IP_SET_HASH_WITH_MARKMASK | 1062 | #ifdef IP_SET_HASH_WITH_MARKMASK |
1056 | markmask = 0xffffffff; | 1063 | markmask = 0xffffffff; |
@@ -1132,25 +1139,32 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, | |||
1132 | rcu_assign_pointer(h->table, t); | 1139 | rcu_assign_pointer(h->table, t); |
1133 | 1140 | ||
1134 | set->data = h; | 1141 | set->data = h; |
1142 | #ifndef IP_SET_PROTO_UNDEF | ||
1135 | if (set->family == NFPROTO_IPV4) { | 1143 | if (set->family == NFPROTO_IPV4) { |
1144 | #endif | ||
1136 | set->variant = &IPSET_TOKEN(HTYPE, 4_variant); | 1145 | set->variant = &IPSET_TOKEN(HTYPE, 4_variant); |
1137 | set->dsize = ip_set_elem_len(set, tb, | 1146 | set->dsize = ip_set_elem_len(set, tb, |
1138 | sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); | 1147 | sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); |
1148 | #ifndef IP_SET_PROTO_UNDEF | ||
1139 | } else { | 1149 | } else { |
1140 | set->variant = &IPSET_TOKEN(HTYPE, 6_variant); | 1150 | set->variant = &IPSET_TOKEN(HTYPE, 6_variant); |
1141 | set->dsize = ip_set_elem_len(set, tb, | 1151 | set->dsize = ip_set_elem_len(set, tb, |
1142 | sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); | 1152 | sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); |
1143 | } | 1153 | } |
1154 | #endif | ||
1144 | if (tb[IPSET_ATTR_TIMEOUT]) { | 1155 | if (tb[IPSET_ATTR_TIMEOUT]) { |
1145 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 1156 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
1157 | #ifndef IP_SET_PROTO_UNDEF | ||
1146 | if (set->family == NFPROTO_IPV4) | 1158 | if (set->family == NFPROTO_IPV4) |
1159 | #endif | ||
1147 | IPSET_TOKEN(HTYPE, 4_gc_init)(set, | 1160 | IPSET_TOKEN(HTYPE, 4_gc_init)(set, |
1148 | IPSET_TOKEN(HTYPE, 4_gc)); | 1161 | IPSET_TOKEN(HTYPE, 4_gc)); |
1162 | #ifndef IP_SET_PROTO_UNDEF | ||
1149 | else | 1163 | else |
1150 | IPSET_TOKEN(HTYPE, 6_gc_init)(set, | 1164 | IPSET_TOKEN(HTYPE, 6_gc_init)(set, |
1151 | IPSET_TOKEN(HTYPE, 6_gc)); | 1165 | IPSET_TOKEN(HTYPE, 6_gc)); |
1166 | #endif | ||
1152 | } | 1167 | } |
1153 | |||
1154 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", | 1168 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", |
1155 | set->name, jhash_size(t->htable_bits), | 1169 | set->name, jhash_size(t->htable_bits), |
1156 | t->htable_bits, h->maxelem, set->data, t); | 1170 | t->htable_bits, h->maxelem, set->data, t); |
diff --git a/net/netfilter/ipset/ip_set_hash_ip.c b/net/netfilter/ipset/ip_set_hash_ip.c index e52739938533..76959d79e9d1 100644 --- a/net/netfilter/ipset/ip_set_hash_ip.c +++ b/net/netfilter/ipset/ip_set_hash_ip.c | |||
@@ -26,7 +26,8 @@ | |||
26 | #define IPSET_TYPE_REV_MIN 0 | 26 | #define IPSET_TYPE_REV_MIN 0 |
27 | /* 1 Counters support */ | 27 | /* 1 Counters support */ |
28 | /* 2 Comments support */ | 28 | /* 2 Comments support */ |
29 | #define IPSET_TYPE_REV_MAX 3 /* Forceadd support */ | 29 | /* 3 Forceadd support */ |
30 | #define IPSET_TYPE_REV_MAX 4 /* skbinfo support */ | ||
30 | 31 | ||
31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
32 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -111,7 +112,10 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
111 | if (unlikely(!tb[IPSET_ATTR_IP] || | 112 | if (unlikely(!tb[IPSET_ATTR_IP] || |
112 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 113 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
113 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 114 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
114 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 115 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
116 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
117 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
118 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
115 | return -IPSET_ERR_PROTOCOL; | 119 | return -IPSET_ERR_PROTOCOL; |
116 | 120 | ||
117 | if (tb[IPSET_ATTR_LINENO]) | 121 | if (tb[IPSET_ATTR_LINENO]) |
@@ -247,6 +251,9 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
247 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 251 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
248 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 252 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
249 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | 253 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
254 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
255 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
256 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || | ||
250 | tb[IPSET_ATTR_IP_TO] || | 257 | tb[IPSET_ATTR_IP_TO] || |
251 | tb[IPSET_ATTR_CIDR])) | 258 | tb[IPSET_ATTR_CIDR])) |
252 | return -IPSET_ERR_PROTOCOL; | 259 | return -IPSET_ERR_PROTOCOL; |
@@ -295,6 +302,9 @@ static struct ip_set_type hash_ip_type __read_mostly = { | |||
295 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 302 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
296 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 303 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
297 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 304 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
305 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
306 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
307 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
298 | }, | 308 | }, |
299 | .me = THIS_MODULE, | 309 | .me = THIS_MODULE, |
300 | }; | 310 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipmark.c b/net/netfilter/ipset/ip_set_hash_ipmark.c index 4eff0a297254..7abf9788cfa8 100644 --- a/net/netfilter/ipset/ip_set_hash_ipmark.c +++ b/net/netfilter/ipset/ip_set_hash_ipmark.c | |||
@@ -25,7 +25,8 @@ | |||
25 | #include <linux/netfilter/ipset/ip_set_hash.h> | 25 | #include <linux/netfilter/ipset/ip_set_hash.h> |
26 | 26 | ||
27 | #define IPSET_TYPE_REV_MIN 0 | 27 | #define IPSET_TYPE_REV_MIN 0 |
28 | #define IPSET_TYPE_REV_MAX 1 /* Forceadd support */ | 28 | /* 1 Forceadd support */ |
29 | #define IPSET_TYPE_REV_MAX 2 /* skbinfo support */ | ||
29 | 30 | ||
30 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
31 | MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>"); | 32 | MODULE_AUTHOR("Vytas Dauksa <vytas.dauksa@smoothwall.net>"); |
@@ -113,7 +114,10 @@ hash_ipmark4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
113 | !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) || | 114 | !ip_set_attr_netorder(tb, IPSET_ATTR_MARK) || |
114 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 115 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
115 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 116 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
116 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 117 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
118 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
119 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
120 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
117 | return -IPSET_ERR_PROTOCOL; | 121 | return -IPSET_ERR_PROTOCOL; |
118 | 122 | ||
119 | if (tb[IPSET_ATTR_LINENO]) | 123 | if (tb[IPSET_ATTR_LINENO]) |
@@ -244,6 +248,9 @@ hash_ipmark6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
244 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 248 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
245 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 249 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
246 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | 250 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
251 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
252 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
253 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || | ||
247 | tb[IPSET_ATTR_IP_TO] || | 254 | tb[IPSET_ATTR_IP_TO] || |
248 | tb[IPSET_ATTR_CIDR])) | 255 | tb[IPSET_ATTR_CIDR])) |
249 | return -IPSET_ERR_PROTOCOL; | 256 | return -IPSET_ERR_PROTOCOL; |
@@ -301,6 +308,9 @@ static struct ip_set_type hash_ipmark_type __read_mostly = { | |||
301 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 308 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
302 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 309 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
303 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 310 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
311 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
312 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
313 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
304 | }, | 314 | }, |
305 | .me = THIS_MODULE, | 315 | .me = THIS_MODULE, |
306 | }; | 316 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipport.c b/net/netfilter/ipset/ip_set_hash_ipport.c index f37a5ae8a5e0..dcbcceb9a52f 100644 --- a/net/netfilter/ipset/ip_set_hash_ipport.c +++ b/net/netfilter/ipset/ip_set_hash_ipport.c | |||
@@ -28,7 +28,8 @@ | |||
28 | /* 1 SCTP and UDPLITE support added */ | 28 | /* 1 SCTP and UDPLITE support added */ |
29 | /* 2 Counters support added */ | 29 | /* 2 Counters support added */ |
30 | /* 3 Comments support added */ | 30 | /* 3 Comments support added */ |
31 | #define IPSET_TYPE_REV_MAX 4 /* Forceadd support added */ | 31 | /* 4 Forceadd support added */ |
32 | #define IPSET_TYPE_REV_MAX 5 /* skbinfo support added */ | ||
32 | 33 | ||
33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 35 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -122,7 +123,10 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
122 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 123 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
123 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 124 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
124 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 125 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
125 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 126 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
127 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
128 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
129 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
126 | return -IPSET_ERR_PROTOCOL; | 130 | return -IPSET_ERR_PROTOCOL; |
127 | 131 | ||
128 | if (tb[IPSET_ATTR_LINENO]) | 132 | if (tb[IPSET_ATTR_LINENO]) |
@@ -287,6 +291,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
287 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 291 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
288 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 292 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
289 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | 293 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
294 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
295 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
296 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || | ||
290 | tb[IPSET_ATTR_IP_TO] || | 297 | tb[IPSET_ATTR_IP_TO] || |
291 | tb[IPSET_ATTR_CIDR])) | 298 | tb[IPSET_ATTR_CIDR])) |
292 | return -IPSET_ERR_PROTOCOL; | 299 | return -IPSET_ERR_PROTOCOL; |
@@ -370,6 +377,9 @@ static struct ip_set_type hash_ipport_type __read_mostly = { | |||
370 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 377 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
371 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 378 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
372 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 379 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
380 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
381 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
382 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
373 | }, | 383 | }, |
374 | .me = THIS_MODULE, | 384 | .me = THIS_MODULE, |
375 | }; | 385 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportip.c b/net/netfilter/ipset/ip_set_hash_ipportip.c index 41ef00eda874..7ef93fc887a1 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportip.c +++ b/net/netfilter/ipset/ip_set_hash_ipportip.c | |||
@@ -28,7 +28,8 @@ | |||
28 | /* 1 SCTP and UDPLITE support added */ | 28 | /* 1 SCTP and UDPLITE support added */ |
29 | /* 2 Counters support added */ | 29 | /* 2 Counters support added */ |
30 | /* 3 Comments support added */ | 30 | /* 3 Comments support added */ |
31 | #define IPSET_TYPE_REV_MAX 4 /* Forceadd support added */ | 31 | /* 4 Forceadd support added */ |
32 | #define IPSET_TYPE_REV_MAX 5 /* skbinfo support added */ | ||
32 | 33 | ||
33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 35 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -124,7 +125,10 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
124 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || | 125 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || |
125 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 126 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
126 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 127 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
127 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 128 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
129 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
130 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
131 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
128 | return -IPSET_ERR_PROTOCOL; | 132 | return -IPSET_ERR_PROTOCOL; |
129 | 133 | ||
130 | if (tb[IPSET_ATTR_LINENO]) | 134 | if (tb[IPSET_ATTR_LINENO]) |
@@ -295,6 +299,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
295 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 299 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
296 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 300 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
297 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | 301 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
302 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
303 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
304 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || | ||
298 | tb[IPSET_ATTR_IP_TO] || | 305 | tb[IPSET_ATTR_IP_TO] || |
299 | tb[IPSET_ATTR_CIDR])) | 306 | tb[IPSET_ATTR_CIDR])) |
300 | return -IPSET_ERR_PROTOCOL; | 307 | return -IPSET_ERR_PROTOCOL; |
@@ -382,6 +389,9 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { | |||
382 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 389 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
383 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 390 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
384 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 391 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
392 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
393 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
394 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
385 | }, | 395 | }, |
386 | .me = THIS_MODULE, | 396 | .me = THIS_MODULE, |
387 | }; | 397 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_ipportnet.c b/net/netfilter/ipset/ip_set_hash_ipportnet.c index 7308d84f9277..b6012ad92781 100644 --- a/net/netfilter/ipset/ip_set_hash_ipportnet.c +++ b/net/netfilter/ipset/ip_set_hash_ipportnet.c | |||
@@ -30,7 +30,8 @@ | |||
30 | /* 3 nomatch flag support added */ | 30 | /* 3 nomatch flag support added */ |
31 | /* 4 Counters support added */ | 31 | /* 4 Counters support added */ |
32 | /* 5 Comments support added */ | 32 | /* 5 Comments support added */ |
33 | #define IPSET_TYPE_REV_MAX 6 /* Forceadd support added */ | 33 | /* 6 Forceadd support added */ |
34 | #define IPSET_TYPE_REV_MAX 7 /* skbinfo support added */ | ||
34 | 35 | ||
35 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
36 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 37 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -179,7 +180,10 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
179 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 180 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
180 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 181 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
181 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 182 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
182 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 183 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
184 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
185 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
186 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
183 | return -IPSET_ERR_PROTOCOL; | 187 | return -IPSET_ERR_PROTOCOL; |
184 | 188 | ||
185 | if (tb[IPSET_ATTR_LINENO]) | 189 | if (tb[IPSET_ATTR_LINENO]) |
@@ -432,6 +436,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
432 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 436 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
433 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 437 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
434 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | 438 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
439 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
440 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
441 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE) || | ||
435 | tb[IPSET_ATTR_IP_TO] || | 442 | tb[IPSET_ATTR_IP_TO] || |
436 | tb[IPSET_ATTR_CIDR])) | 443 | tb[IPSET_ATTR_CIDR])) |
437 | return -IPSET_ERR_PROTOCOL; | 444 | return -IPSET_ERR_PROTOCOL; |
@@ -541,6 +548,9 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = { | |||
541 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 548 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
542 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 549 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
543 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 550 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
551 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
552 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
553 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
544 | }, | 554 | }, |
545 | .me = THIS_MODULE, | 555 | .me = THIS_MODULE, |
546 | }; | 556 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c new file mode 100644 index 000000000000..65690b52a4d5 --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_mac.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* Copyright (C) 2014 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | /* Kernel module implementing an IP set type: the hash:mac type */ | ||
9 | |||
10 | #include <linux/jhash.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/etherdevice.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/if_ether.h> | ||
16 | #include <net/netlink.h> | ||
17 | |||
18 | #include <linux/netfilter.h> | ||
19 | #include <linux/netfilter/ipset/ip_set.h> | ||
20 | #include <linux/netfilter/ipset/ip_set_hash.h> | ||
21 | |||
22 | #define IPSET_TYPE_REV_MIN 0 | ||
23 | #define IPSET_TYPE_REV_MAX 0 | ||
24 | |||
25 | MODULE_LICENSE("GPL"); | ||
26 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | ||
27 | IP_SET_MODULE_DESC("hash:mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); | ||
28 | MODULE_ALIAS("ip_set_hash:mac"); | ||
29 | |||
30 | /* Type specific function prefix */ | ||
31 | #define HTYPE hash_mac | ||
32 | |||
33 | /* Member elements */ | ||
34 | struct hash_mac4_elem { | ||
35 | /* Zero valued IP addresses cannot be stored */ | ||
36 | union { | ||
37 | unsigned char ether[ETH_ALEN]; | ||
38 | __be32 foo[2]; | ||
39 | }; | ||
40 | }; | ||
41 | |||
42 | /* Common functions */ | ||
43 | |||
44 | static inline bool | ||
45 | hash_mac4_data_equal(const struct hash_mac4_elem *e1, | ||
46 | const struct hash_mac4_elem *e2, | ||
47 | u32 *multi) | ||
48 | { | ||
49 | return ether_addr_equal(e1->ether, e2->ether); | ||
50 | } | ||
51 | |||
52 | static inline bool | ||
53 | hash_mac4_data_list(struct sk_buff *skb, const struct hash_mac4_elem *e) | ||
54 | { | ||
55 | return nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, e->ether); | ||
56 | } | ||
57 | |||
58 | static inline void | ||
59 | hash_mac4_data_next(struct hash_mac4_elem *next, | ||
60 | const struct hash_mac4_elem *e) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | #define MTYPE hash_mac4 | ||
65 | #define PF 4 | ||
66 | #define HOST_MASK 32 | ||
67 | #define IP_SET_EMIT_CREATE | ||
68 | #define IP_SET_PROTO_UNDEF | ||
69 | #include "ip_set_hash_gen.h" | ||
70 | |||
71 | /* Zero valued element is not supported */ | ||
72 | static const unsigned char invalid_ether[ETH_ALEN] = { 0 }; | ||
73 | |||
74 | static int | ||
75 | hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
76 | const struct xt_action_param *par, | ||
77 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | ||
78 | { | ||
79 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
80 | struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; | ||
81 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); | ||
82 | |||
83 | /* MAC can be src only */ | ||
84 | if (!(opt->flags & IPSET_DIM_ONE_SRC)) | ||
85 | return 0; | ||
86 | |||
87 | if (skb_mac_header(skb) < skb->head || | ||
88 | (skb_mac_header(skb) + ETH_HLEN) > skb->data) | ||
89 | return -EINVAL; | ||
90 | |||
91 | memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN); | ||
92 | if (memcmp(e.ether, invalid_ether, ETH_ALEN) == 0) | ||
93 | return -EINVAL; | ||
94 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | hash_mac4_uadt(struct ip_set *set, struct nlattr *tb[], | ||
99 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | ||
100 | { | ||
101 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
102 | struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; | ||
103 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); | ||
104 | int ret; | ||
105 | |||
106 | if (unlikely(!tb[IPSET_ATTR_ETHER] || | ||
107 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | ||
108 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | ||
109 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | ||
110 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
111 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
112 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
113 | return -IPSET_ERR_PROTOCOL; | ||
114 | |||
115 | if (tb[IPSET_ATTR_LINENO]) | ||
116 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
117 | |||
118 | ret = ip_set_get_extensions(set, tb, &ext); | ||
119 | if (ret) | ||
120 | return ret; | ||
121 | memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN); | ||
122 | if (memcmp(e.ether, invalid_ether, ETH_ALEN) == 0) | ||
123 | return -IPSET_ERR_HASH_ELEM; | ||
124 | |||
125 | return adtfn(set, &e, &ext, &ext, flags); | ||
126 | } | ||
127 | |||
128 | static struct ip_set_type hash_mac_type __read_mostly = { | ||
129 | .name = "hash:mac", | ||
130 | .protocol = IPSET_PROTOCOL, | ||
131 | .features = IPSET_TYPE_MAC, | ||
132 | .dimension = IPSET_DIM_ONE, | ||
133 | .family = NFPROTO_UNSPEC, | ||
134 | .revision_min = IPSET_TYPE_REV_MIN, | ||
135 | .revision_max = IPSET_TYPE_REV_MAX, | ||
136 | .create = hash_mac_create, | ||
137 | .create_policy = { | ||
138 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | ||
139 | [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, | ||
140 | [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, | ||
141 | [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, | ||
142 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
143 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
144 | }, | ||
145 | .adt_policy = { | ||
146 | [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, | ||
147 | .len = ETH_ALEN }, | ||
148 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
149 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | ||
150 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | ||
151 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | ||
152 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
153 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
154 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
155 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
156 | }, | ||
157 | .me = THIS_MODULE, | ||
158 | }; | ||
159 | |||
160 | static int __init | ||
161 | hash_mac_init(void) | ||
162 | { | ||
163 | return ip_set_type_register(&hash_mac_type); | ||
164 | } | ||
165 | |||
166 | static void __exit | ||
167 | hash_mac_fini(void) | ||
168 | { | ||
169 | ip_set_type_unregister(&hash_mac_type); | ||
170 | } | ||
171 | |||
172 | module_init(hash_mac_init); | ||
173 | module_exit(hash_mac_fini); | ||
diff --git a/net/netfilter/ipset/ip_set_hash_net.c b/net/netfilter/ipset/ip_set_hash_net.c index 4c7d495783a3..6b3ac10ac2f1 100644 --- a/net/netfilter/ipset/ip_set_hash_net.c +++ b/net/netfilter/ipset/ip_set_hash_net.c | |||
@@ -27,7 +27,8 @@ | |||
27 | /* 2 nomatch flag support added */ | 27 | /* 2 nomatch flag support added */ |
28 | /* 3 Counters support added */ | 28 | /* 3 Counters support added */ |
29 | /* 4 Comments support added */ | 29 | /* 4 Comments support added */ |
30 | #define IPSET_TYPE_REV_MAX 5 /* Forceadd support added */ | 30 | /* 5 Forceadd support added */ |
31 | #define IPSET_TYPE_REV_MAX 6 /* skbinfo mapping support added */ | ||
31 | 32 | ||
32 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
33 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -150,7 +151,10 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
150 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 151 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
151 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 152 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
152 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 153 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
153 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 154 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
155 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
156 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
157 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
154 | return -IPSET_ERR_PROTOCOL; | 158 | return -IPSET_ERR_PROTOCOL; |
155 | 159 | ||
156 | if (tb[IPSET_ATTR_LINENO]) | 160 | if (tb[IPSET_ATTR_LINENO]) |
@@ -318,7 +322,10 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
318 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 322 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
319 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 323 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
320 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 324 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
321 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 325 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
326 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
327 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
328 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
322 | return -IPSET_ERR_PROTOCOL; | 329 | return -IPSET_ERR_PROTOCOL; |
323 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | 330 | if (unlikely(tb[IPSET_ATTR_IP_TO])) |
324 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 331 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -377,6 +384,9 @@ static struct ip_set_type hash_net_type __read_mostly = { | |||
377 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 384 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
378 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 385 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
379 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 386 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
387 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
388 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
389 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
380 | }, | 390 | }, |
381 | .me = THIS_MODULE, | 391 | .me = THIS_MODULE, |
382 | }; | 392 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netiface.c b/net/netfilter/ipset/ip_set_hash_netiface.c index db2606805b35..03cdb69ac9bf 100644 --- a/net/netfilter/ipset/ip_set_hash_netiface.c +++ b/net/netfilter/ipset/ip_set_hash_netiface.c | |||
@@ -28,7 +28,8 @@ | |||
28 | /* 2 /0 support added */ | 28 | /* 2 /0 support added */ |
29 | /* 3 Counters support added */ | 29 | /* 3 Counters support added */ |
30 | /* 4 Comments support added */ | 30 | /* 4 Comments support added */ |
31 | #define IPSET_TYPE_REV_MAX 5 /* Forceadd support added */ | 31 | /* 5 Forceadd support added */ |
32 | #define IPSET_TYPE_REV_MAX 6 /* skbinfo support added */ | ||
32 | 33 | ||
33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
34 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 35 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -281,7 +282,10 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
281 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 282 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
282 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 283 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
283 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 284 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
284 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 285 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
286 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
287 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
288 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
285 | return -IPSET_ERR_PROTOCOL; | 289 | return -IPSET_ERR_PROTOCOL; |
286 | 290 | ||
287 | if (tb[IPSET_ATTR_LINENO]) | 291 | if (tb[IPSET_ATTR_LINENO]) |
@@ -514,7 +518,10 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
514 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 518 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
515 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 519 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
516 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 520 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
517 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 521 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
522 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
523 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
524 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
518 | return -IPSET_ERR_PROTOCOL; | 525 | return -IPSET_ERR_PROTOCOL; |
519 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | 526 | if (unlikely(tb[IPSET_ATTR_IP_TO])) |
520 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 527 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -590,6 +597,9 @@ static struct ip_set_type hash_netiface_type __read_mostly = { | |||
590 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 597 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
591 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 598 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
592 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 599 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
600 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
601 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
602 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
593 | }, | 603 | }, |
594 | .me = THIS_MODULE, | 604 | .me = THIS_MODULE, |
595 | }; | 605 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c index 96b131366e7b..da00284b3571 100644 --- a/net/netfilter/ipset/ip_set_hash_netnet.c +++ b/net/netfilter/ipset/ip_set_hash_netnet.c | |||
@@ -24,7 +24,8 @@ | |||
24 | #include <linux/netfilter/ipset/ip_set_hash.h> | 24 | #include <linux/netfilter/ipset/ip_set_hash.h> |
25 | 25 | ||
26 | #define IPSET_TYPE_REV_MIN 0 | 26 | #define IPSET_TYPE_REV_MIN 0 |
27 | #define IPSET_TYPE_REV_MAX 1 /* Forceadd support added */ | 27 | /* 1 Forceadd support added */ |
28 | #define IPSET_TYPE_REV_MAX 2 /* skbinfo support added */ | ||
28 | 29 | ||
29 | MODULE_LICENSE("GPL"); | 30 | MODULE_LICENSE("GPL"); |
30 | MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); | 31 | MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); |
@@ -171,7 +172,10 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
171 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 172 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
172 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 173 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
173 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 174 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
174 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 175 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
176 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
177 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
178 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
175 | return -IPSET_ERR_PROTOCOL; | 179 | return -IPSET_ERR_PROTOCOL; |
176 | 180 | ||
177 | if (tb[IPSET_ATTR_LINENO]) | 181 | if (tb[IPSET_ATTR_LINENO]) |
@@ -394,7 +398,10 @@ hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
394 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 398 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
395 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 399 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
396 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 400 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
397 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 401 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
402 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
403 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
404 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
398 | return -IPSET_ERR_PROTOCOL; | 405 | return -IPSET_ERR_PROTOCOL; |
399 | if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) | 406 | if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) |
400 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 407 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -462,6 +469,9 @@ static struct ip_set_type hash_netnet_type __read_mostly = { | |||
462 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 469 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
463 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 470 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
464 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 471 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
472 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
473 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
474 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
465 | }, | 475 | }, |
466 | .me = THIS_MODULE, | 476 | .me = THIS_MODULE, |
467 | }; | 477 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netport.c b/net/netfilter/ipset/ip_set_hash_netport.c index 1c645fbd09c7..c0ddb58d19dc 100644 --- a/net/netfilter/ipset/ip_set_hash_netport.c +++ b/net/netfilter/ipset/ip_set_hash_netport.c | |||
@@ -29,7 +29,8 @@ | |||
29 | /* 3 nomatch flag support added */ | 29 | /* 3 nomatch flag support added */ |
30 | /* 4 Counters support added */ | 30 | /* 4 Counters support added */ |
31 | /* 5 Comments support added */ | 31 | /* 5 Comments support added */ |
32 | #define IPSET_TYPE_REV_MAX 6 /* Forceadd support added */ | 32 | /* 6 Forceadd support added */ |
33 | #define IPSET_TYPE_REV_MAX 7 /* skbinfo support added */ | ||
33 | 34 | ||
34 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
35 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 36 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -172,7 +173,10 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
172 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 173 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
173 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 174 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
174 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 175 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
175 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 176 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
177 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
178 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
179 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
176 | return -IPSET_ERR_PROTOCOL; | 180 | return -IPSET_ERR_PROTOCOL; |
177 | 181 | ||
178 | if (tb[IPSET_ATTR_LINENO]) | 182 | if (tb[IPSET_ATTR_LINENO]) |
@@ -389,7 +393,10 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
389 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 393 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
390 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 394 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
391 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 395 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
392 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 396 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
397 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
398 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
399 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
393 | return -IPSET_ERR_PROTOCOL; | 400 | return -IPSET_ERR_PROTOCOL; |
394 | if (unlikely(tb[IPSET_ATTR_IP_TO])) | 401 | if (unlikely(tb[IPSET_ATTR_IP_TO])) |
395 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 402 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -489,6 +496,9 @@ static struct ip_set_type hash_netport_type __read_mostly = { | |||
489 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 496 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
490 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 497 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
491 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 498 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
499 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
500 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
501 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
492 | }, | 502 | }, |
493 | .me = THIS_MODULE, | 503 | .me = THIS_MODULE, |
494 | }; | 504 | }; |
diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c index 2f0034347189..b8053d675fc3 100644 --- a/net/netfilter/ipset/ip_set_hash_netportnet.c +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c | |||
@@ -26,7 +26,8 @@ | |||
26 | 26 | ||
27 | #define IPSET_TYPE_REV_MIN 0 | 27 | #define IPSET_TYPE_REV_MIN 0 |
28 | /* 0 Comments support added */ | 28 | /* 0 Comments support added */ |
29 | #define IPSET_TYPE_REV_MAX 1 /* Forceadd support added */ | 29 | /* 1 Forceadd support added */ |
30 | #define IPSET_TYPE_REV_MAX 2 /* skbinfo support added */ | ||
30 | 31 | ||
31 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
32 | MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); | 33 | MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>"); |
@@ -189,7 +190,10 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], | |||
189 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 190 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
190 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 191 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
191 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 192 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
192 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 193 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
194 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
195 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
196 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
193 | return -IPSET_ERR_PROTOCOL; | 197 | return -IPSET_ERR_PROTOCOL; |
194 | 198 | ||
195 | if (tb[IPSET_ATTR_LINENO]) | 199 | if (tb[IPSET_ATTR_LINENO]) |
@@ -460,7 +464,10 @@ hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[], | |||
460 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 464 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
461 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 465 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
462 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 466 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
463 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 467 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
468 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
469 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
470 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
464 | return -IPSET_ERR_PROTOCOL; | 471 | return -IPSET_ERR_PROTOCOL; |
465 | if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) | 472 | if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO])) |
466 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; | 473 | return -IPSET_ERR_HASH_RANGE_UNSUPPORTED; |
@@ -569,6 +576,9 @@ static struct ip_set_type hash_netportnet_type __read_mostly = { | |||
569 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 576 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
570 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 577 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
571 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 578 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
579 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
580 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
581 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
572 | }, | 582 | }, |
573 | .me = THIS_MODULE, | 583 | .me = THIS_MODULE, |
574 | }; | 584 | }; |
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c index f87adbad6076..f8f682806e36 100644 --- a/net/netfilter/ipset/ip_set_list_set.c +++ b/net/netfilter/ipset/ip_set_list_set.c | |||
@@ -17,7 +17,8 @@ | |||
17 | 17 | ||
18 | #define IPSET_TYPE_REV_MIN 0 | 18 | #define IPSET_TYPE_REV_MIN 0 |
19 | /* 1 Counters support added */ | 19 | /* 1 Counters support added */ |
20 | #define IPSET_TYPE_REV_MAX 2 /* Comments support added */ | 20 | /* 2 Comments support added */ |
21 | #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */ | ||
21 | 22 | ||
22 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
23 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | 24 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); |
@@ -73,6 +74,10 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb, | |||
73 | ip_set_update_counter(ext_counter(e, set), | 74 | ip_set_update_counter(ext_counter(e, set), |
74 | ext, &opt->ext, | 75 | ext, &opt->ext, |
75 | cmdflags); | 76 | cmdflags); |
77 | if (SET_WITH_SKBINFO(set)) | ||
78 | ip_set_get_skbinfo(ext_skbinfo(e, set), | ||
79 | ext, &opt->ext, | ||
80 | cmdflags); | ||
76 | return ret; | 81 | return ret; |
77 | } | 82 | } |
78 | } | 83 | } |
@@ -197,6 +202,8 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d, | |||
197 | ip_set_init_counter(ext_counter(e, set), ext); | 202 | ip_set_init_counter(ext_counter(e, set), ext); |
198 | if (SET_WITH_COMMENT(set)) | 203 | if (SET_WITH_COMMENT(set)) |
199 | ip_set_init_comment(ext_comment(e, set), ext); | 204 | ip_set_init_comment(ext_comment(e, set), ext); |
205 | if (SET_WITH_SKBINFO(set)) | ||
206 | ip_set_init_skbinfo(ext_skbinfo(e, set), ext); | ||
200 | return 0; | 207 | return 0; |
201 | } | 208 | } |
202 | 209 | ||
@@ -307,6 +314,8 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, | |||
307 | ip_set_init_counter(ext_counter(e, set), ext); | 314 | ip_set_init_counter(ext_counter(e, set), ext); |
308 | if (SET_WITH_COMMENT(set)) | 315 | if (SET_WITH_COMMENT(set)) |
309 | ip_set_init_comment(ext_comment(e, set), ext); | 316 | ip_set_init_comment(ext_comment(e, set), ext); |
317 | if (SET_WITH_SKBINFO(set)) | ||
318 | ip_set_init_skbinfo(ext_skbinfo(e, set), ext); | ||
310 | /* Set is already added to the list */ | 319 | /* Set is already added to the list */ |
311 | ip_set_put_byindex(map->net, d->id); | 320 | ip_set_put_byindex(map->net, d->id); |
312 | return 0; | 321 | return 0; |
@@ -378,7 +387,10 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[], | |||
378 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | 387 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
379 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || | 388 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) || |
380 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | 389 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || |
381 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) | 390 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || |
391 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
392 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
393 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
382 | return -IPSET_ERR_PROTOCOL; | 394 | return -IPSET_ERR_PROTOCOL; |
383 | 395 | ||
384 | if (tb[IPSET_ATTR_LINENO]) | 396 | if (tb[IPSET_ATTR_LINENO]) |
@@ -667,6 +679,9 @@ static struct ip_set_type list_set_type __read_mostly = { | |||
667 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | 679 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
668 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | 680 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
669 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | 681 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, |
682 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
683 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
684 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
670 | }, | 685 | }, |
671 | .me = THIS_MODULE, | 686 | .me = THIS_MODULE, |
672 | }; | 687 | }; |
diff --git a/net/netfilter/ipvs/Kconfig b/net/netfilter/ipvs/Kconfig index 0c3b1670b0d1..3b6929dec748 100644 --- a/net/netfilter/ipvs/Kconfig +++ b/net/netfilter/ipvs/Kconfig | |||
@@ -152,6 +152,16 @@ config IP_VS_WLC | |||
152 | If you want to compile it in kernel, say Y. To compile it as a | 152 | If you want to compile it in kernel, say Y. To compile it as a |
153 | module, choose M here. If unsure, say N. | 153 | module, choose M here. If unsure, say N. |
154 | 154 | ||
155 | config IP_VS_FO | ||
156 | tristate "weighted failover scheduling" | ||
157 | ---help--- | ||
158 | The weighted failover scheduling algorithm directs network | ||
159 | connections to the server with the highest weight that is | ||
160 | currently available. | ||
161 | |||
162 | If you want to compile it in kernel, say Y. To compile it as a | ||
163 | module, choose M here. If unsure, say N. | ||
164 | |||
155 | config IP_VS_LBLC | 165 | config IP_VS_LBLC |
156 | tristate "locality-based least-connection scheduling" | 166 | tristate "locality-based least-connection scheduling" |
157 | ---help--- | 167 | ---help--- |
diff --git a/net/netfilter/ipvs/Makefile b/net/netfilter/ipvs/Makefile index 34ee602ddb66..38b2723b2e3d 100644 --- a/net/netfilter/ipvs/Makefile +++ b/net/netfilter/ipvs/Makefile | |||
@@ -26,6 +26,7 @@ obj-$(CONFIG_IP_VS_RR) += ip_vs_rr.o | |||
26 | obj-$(CONFIG_IP_VS_WRR) += ip_vs_wrr.o | 26 | obj-$(CONFIG_IP_VS_WRR) += ip_vs_wrr.o |
27 | obj-$(CONFIG_IP_VS_LC) += ip_vs_lc.o | 27 | obj-$(CONFIG_IP_VS_LC) += ip_vs_lc.o |
28 | obj-$(CONFIG_IP_VS_WLC) += ip_vs_wlc.o | 28 | obj-$(CONFIG_IP_VS_WLC) += ip_vs_wlc.o |
29 | obj-$(CONFIG_IP_VS_FO) += ip_vs_fo.o | ||
29 | obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o | 30 | obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o |
30 | obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o | 31 | obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o |
31 | obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o | 32 | obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o |
diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 610e19c0e13f..b0f7b626b56d 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/in.h> | 29 | #include <linux/in.h> |
30 | #include <linux/inet.h> | ||
30 | #include <linux/net.h> | 31 | #include <linux/net.h> |
31 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
32 | #include <linux/module.h> | 33 | #include <linux/module.h> |
@@ -77,6 +78,13 @@ static unsigned int ip_vs_conn_rnd __read_mostly; | |||
77 | #define CT_LOCKARRAY_SIZE (1<<CT_LOCKARRAY_BITS) | 78 | #define CT_LOCKARRAY_SIZE (1<<CT_LOCKARRAY_BITS) |
78 | #define CT_LOCKARRAY_MASK (CT_LOCKARRAY_SIZE-1) | 79 | #define CT_LOCKARRAY_MASK (CT_LOCKARRAY_SIZE-1) |
79 | 80 | ||
81 | /* We need an addrstrlen that works with or without v6 */ | ||
82 | #ifdef CONFIG_IP_VS_IPV6 | ||
83 | #define IP_VS_ADDRSTRLEN INET6_ADDRSTRLEN | ||
84 | #else | ||
85 | #define IP_VS_ADDRSTRLEN (8+1) | ||
86 | #endif | ||
87 | |||
80 | struct ip_vs_aligned_lock | 88 | struct ip_vs_aligned_lock |
81 | { | 89 | { |
82 | spinlock_t l; | 90 | spinlock_t l; |
@@ -488,7 +496,12 @@ static inline void ip_vs_bind_xmit(struct ip_vs_conn *cp) | |||
488 | break; | 496 | break; |
489 | 497 | ||
490 | case IP_VS_CONN_F_TUNNEL: | 498 | case IP_VS_CONN_F_TUNNEL: |
491 | cp->packet_xmit = ip_vs_tunnel_xmit; | 499 | #ifdef CONFIG_IP_VS_IPV6 |
500 | if (cp->daf == AF_INET6) | ||
501 | cp->packet_xmit = ip_vs_tunnel_xmit_v6; | ||
502 | else | ||
503 | #endif | ||
504 | cp->packet_xmit = ip_vs_tunnel_xmit; | ||
492 | break; | 505 | break; |
493 | 506 | ||
494 | case IP_VS_CONN_F_DROUTE: | 507 | case IP_VS_CONN_F_DROUTE: |
@@ -514,7 +527,10 @@ static inline void ip_vs_bind_xmit_v6(struct ip_vs_conn *cp) | |||
514 | break; | 527 | break; |
515 | 528 | ||
516 | case IP_VS_CONN_F_TUNNEL: | 529 | case IP_VS_CONN_F_TUNNEL: |
517 | cp->packet_xmit = ip_vs_tunnel_xmit_v6; | 530 | if (cp->daf == AF_INET6) |
531 | cp->packet_xmit = ip_vs_tunnel_xmit_v6; | ||
532 | else | ||
533 | cp->packet_xmit = ip_vs_tunnel_xmit; | ||
518 | break; | 534 | break; |
519 | 535 | ||
520 | case IP_VS_CONN_F_DROUTE: | 536 | case IP_VS_CONN_F_DROUTE: |
@@ -580,7 +596,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest) | |||
580 | ip_vs_proto_name(cp->protocol), | 596 | ip_vs_proto_name(cp->protocol), |
581 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), | 597 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), |
582 | IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), | 598 | IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), |
583 | IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport), | 599 | IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport), |
584 | ip_vs_fwd_tag(cp), cp->state, | 600 | ip_vs_fwd_tag(cp), cp->state, |
585 | cp->flags, atomic_read(&cp->refcnt), | 601 | cp->flags, atomic_read(&cp->refcnt), |
586 | atomic_read(&dest->refcnt)); | 602 | atomic_read(&dest->refcnt)); |
@@ -616,7 +632,13 @@ void ip_vs_try_bind_dest(struct ip_vs_conn *cp) | |||
616 | struct ip_vs_dest *dest; | 632 | struct ip_vs_dest *dest; |
617 | 633 | ||
618 | rcu_read_lock(); | 634 | rcu_read_lock(); |
619 | dest = ip_vs_find_dest(ip_vs_conn_net(cp), cp->af, &cp->daddr, | 635 | |
636 | /* This function is only invoked by the synchronization code. We do | ||
637 | * not currently support heterogeneous pools with synchronization, | ||
638 | * so we can make the assumption that the svc_af is the same as the | ||
639 | * dest_af | ||
640 | */ | ||
641 | dest = ip_vs_find_dest(ip_vs_conn_net(cp), cp->af, cp->af, &cp->daddr, | ||
620 | cp->dport, &cp->vaddr, cp->vport, | 642 | cp->dport, &cp->vaddr, cp->vport, |
621 | cp->protocol, cp->fwmark, cp->flags); | 643 | cp->protocol, cp->fwmark, cp->flags); |
622 | if (dest) { | 644 | if (dest) { |
@@ -671,7 +693,7 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp) | |||
671 | ip_vs_proto_name(cp->protocol), | 693 | ip_vs_proto_name(cp->protocol), |
672 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), | 694 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), |
673 | IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), | 695 | IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), |
674 | IP_VS_DBG_ADDR(cp->af, &cp->daddr), ntohs(cp->dport), | 696 | IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport), |
675 | ip_vs_fwd_tag(cp), cp->state, | 697 | ip_vs_fwd_tag(cp), cp->state, |
676 | cp->flags, atomic_read(&cp->refcnt), | 698 | cp->flags, atomic_read(&cp->refcnt), |
677 | atomic_read(&dest->refcnt)); | 699 | atomic_read(&dest->refcnt)); |
@@ -740,7 +762,7 @@ int ip_vs_check_template(struct ip_vs_conn *ct) | |||
740 | ntohs(ct->cport), | 762 | ntohs(ct->cport), |
741 | IP_VS_DBG_ADDR(ct->af, &ct->vaddr), | 763 | IP_VS_DBG_ADDR(ct->af, &ct->vaddr), |
742 | ntohs(ct->vport), | 764 | ntohs(ct->vport), |
743 | IP_VS_DBG_ADDR(ct->af, &ct->daddr), | 765 | IP_VS_DBG_ADDR(ct->daf, &ct->daddr), |
744 | ntohs(ct->dport)); | 766 | ntohs(ct->dport)); |
745 | 767 | ||
746 | /* | 768 | /* |
@@ -848,7 +870,7 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp) | |||
848 | * Create a new connection entry and hash it into the ip_vs_conn_tab | 870 | * Create a new connection entry and hash it into the ip_vs_conn_tab |
849 | */ | 871 | */ |
850 | struct ip_vs_conn * | 872 | struct ip_vs_conn * |
851 | ip_vs_conn_new(const struct ip_vs_conn_param *p, | 873 | ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af, |
852 | const union nf_inet_addr *daddr, __be16 dport, unsigned int flags, | 874 | const union nf_inet_addr *daddr, __be16 dport, unsigned int flags, |
853 | struct ip_vs_dest *dest, __u32 fwmark) | 875 | struct ip_vs_dest *dest, __u32 fwmark) |
854 | { | 876 | { |
@@ -867,6 +889,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, | |||
867 | setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp); | 889 | setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp); |
868 | ip_vs_conn_net_set(cp, p->net); | 890 | ip_vs_conn_net_set(cp, p->net); |
869 | cp->af = p->af; | 891 | cp->af = p->af; |
892 | cp->daf = dest_af; | ||
870 | cp->protocol = p->protocol; | 893 | cp->protocol = p->protocol; |
871 | ip_vs_addr_set(p->af, &cp->caddr, p->caddr); | 894 | ip_vs_addr_set(p->af, &cp->caddr, p->caddr); |
872 | cp->cport = p->cport; | 895 | cp->cport = p->cport; |
@@ -874,7 +897,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p, | |||
874 | ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af, | 897 | ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af, |
875 | &cp->vaddr, p->vaddr); | 898 | &cp->vaddr, p->vaddr); |
876 | cp->vport = p->vport; | 899 | cp->vport = p->vport; |
877 | ip_vs_addr_set(p->af, &cp->daddr, daddr); | 900 | ip_vs_addr_set(cp->daf, &cp->daddr, daddr); |
878 | cp->dport = dport; | 901 | cp->dport = dport; |
879 | cp->flags = flags; | 902 | cp->flags = flags; |
880 | cp->fwmark = fwmark; | 903 | cp->fwmark = fwmark; |
@@ -1036,6 +1059,7 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v) | |||
1036 | struct net *net = seq_file_net(seq); | 1059 | struct net *net = seq_file_net(seq); |
1037 | char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3]; | 1060 | char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3]; |
1038 | size_t len = 0; | 1061 | size_t len = 0; |
1062 | char dbuf[IP_VS_ADDRSTRLEN]; | ||
1039 | 1063 | ||
1040 | if (!ip_vs_conn_net_eq(cp, net)) | 1064 | if (!ip_vs_conn_net_eq(cp, net)) |
1041 | return 0; | 1065 | return 0; |
@@ -1050,24 +1074,32 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v) | |||
1050 | pe_data[len] = '\0'; | 1074 | pe_data[len] = '\0'; |
1051 | 1075 | ||
1052 | #ifdef CONFIG_IP_VS_IPV6 | 1076 | #ifdef CONFIG_IP_VS_IPV6 |
1077 | if (cp->daf == AF_INET6) | ||
1078 | snprintf(dbuf, sizeof(dbuf), "%pI6", &cp->daddr.in6); | ||
1079 | else | ||
1080 | #endif | ||
1081 | snprintf(dbuf, sizeof(dbuf), "%08X", | ||
1082 | ntohl(cp->daddr.ip)); | ||
1083 | |||
1084 | #ifdef CONFIG_IP_VS_IPV6 | ||
1053 | if (cp->af == AF_INET6) | 1085 | if (cp->af == AF_INET6) |
1054 | seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X " | 1086 | seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X " |
1055 | "%pI6 %04X %-11s %7lu%s\n", | 1087 | "%s %04X %-11s %7lu%s\n", |
1056 | ip_vs_proto_name(cp->protocol), | 1088 | ip_vs_proto_name(cp->protocol), |
1057 | &cp->caddr.in6, ntohs(cp->cport), | 1089 | &cp->caddr.in6, ntohs(cp->cport), |
1058 | &cp->vaddr.in6, ntohs(cp->vport), | 1090 | &cp->vaddr.in6, ntohs(cp->vport), |
1059 | &cp->daddr.in6, ntohs(cp->dport), | 1091 | dbuf, ntohs(cp->dport), |
1060 | ip_vs_state_name(cp->protocol, cp->state), | 1092 | ip_vs_state_name(cp->protocol, cp->state), |
1061 | (cp->timer.expires-jiffies)/HZ, pe_data); | 1093 | (cp->timer.expires-jiffies)/HZ, pe_data); |
1062 | else | 1094 | else |
1063 | #endif | 1095 | #endif |
1064 | seq_printf(seq, | 1096 | seq_printf(seq, |
1065 | "%-3s %08X %04X %08X %04X" | 1097 | "%-3s %08X %04X %08X %04X" |
1066 | " %08X %04X %-11s %7lu%s\n", | 1098 | " %s %04X %-11s %7lu%s\n", |
1067 | ip_vs_proto_name(cp->protocol), | 1099 | ip_vs_proto_name(cp->protocol), |
1068 | ntohl(cp->caddr.ip), ntohs(cp->cport), | 1100 | ntohl(cp->caddr.ip), ntohs(cp->cport), |
1069 | ntohl(cp->vaddr.ip), ntohs(cp->vport), | 1101 | ntohl(cp->vaddr.ip), ntohs(cp->vport), |
1070 | ntohl(cp->daddr.ip), ntohs(cp->dport), | 1102 | dbuf, ntohs(cp->dport), |
1071 | ip_vs_state_name(cp->protocol, cp->state), | 1103 | ip_vs_state_name(cp->protocol, cp->state), |
1072 | (cp->timer.expires-jiffies)/HZ, pe_data); | 1104 | (cp->timer.expires-jiffies)/HZ, pe_data); |
1073 | } | 1105 | } |
@@ -1105,6 +1137,7 @@ static const char *ip_vs_origin_name(unsigned int flags) | |||
1105 | 1137 | ||
1106 | static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v) | 1138 | static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v) |
1107 | { | 1139 | { |
1140 | char dbuf[IP_VS_ADDRSTRLEN]; | ||
1108 | 1141 | ||
1109 | if (v == SEQ_START_TOKEN) | 1142 | if (v == SEQ_START_TOKEN) |
1110 | seq_puts(seq, | 1143 | seq_puts(seq, |
@@ -1117,12 +1150,21 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v) | |||
1117 | return 0; | 1150 | return 0; |
1118 | 1151 | ||
1119 | #ifdef CONFIG_IP_VS_IPV6 | 1152 | #ifdef CONFIG_IP_VS_IPV6 |
1153 | if (cp->daf == AF_INET6) | ||
1154 | snprintf(dbuf, sizeof(dbuf), "%pI6", &cp->daddr.in6); | ||
1155 | else | ||
1156 | #endif | ||
1157 | snprintf(dbuf, sizeof(dbuf), "%08X", | ||
1158 | ntohl(cp->daddr.ip)); | ||
1159 | |||
1160 | #ifdef CONFIG_IP_VS_IPV6 | ||
1120 | if (cp->af == AF_INET6) | 1161 | if (cp->af == AF_INET6) |
1121 | seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %-6s %7lu\n", | 1162 | seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X " |
1163 | "%s %04X %-11s %-6s %7lu\n", | ||
1122 | ip_vs_proto_name(cp->protocol), | 1164 | ip_vs_proto_name(cp->protocol), |
1123 | &cp->caddr.in6, ntohs(cp->cport), | 1165 | &cp->caddr.in6, ntohs(cp->cport), |
1124 | &cp->vaddr.in6, ntohs(cp->vport), | 1166 | &cp->vaddr.in6, ntohs(cp->vport), |
1125 | &cp->daddr.in6, ntohs(cp->dport), | 1167 | dbuf, ntohs(cp->dport), |
1126 | ip_vs_state_name(cp->protocol, cp->state), | 1168 | ip_vs_state_name(cp->protocol, cp->state), |
1127 | ip_vs_origin_name(cp->flags), | 1169 | ip_vs_origin_name(cp->flags), |
1128 | (cp->timer.expires-jiffies)/HZ); | 1170 | (cp->timer.expires-jiffies)/HZ); |
@@ -1130,11 +1172,11 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v) | |||
1130 | #endif | 1172 | #endif |
1131 | seq_printf(seq, | 1173 | seq_printf(seq, |
1132 | "%-3s %08X %04X %08X %04X " | 1174 | "%-3s %08X %04X %08X %04X " |
1133 | "%08X %04X %-11s %-6s %7lu\n", | 1175 | "%s %04X %-11s %-6s %7lu\n", |
1134 | ip_vs_proto_name(cp->protocol), | 1176 | ip_vs_proto_name(cp->protocol), |
1135 | ntohl(cp->caddr.ip), ntohs(cp->cport), | 1177 | ntohl(cp->caddr.ip), ntohs(cp->cport), |
1136 | ntohl(cp->vaddr.ip), ntohs(cp->vport), | 1178 | ntohl(cp->vaddr.ip), ntohs(cp->vport), |
1137 | ntohl(cp->daddr.ip), ntohs(cp->dport), | 1179 | dbuf, ntohs(cp->dport), |
1138 | ip_vs_state_name(cp->protocol, cp->state), | 1180 | ip_vs_state_name(cp->protocol, cp->state), |
1139 | ip_vs_origin_name(cp->flags), | 1181 | ip_vs_origin_name(cp->flags), |
1140 | (cp->timer.expires-jiffies)/HZ); | 1182 | (cp->timer.expires-jiffies)/HZ); |
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 5c34e8d42e01..990decba1fe4 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c | |||
@@ -328,7 +328,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
328 | * This adds param.pe_data to the template, | 328 | * This adds param.pe_data to the template, |
329 | * and thus param.pe_data will be destroyed | 329 | * and thus param.pe_data will be destroyed |
330 | * when the template expires */ | 330 | * when the template expires */ |
331 | ct = ip_vs_conn_new(¶m, &dest->addr, dport, | 331 | ct = ip_vs_conn_new(¶m, dest->af, &dest->addr, dport, |
332 | IP_VS_CONN_F_TEMPLATE, dest, skb->mark); | 332 | IP_VS_CONN_F_TEMPLATE, dest, skb->mark); |
333 | if (ct == NULL) { | 333 | if (ct == NULL) { |
334 | kfree(param.pe_data); | 334 | kfree(param.pe_data); |
@@ -357,7 +357,8 @@ ip_vs_sched_persist(struct ip_vs_service *svc, | |||
357 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, &iph->saddr, | 357 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, &iph->saddr, |
358 | src_port, &iph->daddr, dst_port, ¶m); | 358 | src_port, &iph->daddr, dst_port, ¶m); |
359 | 359 | ||
360 | cp = ip_vs_conn_new(¶m, &dest->addr, dport, flags, dest, skb->mark); | 360 | cp = ip_vs_conn_new(¶m, dest->af, &dest->addr, dport, flags, dest, |
361 | skb->mark); | ||
361 | if (cp == NULL) { | 362 | if (cp == NULL) { |
362 | ip_vs_conn_put(ct); | 363 | ip_vs_conn_put(ct); |
363 | *ignored = -1; | 364 | *ignored = -1; |
@@ -479,7 +480,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
479 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, | 480 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, |
480 | &iph->saddr, pptr[0], &iph->daddr, | 481 | &iph->saddr, pptr[0], &iph->daddr, |
481 | pptr[1], &p); | 482 | pptr[1], &p); |
482 | cp = ip_vs_conn_new(&p, &dest->addr, | 483 | cp = ip_vs_conn_new(&p, dest->af, &dest->addr, |
483 | dest->port ? dest->port : pptr[1], | 484 | dest->port ? dest->port : pptr[1], |
484 | flags, dest, skb->mark); | 485 | flags, dest, skb->mark); |
485 | if (!cp) { | 486 | if (!cp) { |
@@ -491,9 +492,9 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, | |||
491 | IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u " | 492 | IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u " |
492 | "d:%s:%u conn->flags:%X conn->refcnt:%d\n", | 493 | "d:%s:%u conn->flags:%X conn->refcnt:%d\n", |
493 | ip_vs_fwd_tag(cp), | 494 | ip_vs_fwd_tag(cp), |
494 | IP_VS_DBG_ADDR(svc->af, &cp->caddr), ntohs(cp->cport), | 495 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), ntohs(cp->cport), |
495 | IP_VS_DBG_ADDR(svc->af, &cp->vaddr), ntohs(cp->vport), | 496 | IP_VS_DBG_ADDR(cp->af, &cp->vaddr), ntohs(cp->vport), |
496 | IP_VS_DBG_ADDR(svc->af, &cp->daddr), ntohs(cp->dport), | 497 | IP_VS_DBG_ADDR(cp->daf, &cp->daddr), ntohs(cp->dport), |
497 | cp->flags, atomic_read(&cp->refcnt)); | 498 | cp->flags, atomic_read(&cp->refcnt)); |
498 | 499 | ||
499 | ip_vs_conn_stats(cp, svc); | 500 | ip_vs_conn_stats(cp, svc); |
@@ -550,7 +551,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, | |||
550 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, | 551 | ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, |
551 | &iph->saddr, pptr[0], | 552 | &iph->saddr, pptr[0], |
552 | &iph->daddr, pptr[1], &p); | 553 | &iph->daddr, pptr[1], &p); |
553 | cp = ip_vs_conn_new(&p, &daddr, 0, | 554 | cp = ip_vs_conn_new(&p, svc->af, &daddr, 0, |
554 | IP_VS_CONN_F_BYPASS | flags, | 555 | IP_VS_CONN_F_BYPASS | flags, |
555 | NULL, skb->mark); | 556 | NULL, skb->mark); |
556 | if (!cp) | 557 | if (!cp) |
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index bd2b208ba56c..ac7ba689efe7 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c | |||
@@ -574,8 +574,8 @@ bool ip_vs_has_real_service(struct net *net, int af, __u16 protocol, | |||
574 | * Called under RCU lock. | 574 | * Called under RCU lock. |
575 | */ | 575 | */ |
576 | static struct ip_vs_dest * | 576 | static struct ip_vs_dest * |
577 | ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, | 577 | ip_vs_lookup_dest(struct ip_vs_service *svc, int dest_af, |
578 | __be16 dport) | 578 | const union nf_inet_addr *daddr, __be16 dport) |
579 | { | 579 | { |
580 | struct ip_vs_dest *dest; | 580 | struct ip_vs_dest *dest; |
581 | 581 | ||
@@ -583,9 +583,9 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, | |||
583 | * Find the destination for the given service | 583 | * Find the destination for the given service |
584 | */ | 584 | */ |
585 | list_for_each_entry_rcu(dest, &svc->destinations, n_list) { | 585 | list_for_each_entry_rcu(dest, &svc->destinations, n_list) { |
586 | if ((dest->af == svc->af) | 586 | if ((dest->af == dest_af) && |
587 | && ip_vs_addr_equal(svc->af, &dest->addr, daddr) | 587 | ip_vs_addr_equal(dest_af, &dest->addr, daddr) && |
588 | && (dest->port == dport)) { | 588 | (dest->port == dport)) { |
589 | /* HIT */ | 589 | /* HIT */ |
590 | return dest; | 590 | return dest; |
591 | } | 591 | } |
@@ -602,7 +602,7 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, | |||
602 | * on the backup. | 602 | * on the backup. |
603 | * Called under RCU lock, no refcnt is returned. | 603 | * Called under RCU lock, no refcnt is returned. |
604 | */ | 604 | */ |
605 | struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af, | 605 | struct ip_vs_dest *ip_vs_find_dest(struct net *net, int svc_af, int dest_af, |
606 | const union nf_inet_addr *daddr, | 606 | const union nf_inet_addr *daddr, |
607 | __be16 dport, | 607 | __be16 dport, |
608 | const union nf_inet_addr *vaddr, | 608 | const union nf_inet_addr *vaddr, |
@@ -613,14 +613,14 @@ struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af, | |||
613 | struct ip_vs_service *svc; | 613 | struct ip_vs_service *svc; |
614 | __be16 port = dport; | 614 | __be16 port = dport; |
615 | 615 | ||
616 | svc = ip_vs_service_find(net, af, fwmark, protocol, vaddr, vport); | 616 | svc = ip_vs_service_find(net, svc_af, fwmark, protocol, vaddr, vport); |
617 | if (!svc) | 617 | if (!svc) |
618 | return NULL; | 618 | return NULL; |
619 | if (fwmark && (flags & IP_VS_CONN_F_FWD_MASK) != IP_VS_CONN_F_MASQ) | 619 | if (fwmark && (flags & IP_VS_CONN_F_FWD_MASK) != IP_VS_CONN_F_MASQ) |
620 | port = 0; | 620 | port = 0; |
621 | dest = ip_vs_lookup_dest(svc, daddr, port); | 621 | dest = ip_vs_lookup_dest(svc, dest_af, daddr, port); |
622 | if (!dest) | 622 | if (!dest) |
623 | dest = ip_vs_lookup_dest(svc, daddr, port ^ dport); | 623 | dest = ip_vs_lookup_dest(svc, dest_af, daddr, port ^ dport); |
624 | return dest; | 624 | return dest; |
625 | } | 625 | } |
626 | 626 | ||
@@ -657,8 +657,8 @@ static void __ip_vs_dst_cache_reset(struct ip_vs_dest *dest) | |||
657 | * scheduling. | 657 | * scheduling. |
658 | */ | 658 | */ |
659 | static struct ip_vs_dest * | 659 | static struct ip_vs_dest * |
660 | ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, | 660 | ip_vs_trash_get_dest(struct ip_vs_service *svc, int dest_af, |
661 | __be16 dport) | 661 | const union nf_inet_addr *daddr, __be16 dport) |
662 | { | 662 | { |
663 | struct ip_vs_dest *dest; | 663 | struct ip_vs_dest *dest; |
664 | struct netns_ipvs *ipvs = net_ipvs(svc->net); | 664 | struct netns_ipvs *ipvs = net_ipvs(svc->net); |
@@ -671,11 +671,11 @@ ip_vs_trash_get_dest(struct ip_vs_service *svc, const union nf_inet_addr *daddr, | |||
671 | IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, " | 671 | IP_VS_DBG_BUF(3, "Destination %u/%s:%u still in trash, " |
672 | "dest->refcnt=%d\n", | 672 | "dest->refcnt=%d\n", |
673 | dest->vfwmark, | 673 | dest->vfwmark, |
674 | IP_VS_DBG_ADDR(svc->af, &dest->addr), | 674 | IP_VS_DBG_ADDR(dest->af, &dest->addr), |
675 | ntohs(dest->port), | 675 | ntohs(dest->port), |
676 | atomic_read(&dest->refcnt)); | 676 | atomic_read(&dest->refcnt)); |
677 | if (dest->af == svc->af && | 677 | if (dest->af == dest_af && |
678 | ip_vs_addr_equal(svc->af, &dest->addr, daddr) && | 678 | ip_vs_addr_equal(dest_af, &dest->addr, daddr) && |
679 | dest->port == dport && | 679 | dest->port == dport && |
680 | dest->vfwmark == svc->fwmark && | 680 | dest->vfwmark == svc->fwmark && |
681 | dest->protocol == svc->protocol && | 681 | dest->protocol == svc->protocol && |
@@ -779,6 +779,12 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest, | |||
779 | struct ip_vs_scheduler *sched; | 779 | struct ip_vs_scheduler *sched; |
780 | int conn_flags; | 780 | int conn_flags; |
781 | 781 | ||
782 | /* We cannot modify an address and change the address family */ | ||
783 | BUG_ON(!add && udest->af != dest->af); | ||
784 | |||
785 | if (add && udest->af != svc->af) | ||
786 | ipvs->mixed_address_family_dests++; | ||
787 | |||
782 | /* set the weight and the flags */ | 788 | /* set the weight and the flags */ |
783 | atomic_set(&dest->weight, udest->weight); | 789 | atomic_set(&dest->weight, udest->weight); |
784 | conn_flags = udest->conn_flags & IP_VS_CONN_F_DEST_MASK; | 790 | conn_flags = udest->conn_flags & IP_VS_CONN_F_DEST_MASK; |
@@ -816,6 +822,8 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest, | |||
816 | dest->u_threshold = udest->u_threshold; | 822 | dest->u_threshold = udest->u_threshold; |
817 | dest->l_threshold = udest->l_threshold; | 823 | dest->l_threshold = udest->l_threshold; |
818 | 824 | ||
825 | dest->af = udest->af; | ||
826 | |||
819 | spin_lock_bh(&dest->dst_lock); | 827 | spin_lock_bh(&dest->dst_lock); |
820 | __ip_vs_dst_cache_reset(dest); | 828 | __ip_vs_dst_cache_reset(dest); |
821 | spin_unlock_bh(&dest->dst_lock); | 829 | spin_unlock_bh(&dest->dst_lock); |
@@ -847,7 +855,7 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, | |||
847 | EnterFunction(2); | 855 | EnterFunction(2); |
848 | 856 | ||
849 | #ifdef CONFIG_IP_VS_IPV6 | 857 | #ifdef CONFIG_IP_VS_IPV6 |
850 | if (svc->af == AF_INET6) { | 858 | if (udest->af == AF_INET6) { |
851 | atype = ipv6_addr_type(&udest->addr.in6); | 859 | atype = ipv6_addr_type(&udest->addr.in6); |
852 | if ((!(atype & IPV6_ADDR_UNICAST) || | 860 | if ((!(atype & IPV6_ADDR_UNICAST) || |
853 | atype & IPV6_ADDR_LINKLOCAL) && | 861 | atype & IPV6_ADDR_LINKLOCAL) && |
@@ -875,12 +883,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, | |||
875 | u64_stats_init(&ip_vs_dest_stats->syncp); | 883 | u64_stats_init(&ip_vs_dest_stats->syncp); |
876 | } | 884 | } |
877 | 885 | ||
878 | dest->af = svc->af; | 886 | dest->af = udest->af; |
879 | dest->protocol = svc->protocol; | 887 | dest->protocol = svc->protocol; |
880 | dest->vaddr = svc->addr; | 888 | dest->vaddr = svc->addr; |
881 | dest->vport = svc->port; | 889 | dest->vport = svc->port; |
882 | dest->vfwmark = svc->fwmark; | 890 | dest->vfwmark = svc->fwmark; |
883 | ip_vs_addr_copy(svc->af, &dest->addr, &udest->addr); | 891 | ip_vs_addr_copy(udest->af, &dest->addr, &udest->addr); |
884 | dest->port = udest->port; | 892 | dest->port = udest->port; |
885 | 893 | ||
886 | atomic_set(&dest->activeconns, 0); | 894 | atomic_set(&dest->activeconns, 0); |
@@ -928,11 +936,11 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) | |||
928 | return -ERANGE; | 936 | return -ERANGE; |
929 | } | 937 | } |
930 | 938 | ||
931 | ip_vs_addr_copy(svc->af, &daddr, &udest->addr); | 939 | ip_vs_addr_copy(udest->af, &daddr, &udest->addr); |
932 | 940 | ||
933 | /* We use function that requires RCU lock */ | 941 | /* We use function that requires RCU lock */ |
934 | rcu_read_lock(); | 942 | rcu_read_lock(); |
935 | dest = ip_vs_lookup_dest(svc, &daddr, dport); | 943 | dest = ip_vs_lookup_dest(svc, udest->af, &daddr, dport); |
936 | rcu_read_unlock(); | 944 | rcu_read_unlock(); |
937 | 945 | ||
938 | if (dest != NULL) { | 946 | if (dest != NULL) { |
@@ -944,12 +952,12 @@ ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) | |||
944 | * Check if the dest already exists in the trash and | 952 | * Check if the dest already exists in the trash and |
945 | * is from the same service | 953 | * is from the same service |
946 | */ | 954 | */ |
947 | dest = ip_vs_trash_get_dest(svc, &daddr, dport); | 955 | dest = ip_vs_trash_get_dest(svc, udest->af, &daddr, dport); |
948 | 956 | ||
949 | if (dest != NULL) { | 957 | if (dest != NULL) { |
950 | IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, " | 958 | IP_VS_DBG_BUF(3, "Get destination %s:%u from trash, " |
951 | "dest->refcnt=%d, service %u/%s:%u\n", | 959 | "dest->refcnt=%d, service %u/%s:%u\n", |
952 | IP_VS_DBG_ADDR(svc->af, &daddr), ntohs(dport), | 960 | IP_VS_DBG_ADDR(udest->af, &daddr), ntohs(dport), |
953 | atomic_read(&dest->refcnt), | 961 | atomic_read(&dest->refcnt), |
954 | dest->vfwmark, | 962 | dest->vfwmark, |
955 | IP_VS_DBG_ADDR(svc->af, &dest->vaddr), | 963 | IP_VS_DBG_ADDR(svc->af, &dest->vaddr), |
@@ -992,11 +1000,11 @@ ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) | |||
992 | return -ERANGE; | 1000 | return -ERANGE; |
993 | } | 1001 | } |
994 | 1002 | ||
995 | ip_vs_addr_copy(svc->af, &daddr, &udest->addr); | 1003 | ip_vs_addr_copy(udest->af, &daddr, &udest->addr); |
996 | 1004 | ||
997 | /* We use function that requires RCU lock */ | 1005 | /* We use function that requires RCU lock */ |
998 | rcu_read_lock(); | 1006 | rcu_read_lock(); |
999 | dest = ip_vs_lookup_dest(svc, &daddr, dport); | 1007 | dest = ip_vs_lookup_dest(svc, udest->af, &daddr, dport); |
1000 | rcu_read_unlock(); | 1008 | rcu_read_unlock(); |
1001 | 1009 | ||
1002 | if (dest == NULL) { | 1010 | if (dest == NULL) { |
@@ -1055,6 +1063,9 @@ static void __ip_vs_unlink_dest(struct ip_vs_service *svc, | |||
1055 | list_del_rcu(&dest->n_list); | 1063 | list_del_rcu(&dest->n_list); |
1056 | svc->num_dests--; | 1064 | svc->num_dests--; |
1057 | 1065 | ||
1066 | if (dest->af != svc->af) | ||
1067 | net_ipvs(svc->net)->mixed_address_family_dests--; | ||
1068 | |||
1058 | if (svcupd) { | 1069 | if (svcupd) { |
1059 | struct ip_vs_scheduler *sched; | 1070 | struct ip_vs_scheduler *sched; |
1060 | 1071 | ||
@@ -1078,7 +1089,7 @@ ip_vs_del_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest) | |||
1078 | 1089 | ||
1079 | /* We use function that requires RCU lock */ | 1090 | /* We use function that requires RCU lock */ |
1080 | rcu_read_lock(); | 1091 | rcu_read_lock(); |
1081 | dest = ip_vs_lookup_dest(svc, &udest->addr, dport); | 1092 | dest = ip_vs_lookup_dest(svc, udest->af, &udest->addr, dport); |
1082 | rcu_read_unlock(); | 1093 | rcu_read_unlock(); |
1083 | 1094 | ||
1084 | if (dest == NULL) { | 1095 | if (dest == NULL) { |
@@ -2244,6 +2255,7 @@ static void ip_vs_copy_udest_compat(struct ip_vs_dest_user_kern *udest, | |||
2244 | udest->weight = udest_compat->weight; | 2255 | udest->weight = udest_compat->weight; |
2245 | udest->u_threshold = udest_compat->u_threshold; | 2256 | udest->u_threshold = udest_compat->u_threshold; |
2246 | udest->l_threshold = udest_compat->l_threshold; | 2257 | udest->l_threshold = udest_compat->l_threshold; |
2258 | udest->af = AF_INET; | ||
2247 | } | 2259 | } |
2248 | 2260 | ||
2249 | static int | 2261 | static int |
@@ -2480,6 +2492,12 @@ __ip_vs_get_dest_entries(struct net *net, const struct ip_vs_get_dests *get, | |||
2480 | if (count >= get->num_dests) | 2492 | if (count >= get->num_dests) |
2481 | break; | 2493 | break; |
2482 | 2494 | ||
2495 | /* Cannot expose heterogeneous members via sockopt | ||
2496 | * interface | ||
2497 | */ | ||
2498 | if (dest->af != svc->af) | ||
2499 | continue; | ||
2500 | |||
2483 | entry.addr = dest->addr.ip; | 2501 | entry.addr = dest->addr.ip; |
2484 | entry.port = dest->port; | 2502 | entry.port = dest->port; |
2485 | entry.conn_flags = atomic_read(&dest->conn_flags); | 2503 | entry.conn_flags = atomic_read(&dest->conn_flags); |
@@ -2777,6 +2795,7 @@ static const struct nla_policy ip_vs_dest_policy[IPVS_DEST_ATTR_MAX + 1] = { | |||
2777 | [IPVS_DEST_ATTR_INACT_CONNS] = { .type = NLA_U32 }, | 2795 | [IPVS_DEST_ATTR_INACT_CONNS] = { .type = NLA_U32 }, |
2778 | [IPVS_DEST_ATTR_PERSIST_CONNS] = { .type = NLA_U32 }, | 2796 | [IPVS_DEST_ATTR_PERSIST_CONNS] = { .type = NLA_U32 }, |
2779 | [IPVS_DEST_ATTR_STATS] = { .type = NLA_NESTED }, | 2797 | [IPVS_DEST_ATTR_STATS] = { .type = NLA_NESTED }, |
2798 | [IPVS_DEST_ATTR_ADDR_FAMILY] = { .type = NLA_U16 }, | ||
2780 | }; | 2799 | }; |
2781 | 2800 | ||
2782 | static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, | 2801 | static int ip_vs_genl_fill_stats(struct sk_buff *skb, int container_type, |
@@ -3032,7 +3051,8 @@ static int ip_vs_genl_fill_dest(struct sk_buff *skb, struct ip_vs_dest *dest) | |||
3032 | nla_put_u32(skb, IPVS_DEST_ATTR_INACT_CONNS, | 3051 | nla_put_u32(skb, IPVS_DEST_ATTR_INACT_CONNS, |
3033 | atomic_read(&dest->inactconns)) || | 3052 | atomic_read(&dest->inactconns)) || |
3034 | nla_put_u32(skb, IPVS_DEST_ATTR_PERSIST_CONNS, | 3053 | nla_put_u32(skb, IPVS_DEST_ATTR_PERSIST_CONNS, |
3035 | atomic_read(&dest->persistconns))) | 3054 | atomic_read(&dest->persistconns)) || |
3055 | nla_put_u16(skb, IPVS_DEST_ATTR_ADDR_FAMILY, dest->af)) | ||
3036 | goto nla_put_failure; | 3056 | goto nla_put_failure; |
3037 | if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats)) | 3057 | if (ip_vs_genl_fill_stats(skb, IPVS_DEST_ATTR_STATS, &dest->stats)) |
3038 | goto nla_put_failure; | 3058 | goto nla_put_failure; |
@@ -3113,6 +3133,7 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest, | |||
3113 | { | 3133 | { |
3114 | struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; | 3134 | struct nlattr *attrs[IPVS_DEST_ATTR_MAX + 1]; |
3115 | struct nlattr *nla_addr, *nla_port; | 3135 | struct nlattr *nla_addr, *nla_port; |
3136 | struct nlattr *nla_addr_family; | ||
3116 | 3137 | ||
3117 | /* Parse mandatory identifying destination fields first */ | 3138 | /* Parse mandatory identifying destination fields first */ |
3118 | if (nla == NULL || | 3139 | if (nla == NULL || |
@@ -3121,6 +3142,7 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest, | |||
3121 | 3142 | ||
3122 | nla_addr = attrs[IPVS_DEST_ATTR_ADDR]; | 3143 | nla_addr = attrs[IPVS_DEST_ATTR_ADDR]; |
3123 | nla_port = attrs[IPVS_DEST_ATTR_PORT]; | 3144 | nla_port = attrs[IPVS_DEST_ATTR_PORT]; |
3145 | nla_addr_family = attrs[IPVS_DEST_ATTR_ADDR_FAMILY]; | ||
3124 | 3146 | ||
3125 | if (!(nla_addr && nla_port)) | 3147 | if (!(nla_addr && nla_port)) |
3126 | return -EINVAL; | 3148 | return -EINVAL; |
@@ -3130,6 +3152,11 @@ static int ip_vs_genl_parse_dest(struct ip_vs_dest_user_kern *udest, | |||
3130 | nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr)); | 3152 | nla_memcpy(&udest->addr, nla_addr, sizeof(udest->addr)); |
3131 | udest->port = nla_get_be16(nla_port); | 3153 | udest->port = nla_get_be16(nla_port); |
3132 | 3154 | ||
3155 | if (nla_addr_family) | ||
3156 | udest->af = nla_get_u16(nla_addr_family); | ||
3157 | else | ||
3158 | udest->af = 0; | ||
3159 | |||
3133 | /* If a full entry was requested, check for the additional fields */ | 3160 | /* If a full entry was requested, check for the additional fields */ |
3134 | if (full_entry) { | 3161 | if (full_entry) { |
3135 | struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh, | 3162 | struct nlattr *nla_fwd, *nla_weight, *nla_u_thresh, |
@@ -3234,6 +3261,12 @@ static int ip_vs_genl_new_daemon(struct net *net, struct nlattr **attrs) | |||
3234 | attrs[IPVS_DAEMON_ATTR_SYNC_ID])) | 3261 | attrs[IPVS_DAEMON_ATTR_SYNC_ID])) |
3235 | return -EINVAL; | 3262 | return -EINVAL; |
3236 | 3263 | ||
3264 | /* The synchronization protocol is incompatible with mixed family | ||
3265 | * services | ||
3266 | */ | ||
3267 | if (net_ipvs(net)->mixed_address_family_dests > 0) | ||
3268 | return -EINVAL; | ||
3269 | |||
3237 | return start_sync_thread(net, | 3270 | return start_sync_thread(net, |
3238 | nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]), | 3271 | nla_get_u32(attrs[IPVS_DAEMON_ATTR_STATE]), |
3239 | nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), | 3272 | nla_data(attrs[IPVS_DAEMON_ATTR_MCAST_IFN]), |
@@ -3357,6 +3390,35 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) | |||
3357 | need_full_dest); | 3390 | need_full_dest); |
3358 | if (ret) | 3391 | if (ret) |
3359 | goto out; | 3392 | goto out; |
3393 | |||
3394 | /* Old protocols did not allow the user to specify address | ||
3395 | * family, so we set it to zero instead. We also didn't | ||
3396 | * allow heterogeneous pools in the old code, so it's safe | ||
3397 | * to assume that this will have the same address family as | ||
3398 | * the service. | ||
3399 | */ | ||
3400 | if (udest.af == 0) | ||
3401 | udest.af = svc->af; | ||
3402 | |||
3403 | if (udest.af != svc->af) { | ||
3404 | /* The synchronization protocol is incompatible | ||
3405 | * with mixed family services | ||
3406 | */ | ||
3407 | if (net_ipvs(net)->sync_state) { | ||
3408 | ret = -EINVAL; | ||
3409 | goto out; | ||
3410 | } | ||
3411 | |||
3412 | /* Which connection types do we support? */ | ||
3413 | switch (udest.conn_flags) { | ||
3414 | case IP_VS_CONN_F_TUNNEL: | ||
3415 | /* We are able to forward this */ | ||
3416 | break; | ||
3417 | default: | ||
3418 | ret = -EINVAL; | ||
3419 | goto out; | ||
3420 | } | ||
3421 | } | ||
3360 | } | 3422 | } |
3361 | 3423 | ||
3362 | switch (cmd) { | 3424 | switch (cmd) { |
diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c index c3b84546ea9e..6be5c538b71e 100644 --- a/net/netfilter/ipvs/ip_vs_dh.c +++ b/net/netfilter/ipvs/ip_vs_dh.c | |||
@@ -234,7 +234,7 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
234 | 234 | ||
235 | IP_VS_DBG_BUF(6, "DH: destination IP address %s --> server %s:%d\n", | 235 | IP_VS_DBG_BUF(6, "DH: destination IP address %s --> server %s:%d\n", |
236 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), | 236 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), |
237 | IP_VS_DBG_ADDR(svc->af, &dest->addr), | 237 | IP_VS_DBG_ADDR(dest->af, &dest->addr), |
238 | ntohs(dest->port)); | 238 | ntohs(dest->port)); |
239 | 239 | ||
240 | return dest; | 240 | return dest; |
diff --git a/net/netfilter/ipvs/ip_vs_fo.c b/net/netfilter/ipvs/ip_vs_fo.c new file mode 100644 index 000000000000..e09874d02938 --- /dev/null +++ b/net/netfilter/ipvs/ip_vs_fo.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * IPVS: Weighted Fail Over module | ||
3 | * | ||
4 | * Authors: Kenny Mathis <kmathis@chokepoint.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * Changes: | ||
12 | * Kenny Mathis : added initial functionality based on weight | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #define KMSG_COMPONENT "IPVS" | ||
17 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | |||
22 | #include <net/ip_vs.h> | ||
23 | |||
24 | /* Weighted Fail Over Module */ | ||
25 | static struct ip_vs_dest * | ||
26 | ip_vs_fo_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | ||
27 | struct ip_vs_iphdr *iph) | ||
28 | { | ||
29 | struct ip_vs_dest *dest, *hweight = NULL; | ||
30 | int hw = 0; /* Track highest weight */ | ||
31 | |||
32 | IP_VS_DBG(6, "ip_vs_fo_schedule(): Scheduling...\n"); | ||
33 | |||
34 | /* Basic failover functionality | ||
35 | * Find virtual server with highest weight and send it traffic | ||
36 | */ | ||
37 | list_for_each_entry_rcu(dest, &svc->destinations, n_list) { | ||
38 | if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) && | ||
39 | atomic_read(&dest->weight) > hw) { | ||
40 | hweight = dest; | ||
41 | hw = atomic_read(&dest->weight); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | if (hweight) { | ||
46 | IP_VS_DBG_BUF(6, "FO: server %s:%u activeconns %d weight %d\n", | ||
47 | IP_VS_DBG_ADDR(hweight->af, &hweight->addr), | ||
48 | ntohs(hweight->port), | ||
49 | atomic_read(&hweight->activeconns), | ||
50 | atomic_read(&hweight->weight)); | ||
51 | return hweight; | ||
52 | } | ||
53 | |||
54 | ip_vs_scheduler_err(svc, "no destination available"); | ||
55 | return NULL; | ||
56 | } | ||
57 | |||
58 | static struct ip_vs_scheduler ip_vs_fo_scheduler = { | ||
59 | .name = "fo", | ||
60 | .refcnt = ATOMIC_INIT(0), | ||
61 | .module = THIS_MODULE, | ||
62 | .n_list = LIST_HEAD_INIT(ip_vs_fo_scheduler.n_list), | ||
63 | .schedule = ip_vs_fo_schedule, | ||
64 | }; | ||
65 | |||
66 | static int __init ip_vs_fo_init(void) | ||
67 | { | ||
68 | return register_ip_vs_scheduler(&ip_vs_fo_scheduler); | ||
69 | } | ||
70 | |||
71 | static void __exit ip_vs_fo_cleanup(void) | ||
72 | { | ||
73 | unregister_ip_vs_scheduler(&ip_vs_fo_scheduler); | ||
74 | synchronize_rcu(); | ||
75 | } | ||
76 | |||
77 | module_init(ip_vs_fo_init); | ||
78 | module_exit(ip_vs_fo_cleanup); | ||
79 | MODULE_LICENSE("GPL"); | ||
diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 77c173282f38..a64fa15790e5 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c | |||
@@ -233,7 +233,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
233 | ip_vs_conn_fill_param(ip_vs_conn_net(cp), | 233 | ip_vs_conn_fill_param(ip_vs_conn_net(cp), |
234 | AF_INET, IPPROTO_TCP, &cp->caddr, | 234 | AF_INET, IPPROTO_TCP, &cp->caddr, |
235 | 0, &cp->vaddr, port, &p); | 235 | 0, &cp->vaddr, port, &p); |
236 | n_cp = ip_vs_conn_new(&p, &from, port, | 236 | /* As above, this is ipv4 only */ |
237 | n_cp = ip_vs_conn_new(&p, AF_INET, &from, port, | ||
237 | IP_VS_CONN_F_NO_CPORT | | 238 | IP_VS_CONN_F_NO_CPORT | |
238 | IP_VS_CONN_F_NFCT, | 239 | IP_VS_CONN_F_NFCT, |
239 | cp->dest, skb->mark); | 240 | cp->dest, skb->mark); |
@@ -396,7 +397,8 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, | |||
396 | htons(ntohs(cp->vport)-1), &p); | 397 | htons(ntohs(cp->vport)-1), &p); |
397 | n_cp = ip_vs_conn_in_get(&p); | 398 | n_cp = ip_vs_conn_in_get(&p); |
398 | if (!n_cp) { | 399 | if (!n_cp) { |
399 | n_cp = ip_vs_conn_new(&p, &cp->daddr, | 400 | /* This is ipv4 only */ |
401 | n_cp = ip_vs_conn_new(&p, AF_INET, &cp->daddr, | ||
400 | htons(ntohs(cp->dport)-1), | 402 | htons(ntohs(cp->dport)-1), |
401 | IP_VS_CONN_F_NFCT, cp->dest, | 403 | IP_VS_CONN_F_NFCT, cp->dest, |
402 | skb->mark); | 404 | skb->mark); |
diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 547ff33c1efd..127f14046c51 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c | |||
@@ -199,11 +199,11 @@ ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl, | |||
199 | */ | 199 | */ |
200 | static inline struct ip_vs_lblc_entry * | 200 | static inline struct ip_vs_lblc_entry * |
201 | ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, | 201 | ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, |
202 | struct ip_vs_dest *dest) | 202 | u16 af, struct ip_vs_dest *dest) |
203 | { | 203 | { |
204 | struct ip_vs_lblc_entry *en; | 204 | struct ip_vs_lblc_entry *en; |
205 | 205 | ||
206 | en = ip_vs_lblc_get(dest->af, tbl, daddr); | 206 | en = ip_vs_lblc_get(af, tbl, daddr); |
207 | if (en) { | 207 | if (en) { |
208 | if (en->dest == dest) | 208 | if (en->dest == dest) |
209 | return en; | 209 | return en; |
@@ -213,8 +213,8 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, | |||
213 | if (!en) | 213 | if (!en) |
214 | return NULL; | 214 | return NULL; |
215 | 215 | ||
216 | en->af = dest->af; | 216 | en->af = af; |
217 | ip_vs_addr_copy(dest->af, &en->addr, daddr); | 217 | ip_vs_addr_copy(af, &en->addr, daddr); |
218 | en->lastuse = jiffies; | 218 | en->lastuse = jiffies; |
219 | 219 | ||
220 | ip_vs_dest_hold(dest); | 220 | ip_vs_dest_hold(dest); |
@@ -521,13 +521,13 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
521 | /* If we fail to create a cache entry, we'll just use the valid dest */ | 521 | /* If we fail to create a cache entry, we'll just use the valid dest */ |
522 | spin_lock_bh(&svc->sched_lock); | 522 | spin_lock_bh(&svc->sched_lock); |
523 | if (!tbl->dead) | 523 | if (!tbl->dead) |
524 | ip_vs_lblc_new(tbl, &iph->daddr, dest); | 524 | ip_vs_lblc_new(tbl, &iph->daddr, svc->af, dest); |
525 | spin_unlock_bh(&svc->sched_lock); | 525 | spin_unlock_bh(&svc->sched_lock); |
526 | 526 | ||
527 | out: | 527 | out: |
528 | IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n", | 528 | IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n", |
529 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), | 529 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), |
530 | IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port)); | 530 | IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port)); |
531 | 531 | ||
532 | return dest; | 532 | return dest; |
533 | } | 533 | } |
diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 3f21a2f47de1..2229d2d8bbe0 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c | |||
@@ -362,18 +362,18 @@ ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl, | |||
362 | */ | 362 | */ |
363 | static inline struct ip_vs_lblcr_entry * | 363 | static inline struct ip_vs_lblcr_entry * |
364 | ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, | 364 | ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, |
365 | struct ip_vs_dest *dest) | 365 | u16 af, struct ip_vs_dest *dest) |
366 | { | 366 | { |
367 | struct ip_vs_lblcr_entry *en; | 367 | struct ip_vs_lblcr_entry *en; |
368 | 368 | ||
369 | en = ip_vs_lblcr_get(dest->af, tbl, daddr); | 369 | en = ip_vs_lblcr_get(af, tbl, daddr); |
370 | if (!en) { | 370 | if (!en) { |
371 | en = kmalloc(sizeof(*en), GFP_ATOMIC); | 371 | en = kmalloc(sizeof(*en), GFP_ATOMIC); |
372 | if (!en) | 372 | if (!en) |
373 | return NULL; | 373 | return NULL; |
374 | 374 | ||
375 | en->af = dest->af; | 375 | en->af = af; |
376 | ip_vs_addr_copy(dest->af, &en->addr, daddr); | 376 | ip_vs_addr_copy(af, &en->addr, daddr); |
377 | en->lastuse = jiffies; | 377 | en->lastuse = jiffies; |
378 | 378 | ||
379 | /* initialize its dest set */ | 379 | /* initialize its dest set */ |
@@ -706,13 +706,13 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
706 | /* If we fail to create a cache entry, we'll just use the valid dest */ | 706 | /* If we fail to create a cache entry, we'll just use the valid dest */ |
707 | spin_lock_bh(&svc->sched_lock); | 707 | spin_lock_bh(&svc->sched_lock); |
708 | if (!tbl->dead) | 708 | if (!tbl->dead) |
709 | ip_vs_lblcr_new(tbl, &iph->daddr, dest); | 709 | ip_vs_lblcr_new(tbl, &iph->daddr, svc->af, dest); |
710 | spin_unlock_bh(&svc->sched_lock); | 710 | spin_unlock_bh(&svc->sched_lock); |
711 | 711 | ||
712 | out: | 712 | out: |
713 | IP_VS_DBG_BUF(6, "LBLCR: destination IP address %s --> server %s:%d\n", | 713 | IP_VS_DBG_BUF(6, "LBLCR: destination IP address %s --> server %s:%d\n", |
714 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), | 714 | IP_VS_DBG_ADDR(svc->af, &iph->daddr), |
715 | IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port)); | 715 | IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port)); |
716 | 716 | ||
717 | return dest; | 717 | return dest; |
718 | } | 718 | } |
diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c index 2bdcb1cf2127..19a0769a989a 100644 --- a/net/netfilter/ipvs/ip_vs_lc.c +++ b/net/netfilter/ipvs/ip_vs_lc.c | |||
@@ -59,7 +59,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
59 | else | 59 | else |
60 | IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d " | 60 | IP_VS_DBG_BUF(6, "LC: server %s:%u activeconns %d " |
61 | "inactconns %d\n", | 61 | "inactconns %d\n", |
62 | IP_VS_DBG_ADDR(svc->af, &least->addr), | 62 | IP_VS_DBG_ADDR(least->af, &least->addr), |
63 | ntohs(least->port), | 63 | ntohs(least->port), |
64 | atomic_read(&least->activeconns), | 64 | atomic_read(&least->activeconns), |
65 | atomic_read(&least->inactconns)); | 65 | atomic_read(&least->inactconns)); |
diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c index 961a6de9bb29..a8b63401e773 100644 --- a/net/netfilter/ipvs/ip_vs_nq.c +++ b/net/netfilter/ipvs/ip_vs_nq.c | |||
@@ -107,7 +107,8 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
107 | out: | 107 | out: |
108 | IP_VS_DBG_BUF(6, "NQ: server %s:%u " | 108 | IP_VS_DBG_BUF(6, "NQ: server %s:%u " |
109 | "activeconns %d refcnt %d weight %d overhead %d\n", | 109 | "activeconns %d refcnt %d weight %d overhead %d\n", |
110 | IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port), | 110 | IP_VS_DBG_ADDR(least->af, &least->addr), |
111 | ntohs(least->port), | ||
111 | atomic_read(&least->activeconns), | 112 | atomic_read(&least->activeconns), |
112 | atomic_read(&least->refcnt), | 113 | atomic_read(&least->refcnt), |
113 | atomic_read(&least->weight), loh); | 114 | atomic_read(&least->weight), loh); |
diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index 2f7ea7564044..5b84c0b56642 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c | |||
@@ -432,7 +432,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, | |||
432 | pd->pp->name, | 432 | pd->pp->name, |
433 | ((direction == IP_VS_DIR_OUTPUT) ? | 433 | ((direction == IP_VS_DIR_OUTPUT) ? |
434 | "output " : "input "), | 434 | "output " : "input "), |
435 | IP_VS_DBG_ADDR(cp->af, &cp->daddr), | 435 | IP_VS_DBG_ADDR(cp->daf, &cp->daddr), |
436 | ntohs(cp->dport), | 436 | ntohs(cp->dport), |
437 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), | 437 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), |
438 | ntohs(cp->cport), | 438 | ntohs(cp->cport), |
diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index e3a697234a98..8e92beb0cca9 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c | |||
@@ -510,7 +510,7 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, | |||
510 | th->fin ? 'F' : '.', | 510 | th->fin ? 'F' : '.', |
511 | th->ack ? 'A' : '.', | 511 | th->ack ? 'A' : '.', |
512 | th->rst ? 'R' : '.', | 512 | th->rst ? 'R' : '.', |
513 | IP_VS_DBG_ADDR(cp->af, &cp->daddr), | 513 | IP_VS_DBG_ADDR(cp->daf, &cp->daddr), |
514 | ntohs(cp->dport), | 514 | ntohs(cp->dport), |
515 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), | 515 | IP_VS_DBG_ADDR(cp->af, &cp->caddr), |
516 | ntohs(cp->cport), | 516 | ntohs(cp->cport), |
diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c index 176b87c35e34..58bacfc461ee 100644 --- a/net/netfilter/ipvs/ip_vs_rr.c +++ b/net/netfilter/ipvs/ip_vs_rr.c | |||
@@ -95,7 +95,7 @@ stop: | |||
95 | spin_unlock_bh(&svc->sched_lock); | 95 | spin_unlock_bh(&svc->sched_lock); |
96 | IP_VS_DBG_BUF(6, "RR: server %s:%u " | 96 | IP_VS_DBG_BUF(6, "RR: server %s:%u " |
97 | "activeconns %d refcnt %d weight %d\n", | 97 | "activeconns %d refcnt %d weight %d\n", |
98 | IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port), | 98 | IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port), |
99 | atomic_read(&dest->activeconns), | 99 | atomic_read(&dest->activeconns), |
100 | atomic_read(&dest->refcnt), atomic_read(&dest->weight)); | 100 | atomic_read(&dest->refcnt), atomic_read(&dest->weight)); |
101 | 101 | ||
diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c index e446b9fa7424..f8e2d00f528b 100644 --- a/net/netfilter/ipvs/ip_vs_sed.c +++ b/net/netfilter/ipvs/ip_vs_sed.c | |||
@@ -108,7 +108,8 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
108 | 108 | ||
109 | IP_VS_DBG_BUF(6, "SED: server %s:%u " | 109 | IP_VS_DBG_BUF(6, "SED: server %s:%u " |
110 | "activeconns %d refcnt %d weight %d overhead %d\n", | 110 | "activeconns %d refcnt %d weight %d overhead %d\n", |
111 | IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port), | 111 | IP_VS_DBG_ADDR(least->af, &least->addr), |
112 | ntohs(least->port), | ||
112 | atomic_read(&least->activeconns), | 113 | atomic_read(&least->activeconns), |
113 | atomic_read(&least->refcnt), | 114 | atomic_read(&least->refcnt), |
114 | atomic_read(&least->weight), loh); | 115 | atomic_read(&least->weight), loh); |
diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index cc65b2f42cd4..98a13433b68c 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c | |||
@@ -138,7 +138,7 @@ ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s, | |||
138 | return dest; | 138 | return dest; |
139 | 139 | ||
140 | IP_VS_DBG_BUF(6, "SH: selected unavailable server %s:%d, reselecting", | 140 | IP_VS_DBG_BUF(6, "SH: selected unavailable server %s:%d, reselecting", |
141 | IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port)); | 141 | IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port)); |
142 | 142 | ||
143 | /* if the original dest is unavailable, loop around the table | 143 | /* if the original dest is unavailable, loop around the table |
144 | * starting from ihash to find a new dest | 144 | * starting from ihash to find a new dest |
@@ -153,7 +153,7 @@ ip_vs_sh_get_fallback(struct ip_vs_service *svc, struct ip_vs_sh_state *s, | |||
153 | return dest; | 153 | return dest; |
154 | IP_VS_DBG_BUF(6, "SH: selected unavailable " | 154 | IP_VS_DBG_BUF(6, "SH: selected unavailable " |
155 | "server %s:%d (offset %d), reselecting", | 155 | "server %s:%d (offset %d), reselecting", |
156 | IP_VS_DBG_ADDR(svc->af, &dest->addr), | 156 | IP_VS_DBG_ADDR(dest->af, &dest->addr), |
157 | ntohs(dest->port), roffset); | 157 | ntohs(dest->port), roffset); |
158 | } | 158 | } |
159 | 159 | ||
@@ -192,7 +192,7 @@ ip_vs_sh_reassign(struct ip_vs_sh_state *s, struct ip_vs_service *svc) | |||
192 | RCU_INIT_POINTER(b->dest, dest); | 192 | RCU_INIT_POINTER(b->dest, dest); |
193 | 193 | ||
194 | IP_VS_DBG_BUF(6, "assigned i: %d dest: %s weight: %d\n", | 194 | IP_VS_DBG_BUF(6, "assigned i: %d dest: %s weight: %d\n", |
195 | i, IP_VS_DBG_ADDR(svc->af, &dest->addr), | 195 | i, IP_VS_DBG_ADDR(dest->af, &dest->addr), |
196 | atomic_read(&dest->weight)); | 196 | atomic_read(&dest->weight)); |
197 | 197 | ||
198 | /* Don't move to next dest until filling weight */ | 198 | /* Don't move to next dest until filling weight */ |
@@ -342,7 +342,7 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
342 | 342 | ||
343 | IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n", | 343 | IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n", |
344 | IP_VS_DBG_ADDR(svc->af, &iph->saddr), | 344 | IP_VS_DBG_ADDR(svc->af, &iph->saddr), |
345 | IP_VS_DBG_ADDR(svc->af, &dest->addr), | 345 | IP_VS_DBG_ADDR(dest->af, &dest->addr), |
346 | ntohs(dest->port)); | 346 | ntohs(dest->port)); |
347 | 347 | ||
348 | return dest; | 348 | return dest; |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index eadffb29dec0..7162c86fd50d 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
@@ -880,10 +880,17 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, | |||
880 | * but still handled. | 880 | * but still handled. |
881 | */ | 881 | */ |
882 | rcu_read_lock(); | 882 | rcu_read_lock(); |
883 | dest = ip_vs_find_dest(net, type, daddr, dport, param->vaddr, | 883 | /* This function is only invoked by the synchronization |
884 | param->vport, protocol, fwmark, flags); | 884 | * code. We do not currently support heterogeneous pools |
885 | * with synchronization, so we can make the assumption that | ||
886 | * the svc_af is the same as the dest_af | ||
887 | */ | ||
888 | dest = ip_vs_find_dest(net, type, type, daddr, dport, | ||
889 | param->vaddr, param->vport, protocol, | ||
890 | fwmark, flags); | ||
885 | 891 | ||
886 | cp = ip_vs_conn_new(param, daddr, dport, flags, dest, fwmark); | 892 | cp = ip_vs_conn_new(param, type, daddr, dport, flags, dest, |
893 | fwmark); | ||
887 | rcu_read_unlock(); | 894 | rcu_read_unlock(); |
888 | if (!cp) { | 895 | if (!cp) { |
889 | kfree(param->pe_data); | 896 | kfree(param->pe_data); |
diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c index b5b4650d50a9..6b366fd90554 100644 --- a/net/netfilter/ipvs/ip_vs_wlc.c +++ b/net/netfilter/ipvs/ip_vs_wlc.c | |||
@@ -80,7 +80,8 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
80 | 80 | ||
81 | IP_VS_DBG_BUF(6, "WLC: server %s:%u " | 81 | IP_VS_DBG_BUF(6, "WLC: server %s:%u " |
82 | "activeconns %d refcnt %d weight %d overhead %d\n", | 82 | "activeconns %d refcnt %d weight %d overhead %d\n", |
83 | IP_VS_DBG_ADDR(svc->af, &least->addr), ntohs(least->port), | 83 | IP_VS_DBG_ADDR(least->af, &least->addr), |
84 | ntohs(least->port), | ||
84 | atomic_read(&least->activeconns), | 85 | atomic_read(&least->activeconns), |
85 | atomic_read(&least->refcnt), | 86 | atomic_read(&least->refcnt), |
86 | atomic_read(&least->weight), loh); | 87 | atomic_read(&least->weight), loh); |
diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index 0546cd572d6b..17e6d4406ca7 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c | |||
@@ -216,7 +216,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb, | |||
216 | found: | 216 | found: |
217 | IP_VS_DBG_BUF(6, "WRR: server %s:%u " | 217 | IP_VS_DBG_BUF(6, "WRR: server %s:%u " |
218 | "activeconns %d refcnt %d weight %d\n", | 218 | "activeconns %d refcnt %d weight %d\n", |
219 | IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port), | 219 | IP_VS_DBG_ADDR(dest->af, &dest->addr), ntohs(dest->port), |
220 | atomic_read(&dest->activeconns), | 220 | atomic_read(&dest->activeconns), |
221 | atomic_read(&dest->refcnt), | 221 | atomic_read(&dest->refcnt), |
222 | atomic_read(&dest->weight)); | 222 | atomic_read(&dest->weight)); |
diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index 56896a412bce..91f17c1eb8a2 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c | |||
@@ -157,18 +157,113 @@ retry: | |||
157 | return rt; | 157 | return rt; |
158 | } | 158 | } |
159 | 159 | ||
160 | #ifdef CONFIG_IP_VS_IPV6 | ||
161 | static inline int __ip_vs_is_local_route6(struct rt6_info *rt) | ||
162 | { | ||
163 | return rt->dst.dev && rt->dst.dev->flags & IFF_LOOPBACK; | ||
164 | } | ||
165 | #endif | ||
166 | |||
167 | static inline bool crosses_local_route_boundary(int skb_af, struct sk_buff *skb, | ||
168 | int rt_mode, | ||
169 | bool new_rt_is_local) | ||
170 | { | ||
171 | bool rt_mode_allow_local = !!(rt_mode & IP_VS_RT_MODE_LOCAL); | ||
172 | bool rt_mode_allow_non_local = !!(rt_mode & IP_VS_RT_MODE_LOCAL); | ||
173 | bool rt_mode_allow_redirect = !!(rt_mode & IP_VS_RT_MODE_RDR); | ||
174 | bool source_is_loopback; | ||
175 | bool old_rt_is_local; | ||
176 | |||
177 | #ifdef CONFIG_IP_VS_IPV6 | ||
178 | if (skb_af == AF_INET6) { | ||
179 | int addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr); | ||
180 | |||
181 | source_is_loopback = | ||
182 | (!skb->dev || skb->dev->flags & IFF_LOOPBACK) && | ||
183 | (addr_type & IPV6_ADDR_LOOPBACK); | ||
184 | old_rt_is_local = __ip_vs_is_local_route6( | ||
185 | (struct rt6_info *)skb_dst(skb)); | ||
186 | } else | ||
187 | #endif | ||
188 | { | ||
189 | source_is_loopback = ipv4_is_loopback(ip_hdr(skb)->saddr); | ||
190 | old_rt_is_local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; | ||
191 | } | ||
192 | |||
193 | if (unlikely(new_rt_is_local)) { | ||
194 | if (!rt_mode_allow_local) | ||
195 | return true; | ||
196 | if (!rt_mode_allow_redirect && !old_rt_is_local) | ||
197 | return true; | ||
198 | } else { | ||
199 | if (!rt_mode_allow_non_local) | ||
200 | return true; | ||
201 | if (source_is_loopback) | ||
202 | return true; | ||
203 | } | ||
204 | return false; | ||
205 | } | ||
206 | |||
207 | static inline void maybe_update_pmtu(int skb_af, struct sk_buff *skb, int mtu) | ||
208 | { | ||
209 | struct sock *sk = skb->sk; | ||
210 | struct rtable *ort = skb_rtable(skb); | ||
211 | |||
212 | if (!skb->dev && sk && sk->sk_state != TCP_TIME_WAIT) | ||
213 | ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu); | ||
214 | } | ||
215 | |||
216 | static inline bool ensure_mtu_is_adequate(int skb_af, int rt_mode, | ||
217 | struct ip_vs_iphdr *ipvsh, | ||
218 | struct sk_buff *skb, int mtu) | ||
219 | { | ||
220 | #ifdef CONFIG_IP_VS_IPV6 | ||
221 | if (skb_af == AF_INET6) { | ||
222 | struct net *net = dev_net(skb_dst(skb)->dev); | ||
223 | |||
224 | if (unlikely(__mtu_check_toobig_v6(skb, mtu))) { | ||
225 | if (!skb->dev) | ||
226 | skb->dev = net->loopback_dev; | ||
227 | /* only send ICMP too big on first fragment */ | ||
228 | if (!ipvsh->fragoffs) | ||
229 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | ||
230 | IP_VS_DBG(1, "frag needed for %pI6c\n", | ||
231 | &ipv6_hdr(skb)->saddr); | ||
232 | return false; | ||
233 | } | ||
234 | } else | ||
235 | #endif | ||
236 | { | ||
237 | struct netns_ipvs *ipvs = net_ipvs(skb_net(skb)); | ||
238 | |||
239 | /* If we're going to tunnel the packet and pmtu discovery | ||
240 | * is disabled, we'll just fragment it anyway | ||
241 | */ | ||
242 | if ((rt_mode & IP_VS_RT_MODE_TUNNEL) && !sysctl_pmtu_disc(ipvs)) | ||
243 | return true; | ||
244 | |||
245 | if (unlikely(ip_hdr(skb)->frag_off & htons(IP_DF) && | ||
246 | skb->len > mtu && !skb_is_gso(skb))) { | ||
247 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, | ||
248 | htonl(mtu)); | ||
249 | IP_VS_DBG(1, "frag needed for %pI4\n", | ||
250 | &ip_hdr(skb)->saddr); | ||
251 | return false; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | return true; | ||
256 | } | ||
257 | |||
160 | /* Get route to destination or remote server */ | 258 | /* Get route to destination or remote server */ |
161 | static int | 259 | static int |
162 | __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | 260 | __ip_vs_get_out_rt(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest, |
163 | __be32 daddr, int rt_mode, __be32 *ret_saddr) | 261 | __be32 daddr, int rt_mode, __be32 *ret_saddr, |
262 | struct ip_vs_iphdr *ipvsh) | ||
164 | { | 263 | { |
165 | struct net *net = dev_net(skb_dst(skb)->dev); | 264 | struct net *net = dev_net(skb_dst(skb)->dev); |
166 | struct netns_ipvs *ipvs = net_ipvs(net); | ||
167 | struct ip_vs_dest_dst *dest_dst; | 265 | struct ip_vs_dest_dst *dest_dst; |
168 | struct rtable *rt; /* Route to the other host */ | 266 | struct rtable *rt; /* Route to the other host */ |
169 | struct rtable *ort; /* Original route */ | ||
170 | struct iphdr *iph; | ||
171 | __be16 df; | ||
172 | int mtu; | 267 | int mtu; |
173 | int local, noref = 1; | 268 | int local, noref = 1; |
174 | 269 | ||
@@ -218,30 +313,14 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
218 | } | 313 | } |
219 | 314 | ||
220 | local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0; | 315 | local = (rt->rt_flags & RTCF_LOCAL) ? 1 : 0; |
221 | if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) & | 316 | if (unlikely(crosses_local_route_boundary(skb_af, skb, rt_mode, |
222 | rt_mode)) { | 317 | local))) { |
223 | IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI4\n", | 318 | IP_VS_DBG_RL("We are crossing local and non-local addresses" |
224 | (rt->rt_flags & RTCF_LOCAL) ? | 319 | " daddr=%pI4\n", &dest->addr.ip); |
225 | "local":"non-local", &daddr); | ||
226 | goto err_put; | 320 | goto err_put; |
227 | } | 321 | } |
228 | iph = ip_hdr(skb); | 322 | |
229 | if (likely(!local)) { | 323 | if (unlikely(local)) { |
230 | if (unlikely(ipv4_is_loopback(iph->saddr))) { | ||
231 | IP_VS_DBG_RL("Stopping traffic from loopback address " | ||
232 | "%pI4 to non-local address, dest: %pI4\n", | ||
233 | &iph->saddr, &daddr); | ||
234 | goto err_put; | ||
235 | } | ||
236 | } else { | ||
237 | ort = skb_rtable(skb); | ||
238 | if (!(rt_mode & IP_VS_RT_MODE_RDR) && | ||
239 | !(ort->rt_flags & RTCF_LOCAL)) { | ||
240 | IP_VS_DBG_RL("Redirect from non-local address %pI4 to " | ||
241 | "local requires NAT method, dest: %pI4\n", | ||
242 | &iph->daddr, &daddr); | ||
243 | goto err_put; | ||
244 | } | ||
245 | /* skb to local stack, preserve old route */ | 324 | /* skb to local stack, preserve old route */ |
246 | if (!noref) | 325 | if (!noref) |
247 | ip_rt_put(rt); | 326 | ip_rt_put(rt); |
@@ -250,28 +329,17 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
250 | 329 | ||
251 | if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL))) { | 330 | if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL))) { |
252 | mtu = dst_mtu(&rt->dst); | 331 | mtu = dst_mtu(&rt->dst); |
253 | df = iph->frag_off & htons(IP_DF); | ||
254 | } else { | 332 | } else { |
255 | struct sock *sk = skb->sk; | ||
256 | |||
257 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); | 333 | mtu = dst_mtu(&rt->dst) - sizeof(struct iphdr); |
258 | if (mtu < 68) { | 334 | if (mtu < 68) { |
259 | IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__); | 335 | IP_VS_DBG_RL("%s(): mtu less than 68\n", __func__); |
260 | goto err_put; | 336 | goto err_put; |
261 | } | 337 | } |
262 | ort = skb_rtable(skb); | 338 | maybe_update_pmtu(skb_af, skb, mtu); |
263 | if (!skb->dev && sk && sk->sk_state != TCP_TIME_WAIT) | ||
264 | ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu); | ||
265 | /* MTU check allowed? */ | ||
266 | df = sysctl_pmtu_disc(ipvs) ? iph->frag_off & htons(IP_DF) : 0; | ||
267 | } | 339 | } |
268 | 340 | ||
269 | /* MTU checking */ | 341 | if (!ensure_mtu_is_adequate(skb_af, rt_mode, ipvsh, skb, mtu)) |
270 | if (unlikely(df && skb->len > mtu && !skb_is_gso(skb))) { | ||
271 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); | ||
272 | IP_VS_DBG(1, "frag needed for %pI4\n", &iph->saddr); | ||
273 | goto err_put; | 342 | goto err_put; |
274 | } | ||
275 | 343 | ||
276 | skb_dst_drop(skb); | 344 | skb_dst_drop(skb); |
277 | if (noref) { | 345 | if (noref) { |
@@ -295,12 +363,6 @@ err_unreach: | |||
295 | } | 363 | } |
296 | 364 | ||
297 | #ifdef CONFIG_IP_VS_IPV6 | 365 | #ifdef CONFIG_IP_VS_IPV6 |
298 | |||
299 | static inline int __ip_vs_is_local_route6(struct rt6_info *rt) | ||
300 | { | ||
301 | return rt->dst.dev && rt->dst.dev->flags & IFF_LOOPBACK; | ||
302 | } | ||
303 | |||
304 | static struct dst_entry * | 366 | static struct dst_entry * |
305 | __ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr, | 367 | __ip_vs_route_output_v6(struct net *net, struct in6_addr *daddr, |
306 | struct in6_addr *ret_saddr, int do_xfrm) | 368 | struct in6_addr *ret_saddr, int do_xfrm) |
@@ -339,14 +401,13 @@ out_err: | |||
339 | * Get route to destination or remote server | 401 | * Get route to destination or remote server |
340 | */ | 402 | */ |
341 | static int | 403 | static int |
342 | __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | 404 | __ip_vs_get_out_rt_v6(int skb_af, struct sk_buff *skb, struct ip_vs_dest *dest, |
343 | struct in6_addr *daddr, struct in6_addr *ret_saddr, | 405 | struct in6_addr *daddr, struct in6_addr *ret_saddr, |
344 | struct ip_vs_iphdr *ipvsh, int do_xfrm, int rt_mode) | 406 | struct ip_vs_iphdr *ipvsh, int do_xfrm, int rt_mode) |
345 | { | 407 | { |
346 | struct net *net = dev_net(skb_dst(skb)->dev); | 408 | struct net *net = dev_net(skb_dst(skb)->dev); |
347 | struct ip_vs_dest_dst *dest_dst; | 409 | struct ip_vs_dest_dst *dest_dst; |
348 | struct rt6_info *rt; /* Route to the other host */ | 410 | struct rt6_info *rt; /* Route to the other host */ |
349 | struct rt6_info *ort; /* Original route */ | ||
350 | struct dst_entry *dst; | 411 | struct dst_entry *dst; |
351 | int mtu; | 412 | int mtu; |
352 | int local, noref = 1; | 413 | int local, noref = 1; |
@@ -393,32 +454,15 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
393 | } | 454 | } |
394 | 455 | ||
395 | local = __ip_vs_is_local_route6(rt); | 456 | local = __ip_vs_is_local_route6(rt); |
396 | if (!((local ? IP_VS_RT_MODE_LOCAL : IP_VS_RT_MODE_NON_LOCAL) & | 457 | |
397 | rt_mode)) { | 458 | if (unlikely(crosses_local_route_boundary(skb_af, skb, rt_mode, |
398 | IP_VS_DBG_RL("Stopping traffic to %s address, dest: %pI6c\n", | 459 | local))) { |
399 | local ? "local":"non-local", daddr); | 460 | IP_VS_DBG_RL("We are crossing local and non-local addresses" |
461 | " daddr=%pI6\n", &dest->addr.in6); | ||
400 | goto err_put; | 462 | goto err_put; |
401 | } | 463 | } |
402 | if (likely(!local)) { | 464 | |
403 | if (unlikely((!skb->dev || skb->dev->flags & IFF_LOOPBACK) && | 465 | if (unlikely(local)) { |
404 | ipv6_addr_type(&ipv6_hdr(skb)->saddr) & | ||
405 | IPV6_ADDR_LOOPBACK)) { | ||
406 | IP_VS_DBG_RL("Stopping traffic from loopback address " | ||
407 | "%pI6c to non-local address, " | ||
408 | "dest: %pI6c\n", | ||
409 | &ipv6_hdr(skb)->saddr, daddr); | ||
410 | goto err_put; | ||
411 | } | ||
412 | } else { | ||
413 | ort = (struct rt6_info *) skb_dst(skb); | ||
414 | if (!(rt_mode & IP_VS_RT_MODE_RDR) && | ||
415 | !__ip_vs_is_local_route6(ort)) { | ||
416 | IP_VS_DBG_RL("Redirect from non-local address %pI6c " | ||
417 | "to local requires NAT method, " | ||
418 | "dest: %pI6c\n", | ||
419 | &ipv6_hdr(skb)->daddr, daddr); | ||
420 | goto err_put; | ||
421 | } | ||
422 | /* skb to local stack, preserve old route */ | 466 | /* skb to local stack, preserve old route */ |
423 | if (!noref) | 467 | if (!noref) |
424 | dst_release(&rt->dst); | 468 | dst_release(&rt->dst); |
@@ -429,28 +473,17 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest, | |||
429 | if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL))) | 473 | if (likely(!(rt_mode & IP_VS_RT_MODE_TUNNEL))) |
430 | mtu = dst_mtu(&rt->dst); | 474 | mtu = dst_mtu(&rt->dst); |
431 | else { | 475 | else { |
432 | struct sock *sk = skb->sk; | ||
433 | |||
434 | mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr); | 476 | mtu = dst_mtu(&rt->dst) - sizeof(struct ipv6hdr); |
435 | if (mtu < IPV6_MIN_MTU) { | 477 | if (mtu < IPV6_MIN_MTU) { |
436 | IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__, | 478 | IP_VS_DBG_RL("%s(): mtu less than %d\n", __func__, |
437 | IPV6_MIN_MTU); | 479 | IPV6_MIN_MTU); |
438 | goto err_put; | 480 | goto err_put; |
439 | } | 481 | } |
440 | ort = (struct rt6_info *) skb_dst(skb); | 482 | maybe_update_pmtu(skb_af, skb, mtu); |
441 | if (!skb->dev && sk && sk->sk_state != TCP_TIME_WAIT) | ||
442 | ort->dst.ops->update_pmtu(&ort->dst, sk, NULL, mtu); | ||
443 | } | 483 | } |
444 | 484 | ||
445 | if (unlikely(__mtu_check_toobig_v6(skb, mtu))) { | 485 | if (!ensure_mtu_is_adequate(skb_af, rt_mode, ipvsh, skb, mtu)) |
446 | if (!skb->dev) | ||
447 | skb->dev = net->loopback_dev; | ||
448 | /* only send ICMP too big on first fragment */ | ||
449 | if (!ipvsh->fragoffs) | ||
450 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); | ||
451 | IP_VS_DBG(1, "frag needed for %pI6c\n", &ipv6_hdr(skb)->saddr); | ||
452 | goto err_put; | 486 | goto err_put; |
453 | } | ||
454 | 487 | ||
455 | skb_dst_drop(skb); | 488 | skb_dst_drop(skb); |
456 | if (noref) { | 489 | if (noref) { |
@@ -556,8 +589,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
556 | EnterFunction(10); | 589 | EnterFunction(10); |
557 | 590 | ||
558 | rcu_read_lock(); | 591 | rcu_read_lock(); |
559 | if (__ip_vs_get_out_rt(skb, NULL, iph->daddr, IP_VS_RT_MODE_NON_LOCAL, | 592 | if (__ip_vs_get_out_rt(cp->af, skb, NULL, iph->daddr, |
560 | NULL) < 0) | 593 | IP_VS_RT_MODE_NON_LOCAL, NULL, ipvsh) < 0) |
561 | goto tx_error; | 594 | goto tx_error; |
562 | 595 | ||
563 | ip_send_check(iph); | 596 | ip_send_check(iph); |
@@ -586,7 +619,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
586 | EnterFunction(10); | 619 | EnterFunction(10); |
587 | 620 | ||
588 | rcu_read_lock(); | 621 | rcu_read_lock(); |
589 | if (__ip_vs_get_out_rt_v6(skb, NULL, &ipvsh->daddr.in6, NULL, | 622 | if (__ip_vs_get_out_rt_v6(cp->af, skb, NULL, &ipvsh->daddr.in6, NULL, |
590 | ipvsh, 0, IP_VS_RT_MODE_NON_LOCAL) < 0) | 623 | ipvsh, 0, IP_VS_RT_MODE_NON_LOCAL) < 0) |
591 | goto tx_error; | 624 | goto tx_error; |
592 | 625 | ||
@@ -633,10 +666,10 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
633 | } | 666 | } |
634 | 667 | ||
635 | was_input = rt_is_input_route(skb_rtable(skb)); | 668 | was_input = rt_is_input_route(skb_rtable(skb)); |
636 | local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 669 | local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip, |
637 | IP_VS_RT_MODE_LOCAL | | 670 | IP_VS_RT_MODE_LOCAL | |
638 | IP_VS_RT_MODE_NON_LOCAL | | 671 | IP_VS_RT_MODE_NON_LOCAL | |
639 | IP_VS_RT_MODE_RDR, NULL); | 672 | IP_VS_RT_MODE_RDR, NULL, ipvsh); |
640 | if (local < 0) | 673 | if (local < 0) |
641 | goto tx_error; | 674 | goto tx_error; |
642 | rt = skb_rtable(skb); | 675 | rt = skb_rtable(skb); |
@@ -721,8 +754,8 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
721 | IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p)); | 754 | IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p)); |
722 | } | 755 | } |
723 | 756 | ||
724 | local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 757 | local = __ip_vs_get_out_rt_v6(cp->af, skb, cp->dest, &cp->daddr.in6, |
725 | ipvsh, 0, | 758 | NULL, ipvsh, 0, |
726 | IP_VS_RT_MODE_LOCAL | | 759 | IP_VS_RT_MODE_LOCAL | |
727 | IP_VS_RT_MODE_NON_LOCAL | | 760 | IP_VS_RT_MODE_NON_LOCAL | |
728 | IP_VS_RT_MODE_RDR); | 761 | IP_VS_RT_MODE_RDR); |
@@ -791,6 +824,81 @@ tx_error: | |||
791 | } | 824 | } |
792 | #endif | 825 | #endif |
793 | 826 | ||
827 | /* When forwarding a packet, we must ensure that we've got enough headroom | ||
828 | * for the encapsulation packet in the skb. This also gives us an | ||
829 | * opportunity to figure out what the payload_len, dsfield, ttl, and df | ||
830 | * values should be, so that we won't need to look at the old ip header | ||
831 | * again | ||
832 | */ | ||
833 | static struct sk_buff * | ||
834 | ip_vs_prepare_tunneled_skb(struct sk_buff *skb, int skb_af, | ||
835 | unsigned int max_headroom, __u8 *next_protocol, | ||
836 | __u32 *payload_len, __u8 *dsfield, __u8 *ttl, | ||
837 | __be16 *df) | ||
838 | { | ||
839 | struct sk_buff *new_skb = NULL; | ||
840 | struct iphdr *old_iph = NULL; | ||
841 | #ifdef CONFIG_IP_VS_IPV6 | ||
842 | struct ipv6hdr *old_ipv6h = NULL; | ||
843 | #endif | ||
844 | |||
845 | if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) { | ||
846 | new_skb = skb_realloc_headroom(skb, max_headroom); | ||
847 | if (!new_skb) | ||
848 | goto error; | ||
849 | consume_skb(skb); | ||
850 | skb = new_skb; | ||
851 | } | ||
852 | |||
853 | #ifdef CONFIG_IP_VS_IPV6 | ||
854 | if (skb_af == AF_INET6) { | ||
855 | old_ipv6h = ipv6_hdr(skb); | ||
856 | *next_protocol = IPPROTO_IPV6; | ||
857 | if (payload_len) | ||
858 | *payload_len = | ||
859 | ntohs(old_ipv6h->payload_len) + | ||
860 | sizeof(*old_ipv6h); | ||
861 | *dsfield = ipv6_get_dsfield(old_ipv6h); | ||
862 | *ttl = old_ipv6h->hop_limit; | ||
863 | if (df) | ||
864 | *df = 0; | ||
865 | } else | ||
866 | #endif | ||
867 | { | ||
868 | old_iph = ip_hdr(skb); | ||
869 | /* Copy DF, reset fragment offset and MF */ | ||
870 | if (df) | ||
871 | *df = (old_iph->frag_off & htons(IP_DF)); | ||
872 | *next_protocol = IPPROTO_IPIP; | ||
873 | |||
874 | /* fix old IP header checksum */ | ||
875 | ip_send_check(old_iph); | ||
876 | *dsfield = ipv4_get_dsfield(old_iph); | ||
877 | *ttl = old_iph->ttl; | ||
878 | if (payload_len) | ||
879 | *payload_len = ntohs(old_iph->tot_len); | ||
880 | } | ||
881 | |||
882 | return skb; | ||
883 | error: | ||
884 | kfree_skb(skb); | ||
885 | return ERR_PTR(-ENOMEM); | ||
886 | } | ||
887 | |||
888 | static inline int __tun_gso_type_mask(int encaps_af, int orig_af) | ||
889 | { | ||
890 | if (encaps_af == AF_INET) { | ||
891 | if (orig_af == AF_INET) | ||
892 | return SKB_GSO_IPIP; | ||
893 | |||
894 | return SKB_GSO_SIT; | ||
895 | } | ||
896 | |||
897 | /* GSO: we need to provide proper SKB_GSO_ value for IPv6: | ||
898 | * SKB_GSO_SIT/IPV6 | ||
899 | */ | ||
900 | return 0; | ||
901 | } | ||
794 | 902 | ||
795 | /* | 903 | /* |
796 | * IP Tunneling transmitter | 904 | * IP Tunneling transmitter |
@@ -819,9 +927,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
819 | struct rtable *rt; /* Route to the other host */ | 927 | struct rtable *rt; /* Route to the other host */ |
820 | __be32 saddr; /* Source for tunnel */ | 928 | __be32 saddr; /* Source for tunnel */ |
821 | struct net_device *tdev; /* Device to other host */ | 929 | struct net_device *tdev; /* Device to other host */ |
822 | struct iphdr *old_iph = ip_hdr(skb); | 930 | __u8 next_protocol = 0; |
823 | u8 tos = old_iph->tos; | 931 | __u8 dsfield = 0; |
824 | __be16 df; | 932 | __u8 ttl = 0; |
933 | __be16 df = 0; | ||
934 | __be16 *dfp = NULL; | ||
825 | struct iphdr *iph; /* Our new IP header */ | 935 | struct iphdr *iph; /* Our new IP header */ |
826 | unsigned int max_headroom; /* The extra header space needed */ | 936 | unsigned int max_headroom; /* The extra header space needed */ |
827 | int ret, local; | 937 | int ret, local; |
@@ -829,11 +939,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
829 | EnterFunction(10); | 939 | EnterFunction(10); |
830 | 940 | ||
831 | rcu_read_lock(); | 941 | rcu_read_lock(); |
832 | local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 942 | local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip, |
833 | IP_VS_RT_MODE_LOCAL | | 943 | IP_VS_RT_MODE_LOCAL | |
834 | IP_VS_RT_MODE_NON_LOCAL | | 944 | IP_VS_RT_MODE_NON_LOCAL | |
835 | IP_VS_RT_MODE_CONNECT | | 945 | IP_VS_RT_MODE_CONNECT | |
836 | IP_VS_RT_MODE_TUNNEL, &saddr); | 946 | IP_VS_RT_MODE_TUNNEL, &saddr, ipvsh); |
837 | if (local < 0) | 947 | if (local < 0) |
838 | goto tx_error; | 948 | goto tx_error; |
839 | if (local) { | 949 | if (local) { |
@@ -844,29 +954,21 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
844 | rt = skb_rtable(skb); | 954 | rt = skb_rtable(skb); |
845 | tdev = rt->dst.dev; | 955 | tdev = rt->dst.dev; |
846 | 956 | ||
847 | /* Copy DF, reset fragment offset and MF */ | ||
848 | df = sysctl_pmtu_disc(ipvs) ? old_iph->frag_off & htons(IP_DF) : 0; | ||
849 | |||
850 | /* | 957 | /* |
851 | * Okay, now see if we can stuff it in the buffer as-is. | 958 | * Okay, now see if we can stuff it in the buffer as-is. |
852 | */ | 959 | */ |
853 | max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr); | 960 | max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct iphdr); |
854 | 961 | ||
855 | if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) { | 962 | /* We only care about the df field if sysctl_pmtu_disc(ipvs) is set */ |
856 | struct sk_buff *new_skb = | 963 | dfp = sysctl_pmtu_disc(ipvs) ? &df : NULL; |
857 | skb_realloc_headroom(skb, max_headroom); | 964 | skb = ip_vs_prepare_tunneled_skb(skb, cp->af, max_headroom, |
858 | 965 | &next_protocol, NULL, &dsfield, | |
859 | if (!new_skb) | 966 | &ttl, dfp); |
860 | goto tx_error; | 967 | if (IS_ERR(skb)) |
861 | consume_skb(skb); | 968 | goto tx_error; |
862 | skb = new_skb; | ||
863 | old_iph = ip_hdr(skb); | ||
864 | } | ||
865 | |||
866 | /* fix old IP header checksum */ | ||
867 | ip_send_check(old_iph); | ||
868 | 969 | ||
869 | skb = iptunnel_handle_offloads(skb, false, SKB_GSO_IPIP); | 970 | skb = iptunnel_handle_offloads( |
971 | skb, false, __tun_gso_type_mask(AF_INET, cp->af)); | ||
870 | if (IS_ERR(skb)) | 972 | if (IS_ERR(skb)) |
871 | goto tx_error; | 973 | goto tx_error; |
872 | 974 | ||
@@ -883,11 +985,11 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
883 | iph->version = 4; | 985 | iph->version = 4; |
884 | iph->ihl = sizeof(struct iphdr)>>2; | 986 | iph->ihl = sizeof(struct iphdr)>>2; |
885 | iph->frag_off = df; | 987 | iph->frag_off = df; |
886 | iph->protocol = IPPROTO_IPIP; | 988 | iph->protocol = next_protocol; |
887 | iph->tos = tos; | 989 | iph->tos = dsfield; |
888 | iph->daddr = cp->daddr.ip; | 990 | iph->daddr = cp->daddr.ip; |
889 | iph->saddr = saddr; | 991 | iph->saddr = saddr; |
890 | iph->ttl = old_iph->ttl; | 992 | iph->ttl = ttl; |
891 | ip_select_ident(skb, NULL); | 993 | ip_select_ident(skb, NULL); |
892 | 994 | ||
893 | /* Another hack: avoid icmp_send in ip_fragment */ | 995 | /* Another hack: avoid icmp_send in ip_fragment */ |
@@ -920,7 +1022,10 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
920 | struct rt6_info *rt; /* Route to the other host */ | 1022 | struct rt6_info *rt; /* Route to the other host */ |
921 | struct in6_addr saddr; /* Source for tunnel */ | 1023 | struct in6_addr saddr; /* Source for tunnel */ |
922 | struct net_device *tdev; /* Device to other host */ | 1024 | struct net_device *tdev; /* Device to other host */ |
923 | struct ipv6hdr *old_iph = ipv6_hdr(skb); | 1025 | __u8 next_protocol = 0; |
1026 | __u32 payload_len = 0; | ||
1027 | __u8 dsfield = 0; | ||
1028 | __u8 ttl = 0; | ||
924 | struct ipv6hdr *iph; /* Our new IP header */ | 1029 | struct ipv6hdr *iph; /* Our new IP header */ |
925 | unsigned int max_headroom; /* The extra header space needed */ | 1030 | unsigned int max_headroom; /* The extra header space needed */ |
926 | int ret, local; | 1031 | int ret, local; |
@@ -928,7 +1033,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
928 | EnterFunction(10); | 1033 | EnterFunction(10); |
929 | 1034 | ||
930 | rcu_read_lock(); | 1035 | rcu_read_lock(); |
931 | local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, | 1036 | local = __ip_vs_get_out_rt_v6(cp->af, skb, cp->dest, &cp->daddr.in6, |
932 | &saddr, ipvsh, 1, | 1037 | &saddr, ipvsh, 1, |
933 | IP_VS_RT_MODE_LOCAL | | 1038 | IP_VS_RT_MODE_LOCAL | |
934 | IP_VS_RT_MODE_NON_LOCAL | | 1039 | IP_VS_RT_MODE_NON_LOCAL | |
@@ -948,19 +1053,14 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
948 | */ | 1053 | */ |
949 | max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr); | 1054 | max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(struct ipv6hdr); |
950 | 1055 | ||
951 | if (skb_headroom(skb) < max_headroom || skb_cloned(skb)) { | 1056 | skb = ip_vs_prepare_tunneled_skb(skb, cp->af, max_headroom, |
952 | struct sk_buff *new_skb = | 1057 | &next_protocol, &payload_len, |
953 | skb_realloc_headroom(skb, max_headroom); | 1058 | &dsfield, &ttl, NULL); |
954 | 1059 | if (IS_ERR(skb)) | |
955 | if (!new_skb) | 1060 | goto tx_error; |
956 | goto tx_error; | ||
957 | consume_skb(skb); | ||
958 | skb = new_skb; | ||
959 | old_iph = ipv6_hdr(skb); | ||
960 | } | ||
961 | 1061 | ||
962 | /* GSO: we need to provide proper SKB_GSO_ value for IPv6 */ | 1062 | skb = iptunnel_handle_offloads( |
963 | skb = iptunnel_handle_offloads(skb, false, 0); /* SKB_GSO_SIT/IPV6 */ | 1063 | skb, false, __tun_gso_type_mask(AF_INET6, cp->af)); |
964 | if (IS_ERR(skb)) | 1064 | if (IS_ERR(skb)) |
965 | goto tx_error; | 1065 | goto tx_error; |
966 | 1066 | ||
@@ -975,14 +1075,13 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
975 | */ | 1075 | */ |
976 | iph = ipv6_hdr(skb); | 1076 | iph = ipv6_hdr(skb); |
977 | iph->version = 6; | 1077 | iph->version = 6; |
978 | iph->nexthdr = IPPROTO_IPV6; | 1078 | iph->nexthdr = next_protocol; |
979 | iph->payload_len = old_iph->payload_len; | 1079 | iph->payload_len = htons(payload_len); |
980 | be16_add_cpu(&iph->payload_len, sizeof(*old_iph)); | ||
981 | memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); | 1080 | memset(&iph->flow_lbl, 0, sizeof(iph->flow_lbl)); |
982 | ipv6_change_dsfield(iph, 0, ipv6_get_dsfield(old_iph)); | 1081 | ipv6_change_dsfield(iph, 0, dsfield); |
983 | iph->daddr = cp->daddr.in6; | 1082 | iph->daddr = cp->daddr.in6; |
984 | iph->saddr = saddr; | 1083 | iph->saddr = saddr; |
985 | iph->hop_limit = old_iph->hop_limit; | 1084 | iph->hop_limit = ttl; |
986 | 1085 | ||
987 | /* Another hack: avoid icmp_send in ip_fragment */ | 1086 | /* Another hack: avoid icmp_send in ip_fragment */ |
988 | skb->ignore_df = 1; | 1087 | skb->ignore_df = 1; |
@@ -1021,10 +1120,10 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1021 | EnterFunction(10); | 1120 | EnterFunction(10); |
1022 | 1121 | ||
1023 | rcu_read_lock(); | 1122 | rcu_read_lock(); |
1024 | local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, | 1123 | local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip, |
1025 | IP_VS_RT_MODE_LOCAL | | 1124 | IP_VS_RT_MODE_LOCAL | |
1026 | IP_VS_RT_MODE_NON_LOCAL | | 1125 | IP_VS_RT_MODE_NON_LOCAL | |
1027 | IP_VS_RT_MODE_KNOWN_NH, NULL); | 1126 | IP_VS_RT_MODE_KNOWN_NH, NULL, ipvsh); |
1028 | if (local < 0) | 1127 | if (local < 0) |
1029 | goto tx_error; | 1128 | goto tx_error; |
1030 | if (local) { | 1129 | if (local) { |
@@ -1060,8 +1159,8 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1060 | EnterFunction(10); | 1159 | EnterFunction(10); |
1061 | 1160 | ||
1062 | rcu_read_lock(); | 1161 | rcu_read_lock(); |
1063 | local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 1162 | local = __ip_vs_get_out_rt_v6(cp->af, skb, cp->dest, &cp->daddr.in6, |
1064 | ipvsh, 0, | 1163 | NULL, ipvsh, 0, |
1065 | IP_VS_RT_MODE_LOCAL | | 1164 | IP_VS_RT_MODE_LOCAL | |
1066 | IP_VS_RT_MODE_NON_LOCAL); | 1165 | IP_VS_RT_MODE_NON_LOCAL); |
1067 | if (local < 0) | 1166 | if (local < 0) |
@@ -1128,7 +1227,8 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1128 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | | 1227 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | |
1129 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; | 1228 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; |
1130 | rcu_read_lock(); | 1229 | rcu_read_lock(); |
1131 | local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, rt_mode, NULL); | 1230 | local = __ip_vs_get_out_rt(cp->af, skb, cp->dest, cp->daddr.ip, rt_mode, |
1231 | NULL, iph); | ||
1132 | if (local < 0) | 1232 | if (local < 0) |
1133 | goto tx_error; | 1233 | goto tx_error; |
1134 | rt = skb_rtable(skb); | 1234 | rt = skb_rtable(skb); |
@@ -1219,8 +1319,8 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, | |||
1219 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | | 1319 | IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL | |
1220 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; | 1320 | IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL; |
1221 | rcu_read_lock(); | 1321 | rcu_read_lock(); |
1222 | local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL, | 1322 | local = __ip_vs_get_out_rt_v6(cp->af, skb, cp->dest, &cp->daddr.in6, |
1223 | ipvsh, 0, rt_mode); | 1323 | NULL, ipvsh, 0, rt_mode); |
1224 | if (local < 0) | 1324 | if (local < 0) |
1225 | goto tx_error; | 1325 | goto tx_error; |
1226 | rt = (struct rt6_info *) skb_dst(skb); | 1326 | rt = (struct rt6_info *) skb_dst(skb); |
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index d25f29377648..957c1db66652 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c | |||
@@ -14,6 +14,30 @@ | |||
14 | 14 | ||
15 | static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ; | 15 | static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ; |
16 | 16 | ||
17 | static bool nf_generic_should_process(u8 proto) | ||
18 | { | ||
19 | switch (proto) { | ||
20 | #ifdef CONFIG_NF_CT_PROTO_SCTP_MODULE | ||
21 | case IPPROTO_SCTP: | ||
22 | return false; | ||
23 | #endif | ||
24 | #ifdef CONFIG_NF_CT_PROTO_DCCP_MODULE | ||
25 | case IPPROTO_DCCP: | ||
26 | return false; | ||
27 | #endif | ||
28 | #ifdef CONFIG_NF_CT_PROTO_GRE_MODULE | ||
29 | case IPPROTO_GRE: | ||
30 | return false; | ||
31 | #endif | ||
32 | #ifdef CONFIG_NF_CT_PROTO_UDPLITE_MODULE | ||
33 | case IPPROTO_UDPLITE: | ||
34 | return false; | ||
35 | #endif | ||
36 | default: | ||
37 | return true; | ||
38 | } | ||
39 | } | ||
40 | |||
17 | static inline struct nf_generic_net *generic_pernet(struct net *net) | 41 | static inline struct nf_generic_net *generic_pernet(struct net *net) |
18 | { | 42 | { |
19 | return &net->ct.nf_ct_proto.generic; | 43 | return &net->ct.nf_ct_proto.generic; |
@@ -67,7 +91,7 @@ static int generic_packet(struct nf_conn *ct, | |||
67 | static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, | 91 | static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb, |
68 | unsigned int dataoff, unsigned int *timeouts) | 92 | unsigned int dataoff, unsigned int *timeouts) |
69 | { | 93 | { |
70 | return true; | 94 | return nf_generic_should_process(nf_ct_protonum(ct)); |
71 | } | 95 | } |
72 | 96 | ||
73 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) | 97 | #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 82374601577e..19e79f0d9ad2 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
@@ -405,9 +405,9 @@ static const struct nla_policy nft_table_policy[NFTA_TABLE_MAX + 1] = { | |||
405 | [NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, | 405 | [NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, |
406 | }; | 406 | }; |
407 | 407 | ||
408 | static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq, | 408 | static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, |
409 | int event, u32 flags, int family, | 409 | u32 portid, u32 seq, int event, u32 flags, |
410 | const struct nft_table *table) | 410 | int family, const struct nft_table *table) |
411 | { | 411 | { |
412 | struct nlmsghdr *nlh; | 412 | struct nlmsghdr *nlh; |
413 | struct nfgenmsg *nfmsg; | 413 | struct nfgenmsg *nfmsg; |
@@ -420,7 +420,7 @@ static int nf_tables_fill_table_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
420 | nfmsg = nlmsg_data(nlh); | 420 | nfmsg = nlmsg_data(nlh); |
421 | nfmsg->nfgen_family = family; | 421 | nfmsg->nfgen_family = family; |
422 | nfmsg->version = NFNETLINK_V0; | 422 | nfmsg->version = NFNETLINK_V0; |
423 | nfmsg->res_id = 0; | 423 | nfmsg->res_id = htons(net->nft.base_seq & 0xffff); |
424 | 424 | ||
425 | if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || | 425 | if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || |
426 | nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) || | 426 | nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) || |
@@ -448,8 +448,8 @@ static int nf_tables_table_notify(const struct nft_ctx *ctx, int event) | |||
448 | if (skb == NULL) | 448 | if (skb == NULL) |
449 | goto err; | 449 | goto err; |
450 | 450 | ||
451 | err = nf_tables_fill_table_info(skb, ctx->portid, ctx->seq, event, 0, | 451 | err = nf_tables_fill_table_info(skb, ctx->net, ctx->portid, ctx->seq, |
452 | ctx->afi->family, ctx->table); | 452 | event, 0, ctx->afi->family, ctx->table); |
453 | if (err < 0) { | 453 | if (err < 0) { |
454 | kfree_skb(skb); | 454 | kfree_skb(skb); |
455 | goto err; | 455 | goto err; |
@@ -488,7 +488,7 @@ static int nf_tables_dump_tables(struct sk_buff *skb, | |||
488 | if (idx > s_idx) | 488 | if (idx > s_idx) |
489 | memset(&cb->args[1], 0, | 489 | memset(&cb->args[1], 0, |
490 | sizeof(cb->args) - sizeof(cb->args[0])); | 490 | sizeof(cb->args) - sizeof(cb->args[0])); |
491 | if (nf_tables_fill_table_info(skb, | 491 | if (nf_tables_fill_table_info(skb, net, |
492 | NETLINK_CB(cb->skb).portid, | 492 | NETLINK_CB(cb->skb).portid, |
493 | cb->nlh->nlmsg_seq, | 493 | cb->nlh->nlmsg_seq, |
494 | NFT_MSG_NEWTABLE, | 494 | NFT_MSG_NEWTABLE, |
@@ -540,7 +540,7 @@ static int nf_tables_gettable(struct sock *nlsk, struct sk_buff *skb, | |||
540 | if (!skb2) | 540 | if (!skb2) |
541 | return -ENOMEM; | 541 | return -ENOMEM; |
542 | 542 | ||
543 | err = nf_tables_fill_table_info(skb2, NETLINK_CB(skb).portid, | 543 | err = nf_tables_fill_table_info(skb2, net, NETLINK_CB(skb).portid, |
544 | nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0, | 544 | nlh->nlmsg_seq, NFT_MSG_NEWTABLE, 0, |
545 | family, table); | 545 | family, table); |
546 | if (err < 0) | 546 | if (err < 0) |
@@ -914,9 +914,9 @@ nla_put_failure: | |||
914 | return -ENOSPC; | 914 | return -ENOSPC; |
915 | } | 915 | } |
916 | 916 | ||
917 | static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | 917 | static int nf_tables_fill_chain_info(struct sk_buff *skb, struct net *net, |
918 | int event, u32 flags, int family, | 918 | u32 portid, u32 seq, int event, u32 flags, |
919 | const struct nft_table *table, | 919 | int family, const struct nft_table *table, |
920 | const struct nft_chain *chain) | 920 | const struct nft_chain *chain) |
921 | { | 921 | { |
922 | struct nlmsghdr *nlh; | 922 | struct nlmsghdr *nlh; |
@@ -930,7 +930,7 @@ static int nf_tables_fill_chain_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
930 | nfmsg = nlmsg_data(nlh); | 930 | nfmsg = nlmsg_data(nlh); |
931 | nfmsg->nfgen_family = family; | 931 | nfmsg->nfgen_family = family; |
932 | nfmsg->version = NFNETLINK_V0; | 932 | nfmsg->version = NFNETLINK_V0; |
933 | nfmsg->res_id = 0; | 933 | nfmsg->res_id = htons(net->nft.base_seq & 0xffff); |
934 | 934 | ||
935 | if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name)) | 935 | if (nla_put_string(skb, NFTA_CHAIN_TABLE, table->name)) |
936 | goto nla_put_failure; | 936 | goto nla_put_failure; |
@@ -988,8 +988,8 @@ static int nf_tables_chain_notify(const struct nft_ctx *ctx, int event) | |||
988 | if (skb == NULL) | 988 | if (skb == NULL) |
989 | goto err; | 989 | goto err; |
990 | 990 | ||
991 | err = nf_tables_fill_chain_info(skb, ctx->portid, ctx->seq, event, 0, | 991 | err = nf_tables_fill_chain_info(skb, ctx->net, ctx->portid, ctx->seq, |
992 | ctx->afi->family, ctx->table, | 992 | event, 0, ctx->afi->family, ctx->table, |
993 | ctx->chain); | 993 | ctx->chain); |
994 | if (err < 0) { | 994 | if (err < 0) { |
995 | kfree_skb(skb); | 995 | kfree_skb(skb); |
@@ -1031,7 +1031,8 @@ static int nf_tables_dump_chains(struct sk_buff *skb, | |||
1031 | if (idx > s_idx) | 1031 | if (idx > s_idx) |
1032 | memset(&cb->args[1], 0, | 1032 | memset(&cb->args[1], 0, |
1033 | sizeof(cb->args) - sizeof(cb->args[0])); | 1033 | sizeof(cb->args) - sizeof(cb->args[0])); |
1034 | if (nf_tables_fill_chain_info(skb, NETLINK_CB(cb->skb).portid, | 1034 | if (nf_tables_fill_chain_info(skb, net, |
1035 | NETLINK_CB(cb->skb).portid, | ||
1035 | cb->nlh->nlmsg_seq, | 1036 | cb->nlh->nlmsg_seq, |
1036 | NFT_MSG_NEWCHAIN, | 1037 | NFT_MSG_NEWCHAIN, |
1037 | NLM_F_MULTI, | 1038 | NLM_F_MULTI, |
@@ -1090,7 +1091,7 @@ static int nf_tables_getchain(struct sock *nlsk, struct sk_buff *skb, | |||
1090 | if (!skb2) | 1091 | if (!skb2) |
1091 | return -ENOMEM; | 1092 | return -ENOMEM; |
1092 | 1093 | ||
1093 | err = nf_tables_fill_chain_info(skb2, NETLINK_CB(skb).portid, | 1094 | err = nf_tables_fill_chain_info(skb2, net, NETLINK_CB(skb).portid, |
1094 | nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0, | 1095 | nlh->nlmsg_seq, NFT_MSG_NEWCHAIN, 0, |
1095 | family, table, chain); | 1096 | family, table, chain); |
1096 | if (err < 0) | 1097 | if (err < 0) |
@@ -1647,8 +1648,9 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = { | |||
1647 | .len = NFT_USERDATA_MAXLEN }, | 1648 | .len = NFT_USERDATA_MAXLEN }, |
1648 | }; | 1649 | }; |
1649 | 1650 | ||
1650 | static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, | 1651 | static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, |
1651 | int event, u32 flags, int family, | 1652 | u32 portid, u32 seq, int event, |
1653 | u32 flags, int family, | ||
1652 | const struct nft_table *table, | 1654 | const struct nft_table *table, |
1653 | const struct nft_chain *chain, | 1655 | const struct nft_chain *chain, |
1654 | const struct nft_rule *rule) | 1656 | const struct nft_rule *rule) |
@@ -1668,7 +1670,7 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, u32 portid, u32 seq, | |||
1668 | nfmsg = nlmsg_data(nlh); | 1670 | nfmsg = nlmsg_data(nlh); |
1669 | nfmsg->nfgen_family = family; | 1671 | nfmsg->nfgen_family = family; |
1670 | nfmsg->version = NFNETLINK_V0; | 1672 | nfmsg->version = NFNETLINK_V0; |
1671 | nfmsg->res_id = 0; | 1673 | nfmsg->res_id = htons(net->nft.base_seq & 0xffff); |
1672 | 1674 | ||
1673 | if (nla_put_string(skb, NFTA_RULE_TABLE, table->name)) | 1675 | if (nla_put_string(skb, NFTA_RULE_TABLE, table->name)) |
1674 | goto nla_put_failure; | 1676 | goto nla_put_failure; |
@@ -1724,8 +1726,8 @@ static int nf_tables_rule_notify(const struct nft_ctx *ctx, | |||
1724 | if (skb == NULL) | 1726 | if (skb == NULL) |
1725 | goto err; | 1727 | goto err; |
1726 | 1728 | ||
1727 | err = nf_tables_fill_rule_info(skb, ctx->portid, ctx->seq, event, 0, | 1729 | err = nf_tables_fill_rule_info(skb, ctx->net, ctx->portid, ctx->seq, |
1728 | ctx->afi->family, ctx->table, | 1730 | event, 0, ctx->afi->family, ctx->table, |
1729 | ctx->chain, rule); | 1731 | ctx->chain, rule); |
1730 | if (err < 0) { | 1732 | if (err < 0) { |
1731 | kfree_skb(skb); | 1733 | kfree_skb(skb); |
@@ -1771,7 +1773,7 @@ static int nf_tables_dump_rules(struct sk_buff *skb, | |||
1771 | if (idx > s_idx) | 1773 | if (idx > s_idx) |
1772 | memset(&cb->args[1], 0, | 1774 | memset(&cb->args[1], 0, |
1773 | sizeof(cb->args) - sizeof(cb->args[0])); | 1775 | sizeof(cb->args) - sizeof(cb->args[0])); |
1774 | if (nf_tables_fill_rule_info(skb, NETLINK_CB(cb->skb).portid, | 1776 | if (nf_tables_fill_rule_info(skb, net, NETLINK_CB(cb->skb).portid, |
1775 | cb->nlh->nlmsg_seq, | 1777 | cb->nlh->nlmsg_seq, |
1776 | NFT_MSG_NEWRULE, | 1778 | NFT_MSG_NEWRULE, |
1777 | NLM_F_MULTI | NLM_F_APPEND, | 1779 | NLM_F_MULTI | NLM_F_APPEND, |
@@ -1837,7 +1839,7 @@ static int nf_tables_getrule(struct sock *nlsk, struct sk_buff *skb, | |||
1837 | if (!skb2) | 1839 | if (!skb2) |
1838 | return -ENOMEM; | 1840 | return -ENOMEM; |
1839 | 1841 | ||
1840 | err = nf_tables_fill_rule_info(skb2, NETLINK_CB(skb).portid, | 1842 | err = nf_tables_fill_rule_info(skb2, net, NETLINK_CB(skb).portid, |
1841 | nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0, | 1843 | nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0, |
1842 | family, table, chain, rule); | 1844 | family, table, chain, rule); |
1843 | if (err < 0) | 1845 | if (err < 0) |
@@ -2321,7 +2323,7 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx, | |||
2321 | nfmsg = nlmsg_data(nlh); | 2323 | nfmsg = nlmsg_data(nlh); |
2322 | nfmsg->nfgen_family = ctx->afi->family; | 2324 | nfmsg->nfgen_family = ctx->afi->family; |
2323 | nfmsg->version = NFNETLINK_V0; | 2325 | nfmsg->version = NFNETLINK_V0; |
2324 | nfmsg->res_id = 0; | 2326 | nfmsg->res_id = htons(ctx->net->nft.base_seq & 0xffff); |
2325 | 2327 | ||
2326 | if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name)) | 2328 | if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name)) |
2327 | goto nla_put_failure; | 2329 | goto nla_put_failure; |
@@ -2342,6 +2344,11 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx, | |||
2342 | goto nla_put_failure; | 2344 | goto nla_put_failure; |
2343 | } | 2345 | } |
2344 | 2346 | ||
2347 | if (set->policy != NFT_SET_POL_PERFORMANCE) { | ||
2348 | if (nla_put_be32(skb, NFTA_SET_POLICY, htonl(set->policy))) | ||
2349 | goto nla_put_failure; | ||
2350 | } | ||
2351 | |||
2345 | desc = nla_nest_start(skb, NFTA_SET_DESC); | 2352 | desc = nla_nest_start(skb, NFTA_SET_DESC); |
2346 | if (desc == NULL) | 2353 | if (desc == NULL) |
2347 | goto nla_put_failure; | 2354 | goto nla_put_failure; |
@@ -2667,6 +2674,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb, | |||
2667 | set->dlen = desc.dlen; | 2674 | set->dlen = desc.dlen; |
2668 | set->flags = flags; | 2675 | set->flags = flags; |
2669 | set->size = desc.size; | 2676 | set->size = desc.size; |
2677 | set->policy = policy; | ||
2670 | 2678 | ||
2671 | err = ops->init(set, &desc, nla); | 2679 | err = ops->init(set, &desc, nla); |
2672 | if (err < 0) | 2680 | if (err < 0) |
@@ -2925,7 +2933,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb) | |||
2925 | nfmsg = nlmsg_data(nlh); | 2933 | nfmsg = nlmsg_data(nlh); |
2926 | nfmsg->nfgen_family = ctx.afi->family; | 2934 | nfmsg->nfgen_family = ctx.afi->family; |
2927 | nfmsg->version = NFNETLINK_V0; | 2935 | nfmsg->version = NFNETLINK_V0; |
2928 | nfmsg->res_id = 0; | 2936 | nfmsg->res_id = htons(ctx.net->nft.base_seq & 0xffff); |
2929 | 2937 | ||
2930 | if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name)) | 2938 | if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name)) |
2931 | goto nla_put_failure; | 2939 | goto nla_put_failure; |
@@ -3006,7 +3014,7 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb, | |||
3006 | nfmsg = nlmsg_data(nlh); | 3014 | nfmsg = nlmsg_data(nlh); |
3007 | nfmsg->nfgen_family = ctx->afi->family; | 3015 | nfmsg->nfgen_family = ctx->afi->family; |
3008 | nfmsg->version = NFNETLINK_V0; | 3016 | nfmsg->version = NFNETLINK_V0; |
3009 | nfmsg->res_id = 0; | 3017 | nfmsg->res_id = htons(ctx->net->nft.base_seq & 0xffff); |
3010 | 3018 | ||
3011 | if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name)) | 3019 | if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name)) |
3012 | goto nla_put_failure; | 3020 | goto nla_put_failure; |
@@ -3293,6 +3301,87 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb, | |||
3293 | return err; | 3301 | return err; |
3294 | } | 3302 | } |
3295 | 3303 | ||
3304 | static int nf_tables_fill_gen_info(struct sk_buff *skb, struct net *net, | ||
3305 | u32 portid, u32 seq) | ||
3306 | { | ||
3307 | struct nlmsghdr *nlh; | ||
3308 | struct nfgenmsg *nfmsg; | ||
3309 | int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWGEN; | ||
3310 | |||
3311 | nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), 0); | ||
3312 | if (nlh == NULL) | ||
3313 | goto nla_put_failure; | ||
3314 | |||
3315 | nfmsg = nlmsg_data(nlh); | ||
3316 | nfmsg->nfgen_family = AF_UNSPEC; | ||
3317 | nfmsg->version = NFNETLINK_V0; | ||
3318 | nfmsg->res_id = htons(net->nft.base_seq & 0xffff); | ||
3319 | |||
3320 | if (nla_put_be32(skb, NFTA_GEN_ID, htonl(net->nft.base_seq))) | ||
3321 | goto nla_put_failure; | ||
3322 | |||
3323 | return nlmsg_end(skb, nlh); | ||
3324 | |||
3325 | nla_put_failure: | ||
3326 | nlmsg_trim(skb, nlh); | ||
3327 | return -EMSGSIZE; | ||
3328 | } | ||
3329 | |||
3330 | static int nf_tables_gen_notify(struct net *net, struct sk_buff *skb, int event) | ||
3331 | { | ||
3332 | struct nlmsghdr *nlh = nlmsg_hdr(skb); | ||
3333 | struct sk_buff *skb2; | ||
3334 | int err; | ||
3335 | |||
3336 | if (nlmsg_report(nlh) && | ||
3337 | !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES)) | ||
3338 | return 0; | ||
3339 | |||
3340 | err = -ENOBUFS; | ||
3341 | skb2 = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
3342 | if (skb2 == NULL) | ||
3343 | goto err; | ||
3344 | |||
3345 | err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid, | ||
3346 | nlh->nlmsg_seq); | ||
3347 | if (err < 0) { | ||
3348 | kfree_skb(skb2); | ||
3349 | goto err; | ||
3350 | } | ||
3351 | |||
3352 | err = nfnetlink_send(skb2, net, NETLINK_CB(skb).portid, | ||
3353 | NFNLGRP_NFTABLES, nlmsg_report(nlh), GFP_KERNEL); | ||
3354 | err: | ||
3355 | if (err < 0) { | ||
3356 | nfnetlink_set_err(net, NETLINK_CB(skb).portid, NFNLGRP_NFTABLES, | ||
3357 | err); | ||
3358 | } | ||
3359 | return err; | ||
3360 | } | ||
3361 | |||
3362 | static int nf_tables_getgen(struct sock *nlsk, struct sk_buff *skb, | ||
3363 | const struct nlmsghdr *nlh, | ||
3364 | const struct nlattr * const nla[]) | ||
3365 | { | ||
3366 | struct net *net = sock_net(skb->sk); | ||
3367 | struct sk_buff *skb2; | ||
3368 | int err; | ||
3369 | |||
3370 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
3371 | if (skb2 == NULL) | ||
3372 | return -ENOMEM; | ||
3373 | |||
3374 | err = nf_tables_fill_gen_info(skb2, net, NETLINK_CB(skb).portid, | ||
3375 | nlh->nlmsg_seq); | ||
3376 | if (err < 0) | ||
3377 | goto err; | ||
3378 | |||
3379 | return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid); | ||
3380 | err: | ||
3381 | kfree_skb(skb2); | ||
3382 | return err; | ||
3383 | } | ||
3384 | |||
3296 | static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { | 3385 | static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { |
3297 | [NFT_MSG_NEWTABLE] = { | 3386 | [NFT_MSG_NEWTABLE] = { |
3298 | .call_batch = nf_tables_newtable, | 3387 | .call_batch = nf_tables_newtable, |
@@ -3369,6 +3458,9 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { | |||
3369 | .attr_count = NFTA_SET_ELEM_LIST_MAX, | 3458 | .attr_count = NFTA_SET_ELEM_LIST_MAX, |
3370 | .policy = nft_set_elem_list_policy, | 3459 | .policy = nft_set_elem_list_policy, |
3371 | }, | 3460 | }, |
3461 | [NFT_MSG_GETGEN] = { | ||
3462 | .call = nf_tables_getgen, | ||
3463 | }, | ||
3372 | }; | 3464 | }; |
3373 | 3465 | ||
3374 | static void nft_chain_commit_update(struct nft_trans *trans) | 3466 | static void nft_chain_commit_update(struct nft_trans *trans) |
@@ -3526,6 +3618,8 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
3526 | call_rcu(&trans->rcu_head, nf_tables_commit_release_rcu); | 3618 | call_rcu(&trans->rcu_head, nf_tables_commit_release_rcu); |
3527 | } | 3619 | } |
3528 | 3620 | ||
3621 | nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN); | ||
3622 | |||
3529 | return 0; | 3623 | return 0; |
3530 | } | 3624 | } |
3531 | 3625 | ||
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index c138b8fbe280..f77d3f7f22b5 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c | |||
@@ -333,7 +333,7 @@ replay: | |||
333 | * original skb. | 333 | * original skb. |
334 | */ | 334 | */ |
335 | if (err == -EAGAIN) { | 335 | if (err == -EAGAIN) { |
336 | ss->abort(skb); | 336 | ss->abort(oskb); |
337 | nfnl_unlock(subsys_id); | 337 | nfnl_unlock(subsys_id); |
338 | kfree_skb(nskb); | 338 | kfree_skb(nskb); |
339 | goto replay; | 339 | goto replay; |
@@ -357,9 +357,9 @@ ack: | |||
357 | } | 357 | } |
358 | done: | 358 | done: |
359 | if (success && done) | 359 | if (success && done) |
360 | ss->commit(skb); | 360 | ss->commit(oskb); |
361 | else | 361 | else |
362 | ss->abort(skb); | 362 | ss->abort(oskb); |
363 | 363 | ||
364 | nfnl_unlock(subsys_id); | 364 | nfnl_unlock(subsys_id); |
365 | kfree_skb(nskb); | 365 | kfree_skb(nskb); |
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 272ae4d6fdf4..133eb4772f12 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -1101,22 +1101,11 @@ static const struct seq_operations xt_match_seq_ops = { | |||
1101 | 1101 | ||
1102 | static int xt_match_open(struct inode *inode, struct file *file) | 1102 | static int xt_match_open(struct inode *inode, struct file *file) |
1103 | { | 1103 | { |
1104 | struct seq_file *seq; | ||
1105 | struct nf_mttg_trav *trav; | 1104 | struct nf_mttg_trav *trav; |
1106 | int ret; | 1105 | trav = __seq_open_private(file, &xt_match_seq_ops, sizeof(*trav)); |
1107 | 1106 | if (!trav) | |
1108 | trav = kmalloc(sizeof(*trav), GFP_KERNEL); | ||
1109 | if (trav == NULL) | ||
1110 | return -ENOMEM; | 1107 | return -ENOMEM; |
1111 | 1108 | ||
1112 | ret = seq_open(file, &xt_match_seq_ops); | ||
1113 | if (ret < 0) { | ||
1114 | kfree(trav); | ||
1115 | return ret; | ||
1116 | } | ||
1117 | |||
1118 | seq = file->private_data; | ||
1119 | seq->private = trav; | ||
1120 | trav->nfproto = (unsigned long)PDE_DATA(inode); | 1109 | trav->nfproto = (unsigned long)PDE_DATA(inode); |
1121 | return 0; | 1110 | return 0; |
1122 | } | 1111 | } |
@@ -1165,22 +1154,11 @@ static const struct seq_operations xt_target_seq_ops = { | |||
1165 | 1154 | ||
1166 | static int xt_target_open(struct inode *inode, struct file *file) | 1155 | static int xt_target_open(struct inode *inode, struct file *file) |
1167 | { | 1156 | { |
1168 | struct seq_file *seq; | ||
1169 | struct nf_mttg_trav *trav; | 1157 | struct nf_mttg_trav *trav; |
1170 | int ret; | 1158 | trav = __seq_open_private(file, &xt_target_seq_ops, sizeof(*trav)); |
1171 | 1159 | if (!trav) | |
1172 | trav = kmalloc(sizeof(*trav), GFP_KERNEL); | ||
1173 | if (trav == NULL) | ||
1174 | return -ENOMEM; | 1160 | return -ENOMEM; |
1175 | 1161 | ||
1176 | ret = seq_open(file, &xt_target_seq_ops); | ||
1177 | if (ret < 0) { | ||
1178 | kfree(trav); | ||
1179 | return ret; | ||
1180 | } | ||
1181 | |||
1182 | seq = file->private_data; | ||
1183 | seq->private = trav; | ||
1184 | trav->nfproto = (unsigned long)PDE_DATA(inode); | 1162 | trav->nfproto = (unsigned long)PDE_DATA(inode); |
1185 | return 0; | 1163 | return 0; |
1186 | } | 1164 | } |
diff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c index cb70f6ec5695..5732cd64acc0 100644 --- a/net/netfilter/xt_set.c +++ b/net/netfilter/xt_set.c | |||
@@ -366,6 +366,140 @@ set_target_v2(struct sk_buff *skb, const struct xt_action_param *par) | |||
366 | #define set_target_v2_checkentry set_target_v1_checkentry | 366 | #define set_target_v2_checkentry set_target_v1_checkentry |
367 | #define set_target_v2_destroy set_target_v1_destroy | 367 | #define set_target_v2_destroy set_target_v1_destroy |
368 | 368 | ||
369 | /* Revision 3 target */ | ||
370 | |||
371 | static unsigned int | ||
372 | set_target_v3(struct sk_buff *skb, const struct xt_action_param *par) | ||
373 | { | ||
374 | const struct xt_set_info_target_v3 *info = par->targinfo; | ||
375 | ADT_OPT(add_opt, par->family, info->add_set.dim, | ||
376 | info->add_set.flags, info->flags, info->timeout); | ||
377 | ADT_OPT(del_opt, par->family, info->del_set.dim, | ||
378 | info->del_set.flags, 0, UINT_MAX); | ||
379 | ADT_OPT(map_opt, par->family, info->map_set.dim, | ||
380 | info->map_set.flags, 0, UINT_MAX); | ||
381 | |||
382 | int ret; | ||
383 | |||
384 | /* Normalize to fit into jiffies */ | ||
385 | if (add_opt.ext.timeout != IPSET_NO_TIMEOUT && | ||
386 | add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC) | ||
387 | add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC; | ||
388 | if (info->add_set.index != IPSET_INVALID_ID) | ||
389 | ip_set_add(info->add_set.index, skb, par, &add_opt); | ||
390 | if (info->del_set.index != IPSET_INVALID_ID) | ||
391 | ip_set_del(info->del_set.index, skb, par, &del_opt); | ||
392 | if (info->map_set.index != IPSET_INVALID_ID) { | ||
393 | map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK | | ||
394 | IPSET_FLAG_MAP_SKBPRIO | | ||
395 | IPSET_FLAG_MAP_SKBQUEUE); | ||
396 | ret = match_set(info->map_set.index, skb, par, &map_opt, | ||
397 | info->map_set.flags & IPSET_INV_MATCH); | ||
398 | if (!ret) | ||
399 | return XT_CONTINUE; | ||
400 | if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK) | ||
401 | skb->mark = (skb->mark & ~(map_opt.ext.skbmarkmask)) | ||
402 | ^ (map_opt.ext.skbmark); | ||
403 | if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO) | ||
404 | skb->priority = map_opt.ext.skbprio; | ||
405 | if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) && | ||
406 | skb->dev && | ||
407 | skb->dev->real_num_tx_queues > map_opt.ext.skbqueue) | ||
408 | skb_set_queue_mapping(skb, map_opt.ext.skbqueue); | ||
409 | } | ||
410 | return XT_CONTINUE; | ||
411 | } | ||
412 | |||
413 | |||
414 | static int | ||
415 | set_target_v3_checkentry(const struct xt_tgchk_param *par) | ||
416 | { | ||
417 | const struct xt_set_info_target_v3 *info = par->targinfo; | ||
418 | ip_set_id_t index; | ||
419 | |||
420 | if (info->add_set.index != IPSET_INVALID_ID) { | ||
421 | index = ip_set_nfnl_get_byindex(par->net, | ||
422 | info->add_set.index); | ||
423 | if (index == IPSET_INVALID_ID) { | ||
424 | pr_warn("Cannot find add_set index %u as target\n", | ||
425 | info->add_set.index); | ||
426 | return -ENOENT; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | if (info->del_set.index != IPSET_INVALID_ID) { | ||
431 | index = ip_set_nfnl_get_byindex(par->net, | ||
432 | info->del_set.index); | ||
433 | if (index == IPSET_INVALID_ID) { | ||
434 | pr_warn("Cannot find del_set index %u as target\n", | ||
435 | info->del_set.index); | ||
436 | if (info->add_set.index != IPSET_INVALID_ID) | ||
437 | ip_set_nfnl_put(par->net, | ||
438 | info->add_set.index); | ||
439 | return -ENOENT; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | if (info->map_set.index != IPSET_INVALID_ID) { | ||
444 | if (strncmp(par->table, "mangle", 7)) { | ||
445 | pr_warn("--map-set only usable from mangle table\n"); | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) | | ||
449 | (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) && | ||
450 | !(par->hook_mask & (1 << NF_INET_FORWARD | | ||
451 | 1 << NF_INET_LOCAL_OUT | | ||
452 | 1 << NF_INET_POST_ROUTING))) { | ||
453 | pr_warn("mapping of prio or/and queue is allowed only" | ||
454 | "from OUTPUT/FORWARD/POSTROUTING chains\n"); | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | index = ip_set_nfnl_get_byindex(par->net, | ||
458 | info->map_set.index); | ||
459 | if (index == IPSET_INVALID_ID) { | ||
460 | pr_warn("Cannot find map_set index %u as target\n", | ||
461 | info->map_set.index); | ||
462 | if (info->add_set.index != IPSET_INVALID_ID) | ||
463 | ip_set_nfnl_put(par->net, | ||
464 | info->add_set.index); | ||
465 | if (info->del_set.index != IPSET_INVALID_ID) | ||
466 | ip_set_nfnl_put(par->net, | ||
467 | info->del_set.index); | ||
468 | return -ENOENT; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | if (info->add_set.dim > IPSET_DIM_MAX || | ||
473 | info->del_set.dim > IPSET_DIM_MAX || | ||
474 | info->map_set.dim > IPSET_DIM_MAX) { | ||
475 | pr_warn("Protocol error: SET target dimension " | ||
476 | "is over the limit!\n"); | ||
477 | if (info->add_set.index != IPSET_INVALID_ID) | ||
478 | ip_set_nfnl_put(par->net, info->add_set.index); | ||
479 | if (info->del_set.index != IPSET_INVALID_ID) | ||
480 | ip_set_nfnl_put(par->net, info->del_set.index); | ||
481 | if (info->map_set.index != IPSET_INVALID_ID) | ||
482 | ip_set_nfnl_put(par->net, info->map_set.index); | ||
483 | return -ERANGE; | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static void | ||
490 | set_target_v3_destroy(const struct xt_tgdtor_param *par) | ||
491 | { | ||
492 | const struct xt_set_info_target_v3 *info = par->targinfo; | ||
493 | |||
494 | if (info->add_set.index != IPSET_INVALID_ID) | ||
495 | ip_set_nfnl_put(par->net, info->add_set.index); | ||
496 | if (info->del_set.index != IPSET_INVALID_ID) | ||
497 | ip_set_nfnl_put(par->net, info->del_set.index); | ||
498 | if (info->map_set.index != IPSET_INVALID_ID) | ||
499 | ip_set_nfnl_put(par->net, info->map_set.index); | ||
500 | } | ||
501 | |||
502 | |||
369 | static struct xt_match set_matches[] __read_mostly = { | 503 | static struct xt_match set_matches[] __read_mostly = { |
370 | { | 504 | { |
371 | .name = "set", | 505 | .name = "set", |
@@ -493,6 +627,27 @@ static struct xt_target set_targets[] __read_mostly = { | |||
493 | .destroy = set_target_v2_destroy, | 627 | .destroy = set_target_v2_destroy, |
494 | .me = THIS_MODULE | 628 | .me = THIS_MODULE |
495 | }, | 629 | }, |
630 | /* --map-set support */ | ||
631 | { | ||
632 | .name = "SET", | ||
633 | .revision = 3, | ||
634 | .family = NFPROTO_IPV4, | ||
635 | .target = set_target_v3, | ||
636 | .targetsize = sizeof(struct xt_set_info_target_v3), | ||
637 | .checkentry = set_target_v3_checkentry, | ||
638 | .destroy = set_target_v3_destroy, | ||
639 | .me = THIS_MODULE | ||
640 | }, | ||
641 | { | ||
642 | .name = "SET", | ||
643 | .revision = 3, | ||
644 | .family = NFPROTO_IPV6, | ||
645 | .target = set_target_v3, | ||
646 | .targetsize = sizeof(struct xt_set_info_target_v3), | ||
647 | .checkentry = set_target_v3_checkentry, | ||
648 | .destroy = set_target_v3_destroy, | ||
649 | .me = THIS_MODULE | ||
650 | }, | ||
496 | }; | 651 | }; |
497 | 652 | ||
498 | static int __init xt_set_init(void) | 653 | static int __init xt_set_init(void) |