Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cpworker/src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -728,16 +728,16 @@ static int parse_output_config(cJSON *output_obj, OutputConfig *output, cJSONPar
// Service Tag
cJSON *service_tag = cJSON_GetObjectItemCaseSensitive(gre_obj, "service_tag");
if (!service_tag)
output->config.gre.service_tag = 0xffffffff;
output->config.gre.service_tag = 0x0fffffff;
else
{
int64_t value;
if (!cjson_get_int64_range(service_tag, "gre.service_tag", 0, UINT32_MAX, &value, err))
return PARSE_ERROR;
// The GRE key is service_tag | (direction << 28): the high 4 bits belong to the direction.
// The GRE key is (service_tag & 0x0FFFFFFF) | (direction << 28): the high 4 bits belong to the direction.
if (value > 0x0FFFFFFF)
log_warn("gre.service_tag %lld exceeds 28 bits and overlaps the direction bits of the GRE key",
(long long)value);
log_warn("gre.service_tag %lld exceeds 28 bits: the GRE key carries %lld", (long long)value,
(long long)(value & 0x0FFFFFFF));
output->config.gre.service_tag = (uint32_t)value;
}

Expand Down
3 changes: 2 additions & 1 deletion cpworker/src/output_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ int gre_send_packet(output_base_t *self, const struct pcap_pkthdr *header, const
}

struct gre_header *gre_hdr = (struct gre_header *)output->buf;
gre_hdr->keybit = htonl(output->service_tag | (direct << 28));
// The high 4 bits of the key carry the direction, the low 28 bits the service tag.
gre_hdr->keybit = htonl((output->service_tag & 0x0FFFFFFF) | (direct << 28));
memcpy(&(output->buf[GRE_HEADER_LEN]), pkt_data, frame_len);

// check error_info
Expand Down
13 changes: 11 additions & 2 deletions cpworker/tests/integration/wire_format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,20 +262,29 @@ func TestWireFormat(t *testing.T) {
gre := func(serviceTag int) map[string]any {
return map[string]any{"type": "gre", "gre": map[string]any{"host": "127.0.0.1", "service_tag": serviceTag}}
}
noTag := map[string]any{"type": "gre", "gre": map[string]any{"host": "127.0.0.1"}}
runWireTasks(t, out, []wireTask{
{input: []wirePacket{req, rsp}, output: gre(0x111)},
{input: []wirePacket{req, rsp}, reqPattern: true, output: gre(0x123)},
{input: []wirePacket{req}, output: noTag},
{input: []wirePacket{req, rsp}, reqPattern: true, output: noTag},
{input: []wirePacket{req, rsp}, reqPattern: true, output: gre(0xF0000123)},
})
capturer.Stop()

// Flags 0x2000: only the key bit (RFC 2890), version 0. Protocol type 0x6558:
// transparent Ethernet bridging. The key carries the direction in its high 4 bits
// (USAGE-CPWORKER.md, output.gre). The key without a configured service_tag is #296's.
// transparent Ethernet bridging. The key is the direction in its high 4 bits and the
// low 28 bits of service_tag, 0xFFFFFFF when none is configured (USAGE-CPWORKER.md, output.gre).
want := [][]byte{
cat(unhex("2000 6558 0000 0111"), req.data),
cat(unhex("2000 6558 0000 0111"), rsp.data),
cat(unhex("2000 6558 1000 0123"), req.data),
cat(unhex("2000 6558 2000 0123"), rsp.data),
cat(unhex("2000 6558 0FFF FFFF"), req.data),
cat(unhex("2000 6558 1FFF FFFF"), req.data),
cat(unhex("2000 6558 2FFF FFFF"), rsp.data),
cat(unhex("2000 6558 1000 0123"), req.data),
cat(unhex("2000 6558 2000 0123"), rsp.data),
}
assertSameDatagrams(t, ipPayloads(readPcapData(t, capPath), layers.IPProtocolGRE), want)
})
Expand Down
5 changes: 3 additions & 2 deletions cpworker/tests/unit/config_validation.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ void test_zmq_service_tag_invalid_rejected(void)
assert_rejected(config_with_output(zmq_output_with_service_tag(bad[i])), "invalid zmq.service_tag");
}

