15
15
package vppcalls
16
16
17
17
import (
18
+ "bytes"
18
19
"fmt"
19
20
"net"
20
21
"strings"
21
22
22
23
"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"
23
26
"github.com/ligato/vpp-agent/plugins/vpp/binapi/sr"
24
27
"github.com/ligato/vpp-agent/plugins/vpp/ifplugin/ifaceidx"
28
+ ifnb "github.com/ligato/vpp-agent/plugins/vpp/model/interfaces"
25
29
"github.com/ligato/vpp-agent/plugins/vpp/model/srv6"
26
30
)
27
31
@@ -68,6 +72,9 @@ func (h *SRv6VppHandler) DeleteLocalSid(sidAddr net.IP) error {
68
72
func (h * SRv6VppHandler ) addDelLocalSid (deletion bool , sidAddr net.IP , localSID * srv6.LocalSID , swIfIndex ifaceidx.SwIfIndex ) error {
69
73
h .log .WithFields (logging.Fields {"localSID" : sidAddr , "delete" : deletion , "FIB table ID" : h .fibTableID (localSID ), "end function" : h .endFunction (localSID )}).
70
74
Debug ("Adding/deleting Local SID" , sidAddr )
75
+ if ! deletion && localSID .EndFunction_AD != nil {
76
+ return h .addSRProxy (sidAddr , localSID , swIfIndex )
77
+ }
71
78
req := & sr.SrLocalsidAddDel {
72
79
IsDel : boolToUint (deletion ),
73
80
Localsid : sr.Srv6Sid {Addr : []byte (sidAddr )},
@@ -93,6 +100,63 @@ func (h *SRv6VppHandler) addDelLocalSid(deletion bool, sidAddr net.IP, localSID
93
100
return nil
94
101
}
95
102
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
+
96
160
func (h * SRv6VppHandler ) fibTableID (localSID * srv6.LocalSID ) string {
97
161
if localSID != nil {
98
162
return string (localSID .FibTableId )
@@ -119,6 +183,8 @@ func (h *SRv6VppHandler) endFunction(localSID *srv6.LocalSID) string {
119
183
return fmt .Sprint ("DT4" )
120
184
} else if localSID .EndFunction_DT6 != nil {
121
185
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 )
122
188
}
123
189
return "unknown end function"
124
190
}
@@ -459,3 +525,29 @@ func parseIPv6(str string) (net.IP, error) {
459
525
}
460
526
return ipv6 , nil
461
527
}
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