go.ligato.io/vpp-agent/v3@v3.5.0/plugins/linux/ifplugin/descriptor/interface_veth.go (about) 1 // Copyright (c) 2018 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 descriptor 16 17 import ( 18 "fmt" 19 "hash/fnv" 20 21 "github.com/pkg/errors" 22 23 "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/linuxcalls" 24 25 "go.ligato.io/vpp-agent/v3/plugins/linux/ifplugin/ifaceidx" 26 nslinuxcalls "go.ligato.io/vpp-agent/v3/plugins/linux/nsplugin/linuxcalls" 27 interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/linux/interfaces" 28 ) 29 30 // createVETH creates a new VETH pair if neither of VETH-ends are configured, or just 31 // applies configuration to the unfinished VETH-end with a temporary host name. 32 func (d *InterfaceDescriptor) createVETH( 33 nsCtx nslinuxcalls.NamespaceMgmtCtx, key string, linuxIf *interfaces.Interface, 34 ) (md *ifaceidx.LinuxIfMetadata, err error) { 35 // determine host/logical/temporary interface names 36 hostName := getHostIfName(linuxIf) 37 peerName := linuxIf.GetVeth().GetPeerIfName() 38 tempHostName := getVethTemporaryHostName(linuxIf.GetName()) 39 tempPeerHostName := getVethTemporaryHostName(peerName) 40 41 // context 42 agentPrefix := d.serviceLabel.GetAgentPrefix() 43 44 // check if this VETH-end was already created by the other end 45 _, peerExists := d.intfIndex.LookupByName(peerName) 46 if !peerExists { 47 // delete obsolete/invalid unfinished VETH (ignore errors) 48 _ = d.ifHandler.DeleteInterface(tempHostName) 49 _ = d.ifHandler.DeleteInterface(tempPeerHostName) 50 51 // create a new VETH pair 52 err = d.ifHandler.AddVethInterfacePair(tempHostName, tempPeerHostName) 53 if err != nil { 54 return nil, errors.WithMessagef(err, "error adding veth interface pair %s, %s", tempHostName, tempPeerHostName) 55 } 56 57 // add alias to both VETH ends 58 err = d.ifHandler.SetInterfaceAlias(tempHostName, agentPrefix+linuxcalls.GetVethAlias(linuxIf.Name, peerName)) 59 if err != nil { 60 return nil, errors.WithMessagef(err, "error setting interface %s alias", tempHostName) 61 } 62 err = d.ifHandler.SetInterfaceAlias(tempPeerHostName, agentPrefix+linuxcalls.GetVethAlias(peerName, linuxIf.Name)) 63 if err != nil { 64 return nil, errors.WithMessagef(err, "error setting peer interface %s alias", tempPeerHostName) 65 } 66 } 67 68 // move the VETH-end to the right namespace 69 err = d.setInterfaceNamespace(nsCtx, tempHostName, linuxIf.Namespace) 70 if err != nil { 71 return nil, errors.WithMessagef(err, "error setting interface %s to namespace %v", tempHostName, linuxIf.Namespace) 72 } 73 74 // move to the namespace with the interface 75 revert, err := d.nsPlugin.SwitchToNamespace(nsCtx, linuxIf.Namespace) 76 if err != nil { 77 return nil, errors.WithMessagef(err, "error switching to namespace %v", linuxIf.Namespace) 78 } 79 defer revert() 80 81 // rename from the temporary host name to the requested host name 82 if err = d.ifHandler.RenameInterface(tempHostName, hostName); err != nil { 83 return nil, errors.WithMessagef(err, "error renaming %s to %s", tempHostName, hostName) 84 } 85 86 // build metadata 87 link, err := d.ifHandler.GetLinkByName(hostName) 88 if err != nil { 89 return nil, errors.WithMessagef(err, "error getting link %s", hostName) 90 } 91 92 return &ifaceidx.LinuxIfMetadata{ 93 Namespace: linuxIf.Namespace, 94 LinuxIfIndex: link.Attrs().Index, 95 }, nil 96 } 97 98 // deleteVETH either un-configures one VETH-end if the other end is still configured, or 99 // removes the entire VETH pair. 100 func (d *InterfaceDescriptor) deleteVETH(nsCtx nslinuxcalls.NamespaceMgmtCtx, key string, linuxIf *interfaces.Interface, metadata *ifaceidx.LinuxIfMetadata) error { 101 // determine host/logical/temporary interface names 102 hostName := getHostIfName(linuxIf) 103 peerName := linuxIf.GetVeth().GetPeerIfName() 104 tempHostName := getVethTemporaryHostName(linuxIf.Name) 105 tempPeerHostName := getVethTemporaryHostName(peerName) 106 107 // check if the other end is still configured 108 _, peerExists := d.intfIndex.LookupByName(peerName) 109 if peerExists { 110 // just un-configure this VETH-end, but do not delete the pair 111 112 // rename to the temporary host name 113 err := d.ifHandler.RenameInterface(hostName, tempHostName) 114 if err != nil { 115 d.log.Error(err) 116 return err 117 } 118 119 // move this VETH-end to the default namespace 120 err = d.setInterfaceNamespace(nsCtx, tempHostName, nil) 121 if err != nil { 122 d.log.Error(err) 123 return err 124 } 125 } else { 126 // remove the VETH pair completely now 127 err := d.ifHandler.DeleteInterface(hostName) 128 if err != nil { 129 d.log.Error(err) 130 return err 131 } 132 if tempPeerHostName != "" { 133 // peer should be automatically removed as well, but just in case... 134 _ = d.ifHandler.DeleteInterface(tempPeerHostName) // ignore errors 135 } 136 } 137 138 return nil 139 } 140 141 // getVethTemporaryHostName (deterministically) generates a temporary host name 142 // for a VETH interface. 143 func getVethTemporaryHostName(vethName string) string { 144 if vethName == "" { 145 return "" 146 } 147 return fmt.Sprintf("veth-%d", fnvHash(vethName)) 148 } 149 150 // fnvHash hashes string using fnv32a algorithm. 151 func fnvHash(s string) uint32 { 152 h := fnv.New32a() 153 h.Write([]byte(s)) 154 return h.Sum32() 155 }