cregit-Linux how code gets into the kernel

Release 4.16 drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c

/*
 *  This file is part of the Chelsio T4 Ethernet driver for Linux.
 *  Copyright (C) 2003-2014 Chelsio Communications.  All rights reserved.
 *
 *  Written by Deepak (deepak.s@chelsio.com)
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
 *  release for licensing terms and conditions.
 */

#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/jhash.h>
#include <linux/if_vlan.h>
#include <net/addrconf.h>
#include "cxgb4.h"
#include "clip_tbl.h"


static inline unsigned int ipv4_clip_hash(struct clip_tbl *c, const u32 *key) { unsigned int clipt_size_half = c->clipt_size / 2; return jhash_1word(*key, 0) % clipt_size_half; }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt39100.00%1100.00%
Total39100.00%1100.00%


static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key) { unsigned int clipt_size_half = d->clipt_size / 2; u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; return clipt_size_half + (jhash_1word(xor, 0) % clipt_size_half); }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt65100.00%1100.00%
Total65100.00%1100.00%


static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr, u8 v6) { return v6 ? ipv6_clip_hash(ctbl, addr) : ipv4_clip_hash(ctbl, addr); }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt37100.00%2100.00%
Total37100.00%2100.00%


static int clip6_get_mbox(const struct net_device *dev, const struct in6_addr *lip) { struct adapter *adap = netdev2adap(dev); struct fw_clip_cmd c; memset(&c, 0, sizeof(c)); c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | FW_CMD_REQUEST_F | FW_CMD_WRITE_F); c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c)); *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr); *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8); return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt142100.00%1100.00%
Total142100.00%1100.00%


static int clip6_release_mbox(const struct net_device *dev, const struct in6_addr *lip) { struct adapter *adap = netdev2adap(dev); struct fw_clip_cmd c; memset(&c, 0, sizeof(c)); c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) | FW_CMD_REQUEST_F | FW_CMD_READ_F); c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c)); *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr); *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8); return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false); }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt142100.00%1100.00%
Total142100.00%1100.00%


int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6) { struct adapter *adap = netdev2adap(dev); struct clip_tbl *ctbl = adap->clipt; struct clip_entry *ce, *cte; u32 *addr = (u32 *)lip; int hash; int ret = -1; if (!ctbl) return 0; hash = clip_addr_hash(ctbl, addr, v6); read_lock_bh(&ctbl->lock); list_for_each_entry(cte, &ctbl->hash_list[hash], list) { if (cte->addr6.sin6_family == AF_INET6 && v6) ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr, sizeof(struct in6_addr)); else if (cte->addr.sin_family == AF_INET && !v6) ret = memcmp(lip, (char *)(&cte->addr.sin_addr), sizeof(struct in_addr)); if (!ret) { ce = cte; read_unlock_bh(&ctbl->lock); refcount_inc(&ce->refcnt); return 0; } } read_unlock_bh(&ctbl->lock); write_lock_bh(&ctbl->lock); if (!list_empty(&ctbl->ce_free_head)) { ce = list_first_entry(&ctbl->ce_free_head, struct clip_entry, list); list_del(&ce->list); INIT_LIST_HEAD(&ce->list); spin_lock_init(&ce->lock); refcount_set(&ce->refcnt, 0); atomic_dec(&ctbl->nfree); list_add_tail(&ce->list, &ctbl->hash_list[hash]); if (v6) { ce->addr6.sin6_family = AF_INET6; memcpy(ce->addr6.sin6_addr.s6_addr, lip, sizeof(struct in6_addr)); ret = clip6_get_mbox(dev, (const struct in6_addr *)lip); if (ret) { write_unlock_bh(&ctbl->lock); dev_err(adap->pdev_dev, "CLIP FW cmd failed with error %d, " "Connections using %pI6c wont be " "offloaded", ret, ce->addr6.sin6_addr.s6_addr); return ret; } } else { ce->addr.sin_family = AF_INET; memcpy((char *)(&ce->addr.sin_addr), lip, sizeof(struct in_addr)); } } else { write_unlock_bh(&ctbl->lock); dev_info(adap->pdev_dev, "CLIP table overflow, " "Connections using %pI6c wont be offloaded", (void *)lip); return -ENOMEM; } write_unlock_bh(&ctbl->lock); refcount_set(&ce->refcnt, 1); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt42287.92%240.00%
Hariprasad Shenai438.96%240.00%
Elena Reshetova153.12%120.00%
Total480100.00%5100.00%

EXPORT_SYMBOL(cxgb4_clip_get);
void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6) { struct adapter *adap = netdev2adap(dev); struct clip_tbl *ctbl = adap->clipt; struct clip_entry *ce, *cte; u32 *addr = (u32 *)lip; int hash; int ret = -1; if (!ctbl) return; hash = clip_addr_hash(ctbl, addr, v6); read_lock_bh(&ctbl->lock); list_for_each_entry(cte, &ctbl->hash_list[hash], list) { if (cte->addr6.sin6_family == AF_INET6 && v6) ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr, sizeof(struct in6_addr)); else if (cte->addr.sin_family == AF_INET && !v6) ret = memcmp(lip, (char *)(&cte->addr.sin_addr), sizeof(struct in_addr)); if (!ret) { ce = cte; read_unlock_bh(&ctbl->lock); goto found; } } read_unlock_bh(&ctbl->lock); return; found: write_lock_bh(&ctbl->lock); spin_lock_bh(&ce->lock); if (refcount_dec_and_test(&ce->refcnt)) { list_del(&ce->list); INIT_LIST_HEAD(&ce->list); list_add_tail(&ce->list, &ctbl->ce_free_head); atomic_inc(&ctbl->nfree); if (v6) clip6_release_mbox(dev, (const struct in6_addr *)lip); } spin_unlock_bh(&ce->lock); write_unlock_bh(&ctbl->lock); }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt29797.70%250.00%
Hariprasad Shenai61.97%125.00%
Elena Reshetova10.33%125.00%
Total304100.00%4100.00%

