add DestroyTable and SetDestroyElements (#322)
These methods are like their DeleteTable and SetDeleteElements counterparts, but they do not return an error if the specified table/set does not exist.
This commit is contained in:
parent
3efc75f481
commit
1148f1a84f
|
@ -128,6 +128,47 @@ func ifname(n string) []byte {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTableCreateDestroy(t *testing.T) {
|
||||||
|
c, newNS := nftest.OpenSystemConn(t, *enableSysTests)
|
||||||
|
defer nftest.CleanupSystemConn(t, newNS)
|
||||||
|
defer c.FlushRuleset()
|
||||||
|
|
||||||
|
filter := &nftables.Table{
|
||||||
|
Family: nftables.TableFamilyIPv4,
|
||||||
|
Name: "filter",
|
||||||
|
}
|
||||||
|
c.DestroyTable(filter)
|
||||||
|
c.AddTable(filter)
|
||||||
|
err := c.Flush()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("on Flush: %q", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
lookupMyTable := func() bool {
|
||||||
|
ts, err := c.ListTables()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("on ListTables: %q", err.Error())
|
||||||
|
}
|
||||||
|
return slices.ContainsFunc(ts, func(t *nftables.Table) bool {
|
||||||
|
return t.Name == filter.Name && t.Family == filter.Family
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !lookupMyTable() {
|
||||||
|
t.Fatal("AddTable doesn't create my table!")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.DestroyTable(filter)
|
||||||
|
if err = c.Flush(); err != nil {
|
||||||
|
t.Fatalf("on Flush: %q", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if lookupMyTable() {
|
||||||
|
t.Fatal("DestroyTable doesn't delete my table!")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.DestroyTable(filter) // just for test that 'destroy' ignore error 'not found'
|
||||||
|
}
|
||||||
|
|
||||||
func TestRuleOperations(t *testing.T) {
|
func TestRuleOperations(t *testing.T) {
|
||||||
// Create a new network namespace to test these operations,
|
// Create a new network namespace to test these operations,
|
||||||
// and tear down the namespace at test completion.
|
// and tear down the namespace at test completion.
|
||||||
|
@ -3777,7 +3818,7 @@ func TestDeleteElementNamedSet(t *testing.T) {
|
||||||
Name: "test",
|
Name: "test",
|
||||||
KeyType: nftables.TypeInetService,
|
KeyType: nftables.TypeInetService,
|
||||||
}
|
}
|
||||||
if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}}); err != nil {
|
if err := c.AddSet(portSet, []nftables.SetElement{{Key: []byte{0, 22}}, {Key: []byte{0, 23}}, {Key: []byte{0, 24}}}); err != nil {
|
||||||
t.Errorf("c.AddSet(portSet) failed: %v", err)
|
t.Errorf("c.AddSet(portSet) failed: %v", err)
|
||||||
}
|
}
|
||||||
if err := c.Flush(); err != nil {
|
if err := c.Flush(); err != nil {
|
||||||
|
@ -3794,6 +3835,22 @@ func TestDeleteElementNamedSet(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("c.GetSets() failed: %v", err)
|
t.Errorf("c.GetSets() failed: %v", err)
|
||||||
}
|
}
|
||||||
|
if len(elems) != 2 {
|
||||||
|
t.Fatalf("len(elems) = %d, want 2", len(elems))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 24}}})
|
||||||
|
c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 24}}})
|
||||||
|
c.SetDestroyElements(portSet, []nftables.SetElement{{Key: []byte{0, 99}}})
|
||||||
|
|
||||||
|
if err := c.Flush(); err != nil {
|
||||||
|
t.Errorf("Third c.Flush() failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
elems, err = c.GetSetElements(portSet)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("c.GetSets() failed: %v", err)
|
||||||
|
}
|
||||||
if len(elems) != 1 {
|
if len(elems) != 1 {
|
||||||
t.Fatalf("len(elems) = %d, want 1", len(elems))
|
t.Fatalf("len(elems) = %d, want 1", len(elems))
|
||||||
}
|
}
|
||||||
|
|
14
set.go
14
set.go
|
@ -44,6 +44,9 @@ const (
|
||||||
NFTA_SET_ELEM_KEY_END = 10
|
NFTA_SET_ELEM_KEY_END = 10
|
||||||
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n429
|
// https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h?id=d1289bff58e1878c3162f574c603da993e29b113#n429
|
||||||
NFTA_SET_ELEM_EXPRESSIONS = 0x11
|
NFTA_SET_ELEM_EXPRESSIONS = 0x11
|
||||||
|
// FIXME: in sys@v0.34.0 no unix.NFT_MSG_DESTROYSETELEM const yet.
|
||||||
|
// See nf_tables_msg_types enum in https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h
|
||||||
|
NFT_MSG_DESTROYSETELEM = 0x1e
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetDatatype represents a datatype declared by nft.
|
// SetDatatype represents a datatype declared by nft.
|
||||||
|
@ -391,6 +394,16 @@ func (cc *Conn) SetDeleteElements(s *Set, vals []SetElement) error {
|
||||||
return cc.appendElemList(s, vals, unix.NFT_MSG_DELSETELEM)
|
return cc.appendElemList(s, vals, unix.NFT_MSG_DELSETELEM)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDestroyElements like SetDeleteElements, but not an error if setelement doesn't exists
|
||||||
|
func (cc *Conn) SetDestroyElements(s *Set, vals []SetElement) error {
|
||||||
|
cc.mu.Lock()
|
||||||
|
defer cc.mu.Unlock()
|
||||||
|
if s.Anonymous {
|
||||||
|
return errors.New("anonymous sets cannot be updated")
|
||||||
|
}
|
||||||
|
return cc.appendElemList(s, vals, NFT_MSG_DESTROYSETELEM)
|
||||||
|
}
|
||||||
|
|
||||||
// maxElemBatchSize is the maximum size in bytes of encoded set elements which
|
// maxElemBatchSize is the maximum size in bytes of encoded set elements which
|
||||||
// are sent in one netlink message. The size field of a netlink attribute is a
|
// are sent in one netlink message. The size field of a netlink attribute is a
|
||||||
// uint16, and 1024 bytes is more than enough for the per-message headers.
|
// uint16, and 1024 bytes is more than enough for the per-message headers.
|
||||||
|
@ -828,6 +841,7 @@ func parseSetDatatype(magic uint32) (SetDatatype, error) {
|
||||||
const (
|
const (
|
||||||
newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM)
|
newElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWSETELEM)
|
||||||
delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM)
|
delElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELSETELEM)
|
||||||
|
destroyElemHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_DESTROYSETELEM)
|
||||||
)
|
)
|
||||||
|
|
||||||
func elementsFromMsg(fam byte, msg netlink.Message) ([]SetElement, error) {
|
func elementsFromMsg(fam byte, msg netlink.Message) ([]SetElement, error) {
|
||||||
|
|
16
table.go
16
table.go
|
@ -24,6 +24,10 @@ import (
|
||||||
const (
|
const (
|
||||||
newTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWTABLE)
|
newTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_NEWTABLE)
|
||||||
delTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE)
|
delTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE)
|
||||||
|
|
||||||
|
// FIXME: in sys@v0.34.0 no unix.NFT_MSG_DESTROYTABLE const yet.
|
||||||
|
// See nf_tables_msg_types enum in https://git.netfilter.org/nftables/tree/include/linux/netfilter/nf_tables.h
|
||||||
|
destroyTableHeaderType = netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | 0x1a)
|
||||||
)
|
)
|
||||||
|
|
||||||
// TableFamily specifies the address family for this table.
|
// TableFamily specifies the address family for this table.
|
||||||
|
@ -51,15 +55,25 @@ type Table struct {
|
||||||
|
|
||||||
// DelTable deletes a specific table, along with all chains/rules it contains.
|
// DelTable deletes a specific table, along with all chains/rules it contains.
|
||||||
func (cc *Conn) DelTable(t *Table) {
|
func (cc *Conn) DelTable(t *Table) {
|
||||||
|
cc.delTable(t, delTableHeaderType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DestroyTable is like DelTable, but not an error if table doesn't exists
|
||||||
|
func (cc *Conn) DestroyTable(t *Table) {
|
||||||
|
cc.delTable(t, destroyTableHeaderType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *Conn) delTable(t *Table, hdrType netlink.HeaderType) {
|
||||||
cc.mu.Lock()
|
cc.mu.Lock()
|
||||||
defer cc.mu.Unlock()
|
defer cc.mu.Unlock()
|
||||||
data := cc.marshalAttr([]netlink.Attribute{
|
data := cc.marshalAttr([]netlink.Attribute{
|
||||||
{Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")},
|
{Type: unix.NFTA_TABLE_NAME, Data: []byte(t.Name + "\x00")},
|
||||||
{Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}},
|
{Type: unix.NFTA_TABLE_FLAGS, Data: []byte{0, 0, 0, 0}},
|
||||||
})
|
})
|
||||||
|
|
||||||
cc.messages = append(cc.messages, netlinkMessage{
|
cc.messages = append(cc.messages, netlinkMessage{
|
||||||
Header: netlink.Header{
|
Header: netlink.Header{
|
||||||
Type: netlink.HeaderType((unix.NFNL_SUBSYS_NFTABLES << 8) | unix.NFT_MSG_DELTABLE),
|
Type: hdrType,
|
||||||
Flags: netlink.Request | netlink.Acknowledge,
|
Flags: netlink.Request | netlink.Acknowledge,
|
||||||
},
|
},
|
||||||
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
Data: append(extraHeader(uint8(t.Family), 0), data...),
|
||||||
|
|
Loading…
Reference in New Issue