Classifier API Notes ~~~~~~~~~~~~~~~~~~~~ *Kernel* classifier functions are documented in /afs/cs.cmu.edu/project/cmcl-darwin/kernel/kernel.common/pkt_classifier/[classifier.h,classifier_structure.h] classifier.h is where most of the data structures and types are defined. classifier_structure.h is where most of the interesting functions' prototypes are defined. (For features on selective packet discard, see classifier_selectdisc.h and consult takahasi@cs.) Here is the listing of the functions of interest in classifer_structure.h: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /* * * FUNCTION: classifierCreateClass * * SYNOPSIS: This normally will create a new class node and link it into * the class hierarchy, subject to admission control * * PASS: if_name => the interface to which this call applies * * lOp => by what mechanism shall the new class be linked * into the hierarchy (see linkOption) * * lOpData => if (lOp == BY_FILTER) * lOpData = filter* * if (lOp == NO_LINKING) * lOpData = NULL * * rOp => reservation option (see resvOption) * * rOpData1 => if (rOp == RSVP) * rOpData1 = intTspec* * else if (rOp == GUI) * rOpData1 = GUIsc* * * rOpData2 => if (rOp == RSVP) * rOpData2 = intFlowspec* * * RETURN: if (error) * return a negative error code (currently only -1) * else * return non-negative 32-bit class id for future reference * to the class created * * NOTE: RSVP TC_AddFlowspec() should call classifierCreateClass() with * lOp = NO_LINKING * this way, the class node will be created without being * linked into the tree. * Notice that TC_AddFlowspec() will almost always succeed because * in our link-sharing model, admission control is performed * during TC_AddFilter(). * */ int32_t classifierCreateClass(char* if_name, linkOption lOp, void* lOpData, resvOption rOp, void* rOpData1,void* rOpData2); /* * * FUNCTION: classifierModifyClass * * SYNOPSIS: Modify the reservation for a class node, subject * to admission control * * PASS: if_name => the interface to which this call applies * * classId => class id returned by an earlier * classifierCreateClass call. * * rOp => reservation option (see resvOption) * * rOpData1 => if (rOp == RSVP) * rOpData1 = intTspec* * if (rOp == GUI) * rOpData1 = GUIsc* * * rOpData2 => if (rOp == RSVP) * rOpData2 = intFlowspec* * * RETURN: if (error) * return a negative error code (currently only -1) * nothing modified * else * return 0 * * NOTE: classifierCreateClass() must be called before this function * RSVP TC_ModFlowspec() should use this function * */ int classifierModifyClass(char* if_name, int32_t classId, resvOption rOp, void* rOpData1, void* rOpData2); /* * * FUNCTION: classifierMoveClass * * SYNOPSIS: Change the location of a class node in the hierarchy, * subject to admission control * * PASS: if_name => the interface to which this call applies * * classId => class id returned by an earlier * classifierCreateClass call. * * lOp => by what mechanism shall the new class be linked * into the hierarchy (see linkOption) * * lOpData => if (lOp == BY_FILTER) * lOpData = filter* * if (lOp == NO_LINKING) * lOpData = NULL * * RETURN: if (error) * return a negative error code (currently only -1) * nothing moved * else * return 0 * * NOTE: RSVP TC_AddFilter() should call this function with * lOp = BY_FILTER and lOpData = filter* * Must preceed this call by a TC_AddFlowspec() call * and return classId as the FHandle * No multiple filters allowed for now because of our * link-sharing model. * * RSVP TC_DelFilter() should call this function with * lOp = NO_LINKING and lOpData = NULL * FHandle is essentially the classId * */ int classifierMoveClass(char* if_name, int32_t classId, linkOption lOp, void* lOpData); /* * * FUNCTION: classifierDeleteClass * * SYNOPSIS: Permanently remove a class node from the hierarchy and * destroy all associated data structures * * PASS: if_name => the interface to which this call applies * * classId => class id returned by an earlier * classifierCreateClass call. * * RETURN: if (error) * return a negative error code (currently only -1) * nothing deleted * else * return 0 * * NOTE: RSVP TC_DelFlowspec() should call this function * */ int classifierDeleteClass(char* if_name, int32_t classId); /* * * FUNCTION: classifierRetrieveHierarchy * * SYNOPSIS: This function is for diagnostic purpose. When called, * information about the hierarchy will be passed back to * the caller in the supplied buffer, and the caller (a * user level process) can examine it and display it. * * PASS: if_name => the interface to which this call applies * * numClasses => a return value indicating the number of classes * saved in buffer * * buffer => an array of classInfo in which data is put in * * format: * buffer will be treated as an array of classInfo * structures, and the hierarchy will be stored in * in array in this format: * root * first child of root * (... children ...) * second child of root * (... children ...) * in words, the order is "self, children", the * level parameter will indicate what level the class * is in and therefore parent children relationships * and be determined. * * buf_size => size of the buffer array, will return if full * * * RETURN: if (error) * return a negative error code (currently only -1) * else * return 0 * * buffer => classInfo data * numClasses => number of classes saved * * NOTE: This call is limited to getting only CLASS_MAXSIZE classes * through ioctl. Use the following functions instead. * */ int classifierRetrieveHierarchy(char* if_name, int* numClasses, classInfo* buffer, int buf_size); /* * * FUNCTION: classifierNumClasses * * SYNOPSIS: Get the number of classes currently in the hierarchy * * PASS: if_name => the interface to which this call applies * * RETURN: number of classes * * NOTE: Used to figure out how many times to call classifierNthClass * */ int classifierNumClasses(char* if_name); /* * * FUNCTION: classifierNthClass * * SYNOPSIS: Get the classInfo for the n-th class in the hierarchy * * PASS: if_name => the interface to which this call applies * * n => which class, >= 1 * * entry => struct classInfo* to store info * * RETURN: if (error) * return negative error code (currently only -1) * else * class information in entry * * NOTE: * */ int classifierNthClass(char* if_name, int n, classInfo* entry); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Again, the above are *kernel* functions. To invoke these functions from *user* space, you need to use the "ioctl()" interface for these functions. The ioctl() interface for these functions is documented in /afs/cs.cmu.edu/project/cmcl-darwin/kernel/kernel.common/pkt_classifier/tc_classifier.h You will see lines such as: #define CLASSIFIER_CREATE_CLASS _IOWR('e', 77, struct create_class) CLASSIFIER_CREATE_CLASS is the constant defined for using ioctl() to invoke the kernel function classifierCreateClass(). The data structure specfied (struct create_class, defined later in the same file) is the data structure passed between the user space and kernel space when you call ioctl(... CLASSIFIER_CREATE_CLASS ...). _IOWR indicates that the data structure passed is copied to the kernel space at call time and then the result is copied back to the user space upon return (both write and read). Here is an example of how to invoke classifierCreateClass() in a C program, other functions such as classifierDeleteClass() are invoked in a similar way, except that the data structure you pass will be different (as defined in tc_classifier.h"). ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #define PKT_CLASSIFIER #define PKT_CLASSIFIER_DEBUG #define PKT_CLASSIFIER_MONITOR #define SELECT_DISC #define BSD_KERNEL #include #include #include #include #include #include #include #include void main(int argc, char** argv) { int sockfd; create_class_t newClass; /* assumes argv has all the fields we need for the filter and the service curve */ if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0){ printf ("Cannot open socket\n"); exit(0); } bzero(&newClass, sizeof(create_class_t)); strcpy(newClass.ifName, "de0"); newClass.link_option = BY_FILTER; newClass.resvProt = GUI; newClass.filt_info.fSrcAddr = ntohl(inet_addr(argv[1])); newClass.filt_info.fSrcMask = ntohl(inet_addr(argv[2])); newClass.filt_info.fSrcMskd = newClass.filt_info.fSrcAddr & newClass.filt_info.fSrcMask; newClass.filt_info.fDstAddr = ntohl(inet_addr(argv[3])); newClass.filt_info.fDstMask = ntohl(inet_addr(argv[4])); newClass.filt_info.fDstMskd = newClass.filt_info.fDstAddr & newClass.filt_info.fDstMask; newClass.filt_info.fProto = atoi(argv[5]); newClass.filt_info.fSrcPort = (short)atoi(argv[6]); newClass.filt_info.fDstPort = (short)atoi(argv[7]); newClass.service_curve.m1 = atoi(argv[8]); newClass.service_curve.d = atoi(argv[9]); newClass.service_curve.m2 = atoi(argv[10]); ioctl(sockfd, CLASSIFIER_CREATE_CLASS, &newClass); if (newClass.classID == 0) { printf("Error in creating class\n"); exit(0); } } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~