/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_diffserv.c,v $ $Revision: 1.24.10.1 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_diffserv.c,v $ * $Author: svc-cmnet $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPNET_USE_DIFFSERV #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include "ipnet_h.h" #include "ipnet_classifier.h" /* **************************************************************************** * 4 DEFINES **************************************************************************** */ #ifdef IPNET_DIFFSERV_CLASSIFIER_MODE_BA #define IPNET_DIFFSERV_MAX_MAPPINGS 256 #endif /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_diffserv_key_hash *=========================================================================== * Description: Computes a hash value for the specified diffserv type. * Parameters: name - A diffserv entity name. * Returns: The hash value. * */ IP_STATIC unsigned ipnet_diffserv_key_hash(const char *name) { return ipcom_hash_update(name, (int)ipcom_strlen(name), 0); } /* *=========================================================================== * ipnet_diffserv_obj_hash *=========================================================================== * Description: Computes a hash value for the specified diffserv type. * Parameters: template - The template for an differv entity. * Returns: The hash value. * */ IP_STATIC unsigned ipnet_diffserv_obj_hash(Ipnet_diffserv_handlers_template *template) { return ipcom_hash_update(template->name, (int)ipcom_strlen(template->name), 0); } /* *=========================================================================== * ipnet_diffserv_hash_cmp *=========================================================================== * Description: Compares the type of the template with the specified type. * Parameters: template - A template for a diffserv type. * type - A diffserv type. * Returns: IP_TRUE if the specified type matches the template. * */ IP_STATIC Ip_bool ipnet_diffserv_hash_cmp(Ipnet_diffserv_handlers_template *template, const char *name) { return ipcom_strcmp(template->name, name) == 0; } /* *=========================================================================== * ipnet_diffserv_register_ctor *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_diffserv_register_ctor(Ipnet_diffserv_handlers_template *t) { if (ipcom_hash_add(ipnet->diffserv.meter_marker_ctor_db, t) != IPCOM_SUCCESS) return -IP_ERRNO_ENOMEM; return 0; } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_diffserv_input *=========================================================================== * Description: Inputs a packet that will be processed according to the * rules for its class. * Parameters: dst - destination cache entry. * pkt - A IP datagram. * dst_cache_rx_ctor - constructor for destination cache entry * Returns: * */ IP_GLOBAL Ipnet_dst_cache * ipnet_diffserv_input(Ipnet_dst_cache *dst, Ipcom_pkt *pkt, Ipnet_dst_cache_domain_ctor dst_cache_rx_ctor) { Ipnet_diffserv_handlers *h; Ip_u8 class; #ifdef IPNET_DIFFSERV_CLASSIFIER_MODE_BA class = ipnet_diffserv_get_ds_field(pkt); if (IP_BIT_ISFALSE(ipnet->diffserv.mapping_active[class >> 5], 1u << (class & 0x1f))) return dst; h = ipnet->diffserv.handlers[ipnet->diffserv.ds_to_handler_map[class]]; #else int tag = ipnet_classifier_pkt_to_tag(ipnet->diffserv.classifier, pkt); if (tag < 0) /* * No meter/maker mapping installed for this flow */ return dst; ip_assert(tag < IPNET_DIFFSERV_MAX_HANDLERS); h = ipnet->diffserv.handlers[tag]; #endif ip_assert(h != IP_NULL); if (h->meter_input) h->meter_input(h, pkt); h->marker_input(h, pkt); /* * Check if the DS field has changed */ class = ipnet_diffserv_get_ds_field(pkt); if (dst->flow_spec.ds != class) { Ipnet_flow_spec flow_spec = dst->flow_spec; flow_spec.ds = class; dst = ipnet_dst_cache_get(&flow_spec); if (IP_UNLIKELY(dst == IP_NULL)) { int ret = ipnet_dst_cache_new(&flow_spec, dst_cache_rx_ctor, &dst); if (ret < 0) dst = ipnet_dst_cache_blackhole(); } } return dst; } /* *=========================================================================== * ipnet_diffserv_get_ds_field *=========================================================================== * Description: Returns the value of the type-of-service field (IPv4) or * traffic class (IPv6). * Parameters: pkt - An IP datagram. * Returns: The Differentiated Services Field. e * */ IP_GLOBAL Ip_u8 ipnet_diffserv_get_ds_field(Ipcom_pkt *pkt) { switch (pkt->data[pkt->start] & 0xf0) { #ifdef IPCOM_USE_INET case 0x40: return ((Ipnet_pkt_ip *) ipcom_pkt_get_data(pkt, 0))->tos; #endif /* IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 case 0x60: return IPNET_IP6_GET_CLASS((Ipnet_pkt_ip6 *) ipcom_pkt_get_data(pkt, 0)); #endif /* IPCOM_USE_INET6 */ default: IP_PANIC2(); break; } return 0; } /* *=========================================================================== * ipnet_diffserv_set_ds_field *=========================================================================== * Description: Set the TOS field (IPv4) or traffic class (IPv6) to the * specified value. * Parameters: pkt - An IP datagram. * ds - The Differentiated Services Field. * Returns: * */ IP_GLOBAL void ipnet_diffserv_set_ds_field(Ipcom_pkt *pkt, Ip_u8 ds) { switch (pkt->data[pkt->start] & 0xf0) { #ifdef IPCOM_USE_INET case 0x40: { Ipnet_pkt_ip *iphdr = ipcom_pkt_get_iphdr(pkt); iphdr->tos = ds; /* * Incremental checksum is done on all IP datagrams that is * forwarded, so the full checksum must be recalcuated here. */ iphdr->sum = 0; iphdr->sum = ipcom_in_checksum(iphdr, (Ip_size_t)IPNET_IP4_GET_HDR_OCTET_LEN(iphdr)); break; } #endif /* IPCOM_USE_INET */ #ifdef IPCOM_USE_INET6 case 0x60: IPNET_IP6_SET_CLASS((Ipnet_pkt_ip6 *) ipcom_pkt_get_iphdr(pkt), ds); break; #endif /* IPCOM_USE_INET6 */ default: IP_PANIC(); break; } } /* *=========================================================================== * ipnet_diffserv_ioctl *=========================================================================== * Description: DiffServ public API handler. * Parameters: request - The operation to perform * argp - The argument to the operation. * Returns: 0 = success * <0 = error code. * */ IP_GLOBAL int ipnet_diffserv_ioctl(Ip_u32 request, void *argp) { Ipnet_diffserv_handlers_template *t; Ipnet_diffserv_handlers *h; int i; struct Ipnet_ds *ds = argp; struct Ipnet_ds_map *map = argp; #ifndef IPNET_DIFFSERV_CLASSIFIER_MODE_BA struct Ipnet_ds_filter *filter = argp; #endif switch (request) { #ifdef IPNET_DIFFSERV_CLASSIFIER_MODE_BA case IPNET_SIOCXADSMAP: if (map->filter_id < 0 || map->filter_id >= IPNET_DIFFSERV_MAX_MAPPINGS || map->ds_id < 0 || map->ds_id >= IPNET_DIFFSERV_MAX_HANDLERS) return -IP_ERRNO_EINVAL; if (ipnet->diffserv.handlers[map->ds_id] == IP_NULL) { IPCOM_LOG1(WARNING, "DiffServ: Tried to add a mapping for a non-existing DS ID: %d", map->ds_id); return -IP_ERRNO_EINVAL; } ipnet->diffserv.ds_to_handler_map[map->filter_id] =(Ip_u8) map->ds_id; IP_BIT_SET(ipnet->diffserv.mapping_active[map->filter_id >> 5], 1u << (map->filter_id & 0x1f)); break; case IPNET_SIOCXDDSMAP: if (map->filter_id < 0 || map->filter_id > IPNET_DIFFSERV_MAX_MAPPINGS) return -IP_ERRNO_EINVAL; IP_BIT_CLR(ipnet->diffserv.mapping_active[map->filter_id >> 5], 1 << (map->filter_id & 0x1f)); break; #else case IPNET_SIOCXADSMAP: if (map->ds_id < 0 || map->ds_id > IPNET_DIFFSERV_MAX_HANDLERS) return -IP_ERRNO_EINVAL; if (ipnet->diffserv.handlers[map->ds_id] == IP_NULL) { IPCOM_LOG1(WARNING, "DiffServ: Tried to add a mapping for a non-existing DS ID: %d", map->ds_id); return -IP_ERRNO_EINVAL; } return ipnet_classifier_set_tag(ipnet->diffserv.classifier, map->filter_id, map->ds_id); case IPNET_SIOCXDDSMAP: ipnet_classifier_invalidate_tag(ipnet->diffserv.classifier, map->ds_id); return 0; case IPNET_SIOCXADSFILTER: filter->id = ipnet_classifier_get_smallest_unused_id(ipnet->diffserv.classifier); return ipnet_classifier_add_mapping(ipnet->diffserv.classifier, &filter->rule, filter->id); case IPNET_SIOCXDDSFILTER: return ipnet_classifier_del_mapping(ipnet->diffserv.classifier, filter->id); case IPNET_SIOCXGDSFILTER: return ipnet_classifier_get_filter(ipnet->diffserv.classifier, (struct Ipnet_ds_get_infor*)argp); case IPNET_SIOCXGDSNEXTFILTER: return ipnet_classifier_get_next_filter(ipnet->diffserv.classifier, (struct Ipnet_ds_get_infor*)argp); #endif /* IPNET_DIFFSERV_CLASSIFIER_MODE_BA */ case IPNET_SIOCXDSCREATE: for (i = 0; i < IPNET_DIFFSERV_MAX_HANDLERS; i++) if (ipnet->diffserv.handlers[i] == IP_NULL) { t = ipcom_hash_get(ipnet->diffserv.meter_marker_ctor_db, ds->name); if (t == IP_NULL) return -IP_ERRNO_EINVAL; ds->id = i; return t->create(&ds->d, &ipnet->diffserv.handlers[i]); } return -IP_ERRNO_ENOBUFS; case IPNET_SIOCXDSDESTROY: if (ds->id < 0 || ds->id >= IPNET_DIFFSERV_MAX_HANDLERS) return -IP_ERRNO_EINVAL; h = ipnet->diffserv.handlers[ds->id]; if (h == IP_NULL) return -IP_ERRNO_ESRCH; ipnet->diffserv.handlers[ds->id] = IP_NULL; h->destroy(h); #ifdef IPNET_DIFFSERV_CLASSIFIER_MODE_BA /* Deactivate all mappings to this handler */ for (i = 0; i < IPNET_DIFFSERV_MAX_MAPPINGS; i++) if (ipnet->diffserv.ds_to_handler_map[i] == ds->id) IP_BIT_CLR(ipnet->diffserv.mapping_active[map->filter_id >> 5], 1 << (map->filter_id & 0x1f)); #else ipnet_classifier_invalidate_tag(ipnet->diffserv.classifier, ds->id); #endif break; default: return -IP_ERRNO_EINVAL; } return 0; } /* *=========================================================================== * ipnet_diffserv_init *=========================================================================== * Description: Initializes the DiffServ module. * Parameters: * Returns: 0 = success. * <0 = error code. */ IP_GLOBAL int ipnet_diffserv_init(void) { int ret; ipnet->diffserv.meter_marker_ctor_db = ipcom_hash_new((Ipcom_hash_obj_func) ipnet_diffserv_obj_hash, (Ipcom_hash_key_func) ipnet_diffserv_key_hash, (Ipcom_hash_cmp_func) ipnet_diffserv_hash_cmp); if (ipnet->diffserv.meter_marker_ctor_db == IP_NULL) { IPCOM_LOG0(CRIT, "DiffServ: Out of memory when creating meter/marker database"); return -IP_ERRNO_ENOMEM; } /* All known handlers constructors must be registered here */ if (0 > (ret = ipnet_diffserv_register_ctor(ipnet_diffserv_srtcm_template()))) return ret; if (0 > (ret = ipnet_diffserv_register_ctor(ipnet_diffserv_sm_template()))) return ret; #ifndef IPNET_DIFFSERV_CLASSIFIER_MODE_BA ipnet->diffserv.classifier = ipnet_classifier_new(); if (IP_NULL == ipnet->diffserv.classifier) { IPCOM_LOG0(CRIT, "DiffServ: Out of memory when creating classifier"); return -IP_ERRNO_ENOMEM; } #endif return 0; } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #else int ipnet_diffserv_empty_file; #endif /* IPNET_USE_DIFFSERV */ /* **************************************************************************** * END OF FILE **************************************************************************** */