Skip to content

Commit

Permalink
[BPF] clasiffy correctly forwarded traffic
Browse files Browse the repository at this point in the history
Previously, anything that had source the same as the host was considered
as "from host" by the policy engine and global policies with
applyOnForward=false would apply to such traffic. However, for instance
SNATed traffic due to nat-outgoing would be also considered "from host"
eventhough it originated in a workload.

This fixes it by first looking at a SEEN mark which indicates that the
packet was seen by another endpoint and thus is forwarded with the
exception of packets being routed via the bpf nat iface which is used by
the host processes.
  • Loading branch information
tomastigera committed May 26, 2023
1 parent 03b7805 commit f6058fe
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
2 changes: 2 additions & 0 deletions felix/bpf-gpl/skb.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,6 @@ static CALI_BPF_INLINE void skb_set_mark(struct __sk_buff *skb, __u32 mark)
);
}

#define skb_mark_equals(skb, mask, val) (((skb)->mark & (mask)) == (val))

#endif /* __SKB_H__ */
15 changes: 14 additions & 1 deletion felix/bpf-gpl/tc.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,19 @@ static CALI_BPF_INLINE void calico_tc_process_ct_lookup(struct cali_tc_ctx *ctx)
{
CALI_DEBUG("conntrack entry flags 0x%x\n", ctx->state->ct_result.flags);

/* We are forwarding a packet if it has a seen mark (that is another
* program has seen it already) and is either not routed through the
* bpfnat iface (which may be true for host traffic) or has the specific
* reasons set.
*/
bool forwarding = CALI_F_EGRESS &&
skb_mark_equals(ctx->skb, CALI_SKB_MARK_SEEN_MASK, CALI_SKB_MARK_SEEN) &&
(!skb_mark_equals(ctx->skb, CALI_SKB_MARK_FROM_NAT_IFACE_OUT, CALI_SKB_MARK_FROM_NAT_IFACE_OUT) ||
(skb_mark_equals(ctx->skb, CALI_SKB_MARK_BYPASS_MASK, CALI_SKB_MARK_FALLTHROUGH) ||
skb_mark_equals(ctx->skb, CALI_SKB_MARK_BYPASS_MASK, CALI_SKB_MARK_NAT_OUT) ||
skb_mark_equals(ctx->skb, CALI_SKB_MARK_BYPASS_MASK, CALI_SKB_MARK_MASQ) ||
skb_mark_equals(ctx->skb, CALI_SKB_MARK_BYPASS_MASK, CALI_SKB_MARK_SKIP_FIB)));

if (HAS_HOST_CONFLICT_PROG &&
(ctx->state->ct_result.flags & CALI_CT_FLAG_VIA_NAT_IF) &&
!(ctx->skb->mark & (CALI_SKB_MARK_FROM_NAT_IFACE_OUT | CALI_SKB_MARK_SEEN))) {
Expand Down Expand Up @@ -467,7 +480,7 @@ static CALI_BPF_INLINE void calico_tc_process_ct_lookup(struct cali_tc_ctx *ctx)
}
}

if (rt_addr_is_local_host(ctx->state->ip_src)) {
if (!forwarding && rt_addr_is_local_host(ctx->state->ip_src)) {
CALI_DEBUG("Source IP is local host.\n");
if (CALI_F_TO_HEP && is_failsafe_out(ctx->state->ip_proto, ctx->state->post_nat_dport, ctx->state->post_nat_ip_dst)) {
CALI_DEBUG("Outbound failsafe port: %d. Skip policy.\n", ctx->state->post_nat_dport);
Expand Down
56 changes: 56 additions & 0 deletions felix/fv/bpf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1120,6 +1120,62 @@ func describeBPFTests(opts ...bpfTestOpt) bool {
pol = createPolicy(pol)
})

// The next two policies are to make sure that applyOnForward of a
// global policy is applied correctly to a host endpoint. The deny
// policy is not applied to forwarded traffic!

By("global policy denies traffic to host 1 on host 0", func() {

nets := []string{felixes[1].IP + "/32"}
switch testOpts.tunnel {
case "ipip":
nets = append(nets, felixes[1].ExpectedIPIPTunnelAddr+"/32")
}

pol := api.NewGlobalNetworkPolicy()
pol.Namespace = "fv"
pol.Name = "host-0-1"
pol.Spec.Egress = []api.Rule{
{
Action: "Deny",
Destination: api.EntityRule{
Nets: nets,
},
},
}
pol.Spec.Selector = "node=='" + felixes[0].Name + "'"
pol.Spec.ApplyOnForward = false

pol = createPolicy(pol)
})

By("global policy allows forwarded traffic to host 1 on host 0", func() {

nets := []string{felixes[1].IP + "/32"}
switch testOpts.tunnel {
case "ipip":
nets = append(nets, felixes[1].ExpectedIPIPTunnelAddr+"/32")
}

pol := api.NewGlobalNetworkPolicy()
pol.Namespace = "fv"
pol.Name = "host-0-1-forward"
pol.Spec.Egress = []api.Rule{
{
Action: "Allow",
Destination: api.EntityRule{
Nets: nets,
},
},
}
pol.Spec.Selector = "node=='" + felixes[0].Name + "'"
pol.Spec.ApplyOnForward = true

pol = createPolicy(pol)
})

bpfWaitForPolicy(felixes[0], "eth0", "egress", "default.host-0-1")

k8sClient = infra.(*infrastructure.K8sDatastoreInfra).K8sClient
_ = k8sClient
})
Expand Down

0 comments on commit f6058fe

Please sign in to comment.