162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * net/dccp/qpolicy.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Policy-based packet dequeueing interface for DCCP. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (c) 2008 Tomasz Grobelny <tomasz@grobelny.oswiecenia.net> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include "dccp.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Simple Dequeueing Policy: 1362306a36Sopenharmony_ci * If tx_qlen is different from 0, enqueue up to tx_qlen elements. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_cistatic void qpolicy_simple_push(struct sock *sk, struct sk_buff *skb) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci skb_queue_tail(&sk->sk_write_queue, skb); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic bool qpolicy_simple_full(struct sock *sk) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci return dccp_sk(sk)->dccps_tx_qlen && 2362306a36Sopenharmony_ci sk->sk_write_queue.qlen >= dccp_sk(sk)->dccps_tx_qlen; 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic struct sk_buff *qpolicy_simple_top(struct sock *sk) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci return skb_peek(&sk->sk_write_queue); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * Priority-based Dequeueing Policy: 3362306a36Sopenharmony_ci * If tx_qlen is different from 0 and the queue has reached its upper bound 3462306a36Sopenharmony_ci * of tx_qlen elements, replace older packets lowest-priority-first. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic struct sk_buff *qpolicy_prio_best_skb(struct sock *sk) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct sk_buff *skb, *best = NULL; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci skb_queue_walk(&sk->sk_write_queue, skb) 4162306a36Sopenharmony_ci if (best == NULL || skb->priority > best->priority) 4262306a36Sopenharmony_ci best = skb; 4362306a36Sopenharmony_ci return best; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic struct sk_buff *qpolicy_prio_worst_skb(struct sock *sk) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct sk_buff *skb, *worst = NULL; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci skb_queue_walk(&sk->sk_write_queue, skb) 5162306a36Sopenharmony_ci if (worst == NULL || skb->priority < worst->priority) 5262306a36Sopenharmony_ci worst = skb; 5362306a36Sopenharmony_ci return worst; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic bool qpolicy_prio_full(struct sock *sk) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci if (qpolicy_simple_full(sk)) 5962306a36Sopenharmony_ci dccp_qpolicy_drop(sk, qpolicy_prio_worst_skb(sk)); 6062306a36Sopenharmony_ci return false; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/** 6462306a36Sopenharmony_ci * struct dccp_qpolicy_operations - TX Packet Dequeueing Interface 6562306a36Sopenharmony_ci * @push: add a new @skb to the write queue 6662306a36Sopenharmony_ci * @full: indicates that no more packets will be admitted 6762306a36Sopenharmony_ci * @top: peeks at whatever the queueing policy defines as its `top' 6862306a36Sopenharmony_ci * @params: parameter passed to policy operation 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistruct dccp_qpolicy_operations { 7162306a36Sopenharmony_ci void (*push) (struct sock *sk, struct sk_buff *skb); 7262306a36Sopenharmony_ci bool (*full) (struct sock *sk); 7362306a36Sopenharmony_ci struct sk_buff* (*top) (struct sock *sk); 7462306a36Sopenharmony_ci __be32 params; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic struct dccp_qpolicy_operations qpol_table[DCCPQ_POLICY_MAX] = { 7862306a36Sopenharmony_ci [DCCPQ_POLICY_SIMPLE] = { 7962306a36Sopenharmony_ci .push = qpolicy_simple_push, 8062306a36Sopenharmony_ci .full = qpolicy_simple_full, 8162306a36Sopenharmony_ci .top = qpolicy_simple_top, 8262306a36Sopenharmony_ci .params = 0, 8362306a36Sopenharmony_ci }, 8462306a36Sopenharmony_ci [DCCPQ_POLICY_PRIO] = { 8562306a36Sopenharmony_ci .push = qpolicy_simple_push, 8662306a36Sopenharmony_ci .full = qpolicy_prio_full, 8762306a36Sopenharmony_ci .top = qpolicy_prio_best_skb, 8862306a36Sopenharmony_ci .params = DCCP_SCM_PRIORITY, 8962306a36Sopenharmony_ci }, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * Externally visible interface 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_civoid dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci qpol_table[dccp_sk(sk)->dccps_qpolicy].push(sk, skb); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cibool dccp_qpolicy_full(struct sock *sk) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci return qpol_table[dccp_sk(sk)->dccps_qpolicy].full(sk); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_civoid dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci if (skb != NULL) { 10862306a36Sopenharmony_ci skb_unlink(skb, &sk->sk_write_queue); 10962306a36Sopenharmony_ci kfree_skb(skb); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistruct sk_buff *dccp_qpolicy_top(struct sock *sk) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci return qpol_table[dccp_sk(sk)->dccps_qpolicy].top(sk); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct sk_buff *dccp_qpolicy_pop(struct sock *sk) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct sk_buff *skb = dccp_qpolicy_top(sk); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (skb != NULL) { 12362306a36Sopenharmony_ci /* Clear any skb fields that we used internally */ 12462306a36Sopenharmony_ci skb->priority = 0; 12562306a36Sopenharmony_ci skb_unlink(skb, &sk->sk_write_queue); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci return skb; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cibool dccp_qpolicy_param_ok(struct sock *sk, __be32 param) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci /* check if exactly one bit is set */ 13362306a36Sopenharmony_ci if (!param || (param & (param - 1))) 13462306a36Sopenharmony_ci return false; 13562306a36Sopenharmony_ci return (qpol_table[dccp_sk(sk)->dccps_qpolicy].params & param) == param; 13662306a36Sopenharmony_ci} 137