Class: OsCtld::Devices::V2::BpfProgram

Inherits:
Object
  • Object
show all
Includes:
OsCtl::Lib::Utils::Log
Defined in:
lib/osctld/devices/v2/bpf_program.rb

Overview

Create/destroy & attach/detach BPF programs for devices access control

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, devices) ⇒ BpfProgram

Create a new program

The device list can be nil. In that case, the program cannot be loaded into the kernel, because we don’t know its contents, but we can still create/destroy links or unload the program from the kernel.

Parameters:



23
24
25
26
27
# File 'lib/osctld/devices/v2/bpf_program.rb', line 23

def initialize(name, devices)
  @name = name
  @devices = devices
  @path = BpfFs.prog_pin_path(name)
end

Instance Attribute Details

#nameString (readonly)

Returns:

  • (String)


9
10
11
# File 'lib/osctld/devices/v2/bpf_program.rb', line 9

def name
  @name
end

#pathString (readonly)

Pin file path

Returns:

  • (String)


13
14
15
# File 'lib/osctld/devices/v2/bpf_program.rb', line 13

def path
  @path
end

Instance Method Details

#attach(link) ⇒ Object

Attach program to cgroup

Parameters:



71
72
73
74
75
76
77
78
# File 'lib/osctld/devices/v2/bpf_program.rb', line 71

def attach(link)
  run_devcgprog(
    'attach',
    path,
    link.cgroup_path,
    link.path
  )
end

#attached?(link) ⇒ Boolean

Check if program is attached to a cgroup

Note that even if this method returns ‘true`, the link may still be broken if the underlying cgroup has been destroyed and recreated. We have no way of verifying it using BPF FS.

Parameters:

Returns:

  • (Boolean)


65
66
67
# File 'lib/osctld/devices/v2/bpf_program.rb', line 65

def attached?(link)
  BpfFs.link_pinned?(link.pool_name, link.name)
end

#createObject

Load the program to the kernel



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/osctld/devices/v2/bpf_program.rb', line 35

def create
  if @devices.nil?
    raise 'unable to create incomplete program'
  end

  args = %W[
    -name #{@name}
    new
    #{path}
    allow
  ]

  @devices.each do |dev|
    args << "#{dev.type_s}:#{dev.major}:#{dev.minor}:#{dev.mode}"
  end

  run_devcgprog(*args)
end

#destroyObject



54
55
56
# File 'lib/osctld/devices/v2/bpf_program.rb', line 54

def destroy
  File.unlink(path)
end

#detach(link) ⇒ Object

Detach program from cgroup

Parameters:



99
100
101
# File 'lib/osctld/devices/v2/bpf_program.rb', line 99

def detach(link)
  File.unlink(link.path)
end

#exist?Boolean

Check if the program is loaded within the kernel

Returns:

  • (Boolean)


30
31
32
# File 'lib/osctld/devices/v2/bpf_program.rb', line 30

def exist?
  BpfFs.prog_pinned?(@name)
end

#replace(link, new_link) ⇒ Object

Atomically replace attached program with another program

Parameters:



83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/osctld/devices/v2/bpf_program.rb', line 83

def replace(link, new_link)
  if link.pool_name != new_link.pool_name
    raise ArgumentError,
          "link on pool #{link.pool_name} while new_link on pool #{new_link.pool_name}"
  end

  run_devcgprog(
    'replace',
    link.path,
    BpfFs.prog_pin_path(new_link.prog_name),
    new_link.path
  )
end

#run_devcgprog(*args) ⇒ Object (protected)



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/osctld/devices/v2/bpf_program.rb', line 105

def run_devcgprog(*args)
  cmd = ['devcgprog'] + args

  log(:info, cmd.join(' '))
  pid = Process.spawn(*cmd)
  Process.wait(pid)

  if $?.exitstatus != 0
    raise "#{cmd.join(' ')} failed with exit status #{$?.exitstatus}"
  end

  nil
end