For feedback and comments:
documentation.feedback@alcatel-lucent.com

Table of Contents Previous Next PDF


Python Script Support for ESM
In This Chapter
This section describes the Python script support for Enhanced Subscriber Management (ESM).
The following topics are included:
Python Script Support for ESM
In order to provide programmable flexibility in ESM applications, the SR OS provides the following features with Python script support:
 
Python in SR-OS Overview
The SR-OS python script support is based on Python version 2.4.2. Python has a set of language features (such as functions, lists and dictionaries) and a very large set of packages which provide most of the Python functionality. By keeping the language features intact and drastically reducing the number of packages available, the operator is provided with a flexible, although small, scripting language.
The only feature removed from the Python language is unicode support. The only packages provided to the operator are:
alc — The SR OS-provided packages provide access to various ESM objects such as DHCPv4, DHCPv6 or RADIUS packets.
binascii — Common ASCII decoding like base64.
re — Regular expression support.
struct — Parses and manipulates binary strings.
md5 — MD5 message digest algorithm.
 
Python Changes
Some changes have been made to Python in order to run on an embedded system:
Python Support in sub-ident-policy
A Python script can be configured in sub-ident-policy to return following ESM attributes:
The system will run the Python script configured in the sub-ident-policy against the received DHCPv4 ACK message. This is used as the input of the script. Within the script, the user can set the value with the above ESM attributes.
The alc package contains a DHCP object, and has the following members (Table 21).
 
 
The TLV type provides easy access to the value part of a stream of type-length-value variables, as is the case for the DHCP option field. In the example on , the circuit-ID is accessed as alc.dhcp.options[82][1].
Some DHCP servers do not echo the relay agent option (option 82) when the DHCP message was snooped instead of relayed. For the convenience of the operator, the relay agent option from the request message is returned when alc.dhcp.options[82] is called.
 
Configuration
As an example consider script us5.py on which sets the sub_ident variable based on the circuit ID of three different DSLAMs:
import re 
import alc
import struct
# ASAM DSLAM circuit ID comes in three flavours:
#      FENT   string         "TLV1: ATM:3/0:100.33"
#      GELT   octet-stream   0x01010000A0A0A0A0000000640022
#      GENT   string         "ASAM11 atm 1/1/01:100.35"
#
# Script sets output ('subscriber') to 'sub-vpi.vci', e.g.: 'sub-100.33'. circuitid = str(alc.dhcp.options[82][1])
m = re.search(r'(\d+\.\d+)$', circuitid)
if m:
# FENT and GENT
alc.dhcp.sub_ident = "sub-" + m.group()
elif len(circuitid) >= 3:
# GELT
# Note: what byte order does GELT use for the VCI?
# Assume network byte (big endian) order for now. vpi = struct.unpack('B', circuitid[-3:-2])[0]
vci = struct.unpack('>H', circuitid[-2:])[0]
alc.dhcp.sub_ident = "sub-%d.%d" % (vpi, vci) 
 
Configure the url to this script in a sub-ident-policy as follows:
---------------------------------------------- 
	sub-ident-policy "DSLAM" create
		description "Parse circuit IDs from different DSLAMs" 
		primary
 
			script-url "ftp://xxx.xxx.xxx.xx/py/us5.py" 
			no shutdown
		exit
	exit
----------------------------------------------
 
And attach this sub-ident-policy to the sub-sla-mgmt from a SAP:
A:dut-A>config>service>vpls>sap# info
---------------------------------------------- 
	dhcp
		description "client side" 
		lease-populate 50
 
		no shutdown 
	exit
	anti-spoof ip-mac
	sub-sla-mgmt
		sub-ident-policy "DSLAM" 
		no shutdown
	exit
----------------------------------------------
 
Note that DHCP snooping/relaying should be configured properly in order for this to work.
 
Operator Debugging
Verbose debug output is sent to debug-trace on compile errors, execution errors, execution output and the exported result variables.
A:dut-A>config>subscr-mgmt>sub-ident-pol>primary# script-url "ftp://xxx.xxx.xx.xx/py/
parsefail1.py"
A:dut-A>config>subscr-mgmt>sub-ident-pol>primary# no shutdown
 
1 2006/07/30 01:17:33.14 UTC MINOR: DEBUG #2001 - Python Compile Error
"Python Compile Error: parsefail1.py
	File "ftp://xxx.xxx.xx.xx/py/parsefail1.py", line 2 def invalid_function():
		^
