13.06.2015 Views

Intel IXA SDK ACE Programming Framework - Department of ...

Intel IXA SDK ACE Programming Framework - Department of ...

Intel IXA SDK ACE Programming Framework - Department of ...

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Intel</strong> ® <strong>IXA</strong> <strong>SDK</strong> <strong>ACE</strong> <strong>Programming</strong><br />

<strong>Framework</strong><br />

<strong>IXA</strong> <strong>SDK</strong> 2.0 Developer’s Guide<br />

August 2001<br />

Document Number: A71582-001


Revision History<br />

Revision Date Revision Description<br />

August 2001 3.3 <strong>SDK</strong> 2.0 release.<br />

Information in this document is provided in connection with <strong>Intel</strong> ® products. No license, express or implied, by estoppel or otherwise, to any intellectual<br />

property rights is granted by this document. Except as provided in <strong>Intel</strong>’s Terms and Conditions <strong>of</strong> Sale for such products, <strong>Intel</strong> assumes no liability<br />

whatsoever, and <strong>Intel</strong> disclaims any express or implied warranty, relating to sale and/or use <strong>of</strong> <strong>Intel</strong> products including liability or warranties relating to<br />

fitness for a particular purpose, merchantability, or infringement <strong>of</strong> any patent, copyright or other intellectual property right. <strong>Intel</strong> products are not<br />

intended for use in medical, life saving, or life sustaining applications.<br />

<strong>Intel</strong> may make changes to specifications and product descriptions at any time, without notice.<br />

Designers must not rely on the absence or characteristics <strong>of</strong> any features or instructions marked “reserved” or “undefined.” <strong>Intel</strong> reserves these for<br />

future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them.<br />

The product may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current<br />

characterized errata are available on request.<br />

<strong>Intel</strong> Corporation might have patents or pending patent applications covering subject matter in this document. The furnishing <strong>of</strong> this document does not<br />

give any license to these patents.<br />

This document as well as the s<strong>of</strong>tware and hardware described in it are furnished under license and may only be used or copied in accordance with<br />

the terms <strong>of</strong> the license. The information in this document is furnished for informational use only, is subject to change without notice, and should not be<br />

construed as a commitment by <strong>Intel</strong> Corporation. <strong>Intel</strong> Corporation assumes no responsibility or liability for any errors or inaccuracies that may appear<br />

in this document or any s<strong>of</strong>tware that may be provided in association with this document. Except as permitted by such license, no part <strong>of</strong> this document<br />

may be reproduced, stored in a retrieval system, or transmitted in any form or by any means without the express written consent <strong>of</strong> <strong>Intel</strong> Corporation.<br />

Contact your local <strong>Intel</strong> sales <strong>of</strong>fice or your distributor to obtain the latest specifications and before placing your product order.<br />

Copies <strong>of</strong> documents which have an ordering number and are referenced in this document, or other <strong>Intel</strong> literature may be obtained by calling<br />

1-800-548-4725 or by visiting <strong>Intel</strong>’s website at http://www.intel.com<br />

Copyright © <strong>Intel</strong> Corporation, 2001. All rights reserved.<br />

*Other names and brands may be claimed as the property <strong>of</strong> others.<br />

This product includes s<strong>of</strong>tware developed by parties other than <strong>Intel</strong>. See the back page <strong>of</strong> this document for a list <strong>of</strong> copyrights and license<br />

agreements.


Contents<br />

About This Guide. . . . . . . . . . . . . . . . . . . . . . . . . . ix<br />

Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix<br />

In This Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix<br />

Other Sources <strong>of</strong> Information . . . . . . . . . . . . . . . . . . . . . . . xi<br />

Typographic Conventions . . . . . . . . . . . . . . . . . . . . . . . . xi<br />

Installation Path . . . . . . . . . . . . . . . . . . . . . . . . . . . xii<br />

Syntax Example . . . . . . . . . . . . . . . . . . . . . . . . . . . xii<br />

Contacting <strong>Intel</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii<br />

Web and Internet Sites . . . . . . . . . . . . . . . . . . . . . . . . xii<br />

Customer Support Technicians . . . . . . . . . . . . . . . . . . . . xiii<br />

Chapter 1 Introduction and Overview . . . . . . . . . . . . . . . . . . . . 1<br />

Network Service Applications . . . . . . . . . . . . . . . . . . . . . . . 1<br />

Packet Classification . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

The <strong>IXA</strong> Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

Logical Elements <strong>of</strong> an <strong>IXA</strong> Application . . . . . . . . . . . . . . . . . . . 3<br />

The Data Plane . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

The Control Plane . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

The Management Plane . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

Dividing Tasks Among Code Modules . . . . . . . . . . . . . . . . . . 5<br />

The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling. . . . . . . . . . . . 5<br />

Packet Processing and <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . 5<br />

Writing <strong>ACE</strong>s using C, NCL and <strong>IXA</strong> IDL. . . . . . . . . . . . . . . . . 6<br />

Predefined <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

Accelerated <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

Dividing Tasks Among <strong>ACE</strong> Types . . . . . . . . . . . . . . . . . . . 8<br />

Using Stack <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

OMS for Global Application Services . . . . . . . . . . . . . . . . . . . 10<br />

Creating <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

Defining the Traffic Flow Path with Targets . . . . . . . . . . . . . . . 11<br />

Contents<br />

iii<br />

Revision 3.3, August 2001


Communication Among <strong>ACE</strong>s. . . . . . . . . . . . . . . . . . . . . 12<br />

Micro<strong>ACE</strong> Resource Manager . . . . . . . . . . . . . . . . . . . . . 13<br />

Hardware Architecture: The IXP1200 Network Processor . . . . . . . . . . 14<br />

S<strong>of</strong>tware Configuration . . . . . . . . . . . . . . . . . . . . . . . . 14<br />

Hardware Configuration . . . . . . . . . . . . . . . . . . . . . . . 15<br />

Deploying Applications. . . . . . . . . . . . . . . . . . . . . . . . 17<br />

Components <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> for the IXP1200 . . . . . . . . . . . . . . . . 17<br />

Chapter 2 Elements <strong>of</strong> an Application . . . . . . . . . . . . . . . . . . . . 19<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

The Object Management System . . . . . . . . . . . . . . . . . . . . . 20<br />

Parts <strong>of</strong> the OMS. . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

Accessing the OMS. . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

Naming Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

For More Information . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

<strong>ACE</strong>s and Support Structures. . . . . . . . . . . . . . . . . . . . . . . 22<br />

Creating <strong>ACE</strong>s. . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

Support Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

Additional Services . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

Supporting Languages . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

Micro<strong>ACE</strong> Support Services . . . . . . . . . . . . . . . . . . . . . . . 24<br />

The Application Building Process . . . . . . . . . . . . . . . . . . . . . 25<br />

Chapter 3 Compiling and Testing Applications . . . . . . . . . . . . . . . 29<br />

Overview <strong>of</strong> the <strong>ACE</strong> Compilation and Linking Process . . . . . . . . . . . 29<br />

Intermediate Compilation . . . . . . . . . . . . . . . . . . . . . . . 29<br />

Compiling and Linking Source Files . . . . . . . . . . . . . . . . . . 30<br />

Compiling Kernel <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . 31<br />

Compiling Micro<strong>ACE</strong>s. . . . . . . . . . . . . . . . . . . . . . . . . . 32<br />

Using Makefiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33<br />

Debugging an Application . . . . . . . . . . . . . . . . . . . . . . . . 33<br />

Chapter 4 Configuring and Starting <strong>IXA</strong> Systems . . . . . . . . . . . . . . 35<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35<br />

For Additional Information . . . . . . . . . . . . . . . . . . . . . . 36<br />

Using Startup Scripts and Configuration Files . . . . . . . . . . . . . . . 36<br />

Starting and Initializing Interface <strong>ACE</strong>s . . . . . . . . . . . . . . . . . 37<br />

Microengine Threads . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

The System Configuration File . . . . . . . . . . . . . . . . . . . . . . 37<br />

Configuring Network Interfaces . . . . . . . . . . . . . . . . . . . . 38<br />

Identifying Microcode Images . . . . . . . . . . . . . . . . . . . . . 38<br />

Starting and Configuring Aces . . . . . . . . . . . . . . . . . . . . . 38<br />

Setting Up Particular Configurations . . . . . . . . . . . . . . . . . . . 39<br />

Configuring an L2 Bridge . . . . . . . . . . . . . . . . . . . . . . . 40<br />

System Configuration File . . . . . . . . . . . . . . . . . . . . . 40<br />

iv<br />

Contents<br />

Revision 3.3, August 2001


L2 Bridging Configuration File . . . . . . . . . . . . . . . . . . . 41<br />

Configuring an L3 Forwarder . . . . . . . . . . . . . . . . . . . . . 42<br />

System Configuration File . . . . . . . . . . . . . . . . . . . . . 42<br />

L3 Forwarder Configuration File . . . . . . . . . . . . . . . . . . 43<br />

Configuring an L3 Forwarder with NAT . . . . . . . . . . . . . . . . 44<br />

System Configuration File . . . . . . . . . . . . . . . . . . . . . 44<br />

NAT Configuration File . . . . . . . . . . . . . . . . . . . . . . 45<br />

Launching Application <strong>ACE</strong>s. . . . . . . . . . . . . . . . . . . . . . . 46<br />

Chapter 5 Controlling Packet Flow . . . . . . . . . . . . . . . . . . . . . . 47<br />

Defining Packet Flow . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

Physical Packet Flow . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

Logical Packet Flow . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

Binding Targets as Packet Destinations . . . . . . . . . . . . . . . . . . 48<br />

Binding Targets and <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . 49<br />

Unbound Targets . . . . . . . . . . . . . . . . . . . . . . . . . . 50<br />

Defining Additional Targets . . . . . . . . . . . . . . . . . . . . . . . 50<br />

Directing Packets to a Target . . . . . . . . . . . . . . . . . . . . . . . 51<br />

Using Targets for Packet Processing . . . . . . . . . . . . . . . . . . . . 51<br />

Serial Packet Flow . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

Packet Flow Redirection . . . . . . . . . . . . . . . . . . . . . . . 52<br />

Receiving and Transmitting on Network Interface Ports . . . . . . . . . . . 53<br />

See Also . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />

Chapter 6 Writing Micro<strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

Micro<strong>ACE</strong> Architectural Elements . . . . . . . . . . . . . . . . . . . . 56<br />

Architecture Summary . . . . . . . . . . . . . . . . . . . . . . . . 57<br />

Loading Micro<strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

Setting Up a Processing Pipeline for Micro<strong>ACE</strong>s . . . . . . . . . . . . . 59<br />

Creating Static Bindings . . . . . . . . . . . . . . . . . . . . . . 60<br />

Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong> . . . . . . . . . . . . . . . . 61<br />

Exception Packet Handling . . . . . . . . . . . . . . . . . . . . . . 62<br />

Initializing a Micro<strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . . 62<br />

Initialization Example . . . . . . . . . . . . . . . . . . . . . . . 63<br />

Terminating a Micro<strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . . 64<br />

Termination Example . . . . . . . . . . . . . . . . . . . . . . . 64<br />

Writing an Exception Packet Handler. . . . . . . . . . . . . . . . . . 64<br />

Exception Packet Handler Example . . . . . . . . . . . . . . . . . 65<br />

Allocating Memory for Shared Data . . . . . . . . . . . . . . . . . . 65<br />

Shared Memory Table Example . . . . . . . . . . . . . . . . . . . . 66<br />

Microcode Side: Hash Initialization and Table Implementation . . . . . 66<br />

Core Processor Side: Core Component Hashing. . . . . . . . . . . . 67<br />

Configuring Micro<strong>ACE</strong>s with Crosscalls . . . . . . . . . . . . . . . . . . 68<br />

Microblock Types and Groups . . . . . . . . . . . . . . . . . . . . . . 68<br />

Microblock Types . . . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

Contents<br />

v<br />

Revision 3.3, August 2001


Source Microblocks . . . . . . . . . . . . . . . . . . . . . . . . 69<br />

Transform Microblocks . . . . . . . . . . . . . . . . . . . . . . 70<br />

Sink Microblocks . . . . . . . . . . . . . . . . . . . . . . . . . 70<br />

Examples <strong>of</strong> Microblocks . . . . . . . . . . . . . . . . . . . . . . . 70<br />

Writing a Dispatch Loop . . . . . . . . . . . . . . . . . . . . . . . . . 71<br />

Dispatch Loop Global Registers . . . . . . . . . . . . . . . . . . . . 72<br />

Defining Additional Global Registers . . . . . . . . . . . . . . . . 73<br />

Implementing Control Flow . . . . . . . . . . . . . . . . . . . . . . 73<br />

Dispatch Loop Example. . . . . . . . . . . . . . . . . . . . . . . . 73<br />

Writing a Microblock . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

Returning Values to the Dispatch Loop . . . . . . . . . . . . . . . . . 75<br />

Transmitting a Packet . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

Sending an Exception. . . . . . . . . . . . . . . . . . . . . . . . . 76<br />

Micro<strong>ACE</strong> Design Example . . . . . . . . . . . . . . . . . . . . . . . 77<br />

Chapter 7 Interface <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

Interface <strong>ACE</strong> Crosscalls . . . . . . . . . . . . . . . . . . . . . . . 80<br />

Source Code Location . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

Initializing Interface <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . 81<br />

Creating a Microcode Image with an Interface <strong>ACE</strong> Microblock . . . . . . 81<br />

Starting, Naming, and Binding Interface <strong>ACE</strong>s . . . . . . . . . . . . . . 82<br />

The Input <strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83<br />

Configuring Interface <strong>ACE</strong>s Using Crosscalls . . . . . . . . . . . . . . 83<br />

Responding to Input <strong>ACE</strong> Configuration Crosscalls . . . . . . . . . . . 84<br />

Managing Physical Ports . . . . . . . . . . . . . . . . . . . . . . . 84<br />

Managing Logical Port Configuration. . . . . . . . . . . . . . . . . . 85<br />

The Output <strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85<br />

Sample Output Configurations . . . . . . . . . . . . . . . . . . . . 86<br />

Chapter 8 Stack and Library <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . 87<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87<br />

The Stack <strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88<br />

Starting and Configuring the Stack <strong>ACE</strong> . . . . . . . . . . . . . . . . 88<br />

The L3 Forwarder Library <strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . 89<br />

Starting the Forwarder <strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . 90<br />

Binding the Targets . . . . . . . . . . . . . . . . . . . . . . . . . 90<br />

Configuring the Forwarder . . . . . . . . . . . . . . . . . . . . . . 90<br />

The L2 Bridging Library <strong>ACE</strong>. . . . . . . . . . . . . . . . . . . . . . . 91<br />

Packet Processing . . . . . . . . . . . . . . . . . . . . . . . . . . 92<br />

Starting the L2 Bridger . . . . . . . . . . . . . . . . . . . . . . . . 93<br />

Configuring the L2 Bridger . . . . . . . . . . . . . . . . . . . . . . 94<br />

The NAT Library <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

Packet Processing . . . . . . . . . . . . . . . . . . . . . . . . . . 94<br />

Special Handling. . . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />

FTP Packet Handling . . . . . . . . . . . . . . . . . . . . . . . 95<br />

TCP Fragment Handling . . . . . . . . . . . . . . . . . . . . . . 96<br />

vi<br />

Contents<br />

Revision 3.3, August 2001


ICMP Error Packet Handling . . . . . . . . . . . . . . . . . . . . 96<br />

Starting the NAT <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . . . . 96<br />

Binding the Targets . . . . . . . . . . . . . . . . . . . . . . . . . 97<br />

Configuring the NAT library <strong>ACE</strong>s. . . . . . . . . . . . . . . . . . . 98<br />

Chapter 9 Classifying Packets Using NCL . . . . . . . . . . . . . . . . . . 99<br />

How <strong>ACE</strong>s Handle Packets . . . . . . . . . . . . . . . . . . . . . . . 99<br />

What’s in the NCL Rules File . . . . . . . . . . . . . . . . . . . . . . 100<br />

Classification Elements . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

Sets and Searches . . . . . . . . . . . . . . . . . . . . . . . . . . 100<br />

Defining Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101<br />

Defining Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . 102<br />

How Rules Are Evaluated . . . . . . . . . . . . . . . . . . . . . . . . 103<br />

What Rules Do . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104<br />

Chapter 10 Initializing and Acting on Packets in an <strong>ACE</strong> . . . . . . . . . 105<br />

<strong>ACE</strong> Code Overview . . . . . . . . . . . . . . . . . . . . . . . . . . 105<br />

Initializing the <strong>ACE</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

Defining ASL Objects. . . . . . . . . . . . . . . . . . . . . . . . . 106<br />

Defining the Initialization Function . . . . . . . . . . . . . . . . . . 107<br />

Defining Action and Utility Functions . . . . . . . . . . . . . . . . . . . 108<br />

Defining Action Functions . . . . . . . . . . . . . . . . . . . . . . 108<br />

Action Function Return Values . . . . . . . . . . . . . . . . . . . 108<br />

Predefined Default Action Function . . . . . . . . . . . . . . . . . 109<br />

For More Information . . . . . . . . . . . . . . . . . . . . . . . 109<br />

Defining Callbacks . . . . . . . . . . . . . . . . . . . . . . . . . . 109<br />

Defining Utility Functions . . . . . . . . . . . . . . . . . . . . . . 109<br />

What Action Functions Do . . . . . . . . . . . . . . . . . . . . . . . . 110<br />

Chapter 11 Communication Within an Application . . . . . . . . . . . . . 113<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113<br />

Defining Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . 114<br />

Making and Receiving Remote Calls . . . . . . . . . . . . . . . . . . 114<br />

When to Use Crosscalls . . . . . . . . . . . . . . . . . . . . . . . . 115<br />

Defining Crosscall Interfaces . . . . . . . . . . . . . . . . . . . . . . . 116<br />

Generated Files . . . . . . . . . . . . . . . . . . . . . . . . . . . 116<br />

Organizing Call Operations . . . . . . . . . . . . . . . . . . . . . . 117<br />

Defining Call Operations . . . . . . . . . . . . . . . . . . . . . . . . 118<br />

Operation Names . . . . . . . . . . . . . . . . . . . . . . . . . . 119<br />

Invocation Types for Operations . . . . . . . . . . . . . . . . . . . . . 120<br />

One-way Operations . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

Two-way Operations . . . . . . . . . . . . . . . . . . . . . . . . . 120<br />

Deferred Operations . . . . . . . . . . . . . . . . . . . . . . . . . 121<br />

Handling Asynchronous Responses with a Callback Function . . . . . 121<br />

Specifying Timeouts . . . . . . . . . . . . . . . . . . . . . . . . . 122<br />

Declaring Argument Directions . . . . . . . . . . . . . . . . . . . . 122<br />

Contents<br />

vii<br />

Revision 3.3, August 2001


Integrating Crosscalls with Applications . . . . . . . . . . . . . . . . . . 123<br />

Threads and Crosscalls . . . . . . . . . . . . . . . . . . . . . . . . 124<br />

Crosscalls and Library <strong>ACE</strong>s . . . . . . . . . . . . . . . . . . . . . 124<br />

Initializing and Terminating Interfaces. . . . . . . . . . . . . . . . . . . 125<br />

Initializing the Client . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

Client Initialization Example . . . . . . . . . . . . . . . . . . . . . 125<br />

Initializing the Server. . . . . . . . . . . . . . . . . . . . . . . . . 128<br />

Server Initialization Example . . . . . . . . . . . . . . . . . . . . . 129<br />

Initializing Function Pointers . . . . . . . . . . . . . . . . . . . . . 130<br />

Invoking Crosscall Functions . . . . . . . . . . . . . . . . . . . . . . . 130<br />

Opening a Crosscall Connection . . . . . . . . . . . . . . . . . . . . 131<br />

Remote Call Example. . . . . . . . . . . . . . . . . . . . . . . . . 131<br />

Passing Crosscall Arguments . . . . . . . . . . . . . . . . . . . . . . . 133<br />

Client Side Parameter Passing . . . . . . . . . . . . . . . . . . . . . 134<br />

What the Stub Function Does to Passed Parameters . . . . . . . . . . 135<br />

Server Side Parameter Passing . . . . . . . . . . . . . . . . . . . . . 135<br />

Passing Values in a One-way Call . . . . . . . . . . . . . . . . . . . 136<br />

Passing Values in a Two-way Call . . . . . . . . . . . . . . . . . . . 136<br />

Passing Values in a Deferred Call . . . . . . . . . . . . . . . . . . . 137<br />

Chapter 12 Crosscall Example . . . . . . . . . . . . . . . . . . . . . . . . 139<br />

Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139<br />

Example Interface Definition . . . . . . . . . . . . . . . . . . . . . . . 140<br />

Generated Stub Files . . . . . . . . . . . . . . . . . . . . . . . . . 140<br />

Generated Skeleton Files . . . . . . . . . . . . . . . . . . . . . . . 143<br />

Writing the Crosscall Client . . . . . . . . . . . . . . . . . . . . . . . 144<br />

Writing the Crosscall Server . . . . . . . . . . . . . . . . . . . . . . . 152<br />

Terminating the Server . . . . . . . . . . . . . . . . . . . . . . . . 159<br />

Chapter 13 Using Sets <strong>of</strong> Data to Classify Packets . . . . . . . . . . . . . 161<br />

Overview <strong>of</strong> Sets and Searches . . . . . . . . . . . . . . . . . . . . . . 161<br />

When to Use Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

Defining Sets and Searches . . . . . . . . . . . . . . . . . . . . . . . 162<br />

Defining Sets in NCL . . . . . . . . . . . . . . . . . . . . . . . . . 162<br />

Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />

For More Information . . . . . . . . . . . . . . . . . . . . . . . 164<br />

Defining Sets in ASL . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164<br />

Initializing and Populating Sets . . . . . . . . . . . . . . . . . . . . . . 165<br />

Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165<br />

For More Information . . . . . . . . . . . . . . . . . . . . . . . 167<br />

How to Use Sets and Searches . . . . . . . . . . . . . . . . . . . . . . 167<br />

Using Searches in Rules. . . . . . . . . . . . . . . . . . . . . . . . 167<br />

Using Actions to Modify Sets . . . . . . . . . . . . . . . . . . . . . 167<br />

Deleting Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168<br />

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169<br />

viii<br />

Contents<br />

Revision 3.3, August 2001


About This Guide<br />

This guide introduces you to the <strong>Intel</strong> ® Internet Exchange Architecture (<strong>IXA</strong>) s<strong>of</strong>tware<br />

development kit (<strong>SDK</strong>). This s<strong>of</strong>tware enables you to develop and deliver<br />

networking applications that define rules to classify network packet traffic, and take<br />

actions based on these rules to manage the network traffic.<br />

To develop these networking applications, you need the following:<br />

l The <strong>IXA</strong> <strong>SDK</strong>, a full set <strong>of</strong> tools for developing applications and run-time libraries<br />

for delivering applications<br />

l<br />

A board or system containing the <strong>Intel</strong> IXP1200 network processor, a high-speed<br />

packet-processing chip, such as the IXDP1200 Advanced Development Platform.<br />

This guide helps you get started creating and testing networking applications for<br />

IXP1200s using the <strong>IXA</strong> <strong>SDK</strong>.<br />

Audience<br />

This guide is intended for s<strong>of</strong>tware developers who will design, develop, and deliver<br />

network applications that must process packets at high speed. It assumes that you are<br />

familiar with the following:<br />

l<br />

l<br />

l<br />

C programming<br />

The Linux * and GNU development environment and toolset<br />

Realtime network applications<br />

In This Guide<br />

This guide includes the following chapters:<br />

l<br />

Chapter 1, “Introduction and Overview,” which gives an overview <strong>of</strong> the <strong>IXA</strong><br />

application architecture and system s<strong>of</strong>tware<br />

About This Guide<br />

ix<br />

Revision 3.3, August 2001


In This Guide<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Chapter 2, “Elements <strong>of</strong> an Application,” which introduces the <strong>IXA</strong> system s<strong>of</strong>tware,<br />

the C structures that support the <strong>ACE</strong> model, the error handling system,<br />

and the application building process<br />

Chapter 3, “Compiling and Testing Applications,” which explains the compilation<br />

model for an application containing <strong>ACE</strong>s<br />

Chapter 4, “Configuring and Starting <strong>IXA</strong> Systems,” which explains how to<br />

configure the ports and start the <strong>ACE</strong>s for an <strong>IXA</strong> system<br />

Chapter 5, “Controlling Packet Flow,” which introduces targets as destinations<br />

for packets and explains how packets flow into and out <strong>of</strong> an IXP1200 and <strong>ACE</strong>s<br />

within an application<br />

Chapter 6, “Writing Micro<strong>ACE</strong>s,” which explains the architecture <strong>of</strong> micro<strong>ACE</strong>s<br />

and describes how to write them<br />

Chapter 7, “Interface <strong>ACE</strong>s,” which introduces the system-defined micro<strong>ACE</strong>s<br />

that receive and transmit packets on network interface ports<br />

Chapter 8, “Stack and Library <strong>ACE</strong>s,” which introduces the system-defined<br />

micro<strong>ACE</strong> that represents the Linux TCP/IP stack and library <strong>ACE</strong>s that perform<br />

common networking tasks<br />

Chapter 9, “Classifying Packets Using NCL,” which introduces the Network<br />

Classification Language and explains how to use it to evaluate packets and write<br />

classification rules<br />

Chapter 10, “Initializing and Acting on Packets in an <strong>ACE</strong>,” which describes<br />

some <strong>of</strong> the actions that you can take on packets and explains how to implement<br />

action functions<br />

Chapter 11, “Communication Within an Application,” which shows how to use<br />

the crosscall mechanism for remote function calls between <strong>ACE</strong>s and other<br />

programs<br />

Chapter 12, “Crosscall Example,” which demonstrates the use <strong>of</strong> crosscalls<br />

Chapter 13, “Using Sets <strong>of</strong> Data to Classify Packets,” which describes how to<br />

create sets to associate application data with packets, and how to perform and act<br />

on the results <strong>of</strong> searches in the sets<br />

x<br />

About This Guide<br />

Revision 3.3, August 2001


Other Sources <strong>of</strong> Information<br />

Other Sources <strong>of</strong> Information<br />

This guide is part <strong>of</strong> the <strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> documentation set, which also includes:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

<strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> Reference (<strong>IXA</strong> <strong>SDK</strong> Reference), which<br />

describes the <strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> (s<strong>of</strong>tware development kit), including the <strong>IXA</strong> API,<br />

which consists <strong>of</strong> the OMS services library, the action services library (ASL), and<br />

the micro<strong>ACE</strong> Resource Manager; the Network Classification Language (NCL);<br />

the <strong>IXA</strong> IDL interface definition language; and development tools<br />

<strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> Developer’s Guide (<strong>IXA</strong> <strong>SDK</strong> Developer’s<br />

Guide), which provides programmers with conceptual descriptions and<br />

instructions on writing networking applications for the IXP1200 using the <strong>IXA</strong><br />

<strong>SDK</strong><br />

<strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> Tutorial (<strong>IXA</strong> <strong>SDK</strong> Tutorial), which<br />

provides a step-by-step introduction to building a basic <strong>IXA</strong> application<br />

<strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> Release Notes (<strong>IXA</strong> <strong>SDK</strong> Release Notes),<br />

which lists information about the latest s<strong>of</strong>tware release<br />

<strong>Intel</strong> <strong>IXA</strong> <strong>SDK</strong> for the IXP1200 Installation and Setup Guide (<strong>IXA</strong> <strong>SDK</strong> Installation and<br />

Setup Guide), which describes how to install the <strong>IXA</strong> <strong>SDK</strong> and set up the development<br />

environment<br />

Getting Started, which provides a high-level introduction to the product family<br />

and describes supported hardware and s<strong>of</strong>tware configurations<br />

The IXP1200 Microengine Development Environment documentation set, which<br />

includes the following documents:<br />

— IXP1200 Network Processor Family Microcode Programmer’s Reference Manual<br />

— IXP1200 Network Processor Family Microcode Developer Tools User’s Guide<br />

— IXP1200 Network Processor Family Microcode Example S<strong>of</strong>tware<br />

— IXP1200 Network Processor Family Hardware Reference Manual<br />

— IXP1200 Macro Library Reference Manual<br />

— IXP1200 Macro Library Style Guide<br />

— IXDP1200 I/O Option Card Design Guide<br />

— Microengine C Compiler Language Support Reference Manual<br />

— Microengine C Compiler LIBC Reference Manual<br />

In addition, the <strong>Intel</strong> Web site provides valuable information on products, support,<br />

and the company. See “Contacting <strong>Intel</strong>” on page xii.<br />

Typographic Conventions<br />

This document uses the following typographic conventions to help you locate and<br />

identify information:<br />

Italic text<br />

Bold text<br />

Used for new terms, emphasis, and book titles; also identifies arguments<br />

in syntax descriptions.<br />

Identifies keywords and punctuation in syntax descriptions.<br />

About This Guide<br />

xi<br />

Revision 3.3, August 2001


Contacting <strong>Intel</strong><br />

Courier font Identifies file names, folder names, and text that either appears on<br />

the screen or that you are required to type.<br />

NOTE: Provides extra information, tips, and hints regarding the topic.<br />

CAUTION: Identifies important information about actions that could result in<br />

damage to or loss <strong>of</strong> data or could cause the application to behave<br />

in unexpected ways.<br />

WARNING!<br />

Identifies critical information about actions that could result in<br />

equipment failure or bodily injury.<br />

Installation<br />

Path<br />

The pathname <strong>of</strong> the installation directory for the product is indicated by the<br />

following argument:<br />

<strong>SDK</strong>installpath<br />

The environment variable $IXROOT is set to the actual installation path during installation;<br />

you can use this variable if it is set in your environment.<br />

l<br />

l<br />

The default installation path for a Linux development system is /opt/ixasdk.<br />

The default installation path for a Windows NT * development system is<br />

C:\eLinuxIDE-IXP1200\cygwin\opt\ixasdk.<br />

Syntax<br />

Example<br />

Courier font is used for code. In syntax descriptions, bold indicates required<br />

keywords and a punctuation. In examples, bold highlights interesting parts. Italics<br />

indicate values that are to be replaced, such as arguments or file names. The<br />

following figure shows a sample <strong>of</strong> syntax notation.<br />

Keywords, required punctuation<br />

predicate predicate_name { boolean_expression }<br />

Arguments<br />

Contacting <strong>Intel</strong><br />

You can reach <strong>Intel</strong>’s automated support services 24 hours a day, every day at no<br />

charge. The services contain the most up-to-date information about <strong>Intel</strong> products.<br />

You can access installation instructions, troubleshooting information, and general<br />

product information.<br />

Web and<br />

Internet Sites<br />

You can use the Internet to download s<strong>of</strong>tware updates, troubleshooting tips, installation<br />

notes, and more.<br />

l<br />

General online support services are on the World Wide Web at:<br />

xii<br />

About This Guide<br />

Revision 3.3, August 2001


Contacting <strong>Intel</strong><br />

http://support.intel.com<br />

l<br />

Online support services for the IXP1200 network processor are at:<br />

http://support.intel.com/support/network/processor/ixp1200/<br />

For specific types <strong>of</strong> information and services, go to the following Web and Internet<br />

sites:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Corporate: http://www.intel.com<br />

Networking products: http://www.intel.com/network/<br />

<strong>Intel</strong> <strong>IXA</strong> information: http://developer.intel.com/design/ixa/<br />

<strong>IXA</strong> <strong>SDK</strong>: http://www.intel.com/design/network/products/s<strong>of</strong>tware/index.htm<br />

IXP1200 developer site:<br />

http://developer.intel.com/design/network/products/npfamily/ixp1200.htm<br />

FTP host: download.intel.com<br />

FTP directory: /support/network/adapter<br />

Customer<br />

Support<br />

Technicians<br />

l<br />

l<br />

United States and Canada: 1.916.377.7000 (7:00 - 17:00 M-F Pacific Time)<br />

Worldwide access: <strong>Intel</strong> has technical support centers worldwide. Many <strong>of</strong> the<br />

centers are staffed by technicians who speak the local languages. For a list <strong>of</strong> all<br />

<strong>Intel</strong> support centers, their telephone numbers, and the times they are open, go to:<br />

http://support.intel.com/support/9089.htm<br />

About This Guide<br />

xiii<br />

Revision 3.3, August 2001


Contacting <strong>Intel</strong><br />

xiv<br />

About This Guide<br />

Revision 3.3, August 2001


Chapter 1<br />

Introduction and Overview<br />

This chapter introduces you to the tools that <strong>Intel</strong> ® provides to develop and deliver<br />

network service applications using <strong>Intel</strong>’s Internet Exchange Architecture for<br />

theIXP1200 network processor.<br />

This chapter contains the following topics:<br />

l “Network Service Applications” on page 1<br />

l “Logical Elements <strong>of</strong> an <strong>IXA</strong> Application” on page 3<br />

l “The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling” on page 5<br />

l “OMS for Global Application Services” on page 10<br />

l “Hardware Architecture: The IXP1200 Network Processor” on page 14<br />

l “Components <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> for the IXP1200” on page 17<br />

Network Service Applications<br />

Networks have become a core component <strong>of</strong> businesses; their operation is critical to<br />

the businesses’ daily operation. Applications have become increasingly complex in<br />

order to manage, secure, and optimize these networks.<br />

Application developers and equipment manufacturers must develop and enhance<br />

these applications to meet the rapidly changing needs <strong>of</strong> their users while ensuring<br />

that networks operate with optimal performance.<br />

The following are common examples <strong>of</strong> network services applications:<br />

l Firewalls<br />

l Virtual private networks (VPN)<br />

l Intrusion detection systems<br />

l RMON statistical monitoring applications<br />

Revision 3.3, August 2001<br />

Introduction and Overview 1


Network Service Applications<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Load-balancing systems<br />

Quality <strong>of</strong> service (QoS) applications<br />

Voice over IP (VOIP) applications<br />

Protocol conversion<br />

Layer 3 forwarding<br />

Packet<br />

Classification<br />

At the highest level, as shown in the following figure, a network services application<br />

consists <strong>of</strong> the following:<br />

l<br />

l<br />

Interfaces to and from one or more networks (called network interface ports)<br />

Applications that process packets traveling on the networks<br />

Packet flow<br />

Input interface<br />

Application<br />

Output interface<br />

Such an application classifies the packets—that is, it compares the packet contents<br />

against some set <strong>of</strong> selection criteria. It then takes some action determined by the<br />

result <strong>of</strong> the classification and disposes <strong>of</strong> the packets. For example, it might:<br />

l<br />

l<br />

l<br />

View packets and simply decide whether to pass them to another interface or<br />

application, or to drop them<br />

Collect information about the packets and report on the flow <strong>of</strong> data<br />

Manipulate the packets in some way<br />

The following figure shows how packets might flow through a forwarding application.<br />

Packet flow<br />

Input interface<br />

Packet classification and action<br />

Yes<br />

In data table?<br />

No<br />

Good packet?<br />

No<br />

Drop<br />

Output interface<br />

Yes; update data<br />

The <strong>IXA</strong><br />

Solution<br />

The <strong>Intel</strong> Internet Exchange Architecture provides an efficient and flexible hardware<br />

and s<strong>of</strong>tware infrastructure for developing and delivering network services applications.<br />

You can develop applications for this architecture using the application<br />

programming interface (API), the <strong>IXA</strong> API.<br />

2 Introduction and Overview<br />

Revision 3.3, August 2001


Logical Elements <strong>of</strong> an <strong>IXA</strong> Application<br />

Applications that you develop with the <strong>IXA</strong> API are known as <strong>IXA</strong> applications. The<br />

<strong>IXA</strong> s<strong>of</strong>tware development kit (<strong>SDK</strong>) provides tools and libraries that allow you to<br />

quickly and easily develop and deliver <strong>IXA</strong> applications. These applications directly<br />

manipulate packets, independent <strong>of</strong> the protocol layer.<br />

You use the <strong>IXA</strong> <strong>SDK</strong> to produce applications for a hardware configuration that<br />

includes one or more IXP1200 network processors. Both the s<strong>of</strong>tware and hardware<br />

are optimized for maximum efficiency in providing network services.<br />

The rest <strong>of</strong> this document describes:<br />

l<br />

l<br />

l<br />

The logical architecture and major s<strong>of</strong>tware elements <strong>of</strong> an <strong>IXA</strong> application<br />

The IXP1200 network processor, and how you develop and deploy your application<br />

s<strong>of</strong>tware in the hardware environment<br />

The tools and libraries provided by the <strong>IXA</strong> <strong>SDK</strong><br />

Logical Elements <strong>of</strong> an <strong>IXA</strong> Application<br />

To understand the <strong>IXA</strong> s<strong>of</strong>tware architecture, you must understand the basic levels<br />

<strong>of</strong> tasks that a network services application performs. A network services application<br />

typically operates on three logical planes:<br />

l<br />

l<br />

l<br />

The data processing plane<br />

Data plane functions include the handling and forwarding <strong>of</strong> incoming packets at<br />

high speed.<br />

The control plane<br />

Control functions include the handling <strong>of</strong> exceptional cases or errors, and the<br />

creation and maintenance <strong>of</strong> both application objects and the tables or data sets<br />

that the data processing part uses for lookups.<br />

The management plane<br />

The manager for an application creates and initializes the objects in the other<br />

parts, and starts their execution. High-level management can include, for<br />

example, system or object configuration, or stopping and starting application<br />

functions in response to environmental conditions or user input. A manager<br />

might handle alerts, status reports, and other messages that the application generates.<br />

The Data Plane<br />

A part <strong>of</strong> an <strong>IXA</strong> application that performs data plane functions is a data processor<br />

(sometimes called a forwarding element). It receives buffers <strong>of</strong> data (containing cells,<br />

packets, frames, or even generalized I/O buffers) from a network interface, classifies<br />

them according to their protocols or contents, and determines their disposition by<br />

performing lookups in data tables. The data processor handles the fast path—the most<br />

frequent and usual operations—such as packet forwarding. This part <strong>of</strong> an application<br />

is optimized for performance and handles the bulk <strong>of</strong> network traffic.<br />

For the IXP1200, data processors are commonly implemented as micro<strong>ACE</strong>s compiled<br />

specifically for the microengines. (See “Accelerated <strong>ACE</strong>s” on page 7.)<br />

Introduction and Overview 3<br />

Revision 3.3, August 2001


Logical Elements <strong>of</strong> an <strong>IXA</strong> Application<br />

The Control<br />

Plane<br />

A part <strong>of</strong> an <strong>IXA</strong> application that performs control plane functions is a controller<br />

(sometimes called a control element). This part performs complex or time-consuming<br />

tasks that are encountered in the course <strong>of</strong> packet processing.<br />

For example, when a data processor for a routing application encounters a packet for<br />

which there is no entry in the routing table, it can send that packet to the controller.<br />

This leaves the data processor free to continue forwarding traffic while the controller<br />

finds the proper route and adds it to the table, or otherwise handles the exception.<br />

For the IXP1200, controllers are commonly implemented as conventional <strong>ACE</strong>s and<br />

compiled for the core processor, which provides more operating system services.<br />

Another alternative is to implement controllers using third-party protocol stack s<strong>of</strong>tware<br />

modified for use with the <strong>IXA</strong> <strong>SDK</strong>.<br />

The<br />

Management<br />

Plane<br />

A part <strong>of</strong> an <strong>IXA</strong> application that performs management functions is a manager<br />

program. Management tasks can be handled by an <strong>of</strong>f-chip application or by a standard<br />

Linux * application that runs on the IXP1200. The management code for the <strong>IXA</strong><br />

application is commonly part <strong>of</strong> a larger application that includes some sort <strong>of</strong> user<br />

interface. This part can communicate with the control and data processing pieces by<br />

making calls to the IXP1200 system s<strong>of</strong>tware.<br />

The manager program might, for example, get information from a user through a<br />

graphical user interface (GUI) and respond by changing the direction <strong>of</strong> packet flow<br />

between parts <strong>of</strong> the <strong>IXA</strong> application. Similarly, it might respond to an error message<br />

from the controller by displaying a message to a user through a GUI.<br />

In embedded systems, a manager program might implement an application-specific<br />

management protocol between an IXP1200 subsystem and a central management<br />

element; for example, communication between an IXP1200-based line card and a<br />

management card over a chassis backplane.<br />

Data/control flow<br />

Layer 3 Stateful Load<br />

routing firewall balancer<br />

application application application<br />

Management<br />

application<br />

Management<br />

plane<br />

Route<br />

management,<br />

UI<br />

Policy<br />

management,<br />

GUI<br />

Policy<br />

management,<br />

GUI<br />

Control<br />

module<br />

Control<br />

plane<br />

OSPF,<br />

RIP2, ...<br />

Connection<br />

setup<br />

Connection<br />

setup,<br />

resource<br />

allocation<br />

Data<br />

processing<br />

module<br />

Data<br />

plane<br />

Packet<br />

forward<br />

Packet<br />

pass, drop,<br />

NAT, ...<br />

Packet<br />

forward,<br />

NAT<br />

Traffic flow<br />

4 Introduction and Overview<br />

Revision 3.3, August 2001


The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling<br />

Dividing Tasks<br />

Among Code<br />

Modules<br />

You can divide the tasks belonging to each functional plane among code modules in<br />

any number <strong>of</strong> ways, depending on the complexity <strong>of</strong> your application. A single<br />

control module, for example, might receive messages from multiple data processing<br />

modules, or you might create separate control modules for different control tasks.<br />

Similarly, you might combine control and management plane tasks into a single code<br />

module, or keep them separate.<br />

Different code modules can be compiled to run on different processors, depending on<br />

what is available and appropriate to a module’s tasks.<br />

l<br />

l<br />

Data processing and control modules are commonly located on an IXP1200<br />

network processor where they can react to and process packets at high speeds.<br />

They can be further optimized by compiling them specifically for different processors<br />

on the IXP1200 network processor.<br />

A manager program might be located on another processor where it has access to<br />

user interfaces, storage, and the full range <strong>of</strong> services provided by the operating<br />

system.<br />

For more information on hardware platforms and deployment options, see “Hardware<br />

Architecture: The IXP1200 Network Processor” on page 14.<br />

The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling<br />

In order to encapsulate and modularize the unique tasks involved in packet<br />

processing, the <strong>IXA</strong> API defines a s<strong>of</strong>tware construct called an active computing<br />

element (<strong>ACE</strong>). <strong>ACE</strong>s are represented by a C structure, ix_ace.<br />

Packet<br />

Processing<br />

and <strong>ACE</strong>s<br />

<strong>ACE</strong>s are the primary s<strong>of</strong>tware components for processing packets. Both the data<br />

processing and control parts <strong>of</strong> an application contain <strong>ACE</strong>s. <strong>ACE</strong>s classify the<br />

packets, act on them according to these classifications, and determine their disposition.<br />

You organize <strong>ACE</strong>s as a serial processing pipeline, with packets passed from one<br />

<strong>ACE</strong> to another. Each one can inspect, classify, manipulate, and forward the packets<br />

that it receives.<br />

Packet processing takes place as a sequence <strong>of</strong> steps. Each step is performed by a<br />

separate <strong>ACE</strong>, and consists <strong>of</strong> a classification phase and an action phase.<br />

— During the classification phase, the <strong>ACE</strong> evaluates rules to determine if<br />

specific conditions or criteria exist. If a rule is true, the <strong>ACE</strong> places an associated<br />

action on a queue to be performed after all rules have been evaluated.<br />

More than one rule can be true, in which case all associated actions are queued.<br />

— During the action phase, the <strong>ACE</strong> executes all scheduled actions. If no rules<br />

are true, the <strong>ACE</strong> takes a default action, such as delivering the packet to a<br />

default destination or discarding it. <strong>ACE</strong>s can modify, drop, duplicate, or<br />

simply inspect the packets that they receive. Thus, packets can appear, disappear,<br />

or be changed as they flow through the <strong>ACE</strong>s.<br />

Introduction and Overview 5<br />

Revision 3.3, August 2001


The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling<br />

An <strong>ACE</strong> is defined by several distinct source code files. An initialization part, which<br />

creates and initializes needed structures and variables, and the action part, which<br />

defines the associated action functions, are written in C/C++. The classification part <strong>of</strong><br />

the <strong>ACE</strong>, which defines a set <strong>of</strong> packet classification rules, is written in Network Classification<br />

Language (NCL )<br />

Each <strong>ACE</strong> generally performs one type <strong>of</strong> packet handling or data control task. You<br />

can distribute tasks among <strong>ACE</strong>s, and <strong>ACE</strong>s among code modules in any way that is<br />

logical for your application. The following figure shows the high-level architecture <strong>of</strong><br />

a typical <strong>IXA</strong> application.<br />

Managing application<br />

Object creation,<br />

flow control<br />

Error handling, status<br />

<strong>ACE</strong><br />

Control module<br />

<strong>ACE</strong><br />

Data<br />

management<br />

Data initialization,<br />

configuration<br />

Exception cases<br />

Input interface<br />

Output interface<br />

Packet flow<br />

<strong>ACE</strong><br />

<strong>ACE</strong><br />

Data processing modules<br />

You can create your own <strong>ACE</strong>s using the <strong>IXA</strong> API, or you can use predefined <strong>ACE</strong>s<br />

that perform specific network processing tasks, as described below in “Predefined<br />

<strong>ACE</strong>s.”<br />

Your application defines the flow <strong>of</strong> packets among <strong>ACE</strong>s by creating packet destinations<br />

called targets and by binding the targets to other <strong>ACE</strong>s; see “Defining the Traffic<br />

Flow Path with Targets” on page 11.<br />

Writing <strong>ACE</strong>s<br />

using C, NCL<br />

and <strong>IXA</strong> IDL<br />

In the initialization part <strong>of</strong> an <strong>ACE</strong>, you create the <strong>ACE</strong> structure itself, with its<br />

related communication methods and data structures, using the ASL core C library.<br />

In the classification part <strong>of</strong> an <strong>ACE</strong>, rules can compare packet contents against static<br />

values or against dynamic data. You define these rules using the Network Classification<br />

Language (NCL) provided with the <strong>IXA</strong> <strong>SDK</strong>. NCL is a domain-specific objectoriented<br />

language for defining packet classification rules and identifying the associated<br />

actions to be taken when matches occur. This language-based approach makes<br />

it easy for you to specify the required classification criteria.<br />

6 Introduction and Overview<br />

Revision 3.3, August 2001


The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling<br />

In the action part <strong>of</strong> an <strong>ACE</strong>, you define the <strong>ACE</strong> infrastructure and action functions<br />

in C/C++. In the action functions, you can use run-time support for networking tasks<br />

provided by the ASL application services. These C/C++ class and function libraries<br />

provide support for handling application-specific operations; for example, TCP/IP<br />

operations such as IP fragmentation and reassembly, Network Address Translation<br />

(NAT), and TCP connection monitoring and stream reconstruction.<br />

For communication between <strong>ACE</strong>s and other parts <strong>of</strong> an application, you define<br />

remote function calls, using an interface definition language, <strong>IXA</strong> IDL. This compiles<br />

to C and becomes part <strong>of</strong> the <strong>ACE</strong>’s C source code. See “Communication Among<br />

<strong>ACE</strong>s” on page 12.<br />

Predefined<br />

<strong>ACE</strong>s<br />

Depending on who develops it and how it is created, an <strong>ACE</strong> can be a user <strong>ACE</strong>, a<br />

library <strong>ACE</strong>, or a system <strong>ACE</strong>. You can combine all three types in an application.<br />

l<br />

l<br />

User <strong>ACE</strong>s<br />

User <strong>ACE</strong>s are those that you develop yourself, defining all <strong>of</strong> the classification<br />

rules and actions.<br />

Library <strong>ACE</strong>s<br />

<strong>Intel</strong> supplies a set <strong>of</strong> predefined library <strong>ACE</strong>s, which provide building blocks for<br />

common application functionality such as layer 2 bridging and layer 3 (IP)<br />

forwarding.<br />

NOTE:<br />

Some library <strong>ACE</strong>s are supplied with source code so that you can configure<br />

them and modify their packet classification criteria and actions. When you<br />

modify a library <strong>ACE</strong>, it becomes a user <strong>ACE</strong> and is no longer supported and<br />

maintained by <strong>Intel</strong>.<br />

l<br />

System <strong>ACE</strong>s<br />

These platform-specific <strong>ACE</strong>s represent hardware network interfaces (interface<br />

<strong>ACE</strong>s) or protocol stacks (stack <strong>ACE</strong>s). The system <strong>ACE</strong>s are not necessarily implemented<br />

like other <strong>ACE</strong>s; they simply mask hardware and system details that are<br />

specific to a particular environment, and look like <strong>ACE</strong>s to your application.<br />

The system <strong>ACE</strong>s act as packet sources and destinations. They are opaque to other<br />

<strong>ACE</strong>s. You can configure system <strong>ACE</strong>s and communicate with them, but you<br />

cannot modify them.<br />

You customize the system initialization scripts to load and start the system <strong>ACE</strong>s<br />

your application and hardware configuration requires. The <strong>IXA</strong> <strong>SDK</strong> supplies<br />

system <strong>ACE</strong>s for the Ethernet * 10/100 and gigabit ports on the IXDP1200<br />

Advanced Development Platform, and for the Linux TCP/IP stack.<br />

Accelerated<br />

<strong>ACE</strong>s<br />

The <strong>ACE</strong> architecture allows an <strong>ACE</strong> to take advantage <strong>of</strong> the speed <strong>of</strong> dedicated<br />

processors. An <strong>ACE</strong> that runs entirely on the core processor is a conventional <strong>ACE</strong>. An<br />

<strong>ACE</strong> that includes code for another processor is called an accelerated <strong>ACE</strong>.<br />

The <strong>IXA</strong> <strong>SDK</strong> provides a type <strong>of</strong> accelerated <strong>ACE</strong> called a micro<strong>ACE</strong>. The micro<strong>ACE</strong><br />

programming model provides a framework for creating a packet-processing application<br />

that makes use <strong>of</strong> the IXP1200’s microengines. A micro<strong>ACE</strong> has two logical<br />

components, running on different processors:<br />

Introduction and Overview 7<br />

Revision 3.3, August 2001


The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling<br />

l<br />

l<br />

The core component <strong>of</strong> a micro<strong>ACE</strong> is a complete conventional <strong>ACE</strong>, with<br />

C/C++, NCL, and <strong>IXA</strong> IDL code. The core component runs on the core processor<br />

in the IXP1200.<br />

The acceleration component <strong>of</strong> a micro<strong>ACE</strong>, called a microblock, is hardwarespecific<br />

and is written in IXP1200 microcode (machine code). The microblock runs<br />

on the microengines in the IXP1200. It performs fast-path processing, but can<br />

exchange packets with its core component on the core processor to handle exception<br />

cases.<br />

For more information on hardware platforms and deployment options, see “Hardware<br />

Architecture: The IXP1200 Network Processor” on page 14.<br />

You use micro<strong>ACE</strong>s for optimized, high-speed (fast-path) processing. Because the<br />

IXP1200 network processor contains a number <strong>of</strong> microengines running in parallel,<br />

each with multiple threads, micro<strong>ACE</strong>s provide extremely high efficiency in basic<br />

packet handling. Most system <strong>ACE</strong>s and library <strong>ACE</strong>s are implemented as micro-<br />

<strong>ACE</strong>s.<br />

The <strong>IXA</strong> <strong>SDK</strong> includes a complete set <strong>of</strong> tools, including compilers, linkers, and<br />

debuggers, for working with microcode to develop micro<strong>ACE</strong>s. For more information<br />

on the architecture <strong>of</strong> micro<strong>ACE</strong>s, see Chapter 6, “Writing Micro<strong>ACE</strong>s.”<br />

Dividing Tasks<br />

Among <strong>ACE</strong><br />

Types<br />

Generally, a micro<strong>ACE</strong> looks in a packet to classify it, performs simple transformations<br />

(such as NAT or protocol conversion), and routes it to the appropriate target.<br />

Exceptions are reported to another (conventional) <strong>ACE</strong> for handling. This allows<br />

time-consuming operations to run in parallel without slowing down traffic.<br />

The following figure shows an example <strong>of</strong> a forwarding application that uses a<br />

micro<strong>ACE</strong> for data processing and a conventional <strong>ACE</strong> for control.<br />

8 Introduction and Overview<br />

Revision 3.3, August 2001


The <strong>ACE</strong> <strong>Programming</strong> <strong>Framework</strong> for Packet Handling<br />

Control plane<br />

FwdControl <strong>ACE</strong><br />

Update cache & forward<br />

Full lookup<br />

Forwarding table<br />

Route entry<br />

prefix = 192.0.0.0<br />

ifnum = 82<br />

nexthop = 192.168.0.02<br />

Packet flow<br />

Input interface<br />

Data plane<br />

Forwarding cache<br />

Exception:<br />

Quick lookup<br />

not in cache<br />

Forwarder micro<strong>ACE</strong><br />

Forward<br />

Fast path<br />

Output interface<br />

In this example, the application defines a data table with the forwarding information<br />

on the core processor, and keeps a smaller data cache in the microcode on the microengines.<br />

A micro<strong>ACE</strong> called Forwarder handles most packet forwarding. When it<br />

encounters a packet that does not have an entry in the local forwarding cache, it sends<br />

that packet to a conventional <strong>ACE</strong>, called FwdControl. While the FwdControl <strong>ACE</strong><br />

does a full lookup in the complete forwarding table, the Forwarder <strong>ACE</strong> can<br />

continue to handle traffic flow. When FwdControl is finished, it updates the cache<br />

and, if appropriate, inserts the exception-case packet back into the traffic flow.<br />

l<br />

l<br />

The Resource Manager defines memory management functions for a small<br />

amount <strong>of</strong> memory that can be shared by the microengines and core processor.<br />

For more information, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

The <strong>IXA</strong> API defines data structures and functions for implementing larger data<br />

tables in unshared memory, called sets. For more information, see Chapter 13,<br />

“Using Sets <strong>of</strong> Data to Classify Packets.”<br />

Using Stack<br />

<strong>ACE</strong>s<br />

The <strong>IXA</strong> <strong>SDK</strong> allows you to tie the services <strong>of</strong> the Linux TCP/IP protocol stack into<br />

the structure <strong>of</strong> an <strong>IXA</strong> application.<br />

A system <strong>ACE</strong> called the stack <strong>ACE</strong> enables any other <strong>ACE</strong> in the system to deliver<br />

packets to—or receive packets from—the Linux kernel. You can then use standard<br />

sockets-based application s<strong>of</strong>tware to implement portions <strong>of</strong> an <strong>IXA</strong> application<br />

without having to use the <strong>ACE</strong> s<strong>of</strong>tware model. In this case, other <strong>ACE</strong>s in the system<br />

Introduction and Overview 9<br />

Revision 3.3, August 2001


OMS for Global Application Services<br />

appear, from the Linux TCP/IP stack point <strong>of</strong> view, as standard Ethernet interfaces.<br />

This provides a means for you to re-use existing or third-party protocol stack or<br />

management plane s<strong>of</strong>tware while migrating an application to the <strong>ACE</strong> model.<br />

OMS for Global Application Services<br />

Object Management System (OMS) services are part <strong>of</strong> the <strong>IXA</strong> API. The OMS, part <strong>of</strong><br />

the <strong>IXA</strong> system s<strong>of</strong>tware, is a single logical entity with components distributed<br />

throughout the system. Any <strong>ACE</strong> can make use <strong>of</strong> OMS services. Any program that<br />

must communicate with an <strong>ACE</strong> can do so by registering itself with the OMS as a task.<br />

An application uses global C functions defined by the OMS services to create,<br />

configure, control, and destroy objects and structures in all parts <strong>of</strong> the application,<br />

and to perform global tasks. The primary global services your application requires<br />

are:<br />

l<br />

l<br />

l<br />

Creating and destroying <strong>ACE</strong>s and tasks<br />

Defining and controlling packet flow using targets<br />

Communicating among <strong>ACE</strong>s and tasks<br />

The OMS contains the following parts:<br />

l The Resolver, which creates and deletes <strong>ACE</strong>s, and manages packet flow by<br />

binding <strong>ACE</strong>s and targets.<br />

l<br />

The Name Server, which manages the name space for the OMS, maintaining a<br />

correspondence between names and internal identifiers for <strong>ACE</strong>s, targets and<br />

tasks. The name space allows objects that might be distributed among processors<br />

to address one another unambiguously.<br />

In order to communicate with and through the OMS, a program must create a<br />

communications channel, a separate process or thread containing a communication<br />

access process, or CAP. A program can communicate with both the Resolver and the<br />

Name Server through the same CAP. When you create an <strong>ACE</strong> or task structure, a<br />

CAP is automatically created with it. The OMS provides functions to retrieve the<br />

CAP for use as an argument to other OMS functions.<br />

Creating <strong>ACE</strong>s<br />

An application’s manager program creates and initializes the application’s <strong>ACE</strong>s by<br />

calling Resolver functions in the OMS. To do this, it must first register with the OMS<br />

as a task, using the ASL function ix_task_init. The task provides access to a CAP<br />

channel through which to communicate with the Resolver.<br />

You define an initialization function in the <strong>ACE</strong> executable to create the <strong>ACE</strong> structure<br />

and all support structures such as packet destination targets, data sets and<br />

elements, crosscalls, and events.<br />

When the manager program creates the <strong>ACE</strong>, you pass the <strong>ACE</strong> executable to the<br />

Resolver function ix_res_create_ace. This calls the initialization function and<br />

starts the <strong>ACE</strong>’s main loop, which begins packet and crosscall event processing.<br />

10 Introduction and Overview<br />

Revision 3.3, August 2001


OMS for Global Application Services<br />

The <strong>IXA</strong> <strong>SDK</strong> also supplies utilities to start and stop <strong>ACE</strong>s from the command line or<br />

from a script.<br />

Defining the<br />

Traffic Flow<br />

Path with<br />

Targets<br />

Packets flow from one <strong>ACE</strong> to another, with each <strong>ACE</strong> performing a specific operation.<br />

The packet flow starts with a system <strong>ACE</strong> that represents a network interface<br />

(see “Predefined <strong>ACE</strong>s” on page 7). You determine the order in which packets are<br />

directed from the system <strong>ACE</strong> through intermediate <strong>ACE</strong>s before they are directed<br />

back out to the network through a network interface, or dropped from traffic.<br />

An application defines the paths through which packets flow between <strong>ACE</strong>s by specifying<br />

a set <strong>of</strong> targets. A target is an object within an <strong>ACE</strong> that represents a destination<br />

for packets. Each <strong>ACE</strong> contains a set <strong>of</strong> targets to which it routes packets when it has<br />

finished processing them. Each action ends by directing a packet to a target. For<br />

example, here are three <strong>ACE</strong>s with targets; packet flow among <strong>ACE</strong>s is not yet implemented.<br />

Network interface <strong>ACE</strong><br />

Target T1<br />

Packet flow <strong>ACE</strong> 1<br />

Decision?<br />

Target T2<br />

Target T3<br />

<strong>ACE</strong> 2<br />

Processing<br />

Target T4<br />

The application implements traffic flow between <strong>ACE</strong>s by binding targets in one <strong>ACE</strong><br />

to other <strong>ACE</strong>s. When an application binds a target to an <strong>ACE</strong>, the target serves as the<br />

input queue for that <strong>ACE</strong>. The bound <strong>ACE</strong> is then downstream in the packet flow<br />

from the <strong>ACE</strong> containing the target.<br />

In the following diagram, target T1 is bound to <strong>ACE</strong>1; target T3 is bound to <strong>ACE</strong>2;<br />

and targets T2 and T4 have not yet been bound.<br />

Introduction and Overview 11<br />

Revision 3.3, August 2001


OMS for Global Application Services<br />

Network interface <strong>ACE</strong><br />

Target T1<br />

Packet flow <strong>ACE</strong> 1<br />

Decision?<br />

Target T2<br />

Target T3<br />

<strong>ACE</strong> 2<br />

Processing<br />

Target T4<br />

The management program for an application binds and unbinds targets and <strong>ACE</strong>s<br />

using Resolver functions (ix_res_bind and ix_res_unbind) that are part <strong>of</strong> the<br />

OMS services. The <strong>IXA</strong> <strong>SDK</strong> also supplies utilities to bind <strong>ACE</strong>s and targets from the<br />

command line or from a script.<br />

The target mechanism makes the actual identities <strong>of</strong> the <strong>ACE</strong>s transparent to the<br />

action code that forwards the packets. The management part <strong>of</strong> your application can<br />

change the bindings <strong>of</strong> targets to <strong>ACE</strong>s to alter the path <strong>of</strong> packet flow, without you<br />

having to change the code in the <strong>ACE</strong>s themselves.<br />

For more information, see Chapter 5, “Controlling Packet Flow.”<br />

Communicatio<br />

n Among <strong>ACE</strong>s<br />

<strong>ACE</strong>s <strong>of</strong>ten need to communicate with one another or with a managing application<br />

for various reasons. For example:<br />

l<br />

l<br />

l<br />

<strong>ACE</strong>s can send alerts or status reports to the managing application.<br />

<strong>ACE</strong>s in a data processor module can receive control messages and data from<br />

<strong>ACE</strong>s in a control module.<br />

<strong>ACE</strong>s can send occasional packet data to other <strong>ACE</strong>s for special processing, or can<br />

exchange messages among themselves to coordinate packet processing.<br />

Because <strong>ACE</strong>s and their managing application might be running on different platforms<br />

and be written in different languages, the OMS acts as a message broker, using<br />

a remote procedure call model for object communication.<br />

<strong>ACE</strong>s and tasks communicate using a crosscall interface for remote method invocation.<br />

Remote method calls are handled through the distributed OMS, which provides<br />

marshalling and format conversion to address differences in byte order and word<br />

size between different processors.<br />

An <strong>ACE</strong> or task can act as a server or a client for remote procedure calls.<br />

l<br />

l<br />

The call server contains a crosscall object with the call method implementation.<br />

The call client makes remote calls to the call server using a crosscall reference object.<br />

12 Introduction and Overview<br />

Revision 3.3, August 2001


OMS for Global Application Services<br />

rules<br />

actions<br />

Remote<br />

procedure<br />

call<br />

CAP, crosscall reference<br />

OMS Communication Controller<br />

Client <strong>ACE</strong><br />

Packet<br />

flow<br />

Packet<br />

classification<br />

CAP, crosscall<br />

Response<br />

(optional)<br />

Related<br />

actions<br />

Server <strong>ACE</strong><br />

You define a crosscall interface for an application using an interface definition<br />

language, <strong>IXA</strong> IDL, that is provided with the <strong>IXA</strong> <strong>SDK</strong>. <strong>IXA</strong> IDL is not OMG IDL; it<br />

has been refined to specifically target the type <strong>of</strong> interfaces needed in network packet<br />

processing applications, rather than interfaces for general purpose applications.<br />

You define calls to be synchronous or asynchronous, with or without a response. The<br />

definition compiles to C code that implements the crosscall infrastructure, which you<br />

then modify to provide specific call functions.<br />

l<br />

l<br />

Modify the crosscall source file to implement application-specific call functions.<br />

Compile the source code into the call server executable.<br />

For asynchronous calls with response (deferred calls), modify the callback source<br />

file to implement the callback function that is executed when the call completes.<br />

Compile the source code for the crosscall references (stubs) and callbacks into the<br />

call client executable.<br />

Library <strong>ACE</strong>s and system <strong>ACE</strong>s typically export crosscall interfaces. <strong>ACE</strong>s defined in<br />

your application must import these interfaces and include the crosscall references in<br />

order to invoke the calls in the predefined <strong>ACE</strong>s.<br />

Micro<strong>ACE</strong><br />

Resource<br />

Manager<br />

Programs running on the core processor, including the core components <strong>of</strong> micro-<br />

<strong>ACE</strong>s and <strong>ACE</strong> management applications, communicate with the microengines<br />

using the micro<strong>ACE</strong> Resource Manager. The Resource Manager is system s<strong>of</strong>tware<br />

that runs in the core processor kernel. The Resource Manager API allows a micro<strong>ACE</strong><br />

management program to do the following:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Initialize and configure the IXP1200.<br />

Load code onto microengines.<br />

Enable and disable the microengines.<br />

Get and set the microengine configuration and resource assignments.<br />

Allocate and access uncached SRAM, SDRAM and scratch memory.<br />

Introduction and Overview 13<br />

Revision 3.3, August 2001


Hardware Architecture: The IXP1200 Network Processor<br />

l<br />

l<br />

Create and bind micro<strong>ACE</strong>s.<br />

Send packets to and receive packets from the microengines.<br />

Details <strong>of</strong> the Resource Manager API are provided in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Hardware Architecture: The IXP1200 Network Processor<br />

<strong>IXA</strong> applications run on the <strong>Intel</strong> IXP1200 network processor. The IXP1200 contains<br />

a StrongARM * core processor, a set <strong>of</strong> programmable microengines, onboard SDRAM<br />

and SRAM, and a high-speed bus.<br />

l<br />

l<br />

The StrongARM core processor is a general-purpose processor running an<br />

embedded Linux operating system. Conventional <strong>ACE</strong>s run on the core<br />

processor.<br />

The microengines are very high-speed processors that are specialized for packet<br />

processing. Micro<strong>ACE</strong>s run in microengines. Because there are no OMS services<br />

in the microengines, a component runs on the core processor to handle communications<br />

and control functions for micro<strong>ACE</strong>s.<br />

The <strong>Intel</strong> IXDP1200 Advanced Development Platform incorporates the IXP1200 into<br />

a board that has sixteen Ethernet 10/100 ports and two gigabit ports.<br />

IXM1200 Network<br />

Processor Base Card<br />

Single-Board<br />

Computer<br />

IXP1200<br />

Network<br />

Processor<br />

StrongARM<br />

Microengines<br />

S<strong>of</strong>tware<br />

Configuration<br />

Your s<strong>of</strong>tware environment includes the following:<br />

l<br />

l<br />

The IXP1200 embedded operating system is Linux.<br />

You must download the RAMdisk and Linux kernel onto the IXM1200 Network<br />

Processor Base Card.<br />

Your development environment is a combination <strong>of</strong> the Windows NT operating<br />

system and either a Linux platform or Cygwin for a Linux environment on the<br />

Windows NT platform, with the following development tools:<br />

— Microengine toolchain: Embedded Linux version <strong>of</strong> the IXP1200 Microengine<br />

Development Environment, running under Windows NT.<br />

This enables you to remotely develop and debug code running on<br />

Microengines on the IXP1200. You must install this from Volume II, CD 1.<br />

— StrongARM toolchain: GNU/C++ cross-hosted toolchain. You can invoke the<br />

toolchain utilities from a command shell or through the optional Embedded<br />

Linux IDE.<br />

14 Introduction and Overview<br />

Revision 3.3, August 2001


Hardware Architecture: The IXP1200 Network Processor<br />

This enables you to remotely develop and debug code running on the<br />

StrongARM on the IXP1200. You must install this from Volume II, CD 1.<br />

— Omni-NFS Server, optional.<br />

A 30-day trial version <strong>of</strong> an NFS server that makes directories located on a<br />

Windows NT platform visible to application code running on the StrongARM<br />

core processor. To use this optional s<strong>of</strong>tware, you must install this from<br />

Volume II CD 1.<br />

— Linux IDE, optional.<br />

This supports application development, kernel debugging, and device driver<br />

development. It includes VMON as its debugger and boot loader. To use this<br />

optional s<strong>of</strong>tware, you must install it from the Embedded Linux IDE CD-ROM<br />

Figure 1: Linux s<strong>of</strong>tware configuration for the <strong>Intel</strong> IXDP1200 Advanced Development<br />

Platform using only a Windows NT development environment<br />

IXM1200 Network<br />

Processor Base Card<br />

Windows NT<br />

platform<br />

Linux<br />

Microengine Toolchain:<br />

IXP1200 Microengine Development Environment<br />

StrongARM Toolchain:<br />

GNU C/C++ cross-compiler<br />

Linux IDE (optional)<br />

Figure 2: Linux s<strong>of</strong>tware configuration for the <strong>Intel</strong> IXDP1200 Advanced Development<br />

Platform using both Windows NT and Linux development environments<br />

IXM1200 Network<br />

Processor Base Card<br />

Windows NT<br />

platform<br />

Linux<br />

Microengine Toolchain:<br />

IXP1200 Microengine Development Environment<br />

StrongARM Toolchain:<br />

GNU C/C++ cross-compiler<br />

Linux IDE (optional)<br />

Linux<br />

platform<br />

Hardware<br />

Configuration<br />

To develop applications for the Embedded Linux environment using this release <strong>of</strong><br />

the <strong>IXA</strong> <strong>SDK</strong>, you must have one <strong>of</strong> the hardware configurations described in the <strong>IXA</strong><br />

<strong>SDK</strong> Installation and Setup Guide. There are three supported configurations for developers<br />

using Linux as the embedded operating system:<br />

l<br />

Configuration 1: Windows NT on the single-board computer on the <strong>Intel</strong><br />

IXDP1200 Advanced Development Platform with an external keyboard and<br />

monitor attached.<br />

Introduction and Overview 15<br />

Revision 3.3, August 2001


Hardware Architecture: The IXP1200 Network Processor<br />

IXM1200 Network<br />

Processor Base Card<br />

Single-board<br />

Computer<br />

Keyboard cable<br />

Serial<br />

Video cable<br />

Ethernet (see section on Ethernet connections)<br />

l<br />

Configuration 2: An external Windows NT workstation <strong>of</strong> your own choosing, in<br />

which case the single-board computer is not used.<br />

IXM1200 Network<br />

Processor Base Card<br />

Windows NT Workstation<br />

Serial<br />

Ethernet (see section on Ethernet connections)<br />

l<br />

Configuration 3: An external Linux workstation <strong>of</strong> your own choosing in addition<br />

to Windows NT on the single-board computer.<br />

IXM1200 Network<br />

Processor Base Card<br />

Single-board<br />

Computer<br />

Serial<br />

Keyboard cable<br />

Video cable<br />

Ethernet (see section on Ethernet connections)<br />

Linux workstation<br />

The connections in these configurations include:<br />

l<br />

A serial cable from the serial port <strong>of</strong> the IXM1200 Network Processor Base Card<br />

to the com port <strong>of</strong> the Windows NT platform to provide a remote serial console for<br />

the IXM1200 Network Processor Base Card.<br />

16 Introduction and Overview<br />

Revision 3.3, August 2001


Components <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> for the IXP1200<br />

l<br />

l<br />

Ethernet connections between the IXM1200 Network Processor Base Card and<br />

your chosen Windows NT and/or Linux development platforms as described in<br />

the <strong>IXA</strong> <strong>SDK</strong> Installation and Setup Guide.<br />

For remote debugging <strong>of</strong> the IXM1200 Network Processor Base Card, all configurations<br />

use the Ethernet connection.<br />

In configurations 1 and 3, video and keyboard cables from the single-board<br />

computer to your own external monitor and keyboard.<br />

Deploying<br />

Applications<br />

Most developers <strong>of</strong> <strong>IXA</strong> systems develop hardware and s<strong>of</strong>tware simultaneously:<br />

l<br />

l<br />

OEMs develop boards and systems around the IXP1200 chip.<br />

Appliance vendors develop systems around an <strong>Intel</strong> board, the Policy Accelerator,<br />

which contains a complete IXP1200 subsystem.<br />

At the beginning <strong>of</strong> the development cycle, s<strong>of</strong>tware developers work with a generic<br />

development system. Later in the development cycle, the s<strong>of</strong>tware and hardware<br />

developers work together to integrate the s<strong>of</strong>tware into the deployment hardware<br />

environment.<br />

To deploy an <strong>IXA</strong> application, you use the RAMdisk and flash utilities to create a<br />

flash image that contains both the application code you developed and an embedded<br />

Linux operating system. Depending on your deployment configuration, you download<br />

this image to the flash in the IXP1200 in the factory, or create an initialization or<br />

boot procedure to download it.<br />

Components <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> for the IXP1200<br />

The <strong>IXA</strong> <strong>SDK</strong> is designed specifically to develop <strong>IXA</strong> applications. It contains the<br />

tools, libraries, drivers, and other runtime elements that you use to develop, debug,<br />

and deliver embedded network applications. It also contains efficient languages for<br />

describing and classifying packets and for defining communication interfaces.<br />

The <strong>IXA</strong> <strong>SDK</strong> includes the following elements:<br />

l<br />

An application programming interface, the <strong>IXA</strong> API, which includes the<br />

following:<br />

— Object Management System (OMS) services library, which provides C support<br />

for interobject communication, <strong>ACE</strong> creation, and control <strong>of</strong> traffic flow.<br />

— The Action Services Library (ASL) core services, which provide C and C++<br />

support for the packet-handling mechanism, and C support for data sets,<br />

event scheduling, and error handling.<br />

— The ASL application services, independent libraries which provide C and C++<br />

support for efficient implementation <strong>of</strong> common packet-manipulation tasks,<br />

such as TCP/IP manipulation and reassembly, NAT, string searches in<br />

packets, ARP processing, and so on. These application building blocks speed<br />

development time. Additional libraries are made available from time to time.<br />

— The micro<strong>ACE</strong> Resource Manager API, which provides management services<br />

for micro<strong>ACE</strong>s and microengines and access to shared memory.<br />

Introduction and Overview 17<br />

Revision 3.3, August 2001


Components <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> for the IXP1200<br />

— Microcode macros for use in micro<strong>ACE</strong> microblocks and dispatch loops.<br />

l<br />

l<br />

l<br />

System s<strong>of</strong>tware, which includes the following:<br />

— The <strong>ACE</strong> runtimes for each <strong>ACE</strong>, which perform packet handling<br />

— The Object Management System (OMS), which acts as a name server and<br />

resource manager and provides the framework for interobject communication<br />

— The micro<strong>ACE</strong> Resource Manager, which manages micro<strong>ACE</strong> memory and<br />

coordinates communication between the core component and microblock in<br />

micro<strong>ACE</strong>s.<br />

— An embedded operating system (Linux, a widely-used, standard, open-source<br />

system)<br />

— A boot manager that performs power-on initialization<br />

— Device drivers<br />

— A TCP/IP protocol stack<br />

— Run-time libraries that provide execution and management services for the<br />

<strong>ACE</strong> model, name space, data handling, and interobject communication.<br />

S<strong>of</strong>tware development tools:<br />

— Network Classification Language (NCL), which you use to classify packets<br />

and direct actions to be taken.<br />

— An interface definition language, <strong>IXA</strong> IDL, in which you specify the crosscall<br />

interfaces that objects use to communicate through the OMS.<br />

— Linux compilers, assemblers, linkers, loaders, and debuggers for code in the<br />

various languages (C/C++, IDL, and NCL).<br />

— Command-line utilities for working with <strong>ACE</strong>s.<br />

— The IXP1200 Microengine Development Environment, a tool that supports the<br />

development and integration <strong>of</strong> microcode modules targeted for the microengines,<br />

the optimized packet processors on the IXP1200. This includes<br />

IXP1200 microcode, along with compilers, debuggers, and application development<br />

utilities.<br />

Predefined building blocks<br />

Example code and sample applications, reusable and modifiable library <strong>ACE</strong>s,<br />

predefined protocol descriptions, and other elements to make application development<br />

rapid.<br />

18 Introduction and Overview<br />

Revision 3.3, August 2001


Chapter 2<br />

Elements <strong>of</strong> an Application<br />

This chapter introduces the languages and libraries that you use to build networking<br />

applications with the <strong>Intel</strong> ® <strong>IXA</strong> <strong>SDK</strong>. It describes the <strong>IXA</strong> system s<strong>of</strong>tware that coordinates<br />

objects running on different processors, the C structures that support the <strong>ACE</strong><br />

model, and the application building process.<br />

This chapter contains the following topics:<br />

l “Overview” on page 19<br />

l “The Object Management System” on page 20<br />

l “<strong>ACE</strong>s and Support Structures” on page 22<br />

l “Micro<strong>ACE</strong> Support Services” on page 24<br />

l “The Application Building Process” on page 25<br />

Overview<br />

The <strong>IXA</strong> <strong>SDK</strong> defines the active computing element (<strong>ACE</strong>), and provides an infrastructure<br />

and object-oriented environment that you use to develop applications using<br />

the <strong>ACE</strong> programming framework.<br />

Your application creates C structures and C++ objects for each independent <strong>ACE</strong>, and<br />

additional code in supporting languages such as Network Classification Language<br />

(NCL), <strong>IXA</strong> Interface Definition Language (IDL), and IXP1200 microcode. Each <strong>ACE</strong><br />

can call API functions or predefined macros, as well as defining functions to perform<br />

the network service functionality that your application requires.<br />

The <strong>IXA</strong> <strong>SDK</strong> includes tools for programming the IXP1200 directly in microcode<br />

(assembly language), and also provides the infrastructure for integrating microcode<br />

with <strong>ACE</strong>s using the micro<strong>ACE</strong> architecture.<br />

Revision 3.3, August 2001<br />

Elements <strong>of</strong> an Application 19


The Object Management System<br />

A networking application that uses the <strong>ACE</strong> programming framework makes use <strong>of</strong><br />

function libraries, macros, and so on that are provided with the <strong>SDK</strong>. Such an application<br />

includes source code in the following languages:<br />

Language Tools Libraries and predefined code<br />

C/C++<br />

Gnu toolchain (gcc, ld,<br />

gdb, and so on)<br />

Object Management System<br />

(OMS), Action Services Library<br />

(ASL), Resource Manager, startup<br />

and configuration scripts<br />

IXP1200 microcode<br />

IXP1200 Microengine<br />

Development Environment<br />

IXP1200 packet-handling macros,<br />

micro<strong>ACE</strong> macros<br />

Network Classification<br />

Language (NCL)<br />

<strong>IXA</strong> Interface Definition<br />

Language (IDL)<br />

NCL compiler (nclcomp)<br />

<strong>IXA</strong> IDL compiler<br />

(tao_idl)<br />

TCP/IP protocol definitions<br />

The <strong>IXA</strong> <strong>SDK</strong> provides entire predefined <strong>ACE</strong>s that you can use as building blocks<br />

for rapid application development. These include the following:<br />

l<br />

l<br />

l<br />

The interface <strong>ACE</strong>s, system-defined micro<strong>ACE</strong>s that every application uses to<br />

receive and transmit packets on the network interface ports<br />

The stack <strong>ACE</strong>, which represents the Linux * TCP/IP stack<br />

Several library <strong>ACE</strong>s that perform typical networking tasks such as layer-three<br />

packet forwarding, layer-two bridging, and network address translation.<br />

For more information on the predefined <strong>ACE</strong>s, see Chapter 7, “Interface <strong>ACE</strong>s,” and<br />

Chapter 8, “Stack and Library <strong>ACE</strong>s.”<br />

The Object Management System<br />

The Object Management System (OMS), part <strong>of</strong> the IX system s<strong>of</strong>tware, is a single<br />

logical entity with components distributed throughout the system. The OMS services<br />

are part <strong>of</strong> the <strong>IXA</strong> API. The management and control modules for an application use<br />

the global C functions defined by the OMS services to create, configure, control, and<br />

destroy objects and structures in all parts <strong>of</strong> the application, and to perform global<br />

tasks. The primary global services your application requires are:<br />

l<br />

l<br />

l<br />

Creating and destroying <strong>ACE</strong>s<br />

Defining and controlling packet flow using targets<br />

Communicating among <strong>ACE</strong>s and other programs with crosscalls<br />

Parts <strong>of</strong> the<br />

OMS<br />

The OMS contains the following parts:<br />

l<br />

The Resolver, which creates and deletes <strong>ACE</strong>s, and manages packet flow by<br />

binding <strong>ACE</strong>s and targets.<br />

20 Elements <strong>of</strong> an Application<br />

Revision 3.3, August 2001


The Object Management System<br />

l<br />

The Name Server, which manages the name space for the OMS, maintaining a<br />

correspondence between names and internal identifiers for <strong>ACE</strong>s, targets and so<br />

on. The name space allows objects that might be distributed among processors to<br />

address one another unambiguously.<br />

The OMS also defines some general global functions to coordinate interobject<br />

communication through crosscalls.<br />

You typically set up both the development and delivery environments to start the<br />

OMS automatically on boot, so that it is always running.<br />

Accessing the<br />

OMS<br />

In order to communicate with the OMS, an object or program must create a communications<br />

channel in the form <strong>of</strong> a separate process or thread called a communication<br />

access process, or CAP.<br />

l<br />

l<br />

When you create an <strong>ACE</strong>, the initialization procedure automatically creates the<br />

CAP, and the <strong>ACE</strong> runtime polls that CAP for crosscall events in its main loop.<br />

You can access the CAP with the function ix_ace_to_cap.<br />

If your application contains other programs that need to communicate with the<br />

OMS (a manager program, for example), each such object must register with the<br />

OMS as a task. The task, like an <strong>ACE</strong>, contains a CAP, which you can access with<br />

the function ix_task_to_cap. The task’s main loop must poll for crosscall events<br />

on the CAP channel.<br />

Before you can create an <strong>ACE</strong> or task, you must create a CAP with which to make the<br />

Resolver calls. To create a CAP, use the ASL function ix_cap_init. Any application<br />

that needs to communicate with the OMS must include the ASL core services library,<br />

as well as the OMS services library, even if it does not use any ASL functions other<br />

than ix_cap_init.<br />

Naming<br />

Objects<br />

The Name Server provides a name space, which allows objects that might be distributed<br />

among processors to address one another unambiguously. The Name Server<br />

supports a hierarchical UNIX-like directory structure. The name <strong>of</strong> a target (for<br />

example) needs to be unique only within an <strong>ACE</strong>, and the name <strong>of</strong> the <strong>ACE</strong> needs to<br />

be unique only within an application-defined directory.<br />

To completely and uniquely identify an entity to the Name Server, you must use the<br />

full name, or complete path to the entity. You use the full name whenever you refer to<br />

an object using the OMS services. For example, a call to ix_res_bind must specify<br />

the full name <strong>of</strong> both the target and the <strong>ACE</strong>.<br />

For example, to create a binding between the default target in an <strong>ACE</strong> named MyAce<br />

and an <strong>ACE</strong> named ControlAce, in an application with no other name space directories<br />

defined, use the following full names in the ix_res_bind method:<br />

ix_res_bind (ressession, "/MyAce/default" , "/ControlAce");<br />

For More<br />

Information<br />

l<br />

For more information on targets and bindings, see Chapter 5, “Controlling Packet<br />

Flow.”<br />

Revision 3.3, August 2001<br />

Elements <strong>of</strong> an Application 21


<strong>ACE</strong>s and Support Structures<br />

l<br />

l<br />

For more information on crosscalls, see Chapter 11, “Communication Within an<br />

Application.”<br />

For detailed reference information on OMS functions, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

<strong>ACE</strong>s and Support Structures<br />

The primary processing element on an <strong>IXA</strong> application is the <strong>ACE</strong>. An application<br />

can contain multiple <strong>ACE</strong>s to perform different processing operations, can start and<br />

stop <strong>ACE</strong>s at run time, and can change how packets flow from ports, through <strong>ACE</strong>s,<br />

and out <strong>of</strong> ports.<br />

The <strong>IXA</strong> <strong>SDK</strong> defines system <strong>ACE</strong>s to represent the physical network interfaces and<br />

the Linux TCP/IP stack, and library <strong>ACE</strong>s to perform typical network processing<br />

tasks. You define additional <strong>ACE</strong>s to process packets as needed by your application.<br />

Creating <strong>ACE</strong>s<br />

To define and create an <strong>ACE</strong>, you must first create the <strong>ACE</strong> single object executable.<br />

To do this:<br />

1. Define the <strong>ACE</strong>’s initialization phase in a C source file. This file must contain a<br />

definition for the initialization function ix_init. This function definition must, at<br />

least, allocate an <strong>ACE</strong> structure (ix_ace) and call ix_ace_init, which creates the<br />

<strong>ACE</strong> object. The function should also create and initialize any other structures<br />

that belong to the <strong>ACE</strong>, such as targets and sets. The file must also define a corresponding<br />

termination function (ix_fini) that cleans up the created structures.<br />

2. Define the <strong>ACE</strong>’s action phase in a C source file. The action code must contain<br />

definitions for the <strong>ACE</strong>’s action functions, which implement the handling and<br />

disposition <strong>of</strong> classified packets.<br />

3. Define the crosscall interfaces for interobject communication in an <strong>IXA</strong> IDL source<br />

file, compile it with the tao_idl compiler. This results in additional C source files<br />

for the <strong>ACE</strong>. See “Supporting Languages” on page 23.<br />

4. Define the <strong>ACE</strong>’s classification phase in an NCL source file. See “Supporting<br />

Languages” on page 23.<br />

5. Compile and link the initialization, action, and classification code into a single<br />

executable. (See Chapter 3, “Compiling and Testing Applications.”)<br />

An application’s manager program can create and initialize the application’s <strong>ACE</strong>s<br />

by calling Resolver functions in the OMS. To do this, it must first create a CAP<br />

channel through which to communicate with the Resolver. In the manager program:<br />

1. Create a CAP channel to the OMS using the ASL function ix_cap_init.<br />

2. Open a Resolver session by passing the CAP to the OMS function ix_res_open.<br />

3. Create the <strong>ACE</strong> using the function ix_res_create_ace, passing the Resolver<br />

session handle, the name <strong>of</strong> the <strong>ACE</strong>, and the path to the <strong>ACE</strong> executable in the<br />

development file system.<br />

You can also create <strong>ACE</strong>s from the command line or a script using the utility ixace.<br />

This utility creates a Resolver session and calls the ix_res_create_ace function.<br />

22 Elements <strong>of</strong> an Application<br />

Revision 3.3, August 2001


<strong>ACE</strong>s and Support Structures<br />

To create the <strong>ACE</strong>, the Resolver calls the initialization function you have defined in<br />

the <strong>ACE</strong> executable, and starts the <strong>ACE</strong>’s main loop, which polls continuously for<br />

packet arrival events and crosscall events.<br />

Support<br />

Objects<br />

The following table shows the C structures that can be part <strong>of</strong> an <strong>ACE</strong>.<br />

ASL structure<br />

Description<br />

ix_target<br />

ix_base_t<br />

ix_set<br />

ix_element<br />

ix_event<br />

ix_time<br />

Represents a packet destination target. You define targets<br />

in each <strong>ACE</strong> for all possible packet destinations. Each<br />

<strong>ACE</strong> is automatically initialized with one target, named<br />

default.<br />

l For more information, see Chapter 5, “Controlling<br />

Packet Flow.”<br />

Represents a crosscall interface. You must initialize each<br />

crosscall interface with this structure in both the server<br />

and the client before making any remote calls.<br />

l For more information, see Chapter 11, “Communication<br />

Within an Application.”<br />

Represents a data set, as defined in the <strong>ACE</strong>’s classification<br />

code.<br />

l For more information, see Chapter 13, “Using Sets <strong>of</strong><br />

Data to Classify Packets.”<br />

Represents a data set member element. You modify this<br />

structure to contain your application-specific data.<br />

l For more information, see Chapter 13, “Using Sets <strong>of</strong><br />

Data to Classify Packets.”<br />

Represents a schedulable event. You define a callback<br />

function to be executed when a specified time has<br />

elapsed.<br />

l For more information, see Chapter 10, “Initializing and<br />

Acting on Packets in an <strong>ACE</strong>.”<br />

Represents a time value for scheduling events.<br />

l For more information, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Additional<br />

Services<br />

Additional libraries extend the ASL to provide application services for TCP/IP<br />

packet manipulation. For more information, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Supporting<br />

Languages<br />

The <strong>IXA</strong> <strong>SDK</strong> includes two languages, Network Classification Language (NCL), and<br />

<strong>IXA</strong> Interface Definition Language (IDL), that you use to create some <strong>of</strong> the source<br />

code for an <strong>ACE</strong>.<br />

Elements <strong>of</strong> an Application 23<br />

Revision 3.3, August 2001


Micro<strong>ACE</strong> Support Services<br />

l<br />

l<br />

An <strong>ACE</strong> classifies incoming packets according to rules and protocol definitions<br />

that you write in NCL. For more information, see Chapter 9, “Classifying Packets<br />

Using NCL.”<br />

<strong>ACE</strong>s and other objects communicate using a remote procedure call mechanism<br />

called a crosscall. You define the interfaces for the crosscalls in <strong>IXA</strong> IDL. For more<br />

information, see Chapter 11, “Communication Within an Application.”<br />

Error Handling<br />

Most API functions return an error token, which is a value <strong>of</strong> type ix_error. An error<br />

token <strong>of</strong> zero indicates that the function was successful. When a call is unsuccessful,<br />

it returns a non-zero token that is associated with a descriptive string giving information<br />

about the failure.<br />

The ASL defines a set <strong>of</strong> functions for retrieving the messages associated with error<br />

tokens, and a set <strong>of</strong> macros that provide additional context information for errors. It<br />

also provides functions you can use to add your own uniquely numbered error codes<br />

to provide information about failed operations in your own functions.<br />

l<br />

l<br />

The error handling functions and macros are describe in Chapter 4, “The ASL<br />

Core Support Package API,” <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

The predefined error codes are listed and described in Appendix A, “<strong>IXA</strong> API<br />

Error Codes,” <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Micro<strong>ACE</strong> Support Services<br />

Conventional <strong>ACE</strong>s run on a general-purpose processor. To achieve higher performance,<br />

<strong>ACE</strong>s can use other special-purpose processors for acceleration. An <strong>ACE</strong> that<br />

<strong>of</strong>floads fast-path processing to an IXP1200 microengine is known as a micro<strong>ACE</strong>.<br />

A micro<strong>ACE</strong> combines a core component, a complete <strong>ACE</strong> that runs on the core<br />

processor, with a microblock.<br />

1. Write the microblock in microcode, the assembler language for the IXP1200<br />

microengines.<br />

2. Combine several microblocks with a dispatch loop, also in microcode, that defines<br />

a packet processing pipeline for a microblock group.<br />

3. Compile the microblocks and dispatch loop into a single-object image (a .u<strong>of</strong> file)<br />

that runs on a single microengine.<br />

To write and compile microcode, use the IXP1200 Microengine Development Environment.<br />

The IXP1200 microcode documentation is accessible from the following<br />

directory:<br />

C:IXP1200\documentation\IXP1200 Documentation<br />

Micro<strong>ACE</strong>s and their managing programs communicate with the microengines<br />

using the Resource Manager. The Resource Manager is system s<strong>of</strong>tware that runs in the<br />

core processor kernel. It does resource allocation for memory that is shared by the<br />

core processor and the microengines, and also handles packet demultiplexing and<br />

other system-level microengine management problems.<br />

24 Elements <strong>of</strong> an Application<br />

Revision 3.3, August 2001


The Application Building Process<br />

The Resource Manager defines a C-language API, which you can use in an <strong>ACE</strong><br />

management program or in <strong>ACE</strong> code to set up micro<strong>ACE</strong>s and manage the shared<br />

memory resources.<br />

The <strong>IXA</strong> <strong>SDK</strong> also defines a number <strong>of</strong> microcode macros that specifically support<br />

the micro<strong>ACE</strong> programming framework. Use these in the microblocks and the<br />

dispatch loop to define and access global variables in the shared memory, to manipulate<br />

packet buffers, and to pass packets between the microengine and the core<br />

processor.<br />

l<br />

For more information on micro<strong>ACE</strong>s and their supporting system s<strong>of</strong>tware, see<br />

Chapter 6, “Writing Micro<strong>ACE</strong>s.”<br />

The Application Building Process<br />

The following gives a rough picture <strong>of</strong> the process you use to define all <strong>of</strong> the parts<br />

<strong>of</strong> an <strong>IXA</strong> application, with references to places you can find more information on<br />

each piece.<br />

1. Define your services at a high level, and decide how to implement them with<br />

conventional <strong>ACE</strong>s, micro<strong>ACE</strong>s, and standard application programming.<br />

2. Sketch packet flow among the <strong>ACE</strong>s and decide what targets you will need and<br />

how to bind them.<br />

3. For the micro<strong>ACE</strong>s:<br />

a. Implement the microblocks for each micro<strong>ACE</strong> using the IXP1200<br />

Microengine Development Environment.<br />

b. Write a dispatch loop to implement the microcode packet pipeline for each<br />

microblock group.<br />

c. Create a microcode image for each microengine by compiling and linking the<br />

microblocks in each group (including those for the interface <strong>ACE</strong>s and library<br />

<strong>ACE</strong>s you are using) with the dispatch loop, using the IXP1200 Microengine<br />

Development Environment.<br />

For more information, see Chapter 6, “Writing Micro<strong>ACE</strong>s.”<br />

4. Implement the classification rules for each <strong>ACE</strong> in NCL.<br />

a. Define protocols and predicates. You can include the standard TCP/IP<br />

protocol, which is predefined and provided as part <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong>.<br />

b. Define data sets and searches. For more information, see Chapter 13, “Using<br />

Sets <strong>of</strong> Data to Classify Packets.”<br />

c. Define rules that call action functions. This will help you define the names and<br />

signatures <strong>of</strong> the action functions, which you will define later.<br />

For more information, see Chapter 9, “Classifying Packets Using NCL.”<br />

5. Implement action code for each <strong>ACE</strong> in C, defining the action functions called by<br />

the rules.<br />

For more information, see Chapter 10, “Initializing and Acting on Packets in an<br />

<strong>ACE</strong>.”<br />

Revision 3.3, August 2001<br />

Elements <strong>of</strong> an Application 25


The Application Building Process<br />

6. Define the crosscalls with which <strong>ACE</strong>s and the manager program will communicate:<br />

a. Define crosscall interfaces in <strong>IXA</strong> IDL.<br />

b. Compile the interface definitions with the <strong>IXA</strong> IDL compiler tao_idl. This<br />

produces a set <strong>of</strong> C headers and source files that define crosscalls and crosscall<br />

references.<br />

c. Edit the generated crosscall source to define the call methods.<br />

d. If needed, edit the generated callback sources to define callbacks for asynchronous<br />

calls.<br />

For more information, see Chapter 11, “Communication Within an Application.”<br />

7. Implement initialization code for each <strong>ACE</strong> in C.<br />

a. Define an initialization function to create the <strong>ACE</strong> and its related objects<br />

(targets, sets, and so on). See “Creating <strong>ACE</strong>s” on page 22.<br />

b. Define methods and utility functions.<br />

c. Include the crosscall headers as needed (depending on whether the <strong>ACE</strong> is<br />

acting as a call server or call client). Initialize each crosscall interface in both<br />

the server and the client. See Chapter 11, “Communication Within an Application.”<br />

8. Create the <strong>ACE</strong> executable for each <strong>ACE</strong>.<br />

a. Compile the NCL code using nclcomp, then gcc.<br />

b. Compile the action, initialization, and crosscall code using gcc.<br />

c. Link the rules object, action object, initialization object, and crosscall objects<br />

using ld.<br />

You typically use a makefile to do this. For more information, see Chapter 3,<br />

“Compiling and Testing Applications.”<br />

9. Modify the startup script’s configuration file, ixsys.config:<br />

a. Specify and configure the ports you are using.<br />

b. Create and start the micro<strong>ACE</strong>s, specifying a microcode image for each type<br />

<strong>of</strong> port.<br />

c. Create and start the conventional <strong>ACE</strong>s, passing in a pointer to the single<br />

object executable.<br />

d. Bind targets and <strong>ACE</strong>s to determine packet flow in the application.<br />

e. Run the configuration scripts for any library <strong>ACE</strong>s you are using.<br />

For more information, see Chapter 4, “Configuring and Starting <strong>IXA</strong> Systems.”<br />

10. Create a runtime, downloading the application and operating system to IXP1200<br />

flash. For the development system:<br />

a. Open a remote shell to the IXDP1200 Advanced Development Platform from<br />

the Linux development workstation.<br />

b. Mount the workstation’s NFS directory on the IXP200.<br />

26 Elements <strong>of</strong> an Application<br />

Revision 3.3, August 2001


The Application Building Process<br />

c. Copy all executables to the IXP1200’s NFS directory.<br />

11. Run the startup script, ixstart, from the command line <strong>of</strong> the remote shell.<br />

Elements <strong>of</strong> an Application 27<br />

Revision 3.3, August 2001


The Application Building Process<br />

28 Elements <strong>of</strong> an Application<br />

Revision 3.3, August 2001


Chapter 3<br />

Compiling and Testing Applications<br />

This chapter describes each <strong>of</strong> the compilation steps in detail to help you understand<br />

the compilation model for <strong>ACE</strong>s and <strong>IXA</strong> applications.<br />

This chapter contains the following topics:<br />

l “Overview <strong>of</strong> the <strong>ACE</strong> Compilation and Linking Process” on page 29<br />

l “Compiling Micro<strong>ACE</strong>s” on page 32<br />

l “Using Makefiles” on page 33<br />

l “Debugging an Application” on page 33<br />

Overview <strong>of</strong> the <strong>ACE</strong> Compilation and Linking Process<br />

To create an <strong>ACE</strong> single-object executable file, you compile and link several source<br />

files using the GNU tools, NCL compiler, and <strong>IXA</strong> IDL compiler. Source files include:<br />

l<br />

l<br />

l<br />

C/C++ files for initialization code and action functions<br />

NCL files for classification rules<br />

<strong>IXA</strong> IDL files for crosscall interfaces, which compile to additional C files for the<br />

crosscall source code<br />

Your application uses makefiles and scripts to ensure that all <strong>of</strong> an application’s files<br />

are compiled, linked, and loaded in the correct manner and order.<br />

A micro<strong>ACE</strong> has, in addition to these <strong>ACE</strong> source files that define the core component,<br />

a microcode source file that defines the microblock. See “Compiling<br />

Micro<strong>ACE</strong>s” on page 32.<br />

Intermediate<br />

Compilation<br />

A conventional <strong>ACE</strong> contains rules written in NCL. Compile the NCL file to an intermediate<br />

.s file using the NCL compiler, nclcomp. Compile the intermediate file to a<br />

.o linkable object with the GNU C/C++ compiler, gcc.<br />

Compiling and Testing Applications 29<br />

Revision 3.3, August 2001


Overview <strong>of</strong> the <strong>ACE</strong> Compilation and Linking Process<br />

The names <strong>of</strong> all cross-compilation utilities are prefixed with target platform information.<br />

For the StrongARM * core processor on the IXP1200, the prefix is armv4bunknown-linux-.<br />

For example, to create an executable for an <strong>ACE</strong> to run on the core<br />

processor, use the cross compiler armv4b-unknown-linux-gcc.<br />

When using crosscalls, you must provide crosscall interfaces written in <strong>IXA</strong> IDL.<br />

Compile .idl source files to .c and .h files using the IDL compiler, tao_idl. Include<br />

the header files as needed in the <strong>ACE</strong> initialization code source, depending on<br />

whether the <strong>ACE</strong> acts as a crosscall server or client. (See Chapter 11, “Communication<br />

Within an Application.”) Compile and link the crosscall source files into the <strong>ACE</strong><br />

executable, using gcc and ld.<br />

l<br />

l<br />

For a crosscall server, link in the crosscall source file.<br />

For a crosscall client, link in the stub (crosscall reference) source file, and, if there<br />

are deferred calls, the callback source file.<br />

Compiling and<br />

Linking Source<br />

Files<br />

A conventional <strong>ACE</strong> contains initialization code written in C/C++, which creates<br />

and initializes the <strong>ACE</strong> object and related structure, and action code written in C,<br />

which defines the action functions. Compile the source files for both these parts into<br />

.o linkable objects using the GNU C/C++ compiler, gcc.<br />

Finally, link the rules, action, and initialization objects into a single object <strong>ACE</strong><br />

executable file, using the GNU linker, ld. When you create the <strong>ACE</strong> (using either the<br />

Resolver ix_res_create_ace function in a management program or the ace<br />

keyword in a system configuration file), you specify the path to this executable. See<br />

Chapter 4, “Configuring and Starting <strong>IXA</strong> Systems.”<br />

The following figure shows the general flow <strong>of</strong> application files through the compilation<br />

process.<br />

30 Compiling and Testing Applications<br />

Revision 3.3, August 2001


Overview <strong>of</strong> the <strong>ACE</strong> Compilation and Linking Process<br />

Manager<br />

program<br />

C code<br />

mgr.c<br />

stub.c<br />

ASL<br />

gcc, ld<br />

mgr.o<br />

<strong>IXA</strong> IDL code<br />

ccif.idl<br />

tao_idl<br />

<strong>ACE</strong><br />

code<br />

NCL code<br />

rules.ncl<br />

C code<br />

actions.c<br />

init.c<br />

cc.c<br />

ASL<br />

nclcomp<br />

gcc<br />

rules.s<br />

rules.o<br />

actions.o<br />

init.o<br />

cc.o<br />

ld<br />

ace.o<br />

For more information on options available during compilation and linking, see:<br />

l Chapter 7, “Command-Line Tools,” in the <strong>IXA</strong> <strong>SDK</strong> Reference<br />

l Publicly available GNU C/C++ tool documentation<br />

Compiling<br />

Kernel <strong>ACE</strong>s<br />

During development, all conventional <strong>ACE</strong>s run in user space, so that you can test<br />

and debug them. When you deliver an application, however, you can choose to run<br />

a conventional <strong>ACE</strong> that is in the critical path in kernel space for maximum performance.<br />

If you intend to compile an <strong>ACE</strong> for the kernel, you must write it entirely in<br />

C, not C++.<br />

Although conventional <strong>ACE</strong>s generally do exception processing, while micro<strong>ACE</strong>s<br />

handle fast-path packet processing, some kinds <strong>of</strong> exception processing are more critical<br />

than others. For example, an <strong>ACE</strong> that processes new TCP sessions would need<br />

to be optimized for performance, while one that counts errors would not affect the<br />

overall efficiency <strong>of</strong> the application.<br />

Compiling and Testing Applications 31<br />

Revision 3.3, August 2001


Compiling Micro<strong>ACE</strong>s<br />

Compiling Micro<strong>ACE</strong>s<br />

A micro<strong>ACE</strong> contains a core component, for which you build a single-object<br />

executable in the same way as for a conventional <strong>ACE</strong>. In addition, each<br />

micro<strong>ACE</strong> contains a microblock. The source for the microblock can be:<br />

l<br />

l<br />

A microcode .uc file.<br />

A Micro C file compiled to microcode.<br />

You define a microblock group to run on each microengine and write a microcode<br />

dispatch loop to define the packet processing pipeline in the group. Use<br />

the IXP1200 Microengine Development Environment to compile and link all <strong>of</strong><br />

the microblocks in the group, together with the microcode file for the dispatch<br />

loop, into a microcode image (.u<strong>of</strong> file) for a single microengine.<br />

You must specify the microcode image to be used for each type <strong>of</strong> port, such as<br />

10/100BaseT Ethernet input or gigabit Ethernet output. To do this, you can<br />

modify the startup script’s configuration file (ixsys.config), or use the<br />

Resource Manager function RmUengSetUcode as part <strong>of</strong> your own <strong>ACE</strong> initialization<br />

and management program. You can run the same image on more than<br />

one microengine, or different images on each. The Resource Manager allocates<br />

the threads on the microengines.<br />

The type <strong>of</strong> a microcode image is determined as shown in the following table:<br />

Type<br />

Slow ingress<br />

Slow egress<br />

Fast ingress<br />

Fast egress<br />

Other<br />

Description<br />

The image contains the microblock for the input interface <strong>ACE</strong>, configured<br />

for 10/100BaseT ports.<br />

The image contains the microblock for the output interface <strong>ACE</strong>, configured<br />

for 10/100BaseT ports.<br />

The image contains the microblock for the input interface <strong>ACE</strong>, configured<br />

for gigabit ports.<br />

The image contains the microblock for the output interface <strong>ACE</strong>, configured<br />

for gigabit ports.<br />

The image does not contain an interface <strong>ACE</strong> microblock.<br />

l For more information on writing and starting micro<strong>ACE</strong>s, see Chapter 4,<br />

“Configuring and Starting <strong>IXA</strong> Systems,” and Chapter 6, “Writing<br />

Micro<strong>ACE</strong>s.”<br />

l<br />

For more information on creating and configuring interface <strong>ACE</strong>s, see<br />

Chapter 7, “Interface <strong>ACE</strong>s.”<br />

32 Compiling and Testing Applications<br />

Revision 3.3, August 2001


Using Makefiles<br />

l<br />

The microengine toolchain and the IXP1200 Microengine Development Environment<br />

are documented in the IXP1200 documentation set.<br />

Using Makefiles<br />

The UNIX make utility provides the most effective way to ensure that all <strong>of</strong> an application’s<br />

files are compiled and linked in the correct manner and order.<br />

You can issue compilation and linking commands directly from the command line in<br />

a command shell, but you typically use a makefile to compile and link your application.<br />

Makefiles are designed to handle dependencies in compilation order and variations<br />

in the names and locations <strong>of</strong> tools and source files.<br />

For information on compilation and linking options, see:<br />

l Chapter 7, “Command-Line Tools,” in the <strong>IXA</strong> <strong>SDK</strong> Reference<br />

l<br />

Publicly available GNU C/C++ tool documentation<br />

Debugging an Application<br />

Use the GNU debugger, gdb, to test and debug your <strong>IXA</strong> application. This debugging<br />

tool is provided as part <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> distribution.<br />

You can use GDB on your x86 Linux * host to remotely debug applications running on<br />

the IXDP1200 Advanced Development Platform. For example, to debug a file<br />

myfile.c:<br />

1. Compile myfile.c with the big-endian ARM * toolchain version <strong>of</strong> gcc with the -<br />

g option.<br />

2. Open a remote shell for the IXP1200 on the Linux host using Minicom, or on a<br />

Windows NT * host using Hyperterm.<br />

3. Transfer the binary for myfile into the RAMdisk <strong>of</strong> the IXP1200 using FTP or NFS.<br />

4. In a command shell for the IXP1200, type:<br />

gdbserver hostip_addr:port_number myfile arguments<br />

For example:<br />

gdbserver 10.3.19.128:12345 myfile<br />

5. On the host, go to the source directory for myfile, then start GDB on the file:<br />

cd /mydir<br />

gdb myfile<br />

NOTE:<br />

You can use the front-end GUI provided by Red Hat. To do this, invoke GDB<br />

with xxgdb myfile, rather than gdb myfile.<br />

Compiling and Testing Applications 33<br />

Revision 3.3, August 2001


Debugging an Application<br />

6. At the GDB prompt, connect to the IXP1200 target:<br />

target remote IXP1200_ipaddr:port_number<br />

7. At this point, the program is running and you can begin using the debugger.<br />

— Type list to see the code.<br />

— After setting a breakpoint, type continue (not run).<br />

For more information on how to use GDB, see publicly available GNU tool documentation.<br />

34 Compiling and Testing Applications<br />

Revision 3.3, August 2001


Chapter 4<br />

Configuring and Starting <strong>IXA</strong> Systems<br />

This chapter describes how to start an <strong>IXA</strong> system with a particular port configuration<br />

and launch the application’s system <strong>ACE</strong>s, library <strong>ACE</strong>s, and user <strong>ACE</strong>s.<br />

This chapter contains the following topics:<br />

l “Overview” on page 35<br />

l “Using Startup Scripts and Configuration Files” on page 36<br />

l “The System Configuration File” on page 37<br />

l “Setting Up Particular Configurations” on page 39<br />

l “Launching Application <strong>ACE</strong>s” on page 46<br />

Overview<br />

Typically, you start the system s<strong>of</strong>tware automatically as part <strong>of</strong> booting the<br />

IXDP1200 Advanced Development Platform. To do this, you call a startup script,<br />

which in turn calls other scripts. The scripts use configuration files, which you<br />

modify to configure your application’s port usage and to load, configure, and start<br />

the system, library, and user <strong>ACE</strong>s for your application.<br />

The default system initialization startup script (<strong>SDK</strong>installpath/bin/armbe/ixstart)<br />

loads the <strong>IXA</strong> <strong>SDK</strong> components and drivers and sets up the necessary<br />

Linux * device entries. It then runs the configuration utility ixconfig. This utility<br />

reads the system configuration file, <strong>SDK</strong>installpath/bin/arm-be/ixsys.config.<br />

l<br />

l<br />

You must modify the system configuration file to configure the ports and interface<br />

<strong>ACE</strong>s. The script starts the interface <strong>ACE</strong>s. See “Using Startup Scripts and Configuration<br />

Files” on page 36.<br />

You must specify any micro<strong>ACE</strong>s you want to start in the system configuration<br />

file, and specify where to find the compiled microcode images for your application.<br />

The script starts the microengines and the micro<strong>ACE</strong>s.<br />

Revision 3.3, August 2001<br />

Configuring and Starting <strong>IXA</strong> Systems 35


Using Startup Scripts and Configuration Files<br />

l<br />

l<br />

You can modify the system configuration file to run other startup scripts, such as<br />

those supplied for the library <strong>ACE</strong>s. See “Setting Up Particular Configurations”<br />

on page 39.<br />

You can modify the system configuration file to start user <strong>ACE</strong>s, either directly<br />

(using the ace keyword) or by running the ixsh utility. See “Launching Application<br />

<strong>ACE</strong>s” on page 46.<br />

For Additional<br />

Information<br />

l<br />

l<br />

l<br />

For information on the system and library <strong>ACE</strong>s, see Chapter 7, “Interface<br />

<strong>ACE</strong>s,” and Chapter 8, “Stack and Library <strong>ACE</strong>s.”<br />

For detailed reference information on the keywords and syntax <strong>of</strong> the configuration<br />

files, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Configuration files for sample applications that use various combinations <strong>of</strong><br />

library <strong>ACE</strong>s can be found in the following location:<br />

<strong>SDK</strong>installpath/src/microace/apps<br />

Using Startup Scripts and Configuration Files<br />

The <strong>IXA</strong> <strong>SDK</strong> provides sample scripts and configuration files that start and configure<br />

the interface <strong>ACE</strong>s and other library <strong>ACE</strong>s in typical configurations. These files are<br />

fully commented. To start a particular configuration <strong>of</strong> ports and <strong>ACE</strong>s, including<br />

interface <strong>ACE</strong>s and some set <strong>of</strong> library and user <strong>ACE</strong>s, you use the supplied startup<br />

scripts, modifying their configuration files for your application and configuration.<br />

The basic procedure for starting and exiting the <strong>IXA</strong> system is as follows:<br />

1. Determine the addresses for your network topology, and modify the system<br />

configuration file, ixsys.config, to set up the port configuration<br />

2. Create the necessary configuration files for the library <strong>ACE</strong>s you are using:<br />

— For the L2 bridging <strong>ACE</strong>, modify l2bridge.config.<br />

— For the L3 forwarder <strong>ACE</strong>, modify l3forwarder.config.<br />

— For the NAT <strong>ACE</strong>, modify nat.config.<br />

3. Add sh commands to the system configuration file, ixsys.config, to run the<br />

startup script for each included library <strong>ACE</strong>, specifying the <strong>ACE</strong> name and<br />

configuration file you have created for each one.<br />

4. After booting the IXDP1200 Advanced Development Platform, run the startup<br />

script in the command shell:<br />

$ ./ixstart<br />

5. To shut down the modules, run the termination script in the command shell:<br />

$ ./ixstop<br />

36 Configuring and Starting <strong>IXA</strong> Systems<br />

Revision 3.3, August 2001


The System Configuration File<br />

Starting and<br />

Initializing<br />

Interface <strong>ACE</strong>s<br />

When you invoke startup script at system boot it does the following:<br />

l<br />

l<br />

l<br />

l<br />

Activates the specified ports.<br />

Sets up and starts the input and output interface <strong>ACE</strong>s according to the specified<br />

configuration.<br />

Configures and enables the microengines using Resource Manager calls.<br />

Starts threads on the microengines for each port.<br />

Microengine<br />

Threads<br />

The configuration script associates each port to be used with one <strong>of</strong> the six IXP1200<br />

microengines. The script starts the appropriate threads on each microengine,<br />

according to the ports associated with it, so that enough threads are available for each<br />

port.<br />

l<br />

l<br />

l<br />

Each microengine has four threads.<br />

One gigabit port requires eight threads, so it takes two 2 input microblock groups<br />

to handle it.<br />

One 10/100BaseT port requires one thread, so a microengine can handle up to<br />

four such ports.<br />

For example, an 8/1 configuration could use two microengines for input on the<br />

gigabit port, and two for input on the 8 10/100BaseT ports. This leaves two microengines<br />

to handle output for all ports.<br />

The System Configuration File<br />

The system configuration file specifies the following information for use by the<br />

startup script:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Which ports to use, and their IP address information.<br />

The microcode image to be loaded on each microengine.<br />

The configuration for the input and output interface <strong>ACE</strong>s.<br />

Other micro<strong>ACE</strong>s to be started, including stack and library <strong>ACE</strong>s your application<br />

will use.<br />

Bind configurations for micro<strong>ACE</strong>s (both static and dynamic)<br />

Shell commands to run. Run the ixsh utility to create, run, and bind conventional<br />

<strong>ACE</strong>s, and run other configuration scripts.<br />

The following annotated system configuration file shows how to start and configure<br />

the network interfaces and <strong>ACE</strong>s. This example loads the L3 forwarder library <strong>ACE</strong>,<br />

stack <strong>ACE</strong>, and input and output <strong>ACE</strong>s. It sets up binding such that the forwarder<br />

receives packets directly from the input <strong>ACE</strong> and sends them directly to the stack<br />

<strong>ACE</strong> and the output <strong>ACE</strong>.<br />

Revision 3.3, August 2001<br />

Configuring and Starting <strong>IXA</strong> Systems 37


The System Configuration File<br />

Configuring<br />

Network<br />

Interfaces<br />

# ixsys.config<br />

# *********************************************************<br />

# Setup file for the ixconfig application that configures the<br />

# L3Fwdr library <strong>ACE</strong>, stack <strong>ACE</strong>, and interface <strong>ACE</strong>s<br />

# Specifies:<br />

# - Network interfaces to be started at system boot<br />

# - Micro<strong>ACE</strong>s to be started at system boot (interface, L3Fwdr)<br />

# - Conventional <strong>ACE</strong>s to be started at system boot (stackAce)<br />

# - Bind configuration<br />

# - Shell commands to be run<br />

# *********************************************************<br />

#<br />

# Specify interfaces<br />

interface 0 10.1.0.1 10.1.0.255 255.255.255.0 00:01:02:03:04:05 0<br />

interface 1 10.2.0.1 10.2.0.255 255.255.255.0 00:01:02:03:04:06 0<br />

interface 2 10.3.0.1 10.3.0.255 255.255.255.0 00:01:02:03:04:07 0<br />

interface 3 10.4.0.1 10.4.0.255 255.255.255.0 00:01:02:03:04:08 0<br />

interface 4 10.5.0.1 10.5.0.255 255.255.255.0 00:01:02:03:04:09 0<br />

interface 5 10.6.0.1 10.6.0.255 255.255.255.0 00:01:02:03:04:10 0<br />

interface 6 10.7.0.1 10.7.0.255 255.255.255.0 00:01:02:03:04:11 0<br />

interface 7 10.8.0.1 10.8.0.255 255.255.255.0 00:01:02:03:04:12 0<br />

interface 16 10.17.0.1 10.17.0.255 255.255.255.0 00:01:02:03:04:21 0<br />

NOTE:<br />

These lines tell the ixconfig script to run nine network interfaces. The first<br />

eight (0-7) are 10/100BaseT Ethernet ports, the last (16) is a gigabit Ethernet<br />

port. The ixconfig script uses this information to pass the appropriate<br />

configuration parameters when it creates the input and output micro<strong>ACE</strong>s.<br />

Identifying<br />

Microcode<br />

Images<br />

# **********************************************************<br />

# Specify the microcode image (.u<strong>of</strong>) files<br />

file 0 ./SlowIngressL3.u<strong>of</strong><br />

file 1 ./SlowEgressRR.u<strong>of</strong><br />

file 2 ./FastIngressL3-seq1.u<strong>of</strong><br />

file 3 ./FastIngressL3-seq2.u<strong>of</strong><br />

file 4 ./FastEgressFifo.u<strong>of</strong><br />

NOTE:<br />

These lines tell the ixconfig script which microcode image files to load.<br />

Each microcode image combines the microblocks for the input <strong>ACE</strong> and the<br />

L3Fwdr <strong>ACE</strong> with a dispatch loop.<br />

The <strong>IXA</strong> <strong>SDK</strong> also provides microcode image files that combine input, L2<br />

bridging, L3 forwarding, and NAT. The ixconfig script uses the Resource<br />

Manager library to load the code to the microengines.<br />

Starting and<br />

Configuring<br />

Aces<br />

# **************************************************************<br />

# Specify the micro<strong>ACE</strong>s<br />

microace ifaceInput ./ingressAce none 0 1<br />

microace ifaceOutput ./egressAce none 1 2<br />

microace L3Fwdr ./l3_forward_ace none 0 3 ifaceInput<br />

38 Configuring and Starting <strong>IXA</strong> Systems<br />

Revision 3.3, August 2001


Setting Up Particular Configurations<br />

NOTE:<br />

These lines tell the ixconfig script to launch three micro<strong>ACE</strong>s: the input,<br />

output, and L3Fwdr <strong>ACE</strong>s. The script uses the specified <strong>ACE</strong> single object<br />

file names to launch the core components <strong>of</strong> the micro<strong>ACE</strong>s. For example,<br />

l3_forward_ace is the <strong>ACE</strong> single object file name for the core component<br />

<strong>of</strong> the L3fwdr <strong>ACE</strong>. The ixconfig script uses OMS calls to create the new<br />

<strong>ACE</strong>s.<br />

# *************************************************************<br />

# Specify the conventional <strong>ACE</strong>s (such as stack <strong>ACE</strong>s)<br />

ace stackAce ./kstack none 3 ifaceInput<br />

NOTE:<br />

This line tells the ixconfig script to launch the stack <strong>ACE</strong>, using the<br />

specified <strong>ACE</strong> single object file name, kstack. The ixconfig script uses<br />

OMS calls to create the new <strong>ACE</strong>.<br />

# **************************************************************<br />

# Specify the bindings<br />

bind static ifaceInput/default L3Fwdr<br />

bind static L3Fwdr/out_if ifaceOutput<br />

bind regular L3Fwdr/out_if ifaceOutput<br />

bind regular L3Fwdr/stack stackAce<br />

bind regular stackAce/tx ifaceOutput<br />

NOTE:<br />

These lines tell the ixconfig script to bind the three micro<strong>ACE</strong>s statically as<br />

specified in the dispatch loop. They also creates dynamic bindings from the<br />

forwarder to the output <strong>ACE</strong> and stack <strong>ACE</strong>, and from the stack <strong>ACE</strong> to the<br />

output <strong>ACE</strong>. The ixconfig script uses OMS calls to create the bindings.<br />

# *************************************************************<br />

# Run the startup scripts for the stack <strong>ACE</strong><br />

# and L3 forwarding <strong>ACE</strong>.<br />

sh ./stackconfig ./ixsys.config<br />

sh ./l3config L3Fwdr ./ixsys.config ./route.config-sys-l3fwdr<br />

NOTE:<br />

These lines tell the ixconfig script to run the stackconfig utility to<br />

configure the stack <strong>ACE</strong> with the interface information, and to run the<br />

l3config utility to set up a simple route table. These utilities are in the same<br />

directory as ixsys.config. The l3config utility uses the forwarder’s configuration<br />

crosscalls to add a basic set <strong>of</strong> routes, as specified in the file<br />

route.config-sys-l3fwdr.<br />

Setting Up Particular Configurations<br />

This section shows how to set up the configuration files when using the library <strong>ACE</strong>s<br />

for specific tasks. It shows the following examples:<br />

l “Configuring an L2 Bridge” on page 40<br />

Revision 3.3, August 2001<br />

Configuring and Starting <strong>IXA</strong> Systems 39


Setting Up Particular Configurations<br />

l “Configuring an L3 Forwarder” on page 42<br />

l “Configuring an L3 Forwarder with NAT” on page 44<br />

NOTE:<br />

In these examples, all the commands are executed from a single directory<br />

containing all the executables and script files. If your files are in different<br />

locations, you must specify the paths relative to the execution directory.<br />

Configuring an<br />

L2 Bridge<br />

This example shows how to configure the IXDP1200 Advanced Development Platform<br />

to act as a layer 2 bridge for the fast Ethernet and gigabit Ethernet ports.<br />

System Configuration File<br />

The system configuration file sets up eight octal ports (ports 0-7) and 1 gigabit port<br />

(port 16).<br />

l<br />

l<br />

On LAN segments connected to ports 0 and 1, there are two fixed nodes that will<br />

not move to a new LAN segment, with MAC addresses 00:aa:bb:cc:dd:00 and<br />

00:aa:bb:cc:dd:01 respectively.<br />

On the segments connected to other ports, the MAC addresses <strong>of</strong> connected nodes<br />

are not known at startup.<br />

IXP1200 Evaluation Platform (L2 Bridge)<br />

0 1 2 3 4 5 6 7 16<br />

10.1.0.0/16<br />

10.4.0.0/16<br />

10.2.0.0/16<br />

10.6.0.0/16<br />

10.3.0.0/16<br />

10.7.0.0/16<br />

10.4.0.0/16<br />

10.8.0.0/16<br />

10.17.0.0/16<br />

This configuration file also starts and binds the L2 bridging library <strong>ACE</strong>, and tells the<br />

system startup script to run the L2 bridging configuration script.<br />

# ixsys.config<br />

# Configure ports<br />

interface 0 11.2.10.51 11.2.10.255 255.255.255.0 08:02:03:04:05:06 1<br />

interface 1 11.2.10.52 11.2.10.255 255.255.255.0 08:02:03:04:05:07 1<br />

interface 2 11.2.10.53 11.2.10.255 255.255.255.0 08:02:03:04:05:08 1<br />

interface 3 11.2.10.54 11.2.10.255 255.255.255.0 08:02:03:04:05:09 1<br />

interface 4 11.2.10.55 11.2.10.255 255.255.255.0 08:02:03:04:05:0A 1<br />

interface 5 11.2.10.56 11.2.10.255 255.255.255.0 08:02:03:04:05:0B 1<br />

interface 6 11.2.10.57 11.2.10.255 255.255.255.0 08:02:03:04:05:0C 1<br />

interface 7 11.2.10.58 11.2.10.255 255.255.255.0 08:02:03:04:05:0D 1<br />

interface 16 11.2.10.67 11.2.10.255 255.255.255.0 08:02:03:04:05:16<br />

1<br />

# This line is optional<br />

mode 0<br />

40 Configuring and Starting <strong>IXA</strong> Systems<br />

Revision 3.3, August 2001


Setting Up Particular Configurations<br />

# Specify the microcode image files<br />

file 0 ./SlowIngressL2L3NAT.u<strong>of</strong><br />

file 1 ./SlowEgressRR.u<strong>of</strong><br />

file 2 ./FastIngressL2L3NAT-seq1.u<strong>of</strong><br />

file 3 ./FastIngressL2L3NAT-seq2.u<strong>of</strong><br />

file 4 ./FastEgressFifo.u<strong>of</strong><br />

# Specify the micro<strong>ACE</strong>s<br />

microace ifaceInput ./ingressAce none 0 1<br />

microace ifaceOutput ./egressAce none 1 2<br />

microace L2Bridge ./l2bridge_ace none 0 4<br />

# Specify the bindings<br />

bind static ifaceInput/default L2Bridge<br />

bind static L2Bridge/out_if ifaceOutput<br />

bind regular L2Bridge/out_if ifaceOutput<br />

# Specify the shell command to run the L2 bridge startup script.<br />

sh ./l2config L2Bridge ixsys.config l2bridge.config<br />

L2 Bridging Configuration File<br />

The L2 bridging configuration file adds static forwarding entries to the routing table<br />

and sets up the corresponding port configuration for the L2 bridging <strong>ACE</strong>.<br />

# l2bridge.config<br />

# add forwarding entries<br />

add_fwd_static_entry 0 00:aa:bb:cc:dd:00<br />

add_fwd_static_entry 1 00:aa:bb:cc:dd:01<br />

# set port configuration<br />

set_port_state 0 5<br />

set_port_state 1 5<br />

set_port_state 2 5<br />

set_port_state 3 5<br />

set_port_state 4 5<br />

set_port_state 5 5<br />

set_port_state 6 5<br />

set_port_state 7 5<br />

set_port_state 16 5<br />

enable_port_bridging 0<br />

enable_port_bridging 1<br />

enable_port_bridging 2<br />

enable_port_bridging 3<br />

enable_port_bridging 4<br />

enable_port_bridging 5<br />

enable_port_bridging 6<br />

enable_port_bridging 7<br />

enable_port_bridging 16<br />

set_port_mtu 0 1518<br />

set_port_mtu 1 1518<br />

set_port_mtu 2 1518<br />

Configuring and Starting <strong>IXA</strong> Systems 41<br />

Revision 3.3, August 2001


Setting Up Particular Configurations<br />

set_port_mtu 3 1518<br />

set_port_mtu 4 1518<br />

set_port_mtu 5 1518<br />

set_port_mtu 6 1518<br />

set_port_mtu 7 1518<br />

set_port_mtu 16 1518<br />

Configuring an<br />

L3 Forwarder<br />

This example shows how to configure the IXDP1200 Advanced Development Platform<br />

to act as a layer 3 forwarder for an IP network. This simple example sets up<br />

static routes, populating the routing table using the L3 forwarder configuration<br />

script. The application would use the L3 forwarder’s crosscalls to manage the routing<br />

table at run time.<br />

System Configuration File<br />

This example configures eight octal ports (ports 0-7) and 1 gigabit port (port 16).<br />

l Each port is on a different LAN segment and each LAN segment is a different<br />

network, like an enterprise-wide router.<br />

l<br />

The default gateway is 192.10.11.12 and is on network 192.10.11.0, connected to<br />

port 1.<br />

IXP1200 Evaluation Platform (L3 Forwarder)<br />

0 1 2 3 4 5 6 7 16<br />

10.1.0.0/16<br />

192.10.11.0/24<br />

(Gateway)<br />

10.1.128/24<br />

10.1.192/24<br />

10.1.224/24<br />

10.3.0.0/24<br />

10.4.0.0/24<br />

Router<br />

10.5.0.0/24<br />

10.6.0.0/24<br />

10.7.0.0/24<br />

10.8.0.0/24<br />

10.17.0.0/24<br />

This configuration file also starts and binds the L3 forwarder library <strong>ACE</strong>, and tells<br />

the system startup script to run the L3 forwarder configuration script.<br />

# ixsys.config<br />

# Configure ports<br />

interface 0 10.1.0.1 10.1.0.255 255.255.255.0 00:01:02:03:04:05 0<br />

interface 1 192.10.11.1 192.10.11.255 255.255.255.0<br />

00:01:02:03:04:06 0<br />

interface 2 10.3.0.1 10.3.0.255 255.255.255.0 00:01:02:03:04:07 0<br />

interface 3 10.4.0.1 10.4.0.255 255.255.255.0 00:01:02:03:04:08 0<br />

interface 4 10.5.0.1 10.5.0.255 255.255.255.0 00:01:02:03:04:09 0<br />

interface 5 10.6.0.1 10.6.0.255 255.255.255.0 00:01:02:03:04:10 0<br />

interface 6 10.7.0.1 10.7.0.255 255.255.255.0 00:01:02:03:04:11 0<br />

interface 7 10.8.0.1 10.8.0.255 255.255.255.0 00:01:02:03:04:12 0<br />

42 Configuring and Starting <strong>IXA</strong> Systems<br />

Revision 3.3, August 2001


Setting Up Particular Configurations<br />

interface 16 10.17.0.1 10.17.0.255 255.255.255.0 00:01:02:03:04:20 0<br />

# Specify the microcode images<br />

file 0 ./SlowIngressL3.u<strong>of</strong><br />

file 1 ./SlowEgressRR.u<strong>of</strong><br />

file 2 ./FastIngressL3-seq1.u<strong>of</strong><br />

file 3 ./FastIngressL3-seq2.u<strong>of</strong><br />

file 4 ./FastEgressFifo.u<strong>of</strong><br />

# Specify the micro<strong>ACE</strong>s<br />

microace ifaceInput ./ingressAce none 0 1<br />

microace ifaceOutput ./egressAce none 1 2<br />

microace L3Fwdr ./l3_forward_ace none 0 3 ifaceInput<br />

# Specify the conventional <strong>ACE</strong>s - in this case, the stack <strong>ACE</strong><br />

ace stackAce ./kstack none 3 ifaceInput<br />

# Specify the bindings<br />

bind static ifaceInput/default L3Fwdr<br />

bind static L3Fwdr/out_if ifaceOutput<br />

bind regular L3Fwdr/out_if ifaceOutput<br />

bind regular L3Fwdr/stack stackAce<br />

bind regular stackAce/tx ifaceOutput<br />

# Run the startup scripts for stack <strong>ACE</strong> and L3Fwdr<br />

sh ./stackconfig ./ixsys.config<br />

sh ./l3config L3Fwdr ./ixsys.config ./route.config-sys-l3fwdr<br />

#end <strong>of</strong> ixsys.config<br />

L3 Forwarder Configuration File<br />

The L3 forwarder configuration file adds static routes to the forwarding table and sets<br />

up the default route and gateway.<br />

# l3forwarder.config<br />

# route information for the L3 forwarder<br />

routeadd 10.1.0.0 255.255.0.0 0.0.0.0 0<br />

routeadd 192.10.11.0 255.255.255.0 0.0.0.0 1<br />

routeadd 10.3.0.0 255.255.255.0 0.0.0.0 2<br />

routeadd 10.4.0.0 255.255.255.0 0.0.0.0 3<br />

routeadd 10.5.0.0 255.255.255.0 0.0.0.0 4<br />

routeadd 10.6.0.0 255.255.255.0 0.0.0.0 5<br />

routeadd 10.7.0.0 255.255.255.0 0.0.0.0 6<br />

routeadd 10.8.0.0 255.255.255.0 0.0.0.0 7<br />

routeadd 10.17.0.0 255.255.255.0 0.0.0.0 16<br />

#default route and gateway<br />

routeadd 192.10.11.5 255.255.255.0 0.0.0.0 1<br />

routeadd 0.0.0.0 0.0.0.0 192.10.11.5 1<br />

#end <strong>of</strong> configuration.<br />

Configuring and Starting <strong>IXA</strong> Systems 43<br />

Revision 3.3, August 2001


Setting Up Particular Configurations<br />

Configuring an<br />

L3 Forwarder<br />

with NAT<br />

This example shows how to configure the IXDP1200 Advanced Development Platform<br />

to act as a router with NAT functions, as would typically be used on the border<br />

between two or more networks.<br />

The example sets up the same network topology described in “Configuring an L3<br />

Forwarder” on page 42, adding NAT functionality<br />

l<br />

l<br />

The 192.10.11.0 network is the external network—that is, the IP addresses on this<br />

network are globally unique. The other networks are internal to the site.<br />

— The IP address <strong>of</strong> port 1 on the 192.10.11.0 network is 192.10.11.10.<br />

— The site uses the IP addresses from 192.10.11.50 through 192.10.11.60 as global<br />

unique IP addresses to be used by the internal nodes.<br />

The 10.1.0.0 network is subnetted into 10.1.128.0, 10.1.192.0, 10.1.224.0 networks.<br />

This example configures the NAT library <strong>ACE</strong> to enforce the following policies on the<br />

traffic between the external network and 10.1.0.0 network:<br />

l<br />

l<br />

l<br />

l<br />

Translate 10.1.0.10 to 192.10.11.50 and the reverse.<br />

Translate 10.1.0.11 to 192.10.11.51 and the reverse.<br />

Translate 10.1.0.12 to 192.10.11.52 and the reverse.<br />

For hosts from the 10.1.128.0 network, map to 192.10.11.53 address and the<br />

reverse.<br />

l For hosts from the 10.1.192.0 network, dynamically map to addresses 192.10.11.54<br />

through 192.10.11.58.<br />

l<br />

l<br />

For requests coming onto 192.10.11.10, TCP/UDP port 1000, load balance the<br />

requests, alternating between the nodes 10.1.30.5 and 10.1.30.6.<br />

Drop packets that are destined to IP addresses greater than 10.1.30.10 and less<br />

than 10.1.30.40.<br />

l Pass all packets originating from 10.5.0.0.<br />

System Configuration File<br />

This example configures eight octal ports (ports 0-7) and 1 gigabit port (port 16). It<br />

starts and binds the following <strong>ACE</strong>s, in addition to the interface <strong>ACE</strong>s:<br />

l<br />

l<br />

l<br />

l<br />

the L3 forwarder library <strong>ACE</strong><br />

the L2 bridging library <strong>ACE</strong><br />

the NAT library <strong>ACE</strong><br />

the stack <strong>ACE</strong>.<br />

The file then tells the system startup script to run the configuration scripts for all <strong>of</strong><br />

these <strong>ACE</strong>s.<br />

# ixsys.config<br />

# Configure ports<br />

interface 0 10.1.0.1 10.1.0.255 255.255.255.0 00:01:02:03:04:05 0<br />

interface 1 10.2.0.1 10.2.0.255 255.255.255.0 00:01:02:03:04:06 0<br />

44 Configuring and Starting <strong>IXA</strong> Systems<br />

Revision 3.3, August 2001


Setting Up Particular Configurations<br />

interface 2 10.3.0.1 10.3.0.255 255.255.255.0 00:01:02:03:04:07 0<br />

interface 3 10.4.0.1 10.4.0.255 255.255.255.0 00:01:02:03:04:08 0<br />

interface 4 10.5.0.1 10.5.0.255 255.255.255.0 00:01:02:03:04:09 0<br />

interface 5 10.6.0.1 10.6.0.255 255.255.255.0 00:01:02:03:04:10 0<br />

interface 6 10.7.0.1 10.7.0.255 255.255.255.0 00:01:02:03:04:11 0<br />

interface 7 10.8.0.1 10.8.0.255 255.255.255.0 00:01:02:03:04:12 0<br />

interface 15 10.16.0.1 10.16.0.255 255.255.255.0 00:01:02:03:04:20 0<br />

# Specify microcode images<br />

file 0 ./SlowIngressL2L3NAT.u<strong>of</strong><br />

file 1 ./SlowEgressRR.u<strong>of</strong><br />

file 2 ./FastIngressL2L3NAT-seq1.u<strong>of</strong><br />

file 3 ./FastIngressL2L3NAT-seq2.u<strong>of</strong><br />

file 4 ./FastEgressFifo.u<strong>of</strong><br />

# Specify the micro<strong>ACE</strong>s<br />

microace ifaceInput ./ingressAce none 0 1<br />

microace ifaceOutput ./egressAce none 1 2<br />

microace L3Fwdr ./l3_forward_ace none 0 3 ifaceInput<br />

microace nat ./Nat none 0 5 natc 3<br />

# Specify the convention <strong>ACE</strong>s: stack <strong>ACE</strong> and NAT <strong>ACE</strong><br />

ace stackAce ./kstack none 3 ifaceInput<br />

ace natc ./natctlr none 2 nat 1<br />

# Specify bindings<br />

bind static ifaceInput/default nat<br />

bind static L3Fwdr/out_if ifaceOutput<br />

bind static L2Bridge/default nat<br />

bind static nat/PASS<br />

L3Fwdr<br />

bind regular nat/CONFIG<br />

bind regular L3Fwdr/stack<br />

bind regular stackAce/tx<br />

bind regular natc/default<br />

natc<br />

stackAce<br />

ifaceOutput<br />

nat<br />

# Run startup scripts for stack <strong>ACE</strong>, L3Fwdr <strong>ACE</strong>, and NAT <strong>ACE</strong><br />

sh ./stackconfig ./ixsys.config<br />

sh ./l3config L3Fwdr ./ixsys.config ./route.config-sys-l3fwdr<br />

sh ./natconfig natc ./nat_l2l3nat.config<br />

#end <strong>of</strong> ixsys.config<br />

NAT Configuration File<br />

This example sets up the NAT configuration rules described above.<br />

# nat.config<br />

# create filter ACL<br />

acl_create 0 0<br />

# create NAT ACL<br />

Configuring and Starting <strong>IXA</strong> Systems 45<br />

Revision 3.3, August 2001


Launching Application <strong>ACE</strong>s<br />

acl_create 1 1<br />

#filter rules here<br />

filter 0 DROP IPDEST > 10.1.30.10, IPDEST < 10.1.30.40<br />

filter 0 PASS IPSRC = 10.5.*.*<br />

# nat action rules<br />

filter 0 NAT IPSRC > 10.1.0.9 , IPSRC < 10.1.0.13<br />

filter 0 NAT IPSRC = 10.2.*.*<br />

filter 0 NAT IPSRC = 10.3.*.*<br />

filter 0 NAT IPDST = 192.10.11.10 , DSTPORT = 1000<br />

# drop the rest <strong>of</strong> packets<br />

filter 0 DROP IPSRC=*.*.*.*<br />

# nat rules<br />

nat_static 1 IPSRC = 10.1.0.10 with 192.10.11.50<br />

nat_static 1 IPSRC = 10.1.0.11 with 192.10.11.51<br />

nat_static 1 IPSRC = 10.1.0.12 with 192.10.11.52<br />

nat_ip_masquerade 1 IPSRC = 10.1.128.* with 192.10.11.53<br />

nat_dynamic 1 IPSRC = 10.1.192.* with 192.10.11.54 4<br />

nat_virtual_server 1 IPDEST = 192.10.11.10, DESTPORT = 1000 with<br />

10.1.30.510.1.30.6<br />

#end <strong>of</strong> nat.config<br />

Launching Application <strong>ACE</strong>s<br />

During development, you might need to load and start application <strong>ACE</strong>s interactively.<br />

To run and test an application, you must load and run <strong>ACE</strong>s and create the<br />

bindings that control traffic flow. You can do this from the command line, in a script,<br />

or from a manager or launcher program. Similarly, you can stop <strong>ACE</strong>s and change<br />

binding in any <strong>of</strong> these ways.<br />

l<br />

l<br />

To launch and control the application <strong>ACE</strong>s from a script or the command line,<br />

use the ixsh utility provided in $IXROOT/bin/. This utility is described in<br />

Chapter 8, “Command-Line Tools,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

To launch and control an application <strong>ACE</strong> from a manager or launcher program,<br />

do the following:<br />

a. Open a CAP in its own thread, and use it to open a Resolver session.<br />

b. To start an <strong>ACE</strong>, call the function ix_res_create_ace, passing the Linux path<br />

to the <strong>ACE</strong> executable.<br />

c. To bind targets and <strong>ACE</strong>s, call the function ix_res_bind. Use ix_res_unbind<br />

to change the traffic flow.<br />

d. To halt an <strong>ACE</strong>, call the function ix_res_delete_ace.<br />

These functions and procedures are described in Chapter 2, “OMS Global<br />

Services API,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

46 Configuring and Starting <strong>IXA</strong> Systems<br />

Revision 3.3, August 2001


Chapter 5<br />

Controlling Packet Flow<br />

This chapter explains how packets flow into and out <strong>of</strong> an <strong>IXA</strong> application according<br />

to both the physical connections and the logical connections, known as bindings. It<br />

describes the physical network interfaces, the system and default targets to which<br />

you can direct packets, and how to create additional targets.<br />

This chapter contains the following topics:<br />

l “Defining Packet Flow” on page 47<br />

l “Binding Targets as Packet Destinations” on page 48<br />

l “Defining Additional Targets” on page 50<br />

l “Directing Packets to a Target” on page 51<br />

l “Using Targets for Packet Processing” on page 51<br />

l “Receiving and Transmitting on Network Interface Ports” on page 53<br />

Defining Packet Flow<br />

Physically, packets flow into an IXP1200 system through network interfaces (ports),<br />

and back out through the same or other ports. Logically, packets move through an<br />

<strong>IXA</strong> application from one <strong>ACE</strong> to another. <strong>ACE</strong>s are the s<strong>of</strong>tware entities that receive<br />

and dispose <strong>of</strong> packets.<br />

The system defines <strong>ACE</strong>s that communicate directly with the ports. These interface<br />

<strong>ACE</strong>s get packets from ports and send them to application <strong>ACE</strong>s, and receive packets<br />

from application <strong>ACE</strong>s to send out over ports. The application <strong>ACE</strong>s act on the<br />

packets while they are in the IXP1200 system.<br />

Typically several <strong>ACE</strong>s act on packets, at least to transport them to and from the<br />

ports. You determine the path that packets take through your application’s <strong>ACE</strong>s by<br />

binding the <strong>ACE</strong>s together in the order in which packets should encounter them.<br />

Revision 3.3, August 2001<br />

Controlling Packet Flow 47


Binding Targets as Packet Destinations<br />

Physical<br />

Packet Flow<br />

Each IXP1200 system has several physical network interfaces or ports. Depending on<br />

the board configuration, these can be connected directly to the network or to other<br />

packet sources and destinations, such as other IXP1200 boards. The quantity and type<br />

<strong>of</strong> ports also depends on the board configuration. For example, the IXDP1200<br />

Advanced Development Platform has sixteen fast Ethernet (10/100BaseT) ports and<br />

two gigabit Ethernet ports.<br />

Logical Packet<br />

Flow<br />

The <strong>ACE</strong> model <strong>of</strong> packet handling requires that packets be passed among <strong>ACE</strong>s in<br />

an <strong>IXA</strong> application. Therefore, each physical interface is represented in s<strong>of</strong>tware by a<br />

special-purpose system <strong>ACE</strong> called an interface <strong>ACE</strong>. (These are described in more<br />

detail in a later section, “Receiving and Transmitting on Network Interface Ports” on<br />

page 53.)<br />

The <strong>IXA</strong> <strong>SDK</strong> includes system-defined <strong>ACE</strong>s for each <strong>of</strong> the network interfaces in the<br />

IXDP1200 Advanced Development Platform, and for the Linux * TCP/IP stack. The<br />

quantity, types, and names <strong>of</strong> system <strong>ACE</strong>s depend on the physical configuration <strong>of</strong><br />

the IXP1200 system. Your customized system startup script loads and starts system<br />

<strong>ACE</strong>s for each <strong>of</strong> the ports your application uses.<br />

The interface <strong>ACE</strong>s act as s<strong>of</strong>tware packet sources and destinations for the application.<br />

Packets flow through an IXP1200 system from a port through an interface <strong>ACE</strong><br />

to one or more application <strong>ACE</strong>s, and out through an interface <strong>ACE</strong> to a port, as<br />

shown in the following figure:<br />

Input interface <strong>ACE</strong> Applications and modules Output interface <strong>ACE</strong><br />

Packet flow<br />

match: act on<br />

?<br />

not<br />

match<br />

?<br />

not<br />

Drop<br />

The connections between <strong>ACE</strong>s that determine how packets flow are called bindings.<br />

The API provides the tools for you to bind <strong>ACE</strong>s together. Packets flow through an<br />

IXP1200 system only after you have created bindings.<br />

Binding Targets as Packet Destinations<br />

In an <strong>ACE</strong>, packets flow in only one direction: through the <strong>ACE</strong> to a target within the<br />

<strong>ACE</strong>. A target provides a way to connect an <strong>ACE</strong> to a destination for packets. Each<br />

<strong>ACE</strong> can have multiple targets.<br />

The manager program for the application, which creates the <strong>ACE</strong>s, can also determine<br />

the packet flow by binding targets to other <strong>ACE</strong>s.<br />

l<br />

For a packet to flow into an <strong>ACE</strong>, the application must bind the target in the<br />

packet’s source <strong>ACE</strong> to that <strong>ACE</strong>.<br />

48 Controlling Packet Flow<br />

Revision 3.3, August 2001


Binding Targets as Packet Destinations<br />

l<br />

For a packet to flow out <strong>of</strong> an <strong>ACE</strong>, the application must:<br />

a. Create a target as part <strong>of</strong> the <strong>ACE</strong> (in the <strong>ACE</strong> initialization code).<br />

b. Bind the target to a destination <strong>ACE</strong>, using the function ix_res_bind in the<br />

manager program that creates the <strong>ACE</strong>, or using a command-line utility.<br />

c. Direct the packet to the target in an action function in the <strong>ACE</strong> action code.<br />

This means that every source that sends packets must be represented by an <strong>ACE</strong> that<br />

contains a target, and every destination must be represented by an <strong>ACE</strong>. A packet<br />

source or destination can be, for example, another <strong>ACE</strong> in the same application, an<br />

<strong>ACE</strong> in a different application, or a network interface or protocol stack, represented<br />

by a system <strong>ACE</strong>.<br />

<strong>ACE</strong> A<br />

Packet flow<br />

rule match: action<br />

no match: action<br />

Target 1<br />

Output interface <strong>ACE</strong><br />

Target 2<br />

Targets bound to interface <strong>ACE</strong><br />

Target bound to <strong>ACE</strong> B<br />

<strong>ACE</strong> B<br />

action<br />

Target 3<br />

Binding<br />

Targets and<br />

<strong>ACE</strong>s<br />

Targets are represented in your action code by ix_target structures. Each <strong>ACE</strong> is<br />

automatically initialized with the default target object named default. You can<br />

create additional targets; see “Defining Additional Targets” on page 50.<br />

All targets, including the predefined targets, are initially unbound. You must bind an<br />

<strong>ACE</strong>’s targets before packets can flow. In a simple application, you bind the default<br />

target to the next <strong>ACE</strong> in the normal flow <strong>of</strong> traffic.<br />

You bind application <strong>ACE</strong>s to system <strong>ACE</strong>s to provide packet sources and destinations<br />

for your application. For example, to pass packets out to the network, bind the<br />

system-defined default target <strong>of</strong> MyAce to the output interface <strong>ACE</strong>, as follows:<br />

ix_res_bind (res_session, "/MyAce/default", "/ifaceOutput");<br />

To receive packets from the network, bind the target <strong>of</strong> the input interface <strong>ACE</strong>. For<br />

example:<br />

ix_res_bind (res_session, "/ifaceInput/default", "/MyAce");<br />

NOTE:<br />

For details on the naming <strong>of</strong> <strong>ACE</strong>s, targets, and system <strong>ACE</strong>s, see the <strong>IXA</strong><br />

<strong>SDK</strong> Reference.<br />

In addition to the API function ix_res_bind, the <strong>IXA</strong> <strong>SDK</strong> provides utilities for<br />

binding that you can use from the command line or from a script.<br />

l<br />

The ixbind command binds a target to an <strong>ACE</strong> directly.<br />

Controlling Packet Flow 49<br />

Revision 3.3, August 2001


Defining Additional Targets<br />

l<br />

The ixsh utility has a bind command that you can use as part <strong>of</strong> a series <strong>of</strong> <strong>ACE</strong><br />

management commands.<br />

Typically, the startup script and configuration file determine the bindings for an<br />

application at startup. For details on these and other commands and utilities, see the<br />

<strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Unbound<br />

Targets<br />

Some applications, such as monitors and most intrusion detection systems, do not<br />

forward packets. An <strong>ACE</strong> performing such a task simply discards the packets.<br />

Directing a packet to a target without binding the target to a destination <strong>ACE</strong> causes<br />

packets to be dropped, as shown in the following figure.<br />

<strong>ACE</strong> A<br />

Packet flow<br />

rule match: action<br />

no match: action<br />

Target 1<br />

Output interface <strong>ACE</strong><br />

Target 2<br />

Targets bound to destinations<br />

<strong>ACE</strong> B<br />

rule match: action<br />

no match: action<br />

Target 3<br />

Target 4<br />

Unbound target<br />

Dropped<br />

If you leave a target unbound, then direct packets to it, those packets are dropped.<br />

However, you can drop packets more efficiently by not directing them to a target at<br />

all, while still returning RULE_DONE from the final action function. See “Directing<br />

Packets to a Target” on page 51.<br />

Defining Additional Targets<br />

The set <strong>of</strong> targets in an <strong>ACE</strong> represents the set <strong>of</strong> all possible packet destinations in<br />

that <strong>ACE</strong>, across all actions.<br />

l<br />

l<br />

In a simple case, an <strong>ACE</strong> passes most packets to the default target bound to an<br />

egress interface or to the next processing <strong>ACE</strong>, and defines another target to pass<br />

exception-case packets to a control-module <strong>ACE</strong> for exception processing.<br />

An <strong>ACE</strong> that performs a demultiplexing function, for example, might have<br />

multiple outgoing targets for different types <strong>of</strong> packets.<br />

To create additional targets within your application <strong>ACE</strong>s, you must do the<br />

following:<br />

1. In the ix_init function that creates the <strong>ACE</strong>, allocate an ix_target structure.<br />

2. Create the target using the ix_target_init function.<br />

ix_error ix_init (int argc, char **argv, ix_ace **acep)<br />

{<br />

50 Controlling Packet Flow<br />

Revision 3.3, August 2001


Directing Packets to a Target<br />

//allocate ace and target, pass to init fns<br />

ix_ace myace;<br />

ix_target mytarget;<br />

}<br />

ix_ace_init (myace, argv[1]);//<strong>ACE</strong> name passed in<br />

ix_target_init (mytarget, myace, "MyTarget");<br />

...<br />

Directing Packets to a Target<br />

Action functions in the <strong>ACE</strong> determine the path that a packet takes through an application<br />

by specifying whether the packet has completed processing and by directing<br />

the packet to a specific target.<br />

Packets are represented within action code by an ix_buffer object.<br />

An action function must:<br />

1. Use the function ix_target_take to direct the current packet buffer to the specified<br />

target, if processing is done.<br />

2. Return one <strong>of</strong> the following constant values to indicate whether rule processing<br />

should continue on this packet buffer:<br />

— RULE_DONE<br />

— RULE_CONT<br />

If all action functions specified by successful rules are executed and none <strong>of</strong> them<br />

returns RULE_DONE to indicate that it has disposed <strong>of</strong> the packet buffer, the buffer is<br />

passed to the <strong>ACE</strong>’s default target.<br />

For more information on writing action functions, see the following:<br />

l<br />

l<br />

Chapter 10, “Initializing and Acting on Packets in an <strong>ACE</strong>.”<br />

Chapter 3, “The ASL Core Primary Package API,” in the <strong>IXA</strong> <strong>SDK</strong> Reference<br />

Using Targets for Packet Processing<br />

An application can bind targets to several <strong>ACE</strong>s, possibly on different processors, in<br />

order to perform serial processing on packets, or to distribute packets to different<br />

routes.<br />

Serial Packet<br />

Flow<br />

The following figure illustrates a simple cascade <strong>of</strong> <strong>ACE</strong>s defined by their target<br />

bindings.<br />

Controlling Packet Flow 51<br />

Revision 3.3, August 2001


Using Targets for Packet Processing<br />

Input interface <strong>ACE</strong><br />

Target T1<br />

Bound target-to-<strong>ACE</strong><br />

flow<br />

Output interface <strong>ACE</strong><br />

Packet-to-target<br />

flow<br />

Forwarder <strong>ACE</strong><br />

In cache?<br />

Yes: forward<br />

No<br />

Target T3<br />

Target T2<br />

FwdControl <strong>ACE</strong><br />

Update data;<br />

forward<br />

Target T4<br />

In this example:<br />

l<br />

Target T1 is in the system <strong>ACE</strong> that represents an input network interface. T1 is<br />

bound to the Forwarder <strong>ACE</strong>. This directs all incoming traffic to the Forwarder<br />

<strong>ACE</strong>, which handles basic fast-path processing.<br />

l The Forwarder <strong>ACE</strong> contains two targets, T2 and T3. Most traffic is directed to T2,<br />

which is bound to the system <strong>ACE</strong> for the output network interface. Exception<br />

cases are directed to target T3, which is bound to another <strong>ACE</strong>, called FwdControl.<br />

l<br />

The FwdControl <strong>ACE</strong> processes the exception-case packets that it receives from<br />

the Forwarder <strong>ACE</strong>, then directs them to its own target, T4. T4 is also bound to<br />

the system <strong>ACE</strong> for the output network interface, so the exception-case packets<br />

are inserted back into the traffic flow.<br />

Packet Flow<br />

Redirection<br />

Because packets are passed to targets, rather than directly to other <strong>ACE</strong>s, you can<br />

easily insert another operation into your application by adding another <strong>ACE</strong> and<br />

rebinding the targets.<br />

For example, you could add a Firewall <strong>ACE</strong> to decide whether or not to allow<br />

packets through the output interface. The following figure illustrates how you can<br />

insert this <strong>ACE</strong> without having to change the logic or code <strong>of</strong> the existing <strong>ACE</strong>s,<br />

simply by rebinding the targets T2 (in Forwarder) and T4 (in FwdControl) to the<br />

Firewall <strong>ACE</strong>.<br />

52 Controlling Packet Flow<br />

Revision 3.3, August 2001


Receiving and Transmitting on Network Interface Ports<br />

Network interface <strong>ACE</strong><br />

Network interface <strong>ACE</strong><br />

Target T1<br />

Firewall <strong>ACE</strong><br />

Yes<br />

No<br />

Packet OK?<br />

Target T5<br />

Target T6<br />

Drop<br />

Packet-to-target<br />

flow<br />

Forwarder <strong>ACE</strong><br />

In cache?<br />

Yes: forward<br />

No<br />

Target T3<br />

Target T2<br />

Bound target-to-<strong>ACE</strong><br />

flow<br />

FwdControl <strong>ACE</strong><br />

Update data;<br />

forward<br />

Target T4<br />

In the example, the Firewall <strong>ACE</strong>’s target T5 is bound to the output network interface,<br />

allowing packets into traffic, and target T6 is unbound, allowing packets to be<br />

discarded.<br />

Receiving and Transmitting on Network Interface Ports<br />

In the s<strong>of</strong>tware, physical network interface ports are represented by a specialpurpose<br />

entity called an interface <strong>ACE</strong>. Interface <strong>ACE</strong>s are created and initialized at<br />

system startup, using a configuration script that you customize. You configure the<br />

startup scripts to load and start an input <strong>ACE</strong> and an output <strong>ACE</strong>, configuring them<br />

to receive and transmit on the ports you need, depending on both the physical configuration<br />

<strong>of</strong> the IXP1200 system and on how you plan to use it. For the IXDP1200<br />

Advanced Development Platform, the <strong>IXA</strong> <strong>SDK</strong> provides two types <strong>of</strong> ports, the fast<br />

Ethernet (10/100) ports and the gigabit Ethernet ports. The interface <strong>ACE</strong>s can<br />

handle both types <strong>of</strong> port.<br />

An interface <strong>ACE</strong> is a type <strong>of</strong> system <strong>ACE</strong>. A system <strong>ACE</strong>, unlike other <strong>ACE</strong>s, does<br />

not classify packets, but only transmits them. (The other type <strong>of</strong> system <strong>ACE</strong>, the stack<br />

<strong>ACE</strong>, represents a protocol stack.) However, it looks like an <strong>ACE</strong> to the OMS Name<br />

Server, which allows you to direct packets to and from the ports.<br />

System <strong>ACE</strong>s are implemented as micro<strong>ACE</strong>s—that is, they run partly on the<br />

IXP1200’s microengines, and partly on the core processor.<br />

l<br />

l<br />

The microengine pieces are called microblocks. The microblocks communicate<br />

directly with the hardware ports, assembling mpackets into packet buffers and<br />

disassembling them for transmission.<br />

The core component communicates with the microblocks, and with other <strong>ACE</strong>s.<br />

The input <strong>ACE</strong> exports a crosscall interface that other parts <strong>of</strong> your application<br />

can use to configure it. The output <strong>ACE</strong> does not require further configuration<br />

after installation.<br />

Revision 3.3, August 2001<br />

Controlling Packet Flow 53


Receiving and Transmitting on Network Interface Ports<br />

The input interface <strong>ACE</strong>, like all <strong>ACE</strong>s, has a default target. You must bind the default<br />

target to the micro<strong>ACE</strong> containing the next microblock in the group. This is a static<br />

binding; that is, you cannot change it at run time. It reflects the processing pipeline<br />

on the microengine, which is part <strong>of</strong> compiled code and cannot change at run time.<br />

You can create a static binding in either <strong>of</strong> the following ways:<br />

l<br />

l<br />

Programmatically, use the Resource Manager function RmBindMicroAce, rather<br />

than the Resolver function ix_res_bind.<br />

In the configuration file for the startup script, use the static flag for the bind utility.<br />

For example:<br />

bind static ifaceInput/default CountMicroAce2<br />

See Also<br />

l Chapter 6, “Writing Micro<strong>ACE</strong>s” on page 55<br />

l Chapter 8, “Stack and Library <strong>ACE</strong>s” on page 87<br />

l The <strong>IXA</strong> <strong>SDK</strong> Reference<br />

54 Controlling Packet Flow<br />

Revision 3.3, August 2001


Chapter 6<br />

Writing Micro<strong>ACE</strong>s<br />

This chapter provides information on the architecture and design <strong>of</strong> micro<strong>ACE</strong>s,<br />

which make use <strong>of</strong> the <strong>Intel</strong> ® IXP1200’s microengines for fast-path processing. It<br />

contains the following topics:<br />

l “Overview” on page 55<br />

l “Micro<strong>ACE</strong> Architectural Elements” on page 56<br />

l “Loading Micro<strong>ACE</strong>s” on page 58<br />

l “Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong>” on page 61<br />

l “Configuring Micro<strong>ACE</strong>s with Crosscalls” on page 68<br />

l “Microblock Types and Groups” on page 68<br />

l “Writing a Dispatch Loop” on page 71<br />

l “Writing a Microblock” on page 75<br />

l “Micro<strong>ACE</strong> Design Example” on page 77<br />

Overview<br />

The micro<strong>ACE</strong> programming model allows a packet-processing application to make<br />

use <strong>of</strong> the IXP1200’s microengines for acceleration <strong>of</strong> fast-path processing.<br />

Micro<strong>ACE</strong>s perform specific tasks such as IP forwarding, network address translation<br />

(NAT), and IP filtering.<br />

A micro<strong>ACE</strong> has two logical components, running on different processors:<br />

l<br />

A microblock contains fast-path packet processing logic which you write in microcode<br />

to run on a microengine. Microblocks can be one <strong>of</strong> three types:<br />

— Source microblocks receive packet buffers from outside the microengine.<br />

— Transform microblocks operate on packet buffers and pass them on to other<br />

microblocks.<br />

Writing Micro<strong>ACE</strong>s 55<br />

Revision 3.3, August 2001


Micro<strong>ACE</strong> Architectural Elements<br />

l<br />

— Sink microblocks send packet buffers out <strong>of</strong> the microengine.<br />

Each microblock is associated with a core component, which you write in C/C++<br />

and NCL to run on the core processor. The core component is a complete <strong>ACE</strong><br />

with additional elements that initialize and manage the microblock component.<br />

Interface <strong>ACE</strong>s are implemented as micro<strong>ACE</strong>s with source (Rx) and sink (Tx)<br />

microblocks. You use the interface micro<strong>ACE</strong>s to receive and transmit packets<br />

through the network interface ports.<br />

You typically combine micro<strong>ACE</strong>s with conventional <strong>ACE</strong>s in an application. You<br />

can combine the interface micro<strong>ACE</strong>s with micro<strong>ACE</strong> building blocks that are<br />

provided by <strong>Intel</strong>, that you write yourself, or that are provided by third parties. The<br />

<strong>IXA</strong> <strong>SDK</strong> provides source files for sample applications that use the system and library<br />

<strong>ACE</strong>s in various configurations, in the following location:<br />

<strong>SDK</strong>installpath/src/microace/apps<br />

To develop microcode and build microcode images, use the IXP1200 Microengine<br />

Development Environment. The source files for the micro<strong>ACE</strong>s and dispatch loop<br />

that form a microcode image are collected into a single project file with the extension<br />

.dwp. For information on using the microengine development tools and microcode<br />

reference information, see the IXP1200 documentation set.<br />

Micro<strong>ACE</strong> Architectural Elements<br />

A micro<strong>ACE</strong> combines a core component, which runs on the core processor, with a<br />

microblock, written in microcode to run on a microengine.<br />

l<br />

l<br />

l<br />

l<br />

l<br />

A management program loads and configures micro<strong>ACE</strong>s along with the conventional<br />

<strong>ACE</strong>s for an application.<br />

The management program initializes the micro<strong>ACE</strong> Resource Manager, which<br />

deals with resource allocation, packet demultiplexing, and other system-level<br />

microengine management problems.<br />

Several microblocks are typically combined into a single microengine image<br />

called a microblock group. Each <strong>of</strong> the microblocks in a group is associated with<br />

exactly one core component.<br />

A microcode dispatch loop for each microengine initializes the microblocks in a<br />

group and determines how packets flow into, among, and out <strong>of</strong> the microblocks.<br />

The management program creates static binding among the micro<strong>ACE</strong>s to match<br />

the packet flow among microblocks in each group, as determined by the dispatch<br />

loop. Together, the microblock group and their linked core components form a<br />

micro<strong>ACE</strong> group.<br />

56 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Micro<strong>ACE</strong> Architectural Elements<br />

Architecture<br />

Summary<br />

The following table provides a brief description <strong>of</strong> each element in the micro<strong>ACE</strong><br />

architecture. The remaining sections <strong>of</strong> this chapter go into more detail on each <strong>of</strong> the<br />

elements.<br />

Element<br />

Management program<br />

Resource Manager<br />

Core component<br />

Microblock<br />

Microblock group<br />

Description<br />

A part <strong>of</strong> your application written in C/C++ that starts the<br />

micro<strong>ACE</strong>s along with the conventional <strong>ACE</strong>s for an application,<br />

performing all necessary configuration. Either a management<br />

program or a startup script must initialize <strong>ACE</strong>s,<br />

load and start the microcode images on the microengines,<br />

and set up micro<strong>ACE</strong> bindings to match the way that the dispatch<br />

loop has configured the processing sequence in each<br />

microblock group.<br />

System s<strong>of</strong>tware that provides a set <strong>of</strong> resources for the <strong>ACE</strong><br />

and micro<strong>ACE</strong> management program to use in managing the<br />

microengine memory and shared state. Also provides the<br />

run-time component for handling exception processing.<br />

An <strong>ACE</strong>, written in C/C++ and NCL, that manages a microblock<br />

in addition to classifying and acting on packets.<br />

The <strong>ACE</strong> maintains shared state between itself and its associated<br />

microblock. It acts as a crosscall server and exports a<br />

crosscall interface for management <strong>of</strong> the microblock.<br />

The core component receives exception packets from its<br />

microblock, processes them, and sends them to the appropriate<br />

targets. The core component can also receive packets<br />

from other <strong>ACE</strong>s whose targets are bound to it and send them<br />

down to its microblock for processing.<br />

The core component <strong>of</strong> a micro<strong>ACE</strong> must always have one<br />

static target bound to the micro<strong>ACE</strong> containing the next<br />

microblock in the dispatch loop’s processing sequence.<br />

A microcode macro that provides the acceleration component<br />

<strong>of</strong> a micro<strong>ACE</strong>. Typically processes the most common cases<br />

<strong>of</strong> packet forwarding and passes exception case packets to<br />

the core component for further processing.<br />

A microblock can act as a packet source or sink, or it can<br />

transform packets.<br />

One or more microblocks that have been combined into a single<br />

microengine image.<br />

When you compile a microblock group, the microcode<br />

assembler produces an image file with the extension.u<strong>of</strong>.<br />

The management program loads this image onto a specific<br />

microengine during initialization.<br />

This allows several stages <strong>of</strong> processing to occur on a single<br />

microengine. Typically all threads on the microengine execute<br />

the same microblock group. You can load the same<br />

microblock group on more than one microengine.<br />

Writing Micro<strong>ACE</strong>s 57<br />

Revision 3.3, August 2001


Loading Micro<strong>ACE</strong>s<br />

Element<br />

Dispatch loop<br />

Description<br />

For each microblock group, you write a microcode dispatch<br />

loop to implement the packet flow within the group. The dispatch<br />

loop configures the microblocks in the group into a processing<br />

pipeline.<br />

The loop for each microblock group starts with a packet<br />

source microblock, ends with a packet sink, and can have one<br />

or more transform microblocks in between.<br />

Microcode image<br />

The compiled single object (.u<strong>of</strong> file) that contains the<br />

microblocks in a group and the dispatch loop that defines the<br />

processing pipeline.<br />

Loading Micro<strong>ACE</strong>s<br />

The management program for an application or a startup script must load and start<br />

the <strong>ACE</strong>s and set target bindings. In addition, to load and start micro<strong>ACE</strong>s (including<br />

the interface <strong>ACE</strong>s), the management program or script must do the following:<br />

1. Initialize the Resource Manager using the function RmInit. An application must<br />

do this once before making any other calls to the Resource Manager. The Resource<br />

Manager initializes the hardware.<br />

2. Configure the ports using the function RmSetPortConfig, passing information on<br />

which ports need to be enabled.<br />

You can examine the port configuration that the Resource Manager sets up using<br />

RmUengGetConfig. You can use RmUengSetConfig instead <strong>of</strong> RmSetPortConfig<br />

to configure each microengine individually, or to change the configuration.<br />

3. Use the function RmUengSetUcode to write each compiled microcode image to the<br />

Resource Manager before launching the micro<strong>ACE</strong>s. An image is a .u<strong>of</strong> file<br />

containing the microblock group and dispatch loop for one microengine.<br />

4. Launch the micro<strong>ACE</strong>s using the function RmCreateMicroAce. Like<br />

ix_res_create_ace, this function calls the <strong>ACE</strong>’s initialization function,<br />

ix_init. Each micro<strong>ACE</strong>’s initialization routine must:<br />

a. Register with the Resource Manager using the function RmRegister.<br />

a. Patch variables into the microcode image using the function RmUengPatch-<br />

Symbols.<br />

b. Create at least one target to be statically bound to the micro<strong>ACE</strong> containing the<br />

next microblock in the group.<br />

5. Bind static targets among the micro<strong>ACE</strong>s to match the dispatch loop’s processing<br />

pipeline, using the function RmBindMicroAce.<br />

6. Bind any conventional targets among the micro<strong>ACE</strong>s and other <strong>ACE</strong>s using the<br />

Resolver function ix_res_bind.<br />

7. After launching the micro<strong>ACE</strong>s, load the microcode images for each microengine<br />

using the function RmUengLoad.<br />

58 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Loading Micro<strong>ACE</strong>s<br />

8. Start the micro<strong>ACE</strong> code running on each microengine using the function RmUengEnable.<br />

9. Configure the micro<strong>ACE</strong>s using their startup scripts or crosscalls.<br />

For more information on startup scripts and configuration files, see Chapter 4,<br />

“Configuring and Starting <strong>IXA</strong> Systems.”<br />

For a complete description <strong>of</strong> the Resource Manager and Resolver API functions, see<br />

the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Setting Up a<br />

Processing<br />

Pipeline for<br />

Micro<strong>ACE</strong>s<br />

The microblocks in a single image (a microblock group) form a packet-processing<br />

pipeline on a microengine. Packets come in through the input media interfaces, are<br />

processed by a series <strong>of</strong> microblocks, and are sent out through the output media interfaces,<br />

or on to another microblock group on another microengine.<br />

The dispatch loop’s microcode defines the packet flow among the microblocks in a<br />

group. The packet flow is fixed when you compile the microblocks and dispatch loop<br />

to generate a .u<strong>of</strong> microcode image. You cannot change the packet flow at run time.<br />

After processing a packet, a microblock returns a value to the dispatch loop. The<br />

dispatch loop uses the returned value to determine the disposition <strong>of</strong> the current<br />

packet. The microblock can tell the loop to send packets to:<br />

l<br />

l<br />

l<br />

The next microblock in the group<br />

Its own core component on the core processor<br />

Another microblock group<br />

port<br />

microblock<br />

port<br />

microblock<br />

Packet flow<br />

microblock<br />

Microengine<br />

microblock<br />

microblock<br />

Microengine<br />

Writing Micro<strong>ACE</strong>s 59<br />

Revision 3.3, August 2001


Loading Micro<strong>ACE</strong>s<br />

Creating Static Bindings<br />

For each microblock group, the management program must bind targets in the core<br />

components to correspond to the microblock packet flow implemented by the<br />

dispatch loop. Unlike the bindings <strong>of</strong> conventional targets and <strong>ACE</strong>s, you cannot<br />

change these bindings at run time; they are static.<br />

Core processor<br />

Static Resource Manager bindings<br />

core component a<br />

core component b<br />

Resource Manager<br />

port<br />

Packet flow in dispatch loop<br />

microblock a<br />

microblock b<br />

Microengine<br />

port<br />

A special Resource Manager function, RMBindMicroAce, creates the static bindings.<br />

Like the Resolver function ix_res_bind, this function requires an open Resolver<br />

session. The system does not provide any special target for the static binding; you can<br />

create a target for this purpose, or you can use the default target. For example, if you<br />

create a target named static in micro<strong>ACE</strong> a as shown in the figure, create the static<br />

binding to micro<strong>ACE</strong> b in the ixsys.config system configuration file:<br />

bind static a/static b<br />

If you write your own startup management program, use the Resource Manager<br />

function:<br />

RMBindMicroAce (myResolverSession, "/a/static", "/b");<br />

You can create additional targets in the micro<strong>ACE</strong>, bind them to other conventional<br />

<strong>ACE</strong>s or micro<strong>ACE</strong>s, and send packets to those targets. Similarly, you can bind<br />

targets in other <strong>ACE</strong>s to the micro<strong>ACE</strong> so that it can receive packets from them.<br />

Example<br />

The following pseudocode example <strong>of</strong> an <strong>ACE</strong> management program loads<br />

micro<strong>ACE</strong>s as well as conventional <strong>ACE</strong>s for an application, and sets their bindings,<br />

using Resource Manager API calls.<br />

int main(int argc, char**argv)<br />

{<br />

// Initialize the Resource Manager<br />

RmInit(...);<br />

// Set the port configuration<br />

RmSetPortConfig(...);<br />

// Set the microcode image onto each microengine<br />

for (i = 0; i < MAX_NUM_UENG; i++)<br />

RmUengSetUcode(...);<br />

60 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

// Launch micro<strong>ACE</strong>S. This call is synchronous; by the time it<br />

// returns, the ix_init() <strong>of</strong> the micro<strong>ACE</strong> has been called. The //<br />

program assumes that all imported variables<br />

// were patched in by ix_init()<br />

for (i = 0; i < numberOfMicroaces; i++)<br />

RmCreateMicroAce(...);<br />

// Launch conventional <strong>ACE</strong>S<br />

for (i = 0; i < numberOfRegularAces; i++)<br />

ix_res_create_ace(...);<br />

// Configure the micro<strong>ACE</strong>s and <strong>ACE</strong>s with crosscalls<br />

Configure<strong>ACE</strong>s(...)<br />

// bind the micro<strong>ACE</strong>s together with static targets<br />

for (i = 0; i < numberOfStaticBinds; i++)<br />

RmBindMicroAce(...);<br />

// bind micro<strong>ACE</strong>s and other <strong>ACE</strong>s with regular targets<br />

for (i = 0; i < numberOfRegularBinds; i++)<br />

ix_res_bind(...);<br />

// Load the microcode<br />

RmUengLoad(...);<br />

// Enable the microengines<br />

RmUengEnable(...);<br />

// Loop forever<br />

while (1);<br />

}<br />

Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

The core component runs on the core processor, and performs the following functions<br />

for the micro<strong>ACE</strong>:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Exports <strong>IXA</strong> IDL interfaces to allow applications to configure the micro<strong>ACE</strong>.<br />

Allocates and sets up an SRAM control block to communicate with its associated<br />

microblock running on the microengines.<br />

Allocates and sets up tables and other data structures used by its associated<br />

microblock.<br />

Binds (patches) imported variables in the microcode to appropriate values during<br />

initialization.<br />

Receives exception packets from its associated microblock and processes them<br />

like a conventional <strong>ACE</strong>, using NCL and ASL.<br />

Handles packets received from other <strong>ACE</strong>s, sending them to its associated<br />

microblock on the microengines or to other targets.<br />

Like a conventional <strong>ACE</strong>, the C source code for the core component <strong>of</strong> a micro<strong>ACE</strong><br />

must define an initialization routine, ix_init, and a termination routine, ix_fini.<br />

See “Initializing a Micro<strong>ACE</strong>” on page 62 and “Terminating a Micro<strong>ACE</strong>” on<br />

page 64.<br />

Revision 3.3, August 2001<br />

Writing Micro<strong>ACE</strong>s 61


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

A micro<strong>ACE</strong> can contain conventional targets and the application can bind them to<br />

other <strong>ACE</strong>s or micro<strong>ACE</strong>s in order to pass packets to them. Similarly, an application<br />

can bind another <strong>ACE</strong>’s target to the micro<strong>ACE</strong> in order to send it packets. Like<br />

conventional <strong>ACE</strong>s, micro<strong>ACE</strong>s can use the default action function,<br />

ix_action_default, to handle packets by sending them to the default target.<br />

Exception<br />

Packet<br />

Handling<br />

The core component <strong>of</strong> a micro<strong>ACE</strong> handles exception packets that the microblock<br />

cannot process, using an application-defined exception handler.<br />

During the processing <strong>of</strong> a packet buffer, an exceptional condition might occur that<br />

requires additional processing. In this case, the microblock sends the buffer to its core<br />

processor core component by returning the special value IX_EXCEPTION to the<br />

dispatch loop. It passes an additional application-defined code along with the packet<br />

buffer to indicate what type <strong>of</strong> exception occurred.<br />

When the exception occurs, the dispatch loop places the buffer into a queue going to<br />

the core processor. All microblocks in a group share the queue. To identify the<br />

micro<strong>ACE</strong> that flagged the exception and will handle it, the dispatch loop uses the<br />

<strong>ACE</strong> tag, which is assigned by the RmRegister function when you initialize and start<br />

the micro<strong>ACE</strong>. The <strong>ACE</strong> tag has the form microblockName_TAG. After it has set the<br />

<strong>ACE</strong> tag, the dispatch loop can use the macro DL_SASink to send the packet up.<br />

The C source code for the core component <strong>of</strong> a micro<strong>ACE</strong> must define a handler<br />

routine for exception packets received from the associated microblock. See “Writing<br />

an Exception Packet Handler” on page 64.<br />

Initializing a<br />

Micro<strong>ACE</strong><br />

A management program launches a micro<strong>ACE</strong> using the Resource Manager function<br />

RmCreateMicroAce, which is similar to the Resolver function for creating conventional<br />

<strong>ACE</strong>s, ix_res_create_ace. Like the Resolver function, it requires an active<br />

Resolver session. See the <strong>IXA</strong> <strong>SDK</strong> Reference for details <strong>of</strong> these functions.<br />

Like conventional <strong>ACE</strong>s, the core component <strong>of</strong> a micro<strong>ACE</strong> must define an initialization<br />

routine, ix_init. When you launch the micro<strong>ACE</strong>, the creation function calls<br />

the ix_init function that is defined in the source code specified for the new<br />

micro<strong>ACE</strong>. The creation function passes down command-line arguments to ix_init.<br />

Micro<strong>ACE</strong>s must use the following convention for command-line arguments:<br />

Argument Description<br />

argv[0]<br />

Name <strong>of</strong> the executable.<br />

argv[1] Name <strong>of</strong> the <strong>ACE</strong>.<br />

argv[2]<br />

A bit mask indicating the microengines on which the microblock for this<br />

<strong>ACE</strong> runs. The 6 least significant bits <strong>of</strong> the microengine mask are used.<br />

The microengines are numbered 0-5.<br />

In addition to those things that it does for a conventional <strong>ACE</strong> (creating the ix_ace<br />

structure, calling ix_ace_init, creating related structures such as targets and sets,<br />

and initializing the <strong>ACE</strong> as a crosscall server and/or client), the ix_init initialization<br />

routine for a micro<strong>ACE</strong> must do the following:<br />

62 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

l<br />

l<br />

l<br />

Register the new micro<strong>ACE</strong> with the Resource Manager using the function<br />

RmRegister. This assigns the <strong>ACE</strong> tag that associates the microblock with the core<br />

component.<br />

Patch any imported variables for this micro<strong>ACE</strong> into the microblock, using the<br />

function RmUengPatchSymbols. After the micro<strong>ACE</strong> initialization routine returns,<br />

no more symbols can be patched. Symbols must be patched for all micro<strong>ACE</strong>s<br />

before the management program can load and start the microcode image.<br />

Use the Resource Manager to allocate memory in SRAM for the control block, and<br />

other shared memory (SRAM, SDRAM, or scratch) for any data structures to be<br />

shared with the microengines. See “Allocating Memory for Shared Data” on<br />

page 65.<br />

Initialization Example<br />

The following is a pseudocode example <strong>of</strong> a micro<strong>ACE</strong> initialization routine.<br />

ix_error ix_init (int argc, char** argv, ix_ace **acepp)<br />

{<br />

// Allocate <strong>ACE</strong> structure, get <strong>ACE</strong> name and initialize <strong>ACE</strong><br />

*acepp = malloc(...)<br />

name = argv[1]<br />

ix_ace_init(*acepp, name)<br />

// Initialize the Resource Manager<br />

RmInit(...)<br />

// Allocate SRAM for control block<br />

controlBlock = RmMalloc(...)<br />

// Allocate SRAM/SDRAM/SCRATCH for other data structures<br />

otherMemory = RmMalloc(...)<br />

// Set up these data structures<br />

SetupDataStructures(...)<br />

// Register an exception handler with the Resource Manager<br />

// and get a unique tag for the microblock. This tag can be used<br />

// to sendpackets to the microblock<br />

RmRegister(...)<br />

// Get the microengine mask for this <strong>ACE</strong><br />

meMask = atoi(argv[2])<br />

// For each microengine in the mask, patch variables<br />

// for this <strong>ACE</strong><br />

for (i = 0; i < numberOfImportedVariables; i++)<br />

RmUengpatchSymbol(...)<br />

// Other <strong>ACE</strong>-specific actions, such as creating targets<br />

return 0;<br />

}<br />

Writing Micro<strong>ACE</strong>s 63<br />

Revision 3.3, August 2001


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

Terminating a<br />

Micro<strong>ACE</strong><br />

Like conventional <strong>ACE</strong>s, the core component <strong>of</strong> a micro<strong>ACE</strong> must define an termination<br />

routine, ix_fini. When an application stops a micro<strong>ACE</strong>, the Resource Manager<br />

calls the ix_fini function defined in that <strong>ACE</strong>’s executable. See the <strong>IXA</strong> <strong>SDK</strong> Reference<br />

for details <strong>of</strong> the ix_fini function.<br />

In addition to those actions it takes for a conventional <strong>ACE</strong> (calling the ix_ace_fini<br />

function and freeing the memory allocated for the ix_ace structure), the ix_fini<br />

function for a micro<strong>ACE</strong> must do the following:<br />

l<br />

l<br />

Unregister from the Resource Manager<br />

Free all allocated Resource Manager memory<br />

Termination Example<br />

The following is a pseudocode example <strong>of</strong> a micro<strong>ACE</strong> termination routine:<br />

ix_error ix_fini (int argc, char**argv, ix_ace *acep)<br />

{<br />

// Unregister from the Resource Manager<br />

RmUnRegister(...)<br />

// Free all Resource Manager memory<br />

RmFree(...)<br />

// Terminate the path to the Resource Manager<br />

RmTerm(...)<br />

// Call the ix_ace_fini() function<br />

ix_ace_fini(...)<br />

// Free <strong>ACE</strong> structure and other memory allocated in ix_init<br />

free(...)<br />

}<br />

Writing an<br />

Exception<br />

Packet Handler<br />

The core component <strong>of</strong> a micro<strong>ACE</strong> typically defines a routine to handle exception<br />

packets received from the microblock.<br />

l<br />

l<br />

When you register the micro<strong>ACE</strong> during initialization using the Resource<br />

Manager function RmRegister, pass a pointer to the exception handler function,<br />

which you define in the C/C++ source code for the <strong>ACE</strong>.<br />

The Resource Manager calls the designated exception handler function once for<br />

every exception packet that the microblock identifies.<br />

Each exception packet the microblock sends up is associated with an exception code<br />

to indicate the reason for the exception. The exception handler must call the Resource<br />

Manager function RmGetExceptionCode to retrieve this exception code. Your application<br />

defines the exception codes and their meanings.<br />

The handler routine typically processes the packet and disposes <strong>of</strong> it. It can:<br />

l<br />

Send it back to the microblock for further processing using the Resource Manager<br />

function RmSend.<br />

64 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

l<br />

l<br />

l<br />

Send it to another <strong>ACE</strong> through a conventional target.<br />

Send it to another micro<strong>ACE</strong> through a static target; in this case, the packet is<br />

received by the core component <strong>of</strong> the micro<strong>ACE</strong>, which will send the packet<br />

buffer down to its associated microblock for processing. By convention, you do<br />

not send a packet buffer directly to the microblock <strong>of</strong> another micro<strong>ACE</strong>.<br />

Discard the packet and free the packet buffer.<br />

Exception Packet Handler Example<br />

The following is a pseudocode example <strong>of</strong> an exception handling routine:<br />

int ExceptionPacketHandler (void *ctxp,<br />

ix_ring ring,<br />

ix_buffer buffer)<br />

{<br />

ix_ace* acep = (ix_ace*) ctxp;<br />

// Get the exception code for this packet.<br />

RmGetExceptionCode(...)<br />

// Process the packet and either send it to a target,<br />

// drop it, or use RmSend to send it back to the microblock<br />

...<br />

return 0;<br />

}<br />

Allocating<br />

Memory for<br />

Shared Data<br />

The microengines and core processor share access to three types and areas <strong>of</strong><br />

memory:<br />

l<br />

l<br />

l<br />

uncached SDRAM<br />

SRAM<br />

cache memory (also called scratch memory)<br />

Some <strong>of</strong> the shared memory is used by the <strong>IXA</strong> system s<strong>of</strong>tware and operating<br />

system, but a portion <strong>of</strong> it is available to micro<strong>ACE</strong>s through the Resource Manager.<br />

ASL (16 Mb)<br />

Resource Manager<br />

(48 Mb)<br />

Shared memory for the IXP1200 Evaluation Platform<br />

Linux (64 Mb)<br />

SDRAM<br />

ASL (1 Mb)<br />

Resource Manager<br />

(3 Mb)<br />

SRAM<br />

Resource Manager<br />

(4 Kb)<br />

Scratch<br />

Writing Micro<strong>ACE</strong>s 65<br />

Revision 3.3, August 2001


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

While conventional <strong>ACE</strong>s define sets and searches to access application data, the<br />

microengines cannot access sets. If a micro<strong>ACE</strong> must store and access data, it must<br />

allocate a table in shared memory. The Resource Manager API provides a simple<br />

memory management mechanism, which you use for coarse-grained static allocation.<br />

Use the operating system to do fine-grained, dynamic memory management<br />

within the core component.<br />

Use the following Resource Manager API functions to manage memory for<br />

micro<strong>ACE</strong> data structures that the core component shares with the microblock:<br />

Function<br />

RmMalloc<br />

RmFree<br />

RmRead<br />

RmWrite<br />

RmGetPhysOffset<br />

RmGetBufferPtr<br />

RmGetMemInfo<br />

Description<br />

Allocates memory <strong>of</strong> a particular type (SDRAM, SRAM, or<br />

scratch) for the Resource Manager.<br />

Frees memory <strong>of</strong> a particular type in Resource Manager<br />

memory.<br />

Reads memory allocated by RmMalloc.<br />

Writes to memory allocated by RmMalloc.<br />

Retrieves the physical word <strong>of</strong>fset from start <strong>of</strong> memory for a<br />

segment allocated by RmMalloc.<br />

Retrieves the buffer pointer for memory allocated by the<br />

RmMalloc function.<br />

Retrieves the free-memory statistics.<br />

For details <strong>of</strong> how to use these functions, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Once the core component has set up and initialized data structures in shared memory,<br />

both the core component and microblock must define a mechanism for accessing the<br />

data. In the microblock, you can use the hardware hashing mechanism built into the<br />

IXP1200 network processor to hash into the data tables and reduce the search space.<br />

In order to duplicate these hash values in the core component, the ASL provides a set<br />

<strong>of</strong> hash functions that use the same hashing algorithm. For details <strong>of</strong> the ASL hash<br />

functions, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Shared<br />

Memory Table<br />

Example<br />

The following example shows both sides (microengine and core processor) <strong>of</strong> how<br />

you might allocate a table in shared memory and access it with hash values.<br />

Microcode Side: Hash Initialization and Table Implementation<br />

/* Setting up Hash Table */<br />

mul = MULT ;<br />

ECK(ix_hash64_init(&h64)) ;<br />

ECK(ix_hash64_set_mult(&h64, mul)) ;<br />

/* Microblock Table Implementation */<br />

#macro calculate_hash[key, ipsrc, ipdst, sport, dport, proto]<br />

.local $hash0 $hash1 $hash2 $hash3 $hash4 tmp<br />

.xfer_order $hash0 $hash1 $hash2 $hash3<br />

66 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing the Core Component <strong>of</strong> a Micro<strong>ACE</strong><br />

; Setup the hash unit<br />

;<br />

immed[$hash4, MULT]<br />

csr[write, $hash4, hash_multiplier_64_lo], ctx_swap<br />

; setup the hash keys<br />

move[$hash0, sport]<br />

ld_field[$hash0, 1100, proto, protocol, tuple->dest_port,<br />

tuple->dest_add ) ;<br />

combined_key = key1 ^ key2 ;<br />

Index = TABLE_MASK ;<br />

Index = combined_key & TABLE_MASK;<br />

return Index ;<br />

Writing Micro<strong>ACE</strong>s 67<br />

Revision 3.3, August 2001


Configuring Micro<strong>ACE</strong>s with Crosscalls<br />

}<br />

ix_64bit hash_64( ix_16bit protocol, ix_16bit port,<br />

ix_32bit address )<br />

{<br />

ix_64bit val, key ;<br />

val = 0 ;<br />

key = ((ix_64bit)address) | (((ix_64bit)port)


Microblock Types and Groups<br />

You write a microblock as a microcode macro. Each microblock makes use <strong>of</strong> the<br />

dispatch loop global variables and macros to pass packet buffers and information.<br />

See “Writing a Dispatch Loop” on page 71.<br />

Packet buffers generally flow into the microblock group from a network interface<br />

port. A core component can also send packets down to its own microblock—the<br />

dispatch loop handles packets that come from the core components, steering them to<br />

the appropriate microblock.<br />

A microblock can send packets to the core component <strong>of</strong> its micro<strong>ACE</strong>, or to other<br />

microblocks in the group by returning values to the dispatch loop. The dispatch loop<br />

acts on the return values to define the flow <strong>of</strong> packets within and out <strong>of</strong> the group.<br />

Microblock<br />

Types<br />

There are three types <strong>of</strong> microblocks:<br />

l<br />

l<br />

l<br />

Source microblocks get the packets to be processed by the rest <strong>of</strong> the pipeline.<br />

Examples <strong>of</strong> source microblocks include those that read data from network interface<br />

ports or those that schedule packets for transmission from a set <strong>of</strong> queues.<br />

Transform microblocks process a packet and pass it to the next microblock. Transform<br />

microblocks can modify the buffer data, gather statistics on the buffer<br />

contents, or steer the buffer between multiple code blocks.<br />

Sink microblocks dispose <strong>of</strong> packets within the microblock group. Disposal<br />

actions can include queuing packets to another microblock or to the core component<br />

for further processing or transmitting the packet on a network interface port.<br />

Source Microblocks<br />

Source microblocks are responsible for obtaining the next packet buffer to be<br />

processed. The first microblock to run in a microblock group is the source microblock.<br />

Implement each source microblock as a macro with the following format:<br />

source_block []<br />

The source microblock must do the following:<br />

1. Set the global variable dl_buffer_handle to a valid handle, or to<br />

IX_BUFFER_NULL if there is no buffer to process.<br />

2. Set the buffer length, buffer <strong>of</strong>fset, and the input port variables using the dispatch<br />

loop macros. See “Defining Additional Global Registers” on page 73.<br />

3. If desired, set the receive status flags and the IXP1200 fast port sequence number<br />

if the buffer was received from a fast port.<br />

The microblock <strong>of</strong> an input interface micro<strong>ACE</strong> is an example <strong>of</strong> a source microblock.<br />

This code removes mpackets (the internal unit <strong>of</strong> transfer) from the IX Bus and reassembles<br />

them into a packet buffer. If the current mpacket completes a frame, the code<br />

returns the pointer to the completed buffer. If the frame is not complete, it returns<br />

IX_BUFFER_NULL.<br />

An application-defined source microblock would get the next packet buffer from the<br />

queue where it was passed from another microblock group, and set the buffer handle<br />

to point to it. If no packet buffers are in the queue, it returns IX_BUFFER_NULL.<br />

Writing Micro<strong>ACE</strong>s 69<br />

Revision 3.3, August 2001


Microblock Types and Groups<br />

Transform Microblocks<br />

Transform microblocks perform basic packet operations. Some typical operations<br />

include IP forwarding, NAT, and filtering. The transform microblock operates on the<br />

packet buffer and returns an indication <strong>of</strong> how the packet buffer should be processed<br />

next. Any number <strong>of</strong> transform microblocks can run between the source and sink<br />

microblocks in a microblock group. Implement each transform microblock as a macro<br />

with the following format:<br />

transform_block []<br />

The transform microblock must do the following:<br />

1. Get the current packet buffer handle from the dispatch loop global variable<br />

dl_buffer_handle.<br />

2. Process the packet buffer.<br />

3. Set the value <strong>of</strong> the global variable dl_next_block to tell the dispatch loop where<br />

to send the packet buffer next.<br />

— For fast-path processing, set the variable to the number <strong>of</strong> the next microblock<br />

in the group. Your application defines the microblock numbers.<br />

— For exception cases, set the variable to IX_EXCEPTION to send the buffer to the<br />

transform microblock’s core component. You can pass an exception code with<br />

the packet using the dispatch loop macros.<br />

The microblocks <strong>of</strong> the library <strong>ACE</strong>s are examples <strong>of</strong> transform microblocks.<br />

Sink Microblocks<br />

Sink microblocks are responsible for disposing <strong>of</strong> packet buffers. The last microblock<br />

executed in a microblock group for a given packet buffer is a sink microblock. Implement<br />

each sink microblock as a macro with the following format:<br />

sink_block[]<br />

The sink microblock must do the following:<br />

1. Get the handle to the current packet buffer from the global dispatch loop variable<br />

dl_buffer_handle.<br />

2. If desired, use the dispatch loop macros to get the output port number for the<br />

buffer being processed.<br />

The microblock <strong>of</strong> an output interface micro<strong>ACE</strong> is an example <strong>of</strong> a sink microblock.<br />

This code disassembles a packet buffer into mpackets (the internal unit <strong>of</strong> transfer)<br />

for transmission through a network interface port.<br />

An application-defined sink microblock would queue the packet buffer for<br />

processing by another microblock group.<br />

Examples <strong>of</strong><br />

Microblocks<br />

Typical microblocks for micro<strong>ACE</strong>s can include the following:<br />

70 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing a Dispatch Loop<br />

Block Type Description<br />

Slow Ethernet<br />

Ingress<br />

Fast Ethernet<br />

Ingress<br />

source<br />

source<br />

Reads mpackets from the IX bus and reassembles<br />

them into a packet buffer. When it has a complete<br />

buffer, it returns the handle for further processing. It<br />

can perform link-level filtering as appropriate.<br />

This microblock is used by the input interface <strong>ACE</strong><br />

for this type <strong>of</strong> port.<br />

Similar to the Slow Ethernet Ingress, but handles<br />

the fast (gigabit) Ethernet ports.<br />

This microblock is used by the input interface <strong>ACE</strong><br />

for this type <strong>of</strong> port.<br />

IP Forward transform Performs the destination route lookup and the modifications<br />

needed for forwarding the buffer.<br />

Flow Processor transform Processes packets based on a set <strong>of</strong> tables, using<br />

the 5-tuple that identifies each TCP/UDP connection.<br />

Provides filtering and NAT.<br />

Sink Packet sink Queues packets to be processed by another<br />

microblock group.<br />

Slow Ethernet<br />

Transmit<br />

Fast Ethernet<br />

Transmit<br />

sink<br />

sink<br />

Transmits packet buffers out slow (10/100) Ethernet<br />

ports.<br />

This microblock is used by the output interface <strong>ACE</strong><br />

for this type <strong>of</strong> port.<br />

Transmits packet buffers out fast (gigabit) Ethernet<br />

ports.<br />

This microblock is used by the output interface <strong>ACE</strong><br />

for this type <strong>of</strong> port.<br />

Writing a Dispatch Loop<br />

The packet flow within a microblock group is defined by the microcode dispatch loop<br />

that you provide. You link the dispatch loop with the microblocks in the group to<br />

compile the microcode image (.u<strong>of</strong> file) for each microblock group.<br />

l<br />

l<br />

l<br />

The dispatch loop first initializes each microblock in the group, then handles<br />

packets that have been sent down from the core components on the core<br />

processor, passing them to the proper associated microblocks.<br />

The dispatch loop caches common variables in registers that the microblocks can<br />

access either directly or using a set <strong>of</strong> predefined helper macros.<br />

The main portion <strong>of</strong> the dispatch loop describes the packet flow among the<br />

micro<strong>ACE</strong>s that are part <strong>of</strong> the microblock group.<br />

Writing Micro<strong>ACE</strong>s 71<br />

Revision 3.3, August 2001


Writing a Dispatch Loop<br />

Microblocks in the group return values to the dispatch loop by setting the global variables.<br />

The dispatch loop acts on the return values to define the flow <strong>of</strong> packets within<br />

and out <strong>of</strong> the group.<br />

The dispatch loop can use system-defined macros to transfer packets to and from the<br />

core processor, to send packets to a different microblock group, to access global variables,<br />

and to manipulate packet buffers. The predefined macros are listed and<br />

described in Chapter 6, “Micro<strong>ACE</strong> Support Services,” <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Dispatch Loop<br />

Global<br />

Registers<br />

Each microblock directly sets and accesses the following global registers, which the<br />

dispatch loop can also access:<br />

Global Register<br />

Description<br />

dl_buffer_handle<br />

dl_next_block<br />

Stores a buffer handle for the current packet buffer.<br />

The source microblock at the top <strong>of</strong> the dispatch loop must<br />

set this register to a valid buffer handle or to<br />

IX_BUFFER_NULL.<br />

Stores the microblock return value.<br />

l To steer the packet buffer to the appropriate next transform<br />

microblock for processing, each transform microblock<br />

sets this register to the destination microblock’s<br />

application-defined number.<br />

l To send a packet buffer to the core component on the<br />

core processor, the transform microblock sets this register<br />

to IX_EXCEPTION.<br />

The dispatch loop caches commonly used variables such as thread ID, input and<br />

output port, and so on, in global registers. You must use a .local statement at the<br />

top <strong>of</strong> the dispatch loop to define the global registers for the buffer handle and return<br />

value, and any other registers that will be used by any microblock. For example:<br />

.local dl_buffer_handle dl_next_block dl_reg1 dl_reg2 dl_reg3<br />

The dispatch loop and microblocks can use a set <strong>of</strong> predefined helper macros to set<br />

and retrieve values from these registers, and to create and manipulate packet buffers.<br />

To use these, include the file:<br />

<strong>SDK</strong>installpath/src/microace/common/dispatchloops/<br />

DispatchLoop_h.uc<br />

The predefined macros are listed and described in detail in Chapter 6, “Micro<strong>ACE</strong><br />

Support Services,” <strong>of</strong> the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

72 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing a Dispatch Loop<br />

Defining Additional Global Registers<br />

Depending on register availability, a dispatch loop can define global registers for the<br />

use <strong>of</strong> a particular transform microblock, which are saved across iterations <strong>of</strong> the<br />

dispatch loop. The names <strong>of</strong> global registers that you define for a particular microblock<br />

must be prefixed with the name <strong>of</strong> that microblock, in the form<br />

blockName_regName—for example, wred_averageQueueSize.<br />

All other registers used by a microblock must be declared as .local within the<br />

microblock, as well as in the dispatch loop.<br />

Implementing<br />

Control Flow<br />

Each microblock sets the dl_next_block register, returning a numeric value that<br />

indicates which path a packet buffer should follow, or IX_EXCEPTION. (See<br />

“Returning Values to the Dispatch Loop” on page 75.) The dispatch loop checks the<br />

dl_next_block register and interprets the value. For example:<br />

IPFilter#:<br />

IPFilter[ ]<br />

.if (dl_next_block == 1)<br />

br[DL_MESink#]<br />

.else<br />

br[DL_Drop#]<br />

.endif<br />

The dispatch loop uses this mechanism to determine the sequence in which<br />

micro<strong>ACE</strong>s process packets. Because this sequence is compiled into the microcode<br />

image, it cannot be changed at run time. Your application must set up static target<br />

bindings for the micro<strong>ACE</strong>s to match the processing sequence in the dispatch loop.<br />

For more information, see Chapter 4, “Configuring and Starting <strong>IXA</strong> Systems,” and<br />

Chapter 5, “Controlling Packet Flow.”<br />

Dispatch Loop<br />

Example<br />

The following example shows a typical structure for a dispatch loop.<br />

The dispatch loop begins by declaring all the registers that will be used by the loop<br />

itself and by the microblocks for shared variables. The #include statements identify<br />

each microblock in the group.<br />

; declare global variables<br />

.local dl_buffer_handle dl_next_block dl_reg1 dl_reg2 dl_reg3<br />

; Include microblock source files<br />

#include "EthernetIngress.uc"<br />

#include "IPFilter.uc"<br />

#include "IPFwd.uc"<br />

The dispatch loop initializes each microblock in the group by calling the<br />

BlockName_Init[] macro.<br />

; Do initialization<br />

DL_Init[ ]<br />

EthernetIngress_Init[ ]<br />

IPFilter_Init[ ]<br />

IPFwd_Init[ ]<br />

Writing Micro<strong>ACE</strong>s 73<br />

Revision 3.3, August 2001


Writing a Dispatch Loop<br />

The first part <strong>of</strong> the dispatch loop dequeues packets coming from the core processor,<br />

passing them directly to the destination microblock.<br />

; Run the dispatch loop<br />

.while(1)<br />

; Consume packets from the SA.<br />

DL_SASource[ ]<br />

.if (dl_buffer_handle == IX_BUFFER_NULL)<br />

br[Main_Dispatch#]<br />

.elif (dl_next_block == IPFILTER_TAG)<br />

br[IPFilter#]<br />

.elif (dl_next_block == IPFWD_TAG)<br />

br[IPFwd#]<br />

.endif<br />

In this example, the dispatch loop has an Ethernet interface source microblock,<br />

followed by IPFilter and IPFwd transform microblocks. The microblocks return<br />

value by setting dl_next_block to indicate where to pass the packet next.<br />

; Main dispatch loop<br />

Main_Dispatch#:<br />

EthernetIngress[ ]<br />

.if (dl_buffer_handle == IX_BUFFER_NULL)<br />

.continue<br />

.endif<br />

.if (dl_next_block != 1)<br />

br[DL_Drop#]<br />

.else<br />

IPFilter#:<br />

IPFilter[ ]<br />

.if (dl_next_block == IX_EXCEPTION)<br />

.local ace_tag<br />

immed[ace_tag, IPFILTER_TAG]<br />

DL_SetAceTag[ace_tag]<br />

.endlocal<br />

br[DL_SASink#]<br />

.elif (dl_next_block == 1)<br />

IPFwd#:<br />

IPFwd[ ]<br />

.if (dl_next_block == IX_EXCEPTION)<br />

.local ace_tag<br />

immed[ace_tag, IPFWD_TAG]<br />

DL_SetAceTag[ace_tag]<br />

.endlocal<br />

br[DL_SASink#]<br />

.elif (dl_next_block == 1)<br />

br[DL_MESink#]<br />

.else<br />

br[DL_Drop#]<br />

.endif<br />

.else<br />

br[DL_Drop#]<br />

.endif<br />

.endif<br />

74 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Writing a Microblock<br />

DL_SASink#:<br />

DL_SASink[ ]<br />

.continue<br />

DL_MESink#:<br />

DL_MESink[ ]<br />

.continue<br />

DL_Drop#:<br />

DL_Drop[ ]<br />

.endw<br />

.endlocal<br />

Writing a Microblock<br />

A transform microblock performs whatever classification or processing is necessary<br />

on the current packet buffer, which it finds and stores in a global register. It then<br />

returns an application-defined value in another global register, that the dispatch loop<br />

uses to determine the further disposition <strong>of</strong> the packet buffer. Typically, it either<br />

transmits the packet or flags an exception so that the packet will be processed by the<br />

core component.<br />

Returning<br />

Values to the<br />

Dispatch Loop<br />

Each microblock can have one or more logical outputs, and returns a numeric value<br />

that indicates which path a packet buffer should follow. A microblock identifies the<br />

next destination microblock by setting dl_next_block to an application-defined<br />

number or to IX_EXCEPTION.<br />

l<br />

The return value IX_EXCEPTION is reserved to indicate that the buffer should be<br />

sent to the core component on the core processor for further processing.<br />

l By convention, each microblock numbers its other logical outputs starting at 1.<br />

When you write a microblock for reuse, you must document:<br />

— The number <strong>of</strong> logical outputs it has<br />

— The return values assigned to the outputs<br />

— The semantic meaning associated with the outputs<br />

Transmitting a<br />

Packet<br />

To transmit the current packet after processing, the microblock must do the<br />

following:<br />

1. Determine which network interface port to use for transmission, according to the<br />

application logic.<br />

2. Use the DL_SetOutputPort macro to set the port number in the packet.<br />

3. Set the global register dl_next_block to the application-defined code for transmission.<br />

For example, the following lines set up a fast-path packet for output on the first<br />

gigabit Ethernet port:<br />

Writing Micro<strong>ACE</strong>s 75<br />

Revision 3.3, August 2001


Writing a Microblock<br />

DL_SetOutputPort[16]<br />

immed[dl_next_block, 1]<br />

In this case, the dispatch loop must interpret the next-block value <strong>of</strong> 1 to mean that it<br />

should use the macro DL_MESink to transmit the packet. For example:<br />

.if (dl_next_block == 1)<br />

br[DL_MESink#]<br />

...<br />

DL_MESink#:<br />

DL_MESink[ ]<br />

.continue //return to top <strong>of</strong> dispatch loop<br />

The DL_MESink macro transfers the current packet to the microengine that is running<br />

a microcode image that contains an output interface <strong>ACE</strong> configured for the packet’s<br />

output port.<br />

Sending an<br />

Exception<br />

When an exception occurs, the transform microblock must do the following:<br />

1. Use the DL_SetExceptionCode macro to set the application-defined exception<br />

code<br />

2. Set the dl_next_block register to IX_EXCEPTION.<br />

The dispatch loop must do the following:<br />

1. Check for the next-block value <strong>of</strong> IX_EXCEPTION.<br />

2. Use the macro DL_SetAceTag to set the current <strong>ACE</strong> tag correctly for the microblock<br />

that flagged the exception.<br />

3. Use the macro DL_SASink to send the current packet buffer to the micro<strong>ACE</strong>’s<br />

core component (as identified by the <strong>ACE</strong> tag) for exception processing.<br />

The exception handler in the core component uses the Resource Manager function<br />

RmGetExceptionCode to retrieve the code set by the microblock.<br />

For example, the following lines from the L3 forwarder library <strong>ACE</strong>’s microblock set<br />

the exception code which that <strong>ACE</strong> defines for an ARP packet, then sets the exception<br />

flag in dl_next_block:<br />

immed32[exception_code, IPV4UNICASTFWD_EXCEPTION_ARP]<br />

DL_SetExceptionCode[exception_code]<br />

immed32[dl_next_block, IX_EXCEPTION]<br />

The following lines from a dispatch loop detect the exception state and send the<br />

exception packet to the core component <strong>of</strong> the L3Fwdr micro<strong>ACE</strong>:<br />

L3Fwdr#:<br />

L3Fwdr[ ] //sets exception code and flag<br />

.if (dl_next_block == IX_EXCEPTION)<br />

.local ace_tag<br />

immed[ace_tag, L3FWDR_TAG]<br />

DL_SetAceTag[ace_tag]<br />

.endlocal<br />

br[DL_SASink#]<br />

76 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Micro<strong>ACE</strong> Design Example<br />

.elif (dl_next_block == 1)<br />

DL_SASink#:<br />

DL_SASink[ ]<br />

.continue<br />

Micro<strong>ACE</strong> Design Example<br />

The following example shows how a layer 3 forwarding application uses micro<strong>ACE</strong>s.<br />

Core processor<br />

Stack <strong>ACE</strong><br />

Input IF <strong>ACE</strong><br />

configuration<br />

crosscalls<br />

L3Fwd<br />

<strong>ACE</strong><br />

Output IF <strong>ACE</strong><br />

Resource Manager<br />

port<br />

Input IF<br />

microblock<br />

exception<br />

packets<br />

L3Fwd<br />

microblock<br />

Output IF<br />

microblock<br />

port<br />

Packet flow<br />

Microengine<br />

This application, like most applications, uses the system-defined interface <strong>ACE</strong>s for<br />

input and output <strong>of</strong> packet buffers from and to the network interface ports. The interface<br />

<strong>ACE</strong>s are implemented as micro<strong>ACE</strong>s, with a core component and a microblock<br />

that communicate through the Resource Manager. Applications can configure the<br />

interface <strong>ACE</strong>s using their exported crosscalls.<br />

The application also makes use <strong>of</strong> the system-defined stack <strong>ACE</strong>, which passes<br />

packet buffers to and from the Linux * TCP/IP stack. The stack <strong>ACE</strong> is a conventional<br />

<strong>ACE</strong>.<br />

The application logic is in the L3Fwd micro<strong>ACE</strong>. The microblock component handles<br />

fast-path processing, forwarding packets based on a forwarding table. It sends exception<br />

packets (in this case, those with IP options in the header, fragmented packets,<br />

ARP and so on), to its core component.<br />

The Resource Manager, a piece <strong>of</strong> system s<strong>of</strong>tware running in the core processor<br />

kernel, passes configuration information and packet buffers between the core components<br />

<strong>of</strong> the micro<strong>ACE</strong>s and their associated microblocks.<br />

In addition to the <strong>ACE</strong>s and micro<strong>ACE</strong>s, the application includes:<br />

l A C management program that launches the micro<strong>ACE</strong>s and the stack <strong>ACE</strong>,<br />

binds them together, downloads microcode and enables the microengines.<br />

Writing Micro<strong>ACE</strong>s 77<br />

Revision 3.3, August 2001


Micro<strong>ACE</strong> Design Example<br />

l<br />

A microcode dispatch loop for each microengine that implements the data flow<br />

for that microengine and caches commonly used variables in registers. The<br />

dispatch loop sends and receives packets to and from the core processor and the<br />

other microengines.<br />

During application initialization, the management program binds the static<br />

micro<strong>ACE</strong> targets to reflect the flow <strong>of</strong> data in the dispatch loop. Once bound, they<br />

cannot be changed. The targets between the micro<strong>ACE</strong>s and the stack <strong>ACE</strong> are<br />

conventional targets and can be bound and unbound more than once.<br />

Packets flow through this application as follows:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

The microblock component <strong>of</strong> the input interface micro<strong>ACE</strong> gets a packet from a<br />

port. It sets the input port in a global register using a dispatch loop macro and<br />

passes all packets to the L3Fwd microblock.<br />

The L3Fwd microblock checks whether the packet is an IP packet, ARP packet, or<br />

some other type <strong>of</strong> packet. For every IP packet, the microblock validates the<br />

packet, dropping invalid packets.<br />

— If a packet is valid, but has options in the header, is fragmented, or is multicast<br />

it is considered an exception case and the microblock sends it to the L3Fwdr<br />

core component using the dispatch loop and the Resource Manager.<br />

— If a valid packet is not an exception case, the microblock finds the next-hop IP<br />

address and output port number in the forwarding table. It retrieves the destination<br />

MAC address <strong>of</strong> the next-hop IP and sets it for this packet. It then sets<br />

the output port number in a global register using a dispatch loop macro.<br />

The dispatch loop looks at the output port number in the global register and<br />

queues the valid, nonexception packet for output. There is one queue per port.<br />

The microblock for the output interface micro<strong>ACE</strong> dequeues the packet and sends<br />

it out over the appropriate port.<br />

For an exception packet, the L3Fwdr core component on the core processor<br />

processes the packet. It then takes one <strong>of</strong> the following actions:<br />

— Sends the packet to the output interface <strong>ACE</strong> using the conventional bound<br />

target. The core component <strong>of</strong> the interface <strong>ACE</strong> then sends the packet down<br />

to its own microblock using a Resource Manager call.<br />

— Sends the packet to the stack <strong>ACE</strong>, which processes the packet then sends it to<br />

the output interface <strong>ACE</strong>.<br />

— Sends the packet back down to its own microblock using the Resource<br />

Manager.<br />

78 Writing Micro<strong>ACE</strong>s<br />

Revision 3.3, August 2001


Chapter 7<br />

Interface <strong>ACE</strong>s<br />

This chapter describes the interface <strong>ACE</strong>s, system-defined micro<strong>ACE</strong>s that every<br />

application uses to receive and transmit packets for each network interface port. The<br />

chapter contains the following sections:<br />

l “Overview” on page 79<br />

l “Initializing Interface <strong>ACE</strong>s” on page 81<br />

l “The Input <strong>ACE</strong>” on page 83<br />

l “The Output <strong>ACE</strong>” on page 85<br />

Overview<br />

Interface <strong>ACE</strong>s are micro<strong>ACE</strong>s whose microblocks allows the microengines in the<br />

IXP1200 to communicate with the network interface ports. An IXP1200-based system<br />

must include the interface <strong>ACE</strong>s in order for the <strong>IXA</strong> application to receive and<br />

transmit traffic through any port. The interface <strong>ACE</strong>s can be configured to handle<br />

both 10/100BaseT Ethernet and gigabit Ethernet ports.<br />

The purpose <strong>of</strong> interface <strong>ACE</strong>s is to mask network interface details that are specific<br />

to particular hardware environments. These objects act as packet sources and destinations,<br />

and as drivers for the network interfaces. They are opaque to other <strong>ACE</strong>s.<br />

You can configure interface <strong>ACE</strong>s using their exported crosscall interfaces, but you<br />

cannot modify them.<br />

There are two types <strong>of</strong> interface <strong>ACE</strong>, input and output.<br />

l<br />

The input interface <strong>ACE</strong>, named by convention ifaceInput, is responsible for<br />

receiving packets from all <strong>of</strong> the physical ports. An input <strong>ACE</strong> contains a source<br />

microblock, which acts as a source <strong>of</strong> packet buffers for its microblock group. The<br />

input <strong>ACE</strong> passes received packets to the next microblock in the group.<br />

Revision 3.3, August 2001<br />

Interface <strong>ACE</strong>s 79


Overview<br />

l<br />

The output interface <strong>ACE</strong>, named by convention ifaceOutput, is responsible<br />

for transmitting packets on all <strong>of</strong> the physical ports. An output <strong>ACE</strong><br />

contains a sink microblock, which consumes packet buffers for the microblock<br />

group. The output <strong>ACE</strong> can receive packets from the previous microblock<br />

in its own group or another group, or from a conventional <strong>ACE</strong>.<br />

An application must include the microcode portions <strong>of</strong> these <strong>ACE</strong>s with any<br />

microcode <strong>of</strong> its own to create the microcode image that it downloads to each<br />

<strong>of</strong> the microengines as part <strong>of</strong> its initialization and startup procedure.<br />

l<br />

l<br />

To initialize an application, you run a startup script that loads, configures,<br />

and starts an input and output <strong>ACE</strong> for each port on which the application<br />

will receive and transmit packets.<br />

You combine the microblocks for the interface <strong>ACE</strong>s with any microblocks<br />

<strong>of</strong> your own to create the microcode image that you download to each <strong>of</strong> the<br />

microengines as part <strong>of</strong> the initialization and startup procedure.<br />

The core component <strong>of</strong> an interface <strong>ACE</strong> is written in C/C++. When your application<br />

creates an interface <strong>ACE</strong> during system initialization, the <strong>ACE</strong>’s initialization<br />

function instantiates the ingress or egress class and required helper<br />

classes. Depending on the IXP1200-based board configuration, the initialization<br />

procedure instantiates helper classes as needed for the proper types <strong>of</strong> network<br />

interface ports.<br />

Interface <strong>ACE</strong><br />

Crosscalls<br />

At runtime, an application can configure both physical and logical aspects <strong>of</strong> an<br />

input port using the crosscall interfaces exported by the input <strong>ACE</strong>. The input<br />

<strong>ACE</strong> exports two interfaces:<br />

l<br />

l<br />

The portMgmt interface defines operations that allow an application to<br />

control the physical configuration <strong>of</strong> a port. The physical properties <strong>of</strong> a port<br />

include such things as its port number, MAC address, and whether it is<br />

enabled.<br />

The logicalIfMgmt interface defines operations that allow an application<br />

to control the logical configuration <strong>of</strong> a port. An application can define<br />

multiple logical interface configurations for each port and treat each logical<br />

interface as a virtual port. This allows the application to associate multiple<br />

IP addresses with one physical port.<br />

Only the input <strong>ACE</strong> defines <strong>IXA</strong> IDL crosscall interfaces; it is not necessary to<br />

configure output <strong>ACE</strong>s after installation. To invoke these crosscalls, a program<br />

or <strong>ACE</strong> must connect to the server and initialize the client side <strong>of</strong> each interface<br />

before making any calls. The initialization routine <strong>of</strong> the input <strong>ACE</strong> initializes<br />

the server side <strong>of</strong> its crosscall interfaces.<br />

80 Interface <strong>ACE</strong>s<br />

Revision 3.3, August 2001


Initializing Interface <strong>ACE</strong>s<br />

A complete reference for the input <strong>ACE</strong> configuration crosscalls is provided in the<br />

<strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Source Code<br />

Location<br />

The source code for the interface <strong>ACE</strong>s, including the <strong>IXA</strong> IDL and generated stub<br />

files for the input <strong>ACE</strong> crosscalls, can be found in the following location:<br />

<strong>SDK</strong>installpath/src/microace/aces/interface_ace<br />

Initializing Interface <strong>ACE</strong>s<br />

When you initialize the IXP1200 system, using a management program or startup<br />

script, you specify which ports to use and provide the microcode images for each<br />

microengine. To use the interface <strong>ACE</strong>s, you must build their microblocks into at least<br />

one input and one output microcode image.<br />

After configuring the microengines, the management program or startup script starts<br />

and binds the interface <strong>ACE</strong>s, along with any other micro<strong>ACE</strong>s and conventional<br />

<strong>ACE</strong>s in the application.<br />

Creating a<br />

Microcode<br />

Image with an<br />

Interface <strong>ACE</strong><br />

Microblock<br />

Each microengine is configured for a microcode type, that determines whether it will<br />

perform input or output operations, and on which type <strong>of</strong> port. When you build a<br />

microcode image that includes the microblock for an input or output <strong>ACE</strong>, that<br />

microblock determines the type <strong>of</strong> the image. The type <strong>of</strong> a microcode image is determined<br />

as shown in the following table:<br />

Type<br />

Slow ingress<br />

Slow egress<br />

Fast ingress<br />

Fast egress<br />

Other<br />

Description<br />

The image contains the microblock for the input interface <strong>ACE</strong>, configured<br />

for 10/100BaseT ports.<br />

The image contains the microblock for the output interface <strong>ACE</strong>, configured<br />

for 10/100BaseT ports.<br />

The image contains the microblock for the input interface <strong>ACE</strong>, configured<br />

for gigabit ports.<br />

The image contains the microblock for the output interface <strong>ACE</strong>, configured<br />

for gigabit ports.<br />

The image does not contain an interface <strong>ACE</strong> microblock.<br />

When you specify the microcode images, either programmatically using the RmUeng-<br />

SetUcode function or in the system configuration file, using the file keyword, you<br />

specify the type. The Resource Manager than assigns each microcode image to a<br />

microengine with the correct type.<br />

Interface <strong>ACE</strong>s 81<br />

Revision 3.3, August 2001


Initializing Interface <strong>ACE</strong>s<br />

When you allow the Resource Manager to configure the microengines (by using the<br />

startup script or the Resource Manager function RmSetPortConfig), it sets the types<br />

automatically. You can see how the types are assigned using the Resource Manager<br />

function RmUengGetConfig. To specifically configure a microengine with a type, use<br />

the Resource Manager function RmUengSetConfig.<br />

Starting,<br />

Naming, and<br />

Binding<br />

Interface <strong>ACE</strong>s<br />

You can create, start, and bind interface <strong>ACE</strong>s programmatically, using Resource<br />

Manager functions in a management program, or you can use the startup scripts and<br />

system configuration file for the IXDP1200 Advanced Development Platform. See<br />

Chapter 4, “Configuring and Starting <strong>IXA</strong> Systems.”<br />

You can specify any <strong>ACE</strong> name for an interface <strong>ACE</strong>, but they are, by convention and<br />

by default, named ifaceInput and ifaceOutput. The interface <strong>ACE</strong>s reside at the<br />

root level <strong>of</strong> the Name Server’s name space. To refer to them and their targets, use<br />

names in the form:<br />

/ifaceInput/target_name<br />

Because it is a micro<strong>ACE</strong>, the input <strong>ACE</strong>’s default target must be statically bound<br />

to the micro<strong>ACE</strong> containing the next microblock in the processing pipeline. You can<br />

create a static binding in either <strong>of</strong> the following ways:<br />

l<br />

l<br />

Programmatically, use the Resource Manager function RmBindMicroAce, rather<br />

than the Resolver function ix_res_bind. For example:<br />

RmBindMicroAce ("/ifaceInput/default", "/MyAce");<br />

In the configuration file for the startup script, use the static flag for the bind<br />

statement. For example:<br />

bind static ifaceInput/default MyAce<br />

For example, suppose the application contains a micro<strong>ACE</strong> named MyAce, and the<br />

microcode puts the microblock for My<strong>ACE</strong> next in the processing pipeline after the<br />

input <strong>ACE</strong>. Use the following code to create the static bindings:<br />

RmBindMicroAce ("/MyAce/default"); "/ifaceOutput");<br />

RmBindMicroAce ("/ifaceInput/default", "/MyAce");<br />

An output <strong>ACE</strong> can receive packets from a previous microblock in the same group,<br />

from another microblock group, or from another <strong>ACE</strong>. Any <strong>ACE</strong> that needs to<br />

transmit packets must create a target for transmission and bind it to the output <strong>ACE</strong>.<br />

For example, suppose the core component <strong>of</strong> MyAce receives packets from another<br />

<strong>ACE</strong>, and defines a target, Tx, with which to transmit them. Use the following code<br />

to create a dynamic binding between the Tx target <strong>of</strong> MyAce and the output <strong>ACE</strong>:<br />

ix_res_bind ("/MyAce/Tx", "/ifaceOutput");<br />

To create this dynamic binding in the configuration file, use the bind statement as<br />

follows:<br />

bind dynamic MyAce/Tx ifaceOutput<br />

82 Interface <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The Input <strong>ACE</strong><br />

The Input <strong>ACE</strong><br />

The input <strong>ACE</strong> can be configured to receive packets from either the 10/100BaseT<br />

Ethernet or the gigabit Ethernet ports. The input <strong>ACE</strong> is implemented as a micro<strong>ACE</strong>.<br />

The core component is written in C++.<br />

The microblock handles packet flow by getting packets from the port, and passing<br />

them to the next microblock in its group. It never sends packets up to its core component.<br />

The input <strong>ACE</strong> does not define any targets other than the default target, which<br />

you must bind statically to the micro<strong>ACE</strong> containing the next microblock in the<br />

group. You do not normally bind the targets <strong>of</strong> other <strong>ACE</strong>s to the input <strong>ACE</strong>.<br />

The input <strong>ACE</strong> core component manages the physical and logical configurations for<br />

each port, and keeps statistics on traffic flow. It acts as a server for the exported<br />

configuration crosscalls.<br />

Configuring<br />

Interface <strong>ACE</strong>s<br />

Using<br />

Crosscalls<br />

Only the input <strong>ACE</strong> defines an <strong>IXA</strong> IDL crosscall interface, as it is not necessary to<br />

configure the output <strong>ACE</strong> after installation. Applications can invoke the input <strong>ACE</strong><br />

crosscalls to do the following:<br />

l<br />

l<br />

l<br />

l<br />

Set physical port properties such as MAC address<br />

Set logical interface properties such as a list <strong>of</strong> IP addresses<br />

Enable or disable a network interface port<br />

Retrieve various interface statistics such as the number <strong>of</strong> bytes sent or received<br />

The crosscalls operations are defined in two interfaces, the portMgmt interface and<br />

the logicalIfMgmt interface. The input <strong>ACE</strong> acts as a server for crosscalls and<br />

executes crosscalls on a per-port basis. The initialization routine <strong>of</strong> the input <strong>ACE</strong><br />

initializes the server side <strong>of</strong> both interfaces.<br />

To invoke these crosscalls, a program or <strong>ACE</strong> must initialize the client side <strong>of</strong> the<br />

interfaces before making any calls to the crosscall reference stub functions. A<br />

complete reference for the exported crosscalls is provided in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

When you generate the input <strong>ACE</strong> configuration crosscall C files from the provided<br />

interface definition file, ingress_ace.idl, the <strong>IXA</strong> IDL compiler produces the<br />

following files that you must link into the call client:<br />

Generated File<br />

ingress_ace_stub.c<br />

ingress_ace_stub.h<br />

ingress_ace_cb.c<br />

ingress_ace_cb.h<br />

Description<br />

Contains the stub functions for crosscall references<br />

and the client-side interface initialization and termination<br />

functions.<br />

Contains the templates for deferred operation callback<br />

functions, and the callback function vector table. Use<br />

the templates to implement handler functions for<br />

returned values, and modify the vector table to point to<br />

the function implementations.<br />

Interface <strong>ACE</strong>s 83<br />

Revision 3.3, August 2001


The Input <strong>ACE</strong><br />

Responding to<br />

Input <strong>ACE</strong><br />

Configuration<br />

Crosscalls<br />

Input <strong>ACE</strong> configuration crosscalls that retrieve values are defined as deferred operations.<br />

To handle the values that are returned asynchronously from these calls, the<br />

client program or <strong>ACE</strong> must define handler callback functions.<br />

For each deferred operation, the <strong>IXA</strong> IDL compiler generates a function template for<br />

the callback function in the ingress_ace_cb.c file. The crosscall client must implement<br />

a callback function based on the template. It must then modify the callback<br />

function vector table in the ingress_ace_cb.c file to point to the implementation<br />

rather than the template function.<br />

The following code fragment shows an example <strong>of</strong> how to change the callback function<br />

vectors.<br />

ix_base_t baseArray[0]; /* for IDL interface */<br />

ix_error err;<br />

ix_ace *pAce = (ix_ace *)pIng; /* our global variable */<br />

CC_VMT_portMgmt* pVmtPort = 0;<br />

err = sk_portMgmt_init (&baseArray[0],&pAce->cap[0]);<br />

if (err)<br />

IGA_ERROR_CHAIN(err, sk_portMgmt_init);<br />

err = getCCVMT_portMgmt(&baseArray[0], &pVmtPort);<br />

if (err)<br />

IGA_ERROR_CHAIN(err, getCCVMT_portMgmt);<br />

/* Fill in pointers to implementation <strong>of</strong> functions */<br />

pVmtPort->_pCC_portMgmt_portGetPorts = portGetPorts;<br />

pVmtPort->_pCC_portMgmt_portGetConfig = portGetConfig;<br />

pVmtPort->_pCC_portMgmt_portSetConfig = portSetConfig;<br />

pVmtPort->_pCC_portMgmt_portEnable = portEnable;<br />

pVmtPort->_pCC_portMgmt_portDisable = portDisable;<br />

pVmtPort->_pCC_portMgmt_portGetFlags = portGetFlags;<br />

pVmtPort->_pCC_portMgmt_portSetFlags = portSetFlags;<br />

pVmtPort->_pCC_portMgmt_portAddMacAddrFilter =<br />

portAddMacAddrFilter;<br />

pVmtPort->_pCC_portMgmt_portRemoveMacAddrFilter =<br />

portRemoveMacAddrFilter;<br />

pVmtPort->_pCC_portMgmt_portGetMacAddr = portGetMacAddr;<br />

pVmtPort->_pCC_portMgmt_portSetMacAddr = portSetMacAddr;<br />

pVmtPort->_pCC_portMgmt_portSetPromiscMode = portSetPromiscMode;<br />

pVmtPort->_pCC_portMgmt_portClearPromiscMode =<br />

portClearPromiscMode;<br />

pVmtPort->_pCC_portMgmt_portClearStats = portClearStats;<br />

pVmtPort->_pCC_portMgmt_portGetSnmpStats = portGetSnmpStats;<br />

DBG_MSG("ingressAceIdlInit : portMgmt init successful.\n");<br />

Managing<br />

Physical Ports<br />

The operations defined in the portMgmt interface manage the physical port configuration<br />

<strong>of</strong> an IXP 1200 system. An application can use these crosscalls to do the<br />

following:<br />

84 Interface <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The Output <strong>ACE</strong><br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Initialize and configure the 10/100BaseT ports under the 21440 Octal MAC, and<br />

gigabit ports under the IXF1004.<br />

Enable and disable ports for reception (Rx).<br />

Add and remove MAC addresses for address filtering on a port.<br />

Turn promiscuous mode on or <strong>of</strong>f for a port.<br />

Gather SNMP/RMON statistics for a port, and clear statistics.<br />

Store configuration information, including port type (slow or fast), MTU, MAC<br />

address, and port status flags, for retrieval by applications.<br />

Managing<br />

Logical Port<br />

Configuration<br />

The operations defined in the logicalIfMgmt interface manage the logical, or<br />

virtual, port configuration <strong>of</strong> an IXP 1200 system You can define multiple logical<br />

interfaces for a port. An application can use these crosscalls to do the following:<br />

l<br />

Create, maintain, and destroy logical interface properties for a port. Properties<br />

include:<br />

— IPv4 address<br />

— Mask<br />

— Interface number<br />

— Interface name<br />

— Status flags.<br />

l<br />

Store the logical interface information for retrieval by applications.<br />

The Output <strong>ACE</strong><br />

The output <strong>ACE</strong> can be configured to transmit packets on either the 10/100BaseT or<br />

the gigabit Ethernet ports in an IXP1200 system.<br />

The output <strong>ACE</strong> is a micro<strong>ACE</strong>, whose core component is implemented in C++. It<br />

manages the physical properties <strong>of</strong> a network interface port, and its own microblock.<br />

It does not manage the logical interface properties. The output <strong>ACE</strong> does not require<br />

run-time configuration, and does not export any crosscalls.<br />

Other <strong>ACE</strong>s can bind targets to an output <strong>ACE</strong> and send packets to it. The output<br />

<strong>ACE</strong> relays these packets to the microcode block for transmission.<br />

To manage the physical port properties, the output <strong>ACE</strong> defines an internal method<br />

API to do the following:<br />

l<br />

l<br />

Initialize and configure the 10/100BaseT ports under the 21440 Octal Mac, and<br />

fast ports under the IXF1004.<br />

Enable ports for transmission.<br />

The output <strong>ACE</strong> is always paired with a corresponding microcode block for an input<br />

<strong>ACE</strong> that receives packets on the same port, although the input microcode block need<br />

not be in the same group.<br />

Interface <strong>ACE</strong>s 85<br />

Revision 3.3, August 2001


The Output <strong>ACE</strong><br />

Sample Output<br />

Configurations<br />

There are many possible combinations <strong>of</strong> modes, starting ports, and starting FIFOs<br />

for the output microblocks. This section outlines some <strong>of</strong> the possible configurations<br />

that would work best on an IXP1200 Evaluation Platform, and provides some sample<br />

setup code for them.<br />

The following table lists some suggested configurations <strong>of</strong> one or more output<br />

microblocks for particular setups.<br />

Supported<br />

Ports<br />

Output<br />

Microblock<br />

Mode Start Port Start FIFO<br />

8 100Mb SlowEgress 16 TFIFO entry 0 0<br />

8 100 Mb 1<br />

1Gb<br />

SlowEgress 8 TFIFO entry 0 0<br />

FastEgress 8 TFIFO entry 8 1<br />

2 1Gb FastEgress 8 TFIFO entry 8 0<br />

FastEgress 8 TFIFO entry 9 1<br />

16 100 Mb SlowEgress 8 TFIFO entry 0 0<br />

SlowEgress 8 TFIFO entry 8 1<br />

86 Interface <strong>ACE</strong>s<br />

Revision 3.3, August 2001


Chapter 8<br />

Stack and Library <strong>ACE</strong>s<br />

This chapter describes system-defined <strong>ACE</strong>s provided with the <strong>SDK</strong> for specific<br />

purposes, such as communicating with the operating system’s TCP/IP stack and<br />

performing layer-three unicast packet forwarding. The chapter contains the<br />

following sections:<br />

l “Overview” on page 87<br />

l “The Stack <strong>ACE</strong>” on page 88<br />

l “The L3 Forwarder Library <strong>ACE</strong>” on page 89<br />

l “The L2 Bridging Library <strong>ACE</strong>” on page 91<br />

l “The NAT Library <strong>ACE</strong>s” on page 94<br />

Overview<br />

The <strong>IXA</strong> <strong>SDK</strong> provides the stack <strong>ACE</strong> to represent the Linux * TCP/IP stack, and<br />

library <strong>ACE</strong>s to perform typical networking tasks such as packet forwarding.<br />

The stack <strong>ACE</strong> is a conventional <strong>ACE</strong>. To send packets to the stack you bind <strong>ACE</strong><br />

targets to the stack <strong>ACE</strong>, and to receive packets from the stack you bind its target to<br />

an application or output <strong>ACE</strong>.<br />

Library <strong>ACE</strong>s are generally (but not always) implemented as micro<strong>ACE</strong>s. To integrate<br />

library micro<strong>ACE</strong>s into your application, you link and compile the microblocks<br />

with the microblocks <strong>of</strong> interface and application-specific micro<strong>ACE</strong>s. For more<br />

information on micro<strong>ACE</strong> architecture, see Chapter 6, “Writing Micro<strong>ACE</strong>s,” and<br />

Chapter 6, “Micro<strong>ACE</strong> Support Services,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

You load and bind stack and library <strong>ACE</strong>s as part <strong>of</strong> system initialization. The distribution<br />

includes scripts for loading and starting the supplied <strong>ACE</strong>s. You modify the<br />

startup script’s configuration file to load and start the proper system and library<br />

<strong>ACE</strong>s for your application.<br />

Revision 3.3, August 2001<br />

Stack and Library <strong>ACE</strong>s 87


The Stack <strong>ACE</strong><br />

Sample applications that use the library <strong>ACE</strong>s in various configurations can be found<br />

in the following location:<br />

<strong>SDK</strong>installpath/src/microace/apps<br />

The Stack <strong>ACE</strong><br />

The stack <strong>ACE</strong> is a system-defined <strong>ACE</strong> that integrates Linux TCP/IP stack with an<br />

<strong>IXA</strong> application.<br />

The stack <strong>ACE</strong> is implemented as a conventional <strong>ACE</strong> combined with a kernel-mode<br />

Ethernet device driver. The stack <strong>ACE</strong> appears to the Linux kernel as an Ethernet<br />

device, and to the <strong>IXA</strong> system as an <strong>ACE</strong>.<br />

The stack <strong>ACE</strong> does not perform any classification. When it receives a packets<br />

received from any <strong>ACE</strong> bound to it, the stack <strong>ACE</strong> directs that packet to the Linux<br />

TCP/IP stack.<br />

The stack <strong>ACE</strong> contains one target, named tx. Any packet received from the TCP/IP<br />

stack is directed to the <strong>ACE</strong> bound to that target. The following example shows the<br />

stack <strong>ACE</strong> bound directly to a network interface in both directions:<br />

TCP/IP stack<br />

stack <strong>ACE</strong><br />

tx Target<br />

default target bound to stack <strong>ACE</strong><br />

tx target bound to output <strong>ACE</strong><br />

input port<br />

input <strong>ACE</strong><br />

output <strong>ACE</strong><br />

output port<br />

Starting and<br />

Configuring<br />

the Stack <strong>ACE</strong><br />

The stack <strong>ACE</strong> is, by convention, named stackAce, but you can give it any name. The<br />

stack <strong>ACE</strong> target is named /stack_<strong>ACE</strong>_name/tx. The source code and <strong>ACE</strong> executable<br />

file can be found in the following location:<br />

<strong>SDK</strong>installpath/src/microace/aces/kstack<br />

You can start and bind the stack <strong>ACE</strong> using OMS calls in a manager program. For<br />

example, use the following code to bind the target <strong>of</strong> the stack <strong>ACE</strong> to the output<br />

interface <strong>ACE</strong>, and the application-defined ARP target <strong>of</strong> MyAce to the stack <strong>ACE</strong>:<br />

ix_res_bind ("/stackAce/tx", "/ifaceOutput");<br />

ix_res_bind ("/MyAce/ARP", "/stackAce");<br />

88 Stack and Library <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The L3 Forwarder Library <strong>ACE</strong><br />

You can also start and bind the stack <strong>ACE</strong> using the startup and configuration scripts.<br />

In the ixsys.config file:<br />

l<br />

l<br />

l<br />

Use the ace keyword to start the stack <strong>ACE</strong>.<br />

Create dynamic bindings for it using the bind keyword.<br />

Use the sh keyword to run the stackconfig configuration utility.<br />

This utility uses the port configuration specified in the ixsys.config file. You do not<br />

need to specify further configuration details. For example, the following statement<br />

launches the stackconfig configuration utility, specifying the name <strong>of</strong> the stack<br />

<strong>ACE</strong> as stackAce, and giving the location and name <strong>of</strong> the system configuration file:<br />

sh ./stackconfig stackAce ./ixsys.config<br />

For examples <strong>of</strong> using the startup utilities and configuration files, see Chapter 4,<br />

“Configuring and Starting <strong>IXA</strong> Systems.”<br />

The L3 Forwarder Library <strong>ACE</strong><br />

The <strong>IXA</strong> <strong>SDK</strong> includes a library <strong>ACE</strong> that performs layer-three forwarding, which<br />

you can include in routing applications. The library <strong>ACE</strong> is implemented as a<br />

micro<strong>ACE</strong>.<br />

The L3 forwarder micro<strong>ACE</strong> is an IP version 4 unicast forwarder. It takes in IP<br />

packets from one network interface port, decides what their destinations are, and<br />

sends them out through another port based on the decision. It makes the routing decision<br />

and forwards the IP packet according to the standard described by the Internet<br />

Engineering Task Force (IETF) RFC 1812. The L3 forwarder <strong>ACE</strong> conforms to this<br />

standard in the following area:<br />

l<br />

l<br />

l<br />

l<br />

Verifying that an IP packet is valid (checksums, bad source and destination<br />

addresses, options, and so on),<br />

Updating the various fields (Time to Live (TTL), options),<br />

Performing the destination lookup<br />

Dealing with errors (typically through the Internet Control Message Protocol<br />

ICMP).<br />

For more information on this standard, see www.ietf.org.<br />

The L3 forwarder micro<strong>ACE</strong> forwards IP packets based on a given routing table, and<br />

performs address resolution using the Ethernet Address Resolution Protocol (ARP).<br />

Like all micro<strong>ACE</strong>s, the forwarder contains a microblock and a core component:<br />

l<br />

l<br />

The microblock performs fast-path forwarding <strong>of</strong> IP version 4 packets. For exception<br />

packets, such as those requiring options processing, the microblock sends the<br />

packet to the core component.<br />

The core component is implemented in C++. In addition to processing exception<br />

packets, the core component generates ICMP error messages, handles all ARP<br />

messages and maintains the routing tables.<br />

Revision 3.3, August 2001<br />

Stack and Library <strong>ACE</strong>s 89


The L3 Forwarder Library <strong>ACE</strong><br />

Starting the<br />

Forwarder<br />

<strong>ACE</strong><br />

The forwarder library <strong>ACE</strong> is named by convention L3Fwdr, but you can give it any<br />

name when you launch it. To use the forwarder <strong>ACE</strong>, you typically configure the<br />

L3Fwdr microblock as the next block in each microblock group that contains an input<br />

<strong>ACE</strong> microblock, so that it accepts packets from the input <strong>ACE</strong>. If your application<br />

needs to do other processing on incoming packets first, you might need other <strong>ACE</strong>s<br />

between the input <strong>ACE</strong> and the forwarder.<br />

To start and initialize the L3 forwarder, use thel3config configuration utility. This<br />

utility uses the port configuration specified in the ixsys.config file, then adds<br />

routing table and ARP entries for the L3 forwarder library <strong>ACE</strong> according to specifications<br />

in the L3 forwarder configuration file. Launch this utility from<br />

theixsys.config file as a shell command.<br />

For example, the following statement launches the l3config configuration utility,<br />

specifying the name <strong>of</strong> the L3 forwarding library <strong>ACE</strong> as L3Fwdr, and giving the locations<br />

and names <strong>of</strong> both configuration files:<br />

sh ./l3config L2Bridge ./ixsys.config ./l3forwarder.config<br />

Binding the<br />

Targets<br />

The forwarder <strong>ACE</strong> defines two targets, /forwarder_name/out_if and<br />

/forwarder_name/stack. The forwarder directs packes as follows:<br />

l<br />

l<br />

It sends locally destined packets to stack target. These include broadcast, multicast,<br />

and unicast packets whose destination is one <strong>of</strong> the IP addresses assigned to<br />

the system.<br />

It sends all other valid, correctly routed packets to the out_if target.<br />

If no further processing is needed for outbound destinations, you can statically bind<br />

the out_if target directly to the output interface <strong>ACE</strong>, and configure the microcode<br />

processing pipeline in the same way. To do further processing on outbound packets,<br />

bind the out_if target to the next <strong>ACE</strong> in the processing pipeline. Dynamically bind<br />

the out_if target to the output <strong>ACE</strong> or other handler <strong>ACE</strong> so that the forwarder’s<br />

core component can also use it to transmit packets.<br />

Similarly, you can dynamically bind the stack target directly to the stack <strong>ACE</strong> so that<br />

the forwarder’s core component can pass packets with local destinations to the Linux<br />

TCP/IP stack. If your application needs to do further processing on locally destined<br />

packets, bind the stack target to another handler <strong>ACE</strong>.<br />

For an example <strong>of</strong> starting, configuring, and binding the forwarder <strong>ACE</strong>, see<br />

Chapter 3, “Compiling and Testing Applications.”<br />

Configuring<br />

the Forwarder<br />

The L3 forwarder configuration file uses keyword statements to set up the initial<br />

configuration <strong>of</strong> the routing table and ARP cache for the L3 forwarder library <strong>ACE</strong>.<br />

l<br />

The configuration keywords are described in detail in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

l For an example <strong>of</strong> using the startup utility and configuration file, see Chapter 4,<br />

“Configuring and Starting <strong>IXA</strong> Systems.”<br />

90 Stack and Library <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The L2 Bridging Library <strong>ACE</strong><br />

The L3 forwarding <strong>ACE</strong> exports a crosscall interface that your application uses to<br />

manipulate the routing table, ARP table, and otherwise configure the behavior at run<br />

time. The crosscall operations are organized into functional areas as follows:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Route table calls allow you to:<br />

— Add and delete route table entries<br />

— Perform route table lookups<br />

— Print the route table to a file for debugging<br />

Forwarding configuration calls allow you to get and set configuration flags to<br />

control forwarding behavior<br />

ARP table and configuration calls allow you to:<br />

— Add and delete ARP table entries<br />

— Perform ARP table lookups<br />

— Get and set the ARP sleep time, default age, and back<strong>of</strong>f values<br />

ICMP calls allow you to get and set the ICMP drain value, sleep time, and queue<br />

depth<br />

A statistics call allows you to get statistical information about forwarding activity<br />

for a particular network interface port.<br />

Interface calls allow you to:<br />

— Get and set the layer 2 MAC address <strong>of</strong> a port<br />

— Get and set layer 3 IP addresses <strong>of</strong> a port<br />

— Enable and disable ports<br />

— Get and set the MTU for a port<br />

The crosscalls are described in detail in the <strong>IXA</strong> <strong>SDK</strong> Reference. For more information<br />

on using crosscalls, see Chapter 11, “Communication Within an Application.”<br />

The L2 Bridging Library <strong>ACE</strong><br />

The L2 bridging library <strong>ACE</strong> implements a layer-two bridge according to the<br />

ISO/IEC 15802-3 standard, as described in the ANSI/IEEE Std 802.1D, 1998 Edition.<br />

It is implemented as a micro<strong>ACE</strong>. Like all micro<strong>ACE</strong>s, the forwarder <strong>ACE</strong> contains a<br />

microblock and a core component:<br />

l<br />

l<br />

The microblock performs fast-path forwarding <strong>of</strong> unicast IP version 4 packets<br />

between networks or network segments. It maintains an 8000-entry forwarding<br />

table, and a logical port state that determines how and whether it transmits<br />

packets on a port. It sends exception packets to the core component.<br />

The core component processes exception packets. It defines targets that the<br />

micro<strong>ACE</strong> uses to forward packets to the output interface <strong>ACE</strong> or to other <strong>ACE</strong>s,<br />

such as the stack <strong>ACE</strong> or L3 forwarding <strong>ACE</strong>.<br />

The core component administers the port states and the MAC forwarding table.<br />

It performs aging for dynamic (learned) table entries, and deletes them after the<br />

maximum aging time. It exports crosscalls that allow an application to configure<br />

the table and port states at run time. See “Configuring the L2 Bridger” on page 94.<br />

Stack and Library <strong>ACE</strong>s 91<br />

Revision 3.3, August 2001


The L2 Bridging Library <strong>ACE</strong><br />

Packet<br />

Processing<br />

The microblock drops any packet whose source address is <strong>of</strong> type multicast or broadcast,<br />

whose size exceeds port MTU or is less than 64 bytes (runts), or that has a<br />

reserved destination address.<br />

Packet handling depends on the logical port state:<br />

l When a port is disabled, any packet destined for the port is dropped.<br />

l When a port is blocked or listening and the incoming packet is a BPDU packet, it<br />

is sent to the core component. Otherwise it is dropped.<br />

l<br />

l<br />

When a port is learning, the microblock adds the source MAC address <strong>of</strong> an<br />

incoming packet to the forwarding table.<br />

When a port is forwarding, the microblock learns the MAC address and performs<br />

all packet forwarding. In this state, if the destination MAC address on received<br />

packet is equal to the MAC address <strong>of</strong> the port, this packet is meant for local<br />

administration, L3 forwarding, or a nonroutable protocol. The microblock queues<br />

the packet to a local target for handling.<br />

The core component performs a flooding operation for an incoming packet if the<br />

destination address is not found in the forwarding table. Flooding copies packets,<br />

and can be resource intensive. You can limit flooding to a subset <strong>of</strong> ports by assigning<br />

ethertype protocols to specific ports.<br />

The following exception conditions cause the microblock to send a packet to the core<br />

component:<br />

Condition<br />

BPDU<br />

Learn<br />

Learn and Forward<br />

Description<br />

The incoming port is in the blocked, listening, learning, or forwarding<br />

state and the destination address matches the BPDU multicast<br />

address.<br />

This occurs under either <strong>of</strong> the following conditions:<br />

l The receiving port is in learning state and the source MAC address<br />

was not found in the MAC forwarding table.<br />

l The receiving port is in forwarding state but the output port was not<br />

in the forwarding state, and the source MAC address was not found<br />

in the MAC forwarding table.<br />

The microblock adds an entry to the MAC forwarding table, providing<br />

the source MAC address, the ingress port number, and the dynamic<br />

entry type. An event handler in the core component ages the learned<br />

entries.<br />

The source MAC address is not found in the MAC forwarding table,<br />

the destination MAC address is found, and both the input and output<br />

ports are in forwarding state.<br />

The microblock adds the entry and the core component ages it, as for<br />

the Learn condition.<br />

92 Stack and Library <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The L2 Bridging Library <strong>ACE</strong><br />

Condition<br />

Learn and<br />

Flood<br />

Description<br />

Neither the source nor the destination addresses are found in the<br />

MAC forwarding table, and the input port is in forwarding state.<br />

This packet is flooded to ports that are configured for the protocol type<br />

found in the ethertype <strong>of</strong> this packet.<br />

Learn and ARP The destination MAC address is addressed to this port but the source<br />

MAC address is not found in the MAC forwarding table. The input port<br />

is in forwarding or learning state.<br />

The core component learns the address and passes the packet to<br />

either the L3 forwarder <strong>ACE</strong> or the stack <strong>ACE</strong>.<br />

Flood<br />

Destination MAC address is not found in the forwarding table but the<br />

source MAC address has found a match.<br />

When the input port is in forwarding state, the packet is flooded to<br />

ports that are configured for the protocol type found in the ethertype<br />

<strong>of</strong> this packet.<br />

When the input port is in learning or forwarding state, the microcode<br />

adds a MAC forwarding entry for a unicast, multicast, or broadcast<br />

packet.<br />

Starting the L2<br />

Bridger<br />

The L2 bridging library <strong>ACE</strong> is named by convention L2Bridge, but you can give it<br />

any name when you launch it. The source code, including the <strong>ACE</strong> executable file<br />

and microblock source, can be found in the following location:<br />

<strong>SDK</strong>installpath/src/microace/aces/l2bridge_ace<br />

To use the bridging <strong>ACE</strong>, you typically configure the L2Bridge microblock as the<br />

next block in each microblock group that contains an input <strong>ACE</strong> microblock, so that<br />

it accepts packets from the input <strong>ACE</strong>. If your application needs to do other<br />

processing on incoming packets first, you might need other <strong>ACE</strong>s between the input<br />

<strong>ACE</strong> and the bridger.<br />

The bridger <strong>ACE</strong> defines two targets, /bridger_name/out_if and<br />

/bridger_name/stack.<br />

To start and initialize the L2 bridger, use the l2config configuration utility. This<br />

utility uses the port configuration specified in the system configuration file, then<br />

adds route table entries and sets logical port properties specific to the L2 bridging<br />

library <strong>ACE</strong> according to specifications in the L2 bridge configuration file. Launch<br />

this utility from the ixsys.config file as a shell command.<br />

For example, the following statement launches the l2config configuration utility,<br />

specifying the name <strong>of</strong> the L2 bridging library <strong>ACE</strong> as L2Bridge, and giving the locations<br />

and names <strong>of</strong> both configuration files:<br />

sh ./l2config L2Bridge ./ixsys.config ./l2bridge.config<br />

Stack and Library <strong>ACE</strong>s 93<br />

Revision 3.3, August 2001


The NAT Library <strong>ACE</strong>s<br />

Configuring<br />

the L2 Bridger<br />

The L2 bridge configuration file uses keyword statements to initialize the routes and<br />

port configuration needed by the L2 bridging <strong>ACE</strong>. All the commands operate at the<br />

layer-two level. The logical port configuration does not effect the physical behavior<br />

<strong>of</strong> the port.<br />

l<br />

The keywords are described in detail in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

l For an example <strong>of</strong> using the startup utility and configuration file, see Chapter 4,<br />

“Configuring and Starting <strong>IXA</strong> Systems.”<br />

The <strong>ACE</strong> exports a crosscall interface that your application uses to manipulate the<br />

routing table and port configuration at run time.<br />

You can use the crosscalls to:<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

l<br />

Enable and disable the collection <strong>of</strong> port activity statistics, in the form <strong>of</strong> RFC1493<br />

MIB attributes and tables, and retrieve the statistics.<br />

Update the MAC forwarding table, associating a destination port with destination<br />

MAC addresses and entry types (static or dynamic).<br />

Update the time that learned MAC forwarding table entries are allowed to age<br />

before being automatically removed.<br />

Update port states. A port state can be disabled, blocked, listening, learning, or<br />

forwarding.<br />

Enable and disable Ethernet bridging for a port.<br />

Enable and disable IP bridging for a port when routing is disabled for that port.<br />

Configure port groups for any ethertype protocol, to enable bridging for<br />

nonroutable protocols.<br />

The crosscalls are described in detail in the <strong>IXA</strong> <strong>SDK</strong> Reference. For more information<br />

on using crosscalls, see Chapter 11, “Communication Within an Application.”<br />

The NAT Library <strong>ACE</strong>s<br />

The NAT library application consists <strong>of</strong> two <strong>ACE</strong>s, the NAT micro<strong>ACE</strong> and the NAT<br />

controller, a conventional <strong>ACE</strong>. Together, these <strong>ACE</strong>s perform network address<br />

translation according to rules that you provide.<br />

Packet<br />

Processing<br />

The specific rules for network address translation are defined by your application in<br />

the NAT controller’s access control lists (ACLs). There are two types <strong>of</strong> ACL:<br />

l<br />

l<br />

A filter ACL contains filter rules that specify what actions to take on packets with<br />

specific destination addresses. The possible actions are pass, drop, and NAT.<br />

The NAT ACLs contains network address translation rules. When a packet<br />

matches a filter rule that specifies the NAT action, the <strong>ACE</strong> searches for a<br />

matching NAT rule in the NAT ACLs. The NAT controller maintains ACLs for the<br />

following types <strong>of</strong> network address translation:<br />

— Static<br />

— Dynamic<br />

94 Stack and Library <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The NAT Library <strong>ACE</strong>s<br />

— IP masquerade (port translation)<br />

— Virtual server (load balancing)<br />

The NAT micro<strong>ACE</strong> maintains a cache <strong>of</strong> translations, which it receives from the<br />

NAT controller. The microblock receives incoming packets, parses the header, and<br />

looks for a translation in its cache. If it finds one, it performs the specified IP address<br />

translation and forward the packet to the next microblock in its group.<br />

If the microblock finds no translation in the local cache, it flags an exception and<br />

sends the packet to the core component. The core component sends all packets it<br />

receives (from its own microblock or from other <strong>ACE</strong>s) to the NAT controller.<br />

The NAT controller searches its filter rules to determine whether network address<br />

translation should be performed for the packet. If it should, the <strong>ACE</strong> searches the<br />

appropriate NAT rules to find the correct translation.<br />

When it has found a suitable translation, the NAT controller passes both the translation<br />

and the packet back to the micro<strong>ACE</strong>. The micro<strong>ACE</strong> core component updates<br />

the translation cache, then passes the packet back to the microblock for processing.<br />

Special<br />

Handling<br />

By default, the NAT <strong>ACE</strong>s also handles the following special-case packet types:<br />

l FTP packets<br />

l TCP fragments<br />

l ICMP error packets<br />

You can choose to disable any <strong>of</strong> these provided handlers and replace them with your<br />

own handlers. To do this:<br />

1. Use the enableApps crosscall to disable the handler for a packet type. (For more<br />

information, see the <strong>IXA</strong> <strong>SDK</strong> Reference.)<br />

2. Provide your own handler <strong>ACE</strong> for the packet type.<br />

3. Bind the ALG target <strong>of</strong> the NAT micro<strong>ACE</strong> to your handler <strong>ACE</strong>.<br />

The following sections briefly describe how the NAT <strong>ACE</strong>s handle each special case.<br />

FTP Packet Handling<br />

An FTP PORT or PASV reply command embeds the IP address and port numbers in<br />

the payload. To perform address translation for a PORT or PASV reply command, the<br />

FTP handler parses the payload to find the embedded IP address and port number.<br />

l<br />

l<br />

If the embedded IP address is the same as the IP address in the IP header that<br />

requires translation, then the handler translates the embedded address also.<br />

For IP masquerading (port translation), the handler translates the embedded port<br />

number, assigning a port from the <strong>ACE</strong>’s pool.<br />

Stack and Library <strong>ACE</strong>s 95<br />

Revision 3.3, August 2001


The NAT Library <strong>ACE</strong>s<br />

When the handler modifies the embedded IP address or port, it also changes the<br />

number <strong>of</strong> bytes in the payload and saves the number in the other_data field <strong>of</strong> the<br />

FLOW_DATA structure in SDRAM. This causes a change in the sequence number or<br />

acknowledgement number for subsequent packets. The handler recalculates the IP<br />

checksum to reflect the data changes.<br />

TCP Fragment Handling<br />

When the NAT micro<strong>ACE</strong> receives fragments, it assumes that all <strong>of</strong> the header fields<br />

are in the first fragment. Upon receiving the first fragment, the fragment handler<br />

performs the NAT table lookup.<br />

l<br />

l<br />

If no entry is found, the micro<strong>ACE</strong> flags an exception and sends the packet buffer<br />

to the control <strong>ACE</strong>.<br />

If an entry is found, it begins collecting the fragments in a buffer. If all fragments<br />

are not received within the specified timeout period, the buffer is cleared. When<br />

the datagram is complete, the micro<strong>ACE</strong> begins address translation on the fragments.<br />

If it is a TCP or UDP packet the fragment handler performs address translation for<br />

both the TCP/UDP header and the IP header in the first fragment. For the<br />

remaining fragments, it translates only the IP header addresses. The handler<br />

recalculates all checksums to reflect the data changes.<br />

ICMP Error Packet Handling<br />

When the NAT micro<strong>ACE</strong> receives an ICMP packet, the ICMP handler checks that it<br />

is an ERROR packet, which contains an embedded IP header for the packet that<br />

caused the error. The ICMP handler performs address translation for the IP header<br />

embedded in the message, and recalculates the checksums accordingly. It modifies<br />

the following:<br />

l<br />

l<br />

l<br />

The IP addresses and checksum <strong>of</strong> the IP header embedded in the data <strong>of</strong> the<br />

ICMP packet.<br />

The ICMP header checksum.<br />

The normal IP header checksum.<br />

If the ICMP packet is not an ERROR message, the handler sends it to the default<br />

target. The handler does not store any state for ICMP packets.<br />

Starting the<br />

NAT <strong>ACE</strong>s<br />

To use the NAT library <strong>ACE</strong>s, you must start both the NAT micro<strong>ACE</strong> and the NAT<br />

controller <strong>ACE</strong>.<br />

l<br />

The NAT micro<strong>ACE</strong> is named by convention nat, but you can give it any name<br />

when you launch it. To start the micro<strong>ACE</strong>, you can use the microace keyword in<br />

the system configuration file. For example:<br />

microace nat ./Nat none 0 5 natc 3<br />

l<br />

The NAT controller is named by convention natc, but you can give it any name<br />

when you launch it. To start the NAT controller, you can use the ace keyword in<br />

the system configuration file. For example:<br />

96 Stack and Library <strong>ACE</strong>s<br />

Revision 3.3, August 2001


The NAT Library <strong>ACE</strong>s<br />

ace natc ./natctlr none 2 nat 1<br />

The source code, including the <strong>ACE</strong> executable files and microblock sources, can be<br />

found in the following locations:<br />

<strong>SDK</strong>installpath/src/microace/aces/nat_ace<br />

<strong>SDK</strong>installpath/src/microace/aces/nat_ctlr<br />

You can configure the microblock to get packets directly from the input interface <strong>ACE</strong><br />

microblock, or from the microblock <strong>of</strong> another processing <strong>ACE</strong> such as the L3<br />

forwarder. It can transmit packets directly to an output <strong>ACE</strong>, or to another micro<strong>ACE</strong><br />

for further processing.<br />

To initialize the NAT controller, use the natconfig configuration utility. This utility<br />

sets up the initial ACLs and rules according to specifications in the NAT configuration<br />

file that you supply. Launch this utility from the ixsys.config file as a shell<br />

command.<br />

For example, the following statement launches the natconfig configuration utility,<br />

specifying the name <strong>of</strong> the NAT controller <strong>ACE</strong> as natc, and specifying the configuration<br />

file as nat.config in the same directory:<br />

sh ./natconfig natc ./nat.config<br />

Binding the<br />

Targets<br />

The NAT micro<strong>ACE</strong> defines the following targets:<br />

Target<br />

Description<br />

PASS<br />

CONFIG<br />

DROP<br />

Bind this target statically to the micro<strong>ACE</strong> containing the next microblock<br />

in the group, as defined by the dispatch loop.<br />

When the micro<strong>ACE</strong> finds a cached translation for an incoming<br />

packet, it performs address translation as required then sends the<br />

packet to this target to continue normal processing.<br />

Bind this target to the NAT controller <strong>ACE</strong>.<br />

When the micro<strong>ACE</strong> finds no cached translation for an incoming<br />

packet, it sends the packet to this target so that the NAT controller<br />

can provide a new translation.<br />

This target must remain unbound.<br />

The micro<strong>ACE</strong> drops packets by sending them to this target. The<br />

packet buffer is automatically freed when passed to an unbound target.<br />

Stack and Library <strong>ACE</strong>s 97<br />

Revision 3.3, August 2001


The NAT Library <strong>ACE</strong>s<br />

Target<br />

ALG<br />

DEFAULT<br />

Description<br />

Bind as required for your application.<br />

When one <strong>of</strong> the special packet-handling features (for FTP, TCP fragments,<br />

or ICMP errors) is disabled, the micro<strong>ACE</strong> sends packets <strong>of</strong><br />

that type to this target.<br />

You can define rules to send packets to this target for applicationdefined<br />

handling. (ALG stands for application-level gateway.)<br />

Bind as required for your application.<br />

The micro<strong>ACE</strong> passes all non-TCP/UDP packets (except ARP packets)<br />

to this target.<br />

Configuring<br />

the NAT library<br />

<strong>ACE</strong>s<br />

The NAT controller <strong>ACE</strong> maintains a data structure containing access control lists<br />

(ACLs) which in turn contain the application-defined rules.<br />

l<br />

l<br />

The ACLs are created and initialized by the natconfig startup utility according<br />

to the information you provide in the NAT configuration file.<br />

The NAT controller exports a crosscall interface. Use these crosscalls to add and<br />

delete ACLs and rules at run time.<br />

When adding a rule, you can specify the rule’s position in its ACL. When searching<br />

the rules, the NAT controller applies the first matching rule to an incoming packet.<br />

l<br />

l<br />

l<br />

For more information on startup and configuration, see Chapter 4, “Configuring<br />

and Starting <strong>IXA</strong> Systems.”<br />

For more information on using crosscalls, see Chapter 11, “Communication<br />

Within an Application.”<br />

For detailed information on the configuration file keywords and configuration<br />

crosscalls, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

98 Stack and Library <strong>ACE</strong>s<br />

Revision 3.3, August 2001


Chapter 9<br />

Classifying Packets Using NCL<br />

This chapter describes how an <strong>ACE</strong> classifies incoming packets using its classification<br />

code, which you write in Network Classification Language (NCL).<br />

This chapter contains the following topics:<br />

l “How <strong>ACE</strong>s Handle Packets” on page 99<br />

l “What’s in the NCL Rules File” on page 100<br />

l “Defining Protocols” on page 102<br />

l “Defining Rules” on page 101<br />

l “How Rules Are Evaluated” on page 103<br />

l “What Rules Do” on page 104<br />

How <strong>ACE</strong>s Handle Packets<br />

An <strong>ACE</strong> does three things with a packet:<br />

l Classifies it<br />

l Acts on it<br />

l Disposes <strong>of</strong> it<br />

Packets are received by the IXP1200 as network traffic flows through it. A packet<br />

arrives at an <strong>ACE</strong> from the source to which it is bound as a destination target, as<br />

described in Chapter 5, “Controlling Packet Flow.” The source <strong>of</strong> a packet could be,<br />

for example, either a network interface or another <strong>ACE</strong> earlier in the processing<br />

chain. The <strong>ACE</strong> classifies each incoming packet according to classification rules<br />

defined in the <strong>ACE</strong>’s NCL rules file.<br />

Revision 3.3, August 2001<br />

Classifying Packets Using NCL 99


What’s in the NCL Rules File<br />

As a result <strong>of</strong> the classification, NCL rules trigger action functions that are defined in<br />

the <strong>ACE</strong>’s action code. Action functions can act on packets by examining or retrieving<br />

their contents, or dispose <strong>of</strong> packets by sending them to targets. An action function<br />

can make a final disposition, ending the classification process for that packet, or it can<br />

tell the <strong>ACE</strong> to continue with the classification process and evaluate more rules.<br />

What’s in the NCL Rules File<br />

An <strong>ACE</strong> classifies incoming packets according to the protocol and predicate definitions<br />

in its NCL rules file. Based on the classification, rules trigger action functions<br />

defined in the <strong>ACE</strong>’s action code. The rules file and action file are compiled into a<br />

single object, which you associate with the <strong>ACE</strong> in the <strong>ACE</strong> initialization function<br />

you define.<br />

The NCL rules file has two general parts. In the first part, you define the protocols<br />

and predicates that are the basis <strong>of</strong> classification. In the second part, you define the<br />

rules, which trigger specific actions based on how a packet satisfies the predicates. In<br />

addition to these basic elements, you can define sets and searches in the NCL rules<br />

file.<br />

Classification<br />

Elements<br />

The basic classification elements you define in the NCL rules file are rules and protocols.<br />

l<br />

l<br />

A rule determines whether some statement is true for the current packet. If it is,<br />

the rule specifies an action to take. The action is a function that you defined in the<br />

action code that is part <strong>of</strong> the same <strong>ACE</strong> as the NCL rules file.<br />

A protocol definition describes a set <strong>of</strong> fields <strong>of</strong> particular lengths. A protocol is<br />

usually added on as a header to one or more other nested protocols. The definition<br />

states which other protocols can be nested, and where they start.<br />

For convenience, you can also define named predicates to use in the rules and<br />

protocol definitions. A predicate determines whether something is true <strong>of</strong> a current<br />

packet — for example, whether it conforms to a certain protocol, or whether a particular<br />

field has a particular value. Predicates are named Boolean expressions, which<br />

can contain other predicates and Boolean expressions. You can define predicates as<br />

part <strong>of</strong> a protocol definition or separately.<br />

Sets and<br />

Searches<br />

NCL and the Action Services Library (ASL) together support data tables called sets.<br />

Sets associate application-defined data with packets. You define named searches associated<br />

with a specific set, which determine whether the current packet has a matching<br />

element in the set, based on the values <strong>of</strong> specified fields.<br />

You define and name the sets and searches in the NCL rules file, then use the<br />

compiler to generate corresponding objects in the action code. The sets are implemented<br />

on initialization. You populate the sets with data through actions.<br />

Searchable sets define collections <strong>of</strong> packets which are associated with each other by<br />

virtue <strong>of</strong> their contents. A set member (element) matches packets with a specific<br />

combination <strong>of</strong> field values. If you want to form collections on structural criteria, such<br />

100 Classifying Packets Using NCL<br />

Revision 3.3, August 2001


Defining Rules<br />

as “the set <strong>of</strong> all packets with IP header lengths greater than twenty bytes,” use a classification<br />

predicate rather than a searchable set; see “Defining Protocols” on<br />

page 102.<br />

Sets are an efficient way to track a large number <strong>of</strong> classes <strong>of</strong> packets. They allow you<br />

to keep state information for all packets that have the same values in specific fields.<br />

For example, you can count the number <strong>of</strong> packets that flow between any two specific<br />

IP address pairs, or maintain state for each TCP stream.<br />

For more information on sets and searches, see Chapter 13, “Using Sets <strong>of</strong> Data to<br />

Classify Packets.”<br />

Defining Rules<br />

NCL rules determine what action to take, based on the classification. A rule consists<br />

<strong>of</strong> two parts:<br />

l<br />

l<br />

A predicate part<br />

The predicate part <strong>of</strong> a rule is a Boolean expression that describes the conditions<br />

a packet must meet to have the specified action performed on it.<br />

Predicates might include static comparisons <strong>of</strong> packet contents or comparisons<br />

against dynamically-created state.<br />

An action part<br />

The action part <strong>of</strong> a rule is the name <strong>of</strong> an action function to be executed when the<br />

predicate is true, along with any additional arguments the named function<br />

expects. The action function performs some action upon the incoming packet.<br />

The following example shows the parts <strong>of</strong> a rule:<br />

rule allpackets { ether } { action_all() }<br />

Name <strong>of</strong> this rule<br />

NCL keyword<br />

Predicate<br />

Action<br />

The predicate part <strong>of</strong> the rule can be the name <strong>of</strong> a predicate defined earlier in the file<br />

or in an included file, or it can be a Boolean expression that can, in turn, use named<br />

predicates. A predicate uses packet protocol elements that are defined earlier in the<br />

NCL rules file or in an included file. You access protocol fields using the form<br />

protocol_name.field_name; for example, ip.src. In a predicate, the name <strong>of</strong> the<br />

protocol currently being parsed evaluates to TRUE.<br />

The action part <strong>of</strong> the rule contains the name <strong>of</strong> an action function defined in the<br />

compiled action code that is part <strong>of</strong> the same <strong>ACE</strong>. You can pass arguments to the<br />

function, as required by its definition. The action is executed only when and if the<br />

predicate part <strong>of</strong> the rule evaluates to TRUE.<br />

Classifying Packets Using NCL 101<br />

Revision 3.3, August 2001


Defining Protocols<br />

Defining Protocols<br />

A rule determines whether its predicate is true by looking at fields in the current<br />

packet. The fields are interpreted according to the protocol definitions in the NCL<br />

rules file.<br />

A protocol definition names and describes a protocol. It names and describes the<br />

header fields that make up the protocol, and describes the relationship among<br />

multiple protocols. You generally define protocols in the first main section <strong>of</strong> an NCL<br />

rules file, immediately after the file inclusions and constant definitions, and before<br />

the rules.<br />

The <strong>IXA</strong> <strong>SDK</strong> distribution contains an NCL include file that defines the TCP/IP<br />

protocol. You can include this file in your application, and also use it as a template for<br />

defining other protocols. The sample file is located in the following directory:<br />

<strong>SDK</strong>installpath/include/ix/ncl/ix_tcp.ncl<br />

Protocols <strong>of</strong>ten contain other protocols. The keyword demux in a protocol definition<br />

identifies other protocols that can be nested within it. (The keyword comes from<br />

demultiplexing, the process <strong>of</strong> extracting nested protocols from the protocols that<br />

contain them.) When a packet arrives, the IXP1200 parses the protocol definitions to<br />

classify the packet. When it reaches the demux statement, the parser evaluates the<br />

expressions in the order in which they appear. The first expression that evaluates to<br />

TRUE identifies the nested protocol, and the parser continues into the indicated<br />

protocol definition.<br />

For example, the IP protocol definition contains the following demux statement that<br />

specifies what other protocols could be nested in an IP packet, and at what <strong>of</strong>fset they<br />

would be found:<br />

demux {<br />

invalid { ip_bad at 0 }<br />

badsrc { ip_badsrc at 0 }<br />

(proto == 1) { icmp at hlen }<br />

(proto == 2) { igmp at hlen }<br />

(proto == 6) { tcp at hlen }<br />

(proto == 17) { udp at hlen }<br />

default { ip_unknown_transport at hlen }<br />

}<br />

While a protocol is being parsed, the protocol’s name becomes a Boolean expression<br />

that evaluates to TRUE. For example, if the IP protocol is currently being parsed, the<br />

expression ip evaluates to TRUE.<br />

The following example shows an excerpt from the NBtcpip.ncl include file. This<br />

excerpt defines the header fields for Ethernet packets, defines a reusable Boolean<br />

function (predicate) for the protocol, and specifies the demultiplexing (demux)<br />

method to high-layer protocols.<br />

102 Classifying Packets Using NCL<br />

Revision 3.3, August 2001


How Rules Are Evaluated<br />

protocol ether {<br />

NCL protocol definition<br />

dst { ether[0:6] }<br />

NCL field definition<br />

src { ether[6:6] }<br />

typelen { ether[12:2] }<br />

snap { ether[14:6] }<br />

NCL predicate description<br />

type { ether[20:2] }<br />

predicate isnap { (typelen


What Rules Do<br />

For more information on what actions can be taken and how to define them, see<br />

Chapter 10, “Initializing and Acting on Packets in an <strong>ACE</strong>.”<br />

What Rules Do<br />

A rule can simply check the protocol type and take an appropriate action. For<br />

example, a VPN application might have a rule to check for an IPSec packet. When the<br />

rule succeeds, the action decrypts the packet. The rule might look like this:<br />

rule check_ipsec { ipsec } { action_decrypt () }<br />

A rule can pass field values to the action. For example, the following rule passes the<br />

source and destination addresses:<br />

rule check_ip { ip } { action_ip (ip.src, ip.dst) }<br />

The rule itself can check the source or destination address, or both, against a particular<br />

address, or table <strong>of</strong> addresses.<br />

A rule that checks a specific address might look like this:<br />

rule check_src { ip.src == 10.10.10.30 } { action_A() }<br />

You can use sets to keep tables <strong>of</strong> addresses, and named searches to check incoming<br />

packet addresses against the table. For more information on sets and searches, see<br />

Chapter 13, “Using Sets <strong>of</strong> Data to Classify Packets.”<br />

The rule can check other fields in the packet. For example, in an intrusion detection<br />

application, a rule might check whether a TCP packet is part <strong>of</strong> an HTTP stream. The<br />

rule might look like this:<br />

rule check_http { tcp && (tcp.sport == 80 || tcp.dport == 80) }<br />

{ action_scan () }<br />

When successful, this rule passes the packet to an action function, where it is queued,<br />

reordered, and then searched for interesting strings. If the function finds such a<br />

string, it sends a notification to the control module using a crosscall.<br />

For more information on:<br />

l Defining action functions, see Chapter 10, “Initializing and Acting on Packets in<br />

an <strong>ACE</strong>.”<br />

l<br />

Crosscalls, see Chapter 11, “Communication Within an Application.”<br />

104 Classifying Packets Using NCL<br />

Revision 3.3, August 2001


Chapter 10<br />

Initializing and Acting on Packets in an <strong>ACE</strong><br />

This chapter describes the initialization and action phases <strong>of</strong> an <strong>ACE</strong>. It explains what<br />

is in the <strong>ACE</strong>’s C code files, how to write them, and what kind <strong>of</strong> things an <strong>ACE</strong><br />

might do.<br />

This chapter contains the following topics:<br />

l “<strong>ACE</strong> Code Overview” on page 105<br />

l “Initializing the <strong>ACE</strong>” on page 106<br />

l “Defining Action and Utility Functions” on page 108<br />

l “What Action Functions Do” on page 110<br />

<strong>ACE</strong> Code Overview<br />

Each <strong>ACE</strong> executable contains a C initialization file, linked with a C action file that is<br />

associated with an NCL rules file.<br />

l<br />

l<br />

The initialization file creates and initializes the <strong>ACE</strong> object, and also creates and<br />

initializes any other subclasses, objects, and structures that the <strong>ACE</strong> will need.<br />

The entry point is the application-defined ix_init function, which acts as a main<br />

function for the <strong>ACE</strong>. A corresponding ix_fini function cleans up upon exit by<br />

destroying all objects created during initialization.<br />

The action file contains the action and callback function definitions. These are<br />

entry points that implement the behavior <strong>of</strong> your application in response to<br />

incoming packets, crosscalls, or application-defined events. The action part also<br />

contains any other utility functions that your application might call from the entry<br />

point functions.<br />

Revision 3.3, August 2001<br />

Initializing and Acting on Packets in an <strong>ACE</strong> 105


Initializing the <strong>ACE</strong><br />

You write <strong>ACE</strong> initialization and action code using the following:<br />

l<br />

l<br />

The C/C++ runtime environment<br />

The action services library (ASL), which provides:<br />

— Support for the <strong>ACE</strong> structure and model, including a basic structure for<br />

representing network data packets (the ix_buffer), and for sending them to<br />

different destinations on the network (the ix_target)<br />

— Support for associating application-defined data with packets using data sets<br />

— Support for scheduling application-defined events<br />

The ASL API is described in detail in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Initializing the <strong>ACE</strong><br />

In the initialization portion <strong>of</strong> your action code file, you define any subclasses or<br />

other data structures that the application will need. The initialization function,<br />

ix_init, must create and initialize the <strong>ACE</strong> itself, as well as any other objects and<br />

data the <strong>ACE</strong> will need.<br />

Defining ASL<br />

Objects<br />

Each <strong>ACE</strong> executable file is associated with one <strong>ACE</strong>, which is represented by an<br />

ix_ace structure. Your initialization function must allocate such an object and<br />

initialize it by calling ix_ace_init.<br />

Normally, an application defines a customized <strong>ACE</strong> structure that contains an<br />

ix_ace and other associated objects and data. Your <strong>ACE</strong> initialization function must,<br />

in addition to creating the <strong>ACE</strong> itself, create and initialize all structures associated<br />

with the <strong>ACE</strong>. These can include:<br />

l<br />

l<br />

l<br />

l<br />

Target objects. Each <strong>ACE</strong> automatically includes a target named default, which<br />

you normally bind to the egress network interface <strong>ACE</strong> or to the next <strong>ACE</strong> in the<br />

processing pipeline. You can also define additional targets to bind to other destinations.<br />

For more information, see Chapter 5, “Controlling Packet Flow.”<br />

Communication objects. These include crosscall and crosscall reference objects,<br />

from subclasses produced by the IDL compiler and customized with your application’s<br />

crosscall methods. For deferred crosscalls, you must also define and set<br />

the crosscall callback function. For more information, see Chapter 11, “Communication<br />

Within an Application.”<br />

Data set and set element objects. For each data set, the <strong>ACE</strong> initialization must<br />

declare and create a set structure (ix_set) with the same name and size that was<br />

declared for the set in NCL. It might also populate the set on initialization. For<br />

more information, see Chapter 13, “Using Sets <strong>of</strong> Data to Classify Packets.”<br />

Event objects. These allow you to schedule application-defined events for the<br />

<strong>ACE</strong>. In addition to creating and initializing the event structure (ix_event), you<br />

must define and set an event callback function to perform the desired operation.<br />

106 Initializing and Acting on Packets in an <strong>ACE</strong><br />

Revision 3.3, August 2001


Initializing the <strong>ACE</strong><br />

Your <strong>ACE</strong> also typically contains methods or functions to perform applicationspecific<br />

operations, such as invoking crosscalls or initiating searches, as well as callback<br />

functions for crosscalls and events. For more information, see “Defining Callbacks”<br />

on page 109 and “Defining Utility Functions” on page 109.<br />

Defining the<br />

Initialization<br />

Function<br />

Your <strong>ACE</strong> initialization file must contain a definition for the “main” function for the<br />

<strong>ACE</strong>, ix_init(). In this function, you must create and return the ix_ace object for<br />

the <strong>ACE</strong> to which the code belongs. In addition to creating the <strong>ACE</strong> object, the function<br />

must perform any other initialization the <strong>ACE</strong> needs. It must create targets and<br />

other associated objects and structures, populate sets, or initialize other data structures.<br />

The following is an example <strong>of</strong> an application-defined <strong>ACE</strong> initialization function<br />

that creates an <strong>ACE</strong> containing one target in addition to the default, named<br />

MyTarget:<br />

ix_error ix_init (int argc, char **argv, ix_ace **acep)<br />

{<br />

//allocate ace, pass to ace init<br />

ix_ace myace;<br />

ix_target mytarget;<br />

}<br />

ix_ace_init (myace, argv[1]); //name <strong>of</strong> <strong>ACE</strong> is passed in<br />

ix_target_init (mytarget, myace, "MyTarget");<br />

// error case<br />

// (error handling code here)<br />

//success, return<br />

acep = myace;<br />

return 0;<br />

The Resolver calls the <strong>ACE</strong>’s ix_init function when the application creates an <strong>ACE</strong>.<br />

A manager program can create the <strong>ACE</strong> by calling ix_res_create_ace(), passing<br />

the name <strong>of</strong> the <strong>ACE</strong> as its first argument. (See Chapter 2, “OMS Global Services<br />

API,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.) You can also create the <strong>ACE</strong> directly from the<br />

command line or a script, using the utility ixace. (See Chapter 8, “Command-Line<br />

Tools,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.)<br />

The <strong>ACE</strong> initialization process automatically creates a CAP through which the <strong>ACE</strong><br />

can communicate with the OMS, and starts the <strong>ACE</strong> loop, which listens for packet<br />

arrival and crosscall events.<br />

The <strong>ACE</strong> loop continues to run until the manager module deletes the <strong>ACE</strong> by calling<br />

ix_res_delete_ace, which in turn calls the <strong>ACE</strong>’s ix_fini function. The <strong>ACE</strong>’s<br />

action code must contain a definition for the function ix_fini which correctly<br />

deletes all objects and structures created during initialization.<br />

Initializing and Acting on Packets in an <strong>ACE</strong> 107<br />

Revision 3.3, August 2001


Defining Action and Utility Functions<br />

Defining Action and Utility Functions<br />

The action code file must define the methods and functions that implement the<br />

behavior <strong>of</strong> your application. You can implement behavior in any <strong>of</strong> the following<br />

ways:<br />

l<br />

l<br />

l<br />

Action functions<br />

An action function is executed when an NCL rule’s predicate is TRUE for an<br />

incoming packet. Action functions can call methods or other functions directly, or<br />

schedule events that result in the execution <strong>of</strong> callbacks.<br />

Callbacks<br />

Callbacks are executed in response to crosscall completions or scheduled events.<br />

You define a callback as a function <strong>of</strong> the appropriate type.<br />

Other utility functions<br />

You must provide definitions for utility functions. These are not entry points. To<br />

execute a utility function, you must call it from an action function or callback.<br />

Defining<br />

Action<br />

Functions<br />

Actions are function entry points implemented according to the calling conventions<br />

<strong>of</strong> the C/ C++ programming language. An action function is executed when an NCL<br />

rule predicate is satisfied for an incoming packet. The rule must pass any arguments<br />

that you have defined for the action function, and the action function must return one<br />

<strong>of</strong> the disposition codes that tell the <strong>ACE</strong> whether to continue passing the packet to<br />

other action functions triggered by successful classification rules.<br />

NOTE:<br />

Due to limitations in the gcc compiler, it is recommended that you avoid the<br />

use <strong>of</strong> type bool arguments in action functions. Use unsigned int instead.<br />

Action Function Return Values<br />

An action function that you define must return one <strong>of</strong> the following constant values:<br />

Constant Value Description<br />

RULE_CONT 0 Return RULE_CONT if the action has only observed the<br />

buffer, and additional rules and actions within the context <strong>of</strong><br />

the current <strong>ACE</strong> remain to be processed.<br />

Return this value from functions that do not take ownership<br />

<strong>of</strong> the network packet buffer.<br />

RULE_DONE 1 Return RULE_DONE to terminate processing <strong>of</strong> rules and<br />

actions within the context <strong>of</strong> the current <strong>ACE</strong>, for example,<br />

when a buffer has been sent to a target or stored for later<br />

processing.<br />

Return this value from functions that take ownership <strong>of</strong> the<br />

network packet buffer.<br />

108 Initializing and Acting on Packets in an <strong>ACE</strong><br />

Revision 3.3, August 2001


Defining Action and Utility Functions<br />

CAUTION: If your action function does not return one <strong>of</strong> these codes, your application<br />

can be corrupted when the action function returns, and the corruption may<br />

not be detectable.<br />

Predefined Default Action Function<br />

One action function, ix_action_default, is already defined in the ASL. This function<br />

routes a packet to the <strong>ACE</strong>’s default target. It returns the code RULE_DONE, which<br />

halts all further processing for the packet. It take no arguments. To call this function<br />

in an NCL rule, use a rule like the following:<br />

rule passip { ip } { ix_action_default() }<br />

This would pass all IP packets through to the <strong>ACE</strong>’s default target without further<br />

processing.<br />

For More Information<br />

For more information on defining action functions, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Defining<br />

Callbacks<br />

In the action part <strong>of</strong> your action code file, you define the callbacks that are executed<br />

in response to various events. You can define the following kinds <strong>of</strong> callbacks:<br />

l<br />

l<br />

Deferred crosscall callbacks<br />

The callback or service function for a crosscall implements the behavior to be<br />

executed when a deferred crosscall is completed.<br />

The <strong>IXA</strong> IDL compiler generates a skeleton for each crosscall callback function,<br />

which takes as its arguments the output parameters defined for the corresponding<br />

call in the crosscall interface. You must modify the skeleton to define the<br />

behavior <strong>of</strong> the function.<br />

For more information on call handler callbacks, see Chapter 11, “Communication<br />

Within an Application.”<br />

Scheduled event callbacks<br />

The ix_event mechanism provides for execution <strong>of</strong> functions at arbitrary times<br />

in the future. An action function can schedule, reschedule, or cancel an event, or<br />

change the function that it executes. The event callback function implements the<br />

behavior to be executed at the scheduled time.<br />

For more information on event callbacks, see Chapter 4, “The ASL Core Support<br />

Package API,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Defining Utility<br />

Functions<br />

You can define utility functions in the action file, be called from entry points such as<br />

action functions and callbacks. For example, an <strong>ACE</strong> that serves as a crosscall client<br />

typically contains a utility function to build a message and invoke a remote call, using<br />

the crosscall reference or stub. This utility function can be called, for example, by an<br />

action function in response to the receipt <strong>of</strong> a packet containing specific information.<br />

Initializing and Acting on Packets in an <strong>ACE</strong> 109<br />

Revision 3.3, August 2001


What Action Functions Do<br />

What Action Functions Do<br />

You can define action functions to respond to the successful application <strong>of</strong> a rule in<br />

any way you want. Actions can do any <strong>of</strong> the following:<br />

l<br />

l<br />

l<br />

l<br />

Pass the current packet to any target<br />

Modify a packet before passing it to a target<br />

Increment and decrement application-specific counters<br />

Schedule an event for execution at a later time<br />

l Build and send messages using crosscalls. For more information, see Chapter 11,<br />

“Communication Within an Application.”<br />

l<br />

l<br />

Maintain data sets, creating elements to insert in a set, and deleting elements after<br />

removing them from a set. For more information, see Chapter 13, “Using Sets <strong>of</strong><br />

Data to Classify Packets.”<br />

Call other functions or methods<br />

The following table shows some typical actions you might define for different types<br />

<strong>of</strong> applications. Notice that, while the action is triggered by a rule that checks a particular<br />

condition, the action itself can continue to check conditions before deciding what<br />

to do.<br />

Table 1:<br />

Application Type Classification Action<br />

Firewall<br />

Controls access by maintaining<br />

a set <strong>of</strong> acceptable source<br />

addresses<br />

If packet IP source<br />

address is in my table <strong>of</strong><br />

addresses that have<br />

access to my network<br />

Route the packet to the<br />

appropriate location inside<br />

my network<br />

Firewall<br />

Translates packet addresses<br />

based on a set <strong>of</strong> address<br />

mappings<br />

If packet IP destination<br />

address matches a<br />

known address for<br />

inbound traffic<br />

If the packet IP source<br />

address matches a<br />

known address for outbound<br />

traffic<br />

Change the destination<br />

address to the new address<br />

specified by the matching<br />

set element<br />

Recompute checksums<br />

Change the source address<br />

back to the original mapping<br />

address specified in<br />

the matching set element<br />

Recompute checksums<br />

110 Initializing and Acting on Packets in an <strong>ACE</strong><br />

Revision 3.3, August 2001


What Action Functions Do<br />

Table 1: (Continued)<br />

Application Type Classification Action<br />

Load-balancing<br />

Redirects packets to leastloaded<br />

servers by maintaining<br />

a set <strong>of</strong> possible destination<br />

servers<br />

If the IP source and destination<br />

match an element<br />

in the server set<br />

If the IP source and destination<br />

do not match any<br />

element in the server set,<br />

pass the pointer to where<br />

the record should go to<br />

the action<br />

Perform address translation<br />

(NAT) to change destination<br />

to value from matching<br />

element<br />

Recompute the checksum<br />

Send the packet to the identified<br />

server<br />

Use a load-balancing algorithm<br />

to determine the<br />

server to which the connection<br />

should go<br />

Create a new element for<br />

the server and add it to the<br />

set<br />

Perform NAT on the packet<br />

and send it to the identified<br />

server<br />

Intrusion detection<br />

Network monitoring<br />

If the packet is part <strong>of</strong> a<br />

TCP stream<br />

If the packet is HTTP and<br />

has a specified IP source<br />

address<br />

Search the packet for interesting<br />

strings<br />

If found, notify the application<br />

using an upcall<br />

Search the packet for the<br />

name <strong>of</strong> the web page <strong>of</strong><br />

interest<br />

If found increment a<br />

counter called mywebpage<br />

Quality <strong>of</strong> service<br />

Maintains higher and lower<br />

priority queues for transmitting<br />

traffic<br />

If the IP destination<br />

address equals that <strong>of</strong> an<br />

internal server<br />

If the IP source address<br />

equals that <strong>of</strong> a preferred<br />

customer<br />

Place the packet on a high<br />

priority queue for transmission<br />

Place the packet on a high<br />

priority queue for transmission<br />

If the IP destination<br />

address is an external<br />

web site and the source<br />

address is from a low-priority<br />

department<br />

Place the packet on a low<br />

priority queue for transmission<br />

VPN<br />

If the packet is an IPSec<br />

packet<br />

Decrypt the packet using<br />

cryptographic API calls.<br />

Initializing and Acting on Packets in an <strong>ACE</strong> 111<br />

Revision 3.3, August 2001


What Action Functions Do<br />

112 Initializing and Acting on Packets in an <strong>ACE</strong><br />

Revision 3.3, August 2001


Chapter 11<br />

Communication Within an Application<br />

This chapter introduces the crosscall mechanism that is used for communication<br />

between s<strong>of</strong>tware objects through the Object Management System (OMS). It contains<br />

the following topics:<br />

l “Overview” on page 113<br />

l “Defining Crosscall Interfaces” on page 116<br />

l “Defining Call Operations” on page 118<br />

l “Invocation Types for Operations” on page 120<br />

l “Initializing and Terminating Interfaces” on page 125<br />

l “Invoking Crosscall Functions” on page 130<br />

l “Passing Crosscall Arguments” on page 133<br />

Overview<br />

<strong>ACE</strong>s <strong>of</strong>ten need to communicate with one another or with a managing program for<br />

various reasons. For example:<br />

l<br />

l<br />

l<br />

l<br />

<strong>ACE</strong>s can send alerts or status reports to a managing program.<br />

Data processor <strong>ACE</strong>s can receive control messages and data from control <strong>ACE</strong>s.<br />

Data processor <strong>ACE</strong>s can send occasional packet data to control <strong>ACE</strong>s for special<br />

processing<br />

<strong>ACE</strong>s can exchange messages among themselves to coordinate packet processing.<br />

Because <strong>ACE</strong>s and their managing programs might be running on different platforms<br />

and be written in different languages, the <strong>IXA</strong> provides a communication mechanism<br />

based on remote procedure calls. The remote calls that you define for an <strong>IXA</strong> application<br />

are known as crosscalls.<br />

Revision 3.3, August 2001<br />

Communication Within an Application 113


Overview<br />

The OMS acts as a message broker for crosscalls. It provides marshalling and format<br />

conversion to handle differences in byte order and word size between different<br />

processors.<br />

Defining<br />

Interfaces<br />

You do not need to implement the entire crosscall infrastructure in your application.<br />

Instead, you define an interface, using an interface definition language, <strong>IXA</strong> IDL, that<br />

is provided with the <strong>IXA</strong> <strong>SDK</strong>. In the interface definition file you create a prototype<br />

for each operation, which determines whether a call is synchronous or asynchronous<br />

as well as defining the return type and argument types and directions for each call.<br />

In addition to the call prototypes, the interface definition file includes definitions for<br />

data structures used by the crosscalls.<br />

You compile an <strong>IXA</strong> IDL interface definition using the supplied compiler, tao_idl.<br />

The compiler generates several C source and header files that implement the calling<br />

infrastructure. You include the generated code with your application code. The only<br />

additional code you need to write is the implementation <strong>of</strong> the application-specific<br />

crosscall behavior. The compiler supplies template functions with the proper calling<br />

protocol, based on the interface you defined.<br />

Making and<br />

Receiving<br />

Remote Calls<br />

An <strong>ACE</strong> or an external object can both make and receive remote function calls. An<br />

object that receives calls acts as a crosscall server. An object that makes calls acts as a<br />

crosscall client.<br />

l<br />

l<br />

The call server receives the call from the client and executes the call function.<br />

Depending on how you define the crosscall interface, it can send a response to the<br />

client or not. The server contains the crosscall function implementation, as well as<br />

the generated code for the calling infrastructure.<br />

The call client makes a remote call to the call server. It contains a generated crosscall<br />

reference stub function, as well as generated code for the calling infrastructure.<br />

Depending on the type <strong>of</strong> call, it can also contain a callback function for handling<br />

an asynchronous response from the server.<br />

An <strong>ACE</strong> or task can act as a server for more than one crosscall, and can act as a client<br />

for any number <strong>of</strong> crosscalls as well.<br />

Crosscall<br />

Client<br />

Crosscall<br />

Server<br />

Crosscall<br />

Client<br />

Crosscall<br />

Client<br />

Crosscall<br />

Client<br />

Crosscall<br />

Server<br />

Crosscall<br />

Server<br />

114 Communication Within an Application<br />

Revision 3.3, August 2001


Overview<br />

Each call client or server must open a communication session with OMS. The session<br />

requires a dedicated communications channel called a communication access process<br />

(CAP). The call client or server can be either an <strong>ACE</strong> or a non-<strong>ACE</strong> program.<br />

l<br />

l<br />

When you create an <strong>ACE</strong>, the initialization procedure automatically creates a<br />

CAP for that <strong>ACE</strong>, and the <strong>ACE</strong> runtime polls that CAP for crosscall events in its<br />

main loop. When you initialize crosscalls, extract the <strong>ACE</strong>’s CAP using<br />

ix_ace_to_cap.<br />

A non-<strong>ACE</strong> program that acts as a crosscall client or server must initialize itself<br />

with the OMS as a task, using the ASL function ix_task_init. You can add the<br />

task to the OMS name space using the function ix_ns_add_task.<br />

Run the crosscall session in a separate thread. When you initialize crosscalls,<br />

extract the task’s CAP using ix_task_to_cap. The thread must poll the CAP for<br />

crosscall events using ix_cap_loop.<br />

Application code<br />

CAP, crosscall reference<br />

Remote procedure call<br />

Client task<br />

OMS<br />

Optional response<br />

Packet<br />

flow<br />

CAP, crosscall<br />

Packet Related<br />

classification actions<br />

Server <strong>ACE</strong><br />

When to Use<br />

Crosscalls<br />

Applications typically use crosscalls for configuration. For example, predefined<br />

library <strong>ACE</strong>s and system <strong>ACE</strong>s export crosscall interfaces that allow your application<br />

to configure them by making remote calls.<br />

Crosscalls are not an efficient way to forward packets. You can use a crosscall to send<br />

an occasional packet to another <strong>ACE</strong> for special processing or examination, or to send<br />

data retrieved from a packet. However, applications should use targets rather than<br />

crosscalls to pass packets between <strong>ACE</strong>s in the course <strong>of</strong> normal processing, as the<br />

target mechanism is optimized for packet traffic and is much more efficient.<br />

Communication Within an Application 115<br />

Revision 3.3, August 2001


Defining Crosscall Interfaces<br />

Defining Crosscall Interfaces<br />

You define a crosscall interface for an <strong>ACE</strong> or other object in a .idl file, using the <strong>IXA</strong><br />

Interface Definition Language (<strong>IXA</strong> IDL). The syntax and grammar <strong>of</strong> the <strong>IXA</strong> IDL,<br />

which is similar to C/C++, is completely described in Chapter 7, “<strong>IXA</strong> Interface Definition<br />

Language (<strong>IXA</strong> IDL),” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

An <strong>IXA</strong> IDL compiler is provided with the <strong>IXA</strong> <strong>SDK</strong>. This compiler converts <strong>IXA</strong> IDL<br />

files into customized C files for making remote function invocations. In creating these<br />

C files, the compiler transparently handles hardware dependent issues such as types,<br />

byte order, and alignment. You never need to write C code for the OMS interaction.<br />

Generated<br />

Files<br />

The compiler generates file names by appending a suffix to the <strong>IXA</strong> IDL source file<br />

name for skeleton, crosscall, stub, and callback files. From the source file<br />

idlname.idl, the <strong>IXA</strong> IDL compiler produces the following C files:<br />

Server/Client Generated Files Description<br />

Server only idlname_sk_c.h Crosscall skeleton header.<br />

idlname_sk_c.c<br />

idlname_cc_c.h<br />

idlname_cc_c.c<br />

Crosscall skeleton source.<br />

Crosscall template header, includes skeleton<br />

header.<br />

Crosscall template source, includes skeleton<br />

source.<br />

Use the crosscall template as base for<br />

implementation.<br />

Server and client idlname_stub_c.h Crosscall reference header.<br />

idlname_stub_c.c Crosscall reference source.<br />

idlname_cb_c.h<br />

idlname_cb_c.c<br />

Callback template header.<br />

Callback template source.<br />

Use the callback template as a base for<br />

implementation if there are any deferred<br />

calls.<br />

l<br />

l<br />

Skeletons: These files contain all the code needed for the interaction between the<br />

crosscall (server), the crosscall reference (client), and the OMS.<br />

Use these files without modification. Include the header in the server’s source<br />

code, and link the source file into the server’s executable.<br />

Crosscalls: For each operation, the crosscall template file contains a function<br />

template, and a crosscall virtual method table (VMT) that points to the function<br />

implementations.<br />

Include the header file in the crosscall server’s source code, and link the source<br />

file into the server’s executable. Initialize crosscalls in the server using the generated<br />

initialization functions provided in this file.<br />

116 Communication Within an Application<br />

Revision 3.3, August 2001


Defining Crosscall Interfaces<br />

Use the function templates as a model to provide the call function implementations.<br />

To avoid losing your changes on recompilation, keep the implementations<br />

in a separate source file. Replace the VMT pointers to the template functions with<br />

pointers to your implementations.<br />

l<br />

l<br />

Stubs: These files implement the crosscall reference stub functions, and also<br />

contain infrastructure needed by the server. Use these files without modification.<br />

Include the header in both the client’s and the server’s source code, and link the<br />

source files into the client’s and server’s executables. Initialize crosscalls in the<br />

client using the generated initialization functions provided in this file.<br />

Callbacks: For any deferred call operations, the compiler creates template callback<br />

functions in these files. (See “Invocation Types for Operations” on page 120.) If<br />

there are no deferred operations, these files are empty. When there are callback<br />

functions, the files contain a callback virtual method table (VMT) that points to<br />

the function implementations.<br />

If there are callback functions, include the header in both the client’s and the<br />

server’s source code, and link the source files into the client’s and server’s executables.<br />

Use the templates as a model to provide the callback function implementations.<br />

To avoid losing your changes on recompilation, keep the implementations in a<br />

separate source file. Replace the VMT pointers to the template functions with<br />

pointers to your function implementations.<br />

Organizing<br />

Call<br />

Operations<br />

<strong>IXA</strong> IDL files are structured as a set <strong>of</strong> modules, which, in turn, are composed <strong>of</strong> one<br />

or more interfaces and data structure definitions.<br />

l<br />

l<br />

Each module defines a name space or scope for a set <strong>of</strong> interfaces. You can use<br />

modules to group interfaces, so that you can repeat common operation names<br />

(such as ReportError, for example). Interface names must be unique only within<br />

a module.<br />

Each interface contains the signatures <strong>of</strong> individual operations. Operation names<br />

must be unique only within an interface. Each operation maps to one crosscall<br />

server function and its stub client function. Each deferred operation also maps to<br />

a callback function for handling the asynchronous response.<br />

An <strong>IXA</strong> IDL file can contain more than one interface. <strong>ACE</strong>s and other objects can<br />

import or export more than one interface. Each interface can contain one or more<br />

operations.<br />

You can divide individual call operations among interfaces, or define them all in a<br />

single interface, depending on how you want to organize your application’s functionality.<br />

For example, here is a sample IDL file that defines three crosscall interface definitions,<br />

each containing two operation call signatures, in one module:<br />

module myXcalls<br />

{<br />

interface XcallOne<br />

{<br />

//....<br />

Communication Within an Application 117<br />

Revision 3.3, August 2001


Defining Call Operations<br />

XcallOneFn1 (args);<br />

XcallOneFn2 (args);<br />

//....<br />

};<br />

interface XcallTwo<br />

{<br />

//....<br />

XcallTwoFn1 (args);<br />

XcallTwoFn2 (args);<br />

//....<br />

};<br />

interface XcallThree<br />

{<br />

//....<br />

XcallThreeFn1 (args);<br />

XcallThreeFn2 (args);<br />

//....<br />

};<br />

};<br />

Alternatively, you could define and create a single crosscall that exports all six operations:<br />

module myXcalls<br />

{<br />

interface XcallOneTwoThree<br />

{<br />

//....<br />

XcallOneFn1 (args);<br />

XcallOneFn2 (args);<br />

XcallTwoFn1 (args);<br />

XcallTwoFn2 (args);<br />

XcallThreeFn1 (args);<br />

XcallThreeFn2 (args);<br />

//....<br />

};<br />

The two approaches are equally valid. In either case the compiler generates eight<br />

files. Using separate interface definitions to group operations functionally can make<br />

your code more readable.<br />

Defining Call Operations<br />

In each operation signature in an interface definition you declare the return type, the<br />

directions and types <strong>of</strong> all arguments, and the invocation form. Together, these determine<br />

whether and how values can be returned from the remote function invocation.<br />

118 Communication Within an Application<br />

Revision 3.3, August 2001


Defining Call Operations<br />

Operation<br />

Names<br />

You name each operation in an interface definition, but the operation name is unique<br />

only within the interface. Similarly, the interface name is unique only within a<br />

module. To translate this scoping and create unambiguous names, the <strong>IXA</strong> IDL<br />

compiler produces function names by prepending the module and interface names<br />

to the operation name.<br />

For example, the following interface definition repeats the operation names in two<br />

interfaces:<br />

module mod1<br />

{<br />

interface if1<br />

{<br />

op1 (args);<br />

op2 (args);<br />

};<br />

interface if2<br />

{<br />

op1 (args);<br />

op2 (args);<br />

};<br />

};<br />

In the crosscall source file that results from compilation, the function skeletons are<br />

named as follows:<br />

mod1_if1_op1<br />

mod1_if1_op2<br />

mod1_if2_op1<br />

mod1_if2_op1<br />

If the interface definition includes nested modules or interfaces, they are included in<br />

the generated name from the outside in. For example, in the following interface definition,<br />

module mod2 is nested inside module mod1:<br />

module mod1<br />

{<br />

interface if1<br />

{<br />

op1 (args);<br />

op2 (args);<br />

};<br />

{module mod2<br />

interface if2<br />

{<br />

op1 (args);<br />

op2 (args);<br />

};<br />

};<br />

};<br />

In this case, the generated names for the two op1 operations in the two modules are<br />

as follows:<br />

Communication Within an Application 119<br />

Revision 3.3, August 2001


Invocation Types for Operations<br />

mod1_if1_op1<br />

mod1_mod2_if2_op1<br />

Invocation Types for Operations<br />

There are three forms <strong>of</strong> remote function invocation, which determine whether the<br />

caller receives a response, and if so whether it is synchronous or asynchronous:<br />

l<br />

l<br />

l<br />

One-way calls receive no response.<br />

Two-way calls elicit a synchronous response. The OMS blocks the caller until it<br />

receives the response. (This form can only be used by external crosscall clients.<br />

<strong>ACE</strong>s cannot block.)<br />

Deferred calls allow an asynchronous response. The call returns immediately with<br />

a simple result indicating whether the call was successfully sent. When the call<br />

completes the OMS invokes a callback handler specified by the caller.<br />

You declare the type <strong>of</strong> an operation with a keyword before the operation signature<br />

in the interface definition. The type <strong>of</strong> the operation affects how input and output<br />

arguments are mapped to the generated functions. For more information, see<br />

“Passing Crosscall Arguments” on page 133.<br />

One-way<br />

Operations<br />

When a client calls a one-way function, the object calling the function does not block.<br />

It makes the call and then immediately continues processing, while the remote object<br />

executes the remote function.<br />

l<br />

l<br />

Declare a one-way operation using the keyword oneway before the return type<br />

declaration in the operation signature.<br />

A one-way function invocation cannot return a value. Therefore, you must<br />

declare the return value as void and all parameters as in.<br />

Since the calling object has no way <strong>of</strong> knowing whether the function executed<br />

successfully, use the one-way operation where such knowledge is not essential or<br />

where the success <strong>of</strong> the function call is tested by invoking another function.<br />

The following example shows the signature for a one-way operation in an interface<br />

definition:<br />

oneway void doSomething(in char* name);<br />

The generated skeleton and stub functions for this call are defined to take the input<br />

argument, and return an error token (ix_error) .<br />

Two-way<br />

Operations<br />

When a client calls a two-way function, the calling object blocks (waits for the function<br />

to execute and return) before continuing its own processing. This allows the<br />

remote object to respond, and the caller to determine the success <strong>of</strong> the execution.<br />

l<br />

Declare a two-way operation using the keyword twoway before the return type<br />

declaration in the operation signature. This is the default invocation type, so if<br />

you do not declare the type, the operation is two-way.<br />

120 Communication Within an Application<br />

Revision 3.3, August 2001


Invocation Types for Operations<br />

l<br />

l<br />

A two-way operation can have output arguments. You can use these to return<br />

values from the remote object.<br />

A two-way operation can return a value. The compiler maps the return value to<br />

an output argument before generating the C code.<br />

NOTE:<br />

This form can only be used by external crosscall clients. <strong>ACE</strong>s cannot block.<br />

They can serve two-way calls, but cannot be clients for them.<br />

Here is an example <strong>of</strong> the prototype for a two-way operation in an interface definition:<br />

twoway void doSomething(in int value, out char* name);<br />

This operation has an out parameter that will return a value to the caller.<br />

All generated functions return an ix_error error token. The generated stub function<br />

(that the client uses to invoke the call remotely) is defined to take both the input and<br />

the output argument. For output arguments in a two-way function, the call client<br />

must allocate a variable <strong>of</strong> the proper type and pass its address to the call stub function.<br />

Upon return, the stub function places the output data in the output variable.<br />

Deferred<br />

Operations<br />

In a deferred operation, the calling object expects the remote function to execute and<br />

return but does not block processing until a response is received. It calls the stub function<br />

and then immediately continues processing, while the remote object executes the<br />

remote function. The calling object stores a callback function in a common data area<br />

and executes the callback when a reply is received from the remote function that was<br />

called. In this case, the caller can determine the success <strong>of</strong> the execution <strong>of</strong> the function<br />

on the remote object by the remote object response.<br />

l<br />

l<br />

l<br />

Declare a deferred operation using the keyword deferred before the return type<br />

declaration in the operation signature.<br />

A deferred operation can have output arguments which are passed to the callback<br />

function.<br />

A deferred operation can return a value. The compiler maps the return value to<br />

an output argument before generating the C code.<br />

Here is an example <strong>of</strong> the prototype for a deferred operation in an interface definition:<br />

deferred void doSomething (in int value, out char* name);<br />

The operation returns void but has an out parameter that will return a value to the<br />

callback function in the client.<br />

Handling Asynchronous Responses with a Callback Function<br />

When an interface contains a deferred operation, the compiler generates a template<br />

definition for a callback function in the callback header and source files. You must use<br />

the template to implement the callback function definition.<br />

Communication Within an Application 121<br />

Revision 3.3, August 2001


Invocation Types for Operations<br />

The generated stub function takes the input (in and inout) arguments. The OMS<br />

passes the output (inout and out) values to the callback function. All generated functions<br />

return an error token (ix_error). When the client allocates resources for a stub<br />

function variable, it is responsible for freeing those resources when the application no<br />

longer needs the value.<br />

The callback function template takes the following arguments:<br />

l The interface token, <strong>of</strong> type ix_base_t.<br />

l The error returned by the call function, <strong>of</strong> type ix_error.<br />

l All output (out and inout) arguments defined for the deferred call operation<br />

with which it is associated.<br />

For example, for the deferred operation defined above, the compiler generates a callback<br />

template with the following signature:<br />

ix_error mod1_if1_doSomething_cb (ix_base_t* basep, ix_error<br />

anError, char* name);<br />

Specifying<br />

Timeouts<br />

For two way and deferred operations, you can specify a timeout. For example:<br />

twoway long op1(in long val) context("TIMEOUT=5");<br />

The integer value determines the number <strong>of</strong> seconds the client will wait for a<br />

response before returning an error. If you do not specify a timeout, the default<br />

timeout value is determined by the OMS variable IX_OMS_SYSTEMTIMEOUT.<br />

You cannot specify a timeout <strong>of</strong> 0 seconds.<br />

Declaring<br />

Argument<br />

Directions<br />

Depending on the invocation type (see “Invocation Types for Operations” on<br />

page 120), a call can sometimes return values through output arguments. You declare<br />

operation arguments as input, output, or both input and output using the keywords<br />

in, out, and inout. The direction keyword precedes the type declaration for each<br />

argument.<br />

For example, the following operation signature declares a single input argument:<br />

oneway void accept_source(in appair_t appair);<br />

The following operation signature declares two arguments, where the first is input<br />

and the second is output:<br />

deferred void read_accept_list (in long listlen,<br />

out aplist_t aplist);<br />

The call function that the compiler generates for an operation must always return an<br />

ix_error. If you declare a return type for an operation in the interface definition, the<br />

compiler automatically transforms it to an output variable. For example, the declaration<br />

long op(); is transformed to:<br />

void op (out long _return_long)<br />

122 Communication Within an Application<br />

Revision 3.3, August 2001


Integrating Crosscalls with Applications<br />

The generated call template for an operation takes as parameters all declared arguments<br />

in the interface definition. In general, if a parameter can be used for output<br />

(out or inout), the caller must pass an address and you must define the call function<br />

to dereference it. For more information, see “Passing Crosscall Arguments” on<br />

page 133.<br />

The generated call reference stub takes all input arguments (in and inout), which it<br />

passes to the call function in the server. For a synchronous two-way operation, it also<br />

takes the addresses <strong>of</strong> output arguments (out and inout), which it uses to store<br />

response values.<br />

For an asynchronous deferred operation, the output (out and inout) arguments<br />

become parameters in the template callback function.<br />

Integrating Crosscalls with Applications<br />

To define a crosscall, use the following steps:<br />

1. Create a crosscall interface definition in <strong>IXA</strong> IDL file, file.idl.<br />

2. Compile the file on the command line, using the tao_idl compiler:<br />

> tao_idl file.idl<br />

The <strong>IXA</strong> IDL compiler generates code for both the client and server from the interface<br />

definition. The compiler output includes C source and header files that<br />

contain skeletons <strong>of</strong> the call functions, as well as stub functions with which to<br />

invoke them. These files implement the crosscall infrastructure.<br />

3. Include both the skeleton headers and the stub headers in the call server, and link<br />

the executable with the skeleton and stub C sources.<br />

4. Include the stub header in the call client, and link the executable with the stub<br />

source.<br />

5. For each operation in an interface definition, provide a crosscall function that<br />

actually implements the desired service, according to your application requirements.<br />

The compiler generates a template crosscall function for each operation, which<br />

you can use as a basis for your implementation.<br />

— For prototyping, you can modify the generated files directly. Include the<br />

generated crosscall header in the call server, and link the executable with the<br />

modified crosscall C source. However, the generated file is overwritten each<br />

time you compile the <strong>IXA</strong> IDL, and your changes are lost.<br />

— For a real application, write the crosscall definition in another source file,<br />

making sure it conforms to the template. During initialization, you must<br />

change the crosscall VMT structure to point to your crosscall implementation<br />

instead <strong>of</strong> to the template function.<br />

6. If the interface specifies any deferred (asynchronous) operations, provide a callback<br />

function implementation for each one. This is a function that is executed<br />

when the call completes.<br />

Revision 3.3, August 2001<br />

Communication Within an Application 123


Integrating Crosscalls with Applications<br />

The compiler produces a template callback function for each deferred operation.<br />

As for the crosscall template, you can modify the generated template to provide a<br />

callback definition, or provide an implementation based on the template in<br />

another file. You must change the callback VMT structure to point to your callback<br />

implementation instead <strong>of</strong> to the template function.<br />

7. Initialize each crosscall interface as part <strong>of</strong> the initialization process in both client<br />

and server. Initialization must be complete before the client makes any calls. See<br />

Appendix , “Communication Within an Application” on page 125.<br />

Threads and<br />

Crosscalls<br />

To make two-way calls, a client must use multithreading. If the call client is an <strong>ACE</strong>,<br />

which must be single-threaded, or if the client program needs to be single-threaded<br />

for any other reason, you must use deferred calls rather than two-way calls to return<br />

information to the caller. For a deferred call, you must define a callback function to<br />

handle the returned results, basing it on the template created by the <strong>IXA</strong> IDL<br />

compiler.<br />

An external program that communicates through the OMS is known as a task. To<br />

create the task, use the ASL function ix_task_init, and extract the CAP using<br />

ix_task_to_cap. Add the task to the Name Server using ix_ns_add_task. When<br />

the crosscall client opens a connection to the call server, it passes the task name. (See<br />

“Invoking Crosscall Functions” on page 130.)<br />

In communicating with the Name Server and Resolver, a task can use either an asynchronous<br />

session and entry points (ix_ns_open, ix_res_open) or a synchronous<br />

session and entry points (ix_ns_open_sync, ix_res_open_sync). Synchronous<br />

communication is easier to write and to read, although it requires a separate thread<br />

for the session. <strong>ACE</strong>s must use asynchronous sessions to communicate with the<br />

OMS, because they cannot block. For more information synchronous and asynchronous<br />

OMS sessions, see the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

The thread you create for synchronous communication in a task must poll for crosscall<br />

events using ix_cap_loop or ix_cap_poll.<br />

Crosscalls and<br />

Library <strong>ACE</strong>s<br />

Predefined library and system <strong>ACE</strong>s supplied by <strong>Intel</strong> ® typically act as crosscall<br />

servers. They export their crosscall interface definitions, as well as the generated stub<br />

files resulting from the compilation. You can regenerate the stub files from the original<br />

interfaces if necessary.<br />

Any <strong>ACE</strong> or task in your application can act as a crosscall client to a library or system<br />

<strong>ACE</strong> by including the generated stub code, initializing the crosscall interfaces, and<br />

calling the stub functions.<br />

You must not modify the generated stub code that is provided. If an interface<br />

includes deferred operations, you must define callback handlers based on the<br />

provided templates. These handlers are part <strong>of</strong> your application and are not<br />

supported by <strong>Intel</strong>.<br />

124 Communication Within an Application<br />

Revision 3.3, August 2001


Initializing and Terminating Interfaces<br />

Initializing and Terminating Interfaces<br />

The client and server programs must each provide code to initialize and terminate its<br />

interaction with the OMS crosscall mechanism. Initialization makes the client and<br />

server programs ready to communicate through the OMS. The client can make stub<br />

calls successfully only after initialization is complete.<br />

For each interface defined in the <strong>IXA</strong> IDL file, the compiler generates client initialization<br />

and termination functions in the stub file, and server initialization and termination<br />

functions in the crosscall file.<br />

Initializing the<br />

Client<br />

The client initialization function has a generated name in the form<br />

stub_module_interface_init. It has the following prototype:<br />

ix_error stub_module_interface_init<br />

(ix_base_t *ifbasep,<br />

ix_cap *clientcap);<br />

Argument<br />

ifbasep<br />

clientcap<br />

Description<br />

A pointer to the crosscall base structure (token) for this interface. For<br />

each interface that the client will use, the initialization code must create<br />

a token <strong>of</strong> type ix_base_t, and pass it to the interface initialization<br />

function.<br />

A pointer to the CAP for this call client, the structure used for OMS<br />

communication. To provide this argument, convert the <strong>ACE</strong> or task<br />

structure for the client to an ix_cap using the ASL functions<br />

ix_ace_to_cap and ix_task_to_cap.<br />

The interface base structure, or token, keeps all required information for the specific<br />

interface, until the application releases it after calling the interface’s termination function.<br />

The ix_base_t structure must not reside in read-only memory. Before creating<br />

it, the application should initialize the memory for the structure to zero. For example:<br />

memset(basep,0,size<strong>of</strong>(ix_base_t));<br />

The termination function for the interface has the following signature:<br />

extern ix_error stub_module_interface_fini (ix_base_t* basep);<br />

Client<br />

Initialization<br />

Example<br />

The following example shows how to initialize and terminate a task client for the<br />

ixa_c_Example1 interface.<br />

1. Create and initialize a task, and extract the CAP structure used for OMS communication.<br />

Several interfaces can use the same CAP.<br />

ix_error err = 0;<br />

static ix_task* pTask = NULL;<br />

static ix_cap* pCap = 0;<br />

pTask = malloc(size<strong>of</strong>(ix_task));<br />

Communication Within an Application 125<br />

Revision 3.3, August 2001


Initializing and Terminating Interfaces<br />

if (pTask == NULL)<br />

{<br />

err = ix_error_new(0,0,err, "%s - ix_task structure allocation<br />

failed!\n",localFunctionName);<br />

goto err_label1;<br />

};<br />

err = ix_task_init (pTask,<br />

"debugClientCap");<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err, "%s - ix_task_init call<br />

failed!\n",localFunctionName);<br />

goto err_label1;<br />

};<br />

err = ix_task_to_cap (pTask,<br />

&pCap);<br />

if (err || !pCap)<br />

{<br />

err = ix_error_new(0,0,err, "%s - ix_task_to_cap call<br />

failed!\n",localFunctionName);<br />

goto err_label1;<br />

};<br />

2. For two-way operations declared in the IDL interface, create and start a worker<br />

thread:<br />

/* Thread run function */<br />

static ix_error idl_thread_run(void* cookie, void** dummy)<br />

{<br />

ix_error err = 0;<br />

(void)dummy;<br />

ix_error_init(16, 128);<br />

fprintf(stderr,"Communication thread started!\n");<br />

err = ix_cap_loop((ix_cap*)cookie);<br />

if((err != 0) && !ix_error_is(err, 0, IX_ERROR_STOP))<br />

ix_error_dump(stderr,err);<br />

}<br />

return err;<br />

{<br />

ix_ossl_thread_t aThread;<br />

//utility fn provided w/<strong>SDK</strong><br />

err = ix_ossl_create_thread (&aThread,idl_thread_run,<br />

(void*) pCap);<br />

if (err)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_ossl_create_thread call failed!\n",<br />

localFunctionName);<br />

};<br />

}<br />

126 Communication Within an Application<br />

Revision 3.3, August 2001


Initializing and Terminating Interfaces<br />

3. Create and initialize a token for each interface:<br />

static const char localFunctionName[] =<br />

"initInterface"; ix_error err = 0;<br />

ix_base_t* pToken = 0;<br />

pToken = malloc(size<strong>of</strong>(ix_base_t));<br />

if(pToken == 0)<br />

return ix_error_new(0,0,err,<br />

"%s :: Token allocation failed!\n",<br />

localFunctionName);<br />

memset(pToken,0,size<strong>of</strong>(ix_base_t));<br />

Use memset to initialize the token before passing it to the interface initialization<br />

function.<br />

Create and initialize a different ix_base_t token for each interface the client will<br />

use. Do not use the same token for initializing different interfaces.<br />

4. Initialize the interface by calling its generated initialization function.<br />

err = stub_ixa_c_Example1_init (pToken, pCap);<br />

if(err)<br />

{<br />

free(pToken);<br />

return ix_error_new(0,0,err,<br />

"%s :: Token initialization failed!\n",<br />

localFunctionName);<br />

}<br />

5. If the client defines callback functions for handling the responses to deferred calls,<br />

update the callback function vector table to point to the function implementations.<br />

See “Initializing Function Pointers” on page 130.<br />

6. Connect to the server.<br />

static const char localFunctionName[] =<br />

"connectClient";<br />

static const char serverName[] = "aServer";<br />

ix_error err = 0;<br />

err = ix_oms_connect(pToken, serverName);<br />

if (err)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_oms_connect failed!\n",localFunctionName);<br />

};<br />

err = ix_oms_wait_connected(pToken);<br />

if (err)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_oms_wait_connected failed!\n",<br />

localFunctionName);<br />

};<br />

Communication Within an Application 127<br />

Revision 3.3, August 2001


Initializing and Terminating Interfaces<br />

If the server is already running, the connection completes immediately; otherwise<br />

the application either waits for a server to come up or times out. The call to<br />

ix_oms_wait_connected blocks. If your client is an <strong>ACE</strong>, or cannot block for any<br />

other reason, you must connect asynchronously (see the <strong>IXA</strong> <strong>SDK</strong> Reference for<br />

details).<br />

Connect to the server separately for each client interface.<br />

7. After all interface are initialized and the connection for each is completed, the<br />

client can make calls to stub functions in the interfaces. See “Invoking Crosscall<br />

Functions” on page 130.<br />

8. When the client is finished making calls to an interface, disconnect from the server<br />

connection for that interface.<br />

static const char localFunctionName[] =<br />

"disconnectClient";<br />

ix_error err = 0;<br />

err = ix_oms_disconnect(pToken);<br />

if (err)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_oms_disconnect failed!\n",<br />

localFunctionName);<br />

};<br />

err = ix_oms_wait_disconnected(pToken);<br />

if (err)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_oms_wait_disconnected failed!\n",<br />

localFunctionName);<br />

};<br />

return err;<br />

9. Call the termination function for that interface, then free its token.<br />

ix_error err = 0;<br />

err = stub_ixa_c_Example1_fini(pToken);<br />

free(pToken);<br />

10. Shut down the thread and terminate the task.<br />

err = ix_task_fini(pTask);<br />

Initializing the<br />

Server<br />

The process is similar for the server. The compiler generates server initialization and<br />

termination functions in the skeleton file. The server initialization function has a<br />

generated name in the form sk_module_interface_init. It has the following prototype:<br />

ix_error sk_module_interface_init<br />

(ix_base_t *ifbasep,<br />

ix_cap *servercap);<br />

128 Communication Within an Application<br />

Revision 3.3, August 2001


Initializing and Terminating Interfaces<br />

Argument<br />

ifbase<br />

servercap<br />

Description<br />

A pointer to the crosscall base structure for this interface.<br />

A pointer to the CAP for this call server. To obtain the CAP, use one <strong>of</strong><br />

the ASL functions ix_ace_to_cap or ix_task_to_cap.<br />

The termination function for the interface has the following signature:<br />

extern ix_error sk_module_interface_fini (ix_base_t* basep);<br />

Server<br />

Initialization<br />

Example<br />

The following example shows how to initialize and terminate an <strong>ACE</strong> server for the<br />

ixa_c_Example1 interface:<br />

1. As part <strong>of</strong> the <strong>ACE</strong> initialization (ix_ace_init), extract the CAP structure.<br />

...<br />

ix_cap* pCap=0; //allocate a CAP variable<br />

...<br />

err = ix_ace_to_cap (pAce, &pCap); //extract the CAP<br />

if (err || !pCap)<br />

{<br />

err = ix_error_new(0,0,err, "%s - ix_task_to_cap call<br />

failed!\n",localFunctionName);<br />

goto err_label1;<br />

};<br />

2. Create and initialize a token for each interface:<br />

static const char localFunctionName[] =<br />

"initInterface"; ix_error err = 0;<br />

ix_base_t* pToken = 0;<br />

pToken = malloc(size<strong>of</strong>(ix_base_t));<br />

if(pToken == 0)<br />

return ix_error_new(0,0,err,<br />

"%s :: Token allocation failed!\n",<br />

localFunctionName);<br />

memset(pToken,0,size<strong>of</strong>(ix_base_t));<br />

Use memset to initialize the token before passing it to the interface initialization<br />

function. Create and initialize a different ix_base_t token for each interface. Do<br />

not use the same token for initializing different interfaces.<br />

3. Initialize each interface by calling its generated initialization function, passing the<br />

token and the extracted CAP.<br />

err = sk_ixa_c_Example1_init (pToken, pCap);<br />

if(err)<br />

{<br />

free(pToken);<br />

return ix_error_new(0,0,err,<br />

"%s :: Token initialization failed!\n",<br />

Communication Within an Application 129<br />

Revision 3.3, August 2001


Invoking Crosscall Functions<br />

}<br />

localFunctionName);<br />

4. Reset the crosscall function vector to point to the function implementations,<br />

rather than the templates. See “Initializing Function Pointers” on page 130.<br />

5. During shutdown, call the termination function for each interface, then free its<br />

token.<br />

ix_error err = 0;<br />

err = sk_ixa_c_Example1_fini(pToken);<br />

free(pToken);<br />

Initializing<br />

Function<br />

Pointers<br />

The <strong>IXA</strong> IDL compiler creates a vector table (VMT) that the generated crosscall infrastructure<br />

uses to access the invocation functions. Initially, this table points to the<br />

generated crosscall function templates. The skeleton file defines an accessor function<br />

for the VMT, which you use to change the vector table to point to your function<br />

implementations, which you base on the generated templates.<br />

The accessor function for the crosscall VMT has the following prototype:<br />

extern ix_error getCCVMT_interface<br />

(ix_base_t<br />

*basep,<br />

CC_VMT_interface **pInterfaceCCVMT);<br />

The initialization code for the server must use this accessor to change each crosscall<br />

function pointer. For example:<br />

getCCVMT_MyInterface (pToken, &pCCVMT);<br />

pCCVMT->_pCC_Int1 _op1 = My_Int1_op1;<br />

Similarly, there is a VMT that the client uses to access any callback function for<br />

deferred operations. The stub file defines an accessor function for this VMT that the<br />

client must use to point to the callback function implementations.<br />

The accessor function for the callback VMT has the following prototype:<br />

extern ix_error getCBVMT_interface<br />

(ix_base_t<br />

*basep,<br />

CB_VMT_interface **pInterfaceCBVMT);<br />

The initialization code for the client must use this accessor to change each callback<br />

function. For example:<br />

getCBVMT_MyInterface (pToken, &pCBVMT);<br />

pCBVMT->_pCB_Int1 _cb1 = My_Int1_cb1;<br />

Invoking Crosscall Functions<br />

A call client invokes crosscall functions remotely, using the generated call stub. The<br />

stub has a generated name in the following form:<br />

130 Communication Within an Application<br />

Revision 3.3, August 2001


Invoking Crosscall Functions<br />

ix_error stub_module_interface_callfn<br />

(ix_base_t ifbase,<br />

callargs...)<br />

Each stub function takes as its first argument the interface token (ix_base_t) that the<br />

client defined and initialized for the interface in which the call is defined. This structure<br />

allows the OMS to coordinate the calling operation.<br />

The remaining arguments <strong>of</strong> the stub function are the input arguments defined for<br />

the crosscall, and, in the case <strong>of</strong> a two-way call, the locations <strong>of</strong> variables in which to<br />

store the values <strong>of</strong> any output arguments.<br />

Opening a<br />

Crosscall<br />

Connection<br />

Before you can make any calls, the client must initialize each interface (as described<br />

in “Initializing and Terminating Interfaces” on page 125) and open an OMS connection<br />

to the call server. Because the connection operation takes some time, the client<br />

must make sure that the connection has been established before making calls. The<br />

OMS supplies a number <strong>of</strong> global functions to accomplish this in various ways.<br />

When the call client is an external program, you can open the connection with the<br />

function ix_oms_connect, then block and wait for the connection to complete, using<br />

the function ix_oms_wait_connected.<br />

An <strong>ACE</strong> acting as a call client cannot block, so it cannot wait for the connection to<br />

complete before continuing execution. However, before the client <strong>ACE</strong> can make any<br />

calls, it must make sure that the connection is open. There are two possible ways to<br />

do this:<br />

l<br />

l<br />

Open the connection with the asynchronous function ix_oms_connect_cb, than<br />

wait until the callback is executed before making any calls.<br />

Open the connection with the function ix_oms_connect, which provides no<br />

response, then use the function ix_oms_is_connected to check that the connection<br />

is open before making any calls.<br />

Remote Call<br />

Example<br />

The following example shows an external call client calling into an <strong>ACE</strong>. The example<br />

initializes the crosscall, then establishes a connection to the call server. Because this is<br />

not an <strong>ACE</strong>, it can block and wait until the connection is complete before making the<br />

calls.<br />

ix_error run_test(ix_cap *capp)<br />

{<br />

ix_error err;<br />

ix_base_t if1; //create crosscall base structure<br />

long count = 0;<br />

long retval;<br />

// initialize crosscall interface<br />

memset(&if1,0,size<strong>of</strong>(ix_base_t)); //zero memory<br />

err = stub_toace_if1_init(&if1, capp);<br />

if(err)<br />

return err;<br />

// establish crosscall connect to server <strong>ACE</strong><br />

Communication Within an Application 131<br />

Revision 3.3, August 2001


Invoking Crosscall Functions<br />

err = ix_oms_connect(&if1, "myace");<br />

if(err)<br />

return err;<br />

// wait for connection to complete before making calls<br />

err = ix_oms_wait_connected(&if1);<br />

if(err)<br />

return err;<br />

printf("CONNECTED!!!");<br />

// make calls<br />

while(1){<br />

err = stub_toace_if1_one_func (&base, count++);<br />

if(err)<br />

return err;<br />

printf("Oneway call sent. count = %ld\n", count);<br />

err = stub_toace_if1_two_func (&base, count++, &retval);<br />

if(err)<br />

return err;<br />

printf("Twoway call sent. count = %ld retval = %ld\n",<br />

count, retval);<br />

err = stub_toace_if1_def_func (&base, count++);<br />

if(err)<br />

return err;<br />

printf("Deferred call sent. count = %ld\n",<br />

count);<br />

132 Communication Within an Application<br />

Revision 3.3, August 2001


Passing Crosscall Arguments<br />

}<br />

sleep(1);<br />

}<br />

Passing Crosscall Arguments<br />

The arguments that you declare for an operation in the interface definition can be<br />

used for input, output, or both, depending on the invocation type <strong>of</strong> the operation. If<br />

the operation is two way or deferred, you can also declare a return type, which is<br />

mapped to an output argument.<br />

The compiler maps the declared arguments to parameters in the generated call, stub,<br />

and callback functions and templates in such a way as to allow the calling program<br />

to pass in needed values and retrieve results. If results are expected, the client generally<br />

needs to allocate storage <strong>of</strong> the correct type and pass the address to the stub function.<br />

In general, when invoking a crosscall with an output (out or inout) parameter, the<br />

caller must pass either the address <strong>of</strong> a variable <strong>of</strong> the proper type or the value <strong>of</strong> a<br />

pointer to that type. The crosscall function being invoked must dereference the<br />

parameter to get to the type. For arrays, the caller must pass the address <strong>of</strong> the first<br />

element <strong>of</strong> the array.<br />

For out parameters <strong>of</strong> types string and wstring, the stub allocates storage for the<br />

output value. The client can use and retain that storage indefinitely. When the value<br />

is no longer needed, the client is responsible for freeing the memory. For all other<br />

types, the client must pass the address <strong>of</strong> a variable <strong>of</strong> the correct type.<br />

l<br />

l<br />

For in parameters, the caller must pass the value <strong>of</strong> the parameter for all <strong>of</strong> the<br />

basic types and enumeration types. For arrays, the caller must pass the address <strong>of</strong><br />

the first element <strong>of</strong> the array. For all other structured types, the caller must pass<br />

the address <strong>of</strong> a variable <strong>of</strong> that type.<br />

For strings, the client must pass a char* or wchar_t*.<br />

For inout parameters, the client must pass the address <strong>of</strong> a variable <strong>of</strong> the correct<br />

type for all <strong>of</strong> the basic types, enumeration types, and structured types. For<br />

strings, the client must pass the address <strong>of</strong> a char*, and for wide strings, the<br />

address <strong>of</strong> a wchar_t*. For arrays, the client must pass the address <strong>of</strong> the first<br />

element <strong>of</strong> the array.<br />

The following table summarizes what a client passes as an argument to a stub function<br />

and receives as a result.<br />

Declared Data Type In Inout Out/Return<br />

short short short* short*<br />

long long long* long*<br />

long long long long long long* long long*<br />

Revision 3.3, August 2001<br />

Communication Within an Application 133


Passing Crosscall Arguments<br />

Declared Data Type In Inout Out/Return<br />

unsigned short unsigned short unsigned short* unsigned short*<br />

unsigned long unsigned long unsigned long* unsigned long*<br />

unsigned long long unsigned long long unsigned long long* unsigned long long*<br />

float float float* float*<br />

double double double* double*<br />

long double long double long double* long double*<br />

boolean boolean boolean * boolean*<br />

char char char* char*<br />

wchar wchar* wchar* wchar*<br />

octet octet octet* octet*<br />

enum enum enum* enum*<br />

struct struct* struct* struct*<br />

union union* union* union*<br />

string char* char** char**<br />

wstring wchar* wchar** wchar**<br />

sequence sequence* sequence* sequence*<br />

array array array array<br />

Client Side<br />

Parameter<br />

Passing<br />

On the client side, follow these guidelines in passing parameters to a stub function:<br />

l<br />

l<br />

l<br />

Ensure that all parameter values are valid and properly initialized.<br />

Ensure that variables exist and are properly initialized before the stub call, then<br />

pass their addresses. The generated initialization function properly initializes all<br />

complex type parameters.<br />

When passing in parameters:<br />

— For all basic types, pass by value.<br />

— For complex types except arrays, pass as const type*.<br />

— For strings, pass as const char* or const wchar_t*.<br />

l<br />

When passing inout and out parameters:<br />

— For all basic types and all complex types except arrays, pass as type*.<br />

134 Communication Within an Application<br />

Revision 3.3, August 2001


Passing Crosscall Arguments<br />

— For arrays, pass the address <strong>of</strong> the first element.<br />

— For inout strings, point to a valid zero-terminated arrays <strong>of</strong> characters.<br />

— For two-way calls, allocate string inout parameters on the heap, and set out<br />

parameters to 0. The generated stub code frees the memory before demarshalling<br />

the response values. The client application is responsible for making a<br />

copy if it needs the value. (For deferred calls, out parameters are not generated<br />

in the stub signature and you do not pass addresses for them to the stub<br />

functions.)<br />

The application is responsible for freeing any memory it has allocated after the stub<br />

call returns, before exiting the scope where the variables have been declared. For all<br />

structured data types, clean up by calling the generated termination function.<br />

l<br />

l<br />

l<br />

l<br />

The termination function frees all valid strings that are contained in complex<br />

structures (except sequences with the _release flag set to 0). To ensure that this<br />

is successful, allocate the strings on the heap.<br />

For inout and out string and wstring parameters, the client must free the<br />

addressed memory. For in parameters, the way you free the memory in the client<br />

depends on how you allocated the memory before passing the parameter to the<br />

stub function.<br />

For two-way calls, the client must make copies <strong>of</strong> any useful inout data because<br />

the variables disappear after the stub function returns.<br />

For deferred calls, do not free the inout and out parameters that the OMS will<br />

pass to the callbacks. Make copies <strong>of</strong> any useful data, as these go out <strong>of</strong> scope after<br />

the callback returns.<br />

What the Stub Function Does to Passed Parameters<br />

l<br />

l<br />

l<br />

The generated stub function does not modify in parameters.<br />

For inout parameters, the stub function overwrites the passed parameters with<br />

the new values. In the case <strong>of</strong> strings or complex types containing strings, the stub<br />

frees the memory to which the parameter points. In case <strong>of</strong> unbounded sequences,<br />

if the received buffer is bigger than the existing one, the stub reallocates memory.<br />

If the sequence has the _release flag set to 0, the stub does not free contained<br />

strings.<br />

For out parameters, the stub function writes the result data at the location<br />

provided by the caller, overwriting any data that is already there.<br />

Server Side<br />

Parameter<br />

Passing<br />

On the server side, the OMS properly initializes all parameters before passing them<br />

to the crosscall function. The application should allocate all strings for the crosscall<br />

on the heap. After the crosscall function returns and the response is sent back, the<br />

OMS performs the cleanup, freeing all strings contained in complex structures except<br />

for those contained in sequences where you set the _release flag to 0.<br />

For inout and out string and wstring parameters, the application must first free<br />

the memory that is passed in, then dynamically allocate memory for return values.<br />

The generated code attempts to free the memory as soon the crosscall function<br />

returns. If the application modifies an incoming string in place, there is no need to<br />

free and allocate memory for the return value.<br />

Communication Within an Application 135<br />

Revision 3.3, August 2001


Passing Crosscall Arguments<br />

Passing<br />

Values in a<br />

One-way Call<br />

To make a one-way call, the client must do the following:<br />

1. Initialize the interface containing the one-way call, using the generated initialization<br />

function.<br />

2. Declare and initialize the in variables.<br />

3. Make the call to the appropriate stub function. The stub function does the<br />

following:<br />

— Marshals the operation ID.<br />

— Marshals all in variables.<br />

— Dispatches the call to OMS.<br />

— Returns.<br />

4. Clean up all the input variables.<br />

On the server side, a demultiplexing mechanism receives the call, demarshals the<br />

operation ID and invokes the proper call function as indicated by the operation ID.<br />

The OMS does the following:<br />

1. Creates and initializes variables for all in parameters.<br />

2. Demarshals all in parameters into the corresponding variables.<br />

3. Calls the application-defined crosscall function.<br />

4. Cleans up the in parameter variables.<br />

Passing<br />

Values in a<br />

Two-way Call<br />

To make a two-way call, the client must do the following:<br />

1. Initialize the interface containing the two-way call, using the generated initialization<br />

function.<br />

2. Declare and initialize the in, inout, and out variables.<br />

3. Make the call to the appropriate stub function. The stub function does the<br />

following:<br />

— Marshals the operation ID.<br />

— Marshals all in and inout variables.<br />

— Dispatches the call to OMS and blocks, waiting for the response.<br />

— Releases all inout variables.<br />

— Demarshals inout and out parameters in the corresponding variables<br />

4. Upon return from the call, process returned values as needed.<br />

5. Clean up all variables.<br />

On the server side, a demultiplexing mechanism receives the call, demarshals the<br />

operation ID and invokes the proper call function as indicated by the operation ID.<br />

The OMS does the following:<br />

1. Creates and initializes variables for all in, inout, and out parameters.<br />

2. Demarshals all in, inout, and out parameters into the corresponding variables.<br />

136 Communication Within an Application<br />

Revision 3.3, August 2001


Passing Crosscall Arguments<br />

3. Calls the application-defined crosscall function, which initializes the inout and<br />

out parameters to the return values.<br />

4. Marshals the inout and out variables.<br />

5. Cleans up all variables.<br />

When the client allocates resources for a stub function variable in a two-way call, it is<br />

responsible for freeing those resources when the application no longer needs the<br />

value.<br />

Passing<br />

Values in a<br />

Deferred Call<br />

To make a deferred call, the client must do the following:<br />

1. Initialize the interface containing the deferred call, using the generated initialization<br />

function.<br />

2. Declare and initialize the in and inout variables.<br />

3. Make the call to the appropriate stub function. The stub function does the<br />

following:<br />

— Marshals the operation ID.<br />

— Marshals all in and inout variables.<br />

— Dispatches the call to OMS.<br />

4. Clean up all variables.<br />

On the server side, a demultiplexing mechanism receives the call, demarshals the<br />

operation ID and invokes the proper call function as indicated by the operation ID.<br />

The OMS does the following:<br />

1. Creates and initializes variables for all in, inout, and out parameters.<br />

2. Demarshals all in, inout, and out parameters into the corresponding variables.<br />

3. Calls the application-defined crosscall function, which initializes the inout and<br />

out parameters to the return values.<br />

4. Marshals the inout and out parameters into the corresponding variables.<br />

5. Invokes the application-defined callback function in the client, passing the<br />

parameters as arguments.<br />

6. Cleans up all variables it has created.<br />

When the callback function has performed the required processing on the returned<br />

values, the client must clean up any variables created for it.<br />

Communication Within an Application 137<br />

Revision 3.3, August 2001


Passing Crosscall Arguments<br />

138 Communication Within an Application<br />

Revision 3.3, August 2001


Chapter 12<br />

Crosscall Example<br />

This chapter provides a demonstration <strong>of</strong> the crosscall mechanism that is used for communication<br />

between s<strong>of</strong>tware objects through the OMS. It contains the following topics:<br />

l “Overview” on page 139<br />

l “Example Interface Definition” on page 140<br />

l “Writing the Crosscall Client” on page 144<br />

l “Writing the Crosscall Server” on page 152<br />

Overview<br />

In this example, the <strong>IXA</strong> IDL specification defines an agreement between a client<br />

process and a server process about certain services that will be executed by the server<br />

on behalf <strong>of</strong> the client. In this case, the service is a simple database <strong>of</strong> person objects<br />

with a name and an age, for which a client can add, modify, or delete entries. The <strong>IXA</strong><br />

IDL compiler maps this definition into OMS-specific calls that perform the required<br />

service. The compiler generates source files for the server and for the client.<br />

l<br />

l<br />

For the server side, the compiler generates the required mechanisms for receiving<br />

the call and the invoking the crosscall function, as well as templates for the crosscall<br />

functions that provide the services. When developing the application, you use<br />

the template to implement the actual call functions. The server must link all<br />

generated files and include their headers, so that it contains all <strong>of</strong> the calling infrastructure,<br />

in addition to the call function definitions.<br />

For the client side, the compiler generates stub functions that the client uses to<br />

make the calls, and provides template callback functions for deferred calls. The<br />

client must link the stub code and include the headers, and also the implementations<br />

<strong>of</strong> the callback functions if there are deferred calls.<br />

Revision 3.3, August 2001<br />

Crosscall Example 139


Example Interface Definition<br />

Example Interface Definition<br />

The following <strong>IXA</strong> IDL code defines the Person crosscall interface, which defines a<br />

data structure to hold information about people (their name and age), and one operation<br />

<strong>of</strong> each type to act on that data:<br />

interface Person<br />

{<br />

struct person_Entry<br />

{<br />

string<br />

name;<br />

unsigned short age;<br />

};<br />

};<br />

oneway void addPerson(in person_Entry aPerson);<br />

unsigned short getAge(in string aName);<br />

deferred boolean deletePerson(in string aName);<br />

Notice that the getAge operation uses the default twoway invocation type.<br />

Rather than declaring inout or out parameters, the two-way and deferred operations<br />

return values, which will be mapped to output parameters during compilation.<br />

Generated<br />

Stub Files<br />

The <strong>IXA</strong> IDL compiler generates the following _stub_c.h file for the Person interface.<br />

The generated code declares initialization and termination functions for the client<br />

side <strong>of</strong> the interface, and stub functions for each operation defined in the interface.<br />

The compiler creates a vector table (VMT) that the generated crosscall infrastructure<br />

uses to access the callback functions for deferred operation. Initially, this table points<br />

to the generated callback function templates. This stub file defines an accessor function<br />

for the VMT, which you use to change the vector table to point to your function<br />

implementations, which you base on the generated templates.<br />

#ifndef _OMS_IDL_C_<strong>IXA</strong>_C_EXAMPLE1_STUB_C_H_<br />

#define _OMS_IDL_C_<strong>IXA</strong>_C_EXAMPLE1_STUB_C_H_<br />

#ifdef __cplusplus<br />

extern "C"<br />

{<br />

#endif /* __cplusplus */<br />

#include "ix/asl.h"<br />

#include "ix/ns.h"<br />

#include "ix/ossl.h"<br />

#include "ix/asl/ixbasecc.h"<br />

/**=================================================<br />

* Start stub declaration <strong>of</strong> interface Person<br />

*================================================*/<br />

140 Crosscall Example<br />

Revision 3.3, August 2001


Example Interface Definition<br />

/* Declare the interface name for Person interface */<br />

extern const char Person_intName[];<br />

/* Declare the local operation names for CC_VMT_Person interface */<br />

/* Declare the name for Person::addPerson operation */<br />

extern const char Person_addPerson_opName[];<br />

/* Declare the name for Person::getAge operation */<br />

extern const char Person_getAge_opName[];<br />

/* Declare the name for Person::deletePerson operation */<br />

extern const char Person_deletePerson_opName[];<br />

/* Client initialization function for Person interface */<br />

extern ix_error stub_Person_init(ix_base_t* basep,<br />

ix_cap *capp);<br />

/* Client finalization function for Person interface */<br />

extern ix_error stub_Person_fini(ix_base_t* basep);<br />

typedef struct<br />

{<br />

char* name;<br />

unsigned short age;<br />

} Person_person_Entry;<br />

/**=================================================<br />

* Helper functions for Person_person_Entry structure<br />

*================================================*/<br />

/* Marshaling function for Person::person_Entry structure */<br />

extern ix_error ix_sds_r_Person_person_Entry (ix_sds aSds, const<br />

Person_person_Entry* val);<br />

/* Demarshaling function for Person::person_Entry structure */<br />

extern ix_error ix_sds_p_Person_person_Entry (ix_sds aSds,<br />

Person_person_Entry* val);<br />

/* Initialization function for Person::person_Entry structure */<br />

extern ix_error init_Person_person_Entry (Person_person_Entry* val);<br />

/* Finalization function for Person::person_Entry structure */<br />

extern ix_error fini_Person_person_Entry (Person_person_Entry* val);<br />

/* Release function for Person::person_Entry structure */<br />

extern ix_error release_Person_person_Entry (Person_person_Entry*<br />

val);<br />

/**=================================================<br />

* End helper functions for Person_person_Entry structure<br />

*================================================*/<br />

Crosscall Example 141<br />

Revision 3.3, August 2001


Example Interface Definition<br />

/* Declare the a cross call function pointer type for<br />

Person::addPerson operation */<br />

typedef ix_error (* Person_addPerson_fptr)(ix_base_t* basep, const<br />

Person_person_Entry* aPerson);<br />

/* Declare the crosscall reference function for Person::addPerson<br />

operation */<br />

extern ix_error stub_Person_addPerson(ix_base_t* basep, const<br />

Person_person_Entry* aPerson);<br />

/* Declare the a cross call function pointer type for Person::getAge<br />

operation */<br />

typedef ix_error (* Person_getAge_fptr)(ix_base_t* basep, const<br />

char* aName, unsigned short* _return_val);<br />

/* Declare the crosscall reference function for Person::getAge<br />

operation */<br />

extern ix_error stub_Person_getAge(ix_base_t* basep, const char*<br />

aName, unsigned short* _return_val);<br />

/* Declare the a cross call function pointer type for<br />

Person::deletePerson operation */<br />

typedef ix_error (* Person_deletePerson_fptr)(ix_base_t* basep,<br />

const char* aName, int* _return_val);<br />

/* Declare the crosscall reference function for Person::deletePerson<br />

operation */<br />

extern ix_error stub_Person_deletePerson(ix_base_t* basep, const<br />

char* aName);<br />

/* Declare the deffered callback function for Person::deletePerson<br />

operation */<br />

extern ix_error deferred_cb_Person_deletePerson (ix_error anError,<br />

void* cookie, ix_sds aSds);<br />

/* Declare the callback function pointer type for<br />

Person::deletePerson operation */<br />

typedef ix_error (* Person_deletePerson_cb_fptr)( ix_base_t* basep,<br />

ix_error anError, int _return_val);<br />

/* Declare the crosscall VMT structure for Person interface */<br />

/**************<br />

** CC_VMT_Person structure holds function pointers<br />

** to implementation functions for all local<br />

** and inherited operations<br />

***************/<br />

typedef struct _CC_VMT_Person<br />

{<br />

Person_addPerson_fptr _pCC_Person_addPerson;<br />

Person_getAge_fptr _pCC_Person_getAge;<br />

Person_deletePerson_fptr _pCC_Person_deletePerson;<br />

} CC_VMT_Person;<br />

/* Declare the callback VMT structure for Person interface */<br />

142 Crosscall Example<br />

Revision 3.3, August 2001


Example Interface Definition<br />

/**************<br />

** CB_VMT_Person structure holds function pointers to callback<br />

** functions for all local and inherited operations<br />

****************/<br />

typedef struct _CB_VMT_Person<br />

{<br />

Person_deletePerson_cb_fptr _pCB_Person_deletePerson;<br />

} CB_VMT_Person;<br />

/* Accessor function for callback VMT */<br />

extern ix_error getCBVMT_Person(ix_base_t* basep,<br />

CB_VMT_Person** pInterfaceCBVMT);<br />

/**=================================================<br />

* End stub declaration <strong>of</strong> interface Person<br />

*================================================*/<br />

#ifdef __cplusplus<br />

}<br />

#endif /* __cplusplus */<br />

#endif /* end define */<br />

Generated<br />

Skeleton Files<br />

The <strong>IXA</strong> IDL compiler generates the following _sk_c.h file for the Person interface,<br />

which the server code includes.<br />

The generated code declares initialization and termination functions for the server<br />

side <strong>of</strong> the interface, and invocation functions for each operation defined in the interface.<br />

The compiler creates a vector table (VMT) that the generated crosscall infrastructure<br />

uses to access the invocation functions. Initially, this table points to the<br />

generated crosscall function templates. The skeleton file defines an accessor function<br />

for the VMT, which you use to change the vector table to point to your function<br />

implementations, which you base on the generated templates.<br />

#ifdef __cplusplus<br />

extern "C"<br />

{<br />

#endif /* __cplusplus */<br />

#include "ixa_c_example1_stub_c.h"<br />

/**=================================================<br />

* Start skeleton declaration <strong>of</strong> interface Person<br />

*================================================*/<br />

/* Server initialization function for Person interface */<br />

extern ix_error sk_Person_init (ix_base_t* basep, ix_cap* capp);<br />

/* Server finalization function for Person interface */<br />

extern ix_error sk_Person_fini (ix_base_t* basep);<br />

/* Accessor function for crosscall VMT */<br />

extern ix_error getCCVMT_Person(ix_base_t* basep,<br />

Crosscall Example 143<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

CC_VMT_Person** pInterfaceCCVMT);<br />

/* Declare the invoke function for Person::addPerson operation */<br />

extern ix_error invoke_Person_addPerson(ix_base_t* basep, ix_sds<br />

anSds, idl_ixa_c_crossCall_fptr pFunc);<br />

/* Declare the invoke function for Person::getAge operation */<br />

extern ix_error invoke_Person_getAge(ix_base_t* basep, ix_sds anSds,<br />

idl_ixa_c_crossCall_fptr pFunc);<br />

/* Declare the invoke function for Person::deletePerson operation */<br />

extern ix_error invoke_Person_deletePerson(ix_base_t* basep, ix_sds<br />

anSds, idl_ixa_c_crossCall_fptr pFunc);<br />

/**=================================================<br />

* End skeleton declaration <strong>of</strong> interface Person<br />

*================================================*/<br />

#ifdef __cplusplus<br />

}<br />

#endif /* __cplusplus */<br />

#endif /* end define */<br />

Writing the Crosscall Client<br />

The client program adds a new person, retrieves the age <strong>of</strong> the same person, then<br />

deletes the entry it has added, using the defined crosscalls. The following code establishes<br />

a connection to the server and initializes the crosscall interface, than calls the<br />

generated stub functions and handles the returned values. Finally, it terminates the<br />

crosscall connection and cleans up allocated space.<br />

This file defines an initialization function, idl_client_init, that takes command<br />

line arguments (argc and argv):<br />

l<br />

l<br />

The first argument is the name <strong>of</strong> the crosscall server to which to connect.<br />

The second argument is command, one <strong>of</strong> the strings ADD, DEL, or AGE.<br />

— "ADD" must be followed by two more arguments, a name and a number for<br />

the age. The program will add the specified person.<br />

— "DEL" or "AGE" must be followed by one more argument, a name. The<br />

program will delete or retrieve the name <strong>of</strong> the specified person.<br />

The initialization also changes the callback pointer for the deferred operation from<br />

the generated template function to the application-defined callback function.<br />

//Crosscall client for Person interface<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include "person_stub_c.h"<br />

#include "person_cb_c.h"<br />

144 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

static ix_task* _p_idl_ixa_c_clientTestTask = 0;<br />

static ix_cap* _p_idl_ixa_c_clientTestCap = 0;<br />

static ix_ossl_thread_t _Thread = 0;<br />

static ix_base_t* pToken = 0;<br />

static int responseReceived = 0;<br />

ix_error our_Person_deletePerson_cb(ix_base_t* basep,<br />

ix_error anError, int _return_int);<br />

static ix_error idl_thread_run(void* cookie, void** dummy)<br />

{<br />

ix_error err = 0;<br />

(void)dummy;<br />

ix_error_init(16, 128);<br />

fprintf(stderr,"Communication thread started!\n");<br />

err = ix_cap_loop((ix_cap*)cookie);<br />

if((err != 0) && !ix_error_is(err, 0, IX_ERROR_STOP))<br />

ix_error_dump(stderr,err);<br />

return err;<br />

}<br />

//Callback function for deferred op, based on generated template<br />

ix_error our_Person_deletePerson_cb (ix_base_t* basep,<br />

ix_error anError, int _return_int)<br />

{<br />

static const char localFunctionName[] =<br />

"our_Person_deletePerson_cb";<br />

ix_error err = 0;<br />

(void)basep;<br />

if(anError)<br />

{<br />

responseReceived = 1;<br />

return anError;<br />

}<br />

if(_return_int >= 0)<br />

fprintf(stderr, "%s - deletePerson operation has been<br />

successful!\n", localFunctionName);<br />

else<br />

fprintf(stderr, "%s - deletePerson operation failed!\n",<br />

localFunctionName);<br />

}<br />

responseReceived = 1;<br />

return err;<br />

static ix_error idl_client_init(int argc, char** argv)<br />

{<br />

static char localFunctionName[]="idl_client_init";<br />

ix_error err = 0;<br />

CB_VMT_Person* pCBVMT = 0;<br />

int aResult = 0;<br />

ix_error threadError = 0;<br />

Crosscall Example 145<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

void* context;<br />

if (argc


Writing the Crosscall Client<br />

}<br />

goto err_label1;<br />

memset(pToken,0,size<strong>of</strong>(ix_base_t));//init token memory<br />

//call generated interface initialization function<br />

err = stub_Person_init (pToken, _p_idl_ixa_c_clientTestCap);<br />

if(err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s :: stub_Person_init failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

}<br />

err = ix_oms_connect(pToken, argv[1]);//connect to server<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - ix_oms_connect failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

err = ix_oms_wait_connected(pToken);<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - ix_oms_wait_connected failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

//Specify the externally defined callback function<br />

err = getCBVMT_Person(pToken, &pCBVMT);<br />

if(err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

" getCBVMT_Person function failed!\n");<br />

goto err_label1;<br />

}<br />

pCBVMT->_pCB_Person_deletePerson =<br />

our_Person_deletePerson_cb;<br />

return err;<br />

err_label1:<br />

/* Shutdown */<br />

/* signal the cap to clean-up and exit */<br />

err = ix_cap_shutdown(_p_idl_ixa_c_clientTestCap, &aResult);<br />

if(err || aResult)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - ix_cap_shutdown failed!\n",<br />

localFunctionName);<br />

Crosscall Example 147<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

};<br />

err = ix_ossl_wait_for_thread(_Thread, &threadError,<br />

&context);<br />

ix_ossl_kill_thread(_Thread);<br />

if(_p_idl_ixa_c_clientTestTask!=0)<br />

{<br />

ix_error err1 = 0;<br />

err1 = ix_task_fini(_p_idl_ixa_c_clientTestTask);<br />

if (err1)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_task_fini failed!\n",<br />

localFunctionName);<br />

};<br />

free(_p_idl_ixa_c_clientTestTask);<br />

_p_idl_ixa_c_clientTestTask = 0;<br />

_p_idl_ixa_c_clientTestCap = 0;<br />

}<br />

if(pToken!=0)<br />

{<br />

free(pToken);<br />

pToken = 0;<br />

}<br />

}<br />

return err;<br />

static ix_error idl_client_fini(void) //clean up<br />

{<br />

static char localFunctionName[]="idl_client_fini";<br />

ix_error err = 0;<br />

int aResult = 0;<br />

ix_error threadError = 0;<br />

void* context;<br />

err = ix_oms_disconnect(pToken);//disconnect from server<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - ix_oms_disconnect failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

}<br />

err = ix_oms_wait_disconnected(pToken);<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - ix_oms_wait_disconnected failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

}<br />

148 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

err = stub_Person_fini (pToken);// interface termination fn<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - stub_Person_fini failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

}<br />

err_label1:<br />

/* Shutdown */<br />

/* signal the cap to clean-up and exit */<br />

err = ix_cap_shutdown(_p_idl_ixa_c_clientTestCap, &aResult);<br />

if(err || aResult)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - ix_cap_shutdown failed!\n",<br />

localFunctionName);<br />

goto thread_shutdown;<br />

};<br />

err = ix_ossl_wait_for_thread(_Thread, &threadError,<br />

&context);<br />

thread_shutdown:<br />

ix_ossl_kill_thread(_Thread);<br />

if(_p_idl_ixa_c_clientTestTask!=0)<br />

{<br />

ix_error err1 = 0;<br />

err1 = ix_task_fini(_p_idl_ixa_c_clientTestTask);<br />

if (err1)<br />

{<br />

return ix_error_new(0,0,err,<br />

"%s - ix_task_fini failed!\n",<br />

localFunctionName);<br />

};<br />

free(_p_idl_ixa_c_clientTestTask);<br />

};<br />

}<br />

return err;<br />

static ix_error addPerson(const char* aName,<br />

unsigned short anAge)<br />

{<br />

static char localFunctionName[]="addPerson";<br />

ix_error err = 0;<br />

Person_person_Entry anEntry;<br />

err = init_Person_person_Entry(&anEntry);<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - init_Person_person_Entry failed!\n",<br />

Crosscall Example 149<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

anEntry.name = strdup(aName);<br />

anEntry.age = anAge;<br />

//call generated stub function<br />

err = stub_Person_addPerson(pToken,&anEntry);<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - stub_Person_addPerson failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

fprintf(stderr, "%s added to the database!\n",<br />

aName);<br />

err_label1:<br />

{<br />

ix_error err1 = 0;<br />

err1 = fini_Person_person_Entry(&anEntry);<br />

if (err1)<br />

{<br />

err = ix_error_new(0,0,err1,<br />

"%s - fini_Person_person_Entry failed!\n",<br />

localFunctionName);<br />

}<br />

}<br />

return err;<br />

}<br />

static ix_error getAge (const char* aName,<br />

unsigned short* anAge)<br />

{<br />

static char localFunctionName[]="getAge";<br />

ix_error err = 0;<br />

//call generated stub function<br />

err = stub_Person_getAge (pToken, aName, anAge);<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - stub_Person_getAge failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

}<br />

if(*anAge == 0)<br />

fprintf(stderr, "%s is not in the database!\n",aName);<br />

else<br />

fprintf(stderr, "%s is %hu years old!\n",aName, *anAge);<br />

150 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Client<br />

err_label1:<br />

}<br />

return err;<br />

static ix_error deletePerson(const char* aName)<br />

{<br />

static char localFunctionName[]="deletePerson";<br />

ix_error err = 0;<br />

//call generated stub function<br />

err = stub_Person_deletePerson(pToken,aName);<br />

if (err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - stub_Person_deletePerson failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

}<br />

/* Wait to receive the callback response */<br />

while(!responseReceived)<br />

{<br />

sleep(1);<br />

}<br />

err_label1:<br />

return err;<br />

}<br />

static void idl_client_cleanup(ix_error anError)<br />

{<br />

if (anError)<br />

ix_error_dump(stderr,anError);<br />

ix_error_fini();<br />

}<br />

int main(int argc, char** argv)<br />

{<br />

int exitStatus = 0;<br />

ix_error err = 0;<br />

ix_error_init(16, 128);<br />

err = idl_client_init(argc, argv);<br />

if (err)<br />

{<br />

exitStatus = -1;<br />

goto err_label_1;<br />

}<br />

if(strcmp(argv[2],"ADD") == 0)<br />

{<br />

unsigned short age = 1;<br />

if(argc>4)<br />

Crosscall Example 151<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

age = atoi(argv[4]);<br />

err = addPerson(argv[3],age);<br />

if (err)<br />

{<br />

exitStatus = -2;<br />

goto err_label_1;<br />

};<br />

}<br />

else if(strcmp(argv[2],"DEL") == 0)<br />

{<br />

err = deletePerson(argv[3]);<br />

if (err)<br />

{<br />

exitStatus = -2;<br />

goto err_label_1;<br />

}<br />

}<br />

else if(strcmp(argv[2],"AGE") == 0)<br />

{<br />

unsigned short age;<br />

err = getAge(argv[3],&age);<br />

if (err)<br />

{<br />

exitStatus = -2;<br />

goto err_label_1;<br />

}<br />

}<br />

else<br />

{<br />

fprintf(stderr, "Invalid command!\n");<br />

exitStatus = -2;<br />

goto err_label_1;<br />

}<br />

err_label_1:<br />

err = idl_client_fini();<br />

if (err)<br />

{<br />

exitStatus = -3;<br />

idl_client_cleanup(err);<br />

}<br />

idl_client_cleanup(err);<br />

}<br />

return exitStatus;<br />

Writing the Crosscall Server<br />

The crosscall server implements the crosscall operations, basing them on the template<br />

functions provided by the <strong>IXA</strong> IDL compiler. In this example, the server is an <strong>ACE</strong>,<br />

so it also defines the standard <strong>ACE</strong> initialization and termination functions, ix_init<br />

and ix_fini.<br />

152 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

This example creates a database <strong>of</strong> persons, building a double linked list (sorted by<br />

name) in which to keep all the entries received from clients. It implements the three<br />

operations by adding the new entries to the list, deleting them or getting the person’s<br />

age if it is in the list.<br />

It then uses the generated VMT accessor to change the vector table to point to the<br />

correct implementation functions (rather than the default, the generated template<br />

functions). Using this technique, different servers that implement the same interface<br />

in the same process can have different behavior. You could also change the behavior<br />

at run time, based on an external trigger, by changing the vector table to point to<br />

different function implementations.<br />

The server code uses the generated initialization function from the<br />

skeleton to initialize the server side <strong>of</strong> the crosscall connection,<br />

and uses the generated termination function to terminate the<br />

connection and free resources.<br />

#include <br />

#include <br />

#include <br />

#include "person_sk_c.h"<br />

#include "person_cc_c.h"<br />

int addPersonEntry(const char* name, unsigned short age);<br />

int getPersonsAge(const char* name,unsigned short* pAge);<br />

int deletePersonEntry(const char* name);<br />

ix_error our_Person_addPerson(ix_base_t* basep,<br />

const Person_person_Entry* aPerson);<br />

ix_error our_Person_getAge(ix_base_t* basep, const char* aName,<br />

unsigned short* _return_val);<br />

ix_error our_Person_deletePerson(ix_base_t* basep,<br />

const char* aName, int* _return_val);<br />

int removeEntries(void);<br />

typedef struct _PersonEntry PersonEntry;<br />

/***********************************************************<br />

** Data structure and helper functions for manipulating it<br />

************************************************************/<br />

struct _PersonEntry<br />

{<br />

const char* name;<br />

unsigned short age;<br />

PersonEntry* next;<br />

PersonEntry* prev;<br />

};<br />

static PersonEntry* _personList = 0;<br />

int addPersonEntry(const char* name, unsigned short age)<br />

{<br />

PersonEntry* pEntry = _personList;<br />

PersonEntry* pPrevEntry = 0;<br />

PersonEntry* pNewEntry = 0;<br />

int res = 0;<br />

Crosscall Example 153<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

}<br />

int pos;<br />

for(pos = 0; pEntry != 0; pEntry = pEntry->next, pos++)<br />

{<br />

res = strcmp(pEntry->name,name);<br />

if(res == 0)<br />

return -1;<br />

else if(res < 0)<br />

{<br />

pPrevEntry = pEntry;<br />

continue;<br />

}<br />

else<br />

break;<br />

}<br />

pNewEntry = malloc(size<strong>of</strong>(PersonEntry));<br />

if(pNewEntry == 0)<br />

return -2;<br />

memset(pNewEntry,0,size<strong>of</strong>(PersonEntry));<br />

pNewEntry->name = strdup(name);<br />

pNewEntry->age = age;<br />

if(pos == 0)<br />

{<br />

pNewEntry->next = _personList;<br />

if(_personList != 0)<br />

_personList->prev = pNewEntry;<br />

_personList = pNewEntry;<br />

}<br />

else<br />

{<br />

if(pEntry == 0)<br />

{<br />

pNewEntry->prev = pPrevEntry;<br />

pPrevEntry->next = pNewEntry;<br />

}<br />

else<br />

{<br />

pNewEntry->next = pEntry;<br />

pNewEntry->prev = pEntry->prev;<br />

pEntry->prev = pNewEntry;<br />

if(pNewEntry->prev != 0)<br />

pNewEntry->prev->next = pNewEntry;<br />

}<br />

}<br />

return pos;<br />

int getPersonsAge(const char* name,unsigned short* pAge)<br />

{<br />

PersonEntry* pEntry = _personList;<br />

int pos;<br />

int res;<br />

*pAge = 0;<br />

for(pos = 0; pEntry != 0; pEntry = pEntry->next, pos++)<br />

{<br />

res = strcmp(pEntry->name,name);<br />

154 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

}<br />

if(res == 0)<br />

{<br />

*pAge = pEntry->age;<br />

return pos;<br />

}<br />

else if(res > 0)<br />

return -1;<br />

};<br />

return -1;<br />

int deletePersonEntry(const char* name)<br />

{<br />

PersonEntry* pEntry = _personList;<br />

int res = 0;<br />

int pos;<br />

for(pos = 0; pEntry != 0; pEntry = pEntry->next, pos++)<br />

{<br />

res = strcmp(pEntry->name,name);<br />

if(res == 0)<br />

{<br />

if(pEntry->prev != 0)<br />

pEntry->prev->next = pEntry->next;<br />

else<br />

_personList = pEntry->next;<br />

if(pEntry->next != 0)<br />

pEntry->next->prev = pEntry->prev;<br />

free(pEntry);<br />

return pos;<br />

}<br />

else if(res < 0)<br />

continue;<br />

else<br />

break;<br />

};<br />

return -1;<br />

}<br />

int removeEntries()<br />

{<br />

PersonEntry* pEntry = _personList;<br />

for(; _personList != 0; pEntry = _personList)<br />

{<br />

_personList = _personList->next;<br />

free(pEntry);<br />

};<br />

return 0;<br />

}<br />

static ix_base_t* pToken = 0;<br />

/************************************<br />

** Definition <strong>of</strong> crosscall template function for<br />

** Person::addPerson operation<br />

**************************************/<br />

Crosscall Example 155<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

ix_error our_Person_addPerson(ix_base_t* basep,<br />

const Person_person_Entry* aPerson)<br />

{<br />

static const char localFunctionName[] =<br />

"our_Person_addPerson";<br />

ix_error err = 0;<br />

(void) basep;<br />

if(addPersonEntry(aPerson->name,aPerson->age) < 0)<br />

fprintf(stderr, "%s - addPersonEntry failed!\n",<br />

localFunctionName);<br />

}<br />

return err;<br />

/************************************<br />

** Definition <strong>of</strong> crosscall template function for<br />

** Person::getAge operation<br />

***************************************/<br />

ix_error our_Person_getAge (ix_base_t* basep,<br />

const char* aName,<br />

unsigned short* _return_val)<br />

{<br />

static const char localFunctionName[] = "our_Person_getAge";<br />

ix_error err = 0;<br />

(void) basep;<br />

if(getPersonsAge(aName, _return_val) < 0)<br />

fprintf(stderr, "%s - getPersonsAge failed!\n",<br />

localFunctionName);<br />

}<br />

return err;<br />

/************************************<br />

** Definition <strong>of</strong> crosscall template function for<br />

** Person::deletePerson operation<br />

***********************************/<br />

ix_error our_Person_deletePerson(ix_base_t* basep,<br />

const char* aName,<br />

int* _return_val)<br />

{<br />

static const char localFunctionName[] =<br />

"Person_deletePerson";<br />

ix_error err = 0;<br />

(void) basep;<br />

*_return_val = deletePersonEntry(aName);<br />

if(*_return_val < 0)<br />

fprintf(stderr, "%s - deletePersonEntry failed!\n",<br />

localFunctionName);<br />

return err;<br />

156 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

}<br />

/************************************<br />

** <strong>ACE</strong> initialization<br />

***********************************/<br />

ix_error ix_init(int argc, char** argv, ix_ace** acepp)<br />

{<br />

static char localFunctionName[] = "ix_init";<br />

ix_error err = 0;<br />

ix_ace* pAce = 0;<br />

ix_cap* capp = 0;<br />

CC_VMT_Person* pCCVMT = 0;<br />

if (argc


Writing the Crosscall Server<br />

/* Initialize the token for the Person interface */<br />

err = sk_Person_init (pToken, capp);<br />

if(err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s - Token initialization failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

/* Retrieve the cross call VMT */<br />

err = getCCVMT_Person(pToken, &pCCVMT);<br />

if(err)<br />

{<br />

err = ix_error_new(0,0,err,<br />

"%s :: getCCVMT_Person failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

/* Point crosscall vectors to implemented functions */<br />

pCCVMT->_pCC_Person_addPerson = our_Person_addPerson;<br />

pCCVMT->_pCC_Person_getAge = our_Person_getAge;<br />

pCCVMT->_pCC_Person_deletePerson = our_Person_deletePerson;<br />

*acepp = pAce;<br />

fprintf(stderr,"%s: ace communication is initialized!\n",<br />

localFunctionName);<br />

return err;<br />

err_label1:<br />

if(pAce != 0)<br />

{<br />

/* Finalize the ix_ace structure*/<br />

err = ix_ace_fini(pAce);<br />

if (err)<br />

{<br />

err = ix_error_new(IX_ERROR_LEVEL_LOCAL,<br />

IX_ERROR_NULL, err,<br />

"%s: ix_ace_fini failed!\n", localFunctionName);<br />

};<br />

}<br />

free(pAce);<br />

pAce = 0;<br />

};<br />

if(pToken != 0)<br />

{<br />

free(pToken);<br />

pToken = 0;<br />

};<br />

return err;<br />

158 Crosscall Example<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

// <strong>ACE</strong> termination<br />

ix_error ix_fini(int argc, char** argv, ix_ace* pAce)<br />

{<br />

static char localFunctionName[]="ix_fini";<br />

ix_error err = 0;<br />

(void) argc;<br />

(void) argv;<br />

err = sk_Person_fini (pToken);<br />

if (err)<br />

{<br />

err = ix_error_new(0, 0, err,<br />

"%s: Token finalization failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

/* Cleanup the _personList */<br />

removeEntries();<br />

err_label1:<br />

/* Free the ix_ace structure */<br />

if (pAce != 0)<br />

{<br />

/* Finalize the ix_ace structure*/<br />

err = ix_ace_fini(pAce);<br />

if (err)<br />

{<br />

err = ix_error_new(IX_ERROR_LEVEL_LOCAL,<br />

IX_ERROR_NULL, err,<br />

"%s: ix_ace_fini failed!\n",<br />

localFunctionName);<br />

};<br />

free(pAce);<br />

}<br />

free(pAce);<br />

/* Free the token structure */<br />

if(pToken != 0)<br />

free(pToken);<br />

}<br />

fprintf(stderr, "%s: ix_fini called. Cleaned up!\n",<br />

localFunctionName);<br />

return err;<br />

Terminating<br />

the Server<br />

The following code defines a clean termination for the interface in the server.<br />

static char localFunctionName[]="ix_fini";<br />

ix_error err = 0;<br />

(void) argc;<br />

(void) argv;<br />

Crosscall Example 159<br />

Revision 3.3, August 2001


Writing the Crosscall Server<br />

/* Call the generated termination function */<br />

err = sk_Person_fini (pToken);<br />

if (err)<br />

{<br />

err = ix_error_new(0, 0, err,<br />

"%s: Token finalization failed!\n",<br />

localFunctionName);<br />

goto err_label1;<br />

};<br />

/* Clean up the _personList */<br />

removeEntries();<br />

err_label1:<br />

/* Free the ix_ace structure */<br />

if (pAce != 0)<br />

{<br />

/* Terminate the <strong>ACE</strong> */<br />

err = ix_ace_fini(pAce);<br />

if (err)<br />

{<br />

err = ix_error_new(IX_ERROR_LEVEL_LOCAL,<br />

IX_ERROR_NULL, err,<br />

"%s: ix_ace_fini failed!\n",<br />

localFunctionName);<br />

};<br />

free(pAce);<br />

}<br />

/* Free the token structure */<br />

if(pToken != 0)<br />

free(pToken);<br />

fprintf(stderr, "%s: ix_fini called. Cleaned up!\n",<br />

localFunctionName);<br />

return err;<br />

160 Crosscall Example<br />

Revision 3.3, August 2001


Chapter 13<br />

Using Sets <strong>of</strong> Data to Classify Packets<br />

This chapter describes sets and searches, which you can use to classify packets based<br />

on their contents; that is, the values <strong>of</strong> fields. Sets are an efficient way to track a large<br />

number <strong>of</strong> classes <strong>of</strong> packets.<br />

This chapter contains the following topics:<br />

l “Overview <strong>of</strong> Sets and Searches” on page 161<br />

l “When to Use Sets” on page 162<br />

l “Defining Sets and Searches” on page 162<br />

l “How to Use Sets and Searches” on page 167<br />

Overview <strong>of</strong> Sets and Searches<br />

You can define data tables called sets that associate any arbitrary application-defined<br />

data with packets. For each set, you define one or more named searches that determine<br />

whether the current packet has a matching element in the set, based on the values <strong>of</strong><br />

specified fields.<br />

A set is a collection <strong>of</strong> elements where each element has a header <strong>of</strong> one or more keys,<br />

and contains a pointer to any arbitrary data that you define. A search matches the key<br />

values in the header with the values <strong>of</strong> specific fields in an incoming packet. When<br />

all the values match, you can take an action with regard to the matching element; for<br />

example, add to a counter, or access and save another field value in the packet.<br />

When a search does not match any element with the incoming packet, you have the<br />

option <strong>of</strong> adding a new element to the set.<br />

Revision 3.3, August 2001<br />

Using Sets <strong>of</strong> Data to Classify Packets 161


When to Use Sets<br />

When to Use Sets<br />

You use sets to define collections <strong>of</strong> packets that are associated with each other by<br />

virtue <strong>of</strong> their contents. They allow you to keep state information for all packets that<br />

have the same values in specific fields. If you want to form collections on structural<br />

criteria, such as “the set <strong>of</strong> all packets with IP header lengths greater than twenty<br />

bytes,” use a classification predicate rather than a searchable set.<br />

You can take any kind <strong>of</strong> action you want as a result <strong>of</strong> the set classification. For<br />

example, you can count packets going to or from each address, keeping the counters<br />

as set data. You can set targets for packets based on their set membership, add<br />

members to or delete members from the set, or create messages from the packets or<br />

the set data and pass them to other <strong>ACE</strong>s or programs using crosscalls.<br />

You can use sets to associate application data with packets. For example, you can<br />

initialize a set with a list <strong>of</strong> interesting addresses, in order to classify all packets that<br />

come from or go to those addresses. One search might compare the ip.src field <strong>of</strong><br />

packets to the elements <strong>of</strong> the set, to identify any packets that come from one <strong>of</strong> the<br />

addresses. Another search could compare the ip.dest field to the addresses, to identify<br />

packets that are going to them.<br />

You can also use sets to collect new data about packet flow. For example, you can start<br />

with an empty set, and, for each incoming packet that does not already have a<br />

matching set element, create a new set element using its ip.src value, and add it to<br />

the set. When an incoming packet does match, you can increment a counter in the<br />

matching element. In this way, you can keep track <strong>of</strong> the sources <strong>of</strong> all packets coming<br />

through the <strong>ACE</strong>.<br />

Defining Sets and Searches<br />

Use NCL to declare the name and suggest the size <strong>of</strong> a set, and to define the searches<br />

that evaluate set membership. Declare a corresponding C structures for the set in the<br />

<strong>ACE</strong> initialization code. You modify the contents <strong>of</strong> sets using actions. See “Initializing<br />

and Populating Sets” on page 165.<br />

Defining Sets<br />

in NCL<br />

Use the set keyword to declare, name, and define a set in NCL. You provide the<br />

number <strong>of</strong> keys, and suggest a size for the set. For each set, you can define any<br />

number <strong>of</strong> searches, using the search keyword. Each search is associated with one<br />

and only one set, and you name it using the form setname.searchname. You specify<br />

a requires clause in the search. If this Boolean expression succeeds, the search is<br />

executed, and if it fails the search is not executed.<br />

Each search definition specifies the exact number <strong>of</strong> keys that you specified for the<br />

set, and associates each key with a protocol field. When the search is executed, the<br />

<strong>ACE</strong> runtime compares the value <strong>of</strong> the specified protocol field in the current packet<br />

to the value <strong>of</strong> the corresponding key for each element in the set. If all <strong>of</strong> the field<br />

values in the packet match the key values in an element, the search succeeds, and<br />

keeps a pointer to the matching element.<br />

162 Using Sets <strong>of</strong> Data to Classify Packets<br />

Revision 3.3, August 2001


Defining Sets and Searches<br />

You can use a search in a rule or an action, referring to it by the name,<br />

setname.searchname. When you refer to it by name, you are actually referring to<br />

the result <strong>of</strong> the search, which the <strong>ACE</strong> runtime obtains when it parses the search<br />

definition for an incoming packet. A search can have one <strong>of</strong> the following results:<br />

l<br />

l<br />

l<br />

The search did not run because the requirements were not met.<br />

The search ran and found a matching element.<br />

The search ran and did not find a matching element.<br />

Example<br />

The following NCL example defines a set named setIP that has 2 keys, and two<br />

searches in that set that compare each <strong>of</strong> the keys to fields in the IP protocol. The<br />

searches are only executed for IP packets.<br />

l<br />

l<br />

The search setIP.key1 identifies a set element where the first key matches an IP<br />

packet’s destination address (the field ip.dst).<br />

The search setIP.key2 identifies a set element where the second key matches an<br />

IP packet’s source address (the field ip.src).<br />

Rules invoke one <strong>of</strong> two action functions, passing additional values as required by<br />

the action definition, including the search used.<br />

l<br />

l<br />

When a matching element is found for either key, the action increments a counter<br />

in the element.<br />

When no matching element is found for either key, the action inserts an element<br />

into the set to match the current packet.<br />

//<br />

// A simple application to count the packets<br />

//<br />

// countncl.ncl<br />

//<br />

#include "ix_tcpip.ncl"<br />

Using Sets <strong>of</strong> Data to Classify Packets 163<br />

Revision 3.3, August 2001


Defining Sets and Searches<br />

set setIP<br />

{<br />

size_hint { 256 }<br />

}<br />

search setIP.key1(ip.dst)<br />

{<br />

requires{ ip }<br />

}<br />

search setIP.key2(ip.src)<br />

{<br />

requires{ ip }<br />

}<br />

predicate insertDst { ip && (! setIP.key1) }<br />

predicate insertSrc { ip && (! setIP.key2) }<br />

rule found1 { setIP.key1 }<br />

{ incrementSetElement(1, ip.dst, setIP.key1) }<br />

rule found2 { setIP.key2 }<br />

{ incrementSetElement(2, ip.src, setIP.key2) }<br />

rule new3 { insertDst }<br />

{ insertSetElement(3, ip.dst, setIP.key1) }<br />

rule new4 { insertSrc }<br />

{ insertSetElement(4, ip.src, setIP.key2) }<br />

For More Information<br />

For more information on defining sets and searches in NCL, see Chapter 6, “Network<br />

Classification Language (NCL),” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Defining Sets<br />

in ASL<br />

To use the sets and searches that you define in NCL, your <strong>ACE</strong> initialization code<br />

must include a header file containing set structure declarations that match the NCL<br />

definitions. The <strong>ACE</strong> initialization function must create each set structure using the<br />

ASL function ix_set_new.<br />

The set structure is created on initialization <strong>of</strong> the <strong>ACE</strong>. A mismatch between the<br />

NCL and ASL declarations results in a run-time error.<br />

Action code in the <strong>ACE</strong> can reuse an existing set structure for another set <strong>of</strong> the same<br />

size or smaller by using the function ix_set_init. Again, if the reinitialization does<br />

not match the set’s NCL declaration, a run-time error results.<br />

Example<br />

The following code fragment is part <strong>of</strong> the <strong>ACE</strong> initialization code. It extends the<br />

<strong>ACE</strong> structure to contain a set, and later creates the set as part <strong>of</strong> the <strong>ACE</strong>:<br />

//extend <strong>ACE</strong> structure to include set<br />

struct ace1<br />

{<br />

ix_ace base_ace;<br />

164 Using Sets <strong>of</strong> Data to Classify Packets<br />

Revision 3.3, August 2001


Initializing and Populating Sets<br />

ix_set *setp; // creates set when creating the <strong>ACE</strong><br />

}<br />

...<br />

// on creation, name setIP links it to the NCL<br />

ix_set_new (&acep->setp, 1, 256, "setIP", &acep->ace);<br />

Initializing and Populating Sets<br />

Creating the set structure does not generate any elements with which to populate it.<br />

You can populate a set with an initial set <strong>of</strong> elements, then later add or delete<br />

elements using actions, or you can populate it entirely through actions.<br />

In the action code for the <strong>ACE</strong>, define the action functions invoked by the NCL rules<br />

to retrieve data from a set or place data in a set, based on the results <strong>of</strong> searches.<br />

l<br />

l<br />

l<br />

To create an element, use the ASL function ix_element_new, then initialize the<br />

key values using the function ix_element_init_keys. To associate application<br />

data with the element, access the ix_element->user_info field directly.<br />

To insert the new element in a set, use the function ix_set_insert_element, or<br />

extract the insertion location from the search result, and pass it to the function<br />

ix_set_insert_at_location.<br />

To remove the element from the set, use the function ix_set_remove_element or<br />

ix_set_remove_at_location.<br />

— You can reuse an element that you have removed from a set by reinitializing<br />

the keys.<br />

— You can reuse a removed element in a different set by using the function<br />

ix_element_init, then reinitializing the keys.<br />

Example<br />

The action code for the <strong>ACE</strong> defines the four action functions invoked by the rules.<br />

Each action requires three arguments in addition to the two passed automatically.<br />

The rules pass these additional values to the action on invocation.<br />

// utility fn to construct print string from search result<br />

void my_search_result (ix_search *rsltp, char *buf)<br />

{<br />

switch (ix_set_get_search_result (rsltp)) {<br />

case NOT_RUN:<br />

sprintf(buf, "ix_search = %p, NOT_RUN", rsltp);<br />

break;<br />

case MISS:<br />

sprintf(buf, "ix_search = %p, MISS", rsltp);<br />

break;<br />

case HIT:<br />

sprintf(buf, "ix_search = %p, HIT", rsltp);<br />

break;<br />

default:<br />

my_error_handler((ix_error) 0, "my_search_result failed.");<br />

}<br />

}<br />

Revision 3.3, August 2001<br />

Using Sets <strong>of</strong> Data to Classify Packets 165


Initializing and Populating Sets<br />

//<br />

// ACTION FUNCTION DEFINITIONS<br />

//<br />

int incrementSetElement (ix_ace *ace, ix_buffer buf,<br />

int rule,<br />

int key,<br />

ix_search *rsltp)<br />

{<br />

ix_element *elemp;<br />

int *myData;<br />

char cbuf[128];<br />

my_search_result(rsltp, cbuf);<br />

printf("\t%d) incrementSetElement(%d, 0x%x, %s)\n",<br />

count, rule, key, cbuf);<br />

elemp = ix_set_get_element_from_search_obj(rsltp);<br />

myData = (int*) elemp->user_data;<br />

*myData += 1;<br />

}<br />

return 0;<br />

int insertSetElement(ix_ace *ace, ix_buffer buf,<br />

int rule,<br />

int key,<br />

ix_search *rsltp)<br />

{<br />

ix_element *elemp;<br />

ix_error err;<br />

int *myData;<br />

char cbuf[128];<br />

ace1 *myAce = (ace1*) ace;<br />

ix_set *setIPp = myAce->setIPp;<br />

my_search_result(rsltp, cbuf);<br />

printf("\t%d) insertSetElement(%d, 0x%x, %s)\n",<br />

count, rule, key, cbuf);<br />

err = ix_element_new(&elemp, 1);<br />

if (err) my_error_handler(err, "ix_element_new(&elemp, 1)");<br />

err = ix_element_init_keys(elemp, 1, key);<br />

if (err) my_error_handler(err,<br />

"ix_element_init_keys(elemp, 1, key)");<br />

myData = (int*) malloc(size<strong>of</strong>(int));<br />

*myData = 1;<br />

elemp->user_data = (void*) myData;<br />

166 Using Sets <strong>of</strong> Data to Classify Packets<br />

Revision 3.3, August 2001


How to Use Sets and Searches<br />

err = ix_set_insert_at_location(setIPp, rsltp, elemp);<br />

if (err) my_error_handler(err,<br />

"ix_set_insert_at_location(setIPp, rsltp, elemp)");<br />

}<br />

return 0;<br />

For More Information<br />

For more information on creating and using sets in ASL, see Chapter 4, “The ASL<br />

Core Support Package API,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

How to Use Sets and Searches<br />

The <strong>ACE</strong> runtime executes searches when it runs the classification code for an<br />

incoming packet. For each incoming packet, the <strong>ACE</strong> runtime tries every search<br />

defined in the NCL file. If the requires clause succeeds, the <strong>ACE</strong> runtime executes<br />

the search and stores the result in the corresponding ASL set object.<br />

You can also use the ASL set search functions to initiate a search anywhere in your<br />

action code. For example, you might want to initiate a search in response to an event<br />

or a message.<br />

Using<br />

Searches in<br />

Rules<br />

You can refer to a search by name on either side <strong>of</strong> a rule. How it is used depends on<br />

which side <strong>of</strong> the rule it is on.<br />

l<br />

l<br />

When used on the left side <strong>of</strong> a rule as part <strong>of</strong> the predicate, the search name acts<br />

as a Boolean expression. It succeeds when the search was executed and found a<br />

matching record in the set. If the search was not executed because the requirements<br />

were not met, or if it was executed but failed to find a matching element,<br />

the expression evaluates to FALSE.<br />

When you pass a search name as an action argument on the right side <strong>of</strong> a rule,<br />

the action can use the passed search object to obtain the result <strong>of</strong> the search (HIT,<br />

MISS, or NOT_RUN), and either the found element or a location at which to insert a<br />

new element in the set.<br />

Using Actions<br />

to Modify Sets<br />

When a rule passes a search name to an action, the action function receives a search<br />

object. This object contains:<br />

l<br />

l<br />

l<br />

The result <strong>of</strong> the search, one <strong>of</strong> the constants HIT, MISS, or NOT_RUN. Use the function<br />

ix_set_get_search_result to extract this value.<br />

If the search was successful (that is, the result is HIT), the search object contains<br />

the found element.<br />

If the search was unsuccessful (that is, the result is MISS), the search object<br />

contains a location at which to insert a new element in the set.<br />

Using Sets <strong>of</strong> Data to Classify Packets 167<br />

Revision 3.3, August 2001


How to Use Sets and Searches<br />

Use the function ix_set_get_element_from_search_obj to extract the element or<br />

insertion location. If the search was not run (that is, the result is NOT_RUN), this function<br />

returns NULL.<br />

You can take actions based on the fact <strong>of</strong> a search succeeding or failing, without<br />

regard for the data portion <strong>of</strong> the set element. For example, an action can simply set<br />

the target for the packet based on whether one <strong>of</strong> the searches succeeds.<br />

An action function can also modify a set element by changing its associated data. For<br />

example, when you have identified a packet that is coming from one <strong>of</strong> the interesting<br />

addresses, you can increment a counter in the matching element.<br />

You can look at or copy the data in a matching element, and take actions based on that<br />

data. For example, after a packet comes in from a particular address and you have<br />

incremented the counter in the matching element, you can check whether the counter<br />

has reached a certain value. If it has, you can build a message from it and send it to<br />

the host application in an upcall.<br />

An action function can create a new set element, using the search result’s insertion<br />

location. It can also delete a set element, directly or after a delay. To delay an action<br />

on an element, make the action function schedule an event, and delete the element in<br />

the event callback function.<br />

For more information on set, element, and event manipulation, see Chapter 4, “The<br />

ASL Core Support Package API,” in the <strong>IXA</strong> <strong>SDK</strong> Reference.<br />

Deleting Sets<br />

Use the function ix_set_delete to delete a set and all remaining elements.<br />

To simply remove the set elements without destroying them, use the function<br />

ix_set_foreach to walk through the set.<br />

168 Using Sets <strong>of</strong> Data to Classify Packets<br />

Revision 3.3, August 2001


Index<br />

A<br />

<strong>ACE</strong> 5<br />

accelerated 7<br />

action code part 105<br />

binding 38<br />

blocking not allowed in 120, 124<br />

C structure 5, 106<br />

classification part 99<br />

compared to task 124<br />

conventional vs. accelerated 7<br />

creating 10, 22<br />

creating C structures in 106<br />

defining behavior <strong>of</strong> 108<br />

defining packet flow for 48<br />

initializing 106<br />

languages for writing 6<br />

launching 10<br />

programmatically 46<br />

with script 38<br />

library 87<br />

L2 bridging 91<br />

L3 forwarder 89<br />

NAT 94<br />

packet processing in 5, 99<br />

packet reception 83<br />

packet transmission 85<br />

predefined 7, 87<br />

rules 101<br />

stack 88<br />

targets in 48<br />

using to receive and transmit packets 48<br />

utility functions in 109<br />

what type to use for what task 8<br />

action code 105<br />

action functions 108<br />

callbacks 108<br />

compiling 30<br />

utility functions 108<br />

see also actions, action functions<br />

action functions 5, 108<br />

interaction with rules 108<br />

predefined 109<br />

return values 108<br />

syntax 108<br />

using to create and delete set elements 167<br />

what they do 110<br />

see also actions, action code<br />

Action Services Library, see ASL<br />

actions 5<br />

executing 103<br />

using to direct packets 51<br />

using to modify sets 167<br />

using to populate and modify sets 165<br />

see also action code, action functions<br />

active computing element, see <strong>ACE</strong><br />

API overview 17<br />

applications 1<br />

building blocks 18<br />

input and output 79<br />

L2 bridging 91<br />

L3 forwarding 89<br />

NAT 94<br />

TCP/IP stack 88<br />

communicating within 113, 139<br />

compiling 29<br />

configuring and starting 35<br />

deploying 17<br />

initializing <strong>ACE</strong>s 10<br />

linking 29<br />

organization <strong>of</strong> 3<br />

types 1<br />

argument passing for crosscalls 133<br />

client side 134<br />

deferred calls 137<br />

one-way calls 136<br />

server side 135<br />

two-way calls 136<br />

ASL 17<br />

contents 106<br />

creating objects 106<br />

error codes 24<br />

predefined action functions in 109<br />

return values 24<br />

using for sets and searches 165<br />

using to write <strong>ACE</strong> initialization and action code<br />

105<br />

writing action code in 105<br />

asynchronous crosscalls 120, 121, 123<br />

handling response with callback 121<br />

specifying timeouts for 122<br />

Index 169<br />

Revision 3.3, August 2001


B<br />

bindings 48<br />

full names <strong>of</strong> targets 21<br />

interface <strong>ACE</strong>s 82<br />

L3 forwarder <strong>ACE</strong> targets 90<br />

setting in configuration file 38<br />

setting programmatically 49<br />

stack <strong>ACE</strong> targets 88<br />

static 60<br />

targets 48<br />

unbound targets 50<br />

blocking for crosscalls 120, 124<br />

building blocks 18<br />

for input and output 79<br />

for L2 bridging 91<br />

for L3 forwarding 89<br />

for network address translation 94<br />

for TCP/IP stack handling 88<br />

C<br />

.c files 30<br />

C structures in ASL 23<br />

callbacks 108<br />

defining 109<br />

for deferred crosscall operations 109, 117<br />

for scheduled events 109<br />

CAP 10<br />

using for crosscalls 115<br />

using for OMS session 21<br />

classification 99<br />

definition 2<br />

role <strong>of</strong> protocol definition 102<br />

rule evaluation 103<br />

rules 101<br />

using rules and protocol definitions 100<br />

using sets rather than rules 162<br />

clients, crosscall 114<br />

communication access process, see CAP<br />

communication between <strong>ACE</strong>s and objects 113, 139<br />

see also crosscalls<br />

compilers 20<br />

compiling 32, 33<br />

action and initialization code 30<br />

micro<strong>ACE</strong>s 32<br />

NCL 30<br />

using makefiles 33<br />

configuration files 35<br />

samples for library <strong>ACE</strong>s 39<br />

configuration scripts 35<br />

contacting <strong>Intel</strong> xii<br />

control plane 4<br />

conventional <strong>ACE</strong>, defined 7<br />

conventions, typographical xi<br />

core components 7, 55<br />

in micro<strong>ACE</strong> architecture 57<br />

writing 61<br />

core processor 14<br />

memory shared with microengines 65<br />

creating <strong>ACE</strong>s 22<br />

crosscall interfaces 12<br />

C structure 23<br />

defining 114, 116<br />

example definition 140<br />

initializing and terminating 125<br />

using to organize operations 117<br />

crosscall references 114<br />

crosscalls 12, 113<br />

and threads 124<br />

argument directions 122<br />

deferred operations 120, 121<br />

callback functions for 117, 121, 123<br />

defining callback functions 109<br />

defining operations 118<br />

example 139<br />

writing the client 144<br />

writing the server 152<br />

full names <strong>of</strong> 21<br />

implementing callback functions 117, 130<br />

implementing operations 116, 130<br />

initializing the client 125<br />

example 125<br />

initializing the server 128<br />

example 129<br />

integrating into applications 123<br />

invoking remotely 130<br />

example 131<br />

making and receiving 114<br />

making two-way calls from <strong>ACE</strong>s not allowed 120<br />

naming operations 119<br />

one-way operations 120<br />

opening a connection from the client 131<br />

organizing operations into interfaces 117<br />

passing arguments 133<br />

for deferred call 137<br />

for one-way call 136<br />

for two-way call 136<br />

on client side 134<br />

on server side 135<br />

skeletons, example 143<br />

stubs, example 140<br />

synchronous and asynchronous operations 120<br />

two-way operations 120<br />

using stub functions 130<br />

using to configure input <strong>ACE</strong> 80<br />

handling return values 84<br />

using to configure library <strong>ACE</strong>s 124<br />

using to configure micro<strong>ACE</strong>s 68<br />

when to use 115<br />

customer support xii<br />

170 Index<br />

Revision 3.3, August 2001


D<br />

data processing plane 3<br />

data sets 161<br />

data structures 161<br />

for core processor 161<br />

shared with microengines 65<br />

default targets 49<br />

deferred crosscall operations 120, 121, 123<br />

callback functions for 117, 121<br />

where callbacks are defined 109<br />

delaying actions 106<br />

deploying applications 17<br />

development environment 14<br />

development tools 18, 20, 29<br />

dispatch loop<br />

controlling packet flow 73<br />

dispatch loops 71<br />

application-defined global registers 73<br />

example 73<br />

global registers 72<br />

in micro<strong>ACE</strong> architecture 58<br />

returning values to 75<br />

writing 71<br />

disposing <strong>of</strong> packets 103<br />

dl_buffer_handle register 72<br />

dropping packets 50<br />

.dwp files 56<br />

dynamic NAT 94<br />

E<br />

elements 161<br />

adding to sets 167<br />

C structure 23<br />

deleting from sets 168<br />

searching for in sets 161<br />

embedded Linux 14<br />

embedded operating system 18<br />

environment variable IXROOT xii<br />

error codes 24<br />

event processing 106<br />

events 23<br />

C structure 23<br />

using to delay set element removal 168<br />

example applications 88<br />

exception handling in micro<strong>ACE</strong>s 62<br />

flagging in microblocks 76<br />

writing a handler 64<br />

F<br />

file types 30<br />

firewall applications 1<br />

fragments and NAT 95<br />

FTP and NAT 95<br />

G<br />

gcc compiler 30<br />

GNU toolchain 30<br />

H<br />

handler functions 108<br />

for asynchronous operations 109<br />

for micro<strong>ACE</strong> exception packets 64<br />

hardware architecture 14<br />

hardware configurations 14<br />

I<br />

ICMP errors and NAT 95<br />

.idl files 30<br />

IDL, see <strong>IXA</strong> IDL<br />

in arguments for crosscalls 122<br />

initialization 10<br />

<strong>of</strong> <strong>ACE</strong>s 22<br />

<strong>of</strong> crosscall interfaces 125<br />

<strong>of</strong> function pointers for crosscalls 130<br />

<strong>of</strong> micro<strong>ACE</strong> Resource Manager 58<br />

<strong>of</strong> OMS 21<br />

initialization functions 22<br />

for <strong>ACE</strong>s 22, 106<br />

for micro<strong>ACE</strong>s 62<br />

inout arguments for crosscalls 122<br />

input <strong>ACE</strong>s 79, 83<br />

configuring with crosscalls 80, 83<br />

handling crosscall return values 84<br />

initializing 81<br />

logicalMgmt interface 80<br />

portMgmt interface 80<br />

installation directory pathname xii<br />

<strong>Intel</strong>, contacting xii<br />

interface <strong>ACE</strong>s 79<br />

binding 82<br />

configuring with crosscalls 80<br />

initializing 81<br />

input <strong>ACE</strong> 83<br />

integrating with your application 80<br />

naming 82<br />

output <strong>ACE</strong> 85<br />

source code location 81<br />

starting 82<br />

interface definition language, see <strong>IXA</strong> IDL<br />

interfaces, see network interfaces, ports, or crosscalls,<br />

crosscall interfaces<br />

interobject communication 113, 139<br />

intrusion detection applications 1<br />

IP addresses, setting for ports 38<br />

IP masquerade (port translation) NAT 95<br />

ix_action_default function 109<br />

IX_EXCEPTION 62<br />

<strong>IXA</strong> IDL 18<br />

Index 171<br />

Revision 3.3, August 2001


syntax 118<br />

using to define crosscall interfaces 114, 116<br />

<strong>IXA</strong> IDL compiler 18, 29<br />

generated files 116<br />

IXP 1200 processor 14<br />

IXP1200 Microengine Development Environment 18<br />

IXROOT environment variable xii<br />

ixstart script 35<br />

ixsys.config file 35<br />

K<br />

key point, explanation <strong>of</strong> xi<br />

keys, set 162<br />

associating with protocol fields 162<br />

definition 161<br />

L<br />

L2 bridging library <strong>ACE</strong> 91<br />

configuring 94<br />

packet processing in 92<br />

sample configuration files 40<br />

starting 93<br />

L3 forwarder library <strong>ACE</strong> 89<br />

binding targets 90<br />

configuring 90<br />

sample configuration files 42<br />

starting 90<br />

languages for <strong>ACE</strong> development 18, 20<br />

layer three forwarding 89<br />

layer two bridging 91<br />

ld linker 30<br />

libraries, run-time 18<br />

library <strong>ACE</strong>s 87<br />

defined 7<br />

L2 bridging 91<br />

L3 forwarder 89<br />

NAT 94<br />

sample configurations files 39<br />

used in example applications 88<br />

using crosscalls to configure 124<br />

Linux 14<br />

development tools 18<br />

embedded on IXP1200 18<br />

TCP/IP stack 18, 88<br />

load balancing (virtual server) NAT 95<br />

load balancing applications 2<br />

logicalIfMgmt interface for input <strong>ACE</strong> 80<br />

M<br />

makefiles 33<br />

management plane 4<br />

management programs 22<br />

in micro<strong>ACE</strong> architecture 57<br />

memory shared between microengines and core<br />

processor 65<br />

micro<strong>ACE</strong> Resource Manager 13<br />

micro<strong>ACE</strong>s 7, 32<br />

components and terms 56<br />

configuring with crosscalls 68<br />

defining packet flow with dispatch loop 71<br />

design example 77<br />

exception handling 62, 76<br />

initializing 62<br />

launching 38<br />

library <strong>ACE</strong>s 87<br />

loading 58<br />

macros 18<br />

microcode image files 38<br />

processing pipeline 59<br />

programming model 55<br />

project files 56<br />

Resource Manager 17<br />

terminating 64<br />

transmitting packets from 75<br />

writing the core component 61<br />

microblock groups 68<br />

in micro<strong>ACE</strong> architecture 57<br />

microblocks 7, 55, 75<br />

combining into groups 68<br />

defining packet flow iwth dispatch loop 71<br />

determining packet disposition 75<br />

flagging exceptions 76<br />

in micro<strong>ACE</strong> architecture 57<br />

sink 70<br />

source 69<br />

transform 70<br />

types 69<br />

using to transmit packets 75<br />

microcode 7<br />

compiling 58<br />

development tools 18<br />

macros for micro<strong>ACE</strong>s 18<br />

using Workbench to edit 56<br />

microcode images 58<br />

specifiying files for loading 38<br />

Microengine Development Environment 18<br />

microengine toolchain 32<br />

microengines 14<br />

memory shared with core processor 65<br />

threads 37<br />

N<br />

Name Server 21<br />

synchronous and asynchronous sessions 124<br />

named searches 162<br />

naming and referencing OMS objects 21<br />

172 Index<br />

Revision 3.3, August 2001


NAT library <strong>ACE</strong>s 94<br />

binding targets 97<br />

configuring 98<br />

handling <strong>of</strong> FTP, fragments, and ICMP 95<br />

packet processing in 94<br />

sample configuration files 44<br />

starting 96<br />

NCL 18, 99<br />

compiling 30<br />

using to declare sets 162–164<br />

using to define sets and searches 100<br />

NCL compiler 18, 29<br />

.ncl files 30<br />

nclcomp compiler 29<br />

network address translation (NAT) 94<br />

Network Classification Language, see NCL 169<br />

network interfaces 2<br />

configuring 38<br />

receiving and transmitting on with interface <strong>ACE</strong>s<br />

79<br />

see also ports<br />

note, explanation <strong>of</strong> xi<br />

O<br />

.o files 30<br />

Object Management System, see OMS<br />

objects 23<br />

creating in <strong>ACE</strong> 106<br />

in an <strong>IXA</strong> application 23<br />

naming 21<br />

OMS 10<br />

Name Server 21<br />

Resolver 20<br />

services 17<br />

synchronous and asynchronous entry points 124<br />

one-way crosscall operations 120<br />

out arguments for crosscalls 122<br />

output <strong>ACE</strong>s 79, 85<br />

initializing 81<br />

output ports for packets 75<br />

P<br />

packet flow 48<br />

defining with dispatch loops 71<br />

defining with targets 48<br />

monitoring with sets 162<br />

through micro<strong>ACE</strong>s 73<br />

packets 2<br />

associating with data using sets 162<br />

classification by <strong>ACE</strong>s 99<br />

classification overview 2<br />

defining traffic flow 11<br />

through micro<strong>ACE</strong>s 59<br />

with targets 47<br />

directing to a target 51<br />

disposing <strong>of</strong> 103<br />

dropping 50<br />

forcing serial processing <strong>of</strong> 51<br />

handling with TCP/IP stack 88<br />

receiving 83<br />

receiving and transmitting with interface <strong>ACE</strong>s 79<br />

role <strong>of</strong> protocol definitions in classifying 102<br />

sets <strong>of</strong> 100<br />

setting output port 75<br />

targets as destinations for 48<br />

transferring with crosscalls vs. targets 115<br />

transmitting 85<br />

transmitting from microblocks 75<br />

using an <strong>ACE</strong> to receive and transmit 48<br />

using set searches to check addresses <strong>of</strong> 104<br />

populating sets 165<br />

port translation (IP masquerade) NAT 95<br />

portMgmt interface for input <strong>ACE</strong> 80<br />

ports 2<br />

configuring 35, 38<br />

enabling and disabling 84<br />

IP addresses 85<br />

MAC address 84<br />

managing logical configuration 85<br />

managing physical configuration 84<br />

receiving and transmitting on with interface <strong>ACE</strong>s<br />

79<br />

statistics 84<br />

predicates 100<br />

contents 101<br />

evaluating 103<br />

processing pipeline in micro<strong>ACE</strong>s 59<br />

programming interface overview 17<br />

project file, Workbench 56<br />

protocol definitions 102<br />

definition 100<br />

role in packet classification 102<br />

TCP/IP 102<br />

using to classify packets 100<br />

protocol fields 100<br />

associating with keys 162<br />

Q<br />

quality <strong>of</strong> service (QoS) applications 2<br />

R<br />

receiving packets 83<br />

reference, explanation <strong>of</strong> xi<br />

remote calls 114<br />

remote procedure invocation 113<br />

synchronous and asynchronous 120<br />

Index 173<br />

Revision 3.3, August 2001


Resolver 20<br />

communicating with 22<br />

synchronous and asynchronous sessions 124<br />

Resource Manager 13, 17<br />

API for memory management 66<br />

in micro<strong>ACE</strong> architecture 57<br />

initializing 58<br />

return values 24<br />

for action functions 108<br />

for API functions 24<br />

for crosscalls 122<br />

RMON statistical monitoring applications 1<br />

rules 5, 99<br />

action functions in 101<br />

components <strong>of</strong> 101<br />

definition 100, 101<br />

evaluating 103<br />

predicates 101<br />

using instead <strong>of</strong> sets 162<br />

using set searches in 167<br />

using to trigger actions 100<br />

what they do 104<br />

running applications 35<br />

run-time libraries 18<br />

S<br />

.s files 30<br />

sample applications 88<br />

scheduled event callbacks 109<br />

scripts, startup and configuration 35<br />

<strong>SDK</strong> components 17<br />

system s<strong>of</strong>tware 18<br />

<strong>SDK</strong>installpath meaning xii<br />

searches in sets 162<br />

and rules 100<br />

ASL code requirements 165<br />

defining 162<br />

how to use 167–168<br />

overview 161<br />

results 163<br />

using in rules 167<br />

using to check incoming packet addresses 104<br />

serial processing <strong>of</strong> packets 51<br />

servers, crosscall 114<br />

set elements, see elements 169<br />

set keys 162<br />

associating with protocol fields 162<br />

sets 161<br />

and rules 100<br />

ASL code requirements 165<br />

C structure 23<br />

creating and deleting elements using action<br />

functions 167<br />

declaring using NCL 162–164<br />

defining 162<br />

delaying actions on elements 168<br />

deleting 168<br />

how to use 167–168<br />

overview 161<br />

populating 165<br />

using actions to modify 165, 167<br />

using to associate data with packets 162<br />

using to classify packets 162<br />

using to collect data about packet flow 162<br />

using to keep tables <strong>of</strong> addresses 104<br />

when to use 162<br />

shared memory, microengines and core processor 65<br />

sink microblocks 70<br />

skeletons, generated for crosscalls 116<br />

s<strong>of</strong>tware development tools 18, 29<br />

source microblocks 69<br />

stack <strong>ACE</strong> 87, 88<br />

defined 9<br />

starting and configuring 88<br />

stack, TCP/IP for Linux 18<br />

starting applications 35<br />

startup scripts 35<br />

static bindings 60<br />

static NAT 94<br />

statistical monitoring (RMON) applications 1<br />

structures for <strong>ACE</strong> programming framework 23<br />

creating in <strong>ACE</strong> 106<br />

stub files, example 140<br />

stub functions 114<br />

generated source files 117<br />

using to invoke crosscalls 130<br />

support for <strong>Intel</strong> xii<br />

symbols xi<br />

synchronous and asynchronous crosscalls 120<br />

synchronous crosscalls 120<br />

system <strong>ACE</strong>s 7<br />

interface 79<br />

stack <strong>ACE</strong> 88<br />

system configuration file 37<br />

system s<strong>of</strong>tware 18<br />

OMS 10<br />

Resource Manager 13<br />

starting 35<br />

T<br />

tao_idl compiler 29<br />

targets 11, 50<br />

and packet flow 47<br />

binding 48<br />

binding in configuration file 38<br />

C structure 23<br />

creating 50<br />

default 49<br />

defining 50<br />

directing packets to 51<br />

174 Index<br />

Revision 3.3, August 2001


full names <strong>of</strong> 21<br />

L3 forwarder <strong>ACE</strong> 90<br />

overview 11<br />

stack <strong>ACE</strong> 88<br />

unbound 50<br />

vs. crosscalls, transferring packets with 115<br />

tasks 10<br />

compared to <strong>ACE</strong> 124<br />

defined in OMS 10<br />

using with crosscalls 115, 124<br />

TCP fragments and NAT 95<br />

TCP/IP protocol definition for NCL 102<br />

TCP/IP stack, Linux 18, 88<br />

termination functions 22<br />

for <strong>ACE</strong>s 22<br />

for crosscall interfaces 125<br />

for micro<strong>ACE</strong>s 64<br />

threads 37<br />

and crosscalls 124<br />

on microengines 8, 37<br />

timeouts for asynchronous crosscalls 122<br />

times and events 23<br />

toolchains 20<br />

tools for developers 18, 29<br />

traffic flow 11<br />

through <strong>ACE</strong>s 11<br />

through micro<strong>ACE</strong>s 59, 73<br />

through targets 47<br />

transform microblocks 70<br />

transmitting packets 85<br />

two-way crosscall operations 120<br />

typographical conventions xi<br />

U<br />

unbound targets 50<br />

.u<strong>of</strong> files 58<br />

user <strong>ACE</strong>s 7<br />

utility functions in <strong>ACE</strong>s 109<br />

V<br />

variable IXROOT xii<br />

virtual method table (VMT) 130<br />

for callback implementations 117, 130<br />

for crosscall implementations 116, 130<br />

virtual private networks (VPN) 1<br />

virtual server (load balancing) NAT 95<br />

voice over IP (VOIP) applications 2<br />

WXYZ<br />

warning, explanation <strong>of</strong> xi<br />

Workbench 56<br />

project files 56<br />

Index 175<br />

Revision 3.3, August 2001


176 Index<br />

Revision 3.3, August 2001


Revision 3.3, August 2001<br />

177


<strong>Intel</strong> Corporation<br />

2200 Mission College Blvd.<br />

PO Box 58119<br />

Santa Clara, CA 95052-8119 USA<br />

Tel: 800.628.8686<br />

www.intel.com<br />

Revision 3.3, August 2001

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!