Cost-Optimal Scrubbing with Linear Programming
A volumetric DDoS attack is a game of capacity versus cost. Buy too little protection and the pipe saturates. Buy enough for the worst case and you pay for idle hardware 360 days a year. In this article we model the problem as a linear program, solve it in Python, and then ask a second question: how much on-premise capacity should we buy in the first place?
1. The Problem
We defend a service over a 24-hour horizon, $t = 1,\dots,24$. The traffic volume $d_t$ (Gbps) is a legitimate baseline plus three attack waves of different sizes. Four “resources” can absorb it:
| Resource | Capacity | Unit cost ($/Gbps·h) | Remark |
|---|---|---|---|
| On-premise appliance | $K$ (design variable) | 0.1 | Fixed cost of 0.8 $/Gbps·h for installed capacity |
| Cloud scrubbing A (committed) | 50 Gbps | 2.0 | Contracted plan |
| Cloud scrubbing B (on-demand burst) | 500 Gbps | 6.0 | Expensive emergency capacity |
| Unmitigated traffic | unlimited | 50.0 | Penalty for outage or leakage |
Formulation
For a fixed on-premise capacity $K$, let $x_{i,t}$ be the traffic handled by resource $i$ in hour $t$ and $u_t$ the unmitigated traffic:
$$
\min_{x,u}\quad \sum_{t=1}^{T}\Big(c_0,x_{0,t}+c_A,x_{A,t}+c_B,x_{B,t}+p,u_t\Big)
$$
$$
\text{s.t.}\quad x_{0,t}+x_{A,t}+x_{B,t}+u_t=d_t \quad \forall t
$$
$$
0\le x_{0,t}\le K,\qquad 0\le x_{A,t}\le C_A,\qquad 0\le x_{B,t}\le C_B,\qquad u_t\ge 0
$$
The total daily cost then includes the amortized fixed cost of the appliance, with $f = 0.8$:
$$
J(K)=f,K,T+V^{*}(K)
$$
Here $V^{*}(K)$ is the optimal value of the linear program above. Installing one more Gbps of on-premise capacity is worthwhile only while the variable cost it saves exceeds its fixed cost:
$$
\frac{\partial V^{*}}{\partial K}=-\sum_{t\in\mathcal{B}(K)}\big(c_{\text{next},t}-c_0\big);\le;-,f,T
$$
where $\mathcal{B}(K)$ is the set of hours in which the on-premise appliance is saturated and $c_{\text{next},t}$ is the price of the next-cheapest resource used in that hour. Because $c_0 < c_A < c_B < p$, the optimal allocation always follows a merit order: fill the cheapest resource first, then spill over to the next one.
2. Full Source Code
1 | import time |
3. Code Walkthrough
Section 1: Problem setting
make_demand(scale) builds the traffic profile as a small sinusoidal baseline plus three Gaussian-shaped attack waves peaking at 09:00 (60 Gbps), 15:00 (130 Gbps) and 21:00 (45 Gbps). The scale argument multiplies only the attack part, which lets us later ask “what if attacks are 50% larger?” without touching the legitimate traffic. The unit costs encode the merit order $c_0 < c_A < c_B < p$.
Section 2: The linear program
solve_allocation stacks the $4T = 96$ decision variables as [on-prem (24), cloud A (24), cloud B (24), unmitigated (24)].
- The cost vector
crepeats each unit cost 24 times. - The equality matrix
Ahas one row per hour, with ones in the four columns belonging to that hour. This is the demand-balance constraint $x_{0,t}+x_{A,t}+x_{B,t}+u_t=d_t$. - The
boundslist encodes the capacity limits; only the unmitigated traffic is unbounded above. - The sparse matrix and the HiGHS solver make each solve take a few milliseconds, so no further acceleration is required. The entire study of 31 + 403 LP solves finishes in about one second.
The function returns the allocation matrix, the variable cost (the LP objective) and the fixed cost $f K T$ separately, so the trade-off can be plotted later.
Section 3: Finding the optimal appliance size
We sweep $K$ from 0 to 150 Gbps in steps of 5 and solve one LP per value. The $K$ that minimizes $J(K)=fKT+V^{*}(K)$ is selected, and two benchmark strategies are evaluated for comparison: cloud only ($K=0$) and sized for the peak ($K=\lceil \max_t d_t \rceil$).
Section 4: Sensitivity analysis
The same sweep is repeated for 13 attack scales, producing the matrix Z[scale, capacity]. Taking the minimum along each row gives the optimal capacity and the minimum cost for each attack intensity, which is the “ridge” of the cost surface.
Section 5: Visualization
All six graphs are drawn into one figure, so a single screenshot captures the whole analysis. Panels (3) and (6) are 3D.
4. Execution Results
============================================================ Baseline scenario (attack scale = 1.0) ============================================================ Peak traffic : 135.5 Gbps (hour 15) Optimal on-premise capacity : 45 Gbps Total cost (optimal) : $1,486.4 / day - on-premise fixed : $864.0 - variable : $622.4 Strategy Fixed Variable Total -------------------------------------------------------------------- Cloud only (no on-premise) 0.0 2,283.8 2,283.8 On-premise sized for peak (136) 2,611.2 80.3 2,691.5 Optimal mix (45 Gbps on-premise) 864.0 622.4 1,486.4 Traffic handled per resource over 24 h (Gbps-hours) On-premise : 603.0 Cloud A (committed) : 159.4 Cloud B (burst) : 40.5 Unmitigated : 0.0 Scale Opt. on-prem (Gbps) Min. cost ($/day) 0.40 15 580.4 0.50 20 705.2 0.60 30 856.5 0.70 30 1,014.5 0.80 35 1,169.1 0.90 40 1,326.4 1.00 45 1,486.4 1.10 45 1,642.6 1.20 50 1,800.6 1.30 60 1,966.3 1.40 65 2,134.5 1.50 75 2,315.4 1.60 80 2,493.0 Elapsed time: 1.22 s

