Tuesday, October 15, 2013

[dbus] The useful information and example of D-Bus

D-Bus Main Page: http://www.freedesktop.org/wiki/Software/dbus/#index5h1
D-Bus Basic Overview: http://pythonhosted.org/txdbus/dbus_overview.html
The Installation Guide: http://www.linuxfromscratch.org/blfs/view/svn/general/dbus.html
The Introduction to D-Bus ( more details ) : http://www.freedesktop.org/wiki/IntroductionToDBus/
The D-Bus Tutorial: http://dbus.freedesktop.org/doc/dbus-tutorial.html
D-Bus APIs: http://dbus.freedesktop.org/doc/api/html/


Example Source: http://www.matthew.ath.cx/misc/dbus
I use the example: dbus-example.c from the above source and modify a little bit for bug fixed. And also, here is my test conf file for the permission of using the system bus.


  • dbus-example.c

#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

/**
 * Connect to the DBUS bus and send a broadcast signal
 */
void sendsignal(char* sigvalue)
{
   DBusMessage* msg;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   int ret;
   dbus_uint32_t serial = 0;

   printf("Sending signal with value %s\n", sigvalue);

   // initialise the error value
   dbus_error_init(&err);

   // connect to the DBUS system bus, and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Connection Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (NULL == conn) {
      exit(1);
   }

   // register our name on the bus, and check for errors
   ret = dbus_bus_request_name(conn, "test.signal.source", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Name Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
      exit(1);
   }

   // create a signal & check for errors
   msg = dbus_message_new_signal("/test/signal/Object", // object name of the signal
                                 "test.signal.Type", // interface name of the signal
                                 "Test"); // name of the signal
   if (NULL == msg)
   {
      fprintf(stderr, "Message Null\n");
      exit(1);
   }

   // append arguments onto signal
   dbus_message_iter_init_append(msg, &args);
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &sigvalue)) {
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }

   // send the message and flush the connection
   if (!dbus_connection_send(conn, msg, &serial)) {
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }
   dbus_connection_flush(conn);
 
   printf("Signal Sent\n");
 
   // free the message and close the connection
   dbus_message_unref(msg);
   dbus_connection_close(conn);
}

/**
 * Call a method on a remote object
 */
void query(char* param)
{
   DBusMessage* msg;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   DBusPendingCall* pending;
   int ret;
   dbus_bool_t stat = FALSE;
   dbus_uint32_t level = 0;

   printf("Calling remote method with %s\n", param);

   // initialiset the errors
   dbus_error_init(&err);

   // connect to the system bus and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Connection Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (NULL == conn) {
      exit(1);
   }

   // request our name on the bus
   ret = dbus_bus_request_name(conn, "test.method.caller", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Name Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
      exit(1);
   }

   // create a new method call and check for errors
   msg = dbus_message_new_method_call("test.method.server", // target for the method call
                                      "/test/method/Object", // object to call on
                                      "test.method.Type", // interface to call on
                                      "Method"); // method name
   if (NULL == msg) {
      fprintf(stderr, "Message Null\n");
      exit(1);
   }

   // append arguments
   dbus_message_iter_init_append(msg, &args);
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &param)) {
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }
 
   // send message and get a handle for a reply
   if (!dbus_connection_send_with_reply (conn, msg, &pending, -1)) { // -1 is default timeout
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }
   if (NULL == pending) {
      fprintf(stderr, "Pending Call Null\n");
      exit(1);
   }
   dbus_connection_flush(conn);
 
   printf("Request Sent\n");
 
   // free message
   dbus_message_unref(msg);
 
   // block until we recieve a reply
   dbus_pending_call_block(pending);

   // get the reply message
   msg = dbus_pending_call_steal_reply(pending);
   if (NULL == msg) {
      fprintf(stderr, "Reply Null\n");
      exit(1);
   }
   // free the pending message handle
   dbus_pending_call_unref(pending);

   // read the parameters
   if (!dbus_message_iter_init(msg, &args))
      fprintf(stderr, "Message has no arguments!\n");
   else if (DBUS_TYPE_BOOLEAN != dbus_message_iter_get_arg_type(&args))
      fprintf(stderr, "Argument is not boolean!\n");
   else
      dbus_message_iter_get_basic(&args, &stat);

   if (!dbus_message_iter_next(&args))
      fprintf(stderr, "Message has too few arguments!\n");
   else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
      fprintf(stderr, "Argument is not int!\n");
   else
      dbus_message_iter_get_basic(&args, &level);

   printf("Got Reply: %d, %d\n", stat, level);
 
   // free reply and close connection
   dbus_message_unref(msg);
   dbus_connection_close(conn);
}

void reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
{
   DBusMessage* reply;
   DBusMessageIter args;
   dbus_bool_t stat = TRUE;
   dbus_uint32_t level = 21614;
   dbus_uint32_t serial = 0;
   char* param = "";

   // read the arguments
   if (!dbus_message_iter_init(msg, &args))
      fprintf(stderr, "Message has no arguments!\n");
   else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))
      fprintf(stderr, "Argument is not string!\n");
   else
      dbus_message_iter_get_basic(&args, &param);

   printf("Method called with %s\n", param);

   // create a reply from the message
   reply = dbus_message_new_method_return(msg);

   // add the arguments to the reply
   dbus_message_iter_init_append(reply, &args);
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &stat)) {
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }
   if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &level)) {
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }

   // send the reply && flush the connection
   if (!dbus_connection_send(conn, reply, &serial)) {
      fprintf(stderr, "Out Of Memory!\n");
      exit(1);
   }
   dbus_connection_flush(conn);

   // free the reply
   dbus_message_unref(reply);
}

/**
 * Server that exposes a method call and waits for it to be called
 */
void listen()
{
   DBusMessage* msg;
   DBusMessage* reply;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   int ret;
   char* param;

   printf("Listening for method calls\n");

   // initialise the error
   dbus_error_init(&err);
 
   // connect to the bus and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Connection Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (NULL == conn) {
      fprintf(stderr, "Connection Null\n");
      exit(1);
   }
 
   // request our name on the bus and check for errors
   ret = dbus_bus_request_name(conn, "test.method.server", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Name Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
      fprintf(stderr, "Not Primary Owner (%d)\n", ret);
      exit(1);
   }

   // loop, testing for new messages
   while (true) {
      // non blocking read of the next available message
      dbus_connection_read_write(conn, 0);
      msg = dbus_connection_pop_message(conn);

      // loop again if we haven't got a message
      if (NULL == msg) {
         sleep(1);
         continue;
      }
   
      // check this is a method call for the right interface & method
      if (dbus_message_is_method_call(msg, "test.method.Type", "Method"))
         reply_to_method_call(msg, conn);

      // free the message
      dbus_message_unref(msg);
   }

   // close the connection
   dbus_connection_close(conn);
}

/**
 * Listens for signals on the bus
 */
void receive()
{
   DBusMessage* msg;
   DBusMessageIter args;
   DBusConnection* conn;
   DBusError err;
   int ret;
   char* sigvalue;

   printf("Listening for signals\n");

   // initialise the errors
   dbus_error_init(&err);
 
   // connect to the bus and check for errors
   conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Connection Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   if (NULL == conn) {
      exit(1);
   }
 
   // request our name on the bus and check for errors
   ret = dbus_bus_request_name(conn, "test.signal.sink", DBUS_NAME_FLAG_REPLACE_EXISTING , &err);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Name Error (%s)\n", err.message);
      dbus_error_free(&err);
   }
   //if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
   //   exit(1);
   //}

   // add a rule for which messages we want to see
   dbus_bus_add_match(conn, "type='signal',interface='test.signal.Type'", &err); // see signals from the given interface
   dbus_connection_flush(conn);
   if (dbus_error_is_set(&err)) {
      fprintf(stderr, "Match Error (%s)\n", err.message);
      exit(1);
   }
   printf("Match rule sent\n");

   // loop listening for signals being emmitted
   while (true) {

      // non blocking read of the next available message
      dbus_connection_read_write(conn, 0);
      msg = dbus_connection_pop_message(conn);

      // loop again if we haven't read a message
      if (NULL == msg) {
         sleep(1);
         continue;
      }

      // check if the message is a signal from the correct interface and with the correct name
      if (dbus_message_is_signal(msg, "test.signal.Type", "Test")) {
       
         // read the parameters
         if (!dbus_message_iter_init(msg, &args))
            fprintf(stderr, "Message Has No Parameters\n");
         else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))
            fprintf(stderr, "Argument is not string!\n");
         else
            dbus_message_iter_get_basic(&args, &sigvalue);
       
         printf("Got Signal with value %s\n", sigvalue);
      }

      // free the message
      dbus_message_unref(msg);
   }
   // close the connection
   dbus_connection_close(conn);
}

