Skip to content

Commit

Permalink
bpf: Remove duplicate code in bpf_sock.c
Browse files Browse the repository at this point in the history
This commit refactors __sock{4,6}_xlate() functions in a way that they
can be used to replace __sock{4,6}_snd_xlate().

The refactoring also allows us to get rid of the sock6_xlate_snd_v4_in_v6()
function.

Signed-off-by: Martynas Pumputis <m@lambda.lt>
  • Loading branch information
brb authored and borkmann committed Apr 8, 2020
1 parent 0106b8d commit d8fee7c
Showing 1 changed file with 29 additions and 157 deletions.
186 changes: 29 additions & 157 deletions bpf/bpf_sock.c
Expand Up @@ -234,7 +234,8 @@ sock4_nodeport_wildcard_lookup(struct lb4_key *key __maybe_unused,
}

static __always_inline int __sock4_xlate(struct bpf_sock_addr *ctx,
struct bpf_sock_addr *ctx_full)
struct bpf_sock_addr *ctx_full,
const bool udp_only)
{
const bool in_hostns = ctx_in_hostns(ctx_full);
struct lb4_backend *backend;
Expand All @@ -245,7 +246,7 @@ static __always_inline int __sock4_xlate(struct bpf_sock_addr *ctx,
};
struct lb4_service *slave_svc;

if (!sock_proto_enabled(ctx->protocol))
if (!udp_only && !sock_proto_enabled(ctx->protocol))
return -ENOTSUP;

/* Initial non-wildcarded lookup handles regular services
Expand Down Expand Up @@ -286,14 +287,19 @@ static __always_inline int __sock4_xlate(struct bpf_sock_addr *ctx,
return -ENOENT;
}

if (ctx->protocol != IPPROTO_TCP &&
sock4_update_revnat(ctx_full, backend, &key,
/* revnat entry is not required for TCP protocol */
if (!udp_only && ctx->protocol == IPPROTO_TCP) {
goto update_dst;
}

if (sock4_update_revnat(ctx_full, backend, &key,
slave_svc) < 0) {
update_metrics(0, METRIC_EGRESS, REASON_LB_REVNAT_UPDATE);
return -ENOMEM;
}

ctx->user_ip4 = backend->address;
update_dst:
ctx->user_ip4 = backend->address;
ctx_set_port(ctx, backend->port);

return 0;
Expand All @@ -302,7 +308,7 @@ static __always_inline int __sock4_xlate(struct bpf_sock_addr *ctx,
__section("from-sock4")
int sock4_xlate(struct bpf_sock_addr *ctx)
{
__sock4_xlate(ctx, ctx);
__sock4_xlate(ctx, ctx, false);
return SYS_PROCEED;
}

Expand Down Expand Up @@ -351,61 +357,10 @@ int sock4_post_bind(struct bpf_sock *ctx)
#endif /* ENABLE_NODEPORT || ENABLE_EXTERNAL_IP */

#ifdef ENABLE_HOST_SERVICES_UDP
static __always_inline int __sock4_xlate_snd(struct bpf_sock_addr *ctx,
struct bpf_sock_addr *ctx_full)
{
const bool in_hostns = ctx_in_hostns(ctx_full);
struct lb4_key lkey = {
.address = ctx->user_ip4,
.dport = ctx_dst_port(ctx),
};
struct lb4_backend *backend;
struct lb4_service *svc;
struct lb4_service *slave_svc;

svc = lb4_lookup_service(&lkey);
if (!svc) {
lkey.dport = ctx_dst_port(ctx);
svc = sock4_nodeport_wildcard_lookup(&lkey, true, in_hostns);
if (svc && !lb4_svc_is_nodeport(svc))
svc = NULL;
}
if (!svc)
return -ENXIO;

if (sock4_skip_xlate(svc, in_hostns, ctx->user_ip4))
return -EPERM;

lkey.slave = (sock_local_cookie(ctx_full) % svc->count) + 1;

slave_svc = __lb4_lookup_slave(&lkey);
if (!slave_svc) {
update_metrics(0, METRIC_EGRESS, REASON_LB_NO_SLAVE);
return -ENOENT;
}

backend = __lb4_lookup_backend(slave_svc->backend_id);
if (!backend) {
update_metrics(0, METRIC_EGRESS, REASON_LB_NO_BACKEND);
return -ENOENT;
}

if (sock4_update_revnat(ctx_full, backend, &lkey,
slave_svc) < 0) {
update_metrics(0, METRIC_EGRESS, REASON_LB_REVNAT_UPDATE);
return -ENOMEM;
}

ctx->user_ip4 = backend->address;
ctx_set_port(ctx, backend->port);

return 0;
}

__section("snd-sock4")
int sock4_xlate_snd(struct bpf_sock_addr *ctx)
{
__sock4_xlate_snd(ctx, ctx);
__sock4_xlate(ctx, ctx, true);
return SYS_PROCEED;
}

Expand Down Expand Up @@ -582,7 +537,8 @@ sock6_nodeport_wildcard_lookup(struct lb6_key *key __maybe_unused,
}

static __always_inline
int sock6_xlate_v4_in_v6(struct bpf_sock_addr *ctx __maybe_unused)
int sock6_xlate_v4_in_v6(struct bpf_sock_addr *ctx __maybe_unused,
const bool udp_only __maybe_unused)
{
#ifdef ENABLE_IPV4
struct bpf_sock_addr fake_ctx;
Expand All @@ -598,7 +554,7 @@ int sock6_xlate_v4_in_v6(struct bpf_sock_addr *ctx __maybe_unused)
fake_ctx.user_ip4 = addr6.p4;
fake_ctx.user_port = ctx_dst_port(ctx);

ret = __sock4_xlate(&fake_ctx, ctx);
ret = __sock4_xlate(&fake_ctx, ctx, udp_only);
if (ret < 0)
return ret;

Expand Down Expand Up @@ -669,7 +625,8 @@ int sock6_post_bind(struct bpf_sock *ctx)
}
#endif /* ENABLE_NODEPORT || ENABLE_EXTERNAL_IP */

static __always_inline int __sock6_xlate(struct bpf_sock_addr *ctx)
static __always_inline int __sock6_xlate(struct bpf_sock_addr *ctx,
const bool udp_only)
{
#ifdef ENABLE_IPV6
const bool in_hostns = ctx_in_hostns(ctx);
Expand All @@ -681,7 +638,7 @@ static __always_inline int __sock6_xlate(struct bpf_sock_addr *ctx)
struct lb6_service *slave_svc;
union v6addr v6_orig;

if (!sock_proto_enabled(ctx->protocol))
if (!udp_only && !sock_proto_enabled(ctx->protocol))
return -ENOTSUP;

ctx_get_v6_address(ctx, &key.address);
Expand All @@ -694,7 +651,7 @@ static __always_inline int __sock6_xlate(struct bpf_sock_addr *ctx)
if (svc && !lb6_svc_is_nodeport(svc))
svc = NULL;
else if (!svc)
return sock6_xlate_v4_in_v6(ctx);
return sock6_xlate_v4_in_v6(ctx, udp_only);
}
if (!svc)
return -ENXIO;
Expand All @@ -716,123 +673,38 @@ static __always_inline int __sock6_xlate(struct bpf_sock_addr *ctx)
return -ENOENT;
}

if (ctx->protocol != IPPROTO_TCP &&
sock6_update_revnat(ctx, backend, &key,
if (!udp_only && ctx->protocol == IPPROTO_TCP) {
goto update_dst;
}

if (sock6_update_revnat(ctx, backend, &key,
slave_svc) < 0) {
update_metrics(0, METRIC_EGRESS, REASON_LB_REVNAT_UPDATE);
return -ENOMEM;
}

update_dst:
ctx_set_v6_address(ctx, &backend->address);
ctx_set_port(ctx, backend->port);

return 0;
#else
return sock6_xlate_v4_in_v6(ctx);
return sock6_xlate_v4_in_v6(ctx, udp_only);
#endif /* ENABLE_IPV6 */
}

__section("from-sock6")
int sock6_xlate(struct bpf_sock_addr *ctx)
{
__sock6_xlate(ctx);
__sock6_xlate(ctx, false);
return SYS_PROCEED;
}

#ifdef ENABLE_HOST_SERVICES_UDP
static __always_inline int
sock6_xlate_snd_v4_in_v6(struct bpf_sock_addr *ctx __maybe_unused)
{
#ifdef ENABLE_IPV4
struct bpf_sock_addr fake_ctx;
union v6addr addr6;
int ret;

ctx_get_v6_address(ctx, &addr6);
if (!is_v4_in_v6(&addr6))
return -ENXIO;

__builtin_memset(&fake_ctx, 0, sizeof(fake_ctx));
fake_ctx.protocol = ctx->protocol;
fake_ctx.user_ip4 = addr6.p4;
fake_ctx.user_port = ctx_dst_port(ctx);

ret = __sock4_xlate_snd(&fake_ctx, ctx);
if (ret < 0)
return ret;

build_v4_in_v6(&addr6, fake_ctx.user_ip4);
ctx_set_v6_address(ctx, &addr6);
ctx_set_port(ctx, fake_ctx.user_port);

return 0;
#endif /* ENABLE_IPV4 */
return -ENXIO;
}

static __always_inline int __sock6_xlate_snd(struct bpf_sock_addr *ctx)
{
#ifdef ENABLE_IPV6
const bool in_hostns = ctx_in_hostns(ctx);
struct lb6_backend *backend;
struct lb6_service *svc;
struct lb6_key lkey = {
.dport = ctx_dst_port(ctx),
};
struct lb6_service *slave_svc;
union v6addr v6_orig;

ctx_get_v6_address(ctx, &lkey.address);
v6_orig = lkey.address;

svc = lb6_lookup_service(&lkey);
if (!svc) {
lkey.dport = ctx_dst_port(ctx);
svc = sock6_nodeport_wildcard_lookup(&lkey, true, in_hostns);
if (svc && !lb6_svc_is_nodeport(svc))
svc = NULL;
else if (!svc)
return sock6_xlate_snd_v4_in_v6(ctx);
}
if (!svc)
return -ENXIO;

if (sock6_skip_xlate(svc, in_hostns, &v6_orig))
return -EPERM;

lkey.slave = (sock_local_cookie(ctx) % svc->count) + 1;

slave_svc = __lb6_lookup_slave(&lkey);
if (!slave_svc) {
update_metrics(0, METRIC_EGRESS, REASON_LB_NO_SLAVE);
return -ENOENT;
}

backend = __lb6_lookup_backend(slave_svc->backend_id);
if (!backend) {
update_metrics(0, METRIC_EGRESS, REASON_LB_NO_BACKEND);
return -ENOENT;
}

if (sock6_update_revnat(ctx, backend, &lkey,
slave_svc) < 0) {
update_metrics(0, METRIC_EGRESS, REASON_LB_REVNAT_UPDATE);
return -ENOMEM;
}

ctx_set_v6_address(ctx, &backend->address);
ctx_set_port(ctx, backend->port);

return 0;
#else
return sock6_xlate_snd_v4_in_v6(ctx);
#endif /* ENABLE_IPV6 */
}

__section("snd-sock6")
static __always_inline int sock6_xlate_snd(struct bpf_sock_addr *ctx)
{
__sock6_xlate_snd(ctx);
__sock6_xlate(ctx, true);
return SYS_PROCEED;
}

Expand Down

0 comments on commit d8fee7c

Please sign in to comment.