1 // SPDX-License-Identifier: GPL-2.0-only 2 #define pr_fmt(fmt) "IPVS: " fmt 3 4 #include <linux/module.h> 5 #include <linux/spinlock.h> 6 #include <linux/interrupt.h> 7 #include <asm/string.h> 8 #include <linux/kmod.h> 9 #include <linux/sysctl.h> 10 11 #include <net/ip_vs.h> 12 13 /* IPVS pe list */ 14 static LIST_HEAD(ip_vs_pe); 15 16 /* semaphore for IPVS PEs. */ 17 static DEFINE_MUTEX(ip_vs_pe_mutex); 18 19 /* Get pe in the pe list by name */ 20 struct ip_vs_pe *__ip_vs_pe_getbyname(const char *pe_name) 21 { 22 struct ip_vs_pe *pe; 23 24 IP_VS_DBG(10, "%s(): pe_name \"%s\"\n", __func__, 25 pe_name); 26 27 rcu_read_lock(); 28 list_for_each_entry_rcu(pe, &ip_vs_pe, n_list) { 29 /* Test and get the modules atomically */ 30 if (pe->module && 31 !try_module_get(pe->module)) { 32 /* This pe is just deleted */ 33 continue; 34 } 35 if (strcmp(pe_name, pe->name)==0) { 36 /* HIT */ 37 rcu_read_unlock(); 38 return pe; 39 } 40 module_put(pe->module); 41 } 42 rcu_read_unlock(); 43 44 return NULL; 45 } 46 47 /* Lookup pe and try to load it if it doesn't exist */ 48 struct ip_vs_pe *ip_vs_pe_getbyname(const char *name) 49 { 50 struct ip_vs_pe *pe; 51 52 /* Search for the pe by name */ 53 pe = __ip_vs_pe_getbyname(name); 54 55 /* If pe not found, load the module and search again */ 56 if (!pe) { 57 request_module("ip_vs_pe_%s", name); 58 pe = __ip_vs_pe_getbyname(name); 59 } 60 61 return pe; 62 } 63 64 /* Register a pe in the pe list */ 65 int register_ip_vs_pe(struct ip_vs_pe *pe) 66 { 67 struct ip_vs_pe *tmp; 68 69 /* increase the module use count */ 70 if (!ip_vs_use_count_inc()) 71 return -ENOENT; 72 73 mutex_lock(&ip_vs_pe_mutex); 74 /* Make sure that the pe with this name doesn't exist 75 * in the pe list. 76 */ 77 list_for_each_entry(tmp, &ip_vs_pe, n_list) { 78 if (strcmp(tmp->name, pe->name) == 0) { 79 mutex_unlock(&ip_vs_pe_mutex); 80 ip_vs_use_count_dec(); 81 pr_err("%s(): [%s] pe already existed " 82 "in the system\n", __func__, pe->name); 83 return -EINVAL; 84 } 85 } 86 /* Add it into the d-linked pe list */ 87 list_add_rcu(&pe->n_list, &ip_vs_pe); 88 mutex_unlock(&ip_vs_pe_mutex); 89 90 pr_info("[%s] pe registered.\n", pe->name); 91 92 return 0; 93 } 94 EXPORT_SYMBOL_GPL(register_ip_vs_pe); 95 96 /* Unregister a pe from the pe list */ 97 int unregister_ip_vs_pe(struct ip_vs_pe *pe) 98 { 99 mutex_lock(&ip_vs_pe_mutex); 100 /* Remove it from the d-linked pe list */ 101 list_del_rcu(&pe->n_list); 102 mutex_unlock(&ip_vs_pe_mutex); 103 104 /* decrease the module use count */ 105 ip_vs_use_count_dec(); 106 107 pr_info("[%s] pe unregistered.\n", pe->name); 108 109 return 0; 110 } 111 EXPORT_SYMBOL_GPL(unregister_ip_vs_pe); 112