|
1 | 1 | --- a/ecm_db/ecm_db.c |
2 | 2 | +++ 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 |
4 | 4 | }; |
5 | 5 |
|
6 | 6 | /* |
|
15 | 15 | + case FIB_EVENT_ENTRY_REPLACE: |
16 | 16 | + case FIB_EVENT_ENTRY_DEL: |
17 | 17 | + 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); |
23 | 24 | + } |
24 | 25 | +#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 | ++ */ |
26 | 32 | + DEBUG_TRACE("FIB IPv6 event %lu, flushing v6 connections\n", event); |
27 | 33 | + ecm_db_connection_defunct_ip_version(6); |
28 | 34 | + } |
29 | 35 | +#endif |
30 | 36 | + 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; |
31 | 47 | + } |
32 | 48 | + |
33 | 49 | + return NOTIFY_DONE; |
|
41 | 57 | * ecm_db_ipv4_route_table_update_event() |
42 | 58 | * This is a call back for "routing table update event for IPv4". |
43 | 59 | */ |
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 |
45 | 61 |
|
46 | 62 | if (ecm_db_ipv4_route_enable) { |
47 | 63 | ecm_front_end_ipv4_stop_temp(1); |
48 | 64 | - 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; |
54 | 71 | } |
55 | 72 |
|
56 | 73 | ecm_front_end_ipv4_stop_temp(1); |
57 | 74 | - ret = ip_rt_unregister_notifier(&ecm_db_iproute_table_update_nb); |
58 | 75 | - if (ret) { |
59 | 76 | - DEBUG_ERROR("Could not unregister for the IPV4 routing events error:%d\n", ret); |
60 | 77 | - } |
61 | | -+ unregister_fib_notifier(&init_net, &ecm_fib_notifier); |
| 78 | ++ /* Notifier managed in init/exit */ |
62 | 79 | ecm_front_end_ipv4_stop_temp(0); |
63 | 80 |
|
64 | 81 | 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 |
66 | 83 |
|
67 | 84 | if (ecm_db_ipv6_route_enable) { |
68 | 85 | ecm_front_end_ipv6_stop_temp(1); |
69 | 86 | - 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; |
75 | 93 | } |
76 | 94 |
|
77 | 95 | ecm_front_end_ipv6_stop_temp(1); |
78 | 96 | - ret = rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb); |
79 | 97 | - if (ret) { |
80 | 98 | - DEBUG_ERROR("Could not unregister for the IPV6 routing events error:%d\n", ret); |
81 | 99 | - } |
82 | | -+ /* rt6_unregister_notifier removed, managed by fib_notifier */ |
| 100 | ++ /* Notifier managed in init/exit (shared fib_notifier) */ |
83 | 101 | ecm_front_end_ipv6_stop_temp(0); |
84 | 102 |
|
85 | 103 | 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 | + /* |
87 | 106 | * register for route table modification events |
88 | 107 | */ |
89 | | - if (ecm_db_ipv4_route_enable) { |
| 108 | +- if (ecm_db_ipv4_route_enable) { |
90 | 109 | - 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 | + } |
97 | 117 |
|
98 | 118 | #ifdef ECM_IPV6_ENABLE |
99 | | - if (ecm_db_ipv6_route_enable) { |
| 119 | +- if (ecm_db_ipv6_route_enable) { |
100 | 120 | - 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) |
106 | 130 | * unregister for route table update events only if registered. |
107 | 131 | */ |
108 | 132 | if (ecm_db_ipv4_route_enable) { |
|
114 | 138 | } |
115 | 139 |
|
116 | 140 | #ifdef ECM_IPV6_ENABLE |
117 | | - if (ecm_db_ipv6_route_enable) { |
| 141 | +- if (ecm_db_ipv6_route_enable) { |
118 | 142 | - ret = rt6_unregister_notifier(&ecm_db_ip6route_table_update_nb); |
119 | 143 | - if (ret) { |
120 | 144 | - DEBUG_ERROR("Could not unregister for the IPV6 routing events error:%d\n", ret); |
121 | 145 | - } |
122 | | -+ /* managed by fib_notifier */ |
123 | | - } |
| 146 | +- } |
| 147 | ++ /* IPv6 notifier handled by shared fib_notifier */ |
124 | 148 | #endif |
125 | 149 | 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, |
126 | 215 | --- a/ecm_interface.c |
127 | 216 | +++ 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 |
129 | 218 | if (neigh->nud_state & NUD_FAILED) { |
130 | 219 | DEBUG_TRACE("NUD_FAILED for mac=%pM nud_state : 0x%x", neigh->ha, neigh->nud_state); |
131 | 220 | ecm_interface_node_connections_defunct_by_type(neigh->ha, ECM_DB_IP_VERSION_IGNORE, ECM_DB_CONNECTION_DEFUNCT_TYPE_ARP_DELETE); |
132 | 221 | + } else { |
133 | 222 | + /* |
134 | 223 | + * 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. |
152 | 225 | + */ |
| 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); |
153 | 245 | } |
154 | 246 |
|
155 | 247 | return NOTIFY_DONE; |
156 | | -@@ -10182,7 +10203,7 @@ int ecm_interface_init(void) |
| 248 | +@@ -10182,7 +10206,7 @@ int ecm_interface_init(void) |
157 | 249 | } |
158 | 250 | #endif |
159 | 251 | #ifdef ECM_DB_XREF_ENABLE |
160 | 252 | - 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); |
162 | 254 | #endif |
163 | 255 | #ifdef ECM_INTERFACE_OVS_BRIDGE_ENABLE |
164 | 256 | 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) |
166 | 258 |
|
167 | 259 | unregister_netdevice_notifier(&ecm_interface_netdev_notifier); |
168 | 260 | #ifdef ECM_DB_XREF_ENABLE |
169 | 261 | - 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); |
171 | 263 | #endif |
172 | 264 |
|
173 | 265 | #if defined(ECM_DB_XREF_ENABLE) && defined(ECM_BAND_STEERING_ENABLE) |
0 commit comments