ipvsのthresholdからsorry_serverへ飛ばしたい

ipvsの接続数がthresholdを超えたら「ごめんなさいサーバ」に飛ばせるように試行錯誤中です。
まあ、問題は「ごめんなさいサーバ」をどのように指定してどのように内部で保持するかですかね。

で、なにげに ip_vs_rr.c を眺めててふと思ったんですが、転送先を決定するときは、

・IP_VS_DEST_F_OVERLOADフラグが立っていない
・weightが0より大きい

この両方の条件を満たす転送先を探す訳ですけど、ここを

・IP_VS_DEST_F_OVERLOADフラグが立っていない
・weightが1より大きい

に変えて、weight==1 の転送先を「ごめんなさいサーバ」とみなす事で、構造体に手を加えず
に実現できそうな感じがします。

というわけで、試しに ip_vs_rr.c だけですが、こんな感じで書き換えてみました。

--- linux-2.6.12.6/net/ipv4/ipvs/ip_vs_rr.c     2005-08-30 01:55:27.000000000 +0900
+++ linux-2.6.12.6-sorry/net/ipv4/ipvs/ip_vs_rr.c       2007-03-27 23:19:34.000000000 +0900
@@ -71,11 +71,27 @@
 
                dest = list_entry(q, struct ip_vs_dest, n_list);
                if (!(dest->flags & IP_VS_DEST_F_OVERLOAD) &&
-                   atomic_read(&dest->weight) > 0)
+                   atomic_read(&dest->weight) > 1)
                        /* HIT */
                        goto out;
                q = q->next;
        } while (q != p);
+       /*----- find w==1 -----*/
+       p = (struct list_head *)svc->sched_data;
+       p = p->next;
+       q = p;
+       do {
+               /* skip list head */
+               if (q == &svc->destinations) {
+                       q = q->next;
+                       continue;
+               }
+
+               dest = list_entry(q, struct ip_vs_dest, n_list);
+               if( atomic_read(&dest->weight) == 1 )
+                       goto out;
+               q = q->next;
+       } while (q != p);
        write_unlock(&svc->sched_lock);
        return NULL;

で、keepalived.confはこんな感じにします。

virtual_server 10.37.129.3 {
  delay_loop 6
  lb_algo rr
  lb_kind NAT
  nat_mask 255.255.255.0
  persistence_timeout 0
  protocol TCP
  
  #----- sprry_serverの代わり -----
  real_server 127.0.0.4 22 {
    weight 1
  }
  real_server 127.0.0.2 22 {
    lthreshold 0
    uthreshold 2
    weight 2
  }
  real_server 127.0.0.3 22 {
    lthreshold 0
    uthreshold 2
    weight 2
  }
}

そしてkeepalivedを起動して別のマシンから ssh 10.37.129.3 しまくると・・・

# ipvsadm -Ln             
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.37.129.3:22 rr
  -> 127.0.0.3:22                 Local   2      3          0         
  -> 127.0.0.2:22                 Local   2      3          0         
  -> 127.0.0.4:22                 Local   1      0          0  

weightが1な127.0.0.4以外の転送先にのみ接続されていることがわかります。
もう一回sshすると、本来はuthresholdいっぱいいっぱいなので蹴られますが、ここでは
127.0.0.4に対して転送されるようになるはずです。

# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.37.129.3:22 rr
  -> 127.0.0.3:22                 Local   2      3          0         
  -> 127.0.0.2:22                 Local   2      3          0         
  -> 127.0.0.4:22                 Local   1      1          0 

おお、いいじゃん(笑
これで、接続数がしきい値を超えた場合に「ごめんなさいサーバ」へ飛ばすという目的は達成できました。
ただまあ、このままweightが1な転送先を「ごめんなさいサーバ」とみなすのもいまいち感が漂うのでもう少
しどうにかにしょうかと思います。