Class: OsCtld::Devices::V2::BpfProgramCache

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
OsCtl::Lib::Utils::Log, Singleton
Defined in:
lib/osctld/devices/v2/bpf_program_cache.rb

Overview

Manage a list of BPF programs and their links

Program name is a hash of the listed devices, so identical programs are loaded just once and reused. Program links (i.e. attach on a cgroup) are tracked and when a program has no links left, it is destroyed.

Instance Method Summary collapse

Constructor Details

#initializeBpfProgramCache

Returns a new instance of BpfProgramCache.



22
23
24
25
26
27
28
29
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 22

def initialize
  @mutex = Mutex.new
  @programs = {}
  @links = {}
  @path_cache = {}

  load_programs
end

Instance Method Details

#assets(add) ⇒ Object

Parameters:



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 32

def assets(add)
  sync do
    @programs.each_value do |prog|
      add.file(
        prog.path,
        desc: "BPF program #{prog.name}",
        user: 0,
        group: 0,
        mode: 0o600
      )
    end

    @links.each_value do |cgroup_paths|
      cgroup_paths.each_value do |link|
        add.file(
          link.path,
          desc: "BPF program #{link.prog_name} attached on #{link.cgroup_path}",
          user: 0,
          group: 0,
          mode: 0o600
        )
      end
    end
  end
end

#get_prog_name(devices) ⇒ String

Parameters:

Returns:

  • (String)


138
139
140
141
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 138

def get_prog_name(devices)
  data = devices.map(&:to_s).join(';')
  Digest::SHA2.hexdigest(data)[0..10]
end

Detect existing links in BPF FS

Parameters:

  • pool_name (String)


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 60

def load_links(pool_name)
  sync do
    cnt = 0

    BpfFs.list_links(pool_name).each do |link_name|
      link = Devices::V2::BpfLink.from_name(pool_name, link_name)

      @links[link.prog_name] ||= {}
      @links[link.prog_name][link.cgroup_path] = link

      @path_cache[link.cgroup_path] = link

      cnt += 1
    end

    log(:info, "Loaded #{cnt} links")
  end
end

#load_programsObject (protected)



171
172
173
174
175
176
177
178
179
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 171

def load_programs
  sync do
    BpfFs.list_progs.each do |prog_name|
      @programs[prog_name] = Devices::V2::BpfProgram.new(prog_name, nil)
    end

    log(:info, "Loaded #{@programs.length} programs")
  end
end

#log_typeObject



165
166
167
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 165

def log_type
  'bpf-program-cache'
end

Remove program links to the specified cgroup

Parameters:

  • cgroup_path (String)


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 145

def prune_cgroup_links(cgroup_path)
  sync do
    link = @path_cache.delete(cgroup_path)
    return if link.nil?

    prog = @programs[link.prog_name]

    @links[link.prog_name].delete(cgroup_path)
    prog.detach(link)

    if @links[link.prog_name].empty?
      @links.delete(link.prog_name)
      @programs.delete(link.prog_name)
      prog.destroy
    end
  end

  nil
end

#set(pool_name, devices, cgroup_path, prog_name: nil) ⇒ String

Attach program allowing access to the specified devices to a cgroup

The program is attached only if it is not already attached. If ‘prog_name` is given and its link to the cgroup exists, program `prog_name` is replaced with the new program.

Parameters:

  • pool_name (String)
  • devices (Array<Devices::Device>)
  • cgroup_path (String)
  • prog_name (String, nil) (defaults to: nil)

    previous program name

Returns:

  • (String)

    program name



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 90

def set(pool_name, devices, cgroup_path, prog_name: nil)
  sync do
    new_prog_name = get_prog_name(devices)

    prog =
      if @programs.has_key?(new_prog_name)
        @programs[new_prog_name]
      else
        @programs[new_prog_name] = Devices::V2::BpfProgram.new(
          new_prog_name,
          devices
        )
      end

    prog.create unless prog.exist?

    link = Devices::V2::BpfLink.new(new_prog_name, pool_name, cgroup_path)

    if prog_name && prog_name != new_prog_name && @links[prog_name] && @links[prog_name][cgroup_path]
      old_link = @links[prog_name].delete(cgroup_path)
    end

    unless prog.attached?(link)
      if old_link
        prog.replace(old_link, link)
      else
        prog.attach(link)
      end

      @links[new_prog_name] ||= {}
      @links[new_prog_name][link.cgroup_path] = link

      @path_cache[link.cgroup_path] = link
    end

    if old_link && @links[prog_name].empty?
      old_prog = @programs.delete(prog_name)
      @links.delete(prog_name)

      old_prog.destroy
    end

    new_prog_name
  end
end

#sync(&block) ⇒ Object (protected)



181
182
183
184
185
186
187
# File 'lib/osctld/devices/v2/bpf_program_cache.rb', line 181

def sync(&block)
  if @mutex.owned?
    block.call
  else
    @mutex.synchronize(&block)
  end
end