Skip to content

Commit

Permalink
Adding TCP Info header support to header rewrite (apache#7516) (apach…
Browse files Browse the repository at this point in the history
…e#174)

* Adding TCP Info header support to header rewrite

Adding documentation for TCP Info support for header rewrite plugin

* Adding TCP Info header support to header rewrite

Adding documentation for TCP Info support for header rewrite plugin

* fixing indentation in doc

* adding header file tcp info

* adding header file tcp info

fixing indentation in doc

* adding header file tcp info

fixing indentation in doc

* Fixing headers where TCP info is written

* adding message for internal transaction

* Adding documenation for TCP-INFO in header rewrite

* Fixing internal header debug message for TCP Info

* adding message for internal transaction

Co-authored-by: Divya Bhat <divyashri_bhat@apple.com>
(cherry picked from commit ebd9d38)

Co-authored-by: dbhat <dbhat@users.noreply.github.com>
  • Loading branch information
2 people authored and GitHub Enterprise committed Jul 14, 2021
1 parent fb4c5af commit e6ba6f6
Show file tree
Hide file tree
Showing 8 changed files with 220 additions and 0 deletions.
27 changes: 27 additions & 0 deletions doc/admin-guide/plugins/header_rewrite.en.rst
Expand Up @@ -487,6 +487,24 @@ Refer to `Requests vs. Responses`_ for more information on determining the
context in which the transaction's URL is evaluated. The ``<part>`` may be
specified according to the options documented in `URL Parts`_.

SSN-TXN-COUNT
~~~~~~~~~~~~~
::

cond %{SSN-TXN-COUNT} <operand>

Returns the number of transactions between the Traffic Server proxy and the origin server from a single session.
Any value greater than zero indicates connection reuse.

TCP-INFO
~~~~~~~~
::

cond %{<name>}
add-header @PropertyName "%{TCP-INFO}"

This operation records TCP Info struct field values as an Internal remap as well as global header at the event hook specified by the condition. Supported hook conditions include TXN_START_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Global plugin and REMAP_PSEUDO_HOOK, SEND_RESPONSE_HEADER_HOOK and TXN_CLOSE_HOOK in the Remap plugin. Conditions supported as request headers include TXN_START_HOOK and REMAP_PSEUDO_HOOK. The other conditions are supported as response headers. TCP Info fields currently recorded include rtt, rto, snd_cwnd and all_retrans. This operation is not supported on transactions originated within Traffic Server (for e.g using the |TS| :c:func:`TSHttpTxnIsInternal`)

Condition Operands
------------------

Expand Down Expand Up @@ -931,6 +949,15 @@ cache updates may have been performed. This hook context provides a means to
modify aspects of the response sent to a client, while still caching the
original versions of those attributes delivered by the origin server.

TXN_START_HOOK
~~~~~~~~~~~~~~
Rulesets are evaluated when |TS| receives a request and accepts it. This hook context indicates that a HTTP transaction is initiated and therefore, can only be enabled as a global plugin.

TXN_CLOSE_HOOK
~~~~~~~~~~~~~~

Rulesets are evaluated when |TS| completes a transaction, i.e., after a response has been sent to the client. Therefore, header modifications at this hook condition only makes sense for internal headers.

Affected Conditions
-------------------

Expand Down
116 changes: 116 additions & 0 deletions plugins/header_rewrite/conditions.cc
Expand Up @@ -34,6 +34,17 @@
#include "conditions.h"
#include "lulu.h"

// This is a bit of a hack, to get the more linux specific tcp_info struct ...
#if HAVE_STRUCT_LINUX_TCP_INFO
#ifndef _LINUX_TCP_H
#define _LINUX_TCP_H
#endif
#elif HAVE_NETINET_IN_H
#ifndef _NETINET_TCP_H
#define _NETINET_TCP_H
#endif
#endif

// ConditionStatus
void
ConditionStatus::initialize(Parser &p)
Expand Down Expand Up @@ -1156,3 +1167,108 @@ ConditionStringLiteral::eval(const Resources &res)

return static_cast<const MatcherType *>(_matcher)->test(_literal);
}

