Configure F5 SIP-ALG
From Genesys Documentation
This topic is part of the manual Setting up Genesys Multicloud CX Private Edition for version Current of Genesys Multicloud CX Private Edition.
Contents
Learn how to configure F5 SIP-ALG as the final step in SBC integration with the private edition deployment on OpenShift.
Related documentation:
RSS:
Create SNATs and pools
- Create the Source Network Address Translations (SNATs).
create ltm snat-translation /f5-voice-sipproxy/10.30.3.2 address 10.30.3.2 traffic-group /Common/traffic-group-1
create ltm snat-translation /f5-voice-sipproxy/10.10.2.11 address 10.30.3.2 traffic-group /Common/traffic-group-1
- When traffic is source network address translated to the cluster via the VXLAN tunnel or to the SBCs, translations are used. VXLAN tunnel host subnets provide the source NAT IP addresses used in Network Address Translation to the cluster.
- Add the SNATs to a SNAT pool.
create ltm snatpool f5-voice-sipproxy/snat-towards-sip-servers members add { 10.30.3.2 10.10.2.11 }
- The SNAT pool is used when traffic is source network address translated to the OpenShift Cluster within the tunnel and also the SBCs on the external side. The F5 selects the appropriate SNAT translation when sending it out to the VXLAN/external VLAN.
Sip-media handler iRules
- Create the two iRules required to handle SIP and media:
- media-handler
#irule: media-handler when CLIENT_ACCEPTED { #log local0.debug "In Client Accepted" if { ![info exists read_table_flow_info] } { if { [set target_node_and_snat [table lookup sdp-l-[IP::remote_addr]-[UDP::remote_port]-[IP::local_addr]-[UDP::local_port]]] eq "" } { log local0.debug "Received udp flow for undefined definition ([IP::remote_addr]:[UDP::remote_port]<->[IP::local_addr]:[UDP::local_port])" reject return } set read_table_flow_info yes set snat_ip [getfield $target_node_and_snat "-" 1] set snat_port [getfield $target_node_and_snat "-" 2] set node_ip [getfield $target_node_and_snat "-" 3] set node_port [getfield $target_node_and_snat "-" 4] log local0.debug "Allowing udp flow for ([IP::remote_addr]:[UDP::remote_port]<->[IP::local_addr]:[UDP::local_port]) using node ($node_ip:$node_port) and snat ($snat_ip:$snat_port)" node $node_ip $node_port snat $snat_ip $snat_port } } }
- sip-sdp-handler
#irule: sip-sdp-handler when RULE_INIT { set static::sip_sdp_handler_emit_debug_logs yes set static::sip_sdp_handler_flow_holddown_timeout 10 } proc log_debug {msg} { if { $static::sip_sdp_handler_emit_debug_logs } { if { [clientside] } { set side clientside } else { set side serverside } log local0.debug "($side [IP::remote_addr]:[TCP::remote_port]<->[IP::local_addr]:[TCP::local_port]) $msg" } } proc set_sdp_connection_field_for_ip {ip_address} { if { $ip_address contains ":" } { call log_debug " - setting c= to IN IP6 \[$ip_address\]" SDP::field c 0 "IN IP6 \[$ip_address\]" } else { call log_debug " - setting c= to IN IP4 $ip_address" SDP::field c 0 "IN IP4 $ip_address" } } # call create_media_listener_table_entry when_src_is 10.1.10.10-3000 and_dest_is 10.1.10.100-40000 then_snat_is 10.1.20.100-40000 and_node_is 10.1.20.20-5000 # # The literals when_src_is, and_dest_is, then_snat_is and and_node_is are syntactic sugar. The args must be in the order # provided above. Note the use of a dash (-) rather than colon (:) for ip/port separator. This facilitates easy use of IPv6. # This creates the table entry: # $src-$dest -> $snat-$node proc create_media_listener_table_entry {l1 src l2 dest l3 snat l4 node} { call log_debug " - adding table entry with key (sdp-l-$src-$dest) and value ($snat-$node)" table set "sdp-l-$src-$dest" "$snat-$node" $static::sip_sdp_handler_flow_holddown_timeout indef } when CLIENT_ACCEPTED { set reverse_flow_id "" } when SERVER_CONNECTED { set reverse_flow_id "" } when MR_INGRESS { if { [clientside] } { call log_debug " - storing message lasthop on clientside" set reverse_flow_id [MR::message lasthop] MR::store reverse_flow_id } else { if { $reverse_flow_id ne "" } { MR::message nexthop $reverse_flow_id call log_debug " - using stored reverse flow id = ($reverse_flow_id)" } else { log local0.warn "No reverse flow id, dropping message" MR::message drop "no reverse flow id" } } } when MR_EGRESS { if { [serverside] } { MR::restore reverse_flow_id call log_debug " - restoring flow_id = ($reverse_flow_id)" } } when SIP_REQUEST_SEND { if { [SIP::method] ne "INVITE" or [SIP::call_id] eq "" } { return } call log_debug "SIP::method = ([SIP::method]); Call-ID = ([SIP::call_id])" set clientside_media_ip [getfield [SDP::field connection_address] " " 3] call log_debug " - found ([SDP::media count]) media entries in SDP; connection_address = ($clientside_media_ip); conn info = ([SDP::field connection_address])" # Strictly speaking, this isn't correct, as there may be more than one c=, but customer indicated # that there will only ever be one (and only one m= declaration, though we can be more pedantic for that). call set_sdp_connection_field_for_ip [IP::local_addr] # 64512 == 65535 - 1024 + 1. Reserve port after incr plus one more (for RTCP). However, because the # table entry cannot be set in RULE_INIT (table is not allowed in RULE_INIT) and we must use # 'table incr', the first port returned will be 1026, not 1024. if { [set vs_listen_port [expr { [table incr sdp-xlat-port-incr 2] % 64512 + 1024 }]] == 1026 } { call log_debug "Setting timeout and lifetime for table (sdp-xlat-port-incr) to indef" table timeout sdp-xlat-port-incr indef table lifetime sdp-xlat-port-incr indef } elseif { $vs_listen_port == 5060 } { # SIP OPTIONS requests are made by the server to the same address as we're using for snat, so we need to skip that port # We don't simply set this to 5062 statically and increment the table because, while 'table incr' is atomic, # the work between the previous 'table incr' and this one is not. set listen_port [expr { [table incr sdp-xlat-port-incr 2] % 64512 + 1024 }] } call log_debug " - Ports reserved for media are ($vs_listen_port) and ([expr { $vs_listen_port + 1 }])" for { set i 0 } { $i < [SDP::media count] } { incr i } { set clientside_media_type [SDP::media type $i] set clientside_media_port [SDP::media port $i] call log_debug " - found media type ($clientside_media_type) handled by ($clientside_media_ip:$clientside_media_port)" set sdp_m_table_key "sdp-m-[SIP::call_id]-$clientside_media_type" set sdp_m_table_value "$clientside_media_ip,$clientside_media_port,[IP::local_addr],$vs_listen_port" call log_debug " - setting table entry ($sdp_m_table_key) to ($sdp_m_table_value)" table set $sdp_m_table_key $sdp_m_table_value $static::sip_sdp_handler_flow_holddown_timeout indef call log_debug " - setting SDP m= port to ($vs_listen_port)" SDP::media port $i $vs_listen_port } } when SIP_RESPONSE_SEND { set in_response_to [lindex [split [SIP::header CSeq] " "] 1] if { ([SIP::response code] ne 200 and [SIP::response code] ne 183) or $in_response_to ne "INVITE" or [SIP::call_id] eq "" } { log local0.warn "SIP message escaped due to resp-code not being 200 or 183" return } call log_debug "SIP::code = ([SIP::response code]); in_response_to = ($in_response_to); Call-ID = ([SIP::call_id])" set serverside_node_media_ip [getfield [SDP::field connection_address] " " 3] call log_debug " - found ([SDP::media count]) media entries in SDP; connection_address = ($serverside_node_media_ip)" call set_sdp_connection_field_for_ip [IP::local_addr] for { set i 0 } { $i < [SDP::media count] } { incr i } { set serverside_media_type [SDP::media type $i] if { [set media_information_from_invite_message [table lookup "sdp-m-[SIP::call_id]-$serverside_media_type"]] eq "" } { log local0.warn "Missing media information from INVITE for Call-ID ([SIP::call_id]) of media type ($serverside_media_type). The INVITE OK may have taken too long." # Set SDP::media port anyway. The port is below the minimum provided and there is no flow session table # information, so if the remote end tries to create a UDP flow to this port, it'll trigger an ICMP Unreachable. SDP::media port $i 1023 continue } set serverside_media_port [SDP::media port $i] set clientside_node_media_ip [getfield $media_information_from_invite_message , 1] set clientside_node_media_port [getfield $media_information_from_invite_message , 2] set clientside_vs_ip [IP::local_addr] set serverside_vs_ip [getfield $media_information_from_invite_message , 3] set vs_listen_port [getfield $media_information_from_invite_message , 4] set vs_rtcp_listen_port [expr { $vs_listen_port + 1 }] set clientside_node_rtcp_port [expr { $clientside_node_media_port + 1}] set serverside_node_rtcp_port [expr { $serverside_media_port + 1}] call log_debug " - found media type ($serverside_media_type) handled by ($serverside_node_media_ip:$serverside_media_port)" call log_debug " - matching media type entry from INVITE handled by ($clientside_node_media_ip:$clientside_node_media_port)" call log_debug " - client ($clientside_node_media_ip:$clientside_node_media_port) to listener ($clientside_vs_ip:$vs_listen_port) uses snat ($serverside_vs_ip:$vs_listen_port) to send to node ($serverside_node_media_ip:$serverside_media_port)" call create_media_listener_table_entry when_src_is "$clientside_node_media_ip-$clientside_node_media_port" and_dest_is "$clientside_vs_ip-$vs_listen_port" \ then_snat_is "$serverside_vs_ip-$vs_listen_port" and_node_is "$serverside_node_media_ip-$serverside_media_port" call create_media_listener_table_entry when_src_is "$clientside_node_media_ip-$clientside_node_rtcp_port" and_dest_is "$clientside_vs_ip-$vs_rtcp_listen_port" \ then_snat_is "$serverside_vs_ip-$vs_rtcp_listen_port" and_node_is "$serverside_node_media_ip-$serverside_node_rtcp_port" call log_debug " - client ($serverside_node_media_ip:$serverside_media_port) to listener ($serverside_vs_ip:$vs_listen_port) uses snat ($clientside_vs_ip:$vs_listen_port) to send to node ($clientside_node_media_ip:$clientside_node_media_port)" call create_media_listener_table_entry when_src_is "$serverside_node_media_ip-$serverside_media_port" and_dest_is "$serverside_vs_ip-$vs_listen_port" \ then_snat_is "$clientside_vs_ip-$vs_listen_port" and_node_is "$clientside_node_media_ip-$clientside_node_media_port" call create_media_listener_table_entry when_src_is "$serverside_node_media_ip-$serverside_node_rtcp_port" and_dest_is "$serverside_vs_ip-$vs_rtcp_listen_port" \ then_snat_is "$clientside_vs_ip-$vs_rtcp_listen_port" and_node_is "$clientside_node_media_ip-$clientside_node_rtcp_port" call log_debug " - setting SDP media port to ($vs_listen_port)" SDP::media port $i $vs_listen_port } } }
- Create the SBC pool.
create ltm pool /f5-voice-sipproxy/sbc-pool { members add { <nodeName>:5080 { address <address> }
- Create the SIP Proxy pool.
create ltm pool /f5-voice-sipproxy/sipproxy-pool { members add { <nodeName>:5080 { address <address> }
Create message routing components
- Create the message-routing SIP profile.
create ltm message-routing sip profile session sipsession-sdp-rewrite { app-service none defaults-from /Common/sipsession insert-record-route-header enabled record-route-mode double }
- Create the message-routing transport configuration.
create ltm message-routing sip transport-config /f5-voice-sipproxy/tc-sdp-rewrite1 { profiles add { sipsession-sdp-rewrite { } /Common/f5-tcp-progressive { } } rules { /f5-voice-sipproxy/sip-sdp-handler } source-address-translation { pool snat-towards-sip-servers type snat } source-port 5080
- Create the message-routing SIP peers.
create ltm message-routing sip peer /f5-voice-sipproxy/peer-sbc pool sbc-pool transport-config /f5-voice-sipproxy/tc-sdp-rewrite
create ltm message-routing sip peer /f5-voice-sipproxy/peer-sip-servers pool sipproxy-pool transport-config /f5-voice-sipproxy/tc-sdp-rewrite
- Create the message-routing SIP profile router.
create ltm message-routing sip profile router /f5-voice-sipproxy/router-sdp-rewrite {app-service none defaults-from /Common/siprouter traffic-group /Common/traffic-group-1 }
- You need to first create the message-routing routes referencing the virtual servers. Later, add these routes back into the SIP profile router.
Create virtual servers
A SIP server and media virtual server is required in either direction:
- Externally facing the SBCs for an inbound call
- Internally facing the sip-proxy for outbound calls
sbc-facing-sip
ltm virtual vs-facing-sbc-sip {
destination 10.10.2.11:5080
ip-protocol tcp
mask 255.255.255.255
partition f5-voice-sipproxy
profiles {
/Common/f5-tcp-progressive { }
router-sdp-rewrite { }
sipsession-sdp-rewrite { }
}
rules {
sip-sdp-handler
}
serverssl-use-sni disabled
source 0.0.0.0/0
translate-address enabled
translate-port enabled
vlans {
/Common/external
}
vlans-enabled
sbc-facing-media (vs-media-sbc-facing)
ltm virtual vs-media-sbc-facing {
destination 10.10.2.11:any
ip-protocol udp
mask 255.255.255.255
partition f5-voice-sipproxy
profiles {
/Common/udp { }
}
rules {
media-handler
}
serverssl-use-sni disabled
source 0.0.0.0/0
translate-address enabled
translate-port enabled
vlans {
/Common/external
}
vlans-enabled
sipservers-facing-sip (vs-facing-sip-servers)
ltm virtual vs-facing-sip-servers {
destination 10.30.3.5:5080
ip-protocol tcp
mask 255.255.255.255
partition f5-voice-sipproxy
profiles {
/Common/f5-tcp-progressive { }
router-sdp-rewrite { }
sipsession-sdp-rewrite { }
}
rules {
sip-sdp-handler
}
serverssl-use-sni disabled
source 0.0.0.0/0
translate-address enabled
translate-port enabled
vlans {
/Common/openshift_vxlan
}
vlans-enabled
sipservers-facing-media (vs-facing-sip-servers)
ltm virtual vs-media-servers-facing {
destination 10.30.3.5:any
ip-protocol udp
mask 255.255.255.255
partition f5-voice-sipproxy
profiles {
/Common/udp { }
}
rules {
media-handler
}
serverssl-use-sni disabled
source 0.0.0.0/0
translate-address enabled
translate-port enabled
vlans {
/Common/openshift_vxlan
}
vlans-enabled
- Create the message-routing SIP routes.
create ltm message-routing sip route /f5-voice-sipproxy/route-to-sbcs peers { /f5-voice-sipproxy/peer-sbc } virtual-server /f5-voice-sipproxy/vs-facing-sbc-sip
create ltm message-routing sip route /f5-voice-sipproxy/route-to-sip-servers peers { /f5-voice-sipproxy/peer-sip-servers } virtual-server /f5-voice-sipproxy/vs-facing-sip-servers
- Add the SIP routes to the message-routing SIP profile router.
modify ltm message-routing sip profile router /f5-voice-sipproxy/router-sdp-rewrite { routes add { /f5-voice-sipproxy/route-to-sbcs /f5-voice-sipproxy/route-to-sip-servers } }
Comments or questions about this documentation? Contact us for support!