IndentationError: expected an indented block
"
 
A:dut-A>config>subscr-mgmt>sub-ident-pol>primary# script-url "ftp://xxx.xxx.xx.xx/py/
dump.py"
 
2 2006/07/30 01:24:55.50 UTC MINOR: DEBUG #2001 - Python Output
"Python Output: dump.py htype   = 0
hlen    = 0 hops    = 0 flags   = 0
ciaddr  = '0.0.0.0' yiaddr  = '0.0.0.0' siaddr  = '0.0.0.0' giaddr  = '0.0.0.0' chaddr  = ''
sname   = ''
file    = ''
options = '5\x01\x056\x04\n\x01\x07\n3\x04\x00\x00\x00\xb4\x01\x04\xff\xff\xff
\x00\x1c\x04\n\x02\x02\xffR\x0f\x01\rdut-A|1|1/1/1\xff' "
 
3 2006/07/30 01:24:55.50 UTC MINOR: DEBUG #2001 - Python Result
"Python Result: dump.py
"
 
A:dut-A>config>subscr-mgmt>sub-ident-pol>primary# script-url "ftp://xxx.xxx.xx.xx/py/end- less.py"
 
4 2006/07/30 01:30:17.27 UTC MINOR: DEBUG #2001 - Python Output
"Python Output: endless.py
"
 
5 2006/07/30 01:30:17.27 UTC MINOR: DEBUG #2001 - Python Error
"Python Error: endless.py
Traceback (most recent call last):
File "ftp://xxx.xxx.xx.xx/py/endless.py", line 2, in ? FatalError: script interrupted (timeout)
"
 
Note that all the Python Result events are empty because none of the scripts set any of the output variables.
 
 
 
Python Scripts
Note that the scripts in this section are test scripts and not scripts which the operator would normally use.
dump.py from alc import dhcp
def print_field(key, value):
print '%-8s = %r' % (key, value)
 
def ipaddr2a(ipaddr):
return '%d.%d.%d.%d' % (
(ipaddr & 0xFF000000) >> 24, (ipaddr & 0x00FF0000) >> 16, (ipaddr & 0x0000FF00) >> 8, (ipaddr & 0x000000FF))
 
print_field('htype',   dhcp.htype) print_field('hlen',    dhcp.hlen) print_field('hops',    dhcp.hops) print_field('flags',   dhcp.flags) print_field('ciaddr',  ipaddr2a(dhcp.ciaddr)) print_field('yiaddr',  ipaddr2a(dhcp.yiaddr)) print_field('siaddr',  ipaddr2a(dhcp.siaddr)) print_field('giaddr',  ipaddr2a(dhcp.giaddr)) print_field('chaddr',  dhcp.chaddr) print_field('sname',   dhcp.sname) print_field('file',    dhcp.file) print_field('options', str(dhcp.options))
 
us5.py — import re import alc import struct
 
# ASAM DSLAM circuit ID comes in three flavors:
#       FENT   string         "TLV1: ATM:3/0:100.33"
#       GELT   octet-stream   0x01010000A0A0A0A0000000640022
#       GENT   string         "ASAM11 atm 1/1/01:100.35"
#
# Script sets output ('subscriber') to 'sub-vpi.vci', e.g.: 'sub-100.33'. circuitid = str(alc.dhcp.options[82][1])
m = re.search(r'(\d+\.\d+)$', circuitid)
if m:
# FENT and GENT
alc.dhcp.sub_ident = "sub-" + m.group()
elif len(circuitid) >= 3:
# GELT
# Note: what byte order does GELT use for the VCI?
# Assume network byte (big endian) order for now. vpi = struct.unpack('B', circuitid[-3:-2])[0]
vci = struct.unpack('>H', circuitid[-2:])[0]
alc.dhcp.sub_ident = "sub-%d.%d" % (vpi, vci) 
 
Sample Python Scripts
This section provides examples to show how the script can be used in the context of Enhanced Subscriber Management.
Note that these scripts are included for informational purposes only. The operator must customize the script to match their own network and processes.
 
