1515package vppcalls
1616
1717import (
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 {
6872func (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+
96160func (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