• Mathieu Xhonneux's avatar
    bpf: Add IPv6 Segment Routing helpers · fe94cc29
    Mathieu Xhonneux authored
    The BPF seg6local hook should be powerful enough to enable users to
    implement most of the use-cases one could think of. After some thinking,
    we figured out that the following actions should be possible on a SRv6
    packet, requiring 3 specific helpers :
        - bpf_lwt_seg6_store_bytes: Modify non-sensitive fields of the SRH
        - bpf_lwt_seg6_adjust_srh: Allow to grow or shrink a SRH
                                   (to add/delete TLVs)
        - bpf_lwt_seg6_action: Apply some SRv6 network programming actions
                               (specifically End.X, End.T, End.B6 and
                                End.B6.Encap)
    
    The specifications of these helpers are provided in the patch (see
    include/uapi/linux/bpf.h).
    
    The non-sensitive fields of the SRH are the following : flags, tag and
    TLVs. The other fields can not be modified, to maintain the SRH
    integrity. Flags, tag and TLVs can easily be modified as their validity
    can be checked afterwards via seg6_validate_srh. It is not allowed to
    modify the segments directly. If one wants to add segments on the path,
    he should stack a new SRH using the End.B6 action via
    bpf_lwt_seg6_action.
    
    Growing, shrinking or editing TLVs via the helpers will flag the SRH as
    invalid, and it will have to be re-validated before re-entering the IPv6
    layer. This flag is stored in a per-CPU buffer, along with the current
    header length in bytes.
    
    Storing the SRH len in bytes in the control block is mandatory when using
    bpf_lwt_seg6_adjust_srh. The Header Ext. Length field contains the SRH
    len rounded to 8 bytes (a padding TLV can be inserted to ensure the 8-bytes
    boundary). When adding/deleting TLVs within the BPF program, the SRH may
    temporary be in an invalid state where its length cannot be rounded to 8
    bytes without remainder, hence the need to store the length in bytes
    separately. The caller of the BPF program can then ensure that the SRH's
    final length is valid using this value. Again, a final SRH modified by a
    BPF program which doesn’t respect the 8-bytes boundary will be discarded
    as it will be considered as invalid.
    
    Finally, a fourth helper is provided, bpf_lwt_push_encap, which is
    available from the LWT BPF IN hook, but not from the seg6local BPF one.
    This helper allows to encapsulate a Segment Routing Header (either with
    a new outer IPv6 header, or by inlining it directly in the existing IPv6
    header) into a non-SRv6 packet. This helper is required if we want to
    offer the possibility to dynamically encapsulate a SRH for non-SRv6 packet,
    as the BPF seg6local hook only works on traffic already containing a SRH.
    This is the BPF equivalent of the seg6 LWT infrastructure, which achieves
    the same purpose but with a static SRH per route.
    
    These helpers require CONFIG_IPV6=y (and not =m).
    Signed-off-by: default avatarMathieu Xhonneux <m.xhonneux@gmail.com>
    Acked-by: default avatarDavid Lebrun <dlebrun@google.com>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    fe94cc29
seg6_local.c 19.3 KB