1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <vmlinux.h> 4 #include "bpf_experimental.h" 5 #include "bpf_qdisc_common.h" 6 7 char _license[] SEC("license") = "GPL"; 8 9 struct skb_node { 10 struct sk_buff __kptr * skb; 11 struct bpf_list_node node; 12 }; 13 14 private(A) struct bpf_spin_lock q_fifo_lock; 15 private(A) struct bpf_list_head q_fifo __contains(skb_node, node); 16 17 SEC("struct_ops/bpf_fifo_enqueue") 18 int BPF_PROG(bpf_fifo_enqueue, struct sk_buff *skb, struct Qdisc *sch, 19 struct bpf_sk_buff_ptr *to_free) 20 { 21 struct skb_node *skbn; 22 u32 pkt_len; 23 24 if (sch->q.qlen == sch->limit) 25 goto drop; 26 27 skbn = bpf_obj_new(typeof(*skbn)); 28 if (!skbn) 29 goto drop; 30 31 pkt_len = qdisc_pkt_len(skb); 32 33 sch->q.qlen++; 34 skb = bpf_kptr_xchg(&skbn->skb, skb); 35 if (skb) 36 bpf_qdisc_skb_drop(skb, to_free); 37 38 bpf_spin_lock(&q_fifo_lock); 39 bpf_list_push_back(&q_fifo, &skbn->node); 40 bpf_spin_unlock(&q_fifo_lock); 41 42 sch->qstats.backlog += pkt_len; 43 return NET_XMIT_SUCCESS; 44 drop: 45 bpf_qdisc_skb_drop(skb, to_free); 46 return NET_XMIT_DROP; 47 } 48 49 SEC("struct_ops/bpf_fifo_dequeue") 50 struct sk_buff *BPF_PROG(bpf_fifo_dequeue, struct Qdisc *sch) 51 { 52 struct bpf_list_node *node; 53 struct sk_buff *skb = NULL; 54 struct skb_node *skbn; 55 56 bpf_spin_lock(&q_fifo_lock); 57 node = bpf_list_pop_front(&q_fifo); 58 bpf_spin_unlock(&q_fifo_lock); 59 if (!node) 60 return NULL; 61 62 skbn = container_of(node, struct skb_node, node); 63 skb = bpf_kptr_xchg(&skbn->skb, skb); 64 bpf_obj_drop(skbn); 65 if (!skb) 66 return NULL; 67 68 sch->qstats.backlog -= qdisc_pkt_len(skb); 69 bpf_qdisc_bstats_update(sch, skb); 70 sch->q.qlen--; 71 72 return skb; 73 } 74 75 SEC("struct_ops/bpf_fifo_init") 76 int BPF_PROG(bpf_fifo_init, struct Qdisc *sch, struct nlattr *opt, 77 struct netlink_ext_ack *extack) 78 { 79 sch->limit = 1000; 80 return 0; 81 } 82 83 SEC("struct_ops/bpf_fifo_reset") 84 void BPF_PROG(bpf_fifo_reset, struct Qdisc *sch) 85 { 86 struct bpf_list_node *node; 87 struct skb_node *skbn; 88 int i; 89 90 bpf_for(i, 0, sch->q.qlen) { 91 struct sk_buff *skb = NULL; 92 93 bpf_spin_lock(&q_fifo_lock); 94 node = bpf_list_pop_front(&q_fifo); 95 bpf_spin_unlock(&q_fifo_lock); 96 97 if (!node) 98 break; 99 100 skbn = container_of(node, struct skb_node, node); 101 skb = bpf_kptr_xchg(&skbn->skb, skb); 102 if (skb) 103 bpf_kfree_skb(skb); 104 bpf_obj_drop(skbn); 105 } 106 sch->q.qlen = 0; 107 } 108 109 SEC(".struct_ops") 110 struct Qdisc_ops fifo = { 111 .enqueue = (void *)bpf_fifo_enqueue, 112 .dequeue = (void *)bpf_fifo_dequeue, 113 .init = (void *)bpf_fifo_init, 114 .reset = (void *)bpf_fifo_reset, 115 .id = "bpf_fifo", 116 }; 117 118