Example
This script uses the IP address assigned by the DHCP server to derive both sub_ident and sla_profile_string.
Script:
1.  import alc
2.  yiaddr = alc.dhcp.yiaddr
3.  # Subscriber ID equals full client IP address.
4.  # Note: IP address 10.10.10.10 yields 'sub-168430090'
5.  # and not 'sub-10.10.10.10'
6.  alc.dhcp.sub_ident = 'sub-' + str(yiaddr)
7.  # DHCP server is configured such that the third byte (field) of the IP
8.  # address indicates the session Profile ID.
9.  alc.dhcp.sla_profile_string = 'sp-' + str((yiaddr & 0x0000FF00) >> 8)
 
Explanation:
Line 1 — Imports the library “alc” – Library imports can reside anywhere in the script as long as the items are imported before they are used.
Line 2— Assigns the decimal value of the host’s IP address to a temporary variable “yiaddr”. Line 6: The text “sub_“ followed by yiaddr is assigned to “sub_ident” string.
Line 9— The text “sp-“ followed with the third byte of the IP address is assigned to the “sla- profile” string.
If this script is run, for example, with a DHCP-assigned IP address of:
yiaddr = 10.10.0.2
The following variables are returned:
sub_ident: sub-168427522(hex = A0A00002 = 10.10.0.2)
sla_ident: sp-0 
 
Example
This script returns the sub_profile_string and sla_profile_string, which are coded directly in the Option 82 string.
Script:
1.  import re
2.  import alc
3.  # option 82 formatted as follows:
4.  # "<subscriber Profile>-<sla-profile>”
5.  ident = str(alc.dhcp.options[82][1])
6.  alc.dhcp.sub_ident = ident
7.  tmp = re.match("(?P<sub>.+)-(?P<sla>.+)", str(ident))
8.  alc.dhcp.sub_profile_string = tmp.group("sub")
9.  alc.dhcp.sla_profile_string = tmp.group("sla")
 
Explanation:
Line 1-2 — Import the libraries “re” and “alc”. Library imports can reside anywhere in the script as long as the items are imported before they are used.
Line 6 — Assigns the full contents of the DHCP Option 82 field to the “sub_ident” variable.
Line 7 — Splits the options 82 string into two parts, separated by “-”.
Line 8 — Assigns the first part of the string to the variable “sub_profile_string”.
Line 9 — Assigns the second part of the string to the variable “sla_profile_string”.
If this script is run, for example, with DHCP option field:
options = \x52\x0D\x01\0x0Bmydsl-video
The following variables are returned:
sub_ident: mydsl-video 
sub_profile_string: mydsl 
sla_profile_string: video 
 
Example
This script parses the Option82 “circuit-id” info inserted in the DHCP packet by a DSLAM, and returns the sub_ident string.
Script:
1.  import re
2.  import alc
3.  import struct
4.  # Alcatel 7300 ASAM circuit ID comes in three flavors:
5.  #      FENT   string         "TLV1: ATM:3/0:100.33"
6.  #      GELT   octet-stream   0x01010000A0A0A0A0000000640022
7.  #      GENT   string         "ASAM11 atm 1/1/01:100.35"
8.  #
9.  # Script sets output ('subscriber') to 'sub-vpi.vci',
10. # e.g.: 'sub- 100.33'.
11. circuitid = str(alc.dhcp.options[82][1])
12. m = re.search(r'(\d+\.\d+)$', circuitid)
13. if m:
14.    # FENT and GENT
15.    alc.dhcp.sub_ident = "sub-" + m.group()
16. elif len(circuitid) >= 3:
17.    # GELT
18.    # Note: GELT uses network byte (big endian) order for the VCI
19.    vpi = struct.unpack('B', circuitid[-3:-2])[0]
20.    vci = struct.unpack('>H', circuitid[-2:])[0]
21.    alc.dhcp.sub_ident = "sub-%d.%d" % (vpi, vci)
 
Explanation:
Line 1-2 — Import the libraries “re” and “alc” – Library imports can reside anywhere in the script as long as the items are imported before they are used. Needed if regular expressions are used.
Line 3 — Imports the “struct” library, needed if regular expressions are used.
Line 11 — Assigns the contents of the DHCP Option 82 Circuit-ID field to a temporary variable called “circuitid”.
Line 12 — Parses the “circuitid” and checks for the existence of the regular expression “digit.digit” at the end of the string.
Line 15 — If found, a string containing the text “sub-” followed by these two digits is assigned to the variable “sub-ident”.
Line 16 — If not found, and the length of circuit-id is at least 3.
Line 19 — Parses the “circuitid” and assigns the third-last byte to the temporary variable “vpi”.
Line 20 — Parses the “circuitid” and assigns the last two bytes to the temporary variable “vci”.
Line 21 — Assigns a string containing the text “sub-” followed by vpi and vci to the variable “sub-ident”.
If this script is run, for example, with DHCP option field (assigned by an ASAM with FENT card) containing:
options = \x52\x16\x01\x14TLV1: ATM:3/0:100.33
(in decimal: 80, 22, 1, 20TLV…)
The following variables are returned:
sub_ident: sub-100.33
 
