45#if USE_QOS_TOS && _SQUID_LINUX_
48 int tos_len =
sizeof(tos);
50 if (setsockopt(
server->fd,SOL_IP,IP_RECVTOS,&tos,tos_len)==0) {
51 unsigned char buf[512];
53 if (getsockopt(
server->fd,SOL_IP,IP_PKTOPTIONS,buf,(
socklen_t*)&len) == 0) {
58 unsigned char * pbuf = buf;
59 while (pbuf-buf < len) {
85#if USE_LIBNETFILTERCONNTRACK
96getNfmarkCallback(
enum nf_conntrack_msg_type,
struct nf_conntrack *ct,
void *connmark)
98 auto *mark =
static_cast<nfmark_t *
>(connmark);
99 *mark = nfct_get_attr_u32(ct, ATTR_MARK);
101 return NFCT_CB_CONTINUE;
112 if (
auto ct = nfct_new()) {
117 nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET6);
118 struct in6_addr conn_fde_dst_ip6;
120 nfct_set_attr(ct, ATTR_ORIG_IPV6_DST, conn_fde_dst_ip6.s6_addr);
121 struct in6_addr conn_fde_src_ip6;
123 nfct_set_attr(ct, ATTR_ORIG_IPV6_SRC, conn_fde_src_ip6.s6_addr);
125 nfct_set_attr_u8(ct, ATTR_L3PROTO, AF_INET);
126 struct in_addr conn_fde_dst_ip;
128 nfct_set_attr_u32(ct, ATTR_ORIG_IPV4_DST, conn_fde_dst_ip.s_addr);
129 struct in_addr conn_fde_src_ip;
131 nfct_set_attr_u32(ct, ATTR_ORIG_IPV4_SRC, conn_fde_src_ip.s_addr);
134 nfct_set_attr_u8(ct, ATTR_L4PROTO, IPPROTO_TCP);
135 nfct_set_attr_u16(ct, ATTR_ORIG_PORT_DST, htons(dst.
port()));
136 nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, htons(src.
port()));
149#if USE_LIBNETFILTERCONNTRACK
153 if (
const auto ct = prepareConntrackQuery(src, dst)) {
155 if (
struct nfct_handle *h = nfct_open(CONNTRACK, 0)) {
157 nfct_callback_register(h, NFCT_T_ALL, getNfmarkCallback,
static_cast<void *
>(&mark));
159 int x = nfct_query(h, NFCT_Q_GET, ct);
161 const int xerrno = errno;
162 debugs(17, 2,
"QOS: Failed to retrieve connection mark: (" << x <<
") " <<
xstrerr(xerrno)
163 <<
" (Destination " << dst <<
", source " << src <<
")" );
167 debugs(17, 2,
"QOS: Failed to open conntrack handle for netfilter CONNMARK retrieval.");
171 debugs(17, 2,
"QOS: Failed to allocate new conntrack for netfilter CONNMARK retrieval.");
185#if USE_LIBNETFILTERCONNTRACK
192 if (newMark ==
conn->nfConnmark)
195 if (
const auto ct = prepareConntrackQuery(src, dst)) {
197 if (
struct nfct_handle *h = nfct_open(CONNTRACK, 0)) {
198 nfct_set_attr_u32(ct, ATTR_MARK, newMark);
200 const int queryResult = nfct_query(h, NFCT_Q_UPDATE, ct);
201 if (queryResult == 0) {
202 conn->nfConnmark = newMark;
205 const int xerrno = errno;
206 debugs(17, 2,
"QOS: Failed to modify connection mark: (" << queryResult <<
") " <<
xstrerr(xerrno)
207 <<
" (Destination " << dst <<
", source " << src <<
")" );
211 debugs(17, 2,
"QOS: Failed to open conntrack handle for netfilter CONNMARK modification.");
215 debugs(17, 2,
"QOS: Failed to allocate new conntrack for netfilter CONNMARK modification.");
231 debugs(33, 2,
"QOS: Sibling Peer hit with hier code=" << hierCode <<
", TOS=" <<
int(tos));
234 debugs(33, 2,
"QOS: Parent Peer hit with hier code=" << hierCode <<
", TOS=" <<
int(tos));
238 debugs(33, 2,
"QOS: Preserving TOS on miss, TOS=" <<
int(tos));
241 debugs(33, 2,
"QOS: Cache miss, setting TOS=" <<
int(tos));
252 debugs(33, 2,
"QOS: Sibling Peer hit with hier code=" << hierCode <<
", Mark=" << mark);
255 debugs(33, 2,
"QOS: Parent Peer hit with hier code=" << hierCode <<
", Mark=" << mark);
259 debugs(33, 2,
"QOS: Preserving mark on miss, Mark=" << mark);
262 debugs(33, 2,
"QOS: Cache miss, setting Mark=" << mark);
286 tosMiss(0), tosMissMask(0), preserveMissTos(false),
287 preserveMissTosMask(0xFF), markLocalHit(0), markSiblingHit(0),
288 markParentHit(0), markMiss(0), markMissMask(0),
289 preserveMissMark(false), preserveMissMarkMask(0xFFFFFFFF),
290 tosToServer(nullptr), tosToClient(nullptr), nfmarkToServer(nullptr),
291 nfmarkToClient(nullptr)
306 debugs(3,
DBG_CRITICAL,
"ERROR: Invalid option 'qos_flows'. QOS features not enabled in this build");
313 if (!(mark || tos)) {
314 if (strncmp(token,
"mark",4) == 0) {
315#if SO_MARK && USE_LIBCAP
318#if USE_LIBNETFILTERCONNTRACK
319 preserveMissMark =
true;
321 preserveMissMark =
false;
323 <<
"Netfilter mark preservation not available.");
327 <<
"Linux Netfilter marking not available without LIBCAP support.");
331 <<
"Linux Netfilter marking not available on this platform.");
334 }
else if (strncmp(token,
"tos",3) == 0) {
335 preserveMissTos =
true;
338 preserveMissTos =
true;
343 if (strncmp(token,
"local-hit=",10) == 0) {
356 tosLocalHit = (
tos_t)v;
359 }
else if (strncmp(token,
"sibling-hit=",12) == 0) {
372 tosSiblingHit = (
tos_t)v;
375 }
else if (strncmp(token,
"parent-hit=",11) == 0) {
388 tosParentHit = (
tos_t)v;
391 }
else if (strncmp(token,
"miss=",5) == 0) {
401 debugs(3,
DBG_CRITICAL,
"ERROR: Bad mark miss mask value " << (end + 1) <<
". Using 0xFFFFFFFF instead.");
402 markMissMask = 0xFFFFFFFF;
405 markMissMask = 0xFFFFFFFF;
416 debugs(3,
DBG_CRITICAL,
"ERROR: Bad TOS miss mask value " << (end + 1) <<
". Using 0xFF instead.");
419 tosMissMask = (
tos_t)v;
425 }
else if (strcmp(token,
"disable-preserve-miss") == 0) {
427 if (preserveMissTosMask!=0xFFU || preserveMissMarkMask!=0xFFFFFFFFU) {
428 debugs(3,
DBG_CRITICAL,
"ERROR: miss-mask feature cannot be set with disable-preserve-miss");
432 preserveMissMark =
false;
433 preserveMissMarkMask = 0;
435 preserveMissTos =
false;
436 preserveMissTosMask = 0;
439 }
else if (strncmp(token,
"miss-mask=",10) == 0) {
441 if (mark && preserveMissMark) {
446 }
else if (preserveMissTos) {
452 preserveMissTosMask = (
tos_t)v;
454 debugs(3,
DBG_CRITICAL,
"ERROR: miss-mask feature cannot be set without miss-preservation enabled");
471 if (isHitTosActive()) {
473 p += snprintf(p, 11,
"%s", name);
474 p += snprintf(p, 4,
"%s",
"tos");
476 if (tosLocalHit > 0) {
477 p += snprintf(p, 16,
" local-hit=0x%02X", tosLocalHit);
479 if (tosSiblingHit > 0) {
480 p += snprintf(p, 18,
" sibling-hit=0x%02X", tosSiblingHit);
482 if (tosParentHit > 0) {
483 p += snprintf(p, 17,
" parent-hit=0x%02X", tosParentHit);
486 p += snprintf(p, 11,
" miss=0x%02X", tosMiss);
487 if (tosMissMask!=0xFFU) {
488 p += snprintf(p, 6,
"/0x%02X", tosMissMask);
491 if (preserveMissTos == 0) {
492 p += snprintf(p, 23,
" disable-preserve-miss");
494 if (preserveMissTos && preserveMissTosMask != 0) {
495 p += snprintf(p, 16,
" miss-mask=0x%02X", preserveMissTosMask);
497 p += snprintf(p, 2,
"\n");
500 if (isHitNfmarkActive()) {
501 p += snprintf(p, 11,
"%s", name);
502 p += snprintf(p, 5,
"%s",
"mark");
504 if (markLocalHit > 0) {
505 p += snprintf(p, 22,
" local-hit=0x%02X", markLocalHit);
507 if (markSiblingHit > 0) {
508 p += snprintf(p, 24,
" sibling-hit=0x%02X", markSiblingHit);
510 if (markParentHit > 0) {
511 p += snprintf(p, 23,
" parent-hit=0x%02X", markParentHit);
514 p += snprintf(p, 17,
" miss=0x%02X", markMiss);
515 if (markMissMask!=0xFFFFFFFFU) {
516 p += snprintf(p, 12,
"/0x%02X", markMissMask);
519 if (preserveMissMark ==
false) {
520 p += snprintf(p, 23,
" disable-preserve-miss");
522 if (preserveMissMark && preserveMissMarkMask != 0) {
523 p += snprintf(p, 22,
" miss-mask=0x%02X", preserveMissMarkMask);
525 p += snprintf(p, 2,
"\n");
538 debugs(50, 3,
"for FD " << fd <<
" to " << bTos);
540 if (type == AF_INET) {
542 const int x = setsockopt(fd, IPPROTO_IP, IP_TOS, &bTos,
sizeof(bTos));
545 debugs(50, 2,
"setsockopt(IP_TOS) on " << fd <<
": " <<
xstrerr(xerrno));
553#if defined(IPV6_TCLASS)
554 const int x = setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &bTos,
sizeof(bTos));
557 debugs(50, 2,
"setsockopt(IPV6_TCLASS) on " << fd <<
": " <<
xstrerr(xerrno));
561 debugs(50,
DBG_IMPORTANT,
"WARNING: setsockopt(IPV6_TCLASS) not supported on this platform");
573 conn->tos = (x >= 0) ? tos : 0;
580#if SO_MARK && USE_LIBCAP
581 debugs(50, 3,
"for FD " << fd <<
" to " << mark);
582 const int x = setsockopt(fd, SOL_SOCKET, SO_MARK, &mark,
sizeof(
nfmark_t));
585 debugs(50, 2,
"setsockopt(SO_MARK) on " << fd <<
": " <<
xstrerr(xerrno));
596 debugs(50,
DBG_IMPORTANT,
"WARNING: Netfilter marking disabled (netfilter marking requires build with LIBCAP)");
605 conn->nfmark = (x >= 0) ? mark : 0;
612 acl_nfmark * nfmarkAcls [] = { nfmarkToServer, nfmarkToClient };
614 for (
int i=0; i<2; ++i) {
615 while (nfmarkAcls[i]) {
619 nfmarkAcls[i] = l->
next;
629 acl_tos * tosAcls [] = { tosToServer, tosToClient };
631 for (
int i=0; i<2; ++i) {
636 tosAcls[i] = l->
next;
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
CBDATA_CLASS_INIT(acl_tos)
int conn
the current server connection FD
static char server[MAXLINE]
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.
void dumpConfigLine(char *entry, const char *name) const
bool isAclNfmarkActive() const
Ip::NfMarkConfig markConfig
#define SQUID_CMSG_DATA(cmsg)
A const & max(A const &lhs, A const &rhs)
#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)
int EnableIpv6
Whether IPv6 is supported and type of support.
const char * xstrerr(int error)
bool xstrtoui(const char *s, char **end, unsigned int *value, unsigned int min, unsigned int max)