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