From bfc0e8d4c89a80317d93451bdeda1cf1e79f5279 Mon Sep 17 00:00:00 2001 From: "Srivats P." Date: Sun, 5 Oct 2008 17:07:33 +0000 Subject: [PATCH] Tcp/Udp checksums done. Frame Length Modes done. Data Pattern Modes done. Some minor fixes/enhancements in streamconfigdialog. Added a "Edit Stream" action in StreamList context menu --- client/portgroup.cpp | 1 + client/portstatsmodel.cpp | 2 +- client/portswindow.cpp | 51 ++++-- client/portswindow.h | 1 + client/portswindow.ui | 8 + client/stream.h | 6 +- client/streamconfigdialog.cpp | 196 ++++++++++++++++------ client/streamconfigdialog.h | 5 +- client/streamconfigdialog.ui | 81 ++++++---- common/protocol.proto | 10 +- server/myservice.cpp | 297 ++++++++++++++++++++++++---------- server/myservice.h | 12 +- 12 files changed, 478 insertions(+), 192 deletions(-) diff --git a/client/portgroup.cpp b/client/portgroup.cpp index 686b436..4630c72 100644 --- a/client/portgroup.cpp +++ b/client/portgroup.cpp @@ -159,6 +159,7 @@ void PortGroup::when_configApply(int portIndex, uint *cookie) case 3: qDebug("apply completed"); + mPorts[portIndex].when_syncComplete(); delete cookie; break; diff --git a/client/portstatsmodel.cpp b/client/portstatsmodel.cpp index b3fae30..d554687 100644 --- a/client/portstatsmodel.cpp +++ b/client/portstatsmodel.cpp @@ -12,7 +12,7 @@ PortStatsModel::PortStatsModel(PortGroupList *p, QObject *parent) timer = new QTimer(); connect(timer, SIGNAL(timeout()), this, SLOT(updateStats())); - timer->start(5000); + timer->start(2000); } int PortStatsModel::rowCount(const QModelIndex &parent) const diff --git a/client/portswindow.cpp b/client/portswindow.cpp index 645bd1b..27dec05 100644 --- a/client/portswindow.cpp +++ b/client/portswindow.cpp @@ -23,6 +23,7 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) tvPortList->addAction(actionDisconnect_Port_Group); tvStreamList->addAction(actionNew_Stream); + tvStreamList->addAction(actionEdit_Stream); tvStreamList->addAction(actionDelete_Stream); tvStreamList->setModel(plm->getStreamModel()); @@ -32,10 +33,12 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(when_portModel_dataChanged(const QModelIndex&, const QModelIndex&))); + connect( tvPortList->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(when_portView_currentChanged(const QModelIndex&, const QModelIndex&))); + connect( tvStreamList->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(when_streamView_currentChanged(const QModelIndex&, @@ -43,13 +46,16 @@ PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent) connect( tvStreamList->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(when_streamView_selectionChanged())); + +#if 0 connect( tvPortList->selectionModel(), SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), plm->getStreamModel(), SLOT(setCurrentPortIndex(const QModelIndex&))); +#endif - // Initially we don't have any ports - so trigger selection of - // portgroup detail page + // Initially we don't have any ports/streams - so send signal triggers when_portView_currentChanged(QModelIndex(), QModelIndex()); + when_streamView_currentChanged(QModelIndex(), QModelIndex()); } PortsWindow::~PortsWindow() @@ -66,11 +72,6 @@ void PortsWindow::on_tvStreamList_activated(const QModelIndex & index) qDebug("%s: invalid index", __FUNCTION__); return; } -#if 0 // CleanedUp! - // FIXME(MED): This way of passing params must be changed - scd = new StreamConfigDialog(plm->getStreamModel()->currentPortStreamList(), - (uint) index.row(), this); -#endif scd = new StreamConfigDialog(plm->port(tvPortList->currentIndex()), index.row(), this); qDebug("stream list activated\n"); @@ -81,7 +82,9 @@ void PortsWindow::on_tvStreamList_activated(const QModelIndex & index) void PortsWindow::when_portView_currentChanged(const QModelIndex& current, const QModelIndex& previous) { + plm->getStreamModel()->setCurrentPortIndex(current); updatePortViewActions(current); + updateStreamViewActions(); if (!current.isValid()) { @@ -143,16 +146,32 @@ void PortsWindow::updateStreamViewActions(const QModelIndex& current) void PortsWindow::updateStreamViewActions() { - if (tvStreamList->selectionModel()->hasSelection()) + // For some reason hasSelection() returns true even if selection size is 0 + // so additional check for size introduced + if (tvStreamList->selectionModel()->hasSelection() && + (tvStreamList->selectionModel()->selection().size() > 0)) { qDebug("Has selection %d", tvStreamList->selectionModel()->selection().size()); - // If more than one non-contiguous ranges selected, disable "New" + + // If more than one non-contiguous ranges selected, + // disable "New" and "Edit" if (tvStreamList->selectionModel()->selection().size() > 1) + { actionNew_Stream->setDisabled(true); + actionEdit_Stream->setDisabled(true); + } else + { actionNew_Stream->setEnabled(true); + // Enable "Edit" only if the single range has a single row + if (tvStreamList->selectionModel()->selection().at(0).height() > 1) + actionEdit_Stream->setDisabled(true); + else + actionEdit_Stream->setEnabled(true); + } + // Delete is always enabled as long as we have a selection actionDelete_Stream->setEnabled(true); } @@ -160,6 +179,7 @@ void PortsWindow::updateStreamViewActions() { qDebug("No selection"); actionNew_Stream->setEnabled(true); + actionEdit_Stream->setDisabled(true); actionDelete_Stream->setDisabled(true); } } @@ -346,6 +366,19 @@ void PortsWindow::on_actionNew_Stream_triggered() plm->getStreamModel()->insertRows(row, count); } +void PortsWindow::on_actionEdit_Stream_triggered() +{ + qDebug("Edit Stream Action"); + + // Ensure we have only one range selected which contains only one row + if ((tvStreamList->selectionModel()->selection().size() == 1) && + (tvStreamList->selectionModel()->selection().at(0).height() == 1)) + { + on_tvStreamList_activated(tvStreamList->selectionModel()-> + selection().at(0).topLeft()); + } +} + void PortsWindow::on_actionDelete_Stream_triggered() { qDebug("Delete Stream Action"); diff --git a/client/portswindow.h b/client/portswindow.h index 2a26c2b..a5bc562 100644 --- a/client/portswindow.h +++ b/client/portswindow.h @@ -49,6 +49,7 @@ private slots: void on_actionDisconnect_Port_Group_triggered(); void on_actionNew_Stream_triggered(); + void on_actionEdit_Stream_triggered(); void on_actionDelete_Stream_triggered(); }; diff --git a/client/portswindow.ui b/client/portswindow.ui index 04349d2..99a32af 100644 --- a/client/portswindow.ui +++ b/client/portswindow.ui @@ -206,6 +206,14 @@ Delete Stream + + + :/icons/stream_edit.png + + + Edit Stream + + diff --git a/client/stream.h b/client/stream.h index 42f74ff..6e41702 100644 --- a/client/stream.h +++ b/client/stream.h @@ -883,9 +883,9 @@ public: }; enum DataPatternMode { - e_dp_fixed, - e_dp_inc, - e_dp_dec, + e_dp_fixed_word, + e_dp_inc_byte, + e_dp_dec_byte, e_dp_random }; diff --git a/client/streamconfigdialog.cpp b/client/streamconfigdialog.cpp index cef9771..7ee59f7 100644 --- a/client/streamconfigdialog.cpp +++ b/client/streamconfigdialog.cpp @@ -12,6 +12,8 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, { setupUi(this); setupUiExtra(); + + // setupUi // Time to play match the signals and slots! connect(rbFtNone, SIGNAL(toggled(bool)), rbL3None, SLOT(setChecked(bool))); @@ -28,6 +30,11 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbFtNone, SIGNAL(toggled(bool)), lblType, SLOT(setHidden(bool))); connect(rbFtNone, SIGNAL(toggled(bool)), leType, SLOT(setHidden(bool))); + // Enable/Disable L3 Protocol Choices for FT None + connect(rbFtNone, SIGNAL(toggled(bool)), rbL3None, SLOT(setEnabled(bool))); + connect(rbFtNone, SIGNAL(toggled(bool)), rbL3Ipv4, SLOT(setDisabled(bool))); + connect(rbFtNone, SIGNAL(toggled(bool)), rbL3Arp, SLOT(setDisabled(bool))); + // Show/Hide FrameType related inputs for FT Ethernet2 connect(rbFtEthernet2, SIGNAL(toggled(bool)), lblDsap, SLOT(setHidden(bool))); connect(rbFtEthernet2, SIGNAL(toggled(bool)), leDsap, SLOT(setHidden(bool))); @@ -40,6 +47,11 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbFtEthernet2, SIGNAL(toggled(bool)), lblType, SLOT(setVisible(bool))); connect(rbFtEthernet2, SIGNAL(toggled(bool)), leType, SLOT(setVisible(bool))); + // Enable/Disable L3 Protocol Choices for FT Ethernet2 + connect(rbFtEthernet2, SIGNAL(toggled(bool)), rbL3None, SLOT(setEnabled(bool))); + connect(rbFtEthernet2, SIGNAL(toggled(bool)), rbL3Ipv4, SLOT(setEnabled(bool))); + connect(rbFtEthernet2, SIGNAL(toggled(bool)), rbL3Arp, SLOT(setEnabled(bool))); + // Show/Hide FrameType related inputs for FT 802.3 Raw connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), lblDsap, SLOT(setHidden(bool))); connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), leDsap, SLOT(setHidden(bool))); @@ -52,6 +64,14 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), lblType, SLOT(setHidden(bool))); connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), leType, SLOT(setHidden(bool))); + // Force L3 = None if FT = 802.3 Raw + connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), rbL3None, SLOT(setChecked(bool))); + + // Enable/Disable L3 Protocol Choices for FT 802Dot3Raw + connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), rbL3None, SLOT(setEnabled(bool))); + connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), rbL3Ipv4, SLOT(setDisabled(bool))); + connect(rbFt802Dot3Raw, SIGNAL(toggled(bool)), rbL3Arp, SLOT(setDisabled(bool))); + // Show/Hide FrameType related inputs for FT 802.3 LLC connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), lblDsap, SLOT(setVisible(bool))); connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), leDsap, SLOT(setVisible(bool))); @@ -64,6 +84,14 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), lblType, SLOT(setHidden(bool))); connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), leType, SLOT(setHidden(bool))); + // Force L3 = None if FT = 802.3 LLC (to ensure a valid L3 is selected) + connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), rbL3None, SLOT(setChecked(bool))); + + // Enable/Disable L3 Protocol Choices for FT 802Dot3Llc + connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), rbL3None, SLOT(setEnabled(bool))); + connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), rbL3Ipv4, SLOT(setEnabled(bool))); + connect(rbFt802Dot3Llc, SIGNAL(toggled(bool)), rbL3Arp, SLOT(setDisabled(bool))); + // Show/Hide FrameType related inputs for FT 802.3 LLC SNAP connect(rbFtLlcSnap, SIGNAL(toggled(bool)), lblDsap, SLOT(setVisible(bool))); connect(rbFtLlcSnap, SIGNAL(toggled(bool)), leDsap, SLOT(setVisible(bool))); @@ -76,6 +104,11 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbFtLlcSnap, SIGNAL(toggled(bool)), lblType, SLOT(setVisible(bool))); connect(rbFtLlcSnap, SIGNAL(toggled(bool)), leType, SLOT(setVisible(bool))); + // Enable/Disable L3 Protocol Choices for FT 802.3 LLC SNAP + connect(rbFtLlcSnap, SIGNAL(toggled(bool)), rbL3None, SLOT(setEnabled(bool))); + connect(rbFtLlcSnap, SIGNAL(toggled(bool)), rbL3Ipv4, SLOT(setEnabled(bool))); + connect(rbFtLlcSnap, SIGNAL(toggled(bool)), rbL3Arp, SLOT(setEnabled(bool))); + // Enable/Disable FrameType related inputs for FT 802.3 LLC SNAP connect(rbFtLlcSnap, SIGNAL(toggled(bool)), lblDsap, SLOT(setDisabled(bool))); connect(rbFtLlcSnap, SIGNAL(toggled(bool)), leDsap, SLOT(setDisabled(bool))); @@ -90,7 +123,6 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbL3None, SIGNAL(toggled(bool)), rbL4Igmp, SLOT(setDisabled(bool))); connect(rbL3None, SIGNAL(toggled(bool)), rbL4Tcp, SLOT(setDisabled(bool))); connect(rbL3None, SIGNAL(toggled(bool)), rbL4Udp, SLOT(setDisabled(bool))); - connect(rbL3None, SIGNAL(toggled(bool)), rbL4Other, SLOT(setDisabled(bool))); // Force L4 Protocol = None if L3 Protocol is set to None connect(rbL3None, SIGNAL(toggled(bool)), rbL4None, SLOT(setChecked(bool))); @@ -101,7 +133,6 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbL3Ipv4, SIGNAL(toggled(bool)), rbL4Igmp, SLOT(setEnabled(bool))); connect(rbL3Ipv4, SIGNAL(toggled(bool)), rbL4Tcp, SLOT(setEnabled(bool))); connect(rbL3Ipv4, SIGNAL(toggled(bool)), rbL4Udp, SLOT(setEnabled(bool))); - connect(rbL3Ipv4, SIGNAL(toggled(bool)), rbL4Other, SLOT(setEnabled(bool))); // Enable/Disable L4 Protocol Choices for L3 Protocol ARP connect(rbL3Arp, SIGNAL(toggled(bool)), rbL4None, SLOT(setEnabled(bool))); @@ -109,15 +140,20 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex, connect(rbL3Arp, SIGNAL(toggled(bool)), rbL4Igmp, SLOT(setDisabled(bool))); connect(rbL3Arp, SIGNAL(toggled(bool)), rbL4Tcp, SLOT(setDisabled(bool))); connect(rbL3Arp, SIGNAL(toggled(bool)), rbL4Udp, SLOT(setDisabled(bool))); - connect(rbL3Arp, SIGNAL(toggled(bool)), rbL4Other, SLOT(setDisabled(bool))); // Force L4 Protocol = None if L3 Protocol is set to ARP connect(rbL3Arp, SIGNAL(toggled(bool)), rbL4None, SLOT(setChecked(bool))); - // Init with FT=Eth2 to trigger signals; actual value will be - // initialized by LoadCurrentStream() + //TODO: remove if not needed +#if 0 + // This set of 'clicks' is a hack to trigger signals at dialog creation + // time so that a coherent 'set' is initialized + // Actual stream values will be initialized by LoadCurrentStream() + rbL3Ipv4->click(); + rbL3None->click(); rbFtEthernet2->click(); rbFtNone->click(); +#endif //mpStreamList = streamList; mCurrentStreamIndex = streamIndex; @@ -148,7 +184,21 @@ void StreamConfigDialog::setupUiExtra() QRegExp reHex4B("[0-9,a-f,A-F]{1,8}"); QRegExp reMac("([0-9,a-f,A-F]{2,2}[:-]){5,5}[0-9,a-f,A-F]{2,2}"); - // Setup default stuff that cannot be done in designer + // ---- Setup default stuff that cannot be done in designer ---- + + // Since the dialog defaults are FT = None, L3 = None, L4 = None; + // hide associated input fields since it can't be done in Designer + lblDsap->setHidden(true); + leDsap->setHidden(true); + lblSsap->setHidden(true); + leSsap->setHidden(true); + lblControl->setHidden(true); + leControl->setHidden(true); + lblOui->setHidden(true); + leOui->setHidden(true); + lblType->setHidden(true); + leType->setHidden(true); + twProto->setTabEnabled(2, FALSE); twProto->setTabEnabled(3, FALSE); @@ -189,17 +239,73 @@ StreamConfigDialog::~StreamConfigDialog() delete mpPacketModel; } +void StreamConfigDialog::on_cmbPatternMode_currentIndexChanged(QString mode) +{ + if (mode == "Fixed Word") + { + lePattern->setEnabled(true); + } + else if (mode == "Increment Byte") + { + lePattern->setDisabled(true); + } + else if (mode == "Decrement Byte") + { + lePattern->setDisabled(true); + } + if (mode == "Random") + { + lePattern->setDisabled(true); + } + else + { + qWarning("Unhandled/Unknown PatternMode = %s", mode.toAscii().data()); + } +} +void StreamConfigDialog::on_cmbPktLenMode_currentIndexChanged(QString mode) +{ + if (mode == "Fixed") + { + lePktLen->setEnabled(true); + lePktLenMin->setDisabled(true); + lePktLenMax->setDisabled(true); + } + else if (mode == "Increment") + { + lePktLen->setDisabled(true); + lePktLenMin->setEnabled(true); + lePktLenMax->setEnabled(true); + } + else if (mode == "Decrement") + { + lePktLen->setDisabled(true); + lePktLenMin->setEnabled(true); + lePktLenMax->setEnabled(true); + } + else if (mode == "Random") + { + lePktLen->setDisabled(true); + lePktLenMin->setEnabled(true); + lePktLenMax->setEnabled(true); + } + else + { + qWarning("Unhandled/Unknown PktLenMode = %s", mode.toAscii().data()); + } +} + + void StreamConfigDialog::on_cmbDstMacMode_currentIndexChanged(QString mode) { if (mode == "Fixed") { - leDstMacCount->setEnabled(FALSE); - leDstMacStep->setEnabled(FALSE); + leDstMacCount->setEnabled(false); + leDstMacStep->setEnabled(false); } else { - leDstMacCount->setEnabled(TRUE); - leDstMacStep->setEnabled(TRUE); + leDstMacCount->setEnabled(true); + leDstMacStep->setEnabled(true); } } @@ -207,13 +313,41 @@ void StreamConfigDialog::on_cmbSrcMacMode_currentIndexChanged(QString mode) { if (mode == "Fixed") { - leSrcMacCount->setEnabled(FALSE); - leSrcMacStep->setEnabled(FALSE); + leSrcMacCount->setEnabled(false); + leSrcMacStep->setEnabled(false); } else { - leSrcMacCount->setEnabled(TRUE); - leSrcMacStep->setEnabled(TRUE); + leSrcMacCount->setEnabled(true); + leSrcMacStep->setEnabled(true); + } +} + +void StreamConfigDialog::on_cmbIpSrcAddrMode_currentIndexChanged(QString mode) +{ + if (mode == "Fixed") + { + leIpSrcAddrCount->setDisabled(true); + leIpSrcAddrMask->setDisabled(true); + } + else + { + leIpSrcAddrCount->setEnabled(true); + leIpSrcAddrMask->setEnabled(true); + } +} + +void StreamConfigDialog::on_cmbIpDstAddrMode_currentIndexChanged(QString mode) +{ + if (mode == "Fixed") + { + leIpDstAddrCount->setDisabled(true); + leIpDstAddrMask->setDisabled(true); + } + else + { + leIpDstAddrCount->setEnabled(true); + leIpDstAddrMask->setEnabled(true); } } @@ -371,14 +505,6 @@ void StreamConfigDialog::on_rbL4Udp_toggled(bool checked) } } -void StreamConfigDialog::on_rbL4Other_toggled(bool checked) -{ - if (checked) - leIpProto->setEnabled(true); - else - leIpProto->setEnabled(false); -} - void StreamConfigDialog::update_NumPacketsAndNumBursts() { if (rbSendPackets->isChecked() && rbModeFixed->isChecked()) @@ -512,32 +638,6 @@ void StreamConfigDialog::LoadCurrentStream() qDebug("%s: unknown l4 Protocol %d", __FUNCTION__, pStream->l4Proto()); } -// PB (not needed anymore?) -#if 0 - // Check for specific supported protocols first ... - if (pStream->eth2()->type() == ETH_TYP_IP) - rbL3Ipv4->setChecked(TRUE); - else if (pStream->eth2()->type() == ETH_TYP_ARP) - rbL3Arp->setChecked(TRUE); - - // ... then for None/Other - rbL3None->setChecked((pStream->proto.protoMask & PM_L3_PROTO_NONE) > 0); - rbL3Other->setChecked((pStream->proto.protoMask & PM_L3_PROTO_OTHER) > 0); - - // Check for specific supported protocols first ... - if (pStream->proto.ipProto == IP_PROTO_ICMP) - rbL4Icmp->setChecked(TRUE); - else if (pStream->proto.ipProto == IP_PROTO_IGMP) - rbL4Igmp->setChecked(TRUE); - else if (pStream->proto.ipProto == IP_PROTO_TCP) - rbL4Tcp->setChecked(TRUE); - else if (pStream->proto.ipProto == IP_PROTO_UDP) - rbL4Udp->setChecked(TRUE); - - // ... then for None/Other - rbL4None->setChecked((pStream->proto.protoMask & PM_L4_PROTO_NONE) > 0); - rbL4Other->setChecked((pStream->proto.protoMask & PM_L4_PROTO_OTHER) > 0); -#endif } // L2 diff --git a/client/streamconfigdialog.h b/client/streamconfigdialog.h index f95205d..a8fe510 100644 --- a/client/streamconfigdialog.h +++ b/client/streamconfigdialog.h @@ -39,8 +39,12 @@ private: void StoreCurrentStream(); private slots: + void on_cmbPatternMode_currentIndexChanged(QString mode); + void on_cmbPktLenMode_currentIndexChanged(QString mode); void on_cmbDstMacMode_currentIndexChanged(QString mode); void on_cmbSrcMacMode_currentIndexChanged(QString mode); + void on_cmbIpSrcAddrMode_currentIndexChanged(QString mode); + void on_cmbIpDstAddrMode_currentIndexChanged(QString mode); void on_pbPrev_clicked(); void on_pbNext_clicked(); @@ -57,7 +61,6 @@ private slots: void on_rbL4Igmp_toggled(bool checked); void on_rbL4Tcp_toggled(bool checked); void on_rbL4Udp_toggled(bool checked); - void on_rbL4Other_toggled(bool checked); void update_NumPacketsAndNumBursts(); diff --git a/client/streamconfigdialog.ui b/client/streamconfigdialog.ui index f3ed791..b94e107 100644 --- a/client/streamconfigdialog.ui +++ b/client/streamconfigdialog.ui @@ -8,7 +8,7 @@ 0 0 - 554 + 534 521 @@ -63,17 +63,17 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - Fixed + Fixed Word - Increment + Increment Byte - Decrement + Decrement Byte @@ -141,6 +141,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + 64 @@ -174,6 +177,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + 64 @@ -373,6 +379,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + IPv4 @@ -383,18 +392,11 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - ARP - - - - - false - Other + ARP @@ -420,7 +422,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - true + false ICMP @@ -430,7 +432,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - true + false IGMP @@ -440,7 +442,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - true + false TCP @@ -449,21 +451,11 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - - true - - - UDP - - - - - false - Other + UDP @@ -483,6 +475,19 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -1054,7 +1059,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - + @@ -1130,7 +1135,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - + @@ -1206,6 +1211,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + @@ -1213,6 +1221,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + 255.255.255.255 @@ -1264,6 +1275,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + @@ -1271,6 +1285,9 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff + + false + 255.255.255.255 @@ -1279,7 +1296,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - + @@ -1310,14 +1327,14 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - + Qt::Vertical - 470 + 469 16 @@ -1355,7 +1372,7 @@ QLineEdit:enabled[inputMask = "HH HH HH HH HH HH; "] { background-color: #ccccff - 1 + 0 diff --git a/common/protocol.proto b/common/protocol.proto index fee57b9..04c7a70 100644 --- a/common/protocol.proto +++ b/common/protocol.proto @@ -169,9 +169,9 @@ message StreamCore { } enum DataPatternMode { - e_dp_fixed = 0; - e_dp_inc = 1; - e_dp_dec = 2; + e_dp_fixed_word = 0; + e_dp_inc_byte = 1; + e_dp_dec_byte = 2; e_dp_random = 3; } @@ -195,8 +195,8 @@ message StreamCore { // Frame Length (includes CRC) optional FrameLengthMode len_mode = 14 [default = e_fl_fixed]; optional uint32 frame_len = 15 [default = 64]; - optional uint32 frame_len_min = 16; - optional uint32 frame_len_max = 17; + optional uint32 frame_len_min = 16 [default = 64]; + optional uint32 frame_len_max = 17 [default = 1518]; // Currently Selected Protocols optional FrameType ft = 21 [default = e_ft_none]; diff --git a/server/myservice.cpp b/server/myservice.cpp index b21310d..3296a86 100644 --- a/server/myservice.cpp +++ b/server/myservice.cpp @@ -12,65 +12,105 @@ #define LOG(...) {sprintf(logStr, __VA_ARGS__); host->Log(logStr);} #define MB (1024*1024) -#if 0 -quint16 StreamInfo::ipv4Cksum(quint16 ipHdrLen, quint16 buff[]) +quint32 StreamInfo::pseudoHdrCksumPartial(quint32 srcIp, quint32 dstIp, + quint8 protocol, quint16 len) { - quint16 word16; - quint32 sum=0; - quint16 i; - - // make 16 bit words out of every two adjacent 8 bit words in the packet - // and add them up - for (i = 0; i < ipHdrLen ;i += 2) - { - word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF); - sum = sum + (quint32) word16; - } - - // take only 16 bits out of the 32 bit sum and add up the carries - while (sum>>16) - sum = (sum & 0xFFFF)+(sum >> 16); + quint32 sum; - // one's complement the result - sum = ~sum; - - return (quint16) sum; + sum = srcIp >> 16; + sum += srcIp & 0xFFFF; + sum += dstIp >> 16; + sum += dstIp & 0xFFFF; + sum += (quint16) (protocol); + sum += len; + + // Above calculation done assuming 'big endian' - so convert to host order + return qFromBigEndian(sum); } -#endif -quint16 StreamInfo::ipv4Cksum(uchar *buf, int len) +quint32 StreamInfo::ipv4CksumPartial(uchar *buf, int len) { - quint32 sum = 0; /* assume 32 bit long, 16 bit short */ + quint32 sum = 0; quint16 *ip = (quint16*) buf; - while(len > 1) + if (len & 0x0001) + { + qFatal("Cannot calculate partial checksum on non multiple of 2 length"); + return 0; + } + + while(len) { sum += *ip; - if(sum & 0x80000000) /* if high order bit set, fold */ + if(sum & 0x80000000) sum = (sum & 0xFFFF) + (sum >> 16); ip++; len -= 2; } - if(len) /* take care of left over byte */ + return sum; +} + +quint16 StreamInfo::ipv4Cksum(uchar *buf, int len, quint32 partialSum) +{ + quint32 sum = partialSum; + quint16 *ip = (quint16*) buf; + + while(len > 1) + { + sum += *ip; + if(sum & 0x80000000) + sum = (sum & 0xFFFF) + (sum >> 16); + ip++; + len -= 2; + } + + if (len) sum += (unsigned short) *(unsigned char *)ip; while(sum>>16) sum = (sum & 0xFFFF) + (sum >> 16); - qDebug("cksum = %x", ~sum); return (quint16) ~sum; } int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) { - int u, pktLen, len = 0; + int u, pktLen, dataLen, len = 0; + quint32 srcIp, dstIp; // need it later for TCP/UDP cksum calculation + quint32 cumCksum = 0; // cumulative cksum used to combine partial cksums + int tcpOfs, udpOfs; // needed to fill in cksum later uchar scratch[8]; - // TODO(HI): use FrameLengthMode - don't assume fixed + // Decide a frame length based on length mode + switch(d.core().len_mode()) + { + case OstProto::StreamCore::e_fl_fixed: + pktLen = d.core().frame_len(); + break; + case OstProto::StreamCore::e_fl_inc: + pktLen = d.core().frame_len_min() + (n % + (d.core().frame_len_max() - d.core().frame_len_min() + 1)); + break; + case OstProto::StreamCore::e_fl_dec: + pktLen = d.core().frame_len_max() - (n % + (d.core().frame_len_max() - d.core().frame_len_min() + 1)); + break; + case OstProto::StreamCore::e_fl_random: + pktLen = d.core().frame_len_min() + (qrand() % + (d.core().frame_len_max() - d.core().frame_len_min() + 1)); + break; + default: + qWarning("Unhandled len mode %d. Using default 64", + d.core().len_mode()); + pktLen = 64; + break; + } + // pktLen is adjusted for CRC/FCS which will be added by the NIC - pktLen = d.core().frame_len() - 4; - if (bufMaxSize < pktLen) + pktLen -= 4; + + if ((pktLen < 0) || (pktLen > bufMaxSize)) return 0; // We always have a Mac Header! @@ -226,30 +266,34 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) qToBigEndian((quint16) 0, buf+len); len += 2; - // TODO(HI): Use IpMode - don't assume fixed + // Get Src/Dst IP for this packet using respective IpMode switch(d.ip().src_ip_mode()) { case OstProto::Ip::e_im_fixed: - qToBigEndian((quint32) d.ip().src_ip(), buf+len); + srcIp = (quint32) d.ip().src_ip(); + qToBigEndian(srcIp, buf+len); break; case OstProto::Ip::e_im_inc_host: u = n % d.ip().src_ip_count(); subnet = d.ip().src_ip() & d.ip().src_ip_mask(); host = (((d.ip().src_ip() & ~d.ip().src_ip_mask()) + u) & ~d.ip().src_ip_mask()); - qToBigEndian((quint32) (subnet | host), buf+len); + srcIp = (quint32) (subnet | host); + qToBigEndian(srcIp, buf+len); break; case OstProto::Ip::e_im_dec_host: u = n % d.ip().src_ip_count(); subnet = d.ip().src_ip() & d.ip().src_ip_mask(); host = (((d.ip().src_ip() & ~d.ip().src_ip_mask()) - u) & ~d.ip().src_ip_mask()); - qToBigEndian((quint32) (subnet | host), buf+len); + srcIp = (quint32) (subnet | host); + qToBigEndian(srcIp, buf+len); break; case OstProto::Ip::e_im_random_host: subnet = d.ip().src_ip() & d.ip().src_ip_mask(); host = (qrand() & ~d.ip().src_ip_mask()); - qToBigEndian((quint32) (subnet | host), buf+len); + srcIp = (quint32) (subnet | host); + qToBigEndian(srcIp, buf+len); break; default: qWarning("Unhandled src_ip_mode = %d", d.ip().src_ip_mode()); @@ -259,26 +303,30 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) switch(d.ip().dst_ip_mode()) { case OstProto::Ip::e_im_fixed: - qToBigEndian((quint32) d.ip().dst_ip(), buf+len); + dstIp = (quint32) d.ip().dst_ip(); + qToBigEndian(dstIp, buf+len); break; case OstProto::Ip::e_im_inc_host: u = n % d.ip().dst_ip_count(); subnet = d.ip().dst_ip() & d.ip().dst_ip_mask(); host = (((d.ip().dst_ip() & ~d.ip().dst_ip_mask()) + u) & ~d.ip().dst_ip_mask()); - qToBigEndian((quint32) (subnet | host), buf+len); + dstIp = (quint32) (subnet | host); + qToBigEndian(dstIp, buf+len); break; case OstProto::Ip::e_im_dec_host: u = n % d.ip().dst_ip_count(); subnet = d.ip().dst_ip() & d.ip().dst_ip_mask(); host = (((d.ip().dst_ip() & ~d.ip().dst_ip_mask()) - u) & ~d.ip().dst_ip_mask()); - qToBigEndian((quint32) (subnet | host), buf+len); + dstIp = (quint32) (subnet | host); + qToBigEndian(dstIp, buf+len); break; case OstProto::Ip::e_im_random_host: subnet = d.ip().dst_ip() & d.ip().dst_ip_mask(); host = (qrand() & ~d.ip().dst_ip_mask()); - qToBigEndian((quint32) (subnet | host), buf+len); + dstIp = (quint32) (subnet | host); + qToBigEndian(dstIp, buf+len); break; default: qWarning("Unhandled dst_ip_mode = %d", d.ip().dst_ip_mode()); @@ -291,6 +339,7 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) else *((quint16*)(buf + ipOfs + 10)) = ipv4Cksum(buf + ipOfs, len-ipOfs); break; + } case OstProto::StreamCore::e_l3_arp: // TODO(LOW) @@ -305,6 +354,10 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) break; case OstProto::StreamCore::e_l4_tcp: { + tcpOfs = len; + + cumCksum = pseudoHdrCksumPartial(srcIp, dstIp, 6, pktLen - len); + qToBigEndian((quint16) d.tcp().src_port(), buf+len); len += 2; qToBigEndian((quint16) d.tcp().dst_port(), buf+len); @@ -318,26 +371,30 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) if (d.tcp().is_override_hdrlen()) buf[len+0] = (quint8) d.tcp().hdrlen_rsvd(); else - buf[len+0] = (quint8) 0x50; // FIXME(LOW) + buf[len+0] = (quint8) 0x50; // FIXME(LOW): Hardcoding buf[len+1] = (quint8) d.tcp().flags(); len += 2; qToBigEndian((quint16) d.tcp().window(), buf+len); len +=2; - if (d.tcp().is_override_cksum()) - qToBigEndian((quint16) d.tcp().cksum(), buf+len); - else - qToBigEndian((quint16) 0, buf+len); // FIXME(HI) + // Fill in cksum as 0 for cksum calculation, actual cksum filled later + qToBigEndian((quint16) 0, buf+len); len +=2; qToBigEndian((quint16) d.tcp().urg_ptr(), buf+len); len +=2; + + // Accumulate cumulative cksum + cumCksum += ipv4CksumPartial(buf + tcpOfs, len - tcpOfs); + break; } case OstProto::StreamCore::e_l4_udp: { - int udpLen = pktLen - len; + udpOfs = len; + + cumCksum = pseudoHdrCksumPartial(srcIp, dstIp, 17, pktLen - len); qToBigEndian((quint16) d.udp().src_port(), buf+len); len += 2; @@ -347,14 +404,16 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) if (d.udp().is_override_totlen()) qToBigEndian((quint16) d.udp().totlen(), buf+len); else - qToBigEndian((quint16) udpLen, buf+len); + qToBigEndian((quint16) (pktLen - udpOfs), buf+len); len +=2; - if (d.udp().is_override_cksum()) - qToBigEndian((quint16) d.udp().cksum(), buf+len); - else - qToBigEndian((quint16) 0, buf+len); // FIXME(HI) + // Fill in cksum as 0 for cksum calculation, actual cksum filled later + qToBigEndian((quint16) 0, buf+len); len +=2; + + // Accumulate cumulative cksum + cumCksum += ipv4CksumPartial(buf + udpOfs, len - udpOfs); + break; } case OstProto::StreamCore::e_l4_icmp: @@ -368,15 +427,51 @@ int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n) } // Fill-in the data pattern + dataLen = pktLen - len; + switch(d.core().pattern_mode()) { - int dataLen; + case OstProto::StreamCore::e_dp_fixed_word: + for (int i = 0; i < (dataLen/4)+1; i++) + qToBigEndian((quint32) d.core().pattern(), buf+len+(i*4)); + break; + case OstProto::StreamCore::e_dp_inc_byte: + for (int i = 0; i < dataLen; i++) + buf[len + i] = i % (0xFF + 1); + break; + case OstProto::StreamCore::e_dp_dec_byte: + for (int i = 0; i < dataLen; i++) + buf[len + i] = 0xFF - (i % (0xFF + 1)); + break; + case OstProto::StreamCore::e_dp_random: + for (int i = 0; i < dataLen; i++) + buf[len + i] = qrand() % (0xFF + 1); + break; + default: + qWarning("Unhandled data pattern %d", d.core().pattern_mode()); + } - dataLen = pktLen - len; - for (int i = 0; i < (dataLen/4)+1; i++) - { - // TODO(HI): Use patternMode - qToBigEndian((quint32) d.core().pattern(), buf+len+(i*4)); - } + // Calculate TCP/UDP checksum over the data pattern/payload and fill in + switch (d.core().l4_proto()) + { + case OstProto::StreamCore::e_l4_tcp: + if (d.tcp().is_override_cksum()) + qToBigEndian((quint16) d.tcp().cksum(), buf + tcpOfs + 16); + else + *((quint16*)(buf + tcpOfs + 16)) = + ipv4Cksum(buf + len, dataLen, cumCksum); + break; + case OstProto::StreamCore::e_l4_udp: + if (d.udp().is_override_cksum()) + qToBigEndian((quint16) d.udp().cksum(), buf + udpOfs + 6); + else + *((quint16*)(buf + udpOfs + 6)) = + ipv4Cksum(buf + len, dataLen, cumCksum); + break; + case OstProto::StreamCore::e_l4_none: + case OstProto::StreamCore::e_l4_icmp: + case OstProto::StreamCore::e_l4_igmp: + // No cksum processing required + break; } return pktLen; @@ -414,7 +509,7 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev) } d.mutable_port_id()->set_id(id); - d.set_name("eth"); // FIXME(MED): suffix portid + d.set_name(QString("eth%1").arg(id).toAscii().constData()); d.set_description(dev->description); d.set_is_enabled(true); // FIXME(MED):check d.set_is_oper_up(true); // FIXME(MED):check @@ -425,7 +520,7 @@ PortInfo::PortInfo(uint id, pcap_if_t *dev) // We'll create sendqueue later when required sendQueue = NULL; - pcapExtra.sendQueueNumPkts = 0; + pcapExtra.sendQueueCumLen.clear(); pcapExtra.txPkts = 0; pcapExtra.txBytes = 0; isSendQueueDirty=true; @@ -446,7 +541,7 @@ void PortInfo::update() // TODO(LOW): calculate sendqueue size sendQueue = pcap_sendqueue_alloc(1*MB); - pcapExtra.sendQueueNumPkts = 0; + pcapExtra.sendQueueCumLen.clear(); // First sort the streams by ordinalValue qSort(streamList); @@ -457,35 +552,45 @@ void PortInfo::update() { int numPackets, numBursts; - if (streamList[i].d.control().unit() == - OstProto::StreamControl::e_su_bursts) + switch (streamList[i].d.control().unit()) { + case OstProto::StreamControl::e_su_bursts: numBursts = streamList[i].d.control().num_bursts(); numPackets = streamList[i].d.control().packets_per_burst(); - } - else - { + break; + case OstProto::StreamControl::e_su_packets: numBursts = 1; numPackets = streamList[i].d.control().num_packets(); + break; + default: + qWarning("Unhandled stream control unit %d", + streamList[i].d.control().unit()); + continue; } + for (int j = 0; j < numBursts; j++) { for (int k = 0; k < numPackets; k++) { - pktHdr.len = streamList[i].makePacket( - pktBuf, sizeof(pktBuf), j * numPackets + k); - pktHdr.caplen = pktHdr.len; - pktHdr.ts.tv_sec = pktHdr.ts.tv_usec = 0; // FIXME(HI) + int len; - if (-1 == pcap_sendqueue_queue(sendQueue, &pktHdr, - (u_char*) pktBuf)) + len = streamList[i].makePacket(pktBuf, sizeof(pktBuf), + j * numPackets + k); + if (len > 0) { - qDebug("[port %d] sendqueue_queue() failed for " - "streamidx %d\n", id(), i); + pktHdr.caplen = pktHdr.len = len; + pktHdr.ts.tv_sec = pktHdr.ts.tv_usec = 0; // FIXME(HI) + + if (-1 == pcap_sendqueue_queue(sendQueue, &pktHdr, + (u_char*) pktBuf)) + { + qDebug("[port %d] sendqueue_queue() failed for " + "streamidx %d\n", id(), i); + } + else + pcapExtra.sendQueueCumLen.append(sendQueue->len); } - else - pcapExtra.sendQueueNumPkts++; } } } @@ -496,7 +601,7 @@ void PortInfo::update() void PortInfo::startTransmit() { - uint bytes; + uint bytes, pkts; // TODO(HI): Stream Mode - one pass/continuous bytes = pcap_sendqueue_transmit(devHandle, sendQueue, false); @@ -504,21 +609,35 @@ void PortInfo::startTransmit() { qDebug("port %d: sent (%d/%d) error %s. TxStats may be inconsistent", id(), bytes, sendQueue->len, pcap_geterr(devHandle)); - //! \TODO parse sendqueue using 'bytes' to get actual pkts sent - pcapExtra.txPkts += pcapExtra.sendQueueNumPkts; - pcapExtra.txBytes += bytes; + + // parse sendqueue using 'bytes' to get actual pkts sent +#if 0 + // FIXME(LOW): Get this working + pkts = qUpperBound(pcapExtra.sendQueueCumLen, bytes); +#else + for (int i = 0; i < pcapExtra.sendQueueCumLen.size(); i++) + { + if (pcapExtra.sendQueueCumLen.at(i) > bytes) + { + pkts = i; + break; + } + } +#endif } else { qDebug("port %d: sent (%d/%d) bytes\n", id(), bytes, sendQueue->len); - pcapExtra.txPkts += pcapExtra.sendQueueNumPkts; - pcapExtra.txBytes += bytes; + pkts = pcapExtra.sendQueueCumLen.size(); } // pcap_sendqueue_transmit() returned 'bytes' includes size of pcap_pkthdr // - adjust for it - pcapExtra.txBytes -= pcapExtra.sendQueueNumPkts * sizeof(pcap_pkthdr); + if (bytes) + bytes -= pkts * sizeof(pcap_pkthdr); + pcapExtra.txPkts += pkts; + pcapExtra.txBytes += bytes; } void PortInfo::stopTransmit() @@ -951,7 +1070,7 @@ const ::OstProto::PortIdList* request, portIdx = request->port_id(i).id(); if (portIdx >= numPorts) - continue; // FIXME(MED): partial RPC? + continue; // TODO(LOW): partial RPC? if (portInfo[portIdx]->isDirty()) portInfo[portIdx]->update(); @@ -963,7 +1082,7 @@ const ::OstProto::PortIdList* request, portIdx = request->port_id(i).id(); if (portIdx >= numPorts) - continue; // FIXME(MED): partial RPC? + continue; // TODO(LOW): partial RPC? portInfo[portIdx]->startTransmit(); } @@ -986,7 +1105,7 @@ const ::OstProto::PortIdList* request, portIdx = request->port_id(i).id(); if (portIdx >= numPorts) - continue; // FIXME(MED): partial RPC? + continue; // TODO(LOW): partial RPC? portInfo[portIdx]->stopTransmit(); } @@ -1038,7 +1157,7 @@ const ::OstProto::PortIdList* request, portidx = request->port_id(i).id(); if (portidx >= numPorts) - continue; // FIXME(med): partial rpc? + continue; // TODO(LOW): partial rpc? s = response->add_port_stats(); s->mutable_port_id()->set_id(request->port_id(i).id()); @@ -1082,7 +1201,7 @@ const ::OstProto::PortIdList* request, portIdx = request->port_id(i).id(); if (portIdx >= numPorts) - continue; // FIXME(MED): partial RPC? + continue; // TODO(LOW): partial RPC? portInfo[portIdx]->resetStats(); } diff --git a/server/myservice.h b/server/myservice.h index ecb474e..a14524d 100644 --- a/server/myservice.h +++ b/server/myservice.h @@ -37,8 +37,10 @@ class StreamInfo StreamInfo() { PbHelper pbh; pbh.ForceSetSingularDefault(&d); } - //quint16 ipv4Cksum(quint16 ipHdrLen, quint16 buff[]); - quint16 ipv4Cksum(uchar *buf, int len); + quint32 pseudoHdrCksumPartial(quint32 srcIp, quint32 dstIp, + quint8 protocol, quint16 len); + quint32 ipv4CksumPartial(uchar *buf, int len); + quint16 ipv4Cksum(uchar *buf, int len, quint32 partialSum = 0); int StreamInfo::makePacket(uchar *buf, int bufMaxSize, int n); public: bool operator < (const StreamInfo &s) const @@ -90,8 +92,10 @@ class PortInfo // PCAP supports it, we'll remove from here struct PcapExtra { - //! pcap_sendqueue_transmit() only returns 'bytes' sent - uint sendQueueNumPkts; + //! Used to track num of packets (and their sizes) in the + // send queue. Also used to find out actual num of pkts sent + // in case of partial send in pcap_sendqueue_transmit() + QList sendQueueCumLen; //! PCAP doesn't do any tx stats quint64 txPkts;