If the above script is run, for example, with a DHCP option field (assigned by an ASAM with GELT card) containing:
options = \x52\x10\x01\x0E\x01\x01\x00\x00\xA0\xA0\xA0\xA0\x00\x00\x00\x64 \x00\x22
 
(in decimal: 82, 16, 1, 15, 1, 1, 0, 0, 160, 160, 160, 160, 0, 0, 0, 100, 0, 34; corresponding to VPI 100, VCI 34)
Python returns the following variables:
sub_ident: sub-100.34
 
If the above script is run, for example, with a DHCP option field (assigned by an ASAM with GENT card) containing:
options = \x52\x1A\x01\x18ASAM11 atm 1/1/01:100.35
 
The following variables are returned:
sub_ident: sub-100.35 
 
Limitations
'%' operator — While %f is supported, %g and %e are not supported.
Floating Point Arithmetic — The floating point arithmetic precision on the box is less than the precision required by the regression suites of Python. For example, pow(2., 30) equals to
1024.*1024.*1024. until five numbers after the point instead of seven and sqrt(9) equals to 3. for the first seven numbers after the point.
Using the round operator fixes these problems. For example, round(pow(2., 30)) equals round(1024.*1024.*1024.) and round(sqrt(9)) equals 3.
RADIUS Script Policy Overview
Python scripts for RADIUS AAA packets support manipulation in subscriber management application. This feature is supported on 7750 SRs and 7450 ESSes in mixed mode. A Python script can be executed in following cases:
The input of the script is the corresponding original packet; and the output of packet will be used as the new corresponding packet for further ESM AAA process.
The radius-script-policy contains URLs of a primary and optionally a secondary Python script, which could be a local CF file path or a FTP URL. The configured radius-script-policy could be used in different ESM polices like authentication-policy or radius-accounting-policy.
The following operations are supported within the script:
Note that the following RADIUS attributes or VSA are read-only to Python script:
Since R12.0R1, users should use a Python policy (instead of a RADIUS script policy) for RADIUS packet manipulation.
 
Python RADIUS API
The following new Python objects, alc.radius, have the following methods:
alc.radius also provides methods to manipulate radius attributes via alc.radius.attributes, which has the following methods:
 
Sample Script
From alc import radius
#1. Get the value of an existing Attribute
Username=radius.attributes.get(1)
#2. Modify an existing attribute
radius.attributes.set(1, 'Tom')
#3. Remove an existing attribute
radius.attributes.clear(1)
#4. Add a new attribute
radius.attributes.set(126,”WIFI-operator”) 
Python Policy Overview
The Python policy represents a general framework to support all existing and new python features. A Python policy allows users to configure a Python script for specified ESM packet type (such as DHCP, RADIUS, etc.) in a specified direction (ingress/egress). The system will execute the configured script when sending or receiving the specified type of packet.
Within the script, the corresponding original packet will be used as input. The user can use the system-provided API to manipulate the input packet (such as add/change/remove option/attribute) and the changed packet is the output for further ESM processing. And in case of a DHCP transaction cache, the script could also return ESM attributes.
Python policies support following ESM packet types and application:
The following is an example configuration on a specified group interface. The system will execute cf1:/dhcpv4.py after received DHCPv4 discovery and before system forward DHCPv4 request packet.
config>python# info 
----------------------------------------------
        python-script "dhcpv4" create
            primary-url "cf1:/dhcpv4.py"
            no shutdown
        exit
        python-policy "dhcp" create
            dhcp discover direction ingress script "dhcpv4"
            dhcp request direction egress script "dhcpv4"
        exit
---------------------------------------------
config>service>vprn>sub-if>grp-if>dhcp# info 
----------------------------------------------
                        python-policy "dhcp"
                        server 9.9.9.9 
                        lease-populate 100
                        gi-address 192.168.100.1
                        no shutdown
