On Wed, 2010-09-15 at 02:06 +0000, Amos Jeffries wrote: > On Tue, 14 Sep 2010 23:55:20 +0100, Andrew Beverley <a...@andybev.com> > wrote: > >> * Config.accessList.outgoingTos, Config.accessList.clientsideTos, > >> Config.accessList.outgoingNfmark, Config.accessList.clientsideNfmark > can > >> become members of the Qos scope Config object. All the parsing /free > >> stuff > >> can be moved there too with some #define parse_...() etc for the legacy > >> parser. > >> > > > > I've moved all the configuration variables and functions to the Qos > > scope. I have renamed parse_acl_tos(acl_tos ** head) as > > Ip::Qos::Config::parseConfigAclTos(acl_tos ** head). > > > > However, I'm unable to compile because of the following error: > > > > Qos.cc: In member function ‘void > > Ip::Qos::Config::parseConfigAclTos(acl_tos**)’: > > Qos.cc:377: error: argument of type ‘void (Ip::Qos::Config::)(void*)’ > does > > not match ‘void (*)(void*)’ > > > > The code at line 377 is: > > > > CBDATA_INIT_TYPE_FREECB(acl_tos, freedConfigAclTos); > > > > I have > > > > CBDATA_TYPE(acl_tos); > > > > specified before the parseConfigAclTos function. > > > > Could you give me any ideas as to what I am doing wrong here? If you > > need me to send through any more of the code then please let me know. > > Do you have this with a cast? > #define parse_acl_tos(X) Ip::Qos::Config::parseConfigAclTos((acl_tos > **)X) > > with the cf.data.pre "TYPE: acl_tos" unchanged.
No, I had changed it. However, I have now changed it back to the above, but still get the same error. Any other ideas? Qos.cc: In member function ‘void Ip::Qos::Config::parseConfigAclTos(acl_tos**)’: Qos.cc:377: error: argument of type ‘void (Ip::Qos::Config::)(void*)’ does not match ‘void (*)(void*)’ I have attached my current Qos.cc and Qos.h Thanks, Andy
#include "acl/Gadgets.h" #include "ConfigParser.h" #include "fde.h" #include "HierarchyLogEntry.h" #include "ip/tools.h" #include "Qos.h" #include "Parsing.h" #include "squid.h" #include "Store.h" extern void dump_acl_list(StoreEntry * entry, ACLList * head); /* Qos namespace */ void Ip::Qos::getTosFromServer(const int server_fd, fde *clientFde) { #if USE_QOS_TOS tos_t tos = 1; int tos_len = sizeof(tos); clientFde->tosFromServer = 0; if (setsockopt(server_fd,SOL_IP,IP_RECVTOS,&tos,tos_len)==0) { unsigned char buf[512]; int len = 512; if (getsockopt(server_fd,SOL_IP,IP_PKTOPTIONS,buf,(socklen_t*)&len) == 0) { /* Parse the PKTOPTIONS structure to locate the TOS data message * prepared in the kernel by the ZPH incoming TCP TOS preserving * patch. */ unsigned char * pbuf = buf; while (pbuf-buf < len) { struct cmsghdr *o = (struct cmsghdr*)pbuf; if (o->cmsg_len<=0) break; if (o->cmsg_level == SOL_IP && o->cmsg_type == IP_TOS) { int *tmp = (int*)CMSG_DATA(o); clientFde->tosFromServer = (tos_t)*tmp; break; } pbuf += CMSG_LEN(o->cmsg_len); } } else { debugs(33, 1, "QOS: error in getsockopt(IP_PKTOPTIONS) on FD " << server_fd << " " << xstrerror()); } } else { debugs(33, 1, "QOS: error in setsockopt(IP_RECVTOS) on FD " << server_fd << " " << xstrerror()); } #endif } void Ip::Qos::getNfmarkFromServer(const int server_fd, const fde *servFde, const fde *clientFde) { #if USE_QOS_NFMARK /* Allocate a new conntrack */ if (struct nf_conntrack *ct = nfct_new()) { /* Prepare data needed to find the connection in the conntrack table. * We need the local and remote IP address, and the local and remote * port numbers. */ Ip::Address serv_fde_local_conn; struct addrinfo *addr = NULL; serv_fde_local_conn.InitAddrInfo(addr); getsockname(server_fd, addr->ai_addr, &(addr->ai_addrlen)); serv_fde_local_conn = *addr; serv_fde_local_conn.GetAddrInfo(addr); unsigned short serv_fde_local_port = ((struct sockaddr_in*)addr->ai_addr)->sin_port; struct in6_addr serv_fde_local_ip6; struct in_addr serv_fde_local_ip; if (Ip::EnableIpv6 && serv_fde_local_conn.IsIPv6()) { serv_fde_local_ip6 = ((struct sockaddr_in6*)addr->ai_addr)->sin6_addr; nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6); struct in6_addr serv_fde_remote_ip6; inet_pton(AF_INET6,servFde->ipaddr,(struct in6_addr*)&serv_fde_remote_ip6); nfct_set_attr(ct, ATTR_IPV6_DST, serv_fde_remote_ip6.s6_addr); nfct_set_attr(ct, ATTR_IPV6_SRC, serv_fde_local_ip6.s6_addr); } else { serv_fde_local_ip = ((struct sockaddr_in*)addr->ai_addr)->sin_addr; nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET); nfct_set_attr_u32(ct, ATTR_IPV4_DST, inet_addr(servFde->ipaddr)); nfct_set_attr_u32(ct, ATTR_IPV4_SRC, serv_fde_local_ip.s_addr); } nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_TCP); nfct_set_attr_u16(ct, ATTR_PORT_DST, htons(servFde->remote_port)); nfct_set_attr_u16(ct, ATTR_PORT_SRC, serv_fde_local_port); /* Open a handle to the conntrack */ if (struct nfct_handle *h = nfct_open(CONNTRACK, 0)) { /* Register the callback. The callback function will record the mark value. */ nfct_callback_register(h, NFCT_T_ALL, getNfMarkCallback, (void *)clientFde); /* Query the conntrack table using the data previously set */ int x = nfct_query(h, NFCT_Q_GET, ct); if (x == -1) { debugs(17, 2, "QOS: Failed to retrieve connection mark: (" << x << ") " << strerror(errno) << " (Destination " << servFde->ipaddr << ":" << servFde->remote_port << ", source " << serv_fde_local_conn << ")" ); } nfct_close(h); } else { debugs(17, 2, "QOS: Failed to open conntrack handle for upstream netfilter mark retrieval."); } serv_fde_local_conn.FreeAddrInfo(addr); nfct_destroy(ct); } else { debugs(17, 2, "QOS: Failed to allocate new conntrack for upstream netfilter mark retrieval."); } #endif } #if USE_QOS_NFMARK int Ip::Qos::getNfMarkCallback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *data) { fde *clientFde = (fde *)data; clientFde->nfmarkFromServer = nfct_get_attr_u32(ct, ATTR_MARK); debugs(17, 3, "QOS: Retrieved connection mark value: " << clientFde->nfmarkFromServer); return NFCT_CB_CONTINUE; } #endif int Ip::Qos::doTosLocalMiss(const int fd, const HierarchyLogEntry *hier) { tos_t tos = 0; if (Ip::Qos::TheConfig.tosSiblingHit && hier->code==SIBLING_HIT ) { tos = Ip::Qos::TheConfig.tosSiblingHit; debugs(33, 2, "QOS: Sibling Peer hit with hier code=" << hier->code << ", TOS=" << int(tos)); } else if (Ip::Qos::TheConfig.tosParentHit && hier->code==PARENT_HIT) { tos = Ip::Qos::TheConfig.tosParentHit; debugs(33, 2, "QOS: Parent Peer hit with hier code=" << hier->code << ", TOS=" << int(tos)); } else if (Ip::Qos::TheConfig.preserveMissTos && Ip::Qos::TheConfig.preserveMissTosMask) { tos = fd_table[fd].tosFromServer & Ip::Qos::TheConfig.preserveMissTosMask; debugs(33, 2, "QOS: Preserving TOS on miss, TOS=" << int(tos)); } return setSockTos(fd, tos); } int Ip::Qos::doNfmarkLocalMiss(const int fd, const HierarchyLogEntry *hier) { nfmark_t mark = 0; if (Ip::Qos::TheConfig.markSiblingHit && hier->code==SIBLING_HIT ) { mark = Ip::Qos::TheConfig.markSiblingHit; debugs(33, 2, "QOS: Sibling Peer hit with hier code=" << hier->code << ", Mark=" << mark); } else if (Ip::Qos::TheConfig.markParentHit && hier->code==PARENT_HIT) { mark = Ip::Qos::TheConfig.markParentHit; debugs(33, 2, "QOS: Parent Peer hit with hier code=" << hier->code << ", Mark=" << mark); } else if (Ip::Qos::TheConfig.preserveMissMark) { mark = fd_table[fd].nfmarkFromServer & Ip::Qos::TheConfig.preserveMissMarkMask; debugs(33, 2, "QOS: Preserving mark on miss, Mark=" << mark); } return setSockNfmark(fd, mark); } int Ip::Qos::doTosLocalHit(const int fd) { debugs(33, 2, "QOS: Setting TOS for local hit, TOS=" << int(Ip::Qos::TheConfig.tosLocalHit)); return setSockTos(fd, Ip::Qos::TheConfig.tosLocalHit); } int Ip::Qos::doNfmarkLocalHit(const int fd) { debugs(33, 2, "QOS: Setting netfilter mark for local hit, mark=" << Ip::Qos::TheConfig.markLocalHit); return setSockNfmark(fd, Ip::Qos::TheConfig.markLocalHit); } /* Qos::Config class */ Ip::Qos::Config Ip::Qos::TheConfig; Ip::Qos::Config::Config() { tosLocalHit = 0; tosSiblingHit = 0; tosParentHit = 0; preserveMissTos = false; preserveMissTosMask = 0xFF; markLocalHit = 0; markSiblingHit = 0; markParentHit = 0; preserveMissMark = false; preserveMissMarkMask = 0xFFFFFFFF; } void Ip::Qos::Config::parseConfigLine() { /* parse options ... */ char *token; /* These are set as appropriate and then used to check whether the initial loop has been done */ bool mark = false; bool tos = false; /* Assume preserve is true. We don't set at initialisation as this affects isHitTosActive(). We have to do this now, as we may never match the 'tos' parameter below */ #if !USE_QOS_TOS debugs(3, DBG_CRITICAL, "ERROR: Invalid option 'qos_flows'. QOS features not enabled in this build"); self_destruct(); #endif while ( (token = strtok(NULL, w_space)) ) { // Work out TOS or mark. Default to TOS for backwards compatibility if (!(mark || tos)) { if (strncmp(token, "mark",4) == 0) { #if USE_QOS_NFMARK && defined(_SQUID_LINUX_) mark = true; // Assume preserve is true. We don't set at initialisation as this affects isHitNfmarkActive() preserveMissMark = 1; #elif defined(_SQUID_LINUX_) debugs(3, DBG_CRITICAL, "ERROR: Invalid parameter 'mark' in qos_flows option. " << "Netfilter marking only available for Linux environment"); self_destruct(); #else debugs(3, DBG_CRITICAL, "ERROR: Invalid parameter 'mark' in qos_flows option. " << "Netfilter marking not enabled in this build"); self_destruct(); #endif } else if (strncmp(token, "tos",3) == 0) { preserveMissTos = true; tos = true; } else { preserveMissTos = true; tos = true; } } if (strncmp(token, "local-hit=",10) == 0) { if (mark) { if (!xstrtoui(&token[10], NULL, &markLocalHit, 0, std::numeric_limits<nfmark_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad mark local-hit value " << &token[10]); } else { unsigned int v = 0; if (!xstrtoui(&token[10], NULL, &v, 0, std::numeric_limits<tos_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad TOS local-hit value " << &token[10]); tosLocalHit = (tos_t)v; } } else if (strncmp(token, "sibling-hit=",12) == 0) { if (mark) { if (!xstrtoui(&token[12], NULL, &markSiblingHit, 0, std::numeric_limits<nfmark_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad mark sibling-hit value " << &token[12]); } else { unsigned int v = 0; if (!xstrtoui(&token[12], NULL, &v, 0, std::numeric_limits<tos_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad TOS sibling-hit value " << &token[12]); tosSiblingHit = (tos_t)v; } } else if (strncmp(token, "parent-hit=",11) == 0) { if (mark) { if (!xstrtoui(&token[11], NULL, &markParentHit, 0, std::numeric_limits<nfmark_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad mark parent-hit value " << &token[11]); } else { unsigned int v = 0; if (!xstrtoui(&token[11], NULL, &v, 0, std::numeric_limits<tos_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad TOS parent-hit value " << &token[11]); tosParentHit = (tos_t)v; } } else if (strcmp(token, "disable-preserve-miss") == 0) { if (preserveMissTosMask!=0xFFU || preserveMissMarkMask!=0xFFFFFFFFU) { debugs(3, DBG_CRITICAL, "ERROR: miss-mask feature cannot be set with disable-preserve-miss"); } if (mark) { preserveMissMark = false; preserveMissMarkMask = 0; } else { preserveMissTos = false; preserveMissTosMask = 0; } } else if (strncmp(token, "miss-mask=",10) == 0) { if (mark && preserveMissMark) { if (!xstrtoui(&token[10], NULL, &preserveMissMarkMask, 0, std::numeric_limits<nfmark_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad mark miss-mark value " << &token[10]); } else if (preserveMissTos) { unsigned int v = 0; if (!xstrtoui(&token[10], NULL, &v, 0, std::numeric_limits<tos_t>::max())) debugs(3, DBG_CRITICAL, "ERROR: Bad TOS miss-mark value " << &token[10]); preserveMissTosMask = (tos_t)v; } else { debugs(3, DBG_CRITICAL, "ERROR: miss-mask feature cannot be set with disable-preserve-miss"); } } } } void Ip::Qos::Config::dumpConfigLine(char *entry, const char *name) const { char *p = entry; if (isHitTosActive()) { p += snprintf(p, 11, "%s", name); // strlen("qos_flows "); p += snprintf(p, 4, "%s", "tos"); if (tosLocalHit > 0) { p += snprintf(p, 16, " local-hit=0x%02X", tosLocalHit); } if (tosSiblingHit > 0) { p += snprintf(p, 18, " sibling-hit=0x%02X", tosSiblingHit); } if (tosParentHit > 0) { p += snprintf(p, 17, " parent-hit=0x%02X", tosParentHit); } if (preserveMissTos == 0) { p += snprintf(p, 23, " disable-preserve-miss"); } if (preserveMissTos && preserveMissTosMask != 0) { p += snprintf(p, 16, " miss-mask=0x%02X", preserveMissTosMask); } p += snprintf(p, 2, "\n"); } if (isHitNfmarkActive()) { p += snprintf(p, 11, "%s", name); // strlen("qos_flows "); p += snprintf(p, 5, "%s", "mark"); if (markLocalHit > 0) { p += snprintf(p, 22, " local-hit=0x%02X", markLocalHit); } if (markSiblingHit > 0) { p += snprintf(p, 24, " sibling-hit=0x%02X", markSiblingHit); } if (markParentHit > 0) { p += snprintf(p, 23, " parent-hit=0x%02X", markParentHit); } if (preserveMissMark == 0) { p += snprintf(p, 23, " disable-preserve-miss"); } if (preserveMissMark && preserveMissMarkMask != 0) { p += snprintf(p, 22, " miss-mask=0x%02X", preserveMissMarkMask); } p += snprintf(p, 2, "\n"); } } CBDATA_TYPE(acl_tos); static ConfigParser LegacyParser = ConfigParser(); void Ip::Qos::Config::parseConfigAclTos(acl_tos ** head) { acl_tos *l; acl_tos **tail = head; /* sane name below */ unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */ char *token = strtok(NULL, w_space); if (!token) { self_destruct(); return; } if (!xstrtoui(token, NULL, &tos, 0, std::numeric_limits<tos_t>::max())) { self_destruct(); return; } CBDATA_INIT_TYPE_FREECB(acl_tos, freedConfigAclTos); l = cbdataAlloc(acl_tos); l->tos = (tos_t)tos; aclParseAclList(LegacyParser, &l->aclList); while (*tail) tail = &(*tail)->next; *tail = l; } void Ip::Qos::Config::dumpConfigAclTos(StoreEntry * entry, const char *name, acl_tos * head) { acl_tos *l; for (l = head; l; l = l->next) { if (l->tos > 0) storeAppendPrintf(entry, "%s 0x%02X", name, l->tos); else storeAppendPrintf(entry, "%s none", name); dump_acl_list(entry, l->aclList); storeAppendPrintf(entry, "\n"); } } void Ip::Qos::Config::freedConfigAclTos(void *data) { acl_tos *l = static_cast<acl_tos *>(data); aclDestroyAclList(&l->aclList); } void Ip::Qos::Config::freeConfigAclTos(acl_tos ** head) { while (*head) { acl_tos *l = *head; *head = l->next; l->next = NULL; cbdataFree(l); } } #if !_USE_INLINE_ #include "Qos.cci" #endif
#ifndef SQUID_QOSCONFIG_H #define SQUID_QOSCONFIG_H #include "config.h" #if HAVE_LIBNETFILTER_CONNTRACK_LIBNETFILTER_CONNTRACK_H #include <libnetfilter_conntrack/libnetfilter_conntrack.h> #endif #if HAVE_LIBNETFILTER_CONNTRACK_LIBNETFILTER_CONNTRACK_TCP_H #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h> #endif #if HAVE_LIMITS #include <limits> #endif // Forward-declarations class fde; class HierarchyLogEntry; namespace Ip { /** * QOS namespace contains all the QOS functionality: global functions within * the namespace and the configuration parameters within a config class. */ namespace Qos { /** * Function to retrieve the TOS value of the inbound packet. * Called by FwdState::dispatch if QOS options are enabled. * @param server_fd Server side descriptor of connection to get TOS for * @param clientFde Pointer to client side fde instance to set tosFromServer in */ void getTosFromServer(const int server_fd, fde *clientFde); /** * Function to retrieve the netfilter mark value of the connection * to the upstream server. Called by FwdState::dispatch if QOS * options are enabled. * @param server_fd Server side descriptor of connection to get mark for * @param servFde Pointer to server side fde instance to get mark for * @param clientFde Pointer to client side fde instance to set nfmarkFromServer in */ void getNfmarkFromServer(const int server_fd, const fde *servFde, const fde *clientFde); #if USE_QOS_NFMARK /** * Callback function to mark connection once it's been found. * This function is called by the libnetfilter_conntrack * libraries, during nfct_query in Ip::Qos::getNfmarkFromServer. * nfct_callback_register is used to register this function. * @param nf_conntrack_msg_type Type of conntrack message * @param nf_conntrack Pointer to the conntrack structure * @param clientFde Pointer to client side fde instance to set nfmarkFromServer in */ int getNfMarkCallback(enum nf_conntrack_msg_type type, struct nf_conntrack *ct, void *clientFde); #endif /** * Function to work out and then apply to the socket the appropriate * TOS value to set on packets when items have not been retrieved from * local cache. Called by clientReplyContext::sendMoreData if QOS is * enabled for TOS. * @param fd Descriptor of socket to set the TOS for * @param HierarchyLogEntry Pointer to hier structure of request */ int doTosLocalMiss(const int fd, const HierarchyLogEntry *hier); /** * Function to work out and then apply to the socket the appropriate * netfilter mark value to set on packets when items have not been * retrieved from local cache. Called by clientReplyContext::sendMoreData * if QOS is enabled for TOS. * @param fd Descriptor of socket to set the mark for * @param HierarchyLogEntry Pointer to hier structure of request */ int doNfmarkLocalMiss(const int fd, const HierarchyLogEntry *hier); /** * Function to work out and then apply to the socket the appropriate * TOS value to set on packets when items *have* been retrieved from * local cache. Called by clientReplyContext::doGetMoreData if QOS is * enabled for TOS. * @param fd Descriptor of socket to set the TOS for */ int doTosLocalHit(const int fd); /** * Function to work out and then apply to the socket the appropriate * netfilter mark value to set on packets when items *have* been * retrieved from local cache. Called by clientReplyContext::doGetMoreData * if QOS is enabled for TOS. * @param fd Descriptor of socket to set the mark for */ int doNfmarkLocalHit(const int fd); /** * Function to set the TOS value of packets. Sets the value on the socket * which then gets copied to the packets. * @param fd Descriptor of socket to set the TOS for */ _SQUID_INLINE_ int setSockTos(int fd, tos_t tos); /** * Function to set the netfilter mark value of packets. Sets the value on the * socket which then gets copied to the packets. Called from Ip::Qos::doNfmarkLocalMiss * @param fd Descriptor of socket to set the mark for */ _SQUID_INLINE_ int setSockNfmark(int fd, nfmark_t mark); /** * QOS configuration class. Contains all the parameters for QOS functions as well * as functions to check whether either TOS or MARK QOS is enabled. */ class Config { public: Config(); ~Config() {}; void parseConfigLine(); /** * Dump all the configuration values * * NOTE: Due to the low-level nature of the library these * objects are part of the dump function must be self-contained. * which means no StoreEntry references. Just a basic char* buffer. */ void dumpConfigLine(char *entry, const char *name) const; void parseConfigAclTos(acl_tos ** head); void dumpConfigAclTos(StoreEntry * entry, const char *name, acl_tos * head); void freedConfigAclTos(void *data); void freeConfigAclTos(acl_tos ** head); /// Whether we should modify TOS flags based on cache hits and misses. _SQUID_INLINE_ bool isHitTosActive() const; /// Whether we should modify netfilter marks based on cache hits and misses. _SQUID_INLINE_ bool isHitNfmarkActive() const; /** * Iterates through any outgoing_nfmark or clientside_nfmark configuration parameters * to find out if any Netfilter marking is required. * This function is used on initialisation to define capabilities required (Netfilter * marking requires CAP_NET_ADMIN). */ _SQUID_INLINE_ bool isAclNfmarkActive(); /** * Iterates through any outgoing_tos or clientside_tos configuration parameters * to find out if packets should be marked with TOS flags. */ _SQUID_INLINE_ bool isAclTosActive(); tos_t tosLocalHit; ///< TOS value to apply to local cache hits tos_t tosSiblingHit; ///< TOS value to apply to hits from siblings tos_t tosParentHit; ///< TOS value to apply to hits from parent bool preserveMissTos; ///< Whether to preserve the TOS value of the inbound packet for misses tos_t preserveMissTosMask; ///< The mask to apply when preserving the TOS of misses nfmark_t markLocalHit; ///< Netfilter mark value to apply to local cache hits nfmark_t markSiblingHit; ///< Netfilter mark value to apply to hits from siblings nfmark_t markParentHit; ///< Netfilter mark value to apply to hits from parent bool preserveMissMark; ///< Whether to preserve netfilter mark value of inbound connection nfmark_t preserveMissMarkMask; ///< The mask to apply when preserving the netfilter mark of misses acl_tos *tosToServer; ///< The TOS that packets to the web server should be marked with, based on ACL acl_tos *tosToClient; ///< The TOS that packets to the client should be marked with, based on ACL acl_nfmark *nfmarkToServer; ///< The MARK that packets to the web server should be marked with, based on ACL acl_nfmark *nfmarkToClient; ///< The MARK that packets to the client should be marked with, based on ACL }; /// Globally available instance of Qos::Config extern Config TheConfig; /* legacy parser access wrappers */ #define parse_QosConfig(X) (X)->parseConfigLine() #define free_QosConfig(X) #define dump_QosConfig(e,n,X) do { \ char temp[256]; /* random number. change as needed. max config line length. */ \ (X).dumpConfigLine(temp,n); \ storeAppendPrintf(e, "%s", temp); \ } while(0); #define parse_acl_tos(X) Ip::Qos::Config::parseConfigAclTos((acl_tos **)X) #define dump_acl_tos(X) Ip::Qos::Config::dumpConfigAclTos((acl_tos **)X) #define freed_acl_tos(X) Ip::Qos::Config::freedConfigAclTos((acl_tos **)X) #define free_acl_tos(X) Ip::Qos::Config::freeConfigAclTos((acl_tos **)X) }; // namespace Qos }; // namespace Ip #if _USE_INLINE_ #include "Qos.cci" #endif #endif /* SQUID_QOSCONFIG_H */