Ask is moving to Stack Overflow and Serverfault.com! Please use the "opendaylight" tag on either of these sites. This site is now in Read-Only mode

0

Flows dont get removed from Config datastore

asked 2016-10-13 07:28:57 -0800

ahuja gravatar image

I have written a code which add some flows when a switch (node) comes up. I write it to the config datastore and I can see it in the operational datastore too.

Now, the switch goes down, the flows get removed from the operational datastore only and not from the config datastore. So next time, when the node comes up again and my code tries to write the same flows, it doesn't work. The flows are already there in the config datastore and no extra flow is written to the switch.

Can someone help me what I am doing wrong here. For example one of the those static flows is this:

public void addFlow(NodeId nodeId , NodeUpdated notification, DataBroker dataBroker){


    InstructionsBuilder isb = new InstructionsBuilder();
    InstructionBuilder ib = new InstructionBuilder();
    List<Instruction> instructions = new ArrayList<Instruction>();



    ApplyActionsBuilder applyActionsBuilder= new ApplyActionsBuilder();
    List<Action> actionList = new ArrayList<Action>();

    // Action 1 -> send to Controller
    ActionBuilder ab= new ActionBuilder();
    OutputActionBuilder outputActionBuilderContoller = new OutputActionBuilder();
    Uri controller = new Uri(OutputPortValues.CONTROLLER.toString());
    outputActionBuilderContoller.setOutputNodeConnector(controller);
    ab.setAction(new OutputActionCaseBuilder().setOutputAction(outputActionBuilderContoller.build()).build());
    ab.setOrder(0);
    ab.setKey(new ActionKey(0));

    actionList.add(ab.build());


    applyActionsBuilder.setAction(actionList);


    ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(applyActionsBuilder.build()).build());
    ib.setOrder(1);
    instructions.add(ib.build());
    instructions.add(ib.build());
    isb.setInstruction(instructions);


    FlowBuilder flow = new FlowBuilder();
    FlowId flowId = new FlowId("100");


    flow.setFlowName("ToController");
    flow.setIdleTimeout(0);
    flow.setHardTimeout(0);
    flow.setStrict(false);
    flow.setTableId((short) 1);
    flow.setPriority(0);
    flow.setInstructions(isb.build());
    flow.setKey(new FlowKey(flowId));



       @SuppressWarnings("deprecation")
       InstanceIdentifier<Flow> flowIID = InstanceIdentifier.builder(Nodes.class)
            .child(Node.class, new NodeKey(nodeId))
            .augmentation(FlowCapableNode.class)
            .child(Table.class, new TableKey(flow.getTableId()))
            .child(Flow.class, flow.getKey())
            .build();


       //now the actual writing
       try{
       GenericTransactionUtils.writeData(dataBroker, LogicalDatastoreType.CONFIGURATION, flowIID, flow.build(), true);
       }
       catch (Exception e){
        System.out.println("error in wriing flow" + e);
       }
       System.out.println("ToController Flow written on Table 1");
       return;  }

}

edit retag flag offensive close merge delete

3 answers

Sort by ยป oldest newest most voted
1

answered 2016-10-13 13:55:30 -0800

Basically, when you write a flow to the config datastore, if the switch is connected it gets pushed on the switch, then written on the operational datastore. If the switch goes down, operational datastore does reflect it, as you pointed out, by removing its entry. But the config store remain the same, as it's the config store, e.g. not supposed to reflect the operational state of the device, but the desired state. So when the device comes back up, the flows present in the config datastore will be submitted to the switch, and if success, will be written in the operational datastore.

So if you want the flow to be removed from the config datastore when the switch is doing down, you have to create and submit that transaction yourself.

Hope this helps, Alexis

edit flag offensive delete publish link more

Comments

Thanks Alexis for your response. The problem is when the switch comes up again, the flows on the configurational datastore is not written on the operational datastore. Also, can you give a direction on how to create and submit the transaction to remove the flows from config datastore.

ahuja ( 2016-10-17 22:12:10 -0800 )edit
1

> the flows on the configurational datastore is not written on the operational

What feature are you installing?

> create and submit the transaction to remove the flows from config datastore

https://gist.github.com/anonymous/f9808a9409b44f878b07989e339a8743

Alexis

adetalhouet ( 2016-10-18 05:57:55 -0800 )edit

I am installing these extra features : odl-restconf-all odl-dlux-all odl-netconf-all odl-openflowplugin-all odl-openflowjava-all odl-mdsal-all . Basically am trying to build my own L2 forwarding in a network topology.

ahuja ( 2016-10-18 06:45:59 -0800 )edit

Update: I have indicated the scenario in the answer block.

ahuja ( 2016-10-18 07:45:25 -0800 )edit
0

answered 2016-10-18 07:44:49 -0800

ahuja gravatar image

updated 2016-11-01 09:04:18 -0800

<-------Updated------>

I am using the following code to remove the flow from config datastore.

event onSwitchFlowRemoved is called in case of flow removal.

public void onSwitchFlowRemoved(SwitchFlowRemoved notification) {
    // TODO Auto-generated method stub

    // On flow removal because of timeou, it will notify here
    System.out.println("switch flow removed: " +notification.toString());
    // remove from config datastore checking the cookie if it is
    if (notification.getRemovedReason().isIDLETIMEOUT()){

        // this means the flow is removed because of idle timeout
        // now remove the corresponding flow config datastore.

        removeFlowFromConfigDatastore(notification);
    }

}

Now, in removeFlowFromConfigDatastore() method, I am trying to get the path of the flow and remove it. To do this, I need FlowKey which I dont get from notification. So, I rebuild the FlowKey from source MAC address (the way it was done while adding the flow). This works now perfectly.

