Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/kernel/bpf/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  tcx.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2023 Isovalent */

#include <linux/bpf.h>
#include <linux/bpf_mprog.h>
#include <linux/netdevice.h>

#include <net/tcx.h>

int tcx_prog_attach(const union bpf_attr *attr, struct bpf_prog *prog)
{
 bool created, ingress = attr->attach_type == BPF_TCX_INGRESS;
 struct net *net = current->nsproxy->net_ns;
 struct bpf_mprog_entry *entry, *entry_new;
 struct bpf_prog *replace_prog = NULL;
 struct net_device *dev;
 int ret;

 rtnl_lock();
 dev = __dev_get_by_index(net, attr->target_ifindex);
 if (!dev) {
  ret = -ENODEV;
  goto out;
 }
 if (attr->attach_flags & BPF_F_REPLACE) {
  replace_prog = bpf_prog_get_type(attr->replace_bpf_fd,
       prog->type);
  if (IS_ERR(replace_prog)) {
   ret = PTR_ERR(replace_prog);
   replace_prog = NULL;
   goto out;
  }
 }
 entry = tcx_entry_fetch_or_create(dev, ingress, &created);
 if (!entry) {
  ret = -ENOMEM;
  goto out;
 }
 ret = bpf_mprog_attach(entry, &entry_new, prog, NULL, replace_prog,
          attr->attach_flags, attr->relative_fd,
          attr->expected_revision);
 if (!ret) {
  if (entry != entry_new) {
   tcx_entry_update(dev, entry_new, ingress);
   tcx_entry_sync();
   tcx_skeys_inc(ingress);
  }
  bpf_mprog_commit(entry);
 } else if (created) {
  tcx_entry_free(entry);
 }
out:
 if (replace_prog)
  bpf_prog_put(replace_prog);
 rtnl_unlock();
 return ret;
}

int tcx_prog_detach(const union bpf_attr *attr, struct bpf_prog *prog)
{
 bool ingress = attr->attach_type == BPF_TCX_INGRESS;
 struct net *net = current->nsproxy->net_ns;
 struct bpf_mprog_entry *entry, *entry_new;
 struct net_device *dev;
 int ret;

 rtnl_lock();
 dev = __dev_get_by_index(net, attr->target_ifindex);
 if (!dev) {
  ret = -ENODEV;
  goto out;
 }
 entry = tcx_entry_fetch(dev, ingress);
 if (!entry) {
  ret = -ENOENT;
  goto out;
 }
 ret = bpf_mprog_detach(entry, &entry_new, prog, NULL, attr->attach_flags,
          attr->relative_fd, attr->expected_revision);
 if (!ret) {
  if (!tcx_entry_is_active(entry_new))
   entry_new = NULL;
  tcx_entry_update(dev, entry_new, ingress);
  tcx_entry_sync();
  tcx_skeys_dec(ingress);
  bpf_mprog_commit(entry);
  if (!entry_new)
   tcx_entry_free(entry);
 }
out:
 rtnl_unlock();
 return ret;
}

void tcx_uninstall(struct net_device *dev, bool ingress)
{
 struct bpf_mprog_entry *entry, *entry_new = NULL;
 struct bpf_tuple tuple = {};
 struct bpf_mprog_fp *fp;
 struct bpf_mprog_cp *cp;
 bool active;

 entry = tcx_entry_fetch(dev, ingress);
 if (!entry)
  return;
 active = tcx_entry(entry)->miniq_active;
 if (active)
  bpf_mprog_clear_all(entry, &entry_new);
 tcx_entry_update(dev, entry_new, ingress);
 tcx_entry_sync();
 bpf_mprog_foreach_tuple(entry, fp, cp, tuple) {
  if (tuple.link)
   tcx_link(tuple.link)->dev = NULL;
  else
   bpf_prog_put(tuple.prog);
  tcx_skeys_dec(ingress);
 }
 if (!active)
  tcx_entry_free(entry);
}

int tcx_prog_query(const union bpf_attr *attr, union bpf_attr __user *uattr)
{
 bool ingress = attr->query.attach_type == BPF_TCX_INGRESS;
 struct net *net = current->nsproxy->net_ns;
 struct net_device *dev;
 int ret;

 rtnl_lock();
 dev = __dev_get_by_index(net, attr->query.target_ifindex);
 if (!dev) {
  ret = -ENODEV;
  goto out;
 }
 ret = bpf_mprog_query(attr, uattr, tcx_entry_fetch(dev, ingress));
out:
 rtnl_unlock();
 return ret;
}

static int tcx_link_prog_attach(struct bpf_link *link, u32 flags, u32 id_or_fd,
    u64 revision)
{
 struct tcx_link *tcx = tcx_link(link);
 bool created, ingress = link->attach_type == BPF_TCX_INGRESS;
 struct bpf_mprog_entry *entry, *entry_new;
 struct net_device *dev = tcx->dev;
 int ret;

 ASSERT_RTNL();
 entry = tcx_entry_fetch_or_create(dev, ingress, &created);
 if (!entry)
  return -ENOMEM;
 ret = bpf_mprog_attach(entry, &entry_new, link->prog, link, NULL, flags,
          id_or_fd, revision);
 if (!ret) {
  if (entry != entry_new) {
   tcx_entry_update(dev, entry_new, ingress);
   tcx_entry_sync();
   tcx_skeys_inc(ingress);
  }
  bpf_mprog_commit(entry);
 } else if (created) {
  tcx_entry_free(entry);
 }
 return ret;
}

