Skip to content

Commit f44ade1

Browse files
Update bfd and nat64 plugin (#73)
Signed-off-by: Matus Halaj <[email protected]> Signed-off-by: Matus Halaj <[email protected]> Co-authored-by: Ondrej Fabry <[email protected]>
1 parent 203aeb4 commit f44ade1

16 files changed

+2772
-0
lines changed

plugins/bfd/bfdplugin.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ import (
3838
"go.pantheon.tech/stonework/proto/bfd"
3939

4040
_ "go.pantheon.tech/stonework/plugins/bfd/vppcalls/vpp2106"
41+
_ "go.pantheon.tech/stonework/plugins/bfd/vppcalls/vpp2202"
42+
_ "go.pantheon.tech/stonework/plugins/bfd/vppcalls/vpp2210"
4143
)
4244

4345
// BfdPlugin groups required BFD dependencies and descriptors
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
// Copyright 2022 PANTHEON.tech
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package vpp2202
18+
19+
import (
20+
"context"
21+
"errors"
22+
"fmt"
23+
"os"
24+
"time"
25+
26+
govppapi "go.fd.io/govpp/api"
27+
28+
"go.pantheon.tech/stonework/plugins/bfd/vppcalls"
29+
binapi "go.pantheon.tech/stonework/plugins/binapi/vpp2202/bfd"
30+
"go.pantheon.tech/stonework/plugins/binapi/vpp2202/interface_types"
31+
"go.pantheon.tech/stonework/plugins/binapi/vpp2202/ip_types"
32+
"go.pantheon.tech/stonework/proto/bfd"
33+
)
34+
35+
var (
36+
// EventDeliverTimeout defines maximum time to deliver event upstream.
37+
EventDeliverTimeout = time.Second
38+
39+
// NotificationChanBufferSize defines size of notification channel buffer.
40+
NotificationChanBufferSize = 10
41+
)
42+
43+
// AddBfd creates BFD session attached to the defined interface with given configuration ID.
44+
func (h *BfdVppHandler) AddBfd(confID uint32, bfdEntry *bfd.BFD) error {
45+
// interface
46+
ifMeta, exists := h.ifIndexes.LookupByName(bfdEntry.Interface)
47+
if !exists {
48+
return fmt.Errorf("cannot configure BFD: interface %s is missing", bfdEntry.Interface)
49+
}
50+
51+
localAddr, err := ip_types.ParseAddress(bfdEntry.GetLocalIp())
52+
if err != nil {
53+
return err
54+
}
55+
peerAddr, err := ip_types.ParseAddress(bfdEntry.GetPeerIp())
56+
if err != nil {
57+
return err
58+
}
59+
if localAddr.Af != peerAddr.Af {
60+
return fmt.Errorf("both IP addresses must be the same IP version")
61+
}
62+
req := &binapi.BfdUDPAdd{
63+
SwIfIndex: interface_types.InterfaceIndex(ifMeta.SwIfIndex),
64+
DesiredMinTx: bfdEntry.GetMinTxInterval(),
65+
RequiredMinRx: bfdEntry.GetMinRxInterval(),
66+
LocalAddr: localAddr,
67+
PeerAddr: peerAddr,
68+
DetectMult: uint8(bfdEntry.GetDetectMultiplier()),
69+
BfdKeyID: uint8(confID),
70+
ConfKeyID: confID,
71+
}
72+
73+
resp := &binapi.BfdUDPAddReply{}
74+
return h.callsChannel.SendRequest(req).ReceiveReply(resp)
75+
}
76+
77+
// DeletebfdEntry removes existing BFD session.
78+
func (h *BfdVppHandler) DeleteBfd(bfdEntry *bfd.BFD) error {
79+
ifMeta, exists := h.ifIndexes.LookupByName(bfdEntry.Interface)
80+
if !exists {
81+
return fmt.Errorf("cannot remove BFD: interface %s is missing", bfdEntry.Interface)
82+
}
83+
84+
localAddr, err := ip_types.ParseAddress(bfdEntry.GetLocalIp())
85+
if err != nil {
86+
return err
87+
}
88+
peerAddr, err := ip_types.ParseAddress(bfdEntry.GetPeerIp())
89+
if err != nil {
90+
return err
91+
}
92+
if localAddr.Af != peerAddr.Af {
93+
return fmt.Errorf("both IP addresses must be the same IP version")
94+
}
95+
req := &binapi.BfdUDPDel{
96+
SwIfIndex: interface_types.InterfaceIndex(ifMeta.SwIfIndex),
97+
LocalAddr: localAddr,
98+
PeerAddr: peerAddr,
99+
}
100+
101+
resp := &binapi.BfdUDPDelReply{}
102+
return h.callsChannel.SendRequest(req).ReceiveReply(resp)
103+
}
104+
105+
// DumpBfd returns retrieved BFD data together with BFD state.
106+
func (h *BfdVppHandler) DumpBfd() ([]*vppcalls.BfdDetails, error) {
107+
var bfdList []*vppcalls.BfdDetails
108+
reqCtx := h.callsChannel.SendMultiRequest(&binapi.BfdUDPSessionDump{})
109+
for {
110+
bfdEntryDetails := &binapi.BfdUDPSessionDetails{}
111+
if stop, err := reqCtx.ReceiveReply(bfdEntryDetails); err != nil {
112+
h.log.Error(err)
113+
return nil, err
114+
} else if stop {
115+
break
116+
}
117+
ifName, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(bfdEntryDetails.SwIfIndex))
118+
if !exists {
119+
return nil, fmt.Errorf("BFD interface with index %d is missing", bfdEntryDetails.SwIfIndex)
120+
}
121+
config := &bfd.BFD{
122+
Interface: ifName,
123+
LocalIp: bfdEntryDetails.LocalAddr.String(),
124+
PeerIp: bfdEntryDetails.PeerAddr.String(),
125+
MinTxInterval: bfdEntryDetails.DesiredMinTx,
126+
MinRxInterval: bfdEntryDetails.RequiredMinRx,
127+
DetectMultiplier: uint32(bfdEntryDetails.DetectMult),
128+
}
129+
130+
bfdList = append(bfdList, &vppcalls.BfdDetails{
131+
Config: config,
132+
State: stateToProto(bfdEntryDetails.State),
133+
ConfKey: bfdEntryDetails.ConfKeyID,
134+
BfdKey: bfdEntryDetails.BfdKeyID,
135+
IsAuthenticated: bfdEntryDetails.IsAuthenticated,
136+
})
137+
}
138+
139+
return bfdList, nil
140+
}
141+
142+
// WatchBfdEvents starts BFD event watcher.
143+
func (h *BfdVppHandler) WatchBfdEvents(ctx context.Context, eventChan chan<- *bfd.BFDEvent) error {
144+
notificationChan := make(chan govppapi.Message, NotificationChanBufferSize)
145+
146+
// subscribe to BFD notifications
147+
sub, err := h.callsChannel.SubscribeNotification(notificationChan, &binapi.BfdUDPSessionDetails{})
148+
if err != nil {
149+
return fmt.Errorf("subscribing to VPP notification (bfd_session_event) failed: %v", err)
150+
}
151+
unsubscribe := func() {
152+
if err := sub.Unsubscribe(); err != nil {
153+
h.log.Warnf("unsubscribing VPP notification (bfd_session_event) failed: %v", err)
154+
}
155+
}
156+
157+
go func() {
158+
h.log.Debugf("start watching BFD events")
159+
defer h.log.Debugf("done watching BFD events (%v)", ctx.Err())
160+
161+
for {
162+
select {
163+
case e, open := <-notificationChan:
164+
if !open {
165+
h.log.Debugf("BFD events channel was closed")
166+
unsubscribe()
167+
return
168+
}
169+
170+
bfdEvent, ok := e.(*binapi.BfdUDPSessionDetails)
171+
if !ok {
172+
h.log.Debugf("unexpected notification type: %#v", bfdEvent)
173+
continue
174+
}
175+
176+
event, err := h.toBfdEvent(bfdEvent)
177+
if err != nil {
178+
h.log.Warn(err)
179+
continue
180+
}
181+
182+
select {
183+
case eventChan <- event:
184+
// ok
185+
case <-ctx.Done():
186+
unsubscribe()
187+
return
188+
default:
189+
// in case the channel is full
190+
go func() {
191+
select {
192+
case eventChan <- event:
193+
// sent ok
194+
case <-time.After(EventDeliverTimeout):
195+
h.log.Warnf("BFD (conf-ID: %d) event dropped, cannot deliver", bfdEvent.ConfKeyID)
196+
}
197+
}()
198+
}
199+
case <-ctx.Done():
200+
unsubscribe()
201+
return
202+
}
203+
}
204+
}()
205+
206+
// enable BFD events from VPP
207+
req := &binapi.WantBfdEvents{
208+
PID: uint32(os.Getpid()),
209+
EnableDisable: true,
210+
}
211+
resp := &binapi.WantBfdEventsReply{}
212+
err = h.callsChannel.SendRequest(req).ReceiveReply(resp)
213+
// do not return error on repeated subscribe attempt
214+
if errors.Is(err, govppapi.VPPApiError(govppapi.INVALID_REGISTRATION)) {
215+
h.log.Debugf("already subscribed to BFD events: %v", err)
216+
return nil
217+
}
218+
return err
219+
}
220+
221+
func (h *BfdVppHandler) toBfdEvent(bfdEvent *binapi.BfdUDPSessionDetails) (*bfd.BFDEvent, error) {
222+
ifName, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(bfdEvent.SwIfIndex))
223+
if !exists {
224+
return nil, fmt.Errorf("BFD event for unknown interface (sw_if_index: %d)",
225+
bfdEvent.SwIfIndex)
226+
}
227+
event := &bfd.BFDEvent{
228+
Interface: ifName,
229+
LocalIp: bfdEvent.LocalAddr.String(),
230+
PeerIp: bfdEvent.PeerAddr.String(),
231+
SessionState: stateToProto(bfdEvent.State),
232+
}
233+
return event, nil
234+
}
235+
236+
func stateToProto(state binapi.BfdState) bfd.BFDEvent_SessionState {
237+
switch state {
238+
case 1:
239+
return bfd.BFDEvent_Down
240+
case 2:
241+
return bfd.BFDEvent_Init
242+
case 3:
243+
return bfd.BFDEvent_Up
244+
}
245+
return bfd.BFDEvent_Unknown
246+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
// Copyright 2022 PANTHEON.tech
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
17+
package vpp2202
18+
19+
import (
20+
govppapi "go.fd.io/govpp/api"
21+
"go.ligato.io/cn-infra/v2/logging"
22+
23+
"go.ligato.io/vpp-agent/v3/plugins/vpp/ifplugin/ifaceidx"
24+
25+
"go.pantheon.tech/stonework/plugins/bfd/vppcalls"
26+
binapi "go.pantheon.tech/stonework/plugins/binapi/vpp2202"
27+
"go.pantheon.tech/stonework/plugins/binapi/vpp2202/bfd"
28+
)
29+
30+
func init() {
31+
var msgs []govppapi.Message
32+
msgs = append(msgs, bfd.AllMessages()...)
33+
34+
vppcalls.AddBfdHandlerVersion(binapi.Version, msgs, NewBfdVppHandler)
35+
}
36+
37+
// BfdVppHandler is accessor for BFD-related vppcalls methods
38+
type BfdVppHandler struct {
39+
callsChannel govppapi.Channel
40+
ifIndexes ifaceidx.IfaceMetadataIndex
41+
log logging.Logger
42+
}
43+
44+
// NewBfdVppHandler creates new instance of BFD vppcalls handler
45+
func NewBfdVppHandler(calls govppapi.Channel, ifIndexes ifaceidx.IfaceMetadataIndex, log logging.Logger) vppcalls.BfdVppAPI {
46+
return &BfdVppHandler{
47+
callsChannel: calls,
48+
ifIndexes: ifIndexes,
49+
log: log,
50+
}
51+
}

0 commit comments

Comments
 (0)