Skip to content

Commit ba3770c

Browse files
author
Simon
committed
fix ecm
1 parent 36c471f commit ba3770c

4 files changed

Lines changed: 153 additions & 418 deletions

File tree

Lines changed: 152 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
--- a/ecm_db/ecm_db.c
22
+++ b/ecm_db/ecm_db.c
3-
@@ -253,6 +253,40 @@ static struct file_operations ecm_db_def
3+
@@ -253,6 +253,56 @@ static struct file_operations ecm_db_def
44
};
55

66
/*
@@ -15,19 +15,35 @@
1515
+ case FIB_EVENT_ENTRY_REPLACE:
1616
+ case FIB_EVENT_ENTRY_DEL:
1717
+ case FIB_EVENT_ENTRY_ADD:
18-
+ case FIB_EVENT_RULE_ADD:
19-
+ case FIB_EVENT_RULE_DEL:
20-
+ if (info->family == AF_INET) {
21-
+ DEBUG_TRACE("FIB IPv4 event %lu, flushing v4 connections\n", event);
22-
+ ecm_db_connection_defunct_ip_version(4);
18+
+ if ((info->family == AF_INET) && ecm_db_ipv4_route_enable) {
19+
+ struct fib_entry_notifier_info *fen_info = (struct fib_entry_notifier_info *)ptr;
20+
+ ip_addr_t subnet_addr;
21+
+ ECM_NIN4_ADDR_TO_IP_ADDR(subnet_addr, fen_info->dst);
22+
+ DEBUG_TRACE("FIB IPv4 event %lu, flushing subnet %pI4/%d\n", event, &fen_info->dst, fen_info->dst_len);
23+
+ ecm_db_connection_defunct_by_ip_subnet(4, subnet_addr, fen_info->dst_len);
2324
+ }
2425
+#ifdef ECM_IPV6_ENABLE
25-
+ else if (info->family == AF_INET6) {
26+
+ else if ((info->family == AF_INET6) && ecm_db_ipv6_route_enable) {
27+
+ /*
28+
+ * For IPv6, we currently flush all connections as accessing
29+
+ * the specific subnet details from fib6_entry_notifier_info
30+
+ * across kernel versions is complex.
31+
+ */
2632
+ DEBUG_TRACE("FIB IPv6 event %lu, flushing v6 connections\n", event);
2733
+ ecm_db_connection_defunct_ip_version(6);
2834
+ }
2935
+#endif
3036
+ break;
37+
+
38+
+ case FIB_EVENT_RULE_ADD:
39+
+ case FIB_EVENT_RULE_DEL:
40+
+ /* Rules affect global routing policy, so we flush all */
41+
+ if ((info->family == AF_INET) && ecm_db_ipv4_route_enable) {
42+
+ ecm_db_connection_defunct_ip_version(4);
43+
+ } else if ((info->family == AF_INET6) && ecm_db_ipv6_route_enable) {
44+
+ ecm_db_connection_defunct_ip_version(6);
45+
+ }
46+
+ break;
3147
+ }
3248
+
3349
+ return NOTIFY_DONE;
@@ -41,68 +57,76 @@
4157
* ecm_db_ipv4_route_table_update_event()
4258
* This is a call back for "routing table update event for IPv4".
4359
*/
44-
@@ -565,7 +599,7 @@ static int ecm_db_ipv4_route_handler(con
60+
@@ -565,19 +615,13 @@ static int ecm_db_ipv4_route_handler(con
4561

4662
if (ecm_db_ipv4_route_enable) {
4763
ecm_front_end_ipv4_stop_temp(1);
4864
- ret = ip_rt_register_notifier(&ecm_db_iproute_table_update_nb);
49-
+ ret = register_fib_notifier(&init_net, &ecm_fib_notifier, NULL, NULL);
50-
if (ret) {
51-
DEBUG_ERROR("Could not register for the IPV4 routing events error:%d\n", ret);
52-
}
53-
@@ -574,10 +608,7 @@ static int ecm_db_ipv4_route_handler(con
65+
- if (ret) {
66+
- DEBUG_ERROR("Could not register for the IPV4 routing events error:%d\n", ret);
67+
- }
68+
+ /* Notifier already registered in init */
69+
ecm_front_end_ipv4_stop_temp(0);
70+
return ret;
5471
}
5572

5673
ecm_front_end_ipv4_stop_temp(1);
5774
- ret = ip_rt_unregister_notifier(&ecm_db_iproute_table_update_nb);
5875
- if (ret) {
5976
- DEBUG_ERROR("Could not unregister for the IPV4 routing events error:%d\n", ret);
6077
- }
61-
+ unregister_fib_notifier(&init_net, &ecm_fib_notifier);
78+
+ /* Notifier managed in init/exit */
6279
ecm_front_end_ipv4_stop_temp(0);
6380

6481
return ret;
65-
@@ -626,7 +657,7 @@ static int ecm_db_ipv6_route_handler(con
82+
@@ -626,19 +670,13 @@ static int ecm_db_ipv6_route_handler(con
6683

6784
if (ecm_db_ipv6_route_enable) {
6885
ecm_front_end_ipv6_stop_temp(1);
6986
- ret = rt6_register_notifier(&ecm_db_ip6route_table_update_nb);
70-
+ ret = 0; /* rt6_register_notifier removed, using shared fib_notifier */
71-
if (ret) {
72-
DEBUG_ERROR("Could not register for the IPV6 routing events error:%d\n", ret);
73-
}
74-
@@ -635,10 +666,7 @@ static int ecm_db_ipv6_route_handler(con
87+
- if (ret) {
88+
- DEBUG_ERROR("Could not register for the IPV6 routing events error:%d\n", ret);
89+
- }
90+
+ /* Notifier already registered in init (shared fib_notifier) */
91+
ecm_front_end_ipv6_stop_temp(0);
92+
return ret;
7593
}
7694

7795
ecm_front_end_ipv6_stop_temp(1);
7896
- ret = rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb);
7997
- if (ret) {
8098
- DEBUG_ERROR("Could not unregister for the IPV6 routing events error:%d\n", ret);
8199
- }
82-
+ /* rt6_unregister_notifier removed, managed by fib_notifier */
100+
+ /* Notifier managed in init/exit (shared fib_notifier) */
83101
ecm_front_end_ipv6_stop_temp(0);
84102

85103
return ret;
86-
@@ -752,7 +780,8 @@ int ecm_db_init(struct dentry *dentry)
104+
@@ -751,20 +789,13 @@ int ecm_db_init(struct dentry *dentry)
105+
/*
87106
* register for route table modification events
88107
*/
89-
if (ecm_db_ipv4_route_enable) {
108+
- if (ecm_db_ipv4_route_enable) {
90109
- ret = ip_rt_register_notifier(&ecm_db_iproute_table_update_nb);
91-
+ /* Register FIB notifier (covers v4 and v6) */
92-
+ ret = register_fib_notifier(&init_net, &ecm_fib_notifier, NULL, NULL);
93-
if (ret) {
94-
DEBUG_ERROR("Could not register for the IPV4 routing events error:%d\n", ret);
95-
}
96-
@@ -760,7 +789,7 @@ int ecm_db_init(struct dentry *dentry)
110+
- if (ret) {
111+
- DEBUG_ERROR("Could not register for the IPV4 routing events error:%d\n", ret);
112+
- }
113+
+ ret = register_fib_notifier(&init_net, &ecm_fib_notifier, NULL, NULL);
114+
+ if (ret) {
115+
+ DEBUG_ERROR("Could not register for the routing events error:%d\n", ret);
116+
}
97117

98118
#ifdef ECM_IPV6_ENABLE
99-
if (ecm_db_ipv6_route_enable) {
119+
- if (ecm_db_ipv6_route_enable) {
100120
- ret = rt6_register_notifier(&ecm_db_ip6route_table_update_nb);
101-
+ /* rt6_register_notifier is gone, managed by fib_notifier */
102-
if (ret) {
103-
DEBUG_ERROR("Could not register for the IPV6 routing events error:%d\n", ret);
104-
}
105-
@@ -800,18 +829,12 @@ void ecm_db_exit(void)
121+
- if (ret) {
122+
- DEBUG_ERROR("Could not register for the IPV6 routing events error:%d\n", ret);
123+
- }
124+
- }
125+
+ /* IPv6 notifier handled by shared fib_notifier */
126+
#endif
127+
return ret;
128+
129+
@@ -800,19 +831,11 @@ void ecm_db_exit(void)
106130
* unregister for route table update events only if registered.
107131
*/
108132
if (ecm_db_ipv4_route_enable) {
@@ -114,60 +138,128 @@
114138
}
115139

116140
#ifdef ECM_IPV6_ENABLE
117-
if (ecm_db_ipv6_route_enable) {
141+
- if (ecm_db_ipv6_route_enable) {
118142
- ret = rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb);
119143
- if (ret) {
120144
- DEBUG_ERROR("Could not unregister for the IPV6 routing events error:%d\n", ret);
121145
- }
122-
+ /* managed by fib_notifier */
123-
}
146+
- }
147+
+ /* IPv6 notifier handled by shared fib_notifier */
124148
#endif
125149
ecm_db_connection_defunct_all();
150+
151+
--- a/ecm_db/ecm_db_connection.c
152+
+++ b/ecm_db/ecm_db_connection.c
153+
@@ -5360,3 +5360,50 @@ void ecm_db_connection_exit(void)
154+
unregister_sysctl_table(ecm_db_connection_ctl_table_header);
155+
}
156+
}
157+
+
158+
+/*
159+
+ * ecm_db_connection_defunct_by_ip_subnet()
160+
+ *Defunct connections that match the destination subnet.
161+
+ */
162+
+void ecm_db_connection_defunct_by_ip_subnet(int ip_version, ip_addr_t addr, int mask_len)
163+
+{
164+
+struct ecm_db_connection_instance *ci;
165+
+uint32_t mask[4] = {0, 0, 0, 0};
166+
+
167+
+DEBUG_INFO("Defuncting IPv%d connections for subnet mask len %d\n", ip_version, mask_len);
168+
+
169+
+/* Generate mask */
170+
+if (ip_version == 4) {
171+
+if (mask_len > 32) mask_len = 32;
172+
+if (mask_len > 0) mask[0] = (0xffffffff << (32 - mask_len));
173+
+}
174+
+// IPv6 mask generation omitted
175+
+
176+
+/*
177+
+ * Iterate all connections
178+
+ */
179+
+ci = ecm_db_connections_get_and_ref_first();
180+
+while (ci) {
181+
+struct ecm_db_connection_instance *cin;
182+
+bool match = false;
183+
+
184+
+if (ci->ip_version == ip_version) {
185+
+ip_addr_t dst_addr;
186+
+ecm_db_connection_address_get(ci, ECM_DB_OBJ_DIR_TO, dst_addr);
187+
+// Apply mask to a[0] (assuming v4)
188+
+if (ip_version == 4 && (dst_addr[0] & mask[0]) == (addr[0] & mask[0])) {
189+
+match = true;
190+
+}
191+
+}
192+
+
193+
+if (match) {
194+
+DEBUG_TRACE("%px: defunct (subnet match)\n", ci);
195+
+ecm_db_connection_make_defunct(ci);
196+
+}
197+
+
198+
+cin = ecm_db_connection_get_and_ref_next(ci);
199+
+ecm_db_connection_deref(ci);
200+
+ci = cin;
201+
+}
202+
+}
203+
+EXPORT_SYMBOL(ecm_db_connection_defunct_by_ip_subnet);
204+
--- a/ecm_db/ecm_db_connection.h
205+
+++ b/ecm_db/ecm_db_connection.h
206+
@@ -400,6 +400,8 @@ void ecm_db_connection_defunct_all(void)
207+
void ecm_db_connection_defunct_by_port(int port, ecm_db_obj_dir_t dir);
208+
void ecm_db_connection_defunct_by_protocol(int protocol);
209+
void ecm_db_connection_defunct_ip_version(int ip_version);
210+
+void ecm_db_connection_defunct_by_ip_subnet(int ip_version, ip_addr_t addr, int mask_len);
211+
+void ecm_db_connection_defunct_by_ip_subnet(int ip_version, ip_addr_t addr, int mask_len);
212+
213+
struct ecm_db_connection_instance *ecm_db_connection_serial_find_and_ref(uint32_t serial);
214+
struct ecm_db_connection_instance *ecm_db_connection_find_and_ref(ip_addr_t host1_addr,
126215
--- a/ecm_interface.c
127216
+++ b/ecm_interface.c
128-
@@ -10111,6 +10111,27 @@ static int ecm_interface_netevent_callba
217+
@@ -10111,6 +10111,30 @@ static int ecm_interface_netevent_callba
129218
if (neigh->nud_state & NUD_FAILED) {
130219
DEBUG_TRACE("NUD_FAILED for mac=%pM nud_state : 0x%x", neigh->ha, neigh->nud_state);
131220
ecm_interface_node_connections_defunct_by_type(neigh->ha, ECM_DB_IP_VERSION_IGNORE, ECM_DB_CONNECTION_DEFUNCT_TYPE_ARP_DELETE);
132221
+ } else {
133222
+ /*
134223
+ * Neighbour update event (Kernel 6.12 adaptation)
135-
+ * Check if MAC address changed for this neighbor.
136-
+ * Since standard netevent doesn't give us the old MAC,
137-
+ * and we can't easily look up connections by IP without the old MAC,
138-
+ * we take a safe approach:
139-
+ * If the neighbor is reachable/stale (valid), verify that
140-
+ * connections using this IP actually match this MAC.
141-
+ *
142-
+ * Ideally, we would use ecm_db_host_connections_defunct_by_ip(),
143-
+ * but since that API is missing, we must rely on NUD_FAILED handling
144-
+ * or implement a full IP-based lookup scan.
145-
+ *
146-
+ * For now, this patch assumes that a significant MAC change
147-
+ * will likely cause a NUD_FAILED transition or a new ARP resolution
148-
+ * that might trigger other events.
149-
+ *
150-
+ * TODO: Implement true IP-based flush if strict MAC migration is needed.
151-
+ * Note: neigh_mac_update_register_notify is removed in 6.12+
224+
+ * Reliable MAC roaming: Flush connections for this IP to force re-resolution.
152225
+ */
226+
+ ip_addr_t addr;
227+
+ bool is_v4 = (neigh->tbl->family == AF_INET);
228+
+
229+
+ if (is_v4) {
230+
+ uint32_t val;
231+
+ memcpy(&val, neigh->primary_key, sizeof(val));
232+
+ ECM_NIN4_ADDR_TO_IP_ADDR(addr, val);
233+
+ } else {
234+
+ struct in6_addr v6;
235+
+ memcpy(&v6, neigh->primary_key, sizeof(v6));
236+
+ ECM_NIN6_ADDR_TO_IP_ADDR(addr, v6);
237+
+ }
238+
+
239+
+ DEBUG_TRACE("Neigh update for %pI4/%pI6, flushing connections\n",
240+
+ is_v4 ? neigh->primary_key : NULL,
241+
+ is_v4 ? NULL : neigh->primary_key);
242+
+
243+
+ ecm_db_host_connections_defunct_by_dir(addr, ECM_DB_OBJ_DIR_FROM);
244+
+ ecm_db_host_connections_defunct_by_dir(addr, ECM_DB_OBJ_DIR_TO);
153245
}
154246

155247
return NOTIFY_DONE;
156-
@@ -10182,7 +10203,7 @@ int ecm_interface_init(void)
248+
@@ -10182,7 +10206,7 @@ int ecm_interface_init(void)
157249
}
158250
#endif
159251
#ifdef ECM_DB_XREF_ENABLE
160252
- neigh_mac_update_register_notify(&ecm_interface_neigh_mac_update_nb);
161-
+ /* neigh_mac_update_register_notify(&ecm_interface_neigh_mac_update_nb); - Removed in Kernel 6.12 */
253+
+// neigh_mac_update_register_notify(&ecm_interface_neigh_mac_update_nb);
162254
#endif
163255
#ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE
164256
ovsmgr_notifier_register(&ecm_interface_ovs_notifier);
165-
@@ -10213,7 +10234,7 @@ void ecm_interface_exit(void)
257+
@@ -10213,7 +10237,7 @@ void ecm_interface_exit(void)
166258

167259
unregister_netdevice_notifier(&ecm_interface_netdev_notifier);
168260
#ifdef ECM_DB_XREF_ENABLE
169261
- neigh_mac_update_unregister_notify(&ecm_interface_neigh_mac_update_nb);
170-
+ /* neigh_mac_update_unregister_notify(&ecm_interface_neigh_mac_update_nb); - Removed in Kernel 6.12 */
262+
+// neigh_mac_update_unregister_notify(&ecm_interface_neigh_mac_update_nb);
171263
#endif
172264

173265
#if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE)

0 commit comments

Comments
 (0)