----------------------------------------------
 
Python Policy – RADIUS API
The RADIUS API in Python policy uses the same API of the radius-script-policy.
 
Python Policy – DHCPv4 API
 
 
All attributes, except alc.dhcpv4.pkt_len and alc.dhcpv4.pkt_netlen, are string with value of the actual bytes in the header.
The following is a list all functions of alc.dhcpv4:
DHCPv4 allows using sname and file fields to store options. However all DHCPv4 functions will only operate with the “options” field. If a customer wants to manipulate options in the sname/file field, they need to do the parsing work in the script. (extended string.tlvxy method could help here)
All alc.dhcpv4.get_XXX() will return a data structure:“D4OL” (DHCPv4 Option List)
All alc.dhcpv4.set_XX(OPDL) will accept D4OL as the parameter. Remove all existing instances of the corresponding options and then insert the new options represented by specified D4OL.
 
 
 
 
Examples:
For a packet with an option82 like following
	Option: (82) Agent Information Option
		Length: 22
		Option (82) Suboption: (1) Agent Circuit ID
			Length: 8
			Agent Circuit ID: 4a616e737656e73
		Option 82 Suboption: (2) Agent Remote ID
			Length: 10
			Agent Remote ID 62617369632364617461
 
The option-data is (hex formatted) “01:08:4a:61:6e:73:73:65:6e:73:02:0a:62:61:73:69:63:23:64:61:74:61”
The following is an example script:
import alc
 
option82_list=alc.dhcpv4.get_relayagent()
#option82_list will be [{1:['\x4a\x61\x6e:73\x73\x65\x6e\x73',],2:['\x62\x61\x73\x69\x63\x23\x64\x61\x74\x61',]},]
Option82_list[0][2][0]='basic#video' #change remote-id to 'basic#video'
alc.dhcpv4.set_relayagent(option82_list)#update the option82
 
Python Policy – DHCPv6 API
 
 
All header fields (as the attribute of alc.dhcpv6 class) are strings(except pkt_len ) with exact bytes as it appears in the packet.
If certain attribute does not exist in the given msg-type, for example if the link_attr does not exist in client/server message(C/S msg), then its value should be None.
Examples:
All alc.dhcpv6.get_XXX() will return a data structure:“OPDL” (Option Data structure List)
Else, if the sub-option is not one of above, then the value to the key is a list of string of sub-option-data, each string represent one instance of the sub-option.
All alc.dhcpv6.set_XX(OPDL) will accept an OPDL as the parameter. Remove all existing instances of the corresponding options and then insert new options represented by the specified OPDL.
 
Examples:
For a packet with an IANA option like following:
The option-data is (hex formatted)
“0f:f0:de:f1:00:02:a3:00:00:04:38:00:00:05:00:18:20:01:05:58:60:45:00:47:45:cc:d9:f2:57:27:ea:e0:00:05:46:00:00:05:46:00”
The following is an example script:
import alc
 
iana_list=alc.dhcpv6.get_iana()
#iana_list will be [['\x0f\xf0\xde\xf1','\x00\x02\xa3\x00','\x00\x04\\x38\x00',{5:[['\x20\x01\x05\x58\x60\x45\x00\x47\x45\xcc\xd9\xf2\x57\x27\xea\xe0','\x00\x05\x46\x00','\x00\x05\x46\x00',{}]]}]]
iana_list[0][1]='\x00\x00\x04\xb0' #change T1 to 1200
alc.dhcpv6.set_iana(iana_list)#update the iana
 
Examples: These two function are very similar with IANA, so the examples are skipped here.
Examples: For a packet with IA_PD like following:
The option-data is (hex formatted)
“00:00:00:01:00:00:07:08:00:00:0b:40:00:1a:00:19:00:00:0e:10:00:01:51:80:38:20:01:0d:b8:00:02:00:00:00:00:00:00:00:00:00:00”
 
Following is an example script:
 
import alc
 
