Skip to content

Commit 8c0fb64

Browse files
authored
Merge pull request #1135 from fgschwan/pantheon-dev
Support for Dynamic segment routing proxy with IPv4/IPv6 segment routing unaware services
2 parents 26eb5d4 + fef1de8 commit 8c0fb64

20 files changed

+853
-131
lines changed

plugins/vpp/model/srv6/srv6.pb.go

Lines changed: 126 additions & 58 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/vpp/model/srv6/srv6.proto

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ package srv6;
44

55
message LocalSID {
66
string sid = 1; /* segment id (IPv6 Address) */
7-
uint32 fib_table_id = 2; /* ID of FIB table where to install localsid entry */
7+
uint32 fib_table_id = 2; /* ID of FIB table where to install localsid entry
8+
(LocalSids with End.AD function ignore this setting due to missing setting
9+
in the API. The End.AD functionality is separated from the SRv6 functionality
10+
and have no binary API. It has only the CLI API and that doesn't have
11+
the FIB table setting configurable.) */
812

913
/* Configuration for end functions (all end functions are mutually exclusive) */
1014
End base_end_function = 3;
@@ -15,6 +19,7 @@ message LocalSID {
1519
EndDX6 end_function_DX6 = 8;
1620
EndDT4 end_function_DT4 = 9;
1721
EndDT6 end_function_DT6 = 10;
22+
EndAD end_function_AD = 11;
1823

1924
/* End function behavior of simple endpoint */
2025
message End {
@@ -61,6 +66,13 @@ message LocalSID {
6166
message EndDT6 {
6267
// TODO model this end function
6368
}
69+
70+
/* End function behavior of dynamic segment routing proxy endpoint */
71+
message EndAD {
72+
string service_address = 1; /* IPv6/IPv4 address of SR-unaware service (address type depends whether service is IPv4 or IPv6 service) */
73+
string outgoing_interface = 2; /* name of interface on segment routing proxy side sending data to segment routing unaware service */
74+
string incoming_interface = 3; /* name of interface on segment routing proxy side receiving data from segment routing unaware service */
75+
}
6476
}
6577

6678

plugins/vpp/plugin_impl_vpp.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ func (plugin *Plugin) Close() error {
384384
plugin.aclConfigurator, plugin.ifConfigurator, plugin.bfdConfigurator, plugin.natConfigurator, plugin.stnConfigurator,
385385
plugin.ipSecConfigurator, plugin.bdConfigurator, plugin.fibConfigurator, plugin.xcConfigurator, plugin.arpConfigurator,
386386
plugin.proxyArpConfigurator, plugin.routeConfigurator, plugin.ipNeighConfigurator, plugin.appNsConfigurator,
387-
plugin.puntConfigurator,
387+
plugin.puntConfigurator, plugin.srv6Configurator,
388388
// State updaters
389389
plugin.ifStateUpdater, plugin.bdStateUpdater,
390390
// Channels

plugins/vpp/srplugin/vppcalls/srv6.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515
package vppcalls
1616

1717
import (
18+
"bytes"
1819
"fmt"
1920
"net"
2021
"strings"
2122

2223
"github.com/ligato/cn-infra/logging"
24+
"github.com/ligato/vpp-agent/plugins/govppmux/vppcalls"
25+
"github.com/ligato/vpp-agent/plugins/vpp/binapi/interfaces"
2326
"github.com/ligato/vpp-agent/plugins/vpp/binapi/sr"
2427
"github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx"
28+
ifnb "github.com/ligato/vpp-agent/plugins/vpp/model/interfaces"
2529
"github.com/ligato/vpp-agent/plugins/vpp/model/srv6"
2630
)
2731

@@ -68,6 +72,9 @@ func (h *SRv6VppHandler) DeleteLocalSid(sidAddr net.IP) error {
6872
func (h *SRv6VppHandler) addDelLocalSid(deletion bool, sidAddr net.IP, localSID *srv6.LocalSID, swIfIndex ifaceidx.SwIfIndex) error {
6973
h.log.WithFields(logging.Fields{"localSID": sidAddr, "delete": deletion, "FIB table ID": h.fibTableID(localSID), "end function": h.endFunction(localSID)}).
7074
Debug("Adding/deleting Local SID", sidAddr)
75+
if !deletion && localSID.EndFunction_AD != nil {
76+
return h.addSRProxy(sidAddr, localSID, swIfIndex)
77+
}
7178
req := &sr.SrLocalsidAddDel{
7279
IsDel: boolToUint(deletion),
7380
Localsid: sr.Srv6Sid{Addr: []byte(sidAddr)},
@@ -93,6 +100,63 @@ func (h *SRv6VppHandler) addDelLocalSid(deletion bool, sidAddr net.IP, localSID
93100
return nil
94101
}
95102

103+
// addSRProxy adds local sid with SR-proxy end function (End.AD). This functionality has no binary API in VPP, therefore
104+
// CLI commands are used (VPE binary API that calls VPP's CLI).
105+
func (h *SRv6VppHandler) addSRProxy(sidAddr net.IP, localSID *srv6.LocalSID, swIfIndex ifaceidx.SwIfIndex) error {
106+
// get VPP-internal names of IN and OUT interfaces
107+
names, err := h.interfaceNameMapping()
108+
if err != nil {
109+
return fmt.Errorf("can't convert interface names from etcd to VPP-internal interface names:%v", err)
110+
}
111+
outInterface, found := names[localSID.EndFunction_AD.OutgoingInterface]
112+
if !found {
113+
return fmt.Errorf("can't find VPP-internal name for interface %v (name in etcd)", localSID.EndFunction_AD.OutgoingInterface)
114+
}
115+
inInterface, found := names[localSID.EndFunction_AD.IncomingInterface]
116+
if !found {
117+
return fmt.Errorf("can't find VPP-internal name for interface %v (name in etcd)", localSID.EndFunction_AD.IncomingInterface)
118+
}
119+
120+
// add SR-proxy using VPP CLI
121+
data, err := vppcalls.RunCliCommand(h.callsChannel,
122+
fmt.Sprintf("sr localsid address %v behavior end.ad nh %v oif %v iif %v", sidAddr, localSID.EndFunction_AD.ServiceAddress, outInterface, inInterface))
123+
if err != nil {
124+
return err
125+
}
126+
if len(strings.TrimSpace(string(data))) > 0 {
127+
return fmt.Errorf("addition of dynamic segment routing proxy failed by returning nonblank space text in CLI: %v", string(data))
128+
}
129+
return nil
130+
}
131+
132+
// interfaceNameMapping dumps from VPP internal names of interfaces and uses them to produce mapping from ligato interface names to vpp internal names.
133+
func (h *SRv6VppHandler) interfaceNameMapping() (map[string]string, error) {
134+
mapping := make(map[string]string)
135+
reqCtx := h.callsChannel.SendMultiRequest(&interfaces.SwInterfaceDump{})
136+
137+
for {
138+
// get next interface info
139+
ifDetails := &interfaces.SwInterfaceDetails{}
140+
stop, err := reqCtx.ReceiveReply(ifDetails)
141+
if stop {
142+
break // Break from the loop.
143+
}
144+
if err != nil {
145+
return nil, fmt.Errorf("failed to dump interface: %v", err)
146+
}
147+
148+
// extract and compute names
149+
ligatoName := string(bytes.SplitN(ifDetails.Tag, []byte{0x00}, 2)[0])
150+
vppInternalName := string(bytes.SplitN(ifDetails.InterfaceName, []byte{0x00}, 2)[0])
151+
if guessInterfaceType(string(ifDetails.InterfaceName)) == ifnb.InterfaceType_ETHERNET_CSMACD { // fill name for physical interfaces (they are mostly without tag)
152+
ligatoName = vppInternalName
153+
}
154+
155+
mapping[ligatoName] = vppInternalName
156+
}
157+
return mapping, nil
158+
}
159+
96160
func (h *SRv6VppHandler) fibTableID(localSID *srv6.LocalSID) string {
97161
if localSID != nil {
98162
return string(localSID.FibTableId)
@@ -119,6 +183,8 @@ func (h *SRv6VppHandler) endFunction(localSID *srv6.LocalSID) string {
119183
return fmt.Sprint("DT4")
120184
} else if localSID.EndFunction_DT6 != nil {
121185
return fmt.Sprint("DT6")
186+
} else if localSID.EndFunction_AD != nil {
187+
return fmt.Sprintf("AD{ServiceAddress: %v, OutgoingInterface: %v, IncomingInterface: %v}", localSID.EndFunction_AD.ServiceAddress, localSID.EndFunction_AD.OutgoingInterface, localSID.EndFunction_AD.IncomingInterface)
122188
}
123189
return "unknown end function"
124190
}
@@ -459,3 +525,29 @@ func parseIPv6(str string) (net.IP, error) {
459525
}
460526
return ipv6, nil
461527
}
528+
529+
// guessInterfaceType attempts to guess the correct interface type from its internal name (as given by VPP).
530+
// This is required mainly for those interface types, that do not provide dump binary API,
531+
// such as loopback of af_packet.
532+
func guessInterfaceType(ifName string) ifnb.InterfaceType {
533+
switch {
534+
case strings.HasPrefix(ifName, "loop"):
535+
return ifnb.InterfaceType_SOFTWARE_LOOPBACK
536+
case strings.HasPrefix(ifName, "local"):
537+
return ifnb.InterfaceType_SOFTWARE_LOOPBACK
538+
case strings.HasPrefix(ifName, "memif"):
539+
return ifnb.InterfaceType_MEMORY_INTERFACE
540+
case strings.HasPrefix(ifName, "tap"):
541+
return ifnb.InterfaceType_TAP_INTERFACE
542+
case strings.HasPrefix(ifName, "host"):
543+
return ifnb.InterfaceType_AF_PACKET_INTERFACE
544+
case strings.HasPrefix(ifName, "vxlan"):
545+
return ifnb.InterfaceType_VXLAN_TUNNEL
546+
case strings.HasPrefix(ifName, "ipsec"):
547+
return ifnb.InterfaceType_IPSEC_TUNNEL
548+
case strings.HasPrefix(ifName, "vmxnet3"):
549+
return ifnb.InterfaceType_VMXNET3_INTERFACE
550+
}
551+
552+
return ifnb.InterfaceType_ETHERNET_CSMACD
553+
}

0 commit comments

Comments
 (0)