mirror of
				https://github.com/xdp-project/bpf-examples.git
				synced 2024-05-06 15:54:53 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			154 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef __CODEL_IMPL_H
 | 
						|
#define __CODEL_IMPL_H
 | 
						|
 | 
						|
#ifndef CODEL_TARGET
 | 
						|
#define CODEL_TARGET (10 * 1000 * 1000ULL) /* 10 ms in nanosec */
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef CODEL_EXCEED_INTERVAL
 | 
						|
#define CODEL_EXCEED_INTERVAL	(100 * 1000 * 1000ULL) /* 100 ms in ns*/
 | 
						|
#endif
 | 
						|
 | 
						|
/* Codel like dropping scheme, inspired by:
 | 
						|
 * - RFC:  https://queue.acm.org/detail.cfm?id=2209336
 | 
						|
 * - Code: https://queue.acm.org/appendices/codel.html
 | 
						|
 * - Kernel: include/net/codel_impl.h
 | 
						|
 */
 | 
						|
struct codel_state {
 | 
						|
	/* codel like dropping scheme */
 | 
						|
	__u64	first_above_time; /* Time when above target (0 if below)*/
 | 
						|
	__u64	drop_next;	  /* Time to drop next packet */
 | 
						|
	__u32	count;	/* Packets dropped since going into drop state */
 | 
						|
	__u32	dropping; /* Equal to 1 if in drop state */
 | 
						|
};
 | 
						|
 | 
						|
/* Table lookup for square-root shifted 16 bit */
 | 
						|
static __always_inline __u32 get_sqrt_sh16(__u64 cnt)
 | 
						|
{
 | 
						|
	switch (cnt) {
 | 
						|
	case 1:	return 65536; /* 65536 * sqrt(1) */
 | 
						|
	case 2:	return 92682; /* 65536 * sqrt(2) */
 | 
						|
	case 3:	return 113512; /* 65536 * sqrt(3) */
 | 
						|
	case 4:	return 131072; /* 65536 * sqrt(4) */
 | 
						|
	case 5:	return 146543; /* 65536 * sqrt(5) */
 | 
						|
	case 6:	return 160530; /* 65536 * sqrt(6) */
 | 
						|
	case 7:	return 173392;
 | 
						|
	case 8:	return 185364;
 | 
						|
	case 9:	return 196608;
 | 
						|
	case 10: return 207243;
 | 
						|
	case 11: return 217358;
 | 
						|
	case 12: return 227023;
 | 
						|
	case 13: return 236293;
 | 
						|
	case 14: return 245213;
 | 
						|
	case 15: return 253820;
 | 
						|
	case 16: return 262144; /* 100 ms / sqrt(16) = 25 ms */
 | 
						|
	case 17: return 270212;
 | 
						|
	case 18: return 278046;
 | 
						|
	case 19: return 285664;
 | 
						|
	case 20: return 293086;
 | 
						|
	case 21: return 300324;
 | 
						|
	case 22: return 307391;
 | 
						|
	case 23: return 314300;
 | 
						|
	case 24: return 321060;
 | 
						|
	case 25: return 327680; /* 100 ms / sqrt(25) = 20 ms */
 | 
						|
	case 26: return 334169;
 | 
						|
	case 27: return 340535;
 | 
						|
	case 28: return 346784;
 | 
						|
	case 29: return 352922;
 | 
						|
	case 30: return 358955;
 | 
						|
	case 31: return 364889;
 | 
						|
	case 32: return 370728;
 | 
						|
	case 33: return 376476;
 | 
						|
	case 34: return 382137;
 | 
						|
	case 35: return 387716;
 | 
						|
	case 36: return 393216; /* 100 / sqrt(36) = 16.66 ms */
 | 
						|
	default:
 | 
						|
		return 463410; /* 65536*sqrt(50) => 100/sqrt(50) = 14.14 ms */
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static __always_inline __u64 get_next_interval_sqrt(__u64 cnt)
 | 
						|
{
 | 
						|
	__u64 val = (__u64)CODEL_EXCEED_INTERVAL << 16 / get_sqrt_sh16(cnt);
 | 
						|
	return val;
 | 
						|
}
 | 
						|
 | 
						|
static __always_inline __u64
 | 
						|
codel_control_law(__u64 t, __u64 cnt)
 | 
						|
{
 | 
						|
	return t + get_next_interval_sqrt(cnt);
 | 
						|
}
 | 
						|
 | 
						|
static __always_inline
 | 
						|
bool codel_should_drop(struct codel_state *codel, __u64 t_queue_sz, __u64 now)
 | 
						|
{
 | 
						|
	__u64 interval = CODEL_EXCEED_INTERVAL;
 | 
						|
 | 
						|
	if (t_queue_sz < CODEL_TARGET) {
 | 
						|
		/* went below so we'll stay below for at least interval */
 | 
						|
		codel->first_above_time = 0;
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	if (codel->first_above_time == 0) {
 | 
						|
		/* just went above from below. If we stay above
 | 
						|
		 * for at least interval we'll say it's ok to drop
 | 
						|
		 */
 | 
						|
		codel->first_above_time = now + interval;
 | 
						|
		return false;
 | 
						|
	} else if (now >= codel->first_above_time) {
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
static __always_inline
 | 
						|
bool codel_drop(struct codel_state *codel, __u64 t_queue_sz, __u64 now)
 | 
						|
{
 | 
						|
	__u64 interval = CODEL_EXCEED_INTERVAL;
 | 
						|
 | 
						|
	/* If horizon have been exceed for a while, inc drop intensity*/
 | 
						|
	bool drop = codel_should_drop(codel, t_queue_sz, now);
 | 
						|
 | 
						|
	if (codel->dropping) { /* In dropping state */
 | 
						|
		if (!drop) {
 | 
						|
			/* time below target - leave dropping state */
 | 
						|
			codel->dropping = false;
 | 
						|
			return false;
 | 
						|
		} else if (now >= codel->drop_next) {
 | 
						|
			/* It's time for the next drop. Drop the current
 | 
						|
			 * packet. Schedule the next drop
 | 
						|
			 */
 | 
						|
			codel->count += 1;
 | 
						|
			// schedule the next drop.
 | 
						|
                        codel->drop_next =
 | 
						|
				codel_control_law(codel->drop_next, codel->count);
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
	} else if (drop &&
 | 
						|
		   ((now - codel->drop_next < interval) ||
 | 
						|
		    (now - codel->first_above_time >= interval))) {
 | 
						|
		/* If we get here, then we're not in dropping state.
 | 
						|
		 * Decide  whether it's time to enter dropping state.
 | 
						|
		 */
 | 
						|
		__u32 count = codel->count;
 | 
						|
 | 
						|
		codel->dropping = true;
 | 
						|
 | 
						|
		/* If we're in a drop cycle, drop rate that controlled queue
 | 
						|
                 * on the last cycle is a good starting point to control it now.
 | 
						|
		 */
 | 
						|
		if (now - codel->drop_next < interval)
 | 
						|
			count = count > 2 ? (count - 2) : 1;
 | 
						|
		else
 | 
						|
			count = 1;
 | 
						|
 | 
						|
		codel->count = count;
 | 
						|
		codel->drop_next = codel_control_law(now, count);
 | 
						|
		return true;
 | 
						|
	}
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* __CODEL_IMPL_H */
 |