50#if USE_QOS_TOS && _SQUID_LINUX_
53 int tos_len =
sizeof(tos);
56 unsigned char buf[512];
63 unsigned char * pbuf = buf;
64 while (pbuf-buf < len) {
90#if USE_LIBNETFILTERCONNTRACK
101getNfmarkCallback(
enum nf_conntrack_msg_type,
struct nf_conntrack *ct,
void *connmark)
103 auto *mark =
static_cast<nfmark_t *
>(connmark);
104 *mark = nfct_get_attr_u32(ct, ATTR_MARK);
106 return NFCT_CB_CONTINUE;
117 if (
auto ct = nfct_new()) {
121 if (Ip::EnableIpv6 && src.
isIPv6()) {
122 nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
123 struct in6_addr conn_fde_dst_ip6;
125 nfct_set_attr(ct, ATTR_ORIG_IPV6_DST, conn_fde_dst_ip6.s6_addr);
126 struct in6_addr conn_fde_src_ip6;
128 nfct_set_attr(ct, ATTR_ORIG_IPV6_SRC, conn_fde_src_ip6.s6_addr);
130 nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
131 struct in_addr conn_fde_dst_ip;
133 nfct_set_attr_u32(ct, ATTR_ORIG_IPV4_DST, conn_fde_dst_ip.s_addr);
134 struct in_addr conn_fde_src_ip;
136 nfct_set_attr_u32(ct, ATTR_ORIG_IPV4_SRC, conn_fde_src_ip.s_addr);
139 nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_TCP);
140 nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, htons(dst.
port()));
141 nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, htons(src.
port()));
154#if USE_LIBNETFILTERCONNTRACK
158 if (
const auto ct = prepareConntrackQuery(src, dst)) {
160 if (
struct nfct_handle *h = nfct_open(CONNTRACK, 0)) {
162 nfct_callback_register(h, NFCT_T_ALL, getNfmarkCallback,
static_cast<void *
>(&mark));
164 int x = nfct_query(h, NFCT_Q_GET, ct);
166 const int xerrno = errno;
167 debugs(17, 2,
"QOS: Failed to retrieve connection mark: (" << x <<
") " <<
xstrerr(xerrno)
168 <<
" (Destination " << dst <<
", source " << src <<
")" );
172 debugs(17, 2,
"QOS: Failed to open conntrack handle for netfilter CONNMARK retrieval.");
176 debugs(17, 2,
"QOS: Failed to allocate new conntrack for netfilter CONNMARK retrieval.");
190#if USE_LIBNETFILTERCONNTRACK
200 if (
const auto ct = prepareConntrackQuery(src, dst)) {
202 if (
struct nfct_handle *h = nfct_open(CONNTRACK, 0)) {
203 nfct_set_attr_u32(ct, ATTR_MARK, newMark);
205 const int queryResult = nfct_query(h, NFCT_Q_UPDATE, ct);
206 if (queryResult == 0) {
210 const int xerrno = errno;
211 debugs(17, 2,
"QOS: Failed to modify connection mark: (" << queryResult <<
") " <<
xstrerr(xerrno)
212 <<
" (Destination " << dst <<
", source " << src <<
")" );
216 debugs(17, 2,
"QOS: Failed to open conntrack handle for netfilter CONNMARK modification.");
220 debugs(17, 2,
"QOS: Failed to allocate new conntrack for netfilter CONNMARK modification.");
236 debugs(33, 2,
"QOS: Sibling Peer hit with hier code=" << hierCode <<
", TOS=" <<
int(tos));
239 debugs(33, 2,
"QOS: Parent Peer hit with hier code=" << hierCode <<
", TOS=" <<
int(tos));
243 debugs(33, 2,
"QOS: Preserving TOS on miss, TOS=" <<
int(tos));
246 debugs(33, 2,
"QOS: Cache miss, setting TOS=" <<
int(tos));
257 debugs(33, 2,
"QOS: Sibling Peer hit with hier code=" << hierCode <<
", Mark=" << mark);
260 debugs(33, 2,
"QOS: Parent Peer hit with hier code=" << hierCode <<
", Mark=" << mark);
264 debugs(33, 2,
"QOS: Preserving mark on miss, Mark=" << mark);
267 debugs(33, 2,
"QOS: Cache miss, setting Mark=" << mark);
291 tosMiss(0), tosMissMask(0), preserveMissTos(false),
292 preserveMissTosMask(0xFF), markLocalHit(0), markSiblingHit(0),
293 markParentHit(0), markMiss(0), markMissMask(0),
294 preserveMissMark(false), preserveMissMarkMask(0xFFFFFFFF),
295 tosToServer(nullptr), tosToClient(nullptr), nfmarkToServer(nullptr),
296 nfmarkToClient(nullptr)
317 if (!(mark || tos)) {
318 if (strncmp(token,
"mark",4) == 0) {
319#if HAVE_LIBCAP && SO_MARK
322#if USE_LIBNETFILTERCONNTRACK
323 preserveMissMark =
true;
325 preserveMissMark =
false;
327 <<
"Netfilter mark preservation not available.");
332 "Linux Netfilter marking not available on this platform."),
Here());
334 }
else if (strncmp(token,
"tos",3) == 0) {
335 preserveMissTos =
true;
338 preserveMissTos =
true;
343 if (strncmp(token,
"local-hit=",10) == 0) {
346 if (!
xstrtoui(&token[10],
nullptr, &markLocalHit, 0, std::numeric_limits<nfmark_t>::max())) {
351 if (!
xstrtoui(&token[10],
nullptr, &v, 0, std::numeric_limits<tos_t>::max())) {
354 tosLocalHit = (
tos_t)v;
357 }
else if (strncmp(token,
"sibling-hit=",12) == 0) {
360 if (!
xstrtoui(&token[12],
nullptr, &markSiblingHit, 0, std::numeric_limits<nfmark_t>::max())) {
365 if (!
xstrtoui(&token[12],
nullptr, &v, 0, std::numeric_limits<tos_t>::max())) {
368 tosSiblingHit = (
tos_t)v;
371 }
else if (strncmp(token,
"parent-hit=",11) == 0) {
374 if (!
xstrtoui(&token[11],
nullptr, &markParentHit, 0, std::numeric_limits<nfmark_t>::max())) {
379 if (!
xstrtoui(&token[11],
nullptr, &v, 0, std::numeric_limits<tos_t>::max())) {
382 tosParentHit = (
tos_t)v;
385 }
else if (strncmp(token,
"miss=",5) == 0) {
389 if (!
xstrtoui(&token[5], &end, &markMiss, 0, std::numeric_limits<nfmark_t>::max())) {
394 if (!
xstrtoui(end + 1,
nullptr, &markMissMask, 0, std::numeric_limits<nfmark_t>::max())) {
395 debugs(3,
DBG_CRITICAL,
"ERROR: Bad mark miss mask value " << (end + 1) <<
". Using 0xFFFFFFFF instead.");
396 markMissMask = 0xFFFFFFFF;
399 markMissMask = 0xFFFFFFFF;
404 if (!
xstrtoui(&token[5], &end, &v, 0, std::numeric_limits<tos_t>::max())) {
410 if (!
xstrtoui(end + 1,
nullptr, &v, 0, std::numeric_limits<tos_t>::max())) {
411 debugs(3,
DBG_CRITICAL,
"ERROR: Bad TOS miss mask value " << (end + 1) <<
". Using 0xFF instead.");
414 tosMissMask = (
tos_t)v;
420 }
else if (strcmp(token,
"disable-preserve-miss") == 0) {
422 if (preserveMissTosMask!=0xFFU || preserveMissMarkMask!=0xFFFFFFFFU) {
426 preserveMissMark =
false;
427 preserveMissMarkMask = 0;
429 preserveMissTos =
false;
430 preserveMissTosMask = 0;
433 }
else if (strncmp(token,
"miss-mask=",10) == 0) {
435 if (mark && preserveMissMark) {
436 if (!
xstrtoui(&token[10],
nullptr, &preserveMissMarkMask, 0, std::numeric_limits<nfmark_t>::max())) {
439 }
else if (preserveMissTos) {
441 if (!
xstrtoui(&token[10],
nullptr, &v, 0, std::numeric_limits<tos_t>::max())) {
444 preserveMissTosMask = (
tos_t)v;
454template <
class Integer>
461 if (isHitTosActive()) {
462 os << directiveName <<
" tos";
464 if (tosLocalHit > 0) {
467 if (tosSiblingHit > 0) {
470 if (tosParentHit > 0) {
475 if (tosMissMask!=0xFFU) {
479 if (preserveMissTos == 0) {
480 os <<
" disable-preserve-miss";
482 if (preserveMissTos && preserveMissTosMask != 0) {
489 if (isHitNfmarkActive()) {
490 os << directiveName <<
" mark";
492 if (markLocalHit > 0) {
495 if (markSiblingHit > 0) {
498 if (markParentHit > 0) {
503 if (markMissMask!=0xFFFFFFFFU) {
507 if (preserveMissMark ==
false) {
508 os <<
" disable-preserve-miss";
510 if (preserveMissMark && preserveMissMarkMask != 0) {
526 debugs(50, 3,
"for FD " << fd <<
" to " << bTos);
528 if (type == AF_INET) {
530 const int x =
xsetsockopt(fd, IPPROTO_IP, IP_TOS, &bTos,
sizeof(bTos));
533 debugs(50, 2,
"setsockopt(IP_TOS) on " << fd <<
": " <<
xstrerr(xerrno));
541#if defined(IPV6_TCLASS)
542 const int x =
xsetsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &bTos,
sizeof(bTos));
545 debugs(50, 2,
"setsockopt(IPV6_TCLASS) on " << fd <<
": " <<
xstrerr(xerrno));
549 debugs(50,
DBG_IMPORTANT,
"WARNING: setsockopt(IPV6_TCLASS) not supported on this platform");
561 conn->
tos = (x >= 0) ? tos : 0;
568#if HAVE_LIBCAP && SO_MARK
569 debugs(50, 3,
"for FD " << fd <<
" to " << mark);
573 debugs(50, 2,
"setsockopt(SO_MARK) on " << fd <<
": " <<
xstrerr(xerrno));
584 debugs(50,
DBG_IMPORTANT,
"WARNING: Netfilter marking disabled (requires build --with-cap)");
593 conn->
nfmark = (x >= 0) ? mark : 0;
600 acl_nfmark * nfmarkAcls [] = { nfmarkToServer, nfmarkToClient };
602 for (
int i=0; i<2; ++i) {
603 while (nfmarkAcls[i]) {
607 nfmarkAcls[i] = l->
next;
617 acl_tos * tosAcls [] = { tosToServer, tosToClient };
619 for (
int i=0; i<2; ++i) {
624 tosAcls[i] = l->
next;
#define Assure(condition)
#define Here()
source code location of the caller
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
void dump_QosConfig(StoreEntry *const entry, const char *const directiveName, const Ip::Qos::Config &config)
static auto asQosConfigHex(const Integer n)
helper function for printing Ip::Qos::Config mark and tos values
static char server[MAXLINE]
#define CBDATA_CLASS_INIT(type)
static char * NextToken()
bool getInAddr(struct in_addr &) const
unsigned short port() const
a netfilter mark/mask pair
nfmark_t applyToMark(nfmark_t m) const
bool isEmpty() const
whether the netfilter mark is unset
nfmark_t markParentHit
Netfilter mark value to apply to hits from parent.
tos_t tosMiss
TOS value to apply to cache misses.
bool isAclTosActive() const
nfmark_t markMiss
Netfilter mark value to apply to cache misses.
tos_t preserveMissTosMask
The mask to apply when preserving the TOS of misses. Applies to preserved value from upstream.
nfmark_t markMissMask
Mask for netfilter mark value to apply to cache misses. Applied to the markMiss value.
nfmark_t preserveMissMarkMask
The mask to apply when preserving the netfilter mark of misses. Applied to preserved value from upstr...
tos_t tosMissMask
Mask for TOS value to apply to cache misses. Applied to the tosMiss value.
tos_t tosSiblingHit
TOS value to apply to hits from siblings.
nfmark_t markSiblingHit
Netfilter mark value to apply to hits from siblings.
tos_t tosParentHit
TOS value to apply to hits from parent.
bool isAclNfmarkActive() const
void dumpConfigLine(std::ostream &, const char *) const
report configuration using qos_flows syntax
an std::runtime_error with thrower location info
Ip::NfMarkConfig markConfig
#define SQUID_CMSG_DATA(cmsg)
#define debugs(SECTION, LEVEL, CONTENT)
void aclDestroyAclList(ACLList **list)
void getTosFromServer(const Comm::ConnectionPointer &server, fde *clientFde)
bool setNfConnmark(Comm::ConnectionPointer &conn, const ConnectionDirection connDir, const NfMarkConfig &cm)
ConnectionDirection
Possible Squid roles in connection handling.
@ dirAccepted
accepted (from a client by Squid)
int doNfmarkLocalHit(const Comm::ConnectionPointer &conn)
Config TheConfig
Globally available instance of Qos::Config.
int doTosLocalMiss(const Comm::ConnectionPointer &conn, const hier_code hierCode)
int setSockTos(const Comm::ConnectionPointer &conn, tos_t tos)
int doNfmarkLocalMiss(const Comm::ConnectionPointer &conn, const hier_code hierCode)
int doTosLocalHit(const Comm::ConnectionPointer &conn)
int setSockNfmark(const Comm::ConnectionPointer &conn, nfmark_t mark)
nfmark_t getNfConnmark(const Comm::ConnectionPointer &conn, const ConnectionDirection connDir)
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
int xgetsockopt(int socketFd, int level, int optionName, void *optionValue, socklen_t *optionLength)
POSIX getsockopt(2) equivalent.
int xsetsockopt(int socketFd, int level, int option, const void *value, socklen_t valueLength)
POSIX setsockopt(2) equivalent.
const char * xstrerr(int error)
bool xstrtoui(const char *s, char **end, unsigned int *value, unsigned int min, unsigned int max)