iapd_list=alc.dhcpv6.get_iapd()
#iapd_list will be [['\x00\x00\x00\x01','\x00\x00\x07\x08','\x00\x00\x0b\x40',{26:[['\x00\x00\x0e\x10','\x00\x01\x51\x80','\x38', '\x20\x01\x0d\xb8\x00\x02\x00\x 00\x00\x00\x00\x00\x00\x00\x00\x00',{}]]}]]
iapd_list[0][1]='\x00\x00\x04\xb0' #change T1 to 1200
alc.dhcpv6.set_iapd(iapd_list)#update the iapd
 
 
Examples: For a packet with vendor options like following:
The option-data is (hex formatted)
“00:00:19:7f:00:01:00:09:69:61:2d:6e:61:5f:30:30:31:00:02:00:09:69:61:2d:70:64:5f:30:30:31:00:03:00:01:38:00:04:00:01:40”
The following is an example script:
import alc
 
vendoropts_list=alc.dhcpv6.get_vendoropts()
# vendoropts_list will be [['\x00\x00\x19\x7f', {1:['\x69\x61\x2d\x6e\x61\x5f\x30\x30\x31'],2:[ '\x69\x61\x2d\x70\x64\x5f\x30\x30\x31'],3:['\x38'], 4:['\x40']}]]
iapd_list[0][1][4][0]='\x60' #change sub-option 4’s value to 0x60
alc.dhcpv6.set_vendoropts(vendoropts_list)#update the vendor options
 
To provide direct access to embedded DHCPv6 packet, the system provides following functions:
import alc
#input packet is a relay-reply msg
embed_dhcpv6_packet=alc.dhcpv6.get_relaymsg()
iana_list=embed_dhcpv6_packet.get_iana()
iana_list[0][1]='\x00\x00\x04\xb0' #change T1 to 1200
embed_dhcpv6_packet.set_iana(iana_list)#update the iana of the embedded packet
alc.dhcpv6.set_relaymsg(embed_dhcpv6_packet)#update the Relay Message option
 
import alc
#input packet is a relay-reply msg
embed_lv1_packet=alc.dhcpv6.get_relaymsg() #get the level=1 embedded packet
embed_lv2_packet= embed_lv1_packet.get_relaymsg()#get level-2 packet embedded in level-1 packet
iana_list=embed_dhcpv6_packet.get_iana()
iana_list[0][1]='\x00\x00\x04\xb0' #change T1 to 1200
embed_dhcpv6_packet.set_iana(iana_list)#update the iana
embed_lv1_packet.set_relaymsg(embed_lv2_packet)#update the Relay Message option of lv1 msg
alc.dhcpv6.set_relaymsg(embed_lv1_packet)#update the Relay Message option of the top level msg
 
Python Policy – Diameter API
The alc.diameter Python module provides an API for Diameter message manipulation.
Terminology used in the API description:
top-level-AVP — AVP appearing at the top level in a Diameter message, i.e. not embedded in the Data field of a grouped AVP
embedded-AVP — AVP embedded in the Data field of a grouped AVP. An embedded AVP can be a grouped AVP. This is called nesting.
AVP-tuple — Python tuple with following values:
(AVP code, vendor id, flags)
AVP code : integer, AVP header field
vendor id : integer, AVP header field
flags : string, AVP header field
AVP-value-tuple — Python tuple with following values:
(flags, data)
flags: string, AVP header field
data: string, AVP data field
AVP-key-tuple — Python tuple with following values:
(AVP code, vendor id)
AVP code: integer, AVP header field
vendor id : integer, AVP header field
grouped-AVP-value-tuple — Python tuple with following values:
(flags, grouped-AVP-dictionary)
flags: string, AVP header field
grouped-AVP-dictionary - Python dictionary with following key:value pairs:
{AVP-key-tuple : [AVP-value-tuple or grouped-AVP-value-tuple, …], ... }
key = AVP-key-tuple
value = list of AVP-value-tuples or list of grouped-AVP-value-tuples
grouped-AVP-decode-tuple — Python tuple with following values:
(AVP-key-tuple, …)
tuple of AVP-key-tuples
AVP-order-tuple — Python tuple with following values:
(AVP-key-tuple, …)
tuple of AVP-key-tuples
 
Table 24 displays attributes available in alc.diameter module providing access to the Diameter message header:
 
 
Table 25 displays methods available in alc.diameter module providing message and AVP manipulation functionality:
 
 
 
 
To enable Diameter message manipulation using Python, a python-policy must be configured in the diameter-peer-policy. For example:
configure
    aaa
        diameter-peer-policy "diameter-peer-policy-1" create
            description "Diameter peer policy"
            applications gy
            origin-host "bng.alcatel-lucent.com"
            origin-realm "alcatel-lucent.com"
            python-policy "py-policy-diam-1"
            source-address 192.0.2.5
            peer "peer-1" create
                address 172.16.1.1
                destination-host "server.alcatel-lucent.com"
                destination-realm "alcatel-lucent.com"
                no shutdown
            exit
        exit
    exit
 