EXPORT_SYMBOL(cxgb4_clip_release); /* Retrieves IPv6 addresses from a root device (bond, vlan) associated with * a physical device. * The physical device reference is needed to send the actul CLIP command. */
static int cxgb4_update_dev_clip(struct net_device *root_dev, struct net_device *dev) { struct inet6_dev *idev = NULL; struct inet6_ifaddr *ifa; int ret = 0; idev = __in6_dev_get(root_dev); if (!idev) return ret; read_lock_bh(&idev->lock); list_for_each_entry(ifa, &idev->addr_list, if_list) { ret = cxgb4_clip_get(dev, (const u32 *)ifa->addr.s6_addr, 1); if (ret < 0) break; } read_unlock_bh(&idev->lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt104100.00%1100.00%
Total104100.00%1100.00%


int cxgb4_update_root_dev_clip(struct net_device *dev) { struct net_device *root_dev = NULL; int i, ret = 0; /* First populate the real net device's IPv6 addresses */ ret = cxgb4_update_dev_clip(dev, dev); if (ret) return ret; /* Parse all bond and vlan devices layered on top of the physical dev */ root_dev = netdev_master_upper_dev_get_rcu(dev); if (root_dev) { ret = cxgb4_update_dev_clip(root_dev, dev); if (ret) return ret; } for (i = 0; i < VLAN_N_VID; i++) { root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i); if (!root_dev) continue; ret = cxgb4_update_dev_clip(root_dev, dev); if (ret) break; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt123100.00%1100.00%
Total123100.00%1100.00%

EXPORT_SYMBOL(cxgb4_update_root_dev_clip);
int clip_tbl_show(struct seq_file *seq, void *v) { struct adapter *adapter = seq->private; struct clip_tbl *ctbl = adapter->clipt; struct clip_entry *ce; char ip[60]; int i; read_lock_bh(&ctbl->lock); seq_puts(seq, "IP Address Users\n"); for (i = 0 ; i < ctbl->clipt_size; ++i) { list_for_each_entry(ce, &ctbl->hash_list[i], list) { ip[0] = '\0'; sprintf(ip, "%pISc", &ce->addr); seq_printf(seq, "%-25s %u\n", ip, refcount_read(&ce->refcnt)); } } seq_printf(seq, "Free clip entries : %d\n", atomic_read(&ctbl->nfree)); read_unlock_bh(&ctbl->lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt14999.33%266.67%
Elena Reshetova10.67%133.33%
Total150100.00%3100.00%


struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start, unsigned int clipt_end) { struct clip_entry *cl_list; struct clip_tbl *ctbl; unsigned int clipt_size; int i; if (clipt_start >= clipt_end) return NULL; clipt_size = clipt_end - clipt_start + 1; if (clipt_size < CLIPT_MIN_HASH_BUCKETS) return NULL; ctbl = kvzalloc(sizeof(*ctbl) + clipt_size*sizeof(struct list_head), GFP_KERNEL); if (!ctbl) return NULL; ctbl->clipt_start = clipt_start; ctbl->clipt_size = clipt_size; INIT_LIST_HEAD(&ctbl->ce_free_head); atomic_set(&ctbl->nfree, clipt_size); rwlock_init(&ctbl->lock); for (i = 0; i < ctbl->clipt_size; ++i) INIT_LIST_HEAD(&ctbl->hash_list[i]); cl_list = kvzalloc(clipt_size*sizeof(struct clip_entry), GFP_KERNEL); if (!cl_list) { kvfree(ctbl); return NULL; } ctbl->cl_list = (void *)cl_list; for (i = 0; i < clipt_size; i++) { INIT_LIST_HEAD(&cl_list[i].list); list_add_tail(&cl_list[i].list, &ctbl->ce_free_head); } return ctbl; }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt21591.10%133.33%
Insu Yun145.93%133.33%
Michal Hocko72.97%133.33%
Total236100.00%3100.00%


void t4_cleanup_clip_tbl(struct adapter *adap) { struct clip_tbl *ctbl = adap->clipt; if (ctbl) { if (ctbl->cl_list) kvfree(ctbl->cl_list); kvfree(ctbl); } }

Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt4195.35%150.00%
Michal Hocko24.65%150.00%
Total43100.00%2100.00%

EXPORT_SYMBOL(t4_cleanup_clip_tbl);

Overall Contributors

PersonTokensPropCommitsCommitProp
Anish Bhatt181995.34%228.57%
Hariprasad Shenai492.57%228.57%
Elena Reshetova170.89%114.29%
Insu Yun140.73%114.29%
Michal Hocko90.47%114.29%
Total1908100.00%7100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.