int main(int argc, char** argv)
{
   if (2 > argc) {
      printf ("Syntax: dbus-example [send|receive|listen|query] [<param>]\n");
      return 1;
   }
   char* param = "no param";
   if (3 >= argc && NULL != argv[2]) param = argv[2];
   if (0 == strcmp(argv[1], "send"))
      sendsignal(param);
   else if (0 == strcmp(argv[1], "receive"))
      receive();
   else if (0 == strcmp(argv[1], "listen"))
      listen();
   else if (0 == strcmp(argv[1], "query"))
      query(param);
   else {
      printf ("Syntax: dbus-example [send|receive|listen|query] [<param>]\n");
      return 1;
   }
   return 0;
}



  • mytesting.conf

<!DOCTYPE busconfig PUBLIC
          "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
          "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>

  <!-- Only root or user testing can own the testing service -->
  <policy user="liudanny">
    <allow own="test.signal.source"/>
    <allow own="test.signal.sink"/>
    <allow own="test.method.server"/>
<allow own="test.method.caller"/>
  </policy>
  <policy user="root">
    <allow own="test.signal.source"/>
<allow own="test.signal.sink"/>
<allow own="test.method.server"/>
<allow own="test.method.caller"/>
  </policy>

  <!-- Allow anyone to invoke methods on testing server -->
  <policy context="default">
    <allow send_destination="test.signal.source"/>
    <allow receive_sender="test.signal.source"/>
  </policy>
   <policy context="default">
    <allow send_destination="test.signal.sink"/>
    <allow receive_sender="test.signal.sink"/>
  </policy>
  <policy context="default">
    <allow send_destination="test.method.server"/>
    <allow receive_sender="test.method.server"/>
  </policy>
  <policy context="default">
    <allow send_destination="test.method.caller"/>
    <allow receive_sender="test.method.caller"/>
  </policy>

  <!-- Allow everything, including access to SetHostName to users of the group "liudanny" -->
  <policy group="liudanny">
    <allow send_destination="test.signal.source"/>
    <allow receive_sender="test.signal.source"/>
  </policy>
  <policy user="root">
    <allow send_destination="test.signal.source"/>
    <allow receive_sender="test.signal.source"/>
  </policy>
  <policy group="liudanny">
    <allow send_destination="test.signal.sink"/>
    <allow receive_sender="test.signal.sink"/>
  </policy>
  <policy user="root">
    <allow send_destination="test.signal.sink"/>
    <allow receive_sender="test.signal.sink"/>
  </policy>
    <policy group="liudanny">
    <allow send_destination="test.method.server"/>
    <allow receive_sender="test.method.server"/>
  </policy>
  <policy user="root">
    <allow send_destination="test.method.server"/>
    <allow receive_sender="test.method.server"/>
  </policy>
    <policy group="liudanny">
    <allow send_destination="test.method.caller"/>
    <allow receive_sender="test.method.caller"/>
  </policy>
  <policy user="root">
    <allow send_destination="test.method.caller"/>
    <allow receive_sender="test.method.caller"/>
  </policy>


</busconfig>

Friday, October 11, 2013

[vMotion] The reason of sending RARP packet after vMotion finished

Recently I read the article about How vMotion impacts the forwarding table, I found I didn't quite get understood the following sentence:
"The following article mentioned "When the VM-MAC1 is moved from Host 1 to Host 2 through vMotion process a Reverse ARP (RARP) is issued by Host2’s kernel module on behalf of the VM-MAC1."

After searching RARP and vMotion information, I know why RARP is used here. The answer is quoted from here:
"The goal for sending these frames is to make sure the physical switches in the network learns the location of the Virtual Machines. A physical switch does this learning by observing each incoming frame and make a note of the field called Source MAC Address. Based on that information the switches build tables with mappings between MAC addresses and the switch port where this address could be found."

So, in sum, physical switches and vSphere will update their forwarding table by receiving the broadcast address of RARP packet.

Wednesday, September 18, 2013

[VMware] NSX Topologies with Traffic Flows

http://packetpushers.net/wp-content/uploads/2013/09/PPP-VMware-NSX-Topologies-Traffic-Flows.pdf

