authorgravatar for mattnite@protonmail.comMatt Knight <mattnite@protonmail.com> 2020-09-06 17:45:54-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-07 15:42:41-04:00
loga496f94be92581cdf97a1bd60c4dea0369e26395
treef85d11fa974474ffee67298342c64d6f9ccee3bf
parentdb7a2382977a12e3ad95e3f2249c538d9c31cd87

added map create, update, delete, and prog load


1 files changed, 179 insertions(+), 2 deletions(-)

lib/std/os/linux/bpf.zig+179-2
......@@ -3,9 +3,13 @@
33// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
44// The MIT license requires this copyright notice to be included in all copies
55// and substantial portions of the software.
6usingnamespace std.os;
6usingnamespace std.os.linux;
77const std = @import("../../std.zig");
8const errno = getErrno;
9const unexpectedErrno = std.os.unexpectedErrno;
810const expectEqual = std.testing.expectEqual;
11const expectError = std.testing.expectError;
12const expect = std.testing.expect;
913
1014// instruction classes
1115pub const LD = 0x00;
......@@ -1323,7 +1327,7 @@ pub const ProgAttachAttr = extern struct {
13231327};
13241328
13251329/// struct used by Cmd.prog_test_run command
1326pub const TestAttr = extern struct {
1330pub const TestRunAttr = extern struct {
13271331 prog_fd: fd_t,
13281332 retval: u32,
13291333
......@@ -1484,3 +1488,176 @@ pub const Attr = extern union {
14841488 enable_stats: EnableStatsAttr,
14851489 iter_create: IterCreateAttr,
14861490};
1491
1492pub const Log = struct {
1493 level: u32,
1494 buf: []u8,
1495};
1496
1497pub fn map_create(map_type: MapType, key_size: u32, value_size: u32, max_entries: u32) !fd_t {
1498 var attr = Attr{
1499 .map_create = std.mem.zeroes(MapCreateAttr),
1500 };
1501
1502 attr.map_create.map_type = @enumToInt(map_type);
1503 attr.map_create.key_size = key_size;
1504 attr.map_create.value_size = value_size;
1505 attr.map_create.max_entries = max_entries;
1506
1507 const rc = bpf(.map_create, &attr, @sizeOf(MapCreateAttr));
1508 return switch (errno(rc)) {
1509 0 => @intCast(fd_t, rc),
1510 EINVAL => error.MapTypeOrAttrInvalid,
1511 ENOMEM => error.SystemResources,
1512 EPERM => error.AccessDenied,
1513 else => |err| unexpectedErrno(rc),
1514 };
1515}
1516
1517test "map_create" {
1518 const map = try map_create(.hash, 4, 4, 32);
1519 defer std.os.close(map);
1520}
1521
1522pub fn map_lookup_elem(fd: fd_t, key: []const u8, value: []u8) !void {
1523 var attr = Attr{
1524 .map_elem = std.mem.zeroes(MapElemAttr),
1525 };
1526
1527 attr.map_elem.map_fd = fd;
1528 attr.map_elem.key = @ptrToInt(key.ptr);
1529 attr.map_elem.result.value = @ptrToInt(value.ptr);
1530
1531 const rc = bpf(.map_lookup_elem, &attr, @sizeOf(MapElemAttr));
1532 switch (errno(rc)) {
1533 0 => return,
1534 EBADF => return error.BadFd,
1535 EFAULT => unreachable,
1536 EINVAL => return error.FieldInAttrNeedsZeroing,
1537 ENOENT => return error.NotFound,
1538 EPERM => return error.AccessDenied,
1539 else => |err| return unexpectedErrno(rc),
1540 }
1541}
1542
1543pub fn map_update_elem(fd: fd_t, key: []const u8, value: []const u8, flags: u64) !void {
1544 var attr = Attr{
1545 .map_elem = std.mem.zeroes(MapElemAttr),
1546 };
1547
1548 attr.map_elem.map_fd = fd;
1549 attr.map_elem.key = @ptrToInt(key.ptr);
1550 attr.map_elem.result = .{ .value = @ptrToInt(value.ptr) };
1551 attr.map_elem.flags = flags;
1552
1553 const rc = bpf(.map_update_elem, &attr, @sizeOf(MapElemAttr));
1554 switch (errno(rc)) {
1555 0 => return,
1556 E2BIG => return error.ReachedMaxEntries,
1557 EBADF => return error.BadFd,
1558 EFAULT => unreachable,
1559 EINVAL => return error.FieldInAttrNeedsZeroing,
1560 ENOMEM => return error.SystemResources,
1561 EPERM => return error.AccessDenied,
1562 else => |err| return unexpectedErrno(err),
1563 }
1564}
1565
1566pub fn map_delete_elem(fd: fd_t, key: []const u8) !void {
1567 var attr = Attr{
1568 .map_elem = std.mem.zeroes(MapElemAttr),
1569 };
1570
1571 attr.map_elem.map_fd = fd;
1572 attr.map_elem.key = @ptrToInt(key.ptr);
1573
1574 const rc = bpf(.map_delete_elem, &attr, @sizeOf(MapElemAttr));
1575 switch (errno(rc)) {
1576 0 => return,
1577 EBADF => return error.BadFd,
1578 EFAULT => unreachable,
1579 EINVAL => return error.FieldInAttrNeedsZeroing,
1580 ENOENT => return error.NotFound,
1581 EPERM => return error.AccessDenied,
1582 else => |err| return unexpectedErrno(err),
1583 }
1584}
1585
1586test "map lookup, update, and delete" {
1587 const key_size = 4;
1588 const value_size = 4;
1589 const map = try map_create(.hash, key_size, value_size, 1);
1590 defer std.os.close(map);
1591
1592 const key = std.mem.zeroes([key_size]u8);
1593 var value = std.mem.zeroes([value_size]u8);
1594
1595 // fails looking up value that doesn't exist
1596 expectError(error.NotFound, map_lookup_elem(map, &key, &value));
1597
1598 // succeed at updating and looking up element
1599 try map_update_elem(map, &key, &value, 0);
1600 try map_lookup_elem(map, &key, &value);
1601
1602 // fails inserting more than max entries
1603 const second_key = [key_size]u8{ 0, 0, 0, 1 };
1604 expectError(error.ReachedMaxEntries, map_update_elem(map, &second_key, &value, 0));
1605
1606 // succeed at deleting an existing elem
1607 try map_delete_elem(map, &key);
1608 expectError(error.NotFound, map_lookup_elem(map, &key, &value));
1609
1610 // fail at deleting a non-existing elem
1611 expectError(error.NotFound, map_delete_elem(map, &key));
1612}
1613
1614pub fn prog_load(
1615 prog_type: ProgType,
1616 insns: []const Insn,
1617 log: ?*Log,
1618 license: []const u8,
1619 kern_version: u32,
1620) !fd_t {
1621 var attr = Attr{
1622 .prog_load = std.mem.zeroes(ProgLoadAttr),
1623 };
1624
1625 attr.prog_load.prog_type = @enumToInt(prog_type);
1626 attr.prog_load.insns = @ptrToInt(insns.ptr);
1627 attr.prog_load.insn_cnt = @intCast(u32, insns.len);
1628 attr.prog_load.license = @ptrToInt(license.ptr);
1629 attr.prog_load.kern_version = kern_version;
1630
1631 if (log) |l| {
1632 attr.prog_load.log_buf = @ptrToInt(l.buf.ptr);
1633 attr.prog_load.log_size = @intCast(u32, l.buf.len);
1634 attr.prog_load.log_level = l.level;
1635 }
1636
1637 const rc = bpf(.prog_load, &attr, @sizeOf(ProgLoadAttr));
1638 return switch (errno(rc)) {
1639 0 => @intCast(fd_t, rc),
1640 EACCES => error.UnsafeProgram,
1641 EFAULT => unreachable,
1642 EINVAL => error.InvalidProgram,
1643 EPERM => error.AccessDenied,
1644 else => |err| unexpectedErrno(err),
1645 };
1646}
1647
1648test "prog_load" {
1649 // this should fail because it does not set r0 before exiting
1650 const bad_prog = [_]Insn{
1651 Insn.exit(),
1652 };
1653
1654 const good_prog = [_]Insn{
1655 Insn.mov(.r0, 0),
1656 Insn.exit(),
1657 };
1658
1659 const prog = try prog_load(.socket_filter, &good_prog, null, "MIT", 0);
1660 defer std.os.close(prog);
1661
1662 expectError(error.UnsafeProgram, prog_load(.socket_filter, &bad_prog, null, "MIT", 0));
1663}