aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShahed Shaikh <shahed.shaikh@qlogic.com>2013-08-02 23:15:55 -0400
committerDavid S. Miller <davem@davemloft.net>2013-08-03 15:03:03 -0400
commite0d138d99507362e2e77b4ff61b546a8b63d60b0 (patch)
tree1b452427974097bc571075284fe2427699d9334a
parent4a99ab56cea66f9f67b9d07ace5cd40a336c8e6f (diff)
qlcnic: Fix ingress MAC learning
o Delete MAC address from the adapter's filter table if the source MAC address of ingress packet matches. Signed-off-by: Shahed Shaikh <shahed.shaikh@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c99
1 files changed, 66 insertions, 33 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 82a03d3de894..6946d354f44f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -161,36 +161,68 @@ static inline int qlcnic_82xx_is_lb_pkt(u64 sts_data)
161 return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0; 161 return (qlcnic_get_sts_status(sts_data) == STATUS_CKSUM_LOOP) ? 1 : 0;
162} 162}
163 163
164static void qlcnic_delete_rx_list_mac(struct qlcnic_adapter *adapter,
165 struct qlcnic_filter *fil,
166 void *addr, u16 vlan_id)
167{
168 int ret;
169 u8 op;
170
171 op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
172 ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
173 if (ret)
174 return;
175
176 op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
177 ret = qlcnic_sre_macaddr_change(adapter, addr, vlan_id, op);
178 if (!ret) {
179 hlist_del(&fil->fnode);
180 adapter->rx_fhash.fnum--;
181 }
182}
183
184static struct qlcnic_filter *qlcnic_find_mac_filter(struct hlist_head *head,
185 void *addr, u16 vlan_id)
186{
187 struct qlcnic_filter *tmp_fil = NULL;
188 struct hlist_node *n;
189
190 hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
191 if (!memcmp(tmp_fil->faddr, addr, ETH_ALEN) &&
192 tmp_fil->vlan_id == vlan_id)
193 return tmp_fil;
194 }
195
196 return NULL;
197}
198
164void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, 199void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
165 int loopback_pkt, u16 vlan_id) 200 int loopback_pkt, u16 vlan_id)
166{ 201{
167 struct ethhdr *phdr = (struct ethhdr *)(skb->data); 202 struct ethhdr *phdr = (struct ethhdr *)(skb->data);
168 struct qlcnic_filter *fil, *tmp_fil; 203 struct qlcnic_filter *fil, *tmp_fil;
169 struct hlist_node *n;
170 struct hlist_head *head; 204 struct hlist_head *head;
171 unsigned long time; 205 unsigned long time;
172 u64 src_addr = 0; 206 u64 src_addr = 0;
173 u8 hindex, found = 0, op; 207 u8 hindex, op;
174 int ret; 208 int ret;
175 209
176 memcpy(&src_addr, phdr->h_source, ETH_ALEN); 210 memcpy(&src_addr, phdr->h_source, ETH_ALEN);
211 hindex = qlcnic_mac_hash(src_addr) &
212 (adapter->fhash.fbucket_size - 1);
177 213
178 if (loopback_pkt) { 214 if (loopback_pkt) {
179 if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax) 215 if (adapter->rx_fhash.fnum >= adapter->rx_fhash.fmax)
180 return; 216 return;
181 217
182 hindex = qlcnic_mac_hash(src_addr) &
183 (adapter->fhash.fbucket_size - 1);
184 head = &(adapter->rx_fhash.fhead[hindex]); 218 head = &(adapter->rx_fhash.fhead[hindex]);
185 219
186 hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { 220 tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
187 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) && 221 if (tmp_fil) {
188 tmp_fil->vlan_id == vlan_id) { 222 time = tmp_fil->ftime;
189 time = tmp_fil->ftime; 223 if (time_after(jiffies, QLCNIC_READD_AGE * HZ + time))
190 if (jiffies > (QLCNIC_READD_AGE * HZ + time)) 224 tmp_fil->ftime = jiffies;
191 tmp_fil->ftime = jiffies; 225 return;
192 return;
193 }
194 } 226 }
195 227
196 fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC); 228 fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
@@ -205,36 +237,37 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb,
205 adapter->rx_fhash.fnum++; 237 adapter->rx_fhash.fnum++;
206 spin_unlock(&adapter->rx_mac_learn_lock); 238 spin_unlock(&adapter->rx_mac_learn_lock);
207 } else { 239 } else {
208 hindex = qlcnic_mac_hash(src_addr) & 240 head = &adapter->fhash.fhead[hindex];
209 (adapter->fhash.fbucket_size - 1);
210 head = &(adapter->rx_fhash.fhead[hindex]);
211 spin_lock(&adapter->rx_mac_learn_lock);
212 hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
213 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
214 tmp_fil->vlan_id == vlan_id) {
215 found = 1;
216 break;
217 }
218 }
219 241
220 if (!found) { 242 spin_lock(&adapter->mac_learn_lock);
221 spin_unlock(&adapter->rx_mac_learn_lock);
222 return;
223 }
224 243
225 op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD; 244 tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
226 ret = qlcnic_sre_macaddr_change(adapter, (u8 *)&src_addr, 245 if (tmp_fil) {
227 vlan_id, op);
228 if (!ret) {
229 op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL; 246 op = vlan_id ? QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL;
230 ret = qlcnic_sre_macaddr_change(adapter, 247 ret = qlcnic_sre_macaddr_change(adapter,
231 (u8 *)&src_addr, 248 (u8 *)&src_addr,
232 vlan_id, op); 249 vlan_id, op);
233 if (!ret) { 250 if (!ret) {
234 hlist_del(&(tmp_fil->fnode)); 251 hlist_del(&tmp_fil->fnode);
235 adapter->rx_fhash.fnum--; 252 adapter->fhash.fnum--;
236 } 253 }
254
255 spin_unlock(&adapter->mac_learn_lock);
256
257 return;
237 } 258 }
259
260 spin_unlock(&adapter->mac_learn_lock);
261
262 head = &adapter->rx_fhash.fhead[hindex];
263
264 spin_lock(&adapter->rx_mac_learn_lock);
265
266 tmp_fil = qlcnic_find_mac_filter(head, &src_addr, vlan_id);
267 if (tmp_fil)
268 qlcnic_delete_rx_list_mac(adapter, tmp_fil, &src_addr,
269 vlan_id);
270
238 spin_unlock(&adapter->rx_mac_learn_lock); 271 spin_unlock(&adapter->rx_mac_learn_lock);
239 } 272 }
240} 273}