/// <summary>
        /// Called by a connection when it has received an intact and complete message in wire-format.
        /// Parses the supplied byte-array to generate a typed message for processing.
        /// On return from this routine the connection is free to overwrite the buffer contents.
        /// /// </summary>
        /// <param name="conn">Connection (think TCP to specific network agent) on which message arrived.</param>
        /// <param name="buff">Buffer encoding the message.</param>
        /// <param name="offset">Offset to start of message in the supplied buffer.</param>
        /// <param name="length">Length of message encoding in supplied buffer</param>
        public void ReceiveMessage(Connection conn, MessageTypes messageType, byte[] buff, int offset, int length)
        {
            bool unblock = false;
            switch (messageType)
            {
                case MessageTypes.MessageTypeAck:
                    {
                        conn.MessageAck.InitFromNetBytes(buff, 0);
                        //Console.WriteLine("SendParallel rcv MessageAck({0},{1})", conn.MessageAck.SeqNo, conn.MessageAck.Result);
                        if (conn.MessageAck.Result != (uint)OktoResultCodes.OKTO_RESULT_SUCCESS)
                        {
                            string msg = String.Format("ACK err: conn {0} ResultCode {1} subytpe {2}",
                                conn.HostName, conn.MessageAck.Result, (MessageTypes)conn.MessageAck.SubType);
                            Console.WriteLine(msg);
                        }
                        MessageTypes AckSubType = (MessageTypes)conn.MessageAck.SubType;
                        unblock = DowndatePendingReplies(AckSubType, conn.MessageAck.SeqNo);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeStatsReplyDelta:
                    {
                        MessageStatsReplyDelta mStatsDelta = MessageStatsReplyDelta.CreateFromNetBytes(conn.receiveBuffer, 0, conn, this);
                        //Console.WriteLine("ReceiveRaw MessageStatsReplyDelta({0},{1})", mStatsDelta.SeqNo, mStatsDelta.Result);
                        ulong intervalUSecs = mStatsDelta.IntervalUSecs;

                        foreach (KeyValuePair<ushort, FlowStats> kvp in mStatsDelta.dictFlowStats)
                        {
                            RAP rap = conn.ListRap[kvp.Key];
                            FlowStats flowStats = kvp.Value;
                            rap.SetFlowStats(flowStats);
                        }
                        unblock = DowndatePendingReplies(messageType, mStatsDelta.SeqNo);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeNameToStringSidReply:
                    {
                        MessageVmNameToStringSidReply mNameToSidReply
                            = MessageVmNameToStringSidReply.CreateFromNetBytes(conn.receiveBuffer, 0);
                        string vmKey = conn.HostName + "." + mNameToSidReply.VmName;
                        lock (DictVmNameToSid)
                        {
                            if (!DictVmNameToSid.ContainsKey(vmKey))
                                DictVmNameToSid.Add(vmKey, mNameToSidReply.SidString);
                        }
                        unblock = DowndatePendingReplies(messageType, mNameToSidReply.SeqNo);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeAlert:
                    {
                        MessageAlert mAlert = MessageAlert.CreateFromNetBytes(conn.receiveBuffer, 0);
                        //Console.WriteLine("ReceiveMessage rx alert {0}", mAlert);
                        // Push message to the sequential work queue for upcall into Policy Module.
                        RcWorkItem rcWorkItem = new RcWorkItem(RcWorkItemType.Alert, mAlert, 0, conn);
                        RcWorkQueue.Enqueue(rcWorkItem);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeIoFlowStatsReply:
                    {
                        MessageIoFlowStatsReply mIoFlowStats =
                            MessageIoFlowStatsReply.CreateFromNetBytes(conn.receiveBuffer, 0);
                        foreach (IoFlowMessageParams stats in mIoFlowStats.ListParams)
                            conn.DictIoFlows[stats.FlowId].RapD.SetIoFlowStats(stats.ParameterString);
                        unblock = DowndatePendingReplies(messageType, mIoFlowStats.SeqNo);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeNameToStringSidBatchReply:
                    {
                        MessageVmNameToStringSidBatchReply mNameToSidReply
                            = MessageVmNameToStringSidBatchReply.CreateFromNetBytes(conn.receiveBuffer, 0);
                        lock (DictVmNameToSid)
                        {
                            foreach (KeyValuePair<string, string> kvp in mNameToSidReply.DictVmNameToSid)
                            {
                                string vmKey = MakeVmKey(conn.hostName, kvp.Key);
                                if (!DictVmNameToSid.ContainsKey(vmKey))
                                {
                                    Console.WriteLine("sidBatchReply adding ({0},{1}", vmKey, kvp.Value);
                                    DictVmNameToSid.Add(vmKey, kvp.Value);
                                }
                            }
                        }
                        unblock = DowndatePendingReplies(messageType, mNameToSidReply.SeqNo);
                        conn.BeginReceive();
                        break;
                    }

                default:
                    {
                        string msg = string.Format("SendParallel: unexpected message type {0}", messageType);
                        throw new ApplicationException(msg);
                    }
                //break;
            }
        }
        /// <summary>
        /// Called to initialize the list of RAPS.
        /// </summary>
        /// <param name="listEndpoints">List of (addr,NodeDetails) pairs typically ex ParseConfigFile().</param>
        /// <returns></returns>
        public List<RAP> InitListRap(List<Endpoint> listEndpoints)
        {
            ValidateState(RateControllerState.Init, "InitTrafficMatrix");

            if (listEndpoints.Count == 0)
                throw new ArgumentException("err: input cannot have zero length.");
            if (IsMatrixGenerated)
                throw new ApplicationException("err: InitListRap() can only be called once.");

            matrixDimension = listEndpoints.Count;

            //
            // Setup TCP connection to each network agent and then register with each network agent.
            // Each row in table represents a VM, so all entries in a row use the same network agent.
            //
            foreach (Endpoint ep in listEndpoints)
            {
                Connection conn;
                string serverName = ep.FilterServer;
                if (ep.IsOktofsH && !AgentNameToConn.TryGetValue(serverName, out conn))
                {
                    conn = new Connection(this, serverName, 0, AgentPort);
                    AgentNameToConn.Add(serverName, conn);
                    MessageRegister mRegister = new MessageRegister(++SeqNo, TenantId, AlertVec);
                    const MessageTypes replyType = MessageTypes.MessageTypeRegisterAck;
                    const int typeIndex = (int)replyType;
                    lock (LockPendingReplies[typeIndex])
                    {
                        // Registration messages actually sent sequentially, but using parallel paradigm.
                        // This because SendSequential will break if interleaved with alerts.
                        SendParallel(conn, mRegister.Serialize, replyType, mRegister.SeqNo);
                        conn.BeginReceive();
                        WaitForParallelReplies(replyType, Parameters.DEFAULT_MESSAGE_TIMEOUT_MS);
                    }
                }
            }
            foreach (Endpoint ep in listEndpoints)
            {
                Connection conn;
                string hyperVName = ep.HyperVserver;
                //
                // Connections to remote OktofsAgent socket apps.
                //
                if ((ep.IsOktofsC || ep.IsOktofsH) && !AgentNameToConn.TryGetValue(hyperVName, out conn))
                {
                    conn = new Connection(this, hyperVName, 0, AgentPort);
                    AgentNameToConn.Add(hyperVName, conn);
                    MessageRegister mRegister = new MessageRegister(++SeqNo, TenantId, AlertVec);
                    const MessageTypes replyType = MessageTypes.MessageTypeRegisterAck;
                    const int typeIndex = (int)replyType;
                    lock (LockPendingReplies[typeIndex])
                    {
                        // Registration messages actually sent sequentially, but using parallel paradigm.
                        // This because SendSequential will break if interleaved with alerts.
                        SendParallel(conn, mRegister.Serialize, replyType, mRegister.SeqNo);
                        conn.BeginReceive();
                        WaitForParallelReplies(replyType, Parameters.DEFAULT_MESSAGE_TIMEOUT_MS);
                    }
                }
                //
                // Connections to remote IoFlow socket apps.
                //
                if (ep.IsIoFlowD && !IoFlowNameToConn.TryGetValue(hyperVName, out conn))
                {
                    conn = new Connection(this, hyperVName, 0, Parameters.IOFLOWAGENT_TCP_PORT_NUMBER);
                    IoFlowNameToConn.Add(hyperVName, conn);
                    MessageRegister mRegister = new MessageRegister(++SeqNo, TenantId, AlertVec);
                    const MessageTypes replyType = MessageTypes.MessageTypeRegisterAck;
                    const int typeIndex = (int)replyType;
                    lock (LockPendingReplies[typeIndex])
                    {
                        // Registration messages actually sent sequentially, but using parallel paradigm.
                        // This because SendSequential will break if interleaved with alerts.
                        SendParallel(conn, mRegister.Serialize, replyType, mRegister.SeqNo);
                        conn.BeginReceive();
                        WaitForParallelReplies(replyType, Parameters.DEFAULT_MESSAGE_TIMEOUT_MS);
                    }
                }
            }

            //
            // NT account names in the config file need to be translated into SIDs.
            // This because SIDS in config files are too unfriendly and error-prone.
            // Names and SIDS from an untrusted NT domain are legit, e.g. VMs in a workgroup.
            // Such names cannot be resolved locally, so ask the Hyper-V server to do it for us.
            // If the Hyper-V server is unknown, e.g. H-only config., config must use valid SIDS.
            //

            //
            // Ask Hyper-V servers to translate VM names to SIDS in case VM in untrusted NT domain.
            //
            Dictionary<string, Connection> DictIoFlowVmLookup = new Dictionary<string, Connection>(); // Any not resolved by Oktofs agent.
            foreach (Endpoint nDtls in listEndpoints)
            {
                // Nothing to do if config file claims to know the correct string SID.
                if (nDtls.SidOrAccount.ToUpper().StartsWith("S-1-5-"))
                    continue;
                // Only attempt SID translation at Hyper-V servers i.e. at point C in stack.
                if (!nDtls.Tag.ToUpper().Contains("-VM-SHARE-VOL") &&
                    !nDtls.Tag.ToUpper().Contains("-VM-FILE-VOL") )
                    continue;
                // Maybe we already queried this SID with the given Hyper-V server.
                string VmKey = MakeVmKey(nDtls.HyperVserver, nDtls.SidOrAccount);
                if (DictVmNameToSid.ContainsKey(VmKey))
                {
                    nDtls.StringSid = DictVmNameToSid[VmKey];
                    continue;
                }
                // Ask remote Hyper-V server for the sid: our DC may not trust VMs NT domain (e.g. workgroup).
                Connection conn = null;
                if (AgentNameToConn.TryGetValue(nDtls.HyperVserver, out conn))
                {
                    MessageNameToStringSidQuery mQuerySid =
                        new MessageNameToStringSidQuery(++SeqNo, (uint)nDtls.SidOrAccount.Length, nDtls.SidOrAccount);
                    const MessageTypes replyType = MessageTypes.MessageTypeNameToStringSidReply;
                    const int typeIndex = (int)replyType;
                    lock (LockPendingReplies[typeIndex])
                    {
                        // For now (dbg) VmName to SID translation messages actually sent sequentially.
                        SendParallel(conn, mQuerySid.Serialize, replyType, mQuerySid.SeqNo);
                        WaitForParallelReplies(replyType, Parameters.DEFAULT_MESSAGE_TIMEOUT_MS);
                    }
                    // Fatal error if SidQuery failed to update DictVmNameToSid.
                    if (!DictVmNameToSid.ContainsKey(VmKey))
                        throw new ApplicationException(String.Format("Panic: failed to get SID for {0}", VmKey));
                    continue;
                }
                // If we are using IoFlowAgent but not an OktoFsAgent try the IoFlowagent for the sid.
                if (IoFlowNameToConn.TryGetValue(nDtls.HyperVserver, out conn))
                {
                    if (!DictIoFlowVmLookup.ContainsKey(nDtls.SidOrAccount)){
                        DictIoFlowVmLookup.Add(nDtls.SidOrAccount, conn);
                    }
                }
            }

            // Any unresolved Vm-to-sid lookups are attempted via IoFlow network agent in batches in parallel.
            if (DictIoFlowVmLookup.Count != 0)
            {
                const MessageTypes replyType = MessageTypes.MessageTypeNameToStringSidBatchReply;
                const int typeIndex = (int)replyType;

                lock (LockPendingReplies[typeIndex])
                {
                    foreach (Connection conn in IoFlowNameToConn.Values)
                    {
                        List<string> listVmNames = new List<string>();
                        foreach (KeyValuePair<string, Connection> kvp in DictIoFlowVmLookup)
                            if (kvp.Value == conn)
                                listVmNames.Add(kvp.Key);
                        MessageNameToStringSidBatchQuery bq =
                            new MessageNameToStringSidBatchQuery(++SeqNo, listVmNames);
                        SendParallel(conn, bq.Serialize, replyType, bq.SeqNo);
                    }
                    WaitForParallelReplies(replyType, Parameters.DEFAULT_MESSAGE_TIMEOUT_MS);
                } // lock
            }

            //
            // Set the SID for each RAP. Any trusted account names will be translated to SIDS at agent.
            //
            foreach (Endpoint nDtls in listEndpoints)
            {
                if (nDtls.SidOrAccount.ToUpper().StartsWith("S-1-5-"))
                    nDtls.StringSid = nDtls.SidOrAccount.ToUpper();
                else if (nDtls.Tag.ToUpper().Equals("H-HYPERV-VOL"))
                    nDtls.StringSid = nDtls.SidOrAccount.ToUpper();
                else
                    nDtls.StringSid = DictVmNameToSid[MakeVmKey(nDtls.HyperVserver, nDtls.SidOrAccount)];
            }

            //
            // Initialize RAPs and RAP lookup, and point Connections at each RAP.
            // More than one Connection may ref a RAP (e.g. Oktofs and IoFlow both).
            // Note RAPs not yet bound to flows.
            //
            ListRap = new List<RAP>();
            for (int i = 0; i < listEndpoints.Count; i++)
            {
                string locServername = listEndpoints[i].FilterServer;
                RAP rap = new RAP(listEndpoints[i], listEndpoints[i]);
                Connection conn = null;
                if (AgentNameToConn.TryGetValue(locServername, out conn))
                    conn.ListRap.Add(rap);
                if (IoFlowNameToConn.TryGetValue(locServername, out conn))
                    conn.ListRap.Add(rap);
                DictEpKeyToRap[listEndpoints[i].Key] = rap;
                ListRap.Add(rap);
            }

            Console.WriteLine("InitListRap made {0} RAPs", ListRap.Count);
            return ListRap;
        }
Beispiel #3
0
        /// <summary>
        /// Called by a connection when it has received an intact and complete message in wire-format.
        /// Parses the supplied byte-array to generate a typed message for processing.
        /// On return from this routine the connection is free to overwrite the buffer contents.
        /// /// </summary>
        /// <param name="conn">Connection (think TCP to specific network agent) on which message arrived.</param>
        /// <param name="buff">Buffer encoding the message.</param>
        /// <param name="offset">Offset to start of message in the supplied buffer.</param>
        /// <param name="length">Length of message encoding in supplied buffer</param>
        public void ReceiveMessage(Connection conn, MessageTypes messageType, byte[] buff, int offset, int length)
        {
            switch (messageType)
            {
                case MessageTypes.MessageTypeRegister:
                    {
                        MessageRegister msgRegister = MessageRegister.CreateFromNetBytes(buff, offset);
                        TenantId = msgRegister.TenantId;
                        client.CallbackMessageRegister(conn, msgRegister.TenantId, msgRegister.AlertVec);
                        MessageAck ack = new MessageAck(msgRegister.SeqNo,
                                                        MessageTypes.MessageTypeRegisterAck,
                                                        (uint)OktoResultCodes.OKTO_RESULT_SUCCESS);
                        SendSynchronous(conn, ack.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeIoFlowCreate:
                    {
                        MessageIoFlowCreate msgFlowc = MessageIoFlowCreate.CreateFromNetBytes(buff, offset);
                        lock (LockLocal)
                        {
                            foreach (IoFlowMessageParams flowc in msgFlowc.ListParams)
                            {
                                Console.WriteLine("Agent MessageIoFlowCreate({0},{1})", flowc.FlowId, flowc.ParameterString);
                                if (DictFlowCreateParams.ContainsKey(flowc.FlowId))
                                    throw new ArgumentOutOfRangeException(string.Format("Agent flowc dup FlowId {0}", flowc.FlowId));
                                DictFlowCreateParams.Add(flowc.FlowId, flowc);
                            }
                        }
                        MessageAck ack = new MessageAck(msgFlowc.SeqNo,
                                                        MessageTypes.MessageTypeIoFlowCreateAck,
                                                        (uint)OktoResultCodes.OKTO_RESULT_SUCCESS);
                        SendSynchronous(conn, ack.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeRapFsCreate:
                    {
                        MessageRapFsCreate msgRapc = MessageRapFsCreate.CreateFromNetBytes(buff, offset);

                        lock (LockLocal)
                        {
                            foreach (MsgRapArg rapc in msgRapc.ListMsgRapArg)
                            {
                                Console.WriteLine("Agent MessageRapFsCreate({0},{1},{2})", rapc.FlowId, rapc.stringSid, rapc.ShareOrVolume);
                                if (!DictFlowCreateParams.ContainsKey(rapc.FlowId))
                                    throw new ArgumentOutOfRangeException(string.Format("Agent rapc invalid FlowId {0}", rapc.FlowId));
                                if (DictRapCreateParams.ContainsKey(rapc.FlowId))
                                    throw new ArgumentOutOfRangeException(string.Format("Agent rapc dup FlowId {0}", rapc.FlowId));
                                if (!DictFlowCreateParams.ContainsKey(rapc.FlowId))
                                    throw new ArgumentOutOfRangeException(string.Format("Agent rapc unmatched FlowId {0}", rapc.FlowId));
                                DictRapCreateParams.Add(rapc.FlowId, rapc);
                            }
                        }
                        //
                        // Params look reasonable and FlowCreate and RapCreate match up.
                        // Now we can invite the client to create its IoFlows.
                        //
                        OktoResultCodes result = client.CallbackIoFlowCreate(DictFlowCreateParams, DictRapCreateParams);

                        MessageAck ack = new MessageAck(msgRapc.SeqNo,
                                                        MessageTypes.MessageTypeRapFsCreateAck,
                                                        (uint)result);
                        SendSynchronous(conn, ack.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeStatsZero:
                    {
                        MessageStatsZero msgZero = MessageStatsZero.CreateFromNetBytes(buff, offset);
                        OktoResultCodes result = client.CallbackMessageStatsZero();
                        MessageAck ack = new MessageAck(msgZero.SeqNo,
                                                        MessageTypes.MessageTypeStatsZeroAck,
                                                        (uint)result);
                        SendSynchronous(conn, ack.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeIoFlowUpdate:
                    {
                        MessageIoFlowUpdate msgFlowc = MessageIoFlowUpdate.CreateFromNetBytes(buff, offset);
                        lock (LockLocal)
                        {
                            foreach (IoFlowMessageParams flowu in msgFlowc.ListParams)
                                if (!DictFlowCreateParams.ContainsKey(flowu.FlowId))
                                    throw new ArgumentOutOfRangeException(string.Format("Agent flowu invalid FlowId {0}", flowu.FlowId));
                        }
                        OktoResultCodes result = client.CallbackMessageIoFlowUpdate(msgFlowc.ListParams);
                        MessageAck ack = new MessageAck(msgFlowc.SeqNo,
                                                        MessageTypes.MessageTypeIoFlowUpdateAck,
                                                        (uint)result);
                        SendSynchronous(conn, ack.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeTenantDelete:
                    {
                        MessageTenantDelete msgTend = MessageTenantDelete.CreateFromNetBytes(buff, offset);
                        OktoResultCodes result = client.CallbackMessageTenantDelete();
                        MessageAck ack = new MessageAck(msgTend.SeqNo,
                                                        MessageTypes.MessageTypeTenantDeleteAck,
                                                        (uint)result);
                        SendSynchronous(conn, ack.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeIoFlowStatsQuery:
                    {
                        MessageIoFlowStatsQuery msgStatsQ = MessageIoFlowStatsQuery.CreateFromNetBytes(buff, offset);
                        List<IoFlowMessageParams> listStats = client.CallbackMessageIoFlowStatsQuery();
                        lock (LockLocal)
                        {
                            foreach (IoFlowMessageParams stats in listStats)
                                if (!DictFlowCreateParams.ContainsKey(stats.FlowId))
                                    throw new ArgumentOutOfRangeException(string.Format("Stats reply invalid FlowId {0}", stats.FlowId));
                        }
                        MessageIoFlowStatsReply msgStatsReply = new MessageIoFlowStatsReply(msgStatsQ.SeqNo, listStats, TenantId);
                        SendSynchronous(conn, msgStatsReply.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                case MessageTypes.MessageTypeNameToStringSidBatchQuery:
                    {
                        MessageNameToStringSidBatchQuery msgSidBatchQuery =
                            MessageNameToStringSidBatchQuery.CreateFromNetBytes(buff, offset);
                        Dictionary<string, string> DictVmNameToSid = new Dictionary<string, string>();
                        System.Security.Principal.SecurityIdentifier sid = null;
                        foreach (string vmName in msgSidBatchQuery.ListVmNames)
                        {
                            //XXXET: following two lines are for account names of type europe\
                            sid = VmSID.GetVMnameSid(vmName);
                            if (sid == null)
                            {
                                try
                                {
                                    NTAccount ntaccount = new NTAccount(vmName);
                                    sid = (SecurityIdentifier)ntaccount.Translate(typeof(SecurityIdentifier));
                                }
                                catch (Exception e)
                                {
                                    Debug.Assert(0 == 1, e.Message);
                                }
                            }

                            Console.WriteLine("MessageTypeNameToStringSidBatchQuery: {0} sid {1}", vmName, sid.ToString());
                            DictVmNameToSid.Add(vmName, sid.ToString());
                        }
                        MessageVmNameToStringSidBatchReply msgSidReply =
                            new MessageVmNameToStringSidBatchReply(msgSidBatchQuery.SeqNo,
                                                                   (uint)OktoResultCodes.OKTO_RESULT_SUCCESS,
                                                                   DictVmNameToSid);
                        SendSynchronous(conn, msgSidReply.Serialize);
                        conn.BeginReceive();
                        break;
                    }

                default:
                    {
                        string msg = string.Format("ReceiveMessage: unexpected message type {0}", messageType);
                        throw new ApplicationException(msg);
                    }
            } // switch
        }