[U-Boot] Use U-Boot command to reload image file and reboot

The following step is about the U-Boot to reboot your machine:

U-Boot>printenv

  • You can find the image address and bootm address.

U-Boot>setenv ipaddr 192.168.4.40
U-Boot>setenv serverip 192.168.4.26
U-Boot>setenv ethaddr 00:01:02:03:04:05
U-Boot>setenv netmask 255.255.255.0
U-Boot>saveenv
U-Boot>tftpboot 0xA800000040000000 <<your image file>>
U-Boot>bootm 0xA800000040000074

Wednesday, August 28, 2013

[BPDU] To understand BPDU Filtering an BPDU Guard


Quote from http://www.cisco.com/en/US/docs/switches/lan/catalyst3560/software/release/12.2_55_se/configuration/guide/swstpopt.html#wp1046220




Understanding BPDU Guard


The BPDU guard feature can be globally enabled on the switch or can be enabled per port, but the feature operates with some differences.

At the global level, you enable BPDU guard on Port Fast-enabled ports by using the spanning-tree portfast bpduguard default global configuration command. Spanning tree shuts down ports that are in a Port Fast-operational state if any BPDU is received on them. In a valid configuration, Port Fast-enabled ports do not receive BPDUs. Receiving a BPDU on a Port Fast-enabled port means an invalid configuration, such as the connection of an unauthorized device, and the BPDU guard feature puts the port in the error-disabled state. When this happens, the switch shuts down the entire port on which the violation occurred.

To prevent the port from shutting down, you can use the errdisable detect cause bpduguard shutdown vlan global configuration command to shut down just the offending VLAN on the port where the violation occurred.

At the interface level, you enable BPDU guard on any port by using the spanning-tree bpduguard enable interface configuration command without also enabling the Port Fast feature. When the port receives a BPDU, it is put in the error-disabled state.

The BPDU guard feature provides a secure response to invalid configurations because you must manually put the interface back in service. Use the BPDU guard feature in a service-provider network to prevent an access port from participating in the spanning tree.

Understanding BPDU Filtering


The BPDU filtering feature can be globally enabled on the switch or can be enabled per interface, but the feature operates with some differences.

At the global level, you can enable BPDU filtering on Port Fast-enabled interfaces by using the spanning-tree portfast bpdufilter default global configuration command. This command prevents interfaces that are in a Port Fast-operational state from sending or receiving BPDUs. The interfaces still send a few BPDUs at link-up before the switch begins to filter outbound BPDUs. You should globally enable BPDU filtering on a switch so that hosts connected to these interfaces do not receive BPDUs. If a BPDU is received on a Port Fast-enabled interface, the interface loses its Port Fast-operational status, and BPDU filtering is disabled.

At the interface level, you can enable BPDU filtering on any interface by using the spanning-tree bpdufilter enable interface configuration command without also enabling the Port Fast feature. This command prevents the interface from sending or receiving BPDUs.




Tuesday, August 20, 2013

[Google Chart] Some examples of using Google Chart API in Python

Here are some example codes of using Google Chart APIs written in Python that I wrote several years ago. And some output image for reference.

  • To generate multi-line chart:
def createMultiLineChart(rows, max_value):
urls = "http://chart.apis.google.com/chart?" + \
"chs=" + str(300+24*rows.__len__()) + "x200" + \
"&chd=t:" + ",".join([str(i[1]) for i in rows]) + "|" + ",".join([str(i[2]) for i in rows]) + \
"&cht=lc" + \
"&chls=2,1,0|2,1,0" + \
"&chco=0000ff,ff0000" + \
"&chtt=SMT%20Scrap%20Rate" + \
"&chxt=x,y" + \
"&chg=20,20" + \
"&chds=0," + str(max_value * 1.4) + \
"&chxl=0:|" + "|".join([str(i[0]) for i in rows]) + "|1:|" + "|".join(
[str(i * max_value * 1.4 / 10.0) + '%' for i in range(0,11)]) + \
"&chdl=Day%20S/R(%)|Night%20S/R(%)" + \
"&chm=s,0000ff,0,-1,8|s,ff0000,1,-1,8|N*f3*%,0000ff,0,-1,10|N*f3*%,ff0000,1,-1,10"
return urls


  • To generate multi-line chart:

