go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/l2plugin/vppcalls/vpp2202/dump_vppcalls.go (about) 1 // Copyright (c) 2022 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package vpp2202 16 17 import ( 18 "net" 19 "strings" 20 21 "github.com/pkg/errors" 22 23 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/interface_types" 24 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/ip_types" 25 vpp_l2 "go.ligato.io/vpp-agent/v3/plugins/vpp/binapi/vpp2202/l2" 26 "go.ligato.io/vpp-agent/v3/plugins/vpp/l2plugin/vppcalls" 27 l2 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/l2" 28 ) 29 30 // DumpBridgeDomains implements bridge domain handler. 31 func (h *BridgeDomainVppHandler) DumpBridgeDomains() ([]*vppcalls.BridgeDomainDetails, error) { 32 // At first prepare bridge domain ARP termination table which needs to be dumped separately. 33 bdArpTab, err := h.dumpBridgeDomainMacTable() 34 if err != nil { 35 return nil, errors.Errorf("failed to dump arp termination table: %v", err) 36 } 37 38 // list of resulting BDs 39 var bds []*vppcalls.BridgeDomainDetails 40 41 // dump bridge domains 42 reqCtx := h.callsChannel.SendMultiRequest(&vpp_l2.BridgeDomainDump{ 43 BdID: ^uint32(0), 44 SwIfIndex: ^interface_types.InterfaceIndex(0), 45 }) 46 47 for { 48 bdDetails := &vpp_l2.BridgeDomainDetails{} 49 stop, err := reqCtx.ReceiveReply(bdDetails) 50 if stop { 51 break 52 } 53 if err != nil { 54 return nil, err 55 } 56 57 // bridge domain metadata 58 bdData := &vppcalls.BridgeDomainDetails{ 59 Bd: &l2.BridgeDomain{ 60 Name: strings.Trim(bdDetails.BdTag, "\x00"), 61 Flood: bdDetails.Flood, 62 UnknownUnicastFlood: bdDetails.UuFlood, 63 Forward: bdDetails.Forward, 64 Learn: bdDetails.Learn, 65 ArpTermination: bdDetails.ArpTerm, 66 MacAge: uint32(bdDetails.MacAge), 67 }, 68 Meta: &vppcalls.BridgeDomainMeta{ 69 BdID: bdDetails.BdID, 70 }, 71 } 72 73 // bridge domain interfaces 74 for _, iface := range bdDetails.SwIfDetails { 75 ifaceName, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(iface.SwIfIndex)) 76 if !exists { 77 h.log.Warnf("Bridge domain dump: interface name for index %d not found", iface.SwIfIndex) 78 continue 79 } 80 // Bvi 81 var bvi bool 82 if iface.SwIfIndex == bdDetails.BviSwIfIndex { 83 bvi = true 84 } 85 // add interface entry 86 bdData.Bd.Interfaces = append(bdData.Bd.Interfaces, &l2.BridgeDomain_Interface{ 87 Name: ifaceName, 88 BridgedVirtualInterface: bvi, 89 SplitHorizonGroup: uint32(iface.Shg), 90 }) 91 } 92 93 // Add ARP termination entries. 94 arpTable, ok := bdArpTab[bdDetails.BdID] 95 if ok { 96 bdData.Bd.ArpTerminationTable = arpTable 97 } 98 99 bds = append(bds, bdData) 100 } 101 102 return bds, nil 103 } 104 105 // Reads ARP termination table from all bridge domains. Result is then added to bridge domains. 106 func (h *BridgeDomainVppHandler) dumpBridgeDomainMacTable() (map[uint32][]*l2.BridgeDomain_ArpTerminationEntry, error) { 107 bdArpTable := make(map[uint32][]*l2.BridgeDomain_ArpTerminationEntry) 108 req := &vpp_l2.BdIPMacDump{BdID: ^uint32(0)} 109 110 reqCtx := h.callsChannel.SendMultiRequest(req) 111 for { 112 msg := &vpp_l2.BdIPMacDetails{} 113 stop, err := reqCtx.ReceiveReply(msg) 114 if err != nil { 115 return nil, err 116 } 117 if stop { 118 break 119 } 120 121 // Prepare ARP entry 122 arpEntry := &l2.BridgeDomain_ArpTerminationEntry{} 123 arpEntry.IpAddress = parseAddressToString(msg.Entry.IP) 124 arpEntry.PhysAddress = net.HardwareAddr(msg.Entry.Mac[:]).String() 125 126 // Add ARP entry to result map 127 bdArpTable[msg.Entry.BdID] = append(bdArpTable[msg.Entry.BdID], arpEntry) 128 } 129 130 return bdArpTable, nil 131 } 132 133 // DumpL2FIBs dumps VPP L2 FIB table entries into the northbound API 134 // data structure map indexed by destination MAC address. 135 func (h *FIBVppHandler) DumpL2FIBs() (map[string]*vppcalls.FibTableDetails, error) { 136 // map for the resulting FIBs 137 fibs := make(map[string]*vppcalls.FibTableDetails) 138 139 reqCtx := h.callsChannel.SendMultiRequest(&vpp_l2.L2FibTableDump{BdID: ^uint32(0)}) 140 for { 141 fibDetails := &vpp_l2.L2FibTableDetails{} 142 stop, err := reqCtx.ReceiveReply(fibDetails) 143 if stop { 144 break // Break from the loop. 145 } 146 if err != nil { 147 return nil, err 148 } 149 150 mac := net.HardwareAddr(fibDetails.Mac[:]).String() 151 var action l2.FIBEntry_Action 152 if fibDetails.FilterMac { 153 action = l2.FIBEntry_DROP 154 } else { 155 action = l2.FIBEntry_FORWARD 156 } 157 158 // Interface name (only for FORWARD entries) 159 var ifName string 160 if action == l2.FIBEntry_FORWARD { 161 var exists bool 162 ifName, _, exists = h.ifIndexes.LookupBySwIfIndex(uint32(fibDetails.SwIfIndex)) 163 if !exists { 164 h.log.Warnf("FIB dump: interface name for index %d not found", fibDetails.SwIfIndex) 165 continue 166 } 167 } 168 // Bridge domain name 169 bdName, _, exists := h.bdIndexes.LookupByIndex(fibDetails.BdID) 170 if !exists { 171 h.log.Warnf("FIB dump: bridge domain name for index %d not found", fibDetails.BdID) 172 continue 173 } 174 175 fibs[mac] = &vppcalls.FibTableDetails{ 176 Fib: &l2.FIBEntry{ 177 PhysAddress: mac, 178 BridgeDomain: bdName, 179 Action: action, 180 OutgoingInterface: ifName, 181 StaticConfig: fibDetails.StaticMac, 182 BridgedVirtualInterface: fibDetails.BviMac, 183 }, 184 Meta: &vppcalls.FibMeta{ 185 BdID: fibDetails.BdID, 186 IfIdx: uint32(fibDetails.SwIfIndex), 187 }, 188 } 189 } 190 191 return fibs, nil 192 } 193 194 // DumpXConnectPairs implements xconnect handler. 195 func (h *XConnectVppHandler) DumpXConnectPairs() (map[uint32]*vppcalls.XConnectDetails, error) { 196 // map for the resulting xconnect pairs 197 xpairs := make(map[uint32]*vppcalls.XConnectDetails) 198 reqCtx := h.callsChannel.SendMultiRequest(&vpp_l2.L2XconnectDump{}) 199 for { 200 pairs := &vpp_l2.L2XconnectDetails{} 201 stop, err := reqCtx.ReceiveReply(pairs) 202 if stop { 203 break 204 } 205 if err != nil { 206 return nil, err 207 } 208 209 // Find interface names 210 rxIfaceName, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(pairs.RxSwIfIndex)) 211 if !exists { 212 h.log.Warnf("XConnect dump: rx interface name for index %d not found", pairs.RxSwIfIndex) 213 continue 214 } 215 txIfaceName, _, exists := h.ifIndexes.LookupBySwIfIndex(uint32(pairs.TxSwIfIndex)) 216 if !exists { 217 h.log.Warnf("XConnect dump: tx interface name for index %d not found", pairs.TxSwIfIndex) 218 continue 219 } 220 221 xpairs[uint32(pairs.RxSwIfIndex)] = &vppcalls.XConnectDetails{ 222 Xc: &l2.XConnectPair{ 223 ReceiveInterface: rxIfaceName, 224 TransmitInterface: txIfaceName, 225 }, 226 Meta: &vppcalls.XcMeta{ 227 ReceiveInterfaceSwIfIdx: uint32(pairs.RxSwIfIndex), 228 TransmitInterfaceSwIfIdx: uint32(pairs.TxSwIfIndex), 229 }, 230 } 231 } 232 return xpairs, nil 233 } 234 235 func parseAddressToString(address ip_types.Address) string { 236 var nhIP net.IP = make([]byte, 16) 237 copy(nhIP[:], address.Un.XXX_UnionData[:]) 238 if address.Af == ip_types.ADDRESS_IP4 { 239 return nhIP[:4].To4().String() 240 } 241 if address.Af == ip_types.ADDRESS_IP6 { 242 return nhIP.To16().String() 243 } 244 return "" 245 }