Modifying DSCP value with onePK

In addition to playing around with OpenFlow, I’ve started working with Cisco onePK as well.  You can get to the SDK here:  http://developer.cisco.com/web/onepk/home

One of the services provided is the Data Path Service Set (DPSS), which lets you intercept and modify packets as they go through the router.  Currently this is only available in the C SDK, so I had to dust off my pointer skills and dive into some C.  I thought an interesting exercise would be to take packets and change their DSCP value, so I wrote the following based on the tutorials and examples to change outgoing packets to have a DSCP of 12.  I’ll break down the code into chunks, or if you’d like you can just go to my github site and look at the whole thing:
https://github.com/fredhsu/myonepk-c/tree/master/myfirstapp
First off we after adding the libraries we define some global variables:

static network_interface_t *intf = NULL;
static ace_t* ace;
static acl_t* acl;
static target_t* targ = NULL;
static class_t * acl_class = NULL;
static filter_t * acl_filter = NULL;
static interface_filter_t* intf_filter = NULL;
static onep_collection_t* intfs = NULL;
static unsigned int count = 0;
static network_element_t* ne1 = NULL;
static onep_status_t rc;
static onep_if_name name;
static onep_dpss_handle_t *dpss_handle;
static onep_dpss_packet_loop_t *pak_loop;
static onep_dpss_traffic_reg_t *reg_handle;
static session_config_t *config;
static network_application_t* myapp = NULL;
struct sockaddr_in v4addr;

Some variables to take note of are the ACL, the Network Element, and the DPSS handle and packet loop. These will all become more clear as we move down the code. The variable rc, is used throughout for checking the return code of functions to ensure things went ok. I only did some spotty checks for this example, which generally takes the form of checking if rc == ONEPK_OK

The next part of the code is a callback function that will modify the packets when packets are sent to the agent from the router.

void dpss_tutorial_pak_injector (
onep_dpss_traffic_reg_t *reg,
onep_dpss_paktype_t *pak,
void *client_context,
bool *return_pak)

First I extract a dpss handle, target, and target interface from the *reg variable that was passed when the callback was called:

rc = onep_dpss_traffic_reg_get_dpss_handle (reg, &dpss);
rc = onep_dpss_traffic_reg_get_target(reg, &targ);
rc = onep_policy_get_target_interface(targ, &intf);

Now just as a check, I print out the interface name that I’m listening for packets on:

onep_if_name name;
rc = onep_interface_get_name(intf,name);
printf("Packet arrived on interface [%s]\n",name);

Now I’m going to modify the packet’s DSCP value. I will do so by modifying the bits in the 2nd octet to be a 48, which will set the bits for DSCP to be 12, and the remaning bit. For a refresher, you can look at the IP Packet header here:

http://en.wikipedia.org/wiki/IPv4#Header

First I create a pointer to an array of bytes that I will copy into the packet.

uint8_t newdscp[1] = {48};

Then I modify the packet, with an offset of 1, modifying 1 byte, of the layer 3 header, and inserting the bytes from the array we just created:

rc = onep_dpss_modify_packet(pak,
ONEP_DPSS_LAYER_3,
1,
1,
newdscp,
1
);

Then there is some error checking and we return from the function. Note that I am making use of the default behavior of return_pak = true to return the packet to the router. You can explicitly do this by setting return_pak = false and then telling the agent to return the packet manually as well.

Now I go into the main() function.  The first 20 or so lines are just getting a session established and a connection to the network element I’m using.  Then I create an interface filter and go through the interfaces on the router to find the one we want. The last line below selects the second interface which in my case is the one I have connected to a laptop with a sniffer:

onep_interface_filter_new(&intf_filter);
rc = onep_element_get_interface_list(ne1, intf_filter, &intfs);
rc = onep_collection_get_size(intfs, &count);
if (count <= 0 ) {
fprintf(stderr, "\nNo interfaces available");
return ONEP_FAIL;
}
onep_collection_get_by_index(intfs, 2, (void *)&intf);

Now I create an ACL and class to define what traffic will be “interesting” and handled by the agent:

