02-Mar-2012 05:23
we have an application sending SMS via SMPP and we need to balance the SMS messages based on recipient address to 2 different SMS Centres. SMS with recipient address starting 420 should go to SMSC1 and the rest of SMS's should go to SMSC2. Note that application creates one TCP session and throught this session sends multiple SMS, one SMS is in one TCP packet or more SMS can be placed in one TCP packet.
Thanks
02-Mar-2012 11:34
Could you clarify what you are looking for a little more?
Did you want to direct the traffic to a specific location based on the Client's IP Address or the Destination IP Address?
05-Mar-2012 00:55
I'm looking for routing based on recipient or destination address, in SMPP protocol it means the telephone number. I thing this should require the layer 7 routing as the SMPP protocol is based on pairs of request/response PDUs (protocol data units, or packets) exchanged over OSI layer 4 (TCP session). Is it possible to create an iRule to do the required task?
I do not want to direct the traffic based on destination IP address.
07-Mar-2012 09:39
it is possible. however, there are a few tings to note
- this requires one new feature called message-based load balancing (which is not available in GUI)
- you may need to replay bind message to multiple servers (I assume application create TCP connection and send bind request) I am curious what kind of bind message application use, bind_transmitter?
what kind of SMPP message you are refering to, submit_sm? what SMPP version? what BIG-IP version you are using?
it would be great if you can provide packet trace of your SMPP traffic. (if it does not contain any sensitive data)
Nat
08-Mar-2012 05:09
thanks for reply.
Application creates TCP connection and send bind_transiever. I need to route submit_sm messages from one application to more SMSC's. The submit_sm-resp and deliver_sm shall go from SMSC back to appl. Next, appl responses with deliver_sm-resp, which must go back to the SMSC previously sending deliver_sm.
We use SMPP v3.4
Pavel
08-Mar-2012
07:38
- last edited on
05-Jun-2023
06:12
by
JimmyPackets
here is something that should work... (however, I didnt test 🙂 )
the idea is to decode submit_sm to find dest-addr
rewrite sequence number of request that was sent from SMSC (and rewrite it back to its original value in the _resp)
you may need to apply mblb profile to virtual: modify ltm virtual smpp profiles add {mblb}
when CLIENT_ACCEPTED {
set s_seq_idx 1
set first_bind_resp 1
set smsc1 10.10.10.1
set smsc2 10.10.10.2
TCP::collect
}
when CLIENT_DATA {
while { [TCP::payload length] > 16 } {
binary scan [TCP::payload] IH8IIa* len oper status seq p
if { [TCP::payload length] < $len } {
TCP::collect $len
return
}
switch -glob $oper {
00000002 {
set bind_message [TCP::payload $len]
}
00000004 {
submit_sm
set p [string range $p [expr [string first \x00 $p]+1] end]
binary scan $p cca* ston snpi p
set p [string range $p [expr [string first \x00 $p]+1] end]
binary scan $p ccA* dton dnpi p
set dest [getfield $p \x00 1]
if { $dest starts_with 420 } {
use pool or node command
pool [LB::server pool] member $smsc1 9000
} else {
pool [LB::server pool] member $smsc2 9000
}
}
8* {
rewrite seq
if { [info exists s_seq_map($seq)] } {
set old_seq [lindex $s_seq_map($seq) 0]
TCP::payload replace 12 4 [binary format I $s_seq_idx]
set addr [lindex $s_seq_map($seq) 1]
set port [lindex $s_seq_map($seq) 2]
use pool or node command
pool [LB::server pool] member $addr $port
unset s_seq_map($seq)
}
}
}
TCP::release $len
TCP::notify request
}
TCP::collect
}
when SERVER_CONNECTED {
if { $first_bind_resp } {
TCP::collect
} else {
TCP::collect -all
TCP::respond $bind_message
}
}
when SERVER_DATA {
while { [TCP::payload length] > 16 } {
binary scan [TCP::payload] IH8II len oper status seq
if { [TCP::payload length] < $len } {
TCP::collect $len
return
}
switch -glob $oper {
0* {
rewrite seq
TCP::payload replace 12 4 [binary format I $s_seq_idx]
set s_seq_map($s_seq_idx) "$seq [IP::remote_addr] [TCP::remote_port]"
incr s_seq_idx
}
80000002 {
bind response
if { $first_bind_resp } {
set first_bind_resp 0
} else {
TCP::payload replace 0 [TCP::payload length] ""
set len 0
}
}
}
TCP::release $len
TCP::notify response
}
TCP::collect
}
Nat
08-Mar-2012
07:43
- last edited on
05-Jun-2023
06:12
by
JimmyPackets
while { [TCP::payload length] > 16 } {
should be
while { [TCP::payload length] >= 16 } {
22-Mar-2012 07:20
I have been playing with the BIG-IP last few days and your iRule works fine. I did only small corrections.
Great job! Thanks a lot.
Next I have to do some more tests in our environment, mainly with fault tolerance.
Pavel
22-Mar-2012 14:33
Thanks for update.
Glad to hear that it works.
Looking forward to hear more test result.
Nat
05-Apr-2012 01:03
iRule works fine, tested also for asynchronous SMPP transfer and for more clients.
Once again thank you.
Pavel
05-Apr-2012 09:39
This is cool. Thanks for letting me know.
I forgot to ask. 🙂
Last time you mentioned about a small correction that you fixes the iRule to make it works.
Could you let me know what are they?
Nat
06-Apr-2012 00:30
just small corrections:
- we use bind_transiever, oper is 00000009
- under CLIENT_DATA statement, switch 8*, the original seq number should be entered, the corrected line is:
TCP::payload replace 12 4 [binary format I $old_seq]
and next I added some log entries just to understand the iRule and to check the variables.
Regards
Pavel
06-Apr-2012 14:32
Thanks a lot.
Regards,
Nat
07-May-2012 06:30
I just want to configure the same with bit change.
If client submit message and message comes to Load Balancer and IRule executes that and it has to check the recipient address and take that recipient address connect to database or http check the number is in black list or not if it black list reject that message and send reject response to client if not block listed the processed the message to backed server.
Can any one help me regarding this script.
Regards,
Kiran Reddy
19-Jul-2012 12:18
Sorry for late reply.
I think in your case. you can use this method
https://devcentral.f5.com/wiki/irules.SIDEBAND.ashx
I think example (under Solutions section) on that page are pretty good.
also, I think using http would be easier than database call (if you mean mysql or the like) 🙂
Nat
19-Jul-2012 12:19
Sorry for late reply.
I think in your case. you can use this method
https://devcentral.f5.com/wiki/irules.SIDEBAND.ashx
I think example (under Solutions section) on that page are pretty good.
also, I think using http would be easier than database call (if you mean mysql or the like) 🙂
Nat
23-Nov-2015 11:42
Hi, I see that the topic is quite old, but it's really saving my day, so thanks. Then I got one more question. I could understand from the iRule shared here, that you are balancing based on recipient address, and that's great, but what happens if the ESME opens only one TCP session towards the BigIP? I mean for my case here, I have 2 SMSCs, and 1 ESME, the iRule balance the traffic towards the 2. But the BIND had been done only once towards one of the SMSCs. What is happening is that, when the second SMSC receives the Submit, it shows, "Invalid Bind status", and that's normal because there is no bind done towards the second SMSC. So my question here is that I'm wondering if there is a way, that when the BIND comes to the LB, it clones it towards the 2 SMSCs. If not, I would need some help to make one ESME open only one BIND towards each SMSC (kind of persistance but on 2 servers not only one). Thanks alot for your help ! Best Regards
24-Nov-2015
00:53
- last edited on
22-Nov-2022
07:11
by
JimmyPackets
Hi Hamdi Fersi,
This iRules should replicate the bind... this part of code should do that
when SERVER_CONNECTED {
if { $first_bind_resp } {
TCP::collect
} else {
TCP::collect -all
TCP::respond $bind_message
}
}
one thing to note, the very first iRules expect bind_transmitter (hex 0x00000002) in your case, it could be bind_transceiver (hex 0x00000009)?
anyway, this part of code record the bind message. you could change it from
switch -glob $oper {
00000002 {
set bind_message [TCP::payload $len]
}
to
switch -glob $oper {
00000002 -
00000009 {
set bind_message [TCP::payload $len]
}
so it will record the message for both type of bind
Nat
24-Nov-2015 02:06
Thanks Nat for your quick feedback. after testing that, I succeeded to get binded in one SMSC. but i never could be bound in both of them (with only one BIND request from the ESME). Do I need a second request from the ESME? The ELSE part of the SERVER_CONNECTED event is never reached. Thanks, BR//
24-Nov-2015 03:09
yes, in this iRule, it relies on second request from ESME in order to open connection to more server.
we can use trick like adding enquire_link into TCP::payload on CLIENT_DATA it will then be balanced to 2nd server and trigger the bind replay. however, doing this way, we may make sure we drop matching enquire_link_resp coming back from server
Nat
24-Nov-2015 03:16
Fixed ! I was sending the traffic to only one SMSC: 8* { rewrite seq if { [info exists s_seq_map($seq)] } { set old_seq [lindex $s_seq_map($seq) 0] TCP::payload replace 12 4 [binary format I $s_seq_idx] set addr [lindex $s_seq_map($seq) 1] set port [lindex $s_seq_map($seq) 2] use pool or node command pool [LB::server pool] member $addr $port unset s_seq_map($seq) } }
The thing here is that it's being replicated, but only after ~30seconds (after some Enquire_Link requests received). Thanks again for your help. BR//
10-Dec-2015 11:33
Is that normal that i'm never going into the rewrite block? 8* { rewrite seq if { [info exists s_seq_map($seq)] } { set old_seq [lindex $s_seq_map($seq) 0] TCP::payload replace 12 4 [binary format I $s_seq_idx] set addr [lindex $s_seq_map($seq) 1] set port [lindex $s_seq_map($seq) 2] use pool or node command pool [LB::server pool] member $addr $port unset s_seq_map($seq) } }
Neither: 0* { rewrite seq TCP::payload replace 12 4 [binary format I $s_seq_idx] set s_seq_map($s_seq_idx) "$seq [IP::remote_addr] [TCP::remote_port]" incr s_seq_idx }
14-Dec-2015 02:09
10-Dec-2015 21:48
Hi, I am new to Big-F5, I see that many threads in the message heading about SMPP talk about load balancing support based on SMPP protocol.
we have problem in hand to route the SMPP PDU based on the "system_id" parameter. I some one can help sharing the iLOG configuration, I would appreciate it.
SMPP Protoco:: The system_id parameter is used to identify an ESME or an SMSC at bind time.
24-Feb-2018 04:44
Hello everyone, i have a similar request. Requests are to hit load balancer ip, to two smpp firewalls to the SMSC.
Requests are to hit the loadbalancer each time before getting to any of the smpp firewalls. Which means the loadbalancer is hit thrice.
Is there any irule to ensure that once requests hit the loadbalancer, binds are formed with two or three smpp backend servers
24-Feb-2018 23:11
Hi Kazeem, It is possible to do bind over multiple SMPP backend server and keep them open. This is the concept of MBLB in the previous TMOS version or MRF in the newer TMOS version. However, it is better to do it one by one instead of opening bind all the same time. The iRule above written by Nat (natty76) should do the trick. Try that first and see what the road block.
27-Feb-2018 14:32
Hello Joko, Thanks for your prompt reply.NATTY76 on this thread, explained that adding enquire_link to TCP::payload under CLIENT_DATA,it will help to trigger bind replay .
How can this be configured.
ALSO, FOR MY SCENARIO, THERE ARE two separate smpp firewalls/filters, before requests hit the actual SMSC, my current scenari,is to have three separate load balancer instances before final request hits the SMSC.
This is my current irule for the first instance,
when CLIENT_ACCEPTED { set s_seq_idx 1 set first_bind_resp 1 set mm1 10.199.254.37%5 set mm2 10.199.254.38%5 set mm3 10.199.254.39%5 TCP::collect } when CLIENT_DATA { while { [TCP::payload length] >= 16 } { binary scan [TCP::payload] IH8IIa* len oper status seq p if { [TCP::payload length] < $len } { TCP::collect $len return } switch -glob $oper { 00000002 - 00000009 { set bind_message [TCP::payload $len] } 00000004 { submit_sm set p [string range $p [expr [string first \x00 $p]+1] end] binary scan $p cca* ston snpi p set p [string range $p [expr [string first \x00 $p]+1] end] binary scan $p ccA* dton dnpi p set dest [getfield $p \x00 1] if { $dest starts_with 420 } { use pool or node command pool [LB::server pool] member $mm3 9000 } else { pool [LB::server pool] member $mm1 9000 } elseif { pool [LB::server pool] member $mm2 9000 } } 8* { rewrite seq if { [info exists s_seq_map($seq)] } { set old_seq [lindex $s_seq_map($seq) 0] TCP::payload replace 12 4 [binary format I $s_seq_idx] set addr [lindex $s_seq_map($seq) 1] set port [lindex $s_seq_map($seq) 2] use pool or node command pool [LB::server pool] member $addr $port unset s_seq_map($seq) } } } TCP::release $len TCP::notify request } TCP::collect } when SERVER_CONNECTED { if { $first_bind_resp } { TCP::collect } else { TCP::collect -all TCP::respond $bind_message } } when SERVER_DATA { while { [TCP::payload length] >= 16 } { binary scan [TCP::payload] IH8II len oper status seq if { [TCP::payload length] < $len } { TCP::collect $len return } switch -glob $oper { 0* { rewrite seq TCP::payload replace 12 4 [binary format I $s_seq_idx] set s_seq_map($s_seq_idx) "$seq [IP::remote_addr] [TCP::remote_port]" incr s_seq_idx } 80000002 { bind response if { $first_bind_resp } { set first_bind_resp 0 } else { TCP::payload replace 0 [TCP::payload length] "" set len 0 } } } TCP::release $len TCP::notify response } TCP::collect }
27-Feb-2018 14:48
Hi Joko, How do i add the mrf profile to the virtual server.
28-Feb-2018 09:39
Hello Joko, Thanks for the heads up, the smpp binds hit the 1st smpp firewall, when the request is to be forwarded to the second F5 ip, it returns an invalid system id field.
How can a system id be included inside an SMPP VIP
My topology involves an ESME, two smpp firewalls which communicate via separate F5 vip's To the SMSC.
So, my topology looks like this.
ESME>>>1ST F5 VIP
1ST F5 VIP forwards t0 1st smpp firewalls.
1st smpp firewalls are configured to forward to second f5 VIP.
1ST SMPP FW>>>>>2ND F5 VIP
2nd F5 VIP load balances to 2nd smpp firewalls.
2nd f5 vip>>>2nd smpp firewalls.
2nd smpp firewalls are configured to forward to third f5 vip.
2nd smpp firewalls >>>>> third f5 vip.
third f5 vip load balances to SMSC.
3rd f5 vip>>>SMSC.
The irule used is listed in comment. The bind tranceiver message hits the 1st smpp firewall, and fails on hitting the second F5 VIP, as the second F5 VIP doesn't have the SYSTEM ID parameter configured.
How do i configure the system ID on the 2nd and third F5 VIP's.
28-Feb-2018 11:17
Dear Kazeem,
Honestly, I totally forgot the SMPP spec as my last encounter with SMPP is on 2013. So, I can't help much further about the system ID.
I am more interested in the architecture. I am not sure why there are multiple firewalls with F5 in between. Anyhow, I believe the iRule should be placed in the 3rd VIP instead of the 1st. It should be plain TCP LB in 1st VIP and 2nd VIP. The 3rd VIP should be the one talking SMPP to the SMPP server and doing the MBLB.
Cheers,
-joko
28-Feb-2018 13:17
Thank you Joko, however, i don't understand what you mean by TCP LOAD BALANCING.
Can you please explain or give example of TCP load balancing to a pool of servers
28-Feb-2018 20:30
TCP load balancing means that F5 conduct load-balancing per TCP connection. Once the TCP connection is established to the server-side, the packet from the client will always use that connection to F5 and landed in the same server all the time until the connection is closed. An example would be a VS with standard type and TCP protocol selected, that is TCP LB. It works well for HTTP because short-lived but it does not work well with long-lived connection such as SMPP or DIAMETER. That is the reason on message-based load balancing (MBLB).
02-Mar-2018 16:48
Hello Joko, Your suggestion on TCP load balancing worked!!!!!!!!!!!
I however added mblb profile on cli to the two initial F5 VIP'S. I have noticed something however, the smpp submit_sm works for so long, then after sometime, stops working.
If i however bypass, the 3rd F5 VIP (which has SMSC as pool member) and send submit_sm directly to SMSC, i don't get a timeout.
What do you think could be responsible?.
This is the irule on the 3rd VIP.
when CLIENT_ACCEPTED { set s_seq_idx 1 set first_bind_resp 1 set sms_m1 10.206.140.172%5 set sms_m2 10.206.140.173%5 TCP::collect } when CLIENT_DATA { while { [TCP::payload length] >= 16 } { binary scan [TCP::payload] IH8IIa* len oper status seq p if { [TCP::payload length] < $len } { TCP::collect $len return } switch -glob $oper { 00000002 - 00000009 { set bind_message [TCP::payload $len] } 00000004 { submit_sm set p [string range $p [expr [string first \x00 $p]+1] end] binary scan $p cca* ston snpi p set p [string range $p [expr [string first \x00 $p]+1] end] binary scan $p ccA* dton dnpi p set dest [getfield $p \x00 1] if { $dest starts_with 420 } { use pool or node command pool [LB::server pool] member $sms_m2 10000 } else { pool [LB::server pool] member $sms_m1 10000 } } 8* { rewrite seq if { [info exists s_seq_map($seq)] } { set old_seq [lindex $s_seq_map($seq) 0] TCP::payload replace 12 4 [binary format I $old_seq] set addr [lindex $s_seq_map($seq) 1] set port [lindex $s_seq_map($seq) 2] use pool or node command pool [LB::server pool] member $addr $port unset s_seq_map($seq) } } } TCP::release $len TCP::notify request } TCP::collect } when SERVER_CONNECTED { if { $first_bind_resp } { TCP::collect } else { TCP::collect -all TCP::respond $bind_message } } when SERVER_DATA { while { [TCP::payload length] >= 16 } { binary scan [TCP::payload] IH8II len oper status seq if { [TCP::payload length] < $len } { TCP::collect $len return } switch -glob $oper { 0* { rewrite seq TCP::payload replace 12 4 [binary format I $s_seq_idx] set s_seq_map($s_seq_idx) "$seq [IP::remote_addr] [TCP::remote_port]" incr s_seq_idx } 80000002 { bind response if { $first_bind_resp } { set first_bind_resp 0 } else { TCP::payload replace 0 [TCP::payload length] "" set len 0 } } } TCP::release $len TCP::notify response } TCP::collect }
20-Jun-2018 04:40
Hi
What does "TCP::collect -all" do?
I can't find the '-all' flag anywhere in documentation
31-Jul-2018 04:08
Hello etrust,
Maybe they are like...
Available qualifiers:
" + " Pass, an IP that matches a mechanism with this qualifier will pass.
" - " Fail, an IP that matches a mechanism with this qualifier will fail.
" ~ " SoftFail, an IP that matches a mechanism with this qualifier will soft fail.
" ? " Neutral, an IP that matches a mechanism with this qualifier will neither pass or fail.
But for sure, someone from the F5 team should confirm or deny this assumption.
23-Dec-2020 01:22
Need same load balancing but persist with mobile no. dont need specific mobile no. to go on single server.
Any help?
26-Jan-2021 06:10
Can I kindly have the original irule for the original question?