static void tcx_link_release(struct bpf_link *link)
{
 struct tcx_link *tcx = tcx_link(link);
 bool ingress = link->attach_type == BPF_TCX_INGRESS;
 struct bpf_mprog_entry *entry, *entry_new;
 struct net_device *dev;
 int ret = 0;

 rtnl_lock();
 dev = tcx->dev;
 if (!dev)
  goto out;
 entry = tcx_entry_fetch(dev, ingress);
 if (!entry) {
  ret = -ENOENT;
  goto out;
 }
 ret = bpf_mprog_detach(entry, &entry_new, link->prog, link, 0, 0, 0);
 if (!ret) {
  if (!tcx_entry_is_active(entry_new))
   entry_new = NULL;
  tcx_entry_update(dev, entry_new, ingress);
  tcx_entry_sync();
  tcx_skeys_dec(ingress);
  bpf_mprog_commit(entry);
  if (!entry_new)
   tcx_entry_free(entry);
  tcx->dev = NULL;
 }
out:
 WARN_ON_ONCE(ret);
 rtnl_unlock();
}

static int tcx_link_update(struct bpf_link *link, struct bpf_prog *nprog,
      struct bpf_prog *oprog)
{
 struct tcx_link *tcx = tcx_link(link);
 bool ingress = link->attach_type == BPF_TCX_INGRESS;
 struct bpf_mprog_entry *entry, *entry_new;
 struct net_device *dev;
 int ret = 0;

 rtnl_lock();
 dev = tcx->dev;
 if (!dev) {
  ret = -ENOLINK;
  goto out;
 }
 if (oprog && link->prog != oprog) {
  ret = -EPERM;
  goto out;
 }
 oprog = link->prog;
 if (oprog == nprog) {
  bpf_prog_put(nprog);
  goto out;
 }
 entry = tcx_entry_fetch(dev, ingress);
 if (!entry) {
  ret = -ENOENT;
  goto out;
 }
 ret = bpf_mprog_attach(entry, &entry_new, nprog, link, oprog,
          BPF_F_REPLACE | BPF_F_ID,
          link->prog->aux->id, 0);
 if (!ret) {
  WARN_ON_ONCE(entry != entry_new);
  oprog = xchg(&link->prog, nprog);
  bpf_prog_put(oprog);
  bpf_mprog_commit(entry);
 }
out:
 rtnl_unlock();
 return ret;
}

static void tcx_link_dealloc(struct bpf_link *link)
{
 kfree(tcx_link(link));
}

static void tcx_link_fdinfo(const struct bpf_link *link, struct seq_file *seq)
{
 const struct tcx_link *tcx = tcx_link(link);
 u32 ifindex = 0;

 rtnl_lock();
 if (tcx->dev)
  ifindex = tcx->dev->ifindex;
 rtnl_unlock();

 seq_printf(seq, "ifindex:\t%u\n", ifindex);
 seq_printf(seq, "attach_type:\t%u (%s)\n",
     link->attach_type,
     link->attach_type == BPF_TCX_INGRESS ? "ingress" : "egress");
}

static int tcx_link_fill_info(const struct bpf_link *link,
         struct bpf_link_info *info)
{
 const struct tcx_link *tcx = tcx_link(link);
 u32 ifindex = 0;

 rtnl_lock();
 if (tcx->dev)
  ifindex = tcx->dev->ifindex;
 rtnl_unlock();

 info->tcx.ifindex = ifindex;
 info->tcx.attach_type = link->attach_type;
 return 0;
}

static int tcx_link_detach(struct bpf_link *link)
{
 tcx_link_release(link);
 return 0;
}

static const struct bpf_link_ops tcx_link_lops = {
 .release = tcx_link_release,
 .detach  = tcx_link_detach,
 .dealloc = tcx_link_dealloc,
 .update_prog = tcx_link_update,
 .show_fdinfo = tcx_link_fdinfo,
 .fill_link_info = tcx_link_fill_info,
};

static int tcx_link_init(struct tcx_link *tcx,
    struct bpf_link_primer *link_primer,
    const union bpf_attr *attr,
    struct net_device *dev,
    struct bpf_prog *prog)
{
 bpf_link_init(&tcx->link, BPF_LINK_TYPE_TCX, &tcx_link_lops, prog,
        attr->link_create.attach_type);
 tcx->dev = dev;
 return bpf_link_prime(&tcx->link, link_primer);
}

int tcx_link_attach(const union bpf_attr *attr, struct bpf_prog *prog)
{
 struct net *net = current->nsproxy->net_ns;
 struct bpf_link_primer link_primer;
 struct net_device *dev;
 struct tcx_link *tcx;
 int ret;

 rtnl_lock();
 dev = __dev_get_by_index(net, attr->link_create.target_ifindex);
 if (!dev) {
  ret = -ENODEV;
  goto out;
 }
 tcx = kzalloc(sizeof(*tcx), GFP_USER);
 if (!tcx) {
  ret = -ENOMEM;
  goto out;
 }
 ret = tcx_link_init(tcx, &link_primer, attr, dev, prog);
 if (ret) {
  kfree(tcx);
  goto out;
 }
 ret = tcx_link_prog_attach(&tcx->link, attr->link_create.flags,
       attr->link_create.tcx.relative_fd,
       attr->link_create.tcx.expected_revision);
 if (ret) {
  tcx->dev = NULL;
  bpf_link_cleanup(&link_primer);
  goto out;
 }
 ret = bpf_link_settle(&link_primer);
out:
 rtnl_unlock();
 return ret;
}

Messung V0.5
C=98 H=88 G=93

¤ Dauer der Verarbeitung: 0.36 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.