/*! \file rx_pkt_example.rb
*/
#!/mnt/fastpath/usr/bin/ruby
require 'OpEN'
require 'OpENUtil'
require 'ipaddr'
require 'socket'
include Socket::Constants
#
# Copyright 2016 Broadcom.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
# Ruby 1.8.7.
#
DESTINATION_MAC = 'Destination MAC'
SOURCE_MAC = 'Source MAC'
VLAN_ID = 'VLAN ID'
VLAN_PRIORITY = 'VLAN Priority'
ETHER_TYPE = 'Ether Type'
DESTINATION_IP = 'Destination IPv4'
DESTINATION_IP_MASK = 'Destination Mask'
SOURCE_IP = 'Source IPv4'
SOURCE_IP_MASK = 'Source IPv4 Mask'
DESTINATION_IPV6 = 'Destination IPV6'
DESTINATION_IPV6_MASK = 'Destination IPV6 Mask'
SOURCE_IPV6 = 'Source IPV6'
SOURCE_IPV6_MASK = 'Source IPV6 Mask'
DONE = 'Done'
$open = OpENUtil.new()
def print_sanity_results(result, test, msg, feat)
#Print overall comparison results
if result == OpEN::OPEN_E_UNAVAIL
puts "Sanity test skipped."
elsif result == OpEN::OPEN_E_NONE and test == true
puts "Sanity Success - #{msg} - #{feat}."
else
puts "Sanity Failure - #{msg} - #{feat}."
end
end
def print_bad_result(result, msg)
#Print some general error messages if the result is bad
if result == OpEN::OPEN_E_UNAVAIL
puts "Feature not supported - #{msg} (err #{result})."
elsif result != OpEN::OPEN_E_NONE
puts "Test Failure - #{msg} (err #{result})."
end
end
def get_mac_address(prompt)
#Get a MAC address from the user and return it as an unsigned char
while true
begin
print prompt
mac = STDIN.gets.chomp
macstr = mac.gsub(":","")
if (macstr !~ /^[0-9A-F]+$/i) or (macstr.length != 12)
puts "Invalid MAC address."
else
macstr = [macstr].pack("H*")
return $open.getUCharBuffer(macstr.length, macstr)
end
rescue Exception => e
puts "Invalid MAC address. %s" % e
end
end
end
def get_ipv4_address(prompt)
#get an IP address from user and return it as int
while true
begin
print prompt
return IPAddr.new(STDIN.gets.chomp).to_i
rescue Exception => e
puts "Invalid IPv4 address. %s " % e
end
end
end
def get_ipv6_address(prompt)
#get an IP address from user and return it as open_inet_addr_t
addr = OpEN::Open_inet_addr_t.new
while true
begin
print prompt
addr.addr.ipv6 = IPAddr.new(STDIN.gets.chomp).to_i
addr.family = socket.AF_INET6
return addr
rescue Exception => e
puts "Invalid IPv6 address. %s " % e
end
end
end
def receive_packets(agent_num, pkt_cnt, log_file)
#Create a socket end-point to receive frames
#Display packets received, else write to log_file if defined.
log = log_file ? true : false
# Make sure agent isn't already registered
OpEN.openapiExtAgentPktUnregister(agent_num)
# Register new agent
agent_name = "Test Agent"
agent_string = $open.getCharBuffer(agent_name.length,agent_name)
agent_buff = OpEN::Open_buffdesc.new
agent_buff.pstart = agent_string
agent_buff.size = agent_name.length
result = OpEN.openapiExtAgentPktRegister(agent_num, agent_buff, OpEN::OPEN_TCAM_EXT_AGENT_PKT_RECEIVE)
print_sanity_results(result, true, "openapiExtAgentPktRegister", "Register External Agent: (%s)" % agent_name)
if result != OpEN::OPEN_E_NONE
return
end
# Socket file name is based on agent id
fn = "/tmp/rx.%05d" % agent_num
# Remove previous socket file (must not exist)
File.delete(fn) if File.exist?(fn)
s = Socket.new(Socket::AF_UNIX, Socket::SOCK_DGRAM, 0)
s.bind(Socket.pack_sockaddr_un(fn))
puts "Receiving Packets..."
if log
f = open(log_file, "w")
end
pkt_tp = OpEN.new_open_sysExtAgentPktRxDesc_tp()
idx = 0
while (idx < pkt_cnt)
data = s.recv(OpEN::OPEN_TXRX_MAX_FRAME_SIZE + 64)
OpEN.buf_to_open_sysExtAgentPktRxDesc_t(data, pkt_tp)
pkt = OpEN.open_sysExtAgentPktRxDesc_tp_value(pkt_tp)
if log
f.write("\nPacket received from ifNum %d, pktLen %d" % [pkt.rxIfNum, pkt.pktLength])
f.write("\nPacket content:")
else
puts "Packet %d Version:%d Received from ifNum %d, pktLen %d" % [idx, pkt.version, pkt.rxIfNum, pkt.pktLength]
puts "Packet content:"
end
for i in 0..pkt.pktLength-1
octet = data[pkt.descLen+i,1].unpack("H*")
if log; f.write("%s " % octet)
else; print octet, " "
end
end
if log; f.write("\n")
else; puts
end
idx += 1
end
OpEN.openapiExtAgentPktUnregister(agent_num)
OpEN.delete_open_sysExtAgentPktRxDesc_tp(pkt_tp)
s.close()
if log
f.close()
end
end
class Policy
#TCAM API policy
def initialize(client)
@client = client
@open_policy = OpEN::Open_tcamApiPolicy_t.new
@initialized = false
@handle = nil
end
def finalize()
if @handle
OpEN.delete_OPEN_TCAM_API_POLICYID_tp(@handle)
end
end
def initialize_tcam
#Initialize API and get/store the API versioning in the header
result = OpEN.openapiTcamApiInit(@client)
if result == OpEN::OPEN_E_NONE
version = OpEN::Open_tcam_version_t.new
result = OpEN.openapiTcamApiVersionGet(@client, version)
if result == OpEN::OPEN_E_NONE
@open_policy.policyHeader.versionInfo.versionMajor = version.versionMajor
@open_policy.policyHeader.versionInfo.versionMinor = version.versionMinor
@open_policy.policyHeader.headerLen =
[@open_policy.policyHeader.versionInfo.versionMajor.to_i].pack("i").size +
[@open_policy.policyHeader.versionInfo.versionMinor.to_i].pack("i").size +
[@open_policy.policyHeader.headerLen.to_i].pack("i").size
@initialized = true
end
end
end
def match_dst_mac
#Prompt user for destination mac address and save it
@open_policy.matchDstMac = get_mac_address(DESTINATION_MAC + " (xx:xx:xx:xx:xx:xx) : ")
end
def match_src_mac
#Prompt the user for source mac address and save it
@open_policy.matchSrcMac = get_mac_address(SOURCE_MAC + " (xx:xx:xx:xx:xx:xx) : ")
end
def match_vlan
#Prompt user for vlan and save it
while true
begin
print VLAN_ID + " : "
@open_policy.matchVlanVal = Integer(STDIN.gets.chomp)
break
rescue Exception => e
puts e
puts "Invalid VLAN."
end
end
end
def match_vlan_priority
#Prompt user for vlan priority and save it
while true
begin
print VLAN_PRIORITY + " : "
@open_policy.matchVlanPrio = Integer(STDIN.gets.chomp)
break
rescue Exception => e
puts e
puts "Invalid VLAN priority."
end
end
end
def match_ether_type
#Prompt user for ether type and save it
while true
begin
print ETHER_TYPE + " (xx) : "
@open_policy.matchEthType = [STDIN.gets.chomp].pack("H*").to_i
break
rescue Exception => e
puts e
puts "Invalid Ether type."
end
end
end
def match_dst_ipv4
#Prompt user for IP and save it
@open_policy.matchDstIp = get_ipv4_address(DESTINATION_IP + " : ")
@open_policy.matchDstIpMask = get_ipv4_address(DESTINATION_IP_MASK + " : ")
end
def match_src_ipv4
#Prompt user for IP and save it
@open_policy.matchSrcIp = get_ipv4_address(SOURCE_IP + " : ")
@open_policy.matchSrcIpMask = get_ipv4_address(SOURCE_IP_MASK + " : ")
end
def match_dst_ipv6
#Prompt user for IP and save it
@open_policy.matchDstIpv6Addr = get_ipv6_address(DESTINATION_IPV6 + " : ")
@open_policy.matchDstIpv6Mask = get_ipv6_address(DESTINATION_IPV6_MASK + " : ")
end
def match_src_ipv6
#Prompt user for IP and save it
@open_policy.matchSrcIpv6Mask = get_ipv6_address(SOURCE_IPV6 + " : ")
@open_policy.matchSrcIpv6Mask = get_ipv6_address(SOURCE_IPV6_MASK + " : ")
end
def get_priority_and_type
#Prompt user for policy priority and type and save it
while true
begin
print "Enter policy priority : "
@open_policy.policyPrio = Integer(STDIN.gets.chomp)
break
rescue
puts "Invalid priority, priority must be numeric."
end
end
while true
begin
print "Enter policy type (1:OpenFlow 2:Gen IPv6 3:Egress) : "
policy_type = Integer(STDIN.gets.chomp)
if policy_type == 1
@open_policy.policyType = OpEN::OPEN_TCAM_POLICY_TYPE_OPENFLOW
break
elsif policy_type == 2
@open_policy.policyType = OpEN::OPEN_TCAM_POLICY_TYPE_GEN
break
elsif policy_type == 3
@open_policy.policyType = OpEN::OPEN_TCAM_POLICY_TYPE_EGRESS
break
else
puts "Invalid type."
end
rescue
puts "Invalid type, type must be numeric."
end
end
end
def get_classifiers
#Prompt the user for policy classifiers and save them.
#The input loops until the user is done
while true
begin
puts "Enter classification types"
puts "--------------------------"
print "1: Match ", DESTINATION_MAC; puts
print "2: Match ", SOURCE_MAC; puts
print "3: Match ", VLAN_ID; puts
print "4: Match ", VLAN_PRIORITY; puts
print "5: Match ", ETHER_TYPE; puts
print "6: Match ", DESTINATION_IP; puts
print "7: Match ", SOURCE_IP; puts
print "8: Match ", DESTINATION_IPV6; puts
print "9: Match ", SOURCE_IPV6; puts
print "10:", DONE; puts
print "Enter selection : "
type = STDIN.gets.chomp
puts type
case Integer(type)
when 1; match_dst_mac
when 2; match_src_mac
when 3; match_vlan
when 4; match_vlan_priority
when 5; match_ether_type
when 6; match_dst_ipv4
when 7; match_src_ipv4
when 8; match_dst_ipv6
when 9; match_src_ipv6
when 10; break
end
rescue
end
end
end
def get_actions(agent_num)
#The policy action is hard-coded in this example
@open_policy.actionType |= OpEN::OPEN_TCAM_ACTION_REDIRECT_CPU
@open_policy.ruleNum = agent_num
end
def create
#Create the actual policy on the device
handle_tp = OpEN.new_OPEN_TCAM_API_POLICYID_tp()
result = OpEN.openapiTcamPolicyCreate(@client, @open_policy, handle_tp)
if result == OpEN::OPEN_E_NONE
puts
puts "Policy successfully added."
@handle = handle_tp
else
puts
puts "Error: Policy could not be created"
end
end
def get_interface
#Prompt for interface and add it to the policy
intf_tp = OpEN.new_uint32_tp()
while true
begin
print "Enter interface name (slot/port) : "
interface = STDIN.gets.chomp
name_str = $open.getCharBuffer(interface.length, interface)
name_buff = OpEN::Open_buffdesc.new
name_buff.pstart = name_str
name_buff.size = interface.length+1
result = OpEN.openapiIfNumGet(@client, name_buff, intf_tp)
print_bad_result(result, "get interface")
if result == OpEN::OPEN_E_NONE
intf = OpEN.uint32_tp_value(intf_tp)
result = OpEN.openapiTcamPolicyIntfAdd(@client, @handle, intf)
print_bad_result(result, "add interface")
break
end
rescue
puts "Invalid Interface."
end
end
OpEN.delete_uint32_tp(intf_tp)
end
end
class RxPktExample
#Packet transmission
def initialize(client)
@client = client
end
def test_rx_pkt(agent_num, pkt_cnt, log_file)
#Instantiate and create a policy and assign it to an interface.
#Establish a server socket to accept packets from the agent.
policy = Policy.new(@client)
policy.initialize_tcam()
policy.get_priority_and_type()
policy.get_classifiers()
policy.get_actions(agent_num)
policy.create()
policy.get_interface()
receive_packets(agent_num, pkt_cnt, log_file)
policy.finalize()
end
end
def main()
#Demonstrate OpEN usage for Packet API
# logfile is optional
if ARGV.length < 2 or ARGV.length > 3
puts "rx_pkt_example.py <agentnum> <packetcount> [logfile]"
exit
end
begin
agent_num = Integer(ARGV[0])
rescue
puts "Invalid agent number, <agentnum> must be numeric."
exit
end
begin
packet_count = Integer(ARGV[1])
rescue
puts "Invalid packet count, <packetcount> must be numeric."
exit
end
begin
log_file = ARGV[2]
# if log file entered, create newly initialized log file
# while validating the filename.
fp = open(log_file, "w")
fp.close()
rescue
log_file = nil
end
ret = $open.connect("rx_pkt_example")
if ret == OpEN::OPEN_E_NONE
$open.getNetworkOSVersion()
client = $open.client
example = RxPktExample.new(client)
example.test_rx_pkt(agent_num, packet_count, log_file)
$open.terminate()
else
print "Unable to connect"
end
end
if __FILE__ == $0 then main() end