diff --git a/pkg/agent/multicast/mcast_route.go b/pkg/agent/multicast/mcast_route.go index 279c11c4f19..d45d9ff5370 100644 --- a/pkg/agent/multicast/mcast_route.go +++ b/pkg/agent/multicast/mcast_route.go @@ -38,6 +38,7 @@ func newRouteClient(nodeconfig *config.NodeConfig, groupCache cache.Indexer, mul nodeConfig: nodeconfig, groupCache: groupCache, inboundRouteCache: cache.NewIndexer(getMulticastInboundEntryKey, cache.Indexers{GroupNameIndexName: inboundGroupIndexFunc}), + outboundRouteCache: cache.NewIndexer(getMulticastOutboundEntryKey, cache.Indexers{}), multicastInterfaces: multicastInterfaces.List(), socket: multicastSocket, } @@ -72,6 +73,7 @@ type MRouteClient struct { nodeConfig *config.NodeConfig multicastInterfaces []string inboundRouteCache cache.Indexer + outboundRouteCache cache.Indexer groupCache cache.Indexer socket RouteInterface multicastInterfaceConfigs []multicastInterfaceConfig @@ -165,6 +167,11 @@ func (c *MRouteClient) addOutboundMrouteEntry(src net.IP, group net.IP) (err err if err != nil { return err } + routeEntry := &outboundMulticastRouteEntry{ + group: group.String(), + src: src.String(), + } + c.outboundRouteCache.Add(routeEntry) return nil } @@ -200,11 +207,32 @@ type inboundMulticastRouteEntry struct { vif uint16 } +// outboundMulticastRouteEntry encodes the outbound multicast routing entry. +// For example, +// type inboundMulticastRouteEntry struct { +// group "226.94.9.9" +// src "10.0.0.55" +// vifs vifs of wlan0, ens220 +// } encodes the multicast route entry from Antrea gateway to multicast interfaces +// (10.0.0.55,226.94.9.9) Iif: antrea-gw0 Oifs: wlan0, ens220. +// The iif is always Antrea gateway and oifs are always outbound interfaces +// so we do not put them in the struct. +type outboundMulticastRouteEntry struct { + group string + src string + pktCount uint32 +} + func getMulticastInboundEntryKey(obj interface{}) (string, error) { entry := obj.(*inboundMulticastRouteEntry) return entry.group + "/" + entry.src + "/" + fmt.Sprint(entry.vif), nil } +func getMulticastOutboundEntryKey(obj interface{}) (string, error) { + entry := obj.(*outboundMulticastRouteEntry) + return entry.group + "/" + entry.src, nil +} + func inboundGroupIndexFunc(obj interface{}) ([]string, error) { entry, ok := obj.(*inboundMulticastRouteEntry) if !ok { diff --git a/pkg/agent/multicast/mcast_route_linux.go b/pkg/agent/multicast/mcast_route_linux.go index 9495a007647..4f475911b44 100644 --- a/pkg/agent/multicast/mcast_route_linux.go +++ b/pkg/agent/multicast/mcast_route_linux.go @@ -21,9 +21,12 @@ import ( "fmt" "net" "syscall" + "time" + "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" + multicastsyscall "antrea.io/antrea/pkg/agent/util/syscall" "antrea.io/antrea/pkg/util/runtime" ) @@ -71,6 +74,8 @@ func (c *MRouteClient) run(stopCh <-chan struct{}) { } }() + go wait.NonSlidingUntil(c.testMrouteStats, time.Second, stopCh) + for i := 0; i < int(workerCount); i++ { go c.worker(stopCh) } @@ -78,3 +83,26 @@ func (c *MRouteClient) run(stopCh <-chan struct{}) { c.socket.FlushMRoute() syscall.Close(c.socket.GetFD()) } + +func (c *MRouteClient) testMrouteStats() { + klog.Infof("testing mroute stats") + for _, route := range c.outboundRouteCache.List() { + entry := route.(*outboundMulticastRouteEntry) + srcIP := net.ParseIP(entry.src).To4() + groupIP := net.ParseIP(entry.group).To4() + pktCount := entry.pktCount + sioqSgReq := multicastsyscall.SiocSgReq{ + Src: [4]byte{srcIP[0], srcIP[1], srcIP[2], srcIP[3]}, + Grp: [4]byte{groupIP[0], groupIP[1], groupIP[2], groupIP[3]}, + } + value, err := multicastsyscall.IoctlGetiocSgReq(c.socket.GetFD(), &sioqSgReq) + if err != nil { + klog.Infof(err.Error()) + return + } + klog.Infof("Current mroute stats is %+v, send %d packet in last second", value, value.Pktcnt-pktCount) + entry.pktCount = value.Pktcnt + c.outboundRouteCache.Update(entry) + } + return +} diff --git a/pkg/agent/util/syscall/syscall_unix.go b/pkg/agent/util/syscall/syscall_unix.go index 6a1a494f9cd..7a1a86cc8e3 100644 --- a/pkg/agent/util/syscall/syscall_unix.go +++ b/pkg/agent/util/syscall/syscall_unix.go @@ -19,6 +19,7 @@ package syscall import ( + "runtime" "syscall" "unsafe" ) @@ -34,6 +35,14 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) return } +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + return e1 + } + return +} + // Please add your wrapped syscall functions below func SetsockoptMfcctl(fd, level, opt int, mfcctl *Mfcctl) error { @@ -43,3 +52,9 @@ func SetsockoptMfcctl(fd, level, opt int, mfcctl *Mfcctl) error { func SetsockoptVifctl(fd, level, opt int, vifctl *Vifctl) error { return setsockopt(fd, level, opt, unsafe.Pointer(vifctl), SizeofVifctl) } + +func IoctlGetiocSgReq(fd int, value *SiocSgReq) (*SiocSgReq, error) { + err := ioctl(fd, SIOCGETSGCNT, uintptr(unsafe.Pointer(value))) + runtime.KeepAlive(value) + return value, err +} diff --git a/pkg/agent/util/syscall/ztypes_linux.go b/pkg/agent/util/syscall/ztypes_linux.go index 2d064ccfe3c..db6525ad044 100644 --- a/pkg/agent/util/syscall/ztypes_linux.go +++ b/pkg/agent/util/syscall/ztypes_linux.go @@ -51,3 +51,17 @@ type Vifctl struct { const SizeofMfcctl = 0x3c const SizeofVifctl = 0x10 const SizeofIgmpmsg = 0x14 + +const ( + SIOCGETSGCNT = 0x89e1 +) + +type SiocSgReq = struct { + Src [4]byte /* in_addr */ + Grp [4]byte /* in_addr */ + Pktcnt uint32 + Bytecnt uint32 + If uint32 +} + +const SizeofSiocSgReq = 0x20