def createLineChart(rows, max_value):
urls = "http://chart.apis.google.com/chart?" + \
"chs=" + str(300+24*rows.__len__()) + "x200" + \
"&chd=t:" + ",".join([str(i[1]) for i in rows]) + \
"&cht=lc" + \
"&chls=2,1,0" + \
"&chco=8080ff" + \
"&chtt=SMT%20Scrap%20Rate" + \
"&chxt=x,y" + \
"&chg=20,20" + \
"&chds=0," + str(max_value * 1.4) + \
"&chxl=0:|" + "|".join([str(i[0]) for i in rows]) + "|1:|" + "|".join(
[str(i * max_value * 1.4 / 10.0) + '%' for i in range(0,11)]) +\
"&chdl=S/R(%)" + \
"&chm=s,80C65A,0,-1,10|N*f3*%,8080ff,0,-1,10"
return urls
P.S: It is almost the same as multi-line chart so that I don't provide the image.

  • To generate bar chart:
def createBarChart(rows, max_value):
urls = "http://chart.apis.google.com/chart?" + \
"chs=" + str(300+24*rows.__len__()) + "x200" + \
"&chd=t:" + ",".join([str(i[1]) for i in rows]) + \
"&cht=bvg" + \
"&chco=1d89f9,c6d9fd" + \
"&chtt=SMT%20Scrap%20Rate" + \
"&chxt=x,y" + \
"&chg=20,20" + \
"&chds=0," + str(max_value * 1.4) + \
"&chxl=0:|" + "|".join([str(i[0]) for i in rows]) + "|1:|" + "|".join(
[str(i * max_value * 1.4 / 10.0) + '%' for i in range(0,11)]) +\
"&chdl=S/R(%)" + \
"&chbh=14,9,15"
#"&chf=bg,s,ffffef"
return urls

  • To generate pie chart:
def createPieChart(rows, legend):
urls = "|".join([i[0] for i in rows])
urls = urls.replace(' ','_')
urls=urls.encode('utf8')
urls=urllib.quote(urls,'&=')
return "http://chart.apis.google.com/chart?" + \
"chs=600x150" + \
"&chd=t:" + ",".join([str(i[1]) for i in rows]) + \
"&cht=p3" + \
"&chtt=" + legend + \
"&chl=" + urls

[Linux Command] Redirect stderr to stdout and output to terminal and log into file at the same time

If you want to redirect stderr to stdout, append this at your command: 2>&1 , and also for outputting to terminal and logging into file you should use tee.
Both together would look like this:
$ yourcommand 2>&1 | tee yourlogfile.log

Monday, August 19, 2013

[Floodlight] A simle note from Floodlight dev discussion

For some kind of the reasons, I stopped tracking what's going on Floodlight for a while. I post my previous notes about Floodlight and OpenFlow from Floodlight dev discussion, and hope it is beneficial for those who are still working on it.
  • Floodlight by default gets full packets from switch
    • OFPT_SET_CONFIG

  • GreenMST module for Floodlight
    • GreenMST is a module used to build the Minimum Spanning Tree of an OpenFlow network, thus avoiding brodcast storm, using looped topologies with the LearningSwitch module and switches not supporting the Spanning Tree Protocol.
    • http://github.com/LucaPrete/GreenMST

  • Wildcard Matching on network address
    • OFMatch mTo = new OFMatch();
      mTo.fromString("dl_type=0x800,nw_dst=224.128.0.0/9");
      System.out.println(mTo.toString()); // This prints nw_dst as 224.128.0.0/9
      System.out.println(mTo.getNetworkDestinationMaskLen()); //This prints destination mask length as 9
      But when I do dump-flows in the switch, it doesn't show any mask. It simply gives nw_dst as 224.128.0.0.
       
  • Push static flows based on ingress ports
    • your forwarding would not work any more.  Reason is any packet coming to that port is forced out the same port, making LLDP no longer workable.  LLDP is needed for floodlight to learn topology and route/forward packets.

  • BDDP Topology Discovery
    • In BSN BDDP and BSNPROBE types were defined.  BDDP is used in TopologyDiscovery to detect non-OpenFlow broadcast domains.  BSNPROBE is not used in Floodlight now.

  • Disabling Flooding for a Switch Port
    • OFPortMod p = (OFPortMod) floodlightprovider.
      getOFMessageFactory().getMessage(OFType.PORT_MOD);
      p.setPortNumber((short) 4); // or your port number
      p.setConfig(config); // you have to enter the proper Integer to disable the port (see OpenFlow doc)
    • The setting is related with OFPPC_NO_FLOOD

  • No NAT in Floodlight now
  • Creating static flows in Floodlight
  • Northbound API
    • Right now all the decisions are made logically (load balancer, firewall) so they will never have to travel to other computers. As far as the ordering in which these are executed you can enforce some special ordering by returning something in the isCallbackOrderingPostreq methods supplied by the IFloodlightmodule interface. For instance in the firewall module we have...

      @Override
      public boolean isCallbackOrderingPostreq(OFType type, String name) {
          return (type.equals(OFType.PACKET_IN) && name.equals("forwarding"));
      }

      This says that the module has a post requirement and forces Packet_IN messages to be passed on to the forwarding module. This is an example of how you would enforce an ordering. You can probably find something similar in the loadbalancing module.
  • Virtual Network
    • multiple links between two controller islands (which is the case for fat tree topologies) are not supported by Floodlight, at least for now. See Supported Topologies for details.