// ConditionSessionTransactCount
void
ConditionSessionTransactCount::initialize(Parser &p)
{
Condition::initialize(p);
MatcherType *match = new MatcherType(_cond_op);
std::string const &arg = p.get_arg();

match->set(strtol(arg.c_str(), nullptr, 10));
_matcher = match;
}

bool
ConditionSessionTransactCount::eval(const Resources &res)
{
int const val = TSHttpTxnServerSsnTransactionCount(res.txnp);

TSDebug(PLUGIN_NAME, "Evaluating SSN-TXN-COUNT()");
return static_cast<MatcherType *>(_matcher)->test(val);
}

void
ConditionSessionTransactCount::append_value(std::string &s, Resources const &res)
{
char value[32]; // enough for UINT64_MAX
int const count = TSHttpTxnServerSsnTransactionCount(res.txnp);
int const length = ink_fast_itoa(count, value, sizeof(value));

if (length > 0) {
TSDebug(PLUGIN_NAME, "Appending SSN-TXN-COUNT %s to evaluation value %.*s", _qualifier.c_str(), length, value);
s.append(value, length);
}
}

void
ConditionTcpInfo::initialize(Parser &p)
{
Condition::initialize(p);
TSDebug(PLUGIN_NAME, "Initializing TCP Info");
MatcherType *match = new MatcherType(_cond_op);
std::string const &arg = p.get_arg();

match->set(strtol(arg.c_str(), nullptr, 10));
_matcher = match;
}

void
ConditionTcpInfo::initialize_hooks()
{
add_allowed_hook(TS_HTTP_TXN_START_HOOK);
add_allowed_hook(TS_HTTP_TXN_CLOSE_HOOK);
add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
}

bool
ConditionTcpInfo::eval(const Resources &res)
{
std::string s;

append_value(s, res);
bool rval = static_cast<const Matchers<std::string> *>(_matcher)->test(s);

TSDebug(PLUGIN_NAME, "Evaluating TCP-Info: %s - rval: %d", s.c_str(), rval);

return rval;
}

void
ConditionTcpInfo::append_value(std::string &s, Resources const &res)
{
#if defined(TCP_INFO) && defined(HAVE_STRUCT_TCP_INFO)
if (TSHttpTxnIsInternal(res.txnp)) {
TSDebug(PLUGIN_NAME, "No TCP-INFO available for internal transactions");
return;
}
TSReturnCode tsSsn;
int fd;
struct tcp_info info;
socklen_t tcp_info_len = sizeof(info);
tsSsn = TSHttpTxnClientFdGet(res.txnp, &fd);
if (tsSsn != TS_SUCCESS || fd <= 0) {
TSDebug(PLUGIN_NAME, "error getting the client socket fd from ssn");
}
if (getsockopt(fd, IPPROTO_TCP, TCP_INFO, &info, &tcp_info_len) != 0) {
TSDebug(PLUGIN_NAME, "getsockopt(%d, TCP_INFO) failed: %s", fd, strerror(errno));
}

if (tsSsn == TS_SUCCESS) {
if (tcp_info_len > 0) {
char buf[12 * 4 + 9]; // 4x uint32's + 4x "; " + '\0'
#if !defined(freebsd) || defined(__GLIBC__)
snprintf(buf, sizeof(buf), "%" PRIu32 ";%" PRIu32 ";%" PRIu32 ";%" PRIu32 "", info.tcpi_rtt, info.tcpi_rto,
info.tcpi_snd_cwnd, info.tcpi_retrans);
#else
snprintf(buf, sizeof(buf), "%" PRIu32 ";%" PRIu32 ";%" PRIu32 ";%" PRIu32 "", info.tcpi_rtt, info.tcpi_rto,
info.tcpi_snd_cwnd, info.__tcpi_retrans);
#endif
s += buf;
}
}
#else
s += "-";
#endif
}
39 changes: 39 additions & 0 deletions plugins/header_rewrite/conditions.h
Expand Up @@ -544,3 +544,42 @@ class ConditionStringLiteral : public Condition
private:
std::string _literal;
};

// Single Session Transaction Count
class ConditionSessionTransactCount : public Condition
{
typedef Matchers<int> MatcherType;

public:
ConditionSessionTransactCount() { TSDebug(PLUGIN_NAME_DBG, "ConditionSessionTransactCount()"); }

// noncopyable
ConditionSessionTransactCount(const ConditionSessionTransactCount &) = delete;
void operator=(const ConditionSessionTransactCount &) = delete;

void initialize(Parser &p) override;
void append_value(std::string &s, const Resources &res) override;

protected:
bool eval(const Resources &res) override;
};

