go.ligato.io/vpp-agent/v3@v3.5.0/plugins/vpp/ifplugin/publish_state.go (about) 1 package ifplugin 2 3 import ( 4 "strings" 5 6 "github.com/pkg/errors" 7 "go.ligato.io/cn-infra/v2/datasync" 8 "go.ligato.io/cn-infra/v2/health/statuscheck" 9 "go.ligato.io/cn-infra/v2/health/statuscheck/model/status" 10 11 "go.ligato.io/vpp-agent/v3/proto/ligato/vpp" 12 interfaces "go.ligato.io/vpp-agent/v3/proto/ligato/vpp/interfaces" 13 ) 14 15 // watchStatusEvents watches for resync event of interface state data. 16 func (p *IfPlugin) watchStatusEvents() { 17 defer p.wg.Done() 18 p.Log.Debug("Start watching interface state events") 19 20 for { 21 select { 22 case e := <-p.resyncStatusChan: 23 p.onStatusResyncEvent(e) 24 25 case <-p.ctx.Done(): 26 p.Log.Debug("Stop watching interface state events") 27 return 28 } 29 } 30 } 31 32 // onStatusResyncEvent is triggered during resync of interface state data 33 func (p *IfPlugin) onStatusResyncEvent(e datasync.ResyncEvent) { 34 p.Log.Debugf("received status resync event (%d prefixes)", len(e.GetValues())) 35 36 var wasError error 37 for prefix, vals := range e.GetValues() { 38 var keys []string 39 for { 40 x, stop := vals.GetNext() 41 if stop { 42 break 43 } 44 keys = append(keys, x.GetKey()) 45 } 46 if len(keys) > 0 { 47 p.Log.Debugf("- %q (%v items)", prefix, len(keys)) 48 err := p.resyncIfStateEvents(keys) 49 if err != nil { 50 wasError = err 51 } 52 } else { 53 p.Log.Debugf("- %q (no items)", prefix) 54 } 55 } 56 e.Done(wasError) 57 } 58 59 // resyncIfStateEvents deletes obsolete operation status of network interfaces in DB. 60 func (p *IfPlugin) resyncIfStateEvents(keys []string) error { 61 p.publishLock.Lock() 62 defer p.publishLock.Unlock() 63 64 p.Log.Debugf("resync interface state events with %d keys", len(keys)) 65 66 for _, key := range keys { 67 ifaceName := strings.TrimPrefix(key, interfaces.StatePrefix) 68 if ifaceName == key { 69 continue 70 } 71 72 _, found := p.intfIndex.LookupByName(ifaceName) 73 if !found { 74 err := p.PublishStatistics.Put(key, nil /*means delete*/) 75 if err != nil { 76 return errors.WithMessagef(err, "publish statistic for key %s failed", key) 77 } 78 p.Log.Debugf("Obsolete interface status for %v deleted", key) 79 } else { 80 p.Log.WithField("ifaceName", ifaceName).Debug("interface status is needed") 81 } 82 } 83 84 return nil 85 } 86 87 // publishIfStateEvents goroutine is used to watch interface state notifications 88 // that are propagated to Messaging topic. 89 func (p *IfPlugin) publishIfStateEvents() { 90 defer p.wg.Done() 91 92 // store last errors to prevent repeating 93 var lastPublishErr error 94 var lastNotifErr error 95 96 for { 97 select { 98 case ifState := <-p.ifStateChan: 99 p.publishLock.Lock() 100 key := interfaces.InterfaceStateKey(ifState.State.Name) 101 102 if debugIfStates { 103 p.Log.Debugf("Publishing interface state: %+v", ifState) 104 } 105 106 if p.PublishStatistics != nil { 107 err := p.PublishStatistics.Put(key, ifState.State) 108 if err != nil { 109 if lastPublishErr == nil || lastPublishErr.Error() != err.Error() { 110 p.Log.Error(err) 111 } 112 } 113 lastPublishErr = err 114 } 115 116 // Note: state change is sometimes delivered as an unknown notification 117 stateChange := ifState.Type == interfaces.InterfaceNotification_UPDOWN || 118 ifState.Type == interfaces.InterfaceNotification_UNKNOWN 119 120 // Marshall data into JSON & send kafka message. 121 if p.NotifyStates != nil && stateChange { 122 err := p.NotifyStates.Put(key, ifState.State) 123 if err != nil { 124 if lastNotifErr == nil || lastNotifErr.Error() != err.Error() { 125 p.Log.Error(err) 126 } 127 } 128 lastNotifErr = err 129 } 130 131 // Send interface state data to global agent status 132 if p.statusCheckReg && ifState.State.InternalName != "" { 133 p.StatusCheck.ReportStateChangeWithMeta(p.PluginName, statuscheck.OK, nil, &status.InterfaceStats_Interface{ 134 InternalName: ifState.State.InternalName, 135 Index: ifState.State.IfIndex, 136 Status: ifState.State.AdminStatus.String(), 137 MacAddress: ifState.State.PhysAddress, 138 }) 139 } 140 141 if stateChange || ifState.State.OperStatus == interfaces.InterfaceState_DELETED { 142 if debugIfStates { 143 p.Log.Debugf("Updating link state: %+v", ifState) 144 } 145 p.linkStateDescriptor.UpdateLinkState(ifState) 146 if p.PushNotification != nil { 147 p.PushNotification(&vpp.Notification{ 148 Interface: ifState, 149 }) 150 } 151 } 152 153 p.publishLock.Unlock() 154 155 case <-p.ctx.Done(): 156 // Stop watching for state data updates. 157 return 158 } 159 } 160 }