11package osl
22
33import (
4- "bytes"
54 "context"
65 "errors"
76 "fmt"
87 "net"
98 "os"
9+ "strings"
1010
1111 "github.com/containerd/log"
1212 "github.com/vishvananda/netlink"
1313)
1414
1515// NeighborSearchError indicates that the neighbor is already present
1616type NeighborSearchError struct {
17- ip net.IP
18- mac net.HardwareAddr
19- present bool
20- }
21-
22- func (n NeighborSearchError ) Error () string {
23- return fmt .Sprintf ("Search neighbor failed for IP %v, mac %v, present in db:%t" , n .ip , n .mac , n .present )
24- }
25-
26- type neigh struct {
27- dstIP net.IP
28- dstMac net.HardwareAddr
17+ ip net.IP
18+ mac net.HardwareAddr
2919 linkName string
30- linkDst string
31- family int
20+ present bool
3221}
3322
34- func (n * Namespace ) findNeighbor (dstIP net.IP , dstMac net.HardwareAddr ) * neigh {
35- n .mu .Lock ()
36- defer n .mu .Unlock ()
37-
38- for _ , nh := range n .neighbors {
39- if nh .dstIP .Equal (dstIP ) && bytes .Equal (nh .dstMac , dstMac ) {
40- return nh
41- }
23+ func (n NeighborSearchError ) Error () string {
24+ var b strings.Builder
25+ b .WriteString ("neighbor entry " )
26+ if n .present {
27+ b .WriteString ("already exists " )
28+ } else {
29+ b .WriteString ("not found " )
4230 }
43-
44- return nil
31+ b .WriteString ("for IP " )
32+ b .WriteString (n .ip .String ())
33+ b .WriteString (", mac " )
34+ b .WriteString (n .mac .String ())
35+ if n .linkName != "" {
36+ b .WriteString (", link " )
37+ b .WriteString (n .linkName )
38+ }
39+ return b .String ()
4540}
4641
47- // DeleteNeighbor deletes neighbor entry from the sandbox.
48- func (n * Namespace ) DeleteNeighbor (dstIP net.IP , dstMac net.HardwareAddr ) error {
49- nh := n .findNeighbor (dstIP , dstMac )
50- if nh == nil {
51- return NeighborSearchError {dstIP , dstMac , false }
42+ // DeleteNeighbor deletes a neighbor entry from the sandbox.
43+ //
44+ // To delete an entry inserted by [AddNeighbor] the caller must provide the same
45+ // parameters used to add it.
46+ func (n * Namespace ) DeleteNeighbor (dstIP net.IP , dstMac net.HardwareAddr , options ... NeighOption ) error {
47+ nlnh , linkName , err := n .nlNeigh (dstIP , dstMac , options ... )
48+ if err != nil {
49+ return err
5250 }
5351
54- var linkIndex int
55- if nh .linkDst != "" {
56- iface , err := n .nlHandle .LinkByName (nh .linkDst )
57- if err != nil {
58- return fmt .Errorf ("could not find interface with destination name %s: %v" , nh .linkDst , err )
52+ if err := n .nlHandle .NeighDel (nlnh ); err != nil {
53+ log .G (context .TODO ()).WithFields (log.Fields {
54+ "ip" : dstIP ,
55+ "mac" : dstMac ,
56+ "ifc" : linkName ,
57+ "error" : err ,
58+ }).Warn ("error deleting neighbor entry" )
59+ if errors .Is (err , os .ErrNotExist ) {
60+ return NeighborSearchError {dstIP , dstMac , linkName , false }
5961 }
60- linkIndex = iface .Attrs ().Index
61- }
62-
63- nlnh := & netlink.Neigh {
64- LinkIndex : linkIndex ,
65- IP : dstIP ,
66- State : netlink .NUD_PERMANENT ,
67- Family : nh .family ,
68- }
69-
70- if nh .family > 0 {
71- nlnh .HardwareAddr = dstMac
72- nlnh .Flags = netlink .NTF_SELF
73- }
74-
75- // If the kernel deletion fails for the neighbor entry still remove it
76- // from the namespace cache, otherwise kernel update can fail if the
77- // neighbor moves back to the same host again.
78- if err := n .nlHandle .NeighDel (nlnh ); err != nil && ! errors .Is (err , os .ErrNotExist ) {
79- log .G (context .TODO ()).Warnf ("Deleting neighbor IP %s, mac %s failed, %v" , dstIP , dstMac , err )
62+ return fmt .Errorf ("could not delete neighbor %+v: %w" , nlnh , err )
8063 }
8164
8265 // Delete the dynamic entry in the bridge
83- if nh . family > 0 {
84- if err := n . nlHandle . NeighDel ( & netlink.Neigh {
85- LinkIndex : linkIndex ,
86- IP : dstIP ,
87- Family : nh . family ,
88- HardwareAddr : dstMac ,
89- Flags : netlink . NTF_MASTER ,
90- }); err != nil && ! errors . Is ( err , os . ErrNotExist ) {
91- log . G ( context . TODO ()). WithError ( err ). Warn ("error while deleting neighbor entry" )
66+ if nlnh . Family > 0 {
67+ nlnh . Flags = netlink .NTF_MASTER
68+ if err := n . nlHandle . NeighDel ( nlnh ); err != nil && ! errors . Is ( err , os . ErrNotExist ) {
69+ log . G ( context . TODO ()). WithFields (log. Fields {
70+ "ip" : dstIP ,
71+ "mac" : dstMac ,
72+ "ifc" : linkName ,
73+ "error" : err ,
74+ }). Warn ("error deleting dynamic neighbor entry" )
9275 }
9376 }
9477
95- n .mu .Lock ()
96- for i , neighbor := range n .neighbors {
97- if neighbor .dstIP .Equal (dstIP ) && bytes .Equal (neighbor .dstMac , dstMac ) {
98- n .neighbors = append (n .neighbors [:i ], n .neighbors [i + 1 :]... )
99- break
100- }
101- }
102- n .mu .Unlock ()
103- log .G (context .TODO ()).Debugf ("Neighbor entry deleted for IP %v, mac %v" , dstIP , dstMac )
78+ log .G (context .TODO ()).WithFields (log.Fields {
79+ "ip" : dstIP ,
80+ "mac" : dstMac ,
81+ "ifc" : linkName ,
82+ }).Debug ("Neighbor entry deleted" )
10483
10584 return nil
10685}
10786
10887// AddNeighbor adds a neighbor entry into the sandbox.
10988func (n * Namespace ) AddNeighbor (dstIP net.IP , dstMac net.HardwareAddr , options ... NeighOption ) error {
110- nh := n .findNeighbor (dstIP , dstMac )
111- if nh != nil {
112- log .G (context .TODO ()).Warnf ("Neighbor entry already present for IP %v, mac %v neighbor:%+v" , dstIP , dstMac , nh )
113- return NeighborSearchError {dstIP , dstMac , true }
89+ nlnh , linkName , err := n .nlNeigh (dstIP , dstMac , options ... )
90+ if err != nil {
91+ return err
11492 }
11593
116- nh = & neigh {
117- dstIP : dstIP ,
118- dstMac : dstMac ,
94+ if err := n .nlHandle .NeighAdd (nlnh ); err != nil {
95+ if errors .Is (err , os .ErrExist ) {
96+ log .G (context .TODO ()).WithFields (log.Fields {
97+ "ip" : dstIP ,
98+ "mac" : dstMac ,
99+ "ifc" : linkName ,
100+ "neigh" : fmt .Sprintf ("%+v" , nlnh ),
101+ }).Warn ("Neighbor entry already present" )
102+ return NeighborSearchError {dstIP , dstMac , linkName , true }
103+ } else {
104+ return fmt .Errorf ("could not add neighbor entry %+v: %w" , nlnh , err )
105+ }
119106 }
120107
108+ log .G (context .TODO ()).WithFields (log.Fields {
109+ "ip" : dstIP ,
110+ "mac" : dstMac ,
111+ "ifc" : linkName ,
112+ }).Debug ("Neighbor entry added" )
113+
114+ return nil
115+ }
116+
117+ type neigh struct {
118+ linkName string
119+ family int
120+ }
121+
122+ func (n * Namespace ) nlNeigh (dstIP net.IP , dstMac net.HardwareAddr , options ... NeighOption ) (* netlink.Neigh , string , error ) {
123+ var nh neigh
121124 nh .processNeighOptions (options ... )
122125
123126 nlnh := & netlink.Neigh {
@@ -132,26 +135,16 @@ func (n *Namespace) AddNeighbor(dstIP net.IP, dstMac net.HardwareAddr, options .
132135 }
133136
134137 if nh .linkName != "" {
135- nh . linkDst = n .findDst (nh .linkName , false )
136- if nh . linkDst == "" {
137- return fmt .Errorf ("could not find the interface with name %s" , nh .linkName )
138+ linkDst : = n .findDst (nh .linkName , false )
139+ if linkDst == "" {
140+ return nil , nh . linkName , fmt .Errorf ("could not find the interface with name %s" , nh .linkName )
138141 }
139-
140- iface , err := n .nlHandle .LinkByName (nh .linkDst )
142+ iface , err := n .nlHandle .LinkByName (linkDst )
141143 if err != nil {
142- return fmt .Errorf ("could not find interface with destination name %s: %v " , nh . linkDst , err )
144+ return nil , nh . linkName , fmt .Errorf ("could not find interface with destination name %s: %w " , linkDst , err )
143145 }
144146 nlnh .LinkIndex = iface .Attrs ().Index
145147 }
146148
147- if err := n .nlHandle .NeighSet (nlnh ); err != nil {
148- return fmt .Errorf ("could not add neighbor entry:%+v error:%v" , nlnh , err )
149- }
150-
151- n .mu .Lock ()
152- n .neighbors = append (n .neighbors , nh )
153- n .mu .Unlock ()
154- log .G (context .TODO ()).Debugf ("Neighbor entry added for IP:%v, mac:%v on ifc:%s" , dstIP , dstMac , nh .linkName )
155-
156- return nil
149+ return nlnh , nh .linkName , nil
157150}
0 commit comments