@@ -25,17 +25,29 @@ def generate_rules(
2525 input_rules = []
2626 output_rules = []
2727 for interface in interfaces :
28- for port in config .ports :
28+ if config .ports :
29+ for port in config .ports :
30+ if config .egress :
31+ for protocol in set (config .protocols ):
32+ output_rules .append (
33+ f"iptables -I OUTPUT 1 -p { protocol } --dport { port } -m state --state NEW,RELATED,ESTABLISHED -j DROP"
34+ )
35+ if config .ingress :
36+ for protocol in set (config .protocols ):
37+ input_rules .append (
38+ f"iptables -I INPUT 1 -i { interface } -p { protocol } --dport { port } -m state --state NEW,RELATED,ESTABLISHED -j DROP"
39+ )
40+ else :
41+ # empty ports means block all traffic on all ports
2942 if config .egress :
3043 for protocol in set (config .protocols ):
3144 output_rules .append (
32- f"iptables -I OUTPUT 1 -p { protocol } --dport { port } - m state --state NEW,RELATED,ESTABLISHED -j DROP"
45+ f"iptables -I OUTPUT 1 -p { protocol } -m state --state NEW,RELATED,ESTABLISHED -j DROP"
3346 )
34-
3547 if config .ingress :
3648 for protocol in set (config .protocols ):
3749 input_rules .append (
38- f"iptables -I INPUT 1 -i { interface } -p { protocol } --dport { port } - m state --state NEW,RELATED,ESTABLISHED -j DROP"
50+ f"iptables -I INPUT 1 -i { interface } -p { protocol } -m state --state NEW,RELATED,ESTABLISHED -j DROP"
3951 )
4052 return input_rules , output_rules
4153
@@ -115,3 +127,64 @@ def generate_namespaced_rules(
115127 namespaced_output_rules .extend (ns_output_rules )
116128
117129 return namespaced_input_rules , namespaced_output_rules
130+
131+
132+ def apply_tc_vmi_chaos (
133+ kubecli : KrknKubernetes ,
134+ chaos_pod_name : str ,
135+ namespace : str ,
136+ pid : str ,
137+ iface : str ,
138+ parallel : bool ,
139+ vmi_name : str ,
140+ ):
141+ """Block all traffic on the VMI's tap interface using tc.
142+
143+ Targets tap0 (the VM-facing end of the KubeVirt bridge) rather than the
144+ bridge slave (ovn-udn1-nic). Blocking the bridge slave also cuts OVN's
145+ BFD heartbeats and causes a node-wide network reconvergence; tap0 only
146+ connects to QEMU so blocking it isolates only this VMI.
147+
148+ tc operates at the device layer below iptables and works without br_netfilter:
149+ - root netem loss 100% -> drops traffic sent toward the VM
150+ - ingress + matchall -> drops traffic sent by the VM
151+ Only one pid is needed because all processes in the container share a netns.
152+ """
153+ ns = f"nsenter --target { pid } --net --"
154+ log_info (f"applying tc block on { iface } (egress netem + ingress drop)" , parallel , vmi_name )
155+ kubecli .exec_cmd_in_pod (
156+ [f"{ ns } tc qdisc add dev { iface } root netem loss 100%" ],
157+ chaos_pod_name ,
158+ namespace ,
159+ )
160+ kubecli .exec_cmd_in_pod (
161+ [f"{ ns } tc qdisc add dev { iface } ingress" ],
162+ chaos_pod_name ,
163+ namespace ,
164+ )
165+ kubecli .exec_cmd_in_pod (
166+ [f"{ ns } tc filter add dev { iface } parent ffff: protocol all matchall action drop" ],
167+ chaos_pod_name ,
168+ namespace ,
169+ )
170+
171+
172+ def clean_tc_vmi_chaos (
173+ kubecli : KrknKubernetes ,
174+ chaos_pod_name : str ,
175+ namespace : str ,
176+ pid : str ,
177+ iface : str ,
178+ ):
179+ """Remove tc qdiscs applied by apply_tc_vmi_chaos."""
180+ ns = f"nsenter --target { pid } --net --"
181+ for cmd in [
182+ f"{ ns } tc qdisc del dev { iface } root" ,
183+ f"{ ns } tc qdisc del dev { iface } ingress" ,
184+ ]:
185+ try :
186+ kubecli .exec_cmd_in_pod ([cmd ], chaos_pod_name , namespace )
187+ except Exception :
188+ pass
189+
190+
0 commit comments