The python-policy specifies the python-script to use for each Diameter message type received or transmitted on a Diameter peer. In the ingress direction, the Python script is executed when the corresponding packet type is received on the Diameter peer but prior to further processing in the system. In the egress direction, the Python script is executed prior to sending the corresponding packet type on the Diameter peer. For example:
configure
    python
        python-policy "py-policy-diam-1" create
            description "Python policy"
            diameter ccr direction egress script "diameter-1"
            diameter cca direction ingress script "diameter-2"
        exit
    exit
 
The python-script specifies the location of the script and optional protection mechanism. For example:
configure
    python
        python-script "diameter-1" create
            primary-url "ftp://usr:pwd@192.0.2.1/./py/diam-1.py"
            no shutdown
        exit
    exit
 
As an example, the diam-1.py script, clears the M-bit from the Event-Timestamp AVP (code 55):
	from alc import diameter
	avp55=diameter.get_avps(55,0)
	diameter.set_avps(55,0,[('\x00',avp55[0][1])])
 
 
Python Policy – DHCP Transaction Cache API
A DHCP transaction cache (DTC) is a short-lived cache during DHCPv4/v6 transaction. The cache could be used to store user-chosen information or return ESM attributes via a Python script. The DTC’s lifetime is only during a single DHCP transaction (for example, only between discovery-offer, request-reply). This includes both alc.dtc.store() data and alc.dtc.setESM() data. DTC is also a transaction specific cache, which means the cached information could only be accessed by the Python script running in same DHCP transaction.
The following are the DTC APIs:
 
Python Cache Support
Python cache support allows information to be shared across different run times of the same python script or even different python scripts in a programmatic way. It essentially provides a central memory cache and a set of APIs which let the user store and retrieve strings. For example, a DHCP python-script could store a DHCP option into cache and later a RADIUS python-script could retrieve stored string and add it into access-request.
Each cached entry in the cache is a tuple of (key, val). key is used as entry id. val is the string to be cached. Both key and val are strings. The max length of the key is 512 bytes. Future more, the combine length of key+val is limited by the configured value of entry-size size command in the python-policy.
The Python cache can be enabled per python-policy. Each python policy has its own cache memory which script in other python-policy cannot access. This also implies that the key of a cached entry in different a python policy could overlap.
The user can also specify the max number cache entry per python policy the command max-entries command. System has a global limit for python cache memory of 256MB.
The cached entries could be made persistent by saving it to CF card. This can be enabled with the persistence command in the python policy.
Note: From memory consumption point of view, with MCS enabled, each cached entry will have a corresponding MCS record, so each entry will consume twice amount of memory.
The system also supports syncing the python cache across chassis with MCS. This can be configured per python policy with the mcs-peer command in the python policy.
Each cached entry has a remaining lifetime. If it decreases over time, the system will remove the cached entry if its remaining lifetime is 0. The remaining lifetime can be changed using a system- provided API. The initial lifetime of a newly created cache entry is 600 seconds.
The following are the python cache APIs in a module alc.cache:
 
Applying a Python Policy
The following is a list of places that a Python policy could be applied:
 
Python Script Protection
In order to protect the Python script from unintended changes, the SR-OS supports a new Python script file format:SRPY. Since 12.0R1, SRPY includes a key based hash(HMAC) of the original script content. When the system loads a script with SRPY format, a hash will be computed by using a configured key and script content. The result hash will be compared to the embedded hash. If it is the same, then this script is considered valid. Otherwise, the system will abort with a warning message.
Users can configure protection hmac-sha256 key <key> within a Python script. To mandate, all configured scripts must be in SRPY format.
The system provides a tool command (tool perform python-script protect) to convert a Python script into SRPY format.
 
Tips and Tricks
 
# This script takes 2.5 seconds. s = ""
for c in 'A'*50000:
s += str(ord(c)) + ', ' print '[' + s[:-2] + ']'
 
# This script takes 0.1 seconds. print map(ord, 'A'*50000)