onep_acl_create_l3_acl(AF_INET, ne1, &acl);
onep_acl_create_l3_ace(1, TRUE, &ace); // seq#, permit, ace obj
onep_acl_set_l3_ace_protocol(ace, ONEP_PROTOCOL_ALL);
onep_acl_set_l3_ace_src_prefix(ace, NULL, 24);
onep_acl_set_l3_ace_dst_prefix(ace, NULL, 24);
onep_acl_add_ace(acl, ace);
onep_policy_create_class(ne1, ONEP_CLASS_OPER_OR, &acl_class);
onep_policy_create_acl_filter(acl, &acl_filter);
onep_policy_add_class_filter(acl_class, acl_filter);

Then we create a DPSS packet loop to receive the packets:

onep_dpss_packet_loop_start(1, &pak_loop);
onep_dpss_initialize(&dpss_handle, "dpss_tutorial", ne1);
onep_dpss_packet_loop_register_dpss_handle(pak_loop, dpss_handle);

Now I create a policy interface target to set the interface we’re getting packets from. Also note here that we’ve set that it will handle packets that are leaving the interface (I got stuck here for a bit):

onep_policy_create_interface_target(intf, ONEP_TARGET_LOCATION_HARDWARE_DEFINED_OUTPUT, &targ);

Finally I register for the packets:

onep_dpss_register_for_packets(dpss_handle,
targ,
acl_class,
ONEP_DPSS_ACTION_PUNT,
dpss_tutorial_pak_injector,
0,
&reg_handle);

You’ll see here we provide the DPSS handle we created earlier, the target policy that defines the interface and direction, and the callback function we defined earlier. Also I’ve specified ONEP_DPSS_ACTION_PUNT which tells the router to punt the packets to the agent. With this action set, the router will not forward the packet on, but will take the returned packet from our callback. Another option here is to do a copy where the packet will go on, but a copy will be sent to the agent.

Now all that’s left is to setup the router, run the program, and test it out.  On the router we have to configure onePK and the DPSS service set from the global config mode:

onep
datapath transport gre interface GigabitEthernet0/0
transport socket
start

You’ll see that DPSS will create a GRE tunnel between the router and the agent via the interface specified. Now to run the application, first we have to start dpss_mp to receive the packets. First edit the dpss.conf file located at:

/opt/cisco/onep/c64/sdk-c64-0.7.0.503g/c/bin/dpss.conf

And modify it to your host’s IP address. Then you can run dpss_mp, I’ve done so with the following command:

sudo LD_LIBRARY_PATH=/opt/cisco/onep/c64/sdk-c64-0.7.0.503g/c/lib/ /opt/cisco/onep/c64/sdk-c64-0.7.0.503g/c/bin/dpss_mp_64-0.7.0.503

Finally make and run the program. While the program is running, I went to the router and initiated a telnet to my laptop that was connected and running wireshark. When I look at the traces:
Capture
Success!

Advertisements

4 thoughts on “Modifying DSCP value with onePK

  1. Jan Fijalkowski says:

    router-1#show onep status
    Status: disabled
    Version: 0.7.0
    Transport: socket; Status: disabled
    Transport: tls; Status: disabled
    Transport: tipc; Status: disabled
    router-1#configure terminal
    Enter configuration commands, one per line. End with CNTL/Z.
    router-1(config)#onep
    router-1(config-onep)#datapath transport gre interface vlan 1
    Configuration can’t be changed while a ONE-P session is active

    😦
    cannot make it working, even afetr erase nvram: and reload
    cheers

      • Jan Fijalkowski says:

        CISCO1941W-E/K9 chassis
        C1900 Software (C1900-UNIVERSALK9-M), Version 15.3(2)T

        more interesting:
        router-1(config-onep)#no datapath transport gre interface GigabitEthernet 0/0
        ends with system crash 😦

        *** System received a Bus Error exception ***

        cheers
        fijal

  2. Trying to make with the 32bit version of onePK and get the followig errors:

    myfirstapp.c:44:1: error unknown type name ‘onep_dpss_handle_t’
    myfirstapp.c:45:1: error unknown type name ‘onep_dpss_packet_loop_t’

    Where are these types defined?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s