mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
netfilter pull request 26-10-19
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEjF9xRqF1emXiQiqU1w0aZmrPKyEFAmrWLcoACgkQ1w0aZmrP
KyGlNg/+OGCFkcwos/7Ph9XHFwZWmSAfqB9dJefnJC3Pz4s1q22ZQzZNaKfUHD8y
LDlgLzXjBw8XIfiM9yT6/1vaJiBE8ciWYnynDBxOB9QX01t23GqPDA/EdPJ16ket
LrkJm2tpjNXdqaTm1D8144TaP0/mUGzjqPpH8PwsjCxuDMx0WaaQG4tcU9nWE0S/
YzfgRq0JmWX0um/TIGA3PCZeCVeJ65yhjpDdWm+/ExzmPr29tTlmTedqLz82EPAf
Bw/D1MKk3qAs+IJgUCoTTScLPPsS+zMRvO0Go/ftc9A9hztw/iN/Pfd0J8ZdhMcp
ekwPWvWaZQ1M0WLaffCClao3+86OOSPG0vAQkTHD943asAzu2sv01pnLMopxmJzJ
gq0irC9Zf7X01M6VazGmJtkvWl7MFee1JJDBO3VsRBw4qBm4pu1D+qTJoqwzgAcG
X+p3f6mp7rNL7qT7tgG41BaQ727zI9IOFeZstcqDbn+QyCwdgDZkziF3CynUT2St
FmrhbzxEIQGLMlMRAxNfoX2u64pZ0CU+p2bQku613sFA9WkYLAbsUfyuHGXeIgec
DqMDRxeuI+82mUdPy4+cEAgPlvN+/tCFdTyoeALM/8GyvUCI1Y6Gj80ky1+Y4Bku
kA0GVevusfv0H3Fek/Zozi7hXxOctpLDCnNo2PRB4FM0/mqkUQU=
=ZrLH
-----END PGP SIGNATURE-----
Merge tag 'nf-26-10-19' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
Pablo Neira Ayuso says:
====================
Netfilter/IPVS fixes for net
The following patchset contains Netfilter/IPVS for net:
1) Fix IPv6 nexthdr offset truncation in fragment reassembly,
this has been uncovered by LLM, from Jeremy Jean.
2) Restrict checksums in nfqueue to known protocols and offset,
after this patch the plan is to re-enable nfqueue in userns,
this came via LLM report. from Florian Westhphal.
3) Fix races when handling overload flag in IPVS, this patch
is not perfect but Julian considers this improves the situation.
This was uncovered by LLM. From Julian Anastasov.
4) Error handling for IPVS sync_threshold sysctl, from Joel Granados.
5) Use skb_vlan_tag_get_id() to retrieve the VLAN id, discard tci
bits, when handling VLAN in the flowtable, from Shuangfeng He.
6) Initialize IPCB for inet/ingress reject, uncovered by LLM.
7) Restrict completion of binary search array to anonymous set.
8) Restrict DCCP option matching to avoid out-of-bound read,
from Sung Byeongchan.
9) Reset transport header offset in flowtable after tunnel
decapsulation to fix issue with qdisc xmit path,
from Lorenzo Bianconi.
10) Fix inverted matching in ctnetlink dump filtering,
from Liu Chao.
* tag 'nf-26-10-19' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
netfilter: nf_conntrack_netlink: fix inverted IPv6 tuple filter
netfilter: flowtable: reset transport header after nf_flow_encap_pop()
netfilter: xt_dccp: handle reserved options as single-byte
netfilter: nft_set_rbtree: narrow down range completion to anonymous sets
netfilter: nf_reject: initialize IPCB at inet ingress
netfilter: flowtable: use the vlan id, not the full tci, in the tuple key
ipvs: skip committing sync_threshold when proc_dointvec fails
ipvs: fix more races around the overload flag
netfilter: nft_payload: restrict checksum offsets to known values
netfilter: nf_conntrack: avoid truncating IPv6 nexthdr offset
====================
Link: https://patch.msgid.link/20261019150249.1879516-1-pablo@netfilter.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
d5d524f469
|
|
@ -36,9 +36,6 @@
|
|||
#define IP_VS_HDR_INVERSE 1
|
||||
#define IP_VS_HDR_ICMP 2
|
||||
|
||||
/* Destination Server Flags */
|
||||
#define IP_VS_DEST_F_OVERLOAD 0x0002 /* server is overloaded */
|
||||
|
||||
/* Destination Server Config Flags */
|
||||
#define IP_VS_DEST_CF_AVAILABLE 0x0001 /* server is available */
|
||||
|
||||
|
|
@ -973,33 +970,44 @@ struct ip_vs_dest_dst {
|
|||
* and so on.
|
||||
*/
|
||||
struct ip_vs_dest {
|
||||
/* Cacheline for hash table nodes - read-mostly */
|
||||
|
||||
struct list_head n_list; /* for the dests in the service */
|
||||
struct hlist_node d_list; /* for table with all the dests */
|
||||
|
||||
u16 af; /* address family */
|
||||
__be16 port; /* port number of the server */
|
||||
union nf_inet_addr addr; /* IP address of the server */
|
||||
volatile unsigned int flags; /* dest status flags */
|
||||
atomic_t conn_flags; /* flags to copy to conn */
|
||||
atomic_t weight; /* server weight */
|
||||
unsigned long cflags; /* config flags */
|
||||
atomic_t last_weight; /* server latest weight */
|
||||
|
||||
/* connection thresholds */
|
||||
u32 l_threshold_val;/* used lower threshold */
|
||||
u32 u_threshold_val;/* used upper threshold */
|
||||
/* 32/48 */
|
||||
u32 l_threshold; /* lower threshold */
|
||||
u32 u_threshold; /* upper threshold */
|
||||
|
||||
unsigned long cflags; /* config flags */
|
||||
|
||||
/* 44/64 */
|
||||
atomic_t conn_flags; /* flags to copy to conn */
|
||||
|
||||
__u16 tun_type; /* tunnel type */
|
||||
__be16 tun_port; /* tunnel port */
|
||||
__u16 tun_flags; /* tunnel flags */
|
||||
|
||||
u16 af; /* address family */
|
||||
__be16 port; /* port number of the server */
|
||||
/* 60/80 */
|
||||
union nf_inet_addr addr; /* IP address of the server */
|
||||
|
||||
/* connection counters */
|
||||
atomic_t totalconns; /* total connections */
|
||||
atomic_t activeconns; /* active connections */
|
||||
atomic_t persistconns; /* persistent connections */
|
||||
|
||||
refcount_t refcnt; /* reference counter */
|
||||
struct ip_vs_stats stats; /* statistics */
|
||||
unsigned long idle_start; /* start time, jiffies */
|
||||
|
||||
/* connection counters and thresholds */
|
||||
atomic_t activeconns; /* active connections */
|
||||
atomic_t totalconns; /* total connections */
|
||||
atomic_t persistconns; /* persistent connections */
|
||||
__u32 u_threshold; /* upper threshold */
|
||||
__u32 l_threshold; /* lower threshold */
|
||||
__u32 l_threshold_val;/* used lower threshold */
|
||||
|
||||
/* for destination cache */
|
||||
spinlock_t dst_lock; /* lock of dst_cache */
|
||||
struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */
|
||||
|
|
@ -1915,7 +1923,13 @@ static inline void ip_vs_dest_put_and_free(struct ip_vs_dest *dest)
|
|||
kfree(dest);
|
||||
}
|
||||
|
||||
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode);
|
||||
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, bool overload);
|
||||
|
||||
/* Check if dest is in overloaded state */
|
||||
static inline bool ip_vs_dest_is_overloaded(const struct ip_vs_dest *dest)
|
||||
{
|
||||
return READ_ONCE(dest->l_threshold_val);
|
||||
}
|
||||
|
||||
/* IPVS sync daemon data and function prototypes
|
||||
* (from ip_vs_sync.c)
|
||||
|
|
|
|||
|
|
@ -357,6 +357,11 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
|
|||
if (!skb_valid_dst(skb_in) && nf_reject_fill_skb_dst(skb_in) < 0)
|
||||
return;
|
||||
|
||||
if (hook == NF_INET_INGRESS) {
|
||||
memset(IPCB(skb_in), 0, sizeof(*IPCB(skb_in)));
|
||||
IPCB(skb_in)->iif = skb_in->skb_iif;
|
||||
}
|
||||
|
||||
if (skb_csum_unnecessary(skb_in) ||
|
||||
!nf_reject_verify_csum(skb_in, dataoff, proto)) {
|
||||
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
|
|||
{
|
||||
u8 nexthdr = ipv6_hdr(skb)->nexthdr;
|
||||
const int netoff = skb_network_offset(skb);
|
||||
u8 prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);
|
||||
int prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);
|
||||
int start = netoff + sizeof(struct ipv6hdr);
|
||||
int len = skb->len - start;
|
||||
u8 prevhdr = NEXTHDR_IPV6;
|
||||
|
|
|
|||
|
|
@ -444,6 +444,11 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
|
|||
if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
|
||||
skb_in->dev = net->loopback_dev;
|
||||
|
||||
if (hooknum == NF_INET_INGRESS) {
|
||||
memset(IP6CB(skb_in), 0, sizeof(*IP6CB(skb_in)));
|
||||
IP6CB(skb_in)->iif = skb_in->skb_iif;
|
||||
}
|
||||
|
||||
if (!skb_valid_dst(skb_in) && nf_reject6_fill_skb_dst(skb_in) < 0)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -1153,8 +1153,8 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
|
|||
if (!(flags & IP_VS_CONN_F_INACTIVE))
|
||||
atomic_inc(&dest->activeconns);
|
||||
tc = atomic_inc_return(&dest->totalconns);
|
||||
if (tc == READ_ONCE(dest->u_threshold))
|
||||
ip_vs_dest_update_overload(dest, 1);
|
||||
if (tc >= READ_ONCE(dest->u_threshold_val))
|
||||
ip_vs_dest_update_overload(dest, true);
|
||||
} else {
|
||||
/* It is a persistent connection/template, so increase
|
||||
the persistent connection counter */
|
||||
|
|
@ -1246,8 +1246,8 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp)
|
|||
if (!(cp->flags & IP_VS_CONN_F_INACTIVE))
|
||||
atomic_dec(&dest->activeconns);
|
||||
tc = atomic_fetch_dec(&dest->totalconns);
|
||||
if (tc == READ_ONCE(dest->l_threshold_val))
|
||||
ip_vs_dest_update_overload(dest, -1);
|
||||
if (tc <= READ_ONCE(dest->l_threshold_val))
|
||||
ip_vs_dest_update_overload(dest, false);
|
||||
} else {
|
||||
/* It is a persistent connection/template, so decrease
|
||||
the persistent connection counter */
|
||||
|
|
|
|||
|
|
@ -1309,32 +1309,32 @@ void ip_vs_stats_free(struct ip_vs_stats *stats)
|
|||
* - conns reach u_threshold and exceed it: set the flag
|
||||
* - conns go below l_threshold (or 75% of u_threshold): clear the flag
|
||||
*/
|
||||
static void __ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode)
|
||||
static void __ip_vs_dest_update_overload(struct ip_vs_dest *dest, bool overload)
|
||||
{
|
||||
int conns;
|
||||
u32 l, u;
|
||||
|
||||
lockdep_assert_held(&dest->dst_lock);
|
||||
u = READ_ONCE(dest->u_threshold);
|
||||
if (!u)
|
||||
goto unset;
|
||||
l = READ_ONCE(dest->l_threshold_val);
|
||||
conns = atomic_read(&dest->totalconns);
|
||||
if (conns >= (mode > 0 ? l : u)) {
|
||||
dest->flags |= IP_VS_DEST_F_OVERLOAD;
|
||||
return;
|
||||
if (u) {
|
||||
/* Low threshold defaults to 75% of upper threshold */
|
||||
l = READ_ONCE(dest->l_threshold) ? : (u - (u >> 2));
|
||||
conns = atomic_read(&dest->totalconns);
|
||||
if (conns >= (overload ? l : u)) {
|
||||
WRITE_ONCE(dest->u_threshold_val, INT_MAX);
|
||||
WRITE_ONCE(dest->l_threshold_val, l);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (conns >= (mode < 0 ? u : l))
|
||||
return;
|
||||
|
||||
unset:
|
||||
dest->flags &= ~IP_VS_DEST_F_OVERLOAD;
|
||||
WRITE_ONCE(dest->u_threshold_val, u ? : INT_MAX);
|
||||
WRITE_ONCE(dest->l_threshold_val, 0);
|
||||
}
|
||||
|
||||
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, int mode)
|
||||
void ip_vs_dest_update_overload(struct ip_vs_dest *dest, bool overload)
|
||||
{
|
||||
spin_lock_bh(&dest->dst_lock);
|
||||
__ip_vs_dest_update_overload(dest, mode);
|
||||
__ip_vs_dest_update_overload(dest, overload);
|
||||
spin_unlock_bh(&dest->dst_lock);
|
||||
}
|
||||
|
||||
|
|
@ -1406,15 +1406,13 @@ __ip_vs_update_dest(struct ip_vs_service *svc, struct ip_vs_dest *dest,
|
|||
|
||||
if (READ_ONCE(dest->u_threshold) != udest->u_threshold ||
|
||||
READ_ONCE(dest->l_threshold) != udest->l_threshold) {
|
||||
bool overload;
|
||||
|
||||
spin_lock_bh(&dest->dst_lock);
|
||||
WRITE_ONCE(dest->u_threshold, udest->u_threshold);
|
||||
WRITE_ONCE(dest->l_threshold, udest->l_threshold);
|
||||
/* Low threshold defaults to 75% of upper threshold */
|
||||
WRITE_ONCE(dest->l_threshold_val,
|
||||
udest->l_threshold ? :
|
||||
(udest->u_threshold -
|
||||
(udest->u_threshold >> 2)));
|
||||
__ip_vs_dest_update_overload(dest, 0);
|
||||
overload = ip_vs_dest_is_overloaded(dest);
|
||||
__ip_vs_dest_update_overload(dest, overload);
|
||||
spin_unlock_bh(&dest->dst_lock);
|
||||
}
|
||||
|
||||
|
|
@ -2454,6 +2452,8 @@ proc_do_sync_threshold(const struct ctl_table *table, int write,
|
|||
mutex_lock(&ipvs->sync_mutex);
|
||||
memcpy(val, valp, sizeof(val));
|
||||
rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
|
||||
if (rc)
|
||||
goto out;
|
||||
if (write) {
|
||||
if (val[0] < 0 || val[1] < 0 ||
|
||||
(val[0] >= val[1] && val[1]))
|
||||
|
|
@ -2461,6 +2461,7 @@ proc_do_sync_threshold(const struct ctl_table *table, int write,
|
|||
else
|
||||
memcpy(valp, val, sizeof(val));
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&ipvs->sync_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,16 +195,6 @@ static int ip_vs_dh_dest_changed(struct ip_vs_service *svc,
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* If the dest flags is set with IP_VS_DEST_F_OVERLOAD,
|
||||
* consider that the server is overloaded here.
|
||||
*/
|
||||
static inline int is_overloaded(struct ip_vs_dest *dest)
|
||||
{
|
||||
return dest->flags & IP_VS_DEST_F_OVERLOAD;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Destination hashing scheduling
|
||||
*/
|
||||
|
|
@ -219,10 +209,8 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
|
||||
s = (struct ip_vs_dh_state *) svc->sched_data;
|
||||
dest = ip_vs_dh_get(svc->af, s, &iph->daddr);
|
||||
if (!dest ||
|
||||
!(dest->cflags & IP_VS_DEST_CF_AVAILABLE)
|
||||
|| atomic_read(&dest->weight) <= 0
|
||||
|| is_overloaded(dest)) {
|
||||
if (!dest || atomic_read(&dest->weight) <= 0 ||
|
||||
ip_vs_dest_is_overloaded(dest)) {
|
||||
ip_vs_scheduler_err(svc, "no destination available");
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ ip_vs_fo_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
* Find virtual server with highest weight and send it traffic
|
||||
*/
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
|
||||
if (!ip_vs_dest_is_overloaded(dest) &&
|
||||
atomic_read(&dest->weight) > hw) {
|
||||
hweight = dest;
|
||||
hw = atomic_read(&dest->weight);
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
|
|||
* new connection.
|
||||
*/
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
if (atomic_read(&dest->weight) > 0) {
|
||||
least = dest;
|
||||
|
|
@ -433,7 +433,7 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc)
|
|||
*/
|
||||
nextstage:
|
||||
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
|
||||
doh = ip_vs_dest_conn_overhead(dest);
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
|
|||
/* select the first destination server, whose weight > 0 */
|
||||
list_for_each_entry_rcu(e, &set->list, list) {
|
||||
least = e->dest;
|
||||
if (least->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(least))
|
||||
continue;
|
||||
|
||||
if ((atomic_read(&least->weight) > 0) &&
|
||||
|
|
@ -181,7 +181,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set)
|
|||
nextstage:
|
||||
list_for_each_entry_continue_rcu(e, &set->list, list) {
|
||||
dest = e->dest;
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
|
||||
doh = ip_vs_dest_conn_overhead(dest);
|
||||
|
|
@ -580,7 +580,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
|
|||
* new connection.
|
||||
*/
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
|
||||
if (atomic_read(&dest->weight) > 0) {
|
||||
|
|
@ -596,7 +596,7 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc)
|
|||
*/
|
||||
nextstage:
|
||||
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
|
||||
doh = ip_vs_dest_conn_overhead(dest);
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ ip_vs_lc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
*/
|
||||
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
|
||||
if (ip_vs_dest_is_overloaded(dest) ||
|
||||
atomic_read(&dest->weight) == 0)
|
||||
continue;
|
||||
doh = ip_vs_dest_conn_overhead(dest);
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ static inline void generate_hash_secret(hsiphash_key_t *hash1,
|
|||
static inline bool is_unavailable(struct ip_vs_dest *dest)
|
||||
{
|
||||
return atomic_read(&dest->weight) <= 0 ||
|
||||
dest->flags & IP_VS_DEST_F_OVERLOAD;
|
||||
ip_vs_dest_is_overloaded(dest);
|
||||
}
|
||||
|
||||
/* Returns hash value for IPVS MH entry */
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ ip_vs_nq_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD ||
|
||||
if (ip_vs_dest_is_overloaded(dest) ||
|
||||
!atomic_read(&dest->weight))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ ip_vs_ovf_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
*/
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
w = atomic_read(&dest->weight);
|
||||
if ((dest->flags & IP_VS_DEST_F_OVERLOAD) ||
|
||||
if (ip_vs_dest_is_overloaded(dest) ||
|
||||
atomic_read(&dest->activeconns) > w ||
|
||||
w == 0)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ ip_vs_rr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
list_for_each_entry_continue_rcu(dest,
|
||||
&svc->destinations,
|
||||
n_list) {
|
||||
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
|
||||
if (!ip_vs_dest_is_overloaded(dest) &&
|
||||
atomic_read(&dest->weight) > 0)
|
||||
/* HIT */
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
*/
|
||||
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
|
||||
if (!ip_vs_dest_is_overloaded(dest) &&
|
||||
atomic_read(&dest->weight) > 0) {
|
||||
least = dest;
|
||||
loh = ip_vs_sed_dest_overhead(least);
|
||||
|
|
@ -90,7 +90,7 @@ ip_vs_sed_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
*/
|
||||
nextstage:
|
||||
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
doh = ip_vs_sed_dest_overhead(dest);
|
||||
if ((__s64)loh * atomic_read(&dest->weight) >
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ struct ip_vs_sh_state {
|
|||
static inline bool is_unavailable(struct ip_vs_dest *dest)
|
||||
{
|
||||
return atomic_read(&dest->weight) <= 0 ||
|
||||
dest->flags & IP_VS_DEST_F_OVERLOAD;
|
||||
ip_vs_dest_is_overloaded(dest);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ static struct ip_vs_dest *ip_vs_twos_schedule(struct ip_vs_service *svc,
|
|||
|
||||
/* Generate a random weight between [0,sum of all weights) */
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD)) {
|
||||
if (!ip_vs_dest_is_overloaded(dest)) {
|
||||
weight = atomic_read(&dest->weight);
|
||||
if (weight > 0) {
|
||||
total_weight += weight;
|
||||
|
|
@ -75,7 +75,7 @@ static struct ip_vs_dest *ip_vs_twos_schedule(struct ip_vs_service *svc,
|
|||
|
||||
/* Pick two weighted servers */
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
|
||||
weight = atomic_read(&dest->weight);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
*/
|
||||
|
||||
list_for_each_entry_rcu(dest, &svc->destinations, n_list) {
|
||||
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
|
||||
if (!ip_vs_dest_is_overloaded(dest) &&
|
||||
atomic_read(&dest->weight) > 0) {
|
||||
least = dest;
|
||||
loh = ip_vs_dest_conn_overhead(least);
|
||||
|
|
@ -62,7 +62,7 @@ ip_vs_wlc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
*/
|
||||
nextstage:
|
||||
list_for_each_entry_continue_rcu(dest, &svc->destinations, n_list) {
|
||||
if (dest->flags & IP_VS_DEST_F_OVERLOAD)
|
||||
if (ip_vs_dest_is_overloaded(dest))
|
||||
continue;
|
||||
doh = ip_vs_dest_conn_overhead(dest);
|
||||
if ((__s64)loh * atomic_read(&dest->weight) >
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ ip_vs_wrr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb,
|
|||
list_for_each_entry_continue_rcu(dest,
|
||||
&svc->destinations,
|
||||
n_list) {
|
||||
if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
|
||||
if (!ip_vs_dest_is_overloaded(dest) &&
|
||||
atomic_read(&dest->weight) >= mark->cw)
|
||||
goto found;
|
||||
if (dest == stop)
|
||||
|
|
|
|||
|
|
@ -1098,13 +1098,13 @@ static int ctnetlink_filter_match_tuple(struct nf_conntrack_tuple *filter_tuple,
|
|||
break;
|
||||
case NFPROTO_IPV6:
|
||||
if ((flags & CTA_FILTER_FLAG(CTA_IP_SRC)) &&
|
||||
!ipv6_addr_cmp(&filter_tuple->src.u3.in6,
|
||||
&ct_tuple->src.u3.in6))
|
||||
ipv6_addr_cmp(&filter_tuple->src.u3.in6,
|
||||
&ct_tuple->src.u3.in6))
|
||||
return 0;
|
||||
|
||||
if ((flags & CTA_FILTER_FLAG(CTA_IP_DST)) &&
|
||||
!ipv6_addr_cmp(&filter_tuple->dst.u3.in6,
|
||||
&ct_tuple->dst.u3.in6))
|
||||
ipv6_addr_cmp(&filter_tuple->dst.u3.in6,
|
||||
&ct_tuple->dst.u3.in6))
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,14 +170,14 @@ static void nf_flow_tuple_encap(struct nf_flowtable_ctx *ctx,
|
|||
int i = 0;
|
||||
|
||||
if (skb_vlan_tag_present(skb)) {
|
||||
tuple->encap[i].id = skb_vlan_tag_get(skb);
|
||||
tuple->encap[i].id = skb_vlan_tag_get_id(skb);
|
||||
tuple->encap[i].proto = skb->vlan_proto;
|
||||
i++;
|
||||
}
|
||||
switch (skb->protocol) {
|
||||
case htons(ETH_P_8021Q):
|
||||
veth = (struct vlan_ethhdr *)skb_mac_header(skb);
|
||||
tuple->encap[i].id = ntohs(veth->h_vlan_TCI);
|
||||
tuple->encap[i].id = ntohs(veth->h_vlan_TCI) & VLAN_VID_MASK;
|
||||
tuple->encap[i].proto = skb->protocol;
|
||||
offset += VLAN_HLEN;
|
||||
break;
|
||||
|
|
@ -502,6 +502,7 @@ static int nf_flow_offload_forward(struct nf_flowtable_ctx *ctx,
|
|||
|
||||
nf_flow_encap_pop(ctx, skb, tuplehash);
|
||||
thoff -= ctx->offset;
|
||||
skb_set_transport_header(skb, thoff);
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
nf_flow_nat_ip(flow, skb, thoff, dir, iph);
|
||||
|
|
@ -1097,6 +1098,7 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx,
|
|||
flow_offload_refresh(flow_table, flow, false);
|
||||
|
||||
nf_flow_encap_pop(ctx, skb, tuplehash);
|
||||
skb_set_transport_header(skb, sizeof(*ip6h));
|
||||
|
||||
ip6h = ipv6_hdr(skb);
|
||||
nf_flow_nat_ipv6(flow, skb, dir, ip6h);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <net/gre.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
|
|
@ -1008,11 +1009,14 @@ static bool nft_payload_validate_inet_csum_offset(const struct nft_ctx *ctx,
|
|||
if (priv->csum_flags) /* makes no sense, asks for "re-update" of L4 checksum */
|
||||
return false;
|
||||
|
||||
/* no further check here; offset can't be negative so bogus
|
||||
* offsets can corrupt L4 or payload but not l3 headers.
|
||||
* We already allow arbitrary l4/inner payload writes.
|
||||
*/
|
||||
return true;
|
||||
/* Validate csum_offset is one of the supported transport header checksums */
|
||||
if (priv->csum_offset == offsetof(struct tcphdr, check) ||
|
||||
priv->csum_offset == offsetof(struct udphdr, check) ||
|
||||
priv->csum_offset == offsetof(struct icmphdr, checksum) ||
|
||||
priv->csum_offset == offsetof(struct icmp6hdr, icmp6_cksum))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case NFT_PAYLOAD_INNER_HEADER:
|
||||
return true;
|
||||
case NFT_PAYLOAD_TUN_HEADER:
|
||||
|
|
@ -1046,6 +1050,27 @@ static bool nft_payload_csum_nh_write_ok(const struct nft_payload_set *priv,
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool nft_payload_csum_th_write_ok(const struct nft_payload_set *priv,
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
if (!(pkt->flags & NFT_PKTINFO_L4PROTO))
|
||||
return false;
|
||||
|
||||
switch (pkt->tprot) {
|
||||
case IPPROTO_TCP:
|
||||
return priv->csum_offset == offsetof(struct tcphdr, check);
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
return priv->csum_offset == offsetof(struct udphdr, check);
|
||||
case IPPROTO_ICMPV6:
|
||||
return priv->csum_offset == offsetof(struct icmp6hdr, icmp6_cksum);
|
||||
case IPPROTO_ICMP:
|
||||
return priv->csum_offset == offsetof(struct icmphdr, checksum);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
|
||||
const struct nft_payload_set *priv)
|
||||
{
|
||||
|
|
@ -1055,9 +1080,10 @@ static bool nft_payload_csum_write_ok(const struct nft_pktinfo *pkt,
|
|||
case NFT_PAYLOAD_NETWORK_HEADER:
|
||||
return nft_payload_csum_nh_write_ok(priv, pkt);
|
||||
case NFT_PAYLOAD_TRANSPORT_HEADER:
|
||||
return nft_payload_csum_th_write_ok(priv, pkt);
|
||||
case NFT_PAYLOAD_INNER_HEADER:
|
||||
/* neither offsets are validated, offsets cannot be
|
||||
* negative so real l3 headers cannot be mangled.
|
||||
/* offset is not validated, offset cannot be
|
||||
* negative so real l3/l4 headers cannot be mangled.
|
||||
*/
|
||||
return true;
|
||||
case NFT_PAYLOAD_TUN_HEADER:
|
||||
|
|
|
|||
|
|
@ -1091,7 +1091,8 @@ static void nft_rbtree_commit(struct nft_set *set)
|
|||
* representation. Use next start element to complete this
|
||||
* interval.
|
||||
*/
|
||||
if (nft_rbtree_interval_start(rbe) &&
|
||||
if (nft_set_is_anonymous(set) &&
|
||||
nft_rbtree_interval_start(rbe) &&
|
||||
nft_rbtree_interval_start(prev_rbe) &&
|
||||
priv->array_next->intervals[num_intervals].from)
|
||||
priv->array_next->intervals[num_intervals++].to = &prev_rbe->ext;
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ dccp_find_option(u_int8_t option,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (op[i] < 2 || i == optlen - 1)
|
||||
if (op[i] <= DCCPO_MAX_RESERVED || i == optlen - 1)
|
||||
i++;
|
||||
else
|
||||
i += op[i + 1] ? : 1;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user