// Tcp Info
class ConditionTcpInfo : public Condition
{
typedef Matchers<int> MatcherType;

public:
ConditionTcpInfo() { TSDebug(PLUGIN_NAME_DBG, "Calling CTOR for ConditionTcpInfo"); }

// noncopyable
ConditionTcpInfo(const ConditionTcpInfo &) = delete;
void operator=(const ConditionTcpInfo &) = delete;

void initialize(Parser &p) override;
void append_value(std::string &s, const Resources &res) override;

protected:
bool eval(const Resources &res) override;
void initialize_hooks() override; // Return status only valid in certain hooks
};
4 changes: 4 additions & 0 deletions plugins/header_rewrite/factory.cc
Expand Up @@ -144,6 +144,10 @@ condition_factory(const std::string &cond)
c = new ConditionCidr();
} else if (c_name == "INBOUND") {
c = new ConditionInbound();
} else if (c_name == "SSN-TXN-COUNT") {
c = new ConditionSessionTransactCount();
} else if (c_name == "TCP-INFO") {
c = new ConditionTcpInfo();
} else {
TSError("[%s] Unknown condition %s", PLUGIN_NAME, c_name.c_str());
return nullptr;
Expand Down
6 changes: 6 additions & 0 deletions plugins/header_rewrite/header_rewrite.cc
Expand Up @@ -266,6 +266,12 @@ cont_rewrite_headers(TSCont contp, TSEvent event, void *edata)
case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
hook = TS_HTTP_SEND_RESPONSE_HDR_HOOK;
break;
case TS_EVENT_HTTP_TXN_START:
hook = TS_HTTP_TXN_START_HOOK;
break;
case TS_EVENT_HTTP_TXN_CLOSE:
hook = TS_HTTP_TXN_CLOSE_HOOK;
break;
default:
TSError("[%s] unknown event for this plugin", PLUGIN_NAME);
TSDebug(PLUGIN_NAME, "unknown event for this plugin");
Expand Down
8 changes: 8 additions & 0 deletions plugins/header_rewrite/parser.cc
Expand Up @@ -244,6 +244,14 @@ Parser::cond_is_hook(TSHttpHookID &hook) const
hook = TS_REMAP_PSEUDO_HOOK;
return true;
}
if ("TXN_START_HOOK" == _op) {
hook = TS_HTTP_TXN_START_HOOK;
return true;
}
if ("TXN_CLOSE_HOOK" == _op) {
hook = TS_HTTP_TXN_CLOSE_HOOK;
return true;
}

return false;
}
Expand Down
18 changes: 18 additions & 0 deletions plugins/header_rewrite/resources.cc
Expand Up @@ -99,6 +99,24 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook)
}
break;

case TS_HTTP_TXN_START_HOOK:
// Get TCP Info at transaction start
if (client_bufp && client_hdr_loc) {
TSDebug(PLUGIN_NAME, "\tAdding TXN client request header buffers for TXN Start instance");
bufp = client_bufp;
hdr_loc = client_hdr_loc;
}
break;

case TS_HTTP_TXN_CLOSE_HOOK:
// Get TCP Info at transaction close
TSDebug(PLUGIN_NAME, "\tAdding TXN close buffers");
if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) {
TSDebug(PLUGIN_NAME, "could not gather bufp/hdr_loc for request");
return;
}
break;

default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions plugins/header_rewrite/statement.cc
Expand Up @@ -69,6 +69,8 @@ Statement::initialize_hooks()
add_allowed_hook(TS_HTTP_SEND_REQUEST_HDR_HOOK);
add_allowed_hook(TS_HTTP_SEND_RESPONSE_HDR_HOOK);
add_allowed_hook(TS_REMAP_PSEUDO_HOOK);
add_allowed_hook(TS_HTTP_TXN_START_HOOK);
add_allowed_hook(TS_HTTP_TXN_CLOSE_HOOK);
}

// Parse URL qualifiers, this one is special since it's used in a few places.
Expand Down

0 comments on commit e6ba6f6

Please sign in to comment.