5. Reading the Results
Numerical findings
For the baseline scenario, the traffic peaks at about 135.5 Gbps at 15:00. The optimal on-premise capacity is 45 Gbps, giving a daily cost of about $1,486. The two naive strategies cost considerably more:
| Strategy | Daily cost | Optimal mix saves |
|---|---|---|
| Cloud only | about $2,284 | about 35% |
| On-premise sized for the peak | about $2,692 | about 45% |
The optimal design is not “buy for the peak” and not “outsource everything”. It is a hybrid in which the appliance covers the everyday load and the clouds absorb the spikes.
Graph (1): Optimal hourly allocation
The stacked areas show who handles the traffic in each hour. The on-premise appliance (blue) is always filled first because it is the cheapest. When traffic exceeds 45 Gbps, the committed Cloud A (green) takes the overflow up to its 50 Gbps limit. Only during the 15:00 peak does the expensive burst Cloud B (orange) appear. The red unmitigated layer is absent, which confirms that the penalty of $50 makes dropping traffic never worthwhile here. The stacked top always coincides with the dashed total-traffic line, so the balance constraint is satisfied.
Graph (2): Cost versus on-premise capacity
The fixed cost grows linearly with $K$, while the variable cost falls as more traffic is kept in-house. The sum is a bowl-shaped curve with a clear minimum at 45 Gbps, which matches the marginal condition derived earlier. The curve rises sharply to the left, because every Gbps not covered on-premise spills to a 20 to 60 times more expensive cloud tier. It rises gently but steadily to the right, because capacity beyond the optimum is only used during a few peak hours and mostly sits idle.
Graph (3): 3D cost surface
The surface shows the total daily cost as a function of both the on-premise capacity and the attack scale. Along the attack-scale axis the cost rises monotonically, since stronger attacks always cost more. Along the capacity axis, each slice is a bowl whose bottom moves to the right as attacks get bigger. The red line traces these bottoms, the optimal ridge. A flat valley floor means a robust design: choosing a capacity somewhat off the optimum costs little, so the appliance size does not need to be predicted perfectly.
Graph (4): Strategy comparison
The stacked bars separate fixed from variable cost. “Cloud only” is almost entirely variable cost, so it is flexible but expensive. “Sized for peak” is dominated by fixed cost, so it is safe but wasteful. The optimal mix balances the two and gives the lowest total.
Graph (5): Contour map
This is the top view of graph (3). The red optimal-capacity line moves up and to the right: when attacks double in scale from 0.4 to 1.6, the optimal appliance grows from 15 Gbps to 80 Gbps, which is a much smaller growth than the peak traffic itself. This is the key insight: optimal on-premise capacity grows more slowly than peak attack size, because the rarest, largest spikes are better rented than owned.
Graph (6): 3D bars of mean load
The six-hour blocks show how the work is shared. On-premise load is steady in every block, Cloud A rises in the blocks containing the attack waves, and Cloud B is visible only in the 12–18h block. This gives a quick operational picture of when each contract is actually used, which is useful for contract negotiation, for example when deciding whether the committed cloud capacity should be larger or the burst contract smaller.
6. Conclusion
Dynamic allocation of DDoS mitigation resources is naturally a linear program with a merit-order structure: fill the cheapest resource first and spill to the next. Wrapping that LP in a one-dimensional search over appliance size yields a full capacity-planning tool. In our example the hybrid design saved 35 to 45% compared with the two naive strategies. Natural extensions include multi-day horizons, uncertain attack sizes via stochastic programming, and integer variables for discrete appliance models.











