/** * Init all network transports * * @param netPath * @param rtOpts * @param ptpClock * * @return TRUE if successful */ Boolean netInit(NetPath * netPath, RunTimeOpts * rtOpts, PtpClock * ptpClock) { int temp; struct sockaddr_in addr; #ifdef PTPD_PCAP struct bpf_program program; char errbuf[PCAP_ERRBUF_SIZE]; #endif DBG("netInit\n"); #ifdef PTPD_PCAP netPath->pcapEvent = NULL; netPath->pcapGeneral = NULL; netPath->pcapEventSock = -1; netPath->pcapGeneralSock = -1; #endif netPath->generalSock = -1; netPath->eventSock = -1; #ifdef PTPD_PCAP if (rtOpts->transport == IEEE_802_3) { netPath->headerOffset = PACKET_BEGIN_ETHER; #ifdef HAVE_STRUCT_ETHER_ADDR_OCTET memcpy(netPath->etherDest.octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN); memcpy(netPath->peerEtherDest.octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN); #else memcpy(netPath->etherDest.ether_addr_octet, ether_aton(PTP_ETHER_DST), ETHER_ADDR_LEN); memcpy(netPath->peerEtherDest.ether_addr_octet, ether_aton(PTP_ETHER_PEER), ETHER_ADDR_LEN); #endif /* HAVE_STRUCT_ETHER_ADDR_OCTET */ } else #endif netPath->headerOffset = PACKET_BEGIN_UDP; /* open sockets */ if ((netPath->eventSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0 || (netPath->generalSock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { PERROR("failed to initialize sockets"); return FALSE; } if(!testInterface(rtOpts->ifaceName, rtOpts)) return FALSE; netPath->interfaceInfo.addressFamily = AF_INET; /* the if is here only to get rid of an unused result warning. */ if( getInterfaceInfo(rtOpts->ifaceName, &netPath->interfaceInfo)!= 1) return FALSE; /* No HW address, we'll use the protocol address to form interfaceID -> clockID */ if( !netPath->interfaceInfo.hasHwAddress && netPath->interfaceInfo.hasAfAddress ) { uint32_t addr = netPath->interfaceInfo.afAddress.s_addr; memcpy(netPath->interfaceID, &addr, 2); memcpy(netPath->interfaceID + 4, &addr + 2, 2); /* Initialise interfaceID with hardware address */ } else { memcpy(&netPath->interfaceID, &netPath->interfaceInfo.hwAddress, sizeof(netPath->interfaceID) <= sizeof(netPath->interfaceInfo.hwAddress) ? sizeof(netPath->interfaceID) : sizeof(netPath->interfaceInfo.hwAddress) ); } DBG("Listening on IP: %s\n",inet_ntoa(netPath->interfaceInfo.afAddress)); #ifdef PTPD_PCAP if (rtOpts->pcap == TRUE) { int promisc = (rtOpts->transport == IEEE_802_3 ) ? 1 : 0; if ((netPath->pcapEvent = pcap_open_live(rtOpts->ifaceName, PACKET_SIZE, promisc, PCAP_TIMEOUT, errbuf)) == NULL) { PERROR("failed to open event pcap"); return FALSE; } if (pcap_compile(netPath->pcapEvent, &program, ( rtOpts->transport == IEEE_802_3 ) ? "ether proto 0x88f7": ( rtOpts->ip_mode != IPMODE_MULTICAST ) ? "udp port 319" : "host (224.0.1.129 or 224.0.0.107) and udp port 319" , 1, 0) < 0) { PERROR("failed to compile pcap event filter"); pcap_perror(netPath->pcapEvent, "ptpd2"); return FALSE; } if (pcap_setfilter(netPath->pcapEvent, &program) < 0) { PERROR("failed to set pcap event filter"); return FALSE; } pcap_freecode(&program); if ((netPath->pcapEventSock = pcap_get_selectable_fd(netPath->pcapEvent)) < 0) { PERROR("failed to get pcap event fd"); return FALSE; } if ((netPath->pcapGeneral = pcap_open_live(rtOpts->ifaceName, PACKET_SIZE, promisc, PCAP_TIMEOUT, errbuf)) == NULL) { PERROR("failed to open general pcap"); return FALSE; } if (rtOpts->transport != IEEE_802_3) { if (pcap_compile(netPath->pcapGeneral, &program, ( rtOpts->ip_mode != IPMODE_MULTICAST ) ? "udp port 320" : "host (224.0.1.129 or 224.0.0.107) and udp port 320" , 1, 0) < 0) { PERROR("failed to compile pcap general filter"); pcap_perror(netPath->pcapGeneral, "ptpd2"); return FALSE; } if (pcap_setfilter(netPath->pcapGeneral, &program) < 0) { PERROR("failed to set pcap general filter"); return FALSE; } pcap_freecode(&program); if ((netPath->pcapGeneralSock = pcap_get_selectable_fd(netPath->pcapGeneral)) < 0) { PERROR("failed to get pcap general fd"); return FALSE; } } } #endif #ifdef PTPD_PCAP if(rtOpts->transport == IEEE_802_3) { close(netPath->eventSock); netPath->eventSock = -1; close(netPath->generalSock); netPath->generalSock = -1; /* TX timestamp is not generated for PCAP mode and Ethernet transport */ #ifdef SO_TIMESTAMPING netPath->txTimestampFailure = TRUE; #endif /* SO_TIMESTAMPING */ } else { #endif /* save interface address for IGMP refresh */ netPath->interfaceAddr = netPath->interfaceInfo.afAddress; DBG("Local IP address used : %s \n", inet_ntoa(netPath->interfaceInfo.afAddress)); temp = 1; /* allow address reuse */ if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_REUSEADDR, &temp, sizeof(int)) < 0) { DBG("failed to set socket reuse\n"); } /* bind sockets */ /* * need INADDR_ANY to allow receipt of multi-cast and uni-cast * messages */ /* why??? */ if (rtOpts->pidAsClockId) { if (inet_pton(AF_INET, DEFAULT_PTP_DOMAIN_ADDRESS, &addr.sin_addr) < 0) { PERROR("failed to convert address"); return FALSE; } } else addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_family = AF_INET; addr.sin_port = htons(PTP_EVENT_PORT); if (bind(netPath->eventSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind event socket"); return FALSE; } addr.sin_port = htons(PTP_GENERAL_PORT); if (bind(netPath->generalSock, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { PERROR("failed to bind general socket"); return FALSE; } #ifdef USE_BINDTODEVICE #ifdef linux /* * The following code makes sure that the data is only * received on the specified interface. Without this option, * it's possible to receive PTP from another interface, and * confuse the protocol. Calling bind() with the IP address * of the device instead of INADDR_ANY does not work. * * More info: * http://developerweb.net/viewtopic.php?id=6471 * http://stackoverflow.com/questions/1207746/problems-with-so-bindtodevice-linux-socket-option */ if ( rtOpts->ip_mode != IPMODE_HYBRID ) if (setsockopt(netPath->eventSock, SOL_SOCKET, SO_BINDTODEVICE, rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0 || setsockopt(netPath->generalSock, SOL_SOCKET, SO_BINDTODEVICE, rtOpts->ifaceName, strlen(rtOpts->ifaceName)) < 0){ PERROR("failed to call SO_BINDTODEVICE on the interface"); return FALSE; } #endif #endif /* Set socket dscp */ if(rtOpts->dscpValue) { if (setsockopt(netPath->eventSock, IPPROTO_IP, IP_TOS, &rtOpts->dscpValue, sizeof(int)) < 0 || setsockopt(netPath->generalSock, IPPROTO_IP, IP_TOS, &rtOpts->dscpValue, sizeof(int)) < 0) { PERROR("Failed to set socket DSCP bits"); return FALSE; } } /* send a uni-cast address if specified (useful for testing) */ if(!hostLookup(rtOpts->unicastAddress, &netPath->unicastAddr)) { netPath->unicastAddr = 0; } if(rtOpts->ip_mode != IPMODE_UNICAST) { /* init UDP Multicast on both Default and Peer addresses */ if (!netInitMulticast(netPath, rtOpts)) return FALSE; /* set socket time-to-live */ if(!netSetMulticastTTL(netPath->eventSock,rtOpts->ttl) || !netSetMulticastTTL(netPath->generalSock,rtOpts->ttl)) return FALSE; /* start tracking TTL */ netPath->ttlEvent = rtOpts->ttl; netPath->ttlGeneral = rtOpts->ttl; } #ifdef SO_TIMESTAMPING /* Reset the failure indicator when (re)starting network */ netPath->txTimestampFailure = FALSE; /* for SO_TIMESTAMPING we're receiving transmitted packets via ERRQUEUE */ temp = 0; #else /* enable loopback */ temp = 1; #endif /* make timestamps available through recvmsg() */ if (!netInitTimestamping(netPath,rtOpts)) { ERROR("Failed to enable packet time stamping\n"); return FALSE; } #ifdef SO_TIMESTAMPING /* If we failed to initialise SO_TIMESTAMPING, enable mcast loopback */ if(netPath->txTimestampFailure) temp = 1; #endif if(!netSetMulticastLoopback(netPath, temp)) { return FALSE; } #ifdef PTPD_PCAP } #endif /* Compile ACLs */ if(rtOpts->timingAclEnabled) { freeIpv4AccessList(&netPath->timingAcl); netPath->timingAcl=createIpv4AccessList(rtOpts->timingAclPermitText, rtOpts->timingAclDenyText, rtOpts->timingAclOrder); } if(rtOpts->managementAclEnabled) { freeIpv4AccessList(&netPath->managementAcl); netPath->managementAcl=createIpv4AccessList(rtOpts->managementAclPermitText, rtOpts->managementAclDenyText, rtOpts->managementAclOrder); } return TRUE; }
void restartSubsystems(RunTimeOpts *rtOpts, PtpClock *ptpClock) { DBG("RestartSubsystems: %d\n",rtOpts->restartSubsystems); /* So far, PTP_INITIALIZING is required for both network and protocol restart */ if((rtOpts->restartSubsystems & PTPD_RESTART_PROTOCOL) || (rtOpts->restartSubsystems & PTPD_RESTART_NETWORK)) { if(rtOpts->restartSubsystems & PTPD_RESTART_NETWORK) { NOTIFY("Applying network configuration: going into PTP_INITIALIZING\n"); } /* These parameters have to be passed to ptpClock before re-init */ ptpClock->clockQuality.clockClass = rtOpts->clockQuality.clockClass; ptpClock->slaveOnly = rtOpts->slaveOnly; ptpClock->disabled = rtOpts->portDisabled; if(rtOpts->restartSubsystems & PTPD_RESTART_PROTOCOL) { INFO("Applying protocol configuration: going into %s\n", ptpClock->disabled ? "PTP_DISABLED" : "PTP_INITIALIZING"); } /* Move back to primary interface only during configuration changes. */ ptpClock->runningBackupInterface = FALSE; toState(ptpClock->disabled ? PTP_DISABLED : PTP_INITIALIZING, rtOpts, ptpClock); } else { /* Nothing happens here for now - SIGHUP handler does this anyway */ if(rtOpts->restartSubsystems & PTPD_UPDATE_DATASETS) { NOTIFY("Applying PTP engine configuration: updating datasets\n"); updateDatasets(ptpClock, rtOpts); }} /* Nothing happens here for now - SIGHUP handler does this anyway */ if(rtOpts->restartSubsystems & PTPD_RESTART_LOGGING) { NOTIFY("Applying logging configuration: restarting logging\n"); } if(rtOpts->restartSubsystems & PTPD_RESTART_ACLS) { NOTIFY("Applying access control list configuration\n"); /* re-compile ACLs */ freeIpv4AccessList(&ptpClock->netPath.timingAcl); freeIpv4AccessList(&ptpClock->netPath.managementAcl); if(rtOpts->timingAclEnabled) { ptpClock->netPath.timingAcl=createIpv4AccessList(rtOpts->timingAclPermitText, rtOpts->timingAclDenyText, rtOpts->timingAclOrder); } if(rtOpts->managementAclEnabled) { ptpClock->netPath.managementAcl=createIpv4AccessList(rtOpts->managementAclPermitText, rtOpts->managementAclDenyText, rtOpts->managementAclOrder); } } #ifdef PTPD_STATISTICS /* Reinitialising the outlier filter containers */ if(rtOpts->restartSubsystems & PTPD_RESTART_FILTERS) { NOTIFY("Applying filter configuration: re-initialising filters\n"); freeDoubleMovingStatFilter(&ptpClock->filterMS); freeDoubleMovingStatFilter(&ptpClock->filterSM); ptpClock->oFilterMS.shutdown(&ptpClock->oFilterMS); ptpClock->oFilterSM.shutdown(&ptpClock->oFilterSM); outlierFilterSetup(&ptpClock->oFilterMS); outlierFilterSetup(&ptpClock->oFilterSM); ptpClock->oFilterMS.init(&ptpClock->oFilterMS,&rtOpts->oFilterMSConfig, "delayMS"); ptpClock->oFilterSM.init(&ptpClock->oFilterSM,&rtOpts->oFilterSMConfig, "delaySM"); if(rtOpts->filterMSOpts.enabled) { ptpClock->filterMS = createDoubleMovingStatFilter(&rtOpts->filterMSOpts,"delayMS"); } if(rtOpts->filterSMOpts.enabled) { ptpClock->filterSM = createDoubleMovingStatFilter(&rtOpts->filterSMOpts, "delaySM"); } } #endif /* PTPD_STATISTICS */ ptpClock->timingService.reloadRequested = TRUE; if(rtOpts->restartSubsystems & PTPD_RESTART_NTPENGINE && timingDomain.serviceCount > 1) { ptpClock->ntpControl.timingService.shutdown(&ptpClock->ntpControl.timingService); } if((rtOpts->restartSubsystems & PTPD_RESTART_NTPENGINE) || (rtOpts->restartSubsystems & PTPD_RESTART_NTPCONFIG)) { ntpSetup(rtOpts, ptpClock); } if((rtOpts->restartSubsystems & PTPD_RESTART_NTPENGINE) && rtOpts->ntpOptions.enableEngine) { timingServiceSetup(&ptpClock->ntpControl.timingService); ptpClock->ntpControl.timingService.init(&ptpClock->ntpControl.timingService); } ptpClock->timingService.dataSet.priority1 = rtOpts->preferNTP; timingDomain.electionDelay = rtOpts->electionDelay; if(timingDomain.electionLeft > timingDomain.electionDelay) { timingDomain.electionLeft = timingDomain.electionDelay; } timingDomain.services[0]->holdTime = rtOpts->ntpOptions.failoverTimeout; if(timingDomain.services[0]->holdTimeLeft > timingDomain.services[0]->holdTime) { timingDomain.services[0]->holdTimeLeft = rtOpts->ntpOptions.failoverTimeout; } ptpClock->timingService.timeout = rtOpts->idleTimeout; /* Update PI servo parameters */ setupPIservo(&ptpClock->servo, rtOpts); /* Config changes don't require subsystem restarts - acknowledge it */ if(rtOpts->restartSubsystems == PTPD_RESTART_NONE) { NOTIFY("Applying configuration\n"); } if(rtOpts->restartSubsystems != -1) rtOpts->restartSubsystems = 0; }