code: func (sct *ServiceChangeTracker) serviceToServiceMap(service *v1.Service) ServiceMap {
  	if service == nil {
  		return nil
  	}
  	svcName := types.NamespacedName{Namespace: service.Namespace, Name: service.Name}
  	if utilproxy.ShouldSkipService(svcName, service) {
  		return nil
  	}
  
  	if len(service.Spec.ClusterIP) != 0 {
  		// Filter out the incorrect IP version case.
  		// If ClusterIP on service has incorrect IP version, service itself will be ignored.
  		if sct.isIPv6Mode != nil && utilnet.IsIPv6String(service.Spec.ClusterIP) != *sct.isIPv6Mode {
  			utilproxy.LogAndEmitIncorrectIPVersionEvent(sct.recorder, "clusterIP", service.Spec.ClusterIP, service.Namespace, service.Name, service.UID)
  			return nil
  		}
  	}
  
  	serviceMap := make(ServiceMap)
  	for i := range service.Spec.Ports {
  		servicePort := &service.Spec.Ports[i]
  		svcPortName := ServicePortName{NamespacedName: svcName, Port: servicePort.Name}
  		baseSvcInfo := sct.newBaseServiceInfo(servicePort, service)
  		if sct.makeServiceInfo != nil {
  			serviceMap[svcPortName] = sct.makeServiceInfo(servicePort, service, baseSvcInfo)
  		} else {
  			serviceMap[svcPortName] = baseSvcInfo
  		}
  	}
  	return serviceMap
  }
docs: // serviceToServiceMap translates a single Service object to a ServiceMap.
  //
  // NOTE: service object should NOT be modified.