private void removeFlowFromConfigDatastore(SwitchFlowRemoved notification) {

    Preconditions.checkNotNull(dataBroker);


    NodeRef nodeRef = notification.getNode();

    NodeId nodeId = notification.getNode().getValue().firstKeyOf(Node.class).getId();


    //get Node from nodeId
    //Node node = new NodeBuilder().setId(nodeId).setKey(new NodeKey(nodeId)).build();

    try{
        // get Table key
        TableKey tableKey = new TableKey(notification.getTableId());

        // get Node instance from nodeId
        InstanceIdentifier<Node> node = InstanceIdentifier.builder(Nodes.class)
                .child(Node.class, new NodeKey(nodeId))
                .build();

        //get table Instance
        InstanceIdentifier<Table> table = node.builder()
                .augmentation(FlowCapableNode.class)
                .child(Table.class, tableKey)
                .build();

        // get FlowID from match
        //FlowId flowId = new FlowId(notification.getMatch().getEthernetMatch().getEthernetSource().toString());


        System.out.println();
        System.out.println(" in remove flow from config: MAC is " + MAC);

        FlowId flowId = new FlowId(MAC);


        //get flow instance

        InstanceIdentifier<Flow> flow = table.child(Flow.class, new FlowKey(flowId));


     WriteTransaction removeFlows = dataBroker.newWriteOnlyTransaction();
     removeFlows.delete(LogicalDatastoreType.CONFIGURATION, flow);


     CheckedFuture<Void, TransactionCommitFailedException> future = removeFlows.submit();

     try{
         future.checkedGet();
         System.out.println("Timeout flows removed from conf datastore");
     }

     catch(TransactionCommitFailedException e){

         System.out.println("Cannot remove timeout flows from conf datastore");
     }
    }
 catch (Exception e){

    System.out.println("exception in writing flow " + e);
}

     return;


}

<-------Updated------>

Topology h1----S1----S2----h2

  • S1 (Switch1) comes up. --> Initial flow- go to the controller in case of a miss
  • S2 (Switch1) comes up. --> Initial flow- go to the controller in case of a miss
  • I ping from h1 to h2. h1 arps for h2. There is a table miss -> Packet goes to the Controller -> Flood Flow and h1's MAC flows are written on S1. Same thing happens for S2.
  • S1/S2 removed -> Once the switch comes up, the flows from the configurational datastore are written to the operational datastore. Working fine till now.

  • Now after expiration of flow. Say, h1 MAC to port mapping expired in S1. I ping from h1 to h2. h1 arps for h2. There is a table miss -> Packet goes to the Controller -> H1's MAC address should be learned like before and flows should be written on S1. However, it says successful, but no flow gets to the operational datastore this time.

Ping stops working

edit flag offensive delete publish link more

Comments

Is it possible you're using Boron release? If this is the case, this is a known BUG that will be fix in SR1. See https://bugs.opendaylight.org/show_bug.cgi?id=6655 for more reference.

adetalhouet ( 2016-10-21 05:34:02 -0800 )edit

I am using Beryllium release. I want to remove the flows from the config datastore. Your above github link was of somewhat help. Can I get an example on how to remove a particular flow from config datastore having id "xyz" or cookie id "a".

ahuja ( 2016-10-24 14:50:10 -0800 )edit

@ahuja - I'm unclear whether you could solve your problem or not. To delete flow, you have to specify the flowId along with tableId.
If you want delete flow per cookie id, you would have to iterate through all your flows, match on cookie id, get the associated flow id, and delete it. HTH

adetalhouet ( 2016-10-31 10:18:28 -0800 )edit
0

answered 2016-10-19 00:47:38 -0800

Mandeep gravatar image

updated 2016-10-25 02:58:47 -0800

As Alexis explained, you have to delete flow from config datastore (when switch goes down).

To Delete flow from config datastore using Restconf:

Send HTTP DELETE with following url:

http://${ip}:${port}/restconf/config/opendaylight-inventory:nodes/node/${dpid}/table/0/flow/${flowid}

To Delete flow from config datastore using OSGI Framework:

Not tested but I feel you should see implementation of _removeMDFlow() API at line # 3228 in OpenflowpluginTestCommandProvider

But I would suggest not to delete once switch goes down. Best time to do that just before adding flow. Like if exist but expired then delete & add again.

edit flag offensive delete publish link more

Comments

Thanks Mandeep. Can you give me a direction on how to check whether the flows in the Config datastore are expired or not? Also, I am not using HTTP here. I am writing codes in ODL's Java OSGI framework itself to make it work dynamically.

ahuja ( 2016-10-20 07:05:59 -0800 )edit

i got some interesting thing to share which vouches your solution: https://lists.opendaylight.org/pipermail/openflowplugin-dev/2015-August/003692.html

ahuja ( 2016-10-20 07:39:02 -0800 )edit

I am not aware of any flow expiry in config datastore. As you mentioned in your [Answer] "h1 MAC to port mapping expired in S1", then S1 might have deleted flow from table. If yes, then query to Operational datastore & if that does not exist (but same exist in config) then delete from config data.

Mandeep ( 2016-10-21 00:37:31 -0800 )edit

That seems correct Mandeep. But I am not getting how to remove a flow from config datastore.

ahuja ( 2016-10-24 14:00:26 -0800 )edit
1

Ahuja, updated my answer. I found an test case which deletes flow using OSGI framework. If still does not work, please share your code.

Mandeep ( 2016-10-25 03:00:46 -0800 )edit
Login/Signup to Answer

Question Tools

Follow
1 follower

Stats

Asked: 2016-10-13 07:28:57 -0800

Seen: 282 times

Last updated: Nov 01 '16