Hello,
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
Hi Pavel,
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?
Hi,
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.
Hi Pavel,
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
Hi Nat,
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
Hi Pavel,
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
ummm… i think this line
while { [TCP::payload length] > 16 } {
should be
while { [TCP::payload length] >= 16 } {
Hi Nat,
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
Hi Pavel,
Thanks for update.
Glad to hear that it works.
Looking forward to hear more test result.
Nat
Hi Nat,
iRule works fine, tested also for asynchronous SMPP transfer and for more clients.
Once again thank you.
Pavel
Hi Pavel,
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
Hi Nat,
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
Hi Nat,
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
Hi Kiran,
Sorry for late reply.
I think in your case. you can use this method
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
Hi Kiran,
Sorry for late reply.
I think in your case. you can use this method
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
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
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
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//
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