linux/net/netfilter/ipvs/ip_vs_pe.c
<<
>>
Prefs
   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 */
  15static LIST_HEAD(ip_vs_pe);
  16
  17/* semaphore for IPVS PEs. */
  18static DEFINE_MUTEX(ip_vs_pe_mutex);
  19
  20/* Get pe in the pe list by name */
  21struct 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 */
  49struct 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 */
  66int 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}
  95EXPORT_SYMBOL_GPL(register_ip_vs_pe);
  96
  97/* Unregister a pe from the pe list */
  98int 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}
 112EXPORT_SYMBOL_GPL(unregister_ip_vs_pe);
 113