Qrunch から引っ越し
conntrack については nf_conntrack_max の話題を時々聞くが、
ipvs のセッション数はリミットを気にしなくていいんだっけ。
ちょうど手元にあった kernel-ml-4.13.5-1.el7.elrepo.nosrc.rpm
のソースで確認
そもそも nf_conntrack_max はどうなっているのか確認
net/netfilter/nf_conntrack_core.c
static struct nf_conn *
__nf_conntrack_alloc(struct net *net,
const struct nf_conntrack_zone *zone,
const struct nf_conntrack_tuple *orig,
const struct nf_conntrack_tuple *repl,
gfp_t gfp, u32 hash)
{
struct nf_conn *ct;
/* We don't want any race condition at early drop stage */
atomic_inc(&net->ct.count);
if (nf_conntrack_max &&
unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
if (!early_drop(net, hash)) {
if (!conntrack_gc_work.early_drop)
conntrack_gc_work.early_drop = true;
atomic_dec(&net->ct.count);
net_warn_ratelimited("nf_conntrack: table full, dropping packet\n");
return ERR_PTR(-ENOMEM);
}
}
/*
* Do not use kmem_cache_zalloc(), as this cache uses
* SLAB_TYPESAFE_BY_RCU.
*/
ct = kmem_cache_alloc(nf_conntrack_cachep, gfp);
if (ct == NULL)
goto out;
対象の netns の conntrack の数が nf_conntrack_max より多ければログを出して抜ける。
nf_conntrack_max 以下の場合はその次の処理 kmem_cache_alloc() で nf_conn 構造体の領域が割り当てられるようだ。
続いて ipvs の場合はどうか確認
net/netfilter/ipvs/ip_vs_conn.c
truct ip_vs_conn *
ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
const union nf_inet_addr *daddr, __be16 dport, unsigned int flags,
struct ip_vs_dest *dest, __u32 fwmark)
{
struct ip_vs_conn *cp;
struct netns_ipvs *ipvs = p->ipvs;
struct ip_vs_proto_data *pd = ip_vs_proto_data_get(p->ipvs,
p->protocol);
cp = kmem_cache_alloc(ip_vs_conn_cachep, GFP_ATOMIC);
if (cp == NULL) {
IP_VS_ERR_RL("%s(): no memory\n", __func__);
return NULL;
}
ip_vs_conn_new() にそれらしきものは無い。呼び出し元を見ても、特に何かのパラメータによる制限は無さそう。
スラブアロケータは全然分かってないけど、inode のキャッシュでめっちゃメモリ食われてたという話を聞くし、メモリが空いている限り使えるのだろう。
そういえば inode のキャッシュって drop_caches で消せるけど、これは大丈夫なんだろうか。多分何か識別するものがあるはずなので xfs の inode あたりを確認してみる。
fs/xfs/xfs_super.c
xfs_inode_zone =
kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode",
KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | KM_ZONE_SPREAD |
KM_ZONE_ACCOUNT, xfs_fs_inode_init_once);
fs/xfs/kmem.h
#define KM_ZONE_RECLAIM SLAB_RECLAIM_ACCOUNT
/* 勝手に省略 */
static inline kmem_zone_t *
kmem_zone_init_flags(int size, char *zone_name, unsigned long flags,
void (*construct)(void *))
{
return kmem_cache_create(zone_name, size, 0, flags, construct);
}
include/linux/slab.h
/* The following flags affect the page allocator grouping pages by mobility */
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
kmem_cache_create() する時に SLAB_RECLAIM_ACCOUNT のフラグ渡しているようだ。
ipvs で kmem_cache_create() しているところはこのフラグが無かったので大丈夫なのだろう
net/netfilter/ipvs/ip_vs_conn.c
int __init ip_vs_conn_init(void)
{
int idx;
/* Compute size and mask */
ip_vs_conn_tab_size = 1 << ip_vs_conn_tab_bits;
ip_vs_conn_tab_mask = ip_vs_conn_tab_size - 1;
/*
* Allocate the connection hash table and initialize its list heads
*/
ip_vs_conn_tab = vmalloc(ip_vs_conn_tab_size * sizeof(*ip_vs_conn_tab));
if (!ip_vs_conn_tab)
return -ENOMEM;
/* Allocate ip_vs_conn slab cache */
ip_vs_conn_cachep = kmem_cache_create("ip_vs_conn",
sizeof(struct ip_vs_conn), 0,
SLAB_HWCACHE_ALIGN, NULL);
if (!ip_vs_conn_cachep) {
vfree(ip_vs_conn_tab);
return -ENOMEM;
}
nf_conntrack_max のような全体の (network namespace 毎の) 制限値は無さそうだが、ググったらサービス毎に上限を設定できるらしい。
ipvsadm -h から抜粋すると以下の部分のようだ。
--u-threshold -x uthreshold upper threshold of connections
--l-threshold -y lthreshold lower threshold of connections
lower threshold はどういう時に使うのかよく分からない。気にしないでおく。
upper threshold もそうだが、明示的に指定しなければ制限しないようだ。
ipvsadm -ln --thresholds
した時に Uthreshold が 0 になっていれば制限されていない。
ちょっと試してみたところ、すべての real server が upper threshold に達した状態で新規セッションの通信がきた場合は ICMP Port Unreachable を返すようだ。
それはいいのだが、セッションの数として inactive なセッションもカウントされているので、セッションを使い続けるのではなく接続・切断が頻繁に起こる場合などでは TIME_WAIT が多くなってしまい、制限方法として採用しづらい。
net/netfilter/ipvs/ip_vs_conn.c
static inline int ip_vs_dest_totalconns(struct ip_vs_dest *dest)
{
return atomic_read(&dest->activeconns)
+ atomic_read(&dest->inactconns);
}
/*
* Bind a connection entry with a virtual service destination
* Called just after a new connection entry is created.
*/
static inline void
ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest)
{
/* 勝手に省略 */
if (dest->u_threshold != 0 &&
ip_vs_dest_totalconns(dest) >= dest->u_threshold)
dest->flags |= IP_VS_DEST_F_OVERLOAD;
}
lower/upper threshold を使っていなければ、ipvs セッション上限は気にしない。メモリの量は気にする。
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント