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