bpf: add End.DT6 action to bpf_lwt_seg6_action helper
The seg6local LWT provides the End.DT6 action, which allows to decapsulate an outer IPv6 header containing a Segment Routing Header (SRH), full specification is available here: https://tools.ietf.org/html/draft-filsfils-spring-srv6-network-programming-05 This patch adds this action now to the seg6local BPF interface. Since it is not mandatory that the inner IPv6 header also contains a SRH, seg6_bpf_srh_state has been extended with a pointer to a possible SRH of the outermost IPv6 header. This helps assessing if the validation must be triggered or not, and avoids some calls to ipv6_find_hdr. v3: s/1/true, s/0/false for boolean values v2: - changed true/false -> 1/0 - preempt_enable no longer called in first conditional block Signed-off-by: Mathieu Xhonneux <m.xhonneux@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:

committed by
Daniel Borkmann

parent
1ce6a9fc15
commit
486cdf2158
@@ -459,36 +459,57 @@ drop:
|
||||
|
||||
DEFINE_PER_CPU(struct seg6_bpf_srh_state, seg6_bpf_srh_states);
|
||||
|
||||
bool seg6_bpf_has_valid_srh(struct sk_buff *skb)
|
||||
{
|
||||
struct seg6_bpf_srh_state *srh_state =
|
||||
this_cpu_ptr(&seg6_bpf_srh_states);
|
||||
struct ipv6_sr_hdr *srh = srh_state->srh;
|
||||
|
||||
if (unlikely(srh == NULL))
|
||||
return false;
|
||||
|
||||
if (unlikely(!srh_state->valid)) {
|
||||
if ((srh_state->hdrlen & 7) != 0)
|
||||
return false;
|
||||
|
||||
srh->hdrlen = (u8)(srh_state->hdrlen >> 3);
|
||||
if (!seg6_validate_srh(srh, (srh->hdrlen + 1) << 3))
|
||||
return false;
|
||||
|
||||
srh_state->valid = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int input_action_end_bpf(struct sk_buff *skb,
|
||||
struct seg6_local_lwt *slwt)
|
||||
{
|
||||
struct seg6_bpf_srh_state *srh_state =
|
||||
this_cpu_ptr(&seg6_bpf_srh_states);
|
||||
struct seg6_bpf_srh_state local_srh_state;
|
||||
struct ipv6_sr_hdr *srh;
|
||||
int srhoff = 0;
|
||||
int ret;
|
||||
|
||||
srh = get_and_validate_srh(skb);
|
||||
if (!srh)
|
||||
goto drop;
|
||||
if (!srh) {
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
advance_nextseg(srh, &ipv6_hdr(skb)->daddr);
|
||||
|
||||
/* preempt_disable is needed to protect the per-CPU buffer srh_state,
|
||||
* which is also accessed by the bpf_lwt_seg6_* helpers
|
||||
*/
|
||||
preempt_disable();
|
||||
srh_state->srh = srh;
|
||||
srh_state->hdrlen = srh->hdrlen << 3;
|
||||
srh_state->valid = 1;
|
||||
srh_state->valid = true;
|
||||
|
||||
rcu_read_lock();
|
||||
bpf_compute_data_pointers(skb);
|
||||
ret = bpf_prog_run_save_cb(slwt->bpf.prog, skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
local_srh_state = *srh_state;
|
||||
preempt_enable();
|
||||
|
||||
switch (ret) {
|
||||
case BPF_OK:
|
||||
case BPF_REDIRECT:
|
||||
@@ -500,24 +521,17 @@ static int input_action_end_bpf(struct sk_buff *skb,
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (unlikely((local_srh_state.hdrlen & 7) != 0))
|
||||
goto drop;
|
||||
|
||||
if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
|
||||
goto drop;
|
||||
srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
|
||||
srh->hdrlen = (u8)(local_srh_state.hdrlen >> 3);
|
||||
|
||||
if (!local_srh_state.valid &&
|
||||
unlikely(!seg6_validate_srh(srh, (srh->hdrlen + 1) << 3)))
|
||||
if (srh_state->srh && !seg6_bpf_has_valid_srh(skb))
|
||||
goto drop;
|
||||
|
||||
preempt_enable();
|
||||
if (ret != BPF_REDIRECT)
|
||||
seg6_lookup_nexthop(skb, NULL, 0);
|
||||
|
||||
return dst_input(skb);
|
||||
|
||||
drop:
|
||||
preempt_enable();
|
||||
kfree_skb(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
Reference in New Issue
Block a user