// The high 4 bits of the GRE key carry the direction; larger tags are kept (with a warning) as cpdaemon may send them.
// Larger tags are kept (with a warning) as cpdaemon may send them; the GRE output masks them to 28 bits.
void test_gre_service_tag_uint32_kept(void)
{
const char *values[] = {"0", "268435455", "268435456", "4294967295"};
Expand All @@ -510,9 +510,10 @@ void test_gre_service_tag_uint32_kept(void)
assert_gre_service_tag(gre_output_with_service_tag(values[i]), expected[i]);
}

// The default must fit in 28 bits so that the direction in the high 4 bits of the GRE key survives.
void test_gre_service_tag_default(void)
{
assert_gre_service_tag("{\"type\": \"gre\", \"gre\": {\"host\": \"10.0.0.1\"}}", 0xFFFFFFFF);
assert_gre_service_tag("{\"type\": \"gre\", \"gre\": {\"host\": \"10.0.0.1\"}}", 0x0FFFFFFF);
}

void test_gre_service_tag_invalid_rejected(void)
Expand Down
12 changes: 11 additions & 1 deletion docs/USAGE-CPWORKER-zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,17 @@ cpworker 是基于 libpcap 的网络抓包工具,支持多种输出方式和
| host | string | - | 目的ip |
| bind_device | string | - | 绑定数据包发送接口,默认不指定|
| pmtudisc | string | - | 指定MTU发现模式,可选值: do, dont, want |
| service_tag | int | 0xFFFFFFFF | 业务标签,放在 GRE key 中,28 位(0x0-0xFFFFFFF);key 的高 4 位携带方向 |
| service_tag | int | 0xFFFFFFF | 业务标签,放在 GRE key 中,28 位(0x0-0xFFFFFFF);更大的值保留低 28 位。key 的高 4 位携带方向 |

每个报文是一个 IPv4 包(协议号 47),载荷为 8 字节 GRE 头(RFC 2890)加上采集到的以太网帧:

| 偏移 | 长度 | 字段 | 值 |
| --- | --- | --- | --- |
| 0 | 2 | flags、version | `0x2000`:带 key,version 0 |
| 2 | 2 | protocol type | `0x6558`:透明以太网桥接 |
| 4 | 4 | key(网络字节序) | 第 28–31 位:方向(0 未配置 `req_pattern`,1 请求,2 响应);第 0–27 位:`service_tag & 0xFFFFFFF` |

未配置 `service_tag` 时低 28 位为 `0xFFFFFFF`,key 为 `0x0FFFFFFF`、`0x1FFFFFFF` 或 `0x2FFFFFFF`。方向未知的包被丢弃。

## output.vxlan 参数列表
| 参数 | 类型 | 默认值 | 说明 |
Expand Down
12 changes: 11 additions & 1 deletion docs/USAGE-CPWORKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,17 @@ Values shown in hexadecimal (e.g. `0xFFF`) must be written in decimal in the JSO
| host | string | - | Destination IP |
| bind_device | string | - | Bind interface (default: any) |
| pmtudisc | string | - | MTU discovery mode (do/dont/want) |
| service_tag | int | 0xFFFFFFFF | Service tag carried in the GRE key, 28 bits (0x0-0xFFFFFFF); the high 4 bits of the key carry the direction |
| service_tag | int | 0xFFFFFFF | Service tag carried in the GRE key, 28 bits (0x0-0xFFFFFFF); larger values keep the low 28 bits. The high 4 bits of the key carry the direction |

Each datagram is an IPv4 packet (protocol 47) whose payload is an 8-byte GRE header (RFC 2890) followed by the captured Ethernet frame:

| Offset | Size | Field | Value |
| --- | --- | --- | --- |
| 0 | 2 | flags, version | `0x2000`: key present, version 0 |
| 2 | 2 | protocol type | `0x6558`: transparent Ethernet bridging |
| 4 | 4 | key (network byte order) | bits 28-31: direction (0 no `req_pattern`, 1 request, 2 response); bits 0-27: `service_tag & 0xFFFFFFF` |

Without a `service_tag`, the low 28 bits are `0xFFFFFFF`: the key is `0x0FFFFFFF`, `0x1FFFFFFF` or `0x2FFFFFFF`. Packets of unknown direction are dropped.

## output.vxlan Parameters
| Parameter | Type | Default | Description |
Expand Down
Loading