Monday, August 5, 2013

[SPC] SPC Demo

Here is a SPC System Demo Video that is related with the previous article: [SPC] A simple SPC system introduction

Check it out:
http://www.youtube.com/watch?v=XLRKj2mgnEA

[SPC] A simple SPC system introduction

SPC System
Introduction
  • Statistic Process Control (SPC) has adopted and widely used in many industries, such as, IC foundry, automobile, and so on. It provides the function to monitor the process(manufacturing) capacity and check if the monitor data violates SPC Rules. The following content explains how we build up the system architecture and what the basic items are inside this system.
SPC Chart Setting
  • Table: t1twsql1.mistw.dbo.SPC_CHART_SETTING
  • This table contains all the SPC Chart Setting Data and is critical for message sending and receiving.
  • Column definition:
    • 5 categories(Category1, Category2, Category3, Category4, Category5) are combined with comma, for instance, "T3,37XX,LINEA,N/A,N/A".
    • u_spec_limit: Upper SPEC Limit
    • l_spec_limit: Lower SPEC Limit
    • spc_rules: How many SPC Rules are adopted? For example => 20 + 21 + 2 2 + 23 = 1 + 2 + 4 + 8 = 15 = Rule1 + Rule2 + Rule3 + Rule4
    • sampling_rule: Only support SamplingRuleAvg?
    • sample_number: How many data will become a point value
    • data_type: Double or String
    • is_enabled: Y/N
    • need_to_reset: Y/N
    • xbar: Default X Bar.
    • dev: Default Std. Dev.
    • owner
    • memo
    • last_alarm_time
    • last_updated_time
SPC Rules
  • One point beyond the 3σ control limit
  • 2 out of 3 consecutive points plot outside of the 2σ control limit
  • 4 out of 5 consecutive points plot outside of the 1σ control limit
  • 9 consecutive points on the same side of the centerline
  • 6 consecutive points increase or decrease
  • consecutive points oscillate up and down
  • consecutive points inside of the 1σ control limit
So, when there is any applied SPC Rule that is violated, the SPC Server will send SPC Alarm Email to specific user directly. The following is the example of the email:

SPC Server
  • The main purpose of SPC Server is to monitor the process data and check the SPC Rules. Once it violates rules, the alarm email will send to related persons directly. But, before sending alarm email, there are a bunch of things that need to do. The following content will introduce the detail information about SPC Server.
  • What does the SPC Chart look like in our SPC system?
    • Our SPC Chart will display the latest 24 points data, 3σ control limit lines, and 2 SPEC limit lines as follows:

  • Multi-threading in SPC Server
    • For the purpose of showing dynamic SPC Chart image and updating the SPC info into database, there are several threads doing their jobs to keep SPC Server work well as follows:
      • GUI: This is the main thread. It controls the GUI drawing and event handling with JFrame application.
      • JMS Receiver: We adopt ActiveMQ as JMS Provider and its API to achieving the message receiving and sending. When SPC Server starts, it will generate a JMS Receiver that we have implemented for SPC purpose and this Receiver will listen and watch out if there is any message coming.
      • SPC Chart Drawer: This heavy loading job to draw SPC Chart image is done by the Class: SPCCanvas. It refreshes the current SPC Chart image that includes to draw upper and low SPEC limits, 3σ control limits, xbar line, 24 data points, and some data labels near lines and points in every 100 millisecond. Without it, the SPC Chart image won't show smoothly.
      • DB Sync: In order to know the current SPC info, for instance, xbar, std. dev., and the current 24 data points, last updated time, and last alarm time. The Class: SPCSync is to sync this information into database in every minute. And we can use the web application to query these information.

  • SPC Image Synchronization:
As mentioned below, SPC Server has multi-threads running when it starts so that it will encounter the resource that could be accessed or updated by 2 or more threads at the same time. It's the issue of resource synchronization. In our case, we have to avoid drawing image when SPC Server is adding a new point into its SPC Chart at the same time. In other words, we don't want to see that the SPC Chart image is not complete or not correct. This situation also will affect the correction of SPC Alarm Email. Our solution is to use Semaphore which is based on Lock object to achieve our goal. The more detail is in the following image: 
  • SPC Server Data Process Flow
    • When the number of the point in a SPC Chart reach 24, SPC Server will start to draw the Chart Image.
    • When data message comes, SPC Server will follow up this process flow to deal with SPC calculation and applying SPC Rules.

  • SPC Server Data Structure:
    • The data structure is very important because it controls and contains all the point data and SPC setting in the memory so that we can lookup and operate data quickly. The main data structure is as follows:

  • SPC Server Configuration
    • DataSource?_PROD.properties
      • This properties file is as same as we use in web application
    • activemq_PubSub.config
      • This config file is about the ActiveMQ (JMS Provider) setting
§  mq.url=tcp://localhost:61616
§  mq.messagetype=Topic
§  mq.subject=testtopic
§  mq.username=
§  mq.password=
    • log4j.properties
o    log4j.logger.SPCSERVER=ALL, SERVERFileAppender, consoleAppender
o     
o    #Console Log
o    log4j.appender.consoleAppender=org.apache.log4j.ConsoleAppender
o    log4j.appender.consoleAppender.layout=org.apache.log4j.PatternLayout
o    log4j.appender.consoleAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n
o     
o    #SPC Server File Log
o    log4j.appender.SERVERFileAppender=org.apache.log4j.DailyRollingFileAppender
o    log4j.appender.SERVERFileAppender.DatePattern='.'yyyy-MM-dd
o    log4j.appender.SERVERFileAppender.layout=org.apache.log4j.PatternLayout
o    log4j.appender.SERVERFileAppender.layout.ConversionPattern=%d{yy-MM-dd HH:mm:ss:SSS} [%c] %p :  %m%n
o    log4j.appender.SERVERFileAppender.File=C:\\log\\spc\\spcserver.log
SPC Client
  • SPC Server needs to be fed by data message and SPC Client is playing the role to provide the messaging source. So far we only implement a client program for fetching the columns in TblFinal? table. Different message source could need a different client to deal with because how to generate the data message and what the format of data message are key points. For this case, the the foramt of chart name has 4 categories and 1 data vlaue: Product Name, Test Type, Station, Column Name, and coming with a colon and a data value.
  • For instance, nuvi 3790 Software Version 2.60,A,T3_3001FT07,SNR:44.5
  • SPC Client program will query data from TblFinal? in SPC database(MySQL) and is based on chart name format to generate the data message and send to the topic in JMS Provider.
  • SPC Client Configuration
    • activemq_client.config
o    mq.url=tcp://localhost:61616
o    mq.messagetype=Topic
o    mq.subject=testtopic
o    mq.username=
o    mq.password=
    • spc_client_datasource.config
o    DS_MYSQL.SPC_URL=jdbc:mysql://10.124.0.132:3306/SPC
o    DS_MYSQL.SPC_USER=xxxx
o    DS_MYSQL.SPC_PASSWD=xxxx
o    DS_MYSQL.SPC_DRIVER=com.mysql.jdbc.Driver
o    DS_MYSQL.SPC_CHARENCODING=big5
o    DS_MYSQL.SPC_DBTYPE=MYSQL
    • spc_data_mapper.config
o    #Data Mapper
o    spc.client.main=TBLFINALDataMapper
o    tblfinal=SNR
SPC System Web Application
  • This web application provides all the parameter setting management and query function in SPC.
    • spc_client_query
      • Provide the basic qeury function of SPC setting and current SPC info.

      • Provide the SPC Chart setting for TblFinal?.

      • Provide the Alarm Email setting with SPC chart.